@oh-just-another/state 0.58.0 → 0.60.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.
- package/CHANGELOG.md +158 -0
- package/README.md +78 -27
- package/dist/.tsbuildinfo +1 -1
- package/dist/actions/actionArrange.d.ts +13 -0
- package/dist/actions/actionArrange.d.ts.map +1 -0
- package/dist/actions/actionArrange.js +130 -0
- package/dist/actions/actionArrange.js.map +1 -0
- package/dist/actions/actionClipboard.d.ts +2 -0
- package/dist/actions/actionClipboard.d.ts.map +1 -1
- package/dist/actions/actionClipboard.js +32 -1
- package/dist/actions/actionClipboard.js.map +1 -1
- package/dist/actions/actionKeyboard.d.ts.map +1 -1
- package/dist/actions/actionKeyboard.js +77 -9
- package/dist/actions/actionKeyboard.js.map +1 -1
- package/dist/actions/actionMode.d.ts +4 -0
- package/dist/actions/actionMode.d.ts.map +1 -1
- package/dist/actions/actionMode.js +54 -0
- package/dist/actions/actionMode.js.map +1 -1
- package/dist/actions/actionSelection.d.ts.map +1 -1
- package/dist/actions/actionSelection.js +1 -0
- package/dist/actions/actionSelection.js.map +1 -1
- package/dist/actions/actionText.d.ts +5 -0
- package/dist/actions/actionText.d.ts.map +1 -0
- package/dist/actions/actionText.js +37 -0
- package/dist/actions/actionText.js.map +1 -0
- package/dist/actions/actionView.d.ts +6 -0
- package/dist/actions/actionView.d.ts.map +1 -1
- package/dist/actions/actionView.js +20 -2
- package/dist/actions/actionView.js.map +1 -1
- package/dist/actions/actionZoom.d.ts.map +1 -1
- package/dist/actions/actionZoom.js +5 -0
- package/dist/actions/actionZoom.js.map +1 -1
- package/dist/actions/index.d.ts +6 -4
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +6 -4
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/registry.d.ts.map +1 -1
- package/dist/actions/registry.js +17 -0
- package/dist/actions/registry.js.map +1 -1
- package/dist/actions/types.d.ts +10 -1
- package/dist/actions/types.d.ts.map +1 -1
- package/dist/actions/types.js.map +1 -1
- package/dist/auto-layout-scheduler.d.ts +1 -3
- package/dist/auto-layout-scheduler.d.ts.map +1 -1
- package/dist/auto-layout-scheduler.js +1 -2
- package/dist/auto-layout-scheduler.js.map +1 -1
- package/dist/built-in-handlers.d.ts.map +1 -1
- package/dist/built-in-handlers.js +14 -1
- package/dist/built-in-handlers.js.map +1 -1
- package/dist/clipboard.d.ts +0 -14
- package/dist/clipboard.d.ts.map +1 -1
- package/dist/clipboard.js +1 -1
- package/dist/clipboard.js.map +1 -1
- package/dist/constants.d.ts +208 -41
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +210 -25
- package/dist/constants.js.map +1 -1
- package/dist/dom-events.d.ts +8 -2
- package/dist/dom-events.d.ts.map +1 -1
- package/dist/dom-events.js +12 -0
- package/dist/dom-events.js.map +1 -1
- package/dist/editor/animation-scene.d.ts +36 -0
- package/dist/editor/animation-scene.d.ts.map +1 -0
- package/dist/editor/animation-scene.js +194 -0
- package/dist/editor/animation-scene.js.map +1 -0
- package/dist/editor/animation.d.ts +43 -0
- package/dist/editor/animation.d.ts.map +1 -0
- package/dist/editor/animation.js +80 -0
- package/dist/editor/animation.js.map +1 -0
- package/dist/editor/applies/arrange.d.ts +46 -0
- package/dist/editor/applies/arrange.d.ts.map +1 -0
- package/dist/editor/applies/arrange.js +162 -0
- package/dist/editor/applies/arrange.js.map +1 -0
- package/dist/editor/applies/create.d.ts +0 -6
- package/dist/editor/applies/create.d.ts.map +1 -1
- package/dist/editor/applies/create.js +1 -1
- package/dist/editor/applies/create.js.map +1 -1
- package/dist/editor/applies/edge.d.ts +8 -1
- package/dist/editor/applies/edge.d.ts.map +1 -1
- package/dist/editor/applies/edge.js +31 -1
- package/dist/editor/applies/edge.js.map +1 -1
- package/dist/editor/applies/link-move.d.ts +0 -8
- package/dist/editor/applies/link-move.d.ts.map +1 -1
- package/dist/editor/applies/link-move.js +1 -1
- package/dist/editor/applies/link-move.js.map +1 -1
- package/dist/editor/applies/move.d.ts +6 -0
- package/dist/editor/applies/move.d.ts.map +1 -1
- package/dist/editor/applies/move.js +6 -0
- package/dist/editor/applies/move.js.map +1 -1
- package/dist/editor/applies/resize.d.ts +26 -5
- package/dist/editor/applies/resize.d.ts.map +1 -1
- package/dist/editor/applies/resize.js +91 -13
- package/dist/editor/applies/resize.js.map +1 -1
- package/dist/editor/caret-blink.d.ts +18 -0
- package/dist/editor/caret-blink.d.ts.map +1 -0
- package/dist/editor/caret-blink.js +42 -0
- package/dist/editor/caret-blink.js.map +1 -0
- package/dist/editor/container-ops.d.ts.map +1 -1
- package/dist/editor/container-ops.js +2 -2
- package/dist/editor/container-ops.js.map +1 -1
- package/dist/editor/dirty-rect.d.ts +23 -0
- package/dist/editor/dirty-rect.d.ts.map +1 -0
- package/dist/editor/dirty-rect.js +115 -0
- package/dist/editor/dirty-rect.js.map +1 -0
- package/dist/editor/gif-playback.d.ts +45 -0
- package/dist/editor/gif-playback.d.ts.map +1 -0
- package/dist/editor/gif-playback.js +125 -0
- package/dist/editor/gif-playback.js.map +1 -0
- package/dist/editor/hit-test.d.ts +3 -3
- package/dist/editor/hit-test.d.ts.map +1 -1
- package/dist/editor/hit-test.js +40 -15
- package/dist/editor/hit-test.js.map +1 -1
- package/dist/editor/interaction-state.d.ts +184 -0
- package/dist/editor/interaction-state.d.ts.map +1 -0
- package/dist/editor/interaction-state.js +139 -0
- package/dist/editor/interaction-state.js.map +1 -0
- package/dist/editor/link-handle-drag.d.ts +152 -0
- package/dist/editor/link-handle-drag.d.ts.map +1 -0
- package/dist/editor/link-handle-drag.js +300 -0
- package/dist/editor/link-handle-drag.js.map +1 -0
- package/dist/editor/long-press.d.ts.map +1 -1
- package/dist/editor/long-press.js +2 -2
- package/dist/editor/long-press.js.map +1 -1
- package/dist/editor/pinch.d.ts.map +1 -1
- package/dist/editor/pinch.js +6 -6
- package/dist/editor/pinch.js.map +1 -1
- package/dist/editor/pointer-binding.d.ts +9 -11
- package/dist/editor/pointer-binding.d.ts.map +1 -1
- package/dist/editor/pointer-binding.js +1191 -890
- package/dist/editor/pointer-binding.js.map +1 -1
- package/dist/editor/public/arrange-group.d.ts +3 -9
- package/dist/editor/public/arrange-group.d.ts.map +1 -1
- package/dist/editor/public/arrange-group.js +4 -6
- package/dist/editor/public/arrange-group.js.map +1 -1
- package/dist/editor/public/brush.d.ts +31 -12
- package/dist/editor/public/brush.d.ts.map +1 -1
- package/dist/editor/public/brush.js +66 -17
- package/dist/editor/public/brush.js.map +1 -1
- package/dist/editor/public/clipboard.d.ts +2 -4
- package/dist/editor/public/clipboard.d.ts.map +1 -1
- package/dist/editor/public/clipboard.js +2 -4
- package/dist/editor/public/clipboard.js.map +1 -1
- package/dist/editor/public/cursor.d.ts +29 -0
- package/dist/editor/public/cursor.d.ts.map +1 -0
- package/dist/editor/public/cursor.js +146 -0
- package/dist/editor/public/cursor.js.map +1 -0
- package/dist/editor/public/eraser.d.ts +55 -0
- package/dist/editor/public/eraser.d.ts.map +1 -0
- package/dist/editor/public/eraser.js +65 -0
- package/dist/editor/public/eraser.js.map +1 -0
- package/dist/editor/public/frame-name.d.ts +20 -0
- package/dist/editor/public/frame-name.d.ts.map +1 -0
- package/dist/editor/public/frame-name.js +54 -0
- package/dist/editor/public/frame-name.js.map +1 -0
- package/dist/editor/public/image-insert.d.ts +1 -1
- package/dist/editor/public/image-insert.d.ts.map +1 -1
- package/dist/editor/public/laser.d.ts +38 -0
- package/dist/editor/public/laser.d.ts.map +1 -0
- package/dist/editor/public/laser.js +42 -0
- package/dist/editor/public/laser.js.map +1 -0
- package/dist/editor/public/layers.d.ts.map +1 -1
- package/dist/editor/public/layers.js +2 -2
- package/dist/editor/public/layers.js.map +1 -1
- package/dist/editor/public/link.d.ts +11 -2
- package/dist/editor/public/link.d.ts.map +1 -1
- package/dist/editor/public/link.js +70 -2
- package/dist/editor/public/link.js.map +1 -1
- package/dist/editor/public/placement.d.ts +60 -2
- package/dist/editor/public/placement.d.ts.map +1 -1
- package/dist/editor/public/placement.js +193 -2
- package/dist/editor/public/placement.js.map +1 -1
- package/dist/editor/public/selection-ops.d.ts +35 -1
- package/dist/editor/public/selection-ops.d.ts.map +1 -1
- package/dist/editor/public/selection-ops.js +97 -2
- package/dist/editor/public/selection-ops.js.map +1 -1
- package/dist/editor/public/stroke-eraser-coverage.d.ts +37 -0
- package/dist/editor/public/stroke-eraser-coverage.d.ts.map +1 -0
- package/dist/editor/public/stroke-eraser-coverage.js +168 -0
- package/dist/editor/public/stroke-eraser-coverage.js.map +1 -0
- package/dist/editor/public/stroke-eraser.d.ts +50 -0
- package/dist/editor/public/stroke-eraser.d.ts.map +1 -0
- package/dist/editor/public/stroke-eraser.js +176 -0
- package/dist/editor/public/stroke-eraser.js.map +1 -0
- package/dist/editor/public/stroke-smoothing.d.ts +21 -0
- package/dist/editor/public/stroke-smoothing.d.ts.map +1 -0
- package/dist/editor/public/stroke-smoothing.js +37 -0
- package/dist/editor/public/stroke-smoothing.js.map +1 -0
- package/dist/editor/public/text-edit.d.ts +1 -10
- package/dist/editor/public/text-edit.d.ts.map +1 -1
- package/dist/editor/public/text-edit.js +2 -16
- package/dist/editor/public/text-edit.js.map +1 -1
- package/dist/editor/public/tool-ops.d.ts +130 -0
- package/dist/editor/public/tool-ops.d.ts.map +1 -0
- package/dist/editor/public/tool-ops.js +392 -0
- package/dist/editor/public/tool-ops.js.map +1 -0
- package/dist/editor/public/z-order.d.ts +1 -12
- package/dist/editor/public/z-order.d.ts.map +1 -1
- package/dist/editor/public/z-order.js +5 -5
- package/dist/editor/public/z-order.js.map +1 -1
- package/dist/editor/public/zoom-pan.d.ts +15 -4
- package/dist/editor/public/zoom-pan.d.ts.map +1 -1
- package/dist/editor/public/zoom-pan.js +39 -7
- package/dist/editor/public/zoom-pan.js.map +1 -1
- package/dist/editor/render-orchestrator.d.ts +177 -5
- package/dist/editor/render-orchestrator.d.ts.map +1 -1
- package/dist/editor/render-orchestrator.js +519 -358
- package/dist/editor/render-orchestrator.js.map +1 -1
- package/dist/editor/resize-helpers.d.ts +21 -5
- package/dist/editor/resize-helpers.d.ts.map +1 -1
- package/dist/editor/resize-helpers.js +59 -19
- package/dist/editor/resize-helpers.js.map +1 -1
- package/dist/editor/text-edit.d.ts +136 -0
- package/dist/editor/text-edit.d.ts.map +1 -0
- package/dist/editor/text-edit.js +328 -0
- package/dist/editor/text-edit.js.map +1 -0
- package/dist/editor/viewport-helpers.d.ts.map +1 -1
- package/dist/editor/viewport-helpers.js +3 -3
- package/dist/editor/viewport-helpers.js.map +1 -1
- package/dist/editor-events.d.ts +1 -1
- package/dist/editor-events.d.ts.map +1 -1
- package/dist/editor.d.ts +603 -346
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +1843 -1630
- package/dist/editor.js.map +1 -1
- package/dist/file-drop.d.ts.map +1 -1
- package/dist/file-drop.js +1 -2
- package/dist/file-drop.js.map +1 -1
- package/dist/frame-helpers.d.ts.map +1 -1
- package/dist/frame-helpers.js +5 -5
- package/dist/frame-helpers.js.map +1 -1
- package/dist/group-helpers.d.ts.map +1 -1
- package/dist/group-helpers.js +4 -4
- package/dist/group-helpers.js.map +1 -1
- package/dist/handle.d.ts +59 -6
- package/dist/handle.d.ts.map +1 -1
- package/dist/handle.js +99 -7
- package/dist/handle.js.map +1 -1
- package/dist/hotkeys-binding.d.ts +26 -0
- package/dist/hotkeys-binding.d.ts.map +1 -0
- package/dist/hotkeys-binding.js +35 -0
- package/dist/hotkeys-binding.js.map +1 -0
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -3
- package/dist/index.js.map +1 -1
- package/dist/link-selection.d.ts +3 -5
- package/dist/link-selection.d.ts.map +1 -1
- package/dist/link-selection.js +3 -12
- package/dist/link-selection.js.map +1 -1
- package/dist/machine.d.ts +27 -1
- package/dist/machine.d.ts.map +1 -1
- package/dist/machine.js +38 -0
- package/dist/machine.js.map +1 -1
- package/dist/modes.d.ts +15 -1
- package/dist/modes.d.ts.map +1 -1
- package/dist/modes.js.map +1 -1
- package/dist/overlay.d.ts +92 -6
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +582 -125
- package/dist/overlay.js.map +1 -1
- package/dist/search.d.ts +37 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +45 -0
- package/dist/search.js.map +1 -0
- package/dist/selection.d.ts.map +1 -1
- package/dist/selection.js +2 -10
- package/dist/selection.js.map +1 -1
- package/dist/util.d.ts +8 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +17 -0
- package/dist/util.js.map +1 -0
- package/package.json +7 -7
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { getElement, updateElement } from "@oh-just-another/scene";
|
|
1
|
+
import { getElement, updateElement, } from "@oh-just-another/scene";
|
|
2
2
|
/**
|
|
3
3
|
* Schemes allowed to be stored / opened. Everything else (notably
|
|
4
4
|
* `javascript:`, `data:`, `vbscript:`, `file:`) is rejected so a scene
|
|
5
5
|
* can't smuggle an XSS / local-file payload through an element link.
|
|
6
6
|
*/
|
|
7
7
|
const SAFE_SCHEME = /^(https?:|mailto:)/i;
|
|
8
|
-
|
|
8
|
+
// Domain labels exclude `.` so the literal dots don't overlap the surrounding
|
|
9
|
+
// character classes — that overlap is what lets a crafted `a@!.!.!.…` string
|
|
10
|
+
// drive polynomial backtracking. Each label is matched linearly.
|
|
11
|
+
const BARE_EMAIL = /^[^\s@]+@[^\s@.]+(?:\.[^\s@.]+)+$/;
|
|
9
12
|
/**
|
|
10
13
|
* Normalise user-entered link text into a safe, storable href, or
|
|
11
14
|
* `null` to clear / reject. Adds `https://` to a scheme-less URL,
|
|
@@ -69,4 +72,69 @@ export const computeSetLink = (scene, ids, href) => {
|
|
|
69
72
|
patch: patches.length === 1 && firstPatch !== undefined ? firstPatch : { kind: "batch", patches },
|
|
70
73
|
};
|
|
71
74
|
};
|
|
75
|
+
/**
|
|
76
|
+
* Convert a snap candidate into a `LinkEndpoint`. Anchor snap → named anchor
|
|
77
|
+
* ref; outline snap → outline ref with the sampled ratio. Falls back to a free
|
|
78
|
+
* point if the metadata isn't recognised.
|
|
79
|
+
*/
|
|
80
|
+
const endpointFromSnap = (elementId, candidate, shape) => {
|
|
81
|
+
if (candidate.kind === "anchor") {
|
|
82
|
+
const ref = candidate.metadata?.ref;
|
|
83
|
+
if (ref)
|
|
84
|
+
return { kind: "anchor", elementId, anchor: ref };
|
|
85
|
+
}
|
|
86
|
+
if (candidate.kind === "outline" && typeof candidate.metadata?.ratio === "number") {
|
|
87
|
+
return { kind: "outline", elementId, ratio: candidate.metadata.ratio };
|
|
88
|
+
}
|
|
89
|
+
// Defensive fallback — should not happen with built-in contributors.
|
|
90
|
+
void shape;
|
|
91
|
+
return { kind: "point", position: candidate.snapped };
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Resolve where a link endpoint should attach when dropped at `worldPoint`.
|
|
95
|
+
* Attach contract: a port dot → *fixed* anchor; near an EDGE (not a dot) →
|
|
96
|
+
* *fixed* outline point (a perimeter ratio — survives move/resize); the body
|
|
97
|
+
* interior → *floating* against the whole shape (re-aims as shapes move); empty
|
|
98
|
+
* canvas → a free point. `pressTargetElement` biases the pick toward the pressed
|
|
99
|
+
* shape, but a dot drawn outside the body still binds even when it's null.
|
|
100
|
+
*/
|
|
101
|
+
export const snapLinkEndpoint = (scene, snapEngine, threshold, pressTargetElement, worldPoint) => {
|
|
102
|
+
const result = snapEngine.snap({
|
|
103
|
+
scene,
|
|
104
|
+
probe: worldPoint,
|
|
105
|
+
threshold,
|
|
106
|
+
gesture: "draw-edge",
|
|
107
|
+
});
|
|
108
|
+
const pick = (kind) => {
|
|
109
|
+
if (pressTargetElement !== null) {
|
|
110
|
+
const onTarget = result.all.find((c) => c.kind === kind && c.metadata?.elementId === pressTargetElement);
|
|
111
|
+
if (onTarget)
|
|
112
|
+
return onTarget;
|
|
113
|
+
}
|
|
114
|
+
return result.all.find((c) => c.kind === kind);
|
|
115
|
+
};
|
|
116
|
+
const boundFrom = (cand, want) => {
|
|
117
|
+
if (!cand)
|
|
118
|
+
return null;
|
|
119
|
+
const elId = cand.metadata?.elementId;
|
|
120
|
+
if (elId === undefined)
|
|
121
|
+
return null;
|
|
122
|
+
const shp = getElement(scene, elId);
|
|
123
|
+
if (!shp)
|
|
124
|
+
return null;
|
|
125
|
+
const ep = endpointFromSnap(elId, cand, shp);
|
|
126
|
+
return ep.kind === want ? ep : null;
|
|
127
|
+
};
|
|
128
|
+
const anchorEp = boundFrom(pick("anchor"), "anchor");
|
|
129
|
+
if (anchorEp)
|
|
130
|
+
return anchorEp;
|
|
131
|
+
const outlineEp = boundFrom(pick("outline"), "outline");
|
|
132
|
+
if (outlineEp)
|
|
133
|
+
return outlineEp;
|
|
134
|
+
// No dot/edge snap. Over a shape body → floating; else a free point.
|
|
135
|
+
if (pressTargetElement !== null && getElement(scene, pressTargetElement)) {
|
|
136
|
+
return { kind: "floating", elementId: pressTargetElement };
|
|
137
|
+
}
|
|
138
|
+
return { kind: "point", position: worldPoint };
|
|
139
|
+
};
|
|
72
140
|
//# sourceMappingURL=link.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link.js","sourceRoot":"","sources":["../../../src/editor/public/link.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"link.js","sourceRoot":"","sources":["../../../src/editor/public/link.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type Scene, type Element, type Patch } from "@oh-just-another/scene";
|
|
2
|
-
import type { LayerId, ElementId, Vec2 } from "@oh-just-another/types";
|
|
1
|
+
import { type Scene, type Element, type Patch, type FractionalIndex } from "@oh-just-another/scene";
|
|
2
|
+
import type { LayerId, ElementId, LinkId, Bounds, Vec2 } from "@oh-just-another/types";
|
|
3
3
|
import type { Mode } from "../../modes.js";
|
|
4
4
|
/**
|
|
5
5
|
* Build a shape for keyboard-friendly creation centred on
|
|
@@ -57,4 +57,62 @@ export declare const beginPlacementState: (shape: Element) => {
|
|
|
57
57
|
export declare const computePlacementCancel: (scene: Scene, elementId: ElementId) => {
|
|
58
58
|
readonly scene: Scene;
|
|
59
59
|
};
|
|
60
|
+
/**
|
|
61
|
+
* Ghost geometry for what clicking a start dot would create (standard hover
|
|
62
|
+
* preview): the would-be new element's world bounds + the connector path from
|
|
63
|
+
* the dot to it. Pure — no mutation. Mirrors the placement in the Editor's
|
|
64
|
+
* `createLinkedElementFromAnchor`.
|
|
65
|
+
*/
|
|
66
|
+
export declare const previewClickCreate: (scene: Scene, activeLayerId: LayerId, fromElement: ElementId, anchorName: string) => {
|
|
67
|
+
bounds: Bounds;
|
|
68
|
+
path: readonly Vec2[];
|
|
69
|
+
element: Element;
|
|
70
|
+
ghostScene: Scene;
|
|
71
|
+
ghostLinkId: LinkId;
|
|
72
|
+
} | null;
|
|
73
|
+
/**
|
|
74
|
+
* Compute the scene + two patches (clone-add, link) for the "click a link-start
|
|
75
|
+
* dot" gesture: spawn a same-kind blank clone of `fromElement` in the dot's
|
|
76
|
+
* outward direction and link source → clone. Pure — the caller pre-allocates
|
|
77
|
+
* `newId` / `linkId` and owns the history transaction + selection. Returns
|
|
78
|
+
* `null` when the source is gone.
|
|
79
|
+
*/
|
|
80
|
+
export declare const computeLinkedElementFromAnchor: (scene: Scene, activeLayerId: LayerId, fromElement: ElementId, anchorName: string, newId: ElementId, linkId: LinkId) => {
|
|
81
|
+
scene: Scene;
|
|
82
|
+
addPatch: Patch;
|
|
83
|
+
linkPatch: Patch;
|
|
84
|
+
} | null;
|
|
85
|
+
/**
|
|
86
|
+
* Compute the clone-add patches for an in-place duplicate. `ids` is the expanded
|
|
87
|
+
* set to clone (selection + group/frame descendants), `idMap` the pre-allocated
|
|
88
|
+
* old→new ids so cross-references (`parentId` / `frameId`) remap to the clones.
|
|
89
|
+
* Pure — the caller owns id allocation, the history transaction, and selection.
|
|
90
|
+
* Each clone lands on top of its layer (order recomputed against the growing
|
|
91
|
+
* scene, so clones stack in iteration order).
|
|
92
|
+
*/
|
|
93
|
+
export declare const computeDuplicateInPlace: (scene: Scene, ids: ReadonlySet<ElementId>, idMap: ReadonlyMap<ElementId, ElementId>) => {
|
|
94
|
+
scene: Scene;
|
|
95
|
+
patches: Patch[];
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Compute the scene + two patches (element-add, link re-point) for dropping a
|
|
99
|
+
* link end onto empty canvas and picking a shape from the menu: build a shape
|
|
100
|
+
* from `factory` centred on the drop point and float the dropped link end
|
|
101
|
+
* against it. Pure — the caller pre-allocates `newId` and owns the history
|
|
102
|
+
* transaction + selection.
|
|
103
|
+
*/
|
|
104
|
+
export declare const computeShapeAtLinkDrop: (scene: Scene, activeLayerId: LayerId, drop: {
|
|
105
|
+
linkId: LinkId;
|
|
106
|
+
side: "from" | "to";
|
|
107
|
+
world: Vec2;
|
|
108
|
+
}, newId: ElementId, factory: (ctx: {
|
|
109
|
+
id: ElementId;
|
|
110
|
+
layerId: LayerId;
|
|
111
|
+
position: Vec2;
|
|
112
|
+
order: FractionalIndex;
|
|
113
|
+
}) => Element) => {
|
|
114
|
+
scene: Scene;
|
|
115
|
+
addPatch: Patch;
|
|
116
|
+
linkPatch: Patch;
|
|
117
|
+
};
|
|
60
118
|
//# sourceMappingURL=placement.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"placement.d.ts","sourceRoot":"","sources":["../../../src/editor/public/placement.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"placement.d.ts","sourceRoot":"","sources":["../../../src/editor/public/placement.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { addElement, apply, findContainerAt, getElementWorldBounds, orderForTop, removeElement, } from "@oh-just-another/scene";
|
|
1
|
+
import { addElement, apply, findContainerAt, findNearestAnchor, getAnchorOutwardNormal, getAnchorWorld, getElement, getElementWorldBounds, getLink, isBrush, isFrame, isText, orderForTop, removeElement, routeElbowLink, snapExcludedAnchors, updateLink, } from "@oh-just-another/scene";
|
|
2
2
|
import { elementId as castElementId } from "@oh-just-another/types";
|
|
3
|
-
import { TEXT_DEFAULT_FILL, TEXT_DEFAULT_FONT_FAMILY, TEXT_DEFAULT_FONT_SIZE, } from "../../constants.js";
|
|
3
|
+
import { ANCHOR_CLICK_NEW_ELEMENT_GAP, TEXT_DEFAULT_FILL, TEXT_DEFAULT_FONT_FAMILY, TEXT_DEFAULT_FONT_SIZE, } from "../../constants.js";
|
|
4
|
+
import { req } from "../../util.js";
|
|
5
|
+
import { computeCreateLink } from "../applies/create.js";
|
|
4
6
|
/**
|
|
5
7
|
* Build a shape for keyboard-friendly creation centred on
|
|
6
8
|
* `worldCenter`. Picks `rectangle` / `ellipse` based on `mode` (falls
|
|
@@ -108,4 +110,193 @@ export const beginPlacementState = (shape) => {
|
|
|
108
110
|
};
|
|
109
111
|
/** Undo of `beginPlacement` — remove the placed shape. */
|
|
110
112
|
export const computePlacementCancel = (scene, elementId) => ({ scene: removeElement(scene, elementId).scene });
|
|
113
|
+
// Throwaway ids for the click-create hover preview — never enter the real scene.
|
|
114
|
+
const PREVIEW_GHOST_ELEMENT_ID = "__ghost-preview__";
|
|
115
|
+
const PREVIEW_GHOST_LINK_ID = "__ghost-preview-link__";
|
|
116
|
+
/**
|
|
117
|
+
* Ghost geometry for what clicking a start dot would create (standard hover
|
|
118
|
+
* preview): the would-be new element's world bounds + the connector path from
|
|
119
|
+
* the dot to it. Pure — no mutation. Mirrors the placement in the Editor's
|
|
120
|
+
* `createLinkedElementFromAnchor`.
|
|
121
|
+
*/
|
|
122
|
+
export const previewClickCreate = (scene, activeLayerId, fromElement, anchorName) => {
|
|
123
|
+
const src = getElement(scene, fromElement);
|
|
124
|
+
if (!src)
|
|
125
|
+
return null;
|
|
126
|
+
// Brush strokes don't offer a click-create ghost (see computeLinkedElementFromAnchor).
|
|
127
|
+
if (isBrush(src))
|
|
128
|
+
return null;
|
|
129
|
+
const anchor = { kind: "named", name: anchorName };
|
|
130
|
+
const normal = getAnchorOutwardNormal(src, anchor);
|
|
131
|
+
const b = getElementWorldBounds(src);
|
|
132
|
+
const extentAlong = Math.abs(normal.x) * b.width + Math.abs(normal.y) * b.height;
|
|
133
|
+
const dist = extentAlong + ANCHOR_CLICK_NEW_ELEMENT_GAP;
|
|
134
|
+
const delta = { x: normal.x * dist, y: normal.y * dist };
|
|
135
|
+
const bounds = { x: b.x + delta.x, y: b.y + delta.y, width: b.width, height: b.height };
|
|
136
|
+
const fromWorld = getAnchorWorld(src, anchor);
|
|
137
|
+
// Facing edge of the ghost (toward the source) = its centre pulled back along
|
|
138
|
+
// the normal by half its extent.
|
|
139
|
+
const ghostCx = bounds.x + bounds.width / 2;
|
|
140
|
+
const ghostCy = bounds.y + bounds.height / 2;
|
|
141
|
+
const nearEdge = {
|
|
142
|
+
x: ghostCx - normal.x * (extentAlong / 2),
|
|
143
|
+
y: ghostCy - normal.y * (extentAlong / 2),
|
|
144
|
+
};
|
|
145
|
+
// The would-be element itself — a same-kind clone of the source shifted to the
|
|
146
|
+
// ghost bounds, with blank user text. The overlay renders THIS through the real
|
|
147
|
+
// renderer so the ghost looks like the actual shape (an ellipse ghosts as an
|
|
148
|
+
// ellipse), not a bounding rect. Throwaway id — never enters the real scene.
|
|
149
|
+
let element = {
|
|
150
|
+
...src,
|
|
151
|
+
id: PREVIEW_GHOST_ELEMENT_ID,
|
|
152
|
+
position: { x: src.position.x + delta.x, y: src.position.y + delta.y },
|
|
153
|
+
};
|
|
154
|
+
if (isText(element))
|
|
155
|
+
element = { ...element, text: "" };
|
|
156
|
+
else if (isFrame(element))
|
|
157
|
+
element = { ...element, name: "" };
|
|
158
|
+
// Build a throwaway scene holding the ghost element + the would-be link so the
|
|
159
|
+
// connector can be drawn through the REAL link renderer (same routing,
|
|
160
|
+
// arrowhead and style it'll have once created) — faded — instead of a dashed
|
|
161
|
+
// preview line. The `path` field stays for callers that just want the straight
|
|
162
|
+
// from→to segment.
|
|
163
|
+
const srcCenter = { x: b.x + b.width / 2, y: b.y + b.height / 2 };
|
|
164
|
+
const withGhost = addElement(scene, element).scene;
|
|
165
|
+
const placed = req(getElement(withGhost, PREVIEW_GHOST_ELEMENT_ID));
|
|
166
|
+
const { ref: toRef } = findNearestAnchor(placed, srcCenter, snapExcludedAnchors(placed));
|
|
167
|
+
const linkResult = computeCreateLink(withGhost, { kind: "anchor", elementId: fromElement, anchor }, { kind: "anchor", elementId: PREVIEW_GHOST_ELEMENT_ID, anchor: toRef }, PREVIEW_GHOST_LINK_ID, activeLayerId);
|
|
168
|
+
let ghostScene = linkResult.scene;
|
|
169
|
+
const edge = req(getLink(ghostScene, PREVIEW_GHOST_LINK_ID));
|
|
170
|
+
if ((edge.routing ?? "straight") === "orthogonal") {
|
|
171
|
+
const routedPoints = routeElbowLink(ghostScene, edge);
|
|
172
|
+
ghostScene = updateLink(ghostScene, PREVIEW_GHOST_LINK_ID, (e) => ({
|
|
173
|
+
...e,
|
|
174
|
+
routedPoints,
|
|
175
|
+
})).scene;
|
|
176
|
+
}
|
|
177
|
+
// Render only the ghost link (the shapes stay for endpoint resolution).
|
|
178
|
+
ghostScene = {
|
|
179
|
+
...ghostScene,
|
|
180
|
+
links: new Map([[PREVIEW_GHOST_LINK_ID, req(getLink(ghostScene, PREVIEW_GHOST_LINK_ID))]]),
|
|
181
|
+
};
|
|
182
|
+
return {
|
|
183
|
+
bounds,
|
|
184
|
+
path: [fromWorld, nearEdge],
|
|
185
|
+
element,
|
|
186
|
+
ghostScene,
|
|
187
|
+
ghostLinkId: PREVIEW_GHOST_LINK_ID,
|
|
188
|
+
};
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* Compute the scene + two patches (clone-add, link) for the "click a link-start
|
|
192
|
+
* dot" gesture: spawn a same-kind blank clone of `fromElement` in the dot's
|
|
193
|
+
* outward direction and link source → clone. Pure — the caller pre-allocates
|
|
194
|
+
* `newId` / `linkId` and owns the history transaction + selection. Returns
|
|
195
|
+
* `null` when the source is gone.
|
|
196
|
+
*/
|
|
197
|
+
export const computeLinkedElementFromAnchor = (scene, activeLayerId, fromElement, anchorName, newId, linkId) => {
|
|
198
|
+
const src = getElement(scene, fromElement);
|
|
199
|
+
if (!src)
|
|
200
|
+
return null;
|
|
201
|
+
// Drawn lines (brush strokes) don't clone-create a connected node from a
|
|
202
|
+
// start-dot click — duplicating a freehand line as a "node" is nonsensical.
|
|
203
|
+
// Dragging a real link from the line still works (that path skips this).
|
|
204
|
+
if (isBrush(src))
|
|
205
|
+
return null;
|
|
206
|
+
const anchor = { kind: "named", name: anchorName };
|
|
207
|
+
const normal = getAnchorOutwardNormal(src, anchor);
|
|
208
|
+
const bounds = getElementWorldBounds(src);
|
|
209
|
+
const srcCenter = { x: bounds.x + bounds.width / 2, y: bounds.y + bounds.height / 2 };
|
|
210
|
+
// Same-size clone → centre-to-centre distance = the source's extent along the
|
|
211
|
+
// normal + the gap, leaving exactly ANCHOR_CLICK_NEW_ELEMENT_GAP between the
|
|
212
|
+
// facing edges. `extentAlong` resolves to width for a horizontal normal,
|
|
213
|
+
// height for a vertical one (link-start dots are the four edge midpoints).
|
|
214
|
+
const extentAlong = Math.abs(normal.x) * bounds.width + Math.abs(normal.y) * bounds.height;
|
|
215
|
+
const dist = extentAlong + ANCHOR_CLICK_NEW_ELEMENT_GAP;
|
|
216
|
+
const delta = { x: normal.x * dist, y: normal.y * dist };
|
|
217
|
+
const order = orderForTop([...scene.elements.values()].filter((sh) => sh.layerId === src.layerId).map((sh) => sh.order));
|
|
218
|
+
let clone = {
|
|
219
|
+
...src,
|
|
220
|
+
id: newId,
|
|
221
|
+
position: { x: src.position.x + delta.x, y: src.position.y + delta.y },
|
|
222
|
+
order,
|
|
223
|
+
};
|
|
224
|
+
// Blank user text — a fresh same-kind shape, not a content copy. Cast through
|
|
225
|
+
// `Element` because `exactOptionalPropertyTypes` rejects the bare literal
|
|
226
|
+
// against the union (TS2375), though the narrowed branch is sound.
|
|
227
|
+
if (isText(clone))
|
|
228
|
+
clone = { ...clone, text: "" };
|
|
229
|
+
else if (isFrame(clone))
|
|
230
|
+
clone = { ...clone, name: "" };
|
|
231
|
+
const added = addElement(scene, clone);
|
|
232
|
+
const placed = req(getElement(added.scene, newId));
|
|
233
|
+
const { ref: toRef } = findNearestAnchor(placed, srcCenter, snapExcludedAnchors(placed));
|
|
234
|
+
const linkResult = computeCreateLink(added.scene, { kind: "anchor", elementId: fromElement, anchor }, { kind: "anchor", elementId: newId, anchor: toRef }, linkId, activeLayerId);
|
|
235
|
+
return { scene: linkResult.scene, addPatch: added.patch, linkPatch: linkResult.patch };
|
|
236
|
+
};
|
|
237
|
+
/**
|
|
238
|
+
* Compute the clone-add patches for an in-place duplicate. `ids` is the expanded
|
|
239
|
+
* set to clone (selection + group/frame descendants), `idMap` the pre-allocated
|
|
240
|
+
* old→new ids so cross-references (`parentId` / `frameId`) remap to the clones.
|
|
241
|
+
* Pure — the caller owns id allocation, the history transaction, and selection.
|
|
242
|
+
* Each clone lands on top of its layer (order recomputed against the growing
|
|
243
|
+
* scene, so clones stack in iteration order).
|
|
244
|
+
*/
|
|
245
|
+
export const computeDuplicateInPlace = (scene, ids, idMap) => {
|
|
246
|
+
let next = scene;
|
|
247
|
+
const patches = [];
|
|
248
|
+
for (const id of ids) {
|
|
249
|
+
const shape = getElement(next, id);
|
|
250
|
+
if (!shape)
|
|
251
|
+
continue;
|
|
252
|
+
const newId = idMap.get(id);
|
|
253
|
+
if (newId === undefined)
|
|
254
|
+
continue;
|
|
255
|
+
const order = orderForTop([...next.elements.values()]
|
|
256
|
+
.filter((sh) => sh.layerId === shape.layerId)
|
|
257
|
+
.map((sh) => sh.order));
|
|
258
|
+
const copy = { ...shape, id: newId, order };
|
|
259
|
+
if (copy.parentId !== undefined) {
|
|
260
|
+
const mapped = idMap.get(copy.parentId);
|
|
261
|
+
if (mapped !== undefined)
|
|
262
|
+
copy.parentId = mapped;
|
|
263
|
+
}
|
|
264
|
+
if (copy.frameId !== undefined) {
|
|
265
|
+
const mapped = idMap.get(copy.frameId);
|
|
266
|
+
if (mapped !== undefined)
|
|
267
|
+
copy.frameId = mapped;
|
|
268
|
+
}
|
|
269
|
+
const r = addElement(next, copy);
|
|
270
|
+
next = r.scene;
|
|
271
|
+
patches.push(r.patch);
|
|
272
|
+
}
|
|
273
|
+
return { scene: next, patches };
|
|
274
|
+
};
|
|
275
|
+
/**
|
|
276
|
+
* Compute the scene + two patches (element-add, link re-point) for dropping a
|
|
277
|
+
* link end onto empty canvas and picking a shape from the menu: build a shape
|
|
278
|
+
* from `factory` centred on the drop point and float the dropped link end
|
|
279
|
+
* against it. Pure — the caller pre-allocates `newId` and owns the history
|
|
280
|
+
* transaction + selection.
|
|
281
|
+
*/
|
|
282
|
+
export const computeShapeAtLinkDrop = (scene, activeLayerId, drop, newId, factory) => {
|
|
283
|
+
const order = orderForTop([...scene.elements.values()].filter((sh) => sh.layerId === activeLayerId).map((sh) => sh.order));
|
|
284
|
+
const built = factory({ id: newId, layerId: activeLayerId, position: drop.world, order });
|
|
285
|
+
// Centre the element on the drop point regardless of how the factory anchored
|
|
286
|
+
// it at `position`.
|
|
287
|
+
const wb = getElementWorldBounds(built);
|
|
288
|
+
const shape = {
|
|
289
|
+
...built,
|
|
290
|
+
position: {
|
|
291
|
+
x: built.position.x + (drop.world.x - (wb.x + wb.width / 2)),
|
|
292
|
+
y: built.position.y + (drop.world.y - (wb.y + wb.height / 2)),
|
|
293
|
+
},
|
|
294
|
+
};
|
|
295
|
+
const added = addElement(scene, shape);
|
|
296
|
+
const upd = updateLink(added.scene, drop.linkId, (e) => ({
|
|
297
|
+
...e,
|
|
298
|
+
[drop.side]: { kind: "floating", elementId: newId },
|
|
299
|
+
}));
|
|
300
|
+
return { scene: upd.scene, addPatch: added.patch, linkPatch: upd.patch };
|
|
301
|
+
};
|
|
111
302
|
//# sourceMappingURL=placement.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"placement.js","sourceRoot":"","sources":["../../../src/editor/public/placement.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"placement.js","sourceRoot":"","sources":["../../../src/editor/public/placement.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Scene, type Patch, type TextStyle } from "@oh-just-another/scene";
|
|
1
|
+
import { type Scene, type Element, type Patch, type TextStyle } from "@oh-just-another/scene";
|
|
2
2
|
import type { LinkId, LayerId, ElementId, Vec2 } from "@oh-just-another/types";
|
|
3
3
|
import * as Selection from "../../selection.js";
|
|
4
4
|
/**
|
|
@@ -57,6 +57,18 @@ export declare const computeUpdateStyle: (scene: Scene, ids: Iterable<ElementId>
|
|
|
57
57
|
readonly scene: Scene;
|
|
58
58
|
readonly patch: Patch;
|
|
59
59
|
} | null;
|
|
60
|
+
/**
|
|
61
|
+
* Apply a partial {@link TextStyle} overlay to the character range
|
|
62
|
+
* `[from, to)` of a single text element, producing (or updating) its styled
|
|
63
|
+
* runs. Delegates the run splitting/merging to the pure `applyStyleToRange`
|
|
64
|
+
* in `@oh-just-another/scene`; here we only wrap it as a scene update + patch.
|
|
65
|
+
* Returns `null` when `id` is missing, not a text shape, or the operation is
|
|
66
|
+
* a no-op (e.g. an empty range or unchanged runs).
|
|
67
|
+
*/
|
|
68
|
+
export declare const computeApplyTextRunStyle: (scene: Scene, id: ElementId, from: number, to: number, partial: Partial<TextStyle>) => {
|
|
69
|
+
readonly scene: Scene;
|
|
70
|
+
readonly patch: Patch;
|
|
71
|
+
} | null;
|
|
60
72
|
/**
|
|
61
73
|
* Merge non-style text properties (`fontSize`, `fontFamily`,
|
|
62
74
|
* `maxWidth`) into every selected text shape. Non-text shapes in `ids`
|
|
@@ -71,8 +83,30 @@ export declare const computeUpdateTextProps: (scene: Scene, ids: Iterable<Elemen
|
|
|
71
83
|
readonly scene: Scene;
|
|
72
84
|
readonly patch: Patch;
|
|
73
85
|
} | null;
|
|
86
|
+
/**
|
|
87
|
+
* Pure: step every selected text shape's font size up or down by the
|
|
88
|
+
* multiplicative {@link TEXT_FONT_SIZE_STEP} (at least ±1 px so small sizes
|
|
89
|
+
* still move), clamped to the usable range. Each shape steps from its own
|
|
90
|
+
* size, so a mixed selection keeps its relative sizing. One patch (batch for
|
|
91
|
+
* 2+). `null` when nothing selected is text or every size is already at the
|
|
92
|
+
* clamp.
|
|
93
|
+
*/
|
|
94
|
+
export declare const computeAdjustFontSize: (scene: Scene, ids: Iterable<ElementId>, direction: "increase" | "decrease") => {
|
|
95
|
+
readonly scene: Scene;
|
|
96
|
+
readonly patch: Patch;
|
|
97
|
+
} | null;
|
|
74
98
|
/** Human-readable description for the live-region announce after a nudge. */
|
|
75
99
|
export declare const describeNudge: (delta: Vec2, count: number) => string;
|
|
76
100
|
/** Compose a selection from a freshly-created id list. */
|
|
77
101
|
export declare const selectionFromNewIds: (ids: readonly ElementId[]) => Selection.Selection;
|
|
102
|
+
/**
|
|
103
|
+
* Spatial-keyboard navigation: the nearest top-level interactable element to
|
|
104
|
+
* `refCenter` in `direction`, scored by distance along the axis plus a 45°-cone
|
|
105
|
+
* penalty (so a shape roughly in line wins over a nearer one off to the side).
|
|
106
|
+
* Already-selected and non-interactable shapes are skipped. `null` when nothing
|
|
107
|
+
* lies in that half-plane.
|
|
108
|
+
*/
|
|
109
|
+
export declare const findClosestInDirection: (scene: Scene, selected: {
|
|
110
|
+
has: (id: ElementId) => boolean;
|
|
111
|
+
}, direction: "left" | "right" | "up" | "down", refCenter: Vec2, isInteractable: (s: Element) => boolean) => ElementId | null;
|
|
78
112
|
//# sourceMappingURL=selection-ops.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selection-ops.d.ts","sourceRoot":"","sources":["../../../src/editor/public/selection-ops.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"selection-ops.d.ts","sourceRoot":"","sources":["../../../src/editor/public/selection-ops.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { addElement, getElement, orderForTop, removeLink, removeElement, updateElement, } from "@oh-just-another/scene";
|
|
1
|
+
import { addElement, applyStyleToRange, getElement, getElementWorldBounds, isText, orderForTop, removeLink, removeElement, updateElement, } from "@oh-just-another/scene";
|
|
2
2
|
import { elementId as castElementId } from "@oh-just-another/types";
|
|
3
3
|
import * as Selection from "../../selection.js";
|
|
4
|
+
import { TEXT_FONT_SIZE_STEP, TEXT_MAX_FONT_SIZE, TEXT_RESIZE_MIN_FONT_SIZE, } from "../../constants.js";
|
|
4
5
|
/**
|
|
5
6
|
* Nudge every selected shape (plus descendants) by `delta`, skipping
|
|
6
7
|
* shapes on locked layers. Returns the next scene + patches + count of
|
|
@@ -171,6 +172,24 @@ export const computeUpdateStyle = (scene, ids, partial) => {
|
|
|
171
172
|
patch: patches.length === 1 && firstPatch !== undefined ? firstPatch : { kind: "batch", patches },
|
|
172
173
|
};
|
|
173
174
|
};
|
|
175
|
+
/**
|
|
176
|
+
* Apply a partial {@link TextStyle} overlay to the character range
|
|
177
|
+
* `[from, to)` of a single text element, producing (or updating) its styled
|
|
178
|
+
* runs. Delegates the run splitting/merging to the pure `applyStyleToRange`
|
|
179
|
+
* in `@oh-just-another/scene`; here we only wrap it as a scene update + patch.
|
|
180
|
+
* Returns `null` when `id` is missing, not a text shape, or the operation is
|
|
181
|
+
* a no-op (e.g. an empty range or unchanged runs).
|
|
182
|
+
*/
|
|
183
|
+
export const computeApplyTextRunStyle = (scene, id, from, to, partial) => {
|
|
184
|
+
const el = getElement(scene, id);
|
|
185
|
+
if (el === undefined || !isText(el))
|
|
186
|
+
return null;
|
|
187
|
+
const next = applyStyleToRange(el, from, to, partial);
|
|
188
|
+
if (next === el)
|
|
189
|
+
return null;
|
|
190
|
+
const r = updateElement(scene, id, () => next);
|
|
191
|
+
return { scene: r.scene, patch: r.patch };
|
|
192
|
+
};
|
|
174
193
|
/**
|
|
175
194
|
* Merge non-style text properties (`fontSize`, `fontFamily`,
|
|
176
195
|
* `maxWidth`) into every selected text shape. Non-text shapes in `ids`
|
|
@@ -180,7 +199,8 @@ export const computeUpdateStyle = (scene, ids, partial) => {
|
|
|
180
199
|
export const computeUpdateTextProps = (scene, ids, partial) => {
|
|
181
200
|
const targetIds = [];
|
|
182
201
|
for (const id of ids) {
|
|
183
|
-
|
|
202
|
+
const el = getElement(scene, id);
|
|
203
|
+
if (el !== undefined && isText(el))
|
|
184
204
|
targetIds.push(id);
|
|
185
205
|
}
|
|
186
206
|
if (targetIds.length === 0)
|
|
@@ -198,6 +218,40 @@ export const computeUpdateTextProps = (scene, ids, partial) => {
|
|
|
198
218
|
patch: patches.length === 1 && firstPatch !== undefined ? firstPatch : { kind: "batch", patches },
|
|
199
219
|
};
|
|
200
220
|
};
|
|
221
|
+
/**
|
|
222
|
+
* Pure: step every selected text shape's font size up or down by the
|
|
223
|
+
* multiplicative {@link TEXT_FONT_SIZE_STEP} (at least ±1 px so small sizes
|
|
224
|
+
* still move), clamped to the usable range. Each shape steps from its own
|
|
225
|
+
* size, so a mixed selection keeps its relative sizing. One patch (batch for
|
|
226
|
+
* 2+). `null` when nothing selected is text or every size is already at the
|
|
227
|
+
* clamp.
|
|
228
|
+
*/
|
|
229
|
+
export const computeAdjustFontSize = (scene, ids, direction) => {
|
|
230
|
+
const up = direction === "increase";
|
|
231
|
+
const factor = up ? TEXT_FONT_SIZE_STEP : 1 / TEXT_FONT_SIZE_STEP;
|
|
232
|
+
let s = scene;
|
|
233
|
+
const patches = [];
|
|
234
|
+
for (const id of ids) {
|
|
235
|
+
const el = getElement(s, id);
|
|
236
|
+
if (el === undefined || !isText(el))
|
|
237
|
+
continue;
|
|
238
|
+
const scaled = Math.round(el.fontSize * factor);
|
|
239
|
+
const stepped = up ? Math.max(el.fontSize + 1, scaled) : Math.min(el.fontSize - 1, scaled);
|
|
240
|
+
const next = Math.min(TEXT_MAX_FONT_SIZE, Math.max(TEXT_RESIZE_MIN_FONT_SIZE, stepped));
|
|
241
|
+
if (next === el.fontSize)
|
|
242
|
+
continue;
|
|
243
|
+
const r = updateElement(s, id, (sh) => ({ ...sh, fontSize: next }));
|
|
244
|
+
s = r.scene;
|
|
245
|
+
patches.push(r.patch);
|
|
246
|
+
}
|
|
247
|
+
const firstPatch = patches[0];
|
|
248
|
+
if (firstPatch === undefined)
|
|
249
|
+
return null;
|
|
250
|
+
return {
|
|
251
|
+
scene: s,
|
|
252
|
+
patch: patches.length === 1 ? firstPatch : { kind: "batch", patches },
|
|
253
|
+
};
|
|
254
|
+
};
|
|
201
255
|
/** Human-readable description for the live-region announce after a nudge. */
|
|
202
256
|
export const describeNudge = (delta, count) => {
|
|
203
257
|
const parts = [];
|
|
@@ -219,4 +273,45 @@ export const selectionFromNewIds = (ids) => {
|
|
|
219
273
|
next = Selection.add(next, id);
|
|
220
274
|
return next;
|
|
221
275
|
};
|
|
276
|
+
/**
|
|
277
|
+
* Spatial-keyboard navigation: the nearest top-level interactable element to
|
|
278
|
+
* `refCenter` in `direction`, scored by distance along the axis plus a 45°-cone
|
|
279
|
+
* penalty (so a shape roughly in line wins over a nearer one off to the side).
|
|
280
|
+
* Already-selected and non-interactable shapes are skipped. `null` when nothing
|
|
281
|
+
* lies in that half-plane.
|
|
282
|
+
*/
|
|
283
|
+
export const findClosestInDirection = (scene, selected, direction, refCenter, isInteractable) => {
|
|
284
|
+
const dv = direction === "left"
|
|
285
|
+
? { x: -1, y: 0 }
|
|
286
|
+
: direction === "right"
|
|
287
|
+
? { x: 1, y: 0 }
|
|
288
|
+
: direction === "up"
|
|
289
|
+
? { x: 0, y: -1 }
|
|
290
|
+
: { x: 0, y: 1 };
|
|
291
|
+
let best = null;
|
|
292
|
+
let bestScore = Infinity;
|
|
293
|
+
for (const s of scene.elements.values()) {
|
|
294
|
+
if (s.parentId !== undefined)
|
|
295
|
+
continue; // top-level shapes only
|
|
296
|
+
if (selected.has(s.id))
|
|
297
|
+
continue;
|
|
298
|
+
if (!isInteractable(s))
|
|
299
|
+
continue;
|
|
300
|
+
const b = getElementWorldBounds(s);
|
|
301
|
+
const cx = b.x + b.width / 2 - refCenter.x;
|
|
302
|
+
const cy = b.y + b.height / 2 - refCenter.y;
|
|
303
|
+
const along = cx * dv.x + cy * dv.y;
|
|
304
|
+
if (along <= 0)
|
|
305
|
+
continue; // not in the direction's half-plane
|
|
306
|
+
const perp = Math.abs(cx * dv.y - cy * dv.x);
|
|
307
|
+
if (perp > along)
|
|
308
|
+
continue; // outside the 45° cone
|
|
309
|
+
const score = along + perp;
|
|
310
|
+
if (score < bestScore) {
|
|
311
|
+
bestScore = score;
|
|
312
|
+
best = s.id;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return best;
|
|
316
|
+
};
|
|
222
317
|
//# sourceMappingURL=selection-ops.js.map
|