Skip to content

Commit

Permalink
chore: add embed function for bundled cdn dispatch
Browse files Browse the repository at this point in the history
  • Loading branch information
islxyqwe committed Apr 10, 2024
1 parent 714f006 commit ff48bd8
Show file tree
Hide file tree
Showing 3 changed files with 228 additions and 114 deletions.
114 changes: 2 additions & 112 deletions packages/graphic-walker/src/index.tsx
Original file line number Diff line number Diff line change
@@ -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<IGWHandler>;
export type IRemoteVizAppProps = IVizAppProps & IRemoteComputationProps & React.RefAttributes<IGWHandler>;

export const GraphicWalker = observer(
forwardRef<IGWHandler, IVizAppProps & (ILocalComputationProps | IRemoteComputationProps)>((props, ref) => {
const [shadowRoot, setShadowRoot] = useState<ShadowRoot | null>(null);

const handleMount = (shadowRoot: ShadowRoot) => {
setShadowRoot(shadowRoot);
};
const handleUnmount = () => {
setShadowRoot(null);
};

return (
<AppRoot ref={ref as ForwardedRef<IGWHandlerInsider>}>
<ShadowDom onMount={handleMount} onUnmount={handleUnmount} uiTheme={props.uiTheme ?? props.colorConfig}>
<DOMProvider value={{ head: shadowRoot ?? document.head, body: shadowRoot ?? document.body }}>
<VizAppWithContext {...props} />
</DOMProvider>
</ShadowDom>
</AppRoot>
);
})
) 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<IGWHandler, IVizAppProps & IRendererProps & (ILocalComputationProps | IRemoteComputationProps)>((props, ref) => {
const [shadowRoot, setShadowRoot] = useState<ShadowRoot | null>(null);

const handleMount = (shadowRoot: ShadowRoot) => {
setShadowRoot(shadowRoot);
};
const handleUnmount = () => {
setShadowRoot(null);
};

return (
<AppRoot ref={ref as ForwardedRef<IGWHandlerInsider>}>
<ShadowDom onMount={handleMount} onUnmount={handleUnmount} uiTheme={props.uiTheme ?? props.colorConfig}>
<DOMProvider value={{ head: shadowRoot ?? document.head, body: shadowRoot ?? document.body }}>
<RendererAppWithContext {...props} />
</DOMProvider>
</ShadowDom>
</AppRoot>
);
})
) as {
(p: ILocalVizAppProps & IRendererProps): JSX.Element;
(p: IRemoteVizAppProps & IRendererProps): JSX.Element;
};

export type ILocalTableProps = ITableProps & ILocalComputationProps & React.RefAttributes<IGWHandler>;
export type IRemoteTableProps = ITableProps & IRemoteComputationProps & React.RefAttributes<IGWHandler>;

export const TableWalker = observer(
forwardRef<IGWHandler, ITableProps & IComputationProps>((props, ref) => {
const [shadowRoot, setShadowRoot] = useState<ShadowRoot | null>(null);

const handleMount = (shadowRoot: ShadowRoot) => {
setShadowRoot(shadowRoot);
};
const handleUnmount = () => {
setShadowRoot(null);
};

return (
<AppRoot ref={ref as ForwardedRef<IGWHandlerInsider>}>
<ShadowDom onMount={handleMount} onUnmount={handleUnmount} uiTheme={props.uiTheme ?? props.colorConfig}>
<DOMProvider value={{ head: shadowRoot ?? document.head, body: shadowRoot ?? document.body }}>
<TableAppWithContext {...props} />
</DOMProvider>
</ShadowDom>
</AppRoot>
);
})
) 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';
Expand Down
110 changes: 110 additions & 0 deletions packages/graphic-walker/src/root.tsx
Original file line number Diff line number Diff line change
@@ -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<IGWHandler>;
export type IRemoteVizAppProps = IVizAppProps & IRemoteComputationProps & React.RefAttributes<IGWHandler>;

