@dxos/react-ui-canvas 0.7.5-main.ff8607b → 0.7.5-staging.b81e783

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 (44) hide show
  1. package/README.md +1 -3
  2. package/dist/lib/browser/index.mjs +113 -33
  3. package/dist/lib/browser/index.mjs.map +4 -4
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/node/index.cjs +114 -32
  6. package/dist/lib/node/index.cjs.map +4 -4
  7. package/dist/lib/node/meta.json +1 -1
  8. package/dist/lib/node-esm/index.mjs +113 -33
  9. package/dist/lib/node-esm/index.mjs.map +4 -4
  10. package/dist/lib/node-esm/meta.json +1 -1
  11. package/dist/types/src/components/Canvas/Canvas.d.ts +1 -1
  12. package/dist/types/src/components/Canvas/Canvas.d.ts.map +1 -1
  13. package/dist/types/src/components/Canvas/Canvas.stories.d.ts +1 -0
  14. package/dist/types/src/components/Canvas/Canvas.stories.d.ts.map +1 -1
  15. package/dist/types/src/components/FPS.d.ts +1 -2
  16. package/dist/types/src/components/FPS.d.ts.map +1 -1
  17. package/dist/types/src/components/Grid/Grid.d.ts +6 -5
  18. package/dist/types/src/components/Grid/Grid.d.ts.map +1 -1
  19. package/dist/types/src/components/Grid/Grid.stories.d.ts.map +1 -1
  20. package/dist/types/src/hooks/index.d.ts +1 -1
  21. package/dist/types/src/hooks/index.d.ts.map +1 -1
  22. package/dist/types/src/hooks/projection.d.ts +2 -2
  23. package/dist/types/src/hooks/projection.d.ts.map +1 -1
  24. package/dist/types/src/hooks/{useProjection.d.ts → useCanvasContext.d.ts} +3 -2
  25. package/dist/types/src/hooks/useCanvasContext.d.ts.map +1 -0
  26. package/dist/types/src/hooks/useWheel.d.ts +4 -3
  27. package/dist/types/src/hooks/useWheel.d.ts.map +1 -1
  28. package/dist/types/src/util/svg.d.ts +5 -5
  29. package/dist/types/src/util/svg.d.ts.map +1 -1
  30. package/dist/types/src/util/util.d.ts +1 -0
  31. package/dist/types/src/util/util.d.ts.map +1 -1
  32. package/package.json +14 -13
  33. package/src/components/Canvas/Canvas.stories.tsx +51 -24
  34. package/src/components/Canvas/Canvas.tsx +12 -6
  35. package/src/components/Grid/Grid.stories.tsx +4 -6
  36. package/src/components/Grid/Grid.tsx +34 -8
  37. package/src/hooks/index.ts +1 -1
  38. package/src/hooks/projection.tsx +16 -9
  39. package/src/hooks/{useProjection.tsx → useCanvasContext.tsx} +2 -1
  40. package/src/hooks/useWheel.tsx +60 -8
  41. package/src/util/svg.stories.tsx +1 -1
  42. package/src/util/svg.tsx +2 -2
  43. package/src/util/util.ts +11 -0
  44. package/dist/types/src/hooks/useProjection.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Grid.d.ts","sourceRoot":"","sources":["../../../../../src/components/Grid/Grid.tsx"],"names":[],"mappings":"AAIA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAEnD,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGtD,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AASzC,MAAM,MAAM,SAAS,GAAG,eAAe,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC;AAEtG,eAAO,MAAM,IAAI;QAF6B,MAAM;UAAQ,MAAM;YAAU,MAAM;aAAW,KAAK;;;uCA0CjG,CAAC"}
