@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
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2026 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import type * as Registry from 'effect/reactivity/AtomRegistry';
|
|
6
|
-
|
|
7
|
-
import type { CellGridAtoms } from '../state/atoms.ts';
|
|
8
|
-
import type { Headers } from '../state/types.ts';
|
|
9
|
-
import { cellWidth } from '../state/viewport.ts';
|
|
10
|
-
|
|
11
|
-
const MIN_ZOOM = 0.25;
|
|
12
|
-
const MAX_ZOOM = 8;
|
|
13
|
-
|
|
14
|
-
export type WheelControllerOptions<T> = {
|
|
15
|
-
registry: Registry.AtomRegistry;
|
|
16
|
-
atoms: CellGridAtoms<T>;
|
|
17
|
-
headers: Headers;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Attach wheel handlers. Vertical wheel scrolls y; shift+wheel scrolls x;
|
|
22
|
-
* cmd/ctrl+wheel zooms x around the cursor.
|
|
23
|
-
*/
|
|
24
|
-
export const attachWheelHandlers = <T>(
|
|
25
|
-
element: HTMLElement,
|
|
26
|
-
{ registry, atoms, headers }: WheelControllerOptions<T>,
|
|
27
|
-
): (() => void) => {
|
|
28
|
-
const onWheel = (event: WheelEvent) => {
|
|
29
|
-
if (event.ctrlKey || event.metaKey) {
|
|
30
|
-
event.preventDefault();
|
|
31
|
-
// Zoom around cursor x.
|
|
32
|
-
const rect = element.getBoundingClientRect();
|
|
33
|
-
const x = event.clientX - rect.left;
|
|
34
|
-
const factor = Math.exp(-event.deltaY / 200);
|
|
35
|
-
registry.update(atoms.viewport, (current) => {
|
|
36
|
-
const nextZoom = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, current.zoomX * factor));
|
|
37
|
-
if (nextZoom === current.zoomX) {
|
|
38
|
-
return current;
|
|
39
|
-
}
|
|
40
|
-
const w = cellWidth(current);
|
|
41
|
-
const worldX = (x - headers.left + current.scrollX) / w;
|
|
42
|
-
const nextW = current.baseCellWidth * nextZoom;
|
|
43
|
-
const nextScrollX = Math.max(0, worldX * nextW - (x - headers.left));
|
|
44
|
-
return { ...current, zoomX: nextZoom, scrollX: nextScrollX };
|
|
45
|
-
});
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const dx = event.shiftKey ? event.deltaY : event.deltaX;
|
|
50
|
-
const dy = event.shiftKey ? 0 : event.deltaY;
|
|
51
|
-
const current = registry.get(atoms.viewport);
|
|
52
|
-
const nextScrollX = Math.max(0, current.scrollX + dx);
|
|
53
|
-
const nextScrollY = Math.max(0, current.scrollY + dy);
|
|
54
|
-
|
|
55
|
-
// Only consume the wheel event if we're actually scrolling within the grid.
|
|
56
|
-
// When the user wheels up at the top (scrollY === 0 && dy < 0) or wheels left
|
|
57
|
-
// at the left edge, let the event bubble to the parent so the page or
|
|
58
|
-
// enclosing container can scroll instead of swallowing the gesture.
|
|
59
|
-
if (nextScrollX === current.scrollX && nextScrollY === current.scrollY) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
event.preventDefault();
|
|
63
|
-
registry.set(atoms.viewport, { ...current, scrollX: nextScrollX, scrollY: nextScrollY });
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
element.addEventListener('wheel', onWheel, { passive: false });
|
|
67
|
-
return () => element.removeEventListener('wheel', onWheel);
|
|
68
|
-
};
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2026 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import type { Headers, Selection, Viewport } from '../state/types.ts';
|
|
6
|
-
import { cellWidth, worldToScreen } from '../state/viewport.ts';
|
|
7
|
-
|
|
8
|
-
export type OverlayStyle = {
|
|
9
|
-
playhead: string;
|
|
10
|
-
selectionFill: string;
|
|
11
|
-
selectionStroke: string;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export type DrawOverlayOptions = {
|
|
15
|
-
ctx: CanvasRenderingContext2D;
|
|
16
|
-
size: { width: number; height: number };
|
|
17
|
-
viewport: Viewport;
|
|
18
|
-
headers: Headers;
|
|
19
|
-
selection: Selection;
|
|
20
|
-
/** Playhead position in world units (col + fraction), or null when not playing. */
|
|
21
|
-
playhead: number | null;
|
|
22
|
-
style: OverlayStyle;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const drawOverlay = ({ ctx, size, viewport, headers, selection, playhead, style }: DrawOverlayOptions): void => {
|
|
26
|
-
ctx.clearRect(0, 0, size.width, size.height);
|
|
27
|
-
|
|
28
|
-
ctx.save();
|
|
29
|
-
ctx.beginPath();
|
|
30
|
-
ctx.rect(headers.left, headers.top, size.width - headers.left, size.height - headers.top);
|
|
31
|
-
ctx.clip();
|
|
32
|
-
|
|
33
|
-
// Selection rectangle.
|
|
34
|
-
if (selection.range) {
|
|
35
|
-
const { col0, row0, col1, row1 } = selection.range;
|
|
36
|
-
const minCol = Math.min(col0, col1);
|
|
37
|
-
const maxCol = Math.max(col0, col1);
|
|
38
|
-
const minRow = Math.min(row0, row1);
|
|
39
|
-
const maxRow = Math.max(row0, row1);
|
|
40
|
-
const tl = worldToScreen(viewport, headers, { col: minCol, row: minRow });
|
|
41
|
-
const br = worldToScreen(viewport, headers, { col: maxCol + 1, row: maxRow + 1 });
|
|
42
|
-
ctx.fillStyle = style.selectionFill;
|
|
43
|
-
ctx.fillRect(tl.x, tl.y, br.x - tl.x, br.y - tl.y);
|
|
44
|
-
ctx.strokeStyle = style.selectionStroke;
|
|
45
|
-
ctx.setLineDash([4, 3]);
|
|
46
|
-
ctx.lineWidth = 1;
|
|
47
|
-
ctx.strokeRect(tl.x + 0.5, tl.y + 0.5, br.x - tl.x - 1, br.y - tl.y - 1);
|
|
48
|
-
ctx.setLineDash([]);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Playhead.
|
|
52
|
-
if (playhead !== null) {
|
|
53
|
-
const w = cellWidth(viewport);
|
|
54
|
-
const x = headers.left + playhead * w - viewport.scrollX;
|
|
55
|
-
if (x >= headers.left && x <= size.width) {
|
|
56
|
-
ctx.strokeStyle = style.playhead;
|
|
57
|
-
ctx.lineWidth = 2;
|
|
58
|
-
ctx.beginPath();
|
|
59
|
-
ctx.moveTo(x, headers.top);
|
|
60
|
-
ctx.lineTo(x, size.height);
|
|
61
|
-
ctx.stroke();
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
ctx.restore();
|
|
66
|
-
};
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2026 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import type { Cell, Headers, Row, Viewport } from '../state/types.ts';
|
|
6
|
-
import { cellWidth, visibleCellRange, visibleCells, worldToScreen } from '../state/viewport.ts';
|
|
7
|
-
|
|
8
|
-
export type RenderCellArgs<T> = {
|
|
9
|
-
ctx: CanvasRenderingContext2D;
|
|
10
|
-
x: number;
|
|
11
|
-
y: number;
|
|
12
|
-
w: number;
|
|
13
|
-
h: number;
|
|
14
|
-
cell: Cell<T>;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export type RenderCell<T = unknown> = (args: RenderCellArgs<T>) => void;
|
|
18
|
-
|
|
19
|
-
export type StaticLayerStyle = {
|
|
20
|
-
/** Grid line color, e.g. 'rgba(0,0,0,0.08)'. */
|
|
21
|
-
gridLine: string;
|
|
22
|
-
/** Row band fill (alternating), e.g. 'rgba(0,0,0,0.02)'. */
|
|
23
|
-
rowBand?: string;
|
|
24
|
-
background?: string;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export type DrawCellsOptions<T> = {
|
|
28
|
-
ctx: CanvasRenderingContext2D;
|
|
29
|
-
size: { width: number; height: number };
|
|
30
|
-
viewport: Viewport;
|
|
31
|
-
headers: Headers;
|
|
32
|
-
rows: ReadonlyArray<Row>;
|
|
33
|
-
cells: ReadonlyMap<string, Cell<T>>;
|
|
34
|
-
renderCell: RenderCell<T>;
|
|
35
|
-
style: StaticLayerStyle;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Paint the static layer: background, gridlines, alternating row bands, and cells.
|
|
40
|
-
* Pure with respect to its inputs (writes only to the supplied ctx).
|
|
41
|
-
*/
|
|
42
|
-
export const drawCells = <T>({
|
|
43
|
-
ctx,
|
|
44
|
-
size,
|
|
45
|
-
viewport,
|
|
46
|
-
headers,
|
|
47
|
-
rows,
|
|
48
|
-
cells,
|
|
49
|
-
renderCell,
|
|
50
|
-
style,
|
|
51
|
-
}: DrawCellsOptions<T>): void => {
|
|
52
|
-
ctx.clearRect(0, 0, size.width, size.height);
|
|
53
|
-
|
|
54
|
-
if (style.background) {
|
|
55
|
-
ctx.fillStyle = style.background;
|
|
56
|
-
ctx.fillRect(0, 0, size.width, size.height);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const range = visibleCellRange(viewport, headers, size);
|
|
60
|
-
const w = cellWidth(viewport);
|
|
61
|
-
const h = viewport.cellHeight;
|
|
62
|
-
|
|
63
|
-
// Row bands. Paint odd rows so the stripe pattern matches the TrackHeader's
|
|
64
|
-
// label backgrounds (which darken odd row indices) — keeps the frozen left
|
|
65
|
-
// column and the cell area visually in lockstep.
|
|
66
|
-
if (style.rowBand) {
|
|
67
|
-
ctx.fillStyle = style.rowBand;
|
|
68
|
-
for (let row = range.minRow; row <= Math.min(range.maxRow, rows.length - 1); row++) {
|
|
69
|
-
if (row % 2 === 0) {
|
|
70
|
-
continue;
|
|
71
|
-
}
|
|
72
|
-
const y = headers.top + row * h - viewport.scrollY;
|
|
73
|
-
ctx.fillRect(headers.left, y, size.width - headers.left, h);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Gridlines.
|
|
78
|
-
ctx.strokeStyle = style.gridLine;
|
|
79
|
-
ctx.lineWidth = 1;
|
|
80
|
-
ctx.beginPath();
|
|
81
|
-
for (let col = range.minCol; col <= range.maxCol + 1; col++) {
|
|
82
|
-
const x = Math.floor(headers.left + col * w - viewport.scrollX) + 0.5;
|
|
83
|
-
if (x < headers.left) {
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
ctx.moveTo(x, headers.top);
|
|
87
|
-
ctx.lineTo(x, size.height);
|
|
88
|
-
}
|
|
89
|
-
for (let row = range.minRow; row <= Math.min(range.maxRow + 1, rows.length); row++) {
|
|
90
|
-
const y = Math.floor(headers.top + row * h - viewport.scrollY) + 0.5;
|
|
91
|
-
if (y < headers.top) {
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
ctx.moveTo(headers.left, y);
|
|
95
|
-
ctx.lineTo(size.width, y);
|
|
96
|
-
}
|
|
97
|
-
ctx.stroke();
|
|
98
|
-
|
|
99
|
-
// Cells.
|
|
100
|
-
ctx.save();
|
|
101
|
-
ctx.beginPath();
|
|
102
|
-
ctx.rect(headers.left, headers.top, size.width - headers.left, size.height - headers.top);
|
|
103
|
-
ctx.clip();
|
|
104
|
-
for (const cell of visibleCells(cells, range)) {
|
|
105
|
-
if (cell.row >= rows.length) {
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
const rect = worldToScreen(viewport, headers, cell);
|
|
109
|
-
renderCell({ ctx, ...rect, cell });
|
|
110
|
-
}
|
|
111
|
-
ctx.restore();
|
|
112
|
-
};
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2026 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import * as Atom from 'effect/reactivity/Atom';
|
|
6
|
-
|
|
7
|
-
import type { Cell, Selection, Tool, Viewport } from './types.ts';
|
|
8
|
-
|
|
9
|
-
export type CellGridAtoms<T = unknown> = {
|
|
10
|
-
cells: Atom.Writable<ReadonlyMap<string, Cell<T>>>;
|
|
11
|
-
viewport: Atom.Writable<Viewport>;
|
|
12
|
-
selection: Atom.Writable<Selection>;
|
|
13
|
-
playhead: Atom.Writable<number | null>;
|
|
14
|
-
tool: Atom.Writable<Tool>;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export type CellGridAtomsOptions = {
|
|
18
|
-
cellWidth?: number;
|
|
19
|
-
cellHeight?: number;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export const defaultViewport = (options: CellGridAtomsOptions = {}): Viewport => ({
|
|
23
|
-
scrollX: 0,
|
|
24
|
-
scrollY: 0,
|
|
25
|
-
baseCellWidth: options.cellWidth ?? 24,
|
|
26
|
-
cellHeight: options.cellHeight ?? 24,
|
|
27
|
-
zoomX: 1,
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Create a fresh set of atoms backing a CellGrid instance. Consumers may pass any of these as props
|
|
32
|
-
* or substitute their own (e.g., a cells atom backed by ECHO).
|
|
33
|
-
*
|
|
34
|
-
* Atoms are marked keepAlive so they preserve state across transient unsubscribe windows (e.g. React
|
|
35
|
-
* Strict Mode mount-unmount-remount). Consumers are responsible for the atoms' lifetime.
|
|
36
|
-
*/
|
|
37
|
-
export const createCellGridAtoms = <T = unknown>(options: CellGridAtomsOptions = {}): CellGridAtoms<T> => ({
|
|
38
|
-
cells: Atom.keepAlive(Atom.make<ReadonlyMap<string, Cell<T>>>(new Map())),
|
|
39
|
-
viewport: Atom.keepAlive(Atom.make<Viewport>(defaultViewport(options))),
|
|
40
|
-
selection: Atom.keepAlive(Atom.make<Selection>({ range: null })),
|
|
41
|
-
playhead: Atom.keepAlive(Atom.make<number | null>(null)),
|
|
42
|
-
tool: Atom.keepAlive(Atom.make<Tool>('toggle')),
|
|
43
|
-
});
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2026 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
export type CellCoord = { col: number; row: number };
|
|
6
|
-
|
|
7
|
-
export type Cell<T = unknown> = {
|
|
8
|
-
col: number;
|
|
9
|
-
row: number;
|
|
10
|
-
length: number;
|
|
11
|
-
data?: T;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export type Viewport = {
|
|
15
|
-
/** World-space scroll offset (pixels). */
|
|
16
|
-
scrollX: number;
|
|
17
|
-
scrollY: number;
|
|
18
|
-
/** Cell dimensions in pixels at zoomX = 1. */
|
|
19
|
-
baseCellWidth: number;
|
|
20
|
-
cellHeight: number;
|
|
21
|
-
/** Horizontal zoom factor. */
|
|
22
|
-
zoomX: number;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export type SelectionRange = {
|
|
26
|
-
col0: number;
|
|
27
|
-
row0: number;
|
|
28
|
-
col1: number;
|
|
29
|
-
row1: number;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export type Selection = {
|
|
33
|
-
range: SelectionRange | null;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export type Tool = 'toggle' | 'select' | 'resize' | 'edit' | 'delete';
|
|
37
|
-
|
|
38
|
-
export type Row = { id: string; label?: string };
|
|
39
|
-
|
|
40
|
-
export type Headers = { left: number; top: number };
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2026 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { describe, test } from 'vitest';
|
|
6
|
-
|
|
7
|
-
import { defaultViewport } from './atoms.ts';
|
|
8
|
-
import { hitTestCell, screenToWorld, visibleCellRange, visibleCells, worldToScreen } from './viewport.ts';
|
|
9
|
-
|
|
10
|
-
const headers = { left: 80, top: 24 };
|
|
11
|
-
|
|
12
|
-
describe('viewport', () => {
|
|
13
|
-
test('worldToScreen / screenToWorld round-trip', ({ expect }) => {
|
|
14
|
-
const viewport = { ...defaultViewport(), scrollX: 100, scrollY: 50 };
|
|
15
|
-
const { x, y } = worldToScreen(viewport, headers, { col: 5, row: 3 });
|
|
16
|
-
const back = screenToWorld(viewport, headers, { x, y });
|
|
17
|
-
expect(back.col).toBeCloseTo(5);
|
|
18
|
-
expect(back.row).toBeCloseTo(3);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
test('hitTestCell returns null in header region', ({ expect }) => {
|
|
22
|
-
const viewport = defaultViewport();
|
|
23
|
-
expect(hitTestCell(viewport, headers, { x: 10, y: 10 })).toBeNull();
|
|
24
|
-
expect(hitTestCell(viewport, headers, { x: 200, y: 10 })).toBeNull();
|
|
25
|
-
expect(hitTestCell(viewport, headers, { x: 10, y: 200 })).toBeNull();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test('hitTestCell floors fractional coords', ({ expect }) => {
|
|
29
|
-
const viewport = { ...defaultViewport(), baseCellWidth: 20, cellHeight: 20 };
|
|
30
|
-
const coord = hitTestCell(viewport, headers, { x: 80 + 25, y: 24 + 45 });
|
|
31
|
-
expect(coord).toEqual({ col: 1, row: 2 });
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
test('visibleCellRange respects scroll', ({ expect }) => {
|
|
35
|
-
const viewport = { ...defaultViewport(), scrollX: 240, baseCellWidth: 24, cellHeight: 24 };
|
|
36
|
-
const range = visibleCellRange(viewport, headers, { width: 400, height: 200 });
|
|
37
|
-
expect(range.minCol).toBe(10);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test('visibleCells filters by row and column extent', ({ expect }) => {
|
|
41
|
-
const cells = new Map([
|
|
42
|
-
['0,0', { col: 0, row: 0, length: 1 }],
|
|
43
|
-
['100,0', { col: 100, row: 0, length: 1 }],
|
|
44
|
-
['5,5', { col: 5, row: 5, length: 1 }],
|
|
45
|
-
['8,1', { col: 8, row: 1, length: 10 }],
|
|
46
|
-
]);
|
|
47
|
-
const result = Array.from(visibleCells(cells, { minCol: 0, maxCol: 12, minRow: 0, maxRow: 2 }));
|
|
48
|
-
expect(result.map((cell) => `${cell.col},${cell.row}`).sort()).toEqual(['0,0', '8,1']);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2026 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import type { Cell, CellCoord, Headers, Viewport } from './types.ts';
|
|
6
|
-
|
|
7
|
-
export const cellKey = (col: number, row: number): string => `${col},${row}`;
|
|
8
|
-
|
|
9
|
-
export const cellWidth = (viewport: Viewport): number => viewport.baseCellWidth * viewport.zoomX;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Convert a cell's world coordinates to screen-space pixel rectangle (relative to canvas origin).
|
|
13
|
-
*/
|
|
14
|
-
export const worldToScreen = (
|
|
15
|
-
viewport: Viewport,
|
|
16
|
-
headers: Headers,
|
|
17
|
-
coord: { col: number; row: number; length?: number },
|
|
18
|
-
): { x: number; y: number; w: number; h: number } => {
|
|
19
|
-
const w = cellWidth(viewport);
|
|
20
|
-
return {
|
|
21
|
-
x: headers.left + coord.col * w - viewport.scrollX,
|
|
22
|
-
y: headers.top + coord.row * viewport.cellHeight - viewport.scrollY,
|
|
23
|
-
w: (coord.length ?? 1) * w,
|
|
24
|
-
h: viewport.cellHeight,
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Convert screen-space pixels (relative to canvas origin) to fractional cell coordinates.
|
|
30
|
-
*/
|
|
31
|
-
export const screenToWorld = (
|
|
32
|
-
viewport: Viewport,
|
|
33
|
-
headers: Headers,
|
|
34
|
-
point: { x: number; y: number },
|
|
35
|
-
): { col: number; row: number } => {
|
|
36
|
-
const w = cellWidth(viewport);
|
|
37
|
-
return {
|
|
38
|
-
col: (point.x - headers.left + viewport.scrollX) / w,
|
|
39
|
-
row: (point.y - headers.top + viewport.scrollY) / viewport.cellHeight,
|
|
40
|
-
};
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export const hitTestCell = (
|
|
44
|
-
viewport: Viewport,
|
|
45
|
-
headers: Headers,
|
|
46
|
-
point: { x: number; y: number },
|
|
47
|
-
): CellCoord | null => {
|
|
48
|
-
if (point.x < headers.left || point.y < headers.top) {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
const { col, row } = screenToWorld(viewport, headers, point);
|
|
52
|
-
if (col < 0 || row < 0) {
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
return { col: Math.floor(col), row: Math.floor(row) };
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Compute the inclusive range of cell coordinates intersecting the visible content rect.
|
|
60
|
-
*/
|
|
61
|
-
export const visibleCellRange = (
|
|
62
|
-
viewport: Viewport,
|
|
63
|
-
headers: Headers,
|
|
64
|
-
size: { width: number; height: number },
|
|
65
|
-
): { minCol: number; maxCol: number; minRow: number; maxRow: number } => {
|
|
66
|
-
const w = cellWidth(viewport);
|
|
67
|
-
const innerW = Math.max(0, size.width - headers.left);
|
|
68
|
-
const innerH = Math.max(0, size.height - headers.top);
|
|
69
|
-
const minCol = Math.max(0, Math.floor(viewport.scrollX / w));
|
|
70
|
-
const maxCol = Math.floor((viewport.scrollX + innerW) / w);
|
|
71
|
-
const minRow = Math.max(0, Math.floor(viewport.scrollY / viewport.cellHeight));
|
|
72
|
-
const maxRow = Math.floor((viewport.scrollY + innerH) / viewport.cellHeight);
|
|
73
|
-
return { minCol, maxCol, minRow, maxRow };
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Iterate sparse cell map, yielding only cells whose horizontal extent intersects visible cols and whose row is visible.
|
|
78
|
-
*/
|
|
79
|
-
export const visibleCells = function* <T>(
|
|
80
|
-
cells: ReadonlyMap<string, Cell<T>>,
|
|
81
|
-
range: { minCol: number; maxCol: number; minRow: number; maxRow: number },
|
|
82
|
-
): Generator<Cell<T>> {
|
|
83
|
-
for (const cell of cells.values()) {
|
|
84
|
-
if (cell.row < range.minRow || cell.row > range.maxRow) {
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
const start = cell.col;
|
|
88
|
-
const end = cell.col + cell.length - 1;
|
|
89
|
-
if (end < range.minCol || start > range.maxCol) {
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
yield cell;
|
|
93
|
-
}
|
|
94
|
-
};
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
// Adapted from: https://github.com/smplrspace/react-fps-stats
|
|
4
|
-
//
|
|
5
|
-
|
|
6
|
-
import React, { useEffect, useReducer, useRef } from 'react';
|
|
7
|
-
|
|
8
|
-
import type * as Util from '@dxos/react-ui/Util';
|
|
9
|
-
import { mx } from '@dxos/ui-theme';
|
|
10
|
-
|
|
11
|
-
export type FPSProps = Util.ThemedClassName<{
|
|
12
|
-
width?: number;
|
|
13
|
-
height?: number;
|
|
14
|
-
bar?: string;
|
|
15
|
-
}>;
|
|
16
|
-
|
|
17
|
-
type State = {
|
|
18
|
-
max: number;
|
|
19
|
-
len: number;
|
|
20
|
-
fps: number[];
|
|
21
|
-
frames: number;
|
|
22
|
-
prevTime: number;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const SEC = 1_000;
|
|
26
|
-
|
|
27
|
-
export const FPS = ({ classNames, width = 60, height = 30, bar = 'bg-cyan-500' }: FPSProps) => {
|
|
28
|
-
const [{ fps, max, len }, dispatch] = useReducer(
|
|
29
|
-
(state: State) => {
|
|
30
|
-
const currentTime = Date.now();
|
|
31
|
-
if (currentTime > state.prevTime + SEC) {
|
|
32
|
-
const nextFPS = [
|
|
33
|
-
...new Array(Math.floor((currentTime - state.prevTime - SEC) / SEC)).fill(0),
|
|
34
|
-
Math.max(1, Math.round((state.frames * SEC) / (currentTime - state.prevTime))),
|
|
35
|
-
];
|
|
36
|
-
return {
|
|
37
|
-
max: Math.max(state.max, ...nextFPS),
|
|
38
|
-
len: Math.min(state.len + nextFPS.length, width),
|
|
39
|
-
fps: [...state.fps, ...nextFPS].slice(-width),
|
|
40
|
-
frames: 1,
|
|
41
|
-
prevTime: currentTime,
|
|
42
|
-
};
|
|
43
|
-
} else {
|
|
44
|
-
return { ...state, frames: state.frames + 1 };
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
max: 0,
|
|
49
|
-
len: 0,
|
|
50
|
-
fps: [],
|
|
51
|
-
frames: 0,
|
|
52
|
-
prevTime: Date.now(),
|
|
53
|
-
},
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
const requestRef = useRef<number | null>(null);
|
|
57
|
-
const tick = () => {
|
|
58
|
-
dispatch();
|
|
59
|
-
requestRef.current = requestAnimationFrame(tick);
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
useEffect(() => {
|
|
63
|
-
requestRef.current = requestAnimationFrame(tick);
|
|
64
|
-
return () => {
|
|
65
|
-
if (requestRef.current) {
|
|
66
|
-
cancelAnimationFrame(requestRef.current);
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
}, []);
|
|
70
|
-
|
|
71
|
-
return (
|
|
72
|
-
<div
|
|
73
|
-
style={{ width: width + 6 }}
|
|
74
|
-
className={mx(
|
|
75
|
-
'relative flex flex-col p-0.5',
|
|
76
|
-
'bg-base-surface text-xs text-fg-subtle font-thin pointer-events-none border border-separator',
|
|
77
|
-
classNames,
|
|
78
|
-
)}
|
|
79
|
-
>
|
|
80
|
-
<div>{fps[len - 1]} FPS</div>
|
|
81
|
-
<div className='w-full relative' style={{ height }}>
|
|
82
|
-
{fps.map((frame, i) => (
|
|
83
|
-
<div
|
|
84
|
-
key={`fps-${i}`}
|
|
85
|
-
className={bar}
|
|
86
|
-
style={{
|
|
87
|
-
position: 'absolute',
|
|
88
|
-
bottom: 0,
|
|
89
|
-
right: `${len - 1 - i}px`,
|
|
90
|
-
height: `${(height * frame) / max}px`,
|
|
91
|
-
width: 1,
|
|
92
|
-
}}
|
|
93
|
-
/>
|
|
94
|
-
))}
|
|
95
|
-
</div>
|
|
96
|
-
</div>
|
|
97
|
-
);
|
|
98
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import React from 'react';
|
|
6
|
-
|
|
7
|
-
import { GridComponent, type GridProps } from '../../../components/Grid/index.ts';
|
|
8
|
-
import { useCanvasContext } from '../../hooks/index.ts';
|
|
9
|
-
|
|
10
|
-
export type { GridProps };
|
|
11
|
-
export { GridComponent };
|
|
12
|
-
|
|
13
|
-
// TODO(burdon): Use id of parent canvas.
|
|
14
|
-
export const Grid = (props: GridProps) => {
|
|
15
|
-
const { scale, offset } = useCanvasContext();
|
|
16
|
-
return <GridComponent {...props} scale={scale} offset={offset} />;
|
|
17
|
-
};
|