@graphrefly/graphrefly 0.24.0 → 0.26.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 (184) hide show
  1. package/README.md +8 -0
  2. package/dist/{chunk-QOWVNWOC.js → chunk-3ZWCKRHX.js} +27 -25
  3. package/dist/{chunk-QOWVNWOC.js.map → chunk-3ZWCKRHX.js.map} +1 -1
  4. package/dist/chunk-6LDQFTYS.js +102 -0
  5. package/dist/chunk-6LDQFTYS.js.map +1 -0
  6. package/dist/{chunk-5WGT55R4.js → chunk-AMCG74RZ.js} +195 -24
  7. package/dist/chunk-AMCG74RZ.js.map +1 -0
  8. package/dist/{chunk-AOCBDH4T.js → chunk-BVZYTZ5H.js} +76 -103
  9. package/dist/chunk-BVZYTZ5H.js.map +1 -0
  10. package/dist/chunk-FQMKGR6L.js +330 -0
  11. package/dist/chunk-FQMKGR6L.js.map +1 -0
  12. package/dist/chunk-HXZEYDUR.js +94 -0
  13. package/dist/chunk-HXZEYDUR.js.map +1 -0
  14. package/dist/{chunk-IPLKX3L2.js → chunk-IZYUSJC7.js} +16 -14
  15. package/dist/{chunk-IPLKX3L2.js.map → chunk-IZYUSJC7.js.map} +1 -1
  16. package/dist/chunk-J22W6HV3.js +107 -0
  17. package/dist/chunk-J22W6HV3.js.map +1 -0
  18. package/dist/{chunk-HWPIFSW2.js → chunk-JSCT3CR4.js} +6 -4
  19. package/dist/{chunk-HWPIFSW2.js.map → chunk-JSCT3CR4.js.map} +1 -1
  20. package/dist/chunk-JYXEWPH4.js +62 -0
  21. package/dist/chunk-JYXEWPH4.js.map +1 -0
  22. package/dist/chunk-LCE3GF5P.js +866 -0
  23. package/dist/chunk-LCE3GF5P.js.map +1 -0
  24. package/dist/chunk-MJ2NKQQL.js +119 -0
  25. package/dist/chunk-MJ2NKQQL.js.map +1 -0
  26. package/dist/chunk-N6UR7YVY.js +198 -0
  27. package/dist/chunk-N6UR7YVY.js.map +1 -0
  28. package/dist/chunk-OHISZPOJ.js +97 -0
  29. package/dist/chunk-OHISZPOJ.js.map +1 -0
  30. package/dist/{chunk-5DJTTKX3.js → chunk-PHOUUNK7.js} +74 -111
  31. package/dist/chunk-PHOUUNK7.js.map +1 -0
  32. package/dist/{chunk-PY4XCDLR.js → chunk-RB6QPHJ7.js} +8 -6
  33. package/dist/{chunk-PY4XCDLR.js.map → chunk-RB6QPHJ7.js.map} +1 -1
  34. package/dist/chunk-SN4YWWYO.js +171 -0
  35. package/dist/chunk-SN4YWWYO.js.map +1 -0
  36. package/dist/chunk-SX52TAR4.js +110 -0
  37. package/dist/chunk-SX52TAR4.js.map +1 -0
  38. package/dist/{chunk-XOFWRC73.js → chunk-THTWHNU4.js} +319 -24
  39. package/dist/chunk-THTWHNU4.js.map +1 -0
  40. package/dist/{chunk-H4RVA4VE.js → chunk-VYPWMZ6H.js} +2 -2
  41. package/dist/chunk-XGPU467M.js +136 -0
  42. package/dist/chunk-XGPU467M.js.map +1 -0
  43. package/dist/{chunk-TDEXAMGO.js → chunk-ZQMEI34O.js} +206 -574
  44. package/dist/chunk-ZQMEI34O.js.map +1 -0
  45. package/dist/compat/index.cjs +7656 -0
  46. package/dist/compat/index.cjs.map +1 -0
  47. package/dist/compat/index.d.cts +18 -0
  48. package/dist/compat/index.d.ts +18 -0
  49. package/dist/compat/index.js +49 -0
  50. package/dist/compat/index.js.map +1 -0
  51. package/dist/compat/jotai/index.cjs +2048 -0
  52. package/dist/compat/jotai/index.cjs.map +1 -0
  53. package/dist/compat/jotai/index.d.cts +2 -0
  54. package/dist/compat/jotai/index.d.ts +2 -0
  55. package/dist/compat/jotai/index.js +9 -0
  56. package/dist/compat/jotai/index.js.map +1 -0
  57. package/dist/compat/nanostores/index.cjs +2175 -0
  58. package/dist/compat/nanostores/index.cjs.map +1 -0
  59. package/dist/compat/nanostores/index.d.cts +2 -0
  60. package/dist/compat/nanostores/index.d.ts +2 -0
  61. package/dist/compat/nanostores/index.js +23 -0
  62. package/dist/compat/nanostores/index.js.map +1 -0
  63. package/dist/compat/nestjs/index.cjs +350 -16
  64. package/dist/compat/nestjs/index.cjs.map +1 -1
  65. package/dist/compat/nestjs/index.d.cts +6 -6
  66. package/dist/compat/nestjs/index.d.ts +6 -6
  67. package/dist/compat/nestjs/index.js +10 -9
  68. package/dist/compat/react/index.cjs +141 -0
  69. package/dist/compat/react/index.cjs.map +1 -0
  70. package/dist/compat/react/index.d.cts +2 -0
  71. package/dist/compat/react/index.d.ts +2 -0
  72. package/dist/compat/react/index.js +12 -0
  73. package/dist/compat/react/index.js.map +1 -0
  74. package/dist/compat/solid/index.cjs +128 -0
  75. package/dist/compat/solid/index.cjs.map +1 -0
  76. package/dist/compat/solid/index.d.cts +2 -0
  77. package/dist/compat/solid/index.d.ts +2 -0
  78. package/dist/compat/solid/index.js +12 -0
  79. package/dist/compat/solid/index.js.map +1 -0
  80. package/dist/compat/svelte/index.cjs +131 -0
  81. package/dist/compat/svelte/index.cjs.map +1 -0
  82. package/dist/compat/svelte/index.d.cts +2 -0
  83. package/dist/compat/svelte/index.d.ts +2 -0
  84. package/dist/compat/svelte/index.js +12 -0
  85. package/dist/compat/svelte/index.js.map +1 -0
  86. package/dist/compat/vue/index.cjs +146 -0
  87. package/dist/compat/vue/index.cjs.map +1 -0
  88. package/dist/compat/vue/index.d.cts +3 -0
  89. package/dist/compat/vue/index.d.ts +3 -0
  90. package/dist/compat/vue/index.js +12 -0
  91. package/dist/compat/vue/index.js.map +1 -0
  92. package/dist/compat/zustand/index.cjs +4931 -0
  93. package/dist/compat/zustand/index.cjs.map +1 -0
  94. package/dist/compat/zustand/index.d.cts +5 -0
  95. package/dist/compat/zustand/index.d.ts +5 -0
  96. package/dist/compat/zustand/index.js +12 -0
  97. package/dist/compat/zustand/index.js.map +1 -0
  98. package/dist/core/index.cjs +53 -4
  99. package/dist/core/index.cjs.map +1 -1
  100. package/dist/core/index.d.cts +3 -3
  101. package/dist/core/index.d.ts +3 -3
  102. package/dist/core/index.js +26 -24
  103. package/dist/demo-shell-26p5fVxn.d.cts +102 -0
  104. package/dist/demo-shell-DEp-nMTl.d.ts +102 -0
  105. package/dist/extra/index.cjs +290 -110
  106. package/dist/extra/index.cjs.map +1 -1
  107. package/dist/extra/index.d.cts +5 -4
  108. package/dist/extra/index.d.ts +5 -4
  109. package/dist/extra/index.js +8 -5
  110. package/dist/extra/sources.cjs +2486 -0
  111. package/dist/extra/sources.cjs.map +1 -0
  112. package/dist/extra/sources.d.cts +465 -0
  113. package/dist/extra/sources.d.ts +465 -0
  114. package/dist/extra/sources.js +57 -0
  115. package/dist/extra/sources.js.map +1 -0
  116. package/dist/graph/index.cjs +408 -14
  117. package/dist/graph/index.cjs.map +1 -1
  118. package/dist/graph/index.d.cts +5 -5
  119. package/dist/graph/index.d.ts +5 -5
  120. package/dist/graph/index.js +13 -5
  121. package/dist/{graph-D-3JIQme.d.cts → graph-6tZ5jEzr.d.cts} +195 -4
  122. package/dist/{graph-B6NFqv3z.d.ts → graph-DQ69XU0g.d.ts} +195 -4
  123. package/dist/index-B4MP_8V_.d.cts +37 -0
  124. package/dist/index-BEfE8H_G.d.cts +121 -0
  125. package/dist/{index-D7XgsUt7.d.ts → index-BW1z3BN9.d.ts} +169 -127
  126. package/dist/index-BYOHF0zP.d.ts +34 -0
  127. package/dist/index-B_IP40nB.d.cts +36 -0
  128. package/dist/index-Bd_fwmLf.d.cts +45 -0
  129. package/dist/{index-BysCTzJz.d.ts → index-BeIdBfcb.d.cts} +121 -547
  130. package/dist/index-BjI6ty9z.d.ts +121 -0
  131. package/dist/index-Bxb5ZYc9.d.cts +34 -0
  132. package/dist/{index-BJB7t9gg.d.cts → index-C0ZXMaXO.d.cts} +2 -2
  133. package/dist/{index-b5BYtczN.d.cts → index-C8mdwMXc.d.cts} +169 -127
  134. package/dist/index-CDAjUFIv.d.ts +36 -0
  135. package/dist/index-CPgZ5wRl.d.ts +44 -0
  136. package/dist/{index-AMWewNDe.d.cts → index-CUwyr1Kk.d.cts} +33 -4
  137. package/dist/index-CUyrtuOf.d.cts +127 -0
  138. package/dist/{index-C-TXEa7C.d.ts → index-CY2TljO4.d.ts} +2 -2
  139. package/dist/index-CmnuOibw.d.ts +37 -0
  140. package/dist/{index-DiobMNwE.d.ts → index-CuYwdKO-.d.ts} +3 -3
  141. package/dist/index-DFhjO4Gg.d.cts +44 -0
  142. package/dist/{index-1z8vRTCt.d.cts → index-DdD5MVDL.d.ts} +121 -547
  143. package/dist/index-DrISNAOm.d.ts +45 -0
  144. package/dist/index-QBpffFW-.d.cts +86 -0
  145. package/dist/{index-J7Kc0oIQ.d.cts → index-_oMEWlDq.d.cts} +3 -3
  146. package/dist/{index-CYkjxu3s.d.ts → index-eJ6T_qGM.d.ts} +33 -4
  147. package/dist/index-qldRdbQw.d.ts +86 -0
  148. package/dist/index-xdGjv0nO.d.ts +127 -0
  149. package/dist/index.cjs +2334 -195
  150. package/dist/index.cjs.map +1 -1
  151. package/dist/index.d.cts +1007 -648
  152. package/dist/index.d.ts +1007 -648
  153. package/dist/index.js +1204 -1172
  154. package/dist/index.js.map +1 -1
  155. package/dist/{meta-CnkLA_43.d.ts → meta-BGqSZ7mt.d.ts} +1 -1
  156. package/dist/{meta-DWbkoq1s.d.cts → meta-C0-8XW6Q.d.cts} +1 -1
  157. package/dist/{node-B-f-Lu-k.d.cts → node-C_IBuvX2.d.cts} +26 -1
  158. package/dist/{node-B-f-Lu-k.d.ts → node-C_IBuvX2.d.ts} +26 -1
  159. package/dist/{observable-DBnrwcar.d.cts → observable-Crr1jgzx.d.cts} +1 -1
  160. package/dist/{observable-uP-wy_uK.d.ts → observable-DCk45RH5.d.ts} +1 -1
  161. package/dist/patterns/demo-shell.cjs +5604 -0
  162. package/dist/patterns/demo-shell.cjs.map +1 -0
  163. package/dist/patterns/demo-shell.d.cts +6 -0
  164. package/dist/patterns/demo-shell.d.ts +6 -0
  165. package/dist/patterns/demo-shell.js +15 -0
  166. package/dist/patterns/demo-shell.js.map +1 -0
  167. package/dist/patterns/reactive-layout/index.cjs +843 -29
  168. package/dist/patterns/reactive-layout/index.cjs.map +1 -1
  169. package/dist/patterns/reactive-layout/index.d.cts +6 -5
  170. package/dist/patterns/reactive-layout/index.d.ts +6 -5
  171. package/dist/patterns/reactive-layout/index.js +25 -10
  172. package/dist/reactive-layout-BaOQefHu.d.cts +183 -0
  173. package/dist/reactive-layout-D9gejYXE.d.ts +183 -0
  174. package/dist/{storage-BuTdpCI1.d.cts → storage-BMycWEh2.d.ts} +9 -1
  175. package/dist/{storage-F2X1U1x0.d.ts → storage-DiqWHzVI.d.cts} +9 -1
  176. package/package.json +32 -2
  177. package/dist/chunk-5DJTTKX3.js.map +0 -1
  178. package/dist/chunk-5WGT55R4.js.map +0 -1
  179. package/dist/chunk-AOCBDH4T.js.map +0 -1
  180. package/dist/chunk-MW4VAKAO.js +0 -47
  181. package/dist/chunk-MW4VAKAO.js.map +0 -1
  182. package/dist/chunk-TDEXAMGO.js.map +0 -1
  183. package/dist/chunk-XOFWRC73.js.map +0 -1
  184. /package/dist/{chunk-H4RVA4VE.js.map → chunk-VYPWMZ6H.js.map} +0 -0
