@perspective-dev/react 4.5.2 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,4 +8,3 @@
8
8
  * @module
9
9
  */
10
10
  export * from "./viewer";
11
- export * from "./workspace";
package/dist/esm/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import*as s from"react";import*as d from"react";function c(e,t,n){d.useEffect(()=>{if(!n||!e)return;let o=new AbortController,p=a=>n(a.detail);return e?.addEventListener(t,p,{signal:o.signal}),()=>o.abort()},[e,n])}function w(e){let[t,n]=s.useState(null);return s.useEffect(()=>()=>{t?.delete()},[t]),s.useEffect(()=>{e.client?t?.load(e.client):t?.eject()},[t,e.client]),s.useEffect(()=>{e.client&&e.config&&t?.restore(e.config)},[t,e.client,JSON.stringify(e.config)]),c(t,"perspective-click",e.onClick),c(t,"perspective-select",e.onSelect),c(t,"perspective-config-update",e.onConfigUpdate),s.createElement("perspective-viewer",{ref:n,id:e.id,className:e.className,hidden:e.hidden,slot:e.slot,style:e.style,tabIndex:e.tabIndex,title:e.title})}var k=s.memo(w);import*as i from"react";var g=i.forwardRef(({client:e,layout:t,onLayoutUpdate:n,onNewView:o,onToggleGlobalFilter:p,...a},f)=>{let[r,v]=i.useState();return i.useImperativeHandle(f,()=>r,[r]),i.useEffect(()=>{r&&t&&r.restore(t)},[r,t]),i.useEffect(()=>{r&&e&&r.load(e)},[r,e]),c(r,"workspace-new-view",o),c(r,"workspace-layout-update",n?({layout:l})=>r?.save().then(u=>n(u)):void 0),c(r,"workspace-toggle-global-filter",p),i.createElement("perspective-workspace",{ref:l=>v(l??void 0),...a})}),C=i.memo(g);export{k as PerspectiveViewer,C as PerspectiveWorkspace};
1
+ import*as i from"react";import*as a from"react";function c(e,t,r,n=s=>s.detail){a.useEffect(()=>{if(!r||!e)return;let s=new AbortController,l=o=>r(n(o));return e?.addEventListener(t,l,{signal:s.signal}),()=>s.abort()},[e,r])}function d(e){let[t,r]=i.useState(null);return i.useEffect(()=>()=>{t?.delete()},[t]),i.useEffect(()=>{if(!t)return;let n=!1;return(async()=>{if(!e.client){await t.eject();return}await t.load(e.client),!(n||!e.config)&&("panels"in e.config?await t.restoreWorkspace(e.config):await t.restore(e.config))})(),()=>{n=!0}},[t,e.client,JSON.stringify(e.config)]),c(t,"perspective-click",e.onClick),c(t,"perspective-select",e.onSelect),c(t,"perspective-config-update",e.onConfigUpdate,n=>n.detail.getConfig()),i.createElement("perspective-viewer",{ref:r,id:e.id,className:e.className,hidden:e.hidden,slot:e.slot,style:e.style,tabIndex:e.tabIndex,title:e.title})}var u=i.memo(d);export{u as PerspectiveViewer};
2
2
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../src/viewer.tsx", "../../src/utils.tsx", "../../src/workspace.tsx"],
4
- "sourcesContent": ["// \u250F\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n// \u2503 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588 \u2588 \u2588 \u2588 \u2588 \u2588\u2584 \u2580\u2588\u2588\u2588 \u2588 \u2503\n// \u2503 \u2584\u2584\u2584\u2584\u2584\u2588 \u2588\u2584\u2584\u2584\u2584\u2584 \u2584\u2584\u2584\u2584\u2584\u2588 \u2580\u2580\u2580\u2580\u2580\u2588\u2580\u2580\u2580\u2580\u2580 \u2588 \u2580\u2580\u2580\u2580\u2580\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258C\u2590\u2588\u2588\u2588 \u2588\u2588\u2588\u2584 \u2580\u2588 \u2588 \u2580\u2580\u2580\u2580\u2580 \u2503\n// \u2503 \u2588\u2580\u2580\u2580\u2580\u2580 \u2588\u2580\u2580\u2580\u2580\u2580 \u2588\u2580\u2588\u2588\u2580\u2580 \u2584\u2584\u2584\u2584\u2584 \u2588 \u2584\u2584\u2584\u2584\u2584\u2588 \u2584\u2584\u2584\u2584\u2584\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258C\u2590\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2584 \u2588 \u2584\u2584\u2584\u2584\u2584 \u2503\n// \u2503 \u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588 \u2580\u2588\u2584 \u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588 \u2588\u2588\u2588\u258C\u2590\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2584 \u2588 \u2503\n// \u2523\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u252B\n// \u2503 Copyright (c) 2017, the Perspective Authors. \u2503\n// \u2503 \u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C \u2503\n// \u2503 This file is part of the Perspective library, distributed under the terms \u2503\n// \u2503 of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). \u2503\n// \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u251B\n\nimport * as React from \"react\";\nimport type * as psp from \"@perspective-dev/client\";\nimport type * as pspViewer from \"@perspective-dev/viewer\";\nimport { usePspListener } from \"./utils\";\n\nfunction PerspectiveViewerImpl(props: PerspectiveViewerProps) {\n const [viewer, setViewer] =\n React.useState<pspViewer.HTMLPerspectiveViewerElement | null>(null);\n\n React.useEffect(() => {\n return () => {\n viewer?.delete();\n };\n }, [viewer]);\n\n React.useEffect(() => {\n if (props.client) {\n viewer?.load(props.client);\n } else {\n viewer?.eject();\n }\n }, [viewer, props.client]);\n\n React.useEffect(() => {\n if (props.client && props.config) {\n viewer?.restore(props.config);\n }\n }, [viewer, props.client, JSON.stringify(props.config)]);\n\n usePspListener(viewer, \"perspective-click\", props.onClick);\n usePspListener(viewer, \"perspective-select\", props.onSelect);\n usePspListener(viewer, \"perspective-config-update\", props.onConfigUpdate);\n\n return (\n <perspective-viewer\n ref={setViewer}\n id={props.id}\n className={props.className}\n hidden={props.hidden}\n slot={props.slot}\n style={props.style}\n tabIndex={props.tabIndex}\n title={props.title}\n />\n );\n}\n\n/**\n * Props for the `<PerspectiveViewer>` component.\n */\nexport interface PerspectiveViewerProps {\n client?: psp.Client | Promise<psp.Client> | psp.Table | Promise<psp.Table>;\n config?: pspViewer.ViewerConfigUpdate;\n onConfigUpdate?: (config: pspViewer.ViewerConfigUpdate) => void;\n onClick?: (data: pspViewer.PerspectiveClickEventDetail) => void;\n onSelect?: (data: pspViewer.PerspectiveSelectEventDetail) => void;\n\n // Applicable props from `React.HTMLAttributes`, which we cannot extend\n // directly because Perspective changes the signature of `onClick`.\n className?: string | undefined;\n hidden?: boolean | undefined;\n id?: string | undefined;\n slot?: string | undefined;\n style?: React.CSSProperties | undefined;\n tabIndex?: number | undefined;\n title?: string | undefined;\n}\n\n/**\n * A React wrapper component for `<perspective-viewer>` Custom Element.\n */\nexport const PerspectiveViewer: React.FC<PerspectiveViewerProps> = React.memo(\n PerspectiveViewerImpl,\n);\n", "// \u250F\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n// \u2503 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588 \u2588 \u2588 \u2588 \u2588 \u2588\u2584 \u2580\u2588\u2588\u2588 \u2588 \u2503\n// \u2503 \u2584\u2584\u2584\u2584\u2584\u2588 \u2588\u2584\u2584\u2584\u2584\u2584 \u2584\u2584\u2584\u2584\u2584\u2588 \u2580\u2580\u2580\u2580\u2580\u2588\u2580\u2580\u2580\u2580\u2580 \u2588 \u2580\u2580\u2580\u2580\u2580\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258C\u2590\u2588\u2588\u2588 \u2588\u2588\u2588\u2584 \u2580\u2588 \u2588 \u2580\u2580\u2580\u2580\u2580 \u2503\n// \u2503 \u2588\u2580\u2580\u2580\u2580\u2580 \u2588\u2580\u2580\u2580\u2580\u2580 \u2588\u2580\u2588\u2588\u2580\u2580 \u2584\u2584\u2584\u2584\u2584 \u2588 \u2584\u2584\u2584\u2584\u2584\u2588 \u2584\u2584\u2584\u2584\u2584\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258C\u2590\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2584 \u2588 \u2584\u2584\u2584\u2584\u2584 \u2503\n// \u2503 \u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588 \u2580\u2588\u2584 \u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588 \u2588\u2588\u2588\u258C\u2590\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2584 \u2588 \u2503\n// \u2523\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u252B\n// \u2503 Copyright (c) 2017, the Perspective Authors. \u2503\n// \u2503 \u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C \u2503\n// \u2503 This file is part of the Perspective library, distributed under the terms \u2503\n// \u2503 of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). \u2503\n// \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u251B\n\nimport * as React from \"react\";\n\nexport function usePspListener<A>(\n el: HTMLElement | undefined | null,\n event: string,\n cb?: (x: A) => void,\n) {\n React.useEffect(() => {\n if (!cb || !el) return;\n const ctx = new AbortController();\n const callback = (e: Event) => cb((e as CustomEvent).detail);\n el?.addEventListener(event, callback, { signal: ctx.signal });\n return () => ctx.abort();\n }, [el, cb]);\n}\n", "// \u250F\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n// \u2503 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588 \u2588 \u2588 \u2588 \u2588 \u2588\u2584 \u2580\u2588\u2588\u2588 \u2588 \u2503\n// \u2503 \u2584\u2584\u2584\u2584\u2584\u2588 \u2588\u2584\u2584\u2584\u2584\u2584 \u2584\u2584\u2584\u2584\u2584\u2588 \u2580\u2580\u2580\u2580\u2580\u2588\u2580\u2580\u2580\u2580\u2580 \u2588 \u2580\u2580\u2580\u2580\u2580\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258C\u2590\u2588\u2588\u2588 \u2588\u2588\u2588\u2584 \u2580\u2588 \u2588 \u2580\u2580\u2580\u2580\u2580 \u2503\n// \u2503 \u2588\u2580\u2580\u2580\u2580\u2580 \u2588\u2580\u2580\u2580\u2580\u2580 \u2588\u2580\u2588\u2588\u2580\u2580 \u2584\u2584\u2584\u2584\u2584 \u2588 \u2584\u2584\u2584\u2584\u2584\u2588 \u2584\u2584\u2584\u2584\u2584\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258C\u2590\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2584 \u2588 \u2584\u2584\u2584\u2584\u2584 \u2503\n// \u2503 \u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588 \u2580\u2588\u2584 \u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588 \u2588\u2588\u2588\u258C\u2590\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2584 \u2588 \u2503\n// \u2523\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u252B\n// \u2503 Copyright (c) 2017, the Perspective Authors. \u2503\n// \u2503 \u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C \u2503\n// \u2503 This file is part of the Perspective library, distributed under the terms \u2503\n// \u2503 of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). \u2503\n// \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u251B\n\nimport type * as psp from \"@perspective-dev/client\";\nimport type * as psp_viewer from \"@perspective-dev/viewer\";\nimport type * as pspWorkspace from \"@perspective-dev/workspace\";\nimport { PerspectiveWorkspaceConfig } from \"@perspective-dev/workspace\";\nimport * as utils from \"./utils\";\nimport * as React from \"react\";\n\nexport interface NewViewEventDetail {\n config: psp_viewer.ViewerConfigUpdate;\n widget: pspWorkspace.PerspectiveViewerWidget;\n}\n\nexport interface ToggleGloalFilterEventDetail {\n widget: pspWorkspace.PerspectiveViewerWidget;\n isGlobalFilter: boolean;\n}\n\nexport interface PerspectiveWorkspaceProps\n extends React.HTMLAttributes<HTMLElement> {\n client: psp.Client | Promise<psp.Client>;\n layout: PerspectiveWorkspaceConfig;\n onLayoutUpdate?: (layout: PerspectiveWorkspaceConfig) => void;\n onNewView?: (detail: NewViewEventDetail) => void;\n onToggleGlobalFilter?: (detail: ToggleGloalFilterEventDetail) => void;\n}\n\nconst PerspectiveWorkspaceImpl = React.forwardRef<\n pspWorkspace.HTMLPerspectiveWorkspaceElement | undefined,\n PerspectiveWorkspaceProps\n>(\n (\n {\n client,\n layout,\n onLayoutUpdate,\n onNewView,\n onToggleGlobalFilter,\n ...htmlAttributes\n },\n ref,\n ) => {\n const [workspace, setWorkspace] =\n React.useState<pspWorkspace.HTMLPerspectiveWorkspaceElement>();\n\n React.useImperativeHandle(ref, () => workspace, [workspace]);\n React.useEffect(() => {\n if (workspace && layout) {\n workspace.restore(layout);\n }\n }, [workspace, layout]);\n\n React.useEffect(() => {\n if (workspace && client) {\n workspace.load(client);\n }\n }, [workspace, client]);\n\n utils.usePspListener(workspace, \"workspace-new-view\", onNewView);\n utils.usePspListener(\n workspace,\n \"workspace-layout-update\",\n onLayoutUpdate\n ? ({ layout }: { layout: PerspectiveWorkspaceConfig }) =>\n workspace?.save().then((x) => onLayoutUpdate(x))\n : undefined,\n );\n\n utils.usePspListener(\n workspace,\n \"workspace-toggle-global-filter\",\n onToggleGlobalFilter,\n );\n\n return (\n <perspective-workspace\n ref={(r) => setWorkspace(r ?? undefined)}\n {...htmlAttributes}\n ></perspective-workspace>\n );\n },\n);\n\nexport const PerspectiveWorkspace = React.memo(PerspectiveWorkspaceImpl);\n"],
5
- "mappings": "AAYA,UAAYA,MAAW,QCAvB,UAAYC,MAAW,QAEhB,SAASC,EACZC,EACAC,EACAC,EACF,CACQ,YAAU,IAAM,CAClB,GAAI,CAACA,GAAM,CAACF,EAAI,OAChB,IAAMG,EAAM,IAAI,gBACVC,EAAYC,GAAaH,EAAIG,EAAkB,MAAM,EAC3D,OAAAL,GAAI,iBAAiBC,EAAOG,EAAU,CAAE,OAAQD,EAAI,MAAO,CAAC,EACrD,IAAMA,EAAI,MAAM,CAC3B,EAAG,CAACH,EAAIE,CAAE,CAAC,CACf,CDTA,SAASI,EAAsBC,EAA+B,CAC1D,GAAM,CAACC,EAAQC,CAAS,EACd,WAAwD,IAAI,EAEtE,OAAM,YAAU,IACL,IAAM,CACTD,GAAQ,OAAO,CACnB,EACD,CAACA,CAAM,CAAC,EAEL,YAAU,IAAM,CACdD,EAAM,OACNC,GAAQ,KAAKD,EAAM,MAAM,EAEzBC,GAAQ,MAAM,CAEtB,EAAG,CAACA,EAAQD,EAAM,MAAM,CAAC,EAEnB,YAAU,IAAM,CACdA,EAAM,QAAUA,EAAM,QACtBC,GAAQ,QAAQD,EAAM,MAAM,CAEpC,EAAG,CAACC,EAAQD,EAAM,OAAQ,KAAK,UAAUA,EAAM,MAAM,CAAC,CAAC,EAEvDG,EAAeF,EAAQ,oBAAqBD,EAAM,OAAO,EACzDG,EAAeF,EAAQ,qBAAsBD,EAAM,QAAQ,EAC3DG,EAAeF,EAAQ,4BAA6BD,EAAM,cAAc,EAGpE,gBAAC,sBACG,IAAKE,EACL,GAAIF,EAAM,GACV,UAAWA,EAAM,UACjB,OAAQA,EAAM,OACd,KAAMA,EAAM,KACZ,MAAOA,EAAM,MACb,SAAUA,EAAM,SAChB,MAAOA,EAAM,MACjB,CAER,CA0BO,IAAMI,EAA4D,OACrEL,CACJ,EEpEA,UAAYM,MAAW,QAqBvB,IAAMC,EAAiC,aAInC,CACI,CACI,OAAAC,EACA,OAAAC,EACA,eAAAC,EACA,UAAAC,EACA,qBAAAC,EACA,GAAGC,CACP,EACAC,IACC,CACD,GAAM,CAACC,EAAWC,CAAY,EACpB,WAAuD,EAEjE,OAAM,sBAAoBF,EAAK,IAAMC,EAAW,CAACA,CAAS,CAAC,EACrD,YAAU,IAAM,CACdA,GAAaN,GACbM,EAAU,QAAQN,CAAM,CAEhC,EAAG,CAACM,EAAWN,CAAM,CAAC,EAEhB,YAAU,IAAM,CACdM,GAAaP,GACbO,EAAU,KAAKP,CAAM,CAE7B,EAAG,CAACO,EAAWP,CAAM,CAAC,EAEhBS,EAAeF,EAAW,qBAAsBJ,CAAS,EACzDM,EACFF,EACA,0BACAL,EACM,CAAC,CAAE,OAAAD,CAAO,IACNM,GAAW,KAAK,EAAE,KAAMG,GAAMR,EAAeQ,CAAC,CAAC,EACnD,MACV,EAEMD,EACFF,EACA,iCACAH,CACJ,EAGI,gBAAC,yBACG,IAAMO,GAAMH,EAAaG,GAAK,MAAS,EACtC,GAAGN,EACP,CAET,CACJ,EAEaO,EAA6B,OAAKb,CAAwB",
6
- "names": ["React", "React", "usePspListener", "el", "event", "cb", "ctx", "callback", "e", "PerspectiveViewerImpl", "props", "viewer", "setViewer", "usePspListener", "PerspectiveViewer", "React", "PerspectiveWorkspaceImpl", "client", "layout", "onLayoutUpdate", "onNewView", "onToggleGlobalFilter", "htmlAttributes", "ref", "workspace", "setWorkspace", "usePspListener", "x", "r", "PerspectiveWorkspace"]
3
+ "sources": ["../../src/viewer.tsx", "../../src/utils.tsx"],
4
+ "sourcesContent": ["// \u250F\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n// \u2503 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588 \u2588 \u2588 \u2588 \u2588 \u2588\u2584 \u2580\u2588\u2588\u2588 \u2588 \u2503\n// \u2503 \u2584\u2584\u2584\u2584\u2584\u2588 \u2588\u2584\u2584\u2584\u2584\u2584 \u2584\u2584\u2584\u2584\u2584\u2588 \u2580\u2580\u2580\u2580\u2580\u2588\u2580\u2580\u2580\u2580\u2580 \u2588 \u2580\u2580\u2580\u2580\u2580\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258C\u2590\u2588\u2588\u2588 \u2588\u2588\u2588\u2584 \u2580\u2588 \u2588 \u2580\u2580\u2580\u2580\u2580 \u2503\n// \u2503 \u2588\u2580\u2580\u2580\u2580\u2580 \u2588\u2580\u2580\u2580\u2580\u2580 \u2588\u2580\u2588\u2588\u2580\u2580 \u2584\u2584\u2584\u2584\u2584 \u2588 \u2584\u2584\u2584\u2584\u2584\u2588 \u2584\u2584\u2584\u2584\u2584\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258C\u2590\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2584 \u2588 \u2584\u2584\u2584\u2584\u2584 \u2503\n// \u2503 \u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588 \u2580\u2588\u2584 \u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588 \u2588\u2588\u2588\u258C\u2590\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2584 \u2588 \u2503\n// \u2523\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u252B\n// \u2503 Copyright (c) 2017, the Perspective Authors. \u2503\n// \u2503 \u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C \u2503\n// \u2503 This file is part of the Perspective library, distributed under the terms \u2503\n// \u2503 of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). \u2503\n// \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u251B\n\nimport * as React from \"react\";\nimport type * as psp from \"@perspective-dev/client\";\nimport type * as pspViewer from \"@perspective-dev/viewer\";\nimport { usePspListener } from \"./utils\";\n\nfunction PerspectiveViewerImpl(props: PerspectiveViewerProps) {\n const [viewer, setViewer] =\n React.useState<pspViewer.HTMLPerspectiveViewerElement | null>(null);\n\n React.useEffect(() => {\n return () => {\n viewer?.delete();\n };\n }, [viewer]);\n\n React.useEffect(() => {\n if (!viewer) {\n return;\n }\n\n let cancelled = false;\n (async () => {\n if (!props.client) {\n await viewer.eject();\n return;\n }\n\n await viewer.load(props.client);\n if (cancelled || !props.config) {\n return;\n }\n\n if (\"panels\" in props.config) {\n await viewer.restoreWorkspace(props.config);\n } else {\n await viewer.restore(props.config);\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [viewer, props.client, JSON.stringify(props.config)]);\n\n usePspListener(viewer, \"perspective-click\", props.onClick);\n usePspListener(viewer, \"perspective-select\", props.onSelect);\n usePspListener(\n viewer,\n \"perspective-config-update\",\n props.onConfigUpdate,\n (e) => e.detail.getConfig(),\n );\n\n return (\n <perspective-viewer\n ref={setViewer}\n id={props.id}\n className={props.className}\n hidden={props.hidden}\n slot={props.slot}\n style={props.style}\n tabIndex={props.tabIndex}\n title={props.title}\n />\n );\n}\n\n/**\n * Props for the `<PerspectiveViewer>` component.\n */\nexport interface PerspectiveViewerProps {\n client?: psp.Client | Promise<psp.Client> | psp.Table | Promise<psp.Table>;\n config?: pspViewer.ViewerConfigUpdate | pspViewer.WorkspaceConfigUpdate;\n onConfigUpdate?: (config: pspViewer.ViewerConfigUpdate) => void;\n onClick?: (data: pspViewer.PerspectiveClickEventDetail) => void;\n onSelect?: (data: pspViewer.PerspectiveSelectEventDetail) => void;\n\n // Applicable props from `React.HTMLAttributes`, which we cannot extend\n // directly because Perspective changes the signature of `onClick`.\n className?: string | undefined;\n hidden?: boolean | undefined;\n id?: string | undefined;\n slot?: string | undefined;\n style?: React.CSSProperties | undefined;\n tabIndex?: number | undefined;\n title?: string | undefined;\n}\n\n/**\n * A React wrapper component for `<perspective-viewer>` Custom Element.\n */\nexport const PerspectiveViewer: React.FC<PerspectiveViewerProps> = React.memo(\n PerspectiveViewerImpl,\n);\n", "// \u250F\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n// \u2503 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588 \u2588 \u2588 \u2588 \u2588 \u2588\u2584 \u2580\u2588\u2588\u2588 \u2588 \u2503\n// \u2503 \u2584\u2584\u2584\u2584\u2584\u2588 \u2588\u2584\u2584\u2584\u2584\u2584 \u2584\u2584\u2584\u2584\u2584\u2588 \u2580\u2580\u2580\u2580\u2580\u2588\u2580\u2580\u2580\u2580\u2580 \u2588 \u2580\u2580\u2580\u2580\u2580\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258C\u2590\u2588\u2588\u2588 \u2588\u2588\u2588\u2584 \u2580\u2588 \u2588 \u2580\u2580\u2580\u2580\u2580 \u2503\n// \u2503 \u2588\u2580\u2580\u2580\u2580\u2580 \u2588\u2580\u2580\u2580\u2580\u2580 \u2588\u2580\u2588\u2588\u2580\u2580 \u2584\u2584\u2584\u2584\u2584 \u2588 \u2584\u2584\u2584\u2584\u2584\u2588 \u2584\u2584\u2584\u2584\u2584\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258C\u2590\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2584 \u2588 \u2584\u2584\u2584\u2584\u2584 \u2503\n// \u2503 \u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588 \u2580\u2588\u2584 \u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588 \u2588\u2588\u2588\u258C\u2590\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2584 \u2588 \u2503\n// \u2523\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u252B\n// \u2503 Copyright (c) 2017, the Perspective Authors. \u2503\n// \u2503 \u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C\u254C \u2503\n// \u2503 This file is part of the Perspective library, distributed under the terms \u2503\n// \u2503 of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). \u2503\n// \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u251B\n\nimport * as React from \"react\";\n\nexport function usePspListener<A>(\n el: HTMLElement | undefined | null,\n event: string,\n cb?: (x: A) => void,\n map: (e: CustomEvent) => A = (e) => e.detail,\n) {\n React.useEffect(() => {\n if (!cb || !el) return;\n const ctx = new AbortController();\n const callback = (e: Event) => cb(map(e as CustomEvent));\n el?.addEventListener(event, callback, { signal: ctx.signal });\n return () => ctx.abort();\n }, [el, cb]);\n}\n"],
5
+ "mappings": "AAYA,UAAYA,MAAW,QCAvB,UAAYC,MAAW,QAEhB,SAASC,EACZC,EACAC,EACAC,EACAC,EAA8BC,GAAMA,EAAE,OACxC,CACQ,YAAU,IAAM,CAClB,GAAI,CAACF,GAAM,CAACF,EAAI,OAChB,IAAMK,EAAM,IAAI,gBACVC,EAAYF,GAAaF,EAAGC,EAAIC,CAAgB,CAAC,EACvD,OAAAJ,GAAI,iBAAiBC,EAAOK,EAAU,CAAE,OAAQD,EAAI,MAAO,CAAC,EACrD,IAAMA,EAAI,MAAM,CAC3B,EAAG,CAACL,EAAIE,CAAE,CAAC,CACf,CDVA,SAASK,EAAsBC,EAA+B,CAC1D,GAAM,CAACC,EAAQC,CAAS,EACd,WAAwD,IAAI,EAEtE,OAAM,YAAU,IACL,IAAM,CACTD,GAAQ,OAAO,CACnB,EACD,CAACA,CAAM,CAAC,EAEL,YAAU,IAAM,CAClB,GAAI,CAACA,EACD,OAGJ,IAAIE,EAAY,GAChB,OAAC,SAAY,CACT,GAAI,CAACH,EAAM,OAAQ,CACf,MAAMC,EAAO,MAAM,EACnB,MACJ,CAEA,MAAMA,EAAO,KAAKD,EAAM,MAAM,EAC1B,EAAAG,GAAa,CAACH,EAAM,UAIpB,WAAYA,EAAM,OAClB,MAAMC,EAAO,iBAAiBD,EAAM,MAAM,EAE1C,MAAMC,EAAO,QAAQD,EAAM,MAAM,EAEzC,GAAG,EAEI,IAAM,CACTG,EAAY,EAChB,CACJ,EAAG,CAACF,EAAQD,EAAM,OAAQ,KAAK,UAAUA,EAAM,MAAM,CAAC,CAAC,EAEvDI,EAAeH,EAAQ,oBAAqBD,EAAM,OAAO,EACzDI,EAAeH,EAAQ,qBAAsBD,EAAM,QAAQ,EAC3DI,EACIH,EACA,4BACAD,EAAM,eACLK,GAAMA,EAAE,OAAO,UAAU,CAC9B,EAGI,gBAAC,sBACG,IAAKH,EACL,GAAIF,EAAM,GACV,UAAWA,EAAM,UACjB,OAAQA,EAAM,OACd,KAAMA,EAAM,KACZ,MAAOA,EAAM,MACb,SAAUA,EAAM,SAChB,MAAOA,EAAM,MACjB,CAER,CA0BO,IAAMM,EAA4D,OACrEP,CACJ",
6
+ "names": ["React", "React", "usePspListener", "el", "event", "cb", "map", "e", "ctx", "callback", "PerspectiveViewerImpl", "props", "viewer", "setViewer", "cancelled", "usePspListener", "e", "PerspectiveViewer"]
7
7
  }
