graphwise-reactodia 0.0.1-TR13 → 0.0.1-TR14

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.
@@ -31376,8 +31376,10 @@ let DiagramService = DiagramService_1 = class DiagramService {
31376
31376
  clearTimeout(notifyTimer);
31377
31377
  }
31378
31378
  notifyTimer = setTimeout(() => {
31379
+ if (notifyTimer) {
31380
+ onChangeCallback(model.exportLayout());
31381
+ }
31379
31382
  notifyTimer = undefined;
31380
- onChangeCallback(model.exportLayout());
31381
31383
  }, DiagramService_1.NOTIFY_DEBOUNCE_MS);
31382
31384
  };
31383
31385
  model.history.events.on(DiagramService_1.HISTORY_CHANGED_EVENT, onHistoryChange);
@@ -31385,6 +31387,7 @@ let DiagramService = DiagramService_1 = class DiagramService {
31385
31387
  model.history.events.off(DiagramService_1.HISTORY_CHANGED_EVENT, onHistoryChange);
31386
31388
  if (notifyTimer) {
31387
31389
  clearTimeout(notifyTimer);
31390
+ notifyTimer = undefined;
31388
31391
  }
31389
31392
  };
31390
31393
  }
@@ -31526,34 +31529,33 @@ class SubscriptionList {
31526
31529
  }
31527
31530
  }
31528
31531
 
31529
- const NODE_COLOR_VARIABLES = [
31530
- '--gw-foreground-visual-diagram-categorical-01',
31531
- '--gw-foreground-visual-diagram-categorical-02',
31532
- '--gw-foreground-visual-diagram-categorical-03',
31533
- '--gw-foreground-visual-diagram-categorical-04',
31534
- '--gw-foreground-visual-diagram-categorical-05',
31535
- '--gw-foreground-visual-diagram-categorical-06',
31536
- '--gw-foreground-visual-diagram-categorical-07',
31537
- '--gw-foreground-visual-diagram-categorical-08',
31538
- '--gw-foreground-visual-diagram-categorical-09',
31539
- '--gw-foreground-visual-diagram-categorical-10',
31540
- '--gw-foreground-visual-diagram-categorical-11',
31541
- '--gw-foreground-visual-diagram-categorical-12',
31542
- '--gw-foreground-visual-diagram-categorical-13',
31543
- '--gw-foreground-visual-diagram-categorical-14',
31544
- '--gw-foreground-visual-diagram-categorical-15',
31545
- '--gw-foreground-visual-diagram-categorical-16',
31546
- '--gw-foreground-visual-diagram-categorical-17',
31547
- '--gw-foreground-visual-diagram-categorical-18',
31548
- '--gw-foreground-visual-diagram-categorical-19',
31549
- '--gw-foreground-visual-diagram-categorical-20'
31550
- ];
31551
31532
  /**
31552
31533
  * Color slot assigned to each type, in the order the types are first seen.
31553
31534
  */
31554
31535
  const typeToIndex = new Map();
