pict-section-flow 1.3.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/package.json +7 -2
  2. package/source/Pict-Section-Flow.js +20 -14
  3. package/source/providers/PictProvider-Flow-Background.js +303 -0
  4. package/source/providers/PictProvider-Flow-CSS.js +99 -7
  5. package/source/providers/PictProvider-Flow-ConnectorShapes.js +8 -0
  6. package/source/providers/PictProvider-Flow-Geometry.js +11 -421
  7. package/source/providers/PictProvider-Flow-Icons.js +20 -0
  8. package/source/providers/PictProvider-Flow-Layouts.js +107 -0
  9. package/source/services/PictService-Flow-ConnectionRenderer.js +77 -5
  10. package/source/services/PictService-Flow-CursorManager.js +113 -0
  11. package/source/services/PictService-Flow-InteractionManager.js +443 -61
  12. package/source/services/PictService-Flow-Layout.js +21 -16
  13. package/source/services/PictService-Flow-PathGenerator.js +30 -417
  14. package/source/services/PictService-Flow-RenderManager.js +9 -1
  15. package/source/services/PictService-Flow-ViewportManager.js +102 -0
  16. package/source/views/PictView-Flow-FloatingToolbar.js +57 -0
  17. package/source/views/PictView-Flow-Node.js +36 -0
  18. package/source/views/PictView-Flow-PropertiesPanel.js +27 -5
  19. package/source/views/PictView-Flow-Toolbar.js +148 -13
  20. package/source/views/PictView-Flow.js +628 -3
  21. package/.claude/launch.json +0 -11
  22. package/docs/.nojekyll +0 -0
  23. package/docs/Architecture.md +0 -163
  24. package/docs/Custom-Styling.md +0 -275
  25. package/docs/Data_Model.md +0 -149
  26. package/docs/Event_System.md +0 -156
  27. package/docs/Getting_Started.md +0 -237
  28. package/docs/Implementation_Reference.md +0 -528
  29. package/docs/Layout_Persistence.md +0 -117
  30. package/docs/README.md +0 -103
  31. package/docs/Theme_Integration.md +0 -150
  32. package/docs/_brand.json +0 -18
  33. package/docs/_cover.md +0 -17
  34. package/docs/_playground.json +0 -24
  35. package/docs/_sidebar.md +0 -57
  36. package/docs/_topbar.md +0 -8
  37. package/docs/_version.json +0 -7
  38. package/docs/api/PictFlowCard.md +0 -216
  39. package/docs/api/PictFlowCardPropertiesPanel.md +0 -235
  40. package/docs/api/addConnection.md +0 -101
  41. package/docs/api/addNode.md +0 -137
  42. package/docs/api/autoLayout.md +0 -77
  43. package/docs/api/getFlowData.md +0 -112
  44. package/docs/api/marshalToView.md +0 -95
  45. package/docs/api/openPanel.md +0 -128
  46. package/docs/api/registerHandler.md +0 -174
  47. package/docs/api/registerNodeType.md +0 -142
  48. package/docs/api/removeConnection.md +0 -57
  49. package/docs/api/removeNode.md +0 -80
  50. package/docs/api/saveLayout.md +0 -152
  51. package/docs/api/screenToSVGCoords.md +0 -68
  52. package/docs/api/selectNode.md +0 -116
  53. package/docs/api/setTheme.md +0 -168
  54. package/docs/api/setZoom.md +0 -97
  55. package/docs/api/toggleFullscreen.md +0 -68
  56. package/docs/card-help/EACH.md +0 -19
  57. package/docs/card-help/FREAD.md +0 -24
  58. package/docs/card-help/FWRITE.md +0 -24
  59. package/docs/card-help/GET.md +0 -22
  60. package/docs/card-help/ITE.md +0 -23
  61. package/docs/card-help/LOG.md +0 -23
  62. package/docs/card-help/NOTE.md +0 -17
  63. package/docs/card-help/PREV.md +0 -18
  64. package/docs/card-help/SET.md +0 -27
  65. package/docs/card-help/SPKL.md +0 -22
  66. package/docs/card-help/STAT.md +0 -23
  67. package/docs/card-help/SW.md +0 -25
  68. package/docs/diagrams/architecture-at-a-glance.excalidraw +0 -4270
  69. package/docs/diagrams/architecture-at-a-glance.mmd +0 -30
  70. package/docs/diagrams/architecture-at-a-glance.svg +0 -2
  71. package/docs/diagrams/data-flow.excalidraw +0 -1451
  72. package/docs/diagrams/data-flow.mmd +0 -17
  73. package/docs/diagrams/data-flow.svg +0 -2
  74. package/docs/diagrams/high-level-design.excalidraw +0 -5767
  75. package/docs/diagrams/high-level-design.mmd +0 -86
  76. package/docs/diagrams/high-level-design.svg +0 -2
  77. package/docs/diagrams/relationships.excalidraw +0 -3852
  78. package/docs/diagrams/relationships.mmd +0 -9
  79. package/docs/diagrams/relationships.svg +0 -2
  80. package/docs/diagrams/service-initialization-sequence.excalidraw +0 -1466
  81. package/docs/diagrams/service-initialization-sequence.mmd +0 -19
  82. package/docs/diagrams/service-initialization-sequence.svg +0 -2
  83. package/docs/diagrams/svg-layer-structure.excalidraw +0 -1060
  84. package/docs/diagrams/svg-layer-structure.mmd +0 -18
  85. package/docs/diagrams/svg-layer-structure.svg +0 -2
  86. package/docs/examples/README.md +0 -9
  87. package/docs/examples/simple_cards/README.md +0 -677
  88. package/docs/examples/simple_cards/css/flowexample.css +0 -65
  89. package/docs/examples/simple_cards/index.html +0 -32
  90. package/docs/examples/simple_cards/js/pict.min.js +0 -12
  91. package/docs/examples/simple_cards/pict-section-flow-example-simple-cards.compatible.min.js +0 -1
  92. package/docs/index.html +0 -38
  93. package/docs/playground/app.json +0 -6
  94. package/docs/playground/appdata.json +0 -85
  95. package/docs/playground/application.js +0 -23
  96. package/docs/playground/pict.json +0 -17
  97. package/docs/playground/runtime/pict-application.min.js +0 -2
  98. package/docs/playground/runtime/pict-section-flow.min.js +0 -2
  99. package/docs/playground/runtime/pict-section-modal.min.js +0 -2
  100. package/docs/playground/runtime/pict.min.js +0 -12
  101. package/docs/retold-catalog.json +0 -244
  102. package/docs/retold-keyword-index.json +0 -26028
  103. package/example_applications/simple_cards/css/flowexample.css +0 -65
  104. package/example_applications/simple_cards/html/index.html +0 -32
  105. package/example_applications/simple_cards/package.json +0 -52
  106. package/example_applications/simple_cards/source/Pict-Application-FlowExample-Configuration.json +0 -15
  107. package/example_applications/simple_cards/source/Pict-Application-FlowExample.js +0 -539
  108. package/example_applications/simple_cards/source/card-help-content.js +0 -16
  109. package/example_applications/simple_cards/source/cards/FlowCard-Comment.js +0 -38
  110. package/example_applications/simple_cards/source/cards/FlowCard-DataPreview.js +0 -44
  111. package/example_applications/simple_cards/source/cards/FlowCard-Each.js +0 -38
  112. package/example_applications/simple_cards/source/cards/FlowCard-FileRead.js +0 -56
  113. package/example_applications/simple_cards/source/cards/FlowCard-FileWrite.js +0 -50
  114. package/example_applications/simple_cards/source/cards/FlowCard-GetValue.js +0 -37
  115. package/example_applications/simple_cards/source/cards/FlowCard-IfThenElse.js +0 -49
  116. package/example_applications/simple_cards/source/cards/FlowCard-LogValues.js +0 -55
  117. package/example_applications/simple_cards/source/cards/FlowCard-SetValue.js +0 -97
  118. package/example_applications/simple_cards/source/cards/FlowCard-Sparkline.js +0 -100
  119. package/example_applications/simple_cards/source/cards/FlowCard-StatusMonitor.js +0 -46
  120. package/example_applications/simple_cards/source/cards/FlowCard-Switch.js +0 -39
  121. package/example_applications/simple_cards/source/providers/PictRouter-FlowExample-Configuration.json +0 -22
  122. package/example_applications/simple_cards/source/sample-flows.js +0 -410
  123. package/example_applications/simple_cards/source/views/PictView-FlowExample-About.js +0 -184
  124. package/example_applications/simple_cards/source/views/PictView-FlowExample-BottomBar.js +0 -77
  125. package/example_applications/simple_cards/source/views/PictView-FlowExample-Documentation.js +0 -325
  126. package/example_applications/simple_cards/source/views/PictView-FlowExample-FileWriteInfo.js +0 -59
  127. package/example_applications/simple_cards/source/views/PictView-FlowExample-Layout.js +0 -90
  128. package/example_applications/simple_cards/source/views/PictView-FlowExample-MainWorkspace.js +0 -453
  129. package/example_applications/simple_cards/source/views/PictView-FlowExample-TopBar.js +0 -95
  130. package/scripts/generate-card-help.js +0 -214
  131. package/source/providers/edges/Edge-Bezier.js +0 -41
  132. package/source/providers/edges/Edge-Orthogonal.js +0 -37
  133. package/source/providers/edges/Edge-OrthogonalSnap.js +0 -72
  134. package/source/providers/edges/Edge-Perimeter-Linear.js +0 -31
  135. package/source/providers/edges/Edge-Perimeter-Orthogonal.js +0 -39
  136. package/source/providers/edges/Edge-Perimeter.js +0 -48
  137. package/source/providers/edges/Edge-PerimeterMath.js +0 -92
  138. package/source/providers/edges/Edge-Straight.js +0 -24
  139. package/source/providers/layouts/Layout-Circular.js +0 -203
  140. package/source/providers/layouts/Layout-Coerce.js +0 -40
  141. package/source/providers/layouts/Layout-Columnar.js +0 -134
  142. package/source/providers/layouts/Layout-Custom.js +0 -27
  143. package/source/providers/layouts/Layout-ForcedFromCenter.js +0 -256
  144. package/source/providers/layouts/Layout-Grid.js +0 -134
  145. package/source/providers/layouts/Layout-Layered.js +0 -155
  146. package/source/providers/layouts/Layout-Rank.js +0 -141
  147. package/source/providers/layouts/Layout-Staggered.js +0 -131
  148. package/source/providers/layouts/Layout-Tabular.js +0 -94
  149. package/test/ConnectionHandleManager_tests.js +0 -717
  150. package/test/ConnectionRenderer_tests.js +0 -591
  151. package/test/DataManager_tests.js +0 -859
  152. package/test/Geometry_tests.js +0 -767
  153. package/test/InteractionManager_tests.js +0 -279
  154. package/test/Layout_tests.js +0 -1604
  155. package/test/NodeView_tests.js +0 -66
  156. package/test/PanelManager_tests.js +0 -172
  157. package/test/PathGenerator_tests.js +0 -978
  158. package/test/PortRenderer_tests.js +0 -376
  159. package/test/RenderManager_tests.js +0 -756
  160. package/test/Renderer_tests.js +0 -133
  161. package/test/SelectionManager_tests.js +0 -185
  162. package/test/StylePresets_tests.js +0 -153
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pict-section-flow",
3
- "version": "1.3.0",
3
+ "version": "2.0.0",
4
4
  "description": "Pict Section Flow Diagram",
