@dxos/react-ui-canvas 0.8.4-main.c4373fc → 0.8.4-main.c85a9c8dae

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.
@@ -1,30 +1,29 @@
1
1
  // src/components/Canvas/Canvas.tsx
2
- import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
3
- import React2, { forwardRef, useEffect as useEffect2, useImperativeHandle, useMemo, useState } from "react";
2
+ import React2, { forwardRef, useEffect as useEffect3, useImperativeHandle, useMemo, useState } from "react";
4
3
  import { useResizeDetector } from "react-resize-detector";
5
- import { mx as mx2 } from "@dxos/react-ui-theme";
4
+ import { mx as mx2 } from "@dxos/ui-theme";
6
5
 
7
6
  // src/hooks/projection.tsx
8
7
  import { easeSinOut, interpolate, interpolateObject, transition } from "d3";
9
8
  import { applyToPoints, compose, identity, inverse, scale as scaleMatrix, translate as translateMatrix } from "transformation-matrix";
10
- function _define_property(obj, key, value) {
11
- if (key in obj) {
12
- Object.defineProperty(obj, key, {
13
- value,
14
- enumerable: true,
15
- configurable: true,
16
- writable: true
17
- });
18
- } else {
19
- obj[key] = value;
20
- }
21
- return obj;
22
- }
23
9
  var defaultOrigin = {
24
10
  x: 0,
25
11
  y: 0
26
12
  };
