@peter.prib/renderengine 0.0.0-stage → 0.2.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 (451) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +203 -2
  3. package/REFERENCE.md +2198 -0
  4. package/dist/renderengine-workspace.umd.js +46905 -0
  5. package/dist/renderengine.umd.js +42223 -0
  6. package/examples/archimate.html +66 -0
  7. package/examples/diagram-editor.html +51 -0
  8. package/package.json +65 -4
  9. package/src/BaseRenderer.js +57 -0
  10. package/src/CanvasRenderer.js +194 -0
  11. package/src/Mat4.js +111 -0
  12. package/src/OrbitCamera.js +57 -0
  13. package/src/RendererFactory.js +50 -0
  14. package/src/SVGRenderer.js +439 -0
  15. package/src/archimate.js +723 -0
  16. package/src/archimateArchiFormat.js +1693 -0
  17. package/src/archimateArchiTypes.js +72 -0
  18. package/src/archimateArchive.js +140 -0
  19. package/src/archimateCSV.js +127 -0
  20. package/src/archimateDrawio.js +182 -0
  21. package/src/archimateExchangeFormat.js +546 -0
  22. package/src/archimateRelationshipTable.js +93 -0
  23. package/src/archimateSpecializations.js +161 -0
  24. package/src/chartCatalog.js +589 -0
  25. package/src/charting/ArchimateDiagramEditor.js +1624 -0
  26. package/src/charting/ArchimateSpecializationSelector.js +134 -0
  27. package/src/charting/Axis.js +68 -0
  28. package/src/charting/CameraSeeder.js +30 -0
  29. package/src/charting/CatalogDialog.js +92 -0
  30. package/src/charting/Chart.js +37 -0
  31. package/src/charting/Chart3D.js +99 -0
  32. package/src/charting/ChartBox.js +80 -0
  33. package/src/charting/ChartData.js +27 -0
  34. package/src/charting/ChartRegistry.js +76 -0
  35. package/src/charting/CheckboxTreeSelector.js +304 -0
  36. package/src/charting/ColorField.js +107 -0
  37. package/src/charting/ColorPalette.js +88 -0
  38. package/src/charting/CommandHistory.js +176 -0
  39. package/src/charting/DataFilter.js +52 -0
  40. package/src/charting/Diagram.js +36 -0
  41. package/src/charting/Diagram3D.js +29 -0
  42. package/src/charting/DiagramClipboard.js +31 -0
  43. package/src/charting/DiagramEditor.js +3330 -0
  44. package/src/charting/DiagramEditorCommand.js +110 -0
  45. package/src/charting/DiagramEditorCommands.js +237 -0
  46. package/src/charting/DiagramEditorEdgeCommands.js +142 -0
  47. package/src/charting/DiagramEditorState.js +98 -0
  48. package/src/charting/DiagramRegistry.js +86 -0
  49. package/src/charting/DiagramTypeRegistry.js +326 -0
  50. package/src/charting/DiagramViewPropertiesDialog.js +46 -0
  51. package/src/charting/Edge.js +113 -0
  52. package/src/charting/ErrorBars.js +37 -0
  53. package/src/charting/FilterSystem.js +285 -0
  54. package/src/charting/FindReplaceDialog.js +139 -0
  55. package/src/charting/FormDialog.js +385 -0
  56. package/src/charting/Gauge.js +58 -0
  57. package/src/charting/Hierarchy.js +175 -0
  58. package/src/charting/HintPanel.js +86 -0
  59. package/src/charting/ImageSelector.js +148 -0
  60. package/src/charting/InteractionManager.js +725 -0
  61. package/src/charting/Legend.js +58 -0
  62. package/src/charting/MenuBar.js +62 -0
  63. package/src/charting/ModelFileFormat.js +115 -0
  64. package/src/charting/OrbitControls.js +77 -0
  65. package/src/charting/Palette.js +119 -0
  66. package/src/charting/PopupMenu.js +117 -0
  67. package/src/charting/PropertiesPanel.js +155 -0
  68. package/src/charting/PropertyListEditor.js +96 -0
  69. package/src/charting/PropertyLog.js +92 -0
  70. package/src/charting/SettingsCascade.js +93 -0
  71. package/src/charting/SettingsDialog.js +53 -0
  72. package/src/charting/SettingsManager.js +179 -0
  73. package/src/charting/SettingsViewPropertiesDialog.js +58 -0
  74. package/src/charting/ShapePaths.js +27 -0
  75. package/src/charting/Statistics.js +134 -0
  76. package/src/charting/TemplateCatalog.js +59 -0
  77. package/src/charting/TemplateLibrary.js +103 -0
  78. package/src/charting/TextStyle.js +168 -0
  79. package/src/charting/ViewFit.js +55 -0
  80. package/src/charting/ViewMenu.js +70 -0
  81. package/src/charting/ViewPropertiesDialog.js +77 -0
  82. package/src/charting/ViewTabStrip.js +81 -0
  83. package/src/charting/archimate/ArchiFileFormat.js +32 -0
  84. package/src/charting/archimate/ArchimateCanvasEditor.js +815 -0
  85. package/src/charting/archimate/ArchimateCsvFileFormat.js +35 -0
  86. package/src/charting/archimate/ArchimateEdge.js +137 -0
  87. package/src/charting/archimate/ArchimateElementTemplate.js +195 -0
  88. package/src/charting/archimate/ArchimatePalette.js +102 -0
  89. package/src/charting/archimate/CsvImportDialog.js +105 -0
  90. package/src/charting/archimate/CustomViewpoints.js +74 -0
  91. package/src/charting/archimate/DerivedEdge.js +29 -0
  92. package/src/charting/archimate/DrawioFileFormat.js +24 -0
  93. package/src/charting/archimate/ElementFilterRule.js +21 -0
  94. package/src/charting/archimate/ExchangeFileFormat.js +28 -0
  95. package/src/charting/archimate/ViewGroupTemplate.js +137 -0
  96. package/src/charting/archimate/ViewLineEdge.js +84 -0
  97. package/src/charting/archimate/ViewpointRule.js +45 -0
  98. package/src/charting/archimate/archimateFileFormats.js +12 -0
  99. package/src/charting/archimate/archimateNames.js +5 -0
  100. package/src/charting/archimate/csvMapping.js +122 -0
  101. package/src/charting/archimate/elementMenuItems.js +32 -0
  102. package/src/charting/archimate/elementProperties.js +146 -0
  103. package/src/charting/archimate/elementTypeChoices.js +7 -0
  104. package/src/charting/archimate/elementTypeGroups.js +19 -0
  105. package/src/charting/archimate/index.js +17 -0
  106. package/src/charting/archimate/specializationCatalogDialog.js +64 -0
  107. package/src/charting/archimate/typeGlyph.js +29 -0
  108. package/src/charting/arrangement/Arrangement.js +112 -0
  109. package/src/charting/arrangement/ArrangementCommand.js +29 -0
  110. package/src/charting/arrangement/BackgroundCommand.js +41 -0
  111. package/src/charting/arrangement/BackgroundGroup.js +18 -0
  112. package/src/charting/arrangement/GroupCommand.js +46 -0
  113. package/src/charting/arrangement/ItemGroup.js +62 -0
  114. package/src/charting/arrangement/LockCommand.js +32 -0
  115. package/src/charting/arrangement/UngroupCommand.js +27 -0
  116. package/src/charting/arrangement/alignment.js +88 -0
  117. package/src/charting/arrangement/arrangeMenuItems.js +25 -0
  118. package/src/charting/arrangement/index.js +11 -0
  119. package/src/charting/arrangement/layouts.js +233 -0
  120. package/src/charting/canvas/ArchiHint.js +78 -0
  121. package/src/charting/canvas/CanvasBoxKind.js +39 -0
  122. package/src/charting/canvas/CanvasPalette.js +49 -0
  123. package/src/charting/canvas/CanvasTemplateLibrary.js +61 -0
  124. package/src/charting/canvas/CanvasTemplateMenu.js +151 -0
  125. package/src/charting/canvas/EditHintCommand.js +28 -0
  126. package/src/charting/canvas/canvasBoxKinds.js +27 -0
  127. package/src/charting/canvas/canvasBoxMenuItems.js +40 -0
  128. package/src/charting/canvas/defaultCanvasTemplates.js +186 -0
  129. package/src/charting/canvas/diagramBoxKinds.js +12 -0
  130. package/src/charting/canvas/hintMenuItems.js +49 -0
  131. package/src/charting/charts/ArcGauge.js +55 -0
  132. package/src/charting/charts/AreaChart.js +71 -0
  133. package/src/charting/charts/BarChart.js +80 -0
  134. package/src/charting/charts/BarChart3D.js +56 -0
  135. package/src/charting/charts/BarChart3DOrbit.js +53 -0
  136. package/src/charting/charts/BarChartBase.js +70 -0
  137. package/src/charting/charts/BarGauge.js +42 -0
  138. package/src/charting/charts/BoxPlotChart.js +41 -0
  139. package/src/charting/charts/BubbleChart.js +99 -0
  140. package/src/charting/charts/BubbleChart3D.js +78 -0
  141. package/src/charting/charts/BulletGauge.js +87 -0
  142. package/src/charting/charts/CalendarHeatmapChart.js +204 -0
  143. package/src/charting/charts/CandlestickChart.js +54 -0
  144. package/src/charting/charts/ChordDiagram.js +130 -0
  145. package/src/charting/charts/DensityChart.js +73 -0
  146. package/src/charting/charts/DialGauge.js +65 -0
  147. package/src/charting/charts/DonutChart.js +15 -0
  148. package/src/charting/charts/FunnelChart.js +47 -0
  149. package/src/charting/charts/GanttChart.js +201 -0
  150. package/src/charting/charts/GaugeChart.js +175 -0
  151. package/src/charting/charts/GeoMapChart.js +146 -0
  152. package/src/charting/charts/GroupedBarChart.js +88 -0
  153. package/src/charting/charts/GroupedDistributionChart.js +70 -0
  154. package/src/charting/charts/HeatmapChart.js +80 -0
  155. package/src/charting/charts/HierarchyChart.js +39 -0
  156. package/src/charting/charts/HistogramChart.js +45 -0
  157. package/src/charting/charts/KpiTile.js +72 -0
  158. package/src/charting/charts/LagPlotChart.js +41 -0
  159. package/src/charting/charts/LineChart.js +124 -0
  160. package/src/charting/charts/MultiRingGauge.js +54 -0
  161. package/src/charting/charts/OutlineChart.js +95 -0
  162. package/src/charting/charts/ParallelCoordinatesChart.js +130 -0
  163. package/src/charting/charts/PieChart.js +56 -0
  164. package/src/charting/charts/PipeChart.js +88 -0
  165. package/src/charting/charts/PopulationPyramidChart.js +106 -0
  166. package/src/charting/charts/QQPlotChart.js +64 -0
  167. package/src/charting/charts/RadarChart.js +76 -0
  168. package/src/charting/charts/RadialBarChart.js +96 -0
  169. package/src/charting/charts/RingGauge.js +23 -0
  170. package/src/charting/charts/SankeyDiagram.js +174 -0
  171. package/src/charting/charts/ScatterChart.js +104 -0
  172. package/src/charting/charts/StackedAreaChart.js +15 -0
  173. package/src/charting/charts/StackedBarChart.js +33 -0
  174. package/src/charting/charts/StackedBarChart3DOrbit.js +58 -0
  175. package/src/charting/charts/StreamGraphChart.js +131 -0
  176. package/src/charting/charts/SunburstChart.js +57 -0
  177. package/src/charting/charts/ThermometerGauge.js +43 -0
  178. package/src/charting/charts/TreemapChart.js +54 -0
  179. package/src/charting/charts/ViolinChart.js +37 -0
  180. package/src/charting/charts/WaterfallChart.js +66 -0
  181. package/src/charting/charts/WordCloudChart.js +104 -0
  182. package/src/charting/diagramModel/AddViewCommand.js +33 -0
  183. package/src/charting/diagramModel/DiagramModel.js +39 -0
  184. package/src/charting/diagramModel/DiagramModelSearch.js +22 -0
  185. package/src/charting/diagramModel/DiagramView.js +50 -0
  186. package/src/charting/diagramModel/ModelHistory.js +43 -0
  187. package/src/charting/diagramModel/ModelReport.js +153 -0
  188. package/src/charting/diagramModel/ModelSearch.js +223 -0
  189. package/src/charting/diagramModel/RemoveViewCommand.js +25 -0
  190. package/src/charting/diagramModel/RenameViewCommand.js +21 -0
  191. package/src/charting/diagramModel/ReplaceTextCommand.js +25 -0
  192. package/src/charting/diagramModel/ViewSetChecker.js +34 -0
  193. package/src/charting/diagramModel/ViewSetModel.js +243 -0
  194. package/src/charting/diagramModel/index.js +6 -0
  195. package/src/charting/diagramModel/nameTransforms.js +29 -0
  196. package/src/charting/diagrams/ArchimateCommands.js +141 -0
  197. package/src/charting/diagrams/ArchimateDiagram.js +263 -0
  198. package/src/charting/diagrams/ArchimateModel.js +1155 -0
  199. package/src/charting/diagrams/ArchimateModelChecker.js +125 -0
  200. package/src/charting/diagrams/ArchimateModelReport.js +128 -0
  201. package/src/charting/diagrams/ArchimateModelSearch.js +41 -0
  202. package/src/charting/diagrams/ArchimateValidator.js +357 -0
  203. package/src/charting/diagrams/CanvasView.js +112 -0
  204. package/src/charting/diagrams/ContextMenu.js +37 -0
  205. package/src/charting/diagrams/DataModelDiagram.js +86 -0
  206. package/src/charting/diagrams/DataModelRelationshipStrategy.js +38 -0
  207. package/src/charting/diagrams/DerivedRelationships.js +102 -0
  208. package/src/charting/diagrams/EbnfDiagram.js +39 -0
  209. package/src/charting/diagrams/EdgeGeometry.js +553 -0
  210. package/src/charting/diagrams/EditViewItemCommand.js +128 -0
  211. package/src/charting/diagrams/ElementInstance.js +157 -0
  212. package/src/charting/diagrams/GraphDiagram.js +1340 -0
  213. package/src/charting/diagrams/GraphDiagram3D.js +152 -0
  214. package/src/charting/diagrams/GraphMetrics.js +81 -0
  215. package/src/charting/diagrams/GridOverlay.js +137 -0
  216. package/src/charting/diagrams/ImportRowsCommand.js +62 -0
  217. package/src/charting/diagrams/LabelHelper.js +108 -0
  218. package/src/charting/diagrams/MergeElementsCommand.js +101 -0
  219. package/src/charting/diagrams/NestInstanceCommand.js +34 -0
  220. package/src/charting/diagrams/NodeGeometry.js +158 -0
  221. package/src/charting/diagrams/PlaceItemsCommand.js +77 -0
  222. package/src/charting/diagrams/RadialLayout.js +101 -0
  223. package/src/charting/diagrams/RelationshipInstance.js +93 -0
  224. package/src/charting/diagrams/RemoveGroupFromViewCommand.js +28 -0
  225. package/src/charting/diagrams/RemoveLineCommand.js +27 -0
  226. package/src/charting/diagrams/ShowElementCommand.js +43 -0
  227. package/src/charting/diagrams/SvgCoordinate.js +17 -0
  228. package/src/charting/diagrams/SvgZoom.js +127 -0
  229. package/src/charting/diagrams/Tooltip.js +62 -0
  230. package/src/charting/diagrams/ViewConnectionInstance.js +102 -0
  231. package/src/charting/diagrams/ViewObjectInstance.js +56 -0
  232. package/src/charting/diagrams/commands/AddEdgeCommand.js +34 -0
  233. package/src/charting/diagrams/commands/AddNodeCommand.js +28 -0
  234. package/src/charting/diagrams/commands/AddWaypointCommand.js +27 -0
  235. package/src/charting/diagrams/commands/CreateFolderCommand.js +27 -0
  236. package/src/charting/diagrams/commands/DeleteEdgeCommand.js +30 -0
  237. package/src/charting/diagrams/commands/DeleteFolderCommand.js +47 -0
  238. package/src/charting/diagrams/commands/DeleteNodeCommand.js +35 -0
  239. package/src/charting/diagrams/commands/DeleteWaypointCommand.js +24 -0
  240. package/src/charting/diagrams/commands/GraphCommand.js +65 -0
  241. package/src/charting/diagrams/commands/InvertEdgeCommand.js +24 -0
  242. package/src/charting/diagrams/commands/MoveNodeCommand.js +44 -0
  243. package/src/charting/diagrams/commands/MoveWaypointCommand.js +27 -0
  244. package/src/charting/diagrams/commands/RenameEdgeCommand.js +23 -0
  245. package/src/charting/diagrams/commands/RenameFolderCommand.js +31 -0
  246. package/src/charting/diagrams/commands/RenameNodeCommand.js +27 -0
  247. package/src/charting/diagrams/commands/ResizeNodeCommand.js +46 -0
  248. package/src/charting/diagrams/commands/UpdateEdgeSideCommand.js +40 -0
  249. package/src/charting/diagrams/commands/index.js +17 -0
  250. package/src/charting/diagrams/duplicates.js +49 -0
  251. package/src/charting/diagrams/nesting.js +30 -0
  252. package/src/charting/diagrams/roadmap.js +77 -0
  253. package/src/charting/edgeMarkers/ArrowMarker.js +15 -0
  254. package/src/charting/edgeMarkers/CircleMarker.js +13 -0
  255. package/src/charting/edgeMarkers/CrowsFootMarker.js +16 -0
  256. package/src/charting/edgeMarkers/DiamondMarker.js +15 -0
  257. package/src/charting/edgeMarkers/EdgeMarker.js +34 -0
  258. package/src/charting/edgeMarkers/HalfArrowMarker.js +8 -0
  259. package/src/charting/edgeMarkers/HollowDiamondMarker.js +18 -0
  260. package/src/charting/edgeMarkers/HollowTriangleMarker.js +18 -0
  261. package/src/charting/edgeMarkers/OpenArrowMarker.js +17 -0
  262. package/src/charting/edgeMarkers/index.js +27 -0
  263. package/src/charting/edgeStyle/EdgeStyleCascade.js +22 -0
  264. package/src/charting/edgeStyle/EdgeStyleDialog.js +51 -0
  265. package/src/charting/edgeStyle/EdgeStyleSchema.js +43 -0
  266. package/src/charting/edgeStyle/SetStyleCommand.js +12 -0
  267. package/src/charting/edgeStyle/index.js +4 -0
  268. package/src/charting/emphasis/EmphasisRule.js +42 -0
  269. package/src/charting/emphasis/HighlightRule.js +24 -0
  270. package/src/charting/gauges/ArcTrack.js +51 -0
  271. package/src/charting/gauges/GaugeAnimation.js +51 -0
  272. package/src/charting/gauges/GaugeBands.js +48 -0
  273. package/src/charting/gauges/GaugeScale.js +87 -0
  274. package/src/charting/gauges/GaugeTrack.js +44 -0
  275. package/src/charting/gauges/GaugeValue.js +61 -0
  276. package/src/charting/gauges/HorizontalTrack.js +14 -0
  277. package/src/charting/gauges/LinearTrack.js +29 -0
  278. package/src/charting/gauges/Sparkline.js +42 -0
  279. package/src/charting/gauges/VerticalTrack.js +17 -0
  280. package/src/charting/glyphs/ArrowGlyph.js +21 -0
  281. package/src/charting/glyphs/BatteryGlyph.js +18 -0
  282. package/src/charting/glyphs/ChevronGlyph.js +18 -0
  283. package/src/charting/glyphs/CircleGlyph.js +15 -0
  284. package/src/charting/glyphs/CloudGlyph.js +19 -0
  285. package/src/charting/glyphs/ComponentGlyph.js +18 -0
  286. package/src/charting/glyphs/ConstraintGlyph.js +24 -0
  287. package/src/charting/glyphs/ContractBoxGlyph.js +10 -0
  288. package/src/charting/glyphs/CubeGlyph.js +19 -0
  289. package/src/charting/glyphs/CylinderGlyph.js +19 -0
  290. package/src/charting/glyphs/DashedDoubleArrowGlyph.js +11 -0
  291. package/src/charting/glyphs/DeviceGlyph.js +17 -0
  292. package/src/charting/glyphs/DiamondGlyph.js +17 -0
  293. package/src/charting/glyphs/DocumentGlyph.js +17 -0
  294. package/src/charting/glyphs/DoubleArrowGlyph.js +23 -0
  295. package/src/charting/glyphs/DoubleCircleGlyph.js +24 -0
  296. package/src/charting/glyphs/EllipseGlyph.js +18 -0
  297. package/src/charting/glyphs/FactoryGlyph.js +20 -0
  298. package/src/charting/glyphs/FlagGlyph.js +16 -0
  299. package/src/charting/glyphs/GapCircleGlyph.js +17 -0
  300. package/src/charting/glyphs/GearGlyph.js +37 -0
  301. package/src/charting/glyphs/Glyph.js +98 -0
  302. package/src/charting/glyphs/GroupingBoxGlyph.js +13 -0
  303. package/src/charting/glyphs/HalfCircleGlyph.js +22 -0
  304. package/src/charting/glyphs/HexagonGlyph.js +28 -0
  305. package/src/charting/glyphs/IconGlyph.js +22 -0
  306. package/src/charting/glyphs/ImageGlyph.js +16 -0
  307. package/src/charting/glyphs/JunctionGlyph.js +17 -0
  308. package/src/charting/glyphs/LollipopGlyph.js +22 -0
  309. package/src/charting/glyphs/MagnifierGlyph.js +17 -0
  310. package/src/charting/glyphs/NoteGlyph.js +33 -0
  311. package/src/charting/glyphs/ObjectBoxGlyph.js +21 -0
  312. package/src/charting/glyphs/OrJunctionGlyph.js +17 -0
  313. package/src/charting/glyphs/ParallelogramGlyph.js +20 -0
  314. package/src/charting/glyphs/PersonGlyph.js +23 -0
  315. package/src/charting/glyphs/PillGlyph.js +23 -0
  316. package/src/charting/glyphs/PinGlyph.js +18 -0
  317. package/src/charting/glyphs/PrincipleGlyph.js +23 -0
  318. package/src/charting/glyphs/ProductBoxGlyph.js +16 -0
  319. package/src/charting/glyphs/RectGlyph.js +15 -0
  320. package/src/charting/glyphs/RoundedBoxGlyph.js +13 -0
  321. package/src/charting/glyphs/StackGlyph.js +14 -0
  322. package/src/charting/glyphs/StepsGlyph.js +20 -0
  323. package/src/charting/glyphs/StickFigureGlyph.js +32 -0
  324. package/src/charting/glyphs/SystemSoftwareBoxGlyph.js +16 -0
  325. package/src/charting/glyphs/TabbedBoxGlyph.js +37 -0
  326. package/src/charting/glyphs/TargetGlyph.js +23 -0
  327. package/src/charting/glyphs/WavyBoxGlyph.js +17 -0
  328. package/src/charting/glyphs/WheelGlyph.js +28 -0
  329. package/src/charting/glyphs/drawGlyph.js +28 -0
  330. package/src/charting/glyphs/glyphSvg.js +55 -0
  331. package/src/charting/glyphs/index.js +109 -0
  332. package/src/charting/modelTree/AnalysisPanel.js +159 -0
  333. package/src/charting/modelTree/DiagramTabs.js +217 -0
  334. package/src/charting/modelTree/ModelTree.js +164 -0
  335. package/src/charting/modelTree/ModelTreePanel.js +914 -0
  336. package/src/charting/modelTree/TreeBuilder.js +238 -0
  337. package/src/charting/modelTree/TreeModeRegistry.js +51 -0
  338. package/src/charting/modelTree/TreeViewMode.js +110 -0
  339. package/src/charting/modelTree/buildFilterTrees.js +138 -0
  340. package/src/charting/modelTree/modes/FlatTreeMode.js +46 -0
  341. package/src/charting/modelTree/modes/LayerGroupedTreeMode.js +62 -0
  342. package/src/charting/modelTree/modes/TypeGroupedTreeMode.js +60 -0
  343. package/src/charting/modelTree/treeLayers.js +11 -0
  344. package/src/charting/report/reportHtml.js +82 -0
  345. package/src/charting/report/reportViewer.js +118 -0
  346. package/src/charting/shapes/CircleShape.js +19 -0
  347. package/src/charting/shapes/PathShape.js +17 -0
  348. package/src/charting/shapes/RectShape.js +20 -0
  349. package/src/charting/shapes/Shape.js +20 -0
  350. package/src/charting/shapes/ShapeFactory.js +23 -0
  351. package/src/charting/storage/LocalJsonStore.js +43 -0
  352. package/src/charting/templates/ActorTemplate.js +36 -0
  353. package/src/charting/templates/BoxTemplate.js +27 -0
  354. package/src/charting/templates/CircleTemplate.js +18 -0
  355. package/src/charting/templates/ClassTemplate.js +20 -0
  356. package/src/charting/templates/CloudTemplate.js +43 -0
  357. package/src/charting/templates/ComponentTemplate.js +19 -0
  358. package/src/charting/templates/CylinderTemplate.js +30 -0
  359. package/src/charting/templates/DataStoreTemplate.js +16 -0
  360. package/src/charting/templates/DiamondTemplate.js +10 -0
  361. package/src/charting/templates/DocumentTemplate.js +32 -0
  362. package/src/charting/templates/EllipseTemplate.js +15 -0
  363. package/src/charting/templates/FinalStateTemplate.js +12 -0
  364. package/src/charting/templates/GlyphTemplate.js +47 -0
  365. package/src/charting/templates/HexagonTemplate.js +17 -0
  366. package/src/charting/templates/LifelineTemplate.js +20 -0
  367. package/src/charting/templates/ManualInputTemplate.js +12 -0
  368. package/src/charting/templates/NoteTemplate.js +23 -0
  369. package/src/charting/templates/OctagonTemplate.js +7 -0
  370. package/src/charting/templates/PackageTemplate.js +25 -0
  371. package/src/charting/templates/ParallelogramTemplate.js +11 -0
  372. package/src/charting/templates/PentagonTemplate.js +5 -0
  373. package/src/charting/templates/PolygonTemplate.js +18 -0
  374. package/src/charting/templates/PredefinedProcessTemplate.js +13 -0
  375. package/src/charting/templates/RectangleTemplate.js +28 -0
  376. package/src/charting/templates/RegularPolygonTemplate.js +21 -0
  377. package/src/charting/templates/RoundedRectangleTemplate.js +5 -0
  378. package/src/charting/templates/StadiumTemplate.js +8 -0
  379. package/src/charting/templates/StarTemplate.js +17 -0
  380. package/src/charting/templates/SwimlaneTemplate.js +18 -0
  381. package/src/charting/templates/Template.js +208 -0
  382. package/src/charting/templates/TrapezoidTemplate.js +11 -0
  383. package/src/charting/templates/TriangleTemplate.js +12 -0
  384. package/src/charting/templates/index.js +31 -0
  385. package/src/charting/templates/outline.js +59 -0
  386. package/src/charting/templates/svg.js +19 -0
  387. package/src/charting/textToShapes.js +61 -0
  388. package/src/charting/toolbar/ToolbarButton.js +38 -0
  389. package/src/charting/toolbar/ToolbarCheckbox.js +31 -0
  390. package/src/charting/toolbar/ToolbarItem.js +19 -0
  391. package/src/charting/toolbar/ToolbarMenu.js +36 -0
  392. package/src/charting/toolbar/ToolbarSelect.js +38 -0
  393. package/src/charting/toolbar/ToolbarSeparator.js +7 -0
  394. package/src/charting/toolbar/ToolbarText.js +22 -0
  395. package/src/charting/toolbar/index.js +8 -0
  396. package/src/charting/toolbar/pickFile.js +14 -0
  397. package/src/charting/viewDecorations.js +85 -0
  398. package/src/charting/zOrder.js +57 -0
  399. package/src/csvTable.js +61 -0
  400. package/src/datamodel.js +122 -0
  401. package/src/datawindow/BoundedWindow.js +36 -0
  402. package/src/datawindow/FlatDataWindow.js +34 -0
  403. package/src/datawindow/GraphDataWindow.js +40 -0
  404. package/src/datawindow/GroupedSampleDataWindow.js +16 -0
  405. package/src/datawindow/SeriesDataWindow.js +42 -0
  406. package/src/datawindow/index.js +31 -0
  407. package/src/diagramCatalog.js +30 -0
  408. package/src/ebnfDiagram.js +57 -0
  409. package/src/ebnfParser.js +129 -0
  410. package/src/exportImage.js +233 -0
  411. package/src/index.js +2636 -0
  412. package/src/itIcons.js +84 -0
  413. package/src/kernelExpr.js +243 -0
  414. package/src/propertiesDialog.js +463 -0
  415. package/src/railroadDiagram.js +571 -0
  416. package/src/treeModeCatalog.js +16 -0
  417. package/src/workspace/ContextBus.js +79 -0
  418. package/src/workspace/EditorShell.js +67 -0
  419. package/src/workspace/Part.js +163 -0
  420. package/src/workspace/PartFactory.js +49 -0
  421. package/src/workspace/PartRegistry.js +86 -0
  422. package/src/workspace/Workspace.js +321 -0
  423. package/src/workspace/archimateServices.js +33 -0
  424. package/src/workspace/dom.js +120 -0
  425. package/src/workspace/index.js +75 -0
  426. package/src/workspace/layout/GridNode.js +280 -0
  427. package/src/workspace/layout/LayoutNode.js +89 -0
  428. package/src/workspace/layout/PartNode.js +77 -0
  429. package/src/workspace/layout/SplitNode.js +114 -0
  430. package/src/workspace/layout/TabsNode.js +191 -0
  431. package/src/workspace/layout/index.js +24 -0
  432. package/src/workspace/parts/AdapterPart.js +33 -0
  433. package/src/workspace/parts/ArchimateCanvasPart.js +345 -0
  434. package/src/workspace/parts/ArchimateEditorPart.js +79 -0
  435. package/src/workspace/parts/ChartPart.js +115 -0
  436. package/src/workspace/parts/ContentPart.js +34 -0
  437. package/src/workspace/parts/DetailPart.js +46 -0
  438. package/src/workspace/parts/DiagramEditorPart.js +135 -0
  439. package/src/workspace/parts/EditorPart.js +388 -0
  440. package/src/workspace/parts/HtmlPart.js +25 -0
  441. package/src/workspace/parts/ListPart.js +57 -0
  442. package/src/workspace/parts/ModelFile.js +187 -0
  443. package/src/workspace/parts/ModelsPart.js +135 -0
  444. package/src/workspace/styles.js +258 -0
  445. package/src/workspace/themes.js +96 -0
  446. package/src/workspace/workArea.js +413 -0
  447. package/src/workspace/workAreaModel.js +197 -0
  448. package/src/workspace.js +16 -0
  449. package/src/zip/ZipArchive.js +160 -0
  450. package/src/zip/crc32.js +25 -0
  451. package/src/zip/inflate.js +159 -0