5
5
  "main": "source/Pict-Section-Flow.js",
6
6
  "scripts": {
@@ -15,6 +15,8 @@
15
15
  "dependencies": {
16
16
  "fable-serviceproviderbase": "^3.0.19",
17
17
  "pict-provider": "^1.0.13",
18
+ "pict-provider-graphgeometry": "^1.0.0",
19
+ "pict-provider-graphlayout": "^1.0.0",
18
20
  "pict-section-form": "^1.0.199",
19
21
  "pict-view": "^1.0.68"
20
22
  },
@@ -25,5 +27,8 @@
25
27
  "pict-docuserve": "^1.4.4",
26
28
  "pict-router": "^1.0.10",
27
29
  "quackage": "^1.3.0"
28
- }
30
+ },
31
+ "files": [
32
+ "source"
33
+ ]
29
34
  }
@@ -35,30 +35,36 @@ 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 and edge-theme descriptors now live in the standalone
39
+ // pict-provider-graphlayout module. They are re-exported here unchanged so the
40
+ // historical pict-section-flow export surface (LayoutAlgorithms / EdgeThemes) is
41
+ // preserved for consumers.
42
+ const libPictProviderGraphLayout = require('pict-provider-graphlayout');
43
+
38
44
  // Layout algorithm descriptors (consumers can register custom algorithms via