27
13
  var ProjectionMapper = class {
14
+ _bounds = {
15
+ width: 0,
16
+ height: 0
17
+ };
18
+ _scale = 1;
19
+ _offset = defaultOrigin;
20
+ _toScreen = identity();
21
+ _toModel = identity();
22
+ constructor(bounds, scale, offset) {
23
+ if (bounds && scale && offset) {
24
+ this.update(bounds, scale, offset);
25
+ }
26
+ }
28
27
  update(bounds, scale, offset) {
29
28
  this._bounds = bounds;
30
29
  this._scale = scale;
@@ -52,19 +51,6 @@ var ProjectionMapper = class {
52
51
  toModel(points) {
53
52
  return applyToPoints(this._toModel, points);
54
53
  }
55
- constructor(bounds, scale, offset) {
56
- _define_property(this, "_bounds", {
57
- width: 0,
58
- height: 0
59
- });
60
- _define_property(this, "_scale", 1);
61
- _define_property(this, "_offset", defaultOrigin);
62
- _define_property(this, "_toScreen", identity());
63
- _define_property(this, "_toModel", identity());
64
- if (bounds && scale && offset) {
65
- this.update(bounds, scale, offset);
66
- }
67
- }
68
54
  };
69
55
  var getZoomTransform = ({ scale, offset, pos, newScale }) => {
70
56
  return {
@@ -117,14 +103,81 @@ var useCanvasContext = () => {
117
103
  return useContext(CanvasContext) ?? raise(new Error("Missing CanvasContext"));
118
104
  };
119
105
 
106
+ // src/hooks/useDrag.tsx
107
+ import { bind } from "bind-event-listener";
108
+ import { useEffect, useRef } from "react";
109
+ var useDrag = (_options = {}) => {
110
+ const { root, setProjection } = useCanvasContext();
111
+ const state = useRef({
112
+ panning: false,
113
+ x: 0,
114
+ y: 0
115
+ });
116
+ useEffect(() => {
117
+ if (!root) {
118
+ return;
119
+ }
120
+ return bind(root, {
121
+ type: "pointerdown",
122
+ listener: (ev) => {
123
+ if (ev.button !== 0) {
124
+ return;
125
+ }
126
+ if (ev.defaultPrevented) {
127
+ return;
128
+ }
129
+ if (ev.target !== root || ev.shiftKey) {
130
+ return;
131
+ }
132
+ ev.preventDefault();
133
+ root.setPointerCapture(ev.pointerId);
134
+ state.current = {
135
+ panning: true,
136
+ x: ev.clientX,
137
+ y: ev.clientY
138
+ };
139
+ const moveUnbind = bind(root, {
140
+ type: "pointermove",
141
+ listener: (ev2) => {
142
+ if (!state.current.panning) {
143
+ return;
144
+ }
145
+ const dx = ev2.clientX - state.current.x;
146
+ const dy = ev2.clientY - state.current.y;
147
+ state.current.x = ev2.clientX;
148
+ state.current.y = ev2.clientY;
149
+ setProjection((prev) => ({
150
+ ...prev,
151
+ offset: {
152
+ x: prev.offset.x + dx,
153
+ y: prev.offset.y + dy
154
+ }
155
+ }));
156
+ }
157
+ });
158
+ const upUnbind = bind(root, {
159
+ type: "pointerup",
160
+ listener: (ev2) => {
161
+ state.current.panning = false;
162
+ root.releasePointerCapture(ev2.pointerId);
163
+ moveUnbind();
164
+ upUnbind();
165
+ }
166
+ });
167
+ }
168
+ });
169
+ }, [
170
+ root
171
+ ]);
172
+ };
173
+
120
174
  // src/hooks/useWheel.tsx
121
175
  import { bindAll } from "bind-event-listener";
122
- import { useEffect } from "react";
176
+ import { useEffect as useEffect2 } from "react";
123
177
 
124
178
  // src/util/svg.tsx
125
- import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
126
179
  import React from "react";
127
- import { mx } from "@dxos/react-ui-theme";
180
+ import { mx } from "@dxos/ui-theme";
128
181
  var createPath = (points, join = false) => {
129
182
  return [
130
183
  "M",
@@ -133,144 +186,118 @@ var createPath = (points, join = false) => {
133
186
  ].join(" ");
134
187
  };
135
188
  var Markers = ({ id = "dx-marker", classNames }) => {
136
- var _effect = _useSignals();
137
- try {
138
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Arrow, {
139
- id: `${id}-arrow-start`,
140
- dir: "start",
141
- classNames
142
- }), /* @__PURE__ */ React.createElement(Arrow, {
143
- id: `${id}-arrow-end`,
144
- dir: "end",
145
- classNames
146
- }), /* @__PURE__ */ React.createElement(Arrow, {
147
- id: `${id}-triangle-start`,
148
- dir: "start",
149
- closed: true,
150
- classNames
151
- }), /* @__PURE__ */ React.createElement(Arrow, {
152
- id: `${id}-triangle-end`,
153
- dir: "end",
154
- closed: true,
155
- classNames
156
- }), /* @__PURE__ */ React.createElement(Marker, {
157
- id: `${id}-circle`,
158
- pos: {
159
- x: 8,
160
- y: 8
161
- },
162
- size: {
163
- width: 16,
164
- height: 16
165
- }
166
- }, /* @__PURE__ */ React.createElement("circle", {
167
- cx: 8,
168
- cy: 8,
169
- r: 5,
170
- stroke: "context-stroke",
171
- className: mx(classNames)
172
- })));
173
- } finally {
174
- _effect.f();
175
- }
176
- };
177
- var Marker = ({ id, className, children, pos: { x: refX, y: refY }, size: { width: markerWidth, height: markerHeight }, fill, ...rest }) => {
178
- var _effect = _useSignals();
179
- try {
180
- return /* @__PURE__ */ React.createElement("marker", {
181
- id,
182
- className,
183
- refX,
184
- refY,
185
- markerWidth,
186
- markerHeight,
187
- markerUnits: "strokeWidth",
188
- orient: "auto",
189
- ...rest
190
- }, children);
191
- } finally {
192
- _effect.f();
193
- }
194
- };
195
- var Arrow = ({ classNames, id, size = 16, dir = "end", closed = false }) => {
196
- var _effect = _useSignals();
197
- try {
198
- return /* @__PURE__ */ React.createElement(Marker, {
199
- id,
200
- size: {
201
- width: size,
202
- height: size
203
- },
204
- pos: dir === "end" ? {
205
- x: size,
206
- y: size / 2
207
- } : {
208
- x: 0,
209
- y: size / 2
210
- }
211
- }, /* @__PURE__ */ React.createElement("path", {
212
- fill: closed ? void 0 : "none",
213
- stroke: "context-stroke",
214
- className: mx(classNames),
215
- d: createPath(dir === "end" ? [
216
- {
217
- x: 1,
218
- y: 1
219
- },
220
- {
221
- x: size,
222
- y: size / 2
223
- },
224
- {
225
- x: 1,
226
- y: size - 1
227
- }
228
- ] : [
229
- {
230
- x: size - 1,
231
- y: 1
232
- },
233
- {
234
- x: 0,
235
- y: size / 2
236
- },
237
- {
238
- x: size - 1,
239
- y: size - 1
240
- }
241
- ], closed)
242
- }));
243
- } finally {
244
- _effect.f();
245
- }
189
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Arrow, {
190
+ id: `${id}-arrow-start`,
191
+ dir: "start",
192
+ classNames
193
+ }), /* @__PURE__ */ React.createElement(Arrow, {
194
+ id: `${id}-arrow-end`,
195
+ dir: "end",
196
+ classNames
197
+ }), /* @__PURE__ */ React.createElement(Arrow, {
198
+ id: `${id}-triangle-start`,
199
+ dir: "start",
200
+ closed: true,
201
+ classNames
202
+ }), /* @__PURE__ */ React.createElement(Arrow, {
203
+ id: `${id}-triangle-end`,
204
+ dir: "end",
205
+ closed: true,
206
+ classNames
207
+ }), /* @__PURE__ */ React.createElement(Marker, {
208
+ id: `${id}-circle`,
209
+ pos: {
210
+ x: 8,
211
+ y: 8
212
+ },
213
+ size: {
214
+ width: 16,
215
+ height: 16
216
+ }
217
+ }, /* @__PURE__ */ React.createElement("circle", {
218
+ cx: 8,
219
+ cy: 8,
220
+ r: 5,
221
+ stroke: "context-stroke",
222
+ className: mx(classNames)
223
+ })));
246
224
  };
247
- var GridPattern = ({ classNames, id, size, offset }) => {
248
- var _effect = _useSignals();
249
- try {
250
- return /* @__PURE__ */ React.createElement("pattern", {
251
- id,
252
- x: (size / 2 + offset.x) % size,
253
- y: (size / 2 + offset.y) % size,
254
- width: size,
255
- height: size,
256
- patternUnits: "userSpaceOnUse"
257
- }, /* @__PURE__ */ React.createElement("g", {
258
- className: mx(classNames)
259
- }, /* @__PURE__ */ React.createElement("line", {
260
- x1: 0,
261
- y1: size / 2,
262
- x2: size,
263
- y2: size / 2
264
- }), /* @__PURE__ */ React.createElement("line", {
265
- x1: size / 2,
266
- y1: 0,
267
- x2: size / 2,
268
- y2: size
269
- })));
270
- } finally {
271
- _effect.f();
225
+ var Marker = ({ id, className, children, pos: { x: refX, y: refY }, size: { width: markerWidth, height: markerHeight }, fill, ...rest }) => /* @__PURE__ */ React.createElement("marker", {
226
+ id,
227
+ className,
228
+ refX,
229
+ refY,
230
+ markerWidth,
231
+ markerHeight,
232
+ markerUnits: "strokeWidth",
233
+ orient: "auto",
234
+ ...rest
235
+ }, children);
236
+ var Arrow = ({ classNames, id, size = 16, dir = "end", closed = false }) => /* @__PURE__ */ React.createElement(Marker, {
237
+ id,
238
+ size: {
239
+ width: size,
240
+ height: size
241
+ },
242
+ pos: dir === "end" ? {
243
+ x: size,
244
+ y: size / 2
245
+ } : {
246
+ x: 0,
247
+ y: size / 2
272
248
  }
273
- };
249
+ }, /* @__PURE__ */ React.createElement("path", {
250
+ fill: closed ? void 0 : "none",
251
+ stroke: "context-stroke",
252
+ className: mx(classNames),
253
+ d: createPath(dir === "end" ? [
254
+ {
255
+ x: 1,
256
+ y: 1
257
+ },
258
+ {
259
+ x: size,
260
+ y: size / 2
261
+ },
262
+ {
263
+ x: 1,
264
+ y: size - 1
265
+ }
266
+ ] : [
267
+ {
268
+ x: size - 1,
269
+ y: 1
270
+ },
271
+ {
272
+ x: 0,
273
+ y: size / 2
274
+ },
275
+ {
276
+ x: size - 1,
277
+ y: size - 1
278
+ }
279
+ ], closed)
280
+ }));
281
+ var GridPattern = ({ classNames, id, size, offset }) => /* @__PURE__ */ React.createElement("pattern", {
282
+ id,
283
+ x: (size / 2 + offset.x) % size,
284
+ y: (size / 2 + offset.y) % size,
285
+ width: size,
286
+ height: size,
287
+ patternUnits: "userSpaceOnUse"
288
+ }, /* @__PURE__ */ React.createElement("g", {
289
+ className: mx(classNames)
290
+ }, /* @__PURE__ */ React.createElement("line", {
291
+ x1: 0,
292
+ y1: size / 2,
293
+ x2: size,
294
+ y2: size / 2
295
+ }), /* @__PURE__ */ React.createElement("line", {
296
+ x1: size / 2,
297
+ y1: 0,
298
+ x2: size / 2,
299
+ y2: size
300
+ })));
274
301
 
275
302
  // src/util/util.ts
276
303
  var logged = false;
@@ -313,7 +340,7 @@ var defaultOptions = {
313
340
  };
314
341
  var useWheel = (options = defaultOptions) => {
315
342
  const { root, setProjection } = useCanvasContext();
316
- useEffect(() => {
343
+ useEffect2(() => {
317
344
  if (!root) {
318
345
  return;
319
346
  }
@@ -326,9 +353,6 @@ var useWheel = (options = defaultOptions) => {
326
353
  },
327
354
  listener: (ev) => {
328
355
  const zooming = isWheelZooming(ev);
329
- if (!hasFocus(root) && !zooming) {
330
- return;
331
- }
332
356
  ev.preventDefault();
333
357
  if (zooming && !options.zoom) {
334
358
  return;
@@ -372,191 +396,161 @@ var isWheelZooming = (ev) => {
372
396
  }
373
397
  return false;
374
398
  };
375
- var hasFocus = (element) => {
376
- const activeElement = document.activeElement;
377
- if (!activeElement) {
378
- return false;
379
- }
380
- let shadowActive = activeElement;
381
- while (shadowActive?.shadowRoot?.activeElement) {
382
- shadowActive = shadowActive.shadowRoot.activeElement;
383
- }
384
- let current = element;
385
- while (current) {
386
- if (current === activeElement || current === shadowActive) {
387
- return true;
388
- }
389
- current = current.parentElement;
390
- }
391
- return false;
392
- };
393
399
 
394
400
  // src/components/Canvas/Canvas.tsx
395
- var Canvas = /* @__PURE__ */ forwardRef(({ children, classNames, scale: _scale = 1, offset: _offset = defaultOrigin, ...props }, forwardedRef) => {
396
- var _effect = _useSignals2();
397
- try {
398
- const { ref, width = 0, height = 0 } = useResizeDetector();
399
- const [ready, setReady] = useState(false);
400
- const [{ scale, offset }, setProjection] = useState({
401
- scale: _scale,
402
- offset: _offset
403
- });
404
- useEffect2(() => {
405
- if (width && height && offset === defaultOrigin) {
406
- setProjection({
407
- scale,
408
- offset: {
409
- x: width / 2,
410
- y: height / 2
411
- }
412
- });
401
+ var Canvas = /* @__PURE__ */ forwardRef(({ children, classNames, scale: scaleProp = 1, offset: offsetProp = defaultOrigin, ...props }, forwardedRef) => {
402
+ const { ref, width = 0, height = 0 } = useResizeDetector();
403
+ const [ready, setReady] = useState(false);
404
+ const [{ scale, offset }, setProjection] = useState({
405
+ scale: scaleProp,
406
+ offset: offsetProp
407
+ });
408
+ useEffect3(() => {
409
+ if (width && height && offset === defaultOrigin) {
410
+ setProjection({
411
+ scale,
412
+ offset: {
413
+ x: width / 2,
414
+ y: height / 2
415
+ }
416
+ });
417
+ }
418
+ }, [
419
+ width,
420
+ height,
421
+ scale,
422
+ offset
423
+ ]);
424
+ const projection = useMemo(() => new ProjectionMapper(), []);
425
+ useEffect3(() => {
426
+ projection.update({
427
+ width,
428
+ height
429
+ }, scale, offset);
430
+ if (offset !== defaultOrigin) {
431
+ setReady(true);
432
+ }
433
+ }, [
434
+ projection,
435
+ scale,
436
+ offset,
437
+ width,
438
+ height
439
+ ]);
440
+ const styles = useMemo(() => {
441
+ return {
442
+ // NOTE: Order is important.
443
+ transform: `translate(${offset.x}px, ${offset.y}px) scale(${scale})`,
444
+ visibility: width && height ? "visible" : "hidden"
445
+ };
446
+ }, [
447
+ scale,
448
+ offset
449
+ ]);
450
+ useImperativeHandle(forwardedRef, () => {
451
+ return {
452
+ setProjection: async (projection2) => {
453
+ setProjection(projection2);
413
454
  }
414
- }, [
455
+ };
456
+ }, [
457
+ ref
458
+ ]);
459
+ return /* @__PURE__ */ React2.createElement(CanvasContext.Provider, {
460
+ value: {
461
+ root: ref.current,
462
+ ready,
415
463
  width,
416
464
  height,
417
465
  scale,
418
- offset
419
- ]);
420
- const projection = useMemo(() => new ProjectionMapper(), []);
421
- useEffect2(() => {
422
- projection.update({
423
- width,
424
- height
425
- }, scale, offset);
426
- if (offset !== defaultOrigin) {
427
- setReady(true);
428
- }
429
- }, [
430
- projection,
431
- scale,
432
466
  offset,
433
- width,
434
- height
435
- ]);
436
- const styles = useMemo(() => {
437
- return {
438
- // NOTE: Order is important.
439
- transform: `translate(${offset.x}px, ${offset.y}px) scale(${scale})`,
440
- visibility: width && height ? "visible" : "hidden"
441
- };
442
- }, [
443
- scale,
444
- offset
445
- ]);
446
- useImperativeHandle(forwardedRef, () => {
447
- return {
448
- setProjection: async (projection2) => {
449
- setProjection(projection2);
450
- }
451
- };
452
- }, [
453
- ref
454
- ]);
455
- return /* @__PURE__ */ React2.createElement(CanvasContext.Provider, {
456
- value: {
457
- root: ref.current,
458
- ready,
459
- width,
460
- height,
461
- scale,
462
- offset,
463
- styles,
464
- projection,
465
- setProjection
466
- }
467
- }, /* @__PURE__ */ React2.createElement("div", {
468
- role: "none",
469
- ...props,
470
- className: mx2("absolute inset-0 overflow-hidden", classNames),
471
- ref
472
- }, ready ? children : null));
473
- } finally {
474
- _effect.f();
475
- }
467
+ styles,
468
+ projection,
469
+ setProjection
470
+ }
471
+ }, /* @__PURE__ */ React2.createElement("div", {
472
+ role: "none",
473
+ ...props,
474
+ className: mx2("absolute inset-0 overflow-hidden", classNames),
475
+ ref
476
+ }, ready ? children : null));
476
477
  });
477
478
 
478
479
  // src/components/FPS.tsx
479
- import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
480
- import React3, { useEffect as useEffect3, useReducer, useRef } from "react";
481
- import { mx as mx3 } from "@dxos/react-ui-theme";
480
+ import React3, { useEffect as useEffect4, useReducer, useRef as useRef2 } from "react";
481
+ import { mx as mx3 } from "@dxos/ui-theme";
482
482
  var SEC = 1e3;
483
483
  var FPS = ({ classNames, width = 60, height = 30, bar = "bg-cyan-500" }) => {
484
- var _effect = _useSignals3();
485
- try {
486
- const [{ fps, max, len }, dispatch] = useReducer((state) => {
487
- const currentTime = Date.now();
488
- if (currentTime > state.prevTime + SEC) {
489
- const nextFPS = [
490
- ...new Array(Math.floor((currentTime - state.prevTime - SEC) / SEC)).fill(0),
491
- Math.max(1, Math.round(state.frames * SEC / (currentTime - state.prevTime)))
492
- ];
493
- return {
494
- max: Math.max(state.max, ...nextFPS),
495
- len: Math.min(state.len + nextFPS.length, width),
496
- fps: [
497
- ...state.fps,
498
- ...nextFPS
499
- ].slice(-width),
500
- frames: 1,
501
- prevTime: currentTime
502
- };
503
- } else {
504
- return {
505
- ...state,
506
- frames: state.frames + 1
507
- };
508
- }
509
- }, {
510
- max: 0,
511
- len: 0,
512
- fps: [],
513
- frames: 0,
514
- prevTime: Date.now()
515
- });
516
- const requestRef = useRef(null);
517
- const tick = () => {
518
- dispatch();
519
- requestRef.current = requestAnimationFrame(tick);
520
- };
521
- useEffect3(() => {
522
- requestRef.current = requestAnimationFrame(tick);
523
- return () => {
524
- if (requestRef.current) {
525
- cancelAnimationFrame(requestRef.current);
526
- }
484
+ const [{ fps, max, len }, dispatch] = useReducer((state) => {
485
+ const currentTime = Date.now();
486
+ if (currentTime > state.prevTime + SEC) {
487
+ const nextFPS = [
488
+ ...new Array(Math.floor((currentTime - state.prevTime - SEC) / SEC)).fill(0),
489
+ Math.max(1, Math.round(state.frames * SEC / (currentTime - state.prevTime)))
490
+ ];
491
+ return {
492
+ max: Math.max(state.max, ...nextFPS),
493
+ len: Math.min(state.len + nextFPS.length, width),
494
+ fps: [
495
+ ...state.fps,
496
+ ...nextFPS
497
+ ].slice(-width),
498
+ frames: 1,
499
+ prevTime: currentTime
527
500
  };
528
- }, []);
529
- return /* @__PURE__ */ React3.createElement("div", {
530
- style: {
531
- width: width + 6
532
- },
533
- className: mx3("relative flex flex-col p-0.5", "bg-baseSurface text-xs text-subdued font-thin pointer-events-none border border-separator", classNames)
534
- }, /* @__PURE__ */ React3.createElement("div", null, fps[len - 1], " FPS"), /* @__PURE__ */ React3.createElement("div", {
535
- className: "w-full relative",
536
- style: {
537
- height
538
- }
539
- }, fps.map((frame, i) => /* @__PURE__ */ React3.createElement("div", {
540
- key: `fps-${i}`,
541
- className: bar,
542
- style: {
543
- position: "absolute",
544
- bottom: 0,
545
- right: `${len - 1 - i}px`,
546
- height: `${height * frame / max}px`,
547
- width: 1
501
+ } else {
502
+ return {
503
+ ...state,
504
+ frames: state.frames + 1
505
+ };
506
+ }
507
+ }, {
508
+ max: 0,
509
+ len: 0,
510
+ fps: [],
511
+ frames: 0,
512
+ prevTime: Date.now()
513
+ });
514
+ const requestRef = useRef2(null);
515
+ const tick = () => {
516
+ dispatch();
517
+ requestRef.current = requestAnimationFrame(tick);
518
+ };
519
+ useEffect4(() => {
520
+ requestRef.current = requestAnimationFrame(tick);
521
+ return () => {
522
+ if (requestRef.current) {
523
+ cancelAnimationFrame(requestRef.current);
548
524
  }
549
- }))));
550
- } finally {
551
- _effect.f();
552
- }
525
+ };
526
+ }, []);
527
+ return /* @__PURE__ */ React3.createElement("div", {
528
+ style: {
529
+ width: width + 6
530
+ },
531
+ className: mx3("relative flex flex-col p-0.5", "bg-base-surface text-xs text-subdued font-thin pointer-events-none border border-separator", classNames)
532
+ }, /* @__PURE__ */ React3.createElement("div", null, fps[len - 1], " FPS"), /* @__PURE__ */ React3.createElement("div", {
533
+ className: "w-full relative",
534
+ style: {
535
+ height
536
+ }
537
+ }, fps.map((frame, i) => /* @__PURE__ */ React3.createElement("div", {
538
+ key: `fps-${i}`,
539
+ className: bar,
540
+ style: {
541
+ position: "absolute",
542
+ bottom: 0,
543
+ right: `${len - 1 - i}px`,
544
+ height: `${height * frame / max}px`,
545
+ width: 1
546
+ }
547
+ }))));
553
548
  };
554
549
 
555
550
  // src/components/Grid/Grid.tsx
556
- import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
557
551
  import React4, { forwardRef as forwardRef2, useId, useMemo as useMemo2 } from "react";
558
552
  import { useForwardedRef } from "@dxos/react-ui";
559
- import { mx as mx4 } from "@dxos/react-ui-theme";
553
+ import { mx as mx4 } from "@dxos/ui-theme";
560
554
  var gridRatios = [
561
555
  1 / 4,
562
556
  1,
@@ -569,64 +563,54 @@ var defaultOffset = {
569
563
  y: 0
570
564
  };
571
565
  var createId = (parent, grid) => `dx-canvas-grid-${parent}-${grid}`;
572
- var GridComponent = /* @__PURE__ */ forwardRef2(({ size: gridSize = defaultGridSize, scale = 1, offset = defaultOffset, showAxes = true, classNames }, forwardedRef) => {
573
- var _effect = _useSignals4();
574
- try {
575
- const svgRef = useForwardedRef(forwardedRef);
576
- const instanceId = useId();
577
- const grids = useMemo2(() => gridRatios.map((ratio) => ({
578
- id: ratio,
579
- size: ratio * gridSize * scale
580
- })).filter(({ size }) => size >= gridSize && size <= 256), [
581
- gridSize,
582
- scale
583
- ]);
584
- const { width = 0, height = 0 } = svgRef.current?.getBoundingClientRect() ?? {};
585
- return /* @__PURE__ */ React4.createElement("svg", {
586
- ...testId("dx-canvas-grid"),
587
- ref: svgRef,
588
- className: mx4("absolute inset-0 w-full h-full pointer-events-none touch-none select-none", "stroke-neutral-500", classNames)
589
- }, /* @__PURE__ */ React4.createElement("defs", null, grids.map(({ id, size }) => /* @__PURE__ */ React4.createElement(GridPattern, {
590
- key: id,
591
- id: createId(instanceId, id),
592
- offset,
593
- size
594
- }))), showAxes && /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement("line", {
595
- x1: 0,
596
- y1: offset.y,
597
- x2: width,
598
- y2: offset.y,
599
- className: "stroke-neutral-500 opacity-40"
600
- }), /* @__PURE__ */ React4.createElement("line", {
601
- x1: offset.x,
602
- y1: 0,
603
- x2: offset.x,
604
- y2: height,
605
- className: "stroke-neutral-500 opacity-40"
606
- })), /* @__PURE__ */ React4.createElement("g", null, grids.map(({ id }, i) => /* @__PURE__ */ React4.createElement("rect", {
607
- key: id,
608
- opacity: 0.1 + i * 0.05,
609
- fill: `url(#${createId(instanceId, id)})`,
610
- width: "100%",
611
- height: "100%"
612
- }))));
613
- } finally {
614
- _effect.f();
615
- }
616
- });
617
566
  var Grid = (props) => {
618
- var _effect = _useSignals4();
619
- try {
620
- const { scale, offset } = useCanvasContext();
621
- return /* @__PURE__ */ React4.createElement(GridComponent, {
622
- ...props,
623
- scale,
624
- offset
625
- });
626
- } finally {
627
- _effect.f();
628
- }
567
+ const { scale, offset } = useCanvasContext();
568
+ return /* @__PURE__ */ React4.createElement(GridComponent, {
569
+ ...props,
570
+ scale,
571
+ offset
572
+ });
629
573
  };
574
+ var GridComponent = /* @__PURE__ */ forwardRef2(({ size: gridSize = defaultGridSize, scale = 1, offset = defaultOffset, showAxes = true, classNames }, forwardedRef) => {
575
+ const svgRef = useForwardedRef(forwardedRef);
576
+ const { width = 0, height = 0 } = svgRef.current?.getBoundingClientRect() ?? {};
577
+ const instanceId = useId();
578
+ const grids = useMemo2(() => gridRatios.map((ratio) => ({
579
+ id: ratio,
580
+ size: ratio * gridSize * scale
581
+ })).filter(({ size }) => size >= gridSize && size <= 128), [
582
+ gridSize,
583
+ scale
584
+ ]);
585
+ return /* @__PURE__ */ React4.createElement("svg", {
586
+ ...testId("dx-canvas-grid"),
587
+ ref: svgRef,
588
+ className: mx4("absolute inset-0 w-full h-full pointer-events-none touch-none select-none", "stroke-neutral-500", classNames)
589
+ }, /* @__PURE__ */ React4.createElement("defs", null, grids.map(({ id, size }) => /* @__PURE__ */ React4.createElement(GridPattern, {
590
+ key: id,
591
+ id: createId(instanceId, id),
592
+ offset,
593
+ size
594
+ }))), showAxes && /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement("line", {
595
+ x1: 0,
596
+ y1: offset.y,
597
+ x2: width,
598
+ y2: offset.y,
599
+ className: "stroke-neutral-500 opacity-40"
600
+ }), /* @__PURE__ */ React4.createElement("line", {
601
+ x1: offset.x,
602
+ y1: 0,
603
+ x2: offset.x,
604
+ y2: height,
605
+ className: "stroke-neutral-500 opacity-40"
606
+ })), /* @__PURE__ */ React4.createElement("g", null, grids.map(({ id }, i) => /* @__PURE__ */ React4.createElement("rect", {
607
+ key: id,
608
+ opacity: 0.1 + i * 0.05,
609
+ fill: `url(#${createId(instanceId, id)})`,
610
+ width: "100%",
611
+ height: "100%"
612
+ }))));
613
+ });
630
614
 
631
615
  // src/types.ts
632
616
  import * as Schema from "effect/Schema";
@@ -661,6 +645,7 @@ export {
661
645
  inspectElement,
662
646
  testId,
663
647
  useCanvasContext,
648
+ useDrag,
664
649
  useWheel,
665
650
  zoomInPlace,
666
651
  zoomTo