1
+ {"version":3,"file":"Grid.d.ts","sourceRoot":"","sources":["../../../../../src/components/Grid/Grid.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAqC,MAAM,OAAO,CAAC;AAE1D,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAIvE,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAUzC,MAAM,MAAM,SAAS,GAAG,eAAe,CAAC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC,CAAC;AAEH,eAAO,MAAM,aAAa;WANjB,MAAM;YACL,MAAM;aACL,KAAK;eACH,OAAO;;;uCAwDnB,CAAC;AAGF,eAAO,MAAM,IAAI,UAAW,SAAS,4CAGpC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Grid.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/Grid/Grid.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAKvD,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC;AAgB9C,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,SAAS,CAKzB,CAAC;AAEF,eAAe,IAAI,CAAC;AAEpB,KAAK,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;AAEjC,eAAO,MAAM,OAAO,EAAE,KAIrB,CAAC"}
1
+ {"version":3,"file":"Grid.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/Grid/Grid.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAKvD,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC;AAcvD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,SAAS,CAKzB,CAAC;AAEF,eAAe,IAAI,CAAC;AAEpB,KAAK,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;AAEjC,eAAO,MAAM,OAAO,EAAE,KAIrB,CAAC"}
@@ -1,4 +1,4 @@
1
1
  export * from './projection';
2
- export * from './useProjection';
2
+ export * from './useCanvasContext';
3
3
  export * from './useWheel';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/hooks/index.ts"],"names":[],"mappings":"AAIA,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/hooks/index.ts"],"names":[],"mappings":"AAIA,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { type Point, type Dimension } from '../types';
2
- export declare const defaultOffset: Point;
2
+ export declare const defaultOrigin: Point;
3
3
  export type ProjectionState = {
4
4
  scale: number;
5
5
  offset: Point;
@@ -54,5 +54,5 @@ export declare const zoomInPlace: (setTransform: (state: ProjectionState) => voi
54
54
  /**
55
55
  * Zoom to new scale and position.
56
56
  */
57
- export declare const zoomTo: (setTransform: (state: ProjectionState) => void, current: ProjectionState, next: ProjectionState, delay?: number) => void;
57
+ export declare const zoomTo: (setTransform: (state: ProjectionState) => void, current: ProjectionState, next: ProjectionState, delay?: number, cb?: () => void) => void;
58
58
  //# sourceMappingURL=projection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"projection.d.ts","sourceRoot":"","sources":["../../../../src/hooks/projection.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAEtD,eAAO,MAAM,aAAa,EAAE,KAAsB,CAAC;AAGnD,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,CAAC;CACf,CAAC;AAKF;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,MAAM,IAAI,SAAS,CAAC;IACxB,IAAI,KAAK,IAAI,MAAM,CAAC;IACpB,IAAI,MAAM,IAAI,KAAK,CAAC;IAEpB;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC;IAEnC;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC;CACnC;AAED,qBAAa,gBAAiB,YAAW,UAAU;IACjD,OAAO,CAAC,OAAO,CAAsC;IACrD,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,QAAQ,CAAsB;gBAE1B,MAAM,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK;IAM9D,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK;IAStD,IAAI,MAAM;;;MAET;IAED,IAAI,KAAK,WAER;IAED,IAAI,MAAM;;;MAET;IAED,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE;IAIlC,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE;CAGlC;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB,sCAK1B,eAAe,GAAG;IAAE,GAAG,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,KAAG,eAQvD,CAAC;AAEF;;GAEG;AAEH,eAAO,MAAM,WAAW,iBACR,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,OACzC,KAAK,UACF,KAAK,WACJ,MAAM,QACT,MAAM,yBAWb,CAAC;AAEF;;GAEG;AAEH,eAAO,MAAM,MAAM,iBACH,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,WACrC,eAAe,QAClB,eAAe,yBAWtB,CAAC"}
1
+ {"version":3,"file":"projection.d.ts","sourceRoot":"","sources":["../../../../src/hooks/projection.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAEtD,eAAO,MAAM,aAAa,EAAE,KAAsB,CAAC;AAGnD,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,CAAC;CACf,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,MAAM,IAAI,SAAS,CAAC;IACxB,IAAI,KAAK,IAAI,MAAM,CAAC;IACpB,IAAI,MAAM,IAAI,KAAK,CAAC;IAEpB;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC;IAEnC;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC;CACnC;AAED,qBAAa,gBAAiB,YAAW,UAAU;IACjD,OAAO,CAAC,OAAO,CAAsC;IACrD,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,QAAQ,CAAsB;gBAE1B,MAAM,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK;IAM9D,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK;IAetD,IAAI,MAAM;;;MAET;IAED,IAAI,KAAK,WAER;IAED,IAAI,MAAM;;;MAET;IAED,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE;IAIlC,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE;CAGlC;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB,sCAK1B,eAAe,GAAG;IAAE,GAAG,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,KAAG,eAQvD,CAAC;AAEF;;GAEG;AAEH,eAAO,MAAM,WAAW,iBACR,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,OACzC,KAAK,UACF,KAAK,WACJ,MAAM,QACT,MAAM,yBAWb,CAAC;AAIF;;GAEG;AAEH,eAAO,MAAM,MAAM,iBACH,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,WACrC,eAAe,QAClB,eAAe,0CAatB,CAAC"}
@@ -2,11 +2,12 @@ import { type CSSProperties, type Dispatch, type SetStateAction } from 'react';
2
2
  import { type Projection, type ProjectionState } from './projection';
3
3
  export type CanvasContext = ProjectionState & {
4
4
  root: HTMLDivElement;
5
+ ready: boolean;
5
6
  width: number;
6
7
  height: number;
7
8
  styles: CSSProperties;
8
9
  projection: Projection;
9
10
  setProjection: Dispatch<SetStateAction<ProjectionState>>;
10
11
  };
11
- export declare const useProjection: () => CanvasContext;
12
- //# sourceMappingURL=useProjection.d.ts.map
12
+ export declare const useCanvasContext: () => CanvasContext;
13
+ //# sourceMappingURL=useCanvasContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCanvasContext.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useCanvasContext.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,QAAQ,EAAE,KAAK,cAAc,EAA6B,MAAM,OAAO,CAAC;AAI1G,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAErE,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG;IAC5C,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;IACvB,aAAa,EAAE,QAAQ,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC,CAAC;CAC1D,CAAC;AAQF,eAAO,MAAM,gBAAgB,QAAO,aAEnC,CAAC"}
@@ -1,7 +1,8 @@
1
- import { type Dispatch, type SetStateAction } from 'react';
2
- import { type ProjectionState } from './projection';
1
+ export type WheelOptions = {
2
+ zoom?: boolean;
3
+ };
3
4
  /**
4
5
  * Handle wheel events to update the transform state (zoom and offset).
5
6
  */
6
- export declare const useWheel: (el: HTMLDivElement | null, setProjection: Dispatch<SetStateAction<ProjectionState>>) => void;
7
+ export declare const useWheel: (options?: WheelOptions) => void;
7
8
  //# sourceMappingURL=useWheel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useWheel.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useWheel.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,cAAc,EAAa,MAAM,OAAO,CAAC;AAEtE,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAGtE;;GAEG;AACH,eAAO,MAAM,QAAQ,OAAQ,cAAc,GAAG,IAAI,iBAAiB,QAAQ,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC,SAyC3G,CAAC"}
1
+ {"version":3,"file":"useWheel.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useWheel.tsx"],"names":[],"mappings":"AAWA,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAMF;;GAEG;AACH,eAAO,MAAM,QAAQ,aAAa,YAAY,SAkD7C,CAAC"}
@@ -1,4 +1,4 @@
1
- import React, { type PropsWithChildren, type SVGProps } from 'react';
1
+ import { type PropsWithChildren, type SVGProps } from 'react';
2
2
  import { type ThemedClassName } from '@dxos/react-ui';
3
3
  import { type Dimension, type Point } from '../types';
4
4
  export declare const createPath: (points: Point[], join?: boolean) => string;
@@ -8,7 +8,7 @@ export declare const createPath: (points: Point[], join?: boolean) => string;
8
8
  */
9
9
  export declare const Markers: ({ id, classNames }: ThemedClassName<{
10
10
  id?: string;
11
- }>) => React.JSX.Element;
11
+ }>) => import("react/jsx-runtime").JSX.Element;
12
12
  export type MarkerProps = SVGProps<SVGMarkerElement> & PropsWithChildren<ThemedClassName<{
13
13
  id: string;
14
14
  pos: Point;
@@ -18,16 +18,16 @@ export type MarkerProps = SVGProps<SVGMarkerElement> & PropsWithChildren<ThemedC
18
18
  /**
19
19
  * https://www.w3.org/TR/SVG2/painting.html#Markers
20
20
  */
21
- export declare const Marker: ({ id, className, children, pos: { x: refX, y: refY }, size: { width: markerWidth, height: markerHeight }, fill, ...rest }: MarkerProps) => React.JSX.Element;
21
+ export declare const Marker: ({ id, className, children, pos: { x: refX, y: refY }, size: { width: markerWidth, height: markerHeight }, fill, ...rest }: MarkerProps) => import("react/jsx-runtime").JSX.Element;
22
22
  export declare const Arrow: ({ classNames, id, size, dir, closed, }: ThemedClassName<{
23
23
  id: string;
24
24
  size?: number;
25
25
  dir?: "start" | "end";
26
26
  closed?: boolean;
27
- }>) => React.JSX.Element;
27
+ }>) => import("react/jsx-runtime").JSX.Element;
28
28
  export declare const GridPattern: ({ classNames, id, size, offset, }: ThemedClassName<{
29
29
  id: string;
30
30
  size: number;
31
31
  offset: Point;
32
- }>) => React.JSX.Element;
32
+ }>) => import("react/jsx-runtime").JSX.Element;
33
33
  //# sourceMappingURL=svg.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"svg.d.ts","sourceRoot":"","sources":["../../../../src/util/svg.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,EAAE,KAAK,iBAAiB,EAAE,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAC;AAErE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGtD,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,KAAK,EAAE,MAAM,UAAU,CAAC;AAMtD,eAAO,MAAM,UAAU,WAAY,KAAK,EAAE,2BAEzC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,OAAO,uBAAsC,eAAe,CAAC;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,sBAYzF,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,gBAAgB,CAAC,GAClD,iBAAiB,CACf,eAAe,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,KAAK,CAAC;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC,CACH,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,MAAM,8HAQhB,WAAW,sBAgBb,CAAC;AAEF,eAAO,MAAM,KAAK,2CAMf,eAAe,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,sBA0BzF,CAAC;AAEF,eAAO,MAAM,WAAW,sCAKrB,eAAe,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,KAAK,CAAA;CAAE,CAAC,sBAe9D,CAAC"}
