@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,33 @@
1
+ import {
2
+ RenderEngine, ArchimateModel, ArchimateSpecializationSelector, DerivedRelationships, DiagramTabs, ModelTree,
3
+ SettingsManager, buildAnalysisPanel, buildModelTreePanel, fromArchimateView, parseArchiModel, toArchimateModel,
4
+ parseArchiFile, toArchiFile, toArchiExport, showGlobalSettingsDialog, showPropertiesDialog, showDiagramPropertiesDialog,
5
+ } from '../index.js';
6
+
7
+ /**
8
+ * What ArchimateDiagramEditor takes as its `workspace` option: the classes and
9
+ * dialogs it builds its model tree, tabs, settings and import/export from,
10
+ * collected by direct import. A part hands this in rather than reading a
11
+ * bundle's global, so it works the same however the library was loaded.
12
+ */
13
+ export const ARCHIMATE_SERVICES = Object.freeze({
14
+ RenderEngine,
15
+ ArchimateModel,
16
+ ArchimateSpecializationRegistry: RenderEngine.ArchimateSpecializationRegistry,
17
+ ArchimateSpecializationSelector,
18
+ DerivedRelationships,
19
+ DiagramTabs,
20
+ ModelTree,
21
+ SettingsManager,
22
+ buildAnalysisPanel,
23
+ buildModelTreePanel,
24
+ fromArchimateView,
25
+ parseArchiModel,
26
+ parseArchiFile,
27
+ toArchiFile,
28
+ toArchiExport,
29
+ toArchimateModel,
30
+ showGlobalSettingsDialog,
31
+ showPropertiesDialog,
32
+ showDiagramPropertiesDialog,
33
+ });
@@ -0,0 +1,120 @@
1
+ /**
2
+ * el() — build DOM from a plain-JSON element spec.
3
+ *
4
+ * The shell's structural guardrail: markup is generated from JavaScript and
5
+ * JSON objects, not written as HTML strings. Structure stays *data* — it can be
6
+ * inspected, composed, serialized and diffed the same way the layout tree is,
7
+ * and it never goes through an HTML parser, so text content cannot inject
8
+ * markup. Raw HTML injection is the deliberate escape hatch (`HtmlPart`), not
9
+ * the default (`ContentPart`).
10
+ *
11
+ * Spec shape — every field optional:
12
+ *
13
+ * {
14
+ * tag: 'div', // default 'div'
15
+ * cls: 'ws-toolbar' | ['a','b'], // class names
16
+ * text: 'label', // textContent (escaped by construction)
17
+ * attrs: { role: 'tablist' }, // setAttribute; null/false/undefined skipped
18
+ * dataset: { partId: 'nav' }, // data-* attributes
19
+ * style: { flex: '1 1 auto' }, // inline style properties
20
+ * on: { click: fn }, // addEventListener
21
+ * children: [spec | Node | string], // strings become text nodes
22
+ * ref: (element) => {}, // capture the node without querySelector
23
+ * }
24
+ *
25
+ * A bare string spec produces a text node, so `children: ['plain text']` works.
26
+ */
27
+ export function el(spec, doc = document) {
28
+ if (spec == null) return doc.createTextNode('');
29
+ if (typeof spec === 'string' || typeof spec === 'number') return doc.createTextNode(String(spec));
30
+ // Duck-typed rather than `instanceof Node`: `Node` is a browser global, so
31
+ // that test throws a ReferenceError anywhere else — including under a
32
+ // substituted document. A spec object never carries either of these.
33
+ if (typeof spec.nodeType === 'number' || typeof spec.appendChild === 'function') return spec;
34
+
35
+ const node = doc.createElement(spec.tag ?? 'div');
36
+
37
+ if (spec.cls) {
38
+ const classes = Array.isArray(spec.cls) ? spec.cls : [spec.cls];
39
+ node.className = classes.filter(Boolean).join(' ');
40
+ }
41
+ if (spec.text != null) node.textContent = String(spec.text);
42
+
43
+ for (const [k, v] of Object.entries(spec.attrs ?? {})) {
44
+ if (v == null || v === false) continue;
45
+ node.setAttribute(k, v === true ? '' : String(v));
46
+ }
47
+ for (const [k, v] of Object.entries(spec.dataset ?? {})) {
48
+ if (v == null) continue;
49
+ node.dataset[k] = String(v);
50
+ }
51
+ for (const [k, v] of Object.entries(spec.style ?? {})) {
52
+ if (v == null) continue;
53
+ node.style.setProperty(cssProp(k), String(v));
54
+ }
55
+ for (const [event, handler] of Object.entries(spec.on ?? {})) {
56
+ if (typeof handler === 'function') node.addEventListener(event, handler);
57
+ }
58
+ for (const child of spec.children ?? []) {
59
+ node.appendChild(el(child, doc));
60
+ }
61
+
62
+ spec.ref?.(node);
63
+ return node;
64
+ }
65
+
66
+ /** Build several specs into a DocumentFragment. */
67
+ export function frag(specs, doc = document) {
68
+ const f = doc.createDocumentFragment();
69
+ for (const spec of specs ?? []) f.appendChild(el(spec, doc));
70
+ return f;
71
+ }
72
+
73
+ /** Replace an element's contents with freshly built specs. */
74
+ export function render(host, specs, doc = document) {
75
+ host.textContent = '';
76
+ host.appendChild(frag(Array.isArray(specs) ? specs : [specs], doc));
77
+ return host;
78
+ }
79
+
80
+ /** camelCase → kebab-case, so style keys can be written either way. */
81
+ function cssProp(key) {
82
+ return key.startsWith('--') ? key : key.replace(/[A-Z]/g, c => `-${c.toLowerCase()}`);
83
+ }
84
+
85
+ const VOID_TAGS = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'source', 'track', 'wbr']);
86
+ const escapeHtml = (s) => String(s).replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[c]);
87
+
88
+ /**
89
+ * The same spec as el(), written out as HTML text: for a page that is saved
90
+ * rather than shown (a report). Text and attribute values are escaped; `on`
91
+ * and `ref` have no meaning in text and are left out. `script` is the one
92
+ * extra field: the trusted contents of a <script> or <style> (not escaped,
93
+ * but `</` is, so it cannot close its element early).
94
+ */
95
+ export function toHtml(spec) {
96
+ if (spec == null) return '';
97
+ if (typeof spec === 'string' || typeof spec === 'number') return escapeHtml(spec);
98
+ if (Array.isArray(spec)) return spec.map(toHtml).join('');
99
+ const tag = spec.tag ?? 'div';
100
+ const attrs = [];
101
+ if (spec.cls) {
102
+ const classes = (Array.isArray(spec.cls) ? spec.cls : [spec.cls]).filter(Boolean);
103
+ if (classes.length) attrs.push(['class', classes.join(' ')]);
104
+ }
105
+ for (const [k, v] of Object.entries(spec.attrs ?? {})) {
106
+ if (v == null || v === false) continue;
107
+ attrs.push([k, v === true ? '' : String(v)]);
108
+ }
109
+ for (const [k, v] of Object.entries(spec.dataset ?? {})) {
110
+ if (v != null) attrs.push([`data-${cssProp(k)}`, String(v)]);
111
+ }
112
+ const style = Object.entries(spec.style ?? {}).filter(([, v]) => v != null).map(([k, v]) => `${cssProp(k)}: ${v}`).join('; ');
113
+ if (style) attrs.push(['style', style]);
114
+ const open = `<${tag}${attrs.map(([k, v]) => ` ${k}="${escapeHtml(v)}"`).join('')}>`;
115
+ if (VOID_TAGS.has(tag)) return open;
116
+ const inner = spec.script != null
117
+ ? String(spec.script).replace(/<\//g, '<\\/')
118
+ : (spec.text != null ? escapeHtml(spec.text) : '') + (spec.children ?? []).map(toHtml).join('');
119
+ return `${open}${inner}</${tag}>`;
120
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Workspace — browser-only entry point for the application shell.
3
+ *
4
+ * Deliberately NOT re-exported from `src/index.js`: `Workspace` subclasses
5
+ * HTMLElement at module scope, so merely importing it throws under node — and
6
+ * `src/index.js` is the node entry the test suite loads. Import this module
7
+ * directly from a browser instead.
8
+ *
9
+ * Importing it registers the `<ws-workspace>` element. Built-in part types are
10
+ * NOT auto-registered: which parts exist is the consumer's decision, and
11
+ * pulling ChartPart in unconditionally would drag the whole RenderEngine into
12
+ * a shell that may only ever host adapted panels. Call
13
+ * `registerBuiltinParts(ws)` for the standard set, or register individually.
14
+ *
15
+ * See WORKSPACE_ARCHITECTURE.md for the design.
16
+ */
17
+ import { Workspace, WORKSPACE_TAG, WORKSPACE_SCHEMA_VERSION, defineWorkspace } from './Workspace.js';
18
+ import { ContextBus } from './ContextBus.js';
19
+ import { Part } from './Part.js';
20
+ import { PartRegistry } from './PartRegistry.js';
21
+ import { PartFactory } from './PartFactory.js';
22
+ import { ContentPart } from './parts/ContentPart.js';
23
+ import { HtmlPart } from './parts/HtmlPart.js';
24
+ import { ListPart } from './parts/ListPart.js';
25
+ import { DetailPart } from './parts/DetailPart.js';
26
+ import { AdapterPart } from './parts/AdapterPart.js';
27
+ import { ModelsPart } from './parts/ModelsPart.js';
28
+
29
+ defineWorkspace();
30
+
31
+ /** The dependency-free part types — everything except ChartPart. */
32
+ export const BUILTIN_PARTS = [ContentPart, HtmlPart, ListPart, DetailPart, AdapterPart, ModelsPart];
33
+
34
+ /** Convenience: register the standard part types on a workspace element. */
35
+ export function registerBuiltinParts(ws) {
36
+ ws.registerParts(BUILTIN_PARTS);
37
+ return ws;
38
+ }
39
+
40
+ export {
41
+ Workspace, WORKSPACE_TAG, WORKSPACE_SCHEMA_VERSION, defineWorkspace,
42
+ ContextBus, Part, PartRegistry, PartFactory,
43
+ ContentPart, HtmlPart, ListPart, DetailPart, AdapterPart, ModelsPart,
44
+ };
45
+ export { el, frag, render } from './dom.js';
46
+
47
+ // The engine's whole public API, re-exported so the workspace UMD bundle is a
48
+ // superset of the main one: a page that loads renderengine-workspace.umd.js
49
+ // gets both the shell and RenderEngine from a single script tag, instead of
50
+ // having to load two bundles in the right order. A star export rather than a
51
+ // list, so nothing the engine adds can go missing here; this module's own
52
+ // exports take precedence over any of the same name.
53
+ export * from '../index.js';
54
+ export {
55
+ BUILTIN_THEMES, SYSTEM_THEME, THEME_VARS,
56
+ LIGHT_THEME, DARK_THEME, MIDNIGHT_THEME, SEPIA_THEME,
57
+ } from './themes.js';
58
+ export { ChartPart } from './parts/ChartPart.js';
59
+ export { EditorPart } from './parts/EditorPart.js';
60
+ export { DiagramEditorPart } from './parts/DiagramEditorPart.js';
61
+ export { ArchimateEditorPart } from './parts/ArchimateEditorPart.js';
62
+ export { ArchimateCanvasPart } from './parts/ArchimateCanvasPart.js';
63
+ export { ARCHIMATE_SERVICES } from './archimateServices.js';
64
+ export { EditorShell } from './EditorShell.js';
65
+ export {
66
+ createLayout, LayoutNode, PartNode, SplitNode, TabsNode, GridNode,
67
+ GRID_COLS, ROW_UNIT_PX, GRID_GAP_PX,
68
+ MIN_COL_SPAN, MIN_ROW_SPAN, DEFAULT_COL_SPAN, DEFAULT_ROW_SPAN,
69
+ } from './layout/index.js';
70
+ export { WORKSPACE_CSS, ensureStyles } from './styles.js';
71
+ export { WorkArea } from './workArea.js';
72
+ export {
73
+ emptyWorkArea, listGroups, listOpenParts, findPart, resolveGroup,
74
+ openPart, closePart, focusPart,
75
+ } from './workAreaModel.js';
@@ -0,0 +1,280 @@
1
+ import { LayoutNode } from './LayoutNode.js';
2
+ import { el, render } from '../dom.js';
3
+
4
+ /**
5
+ * GridNode — a 12-column grid of draggable, resizable panes.
6
+ *
7
+ * The geometry, snapping, collision-swap and "crystallize" behaviour here are
8
+ * lifted from sqlengine workbench's `dashboard.js`, which is where this model
9
+ * was proven in production. Keeping the numbers and the semantics identical is
10
+ * deliberate: it is what lets an existing dashboard document load into this
11
+ * shell unchanged, via `GridNode.migrateChildren()`.
12
+ *
13
+ * A child's placement lives in `child.spec.layout = {col, row, colSpan, rowSpan}`.
14
+ * `col`/`row` are 1-based and stay undefined until a pane is actually dragged,
15
+ * so an untouched grid flows left-to-right via native CSS grid auto-placement.
16
+ * The first drag or resize on ANY pane crystallizes the whole grid — every
17
+ * pane's currently rendered position is captured into explicit col/row — so
18
+ * pinned and auto-flowing panes are never mixed after that point.
19
+ */
20
+
21
+ export const GRID_COLS = 12;
22
+ export const ROW_UNIT_PX = 20; // must match .ws-grid's grid-auto-rows
23
+ export const GRID_GAP_PX = 14; // must match .ws-grid's gap
24
+ export const MIN_COL_SPAN = 2;
25
+ export const MIN_ROW_SPAN = 4;
26
+ export const DEFAULT_COL_SPAN = 6;
27
+ export const DEFAULT_ROW_SPAN = 9;
28
+
29
+ /** Old dashboard shape `{span: 1-4, height: 'sm'|'md'|'lg'}` → `{colSpan,rowSpan}`. */
30
+ const OLD_HEIGHT_TO_ROWS = { sm: 6, md: 9, lg: 13 };
31
+
32
+ const clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
33
+
34
+ function rectsOverlap(a, b) {
35
+ if (a.col == null || b.col == null) return false;
36
+ return a.col < b.col + b.colSpan && a.col + a.colSpan > b.col &&
37
+ a.row < b.row + b.rowSpan && a.row + a.rowSpan > b.row;
38
+ }
39
+
40
+ export class GridNode extends LayoutNode {
41
+ static type = 'grid';
42
+
43
+ /**
44
+ * Convert legacy `{span, height}` child layouts in place. Returns true if
45
+ * anything was converted, so the caller knows to persist the migration
46
+ * rather than re-derive it on every load.
47
+ */
48
+ static migrateChildren(children) {
49
+ let migrated = false;
50
+ for (const child of children ?? []) {
51
+ const old = child.layout ?? {};
52
+ if (old.colSpan != null) continue;
53
+ child.layout = {
54
+ colSpan: clamp((old.span ?? 2) * 3, MIN_COL_SPAN, GRID_COLS),
55
+ rowSpan: OLD_HEIGHT_TO_ROWS[old.height ?? 'md'] ?? DEFAULT_ROW_SPAN,
56
+ };
57
+ migrated = true;
58
+ }
59
+ return migrated;
60
+ }
61
+
62
+ constructor(spec = {}) {
63
+ super(spec);
64
+ this.cols = spec.cols ?? GRID_COLS;
65
+ this.movable = spec.movable !== false;
66
+ this.resizable = spec.resizable !== false;
67
+ for (const child of this.children) {
68
+ const l = child.spec.layout ?? (child.spec.layout = {});
69
+ l.colSpan ??= DEFAULT_COL_SPAN;
70
+ l.rowSpan ??= DEFAULT_ROW_SPAN;
71
+ }
72
+ this._panes = [];
73
+ }
74
+
75
+ build(ctx) {
76
+ this.el.classList.add('ws-grid');
77
+ this.el.style.gridTemplateColumns = `repeat(${this.cols}, minmax(0, 1fr))`;
78
+ this._panes = [];
79
+
80
+ this.children.forEach((child) => {
81
+ let header, body;
82
+ const paneEl = this.el.appendChild(el({
83
+ cls: 'ws-pane',
84
+ children: [
85
+ { cls: 'ws-pane-header', attrs: { title: this.movable ? 'Drag to move' : null },
86
+ ref: n => { header = n; } },
87
+ { cls: 'ws-pane-body', ref: n => { body = n; } },
88
+ ],
89
+ }));
90
+ this._panes.push(paneEl);
91
+ this._applyPlacement(paneEl, child.spec.layout);
92
+
93
+ child.render(body, ctx);
94
+ child.activate?.();
95
+ // After render(): a PartNode only resolves its part — and therefore
96
+ // its title and actions — during render(), so building the header
97
+ // earlier would show the raw part id and no buttons.
98
+ this._buildPaneHeader(header, child);
99
+
100
+ if (this.movable) this._attachDragMove(paneEl, header, child);
101
+ if (this.resizable) this._attachResize(paneEl, child);
102
+ });
103
+ }
104
+
105
+ activate() {
106
+ for (const child of this.children) child.activate?.();
107
+ }
108
+
109
+ /**
110
+ * Title plus the part's own pane actions (rename, refresh, close, …).
111
+ *
112
+ * Actions come from the mounted Part, not from the layout spec: they carry
113
+ * callbacks, and the layout tree has to stay serializable JSON. `_attachDragMove`
114
+ * already ignores pointerdowns inside `.ws-pane-controls`, so a button click
115
+ * never starts a pane drag.
116
+ */
117
+ _buildPaneHeader(header, child) {
118
+ const actions = child.paneActions?.() ?? [];
119
+ render(header, [
120
+ { tag: 'span', cls: 'ws-pane-title', text: child.label?.() ?? child.spec?.title ?? '',
121
+ attrs: { title: child.paneTooltip?.() ?? null } },
122
+ ...(actions.length ? [{
123
+ tag: 'span', cls: 'ws-pane-controls',
124
+ children: actions.map(a => ({
125
+ tag: 'button',
126
+ cls: 'ws-pane-btn',
127
+ text: a.label,
128
+ attrs: { type: 'button', title: a.title ?? a.label },
129
+ on: { click: (e) => { e.stopPropagation(); a.onClick?.(e); } },
130
+ })),
131
+ }] : []),
132
+ ]);
133
+ }
134
+
135
+ _applyPlacement(paneEl, l) {
136
+ paneEl.style.gridColumn = l.col != null ? `${l.col} / span ${l.colSpan}` : `span ${l.colSpan}`;
137
+ paneEl.style.gridRow = l.row != null ? `${l.row} / span ${l.rowSpan}` : `span ${l.rowSpan}`;
138
+ }
139
+
140
+ /** Re-apply every pane's placement after a move/resize commits. */
141
+ _restyleAll() {
142
+ this.children.forEach((child, i) => {
143
+ const paneEl = this._panes[i];
144
+ if (paneEl) this._applyPlacement(paneEl, child.spec.layout);
145
+ });
146
+ }
147
+
148
+ _metrics() {
149
+ const rect = this.el.getBoundingClientRect();
150
+ const colWidth = (rect.width - GRID_GAP_PX * (this.cols - 1)) / this.cols;
151
+ return { rect, colWidth, rowHeight: ROW_UNIT_PX, gap: GRID_GAP_PX };
152
+ }
153
+
154
+ /**
155
+ * Capture every pane's currently rendered position into explicit col/row if
156
+ * any pane lacks one. Visually a no-op — see the class doc for why the
157
+ * whole grid is pinned at once rather than per pane.
158
+ */
159
+ _crystallizeIfNeeded() {
160
+ if (!this.children.some(c => c.spec.layout.col == null || c.spec.layout.row == null)) return;
161
+ const { rect, colWidth, rowHeight, gap } = this._metrics();
162
+ this.children.forEach((child, i) => {
163
+ const l = child.spec.layout;
164
+ if (l.col != null && l.row != null) return;
165
+ const paneEl = this._panes[i];
166
+ if (!paneEl) return;
167
+ const r = paneEl.getBoundingClientRect();
168
+ l.col = Math.max(1, Math.round((r.left - rect.left) / (colWidth + gap)) + 1);
169
+ l.row = Math.max(1, Math.round((r.top - rect.top) / (rowHeight + gap)) + 1);
170
+ });
171
+ }
172
+
173
+ _attachDragMove(paneEl, header, child) {
174
+ header.addEventListener('pointerdown', (e) => {
175
+ if (e.button !== 0 || e.target.closest('.ws-pane-controls')) return;
176
+ this._crystallizeIfNeeded();
177
+ const l = child.spec.layout;
178
+ const { colWidth, rowHeight, gap } = this._metrics();
179
+ const startX = e.clientX, startY = e.clientY;
180
+ const startCol = l.col, startRow = l.row;
181
+ header.setPointerCapture(e.pointerId);
182
+ paneEl.classList.add('ws-pane-dragging');
183
+
184
+ const onMove = (ev) => {
185
+ paneEl.style.transform = `translate(${ev.clientX - startX}px, ${ev.clientY - startY}px)`;
186
+ };
187
+ const onUp = (ev) => {
188
+ header.releasePointerCapture(e.pointerId);
189
+ header.removeEventListener('pointermove', onMove);
190
+ header.removeEventListener('pointerup', onUp);
191
+ header.removeEventListener('pointercancel', onUp);
192
+ paneEl.style.transform = '';
193
+ paneEl.classList.remove('ws-pane-dragging');
194
+
195
+ const colDelta = Math.round((ev.clientX - startX) / (colWidth + gap));
196
+ const rowDelta = Math.round((ev.clientY - startY) / (rowHeight + gap));
197
+ if (colDelta === 0 && rowDelta === 0) return; // a click, not a drag
198
+
199
+ const targetCol = clamp(startCol + colDelta, 1, this.cols - l.colSpan + 1);
200
+ const targetRow = Math.max(1, startRow + rowDelta);
201
+ const target = { col: targetCol, row: targetRow, colSpan: l.colSpan, rowSpan: l.rowSpan };
202
+
203
+ // Simple and predictable rather than a real bin-packer: landing
204
+ // on exactly one occupied pane swaps the two.
205
+ const occupant = this.children.find(c => c !== child && rectsOverlap(target, c.spec.layout));
206
+ if (occupant) {
207
+ const swapCol = occupant.spec.layout.col, swapRow = occupant.spec.layout.row;
208
+ occupant.spec.layout.col = l.col;
209
+ occupant.spec.layout.row = l.row;
210
+ l.col = swapCol;
211
+ l.row = swapRow;
212
+ } else {
213
+ l.col = targetCol;
214
+ l.row = targetRow;
215
+ }
216
+ this._restyleAll();
217
+ this._emitChange();
218
+ };
219
+ header.addEventListener('pointermove', onMove);
220
+ header.addEventListener('pointerup', onUp);
221
+ header.addEventListener('pointercancel', onUp);
222
+ });
223
+ }
224
+
225
+ _attachResize(paneEl, child) {
226
+ const handle = paneEl.appendChild(el({
227
+ cls: 'ws-resize-handle',
228
+ text: '⤡',
229
+ attrs: { title: 'Drag to resize' },
230
+ }));
231
+
232
+ handle.addEventListener('pointerdown', (e) => {
233
+ if (e.button !== 0) return;
234
+ e.stopPropagation();
235
+ this._crystallizeIfNeeded();
236
+ const l = child.spec.layout;
237
+ const { colWidth, rowHeight, gap } = this._metrics();
238
+ const startX = e.clientX, startY = e.clientY;
239
+ const startColSpan = l.colSpan, startRowSpan = l.rowSpan;
240
+ const maxColSpan = this.cols - l.col + 1;
241
+ handle.setPointerCapture(e.pointerId);
242
+ paneEl.classList.add('ws-pane-dragging');
243
+
244
+ const computeSpans = (ev) => ({
245
+ colSpan: clamp(startColSpan + Math.round((ev.clientX - startX) / (colWidth + gap)), MIN_COL_SPAN, maxColSpan),
246
+ rowSpan: Math.max(MIN_ROW_SPAN, startRowSpan + Math.round((ev.clientY - startY) / (rowHeight + gap))),
247
+ });
248
+ const onMove = (ev) => {
249
+ const { colSpan, rowSpan } = computeSpans(ev);
250
+ paneEl.style.gridColumn = `${l.col} / span ${colSpan}`;
251
+ paneEl.style.gridRow = `${l.row} / span ${rowSpan}`;
252
+ };
253
+ const onUp = (ev) => {
254
+ handle.releasePointerCapture(e.pointerId);
255
+ handle.removeEventListener('pointermove', onMove);
256
+ handle.removeEventListener('pointerup', onUp);
257
+ handle.removeEventListener('pointercancel', onUp);
258
+ paneEl.classList.remove('ws-pane-dragging');
259
+ const { colSpan, rowSpan } = computeSpans(ev);
260
+ l.colSpan = colSpan;
261
+ l.rowSpan = rowSpan;
262
+ this._restyleAll();
263
+ this._emitChange();
264
+ };
265
+ handle.addEventListener('pointermove', onMove);
266
+ handle.addEventListener('pointerup', onUp);
267
+ handle.addEventListener('pointercancel', onUp);
268
+ });
269
+ }
270
+
271
+ serialize() {
272
+ return {
273
+ type: GridNode.type,
274
+ cols: this.cols,
275
+ ...(this.movable ? {} : { movable: false }),
276
+ ...(this.resizable ? {} : { resizable: false }),
277
+ children: this.children.map(c => c.serialize()),
278
+ };
279
+ }
280
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * LayoutNode — base class for the layout tree.
3
+ *
4
+ * One subclass per node kind, one file each: SplitNode, TabsNode, GridNode,
5
+ * PartNode. The serialized form carries a `type` discriminator because JSON has
6
+ * no classes; `LayoutNode.create()` maps it back. Subclasses import only this
7
+ * base and call `LayoutNode.create()` for their children, so there is no import
8
+ * cycle with `layout/index.js` (which is what populates the type table).
9
+ */
10
+ import { el } from '../dom.js';
11
+
12
+ export class LayoutNode {
13
+ /** Discriminator used in serialized form. Every subclass overrides this. */
14
+ static type = null;
15
+
16
+ /** @type {Map<string, typeof LayoutNode>} populated by layout/index.js */
17
+ static _types = new Map();
18
+
19
+ static registerType(NodeClass) {
20
+ if (!NodeClass?.type) throw new Error(`Layout node ${NodeClass?.name} has no static type`);
21
+ LayoutNode._types.set(NodeClass.type, NodeClass);
22
+ }
23
+
24
+ /** Build a node (and its subtree) from a plain-JSON descriptor. */
25
+ static create(json) {
26
+ if (json instanceof LayoutNode) return json;
27
+ const NodeClass = LayoutNode._types.get(json?.type);
28
+ if (!NodeClass) {
29
+ throw new Error(`Unknown layout node type "${json?.type}" (known: ${[...LayoutNode._types.keys()].join(', ') || 'none'})`);
30
+ }
31
+ return new NodeClass(json);
32
+ }
33
+
34
+ constructor(spec = {}) {
35
+ if (new.target === LayoutNode) throw new TypeError('LayoutNode is abstract — subclass it');
36
+ this.spec = spec;
37
+ /** @type {LayoutNode[]} */
38
+ this.children = (spec.children ?? []).map(c => LayoutNode.create(c));
39
+ /** @type {HTMLElement|null} this node's own root element */
40
+ this.el = null;
41
+ this.ctx = null;
42
+ }
43
+
44
+ /**
45
+ * Build DOM into `host`. Subclasses override `build()`, not this — this
46
+ * handles the common element/ctx bookkeeping.
47
+ */
48
+ render(host, ctx) {
49
+ this.ctx = ctx;
50
+ // `ws-node-<type>`, not `ws-<type>` — the latter would give a PartNode
51
+ // the class `ws-part`, which is what a mounted Part names its own root.
52
+ this.el = host.appendChild(el({ cls: ['ws-node', `ws-node-${this.constructor.type}`] }));
53
+ this.build(ctx);
54
+ return this.el;
55
+ }
56
+
57
+ /** Subclasses implement. `this.el` is attached and empty. */
58
+ build() {
59
+ throw new Error(`${this.constructor.name} must implement build()`);
60
+ }
61
+
62
+ /**
63
+ * Detach this node's DOM. Does NOT dispose parts — part lifetime belongs to
64
+ * the PartRegistry pool so instances survive a perspective switch (see
65
+ * PartRegistry.disposeExcept).
66
+ */
67
+ dispose() {
68
+ for (const child of this.children) child.dispose();
69
+ if (this.el?.parentNode) this.el.parentNode.removeChild(this.el);
70
+ this.el = null;
71
+ this.ctx = null;
72
+ }
73
+
74
+ /** Every part id referenced in this subtree. */
75
+ partIds() {
76
+ return this.children.flatMap(c => c.partIds());
77
+ }
78
+
79
+ serialize() {
80
+ const out = { ...this.spec, type: this.constructor.type };
81
+ if (this.children.length) out.children = this.children.map(c => c.serialize());
82
+ return out;
83
+ }
84
+
85
+ /** Notify the shell that geometry changed and should be persisted. */
86
+ _emitChange() {
87
+ this.ctx?.onLayoutChange?.();
88
+ }
89
+ }
@@ -0,0 +1,77 @@
1
+ import { LayoutNode } from './LayoutNode.js';
2
+ import { render } from '../dom.js';
3
+
4
+ /**
5
+ * PartNode — leaf of the layout tree. Resolves `partId` against the shell's
6
+ * PartRegistry pool and mounts that part into its own container.
7
+ *
8
+ * Mounting is lazy: `build()` only creates the container. `activate()` does the
9
+ * actual `part.mount()`, and TabsNode calls it when a tab is first shown. Once
10
+ * mounted the part stays mounted (see Part's class doc) — lazy-then-permanent,
11
+ * not mount/unmount per switch. Nodes outside a TabsNode are activated
12
+ * immediately by their parent.
13
+ */
14
+ export class PartNode extends LayoutNode {
15
+ static type = 'part';
16
+
17
+ constructor(spec = {}) {
18
+ super(spec);
19
+ this.partId = spec.partId ?? spec.id;
20
+ if (!this.partId) throw new Error('PartNode requires a partId');
21
+ this.part = null;
22
+ }
23
+
24
+ build(ctx) {
25
+ this.el.classList.add('ws-part-host');
26
+ this.el.dataset.partId = this.partId;
27
+ this.part = ctx.registry.get(this.partId);
28
+ if (!this.part) {
29
+ render(this.el, { cls: 'ws-part-missing', text: `Unknown part: ${this.partId}` });
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Mount the part, or re-parent it if it is already live (pooled across a
35
+ * perspective switch). Idempotent.
36
+ */
37
+ activate() {
38
+ if (!this.part) return;
39
+ try {
40
+ this.part.mount(this.el, this.ctx);
41
+ } catch (err) {
42
+ console.error(`PartNode: part "${this.partId}" failed to mount`, err);
43
+ render(this.el, { cls: 'ws-part-missing', text: `Part "${this.partId}" failed to mount — see console.` });
44
+ }
45
+ }
46
+
47
+ /** Title for a tab strip / pane header. */
48
+ label() {
49
+ return this.part?.title ?? this.spec.title ?? this.partId;
50
+ }
51
+
52
+ /** Pane-header buttons contributed by the mounted part. */
53
+ paneActions() {
54
+ return this.part?.actions ?? [];
55
+ }
56
+
57
+ /** Hover text for the pane title. */
58
+ paneTooltip() {
59
+ return this.part?.paneTooltip ?? null;
60
+ }
61
+
62
+ dispose() {
63
+ // Detach the part's element without disposing the instance — the pool
64
+ // decides whether it survives the perspective switch, and detach()
65
+ // keeps its DOM (and therefore its state) intact either way.
66
+ this.part?.detach();
67
+ super.dispose();
68
+ }
69
+
70
+ partIds() {
71
+ return [this.partId];
72
+ }
73
+
74
+ serialize() {
75
+ return { type: PartNode.type, partId: this.partId, ...(this.spec.layout ? { layout: { ...this.spec.layout } } : {}) };
76
+ }
77
+ }