@graphrefly/ts 0.0.0 → 0.0.1
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/README.md +135 -0
- package/dist/adapters/index.cjs +105 -66
- package/dist/adapters/index.cjs.map +1 -1
- package/dist/adapters/index.d.cts +11 -136
- package/dist/adapters/index.d.ts +11 -136
- package/dist/adapters/index.js +27 -225
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/observe-storage.d.cts +4 -4
- package/dist/adapters/observe-storage.d.ts +4 -4
- package/dist/adapters/observe-storage.js +1 -0
- package/dist/adapters/observe-storage.js.map +1 -1
- package/dist/adapters/react.cjs +166 -0
- package/dist/adapters/react.cjs.map +1 -0
- package/dist/adapters/react.d.cts +31 -0
- package/dist/adapters/react.d.ts +31 -0
- package/dist/adapters/react.js +51 -0
- package/dist/adapters/react.js.map +1 -0
- package/dist/adapters/solid.cjs +157 -0
- package/dist/adapters/solid.cjs.map +1 -0
- package/dist/adapters/solid.d.cts +26 -0
- package/dist/adapters/solid.d.ts +26 -0
- package/dist/adapters/solid.js +48 -0
- package/dist/adapters/solid.js.map +1 -0
- package/dist/adapters/svelte.cjs +148 -0
- package/dist/adapters/svelte.cjs.map +1 -0
- package/dist/adapters/svelte.d.cts +31 -0
- package/dist/adapters/svelte.d.ts +31 -0
- package/dist/adapters/svelte.js +46 -0
- package/dist/adapters/svelte.js.map +1 -0
- package/dist/adapters/vue.cjs +155 -0
- package/dist/adapters/vue.cjs.map +1 -0
- package/dist/adapters/vue.d.cts +26 -0
- package/dist/adapters/vue.d.ts +26 -0
- package/dist/adapters/vue.js +46 -0
- package/dist/adapters/vue.js.map +1 -0
- package/dist/agent-runtime-BesGDZcB.d.ts +555 -0
- package/dist/agent-runtime-DZTJ3C-p.d.cts +555 -0
- package/dist/agentic-memory-BmRCvh0d.d.ts +517 -0
- package/dist/agentic-memory-DfuVZ-lY.d.cts +517 -0
- package/dist/capability-admission-B0BzqAm5.d.cts +102 -0
- package/dist/capability-admission-g0mn9hpq.d.ts +102 -0
- package/dist/{chunk-JR4IKCR2.js → chunk-2747WN4Y.js} +5 -5
- package/dist/{chunk-2ILL7HQI.js → chunk-3JR3EDB2.js} +17 -17
- package/dist/{chunk-2ILL7HQI.js.map → chunk-3JR3EDB2.js.map} +1 -1
- package/dist/{chunk-GDL26N2T.js → chunk-3KN7NJDR.js} +2 -2
- package/dist/{chunk-DJC4CHLQ.js → chunk-43BKLFZU.js} +9 -9
- package/dist/chunk-6XAIOL3X.js +2407 -0
- package/dist/chunk-6XAIOL3X.js.map +1 -0
- package/dist/{chunk-SCRFRCGR.js → chunk-BSQGE5PS.js} +1 -1
- package/dist/{chunk-Y3ZLRGHC.js → chunk-CZNV3VXM.js} +16 -16
- package/dist/chunk-DGUM43GV.js +11 -0
- package/dist/chunk-DGUM43GV.js.map +1 -0
- package/dist/{chunk-JIMUDQN3.js → chunk-FBUU43PM.js} +2 -2
- package/dist/chunk-H75VXTGT.js +219 -0
- package/dist/chunk-H75VXTGT.js.map +1 -0
- package/dist/{chunk-RIIOUTGM.js → chunk-HKK2JD7Z.js} +12 -9
- package/dist/chunk-HKK2JD7Z.js.map +1 -0
- package/dist/{chunk-D6BG7U6A.js → chunk-IXZBUWSP.js} +3 -3
- package/dist/chunk-PC3BTTBE.js +3217 -0
- package/dist/chunk-PC3BTTBE.js.map +1 -0
- package/dist/chunk-QFY4AFY4.js +879 -0
- package/dist/chunk-QFY4AFY4.js.map +1 -0
- package/dist/{chunk-DK554R7P.js → chunk-S6HXABGL.js} +2 -1
- package/dist/chunk-S6HXABGL.js.map +1 -0
- package/dist/{chunk-PKVBHGBM.js → chunk-SS2A464I.js} +7 -7
- package/dist/chunk-UT3MHJCW.js +49 -0
- package/dist/chunk-UT3MHJCW.js.map +1 -0
- package/dist/{chunk-G4M3NHRJ.js → chunk-V7CIJE4B.js} +3 -3
- package/dist/{chunk-TEW47IVR.js → chunk-VPEFSDME.js} +2 -2
- package/dist/chunk-VTHLCFN4.js +368 -0
- package/dist/chunk-VTHLCFN4.js.map +1 -0
- package/dist/{chunk-SWTLEQL6.js → chunk-WQIA3GFB.js} +2 -2
- package/dist/chunk-WQIA3GFB.js.map +1 -0
- package/dist/{chunk-I3IHOHCJ.js → chunk-XKXWK2KP.js} +108 -64
- package/dist/chunk-XKXWK2KP.js.map +1 -0
- package/dist/{chunk-COHO25CZ.js → chunk-YDSIVHRR.js} +553 -7
- package/dist/chunk-YDSIVHRR.js.map +1 -0
- package/dist/chunk-YXMZ2N6J.js +1884 -0
- package/dist/chunk-YXMZ2N6J.js.map +1 -0
- package/dist/composition/index.cjs +102 -57
- package/dist/composition/index.cjs.map +1 -1
- package/dist/composition/index.d.cts +4 -4
- package/dist/composition/index.d.ts +4 -4
- package/dist/composition/index.js +6 -5
- package/dist/core/index.cjs +102 -57
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +2 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +5 -4
- package/dist/cqrs/index.cjs.map +1 -1
- package/dist/cqrs/index.d.cts +4 -4
- package/dist/cqrs/index.d.ts +4 -4
- package/dist/cqrs/index.js +3 -2
- package/dist/cqrs/index.js.map +1 -1
- package/dist/cqrs/messaging.cjs +312 -0
- package/dist/cqrs/messaging.cjs.map +1 -0
- package/dist/cqrs/messaging.d.cts +57 -0
- package/dist/cqrs/messaging.d.ts +57 -0
- package/dist/cqrs/messaging.js +274 -0
- package/dist/cqrs/messaging.js.map +1 -0
- package/dist/cqrs/work-queue.cjs +329 -0
- package/dist/cqrs/work-queue.cjs.map +1 -0
- package/dist/cqrs/work-queue.d.cts +90 -0
- package/dist/cqrs/work-queue.d.ts +90 -0
- package/dist/cqrs/work-queue.js +292 -0
- package/dist/cqrs/work-queue.js.map +1 -0
- package/dist/data/index.cjs +19 -0
- package/dist/data/index.cjs.map +1 -0
- package/dist/data/index.d.cts +36 -0
- package/dist/data/index.d.ts +36 -0
- package/dist/data/index.js +1 -0
- package/dist/data/index.js.map +1 -0
- package/dist/data-structures/index.cjs +105 -57
- package/dist/data-structures/index.cjs.map +1 -1
- package/dist/data-structures/index.d.cts +8 -8
- package/dist/data-structures/index.d.ts +8 -8
- package/dist/data-structures/index.js +7 -6
- package/dist/{describe-BZb7AS2y.d.ts → describe-BpyJuWkw.d.ts} +1 -1
- package/dist/{describe-Ciu8SUnN.d.cts → describe-DYMw_l1C.d.cts} +1 -1
- package/dist/executors/work-queue.cjs +342 -0
- package/dist/executors/work-queue.cjs.map +1 -0
- package/dist/executors/work-queue.d.cts +90 -0
- package/dist/executors/work-queue.d.ts +90 -0
- package/dist/executors/work-queue.js +306 -0
- package/dist/executors/work-queue.js.map +1 -0
- package/dist/graph/index.cjs +112 -58
- package/dist/graph/index.cjs.map +1 -1
- package/dist/graph/index.d.cts +9 -9
- package/dist/graph/index.d.ts +9 -9
- package/dist/graph/index.js +18 -17
- package/dist/{graph-DfdF9zy4.d.ts → graph-D-1-SQeC.d.ts} +3 -3
- package/dist/{graph-s23RbbFO.d.cts → graph-DCEWh4T2.d.cts} +3 -3
- package/dist/{index-CAEmLCYF.d.cts → index-72VZC0-E.d.cts} +2 -2
- package/dist/{index-SnzZu3x7.d.ts → index-Bmxeu0nK.d.ts} +2 -2
- package/dist/index.cjs +112 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -10
- package/dist/index.d.ts +11 -10
- package/dist/index.js +118 -113
- package/dist/inspection/boundary.cjs +98 -0
- package/dist/inspection/boundary.cjs.map +1 -0
- package/dist/inspection/boundary.d.cts +61 -0
- package/dist/inspection/boundary.d.ts +61 -0
- package/dist/inspection/boundary.js +75 -0
- package/dist/inspection/boundary.js.map +1 -0
- package/dist/{messages-BZqrGGm1.d.ts → messages-CAzUPPJM.d.cts} +10 -5
- package/dist/{messages-BZqrGGm1.d.cts → messages-CAzUPPJM.d.ts} +10 -5
- package/dist/messaging/index.cjs +744 -613
- package/dist/messaging/index.cjs.map +1 -1
- package/dist/messaging/index.d.cts +216 -160
- package/dist/messaging/index.d.ts +216 -160
- package/dist/messaging/index.js +19 -749
- package/dist/messaging/index.js.map +1 -1
- package/dist/operators/index.cjs +102 -57
- package/dist/operators/index.cjs.map +1 -1
- package/dist/operators/index.d.cts +6 -6
- package/dist/operators/index.d.ts +6 -6
- package/dist/operators/index.js +8 -7
- package/dist/orchestration/index.cjs +3333 -59
- package/dist/orchestration/index.cjs.map +1 -1
- package/dist/orchestration/index.d.cts +7 -4
- package/dist/orchestration/index.d.ts +7 -4
- package/dist/orchestration/index.js +49 -8
- package/dist/orchestration/index.js.map +1 -1
- package/dist/orchestration/messaging.cjs +314 -0
- package/dist/orchestration/messaging.cjs.map +1 -0
- package/dist/orchestration/messaging.d.cts +59 -0
- package/dist/orchestration/messaging.d.ts +59 -0
- package/dist/orchestration/messaging.js +276 -0
- package/dist/orchestration/messaging.js.map +1 -0
- package/dist/orchestration/work-queue.cjs +262 -0
- package/dist/orchestration/work-queue.cjs.map +1 -0
- package/dist/orchestration/work-queue.d.cts +85 -0
- package/dist/orchestration/work-queue.d.ts +85 -0
- package/dist/orchestration/work-queue.js +226 -0
- package/dist/orchestration/work-queue.js.map +1 -0
- package/dist/patterns/event-flow.cjs +447 -0
- package/dist/patterns/event-flow.cjs.map +1 -0
- package/dist/patterns/event-flow.d.cts +115 -0
- package/dist/patterns/event-flow.d.ts +115 -0
- package/dist/patterns/event-flow.js +14 -0
- package/dist/patterns/event-flow.js.map +1 -0
- package/dist/patterns/index.cjs +423 -18
- package/dist/patterns/index.cjs.map +1 -1
- package/dist/patterns/index.d.cts +8 -5
- package/dist/patterns/index.d.ts +8 -5
- package/dist/patterns/index.js +13 -4
- package/dist/{reactive-collection-Cb1II1Fi.d.ts → reactive-collection-BAmfrGjd.d.ts} +9 -9
- package/dist/{reactive-collection-BxBqtIOE.d.cts → reactive-collection-DNV0-gFi.d.cts} +9 -9
- package/dist/{reactive-collection-storage-D-KmjE0J.d.cts → reactive-collection-storage-BNEldDyi.d.cts} +5 -5
- package/dist/{reactive-collection-storage-BNiEc-Gd.d.ts → reactive-collection-storage-YZsAQsWK.d.ts} +5 -5
- package/dist/{reactive-map-D-g3dv8I.d.cts → reactive-map-DRD1LJ2H.d.cts} +6 -6
- package/dist/{reactive-map-BcB4KsQR.d.ts → reactive-map-EsDiCmJk.d.ts} +6 -6
- package/dist/render/index.d.cts +3 -3
- package/dist/render/index.d.ts +3 -3
- package/dist/render/index.js +1 -0
- package/dist/{semantic-memory-graph-BYoIlP35.d.cts → semantic-memory-graph-DKuNzuWw.d.cts} +2 -2
- package/dist/{semantic-memory-graph-CxyXLms3.d.ts → semantic-memory-graph-uwbwJdhe.d.ts} +2 -2
- package/dist/solutions/index.cjs +4478 -2
- package/dist/solutions/index.cjs.map +1 -1
- package/dist/solutions/index.d.cts +13 -519
- package/dist/solutions/index.d.ts +13 -519
- package/dist/solutions/index.js +90 -6
- package/dist/solutions/reactive-layout/browser/index.cjs +449 -0
- package/dist/solutions/reactive-layout/browser/index.cjs.map +1 -0
- package/dist/solutions/reactive-layout/browser/index.d.cts +44 -0
- package/dist/solutions/reactive-layout/browser/index.d.ts +44 -0
- package/dist/solutions/reactive-layout/browser/index.js +69 -0
- package/dist/solutions/reactive-layout/browser/index.js.map +1 -0
- package/dist/solutions/reactive-layout/index.cjs +4266 -0
- package/dist/solutions/reactive-layout/index.cjs.map +1 -0
- package/dist/solutions/reactive-layout/index.d.cts +581 -0
- package/dist/solutions/reactive-layout/index.d.ts +581 -0
- package/dist/solutions/reactive-layout/index.js +86 -0
- package/dist/solutions/reactive-layout/index.js.map +1 -0
- package/dist/solutions/reactive-layout/node-canvas/index.cjs +545 -0
- package/dist/solutions/reactive-layout/node-canvas/index.cjs.map +1 -0
- package/dist/solutions/reactive-layout/node-canvas/index.d.cts +54 -0
- package/dist/solutions/reactive-layout/node-canvas/index.d.ts +54 -0
- package/dist/solutions/reactive-layout/node-canvas/index.js +131 -0
- package/dist/solutions/reactive-layout/node-canvas/index.js.map +1 -0
- package/dist/solutions/reactive-layout/react-native/index.cjs +494 -0
- package/dist/solutions/reactive-layout/react-native/index.cjs.map +1 -0
- package/dist/solutions/reactive-layout/react-native/index.d.cts +51 -0
- package/dist/solutions/reactive-layout/react-native/index.d.ts +51 -0
- package/dist/solutions/reactive-layout/react-native/index.js +77 -0
- package/dist/solutions/reactive-layout/react-native/index.js.map +1 -0
- package/dist/solutions/reactive-layout/skia/index.cjs +547 -0
- package/dist/solutions/reactive-layout/skia/index.cjs.map +1 -0
- package/dist/solutions/reactive-layout/skia/index.d.cts +64 -0
- package/dist/solutions/reactive-layout/skia/index.d.ts +64 -0
- package/dist/solutions/reactive-layout/skia/index.js +70 -0
- package/dist/solutions/reactive-layout/skia/index.js.map +1 -0
- package/dist/solutions/work-item/actions.cjs +2164 -0
- package/dist/solutions/work-item/actions.cjs.map +1 -0
- package/dist/solutions/work-item/actions.d.cts +201 -0
- package/dist/solutions/work-item/actions.d.ts +201 -0
- package/dist/solutions/work-item/actions.js +1454 -0
- package/dist/solutions/work-item/actions.js.map +1 -0
- package/dist/solutions/work-item/scheduling.cjs +2454 -0
- package/dist/solutions/work-item/scheduling.cjs.map +1 -0
- package/dist/solutions/work-item/scheduling.d.cts +433 -0
- package/dist/solutions/work-item/scheduling.d.ts +433 -0
- package/dist/solutions/work-item/scheduling.js +32 -0
- package/dist/solutions/work-item/scheduling.js.map +1 -0
- package/dist/solutions/work-item/work-queue.cjs +306 -0
- package/dist/solutions/work-item/work-queue.cjs.map +1 -0
- package/dist/solutions/work-item/work-queue.d.cts +71 -0
- package/dist/solutions/work-item/work-queue.d.ts +71 -0
- package/dist/solutions/work-item/work-queue.js +270 -0
- package/dist/solutions/work-item/work-queue.js.map +1 -0
- package/dist/sources/browser.cjs +169 -57
- package/dist/sources/browser.cjs.map +1 -1
- package/dist/sources/browser.d.cts +33 -6
- package/dist/sources/browser.d.ts +33 -6
- package/dist/sources/browser.js +73 -6
- package/dist/sources/browser.js.map +1 -1
- package/dist/sources/index.cjs +102 -57
- package/dist/sources/index.cjs.map +1 -1
- package/dist/sources/index.d.cts +5 -5
- package/dist/sources/index.d.ts +5 -5
- package/dist/sources/index.js +6 -5
- package/dist/sources/node.cjs.map +1 -1
- package/dist/sources/node.d.cts +4 -4
- package/dist/sources/node.d.ts +4 -4
- package/dist/sources/node.js +2 -1
- package/dist/sources/node.js.map +1 -1
- package/dist/storage/browser.js +1 -0
- package/dist/storage/browser.js.map +1 -1
- package/dist/storage/index.d.cts +5 -5
- package/dist/storage/index.d.ts +5 -5
- package/dist/storage/index.js +5 -4
- package/dist/storage/node.js +1 -0
- package/dist/storage/node.js.map +1 -1
- package/dist/store-C-joM4gh.d.ts +123 -0
- package/dist/store-CNJwmT-h.d.cts +123 -0
- package/dist/testing/index.cjs +1 -0
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +3 -2
- package/dist/{types-h12mNYbq.d.ts → types-BsJvElYZ.d.ts} +31 -31
- package/dist/{types-bNMSWKqF.d.cts → types-CcPIn7sy.d.cts} +31 -31
- package/dist/work-item-runtime-C3M79vE9.d.ts +228 -0
- package/dist/work-item-runtime-qaVgsL0T.d.cts +228 -0
- package/dist/work-queue/index.cjs +1132 -0
- package/dist/work-queue/index.cjs.map +1 -0
- package/dist/work-queue/index.d.cts +369 -0
- package/dist/work-queue/index.d.ts +369 -0
- package/dist/work-queue/index.js +1078 -0
- package/dist/work-queue/index.js.map +1 -0
- package/package.json +266 -2
- package/dist/chunk-COHO25CZ.js.map +0 -1
- package/dist/chunk-DK554R7P.js.map +0 -1
- package/dist/chunk-I3IHOHCJ.js.map +0 -1
- package/dist/chunk-RIIOUTGM.js.map +0 -1
- package/dist/chunk-SWTLEQL6.js.map +0 -1
- /package/dist/{chunk-JR4IKCR2.js.map → chunk-2747WN4Y.js.map} +0 -0
- /package/dist/{chunk-GDL26N2T.js.map → chunk-3KN7NJDR.js.map} +0 -0
- /package/dist/{chunk-DJC4CHLQ.js.map → chunk-43BKLFZU.js.map} +0 -0
- /package/dist/{chunk-SCRFRCGR.js.map → chunk-BSQGE5PS.js.map} +0 -0
- /package/dist/{chunk-Y3ZLRGHC.js.map → chunk-CZNV3VXM.js.map} +0 -0
- /package/dist/{chunk-JIMUDQN3.js.map → chunk-FBUU43PM.js.map} +0 -0
- /package/dist/{chunk-D6BG7U6A.js.map → chunk-IXZBUWSP.js.map} +0 -0
- /package/dist/{chunk-PKVBHGBM.js.map → chunk-SS2A464I.js.map} +0 -0
- /package/dist/{chunk-G4M3NHRJ.js.map → chunk-V7CIJE4B.js.map} +0 -0
- /package/dist/{chunk-TEW47IVR.js.map → chunk-VPEFSDME.js.map} +0 -0
|
@@ -0,0 +1,1884 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Node
|
|
3
|
+
} from "./chunk-XKXWK2KP.js";
|
|
4
|
+
import {
|
|
5
|
+
depLatest
|
|
6
|
+
} from "./chunk-WQIA3GFB.js";
|
|
7
|
+
import {
|
|
8
|
+
errorPayload
|
|
9
|
+
} from "./chunk-S6HXABGL.js";
|
|
10
|
+
|
|
11
|
+
// src/solutions/reactive-layout/index.ts
|
|
12
|
+
var TEXT_SEGMENTS_MEASUREMENT_KIND = "text-segments";
|
|
13
|
+
var BLOCKS_MEASUREMENT_KIND = "blocks";
|
|
14
|
+
var READINESS_MEASUREMENT_KIND = "readiness";
|
|
15
|
+
var IMAGE_SIZE_MEASUREMENT_KIND = "image-size";
|
|
16
|
+
var SVG_BOUNDS_MEASUREMENT_KIND = "svg-bounds";
|
|
17
|
+
var kinsokuStart = /* @__PURE__ */ new Set([
|
|
18
|
+
"\u3001",
|
|
19
|
+
"\u3002",
|
|
20
|
+
"\u30FB",
|
|
21
|
+
"\uFF09",
|
|
22
|
+
"\u3015",
|
|
23
|
+
"\u3009",
|
|
24
|
+
"\u300B",
|
|
25
|
+
"\u300D",
|
|
26
|
+
"\u300F",
|
|
27
|
+
"\u3011"
|
|
28
|
+
]);
|
|
29
|
+
var leftStickyPunctuation = /* @__PURE__ */ new Set([
|
|
30
|
+
".",
|
|
31
|
+
",",
|
|
32
|
+
"!",
|
|
33
|
+
"?",
|
|
34
|
+
":",
|
|
35
|
+
";",
|
|
36
|
+
")",
|
|
37
|
+
"]",
|
|
38
|
+
"}",
|
|
39
|
+
"%",
|
|
40
|
+
'"',
|
|
41
|
+
"\u201D",
|
|
42
|
+
"\u2019",
|
|
43
|
+
"\xBB",
|
|
44
|
+
"\u203A",
|
|
45
|
+
"\u2026"
|
|
46
|
+
]);
|
|
47
|
+
function isCJK(text) {
|
|
48
|
+
for (const ch of text) {
|
|
49
|
+
const c = ch.codePointAt(0);
|
|
50
|
+
if (c !== void 0 && c >= 19968 && c <= 40959 || c !== void 0 && c >= 13312 && c <= 19903 || c !== void 0 && c >= 12288 && c <= 12351 || c !== void 0 && c >= 12352 && c <= 12447 || c !== void 0 && c >= 44032 && c <= 55215 || c !== void 0 && c >= 65280 && c <= 65519) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
function normalizeWhitespace(text) {
|
|
57
|
+
return text.replace(/[\t\f ]+/g, " ").replace(/^ | $/g, "");
|
|
58
|
+
}
|
|
59
|
+
function segmentText(text, segmentAdapter) {
|
|
60
|
+
const pieces = [];
|
|
61
|
+
for (const s of segmentAdapter.segmentWords(text)) {
|
|
62
|
+
const wordSegment = s.segment;
|
|
63
|
+
const rawWordLike = s.isWordLike ?? false;
|
|
64
|
+
const pieceTexts = [];
|
|
65
|
+
const pieceWordLikes = [];
|
|
66
|
+
const pieceKinds = [];
|
|
67
|
+
let currentText = "";
|
|
68
|
+
let currentKind = null;
|
|
69
|
+
for (const ch of wordSegment) {
|
|
70
|
+
let kind;
|
|
71
|
+
if (ch === " ") {
|
|
72
|
+
kind = "space";
|
|
73
|
+
} else if (ch === "\u200B") {
|
|
74
|
+
kind = "zero-width-break";
|
|
75
|
+
} else if (ch === "\xAD") {
|
|
76
|
+
kind = "soft-hyphen";
|
|
77
|
+
} else if (ch === "\n") {
|
|
78
|
+
kind = "hard-break";
|
|
79
|
+
} else {
|
|
80
|
+
kind = "text";
|
|
81
|
+
}
|
|
82
|
+
if (currentKind !== null && kind === currentKind) {
|
|
83
|
+
currentText += ch;
|
|
84
|
+
} else {
|
|
85
|
+
if (currentKind !== null) {
|
|
86
|
+
pieceTexts.push(currentText);
|
|
87
|
+
pieceWordLikes.push(currentKind === "text" && rawWordLike);
|
|
88
|
+
pieceKinds.push(currentKind);
|
|
89
|
+
}
|
|
90
|
+
currentText = ch;
|
|
91
|
+
currentKind = kind;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (currentKind !== null) {
|
|
95
|
+
pieceTexts.push(currentText);
|
|
96
|
+
pieceWordLikes.push(currentKind === "text" && rawWordLike);
|
|
97
|
+
pieceKinds.push(currentKind);
|
|
98
|
+
}
|
|
99
|
+
pieces.push({ texts: pieceTexts, isWordLike: pieceWordLikes, kinds: pieceKinds });
|
|
100
|
+
}
|
|
101
|
+
return pieces;
|
|
102
|
+
}
|
|
103
|
+
function* fallbackSegmentWords(text) {
|
|
104
|
+
let index = 0;
|
|
105
|
+
let current = "";
|
|
106
|
+
let currentIndex = 0;
|
|
107
|
+
let currentWordLike = null;
|
|
108
|
+
const flush = () => {
|
|
109
|
+
if (current.length === 0 || currentWordLike === null) return void 0;
|
|
110
|
+
const out2 = { segment: current, index: currentIndex, isWordLike: currentWordLike };
|
|
111
|
+
current = "";
|
|
112
|
+
currentWordLike = null;
|
|
113
|
+
return out2;
|
|
114
|
+
};
|
|
115
|
+
for (const ch of text) {
|
|
116
|
+
const isWordLike = !/[\s\u200B\u00AD]/u.test(ch);
|
|
117
|
+
if (currentWordLike !== null && currentWordLike !== isWordLike) {
|
|
118
|
+
const out2 = flush();
|
|
119
|
+
if (out2) yield out2;
|
|
120
|
+
}
|
|
121
|
+
if (currentWordLike === null) {
|
|
122
|
+
currentWordLike = isWordLike;
|
|
123
|
+
currentIndex = index;
|
|
124
|
+
}
|
|
125
|
+
current += ch;
|
|
126
|
+
index += ch.length;
|
|
127
|
+
}
|
|
128
|
+
const out = flush();
|
|
129
|
+
if (out) yield out;
|
|
130
|
+
}
|
|
131
|
+
function* fallbackSegmentGraphemes(text) {
|
|
132
|
+
let index = 0;
|
|
133
|
+
for (const ch of text) {
|
|
134
|
+
yield { segment: ch, index };
|
|
135
|
+
index += ch.length;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function createDefaultSegmentAdapter() {
|
|
139
|
+
return {
|
|
140
|
+
segmentWords(text) {
|
|
141
|
+
return fallbackSegmentWords(text);
|
|
142
|
+
},
|
|
143
|
+
segmentGraphemes(text) {
|
|
144
|
+
return fallbackSegmentGraphemes(text);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
var defaultSegmentAdapter = null;
|
|
149
|
+
function getDefaultSegmentAdapter() {
|
|
150
|
+
if (defaultSegmentAdapter === null) {
|
|
151
|
+
defaultSegmentAdapter = createDefaultSegmentAdapter();
|
|
152
|
+
}
|
|
153
|
+
return defaultSegmentAdapter;
|
|
154
|
+
}
|
|
155
|
+
function measuredWidth(value) {
|
|
156
|
+
const width = typeof value === "number" ? value : value.width;
|
|
157
|
+
return Number.isFinite(width) && width >= 0 ? width : 0;
|
|
158
|
+
}
|
|
159
|
+
function metricKey(text, font) {
|
|
160
|
+
return `${font}\0${text}`;
|
|
161
|
+
}
|
|
162
|
+
var InjectedMeasureAdapter = class {
|
|
163
|
+
measure;
|
|
164
|
+
shouldCache;
|
|
165
|
+
cache = /* @__PURE__ */ new Map();
|
|
166
|
+
constructor(measure, opts = {}) {
|
|
167
|
+
this.measure = measure;
|
|
168
|
+
this.shouldCache = opts.cache ?? true;
|
|
169
|
+
}
|
|
170
|
+
measureSegment(text, font) {
|
|
171
|
+
const key = metricKey(text, font);
|
|
172
|
+
if (this.shouldCache) {
|
|
173
|
+
const cached = this.cache.get(key);
|
|
174
|
+
if (cached !== void 0) return { width: cached };
|
|
175
|
+
}
|
|
176
|
+
const width = measuredWidth(this.measure(text, font));
|
|
177
|
+
if (this.shouldCache) this.cache.set(key, width);
|
|
178
|
+
return { width };
|
|
179
|
+
}
|
|
180
|
+
clearCache() {
|
|
181
|
+
this.cache.clear();
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
var PrecomputedMeasureAdapter = class {
|
|
185
|
+
metrics;
|
|
186
|
+
fallback;
|
|
187
|
+
cellWidth;
|
|
188
|
+
constructor(opts) {
|
|
189
|
+
this.metrics = opts.metrics instanceof Map ? opts.metrics : new Map(Object.entries(opts.metrics));
|
|
190
|
+
this.fallback = opts.fallback ?? "error";
|
|
191
|
+
this.cellWidth = nonNegativeFinite(opts.cellWidth ?? 8, 8);
|
|
192
|
+
}
|
|
193
|
+
measureSegment(text, font) {
|
|
194
|
+
const fontScoped = this.metrics.get(metricKey(text, font));
|
|
195
|
+
if (fontScoped !== void 0) return { width: nonNegativeFinite(fontScoped, 0) };
|
|
196
|
+
const unscoped = this.metrics.get(text);
|
|
197
|
+
if (unscoped !== void 0) return { width: nonNegativeFinite(unscoped, 0) };
|
|
198
|
+
if (this.fallback === "per-char") {
|
|
199
|
+
return { width: Array.from(text).length * this.cellWidth };
|
|
200
|
+
}
|
|
201
|
+
throw new Error(`No precomputed metric for segment ${JSON.stringify(text)}`);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
var CellMeasureAdapter = class {
|
|
205
|
+
cellWidth;
|
|
206
|
+
wideCellWidth;
|
|
207
|
+
tabCells;
|
|
208
|
+
constructor(opts = {}) {
|
|
209
|
+
this.cellWidth = nonNegativeFinite(opts.cellWidth ?? 8, 8);
|
|
210
|
+
this.wideCellWidth = nonNegativeFinite(
|
|
211
|
+
opts.wideCellWidth ?? this.cellWidth * 2,
|
|
212
|
+
this.cellWidth * 2
|
|
213
|
+
);
|
|
214
|
+
this.tabCells = Math.max(1, Math.floor(nonNegativeFinite(opts.tabCells ?? 4, 4)));
|
|
215
|
+
}
|
|
216
|
+
measureSegment(text) {
|
|
217
|
+
let width = 0;
|
|
218
|
+
for (const char of text) {
|
|
219
|
+
if (char === " ") width += this.cellWidth * this.tabCells;
|
|
220
|
+
else width += isCJK(char) ? this.wideCellWidth : this.cellWidth;
|
|
221
|
+
}
|
|
222
|
+
return { width };
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
var CapabilityMeasureAdapter = class {
|
|
226
|
+
capability;
|
|
227
|
+
constructor(capability) {
|
|
228
|
+
this.capability = capability;
|
|
229
|
+
}
|
|
230
|
+
measureSegment(text, font) {
|
|
231
|
+
return { width: measuredWidth(this.capability.measureText(text, font)) };
|
|
232
|
+
}
|
|
233
|
+
clearCache() {
|
|
234
|
+
this.capability.clearCache?.();
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
function stripSvgIgnoredContent(svg) {
|
|
238
|
+
return svg.replace(/<!--[\s\S]*?-->/g, "").replace(/<!\[CDATA\[[\s\S]*?\]\]>/g, "");
|
|
239
|
+
}
|
|
240
|
+
function readSvgRootTag(svg) {
|
|
241
|
+
return /<svg\b[^>]*>/i.exec(svg)?.[0] ?? null;
|
|
242
|
+
}
|
|
243
|
+
function readNumericAttr(tag, attr) {
|
|
244
|
+
const pattern = new RegExp(`(?:^|\\s)${attr}\\s*=\\s*["']?(-?\\d+(?:\\.\\d+)?)`, "i");
|
|
245
|
+
const match = pattern.exec(tag);
|
|
246
|
+
if (!match) return null;
|
|
247
|
+
const value = Number(match[1]);
|
|
248
|
+
return Number.isFinite(value) && value >= 0 ? value : null;
|
|
249
|
+
}
|
|
250
|
+
function readViewBox(tag) {
|
|
251
|
+
const match = /\bviewBox\s*=\s*["']\s*(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*["']/i.exec(
|
|
252
|
+
tag
|
|
253
|
+
);
|
|
254
|
+
if (!match) return null;
|
|
255
|
+
const width = Number(match[3]);
|
|
256
|
+
const height = Number(match[4]);
|
|
257
|
+
if (!Number.isFinite(width) || !Number.isFinite(height) || width < 0 || height < 0) {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
return { width, height };
|
|
261
|
+
}
|
|
262
|
+
var SvgBoundsAdapter = class {
|
|
263
|
+
measureSvg(svg) {
|
|
264
|
+
const cleaned = stripSvgIgnoredContent(svg);
|
|
265
|
+
const rootTag = readSvgRootTag(cleaned);
|
|
266
|
+
if (rootTag === null) throw new Error("Cannot measure SVG without a root <svg> element");
|
|
267
|
+
const width = readNumericAttr(rootTag, "width");
|
|
268
|
+
const height = readNumericAttr(rootTag, "height");
|
|
269
|
+
if (width !== null && height !== null) return { width, height };
|
|
270
|
+
const viewBox = readViewBox(rootTag);
|
|
271
|
+
if (viewBox) return viewBox;
|
|
272
|
+
throw new Error("Cannot measure SVG without width/height or viewBox");
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
var ImageSizeAdapter = class {
|
|
276
|
+
sizes;
|
|
277
|
+
constructor(sizes) {
|
|
278
|
+
this.sizes = isImageSizeLookup(sizes) ? sizes : new Map(Object.entries(sizes));
|
|
279
|
+
}
|
|
280
|
+
measureImage(src) {
|
|
281
|
+
const size = this.sizes.get(src);
|
|
282
|
+
if (!size) throw new Error(`No image size registered for ${JSON.stringify(src)}`);
|
|
283
|
+
return size;
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
function isImageSizeLookup(value) {
|
|
287
|
+
if (value === null) return false;
|
|
288
|
+
const valueType = typeof value;
|
|
289
|
+
if (valueType !== "object" && valueType !== "function") return false;
|
|
290
|
+
return typeof value.get === "function";
|
|
291
|
+
}
|
|
292
|
+
function measurementIssue(code, message, targetId, measurementKind, opts = {}) {
|
|
293
|
+
return {
|
|
294
|
+
kind: "issue",
|
|
295
|
+
code,
|
|
296
|
+
message,
|
|
297
|
+
severity: opts.severity ?? "warning",
|
|
298
|
+
source: opts.source,
|
|
299
|
+
subjectId: targetId,
|
|
300
|
+
measurementKind,
|
|
301
|
+
details: opts.details,
|
|
302
|
+
metadata: opts.metadata
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
function measurementOk(targetId, measurementKind, value, opts = {}) {
|
|
306
|
+
return {
|
|
307
|
+
kind: "ok",
|
|
308
|
+
targetId,
|
|
309
|
+
measurementKind,
|
|
310
|
+
value,
|
|
311
|
+
source: opts.source,
|
|
312
|
+
metadata: opts.metadata
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
function latestMeasurementValue(measurements, targetId, measurementKind) {
|
|
316
|
+
let value;
|
|
317
|
+
for (const fact of measurements) {
|
|
318
|
+
if (fact.kind === "ok" && fact.targetId === targetId && fact.measurementKind === measurementKind) {
|
|
319
|
+
value = fact.value;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return value;
|
|
323
|
+
}
|
|
324
|
+
function tryMeasureHyphenWidth(adapter, font) {
|
|
325
|
+
try {
|
|
326
|
+
return nonNegativeFinite(adapter.measureSegment("-", font).width, 0);
|
|
327
|
+
} catch {
|
|
328
|
+
return void 0;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
function validMeasurementSize(size, label) {
|
|
332
|
+
if (!Number.isFinite(size.width) || !Number.isFinite(size.height) || size.width < 0 || size.height < 0) {
|
|
333
|
+
throw new Error(`Invalid ${label} measurement size`);
|
|
334
|
+
}
|
|
335
|
+
return size;
|
|
336
|
+
}
|
|
337
|
+
function textMeasurementFacts(text, font, adapter, cache, segmentAdapter, targetId, source) {
|
|
338
|
+
try {
|
|
339
|
+
const segments = analyzeAndMeasure(text, font, adapter, cache, void 0, segmentAdapter);
|
|
340
|
+
const hyphenWidth = tryMeasureHyphenWidth(adapter, font);
|
|
341
|
+
const facts = [
|
|
342
|
+
measurementOk(
|
|
343
|
+
targetId,
|
|
344
|
+
TEXT_SEGMENTS_MEASUREMENT_KIND,
|
|
345
|
+
hyphenWidth === void 0 ? { segments } : { segments, hyphenWidth },
|
|
346
|
+
{ source }
|
|
347
|
+
)
|
|
348
|
+
];
|
|
349
|
+
if (hyphenWidth === void 0) {
|
|
350
|
+
facts.push(
|
|
351
|
+
measurementIssue(
|
|
352
|
+
"measurement.hyphen.failed",
|
|
353
|
+
`Hyphen measurement failed for '${targetId}'`,
|
|
354
|
+
targetId,
|
|
355
|
+
TEXT_SEGMENTS_MEASUREMENT_KIND,
|
|
356
|
+
{ source, severity: "warning" }
|
|
357
|
+
)
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
return facts;
|
|
361
|
+
} catch (error) {
|
|
362
|
+
return [
|
|
363
|
+
measurementIssue(
|
|
364
|
+
"measurement.failed",
|
|
365
|
+
`Text measurement failed for '${targetId}'`,
|
|
366
|
+
targetId,
|
|
367
|
+
TEXT_SEGMENTS_MEASUREMENT_KIND,
|
|
368
|
+
{ source, details: error, severity: "error" }
|
|
369
|
+
)
|
|
370
|
+
];
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
function inputNode(g, input, fallback, name) {
|
|
374
|
+
if (input instanceof Node) {
|
|
375
|
+
return {
|
|
376
|
+
node: input,
|
|
377
|
+
set(value) {
|
|
378
|
+
const maybeState = input;
|
|
379
|
+
if (typeof maybeState.set !== "function") {
|
|
380
|
+
throw new TypeError(`reactive-layout input '${name}' is not a writable state node`);
|
|
381
|
+
}
|
|
382
|
+
maybeState.set(value);
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
const state = g.state(input ?? fallback, { name });
|
|
387
|
+
return { node: state, set: (value) => state.set(value) };
|
|
388
|
+
}
|
|
389
|
+
function scopedName(scope, local) {
|
|
390
|
+
return scope === local ? local : `${scope}:${local}`;
|
|
391
|
+
}
|
|
392
|
+
function textMeasurementProvider(opts) {
|
|
393
|
+
const targetId = opts.targetId ?? "text";
|
|
394
|
+
const name = opts.name ?? `${targetId}-measurements`;
|
|
395
|
+
const source = opts.source ?? name;
|
|
396
|
+
const cache = /* @__PURE__ */ new Map();
|
|
397
|
+
let activeAdapter = null;
|
|
398
|
+
return opts.graph.node(
|
|
399
|
+
opts.segmentAdapter ? [opts.text, opts.font, opts.adapter, opts.segmentAdapter] : [opts.text, opts.font, opts.adapter],
|
|
400
|
+
(ctx) => {
|
|
401
|
+
const flush = () => {
|
|
402
|
+
cache.clear();
|
|
403
|
+
depLatest(ctx, 2).clearCache?.();
|
|
404
|
+
};
|
|
405
|
+
ctx.onDeactivation(flush);
|
|
406
|
+
ctx.onInvalidate(flush);
|
|
407
|
+
const text = depLatest(ctx, 0);
|
|
408
|
+
const font = depLatest(ctx, 1);
|
|
409
|
+
const adapter = depLatest(ctx, 2);
|
|
410
|
+
if (adapter !== activeAdapter) {
|
|
411
|
+
cache.clear();
|
|
412
|
+
activeAdapter = adapter;
|
|
413
|
+
}
|
|
414
|
+
const segmentAdapter = opts.segmentAdapter === void 0 ? getDefaultSegmentAdapter() : depLatest(ctx, 3);
|
|
415
|
+
ctx.down([
|
|
416
|
+
[
|
|
417
|
+
"DATA",
|
|
418
|
+
textMeasurementFacts(text, font, adapter, cache, segmentAdapter, targetId, source)
|
|
419
|
+
]
|
|
420
|
+
]);
|
|
421
|
+
},
|
|
422
|
+
{ name }
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
function injectedTextMeasurements(opts) {
|
|
426
|
+
const targetId = opts.targetId ?? "text";
|
|
427
|
+
const adapter = opts.graph.state(
|
|
428
|
+
new InjectedMeasureAdapter(opts.measure, { cache: opts.cache }),
|
|
429
|
+
{
|
|
430
|
+
name: opts.name ? scopedName(opts.name, "measure-capability") : `${targetId}-measure-capability`
|
|
431
|
+
}
|
|
432
|
+
);
|
|
433
|
+
return textMeasurementProvider({
|
|
434
|
+
...opts,
|
|
435
|
+
adapter,
|
|
436
|
+
source: opts.source ?? "injectedTextMeasurements"
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
function precomputedTextMeasurements(opts) {
|
|
440
|
+
const targetId = opts.targetId ?? "text";
|
|
441
|
+
const adapter = opts.graph.state(new PrecomputedMeasureAdapter(opts), {
|
|
442
|
+
name: opts.name ? scopedName(opts.name, "measure-capability") : `${targetId}-measure-capability`
|
|
443
|
+
});
|
|
444
|
+
return textMeasurementProvider({
|
|
445
|
+
...opts,
|
|
446
|
+
adapter,
|
|
447
|
+
source: opts.source ?? "precomputedTextMeasurements"
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
function cellTextMeasurements(opts) {
|
|
451
|
+
const targetId = opts.targetId ?? "text";
|
|
452
|
+
const adapter = opts.graph.state(new CellMeasureAdapter(opts), {
|
|
453
|
+
name: opts.name ? scopedName(opts.name, "measure-capability") : `${targetId}-measure-capability`
|
|
454
|
+
});
|
|
455
|
+
return textMeasurementProvider({
|
|
456
|
+
...opts,
|
|
457
|
+
adapter,
|
|
458
|
+
source: opts.source ?? "cellTextMeasurements"
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
function capabilityTextMeasurements(opts) {
|
|
462
|
+
const targetId = opts.targetId ?? "text";
|
|
463
|
+
const adapter = opts.graph.node(
|
|
464
|
+
[opts.capability],
|
|
465
|
+
(ctx) => {
|
|
466
|
+
ctx.down([
|
|
467
|
+
["DATA", new CapabilityMeasureAdapter(depLatest(ctx, 0))]
|
|
468
|
+
]);
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
name: opts.name ? scopedName(opts.name, "measure-capability") : `${targetId}-measure-capability`
|
|
472
|
+
}
|
|
473
|
+
);
|
|
474
|
+
return textMeasurementProvider({
|
|
475
|
+
...opts,
|
|
476
|
+
adapter,
|
|
477
|
+
source: opts.source ?? "capabilityTextMeasurements"
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
function readinessTextMeasurements(opts) {
|
|
481
|
+
const targetId = opts.targetId ?? "text";
|
|
482
|
+
const name = opts.name ?? `${targetId}-measurements`;
|
|
483
|
+
const source = opts.source ?? name;
|
|
484
|
+
const cache = /* @__PURE__ */ new Map();
|
|
485
|
+
let activeAdapter = null;
|
|
486
|
+
let activeReadiness = null;
|
|
487
|
+
const deps = opts.segmentAdapter ? [opts.text, opts.font, opts.adapter, opts.readiness, opts.segmentAdapter] : [opts.text, opts.font, opts.adapter, opts.readiness];
|
|
488
|
+
return opts.graph.node(
|
|
489
|
+
deps,
|
|
490
|
+
(ctx) => {
|
|
491
|
+
const flush = () => {
|
|
492
|
+
cache.clear();
|
|
493
|
+
depLatest(ctx, 2).clearCache?.();
|
|
494
|
+
};
|
|
495
|
+
ctx.onDeactivation(flush);
|
|
496
|
+
ctx.onInvalidate(flush);
|
|
497
|
+
const text = depLatest(ctx, 0);
|
|
498
|
+
const font = depLatest(ctx, 1);
|
|
499
|
+
const adapter = depLatest(ctx, 2);
|
|
500
|
+
if (adapter !== activeAdapter) {
|
|
501
|
+
cache.clear();
|
|
502
|
+
activeAdapter = adapter;
|
|
503
|
+
}
|
|
504
|
+
const readiness = depLatest(ctx, 3);
|
|
505
|
+
if (readiness !== activeReadiness) {
|
|
506
|
+
cache.clear();
|
|
507
|
+
activeReadiness = readiness;
|
|
508
|
+
}
|
|
509
|
+
if (!readiness.ready) {
|
|
510
|
+
ctx.down([
|
|
511
|
+
[
|
|
512
|
+
"DATA",
|
|
513
|
+
[
|
|
514
|
+
measurementIssue(
|
|
515
|
+
readiness.code ?? "measurement.not-ready",
|
|
516
|
+
readiness.message ?? `Measurement readiness blocked '${targetId}'`,
|
|
517
|
+
targetId,
|
|
518
|
+
TEXT_SEGMENTS_MEASUREMENT_KIND,
|
|
519
|
+
{
|
|
520
|
+
source: readiness.source ?? source,
|
|
521
|
+
details: readiness.details,
|
|
522
|
+
metadata: readiness.metadata,
|
|
523
|
+
severity: "warning"
|
|
524
|
+
}
|
|
525
|
+
)
|
|
526
|
+
]
|
|
527
|
+
]
|
|
528
|
+
]);
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
const segmentAdapter = opts.segmentAdapter === void 0 ? getDefaultSegmentAdapter() : depLatest(ctx, 4);
|
|
532
|
+
ctx.down([
|
|
533
|
+
[
|
|
534
|
+
"DATA",
|
|
535
|
+
textMeasurementFacts(text, font, adapter, cache, segmentAdapter, targetId, source)
|
|
536
|
+
]
|
|
537
|
+
]);
|
|
538
|
+
},
|
|
539
|
+
{ name }
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
function readinessMeasurements(opts) {
|
|
543
|
+
const targetId = opts.targetId ?? "measurement-readiness";
|
|
544
|
+
const measurementKind = opts.measurementKind ?? READINESS_MEASUREMENT_KIND;
|
|
545
|
+
const name = opts.name ?? `${targetId}-measurements`;
|
|
546
|
+
const source = opts.source ?? name;
|
|
547
|
+
return opts.graph.node(
|
|
548
|
+
[opts.readiness],
|
|
549
|
+
(ctx) => {
|
|
550
|
+
const readiness = depLatest(ctx, 0);
|
|
551
|
+
if (!readiness.ready) {
|
|
552
|
+
ctx.down([
|
|
553
|
+
[
|
|
554
|
+
"DATA",
|
|
555
|
+
[
|
|
556
|
+
measurementIssue(
|
|
557
|
+
readiness.code ?? "measurement.not-ready",
|
|
558
|
+
readiness.message ?? `Measurement readiness blocked '${targetId}'`,
|
|
559
|
+
targetId,
|
|
560
|
+
measurementKind,
|
|
561
|
+
{
|
|
562
|
+
source: readiness.source ?? source,
|
|
563
|
+
details: readiness.details,
|
|
564
|
+
metadata: readiness.metadata,
|
|
565
|
+
severity: "warning"
|
|
566
|
+
}
|
|
567
|
+
)
|
|
568
|
+
]
|
|
569
|
+
]
|
|
570
|
+
]);
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
ctx.down([
|
|
574
|
+
[
|
|
575
|
+
"DATA",
|
|
576
|
+
[
|
|
577
|
+
measurementOk(targetId, measurementKind, readiness, {
|
|
578
|
+
source: readiness.source ?? source,
|
|
579
|
+
metadata: readiness.metadata
|
|
580
|
+
})
|
|
581
|
+
]
|
|
582
|
+
]
|
|
583
|
+
]);
|
|
584
|
+
},
|
|
585
|
+
{ name }
|
|
586
|
+
);
|
|
587
|
+
}
|
|
588
|
+
function imageSizeMeasurements(opts) {
|
|
589
|
+
const measurementKind = opts.measurementKind ?? IMAGE_SIZE_MEASUREMENT_KIND;
|
|
590
|
+
const name = opts.name ?? "image-size-measurements";
|
|
591
|
+
const source = opts.source ?? name;
|
|
592
|
+
return opts.graph.node(
|
|
593
|
+
[opts.images, opts.measurer],
|
|
594
|
+
(ctx) => {
|
|
595
|
+
const images = depLatest(ctx, 0);
|
|
596
|
+
const measurer = depLatest(ctx, 1);
|
|
597
|
+
const facts = [];
|
|
598
|
+
for (let i = 0; i < images.length; i += 1) {
|
|
599
|
+
const image = images[i];
|
|
600
|
+
const subjectId = image?.id ?? image?.src ?? `image:${i}`;
|
|
601
|
+
try {
|
|
602
|
+
if (image === void 0) throw new Error(`Missing image target at index ${i}`);
|
|
603
|
+
facts.push(
|
|
604
|
+
measurementOk(
|
|
605
|
+
subjectId,
|
|
606
|
+
measurementKind,
|
|
607
|
+
validMeasurementSize(measurer.measureImage(image.src), "image"),
|
|
608
|
+
{
|
|
609
|
+
source,
|
|
610
|
+
metadata: image.metadata
|
|
611
|
+
}
|
|
612
|
+
)
|
|
613
|
+
);
|
|
614
|
+
} catch (error) {
|
|
615
|
+
facts.push(
|
|
616
|
+
measurementIssue(
|
|
617
|
+
"measurement.image-size.failed",
|
|
618
|
+
`Image size measurement failed for '${subjectId}'`,
|
|
619
|
+
subjectId,
|
|
620
|
+
measurementKind,
|
|
621
|
+
{
|
|
622
|
+
source,
|
|
623
|
+
details: { error, index: i, src: image?.src },
|
|
624
|
+
metadata: image?.metadata,
|
|
625
|
+
severity: "error"
|
|
626
|
+
}
|
|
627
|
+
)
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
ctx.down([["DATA", facts]]);
|
|
632
|
+
},
|
|
633
|
+
{ name }
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
function svgBoundsMeasurements(opts) {
|
|
637
|
+
const measurementKind = opts.measurementKind ?? SVG_BOUNDS_MEASUREMENT_KIND;
|
|
638
|
+
const name = opts.name ?? "svg-bounds-measurements";
|
|
639
|
+
const source = opts.source ?? name;
|
|
640
|
+
return opts.graph.node(
|
|
641
|
+
[opts.svgs, opts.measurer],
|
|
642
|
+
(ctx) => {
|
|
643
|
+
const svgs = depLatest(ctx, 0);
|
|
644
|
+
const measurer = depLatest(ctx, 1);
|
|
645
|
+
const facts = [];
|
|
646
|
+
for (let i = 0; i < svgs.length; i += 1) {
|
|
647
|
+
const svg = svgs[i];
|
|
648
|
+
const subjectId = svg?.id ?? `svg:${i}`;
|
|
649
|
+
try {
|
|
650
|
+
if (svg === void 0) throw new Error(`Missing SVG target at index ${i}`);
|
|
651
|
+
facts.push(
|
|
652
|
+
measurementOk(
|
|
653
|
+
subjectId,
|
|
654
|
+
measurementKind,
|
|
655
|
+
validMeasurementSize(measurer.measureSvg(svg.svg), "SVG"),
|
|
656
|
+
{
|
|
657
|
+
source,
|
|
658
|
+
metadata: svg.metadata
|
|
659
|
+
}
|
|
660
|
+
)
|
|
661
|
+
);
|
|
662
|
+
} catch (error) {
|
|
663
|
+
facts.push(
|
|
664
|
+
measurementIssue(
|
|
665
|
+
"measurement.svg-bounds.failed",
|
|
666
|
+
`SVG bounds measurement failed for '${subjectId}'`,
|
|
667
|
+
subjectId,
|
|
668
|
+
measurementKind,
|
|
669
|
+
{
|
|
670
|
+
source,
|
|
671
|
+
details: { error, index: i },
|
|
672
|
+
metadata: svg?.metadata,
|
|
673
|
+
severity: "error"
|
|
674
|
+
}
|
|
675
|
+
)
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
ctx.down([["DATA", facts]]);
|
|
680
|
+
},
|
|
681
|
+
{ name }
|
|
682
|
+
);
|
|
683
|
+
}
|
|
684
|
+
function mergeMeasurements(opts) {
|
|
685
|
+
const sources = [...opts.sources];
|
|
686
|
+
return opts.graph.node(
|
|
687
|
+
sources,
|
|
688
|
+
(ctx) => {
|
|
689
|
+
const facts = [];
|
|
690
|
+
for (let i = 0; i < sources.length; i += 1) {
|
|
691
|
+
facts.push(...depLatest(ctx, i));
|
|
692
|
+
}
|
|
693
|
+
ctx.down([["DATA", facts]]);
|
|
694
|
+
},
|
|
695
|
+
{ name: opts.name ?? "measurements" }
|
|
696
|
+
);
|
|
697
|
+
}
|
|
698
|
+
function blockAdaptersProvider(opts) {
|
|
699
|
+
const deps = [];
|
|
700
|
+
const positions = {};
|
|
701
|
+
if (opts.text) {
|
|
702
|
+
positions.text = deps.length;
|
|
703
|
+
deps.push(opts.text);
|
|
704
|
+
}
|
|
705
|
+
if (opts.svg) {
|
|
706
|
+
positions.svg = deps.length;
|
|
707
|
+
deps.push(opts.svg);
|
|
708
|
+
}
|
|
709
|
+
if (opts.image) {
|
|
710
|
+
positions.image = deps.length;
|
|
711
|
+
deps.push(opts.image);
|
|
712
|
+
}
|
|
713
|
+
return opts.graph.node(
|
|
714
|
+
deps,
|
|
715
|
+
(ctx) => {
|
|
716
|
+
const adapters = {
|
|
717
|
+
text: positions.text === void 0 ? void 0 : depLatest(ctx, positions.text),
|
|
718
|
+
svg: positions.svg === void 0 ? void 0 : depLatest(ctx, positions.svg),
|
|
719
|
+
image: positions.image === void 0 ? void 0 : depLatest(ctx, positions.image)
|
|
720
|
+
};
|
|
721
|
+
ctx.down([["DATA", adapters]]);
|
|
722
|
+
},
|
|
723
|
+
{ name: opts.name ?? "block-adapters" }
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
function blockMeasurementProvider(opts) {
|
|
727
|
+
const targetId = opts.targetId ?? "blocks";
|
|
728
|
+
const name = opts.name ?? `${targetId}-measurements`;
|
|
729
|
+
const source = opts.source ?? name;
|
|
730
|
+
const cache = /* @__PURE__ */ new Map();
|
|
731
|
+
let activeTextAdapter;
|
|
732
|
+
const deps = [opts.blocks, opts.maxWidth, opts.adapters];
|
|
733
|
+
if (opts.font) deps.push(opts.font);
|
|
734
|
+
if (opts.lineHeight) deps.push(opts.lineHeight);
|
|
735
|
+
if (opts.segmentAdapter) deps.push(opts.segmentAdapter);
|
|
736
|
+
return opts.graph.node(
|
|
737
|
+
deps,
|
|
738
|
+
(ctx) => {
|
|
739
|
+
const flush = () => {
|
|
740
|
+
cache.clear();
|
|
741
|
+
const adapters = depLatest(ctx, 2);
|
|
742
|
+
adapters.text?.clearCache?.();
|
|
743
|
+
};
|
|
744
|
+
ctx.onDeactivation(flush);
|
|
745
|
+
ctx.onInvalidate(flush);
|
|
746
|
+
try {
|
|
747
|
+
const blocks = depLatest(ctx, 0);
|
|
748
|
+
const maxWidth = nonNegativeFinite(depLatest(ctx, 1), 0);
|
|
749
|
+
const adapters = depLatest(ctx, 2);
|
|
750
|
+
if (adapters.text !== activeTextAdapter) {
|
|
751
|
+
cache.clear();
|
|
752
|
+
activeTextAdapter = adapters.text;
|
|
753
|
+
}
|
|
754
|
+
let depIndex = 3;
|
|
755
|
+
const font = opts.font ? depLatest(ctx, depIndex++) : void 0;
|
|
756
|
+
const lineHeight = opts.lineHeight ? nonNegativeFinite(depLatest(ctx, depIndex++), 0) : void 0;
|
|
757
|
+
const segmentAdapter = opts.segmentAdapter ? depLatest(ctx, depIndex) : getDefaultSegmentAdapter();
|
|
758
|
+
const measured = [];
|
|
759
|
+
const issues = [];
|
|
760
|
+
for (let i = 0; i < blocks.length; i += 1) {
|
|
761
|
+
const block = blocks[i];
|
|
762
|
+
const subjectId = block?.id ?? `${targetId}:${i}`;
|
|
763
|
+
try {
|
|
764
|
+
if (block === void 0) {
|
|
765
|
+
throw new Error(`Missing content block at index ${i}`);
|
|
766
|
+
}
|
|
767
|
+
const blockFont = block.kind === "text" ? block.font ?? font ?? "16px sans-serif" : void 0;
|
|
768
|
+
const hyphenWidth = block.kind === "text" && adapters.text ? tryMeasureHyphenWidth(adapters.text, blockFont ?? "16px sans-serif") : void 0;
|
|
769
|
+
measured.push(
|
|
770
|
+
measureBlock(block, {
|
|
771
|
+
adapters,
|
|
772
|
+
font,
|
|
773
|
+
hyphenWidth,
|
|
774
|
+
lineHeight,
|
|
775
|
+
maxWidth,
|
|
776
|
+
cache,
|
|
777
|
+
segmentAdapter
|
|
778
|
+
})
|
|
779
|
+
);
|
|
780
|
+
if (block.kind === "text" && adapters.text) {
|
|
781
|
+
if (hyphenWidth === void 0) {
|
|
782
|
+
issues.push(
|
|
783
|
+
measurementIssue(
|
|
784
|
+
"measurement.hyphen.failed",
|
|
785
|
+
`Hyphen measurement failed for '${subjectId}'`,
|
|
786
|
+
subjectId,
|
|
787
|
+
BLOCKS_MEASUREMENT_KIND,
|
|
788
|
+
{
|
|
789
|
+
source,
|
|
790
|
+
details: { targetId, index: i },
|
|
791
|
+
severity: "warning"
|
|
792
|
+
}
|
|
793
|
+
)
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
} catch (error) {
|
|
798
|
+
issues.push(
|
|
799
|
+
measurementIssue(
|
|
800
|
+
"measurement.block.failed",
|
|
801
|
+
`Block measurement failed for '${subjectId}'`,
|
|
802
|
+
subjectId,
|
|
803
|
+
BLOCKS_MEASUREMENT_KIND,
|
|
804
|
+
{
|
|
805
|
+
source,
|
|
806
|
+
details: { error, targetId, index: i, blockKind: block?.kind },
|
|
807
|
+
severity: "error"
|
|
808
|
+
}
|
|
809
|
+
)
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
ctx.down([
|
|
814
|
+
[
|
|
815
|
+
"DATA",
|
|
816
|
+
[
|
|
817
|
+
measurementOk(
|
|
818
|
+
targetId,
|
|
819
|
+
BLOCKS_MEASUREMENT_KIND,
|
|
820
|
+
{ blocks: measured },
|
|
821
|
+
{ source }
|
|
822
|
+
),
|
|
823
|
+
...issues
|
|
824
|
+
]
|
|
825
|
+
]
|
|
826
|
+
]);
|
|
827
|
+
} catch (error) {
|
|
828
|
+
ctx.down([
|
|
829
|
+
[
|
|
830
|
+
"DATA",
|
|
831
|
+
[
|
|
832
|
+
measurementIssue(
|
|
833
|
+
"measurement.failed",
|
|
834
|
+
`Block measurement failed for '${targetId}'`,
|
|
835
|
+
targetId,
|
|
836
|
+
BLOCKS_MEASUREMENT_KIND,
|
|
837
|
+
{ source, details: error, severity: "error" }
|
|
838
|
+
)
|
|
839
|
+
]
|
|
840
|
+
]
|
|
841
|
+
]);
|
|
842
|
+
}
|
|
843
|
+
},
|
|
844
|
+
{ name }
|
|
845
|
+
);
|
|
846
|
+
}
|
|
847
|
+
function analyzeAndMeasure(text, font, adapter, cache, stats, segmentAdapter) {
|
|
848
|
+
const normalized = normalizeWhitespace(text);
|
|
849
|
+
if (normalized.length === 0) {
|
|
850
|
+
return [];
|
|
851
|
+
}
|
|
852
|
+
const segAdapter = segmentAdapter ?? getDefaultSegmentAdapter();
|
|
853
|
+
const pieces = segmentText(normalized, segAdapter);
|
|
854
|
+
const rawTexts = [];
|
|
855
|
+
const rawKinds = [];
|
|
856
|
+
const rawWordLike = [];
|
|
857
|
+
for (const piece of pieces) {
|
|
858
|
+
for (let i = 0; i < piece.texts.length; i += 1) {
|
|
859
|
+
rawTexts.push(piece.texts[i]);
|
|
860
|
+
rawKinds.push(piece.kinds[i]);
|
|
861
|
+
rawWordLike.push(piece.isWordLike[i]);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
const mergedTexts = [];
|
|
865
|
+
const mergedKinds = [];
|
|
866
|
+
const mergedWordLike = [];
|
|
867
|
+
for (let i = 0; i < rawTexts.length; i += 1) {
|
|
868
|
+
const t = rawTexts[i];
|
|
869
|
+
const k = rawKinds[i];
|
|
870
|
+
const wl = rawWordLike[i];
|
|
871
|
+
if (k === "text" && !wl && mergedTexts.length > 0 && mergedKinds[mergedTexts.length - 1] === "text") {
|
|
872
|
+
const isSticky = t.length === 1 && (leftStickyPunctuation.has(t) || kinsokuStart.has(t));
|
|
873
|
+
if (isSticky) {
|
|
874
|
+
mergedTexts[mergedTexts.length - 1] += t;
|
|
875
|
+
continue;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
if (t === "-" && mergedTexts.length > 0 && mergedKinds[mergedKinds.length - 1] === "text" && mergedWordLike[mergedWordLike.length - 1]) {
|
|
879
|
+
mergedTexts[mergedTexts.length - 1] += t;
|
|
880
|
+
continue;
|
|
881
|
+
}
|
|
882
|
+
mergedTexts.push(t);
|
|
883
|
+
mergedKinds.push(k);
|
|
884
|
+
mergedWordLike.push(wl);
|
|
885
|
+
}
|
|
886
|
+
const fontCache = cache.get(font) ?? /* @__PURE__ */ new Map();
|
|
887
|
+
if (!cache.has(font)) cache.set(font, fontCache);
|
|
888
|
+
function measureCached(segment) {
|
|
889
|
+
const cached = fontCache.get(segment);
|
|
890
|
+
if (cached === void 0) {
|
|
891
|
+
if (stats) stats.misses += 1;
|
|
892
|
+
const measured = adapter.measureSegment(segment, font).width;
|
|
893
|
+
const width = Number.isFinite(measured) && measured >= 0 ? measured : 0;
|
|
894
|
+
fontCache.set(segment, width);
|
|
895
|
+
return width;
|
|
896
|
+
}
|
|
897
|
+
if (stats) stats.hits += 1;
|
|
898
|
+
return cached;
|
|
899
|
+
}
|
|
900
|
+
const out = [];
|
|
901
|
+
for (let i = 0; i < mergedTexts.length; i += 1) {
|
|
902
|
+
const t = mergedTexts[i];
|
|
903
|
+
const kind = mergedKinds[i];
|
|
904
|
+
if (kind !== "text") {
|
|
905
|
+
out.push({
|
|
906
|
+
text: t,
|
|
907
|
+
width: kind === "space" ? measureCached(" ") * t.length : 0,
|
|
908
|
+
kind,
|
|
909
|
+
graphemeWidths: null
|
|
910
|
+
});
|
|
911
|
+
continue;
|
|
912
|
+
}
|
|
913
|
+
if (isCJK(t)) {
|
|
914
|
+
let unitText = "";
|
|
915
|
+
for (const graphemeSegment of segAdapter.segmentGraphemes(t)) {
|
|
916
|
+
const grapheme = graphemeSegment.segment;
|
|
917
|
+
if (unitText.length > 0 && kinsokuStart.has(grapheme)) {
|
|
918
|
+
unitText += grapheme;
|
|
919
|
+
continue;
|
|
920
|
+
}
|
|
921
|
+
if (unitText.length > 0) {
|
|
922
|
+
out.push({
|
|
923
|
+
text: unitText,
|
|
924
|
+
width: measureCached(unitText),
|
|
925
|
+
kind: "text",
|
|
926
|
+
graphemeWidths: null
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
unitText = grapheme;
|
|
930
|
+
}
|
|
931
|
+
if (unitText.length > 0) {
|
|
932
|
+
out.push({
|
|
933
|
+
text: unitText,
|
|
934
|
+
width: measureCached(unitText),
|
|
935
|
+
kind: "text",
|
|
936
|
+
graphemeWidths: null
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
continue;
|
|
940
|
+
}
|
|
941
|
+
const textWidth = measureCached(t);
|
|
942
|
+
let graphemeWidths = null;
|
|
943
|
+
if (mergedWordLike[i] && t.length > 1) {
|
|
944
|
+
const widths = [];
|
|
945
|
+
for (const grapheme of segAdapter.segmentGraphemes(t)) {
|
|
946
|
+
widths.push(measureCached(grapheme.segment));
|
|
947
|
+
}
|
|
948
|
+
if (widths.length > 1) graphemeWidths = widths;
|
|
949
|
+
}
|
|
950
|
+
out.push({
|
|
951
|
+
text: t,
|
|
952
|
+
width: textWidth,
|
|
953
|
+
kind: "text",
|
|
954
|
+
graphemeWidths
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
return out;
|
|
958
|
+
}
|
|
959
|
+
function computeLineBreaks(segments, maxWidth, opts = {}) {
|
|
960
|
+
if (segments.length === 0) return { lines: [], lineCount: 0 };
|
|
961
|
+
const segAdapter = opts.segmentAdapter ?? getDefaultSegmentAdapter();
|
|
962
|
+
const lines = [];
|
|
963
|
+
let cursor = { segmentIndex: 0, graphemeIndex: 0 };
|
|
964
|
+
while (cursor.segmentIndex < segments.length) {
|
|
965
|
+
const next = layoutNextLine(segments, cursor, maxWidth, {
|
|
966
|
+
hyphenWidth: opts.hyphenWidth,
|
|
967
|
+
segmentAdapter: segAdapter
|
|
968
|
+
});
|
|
969
|
+
if (next === null) break;
|
|
970
|
+
lines.push({
|
|
971
|
+
text: next.text,
|
|
972
|
+
width: next.width,
|
|
973
|
+
startSegment: next.start.segmentIndex,
|
|
974
|
+
startGrapheme: next.start.graphemeIndex,
|
|
975
|
+
endSegment: next.end.segmentIndex,
|
|
976
|
+
endGrapheme: next.end.graphemeIndex
|
|
977
|
+
});
|
|
978
|
+
if (next.end.segmentIndex === cursor.segmentIndex && next.end.graphemeIndex === cursor.graphemeIndex) {
|
|
979
|
+
break;
|
|
980
|
+
}
|
|
981
|
+
cursor = next.end;
|
|
982
|
+
}
|
|
983
|
+
return { lines, lineCount: lines.length };
|
|
984
|
+
}
|
|
985
|
+
function canBreakAfter(kind) {
|
|
986
|
+
return kind === "space" || kind === "zero-width-break" || kind === "soft-hyphen";
|
|
987
|
+
}
|
|
988
|
+
function sliceSegmentText(seg, startGrapheme, endGrapheme, segmentAdapter) {
|
|
989
|
+
if (startGrapheme === 0 && endGrapheme < 0) return seg.text;
|
|
990
|
+
const graphemes = [...segmentAdapter.segmentGraphemes(seg.text)].map((g) => g.segment);
|
|
991
|
+
const stop = endGrapheme < 0 ? graphemes.length : endGrapheme;
|
|
992
|
+
return graphemes.slice(startGrapheme, stop).join("");
|
|
993
|
+
}
|
|
994
|
+
function buildLineText(segments, startSegment, startGrapheme, endSegment, endGrapheme, appendHyphen, segmentAdapter) {
|
|
995
|
+
let text = "";
|
|
996
|
+
for (let i = startSegment; i < endSegment; i += 1) {
|
|
997
|
+
const seg = segments[i];
|
|
998
|
+
if (seg.kind === "soft-hyphen" || seg.kind === "hard-break") continue;
|
|
999
|
+
if (i === startSegment && startGrapheme > 0) {
|
|
1000
|
+
text += sliceSegmentText(seg, startGrapheme, -1, segmentAdapter);
|
|
1001
|
+
} else {
|
|
1002
|
+
text += seg.text;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
if (endGrapheme > 0 && endSegment < segments.length) {
|
|
1006
|
+
const seg = segments[endSegment];
|
|
1007
|
+
const from = startSegment === endSegment ? startGrapheme : 0;
|
|
1008
|
+
text += sliceSegmentText(seg, from, endGrapheme, segmentAdapter);
|
|
1009
|
+
}
|
|
1010
|
+
if (appendHyphen) text += "-";
|
|
1011
|
+
return text;
|
|
1012
|
+
}
|
|
1013
|
+
function resolveHyphenWidth(ctx) {
|
|
1014
|
+
if (ctx?.hyphenWidth !== void 0) return nonNegativeFinite(ctx.hyphenWidth, 0);
|
|
1015
|
+
if (ctx?.adapter === void 0 || ctx.font === void 0) return 0;
|
|
1016
|
+
const cache = ctx.cache;
|
|
1017
|
+
if (cache) {
|
|
1018
|
+
let fontCache = cache.get(ctx.font);
|
|
1019
|
+
if (fontCache === void 0) {
|
|
1020
|
+
fontCache = /* @__PURE__ */ new Map();
|
|
1021
|
+
cache.set(ctx.font, fontCache);
|
|
1022
|
+
}
|
|
1023
|
+
let width = fontCache.get("-");
|
|
1024
|
+
if (width === void 0) {
|
|
1025
|
+
width = ctx.adapter.measureSegment("-", ctx.font).width;
|
|
1026
|
+
fontCache.set("-", width);
|
|
1027
|
+
}
|
|
1028
|
+
return width;
|
|
1029
|
+
}
|
|
1030
|
+
return ctx.adapter.measureSegment("-", ctx.font).width;
|
|
1031
|
+
}
|
|
1032
|
+
function layoutNextLine(segments, cursor, slotWidth, ctx) {
|
|
1033
|
+
let i = cursor.segmentIndex;
|
|
1034
|
+
const initialGrapheme = cursor.graphemeIndex;
|
|
1035
|
+
const segmentAdapter = ctx?.segmentAdapter ?? getDefaultSegmentAdapter();
|
|
1036
|
+
if (i >= segments.length) return null;
|
|
1037
|
+
if (initialGrapheme === 0) {
|
|
1038
|
+
while (i < segments.length) {
|
|
1039
|
+
const seg = segments[i];
|
|
1040
|
+
if (seg.kind === "hard-break") {
|
|
1041
|
+
return {
|
|
1042
|
+
text: "",
|
|
1043
|
+
width: 0,
|
|
1044
|
+
start: { segmentIndex: cursor.segmentIndex, graphemeIndex: 0 },
|
|
1045
|
+
end: { segmentIndex: i + 1, graphemeIndex: 0 }
|
|
1046
|
+
};
|
|
1047
|
+
}
|
|
1048
|
+
if (seg.kind === "space" || seg.kind === "zero-width-break" || seg.kind === "soft-hyphen") {
|
|
1049
|
+
i += 1;
|
|
1050
|
+
continue;
|
|
1051
|
+
}
|
|
1052
|
+
break;
|
|
1053
|
+
}
|
|
1054
|
+
if (i >= segments.length) return null;
|
|
1055
|
+
}
|
|
1056
|
+
const hyphenWidth = resolveHyphenWidth(ctx);
|
|
1057
|
+
const startSegment = i;
|
|
1058
|
+
const startGrapheme = i === cursor.segmentIndex ? initialGrapheme : 0;
|
|
1059
|
+
let lineW = 0;
|
|
1060
|
+
let lineEndSegment = startSegment;
|
|
1061
|
+
let lineEndGrapheme = 0;
|
|
1062
|
+
let hasContent = false;
|
|
1063
|
+
let pendingBreakSegment = -1;
|
|
1064
|
+
let pendingBreakGrapheme = 0;
|
|
1065
|
+
let pendingBreakWidth = 0;
|
|
1066
|
+
let pendingBreakSoftHyphen = false;
|
|
1067
|
+
const recordPending = (sIdx, gIdx, width, kind) => {
|
|
1068
|
+
pendingBreakSegment = sIdx;
|
|
1069
|
+
pendingBreakGrapheme = gIdx;
|
|
1070
|
+
pendingBreakWidth = width;
|
|
1071
|
+
pendingBreakSoftHyphen = kind === "soft-hyphen";
|
|
1072
|
+
};
|
|
1073
|
+
const consumeBreakable = (segIdx, startG, widths) => {
|
|
1074
|
+
for (let g = startG; g < widths.length; g += 1) {
|
|
1075
|
+
const gw = widths[g];
|
|
1076
|
+
if (!hasContent) {
|
|
1077
|
+
lineW = gw;
|
|
1078
|
+
lineEndSegment = segIdx;
|
|
1079
|
+
lineEndGrapheme = g + 1;
|
|
1080
|
+
hasContent = true;
|
|
1081
|
+
continue;
|
|
1082
|
+
}
|
|
1083
|
+
if (lineW + gw > slotWidth + 1e-3) {
|
|
1084
|
+
return true;
|
|
1085
|
+
}
|
|
1086
|
+
lineW += gw;
|
|
1087
|
+
lineEndSegment = segIdx;
|
|
1088
|
+
lineEndGrapheme = g + 1;
|
|
1089
|
+
}
|
|
1090
|
+
if (lineEndSegment === segIdx && lineEndGrapheme === widths.length) {
|
|
1091
|
+
lineEndSegment = segIdx + 1;
|
|
1092
|
+
lineEndGrapheme = 0;
|
|
1093
|
+
}
|
|
1094
|
+
return false;
|
|
1095
|
+
};
|
|
1096
|
+
if (startGrapheme > 0 && startSegment < segments.length) {
|
|
1097
|
+
const seg = segments[startSegment];
|
|
1098
|
+
if (seg.graphemeWidths) {
|
|
1099
|
+
const overflow = consumeBreakable(startSegment, startGrapheme, seg.graphemeWidths);
|
|
1100
|
+
if (overflow) {
|
|
1101
|
+
const text2 = buildLineText(
|
|
1102
|
+
segments,
|
|
1103
|
+
startSegment,
|
|
1104
|
+
startGrapheme,
|
|
1105
|
+
lineEndSegment,
|
|
1106
|
+
lineEndGrapheme,
|
|
1107
|
+
false,
|
|
1108
|
+
segmentAdapter
|
|
1109
|
+
);
|
|
1110
|
+
return {
|
|
1111
|
+
text: text2,
|
|
1112
|
+
width: lineW,
|
|
1113
|
+
start: { segmentIndex: startSegment, graphemeIndex: startGrapheme },
|
|
1114
|
+
end: { segmentIndex: lineEndSegment, graphemeIndex: lineEndGrapheme }
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
i = lineEndSegment;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
for (; i < segments.length; i += 1) {
|
|
1121
|
+
const seg = segments[i];
|
|
1122
|
+
if (seg.kind === "hard-break") {
|
|
1123
|
+
if (hasContent) {
|
|
1124
|
+
const endsAtSoftHyphen2 = lineEndSegment > 0 && segments[lineEndSegment - 1]?.kind === "soft-hyphen";
|
|
1125
|
+
const text2 = buildLineText(
|
|
1126
|
+
segments,
|
|
1127
|
+
startSegment,
|
|
1128
|
+
startGrapheme,
|
|
1129
|
+
lineEndSegment,
|
|
1130
|
+
lineEndGrapheme,
|
|
1131
|
+
endsAtSoftHyphen2,
|
|
1132
|
+
segmentAdapter
|
|
1133
|
+
);
|
|
1134
|
+
return {
|
|
1135
|
+
text: text2,
|
|
1136
|
+
width: lineW + (endsAtSoftHyphen2 ? hyphenWidth : 0),
|
|
1137
|
+
start: { segmentIndex: startSegment, graphemeIndex: startGrapheme },
|
|
1138
|
+
end: { segmentIndex: i + 1, graphemeIndex: 0 }
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
return {
|
|
1142
|
+
text: "",
|
|
1143
|
+
width: 0,
|
|
1144
|
+
start: { segmentIndex: startSegment, graphemeIndex: startGrapheme },
|
|
1145
|
+
end: { segmentIndex: i + 1, graphemeIndex: 0 }
|
|
1146
|
+
};
|
|
1147
|
+
}
|
|
1148
|
+
const w = seg.width;
|
|
1149
|
+
if (!hasContent) {
|
|
1150
|
+
if (w > slotWidth && seg.graphemeWidths) {
|
|
1151
|
+
const overflow = consumeBreakable(i, 0, seg.graphemeWidths);
|
|
1152
|
+
if (overflow) {
|
|
1153
|
+
const text2 = buildLineText(
|
|
1154
|
+
segments,
|
|
1155
|
+
startSegment,
|
|
1156
|
+
startGrapheme,
|
|
1157
|
+
lineEndSegment,
|
|
1158
|
+
lineEndGrapheme,
|
|
1159
|
+
false,
|
|
1160
|
+
segmentAdapter
|
|
1161
|
+
);
|
|
1162
|
+
return {
|
|
1163
|
+
text: text2,
|
|
1164
|
+
width: lineW,
|
|
1165
|
+
start: { segmentIndex: startSegment, graphemeIndex: startGrapheme },
|
|
1166
|
+
end: { segmentIndex: lineEndSegment, graphemeIndex: lineEndGrapheme }
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
i = lineEndSegment - 1;
|
|
1170
|
+
continue;
|
|
1171
|
+
}
|
|
1172
|
+
lineW = w;
|
|
1173
|
+
lineEndSegment = i + 1;
|
|
1174
|
+
lineEndGrapheme = 0;
|
|
1175
|
+
hasContent = true;
|
|
1176
|
+
if (canBreakAfter(seg.kind)) {
|
|
1177
|
+
recordPending(i + 1, 0, seg.kind === "space" ? lineW - w : lineW, seg.kind);
|
|
1178
|
+
}
|
|
1179
|
+
continue;
|
|
1180
|
+
}
|
|
1181
|
+
const projectedWidth = lineW + w;
|
|
1182
|
+
if (projectedWidth > slotWidth + 1e-3) {
|
|
1183
|
+
if (canBreakAfter(seg.kind)) {
|
|
1184
|
+
lineEndSegment = i + 1;
|
|
1185
|
+
lineEndGrapheme = 0;
|
|
1186
|
+
const endsAtSoftHyphen2 = seg.kind === "soft-hyphen";
|
|
1187
|
+
const text3 = buildLineText(
|
|
1188
|
+
segments,
|
|
1189
|
+
startSegment,
|
|
1190
|
+
startGrapheme,
|
|
1191
|
+
lineEndSegment,
|
|
1192
|
+
lineEndGrapheme,
|
|
1193
|
+
endsAtSoftHyphen2,
|
|
1194
|
+
segmentAdapter
|
|
1195
|
+
);
|
|
1196
|
+
return {
|
|
1197
|
+
text: text3,
|
|
1198
|
+
width: seg.kind === "space" ? lineW : lineW + (endsAtSoftHyphen2 ? hyphenWidth : 0),
|
|
1199
|
+
start: { segmentIndex: startSegment, graphemeIndex: startGrapheme },
|
|
1200
|
+
end: { segmentIndex: lineEndSegment, graphemeIndex: lineEndGrapheme }
|
|
1201
|
+
};
|
|
1202
|
+
}
|
|
1203
|
+
if (pendingBreakSegment >= 0) {
|
|
1204
|
+
const text3 = buildLineText(
|
|
1205
|
+
segments,
|
|
1206
|
+
startSegment,
|
|
1207
|
+
startGrapheme,
|
|
1208
|
+
pendingBreakSegment,
|
|
1209
|
+
pendingBreakGrapheme,
|
|
1210
|
+
pendingBreakSoftHyphen,
|
|
1211
|
+
segmentAdapter
|
|
1212
|
+
);
|
|
1213
|
+
return {
|
|
1214
|
+
text: text3,
|
|
1215
|
+
width: pendingBreakWidth + (pendingBreakSoftHyphen ? hyphenWidth : 0),
|
|
1216
|
+
start: { segmentIndex: startSegment, graphemeIndex: startGrapheme },
|
|
1217
|
+
end: { segmentIndex: pendingBreakSegment, graphemeIndex: pendingBreakGrapheme }
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
if (w > slotWidth && seg.graphemeWidths) {
|
|
1221
|
+
const text3 = buildLineText(
|
|
1222
|
+
segments,
|
|
1223
|
+
startSegment,
|
|
1224
|
+
startGrapheme,
|
|
1225
|
+
lineEndSegment,
|
|
1226
|
+
lineEndGrapheme,
|
|
1227
|
+
false,
|
|
1228
|
+
segmentAdapter
|
|
1229
|
+
);
|
|
1230
|
+
return {
|
|
1231
|
+
text: text3,
|
|
1232
|
+
width: lineW,
|
|
1233
|
+
start: { segmentIndex: startSegment, graphemeIndex: startGrapheme },
|
|
1234
|
+
end: { segmentIndex: lineEndSegment, graphemeIndex: lineEndGrapheme }
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
const text2 = buildLineText(
|
|
1238
|
+
segments,
|
|
1239
|
+
startSegment,
|
|
1240
|
+
startGrapheme,
|
|
1241
|
+
lineEndSegment,
|
|
1242
|
+
lineEndGrapheme,
|
|
1243
|
+
false,
|
|
1244
|
+
segmentAdapter
|
|
1245
|
+
);
|
|
1246
|
+
return {
|
|
1247
|
+
text: text2,
|
|
1248
|
+
width: lineW,
|
|
1249
|
+
start: { segmentIndex: startSegment, graphemeIndex: startGrapheme },
|
|
1250
|
+
end: { segmentIndex: lineEndSegment, graphemeIndex: lineEndGrapheme }
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1253
|
+
lineW = projectedWidth;
|
|
1254
|
+
lineEndSegment = i + 1;
|
|
1255
|
+
lineEndGrapheme = 0;
|
|
1256
|
+
if (canBreakAfter(seg.kind)) {
|
|
1257
|
+
recordPending(i + 1, 0, seg.kind === "space" ? lineW - w : lineW, seg.kind);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
if (!hasContent) return null;
|
|
1261
|
+
const endsAtSoftHyphen = lineEndSegment > 0 && segments[lineEndSegment - 1]?.kind === "soft-hyphen";
|
|
1262
|
+
const text = buildLineText(
|
|
1263
|
+
segments,
|
|
1264
|
+
startSegment,
|
|
1265
|
+
startGrapheme,
|
|
1266
|
+
lineEndSegment,
|
|
1267
|
+
lineEndGrapheme,
|
|
1268
|
+
endsAtSoftHyphen,
|
|
1269
|
+
segmentAdapter
|
|
1270
|
+
);
|
|
1271
|
+
return {
|
|
1272
|
+
text,
|
|
1273
|
+
width: lineW + (endsAtSoftHyphen ? hyphenWidth : 0),
|
|
1274
|
+
start: { segmentIndex: startSegment, graphemeIndex: startGrapheme },
|
|
1275
|
+
end: { segmentIndex: lineEndSegment, graphemeIndex: lineEndGrapheme }
|
|
1276
|
+
};
|
|
1277
|
+
}
|
|
1278
|
+
function carveTextLineSlots(base, blocked, minSlotWidth = 0) {
|
|
1279
|
+
let slots = [base];
|
|
1280
|
+
for (const block of blocked) {
|
|
1281
|
+
const next = [];
|
|
1282
|
+
for (const slot of slots) {
|
|
1283
|
+
if (block.right <= slot.left || block.left >= slot.right) {
|
|
1284
|
+
next.push(slot);
|
|
1285
|
+
continue;
|
|
1286
|
+
}
|
|
1287
|
+
if (block.left > slot.left) next.push({ left: slot.left, right: block.left });
|
|
1288
|
+
if (block.right < slot.right) next.push({ left: block.right, right: slot.right });
|
|
1289
|
+
}
|
|
1290
|
+
slots = next;
|
|
1291
|
+
}
|
|
1292
|
+
if (minSlotWidth > 0) return slots.filter((slot) => slot.right - slot.left >= minSlotWidth);
|
|
1293
|
+
return slots;
|
|
1294
|
+
}
|
|
1295
|
+
function computeCharPositions(lineBreaks, segments, lineHeight, segmentAdapter) {
|
|
1296
|
+
const positions = [];
|
|
1297
|
+
const segAdapter = segmentAdapter ?? getDefaultSegmentAdapter();
|
|
1298
|
+
for (let lineIdx = 0; lineIdx < lineBreaks.lines.length; lineIdx += 1) {
|
|
1299
|
+
const line = lineBreaks.lines[lineIdx];
|
|
1300
|
+
const y = lineIdx * lineHeight;
|
|
1301
|
+
let x = 0;
|
|
1302
|
+
for (let si = line.startSegment; si < segments.length; si += 1) {
|
|
1303
|
+
const seg = segments[si];
|
|
1304
|
+
if (seg.kind === "soft-hyphen" || seg.kind === "hard-break") {
|
|
1305
|
+
if (si >= line.endSegment && line.endGrapheme === 0) break;
|
|
1306
|
+
continue;
|
|
1307
|
+
}
|
|
1308
|
+
const graphemes = [...segAdapter.segmentGraphemes(seg.text)].map((g) => g.segment);
|
|
1309
|
+
if (graphemes.length === 0) continue;
|
|
1310
|
+
const startGrapheme = si === line.startSegment ? line.startGrapheme : 0;
|
|
1311
|
+
let endGrapheme;
|
|
1312
|
+
if (si < line.endSegment) {
|
|
1313
|
+
endGrapheme = graphemes.length;
|
|
1314
|
+
} else if (si === line.endSegment && line.endGrapheme > 0) {
|
|
1315
|
+
endGrapheme = line.endGrapheme;
|
|
1316
|
+
} else {
|
|
1317
|
+
break;
|
|
1318
|
+
}
|
|
1319
|
+
for (let g = startGrapheme; g < endGrapheme; g += 1) {
|
|
1320
|
+
const width = seg.graphemeWidths ? seg.graphemeWidths[g] : seg.width / graphemes.length;
|
|
1321
|
+
positions.push({ x, y, width, height: lineHeight, line: lineIdx });
|
|
1322
|
+
x += width;
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
return positions;
|
|
1327
|
+
}
|
|
1328
|
+
function nonNegativeFinite(value, fallback) {
|
|
1329
|
+
return Number.isFinite(value) ? Math.max(0, value) : fallback;
|
|
1330
|
+
}
|
|
1331
|
+
function finiteNumber(value, fallback) {
|
|
1332
|
+
return Number.isFinite(value) ? value : fallback;
|
|
1333
|
+
}
|
|
1334
|
+
function emitLayoutError(ctx, error, fallback) {
|
|
1335
|
+
ctx.down([["ERROR", errorPayload(error, fallback)]]);
|
|
1336
|
+
}
|
|
1337
|
+
function positiveFinite(value, fallback) {
|
|
1338
|
+
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
1339
|
+
}
|
|
1340
|
+
function clampDimension(value) {
|
|
1341
|
+
return nonNegativeFinite(value ?? 0, 0);
|
|
1342
|
+
}
|
|
1343
|
+
function fitSize(size, maxWidth) {
|
|
1344
|
+
const width = nonNegativeFinite(size.width, 0);
|
|
1345
|
+
const height = nonNegativeFinite(size.height, 0);
|
|
1346
|
+
if (width === 0 || maxWidth <= 0 || width <= maxWidth) return { width, height };
|
|
1347
|
+
const scale = maxWidth / width;
|
|
1348
|
+
return { width: maxWidth, height: height * scale };
|
|
1349
|
+
}
|
|
1350
|
+
function blockMaxWidth(blockMaxWidth2, maxWidth) {
|
|
1351
|
+
const own = blockMaxWidth2 === void 0 ? maxWidth : nonNegativeFinite(blockMaxWidth2, maxWidth);
|
|
1352
|
+
if (maxWidth <= 0) return own;
|
|
1353
|
+
if (own <= 0) return maxWidth;
|
|
1354
|
+
return Math.min(own, maxWidth);
|
|
1355
|
+
}
|
|
1356
|
+
function resolveTextAdapter(opts) {
|
|
1357
|
+
const adapter = opts.adapters?.text ?? opts.adapter;
|
|
1358
|
+
if (!adapter) throw new Error("Text blocks require a MeasurementAdapter");
|
|
1359
|
+
return adapter;
|
|
1360
|
+
}
|
|
1361
|
+
function measureBlock(block, opts) {
|
|
1362
|
+
const maxWidth = nonNegativeFinite(opts.maxWidth ?? 800, 800);
|
|
1363
|
+
const marginTop = nonNegativeFinite(block.marginTop ?? 0, 0);
|
|
1364
|
+
const marginBottom = nonNegativeFinite(block.marginBottom ?? 0, 0);
|
|
1365
|
+
if (block.kind === "text") {
|
|
1366
|
+
const adapter = resolveTextAdapter(opts);
|
|
1367
|
+
const font = block.font ?? opts.font ?? "16px sans-serif";
|
|
1368
|
+
const lineHeight = positiveFinite(block.lineHeight ?? opts.lineHeight ?? 20, 20);
|
|
1369
|
+
const cache = opts.cache ?? /* @__PURE__ */ new Map();
|
|
1370
|
+
const width = blockMaxWidth(block.maxWidth, maxWidth);
|
|
1371
|
+
const segments = analyzeAndMeasure(
|
|
1372
|
+
block.text,
|
|
1373
|
+
font,
|
|
1374
|
+
adapter,
|
|
1375
|
+
cache,
|
|
1376
|
+
void 0,
|
|
1377
|
+
opts.segmentAdapter
|
|
1378
|
+
);
|
|
1379
|
+
const hyphenWidth = Object.hasOwn(opts, "hyphenWidth") ? opts.hyphenWidth : tryMeasureHyphenWidth(adapter, font);
|
|
1380
|
+
const lineBreaks = computeLineBreaks(segments, width, {
|
|
1381
|
+
hyphenWidth,
|
|
1382
|
+
segmentAdapter: opts.segmentAdapter
|
|
1383
|
+
});
|
|
1384
|
+
const charPositions = computeCharPositions(
|
|
1385
|
+
lineBreaks,
|
|
1386
|
+
segments,
|
|
1387
|
+
lineHeight,
|
|
1388
|
+
opts.segmentAdapter
|
|
1389
|
+
);
|
|
1390
|
+
return {
|
|
1391
|
+
block,
|
|
1392
|
+
kind: block.kind,
|
|
1393
|
+
id: block.id,
|
|
1394
|
+
width: lineBreaks.lines.reduce((acc, line) => Math.max(acc, line.width), 0),
|
|
1395
|
+
height: lineBreaks.lineCount * lineHeight,
|
|
1396
|
+
marginTop,
|
|
1397
|
+
marginBottom,
|
|
1398
|
+
segments,
|
|
1399
|
+
lineBreaks,
|
|
1400
|
+
charPositions
|
|
1401
|
+
};
|
|
1402
|
+
}
|
|
1403
|
+
if (block.kind === "image") {
|
|
1404
|
+
const explicit2 = block.width !== void 0 && block.height !== void 0 ? { width: clampDimension(block.width), height: clampDimension(block.height) } : opts.adapters?.image?.measureImage(block.src);
|
|
1405
|
+
if (!explicit2) throw new Error("Image blocks require width/height or an ImageMeasurer");
|
|
1406
|
+
const size2 = fitSize(explicit2, blockMaxWidth(block.maxWidth, maxWidth));
|
|
1407
|
+
return {
|
|
1408
|
+
block,
|
|
1409
|
+
kind: block.kind,
|
|
1410
|
+
id: block.id,
|
|
1411
|
+
width: size2.width,
|
|
1412
|
+
height: size2.height,
|
|
1413
|
+
marginTop,
|
|
1414
|
+
marginBottom
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
const explicit = block.width !== void 0 && block.height !== void 0 ? { width: clampDimension(block.width), height: clampDimension(block.height) } : opts.adapters?.svg?.measureSvg(block.svg);
|
|
1418
|
+
if (!explicit) throw new Error("SVG blocks require width/height or a SvgMeasurer");
|
|
1419
|
+
const size = fitSize(explicit, blockMaxWidth(block.maxWidth, maxWidth));
|
|
1420
|
+
return {
|
|
1421
|
+
block,
|
|
1422
|
+
kind: block.kind,
|
|
1423
|
+
id: block.id,
|
|
1424
|
+
width: size.width,
|
|
1425
|
+
height: size.height,
|
|
1426
|
+
marginTop,
|
|
1427
|
+
marginBottom
|
|
1428
|
+
};
|
|
1429
|
+
}
|
|
1430
|
+
function measureBlocks(blocks, opts) {
|
|
1431
|
+
const cache = opts.cache ?? /* @__PURE__ */ new Map();
|
|
1432
|
+
return blocks.map((block) => measureBlock(block, { ...opts, cache }));
|
|
1433
|
+
}
|
|
1434
|
+
function computeBlockFlow(blocks, gap = 0) {
|
|
1435
|
+
const spacing = nonNegativeFinite(gap, 0);
|
|
1436
|
+
let y = 0;
|
|
1437
|
+
return blocks.map((block) => {
|
|
1438
|
+
y += block.marginTop;
|
|
1439
|
+
const positioned = { ...block, x: 0, y };
|
|
1440
|
+
y += block.height + block.marginBottom + spacing;
|
|
1441
|
+
return positioned;
|
|
1442
|
+
});
|
|
1443
|
+
}
|
|
1444
|
+
function computeTotalHeight(blocks) {
|
|
1445
|
+
if (blocks.length === 0) return 0;
|
|
1446
|
+
let bottom = 0;
|
|
1447
|
+
for (const block of blocks) {
|
|
1448
|
+
bottom = Math.max(bottom, block.y + block.height + block.marginBottom);
|
|
1449
|
+
}
|
|
1450
|
+
return bottom;
|
|
1451
|
+
}
|
|
1452
|
+
function columnGeometry(container, columns) {
|
|
1453
|
+
const paddingX = nonNegativeFinite(container.paddingX ?? 0, 0);
|
|
1454
|
+
const paddingY = nonNegativeFinite(container.paddingY ?? 0, 0);
|
|
1455
|
+
const count = Math.max(1, Math.floor(nonNegativeFinite(columns?.count ?? 1, 1)));
|
|
1456
|
+
const gap = nonNegativeFinite(columns?.gap ?? 0, 0);
|
|
1457
|
+
const width = nonNegativeFinite(container.width, 0);
|
|
1458
|
+
const height = nonNegativeFinite(container.height, 0);
|
|
1459
|
+
const innerWidth = Math.max(0, width - paddingX * 2 - gap * (count - 1));
|
|
1460
|
+
const columnWidth = count > 0 ? innerWidth / count : 0;
|
|
1461
|
+
return { paddingX, paddingY, count, gap, width, height, columnWidth };
|
|
1462
|
+
}
|
|
1463
|
+
function sanitizeFlowContainer(container) {
|
|
1464
|
+
return {
|
|
1465
|
+
width: nonNegativeFinite(container.width, 0),
|
|
1466
|
+
height: nonNegativeFinite(container.height, 0),
|
|
1467
|
+
paddingX: container.paddingX === void 0 ? void 0 : nonNegativeFinite(container.paddingX, 0),
|
|
1468
|
+
paddingY: container.paddingY === void 0 ? void 0 : nonNegativeFinite(container.paddingY, 0)
|
|
1469
|
+
};
|
|
1470
|
+
}
|
|
1471
|
+
function sanitizeFlowColumns(columns) {
|
|
1472
|
+
return {
|
|
1473
|
+
count: columns.count === void 0 ? void 0 : Math.max(1, Math.floor(nonNegativeFinite(columns.count, 1))),
|
|
1474
|
+
gap: columns.gap === void 0 ? void 0 : nonNegativeFinite(columns.gap, 0)
|
|
1475
|
+
};
|
|
1476
|
+
}
|
|
1477
|
+
function sanitizeObstacles(obstacles) {
|
|
1478
|
+
return obstacles.map((obstacle) => {
|
|
1479
|
+
if (obstacle.kind === "circle") {
|
|
1480
|
+
return {
|
|
1481
|
+
kind: obstacle.kind,
|
|
1482
|
+
cx: finiteNumber(obstacle.cx, 0),
|
|
1483
|
+
cy: finiteNumber(obstacle.cy, 0),
|
|
1484
|
+
r: nonNegativeFinite(obstacle.r, 0)
|
|
1485
|
+
};
|
|
1486
|
+
}
|
|
1487
|
+
return {
|
|
1488
|
+
kind: obstacle.kind,
|
|
1489
|
+
x: finiteNumber(obstacle.x, 0),
|
|
1490
|
+
y: finiteNumber(obstacle.y, 0),
|
|
1491
|
+
width: nonNegativeFinite(obstacle.width, 0),
|
|
1492
|
+
height: nonNegativeFinite(obstacle.height, 0)
|
|
1493
|
+
};
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1496
|
+
function circleIntervalForBand(obstacle, bandTop, bandBottom) {
|
|
1497
|
+
const radius = nonNegativeFinite(obstacle.r, 0);
|
|
1498
|
+
const centerY = obstacle.cy;
|
|
1499
|
+
const nearestY = Math.max(bandTop, Math.min(centerY, bandBottom));
|
|
1500
|
+
const dy = nearestY - centerY;
|
|
1501
|
+
if (Math.abs(dy) > radius) return null;
|
|
1502
|
+
const dx = Math.sqrt(Math.max(0, radius * radius - dy * dy));
|
|
1503
|
+
return { left: obstacle.cx - dx, right: obstacle.cx + dx };
|
|
1504
|
+
}
|
|
1505
|
+
function rectIntervalForBand(obstacle, bandTop, bandBottom) {
|
|
1506
|
+
const left = obstacle.x;
|
|
1507
|
+
const right = obstacle.x + nonNegativeFinite(obstacle.width, 0);
|
|
1508
|
+
const top = obstacle.y;
|
|
1509
|
+
const bottom = obstacle.y + nonNegativeFinite(obstacle.height, 0);
|
|
1510
|
+
if (bottom <= bandTop || top >= bandBottom || right <= left) return null;
|
|
1511
|
+
return { left, right };
|
|
1512
|
+
}
|
|
1513
|
+
function blockedIntervalsForBand(obstacles, bandTop, bandBottom) {
|
|
1514
|
+
const intervals = [];
|
|
1515
|
+
for (const obstacle of obstacles) {
|
|
1516
|
+
const interval = obstacle.kind === "circle" ? circleIntervalForBand(obstacle, bandTop, bandBottom) : rectIntervalForBand(obstacle, bandTop, bandBottom);
|
|
1517
|
+
if (interval) intervals.push(interval);
|
|
1518
|
+
}
|
|
1519
|
+
return intervals.sort((a, b) => a.left - b.left);
|
|
1520
|
+
}
|
|
1521
|
+
function computeFlowLines(segments, opts) {
|
|
1522
|
+
const geometry = columnGeometry(opts.container, opts.columns);
|
|
1523
|
+
const lineHeight = positiveFinite(opts.lineHeight, 20);
|
|
1524
|
+
const minSlotWidth = nonNegativeFinite(opts.minSlotWidth ?? 0, 0);
|
|
1525
|
+
const obstacles = opts.obstacles ?? [];
|
|
1526
|
+
const segmentAdapter = opts.segmentAdapter ?? getDefaultSegmentAdapter();
|
|
1527
|
+
const lines = [];
|
|
1528
|
+
let cursor = { segmentIndex: 0, graphemeIndex: 0 };
|
|
1529
|
+
const contentBottom = Math.max(geometry.paddingY, geometry.height - geometry.paddingY);
|
|
1530
|
+
for (let columnIndex = 0; columnIndex < geometry.count; columnIndex += 1) {
|
|
1531
|
+
const columnLeft = geometry.paddingX + columnIndex * (geometry.columnWidth + geometry.gap);
|
|
1532
|
+
const columnRight = columnLeft + geometry.columnWidth;
|
|
1533
|
+
for (let y = geometry.paddingY; y + lineHeight <= contentBottom + 1e-3 && cursor.segmentIndex < segments.length; y += lineHeight) {
|
|
1534
|
+
const blocked = blockedIntervalsForBand(obstacles, y, y + lineHeight);
|
|
1535
|
+
const slots = carveTextLineSlots(
|
|
1536
|
+
{ left: columnLeft, right: columnRight },
|
|
1537
|
+
blocked,
|
|
1538
|
+
Math.max(minSlotWidth, 1e-6)
|
|
1539
|
+
);
|
|
1540
|
+
for (const slot of slots) {
|
|
1541
|
+
if (cursor.segmentIndex >= segments.length) break;
|
|
1542
|
+
const slotWidth = slot.right - slot.left;
|
|
1543
|
+
const next = layoutNextLine(segments, cursor, slotWidth, {
|
|
1544
|
+
hyphenWidth: opts.hyphenWidth,
|
|
1545
|
+
segmentAdapter
|
|
1546
|
+
});
|
|
1547
|
+
if (next === null) {
|
|
1548
|
+
cursor = { segmentIndex: segments.length, graphemeIndex: 0 };
|
|
1549
|
+
break;
|
|
1550
|
+
}
|
|
1551
|
+
if (next.end.segmentIndex === cursor.segmentIndex && next.end.graphemeIndex === cursor.graphemeIndex) {
|
|
1552
|
+
break;
|
|
1553
|
+
}
|
|
1554
|
+
cursor = next.end;
|
|
1555
|
+
if (next.text.length === 0 && next.width === 0) break;
|
|
1556
|
+
lines.push({
|
|
1557
|
+
text: next.text,
|
|
1558
|
+
width: next.width,
|
|
1559
|
+
startSegment: next.start.segmentIndex,
|
|
1560
|
+
startGrapheme: next.start.graphemeIndex,
|
|
1561
|
+
endSegment: next.end.segmentIndex,
|
|
1562
|
+
endGrapheme: next.end.graphemeIndex,
|
|
1563
|
+
x: slot.left,
|
|
1564
|
+
y,
|
|
1565
|
+
slotWidth,
|
|
1566
|
+
columnIndex
|
|
1567
|
+
});
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
return {
|
|
1572
|
+
lines,
|
|
1573
|
+
cursor,
|
|
1574
|
+
done: cursor.segmentIndex >= segments.length
|
|
1575
|
+
};
|
|
1576
|
+
}
|
|
1577
|
+
function reactiveLayout(opts) {
|
|
1578
|
+
const { measurements, segmentAdapter: segmentAdapterOpt, name = "reactive-layout" } = opts;
|
|
1579
|
+
const targetId = opts.targetId ?? "text";
|
|
1580
|
+
const segAdapter = segmentAdapterOpt ?? getDefaultSegmentAdapter();
|
|
1581
|
+
const g = opts.graph;
|
|
1582
|
+
const lineHeightInput = inputNode(
|
|
1583
|
+
g,
|
|
1584
|
+
opts.lineHeight instanceof Node ? opts.lineHeight : nonNegativeFinite(opts.lineHeight ?? 20, 20),
|
|
1585
|
+
nonNegativeFinite(20, 20),
|
|
1586
|
+
scopedName(name, "line-height")
|
|
1587
|
+
);
|
|
1588
|
+
const maxWidthInput = inputNode(
|
|
1589
|
+
g,
|
|
1590
|
+
opts.maxWidth instanceof Node ? opts.maxWidth : nonNegativeFinite(opts.maxWidth ?? 800, 800),
|
|
1591
|
+
nonNegativeFinite(800, 800),
|
|
1592
|
+
scopedName(name, "max-width")
|
|
1593
|
+
);
|
|
1594
|
+
const segments = g.node(
|
|
1595
|
+
[measurements],
|
|
1596
|
+
(ctx) => {
|
|
1597
|
+
try {
|
|
1598
|
+
const measured = latestMeasurementValue(
|
|
1599
|
+
depLatest(ctx, 0),
|
|
1600
|
+
targetId,
|
|
1601
|
+
TEXT_SEGMENTS_MEASUREMENT_KIND
|
|
1602
|
+
);
|
|
1603
|
+
ctx.down([["DATA", measured?.segments ?? []]]);
|
|
1604
|
+
} catch (error) {
|
|
1605
|
+
emitLayoutError(ctx, error, "reactiveLayout segments failed");
|
|
1606
|
+
}
|
|
1607
|
+
},
|
|
1608
|
+
{ name: scopedName(name, "segments") }
|
|
1609
|
+
);
|
|
1610
|
+
const lineBreaks = g.node(
|
|
1611
|
+
[segments, maxWidthInput.node, measurements],
|
|
1612
|
+
(ctx) => {
|
|
1613
|
+
try {
|
|
1614
|
+
const measured = latestMeasurementValue(
|
|
1615
|
+
depLatest(ctx, 2),
|
|
1616
|
+
targetId,
|
|
1617
|
+
TEXT_SEGMENTS_MEASUREMENT_KIND
|
|
1618
|
+
);
|
|
1619
|
+
const computed = computeLineBreaks(
|
|
1620
|
+
depLatest(ctx, 0),
|
|
1621
|
+
nonNegativeFinite(depLatest(ctx, 1), 0),
|
|
1622
|
+
{ hyphenWidth: measured?.hyphenWidth, segmentAdapter: segAdapter }
|
|
1623
|
+
);
|
|
1624
|
+
ctx.down([["DATA", computed]]);
|
|
1625
|
+
} catch (error) {
|
|
1626
|
+
emitLayoutError(ctx, error, "reactiveLayout line breaks failed");
|
|
1627
|
+
}
|
|
1628
|
+
},
|
|
1629
|
+
{ name: scopedName(name, "line-breaks") }
|
|
1630
|
+
);
|
|
1631
|
+
const height = g.node(
|
|
1632
|
+
[lineBreaks, lineHeightInput.node],
|
|
1633
|
+
(ctx) => {
|
|
1634
|
+
try {
|
|
1635
|
+
const lines = depLatest(ctx, 0);
|
|
1636
|
+
const lineHeight = nonNegativeFinite(depLatest(ctx, 1), 0);
|
|
1637
|
+
ctx.down([["DATA", lines.lineCount * lineHeight]]);
|
|
1638
|
+
} catch (error) {
|
|
1639
|
+
emitLayoutError(ctx, error, "reactiveLayout height failed");
|
|
1640
|
+
}
|
|
1641
|
+
},
|
|
1642
|
+
{ name: scopedName(name, "height") }
|
|
1643
|
+
);
|
|
1644
|
+
const charPositions = g.node(
|
|
1645
|
+
[lineBreaks, segments, lineHeightInput.node],
|
|
1646
|
+
(ctx) => {
|
|
1647
|
+
try {
|
|
1648
|
+
const positions = computeCharPositions(
|
|
1649
|
+
depLatest(ctx, 0),
|
|
1650
|
+
depLatest(ctx, 1),
|
|
1651
|
+
nonNegativeFinite(depLatest(ctx, 2), 0),
|
|
1652
|
+
segAdapter
|
|
1653
|
+
);
|
|
1654
|
+
ctx.down([["DATA", positions]]);
|
|
1655
|
+
} catch (error) {
|
|
1656
|
+
emitLayoutError(ctx, error, "reactiveLayout char positions failed");
|
|
1657
|
+
}
|
|
1658
|
+
},
|
|
1659
|
+
{ name: scopedName(name, "char-positions") }
|
|
1660
|
+
);
|
|
1661
|
+
return {
|
|
1662
|
+
graph: g,
|
|
1663
|
+
input: {
|
|
1664
|
+
lineHeight: lineHeightInput.node,
|
|
1665
|
+
maxWidth: maxWidthInput.node,
|
|
1666
|
+
measurements
|
|
1667
|
+
},
|
|
1668
|
+
setLineHeight(lineHeight) {
|
|
1669
|
+
lineHeightInput.set(nonNegativeFinite(lineHeight, 0));
|
|
1670
|
+
},
|
|
1671
|
+
setMaxWidth(maxWidth) {
|
|
1672
|
+
maxWidthInput.set(nonNegativeFinite(maxWidth, 0));
|
|
1673
|
+
},
|
|
1674
|
+
segments,
|
|
1675
|
+
lineBreaks,
|
|
1676
|
+
height,
|
|
1677
|
+
charPositions
|
|
1678
|
+
};
|
|
1679
|
+
}
|
|
1680
|
+
function reactiveBlockLayout(opts) {
|
|
1681
|
+
const { measurements, name = "reactive-block-layout" } = opts;
|
|
1682
|
+
const targetId = opts.targetId ?? "blocks";
|
|
1683
|
+
const g = opts.graph;
|
|
1684
|
+
const gapInput = inputNode(
|
|
1685
|
+
g,
|
|
1686
|
+
opts.gap instanceof Node ? opts.gap : nonNegativeFinite(opts.gap ?? 0, 0),
|
|
1687
|
+
nonNegativeFinite(0, 0),
|
|
1688
|
+
scopedName(name, "gap")
|
|
1689
|
+
);
|
|
1690
|
+
const measuredBlocks = g.node(
|
|
1691
|
+
[measurements],
|
|
1692
|
+
(ctx) => {
|
|
1693
|
+
try {
|
|
1694
|
+
const measured = latestMeasurementValue(
|
|
1695
|
+
depLatest(ctx, 0),
|
|
1696
|
+
targetId,
|
|
1697
|
+
BLOCKS_MEASUREMENT_KIND
|
|
1698
|
+
);
|
|
1699
|
+
ctx.down([["DATA", measured?.blocks ?? []]]);
|
|
1700
|
+
} catch (error) {
|
|
1701
|
+
emitLayoutError(ctx, error, "reactiveBlockLayout measured-blocks failed");
|
|
1702
|
+
}
|
|
1703
|
+
},
|
|
1704
|
+
{ name: scopedName(name, "measured-blocks") }
|
|
1705
|
+
);
|
|
1706
|
+
const blockFlow = g.node(
|
|
1707
|
+
[measuredBlocks, gapInput.node],
|
|
1708
|
+
(ctx) => {
|
|
1709
|
+
try {
|
|
1710
|
+
const positioned = computeBlockFlow(
|
|
1711
|
+
depLatest(ctx, 0),
|
|
1712
|
+
nonNegativeFinite(depLatest(ctx, 1), 0)
|
|
1713
|
+
);
|
|
1714
|
+
ctx.down([["DATA", positioned]]);
|
|
1715
|
+
} catch (error) {
|
|
1716
|
+
emitLayoutError(ctx, error, "reactiveBlockLayout flow failed");
|
|
1717
|
+
}
|
|
1718
|
+
},
|
|
1719
|
+
{ name: scopedName(name, "block-flow") }
|
|
1720
|
+
);
|
|
1721
|
+
const totalHeight = g.node(
|
|
1722
|
+
[blockFlow],
|
|
1723
|
+
(ctx) => {
|
|
1724
|
+
try {
|
|
1725
|
+
ctx.down([["DATA", computeTotalHeight(depLatest(ctx, 0))]]);
|
|
1726
|
+
} catch (error) {
|
|
1727
|
+
emitLayoutError(ctx, error, "reactiveBlockLayout total height failed");
|
|
1728
|
+
}
|
|
1729
|
+
},
|
|
1730
|
+
{ name: scopedName(name, "total-height") }
|
|
1731
|
+
);
|
|
1732
|
+
return {
|
|
1733
|
+
graph: g,
|
|
1734
|
+
input: {
|
|
1735
|
+
gap: gapInput.node,
|
|
1736
|
+
measurements
|
|
1737
|
+
},
|
|
1738
|
+
setGap(gap) {
|
|
1739
|
+
gapInput.set(nonNegativeFinite(gap, 0));
|
|
1740
|
+
},
|
|
1741
|
+
measuredBlocks,
|
|
1742
|
+
blockFlow,
|
|
1743
|
+
totalHeight
|
|
1744
|
+
};
|
|
1745
|
+
}
|
|
1746
|
+
function reactiveFlowLayout(opts) {
|
|
1747
|
+
const { measurements, segmentAdapter: segmentAdapterOpt, name = "reactive-flow-layout" } = opts;
|
|
1748
|
+
const targetId = opts.targetId ?? "text";
|
|
1749
|
+
const segAdapter = segmentAdapterOpt ?? getDefaultSegmentAdapter();
|
|
1750
|
+
const g = opts.graph;
|
|
1751
|
+
const lineHeightInput = inputNode(
|
|
1752
|
+
g,
|
|
1753
|
+
opts.lineHeight instanceof Node ? opts.lineHeight : nonNegativeFinite(opts.lineHeight ?? 20, 20),
|
|
1754
|
+
nonNegativeFinite(20, 20),
|
|
1755
|
+
scopedName(name, "line-height")
|
|
1756
|
+
);
|
|
1757
|
+
const containerInput = inputNode(
|
|
1758
|
+
g,
|
|
1759
|
+
opts.container,
|
|
1760
|
+
{ width: 800, height: 600 },
|
|
1761
|
+
scopedName(name, "container")
|
|
1762
|
+
);
|
|
1763
|
+
const columnsInput = inputNode(
|
|
1764
|
+
g,
|
|
1765
|
+
opts.columns,
|
|
1766
|
+
{ count: 1, gap: 0 },
|
|
1767
|
+
scopedName(name, "columns")
|
|
1768
|
+
);
|
|
1769
|
+
const obstaclesInput = inputNode(g, opts.obstacles, [], scopedName(name, "obstacles"));
|
|
1770
|
+
const segments = g.node(
|
|
1771
|
+
[measurements],
|
|
1772
|
+
(ctx) => {
|
|
1773
|
+
try {
|
|
1774
|
+
const measured = latestMeasurementValue(
|
|
1775
|
+
depLatest(ctx, 0),
|
|
1776
|
+
targetId,
|
|
1777
|
+
TEXT_SEGMENTS_MEASUREMENT_KIND
|
|
1778
|
+
);
|
|
1779
|
+
ctx.down([["DATA", measured?.segments ?? []]]);
|
|
1780
|
+
} catch (error) {
|
|
1781
|
+
emitLayoutError(ctx, error, "reactiveFlowLayout segments failed");
|
|
1782
|
+
}
|
|
1783
|
+
},
|
|
1784
|
+
{ name: scopedName(name, "segments") }
|
|
1785
|
+
);
|
|
1786
|
+
const flowLines = g.node(
|
|
1787
|
+
[
|
|
1788
|
+
segments,
|
|
1789
|
+
lineHeightInput.node,
|
|
1790
|
+
containerInput.node,
|
|
1791
|
+
columnsInput.node,
|
|
1792
|
+
obstaclesInput.node,
|
|
1793
|
+
measurements
|
|
1794
|
+
],
|
|
1795
|
+
(ctx) => {
|
|
1796
|
+
try {
|
|
1797
|
+
const measured = latestMeasurementValue(
|
|
1798
|
+
depLatest(ctx, 5),
|
|
1799
|
+
targetId,
|
|
1800
|
+
TEXT_SEGMENTS_MEASUREMENT_KIND
|
|
1801
|
+
);
|
|
1802
|
+
const computed = computeFlowLines(depLatest(ctx, 0), {
|
|
1803
|
+
lineHeight: nonNegativeFinite(depLatest(ctx, 1), 0),
|
|
1804
|
+
container: sanitizeFlowContainer(depLatest(ctx, 2)),
|
|
1805
|
+
columns: sanitizeFlowColumns(depLatest(ctx, 3)),
|
|
1806
|
+
obstacles: sanitizeObstacles(depLatest(ctx, 4)),
|
|
1807
|
+
minSlotWidth: nonNegativeFinite(opts.minSlotWidth ?? 0, 0),
|
|
1808
|
+
hyphenWidth: measured?.hyphenWidth,
|
|
1809
|
+
segmentAdapter: segAdapter
|
|
1810
|
+
});
|
|
1811
|
+
ctx.down([["DATA", computed]]);
|
|
1812
|
+
} catch (error) {
|
|
1813
|
+
emitLayoutError(ctx, error, "reactiveFlowLayout flow lines failed");
|
|
1814
|
+
}
|
|
1815
|
+
},
|
|
1816
|
+
{ name: scopedName(name, "flow-lines") }
|
|
1817
|
+
);
|
|
1818
|
+
return {
|
|
1819
|
+
graph: g,
|
|
1820
|
+
input: {
|
|
1821
|
+
lineHeight: lineHeightInput.node,
|
|
1822
|
+
container: containerInput.node,
|
|
1823
|
+
columns: columnsInput.node,
|
|
1824
|
+
obstacles: obstaclesInput.node,
|
|
1825
|
+
measurements
|
|
1826
|
+
},
|
|
1827
|
+
setLineHeight(lineHeight) {
|
|
1828
|
+
lineHeightInput.set(nonNegativeFinite(lineHeight, 0));
|
|
1829
|
+
},
|
|
1830
|
+
setContainer(container) {
|
|
1831
|
+
containerInput.set(container);
|
|
1832
|
+
},
|
|
1833
|
+
setColumns(columns) {
|
|
1834
|
+
columnsInput.set(columns);
|
|
1835
|
+
},
|
|
1836
|
+
setObstacles(obstacles) {
|
|
1837
|
+
obstaclesInput.set(obstacles);
|
|
1838
|
+
},
|
|
1839
|
+
segments,
|
|
1840
|
+
flowLines
|
|
1841
|
+
};
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
export {
|
|
1845
|
+
TEXT_SEGMENTS_MEASUREMENT_KIND,
|
|
1846
|
+
BLOCKS_MEASUREMENT_KIND,
|
|
1847
|
+
READINESS_MEASUREMENT_KIND,
|
|
1848
|
+
IMAGE_SIZE_MEASUREMENT_KIND,
|
|
1849
|
+
SVG_BOUNDS_MEASUREMENT_KIND,
|
|
1850
|
+
InjectedMeasureAdapter,
|
|
1851
|
+
PrecomputedMeasureAdapter,
|
|
1852
|
+
CellMeasureAdapter,
|
|
1853
|
+
CapabilityMeasureAdapter,
|
|
1854
|
+
SvgBoundsAdapter,
|
|
1855
|
+
ImageSizeAdapter,
|
|
1856
|
+
textMeasurementProvider,
|
|
1857
|
+
injectedTextMeasurements,
|
|
1858
|
+
precomputedTextMeasurements,
|
|
1859
|
+
cellTextMeasurements,
|
|
1860
|
+
capabilityTextMeasurements,
|
|
1861
|
+
readinessTextMeasurements,
|
|
1862
|
+
readinessMeasurements,
|
|
1863
|
+
imageSizeMeasurements,
|
|
1864
|
+
svgBoundsMeasurements,
|
|
1865
|
+
mergeMeasurements,
|
|
1866
|
+
blockAdaptersProvider,
|
|
1867
|
+
blockMeasurementProvider,
|
|
1868
|
+
analyzeAndMeasure,
|
|
1869
|
+
computeLineBreaks,
|
|
1870
|
+
layoutNextLine,
|
|
1871
|
+
carveTextLineSlots,
|
|
1872
|
+
computeCharPositions,
|
|
1873
|
+
measureBlock,
|
|
1874
|
+
measureBlocks,
|
|
1875
|
+
computeBlockFlow,
|
|
1876
|
+
computeTotalHeight,
|
|
1877
|
+
circleIntervalForBand,
|
|
1878
|
+
rectIntervalForBand,
|
|
1879
|
+
computeFlowLines,
|
|
1880
|
+
reactiveLayout,
|
|
1881
|
+
reactiveBlockLayout,
|
|
1882
|
+
reactiveFlowLayout
|
|
1883
|
+
};
|
|
1884
|
+
//# sourceMappingURL=chunk-YXMZ2N6J.js.map
|