31555
- function getColor(variable) {
31556
- return getComputedStyle(document.documentElement).getPropertyValue(variable).trim();
31536
+ /**
31537
+ * Returns the internal property of the given palette slot, numbered from 1 and padded to two digits as in `_theme.scss`.
31538
+ */
31539
+ function getTypeColorProperty(slot) {
31540
+ return `--_graphwise-reactodia-type-color-${String(slot).padStart(2, '0')}`;
31541
+ }
31542
+ /**
31543
+ * Reads the type palette of the Theme API: the internal properties `_theme.scss` resolves from the ones
31544
+ * the host declares, in slot order up to the first empty one.
31545
+ */
31546
+ function getPalette() {
31547
+ const host = document.querySelector('graphwise-reactodia');
31548
+ if (!host) {
31549
+ return [];
31550
+ }
31551
+ const style = getComputedStyle(host);
31552
+ const palette = [];
31553
+ let color = style.getPropertyValue(getTypeColorProperty(1)).trim();
31554
+ while (color) {
31555
+ palette.push(color);
31556
+ color = style.getPropertyValue(getTypeColorProperty(palette.length + 1)).trim();
31557
+ }
31558
+ return palette;
31557
31559
  }
31558
31560
  /**
31559
31561
  * Colors an element by its type: each type takes the next color from the palette, which wraps
@@ -31573,8 +31575,8 @@ const resolveTypeStyle = (types) => {
31573
31575
  index = typeToIndex.size;
31574
31576
  typeToIndex.set(type, index);
31575
31577
  }
31576
- const color = getColor(NODE_COLOR_VARIABLES[index % NODE_COLOR_VARIABLES.length]);
31577
- return color ? { color } : undefined;
31578
+ const colors = getPalette();
31579
+ return colors.length ? { color: colors[index % colors.length] } : undefined;
31578
31580
  };
31579
31581
  const resetColors = () => {
31580
31582
  typeToIndex.clear();
@@ -31697,6 +31699,10 @@ let workspaceContext = null;
31697
31699
  * the React root.
31698
31700
  */
31699
31701
  const subscriptions = new SubscriptionList();
31702
+ let diagramStorageSubscription;
31703
+ const diagramService = service(DiagramService);
31704
+ const diagramStorageService = service(DiagramStorageService);
31705
+ const eventService = service(EventService);
31700
31706
  /**
31701
31707
  * Builds a Reactodia {@link SparqlDataProvider} for the given endpoint using the supplied
31702
31708
  * query preset. The host owns the query configuration and always passes it in via props.
@@ -31756,20 +31762,30 @@ async function seedGraphToCanvas(context, dataProvider, links, signal) {
31756
31762
  * root in {@link unmountReactodia}.
31757
31763
  */
31758
31764
  function onDiagramChange(model) {
31759
- const storage = service(DiagramStorageService);
31760
- const diagramService = service(DiagramService);
31761
- subscriptions.add(diagramService.subscribeToDiagramChange(model, (diagram) => storage.save(diagram)));
31765
+ subscribeToDiagramChange(model);
31766
+ }
31767
+ /**
31768
+ * Starts persisting the model's edits to local storage, keeping the subscription in {@link diagramStorageSubscription}.
31769
+ */
31770
+ function subscribeToDiagramChange(model) {
31771
+ diagramStorageSubscription === null || diagramStorageSubscription === void 0 ? void 0 : diagramStorageSubscription();
31772
+ diagramStorageSubscription = diagramService.subscribeToDiagramChange(model, (diagram) => diagramStorageService.save(diagram));
31773
+ subscriptions.add(diagramStorageSubscription);
31762
31774
  }
31763
31775
  /**
31764
31776
  * Subscribes to the host's "clear persisted diagram" command so the saved layout is dropped on
31765
31777
  * request (e.g. before a fresh seed should take precedence over previously saved edits). The
31766
31778
  * subscription is tracked in {@link subscriptions} so it is released together with the React
31767
31779
  * root in {@link unmountReactodia}.
31780
+ *
31781
+ * @param model The diagram model whose edits are persisted
31768
31782
  */
31769
- function onClearDiagramStorage() {
31770
- const storage = service(DiagramStorageService);
31771
- const eventService = service(EventService);
31772
- subscriptions.add(eventService.subscribeToClearDiagramStorage(() => storage.clear()));
31783
+ function onClearDiagramStorage(model) {
31784
+ subscriptions.add(eventService.subscribeToClearDiagramStorage(() => {
31785
+ // re-subscribe, to avoid any pending debounced saves, which may write over the cleared diagram
31786
+ subscribeToDiagramChange(model);
31787
+ diagramStorageService.clear();
31788
+ }));
31773
31789
  }
31774
31790
  /**
31775
31791
  * The Reactodia workspace React component.
@@ -31788,11 +31804,10 @@ function ReactodiaApp(props) {
31788
31804
  workspaceContext = context;
31789
31805
  const { model } = context;
31790
31806
  onDiagramChange(model);
31791
- onClearDiagramStorage();
31807
+ onClearDiagramStorage(model);
31792
31808
  const dataProvider = createDataProvider(props);
31793
31809
  const isReload = props.isReload;
31794
- const savedDiagram = service(DiagramStorageService).load();
31795
- const diagramService = service(DiagramService);
31810
+ const savedDiagram = diagramStorageService.load();
31796
31811
  if (isReload) {
31797
31812
  // Reload the diagram that is currently on the canvas. This may happen when the host changes the provider
31798
31813
  // settings, or when the user switches the language at runtime, since there is no existing mechanism to
@@ -31828,6 +31843,7 @@ function ReactodiaApp(props) {
31828
31843
  translations: translationsForLanguage(language),
31829
31844
  typeStyleResolver: resolveTypeStyle
31830
31845
  }, reactExports.createElement(DefaultWorkspace, {
31846
+ colorScheme: props.theme,
31831
31847
  menu: reactExports.createElement(GraphwiseMenu),
31832
31848
  // place Undo/redo/layout actions in top right corner.
31833
31849
  actionsToolbar: { dock: 'ne' }
@@ -31869,7 +31885,7 @@ function unmountReactodia(root) {
31869
31885
  root.unmount();
31870
31886
  }
31871
31887
 
31872
- const graphwiseReactodiaCss = "graphwise-reactodia{display:block;width:100%;height:75vh}graphwise-reactodia .reactodia-container{position:relative;width:100%;height:100%}graphwise-reactodia .reactodia-selection-action__link{display:none}";
31888
+ const graphwiseReactodiaCss = "graphwise-reactodia{--_graphwise-reactodia-type-color-01:var(--graphwise-reactodia-type-color-01);--_graphwise-reactodia-type-color-02:var(--graphwise-reactodia-type-color-02);--_graphwise-reactodia-type-color-03:var(--graphwise-reactodia-type-color-03);--_graphwise-reactodia-type-color-04:var(--graphwise-reactodia-type-color-04);--_graphwise-reactodia-type-color-05:var(--graphwise-reactodia-type-color-05);--_graphwise-reactodia-type-color-06:var(--graphwise-reactodia-type-color-06);--_graphwise-reactodia-type-color-07:var(--graphwise-reactodia-type-color-07);--_graphwise-reactodia-type-color-08:var(--graphwise-reactodia-type-color-08);--_graphwise-reactodia-type-color-09:var(--graphwise-reactodia-type-color-09);--_graphwise-reactodia-type-color-10:var(--graphwise-reactodia-type-color-10);--_graphwise-reactodia-type-color-11:var(--graphwise-reactodia-type-color-11);--_graphwise-reactodia-type-color-12:var(--graphwise-reactodia-type-color-12);--_graphwise-reactodia-type-color-13:var(--graphwise-reactodia-type-color-13);--_graphwise-reactodia-type-color-14:var(--graphwise-reactodia-type-color-14);--_graphwise-reactodia-type-color-15:var(--graphwise-reactodia-type-color-15);--_graphwise-reactodia-type-color-16:var(--graphwise-reactodia-type-color-16);--_graphwise-reactodia-type-color-17:var(--graphwise-reactodia-type-color-17);--_graphwise-reactodia-type-color-18:var(--graphwise-reactodia-type-color-18);--_graphwise-reactodia-type-color-19:var(--graphwise-reactodia-type-color-19);--_graphwise-reactodia-type-color-20:var(--graphwise-reactodia-type-color-20)}graphwise-reactodia{display:block;width:100%;height:100%}graphwise-reactodia .reactodia-container{position:relative;width:100%;height:100%}graphwise-reactodia .reactodia-selection-action__link{display:none}";
31873
31889
 
31874
31890
  const GraphwiseReactodia = class {
31875
31891
  constructor(hostRef) {
@@ -31904,7 +31920,7 @@ const GraphwiseReactodia = class {
31904
31920
  }
31905
31921
  }
31906
31922
  render() {
31907
- return (index$1.h(index$1.Host, { key: '6f1115b91eac308ef155978dfe1482f152c38b1b' }));
31923
+ return (index$1.h(index$1.Host, { key: 'b2e584a0f1de975692197473d516219a7aa0f42f' }));
31908
31924
  }
31909
31925
  renderGraph(isReloading) {
31910
31926
  var _a;
@@ -31926,6 +31942,7 @@ const GraphwiseReactodia = class {
31926
31942
  config: this.config,
31927
31943
  language: this.language,
31928
31944
  providerSettings: this.providerSettings,
31945
+ theme: this.theme,
31929
31946
  };
31930
31947
  if (this.reactRoot && !isReloading) {
31931
31948
  void updateReactodia(props);
@@ -1,7 +1,50 @@
1
+ graphwise-reactodia {
2
+ /** @prop --graphwise-reactodia-type-color-01: Color slot 1 of 20 for node types */
3
+ --_graphwise-reactodia-type-color-01: var(--graphwise-reactodia-type-color-01);
4
+ /** @prop --graphwise-reactodia-type-color-02: Color slot 2 of 20 for node types */
5
+ --_graphwise-reactodia-type-color-02: var(--graphwise-reactodia-type-color-02);
6
+ /** @prop --graphwise-reactodia-type-color-03: Color slot 3 of 20 for node types */
7
+ --_graphwise-reactodia-type-color-03: var(--graphwise-reactodia-type-color-03);
8
+ /** @prop --graphwise-reactodia-type-color-04: Color slot 4 of 20 for node types */
9
+ --_graphwise-reactodia-type-color-04: var(--graphwise-reactodia-type-color-04);
10
+ /** @prop --graphwise-reactodia-type-color-05: Color slot 5 of 20 for node types */
11
+ --_graphwise-reactodia-type-color-05: var(--graphwise-reactodia-type-color-05);
12
+ /** @prop --graphwise-reactodia-type-color-06: Color slot 6 of 20 for node types */
13
+ --_graphwise-reactodia-type-color-06: var(--graphwise-reactodia-type-color-06);
14
+ /** @prop --graphwise-reactodia-type-color-07: Color slot 7 of 20 for node types */
15
+ --_graphwise-reactodia-type-color-07: var(--graphwise-reactodia-type-color-07);
16
+ /** @prop --graphwise-reactodia-type-color-08: Color slot 8 of 20 for node types */
17
+ --_graphwise-reactodia-type-color-08: var(--graphwise-reactodia-type-color-08);
18
+ /** @prop --graphwise-reactodia-type-color-09: Color slot 9 of 20 for node types */
19
+ --_graphwise-reactodia-type-color-09: var(--graphwise-reactodia-type-color-09);
20
+ /** @prop --graphwise-reactodia-type-color-10: Color slot 10 of 20 for node types */
21
+ --_graphwise-reactodia-type-color-10: var(--graphwise-reactodia-type-color-10);
22
+ /** @prop --graphwise-reactodia-type-color-11: Color slot 11 of 20 for node types */
23
+ --_graphwise-reactodia-type-color-11: var(--graphwise-reactodia-type-color-11);
24
+ /** @prop --graphwise-reactodia-type-color-12: Color slot 12 of 20 for node types */
25
+ --_graphwise-reactodia-type-color-12: var(--graphwise-reactodia-type-color-12);
26
+ /** @prop --graphwise-reactodia-type-color-13: Color slot 13 of 20 for node types */
27
+ --_graphwise-reactodia-type-color-13: var(--graphwise-reactodia-type-color-13);
28
+ /** @prop --graphwise-reactodia-type-color-14: Color slot 14 of 20 for node types */
29
+ --_graphwise-reactodia-type-color-14: var(--graphwise-reactodia-type-color-14);
30
+ /** @prop --graphwise-reactodia-type-color-15: Color slot 15 of 20 for node types */
31
+ --_graphwise-reactodia-type-color-15: var(--graphwise-reactodia-type-color-15);
32
+ /** @prop --graphwise-reactodia-type-color-16: Color slot 16 of 20 for node types */
33
+ --_graphwise-reactodia-type-color-16: var(--graphwise-reactodia-type-color-16);
34
+ /** @prop --graphwise-reactodia-type-color-17: Color slot 17 of 20 for node types */
35
+ --_graphwise-reactodia-type-color-17: var(--graphwise-reactodia-type-color-17);
36
+ /** @prop --graphwise-reactodia-type-color-18: Color slot 18 of 20 for node types */
37
+ --_graphwise-reactodia-type-color-18: var(--graphwise-reactodia-type-color-18);
38
+ /** @prop --graphwise-reactodia-type-color-19: Color slot 19 of 20 for node types */
39
+ --_graphwise-reactodia-type-color-19: var(--graphwise-reactodia-type-color-19);
40
+ /** @prop --graphwise-reactodia-type-color-20: Color slot 20 of 20 for node types */
41
+ --_graphwise-reactodia-type-color-20: var(--graphwise-reactodia-type-color-20);
42
+ }
43
+
1
44
  graphwise-reactodia {
2
45
  display: block;
3
46
  width: 100%;
4
- height: 75vh;
47
+ height: 100%;
5
48
  }
6
49
  graphwise-reactodia .reactodia-container {
7
50
  position: relative;
@@ -45,7 +45,7 @@ export class GraphwiseReactodia {
45
45
  }
46
46
  }
47
47
  render() {
48
- return (h(Host, { key: '6f1115b91eac308ef155978dfe1482f152c38b1b' }));
48
+ return (h(Host, { key: 'b2e584a0f1de975692197473d516219a7aa0f42f' }));
49
49
  }
50
50
  renderGraph(isReloading) {
51
51
  var _a;
@@ -67,6 +67,7 @@ export class GraphwiseReactodia {
67
67
  config: this.config,
68
68
  language: this.language,
69
69
  providerSettings: this.providerSettings,
70
+ theme: this.theme,
70
71
  };
71
72
  if (this.reactRoot && !isReloading) {
72
73
  void updateReactodia(props);
@@ -186,15 +187,15 @@ export class GraphwiseReactodia {
186
187
  "attribute": "theme",
187
188
  "mutable": false,
188
189
  "complexType": {
189
- "original": "string",
190
- "resolved": "string",
190
+ "original": "'light' | 'dark'",
191
+ "resolved": "\"dark\" | \"light\"",
191
192
  "references": {}
192
193
  },
193
194
  "required": false,
194
195
  "optional": true,
195
196
  "docs": {
196
197
  "tags": [],
197
- "text": "The theme currently applied by the host (e.g. `light`, `dark`). The value itself is never read -\nthe node colors are taken from the host's CSS custom properties - it only signals that those\nvalues have changed. The host owns the theme, including whether it follows the OS color scheme,\nso the change is passed in instead of being detected here."
198
+ "text": "The reactodia theme to use"
198
199
  },
199
200
  "getter": false,
200
201
  "setter": false,
@@ -33,6 +33,10 @@ let workspaceContext = null;
33
33
  * the React root.
34
34
  */
35
35
  const subscriptions = new SubscriptionList();
36
+ let diagramStorageSubscription;
37
+ const diagramService = service(DiagramService);
38
+ const diagramStorageService = service(DiagramStorageService);
39
+ const eventService = service(EventService);
36
40
  /**
37
41
  * Builds a Reactodia {@link SparqlDataProvider} for the given endpoint using the supplied
38
42
  * query preset. The host owns the query configuration and always passes it in via props.
@@ -92,20 +96,30 @@ async function seedGraphToCanvas(context, dataProvider, links, signal) {
92
96
  * root in {@link unmountReactodia}.
93
97
  */
94
98
  function onDiagramChange(model) {
95
- const storage = service(DiagramStorageService);
96
- const diagramService = service(DiagramService);
97
- subscriptions.add(diagramService.subscribeToDiagramChange(model, (diagram) => storage.save(diagram)));
99
+ subscribeToDiagramChange(model);
100
+ }
101
+ /**
102
+ * Starts persisting the model's edits to local storage, keeping the subscription in {@link diagramStorageSubscription}.
103
+ */
104
+ function subscribeToDiagramChange(model) {
105
+ diagramStorageSubscription === null || diagramStorageSubscription === void 0 ? void 0 : diagramStorageSubscription();
106
+ diagramStorageSubscription = diagramService.subscribeToDiagramChange(model, (diagram) => diagramStorageService.save(diagram));
107
+ subscriptions.add(diagramStorageSubscription);
98
108
  }
99
109
  /**
100
110
  * Subscribes to the host's "clear persisted diagram" command so the saved layout is dropped on
101
111
  * request (e.g. before a fresh seed should take precedence over previously saved edits). The
102
112
  * subscription is tracked in {@link subscriptions} so it is released together with the React
103
113
  * root in {@link unmountReactodia}.
114
+ *
115
+ * @param model The diagram model whose edits are persisted
104
116
  */
105
- function onClearDiagramStorage() {
106
- const storage = service(DiagramStorageService);
107
- const eventService = service(EventService);
108
- subscriptions.add(eventService.subscribeToClearDiagramStorage(() => storage.clear()));
117
+ function onClearDiagramStorage(model) {
118
+ subscriptions.add(eventService.subscribeToClearDiagramStorage(() => {
119
+ // re-subscribe, to avoid any pending debounced saves, which may write over the cleared diagram
120
+ subscribeToDiagramChange(model);
121
+ diagramStorageService.clear();
122
+ }));
109
123
  }
110
124
  /**
111
125
  * The Reactodia workspace React component.
@@ -124,11 +138,10 @@ function ReactodiaApp(props) {
124
138
  workspaceContext = context;
125
139
  const { model } = context;
126
140
  onDiagramChange(model);
127
- onClearDiagramStorage();
141
+ onClearDiagramStorage(model);
128
142
  const dataProvider = createDataProvider(props);
129
143
  const isReload = props.isReload;
130
- const savedDiagram = service(DiagramStorageService).load();
131
- const diagramService = service(DiagramService);
144
+ const savedDiagram = diagramStorageService.load();
132
145
  if (isReload) {
133
146
  // Reload the diagram that is currently on the canvas. This may happen when the host changes the provider
134
147
  // settings, or when the user switches the language at runtime, since there is no existing mechanism to
@@ -164,6 +177,7 @@ function ReactodiaApp(props) {
164
177
  translations: translationsForLanguage(language),
165
178
  typeStyleResolver: resolveTypeStyle
166
179
  }, createElement(DefaultWorkspace, {
180
+ colorScheme: props.theme,
167
181
  menu: createElement(GraphwiseMenu),
168
182
  // place Undo/redo/layout actions in top right corner.
169
183
  actionsToolbar: { dock: 'ne' }
@@ -46,8 +46,10 @@ let DiagramService = DiagramService_1 = class DiagramService {
46
46
  clearTimeout(notifyTimer);
47
47
  }
48
48
  notifyTimer = setTimeout(() => {
49
+ if (notifyTimer) {
50
+ onChangeCallback(model.exportLayout());
51
+ }
49
52
  notifyTimer = undefined;
50
- onChangeCallback(model.exportLayout());
51
53
  }, DiagramService_1.NOTIFY_DEBOUNCE_MS);
52
54
  };
53
55
  model.history.events.on(DiagramService_1.HISTORY_CHANGED_EVENT, onHistoryChange);
@@ -55,6 +57,7 @@ let DiagramService = DiagramService_1 = class DiagramService {
55
57
  model.history.events.off(DiagramService_1.HISTORY_CHANGED_EVENT, onHistoryChange);
56
58
  if (notifyTimer) {
57
59
  clearTimeout(notifyTimer);
60
+ notifyTimer = undefined;
58
61
  }
59
62
  };
60
63
  }
@@ -1,31 +1,30 @@
1
- const NODE_COLOR_VARIABLES = [
2
- '--gw-foreground-visual-diagram-categorical-01',
3
- '--gw-foreground-visual-diagram-categorical-02',
4
- '--gw-foreground-visual-diagram-categorical-03',
5
- '--gw-foreground-visual-diagram-categorical-04',
6
- '--gw-foreground-visual-diagram-categorical-05',
7
- '--gw-foreground-visual-diagram-categorical-06',
8
- '--gw-foreground-visual-diagram-categorical-07',
9
- '--gw-foreground-visual-diagram-categorical-08',
10
- '--gw-foreground-visual-diagram-categorical-09',
11
- '--gw-foreground-visual-diagram-categorical-10',
12
- '--gw-foreground-visual-diagram-categorical-11',
13
- '--gw-foreground-visual-diagram-categorical-12',
14
- '--gw-foreground-visual-diagram-categorical-13',
15
- '--gw-foreground-visual-diagram-categorical-14',
16
- '--gw-foreground-visual-diagram-categorical-15',
17
- '--gw-foreground-visual-diagram-categorical-16',
18
- '--gw-foreground-visual-diagram-categorical-17',
19
- '--gw-foreground-visual-diagram-categorical-18',
20
- '--gw-foreground-visual-diagram-categorical-19',
21
- '--gw-foreground-visual-diagram-categorical-20'
22
- ];
23
1
  /**
24
2
  * Color slot assigned to each type, in the order the types are first seen.
25
3
  */
26
4
  const typeToIndex = new Map();
27
- function getColor(variable) {
28
- return getComputedStyle(document.documentElement).getPropertyValue(variable).trim();
5
+ /**
6
+ * Returns the internal property of the given palette slot, numbered from 1 and padded to two digits as in `_theme.scss`.
7
+ */
8
+ function getTypeColorProperty(slot) {
9
+ return `--_graphwise-reactodia-type-color-${String(slot).padStart(2, '0')}`;
10
+ }
11
+ /**
12
+ * Reads the type palette of the Theme API: the internal properties `_theme.scss` resolves from the ones
13
+ * the host declares, in slot order up to the first empty one.
14
+ */
15
+ function getPalette() {
16
+ const host = document.querySelector('graphwise-reactodia');
17
+ if (!host) {
18
+ return [];
19
+ }
20
+ const style = getComputedStyle(host);
21
+ const palette = [];
22
+ let color = style.getPropertyValue(getTypeColorProperty(1)).trim();
23
+ while (color) {
24
+ palette.push(color);
25
+ color = style.getPropertyValue(getTypeColorProperty(palette.length + 1)).trim();
26
+ }
27
+ return palette;
29
28
  }
30
29
  /**
31
30
  * Colors an element by its type: each type takes the next color from the palette, which wraps
@@ -45,8 +44,8 @@ export const resolveTypeStyle = (types) => {
45
44
  index = typeToIndex.size;
46
45
  typeToIndex.set(type, index);
47
46
  }
48
- const color = getColor(NODE_COLOR_VARIABLES[index % NODE_COLOR_VARIABLES.length]);
49
- return color ? { color } : undefined;
47
+ const colors = getPalette();
48
+ return colors.length ? { color: colors[index % colors.length] } : undefined;
50
49
  };
51
50
  export const resetColors = () => {
52
51
  typeToIndex.clear();
@@ -49,6 +49,10 @@ function setLanguage(language) {
49
49
  reactodia.language = language;
50
50
  }
51
51
 
52
+ function setTheme(theme) {
53
+ reactodia.theme = theme;
54
+ }
55
+
52
56
  // The host asks the component to drop its persisted diagram by dispatching a namespaced window
53
57
  // event, rather than holding an element reference and calling a method on it.
54
58
  function clearDiagramStorage() {
@@ -31374,8 +31374,10 @@ let DiagramService = DiagramService_1 = class DiagramService {
31374
31374
  clearTimeout(notifyTimer);
31375
31375
  }
31376
31376
  notifyTimer = setTimeout(() => {
31377
+ if (notifyTimer) {
31378
+ onChangeCallback(model.exportLayout());
31379
+ }
31377
31380
  notifyTimer = undefined;
31378
- onChangeCallback(model.exportLayout());
31379
31381
  }, DiagramService_1.NOTIFY_DEBOUNCE_MS);
31380
31382
  };
31381
31383
  model.history.events.on(DiagramService_1.HISTORY_CHANGED_EVENT, onHistoryChange);
@@ -31383,6 +31385,7 @@ let DiagramService = DiagramService_1 = class DiagramService {
31383
31385
  model.history.events.off(DiagramService_1.HISTORY_CHANGED_EVENT, onHistoryChange);
31384
31386
  if (notifyTimer) {
31385
31387
  clearTimeout(notifyTimer);
31388
+ notifyTimer = undefined;
31386
31389
  }
31387
31390
  };
31388
31391
  }
@@ -31524,34 +31527,33 @@ class SubscriptionList {
31524
31527
  }
31525
31528
  }
31526
31529
 
31527
- const NODE_COLOR_VARIABLES = [
31528
- '--gw-foreground-visual-diagram-categorical-01',
31529
- '--gw-foreground-visual-diagram-categorical-02',
31530
- '--gw-foreground-visual-diagram-categorical-03',
31531
- '--gw-foreground-visual-diagram-categorical-04',
31532
- '--gw-foreground-visual-diagram-categorical-05',
31533
- '--gw-foreground-visual-diagram-categorical-06',
31534
- '--gw-foreground-visual-diagram-categorical-07',
31535
- '--gw-foreground-visual-diagram-categorical-08',
31536
- '--gw-foreground-visual-diagram-categorical-09',
31537
- '--gw-foreground-visual-diagram-categorical-10',
31538
- '--gw-foreground-visual-diagram-categorical-11',
31539
- '--gw-foreground-visual-diagram-categorical-12',
31540
- '--gw-foreground-visual-diagram-categorical-13',
31541
- '--gw-foreground-visual-diagram-categorical-14',
31542
- '--gw-foreground-visual-diagram-categorical-15',
31543
- '--gw-foreground-visual-diagram-categorical-16',
31544
- '--gw-foreground-visual-diagram-categorical-17',
31545
- '--gw-foreground-visual-diagram-categorical-18',
31546
- '--gw-foreground-visual-diagram-categorical-19',
31547
- '--gw-foreground-visual-diagram-categorical-20'
31548
- ];
31549
31530
  /**
31550
31531
  * Color slot assigned to each type, in the order the types are first seen.
31551
31532
  */
31552
31533
  const typeToIndex = new Map();
31553
- function getColor(variable) {
31554
- return getComputedStyle(document.documentElement).getPropertyValue(variable).trim();
31534
+ /**
31535
+ * Returns the internal property of the given palette slot, numbered from 1 and padded to two digits as in `_theme.scss`.
31536
+ */
31537
+ function getTypeColorProperty(slot) {
31538
+ return `--_graphwise-reactodia-type-color-${String(slot).padStart(2, '0')}`;
31539
+ }
31540
+ /**
31541
+ * Reads the type palette of the Theme API: the internal properties `_theme.scss` resolves from the ones
31542
+ * the host declares, in slot order up to the first empty one.
31543
+ */
31544
+ function getPalette() {
31545
+ const host = document.querySelector('graphwise-reactodia');
31546
+ if (!host) {
31547
+ return [];
31548
+ }
31549
+ const style = getComputedStyle(host);
31550
+ const palette = [];
31551
+ let color = style.getPropertyValue(getTypeColorProperty(1)).trim();
31552
+ while (color) {
31553
+ palette.push(color);
31554
+ color = style.getPropertyValue(getTypeColorProperty(palette.length + 1)).trim();
31555
+ }
31556
+ return palette;
31555
31557
  }
31556
31558
  /**
31557
31559
  * Colors an element by its type: each type takes the next color from the palette, which wraps
@@ -31571,8 +31573,8 @@ const resolveTypeStyle = (types) => {
31571
31573
  index = typeToIndex.size;
31572
31574
  typeToIndex.set(type, index);
31573
31575
  }
31574
- const color = getColor(NODE_COLOR_VARIABLES[index % NODE_COLOR_VARIABLES.length]);
31575
- return color ? { color } : undefined;
31576
+ const colors = getPalette();
31577
+ return colors.length ? { color: colors[index % colors.length] } : undefined;
31576
31578
  };
31577
31579
  const resetColors = () => {
31578
31580
  typeToIndex.clear();
@@ -31695,6 +31697,10 @@ let workspaceContext = null;
31695
31697
  * the React root.
31696
31698
  */
31697
31699
  const subscriptions = new SubscriptionList();
31700
+ let diagramStorageSubscription;
31701
+ const diagramService = service(DiagramService);
31702
+ const diagramStorageService = service(DiagramStorageService);
31703
+ const eventService = service(EventService);
31698
31704
  /**
31699
31705
  * Builds a Reactodia {@link SparqlDataProvider} for the given endpoint using the supplied
31700
31706
  * query preset. The host owns the query configuration and always passes it in via props.
@@ -31754,20 +31760,30 @@ async function seedGraphToCanvas(context, dataProvider, links, signal) {
31754
31760
  * root in {@link unmountReactodia}.
31755
31761
  */
31756
31762
  function onDiagramChange(model) {
31757
- const storage = service(DiagramStorageService);
31758
- const diagramService = service(DiagramService);
31759
- subscriptions.add(diagramService.subscribeToDiagramChange(model, (diagram) => storage.save(diagram)));
31763
+ subscribeToDiagramChange(model);
31764
+ }
31765
+ /**
31766
+ * Starts persisting the model's edits to local storage, keeping the subscription in {@link diagramStorageSubscription}.
31767
+ */
31768
+ function subscribeToDiagramChange(model) {
31769
+ diagramStorageSubscription === null || diagramStorageSubscription === void 0 ? void 0 : diagramStorageSubscription();
31770
+ diagramStorageSubscription = diagramService.subscribeToDiagramChange(model, (diagram) => diagramStorageService.save(diagram));
31771
+ subscriptions.add(diagramStorageSubscription);
31760
31772
  }
31761
31773
  /**
31762
31774
  * Subscribes to the host's "clear persisted diagram" command so the saved layout is dropped on
31763
31775
  * request (e.g. before a fresh seed should take precedence over previously saved edits). The
31764
31776
  * subscription is tracked in {@link subscriptions} so it is released together with the React
31765
31777
  * root in {@link unmountReactodia}.
31778
+ *
31779
+ * @param model The diagram model whose edits are persisted
31766
31780
  */
31767
- function onClearDiagramStorage() {
31768
- const storage = service(DiagramStorageService);
31769
- const eventService = service(EventService);
31770
- subscriptions.add(eventService.subscribeToClearDiagramStorage(() => storage.clear()));
31781
+ function onClearDiagramStorage(model) {
31782
+ subscriptions.add(eventService.subscribeToClearDiagramStorage(() => {
31783
+ // re-subscribe, to avoid any pending debounced saves, which may write over the cleared diagram
31784
+ subscribeToDiagramChange(model);
31785
+ diagramStorageService.clear();
31786
+ }));
31771
31787
  }
31772
31788
  /**
31773
31789
  * The Reactodia workspace React component.
@@ -31786,11 +31802,10 @@ function ReactodiaApp(props) {
31786
31802
  workspaceContext = context;
31787
31803
  const { model } = context;
31788
31804
  onDiagramChange(model);
31789
- onClearDiagramStorage();
31805
+ onClearDiagramStorage(model);
31790
31806
  const dataProvider = createDataProvider(props);
31791
31807
  const isReload = props.isReload;
31792
- const savedDiagram = service(DiagramStorageService).load();
31793
- const diagramService = service(DiagramService);
31808
+ const savedDiagram = diagramStorageService.load();
31794
31809
  if (isReload) {
31795
31810
  // Reload the diagram that is currently on the canvas. This may happen when the host changes the provider
31796
31811
  // settings, or when the user switches the language at runtime, since there is no existing mechanism to
@@ -31826,6 +31841,7 @@ function ReactodiaApp(props) {
31826
31841
  translations: translationsForLanguage(language),
31827
31842
  typeStyleResolver: resolveTypeStyle
31828
31843
  }, reactExports.createElement(DefaultWorkspace, {
31844
+ colorScheme: props.theme,
31829
31845
  menu: reactExports.createElement(GraphwiseMenu),
31830
31846
  // place Undo/redo/layout actions in top right corner.
31831
31847
  actionsToolbar: { dock: 'ne' }
@@ -31867,7 +31883,7 @@ function unmountReactodia(root) {
31867
31883
  root.unmount();
31868
31884
  }
31869
31885
 
31870
- const graphwiseReactodiaCss = "graphwise-reactodia{display:block;width:100%;height:75vh}graphwise-reactodia .reactodia-container{position:relative;width:100%;height:100%}graphwise-reactodia .reactodia-selection-action__link{display:none}";
31886
+ const graphwiseReactodiaCss = "graphwise-reactodia{--_graphwise-reactodia-type-color-01:var(--graphwise-reactodia-type-color-01);--_graphwise-reactodia-type-color-02:var(--graphwise-reactodia-type-color-02);--_graphwise-reactodia-type-color-03:var(--graphwise-reactodia-type-color-03);--_graphwise-reactodia-type-color-04:var(--graphwise-reactodia-type-color-04);--_graphwise-reactodia-type-color-05:var(--graphwise-reactodia-type-color-05);--_graphwise-reactodia-type-color-06:var(--graphwise-reactodia-type-color-06);--_graphwise-reactodia-type-color-07:var(--graphwise-reactodia-type-color-07);--_graphwise-reactodia-type-color-08:var(--graphwise-reactodia-type-color-08);--_graphwise-reactodia-type-color-09:var(--graphwise-reactodia-type-color-09);--_graphwise-reactodia-type-color-10:var(--graphwise-reactodia-type-color-10);--_graphwise-reactodia-type-color-11:var(--graphwise-reactodia-type-color-11);--_graphwise-reactodia-type-color-12:var(--graphwise-reactodia-type-color-12);--_graphwise-reactodia-type-color-13:var(--graphwise-reactodia-type-color-13);--_graphwise-reactodia-type-color-14:var(--graphwise-reactodia-type-color-14);--_graphwise-reactodia-type-color-15:var(--graphwise-reactodia-type-color-15);--_graphwise-reactodia-type-color-16:var(--graphwise-reactodia-type-color-16);--_graphwise-reactodia-type-color-17:var(--graphwise-reactodia-type-color-17);--_graphwise-reactodia-type-color-18:var(--graphwise-reactodia-type-color-18);--_graphwise-reactodia-type-color-19:var(--graphwise-reactodia-type-color-19);--_graphwise-reactodia-type-color-20:var(--graphwise-reactodia-type-color-20)}graphwise-reactodia{display:block;width:100%;height:100%}graphwise-reactodia .reactodia-container{position:relative;width:100%;height:100%}graphwise-reactodia .reactodia-selection-action__link{display:none}";
31871
31887
 
31872
31888
  const GraphwiseReactodia = class {
31873
31889
  constructor(hostRef) {
@@ -31902,7 +31918,7 @@ const GraphwiseReactodia = class {
31902
31918
  }
31903
31919
  }
31904
31920
  render() {
31905
- return (h(Host, { key: '6f1115b91eac308ef155978dfe1482f152c38b1b' }));
31921
+ return (h(Host, { key: 'b2e584a0f1de975692197473d516219a7aa0f42f' }));
31906
31922
  }
31907
31923
  renderGraph(isReloading) {
31908
31924
  var _a;
@@ -31924,6 +31940,7 @@ const GraphwiseReactodia = class {
31924
31940
  config: this.config,
31925
31941
  language: this.language,
31926
31942
  providerSettings: this.providerSettings,
31943
+ theme: this.theme,
31927
31944
  };
31928
31945
  if (this.reactRoot && !isReloading) {
31929
31946
  void updateReactodia(props);
@@ -1 +1 @@
1
- import{p as e,b as r}from"./p-Cypw7ydc.js";export{s as setNonce}from"./p-Cypw7ydc.js";import{g as t}from"./p-CalY52z6.js";(()=>{const r=import.meta.url,t={};return""!==r&&(t.resourcesUrl=new URL(".",r).href),e(t)})().then((async e=>(await t(),r([["p-420b9dce",[[0,"graphwise-reactodia",{currentRepository:[1,"current-repository"],config:[16],language:[1],providerSettings:[16,"provider-settings"],theme:[1]},null,{currentRepository:["onCurrentRepositoryChange"],language:["onLanguageOrSettingsChange"],providerSettings:["onLanguageOrSettingsChange"],theme:["onThemeChange"]}]]]],e))));
1
+ import{p as e,b as r}from"./p-Cypw7ydc.js";export{s as setNonce}from"./p-Cypw7ydc.js";import{g as t}from"./p-CalY52z6.js";(()=>{const r=import.meta.url,t={};return""!==r&&(t.resourcesUrl=new URL(".",r).href),e(t)})().then((async e=>(await t(),r([["p-0cb06f14",[[0,"graphwise-reactodia",{currentRepository:[1,"current-repository"],config:[16],language:[1],providerSettings:[16,"provider-settings"],theme:[1]},null,{currentRepository:["onCurrentRepositoryChange"],language:["onLanguageOrSettingsChange"],providerSettings:["onLanguageOrSettingsChange"],theme:["onThemeChange"]}]]]],e))));