@@ -1,16 +1,26 @@
1
+ import {
2
+ analyzeAndMeasure,
3
+ carveTextLineSlots,
4
+ computeCharPositions,
5
+ computeLineBreaks,
6
+ layoutNextLine,
7
+ reactiveLayout
8
+ } from "./chunk-LCE3GF5P.js";
1
9
  import {
2
10
  emitToMeta
3
- } from "./chunk-HWPIFSW2.js";
11
+ } from "./chunk-JSCT3CR4.js";
4
12
  import {
5
13
  Graph
6
- } from "./chunk-XOFWRC73.js";
14
+ } from "./chunk-THTWHNU4.js";
7
15
  import {
8
- __export,
9
16
  derived,
10
17
  monotonicNs,
11
18
  node,
12
19
  state
13
- } from "./chunk-5DJTTKX3.js";
20
+ } from "./chunk-PHOUUNK7.js";
21
+ import {
22
+ __export
23
+ } from "./chunk-SX52TAR4.js";
14
24
 
15
25
  // src/patterns/reactive-layout/index.ts
16
26
  var reactive_layout_exports = {};
@@ -22,14 +32,20 @@ __export(reactive_layout_exports, {
22
32
  PrecomputedAdapter: () => PrecomputedAdapter,
23
33
  SvgBoundsAdapter: () => SvgBoundsAdapter,
24
34
  analyzeAndMeasure: () => analyzeAndMeasure,
35
+ carveTextLineSlots: () => carveTextLineSlots,
36
+ circleIntervalForBand: () => circleIntervalForBand,
25
37
  computeBlockFlow: () => computeBlockFlow,
26
38
  computeCharPositions: () => computeCharPositions,
39
+ computeFlowLines: () => computeFlowLines,
27
40
  computeLineBreaks: () => computeLineBreaks,
28
41
  computeTotalHeight: () => computeTotalHeight,
42
+ layoutNextLine: () => layoutNextLine,
29
43
  measureBlock: () => measureBlock,
30
44
  measureBlocks: () => measureBlocks,
31
45
  reactiveBlockLayout: () => reactiveBlockLayout,
32
- reactiveLayout: () => reactiveLayout
46
+ reactiveFlowLayout: () => reactiveFlowLayout,
47
+ reactiveLayout: () => reactiveLayout,
48
+ rectIntervalForBand: () => rectIntervalForBand
33
49
  });
