@oh-just-another/scene 0.57.0

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 (129) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE +21 -0
  3. package/README.md +72 -0
  4. package/dist/.tsbuildinfo +1 -0
  5. package/dist/a11y.d.ts +23 -0
  6. package/dist/a11y.d.ts.map +1 -0
  7. package/dist/a11y.js +37 -0
  8. package/dist/a11y.js.map +1 -0
  9. package/dist/anchors.d.ts +120 -0
  10. package/dist/anchors.d.ts.map +1 -0
  11. package/dist/anchors.js +322 -0
  12. package/dist/anchors.js.map +1 -0
  13. package/dist/annotation-geometry.d.ts +11 -0
  14. package/dist/annotation-geometry.d.ts.map +1 -0
  15. package/dist/annotation-geometry.js +19 -0
  16. package/dist/annotation-geometry.js.map +1 -0
  17. package/dist/annotation.d.ts +32 -0
  18. package/dist/annotation.d.ts.map +1 -0
  19. package/dist/annotation.js +2 -0
  20. package/dist/annotation.js.map +1 -0
  21. package/dist/constants.d.ts +186 -0
  22. package/dist/constants.d.ts.map +1 -0
  23. package/dist/constants.js +186 -0
  24. package/dist/constants.js.map +1 -0
  25. package/dist/container.d.ts +112 -0
  26. package/dist/container.d.ts.map +1 -0
  27. package/dist/container.js +227 -0
  28. package/dist/container.js.map +1 -0
  29. package/dist/diff.d.ts +22 -0
  30. package/dist/diff.d.ts.map +1 -0
  31. package/dist/diff.js +18 -0
  32. package/dist/diff.js.map +1 -0
  33. package/dist/edge-curve.d.ts +37 -0
  34. package/dist/edge-curve.d.ts.map +1 -0
  35. package/dist/edge-curve.js +72 -0
  36. package/dist/edge-curve.js.map +1 -0
  37. package/dist/edge-geometry.d.ts +96 -0
  38. package/dist/edge-geometry.d.ts.map +1 -0
  39. package/dist/edge-geometry.js +467 -0
  40. package/dist/edge-geometry.js.map +1 -0
  41. package/dist/edge.d.ts +206 -0
  42. package/dist/edge.d.ts.map +1 -0
  43. package/dist/edge.js +2 -0
  44. package/dist/edge.js.map +1 -0
  45. package/dist/elbow-link.d.ts +23 -0
  46. package/dist/elbow-link.d.ts.map +1 -0
  47. package/dist/elbow-link.js +419 -0
  48. package/dist/elbow-link.js.map +1 -0
  49. package/dist/elbow-router.d.ts +20 -0
  50. package/dist/elbow-router.d.ts.map +1 -0
  51. package/dist/elbow-router.js +218 -0
  52. package/dist/elbow-router.js.map +1 -0
  53. package/dist/file.d.ts +41 -0
  54. package/dist/file.d.ts.map +1 -0
  55. package/dist/file.js +13 -0
  56. package/dist/file.js.map +1 -0
  57. package/dist/heading.d.ts +42 -0
  58. package/dist/heading.d.ts.map +1 -0
  59. package/dist/heading.js +77 -0
  60. package/dist/heading.js.map +1 -0
  61. package/dist/index.d.ts +47 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +40 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/layer.d.ts +18 -0
  66. package/dist/layer.d.ts.map +1 -0
  67. package/dist/layer.js +2 -0
  68. package/dist/layer.js.map +1 -0
  69. package/dist/layout-registry.d.ts +35 -0
  70. package/dist/layout-registry.d.ts.map +1 -0
  71. package/dist/layout-registry.js +13 -0
  72. package/dist/layout-registry.js.map +1 -0
  73. package/dist/layout.d.ts +128 -0
  74. package/dist/layout.d.ts.map +1 -0
  75. package/dist/layout.js +453 -0
  76. package/dist/layout.js.map +1 -0
  77. package/dist/operations.d.ts +32 -0
  78. package/dist/operations.d.ts.map +1 -0
  79. package/dist/operations.js +105 -0
  80. package/dist/operations.js.map +1 -0
  81. package/dist/outline.d.ts +36 -0
  82. package/dist/outline.d.ts.map +1 -0
  83. package/dist/outline.js +129 -0
  84. package/dist/outline.js.map +1 -0
  85. package/dist/patch.d.ts +57 -0
  86. package/dist/patch.d.ts.map +1 -0
  87. package/dist/patch.js +47 -0
  88. package/dist/patch.js.map +1 -0
  89. package/dist/queries.d.ts +115 -0
  90. package/dist/queries.d.ts.map +1 -0
  91. package/dist/queries.js +403 -0
  92. package/dist/queries.js.map +1 -0
  93. package/dist/render-bounds.d.ts +36 -0
  94. package/dist/render-bounds.d.ts.map +1 -0
  95. package/dist/render-bounds.js +36 -0
  96. package/dist/render-bounds.js.map +1 -0
  97. package/dist/scene.d.ts +80 -0
  98. package/dist/scene.d.ts.map +1 -0
  99. package/dist/scene.js +129 -0
  100. package/dist/scene.js.map +1 -0
  101. package/dist/shape.d.ts +306 -0
  102. package/dist/shape.d.ts.map +1 -0
  103. package/dist/shape.js +192 -0
  104. package/dist/shape.js.map +1 -0
  105. package/dist/snap.d.ts +88 -0
  106. package/dist/snap.d.ts.map +1 -0
  107. package/dist/snap.js +128 -0
  108. package/dist/snap.js.map +1 -0
  109. package/dist/spatial.d.ts +38 -0
  110. package/dist/spatial.d.ts.map +1 -0
  111. package/dist/spatial.js +95 -0
  112. package/dist/spatial.js.map +1 -0
  113. package/dist/style.d.ts +87 -0
  114. package/dist/style.d.ts.map +1 -0
  115. package/dist/style.js +43 -0
  116. package/dist/style.js.map +1 -0
  117. package/dist/text-measure.d.ts +29 -0
  118. package/dist/text-measure.d.ts.map +1 -0
  119. package/dist/text-measure.js +8 -0
  120. package/dist/text-measure.js.map +1 -0
  121. package/dist/three-way-merge.d.ts +59 -0
  122. package/dist/three-way-merge.d.ts.map +1 -0
  123. package/dist/three-way-merge.js +108 -0
  124. package/dist/three-way-merge.js.map +1 -0
  125. package/dist/viewport.d.ts +78 -0
  126. package/dist/viewport.d.ts.map +1 -0
  127. package/dist/viewport.js +62 -0
  128. package/dist/viewport.js.map +1 -0
  129. package/package.json +54 -0
