@canvas-harness/react 0.0.1 → 0.0.3

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/dist/index.cjs CHANGED
@@ -18,6 +18,54 @@ function useCanvasStore() {
18
18
  }
19
19
  return store;
20
20
  }
21
+ function useInteractionState() {
22
+ const store = useCanvasStore();
23
+ return react.useSyncExternalStore(
24
+ (cb) => store.subscribe("interaction", cb),
25
+ () => store.getInteractionState()
26
+ );
27
+ }
28
+ function useInteractionMode() {
29
+ const store = useCanvasStore();
30
+ return react.useSyncExternalStore(
31
+ (cb) => {
32
+ let lastMode = store.getInteractionState().mode;
33
+ return store.subscribe("interaction", (state) => {
34
+ if (state.mode !== lastMode) {
35
+ lastMode = state.mode;
36
+ cb();
37
+ }
38
+ });
39
+ },
40
+ () => store.getInteractionState().mode
41
+ );
42
+ }
43
+ function useCursor() {
44
+ const store = useCanvasStore();
45
+ return react.useSyncExternalStore(
46
+ (cb) => store.subscribe("interaction", cb),
47
+ () => store.getInteractionState().pointer
48
+ );
49
+ }
50
+ function useIsMoving() {
51
+ const mode = useInteractionMode();
52
+ return mode === "panning" || mode === "zooming" || mode === "dragging" || mode === "resizing" || mode === "rotating";
53
+ }
54
+ var EMPTY_DRAGGED = [];
55
+ function useDraggedIds() {
56
+ const store = useCanvasStore();
57
+ return react.useSyncExternalStore(
58
+ (cb) => store.subscribe("interaction", cb),
59
+ () => {
60
+ const state = store.getInteractionState();
61
+ return state.draggedIds.length === 0 ? EMPTY_DRAGGED : state.draggedIds;
62
+ }
63
+ );
64
+ }
65
+ function useIsPenActive() {
66
+ const cursor = useCursor();
67
+ return cursor?.pointerType === "pen";
68
+ }
21
69
  function EditorMount({
22
70
  store,
23
71
  factory = core.createDefaultTextareaEditor
@@ -713,7 +761,9 @@ var useOverlayHost = () => {
713
761
  }, []);
714
762
  return { mountedIds, setMountedIds };
715
763
  };