34
50
 
35
51
  // src/patterns/reactive-layout/measurement-adapters.ts
@@ -226,7 +242,7 @@ var CanvasMeasureAdapter = class {
226
242
  this.currentFont = font;
227
243
  }
228
244
  let width = ctx.measureText(text).width;
229
- if (this.emojiCorrection !== 1 && /\p{Emoji_Presentation}/u.test(text)) {
245
+ if (this.emojiCorrection !== 1 && new RegExp("\\p{Emoji_Presentation}", "u").test(text)) {
230
246
  width *= this.emojiCorrection;
231
247
  }
232
248
  return { width };
@@ -310,569 +326,6 @@ var ImageSizeAdapter = class {
310
326
  }
311
327
  };
312
328
 
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 flushLine(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
- flushLine();
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
- flushLine(i + 1, 0, seg.kind === "space" ? lineW - w : lineW);
641
- continue;
642
- }
643
- if (pendingBreakSeg >= 0) {
644
- flushLine(pendingBreakSeg, 0, pendingBreakWidth);
645
- i--;
646
- continue;
647
- }
648
- if (w > maxWidth && seg.graphemeWidths) {
649
- flushLine();
650
- appendBreakableSegment(i, 0, seg.graphemeWidths);
651
- continue;
652
- }
653
- flushLine();
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
- flushLine();
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
- flushLine();
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 = node(
749
- [textNode, fontNode],
750
- (data, actions, ctx) => {
751
- const b0 = data[0];
752
- const textVal = b0 != null && b0.length > 0 ? b0.at(-1) : ctx.prevData[0];
753
- const b1 = data[1];
754
- const fontVal = b1 != null && b1.length > 0 ? b1.at(-1) : ctx.prevData[1];
755
- const t0 = monotonicNs();
756
- const measureStats = { hits: 0, misses: 0 };
757
- const result = analyzeAndMeasure(
758
- textVal,
759
- fontVal,
760
- adapter,
761
- measureCache,
762
- measureStats
763
- );
764
- const elapsed = monotonicNs() - t0;
765
- const lookups = measureStats.hits + measureStats.misses;
766
- const hitRate = lookups === 0 ? 1 : measureStats.hits / lookups;
767
- const meta = segmentsNode.meta;
768
- if (meta) {
769
- emitToMeta(meta["cache-hit-rate"], hitRate);
770
- emitToMeta(meta["segment-count"], result.length);
771
- emitToMeta(meta["layout-time-ns"], elapsed);
772
- }
773
- actions.emit(result);
774
- return () => {
775
- measureCache.clear();
776
- adapter.clearCache?.();
777
- };
778
- },
779
- {
780
- name: "segments",
781
- describeKind: "derived",
782
- meta: {
783
- "cache-hit-rate": 0,
784
- "segment-count": 0,
785
- "layout-time-ns": 0
786
- },
787
- equals: (a, b) => {
788
- const sa = a;
789
- const sb = b;
790
- if (sa == null || sb == null) return sa === sb;
791
- if (sa.length !== sb.length) return false;
792
- for (let i = 0; i < sa.length; i++) {
793
- const pa = sa[i];
794
- const pb = sb[i];
795
- if (pa.text !== pb.text || pa.width !== pb.width || pa.kind !== pb.kind || !graphemeWidthsEqual(pa.graphemeWidths ?? null, pb.graphemeWidths ?? null))
796
- return false;
797
- }
798
- return true;
799
- }
800
- }
801
- );
802
- const lineBreaksNode = derived(
803
- [segmentsNode, maxWidthNode, fontNode],
804
- ([segs, mw, font]) => {
805
- return computeLineBreaks(
806
- segs,
807
- mw,
808
- adapter,
809
- font,
810
- measureCache
811
- );
812
- },
813
- {
814
- name: "line-breaks",
815
- equals: (a, b) => {
816
- const la = a;
817
- const lb = b;
818
- if (la == null || lb == null) return la === lb;
819
- if (la.lineCount !== lb.lineCount) return false;
820
- for (let i = 0; i < la.lines.length; i++) {
821
- const lineA = la.lines[i];
822
- const lineB = lb.lines[i];
823
- 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)
824
- return false;
825
- }
826
- return true;
827
- }
828
- }
829
- );
830
- const heightNode = derived(
831
- [lineBreaksNode, lineHeightNode],
832
- ([lb, lh]) => lb.lineCount * lh,
833
- { name: "height" }
834
- );
835
- const charPositionsNode = derived(
836
- [lineBreaksNode, segmentsNode, lineHeightNode],
837
- ([lb, segs, lh]) => {
838
- return computeCharPositions(lb, segs, lh);
839
- },
840
- {
841
- name: "char-positions",
842
- equals: (a, b) => {
843
- const ca = a;
844
- const cb = b;
845
- if (ca == null || cb == null) return ca === cb;
846
- if (ca.length !== cb.length) return false;
847
- for (let i = 0; i < ca.length; i++) {
848
- if (ca[i].x !== cb[i].x || ca[i].y !== cb[i].y || ca[i].width !== cb[i].width)
849
- return false;
850
- }
851
- return true;
852
- }
853
- }
854
- );
855
- g.add("text", textNode);
856
- g.add("font", fontNode);
857
- g.add("line-height", lineHeightNode);
858
- g.add("max-width", maxWidthNode);
859
- g.add("segments", segmentsNode);
860
- g.add("line-breaks", lineBreaksNode);
861
- g.add("height", heightNode);
862
- g.add("char-positions", charPositionsNode);
863
- return {
864
- graph: g,
865
- setText: (text) => g.set("text", text),
866
- setFont: (font) => g.set("font", font),
867
- setLineHeight: (lh) => g.set("line-height", lh),
868
- setMaxWidth: (mw) => g.set("max-width", Math.max(0, mw)),
869
- segments: segmentsNode,
870
- lineBreaks: lineBreaksNode,
871
- height: heightNode,
872
- charPositions: charPositionsNode
873
- };
874
- }
875
-
876
329
  // src/patterns/reactive-layout/reactive-block-layout.ts
