pict-section-flow 1.4.0 → 2.0.1

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 (164) 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 +73 -7
  5. package/source/providers/PictProvider-Flow-Geometry.js +11 -421
  6. package/source/providers/PictProvider-Flow-Icons.js +12 -0
  7. package/source/providers/PictProvider-Flow-Layouts.js +107 -0
  8. package/source/services/PictService-Flow-ConnectionRenderer.js +1 -1
  9. package/source/services/PictService-Flow-CursorManager.js +113 -0
  10. package/source/services/PictService-Flow-InteractionManager.js +439 -59
  11. package/source/services/PictService-Flow-Layout.js +21 -16
  12. package/source/services/PictService-Flow-PathGenerator.js +30 -417
  13. package/source/services/PictService-Flow-RenderManager.js +23 -3
  14. package/source/services/PictService-Flow-ViewportManager.js +102 -0
  15. package/source/views/PictView-Flow-FloatingToolbar.js +5 -1
  16. package/source/views/PictView-Flow-Node.js +29 -0
  17. package/source/views/PictView-Flow-Toolbar.js +50 -3
  18. package/source/views/PictView-Flow.js +591 -2
  19. package/.claude/launch.json +0 -11
  20. package/docs/.nojekyll +0 -0
  21. package/docs/Architecture.md +0 -163
  22. package/docs/Custom-Styling.md +0 -275
  23. package/docs/Data_Model.md +0 -149
  24. package/docs/Event_System.md +0 -156
  25. package/docs/Getting_Started.md +0 -237
  26. package/docs/Implementation_Reference.md +0 -528
  27. package/docs/Layout_Persistence.md +0 -117
  28. package/docs/README.md +0 -103
  29. package/docs/Theme_Integration.md +0 -150
  30. package/docs/_brand.json +0 -18
  31. package/docs/_cover.md +0 -17
  32. package/docs/_playground.json +0 -24
  33. package/docs/_sidebar.md +0 -57
  34. package/docs/_topbar.md +0 -8
  35. package/docs/_version.json +0 -7
  36. package/docs/api/PictFlowCard.md +0 -216
  37. package/docs/api/PictFlowCardPropertiesPanel.md +0 -235
  38. package/docs/api/addConnection.md +0 -101
  39. package/docs/api/addNode.md +0 -137
  40. package/docs/api/autoLayout.md +0 -77
  41. package/docs/api/getFlowData.md +0 -112
  42. package/docs/api/marshalToView.md +0 -95
  43. package/docs/api/openPanel.md +0 -128
  44. package/docs/api/registerHandler.md +0 -174
  45. package/docs/api/registerNodeType.md +0 -142
  46. package/docs/api/removeConnection.md +0 -57
  47. package/docs/api/removeNode.md +0 -80
  48. package/docs/api/saveLayout.md +0 -152
  49. package/docs/api/screenToSVGCoords.md +0 -68
  50. package/docs/api/selectNode.md +0 -116
  51. package/docs/api/setTheme.md +0 -168
  52. package/docs/api/setZoom.md +0 -97
  53. package/docs/api/toggleFullscreen.md +0 -68
  54. package/docs/card-help/EACH.md +0 -19
  55. package/docs/card-help/FREAD.md +0 -24
  56. package/docs/card-help/FWRITE.md +0 -24
  57. package/docs/card-help/GET.md +0 -22
  58. package/docs/card-help/ITE.md +0 -23
  59. package/docs/card-help/LOG.md +0 -23
  60. package/docs/card-help/NOTE.md +0 -17
  61. package/docs/card-help/PREV.md +0 -18
  62. package/docs/card-help/SET.md +0 -27
  63. package/docs/card-help/SPKL.md +0 -22
  64. package/docs/card-help/STAT.md +0 -23
  65. package/docs/card-help/SW.md +0 -25
  66. package/docs/diagrams/architecture-at-a-glance.excalidraw +0 -4270
  67. package/docs/diagrams/architecture-at-a-glance.mmd +0 -30
  68. package/docs/diagrams/architecture-at-a-glance.svg +0 -2
  69. package/docs/diagrams/data-flow.excalidraw +0 -1451
  70. package/docs/diagrams/data-flow.mmd +0 -17
  71. package/docs/diagrams/data-flow.svg +0 -2
  72. package/docs/diagrams/high-level-design.excalidraw +0 -5767
  73. package/docs/diagrams/high-level-design.mmd +0 -86
  74. package/docs/diagrams/high-level-design.svg +0 -2
  75. package/docs/diagrams/relationships.excalidraw +0 -3852
  76. package/docs/diagrams/relationships.mmd +0 -9
  77. package/docs/diagrams/relationships.svg +0 -2
  78. package/docs/diagrams/service-initialization-sequence.excalidraw +0 -1466
  79. package/docs/diagrams/service-initialization-sequence.mmd +0 -19
  80. package/docs/diagrams/service-initialization-sequence.svg +0 -2
  81. package/docs/diagrams/svg-layer-structure.excalidraw +0 -1060
  82. package/docs/diagrams/svg-layer-structure.mmd +0 -18
  83. package/docs/diagrams/svg-layer-structure.svg +0 -2
  84. package/docs/examples/README.md +0 -9
  85. package/docs/examples/simple_cards/README.md +0 -677
  86. package/docs/examples/simple_cards/css/flowexample.css +0 -65
  87. package/docs/examples/simple_cards/index.html +0 -32
  88. package/docs/examples/simple_cards/js/pict.min.js +0 -12
  89. package/docs/examples/simple_cards/pict-section-flow-example-simple-cards.compatible.min.js +0 -1
  90. package/docs/index.html +0 -38
  91. package/docs/playground/app.json +0 -6
  92. package/docs/playground/appdata.json +0 -85
  93. package/docs/playground/application.js +0 -23
  94. package/docs/playground/pict.json +0 -17
  95. package/docs/playground/runtime/pict-application.min.js +0 -2
  96. package/docs/playground/runtime/pict-section-flow.min.js +0 -2
  97. package/docs/playground/runtime/pict-section-modal.min.js +0 -2
  98. package/docs/playground/runtime/pict.min.js +0 -12
  99. package/docs/retold-catalog.json +0 -244
  100. package/docs/retold-keyword-index.json +0 -26028
  101. package/example_applications/simple_cards/css/flowexample.css +0 -65
  102. package/example_applications/simple_cards/html/index.html +0 -32
  103. package/example_applications/simple_cards/package.json +0 -52
  104. package/example_applications/simple_cards/source/Pict-Application-FlowExample-Configuration.json +0 -15
  105. package/example_applications/simple_cards/source/Pict-Application-FlowExample.js +0 -539
  106. package/example_applications/simple_cards/source/card-help-content.js +0 -16
  107. package/example_applications/simple_cards/source/cards/FlowCard-Comment.js +0 -38
  108. package/example_applications/simple_cards/source/cards/FlowCard-DataPreview.js +0 -44
  109. package/example_applications/simple_cards/source/cards/FlowCard-Each.js +0 -38
  110. package/example_applications/simple_cards/source/cards/FlowCard-FileRead.js +0 -56
  111. package/example_applications/simple_cards/source/cards/FlowCard-FileWrite.js +0 -50
  112. package/example_applications/simple_cards/source/cards/FlowCard-GetValue.js +0 -37
  113. package/example_applications/simple_cards/source/cards/FlowCard-IfThenElse.js +0 -49
  114. package/example_applications/simple_cards/source/cards/FlowCard-LogValues.js +0 -55
  115. package/example_applications/simple_cards/source/cards/FlowCard-SetValue.js +0 -97
  116. package/example_applications/simple_cards/source/cards/FlowCard-Sparkline.js +0 -100
  117. package/example_applications/simple_cards/source/cards/FlowCard-StatusMonitor.js +0 -46
  118. package/example_applications/simple_cards/source/cards/FlowCard-Switch.js +0 -39
  119. package/example_applications/simple_cards/source/providers/PictRouter-FlowExample-Configuration.json +0 -22
  120. package/example_applications/simple_cards/source/sample-flows.js +0 -410
  121. package/example_applications/simple_cards/source/views/PictView-FlowExample-About.js +0 -184
  122. package/example_applications/simple_cards/source/views/PictView-FlowExample-BottomBar.js +0 -77
  123. package/example_applications/simple_cards/source/views/PictView-FlowExample-Documentation.js +0 -325
  124. package/example_applications/simple_cards/source/views/PictView-FlowExample-FileWriteInfo.js +0 -59
  125. package/example_applications/simple_cards/source/views/PictView-FlowExample-Layout.js +0 -90
  126. package/example_applications/simple_cards/source/views/PictView-FlowExample-MainWorkspace.js +0 -453
  127. package/example_applications/simple_cards/source/views/PictView-FlowExample-TopBar.js +0 -95
  128. package/scripts/generate-card-help.js +0 -214
  129. package/source/providers/edges/Edge-Bezier.js +0 -41
  130. package/source/providers/edges/Edge-Orthogonal.js +0 -37
  131. package/source/providers/edges/Edge-OrthogonalSnap.js +0 -72
  132. package/source/providers/edges/Edge-Perimeter-Linear.js +0 -31
  133. package/source/providers/edges/Edge-Perimeter-Orthogonal.js +0 -39
  134. package/source/providers/edges/Edge-Perimeter.js +0 -48
  135. package/source/providers/edges/Edge-PerimeterMath.js +0 -92
  136. package/source/providers/edges/Edge-Straight.js +0 -24
  137. package/source/providers/layouts/Layout-Circular.js +0 -203
  138. package/source/providers/layouts/Layout-Coerce.js +0 -40
  139. package/source/providers/layouts/Layout-Columnar.js +0 -134
  140. package/source/providers/layouts/Layout-Custom.js +0 -27
  141. package/source/providers/layouts/Layout-ForcedFromCenter.js +0 -256
  142. package/source/providers/layouts/Layout-Grid.js +0 -134
  143. package/source/providers/layouts/Layout-Layered.js +0 -155
  144. package/source/providers/layouts/Layout-Rank.js +0 -141
  145. package/source/providers/layouts/Layout-Staggered.js +0 -131
  146. package/source/providers/layouts/Layout-Tabular.js +0 -94
  147. package/test/CardPalette_tests.js +0 -43
  148. package/test/ConnectionHandleManager_tests.js +0 -717
  149. package/test/ConnectionRenderer_tests.js +0 -591
  150. package/test/ConnectionStyle_tests.js +0 -90
  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
  163. package/test/ToolbarExtraButtons_tests.js +0 -138
  164. package/test/UndirectedConnections_tests.js +0 -70
