pict-section-flow 0.0.17 → 0.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +18 -18
  2. package/docs/Architecture.md +1 -1
  3. package/docs/Data_Model.md +2 -2
  4. package/docs/Getting_Started.md +5 -5
  5. package/docs/Implementation_Reference.md +6 -6
  6. package/docs/Layout_Persistence.md +3 -3
  7. package/docs/README.md +12 -12
  8. package/docs/Theme_Integration.md +150 -0
  9. package/docs/_cover.md +1 -1
  10. package/docs/_sidebar.md +7 -6
  11. package/docs/_version.json +7 -0
  12. package/docs/api/PictFlowCard.md +6 -6
  13. package/docs/api/PictFlowCardPropertiesPanel.md +2 -2
  14. package/docs/api/addConnection.md +4 -4
  15. package/docs/api/addNode.md +6 -6
  16. package/docs/api/autoLayout.md +2 -2
  17. package/docs/api/getFlowData.md +5 -5
  18. package/docs/api/marshalToView.md +3 -3
  19. package/docs/api/openPanel.md +2 -2
  20. package/docs/api/registerHandler.md +3 -3
  21. package/docs/api/registerNodeType.md +3 -3
  22. package/docs/api/removeConnection.md +5 -5
  23. package/docs/api/removeNode.md +6 -6
  24. package/docs/api/saveLayout.md +2 -2
  25. package/docs/api/screenToSVGCoords.md +2 -2
  26. package/docs/api/selectNode.md +3 -3
  27. package/docs/api/setTheme.md +2 -2
  28. package/docs/api/setZoom.md +3 -3
  29. package/docs/api/toggleFullscreen.md +2 -2
  30. package/docs/card-help/EACH.md +3 -3
  31. package/docs/card-help/FREAD.md +5 -5
  32. package/docs/card-help/FWRITE.md +5 -5
  33. package/docs/card-help/GET.md +2 -2
  34. package/docs/card-help/ITE.md +3 -3
  35. package/docs/card-help/LOG.md +4 -4
  36. package/docs/card-help/NOTE.md +1 -1
  37. package/docs/card-help/PREV.md +2 -2
  38. package/docs/card-help/SET.md +5 -5
  39. package/docs/card-help/SPKL.md +2 -2
  40. package/docs/card-help/STAT.md +3 -3
  41. package/docs/card-help/SW.md +4 -4
  42. package/docs/css/docuserve.css +277 -23
  43. package/docs/index.html +2 -2
  44. package/docs/retold-catalog.json +1 -1
  45. package/docs/retold-keyword-index.json +1 -1
  46. package/example_applications/simple_cards/css/flowexample.css +2 -2
  47. package/example_applications/simple_cards/source/card-help-content.js +12 -12
  48. package/example_applications/simple_cards/source/cards/FlowCard-DataPreview.js +1 -1
  49. package/example_applications/simple_cards/source/sample-flows.js +410 -0
  50. package/example_applications/simple_cards/source/views/PictView-FlowExample-About.js +5 -5
  51. package/example_applications/simple_cards/source/views/PictView-FlowExample-Documentation.js +5 -5
  52. package/example_applications/simple_cards/source/views/PictView-FlowExample-FileWriteInfo.js +4 -4
  53. package/example_applications/simple_cards/source/views/PictView-FlowExample-MainWorkspace.js +141 -8
  54. package/example_applications/simple_cards/source/views/PictView-FlowExample-TopBar.js +2 -2
  55. package/package.json +8 -7
  56. package/source/Pict-Section-Flow.js +26 -0
  57. package/source/providers/PictProvider-Flow-CSS.js +435 -61
  58. package/source/providers/PictProvider-Flow-ConnectorShapes.js +9 -5
  59. package/source/providers/PictProvider-Flow-NodeTypes.js +10 -0
  60. package/source/providers/PictProvider-Flow-PanelChrome.js +7 -17
  61. package/source/providers/PictProvider-Flow-Theme.js +7 -7
  62. package/source/providers/edges/Edge-Bezier.js +41 -0
  63. package/source/providers/edges/Edge-Orthogonal.js +37 -0
  64. package/source/providers/edges/Edge-OrthogonalSnap.js +72 -0
  65. package/source/providers/edges/Edge-Perimeter-Linear.js +31 -0
  66. package/source/providers/edges/Edge-Perimeter-Orthogonal.js +39 -0
  67. package/source/providers/edges/Edge-Perimeter.js +48 -0
  68. package/source/providers/edges/Edge-PerimeterMath.js +92 -0
  69. package/source/providers/edges/Edge-Straight.js +24 -0
  70. package/source/providers/layouts/Layout-Circular.js +203 -0
  71. package/source/providers/layouts/Layout-Coerce.js +40 -0
  72. package/source/providers/layouts/Layout-Columnar.js +134 -0
  73. package/source/providers/layouts/Layout-Custom.js +27 -0
  74. package/source/providers/layouts/Layout-ForcedFromCenter.js +256 -0
  75. package/source/providers/layouts/Layout-Grid.js +134 -0
  76. package/source/providers/layouts/Layout-Layered.js +209 -0
  77. package/source/providers/layouts/Layout-Tabular.js +94 -0
  78. package/source/services/PictService-Flow-ConnectionRenderer.js +532 -28
  79. package/source/services/PictService-Flow-DataManager.js +12 -1
  80. package/source/services/PictService-Flow-InteractionManager.js +39 -42
  81. package/source/services/PictService-Flow-Layout.js +305 -121
  82. package/source/services/PictService-Flow-PortRenderer.js +108 -26
  83. package/source/services/PictService-Flow-RenderManager.js +41 -11
  84. package/source/views/PictView-Flow-FloatingToolbar.js +69 -61
  85. package/source/views/PictView-Flow-Node.js +47 -6
  86. package/source/views/PictView-Flow-PropertiesPanel.js +46 -53
  87. package/source/views/PictView-Flow-Toolbar.js +1065 -485
  88. package/source/views/PictView-Flow.js +455 -7
  89. package/test/Layout_tests.js +1400 -0
  90. package/test/PortRenderer_tests.js +11 -2
package/docs/index.html CHANGED
@@ -4,9 +4,9 @@
4
4
  <meta charset="utf-8">
5
5
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
7
- <meta name="description" content="Documentation powered by pict-docuserve">
7
+ <meta name="description" content="Pict-Section-Flow v0.0.17 Documentation Pict Section Flow Diagram">
8
8
 
9
- <title>Documentation</title>
9
+ <title>Pict-Section-Flow v0.0.17 Documentation</title>
10
10
 
11
11
  <!-- Application Stylesheet -->
12
12
  <link href="css/docuserve.css" rel="stylesheet">
