@graphrefly/graphrefly 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +234 -0
  3. package/dist/chunk-5X3LAO3B.js +1571 -0
  4. package/dist/chunk-5X3LAO3B.js.map +1 -0
  5. package/dist/chunk-6W5SGIGB.js +1793 -0
  6. package/dist/chunk-6W5SGIGB.js.map +1 -0
  7. package/dist/chunk-CP6MNKAA.js +97 -0
  8. package/dist/chunk-CP6MNKAA.js.map +1 -0
  9. package/dist/chunk-HP7OKEOE.js +107 -0
  10. package/dist/chunk-HP7OKEOE.js.map +1 -0
  11. package/dist/chunk-KWXPDASV.js +781 -0
  12. package/dist/chunk-KWXPDASV.js.map +1 -0
  13. package/dist/chunk-O3PI7W45.js +68 -0
  14. package/dist/chunk-O3PI7W45.js.map +1 -0
  15. package/dist/chunk-QW7H3ICI.js +1372 -0
  16. package/dist/chunk-QW7H3ICI.js.map +1 -0
  17. package/dist/chunk-VPS7L64N.js +4785 -0
  18. package/dist/chunk-VPS7L64N.js.map +1 -0
  19. package/dist/chunk-Z4Y4FMQN.js +1097 -0
  20. package/dist/chunk-Z4Y4FMQN.js.map +1 -0
  21. package/dist/compat/nestjs/index.cjs +4883 -0
  22. package/dist/compat/nestjs/index.cjs.map +1 -0
  23. package/dist/compat/nestjs/index.d.cts +7 -0
  24. package/dist/compat/nestjs/index.d.ts +7 -0
  25. package/dist/compat/nestjs/index.js +84 -0
  26. package/dist/compat/nestjs/index.js.map +1 -0
  27. package/dist/core/index.cjs +1632 -0
  28. package/dist/core/index.cjs.map +1 -0
  29. package/dist/core/index.d.cts +2 -0
  30. package/dist/core/index.d.ts +2 -0
  31. package/dist/core/index.js +90 -0
  32. package/dist/core/index.js.map +1 -0
  33. package/dist/extra/index.cjs +6885 -0
  34. package/dist/extra/index.cjs.map +1 -0
  35. package/dist/extra/index.d.cts +5 -0
  36. package/dist/extra/index.d.ts +5 -0
  37. package/dist/extra/index.js +290 -0
  38. package/dist/extra/index.js.map +1 -0
  39. package/dist/graph/index.cjs +3225 -0
  40. package/dist/graph/index.cjs.map +1 -0
  41. package/dist/graph/index.d.cts +3 -0
  42. package/dist/graph/index.d.ts +3 -0
  43. package/dist/graph/index.js +25 -0
  44. package/dist/graph/index.js.map +1 -0
  45. package/dist/graph-CL_ZDAj9.d.cts +605 -0
  46. package/dist/graph-D18qmsNm.d.ts +605 -0
  47. package/dist/index-B6SsZs2h.d.cts +3463 -0
  48. package/dist/index-B7eOdgEx.d.ts +449 -0
  49. package/dist/index-BHUvlQ3v.d.ts +3463 -0
  50. package/dist/index-BtK55IE2.d.ts +231 -0
  51. package/dist/index-BvhgZRHK.d.cts +231 -0
  52. package/dist/index-Bvy_6CaN.d.ts +452 -0
  53. package/dist/index-C3BMRmmp.d.cts +449 -0
  54. package/dist/index-C5mqLhMX.d.cts +452 -0
  55. package/dist/index-CP_QvbWu.d.ts +940 -0
  56. package/dist/index-D_geH2Bm.d.cts +940 -0
  57. package/dist/index.cjs +14843 -0
  58. package/dist/index.cjs.map +1 -0
  59. package/dist/index.d.cts +1517 -0
  60. package/dist/index.d.ts +1517 -0
  61. package/dist/index.js +3649 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/meta-BsF6Sag9.d.cts +607 -0
  64. package/dist/meta-BsF6Sag9.d.ts +607 -0
  65. package/dist/patterns/reactive-layout/index.cjs +4143 -0
  66. package/dist/patterns/reactive-layout/index.cjs.map +1 -0
  67. package/dist/patterns/reactive-layout/index.d.cts +3 -0
  68. package/dist/patterns/reactive-layout/index.d.ts +3 -0
  69. package/dist/patterns/reactive-layout/index.js +38 -0
  70. package/dist/patterns/reactive-layout/index.js.map +1 -0
  71. package/dist/reactive-log-BfvfNWQh.d.cts +137 -0
  72. package/dist/reactive-log-ohLmTXoZ.d.ts +137 -0
  73. package/package.json +256 -0
