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