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
@@ -1,5 +1,5 @@
1
1
  const libFableServiceProviderBase = require('fable-serviceproviderbase');
2
- const libPerimeterMath = require('../providers/edges/Edge-PerimeterMath.js');
2
+ const libPerimeterMath = require('pict-provider-graphlayout').Edges.PerimeterMath;
3
3
 
4
4
  // Chip (port-label badge) geometry — must mirror PortRenderer's badge
5
5
  // dimensions exactly so hint paths land on the chip's actual outer
@@ -116,12 +116,13 @@ class PictServiceFlowConnectionRenderer extends libFableServiceProviderBase
116
116
 
117
117
  // Hit area (wider invisible path for easier selection)
118
118
  let tmpShapeProvider = this._FlowView._ConnectorShapesProvider;
119
+ let tmpPathElement = null;
119
120
  if (tmpShapeProvider)
120
121
  {
121
122
  let tmpHitArea = tmpShapeProvider.createConnectionHitAreaElement(tmpPath, pConnection.Hash);
122
123
  pConnectionsLayer.appendChild(tmpHitArea);
123
124
 
124
- let tmpPathElement = tmpShapeProvider.createConnectionPathElement(
125
+ tmpPathElement = tmpShapeProvider.createConnectionPathElement(
125
126
  tmpPath, pConnection.Hash, pIsSelected, tmpViewIdentifier);
126
127
  if (tmpConnTypeClass)
127
128
  {
@@ -145,7 +146,7 @@ class PictServiceFlowConnectionRenderer extends libFableServiceProviderBase
145
146
  tmpHitArea.setAttribute('data-element-type', 'connection-hitarea');
146
147
  pConnectionsLayer.appendChild(tmpHitArea);
147
148
 
148
- let tmpPathElement = this._FlowView._SVGHelperProvider.createSVGElement('path');
149
+ tmpPathElement = this._FlowView._SVGHelperProvider.createSVGElement('path');
149
150
  tmpPathElement.setAttribute('class', `pict-flow-connection${tmpConnTypeClass} ${pIsSelected ? 'selected' : ''}`);
150
151
  tmpPathElement.setAttribute('d', tmpPath);
151
152
  tmpPathElement.setAttribute('data-connection-hash', pConnection.Hash);
@@ -160,14 +161,25 @@ class PictServiceFlowConnectionRenderer extends libFableServiceProviderBase
160
161
  pConnectionsLayer.appendChild(tmpPathElement);
161
162
  }
162
163
 
164
+ // Per-connection host styling (a moodboard styles its own edges): stroke color / width / dash and
165
+ // the end markers, applied only when the connection's Data carries them so default (workflow)
166
+ // connections are untouched. A label, when set, is drawn at the midpoint.
167
+ let tmpHasMarkers = (typeof tmpData.SourceMarker !== 'undefined' || typeof tmpData.TargetMarker !== 'undefined');
168
+ this._applyConnectionStyle(tmpPathElement, tmpData, tmpViewIdentifier);
169
+ this._renderConnectionLabel(pConnection, tmpData, pConnectionsLayer, tmpSourcePos, tmpTargetPos);
170
+
163
171
  // Render the colored endpoint dot at each end of the connection
164
172
  // into the dedicated endpoints layer (sits *above* the nodes
165
173
  // layer so the dot doesn't get hidden under the card chrome
166
174
  // when an edge theme places it on the node's perimeter).
167
175
  // PortRenderer suppresses its own circle for any port that
168
- // participates in a connection — we own the dot here.
176
+ // participates in a connection — we own the dot here. Skipped when the
177
+ // connection supplies its own end markers (those own the endpoints).
169
178
  let tmpEndpointsLayer = this._FlowView._EndpointsLayer || pConnectionsLayer;
170
- this._renderEndpointDots(pConnection, tmpEndpointsLayer, tmpSourcePos, tmpTargetPos);
179
+ if (!tmpHasMarkers)
180
+ {
181
+ this._renderEndpointDots(pConnection, tmpEndpointsLayer, tmpSourcePos, tmpTargetPos);
182
+ }
171
183
 
172
184
  // When the resolved attachment differs from the card-defined port
173
185
  // position (e.g. a Perimeter theme moved the dot to the edge of the
@@ -187,6 +199,66 @@ class PictServiceFlowConnectionRenderer extends libFableServiceProviderBase
187
199
  }
188
200
  }
189
201
 
