pict-section-flow 0.0.18 → 0.0.19

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.
@@ -0,0 +1,150 @@
1
+ # Theme integration
2
+
3
+ `pict-section-flow` participates in the host application's theme system in two layers:
4
+
5
+ 1. **Host theme (light/dark/palette)** — provided by `pict-provider-theme` via `--theme-color-*` CSS custom properties on `:root` and a `theme-light` / `theme-dark` class on `<html>`.
6
+ 2. **Flow visual theme (sketch, blueprint, mono, retro-80s, retro-90s, whiteboard, default)** — provided by the editor's own `PictProvider-Flow-Theme` and applied as scope-local overrides on `.pict-flow-container`.
7
+
8
+ Both layers cooperate. The flow editor's `--pf-*` tokens default to the matching `--theme-color-*` token, so when the host swaps light/dark or palette, all neutral flow chrome (panels, toolbars, text, connections, grid) updates with no JS work. Visual themes that intentionally diverge from the host palette (e.g. blueprint's deep blue canvas, retro-80s neon) override the relevant `--pf-*` tokens explicitly.
9
+
10
+ ## Host wiring
11
+
12
+ When a host application registers `pict-provider-theme`:
13
+
14
+ ```javascript
15
+ const libPictProviderTheme = require('pict-provider-theme');
16
+ pict.addProvider('Theme', libPictProviderTheme.default_configuration, libPictProviderTheme);
17
+ pict.providers.Theme.registerTheme(require('pict-provider-theme/source/themes/retold-default.json'));
18
+ pict.providers.Theme.applyTheme('retold-default', 'system');
19
+ ```
20
+
21
+ …the flow editor automatically detects it during `onBeforeInitialize` (duck-typed via `applyTheme`/`onApply`/`listThemes`) and subscribes to its `onApply` hook. On every host theme change the editor:
22
+
23
+ - Re-runs `_CSSProvider.registerCSS()` so CSS layered on top by the active flow visual theme stays in the cascade.
24
+ - Calls `_reinjectMarkerDefs()` so SVG `<marker>` arrowhead polygons rebuild with the new fills.
25
+ - Calls `renderFlow()` to repaint nodes/connections (so any inline-rendered colors refresh).
26
+
27
+ No code changes are required in host apps beyond installing and applying `pict-provider-theme` as you would for any other consumer.
28
+
29
+ ## Token mapping
30
+
31
+ | Flow token (`--pf-…`) | Host token (`--theme-color-…`) | Hardcoded fallback |
32
+ |---|---|---|
33
+ | `--pf-text-primary` | `text-primary` | `#2c3e50` |
34
+ | `--pf-text-secondary` | `text-secondary` | `#7f8c8d` |
35
+ | `--pf-text-tertiary` | `text-muted` | `#8e99a4` |
36
+ | `--pf-node-body-fill` | `background-panel` | `#ffffff` |
37
+ | `--pf-node-body-stroke` | `border-default` | `#d0d4d8` |
38
+ | `--pf-node-body-stroke-hover` | `border-strong` | `#b0b8c0` |
39
+ | `--pf-node-selected-stroke` | `brand-primary` | `#3498db` |
40
+ | `--pf-node-shadow` (and hover/dragging) | `shadow-color` | `rgba(0,0,0,0.10)` |
41
+ | `--pf-port-input-fill` | `status-info` | `#3498db` |
42
+ | `--pf-port-output-fill` | `status-success` | `#2ecc71` |
43
+ | `--pf-port-error-fill` | `status-error` | `#e74c3c` |
44
+ | `--pf-connection-stroke` | `border-strong` | `#95a5a6` |
45
+ | `--pf-connection-selected-stroke` | `brand-primary` | `#3498db` |
46
+ | `--pf-panel-bg` | `background-panel` | `#ffffff` |
47
+ | `--pf-panel-titlebar-bg` | `background-secondary` | `#f7f8fa` |
48
+ | `--pf-toolbar-bg` | `background-panel` | `#ffffff` |
49
+ | `--pf-toolbar-border` | `border-default` | `#e0e0e0` |
50
+ | `--pf-canvas-bg` | `background-secondary` | `#fafafa` |
51
+ | `--pf-grid-stroke` | `border-light` | `#e8e8e8` |
52
+ | `--pf-input-border` | `border-default` | `#d5d8dc` |
53
+ | `--pf-input-border-focus` | `focus-outline` | `#3498db` |
54
+
55
+ Tokens not in this list (e.g. node-variant fills, Chart.js-style category colors) keep hardcoded values because they aren't conventionally part of host palettes.
56
+
57
+ ## Card color roles
58
+
59
+ Card types and individual nodes can opt into a **color role** that tracks the host theme automatically. Roles are class-driven, so changing the host theme repaints every card using that role with no JS work.
60
+
61
+ ### Available roles
62
+
63
+ | Role | Tracks | Typical use |
64
+ |---|---|---|
65
+ | `success` | `--theme-color-status-success` | Start, success, complete |
66
+ | `warning` | `--theme-color-status-warning` | Decision, caution, conditional |
67
+ | `error` | `--theme-color-status-error` | Halt, error, abort |
68
+ | `info` | `--theme-color-status-info` | Informational, log, debug |
69
+ | `accent` | `--theme-color-brand-accent` | End, brand-flavored highlights |
70
+ | `neutral` | `--theme-color-text-primary` + `--theme-color-background-panel` | Default, generic |
71
+
72
+ Each role exposes `--pf-color-<role>` (the strong/title-bar color) and `--pf-color-<role>-soft` (a tinted body fill computed via `color-mix(...)` against the strong color). Hosts can override either token at any scope to retint a role globally.
73
+
74
+ ### Built-in node types
75
+
76
+ The five default node types ship with roles wired up:
77
+
78
+ | Type | Role |
79
+ |---|---|
80
+ | `default` | `neutral` |
81
+ | `start` | `success` |
82
+ | `end` | `accent` |
83
+ | `halt` | `error` |
84
+ | `decision` | `warning` |
85
+
86
+ Their hex `TitleBarColor` / `BodyStyle` fields remain as fallbacks for code paths that bypass CSS (legacy consumers, exports). When the role's CSS class is in effect, those hex presentation attributes are overridden by the role rules — host themes propagate, but the hex values keep the editor presentable in unstyled contexts.
87
+
88
+ ### Custom card types
89
+
90
+ ```javascript
91
+ flowView._NodeTypeProvider.registerNodeType('my-card-type', {
92
+ Hash: 'my-card-type',
93
+ Label: 'My Card',
94
+ DefaultPorts: [ /* … */ ],
95
+ ColorRole: 'info', // theme-aware
96
+ TitleBarColor: '#3498db', // optional fallback
97
+ BodyStyle: { fill: '#ebf5fb' } // optional fallback
98
+ });
99
+ ```
100
+
101
+ The renderer adds `pict-flow-node-color-info` to the node group; CSS handles the rest.
102
+
103
+ ### Per-node overrides
104
+
105
+ A specific card can override the role its type defines:
106
+
107
+ ```javascript
108
+ flowData.Nodes.push({
109
+ Hash: 'node-special',
110
+ Type: 'my-card-type',
111
+ ColorRole: 'warning', // override the type's role
112
+ // …
113
+ });
114
+ ```
115
+
116
+ Set `ColorRole: 'none'` on a specific node to opt out of role styling entirely (useful when keeping a custom hex via `Style.BodyFill` etc.).
117
+
118
+ ### Custom roles
119
+
120
+ To define new roles, add `--pf-color-<role>` / `--pf-color-<role>-soft` tokens at `.pict-flow-container` scope and matching `.pict-flow-node-color-<role>` CSS rules in your host stylesheet:
121
+
122
+ ```css
123
+ .pict-flow-container {
124
+ --pf-color-experimental: var(--theme-color-brand-primary, #6b8eff);
125
+ --pf-color-experimental-soft: color-mix(in srgb, var(--pf-color-experimental) 14%, transparent);
126
+ }
127
+ .pict-flow-node-color-experimental .pict-flow-node-body {
128
+ fill: var(--pf-color-experimental-soft);
129
+ stroke: var(--pf-color-experimental);
130
+ stroke-width: 1.5;
131
+ }
132
+ .pict-flow-node-color-experimental .pict-flow-node-title-bar,
133
+ .pict-flow-node-color-experimental .pict-flow-node-title-bar-bottom {
134
+ fill: var(--pf-color-experimental);
135
+ }
136
+ ```
137
+
138
+ ## Arrowhead markers
139
+
140
+ `<marker>` elements live inside `<defs>` and don't pick up the same CSS variable cascade as regular SVG content in every browser. To make them theme-tracking, each generated polygon now carries a class (`pict-flow-arrowhead-default`, `pict-flow-arrowhead-selected`, `pict-flow-arrowhead-event-in`, …) and the corresponding CSS rule sets `fill` to the matching `--pf-…` token. The `fill="…"` attribute remains on the polygon as a graceful fallback when CSS can't reach it.
141
+
142
+ ## Flow visual themes
143
+
144
+ The seven flow themes (`default`, `sketch`, `blueprint`, `mono`, `retro-80s`, `retro-90s`, `whiteboard`) ship with explicit `CSSVariables` and `AdditionalCSS` blocks. They layer on top of the host theme by emitting their overrides into `.pict-flow-container { … }`. Because `:root`-scoped host tokens have lower specificity than `.pict-flow-container`-scoped flow tokens, the visual theme always wins where it sets a value, and the host theme controls everything it doesn't.
145
+
146
+ The `default` flow theme intentionally sets no overrides — it lets the host theme drive the look.
147
+
148
+ ## Disabling host integration
149
+
150
+ If a host wants the flow editor to ignore the host theme (e.g. to keep a fixed Sketch-style appearance regardless of the surrounding page), don't apply a host theme provider — or unsubscribe after construction by calling the dispose function returned via `flowView._HostThemeUnsubscribe`. This is rarely needed; flow visual themes already win where they care.
package/docs/_sidebar.md CHANGED
@@ -3,6 +3,7 @@
3
3
  - [Overview](/)
