@genesislcap/foundation-react-utils 15.46.2-FUI-2628.2 → 15.46.2-FUI-2628.3
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.
- package/README.md +18 -0
- package/dist/custom-elements.json +57 -0
- package/dist/dts/workspace/index.d.ts +4 -1
- package/dist/dts/workspace/index.d.ts.map +1 -1
- package/dist/dts/workspace/use-workspace-flex-layout.d.ts +34 -0
- package/dist/dts/workspace/use-workspace-flex-layout.d.ts.map +1 -0
- package/dist/esm/workspace/index.js +4 -1
- package/dist/esm/workspace/use-workspace-flex-layout.js +84 -0
- package/package.json +13 -13
package/README.md
CHANGED
|
@@ -88,6 +88,24 @@ registerFactory('positions', reactFactory(PositionsPanel));
|
|
|
88
88
|
- `useWorkspaceFilter` also applies the current workspace's saved value on mount, so a filter
|
|
89
89
|
inside a pane that is recreated by a layout load still picks up its saved value.
|
|
90
90
|
|
|
91
|
+
### flexlayout-react layouts
|
|
92
|
+
|
|
93
|
+
`LayoutWrapper` only covers `rapid-layout`. For a flexlayout-react layout, hold the `Model` in
|
|
94
|
+
state and register it with `useWorkspaceFlexLayout`; loading a workspace hands you a new model:
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
import { Layout, Model } from '@genesislcap/foundation-react-utils/flexlayout';
|
|
98
|
+
import { useWorkspaceFlexLayout } from '@genesislcap/foundation-react-utils/workspace';
|
|
99
|
+
|
|
100
|
+
const [model, setModel] = useState(() => Model.fromJson(defaultLayout));
|
|
101
|
+
useWorkspaceFlexLayout('home-layout', model, setModel);
|
|
102
|
+
|
|
103
|
+
return <Layout model={model} factory={factory} />;
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Tabs opened or closed by a loaded layout mount and unmount as usual, so `GridRegister` and
|
|
107
|
+
`useWorkspaceFilter` inside them pick up the workspace's state as they register.
|
|
108
|
+
|
|
91
109
|
## License
|
|
92
110
|
|
|
93
111
|
Note: this project provides front-end dependencies and uses licensed components listed in the next section; thus, licenses for those components are required during development. Contact [Genesis Global](https://genesis.global/contact-us/) for more details.
|
|
@@ -544,6 +544,14 @@
|
|
|
544
544
|
"name": "useWorkspaceFilter",
|
|
545
545
|
"module": "./use-workspace-filter"
|
|
546
546
|
}
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
"kind": "js",
|
|
550
|
+
"name": "useWorkspaceFlexLayout",
|
|
551
|
+
"declaration": {
|
|
552
|
+
"name": "useWorkspaceFlexLayout",
|
|
553
|
+
"module": "./use-workspace-flex-layout"
|
|
554
|
+
}
|
|
547
555
|
}
|
|
548
556
|
]
|
|
549
557
|
},
|
|
@@ -595,6 +603,55 @@
|
|
|
595
603
|
}
|
|
596
604
|
}
|
|
597
605
|
]
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
"kind": "javascript-module",
|
|
609
|
+
"path": "src/workspace/use-workspace-flex-layout.ts",
|
|
610
|
+
"declarations": [
|
|
611
|
+
{
|
|
612
|
+
"kind": "function",
|
|
613
|
+
"name": "useWorkspaceFlexLayout",
|
|
614
|
+
"return": {
|
|
615
|
+
"type": {
|
|
616
|
+
"text": "void"
|
|
617
|
+
}
|
|
618
|
+
},
|
|
619
|
+
"parameters": [
|
|
620
|
+
{
|
|
621
|
+
"name": "layoutKey",
|
|
622
|
+
"type": {
|
|
623
|
+
"text": "string"
|
|
624
|
+
},
|
|
625
|
+
"description": "Unique key the layout is saved under. An empty key skips registration."
|
|
626
|
+
},
|
|
627
|
+
{
|
|
628
|
+
"name": "model",
|
|
629
|
+
"type": {
|
|
630
|
+
"text": "Model"
|
|
631
|
+
},
|
|
632
|
+
"description": "The model currently rendered by `<Layout>`."
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
"name": "setModel",
|
|
636
|
+
"type": {
|
|
637
|
+
"text": "(model: Model) => void"
|
|
638
|
+
},
|
|
639
|
+
"description": "Called with a new model when a workspace is loaded."
|
|
640
|
+
}
|
|
641
|
+
],
|
|
642
|
+
"description": "Registers a flexlayout-react `Model` with the foundation-workspace `LayoutRegistry`, so\n`<workspace-manager>` saves the layout (which tabs are open, how they're split and sized, which\nis selected) with the workspace and restores it on load."
|
|
643
|
+
}
|
|
644
|
+
],
|
|
645
|
+
"exports": [
|
|
646
|
+
{
|
|
647
|
+
"kind": "js",
|
|
648
|
+
"name": "useWorkspaceFlexLayout",
|
|
649
|
+
"declaration": {
|
|
650
|
+
"name": "useWorkspaceFlexLayout",
|
|
651
|
+
"module": "src/workspace/use-workspace-flex-layout.ts"
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
]
|
|
598
655
|
}
|
|
599
656
|
]
|
|
600
657
|
}
|
|
@@ -7,13 +7,16 @@
|
|
|
7
7
|
* Exposed as a subpath (`/workspace`) rather than from the package root so that consumers which
|
|
8
8
|
* don't use workspaces don't load foundation-workspace (and the grid-pro graph behind it).
|
|
9
9
|
*
|
|
10
|
-
* Grids,
|
|
10
|
+
* Grids, `rapid-layout` and the save/load UI need no hook: use the element wrappers from
|
|
11
11
|
* `@genesislcap/foundation-workspace/react` (`GridRegister`, `LayoutWrapper`, `WorkspaceManager`).
|
|
12
12
|
* Inside a `rapid-layout`, render panes through `registerFactory` + `reactFactory` rather than as
|
|
13
13
|
* JSX children, because loading a saved layout rebuilds panes and cloned DOM loses React state.
|
|
14
14
|
*
|
|
15
15
|
* Key exports:
|
|
16
16
|
* - `useWorkspaceFilter` — register React filter state so workspaces save and restore it.
|
|
17
|
+
* - `useWorkspaceFlexLayout` — register a flexlayout-react `Model` so workspaces save and restore
|
|
18
|
+
* the layout.
|
|
17
19
|
*/
|
|
18
20
|
export { useWorkspaceFilter } from './use-workspace-filter';
|
|
21
|
+
export { useWorkspaceFlexLayout } from './use-workspace-flex-layout';
|
|
19
22
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/workspace/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/workspace/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Model } from 'flexlayout-react';
|
|
2
|
+
/**
|
|
3
|
+
* Registers a flexlayout-react `Model` with the foundation-workspace `LayoutRegistry`, so
|
|
4
|
+
* `<workspace-manager>` saves the layout (which tabs are open, how they're split and sized, which
|
|
5
|
+
* is selected) with the workspace and restores it on load.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* The React counterpart of `LayoutWrapper` (`layout-register`), which only covers `rapid-layout`.
|
|
9
|
+
* A workspace stores the model's `toJson()`; loading one builds a new model with `Model.fromJson`
|
|
10
|
+
* and hands it to `setModel`, so the app renders `<Layout model={model} />` from state.
|
|
11
|
+
*
|
|
12
|
+
* - Registers on mount and unregisters on unmount (or when `layoutKey` changes). Registering
|
|
13
|
+
* applies the layout's stored config straight away, when a workspace loaded earlier has one.
|
|
14
|
+
* - The registry always reads the latest `model` and calls the latest `setModel`, so neither needs
|
|
15
|
+
* to be memoised.
|
|
16
|
+
* - Tabs that a loaded layout closes unmount, and ones it opens mount: their grids and filters
|
|
17
|
+
* (`GridRegister`, `useWorkspaceFilter`) pick up the workspace's state as they register.
|
|
18
|
+
* - A saved config that flexlayout-react can't read is logged and ignored; the current layout
|
|
19
|
+
* stays.
|
|
20
|
+
*
|
|
21
|
+
* @param layoutKey - Unique key the layout is saved under. An empty key skips registration.
|
|
22
|
+
* @param model - The model currently rendered by `<Layout>`.
|
|
23
|
+
* @param setModel - Called with a new model when a workspace is loaded.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* const [model, setModel] = useState(() => Model.fromJson(defaultLayout));
|
|
28
|
+
* useWorkspaceFlexLayout('home-layout', model, setModel);
|
|
29
|
+
* return <Layout model={model} factory={factory} />;
|
|
30
|
+
* ```
|
|
31
|
+
* @alpha
|
|
32
|
+
*/
|
|
33
|
+
export declare function useWorkspaceFlexLayout(layoutKey: string, model: Model, setModel: (model: Model) => void): void;
|
|
34
|
+
//# sourceMappingURL=use-workspace-flex-layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-workspace-flex-layout.d.ts","sourceRoot":"","sources":["../../../src/workspace/use-workspace-flex-layout.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAmB,MAAM,kBAAkB,CAAC;AAG1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAC/B,IAAI,CAkCN"}
|
|
@@ -7,12 +7,15 @@
|
|
|
7
7
|
* Exposed as a subpath (`/workspace`) rather than from the package root so that consumers which
|
|
8
8
|
* don't use workspaces don't load foundation-workspace (and the grid-pro graph behind it).
|
|
9
9
|
*
|
|
10
|
-
* Grids,
|
|
10
|
+
* Grids, `rapid-layout` and the save/load UI need no hook: use the element wrappers from
|
|
11
11
|
* `@genesislcap/foundation-workspace/react` (`GridRegister`, `LayoutWrapper`, `WorkspaceManager`).
|
|
12
12
|
* Inside a `rapid-layout`, render panes through `registerFactory` + `reactFactory` rather than as
|
|
13
13
|
* JSX children, because loading a saved layout rebuilds panes and cloned DOM loses React state.
|
|
14
14
|
*
|
|
15
15
|
* Key exports:
|
|
16
16
|
* - `useWorkspaceFilter` — register React filter state so workspaces save and restore it.
|
|
17
|
+
* - `useWorkspaceFlexLayout` — register a flexlayout-react `Model` so workspaces save and restore
|
|
18
|
+
* the layout.
|
|
17
19
|
*/
|
|
18
20
|
export { useWorkspaceFilter } from './use-workspace-filter';
|
|
21
|
+
export { useWorkspaceFlexLayout } from './use-workspace-flex-layout';
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { LayoutRegistry } from '@genesislcap/foundation-workspace';
|
|
2
|
+
import { DI } from '@genesislcap/web-core';
|
|
3
|
+
import { Model } from 'flexlayout-react';
|
|
4
|
+
import { useEffect, useLayoutEffect, useRef } from 'react';
|
|
5
|
+
/**
|
|
6
|
+
* Registers a flexlayout-react `Model` with the foundation-workspace `LayoutRegistry`, so
|
|
7
|
+
* `<workspace-manager>` saves the layout (which tabs are open, how they're split and sized, which
|
|
8
|
+
* is selected) with the workspace and restores it on load.
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* The React counterpart of `LayoutWrapper` (`layout-register`), which only covers `rapid-layout`.
|
|
12
|
+
* A workspace stores the model's `toJson()`; loading one builds a new model with `Model.fromJson`
|
|
13
|
+
* and hands it to `setModel`, so the app renders `<Layout model={model} />` from state.
|
|
14
|
+
*
|
|
15
|
+
* - Registers on mount and unregisters on unmount (or when `layoutKey` changes). Registering
|
|
16
|
+
* applies the layout's stored config straight away, when a workspace loaded earlier has one.
|
|
17
|
+
* - The registry always reads the latest `model` and calls the latest `setModel`, so neither needs
|
|
18
|
+
* to be memoised.
|
|
19
|
+
* - Tabs that a loaded layout closes unmount, and ones it opens mount: their grids and filters
|
|
20
|
+
* (`GridRegister`, `useWorkspaceFilter`) pick up the workspace's state as they register.
|
|
21
|
+
* - A saved config that flexlayout-react can't read is logged and ignored; the current layout
|
|
22
|
+
* stays.
|
|
23
|
+
*
|
|
24
|
+
* @param layoutKey - Unique key the layout is saved under. An empty key skips registration.
|
|
25
|
+
* @param model - The model currently rendered by `<Layout>`.
|
|
26
|
+
* @param setModel - Called with a new model when a workspace is loaded.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```tsx
|
|
30
|
+
* const [model, setModel] = useState(() => Model.fromJson(defaultLayout));
|
|
31
|
+
* useWorkspaceFlexLayout('home-layout', model, setModel);
|
|
32
|
+
* return <Layout model={model} factory={factory} />;
|
|
33
|
+
* ```
|
|
34
|
+
* @alpha
|
|
35
|
+
*/
|
|
36
|
+
export function useWorkspaceFlexLayout(layoutKey, model, setModel) {
|
|
37
|
+
const latest = useRef({ model, setModel });
|
|
38
|
+
useLayoutEffect(() => {
|
|
39
|
+
latest.current = { model, setModel };
|
|
40
|
+
});
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (!layoutKey) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
const layoutRegistry = DI.getOrCreateDOMContainer().get(LayoutRegistry);
|
|
46
|
+
const layout = {
|
|
47
|
+
// A flexlayout Model is complete as soon as it exists; there's no first load to wait for.
|
|
48
|
+
hasFirstLoaded: true,
|
|
49
|
+
getLayout: () => latest.current.model.toJson(),
|
|
50
|
+
loadLayout: (saved) => {
|
|
51
|
+
const next = readModel(saved);
|
|
52
|
+
if (next) {
|
|
53
|
+
latest.current.setModel(next);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
console.warn(`useWorkspaceFlexLayout: ignoring unreadable layout for ${layoutKey}`);
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
addEventListener: () => { },
|
|
60
|
+
};
|
|
61
|
+
layoutRegistry.registerLayout(layoutKey, layout);
|
|
62
|
+
return () => {
|
|
63
|
+
layoutRegistry.unregisterLayout(layoutKey);
|
|
64
|
+
};
|
|
65
|
+
}, [layoutKey]);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Builds a model from a saved flexlayout config, or returns null for anything else — e.g. a
|
|
69
|
+
* `rapid-layout` config saved under the same key. `Model.fromJson` doesn't validate: it builds a
|
|
70
|
+
* broken model from malformed JSON rather than throwing.
|
|
71
|
+
*/
|
|
72
|
+
function readModel(saved) {
|
|
73
|
+
const json = saved;
|
|
74
|
+
const root = json === null || json === void 0 ? void 0 : json.layout;
|
|
75
|
+
if (!root || typeof root !== 'object' || typeof root.type !== 'string') {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
return Model.fromJson(json);
|
|
80
|
+
}
|
|
81
|
+
catch (_a) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genesislcap/foundation-react-utils",
|
|
3
3
|
"description": "Genesis Foundation React Utils",
|
|
4
|
-
"version": "15.46.2-FUI-2628.
|
|
4
|
+
"version": "15.46.2-FUI-2628.3",
|
|
5
5
|
"sideEffects": [
|
|
6
6
|
"./dist/esm/flexlayout/index.js"
|
|
7
7
|
],
|
|
@@ -63,12 +63,12 @@
|
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@genesislcap/foundation-testing": "15.46.2-FUI-2628.
|
|
67
|
-
"@genesislcap/genx": "15.46.2-FUI-2628.
|
|
68
|
-
"@genesislcap/ts-builder": "15.46.2-FUI-2628.
|
|
69
|
-
"@genesislcap/uvu-playwright-builder": "15.46.2-FUI-2628.
|
|
70
|
-
"@genesislcap/vite-builder": "15.46.2-FUI-2628.
|
|
71
|
-
"@genesislcap/webpack-builder": "15.46.2-FUI-2628.
|
|
66
|
+
"@genesislcap/foundation-testing": "15.46.2-FUI-2628.3",
|
|
67
|
+
"@genesislcap/genx": "15.46.2-FUI-2628.3",
|
|
68
|
+
"@genesislcap/ts-builder": "15.46.2-FUI-2628.3",
|
|
69
|
+
"@genesislcap/uvu-playwright-builder": "15.46.2-FUI-2628.3",
|
|
70
|
+
"@genesislcap/vite-builder": "15.46.2-FUI-2628.3",
|
|
71
|
+
"@genesislcap/webpack-builder": "15.46.2-FUI-2628.3",
|
|
72
72
|
"react-router-dom": "^7.1.3"
|
|
73
73
|
},
|
|
74
74
|
"peerDependencies": {
|
|
@@ -82,12 +82,12 @@
|
|
|
82
82
|
}
|
|
83
83
|
},
|
|
84
84
|
"dependencies": {
|
|
85
|
-
"@genesislcap/foundation-forms": "15.46.2-FUI-2628.
|
|
86
|
-
"@genesislcap/foundation-layout": "15.46.2-FUI-2628.
|
|
87
|
-
"@genesislcap/foundation-logger": "15.46.2-FUI-2628.
|
|
88
|
-
"@genesislcap/foundation-workspace": "15.46.2-FUI-2628.
|
|
89
|
-
"@genesislcap/rapid-design-system": "15.46.2-FUI-2628.
|
|
90
|
-
"@genesislcap/web-core": "15.46.2-FUI-2628.
|
|
85
|
+
"@genesislcap/foundation-forms": "15.46.2-FUI-2628.3",
|
|
86
|
+
"@genesislcap/foundation-layout": "15.46.2-FUI-2628.3",
|
|
87
|
+
"@genesislcap/foundation-logger": "15.46.2-FUI-2628.3",
|
|
88
|
+
"@genesislcap/foundation-workspace": "15.46.2-FUI-2628.3",
|
|
89
|
+
"@genesislcap/rapid-design-system": "15.46.2-FUI-2628.3",
|
|
90
|
+
"@genesislcap/web-core": "15.46.2-FUI-2628.3",
|
|
91
91
|
"@jsonforms/core": "^3.2.1",
|
|
92
92
|
"@r2wc/core": "1.3.1",
|
|
93
93
|
"@r2wc/react-to-web-component": "^2.0.2",
|