39
45
  // _LayoutService.registerAlgorithm({ Name, Apply, DefaultParameters, ParameterSchema }))
40
46
  module.exports.LayoutAlgorithms =
41
47
  {
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')
48
+ Custom: libPictProviderGraphLayout.Layouts.Custom,
49
+ Layered: libPictProviderGraphLayout.Layouts.Layered,
50
+ ForcedFromCenter: libPictProviderGraphLayout.Layouts.ForcedFromCenter,
51
+ Grid: libPictProviderGraphLayout.Layouts.Grid,
52
+ Circular: libPictProviderGraphLayout.Layouts.Circular,
53
+ Tabular: libPictProviderGraphLayout.Layouts.Tabular,
54
+ Columnar: libPictProviderGraphLayout.Layouts.Columnar
49
55
  };
50
56
 
51
57
  // Edge-theme descriptors (consumers can register custom edge themes via
52
58
  // _LayoutService.registerEdgeTheme({ Name, GeneratePath, AdjustLayout?, ResolveAttachment?, ... }))
53
59
  module.exports.EdgeThemes =
54
60
  {
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')
61
+ Bezier: libPictProviderGraphLayout.Edges.Bezier,
62
+ Orthogonal: libPictProviderGraphLayout.Edges.Orthogonal,
63
+ Straight: libPictProviderGraphLayout.Edges.Straight,
64
+ OrthogonalSnap: libPictProviderGraphLayout.Edges.OrthogonalSnap,
65
+ Perimeter: libPictProviderGraphLayout.Edges.Perimeter,
66
+ PerimeterLinear: libPictProviderGraphLayout.Edges.PerimeterLinear,
67
+ PerimeterOrthogonal: libPictProviderGraphLayout.Edges.PerimeterOrthogonal
62
68
  };
63
69
 
64
70
  // FlowCard base class
