@dxos/react-ui-canvas 0.13.0 → 0.14.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/README.md +1 -1
- package/dist/lib/index.mjs +9044 -1135
- package/dist/lib/index.mjs.map +1 -1
- package/dist/types/src/components/About/About.d.ts +13 -0
- package/dist/types/src/components/About/About.d.ts.map +1 -0
- package/dist/types/src/components/About/About.stories.d.ts +7 -0
- package/dist/types/src/components/About/About.stories.d.ts.map +1 -0
- package/dist/types/src/components/About/index.d.ts +2 -0
- package/dist/types/src/components/About/index.d.ts.map +1 -0
- package/dist/types/src/components/Breadcrumbs/Breadcrumbs.d.ts.map +1 -1
- package/dist/types/src/components/ControlFrame/ControlFrame.d.ts +8 -2
- package/dist/types/src/components/ControlFrame/ControlFrame.d.ts.map +1 -1
- package/dist/types/src/components/Layers/Layers.d.ts +30 -0
- package/dist/types/src/components/Layers/Layers.d.ts.map +1 -0
- package/dist/types/src/components/Layers/Layers.stories.d.ts +11 -0
- package/dist/types/src/components/Layers/Layers.stories.d.ts.map +1 -0
- package/dist/types/src/components/Layers/index.d.ts +2 -0
- package/dist/types/src/components/Layers/index.d.ts.map +1 -0
- package/dist/types/src/components/Palette/Palette.d.ts +20 -4
- package/dist/types/src/components/Palette/Palette.d.ts.map +1 -1
- package/dist/types/src/components/Palette/Palette.stories.d.ts +22 -0
- package/dist/types/src/components/Palette/Palette.stories.d.ts.map +1 -0
- package/dist/types/src/components/PartEditor/PartEditor.d.ts.map +1 -1
- package/dist/types/src/components/Properties/AlignField.d.ts +23 -0
- package/dist/types/src/components/Properties/AlignField.d.ts.map +1 -0
- package/dist/types/src/components/Properties/ClassField.d.ts +23 -0
- package/dist/types/src/components/Properties/ClassField.d.ts.map +1 -0
- package/dist/types/src/components/Properties/FontField.d.ts +7 -0
- package/dist/types/src/components/Properties/FontField.d.ts.map +1 -0
- package/dist/types/src/components/Properties/LayerField.d.ts +17 -0
- package/dist/types/src/components/Properties/LayerField.d.ts.map +1 -0
- package/dist/types/src/components/Properties/Properties.d.ts +27 -3
- package/dist/types/src/components/Properties/Properties.d.ts.map +1 -1
- package/dist/types/src/components/Properties/Properties.stories.d.ts +20 -0
- package/dist/types/src/components/Properties/Properties.stories.d.ts.map +1 -0
- package/dist/types/src/components/Properties/SceneField.d.ts +8 -0
- package/dist/types/src/components/Properties/SceneField.d.ts.map +1 -0
- package/dist/types/src/components/Properties/StyleGrid.d.ts +15 -5
- package/dist/types/src/components/Properties/StyleGrid.d.ts.map +1 -1
- package/dist/types/src/components/Properties/StyleGrid.stories.d.ts +7 -0
- package/dist/types/src/components/Properties/StyleGrid.stories.d.ts.map +1 -0
- package/dist/types/src/components/SceneLayer/SceneLayer.d.ts +31 -7
- package/dist/types/src/components/SceneLayer/SceneLayer.d.ts.map +1 -1
- package/dist/types/src/components/SceneView/Dock.d.ts +22 -0
- package/dist/types/src/components/SceneView/Dock.d.ts.map +1 -0
- package/dist/types/src/components/SceneView/Dock.stories.d.ts +15 -0
- package/dist/types/src/components/SceneView/Dock.stories.d.ts.map +1 -0
- package/dist/types/src/components/SceneView/SceneView.d.ts +33 -7
- package/dist/types/src/components/SceneView/SceneView.d.ts.map +1 -1
- package/dist/types/src/components/SceneView/SceneView.stories.d.ts +16 -6
- package/dist/types/src/components/SceneView/SceneView.stories.d.ts.map +1 -1
- package/dist/types/src/components/SceneView/SceneViewContext.d.ts +36 -4
- package/dist/types/src/components/SceneView/SceneViewContext.d.ts.map +1 -1
- package/dist/types/src/components/SceneView/Scored.stories.d.ts +4 -4
- package/dist/types/src/components/SceneView/Scored.stories.d.ts.map +1 -1
- package/dist/types/src/components/SceneView/usePointerMachine.d.ts +3 -1
- package/dist/types/src/components/SceneView/usePointerMachine.d.ts.map +1 -1
- package/dist/types/src/components/SceneView/useSceneCamera.d.ts +2 -2
- package/dist/types/src/components/SceneView/useSceneCamera.d.ts.map +1 -1
- package/dist/types/src/components/SceneView/useSceneClipboard.d.ts.map +1 -1
- package/dist/types/src/components/SceneView/useSceneKeys.d.ts.map +1 -1
- package/dist/types/src/components/SceneView/useSceneNavigation.d.ts +7 -4
- package/dist/types/src/components/SceneView/useSceneNavigation.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +2 -0
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +2 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useWheel.d.ts +5 -0
- package/dist/types/src/hooks/useWheel.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +4 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/model/atoms.d.ts +21 -3
- package/dist/types/src/model/atoms.d.ts.map +1 -1
- package/dist/types/src/model/projection.d.ts.map +1 -1
- package/dist/types/src/model/projections/constrained.d.ts +2 -1
- package/dist/types/src/model/projections/constrained.d.ts.map +1 -1
- package/dist/types/src/model/projections/dynamic.d.ts.map +1 -1
- package/dist/types/src/model/projections/lattice.d.ts.map +1 -1
- package/dist/types/src/model/registry.d.ts +21 -3
- package/dist/types/src/model/registry.d.ts.map +1 -1
- package/dist/types/src/model/store.d.ts +10 -2
- package/dist/types/src/model/store.d.ts.map +1 -1
- package/dist/types/src/model/types.d.ts +699 -338
- package/dist/types/src/model/types.d.ts.map +1 -1
- package/dist/types/src/playwright/SceneManager.d.ts +1 -1
- package/dist/types/src/playwright/SceneManager.d.ts.map +1 -1
- package/dist/types/src/utils/builder.d.ts +22 -41
- package/dist/types/src/utils/builder.d.ts.map +1 -1
- package/dist/types/src/utils/camera.d.ts +19 -10
- package/dist/types/src/utils/camera.d.ts.map +1 -1
- package/dist/types/src/utils/clipboard.d.ts +4 -2
- package/dist/types/src/utils/clipboard.d.ts.map +1 -1
- package/dist/types/src/utils/diagram.d.ts.map +1 -1
- package/dist/types/src/utils/group.d.ts +14 -0
- package/dist/types/src/utils/group.d.ts.map +1 -0
- package/dist/types/src/utils/group.test.d.ts +2 -0
- package/dist/types/src/utils/group.test.d.ts.map +1 -0
- package/dist/types/src/utils/gutter-route.d.ts +7 -0
- package/dist/types/src/utils/gutter-route.d.ts.map +1 -1
- package/dist/types/src/utils/hit.d.ts +3 -20
- package/dist/types/src/utils/hit.d.ts.map +1 -1
- package/dist/types/src/utils/index.d.ts +3 -0
- package/dist/types/src/utils/index.d.ts.map +1 -1
- package/dist/types/src/utils/lattice.d.ts +5 -0
- package/dist/types/src/utils/lattice.d.ts.map +1 -1
- package/dist/types/src/utils/layers.d.ts +35 -0
- package/dist/types/src/utils/layers.d.ts.map +1 -0
- package/dist/types/src/utils/layers.test.d.ts +2 -0
- package/dist/types/src/utils/layers.test.d.ts.map +1 -0
- package/dist/types/src/utils/parts.d.ts +25 -9
- package/dist/types/src/utils/parts.d.ts.map +1 -1
- package/dist/types/src/utils/ports.d.ts +2 -0
- package/dist/types/src/utils/ports.d.ts.map +1 -1
- package/dist/types/src/utils/properties.d.ts +4 -3
- package/dist/types/src/utils/properties.d.ts.map +1 -1
- package/dist/types/src/utils/route.d.ts +5 -0
- package/dist/types/src/utils/route.d.ts.map +1 -1
- package/dist/types/src/utils/scenes.d.ts +14 -0
- package/dist/types/src/utils/scenes.d.ts.map +1 -0
- package/dist/types/src/utils/scenes.test.d.ts +2 -0
- package/dist/types/src/utils/scenes.test.d.ts.map +1 -0
- package/dist/types/src/utils/shapes.d.ts +23 -9
- package/dist/types/src/utils/shapes.d.ts.map +1 -1
- package/dist/types/src/utils/style.d.ts +29 -6
- package/dist/types/src/utils/style.d.ts.map +1 -1
- package/dist/types/src/utils/style.test.d.ts +2 -0
- package/dist/types/src/utils/style.test.d.ts.map +1 -0
- package/dist/types/src/utils/testing.d.ts +2 -2
- package/dist/types/src/utils/testing.d.ts.map +1 -1
- package/dist/types/src/utils/undo.d.ts +15 -4
- package/dist/types/src/utils/undo.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +20 -26
- package/src/components/About/About.stories.tsx +32 -0
- package/src/components/About/About.tsx +38 -0
- package/src/components/About/index.ts +5 -0
- package/src/components/Breadcrumbs/Breadcrumbs.tsx +17 -3
- package/src/components/ControlFrame/ControlFrame.tsx +138 -82
- package/src/components/Grid/Grid.stories.tsx +1 -1
- package/src/components/Layers/Layers.stories.tsx +131 -0
- package/src/components/Layers/Layers.tsx +216 -0
- package/src/components/Layers/index.ts +5 -0
- package/src/components/Palette/Palette.stories.tsx +135 -0
- package/src/components/Palette/Palette.tsx +230 -39
- package/src/components/PartEditor/PartEditor.tsx +4 -3
- package/src/components/Properties/AlignField.tsx +117 -0
- package/src/components/Properties/ClassField.tsx +44 -0
- package/src/components/Properties/FontField.tsx +73 -0
- package/src/components/Properties/LayerField.tsx +61 -0
- package/src/components/Properties/Properties.stories.tsx +113 -0
- package/src/components/Properties/Properties.tsx +240 -60
- package/src/components/Properties/SceneField.tsx +22 -0
- package/src/components/Properties/StyleGrid.stories.tsx +50 -0
- package/src/components/Properties/StyleGrid.tsx +54 -26
- package/src/components/SceneLayer/SceneLayer.tsx +497 -188
- package/src/components/SceneView/Constrained.stories.tsx +1 -1
- package/src/components/SceneView/Dock.stories.tsx +95 -0
- package/src/components/SceneView/Dock.tsx +146 -0
- package/src/components/SceneView/Dynamic.stories.tsx +1 -1
- package/src/components/SceneView/SceneView.stories.tsx +170 -18
- package/src/components/SceneView/SceneView.tsx +565 -151
- package/src/components/SceneView/SceneViewContext.ts +23 -2
- package/src/components/SceneView/Scored.stories.tsx +11 -11
- package/src/components/SceneView/usePointerMachine.ts +80 -20
- package/src/components/SceneView/useSceneCamera.ts +15 -8
- package/src/components/SceneView/useSceneClipboard.ts +4 -0
- package/src/components/SceneView/useSceneKeys.ts +6 -4
- package/src/components/SceneView/useSceneNavigation.ts +44 -33
- package/src/components/Toolbar/Toolbar.stories.tsx +14 -15
- package/src/components/Toolbar/Toolbar.tsx +15 -4
- package/src/components/index.ts +2 -0
- package/src/hooks/useWheel.ts +35 -0
- package/src/index.ts +4 -3
- package/src/model/atoms.ts +27 -3
- package/src/model/projection.ts +5 -0
- package/src/model/projections/constrained.test.ts +18 -10
- package/src/model/projections/constrained.ts +19 -8
- package/src/model/projections/dynamic.ts +5 -2
- package/src/model/projections/lattice.ts +15 -3
- package/src/model/registry.test.ts +14 -9
- package/src/model/registry.ts +39 -34
- package/src/model/store.ts +12 -2
- package/src/model/types.ts +124 -36
- package/src/playwright/SceneManager.ts +2 -2
- package/src/playwright/create.spec.ts +5 -3
- package/src/playwright/demo.spec.ts +2 -2
- package/src/playwright/lattice.spec.ts +4 -5
- package/src/playwright/scene.spec.ts +27 -25
- package/src/utils/builder.test.ts +46 -9
- package/src/utils/builder.ts +42 -18
- package/src/utils/camera.test.ts +22 -51
- package/src/utils/camera.ts +39 -32
- package/src/utils/clipboard.test.ts +23 -2
- package/src/utils/clipboard.ts +8 -4
- package/src/utils/diagram.test.ts +3 -1
- package/src/utils/diagram.ts +3 -25
- package/src/utils/group.test.ts +69 -0
- package/src/utils/group.ts +94 -0
- package/src/utils/gutter-route.test.ts +49 -0
- package/src/utils/gutter-route.ts +142 -16
- package/src/utils/hit.test.ts +4 -38
- package/src/utils/hit.ts +4 -26
- package/src/utils/index.ts +3 -0
- package/src/utils/lattice.ts +7 -1
- package/src/utils/layers.test.ts +139 -0
- package/src/utils/layers.ts +175 -0
- package/src/utils/parts.test.ts +66 -32
- package/src/utils/parts.ts +63 -41
- package/src/utils/ports.ts +7 -4
- package/src/utils/properties.test.ts +23 -6
- package/src/utils/properties.ts +66 -16
- package/src/utils/route.test.ts +51 -2
- package/src/utils/route.ts +133 -23
- package/src/utils/scenes.test.ts +38 -0
- package/src/utils/scenes.ts +54 -0
- package/src/utils/shapes.test.ts +33 -8
- package/src/utils/shapes.ts +51 -35
- package/src/utils/style.test.ts +54 -0
- package/src/utils/style.ts +153 -40
- package/src/utils/testing.test.ts +3 -3
- package/src/utils/testing.ts +21 -30
- package/src/utils/undo.test.ts +25 -2
- package/src/utils/undo.ts +50 -13
- package/dist/lib/chunk-Grid.mjs +0 -99
- package/dist/lib/chunk-Grid.mjs.map +0 -1
- package/dist/lib/scene.mjs +0 -6835
- package/dist/lib/scene.mjs.map +0 -1
- package/dist/lib/types.mjs +0 -16
- package/dist/lib/types.mjs.map +0 -1
- package/dist/types/src/archive/components/Canvas/Canvas.d.ts +0 -15
- package/dist/types/src/archive/components/Canvas/Canvas.d.ts.map +0 -1
- package/dist/types/src/archive/components/Canvas/Canvas.stories.d.ts +0 -18
- package/dist/types/src/archive/components/Canvas/Canvas.stories.d.ts.map +0 -1
- package/dist/types/src/archive/components/Canvas/index.d.ts +0 -2
- package/dist/types/src/archive/components/Canvas/index.d.ts.map +0 -1
- package/dist/types/src/archive/components/CellGrid/CellGrid.d.ts +0 -21
- package/dist/types/src/archive/components/CellGrid/CellGrid.d.ts.map +0 -1
- package/dist/types/src/archive/components/CellGrid/CellGrid.stories.d.ts +0 -21
- package/dist/types/src/archive/components/CellGrid/CellGrid.stories.d.ts.map +0 -1
- package/dist/types/src/archive/components/CellGrid/headers/Ruler.d.ts +0 -15
- package/dist/types/src/archive/components/CellGrid/headers/Ruler.d.ts.map +0 -1
- package/dist/types/src/archive/components/CellGrid/headers/TrackHeader.d.ts +0 -19
- package/dist/types/src/archive/components/CellGrid/headers/TrackHeader.d.ts.map +0 -1
- package/dist/types/src/archive/components/CellGrid/headers/index.d.ts +0 -3
- package/dist/types/src/archive/components/CellGrid/headers/index.d.ts.map +0 -1
- package/dist/types/src/archive/components/CellGrid/index.d.ts +0 -6
- package/dist/types/src/archive/components/CellGrid/index.d.ts.map +0 -1
- package/dist/types/src/archive/components/CellGrid/input/index.d.ts +0 -3
- package/dist/types/src/archive/components/CellGrid/input/index.d.ts.map +0 -1
- package/dist/types/src/archive/components/CellGrid/input/pointer.d.ts +0 -33
- package/dist/types/src/archive/components/CellGrid/input/pointer.d.ts.map +0 -1
- package/dist/types/src/archive/components/CellGrid/input/wheel.d.ts +0 -14
- package/dist/types/src/archive/components/CellGrid/input/wheel.d.ts.map +0 -1
- package/dist/types/src/archive/components/CellGrid/render/index.d.ts +0 -3
- package/dist/types/src/archive/components/CellGrid/render/index.d.ts.map +0 -1
- package/dist/types/src/archive/components/CellGrid/render/overlay-layer.d.ts +0 -21
- package/dist/types/src/archive/components/CellGrid/render/overlay-layer.d.ts.map +0 -1
- package/dist/types/src/archive/components/CellGrid/render/static-layer.d.ts +0 -36
- package/dist/types/src/archive/components/CellGrid/render/static-layer.d.ts.map +0 -1
- package/dist/types/src/archive/components/CellGrid/state/atoms.d.ts +0 -23
- package/dist/types/src/archive/components/CellGrid/state/atoms.d.ts.map +0 -1
- package/dist/types/src/archive/components/CellGrid/state/index.d.ts +0 -4
- package/dist/types/src/archive/components/CellGrid/state/index.d.ts.map +0 -1
- package/dist/types/src/archive/components/CellGrid/state/types.d.ts +0 -39
- package/dist/types/src/archive/components/CellGrid/state/types.d.ts.map +0 -1
- package/dist/types/src/archive/components/CellGrid/state/viewport.d.ts +0 -52
- package/dist/types/src/archive/components/CellGrid/state/viewport.d.ts.map +0 -1
- package/dist/types/src/archive/components/CellGrid/state/viewport.test.d.ts +0 -2
- package/dist/types/src/archive/components/CellGrid/state/viewport.test.d.ts.map +0 -1
- package/dist/types/src/archive/components/FPS.d.ts +0 -9
- package/dist/types/src/archive/components/FPS.d.ts.map +0 -1
- package/dist/types/src/archive/components/Grid/Grid.d.ts +0 -6
- package/dist/types/src/archive/components/Grid/Grid.d.ts.map +0 -1
- package/dist/types/src/archive/components/Grid/index.d.ts +0 -2
- package/dist/types/src/archive/components/Grid/index.d.ts.map +0 -1
- package/dist/types/src/archive/components/index.d.ts +0 -5
- package/dist/types/src/archive/components/index.d.ts.map +0 -1
- package/dist/types/src/archive/hooks/index.d.ts +0 -5
- package/dist/types/src/archive/hooks/index.d.ts.map +0 -1
- package/dist/types/src/archive/hooks/projection.d.ts +0 -60
- package/dist/types/src/archive/hooks/projection.d.ts.map +0 -1
- package/dist/types/src/archive/hooks/useCanvasContext.d.ts +0 -13
- package/dist/types/src/archive/hooks/useCanvasContext.d.ts.map +0 -1
- package/dist/types/src/archive/hooks/useDrag.d.ts +0 -6
- package/dist/types/src/archive/hooks/useDrag.d.ts.map +0 -1
- package/dist/types/src/archive/hooks/useWheel.d.ts +0 -8
- package/dist/types/src/archive/hooks/useWheel.d.ts.map +0 -1
- package/dist/types/src/archive/index.d.ts +0 -5
- package/dist/types/src/archive/index.d.ts.map +0 -1
- package/dist/types/src/archive/types.d.ts +0 -19
- package/dist/types/src/archive/types.d.ts.map +0 -1
- package/dist/types/src/archive/util/index.d.ts +0 -4
- package/dist/types/src/archive/util/index.d.ts.map +0 -1
- package/dist/types/src/archive/util/svg-path.d.ts +0 -4
- package/dist/types/src/archive/util/svg-path.d.ts.map +0 -1
- package/dist/types/src/archive/util/svg.d.ts +0 -32
- package/dist/types/src/archive/util/svg.d.ts.map +0 -1
- package/dist/types/src/archive/util/svg.stories.d.ts +0 -15
- package/dist/types/src/archive/util/svg.stories.d.ts.map +0 -1
- package/dist/types/src/archive/util/util.d.ts +0 -17
- package/dist/types/src/archive/util/util.d.ts.map +0 -1
- package/dist/types/src/scene.d.ts +0 -5
- package/dist/types/src/scene.d.ts.map +0 -1
- package/src/archive/components/Canvas/Canvas.stories.tsx +0 -111
- package/src/archive/components/Canvas/Canvas.tsx +0 -87
- package/src/archive/components/Canvas/index.ts +0 -5
- package/src/archive/components/CellGrid/CellGrid.stories.tsx +0 -239
- package/src/archive/components/CellGrid/CellGrid.tsx +0 -270
- package/src/archive/components/CellGrid/headers/Ruler.tsx +0 -71
- package/src/archive/components/CellGrid/headers/TrackHeader.tsx +0 -58
- package/src/archive/components/CellGrid/headers/index.ts +0 -6
- package/src/archive/components/CellGrid/index.ts +0 -9
- package/src/archive/components/CellGrid/input/index.ts +0 -6
- package/src/archive/components/CellGrid/input/pointer.ts +0 -236
- package/src/archive/components/CellGrid/input/wheel.ts +0 -68
- package/src/archive/components/CellGrid/render/index.ts +0 -6
- package/src/archive/components/CellGrid/render/overlay-layer.ts +0 -66
- package/src/archive/components/CellGrid/render/static-layer.ts +0 -112
- package/src/archive/components/CellGrid/state/atoms.ts +0 -43
- package/src/archive/components/CellGrid/state/index.ts +0 -7
- package/src/archive/components/CellGrid/state/types.ts +0 -40
- package/src/archive/components/CellGrid/state/viewport.test.ts +0 -50
- package/src/archive/components/CellGrid/state/viewport.ts +0 -94
- package/src/archive/components/FPS.tsx +0 -98
- package/src/archive/components/Grid/Grid.tsx +0 -17
- package/src/archive/components/Grid/index.ts +0 -5
- package/src/archive/components/index.ts +0 -8
- package/src/archive/hooks/index.ts +0 -8
- package/src/archive/hooks/projection.tsx +0 -156
- package/src/archive/hooks/useCanvasContext.ts +0 -32
- package/src/archive/hooks/useDrag.tsx +0 -96
- package/src/archive/hooks/useWheel.tsx +0 -80
- package/src/archive/index.ts +0 -8
- package/src/archive/types.ts +0 -14
- package/src/archive/util/index.ts +0 -7
- package/src/archive/util/svg-path.ts +0 -13
- package/src/archive/util/svg.stories.tsx +0 -46
- package/src/archive/util/svg.tsx +0 -128
- package/src/archive/util/util.ts +0 -50
- package/src/scene.ts +0 -9
|
@@ -19,7 +19,7 @@ import type * as Util from '@dxos/react-ui/Util';
|
|
|
19
19
|
import { createBasicExtensions, createThemeExtensions } from '@dxos/ui-editor';
|
|
20
20
|
import { mx } from '@dxos/ui-theme';
|
|
21
21
|
|
|
22
|
-
import { type PartEditing, type PartKey
|
|
22
|
+
import { type PartEditing, type PartKey } from '../../utils/parts.ts';
|
|
23
23
|
|
|
24
24
|
export type TextPartProps = Util.ThemedClassName<
|
|
25
25
|
PropsWithChildren<{
|
|
@@ -36,7 +36,8 @@ export const TextPart = ({ classNames, part, text, editing, children }: TextPart
|
|
|
36
36
|
<PartEditor classNames={classNames} part={part} text={text} editing={editing} />
|
|
37
37
|
) : (
|
|
38
38
|
<div className={mx(classNames)} data-part={part}>
|
|
39
|
-
{
|
|
39
|
+
{/* The text's own box, which a part's layout may pad (its line boxes, not the part's frame). */}
|
|
40
|
+
<span className='inline-block'>{children}</span>
|
|
40
41
|
</div>
|
|
41
42
|
);
|
|
42
43
|
|
|
@@ -46,7 +47,7 @@ const stop = (event: React.SyntheticEvent) => event.stopPropagation();
|
|
|
46
47
|
|
|
47
48
|
const PartEditor = ({ classNames, part, text, editing }: PartEditorProps) => {
|
|
48
49
|
const themeMode = Hooks.useThemeMode();
|
|
49
|
-
const multiline =
|
|
50
|
+
const multiline = editing.multiline;
|
|
50
51
|
// Commit or cancel once: the editor unmounts on either, and its focus loss must not commit again.
|
|
51
52
|
const done = useRef(false);
|
|
52
53
|
const finish = (action: () => void) => {
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import type * as SchemaAST from 'effect/SchemaAST';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
|
|
8
|
+
import { Form, type FormFieldRenderer, useFormFieldState } from '@dxos/react-ui-form';
|
|
9
|
+
import * as Layout from '@dxos/react-ui/Layout';
|
|
10
|
+
import * as ToggleGroup from '@dxos/react-ui/ToggleGroup';
|
|
11
|
+
|
|
12
|
+
import { type HorizontalAlign, NodeStyle, type VerticalAlign } from '../../model/types.ts';
|
|
13
|
+
|
|
14
|
+
export type IconToggleOption<T extends string> = { value: T; icon: string; label: string };
|
|
15
|
+
|
|
16
|
+
export type IconToggleProps<T extends string> = {
|
|
17
|
+
label: string;
|
|
18
|
+
options: readonly IconToggleOption<T>[];
|
|
19
|
+
value?: T;
|
|
20
|
+
readonly?: boolean;
|
|
21
|
+
onValueChange: (value: T) => void;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/** One choice of a few, each an icon: a single-select toggle group whose pressed item is the value. */
|
|
25
|
+
export const IconToggle = <T extends string>({
|
|
26
|
+
label,
|
|
27
|
+
options,
|
|
28
|
+
value,
|
|
29
|
+
readonly,
|
|
30
|
+
onValueChange,
|
|
31
|
+
}: IconToggleProps<T>) => (
|
|
32
|
+
<ToggleGroup.Root
|
|
33
|
+
type='single'
|
|
34
|
+
value={value ?? ''}
|
|
35
|
+
aria-label={label}
|
|
36
|
+
onValueChange={(next) => {
|
|
37
|
+
// Pressing the pressed item releases it in the group; the value stays what it was.
|
|
38
|
+
const option = options.find((candidate) => candidate.value === next);
|
|
39
|
+
if (option) {
|
|
40
|
+
onValueChange(option.value);
|
|
41
|
+
}
|
|
42
|
+
}}
|
|
43
|
+
>
|
|
44
|
+
{options.map((option) => (
|
|
45
|
+
<ToggleGroup.Item
|
|
46
|
+
key={option.value}
|
|
47
|
+
value={option.value}
|
|
48
|
+
variant='ghost'
|
|
49
|
+
icon={option.icon}
|
|
50
|
+
iconOnly
|
|
51
|
+
label={option.label}
|
|
52
|
+
disabled={readonly}
|
|
53
|
+
data-testid={`align-${option.value}`}
|
|
54
|
+
/>
|
|
55
|
+
))}
|
|
56
|
+
</ToggleGroup.Root>
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const HORIZONTAL: readonly IconToggleOption<HorizontalAlign>[] = [
|
|
60
|
+
{ value: 'left', icon: 'ph--align-left-simple--regular', label: 'Align left' },
|
|
61
|
+
{ value: 'center', icon: 'ph--align-center-vertical-simple--regular', label: 'Align centre' },
|
|
62
|
+
{ value: 'right', icon: 'ph--align-right-simple--regular', label: 'Align right' },
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
const VERTICAL: readonly IconToggleOption<VerticalAlign>[] = [
|
|
66
|
+
{ value: 'top', icon: 'ph--align-top-simple--regular', label: 'Align top' },
|
|
67
|
+
{ value: 'middle', icon: 'ph--align-center-horizontal-simple--regular', label: 'Align middle' },
|
|
68
|
+
{ value: 'bottom', icon: 'ph--align-bottom-simple--regular', label: 'Align bottom' },
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The text alignment, rendered at `style.alignHorizontal`: the horizontal and vertical toggles side by side in one
|
|
73
|
+
* row (`style.alignVertical` is hidden). Each writes only its own path, so an edit across a selection leaves each
|
|
74
|
+
* element's other style values.
|
|
75
|
+
*/
|
|
76
|
+
export const AlignField: FormFieldRenderer = ({ jsonPath, readonly }) => {
|
|
77
|
+
const stylePath = (jsonPath ?? 'style.alignHorizontal').split('.').slice(0, -1);
|
|
78
|
+
const horizontalField = useFormFieldState('AlignField', [...stylePath, 'alignHorizontal']);
|
|
79
|
+
const verticalField = useFormFieldState('AlignField', [...stylePath, 'alignVertical']);
|
|
80
|
+
const horizontal = HORIZONTAL.find((option) => option.value === horizontalField.getValue())?.value;
|
|
81
|
+
const vertical = VERTICAL.find((option) => option.value === verticalField.getValue())?.value;
|
|
82
|
+
// A pick is a commit: a toggle never blurs, so it commits itself.
|
|
83
|
+
const pick = (field: typeof horizontalField, ast: SchemaAST.AST, value: string) => {
|
|
84
|
+
field.onValueChange(ast, value);
|
|
85
|
+
field.onBlur();
|
|
86
|
+
};
|
|
87
|
+
return (
|
|
88
|
+
<Layout.Container
|
|
89
|
+
layout='row'
|
|
90
|
+
gutter='inherit'
|
|
91
|
+
align='start'
|
|
92
|
+
gap='md'
|
|
93
|
+
columns='repeat(2, minmax(0, 1fr))'
|
|
94
|
+
// The properties panel is narrow, and the two toggles fit side by side there, so the row never stacks.
|
|
95
|
+
fixed
|
|
96
|
+
>
|
|
97
|
+
<Form.Field path={jsonPath} label='Horizontal' readonly={readonly}>
|
|
98
|
+
<IconToggle
|
|
99
|
+
label='Horizontal alignment'
|
|
100
|
+
options={HORIZONTAL}
|
|
101
|
+
value={horizontal}
|
|
102
|
+
readonly={!!readonly}
|
|
103
|
+
onValueChange={(next) => pick(horizontalField, NodeStyle.fields.alignHorizontal.ast, next)}
|
|
104
|
+
/>
|
|
105
|
+
</Form.Field>
|
|
106
|
+
<Form.Field path={[...stylePath, 'alignVertical'].join('.')} label='Vertical' readonly={readonly}>
|
|
107
|
+
<IconToggle
|
|
108
|
+
label='Vertical alignment'
|
|
109
|
+
options={VERTICAL}
|
|
110
|
+
value={vertical}
|
|
111
|
+
readonly={!!readonly}
|
|
112
|
+
onValueChange={(next) => pick(verticalField, NodeStyle.fields.alignVertical.ast, next)}
|
|
113
|
+
/>
|
|
114
|
+
</Form.Field>
|
|
115
|
+
</Layout.Container>
|
|
116
|
+
);
|
|
117
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { createContext, useContext, useMemo } from 'react';
|
|
6
|
+
|
|
7
|
+
import { Form, type FormFieldRenderer, SelectControl } from '@dxos/react-ui-form';
|
|
8
|
+
|
|
9
|
+
import { type StyleMap } from '../../model/types.ts';
|
|
10
|
+
|
|
11
|
+
/** The drawing's style classes, for the class field; unset when the host offers none, so the field is hidden. */
|
|
12
|
+
export const StyleClassesContext = createContext<StyleMap | undefined>(undefined);
|
|
13
|
+
|
|
14
|
+
/** The select's value for no class: a select item needs a non-empty value. */
|
|
15
|
+
const NO_CLASS = '-';
|
|
16
|
+
|
|
17
|
+
/** An element's style class: one of the drawing's, or none, leaving only its own style. */
|
|
18
|
+
export const ClassField: FormFieldRenderer = ({ type, label, jsonPath, readonly, getValue, onValueChange, onBlur }) => {
|
|
19
|
+
const styles = useContext(StyleClassesContext);
|
|
20
|
+
const items = useMemo(
|
|
21
|
+
() => [
|
|
22
|
+
{ value: NO_CLASS, label: 'None' },
|
|
23
|
+
...Object.values(styles ?? {})
|
|
24
|
+
.map((styleClass) => ({ value: styleClass.id, label: styleClass.name }))
|
|
25
|
+
.sort((left, right) => left.label.localeCompare(right.label)),
|
|
26
|
+
],
|
|
27
|
+
[styles],
|
|
28
|
+
);
|
|
29
|
+
const value: unknown = getValue();
|
|
30
|
+
return (
|
|
31
|
+
<Form.Field path={jsonPath} label={label} readonly={readonly}>
|
|
32
|
+
<SelectControl
|
|
33
|
+
items={items}
|
|
34
|
+
value={typeof value === 'string' ? value : NO_CLASS}
|
|
35
|
+
readonly={readonly}
|
|
36
|
+
onValueChange={(next) => {
|
|
37
|
+
// A choice is a commit: the select never blurs, so it commits itself.
|
|
38
|
+
onValueChange(type, next === NO_CLASS ? undefined : next);
|
|
39
|
+
onBlur();
|
|
40
|
+
}}
|
|
41
|
+
/>
|
|
42
|
+
</Form.Field>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
import { Form, type FormFieldRenderer, SelectControl, useFormFieldState } from '@dxos/react-ui-form';
|
|
8
|
+
import * as Input from '@dxos/react-ui/Input';
|
|
9
|
+
import * as Layout from '@dxos/react-ui/Layout';
|
|
10
|
+
|
|
11
|
+
import { FONT_FAMILIES, type FontFamily, NodeStyle } from '../../model/types.ts';
|
|
12
|
+
|
|
13
|
+
const FAMILY_LABELS: Record<FontFamily, string> = { default: 'Default', monospace: 'Monospace' };
|
|
14
|
+
|
|
15
|
+
const FAMILIES = FONT_FAMILIES.map((value) => ({ value, label: FAMILY_LABELS[value] }));
|
|
16
|
+
|
|
17
|
+
/** The editor's readable range; stored sizes outside it are kept, not checked. */
|
|
18
|
+
const FONT_SIZE = { min: 8, max: 80, step: 1 };
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The text face and size, rendered at `style.fontFamily`: the two side by side in one row (`style.fontSize` is
|
|
22
|
+
* hidden). Each writes only its own path, so an edit across a selection leaves each element's other style values.
|
|
23
|
+
*/
|
|
24
|
+
export const FontField: FormFieldRenderer = ({ jsonPath, readonly }) => {
|
|
25
|
+
const stylePath = (jsonPath ?? 'style.fontFamily').split('.').slice(0, -1);
|
|
26
|
+
const familyField = useFormFieldState('FontField', [...stylePath, 'fontFamily']);
|
|
27
|
+
const sizeField = useFormFieldState('FontField', [...stylePath, 'fontSize']);
|
|
28
|
+
const family: unknown = familyField.getValue();
|
|
29
|
+
const size: unknown = sizeField.getValue();
|
|
30
|
+
return (
|
|
31
|
+
<Layout.Container
|
|
32
|
+
layout='row'
|
|
33
|
+
gutter='inherit'
|
|
34
|
+
align='start'
|
|
35
|
+
gap='md'
|
|
36
|
+
columns='repeat(2, minmax(0, 1fr))'
|
|
37
|
+
// The properties panel is narrow, and the two controls fit side by side there, so the row never stacks.
|
|
38
|
+
fixed
|
|
39
|
+
>
|
|
40
|
+
<Form.Field path={jsonPath} label='Font' readonly={readonly}>
|
|
41
|
+
<SelectControl
|
|
42
|
+
items={FAMILIES}
|
|
43
|
+
value={typeof family === 'string' ? family : 'default'}
|
|
44
|
+
readonly={readonly}
|
|
45
|
+
onValueChange={(next) => {
|
|
46
|
+
const fontFamily = FONT_FAMILIES.find((family) => family === next);
|
|
47
|
+
// The body face is the default, so it is stored as unset; a pick never blurs, so it commits itself.
|
|
48
|
+
familyField.onValueChange(
|
|
49
|
+
NodeStyle.fields.fontFamily.ast,
|
|
50
|
+
fontFamily === 'default' ? undefined : fontFamily,
|
|
51
|
+
);
|
|
52
|
+
familyField.onBlur();
|
|
53
|
+
}}
|
|
54
|
+
/>
|
|
55
|
+
</Form.Field>
|
|
56
|
+
<Form.Field path={[...stylePath, 'fontSize'].join('.')} label='Font size' readonly={readonly}>
|
|
57
|
+
<Input.Number
|
|
58
|
+
disabled={!!readonly}
|
|
59
|
+
{...FONT_SIZE}
|
|
60
|
+
formatOptions={{ maximumFractionDigits: 0 }}
|
|
61
|
+
value={typeof size === 'number' ? String(size) : ''}
|
|
62
|
+
onValueChange={(_, fontSize) => {
|
|
63
|
+
if (!Number.isNaN(fontSize)) {
|
|
64
|
+
// A stepper press never blurs, so each value commits itself.
|
|
65
|
+
sizeField.onValueChange(NodeStyle.fields.fontSize.ast, fontSize);
|
|
66
|
+
sizeField.onBlur();
|
|
67
|
+
}
|
|
68
|
+
}}
|
|
69
|
+
/>
|
|
70
|
+
</Form.Field>
|
|
71
|
+
</Layout.Container>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Schema from 'effect/Schema';
|
|
6
|
+
import React, { createContext, useContext, useMemo } from 'react';
|
|
7
|
+
|
|
8
|
+
import { Form, type FormFieldRenderer, SelectControl, useFormFieldState } from '@dxos/react-ui-form';
|
|
9
|
+
import * as Layout from '@dxos/react-ui/Layout';
|
|
10
|
+
|
|
11
|
+
import { type Layer } from '../../model/types.ts';
|
|
12
|
+
import { ClassField, StyleClassesContext } from './ClassField.tsx';
|
|
13
|
+
|
|
14
|
+
/** The scene's layers, bottom first, for the layer field. */
|
|
15
|
+
export const LayersContext = createContext<readonly Layer[]>([]);
|
|
16
|
+
|
|
17
|
+
/** The layer an element is on: one of the scene's, listed top first as they stack. */
|
|
18
|
+
export const LayerField: FormFieldRenderer = ({ type, label, jsonPath, readonly, getValue, onValueChange, onBlur }) => {
|
|
19
|
+
const layers = useContext(LayersContext);
|
|
20
|
+
const items = useMemo(() => [...layers].reverse().map((layer) => ({ value: layer.id, label: layer.name })), [layers]);
|
|
21
|
+
const value: unknown = getValue();
|
|
22
|
+
return (
|
|
23
|
+
<Form.Field path={jsonPath} label={label} readonly={readonly}>
|
|
24
|
+
<SelectControl
|
|
25
|
+
items={items}
|
|
26
|
+
value={typeof value === 'string' ? value : undefined}
|
|
27
|
+
readonly={readonly}
|
|
28
|
+
onValueChange={(next) => {
|
|
29
|
+
// A choice is a commit: the select never blurs, so it commits itself.
|
|
30
|
+
onValueChange(type, next);
|
|
31
|
+
onBlur();
|
|
32
|
+
}}
|
|
33
|
+
/>
|
|
34
|
+
</Form.Field>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The layer and the style class side by side in one row, rendered at `layer` (`class` is hidden); the class select
|
|
40
|
+
* only while the host offers classes.
|
|
41
|
+
*/
|
|
42
|
+
export const LayerClassField: FormFieldRenderer = (props) => {
|
|
43
|
+
const styles = useContext(StyleClassesContext);
|
|
44
|
+
const classField = useFormFieldState('LayerClassField', ['class']);
|
|
45
|
+
return (
|
|
46
|
+
<Layout.Container
|
|
47
|
+
layout='row'
|
|
48
|
+
gutter='inherit'
|
|
49
|
+
align='start'
|
|
50
|
+
gap='md'
|
|
51
|
+
columns='repeat(2, minmax(0, 1fr))'
|
|
52
|
+
// The properties panel is narrow, and the two selects fit side by side there, so the row never stacks.
|
|
53
|
+
fixed
|
|
54
|
+
>
|
|
55
|
+
<LayerField {...props} />
|
|
56
|
+
{styles && (
|
|
57
|
+
<ClassField {...classField} type={Schema.String.ast} label='Class' jsonPath='class' readonly={props.readonly} />
|
|
58
|
+
)}
|
|
59
|
+
</Layout.Container>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useAtomValue } from '@effect/atom-react/Hooks';
|
|
6
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
7
|
+
import React, { useLayoutEffect, useMemo } from 'react';
|
|
8
|
+
import { expect, within } from 'storybook/test';
|
|
9
|
+
|
|
10
|
+
import { Panel } from '@dxos/react-ui';
|
|
11
|
+
import { translations as formTranslations } from '@dxos/react-ui-form/translations';
|
|
12
|
+
import { JsonHighlighter } from '@dxos/react-ui-syntax-highlighter';
|
|
13
|
+
import { withLayout, withRegistry, withTheme } from '@dxos/react-ui/testing';
|
|
14
|
+
import { translations as uiTranslations } from '@dxos/react-ui/translations';
|
|
15
|
+
|
|
16
|
+
import { useRegistry, useSceneProjection } from '../../hooks/index.ts';
|
|
17
|
+
import { createSceneViewAtoms } from '../../model/atoms.ts';
|
|
18
|
+
import { createMemoryStore } from '../../model/store.ts';
|
|
19
|
+
import { type ElementId, type Layer, type Scene, getElement } from '../../model/types.ts';
|
|
20
|
+
import { SceneBuilder } from '../../utils/builder.ts';
|
|
21
|
+
import { between } from '../../utils/order.ts';
|
|
22
|
+
import { Properties } from './Properties.tsx';
|
|
23
|
+
|
|
24
|
+
const box = (x: number, y = 0) => ({ x, y, width: 256, height: 128 });
|
|
25
|
+
|
|
26
|
+
/** Three layers, bottom first; `a` and the link are on the diagram layer, `n` on notes. */
|
|
27
|
+
const LAYERS: Layer[] = (() => {
|
|
28
|
+
const background: Layer = { id: 'background', name: 'Background', z: between() };
|
|
29
|
+
const notes: Layer = { id: 'notes', name: 'Notes', z: between(background.z) };
|
|
30
|
+
const diagram: Layer = { id: 'diagram', name: 'Diagram', z: between(notes.z) };
|
|
31
|
+
return [background, notes, diagram];
|
|
32
|
+
})();
|
|
33
|
+
|
|
34
|
+
const SCENE: Scene = (() => {
|
|
35
|
+
const {
|
|
36
|
+
scenes: [scene],
|
|
37
|
+
} = SceneBuilder.scene('root', [
|
|
38
|
+
SceneBuilder.rect('a', box(0)).properties({ label: 'Rect', layer: 'diagram', style: { hue: 'teal' } }),
|
|
39
|
+
SceneBuilder.rect('b', box(400)).properties({ label: 'Other', layer: 'background' }),
|
|
40
|
+
SceneBuilder.note('n', box(0, 200)).properties({ layer: 'notes' }),
|
|
41
|
+
SceneBuilder.link('curve', 'a', 'b')
|
|
42
|
+
.id('ab')
|
|
43
|
+
.properties({ layer: 'diagram', style: { lineStyle: 'dashed' } }),
|
|
44
|
+
]).build();
|
|
45
|
+
return { ...scene, layers: Object.fromEntries(LAYERS.map((layer) => [layer.id, layer])) };
|
|
46
|
+
})();
|
|
47
|
+
|
|
48
|
+
type StoryArgs = {
|
|
49
|
+
/** The elements the panel edits. */
|
|
50
|
+
select: ElementId[];
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/** The panel alone, over an in-memory scene and a fixed selection: no canvas, so every field can be read in full. */
|
|
54
|
+
const DefaultStory = ({ select }: StoryArgs) => {
|
|
55
|
+
const registry = useRegistry();
|
|
56
|
+
const store = useMemo(() => createMemoryStore([SCENE]), []);
|
|
57
|
+
const atoms = useMemo(() => createSceneViewAtoms(SCENE.id), []);
|
|
58
|
+
const projection = useSceneProjection({ store, atoms });
|
|
59
|
+
useLayoutEffect(() => {
|
|
60
|
+
registry.set(atoms.selection, new Set(select));
|
|
61
|
+
}, [registry, atoms, select]);
|
|
62
|
+
// The selection as the model holds it, beside the panel editing it, so every edit shows what it wrote.
|
|
63
|
+
const scene = useAtomValue(projection.scene);
|
|
64
|
+
const styles = useAtomValue(store.styles);
|
|
65
|
+
const selected = select.flatMap((id) => getElement(scene, id) ?? []);
|
|
66
|
+
return (
|
|
67
|
+
<Panel.Root>
|
|
68
|
+
<Panel.Body classNames='grid grid-cols-[20rem_1fr] gap-3'>
|
|
69
|
+
<Properties projection={projection} atoms={atoms} styles={store.styles} />
|
|
70
|
+
<JsonHighlighter data={{ selected, styles }} classNames='text-sm' />
|
|
71
|
+
</Panel.Body>
|
|
72
|
+
</Panel.Root>
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const meta: Meta<StoryArgs> = {
|
|
77
|
+
title: 'ui/react-ui-canvas/Properties',
|
|
78
|
+
render: DefaultStory,
|
|
79
|
+
decorators: [withRegistry, withTheme(), withLayout({ layout: 'column', classNames: 'w-[50rem]' })],
|
|
80
|
+
args: { select: ['a'] },
|
|
81
|
+
parameters: { translations: [...uiTranslations, ...formTranslations] },
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export default meta;
|
|
85
|
+
|
|
86
|
+
type Story = StoryObj<StoryArgs>;
|
|
87
|
+
|
|
88
|
+
/** A shape: its layer, class and the whole style (the full colour grid, line style and text alignment). */
|
|
89
|
+
export const Default: Story = {};
|
|
90
|
+
|
|
91
|
+
/** A link: the common style base alone (the outline row and line style), its layer and class. */
|
|
92
|
+
export const Link: Story = { args: { select: ['ab'] } };
|
|
93
|
+
|
|
94
|
+
/** A shape and a link: only what both declare, the style narrowed to its common base. */
|
|
95
|
+
export const Mixed: Story = { args: { select: ['a', 'ab'] } };
|
|
96
|
+
|
|
97
|
+
/** A note on its own layer. */
|
|
98
|
+
export const Note: Story = { args: { select: ['n'] } };
|
|
99
|
+
|
|
100
|
+
/** The layer selector lists the scene's layers top first and shows the element's own. */
|
|
101
|
+
export const Test: Story = {
|
|
102
|
+
args: { select: ['n'] },
|
|
103
|
+
play: async ({ canvasElement }) => {
|
|
104
|
+
const canvas = within(canvasElement);
|
|
105
|
+
// 1. The panel renders the selection's fields.
|
|
106
|
+
await expect(await canvas.findByTestId('properties')).toBeInTheDocument();
|
|
107
|
+
// 2. The layer field shows the note's layer.
|
|
108
|
+
const layer = await canvas.findByRole('combobox', { name: 'Layer' });
|
|
109
|
+
await expect(layer).toHaveTextContent('Notes');
|
|
110
|
+
// 3. The font row shows the face, unset reading as the body face.
|
|
111
|
+
await expect(await canvas.findByRole('combobox', { name: 'Font' })).toHaveTextContent('Default');
|
|
112
|
+
},
|
|
113
|
+
};
|