1
+ {"version":3,"file":"svg.d.ts","sourceRoot":"","sources":["../../../../src/util/svg.tsx"],"names":[],"mappings":"AAIA,OAAc,EAAE,KAAK,iBAAiB,EAAE,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAC;AAErE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGtD,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,KAAK,EAAE,MAAM,UAAU,CAAC;AAMtD,eAAO,MAAM,UAAU,WAAY,KAAK,EAAE,2BAEzC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,OAAO,uBAAsC,eAAe,CAAC;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,4CAYzF,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,gBAAgB,CAAC,GAClD,iBAAiB,CACf,eAAe,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,KAAK,CAAC;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC,CACH,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,MAAM,8HAQhB,WAAW,4CAgBb,CAAC;AAEF,eAAO,MAAM,KAAK,2CAMf,eAAe,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,4CA0BzF,CAAC;AAEF,eAAO,MAAM,WAAW,sCAKrB,eAAe,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,KAAK,CAAA;CAAE,CAAC,4CAe9D,CAAC"}
@@ -12,5 +12,6 @@ export declare const getRelativePoint: (el: HTMLElement, ev: MouseEvent) => {
12
12
  export declare const testId: <ID = string>(id: ID, inspect?: boolean) => {
13
13
  "data-test-id": ID;
14
14
  };
15
+ export declare const inspectElement: (el: Element) => void;
15
16
  export declare const DATA_TEST_ID = "data-test-id";
16
17
  //# sourceMappingURL=util.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../../src/util/util.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,eAAO,MAAM,gBAAgB,OAAQ,WAAW,MAAM,UAAU;;;CAG/D,CAAC;AAEF;;GAEG;AAEH,eAAO,MAAM,MAAM,GAAI,EAAE,eAAe,EAAE;;CAiBzC,CAAC;AAEF,eAAO,MAAM,YAAY,iBAAiB,CAAC"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../../src/util/util.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,eAAO,MAAM,gBAAgB,OAAQ,WAAW,MAAM,UAAU;;;CAG/D,CAAC;AAEF;;GAEG;AAEH,eAAO,MAAM,MAAM,GAAI,EAAE,eAAe,EAAE;;CAiBzC,CAAC;AAEF,eAAO,MAAM,cAAc,OAAQ,OAAO,SASzC,CAAC;AAEF,eAAO,MAAM,YAAY,iBAAiB,CAAC"}
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-canvas",
3
- "version": "0.7.5-main.ff8607b",
3
+ "version": "0.7.5-staging.b81e783",
4
4
  "description": "A canvas component.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
7
7
  "license": "MIT",
8
8
  "author": "DXOS.org",
9
+ "type": "module",
9
10
  "exports": {
10
11
  ".": {
11
12
  "types": "./dist/types/src/index.d.ts",
@@ -26,14 +27,14 @@
26
27
  "@radix-ui/react-context": "1.1.1",
27
28
  "bind-event-listener": "^3.0.0",
28
29
  "d3": "^7.9.0",
29
- "effect": "^3.12.1",
30
+ "effect": "^3.12.3",
30
31
  "react-resize-detector": "^11.0.1",
31
32
  "transformation-matrix": "^2.16.1",
32
- "@dxos/debug": "0.7.5-main.ff8607b",
33
- "@dxos/effect": "0.7.5-main.ff8607b",
34
- "@dxos/invariant": "0.7.5-main.ff8607b",
35
- "@dxos/log": "0.7.5-main.ff8607b",
36
- "@dxos/util": "0.7.5-main.ff8607b"
33
+ "@dxos/invariant": "0.7.5-staging.b81e783",
34
+ "@dxos/debug": "0.7.5-staging.b81e783",
35
+ "@dxos/effect": "0.7.5-staging.b81e783",
36
+ "@dxos/log": "0.7.5-staging.b81e783",
37
+ "@dxos/util": "0.7.5-staging.b81e783"
37
38
  },
38
39
  "devDependencies": {
39
40
  "@effect/schema": "^0.75.5",
@@ -43,17 +44,17 @@
43
44
  "react": "~18.2.0",
44
45
  "react-dom": "~18.2.0",
45
46
  "vite": "5.4.7",
46
- "@dxos/react-ui": "0.7.5-main.ff8607b",
47
- "@dxos/react-ui-theme": "0.7.5-main.ff8607b",
48
- "@dxos/random": "0.7.5-main.ff8607b",
49
- "@dxos/storybook-utils": "0.7.5-main.ff8607b"
47
+ "@dxos/random": "0.7.5-staging.b81e783",
48
+ "@dxos/react-ui": "0.7.5-staging.b81e783",
49
+ "@dxos/react-ui-theme": "0.7.5-staging.b81e783",
50
+ "@dxos/storybook-utils": "0.7.5-staging.b81e783"
50
51
  },
51
52
  "peerDependencies": {
52
53
  "@effect/schema": "^0.75.5",
53
54
  "react": "~18.2.0",
54
55
  "react-dom": "~18.2.0",
55
- "@dxos/react-ui": "0.7.5-main.ff8607b",
56
- "@dxos/react-ui-theme": "0.7.5-main.ff8607b"
56
+ "@dxos/react-ui": "0.7.5-staging.b81e783",
57
+ "@dxos/react-ui-theme": "0.7.5-staging.b81e783"
57
58
  },
58
59
  "publishConfig": {
59
60
  "access": "public"
@@ -10,38 +10,62 @@ import React from 'react';
10
10
  import { withLayout, withTheme } from '@dxos/storybook-utils';
11
11
 
12
12
  import { Canvas } from './Canvas';
13
- import { useProjection, useWheel } from '../../hooks';
13
+ import { useCanvasContext, useWheel } from '../../hooks';
14
14
  import { type Point } from '../../types';
15
15
  import { testId } from '../../util';
16
16
  import { Grid, type GridProps } from '../Grid';
17
17
 
18
+ const size = 128;
19
+
20
+ const points: Point[] = [0, (2 * Math.PI) / 3, (2 * Math.PI * 2) / 3].map((a, i) => ({
21
+ x: Math.round(Math.cos(a - Math.PI / 2) * size * 1.5),
22
+ y: Math.round(Math.sin(a - Math.PI / 2) * size * 1.5),
23
+ }));
24
+
18
25
  const Render = (props: GridProps) => {
19
26
  return (
20
27
  <Canvas>
21
- <Content {...props} />
28
+ <Grid {...props} />
29
+ <Content />
22
30
  </Canvas>
23
31
  );
24
32
  };
25
33
 
26
- const Content = (props: GridProps) => {
27
- const { root, scale, offset, styles, setProjection } = useProjection();
28
- useWheel(root, setProjection);
29
-
34
+ const TwoCanvases = (props: GridProps) => {
30
35
  return (
31
- <>
32
- <Grid scale={scale} offset={offset} {...props} />
33
- <div className='absolute' style={styles}>
34
- <Item x={0} y={-128} />
35
- <Item x={-128} y={128} />
36
- <Item x={128} y={128} />
36
+ <div className='grid grid-cols-2 gap-2 w-full h-full'>
37
+ <div className='h-full relative'>
38
+ <Canvas>
39
+ <Grid {...props} />
40
+ <Content />
41
+ </Canvas>
42
+ </div>
43
+ <div className='h-full relative'>
44
+ <Canvas>
45
+ <Grid {...props} />
46
+ <Content />
47
+ </Canvas>
37
48
  </div>
38
- </>
49
+ </div>
39
50
  );
40
51
  };
41
52
 
42
- const Item = ({ x, y }: Point) => {
43
- const size = 128;
44
- const pos = {
53
+ const Content = () => {
54
+ useWheel();
55
+ return (
56
+ <div>
57
+ {points.map(({ x, y }, i) => (
58
+ <Item key={i} x={x} y={y} />
59
+ ))}
60
+ </div>
61
+ );
62
+ };
63
+
64
+ const Item = (p: Point) => {
65
+ const { projection } = useCanvasContext();
66
+ const r = (projection.scale * size) / 2;
67
+ const [{ x, y }] = projection.toScreen([p]);
68
+ const rect = {
45
69
  left: x - size / 2,
46
70
  top: y - size / 2,
47
71
  width: size,
@@ -50,14 +74,15 @@ const Item = ({ x, y }: Point) => {
50
74
 
51
75
  return (
52
76
  <div {...testId('dx-test', true)}>
53
- <div className='absolute flex border border-red-500 justify-center items-center' style={pos}>
77
+ <div className='absolute flex justify-center items-center' style={rect}>
54
78
  <div className='font-mono'>
55
- ({x},{y})
79
+ ({p.x},{p.y})
56
80
  </div>
57
81
  </div>
82
+
58
83
  {/* NOTE: Width and height are not important since overflow-visible. */}
59
- <svg className='absolute overflow-visible' style={pos}>
60
- <circle cx={64} cy={64} r={64} className='stroke-red-500 storke-width-2 fill-none' />
84
+ <svg className='absolute overflow-visible'>
85
+ <circle cx={x} cy={y} r={r} className='stroke-red-500 storke-width-2 fill-none' />
61
86
  </svg>
62
87
  </div>
63
88
  );
@@ -75,8 +100,10 @@ export default meta;
75
100
  type Story = StoryObj<GridProps>;
76
101
 
77
102
  export const Default: Story = {
78
- args: {
79
- id: 'test',
80
- size: 16,
81
- },
103
+ args: { size: 16 },
104
+ };
105
+
106
+ export const SideBySide: Story = {
107
+ args: { size: 16 },
108
+ render: TwoCanvases,
82
109
  };
@@ -4,20 +4,20 @@
4
4
 
5
5
  import React, {
6
6
  type CSSProperties,
7
+ type HTMLAttributes,
7
8
  type PropsWithChildren,
8
9
  forwardRef,
9
10
  useEffect,
10
11
  useImperativeHandle,
11
12
  useMemo,
12
13
  useState,
13
- type HTMLAttributes,
14
14
  } from 'react';
15
15
  import { useResizeDetector } from 'react-resize-detector';
16
16
 
17
17
  import { type ThemedClassName } from '@dxos/react-ui';
18
18
  import { mx } from '@dxos/react-ui-theme';
19
19
 
20
- import { defaultOffset, CanvasContext, ProjectionMapper, type ProjectionState } from '../../hooks';
20
+ import { defaultOrigin, CanvasContext, ProjectionMapper, type ProjectionState } from '../../hooks';
21
21
 
22
22
  export interface CanvasController {
23
23
  setProjection(projection: ProjectionState): Promise<void>;
@@ -30,14 +30,17 @@ export type CanvasProps = ThemedClassName<PropsWithChildren<Partial<ProjectionSt
30
30
  * Manages CSS projection.
31
31
  */
32
32
  export const Canvas = forwardRef<CanvasController, CanvasProps>(
33
- ({ children, classNames, scale: _scale = 1, offset: _offset = defaultOffset, ...props }, forwardedRef) => {
33
+ ({ children, classNames, scale: _scale = 1, offset: _offset = defaultOrigin, ...props }, forwardedRef) => {
34
34
  // Size.
35
35
  const { ref, width = 0, height = 0 } = useResizeDetector();
36
36
 
37
+ // Ready when initially resized.
38
+ const [ready, setReady] = useState(false);
39
+
37
40
  // Projection.
38
41
  const [{ scale, offset }, setProjection] = useState<ProjectionState>({ scale: _scale, offset: _offset });
39
42
  useEffect(() => {
40
- if (width && height && offset === defaultOffset) {
43
+ if (width && height && offset === defaultOrigin) {
41
44
  setProjection({ scale, offset: { x: width / 2, y: height / 2 } });
42
45
  }
43
46
  }, [width, height, scale, offset]);
@@ -46,6 +49,9 @@ export const Canvas = forwardRef<CanvasController, CanvasProps>(
46
49
  const projection = useMemo(() => new ProjectionMapper(), []);
47
50
  useEffect(() => {
48
51
  projection.update({ width, height }, scale, offset);
52
+ if (offset !== defaultOrigin) {
53
+ setReady(true);
54
+ }
49
55
  }, [projection, scale, offset, width, height]);
50
56
 
51
57
  // CSS transforms.
@@ -72,10 +78,10 @@ export const Canvas = forwardRef<CanvasController, CanvasProps>(
72
78
 
73
79
  return (
74
80
  <CanvasContext.Provider
75
- value={{ root: ref.current, width, height, scale, offset, styles, projection, setProjection }}
81
+ value={{ root: ref.current, ready, width, height, scale, offset, styles, projection, setProjection }}
76
82
  >
77
83
  <div role='none' {...props} className={mx('absolute inset-0 overflow-hidden', classNames)} ref={ref}>
78
- {children}
84
+ {ready ? children : null}
79
85
  </div>
80
86
  </CanvasContext.Provider>
81
87
  );
@@ -9,25 +9,23 @@ import React, { useRef, useState } from 'react';
9
9
 
10
10
  import { withLayout, withTheme } from '@dxos/storybook-utils';
11
11
 
12
- import { Grid, type GridProps } from './Grid';
12
+ import { GridComponent, type GridProps } from './Grid';
13
13
  import { type ProjectionState } from '../../hooks';
14
- import { useWheel } from '../../hooks';
15
14
 
16
15
  const Render = (props: GridProps) => {
17
16
  const ref = useRef<HTMLDivElement>(null);
18
- const [{ scale, offset }, setProjection] = useState<ProjectionState>({ scale: 1, offset: { x: 0, y: 0 } });
19
- useWheel(ref.current, setProjection);
17
+ const [{ scale, offset }] = useState<ProjectionState>({ scale: 1, offset: { x: 0, y: 0 } });
20
18
 
21
19
  return (
22
20
  <div ref={ref} className='grow'>
23
- <Grid scale={scale} offset={offset} {...props} />
21
+ <GridComponent scale={scale} offset={offset} {...props} />
24
22
  </div>
25
23
  );
26
24
  };
27
25
 
28
26
  const meta: Meta<GridProps> = {
29
27
  title: 'ui/react-ui-canvas/Grid',
30
- component: Grid,
28
+ component: GridComponent,
31
29
  render: Render,
32
30
  decorators: [withTheme, withLayout({ fullscreen: true })],
33
31
  };
@@ -2,24 +2,36 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import React, { forwardRef, useMemo } from 'react';
5
+ import React, { forwardRef, useMemo, useId } from 'react';
6
6
 
7
- import { type ThemedClassName } from '@dxos/react-ui';
7
+ import { useForwardedRef, type ThemedClassName } from '@dxos/react-ui';
8
8
  import { mx } from '@dxos/react-ui-theme';
9
9
 
10
+ import { useCanvasContext } from '../../hooks';
10
11
  import { type Point } from '../../types';
11
12
  import { GridPattern, testId } from '../../util';
12
13
 
13
14
  const gridRatios = [1 / 4, 1, 4, 16];
14
15
 
16
+ const defaultGridSize = 16;
15
17
  const defaultOffset: Point = { x: 0, y: 0 };
16
18
 
17
19
  const createId = (parent: string, grid: number) => `dx-canvas-grid-${parent}-${grid}`;
18
20
 
19
- export type GridProps = ThemedClassName<{ id: string; size: number; scale?: number; offset?: Point }>;
21
+ export type GridProps = ThemedClassName<{
22
+ size?: number;
23
+ scale?: number;
24
+ offset?: Point;
25
+ showAxes?: boolean;
26
+ }>;
20
27
 
21
- export const Grid = forwardRef<SVGSVGElement, GridProps>(
22
- ({ id: parentId, size: gridSize, scale = 1, offset = defaultOffset, classNames }, forwardedRef) => {
28
+ export const GridComponent = forwardRef<SVGSVGElement, GridProps>(
29
+ (
30
+ { size: gridSize = defaultGridSize, scale = 1, offset = defaultOffset, showAxes = true, classNames },
31
+ forwardedRef,
32
+ ) => {
33
+ const svgRef = useForwardedRef(forwardedRef);
34
+ const instanceId = useId();
23
35
  const grids = useMemo(
24
36
  () =>
25
37
  gridRatios
@@ -28,10 +40,12 @@ export const Grid = forwardRef<SVGSVGElement, GridProps>(
28
40
  [gridSize, scale],
29
41
  );
30
42
 
43
+ const { width = 0, height = 0 } = svgRef.current?.getBoundingClientRect() ?? {};
44
+
31
45
  return (
32
46
  <svg
33
47
  {...testId('dx-canvas-grid')}
34
- ref={forwardedRef}
48
+ ref={svgRef}
35
49
  className={mx(
36
50
  'absolute inset-0 w-full h-full pointer-events-none touch-none select-none',
37
51
  'stroke-neutral-500',
@@ -41,15 +55,21 @@ export const Grid = forwardRef<SVGSVGElement, GridProps>(
41
55
  {/* NOTE: The pattern is offset so that the middle of the pattern aligns with the grid. */}
42
56
  <defs>
43
57
  {grids.map(({ id, size }) => (
44
- <GridPattern key={id} id={createId(parentId, id)} offset={offset} size={size} />
58
+ <GridPattern key={id} id={createId(instanceId, id)} offset={offset} size={size} />
45
59
  ))}
46
60
  </defs>
61
+ {showAxes && (
62
+ <>
63
+ <line x1={0} y1={offset.y} x2={width} y2={offset.y} className='stroke-neutral-500 opacity-40' />
64
+ <line x1={offset.x} y1={0} x2={offset.x} y2={height} className='stroke-neutral-500 opacity-40' />
65
+ </>
66
+ )}
47
67
  <g>
48
68
  {grids.map(({ id }, i) => (
49
69
  <rect
50
70
  key={id}
51
71
  opacity={0.1 + i * 0.05}
52
- fill={`url(#${createId(parentId, id)})`}
72
+ fill={`url(#${createId(instanceId, id)})`}
53
73
  width='100%'
54
74
  height='100%'
55
75
  />
@@ -59,3 +79,9 @@ export const Grid = forwardRef<SVGSVGElement, GridProps>(
59
79
  );
60
80
  },
61
81
  );
82
+
83
+ // TODO(burdon): Use id of parent canvas.
84
+ export const Grid = (props: GridProps) => {
85
+ const { scale, offset } = useCanvasContext();
86
+ return <GridComponent {...props} scale={scale} offset={offset} />;
87
+ };
@@ -3,5 +3,5 @@
3
3
  //
4
4
 
5
5
  export * from './projection';
6
- export * from './useProjection';
6
+ export * from './useCanvasContext';
7
7
  export * from './useWheel';
@@ -7,15 +7,15 @@ import {
7
7
  type Matrix,
8
8
  applyToPoints,
9
9
  compose,
10
- inverse,
11
- translate as translateMatrix,
12
10
  identity,
11
+ inverse,
13
12
  scale as scaleMatrix,
13
+ translate as translateMatrix,
14
14
  } from 'transformation-matrix';
15
15
 
16
16
  import { type Point, type Dimension } from '../types';
17
17
 
18
- export const defaultOffset: Point = { x: 0, y: 0 };
18
+ export const defaultOrigin: Point = { x: 0, y: 0 };
19
19
 
20
20
  // TODO(burdon): Rotation also?
21
21
  export type ProjectionState = {
@@ -23,9 +23,6 @@ export type ProjectionState = {
23
23
  offset: Point;
24
24
  };
25
25
 
26
- // TODO(burdon): Tradeoff between stable ProjectionMapping object that can be used with live values within a closure,
27
- // vs. a reactive object that can trigger updates?
28
-
29
26
  /**
30
27
  * Maps between screen and model coordinates.
31
28
  */
@@ -48,7 +45,7 @@ export interface Projection {
48
45
  export class ProjectionMapper implements Projection {
49
46
  private _bounds: Dimension = { width: 0, height: 0 };
50
47
  private _scale: number = 1;
51
- private _offset: Point = defaultOffset;
48
+ private _offset: Point = defaultOrigin;
52
49
  private _toScreen: Matrix = identity();
53
50
  private _toModel: Matrix = identity();
54
51
 
@@ -62,7 +59,13 @@ export class ProjectionMapper implements Projection {
62
59
  this._bounds = bounds;
63
60
  this._scale = scale;
64
61
  this._offset = offset;
65
- this._toScreen = compose(translateMatrix(this._offset.x, this._offset.y), scaleMatrix(this._scale));
62
+ this._toScreen = compose(
63
+ // NOTE: Order is important.
64
+ translateMatrix(this._offset.x, this._offset.y),
65
+ scaleMatrix(this._scale),
66
+ // TODO(burdon): Flip.
67
+ // flipX(),
68
+ );
66
69
  this._toModel = inverse(this._toScreen);
67
70
  return this;
68
71
  }
@@ -128,6 +131,8 @@ export const zoomInPlace = (
128
131
  });
129
132
  };
130
133
 
134
+ const noop = () => {};
135
+
131
136
  /**
132
137
  * Zoom to new scale and position.
133
138
  */
@@ -137,6 +142,7 @@ export const zoomTo = (
137
142
  current: ProjectionState,
138
143
  next: ProjectionState,
139
144
  delay = 200,
145
+ cb = noop,
140
146
  ) => {
141
147
  const is = d3.interpolateObject({ scale: current.scale, ...current.offset }, { scale: next.scale, ...next.offset });
142
148
  d3.transition()
@@ -145,5 +151,6 @@ export const zoomTo = (
145
151
  .tween('zoom', () => (t) => {
146
152
  const { scale, x, y } = is(t);
147
153
  setTransform({ scale, offset: { x, y } });
148
- });
154
+ })
155
+ .on('end', cb);
149
156
  };
@@ -10,6 +10,7 @@ import { type Projection, type ProjectionState } from './projection';
10
10
 
11
11
  export type CanvasContext = ProjectionState & {
12
12
  root: HTMLDivElement;
13
+ ready: boolean;
13
14
  width: number;
14
15
  height: number;
15
16
  styles: CSSProperties;
@@ -23,6 +24,6 @@ export type CanvasContext = ProjectionState & {
23
24
  // TODO(burdon): Use radix?
24
25
  export const CanvasContext = createContext<CanvasContext | null>(null);
25
26
 
26
- export const useProjection = (): CanvasContext => {
27
+ export const useCanvasContext = (): CanvasContext => {
27
28
  return useContext(CanvasContext) ?? raise(new Error('Missing CanvasContext'));
28
29
  };