@@ -1,5 +1,5 @@
1
1
  {
2
- "Generated": "2026-03-17T22:19:31.420Z",
2
+ "Generated": "2026-04-10T17:25:15.652Z",
3
3
  "GitHubOrg": "stevenvelozo",
4
4
  "DefaultBranch": "master",
5
5
  "Groups": [
@@ -1,5 +1,5 @@
1
1
  {
2
- "Generated": "2026-03-17T22:19:31.660Z",
2
+ "Generated": "2026-04-10T17:25:15.920Z",
3
3
  "DocumentCount": 30,
4
4
  "LunrIndex": {
5
5
  "version": "2.3.9",
@@ -13,7 +13,7 @@ html, body {
13
13
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
14
14
  font-size: 16px;
15
15
  line-height: 1.5;
16
- color: #333;
16
+ color: var(--theme-color-text-primary, #333);
17
17
  background-color: #f5f7fa;
18
18
  -webkit-font-smoothing: antialiased;
19
19
  -moz-osx-font-smoothing: grayscale;
@@ -45,7 +45,7 @@ a:hover {
45
45
  }
46
46
 
47
47
  ::-webkit-scrollbar-track {
48
- background: #f1f1f1;
48
+ background: var(--theme-color-background-tertiary, #f1f1f1);
49
49
  }
50
50
 
51
51
  ::-webkit-scrollbar-thumb {
@@ -1,16 +1,16 @@
1
1
  // Auto-generated by scripts/generate-card-help.js — do not edit manually.
2
2
  // Source markdown files are in docs/card-help/
3
3
  module.exports = {
4
- "EACH": "<h1>Each (Loop Iterator)</h1><p>The <b>Each</b> node iterates over a collection, executing connected downstream nodes once for each item. When iteration completes, the <b>Done</b> output fires.</p><h2>Ports</h2><ul><li><b>Collection</b> (input) an array or iterable to loop over</li><li><b>Item</b> (output) fires once per element with the current item</li><li><b>Done</b> (output) fires after all items have been processed</li></ul><h2>Behavior</h2><p>When a collection arrives at the input port, the Each node processes items sequentially. For every element in the collection, the <b>Item</b> output is activated with the current element as the payload. After the final element is processed, the <b>Done</b> output fires to signal completion.</p><h2>Tips</h2><ul><li>Connect <b>Item</b> to a processing chain and <b>Done</b> to continuation logic</li><li>Nested loops are supported by chaining multiple Each nodes</li><li>Empty collections skip directly to the <b>Done</b> output</li></ul>",
5
- "FREAD": "<h1>File Read</h1><p>The <b>File Read</b> node reads the contents of a file from the filesystem and outputs the data.</p><h2>Ports</h2><ul><li><b>Path</b> (input) the filesystem path to read</li><li><b>Data</b> (output) the file contents on success</li><li><b>Error</b> (output) fires if the read operation fails</li></ul><h2>Properties</h2><ul><li><b>FilePath</b> the path to the file to read</li><li><b>Encoding</b> character encoding for text files (e.g. <code>utf8</code>, <code>ascii</code>)</li></ul><h2>Behavior</h2><p>When triggered, the node reads the file at the configured path. On success, the raw file contents are emitted from the <b>Data</b> output. If the file does not exist or cannot be read, the <b>Error</b> output fires with a descriptive error message.</p><h2>Tips</h2><ul><li>Use a Get Value node upstream to dynamically set the file path</li><li>Pair with a Data Preview node to inspect the file contents</li><li>Connect the <b>Error</b> output to logging or notification nodes for robust error handling</li></ul>",
6
- "FWRITE": "<h1>File Write</h1><p>The <b>File Write</b> node writes data to a file on the filesystem.</p><h2>Ports</h2><ul><li><b>Path</b> (input) the destination filesystem path</li><li><b>Data</b> (input) the content to write</li><li><b>Done</b> (output) fires after a successful write</li><li><b>Error</b> (output) fires if the write operation fails</li></ul><h2>Behavior</h2><p>When both inputs are satisfied, the node writes the provided data to the specified file path. On success the <b>Done</b> output fires. If the write fails (for example due to permissions or a missing directory), the <b>Error</b> output fires with a descriptive error message.</p><h2>Properties Panel</h2><p>The properties panel shows a View-based info panel with details about the configured file path and write options.</p><h2>Tips</h2><ul><li>Directories in the path are not created automatically ensure they exist before writing</li><li>Combine with a Set Value node to format data before writing</li><li>Connect the <b>Error</b> output to a Log Values node to capture write failures</li></ul>",
7
- "GET": "<h1>Get Value</h1><p>The <b>Get Value</b> node retrieves a named variable from the flow context and emits its current value.</p><h2>Ports</h2><ul><li><b>In</b> (input) trigger to read the value</li><li><b>Value</b> (output) the retrieved value</li></ul><h2>Behavior</h2><p>When triggered, the node looks up a named key in the flow context and emits the stored value from the <b>Value</b> output. If the key does not exist, the output value is <code>undefined</code>.</p><h2>Usage</h2><p>Pair with a <b>Set Value</b> node to establish a read/write variable pattern. The Set Value node stores a value under a named key; the Get Value node retrieves it downstream.</p><h2>Tips</h2><ul><li>Variable names are case-sensitive</li><li>Use descriptive variable names to keep flows readable</li><li>Get Value is especially useful for accessing values set in a different branch of the flow</li></ul>",
8
- "ITE": "<h1>If-Then-Else</h1><p>The <b>If-Then-Else</b> node evaluates a boolean condition expression and routes the flow to one of two outputs.</p><h2>Ports</h2><ul><li><b>In</b> (input) trigger that starts the evaluation</li><li><b>Then</b> (output) activated when the condition is <b>true</b></li><li><b>Else</b> (output) activated when the condition is <b>false</b></li></ul><h2>Behavior</h2><p>When the input fires, the node evaluates the configured condition expression against the current flow context. If the expression resolves to a truthy value, the <b>Then</b> output is activated. Otherwise, the <b>Else</b> output is activated. Exactly one output fires per evaluation.</p><h2>Configuration</h2><p>Set the condition expression in the node's data properties. The expression is evaluated in the flow context, giving it access to any variables set by upstream Set Value nodes.</p><h2>Tips</h2><ul><li>Chain multiple If-Then-Else nodes for complex branching logic</li><li>Connect the <b>Else</b> output to another If-Then-Else to build else-if chains</li><li>Use descriptive condition expressions to keep the flow self-documenting</li></ul>",
9
- "LOG": "<h1>Log Values</h1><p>The <b>Log Values</b> node writes incoming data to the console or log output for debugging purposes.</p><h2>Ports</h2><ul><li><b>Values</b> (input, multi) accepts one or more connections carrying values to log</li><li><b>Pass</b> (output) passes the last received value through unchanged</li></ul><h2>Properties</h2><ul><li><b>LogLevel</b> the severity level for the log entry (e.g. <code>info</code>, <code>warn</code>, <code>error</code>, <code>trace</code>)</li><li><b>Format</b> an optional format string controlling how values are serialized</li></ul><h2>Behavior</h2><p>When data arrives at any input connection, the node serializes the value and writes it to the configured log output at the specified log level. The data is then forwarded to the <b>Pass</b> output unchanged, so the Log Values node can be inserted inline without disrupting the flow.</p><h2>Tips</h2><ul><li>Use multiple input connections to aggregate log output from parallel branches</li><li>Set the log level to <code>trace</code> during development and <code>warn</code> in production flows</li><li>Insert between any two nodes for quick inline debugging</li></ul>",
10
- "NOTE": "<h1>Comment</h1><p>The <b>Comment</b> node is a floating annotation for documenting flow logic. It has no input or output ports and does not participate in data flow execution.</p><h2>Usage</h2><p>Drop a Comment node anywhere on the canvas to add context, explain design decisions, or leave notes for collaborators. The note text is stored in the node's <code>Data.NoteText</code> property and displayed directly in the node body.</p><h2>Properties</h2><ul><li><b>NoteText</b> the annotation content displayed in the node body</li></ul><h2>Tips</h2><ul><li>Use comments to explain complex branching logic or non-obvious configuration choices</li><li>Comment nodes can be freely repositioned without affecting connections</li><li>Group related comments near the nodes they describe</li></ul>",
11
- "PREV": "<h1>Data Preview</h1><p>The <b>Data Preview</b> node displays a tabular summary of the data flowing through it. Use it as an inline debugger to inspect field names, types, and current values without interrupting the flow.</p><h2>Ports</h2><ul><li><b>Data</b> (input) the data object to inspect</li><li><b>Pass</b> (output) passes the data through unchanged</li></ul><h2>Behavior</h2><p>The preview renders a compact table inside the node body showing each field's name, inferred data type, and current value. The node is pass-through: data enters on the left and exits on the right without modification.</p><h2>Tips</h2><ul><li>Insert a Data Preview between two nodes to inspect intermediate state</li><li>The preview updates whenever new data arrives at the input port</li><li>Useful during development for verifying data transformations</li></ul>",
12
- "SET": "<h1>Set Value</h1><p>The <b>Set Value</b> node assigns a value to a named variable in the flow context.</p><h2>Ports</h2><ul><li><b>In</b> (input) trigger to perform the assignment</li><li><b>Out</b> (output) fires after the value has been set</li></ul><h2>Properties</h2><ul><li><b>Variable Name</b> the key under which the value will be stored</li><li><b>Value Expression</b> the expression to evaluate and assign</li></ul><h2>Behavior</h2><p>When triggered, the node evaluates the <b>Value Expression</b> and stores the result under the configured <b>Variable Name</b> in the flow context. Downstream nodes can read this value using a <b>Get Value</b> node with the same variable name.</p><h2>Configuration</h2><p>Open the properties panel to configure the variable name and value expression using the built-in form editor.</p><h2>Tips</h2><ul><li>Variable names are case-sensitive use consistent naming conventions</li><li>Value expressions have access to the current flow context</li><li>Use Set Value at the beginning of a flow to initialize default variables</li></ul>",
13
- "SPKL": "<h1>Sparkline</h1><p>The <b>Sparkline</b> node renders a live sparkline chart visualizing numeric throughput data directly in the node body.</p><h2>Ports</h2><ul><li><b>Values</b> (input) a numeric array or stream of values to plot</li><li><b>Stats</b> (output) emits computed statistics (min, max, mean) for the data set</li></ul><h2>Behavior</h2><p>The node draws a compact line chart inside the node body using a canvas renderer. As new numeric data arrives at the input, the chart updates to reflect the latest values. The filled area under the line and an endpoint dot provide visual emphasis on the current value.</p><h2>Appearance</h2><p>The chart uses the node's theme color for the line and fill area. The last data point is highlighted with a dot. The sparkline scales automatically to fit the available body area.</p><h2>Tips</h2><ul><li>Connect to any node that produces a numeric array for instant visualization</li><li>Use alongside a Data Preview node for combined visual and tabular inspection</li><li>The Stats output is useful for feeding threshold values into an If-Then-Else node</li></ul>",
14
- "STAT": "<h1>Status Monitor</h1><p>The <b>Status Monitor</b> node monitors the health status of upstream services and reports availability.</p><h2>Ports</h2><ul><li><b>Check</b> (input, multi) accepts connections from one or more services to monitor</li><li><b>Healthy</b> (output) fires when all monitored services report healthy</li><li><b>Degraded</b> (output) fires when one or more services report degraded status</li></ul><h2>Behavior</h2><p>The node body displays a visual health grid showing the status of each monitored service with colored indicators. Green indicates a healthy service; yellow indicates degraded performance. When all services are healthy, the <b>Healthy</b> output is activated. If any service reports degraded status, the <b>Degraded</b> output fires instead.</p><h2>Appearance</h2><p>The node body renders SVG status circles labeled with service names (e.g. API, DB, Cache, Queue). Port labels appear on hover for a cleaner default appearance.</p><h2>Tips</h2><ul><li>Connect multiple services to the <b>Check</b> input to build a comprehensive health dashboard</li><li>Route the <b>Degraded</b> output to notification or alerting nodes</li><li>Combine with an Each node to check a dynamic list of service endpoints</li></ul>",
15
- "SW": "<h1>Switch</h1><p>The <b>Switch</b> node routes execution to one of multiple outputs based on a matching value, similar to a switch/case statement in programming.</p><h2>Ports</h2><ul><li><b>In</b> (input) the value to match against cases</li><li><b>Case A</b> (output) fires when the input matches case A</li><li><b>Case B</b> (output) fires when the input matches case B</li><li><b>Default</b> (output) fires when the input does not match any defined case</li></ul><h2>Behavior</h2><p>When a value arrives at the input, the node compares it against each configured case. The first matching case's output is activated. If no case matches, the <b>Default</b> output fires. Only one output is activated per evaluation.</p><h2>Configuration</h2><p>Define case match values in the node's data properties. Each case corresponds to one of the named outputs.</p><h2>Tips</h2><ul><li>Add more output ports by extending the card definition for additional cases</li><li>Use the <b>Default</b> output as a catch-all for unexpected values</li><li>Chain a Switch after an If-Then-Else for multi-level routing logic</li><li>Case matching is based on strict equality</li></ul>"
4
+ "EACH": "<h1>Each (Loop Iterator)</h1><p>The <b>Each</b> node iterates over a collection, executing connected downstream nodes once for each item. When iteration completes, the <b>Done</b> output fires.</p><h2>Ports</h2><ul><li><b>Collection</b> (input) -- an array or iterable to loop over</li><li><b>Item</b> (output) -- fires once per element with the current item</li><li><b>Done</b> (output) -- fires after all items have been processed</li></ul><h2>Behavior</h2><p>When a collection arrives at the input port, the Each node processes items sequentially. For every element in the collection, the <b>Item</b> output is activated with the current element as the payload. After the final element is processed, the <b>Done</b> output fires to signal completion.</p><h2>Tips</h2><ul><li>Connect <b>Item</b> to a processing chain and <b>Done</b> to continuation logic</li><li>Nested loops are supported by chaining multiple Each nodes</li><li>Empty collections skip directly to the <b>Done</b> output</li></ul>",
5
+ "FREAD": "<h1>File Read</h1><p>The <b>File Read</b> node reads the contents of a file from the filesystem and outputs the data.</p><h2>Ports</h2><ul><li><b>Path</b> (input) -- the filesystem path to read</li><li><b>Data</b> (output) -- the file contents on success</li><li><b>Error</b> (output) -- fires if the read operation fails</li></ul><h2>Properties</h2><ul><li><b>FilePath</b> -- the path to the file to read</li><li><b>Encoding</b> -- character encoding for text files (e.g. <code>utf8</code>, <code>ascii</code>)</li></ul><h2>Behavior</h2><p>When triggered, the node reads the file at the configured path. On success, the raw file contents are emitted from the <b>Data</b> output. If the file does not exist or cannot be read, the <b>Error</b> output fires with a descriptive error message.</p><h2>Tips</h2><ul><li>Use a Get Value node upstream to dynamically set the file path</li><li>Pair with a Data Preview node to inspect the file contents</li><li>Connect the <b>Error</b> output to logging or notification nodes for robust error handling</li></ul>",
6
+ "FWRITE": "<h1>File Write</h1><p>The <b>File Write</b> node writes data to a file on the filesystem.</p><h2>Ports</h2><ul><li><b>Path</b> (input) -- the destination filesystem path</li><li><b>Data</b> (input) -- the content to write</li><li><b>Done</b> (output) -- fires after a successful write</li><li><b>Error</b> (output) -- fires if the write operation fails</li></ul><h2>Behavior</h2><p>When both inputs are satisfied, the node writes the provided data to the specified file path. On success the <b>Done</b> output fires. If the write fails (for example due to permissions or a missing directory), the <b>Error</b> output fires with a descriptive error message.</p><h2>Properties Panel</h2><p>The properties panel shows a View-based info panel with details about the configured file path and write options.</p><h2>Tips</h2><ul><li>Directories in the path are not created automatically -- ensure they exist before writing</li><li>Combine with a Set Value node to format data before writing</li><li>Connect the <b>Error</b> output to a Log Values node to capture write failures</li></ul>",
7
+ "GET": "<h1>Get Value</h1><p>The <b>Get Value</b> node retrieves a named variable from the flow context and emits its current value.</p><h2>Ports</h2><ul><li><b>In</b> (input) -- trigger to read the value</li><li><b>Value</b> (output) -- the retrieved value</li></ul><h2>Behavior</h2><p>When triggered, the node looks up a named key in the flow context and emits the stored value from the <b>Value</b> output. If the key does not exist, the output value is <code>undefined</code>.</p><h2>Usage</h2><p>Pair with a <b>Set Value</b> node to establish a read/write variable pattern. The Set Value node stores a value under a named key; the Get Value node retrieves it downstream.</p><h2>Tips</h2><ul><li>Variable names are case-sensitive</li><li>Use descriptive variable names to keep flows readable</li><li>Get Value is especially useful for accessing values set in a different branch of the flow</li></ul>",
8
+ "ITE": "<h1>If-Then-Else</h1><p>The <b>If-Then-Else</b> node evaluates a boolean condition expression and routes the flow to one of two outputs.</p><h2>Ports</h2><ul><li><b>In</b> (input) -- trigger that starts the evaluation</li><li><b>Then</b> (output) -- activated when the condition is <b>true</b></li><li><b>Else</b> (output) -- activated when the condition is <b>false</b></li></ul><h2>Behavior</h2><p>When the input fires, the node evaluates the configured condition expression against the current flow context. If the expression resolves to a truthy value, the <b>Then</b> output is activated. Otherwise, the <b>Else</b> output is activated. Exactly one output fires per evaluation.</p><h2>Configuration</h2><p>Set the condition expression in the node's data properties. The expression is evaluated in the flow context, giving it access to any variables set by upstream Set Value nodes.</p><h2>Tips</h2><ul><li>Chain multiple If-Then-Else nodes for complex branching logic</li><li>Connect the <b>Else</b> output to another If-Then-Else to build else-if chains</li><li>Use descriptive condition expressions to keep the flow self-documenting</li></ul>",
9
+ "LOG": "<h1>Log Values</h1><p>The <b>Log Values</b> node writes incoming data to the console or log output for debugging purposes.</p><h2>Ports</h2><ul><li><b>Values</b> (input, multi) -- accepts one or more connections carrying values to log</li><li><b>Pass</b> (output) -- passes the last received value through unchanged</li></ul><h2>Properties</h2><ul><li><b>LogLevel</b> -- the severity level for the log entry (e.g. <code>info</code>, <code>warn</code>, <code>error</code>, <code>trace</code>)</li><li><b>Format</b> -- an optional format string controlling how values are serialized</li></ul><h2>Behavior</h2><p>When data arrives at any input connection, the node serializes the value and writes it to the configured log output at the specified log level. The data is then forwarded to the <b>Pass</b> output unchanged, so the Log Values node can be inserted inline without disrupting the flow.</p><h2>Tips</h2><ul><li>Use multiple input connections to aggregate log output from parallel branches</li><li>Set the log level to <code>trace</code> during development and <code>warn</code> in production flows</li><li>Insert between any two nodes for quick inline debugging</li></ul>",
10
+ "NOTE": "<h1>Comment</h1><p>The <b>Comment</b> node is a floating annotation for documenting flow logic. It has no input or output ports and does not participate in data flow execution.</p><h2>Usage</h2><p>Drop a Comment node anywhere on the canvas to add context, explain design decisions, or leave notes for collaborators. The note text is stored in the node's <code>Data.NoteText</code> property and displayed directly in the node body.</p><h2>Properties</h2><ul><li><b>NoteText</b> -- the annotation content displayed in the node body</li></ul><h2>Tips</h2><ul><li>Use comments to explain complex branching logic or non-obvious configuration choices</li><li>Comment nodes can be freely repositioned without affecting connections</li><li>Group related comments near the nodes they describe</li></ul>",
11
+ "PREV": "<h1>Data Preview</h1><p>The <b>Data Preview</b> node displays a tabular summary of the data flowing through it. Use it as an inline debugger to inspect field names, types, and current values without interrupting the flow.</p><h2>Ports</h2><ul><li><b>Data</b> (input) -- the data object to inspect</li><li><b>Pass</b> (output) -- passes the data through unchanged</li></ul><h2>Behavior</h2><p>The preview renders a compact table inside the node body showing each field's name, inferred data type, and current value. The node is pass-through: data enters on the left and exits on the right without modification.</p><h2>Tips</h2><ul><li>Insert a Data Preview between two nodes to inspect intermediate state</li><li>The preview updates whenever new data arrives at the input port</li><li>Useful during development for verifying data transformations</li></ul>",
12
+ "SET": "<h1>Set Value</h1><p>The <b>Set Value</b> node assigns a value to a named variable in the flow context.</p><h2>Ports</h2><ul><li><b>In</b> (input) -- trigger to perform the assignment</li><li><b>Out</b> (output) -- fires after the value has been set</li></ul><h2>Properties</h2><ul><li><b>Variable Name</b> -- the key under which the value will be stored</li><li><b>Value Expression</b> -- the expression to evaluate and assign</li></ul><h2>Behavior</h2><p>When triggered, the node evaluates the <b>Value Expression</b> and stores the result under the configured <b>Variable Name</b> in the flow context. Downstream nodes can read this value using a <b>Get Value</b> node with the same variable name.</p><h2>Configuration</h2><p>Open the properties panel to configure the variable name and value expression using the built-in form editor.</p><h2>Tips</h2><ul><li>Variable names are case-sensitive -- use consistent naming conventions</li><li>Value expressions have access to the current flow context</li><li>Use Set Value at the beginning of a flow to initialize default variables</li></ul>",
13
+ "SPKL": "<h1>Sparkline</h1><p>The <b>Sparkline</b> node renders a live sparkline chart visualizing numeric throughput data directly in the node body.</p><h2>Ports</h2><ul><li><b>Values</b> (input) -- a numeric array or stream of values to plot</li><li><b>Stats</b> (output) -- emits computed statistics (min, max, mean) for the data set</li></ul><h2>Behavior</h2><p>The node draws a compact line chart inside the node body using a canvas renderer. As new numeric data arrives at the input, the chart updates to reflect the latest values. The filled area under the line and an endpoint dot provide visual emphasis on the current value.</p><h2>Appearance</h2><p>The chart uses the node's theme color for the line and fill area. The last data point is highlighted with a dot. The sparkline scales automatically to fit the available body area.</p><h2>Tips</h2><ul><li>Connect to any node that produces a numeric array for instant visualization</li><li>Use alongside a Data Preview node for combined visual and tabular inspection</li><li>The Stats output is useful for feeding threshold values into an If-Then-Else node</li></ul>",
14
+ "STAT": "<h1>Status Monitor</h1><p>The <b>Status Monitor</b> node monitors the health status of upstream services and reports availability.</p><h2>Ports</h2><ul><li><b>Check</b> (input, multi) -- accepts connections from one or more services to monitor</li><li><b>Healthy</b> (output) -- fires when all monitored services report healthy</li><li><b>Degraded</b> (output) -- fires when one or more services report degraded status</li></ul><h2>Behavior</h2><p>The node body displays a visual health grid showing the status of each monitored service with colored indicators. Green indicates a healthy service; yellow indicates degraded performance. When all services are healthy, the <b>Healthy</b> output is activated. If any service reports degraded status, the <b>Degraded</b> output fires instead.</p><h2>Appearance</h2><p>The node body renders SVG status circles labeled with service names (e.g. API, DB, Cache, Queue). Port labels appear on hover for a cleaner default appearance.</p><h2>Tips</h2><ul><li>Connect multiple services to the <b>Check</b> input to build a comprehensive health dashboard</li><li>Route the <b>Degraded</b> output to notification or alerting nodes</li><li>Combine with an Each node to check a dynamic list of service endpoints</li></ul>",
15
+ "SW": "<h1>Switch</h1><p>The <b>Switch</b> node routes execution to one of multiple outputs based on a matching value, similar to a switch/case statement in programming.</p><h2>Ports</h2><ul><li><b>In</b> (input) -- the value to match against cases</li><li><b>Case A</b> (output) -- fires when the input matches case A</li><li><b>Case B</b> (output) -- fires when the input matches case B</li><li><b>Default</b> (output) -- fires when the input does not match any defined case</li></ul><h2>Behavior</h2><p>When a value arrives at the input, the node compares it against each configured case. The first matching case's output is activated. If no case matches, the <b>Default</b> output fires. Only one output is activated per evaluation.</p><h2>Configuration</h2><p>Define case match values in the node's data properties. Each case corresponds to one of the named outputs.</p><h2>Tips</h2><ul><li>Add more output ports by extending the card definition for additional cases</li><li>Use the <b>Default</b> output as a catch-all for unexpected values</li><li>Chain a Switch after an If-Then-Else for multi-level routing logic</li><li>Case matching is based on strict equality</li></ul>"
16
16
  };
@@ -33,7 +33,7 @@ class FlowCardDataPreview extends libPictFlowCard
33
33
  BodyContent:
34
34
  {
35
35
  ContentType: 'html',
36
- Template: '<table style="width:100%;border-collapse:collapse;font-size:9px;color:#2c3e50"><tr style="background:#d6eaf8"><td style="padding:3px 5px;font-weight:600">Field</td><td style="padding:3px 5px;font-weight:600">Type</td><td style="padding:3px 5px;font-weight:600">Value</td></tr><tr><td style="padding:2px 5px;border-top:1px solid #d5dbdb">name</td><td style="padding:2px 5px;border-top:1px solid #d5dbdb;color:#8e44ad">str</td><td style="padding:2px 5px;border-top:1px solid #d5dbdb;color:#7f8c8d">&#x22;config&#x22;</td></tr><tr><td style="padding:2px 5px;border-top:1px solid #d5dbdb">count</td><td style="padding:2px 5px;border-top:1px solid #d5dbdb;color:#8e44ad">num</td><td style="padding:2px 5px;border-top:1px solid #d5dbdb;color:#7f8c8d">42</td></tr><tr><td style="padding:2px 5px;border-top:1px solid #d5dbdb">active</td><td style="padding:2px 5px;border-top:1px solid #d5dbdb;color:#8e44ad">bool</td><td style="padding:2px 5px;border-top:1px solid #d5dbdb;color:#27ae60">true</td></tr></table>'
36
+ Template: '<table style="width:100%;border-collapse:collapse;font-size:9px;color:#2c3e50"><tr style="background:#d6eaf8"><td style="padding:3px 5px;font-weight:600">Field</td><td style="padding:3px 5px;font-weight:600">Type</td><td style="padding:3px 5px;font-weight:600">Value</td></tr><tr><td style="padding:2px 5px;border-top:1px solid #d5dbdb">name</td><td style="padding:2px 5px;border-top:1px solid #d5dbdb;color:#8e44ad">str</td><td style="padding:2px 5px;border-top:1px solid #d5dbdb;color:#7f8c8d">&#x22;config&#x22;</td></tr><tr><td style="padding:2px 5px;border-top:1px solid #d5dbdb">count</td><td style="padding:2px 5px;border-top:1px solid #d5dbdb;color:#8e44ad">num</td><td style="padding:2px 5px;border-top:1px solid #d5dbdb;color:#7f8c8d">42</td></tr><tr><td style="padding:2px 5px;border-top:1px solid #d5dbdb">active</td><td style="padding:2px 5px;border-top:1px solid #d5dbdb;color:#8e44ad">bool</td><td style="padding:2px 5px;border-top:1px solid #d5dbdb;color:var(--theme-color-status-success, #27ae60)">true</td></tr></table>'
37
37
  }
38
38
  },
39
39
  pOptions),
@@ -0,0 +1,410 @@
1
+ /**
2
+ * sample-flows.js
3
+ *
4
+ * Showcase graphs for trying out the seven layout algorithms in
5
+ * pict-section-flow. Each sample is a small flow definition with
6
+ * `Name`, `Description`, `Recommended` (layout that shines), and
7
+ * `Flow` (a `_FlowData`-shaped object).
8
+ *
9
+ * Use the dropdown above the flow diagram to load a sample, then
10
+ * open the Algorithm popup to compare layouts. The descriptions
11
+ * call out which layouts shine and which struggle on each shape.
12
+ *
13
+ * All nodes use the 'default' card type with simple In/Out ports —
14
+ * the focus is on graph topology, not on the cards themselves.
15
+ */
16
+
17
+ // Ultravisor-flavored category palette — same families as
18
+ // Ultravisor-CardConfigGenerator's _CategoryColors so the per-node
19
+ // hint/border colors here read the same way they do in real flows.
20
+ const _CATEGORY_COLORS =
21
+ {
22
+ 'core': { TitleBarColor: '#ab47bc', BodyStyle: { fill: '#f3e5f5', stroke: '#ab47bc' } },
23
+ 'flow': { TitleBarColor: '#78909c', BodyStyle: { fill: '#eceff1', stroke: '#78909c' } },
24
+ 'data': { TitleBarColor: '#ff9800', BodyStyle: { fill: '#fff3e0', stroke: '#ff9800' } },
25
+ 'file-io': { TitleBarColor: '#42a5f5', BodyStyle: { fill: '#eaf2f8', stroke: '#42a5f5' } },
26
+ 'rest': { TitleBarColor: '#29b6f6', BodyStyle: { fill: '#e1f5fe', stroke: '#29b6f6' } },
27
+ 'meadow': { TitleBarColor: '#66bb6a', BodyStyle: { fill: '#e8f5e9', stroke: '#66bb6a' } },
28
+ 'pipeline': { TitleBarColor: '#ec407a', BodyStyle: { fill: '#fce4ec', stroke: '#ec407a' } },
29
+ 'llm': { TitleBarColor: '#26a69a', BodyStyle: { fill: '#e0f7fa', stroke: '#26a69a' } },
30
+ 'ext': { TitleBarColor: '#9c6afe', BodyStyle: { fill: '#ede9fe', stroke: '#9c6afe' } }
31
+ };
32
+
33
+ function _node(pHash, pTitle, pX, pY, pCategory)
34
+ {
35
+ let tmpNode =
36
+ {
37
+ Hash: pHash,
38
+ Type: 'default',
39
+ X: pX,
40
+ Y: pY,
41
+ Width: 140,
42
+ Height: 70,
43
+ Title: pTitle,
44
+ Ports:
45
+ [
46
+ { Hash: `${pHash}-in`, Direction: 'input', Side: 'left', Label: 'In' },
47
+ { Hash: `${pHash}-out`, Direction: 'output', Side: 'right', Label: 'Out' }
48
+ ],
49
+ Data: {}
50
+ };
51
+ if (pCategory && _CATEGORY_COLORS[pCategory])
52
+ {
53
+ let tmpColors = _CATEGORY_COLORS[pCategory];
54
+ tmpNode.TitleBarColor = tmpColors.TitleBarColor;
55
+ tmpNode.BodyStyle = tmpColors.BodyStyle;
56
+ }
57
+ return tmpNode;
58
+ }
59
+
60
+ function _edge(pSourceHash, pTargetHash, pSuffix)
61
+ {
62
+ let tmpHash = `c-${pSourceHash}-${pTargetHash}${pSuffix ? `-${pSuffix}` : ''}`;
63
+ return {
64
+ Hash: tmpHash,
65
+ SourceNodeHash: pSourceHash,
66
+ SourcePortHash: `${pSourceHash}-out`,
67
+ TargetNodeHash: pTargetHash,
68
+ TargetPortHash: `${pTargetHash}-in`,
69
+ Data: {}
70
+ };
71
+ }
72
+
73
+ function _emptyViewState()
74
+ {
75
+ return { PanX: 0, PanY: 0, Zoom: 1, SelectedNodeHash: null, SelectedConnectionHash: null, SelectedTetherHash: null };
76
+ }
77
+
78
+ function _flow(pNodes, pConnections, pAlgorithm, pParameters, pAutoApply)
79
+ {
80
+ return {
81
+ Nodes: pNodes,
82
+ Connections: pConnections || [],
83
+ OpenPanels: [],
84
+ SavedLayouts: [],
85
+ ViewState: _emptyViewState(),
86
+ LayoutAlgorithm: pAlgorithm || 'Custom',
87
+ LayoutParameters: pParameters || {},
88
+ LayoutAutoApply: !!pAutoApply
89
+ };
90
+ }
91
+
92
+ // ── 1. Linear Chain ────────────────────────────────────────────────────
93
+ // A → B → C → D → E → F
94
+ function _linearChain()
95
+ {
96
+ let tmpCount = 6;
97
+ let tmpNodes = [];
98
+ let tmpEdges = [];
99
+ for (let i = 0; i < tmpCount; i++)
100
+ {
101
+ let tmpHash = `lc-${String.fromCharCode(65 + i)}`;
102
+ tmpNodes.push(_node(tmpHash, String.fromCharCode(65 + i), 100, 100 + i * 110));
103
+ if (i > 0)
104
+ {
105
+ let tmpPrev = `lc-${String.fromCharCode(65 + i - 1)}`;
106
+ tmpEdges.push(_edge(tmpPrev, tmpHash));
107
+ }
108
+ }
109
+ return _flow(tmpNodes, tmpEdges);
110
+ }
111
+
112
+ // ── 2. Binary Tree (depth 3) ───────────────────────────────────────────
113
+ // Root → 2 children → 4 grandchildren = 7 nodes
114
+ function _binaryTree()
115
+ {
116
+ let tmpNodes = [];
117
+ let tmpEdges = [];
118
+ let tmpHashes = ['root', 'l', 'r', 'll', 'lr', 'rl', 'rr'];
119
+ let tmpLabels = ['Root', 'L', 'R', 'LL', 'LR', 'RL', 'RR'];
120
+ let tmpPositions = [
121
+ [400, 100], // root
122
+ [250, 240], [550, 240], // l, r
123
+ [150, 380], [350, 380], [450, 380], [650, 380] // ll lr rl rr
124
+ ];
125
+ for (let i = 0; i < tmpHashes.length; i++)
126
+ {
127
+ tmpNodes.push(_node(`bt-${tmpHashes[i]}`, tmpLabels[i], tmpPositions[i][0], tmpPositions[i][1]));
128
+ }
129
+ tmpEdges.push(_edge('bt-root', 'bt-l'));
130
+ tmpEdges.push(_edge('bt-root', 'bt-r'));
131
+ tmpEdges.push(_edge('bt-l', 'bt-ll'));
132
+ tmpEdges.push(_edge('bt-l', 'bt-lr'));
133
+ tmpEdges.push(_edge('bt-r', 'bt-rl'));
134
+ tmpEdges.push(_edge('bt-r', 'bt-rr'));
135
+ return _flow(tmpNodes, tmpEdges);
136
+ }
137
+
138
+ // ── 3. Star Hub (1 hub + 8 spokes) ─────────────────────────────────────
139
+ // Each spoke gets a distinct Ultravisor-style category color so the
140
+ // hint beziers (which are colored by the *other end's* identity) fan
141
+ // out in 8 different colors when you hover the hub's "Out" badge.
142
+ function _starHub()
143
+ {
144
+ let tmpNodes = [];
145
+ let tmpEdges = [];
146
+ let tmpSpokeKinds =
147
+ [
148
+ { key: 'rest', label: 'REST API' },
149
+ { key: 'meadow', label: 'Meadow' },
150
+ { key: 'data', label: 'Transform' },
151
+ { key: 'file-io', label: 'File I/O' },
152
+ { key: 'pipeline', label: 'Pipeline' },
153
+ { key: 'llm', label: 'LLM' },
154
+ { key: 'ext', label: 'Extension' },
155
+ { key: 'flow', label: 'Control' }
156
+ ];
157
+ tmpNodes.push(_node('star-hub', 'Hub', 400, 350, 'core'));
158
+ for (let i = 0; i < tmpSpokeKinds.length; i++)
159
+ {
160
+ let tmpAngle = (i / tmpSpokeKinds.length) * 2 * Math.PI;
161
+ let tmpX = 400 + Math.round(Math.cos(tmpAngle) * 240);
162
+ let tmpY = 350 + Math.round(Math.sin(tmpAngle) * 240);
163
+ let tmpHash = `star-s${i}`;
164
+ tmpNodes.push(_node(tmpHash, tmpSpokeKinds[i].label, tmpX, tmpY, tmpSpokeKinds[i].key));
165
+ tmpEdges.push(_edge('star-hub', tmpHash));
166
+ }
167
+ return _flow(tmpNodes, tmpEdges);
168
+ }
169
+
170
+ // ── 4. Diamond Lattice ─────────────────────────────────────────────────
171
+ // Start → {A,B,C} → {D,E,F} (cross-edges) → Merge → End. Nine nodes.
172
+ function _diamondLattice()
173
+ {
174
+ let tmpNodes =
175
+ [
176
+ _node('dl-start', 'Start', 100, 200),
177
+ _node('dl-a', 'A', 300, 100),
178
+ _node('dl-b', 'B', 300, 250),
179
+ _node('dl-c', 'C', 300, 400),
180
+ _node('dl-d', 'D', 550, 100),
181
+ _node('dl-e', 'E', 550, 250),
182
+ _node('dl-f', 'F', 550, 400),
183
+ _node('dl-merge', 'Merge', 800, 250),
184
+ _node('dl-end', 'End', 1050, 250)
185
+ ];
186
+ let tmpEdges =
187
+ [
188
+ _edge('dl-start', 'dl-a'),
189
+ _edge('dl-start', 'dl-b'),
190
+ _edge('dl-start', 'dl-c'),
191
+ _edge('dl-a', 'dl-d'),
192
+ _edge('dl-a', 'dl-e'), // cross
193
+ _edge('dl-b', 'dl-e'),
194
+ _edge('dl-c', 'dl-e'), // cross
195
+ _edge('dl-c', 'dl-f'),
196
+ _edge('dl-d', 'dl-merge'),
197
+ _edge('dl-e', 'dl-merge'),
198
+ _edge('dl-f', 'dl-merge'),
199
+ _edge('dl-merge', 'dl-end')
200
+ ];
201
+ return _flow(tmpNodes, tmpEdges);
202
+ }
203
+
204
+ // ── 5. Disconnected Components (3 chains × 4 nodes) ────────────────────
205
+ function _disconnectedComponents()
206
+ {
207
+ let tmpNodes = [];
208
+ let tmpEdges = [];
209
+ let tmpClusters = ['α', 'β', 'γ'];
210
+ for (let c = 0; c < tmpClusters.length; c++)
211
+ {
212
+ for (let i = 0; i < 4; i++)
213
+ {
214
+ let tmpHash = `dc-${tmpClusters[c]}-${i}`;
215
+ tmpNodes.push(_node(tmpHash, `${tmpClusters[c]}${i}`, 150 + c * 350, 100 + i * 110));
216
+ if (i > 0)
217
+ {
218
+ let tmpPrev = `dc-${tmpClusters[c]}-${i - 1}`;
219
+ tmpEdges.push(_edge(tmpPrev, tmpHash));
220
+ }
221
+ }
222
+ }
223
+ return _flow(tmpNodes, tmpEdges);
224
+ }
225
+
226
+ // ── 6. Dense Cluster (7 nodes, ~15 edges, near-complete) ───────────────
227
+ function _denseCluster()
228
+ {
229
+ let tmpNodes = [];
230
+ let tmpEdges = [];
231
+ let tmpCount = 7;
232
+ for (let i = 0; i < tmpCount; i++)
233
+ {
234
+ let tmpAngle = (i / tmpCount) * 2 * Math.PI;
235
+ let tmpX = 400 + Math.round(Math.cos(tmpAngle) * 200);
236
+ let tmpY = 300 + Math.round(Math.sin(tmpAngle) * 200);
237
+ tmpNodes.push(_node(`dn-${i}`, `N${i}`, tmpX, tmpY));
238
+ }
239
+ // Connect each node to ~3 others (skip-1 and skip-2 patterns) — yields ~14 edges
240
+ for (let i = 0; i < tmpCount; i++)
241
+ {
242
+ tmpEdges.push(_edge(`dn-${i}`, `dn-${(i + 1) % tmpCount}`));
243
+ tmpEdges.push(_edge(`dn-${i}`, `dn-${(i + 2) % tmpCount}`));
244
+ }
245
+ return _flow(tmpNodes, tmpEdges);
246
+ }
247
+
248
+ // ── 7. Cyclic Network (8 nodes, ring + chord) ──────────────────────────
249
+ function _cyclicNetwork()
250
+ {
251
+ let tmpNodes = [];
252
+ let tmpEdges = [];
253
+ let tmpCount = 8;
254
+ for (let i = 0; i < tmpCount; i++)
255
+ {
256
+ let tmpAngle = (i / tmpCount) * 2 * Math.PI;
257
+ let tmpX = 400 + Math.round(Math.cos(tmpAngle) * 220);
258
+ let tmpY = 300 + Math.round(Math.sin(tmpAngle) * 220);
259
+ tmpNodes.push(_node(`cy-${i}`, `Z${i}`, tmpX, tmpY));
260
+ }
261
+ // Ring of forward edges 0→1→2→…→7→0 (back-edge creates the cycle)
262
+ for (let i = 0; i < tmpCount; i++)
263
+ {
264
+ tmpEdges.push(_edge(`cy-${i}`, `cy-${(i + 1) % tmpCount}`));
265
+ }
266
+ // One chord across the ring
267
+ tmpEdges.push(_edge('cy-0', 'cy-4'));
268
+ return _flow(tmpNodes, tmpEdges);
269
+ }
270
+
271
+ // ── 8. Mesh 4×4 (16 nodes, 4-neighbor edges) ───────────────────────────
272
+ function _mesh4x4()
273
+ {
274
+ let tmpNodes = [];
275
+ let tmpEdges = [];
276
+ let tmpRows = 4, tmpCols = 4;
277
+ for (let r = 0; r < tmpRows; r++)
278
+ {
279
+ for (let c = 0; c < tmpCols; c++)
280
+ {
281
+ let tmpHash = `mesh-${r}-${c}`;
282
+ tmpNodes.push(_node(tmpHash, `(${r},${c})`, 150 + c * 180, 100 + r * 130));
283
+ }
284
+ }
285
+ for (let r = 0; r < tmpRows; r++)
286
+ {
287
+ for (let c = 0; c < tmpCols; c++)
288
+ {
289
+ if (c < tmpCols - 1) tmpEdges.push(_edge(`mesh-${r}-${c}`, `mesh-${r}-${c + 1}`));
290
+ if (r < tmpRows - 1) tmpEdges.push(_edge(`mesh-${r}-${c}`, `mesh-${r + 1}-${c}`));
291
+ }
292
+ }
293
+ return _flow(tmpNodes, tmpEdges);
294
+ }
295
+
296
+ // ── 9. Floating Widgets (12 isolated nodes, no edges) ──────────────────
297
+ function _floatingWidgets()
298
+ {
299
+ let tmpNodes = [];
300
+ let tmpLabels = ['Chart', 'Table', 'KPI', 'Gauge', 'Sparkline', 'Heatmap', 'Pie', 'Bar', 'Map', 'Timeline', 'Note', 'Image'];
301
+ for (let i = 0; i < tmpLabels.length; i++)
302
+ {
303
+ let tmpRow = Math.floor(i / 4);
304
+ let tmpCol = i % 4;
305
+ tmpNodes.push(_node(`fw-${i}`, tmpLabels[i], 150 + tmpCol * 180, 100 + tmpRow * 130));
306
+ }
307
+ return _flow(tmpNodes, []);
308
+ }
309
+
310
+ // ── 10. Wide Fan-Out (1 root → 12 leaves) ──────────────────────────────
311
+ function _wideFanOut()
312
+ {
313
+ let tmpNodes = [];
314
+ let tmpEdges = [];
315
+ tmpNodes.push(_node('fan-root', 'Source', 100, 400));
316
+ for (let i = 0; i < 12; i++)
317
+ {
318
+ let tmpHash = `fan-leaf-${i}`;
319
+ tmpNodes.push(_node(tmpHash, `L${i}`, 400 + (i % 4) * 160, 100 + Math.floor(i / 4) * 130));
320
+ tmpEdges.push(_edge('fan-root', tmpHash));
321
+ }
322
+ return _flow(tmpNodes, tmpEdges);
323
+ }
324
+
325
+ const SAMPLE_FLOWS =
326
+ {
327
+ 'linear-chain':
328
+ {
329
+ Name: 'Linear Chain',
330
+ Description: 'A → B → C → D → E → F. Six nodes, single path. Layered (left-to-right) and Tabular (top-to-bottom) read like a story; Circular wastes a ring on what should be a line; ForcedFromCenter is overkill.',
331
+ Recommended: 'Layered',
332
+ Flow: _linearChain()
333
+ },
334
+ 'binary-tree':
335
+ {
336
+ Name: 'Binary Tree (depth 3)',
337
+ Description: 'Root branches into 2 children, each into 2 grandchildren. Layered shows the hierarchy clearly (depth-by-depth); Circular puts the root at center with leaves on outer ring; Grid loses the parent-child relationships entirely.',
338
+ Recommended: 'Layered',
339
+ Flow: _binaryTree()
340
+ },
341
+ 'star-hub':
342
+ {
343
+ Name: 'Star Hub (8 spokes)',
344
+ Description: 'One hub connected to 8 leaves. Circular shines (root at center, spokes evenly around); Layered crowds all 8 spokes in a single second column; ForcedFromCenter does an OK job; Grid ignores the topology completely.',
345
+ Recommended: 'Circular',
346
+ Flow: _starHub()
347
+ },
348
+ 'diamond-lattice':
349
+ {
350
+ Name: 'Diamond Lattice (DAG)',
351
+ Description: 'Start fans out to 3 paths through 6 middle nodes (with cross-edges) and merges at End. Layered is in its element — the parallel depth structure becomes obvious. Tabular flattens it; Circular loses direction.',
352
+ Recommended: 'Layered',
353
+ Flow: _diamondLattice()
354
+ },
355
+ 'disconnected-components':
356
+ {
357
+ Name: 'Disconnected Components',
358
+ Description: 'Three independent chains of 4 nodes each, no cross-edges. Grid and Columnar give each chain equal real estate. Layered piles the 3 roots in one column. ForcedFromCenter clusters them naturally but with no separation guarantee.',
359
+ Recommended: 'Columnar',
360
+ Flow: _disconnectedComponents()
361
+ },
362
+ 'dense-cluster':
363
+ {
364
+ Name: 'Dense Cluster (near-complete)',
365
+ Description: 'Seven nodes with ~14 edges (each node connects to its two nearest neighbors in both directions). ForcedFromCenter shines — spring forces find a clean radial layout. Layered tries to topo-sort it and produces a wide-and-shallow mess. Circular is also pretty good here.',
366
+ Recommended: 'ForcedFromCenter',
367
+ Flow: _denseCluster()
368
+ },
369
+ 'cyclic-network':
370
+ {
371
+ Name: 'Cyclic Network',
372
+ Description: 'Eight nodes in a ring plus one chord. The cycle defeats Kahn topological sort — Layered falls back to a "remaining nodes" pass (correct but ugly). Circular renders the ring cleanly. ForcedFromCenter finds a relaxed equilibrium.',
373
+ Recommended: 'Circular',
374
+ Flow: _cyclicNetwork()
375
+ },
376
+ 'mesh-4x4':
377
+ {
378
+ Name: 'Mesh 4×4',
379
+ Description: '16 nodes in a 4×4 grid topology with right/down neighbor edges. Grid is the obvious win (the layout matches the data). Columnar (4 cols, FillOrder=row) also nails it. Layered produces a long zig-zag through 7 layers.',
380
+ Recommended: 'Grid',
381
+ Flow: _mesh4x4()
382
+ },
383
+ 'floating-widgets':
384
+ {
385
+ Name: 'Floating Widgets (no edges)',
386
+ Description: '12 unconnected nodes — exactly the dashboard-builder shape. Grid, Columnar, and Tabular all produce clean deterministic arrangements. Layered, Circular, and ForcedFromCenter degrade gracefully (single layer / single ring / random spread).',
387
+ Recommended: 'Grid',
388
+ Flow: _floatingWidgets()
389
+ },
390
+ 'wide-fan-out':
391
+ {
392
+ Name: 'Wide Fan-Out (1 → 12)',
393
+ Description: 'One source node connects to 12 leaves. Circular places the source at center with leaves on a single outer ring — clean and balanced. Layered makes the second column 12 nodes tall. Grid spreads leaves and loses the source-to-leaf relationship.',
394
+ Recommended: 'Circular',
395
+ Flow: _wideFanOut()
396
+ }
397
+ };
398
+
399
+ module.exports =
400
+ {
401
+ SAMPLE_FLOWS: SAMPLE_FLOWS,
402
+ getSampleNames: function ()
403
+ {
404
+ return Object.keys(SAMPLE_FLOWS);
405
+ },
406
+ getSample: function (pKey)
407
+ {
408
+ return SAMPLE_FLOWS[pKey] || null;
409
+ }
410
+ };
@@ -18,7 +18,7 @@ const _ViewConfiguration =
18
18
  .flowexample-about-header {
19
19
  text-align: center;
20
20
  padding-bottom: 1.5em;
21
- border-bottom: 1px solid #eee;
21
+ border-bottom: 1px solid var(--theme-color-border-light, #eee);
22
22
  margin-bottom: 2em;
23
23
  }
24
24
  .flowexample-about-header h1 {
@@ -39,7 +39,7 @@ const _ViewConfiguration =
39
39
  font-size: 1.3em;
40
40
  }
41
41
  .flowexample-about p {
42
- color: #555;
42
+ color: var(--theme-color-text-secondary, #555);
43
43
  line-height: 1.7;
44
44
  }
45
45
  .flowexample-about-tech {
@@ -62,7 +62,7 @@ const _ViewConfiguration =
62
62
  }
63
63
  .flowexample-about-tech-item span {
64
64
  font-size: 0.85em;
65
- color: #666;
65
+ color: var(--theme-color-text-secondary, #666);
66
66
  }
67
67
  .flowexample-about-features {
68
68
  display: grid;
@@ -71,8 +71,8 @@ const _ViewConfiguration =
71
71
  margin-top: 1em;
72
72
  }
73
73
  .flowexample-about-feature {
74
- background: #fff;
75
- border: 1px solid #e0e0e0;
74
+ background: var(--theme-color-background-panel, #fff);
75
+ border: 1px solid var(--theme-color-border-default, #e0e0e0);
76
76
  border-radius: 6px;
77
77
  padding: 1.25em;
78
78
  }
@@ -18,7 +18,7 @@ const _ViewConfiguration =
18
18
  .flowexample-docs-header {
19
19
  text-align: center;
20
20
  padding-bottom: 1.5em;
21
- border-bottom: 1px solid #eee;
21
+ border-bottom: 1px solid var(--theme-color-border-light, #eee);
22
22
  margin-bottom: 2em;
23
23
  }
24
24
  .flowexample-docs-header h1 {
@@ -37,7 +37,7 @@ const _ViewConfiguration =
37
37
  font-weight: 400;
38
38
  color: #2c3e50;
39
39
  font-size: 1.3em;
40
- border-bottom: 1px solid #eee;
40
+ border-bottom: 1px solid var(--theme-color-border-light, #eee);
41
41
  padding-bottom: 0.35em;
42
42
  }
43
43
  .flowexample-docs h3 {
@@ -47,7 +47,7 @@ const _ViewConfiguration =
47
47
  font-size: 1.05em;
48
48
  }
49
49
  .flowexample-docs p {
50
- color: #555;
50
+ color: var(--theme-color-text-secondary, #555);
51
51
  line-height: 1.7;
52
52
  }
53
53
  .flowexample-docs code {
@@ -55,7 +55,7 @@ const _ViewConfiguration =
55
55
  padding: 0.15em 0.4em;
56
56
  border-radius: 3px;
57
57
  font-size: 0.9em;
58
- color: #e74c3c;
58
+ color: var(--theme-color-status-error, #e74c3c);
59
59
  }
60
60
  .flowexample-docs pre {
61
61
  background: #2c3e50;
@@ -72,7 +72,7 @@ const _ViewConfiguration =
72
72
  color: #ecf0f1;
73
73
  }
74
74
  .flowexample-docs ul {
75
- color: #555;
75
+ color: var(--theme-color-text-secondary, #555);
76
76
  line-height: 1.8;
77
77
  padding-left: 1.5em;
78
78
  }