@graphrefly/graphrefly 0.23.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-NZMBRXQV.js → chunk-5DJTTKX3.js} +11 -13
- package/dist/chunk-5DJTTKX3.js.map +1 -0
- package/dist/{chunk-PNUZM7PC.js → chunk-EVR6UFUV.js} +6 -6
- package/dist/{chunk-HVBX5KIW.js → chunk-H4RVA4VE.js} +2 -2
- package/dist/{chunk-32N5A454.js → chunk-HWPIFSW2.js} +2 -2
- package/dist/chunk-HWPIFSW2.js.map +1 -0
- package/dist/{chunk-XTLYW4FR.js → chunk-IAHGTNOZ.js} +6 -4
- package/dist/{chunk-XTLYW4FR.js.map → chunk-IAHGTNOZ.js.map} +1 -1
- package/dist/{chunk-CWYPA63G.js → chunk-L2GLW2U7.js} +69 -2
- package/dist/chunk-L2GLW2U7.js.map +1 -0
- package/dist/{chunk-2GQLMQVJ.js → chunk-MW4VAKAO.js} +3 -3
- package/dist/{chunk-JFONSPNF.js → chunk-PY4XCDLR.js} +2 -2
- package/dist/{chunk-263BEJJO.js → chunk-QOWVNWOC.js} +3 -3
- package/dist/{chunk-PX6PDUJ5.js → chunk-TKE3JGOH.js} +491 -19
- package/dist/chunk-TKE3JGOH.js.map +1 -0
- package/dist/{chunk-XRFJJ2IU.js → chunk-XOFWRC73.js} +3 -3
- package/dist/compat/nestjs/index.cjs +10 -12
- package/dist/compat/nestjs/index.cjs.map +1 -1
- package/dist/compat/nestjs/index.d.cts +6 -6
- package/dist/compat/nestjs/index.d.ts +6 -6
- package/dist/compat/nestjs/index.js +9 -9
- package/dist/core/index.cjs +10 -12
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +3 -3
- package/dist/core/index.d.ts +3 -3
- package/dist/core/index.js +3 -3
- package/dist/extra/index.cjs +78 -12
- package/dist/extra/index.cjs.map +1 -1
- package/dist/extra/index.d.cts +4 -4
- package/dist/extra/index.d.ts +4 -4
- package/dist/extra/index.js +6 -4
- package/dist/graph/index.cjs +10 -12
- package/dist/graph/index.cjs.map +1 -1
- package/dist/graph/index.d.cts +5 -5
- package/dist/graph/index.d.ts +5 -5
- package/dist/graph/index.js +4 -4
- package/dist/{graph-CEO2FkLY.d.ts → graph-B6NFqv3z.d.ts} +3 -3
- package/dist/{graph-BtdSRHUc.d.cts → graph-D-3JIQme.d.cts} +3 -3
- package/dist/{index-BFGjXbiP.d.cts → index-AMWewNDe.d.cts} +2 -2
- package/dist/{index-BUj3ASVe.d.cts → index-BJB7t9gg.d.cts} +10 -24
- package/dist/{index-DSPc5rkv.d.ts → index-C-TXEa7C.d.ts} +10 -24
- package/dist/{index-CkElcUY6.d.ts → index-CYkjxu3s.d.ts} +2 -2
- package/dist/{index-B0tfuXwV.d.cts → index-Ch0IpIO0.d.cts} +32 -5
- package/dist/{index-C59uSJAH.d.cts → index-DKE1EATr.d.cts} +224 -4
- package/dist/{index-DgscL7v0.d.ts → index-DiobMNwE.d.ts} +3 -3
- package/dist/{index-RXN94sHK.d.ts → index-Ds23Wvou.d.ts} +32 -5
- package/dist/{index-BPlWVAKY.d.cts → index-J7Kc0oIQ.d.cts} +3 -3
- package/dist/{index-jEtF4N7L.d.ts → index-OXImXMq6.d.ts} +224 -4
- package/dist/index.cjs +570 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -15
- package/dist/index.d.ts +15 -15
- package/dist/index.js +23 -31
- package/dist/index.js.map +1 -1
- package/dist/{meta-3QjzotRv.d.ts → meta-CnkLA_43.d.ts} +1 -1
- package/dist/{meta-B-Lbs4-O.d.cts → meta-DWbkoq1s.d.cts} +1 -1
- package/dist/{node-C7PD3sn9.d.cts → node-B-f-Lu-k.d.cts} +15 -13
- package/dist/{node-C7PD3sn9.d.ts → node-B-f-Lu-k.d.ts} +15 -13
- package/dist/{observable-axpzv1K2.d.cts → observable-DBnrwcar.d.cts} +1 -1
- package/dist/{observable-EyO-moQY.d.ts → observable-uP-wy_uK.d.ts} +1 -1
- package/dist/patterns/reactive-layout/index.cjs +498 -28
- package/dist/patterns/reactive-layout/index.cjs.map +1 -1
- package/dist/patterns/reactive-layout/index.d.cts +5 -5
- package/dist/patterns/reactive-layout/index.d.ts +5 -5
- package/dist/patterns/reactive-layout/index.js +20 -8
- package/dist/{storage-DIgAr7M_.d.cts → storage-BuTdpCI1.d.cts} +1 -1
- package/dist/{storage-CHT5WE9m.d.ts → storage-F2X1U1x0.d.ts} +1 -1
- package/package.json +2 -2
- package/dist/chunk-32N5A454.js.map +0 -1
- package/dist/chunk-CWYPA63G.js.map +0 -1
- package/dist/chunk-NZMBRXQV.js.map +0 -1
- package/dist/chunk-PX6PDUJ5.js.map +0 -1
- /package/dist/{chunk-PNUZM7PC.js.map → chunk-EVR6UFUV.js.map} +0 -0
- /package/dist/{chunk-HVBX5KIW.js.map → chunk-H4RVA4VE.js.map} +0 -0
- /package/dist/{chunk-2GQLMQVJ.js.map → chunk-MW4VAKAO.js.map} +0 -0
- /package/dist/{chunk-JFONSPNF.js.map → chunk-PY4XCDLR.js.map} +0 -0
- /package/dist/{chunk-263BEJJO.js.map → chunk-QOWVNWOC.js.map} +0 -0
- /package/dist/{chunk-XRFJJ2IU.js.map → chunk-XOFWRC73.js.map} +0 -0
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
emitToMeta
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-HWPIFSW2.js";
|
|
4
4
|
import {
|
|
5
5
|
Graph
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XOFWRC73.js";
|
|
7
7
|
import {
|
|
8
8
|
__export,
|
|
9
9
|
derived,
|
|
10
10
|
monotonicNs,
|
|
11
11
|
node,
|
|
12
12
|
state
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-5DJTTKX3.js";
|
|
14
14
|
|
|
15
15
|
// src/patterns/reactive-layout/index.ts
|
|
16
16
|
var reactive_layout_exports = {};
|
|
@@ -22,14 +22,20 @@ __export(reactive_layout_exports, {
|
|
|
22
22
|
PrecomputedAdapter: () => PrecomputedAdapter,
|
|
23
23
|
SvgBoundsAdapter: () => SvgBoundsAdapter,
|
|
24
24
|
analyzeAndMeasure: () => analyzeAndMeasure,
|
|
25
|
+
carveTextLineSlots: () => carveTextLineSlots,
|
|
26
|
+
circleIntervalForBand: () => circleIntervalForBand,
|
|
25
27
|
computeBlockFlow: () => computeBlockFlow,
|
|
26
28
|
computeCharPositions: () => computeCharPositions,
|
|
29
|
+
computeFlowLines: () => computeFlowLines,
|
|
27
30
|
computeLineBreaks: () => computeLineBreaks,
|
|
28
31
|
computeTotalHeight: () => computeTotalHeight,
|
|
32
|
+
layoutNextLine: () => layoutNextLine,
|
|
29
33
|
measureBlock: () => measureBlock,
|
|
30
34
|
measureBlocks: () => measureBlocks,
|
|
31
35
|
reactiveBlockLayout: () => reactiveBlockLayout,
|
|
32
|
-
|
|
36
|
+
reactiveFlowLayout: () => reactiveFlowLayout,
|
|
37
|
+
reactiveLayout: () => reactiveLayout,
|
|
38
|
+
rectIntervalForBand: () => rectIntervalForBand
|
|
33
39
|
});
|
|
34
40
|
|
|
35
41
|
// src/patterns/reactive-layout/measurement-adapters.ts
|
|
@@ -408,7 +414,7 @@ function analyzeAndMeasure(text, font, adapter, cache, stats) {
|
|
|
408
414
|
const normalized = normalizeWhitespace(text);
|
|
409
415
|
if (normalized.length === 0) return [];
|
|
410
416
|
const pieces = segmentText(normalized);
|
|
411
|
-
const
|
|
417
|
+
const graphemeSegmenter2 = new Intl.Segmenter(void 0, {
|
|
412
418
|
granularity: "grapheme"
|
|
413
419
|
});
|
|
414
420
|
const rawTexts = [];
|
|
@@ -452,7 +458,8 @@ function analyzeAndMeasure(text, font, adapter, cache, stats) {
|
|
|
452
458
|
let w = fontCache.get(seg);
|
|
453
459
|
if (w === void 0) {
|
|
454
460
|
if (stats) stats.misses += 1;
|
|
455
|
-
|
|
461
|
+
const raw = adapter.measureSegment(seg, font).width;
|
|
462
|
+
w = Number.isFinite(raw) && raw >= 0 ? raw : 0;
|
|
456
463
|
fontCache.set(seg, w);
|
|
457
464
|
} else if (stats) {
|
|
458
465
|
stats.hits += 1;
|
|
@@ -474,7 +481,7 @@ function analyzeAndMeasure(text, font, adapter, cache, stats) {
|
|
|
474
481
|
}
|
|
475
482
|
if (isCJK(t)) {
|
|
476
483
|
let unitText = "";
|
|
477
|
-
for (const gs of
|
|
484
|
+
for (const gs of graphemeSegmenter2.segment(t)) {
|
|
478
485
|
const grapheme = gs.segment;
|
|
479
486
|
if (unitText.length > 0 && kinsokuStart.has(grapheme)) {
|
|
480
487
|
unitText += grapheme;
|
|
@@ -506,7 +513,7 @@ function analyzeAndMeasure(text, font, adapter, cache, stats) {
|
|
|
506
513
|
let graphemeWidths = null;
|
|
507
514
|
if (mergedWordLike[i] && t.length > 1) {
|
|
508
515
|
const gWidths = [];
|
|
509
|
-
for (const gs of
|
|
516
|
+
for (const gs of graphemeSegmenter2.segment(t)) {
|
|
510
517
|
gWidths.push(measureCached(gs.segment));
|
|
511
518
|
}
|
|
512
519
|
if (gWidths.length > 1) {
|
|
@@ -546,10 +553,10 @@ function computeLineBreaks(segments, maxWidth, adapter, font, cache) {
|
|
|
546
553
|
const seg = segments[i];
|
|
547
554
|
if (seg.kind === "soft-hyphen" || seg.kind === "hard-break") continue;
|
|
548
555
|
if (i === lineStartSeg && lineStartGrapheme > 0 && seg.graphemeWidths) {
|
|
549
|
-
const
|
|
556
|
+
const graphemeSegmenter2 = new Intl.Segmenter(void 0, {
|
|
550
557
|
granularity: "grapheme"
|
|
551
558
|
});
|
|
552
|
-
const graphemes = [...
|
|
559
|
+
const graphemes = [...graphemeSegmenter2.segment(seg.text)].map((g) => g.segment);
|
|
553
560
|
text += graphemes.slice(lineStartGrapheme).join("");
|
|
554
561
|
} else {
|
|
555
562
|
text += seg.text;
|
|
@@ -557,10 +564,10 @@ function computeLineBreaks(segments, maxWidth, adapter, font, cache) {
|
|
|
557
564
|
}
|
|
558
565
|
if (endGrapheme > 0 && endSeg < segments.length) {
|
|
559
566
|
const seg = segments[endSeg];
|
|
560
|
-
const
|
|
567
|
+
const graphemeSegmenter2 = new Intl.Segmenter(void 0, {
|
|
561
568
|
granularity: "grapheme"
|
|
562
569
|
});
|
|
563
|
-
const graphemes = [...
|
|
570
|
+
const graphemes = [...graphemeSegmenter2.segment(seg.text)].map((g) => g.segment);
|
|
564
571
|
const startG = lineStartSeg === endSeg ? lineStartGrapheme : 0;
|
|
565
572
|
text += graphemes.slice(startG, endGrapheme).join("");
|
|
566
573
|
}
|
|
@@ -580,7 +587,7 @@ function computeLineBreaks(segments, maxWidth, adapter, font, cache) {
|
|
|
580
587
|
pendingBreakSeg = -1;
|
|
581
588
|
pendingBreakWidth = 0;
|
|
582
589
|
}
|
|
583
|
-
function
|
|
590
|
+
function canBreakAfter2(kind) {
|
|
584
591
|
return kind === "space" || kind === "zero-width-break" || kind === "soft-hyphen";
|
|
585
592
|
}
|
|
586
593
|
function startLine(segIdx, graphemeIdx, width) {
|
|
@@ -625,7 +632,7 @@ function computeLineBreaks(segments, maxWidth, adapter, font, cache) {
|
|
|
625
632
|
} else {
|
|
626
633
|
startLine(i, 0, w);
|
|
627
634
|
}
|
|
628
|
-
if (
|
|
635
|
+
if (canBreakAfter2(seg.kind)) {
|
|
629
636
|
pendingBreakSeg = i + 1;
|
|
630
637
|
pendingBreakWidth = seg.kind === "space" ? lineW - w : lineW;
|
|
631
638
|
}
|
|
@@ -633,7 +640,7 @@ function computeLineBreaks(segments, maxWidth, adapter, font, cache) {
|
|
|
633
640
|
}
|
|
634
641
|
const newW = lineW + w;
|
|
635
642
|
if (newW > maxWidth + 5e-3) {
|
|
636
|
-
if (
|
|
643
|
+
if (canBreakAfter2(seg.kind)) {
|
|
637
644
|
lineW += w;
|
|
638
645
|
lineEndSeg = i + 1;
|
|
639
646
|
lineEndGrapheme = 0;
|
|
@@ -657,7 +664,7 @@ function computeLineBreaks(segments, maxWidth, adapter, font, cache) {
|
|
|
657
664
|
lineW = newW;
|
|
658
665
|
lineEndSeg = i + 1;
|
|
659
666
|
lineEndGrapheme = 0;
|
|
660
|
-
if (
|
|
667
|
+
if (canBreakAfter2(seg.kind)) {
|
|
661
668
|
pendingBreakSeg = i + 1;
|
|
662
669
|
pendingBreakWidth = seg.kind === "space" ? lineW - w : lineW;
|
|
663
670
|
}
|
|
@@ -688,9 +695,289 @@ function computeLineBreaks(segments, maxWidth, adapter, font, cache) {
|
|
|
688
695
|
}
|
|
689
696
|
}
|
|
690
697
|
}
|
|
698
|
+
function canBreakAfter(kind) {
|
|
699
|
+
return kind === "space" || kind === "zero-width-break" || kind === "soft-hyphen";
|
|
700
|
+
}
|
|
701
|
+
var _graphemeSegmenter = null;
|
|
702
|
+
function graphemeSegmenter() {
|
|
703
|
+
if (_graphemeSegmenter === null) {
|
|
704
|
+
_graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
705
|
+
}
|
|
706
|
+
return _graphemeSegmenter;
|
|
707
|
+
}
|
|
708
|
+
function sliceSegmentText(seg, startG, endG) {
|
|
709
|
+
if (startG === 0 && endG < 0) return seg.text;
|
|
710
|
+
const graphemes = [...graphemeSegmenter().segment(seg.text)].map((g) => g.segment);
|
|
711
|
+
const stop = endG < 0 ? graphemes.length : endG;
|
|
712
|
+
return graphemes.slice(startG, stop).join("");
|
|
713
|
+
}
|
|
714
|
+
function buildLineText(segments, startSeg, startG, endSeg, endG, appendHyphen) {
|
|
715
|
+
let text = "";
|
|
716
|
+
for (let i = startSeg; i < endSeg; i++) {
|
|
717
|
+
const seg = segments[i];
|
|
718
|
+
if (seg.kind === "soft-hyphen" || seg.kind === "hard-break") continue;
|
|
719
|
+
if (i === startSeg && startG > 0) {
|
|
720
|
+
text += sliceSegmentText(seg, startG, -1);
|
|
721
|
+
} else {
|
|
722
|
+
text += seg.text;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
if (endG > 0 && endSeg < segments.length) {
|
|
726
|
+
const seg = segments[endSeg];
|
|
727
|
+
const from = startSeg === endSeg ? startG : 0;
|
|
728
|
+
text += sliceSegmentText(seg, from, endG);
|
|
729
|
+
}
|
|
730
|
+
if (appendHyphen) text += "-";
|
|
731
|
+
return text;
|
|
732
|
+
}
|
|
733
|
+
function resolveHyphenWidth(ctx) {
|
|
734
|
+
if (!ctx || !ctx.adapter || !ctx.font) return 0;
|
|
735
|
+
const cache = ctx.cache;
|
|
736
|
+
if (cache) {
|
|
737
|
+
let fc = cache.get(ctx.font);
|
|
738
|
+
if (!fc) {
|
|
739
|
+
fc = /* @__PURE__ */ new Map();
|
|
740
|
+
cache.set(ctx.font, fc);
|
|
741
|
+
}
|
|
742
|
+
let hw = fc.get("-");
|
|
743
|
+
if (hw === void 0) {
|
|
744
|
+
hw = ctx.adapter.measureSegment("-", ctx.font).width;
|
|
745
|
+
fc.set("-", hw);
|
|
746
|
+
}
|
|
747
|
+
return hw;
|
|
748
|
+
}
|
|
749
|
+
return ctx.adapter.measureSegment("-", ctx.font).width;
|
|
750
|
+
}
|
|
751
|
+
function layoutNextLine(segments, cursor, slotWidth, ctx) {
|
|
752
|
+
let i = cursor.segmentIndex;
|
|
753
|
+
const initialG = cursor.graphemeIndex;
|
|
754
|
+
if (i >= segments.length) return null;
|
|
755
|
+
if (initialG === 0) {
|
|
756
|
+
while (i < segments.length) {
|
|
757
|
+
const seg = segments[i];
|
|
758
|
+
if (seg.kind === "hard-break") {
|
|
759
|
+
return {
|
|
760
|
+
text: "",
|
|
761
|
+
width: 0,
|
|
762
|
+
start: { segmentIndex: cursor.segmentIndex, graphemeIndex: 0 },
|
|
763
|
+
end: { segmentIndex: i + 1, graphemeIndex: 0 }
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
if (seg.kind === "space" || seg.kind === "zero-width-break" || seg.kind === "soft-hyphen") {
|
|
767
|
+
i += 1;
|
|
768
|
+
continue;
|
|
769
|
+
}
|
|
770
|
+
break;
|
|
771
|
+
}
|
|
772
|
+
if (i >= segments.length) return null;
|
|
773
|
+
}
|
|
774
|
+
const hyphenWidth = resolveHyphenWidth(ctx);
|
|
775
|
+
const startSeg = i;
|
|
776
|
+
const startG = i === cursor.segmentIndex ? initialG : 0;
|
|
777
|
+
let lineW = 0;
|
|
778
|
+
let lineEndSeg = startSeg;
|
|
779
|
+
let lineEndG = 0;
|
|
780
|
+
let hasContent = false;
|
|
781
|
+
let pendingBreakSeg = -1;
|
|
782
|
+
let pendingBreakG = 0;
|
|
783
|
+
let pendingBreakWidth = 0;
|
|
784
|
+
let pendingBreakSoftHyphen = false;
|
|
785
|
+
const recordPending = (sIdx, gIdx, widthAtBreak, kind) => {
|
|
786
|
+
pendingBreakSeg = sIdx;
|
|
787
|
+
pendingBreakG = gIdx;
|
|
788
|
+
pendingBreakWidth = widthAtBreak;
|
|
789
|
+
pendingBreakSoftHyphen = kind === "soft-hyphen";
|
|
790
|
+
};
|
|
791
|
+
const consumeBreakable = (segIdx, gStart, gWidths) => {
|
|
792
|
+
for (let g = gStart; g < gWidths.length; g++) {
|
|
793
|
+
const gw = gWidths[g];
|
|
794
|
+
if (!hasContent) {
|
|
795
|
+
lineW = gw;
|
|
796
|
+
lineEndSeg = segIdx;
|
|
797
|
+
lineEndG = g + 1;
|
|
798
|
+
hasContent = true;
|
|
799
|
+
continue;
|
|
800
|
+
}
|
|
801
|
+
if (lineW + gw > slotWidth + 5e-3) {
|
|
802
|
+
return true;
|
|
803
|
+
}
|
|
804
|
+
lineW += gw;
|
|
805
|
+
lineEndSeg = segIdx;
|
|
806
|
+
lineEndG = g + 1;
|
|
807
|
+
}
|
|
808
|
+
if (lineEndSeg === segIdx && lineEndG === gWidths.length) {
|
|
809
|
+
lineEndSeg = segIdx + 1;
|
|
810
|
+
lineEndG = 0;
|
|
811
|
+
}
|
|
812
|
+
return false;
|
|
813
|
+
};
|
|
814
|
+
if (startG > 0 && startSeg < segments.length) {
|
|
815
|
+
const seg = segments[startSeg];
|
|
816
|
+
if (seg.graphemeWidths) {
|
|
817
|
+
const overflowed = consumeBreakable(startSeg, startG, seg.graphemeWidths);
|
|
818
|
+
if (overflowed) {
|
|
819
|
+
const text2 = buildLineText(segments, startSeg, startG, lineEndSeg, lineEndG, false);
|
|
820
|
+
return {
|
|
821
|
+
text: text2,
|
|
822
|
+
width: lineW,
|
|
823
|
+
start: { segmentIndex: startSeg, graphemeIndex: startG },
|
|
824
|
+
end: { segmentIndex: lineEndSeg, graphemeIndex: lineEndG }
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
i = lineEndSeg;
|
|
828
|
+
} else {
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
for (; i < segments.length; ) {
|
|
832
|
+
const seg = segments[i];
|
|
833
|
+
if (seg.kind === "hard-break") {
|
|
834
|
+
if (hasContent) {
|
|
835
|
+
const endsAtSoftHyphen2 = lineEndSeg > 0 && segments[lineEndSeg - 1]?.kind === "soft-hyphen";
|
|
836
|
+
const text2 = buildLineText(
|
|
837
|
+
segments,
|
|
838
|
+
startSeg,
|
|
839
|
+
startG,
|
|
840
|
+
lineEndSeg,
|
|
841
|
+
lineEndG,
|
|
842
|
+
endsAtSoftHyphen2
|
|
843
|
+
);
|
|
844
|
+
return {
|
|
845
|
+
text: text2,
|
|
846
|
+
width: lineW + (endsAtSoftHyphen2 ? hyphenWidth : 0),
|
|
847
|
+
start: { segmentIndex: startSeg, graphemeIndex: startG },
|
|
848
|
+
end: { segmentIndex: lineEndSeg, graphemeIndex: lineEndG }
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
return {
|
|
852
|
+
text: "",
|
|
853
|
+
width: 0,
|
|
854
|
+
start: { segmentIndex: startSeg, graphemeIndex: startG },
|
|
855
|
+
end: { segmentIndex: i + 1, graphemeIndex: 0 }
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
const w = seg.width;
|
|
859
|
+
if (!hasContent) {
|
|
860
|
+
if (w > slotWidth && seg.graphemeWidths) {
|
|
861
|
+
const overflowed = consumeBreakable(i, 0, seg.graphemeWidths);
|
|
862
|
+
if (overflowed) {
|
|
863
|
+
const text2 = buildLineText(segments, startSeg, startG, lineEndSeg, lineEndG, false);
|
|
864
|
+
return {
|
|
865
|
+
text: text2,
|
|
866
|
+
width: lineW,
|
|
867
|
+
start: { segmentIndex: startSeg, graphemeIndex: startG },
|
|
868
|
+
end: { segmentIndex: lineEndSeg, graphemeIndex: lineEndG }
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
i = lineEndSeg;
|
|
872
|
+
continue;
|
|
873
|
+
}
|
|
874
|
+
lineW = w;
|
|
875
|
+
lineEndSeg = i + 1;
|
|
876
|
+
lineEndG = 0;
|
|
877
|
+
hasContent = true;
|
|
878
|
+
if (canBreakAfter(seg.kind)) {
|
|
879
|
+
recordPending(i + 1, 0, seg.kind === "space" ? lineW - w : lineW, seg.kind);
|
|
880
|
+
}
|
|
881
|
+
i += 1;
|
|
882
|
+
continue;
|
|
883
|
+
}
|
|
884
|
+
const newW = lineW + w;
|
|
885
|
+
if (newW > slotWidth + 5e-3) {
|
|
886
|
+
if (canBreakAfter(seg.kind)) {
|
|
887
|
+
lineEndSeg = i + 1;
|
|
888
|
+
lineEndG = 0;
|
|
889
|
+
const endsAtSoftHyphen2 = seg.kind === "soft-hyphen";
|
|
890
|
+
const finalWidth = seg.kind === "space" ? lineW : lineW + (endsAtSoftHyphen2 ? hyphenWidth : 0);
|
|
891
|
+
const text3 = buildLineText(
|
|
892
|
+
segments,
|
|
893
|
+
startSeg,
|
|
894
|
+
startG,
|
|
895
|
+
lineEndSeg,
|
|
896
|
+
lineEndG,
|
|
897
|
+
endsAtSoftHyphen2
|
|
898
|
+
);
|
|
899
|
+
return {
|
|
900
|
+
text: text3,
|
|
901
|
+
width: finalWidth,
|
|
902
|
+
start: { segmentIndex: startSeg, graphemeIndex: startG },
|
|
903
|
+
end: { segmentIndex: lineEndSeg, graphemeIndex: lineEndG }
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
if (pendingBreakSeg >= 0) {
|
|
907
|
+
const text3 = buildLineText(
|
|
908
|
+
segments,
|
|
909
|
+
startSeg,
|
|
910
|
+
startG,
|
|
911
|
+
pendingBreakSeg,
|
|
912
|
+
pendingBreakG,
|
|
913
|
+
pendingBreakSoftHyphen
|
|
914
|
+
);
|
|
915
|
+
return {
|
|
916
|
+
text: text3,
|
|
917
|
+
width: pendingBreakWidth + (pendingBreakSoftHyphen ? hyphenWidth : 0),
|
|
918
|
+
start: { segmentIndex: startSeg, graphemeIndex: startG },
|
|
919
|
+
end: { segmentIndex: pendingBreakSeg, graphemeIndex: pendingBreakG }
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
if (w > slotWidth && seg.graphemeWidths) {
|
|
923
|
+
const text3 = buildLineText(segments, startSeg, startG, lineEndSeg, lineEndG, false);
|
|
924
|
+
return {
|
|
925
|
+
text: text3,
|
|
926
|
+
width: lineW,
|
|
927
|
+
start: { segmentIndex: startSeg, graphemeIndex: startG },
|
|
928
|
+
end: { segmentIndex: lineEndSeg, graphemeIndex: lineEndG }
|
|
929
|
+
};
|
|
930
|
+
}
|
|
931
|
+
const text2 = buildLineText(segments, startSeg, startG, lineEndSeg, lineEndG, false);
|
|
932
|
+
return {
|
|
933
|
+
text: text2,
|
|
934
|
+
width: lineW,
|
|
935
|
+
start: { segmentIndex: startSeg, graphemeIndex: startG },
|
|
936
|
+
end: { segmentIndex: lineEndSeg, graphemeIndex: lineEndG }
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
lineW = newW;
|
|
940
|
+
lineEndSeg = i + 1;
|
|
941
|
+
lineEndG = 0;
|
|
942
|
+
if (canBreakAfter(seg.kind)) {
|
|
943
|
+
recordPending(i + 1, 0, seg.kind === "space" ? lineW - w : lineW, seg.kind);
|
|
944
|
+
}
|
|
945
|
+
i += 1;
|
|
946
|
+
}
|
|
947
|
+
if (!hasContent) return null;
|
|
948
|
+
const endsAtSoftHyphen = lineEndSeg > 0 && segments[lineEndSeg - 1]?.kind === "soft-hyphen";
|
|
949
|
+
const text = buildLineText(segments, startSeg, startG, lineEndSeg, lineEndG, endsAtSoftHyphen);
|
|
950
|
+
return {
|
|
951
|
+
text,
|
|
952
|
+
width: lineW + (endsAtSoftHyphen ? hyphenWidth : 0),
|
|
953
|
+
start: { segmentIndex: startSeg, graphemeIndex: startG },
|
|
954
|
+
end: { segmentIndex: lineEndSeg, graphemeIndex: lineEndG }
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
function carveTextLineSlots(base, blocked, minSlotWidth = 0) {
|
|
958
|
+
let slots = [base];
|
|
959
|
+
for (let bi = 0; bi < blocked.length; bi++) {
|
|
960
|
+
const block = blocked[bi];
|
|
961
|
+
const next = [];
|
|
962
|
+
for (let si = 0; si < slots.length; si++) {
|
|
963
|
+
const slot = slots[si];
|
|
964
|
+
if (block.right <= slot.left || block.left >= slot.right) {
|
|
965
|
+
next.push(slot);
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
968
|
+
if (block.left > slot.left) next.push({ left: slot.left, right: block.left });
|
|
969
|
+
if (block.right < slot.right) next.push({ left: block.right, right: slot.right });
|
|
970
|
+
}
|
|
971
|
+
slots = next;
|
|
972
|
+
}
|
|
973
|
+
if (minSlotWidth > 0) {
|
|
974
|
+
return slots.filter((s) => s.right - s.left >= minSlotWidth);
|
|
975
|
+
}
|
|
976
|
+
return slots;
|
|
977
|
+
}
|
|
691
978
|
function computeCharPositions(lineBreaks, segments, lineHeight) {
|
|
692
979
|
const positions = [];
|
|
693
|
-
const
|
|
980
|
+
const graphemeSegmenter2 = new Intl.Segmenter(void 0, {
|
|
694
981
|
granularity: "grapheme"
|
|
695
982
|
});
|
|
696
983
|
for (let lineIdx = 0; lineIdx < lineBreaks.lines.length; lineIdx++) {
|
|
@@ -703,7 +990,7 @@ function computeCharPositions(lineBreaks, segments, lineHeight) {
|
|
|
703
990
|
if (si >= line.endSegment && line.endGrapheme === 0) break;
|
|
704
991
|
continue;
|
|
705
992
|
}
|
|
706
|
-
const graphemes = [...
|
|
993
|
+
const graphemes = [...graphemeSegmenter2.segment(seg.text)].map((g) => g.segment);
|
|
707
994
|
if (graphemes.length === 0) continue;
|
|
708
995
|
const startG = si === line.startSegment ? line.startGrapheme : 0;
|
|
709
996
|
let endG;
|
|
@@ -1060,9 +1347,190 @@ function reactiveBlockLayout(opts) {
|
|
|
1060
1347
|
};
|
|
1061
1348
|
}
|
|
1062
1349
|
|
|
1350
|
+
// src/patterns/reactive-layout/reactive-flow-layout.ts
|
|
1351
|
+
function circleIntervalForBand(o, bandTop, bandBottom) {
|
|
1352
|
+
const hPad = o.hPad ?? 0;
|
|
1353
|
+
const vPad = o.vPad ?? 0;
|
|
1354
|
+
const top = bandTop - vPad;
|
|
1355
|
+
const bottom = bandBottom + vPad;
|
|
1356
|
+
if (top >= o.cy + o.r || bottom <= o.cy - o.r) return null;
|
|
1357
|
+
const minDy = o.cy >= top && o.cy <= bottom ? 0 : o.cy < top ? top - o.cy : o.cy - bottom;
|
|
1358
|
+
if (minDy >= o.r) return null;
|
|
1359
|
+
const maxDx = Math.sqrt(o.r * o.r - minDy * minDy);
|
|
1360
|
+
return { left: o.cx - maxDx - hPad, right: o.cx + maxDx + hPad };
|
|
1361
|
+
}
|
|
1362
|
+
function rectIntervalForBand(o, bandTop, bandBottom) {
|
|
1363
|
+
const hPad = o.hPad ?? 0;
|
|
1364
|
+
const vPad = o.vPad ?? 0;
|
|
1365
|
+
if (bandBottom <= o.y - vPad) return null;
|
|
1366
|
+
if (bandTop >= o.y + o.h + vPad) return null;
|
|
1367
|
+
return { left: o.x - hPad, right: o.x + o.w + hPad };
|
|
1368
|
+
}
|
|
1369
|
+
function obstacleIntervalForBand(o, bandTop, bandBottom) {
|
|
1370
|
+
return o.kind === "circle" ? circleIntervalForBand(o, bandTop, bandBottom) : rectIntervalForBand(o, bandTop, bandBottom);
|
|
1371
|
+
}
|
|
1372
|
+
function computeFlowLines(segments, container, columns, obstacles, lineHeight, minSlotWidth) {
|
|
1373
|
+
const lines = [];
|
|
1374
|
+
let cursor = { segmentIndex: 0, graphemeIndex: 0 };
|
|
1375
|
+
if (segments.length === 0 || columns.count <= 0 || lineHeight <= 0) {
|
|
1376
|
+
return { lines, cursor };
|
|
1377
|
+
}
|
|
1378
|
+
const padX = container.paddingX ?? 0;
|
|
1379
|
+
const padY = container.paddingY ?? 0;
|
|
1380
|
+
const availWidth = Math.max(0, container.width - padX * 2);
|
|
1381
|
+
const availHeight = Math.max(0, container.height - padY * 2);
|
|
1382
|
+
const gapTotal = columns.gap * Math.max(0, columns.count - 1);
|
|
1383
|
+
const colWidth = Math.max(0, (availWidth - gapTotal) / columns.count);
|
|
1384
|
+
if (colWidth <= 0) return { lines, cursor };
|
|
1385
|
+
outerCol: for (let col = 0; col < columns.count; col++) {
|
|
1386
|
+
const colLeft = padX + col * (colWidth + columns.gap);
|
|
1387
|
+
const colRight = colLeft + colWidth;
|
|
1388
|
+
let bandTop = padY;
|
|
1389
|
+
while (bandTop + lineHeight <= padY + availHeight) {
|
|
1390
|
+
const bandBottom = bandTop + lineHeight;
|
|
1391
|
+
const blocked = [];
|
|
1392
|
+
for (let oi = 0; oi < obstacles.length; oi++) {
|
|
1393
|
+
const iv = obstacleIntervalForBand(obstacles[oi], bandTop, bandBottom);
|
|
1394
|
+
if (iv !== null) blocked.push(iv);
|
|
1395
|
+
}
|
|
1396
|
+
const slots = carveTextLineSlots({ left: colLeft, right: colRight }, blocked, minSlotWidth);
|
|
1397
|
+
if (slots.length === 0) {
|
|
1398
|
+
bandTop += lineHeight;
|
|
1399
|
+
continue;
|
|
1400
|
+
}
|
|
1401
|
+
let hardBreakThisBand = false;
|
|
1402
|
+
for (let si = 0; si < slots.length; si++) {
|
|
1403
|
+
const slot = slots[si];
|
|
1404
|
+
const slotW = slot.right - slot.left;
|
|
1405
|
+
const line = layoutNextLine(segments, cursor, slotW);
|
|
1406
|
+
if (line === null) {
|
|
1407
|
+
return { lines, cursor };
|
|
1408
|
+
}
|
|
1409
|
+
if (line.text.length === 0 && line.width === 0) {
|
|
1410
|
+
cursor = line.end;
|
|
1411
|
+
hardBreakThisBand = true;
|
|
1412
|
+
break;
|
|
1413
|
+
}
|
|
1414
|
+
lines.push({
|
|
1415
|
+
x: slot.left,
|
|
1416
|
+
y: bandTop,
|
|
1417
|
+
width: line.width,
|
|
1418
|
+
slotWidth: slotW,
|
|
1419
|
+
text: line.text,
|
|
1420
|
+
columnIndex: col,
|
|
1421
|
+
flushToRight: slot.right < colRight - 0.5
|
|
1422
|
+
});
|
|
1423
|
+
cursor = line.end;
|
|
1424
|
+
}
|
|
1425
|
+
bandTop += lineHeight;
|
|
1426
|
+
if (hardBreakThisBand) continue;
|
|
1427
|
+
if (cursor.segmentIndex >= segments.length) break outerCol;
|
|
1428
|
+
}
|
|
1429
|
+
if (cursor.segmentIndex >= segments.length) break;
|
|
1430
|
+
}
|
|
1431
|
+
return { lines, cursor };
|
|
1432
|
+
}
|
|
1433
|
+
function reactiveFlowLayout(opts) {
|
|
1434
|
+
const { adapter, name = "reactive-flow-layout", minSlotWidth = 20 } = opts;
|
|
1435
|
+
const g = new Graph(name);
|
|
1436
|
+
const measureCache = /* @__PURE__ */ new Map();
|
|
1437
|
+
const textNode = state(opts.text ?? "", { name: "text" });
|
|
1438
|
+
const fontNode = state(opts.font ?? "16px sans-serif", { name: "font" });
|
|
1439
|
+
const lineHeightNode = state(opts.lineHeight ?? 20, { name: "line-height" });
|
|
1440
|
+
const containerNode = state(
|
|
1441
|
+
opts.container ?? { width: 800, height: 600, paddingX: 0, paddingY: 0 },
|
|
1442
|
+
{ name: "container" }
|
|
1443
|
+
);
|
|
1444
|
+
const columnsNode = state(opts.columns ?? { count: 1, gap: 0 }, {
|
|
1445
|
+
name: "columns"
|
|
1446
|
+
});
|
|
1447
|
+
const obstaclesNode = state(opts.obstacles ?? [], { name: "obstacles" });
|
|
1448
|
+
const segmentsNode = node(
|
|
1449
|
+
[textNode, fontNode],
|
|
1450
|
+
(data, actions, ctx) => {
|
|
1451
|
+
const b0 = data[0];
|
|
1452
|
+
const textVal = b0 != null && b0.length > 0 ? b0.at(-1) : ctx.prevData[0];
|
|
1453
|
+
const b1 = data[1];
|
|
1454
|
+
const fontVal = b1 != null && b1.length > 0 ? b1.at(-1) : ctx.prevData[1];
|
|
1455
|
+
const result = analyzeAndMeasure(textVal, fontVal, adapter, measureCache);
|
|
1456
|
+
actions.emit(result);
|
|
1457
|
+
return () => {
|
|
1458
|
+
measureCache.clear();
|
|
1459
|
+
adapter.clearCache?.();
|
|
1460
|
+
};
|
|
1461
|
+
},
|
|
1462
|
+
{ name: "segments", describeKind: "derived" }
|
|
1463
|
+
);
|
|
1464
|
+
const flowLinesNode = derived(
|
|
1465
|
+
[segmentsNode, containerNode, columnsNode, obstaclesNode, lineHeightNode],
|
|
1466
|
+
([segs, cont, cols, obs, lh]) => {
|
|
1467
|
+
const segments = segs;
|
|
1468
|
+
const t0 = monotonicNs();
|
|
1469
|
+
const { lines: result, cursor } = computeFlowLines(
|
|
1470
|
+
segments,
|
|
1471
|
+
cont,
|
|
1472
|
+
cols,
|
|
1473
|
+
obs,
|
|
1474
|
+
lh,
|
|
1475
|
+
minSlotWidth
|
|
1476
|
+
);
|
|
1477
|
+
const elapsed = monotonicNs() - t0;
|
|
1478
|
+
const overflow = Math.max(0, segments.length - cursor.segmentIndex);
|
|
1479
|
+
const meta = flowLinesNode.meta;
|
|
1480
|
+
if (meta) {
|
|
1481
|
+
emitToMeta(meta["line-count"], result.length);
|
|
1482
|
+
emitToMeta(meta["layout-time-ns"], elapsed);
|
|
1483
|
+
emitToMeta(meta["overflow-segments"], overflow);
|
|
1484
|
+
}
|
|
1485
|
+
return result;
|
|
1486
|
+
},
|
|
1487
|
+
{
|
|
1488
|
+
name: "flow-lines",
|
|
1489
|
+
meta: {
|
|
1490
|
+
"line-count": 0,
|
|
1491
|
+
"layout-time-ns": 0,
|
|
1492
|
+
"overflow-segments": 0
|
|
1493
|
+
},
|
|
1494
|
+
equals: (a, b) => {
|
|
1495
|
+
const la = a;
|
|
1496
|
+
const lb = b;
|
|
1497
|
+
if (la.length !== lb.length) return false;
|
|
1498
|
+
for (let i = 0; i < la.length; i++) {
|
|
1499
|
+
const pa = la[i];
|
|
1500
|
+
const pb = lb[i];
|
|
1501
|
+
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)
|
|
1502
|
+
return false;
|
|
1503
|
+
}
|
|
1504
|
+
return true;
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
);
|
|
1508
|
+
g.add("text", textNode);
|
|
1509
|
+
g.add("font", fontNode);
|
|
1510
|
+
g.add("line-height", lineHeightNode);
|
|
1511
|
+
g.add("container", containerNode);
|
|
1512
|
+
g.add("columns", columnsNode);
|
|
1513
|
+
g.add("obstacles", obstaclesNode);
|
|
1514
|
+
g.add("segments", segmentsNode);
|
|
1515
|
+
g.add("flow-lines", flowLinesNode);
|
|
1516
|
+
return {
|
|
1517
|
+
graph: g,
|
|
1518
|
+
setText: (t) => g.set("text", t),
|
|
1519
|
+
setFont: (f) => g.set("font", f),
|
|
1520
|
+
setLineHeight: (lh) => g.set("line-height", lh),
|
|
1521
|
+
setContainer: (c) => g.set("container", c),
|
|
1522
|
+
setColumns: (c) => g.set("columns", c),
|
|
1523
|
+
setObstacles: (o) => g.set("obstacles", o),
|
|
1524
|
+
segments: segmentsNode,
|
|
1525
|
+
flowLines: flowLinesNode
|
|
1526
|
+
};
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1063
1529
|
export {
|
|
1064
1530
|
analyzeAndMeasure,
|
|
1065
1531
|
computeLineBreaks,
|
|
1532
|
+
layoutNextLine,
|
|
1533
|
+
carveTextLineSlots,
|
|
1066
1534
|
computeCharPositions,
|
|
1067
1535
|
reactiveLayout,
|
|
1068
1536
|
CliMeasureAdapter,
|
|
@@ -1076,6 +1544,10 @@ export {
|
|
|
1076
1544
|
computeBlockFlow,
|
|
1077
1545
|
computeTotalHeight,
|
|
1078
1546
|
reactiveBlockLayout,
|
|
1547
|
+
circleIntervalForBand,
|
|
1548
|
+
rectIntervalForBand,
|
|
1549
|
+
computeFlowLines,
|
|
1550
|
+
reactiveFlowLayout,
|
|
1079
1551
|
reactive_layout_exports
|
|
1080
1552
|
};
|
|
1081
|
-
//# sourceMappingURL=chunk-
|
|
1553
|
+
//# sourceMappingURL=chunk-TKE3JGOH.js.map
|