From ff48bd834142a3de422b4f200280252309a24c97 Mon Sep 17 00:00:00 2001 From: islxyqwe Date: Wed, 10 Apr 2024 20:37:20 +0800 Subject: [PATCH] chore: add embed function for bundled cdn dispatch --- packages/graphic-walker/src/index.tsx | 114 +---------------------- packages/graphic-walker/src/root.tsx | 110 ++++++++++++++++++++++ packages/graphic-walker/src/vanilla.tsx | 118 +++++++++++++++++++++++- 3 files changed, 228 insertions(+), 114 deletions(-) create mode 100644 packages/graphic-walker/src/root.tsx diff --git a/packages/graphic-walker/src/index.tsx b/packages/graphic-walker/src/index.tsx index af1a4921..8297b4e1 100644 --- a/packages/graphic-walker/src/index.tsx +++ b/packages/graphic-walker/src/index.tsx @@ -1,117 +1,7 @@ -import React, { type ForwardedRef, forwardRef, useState } from 'react'; -import { DOMProvider } from '@kanaries/react-beautiful-dnd'; -import { observer } from 'mobx-react-lite'; -import { VizAppWithContext } from './App'; -import { ShadowDom } from './shadow-dom'; -import AppRoot from './components/appRoot'; -import type { - IGWHandler, - IGWHandlerInsider, - ITableProps, - IVizAppProps, - ILocalComputationProps, - IRemoteComputationProps, - IComputationProps, - IVisualLayout, -} from './interfaces'; - -import './empty_sheet.css'; -import { TableAppWithContext } from './Table'; -import { RendererAppWithContext } from './Renderer'; - -export type ILocalVizAppProps = IVizAppProps & ILocalComputationProps & React.RefAttributes; -export type IRemoteVizAppProps = IVizAppProps & IRemoteComputationProps & React.RefAttributes; - -export const GraphicWalker = observer( - forwardRef((props, ref) => { - const [shadowRoot, setShadowRoot] = useState(null); - - const handleMount = (shadowRoot: ShadowRoot) => { - setShadowRoot(shadowRoot); - }; - const handleUnmount = () => { - setShadowRoot(null); - }; - - return ( - }> - - - - - - - ); - }) -) as { - (p: ILocalVizAppProps): JSX.Element; - (p: IRemoteVizAppProps): JSX.Element; -}; - -export type IRendererProps = { - containerClassName?: string; - containerStyle?: React.CSSProperties; - overrideSize?: IVisualLayout['size']; -}; - -export const GraphicRenderer = observer( - forwardRef((props, ref) => { - const [shadowRoot, setShadowRoot] = useState(null); - - const handleMount = (shadowRoot: ShadowRoot) => { - setShadowRoot(shadowRoot); - }; - const handleUnmount = () => { - setShadowRoot(null); - }; - - return ( - }> - - - - - - - ); - }) -) as { - (p: ILocalVizAppProps & IRendererProps): JSX.Element; - (p: IRemoteVizAppProps & IRendererProps): JSX.Element; -}; - -export type ILocalTableProps = ITableProps & ILocalComputationProps & React.RefAttributes; -export type IRemoteTableProps = ITableProps & IRemoteComputationProps & React.RefAttributes; - -export const TableWalker = observer( - forwardRef((props, ref) => { - const [shadowRoot, setShadowRoot] = useState(null); - - const handleMount = (shadowRoot: ShadowRoot) => { - setShadowRoot(shadowRoot); - }; - const handleUnmount = () => { - setShadowRoot(null); - }; - - return ( - }> - - - - - - - ); - }) -) as { - (p: ILocalTableProps): JSX.Element; - (p: IRemoteTableProps): JSX.Element; -}; - +export * from './root'; export { default as PureRenderer } from './renderer/pureRenderer'; export type { ILocalPureRendererProps, IRemotePureRendererProps } from './renderer/pureRenderer'; -export { embedGraphicWalker } from './vanilla'; +export { embedGraphicWalker, embedGraphicRenderer, embedPureRenderer, embedTableWalker } from './vanilla'; export * from './interfaces'; export * from './store/visualSpecStore'; export { resolveChart, convertChart, parseChart } from './models/visSpecHistory'; diff --git a/packages/graphic-walker/src/root.tsx b/packages/graphic-walker/src/root.tsx new file mode 100644 index 00000000..af145e7f --- /dev/null +++ b/packages/graphic-walker/src/root.tsx @@ -0,0 +1,110 @@ +import React, { type ForwardedRef, forwardRef, useState } from 'react'; +import { DOMProvider } from '@kanaries/react-beautiful-dnd'; +import { observer } from 'mobx-react-lite'; +import { VizAppWithContext } from './App'; +import { ShadowDom } from './shadow-dom'; +import AppRoot from './components/appRoot'; +import type { + IGWHandler, + IGWHandlerInsider, + ITableProps, + IVizAppProps, + ILocalComputationProps, + IRemoteComputationProps, + IComputationProps, + IVisualLayout, +} from './interfaces'; + +import './empty_sheet.css'; +import { TableAppWithContext } from './Table'; +import { RendererAppWithContext } from './Renderer'; + +export type ILocalVizAppProps = IVizAppProps & ILocalComputationProps & React.RefAttributes; +export type IRemoteVizAppProps = IVizAppProps & IRemoteComputationProps & React.RefAttributes; + +export const GraphicWalker = observer( + forwardRef((props, ref) => { + const [shadowRoot, setShadowRoot] = useState(null); + + const handleMount = (shadowRoot: ShadowRoot) => { + setShadowRoot(shadowRoot); + }; + const handleUnmount = () => { + setShadowRoot(null); + }; + + return ( + }> + + + + + + + ); + }) +) as { + (p: ILocalVizAppProps): JSX.Element; + (p: IRemoteVizAppProps): JSX.Element; +}; + +export type IRendererProps = { + containerClassName?: string; + containerStyle?: React.CSSProperties; + overrideSize?: IVisualLayout['size']; +}; + +export const GraphicRenderer = observer( + forwardRef((props, ref) => { + const [shadowRoot, setShadowRoot] = useState(null); + + const handleMount = (shadowRoot: ShadowRoot) => { + setShadowRoot(shadowRoot); + }; + const handleUnmount = () => { + setShadowRoot(null); + }; + + return ( + }> + + + + + + + ); + }) +) as { + (p: ILocalVizAppProps & IRendererProps): JSX.Element; + (p: IRemoteVizAppProps & IRendererProps): JSX.Element; +}; + +export type ILocalTableProps = ITableProps & ILocalComputationProps & React.RefAttributes; +export type IRemoteTableProps = ITableProps & IRemoteComputationProps & React.RefAttributes; + +export const TableWalker = observer( + forwardRef((props, ref) => { + const [shadowRoot, setShadowRoot] = useState(null); + + const handleMount = (shadowRoot: ShadowRoot) => { + setShadowRoot(shadowRoot); + }; + const handleUnmount = () => { + setShadowRoot(null); + }; + + return ( + }> + + + + + + + ); + }) +) as { + (p: ILocalTableProps): JSX.Element; + (p: IRemoteTableProps): JSX.Element; +}; diff --git a/packages/graphic-walker/src/vanilla.tsx b/packages/graphic-walker/src/vanilla.tsx index c603cde2..138a2c8a 100644 --- a/packages/graphic-walker/src/vanilla.tsx +++ b/packages/graphic-walker/src/vanilla.tsx @@ -1,7 +1,10 @@ import React, { useMemo } from 'react'; import ReactDOM from 'react-dom'; -import { DataSourceSegmentComponent, GraphicWalker, IGWProps } from './index'; import { createMemoryProvider } from './dataSourceProvider/memory'; +import { IGWProps } from './interfaces'; +import { DataSourceSegmentComponent } from './dataSource'; +import { GraphicRenderer, GraphicWalker, ILocalTableProps, ILocalVizAppProps, IRemoteTableProps, IRemoteVizAppProps, TableWalker } from './root'; +import PureRenderer, { ILocalPureRendererProps, IRemotePureRendererProps } from './renderer/pureRenderer'; function FullGraphicWalker(props: IGWProps) { const provider = useMemo(() => createMemoryProvider(), []); @@ -23,13 +26,40 @@ function FullGraphicWalker(props: IGWProps) { ); } -export function embedGraphicWalker(dom: HTMLElement | null, props: IGWProps | undefined = {}) { +const hasData = (props: ILocalVizAppProps | IRemoteVizAppProps | IGWProps): props is ILocalVizAppProps | IRemoteVizAppProps => + 'dataSource' in props || 'data' in props || 'computation' in props || 'rawFields' in props || 'fields' in props; + +export function embedGraphicWalker(dom: HTMLElement | null, props: ILocalVizAppProps | undefined); +export function embedGraphicWalker(dom: HTMLElement | null, props: IRemoteVizAppProps | undefined); +export function embedGraphicWalker(dom: HTMLElement | null, props: IGWProps | undefined); +export function embedGraphicWalker(dom, props: IGWProps | ILocalVizAppProps | IRemoteVizAppProps = {}) { if (!dom) { throw 'DOM element not found.'; } // Example: Detect if Concurrent Mode is available const isConcurrentModeAvailable = 'createRoot' in ReactDOM; + if (hasData(props)) { + if (isConcurrentModeAvailable) { + if (import.meta.env.DEV) { + console.warn( + 'React 18+ detected, remove strict mode if you meet drag and drop issue. more info at https://docs.kanaries.net/graphic-walker/faq/graphic-walker-react-18' + ); + } + // @ts-ignore + const root = ReactDOM.createRoot(dom as HTMLElement); + root.render(); + } else { + ReactDOM.render( + + + , + dom as HTMLElement + ); + } + return; + } + // Use the new ReactDOM.createRoot API if available, otherwise fall back to the old ReactDOM.render API if (isConcurrentModeAvailable) { if (import.meta.env.DEV) { @@ -49,3 +79,87 @@ export function embedGraphicWalker(dom: HTMLElement | null, props: IGWProps | un ); } } + +export function embedGraphicRenderer(dom: HTMLElement | null, props: ILocalVizAppProps | undefined); +export function embedGraphicRenderer(dom: HTMLElement | null, props: IRemoteVizAppProps | undefined); +export function embedGraphicRenderer(dom, props = {}) { + if (!dom) { + throw 'DOM element not found.'; + } + // Example: Detect if Concurrent Mode is available + const isConcurrentModeAvailable = 'createRoot' in ReactDOM; + + if (isConcurrentModeAvailable) { + if (import.meta.env.DEV) { + console.warn( + 'React 18+ detected, remove strict mode if you meet drag and drop issue. more info at https://docs.kanaries.net/graphic-walker/faq/graphic-walker-react-18' + ); + } + // @ts-ignore + const root = ReactDOM.createRoot(dom as HTMLElement); + root.render(); + } else { + ReactDOM.render( + + + , + dom as HTMLElement + ); + } +} + +export function embedTableWalker(dom: HTMLElement | null, props: ILocalTableProps | undefined); +export function embedTableWalker(dom: HTMLElement | null, props: IRemoteTableProps | undefined); +export function embedTableWalker(dom, props = {}) { + if (!dom) { + throw 'DOM element not found.'; + } + // Example: Detect if Concurrent Mode is available + const isConcurrentModeAvailable = 'createRoot' in ReactDOM; + + if (isConcurrentModeAvailable) { + if (import.meta.env.DEV) { + console.warn( + 'React 18+ detected, remove strict mode if you meet drag and drop issue. more info at https://docs.kanaries.net/graphic-walker/faq/graphic-walker-react-18' + ); + } + // @ts-ignore + const root = ReactDOM.createRoot(dom as HTMLElement); + root.render(); + } else { + ReactDOM.render( + + + , + dom as HTMLElement + ); + } +} + +export function embedPureRenderer(dom: HTMLElement | null, props: ILocalPureRendererProps); +export function embedPureRenderer(dom: HTMLElement | null, props: IRemotePureRendererProps); +export function embedPureRenderer(dom, props) { + if (!dom) { + throw 'DOM element not found.'; + } + // Example: Detect if Concurrent Mode is available + const isConcurrentModeAvailable = 'createRoot' in ReactDOM; + + if (isConcurrentModeAvailable) { + if (import.meta.env.DEV) { + console.warn( + 'React 18+ detected, remove strict mode if you meet drag and drop issue. more info at https://docs.kanaries.net/graphic-walker/faq/graphic-walker-react-18' + ); + } + // @ts-ignore + const root = ReactDOM.createRoot(dom as HTMLElement); + root.render(); + } else { + ReactDOM.render( + + + , + dom as HTMLElement + ); + } +}