@sqlrooms/room-shell 0.26.0-rc.5 → 0.26.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.
package/README.md CHANGED
@@ -43,57 +43,47 @@ The room-shell package uses Zustand for state management. You can create a custo
43
43
  import {
44
44
  createRoomShellSlice,
45
45
  createRoomStore,
46
- RoomState,
47
- BaseRoomConfig,
46
+ RoomShellSliceState,
48
47
  } from '@sqlrooms/room-shell';
49
- import {z} from 'zod';
50
-
51
- // Define your custom config schema (optional)
52
- const MyRoomConfig = BaseRoomConfig.extend({
53
- myCustomSetting: z.string().default('default value'),
54
- });
55
- type MyRoomConfig = z.infer<typeof MyRoomConfig>;
56
48
 
57
49
  // Define your custom app state
58
- type MyRoomState = RoomState<MyRoomConfig> & {
50
+ type MyRoomState = RoomShellSliceState & {
59
51
  myFeatureData: any[];
60
52
  addItem: (item: any) => void;
61
53
  removeItem: (id: string) => void;
62
54
  };
63
55
 
64
56
  // Create a room store with custom state
65
- export const {roomStore, useRoomStore} = createRoomStore<
66
- MyRoomConfig,
67
- MyRoomState
68
- >((set, get, store) => ({
69
- // Base room slice with initial configuration
70
- ...createRoomShellSlice<MyRoomConfig>({
71
- config: {
72
- title: 'My Room',
73
- layout: {
74
- /* layout configuration */
57
+ export const {roomStore, useRoomStore} = createRoomStore<MyRoomState>(
58
+ (set, get, store) => ({
59
+ // Base room slice with initial configuration
60
+ ...createRoomShellSlice({
61
+ config: {
62
+ title: 'My Room',
63
+ dataSources: [],
75
64
  },
76
- dataSources: [],
77
- myCustomSetting: 'custom value',
78
- },
79
- room: {
80
- panels: {
81
- /* panel definitions */
65
+ layout: {
66
+ config: {
67
+ /* layout configuration */
68
+ },
69
+ panels: {
70
+ /* panel definitions */
71
+ },
82
72
  },
83
- },
84
- })(set, get, store),
85
-
86
- // Custom state and actions
87
- myFeatureData: [],
88
- addItem: (item) =>
89
- set((state) => ({
90
- myFeatureData: [...state.myFeatureData, item],
91
- })),
92
- removeItem: (id) =>
93
- set((state) => ({
94
- myFeatureData: state.myFeatureData.filter((item) => item.id !== id),
95
- })),
96
- }));
73
+ })(set, get, store),
74
+
75
+ // Custom state and actions
76
+ myFeatureData: [],
77
+ addItem: (item) =>
78
+ set((state) => ({
79
+ myFeatureData: [...state.myFeatureData, item],
80
+ })),
81
+ removeItem: (id) =>
82
+ set((state) => ({
83
+ myFeatureData: state.myFeatureData.filter((item) => item.id !== id),
84
+ })),
85
+ }),
86
+ );
97
87
 
98
88
  // Use the store in a component with selector for better performance
99
89
  function MyComponent() {
@@ -122,41 +112,33 @@ import {persist} from 'zustand/middleware';
122
112
  import {
123
113
  createRoomShellSlice,
124
114
  createRoomStore,
125
- RoomState,
115
+ RoomShellSliceState,
126
116
  BaseRoomConfig,
117
+ LayoutConfig,
118
+ createPersistHelpers,
119
+ StateCreator,
127
120
  } from '@sqlrooms/room-shell';
128
- import {z} from 'zod';
129
-
130
- // Define your custom config schema
131
- const MyRoomConfig = BaseRoomConfig.extend({
132
- myCustomSetting: z.string().default('default value'),
133
- });
134
- type MyRoomConfig = z.infer<typeof MyRoomConfig>;
135
121
 
136
122
  // Define your custom app state
137
- type MyRoomState = RoomState<MyRoomConfig> & {
123
+ type MyRoomState = RoomShellSliceState & {
138
124
  myFeatureData: any[];
139
125
  addItem: (item: any) => void;
140
126
  };
141
127
 
142
128
  // Create a store with persistence
143
- export const {roomStore, useRoomStore} = createRoomStore<
144
- MyRoomConfig,
145
- MyRoomState
146
- >(
129
+ export const {roomStore, useRoomStore} = createRoomStore<MyRoomState>(
147
130
  persist(
148
131
  (set, get, store) => ({
149
132
  // Base room slice
150
- ...createRoomShellSlice<MyRoomConfig>({
133
+ ...createRoomShellSlice({
151
134
  config: {
152
135
  title: 'My Room',
153
- layout: {
154
- /* layout configuration */
155
- },
156
136
  dataSources: [],
157
- myCustomSetting: 'custom value',
158
137
  },
159
- room: {
138
+ layout: {
139
+ config: {
140
+ /* layout configuration */
141
+ },
160
142
  panels: {
161
143
  /* panel definitions */
162
144
  },
@@ -172,12 +154,13 @@ export const {roomStore, useRoomStore} = createRoomStore<
172
154
  }),
173
155
  {
174
156
  name: 'my-room-storage',
175
- partialize: (state) => ({
176
- // Persist only the config part of the state
177
- config: state.config,
157
+ // Use helper to persist configuration
158
+ ...createPersistHelpers({
159
+ room: BaseRoomConfig,
160
+ layout: LayoutConfig,
178
161
  }),
179
162
  },
180
- ),
163
+ ) as StateCreator<MyRoomState>,
181
164
  );
182
165
  ```
183
166
 
@@ -189,7 +172,7 @@ For larger applications, you can organize your state into feature slices:
189
172
  import {
190
173
  createRoomShellSlice,
191
174
  createRoomStore,
192
- RoomState,
175
+ RoomShellSliceState,
193
176
  } from '@sqlrooms/room-shell';
194
177
  import {createMyFeatureSlice, MyFeatureState} from './myFeatureSlice';
195
178
  import {
@@ -198,32 +181,34 @@ import {
198
181
  } from './anotherFeatureSlice';
199
182
 
200
183
  // Combined app state type
201
- type RoomState = RoomState<MyRoomConfig> & MyFeatureState & AnotherFeatureState;
184
+ type MyRoomState = RoomShellSliceState & MyFeatureState & AnotherFeatureState;
202
185
 
203
186
  // Create a store with multiple slices
204
- export const {roomStore, useRoomStore} = createRoomStore<
205
- MyRoomConfig,
206
- RoomState
207
- >((set, get, store) => ({
208
- // Base room slice
209
- ...createRoomShellSlice<MyRoomConfig>({
210
- config: {
211
- /* initial config */
212
- },
213
- room: {
214
- panels: {
215
- /* panel definitions */
187
+ export const {roomStore, useRoomStore} = createRoomStore<MyRoomState>(
188
+ (set, get, store) => ({
189
+ // Base room slice
190
+ ...createRoomShellSlice({
191
+ config: {
192
+ /* initial config */
216
193
  },
217
- },
218
- })(set, get, store),
219
-
220
- // Feature slices
221
- ...createMyFeatureSlice()(set, get, store),
222
- ...createAnotherFeatureSlice({
223
- // Feature-specific options
224
- customOption: 'value',
225
- })(set, get, store),
226
- }));
194
+ layout: {
195
+ config: {
196
+ /* layout configuration */
197
+ },
198
+ panels: {
199
+ /* panel definitions */
200
+ },
201
+ },
202
+ })(set, get, store),
203
+
204
+ // Feature slices
205
+ ...createMyFeatureSlice()(set, get, store),
206
+ ...createAnotherFeatureSlice({
207
+ // Feature-specific options
208
+ customOption: 'value',
209
+ })(set, get, store),
210
+ }),
211
+ );
227
212
  ```
228
213
 
229
214
  ### Managing Data Sources
@@ -295,12 +280,12 @@ The RoomStore is the core of the room-shell package. It provides a comprehensive
295
280
 
296
281
  ### State Properties
297
282
 
298
- #### `config`
283
+ #### `room.config`
299
284
 
300
285
  The room configuration, which can be persisted between sessions.
301
286
 
302
287
  ```tsx
303
- const config = useRoomStore((state) => state.config);
288
+ const config = useRoomStore((state) => state.room.config);
304
289
  console.log(config.title); // Access room title
305
290
  ```
306
291
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sqlrooms/room-shell",
3
- "version": "0.26.0-rc.5",
3
+ "version": "0.26.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "module": "dist/index.js",
@@ -25,14 +25,14 @@
25
25
  "typedoc": "typedoc"
26
26
  },
27
27
  "dependencies": {
28
- "@sqlrooms/data-table": "0.26.0-rc.5",
29
- "@sqlrooms/duckdb": "0.26.0-rc.5",
30
- "@sqlrooms/layout": "0.26.0-rc.5",
31
- "@sqlrooms/layout-config": "0.26.0-rc.5",
32
- "@sqlrooms/room-config": "0.26.0-rc.5",
33
- "@sqlrooms/room-store": "0.26.0-rc.5",
34
- "@sqlrooms/ui": "0.26.0-rc.5",
35
- "@sqlrooms/utils": "0.26.0-rc.5",
28
+ "@sqlrooms/data-table": "0.26.0",
29
+ "@sqlrooms/duckdb": "0.26.0",
30
+ "@sqlrooms/layout": "0.26.0",
31
+ "@sqlrooms/layout-config": "0.26.0",
32
+ "@sqlrooms/room-config": "0.26.0",
33
+ "@sqlrooms/room-store": "0.26.0",
34
+ "@sqlrooms/ui": "0.26.0",
35
+ "@sqlrooms/utils": "0.26.0",
36
36
  "apache-arrow": "17.0.0",
37
37
  "immer": "^10.1.3",
38
38
  "lucide-react": "^0.544.0",
@@ -44,5 +44,5 @@
44
44
  "react": ">=18",
45
45
  "react-dom": ">=18"
46
46
  },
47
- "gitHead": "dc1c3b765718c8748aa11cce3cc83f907d3e5963"
47
+ "gitHead": "3376e76ddfa3c54097b79a20b88a1c37814dca61"
48
48
  }
@@ -1,3 +0,0 @@
1
- import React from 'react';
2
- export declare const RoomShell: React.FC;
3
- //# sourceMappingURL=RoomBuilder.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"RoomBuilder.d.ts","sourceRoot":"","sources":["../src/RoomBuilder.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAI5D,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EA8D7B,CAAC"}
@@ -1,28 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { ProgressModal, SpinnerPane } from '@sqlrooms/ui';
3
- import { MosaicLayout, getVisibleMosaicLayoutPanels } from '@sqlrooms/layout';
4
- import { Suspense, useCallback, useMemo } from 'react';
5
- import { useBaseRoomShellStore } from './RoomShellSlice';
6
- export const RoomShell = () => {
7
- const layout = useBaseRoomShellStore((state) => state.layout.config);
8
- const setLayout = useBaseRoomShellStore((state) => state.layout.setLayout);
9
- const panels = useBaseRoomShellStore((state) => state.layout.panels);
10
- const loadingProgress = useBaseRoomShellStore((state) => state.room.getLoadingProgress());
11
- const ErrorBoundary = useBaseRoomShellStore((state) => state.room.CustomErrorBoundary);
12
- const visibleRoomPanels = useMemo(() => getVisibleMosaicLayoutPanels(layout?.nodes), [layout]);
13
- const handleLayoutChange = useCallback((nodes) => {
14
- // Keep layout properties, e.g. 'pinned' and 'fixed'
15
- setLayout({ ...layout, nodes });
16
- }, [setLayout, layout]);
17
- const renderedPanels = useMemo(() => {
18
- return Array.from(visibleRoomPanels).reduce((acc, id) => {
19
- const PanelComp = panels[id]?.component;
20
- if (PanelComp) {
21
- acc.set(id, _jsx(ErrorBoundary, { children: _jsx(PanelComp, {}) }));
22
- }
23
- return acc;
24
- }, new Map());
25
- }, [ErrorBoundary, panels, visibleRoomPanels]);
26
- return (_jsx(ErrorBoundary, { children: _jsxs(Suspense, { fallback: _jsx(SpinnerPane, { h: "100%" }), children: [_jsx("div", { className: "flex h-full w-full flex-grow flex-col items-stretch px-0 pb-0", children: layout ? (_jsx(MosaicLayout, { renderTile: (id) => _jsx(_Fragment, { children: renderedPanels.get(id) }), value: layout.nodes, onChange: handleLayoutChange })) : null }), _jsx(ProgressModal, { isOpen: loadingProgress !== undefined, title: "Loading", loadingStage: loadingProgress?.message, indeterminate: true })] }) }));
27
- };
28
- //# sourceMappingURL=RoomBuilder.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"RoomBuilder.js","sourceRoot":"","sources":["../src/RoomBuilder.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,aAAa,EAAE,WAAW,EAAC,MAAM,cAAc,CAAC;AACxD,OAAO,EAAC,YAAY,EAAE,4BAA4B,EAAC,MAAM,kBAAkB,CAAC;AAC5E,OAAc,EAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAC,MAAM,OAAO,CAAC;AAE5D,OAAO,EAAC,qBAAqB,EAAC,MAAM,kBAAkB,CAAC;AAEvD,MAAM,CAAC,MAAM,SAAS,GAAa,GAAG,EAAE;IACtC,MAAM,MAAM,GAAG,qBAAqB,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACrE,MAAM,SAAS,GAAG,qBAAqB,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC3E,MAAM,MAAM,GAAG,qBAAqB,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACrE,MAAM,eAAe,GAAG,qBAAqB,CAAC,CAAC,KAAK,EAAE,EAAE,CACtD,KAAK,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAChC,CAAC;IACF,MAAM,aAAa,GAAG,qBAAqB,CACzC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAC1C,CAAC;IAEF,MAAM,iBAAiB,GAAG,OAAO,CAC/B,GAAG,EAAE,CAAC,4BAA4B,CAAC,MAAM,EAAE,KAAK,CAAC,EACjD,CAAC,MAAM,CAAC,CACT,CAAC;IAEF,MAAM,kBAAkB,GAAG,WAAW,CACpC,CAAC,KAAgC,EAAE,EAAE;QACnC,oDAAoD;QACpD,SAAS,CAAC,EAAC,GAAG,MAAM,EAAE,KAAK,EAAC,CAAC,CAAC;IAChC,CAAC,EACD,CAAC,SAAS,EAAE,MAAM,CAAC,CACpB,CAAC;IAEF,MAAM,cAAc,GAAiC,OAAO,CAAC,GAAG,EAAE;QAChE,OAAO,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAU,EAAE,EAAE;YAC9D,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC;YACxC,IAAI,SAAS,EAAE,CAAC;gBACd,GAAG,CAAC,GAAG,CACL,EAAE,EACF,KAAC,aAAa,cACZ,KAAC,SAAS,KAAG,GACC,CACjB,CAAC;YACJ,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC,EAAE,IAAI,GAAG,EAA2B,CAAC,CAAC;IACzC,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAE/C,OAAO,CACL,KAAC,aAAa,cACZ,MAAC,QAAQ,IAAC,QAAQ,EAAE,KAAC,WAAW,IAAC,CAAC,EAAC,MAAM,GAAG,aAC1C,cAAK,SAAS,EAAC,+DAA+D,YAC3E,MAAM,CAAC,CAAC,CAAC,CACR,KAAC,YAAY,IACX,UAAU,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,4BAAG,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,GAAI,EACjD,KAAK,EAAE,MAAM,CAAC,KAAK,EACnB,QAAQ,EAAE,kBAAkB,GAC5B,CACH,CAAC,CAAC,CAAC,IAAI,GACJ,EAEN,KAAC,aAAa,IACZ,MAAM,EAAE,eAAe,KAAK,SAAS,EACrC,KAAK,EAAC,SAAS,EACf,YAAY,EAAE,eAAe,EAAE,OAAO,EACtC,aAAa,EAAE,IAAI,GAEnB,IACO,GACG,CACjB,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {ProgressModal, SpinnerPane} from '@sqlrooms/ui';\nimport {MosaicLayout, getVisibleMosaicLayoutPanels} from '@sqlrooms/layout';\nimport React, {Suspense, useCallback, useMemo} from 'react';\nimport type {MosaicNode} from 'react-mosaic-component';\nimport {useBaseRoomShellStore} from './RoomShellSlice';\n\nexport const RoomShell: React.FC = () => {\n const layout = useBaseRoomShellStore((state) => state.layout.config);\n const setLayout = useBaseRoomShellStore((state) => state.layout.setLayout);\n const panels = useBaseRoomShellStore((state) => state.layout.panels);\n const loadingProgress = useBaseRoomShellStore((state) =>\n state.room.getLoadingProgress(),\n );\n const ErrorBoundary = useBaseRoomShellStore(\n (state) => state.room.CustomErrorBoundary,\n );\n\n const visibleRoomPanels = useMemo(\n () => getVisibleMosaicLayoutPanels(layout?.nodes),\n [layout],\n );\n\n const handleLayoutChange = useCallback(\n (nodes: MosaicNode<string> | null) => {\n // Keep layout properties, e.g. 'pinned' and 'fixed'\n setLayout({...layout, nodes});\n },\n [setLayout, layout],\n );\n\n const renderedPanels: Map<string, React.ReactNode> = useMemo(() => {\n return Array.from(visibleRoomPanels).reduce((acc, id: string) => {\n const PanelComp = panels[id]?.component;\n if (PanelComp) {\n acc.set(\n id,\n <ErrorBoundary>\n <PanelComp />\n </ErrorBoundary>,\n );\n }\n return acc;\n }, new Map<string, React.ReactNode>());\n }, [ErrorBoundary, panels, visibleRoomPanels]);\n\n return (\n <ErrorBoundary>\n <Suspense fallback={<SpinnerPane h=\"100%\" />}>\n <div className=\"flex h-full w-full flex-grow flex-col items-stretch px-0 pb-0\">\n {layout ? (\n <MosaicLayout\n renderTile={(id) => <>{renderedPanels.get(id)}</>}\n value={layout.nodes}\n onChange={handleLayoutChange}\n />\n ) : null}\n </div>\n\n <ProgressModal\n isOpen={loadingProgress !== undefined}\n title=\"Loading\"\n loadingStage={loadingProgress?.message}\n indeterminate={true}\n // progress={loadingProgress?.progress}\n />\n </Suspense>\n </ErrorBoundary>\n );\n};\n"]}