@perspective-dev/viewer 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.
Files changed (178) hide show
  1. package/dist/cdn/perspective-viewer.js +20 -1
  2. package/dist/cdn/perspective-viewer.js.map +4 -4
  3. package/dist/css/botanical.css +1 -1
  4. package/dist/css/dracula.css +1 -1
  5. package/dist/css/gruvbox-dark.css +1 -1
  6. package/dist/css/gruvbox.css +1 -1
  7. package/dist/css/icons.css +1 -1
  8. package/dist/css/monokai.css +1 -1
  9. package/dist/css/phosphor.css +1 -1
  10. package/dist/css/pro-dark.css +1 -1
  11. package/dist/css/pro.css +1 -1
  12. package/dist/css/solarized-dark.css +1 -1
  13. package/dist/css/solarized.css +1 -1
  14. package/dist/css/themes.css +1 -1
  15. package/dist/css/vaporwave.css +1 -1
  16. package/dist/esm/extensions.d.ts +22 -3
  17. package/dist/esm/perspective-viewer.d.ts +9 -0
  18. package/dist/esm/perspective-viewer.inline.js +20 -1
  19. package/dist/esm/perspective-viewer.inline.js.map +4 -4
  20. package/dist/esm/perspective-viewer.js +20 -1
  21. package/dist/esm/perspective-viewer.js.map +4 -4
  22. package/dist/esm/plugin.d.ts +71 -5
  23. package/dist/esm/ts-rs/ClientOptions.d.ts +7 -0
  24. package/dist/esm/ts-rs/ExportMethod.d.ts +1 -0
  25. package/dist/esm/ts-rs/ExportOptions.d.ts +9 -0
  26. package/dist/esm/ts-rs/GetClientOptions.d.ts +8 -0
  27. package/dist/esm/ts-rs/GetTableOptions.d.ts +8 -0
  28. package/dist/esm/ts-rs/Layout.d.ts +11 -0
  29. package/dist/esm/ts-rs/Orientation.d.ts +4 -0
  30. package/dist/esm/ts-rs/PanelOptions.d.ts +7 -0
  31. package/dist/esm/ts-rs/PanelViewerConfig.d.ts +39 -0
  32. package/dist/esm/ts-rs/SplitLayout.d.ts +7 -0
  33. package/dist/esm/ts-rs/TabLayout.d.ts +10 -0
  34. package/dist/esm/ts-rs/ViewerConfig.d.ts +6 -2
  35. package/dist/esm/ts-rs/WorkspaceConfig.d.ts +40 -0
  36. package/dist/esm/ts-rs/WorkspaceConfigUpdate.d.ts +28 -0
  37. package/dist/wasm/perspective-viewer.d.ts +211 -77
  38. package/dist/wasm/perspective-viewer.js +528 -180
  39. package/dist/wasm/perspective-viewer.wasm +0 -0
  40. package/dist/wasm/perspective-viewer.wasm.d.ts +34 -26
  41. package/dist/wasm/snippets/perspective-viewer-daeef4ceb066e6c7/inline0.js +6 -0
  42. package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline3.js → perspective-viewer-daeef4ceb066e6c7/inline4.js} +5 -0
  43. package/package.json +3 -2
  44. package/src/css/_context_menu.css +14 -0
  45. package/src/css/column-settings-panel.css +1 -1
  46. package/src/css/containers/context-menu.css +101 -0
  47. package/src/css/panel-tab.css +193 -0
  48. package/src/css/plugin-selector.css +7 -10
  49. package/src/css/status-bar.css +75 -81
  50. package/src/css/viewer.css +180 -70
  51. package/src/rust/components/column_dropdown.rs +40 -30
  52. package/src/rust/components/column_selector/active_column.rs +7 -18
  53. package/src/rust/components/column_selector/aggregate_selector.rs +4 -7
  54. package/src/rust/components/column_selector/config_selector.rs +33 -81
  55. package/src/rust/components/column_selector/filter_column.rs +5 -15
  56. package/src/rust/components/column_selector/inactive_column.rs +3 -8
  57. package/src/rust/components/column_selector/sort_column.rs +3 -6
  58. package/src/rust/components/column_selector.rs +5 -11
  59. package/src/rust/components/containers/split_panel.rs +175 -62
  60. package/src/rust/components/context_menu.rs +130 -0
  61. package/src/rust/components/form/debug.rs +3 -0
  62. package/src/rust/components/global_filter_bar.rs +76 -0
  63. package/src/rust/components/main_panel/frame_theme.rs +186 -0
  64. package/src/rust/components/main_panel/msg.rs +62 -0
  65. package/src/rust/components/main_panel/presize.rs +220 -0
  66. package/src/rust/components/main_panel/reconcile.rs +224 -0
  67. package/src/rust/components/main_panel/render.rs +385 -0
  68. package/src/rust/components/main_panel/update.rs +184 -0
  69. package/src/rust/components/main_panel.rs +311 -71
  70. package/src/rust/components/mod.rs +4 -0
  71. package/src/rust/components/panel_menu.rs +486 -0
  72. package/src/rust/components/panel_tab.rs +505 -0
  73. package/src/rust/components/plugin_tab.rs +1 -1
  74. package/src/rust/components/settings_panel.rs +13 -5
  75. package/src/rust/components/status_bar.rs +110 -178
  76. package/src/rust/components/status_indicator.rs +6 -9
  77. package/src/rust/components/style/mod.rs +5 -0
  78. package/src/rust/components/style/style_provider.rs +2 -0
  79. package/src/rust/components/viewer/filters.rs +133 -0
  80. package/src/rust/components/viewer/msg.rs +180 -0
  81. package/src/rust/components/viewer/panels.rs +326 -0
  82. package/src/rust/components/viewer/render.rs +243 -0
  83. package/src/rust/components/viewer/settings.rs +402 -0
  84. package/src/rust/components/viewer/snapshots.rs +134 -0
  85. package/src/rust/components/viewer/wiring.rs +505 -0
  86. package/src/rust/components/viewer.rs +243 -756
  87. package/src/rust/config/export_method.rs +1 -1
  88. package/src/rust/config/mod.rs +4 -0
  89. package/src/rust/config/options.rs +71 -0
  90. package/src/rust/config/viewer_config.rs +24 -2
  91. package/src/rust/config/workspace_config.rs +92 -0
  92. package/src/rust/custom_elements/copy_dropdown.rs +3 -1
  93. package/src/rust/custom_elements/debug_plugin.rs +20 -1
  94. package/src/rust/custom_elements/export_dropdown.rs +3 -1
  95. package/src/rust/custom_elements/viewer.rs +1015 -286
  96. package/src/rust/custom_events.rs +212 -61
  97. package/src/rust/js/mod.rs +2 -0
  98. package/src/rust/js/plugin.rs +297 -10
  99. package/src/rust/js/regular_layout.rs +258 -0
  100. package/src/rust/lib.rs +20 -1
  101. package/src/rust/presentation.rs +66 -33
  102. package/src/rust/queries/get_viewer_config.rs +29 -11
  103. package/src/rust/queries/plugin_column_styles.rs +2 -2
  104. package/src/rust/renderer/activate.rs +41 -14
  105. package/src/rust/renderer/dispatch.rs +436 -0
  106. package/src/rust/renderer/plugin_config.rs +495 -0
  107. package/src/rust/renderer/registry.rs +18 -6
  108. package/src/rust/renderer/render_timer.rs +29 -10
  109. package/src/rust/renderer.rs +350 -837
  110. package/src/rust/session/column_defaults_update.rs +26 -8
  111. package/src/rust/session/view_subscription.rs +30 -15
  112. package/src/rust/session.rs +753 -264
  113. package/src/rust/tasks/apply_global_filters.rs +89 -0
  114. package/src/rust/tasks/auto_pause.rs +171 -0
  115. package/src/rust/tasks/copy_export.rs +29 -19
  116. package/src/rust/tasks/create_panel.rs +243 -0
  117. package/src/rust/tasks/dismiss_render_warning.rs +3 -1
  118. package/src/rust/tasks/edit_expression.rs +4 -4
  119. package/src/rust/tasks/eject.rs +64 -23
  120. package/src/rust/tasks/mod.rs +28 -4
  121. package/src/rust/tasks/pipeline.rs +411 -0
  122. package/src/rust/tasks/presize_panels.rs +324 -0
  123. package/src/rust/tasks/reset_all.rs +22 -12
  124. package/src/rust/tasks/resize_observer.rs +124 -87
  125. package/src/rust/tasks/restore_and_render.rs +80 -86
  126. package/src/rust/tasks/restore_panel.rs +145 -0
  127. package/src/rust/tasks/send_column_config.rs +5 -2
  128. package/src/rust/tasks/send_plugin_config.rs +5 -2
  129. package/src/rust/tasks/set_edit_mode.rs +59 -0
  130. package/src/rust/tasks/sync_update_panels.rs +152 -0
  131. package/src/rust/tasks/table_lifecycle.rs +158 -0
  132. package/src/rust/tasks/update_theme.rs +56 -12
  133. package/src/rust/utils/completion.rs +56 -0
  134. package/src/rust/utils/custom_element.rs +5 -0
  135. package/src/rust/utils/debounce.rs +130 -7
  136. package/src/rust/utils/mod.rs +6 -0
  137. package/src/rust/utils/pending_effects.rs +62 -0
  138. package/src/rust/utils/spawn.rs +33 -0
  139. package/src/rust/utils/weak_scope.rs +0 -10
  140. package/src/rust/workspace.rs +846 -0
  141. package/src/svg/active-indicator.svg +3 -0
  142. package/src/themes/botanical.css +5 -2
  143. package/src/themes/defaults.css +54 -2
  144. package/src/themes/dracula.css +6 -3
  145. package/src/themes/gruvbox-dark.css +5 -2
  146. package/src/themes/gruvbox.css +5 -2
  147. package/src/themes/icons.css +4 -2
  148. package/src/themes/monokai.css +5 -2
  149. package/src/themes/phosphor.css +5 -2
  150. package/src/themes/pro-dark.css +5 -2
  151. package/src/themes/pro.css +2 -1
  152. package/src/themes/solarized-dark.css +5 -2
  153. package/src/themes/solarized.css +5 -2
  154. package/src/themes/vaporwave.css +5 -2
  155. package/src/ts/bootstrap.ts +8 -7
  156. package/src/ts/extensions.ts +30 -2
  157. package/src/ts/perspective-viewer.ts +10 -0
  158. package/src/ts/plugin.ts +72 -5
  159. package/src/ts/ts-rs/ClientOptions.ts +7 -0
  160. package/src/ts/ts-rs/ExportMethod.ts +3 -0
  161. package/src/ts/ts-rs/ExportOptions.ts +8 -0
  162. package/src/ts/ts-rs/GetClientOptions.ts +7 -0
  163. package/src/ts/ts-rs/GetTableOptions.ts +7 -0
  164. package/src/ts/ts-rs/Layout.ts +9 -0
  165. package/src/ts/ts-rs/Orientation.ts +6 -0
  166. package/src/ts/ts-rs/PanelOptions.ts +7 -0
  167. package/src/ts/ts-rs/PanelViewerConfig.ts +15 -0
  168. package/src/ts/ts-rs/SplitLayout.ts +5 -0
  169. package/src/ts/ts-rs/TabLayout.ts +11 -0
  170. package/src/ts/ts-rs/ViewerConfig.ts +6 -2
  171. package/src/ts/ts-rs/WorkspaceConfig.ts +36 -0
  172. package/src/ts/ts-rs/WorkspaceConfigUpdate.ts +24 -0
  173. package/src/rust/tasks/intersection_observer.rs +0 -98
  174. package/src/rust/tasks/update_and_render.rs +0 -110
  175. /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline0.js → perspective-viewer-daeef4ceb066e6c7/inline1.js} +0 -0
  176. /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline1.js → perspective-viewer-daeef4ceb066e6c7/inline2.js} +0 -0
  177. /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline2.js → perspective-viewer-daeef4ceb066e6c7/inline3.js} +0 -0
  178. /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline4.js → perspective-viewer-daeef4ceb066e6c7/inline5.js} +0 -0
