@dxos/react-ui-canvas 0.8.4-main.a4bbb77 → 0.8.4-main.abd8ff62ef

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