4
4
  - [Quick Start](Getting_Started.md)
5
5
  - [Custom Styling](Custom-Styling.md)
6
+ - [Theme Integration](Theme_Integration.md)
6
7
 
7
8
  - Architecture
8
9
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pict-section-flow",
3
- "version": "0.0.18",
3
+ "version": "0.0.19",
4
4
  "description": "Pict Section Flow Diagram",
5
5
  "main": "source/Pict-Section-Flow.js",
6
6
  "scripts": {
@@ -14,16 +14,16 @@
14
14
  "license": "MIT",
15
15
  "dependencies": {
16
16
  "fable-serviceproviderbase": "^3.0.19",
17
- "pict-provider": "^1.0.12",
18
- "pict-section-form": "^1.0.195",
19
- "pict-view": "^1.0.67"
17
+ "pict-provider": "^1.0.13",
18
+ "pict-section-form": "^1.0.196",
19
+ "pict-view": "^1.0.68"
20
20
  },
21
21
  "devDependencies": {
22
22
  "chai": "^6.2.2",
23
23
  "mocha": "^11.7.5",
24
- "pict": "^1.0.359",
25
- "pict-docuserve": "^0.1.5",
26
- "pict-router": "^1.0.9",
27
- "quackage": "^1.1.0"
24
+ "pict": "^1.0.367",
25
+ "pict-docuserve": "^0.1.6",
26
+ "pict-router": "^1.0.10",
27
+ "quackage": "^1.2.3"
28
28
  }
29
29
  }