@@ -15,6 +15,36 @@ import { PluginStaticConfig } from "./ts-rs/PluginStaticConfig.js";
15
15
  * level (if packaged as a library), or during application init to ensure global
16
16
  * availability of a plugin.
17
17
  *
18
+ * ## Dispatch contract
19
+ *
20
+ * The host dispatches each method for exactly one reason, and never
21
+ * defensively — implementations may rely on these meanings:
22
+ *
23
+ * - `draw(view)` — `view` is NEW to this plugin: a new engine `View` was
24
+ * constructed, or this plugin was freshly selected and owes its first
25
+ * render. Safe to reset zoom/scroll/selection state.
26
+ * - `update(view)` — same `View`, but a plugin-visible input genuinely
27
+ * changed: new data (`View.on_update`), an effective view-config delta
28
+ * without a rebuild, a *changed* plugin/columns config just delivered
29
+ * via `restore()`, changed CSS just applied via `restyle()`, a
30
+ * render-limits change, or an explicit public `viewer.restore()` call
31
+ * (the no-op-restore refresh affordance). Host-internal operations that
32
+ * change none of these dispatch nothing.
33
+ * - `resize(view)` — geometry or visibility changed (including panel
34
+ * activation); repaint from retained state, no data or CSS re-read.
35
+ * - `restyle()` — the effective theme genuinely changed; when a
36
+ * `draw`/`update` is part of the same operation, `restyle()` is called
37
+ * immediately BEFORE it, so one render pass paints in the new theme.
38
+ * - `restore()`/`save()` — state transfer only. Plugins must NOT render
39
+ * from `restore()` (a changed restore is always followed by exactly one
40
+ * `update`) and must NOT call host APIs from inside it — a
41
+ * `restore()` echo re-enters the host's public surface and forces
42
+ * a redundant render (the classic double-render-on-load bug).
43
+ *
44
+ * Rendering methods (`draw`, `update`, `resize`, `render`, `clear`) and
45
+ * `delete` are serialized per element — the host never overlaps them, and
46
+ * each call runs to completion before the next begins.
47
+ *
18
48
  * @example
