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.
- package/docs/Theme_Integration.md +150 -0
- package/docs/_sidebar.md +1 -0
- package/package.json +8 -8
- package/source/providers/PictProvider-Flow-CSS.js +197 -47
- package/source/providers/PictProvider-Flow-ConnectorShapes.js +9 -5
- package/source/providers/PictProvider-Flow-NodeTypes.js +10 -0
- package/source/providers/PictProvider-Flow-PanelChrome.js +7 -17
- package/source/services/PictService-Flow-InteractionManager.js +39 -42
- package/source/services/PictService-Flow-PortRenderer.js +10 -24
- package/source/views/PictView-Flow-FloatingToolbar.js +69 -61
- package/source/views/PictView-Flow-Node.js +19 -6
- package/source/views/PictView-Flow-PropertiesPanel.js +46 -53
- package/source/views/PictView-Flow-Toolbar.js +664 -789
- package/source/views/PictView-Flow.js +183 -2
|
@@ -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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pict-section-flow",
|
|
3
|
-
"version": "0.0.
|
|
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.
|
|
18
|
-
"pict-section-form": "^1.0.
|
|
19
|
-
"pict-view": "^1.0.
|
|
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.
|
|
25
|
-
"pict-docuserve": "^0.1.
|
|
26
|
-
"pict-router": "^1.0.
|
|
27
|
-
"quackage": "^1.
|
|
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
|
|
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
|
-
{
|
|
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
|
-
//
|
|
69
|
-
//
|
|
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
|
|