@@ -0,0 +1,108 @@
1
+ export const mergeScenesThreeWay = (ancestor, source, target, options = {}) => {
2
+ const eq = options.compareElements ?? ((a, b) => a === b);
3
+ const conflicts = [];
4
+ // Start from target — conflicts default to keeping target until
5
+ // the host resolves them.
6
+ const merged = new Map(target.elements);
7
+ const allIds = new Set();
8
+ for (const id of ancestor.elements.keys())
9
+ allIds.add(id);
10
+ for (const id of source.elements.keys())
11
+ allIds.add(id);
12
+ for (const id of target.elements.keys())
13
+ allIds.add(id);
14
+ for (const id of allIds) {
15
+ const a = ancestor.elements.get(id) ?? null;
16
+ const s = source.elements.get(id) ?? null;
17
+ const t = target.elements.get(id) ?? null;
18
+ // Case 1: no change in either branch — keep target's version.
19
+ if (a !== null && s !== null && t !== null && eq(s, a) && eq(t, a))
20
+ continue;
21
+ // Case 2: only source changed (target untouched vs ancestor).
22
+ if (a !== null && t !== null && eq(t, a)) {
23
+ if (s === null)
24
+ merged.delete(id);
25
+ else
26
+ merged.set(id, s);
27
+ continue;
28
+ }
29
+ // Case 2': only target changed (source untouched vs ancestor).
30
+ if (a !== null && s !== null && eq(s, a)) {
31
+ // target already in `merged`; keep as-is.
32
+ continue;
33
+ }
34
+ // Case 3: source removed, target unchanged → take the removal.
35
+ if (a !== null && s === null && t !== null && eq(t, a)) {
36
+ merged.delete(id);
37
+ continue;
38
+ }
39
+ // Case 3': target removed, source unchanged → keep target's
40
+ // removal (deletion already in merged map).
41
+ if (a !== null && t === null && s !== null && eq(s, a)) {
42
+ continue;
43
+ }
44
+ // Case 4: same change in both branches — accept either.
45
+ if (s !== null && t !== null && eq(s, t))
46
+ continue;
47
+ // Case 4': both removed.
48
+ if (s === null && t === null) {
49
+ merged.delete(id);
50
+ continue;
51
+ }
52
+ // Case 5: shape added in source only (not in ancestor or target).
53
+ if (a === null && t === null && s !== null) {
54
+ merged.set(id, s);
55
+ continue;
56
+ }
57
+ // Case 5': shape added in target only — already in merged.
58
+ if (a === null && s === null && t !== null)
59
+ continue;
60
+ // Anything else is a genuine conflict.
61
+ conflicts.push({ elementId: id, base: a, source: s, target: t });
62
+ }
63
+ // Scene wrapper: keep target's edges / layers / viewport /
64
+ // annotations — only the shapes pass through three-way merge.
65
+ const autoMerged = { ...target, elements: merged };
66
+ return { autoMerged, conflicts };
67
+ };
68
+ export const applyConflictResolutions = (report, resolutions, cloneWithNewId = defaultClone) => {
69
+ const merged = new Map(report.autoMerged.elements);
70
+ const byId = new Map();
71
+ for (const c of report.conflicts)
72
+ byId.set(c.elementId, c);
73
+ for (const res of resolutions) {
74
+ const c = byId.get(res.elementId);
75
+ if (!c)
76
+ continue;
77
+ switch (res.choice) {
78
+ case "ours":
79
+ if (c.target !== null)
80
+ merged.set(c.elementId, c.target);
81
+ else
82
+ merged.delete(c.elementId);
83
+ break;
84
+ case "theirs":
85
+ if (c.source !== null)
86
+ merged.set(c.elementId, c.source);
87
+ else
88
+ merged.delete(c.elementId);
89
+ break;
90
+ case "both":
91
+ if (c.target !== null)
92
+ merged.set(c.elementId, c.target);
93
+ else
94
+ merged.delete(c.elementId);
95
+ if (c.source !== null) {
96
+ const dup = cloneWithNewId(c.source);
97
+ merged.set(dup.id, dup);
98
+ }
99
+ break;
100
+ }
101
+ }
102
+ return { ...report.autoMerged, elements: merged };
103
+ };
104
+ const defaultClone = (shape) => {
105
+ const nextId = `${shape.id}-copy`;
106
+ return { ...shape, id: nextId };
107
+ };
108
+ //# sourceMappingURL=three-way-merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"three-way-merge.js","sourceRoot":"","sources":["../src/three-way-merge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import type { Transform, Vec2 } from "@oh-just-another/types";
2
+ /**
3
+ * Visual style of the background grid (when `gridSize > 0`).
4
+ * `"lines"` — classic ruled grid (default; matches a standard grid).
5
+ * `"dots"` — a dot at every grid intersection. Looks calmer for
6
+ * free-form diagramming (standard style).
7
+ *
8
+ * Snap behaviour is identical between styles — only the paint
9
+ * differs.
10
+ */
11
+ export type GridStyle = "lines" | "dots";
12
+ /**
13
+ * Camera over the world. Stored as pan/zoom/rotation rather than a raw matrix
14
+ * because every UI control (zoom-to-fit, hotkeys, pinch) wants these axes
15
+ * directly; the matrix form is derivable.
16
+ */
17
+ export interface Viewport {
18
+ /** World coordinate at viewport (0, 0) before rotation. */
19
+ readonly pan: Vec2;
20
+ /** Uniform scale. 1 = native; 2 = zoomed in 2×. */
21
+ readonly zoom: number;
22
+ /** Rotation in radians, counter-clockwise. */
23
+ readonly rotation: number;
24
+ readonly size: {
25
+ readonly width: number;
26
+ readonly height: number;
27
+ };
28
+ /**
29
+ * Grid size in world units. When `undefined` / `0` the background
30
+ * grid is hidden. Renderers that paint a background grid use this
31
+ * value. Snap-to-grid uses it when present and falls back to
32
+ * {@link DEFAULT_GRID_SPACING} when the grid is hidden but snapping
33
+ * is still on (see {@link resolveSnapSpacing}).
34
+ */
35
+ readonly gridSize?: number;
36
+ /**
37
+ * How the grid is painted. Default `"lines"` for backwards-compat;
38
+ * snap math doesn't read this field. Renderers fall back to lines
39
+ * when the field is missing.
40
+ */
41
+ readonly gridStyle?: GridStyle;
42
+ /**
43
+ * Whether dragging / resizing / creating snaps geometry to the grid.
44
+ * `undefined` is treated as ON (see {@link isSnapToGridEnabled}) so
45
+ * existing documents get the default-on behaviour. Independent of
46
+ * grid visibility — snapping can stay on with the grid hidden.
47
+ */
48
+ readonly snapToGrid?: boolean;
49
+ }
50
+ /**
51
+ * Resolve the world-unit spacing snap-to-grid should round to. Uses the
52
+ * visible `gridSize` when set, otherwise the {@link DEFAULT_GRID_SPACING}
53
+ * fallback — so snapping keeps working when the grid is hidden.
54
+ */
55
+ export declare const resolveSnapSpacing: (viewport: Viewport) => number;
56
+ /**
57
+ * Whether snap-to-grid is enabled for this viewport. `undefined`
58
+ * (legacy / fresh documents) counts as ON — the product default.
59
+ */
60
+ export declare const isSnapToGridEnabled: (viewport: Viewport) => boolean;
61
+ export declare const DEFAULT_VIEWPORT: Viewport;
62
+ /** World → screen transform. */
63
+ export declare const getWorldToScreen: (viewport: Viewport) => Transform;
64
+ /** Screen → world transform (inverse of `getWorldToScreen`). */
65
+ export declare const getScreenToWorld: (viewport: Viewport) => Transform;
66
+ /**
67
+ * Pan the camera by a screen-space delta. Most useful for drag handlers that
68
+ * report pixel deltas; the delta is divided by `zoom` so panning by 1 screen
69
+ * pixel moves the world by 1 / zoom world units.
70
+ */
71
+ export declare const panBy: (viewport: Viewport, deltaScreen: Vec2) => Viewport;
72
+ /**
73
+ * Multiplicative zoom around a world-space anchor. The anchor stays under the
74
+ * same screen pixel, which is what users expect from mouse-wheel zoom.
75
+ */
76
+ export declare const zoomAt: (viewport: Viewport, factor: number, anchorWorld: Vec2) => Viewport;
77
+ export declare const resize: (viewport: Viewport, width: number, height: number) => Viewport;
78
+ //# sourceMappingURL=viewport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewport.d.ts","sourceRoot":"","sources":["../src/viewport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAI9D;;;;;;;;GAQG;AACH,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAEzC;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,2DAA2D;IAC3D,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC;IACnB,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8CAA8C;IAC9C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,UAAU,QAAQ,KAAG,MAC+B,CAAC;AAExF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,UAAU,QAAQ,KAAG,OAAsC,CAAC;AAEhG,eAAO,MAAM,gBAAgB,EAAE,QAK7B,CAAC;AAEH,gCAAgC;AAChC,eAAO,MAAM,gBAAgB,GAAI,UAAU,QAAQ,KAAG,SAMrD,CAAC;AAEF,gEAAgE;AAChE,eAAO,MAAM,gBAAgB,GAAI,UAAU,QAAQ,KAAG,SACV,CAAC;AAE7C;;;;GAIG;AACH,eAAO,MAAM,KAAK,GAAI,UAAU,QAAQ,EAAE,aAAa,IAAI,KAAG,QAM5D,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,MAAM,GAAI,UAAU,QAAQ,EAAE,QAAQ,MAAM,EAAE,aAAa,IAAI,KAAG,QAW9E,CAAC;AAEF,eAAO,MAAM,MAAM,GAAI,UAAU,QAAQ,EAAE,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAG,QAGzE,CAAC"}
@@ -0,0 +1,62 @@
1
+ import { matrix } from "@oh-just-another/math";
2
+ import { DEFAULT_GRID_SPACING } from "./constants.js";
3
+ /**
4
+ * Resolve the world-unit spacing snap-to-grid should round to. Uses the
5
+ * visible `gridSize` when set, otherwise the {@link DEFAULT_GRID_SPACING}
6
+ * fallback — so snapping keeps working when the grid is hidden.
7
+ */
8
+ export const resolveSnapSpacing = (viewport) => viewport.gridSize && viewport.gridSize > 0 ? viewport.gridSize : DEFAULT_GRID_SPACING;
9
+ /**
10
+ * Whether snap-to-grid is enabled for this viewport. `undefined`
11
+ * (legacy / fresh documents) counts as ON — the product default.
12
+ */
13
+ export const isSnapToGridEnabled = (viewport) => viewport.snapToGrid ?? true;
14
+ export const DEFAULT_VIEWPORT = Object.freeze({
15
+ pan: { x: 0, y: 0 },
16
+ zoom: 1,
17
+ rotation: 0,
18
+ size: { width: 0, height: 0 },
19
+ });
20
+ /** World → screen transform. */
21
+ export const getWorldToScreen = (viewport) => {
22
+ // Order: world point → translate by -pan → rotate → scale.
23
+ const translate = matrix.translation(-viewport.pan.x, -viewport.pan.y);
24
+ const rotate = matrix.rotation(viewport.rotation);
25
+ const scale = matrix.scaling(viewport.zoom);
26
+ return matrix.multiply(scale, matrix.multiply(rotate, translate));
27
+ };
28
+ /** Screen → world transform (inverse of `getWorldToScreen`). */
29
+ export const getScreenToWorld = (viewport) => matrix.inverse(getWorldToScreen(viewport));
30
+ /**
31
+ * Pan the camera by a screen-space delta. Most useful for drag handlers that
32
+ * report pixel deltas; the delta is divided by `zoom` so panning by 1 screen
33
+ * pixel moves the world by 1 / zoom world units.
34
+ */
35
+ export const panBy = (viewport, deltaScreen) => ({
36
+ ...viewport,
37
+ pan: {
38
+ x: viewport.pan.x - deltaScreen.x / viewport.zoom,
39
+ y: viewport.pan.y - deltaScreen.y / viewport.zoom,
40
+ },
41
+ });
42
+ /**
43
+ * Multiplicative zoom around a world-space anchor. The anchor stays under the
44
+ * same screen pixel, which is what users expect from mouse-wheel zoom.
45
+ */
46
+ export const zoomAt = (viewport, factor, anchorWorld) => {
47
+ const newZoom = viewport.zoom * factor;
48
+ // Adjust pan so that anchorWorld maps to the same screen point.
49
+ return {
50
+ ...viewport,
51
+ zoom: newZoom,
52
+ pan: {
53
+ x: anchorWorld.x - (anchorWorld.x - viewport.pan.x) / factor,
54
+ y: anchorWorld.y - (anchorWorld.y - viewport.pan.y) / factor,
55
+ },
56
+ };
57
+ };
58
+ export const resize = (viewport, width, height) => ({
59
+ ...viewport,
60
+ size: { width, height },
61
+ });
62
+ //# sourceMappingURL=viewport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewport.js","sourceRoot":"","sources":["../src/viewport.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@oh-just-another/scene",
3
+ "version": "0.57.0",
4
+ "description": "scene package",
5
+ "license": "MIT",
6
+ "author": "Rustam Garifulin <rustam@n69.in>",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/oh-just-another/diagram.git",
10
+ "directory": "packages/scene"
11
+ },
12
+ "homepage": "https://github.com/oh-just-another/diagram#readme",
13
+ "bugs": "https://github.com/oh-just-another/diagram/issues",
14
+ "keywords": [
15
+ "diagram",
16
+ "canvas",
17
+ "svg",
18
+ "editor",
19
+ "graph",
20
+ "drawing"
21
+ ],
22
+ "type": "module",
23
+ "main": "./dist/index.js",
24
+ "module": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.js"
30
+ }
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md",
35
+ "CHANGELOG.md"
36
+ ],
37
+ "sideEffects": false,
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "dependencies": {
42
+ "fractional-keys": "^0.1.1",
43
+ "@oh-just-another/types": "0.57.0",
44
+ "@oh-just-another/math": "0.57.0"
45
+ },
46
+ "scripts": {
47
+ "build": "tsc -b tsconfig.build.json",
48
+ "typecheck": "tsc --noEmit",
49
+ "test": "vitest run",
50
+ "test:watch": "vitest",
51
+ "lint": "eslint src tests",
52
+ "clean": "rm -rf dist *.tsbuildinfo"
53
+ }
54
+ }