19
49
  * ```javascript
20
50
  * const BasePlugin = customElements.get("perspective-viewer-plugin");
@@ -53,6 +83,14 @@ export interface IPerspectiveViewerPlugin {
53
83
  * provision to cancel a render in progress per se, calling a method on
54
84
  * a `View` which has been deleted will throw an exception.
55
85
  *
86
+ * The host invokes `draw` ONLY when `view` is NEW to this plugin — a
87
+ * new engine `View` was constructed for a config change, or this plugin
88
+ * element was freshly selected and owes its first render of the bound
89
+ * `View` — so implementations may treat it as "new data shape" and
90
+ * reset zoom/scroll/selection-domain state. Repaints of the same
91
+ * `View` arrive as `update()` (data or style refresh) or `resize()`
92
+ * (geometry/chrome), never `draw()`.
93
+ *
56
94
  * @example
57
95
  * ```
58
96
  * async draw(view: perspective.View): Promise<void> {
@@ -63,9 +101,9 @@ export interface IPerspectiveViewerPlugin {
63
101
  */
64
102
  draw(view: View): Promise<void>;
65
103
  /**
66
- * Draw under the assumption that the `ViewConfig` has not changed since
67
- * the previous call to `draw()`, but the underlying data has. Defaults to
68
- * dispatch to `draw()`.
104
+ * Draw under the assumption that the `View` has not changed since the
105
+ * previous call to `draw()`, but some plugin-visible input has.
106
+ * Defaults to dispatch to `draw()`.
69
107
  *
70
108
  * @example
71
109
  * ```javascript
@@ -91,18 +129,46 @@ export interface IPerspectiveViewerPlugin {
91
129
  clear(): Promise<void>;
92
130
  /**
93
131
  * Like `update()`, but for when the dimensions of the plugin have changed
94
- * and the underlying data has not.
132
+ * and the underlying data has not — a repaint from retained state,
133
+ * invoked ONLY when geometry or visibility changed: box resizes,
134
+ * presize sweeps, and the panel-ACTIVATION chrome nudge (multi-panel),
135
+ * so implementations should repaint activation-dependent chrome here
136
+ * and no-op while hidden (`offsetParent == null`).
95
137
  */
96
138
  resize(view: View): Promise<void>;
97
139
  /**
98
140
  * Notify the plugin that the style environment has changed. Useful for
99
- * plugins which read CSS styles via `window.getComputedStyle()`.
141
+ * plugins which read CSS styles via `window.getComputedStyle()` — this
142
+ * is the ONLY point at which a plugin is expected to (re-)read them
143
+ * (besides its first `draw()`), so implementations may cache computed
144
+ * styles between `restyle()` calls.
100
145
  */
101
146
  restyle(): void;
102
147
  /**
103
148
  * Restore this plugin to a state previously returned by `save()`.
149
+ *
150
+ * State transfer ONLY — implementations must not render from
151
+ * `restore()` (the host follows a restore that genuinely changed
152
+ * plugin state with exactly one `update()` in the same serialized
153
+ * sequence), and must not call host `<perspective-viewer>` APIs from
154
+ * inside it: an echoed `restore()` re-enters the host's public
155
+ * surface where it is indistinguishable from a user call and forces a
156
+ * redundant render. Host API calls to persist plugin state belong to
157
+ * genuine user-gesture handlers (e.g. a toolbar click), never to the
158
+ * `restore()` delivery path.
104
159
  */
105
160
  restore(config: any): void;
161
+ /**
162
+ * OPTIONAL — clear any visible user selection state (highlighted rows,
163
+ * pinned tooltips) WITHOUT emitting selection events. The host
164
+ * `<perspective-viewer>` invokes this when an element-level global
165
+ * filter contributed by this plugin's selection is removed from the
166
+ * global filter bar, so the selection visual can't outlive the filter
167
+ * it produced. Called under the host's per-panel render serialization
168
+ * (like `draw`), so implementations may redraw. Plugins without a
169
+ * selection UI may omit it.
170
+ */
171
+ deselect?(): Promise<void>;
106
172
  /**
107
173
  * Free any resources acquired by this plugin and prepare to be deleted.
108
174
  */
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The `eject` argument: the loaded client to remove by name; the active
3
+ * panel's client when omitted.
4
+ */
5
+ export type ClientOptions = {
6
+ client?: string;
7
+ };
@@ -0,0 +1 @@
1
+ export type ExportMethod = "csv" | "csv-all" | "csv-selected" | "json" | "json-all" | "json-selected" | "ndjson" | "ndjson-all" | "ndjson-selected" | "html" | "plugin" | "arrow" | "arrow-selected" | "arrow-all" | "json-config";
@@ -0,0 +1,9 @@
1
+ import type { ExportMethod } from "./ExportMethod.js";
2
+ /**
3
+ * The `download` / `export` / `copy` argument: the `ExportMethod` and target
4
+ * panel.
5
+ */
6
+ export type ExportOptions = {
7
+ method?: ExportMethod;
8
+ panel?: string;
9
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The `getClient` argument: whether to `wait` for a `Client`, and the target
3
+ * panel.
4
+ */
5
+ export type GetClientOptions = {
6
+ wait?: boolean;
7
+ panel?: string;
8
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The `getTable` argument: whether to `wait` for a `Table`, and the target
3
+ * panel.
4
+ */
5
+ export type GetTableOptions = {
6
+ wait?: boolean;
7
+ panel?: string;
8
+ };
@@ -0,0 +1,11 @@
1
+ import type { SplitLayout } from "./SplitLayout.js";
2
+ import type { TabLayout } from "./TabLayout.js";
3
+ /**
4
+ * A serde mirror of `regular-layout`'s serialized layout tree, as returned by
5
+ * [`RegularLayout::save`] and accepted by [`RegularLayout::restore`].
6
+ */
7
+ export type Layout = {
8
+ "type": "split-layout";
9
+ } & SplitLayout | {
10
+ "type": "tab-layout";
11
+ } & TabLayout;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * The orientation of a [`SplitLayout`].
3
+ */
4
+ export type Orientation = "horizontal" | "vertical";
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Selects the target panel of a panel-scoped `<perspective-viewer>` method;
3
+ * the active panel when `panel` is omitted.
4
+ */
5
+ export type PanelOptions = {
6
+ panel?: string;
7
+ };
@@ -0,0 +1,39 @@
1
+ import type { Aggregate } from "./Aggregate.js";
2
+ import type { Expressions } from "./Expressions.js";
3
+ import type { Filter } from "./Filter.js";
4
+ import type { FilterReducer } from "./FilterReducer.js";
5
+ import type { GroupRollupMode } from "./GroupRollupMode.js";
6
+ import type { Sort } from "./Sort.js";
7
+ import type { JsonValue } from "./serde_json/JsonValue.js";
8
+ /**
9
+ * The per-panel state of a [`ViewerConfig`] — everything except the
10
+ * element-level `settings` flag. This is the `panels` entry type of the
11
+ * whole-element config format.
12
+ */
13
+ export type PanelViewerConfig<V = string> = {
14
+ version: V;
15
+ columns_config: {
16
+ [key in string]?: {
17
+ [key in string]?: JsonValue;
18
+ };
19
+ };
20
+ plugin: string;
21
+ plugin_config: {
22
+ [key in string]?: JsonValue;
23
+ };
24
+ table: string | null;
25
+ theme: string | null;
26
+ title: string | null;
27
+ group_by: Array<string>;
28
+ split_by: Array<string>;
29
+ sort: Array<Sort>;
30
+ filter: Array<Filter>;
31
+ group_rollup_mode: GroupRollupMode;
32
+ filter_op?: FilterReducer;
33
+ expressions: Expressions;
34
+ columns: Array<string | null>;
35
+ aggregates: {
36
+ [key in string]?: Aggregate;
37
+ };
38
+ group_by_depth?: number | null;
39
+ };
@@ -0,0 +1,7 @@
1
+ import type { Layout } from "./Layout.js";
2
+ import type { Orientation } from "./Orientation.js";
3
+ export type SplitLayout = {
4
+ children: Array<Layout>;
5
+ sizes: Array<number>;
6
+ orientation: Orientation;
7
+ };
@@ -0,0 +1,10 @@
1
+ export type TabLayout = {
2
+ /**
3
+ * Panel ids (slot names) in this stack.
4
+ */
5
+ tabs: Array<string>;
6
+ /**
7
+ * Index of the selected tab within `tabs`.
8
+ */
9
+ selected?: number;
10
+ };
@@ -7,9 +7,14 @@ import type { Sort } from "./Sort.js";
7
7
  import type { JsonValue } from "./serde_json/JsonValue.js";
8
8
  /**
9
9
  * The state of an entire `custom_elements::PerspectiveViewerElement` component
10
- * and its `Plugin`.
10
+ * and its `Plugin`: the element-level `settings` flag plus the per-panel
11
+ * [`PanelViewerConfig`]. The split exists so the whole-element config format
12
+ * can serialize panel entries *without* a `settings` key (it is element-level
13
+ * state there, carried by the top-level `active` field instead), while the
14
+ * single-panel format flattens back to the legacy shape.
11
15
  */
12
16
  export type ViewerConfig<V = string> = {
17
+ settings: boolean;
13
18
  version: V;
14
19
  columns_config: {
15
20
  [key in string]?: {
@@ -20,7 +25,6 @@ export type ViewerConfig<V = string> = {
20
25
  plugin_config: {
21
26
  [key in string]?: JsonValue;
22
27
  };
23
- settings: boolean;
24
28
  table: string | null;
25
29
  theme: string | null;
26
30
  title: string | null;
@@ -0,0 +1,40 @@
1
+ import type { Filter } from "./Filter.js";
2
+ import type { Layout } from "./Layout.js";
3
+ import type { PanelViewerConfig } from "./PanelViewerConfig.js";
4
+ /**
5
+ * The whole-element config format (`{version, active?, layout, panels}`) —
6
+ * the multi-panel counterpart of the single-panel [`ViewerConfig`] — as
7
+ * emitted by [`PerspectiveViewerElement::save`].
8
+ *
9
+ * - `panels` entries are [`PanelViewerConfig`]s: per-panel state only, no
10
+ * `settings` key (element-level state).
11
+ * - `active` names the panel targeted by the *open* settings sidebar; it is
12
+ * omitted when the sidebar is closed.
13
+ */
14
+ export type WorkspaceConfig = {
15
+ version: string;
16
+ active?: string;
17
+ layout: Layout | null;
18
+ /**
19
+ * `BTreeMap` (not `HashMap`) so `save()` serializes panels in a
20
+ * DETERMINISTIC (sorted) key order — a fresh `HashMap` per call
21
+ * iterates in a per-instance random order, which made consecutive
22
+ * `save()` outputs byte-unstable.
23
+ */
24
+ panels: {
25
+ [key in string]?: PanelViewerConfig<string>;
26
+ };
27
+ /**
28
+ * The element-level global (master/detail cross-) filters. A transient
29
+ * overlay on every detail panel's view — persisted here, never in a
30
+ * per-panel entry. Omitted when empty.
31
+ */
32
+ global_filters?: Array<Filter>;
33
+ /**
34
+ * The MASTER (filter-source) panels' ids, referencing `panels` keys.
35
+ * Roles are layout state (like the panel arrangement), so they persist;
36
+ * which master contributed which clause does not — restored
37
+ * `global_filters` are one unattributed bucket. Omitted when empty.
38
+ */
39
+ masters?: Array<string>;
40
+ };
@@ -0,0 +1,28 @@
1
+ import type { Filter } from "./Filter.js";
2
+ import type { Layout } from "./Layout.js";
3
+ import type { ViewerConfigUpdate } from "./ViewerConfigUpdate.js";
4
+ /**
5
+ * The parse target of a whole-element config in
6
+ * [`PerspectiveViewerElement::restore`]. Mirrors [`WorkspaceConfig`],
7
+ * but `panels` entries are full [`ViewerConfigUpdate`]s so a stray per-panel
8
+ * `settings` can be detected (warned, then ignored — `create_panel` strips
9
+ * it).
10
+ */
11
+ export type WorkspaceConfigUpdate = {
12
+ active?: string;
13
+ layout?: Layout;
14
+ panels: {
15
+ [key in string]?: ViewerConfigUpdate;
16
+ };
17
+ /**
18
+ * The element-level global (master/detail cross-) filters to re-apply as
19
+ * a transient overlay on every DETAIL panel. Restored as one
20
+ * unattributed bucket: the next selection on any master replaces it.
21
+ */
22
+ global_filters?: Array<Filter>;
23
+ /**
24
+ * The master (filter-source) panels, by saved `panels` key. An id not in
25
+ * `panels` warns and is dropped.
26
+ */
27
+ masters?: Array<string>;
28
+ };