export const GraphicWalker = observer(
forwardRef<IGWHandler, IVizAppProps & (ILocalComputationProps | IRemoteComputationProps)>((props, ref) => {
const [shadowRoot, setShadowRoot] = useState<ShadowRoot | null>(null);

const handleMount = (shadowRoot: ShadowRoot) => {
setShadowRoot(shadowRoot);
};
const handleUnmount = () => {
setShadowRoot(null);
};

return (
<AppRoot ref={ref as ForwardedRef<IGWHandlerInsider>}>
<ShadowDom onMount={handleMount} onUnmount={handleUnmount} uiTheme={props.uiTheme ?? props.colorConfig}>
<DOMProvider value={{ head: shadowRoot ?? document.head, body: shadowRoot ?? document.body }}>
<VizAppWithContext {...props} />
</DOMProvider>
</ShadowDom>
</AppRoot>
);
})
) 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<IGWHandler, IVizAppProps & IRendererProps & (ILocalComputationProps | IRemoteComputationProps)>((props, ref) => {
const [shadowRoot, setShadowRoot] = useState<ShadowRoot | null>(null);

const handleMount = (shadowRoot: ShadowRoot) => {
setShadowRoot(shadowRoot);
};
const handleUnmount = () => {
setShadowRoot(null);
};

return (
<AppRoot ref={ref as ForwardedRef<IGWHandlerInsider>}>
<ShadowDom onMount={handleMount} onUnmount={handleUnmount} uiTheme={props.uiTheme ?? props.colorConfig}>
<DOMProvider value={{ head: shadowRoot ?? document.head, body: shadowRoot ?? document.body }}>
<RendererAppWithContext {...props} />
</DOMProvider>
</ShadowDom>
</AppRoot>
);
})
) as {
(p: ILocalVizAppProps & IRendererProps): JSX.Element;
(p: IRemoteVizAppProps & IRendererProps): JSX.Element;
};

export type ILocalTableProps = ITableProps & ILocalComputationProps & React.RefAttributes<IGWHandler>;
export type IRemoteTableProps = ITableProps & IRemoteComputationProps & React.RefAttributes<IGWHandler>;

export const TableWalker = observer(
forwardRef<IGWHandler, ITableProps & IComputationProps>((props, ref) => {
const [shadowRoot, setShadowRoot] = useState<ShadowRoot | null>(null);

const handleMount = (shadowRoot: ShadowRoot) => {
setShadowRoot(shadowRoot);
};
const handleUnmount = () => {
setShadowRoot(null);
};

return (
<AppRoot ref={ref as ForwardedRef<IGWHandlerInsider>}>
<ShadowDom onMount={handleMount} onUnmount={handleUnmount} uiTheme={props.uiTheme ?? props.colorConfig}>
<DOMProvider value={{ head: shadowRoot ?? document.head, body: shadowRoot ?? document.body }}>
<TableAppWithContext {...props} />
</DOMProvider>
</ShadowDom>
</AppRoot>
);
})
) as {
(p: ILocalTableProps): JSX.Element;
(p: IRemoteTableProps): JSX.Element;
};
118 changes: 116 additions & 2 deletions packages/graphic-walker/src/vanilla.tsx
Original file line number Diff line number Diff line change
@@ -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(), []);
Expand All @@ -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(<GraphicWalker themeKey="g2" {...props} />);
} else {
ReactDOM.render(
<React.StrictMode>
<GraphicWalker themeKey="g2" {...props} />
</React.StrictMode>,
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) {
Expand All @@ -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(<GraphicRenderer themeKey="g2" {...props} />);
} else {
ReactDOM.render(
<React.StrictMode>
<GraphicRenderer themeKey="g2" {...props} />
</React.StrictMode>,
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(<TableWalker themeKey="g2" {...props} />);
} else {
ReactDOM.render(
<React.StrictMode>
<TableWalker themeKey="g2" {...props} />
</React.StrictMode>,
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(<PureRenderer themeKey="g2" {...props} />);
} else {
ReactDOM.render(
<React.StrictMode>
<PureRenderer themeKey="g2" {...props} />
</React.StrictMode>,
dom as HTMLElement
);
}
}

0 comments on commit ff48bd8

Please sign in to comment.