@@ -0,0 +1,413 @@
1
+ /**
2
+ * WorkArea — the IDE-style editor area: several views open at once, in tab
3
+ * groups that can sit side by side.
4
+ *
5
+ * The whole point is the separation the plain `tabs`/`split` layout does not
6
+ * make on its own: a view being OPEN (it has a tab) is not the same as it being
7
+ * VISIBLE (its tab is selected in a group that is on screen). A shell that
8
+ * rebuilds a fixed layout per view can only ever show one; a work area lets you
9
+ * put the data model next to the notebook that queries it.
10
+ *
11
+ * Structure lives in `workAreaModel.js` as pure functions over plain JSON, and
12
+ * this class is the thin rendering shell over them:
13
+ *
14
+ * model (JSON) --createLayout--> live layout tree --serialize--> model
15
+ *
16
+ * The live tree is authoritative for the things the user adjusts directly —
17
+ * splitter positions, which tab is selected — so every structural change starts
18
+ * by reading them back out of it (`_syncFromTree`). Rebuilding the subtree
19
+ * afterwards is cheap and non-destructive: `PartNode.dispose()` only detaches a
20
+ * part and `Part.mount()` re-parents it, so a part keeps its DOM, its state and
21
+ * its bus subscriptions across the rebuild.
22
+ *
23
+ * Selecting a tab does NOT rebuild, though — the pane elements are what scroll,
24
+ * and replacing them would throw away scroll position on every tab click.
25
+ */
26
+ import { createLayout } from './layout/index.js';
27
+ import { el } from './dom.js';
28
+ import {
29
+ emptyWorkArea, listGroups, listOpenParts, findPart,
30
+ openPart, closePart, focusPart,
31
+ } from './workAreaModel.js';
32
+
33
+ export class WorkArea {
34
+ /**
35
+ * @param {object} [options]
36
+ * @param {object} [options.area] serialized area to restore
37
+ * @param {string} [options.activeGroupId] group new views open into
38
+ * @param {Function} [options.onChange] ({ area, activeGroupId, reason }) — persist here
39
+ * @param {*} [options.placeholder] el() spec shown when nothing is open
40
+ * @param {Element} [options.actionsHost] filled with the focused view's `actions`
41
+ * @param {Element} [options.outlineHost] filled with the focused view's outline part
42
+ * @param {Function} [options.outlineFor] (partId) => outline partId | null
43
+ * @param {*} [options.outlinePlaceholder] el() spec when a view has no outline
44
+ * @param {Function} [options.beforeClose] (partId) => false to keep a tab its close button was
45
+ * pressed on (unsaved work, say); the handler may close it later
46
+ */
47
+ constructor({
48
+ area, activeGroupId, onChange, placeholder,
49
+ actionsHost, outlineHost, outlineFor, outlinePlaceholder, beforeClose,
50
+ } = {}) {
51
+ this.area = area ?? emptyWorkArea();
52
+ this.activeGroupId = activeGroupId ?? listGroups(this.area)[0]?.id ?? null;
53
+ this.onChange = onChange ?? null;
54
+ this.beforeClose = beforeClose ?? null;
55
+ this.placeholder = placeholder ?? { cls: 'ws-workarea-empty', text: 'Nothing open' };
56
+ this.host = null;
57
+ this.ctx = null;
58
+ this._tree = null;
59
+ this._outerCtx = null;
60
+
61
+ // Frame slots. Both are filled from whichever view has FOCUS, which is
62
+ // the whole reason they live here: the work area is the only thing that
63
+ // knows what that is.
64
+ this.actionsHost = actionsHost ?? null;
65
+ this.outlineHost = outlineHost ?? null;
66
+ this.outlineFor = outlineFor ?? null;
67
+ this.outlinePlaceholder = outlinePlaceholder ?? null;
68
+ this._outlinePart = null;
69
+ this._slotPartId = null;
70
+ }
71
+
72
+ /* ── Queries ────────────────────────────────────────────────────────── */
73
+
74
+ /** Every open part id, in group order. */
75
+ openParts() { return listOpenParts(this.area); }
76
+
77
+ isOpen(partId) { return !!findPart(this.area, partId); }
78
+
79
+ /** The part id selected in each group — i.e. what is actually on screen. */
80
+ visibleParts() {
81
+ return listGroups(this.area)
82
+ .map(g => g.children?.[g.active ?? 0]?.partId)
83
+ .filter(Boolean);
84
+ }
85
+
86
+ /**
87
+ * The view with focus: the selected tab of the active group. This is what a
88
+ * shell keys its chrome off — window title, breadcrumb, which toolbar
89
+ * belongs to what — and it is not the same as "the last thing opened",
90
+ * because clicking into another group changes it.
91
+ */
92
+ activePart() {
93
+ const groups = listGroups(this.area);
94
+ const group = groups.find(g => g.id === this.activeGroupId) ?? groups[0];
95
+ return group?.children?.[group.active ?? 0]?.partId ?? null;
96
+ }
97
+
98
+ groupCount() { return listGroups(this.area).length; }
99
+
100
+ /** `{ area, activeGroupId }` — hand straight to a store, pass back to the ctor. */
101
+ serialize() {
102
+ this._syncFromTree();
103
+ return { area: this.area, activeGroupId: this.activeGroupId };
104
+ }
105
+
106
+ /* ── Rendering ──────────────────────────────────────────────────────── */
107
+
108
+ render(host, ctx = {}) {
109
+ this.host = host;
110
+ this._outerCtx = ctx;
111
+ this.ctx = {
112
+ ...ctx,
113
+ // Closing and group focus are decisions about the AREA, not about
114
+ // one tab strip, so they are intercepted here rather than left to
115
+ // TabsNode's own handling.
116
+ onTabClose: ({ partId }) => { if (partId && this.beforeClose?.(partId) !== false) this.close(partId); },
117
+ onGroupFocus: (id) => this._setActiveGroup(id),
118
+ onLayoutChange: () => this._changed('layout'),
119
+ };
120
+ this._build();
121
+ // Both slots explicitly: nothing has focus yet as far as they are
122
+ // concerned, so a restored area would otherwise come back with an empty
123
+ // action bar and an empty rail.
124
+ this._syncSlots({ actions: true, outline: true });
125
+ return this;
126
+ }
127
+
128
+ _build() {
129
+ if (!this.host) return;
130
+ this._tree?.dispose();
131
+ this._tree = null;
132
+ this.host.textContent = '';
133
+
134
+ if (!listOpenParts(this.area).length) {
135
+ if (this.placeholder) this.host.appendChild(el(this.placeholder));
136
+ return;
137
+ }
138
+
139
+ this._tree = createLayout(this.area);
140
+ this._tree.render(this.host, this.ctx);
141
+ this._tree.activate();
142
+ this._markActiveGroup();
143
+ }
144
+
145
+ /* ── Frame slots ────────────────────────────────────────────────────── */
146
+
147
+ /**
148
+ * Point the action bar and outline rail at whatever now has focus.
149
+ *
150
+ * A slot is re-read when focus MOVED, or when the caller asks for that slot
151
+ * specifically. The two are asked for separately because their costs
152
+ * differ: re-reading actions is a handful of buttons, whereas re-showing an
153
+ * outline re-parents an element, which resets its scroll position — so a
154
+ * `refreshActions()` must not quietly scroll a long tree back to the top.
155
+ */
156
+ _syncSlots({ actions = false, outline = false } = {}) {
157
+ const partId = this.activePart();
158
+ const moved = partId !== this._slotPartId;
159
+ if (!moved && !actions && !outline) return;
160
+ this._slotPartId = partId;
161
+ if (moved || actions) this._renderActions(partId);
162
+ if (moved || outline) this._showOutline(partId);
163
+ }
164
+
165
+ _renderActions(partId) {
166
+ if (!this.actionsHost) return;
167
+ this.actionsHost.textContent = '';
168
+ const actions = partId ? (this.ctx?.registry?.get(partId)?.actions ?? []) : [];
169
+ this.actionsHost.classList.toggle('ws-actionbar-empty', !actions.length);
170
+ for (const action of actions) {
171
+ if (!action) continue;
172
+ // An already-built element is passed straight through. This is the
173
+ // AdapterPart bargain again: a panel that already has a working
174
+ // toolbar — with selects, labels and its own rebuild logic — joins
175
+ // the frame's action bar by handing it over, not by being rewritten
176
+ // into a button array that could not express it anyway.
177
+ if (typeof action.nodeType === 'number' || typeof action.appendChild === 'function') {
178
+ this.actionsHost.appendChild(action);
179
+ continue;
180
+ }
181
+ if (action.separator) { this.actionsHost.appendChild(el({ cls: 'ws-action-sep' })); continue; }
182
+ this.actionsHost.appendChild(el({
183
+ tag: 'button',
184
+ cls: ['ws-action', action.cls],
185
+ text: action.label ?? '',
186
+ attrs: {
187
+ type: 'button',
188
+ title: action.title ?? action.label ?? null,
189
+ disabled: action.disabled || null,
190
+ },
191
+ on: { click: (e) => action.onClick?.(e, this) },
192
+ }));
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Show the focused view's outline.
198
+ *
199
+ * An outline is an ordinary Part, resolved through the registry — not a new
200
+ * kind of thing. That is what gets it pooling, mount-once-then-re-parent and
201
+ * lifecycle for free: a tree keeps its expanded nodes and scroll position
202
+ * while you work in another view and come back.
203
+ */
204
+ _showOutline(partId) {
205
+ if (!this.outlineHost) return;
206
+ const outlineId = partId && this.outlineFor ? this.outlineFor(partId) : null;
207
+ const next = outlineId ? this.ctx?.registry?.get(outlineId) : null;
208
+
209
+ // Detached by name rather than by clearing the host: the outgoing
210
+ // outline is a pooled part, and `detach()` is the call that says so.
211
+ this._outlinePart?.detach();
212
+ this._outlinePart = null;
213
+ this._placeholderEl?.remove();
214
+ this._placeholderEl = null;
215
+ this.outlineHost.classList.toggle('ws-outline-empty', !next);
216
+
217
+ if (!next) {
218
+ if (this.outlinePlaceholder) {
219
+ this._placeholderEl = this.outlineHost.appendChild(el(this.outlinePlaceholder));
220
+ }
221
+ return;
222
+ }
223
+ try {
224
+ next.mount(this.outlineHost, this.ctx);
225
+ this._outlinePart = next;
226
+ } catch (err) {
227
+ console.error(`WorkArea: outline part "${outlineId}" failed to mount`, err);
228
+ this.outlineHost.classList.add('ws-outline-empty');
229
+ }
230
+ }
231
+
232
+ /** Re-read the focused view's actions — call when a panel's state changes. */
233
+ refreshActions() {
234
+ this._syncSlots({ actions: true });
235
+ return this;
236
+ }
237
+
238
+ /**
239
+ * Re-read both slots. For the case a lazily-mounted view creates the very
240
+ * things the slots are meant to show *after* it took focus — the action bar
241
+ * and outline were resolved against a panel that did not exist yet.
242
+ */
243
+ refreshSlots() {
244
+ this._syncSlots({ actions: true, outline: true });
245
+ return this;
246
+ }
247
+
248
+ /** The outline part currently on show, if any. */
249
+ get outlinePart() { return this._outlinePart; }
250
+
251
+ /**
252
+ * Read the live tree back into the model. Splitter drags and tab selections
253
+ * only ever happened to the DOM nodes; skipping this would silently undo
254
+ * them the next time anything opens or closes.
255
+ */
256
+ _syncFromTree() {
257
+ if (this._tree) this.area = this._tree.serialize();
258
+ return this.area;
259
+ }
260
+
261
+ /** Show every tab's label as its part's title is now (a file name that changed, say). */
262
+ refreshLabels() {
263
+ const walk = (node) => {
264
+ if (node?.constructor?.type === 'tabs') node.refreshLabels?.();
265
+ for (const child of node?.children ?? []) walk(child);
266
+ };
267
+ if (this._tree) walk(this._tree);
268
+ return this;
269
+ }
270
+
271
+ /** Live TabsNode for a group id, or null when nothing is rendered. */
272
+ _liveGroup(groupId) {
273
+ const walk = (node) => {
274
+ if (node?.id === groupId && node.constructor?.type === 'tabs') return node;
275
+ for (const child of node?.children ?? []) {
276
+ const hit = walk(child);
277
+ if (hit) return hit;
278
+ }
279
+ return null;
280
+ };
281
+ return this._tree ? walk(this._tree) : null;
282
+ }
283
+
284
+ /**
285
+ * Tint the active group's tab strip, but only once there is more than one
286
+ * group — with a single group "where the next view opens" is not a question
287
+ * anyone is asking, and the accent would just be noise.
288
+ */
289
+ _markActiveGroup() {
290
+ const many = this.groupCount() > 1;
291
+ for (const group of listGroups(this.area)) {
292
+ const live = this._liveGroup(group.id);
293
+ live?.el?.classList.toggle('ws-group-active', many && group.id === this.activeGroupId);
294
+ }
295
+ }
296
+
297
+ _setActiveGroup(id) {
298
+ if (!id || id === this.activeGroupId) return;
299
+ this.activeGroupId = id;
300
+ this._markActiveGroup();
301
+ this._changed('focus-group');
302
+ }
303
+
304
+ _changed(reason) {
305
+ this._syncFromTree();
306
+ // Before onChange, so a consumer reacting to the change (updating its
307
+ // own chrome, persisting) sees a frame that already agrees with focus.
308
+ this._syncSlots();
309
+ this.onChange?.({ area: this.area, activeGroupId: this.activeGroupId, reason });
310
+ this._outerCtx?.onLayoutChange?.();
311
+ }
312
+
313
+ /* ── Commands ───────────────────────────────────────────────────────── */
314
+
315
+ /**
316
+ * Open a view.
317
+ *
318
+ * `where`: `'tab'` (default) adds it to the active group; `'right'`,
319
+ * `'left'`, `'below'` or `'above'` opens a new group beside it — which is
320
+ * what actually gets two views on screen together.
321
+ *
322
+ * Already open anywhere -> focused, not duplicated: a part instance owns one
323
+ * DOM element, so a second tab for it would necessarily be empty.
324
+ */
325
+ open(partId, { where = 'tab' } = {}) {
326
+ if (!partId) return this;
327
+ if (this.isOpen(partId)) return this.focus(partId);
328
+ this._syncFromTree();
329
+ const next = openPart(this.area, partId, { where, activeGroupId: this.activeGroupId });
330
+ this.area = next.area;
331
+ this.activeGroupId = next.activeGroupId;
332
+ this._build();
333
+ this._changed('open');
334
+ return this;
335
+ }
336
+
337
+ /** Open beside the active group — the "split editor" gesture. */
338
+ openToSide(partId, side = 'right') { return this.open(partId, { where: side }); }
339
+
340
+ /**
341
+ * Select an already-open view. Deliberately does not rebuild: it drives the
342
+ * live TabsNode, so pane scroll positions and the DOM survive a tab click.
343
+ */
344
+ focus(partId) {
345
+ const found = findPart(this._syncFromTree(), partId);
346
+ if (!found) return this;
347
+ const live = this._liveGroup(found.group.id);
348
+ if (live) {
349
+ live.select(found.index, true);
350
+ this.activeGroupId = found.group.id;
351
+ this._markActiveGroup();
352
+ this._changed('focus');
353
+ return this;
354
+ }
355
+ const next = focusPart(this.area, partId, { activeGroupId: this.activeGroupId });
356
+ this.area = next.area;
357
+ this.activeGroupId = next.activeGroupId;
358
+ this._build();
359
+ this._changed('focus');
360
+ return this;
361
+ }
362
+
363
+ /**
364
+ * Close a view. Its group disappears when it held the last tab, and a split
365
+ * left with one child collapses into it — so closing back down to one view
366
+ * leaves a plain tab strip rather than a split with an empty half.
367
+ */
368
+ close(partId) {
369
+ this._syncFromTree();
370
+ const next = closePart(this.area, partId, { activeGroupId: this.activeGroupId });
371
+ if (!next.closed) return this;
372
+ this.area = next.area;
373
+ this.activeGroupId = next.activeGroupId;
374
+ this._build();
375
+ this._changed('close');
376
+ return this;
377
+ }
378
+
379
+ /** Close everything, leaving one empty group. */
380
+ closeAll() {
381
+ for (const partId of this.openParts()) this.close(partId);
382
+ return this;
383
+ }
384
+
385
+ /**
386
+ * Replace the whole area — restoring a saved one, or switching perspective.
387
+ * Parts the new area does not reference are left in the registry pool, so
388
+ * switching back finds them as they were.
389
+ */
390
+ setArea(area, activeGroupId) {
391
+ this.area = area ?? emptyWorkArea();
392
+ this.activeGroupId = activeGroupId ?? listGroups(this.area)[0]?.id ?? null;
393
+ this._build();
394
+ this._changed('set-area');
395
+ return this;
396
+ }
397
+
398
+ dispose() {
399
+ this._tree?.dispose();
400
+ this._tree = null;
401
+ // Detached, not disposed — the outline is a pooled part like any other,
402
+ // and destroying it here would take it out of the registry for good.
403
+ this._outlinePart?.detach();
404
+ this._outlinePart = null;
405
+ this._placeholderEl = null;
406
+ this._slotPartId = null;
407
+ if (this.host) this.host.textContent = '';
408
+ if (this.actionsHost) this.actionsHost.textContent = '';
409
+ if (this.outlineHost) this.outlineHost.textContent = '';
410
+ this.host = null;
411
+ this.ctx = null;
412
+ }
413
+ }
@@ -0,0 +1,197 @@
1
+ /**
2
+ * workAreaModel — the pure half of an IDE-style work area.
3
+ *
4
+ * A work area is a layout subtree made only of TABS GROUPS, optionally
5
+ * arranged by SPLITS: one or more tab strips, each holding several open parts,
6
+ * side by side or stacked. That is the difference between "one view at a time"
7
+ * and an IDE: a part being OPEN (a tab exists) is separate from it being
8
+ * VISIBLE (its tab is selected, in a group that is on screen), and two parts in
9
+ * different groups are visible at once.
10
+ *
11
+ * Everything here is a pure function over plain JSON — the same descriptors
12
+ * `createLayout()` consumes — so the interesting behaviour (where a new tab
13
+ * lands, what collapses when the last tab in a group closes) is testable
14
+ * without a DOM. `WorkArea` (workArea.js) is the thin rendering shell on top.
15
+ *
16
+ * group := { type:'tabs', id, active, closable, children:[{type:'part', partId}] }
17
+ * area := group | { type:'split', dir:'row'|'col', sizes, children:[area, …] }
18
+ *
19
+ * Only `tabs` nodes carry an `id`, because a group is the only thing anything
20
+ * needs to address: "open this beside the active group", "this group is now
21
+ * active". Splits are structure, and they come and go as groups are added and
22
+ * removed.
23
+ */
24
+
25
+ const SIDES = { right: 'row', left: 'row', below: 'col', above: 'col' };
26
+
27
+ const clone = (x) => (typeof structuredClone === 'function' ? structuredClone(x) : JSON.parse(JSON.stringify(x)));
28
+
29
+ const isGroup = (n) => n?.type === 'tabs';
30
+ const isSplit = (n) => n?.type === 'split';
31
+
32
+ /** A work area with one empty group — what an area collapses to when the last tab closes. */
33
+ export function emptyWorkArea(groupId = 'g1') {
34
+ return { type: 'tabs', id: groupId, active: 0, closable: true, children: [] };
35
+ }
36
+
37
+ /** Every tabs group in the area, in left-to-right/top-to-bottom order. */
38
+ export function listGroups(area) {
39
+ if (!area) return [];
40
+ if (isGroup(area)) return [area];
41
+ return (area.children ?? []).flatMap(listGroups);
42
+ }
43
+
44
+ /** Every open part id, in group order. */
45
+ export function listOpenParts(area) {
46
+ return listGroups(area).flatMap(g => (g.children ?? []).map(c => c.partId));
47
+ }
48
+
49
+ /** `{ group, index }` for whichever group holds `partId`, or null. */
50
+ export function findPart(area, partId) {
51
+ for (const group of listGroups(area)) {
52
+ const index = (group.children ?? []).findIndex(c => c.partId === partId);
53
+ if (index >= 0) return { group, index };
54
+ }
55
+ return null;
56
+ }
57
+
58
+ /** The group `groupId` names, else the first group, else null. */
59
+ export function resolveGroup(area, groupId) {
60
+ const groups = listGroups(area);
61
+ return groups.find(g => g.id === groupId) ?? groups[0] ?? null;
62
+ }
63
+
64
+ /** An id no existing group is using — `g1`, `g2`, … */
65
+ function nextGroupId(area) {
66
+ const taken = new Set(listGroups(area).map(g => g.id));
67
+ for (let i = 1; ; i++) {
68
+ const id = `g${i}`;
69
+ if (!taken.has(id)) return id;
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Open `partId`.
75
+ *
76
+ * Already open anywhere -> focus it instead of opening a second copy: a part
77
+ * instance owns one DOM element (see Part), so the same part cannot be in two
78
+ * panes at once, and silently cloning the tab would leave one of them empty.
79
+ *
80
+ * `where`:
81
+ * 'tab' — another tab in the active group (default)
82
+ * 'right'|'left'|'below'|'above' — a NEW group beside the active one, which
83
+ * is what actually puts two parts on screen
84
+ * together
85
+ *
86
+ * Returns `{ area, activeGroupId, opened }` — `opened` false when it was
87
+ * already open, so a caller can tell a fresh open from a focus.
88
+ */
89
+ export function openPart(area, partId, { where = 'tab', activeGroupId } = {}) {
90
+ const existing = findPart(area, partId);
91
+ if (existing) return focusPart(area, partId, { activeGroupId });
92
+
93
+ const next = clone(area ?? emptyWorkArea());
94
+ const target = resolveGroup(next, activeGroupId) ?? resolveGroup(next);
95
+ const partNode = { type: 'part', partId };
96
+
97
+ if (where === 'tab' || !SIDES[where]) {
98
+ target.children = [...(target.children ?? []), partNode];
99
+ target.active = target.children.length - 1;
100
+ return { area: next, activeGroupId: target.id, opened: true };
101
+ }
102
+
103
+ const dir = SIDES[where];
104
+ const before = where === 'left' || where === 'above';
105
+ const group = { type: 'tabs', id: nextGroupId(next), active: 0, closable: true, children: [partNode] };
106
+ const placed = _placeBeside(next, target, group, dir, before);
107
+ return { area: placed, activeGroupId: group.id, opened: true };
108
+ }
109
+
110
+ /**
111
+ * Put `group` next to `target`. When target's own parent split already runs in
112
+ * the same direction the group joins it as a sibling rather than nesting a
113
+ * second split inside it — otherwise opening three views to the right builds a
114
+ * right-leaning tower of two-child splits, which serializes badly and resizes
115
+ * worse (each splitter would only move two of the panes).
116
+ */
117
+ function _placeBeside(area, target, group, dir, before) {
118
+ const walk = (node, parentDir) => {
119
+ if (node === target) {
120
+ // No parent split in this direction — wrap the target in a new one.
121
+ if (parentDir !== dir) {
122
+ return { type: 'split', dir, sizes: [null, null], children: before ? [group, node] : [node, group] };
123
+ }
124
+ return node; // handled by the parent split below
125
+ }
126
+ if (!isSplit(node)) return node;
127
+
128
+ const children = node.children ?? [];
129
+ const at = children.indexOf(target);
130
+ if (at >= 0 && node.dir === dir) {
131
+ const insertAt = before ? at : at + 1;
132
+ const nextChildren = [...children];
133
+ nextChildren.splice(insertAt, 0, group);
134
+ const sizes = (node.sizes ?? []).slice();
135
+ while (sizes.length < children.length) sizes.push(null);
136
+ sizes.splice(insertAt, 0, null);
137
+ return { ...node, children: nextChildren, sizes };
138
+ }
139
+ return { ...node, children: children.map(c => walk(c, node.dir)) };
140
+ };
141
+ return walk(area, null);
142
+ }
143
+
144
+ /**
145
+ * Close `partId`. An emptied group is removed, and a split left holding a
146
+ * single child collapses into that child — so closing back down to one view
147
+ * leaves a plain tab strip, not a split with an empty half. The area never
148
+ * disappears entirely: closing the last tab anywhere leaves one empty group.
149
+ */
150
+ export function closePart(area, partId, { activeGroupId } = {}) {
151
+ const found = findPart(area, partId);
152
+ if (!found) return { area, activeGroupId, closed: false };
153
+ const closedGroupId = found.group.id;
154
+
155
+ const prune = (node) => {
156
+ if (isGroup(node)) {
157
+ const children = (node.children ?? []).filter(c => c.partId !== partId);
158
+ if (!children.length) return null;
159
+ const removedAt = (node.children ?? []).findIndex(c => c.partId === partId);
160
+ let active = node.active ?? 0;
161
+ // Keep the neighbour selected rather than jumping to tab 0 — closing
162
+ // the active tab should land on what was next to it.
163
+ if (removedAt >= 0 && removedAt < active) active -= 1;
164
+ return { ...node, children, active: Math.max(0, Math.min(active, children.length - 1)) };
165
+ }
166
+ if (!isSplit(node)) return node;
167
+ const sizes = (node.sizes ?? []).slice();
168
+ const kept = [];
169
+ const keptSizes = [];
170
+ (node.children ?? []).forEach((child, i) => {
171
+ const pruned = prune(child);
172
+ if (pruned) { kept.push(pruned); keptSizes.push(sizes[i] ?? null); }
173
+ });
174
+ if (!kept.length) return null;
175
+ if (kept.length === 1) return kept[0]; // collapse the split away
176
+ return { ...node, children: kept, sizes: keptSizes };
177
+ };
178
+
179
+ const pruned = prune(clone(area));
180
+ const next = pruned ?? emptyWorkArea(closedGroupId);
181
+ const stillThere = listGroups(next).some(g => g.id === activeGroupId);
182
+ return {
183
+ area: next,
184
+ activeGroupId: stillThere ? activeGroupId : (listGroups(next)[0]?.id ?? null),
185
+ closed: true,
186
+ };
187
+ }
188
+
189
+ /** Select `partId`'s tab and make its group active. No-op if it isn't open. */
190
+ export function focusPart(area, partId, { activeGroupId } = {}) {
191
+ const found = findPart(area, partId);
192
+ if (!found) return { area, activeGroupId, opened: false };
193
+ const next = clone(area);
194
+ const group = listGroups(next).find(g => g.id === found.group.id);
195
+ group.active = (group.children ?? []).findIndex(c => c.partId === partId);
196
+ return { area: next, activeGroupId: group.id, opened: false };
197
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Compatibility shim.
3
+ *
4
+ * This path used to hold a standalone prototype shell: a fixed five-region
5
+ * slot layout (navigation/context/workspace/details/tabs) with an EventBus,
6
+ * a hard-coded perspective state machine, and a plugin manager whose plugins
7
+ * never actually contributed any UI. It could not express either target
8
+ * consumer — sqlengine workbench's sidebar+main+tool-panels, or its 12-column
9
+ * dashboard grid — so it was replaced by the part/layout/context model in
10
+ * `src/workspace/`. See WORKSPACE_ARCHITECTURE.md.
11
+ *
12
+ * Kept as a re-export so `import '.../src/workspace.js'` still registers the
13
+ * `<ws-workspace>` element. Both files defining the same tag would otherwise
14
+ * collide, with whichever imported first silently winning.
15
+ */
16
+ export * from './workspace/index.js';