pict-section-flow 0.0.16 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -18
- package/docs/Architecture.md +1 -1
- package/docs/Data_Model.md +2 -2
- package/docs/Getting_Started.md +5 -5
- package/docs/Implementation_Reference.md +6 -6
- package/docs/Layout_Persistence.md +3 -3
- package/docs/README.md +12 -12
- package/docs/_cover.md +1 -1
- package/docs/_sidebar.md +6 -6
- package/docs/_version.json +7 -0
- package/docs/api/PictFlowCard.md +6 -6
- package/docs/api/PictFlowCardPropertiesPanel.md +2 -2
- package/docs/api/addConnection.md +4 -4
- package/docs/api/addNode.md +6 -6
- package/docs/api/autoLayout.md +2 -2
- package/docs/api/getFlowData.md +5 -5
- package/docs/api/marshalToView.md +3 -3
- package/docs/api/openPanel.md +2 -2
- package/docs/api/registerHandler.md +3 -3
- package/docs/api/registerNodeType.md +3 -3
- package/docs/api/removeConnection.md +5 -5
- package/docs/api/removeNode.md +6 -6
- package/docs/api/saveLayout.md +2 -2
- package/docs/api/screenToSVGCoords.md +2 -2
- package/docs/api/selectNode.md +3 -3
- package/docs/api/setTheme.md +2 -2
- package/docs/api/setZoom.md +3 -3
- package/docs/api/toggleFullscreen.md +2 -2
- package/docs/card-help/EACH.md +3 -3
- package/docs/card-help/FREAD.md +5 -5
- package/docs/card-help/FWRITE.md +5 -5
- package/docs/card-help/GET.md +2 -2
- package/docs/card-help/ITE.md +3 -3
- package/docs/card-help/LOG.md +4 -4
- package/docs/card-help/NOTE.md +1 -1
- package/docs/card-help/PREV.md +2 -2
- package/docs/card-help/SET.md +5 -5
- package/docs/card-help/SPKL.md +2 -2
- package/docs/card-help/STAT.md +3 -3
- package/docs/card-help/SW.md +4 -4
- package/docs/css/docuserve.css +277 -23
- package/docs/index.html +2 -2
- package/docs/retold-catalog.json +1 -1
- package/docs/retold-keyword-index.json +1 -1
- package/example_applications/simple_cards/css/flowexample.css +2 -2
- package/example_applications/simple_cards/source/card-help-content.js +12 -12
- package/example_applications/simple_cards/source/cards/FlowCard-DataPreview.js +1 -1
- package/example_applications/simple_cards/source/sample-flows.js +410 -0
- package/example_applications/simple_cards/source/views/PictView-FlowExample-About.js +5 -5
- package/example_applications/simple_cards/source/views/PictView-FlowExample-Documentation.js +5 -5
- package/example_applications/simple_cards/source/views/PictView-FlowExample-FileWriteInfo.js +4 -4
- package/example_applications/simple_cards/source/views/PictView-FlowExample-MainWorkspace.js +141 -8
- package/example_applications/simple_cards/source/views/PictView-FlowExample-TopBar.js +2 -2
- package/package.json +3 -2
- package/source/Pict-Section-Flow.js +26 -0
- package/source/providers/PictProvider-Flow-CSS.js +244 -14
- package/source/providers/PictProvider-Flow-Theme.js +7 -7
- package/source/providers/edges/Edge-Bezier.js +41 -0
- package/source/providers/edges/Edge-Orthogonal.js +37 -0
- package/source/providers/edges/Edge-OrthogonalSnap.js +72 -0
- package/source/providers/edges/Edge-Perimeter-Linear.js +31 -0
- package/source/providers/edges/Edge-Perimeter-Orthogonal.js +39 -0
- package/source/providers/edges/Edge-Perimeter.js +48 -0
- package/source/providers/edges/Edge-PerimeterMath.js +92 -0
- package/source/providers/edges/Edge-Straight.js +24 -0
- package/source/providers/layouts/Layout-Circular.js +203 -0
- package/source/providers/layouts/Layout-Coerce.js +40 -0
- package/source/providers/layouts/Layout-Columnar.js +134 -0
- package/source/providers/layouts/Layout-Custom.js +27 -0
- package/source/providers/layouts/Layout-ForcedFromCenter.js +256 -0
- package/source/providers/layouts/Layout-Grid.js +134 -0
- package/source/providers/layouts/Layout-Layered.js +209 -0
- package/source/providers/layouts/Layout-Tabular.js +94 -0
- package/source/services/PictService-Flow-ConnectionRenderer.js +532 -28
- package/source/services/PictService-Flow-DataManager.js +12 -1
- package/source/services/PictService-Flow-Layout.js +305 -121
- package/source/services/PictService-Flow-PortRenderer.js +122 -26
- package/source/services/PictService-Flow-RenderManager.js +41 -11
- package/source/views/PictView-Flow-FloatingToolbar.js +3 -3
- package/source/views/PictView-Flow-Node.js +28 -0
- package/source/views/PictView-Flow-Toolbar.js +715 -10
- package/source/views/PictView-Flow.js +272 -5
- package/test/Layout_tests.js +1400 -0
- package/test/PortRenderer_tests.js +11 -2
package/example_applications/simple_cards/source/views/PictView-FlowExample-MainWorkspace.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const libPictView = require('pict-view');
|
|
2
2
|
const libPictSectionFlow = require('pict-section-flow');
|
|
3
|
+
const libSampleFlows = require('../sample-flows.js');
|
|
3
4
|
|
|
4
5
|
// FlowCard definitions
|
|
5
6
|
const libFlowCardIfThenElse = require('../cards/FlowCard-IfThenElse.js');
|
|
@@ -36,7 +37,7 @@ const _ViewConfiguration =
|
|
|
36
37
|
flex-shrink: 0;
|
|
37
38
|
margin: 0 0 0.75em 0;
|
|
38
39
|
padding-bottom: 0.75em;
|
|
39
|
-
border-bottom: 1px solid #eee;
|
|
40
|
+
border-bottom: 1px solid var(--theme-color-border-light, #eee);
|
|
40
41
|
display: flex;
|
|
41
42
|
align-items: flex-start;
|
|
42
43
|
justify-content: space-between;
|
|
@@ -59,7 +60,7 @@ const _ViewConfiguration =
|
|
|
59
60
|
height: 36px;
|
|
60
61
|
border-radius: 50%;
|
|
61
62
|
border: 2px solid #3498db;
|
|
62
|
-
background: #fff;
|
|
63
|
+
background: var(--theme-color-background-panel, #fff);
|
|
63
64
|
color: #3498db;
|
|
64
65
|
font-size: 1.2em;
|
|
65
66
|
font-weight: 700;
|
|
@@ -71,16 +72,57 @@ const _ViewConfiguration =
|
|
|
71
72
|
}
|
|
72
73
|
.flowexample-help-toggle:hover {
|
|
73
74
|
background: #3498db;
|
|
74
|
-
color: #fff;
|
|
75
|
+
color: var(--theme-color-background-panel, #fff);
|
|
75
76
|
}
|
|
76
77
|
.flowexample-help-toggle.active {
|
|
77
78
|
background: #3498db;
|
|
78
|
-
color: #fff;
|
|
79
|
+
color: var(--theme-color-background-panel, #fff);
|
|
79
80
|
}
|
|
80
81
|
#FlowExample-Flow-Container {
|
|
81
82
|
flex: 1;
|
|
82
83
|
min-height: 0;
|
|
83
84
|
}
|
|
85
|
+
.flowexample-sample-bar {
|
|
86
|
+
flex-shrink: 0;
|
|
87
|
+
margin: 0 0 0.75em 0;
|
|
88
|
+
padding: 0.6em 0.75em;
|
|
89
|
+
background: var(--theme-color-background-panel, #fff);
|
|
90
|
+
border: 1px solid var(--theme-color-border-light, #dee2e6);
|
|
91
|
+
border-radius: 6px;
|
|
92
|
+
display: flex;
|
|
93
|
+
align-items: center;
|
|
94
|
+
gap: 0.6em;
|
|
95
|
+
flex-wrap: wrap;
|
|
96
|
+
}
|
|
97
|
+
.flowexample-sample-bar label {
|
|
98
|
+
font-weight: 600;
|
|
99
|
+
color: #2c3e50;
|
|
100
|
+
font-size: 0.9em;
|
|
101
|
+
}
|
|
102
|
+
.flowexample-sample-bar select {
|
|
103
|
+
padding: 0.35em 0.55em;
|
|
104
|
+
border: 1px solid #ced4da;
|
|
105
|
+
border-radius: 4px;
|
|
106
|
+
background: #fff;
|
|
107
|
+
font-size: 0.95em;
|
|
108
|
+
min-width: 220px;
|
|
109
|
+
}
|
|
110
|
+
.flowexample-sample-description {
|
|
111
|
+
flex: 1;
|
|
112
|
+
min-width: 280px;
|
|
113
|
+
color: #5a6470;
|
|
114
|
+
font-size: 0.85em;
|
|
115
|
+
line-height: 1.4;
|
|
116
|
+
}
|
|
117
|
+
.flowexample-sample-recommended {
|
|
118
|
+
padding: 0.2em 0.55em;
|
|
119
|
+
background: #eaf6ee;
|
|
120
|
+
color: #1f7a3f;
|
|
121
|
+
border-radius: 4px;
|
|
122
|
+
font-size: 0.8em;
|
|
123
|
+
font-weight: 600;
|
|
124
|
+
white-space: nowrap;
|
|
125
|
+
}
|
|
84
126
|
.flowexample-help-panel {
|
|
85
127
|
flex-shrink: 0;
|
|
86
128
|
display: none;
|
|
@@ -105,8 +147,8 @@ const _ViewConfiguration =
|
|
|
105
147
|
gap: 1em;
|
|
106
148
|
}
|
|
107
149
|
.flowexample-hint {
|
|
108
|
-
background: #fff;
|
|
109
|
-
border: 1px solid #e0e0e0;
|
|
150
|
+
background: var(--theme-color-background-panel, #fff);
|
|
151
|
+
border: 1px solid var(--theme-color-border-default, #e0e0e0);
|
|
110
152
|
border-radius: 6px;
|
|
111
153
|
padding: 1em 1.25em;
|
|
112
154
|
}
|
|
@@ -117,7 +159,7 @@ const _ViewConfiguration =
|
|
|
117
159
|
}
|
|
118
160
|
.flowexample-hint p {
|
|
119
161
|
margin: 0;
|
|
120
|
-
color: #666;
|
|
162
|
+
color: var(--theme-color-text-secondary, #666);
|
|
121
163
|
font-size: 0.85em;
|
|
122
164
|
line-height: 1.5;
|
|
123
165
|
}
|
|
@@ -126,7 +168,7 @@ const _ViewConfiguration =
|
|
|
126
168
|
padding: 0.1em 0.3em;
|
|
127
169
|
border-radius: 3px;
|
|
128
170
|
font-size: 0.9em;
|
|
129
|
-
color: #e74c3c;
|
|
171
|
+
color: var(--theme-color-status-error, #e74c3c);
|
|
130
172
|
}
|
|
131
173
|
`,
|
|
132
174
|
|
|
@@ -180,6 +222,12 @@ const _ViewConfiguration =
|
|
|
180
222
|
</div>
|
|
181
223
|
</div>
|
|
182
224
|
</div>
|
|
225
|
+
<div class="flowexample-sample-bar">
|
|
226
|
+
<label for="FlowExample-SampleSelect">Sample graph:</label>
|
|
227
|
+
<select id="FlowExample-SampleSelect"></select>
|
|
228
|
+
<span class="flowexample-sample-recommended" id="FlowExample-SampleRecommended"></span>
|
|
229
|
+
<span class="flowexample-sample-description" id="FlowExample-SampleDescription">Pick a sample, then open the <strong>Algorithm</strong> popup in the toolbar to compare layouts.</span>
|
|
230
|
+
</div>
|
|
183
231
|
<div id="FlowExample-Flow-Container"></div>
|
|
184
232
|
</div>
|
|
185
233
|
`
|
|
@@ -311,8 +359,93 @@ class FlowExampleMainWorkspaceView extends libPictView
|
|
|
311
359
|
});
|
|
312
360
|
}
|
|
313
361
|
|
|
362
|
+
// Populate the sample-graph selector and wire its change handler.
|
|
363
|
+
this._populateSampleSelector();
|
|
364
|
+
|
|
314
365
|
return super.onAfterRender(pRenderable, pRenderDestinationAddress, pRecord, pContent);
|
|
315
366
|
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Populate the sample-graph dropdown above the flow diagram and wire
|
|
370
|
+
* the change handler. The first option ("Hello World") is the rich
|
|
371
|
+
* default flow that lives in AppData.FlowExample.SampleFlow; the rest
|
|
372
|
+
* come from sample-flows.js and showcase a different layout strength.
|
|
373
|
+
*/
|
|
374
|
+
_populateSampleSelector()
|
|
375
|
+
{
|
|
376
|
+
let tmpSelect = document.getElementById('FlowExample-SampleSelect');
|
|
377
|
+
let tmpDesc = document.getElementById('FlowExample-SampleDescription');
|
|
378
|
+
let tmpReco = document.getElementById('FlowExample-SampleRecommended');
|
|
379
|
+
if (!tmpSelect || !tmpDesc || !tmpReco) return;
|
|
380
|
+
|
|
381
|
+
// Clear pre-existing options
|
|
382
|
+
while (tmpSelect.firstChild) tmpSelect.removeChild(tmpSelect.firstChild);
|
|
383
|
+
|
|
384
|
+
let tmpHelloOpt = document.createElement('option');
|
|
385
|
+
tmpHelloOpt.value = '__hello-world__';
|
|
386
|
+
tmpHelloOpt.textContent = 'Hello World — multi-feature reference';
|
|
387
|
+
tmpSelect.appendChild(tmpHelloOpt);
|
|
388
|
+
|
|
389
|
+
let tmpKeys = libSampleFlows.getSampleNames();
|
|
390
|
+
for (let i = 0; i < tmpKeys.length; i++)
|
|
391
|
+
{
|
|
392
|
+
let tmpSample = libSampleFlows.getSample(tmpKeys[i]);
|
|
393
|
+
let tmpOpt = document.createElement('option');
|
|
394
|
+
tmpOpt.value = tmpKeys[i];
|
|
395
|
+
tmpOpt.textContent = tmpSample.Name;
|
|
396
|
+
tmpSelect.appendChild(tmpOpt);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Initial description (Hello World)
|
|
400
|
+
tmpDesc.innerHTML = 'Pick a sample, then open the <strong>Algorithm</strong> popup in the toolbar to compare layouts.';
|
|
401
|
+
tmpReco.style.display = 'none';
|
|
402
|
+
|
|
403
|
+
let tmpView = this;
|
|
404
|
+
tmpSelect.addEventListener('change', function ()
|
|
405
|
+
{
|
|
406
|
+
let tmpKey = tmpSelect.value;
|
|
407
|
+
tmpView._loadSample(tmpKey, tmpDesc, tmpReco);
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Load a sample flow into the FlowView. `__hello-world__` reloads the
|
|
413
|
+
* original AppData-backed flow; everything else comes from sample-flows.
|
|
414
|
+
*
|
|
415
|
+
* @param {string} pKey
|
|
416
|
+
* @param {HTMLElement} pDescEl
|
|
417
|
+
* @param {HTMLElement} pRecoEl
|
|
418
|
+
*/
|
|
419
|
+
_loadSample(pKey, pDescEl, pRecoEl)
|
|
420
|
+
{
|
|
421
|
+
if (!this._FlowView) return;
|
|
422
|
+
|
|
423
|
+
if (pKey === '__hello-world__')
|
|
424
|
+
{
|
|
425
|
+
this._FlowView.setFlowData(this.pict.AppData.FlowExample.SampleFlow);
|
|
426
|
+
pDescEl.innerHTML = 'The full reference flow with all card types, properties panels, and an error branch. Originally designed by hand — set <code>LayoutAlgorithm</code> to <em>Layered</em> to see how the auto-layout compares.';
|
|
427
|
+
pRecoEl.style.display = 'none';
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
let tmpSample = libSampleFlows.getSample(pKey);
|
|
432
|
+
if (!tmpSample) return;
|
|
433
|
+
|
|
434
|
+
// setFlowData expects a fresh _FlowData-shaped object — deep clone so
|
|
435
|
+
// re-loading the same sample doesn't share mutated node references
|
|
436
|
+
// with prior loads.
|
|
437
|
+
this._FlowView.setFlowData(JSON.parse(JSON.stringify(tmpSample.Flow)));
|
|
438
|
+
pDescEl.textContent = tmpSample.Description;
|
|
439
|
+
if (tmpSample.Recommended)
|
|
440
|
+
{
|
|
441
|
+
pRecoEl.style.display = '';
|
|
442
|
+
pRecoEl.textContent = `Try: ${tmpSample.Recommended}`;
|
|
443
|
+
}
|
|
444
|
+
else
|
|
445
|
+
{
|
|
446
|
+
pRecoEl.style.display = 'none';
|
|
447
|
+
}
|
|
448
|
+
}
|
|
316
449
|
}
|
|
317
450
|
|
|
318
451
|
module.exports = FlowExampleMainWorkspaceView;
|
|
@@ -32,7 +32,7 @@ const _ViewConfiguration =
|
|
|
32
32
|
cursor: pointer;
|
|
33
33
|
}
|
|
34
34
|
.flowexample-topbar-brand:hover {
|
|
35
|
-
color: #fff;
|
|
35
|
+
color: var(--theme-color-background-panel, #fff);
|
|
36
36
|
}
|
|
37
37
|
.flowexample-topbar-nav {
|
|
38
38
|
display: flex;
|
|
@@ -50,7 +50,7 @@ const _ViewConfiguration =
|
|
|
50
50
|
}
|
|
51
51
|
.flowexample-topbar-nav a:hover {
|
|
52
52
|
background-color: #34495e;
|
|
53
|
-
color: #fff;
|
|
53
|
+
color: var(--theme-color-background-panel, #fff);
|
|
54
54
|
}
|
|
55
55
|
`,
|
|
56
56
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pict-section-flow",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18",
|
|
4
4
|
"description": "Pict Section Flow Diagram",
|
|
5
5
|
"main": "source/Pict-Section-Flow.js",
|
|
6
6
|
"scripts": {
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"chai": "^6.2.2",
|
|
23
23
|
"mocha": "^11.7.5",
|
|
24
24
|
"pict": "^1.0.359",
|
|
25
|
+
"pict-docuserve": "^0.1.5",
|
|
25
26
|
"pict-router": "^1.0.9",
|
|
26
|
-
"quackage": "^1.0
|
|
27
|
+
"quackage": "^1.1.0"
|
|
27
28
|
}
|
|
28
29
|
}
|
|
@@ -35,6 +35,32 @@ module.exports.PictProviderFlowCSS = require('./providers/PictProvider-Flow-CSS.
|
|
|
35
35
|
module.exports.PictProviderFlowIcons = require('./providers/PictProvider-Flow-Icons.js');
|
|
36
36
|
module.exports.PictProviderFlowConnectorShapes = require('./providers/PictProvider-Flow-ConnectorShapes.js');
|
|
37
37
|
|
|
38
|
+
// Layout algorithm descriptors (consumers can register custom algorithms via
|
|
39
|
+
// _LayoutService.registerAlgorithm({ Name, Apply, DefaultParameters, ParameterSchema }))
|
|
40
|
+
module.exports.LayoutAlgorithms =
|
|
41
|
+
{
|
|
42
|
+
Custom: require('./providers/layouts/Layout-Custom.js'),
|
|
43
|
+
Layered: require('./providers/layouts/Layout-Layered.js'),
|
|
44
|
+
ForcedFromCenter: require('./providers/layouts/Layout-ForcedFromCenter.js'),
|
|
45
|
+
Grid: require('./providers/layouts/Layout-Grid.js'),
|
|
46
|
+
Circular: require('./providers/layouts/Layout-Circular.js'),
|
|
47
|
+
Tabular: require('./providers/layouts/Layout-Tabular.js'),
|
|
48
|
+
Columnar: require('./providers/layouts/Layout-Columnar.js')
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Edge-theme descriptors (consumers can register custom edge themes via
|
|
52
|
+
// _LayoutService.registerEdgeTheme({ Name, GeneratePath, AdjustLayout?, ResolveAttachment?, ... }))
|
|
53
|
+
module.exports.EdgeThemes =
|
|
54
|
+
{
|
|
55
|
+
Bezier: require('./providers/edges/Edge-Bezier.js'),
|
|
56
|
+
Orthogonal: require('./providers/edges/Edge-Orthogonal.js'),
|
|
57
|
+
Straight: require('./providers/edges/Edge-Straight.js'),
|
|
58
|
+
OrthogonalSnap: require('./providers/edges/Edge-OrthogonalSnap.js'),
|
|
59
|
+
Perimeter: require('./providers/edges/Edge-Perimeter.js'),
|
|
60
|
+
PerimeterLinear: require('./providers/edges/Edge-Perimeter-Linear.js'),
|
|
61
|
+
PerimeterOrthogonal: require('./providers/edges/Edge-Perimeter-Orthogonal.js')
|
|
62
|
+
};
|
|
63
|
+
|
|
38
64
|
// FlowCard base class
|
|
39
65
|
module.exports.PictFlowCard = require('./PictFlowCard.js');
|
|
40
66
|
|
|
@@ -47,7 +47,7 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
|
|
|
47
47
|
--pf-text-placeholder: #95a5a6;
|
|
48
48
|
|
|
49
49
|
/* Node */
|
|
50
|
-
--pf-node-body-fill: #ffffff;
|
|
50
|
+
--pf-node-body-fill: var(--theme-color-background-panel, #ffffff);
|
|
51
51
|
--pf-node-body-stroke: #d0d4d8;
|
|
52
52
|
--pf-node-body-stroke-hover: #b0b8c0;
|
|
53
53
|
--pf-node-body-stroke-width: 1;
|
|
@@ -56,7 +56,7 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
|
|
|
56
56
|
--pf-node-shadow-hover: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.15));
|
|
57
57
|
--pf-node-shadow-selected: drop-shadow(0 2px 8px rgba(52, 152, 219, 0.25));
|
|
58
58
|
--pf-node-shadow-dragging: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.20));
|
|
59
|
-
--pf-node-title-fill: #ffffff;
|
|
59
|
+
--pf-node-title-fill: var(--theme-color-background-panel, #ffffff);
|
|
60
60
|
--pf-node-title-size: 11.5px;
|
|
61
61
|
--pf-node-title-weight: 600;
|
|
62
62
|
--pf-node-title-bar-color: #2c3e50;
|
|
@@ -65,35 +65,35 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
|
|
|
65
65
|
|
|
66
66
|
/* Node Variants */
|
|
67
67
|
--pf-node-start-fill: #eafaf1;
|
|
68
|
-
--pf-node-start-stroke: #27ae60;
|
|
68
|
+
--pf-node-start-stroke: var(--theme-color-status-success, #27ae60);
|
|
69
69
|
--pf-node-end-fill: #e8f8f5;
|
|
70
70
|
--pf-node-end-stroke: #1abc9c;
|
|
71
71
|
--pf-node-halt-fill: #fdedec;
|
|
72
|
-
--pf-node-halt-stroke: #e74c3c;
|
|
72
|
+
--pf-node-halt-stroke: var(--theme-color-status-error, #e74c3c);
|
|
73
73
|
--pf-node-decision-fill: #fff9e6;
|
|
74
|
-
--pf-node-decision-stroke: #f39c12;
|
|
74
|
+
--pf-node-decision-stroke: var(--theme-color-status-warning, #f39c12);
|
|
75
75
|
|
|
76
76
|
/* Ports */
|
|
77
77
|
--pf-port-input-fill: #3498db;
|
|
78
|
-
--pf-port-output-fill: #2ecc71;
|
|
79
|
-
--pf-port-stroke: #ffffff;
|
|
78
|
+
--pf-port-output-fill: var(--theme-color-status-success, #2ecc71);
|
|
79
|
+
--pf-port-stroke: var(--theme-color-background-panel, #ffffff);
|
|
80
80
|
--pf-port-stroke-width: 2;
|
|
81
81
|
--pf-port-label-bg: rgba(255, 253, 240, 0.5);
|
|
82
82
|
--pf-port-label-text: #2c3e50;
|
|
83
83
|
|
|
84
84
|
/* Port Type Colors */
|
|
85
85
|
--pf-port-event-in-fill: #3498db;
|
|
86
|
-
--pf-port-event-out-fill: #2ecc71;
|
|
86
|
+
--pf-port-event-out-fill: var(--theme-color-status-success, #2ecc71);
|
|
87
87
|
--pf-port-setting-fill: #e67e22;
|
|
88
88
|
--pf-port-value-fill: #f1c40f;
|
|
89
|
-
--pf-port-error-fill: #e74c3c;
|
|
89
|
+
--pf-port-error-fill: var(--theme-color-status-error, #e74c3c);
|
|
90
90
|
|
|
91
91
|
/* Connection Type Colors (match source port) */
|
|
92
92
|
--pf-connection-event-in-stroke: #3498db;
|
|
93
|
-
--pf-connection-event-out-stroke: #2ecc71;
|
|
93
|
+
--pf-connection-event-out-stroke: var(--theme-color-status-success, #2ecc71);
|
|
94
94
|
--pf-connection-setting-stroke: #e67e22;
|
|
95
95
|
--pf-connection-value-stroke: #f1c40f;
|
|
96
|
-
--pf-connection-error-stroke: #e74c3c;
|
|
96
|
+
--pf-connection-error-stroke: var(--theme-color-status-error, #e74c3c);
|
|
97
97
|
|
|
98
98
|
/* Connections */
|
|
99
99
|
--pf-connection-stroke: #95a5a6;
|
|
@@ -141,7 +141,7 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
|
|
|
141
141
|
|
|
142
142
|
/* Toolbar */
|
|
143
143
|
--pf-toolbar-bg: #ffffff;
|
|
144
|
-
--pf-toolbar-border: #e0e0e0;
|
|
144
|
+
--pf-toolbar-border: var(--theme-color-border-default, #e0e0e0);
|
|
145
145
|
|
|
146
146
|
/* Palette Cards */
|
|
147
147
|
--pf-card-border: #d5d8dc;
|
|
@@ -150,7 +150,7 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
|
|
|
150
150
|
|
|
151
151
|
/* Canvas */
|
|
152
152
|
--pf-canvas-bg: #fafafa;
|
|
153
|
-
--pf-grid-stroke: #e8e8e8;
|
|
153
|
+
--pf-grid-stroke: var(--theme-color-border-light, #e8e8e8);
|
|
154
154
|
|
|
155
155
|
position: relative;
|
|
156
156
|
width: 100%;
|
|
@@ -396,6 +396,187 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
|
|
|
396
396
|
.pict-flow-node-port-labels-hover:hover .pict-flow-port-label-bg {
|
|
397
397
|
opacity: 1;
|
|
398
398
|
}
|
|
399
|
+
|
|
400
|
+
/* Port-hint beziers — drawn from the badge to the actual dot
|
|
401
|
+
when an edge theme has rerouted the connection. Hidden by
|
|
402
|
+
default; PortRenderer / NodeView toggle data-active on hover. */
|
|
403
|
+
.pict-flow-port-hint {
|
|
404
|
+
fill: none;
|
|
405
|
+
stroke: var(--pf-connection-stroke-hover, #3498db);
|
|
406
|
+
stroke-width: 1.75;
|
|
407
|
+
stroke-dasharray: 4 3;
|
|
408
|
+
stroke-linecap: round;
|
|
409
|
+
opacity: 0;
|
|
410
|
+
pointer-events: none;
|
|
411
|
+
transition: opacity 0.18s ease;
|
|
412
|
+
}
|
|
413
|
+
.pict-flow-port-hint[data-active="true"] {
|
|
414
|
+
opacity: 0.7;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/* ── Layout-algorithm popup: tightened layout + form styling ── */
|
|
418
|
+
.pict-flow-popup-layout-algorithm-row {
|
|
419
|
+
display: flex;
|
|
420
|
+
flex-direction: column;
|
|
421
|
+
gap: 4px;
|
|
422
|
+
padding: 6px 10px 4px;
|
|
423
|
+
}
|
|
424
|
+
.pict-flow-popup-layout-algorithm-row > .pict-flow-popup-settings-label {
|
|
425
|
+
font-size: 10px;
|
|
426
|
+
font-weight: 700;
|
|
427
|
+
text-transform: uppercase;
|
|
428
|
+
letter-spacing: 0.05em;
|
|
429
|
+
opacity: 0.7;
|
|
430
|
+
margin: 0;
|
|
431
|
+
}
|
|
432
|
+
.pict-flow-popup-layout-algorithm-controls {
|
|
433
|
+
display: flex;
|
|
434
|
+
align-items: stretch;
|
|
435
|
+
gap: 4px;
|
|
436
|
+
}
|
|
437
|
+
.pict-flow-popup-layout-algorithm-select {
|
|
438
|
+
flex: 1 1 auto;
|
|
439
|
+
min-width: 0;
|
|
440
|
+
}
|
|
441
|
+
.pict-flow-popup-collapse-toggle {
|
|
442
|
+
flex: 0 0 auto;
|
|
443
|
+
width: 28px;
|
|
444
|
+
padding: 0;
|
|
445
|
+
border: 1px solid var(--pf-button-border, #ccc);
|
|
446
|
+
border-radius: 3px;
|
|
447
|
+
background: var(--pf-toolbar-bg, #fff);
|
|
448
|
+
color: var(--pf-text-secondary, #5a6470);
|
|
449
|
+
cursor: pointer;
|
|
450
|
+
display: inline-flex;
|
|
451
|
+
align-items: center;
|
|
452
|
+
justify-content: center;
|
|
453
|
+
transition: background-color 0.15s, color 0.15s, border-color 0.15s;
|
|
454
|
+
}
|
|
455
|
+
.pict-flow-popup-collapse-toggle:hover {
|
|
456
|
+
background-color: var(--pf-button-hover-bg, #eef);
|
|
457
|
+
color: var(--pf-text-primary, #2c3e50);
|
|
458
|
+
}
|
|
459
|
+
/* "Open" state: pressed-in look so the user sees that the form
|
|
460
|
+
below is being driven by this gear. */
|
|
461
|
+
.pict-flow-popup-collapse-toggle[aria-expanded="true"] {
|
|
462
|
+
background-color: var(--pf-button-active-bg, #d6e4f0);
|
|
463
|
+
color: var(--pf-text-primary, #2c3e50);
|
|
464
|
+
border-color: var(--pf-button-hover-border, #3498db);
|
|
465
|
+
}
|
|
466
|
+
.pict-flow-popup-collapse-toggle svg {
|
|
467
|
+
display: block;
|
|
468
|
+
}
|
|
469
|
+
/* Subordinate description text — sits under a control (algorithm
|
|
470
|
+
dropdown, edge-theme dropdown, etc.) and explains it. Indented
|
|
471
|
+
from the section's left edge with a faint left rule so the
|
|
472
|
+
visual hierarchy is unambiguous: SECTION LABEL > control >
|
|
473
|
+
description. */
|
|
474
|
+
.pict-flow-popup-control-description {
|
|
475
|
+
font-size: 11px;
|
|
476
|
+
line-height: 1.4;
|
|
477
|
+
color: var(--pf-text-secondary, #5a6470);
|
|
478
|
+
padding: 4px 12px 8px 28px;
|
|
479
|
+
margin-left: 14px;
|
|
480
|
+
border-left: 2px solid var(--pf-divider-light, #e6e6e6);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/* The form host. Acts as the collapsible container around the
|
|
484
|
+
pict-section-form metacontroller's emitted markup. */
|
|
485
|
+
.pict-flow-popup-layout-form-host {
|
|
486
|
+
margin: 0 10px 8px;
|
|
487
|
+
padding: 8px 10px;
|
|
488
|
+
background: var(--pf-toolbar-bg, #fafafa);
|
|
489
|
+
border: 1px solid var(--pf-button-border, #e0e0e0);
|
|
490
|
+
border-radius: 6px;
|
|
491
|
+
overflow: hidden;
|
|
492
|
+
max-height: 600px;
|
|
493
|
+
transition: max-height 0.22s ease, padding 0.22s ease,
|
|
494
|
+
margin 0.22s ease, border-color 0.22s ease, opacity 0.18s ease;
|
|
495
|
+
opacity: 1;
|
|
496
|
+
}
|
|
497
|
+
.pict-flow-popup-layout-form-host[data-collapsed="true"] {
|
|
498
|
+
max-height: 0;
|
|
499
|
+
padding-top: 0;
|
|
500
|
+
padding-bottom: 0;
|
|
501
|
+
margin-top: 0;
|
|
502
|
+
margin-bottom: 0;
|
|
503
|
+
border-color: transparent;
|
|
504
|
+
opacity: 0;
|
|
505
|
+
}
|
|
506
|
+
.pict-flow-popup-layout-form-host > div { width: 100%; }
|
|
507
|
+
|
|
508
|
+
/* Form contents — make the auto-rendered sections look professional.
|
|
509
|
+
The section headings stay visible; the redundant per-section
|
|
510
|
+
"Group: Defaults" h3 is suppressed. */
|
|
511
|
+
.pict-flow-popup-layout-form .pict-form-view {
|
|
512
|
+
display: block;
|
|
513
|
+
}
|
|
514
|
+
.pict-flow-popup-layout-form .pict-form-section {
|
|
515
|
+
margin: 0;
|
|
516
|
+
padding: 0;
|
|
517
|
+
}
|
|
518
|
+
.pict-flow-popup-layout-form .pict-form-section h2 {
|
|
519
|
+
font-size: 10px;
|
|
520
|
+
font-weight: 700;
|
|
521
|
+
text-transform: uppercase;
|
|
522
|
+
letter-spacing: 0.05em;
|
|
523
|
+
opacity: 0.6;
|
|
524
|
+
margin: 8px 0 4px;
|
|
525
|
+
padding: 0;
|
|
526
|
+
border-bottom: 1px solid var(--pf-button-border, #e6e6e6);
|
|
527
|
+
padding-bottom: 3px;
|
|
528
|
+
}
|
|
529
|
+
.pict-flow-popup-layout-form .pict-form-section:first-child h2,
|
|
530
|
+
.pict-flow-popup-layout-form .pict-form-section h2:first-child {
|
|
531
|
+
margin-top: 0;
|
|
532
|
+
}
|
|
533
|
+
/* Group headings ("Group: Defaults") are noise — every algorithm
|
|
534
|
+
has exactly one group right now. Hide them. */
|
|
535
|
+
.pict-flow-popup-layout-form .pict-form-section h3 {
|
|
536
|
+
display: none;
|
|
537
|
+
}
|
|
538
|
+
/* Each row of inputs lives in a flat <div> as alternating
|
|
539
|
+
<span>label</span><input> pairs. Lay them out in a balanced grid. */
|
|
540
|
+
.pict-flow-popup-layout-form .pict-form-section > div > div {
|
|
541
|
+
display: flex;
|
|
542
|
+
flex-wrap: wrap;
|
|
543
|
+
gap: 4px 14px;
|
|
544
|
+
margin: 4px 0;
|
|
545
|
+
align-items: center;
|
|
546
|
+
}
|
|
547
|
+
.pict-flow-popup-layout-form .pict-form-section span {
|
|
548
|
+
font-size: 12px;
|
|
549
|
+
color: var(--pf-text-primary, #2c3e50);
|
|
550
|
+
line-height: 1.4;
|
|
551
|
+
margin: 0;
|
|
552
|
+
}
|
|
553
|
+
.pict-flow-popup-layout-form input[type="number"],
|
|
554
|
+
.pict-flow-popup-layout-form input[type="text"],
|
|
555
|
+
.pict-flow-popup-layout-form select {
|
|
556
|
+
width: 88px;
|
|
557
|
+
padding: 2px 6px;
|
|
558
|
+
border: 1px solid var(--pf-button-border, #ccc);
|
|
559
|
+
border-radius: 3px;
|
|
560
|
+
font-size: 12px;
|
|
561
|
+
line-height: 1.3;
|
|
562
|
+
background: #fff;
|
|
563
|
+
color: var(--pf-text-primary, #2c3e50);
|
|
564
|
+
margin-left: -8px; /* tighten gap between label and its input */
|
|
565
|
+
}
|
|
566
|
+
.pict-flow-popup-layout-form select {
|
|
567
|
+
width: auto;
|
|
568
|
+
min-width: 110px;
|
|
569
|
+
}
|
|
570
|
+
.pict-flow-popup-layout-form input[type="number"]:focus,
|
|
571
|
+
.pict-flow-popup-layout-form input[type="text"]:focus,
|
|
572
|
+
.pict-flow-popup-layout-form select:focus {
|
|
573
|
+
outline: none;
|
|
574
|
+
border-color: var(--pf-button-hover-border, #3498db);
|
|
575
|
+
box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.15);
|
|
576
|
+
}
|
|
577
|
+
.pict-flow-popup-layout-form input[type="checkbox"] {
|
|
578
|
+
margin: 0 4px 0 0;
|
|
579
|
+
}
|
|
399
580
|
`;
|
|
400
581
|
}
|
|
401
582
|
|
|
@@ -787,6 +968,26 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
|
|
|
787
968
|
cursor: pointer;
|
|
788
969
|
flex: 0 0 28px;
|
|
789
970
|
}
|
|
971
|
+
|
|
972
|
+
/* Suppress native number-input spinner buttons on every input
|
|
973
|
+
inside a properties panel. Panels live inside <foreignObject>;
|
|
974
|
+
browsers (Chromium / WebKit) render the up/down spinner chrome
|
|
975
|
+
as native overlays that don't always respect SVG transforms or
|
|
976
|
+
the parent tab pane's display:none — leaving stale spinner
|
|
977
|
+
artifacts hanging around when the user switches tabs or pans
|
|
978
|
+
the diagram. The user can still type numbers; they just don't
|
|
979
|
+
get clickable spinners. (If we ever want spinners back, build
|
|
980
|
+
them as real DOM elements next to the input, not native chrome.) */
|
|
981
|
+
.pict-flow-panel input[type="number"] {
|
|
982
|
+
-moz-appearance: textfield;
|
|
983
|
+
appearance: textfield;
|
|
984
|
+
}
|
|
985
|
+
.pict-flow-panel input[type="number"]::-webkit-outer-spin-button,
|
|
986
|
+
.pict-flow-panel input[type="number"]::-webkit-inner-spin-button {
|
|
987
|
+
-webkit-appearance: none;
|
|
988
|
+
appearance: none;
|
|
989
|
+
margin: 0;
|
|
990
|
+
}
|
|
790
991
|
`;
|
|
791
992
|
}
|
|
792
993
|
|
|
@@ -927,6 +1128,9 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
|
|
|
927
1128
|
user-select: none;
|
|
928
1129
|
-webkit-user-select: none;
|
|
929
1130
|
}
|
|
1131
|
+
.pict-flow-toolbar-btn:focus {
|
|
1132
|
+
outline: none;
|
|
1133
|
+
}
|
|
930
1134
|
.pict-flow-toolbar-btn:hover {
|
|
931
1135
|
background-color: var(--pf-button-hover-bg);
|
|
932
1136
|
border-color: var(--pf-button-hover-border);
|
|
@@ -951,6 +1155,29 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
|
|
|
951
1155
|
align-items: center;
|
|
952
1156
|
margin-left: 0.15em;
|
|
953
1157
|
}
|
|
1158
|
+
/* Split button — visible as one connected unit; the two halves
|
|
1159
|
+
route to different actions. Used for "Auto" so clicking the
|
|
1160
|
+
icon/text applies the current layout while the chevron half
|
|
1161
|
+
opens the algorithm popup with a generous hit area. */
|
|
1162
|
+
.pict-flow-toolbar-btn-split {
|
|
1163
|
+
display: inline-flex;
|
|
1164
|
+
align-items: stretch;
|
|
1165
|
+
}
|
|
1166
|
+
.pict-flow-toolbar-btn-split-main {
|
|
1167
|
+
border-top-right-radius: 0;
|
|
1168
|
+
border-bottom-right-radius: 0;
|
|
1169
|
+
border-right: 1px solid var(--pf-button-border);
|
|
1170
|
+
margin-right: -1px; /* collapse the seam between the two buttons */
|
|
1171
|
+
}
|
|
1172
|
+
.pict-flow-toolbar-btn-split-chevron {
|
|
1173
|
+
border-top-left-radius: 0;
|
|
1174
|
+
border-bottom-left-radius: 0;
|
|
1175
|
+
padding-left: 0.55em;
|
|
1176
|
+
padding-right: 0.55em;
|
|
1177
|
+
}
|
|
1178
|
+
.pict-flow-toolbar-btn-split-chevron .pict-flow-toolbar-btn-chevron {
|
|
1179
|
+
margin: 0;
|
|
1180
|
+
}
|
|
954
1181
|
.pict-flow-toolbar-right {
|
|
955
1182
|
margin-left: auto;
|
|
956
1183
|
border-right: none;
|
|
@@ -1072,7 +1299,7 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
|
|
|
1072
1299
|
border-radius: 6px;
|
|
1073
1300
|
box-shadow: 0 4px 16px rgba(0,0,0,0.12);
|
|
1074
1301
|
min-width: 240px;
|
|
1075
|
-
max-height:
|
|
1302
|
+
max-height: 80vh;
|
|
1076
1303
|
overflow-y: auto;
|
|
1077
1304
|
padding: 0.35em 0;
|
|
1078
1305
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
@@ -1387,6 +1614,9 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
|
|
|
1387
1614
|
justify-content: center;
|
|
1388
1615
|
transition: background-color 0.15s;
|
|
1389
1616
|
}
|
|
1617
|
+
.pict-flow-floating-btn:focus {
|
|
1618
|
+
outline: none;
|
|
1619
|
+
}
|
|
1390
1620
|
.pict-flow-floating-btn:hover {
|
|
1391
1621
|
background-color: var(--pf-button-hover-bg);
|
|
1392
1622
|
}
|
|
@@ -219,7 +219,7 @@ class PictProviderFlowTheme extends libFableServiceProviderBase
|
|
|
219
219
|
.pict-flow-toolbar-btn {
|
|
220
220
|
background-color: rgba(255,255,255,0.05);
|
|
221
221
|
border-color: rgba(255,255,255,0.2);
|
|
222
|
-
color: #ffffff;
|
|
222
|
+
color: var(--theme-color-background-panel, #ffffff);
|
|
223
223
|
}
|
|
224
224
|
.pict-flow-toolbar-btn:hover {
|
|
225
225
|
background-color: rgba(255,255,255,0.1);
|
|
@@ -458,16 +458,16 @@ class PictProviderFlowTheme extends libFableServiceProviderBase
|
|
|
458
458
|
.pict-flow-toolbar {
|
|
459
459
|
background-color: #c0c0c0;
|
|
460
460
|
border-bottom: 2px solid #808080;
|
|
461
|
-
border-top: 1px solid #ffffff;
|
|
461
|
+
border-top: 1px solid var(--theme-color-background-panel, #ffffff);
|
|
462
462
|
}
|
|
463
463
|
.pict-flow-toolbar-btn {
|
|
464
464
|
background-color: #c0c0c0;
|
|
465
465
|
border: 2px outset #c0c0c0;
|
|
466
466
|
border-radius: 0;
|
|
467
|
-
color: #000000;
|
|
467
|
+
color: var(--theme-color-text-primary, #000000);
|
|
468
468
|
}
|
|
469
469
|
.pict-flow-toolbar-btn:hover {
|
|
470
|
-
background-color: #d0d0d0;
|
|
470
|
+
background-color: var(--theme-color-border-default, #d0d0d0);
|
|
471
471
|
}
|
|
472
472
|
.pict-flow-toolbar-btn:active {
|
|
473
473
|
border-style: inset;
|
|
@@ -544,10 +544,10 @@ class PictProviderFlowTheme extends libFableServiceProviderBase
|
|
|
544
544
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
|
|
545
545
|
}
|
|
546
546
|
/* Node-type bracket colors — each type gets its own bracket color */
|
|
547
|
-
.pict-flow-node-start .pict-flow-node-bracket { stroke: #27ae60; }
|
|
547
|
+
.pict-flow-node-start .pict-flow-node-bracket { stroke: var(--theme-color-status-success, #27ae60); }
|
|
548
548
|
.pict-flow-node-end .pict-flow-node-bracket { stroke: #1abc9c; }
|
|
549
|
-
.pict-flow-node-halt .pict-flow-node-bracket { stroke: #e74c3c; }
|
|
550
|
-
.pict-flow-node-decision .pict-flow-node-bracket { stroke: #f39c12; }
|
|
549
|
+
.pict-flow-node-halt .pict-flow-node-bracket { stroke: var(--theme-color-status-error, #e74c3c); }
|
|
550
|
+
.pict-flow-node-decision .pict-flow-node-bracket { stroke: var(--theme-color-status-warning, #f39c12); }
|
|
551
551
|
.pict-flow-node-default .pict-flow-node-bracket { stroke: #3498db; }
|
|
552
552
|
.pict-flow-node-action .pict-flow-node-bracket { stroke: #2c3e50; }
|
|
553
553
|
/* Override variant rules: no fills/strokes on body rects in whiteboard */
|