diff --git a/packages/app-aco/src/config/table/Column.tsx b/packages/app-aco/src/config/table/Column.tsx index eeb5dd5d1eb..4c012484852 100644 --- a/packages/app-aco/src/config/table/Column.tsx +++ b/packages/app-aco/src/config/table/Column.tsx @@ -82,3 +82,5 @@ const isFolderRow = (row: BaseTableItem): row is FolderTableItem => { }; export const Column = Object.assign(BaseColumn, { isFolderRow, createUseTableRow }); + +Column["displayName"] = "AcoColumn"; diff --git a/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerView/FileManagerViewConfig.tsx b/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerView/FileManagerViewConfig.tsx index 4f6e791627c..4a19b47c1b0 100644 --- a/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerView/FileManagerViewConfig.tsx +++ b/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerView/FileManagerViewConfig.tsx @@ -1,11 +1,22 @@ -import { useMemo } from "react"; +import React, { useMemo } from "react"; import { createConfigurableComponent } from "@webiny/react-properties"; import { Browser, BrowserConfig } from "./configComponents/Browser"; import { FileDetails, FileDetailsConfig } from "./configComponents/FileDetails"; import { getThumbnailRenderer } from "./getThumbnailRenderer"; +import { CompositionScope } from "@webiny/react-composition"; const base = createConfigurableComponent("FileManagerView"); +const ScopedFileManagerViewConfig = ({ children }: { children: React.ReactNode }) => { + return ( + + {children} + + ); +}; + +ScopedFileManagerViewConfig.displayName = "FileManagerViewConfig"; + export const FileManagerViewConfig = Object.assign(base.Config, { Browser, FileDetails }); export const FileManagerViewWithConfig = base.WithConfig; diff --git a/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerView/configComponents/Browser/FileAction.tsx b/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerView/configComponents/Browser/FileAction.tsx index 9c4b414cb48..ede69cf5f4c 100644 --- a/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerView/configComponents/Browser/FileAction.tsx +++ b/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerView/configComponents/Browser/FileAction.tsx @@ -1,5 +1,4 @@ import React from "react"; -import { CompositionScope } from "@webiny/react-composition"; import { AcoConfig, RecordActionConfig } from "@webiny/app-aco"; const { Record } = AcoConfig; @@ -10,11 +9,9 @@ type FileActionProps = React.ComponentProps; const BaseFileAction = (props: FileActionProps) => { return ( - - - - - + + + ); }; diff --git a/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerView/configComponents/Browser/FolderAction.tsx b/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerView/configComponents/Browser/FolderAction.tsx index f019f44b279..7839116b234 100644 --- a/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerView/configComponents/Browser/FolderAction.tsx +++ b/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerView/configComponents/Browser/FolderAction.tsx @@ -1,5 +1,4 @@ import React from "react"; -import { CompositionScope } from "@webiny/react-composition"; import { AcoConfig, FolderActionConfig } from "@webiny/app-aco"; const { Folder } = AcoConfig; @@ -10,11 +9,9 @@ type FolderActionProps = React.ComponentProps; const BaseFolderAction = (props: FolderActionProps) => { return ( - - - - - + + + ); }; diff --git a/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerView/configComponents/Browser/Table/Column.tsx b/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerView/configComponents/Browser/Table/Column.tsx index 91c21eb81a5..719bfb45e70 100644 --- a/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerView/configComponents/Browser/Table/Column.tsx +++ b/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerView/configComponents/Browser/Table/Column.tsx @@ -1,5 +1,4 @@ import React from "react"; -import { CompositionScope } from "@webiny/react-composition"; import { AcoConfig, TableColumnConfig as ColumnConfig } from "@webiny/app-aco"; import { TableItem } from "~/types"; @@ -11,11 +10,9 @@ type ColumnProps = React.ComponentProps; const BaseColumn = (props: ColumnProps) => { return ( - - - - - + + + ); }; diff --git a/packages/app-headless-cms/src/admin/components/LexicalCmsEditor/LexicalCmsEditor.tsx b/packages/app-headless-cms/src/admin/components/LexicalCmsEditor/LexicalCmsEditor.tsx index 925468df5af..60469ba8715 100644 --- a/packages/app-headless-cms/src/admin/components/LexicalCmsEditor/LexicalCmsEditor.tsx +++ b/packages/app-headless-cms/src/admin/components/LexicalCmsEditor/LexicalCmsEditor.tsx @@ -1,7 +1,6 @@ import React, { useCallback } from "react"; import { StaticToolbar } from "@webiny/lexical-editor"; import { RichTextEditorProps } from "@webiny/lexical-editor/types"; -import { CompositionScope } from "@webiny/react-composition"; import { LexicalEditor } from "@webiny/app-admin/components/LexicalEditor"; const placeholderStyles: React.CSSProperties = { position: "absolute", top: 40, left: 25 }; @@ -20,11 +19,7 @@ const styles: React.CSSProperties = { maxHeight: 350 }; -const toolbar = ( - - - -); +const toolbar = ; export const LexicalCmsEditor = (props: Omit) => { const onChange = useCallback( diff --git a/packages/app-headless-cms/src/admin/config/contentEntries/list/Browser/AdvancedSearch/FieldRenderer.tsx b/packages/app-headless-cms/src/admin/config/contentEntries/list/Browser/AdvancedSearch/FieldRenderer.tsx index b240d2f8cc7..cb021a5122d 100644 --- a/packages/app-headless-cms/src/admin/config/contentEntries/list/Browser/AdvancedSearch/FieldRenderer.tsx +++ b/packages/app-headless-cms/src/admin/config/contentEntries/list/Browser/AdvancedSearch/FieldRenderer.tsx @@ -1,5 +1,4 @@ import React from "react"; -import { CompositionScope } from "@webiny/react-composition"; import { AcoConfig, AdvancedSearchFieldRendererConfig as FieldRendererConfig @@ -23,11 +22,9 @@ const BaseFieldRenderer = ({ modelIds = [], ...props }: FieldRendererProps) => { } return ( - - - - - + + + ); }; diff --git a/packages/app-headless-cms/src/admin/config/contentEntries/list/Browser/EntryAction.tsx b/packages/app-headless-cms/src/admin/config/contentEntries/list/Browser/EntryAction.tsx index ea5c9c8a216..00bf9ef8f22 100644 --- a/packages/app-headless-cms/src/admin/config/contentEntries/list/Browser/EntryAction.tsx +++ b/packages/app-headless-cms/src/admin/config/contentEntries/list/Browser/EntryAction.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { CompositionScope, makeDecoratable } from "@webiny/react-composition"; +import { makeDecoratable } from "@webiny/react-composition"; import { AcoConfig, RecordActionConfig } from "@webiny/app-aco"; import { IsApplicableToCurrentModel } from "~/admin/config/IsApplicableToCurrentModel"; @@ -15,13 +15,11 @@ const BaseEntryAction = makeDecoratable( "EntryAction", ({ modelIds = [], ...props }: EntryActionProps) => { return ( - - - - - - - + + + + + ); } ); diff --git a/packages/app-headless-cms/src/admin/config/contentEntries/list/Browser/FolderAction.tsx b/packages/app-headless-cms/src/admin/config/contentEntries/list/Browser/FolderAction.tsx index 53f2c20001b..40d950d578f 100644 --- a/packages/app-headless-cms/src/admin/config/contentEntries/list/Browser/FolderAction.tsx +++ b/packages/app-headless-cms/src/admin/config/contentEntries/list/Browser/FolderAction.tsx @@ -1,5 +1,4 @@ import React from "react"; -import { CompositionScope } from "@webiny/react-composition"; import { AcoConfig, FolderActionConfig } from "@webiny/app-aco"; import { useModel } from "~/admin/hooks"; @@ -19,11 +18,9 @@ const BaseFolderAction = ({ modelIds = [], ...props }: FolderActionProps) => { } return ( - - - - - + + + ); }; diff --git a/packages/app-headless-cms/src/admin/config/contentEntries/list/Browser/Table/Column.tsx b/packages/app-headless-cms/src/admin/config/contentEntries/list/Browser/Table/Column.tsx index d71110f2f93..e1ebeb81801 100644 --- a/packages/app-headless-cms/src/admin/config/contentEntries/list/Browser/Table/Column.tsx +++ b/packages/app-headless-cms/src/admin/config/contentEntries/list/Browser/Table/Column.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { CompositionScope, makeDecoratable } from "@webiny/react-composition"; +import { makeDecoratable } from "@webiny/react-composition"; import { AcoConfig, TableColumnConfig as ColumnConfig } from "@webiny/app-aco"; import { TableItem } from "~/types"; import { IsApplicableToCurrentModel } from "~/admin/config/IsApplicableToCurrentModel"; @@ -14,13 +14,11 @@ export interface ColumnProps extends React.ComponentProps { return ( - - - - - - - + + + + + ); }; diff --git a/packages/app-headless-cms/src/admin/config/contentEntries/list/ContentEntryListConfig.tsx b/packages/app-headless-cms/src/admin/config/contentEntries/list/ContentEntryListConfig.tsx index 5a383dc7529..a4d036cc30e 100644 --- a/packages/app-headless-cms/src/admin/config/contentEntries/list/ContentEntryListConfig.tsx +++ b/packages/app-headless-cms/src/admin/config/contentEntries/list/ContentEntryListConfig.tsx @@ -1,10 +1,21 @@ -import { useMemo } from "react"; +import React, { useMemo } from "react"; import { createConfigurableComponent } from "@webiny/react-properties"; import { Browser, BrowserConfig } from "./Browser"; +import { CompositionScope } from "@webiny/react-composition"; const base = createConfigurableComponent("ContentEntryListConfig"); -export const ContentEntryListConfig = Object.assign(base.Config, { Browser }); +const ScopedContentEntryListConfig = ({ children }: { children: React.ReactNode }) => { + return ( + + {children} + + ); +}; + +ScopedContentEntryListConfig.displayName = "ContentEntryListConfig"; + +export const ContentEntryListConfig = Object.assign(ScopedContentEntryListConfig, { Browser }); export const ContentEntryListWithConfig = base.WithConfig; interface ContentEntryListConfig { diff --git a/packages/app-page-builder/src/admin/config/pages/list/Browser/FolderAction.tsx b/packages/app-page-builder/src/admin/config/pages/list/Browser/FolderAction.tsx index 4cb11debe14..7839116b234 100644 --- a/packages/app-page-builder/src/admin/config/pages/list/Browser/FolderAction.tsx +++ b/packages/app-page-builder/src/admin/config/pages/list/Browser/FolderAction.tsx @@ -1,5 +1,4 @@ import React from "react"; -import { CompositionScope } from "@webiny/react-composition"; import { AcoConfig, FolderActionConfig } from "@webiny/app-aco"; const { Folder } = AcoConfig; @@ -10,11 +9,9 @@ type FolderActionProps = React.ComponentProps; const BaseFolderAction = (props: FolderActionProps) => { return ( - - - - - + + + ); }; diff --git a/packages/app-page-builder/src/admin/config/pages/list/Browser/PageAction.tsx b/packages/app-page-builder/src/admin/config/pages/list/Browser/PageAction.tsx index b30ac8369e5..6769638c4a7 100644 --- a/packages/app-page-builder/src/admin/config/pages/list/Browser/PageAction.tsx +++ b/packages/app-page-builder/src/admin/config/pages/list/Browser/PageAction.tsx @@ -1,5 +1,4 @@ import React from "react"; -import { CompositionScope } from "@webiny/react-composition"; import { AcoConfig, RecordActionConfig } from "@webiny/app-aco"; const { Record } = AcoConfig; @@ -10,11 +9,9 @@ type PageActionProps = React.ComponentProps; const BasePageAction = (props: PageActionProps) => { return ( - - - - - + + + ); }; diff --git a/packages/app-page-builder/src/admin/config/pages/list/Browser/Table/Column.tsx b/packages/app-page-builder/src/admin/config/pages/list/Browser/Table/Column.tsx index d43d6e36b8c..a7f89ac404f 100644 --- a/packages/app-page-builder/src/admin/config/pages/list/Browser/Table/Column.tsx +++ b/packages/app-page-builder/src/admin/config/pages/list/Browser/Table/Column.tsx @@ -1,5 +1,4 @@ import React from "react"; -import { CompositionScope } from "@webiny/react-composition"; import { AcoConfig, TableColumnConfig as ColumnConfig } from "@webiny/app-aco"; import { TableItem } from "~/types"; @@ -9,13 +8,11 @@ export { ColumnConfig }; type ColumnProps = React.ComponentProps; -const BaseColumn = (props: ColumnProps) => { +const BaseColumn: React.FC = props => { return ( - - - - - + + + ); }; @@ -23,3 +20,5 @@ export const Column = Object.assign(BaseColumn, { useTableRow: Table.Column.createUseTableRow(), isFolderRow: Table.Column.isFolderRow }); + +Column["displayName"] = "Column"; diff --git a/packages/app-page-builder/src/admin/config/pages/list/PageListConfig.tsx b/packages/app-page-builder/src/admin/config/pages/list/PageListConfig.tsx index 5a7485790f2..929a98ee9fb 100644 --- a/packages/app-page-builder/src/admin/config/pages/list/PageListConfig.tsx +++ b/packages/app-page-builder/src/admin/config/pages/list/PageListConfig.tsx @@ -1,10 +1,21 @@ -import { useMemo } from "react"; +import React, { useMemo } from "react"; import { createConfigurableComponent } from "@webiny/react-properties"; import { Browser, BrowserConfig } from "./Browser"; +import { CompositionScope } from "@webiny/react-composition"; const base = createConfigurableComponent("PageListConfig"); -export const PageListConfig = Object.assign(base.Config, { Browser }); +const ScopedPagesListConfig = ({ children }: { children: React.ReactNode }) => { + return ( + + {children} + + ); +}; + +ScopedPagesListConfig.displayName = "PagesListConfig"; + +export const PageListConfig = Object.assign(ScopedPagesListConfig, { Browser }); export const PageListWithConfig = base.WithConfig; interface PageListConfig { diff --git a/packages/app-page-builder/src/admin/plugins/routes.tsx b/packages/app-page-builder/src/admin/plugins/routes.tsx index 8cd18ad6eb2..2c58f7f1b78 100644 --- a/packages/app-page-builder/src/admin/plugins/routes.tsx +++ b/packages/app-page-builder/src/admin/plugins/routes.tsx @@ -71,7 +71,7 @@ const plugins: RoutePlugin[] = [ - + @@ -196,3 +196,6 @@ const plugins: RoutePlugin[] = [ ]; export default plugins; + +// *, pb.page, grid.background, fm +// *, pb.page, fm diff --git a/packages/app-trash-bin/src/Presentation/configs/list/Browser/Table/Column.tsx b/packages/app-trash-bin/src/Presentation/configs/list/Browser/Table/Column.tsx index 14462c1d997..84a5cb0cd8b 100644 --- a/packages/app-trash-bin/src/Presentation/configs/list/Browser/Table/Column.tsx +++ b/packages/app-trash-bin/src/Presentation/configs/list/Browser/Table/Column.tsx @@ -1,5 +1,4 @@ import React from "react"; -import { CompositionScope } from "@webiny/react-composition"; import { AcoConfig, TableColumnConfig as ColumnConfig } from "@webiny/app-aco"; import { TrashBinItemDTO } from "~/Domain"; @@ -11,11 +10,9 @@ type ColumnProps = React.ComponentProps; const BaseColumn = (props: ColumnProps) => { return ( - - - - - + + + ); }; diff --git a/packages/app-trash-bin/src/Presentation/configs/list/Browser/Table/Sorting.tsx b/packages/app-trash-bin/src/Presentation/configs/list/Browser/Table/Sorting.tsx index cf282678ce9..de3bd4c283d 100644 --- a/packages/app-trash-bin/src/Presentation/configs/list/Browser/Table/Sorting.tsx +++ b/packages/app-trash-bin/src/Presentation/configs/list/Browser/Table/Sorting.tsx @@ -1,5 +1,4 @@ import React from "react"; -import { CompositionScope } from "@webiny/react-composition"; import { AcoConfig, TableSortingConfig as SortingConfig } from "@webiny/app-aco"; const { Table } = AcoConfig; @@ -10,10 +9,8 @@ type SortingProps = React.ComponentProps; export const Sorting = (props: SortingProps) => { return ( - - - - - + + + ); }; diff --git a/packages/app-trash-bin/src/Presentation/configs/list/TrashBinListConfig.tsx b/packages/app-trash-bin/src/Presentation/configs/list/TrashBinListConfig.tsx index 2960021e3c2..378cf77d120 100644 --- a/packages/app-trash-bin/src/Presentation/configs/list/TrashBinListConfig.tsx +++ b/packages/app-trash-bin/src/Presentation/configs/list/TrashBinListConfig.tsx @@ -1,10 +1,21 @@ -import { useMemo } from "react"; +import React, { useMemo } from "react"; import { createConfigurableComponent } from "@webiny/react-properties"; import { Browser, BrowserConfig } from "./Browser"; +import { CompositionScope } from "@webiny/react-composition"; const base = createConfigurableComponent("TrashBinListConfig"); -export const TrashBinListConfig = Object.assign(base.Config, { Browser }); +const ScopedTrashBinListConfig = ({ children }: { children: React.ReactNode }) => { + return ( + + {children} + + ); +}; + +ScopedTrashBinListConfig.displayName = "TrashBinListConfig"; + +export const TrashBinListConfig = Object.assign(ScopedTrashBinListConfig, { Browser }); export const TrashBinListWithConfig = base.WithConfig; interface TrashBinListConfig { diff --git a/packages/lexical-editor-pb-element/src/index.tsx b/packages/lexical-editor-pb-element/src/index.tsx index 48a3440f4b4..8449f332b5c 100644 --- a/packages/lexical-editor-pb-element/src/index.tsx +++ b/packages/lexical-editor-pb-element/src/index.tsx @@ -14,11 +14,13 @@ export * from "./LexicalEditor"; export const LexicalEditorPlugin = () => { return ( <> - - - - - + + + + + + + } /> {/* Block editor variables */} diff --git a/packages/react-composition/src/Context.tsx b/packages/react-composition/src/Context.tsx index 39c9e4995c2..457c887a31f 100644 --- a/packages/react-composition/src/Context.tsx +++ b/packages/react-composition/src/Context.tsx @@ -3,6 +3,7 @@ import React, { createContext, useCallback, useContext, + useEffect, useMemo, useState } from "react"; @@ -79,6 +80,10 @@ interface CompositionProviderProps { children: React.ReactNode; } +const getCacheKey = (scopes: string[]) => { + return scopes.join(";"); +}; + /** * Scopes are ordered in reverse, to go from child to parent. As we iterate over scopes, we try to find the latest component * recipe (a "recipe" is a base component + all decorators registered so far). If none exist, we return an empty recipe. @@ -88,8 +93,9 @@ const findComponentRecipe = ( lookupScopes: string[], components: ComponentScopes ) => { - for (const scope of lookupScopes) { - const scopeMap: ComposedComponents = components.get(scope) || new Map(); + for (let i = lookupScopes.length; i > 0; i--) { + const cacheKey = getCacheKey(lookupScopes.slice(0, i)); + const scopeMap: ComposedComponents = components.get(cacheKey) || new Map(); const recipe = scopeMap.get(component); if (recipe) { return recipe; @@ -104,12 +110,11 @@ const composeComponents = ( decorators: Array<[GenericComponent | GenericHook, Decorator[]]>, scopes: string[] = [] ) => { - const targetScope = scopes[scopes.length - 1]; - const targetComponents = components.get(targetScope) || new Map(); - const lookupScopes = scopes.reverse(); + const cacheKey = getCacheKey(scopes); + const targetComponents: ComposedComponents = components.get(cacheKey) || new Map(); for (const [component, hocs] of decorators) { - const recipe = findComponentRecipe(component, lookupScopes, components); + const recipe = findComponentRecipe(component, scopes, components); const newHocs = [...(recipe.hocs || []), ...hocs] as Decorator< GenericHook | GenericComponent @@ -120,7 +125,7 @@ const composeComponents = ( hocs: newHocs }); - components.set(targetScope, targetComponents); + components.set(cacheKey, targetComponents); } return components; @@ -143,20 +148,18 @@ export const CompositionProvider = ({ decorators = [], children }: CompositionPr hocs: HigherOrderComponent[], scopes: string[] = [] ) => { + const allScopes = ["*", ...scopes]; + setComponents(prevComponents => { - return composeComponents( - new Map(prevComponents), - [[component, hocs]], - ["*", ...scopes] - ); + return composeComponents(new Map(prevComponents), [[component, hocs]], allScopes); }); // Return a function that will remove the added HOCs. return () => { - const scope = scopes[scopes.length - 1]; + const cacheKey = getCacheKey(allScopes); setComponents(prevComponents => { const components = new Map(prevComponents); - const scopeMap: ComposedComponents = components.get(scope) || new Map(); + const scopeMap: ComposedComponents = components.get(cacheKey) || new Map(); const recipe = scopeMap.get(component) || { component: null, hocs: [] @@ -170,7 +173,7 @@ export const CompositionProvider = ({ decorators = [], children }: CompositionPr hocs: newHOCs }); - components.set(scope, scopeMap); + components.set(cacheKey, scopeMap); return components; }); }; @@ -180,9 +183,10 @@ export const CompositionProvider = ({ decorators = [], children }: CompositionPr const getComponent = useCallback( (Component, scope = []) => { - const scopesToResolve = ["*", ...scope].reverse(); - for (const scope of scopesToResolve) { - const scopeMap: ComposedComponents = components.get(scope) || new Map(); + const scopes = ["*", ...scope]; + for (let i = scopes.length; i > 0; i--) { + const cacheKey = getCacheKey(scopes.slice(0, i)); + const scopeMap: ComposedComponents = components.get(cacheKey) || new Map(); const composedComponent = scopeMap.get(Component); if (composedComponent) { return composedComponent.component; @@ -203,6 +207,15 @@ export const CompositionProvider = ({ decorators = [], children }: CompositionPr [components, composeComponent] ); + useEffect(() => { + if (process.env.NODE_ENV !== "production") { + // @ts-expect-error This is a developers-only utility. + window["debug_printComposedComponents"] = () => { + console.log(components); + }; + } + }, [components]); + return {children}; }; diff --git a/packages/react-composition/src/makeDecoratable.tsx b/packages/react-composition/src/makeDecoratable.tsx index eeea12f73b7..9310b10463d 100644 --- a/packages/react-composition/src/makeDecoratable.tsx +++ b/packages/react-composition/src/makeDecoratable.tsx @@ -77,7 +77,9 @@ export function makeDecoratable( ): ReturnType>; export function makeDecoratable(hookOrName: any, Component?: any) { if (Component) { - return makeDecoratableComponent(hookOrName, React.memo(Component)); + const component = makeDecoratableComponent(hookOrName, React.memo(Component)); + component.original.displayName = hookOrName; + return component; } return makeDecoratableHook(hookOrName);