@dxos/react-ui-canvas 0.8.3-staging.0fa589b → 0.8.4-main.03d5cd7b56

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