Compare commits

...

3 Commits

Author SHA1 Message Date
Tom Moor fb8a7f55d3 tsc 1 2023-07-03 21:55:53 -04:00
Tom Moor 76525da52d Merge main 2023-07-03 21:25:40 -04:00
Tom Moor c59949dbd4 React 18 upgrade 2023-07-03 21:24:38 -04:00
44 changed files with 791 additions and 939 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ import * as React from "react";
import { IntegrationService } from "@shared/types";
import env from "~/env";
const Analytics: React.FC = ({ children }) => {
const Analytics: React.FC<React.PropsWithChildren> = ({ children }) => {
// Google Analytics 3
React.useEffect(() => {
if (!env.GOOGLE_ANALYTICS_ID?.startsWith("UA-")) {
+3 -1
View File
@@ -37,7 +37,9 @@ const DocumentInsights = lazyWithRetry(
);
const CommandBar = lazyWithRetry(() => import("~/components/CommandBar"));
const AuthenticatedLayout: React.FC = ({ children }) => {
const AuthenticatedLayout: React.FC<React.PropsWithChildren> = ({
children,
}) => {
const { ui, auth } = useStores();
const location = useLocation();
const can = usePolicy(ui.activeCollectionId);
+2 -2
View File
@@ -2,9 +2,9 @@ import * as React from "react";
import styled from "styled-components";
import breakpoint from "styled-components-breakpoint";
type Props = {
type Props = React.PropsWithChildren<{
withStickyHeader?: boolean;
};
}>;
const Container = styled.div<Props>`
width: 100%;
+1 -1
View File
@@ -52,7 +52,7 @@ function CommandBar() {
);
}
const KBarPortal: React.FC = ({ children }) => {
const KBarPortal: React.FC<React.PropsWithChildren> = ({ children }) => {
const { showing } = useKBar((state) => ({
showing: state.visualState !== "hidden",
}));
+2 -2
View File
@@ -6,7 +6,7 @@ import Text from "~/components/Text";
import useStores from "~/hooks/useStores";
import useToasts from "~/hooks/useToasts";
type Props = {
type Props = React.PropsWithChildren<{
/** Callback when the dialog is submitted */
onSubmit: () => Promise<void> | void;
/** Text to display on the submit button */
@@ -17,7 +17,7 @@ type Props = {
danger?: boolean;
/** Keep the submit button disabled */
disabled?: boolean;
};
}>;
const ConfirmationDialog: React.FC<Props> = ({
onSubmit,
+12 -11
View File
@@ -36,17 +36,18 @@ export type Placement =
| "left"
| "left-start";
type Props = MenuStateReturn & {
"aria-label"?: string;
/** The parent menu state if this is a submenu. */
parentMenuState?: Omit<MenuStateReturn, "items">;
/** Called when the context menu is opened. */
onOpen?: () => void;
/** Called when the context menu is closed. */
onClose?: () => void;
/** Called when the context menu is clicked. */
onClick?: (ev: React.MouseEvent) => void;
};
type Props = MenuStateReturn &
React.PropsWithChildren<{
"aria-label"?: string;
/** The parent menu state if this is a submenu. */
parentMenuState?: Omit<MenuStateReturn, "items">;
/** Called when the context menu is opened. */
onOpen?: () => void;
/** Called when the context menu is closed. */
onClose?: () => void;
/** Called when the context menu is clicked. */
onClick?: (ev: React.MouseEvent) => void;
}>;
const ContextMenu: React.FC<Props> = ({
children,
+2 -2
View File
@@ -16,10 +16,10 @@ import {
trashPath,
} from "~/utils/routeHelpers";
type Props = {
type Props = React.PropsWithChildren<{
document: Document;
onlyText?: boolean;
};
}>;
function useCategory(document: Document): MenuInternalLink | null {
const { t } = useTranslation();
+2 -2
View File
@@ -14,7 +14,7 @@ import Time from "~/components/Time";
import useCurrentUser from "~/hooks/useCurrentUser";
import useStores from "~/hooks/useStores";
type Props = {
type Props = React.PropsWithChildren<{
showCollection?: boolean;
showPublished?: boolean;
showLastViewed?: boolean;
@@ -23,7 +23,7 @@ type Props = {
revision?: Revision;
replace?: boolean;
to?: LocationDescriptor;
};
}>;
const DocumentMeta: React.FC<Props> = ({
showPublished,
+2 -2
View File
@@ -1,8 +1,8 @@
import * as React from "react";
type Props = {
type Props = React.PropsWithChildren<{
className?: string;
};
}>;
const EventBoundary: React.FC<Props> = ({ children, className }) => {
const handleClick = React.useCallback((event: React.SyntheticEvent) => {
+2 -2
View File
@@ -5,11 +5,11 @@ import { depths, s } from "@shared/styles";
import Scrollable from "~/components/Scrollable";
import usePrevious from "~/hooks/usePrevious";
type Props = {
type Props = React.PropsWithChildren<{
isOpen: boolean;
title?: string;
onRequestClose: () => void;
};
}>;
const Guide: React.FC<Props> = ({
children,
+2 -2
View File
@@ -4,9 +4,9 @@ import styled from "styled-components";
import { s } from "@shared/styles";
import Flex from "~/components/Flex";
type Props = {
type Props = React.PropsWithChildren<{
label: React.ReactNode | string;
};
}>;
const Labeled: React.FC<Props> = ({ label, children, ...props }) => (
<Flex column {...props}>
+2 -2
View File
@@ -15,11 +15,11 @@ import { MenuProvider } from "~/hooks/useMenuContext";
import useStores from "~/hooks/useStores";
import { isModKey } from "~/utils/keyboard";
type Props = {
type Props = React.PropsWithChildren<{
title?: string;
sidebar?: React.ReactNode;
sidebarRight?: React.ReactNode;
};
}>;
const Layout: React.FC<Props> = ({
title,
+3 -1
View File
@@ -5,7 +5,9 @@ import { loadPolyfills } from "~/utils/polyfills";
/**
* Asyncronously load required polyfills. Should wrap the React tree.
*/
export const LazyPolyfill: React.FC = ({ children }) => {
export const LazyPolyfill: React.FC<React.PropsWithChildren> = ({
children,
}) => {
const [isLoaded, setIsLoaded] = React.useState(false);
React.useEffect(() => {
+2 -2
View File
@@ -20,14 +20,14 @@ function eachMinute(fn: () => void) {
};
}
type Props = {
type Props = React.PropsWithChildren<{
dateTime: string;
tooltipDelay?: number;
addSuffix?: boolean;
shorten?: boolean;
relative?: boolean;
format?: Partial<Record<keyof typeof locales, string>>;
};
}>;
const LocaleTime: React.FC<Props> = ({
addSuffix,
+3 -2
View File
@@ -19,12 +19,13 @@ import Desktop from "~/utils/Desktop";
import ErrorBoundary from "./ErrorBoundary";
let openModals = 0;
type Props = {
type Props = React.PropsWithChildren<{
isOpen: boolean;
isCentered?: boolean;
title?: React.ReactNode;
onRequestClose: () => void;
};
}>;
const Modal: React.FC<Props> = ({
children,
@@ -7,7 +7,9 @@ import { depths } from "@shared/styles";
import Popover from "~/components/Popover";
import Notifications from "./Notifications";
const NotificationsPopover: React.FC = ({ children }) => {
const NotificationsPopover: React.FC<React.PropsWithChildren> = ({
children,
}) => {
const { t } = useTranslation();
const scrollableRef = React.useRef<HTMLDivElement>(null);
-102
View File
@@ -1,102 +0,0 @@
import "../stores";
import { shallow } from "enzyme";
import { TFunction } from "i18next";
import * as React from "react";
import { getI18n } from "react-i18next";
import { DEFAULT_PAGINATION_LIMIT } from "~/stores/BaseStore";
import RootStore from "~/stores/RootStore";
import { runAllPromises } from "~/test/support";
import { Component as PaginatedList } from "./PaginatedList";
describe("PaginatedList", () => {
const render = () => null;
const i18n = getI18n();
const { logout, ...store } = new RootStore();
const props = {
i18n,
tReady: true,
t: ((key: string) => key) as TFunction,
logout: () => {
//
},
...store,
};
it("with no items renders nothing", () => {
const list = shallow(
<PaginatedList items={[]} renderItem={render} {...props} />
);
expect(list).toEqual({});
});
it("with no items renders empty prop", () => {
const list = shallow(
<PaginatedList
items={[]}
empty={<p>Sorry, no results</p>}
renderItem={render}
{...props}
/>
);
expect(list.text()).toEqual("Sorry, no results");
});
it("calls fetch with options + pagination on mount", () => {
const fetch = jest.fn();
const options = {
id: "one",
};
shallow(
<PaginatedList
items={[]}
fetch={fetch}
options={options}
renderItem={render}
{...props}
/>
);
expect(fetch).toHaveBeenCalledWith({
...options,
limit: DEFAULT_PAGINATION_LIMIT,
offset: 0,
});
});
it("calls fetch when options prop changes", async () => {
const fetchedItems = Array(DEFAULT_PAGINATION_LIMIT).fill(undefined);
const fetch = jest.fn().mockReturnValue(Promise.resolve(fetchedItems));
const list = shallow(
<PaginatedList
items={[]}
fetch={fetch}
options={{
id: "one",
}}
renderItem={render}
{...props}
/>
);
await runAllPromises();
expect(fetch).toHaveBeenCalledWith({
id: "one",
limit: DEFAULT_PAGINATION_LIMIT,
offset: 0,
});
fetch.mockReset();
list.setProps({
fetch,
items: [],
options: {
id: "two",
},
});
await runAllPromises();
expect(fetch).toHaveBeenCalledWith({
id: "two",
limit: DEFAULT_PAGINATION_LIMIT,
offset: 0,
});
});
});
+2 -2
View File
@@ -4,14 +4,14 @@ import CenteredContent from "~/components/CenteredContent";
import Header from "~/components/Header";
import PageTitle from "~/components/PageTitle";
type Props = {
type Props = React.PropsWithChildren<{
icon?: React.ReactNode;
title?: React.ReactNode;
textTitle?: string;
left?: React.ReactNode;
actions?: React.ReactNode;
centered?: boolean;
};
}>;
const Scene: React.FC<Props> = ({
title,
+2 -2
View File
@@ -2,10 +2,10 @@ import * as React from "react";
import styled from "styled-components";
import Flex from "./Flex";
type Props = {
type Props = React.PropsWithChildren<{
size?: number;
color?: string;
};
}>;
const Squircle: React.FC<Props> = ({ color, size = 28, children }) => (
<Wrapper
+2 -2
View File
@@ -2,9 +2,9 @@ import * as React from "react";
import styled from "styled-components";
import { s } from "@shared/styles";
type Props = {
type Props = React.PropsWithChildren<{
sticky?: boolean;
};
}>;
const H3 = styled.h3`
border-bottom: 1px solid ${s("divider")};
+1 -1
View File
@@ -57,7 +57,7 @@ export const Separator = styled.span`
margin-top: 6px;
`;
const Tabs: React.FC = ({ children }) => {
const Tabs: React.FC<React.PropsWithChildren> = ({ children }) => {
const ref = React.useRef<any>();
const [shadowVisible, setShadow] = React.useState(false);
const { width } = useWindowSize();
+1 -1
View File
@@ -7,7 +7,7 @@ import useBuildTheme from "~/hooks/useBuildTheme";
import useStores from "~/hooks/useStores";
import { TooltipStyles } from "./Tooltip";
const Theme: React.FC = ({ children }) => {
const Theme: React.FC<React.PropsWithChildren> = ({ children }) => {
const { auth, ui } = useStores();
const theme = useBuildTheme(
auth.team?.getPreference(TeamPreference.CustomTheme) ||
+7 -8
View File
@@ -1,7 +1,7 @@
import { Node as ProsemirrorNode } from "prosemirror-model";
import { EditorView, Decoration } from "prosemirror-view";
import * as React from "react";
import ReactDOM from "react-dom";
import ReactDOM from "react-dom/client";
import { ThemeProvider } from "styled-components";
import Extension from "@shared/editor/lib/Extension";
import { ComponentProps } from "@shared/editor/types";
@@ -19,6 +19,7 @@ export default class ComponentView {
decorations: Decoration[];
isSelected = false;
root: ReactDOM.Root;
dom: HTMLElement | null;
// See https://prosemirror.net/docs/ref/#view.NodeView
@@ -70,10 +71,10 @@ export default class ComponentView {
getPos: this.getPos,
});
ReactDOM.render(
<ThemeProvider theme={theme}>{children}</ThemeProvider>,
this.dom
);
if (this.dom) {
this.root = ReactDOM.createRoot(this.dom);
this.root.render(<ThemeProvider theme={theme}>{children}</ThemeProvider>);
}
};
update(node: ProsemirrorNode) {
@@ -108,9 +109,7 @@ export default class ComponentView {
window.removeEventListener("theme-changed", this.renderElement);
window.removeEventListener("location-changed", this.renderElement);
if (this.dom) {
ReactDOM.unmountComponentAtNode(this.dom);
}
this.root?.unmount();
this.dom = null;
}
+3 -1
View File
@@ -8,7 +8,9 @@ type MenuContextType = {
const MenuContext = React.createContext<MenuContextType | null>(null);
export const MenuProvider: React.FC = ({ children }) => {
export const MenuProvider: React.FC<React.PropsWithChildren> = ({
children,
}) => {
const [isMenuOpen, setIsMenuOpen] = React.useState(false);
const memoized = React.useMemo(
() => ({
+2 -2
View File
@@ -5,7 +5,7 @@ import { LazyMotion } from "framer-motion";
import { KBarProvider } from "kbar";
import { Provider } from "mobx-react";
import * as React from "react";
import { render } from "react-dom";
import ReactDOM from "react-dom/client";
import { HelmetProvider } from "react-helmet-async";
import { Router } from "react-router-dom";
import stores from "~/stores";
@@ -81,7 +81,7 @@ if (element) {
</React.StrictMode>
);
render(<App />, element);
ReactDOM.createRoot(element).render(<App />);
}
window.addEventListener("load", async () => {
+1 -1
View File
@@ -20,7 +20,7 @@ import usePrevious from "~/hooks/usePrevious";
import useStores from "~/hooks/useStores";
import separator from "~/menus/separator";
const AccountMenu: React.FC = ({ children }) => {
const AccountMenu: React.FC<React.PropsWithChildren> = ({ children }) => {
const menu = useMenuState({
placement: "bottom-end",
modal: true,
+1 -1
View File
@@ -11,7 +11,7 @@ import usePrevious from "~/hooks/usePrevious";
import useStores from "~/hooks/useStores";
import separator from "~/menus/separator";
const OrganizationMenu: React.FC = ({ children }) => {
const OrganizationMenu: React.FC<React.PropsWithChildren> = ({ children }) => {
const menu = useMenuState({
unstable_offset: [4, -4],
placement: "bottom-start",
+2 -2
View File
@@ -8,11 +8,11 @@ import Text from "~/components/Text";
import useImportDocument from "~/hooks/useImportDocument";
import useToasts from "~/hooks/useToasts";
type Props = {
type Props = React.PropsWithChildren<{
disabled: boolean;
accept: string;
collectionId: string;
};
}>;
const DropToImport: React.FC<Props> = ({
children,
@@ -9,9 +9,9 @@ import styled, { useTheme } from "styled-components";
import Button from "~/components/Button";
import Text from "~/components/Text";
type Props = {
type Props = React.PropsWithChildren<{
title: React.ReactNode;
};
}>;
const HelpDisclosure: React.FC<Props> = ({ title, children }) => {
const disclosure = useDisclosureState({ animated: true });
@@ -5,13 +5,13 @@ import breakpoint from "styled-components-breakpoint";
import Flex from "~/components/Flex";
import Text from "~/components/Text";
type Props = {
type Props = React.PropsWithChildren<{
label: React.ReactNode;
description?: React.ReactNode;
name: string;
visible?: boolean;
border?: boolean;
};
}>;
const Row = styled(Flex)<{ $border?: boolean }>`
display: block;
-6
View File
@@ -1,16 +1,10 @@
/* eslint-disable */
// @ts-expect-error ts-migrate(7016) FIXME: Could not find a declaration file for module '../.... Remove this comment to see the full error message
import localStorage from "../../__mocks__/localStorage";
import Enzyme from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import { initI18n } from "../utils/i18n";
initI18n();
Enzyme.configure({
adapter: new Adapter()
});
global.localStorage = localStorage;
require("jest-fetch-mock").enableMocks();
+5 -10
View File
@@ -168,12 +168,12 @@
"quoted-printable": "^1.0.1",
"randomstring": "1.2.3",
"rate-limiter-flexible": "^2.4.1",
"react": "^17.0.2",
"react": "^18.2.0",
"react-avatar-editor": "^13.0.0",
"react-color": "^2.17.3",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "^17.0.2",
"react-dom": "^18.2.0",
"react-dropzone": "^11.3.2",
"react-helmet-async": "^1.3.0",
"react-hook-form": "^7.41.5",
@@ -202,7 +202,7 @@
"socket.io-redis": "^6.1.1",
"stoppable": "^1.1.0",
"string-replace-to-array": "^2.1.0",
"styled-components": "^5.2.3",
"styled-components": "^6.0.2",
"styled-components-breakpoint": "^2.1.1",
"styled-normalize": "^8.0.7",
"throng": "^5.0.0",
@@ -233,8 +233,6 @@
"@types/body-scroll-lock": "^3.1.0",
"@types/crypto-js": "^4.1.1",
"@types/emoji-regex": "^9.2.0",
"@types/enzyme": "^3.10.13",
"@types/enzyme-adapter-react-16": "^1.0.6",
"@types/express-useragent": "^1.0.2",
"@types/formidable": "^2.0.6",
"@types/fs-extra": "^11.0.1",
@@ -267,10 +265,10 @@
"@types/passport-oauth2": "^1.4.11",
"@types/quoted-printable": "^1.0.0",
"@types/randomstring": "^1.1.8",
"@types/react": "^17.0.34",
"@types/react": "^18.2.0",
"@types/react-avatar-editor": "^13.0.0",
"@types/react-color": "^3.0.6",
"@types/react-dom": "^17.0.11",
"@types/react-dom": "^18.2.0",
"@types/react-helmet": "^6.1.6",
"@types/react-portal": "^4.0.4",
"@types/react-router-dom": "^5.3.2",
@@ -283,7 +281,6 @@
"@types/sequelize": "^4.28.10",
"@types/slug": "^5.0.3",
"@types/stoppable": "^1.1.1",
"@types/styled-components": "^5.1.15",
"@types/throng": "^5.0.4",
"@types/tmp": "^0.2.3",
"@types/turndown": "^5.0.1",
@@ -298,8 +295,6 @@
"babel-plugin-tsconfig-paths-module-resolver": "^1.0.4",
"browserslist-to-esbuild": "^1.2.0",
"concurrently": "^7.4.0",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.7",
"eslint": "^8.44.0",
"eslint-config-prettier": "^8.8.0",
"eslint-import-resolver-typescript": "^3.5.4",
+1 -1
View File
@@ -2,7 +2,7 @@ import { Table, TBody, TR, TD } from "oy-vey";
import * as React from "react";
import EmptySpace from "./EmptySpace";
const Body: React.FC = ({ children }) => (
const Body: React.FC<React.PropsWithChildren> = ({ children }) => (
<Table width="100%">
<TBody>
<TR>
@@ -1,8 +1,8 @@
import * as React from "react";
type Props = {
type Props = React.PropsWithChildren<{
href: string;
};
}>;
const style: React.CSSProperties = {
display: "inline-block",
@@ -12,7 +12,7 @@ const style: React.CSSProperties = {
letterSpacing: "0.1em",
};
const CopyableCode: React.FC = (props) => (
const CopyableCode: React.FC<React.PropsWithChildren> = (props) => (
<pre {...props} style={style}>
{props.children}
</pre>
@@ -2,7 +2,7 @@ import { Table, TBody, TR, TD } from "oy-vey";
import * as React from "react";
import theme from "@shared/styles/theme";
const EmailLayout: React.FC = ({ children }) => (
const EmailLayout: React.FC<React.PropsWithChildren> = ({ children }) => (
<Table width="550">
<TBody>
<TR>
@@ -5,7 +5,7 @@ const style = {
fontSize: "18px",
};
const Heading: React.FC = ({ children }) => (
const Heading: React.FC<React.PropsWithChildren> = ({ children }) => (
<p>
<span style={style}>{children}</span>
</p>
@@ -248,7 +248,6 @@ class ControlledBase extends Component<
data-rmiz-modal=""
id={idModal}
onClick={handleDialogClick}
// @ts-expect-error does not exist
onClose={handleUnzoom}
onCancel={handleDialogCancel}
onKeyDown={handleDialogKeyDown}
+2 -2
View File
@@ -1,5 +1,5 @@
import * as React from "react";
import styled, { css, DefaultTheme, ThemeProps } from "styled-components";
import styled, { css } from "styled-components";
import { s } from "../../styles";
type Props = {
@@ -12,7 +12,7 @@ type Props = {
onMouseDown?: React.MouseEventHandler<HTMLAnchorElement>;
};
export default function Widget(props: Props & ThemeProps<DefaultTheme>) {
export default function Widget(props: Props) {
return (
<Wrapper
className={
+2 -2
View File
@@ -2,7 +2,7 @@ import { PlusIcon } from "outline-icons";
import { Plugin } from "prosemirror-state";
import { Decoration, DecorationSet } from "prosemirror-view";
import * as React from "react";
import ReactDOM from "react-dom";
import ReactDOM from "react-dom/client";
import { SuggestionsMenuType } from "../plugins/Suggestions";
import { findParentNode } from "../queries/findParentNode";
import { EventType } from "../types";
@@ -25,7 +25,7 @@ export default class BlockMenu extends Suggestion {
const button = document.createElement("button");
button.className = "block-menu-trigger";
button.type = "button";
ReactDOM.render(<PlusIcon />, button);
ReactDOM.createRoot(button).render(<PlusIcon />);
return [
...super.plugins,
+2 -2
View File
@@ -1,7 +1,7 @@
import { EditorState, Plugin } from "prosemirror-state";
import { Decoration, DecorationSet } from "prosemirror-view";
import * as React from "react";
import ReactDOM from "react-dom";
import ReactDOM from "react-dom/client";
import FileExtension from "../components/FileExtension";
// based on the example at: https://prosemirror.net/examples/upload/
@@ -55,7 +55,7 @@ const uploadPlaceholder = new Plugin({
icon.className = "icon";
const component = <FileExtension title={action.add.file.name} />;
ReactDOM.render(component, icon);
ReactDOM.createRoot(icon).render(component);
element.appendChild(icon);
const text = document.createElement("span");
+2 -2
View File
@@ -12,7 +12,7 @@ import {
import { Command, EditorState, Plugin } from "prosemirror-state";
import { Decoration, DecorationSet, EditorView } from "prosemirror-view";
import * as React from "react";
import ReactDOM from "react-dom";
import ReactDOM from "react-dom/client";
import { isExternalUrl, sanitizeUrl } from "../../utils/urls";
import findLinkNodes from "../queries/findLinkNodes";
import getMarkRange from "../queries/getMarkRange";
@@ -27,7 +27,7 @@ if (typeof window !== "undefined") {
const component = <OpenIcon size={16} />;
icon = document.createElement("span");
icon.className = "external-link";
ReactDOM.render(component, icon);
ReactDOM.createRoot(icon).render(component);
}
function isPlainURL(
+2 -2
View File
@@ -3,7 +3,7 @@ import { WarningIcon, InfoIcon, StarredIcon, DoneIcon } from "outline-icons";
import { wrappingInputRule } from "prosemirror-inputrules";
import { NodeSpec, Node as ProsemirrorNode, NodeType } from "prosemirror-model";
import * as React from "react";
import ReactDOM from "react-dom";
import ReactDOM from "react-dom/client";
import toggleWrap from "../commands/toggleWrap";
import { MarkdownSerializerState } from "../lib/markdown/serializer";
import noticesRule from "../rules/notices";
@@ -121,7 +121,7 @@ export default class Notice extends Node {
icon = document.createElement("div");
icon.className = "icon";
ReactDOM.render(component, icon);
ReactDOM.createRoot(icon).render(component);
}
return [
+698 -741
View File
File diff suppressed because it is too large Load Diff