@@ -37,31 +37,37 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
37
37
  /* ── Design Tokens ─────────────────────────────────────
38
38
  Override these custom properties to theme the flow diagram.
39
39
  Node-type classes (.pict-flow-node-{type}) can scope-override
40
- any variable for per-type variation. */
40
+ any variable for per-type variation.
41
+
42
+ Defaults reference the host application's pict-provider-theme
43
+ tokens (--theme-color-*) when available, with hardcoded
44
+ fallbacks so the editor still looks reasonable in unthemed
45
+ contexts. Internal flow themes (sketch, blueprint, etc.) keep
46
+ layering on top via .pict-flow-container scoped overrides. */
41
47
 
42
48
  /* Text */
43
- --pf-text-primary: #2c3e50;
44
- --pf-text-heading: #1a252f;
45
- --pf-text-secondary: #7f8c8d;
46
- --pf-text-tertiary: #8e99a4;
47
- --pf-text-placeholder: #95a5a6;
49
+ --pf-text-primary: var(--theme-color-text-primary, #2c3e50);
50
+ --pf-text-heading: var(--theme-color-text-primary, #1a252f);
51
+ --pf-text-secondary: var(--theme-color-text-secondary, #7f8c8d);
52
+ --pf-text-tertiary: var(--theme-color-text-muted, #8e99a4);
53
+ --pf-text-placeholder: var(--theme-color-text-placeholder, #95a5a6);
48
54
 
49
55
  /* Node */
50
56
  --pf-node-body-fill: var(--theme-color-background-panel, #ffffff);
51
- --pf-node-body-stroke: #d0d4d8;
52
- --pf-node-body-stroke-hover: #b0b8c0;
57
+ --pf-node-body-stroke: var(--theme-color-border-default, #d0d4d8);
58
+ --pf-node-body-stroke-hover: var(--theme-color-border-strong, #b0b8c0);
53
59
  --pf-node-body-stroke-width: 1;
54
60
  --pf-node-body-radius: 8px;
55
- --pf-node-shadow: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.10));
56
- --pf-node-shadow-hover: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.15));
61
+ --pf-node-shadow: drop-shadow(0 1px 3px var(--theme-color-shadow-color, rgba(0, 0, 0, 0.10)));
62
+ --pf-node-shadow-hover: drop-shadow(0 2px 6px var(--theme-color-shadow-color, rgba(0, 0, 0, 0.15)));
57
63
  --pf-node-shadow-selected: drop-shadow(0 2px 8px rgba(52, 152, 219, 0.25));
58
- --pf-node-shadow-dragging: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.20));
64
+ --pf-node-shadow-dragging: drop-shadow(0 4px 12px var(--theme-color-shadow-color, rgba(0, 0, 0, 0.20)));
59
65
  --pf-node-title-fill: var(--theme-color-background-panel, #ffffff);
60
66
  --pf-node-title-size: 11.5px;
61
67
  --pf-node-title-weight: 600;
62
- --pf-node-title-bar-color: #2c3e50;
63
- --pf-node-type-label-fill: #a0a8b0;
64
- --pf-node-selected-stroke: #3498db;
68
+ --pf-node-title-bar-color: var(--theme-color-text-primary, #2c3e50);
69
+ --pf-node-type-label-fill: var(--theme-color-text-muted, #a0a8b0);
70
+ --pf-node-selected-stroke: var(--theme-color-brand-primary, #3498db);
65
71
 
66
72
  /* Node Variants */
67
73
  --pf-node-start-fill: #eafaf1;
@@ -73,83 +79,111 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
73
79
  --pf-node-decision-fill: #fff9e6;
74
80
  --pf-node-decision-stroke: var(--theme-color-status-warning, #f39c12);
75
81
 
82
+ /* ── Color roles ───────────────────────────────────────
83
+ Generic, theme-aware semantic colors that node types and
84
+ individual cards opt into via a ColorRole field. The
85
+ "-soft" variant is the tinted background; the bare role is
86
+ the title-bar / outline / accent stroke.
87
+
88
+ Hosts can override any of these tokens at .pict-flow-container
89
+ scope (or at their own scope) without touching JS. Built-in
90
+ node types resolve their visuals through these tokens, so
91
+ theming a role automatically retints every card that uses it.
92
+
93
+ Soft tints use color-mix() — supported in Chrome 111+,
94
+ Safari 16.2+, Firefox 113+. The hardcoded fallbacks keep the
95
+ editor presentable on older engines. */
96
+ --pf-color-success: var(--theme-color-status-success, #27ae60);
97
+ --pf-color-success-soft: color-mix(in srgb, var(--pf-color-success) 12%, transparent);
98
+ --pf-color-warning: var(--theme-color-status-warning, #f39c12);
99
+ --pf-color-warning-soft: color-mix(in srgb, var(--pf-color-warning) 14%, transparent);
100
+ --pf-color-error: var(--theme-color-status-error, #e74c3c);
101
+ --pf-color-error-soft: color-mix(in srgb, var(--pf-color-error) 12%, transparent);
102
+ --pf-color-info: var(--theme-color-status-info, #3498db);
103
+ --pf-color-info-soft: color-mix(in srgb, var(--pf-color-info) 12%, transparent);
104
+ --pf-color-accent: var(--theme-color-brand-accent, #1abc9c);
105
+ --pf-color-accent-soft: color-mix(in srgb, var(--pf-color-accent) 14%, transparent);
106
+ --pf-color-neutral: var(--theme-color-text-primary, #2c3e50);
107
+ --pf-color-neutral-soft: var(--theme-color-background-panel, #ffffff);
108
+ --pf-color-neutral-onfill: var(--theme-color-background-panel, #ffffff);
109
+
76
110
  /* Ports */
77
- --pf-port-input-fill: #3498db;
111
+ --pf-port-input-fill: var(--theme-color-status-info, #3498db);
78
112
  --pf-port-output-fill: var(--theme-color-status-success, #2ecc71);
79
113
  --pf-port-stroke: var(--theme-color-background-panel, #ffffff);
80
114
  --pf-port-stroke-width: 2;
81
115
  --pf-port-label-bg: rgba(255, 253, 240, 0.5);
82
- --pf-port-label-text: #2c3e50;
116
+ --pf-port-label-text: var(--theme-color-text-primary, #2c3e50);
83
117
 
84
118
  /* Port Type Colors */
85
- --pf-port-event-in-fill: #3498db;
119
+ --pf-port-event-in-fill: var(--theme-color-status-info, #3498db);
86
120
  --pf-port-event-out-fill: var(--theme-color-status-success, #2ecc71);
87
121
  --pf-port-setting-fill: #e67e22;
88
122
  --pf-port-value-fill: #f1c40f;
89
123
  --pf-port-error-fill: var(--theme-color-status-error, #e74c3c);
90
124
 
91
125
  /* Connection Type Colors (match source port) */
92
- --pf-connection-event-in-stroke: #3498db;
126
+ --pf-connection-event-in-stroke: var(--theme-color-status-info, #3498db);
93
127
  --pf-connection-event-out-stroke: var(--theme-color-status-success, #2ecc71);
94
128
  --pf-connection-setting-stroke: #e67e22;
95
129
  --pf-connection-value-stroke: #f1c40f;
96
130
  --pf-connection-error-stroke: var(--theme-color-status-error, #e74c3c);
97
131
 
98
132
  /* Connections */
99
- --pf-connection-stroke: #95a5a6;
100
- --pf-connection-stroke-hover: #7f8c8d;
101
- --pf-connection-selected-stroke: #3498db;
133
+ --pf-connection-stroke: var(--theme-color-border-strong, #95a5a6);
134
+ --pf-connection-stroke-hover: var(--theme-color-text-secondary, #7f8c8d);
135
+ --pf-connection-selected-stroke: var(--theme-color-brand-primary, #3498db);
102
136
 
103
137
  /* Panels */
104
- --pf-panel-bg: #ffffff;
105
- --pf-panel-border: #d0d4d8;
138
+ --pf-panel-bg: var(--theme-color-background-panel, #ffffff);
139
+ --pf-panel-border: var(--theme-color-border-default, #d0d4d8);
106
140
  --pf-panel-radius: 8px;
107
- --pf-panel-shadow: 0 4px 12px rgba(0,0,0,0.10), 0 1px 3px rgba(0,0,0,0.06);
108
- --pf-panel-titlebar-bg: #f7f8fa;
109
- --pf-panel-titlebar-border: #e8eaed;
110
- --pf-panel-title-color: #2c3e50;
141
+ --pf-panel-shadow: 0 4px 12px var(--theme-color-shadow-color, rgba(0, 0, 0, 0.10)), 0 1px 3px var(--theme-color-shadow-color, rgba(0, 0, 0, 0.06));
142
+ --pf-panel-titlebar-bg: var(--theme-color-background-secondary, #f7f8fa);
143
+ --pf-panel-titlebar-border: var(--theme-color-border-light, #e8eaed);
144
+ --pf-panel-title-color: var(--theme-color-text-primary, #2c3e50);
111
145
 
112
146
  /* Tabs */
113
- --pf-tab-text: #8e99a4;
114
- --pf-tab-text-hover: #5a6a7a;
147
+ --pf-tab-text: var(--theme-color-text-muted, #8e99a4);
148
+ --pf-tab-text-hover: var(--theme-color-text-secondary, #5a6a7a);
115
149
  --pf-tab-active-border: var(--pf-node-selected-stroke);
116
- --pf-resize-handle-hover: #e0e3e6;
150
+ --pf-resize-handle-hover: var(--theme-color-border-light, #e0e3e6);
117
151
 
118
152
  /* Forms & Inputs */
119
- --pf-input-border: #d5d8dc;
120
- --pf-input-border-focus: #3498db;
121
- --pf-divider-light: #ecf0f1;
122
- --pf-divider-medium: #e8eaed;
153
+ --pf-input-border: var(--theme-color-border-default, #d5d8dc);
154
+ --pf-input-border-focus: var(--theme-color-focus-outline, #3498db);
155
+ --pf-divider-light: var(--theme-color-border-light, #ecf0f1);
156
+ --pf-divider-medium: var(--theme-color-border-light, #e8eaed);
123
157
 
124
158
  /* Buttons */
125
- --pf-button-border: #bdc3c7;
126
- --pf-button-hover-border: #95a5a6;
127
- --pf-button-hover-bg: #ecf0f1;
128
- --pf-button-active-bg: #d5dbdb;
129
- --pf-button-danger-text: #e74c3c;
159
+ --pf-button-border: var(--theme-color-border-default, #bdc3c7);
160
+ --pf-button-hover-border: var(--theme-color-border-strong, #95a5a6);
161
+ --pf-button-hover-bg: var(--theme-color-background-hover, #ecf0f1);
162
+ --pf-button-active-bg: var(--theme-color-background-selected, #d5dbdb);
163
+ --pf-button-danger-text: var(--theme-color-status-error, #e74c3c);
130
164
  --pf-button-danger-hover-bg: #fdedec;
131
- --pf-button-close-color: #b0b8c0;
165
+ --pf-button-close-color: var(--theme-color-text-muted, #b0b8c0);
132
166
 
133
167
  /* Badges */
134
- --pf-badge-category-bg: #f0f2f4;
135
- --pf-badge-category-text: #6b7b8d;
168
+ --pf-badge-category-bg: var(--theme-color-background-tertiary, #f0f2f4);
169
+ --pf-badge-category-text: var(--theme-color-text-secondary, #6b7b8d);
136
170
  --pf-badge-code-bg: #eaf2f8;
137
171
  --pf-badge-code-text: #2980b9;
138
172
 
139
173
  /* Info Panel */
140
- --pf-port-item-bg: #f8f9fa;
174
+ --pf-port-item-bg: var(--theme-color-background-secondary, #f8f9fa);
141
175
 
142
176
  /* Toolbar */
143
- --pf-toolbar-bg: #ffffff;
177
+ --pf-toolbar-bg: var(--theme-color-background-panel, #ffffff);
144
178
  --pf-toolbar-border: var(--theme-color-border-default, #e0e0e0);
145
179
 
146
180
  /* Palette Cards */
147
- --pf-card-border: #d5d8dc;
148
- --pf-card-hover-bg: #eaf2f8;
181
+ --pf-card-border: var(--theme-color-border-default, #d5d8dc);
182
+ --pf-card-hover-bg: var(--theme-color-background-hover, #eaf2f8);
149
183
  --pf-card-hover-shadow: 0 1px 3px rgba(52, 152, 219, 0.15);
150
184
 
151
185
  /* Canvas */
152
- --pf-canvas-bg: #fafafa;
186
+ --pf-canvas-bg: var(--theme-color-background-secondary, #fafafa);
153
187
  --pf-grid-stroke: var(--theme-color-border-light, #e8e8e8);
154
188
 
155
189
  position: relative;
@@ -330,6 +364,94 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
330
364
  stroke: var(--pf-node-halt-stroke);
331
365
  stroke-width: 1.5;
332
366
  }
367
+
368
+ /* ── Color-role variants ────────────────────────────────
369
+ Cards opt into a role via ColorRole on the node-type config or
370
+ a per-node override. The renderer adds .pict-flow-node-color-{role}
371
+ to the node group, which pulls fill/stroke/title-bar colors from
372
+ the --pf-color-* tokens — those in turn track the host's
373
+ --theme-color-* tokens so light/dark/palette swaps propagate.
374
+
375
+ Roles deliberately don't override .pict-flow-node-body-content-*
376
+ styling — the body content's visual identity is the consumer's
377
+ responsibility. */
378
+ .pict-flow-node-color-success .pict-flow-node-body {
379
+ fill: var(--pf-color-success-soft);
380
+ stroke: var(--pf-color-success);
381
+ stroke-width: 1.5;
382
+ }
383
+ .pict-flow-node-color-success .pict-flow-node-title-bar,
384
+ .pict-flow-node-color-success .pict-flow-node-title-bar-bottom {
385
+ fill: var(--pf-color-success);
386
+ }
387
+ .pict-flow-node-color-success .pict-flow-node-bracket {
388
+ stroke: var(--pf-color-success);
389
+ }
390
+
391
+ .pict-flow-node-color-warning .pict-flow-node-body {
392
+ fill: var(--pf-color-warning-soft);
393
+ stroke: var(--pf-color-warning);
394
+ stroke-width: 1.5;
395
+ }
396
+ .pict-flow-node-color-warning .pict-flow-node-title-bar,
397
+ .pict-flow-node-color-warning .pict-flow-node-title-bar-bottom {
398
+ fill: var(--pf-color-warning);
399
+ }
400
+ .pict-flow-node-color-warning .pict-flow-node-bracket {
401
+ stroke: var(--pf-color-warning);
402
+ }
403
+
404
+ .pict-flow-node-color-error .pict-flow-node-body {
405
+ fill: var(--pf-color-error-soft);
406
+ stroke: var(--pf-color-error);
407
+ stroke-width: 1.5;
408
+ }
409
+ .pict-flow-node-color-error .pict-flow-node-title-bar,
410
+ .pict-flow-node-color-error .pict-flow-node-title-bar-bottom {
411
+ fill: var(--pf-color-error);
412
+ }
413
+ .pict-flow-node-color-error .pict-flow-node-bracket {
414
+ stroke: var(--pf-color-error);
415
+ }
416
+
417
+ .pict-flow-node-color-info .pict-flow-node-body {
418
+ fill: var(--pf-color-info-soft);
419
+ stroke: var(--pf-color-info);
420
+ stroke-width: 1.5;
421
+ }
422
+ .pict-flow-node-color-info .pict-flow-node-title-bar,
423
+ .pict-flow-node-color-info .pict-flow-node-title-bar-bottom {
424
+ fill: var(--pf-color-info);
425
+ }
426
+ .pict-flow-node-color-info .pict-flow-node-bracket {
427
+ stroke: var(--pf-color-info);
428
+ }
429
+
430
+ .pict-flow-node-color-accent .pict-flow-node-body {
431
+ fill: var(--pf-color-accent-soft);
432
+ stroke: var(--pf-color-accent);
433
+ stroke-width: 1.5;
434
+ }
435
+ .pict-flow-node-color-accent .pict-flow-node-title-bar,
436
+ .pict-flow-node-color-accent .pict-flow-node-title-bar-bottom {
437
+ fill: var(--pf-color-accent);
438
+ }
439
+ .pict-flow-node-color-accent .pict-flow-node-bracket {
440
+ stroke: var(--pf-color-accent);
441
+ }
442
+
443
+ .pict-flow-node-color-neutral .pict-flow-node-body {
444
+ fill: var(--pf-color-neutral-soft);
445
+ stroke: var(--pf-color-neutral);
446
+ stroke-width: 1;
447
+ }
448
+ .pict-flow-node-color-neutral .pict-flow-node-title-bar,
449
+ .pict-flow-node-color-neutral .pict-flow-node-title-bar-bottom {
450
+ fill: var(--pf-color-neutral);
451
+ }
452
+ .pict-flow-node-color-neutral .pict-flow-node-bracket {
453
+ stroke: var(--pf-color-neutral);
454
+ }
333
455
  `;
334
456
  }
335
457
 
@@ -588,6 +710,34 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
588
710
  getConnectionCSS()
589
711
  {
590
712
  return /*css*/`
713
+ /* Arrowhead markers use CSS-driven fills so they follow --pf-* tokens
714
+ (which in turn map to host --theme-color-* tokens). The polygon's
715
+ fill attribute is the fallback when CSS does not reach the marker. */
716
+ .pict-flow-svg .pict-flow-arrowhead-default {
717
+ fill: var(--pf-connection-stroke);
718
+ }
719
+ .pict-flow-svg .pict-flow-arrowhead-selected {
720
+ fill: var(--pf-connection-selected-stroke);
721
+ }
722
+ .pict-flow-svg .pict-flow-arrowhead-tether {
723
+ fill: var(--pf-connection-stroke);
724
+ }
725
+ .pict-flow-svg .pict-flow-arrowhead-event-in {
726
+ fill: var(--pf-connection-event-in-stroke);
727
+ }
728
+ .pict-flow-svg .pict-flow-arrowhead-event-out {
729
+ fill: var(--pf-connection-event-out-stroke);
730
+ }
731
+ .pict-flow-svg .pict-flow-arrowhead-setting {
732
+ fill: var(--pf-connection-setting-stroke);
733
+ }
734
+ .pict-flow-svg .pict-flow-arrowhead-value {
735
+ fill: var(--pf-connection-value-stroke);
736
+ }
737
+ .pict-flow-svg .pict-flow-arrowhead-error {
738
+ fill: var(--pf-connection-error-stroke);
739
+ }
740
+
591
741
  .pict-flow-connection {
592
742
  fill: none;
593
743
  stroke: var(--pf-connection-stroke);
@@ -409,14 +409,18 @@ class PictProviderFlowConnectorShapes extends libFableServiceProviderBase
409
409
 
410
410
  let tmpMarkup = '';
411
411
 
412
- // Normal connection arrowhead (default gray)
412
+ // Normal connection arrowhead class-driven fill so the host theme's
413
+ // --theme-color-* tokens (mapped to --pf-connection-stroke etc. in
414
+ // PictProvider-Flow-CSS) flow through automatically. The polygon's
415
+ // `fill` attribute is kept as a fallback for environments that
416
+ // ignore CSS rules on marker children.
413
417
  tmpMarkup += '<marker id="flow-arrowhead-' + pViewIdentifier + '"'
414
418
  + ' markerWidth="' + tmpConnectionMarker.MarkerWidth + '"'
415
419
  + ' markerHeight="' + tmpConnectionMarker.MarkerHeight + '"'
416
420
  + ' refX="' + tmpConnectionMarker.RefX + '"'
417
421
  + ' refY="' + tmpConnectionMarker.RefY + '"'
418
422
  + ' orient="auto" markerUnits="strokeWidth">'
419
- + '<polygon points="' + tmpConnectionMarker.Points + '" fill="' + tmpConnectionMarker.Fill + '" />'
423
+ + '<polygon class="pict-flow-arrowhead pict-flow-arrowhead-default" points="' + tmpConnectionMarker.Points + '" fill="' + tmpConnectionMarker.Fill + '" />'
420
424
  + '</marker>';
421
425
 
422
426
  // Per-port-type connection arrowheads
@@ -437,7 +441,7 @@ class PictProviderFlowConnectorShapes extends libFableServiceProviderBase
437
441
  + ' refX="' + tmpConnectionMarker.RefX + '"'
438
442
  + ' refY="' + tmpConnectionMarker.RefY + '"'
439
443
  + ' orient="auto" markerUnits="strokeWidth">'
440
- + '<polygon points="' + tmpConnectionMarker.Points + '" fill="' + tmpPortTypeColors[tmpType] + '" />'
444
+ + '<polygon class="pict-flow-arrowhead pict-flow-arrowhead-' + tmpType + '" points="' + tmpConnectionMarker.Points + '" fill="' + tmpPortTypeColors[tmpType] + '" />'
441
445
  + '</marker>';
442
446
  }
443
447
 
@@ -448,7 +452,7 @@ class PictProviderFlowConnectorShapes extends libFableServiceProviderBase
448
452
  + ' refX="' + tmpSelectedMarker.RefX + '"'
449
453
  + ' refY="' + tmpSelectedMarker.RefY + '"'
450
454
  + ' orient="auto" markerUnits="strokeWidth">'
451
- + '<polygon points="' + tmpSelectedMarker.Points + '" fill="' + tmpSelectedMarker.Fill + '" />'
455
+ + '<polygon class="pict-flow-arrowhead pict-flow-arrowhead-selected" points="' + tmpSelectedMarker.Points + '" fill="' + tmpSelectedMarker.Fill + '" />'
452
456
  + '</marker>';
453
457
 
454
458
  // Tether arrowhead
@@ -458,7 +462,7 @@ class PictProviderFlowConnectorShapes extends libFableServiceProviderBase
458
462
  + ' refX="' + tmpTetherMarker.RefX + '"'
459
463
  + ' refY="' + tmpTetherMarker.RefY + '"'
460
464
  + ' orient="auto" markerUnits="strokeWidth">'
461
- + '<polygon points="' + tmpTetherMarker.Points + '" fill="' + tmpTetherMarker.Fill + '" />'
465
+ + '<polygon class="pict-flow-arrowhead pict-flow-arrowhead-tether" points="' + tmpTetherMarker.Points + '" fill="' + tmpTetherMarker.Fill + '" />'
462
466
  + '</marker>';
463
467
 
464
468
  return tmpMarkup;
@@ -1,5 +1,10 @@
1
1
  const libPictProvider = require('pict-provider');
2
2
 
3
+ // Built-in node types reference theme-aware roles via `ColorRole`. The
4
+ // hex `TitleBarColor` / `BodyStyle` values remain as fallbacks for
5
+ // rendering paths that bypass CSS (legacy consumers, exports). When a
6
+ // role is set, the renderer skips applying those hex attributes — the
7
+ // role's CSS class drives the visuals so theme swaps propagate.
3
8
  const _DefaultNodeTypes =
4
9
  {
5
10
  'default':
@@ -13,6 +18,7 @@ const _DefaultNodeTypes =
13
18
  { Hash: null, Direction: 'input', Side: 'left', Label: 'In' },
14
19
  { Hash: null, Direction: 'output', Side: 'right', Label: 'Out' }
15
20
  ],
21
+ ColorRole: 'neutral',
16
22
  TitleBarColor: '#2c3e50',
17
23
  BodyStyle: {}
18
24
  },
@@ -26,6 +32,7 @@ const _DefaultNodeTypes =
26
32
  [
27
33
  { Hash: null, Direction: 'output', Side: 'right', Label: 'Out' }
28
34
  ],
35
+ ColorRole: 'success',
29
36
  TitleBarColor: '#27ae60',
30
37
  BodyStyle:
31
38
  {
@@ -43,6 +50,7 @@ const _DefaultNodeTypes =
43
50
  [
44
51
  { Hash: null, Direction: 'input', Side: 'left', Label: 'In' }
45
52
  ],
53
+ ColorRole: 'accent',
46
54
  TitleBarColor: '#1abc9c',
47
55
  BodyStyle:
48
56
  {
@@ -60,6 +68,7 @@ const _DefaultNodeTypes =
60
68
  [
61
69
  { Hash: null, Direction: 'input', Side: 'left', Label: 'In' }
62
70
  ],
71
+ ColorRole: 'error',
63
72
  TitleBarColor: '#e74c3c',
64
73
  BodyStyle:
65
74
  {
@@ -79,6 +88,7 @@ const _DefaultNodeTypes =
79
88
  { Hash: null, Direction: 'output', Side: 'right', Label: 'Yes' },
80
89
  { Hash: null, Direction: 'output', Side: 'bottom', Label: 'No' }
81
90
  ],
91
+ ColorRole: 'warning',
82
92
  TitleBarColor: '#f39c12',
83
93
  BodyStyle:
84
94
  {
@@ -50,7 +50,11 @@ class PictProviderFlowPanelChrome extends libFableServiceProviderBase
50
50
  let tmpPict = this._FlowView.pict || this._FlowView.fable;
51
51
  let tmpTitle = pPanelData.Title || 'Properties';
52
52
  let tmpChromeHTML = tmpPict.parseTemplateByHash('Flow-PanelChrome-Template',
53
- { Hash: pPanelData.Hash, Title: tmpTitle });
53
+ {
54
+ Hash: pPanelData.Hash,
55
+ Title: tmpTitle,
56
+ FlowViewIdentifier: this._FlowView.options.ViewIdentifier
57
+ });
54
58
 
55
59
  tmpFO.innerHTML = tmpChromeHTML;
56
60
 
@@ -65,22 +69,8 @@ class PictProviderFlowPanelChrome extends libFableServiceProviderBase
65
69
  tmpCloseIcon.textContent = '\u2715';
66
70
  }
67
71
 
68
- // Attach event isolation to the scrollable content area so
69
- // pointer/wheel events inside the panel do not trigger SVG interactions
70
- let tmpContent = tmpFO.querySelector('.pict-flow-panel-content');
71
- if (tmpContent)
72
- {
73
- tmpContent.addEventListener('pointerdown', (pEvent) => { pEvent.stopPropagation(); });
74
- tmpContent.addEventListener('wheel', (pEvent) => { pEvent.stopPropagation(); });
75
- }
76
-
77
- // Isolate events on the tab bar
78
- let tmpTabbar = tmpFO.querySelector('.pict-flow-panel-tabbar');
79
- if (tmpTabbar)
80
- {
81
- tmpTabbar.addEventListener('pointerdown', (pEvent) => { pEvent.stopPropagation(); });
82
- tmpTabbar.addEventListener('wheel', (pEvent) => { pEvent.stopPropagation(); });
83
- }
72
+ // Pointer/wheel isolation lives on the inline onpointerdown/onwheel
73
+ // attributes in Flow-PanelChrome-Template see PictView-Flow.js.
84
74
 
85
75
  pPanelsLayer.appendChild(tmpFO);
86
76