@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.
- package/LICENSE +21 -0
- package/README.md +203 -2
- package/REFERENCE.md +2198 -0
- package/dist/renderengine-workspace.umd.js +46905 -0
- package/dist/renderengine.umd.js +42223 -0
- package/examples/archimate.html +66 -0
- package/examples/diagram-editor.html +51 -0
- package/package.json +65 -4
- package/src/BaseRenderer.js +57 -0
- package/src/CanvasRenderer.js +194 -0
- package/src/Mat4.js +111 -0
- package/src/OrbitCamera.js +57 -0
- package/src/RendererFactory.js +50 -0
- package/src/SVGRenderer.js +439 -0
- package/src/archimate.js +723 -0
- package/src/archimateArchiFormat.js +1693 -0
- package/src/archimateArchiTypes.js +72 -0
- package/src/archimateArchive.js +140 -0
- package/src/archimateCSV.js +127 -0
- package/src/archimateDrawio.js +182 -0
- package/src/archimateExchangeFormat.js +546 -0
- package/src/archimateRelationshipTable.js +93 -0
- package/src/archimateSpecializations.js +161 -0
- package/src/chartCatalog.js +589 -0
- package/src/charting/ArchimateDiagramEditor.js +1624 -0
- package/src/charting/ArchimateSpecializationSelector.js +134 -0
- package/src/charting/Axis.js +68 -0
- package/src/charting/CameraSeeder.js +30 -0
- package/src/charting/CatalogDialog.js +92 -0
- package/src/charting/Chart.js +37 -0
- package/src/charting/Chart3D.js +99 -0
- package/src/charting/ChartBox.js +80 -0
- package/src/charting/ChartData.js +27 -0
- package/src/charting/ChartRegistry.js +76 -0
- package/src/charting/CheckboxTreeSelector.js +304 -0
- package/src/charting/ColorField.js +107 -0
- package/src/charting/ColorPalette.js +88 -0
- package/src/charting/CommandHistory.js +176 -0
- package/src/charting/DataFilter.js +52 -0
- package/src/charting/Diagram.js +36 -0
- package/src/charting/Diagram3D.js +29 -0
- package/src/charting/DiagramClipboard.js +31 -0
- package/src/charting/DiagramEditor.js +3330 -0
- package/src/charting/DiagramEditorCommand.js +110 -0
- package/src/charting/DiagramEditorCommands.js +237 -0
- package/src/charting/DiagramEditorEdgeCommands.js +142 -0
- package/src/charting/DiagramEditorState.js +98 -0
- package/src/charting/DiagramRegistry.js +86 -0
- package/src/charting/DiagramTypeRegistry.js +326 -0
- package/src/charting/DiagramViewPropertiesDialog.js +46 -0
- package/src/charting/Edge.js +113 -0
- package/src/charting/ErrorBars.js +37 -0
- package/src/charting/FilterSystem.js +285 -0
- package/src/charting/FindReplaceDialog.js +139 -0
- package/src/charting/FormDialog.js +385 -0
- package/src/charting/Gauge.js +58 -0
- package/src/charting/Hierarchy.js +175 -0
- package/src/charting/HintPanel.js +86 -0
- package/src/charting/ImageSelector.js +148 -0
- package/src/charting/InteractionManager.js +725 -0
- package/src/charting/Legend.js +58 -0
- package/src/charting/MenuBar.js +62 -0
- package/src/charting/ModelFileFormat.js +115 -0
- package/src/charting/OrbitControls.js +77 -0
- package/src/charting/Palette.js +119 -0
- package/src/charting/PopupMenu.js +117 -0
- package/src/charting/PropertiesPanel.js +155 -0
- package/src/charting/PropertyListEditor.js +96 -0
- package/src/charting/PropertyLog.js +92 -0
- package/src/charting/SettingsCascade.js +93 -0
- package/src/charting/SettingsDialog.js +53 -0
- package/src/charting/SettingsManager.js +179 -0
- package/src/charting/SettingsViewPropertiesDialog.js +58 -0
- package/src/charting/ShapePaths.js +27 -0
- package/src/charting/Statistics.js +134 -0
- package/src/charting/TemplateCatalog.js +59 -0
- package/src/charting/TemplateLibrary.js +103 -0
- package/src/charting/TextStyle.js +168 -0
- package/src/charting/ViewFit.js +55 -0
- package/src/charting/ViewMenu.js +70 -0
- package/src/charting/ViewPropertiesDialog.js +77 -0
- package/src/charting/ViewTabStrip.js +81 -0
- package/src/charting/archimate/ArchiFileFormat.js +32 -0
- package/src/charting/archimate/ArchimateCanvasEditor.js +815 -0
- package/src/charting/archimate/ArchimateCsvFileFormat.js +35 -0
- package/src/charting/archimate/ArchimateEdge.js +137 -0
- package/src/charting/archimate/ArchimateElementTemplate.js +195 -0
- package/src/charting/archimate/ArchimatePalette.js +102 -0
- package/src/charting/archimate/CsvImportDialog.js +105 -0
- package/src/charting/archimate/CustomViewpoints.js +74 -0
- package/src/charting/archimate/DerivedEdge.js +29 -0
- package/src/charting/archimate/DrawioFileFormat.js +24 -0
- package/src/charting/archimate/ElementFilterRule.js +21 -0
- package/src/charting/archimate/ExchangeFileFormat.js +28 -0
- package/src/charting/archimate/ViewGroupTemplate.js +137 -0
- package/src/charting/archimate/ViewLineEdge.js +84 -0
- package/src/charting/archimate/ViewpointRule.js +45 -0
- package/src/charting/archimate/archimateFileFormats.js +12 -0
- package/src/charting/archimate/archimateNames.js +5 -0
- package/src/charting/archimate/csvMapping.js +122 -0
- package/src/charting/archimate/elementMenuItems.js +32 -0
- package/src/charting/archimate/elementProperties.js +146 -0
- package/src/charting/archimate/elementTypeChoices.js +7 -0
- package/src/charting/archimate/elementTypeGroups.js +19 -0
- package/src/charting/archimate/index.js +17 -0
- package/src/charting/archimate/specializationCatalogDialog.js +64 -0
- package/src/charting/archimate/typeGlyph.js +29 -0
- package/src/charting/arrangement/Arrangement.js +112 -0
- package/src/charting/arrangement/ArrangementCommand.js +29 -0
- package/src/charting/arrangement/BackgroundCommand.js +41 -0
- package/src/charting/arrangement/BackgroundGroup.js +18 -0
- package/src/charting/arrangement/GroupCommand.js +46 -0
- package/src/charting/arrangement/ItemGroup.js +62 -0
- package/src/charting/arrangement/LockCommand.js +32 -0
- package/src/charting/arrangement/UngroupCommand.js +27 -0
- package/src/charting/arrangement/alignment.js +88 -0
- package/src/charting/arrangement/arrangeMenuItems.js +25 -0
- package/src/charting/arrangement/index.js +11 -0
- package/src/charting/arrangement/layouts.js +233 -0
- package/src/charting/canvas/ArchiHint.js +78 -0
- package/src/charting/canvas/CanvasBoxKind.js +39 -0
- package/src/charting/canvas/CanvasPalette.js +49 -0
- package/src/charting/canvas/CanvasTemplateLibrary.js +61 -0
- package/src/charting/canvas/CanvasTemplateMenu.js +151 -0
- package/src/charting/canvas/EditHintCommand.js +28 -0
- package/src/charting/canvas/canvasBoxKinds.js +27 -0
- package/src/charting/canvas/canvasBoxMenuItems.js +40 -0
- package/src/charting/canvas/defaultCanvasTemplates.js +186 -0
- package/src/charting/canvas/diagramBoxKinds.js +12 -0
- package/src/charting/canvas/hintMenuItems.js +49 -0
- package/src/charting/charts/ArcGauge.js +55 -0
- package/src/charting/charts/AreaChart.js +71 -0
- package/src/charting/charts/BarChart.js +80 -0
- package/src/charting/charts/BarChart3D.js +56 -0
- package/src/charting/charts/BarChart3DOrbit.js +53 -0
- package/src/charting/charts/BarChartBase.js +70 -0
- package/src/charting/charts/BarGauge.js +42 -0
- package/src/charting/charts/BoxPlotChart.js +41 -0
- package/src/charting/charts/BubbleChart.js +99 -0
- package/src/charting/charts/BubbleChart3D.js +78 -0
- package/src/charting/charts/BulletGauge.js +87 -0
- package/src/charting/charts/CalendarHeatmapChart.js +204 -0
- package/src/charting/charts/CandlestickChart.js +54 -0
- package/src/charting/charts/ChordDiagram.js +130 -0
- package/src/charting/charts/DensityChart.js +73 -0
- package/src/charting/charts/DialGauge.js +65 -0
- package/src/charting/charts/DonutChart.js +15 -0
- package/src/charting/charts/FunnelChart.js +47 -0
- package/src/charting/charts/GanttChart.js +201 -0
- package/src/charting/charts/GaugeChart.js +175 -0
- package/src/charting/charts/GeoMapChart.js +146 -0
- package/src/charting/charts/GroupedBarChart.js +88 -0
- package/src/charting/charts/GroupedDistributionChart.js +70 -0
- package/src/charting/charts/HeatmapChart.js +80 -0
- package/src/charting/charts/HierarchyChart.js +39 -0
- package/src/charting/charts/HistogramChart.js +45 -0
- package/src/charting/charts/KpiTile.js +72 -0
- package/src/charting/charts/LagPlotChart.js +41 -0
- package/src/charting/charts/LineChart.js +124 -0
- package/src/charting/charts/MultiRingGauge.js +54 -0
- package/src/charting/charts/OutlineChart.js +95 -0
- package/src/charting/charts/ParallelCoordinatesChart.js +130 -0
- package/src/charting/charts/PieChart.js +56 -0
- package/src/charting/charts/PipeChart.js +88 -0
- package/src/charting/charts/PopulationPyramidChart.js +106 -0
- package/src/charting/charts/QQPlotChart.js +64 -0
- package/src/charting/charts/RadarChart.js +76 -0
- package/src/charting/charts/RadialBarChart.js +96 -0
- package/src/charting/charts/RingGauge.js +23 -0
- package/src/charting/charts/SankeyDiagram.js +174 -0
- package/src/charting/charts/ScatterChart.js +104 -0
- package/src/charting/charts/StackedAreaChart.js +15 -0
- package/src/charting/charts/StackedBarChart.js +33 -0
- package/src/charting/charts/StackedBarChart3DOrbit.js +58 -0
- package/src/charting/charts/StreamGraphChart.js +131 -0
- package/src/charting/charts/SunburstChart.js +57 -0
- package/src/charting/charts/ThermometerGauge.js +43 -0
- package/src/charting/charts/TreemapChart.js +54 -0
- package/src/charting/charts/ViolinChart.js +37 -0
- package/src/charting/charts/WaterfallChart.js +66 -0
- package/src/charting/charts/WordCloudChart.js +104 -0
- package/src/charting/diagramModel/AddViewCommand.js +33 -0
- package/src/charting/diagramModel/DiagramModel.js +39 -0
- package/src/charting/diagramModel/DiagramModelSearch.js +22 -0
- package/src/charting/diagramModel/DiagramView.js +50 -0
- package/src/charting/diagramModel/ModelHistory.js +43 -0
- package/src/charting/diagramModel/ModelReport.js +153 -0
- package/src/charting/diagramModel/ModelSearch.js +223 -0
- package/src/charting/diagramModel/RemoveViewCommand.js +25 -0
- package/src/charting/diagramModel/RenameViewCommand.js +21 -0
- package/src/charting/diagramModel/ReplaceTextCommand.js +25 -0
- package/src/charting/diagramModel/ViewSetChecker.js +34 -0
- package/src/charting/diagramModel/ViewSetModel.js +243 -0
- package/src/charting/diagramModel/index.js +6 -0
- package/src/charting/diagramModel/nameTransforms.js +29 -0
- package/src/charting/diagrams/ArchimateCommands.js +141 -0
- package/src/charting/diagrams/ArchimateDiagram.js +263 -0
- package/src/charting/diagrams/ArchimateModel.js +1155 -0
- package/src/charting/diagrams/ArchimateModelChecker.js +125 -0
- package/src/charting/diagrams/ArchimateModelReport.js +128 -0
- package/src/charting/diagrams/ArchimateModelSearch.js +41 -0
- package/src/charting/diagrams/ArchimateValidator.js +357 -0
- package/src/charting/diagrams/CanvasView.js +112 -0
- package/src/charting/diagrams/ContextMenu.js +37 -0
- package/src/charting/diagrams/DataModelDiagram.js +86 -0
- package/src/charting/diagrams/DataModelRelationshipStrategy.js +38 -0
- package/src/charting/diagrams/DerivedRelationships.js +102 -0
- package/src/charting/diagrams/EbnfDiagram.js +39 -0
- package/src/charting/diagrams/EdgeGeometry.js +553 -0
- package/src/charting/diagrams/EditViewItemCommand.js +128 -0
- package/src/charting/diagrams/ElementInstance.js +157 -0
- package/src/charting/diagrams/GraphDiagram.js +1340 -0
- package/src/charting/diagrams/GraphDiagram3D.js +152 -0
- package/src/charting/diagrams/GraphMetrics.js +81 -0
- package/src/charting/diagrams/GridOverlay.js +137 -0
- package/src/charting/diagrams/ImportRowsCommand.js +62 -0
- package/src/charting/diagrams/LabelHelper.js +108 -0
- package/src/charting/diagrams/MergeElementsCommand.js +101 -0
- package/src/charting/diagrams/NestInstanceCommand.js +34 -0
- package/src/charting/diagrams/NodeGeometry.js +158 -0
- package/src/charting/diagrams/PlaceItemsCommand.js +77 -0
- package/src/charting/diagrams/RadialLayout.js +101 -0
- package/src/charting/diagrams/RelationshipInstance.js +93 -0
- package/src/charting/diagrams/RemoveGroupFromViewCommand.js +28 -0
- package/src/charting/diagrams/RemoveLineCommand.js +27 -0
- package/src/charting/diagrams/ShowElementCommand.js +43 -0
- package/src/charting/diagrams/SvgCoordinate.js +17 -0
- package/src/charting/diagrams/SvgZoom.js +127 -0
- package/src/charting/diagrams/Tooltip.js +62 -0
- package/src/charting/diagrams/ViewConnectionInstance.js +102 -0
- package/src/charting/diagrams/ViewObjectInstance.js +56 -0
- package/src/charting/diagrams/commands/AddEdgeCommand.js +34 -0
- package/src/charting/diagrams/commands/AddNodeCommand.js +28 -0
- package/src/charting/diagrams/commands/AddWaypointCommand.js +27 -0
- package/src/charting/diagrams/commands/CreateFolderCommand.js +27 -0
- package/src/charting/diagrams/commands/DeleteEdgeCommand.js +30 -0
- package/src/charting/diagrams/commands/DeleteFolderCommand.js +47 -0
- package/src/charting/diagrams/commands/DeleteNodeCommand.js +35 -0
- package/src/charting/diagrams/commands/DeleteWaypointCommand.js +24 -0
- package/src/charting/diagrams/commands/GraphCommand.js +65 -0
- package/src/charting/diagrams/commands/InvertEdgeCommand.js +24 -0
- package/src/charting/diagrams/commands/MoveNodeCommand.js +44 -0
- package/src/charting/diagrams/commands/MoveWaypointCommand.js +27 -0
- package/src/charting/diagrams/commands/RenameEdgeCommand.js +23 -0
- package/src/charting/diagrams/commands/RenameFolderCommand.js +31 -0
- package/src/charting/diagrams/commands/RenameNodeCommand.js +27 -0
- package/src/charting/diagrams/commands/ResizeNodeCommand.js +46 -0
- package/src/charting/diagrams/commands/UpdateEdgeSideCommand.js +40 -0
- package/src/charting/diagrams/commands/index.js +17 -0
- package/src/charting/diagrams/duplicates.js +49 -0
- package/src/charting/diagrams/nesting.js +30 -0
- package/src/charting/diagrams/roadmap.js +77 -0
- package/src/charting/edgeMarkers/ArrowMarker.js +15 -0
- package/src/charting/edgeMarkers/CircleMarker.js +13 -0
- package/src/charting/edgeMarkers/CrowsFootMarker.js +16 -0
- package/src/charting/edgeMarkers/DiamondMarker.js +15 -0
- package/src/charting/edgeMarkers/EdgeMarker.js +34 -0
- package/src/charting/edgeMarkers/HalfArrowMarker.js +8 -0
- package/src/charting/edgeMarkers/HollowDiamondMarker.js +18 -0
- package/src/charting/edgeMarkers/HollowTriangleMarker.js +18 -0
- package/src/charting/edgeMarkers/OpenArrowMarker.js +17 -0
- package/src/charting/edgeMarkers/index.js +27 -0
- package/src/charting/edgeStyle/EdgeStyleCascade.js +22 -0
- package/src/charting/edgeStyle/EdgeStyleDialog.js +51 -0
- package/src/charting/edgeStyle/EdgeStyleSchema.js +43 -0
- package/src/charting/edgeStyle/SetStyleCommand.js +12 -0
- package/src/charting/edgeStyle/index.js +4 -0
- package/src/charting/emphasis/EmphasisRule.js +42 -0
- package/src/charting/emphasis/HighlightRule.js +24 -0
- package/src/charting/gauges/ArcTrack.js +51 -0
- package/src/charting/gauges/GaugeAnimation.js +51 -0
- package/src/charting/gauges/GaugeBands.js +48 -0
- package/src/charting/gauges/GaugeScale.js +87 -0
- package/src/charting/gauges/GaugeTrack.js +44 -0
- package/src/charting/gauges/GaugeValue.js +61 -0
- package/src/charting/gauges/HorizontalTrack.js +14 -0
- package/src/charting/gauges/LinearTrack.js +29 -0
- package/src/charting/gauges/Sparkline.js +42 -0
- package/src/charting/gauges/VerticalTrack.js +17 -0
- package/src/charting/glyphs/ArrowGlyph.js +21 -0
- package/src/charting/glyphs/BatteryGlyph.js +18 -0
- package/src/charting/glyphs/ChevronGlyph.js +18 -0
- package/src/charting/glyphs/CircleGlyph.js +15 -0
- package/src/charting/glyphs/CloudGlyph.js +19 -0
- package/src/charting/glyphs/ComponentGlyph.js +18 -0
- package/src/charting/glyphs/ConstraintGlyph.js +24 -0
- package/src/charting/glyphs/ContractBoxGlyph.js +10 -0
- package/src/charting/glyphs/CubeGlyph.js +19 -0
- package/src/charting/glyphs/CylinderGlyph.js +19 -0
- package/src/charting/glyphs/DashedDoubleArrowGlyph.js +11 -0
- package/src/charting/glyphs/DeviceGlyph.js +17 -0
- package/src/charting/glyphs/DiamondGlyph.js +17 -0
- package/src/charting/glyphs/DocumentGlyph.js +17 -0
- package/src/charting/glyphs/DoubleArrowGlyph.js +23 -0
- package/src/charting/glyphs/DoubleCircleGlyph.js +24 -0
- package/src/charting/glyphs/EllipseGlyph.js +18 -0
- package/src/charting/glyphs/FactoryGlyph.js +20 -0
- package/src/charting/glyphs/FlagGlyph.js +16 -0
- package/src/charting/glyphs/GapCircleGlyph.js +17 -0
- package/src/charting/glyphs/GearGlyph.js +37 -0
- package/src/charting/glyphs/Glyph.js +98 -0
- package/src/charting/glyphs/GroupingBoxGlyph.js +13 -0
- package/src/charting/glyphs/HalfCircleGlyph.js +22 -0
- package/src/charting/glyphs/HexagonGlyph.js +28 -0
- package/src/charting/glyphs/IconGlyph.js +22 -0
- package/src/charting/glyphs/ImageGlyph.js +16 -0
- package/src/charting/glyphs/JunctionGlyph.js +17 -0
- package/src/charting/glyphs/LollipopGlyph.js +22 -0
- package/src/charting/glyphs/MagnifierGlyph.js +17 -0
- package/src/charting/glyphs/NoteGlyph.js +33 -0
- package/src/charting/glyphs/ObjectBoxGlyph.js +21 -0
- package/src/charting/glyphs/OrJunctionGlyph.js +17 -0
- package/src/charting/glyphs/ParallelogramGlyph.js +20 -0
- package/src/charting/glyphs/PersonGlyph.js +23 -0
- package/src/charting/glyphs/PillGlyph.js +23 -0
- package/src/charting/glyphs/PinGlyph.js +18 -0
- package/src/charting/glyphs/PrincipleGlyph.js +23 -0
- package/src/charting/glyphs/ProductBoxGlyph.js +16 -0
- package/src/charting/glyphs/RectGlyph.js +15 -0
- package/src/charting/glyphs/RoundedBoxGlyph.js +13 -0
- package/src/charting/glyphs/StackGlyph.js +14 -0
- package/src/charting/glyphs/StepsGlyph.js +20 -0
- package/src/charting/glyphs/StickFigureGlyph.js +32 -0
- package/src/charting/glyphs/SystemSoftwareBoxGlyph.js +16 -0
- package/src/charting/glyphs/TabbedBoxGlyph.js +37 -0
- package/src/charting/glyphs/TargetGlyph.js +23 -0
- package/src/charting/glyphs/WavyBoxGlyph.js +17 -0
- package/src/charting/glyphs/WheelGlyph.js +28 -0
- package/src/charting/glyphs/drawGlyph.js +28 -0
- package/src/charting/glyphs/glyphSvg.js +55 -0
- package/src/charting/glyphs/index.js +109 -0
- package/src/charting/modelTree/AnalysisPanel.js +159 -0
- package/src/charting/modelTree/DiagramTabs.js +217 -0
- package/src/charting/modelTree/ModelTree.js +164 -0
- package/src/charting/modelTree/ModelTreePanel.js +914 -0
- package/src/charting/modelTree/TreeBuilder.js +238 -0
- package/src/charting/modelTree/TreeModeRegistry.js +51 -0
- package/src/charting/modelTree/TreeViewMode.js +110 -0
- package/src/charting/modelTree/buildFilterTrees.js +138 -0
- package/src/charting/modelTree/modes/FlatTreeMode.js +46 -0
- package/src/charting/modelTree/modes/LayerGroupedTreeMode.js +62 -0
- package/src/charting/modelTree/modes/TypeGroupedTreeMode.js +60 -0
- package/src/charting/modelTree/treeLayers.js +11 -0
- package/src/charting/report/reportHtml.js +82 -0
- package/src/charting/report/reportViewer.js +118 -0
- package/src/charting/shapes/CircleShape.js +19 -0
- package/src/charting/shapes/PathShape.js +17 -0
- package/src/charting/shapes/RectShape.js +20 -0
- package/src/charting/shapes/Shape.js +20 -0
- package/src/charting/shapes/ShapeFactory.js +23 -0
- package/src/charting/storage/LocalJsonStore.js +43 -0
- package/src/charting/templates/ActorTemplate.js +36 -0
- package/src/charting/templates/BoxTemplate.js +27 -0
- package/src/charting/templates/CircleTemplate.js +18 -0
- package/src/charting/templates/ClassTemplate.js +20 -0
- package/src/charting/templates/CloudTemplate.js +43 -0
- package/src/charting/templates/ComponentTemplate.js +19 -0
- package/src/charting/templates/CylinderTemplate.js +30 -0
- package/src/charting/templates/DataStoreTemplate.js +16 -0
- package/src/charting/templates/DiamondTemplate.js +10 -0
- package/src/charting/templates/DocumentTemplate.js +32 -0
- package/src/charting/templates/EllipseTemplate.js +15 -0
- package/src/charting/templates/FinalStateTemplate.js +12 -0
- package/src/charting/templates/GlyphTemplate.js +47 -0
- package/src/charting/templates/HexagonTemplate.js +17 -0
- package/src/charting/templates/LifelineTemplate.js +20 -0
- package/src/charting/templates/ManualInputTemplate.js +12 -0
- package/src/charting/templates/NoteTemplate.js +23 -0
- package/src/charting/templates/OctagonTemplate.js +7 -0
- package/src/charting/templates/PackageTemplate.js +25 -0
- package/src/charting/templates/ParallelogramTemplate.js +11 -0
- package/src/charting/templates/PentagonTemplate.js +5 -0
- package/src/charting/templates/PolygonTemplate.js +18 -0
- package/src/charting/templates/PredefinedProcessTemplate.js +13 -0
- package/src/charting/templates/RectangleTemplate.js +28 -0
- package/src/charting/templates/RegularPolygonTemplate.js +21 -0
- package/src/charting/templates/RoundedRectangleTemplate.js +5 -0
- package/src/charting/templates/StadiumTemplate.js +8 -0
- package/src/charting/templates/StarTemplate.js +17 -0
- package/src/charting/templates/SwimlaneTemplate.js +18 -0
- package/src/charting/templates/Template.js +208 -0
- package/src/charting/templates/TrapezoidTemplate.js +11 -0
- package/src/charting/templates/TriangleTemplate.js +12 -0
- package/src/charting/templates/index.js +31 -0
- package/src/charting/templates/outline.js +59 -0
- package/src/charting/templates/svg.js +19 -0
- package/src/charting/textToShapes.js +61 -0
- package/src/charting/toolbar/ToolbarButton.js +38 -0
- package/src/charting/toolbar/ToolbarCheckbox.js +31 -0
- package/src/charting/toolbar/ToolbarItem.js +19 -0
- package/src/charting/toolbar/ToolbarMenu.js +36 -0
- package/src/charting/toolbar/ToolbarSelect.js +38 -0
- package/src/charting/toolbar/ToolbarSeparator.js +7 -0
- package/src/charting/toolbar/ToolbarText.js +22 -0
- package/src/charting/toolbar/index.js +8 -0
- package/src/charting/toolbar/pickFile.js +14 -0
- package/src/charting/viewDecorations.js +85 -0
- package/src/charting/zOrder.js +57 -0
- package/src/csvTable.js +61 -0
- package/src/datamodel.js +122 -0
- package/src/datawindow/BoundedWindow.js +36 -0
- package/src/datawindow/FlatDataWindow.js +34 -0
- package/src/datawindow/GraphDataWindow.js +40 -0
- package/src/datawindow/GroupedSampleDataWindow.js +16 -0
- package/src/datawindow/SeriesDataWindow.js +42 -0
- package/src/datawindow/index.js +31 -0
- package/src/diagramCatalog.js +30 -0
- package/src/ebnfDiagram.js +57 -0
- package/src/ebnfParser.js +129 -0
- package/src/exportImage.js +233 -0
- package/src/index.js +2636 -0
- package/src/itIcons.js +84 -0
- package/src/kernelExpr.js +243 -0
- package/src/propertiesDialog.js +463 -0
- package/src/railroadDiagram.js +571 -0
- package/src/treeModeCatalog.js +16 -0
- package/src/workspace/ContextBus.js +79 -0
- package/src/workspace/EditorShell.js +67 -0
- package/src/workspace/Part.js +163 -0
- package/src/workspace/PartFactory.js +49 -0
- package/src/workspace/PartRegistry.js +86 -0
- package/src/workspace/Workspace.js +321 -0
- package/src/workspace/archimateServices.js +33 -0
- package/src/workspace/dom.js +120 -0
- package/src/workspace/index.js +75 -0
- package/src/workspace/layout/GridNode.js +280 -0
- package/src/workspace/layout/LayoutNode.js +89 -0
- package/src/workspace/layout/PartNode.js +77 -0
- package/src/workspace/layout/SplitNode.js +114 -0
- package/src/workspace/layout/TabsNode.js +191 -0
- package/src/workspace/layout/index.js +24 -0
- package/src/workspace/parts/AdapterPart.js +33 -0
- package/src/workspace/parts/ArchimateCanvasPart.js +345 -0
- package/src/workspace/parts/ArchimateEditorPart.js +79 -0
- package/src/workspace/parts/ChartPart.js +115 -0
- package/src/workspace/parts/ContentPart.js +34 -0
- package/src/workspace/parts/DetailPart.js +46 -0
- package/src/workspace/parts/DiagramEditorPart.js +135 -0
- package/src/workspace/parts/EditorPart.js +388 -0
- package/src/workspace/parts/HtmlPart.js +25 -0
- package/src/workspace/parts/ListPart.js +57 -0
- package/src/workspace/parts/ModelFile.js +187 -0
- package/src/workspace/parts/ModelsPart.js +135 -0
- package/src/workspace/styles.js +258 -0
- package/src/workspace/themes.js +96 -0
- package/src/workspace/workArea.js +413 -0
- package/src/workspace/workAreaModel.js +197 -0
- package/src/workspace.js +16 -0
- package/src/zip/ZipArchive.js +160 -0
- package/src/zip/crc32.js +25 -0
- package/src/zip/inflate.js +159 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { el } from './dom.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* EditorShell — the workbench layout diagram editors share: a toolbar row, a
|
|
5
|
+
* side panel (model tree, palette), the main area (tabs + canvas) and an
|
|
6
|
+
* optional right-hand aside. Built with el() and inline styles, so it needs no
|
|
7
|
+
* stylesheet and never restyles the host page.
|
|
8
|
+
*
|
|
9
|
+
* Not a custom element, so the engine bundle can use it under node too.
|
|
10
|
+
*/
|
|
11
|
+
export class EditorShell {
|
|
12
|
+
/**
|
|
13
|
+
* @param {Object} [options]
|
|
14
|
+
* @param {Document} [options.document]
|
|
15
|
+
* @param {string} [options.sideWidth]
|
|
16
|
+
* @param {boolean} [options.aside] - Add a right-hand panel
|
|
17
|
+
* @param {string} [options.asideWidth]
|
|
18
|
+
* @param {Object<string, string>} [options.ids] - Element ids per region: toolbar, side, main, aside
|
|
19
|
+
* @param {boolean} [options.fullPage] - Fill the viewport (and drop the body margin)
|
|
20
|
+
*/
|
|
21
|
+
constructor({ document: doc = document, sideWidth = '280px', aside = false, asideWidth = '300px', ids = {}, fullPage = false } = {}) {
|
|
22
|
+
this.doc = doc;
|
|
23
|
+
this.sideWidth = sideWidth;
|
|
24
|
+
this.aside = aside;
|
|
25
|
+
this.asideWidth = asideWidth;
|
|
26
|
+
this.ids = ids;
|
|
27
|
+
this.fullPage = fullPage;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** @returns {{root: HTMLElement, toolbar: HTMLElement, side: HTMLElement, main: HTMLElement, aside?: HTMLElement}} */
|
|
31
|
+
build() {
|
|
32
|
+
const regions = {};
|
|
33
|
+
const region = (name, style) => ({
|
|
34
|
+
attrs: { id: this.ids[name] ?? null, 'data-shell-region': name },
|
|
35
|
+
style,
|
|
36
|
+
ref: (n) => { regions[name] = n; },
|
|
37
|
+
});
|
|
38
|
+
const panel = { background: '#fafafa', overflowY: 'auto', minHeight: '0', boxSizing: 'border-box' };
|
|
39
|
+
regions.root = el({
|
|
40
|
+
attrs: { 'data-editor-shell': '' },
|
|
41
|
+
style: {
|
|
42
|
+
display: 'flex', flexDirection: 'column', height: this.fullPage ? '100vh' : '100%', minHeight: '0',
|
|
43
|
+
fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif", color: '#333', background: '#f5f5f5',
|
|
44
|
+
},
|
|
45
|
+
children: [
|
|
46
|
+
region('toolbar', { flex: '0 0 auto' }),
|
|
47
|
+
{
|
|
48
|
+
style: { display: 'flex', flex: '1 1 auto', minHeight: '0', overflow: 'hidden' },
|
|
49
|
+
children: [
|
|
50
|
+
region('side', { ...panel, flex: `0 0 ${this.sideWidth}`, borderRight: '1px solid #ddd' }),
|
|
51
|
+
region('main', { flex: '1 1 auto', display: 'flex', flexDirection: 'column', minWidth: '0', minHeight: '0', background: '#fff', position: 'relative' }),
|
|
52
|
+
this.aside && region('aside', { ...panel, flex: `0 0 ${this.asideWidth}`, borderLeft: '1px solid #ddd' }),
|
|
53
|
+
].filter(Boolean),
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
}, this.doc);
|
|
57
|
+
return regions;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Replace the host's contents with the shell. */
|
|
61
|
+
mount(host) {
|
|
62
|
+
const regions = this.build();
|
|
63
|
+
host.replaceChildren(regions.root);
|
|
64
|
+
if (this.fullPage) this.doc.body.style.margin = '0';
|
|
65
|
+
return regions;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Part — base class for one unit of contributed UI.
|
|
3
|
+
*
|
|
4
|
+
* Subclasses live one-per-file under `parts/` and set `static type` (the
|
|
5
|
+
* registry key) plus, where meaningful, `static publishes` / `static subscribes`
|
|
6
|
+
* (the channel names they read and write). Those two are static metadata rather
|
|
7
|
+
* than ad-hoc `bus.subscribe()` calls buried inside `render()` precisely so a
|
|
8
|
+
* visual wiring UI can enumerate them without instantiating anything — that's
|
|
9
|
+
* the mashup authoring story.
|
|
10
|
+
*
|
|
11
|
+
* Lifecycle is `mount()` → `dispose()`. There is deliberately no "deactivate"
|
|
12
|
+
* hook: a part that is hidden but still in the layout tree stays mounted,
|
|
13
|
+
* because tearing down and rebuilding on every tab switch is what makes an IDE
|
|
14
|
+
* shell feel slow. A part that must stop work while hidden should subscribe to
|
|
15
|
+
* a visibility channel instead.
|
|
16
|
+
*/
|
|
17
|
+
import { el } from './dom.js';
|
|
18
|
+
|
|
19
|
+
export class Part {
|
|
20
|
+
/** Registry key. Every concrete subclass must override this. */
|
|
21
|
+
static type = null;
|
|
22
|
+
|
|
23
|
+
/** Channel names this part writes / reads. Metadata only — see class doc. */
|
|
24
|
+
static publishes = [];
|
|
25
|
+
static subscribes = [];
|
|
26
|
+
|
|
27
|
+
constructor(spec = {}) {
|
|
28
|
+
if (new.target === Part) throw new TypeError('Part is abstract — subclass it');
|
|
29
|
+
this.id = spec.id;
|
|
30
|
+
this.title = spec.title ?? spec.id;
|
|
31
|
+
this.spec = spec;
|
|
32
|
+
/** The element this part owns. Created once, re-parented thereafter. */
|
|
33
|
+
this.root = null;
|
|
34
|
+
this.container = null;
|
|
35
|
+
this.ctx = null;
|
|
36
|
+
/** @type {Array<Function>} teardown callbacks run by dispose() */
|
|
37
|
+
this._disposers = [];
|
|
38
|
+
this._mounted = false;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get mounted() { return this._mounted; }
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Attach to a host element. `ctx` carries the shell's services —
|
|
45
|
+
* `{ bus, engine, registry, theme, ...consumer extras }`.
|
|
46
|
+
*
|
|
47
|
+
* The part owns `this.root` and only builds it once. Calling `mount()`
|
|
48
|
+
* again — which happens when a perspective switch rebuilds the tree around
|
|
49
|
+
* a pooled part — re-parents that same element instead of re-rendering.
|
|
50
|
+
* That is what actually preserves scroll position, text selection and
|
|
51
|
+
* unsaved input across a perspective switch; re-running `render()` would
|
|
52
|
+
* throw all of it away.
|
|
53
|
+
*/
|
|
54
|
+
mount(host, ctx) {
|
|
55
|
+
if (!this._mounted) {
|
|
56
|
+
this.root = el({
|
|
57
|
+
cls: 'ws-part',
|
|
58
|
+
dataset: { partId: this.id ?? '', partType: this.constructor.type ?? '' },
|
|
59
|
+
});
|
|
60
|
+
this.container = this.root;
|
|
61
|
+
this.ctx = ctx;
|
|
62
|
+
this._mounted = true;
|
|
63
|
+
host.appendChild(this.root);
|
|
64
|
+
this.render();
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
host.appendChild(this.root); // moves it; no re-render
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Whether the part is on screen now: mounted, in the page, and not in a
|
|
72
|
+
* hidden tab (a part in a tab that is not selected stays mounted). Keys a
|
|
73
|
+
* part listens for on the whole page should only act while it is.
|
|
74
|
+
*/
|
|
75
|
+
isShown() {
|
|
76
|
+
const node = this.container;
|
|
77
|
+
if (!this.mounted || !node?.isConnected) return false;
|
|
78
|
+
return typeof node.getClientRects === 'function' ? node.getClientRects().length > 0 : true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Remove from the DOM but keep the element and all state intact. */
|
|
82
|
+
detach() {
|
|
83
|
+
if (this.root?.parentNode) this.root.parentNode.removeChild(this.root);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Subclasses implement this. `this.container` / `this.ctx` are set. */
|
|
87
|
+
render() {
|
|
88
|
+
throw new Error(`${this.constructor.name} must implement render()`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* ── Leak-safe helpers ───────────────────────────────────────────────────
|
|
92
|
+
Anything registered through these is torn down by dispose(). Parts that
|
|
93
|
+
reach past them (raw setInterval, raw addEventListener on window) are on
|
|
94
|
+
their own — a leaked pane refresh timer keeps hitting the server forever
|
|
95
|
+
after the pane is gone, which is exactly the failure this guards. */
|
|
96
|
+
|
|
97
|
+
subscribe(channel, fn) {
|
|
98
|
+
const off = this.ctx.bus.subscribe(channel, fn);
|
|
99
|
+
this._disposers.push(off);
|
|
100
|
+
return off;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
publish(channel, value) {
|
|
104
|
+
this.ctx.bus.publish(channel, value);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
every(ms, fn) {
|
|
108
|
+
const id = setInterval(fn, ms);
|
|
109
|
+
this._disposers.push(() => clearInterval(id));
|
|
110
|
+
return id;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
listen(target, event, fn, options) {
|
|
114
|
+
target.addEventListener(event, fn, options);
|
|
115
|
+
this._disposers.push(() => target.removeEventListener(event, fn, options));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Register an arbitrary teardown callback. */
|
|
119
|
+
onDispose(fn) {
|
|
120
|
+
this._disposers.push(fn);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Buttons this part contributes to its pane header or to a frame's action
|
|
125
|
+
* bar, as `[{label, title?, onClick, disabled?, separator?}]`. Rendered by
|
|
126
|
+
* GridNode into `.ws-pane-controls`, and by WorkArea into its action bar.
|
|
127
|
+
*
|
|
128
|
+
* On the Part rather than in the layout spec because they carry callbacks
|
|
129
|
+
* and the layout tree has to stay serializable JSON. Subclasses override, or
|
|
130
|
+
* a spec may supply a plain array for adapter-style parts.
|
|
131
|
+
*
|
|
132
|
+
* A spec may also supply a FUNCTION, called each time the actions are read.
|
|
133
|
+
* That is what lets a panel's buttons depend on its own state — "Export" is
|
|
134
|
+
* disabled until something is loaded — without the shell having to know
|
|
135
|
+
* anything about that state. An array stays an array, so nothing that
|
|
136
|
+
* already supplies one changes.
|
|
137
|
+
*/
|
|
138
|
+
get actions() {
|
|
139
|
+
const a = this.spec.actions;
|
|
140
|
+
return (typeof a === 'function' ? a(this) : a) ?? [];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Optional hover text for the pane title (e.g. type and refresh interval). */
|
|
144
|
+
get paneTooltip() {
|
|
145
|
+
return this.spec.paneTooltip ?? null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
dispose() {
|
|
149
|
+
for (const fn of this._disposers.reverse()) {
|
|
150
|
+
try { fn(); } catch (err) { console.error(`${this.constructor.name}#${this.id}: disposer threw`, err); }
|
|
151
|
+
}
|
|
152
|
+
this._disposers = [];
|
|
153
|
+
if (this.root?.parentNode) this.root.parentNode.removeChild(this.root);
|
|
154
|
+
this.root = null;
|
|
155
|
+
this.container = null;
|
|
156
|
+
this.ctx = null;
|
|
157
|
+
this._mounted = false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
serialize() {
|
|
161
|
+
return { ...this.spec, type: this.constructor.type, id: this.id, title: this.title };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Part } from './Part.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PartFactory — instantiates Part subclasses from specs.
|
|
5
|
+
*
|
|
6
|
+
* Separates object creation from the pooling lifecycle in PartRegistry so each
|
|
7
|
+
* class has a single responsibility.
|
|
8
|
+
*/
|
|
9
|
+
export class PartFactory {
|
|
10
|
+
constructor() {
|
|
11
|
+
/** @type {Map<string, typeof Part>} */
|
|
12
|
+
this._types = new Map();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Register a Part subclass, keyed on its static `type`. */
|
|
16
|
+
register(PartClass) {
|
|
17
|
+
const type = PartClass?.type;
|
|
18
|
+
if (!type) throw new Error(`Part class ${PartClass?.name ?? PartClass} has no static type`);
|
|
19
|
+
if (!(PartClass.prototype instanceof Part)) {
|
|
20
|
+
throw new Error(`${PartClass.name} must extend Part`);
|
|
21
|
+
}
|
|
22
|
+
this._types.set(type, PartClass);
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
registerAll(classes) {
|
|
27
|
+
for (const c of classes) this.register(c);
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
hasType(type) { return this._types.has(type); }
|
|
32
|
+
registeredTypes() { return [...this._types.keys()]; }
|
|
33
|
+
|
|
34
|
+
/** Registered types with their declared channels — feeds a wiring UI. */
|
|
35
|
+
describeTypes() {
|
|
36
|
+
return [...this._types.values()].map(Cls => ({
|
|
37
|
+
type: Cls.type,
|
|
38
|
+
publishes: Cls.publishes ?? [],
|
|
39
|
+
subscribes: Cls.subscribes ?? [],
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Instantiate from a spec. */
|
|
44
|
+
create(spec) {
|
|
45
|
+
const PartClass = this._types.get(spec?.type);
|
|
46
|
+
if (!PartClass) throw new Error(`Unknown part type "${spec?.type}" (registered: ${this.registeredTypes().join(', ') || 'none'})`);
|
|
47
|
+
return new PartClass(spec);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { PartFactory } from './PartFactory.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PartRegistry — live instance pool for Part subclasses.
|
|
5
|
+
*
|
|
6
|
+
* The pool is what makes perspective switching cheap and non-destructive:
|
|
7
|
+
* instances are keyed by part id, so if the incoming perspective also
|
|
8
|
+
* references `notebook`, the same instance is reused and keeps its scroll
|
|
9
|
+
* position, unsaved buffer and subscriptions.
|
|
10
|
+
*
|
|
11
|
+
* Pooled parts are NOT disposed when a perspective stops referencing them —
|
|
12
|
+
* they are only detached, so switching back finds them intact. Disposal is
|
|
13
|
+
* explicit: `remove`, `disposeExcept`, `disposeAll`.
|
|
14
|
+
*
|
|
15
|
+
* Type registration and instantiation live in PartFactory; this class owns
|
|
16
|
+
* only the instance pool lifecycle.
|
|
17
|
+
*/
|
|
18
|
+
export class PartRegistry {
|
|
19
|
+
constructor(factory = new PartFactory()) {
|
|
20
|
+
/** @type {PartFactory} */
|
|
21
|
+
this._factory = factory;
|
|
22
|
+
/** @type {Map<string, Part>} */
|
|
23
|
+
this._instances = new Map();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Register a Part subclass with the underlying factory. */
|
|
27
|
+
register(PartClass) {
|
|
28
|
+
this._factory.register(PartClass);
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
registerAll(classes) {
|
|
33
|
+
this._factory.registerAll(classes);
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
hasType(type) { return this._factory.hasType(type); }
|
|
38
|
+
|
|
39
|
+
/** Instantiate from a spec without pooling it. */
|
|
40
|
+
create(spec) {
|
|
41
|
+
return this._factory.create(spec);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Add a part to the pool from its spec. Ids must be unique — a duplicate id
|
|
46
|
+
* silently replacing a live part would orphan its subscriptions.
|
|
47
|
+
*/
|
|
48
|
+
add(spec) {
|
|
49
|
+
if (!spec?.id) throw new Error('Part spec requires an id');
|
|
50
|
+
if (this._instances.has(spec.id)) throw new Error(`Part id "${spec.id}" already exists`);
|
|
51
|
+
const part = this.create(spec);
|
|
52
|
+
this._instances.set(spec.id, part);
|
|
53
|
+
return part;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
get(id) { return this._instances.get(id); }
|
|
57
|
+
has(id) { return this._instances.has(id); }
|
|
58
|
+
ids() { return [...this._instances.keys()]; }
|
|
59
|
+
|
|
60
|
+
remove(id) {
|
|
61
|
+
const part = this._instances.get(id);
|
|
62
|
+
if (!part) return false;
|
|
63
|
+
part.dispose();
|
|
64
|
+
this._instances.delete(id);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Dispose every pooled part whose id is not in `keepIds`. */
|
|
69
|
+
disposeExcept(keepIds) {
|
|
70
|
+
const keep = new Set(keepIds);
|
|
71
|
+
for (const id of [...this._instances.keys()]) {
|
|
72
|
+
if (!keep.has(id)) this.remove(id);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
disposeAll() { this.disposeExcept([]); }
|
|
77
|
+
|
|
78
|
+
/** Registered types with their declared channels — feeds a wiring UI. */
|
|
79
|
+
describeTypes() {
|
|
80
|
+
return this._factory.describeTypes();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
serialize() {
|
|
84
|
+
return [...this._instances.values()].map(p => p.serialize());
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { ContextBus } from './ContextBus.js';
|
|
2
|
+
import { PartRegistry } from './PartRegistry.js';
|
|
3
|
+
import { createLayout } from './layout/index.js';
|
|
4
|
+
import { ensureStyles } from './styles.js';
|
|
5
|
+
import { BUILTIN_THEMES, SYSTEM_THEME } from './themes.js';
|
|
6
|
+
import { render } from './dom.js';
|
|
7
|
+
|
|
8
|
+
/** Bump when the serialized shape changes; `deserialize` migrates on the way in. */
|
|
9
|
+
export const WORKSPACE_SCHEMA_VERSION = 1;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Workspace — the `<ws-workspace>` custom element and the shell's public API.
|
|
13
|
+
*
|
|
14
|
+
* Renders into **light DOM**: parts routinely carry their own stylesheets, and a
|
|
15
|
+
* consumer stylesheet cannot cross a shadow boundary. All shell markup is
|
|
16
|
+
* `ws-`-prefixed and themed through CSS custom properties instead.
|
|
17
|
+
*
|
|
18
|
+
* Typical wiring:
|
|
19
|
+
*
|
|
20
|
+
* const ws = document.querySelector('ws-workspace');
|
|
21
|
+
* ws.registerParts([ListPart, DetailPart, ChartPart]);
|
|
22
|
+
* ws.addPart({ id: 'nav', type: 'list', title: 'Tables', items: [...] });
|
|
23
|
+
* ws.registerPerspective('default', { type: 'split', dir: 'row', children: [...] });
|
|
24
|
+
* ws.activatePerspective('default');
|
|
25
|
+
*/
|
|
26
|
+
export class Workspace extends HTMLElement {
|
|
27
|
+
constructor() {
|
|
28
|
+
super();
|
|
29
|
+
this.bus = new ContextBus();
|
|
30
|
+
this.registry = new PartRegistry();
|
|
31
|
+
/** @type {Map<string, object>} name → layout JSON */
|
|
32
|
+
this.perspectives = new Map();
|
|
33
|
+
this.activePerspective = null;
|
|
34
|
+
/** @type {import('./layout/LayoutNode.js').LayoutNode|null} */
|
|
35
|
+
this.tree = null;
|
|
36
|
+
/** @type {Map<string, object>} theme name → CSS custom-property map */
|
|
37
|
+
this.themes = new Map(Object.entries(BUILTIN_THEMES));
|
|
38
|
+
/** The *selection* — may be `system`, which resolves at apply time. */
|
|
39
|
+
this.theme = 'light';
|
|
40
|
+
/** Custom properties currently written onto the host, so they can be
|
|
41
|
+
* cleared before a different theme is applied. */
|
|
42
|
+
this._appliedVars = [];
|
|
43
|
+
this._built = false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* ── Element lifecycle ──────────────────────────────────────────────── */
|
|
47
|
+
|
|
48
|
+
connectedCallback() {
|
|
49
|
+
if (this._built) return;
|
|
50
|
+
this._built = true;
|
|
51
|
+
ensureStyles(this.ownerDocument ?? document);
|
|
52
|
+
this.classList.add('ws-workspace');
|
|
53
|
+
|
|
54
|
+
// Chrome is built from element specs rather than an HTML string, and
|
|
55
|
+
// `ref` captures the nodes directly — no querySelector round-trip.
|
|
56
|
+
// `label`, not `title` — `title` is a global HTML attribute and would
|
|
57
|
+
// also render a browser tooltip over the whole workspace.
|
|
58
|
+
render(this, [
|
|
59
|
+
{ cls: 'ws-toolbar', children: [
|
|
60
|
+
{ tag: 'span', cls: 'ws-toolbar-title', text: this.getAttribute('label') ?? '' },
|
|
61
|
+
{ tag: 'span', cls: 'ws-toolbar-spacer' },
|
|
62
|
+
{ tag: 'span', cls: 'ws-theme-picker', ref: n => { this._themePickerEl = n; } },
|
|
63
|
+
{ tag: 'span', cls: 'ws-perspectives', ref: n => { this._perspectivesEl = n; } },
|
|
64
|
+
]},
|
|
65
|
+
{ cls: 'ws-root', ref: n => { this._rootEl = n; } },
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
this.applyTheme(this.getAttribute('theme') ?? 'light');
|
|
69
|
+
this._renderThemePicker();
|
|
70
|
+
|
|
71
|
+
// A perspective registered before the element was connected renders now.
|
|
72
|
+
if (this.activePerspective) this._renderTree();
|
|
73
|
+
else if (this.perspectives.size) this.activatePerspective([...this.perspectives.keys()][0]);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
disconnectedCallback() {
|
|
77
|
+
this.tree?.dispose();
|
|
78
|
+
this.tree = null;
|
|
79
|
+
this._watchSystemTheme(false); // a live matchMedia listener would outlive the element
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* ── Parts ──────────────────────────────────────────────────────────── */
|
|
83
|
+
|
|
84
|
+
registerPart(PartClass) { this.registry.register(PartClass); return this; }
|
|
85
|
+
registerParts(classes) { this.registry.registerAll(classes); return this; }
|
|
86
|
+
|
|
87
|
+
/** Create a pooled part instance from a spec. */
|
|
88
|
+
addPart(spec) { return this.registry.add(spec); }
|
|
89
|
+
addParts(specs) { return specs.map(s => this.addPart(s)); }
|
|
90
|
+
getPart(id) { return this.registry.get(id); }
|
|
91
|
+
removePart(id) { return this.registry.remove(id); }
|
|
92
|
+
|
|
93
|
+
/* ── Perspectives ───────────────────────────────────────────────────── */
|
|
94
|
+
|
|
95
|
+
registerPerspective(name, layoutJson) {
|
|
96
|
+
this.perspectives.set(name, layoutJson);
|
|
97
|
+
this._renderPerspectiveButtons();
|
|
98
|
+
return this;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Switch to a named perspective.
|
|
103
|
+
*
|
|
104
|
+
* Parts are pooled by id and live for the workspace's lifetime, so a part
|
|
105
|
+
* the incoming perspective also references is re-parented rather than
|
|
106
|
+
* rebuilt — it keeps its scroll position, unsaved input and subscriptions.
|
|
107
|
+
* Parts the incoming perspective doesn't reference are detached, not
|
|
108
|
+
* destroyed, so switching back restores them intact.
|
|
109
|
+
*
|
|
110
|
+
* There is deliberately no legal-transition table: a framework cannot know
|
|
111
|
+
* a consumer's perspectives. Pass `guard` to veto a switch if you need one.
|
|
112
|
+
*/
|
|
113
|
+
activatePerspective(name) {
|
|
114
|
+
const layout = this.perspectives.get(name);
|
|
115
|
+
if (!layout) throw new Error(`Unknown perspective "${name}"`);
|
|
116
|
+
const from = this.activePerspective;
|
|
117
|
+
if (from === name) return true;
|
|
118
|
+
if (this.guard && this.guard(from, name) === false) return false;
|
|
119
|
+
|
|
120
|
+
this.tree?.dispose();
|
|
121
|
+
this.activePerspective = name;
|
|
122
|
+
this._renderTree();
|
|
123
|
+
|
|
124
|
+
this.dispatchEvent(new CustomEvent('ws-perspective-change', {
|
|
125
|
+
detail: { from, to: name }, bubbles: true,
|
|
126
|
+
}));
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
_renderTree() {
|
|
131
|
+
if (!this._rootEl) return;
|
|
132
|
+
const layout = this.perspectives.get(this.activePerspective);
|
|
133
|
+
this._rootEl.textContent = '';
|
|
134
|
+
this.tree = createLayout(layout);
|
|
135
|
+
this.tree.render(this._rootEl, this._ctx());
|
|
136
|
+
this.tree.activate?.();
|
|
137
|
+
// Parts the new tree doesn't reference are deliberately NOT disposed —
|
|
138
|
+
// they are merely detached (PartNode.dispose), keeping their DOM and
|
|
139
|
+
// state. Disposing them would delete them from the pool, so switching
|
|
140
|
+
// back to the perspective that used them would find them gone. Part
|
|
141
|
+
// lifetime ends only at removePart()/deserialize().
|
|
142
|
+
this._renderPerspectiveButtons();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
_ctx() {
|
|
146
|
+
return {
|
|
147
|
+
bus: this.bus,
|
|
148
|
+
registry: this.registry,
|
|
149
|
+
workspace: this,
|
|
150
|
+
onLayoutChange: () => this._onLayoutChange(),
|
|
151
|
+
...(this.services ?? {}),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
_onLayoutChange() {
|
|
156
|
+
if (this.activePerspective) {
|
|
157
|
+
this.perspectives.set(this.activePerspective, this.tree.serialize());
|
|
158
|
+
}
|
|
159
|
+
this.dispatchEvent(new CustomEvent('ws-layout-change', {
|
|
160
|
+
detail: { perspective: this.activePerspective }, bubbles: true,
|
|
161
|
+
}));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
_renderPerspectiveButtons() {
|
|
165
|
+
if (!this._perspectivesEl) return;
|
|
166
|
+
render(this._perspectivesEl, [...this.perspectives.keys()].map(name => ({
|
|
167
|
+
tag: 'button',
|
|
168
|
+
cls: ['ws-perspective-btn', name === this.activePerspective && 'ws-active'],
|
|
169
|
+
text: name,
|
|
170
|
+
attrs: { type: 'button' },
|
|
171
|
+
on: { click: () => this.activatePerspective(name) },
|
|
172
|
+
})));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* ── Theming ────────────────────────────────────────────────────────── */
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Register a custom-property set under a name. It appears in the toolbar's
|
|
179
|
+
* theme picker immediately — the picker is built from the registry, so a
|
|
180
|
+
* consumer theme needs no CSS and no picker change.
|
|
181
|
+
*/
|
|
182
|
+
registerTheme(name, vars) {
|
|
183
|
+
this.themes.set(name, vars);
|
|
184
|
+
this._renderThemePicker();
|
|
185
|
+
return this;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** Registered theme names, plus the reserved `system` option. */
|
|
189
|
+
themeNames() { return [SYSTEM_THEME, ...this.themes.keys()]; }
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Apply a theme by name, or `system` to follow the OS setting.
|
|
193
|
+
*
|
|
194
|
+
* The previous theme's properties are removed before the new ones are set:
|
|
195
|
+
* a custom theme may define only some of the vars, and leftovers from the
|
|
196
|
+
* outgoing theme would otherwise show through as a mismatched palette.
|
|
197
|
+
*/
|
|
198
|
+
applyTheme(name) {
|
|
199
|
+
const resolved = name === SYSTEM_THEME ? this._systemTheme() : name;
|
|
200
|
+
const vars = this.themes.get(resolved);
|
|
201
|
+
if (!vars && name !== SYSTEM_THEME) return this;
|
|
202
|
+
|
|
203
|
+
for (const key of this._appliedVars) this.style.removeProperty(key);
|
|
204
|
+
this._appliedVars = [];
|
|
205
|
+
for (const [k, v] of Object.entries(vars ?? {})) {
|
|
206
|
+
this.style.setProperty(k, v);
|
|
207
|
+
this._appliedVars.push(k);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const previous = this.theme;
|
|
211
|
+
this.theme = name; // the selection ('system' stays 'system')
|
|
212
|
+
this.setAttribute('data-theme', resolved); // the resolved name, for consumer CSS hooks
|
|
213
|
+
this._watchSystemTheme(name === SYSTEM_THEME);
|
|
214
|
+
if (this._themeSelect) this._themeSelect.value = name;
|
|
215
|
+
|
|
216
|
+
if (previous !== name) {
|
|
217
|
+
this.dispatchEvent(new CustomEvent('ws-theme-change', {
|
|
218
|
+
detail: { theme: name, resolved }, bubbles: true,
|
|
219
|
+
}));
|
|
220
|
+
}
|
|
221
|
+
return this;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
_systemTheme() {
|
|
225
|
+
return globalThis.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/** Keep `system` live: re-apply when the OS flips between light and dark. */
|
|
229
|
+
_watchSystemTheme(enabled) {
|
|
230
|
+
if (enabled && !this._systemThemeQuery) {
|
|
231
|
+
this._systemThemeQuery = globalThis.matchMedia?.('(prefers-color-scheme: dark)');
|
|
232
|
+
this._onSystemThemeChange = () => { if (this.theme === SYSTEM_THEME) this.applyTheme(SYSTEM_THEME); };
|
|
233
|
+
this._systemThemeQuery?.addEventListener('change', this._onSystemThemeChange);
|
|
234
|
+
} else if (!enabled && this._systemThemeQuery) {
|
|
235
|
+
this._systemThemeQuery.removeEventListener('change', this._onSystemThemeChange);
|
|
236
|
+
this._systemThemeQuery = null;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
_renderThemePicker() {
|
|
241
|
+
if (!this._themePickerEl) return;
|
|
242
|
+
if (this.getAttribute('theme-picker') === 'hidden') {
|
|
243
|
+
this._themePickerEl.textContent = '';
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
render(this._themePickerEl, [
|
|
247
|
+
{ tag: 'label', text: 'Theme', attrs: { for: 'ws-theme-select' } },
|
|
248
|
+
{
|
|
249
|
+
tag: 'select',
|
|
250
|
+
cls: 'ws-theme-select',
|
|
251
|
+
attrs: { id: 'ws-theme-select', title: 'Colour theme' },
|
|
252
|
+
on: { change: e => this.applyTheme(e.target.value) },
|
|
253
|
+
ref: n => { this._themeSelect = n; n.value = this.theme; },
|
|
254
|
+
children: this.themeNames().map(name => ({
|
|
255
|
+
tag: 'option',
|
|
256
|
+
text: name === SYSTEM_THEME ? 'System' : name[0].toUpperCase() + name.slice(1),
|
|
257
|
+
attrs: { value: name, selected: name === this.theme },
|
|
258
|
+
})),
|
|
259
|
+
},
|
|
260
|
+
]);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/* ── Persistence ────────────────────────────────────────────────────── */
|
|
264
|
+
|
|
265
|
+
serialize() {
|
|
266
|
+
if (this.tree && this.activePerspective) {
|
|
267
|
+
this.perspectives.set(this.activePerspective, this.tree.serialize());
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
version: WORKSPACE_SCHEMA_VERSION,
|
|
271
|
+
theme: this.theme,
|
|
272
|
+
activePerspective: this.activePerspective,
|
|
273
|
+
perspectives: Object.fromEntries(this.perspectives),
|
|
274
|
+
parts: this.registry.serialize(),
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Restore a serialized workspace. Part *types* must already be registered —
|
|
280
|
+
* a saved document carries specs, not code.
|
|
281
|
+
*
|
|
282
|
+
* `version` is honoured from day one on purpose: layout schemas change, and
|
|
283
|
+
* sqlengine's dashboard already had to retrofit exactly this migration once.
|
|
284
|
+
*/
|
|
285
|
+
deserialize(json, { migrate } = {}) {
|
|
286
|
+
const doc = migrate ? migrate(json) : json;
|
|
287
|
+
if (doc.version > WORKSPACE_SCHEMA_VERSION) {
|
|
288
|
+
throw new Error(`Workspace document version ${doc.version} is newer than this build (${WORKSPACE_SCHEMA_VERSION})`);
|
|
289
|
+
}
|
|
290
|
+
this.registry.disposeAll();
|
|
291
|
+
for (const spec of doc.parts ?? []) {
|
|
292
|
+
if (spec.adapter) continue; // AdapterPart's mount fn cannot round-trip — re-add it in code
|
|
293
|
+
this.addPart(spec);
|
|
294
|
+
}
|
|
295
|
+
// Only a theme this build actually knows — a document naming one the
|
|
296
|
+
// consumer no longer registers must not leave the shell unstyled.
|
|
297
|
+
if (doc.theme && (doc.theme === SYSTEM_THEME || this.themes.has(doc.theme))) {
|
|
298
|
+
this.applyTheme(doc.theme);
|
|
299
|
+
}
|
|
300
|
+
this.perspectives = new Map(Object.entries(doc.perspectives ?? {}));
|
|
301
|
+
this.activePerspective = null;
|
|
302
|
+
if (doc.activePerspective && this.perspectives.has(doc.activePerspective)) {
|
|
303
|
+
this.activatePerspective(doc.activePerspective);
|
|
304
|
+
}
|
|
305
|
+
return this;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export const WORKSPACE_TAG = 'ws-workspace';
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Register the element. Custom element names must contain a hyphen, so
|
|
313
|
+
* `workspace` is not a legal name — `define()` throws SyntaxError on it.
|
|
314
|
+
* Guarded so importing this module twice does not throw on re-definition.
|
|
315
|
+
*/
|
|
316
|
+
export function defineWorkspace(tag = WORKSPACE_TAG) {
|
|
317
|
+
if (typeof customElements === 'undefined') return false;
|
|
318
|
+
if (customElements.get(tag)) return false;
|
|
319
|
+
customElements.define(tag, Workspace);
|
|
320
|
+
return true;
|
|
321
|
+
}
|