@dxos/react-ui-canvas 0.8.4-main.ef1bc66f44 → 0.8.4-main.f466a3d56e
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 +102 -5
- package/dist/lib/browser/index.mjs +780 -22
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +780 -22
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Canvas/Canvas.d.ts +1 -1
- package/dist/types/src/components/Canvas/Canvas.stories.d.ts.map +1 -1
- package/dist/types/src/components/CellGrid/CellGrid.d.ts +21 -0
- package/dist/types/src/components/CellGrid/CellGrid.d.ts.map +1 -0
- package/dist/types/src/components/CellGrid/CellGrid.stories.d.ts +21 -0
- package/dist/types/src/components/CellGrid/CellGrid.stories.d.ts.map +1 -0
- package/dist/types/src/components/CellGrid/headers/Ruler.d.ts +15 -0
- package/dist/types/src/components/CellGrid/headers/Ruler.d.ts.map +1 -0
- package/dist/types/src/components/CellGrid/headers/TrackHeader.d.ts +19 -0
- package/dist/types/src/components/CellGrid/headers/TrackHeader.d.ts.map +1 -0
- package/dist/types/src/components/CellGrid/headers/index.d.ts +3 -0
- package/dist/types/src/components/CellGrid/headers/index.d.ts.map +1 -0
- package/dist/types/src/components/CellGrid/index.d.ts +6 -0
- package/dist/types/src/components/CellGrid/index.d.ts.map +1 -0
- package/dist/types/src/components/CellGrid/input/index.d.ts +3 -0
- package/dist/types/src/components/CellGrid/input/index.d.ts.map +1 -0
- package/dist/types/src/components/CellGrid/input/pointer.d.ts +29 -0
- package/dist/types/src/components/CellGrid/input/pointer.d.ts.map +1 -0
- package/dist/types/src/components/CellGrid/input/wheel.d.ts +14 -0
- package/dist/types/src/components/CellGrid/input/wheel.d.ts.map +1 -0
- package/dist/types/src/components/CellGrid/render/index.d.ts +3 -0
- package/dist/types/src/components/CellGrid/render/index.d.ts.map +1 -0
- package/dist/types/src/components/CellGrid/render/overlay-layer.d.ts +21 -0
- package/dist/types/src/components/CellGrid/render/overlay-layer.d.ts.map +1 -0
- package/dist/types/src/components/CellGrid/render/static-layer.d.ts +36 -0
- package/dist/types/src/components/CellGrid/render/static-layer.d.ts.map +1 -0
- package/dist/types/src/components/CellGrid/state/atoms.d.ts +23 -0
- package/dist/types/src/components/CellGrid/state/atoms.d.ts.map +1 -0
- package/dist/types/src/components/CellGrid/state/index.d.ts +4 -0
- package/dist/types/src/components/CellGrid/state/index.d.ts.map +1 -0
- package/dist/types/src/components/CellGrid/state/types.d.ts +39 -0
- package/dist/types/src/components/CellGrid/state/types.d.ts.map +1 -0
- package/dist/types/src/components/CellGrid/state/viewport.d.ts +52 -0
- package/dist/types/src/components/CellGrid/state/viewport.d.ts.map +1 -0
- package/dist/types/src/components/CellGrid/state/viewport.test.d.ts +2 -0
- package/dist/types/src/components/CellGrid/state/viewport.test.d.ts.map +1 -0
- package/dist/types/src/components/FPS.d.ts.map +1 -1
- package/dist/types/src/components/Grid/Grid.d.ts.map +1 -1
- package/dist/types/src/components/Grid/Grid.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +1 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/hooks/projection.d.ts.map +1 -1
- package/dist/types/src/hooks/useDrag.d.ts.map +1 -1
- package/dist/types/src/hooks/useWheel.d.ts.map +1 -1
- package/dist/types/src/util/svg.d.ts +1 -1
- package/dist/types/src/util/svg.d.ts.map +1 -1
- package/dist/types/src/util/svg.stories.d.ts.map +1 -1
- package/dist/types/src/util/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -18
- package/src/components/Canvas/Canvas.stories.tsx +5 -6
- package/src/components/Canvas/Canvas.tsx +3 -3
- package/src/components/CellGrid/CellGrid.stories.tsx +238 -0
- package/src/components/CellGrid/CellGrid.tsx +266 -0
- package/src/components/CellGrid/headers/Ruler.tsx +71 -0
- package/src/components/CellGrid/headers/TrackHeader.tsx +58 -0
- package/src/components/CellGrid/headers/index.ts +6 -0
- package/src/components/CellGrid/index.ts +9 -0
- package/src/components/CellGrid/input/index.ts +6 -0
- package/src/components/CellGrid/input/pointer.ts +208 -0
- package/src/components/CellGrid/input/wheel.ts +68 -0
- package/src/components/CellGrid/render/index.ts +6 -0
- package/src/components/CellGrid/render/overlay-layer.ts +66 -0
- package/src/components/CellGrid/render/static-layer.ts +112 -0
- package/src/components/CellGrid/state/atoms.ts +43 -0
- package/src/components/CellGrid/state/index.ts +7 -0
- package/src/components/CellGrid/state/types.ts +40 -0
- package/src/components/CellGrid/state/viewport.test.ts +50 -0
- package/src/components/CellGrid/state/viewport.ts +94 -0
- package/src/components/FPS.tsx +2 -2
- package/src/components/Grid/Grid.stories.tsx +3 -4
- package/src/components/Grid/Grid.tsx +1 -5
- package/src/components/index.ts +1 -0
- package/src/hooks/useWheel.tsx +0 -1
- package/src/util/svg.stories.tsx +1 -1
|
@@ -400,11 +400,11 @@ var isWheelZooming = (ev) => {
|
|
|
400
400
|
};
|
|
401
401
|
|
|
402
402
|
// src/components/Canvas/Canvas.tsx
|
|
403
|
-
var Canvas = /* @__PURE__ */ forwardRef(({ children, classNames, scale:
|
|
403
|
+
var Canvas = /* @__PURE__ */ forwardRef(({ children, classNames, scale: scaleProp = 1, offset: offsetProp = defaultOrigin, ...props }, forwardedRef) => {
|
|
404
404
|
const { ref, width = 0, height = 0 } = useResizeDetector();
|
|
405
405
|
const [ready, setReady] = useState(false);
|
|
406
406
|
const [{ scale, offset }, setProjection] = useState({
|
|
407
|
-
scale:
|
|
407
|
+
scale: scaleProp,
|
|
408
408
|
offset: offsetProp
|
|
409
409
|
});
|
|
410
410
|
useEffect3(() => {
|
|
@@ -471,16 +471,757 @@ var Canvas = /* @__PURE__ */ forwardRef(({ children, classNames, scale: _scale =
|
|
|
471
471
|
setProjection
|
|
472
472
|
}
|
|
473
473
|
}, /* @__PURE__ */ React2.createElement("div", {
|
|
474
|
-
role: "none",
|
|
475
474
|
...props,
|
|
476
475
|
className: mx2("absolute inset-0 overflow-hidden", classNames),
|
|
477
476
|
ref
|
|
478
477
|
}, ready ? children : null));
|
|
479
478
|
});
|
|
480
479
|
|
|
481
|
-
// src/components/
|
|
482
|
-
import
|
|
480
|
+
// src/components/CellGrid/CellGrid.tsx
|
|
481
|
+
import { RegistryContext } from "@effect-atom/atom-react";
|
|
482
|
+
import React5, { useContext as useContext2, useEffect as useEffect4, useMemo as useMemo3, useRef as useRef2, useState as useState2 } from "react";
|
|
483
|
+
import { useResizeDetector as useResizeDetector2 } from "react-resize-detector";
|
|
484
|
+
import { mx as mx5 } from "@dxos/ui-theme";
|
|
485
|
+
|
|
486
|
+
// src/components/CellGrid/headers/Ruler.tsx
|
|
487
|
+
import React3, { useMemo as useMemo2 } from "react";
|
|
483
488
|
import { mx as mx3 } from "@dxos/ui-theme";
|
|
489
|
+
|
|
490
|
+
// src/components/CellGrid/state/viewport.ts
|
|
491
|
+
var cellKey = (col, row) => `${col},${row}`;
|
|
492
|
+
var cellWidth = (viewport) => viewport.baseCellWidth * viewport.zoomX;
|
|
493
|
+
var worldToScreen = (viewport, headers, coord) => {
|
|
494
|
+
const w = cellWidth(viewport);
|
|
495
|
+
return {
|
|
496
|
+
x: headers.left + coord.col * w - viewport.scrollX,
|
|
497
|
+
y: headers.top + coord.row * viewport.cellHeight - viewport.scrollY,
|
|
498
|
+
w: (coord.length ?? 1) * w,
|
|
499
|
+
h: viewport.cellHeight
|
|
500
|
+
};
|
|
501
|
+
};
|
|
502
|
+
var screenToWorld = (viewport, headers, point) => {
|
|
503
|
+
const w = cellWidth(viewport);
|
|
504
|
+
return {
|
|
505
|
+
col: (point.x - headers.left + viewport.scrollX) / w,
|
|
506
|
+
row: (point.y - headers.top + viewport.scrollY) / viewport.cellHeight
|
|
507
|
+
};
|
|
508
|
+
};
|
|
509
|
+
var hitTestCell = (viewport, headers, point) => {
|
|
510
|
+
if (point.x < headers.left || point.y < headers.top) {
|
|
511
|
+
return null;
|
|
512
|
+
}
|
|
513
|
+
const { col, row } = screenToWorld(viewport, headers, point);
|
|
514
|
+
if (col < 0 || row < 0) {
|
|
515
|
+
return null;
|
|
516
|
+
}
|
|
517
|
+
return {
|
|
518
|
+
col: Math.floor(col),
|
|
519
|
+
row: Math.floor(row)
|
|
520
|
+
};
|
|
521
|
+
};
|
|
522
|
+
var visibleCellRange = (viewport, headers, size) => {
|
|
523
|
+
const w = cellWidth(viewport);
|
|
524
|
+
const innerW = Math.max(0, size.width - headers.left);
|
|
525
|
+
const innerH = Math.max(0, size.height - headers.top);
|
|
526
|
+
const minCol = Math.max(0, Math.floor(viewport.scrollX / w));
|
|
527
|
+
const maxCol = Math.floor((viewport.scrollX + innerW) / w);
|
|
528
|
+
const minRow = Math.max(0, Math.floor(viewport.scrollY / viewport.cellHeight));
|
|
529
|
+
const maxRow = Math.floor((viewport.scrollY + innerH) / viewport.cellHeight);
|
|
530
|
+
return {
|
|
531
|
+
minCol,
|
|
532
|
+
maxCol,
|
|
533
|
+
minRow,
|
|
534
|
+
maxRow
|
|
535
|
+
};
|
|
536
|
+
};
|
|
537
|
+
var visibleCells = function* (cells, range) {
|
|
538
|
+
for (const cell of cells.values()) {
|
|
539
|
+
if (cell.row < range.minRow || cell.row > range.maxRow) {
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
const start = cell.col;
|
|
543
|
+
const end = cell.col + cell.length - 1;
|
|
544
|
+
if (end < range.minCol || start > range.maxCol) {
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
547
|
+
yield cell;
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
// src/components/CellGrid/headers/Ruler.tsx
|
|
552
|
+
var Ruler = ({ viewport, headers, width, majorEvery = 4, classNames }) => {
|
|
553
|
+
const safeMajorEvery = Math.max(1, Math.floor(majorEvery));
|
|
554
|
+
const ticks = useMemo2(() => {
|
|
555
|
+
const w = cellWidth(viewport);
|
|
556
|
+
if (w < 1 || width <= headers.left) {
|
|
557
|
+
return [];
|
|
558
|
+
}
|
|
559
|
+
const innerWidth = width - headers.left;
|
|
560
|
+
const startCol = Math.floor(viewport.scrollX / w);
|
|
561
|
+
const endCol = Math.ceil((viewport.scrollX + innerWidth) / w);
|
|
562
|
+
const result = [];
|
|
563
|
+
for (let col = startCol; col <= endCol; col++) {
|
|
564
|
+
result.push({
|
|
565
|
+
col,
|
|
566
|
+
x: headers.left + col * w - viewport.scrollX,
|
|
567
|
+
major: col % safeMajorEvery === 0
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
return result;
|
|
571
|
+
}, [
|
|
572
|
+
viewport,
|
|
573
|
+
headers.left,
|
|
574
|
+
width,
|
|
575
|
+
safeMajorEvery
|
|
576
|
+
]);
|
|
577
|
+
return /* @__PURE__ */ React3.createElement("div", {
|
|
578
|
+
className: mx3("absolute top-0 left-0 right-0 border-b border-neutral-200 dark:border-neutral-700 bg-baseSurface select-none overflow-hidden", classNames),
|
|
579
|
+
style: {
|
|
580
|
+
height: headers.top
|
|
581
|
+
}
|
|
582
|
+
}, ticks.map(({ col, x, major }) => /* @__PURE__ */ React3.createElement("div", {
|
|
583
|
+
key: col,
|
|
584
|
+
className: mx3("absolute top-0 bottom-0 text-[10px] text-neutral-500 dark:text-neutral-400", major ? "border-l border-neutral-400 dark:border-neutral-500" : "border-l border-neutral-200 dark:border-neutral-700"),
|
|
585
|
+
style: {
|
|
586
|
+
transform: `translateX(${x}px)`
|
|
587
|
+
}
|
|
588
|
+
}, major ? /* @__PURE__ */ React3.createElement("span", {
|
|
589
|
+
className: "absolute left-1 top-0"
|
|
590
|
+
}, col) : null)));
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
// src/components/CellGrid/headers/TrackHeader.tsx
|
|
594
|
+
import React4 from "react";
|
|
595
|
+
import { mx as mx4 } from "@dxos/ui-theme";
|
|
596
|
+
var TrackHeader = ({ viewport, headers, rows, height, classNames }) => {
|
|
597
|
+
return /* @__PURE__ */ React4.createElement("div", {
|
|
598
|
+
className: mx4("absolute left-0 border-r border-neutral-200 dark:border-neutral-700 select-none overflow-hidden", classNames),
|
|
599
|
+
style: {
|
|
600
|
+
top: headers.top,
|
|
601
|
+
width: headers.left,
|
|
602
|
+
height: Math.max(0, height - headers.top)
|
|
603
|
+
}
|
|
604
|
+
}, /* @__PURE__ */ React4.createElement("div", {
|
|
605
|
+
style: {
|
|
606
|
+
transform: `translateY(${-viewport.scrollY}px)`
|
|
607
|
+
}
|
|
608
|
+
}, rows.map((row, index) => /* @__PURE__ */ React4.createElement("div", {
|
|
609
|
+
key: row.id,
|
|
610
|
+
className: "flex items-center px-2 text-xs text-neutral-700 dark:text-neutral-300",
|
|
611
|
+
style: {
|
|
612
|
+
height: viewport.cellHeight,
|
|
613
|
+
// Match the canvas's row-band: a translucent gray overlay on odd rows,
|
|
614
|
+
// transparent on even rows. The container's overall background bleeds
|
|
615
|
+
// through, so the labels stay legible in both themes.
|
|
616
|
+
backgroundColor: index % 2 === 0 ? "transparent" : "rgba(128, 128, 128, 0.08)",
|
|
617
|
+
// Match the canvas gridline color (rgba(128, 128, 128, 0.25)). Use a
|
|
618
|
+
// half-pixel inset to keep crisp single-pixel rendering on retina.
|
|
619
|
+
boxShadow: "inset 0 -1px 0 rgba(128, 128, 128, 0.25)"
|
|
620
|
+
}
|
|
621
|
+
}, row.label ?? row.id))));
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
// src/components/CellGrid/input/pointer.ts
|
|
625
|
+
var attachPointerHandlers = (element, { registry, atoms, headers, handlers }) => {
|
|
626
|
+
let drag = null;
|
|
627
|
+
const local = (event) => {
|
|
628
|
+
const rect = element.getBoundingClientRect();
|
|
629
|
+
return {
|
|
630
|
+
x: event.clientX - rect.left,
|
|
631
|
+
y: event.clientY - rect.top
|
|
632
|
+
};
|
|
633
|
+
};
|
|
634
|
+
const tryCapture = (pointerId) => {
|
|
635
|
+
try {
|
|
636
|
+
element.setPointerCapture(pointerId);
|
|
637
|
+
} catch {
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
const onPointerDown = (event) => {
|
|
641
|
+
if (event.button === 1 || event.button === 0 && event.altKey) {
|
|
642
|
+
drag = {
|
|
643
|
+
kind: "pan",
|
|
644
|
+
lastX: event.clientX,
|
|
645
|
+
lastY: event.clientY
|
|
646
|
+
};
|
|
647
|
+
tryCapture(event.pointerId);
|
|
648
|
+
event.preventDefault();
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
if (event.button !== 0) {
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
const viewport = registry.get(atoms.viewport);
|
|
655
|
+
const point = local(event);
|
|
656
|
+
const coord = hitTestCell(viewport, headers, point);
|
|
657
|
+
if (!coord) {
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
const tool = registry.get(atoms.tool);
|
|
661
|
+
tryCapture(event.pointerId);
|
|
662
|
+
switch (tool) {
|
|
663
|
+
case "toggle":
|
|
664
|
+
case "resize": {
|
|
665
|
+
const cells = registry.get(atoms.cells);
|
|
666
|
+
const key = cellKey(coord.col, coord.row);
|
|
667
|
+
const mode = cells.has(key) ? "unset" : "set";
|
|
668
|
+
handlers.onCellToggle?.(coord, mode);
|
|
669
|
+
drag = {
|
|
670
|
+
kind: "toggle",
|
|
671
|
+
mode,
|
|
672
|
+
touched: /* @__PURE__ */ new Set([
|
|
673
|
+
key
|
|
674
|
+
])
|
|
675
|
+
};
|
|
676
|
+
break;
|
|
677
|
+
}
|
|
678
|
+
case "select": {
|
|
679
|
+
drag = {
|
|
680
|
+
kind: "select",
|
|
681
|
+
origin: coord
|
|
682
|
+
};
|
|
683
|
+
registry.set(atoms.selection, {
|
|
684
|
+
range: {
|
|
685
|
+
col0: coord.col,
|
|
686
|
+
row0: coord.row,
|
|
687
|
+
col1: coord.col,
|
|
688
|
+
row1: coord.row
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
break;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
const onPointerMove = (event) => {
|
|
696
|
+
if (!drag) {
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
if (drag.kind === "pan") {
|
|
700
|
+
const dx = event.clientX - drag.lastX;
|
|
701
|
+
const dy = event.clientY - drag.lastY;
|
|
702
|
+
drag.lastX = event.clientX;
|
|
703
|
+
drag.lastY = event.clientY;
|
|
704
|
+
registry.update(atoms.viewport, (current) => ({
|
|
705
|
+
...current,
|
|
706
|
+
scrollX: Math.max(0, current.scrollX - dx),
|
|
707
|
+
scrollY: Math.max(0, current.scrollY - dy)
|
|
708
|
+
}));
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
const viewport = registry.get(atoms.viewport);
|
|
712
|
+
const coord = hitTestCell(viewport, headers, local(event));
|
|
713
|
+
if (!coord) {
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
if (drag.kind === "toggle") {
|
|
717
|
+
const key = cellKey(coord.col, coord.row);
|
|
718
|
+
if (!drag.touched.has(key)) {
|
|
719
|
+
drag.touched.add(key);
|
|
720
|
+
handlers.onCellToggle?.(coord, drag.mode);
|
|
721
|
+
}
|
|
722
|
+
} else if (drag.kind === "select") {
|
|
723
|
+
registry.set(atoms.selection, {
|
|
724
|
+
range: {
|
|
725
|
+
col0: drag.origin.col,
|
|
726
|
+
row0: drag.origin.row,
|
|
727
|
+
col1: coord.col,
|
|
728
|
+
row1: coord.row
|
|
729
|
+
}
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
};
|
|
733
|
+
const releaseCapture = (event) => {
|
|
734
|
+
if (element.hasPointerCapture(event.pointerId)) {
|
|
735
|
+
element.releasePointerCapture(event.pointerId);
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
const onPointerUp = (event) => {
|
|
739
|
+
if (!drag) {
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
if (drag.kind === "select") {
|
|
743
|
+
const range = registry.get(atoms.selection).range;
|
|
744
|
+
if (range) {
|
|
745
|
+
handlers.onSelectionCommit?.(range);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
drag = null;
|
|
749
|
+
releaseCapture(event);
|
|
750
|
+
};
|
|
751
|
+
const onPointerCancel = (event) => {
|
|
752
|
+
drag = null;
|
|
753
|
+
releaseCapture(event);
|
|
754
|
+
};
|
|
755
|
+
element.addEventListener("pointerdown", onPointerDown);
|
|
756
|
+
element.addEventListener("pointermove", onPointerMove);
|
|
757
|
+
element.addEventListener("pointerup", onPointerUp);
|
|
758
|
+
element.addEventListener("pointercancel", onPointerCancel);
|
|
759
|
+
return () => {
|
|
760
|
+
element.removeEventListener("pointerdown", onPointerDown);
|
|
761
|
+
element.removeEventListener("pointermove", onPointerMove);
|
|
762
|
+
element.removeEventListener("pointerup", onPointerUp);
|
|
763
|
+
element.removeEventListener("pointercancel", onPointerCancel);
|
|
764
|
+
};
|
|
765
|
+
};
|
|
766
|
+
var toggleCell = (registry, atoms, coord, factory, mode = "toggle") => {
|
|
767
|
+
registry.update(atoms.cells, (current) => {
|
|
768
|
+
const next = new Map(current);
|
|
769
|
+
const key = cellKey(coord.col, coord.row);
|
|
770
|
+
const exists = next.has(key);
|
|
771
|
+
if (mode === "set" || mode === "toggle" && !exists) {
|
|
772
|
+
next.set(key, factory(coord));
|
|
773
|
+
} else if (mode === "unset" || mode === "toggle" && exists) {
|
|
774
|
+
next.delete(key);
|
|
775
|
+
}
|
|
776
|
+
return next;
|
|
777
|
+
});
|
|
778
|
+
};
|
|
779
|
+
|
|
780
|
+
// src/components/CellGrid/input/wheel.ts
|
|
781
|
+
var MIN_ZOOM = 0.25;
|
|
782
|
+
var MAX_ZOOM = 8;
|
|
783
|
+
var attachWheelHandlers = (element, { registry, atoms, headers }) => {
|
|
784
|
+
const onWheel = (event) => {
|
|
785
|
+
if (event.ctrlKey || event.metaKey) {
|
|
786
|
+
event.preventDefault();
|
|
787
|
+
const rect = element.getBoundingClientRect();
|
|
788
|
+
const x = event.clientX - rect.left;
|
|
789
|
+
const factor = Math.exp(-event.deltaY / 200);
|
|
790
|
+
registry.update(atoms.viewport, (current2) => {
|
|
791
|
+
const nextZoom = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, current2.zoomX * factor));
|
|
792
|
+
if (nextZoom === current2.zoomX) {
|
|
793
|
+
return current2;
|
|
794
|
+
}
|
|
795
|
+
const w = cellWidth(current2);
|
|
796
|
+
const worldX = (x - headers.left + current2.scrollX) / w;
|
|
797
|
+
const nextW = current2.baseCellWidth * nextZoom;
|
|
798
|
+
const nextScrollX2 = Math.max(0, worldX * nextW - (x - headers.left));
|
|
799
|
+
return {
|
|
800
|
+
...current2,
|
|
801
|
+
zoomX: nextZoom,
|
|
802
|
+
scrollX: nextScrollX2
|
|
803
|
+
};
|
|
804
|
+
});
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
const dx = event.shiftKey ? event.deltaY : event.deltaX;
|
|
808
|
+
const dy = event.shiftKey ? 0 : event.deltaY;
|
|
809
|
+
const current = registry.get(atoms.viewport);
|
|
810
|
+
const nextScrollX = Math.max(0, current.scrollX + dx);
|
|
811
|
+
const nextScrollY = Math.max(0, current.scrollY + dy);
|
|
812
|
+
if (nextScrollX === current.scrollX && nextScrollY === current.scrollY) {
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
event.preventDefault();
|
|
816
|
+
registry.set(atoms.viewport, {
|
|
817
|
+
...current,
|
|
818
|
+
scrollX: nextScrollX,
|
|
819
|
+
scrollY: nextScrollY
|
|
820
|
+
});
|
|
821
|
+
};
|
|
822
|
+
element.addEventListener("wheel", onWheel, {
|
|
823
|
+
passive: false
|
|
824
|
+
});
|
|
825
|
+
return () => element.removeEventListener("wheel", onWheel);
|
|
826
|
+
};
|
|
827
|
+
|
|
828
|
+
// src/components/CellGrid/render/overlay-layer.ts
|
|
829
|
+
var drawOverlay = ({ ctx, size, viewport, headers, selection, playhead, style }) => {
|
|
830
|
+
ctx.clearRect(0, 0, size.width, size.height);
|
|
831
|
+
ctx.save();
|
|
832
|
+
ctx.beginPath();
|
|
833
|
+
ctx.rect(headers.left, headers.top, size.width - headers.left, size.height - headers.top);
|
|
834
|
+
ctx.clip();
|
|
835
|
+
if (selection.range) {
|
|
836
|
+
const { col0, row0, col1, row1 } = selection.range;
|
|
837
|
+
const minCol = Math.min(col0, col1);
|
|
838
|
+
const maxCol = Math.max(col0, col1);
|
|
839
|
+
const minRow = Math.min(row0, row1);
|
|
840
|
+
const maxRow = Math.max(row0, row1);
|
|
841
|
+
const tl = worldToScreen(viewport, headers, {
|
|
842
|
+
col: minCol,
|
|
843
|
+
row: minRow
|
|
844
|
+
});
|
|
845
|
+
const br = worldToScreen(viewport, headers, {
|
|
846
|
+
col: maxCol + 1,
|
|
847
|
+
row: maxRow + 1
|
|
848
|
+
});
|
|
849
|
+
ctx.fillStyle = style.selectionFill;
|
|
850
|
+
ctx.fillRect(tl.x, tl.y, br.x - tl.x, br.y - tl.y);
|
|
851
|
+
ctx.strokeStyle = style.selectionStroke;
|
|
852
|
+
ctx.setLineDash([
|
|
853
|
+
4,
|
|
854
|
+
3
|
|
855
|
+
]);
|
|
856
|
+
ctx.lineWidth = 1;
|
|
857
|
+
ctx.strokeRect(tl.x + 0.5, tl.y + 0.5, br.x - tl.x - 1, br.y - tl.y - 1);
|
|
858
|
+
ctx.setLineDash([]);
|
|
859
|
+
}
|
|
860
|
+
if (playhead !== null) {
|
|
861
|
+
const w = cellWidth(viewport);
|
|
862
|
+
const x = headers.left + playhead * w - viewport.scrollX;
|
|
863
|
+
if (x >= headers.left && x <= size.width) {
|
|
864
|
+
ctx.strokeStyle = style.playhead;
|
|
865
|
+
ctx.lineWidth = 2;
|
|
866
|
+
ctx.beginPath();
|
|
867
|
+
ctx.moveTo(x, headers.top);
|
|
868
|
+
ctx.lineTo(x, size.height);
|
|
869
|
+
ctx.stroke();
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
ctx.restore();
|
|
873
|
+
};
|
|
874
|
+
|
|
875
|
+
// src/components/CellGrid/render/static-layer.ts
|
|
876
|
+
var drawCells = ({ ctx, size, viewport, headers, rows, cells, renderCell, style }) => {
|
|
877
|
+
ctx.clearRect(0, 0, size.width, size.height);
|
|
878
|
+
if (style.background) {
|
|
879
|
+
ctx.fillStyle = style.background;
|
|
880
|
+
ctx.fillRect(0, 0, size.width, size.height);
|
|
881
|
+
}
|
|
882
|
+
const range = visibleCellRange(viewport, headers, size);
|
|
883
|
+
const w = cellWidth(viewport);
|
|
884
|
+
const h = viewport.cellHeight;
|
|
885
|
+
if (style.rowBand) {
|
|
886
|
+
ctx.fillStyle = style.rowBand;
|
|
887
|
+
for (let row = range.minRow; row <= Math.min(range.maxRow, rows.length - 1); row++) {
|
|
888
|
+
if (row % 2 === 0) {
|
|
889
|
+
continue;
|
|
890
|
+
}
|
|
891
|
+
const y = headers.top + row * h - viewport.scrollY;
|
|
892
|
+
ctx.fillRect(headers.left, y, size.width - headers.left, h);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
ctx.strokeStyle = style.gridLine;
|
|
896
|
+
ctx.lineWidth = 1;
|
|
897
|
+
ctx.beginPath();
|
|
898
|
+
for (let col = range.minCol; col <= range.maxCol + 1; col++) {
|
|
899
|
+
const x = Math.floor(headers.left + col * w - viewport.scrollX) + 0.5;
|
|
900
|
+
if (x < headers.left) {
|
|
901
|
+
continue;
|
|
902
|
+
}
|
|
903
|
+
ctx.moveTo(x, headers.top);
|
|
904
|
+
ctx.lineTo(x, size.height);
|
|
905
|
+
}
|
|
906
|
+
for (let row = range.minRow; row <= Math.min(range.maxRow + 1, rows.length); row++) {
|
|
907
|
+
const y = Math.floor(headers.top + row * h - viewport.scrollY) + 0.5;
|
|
908
|
+
if (y < headers.top) {
|
|
909
|
+
continue;
|
|
910
|
+
}
|
|
911
|
+
ctx.moveTo(headers.left, y);
|
|
912
|
+
ctx.lineTo(size.width, y);
|
|
913
|
+
}
|
|
914
|
+
ctx.stroke();
|
|
915
|
+
ctx.save();
|
|
916
|
+
ctx.beginPath();
|
|
917
|
+
ctx.rect(headers.left, headers.top, size.width - headers.left, size.height - headers.top);
|
|
918
|
+
ctx.clip();
|
|
919
|
+
for (const cell of visibleCells(cells, range)) {
|
|
920
|
+
if (cell.row >= rows.length) {
|
|
921
|
+
continue;
|
|
922
|
+
}
|
|
923
|
+
const rect = worldToScreen(viewport, headers, cell);
|
|
924
|
+
renderCell({
|
|
925
|
+
ctx,
|
|
926
|
+
...rect,
|
|
927
|
+
cell
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
ctx.restore();
|
|
931
|
+
};
|
|
932
|
+
|
|
933
|
+
// src/components/CellGrid/CellGrid.tsx
|
|
934
|
+
var defaultHeaders = {
|
|
935
|
+
left: 80,
|
|
936
|
+
top: 24
|
|
937
|
+
};
|
|
938
|
+
var defaultStaticStyle = {
|
|
939
|
+
gridLine: "rgba(128,128,128,0.25)",
|
|
940
|
+
rowBand: "rgba(128,128,128,0.06)"
|
|
941
|
+
};
|
|
942
|
+
var defaultOverlayStyle = {
|
|
943
|
+
playhead: "rgb(220, 38, 38)",
|
|
944
|
+
selectionFill: "rgba(59, 130, 246, 0.15)",
|
|
945
|
+
selectionStroke: "rgb(59, 130, 246)"
|
|
946
|
+
};
|
|
947
|
+
var setupCanvas = (canvas, width, height) => {
|
|
948
|
+
const dpr = window.devicePixelRatio || 1;
|
|
949
|
+
canvas.width = Math.max(1, Math.floor(width * dpr));
|
|
950
|
+
canvas.height = Math.max(1, Math.floor(height * dpr));
|
|
951
|
+
canvas.style.width = `${width}px`;
|
|
952
|
+
canvas.style.height = `${height}px`;
|
|
953
|
+
const ctx = canvas.getContext("2d");
|
|
954
|
+
if (!ctx) {
|
|
955
|
+
return null;
|
|
956
|
+
}
|
|
957
|
+
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
958
|
+
return ctx;
|
|
959
|
+
};
|
|
960
|
+
var CellGrid = ({ atoms, rows, renderCell, headers: headersProp, staticStyle: staticStyleProp, overlayStyle: overlayStyleProp, classNames, onCellToggle, onSelectionCommit }) => {
|
|
961
|
+
const registry = useContext2(RegistryContext);
|
|
962
|
+
const headers = useMemo3(() => {
|
|
963
|
+
if (headersProp === false) {
|
|
964
|
+
return {
|
|
965
|
+
left: 0,
|
|
966
|
+
top: 0
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
return {
|
|
970
|
+
...defaultHeaders,
|
|
971
|
+
...headersProp ?? {}
|
|
972
|
+
};
|
|
973
|
+
}, [
|
|
974
|
+
headersProp
|
|
975
|
+
]);
|
|
976
|
+
const staticStyle = useMemo3(() => ({
|
|
977
|
+
...defaultStaticStyle,
|
|
978
|
+
...staticStyleProp ?? {}
|
|
979
|
+
}), [
|
|
980
|
+
staticStyleProp
|
|
981
|
+
]);
|
|
982
|
+
const overlayStyle = useMemo3(() => ({
|
|
983
|
+
...defaultOverlayStyle,
|
|
984
|
+
...overlayStyleProp ?? {}
|
|
985
|
+
}), [
|
|
986
|
+
overlayStyleProp
|
|
987
|
+
]);
|
|
988
|
+
const { ref: containerRef, width = 0, height = 0 } = useResizeDetector2();
|
|
989
|
+
const staticCanvasRef = useRef2(null);
|
|
990
|
+
const overlayCanvasRef = useRef2(null);
|
|
991
|
+
const overlayInputRef = useRef2(null);
|
|
992
|
+
const [staticCtx, setStaticCtx] = useState2(null);
|
|
993
|
+
const [overlayCtx, setOverlayCtx] = useState2(null);
|
|
994
|
+
const [viewportState, setViewportState] = useState2(() => registry.get(atoms.viewport));
|
|
995
|
+
useEffect4(() => {
|
|
996
|
+
if (!width || !height) {
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
if (staticCanvasRef.current) {
|
|
1000
|
+
const ctx = setupCanvas(staticCanvasRef.current, width, height);
|
|
1001
|
+
setStaticCtx(ctx);
|
|
1002
|
+
}
|
|
1003
|
+
if (overlayCanvasRef.current) {
|
|
1004
|
+
const ctx = setupCanvas(overlayCanvasRef.current, width, height);
|
|
1005
|
+
setOverlayCtx(ctx);
|
|
1006
|
+
}
|
|
1007
|
+
}, [
|
|
1008
|
+
width,
|
|
1009
|
+
height
|
|
1010
|
+
]);
|
|
1011
|
+
useEffect4(() => registry.subscribe(atoms.viewport, (next) => setViewportState(next)), [
|
|
1012
|
+
registry,
|
|
1013
|
+
atoms.viewport
|
|
1014
|
+
]);
|
|
1015
|
+
useEffect4(() => {
|
|
1016
|
+
if (!staticCtx || !width || !height) {
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
let raf = null;
|
|
1020
|
+
const schedule = () => {
|
|
1021
|
+
if (raf !== null) {
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1024
|
+
raf = requestAnimationFrame(() => {
|
|
1025
|
+
raf = null;
|
|
1026
|
+
drawCells({
|
|
1027
|
+
ctx: staticCtx,
|
|
1028
|
+
size: {
|
|
1029
|
+
width,
|
|
1030
|
+
height
|
|
1031
|
+
},
|
|
1032
|
+
viewport: registry.get(atoms.viewport),
|
|
1033
|
+
headers,
|
|
1034
|
+
rows,
|
|
1035
|
+
cells: registry.get(atoms.cells),
|
|
1036
|
+
renderCell,
|
|
1037
|
+
style: staticStyle
|
|
1038
|
+
});
|
|
1039
|
+
});
|
|
1040
|
+
};
|
|
1041
|
+
schedule();
|
|
1042
|
+
const unsubCells = registry.subscribe(atoms.cells, schedule);
|
|
1043
|
+
const unsubViewport = registry.subscribe(atoms.viewport, schedule);
|
|
1044
|
+
return () => {
|
|
1045
|
+
if (raf !== null) {
|
|
1046
|
+
cancelAnimationFrame(raf);
|
|
1047
|
+
}
|
|
1048
|
+
unsubCells();
|
|
1049
|
+
unsubViewport();
|
|
1050
|
+
};
|
|
1051
|
+
}, [
|
|
1052
|
+
staticCtx,
|
|
1053
|
+
width,
|
|
1054
|
+
height,
|
|
1055
|
+
registry,
|
|
1056
|
+
atoms.cells,
|
|
1057
|
+
atoms.viewport,
|
|
1058
|
+
headers,
|
|
1059
|
+
rows,
|
|
1060
|
+
renderCell,
|
|
1061
|
+
staticStyle
|
|
1062
|
+
]);
|
|
1063
|
+
useEffect4(() => {
|
|
1064
|
+
if (!overlayCtx || !width || !height) {
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
let raf = null;
|
|
1068
|
+
let stopped = false;
|
|
1069
|
+
const paint = () => {
|
|
1070
|
+
drawOverlay({
|
|
1071
|
+
ctx: overlayCtx,
|
|
1072
|
+
size: {
|
|
1073
|
+
width,
|
|
1074
|
+
height
|
|
1075
|
+
},
|
|
1076
|
+
viewport: registry.get(atoms.viewport),
|
|
1077
|
+
headers,
|
|
1078
|
+
selection: registry.get(atoms.selection),
|
|
1079
|
+
playhead: registry.get(atoms.playhead),
|
|
1080
|
+
style: overlayStyle
|
|
1081
|
+
});
|
|
1082
|
+
};
|
|
1083
|
+
const isAnimating = () => registry.get(atoms.playhead) !== null;
|
|
1084
|
+
const loop = () => {
|
|
1085
|
+
if (stopped) {
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1088
|
+
paint();
|
|
1089
|
+
if (isAnimating()) {
|
|
1090
|
+
raf = requestAnimationFrame(loop);
|
|
1091
|
+
} else {
|
|
1092
|
+
raf = null;
|
|
1093
|
+
}
|
|
1094
|
+
};
|
|
1095
|
+
const kick = () => {
|
|
1096
|
+
paint();
|
|
1097
|
+
if (raf === null && isAnimating()) {
|
|
1098
|
+
raf = requestAnimationFrame(loop);
|
|
1099
|
+
}
|
|
1100
|
+
};
|
|
1101
|
+
kick();
|
|
1102
|
+
const unsubSelection = registry.subscribe(atoms.selection, () => paint());
|
|
1103
|
+
const unsubPlayhead = registry.subscribe(atoms.playhead, kick);
|
|
1104
|
+
const unsubViewport = registry.subscribe(atoms.viewport, () => paint());
|
|
1105
|
+
return () => {
|
|
1106
|
+
stopped = true;
|
|
1107
|
+
if (raf !== null) {
|
|
1108
|
+
cancelAnimationFrame(raf);
|
|
1109
|
+
}
|
|
1110
|
+
unsubSelection();
|
|
1111
|
+
unsubPlayhead();
|
|
1112
|
+
unsubViewport();
|
|
1113
|
+
};
|
|
1114
|
+
}, [
|
|
1115
|
+
overlayCtx,
|
|
1116
|
+
width,
|
|
1117
|
+
height,
|
|
1118
|
+
registry,
|
|
1119
|
+
atoms.selection,
|
|
1120
|
+
atoms.playhead,
|
|
1121
|
+
atoms.viewport,
|
|
1122
|
+
headers,
|
|
1123
|
+
overlayStyle
|
|
1124
|
+
]);
|
|
1125
|
+
const callbacksRef = useRef2({
|
|
1126
|
+
onCellToggle,
|
|
1127
|
+
onSelectionCommit
|
|
1128
|
+
});
|
|
1129
|
+
callbacksRef.current = {
|
|
1130
|
+
onCellToggle,
|
|
1131
|
+
onSelectionCommit
|
|
1132
|
+
};
|
|
1133
|
+
useEffect4(() => {
|
|
1134
|
+
const element = overlayInputRef.current;
|
|
1135
|
+
if (!element) {
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
const detachPointer = attachPointerHandlers(element, {
|
|
1139
|
+
registry,
|
|
1140
|
+
atoms,
|
|
1141
|
+
headers,
|
|
1142
|
+
handlers: {
|
|
1143
|
+
onCellToggle: (coord, mode) => callbacksRef.current.onCellToggle?.(coord, mode),
|
|
1144
|
+
onSelectionCommit: (range) => callbacksRef.current.onSelectionCommit?.(range)
|
|
1145
|
+
}
|
|
1146
|
+
});
|
|
1147
|
+
const detachWheel = attachWheelHandlers(element, {
|
|
1148
|
+
registry,
|
|
1149
|
+
atoms,
|
|
1150
|
+
headers
|
|
1151
|
+
});
|
|
1152
|
+
return () => {
|
|
1153
|
+
detachPointer();
|
|
1154
|
+
detachWheel();
|
|
1155
|
+
};
|
|
1156
|
+
}, [
|
|
1157
|
+
registry,
|
|
1158
|
+
atoms,
|
|
1159
|
+
headers
|
|
1160
|
+
]);
|
|
1161
|
+
return /* @__PURE__ */ React5.createElement("div", {
|
|
1162
|
+
ref: containerRef,
|
|
1163
|
+
className: mx5("relative w-full h-full overflow-hidden bg-baseSurface", classNames)
|
|
1164
|
+
}, /* @__PURE__ */ React5.createElement("canvas", {
|
|
1165
|
+
ref: staticCanvasRef,
|
|
1166
|
+
className: "absolute inset-0 pointer-events-none",
|
|
1167
|
+
style: {
|
|
1168
|
+
top: -1,
|
|
1169
|
+
left: -1
|
|
1170
|
+
}
|
|
1171
|
+
}), /* @__PURE__ */ React5.createElement("canvas", {
|
|
1172
|
+
ref: overlayCanvasRef,
|
|
1173
|
+
className: "absolute inset-0 pointer-events-none",
|
|
1174
|
+
style: {
|
|
1175
|
+
top: -1,
|
|
1176
|
+
left: -1
|
|
1177
|
+
}
|
|
1178
|
+
}), /* @__PURE__ */ React5.createElement("div", {
|
|
1179
|
+
ref: overlayInputRef,
|
|
1180
|
+
className: "absolute inset-0 touch-none",
|
|
1181
|
+
style: {
|
|
1182
|
+
paddingLeft: headers.left,
|
|
1183
|
+
paddingTop: headers.top
|
|
1184
|
+
}
|
|
1185
|
+
}), headers.top > 0 && /* @__PURE__ */ React5.createElement(Ruler, {
|
|
1186
|
+
viewport: viewportState,
|
|
1187
|
+
headers,
|
|
1188
|
+
width
|
|
1189
|
+
}), headers.left > 0 && /* @__PURE__ */ React5.createElement(TrackHeader, {
|
|
1190
|
+
viewport: viewportState,
|
|
1191
|
+
headers,
|
|
1192
|
+
rows,
|
|
1193
|
+
height
|
|
1194
|
+
}), headers.top > 0 && headers.left > 0 && /* @__PURE__ */ React5.createElement("div", {
|
|
1195
|
+
className: "absolute top-0 left-0 border-b border-r border-neutral-200 dark:border-neutral-700 bg-baseSurface",
|
|
1196
|
+
style: {
|
|
1197
|
+
width: headers.left,
|
|
1198
|
+
height: headers.top
|
|
1199
|
+
}
|
|
1200
|
+
}));
|
|
1201
|
+
};
|
|
1202
|
+
|
|
1203
|
+
// src/components/CellGrid/state/atoms.ts
|
|
1204
|
+
import { Atom } from "@effect-atom/atom-react";
|
|
1205
|
+
var defaultViewport = (options = {}) => ({
|
|
1206
|
+
scrollX: 0,
|
|
1207
|
+
scrollY: 0,
|
|
1208
|
+
baseCellWidth: options.cellWidth ?? 24,
|
|
1209
|
+
cellHeight: options.cellHeight ?? 24,
|
|
1210
|
+
zoomX: 1
|
|
1211
|
+
});
|
|
1212
|
+
var createCellGridAtoms = (options = {}) => ({
|
|
1213
|
+
cells: Atom.keepAlive(Atom.make(/* @__PURE__ */ new Map())),
|
|
1214
|
+
viewport: Atom.keepAlive(Atom.make(defaultViewport(options))),
|
|
1215
|
+
selection: Atom.keepAlive(Atom.make({
|
|
1216
|
+
range: null
|
|
1217
|
+
})),
|
|
1218
|
+
playhead: Atom.keepAlive(Atom.make(null)),
|
|
1219
|
+
tool: Atom.keepAlive(Atom.make("toggle"))
|
|
1220
|
+
});
|
|
1221
|
+
|
|
1222
|
+
// src/components/FPS.tsx
|
|
1223
|
+
import React6, { useEffect as useEffect5, useReducer, useRef as useRef3 } from "react";
|
|
1224
|
+
import { mx as mx6 } from "@dxos/ui-theme";
|
|
484
1225
|
var SEC = 1e3;
|
|
485
1226
|
var FPS = ({ classNames, width = 60, height = 30, bar = "bg-cyan-500" }) => {
|
|
486
1227
|
const [{ fps, max, len }, dispatch] = useReducer((state) => {
|
|
@@ -513,12 +1254,12 @@ var FPS = ({ classNames, width = 60, height = 30, bar = "bg-cyan-500" }) => {
|
|
|
513
1254
|
frames: 0,
|
|
514
1255
|
prevTime: Date.now()
|
|
515
1256
|
});
|
|
516
|
-
const requestRef =
|
|
1257
|
+
const requestRef = useRef3(null);
|
|
517
1258
|
const tick = () => {
|
|
518
1259
|
dispatch();
|
|
519
1260
|
requestRef.current = requestAnimationFrame(tick);
|
|
520
1261
|
};
|
|
521
|
-
|
|
1262
|
+
useEffect5(() => {
|
|
522
1263
|
requestRef.current = requestAnimationFrame(tick);
|
|
523
1264
|
return () => {
|
|
524
1265
|
if (requestRef.current) {
|
|
@@ -526,17 +1267,17 @@ var FPS = ({ classNames, width = 60, height = 30, bar = "bg-cyan-500" }) => {
|
|
|
526
1267
|
}
|
|
527
1268
|
};
|
|
528
1269
|
}, []);
|
|
529
|
-
return /* @__PURE__ */
|
|
1270
|
+
return /* @__PURE__ */ React6.createElement("div", {
|
|
530
1271
|
style: {
|
|
531
1272
|
width: width + 6
|
|
532
1273
|
},
|
|
533
|
-
className:
|
|
534
|
-
}, /* @__PURE__ */
|
|
535
|
-
className: "
|
|
1274
|
+
className: mx6("relative flex flex-col p-0.5", "bg-base-surface text-xs text-subdued font-thin pointer-events-none border border-separator", classNames)
|
|
1275
|
+
}, /* @__PURE__ */ React6.createElement("div", null, fps[len - 1], " FPS"), /* @__PURE__ */ React6.createElement("div", {
|
|
1276
|
+
className: "w-full relative",
|
|
536
1277
|
style: {
|
|
537
1278
|
height
|
|
538
1279
|
}
|
|
539
|
-
}, fps.map((frame, i) => /* @__PURE__ */
|
|
1280
|
+
}, fps.map((frame, i) => /* @__PURE__ */ React6.createElement("div", {
|
|
540
1281
|
key: `fps-${i}`,
|
|
541
1282
|
className: bar,
|
|
542
1283
|
style: {
|
|
@@ -550,9 +1291,9 @@ var FPS = ({ classNames, width = 60, height = 30, bar = "bg-cyan-500" }) => {
|
|
|
550
1291
|
};
|
|
551
1292
|
|
|
552
1293
|
// src/components/Grid/Grid.tsx
|
|
553
|
-
import
|
|
1294
|
+
import React7, { forwardRef as forwardRef2, useId, useMemo as useMemo4 } from "react";
|
|
554
1295
|
import { useForwardedRef } from "@dxos/react-ui";
|
|
555
|
-
import { mx as
|
|
1296
|
+
import { mx as mx7 } from "@dxos/ui-theme";
|
|
556
1297
|
var gridRatios = [
|
|
557
1298
|
1 / 4,
|
|
558
1299
|
1,
|
|
@@ -567,7 +1308,7 @@ var defaultOffset = {
|
|
|
567
1308
|
var createId = (parent, grid) => `dx-canvas-grid-${parent}-${grid}`;
|
|
568
1309
|
var Grid = (props) => {
|
|
569
1310
|
const { scale, offset } = useCanvasContext();
|
|
570
|
-
return /* @__PURE__ */
|
|
1311
|
+
return /* @__PURE__ */ React7.createElement(GridComponent, {
|
|
571
1312
|
...props,
|
|
572
1313
|
scale,
|
|
573
1314
|
offset
|
|
@@ -577,35 +1318,35 @@ var GridComponent = /* @__PURE__ */ forwardRef2(({ size: gridSize = defaultGridS
|
|
|
577
1318
|
const svgRef = useForwardedRef(forwardedRef);
|
|
578
1319
|
const { width = 0, height = 0 } = svgRef.current?.getBoundingClientRect() ?? {};
|
|
579
1320
|
const instanceId = useId();
|
|
580
|
-
const grids =
|
|
1321
|
+
const grids = useMemo4(() => gridRatios.map((ratio) => ({
|
|
581
1322
|
id: ratio,
|
|
582
1323
|
size: ratio * gridSize * scale
|
|
583
1324
|
})).filter(({ size }) => size >= gridSize && size <= 128), [
|
|
584
1325
|
gridSize,
|
|
585
1326
|
scale
|
|
586
1327
|
]);
|
|
587
|
-
return /* @__PURE__ */
|
|
1328
|
+
return /* @__PURE__ */ React7.createElement("svg", {
|
|
588
1329
|
...testId("dx-canvas-grid"),
|
|
589
1330
|
ref: svgRef,
|
|
590
|
-
className:
|
|
591
|
-
}, /* @__PURE__ */
|
|
1331
|
+
className: mx7("dx-fullscreen pointer-events-none touch-none select-none", "stroke-neutral-500", classNames)
|
|
1332
|
+
}, /* @__PURE__ */ React7.createElement("defs", null, grids.map(({ id, size }) => /* @__PURE__ */ React7.createElement(GridPattern, {
|
|
592
1333
|
key: id,
|
|
593
1334
|
id: createId(instanceId, id),
|
|
594
1335
|
offset,
|
|
595
1336
|
size
|
|
596
|
-
}))), showAxes && /* @__PURE__ */
|
|
1337
|
+
}))), showAxes && /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement("line", {
|
|
597
1338
|
x1: 0,
|
|
598
1339
|
y1: offset.y,
|
|
599
1340
|
x2: width,
|
|
600
1341
|
y2: offset.y,
|
|
601
1342
|
className: "stroke-neutral-500 opacity-40"
|
|
602
|
-
}), /* @__PURE__ */
|
|
1343
|
+
}), /* @__PURE__ */ React7.createElement("line", {
|
|
603
1344
|
x1: offset.x,
|
|
604
1345
|
y1: 0,
|
|
605
1346
|
x2: offset.x,
|
|
606
1347
|
y2: height,
|
|
607
1348
|
className: "stroke-neutral-500 opacity-40"
|
|
608
|
-
})), /* @__PURE__ */
|
|
1349
|
+
})), /* @__PURE__ */ React7.createElement("g", null, grids.map(({ id }, i) => /* @__PURE__ */ React7.createElement("rect", {
|
|
609
1350
|
key: id,
|
|
610
1351
|
opacity: 0.1 + i * 0.05,
|
|
611
1352
|
fill: `url(#${createId(instanceId, id)})`,
|
|
@@ -629,6 +1370,7 @@ export {
|
|
|
629
1370
|
Arrow,
|
|
630
1371
|
Canvas,
|
|
631
1372
|
CanvasContext,
|
|
1373
|
+
CellGrid,
|
|
632
1374
|
DATA_TEST_ID,
|
|
633
1375
|
Dimension,
|
|
634
1376
|
FPS,
|
|
@@ -640,15 +1382,31 @@ export {
|
|
|
640
1382
|
Point,
|
|
641
1383
|
ProjectionMapper,
|
|
642
1384
|
Rect,
|
|
1385
|
+
Ruler,
|
|
1386
|
+
TrackHeader,
|
|
1387
|
+
attachPointerHandlers,
|
|
1388
|
+
attachWheelHandlers,
|
|
1389
|
+
cellKey,
|
|
1390
|
+
cellWidth,
|
|
1391
|
+
createCellGridAtoms,
|
|
643
1392
|
createPath,
|
|
644
1393
|
defaultOrigin,
|
|
1394
|
+
defaultViewport,
|
|
1395
|
+
drawCells,
|
|
1396
|
+
drawOverlay,
|
|
645
1397
|
getRelativePoint,
|
|
646
1398
|
getZoomTransform,
|
|
1399
|
+
hitTestCell,
|
|
647
1400
|
inspectElement,
|
|
1401
|
+
screenToWorld,
|
|
648
1402
|
testId,
|
|
1403
|
+
toggleCell,
|
|
649
1404
|
useCanvasContext,
|
|
650
1405
|
useDrag,
|
|
651
1406
|
useWheel,
|
|
1407
|
+
visibleCellRange,
|
|
1408
|
+
visibleCells,
|
|
1409
|
+
worldToScreen,
|
|
652
1410
|
zoomInPlace,
|
|
653
1411
|
zoomTo
|
|
654
1412
|
};
|