877
330
  function measureBlock(block, maxWidth, adapters, measureCache, defaultFont, defaultLineHeight, index) {
878
331
  switch (block.type) {
@@ -1060,11 +513,186 @@ function reactiveBlockLayout(opts) {
1060
513
  };
1061
514
  }
1062
515
 
516
+ // src/patterns/reactive-layout/reactive-flow-layout.ts
517
+ function circleIntervalForBand(o, bandTop, bandBottom) {
518
+ const hPad = o.hPad ?? 0;
519
+ const vPad = o.vPad ?? 0;
520
+ const top = bandTop - vPad;
521
+ const bottom = bandBottom + vPad;
522
+ if (top >= o.cy + o.r || bottom <= o.cy - o.r) return null;
523
+ const minDy = o.cy >= top && o.cy <= bottom ? 0 : o.cy < top ? top - o.cy : o.cy - bottom;
524
+ if (minDy >= o.r) return null;
525
+ const maxDx = Math.sqrt(o.r * o.r - minDy * minDy);
526
+ return { left: o.cx - maxDx - hPad, right: o.cx + maxDx + hPad };
527
+ }
528
+ function rectIntervalForBand(o, bandTop, bandBottom) {
529
+ const hPad = o.hPad ?? 0;
530
+ const vPad = o.vPad ?? 0;
531
+ if (bandBottom <= o.y - vPad) return null;
532
+ if (bandTop >= o.y + o.h + vPad) return null;
533
+ return { left: o.x - hPad, right: o.x + o.w + hPad };
534
+ }
535
+ function obstacleIntervalForBand(o, bandTop, bandBottom) {
536
+ return o.kind === "circle" ? circleIntervalForBand(o, bandTop, bandBottom) : rectIntervalForBand(o, bandTop, bandBottom);
537
+ }
538
+ function computeFlowLines(segments, container, columns, obstacles, lineHeight, minSlotWidth) {
539
+ const lines = [];
540
+ let cursor = { segmentIndex: 0, graphemeIndex: 0 };
541
+ if (segments.length === 0 || columns.count <= 0 || lineHeight <= 0) {
542
+ return { lines, cursor };
543
+ }
544
+ const padX = container.paddingX ?? 0;
545
+ const padY = container.paddingY ?? 0;
546
+ const availWidth = Math.max(0, container.width - padX * 2);
547
+ const availHeight = Math.max(0, container.height - padY * 2);
548
+ const gapTotal = columns.gap * Math.max(0, columns.count - 1);
549
+ const colWidth = Math.max(0, (availWidth - gapTotal) / columns.count);
550
+ if (colWidth <= 0) return { lines, cursor };
551
+ outerCol: for (let col = 0; col < columns.count; col++) {
552
+ const colLeft = padX + col * (colWidth + columns.gap);
553
+ const colRight = colLeft + colWidth;
554
+ let bandTop = padY;
555
+ while (bandTop + lineHeight <= padY + availHeight) {
556
+ const bandBottom = bandTop + lineHeight;
557
+ const blocked = [];
558
+ for (let oi = 0; oi < obstacles.length; oi++) {
559
+ const iv = obstacleIntervalForBand(obstacles[oi], bandTop, bandBottom);
560
+ if (iv !== null) blocked.push(iv);
561
+ }
562
+ const slots = carveTextLineSlots({ left: colLeft, right: colRight }, blocked, minSlotWidth);
563
+ if (slots.length === 0) {
564
+ bandTop += lineHeight;
565
+ continue;
566
+ }
567
+ let hardBreakThisBand = false;
568
+ for (let si = 0; si < slots.length; si++) {
569
+ const slot = slots[si];
570
+ const slotW = slot.right - slot.left;
571
+ const line = layoutNextLine(segments, cursor, slotW);
572
+ if (line === null) {
573
+ return { lines, cursor };
574
+ }
575
+ if (line.text.length === 0 && line.width === 0) {
576
+ cursor = line.end;
577
+ hardBreakThisBand = true;
578
+ break;
579
+ }
580
+ lines.push({
581
+ x: slot.left,
582
+ y: bandTop,
583
+ width: line.width,
584
+ slotWidth: slotW,
585
+ text: line.text,
586
+ columnIndex: col,
587
+ flushToRight: slot.right < colRight - 0.5
588
+ });
589
+ cursor = line.end;
590
+ }
591
+ bandTop += lineHeight;
592
+ if (hardBreakThisBand) continue;
593
+ if (cursor.segmentIndex >= segments.length) break outerCol;
594
+ }
595
+ if (cursor.segmentIndex >= segments.length) break;
596
+ }
597
+ return { lines, cursor };
598
+ }
599
+ function reactiveFlowLayout(opts) {
600
+ const { adapter, name = "reactive-flow-layout", minSlotWidth = 20 } = opts;
601
+ const g = new Graph(name);
602
+ const measureCache = /* @__PURE__ */ new Map();
603
+ const textNode = state(opts.text ?? "", { name: "text" });
604
+ const fontNode = state(opts.font ?? "16px sans-serif", { name: "font" });
605
+ const lineHeightNode = state(opts.lineHeight ?? 20, { name: "line-height" });
606
+ const containerNode = state(
607
+ opts.container ?? { width: 800, height: 600, paddingX: 0, paddingY: 0 },
608
+ { name: "container" }
609
+ );
610
+ const columnsNode = state(opts.columns ?? { count: 1, gap: 0 }, {
611
+ name: "columns"
612
+ });
613
+ const obstaclesNode = state(opts.obstacles ?? [], { name: "obstacles" });
614
+ const segmentsNode = node(
615
+ [textNode, fontNode],
616
+ (data, actions, ctx) => {
617
+ const b0 = data[0];
618
+ const textVal = b0 != null && b0.length > 0 ? b0.at(-1) : ctx.prevData[0];
619
+ const b1 = data[1];
620
+ const fontVal = b1 != null && b1.length > 0 ? b1.at(-1) : ctx.prevData[1];
621
+ const result = analyzeAndMeasure(textVal, fontVal, adapter, measureCache);
622
+ actions.emit(result);
623
+ return () => {
624
+ measureCache.clear();
625
+ adapter.clearCache?.();
626
+ };
627
+ },
628
+ { name: "segments", describeKind: "derived" }
629
+ );
630
+ const flowLinesNode = derived(
631
+ [segmentsNode, containerNode, columnsNode, obstaclesNode, lineHeightNode],
632
+ ([segs, cont, cols, obs, lh]) => {
633
+ const segments = segs;
634
+ const t0 = monotonicNs();
635
+ const { lines: result, cursor } = computeFlowLines(
636
+ segments,
637
+ cont,
638
+ cols,
639
+ obs,
640
+ lh,
641
+ minSlotWidth
642
+ );
643
+ const elapsed = monotonicNs() - t0;
644
+ const overflow = Math.max(0, segments.length - cursor.segmentIndex);
645
+ const meta = flowLinesNode.meta;
646
+ if (meta) {
647
+ emitToMeta(meta["line-count"], result.length);
648
+ emitToMeta(meta["layout-time-ns"], elapsed);
649
+ emitToMeta(meta["overflow-segments"], overflow);
650
+ }
651
+ return result;
652
+ },
653
+ {
654
+ name: "flow-lines",
655
+ meta: {
656
+ "line-count": 0,
657
+ "layout-time-ns": 0,
658
+ "overflow-segments": 0
659
+ },
660
+ equals: (a, b) => {
661
+ const la = a;
662
+ const lb = b;
663
+ if (la.length !== lb.length) return false;
664
+ for (let i = 0; i < la.length; i++) {
665
+ const pa = la[i];
666
+ const pb = lb[i];
667
+ if (pa.x !== pb.x || pa.y !== pb.y || pa.width !== pb.width || pa.slotWidth !== pb.slotWidth || pa.text !== pb.text || pa.columnIndex !== pb.columnIndex || pa.flushToRight !== pb.flushToRight)
668
+ return false;
669
+ }
670
+ return true;
671
+ }
672
+ }
673
+ );
674
+ g.add("text", textNode);
675
+ g.add("font", fontNode);
676
+ g.add("line-height", lineHeightNode);
677
+ g.add("container", containerNode);
678
+ g.add("columns", columnsNode);
679
+ g.add("obstacles", obstaclesNode);
680
+ g.add("segments", segmentsNode);
681
+ g.add("flow-lines", flowLinesNode);
682
+ return {
683
+ graph: g,
684
+ setText: (t) => g.set("text", t),
685
+ setFont: (f) => g.set("font", f),
686
+ setLineHeight: (lh) => g.set("line-height", lh),
687
+ setContainer: (c) => g.set("container", c),
688
+ setColumns: (c) => g.set("columns", c),
689
+ setObstacles: (o) => g.set("obstacles", o),
690
+ segments: segmentsNode,
691
+ flowLines: flowLinesNode
692
+ };
693
+ }
694
+
1063
695
  export {
1064
- analyzeAndMeasure,
1065
- computeLineBreaks,
1066
- computeCharPositions,
1067
- reactiveLayout,
1068
696
  CliMeasureAdapter,
1069
697
  PrecomputedAdapter,
1070
698
  CanvasMeasureAdapter,
@@ -1076,6 +704,10 @@ export {
1076
704
  computeBlockFlow,
1077
705
  computeTotalHeight,
1078
706
  reactiveBlockLayout,
707
+ circleIntervalForBand,
708
+ rectIntervalForBand,
709
+ computeFlowLines,
710
+ reactiveFlowLayout,
1079
711
  reactive_layout_exports
1080
712
  };
1081
- //# sourceMappingURL=chunk-TDEXAMGO.js.map
713
+ //# sourceMappingURL=chunk-ZQMEI34O.js.map