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