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