202
+ // Apply per-connection host styling to the path element from the connection's Data: StrokeColor,
203
+ // StrokeWidth, StrokeStyle ('solid' | 'dashed' | 'dotted') and SourceMarker / TargetMarker
204
+ // ('none' | 'arrow' | 'dot' | 'square'). Each is applied only when present, so connections that do
205
+ // not carry these keys render exactly as before.
206
+ _applyConnectionStyle(pPathElement, pData, pViewIdentifier)
207
+ {
208
+ if (!pPathElement || !pData || !pPathElement.style) { return; }
209
+ // Stroke color / width / dash go through inline style, NOT SVG presentation attributes: the
210
+ // .pict-flow-connection CSS rule sets stroke + stroke-width, and a stylesheet rule beats a
211
+ // presentation attribute, so an attribute would be silently ignored. Inline style outranks the
212
+ // stylesheet, so the per-connection appearance wins.
213
+ if (pData.StrokeColor) { pPathElement.style.stroke = pData.StrokeColor; }
214
+ if (pData.StrokeWidth) { pPathElement.style.strokeWidth = String(pData.StrokeWidth); }
215
+ if (pData.StrokeStyle)
216
+ {
217
+ pPathElement.style.strokeDasharray = (pData.StrokeStyle === 'dashed') ? '7,5' : ((pData.StrokeStyle === 'dotted') ? '1.5,4' : 'none');
218
+ }
219
+ // Markers are not styled by CSS, so attributes are correct (they reference the marker defs).
220
+ if (typeof pData.TargetMarker !== 'undefined')
221
+ {
222
+ let tmpEnd = this._connectionMarkerId(pData.TargetMarker, 'end', pViewIdentifier);
223
+ if (tmpEnd) { pPathElement.setAttribute('marker-end', 'url(#' + tmpEnd + ')'); }
224
+ else { pPathElement.removeAttribute('marker-end'); }
225
+ }
226
+ if (typeof pData.SourceMarker !== 'undefined')
227
+ {
228
+ let tmpStart = this._connectionMarkerId(pData.SourceMarker, 'start', pViewIdentifier);
229
+ if (tmpStart) { pPathElement.setAttribute('marker-start', 'url(#' + tmpStart + ')'); }
230
+ else { pPathElement.removeAttribute('marker-start'); }
231
+ }
232
+ }
233
+
234
+ // Resolve a marker name + end ('start' | 'end') to its SVG marker def id; null for 'none'/unknown.
235
+ _connectionMarkerId(pMarker, pEnd, pViewIdentifier)
236
+ {
237
+ if (pMarker === 'arrow') { return 'flow-marker-arrow-' + pEnd + '-' + pViewIdentifier; }
238
+ if (pMarker === 'dot') { return 'flow-marker-dot-' + pViewIdentifier; }
239
+ if (pMarker === 'square') { return 'flow-marker-square-' + pViewIdentifier; }
240
+ return null;
241
+ }
242
+
243
+ // Draw a connection's label (Data.Label) at the midpoint of its endpoints. A white halo (paint-order
244
+ // stroke, set in CSS) keeps it legible over the line. Skipped when there is no label.
245
+ _renderConnectionLabel(pConnection, pData, pLayer, pSourcePos, pTargetPos)
246
+ {
247
+ // Render when a Label key is present (even ''), so a host that edits the label in place has an
248
+ // element to update; a connection with no Label key (a default workflow edge) gets none.
249
+ if (!pData || typeof pData.Label === 'undefined' || !pSourcePos || !pTargetPos) { return; }
250
+ if (!this._FlowView._SVGHelperProvider) { return; }
251
+ let tmpText = this._FlowView._SVGHelperProvider.createSVGElement('text');
252
+ tmpText.setAttribute('class', 'pict-flow-connection-label');
253
+ tmpText.setAttribute('x', String((pSourcePos.x + pTargetPos.x) / 2));
254
+ tmpText.setAttribute('y', String((pSourcePos.y + pTargetPos.y) / 2));
255
+ tmpText.setAttribute('text-anchor', 'middle');
256
+ tmpText.setAttribute('dominant-baseline', 'middle');
257
+ tmpText.setAttribute('data-connection-hash', pConnection.Hash);
258
+ tmpText.textContent = pData.Label;
259
+ pLayer.appendChild(tmpText);
260
+ }
261
+
190
262
  /**
191
263
  * Append the colored endpoint dots for both ends of a connection
192
264
  * onto the destination layer (absolute coords). Reuses
@@ -0,0 +1,113 @@
1
+ const libFableServiceProviderBase = require('fable-serviceproviderbase');
2
+
3
+ /**
4
+ * PictService-Flow-CursorManager
5
+ *
6
+ * Owns the canvas pointer cursor as a single, intentional concern. The cursor is
7
+ * a pure function of the interaction state machine (InteractionManager._State)
8
+ * plus the view mode (read-only, read-only navigation, whether panning is
9
+ * enabled). It is applied through ONE chokepoint: a `data-flow-cursor` token
10
+ * attribute on the SVG element, which the CSS maps to a real cursor.
11
+ *
12
+ * This replaces the previous approach (a base `cursor: grab` on the SVG plus
13
+ * `panning` / `connecting` class toggles scattered across the InteractionManager)
14
+ * so cursor behavior is derived from state rather than maintained by hand at
15
+ * every interaction site. Element-scoped hover cursors (ports, handles, panel
16
+ * chrome, toolbar buttons) stay on those elements -- they are correctly scoped
17
+ * and win for their own element regardless of the canvas cursor.
18
+ *
19
+ * To extend: add a state-to-token case in resolveCursor and a CSS rule for the
20
+ * token. The InteractionManager calls update() on every state transition (via
21
+ * its _setState), and the view calls it when the mode changes.
22
+ */
23
+ class PictServiceFlowCursorManager extends libFableServiceProviderBase
24
+ {
25
+ constructor(pFable, pOptions, pServiceHash)
26
+ {
27
+ super(pFable, pOptions, pServiceHash);
28
+
29
+ this.serviceType = 'PictServiceFlowCursorManager';
30
+
31
+ this._FlowView = (pOptions && pOptions.FlowView) ? pOptions.FlowView : null;
32
+ }
33
+
34
+ /**
35
+ * Map an interaction state + mode to a cursor token. Pure: no DOM, no side
36
+ * effects, so it is unit testable.
37
+ *
38
+ * @param {Object} pContext - { state, readOnly, navigating, panningEnabled }
39
+ * @returns {string} a cursor token: 'default' | 'grab' | 'grabbing' | 'crosshair' | 'resize'
40
+ */
41
+ resolveCursor(pContext)
42
+ {
43
+ let tmpContext = pContext || {};
44
+
45
+ switch (tmpContext.state)
46
+ {
47
+ case 'panning':
48
+ case 'dragging-node':
49
+ case 'dragging-panel':
50
+ case 'dragging-handle':
51
+ case 'rotating-node':
52
+ return 'grabbing';
53
+
54
+ case 'resizing-node':
55
+ case 'resizing-panel':
56
+ return 'resize';
57
+
58
+ case 'connecting':
59
+ case 'marquee':
60
+ return 'crosshair';
61
+
62
+ default:
63
+ // Idle: the canvas cursor signals whether the background can be grabbed.
64
+ // Read-only is static unless navigation (the hand toggle) is on; in edit
65
+ // mode the background is grabbable when panning is enabled.
66
+ if (tmpContext.readOnly)
67
+ {
68
+ return tmpContext.navigating ? 'grab' : 'default';
69
+ }
70
+ return tmpContext.panningEnabled ? 'grab' : 'default';
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Gather the current state + mode and apply the resolved cursor token. Called
76
+ * by the InteractionManager on every state transition and by the view on mode
77
+ * changes. Safe to call before the SVG exists (no-op).
78
+ */
79
+ update()
80
+ {
81
+ if (!this._FlowView)
82
+ {
83
+ return;
84
+ }
85
+
86
+ let tmpInteractionManager = this._FlowView._InteractionManager;
87
+ let tmpToken = this.resolveCursor(
88
+ {
89
+ state: (tmpInteractionManager && tmpInteractionManager._State) ? tmpInteractionManager._State : 'idle',
90
+ readOnly: (typeof this._FlowView.isReadOnly === 'function') ? this._FlowView.isReadOnly() : false,
91
+ navigating: (typeof this._FlowView.isReadOnlyNavigation === 'function') ? this._FlowView.isReadOnlyNavigation() : false,
92
+ panningEnabled: this._FlowView.options ? (this._FlowView.options.EnablePanning !== false) : true
93
+ });
94
+
95
+ this.apply(tmpToken);
96
+ }
97
+
98
+ /**
99
+ * Write the cursor token to the SVG element. The CSS maps
100
+ * `.pict-flow-svg[data-flow-cursor="<token>"]` to a real cursor.
101
+ * @param {string} pToken
102
+ */
103
+ apply(pToken)
104
+ {
105
+ let tmpElement = this._FlowView ? this._FlowView._SVGElement : null;
106
+ if (tmpElement && typeof tmpElement.setAttribute === 'function')
107
+ {
108
+ tmpElement.setAttribute('data-flow-cursor', pToken);
109
+ }
110
+ }
111
+ }
112
+
113
+ module.exports = PictServiceFlowCursorManager;