@inditextech/weave-sdk 5.7.0-SNAPSHOT.595.1 → 5.7.0-SNAPSHOT.596.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/sdk.js +246 -175
- package/dist/sdk.node.js +246 -175
- package/dist/sdk.node.stats.html +1 -1
- package/dist/sdk.stats.html +1 -1
- package/dist/types.d.ts +39 -7
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +246 -175
- package/dist/types.js.map +1 -1
- package/dist/types.stats.html +1 -1
- package/package.json +2 -2
package/dist/types.js
CHANGED
|
@@ -9502,7 +9502,7 @@ var WeaveRegisterManager = class {
|
|
|
9502
9502
|
};
|
|
9503
9503
|
//#endregion
|
|
9504
9504
|
//#region package.json
|
|
9505
|
-
var version = "5.7.0-SNAPSHOT.
|
|
9505
|
+
var version = "5.7.0-SNAPSHOT.596.1";
|
|
9506
9506
|
//#endregion
|
|
9507
9507
|
//#region src/managers/setup.ts
|
|
9508
9508
|
var WeaveSetupManager = class {
|
|
@@ -14455,7 +14455,7 @@ function normalizeRuns(runs) {
|
|
|
14455
14455
|
const out = [];
|
|
14456
14456
|
for (const run of runs) {
|
|
14457
14457
|
if (run.t === "") continue;
|
|
14458
|
-
const last = out
|
|
14458
|
+
const last = out.at(-1);
|
|
14459
14459
|
if (last && sameMarks(last.m, run.m)) last.t += run.t;
|
|
14460
14460
|
else out.push({
|
|
14461
14461
|
t: run.t,
|
|
@@ -14530,7 +14530,7 @@ function replaceRange(blocks, start, end, insert) {
|
|
|
14530
14530
|
const suffixBlocks = [];
|
|
14531
14531
|
let inheritedMarks;
|
|
14532
14532
|
let pos = 0;
|
|
14533
|
-
blocks.forEach((block
|
|
14533
|
+
blocks.forEach((block) => {
|
|
14534
14534
|
const len = blockText(block).length;
|
|
14535
14535
|
const bStart = pos;
|
|
14536
14536
|
const bEnd = pos + len;
|
|
@@ -14595,6 +14595,43 @@ const now = () => typeof performance !== "undefined" ? performance.now() : Date.
|
|
|
14595
14595
|
const WS = /\s/;
|
|
14596
14596
|
const MAX_CACHE = 2e4;
|
|
14597
14597
|
const MAX_CACHED_CHUNK = 256;
|
|
14598
|
+
function flattenBlock(block) {
|
|
14599
|
+
const graphemes = [];
|
|
14600
|
+
const runOf = [];
|
|
14601
|
+
for (let ri = 0; ri < block.runs.length; ri++) for (const g of splitGraphemes(block.runs[ri].t)) {
|
|
14602
|
+
graphemes.push(g);
|
|
14603
|
+
runOf.push(ri);
|
|
14604
|
+
}
|
|
14605
|
+
return {
|
|
14606
|
+
graphemes,
|
|
14607
|
+
runOf
|
|
14608
|
+
};
|
|
14609
|
+
}
|
|
14610
|
+
function trimTrailingSpace(graphemes, start, end) {
|
|
14611
|
+
let e = end;
|
|
14612
|
+
while (e > start && WS.test(graphemes[e - 1])) e--;
|
|
14613
|
+
return e;
|
|
14614
|
+
}
|
|
14615
|
+
function skipSpace(graphemes, from) {
|
|
14616
|
+
let i = from;
|
|
14617
|
+
while (i < graphemes.length && WS.test(graphemes[i])) i++;
|
|
14618
|
+
return i;
|
|
14619
|
+
}
|
|
14620
|
+
const isNum = (v) => v !== void 0 && !Number.isNaN(v);
|
|
14621
|
+
/** Konva's word wrap: break after the last space/dash that fits (0 = no break). */
|
|
14622
|
+
function wordWrapIndex(graphemes, start, matchLen, matchWidth, maxWidth) {
|
|
14623
|
+
const nextChar = graphemes[start + matchLen];
|
|
14624
|
+
if ((nextChar === " " || nextChar === "-") && matchWidth <= maxWidth) return matchLen;
|
|
14625
|
+
const seg = graphemes.slice(start, start + matchLen);
|
|
14626
|
+
return Math.max(seg.lastIndexOf(" "), seg.lastIndexOf("-")) + 1;
|
|
14627
|
+
}
|
|
14628
|
+
function applyAlign(lines, align, width, padding) {
|
|
14629
|
+
if (align === "left") return;
|
|
14630
|
+
for (const line of lines) {
|
|
14631
|
+
const free = width - line.width - padding * 2;
|
|
14632
|
+
line.offsetX = align === "center" ? free / 2 : free;
|
|
14633
|
+
}
|
|
14634
|
+
}
|
|
14598
14635
|
var TextLayoutEngine = class {
|
|
14599
14636
|
measure;
|
|
14600
14637
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -14652,8 +14689,8 @@ var TextLayoutEngine = class {
|
|
|
14652
14689
|
layout(blocks, style, bounds) {
|
|
14653
14690
|
const font = fontString(style);
|
|
14654
14691
|
const padding = bounds.padding;
|
|
14655
|
-
const fixedWidth =
|
|
14656
|
-
const fixedHeight =
|
|
14692
|
+
const fixedWidth = isNum(bounds.width);
|
|
14693
|
+
const fixedHeight = isNum(bounds.height);
|
|
14657
14694
|
const maxWidth = (bounds.width ?? 0) - padding * 2;
|
|
14658
14695
|
const maxHeightPx = (bounds.height ?? 0) - padding * 2;
|
|
14659
14696
|
const lineHeightPx = style.lineHeight * style.fontSize;
|
|
@@ -14663,9 +14700,8 @@ var TextLayoutEngine = class {
|
|
|
14663
14700
|
let relaid = 0;
|
|
14664
14701
|
const lines = [];
|
|
14665
14702
|
let textWidth = 0;
|
|
14666
|
-
let currentHeightPx = 0;
|
|
14667
14703
|
let offset = 0;
|
|
14668
|
-
|
|
14704
|
+
for (let p = 0; p < blocks.length; p++) {
|
|
14669
14705
|
const block = blocks[p];
|
|
14670
14706
|
const sig = `${sigBase}|${JSON.stringify(block.runs)}`;
|
|
14671
14707
|
let entry = prev[p]?.sig === sig ? prev[p] : this.pool.get(sig);
|
|
@@ -14674,27 +14710,14 @@ var TextLayoutEngine = class {
|
|
|
14674
14710
|
relaid++;
|
|
14675
14711
|
}
|
|
14676
14712
|
next.push(entry);
|
|
14677
|
-
|
|
14678
|
-
|
|
14679
|
-
|
|
14680
|
-
|
|
14681
|
-
|
|
14682
|
-
|
|
14683
|
-
|
|
14684
|
-
|
|
14685
|
-
end: offset + startChar + text.length,
|
|
14686
|
-
text,
|
|
14687
|
-
width,
|
|
14688
|
-
measuredWidth: pl.measuredWidth,
|
|
14689
|
-
offsetX: 0,
|
|
14690
|
-
y: lines.length * lineHeightPx,
|
|
14691
|
-
segments,
|
|
14692
|
-
lastInParagraph: pl.lastInParagraph
|
|
14693
|
-
});
|
|
14694
|
-
textWidth = Math.max(textWidth, pl.measuredWidth);
|
|
14695
|
-
currentHeightPx += lineHeightPx;
|
|
14696
|
-
if (fixedHeight && currentHeightPx + lineHeightPx > maxHeightPx) break outer;
|
|
14697
|
-
}
|
|
14713
|
+
const emitted = this.emitLines(entry, block, p, offset, lines, {
|
|
14714
|
+
font,
|
|
14715
|
+
style,
|
|
14716
|
+
lineHeightPx,
|
|
14717
|
+
maxHeightPx: fixedHeight ? maxHeightPx : void 0
|
|
14718
|
+
});
|
|
14719
|
+
textWidth = Math.max(textWidth, emitted.maxWidth);
|
|
14720
|
+
if (emitted.stopped) break;
|
|
14698
14721
|
offset += blockText(block).length + 1;
|
|
14699
14722
|
}
|
|
14700
14723
|
this.paragraphs = next;
|
|
@@ -14702,10 +14725,7 @@ var TextLayoutEngine = class {
|
|
|
14702
14725
|
this.lastParagraphsRelaid = relaid;
|
|
14703
14726
|
const width = fixedWidth ? bounds.width : textWidth + padding * 2;
|
|
14704
14727
|
const height = fixedHeight ? bounds.height : lines.length * lineHeightPx + padding * 2;
|
|
14705
|
-
|
|
14706
|
-
const free = width - line.width - padding * 2;
|
|
14707
|
-
line.offsetX = style.align === "center" ? free / 2 : free;
|
|
14708
|
-
}
|
|
14728
|
+
applyAlign(lines, style.align, width, padding);
|
|
14709
14729
|
return {
|
|
14710
14730
|
lines,
|
|
14711
14731
|
textWidth,
|
|
@@ -14715,7 +14735,38 @@ var TextLayoutEngine = class {
|
|
|
14715
14735
|
height
|
|
14716
14736
|
};
|
|
14717
14737
|
}
|
|
14718
|
-
|
|
14738
|
+
/** Append a paragraph's lines to `lines`; stops once a fixed height is full. */
|
|
14739
|
+
emitLines(entry, block, paragraph, offset, lines, opts) {
|
|
14740
|
+
const { font, style, lineHeightPx, maxHeightPx } = opts;
|
|
14741
|
+
let maxWidth = 0;
|
|
14742
|
+
for (const pl of entry.lines) {
|
|
14743
|
+
const text = entry.graphemes.slice(pl.startG, pl.endG).join("");
|
|
14744
|
+
const segments = this.buildSegments(entry, block, pl, font, style);
|
|
14745
|
+
const startChar = entry.graphemes.slice(0, pl.startG).join("").length;
|
|
14746
|
+
lines.push({
|
|
14747
|
+
paragraph,
|
|
14748
|
+
start: offset + startChar,
|
|
14749
|
+
end: offset + startChar + text.length,
|
|
14750
|
+
text,
|
|
14751
|
+
width: segments.reduce((a, s) => a + s.width, 0),
|
|
14752
|
+
measuredWidth: pl.measuredWidth,
|
|
14753
|
+
offsetX: 0,
|
|
14754
|
+
y: lines.length * lineHeightPx,
|
|
14755
|
+
segments,
|
|
14756
|
+
lastInParagraph: pl.lastInParagraph
|
|
14757
|
+
});
|
|
14758
|
+
maxWidth = Math.max(maxWidth, pl.measuredWidth);
|
|
14759
|
+
if (maxHeightPx !== void 0 && (lines.length + 1) * lineHeightPx > maxHeightPx) return {
|
|
14760
|
+
stopped: true,
|
|
14761
|
+
maxWidth
|
|
14762
|
+
};
|
|
14763
|
+
}
|
|
14764
|
+
return {
|
|
14765
|
+
stopped: false,
|
|
14766
|
+
maxWidth
|
|
14767
|
+
};
|
|
14768
|
+
}
|
|
14769
|
+
rangeWidth(entry, from, to, font, spacing) {
|
|
14719
14770
|
let width = 0;
|
|
14720
14771
|
let i = from;
|
|
14721
14772
|
while (i < to) {
|
|
@@ -14727,15 +14778,39 @@ var TextLayoutEngine = class {
|
|
|
14727
14778
|
}
|
|
14728
14779
|
return width;
|
|
14729
14780
|
}
|
|
14781
|
+
/**
|
|
14782
|
+
* Longest prefix of graphemes[start..n) that fits `maxWidth`, found with an
|
|
14783
|
+
* exponential probe (bounds the work to about one line) plus a binary
|
|
14784
|
+
* search, like Konva. Always consumes at least one grapheme.
|
|
14785
|
+
*/
|
|
14786
|
+
longestFit(start, n, maxWidth, width) {
|
|
14787
|
+
let low = 0;
|
|
14788
|
+
let high = n - start;
|
|
14789
|
+
let probe = Math.min(high, 32);
|
|
14790
|
+
while (probe < high && width(start, start + probe) <= maxWidth) probe = Math.min(high, probe * 2);
|
|
14791
|
+
high = probe;
|
|
14792
|
+
let matchLen = 0;
|
|
14793
|
+
let matchWidth = 0;
|
|
14794
|
+
while (low < high) {
|
|
14795
|
+
const mid = low + high >>> 1;
|
|
14796
|
+
const w = width(start, start + mid + 1);
|
|
14797
|
+
if (w <= maxWidth) {
|
|
14798
|
+
low = mid + 1;
|
|
14799
|
+
matchLen = mid + 1;
|
|
14800
|
+
matchWidth = w;
|
|
14801
|
+
} else high = mid;
|
|
14802
|
+
}
|
|
14803
|
+
if (matchLen === 0) {
|
|
14804
|
+
matchLen = 1;
|
|
14805
|
+
matchWidth = width(start, start + 1);
|
|
14806
|
+
}
|
|
14807
|
+
return {
|
|
14808
|
+
matchLen,
|
|
14809
|
+
matchWidth
|
|
14810
|
+
};
|
|
14811
|
+
}
|
|
14730
14812
|
layoutParagraph(block, sig, font, style, fixedWidth, maxWidth) {
|
|
14731
|
-
const graphemes =
|
|
14732
|
-
const runOf = [];
|
|
14733
|
-
block.runs.forEach((run, ri) => {
|
|
14734
|
-
for (const g of splitGraphemes(run.t)) {
|
|
14735
|
-
graphemes.push(g);
|
|
14736
|
-
runOf.push(ri);
|
|
14737
|
-
}
|
|
14738
|
-
});
|
|
14813
|
+
const { graphemes, runOf } = flattenBlock(block);
|
|
14739
14814
|
const entry = {
|
|
14740
14815
|
sig,
|
|
14741
14816
|
graphemes,
|
|
@@ -14744,7 +14819,7 @@ var TextLayoutEngine = class {
|
|
|
14744
14819
|
};
|
|
14745
14820
|
const n = graphemes.length;
|
|
14746
14821
|
const spacing = style.letterSpacing;
|
|
14747
|
-
const width = (a, b) => this.rangeWidth(entry,
|
|
14822
|
+
const width = (a, b) => this.rangeWidth(entry, a, b, font, spacing);
|
|
14748
14823
|
const shouldWrap = style.wrap !== "none";
|
|
14749
14824
|
const wrapAtWord = style.wrap !== "char" && shouldWrap;
|
|
14750
14825
|
const whole = width(0, n);
|
|
@@ -14759,26 +14834,7 @@ var TextLayoutEngine = class {
|
|
|
14759
14834
|
}
|
|
14760
14835
|
let start = 0;
|
|
14761
14836
|
while (start < n) {
|
|
14762
|
-
let
|
|
14763
|
-
let high = n - start;
|
|
14764
|
-
let probe = Math.min(high, 32);
|
|
14765
|
-
while (probe < high && width(start, start + probe) <= maxWidth) probe = Math.min(high, probe * 2);
|
|
14766
|
-
high = probe;
|
|
14767
|
-
let matchLen = 0;
|
|
14768
|
-
let matchWidth = 0;
|
|
14769
|
-
while (low < high) {
|
|
14770
|
-
const mid = low + high >>> 1;
|
|
14771
|
-
const w = width(start, start + mid + 1);
|
|
14772
|
-
if (w <= maxWidth) {
|
|
14773
|
-
low = mid + 1;
|
|
14774
|
-
matchLen = mid + 1;
|
|
14775
|
-
matchWidth = w;
|
|
14776
|
-
} else high = mid;
|
|
14777
|
-
}
|
|
14778
|
-
if (matchLen === 0) {
|
|
14779
|
-
matchLen = 1;
|
|
14780
|
-
matchWidth = width(start, start + 1);
|
|
14781
|
-
}
|
|
14837
|
+
let { matchLen, matchWidth } = this.longestFit(start, n, maxWidth, width);
|
|
14782
14838
|
if (start + matchLen >= n) {
|
|
14783
14839
|
entry.lines.push({
|
|
14784
14840
|
startG: start,
|
|
@@ -14789,32 +14845,22 @@ var TextLayoutEngine = class {
|
|
|
14789
14845
|
return entry;
|
|
14790
14846
|
}
|
|
14791
14847
|
if (wrapAtWord) {
|
|
14792
|
-
const
|
|
14793
|
-
|
|
14794
|
-
|
|
14795
|
-
if (nextIsSpaceOrDash && matchWidth <= maxWidth) wrapIndex = matchLen;
|
|
14796
|
-
else {
|
|
14797
|
-
const seg = graphemes.slice(start, start + matchLen);
|
|
14798
|
-
wrapIndex = Math.max(seg.lastIndexOf(" "), seg.lastIndexOf("-")) + 1;
|
|
14799
|
-
}
|
|
14800
|
-
if (wrapIndex > 0) {
|
|
14801
|
-
matchLen = wrapIndex;
|
|
14848
|
+
const wrapped = wordWrapIndex(graphemes, start, matchLen, matchWidth, maxWidth);
|
|
14849
|
+
if (wrapped > 0) {
|
|
14850
|
+
matchLen = wrapped;
|
|
14802
14851
|
matchWidth = width(start, start + matchLen);
|
|
14803
14852
|
}
|
|
14804
14853
|
}
|
|
14805
|
-
|
|
14806
|
-
let trimmedEnd = end;
|
|
14807
|
-
while (trimmedEnd > start && WS.test(graphemes[trimmedEnd - 1])) trimmedEnd--;
|
|
14854
|
+
const end = start + matchLen;
|
|
14808
14855
|
entry.lines.push({
|
|
14809
14856
|
startG: start,
|
|
14810
|
-
endG:
|
|
14857
|
+
endG: trimTrailingSpace(graphemes, start, end),
|
|
14811
14858
|
measuredWidth: matchWidth,
|
|
14812
14859
|
lastInParagraph: false
|
|
14813
14860
|
});
|
|
14814
|
-
|
|
14815
|
-
start = end;
|
|
14861
|
+
start = skipSpace(graphemes, end);
|
|
14816
14862
|
}
|
|
14817
|
-
const last = entry.lines
|
|
14863
|
+
const last = entry.lines.at(-1);
|
|
14818
14864
|
if (last) last.lastInParagraph = true;
|
|
14819
14865
|
return entry;
|
|
14820
14866
|
}
|
|
@@ -14876,8 +14922,6 @@ var WeaveTextV2Shape = class extends Konva.Shape {
|
|
|
14876
14922
|
this.on(LAYOUT_ATTRS.map((a) => `${a}Change.konva`).join(" "), () => {
|
|
14877
14923
|
this.layoutCache = null;
|
|
14878
14924
|
});
|
|
14879
|
-
this.sceneFunc(this._paint);
|
|
14880
|
-
this.hitFunc(this._hit);
|
|
14881
14925
|
}
|
|
14882
14926
|
text(value) {
|
|
14883
14927
|
if (value === void 0) return typeof this.attrs.text === "string" ? this.attrs.text : blocksToText(this.getBlocks());
|
|
@@ -15069,18 +15113,12 @@ var WeaveTextV2Shape = class extends Konva.Shape {
|
|
|
15069
15113
|
y2: Math.max(...pts.map((p) => p.y))
|
|
15070
15114
|
};
|
|
15071
15115
|
}
|
|
15072
|
-
|
|
15116
|
+
_sceneFunc = (ctx, shape) => {
|
|
15073
15117
|
const self = shape;
|
|
15074
15118
|
const layout = self.ensureLayout();
|
|
15075
15119
|
if (layout.lines.length === 0) return;
|
|
15076
|
-
const fontSize = self.fontSize();
|
|
15077
15120
|
const padding = self.padding();
|
|
15078
15121
|
const lineHeightPx = layout.lineHeightPx;
|
|
15079
|
-
const decoration = self.textDecoration();
|
|
15080
|
-
const underline = decoration.includes("underline");
|
|
15081
|
-
const lineThrough = decoration.includes("line-through");
|
|
15082
|
-
const spacing = self.letterSpacing();
|
|
15083
|
-
const fill = self.fill();
|
|
15084
15122
|
let baseline = "middle";
|
|
15085
15123
|
let translateY = lineHeightPx / 2;
|
|
15086
15124
|
if (!Konva.legacyTextRendering) {
|
|
@@ -15091,62 +15129,63 @@ var WeaveTextV2Shape = class extends Konva.Shape {
|
|
|
15091
15129
|
ctx.setAttr("font", fontString(self.style()));
|
|
15092
15130
|
ctx.setAttr("textBaseline", baseline);
|
|
15093
15131
|
ctx.setAttr("textAlign", "left");
|
|
15094
|
-
|
|
15095
|
-
const va = self.verticalAlign();
|
|
15096
|
-
const used = layout.lines.length * lineHeightPx + padding * 2;
|
|
15097
|
-
if (va === "middle") alignY = (self.getHeight() - used) / 2;
|
|
15098
|
-
else if (va === "bottom") alignY = self.getHeight() - used;
|
|
15132
|
+
const alignY = self.verticalOffset(layout);
|
|
15099
15133
|
ctx.translate(padding, alignY + padding);
|
|
15100
15134
|
const range = self.visibleRange();
|
|
15101
|
-
const
|
|
15135
|
+
const top = alignY + padding;
|
|
15102
15136
|
for (let n = 0; n < layout.lines.length; n++) {
|
|
15103
|
-
const
|
|
15104
|
-
|
|
15105
|
-
|
|
15106
|
-
ctx.save();
|
|
15107
|
-
const baseX = line.offsetX;
|
|
15108
|
-
if (underline) {
|
|
15109
|
-
ctx.save();
|
|
15110
|
-
ctx.beginPath();
|
|
15111
|
-
const uy = y + Math.round(fontSize / 4);
|
|
15112
|
-
ctx.moveTo(baseX, uy);
|
|
15113
|
-
ctx.lineTo(baseX + Math.round(line.width), uy);
|
|
15114
|
-
ctx.lineWidth = fontSize / 15;
|
|
15115
|
-
ctx.strokeStyle = fill;
|
|
15116
|
-
ctx.stroke();
|
|
15117
|
-
ctx.restore();
|
|
15118
|
-
}
|
|
15119
|
-
for (const seg of line.segments) {
|
|
15120
|
-
let x = baseX + seg.x;
|
|
15121
|
-
if (spacing !== 0) for (const ch of Array.from(seg.t)) {
|
|
15122
|
-
paintSelf._partialText = ch;
|
|
15123
|
-
paintSelf._partialTextX = x;
|
|
15124
|
-
paintSelf._partialTextY = y;
|
|
15125
|
-
ctx.fillStrokeShape(self);
|
|
15126
|
-
x += self.measureSize(ch).width + spacing;
|
|
15127
|
-
}
|
|
15128
|
-
else {
|
|
15129
|
-
paintSelf._partialText = seg.t;
|
|
15130
|
-
paintSelf._partialTextX = x;
|
|
15131
|
-
paintSelf._partialTextY = y;
|
|
15132
|
-
ctx.fillStrokeShape(self);
|
|
15133
|
-
}
|
|
15134
|
-
}
|
|
15135
|
-
if (lineThrough) {
|
|
15136
|
-
ctx.save();
|
|
15137
|
-
ctx.beginPath();
|
|
15138
|
-
const ly = y - Math.round(fontSize / 4);
|
|
15139
|
-
ctx.moveTo(baseX, ly);
|
|
15140
|
-
ctx.lineTo(baseX + Math.round(line.width), ly);
|
|
15141
|
-
ctx.lineWidth = fontSize / 15;
|
|
15142
|
-
ctx.strokeStyle = fill;
|
|
15143
|
-
ctx.stroke();
|
|
15144
|
-
ctx.restore();
|
|
15145
|
-
}
|
|
15146
|
-
ctx.restore();
|
|
15137
|
+
const lineTop = top + n * lineHeightPx;
|
|
15138
|
+
if (range && (lineTop + lineHeightPx < range.y1 - lineHeightPx || lineTop > range.y2 + lineHeightPx)) continue;
|
|
15139
|
+
self.paintLine(ctx, layout.lines[n], translateY + n * lineHeightPx);
|
|
15147
15140
|
}
|
|
15148
15141
|
};
|
|
15149
|
-
|
|
15142
|
+
/** Vertical offset of the text block inside the box (verticalAlign). */
|
|
15143
|
+
verticalOffset(layout) {
|
|
15144
|
+
const used = layout.lines.length * layout.lineHeightPx + this.padding() * 2;
|
|
15145
|
+
const va = this.verticalAlign();
|
|
15146
|
+
if (va === "middle") return (this.getHeight() - used) / 2;
|
|
15147
|
+
if (va === "bottom") return this.getHeight() - used;
|
|
15148
|
+
return 0;
|
|
15149
|
+
}
|
|
15150
|
+
paintLine(ctx, line, y) {
|
|
15151
|
+
const decoration = this.textDecoration();
|
|
15152
|
+
const fontSize = this.fontSize();
|
|
15153
|
+
ctx.save();
|
|
15154
|
+
if (decoration.includes("underline")) this.strokeDecoration(ctx, line, y + Math.round(fontSize / 4));
|
|
15155
|
+
for (const seg of line.segments) this.paintSegment(ctx, seg.t, line.offsetX + seg.x, y);
|
|
15156
|
+
if (decoration.includes("line-through")) this.strokeDecoration(ctx, line, y - Math.round(fontSize / 4));
|
|
15157
|
+
ctx.restore();
|
|
15158
|
+
}
|
|
15159
|
+
strokeDecoration(ctx, line, y) {
|
|
15160
|
+
ctx.save();
|
|
15161
|
+
ctx.beginPath();
|
|
15162
|
+
ctx.moveTo(line.offsetX, y);
|
|
15163
|
+
ctx.lineTo(line.offsetX + Math.round(line.width), y);
|
|
15164
|
+
ctx.lineWidth = this.fontSize() / 15;
|
|
15165
|
+
ctx.strokeStyle = this.fill();
|
|
15166
|
+
ctx.stroke();
|
|
15167
|
+
ctx.restore();
|
|
15168
|
+
}
|
|
15169
|
+
paintSegment(ctx, text, x, y) {
|
|
15170
|
+
const spacing = this.letterSpacing();
|
|
15171
|
+
if (spacing === 0) {
|
|
15172
|
+
this.fillText(ctx, text, x, y);
|
|
15173
|
+
return;
|
|
15174
|
+
}
|
|
15175
|
+
let cx = x;
|
|
15176
|
+
for (const ch of Array.from(text)) {
|
|
15177
|
+
this.fillText(ctx, ch, cx, y);
|
|
15178
|
+
cx += this.measureSize(ch).width + spacing;
|
|
15179
|
+
}
|
|
15180
|
+
}
|
|
15181
|
+
fillText(ctx, text, x, y) {
|
|
15182
|
+
const self = this;
|
|
15183
|
+
self._partialText = text;
|
|
15184
|
+
self._partialTextX = x;
|
|
15185
|
+
self._partialTextY = y;
|
|
15186
|
+
ctx.fillStrokeShape(this);
|
|
15187
|
+
}
|
|
15188
|
+
_hitFunc = (ctx, shape) => {
|
|
15150
15189
|
ctx.beginPath();
|
|
15151
15190
|
const self = shape;
|
|
15152
15191
|
ctx.rect(0, 0, self.getWidth(), self.getHeight());
|
|
@@ -15254,7 +15293,7 @@ function lineIndexAt(layout, offset) {
|
|
|
15254
15293
|
if (l.start <= offset) fallback = i;
|
|
15255
15294
|
if (offset >= l.start && offset <= l.end) {
|
|
15256
15295
|
const next = lines[i + 1];
|
|
15257
|
-
if (offset === l.end && !l.lastInParagraph && next
|
|
15296
|
+
if (offset === l.end && !l.lastInParagraph && next?.start === offset) continue;
|
|
15258
15297
|
return i;
|
|
15259
15298
|
}
|
|
15260
15299
|
}
|
|
@@ -15303,10 +15342,7 @@ function offsetInLine(line, x, measure) {
|
|
|
15303
15342
|
function moveVertical(layout, offset, dir, desiredX, measure) {
|
|
15304
15343
|
const j = lineIndexAt(layout, offset) + dir;
|
|
15305
15344
|
if (j < 0) return 0;
|
|
15306
|
-
if (j >= layout.lines.length)
|
|
15307
|
-
const last = layout.lines[layout.lines.length - 1];
|
|
15308
|
-
return last ? last.end : 0;
|
|
15309
|
-
}
|
|
15345
|
+
if (j >= layout.lines.length) return layout.lines.at(-1)?.end ?? 0;
|
|
15310
15346
|
return offsetInLine(layout.lines[j], desiredX, measure);
|
|
15311
15347
|
}
|
|
15312
15348
|
function lineHome(layout, offset) {
|
|
@@ -15536,9 +15572,10 @@ var TextEditSession = class {
|
|
|
15536
15572
|
capture: true
|
|
15537
15573
|
});
|
|
15538
15574
|
window.weaveTextEditing = {
|
|
15539
|
-
...window.weaveTextEditing
|
|
15575
|
+
...window.weaveTextEditing,
|
|
15540
15576
|
[this.id]: this.id
|
|
15541
15577
|
};
|
|
15578
|
+
if (this.host.selectAllOnStart) this.model.selectAll();
|
|
15542
15579
|
this.syncTextarea();
|
|
15543
15580
|
ta.focus();
|
|
15544
15581
|
this.positionTextarea();
|
|
@@ -15642,41 +15679,43 @@ var TextEditSession = class {
|
|
|
15642
15679
|
this.afterSelectionChange();
|
|
15643
15680
|
}
|
|
15644
15681
|
};
|
|
15645
|
-
|
|
15646
|
-
|
|
15682
|
+
/** Keys the session handles itself; everything else stays native. */
|
|
15683
|
+
handleSessionKey(e) {
|
|
15647
15684
|
const mod = e.ctrlKey || e.metaKey;
|
|
15648
15685
|
const key = e.key.toLowerCase();
|
|
15649
|
-
|
|
15650
|
-
|
|
15651
|
-
|
|
15652
|
-
|
|
15653
|
-
|
|
15654
|
-
if (
|
|
15655
|
-
|
|
15656
|
-
|
|
15657
|
-
|
|
15686
|
+
const isUndo = mod && key === "z" && !e.shiftKey;
|
|
15687
|
+
const isRedo = mod && (key === "y" || key === "z" && e.shiftKey);
|
|
15688
|
+
if (e.key === "Escape") this.host.onRequestExit("escape");
|
|
15689
|
+
else if (isUndo) this.undo();
|
|
15690
|
+
else if (isRedo) this.redo();
|
|
15691
|
+
else if (e.key === "Tab") return true;
|
|
15692
|
+
else return false;
|
|
15693
|
+
return true;
|
|
15694
|
+
}
|
|
15695
|
+
handleNavigationKey(e) {
|
|
15696
|
+
if (e.ctrlKey || e.metaKey) return false;
|
|
15697
|
+
if ((e.key === "ArrowUp" || e.key === "ArrowDown") && !e.altKey) {
|
|
15698
|
+
this.moveVertically(e.key === "ArrowUp" ? -1 : 1, e.shiftKey);
|
|
15699
|
+
return true;
|
|
15658
15700
|
}
|
|
15659
|
-
if (
|
|
15660
|
-
|
|
15661
|
-
this.
|
|
15662
|
-
|
|
15701
|
+
if (e.key === "Home" || e.key === "End") {
|
|
15702
|
+
const layout = this.target.getLayout();
|
|
15703
|
+
const to = e.key === "Home" ? lineHome(layout, this.model.focus) : lineEnd(layout, this.model.focus);
|
|
15704
|
+
this.model.moveTo(to, e.shiftKey);
|
|
15705
|
+
this.afterSelectionChange();
|
|
15706
|
+
return true;
|
|
15663
15707
|
}
|
|
15664
|
-
|
|
15708
|
+
return false;
|
|
15709
|
+
}
|
|
15710
|
+
onKeyDown = (e) => {
|
|
15711
|
+
e.stopPropagation();
|
|
15712
|
+
if (this.handleSessionKey(e)) {
|
|
15665
15713
|
e.preventDefault();
|
|
15666
15714
|
return;
|
|
15667
15715
|
}
|
|
15668
15716
|
if (this.composing) return;
|
|
15669
|
-
if ((e
|
|
15717
|
+
if (this.handleNavigationKey(e)) {
|
|
15670
15718
|
e.preventDefault();
|
|
15671
|
-
this.moveVertically(e.key === "ArrowUp" ? -1 : 1, e.shiftKey);
|
|
15672
|
-
return;
|
|
15673
|
-
}
|
|
15674
|
-
if ((e.key === "Home" || e.key === "End") && !mod) {
|
|
15675
|
-
e.preventDefault();
|
|
15676
|
-
const layout = this.target.getLayout();
|
|
15677
|
-
const to = e.key === "Home" ? lineHome(layout, this.model.focus) : lineEnd(layout, this.model.focus);
|
|
15678
|
-
this.model.moveTo(to, e.shiftKey);
|
|
15679
|
-
this.afterSelectionChange();
|
|
15680
15719
|
return;
|
|
15681
15720
|
}
|
|
15682
15721
|
setTimeout(this.syncFromTextarea, 0);
|
|
@@ -15690,7 +15729,7 @@ var TextEditSession = class {
|
|
|
15690
15729
|
};
|
|
15691
15730
|
moveVertically(dir, extend) {
|
|
15692
15731
|
const layout = this.target.getLayout();
|
|
15693
|
-
|
|
15732
|
+
this.model.desiredX ??= caretRect(layout, this.model.focus, this.target.measure).x;
|
|
15694
15733
|
const to = moveVertical(layout, this.model.focus, dir, this.model.desiredX, this.target.measure);
|
|
15695
15734
|
this.model.moveTo(to, extend, true);
|
|
15696
15735
|
this.afterSelectionChange();
|
|
@@ -15708,11 +15747,17 @@ var TextEditSession = class {
|
|
|
15708
15747
|
while (s < max - p && oldText[oldText.length - 1 - s] === newText[newText.length - 1 - s]) s++;
|
|
15709
15748
|
const inserted = newText.slice(p, newText.length - s);
|
|
15710
15749
|
const inputType = e.inputType ?? "";
|
|
15711
|
-
const kind = this.
|
|
15750
|
+
const kind = this.editKindFor(inputType);
|
|
15712
15751
|
this.model.replaceRange(p, oldText.length - s, inserted, kind);
|
|
15713
15752
|
this.model.anchor = this.model.focus = Math.min(ta.selectionEnd, this.model.getText().length);
|
|
15714
15753
|
this.afterContentChange(inserted.length);
|
|
15715
15754
|
};
|
|
15755
|
+
editKindFor(inputType) {
|
|
15756
|
+
if (this.composing || inputType.includes("Composition")) return "ime";
|
|
15757
|
+
if (inputType.startsWith("delete")) return "delete";
|
|
15758
|
+
if (inputType === "insertFromPaste") return "paste";
|
|
15759
|
+
return "type";
|
|
15760
|
+
}
|
|
15716
15761
|
onPaste = (e) => {
|
|
15717
15762
|
e.stopPropagation();
|
|
15718
15763
|
e.preventDefault();
|
|
@@ -15859,6 +15904,17 @@ var TextEditSession = class {
|
|
|
15859
15904
|
const o = this.target.getContentOffset();
|
|
15860
15905
|
ctx.save();
|
|
15861
15906
|
ctx.transform(rel.m[0], rel.m[1], rel.m[2], rel.m[3], rel.m[4], rel.m[5]);
|
|
15907
|
+
if (this.host.outlineColor) {
|
|
15908
|
+
const scale = Math.hypot(abs.m[0], abs.m[1]) || 1;
|
|
15909
|
+
const lw = (this.host.outlineWidth ?? 1) / scale;
|
|
15910
|
+
const { width, height } = this.target.getSize();
|
|
15911
|
+
ctx.setAttr("strokeStyle", this.host.outlineColor);
|
|
15912
|
+
ctx.setAttr("lineWidth", lw);
|
|
15913
|
+
ctx.beginPath();
|
|
15914
|
+
const pad = (this.host.outlinePadding ?? 0) / scale;
|
|
15915
|
+
ctx.rect(-pad, -pad, width + pad * 2, height + pad * 2);
|
|
15916
|
+
ctx.stroke();
|
|
15917
|
+
}
|
|
15862
15918
|
ctx.translate(o.x, o.y);
|
|
15863
15919
|
const { start, end } = this.model.getSelection();
|
|
15864
15920
|
if (start !== end) {
|
|
@@ -15902,6 +15958,12 @@ const WEAVE_TEXT_V2_SIZE_WARNING_THRESHOLD = 2e5;
|
|
|
15902
15958
|
const WEAVE_TEXT_V2_SELECTION_COLOR = "rgba(66, 133, 244, 0.35)";
|
|
15903
15959
|
const WEAVE_TEXT_V2_DEFAULT_CONFIG = {
|
|
15904
15960
|
...WEAVE_TEXT_NODE_DEFAULT_CONFIG,
|
|
15961
|
+
edition: { outline: {
|
|
15962
|
+
enabled: true,
|
|
15963
|
+
color: "#0074ff",
|
|
15964
|
+
width: 1,
|
|
15965
|
+
padding: 0
|
|
15966
|
+
} },
|
|
15905
15967
|
sizeWarning: { threshold: WEAVE_TEXT_V2_SIZE_WARNING_THRESHOLD }
|
|
15906
15968
|
};
|
|
15907
15969
|
//#endregion
|
|
@@ -15913,6 +15975,8 @@ const CORNER_ANCHORS = [
|
|
|
15913
15975
|
"bottom-right"
|
|
15914
15976
|
];
|
|
15915
15977
|
const SIDE_ANCHORS = ["middle-right", "middle-left"];
|
|
15978
|
+
const CORNER_ANCHOR_SET = new Set(CORNER_ANCHORS);
|
|
15979
|
+
const SIDE_ANCHOR_SET = new Set(SIDE_ANCHORS);
|
|
15916
15980
|
/**
|
|
15917
15981
|
* Drop-in replacement for `WeaveTextNode`. Same `nodeType` (`'text'`), so
|
|
15918
15982
|
* existing documents load unchanged; register it INSTEAD of `WeaveTextNode`
|
|
@@ -16146,8 +16210,14 @@ var WeaveTextV2Node = class extends WeaveNode {
|
|
|
16146
16210
|
y: p.y * sy
|
|
16147
16211
|
};
|
|
16148
16212
|
},
|
|
16213
|
+
selectAllOnStart: !create,
|
|
16149
16214
|
caretColor: this.config.cursor.color,
|
|
16150
16215
|
selectionColor: WEAVE_TEXT_V2_SELECTION_COLOR,
|
|
16216
|
+
...this.config.edition.outline.enabled && {
|
|
16217
|
+
outlineColor: this.config.edition.outline.color,
|
|
16218
|
+
outlineWidth: this.config.edition.outline.width,
|
|
16219
|
+
outlinePadding: this.config.edition.outline.padding
|
|
16220
|
+
},
|
|
16151
16221
|
signal: this.instance.getEventsController().signal,
|
|
16152
16222
|
onChange: (blocks) => this.checkSize(shape, blocks),
|
|
16153
16223
|
onRequestExit: () => this.exitEditMode(shape)
|
|
@@ -16213,8 +16283,8 @@ var WeaveTextV2Node = class extends WeaveNode {
|
|
|
16213
16283
|
}
|
|
16214
16284
|
setupTransform(text) {
|
|
16215
16285
|
let actualAnchor = void 0;
|
|
16216
|
-
const isSide = () =>
|
|
16217
|
-
const isCorner = () =>
|
|
16286
|
+
const isSide = () => SIDE_ANCHOR_SET.has(actualAnchor ?? "");
|
|
16287
|
+
const isCorner = () => CORNER_ANCHOR_SET.has(actualAnchor ?? "");
|
|
16218
16288
|
const autoWidthLayout = () => [TEXT_LAYOUT.AUTO_HEIGHT, TEXT_LAYOUT.SMART].includes(text.getAttrs().layout);
|
|
16219
16289
|
text.on("transformstart", (e) => {
|
|
16220
16290
|
const ctrlOrMeta = e.evt.ctrlKey || e.evt.metaKey;
|
|
@@ -16311,6 +16381,7 @@ var WeaveTextV2Node = class extends WeaveNode {
|
|
|
16311
16381
|
serialize(instance) {
|
|
16312
16382
|
const attrs = instance.getAttrs();
|
|
16313
16383
|
const cleanedAttrs = { ...attrs };
|
|
16384
|
+
for (const key of Object.keys(cleanedAttrs)) if (typeof cleanedAttrs[key] === "function") delete cleanedAttrs[key];
|
|
16314
16385
|
delete cleanedAttrs.mutexLocked;
|
|
16315
16386
|
delete cleanedAttrs.mutexUserId;
|
|
16316
16387
|
delete cleanedAttrs.draggable;
|