mirror of
https://github.com/excalidraw/excalidraw.git
synced 2024-11-10 11:35:52 +01:00
feat: render unknown supplied children to UI (#6096)
This commit is contained in:
parent
699897f71b
commit
0982da38fe
@ -15,11 +15,7 @@ import {
|
|||||||
BinaryFiles,
|
BinaryFiles,
|
||||||
UIChildrenComponents,
|
UIChildrenComponents,
|
||||||
} from "../types";
|
} from "../types";
|
||||||
import {
|
import { isShallowEqual, muteFSAbortError, getReactChildren } from "../utils";
|
||||||
isShallowEqual,
|
|
||||||
muteFSAbortError,
|
|
||||||
ReactChildrenToObject,
|
|
||||||
} from "../utils";
|
|
||||||
import { SelectedShapeActions, ShapesSwitcher } from "./Actions";
|
import { SelectedShapeActions, ShapesSwitcher } from "./Actions";
|
||||||
import CollabButton from "./CollabButton";
|
import CollabButton from "./CollabButton";
|
||||||
import { ErrorDialog } from "./ErrorDialog";
|
import { ErrorDialog } from "./ErrorDialog";
|
||||||
@ -111,8 +107,11 @@ const LayerUI = ({
|
|||||||
}: LayerUIProps) => {
|
}: LayerUIProps) => {
|
||||||
const device = useDevice();
|
const device = useDevice();
|
||||||
|
|
||||||
const childrenComponents =
|
const [childrenComponents, restChildren] =
|
||||||
ReactChildrenToObject<UIChildrenComponents>(children);
|
getReactChildren<UIChildrenComponents>(children, {
|
||||||
|
Menu: true,
|
||||||
|
FooterCenter: true,
|
||||||
|
});
|
||||||
|
|
||||||
const renderJSONExportDialog = () => {
|
const renderJSONExportDialog = () => {
|
||||||
if (!UIOptions.canvasActions.export) {
|
if (!UIOptions.canvasActions.export) {
|
||||||
@ -390,6 +389,7 @@ const LayerUI = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{restChildren}
|
||||||
{appState.isLoading && <LoadingMessage delay={250} />}
|
{appState.isLoading && <LoadingMessage delay={250} />}
|
||||||
{appState.errorMessage && (
|
{appState.errorMessage && (
|
||||||
<ErrorDialog
|
<ErrorDialog
|
||||||
|
@ -15,6 +15,8 @@ Please add the latest change on the top under the correct section.
|
|||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
|
- Any top-level children passed to the `<Excalidraw/>` component that do not belong to one of the officially supported Excalidraw children components are now rendered directly inside the Excalidraw container (previously, they weren't rendered at all) [#6096](https://github.com/excalidraw/excalidraw/pull/6096).
|
||||||
|
|
||||||
- Expose component API for the Excalidraw main menu [#6034](https://github.com/excalidraw/excalidraw/pull/6034), You can read more about its usage [here](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#MainMenu)
|
- Expose component API for the Excalidraw main menu [#6034](https://github.com/excalidraw/excalidraw/pull/6034), You can read more about its usage [here](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#MainMenu)
|
||||||
|
|
||||||
- Render Footer as a component instead of render prop [#5970](https://github.com/excalidraw/excalidraw/pull/5970). You can read more about its usage [here](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#Footer)
|
- Render Footer as a component instead of render prop [#5970](https://github.com/excalidraw/excalidraw/pull/5970). You can read more about its usage [here](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#Footer)
|
||||||
|
53
src/utils.ts
53
src/utils.ts
@ -687,27 +687,46 @@ export const queryFocusableElements = (container: HTMLElement | null) => {
|
|||||||
: [];
|
: [];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ReactChildrenToObject = <
|
/**
|
||||||
T extends {
|
* Partitions React children into named components and the rest of children.
|
||||||
[k in string]?:
|
*
|
||||||
| React.ReactPortal
|
* Returns known children as a dictionary of react children keyed by their
|
||||||
| React.ReactElement<unknown, string | React.JSXElementConstructor<any>>;
|
* displayName, and the rest children as an array.
|
||||||
|
*
|
||||||
|
* NOTE all named react components are included in the dictionary, irrespective
|
||||||
|
* of the supplied type parameter. This means you may be throwing away
|
||||||
|
* children that you aren't expecting, but should nonetheless be rendered.
|
||||||
|
* To guard against this (provided you care about the rest children at all),
|
||||||
|
* supply a second parameter with an object with keys of the expected children.
|
||||||
|
*/
|
||||||
|
export const getReactChildren = <
|
||||||
|
KnownChildren extends {
|
||||||
|
[k in string]?: React.ReactNode;
|
||||||
},
|
},
|
||||||
>(
|
>(
|
||||||
children: React.ReactNode,
|
children: React.ReactNode,
|
||||||
|
expectedComponents?: Record<keyof KnownChildren, any>,
|
||||||
) => {
|
) => {
|
||||||
return React.Children.toArray(children).reduce((acc, child) => {
|
const restChildren: React.ReactNode[] = [];
|
||||||
if (
|
|
||||||
React.isValidElement(child) &&
|
const knownChildren = React.Children.toArray(children).reduce(
|
||||||
typeof child.type !== "string" &&
|
(acc, child) => {
|
||||||
//@ts-ignore
|
if (
|
||||||
child?.type.displayName
|
React.isValidElement(child) &&
|
||||||
) {
|
(!expectedComponents ||
|
||||||
// @ts-ignore
|
((child.type as any).displayName as string) in expectedComponents)
|
||||||
acc[child.type.displayName] = child;
|
) {
|
||||||
}
|
// @ts-ignore
|
||||||
return acc;
|
acc[child.type.displayName] = child;
|
||||||
}, {} as Partial<T>);
|
} else {
|
||||||
|
restChildren.push(child);
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{} as Partial<KnownChildren>,
|
||||||
|
);
|
||||||
|
|
||||||
|
return [knownChildren, restChildren] as const;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isShallowEqual = <T extends Record<string, any>>(
|
export const isShallowEqual = <T extends Record<string, any>>(
|
||||||
|
Loading…
Reference in New Issue
Block a user