@neta-art/cohub 8.23.0 → 9.0.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/dist/board/animation.d.ts +57 -181
- package/dist/board/animation.js +374 -220
- package/dist/board/core/arrow-geometry.d.ts +33 -18
- package/dist/board/core/arrow-geometry.js +283 -52
- package/dist/board/core/draw-geometry.d.ts +22 -36
- package/dist/board/core/draw-geometry.js +148 -85
- package/dist/board/core/export-assets.d.ts +3 -6
- package/dist/board/core/export-assets.js +0 -2
- package/dist/board/core/export-plan.d.ts +12 -63
- package/dist/board/core/export-plan.js +55 -94
- package/dist/board/core/palette.d.ts +4 -21
- package/dist/board/core/palette.js +8 -13
- package/dist/board/core/scene.d.ts +33 -0
- package/dist/board/core/scene.js +302 -0
- package/dist/board/core/shape-definition.d.ts +12 -24
- package/dist/board/core/shape-definition.js +0 -19
- package/dist/board/core/shape-types.d.ts +6 -120
- package/dist/board/core/shape-types.js +5 -5
- package/dist/board/core/text-metrics.d.ts +8 -11
- package/dist/board/core/text-metrics.js +5 -34
- package/dist/board/core/tool-styles.d.ts +6 -16
- package/dist/board/core/tool-styles.js +17 -25
- package/dist/board/export/index.d.ts +10 -17
- package/dist/board/export/index.js +22 -21
- package/dist/board/export/scene.d.ts +10 -16
- package/dist/board/export/scene.js +17 -30
- package/dist/board/geometry.d.ts +27 -56
- package/dist/board/geometry.js +7 -67
- package/dist/board/headless/index.d.ts +7 -27
- package/dist/board/headless/index.js +20 -19
- package/dist/board/headless/sketch.d.ts +19 -0
- package/dist/board/headless/sketch.js +146 -0
- package/dist/board/image-key.d.ts +2 -12
- package/dist/board/image-key.js +3 -13
- package/dist/board/index.d.ts +18 -20
- package/dist/board/index.js +17 -17
- package/dist/board/media-playback.d.ts +3 -6
- package/dist/board/media-playback.js +6 -6
- package/dist/board/presets.d.ts +150 -0
- package/dist/board/presets.js +226 -0
- package/dist/board/render/board-background.d.ts +5 -3
- package/dist/board/render/board-background.js +8 -7
- package/dist/board/render/clip.d.ts +14 -0
- package/dist/board/render/clip.js +47 -0
- package/dist/board/render/index.d.ts +8 -5
- package/dist/board/render/index.js +7 -4
- package/dist/board/render/media-interaction.d.ts +4 -5
- package/dist/board/render/media-interaction.js +1 -2
- package/dist/board/render/palette.d.ts +6 -2
- package/dist/board/render/palette.js +7 -1
- package/dist/board/render/renderers/arrow-card-renderer.js +69 -71
- package/dist/board/render/renderers/audio-card-renderer.js +3 -3
- package/dist/board/render/renderers/base-card-renderer.d.ts +6 -17
- package/dist/board/render/renderers/base-card-renderer.js +1 -24
- package/dist/board/render/renderers/board-renderer-registry.d.ts +20 -50
- package/dist/board/render/renderers/board-renderer-registry.js +6 -7
- package/dist/board/render/renderers/draw-card-renderer.js +89 -56
- package/dist/board/render/renderers/effect-card-renderer.d.ts +6 -0
- package/dist/board/render/renderers/effect-card-renderer.js +197 -0
- package/dist/board/render/renderers/far-plate.d.ts +4 -21
- package/dist/board/render/renderers/far-plate.js +15 -34
- package/dist/board/render/renderers/file-card-renderer.d.ts +4 -25
- package/dist/board/render/renderers/file-card-renderer.js +8 -58
- package/dist/board/render/renderers/frame-card-renderer.js +28 -28
- package/dist/board/render/renderers/image-card-renderer.d.ts +4 -3
- package/dist/board/render/renderers/image-card-renderer.js +0 -9
- package/dist/board/render/renderers/shape-card-renderer.d.ts +9 -0
- package/dist/board/render/renderers/shape-card-renderer.js +240 -0
- package/dist/board/render/renderers/sketch-card-renderer.d.ts +5 -0
- package/dist/board/render/renderers/sketch-card-renderer.js +98 -0
- package/dist/board/render/renderers/task-card-renderer.d.ts +0 -1
- package/dist/board/render/renderers/task-card-renderer.js +14 -16
- package/dist/board/render/renderers/text-card-renderer.d.ts +1 -3
- package/dist/board/render/renderers/text-card-renderer.js +56 -46
- package/dist/board/render/renderers/unknown-card-renderer.js +4 -10
- package/dist/board/render/renderers/video-card-renderer.d.ts +4 -2
- package/dist/board/render/renderers/video-card-renderer.js +2 -1
- package/dist/board/render/sketch-host.d.ts +14 -0
- package/dist/board/render/sketch-host.js +216 -0
- package/dist/board/render/stroke.d.ts +12 -0
- package/dist/board/render/stroke.js +90 -0
- package/dist/board/render/text-measurement.d.ts +6 -26
- package/dist/board/render/text-measurement.js +11 -30
- package/dist/board/replay.d.ts +6 -31
- package/dist/board/replay.js +45 -203
- package/dist/board/runtime/board-player.d.ts +24 -0
- package/dist/board/runtime/board-player.js +161 -0
- package/dist/board/task.d.ts +2 -10
- package/dist/board/task.js +1 -10
- package/dist/chunks/environment.d.ts +2296 -3864
- package/dist/chunks/host-bridge.d.ts +253 -0
- package/dist/chunks/http.d.ts +238 -58
- package/dist/chunks/http.js +1061 -1034
- package/dist/chunks/transport.js +113 -59
- package/dist/chunks/websocket.d.ts +1 -1
- package/dist/chunks/websocket.js +1 -1
- package/dist/host-bridge.d.ts +54 -0
- package/dist/host-bridge.js +322 -0
- package/dist/http.d.ts +3 -3
- package/dist/index.d.ts +76 -193
- package/dist/index.js +2037 -1191
- package/dist/protocol/dist/board-constants.d.ts +1 -29
- package/dist/protocol/dist/board-constants.js +2 -115
- package/dist/protocol/dist/board-layout.d.ts +59 -0
- package/dist/protocol/dist/board-layout.js +482 -0
- package/dist/protocol/dist/board-model.d.ts +2052 -0
- package/dist/protocol/dist/board-model.js +592 -0
- package/dist/protocol/dist/board-patch.d.ts +86 -0
- package/dist/protocol/dist/board-patch.js +734 -0
- package/dist/protocol/dist/board-schema.d.ts +33 -0
- package/dist/protocol/dist/board-schema.js +59 -0
- package/dist/protocol/dist/board-upgrade.d.ts +1 -0
- package/dist/protocol/dist/board-url.d.ts +1 -3
- package/dist/protocol/dist/board-url.js +2 -2
- package/dist/protocol/dist/board.d.ts +37 -232
- package/dist/protocol/dist/board.js +62 -160
- package/dist/protocol/dist/display/actions.d.ts +1 -0
- package/dist/protocol/dist/display/index.d.ts +2 -0
- package/dist/protocol/dist/index.d.ts +11 -12
- package/dist/protocol/dist/model/metrics.d.ts +2 -0
- package/dist/protocol/dist/model/session.d.ts +2 -1
- package/dist/protocol/dist/realtime/types.d.ts +2 -2
- package/dist/protocol/dist/runtime/index.d.ts +1 -0
- package/dist/space-picker.d.ts +1 -0
- package/dist/space-picker.js +1 -0
- package/dist/types.d.ts +2 -5
- package/package.json +9 -1
- package/dist/board/core/connections.d.ts +0 -108
- package/dist/board/core/connections.js +0 -455
- package/dist/board/mutation.d.ts +0 -6
- package/dist/board/mutation.js +0 -14
- package/dist/board/render/connection-layer.d.ts +0 -53
- package/dist/board/render/connection-layer.js +0 -375
- package/dist/board/render/renderers/geo-card-renderer.d.ts +0 -5
- package/dist/board/render/renderers/geo-card-renderer.js +0 -127
- package/dist/board/semantic-document.d.ts +0 -37
- package/dist/board/semantic-document.js +0 -288
- package/dist/board/semantic-mutation.d.ts +0 -10
- package/dist/board/semantic-mutation.js +0 -209
- package/dist/protocol/dist/board-animation.js +0 -34
- package/dist/protocol/dist/board-authoring.d.ts +0 -1326
- package/dist/protocol/dist/board-authoring.js +0 -302
- package/dist/protocol/dist/board-capability-registry.d.ts +0 -2
- package/dist/protocol/dist/board-capability-registry.js +0 -123
- package/dist/protocol/dist/board-codec.d.ts +0 -3
- package/dist/protocol/dist/board-codec.js +0 -383
- package/dist/protocol/dist/board-composition.d.ts +0 -383
- package/dist/protocol/dist/board-composition.js +0 -310
- package/dist/protocol/dist/board-connection.d.ts +0 -317
- package/dist/protocol/dist/board-connection.js +0 -219
- package/dist/protocol/dist/board-document.d.ts +0 -1566
- package/dist/protocol/dist/board-document.js +0 -456
- package/dist/protocol/dist/board-effect.d.ts +0 -96
- package/dist/protocol/dist/board-effect.js +0 -54
- package/dist/protocol/dist/board-geometry.d.ts +0 -15
- package/dist/protocol/dist/board-geometry.js +0 -137
- package/dist/protocol/dist/board-node.d.ts +0 -8
- package/dist/protocol/dist/board-node.js +0 -252
- /package/dist/protocol/dist/{board-animation.d.ts → host-bridge.d.ts} +0 -0
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
//#region src/board/core/palette.ts
|
|
2
|
-
/**
|
|
3
|
-
* Label color fallbacks mirror `--board-color-*-label`, which every theme maps
|
|
4
|
-
* to `--text-primary`: labels sit on a *translucent* fill over the page, not on
|
|
5
|
-
* a saturated swatch, so a tinted label would be dark-on-dark. Keeping these in
|
|
6
|
-
* step with `theme.css` is what makes a headless export match the screen.
|
|
7
|
-
*/
|
|
8
2
|
const LABEL_DARK = 16053492;
|
|
9
3
|
const LABEL_LIGHT = 1579035;
|
|
10
4
|
const BOARD_COLORS = [
|
|
@@ -143,24 +137,25 @@ function isBoardColorId(value) {
|
|
|
143
137
|
function boardColorCssVar(id, part) {
|
|
144
138
|
return `--board-color-${id}-${part}`;
|
|
145
139
|
}
|
|
146
|
-
/** Resolve a color id to concrete values for a color mode. Unknown → brand. */
|
|
147
140
|
function resolveBoardColor(id, mode) {
|
|
148
141
|
return ((isBoardColorId(id) ? COLOR_INDEX.get(id) : void 0) ?? COLOR_INDEX.get("brand"))[mode];
|
|
149
142
|
}
|
|
150
|
-
/** Build a full shape-color table from hard-coded fallbacks (export / SSR). */
|
|
151
143
|
function buildFallbackShapeColors(mode) {
|
|
152
144
|
const out = {};
|
|
153
145
|
for (const entry of BOARD_COLORS) out[entry.id] = entry[mode];
|
|
154
146
|
return out;
|
|
155
147
|
}
|
|
156
|
-
/**
|
|
157
|
-
* Pick a concrete color from a live shape-color table, falling back to the
|
|
158
|
-
* default brand entry when the id is unknown.
|
|
159
|
-
*/
|
|
160
148
|
function pickBoardColor(colors, id, mode = "dark") {
|
|
161
149
|
if (colors && isBoardColorId(id) && colors[id]) return colors[id];
|
|
162
150
|
if (colors) return colors[DEFAULT_BOARD_COLOR];
|
|
163
151
|
return resolveBoardColor(id, mode);
|
|
164
152
|
}
|
|
153
|
+
function resolveItemColor(color, fallback, colors, mode, parseCss, part = "stroke") {
|
|
154
|
+
const value = typeof color === "object" && color ? color[mode] : color;
|
|
155
|
+
if (value === void 0) return pickBoardColor(colors, fallback, mode)[part];
|
|
156
|
+
const token = value.trim().toLowerCase();
|
|
157
|
+
if (isBoardColorId(token)) return pickBoardColor(colors, token, mode)[part];
|
|
158
|
+
return parseCss(value) ?? pickBoardColor(colors, fallback, mode)[part];
|
|
159
|
+
}
|
|
165
160
|
//#endregion
|
|
166
|
-
export { BOARD_COLORS, DEFAULT_BOARD_COLOR, boardColorCssVar, buildFallbackShapeColors, isBoardColorId, pickBoardColor, resolveBoardColor };
|
|
161
|
+
export { BOARD_COLORS, DEFAULT_BOARD_COLOR, boardColorCssVar, buildFallbackShapeColors, isBoardColorId, pickBoardColor, resolveBoardColor, resolveItemColor };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { BoardDocument, BoardItem } from "../../protocol/dist/board-model.js";
|
|
2
|
+
import { BoardFrame, BoardItemLookup, BoardLayout, BoardMatrix, BoardRect } from "../../protocol/dist/board-layout.js";
|
|
3
|
+
import "../../protocol/dist/index.js";
|
|
4
|
+
//#region src/board/core/scene.d.ts
|
|
5
|
+
type SceneItem<T extends BoardItem = BoardItem> = T & {
|
|
6
|
+
readonly id: string;
|
|
7
|
+
readonly frame: BoardFrame;
|
|
8
|
+
};
|
|
9
|
+
type BoardSceneItem = SceneItem;
|
|
10
|
+
type BoardScene = {
|
|
11
|
+
readonly items: readonly BoardSceneItem[];
|
|
12
|
+
get(id: string): BoardSceneItem | undefined;
|
|
13
|
+
indexOf(id: string): number;
|
|
14
|
+
readonly layout: BoardLayout;
|
|
15
|
+
children(id: string | undefined): readonly string[];
|
|
16
|
+
descendants(id: string): string[];
|
|
17
|
+
binders(id: string): readonly string[];
|
|
18
|
+
opacity(id: string): number;
|
|
19
|
+
};
|
|
20
|
+
declare function orderBoardItems(items: Readonly<Record<string, BoardItem>>): string[];
|
|
21
|
+
declare function buildBoardScene(document: BoardDocument, previous?: BoardScene | null): BoardScene;
|
|
22
|
+
declare function refreshBoardScene(previous: BoardScene, lookup: BoardItemLookup, ids: Iterable<string>): BoardScene;
|
|
23
|
+
declare function toSceneItem(id: string, item: BoardItem, layout: BoardLayout): BoardSceneItem;
|
|
24
|
+
declare function sceneItemToItem(scene: BoardSceneItem | (BoardItem & {
|
|
25
|
+
id: string;
|
|
26
|
+
frame?: BoardFrame;
|
|
27
|
+
}), layout: BoardLayout): BoardItem;
|
|
28
|
+
declare function placeItem(item: BoardItem, frame: BoardFrame, parent: BoardMatrix, box: BoardRect): BoardItem;
|
|
29
|
+
declare function sceneItemsToRecord(items: readonly (BoardSceneItem | (BoardItem & {
|
|
30
|
+
id: string;
|
|
31
|
+
}))[], layout: BoardLayout): Record<string, BoardItem>;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { BoardScene, BoardSceneItem, SceneItem, buildBoardScene, orderBoardItems, placeItem, refreshBoardScene, sceneItemToItem, sceneItemsToRecord, toSceneItem };
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { IDENTITY_MATRIX, applyMatrix, arrowBindings, clampBoardFontSize, createBoardLayout, drawPointsBounds, invertMatrix, layoutBoardText, scaleVector } from "../../protocol/dist/board-layout.js";
|
|
2
|
+
//#region src/board/core/scene.ts
|
|
3
|
+
const EPSILON = 1e-6;
|
|
4
|
+
function stripScene(item) {
|
|
5
|
+
if (!("frame" in item) && !("id" in item)) return item;
|
|
6
|
+
const { id: _id, frame: _frame, ...rest } = item;
|
|
7
|
+
return rest;
|
|
8
|
+
}
|
|
9
|
+
function orderBoardItems(items) {
|
|
10
|
+
const children = /* @__PURE__ */ new Map();
|
|
11
|
+
for (const [id, item] of Object.entries(items)) {
|
|
12
|
+
const parent = item.parent && items[item.parent] && item.parent !== id ? item.parent : "";
|
|
13
|
+
const list = children.get(parent) ?? [];
|
|
14
|
+
list.push(id);
|
|
15
|
+
children.set(parent, list);
|
|
16
|
+
}
|
|
17
|
+
const compare = (a, b) => (items[a]?.z ?? 0) - (items[b]?.z ?? 0) || (a < b ? -1 : a > b ? 1 : 0);
|
|
18
|
+
for (const list of children.values()) list.sort(compare);
|
|
19
|
+
const order = [];
|
|
20
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21
|
+
const visit = (id) => {
|
|
22
|
+
if (seen.has(id)) return;
|
|
23
|
+
seen.add(id);
|
|
24
|
+
order.push(id);
|
|
25
|
+
for (const child of children.get(id) ?? []) visit(child);
|
|
26
|
+
};
|
|
27
|
+
for (const id of children.get("") ?? []) visit(id);
|
|
28
|
+
for (const id of Object.keys(items)) visit(id);
|
|
29
|
+
return order;
|
|
30
|
+
}
|
|
31
|
+
function buildBoardScene(document, previous) {
|
|
32
|
+
const items = document.items;
|
|
33
|
+
const children = /* @__PURE__ */ new Map();
|
|
34
|
+
const binders = /* @__PURE__ */ new Map();
|
|
35
|
+
for (const [id, item] of Object.entries(items)) {
|
|
36
|
+
const parent = item.parent && items[item.parent] ? item.parent : "";
|
|
37
|
+
const list = children.get(parent) ?? [];
|
|
38
|
+
list.push(id);
|
|
39
|
+
children.set(parent, list);
|
|
40
|
+
for (const bound of arrowBindings(item)) binders.set(bound, [...binders.get(bound) ?? [], id]);
|
|
41
|
+
}
|
|
42
|
+
const layout = createBoardLayout((id) => items[id], (id) => [...children.get(id) ?? [], ...binders.get(id) ?? []]);
|
|
43
|
+
const stable = /* @__PURE__ */ new Map();
|
|
44
|
+
const isStable = (id, depth = 0) => {
|
|
45
|
+
const known = stable.get(id);
|
|
46
|
+
if (known !== void 0) return known;
|
|
47
|
+
const item = items[id];
|
|
48
|
+
const before = previous?.get(id);
|
|
49
|
+
let result = Boolean(item && before && stripSceneSource(before) === item) && depth < 64;
|
|
50
|
+
if (result && item?.parent && items[item.parent]) result = isStable(item.parent, depth + 1);
|
|
51
|
+
if (result && item) {
|
|
52
|
+
for (const bound of arrowBindings(item)) if (items[bound] && !isStable(bound, depth + 1)) result = false;
|
|
53
|
+
}
|
|
54
|
+
stable.set(id, result);
|
|
55
|
+
return result;
|
|
56
|
+
};
|
|
57
|
+
const ordered = orderBoardItems(items);
|
|
58
|
+
const sceneItems = [];
|
|
59
|
+
const byId = /* @__PURE__ */ new Map();
|
|
60
|
+
const indexById = /* @__PURE__ */ new Map();
|
|
61
|
+
for (const id of ordered) {
|
|
62
|
+
const item = items[id];
|
|
63
|
+
const scene = (isStable(id) ? previous?.get(id) : void 0) ?? toSceneItem(id, item, layout);
|
|
64
|
+
indexById.set(id, sceneItems.length);
|
|
65
|
+
sceneItems.push(scene);
|
|
66
|
+
byId.set(id, scene);
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
items: sceneItems,
|
|
70
|
+
get: (id) => byId.get(id),
|
|
71
|
+
indexOf: (id) => indexById.get(id) ?? -1,
|
|
72
|
+
layout,
|
|
73
|
+
children: (id) => children.get(id ?? "") ?? [],
|
|
74
|
+
descendants: (id) => {
|
|
75
|
+
const result = [];
|
|
76
|
+
const seen = /* @__PURE__ */ new Set([id]);
|
|
77
|
+
const stack = [...children.get(id) ?? []];
|
|
78
|
+
while (stack.length) {
|
|
79
|
+
const next = stack.pop();
|
|
80
|
+
if (seen.has(next)) continue;
|
|
81
|
+
seen.add(next);
|
|
82
|
+
result.push(next);
|
|
83
|
+
stack.push(...children.get(next) ?? []);
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
},
|
|
87
|
+
binders: (id) => binders.get(id) ?? [],
|
|
88
|
+
opacity: (id) => cumulativeOpacity((key) => items[key], id)
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function cumulativeOpacity(lookup, id) {
|
|
92
|
+
let value = 1;
|
|
93
|
+
let cursor = id;
|
|
94
|
+
for (let depth = 0; cursor && depth < 64; depth += 1) {
|
|
95
|
+
const item = lookup(cursor);
|
|
96
|
+
if (!item) break;
|
|
97
|
+
value *= item.opacity;
|
|
98
|
+
cursor = item.parent;
|
|
99
|
+
}
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
function refreshBoardScene(previous, lookup, ids) {
|
|
103
|
+
const changedIds = [...ids];
|
|
104
|
+
if (changedIds.length === 0) return previous;
|
|
105
|
+
const dependents = (id) => [...previous.children(id), ...previous.binders(id)];
|
|
106
|
+
const layout = previous.layout;
|
|
107
|
+
layout.setLookup(lookup);
|
|
108
|
+
layout.invalidate(changedIds);
|
|
109
|
+
const affected = /* @__PURE__ */ new Set();
|
|
110
|
+
const stack = [...changedIds];
|
|
111
|
+
while (stack.length) {
|
|
112
|
+
const id = stack.pop();
|
|
113
|
+
if (affected.has(id) || !lookup(id)) continue;
|
|
114
|
+
affected.add(id);
|
|
115
|
+
stack.push(...dependents(id));
|
|
116
|
+
}
|
|
117
|
+
if (affected.size === 0) return previous;
|
|
118
|
+
const sceneItems = previous.items.slice();
|
|
119
|
+
const chain = refreshed.get(previous);
|
|
120
|
+
const base = chain?.base ?? previous;
|
|
121
|
+
const overrides = new Map(chain?.overrides);
|
|
122
|
+
for (const id of affected) {
|
|
123
|
+
const index = previous.indexOf(id);
|
|
124
|
+
const scene = toSceneItem(id, lookup(id), layout);
|
|
125
|
+
overrides.set(id, scene);
|
|
126
|
+
if (index >= 0) sceneItems[index] = scene;
|
|
127
|
+
}
|
|
128
|
+
const scene = {
|
|
129
|
+
...base,
|
|
130
|
+
items: sceneItems,
|
|
131
|
+
get: (id) => overrides.get(id) ?? base.get(id),
|
|
132
|
+
layout,
|
|
133
|
+
opacity: (id) => cumulativeOpacity(lookup, id)
|
|
134
|
+
};
|
|
135
|
+
refreshed.set(scene, {
|
|
136
|
+
base,
|
|
137
|
+
overrides
|
|
138
|
+
});
|
|
139
|
+
return scene;
|
|
140
|
+
}
|
|
141
|
+
const refreshed = /* @__PURE__ */ new WeakMap();
|
|
142
|
+
const sources = /* @__PURE__ */ new WeakMap();
|
|
143
|
+
function stripSceneSource(scene) {
|
|
144
|
+
return sources.get(scene);
|
|
145
|
+
}
|
|
146
|
+
function toSceneItem(id, item, layout) {
|
|
147
|
+
const scene = {
|
|
148
|
+
...item,
|
|
149
|
+
id,
|
|
150
|
+
frame: layout.frame(id)
|
|
151
|
+
};
|
|
152
|
+
sources.set(scene, item);
|
|
153
|
+
return scene;
|
|
154
|
+
}
|
|
155
|
+
function sameFrame(a, b) {
|
|
156
|
+
return Math.abs(a.x - b.x) < EPSILON && Math.abs(a.y - b.y) < EPSILON && Math.abs(a.width - b.width) < EPSILON && Math.abs(a.height - b.height) < EPSILON && Math.abs(a.rotation - b.rotation) < EPSILON;
|
|
157
|
+
}
|
|
158
|
+
function sceneItemToItem(scene, layout) {
|
|
159
|
+
const source = sources.get(scene);
|
|
160
|
+
if (source) return source;
|
|
161
|
+
const item = stripScene(scene);
|
|
162
|
+
const frame = scene.frame;
|
|
163
|
+
if (!frame) return item;
|
|
164
|
+
if (layout.has(scene.id) && sameFrame(frame, layout.frame(scene.id))) return item;
|
|
165
|
+
return placeItem(item, frame, item.parent && layout.has(item.parent) ? layout.matrix(item.parent) : IDENTITY_MATRIX, itemBox(item, layout, scene.id));
|
|
166
|
+
}
|
|
167
|
+
function itemBox(item, layout, id) {
|
|
168
|
+
if ("size" in item && item.size) return {
|
|
169
|
+
x: 0,
|
|
170
|
+
y: 0,
|
|
171
|
+
width: item.size.width,
|
|
172
|
+
height: item.size.height
|
|
173
|
+
};
|
|
174
|
+
if (item.type === "text") {
|
|
175
|
+
const text = layoutBoardText(item.props);
|
|
176
|
+
return {
|
|
177
|
+
x: 0,
|
|
178
|
+
y: 0,
|
|
179
|
+
width: text.width,
|
|
180
|
+
height: text.height
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
if (item.type === "draw") return drawPointsBounds(item.props.points, item.style.strokeWidth ?? 4);
|
|
184
|
+
return layout.box(id);
|
|
185
|
+
}
|
|
186
|
+
function placeItem(item, frame, parent, box) {
|
|
187
|
+
const [a, b] = parent;
|
|
188
|
+
const parentScale = Math.hypot(a, b) || 1;
|
|
189
|
+
const parentRotation = Math.atan2(b, a) * 180 / Math.PI;
|
|
190
|
+
const center = applyMatrix(invertMatrix(parent), {
|
|
191
|
+
x: frame.x + frame.width / 2,
|
|
192
|
+
y: frame.y + frame.height / 2
|
|
193
|
+
});
|
|
194
|
+
const scale = scaleVector(item.scale);
|
|
195
|
+
const width = frame.width / parentScale / (Math.abs(scale.x) || 1);
|
|
196
|
+
const height = frame.height / parentScale / (Math.abs(scale.y) || 1);
|
|
197
|
+
if (item.type === "arrow") {
|
|
198
|
+
const currentCenter = {
|
|
199
|
+
x: item.position.x + box.x + box.width / 2,
|
|
200
|
+
y: item.position.y + box.y + box.height / 2
|
|
201
|
+
};
|
|
202
|
+
const dx = center.x - currentCenter.x;
|
|
203
|
+
const dy = center.y - currentCenter.y;
|
|
204
|
+
if (Math.abs(dx) < EPSILON && Math.abs(dy) < EPSILON) return item;
|
|
205
|
+
return {
|
|
206
|
+
...item,
|
|
207
|
+
position: {
|
|
208
|
+
x: item.position.x + dx,
|
|
209
|
+
y: item.position.y + dy
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
let next = item;
|
|
214
|
+
let nextBox = box;
|
|
215
|
+
if (Math.abs(width - box.width) > EPSILON || Math.abs(height - box.height) > EPSILON) {
|
|
216
|
+
if (item.type === "text") {
|
|
217
|
+
const factor = Math.abs(width - box.width) > EPSILON ? width / box.width : height / box.height;
|
|
218
|
+
const props = {
|
|
219
|
+
...item.props,
|
|
220
|
+
fontSize: clampBoardFontSize(item.props.fontSize * factor),
|
|
221
|
+
...item.props.width ? { width: item.props.width * factor } : {}
|
|
222
|
+
};
|
|
223
|
+
next = {
|
|
224
|
+
...item,
|
|
225
|
+
props
|
|
226
|
+
};
|
|
227
|
+
const text = layoutBoardText(props);
|
|
228
|
+
nextBox = {
|
|
229
|
+
x: 0,
|
|
230
|
+
y: 0,
|
|
231
|
+
width: text.width,
|
|
232
|
+
height: text.height
|
|
233
|
+
};
|
|
234
|
+
} else if (item.type === "draw") {
|
|
235
|
+
const sx = width / box.width;
|
|
236
|
+
const sy = height / box.height;
|
|
237
|
+
const points = item.props.points.map((point) => ({
|
|
238
|
+
...point,
|
|
239
|
+
x: box.x + (point.x - box.x) * sx,
|
|
240
|
+
y: box.y + (point.y - box.y) * sy
|
|
241
|
+
}));
|
|
242
|
+
next = {
|
|
243
|
+
...item,
|
|
244
|
+
props: {
|
|
245
|
+
...item.props,
|
|
246
|
+
points
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
nextBox = drawPointsBounds(points, item.style.strokeWidth ?? 4);
|
|
250
|
+
} else if ("size" in item && item.size) {
|
|
251
|
+
next = {
|
|
252
|
+
...item,
|
|
253
|
+
size: {
|
|
254
|
+
width,
|
|
255
|
+
height
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
nextBox = {
|
|
259
|
+
x: 0,
|
|
260
|
+
y: 0,
|
|
261
|
+
width,
|
|
262
|
+
height
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
const rotation = frame.rotation - parentRotation;
|
|
267
|
+
const radians = rotation * Math.PI / 180;
|
|
268
|
+
const origin = {
|
|
269
|
+
x: nextBox.x + item.origin.x * nextBox.width,
|
|
270
|
+
y: nextBox.y + item.origin.y * nextBox.height
|
|
271
|
+
};
|
|
272
|
+
const boxCenter = {
|
|
273
|
+
x: nextBox.x + nextBox.width / 2,
|
|
274
|
+
y: nextBox.y + nextBox.height / 2
|
|
275
|
+
};
|
|
276
|
+
const dx = (boxCenter.x - origin.x) * scale.x;
|
|
277
|
+
const dy = (boxCenter.y - origin.y) * scale.y;
|
|
278
|
+
const rotated = {
|
|
279
|
+
x: dx * Math.cos(radians) - dy * Math.sin(radians),
|
|
280
|
+
y: dx * Math.sin(radians) + dy * Math.cos(radians)
|
|
281
|
+
};
|
|
282
|
+
const position = {
|
|
283
|
+
x: center.x - origin.x - rotated.x,
|
|
284
|
+
y: center.y - origin.y - rotated.y
|
|
285
|
+
};
|
|
286
|
+
return {
|
|
287
|
+
...next,
|
|
288
|
+
position,
|
|
289
|
+
rotation: normalizeDegrees(rotation)
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
function normalizeDegrees(value) {
|
|
293
|
+
const normalized = (value % 360 + 540) % 360 - 180;
|
|
294
|
+
return Math.abs(normalized) < EPSILON ? 0 : Number(normalized.toFixed(6));
|
|
295
|
+
}
|
|
296
|
+
function sceneItemsToRecord(items, layout) {
|
|
297
|
+
const record = {};
|
|
298
|
+
for (const scene of items) record[scene.id] = sceneItemToItem(scene, layout);
|
|
299
|
+
return record;
|
|
300
|
+
}
|
|
301
|
+
//#endregion
|
|
302
|
+
export { buildBoardScene, orderBoardItems, placeItem, refreshBoardScene, sceneItemToItem, sceneItemsToRecord, toSceneItem };
|
|
@@ -1,35 +1,23 @@
|
|
|
1
|
-
import { BoardFrame, BoardItem } from "../../protocol/dist/board-document.js";
|
|
2
1
|
import { Rect, WorldPoint } from "../geometry.js";
|
|
2
|
+
import { BoardSceneItem } from "./scene.js";
|
|
3
3
|
import { ShapeCapabilities, ShapeGeometry, ShapeHandle, ShapeResizeMode } from "./shape-types.js";
|
|
4
4
|
//#region src/board/core/shape-definition.d.ts
|
|
5
5
|
type ShapeDefinition = {
|
|
6
|
-
/** The item type this definition handles. */
|
|
7
6
|
type: string;
|
|
8
7
|
capabilities: ShapeCapabilities;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
/** Interaction handles in the shape's local space. Defaults to none. */
|
|
14
|
-
getHandles?: (item: BoardItem) => ShapeHandle[];
|
|
15
|
-
/**
|
|
16
|
-
* Local-space geometry outline, used for precise hit tests and snapping.
|
|
17
|
-
* Optional; box shapes rely on the frame directly.
|
|
18
|
-
*/
|
|
19
|
-
getGeometry?: (item: BoardItem) => ShapeGeometry;
|
|
8
|
+
getBounds?: (item: BoardSceneItem) => Rect;
|
|
9
|
+
hitTest?: (item: BoardSceneItem, point: WorldPoint) => boolean;
|
|
10
|
+
getHandles?: (item: BoardSceneItem) => ShapeHandle[];
|
|
11
|
+
getGeometry?: (item: BoardSceneItem) => ShapeGeometry;
|
|
20
12
|
};
|
|
21
13
|
declare function registerShapeDefinition(definition: ShapeDefinition): void;
|
|
22
14
|
declare function getShapeDefinition(type: string): ShapeDefinition | undefined;
|
|
23
|
-
/**
|
|
24
|
-
* The generic fallback for unknown shape types: a plain movable/resizable box.
|
|
25
|
-
* This guarantees a shape authored by a newer client is still interactive here.
|
|
26
|
-
*/
|
|
27
15
|
declare const unknownShapeDefinition: ShapeDefinition;
|
|
28
|
-
declare function definitionForItem(item:
|
|
29
|
-
declare function shapeBounds(item:
|
|
30
|
-
declare function shapeHitTest(item:
|
|
31
|
-
declare function shapeHandles(item:
|
|
32
|
-
declare function shapeCapabilities(item:
|
|
33
|
-
declare function shapeResizeMode(item:
|
|
16
|
+
declare function definitionForItem(item: BoardSceneItem): ShapeDefinition;
|
|
17
|
+
declare function shapeBounds(item: BoardSceneItem): Rect;
|
|
18
|
+
declare function shapeHitTest(item: BoardSceneItem, point: WorldPoint): boolean;
|
|
19
|
+
declare function shapeHandles(item: BoardSceneItem): ShapeHandle[];
|
|
20
|
+
declare function shapeCapabilities(item: BoardSceneItem): ShapeCapabilities;
|
|
21
|
+
declare function shapeResizeMode(item: BoardSceneItem): ShapeResizeMode;
|
|
34
22
|
//#endregion
|
|
35
|
-
export {
|
|
23
|
+
export { ShapeDefinition, definitionForItem, getShapeDefinition, registerShapeDefinition, shapeBounds, shapeCapabilities, shapeHandles, shapeHitTest, shapeResizeMode, unknownShapeDefinition };
|
|
@@ -1,20 +1,6 @@
|
|
|
1
|
-
import { isUnknownItem } from "../../protocol/dist/board-document.js";
|
|
2
1
|
import { frameContainsPoint, itemBounds } from "../geometry.js";
|
|
3
2
|
import { resizeModeForCapabilities } from "./shape-types.js";
|
|
4
3
|
//#region src/board/core/shape-definition.ts
|
|
5
|
-
/**
|
|
6
|
-
* ShapeDefinition protocol + registry.
|
|
7
|
-
*
|
|
8
|
-
* A ShapeDefinition describes everything the editor needs to *behave* correctly
|
|
9
|
-
* around a shape — bounds, hit testing, handles, capabilities, snap targets —
|
|
10
|
-
* with no knowledge of how the shape is drawn. The Pixi renderers are a separate
|
|
11
|
-
* concern (board-renderer-registry). This separation is what lets us add a shape
|
|
12
|
-
* by writing one definition + one renderer, and keeps geometry fully unit-testable
|
|
13
|
-
* without a GPU.
|
|
14
|
-
*
|
|
15
|
-
* Definitions are looked up by `item.type`. Unknown types fall back to a generic
|
|
16
|
-
* box definition so unrecognised shapes still select, move and resize.
|
|
17
|
-
*/
|
|
18
4
|
const definitions = /* @__PURE__ */ new Map();
|
|
19
5
|
function registerShapeDefinition(definition) {
|
|
20
6
|
definitions.set(definition.type, definition);
|
|
@@ -22,10 +8,6 @@ function registerShapeDefinition(definition) {
|
|
|
22
8
|
function getShapeDefinition(type) {
|
|
23
9
|
return definitions.get(type);
|
|
24
10
|
}
|
|
25
|
-
/**
|
|
26
|
-
* The generic fallback for unknown shape types: a plain movable/resizable box.
|
|
27
|
-
* This guarantees a shape authored by a newer client is still interactive here.
|
|
28
|
-
*/
|
|
29
11
|
const unknownShapeDefinition = {
|
|
30
12
|
type: "__unknown__",
|
|
31
13
|
capabilities: {
|
|
@@ -40,7 +22,6 @@ const unknownShapeDefinition = {
|
|
|
40
22
|
}
|
|
41
23
|
};
|
|
42
24
|
function definitionForItem(item) {
|
|
43
|
-
if (isUnknownItem(item)) return unknownShapeDefinition;
|
|
44
25
|
return definitions.get(item.type) ?? unknownShapeDefinition;
|
|
45
26
|
}
|
|
46
27
|
function shapeBounds(item) {
|
|
@@ -1,152 +1,38 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { BoardFrame } from "../../protocol/dist/board-
|
|
1
|
+
import { BoardShapeGeometry } from "../../protocol/dist/board-model.js";
|
|
2
|
+
import { BoardFrame } from "../../protocol/dist/board-layout.js";
|
|
3
3
|
import "../../protocol/dist/index.js";
|
|
4
4
|
import { Rect, WorldPoint } from "../geometry.js";
|
|
5
5
|
//#region src/board/core/shape-types.d.ts
|
|
6
|
-
/**
|
|
7
|
-
* A shape's geometry, expressed in the shape's local space (origin at the
|
|
8
|
-
* frame's top-left, unrotated). Hit testing and handles are derived from this,
|
|
9
|
-
* so a shape only declares its outline once.
|
|
10
|
-
*/
|
|
11
6
|
type ShapeGeometry = {
|
|
12
|
-
/** Axis-aligned bounds in local space (usually the full frame). */
|
|
13
7
|
bounds: Rect;
|
|
14
|
-
/**
|
|
15
|
-
* Exact point containment test in *world* space. Receives the shape frame so
|
|
16
|
-
* it can account for rotation. Defaults to the rotated-rect test when absent.
|
|
17
|
-
*/
|
|
18
8
|
containsWorldPoint?: (frame: BoardFrame, point: WorldPoint) => boolean;
|
|
19
9
|
};
|
|
20
10
|
type ShapeHandleId = string;
|
|
21
11
|
type ShapeHandle = {
|
|
22
12
|
id: ShapeHandleId;
|
|
23
|
-
/** Position in the shape's local (unrotated, frame-origin) space. */
|
|
24
13
|
x: number;
|
|
25
14
|
y: number;
|
|
26
|
-
/** Visual + hit radius hint in screen px; the stage scales by zoom. */
|
|
27
15
|
radius?: number;
|
|
28
16
|
};
|
|
29
|
-
/** Result of dragging a handle: a patched frame and/or shape props. */
|
|
30
17
|
type HandleDragResult = {
|
|
31
18
|
frame?: BoardFrame;
|
|
32
19
|
props?: Record<string, unknown>;
|
|
33
20
|
};
|
|
34
|
-
/**
|
|
35
|
-
* What a shape supports. The editor, selection toolbar and tools read these so
|
|
36
|
-
* behaviour is data-driven: adding a shape never requires editing the editor.
|
|
37
|
-
*/
|
|
38
21
|
type ShapeCapabilities = {
|
|
39
|
-
/** Can be moved by dragging. */
|
|
40
22
|
canMove: boolean;
|
|
41
|
-
/** Shows resize handles. */
|
|
42
23
|
canResize: boolean;
|
|
43
|
-
/**
|
|
44
|
-
* Resize always preserves the shape's aspect ratio, regardless of Shift.
|
|
45
|
-
* True for shapes whose content has a single intrinsic scale (text font size,
|
|
46
|
-
* media pixels, stroke geometry) — distorting the frame would either letterbox
|
|
47
|
-
* the content or have no representation in the data model.
|
|
48
|
-
*/
|
|
49
24
|
aspectLocked: boolean;
|
|
50
|
-
/** Shows the rotation handle. */
|
|
51
25
|
canRotate: boolean;
|
|
52
|
-
/** Supports double-click inline editing. */
|
|
53
26
|
canEdit: boolean;
|
|
54
|
-
/**
|
|
55
|
-
* Can be an endpoint of a connection.
|
|
56
|
-
*
|
|
57
|
-
* False for shapes that are themselves annotation strokes (draw, arrow): a
|
|
58
|
-
* relation between two scribbles has no meaning the model could express, and
|
|
59
|
-
* allowing it would produce edges no reader could interpret.
|
|
60
|
-
*/
|
|
61
27
|
canConnect: boolean;
|
|
62
|
-
/** Participates in snapping as a target. */
|
|
63
28
|
canSnap: boolean;
|
|
64
|
-
/** Can be locked against accidental edits. */
|
|
65
29
|
canLock: boolean;
|
|
66
30
|
};
|
|
67
|
-
/**
|
|
68
|
-
* Effective resize behaviour derived from the backwards-compatible capability
|
|
69
|
-
* flags. Consumers should use this mode instead of repeating the flag matrix.
|
|
70
|
-
*/
|
|
71
31
|
type ShapeResizeMode = "none" | "uniform" | "free";
|
|
72
32
|
declare function resizeModeForCapabilities(capabilities: ShapeCapabilities): ShapeResizeMode;
|
|
73
33
|
declare const FULL_CAPABILITIES: ShapeCapabilities;
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
* re-rendered at any LOD later without losing information — data first.
|
|
78
|
-
*/
|
|
79
|
-
type DrawPoint = {
|
|
80
|
-
x: number;
|
|
81
|
-
y: number;
|
|
82
|
-
/** Pen pressure 0..1; 0.5 when unavailable (mouse). */
|
|
83
|
-
p: number;
|
|
84
|
-
};
|
|
85
|
-
type DrawShapeProps = {
|
|
86
|
-
/** Raw samples in the shape's local space. */
|
|
87
|
-
points: DrawPoint[];
|
|
88
|
-
color: string;
|
|
89
|
-
/** Stroke width in world units. */
|
|
90
|
-
size: number;
|
|
91
|
-
};
|
|
92
|
-
type GeoKind = BoardGeoKind;
|
|
93
|
-
declare const GEO_KINDS: readonly GeoKind[];
|
|
94
|
-
declare function isGeoKind(value: unknown): value is GeoKind;
|
|
95
|
-
type GeoShapeProps = {
|
|
96
|
-
geo: GeoKind;
|
|
97
|
-
/** Optional label rendered centered inside the shape. */
|
|
98
|
-
text: string;
|
|
99
|
-
color: string;
|
|
100
|
-
/** Fill opacity 0..1 (0 = outline only). */
|
|
101
|
-
fillOpacity: number;
|
|
102
|
-
};
|
|
103
|
-
/**
|
|
104
|
-
* An arrow endpoint: either a free point (local space) or a binding to another
|
|
105
|
-
* shape. Bindings use a normalized anchor (0..1 of the target's frame) so the
|
|
106
|
-
* arrow tracks the target through move/resize without storing absolute coords.
|
|
107
|
-
*/
|
|
108
|
-
type ArrowEndpoint = {
|
|
109
|
-
kind: "point";
|
|
110
|
-
x: number;
|
|
111
|
-
y: number;
|
|
112
|
-
} | {
|
|
113
|
-
kind: "binding";
|
|
114
|
-
/** Target shape id. */
|
|
115
|
-
target: string;
|
|
116
|
-
/** Normalized anchor on the target frame (0..1). */
|
|
117
|
-
nx: number;
|
|
118
|
-
ny: number;
|
|
119
|
-
/** Whether the binding snaps to the nearest edge/center. */
|
|
120
|
-
precise: boolean;
|
|
121
|
-
};
|
|
122
|
-
type ArrowShapeProps = {
|
|
123
|
-
start: ArrowEndpoint;
|
|
124
|
-
end: ArrowEndpoint;
|
|
125
|
-
/** Bend of a curved arrow, as a fraction of the length (-0.5..0.5). */
|
|
126
|
-
bend: number;
|
|
127
|
-
color: string;
|
|
128
|
-
size: number;
|
|
129
|
-
/** Arrowhead placement. */
|
|
130
|
-
arrowStart: boolean;
|
|
131
|
-
arrowEnd: boolean;
|
|
132
|
-
label: string;
|
|
133
|
-
};
|
|
134
|
-
type TextShapeProps = {
|
|
135
|
-
text: string;
|
|
136
|
-
color: string;
|
|
137
|
-
fontSize: number;
|
|
138
|
-
};
|
|
139
|
-
type ImageShapeProps = {
|
|
140
|
-
path: string;
|
|
141
|
-
mimeType?: string;
|
|
142
|
-
};
|
|
143
|
-
type VideoShapeProps = {
|
|
144
|
-
path: string;
|
|
145
|
-
mimeType?: string;
|
|
146
|
-
};
|
|
147
|
-
type AudioShapeProps = {
|
|
148
|
-
path: string;
|
|
149
|
-
mimeType?: string;
|
|
150
|
-
};
|
|
34
|
+
type ShapeKind = Exclude<BoardShapeGeometry, "path">;
|
|
35
|
+
declare const SHAPE_KINDS: ShapeKind[];
|
|
36
|
+
declare function isShapeKind(value: unknown): value is ShapeKind;
|
|
151
37
|
//#endregion
|
|
152
|
-
export {
|
|
38
|
+
export { FULL_CAPABILITIES, HandleDragResult, SHAPE_KINDS, ShapeCapabilities, ShapeGeometry, ShapeHandle, ShapeHandleId, ShapeKind, ShapeResizeMode, isShapeKind, resizeModeForCapabilities };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BOARD_SHAPE_GEOMETRIES } from "../../protocol/dist/board-model.js";
|
|
2
2
|
//#region src/board/core/shape-types.ts
|
|
3
3
|
function resizeModeForCapabilities(capabilities) {
|
|
4
4
|
if (!capabilities.canResize) return "none";
|
|
@@ -14,9 +14,9 @@ const FULL_CAPABILITIES = {
|
|
|
14
14
|
canSnap: true,
|
|
15
15
|
canLock: true
|
|
16
16
|
};
|
|
17
|
-
const
|
|
18
|
-
function
|
|
19
|
-
return typeof value === "string" &&
|
|
17
|
+
const SHAPE_KINDS = BOARD_SHAPE_GEOMETRIES.filter((kind) => kind !== "path");
|
|
18
|
+
function isShapeKind(value) {
|
|
19
|
+
return typeof value === "string" && SHAPE_KINDS.includes(value);
|
|
20
20
|
}
|
|
21
21
|
//#endregion
|
|
22
|
-
export { FULL_CAPABILITIES,
|
|
22
|
+
export { FULL_CAPABILITIES, SHAPE_KINDS, isShapeKind, resizeModeForCapabilities };
|
|
@@ -1,18 +1,15 @@
|
|
|
1
|
+
import { clampBoardFontSize } from "../../protocol/dist/board-layout.js";
|
|
2
|
+
import "../../protocol/dist/index.js";
|
|
1
3
|
//#region src/board/core/text-metrics.d.ts
|
|
2
4
|
declare const TEXT_FONT_FAMILY = "Geist";
|
|
3
5
|
declare const TEXT_FONT_SIZE = 24;
|
|
4
6
|
declare const TEXT_LINE_HEIGHT = 32;
|
|
5
7
|
declare const TEXT_MIN_FONT_SIZE = 2;
|
|
6
8
|
declare const TEXT_MAX_FONT_SIZE = 512;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/** Measure unwrapped plain text into scalable world-space bounds. */
|
|
13
|
-
declare function measureBoardText(text: string, fontSize?: number): {
|
|
14
|
-
width: number;
|
|
15
|
-
height: number;
|
|
16
|
-
};
|
|
9
|
+
declare function boardFontFamily(font: string, stacks: {
|
|
10
|
+
sans: string;
|
|
11
|
+
serif: string;
|
|
12
|
+
mono: string;
|
|
13
|
+
}): string;
|
|
17
14
|
//#endregion
|
|
18
|
-
export { TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE,
|
|
15
|
+
export { TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, boardFontFamily, clampBoardFontSize as clampBoardTextFontSize };
|