@@ -1,677 +0,0 @@
1
- # Simple Cards - Every Flow Card Type, Every Panel Type
2
-
3
- <!-- docuserve:example-launch:start -->
4
- > **[Launch the live app](examples/simple%5Fcards/index.html)** - runs in your browser, opens in a new tab.
5
- <!-- docuserve:example-launch:end -->
6
-
7
- Simple Cards is the **reference example** for `pict-section-flow`. It
8
- defines twelve custom card classes covering every category
9
- (control flow, I/O, data, debug, monitoring, visualization), wires
10
- them into a single Pict application with `pict-section-form`-driven
11
- properties panels, ships a curated catalog of sample flows that
12
- exercise each layout algorithm, and provides a fully-functional
13
- multi-page shell (Home / About / Documentation) around the canvas.
14
-
15
- If you are looking for "what does a card class look like?" - read
16
- `source/cards/`. If you are looking for "how do I host the flow
17
- view inside an application?" - read
18
- `source/views/PictView-FlowExample-MainWorkspace.js`. If you are
19
- looking for "what does a real seed graph look like?" - see
20
- `source/Pict-Application-FlowExample.js`, which inlines a 16-node
21
- flow with every card type, every panel type, and an error branch.
22
-
23
- ## What it demonstrates
24
-
25
- | Capability | Where you see it |
26
- |------------|------------------|
27
- | Custom `PictFlowCard` subclasses | `source/cards/FlowCard-*.js` - 12 cards across 6 categories |
28
- | Properties panel type: `Markdown` | If-Then-Else card - static markdown blurb |
29
- | Properties panel type: `Template` | Log Values card - `pict-template` over `Record.Data.*` |
30
- | Properties panel type: `Form` | Set Value card - full `pict-section-form` manifest inside the panel |
31
- | Properties panel type: `View` | File Write card - host-registered Pict view rendered into the panel |
32
- | `BodyContent` rendering type: SVG | Status Monitor card - inline SVG circles + labels |
33
- | `BodyContent` rendering type: HTML | Data Preview / Note cards - HTML table / multi-line text |
34
- | `BodyContent` rendering type: Canvas | Sparkline card - `RenderCallback(canvas, ...)` paints a 2D chart |
35
- | Pre-registered node types | `NodeTypes: this._buildFlowCardNodeTypes()` - toolbar palette ready on first render |
36
- | Seed flow data on `AppData` | `AppData.FlowExample.SampleFlow` - 16 nodes, 18 connections, an error branch |
37
- | Sample-graph catalog + layout algorithm hint | Dropdown above the canvas; each sample suggests a `Recommended` layout |
38
- | Multi-page routing inside the shell | `pict-router` with `/Home`, `/About`, `/Documentation` routes |
39
- | `LayoutAlgorithm` driven re-layout | `setFlowData(...)` carries `LayoutAlgorithm`; the toolbar's Algorithm popup compares them live |
40
- | Help overlay for the canvas | "?" button toggles a CSS-grid hint panel with 8 cards covering Add / Connect / Pan etc. |
41
-
42
- ## Key files
43
-
44
- - `source/Pict-Application-FlowExample.js` - application class.
45
- Registers the router + every page view, declares the seed
46
- `SampleFlow` with one of every card type, and exposes
47
- `navigateTo()` / `showView()` for the router callbacks.
48
- - `source/Pict-Application-FlowExample-Configuration.json` - Pict
49
- config: product name, main viewport, auto-render flags.
50
- - `source/providers/PictRouter-FlowExample-Configuration.json` -
51
- route map. Each route's `template` calls into
52
- `Pict.PictApplication.showView('FlowExample-...')`.
53
- - `source/views/PictView-FlowExample-Layout.js` - top-level shell.
54
- Renders the topbar, content, and bottombar containers, then
55
- resolves the router so the current hash lands on the right page.
56
- - `source/views/PictView-FlowExample-TopBar.js` /
57
- `PictView-FlowExample-BottomBar.js` - branded chrome views with
58
- inline navigation links.
59
- - `source/views/PictView-FlowExample-MainWorkspace.js` - the page
60
- that hosts the flow canvas. Builds the FlowCard node type map,
61
- instantiates the flow view, wires the help toggle and the
62
- sample-graph selector.
63
- - `source/views/PictView-FlowExample-About.js` /
64
- `PictView-FlowExample-Documentation.js` - the two other pages.
65
- - `source/views/PictView-FlowExample-FileWriteInfo.js` - the host
66
- view that the File Write card's `View`-type panel renders.
67
- - `source/cards/FlowCard-*.js` - twelve card classes. Each is
68
- one file, each extends `pict-section-flow.PictFlowCard`.
69
- - `source/sample-flows.js` - the curated catalog of sample graphs
70
- that the dropdown above the canvas exposes.
71
-
72
- ## The seed flow
73
-
74
- `AppData.FlowExample.SampleFlow` is a complete `_FlowData` object
75
- declared inline in `onAfterInitializeAsync`. It is the "Hello World"
76
- the canvas opens to:
77
-
78
- ```js
79
- this.pict.AppData.FlowExample.SampleFlow =
80
- {
81
- Nodes:
82
- [
83
- { Hash: 'node-start', Type: 'start', X: 50, Y: 180, Width: 140, Height: 80, Title: 'Start',
84
- Ports: [ { Hash: 'port-start-out', Direction: 'output', Side: 'right', Label: 'Out' } ], Data: {} },
85
- { Hash: 'node-fread', Type: 'FREAD', /* ... */ },
86
- { Hash: 'node-check', Type: 'ITE', /* ... */ },
87
- { Hash: 'node-each', Type: 'EACH', /* ... */ },
88
- { Hash: 'node-get', Type: 'GET', /* ... */ },
89
- { Hash: 'node-set', Type: 'SET', /* ... */ },
90
- { Hash: 'node-switch', Type: 'SW', /* ... */ },
91
- { Hash: 'node-log', Type: 'LOG', /* ... */ },
92
- { Hash: 'node-fwrite', Type: 'FWRITE', /* ... */ },
93
- { Hash: 'node-end', Type: 'end', /* ... */ },
94
- /* error branch: node-log-err, node-halt */
95
- /* body-content showcase: node-status, node-preview, node-spark, node-comment */
96
- ],
97
- Connections: [ /* 18 edges including an error branch */ ],
98
- ViewState: { PanX: 0, PanY: 0, Zoom: 1, SelectedNodeHash: null, SelectedConnectionHash: null }
99
- };
100
- ```
101
-
102
- Every node references a card type by its `Code` (`FREAD`, `ITE`,
103
- etc.); the host registers the card classes in the workspace view so
104
- the flow view's `NodeTypeProvider` knows how to paint them.
105
-
106
- ---
107
-
108
- ## Feature 1 - Defining a custom card class
109
-
110
- A custom card is a `PictFlowCard` subclass. The constructor passes
111
- its declarative configuration into the parent class - title,
112
- description, ports, sizing, colors, optional panel, optional body
113
- content. Here is the If-Then-Else card in full:
114
-
115
- ```js
116
- const libPictFlowCard = require('pict-section-flow').PictFlowCard;
117
- const libCardHelp = require('../card-help-content');
118
-
119
- class FlowCardIfThenElse extends libPictFlowCard
120
- {
121
- constructor(pFable, pOptions, pServiceHash)
122
- {
123
- super(pFable, Object.assign(
124
- {},
125
- {
126
- Title: 'If-Then-Else',
127
- Name: 'Conditional Branch',
128
- Code: 'ITE',
129
- Description: 'Evaluates a condition and routes to the Then or Else branch.',
130
- Help: libCardHelp['ITE'] || false,
131
- Icon: 'ITE',
132
- Tooltip: 'If-Then-Else: Routes flow based on a boolean condition',
133
- Category: 'Control Flow',
134
- TitleBarColor: '#e67e22',
135
- BodyStyle: { fill: '#fef5e7', stroke: '#e67e22' },
136
- Width: 200,
137
- Height: 100,
138
- Inputs: [ { Name: 'In', Side: 'left', MinimumInputCount: 1, MaximumInputCount: 1 } ],
139
- Outputs: [ { Name: 'Then', Side: 'right' }, { Name: 'Else', Side: 'bottom' } ],
140
- PropertiesPanel:
141
- {
142
- PanelType: 'Markdown',
143
- DefaultWidth: 300,
144
- DefaultHeight: 200,
145
- Title: 'If-Then-Else Info',
146
- Configuration: { Markdown: '## Conditional Branch\n\nEvaluates a **boolean condition**...' }
147
- }
148
- },
149
- pOptions),
150
- pServiceHash);
151
- }
152
- }
153
-
154
- module.exports = FlowCardIfThenElse;
155
- ```
156
-
157
- `Code` is the wire-shape identifier - what each node in the flow
158
- data carries as its `Type`. `Category` groups the card in the
159
- toolbar palette. `Inputs` and `Outputs` declare port slots with
160
- their side (top/right/bottom/left) and cardinality
161
- (`MinimumInputCount` / `MaximumInputCount`; `-1` means unbounded).
162
- The `Help` block (lazy-loaded from `card-help-content.js`) is the
163
- content for the per-card help drawer.
164
-
165
- This is the entire card. Twelve such files cover the example.
166
-
167
- ---
168
-
169
- ## Feature 2 - Pre-registered node types
170
-
171
- The host workspace view builds a `NodeTypes` map by instantiating
172
- each card class once, calling its `getNodeTypeConfiguration()`, and
173
- keying the resulting config by its `Hash`. The map is then handed
174
- to the flow view at registration time:
175
-
176
- ```js
177
- _buildFlowCardNodeTypes()
178
- {
179
- let tmpCardClasses =
180
- [
181
- libFlowCardIfThenElse, libFlowCardSwitch, libFlowCardEach,
182
- libFlowCardFileRead, libFlowCardFileWrite,
183
- libFlowCardLogValues, libFlowCardSetValue, libFlowCardGetValue,
184
- libFlowCardStatusMonitor, libFlowCardDataPreview,
185
- libFlowCardSparkline, libFlowCardComment
186
- ];
187
-
188
- let tmpNodeTypes = {};
189
- for (let i = 0; i < tmpCardClasses.length; i++)
190
- {
191
- let tmpCard = new tmpCardClasses[i](this.fable, {}, `FlowCard-${i}`);
192
- let tmpConfig = tmpCard.getNodeTypeConfiguration();
193
- tmpNodeTypes[tmpConfig.Hash] = tmpConfig;
194
- }
195
- return tmpNodeTypes;
196
- }
197
- ```
198
-
199
- The flow view receives `NodeTypes` as part of its options, which
200
- means the `NodeTypeProvider` is fully populated **before the
201
- toolbar renders**. Without pre-registration, the toolbar palette
202
- would show an empty list on first paint and fill in only after a
203
- later `registerNodeType(...)` call - visible flicker, no benefit.
204
-
205
- ```js
206
- this._FlowView = this.pict.addView('FlowExample-FlowDiagram',
207
- {
208
- ViewIdentifier: 'FlowExample-FlowDiagram',
209
- FlowDataAddress: 'AppData.FlowExample.SampleFlow',
210
- TargetElementAddress: '#Flow-SVG-Container',
211
- EnableToolbar: true, EnablePanning: true, EnableZooming: true,
212
- EnableNodeDragging: true, EnableConnectionCreation: true,
213
- EnableGridSnap: false, GridSnapSize: 20,
214
- MinZoom: 0.1, MaxZoom: 5.0, ZoomStep: 0.1,
215
- DefaultNodeType: 'default', DefaultNodeWidth: 180, DefaultNodeHeight: 80,
216
- NodeTypes: this._buildFlowCardNodeTypes(),
217
- /* Renderables ... */
218
- },
219
- libPictSectionFlow
220
- );
221
- ```
222
-
223
- `FlowDataAddress` points at the AppData slot the seed flow lives
224
- in; the flow view two-way binds against it. Mutations from the
225
- canvas (drag a node, draw a connection, delete an edge) write
226
- back; mutations from the host (`setFlowData(...)`) re-render.
227
-
228
- ---
229
-
230
- ## Feature 3 - Properties panel types: Markdown, Template, Form, View
231
-
232
- The four built-in `PropertiesPanel.PanelType` values cover most of
233
- what a node-editing UI needs. The example demonstrates one of
234
- each:
235
-
236
- **Markdown** (If-Then-Else card):
237
-
238
- ```js
239
- PropertiesPanel:
240
- {
241
- PanelType: 'Markdown',
242
- DefaultWidth: 300, DefaultHeight: 200,
243
- Title: 'If-Then-Else Info',
244
- Configuration: { Markdown: '## Conditional Branch\n\nEvaluates a **boolean condition**...' }
245
- }
246
- ```
247
-
248
- Static documentation with markdown rendering. No data binding;
249
- read-only.
250
-
251
- **Template** (Log Values card):
252
-
253
- ```js
254
- PropertiesPanel:
255
- {
256
- PanelType: 'Template',
257
- DefaultWidth: 260, DefaultHeight: 140,
258
- Title: 'Log Settings',
259
- Configuration:
260
- {
261
- Templates:
262
- [
263
- {
264
- Hash: 'flow-card-log-panel',
265
- Template: '<div style="padding:4px"><label style="font-size:11px;color:#7f8c8d">Log Level</label>' +
266
- '<div style="font-size:12px;padding:4px 0">{~D:Record.Data.LogLevel~}</div>' +
267
- '<label style="font-size:11px;color:#7f8c8d">Format</label>' +
268
- '<div style="font-size:12px;padding:4px 0">{~D:Record.Data.Format~}</div></div>'
269
- }
270
- ],
271
- TemplateHash: 'flow-card-log-panel'
272
- }
273
- }
274
- ```
275
-
276
- `pict-template` syntax - `{~D:Record.Data.LogLevel~}` resolves
277
- against the node's `Data` block. Read-only viewer surfaced from a
278
- template hash; ideal for showing computed or formatted state.
279
-
280
- **Form** (Set Value card):
281
-
282
- ```js
283
- PropertiesPanel:
284
- {
285
- PanelType: 'Form',
286
- DefaultWidth: 320, DefaultHeight: 200,
287
- Title: 'Set Value Properties',
288
- Configuration:
289
- {
290
- Manifest:
291
- {
292
- Scope: 'FlowCardSetValue',
293
- Sections: [ { Name: 'Value Assignment', Hash: 'SetValueSection',
294
- Groups: [ { Name: 'Settings', Hash: 'SetValueGroup' } ] } ],
295
- Descriptors:
296
- {
297
- 'Record.Data.VariableName':
298
- {
299
- Name: 'Variable Name', Hash: 'VariableName', DataType: 'String', Default: '',
300
- PictForm: { Section: 'SetValueSection', Group: 'SetValueGroup', Row: 1, Width: 12 }
301
- },
302
- 'Record.Data.Expression':
303
- {
304
- Name: 'Value Expression', Hash: 'Expression', DataType: 'String', Default: '',
305
- PictForm: { Section: 'SetValueSection', Group: 'SetValueGroup',
306
- Row: 2, Width: 12, InputType: 'TextArea' }
307
- }
308
- }
309
- }
310
- }
311
- }
312
- ```
313
-
314
- A full `pict-section-form` manifest. The panel renders a live form;
315
- edits flow back into the node's `Data` block; the next save snapshots
316
- them. The Set Value card's `VariableName` and `Expression` fields
317
- are what a flow engine would later read at evaluation time.
318
-
319
- **View** (File Write card):
320
-
321
- ```js
322
- PropertiesPanel:
323
- {
324
- PanelType: 'View',
325
- DefaultWidth: 260, DefaultHeight: 180,
326
- Title: 'File Write Info',
327
- Configuration: { ViewHash: 'FlowExample-FileWriteInfo' }
328
- }
329
- ```
330
-
331
- The application registers `FlowExample-FileWriteInfo` as a Pict
332
- view (any host-defined view), and the panel renders it. This is the
333
- escape hatch for "I need something none of the built-in panels
334
- cover" - a third-party widget, a custom editor, an embedded
335
- preview.
336
-
337
- The four types cover the gradient from "static" (Markdown) ->
338
- "templated read-only" (Template) -> "structured editing" (Form) ->
339
- "anything you can build" (View).
340
-
341
- ---
342
-
343
- ## Feature 4 - BodyContent: SVG / HTML / Canvas
344
-
345
- Every card has an optional `BodyContent` block that paints inside
346
- the node's body (between the title bar and the port row). Three
347
- content types cover the spectrum from static vector art to live
348
- rendered visualizations:
349
-
350
- **SVG** - declarative shapes inline in the node:
351
-
352
- ```js
353
- // FlowCard-StatusMonitor.js
354
- BodyContent:
355
- {
356
- ContentType: 'svg',
357
- Template: '<circle cx="30" cy="28" r="6" fill="#27ae60" opacity="0.9"/>' +
358
- '<text x="42" y="32" font-size="9" fill="#2c3e50">API</text>' +
359
- '<circle cx="100" cy="28" r="6" fill="#27ae60" opacity="0.9"/>' +
360
- '<text x="112" y="32" font-size="9" fill="#2c3e50">DB</text>' +
361
- /* ... */
362
- }
363
- ```
364
-
365
- The SVG template is interpolated into the node's `<svg>` group, so
366
- every primitive coordinate is in the node's local space (`0,0` is
367
- the body top-left). Use this for status indicators, mini-icons,
368
- glyphs.
369
-
370
- **HTML** - `foreignObject`-wrapped markup for rich text and tables:
371
-
372
- ```js
373
- // FlowCard-DataPreview.js
374
- BodyContent:
375
- {
376
- ContentType: 'html',
377
- Template:
378
- '<table style="width:100%;border-collapse:collapse;font-size:9px;color:#2c3e50">' +
379
- '<tr style="background:#d6eaf8">' +
380
- '<td style="padding:3px 5px;font-weight:600">Field</td>' +
381
- '<td style="padding:3px 5px;font-weight:600">Type</td>' +
382
- '<td style="padding:3px 5px;font-weight:600">Value</td>' +
383
- '</tr>' +
384
- /* ... */
385
- '</table>'
386
- }
387
- ```
388
-
389
- The HTML is wrapped in an SVG `<foreignObject>` and sized to the
390
- node body. Use it for the things SVG `<text>` can't do - tables,
391
- multi-line wrapping, real CSS.
392
-
393
- **Canvas** - programmatic drawing via a render callback:
394
-
395
- ```js
396
- // FlowCard-Sparkline.js
397
- BodyContent:
398
- {
399
- ContentType: 'canvas',
400
- RenderCallback: function (pCanvas, pNodeData, pNodeTypeConfig, pBounds)
401
- {
402
- let tmpCtx = pCanvas.getContext('2d');
403
- if (!tmpCtx) return;
404
-
405
- let tmpData = [12, 19, 8, 25, 15, 30, 22, 18, 35, 28, 14, 32, 20, 26, 10, 24, 33, 17, 29, 21];
406
- let tmpMax = Math.max.apply(null, tmpData);
407
- let tmpMin = Math.min.apply(null, tmpData);
408
- let tmpRange = tmpMax - tmpMin || 1;
409
- let tmpPadding = 6;
410
- let tmpChartW = pCanvas.width - (tmpPadding * 2);
411
- let tmpChartH = pCanvas.height - (tmpPadding * 2);
412
- let tmpStep = tmpChartW / (tmpData.length - 1);
413
-
414
- // Fill the area beneath the line ...
415
- tmpCtx.beginPath();
416
- tmpCtx.moveTo(tmpPadding, pCanvas.height - tmpPadding);
417
- for (let i = 0; i < tmpData.length; i++)
418
- {
419
- let tmpX = tmpPadding + (i * tmpStep);
420
- let tmpY = tmpPadding + tmpChartH - ((tmpData[i] - tmpMin) / tmpRange) * tmpChartH;
421
- tmpCtx.lineTo(tmpX, tmpY);
422
- }
423
- /* ... draw line, end dot ... */
424
- }
425
- }
426
- ```
427
-
428
- The framework calls `RenderCallback` with a sized `<canvas>` element
429
- and the node's own data, so the chart redraws on every re-render
430
- (node drag, zoom change, theme switch). Use this for charts,
431
- visualizations of data the node carries, any non-trivial 2D rendering.
432
-
433
- ---
434
-
435
- ## Feature 5 - Host shell + multi-page routing
436
-
437
- The application has three top-level pages - Home (the canvas),
438
- About, and Documentation - wired through `pict-router`. The route
439
- configuration JSON lives next to the application:
440
-
441
- ```json
442
- {
443
- "ProviderIdentifier": "Pict-Router",
444
- "AutoInitialize": true,
445
- "AutoInitializeOrdinal": 0,
446
- "Routes":
447
- [
448
- { "path": "/Home", "template": "{~LV:Pict.PictApplication.showView(`FlowExample-MainWorkspace`)~}" },
449
- { "path": "/About", "template": "{~LV:Pict.PictApplication.showView(`FlowExample-About`)~}" },
450
- { "path": "/Documentation", "template": "{~LV:Pict.PictApplication.showView(`FlowExample-Documentation`)~}" }
451
- ]
452
- }
453
- ```
454
-
455
- The `{~LV:...~}` is the live-value template tag - it evaluates
456
- the expression every time the route matches, calling the
457
- application's `showView(viewIdentifier)` method. That method
458
- swaps the content container's view in place:
459
-
460
- ```js
461
- showView(pViewIdentifier)
462
- {
463
- if (pViewIdentifier in this.pict.views)
464
- {
465
- this.pict.AppData.FlowExample.CurrentRoute = pViewIdentifier;
466
- this.pict.views[pViewIdentifier].render();
467
- }
468
- else
469
- {
470
- this.pict.log.warn(`View [${pViewIdentifier}] not found; falling back to main workspace.`);
471
- this.pict.views['FlowExample-MainWorkspace'].render();
472
- }
473
- }
474
- ```
475
-
476
- The topbar and bottombar are siblings of the content container in
477
- the layout shell - they don't re-render on route change. The
478
- brand link calls `Pict.PictApplication.navigateTo('/Home')`, which
479
- in turn calls the router's `navigate(...)`; the router fires the
480
- template; the host calls `showView(...)`. Same path as a direct hash
481
- URL - `#/Documentation` works the same way.
482
-
483
- The flow view re-initializes its SVG primitives whenever the
484
- workspace re-renders, so navigating away to About and back to Home
485
- gets a fresh canvas:
486
-
487
- ```js
488
- // In MainWorkspace's onAfterRender:
489
- this._FlowView.initialRenderComplete = false;
490
- this._FlowView.render();
491
- ```
492
-
493
- ---
494
-
495
- ## Feature 6 - Sample-graph catalog with layout-algorithm hints
496
-
497
- The dropdown above the canvas surfaces a curated set of graphs
498
- shaped to exercise the flow view's seven layout algorithms (the
499
- "Hello World" reference, linear chains, fan-outs, grids, etc.).
500
- Each catalog entry declares a `Name`, `Description`, optional
501
- `Recommended` layout, and a complete `_FlowData` object:
502
-
503
- ```js
504
- // sample-flows.js
505
- function _flow(pNodes, pConnections, pAlgorithm, pParameters, pAutoApply)
506
- {
507
- return {
508
- Nodes: pNodes,
509
- Connections: pConnections || [],
510
- OpenPanels: [],
511
- SavedLayouts: [],
512
- ViewState: _emptyViewState(),
513
- LayoutAlgorithm: pAlgorithm || 'Custom',
514
- LayoutParameters: pParameters || {},
515
- LayoutAutoApply: !!pAutoApply
516
- };
517
- }
518
- ```
519
-
520
- The workspace view's `_loadSample` callback deep-clones the sample
521
- flow (so reloading does not share references with the prior load)
522
- and pushes it through `setFlowData(...)`:
523
-
524
- ```js
525
- _loadSample(pKey, pDescEl, pRecoEl)
526
- {
527
- if (!this._FlowView) return;
528
-
529
- if (pKey === '__hello-world__')
530
- {
531
- this._FlowView.setFlowData(this.pict.AppData.FlowExample.SampleFlow);
532
- pDescEl.innerHTML = 'The full reference flow with all card types, properties panels, and an error branch.' +
533
- ' Originally designed by hand - set <code>LayoutAlgorithm</code> to <em>Layered</em>' +
534
- ' to see how the auto-layout compares.';
535
- pRecoEl.style.display = 'none';
536
- return;
537
- }
538
-
539
- let tmpSample = libSampleFlows.getSample(pKey);
540
- if (!tmpSample) return;
541
-
542
- this._FlowView.setFlowData(JSON.parse(JSON.stringify(tmpSample.Flow)));
543
- pDescEl.textContent = tmpSample.Description;
544
- if (tmpSample.Recommended)
545
- {
546
- pRecoEl.style.display = '';
547
- pRecoEl.textContent = `Try: ${tmpSample.Recommended}`;
548
- }
549
- else
550
- {
551
- pRecoEl.style.display = 'none';
552
- }
553
- }
554
- ```
555
-
556
- Picking a sample swaps the canvas instantly. Opening the toolbar's
557
- Algorithm popup lets you flip between layouts and watch the same
558
- graph re-arrange - which is the whole point of the catalog. Some
559
- shapes shine under Layered; some under Force-Directed; the
560
- `Recommended` hint is the curator's pick.
561
-
562
- ---
563
-
564
- ## Feature 7 - Help overlay rendered from a CSS grid
565
-
566
- The "?" button in the workspace header toggles a hint panel built
567
- as a CSS grid. The panel itself is part of the workspace template;
568
- the toggle simply adds/removes a `visible` class:
569
-
570
- ```js
571
- let tmpHelpToggle = document.getElementById('FlowExample-HelpToggle');
572
- let tmpHelpPanel = document.getElementById('FlowExample-HelpPanel');
573
- if (tmpHelpToggle && tmpHelpPanel)
574
- {
575
- tmpHelpToggle.addEventListener('click', function ()
576
- {
577
- tmpHelpPanel.classList.toggle('visible');
578
- tmpHelpToggle.classList.toggle('active');
579
- });
580
- }
581
- ```
582
-
583
- The eight hints - Add / Connect / Move / Pan & Zoom / Delete /
584
- Auto Layout / Properties / Save Layouts - are static `<div>`s in
585
- the workspace template, each with a heading and short description:
586
-
587
- ```html
588
- <div class="flowexample-hints">
589
- <div class="flowexample-hint">
590
- <h4>Add Nodes</h4>
591
- <p>Select a node type from the dropdown and click <code>+ Add Node</code> in the toolbar.</p>
592
- </div>
593
- <div class="flowexample-hint">
594
- <h4>Connect Nodes</h4>
595
- <p>Drag from a green output port to a blue input port to create a connection.</p>
596
- </div>
597
- /* ... six more ... */
598
- </div>
599
- ```
600
-
601
- `grid-template-columns: repeat(auto-fill, minmax(220px, 1fr))` makes
602
- the grid reflow without media queries - the hints arrange themselves
603
- across whatever width the viewport gives them.
604
-
605
- ---
606
-
607
- ## Running the example
608
-
609
- ```bash
610
- cd example_applications/simple_cards
611
- npm install
612
- npm run build
613
- # serve ./dist/ over HTTP (e.g. `cd dist && python3 -m http.server 8000`)
614
- ```
615
-
616
- The `prebuild` script generates `card-help/*.md` documentation
617
- from the card sources into `docs/card-help/`. The build itself is
618
- `npx quack build && npx quack copy` - emits the application
619
- bundle and copies the html/css/pict assets into `dist/`.
620
-
621
- ## Things to try in the running app
622
-
623
- - **Drop in the Hello World flow** - the canvas opens to it. Pan
624
- around; every card type is on the page.
625
- - **Open a properties panel** - double-click the Set Value node
626
- for the Form panel; the Log Values node for the Template panel;
627
- the If-Then-Else node for the Markdown panel; the File Write
628
- node for the View panel.
629
- - **Switch sample graphs** - pick "Linear Chain" or "Fan-Out". The
630
- canvas swaps to the new shape. Open the toolbar's Algorithm
631
- popup and try `Layered` vs `Force-Directed`.
632
- - **Toggle the help overlay** - click the `?` button in the header.
633
- The eight hint cards appear in a responsive grid.
634
- - **Navigate** - click `About` in the topbar, then back to `Home`.
635
- The flow re-renders cleanly; the topbar/bottombar stay put.
636
- - **Inspect the BodyContent showcase** - at the bottom-left of the
637
- Hello World graph are four cards: Status Monitor (SVG circles),
638
- Data Preview (HTML table), Throughput (canvas-rendered sparkline),
639
- Note (HTML text). Each demonstrates one rendering type.
640
-
641
- ## Takeaways
642
-
643
- 1. **A card is one file, ~30 lines.** Twelve cards, twelve files,
644
- twelve constructors that hand declarative config to
645
- `PictFlowCard`. No inheritance trees, no template files.
646
- 2. **Pre-register node types via `NodeTypes` in the view options.**
647
- The toolbar palette is alive before its first paint, no
648
- subsequent `registerNodeType` flicker.
649
- 3. **Pick your panel type by what you want to bind.** Markdown for
650
- docs, Template for read-only display, Form for structured
651
- editing, View for everything else. They share the same panel
652
- chrome and tether-line behavior.
653
- 4. **`BodyContent` is per-card.** SVG for icons, HTML for tables,
654
- Canvas for charts. The framework wires it; the card declares
655
- it.
656
- 5. **The sample-graph catalog is the layout algorithm's test
657
- harness.** Each sample is a shape; the dropdown swaps shapes;
658
- the Algorithm popup swaps layouts. That is how you discover
659
- which layout fits which kind of graph.
660
-
661
- ## Related documentation
662
-
663
- - [Getting Started](../../Getting_Started.md) - minimum-viable flow
664
- view; build the first card from scratch.
665
- - [Architecture](../../Architecture.md) - service / provider /
666
- view layering of the section.
667
- - [Implementation Reference](../../Implementation_Reference.md) -
668
- full API surface.
669
- - [Data Model](../../Data_Model.md) - the `_FlowData` shape used
670
- by the seed flow and the sample catalog.
671
- - [PictFlowCard](../../api/PictFlowCard.md) - the card base class.
672
- - [PictFlowCardPropertiesPanel](../../api/PictFlowCardPropertiesPanel.md)
673
- - the panel base class extending to custom panel types.
674
- - [registerNodeType](../../api/registerNodeType.md) - the
675
- alternative to passing `NodeTypes` at construction time.
676
- - [setTheme / registerTheme](../../api/setTheme.md) - the theming
677
- surface every card respects.