716
- var usePanZoom = (ref, store) => {
764
+ var usePanZoom = (ref, store, tool) => {
765
+ const toolRef = react.useRef(tool);
766
+ toolRef.current = tool;
717
767
  react.useEffect(() => {
718
768
  const el = ref.current;
719
769
  if (!el) return;
@@ -851,7 +901,8 @@ var usePanZoom = (ref, store) => {
851
901
  }
852
902
  return;
853
903
  }
854
- if (e.button === 1 || e.button === 0 && panActivatedBySpace) {
904
+ const handToolActive = toolRef.current === "pan";
905
+ if (e.button === 1 || e.button === 0 && (panActivatedBySpace || handToolActive)) {
855
906
  panning = true;
856
907
  lastX = e.clientX;
857
908
  lastY = e.clientY;
@@ -981,6 +1032,7 @@ function CanvasSurface({
981
1032
  onCreateDrag,
982
1033
  arrowDefaults,
983
1034
  background,
1035
+ selectionColor,
984
1036
  renderCustomNodeView,
985
1037
  children
986
1038
  }) {
@@ -993,8 +1045,9 @@ function CanvasSurface({
993
1045
  const toolRef = react.useRef(tool);
994
1046
  toolRef.current = tool;
995
1047
  const { w, h } = useResizeObserver(wrapRef);
996
- usePanZoom(wrapRef, store);
1048
+ usePanZoom(wrapRef, store, tool);
997
1049
  useInteractionGesture(wrapRef, store, tool);
1050
+ const interactionMode = useInteractionMode();
998
1051
  useArrowTool(wrapRef, store, tool === "arrow", arrowDefaults);
999
1052
  const { mountedIds, setMountedIds } = useOverlayHost();
1000
1053
  const [camera, setCamera] = react.useState(() => store.getCamera());
@@ -1013,6 +1066,7 @@ function CanvasSurface({
1013
1066
  width: w,
1014
1067
  height: h,
1015
1068
  background,
1069
+ selectionColor,
1016
1070
  onOverlayChange: (ids) => setMountedIds(ids)
1017
1071
  });
1018
1072
  r.start();
@@ -1026,6 +1080,9 @@ function CanvasSurface({
1026
1080
  react.useEffect(() => {
1027
1081
  rendererRef.current?.setBackground(background);
1028
1082
  }, [background]);
1083
+ react.useEffect(() => {
1084
+ if (selectionColor !== void 0) rendererRef.current?.setSelectionColor(selectionColor);
1085
+ }, [selectionColor]);
1029
1086
  react.useEffect(() => {
1030
1087
  const el = wrapRef.current;
1031
1088
  if (!el) return;
@@ -1063,6 +1120,7 @@ function CanvasSurface({
1063
1120
  el.removeEventListener("dblclick", onDoubleClickHandler);
1064
1121
  };
1065
1122
  }, [store, onClick, onDoubleClick]);
1123
+ const justCommittedRef = react.useRef(false);
1066
1124
  react.useEffect(() => {
1067
1125
  const el = wrapRef.current;
1068
1126
  if (!el || !onCreateDrag) return;
@@ -1070,7 +1128,6 @@ function CanvasSurface({
1070
1128
  let startScreen = null;
1071
1129
  let activePointerId = null;
1072
1130
  let committed = false;
1073
- const justCommittedRef = { current: false };
1074
1131
  const screenFromEvent = (e) => {
1075
1132
  const rect = el.getBoundingClientRect();
1076
1133
  return { x: e.clientX - rect.left, y: e.clientY - rect.top };
@@ -1201,7 +1258,7 @@ function CanvasSurface({
1201
1258
  inset: 0,
1202
1259
  background: "#f8fafc",
1203
1260
  overflow: "hidden",
1204
- cursor: tool === "select" ? "default" : "crosshair",
1261
+ cursor: tool === "pan" ? interactionMode === "panning" ? "grabbing" : "grab" : tool === "select" ? "default" : "crosshair",
1205
1262
  touchAction: "none"
1206
1263
  },
1207
1264
  children: [
@@ -1551,54 +1608,6 @@ function useCamera() {
1551
1608
  () => store.getCamera()
1552
1609
  );
1553
1610
  }
1554
- function useInteractionState() {
1555
- const store = useCanvasStore();
1556
- return react.useSyncExternalStore(
1557
- (cb) => store.subscribe("interaction", cb),
1558
- () => store.getInteractionState()
1559
- );
1560
- }
1561
- function useInteractionMode() {
1562
- const store = useCanvasStore();
1563
- return react.useSyncExternalStore(
1564
- (cb) => {
1565
- let lastMode = store.getInteractionState().mode;
1566
- return store.subscribe("interaction", (state) => {
1567
- if (state.mode !== lastMode) {
1568
- lastMode = state.mode;
1569
- cb();
1570
- }
1571
- });
1572
- },
1573
- () => store.getInteractionState().mode
1574
- );
1575
- }
1576
- function useCursor() {
1577
- const store = useCanvasStore();
1578
- return react.useSyncExternalStore(
1579
- (cb) => store.subscribe("interaction", cb),
1580
- () => store.getInteractionState().pointer
1581
- );
1582
- }
1583
- function useIsMoving() {
1584
- const mode = useInteractionMode();
1585
- return mode === "panning" || mode === "zooming" || mode === "dragging" || mode === "resizing" || mode === "rotating";
1586
- }
1587
- var EMPTY_DRAGGED = [];
1588
- function useDraggedIds() {
1589
- const store = useCanvasStore();
1590
- return react.useSyncExternalStore(
1591
- (cb) => store.subscribe("interaction", cb),
1592
- () => {
1593
- const state = store.getInteractionState();
1594
- return state.draggedIds.length === 0 ? EMPTY_DRAGGED : state.draggedIds;
1595
- }
1596
- );
1597
- }
1598
- function useIsPenActive() {
1599
- const cursor = useCursor();
1600
- return cursor?.pointerType === "pen";
1601
- }
1602
1611
  function useLocalPresence() {
1603
1612
  const store = useCanvasStore();
1604
1613
  return react.useSyncExternalStore(