@@ -0,0 +1,1097 @@
1
+ import {
2
+ Graph
3
+ } from "./chunk-6W5SGIGB.js";
4
+ import {
5
+ DATA,
6
+ INVALIDATE,
7
+ TEARDOWN,
8
+ __export,
9
+ derived,
10
+ emitWithBatch,
11
+ monotonicNs,
12
+ state
13
+ } from "./chunk-5X3LAO3B.js";
14
+
15
+ // src/patterns/reactive-layout/index.ts
16
+ var reactive_layout_exports = {};
17
+ __export(reactive_layout_exports, {
18
+ CanvasMeasureAdapter: () => CanvasMeasureAdapter,
19
+ CliMeasureAdapter: () => CliMeasureAdapter,
20
+ ImageSizeAdapter: () => ImageSizeAdapter,
21
+ NodeCanvasMeasureAdapter: () => NodeCanvasMeasureAdapter,
22
+ PrecomputedAdapter: () => PrecomputedAdapter,
23
+ SvgBoundsAdapter: () => SvgBoundsAdapter,
24
+ analyzeAndMeasure: () => analyzeAndMeasure,
25
+ computeBlockFlow: () => computeBlockFlow,
26
+ computeCharPositions: () => computeCharPositions,
27
+ computeLineBreaks: () => computeLineBreaks,
28
+ computeTotalHeight: () => computeTotalHeight,
29
+ measureBlock: () => measureBlock,
30
+ measureBlocks: () => measureBlocks,
31
+ reactiveBlockLayout: () => reactiveBlockLayout,
32
+ reactiveLayout: () => reactiveLayout
33
+ });
34
+
35
+ // src/patterns/reactive-layout/measurement-adapters.ts
36
+ function cellWidth(code) {
37
+ if (code >= 768 && code <= 879 || // Combining Diacritical Marks
38
+ code >= 1155 && code <= 1161 || // Cyrillic combining marks
39
+ code >= 1425 && code <= 1469 || // Hebrew combining marks
40
+ code >= 1552 && code <= 1562 || // Arabic combining marks
41
+ code >= 1611 && code <= 1631 || // Arabic combining marks
42
+ code >= 1648 && code === 1648 || // Arabic superscript alef
43
+ code >= 1750 && code <= 1756 || // Arabic combining marks
44
+ code >= 1759 && code <= 1764 || // Arabic combining marks
45
+ code >= 1767 && code <= 1768 || // Arabic combining marks
46
+ code >= 1770 && code <= 1773 || // Arabic combining marks
47
+ code >= 1840 && code <= 1866 || // Syriac combining marks
48
+ code >= 1958 && code <= 1968 || // Thaana combining marks
49
+ code >= 2304 && code <= 2307 || // Devanagari combining marks
50
+ code >= 2362 && code <= 2383 || // Devanagari combining marks
51
+ code >= 2385 && code <= 2391 || // Devanagari combining marks
52
+ code >= 2402 && code <= 2403 || // Devanagari combining marks
53
+ code >= 2433 && code <= 2435 || // Bengali combining marks
54
+ code >= 2492 && code <= 2509 || // Bengali combining marks
55
+ code >= 2561 && code <= 2563 || // Gurmukhi combining marks
56
+ code >= 2620 && code <= 2641 || // Gurmukhi combining marks
57
+ code >= 2672 && code <= 2673 || // Gurmukhi combining marks
58
+ code >= 2677 && code === 2677 || // Gurmukhi combining mark
59
+ code >= 3633 && code === 3633 || // Thai combining mark
60
+ code >= 3636 && code <= 3642 || // Thai combining marks
61
+ code >= 3655 && code <= 3662 || // Thai combining marks
62
+ code >= 3761 && code === 3761 || // Lao combining mark
63
+ code >= 3764 && code <= 3772 || // Lao combining marks
64
+ code >= 3784 && code <= 3790 || // Lao combining marks
65
+ code >= 7616 && code <= 7679 || // Combining Diacritical Marks Supplement
66
+ code >= 8400 && code <= 8447 || // Combining Diacritical Marks for Symbols
67
+ code >= 65024 && code <= 65039 || // Variation Selectors
68
+ code >= 65056 && code <= 65071 || // Combining Half Marks
69
+ code === 8205) {
70
+ return 0;
71
+ }
72
+ if (code >= 4352 && code <= 4447 || // Hangul Jamo
73
+ code >= 8986 && code <= 8987 || // Watch, Hourglass
74
+ code >= 9001 && code <= 9002 || // Angle brackets
75
+ code >= 9193 && code <= 9203 || // Media control symbols
76
+ code >= 9208 && code <= 9210 || // Media control symbols
77
+ code >= 9725 && code <= 9726 || // Medium squares
78
+ code >= 9748 && code <= 9749 || // Umbrella, Hot Beverage
79
+ code >= 9800 && code <= 9811 || // Zodiac symbols
80
+ code === 9855 || // Wheelchair
81
+ code === 9875 || // Anchor
82
+ code === 9889 || // High Voltage
83
+ code >= 9898 && code <= 9899 || // Medium circles
84
+ code >= 9917 && code <= 9918 || // Soccer, Baseball
85
+ code >= 9924 && code <= 9925 || // Snowman, Sun behind cloud
86
+ code === 9934 || // Ophiuchus
87
+ code === 9940 || // No Entry
88
+ code === 9962 || // Church
89
+ code >= 9970 && code <= 9971 || // Fountain, Golf
90
+ code === 9973 || // Sailboat
91
+ code === 9978 || // Tent
92
+ code === 9981 || // Fuel Pump
93
+ code === 9986 || // Scissors
94
+ code === 9989 || // Check Mark
95
+ code >= 9992 && code <= 9997 || // Airplane...Writing Hand
96
+ code === 9999 || // Pencil
97
+ code >= 10067 && code <= 10069 || // Question marks
98
+ code === 10071 || // Exclamation
99
+ code >= 10133 && code <= 10135 || // Plus, Minus, Divide
100
+ code === 10160 || // Curly Loop
101
+ code === 10175 || // Double Curly Loop
102
+ code >= 10548 && code <= 10549 || // Arrows
103
+ code >= 11013 && code <= 11015 || // Arrows
104
+ code >= 11035 && code <= 11036 || // Squares
105
+ code === 11088 || // Star
106
+ code === 11093 || // Circle
107
+ code >= 11904 && code <= 12350 || // CJK Radicals, Symbols, Punctuation
108
+ code >= 12352 && code <= 12447 || // Hiragana
109
+ code >= 12448 && code <= 12543 || // Katakana
110
+ code >= 12549 && code <= 12591 || // Bopomofo
111
+ code >= 12593 && code <= 12686 || // Hangul Compatibility Jamo
112
+ code >= 12688 && code <= 12771 || // Kanbun, CJK Strokes
113
+ code >= 12784 && code <= 12830 || // Katakana Phonetic Extensions
114
+ code >= 12832 && code <= 12871 || // Enclosed CJK
115
+ code >= 12880 && code <= 19903 || // CJK Extensions + Unified block
116
+ code >= 19968 && code <= 40959 || // CJK Unified Ideographs
117
+ code >= 43360 && code <= 43388 || // Hangul Jamo Extended-A
118
+ code >= 44032 && code <= 55203 || // Hangul Syllables
119
+ code >= 63744 && code <= 64255 || // CJK Compatibility Ideographs
120
+ code >= 65040 && code <= 65049 || // Vertical forms
121
+ code >= 65072 && code <= 65131 || // CJK Compatibility Forms
122
+ code >= 65281 && code <= 65376 || // Fullwidth Forms (excl. halfwidth)
123
+ code >= 65504 && code <= 65510 || // Fullwidth Signs
124
+ code >= 126980 && code === 126980 || // Mahjong Red Dragon
125
+ code === 127183 || // Joker
126
+ code >= 127344 && code <= 127345 || // A/B buttons
127
+ code === 127358 || // O button
128
+ code === 127359 || // P button
129
+ code === 127374 || // AB button
130
+ code >= 127377 && code <= 127386 || // Squared symbols
131
+ code >= 127456 && code <= 127487 || // Regional Indicator Symbols
132
+ code >= 127488 && code <= 127490 || // Enclosed ideographic
133
+ code === 127514 || // Squared CJK
134
+ code === 127535 || // Squared CJK
135
+ code >= 127538 && code <= 127546 || // Squared CJK
136
+ code >= 127568 && code <= 127569 || // Circled ideographic
137
+ code >= 127744 && code <= 129535 || // Misc Symbols / Emoticons / Emoji
138
+ code >= 129536 && code <= 129791 || // Chess, Symbols Extended-A
139
+ code >= 129792 && code <= 130047 || // Symbols for Legacy Computing
140
+ code >= 131072 && code <= 196605 || // CJK Extension B-F (excl. nonchars)
141
+ code >= 196608 && code <= 262141) {
142
+ return 2;
143
+ }
144
+ return 1;
145
+ }
146
+ function countCells(text) {
147
+ let cells = 0;
148
+ for (const ch of text) {
149
+ cells += cellWidth(ch.codePointAt(0));
150
+ }
151
+ return cells;
152
+ }
153
+ var CliMeasureAdapter = class {
154
+ cellPx;
155
+ constructor(opts) {
156
+ this.cellPx = opts?.cellPx ?? 8;
157
+ }
158
+ measureSegment(text, _font) {
159
+ return { width: countCells(text) * this.cellPx };
160
+ }
161
+ };
162
+ var PrecomputedAdapterKeyError = class extends Error {
163
+ name = "KeyError";
164
+ };
165
+ var PrecomputedAdapter = class {
166
+ metrics;
167
+ fallback;
168
+ constructor(opts) {
169
+ this.metrics = opts.metrics;
170
+ const fb = opts.fallback ?? "per-char";
171
+ if (fb !== "per-char" && fb !== "error") {
172
+ throw new Error(
173
+ `fallback must be 'per-char' or 'error', got ${JSON.stringify(opts.fallback)}`
174
+ );
175
+ }
176
+ this.fallback = fb;
177
+ }
178
+ measureSegment(text, font) {
179
+ const fontMap = this.metrics[font];
180
+ if (fontMap) {
181
+ const w = fontMap[text];
182
+ if (w !== void 0) return { width: w };
183
+ }
184
+ if (this.fallback === "error") {
185
+ throw new PrecomputedAdapterKeyError(
186
+ `PrecomputedAdapter: no metrics for segment ${JSON.stringify(text)} in font ${JSON.stringify(font)}`
187
+ );
188
+ }
189
+ let total = 0;
190
+ if (fontMap) {
191
+ for (const ch of text) {
192
+ const cw = fontMap[ch];
193
+ if (cw !== void 0) {
194
+ total += cw;
195
+ }
196
+ }
197
+ }
198
+ return { width: total };
199
+ }
200
+ };
201
+ var CanvasMeasureAdapter = class {
202
+ ctx = null;
203
+ currentFont = "";
204
+ emojiCorrection;
205
+ constructor(opts) {
206
+ this.emojiCorrection = opts?.emojiCorrection ?? 1;
207
+ }
208
+ getContext() {
209
+ if (!this.ctx) {
210
+ if (typeof OffscreenCanvas === "undefined") {
211
+ throw new Error(
212
+ "CanvasMeasureAdapter requires a browser environment with OffscreenCanvas support. Use CliMeasureAdapter or NodeCanvasMeasureAdapter for Node.js."
213
+ );
214
+ }
215
+ const canvas = new OffscreenCanvas(0, 0);
216
+ const ctx = canvas.getContext("2d");
217
+ if (!ctx) throw new Error("CanvasMeasureAdapter: failed to get 2d context");
218
+ this.ctx = ctx;
219
+ }
220
+ return this.ctx;
221
+ }
222
+ measureSegment(text, font) {
223
+ const ctx = this.getContext();
224
+ if (font !== this.currentFont) {
225
+ ctx.font = font;
226
+ this.currentFont = font;
227
+ }
228
+ let width = ctx.measureText(text).width;
229
+ if (this.emojiCorrection !== 1 && /\p{Emoji_Presentation}/u.test(text)) {
230
+ width *= this.emojiCorrection;
231
+ }
232
+ return { width };
233
+ }
234
+ clearCache() {
235
+ this.currentFont = "";
236
+ }
237
+ };
238
+ var NodeCanvasMeasureAdapter = class {
239
+ ctx = null;
240
+ currentFont = "";
241
+ canvasModule;
242
+ constructor(canvasModule) {
243
+ this.canvasModule = canvasModule;
244
+ }
245
+ getContext() {
246
+ if (!this.ctx) {
247
+ const canvas = this.canvasModule.createCanvas(0, 0);
248
+ const ctx = canvas.getContext("2d");
249
+ if (!ctx) throw new Error("NodeCanvasMeasureAdapter: failed to get 2d context");
250
+ this.ctx = ctx;
251
+ }
252
+ return this.ctx;
253
+ }
254
+ measureSegment(text, font) {
255
+ const ctx = this.getContext();
256
+ if (font !== this.currentFont) {
257
+ ctx.font = font;
258
+ this.currentFont = font;
259
+ }
260
+ return { width: ctx.measureText(text).width };
261
+ }
262
+ clearCache() {
263
+ this.currentFont = "";
264
+ }
265
+ };
266
+ var SvgBoundsAdapter = class {
267
+ measureSvg(content) {
268
+ const viewBoxMatch = content.match(/viewBox\s*=\s*["']([^"']+)["']/);
269
+ if (viewBoxMatch) {
270
+ const parts = viewBoxMatch[1].trim().split(/[\s,]+/);
271
+ if (parts.length >= 4) {
272
+ const w = Number.parseFloat(parts[2]);
273
+ const h = Number.parseFloat(parts[3]);
274
+ if (Number.isFinite(w) && Number.isFinite(h) && w > 0 && h > 0) {
275
+ return { width: w, height: h };
276
+ }
277
+ throw new Error(
278
+ "SvgBoundsAdapter: viewBox width/height are missing, non-finite, or not positive"
279
+ );
280
+ }
281
+ }
282
+ const widthMatch = content.match(/<svg[^>]*\bwidth\s*=\s*["']?([\d.]+)/);
283
+ const heightMatch = content.match(/<svg[^>]*\bheight\s*=\s*["']?([\d.]+)/);
284
+ if (widthMatch && heightMatch) {
285
+ const w = Number.parseFloat(widthMatch[1]);
286
+ const h = Number.parseFloat(heightMatch[1]);
287
+ if (Number.isFinite(w) && Number.isFinite(h) && w > 0 && h > 0) {
288
+ return { width: w, height: h };
289
+ }
290
+ throw new Error(
291
+ "SvgBoundsAdapter: svg width/height attributes are non-finite or not positive"
292
+ );
293
+ }
294
+ throw new Error(
295
+ "SvgBoundsAdapter: cannot determine dimensions \u2014 SVG has no viewBox or width/height attributes"
296
+ );
297
+ }
298
+ };
299
+ var ImageSizeAdapter = class {
300
+ sizes;
301
+ constructor(sizes) {
302
+ this.sizes = new Map(Object.entries(sizes));
303
+ }
304
+ measureImage(src) {
305
+ const dims = this.sizes.get(src);
306
+ if (!dims) {
307
+ throw new Error(`ImageSizeAdapter: no dimensions registered for ${JSON.stringify(src)}`);
308
+ }
309
+ return { width: dims.width, height: dims.height };
310
+ }
311
+ };
312
+
313
+ // src/patterns/reactive-layout/reactive-layout.ts
314
+ function isCJK(s) {
315
+ for (const ch of s) {
316
+ const c = ch.codePointAt(0);
317
+ if (c >= 19968 && c <= 40959 || // CJK Unified Ideographs
318
+ c >= 13312 && c <= 19903 || // CJK Extension A
319
+ c >= 12288 && c <= 12351 || // CJK Symbols and Punctuation
320
+ c >= 12352 && c <= 12447 || // Hiragana
321
+ c >= 12448 && c <= 12543 || // Katakana
322
+ c >= 44032 && c <= 55215 || // Hangul
323
+ c >= 65280 && c <= 65519) {
324
+ return true;
325
+ }
326
+ }
327
+ return false;
328
+ }
329
+ var kinsokuStart = /* @__PURE__ */ new Set([
330
+ "\uFF0C",
331
+ "\uFF0E",
332
+ "\uFF01",
333
+ "\uFF1A",
334
+ "\uFF1B",
335
+ "\uFF1F",
336
+ "\u3001",
337
+ "\u3002",
338
+ "\u30FB",
339
+ "\uFF09",
340
+ "\u3015",
341
+ "\u3009",
342
+ "\u300B",
343
+ "\u300D",
344
+ "\u300F",
345
+ "\u3011"
346
+ ]);
347
+ var leftStickyPunctuation = /* @__PURE__ */ new Set([
348
+ ".",
349
+ ",",
350
+ "!",
351
+ "?",
352
+ ":",
353
+ ";",
354
+ ")",
355
+ "]",
356
+ "}",
357
+ "%",
358
+ '"',
359
+ "\u201D",
360
+ "\u2019",
361
+ "\xBB",
362
+ "\u203A",
363
+ "\u2026"
364
+ ]);
365
+ function normalizeWhitespace(text) {
366
+ return text.replace(/[\t\n\r\f ]+/g, " ").replace(/^ | $/g, "");
367
+ }
368
+ function segmentText(normalized) {
369
+ const wordSegmenter = new Intl.Segmenter(void 0, { granularity: "word" });
370
+ const pieces = [];
371
+ for (const s of wordSegmenter.segment(normalized)) {
372
+ const text = s.segment;
373
+ const isWordLike = s.isWordLike ?? false;
374
+ const texts = [];
375
+ const wordLikes = [];
376
+ const kinds = [];
377
+ let currentText = "";
378
+ let currentKind = null;
379
+ for (const ch of text) {
380
+ let kind;
381
+ if (ch === " ") kind = "space";
382
+ else if (ch === "\u200B") kind = "zero-width-break";
383
+ else if (ch === "\xAD") kind = "soft-hyphen";
384
+ else if (ch === "\n") kind = "hard-break";
385
+ else kind = "text";
386
+ if (currentKind !== null && kind === currentKind) {
387
+ currentText += ch;
388
+ } else {
389
+ if (currentKind !== null) {
390
+ texts.push(currentText);
391
+ wordLikes.push(currentKind === "text" && isWordLike);
392
+ kinds.push(currentKind);
393
+ }
394
+ currentText = ch;
395
+ currentKind = kind;
396
+ }
397
+ }
398
+ if (currentKind !== null) {
399
+ texts.push(currentText);
400
+ wordLikes.push(currentKind === "text" && isWordLike);
401
+ kinds.push(currentKind);
402
+ }
403
+ pieces.push({ texts, isWordLike: wordLikes, kinds });
404
+ }
405
+ return pieces;
406
+ }
407
+ function analyzeAndMeasure(text, font, adapter, cache, stats) {
408
+ const normalized = normalizeWhitespace(text);
409
+ if (normalized.length === 0) return [];
410
+ const pieces = segmentText(normalized);
411
+ const graphemeSegmenter = new Intl.Segmenter(void 0, {
412
+ granularity: "grapheme"
413
+ });
414
+ const rawTexts = [];
415
+ const rawKinds = [];
416
+ const rawWordLike = [];
417
+ for (const piece of pieces) {
418
+ for (let i = 0; i < piece.texts.length; i++) {
419
+ rawTexts.push(piece.texts[i]);
420
+ rawKinds.push(piece.kinds[i]);
421
+ rawWordLike.push(piece.isWordLike[i]);
422
+ }
423
+ }
424
+ const mergedTexts = [];
425
+ const mergedKinds = [];
426
+ const mergedWordLike = [];
427
+ for (let i = 0; i < rawTexts.length; i++) {
428
+ const t = rawTexts[i];
429
+ const k = rawKinds[i];
430
+ const wl = rawWordLike[i];
431
+ if (k === "text" && !wl && mergedTexts.length > 0 && mergedKinds[mergedKinds.length - 1] === "text") {
432
+ const isSticky = t.length === 1 && (leftStickyPunctuation.has(t) || kinsokuStart.has(t));
433
+ if (isSticky) {
434
+ mergedTexts[mergedTexts.length - 1] += t;
435
+ continue;
436
+ }
437
+ }
438
+ if (t === "-" && mergedTexts.length > 0 && mergedKinds[mergedKinds.length - 1] === "text" && mergedWordLike[mergedWordLike.length - 1]) {
439
+ mergedTexts[mergedTexts.length - 1] += t;
440
+ continue;
441
+ }
442
+ mergedTexts.push(t);
443
+ mergedKinds.push(k);
444
+ mergedWordLike.push(wl);
445
+ }
446
+ let fontCache = cache.get(font);
447
+ if (!fontCache) {
448
+ fontCache = /* @__PURE__ */ new Map();
449
+ cache.set(font, fontCache);
450
+ }
451
+ function measureCached(seg) {
452
+ let w = fontCache.get(seg);
453
+ if (w === void 0) {
454
+ if (stats) stats.misses += 1;
455
+ w = adapter.measureSegment(seg, font).width;
456
+ fontCache.set(seg, w);
457
+ } else if (stats) {
458
+ stats.hits += 1;
459
+ }
460
+ return w;
461
+ }
462
+ const segments = [];
463
+ for (let i = 0; i < mergedTexts.length; i++) {
464
+ const t = mergedTexts[i];
465
+ const k = mergedKinds[i];
466
+ if (k !== "text") {
467
+ segments.push({
468
+ text: t,
469
+ width: k === "space" ? measureCached(" ") * t.length : 0,
470
+ kind: k,
471
+ graphemeWidths: null
472
+ });
473
+ continue;
474
+ }
475
+ if (isCJK(t)) {
476
+ let unitText = "";
477
+ for (const gs of graphemeSegmenter.segment(t)) {
478
+ const grapheme = gs.segment;
479
+ if (unitText.length > 0 && kinsokuStart.has(grapheme)) {
480
+ unitText += grapheme;
481
+ continue;
482
+ }
483
+ if (unitText.length > 0) {
484
+ const w2 = measureCached(unitText);
485
+ segments.push({
486
+ text: unitText,
487
+ width: w2,
488
+ kind: "text",
489
+ graphemeWidths: null
490
+ });
491
+ }
492
+ unitText = grapheme;
493
+ }
494
+ if (unitText.length > 0) {
495
+ const w2 = measureCached(unitText);
496
+ segments.push({
497
+ text: unitText,
498
+ width: w2,
499
+ kind: "text",
500
+ graphemeWidths: null
501
+ });
502
+ }
503
+ continue;
504
+ }
505
+ const w = measureCached(t);
506
+ let graphemeWidths = null;
507
+ if (mergedWordLike[i] && t.length > 1) {
508
+ const gWidths = [];
509
+ for (const gs of graphemeSegmenter.segment(t)) {
510
+ gWidths.push(measureCached(gs.segment));
511
+ }
512
+ if (gWidths.length > 1) {
513
+ graphemeWidths = gWidths;
514
+ }
515
+ }
516
+ segments.push({ text: t, width: w, kind: "text", graphemeWidths });
517
+ }
518
+ return segments;
519
+ }
520
+ function computeLineBreaks(segments, maxWidth, adapter, font, cache) {
521
+ if (segments.length === 0) {
522
+ return { lines: [], lineCount: 0 };
523
+ }
524
+ const lines = [];
525
+ let lineW = 0;
526
+ let hasContent = false;
527
+ let lineStartSeg = 0;
528
+ let lineStartGrapheme = 0;
529
+ let lineEndSeg = 0;
530
+ let lineEndGrapheme = 0;
531
+ let pendingBreakSeg = -1;
532
+ let pendingBreakWidth = 0;
533
+ let fontCache = cache.get(font);
534
+ if (!fontCache) {
535
+ fontCache = /* @__PURE__ */ new Map();
536
+ cache.set(font, fontCache);
537
+ }
538
+ let hyphenWidth = fontCache.get("-");
539
+ if (hyphenWidth === void 0) {
540
+ hyphenWidth = adapter.measureSegment("-", font).width;
541
+ fontCache.set("-", hyphenWidth);
542
+ }
543
+ function emitLine(endSeg = lineEndSeg, endGrapheme = lineEndGrapheme, width = lineW) {
544
+ let text = "";
545
+ for (let i = lineStartSeg; i < endSeg; i++) {
546
+ const seg = segments[i];
547
+ if (seg.kind === "soft-hyphen" || seg.kind === "hard-break") continue;
548
+ if (i === lineStartSeg && lineStartGrapheme > 0 && seg.graphemeWidths) {
549
+ const graphemeSegmenter = new Intl.Segmenter(void 0, {
550
+ granularity: "grapheme"
551
+ });
552
+ const graphemes = [...graphemeSegmenter.segment(seg.text)].map((g) => g.segment);
553
+ text += graphemes.slice(lineStartGrapheme).join("");
554
+ } else {
555
+ text += seg.text;
556
+ }
557
+ }
558
+ if (endGrapheme > 0 && endSeg < segments.length) {
559
+ const seg = segments[endSeg];
560
+ const graphemeSegmenter = new Intl.Segmenter(void 0, {
561
+ granularity: "grapheme"
562
+ });
563
+ const graphemes = [...graphemeSegmenter.segment(seg.text)].map((g) => g.segment);
564
+ const startG = lineStartSeg === endSeg ? lineStartGrapheme : 0;
565
+ text += graphemes.slice(startG, endGrapheme).join("");
566
+ }
567
+ if (endSeg > 0 && segments[endSeg - 1]?.kind === "soft-hyphen" && !(lineStartSeg === endSeg && lineStartGrapheme > 0)) {
568
+ text += "-";
569
+ }
570
+ lines.push({
571
+ text,
572
+ width,
573
+ startSegment: lineStartSeg,
574
+ startGrapheme: lineStartGrapheme,
575
+ endSegment: endSeg,
576
+ endGrapheme
577
+ });
578
+ lineW = 0;
579
+ hasContent = false;
580
+ pendingBreakSeg = -1;
581
+ pendingBreakWidth = 0;
582
+ }
583
+ function canBreakAfter(kind) {
584
+ return kind === "space" || kind === "zero-width-break" || kind === "soft-hyphen";
585
+ }
586
+ function startLine(segIdx, graphemeIdx, width) {
587
+ hasContent = true;
588
+ lineStartSeg = segIdx;
589
+ lineStartGrapheme = graphemeIdx;
590
+ lineEndSeg = segIdx + 1;
591
+ lineEndGrapheme = 0;
592
+ lineW = width;
593
+ }
594
+ function startLineAtGrapheme(segIdx, graphemeIdx, width) {
595
+ hasContent = true;
596
+ lineStartSeg = segIdx;
597
+ lineStartGrapheme = graphemeIdx;
598
+ lineEndSeg = segIdx;
599
+ lineEndGrapheme = graphemeIdx + 1;
600
+ lineW = width;
601
+ }
602
+ for (let i = 0; i < segments.length; i++) {
603
+ const seg = segments[i];
604
+ if (seg.kind === "hard-break") {
605
+ if (hasContent) {
606
+ emitLine();
607
+ } else {
608
+ lines.push({
609
+ text: "",
610
+ width: 0,
611
+ startSegment: i,
612
+ startGrapheme: 0,
613
+ endSegment: i,
614
+ endGrapheme: 0
615
+ });
616
+ }
617
+ lineStartSeg = i + 1;
618
+ lineStartGrapheme = 0;
619
+ continue;
620
+ }
621
+ const w = seg.width;
622
+ if (!hasContent) {
623
+ if (w > maxWidth && seg.graphemeWidths) {
624
+ appendBreakableSegment(i, 0, seg.graphemeWidths);
625
+ } else {
626
+ startLine(i, 0, w);
627
+ }
628
+ if (canBreakAfter(seg.kind)) {
629
+ pendingBreakSeg = i + 1;
630
+ pendingBreakWidth = seg.kind === "space" ? lineW - w : lineW;
631
+ }
632
+ continue;
633
+ }
634
+ const newW = lineW + w;
635
+ if (newW > maxWidth + 5e-3) {
636
+ if (canBreakAfter(seg.kind)) {
637
+ lineW += w;
638
+ lineEndSeg = i + 1;
639
+ lineEndGrapheme = 0;
640
+ emitLine(i + 1, 0, seg.kind === "space" ? lineW - w : lineW);
641
+ continue;
642
+ }
643
+ if (pendingBreakSeg >= 0) {
644
+ emitLine(pendingBreakSeg, 0, pendingBreakWidth);
645
+ i--;
646
+ continue;
647
+ }
648
+ if (w > maxWidth && seg.graphemeWidths) {
649
+ emitLine();
650
+ appendBreakableSegment(i, 0, seg.graphemeWidths);
651
+ continue;
652
+ }
653
+ emitLine();
654
+ i--;
655
+ continue;
656
+ }
657
+ lineW = newW;
658
+ lineEndSeg = i + 1;
659
+ lineEndGrapheme = 0;
660
+ if (canBreakAfter(seg.kind)) {
661
+ pendingBreakSeg = i + 1;
662
+ pendingBreakWidth = seg.kind === "space" ? lineW - w : lineW;
663
+ }
664
+ }
665
+ if (hasContent) {
666
+ emitLine();
667
+ }
668
+ return { lines, lineCount: lines.length };
669
+ function appendBreakableSegment(segIdx, startG, gWidths) {
670
+ for (let g = startG; g < gWidths.length; g++) {
671
+ const gw = gWidths[g];
672
+ if (!hasContent) {
673
+ startLineAtGrapheme(segIdx, g, gw);
674
+ continue;
675
+ }
676
+ if (lineW + gw > maxWidth + 5e-3) {
677
+ emitLine();
678
+ startLineAtGrapheme(segIdx, g, gw);
679
+ } else {
680
+ lineW += gw;
681
+ lineEndSeg = segIdx;
682
+ lineEndGrapheme = g + 1;
683
+ }
684
+ }
685
+ if (hasContent && lineEndSeg === segIdx && lineEndGrapheme === gWidths.length) {
686
+ lineEndSeg = segIdx + 1;
687
+ lineEndGrapheme = 0;
688
+ }
689
+ }
690
+ }
691
+ function computeCharPositions(lineBreaks, segments, lineHeight) {
692
+ const positions = [];
693
+ const graphemeSegmenter = new Intl.Segmenter(void 0, {
694
+ granularity: "grapheme"
695
+ });
696
+ for (let lineIdx = 0; lineIdx < lineBreaks.lines.length; lineIdx++) {
697
+ const line = lineBreaks.lines[lineIdx];
698
+ const y = lineIdx * lineHeight;
699
+ let x = 0;
700
+ for (let si = line.startSegment; si < segments.length; si++) {
701
+ const seg = segments[si];
702
+ if (seg.kind === "soft-hyphen" || seg.kind === "hard-break") {
703
+ if (si >= line.endSegment && line.endGrapheme === 0) break;
704
+ continue;
705
+ }
706
+ const graphemes = [...graphemeSegmenter.segment(seg.text)].map((g) => g.segment);
707
+ if (graphemes.length === 0) continue;
708
+ const startG = si === line.startSegment ? line.startGrapheme : 0;
709
+ let endG;
710
+ if (si < line.endSegment) {
711
+ endG = graphemes.length;
712
+ } else if (si === line.endSegment && line.endGrapheme > 0) {
713
+ endG = line.endGrapheme;
714
+ } else {
715
+ break;
716
+ }
717
+ for (let g = startG; g < endG; g++) {
718
+ const gWidth = seg.graphemeWidths ? seg.graphemeWidths[g] : seg.width / graphemes.length;
719
+ positions.push({ x, y, width: gWidth, height: lineHeight, line: lineIdx });
720
+ x += gWidth;
721
+ }
722
+ }
723
+ }
724
+ return positions;
725
+ }
726
+ function reactiveLayout(opts) {
727
+ const { adapter, name = "reactive-layout" } = opts;
728
+ const g = new Graph(name);
729
+ const measureCache = /* @__PURE__ */ new Map();
730
+ const textNode = state(opts.text ?? "", { name: "text" });
731
+ const fontNode = state(opts.font ?? "16px sans-serif", {
732
+ name: "font"
733
+ });
734
+ const lineHeightNode = state(opts.lineHeight ?? 20, {
735
+ name: "line-height"
736
+ });
737
+ const maxWidthNode = state(Math.max(0, opts.maxWidth ?? 800), {
738
+ name: "max-width"
739
+ });
740
+ function graphemeWidthsEqual(a, b) {
741
+ if (a === null || b === null) return a === b;
742
+ if (a.length !== b.length) return false;
743
+ for (let i = 0; i < a.length; i++) {
744
+ if (a[i] !== b[i]) return false;
745
+ }
746
+ return true;
747
+ }
748
+ const segmentsNode = derived(
749
+ [textNode, fontNode],
750
+ ([textVal, fontVal]) => {
751
+ const t0 = monotonicNs();
752
+ const measureStats = { hits: 0, misses: 0 };
753
+ const result = analyzeAndMeasure(
754
+ textVal,
755
+ fontVal,
756
+ adapter,
757
+ measureCache,
758
+ measureStats
759
+ );
760
+ const elapsed = monotonicNs() - t0;
761
+ const lookups = measureStats.hits + measureStats.misses;
762
+ const hitRate = lookups === 0 ? 1 : measureStats.hits / lookups;
763
+ const meta = segmentsNode.meta;
764
+ if (meta) {
765
+ const hr = hitRate;
766
+ const len = result.length;
767
+ const el = elapsed;
768
+ emitWithBatch((msgs) => meta["cache-hit-rate"]?.down(msgs), [[DATA, hr]], 3);
769
+ emitWithBatch((msgs) => meta["segment-count"]?.down(msgs), [[DATA, len]], 3);
770
+ emitWithBatch((msgs) => meta["layout-time-ns"]?.down(msgs), [[DATA, el]], 3);
771
+ }
772
+ return result;
773
+ },
774
+ {
775
+ name: "segments",
776
+ meta: {
777
+ "cache-hit-rate": 0,
778
+ "segment-count": 0,
779
+ "layout-time-ns": 0
780
+ },
781
+ onMessage(msg) {
782
+ if (msg[0] === INVALIDATE || msg[0] === TEARDOWN) {
783
+ measureCache.clear();
784
+ adapter.clearCache?.();
785
+ }
786
+ return false;
787
+ },
788
+ equals: (a, b) => {
789
+ const sa = a;
790
+ const sb = b;
791
+ if (sa == null || sb == null) return sa === sb;
792
+ if (sa.length !== sb.length) return false;
793
+ for (let i = 0; i < sa.length; i++) {
794
+ const pa = sa[i];
795
+ const pb = sb[i];
796
+ if (pa.text !== pb.text || pa.width !== pb.width || pa.kind !== pb.kind || !graphemeWidthsEqual(pa.graphemeWidths ?? null, pb.graphemeWidths ?? null))
797
+ return false;
798
+ }
799
+ return true;
800
+ }
801
+ }
802
+ );
803
+ const lineBreaksNode = derived(
804
+ [segmentsNode, maxWidthNode, fontNode],
805
+ ([segs, mw, font]) => {
806
+ return computeLineBreaks(
807
+ segs,
808
+ mw,
809
+ adapter,
810
+ font,
811
+ measureCache
812
+ );
813
+ },
814
+ {
815
+ name: "line-breaks",
816
+ equals: (a, b) => {
817
+ const la = a;
818
+ const lb = b;
819
+ if (la == null || lb == null) return la === lb;
820
+ if (la.lineCount !== lb.lineCount) return false;
821
+ for (let i = 0; i < la.lines.length; i++) {
822
+ const lineA = la.lines[i];
823
+ const lineB = lb.lines[i];
824
+ if (lineA.text !== lineB.text || lineA.width !== lineB.width || lineA.startSegment !== lineB.startSegment || lineA.startGrapheme !== lineB.startGrapheme || lineA.endSegment !== lineB.endSegment || lineA.endGrapheme !== lineB.endGrapheme)
825
+ return false;
826
+ }
827
+ return true;
828
+ }
829
+ }
830
+ );
831
+ const heightNode = derived(
832
+ [lineBreaksNode, lineHeightNode],
833
+ ([lb, lh]) => lb.lineCount * lh,
834
+ { name: "height" }
835
+ );
836
+ const charPositionsNode = derived(
837
+ [lineBreaksNode, segmentsNode, lineHeightNode],
838
+ ([lb, segs, lh]) => {
839
+ return computeCharPositions(lb, segs, lh);
840
+ },
841
+ {
842
+ name: "char-positions",
843
+ equals: (a, b) => {
844
+ const ca = a;
845
+ const cb = b;
846
+ if (ca == null || cb == null) return ca === cb;
847
+ if (ca.length !== cb.length) return false;
848
+ for (let i = 0; i < ca.length; i++) {
849
+ if (ca[i].x !== cb[i].x || ca[i].y !== cb[i].y || ca[i].width !== cb[i].width)
850
+ return false;
851
+ }
852
+ return true;
853
+ }
854
+ }
855
+ );
856
+ g.add("text", textNode);
857
+ g.add("font", fontNode);
858
+ g.add("line-height", lineHeightNode);
859
+ g.add("max-width", maxWidthNode);
860
+ g.add("segments", segmentsNode);
861
+ g.add("line-breaks", lineBreaksNode);
862
+ g.add("height", heightNode);
863
+ g.add("char-positions", charPositionsNode);
864
+ g.connect("text", "segments");
865
+ g.connect("font", "segments");
866
+ g.connect("segments", "line-breaks");
867
+ g.connect("max-width", "line-breaks");
868
+ g.connect("font", "line-breaks");
869
+ g.connect("line-breaks", "height");
870
+ g.connect("line-height", "height");
871
+ g.connect("line-breaks", "char-positions");
872
+ g.connect("segments", "char-positions");
873
+ g.connect("line-height", "char-positions");
874
+ return {
875
+ graph: g,
876
+ setText: (text) => g.set("text", text),
877
+ setFont: (font) => g.set("font", font),
878
+ setLineHeight: (lh) => g.set("line-height", lh),
879
+ setMaxWidth: (mw) => g.set("max-width", Math.max(0, mw)),
880
+ segments: segmentsNode,
881
+ lineBreaks: lineBreaksNode,
882
+ height: heightNode,
883
+ charPositions: charPositionsNode
884
+ };
885
+ }
886
+
887
+ // src/patterns/reactive-layout/reactive-block-layout.ts
888
+ function measureBlock(block, maxWidth, adapters, measureCache, defaultFont, defaultLineHeight, index) {
889
+ switch (block.type) {
890
+ case "text": {
891
+ const font = block.font ?? defaultFont;
892
+ const lineHeight = block.lineHeight ?? defaultLineHeight;
893
+ const segments = analyzeAndMeasure(block.text, font, adapters.text, measureCache);
894
+ const lineBreaks = computeLineBreaks(segments, maxWidth, adapters.text, font, measureCache);
895
+ const charPositions = computeCharPositions(lineBreaks, segments, lineHeight);
896
+ const height = lineBreaks.lineCount * lineHeight;
897
+ let width = 0;
898
+ for (const line of lineBreaks.lines) {
899
+ if (line.width > width) width = line.width;
900
+ }
901
+ return {
902
+ index,
903
+ type: "text",
904
+ width: Math.min(width, maxWidth),
905
+ height,
906
+ textSegments: segments,
907
+ textLineBreaks: lineBreaks,
908
+ textCharPositions: charPositions
909
+ };
910
+ }
911
+ case "image": {
912
+ let w;
913
+ let h;
914
+ if (block.naturalWidth != null && block.naturalHeight != null) {
915
+ w = block.naturalWidth;
916
+ h = block.naturalHeight;
917
+ } else if (adapters.image) {
918
+ const dims = adapters.image.measureImage(block.src);
919
+ w = dims.width;
920
+ h = dims.height;
921
+ } else {
922
+ throw new Error(
923
+ `Image block at index ${index} has no naturalWidth/naturalHeight and no ImageMeasurer adapter`
924
+ );
925
+ }
926
+ if (w > maxWidth) {
927
+ h = h * maxWidth / w;
928
+ w = maxWidth;
929
+ }
930
+ return { index, type: "image", width: w, height: h };
931
+ }
932
+ case "svg": {
933
+ let w;
934
+ let h;
935
+ if (block.viewBox) {
936
+ w = block.viewBox.width;
937
+ h = block.viewBox.height;
938
+ } else if (adapters.svg) {
939
+ const dims = adapters.svg.measureSvg(block.content);
940
+ w = dims.width;
941
+ h = dims.height;
942
+ } else {
943
+ throw new Error(`SVG block at index ${index} has no viewBox and no SvgMeasurer adapter`);
944
+ }
945
+ if (w > maxWidth) {
946
+ h = h * maxWidth / w;
947
+ w = maxWidth;
948
+ }
949
+ return { index, type: "svg", width: w, height: h };
950
+ }
951
+ }
952
+ }
953
+ function measureBlocks(blocks, maxWidth, adapters, measureCache, defaultFont, defaultLineHeight) {
954
+ return blocks.map(
955
+ (block, i) => measureBlock(block, maxWidth, adapters, measureCache, defaultFont, defaultLineHeight, i)
956
+ );
957
+ }
958
+ function computeBlockFlow(measured, gap) {
959
+ const result = [];
960
+ let y = 0;
961
+ for (let i = 0; i < measured.length; i++) {
962
+ const m = measured[i];
963
+ result.push({ ...m, x: 0, y });
964
+ y += m.height + (i < measured.length - 1 ? gap : 0);
965
+ }
966
+ return result;
967
+ }
968
+ function computeTotalHeight(flow) {
969
+ if (flow.length === 0) return 0;
970
+ const last = flow[flow.length - 1];
971
+ return last.y + last.height;
972
+ }
973
+ function reactiveBlockLayout(opts) {
974
+ const {
975
+ adapters,
976
+ name = "reactive-block-layout",
977
+ defaultFont = "16px sans-serif",
978
+ defaultLineHeight = 20
979
+ } = opts;
980
+ const g = new Graph(name);
981
+ const measureCache = /* @__PURE__ */ new Map();
982
+ const blocksNode = state(opts.blocks ?? [], { name: "blocks" });
983
+ const maxWidthNode = state(Math.max(0, opts.maxWidth ?? 800), { name: "max-width" });
984
+ const gapNode = state(opts.gap ?? 0, { name: "gap" });
985
+ const measuredBlocksNode = derived(
986
+ [blocksNode, maxWidthNode],
987
+ ([blocksVal, mwVal]) => {
988
+ const t0 = monotonicNs();
989
+ const result = measureBlocks(
990
+ blocksVal,
991
+ mwVal,
992
+ adapters,
993
+ measureCache,
994
+ defaultFont,
995
+ defaultLineHeight
996
+ );
997
+ const elapsed = monotonicNs() - t0;
998
+ const meta = measuredBlocksNode.meta;
999
+ if (meta) {
1000
+ emitWithBatch((msgs) => meta["block-count"]?.down(msgs), [[DATA, result.length]], 3);
1001
+ emitWithBatch((msgs) => meta["layout-time-ns"]?.down(msgs), [[DATA, elapsed]], 3);
1002
+ }
1003
+ return result;
1004
+ },
1005
+ {
1006
+ name: "measured-blocks",
1007
+ meta: { "block-count": 0, "layout-time-ns": 0 },
1008
+ onMessage(msg, _depIndex, _actions) {
1009
+ if (msg[0] === INVALIDATE || msg[0] === TEARDOWN) {
1010
+ measureCache.clear();
1011
+ adapters.text.clearCache?.();
1012
+ }
1013
+ return false;
1014
+ },
1015
+ equals: (a, b) => {
1016
+ const ma = a;
1017
+ const mb = b;
1018
+ if (ma == null || mb == null) return ma === mb;
1019
+ if (ma.length !== mb.length) return false;
1020
+ for (let i = 0; i < ma.length; i++) {
1021
+ const ba = ma[i];
1022
+ const bb = mb[i];
1023
+ if (ba.type !== bb.type || ba.width !== bb.width || ba.height !== bb.height || ba.index !== bb.index)
1024
+ return false;
1025
+ }
1026
+ return true;
1027
+ }
1028
+ }
1029
+ );
1030
+ const blockFlowNode = derived(
1031
+ [measuredBlocksNode, gapNode],
1032
+ ([measured, gapVal]) => {
1033
+ return computeBlockFlow(measured, gapVal);
1034
+ },
1035
+ {
1036
+ name: "block-flow",
1037
+ equals: (a, b) => {
1038
+ const fa = a;
1039
+ const fb = b;
1040
+ if (fa == null || fb == null) return fa === fb;
1041
+ if (fa.length !== fb.length) return false;
1042
+ for (let i = 0; i < fa.length; i++) {
1043
+ const pa = fa[i];
1044
+ const pb = fb[i];
1045
+ if (pa.x !== pb.x || pa.y !== pb.y || pa.width !== pb.width || pa.height !== pb.height)
1046
+ return false;
1047
+ }
1048
+ return true;
1049
+ }
1050
+ }
1051
+ );
1052
+ const totalHeightNode = derived(
1053
+ [blockFlowNode],
1054
+ ([flow]) => computeTotalHeight(flow),
1055
+ { name: "total-height" }
1056
+ );
1057
+ g.add("blocks", blocksNode);
1058
+ g.add("max-width", maxWidthNode);
1059
+ g.add("gap", gapNode);
1060
+ g.add("measured-blocks", measuredBlocksNode);
1061
+ g.add("block-flow", blockFlowNode);
1062
+ g.add("total-height", totalHeightNode);
1063
+ g.connect("blocks", "measured-blocks");
1064
+ g.connect("max-width", "measured-blocks");
1065
+ g.connect("measured-blocks", "block-flow");
1066
+ g.connect("gap", "block-flow");
1067
+ g.connect("block-flow", "total-height");
1068
+ return {
1069
+ graph: g,
1070
+ setBlocks: (blocks) => g.set("blocks", blocks),
1071
+ setMaxWidth: (mw) => g.set("max-width", Math.max(0, mw)),
1072
+ setGap: (gap) => g.set("gap", gap),
1073
+ measuredBlocks: measuredBlocksNode,
1074
+ blockFlow: blockFlowNode,
1075
+ totalHeight: totalHeightNode
1076
+ };
1077
+ }
1078
+
1079
+ export {
1080
+ CliMeasureAdapter,
1081
+ PrecomputedAdapter,
1082
+ CanvasMeasureAdapter,
1083
+ NodeCanvasMeasureAdapter,
1084
+ SvgBoundsAdapter,
1085
+ ImageSizeAdapter,
1086
+ analyzeAndMeasure,
1087
+ computeLineBreaks,
1088
+ computeCharPositions,
1089
+ reactiveLayout,
1090
+ measureBlock,
1091
+ measureBlocks,
1092
+ computeBlockFlow,
1093
+ computeTotalHeight,
1094
+ reactiveBlockLayout,
1095
+ reactive_layout_exports
1096
+ };
1097
+ //# sourceMappingURL=chunk-Z4Y4FMQN.js.map