@@ -1 +1 @@
1
- export declare function usePspListener<A>(el: HTMLElement | undefined | null, event: string, cb?: (x: A) => void): void;
1
+ export declare function usePspListener<A>(el: HTMLElement | undefined | null, event: string, cb?: (x: A) => void, map?: (e: CustomEvent) => A): void;
@@ -6,7 +6,7 @@ import type * as pspViewer from "@perspective-dev/viewer";
6
6
  */
7
7
  export interface PerspectiveViewerProps {
8
8
  client?: psp.Client | Promise<psp.Client> | psp.Table | Promise<psp.Table>;
9
- config?: pspViewer.ViewerConfigUpdate;
9
+ config?: pspViewer.ViewerConfigUpdate | pspViewer.WorkspaceConfigUpdate;
10
10
  onConfigUpdate?: (config: pspViewer.ViewerConfigUpdate) => void;
11
11
  onClick?: (data: pspViewer.PerspectiveClickEventDetail) => void;
12
12
  onSelect?: (data: pspViewer.PerspectiveSelectEventDetail) => void;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@perspective-dev/react",
3
- "version": "4.5.2",
4
- "description": "React component wrappers for `<perspective-viewer>` and `<perspective-workspace>`",
3
+ "version": "5.0.0",
4
+ "description": "React component wrappers for `<perspective-viewer>`",
5
5
  "keywords": [
6
6
  "perspective",
7
7
  "react",
@@ -31,7 +31,6 @@
31
31
  "dependencies": {
32
32
  "@perspective-dev/client": "",
33
33
  "@perspective-dev/viewer": "",
34
- "@perspective-dev/workspace": "",
35
34
  "@types/react": ">17 <20",
36
35
  "react": ">17 <20",
37
36
  "react-dom": ">17 <20"
package/src/index.tsx CHANGED
@@ -21,4 +21,3 @@
21
21
  */
22
22
 
23
23
  export * from "./viewer";
24
- export * from "./workspace";
package/src/utils.tsx CHANGED
@@ -16,11 +16,12 @@ export function usePspListener<A>(
16
16
  el: HTMLElement | undefined | null,
17
17
  event: string,
18
18
  cb?: (x: A) => void,
19
+ map: (e: CustomEvent) => A = (e) => e.detail,
19
20
  ) {
20
21
  React.useEffect(() => {
21
22
  if (!cb || !el) return;
22
23
  const ctx = new AbortController();
23
- const callback = (e: Event) => cb((e as CustomEvent).detail);
24
+ const callback = (e: Event) => cb(map(e as CustomEvent));
24
25
  el?.addEventListener(event, callback, { signal: ctx.signal });
25
26
  return () => ctx.abort();
26
27
  }, [el, cb]);
package/src/viewer.tsx CHANGED
@@ -26,22 +26,42 @@ function PerspectiveViewerImpl(props: PerspectiveViewerProps) {
26
26
  }, [viewer]);
27
27
 
28
28
  React.useEffect(() => {
29
- if (props.client) {
30
- viewer?.load(props.client);
31
- } else {
32
- viewer?.eject();
29
+ if (!viewer) {
30
+ return;
33
31
  }
34
- }, [viewer, props.client]);
35
32
 
36
- React.useEffect(() => {
37
- if (props.client && props.config) {
38
- viewer?.restore(props.config);
39
- }
33
+ let cancelled = false;
34
+ (async () => {
35
+ if (!props.client) {
36
+ await viewer.eject();
37
+ return;
38
+ }
39
+
40
+ await viewer.load(props.client);
41
+ if (cancelled || !props.config) {
42
+ return;
43
+ }
44
+
45
+ if ("panels" in props.config) {
46
+ await viewer.restoreWorkspace(props.config);
47
+ } else {
48
+ await viewer.restore(props.config);
49
+ }
50
+ })();
51
+
52
+ return () => {
53
+ cancelled = true;
54
+ };
40
55
  }, [viewer, props.client, JSON.stringify(props.config)]);
41
56
 
42
57
  usePspListener(viewer, "perspective-click", props.onClick);
43
58
  usePspListener(viewer, "perspective-select", props.onSelect);
44
- usePspListener(viewer, "perspective-config-update", props.onConfigUpdate);
59
+ usePspListener(
60
+ viewer,
61
+ "perspective-config-update",
62
+ props.onConfigUpdate,
63
+ (e) => e.detail.getConfig(),
64
+ );
45
65
 
46
66
  return (
47
67
  <perspective-viewer
@@ -62,7 +82,7 @@ function PerspectiveViewerImpl(props: PerspectiveViewerProps) {
62
82
  */
63
83
  export interface PerspectiveViewerProps {
64
84
  client?: psp.Client | Promise<psp.Client> | psp.Table | Promise<psp.Table>;
65
- config?: pspViewer.ViewerConfigUpdate;
85
+ config?: pspViewer.ViewerConfigUpdate | pspViewer.WorkspaceConfigUpdate;
66
86
  onConfigUpdate?: (config: pspViewer.ViewerConfigUpdate) => void;
67
87
  onClick?: (data: pspViewer.PerspectiveClickEventDetail) => void;
68
88
  onSelect?: (data: pspViewer.PerspectiveSelectEventDetail) => void;
@@ -14,7 +14,6 @@ import perspective from "@perspective-dev/client";
14
14
  import perspective_viewer from "@perspective-dev/viewer";
15
15
  import "@perspective-dev/viewer-datagrid";
16
16
  import "@perspective-dev/viewer-charts";
17
- import "@perspective-dev/workspace";
18
17
 
19
18
  // @ts-ignore
20
19
  import SERVER_WASM from "@perspective-dev/server/dist/wasm/perspective-server.wasm?url";
@@ -36,7 +35,6 @@ import SUPERSTORE_ARROW from "superstore-arrow/superstore.lz4.arrow?url";
36
35
  import * as React from "react";
37
36
  import {
38
37
  PerspectiveViewer,
39
- PerspectiveWorkspace,
40
38
  } from "@perspective-dev/react";
41
39
 
42
40
  import "@perspective-dev/viewer/dist/css/themes.css";
package/test/js/index.css CHANGED
@@ -62,7 +62,7 @@ button {
62
62
  flex-direction: row;
63
63
  }
64
64
 
65
- perspective-workspace {
65
+ perspective-viewer {
66
66
  height: 100vh;
67
67
  }
68
68
  }
@@ -30,19 +30,19 @@ test.describe("Perspective React", () => {
30
30
  const comp = await mount(<EmptyWorkspace />);
31
31
  const toggleMount = comp.locator("button.toggle-mount");
32
32
  const addViewer = comp.locator("button.add-viewer");
33
- const workspace = comp.locator("perspective-workspace");
34
- const viewer = comp.locator("perspective-viewer");
33
+ const workspace = comp.locator("perspective-viewer");
35
34
  await toggleMount.waitFor();
36
35
  await addViewer.click();
37
36
  await addViewer.click();
38
37
  await addViewer.click();
39
38
  await page.waitForFunction(
40
- () =>
41
- document.querySelector("perspective-workspace")!.children
42
- .length === 3,
39
+ (expected) =>
40
+ (
41
+ document.querySelector("perspective-viewer") as any
42
+ )?.getPanelNames?.().length === expected,
43
+ 3,
43
44
  );
44
45
 
45
- await expect(viewer).toHaveCount(3);
46
46
  await toggleMount.click();
47
47
  await workspace.waitFor({ state: "detached" });
48
48
 
@@ -51,43 +51,40 @@ test.describe("Perspective React", () => {
51
51
  await toggleMount.click();
52
52
  await workspace.waitFor();
53
53
  await page.waitForFunction(
54
- () =>
55
- document.querySelector("perspective-workspace")!.children
56
- .length === 3,
54
+ (expected) =>
55
+ (
56
+ document.querySelector("perspective-viewer") as any
57
+ )?.getPanelNames?.().length === expected,
58
+ 3,
57
59
  );
58
- await expect(viewer).toHaveCount(3);
59
60
  });
60
61
 
61
- test("Adding a viewer in single-document mode leaves SDM", async ({
62
- page,
63
- mount,
64
- }) => {
62
+ test("Adding a panel to a lone-panel viewer", async ({ page, mount }) => {
65
63
  const name = "abcdef";
66
64
  const comp = await mount(<SingleView name={name} />);
67
65
  const addViewer = comp.locator("button.add-viewer");
68
- const viewer = comp.locator("perspective-viewer");
69
- const settingsBtn = comp.locator(`perspective-viewer #settings_button`);
66
+ const settingsBtn = comp.locator(
67
+ `perspective-viewer perspective-viewer-tab .psp-tab-settings`,
68
+ );
70
69
 
71
70
  await settingsBtn.waitFor();
72
71
  await addViewer.waitFor();
73
72
  await addViewer.click();
74
73
  await page.waitForFunction(
75
- () =>
76
- document.querySelector("perspective-workspace")!.children
77
- .length === 2,
74
+ (expected) =>
75
+ (
76
+ document.querySelector("perspective-viewer") as any
77
+ )?.getPanelNames?.().length === expected,
78
+ 2,
78
79
  );
79
80
 
80
- expect(await viewer.count()).toBe(2);
81
- await settingsBtn.first().click();
82
- const settingsPanel = viewer.locator("#settings_panel");
83
- await settingsPanel.waitFor();
84
81
  await addViewer.click();
85
82
  await page.waitForFunction(
86
- () =>
87
- document.querySelector("perspective-workspace")!.children
88
- .length === 3,
83
+ (expected) =>
84
+ (
85
+ document.querySelector("perspective-viewer") as any
86
+ )?.getPanelNames?.().length === expected,
87
+ 3,
89
88
  );
90
- expect(await viewer.count()).toBe(3);
91
- await settingsPanel.waitFor({ state: "detached" });
92
89
  });
93
90
  });
@@ -9,27 +9,19 @@
9
9
  // ┃ This file is part of the Perspective library, distributed under the terms ┃
10
10
  // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
11
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
- import "@perspective-dev/workspace";
13
-
14
- import {
15
- HTMLPerspectiveWorkspaceElement,
16
- PerspectiveWorkspaceConfig,
17
- } from "@perspective-dev/workspace";
18
12
 
19
13
  import * as React from "react";
20
14
 
21
- import { PerspectiveWorkspace } from "@perspective-dev/react";
15
+ import { PerspectiveViewer } from "@perspective-dev/react";
22
16
 
23
17
  import perspective_viewer from "@perspective-dev/viewer";
18
+ import type { ViewerConfigUpdate } from "@perspective-dev/viewer";
24
19
  import "@perspective-dev/viewer-datagrid";
25
20
  import "@perspective-dev/viewer-charts";
26
- import "@perspective-dev/workspace";
27
- import * as Workspace from "@perspective-dev/workspace";
28
21
 
29
22
  import * as perspective from "@perspective-dev/client";
30
23
 
31
24
  import "@perspective-dev/viewer/dist/css/themes.css";
32
- import "@perspective-dev/workspace/dist/css/pro.css";
33
25
  import "./index.css";
34
26
 
35
27
  // @ts-ignore
@@ -45,19 +37,51 @@ await Promise.all([
45
37
 
46
38
  const CLIENT = await perspective.worker();
47
39
 
40
+ /// The merged `<perspective-viewer>` whole-element config: a `regular-layout`
41
+ /// tree + a per-panel `ViewerConfig` map. (Formerly
42
+ /// `@perspective-dev/workspace`'s `PerspectiveWorkspaceConfig`.)
43
+ interface MultiPanelConfig {
44
+ layout?: Record<string, unknown>;
45
+ panels: Record<string, Record<string, unknown>>;
46
+ }
47
+
48
+ /// Append a panel, re-deriving an even horizontal split of one stack per
49
+ /// panel. (Formerly `Workspace.addViewer`.)
50
+ function addPanel(
51
+ config: MultiPanelConfig,
52
+ panel: Record<string, unknown>,
53
+ id: string,
54
+ ): MultiPanelConfig {
55
+ const panels = { ...config.panels, [id]: panel };
56
+ const ids = Object.keys(panels);
57
+ return {
58
+ layout: {
59
+ type: "split-layout",
60
+ orientation: "horizontal",
61
+ sizes: ids.map(() => 1 / ids.length),
62
+ children: ids.map((k) => ({
63
+ type: "tab-layout",
64
+ tabs: [k],
65
+ selected: 0,
66
+ })),
67
+ },
68
+ panels,
69
+ };
70
+ }
71
+
48
72
  interface WorkspaceState {
49
- layout: PerspectiveWorkspaceConfig;
73
+ config: MultiPanelConfig;
50
74
  mounted: boolean;
51
75
  }
52
76
 
53
77
  interface WorkspaceAppProps {
54
- layout: PerspectiveWorkspaceConfig;
78
+ config: MultiPanelConfig;
55
79
  onSpecial?: () => void;
56
80
  }
57
81
 
58
82
  const WorkspaceApp: React.FC<WorkspaceAppProps> = (props) => {
59
83
  const [state, setState] = React.useState<WorkspaceState>({
60
- layout: props.layout,
84
+ config: props.config,
61
85
  mounted: true,
62
86
  });
63
87
 
@@ -65,35 +89,30 @@ const WorkspaceApp: React.FC<WorkspaceAppProps> = (props) => {
65
89
  const name = window.crypto.randomUUID();
66
90
  const data = `a,b,c\n${Math.random()},${Math.random()},${Math.random()}`;
67
91
  CLIENT.table(data, { name });
68
- const nextId = Workspace.genId(state.layout);
69
- const layout = Workspace.addViewer(
70
- state.layout,
92
+ const config = addPanel(
93
+ state.config,
71
94
  {
72
95
  table: name,
73
96
  title: name,
74
97
  },
75
- nextId,
98
+ name,
76
99
  );
77
100
 
78
101
  setState({
79
102
  ...state,
80
- layout,
103
+ config,
81
104
  });
82
105
  };
83
106
 
84
107
  const onClickToggleMount = () =>
85
108
  setState((old) => ({ ...old, mounted: !state.mounted }));
86
109
 
87
- const onLayoutUpdate = (layout: PerspectiveWorkspaceConfig) => {
88
- setState({ ...state, layout });
89
- };
90
-
91
110
  React.useEffect(() => {
92
111
  setState((s) => ({
93
112
  ...s,
94
- layout: props.layout,
113
+ config: props.config,
95
114
  }));
96
- }, [props.layout]);
115
+ }, [props.config]);
97
116
 
98
117
  return (
99
118
  <div className="workspace-container">
@@ -111,37 +130,30 @@ const WorkspaceApp: React.FC<WorkspaceAppProps> = (props) => {
111
130
  )}
112
131
  </div>
113
132
  {state.mounted && (
114
- <PerspectiveWorkspace
133
+ <PerspectiveViewer
115
134
  client={CLIENT}
116
- layout={state.layout}
117
- onLayoutUpdate={onLayoutUpdate}
135
+ config={state.config as unknown as ViewerConfigUpdate}
118
136
  />
119
137
  )}
120
138
  </div>
121
139
  );
122
140
  };
123
141
 
124
- /// Renders the app with a default empty workspace
142
+ /// Renders the app with a default empty workspace (a multi-panel viewer always
143
+ /// has at least one — empty — seed panel).
125
144
  export const EmptyWorkspace: React.FC = () => {
126
- return (
127
- <WorkspaceApp
128
- layout={{ sizes: [1], viewers: {}, detail: { main: null } }}
129
- />
130
- );
145
+ return <WorkspaceApp config={{ panels: {} }} />;
131
146
  };
132
147
 
133
148
  export const SingleView: React.FC<{ name: string }> = ({ name }) => {
134
149
  const _table = CLIENT.table("a,b,c\n1,2,3", { name });
135
- const layout: PerspectiveWorkspaceConfig = {
136
- sizes: [1],
137
- detail: {
138
- main: {
139
- type: "tab-area",
140
- currentIndex: 0,
141
- widgets: [name],
142
- },
150
+ const config: MultiPanelConfig = {
151
+ layout: {
152
+ type: "tab-layout",
153
+ tabs: [name],
154
+ selected: 0,
143
155
  },
144
- viewers: {
156
+ panels: {
145
157
  [name]: {
146
158
  table: name,
147
159
  columns: ["a", "b", "c"],
@@ -150,5 +162,5 @@ export const SingleView: React.FC<{ name: string }> = ({ name }) => {
150
162
  },
151
163
  };
152
164
 
153
- return <WorkspaceApp layout={layout} />;
165
+ return <WorkspaceApp config={config} />;
154
166
  };
@@ -1,21 +0,0 @@
1
- import type * as psp from "@perspective-dev/client";
2
- import type * as psp_viewer from "@perspective-dev/viewer";
3
- import type * as pspWorkspace from "@perspective-dev/workspace";
4
- import { PerspectiveWorkspaceConfig } from "@perspective-dev/workspace";
5
- import * as React from "react";
6
- export interface NewViewEventDetail {
7
- config: psp_viewer.ViewerConfigUpdate;
8
- widget: pspWorkspace.PerspectiveViewerWidget;
9
- }
10
- export interface ToggleGloalFilterEventDetail {
11
- widget: pspWorkspace.PerspectiveViewerWidget;
12
- isGlobalFilter: boolean;
13
- }
14
- export interface PerspectiveWorkspaceProps extends React.HTMLAttributes<HTMLElement> {
15
- client: psp.Client | Promise<psp.Client>;
16
- layout: PerspectiveWorkspaceConfig;
17
- onLayoutUpdate?: (layout: PerspectiveWorkspaceConfig) => void;
18
- onNewView?: (detail: NewViewEventDetail) => void;
19
- onToggleGlobalFilter?: (detail: ToggleGloalFilterEventDetail) => void;
20
- }
21
- export declare const PerspectiveWorkspace: React.NamedExoticComponent<PerspectiveWorkspaceProps & React.RefAttributes<pspWorkspace.HTMLPerspectiveWorkspaceElement | undefined>>;
package/src/workspace.tsx DELETED
@@ -1,95 +0,0 @@
1
- // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2
- // ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
3
- // ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
4
- // ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
5
- // ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
6
- // ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7
- // ┃ Copyright (c) 2017, the Perspective Authors. ┃
8
- // ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9
- // ┃ This file is part of the Perspective library, distributed under the terms ┃
10
- // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
- // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
-
13
- import type * as psp from "@perspective-dev/client";
14
- import type * as psp_viewer from "@perspective-dev/viewer";
15
- import type * as pspWorkspace from "@perspective-dev/workspace";
16
- import { PerspectiveWorkspaceConfig } from "@perspective-dev/workspace";
17
- import * as utils from "./utils";
18
- import * as React from "react";
19
-
20
- export interface NewViewEventDetail {
21
- config: psp_viewer.ViewerConfigUpdate;
22
- widget: pspWorkspace.PerspectiveViewerWidget;
23
- }
24
-
25
- export interface ToggleGloalFilterEventDetail {
26
- widget: pspWorkspace.PerspectiveViewerWidget;
27
- isGlobalFilter: boolean;
28
- }
29
-
30
- export interface PerspectiveWorkspaceProps
31
- extends React.HTMLAttributes<HTMLElement> {
32
- client: psp.Client | Promise<psp.Client>;
33
- layout: PerspectiveWorkspaceConfig;
34
- onLayoutUpdate?: (layout: PerspectiveWorkspaceConfig) => void;
35
- onNewView?: (detail: NewViewEventDetail) => void;
36
- onToggleGlobalFilter?: (detail: ToggleGloalFilterEventDetail) => void;
37
- }
38
-
39
- const PerspectiveWorkspaceImpl = React.forwardRef<
40
- pspWorkspace.HTMLPerspectiveWorkspaceElement | undefined,
41
- PerspectiveWorkspaceProps
42
- >(
43
- (
44
- {
45
- client,
46
- layout,
47
- onLayoutUpdate,
48
- onNewView,
49
- onToggleGlobalFilter,
50
- ...htmlAttributes
51
- },
52
- ref,
53
- ) => {
54
- const [workspace, setWorkspace] =
55
- React.useState<pspWorkspace.HTMLPerspectiveWorkspaceElement>();
56
-
57
- React.useImperativeHandle(ref, () => workspace, [workspace]);
58
- React.useEffect(() => {
59
- if (workspace && layout) {
60
- workspace.restore(layout);
61
- }
62
- }, [workspace, layout]);
63
-
64
- React.useEffect(() => {
65
- if (workspace && client) {
66
- workspace.load(client);
67
- }
68
- }, [workspace, client]);
69
-
70
- utils.usePspListener(workspace, "workspace-new-view", onNewView);
71
- utils.usePspListener(
72
- workspace,
73
- "workspace-layout-update",
74
- onLayoutUpdate
75
- ? ({ layout }: { layout: PerspectiveWorkspaceConfig }) =>
76
- workspace?.save().then((x) => onLayoutUpdate(x))
77
- : undefined,
78
- );
79
-
80
- utils.usePspListener(
81
- workspace,
82
- "workspace-toggle-global-filter",
83
- onToggleGlobalFilter,
84
- );
85
-
86
- return (
87
- <perspective-workspace
88
- ref={(r) => setWorkspace(r ?? undefined)}
89
- {...htmlAttributes}
90
- ></perspective-workspace>
91
- );
92
- },
93
- );
94
-
95
- export const PerspectiveWorkspace = React.memo(PerspectiveWorkspaceImpl);