@@ -0,0 +1,303 @@
1
+ const libPictProvider = require('pict-provider');
2
+
3
+ /**
4
+ * PictProvider-Flow-Background
5
+ *
6
+ * Native canvas background for the flow diagram. The container template ships a
7
+ * default grid; this provider lets a host pick a background through config or
8
+ * ViewState instead of hand-painting the SVG from outside (which moodboard used
9
+ * to do). When no background is configured the provider is a no-op and the
10
+ * template grid stands, so existing diagrams are unchanged.
11
+ *
12
+ * Background shape:
13
+ * { Style: 'grid' | 'dots' | 'graph' | 'solid' | 'image' | 'none',
14
+ * Color?: string, // line / dot color (minor lines for 'graph')
15
+ * MajorColor?: string, // 'graph' only: the heavier every-Nth line color
16
+ * Paper?: string, // grid/dots/graph: solid fill painted behind the pattern
17
+ * Image?: string,
18
+ * GridSize?: number, // cell spacing (minor cell for 'graph')
19
+ * MajorEvery?: number, // 'graph' only: heavier line every N cells (default 10)
20
+ * DotSize?: number,
21
+ * LineWidth?: number, // grid/graph minor line width
22
+ * MajorLineWidth?: number } // 'graph' major line width
23
+ *
24
+ * Named presets (smaller / lighter / darker dots, grids, blue graph paper,
25
+ * blueprint, ...) live in PRESETS and are fetched with preset(name).
26
+ *
27
+ * The markup generators are pure (string in, string out) and unit tested; only
28
+ * apply() touches the DOM.
29
+ */
30
+ const _ProviderConfiguration =
31
+ {
32
+ ProviderIdentifier: 'PictProviderFlowBackground'
33
+ };
34
+
35
+ const _DEFAULT_GRID_SIZE = 20;
36
+ const _DEFAULT_DOT_SIZE = 2;
37
+ const _DEFAULT_DOT_FILL = 'var(--theme-color-text-secondary, #b0b0b0)';
38
+ const _DEFAULT_MAJOR_EVERY = 10;
39
+ // Concrete fallback line color for 'graph' (var() does not resolve in an SVG
40
+ // presentation attribute, and graph lines are drawn with stroke="...").
41
+ const _DEFAULT_GRID_LINE = '#cbd5e1';
42
+
43
+ // Named, ready-to-use backgrounds. preset(name) returns a fresh clone so callers
44
+ // can tweak one without mutating the catalog.
45
+ const _PRESETS =
46
+ {
47
+ 'dots': { Style: 'dots', GridSize: 20, DotSize: 2 },
48
+ 'dots-small': { Style: 'dots', GridSize: 14, DotSize: 1 },
49
+ 'dots-light': { Style: 'dots', GridSize: 20, DotSize: 2, Color: '#dcdcdc' },
50
+ 'dots-dark': { Style: 'dots', GridSize: 22, DotSize: 2.4, Color: '#64748b' },
51
+ 'grid': { Style: 'grid', GridSize: 20 },
52
+ 'grid-fine': { Style: 'grid', GridSize: 12, Color: '#e2e8f0' },
53
+ // "10-square grid with light and more-light-blue lines": minor light-blue lines
54
+ // every 16px, a heavier sky-blue line every 10 cells, on white paper.
55
+ 'graph-blue': { Style: 'graph', GridSize: 16, MajorEvery: 10, Color: '#dbeafe', MajorColor: '#93c5fd', LineWidth: 1, MajorLineWidth: 1.5, Paper: '#ffffff' },
56
+ // Classic dark blueprint: light-blue lines on deep navy paper.
57
+ 'blueprint': { Style: 'graph', GridSize: 16, MajorEvery: 10, Color: '#3b6ea5', MajorColor: '#6fa8dc', LineWidth: 1, MajorLineWidth: 1.5, Paper: '#0f2a4a' },
58
+ 'solid': { Style: 'solid', Color: '#faf7f2' },
59
+ 'none': { Style: 'none' }
60
+ };
61
+
62
+ class PictProviderFlowBackground extends libPictProvider
63
+ {
64
+ constructor(pFable, pOptions, pServiceHash)
65
+ {
66
+ let tmpOptions = Object.assign({}, _ProviderConfiguration, pOptions);
67
+ super(pFable, tmpOptions, pServiceHash);
68
+
69
+ this.serviceType = 'PictProviderFlowBackground';
70
+
71
+ this._FlowView = (pOptions && pOptions.FlowView) ? pOptions.FlowView : null;
72
+ }
73
+
74
+ /**
75
+ * The pattern element id for a view + style.
76
+ * @param {string} pViewIdentifier
77
+ * @param {string} pStyle
78
+ * @returns {string}
79
+ */
80
+ patternId(pViewIdentifier, pStyle)
81
+ {
82
+ return `flow-bg-${pStyle}-${pViewIdentifier}`;
83
+ }
84
+
85
+ /**
86
+ * Generate the <pattern> markup for grid/dots backgrounds. Returns '' for
87
+ * styles that need no pattern (solid, image, none) or when nothing is set.
88
+ * Pure.
89
+ * @param {string} pViewIdentifier
90
+ * @param {Object} pBackground
91
+ * @returns {string}
92
+ */
93
+ generatePatternMarkup(pViewIdentifier, pBackground)
94
+ {
95
+ if (!pBackground || !pBackground.Style)
96
+ {
97
+ return '';
98
+ }
99
+
100
+ // Optional solid fill painted behind the pattern (paper color). Empty unless set.
101
+ let tmpPaper = function (pW, pH)
102
+ {
103
+ return pBackground.Paper ? `<rect width="${pW}" height="${pH}" fill="${pBackground.Paper}" />` : '';
104
+ };
105
+
106
+ if (pBackground.Style === 'grid')
107
+ {
108
+ let tmpSize = (typeof pBackground.GridSize === 'number') ? pBackground.GridSize : _DEFAULT_GRID_SIZE;
109
+ // With no explicit Color the lines inherit the theme via the existing
110
+ // CSS class, matching the template grid; a Color overrides inline.
111
+ let tmpStroke = pBackground.Color ? ` style="stroke:${pBackground.Color}"` : '';
112
+ let tmpWidth = (typeof pBackground.LineWidth === 'number') ? ` stroke-width="${pBackground.LineWidth}"` : '';
113
+ let tmpId = this.patternId(pViewIdentifier, 'grid');
114
+ return `<pattern id="${tmpId}" width="${tmpSize}" height="${tmpSize}" patternUnits="userSpaceOnUse">`
115
+ + tmpPaper(tmpSize, tmpSize)
116
+ + `<line x1="${tmpSize}" y1="0" x2="${tmpSize}" y2="${tmpSize}" class="pict-flow-grid-pattern"${tmpStroke}${tmpWidth} />`
117
+ + `<line x1="0" y1="${tmpSize}" x2="${tmpSize}" y2="${tmpSize}" class="pict-flow-grid-pattern"${tmpStroke}${tmpWidth} />`
118
+ + `</pattern>`;
119
+ }
120
+
121
+ if (pBackground.Style === 'dots')
122
+ {
123
+ let tmpSize = (typeof pBackground.GridSize === 'number') ? pBackground.GridSize : _DEFAULT_GRID_SIZE;
124
+ let tmpDot = (typeof pBackground.DotSize === 'number') ? pBackground.DotSize : _DEFAULT_DOT_SIZE;
125
+ let tmpFill = pBackground.Color ? pBackground.Color : _DEFAULT_DOT_FILL;
126
+ let tmpId = this.patternId(pViewIdentifier, 'dots');
127
+ return `<pattern id="${tmpId}" width="${tmpSize}" height="${tmpSize}" patternUnits="userSpaceOnUse">`
128
+ + tmpPaper(tmpSize, tmpSize)
129
+ + `<circle cx="${tmpSize / 2}" cy="${tmpSize / 2}" r="${tmpDot}" fill="${tmpFill}" />`
130
+ + `</pattern>`;
131
+ }
132
+
133
+ if (pBackground.Style === 'graph')
134
+ {
135
+ // Graph paper: a fine minor grid tiled inside a heavier major grid drawn
136
+ // every MajorEvery cells. Two patterns — the major one fills itself with the
137
+ // minor pattern, then strokes the heavier lines on top.
138
+ let tmpMinor = (typeof pBackground.GridSize === 'number') ? pBackground.GridSize : _DEFAULT_GRID_SIZE;
139
+ let tmpMajorEvery = (typeof pBackground.MajorEvery === 'number') ? pBackground.MajorEvery : _DEFAULT_MAJOR_EVERY;
140
+ let tmpMajor = tmpMinor * tmpMajorEvery;
141
+ let tmpMinorColor = pBackground.Color || _DEFAULT_GRID_LINE;
142
+ let tmpMajorColor = pBackground.MajorColor || tmpMinorColor;
143
+ let tmpMinorWidth = (typeof pBackground.LineWidth === 'number') ? pBackground.LineWidth : 1;
144
+ let tmpMajorWidth = (typeof pBackground.MajorLineWidth === 'number') ? pBackground.MajorLineWidth : 1.5;
145
+ let tmpMinorId = this.patternId(pViewIdentifier, 'graph-minor');
146
+ let tmpId = this.patternId(pViewIdentifier, 'graph');
147
+
148
+ let tmpMinorPattern = `<pattern id="${tmpMinorId}" width="${tmpMinor}" height="${tmpMinor}" patternUnits="userSpaceOnUse">`
149
+ + `<line x1="${tmpMinor}" y1="0" x2="${tmpMinor}" y2="${tmpMinor}" stroke="${tmpMinorColor}" stroke-width="${tmpMinorWidth}" />`
150
+ + `<line x1="0" y1="${tmpMinor}" x2="${tmpMinor}" y2="${tmpMinor}" stroke="${tmpMinorColor}" stroke-width="${tmpMinorWidth}" />`
151
+ + `</pattern>`;
152
+ let tmpMajorPattern = `<pattern id="${tmpId}" width="${tmpMajor}" height="${tmpMajor}" patternUnits="userSpaceOnUse">`
153
+ + tmpPaper(tmpMajor, tmpMajor)
154
+ + `<rect width="${tmpMajor}" height="${tmpMajor}" fill="url(#${tmpMinorId})" />`
155
+ + `<line x1="${tmpMajor}" y1="0" x2="${tmpMajor}" y2="${tmpMajor}" stroke="${tmpMajorColor}" stroke-width="${tmpMajorWidth}" />`
156
+ + `<line x1="0" y1="${tmpMajor}" x2="${tmpMajor}" y2="${tmpMajor}" stroke="${tmpMajorColor}" stroke-width="${tmpMajorWidth}" />`
157
+ + `</pattern>`;
158
+ return tmpMinorPattern + tmpMajorPattern;
159
+ }
160
+
161
+ return '';
162
+ }
163
+
164
+ /**
165
+ * Resolve the fill value for the background rect. Pure.
166
+ * grid/dots -> url(#pattern); solid -> Color; image -> url(Image);
167
+ * none -> 'none'. Returns null when nothing is configured.
168
+ * @param {string} pViewIdentifier
169
+ * @param {Object} pBackground
170
+ * @returns {string|null}
171
+ */
172
+ resolveFill(pViewIdentifier, pBackground)
173
+ {
174
+ if (!pBackground || !pBackground.Style)
175
+ {
176
+ return null;
177
+ }
178
+
179
+ switch (pBackground.Style)
180
+ {
181
+ case 'grid': return `url(#${this.patternId(pViewIdentifier, 'grid')})`;
182
+ case 'dots': return `url(#${this.patternId(pViewIdentifier, 'dots')})`;
183
+ case 'graph': return `url(#${this.patternId(pViewIdentifier, 'graph')})`;
184
+ case 'solid': return pBackground.Color || 'transparent';
185
+ case 'image': return pBackground.Image ? `url(${pBackground.Image})` : 'none';
186
+ case 'none': return 'none';
187
+ default: return null;
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Resolve the effective background for a flow view: ViewState wins, then the
193
+ * static option. Returns null/false when none is configured.
194
+ * @param {Object} pFlowView
195
+ */
196
+ resolveBackground(pFlowView)
197
+ {
198
+ if (!pFlowView)
199
+ {
200
+ return null;
201
+ }
202
+ let tmpViewStateBackground = (pFlowView._FlowData && pFlowView._FlowData.ViewState)
203
+ ? pFlowView._FlowData.ViewState.Background
204
+ : null;
205
+ if (tmpViewStateBackground)
206
+ {
207
+ return tmpViewStateBackground;
208
+ }
209
+ return (pFlowView.options && pFlowView.options.Background) ? pFlowView.options.Background : null;
210
+ }
211
+
212
+ /**
213
+ * Fetch a named background preset as a fresh object (safe to tweak / store on
214
+ * ViewState). Unknown names return null.
215
+ * @param {string} pName
216
+ * @returns {Object|null}
217
+ */
218
+ preset(pName)
219
+ {
220
+ let tmpPreset = _PRESETS[pName];
221
+ return tmpPreset ? JSON.parse(JSON.stringify(tmpPreset)) : null;
222
+ }
223
+
224
+ /**
225
+ * The available preset names, in catalog order.
226
+ * @returns {string[]}
227
+ */
228
+ presetNames()
229
+ {
230
+ return Object.keys(_PRESETS);
231
+ }
232
+
233
+ /**
234
+ * Apply the configured background to the live SVG. No-op when nothing is
235
+ * configured (the template grid stands). DOM-touching; verified in browser.
236
+ * @param {Object} [pFlowView]
237
+ * @returns {boolean} true when a background was applied
238
+ */
239
+ apply(pFlowView)
240
+ {
241
+ let tmpFlowView = pFlowView || this._FlowView;
242
+ if (!tmpFlowView || !tmpFlowView._SVGElement)
243
+ {
244
+ return false;
245
+ }
246
+
247
+ let tmpBackground = this.resolveBackground(tmpFlowView);
248
+ if (!tmpBackground || !tmpBackground.Style)
249
+ {
250
+ return false;
251
+ }
252
+
253
+ let tmpViewIdentifier = tmpFlowView.options.ViewIdentifier;
254
+ let tmpSVG = tmpFlowView._SVGElement;
255
+
256
+ // Replace any pattern we previously injected, then add the new one.
257
+ let tmpDefs = tmpSVG.querySelector('defs');
258
+ if (tmpDefs)
259
+ {
260
+ let tmpOld = tmpDefs.querySelectorAll('[data-flow-bg-pattern]');
261
+ for (let i = 0; i < tmpOld.length; i++)
262
+ {
263
+ tmpOld[i].remove();
264
+ }
265
+ let tmpMarkup = this.generatePatternMarkup(tmpViewIdentifier, tmpBackground);
266
+ if (tmpMarkup)
267
+ {
268
+ let tmpScratch = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
269
+ tmpScratch.innerHTML = tmpMarkup;
270
+ while (tmpScratch.firstChild)
271
+ {
272
+ let tmpChild = tmpScratch.firstChild;
273
+ if (tmpChild.setAttribute)
274
+ {
275
+ tmpChild.setAttribute('data-flow-bg-pattern', 'true');
276
+ }
277
+ tmpDefs.appendChild(tmpChild);
278
+ }
279
+ }
280
+ }
281
+
282
+ let tmpFill = this.resolveFill(tmpViewIdentifier, tmpBackground);
283
+ let tmpRect = tmpSVG.querySelector('.pict-flow-grid-background');
284
+ if (tmpRect && tmpFill !== null)
285
+ {
286
+ tmpRect.setAttribute('fill', tmpFill);
287
+ }
288
+
289
+ // A solid color also tints the container behind the (transparent) rect.
290
+ let tmpContainer = (typeof tmpSVG.closest === 'function') ? tmpSVG.closest('.pict-flow-svg-container') : null;
291
+ if (tmpContainer)
292
+ {
293
+ tmpContainer.style.backgroundColor = (tmpBackground.Style === 'solid' && tmpBackground.Color) ? tmpBackground.Color : '';
294
+ }
295
+
296
+ return true;
297
+ }
298
+ }
299
+
300
+ module.exports = PictProviderFlowBackground;
301
+
302
+ module.exports.default_configuration = _ProviderConfiguration;
303
+ module.exports.PRESETS = _PRESETS;
@@ -205,16 +205,19 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
205
205
  .pict-flow-svg {
206
206
  width: 100%;
207
207
  height: 100%;
208
- cursor: grab;
208
+ cursor: default;
209
209
  user-select: none;
210
210
  -webkit-user-select: none;
211
211
  }
212
- .pict-flow-svg.panning {
213
- cursor: grabbing;
214
- }
215
- .pict-flow-svg.connecting {
216
- cursor: crosshair;
217
- }
212
+ /* The canvas cursor is owned by the CursorManager: it sets data-flow-cursor
213
+ on the SVG from the interaction state + view mode, and these map the
214
+ tokens to real cursors. Element-scoped hover cursors (ports, handles,
215
+ panel chrome, toolbar buttons) still win for their own elements. */
216
+ .pict-flow-svg[data-flow-cursor="grab"] { cursor: grab; }
217
+ .pict-flow-svg[data-flow-cursor="grabbing"] { cursor: grabbing; }
218
+ .pict-flow-svg[data-flow-cursor="crosshair"] { cursor: crosshair; }
219
+ .pict-flow-svg[data-flow-cursor="resize"] { cursor: nwse-resize; }
220
+ .pict-flow-svg[data-flow-cursor="default"] { cursor: default; }
218
221
  .pict-flow-grid-pattern line {
219
222
  stroke: var(--pf-grid-stroke);
220
223
  stroke-width: 0.5;
@@ -768,6 +771,19 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
768
771
  cursor: pointer;
769
772
  transition: stroke 0.15s;
770
773
  }
774
+ /* A connection's label (Data.Label), drawn at the midpoint. The white halo (paint-order) keeps it
775
+ legible where it crosses the line. */
776
+ .pict-flow-connection-label {
777
+ font-size: 12px;
778
+ font-family: inherit;
779
+ fill: var(--pf-text-primary, #2c3e50);
780
+ paint-order: stroke;
781
+ stroke: var(--theme-color-background-primary, #ffffff);
782
+ stroke-width: 3px;
783
+ stroke-linejoin: round;
784
+ pointer-events: none;
785
+ user-select: none;
786
+ }
771
787
  .pict-flow-connection:hover {
772
788
  stroke: var(--pf-connection-stroke-hover);
773
789
  stroke-width: 3;
@@ -1285,6 +1301,46 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
1285
1301
  border-right: none;
1286
1302
  padding-right: 0;
1287
1303
  }
1304
+ /* The host-supplied extra-button group (ToolbarExtraButtons) renders even
1305
+ when empty; collapse it so consumers that pass no buttons see no gap. */
1306
+ .pict-flow-toolbar-group:empty {
1307
+ display: none;
1308
+ }
1309
+ .pict-flow-toolbar-btn-active {
1310
+ background-color: var(--pf-button-active-bg);
1311
+ border-color: var(--pf-button-hover-border);
1312
+ }
1313
+ /* Toggle-state LED: a status dot in the corner of a toggle button (one marked
1314
+ Toggle:true). Action buttons render no LED; a toggle shows an empty outline
1315
+ when off and a filled green dot when on (the .active class). Works on the
1316
+ docked and floating toolbars. */
1317
+ .pict-flow-toolbar-btn, .pict-flow-floating-btn {
1318
+ position: relative;
1319
+ }
1320
+ .pict-flow-toolbar-btn-led {
1321
+ display: none;
1322
+ position: absolute;
1323
+ right: 2px;
1324
+ bottom: 2px;
1325
+ width: 7px;
1326
+ height: 7px;
1327
+ box-sizing: border-box;
1328
+ border-radius: 50%;
1329
+ border: 1.5px solid var(--pf-button-border, #c2cad6);
1330
+ background: transparent;
1331
+ pointer-events: none;
1332
+ }
1333
+ .pict-flow-toolbar-btn-toggle .pict-flow-toolbar-btn-led {
1334
+ display: block;
1335
+ }
1336
+ .pict-flow-toolbar-btn-toggle.pict-flow-toolbar-btn-active .pict-flow-toolbar-btn-led {
1337
+ background: var(--theme-color-status-success, #27ae60);
1338
+ border-color: var(--theme-color-status-success, #27ae60);
1339
+ }
1340
+ /* An icon-only host button (ToolbarExtraButtons with no Label) renders an empty text span. */
1341
+ .pict-flow-toolbar-btn-text:empty {
1342
+ display: none;
1343
+ }
1288
1344
  .pict-flow-toolbar-btn {
1289
1345
  display: inline-flex;
1290
1346
  align-items: center;
@@ -1993,6 +2049,12 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
1993
2049
  // Remove existing CSS first so we can re-register with updated theme overrides
1994
2050
  this.fable.CSSMap.removeCSS('PictSectionFlow-CSS');
1995
2051
  this.fable.CSSMap.addCSS('PictSectionFlow-CSS', this.generateCSS(), 500, 'PictProviderFlowCSS');
2052
+
2053
+ // Supplemental CSS (read-only chrome hiding + content frame), at a
2054
+ // priority above the base so the hides win.
2055
+ this.fable.CSSMap.removeCSS('PictSectionFlow-Supplemental-CSS');
2056
+ this.fable.CSSMap.addCSS('PictSectionFlow-Supplemental-CSS', this._supplementalCSS(), 502, 'PictProviderFlowCSS');
2057
+
1996
2058
  // Re-inject into the DOM to apply the updated CSS
1997
2059
  this.fable.CSSMap.injectCSS();
1998
2060
  }
@@ -2027,6 +2089,36 @@ class PictProviderFlowCSS extends libFableServiceProviderBase
2027
2089
  this.fable.CSSMap.addCSS('PictSectionFlow-Renderer-CSS', tmpCSS, 501, 'PictProviderFlowCSS');
2028
2090
  this.fable.CSSMap.injectCSS();
2029
2091
  }
2092
+
2093
+ /**
2094
+ * Supplemental CSS: hides editing chrome when the container carries the
2095
+ * 'pict-flow-readonly' class (set by PictView-Flow.setReadOnly), and styles
2096
+ * the content-frame rectangle. Replaces the ad-hoc CSS consumers (e.g.
2097
+ * moodboard) used to inject for a read-only look or a board frame.
2098
+ * @returns {string}
2099
+ */
2100
+ _supplementalCSS()
2101
+ {
2102
+ return /*css*/`
2103
+ .pict-flow-readonly .pict-flow-port,
2104
+ .pict-flow-readonly .pict-flow-port-hint,
2105
+ .pict-flow-readonly .pict-flow-node-resize-handle { display: none; }
2106
+ .pict-flow-readonly [data-flow-action="add-node"],
2107
+ .pict-flow-readonly [data-flow-action="delete-selected"],
2108
+ .pict-flow-readonly [data-flow-action="cards-popup"] { display: none; }
2109
+ .pict-flow-frame { fill: none; stroke: var(--theme-color-border, #9aa3ab); stroke-width: 1.5; stroke-dasharray: 8 6; pointer-events: none; }
2110
+ .pict-flow-frame-handle { fill: var(--theme-color-background-panel, #ffffff); stroke: var(--theme-color-brand-primary, #2e7d74); stroke-width: 1.5; }
2111
+ .pict-flow-frame-handle:hover { fill: var(--theme-color-brand-primary, #2e7d74); }
2112
+ .pict-flow-frame-handle-n, .pict-flow-frame-handle-s { cursor: ns-resize; }
2113
+ .pict-flow-frame-handle-e, .pict-flow-frame-handle-w { cursor: ew-resize; }
2114
+ .pict-flow-frame-move-handle { cursor: move; rx: 6; }
2115
+ .pict-flow-node-rotate-arm { stroke: var(--theme-color-brand-primary, #2e7d74); stroke-width: 1.5; }
2116
+ .pict-flow-node-rotate-handle { fill: var(--theme-color-background-panel, #ffffff); stroke: var(--theme-color-brand-primary, #2e7d74); stroke-width: 1.5; cursor: grab; }
2117
+ .pict-flow-node-rotate-handle:hover { fill: var(--theme-color-brand-primary, #2e7d74); }
2118
+ .pict-flow-readonly .pict-flow-node-rotate-arm,
2119
+ .pict-flow-readonly .pict-flow-node-rotate-handle { display: none; }
2120
+ `;
2121
+ }
2030
2122
  }
2031
2123
 
2032
2124
  module.exports = PictProviderFlowCSS;
@@ -465,6 +465,14 @@ class PictProviderFlowConnectorShapes extends libFableServiceProviderBase
465
465
  + '<polygon class="pict-flow-arrowhead pict-flow-arrowhead-tether" points="' + tmpTetherMarker.Points + '" fill="' + tmpTetherMarker.Fill + '" />'
466
466
  + '</marker>';
467
467
 
468
+ // Generic per-connection end markers, selectable per connection via Data.SourceMarker /
469
+ // Data.TargetMarker (a host like a moodboard styles its own edges). fill="context-stroke" makes
470
+ // each marker take the connection's own stroke color, so a recolored line recolors its markers.
471
+ tmpMarkup += '<marker id="flow-marker-arrow-end-' + pViewIdentifier + '" markerWidth="10" markerHeight="10" refX="8.5" refY="5" orient="auto" markerUnits="strokeWidth"><path d="M1,1 L9,5 L1,9 z" fill="context-stroke" /></marker>';
472
+ tmpMarkup += '<marker id="flow-marker-arrow-start-' + pViewIdentifier + '" markerWidth="10" markerHeight="10" refX="1.5" refY="5" orient="auto-start-reverse" markerUnits="strokeWidth"><path d="M1,1 L9,5 L1,9 z" fill="context-stroke" /></marker>';
473
+ tmpMarkup += '<marker id="flow-marker-dot-' + pViewIdentifier + '" markerWidth="8" markerHeight="8" refX="4" refY="4" orient="auto" markerUnits="strokeWidth"><circle cx="4" cy="4" r="3" fill="context-stroke" /></marker>';
474
+ tmpMarkup += '<marker id="flow-marker-square-' + pViewIdentifier + '" markerWidth="8" markerHeight="8" refX="4" refY="4" orient="auto" markerUnits="strokeWidth"><rect x="1" y="1" width="6" height="6" fill="context-stroke" /></marker>';
475
+
468
476
  return tmpMarkup;
469
477
  }
470
478
  }