@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/sdk.node.js
CHANGED
|
@@ -9505,7 +9505,7 @@ var WeaveRegisterManager = class {
|
|
|
9505
9505
|
};
|
|
9506
9506
|
//#endregion
|
|
9507
9507
|
//#region package.json
|
|
9508
|
-
var version = "5.7.0-SNAPSHOT.
|
|
9508
|
+
var version = "5.7.0-SNAPSHOT.596.1";
|
|
9509
9509
|
//#endregion
|
|
9510
9510
|
//#region src/managers/setup.ts
|
|
9511
9511
|
var WeaveSetupManager = class {
|
|
@@ -14415,7 +14415,7 @@ function normalizeRuns(runs) {
|
|
|
14415
14415
|
const out = [];
|
|
14416
14416
|
for (const run of runs) {
|
|
14417
14417
|
if (run.t === "") continue;
|
|
14418
|
-
const last = out
|
|
14418
|
+
const last = out.at(-1);
|
|
14419
14419
|
if (last && sameMarks(last.m, run.m)) last.t += run.t;
|
|
14420
14420
|
else out.push({
|
|
14421
14421
|
t: run.t,
|
|
@@ -14490,7 +14490,7 @@ function replaceRange(blocks, start, end, insert) {
|
|
|
14490
14490
|
const suffixBlocks = [];
|
|
14491
14491
|
let inheritedMarks;
|
|
14492
14492
|
let pos = 0;
|
|
14493
|
-
blocks.forEach((block
|
|
14493
|
+
blocks.forEach((block) => {
|
|
14494
14494
|
const len = blockText(block).length;
|
|
14495
14495
|
const bStart = pos;
|
|
14496
14496
|
const bEnd = pos + len;
|
|
@@ -14555,6 +14555,43 @@ const now = () => typeof performance !== "undefined" ? performance.now() : Date.
|
|
|
14555
14555
|
const WS = /\s/;
|
|
14556
14556
|
const MAX_CACHE = 2e4;
|
|
14557
14557
|
const MAX_CACHED_CHUNK = 256;
|
|
14558
|
+
function flattenBlock(block) {
|
|
14559
|
+
const graphemes = [];
|
|
14560
|
+
const runOf = [];
|
|
14561
|
+
for (let ri = 0; ri < block.runs.length; ri++) for (const g of splitGraphemes(block.runs[ri].t)) {
|
|
14562
|
+
graphemes.push(g);
|
|
14563
|
+
runOf.push(ri);
|
|
14564
|
+
}
|
|
14565
|
+
return {
|
|
14566
|
+
graphemes,
|
|
14567
|
+
runOf
|
|
14568
|
+
};
|
|
14569
|
+
}
|
|
14570
|
+
function trimTrailingSpace(graphemes, start, end) {
|
|
14571
|
+
let e = end;
|
|
14572
|
+
while (e > start && WS.test(graphemes[e - 1])) e--;
|
|
14573
|
+
return e;
|
|
14574
|
+
}
|
|
14575
|
+
function skipSpace(graphemes, from) {
|
|
14576
|
+
let i = from;
|
|
14577
|
+
while (i < graphemes.length && WS.test(graphemes[i])) i++;
|
|
14578
|
+
return i;
|
|
14579
|
+
}
|
|
14580
|
+
const isNum = (v) => v !== void 0 && !Number.isNaN(v);
|
|
14581
|
+
/** Konva's word wrap: break after the last space/dash that fits (0 = no break). */
|
|
14582
|
+
function wordWrapIndex(graphemes, start, matchLen, matchWidth, maxWidth) {
|
|
14583
|
+
const nextChar = graphemes[start + matchLen];
|
|
14584
|
+
if ((nextChar === " " || nextChar === "-") && matchWidth <= maxWidth) return matchLen;
|
|
14585
|
+
const seg = graphemes.slice(start, start + matchLen);
|
|
14586
|
+
return Math.max(seg.lastIndexOf(" "), seg.lastIndexOf("-")) + 1;
|
|
14587
|
+
}
|
|
14588
|
+
function applyAlign(lines, align, width, padding) {
|
|
14589
|
+
if (align === "left") return;
|
|
14590
|
+
for (const line of lines) {
|
|
14591
|
+
const free = width - line.width - padding * 2;
|
|
14592
|
+
line.offsetX = align === "center" ? free / 2 : free;
|
|
14593
|
+
}
|
|
14594
|
+
}
|
|
14558
14595
|
var TextLayoutEngine = class {
|
|
14559
14596
|
measure;
|
|
14560
14597
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -14612,8 +14649,8 @@ var TextLayoutEngine = class {
|
|
|
14612
14649
|
layout(blocks, style, bounds) {
|
|
14613
14650
|
const font = fontString(style);
|
|
14614
14651
|
const padding = bounds.padding;
|
|
14615
|
-
const fixedWidth =
|
|
14616
|
-
const fixedHeight =
|
|
14652
|
+
const fixedWidth = isNum(bounds.width);
|
|
14653
|
+
const fixedHeight = isNum(bounds.height);
|
|
14617
14654
|
const maxWidth = (bounds.width ?? 0) - padding * 2;
|
|
14618
14655
|
const maxHeightPx = (bounds.height ?? 0) - padding * 2;
|
|
14619
14656
|
const lineHeightPx = style.lineHeight * style.fontSize;
|
|
@@ -14623,9 +14660,8 @@ var TextLayoutEngine = class {
|
|
|
14623
14660
|
let relaid = 0;
|
|
14624
14661
|
const lines = [];
|
|
14625
14662
|
let textWidth = 0;
|
|
14626
|
-
let currentHeightPx = 0;
|
|
14627
14663
|
let offset = 0;
|
|
14628
|
-
|
|
14664
|
+
for (let p = 0; p < blocks.length; p++) {
|
|
14629
14665
|
const block = blocks[p];
|
|
14630
14666
|
const sig = `${sigBase}|${JSON.stringify(block.runs)}`;
|
|
14631
14667
|
let entry = prev[p]?.sig === sig ? prev[p] : this.pool.get(sig);
|
|
@@ -14634,27 +14670,14 @@ var TextLayoutEngine = class {
|
|
|
14634
14670
|
relaid++;
|
|
14635
14671
|
}
|
|
14636
14672
|
next.push(entry);
|
|
14637
|
-
|
|
14638
|
-
|
|
14639
|
-
|
|
14640
|
-
|
|
14641
|
-
|
|
14642
|
-
|
|
14643
|
-
|
|
14644
|
-
|
|
14645
|
-
end: offset + startChar + text.length,
|
|
14646
|
-
text,
|
|
14647
|
-
width,
|
|
14648
|
-
measuredWidth: pl.measuredWidth,
|
|
14649
|
-
offsetX: 0,
|
|
14650
|
-
y: lines.length * lineHeightPx,
|
|
14651
|
-
segments,
|
|
14652
|
-
lastInParagraph: pl.lastInParagraph
|
|
14653
|
-
});
|
|
14654
|
-
textWidth = Math.max(textWidth, pl.measuredWidth);
|
|
14655
|
-
currentHeightPx += lineHeightPx;
|
|
14656
|
-
if (fixedHeight && currentHeightPx + lineHeightPx > maxHeightPx) break outer;
|
|
14657
|
-
}
|
|
14673
|
+
const emitted = this.emitLines(entry, block, p, offset, lines, {
|
|
14674
|
+
font,
|
|
14675
|
+
style,
|
|
14676
|
+
lineHeightPx,
|
|
14677
|
+
maxHeightPx: fixedHeight ? maxHeightPx : void 0
|
|
14678
|
+
});
|
|
14679
|
+
textWidth = Math.max(textWidth, emitted.maxWidth);
|
|
14680
|
+
if (emitted.stopped) break;
|
|
14658
14681
|
offset += blockText(block).length + 1;
|
|
14659
14682
|
}
|
|
14660
14683
|
this.paragraphs = next;
|
|
@@ -14662,10 +14685,7 @@ var TextLayoutEngine = class {
|
|
|
14662
14685
|
this.lastParagraphsRelaid = relaid;
|
|
14663
14686
|
const width = fixedWidth ? bounds.width : textWidth + padding * 2;
|
|
14664
14687
|
const height = fixedHeight ? bounds.height : lines.length * lineHeightPx + padding * 2;
|
|
14665
|
-
|
|
14666
|
-
const free = width - line.width - padding * 2;
|
|
14667
|
-
line.offsetX = style.align === "center" ? free / 2 : free;
|
|
14668
|
-
}
|
|
14688
|
+
applyAlign(lines, style.align, width, padding);
|
|
14669
14689
|
return {
|
|
14670
14690
|
lines,
|
|
14671
14691
|
textWidth,
|
|
@@ -14675,7 +14695,38 @@ var TextLayoutEngine = class {
|
|
|
14675
14695
|
height
|
|
14676
14696
|
};
|
|
14677
14697
|
}
|
|
14678
|
-
|
|
14698
|
+
/** Append a paragraph's lines to `lines`; stops once a fixed height is full. */
|
|
14699
|
+
emitLines(entry, block, paragraph, offset, lines, opts) {
|
|
14700
|
+
const { font, style, lineHeightPx, maxHeightPx } = opts;
|
|
14701
|
+
let maxWidth = 0;
|
|
14702
|
+
for (const pl of entry.lines) {
|
|
14703
|
+
const text = entry.graphemes.slice(pl.startG, pl.endG).join("");
|
|
14704
|
+
const segments = this.buildSegments(entry, block, pl, font, style);
|
|
14705
|
+
const startChar = entry.graphemes.slice(0, pl.startG).join("").length;
|
|
14706
|
+
lines.push({
|
|
14707
|
+
paragraph,
|
|
14708
|
+
start: offset + startChar,
|
|
14709
|
+
end: offset + startChar + text.length,
|
|
14710
|
+
text,
|
|
14711
|
+
width: segments.reduce((a, s) => a + s.width, 0),
|
|
14712
|
+
measuredWidth: pl.measuredWidth,
|
|
14713
|
+
offsetX: 0,
|
|
14714
|
+
y: lines.length * lineHeightPx,
|
|
14715
|
+
segments,
|
|
14716
|
+
lastInParagraph: pl.lastInParagraph
|
|
14717
|
+
});
|
|
14718
|
+
maxWidth = Math.max(maxWidth, pl.measuredWidth);
|
|
14719
|
+
if (maxHeightPx !== void 0 && (lines.length + 1) * lineHeightPx > maxHeightPx) return {
|
|
14720
|
+
stopped: true,
|
|
14721
|
+
maxWidth
|
|
14722
|
+
};
|
|
14723
|
+
}
|
|
14724
|
+
return {
|
|
14725
|
+
stopped: false,
|
|
14726
|
+
maxWidth
|
|
14727
|
+
};
|
|
14728
|
+
}
|
|
14729
|
+
rangeWidth(entry, from, to, font, spacing) {
|
|
14679
14730
|
let width = 0;
|
|
14680
14731
|
let i = from;
|
|
14681
14732
|
while (i < to) {
|
|
@@ -14687,15 +14738,39 @@ var TextLayoutEngine = class {
|
|
|
14687
14738
|
}
|
|
14688
14739
|
return width;
|
|
14689
14740
|
}
|
|
14741
|
+
/**
|
|
14742
|
+
* Longest prefix of graphemes[start..n) that fits `maxWidth`, found with an
|
|
14743
|
+
* exponential probe (bounds the work to about one line) plus a binary
|
|
14744
|
+
* search, like Konva. Always consumes at least one grapheme.
|
|
14745
|
+
*/
|
|
14746
|
+
longestFit(start, n, maxWidth, width) {
|
|
14747
|
+
let low = 0;
|
|
14748
|
+
let high = n - start;
|
|
14749
|
+
let probe = Math.min(high, 32);
|
|
14750
|
+
while (probe < high && width(start, start + probe) <= maxWidth) probe = Math.min(high, probe * 2);
|
|
14751
|
+
high = probe;
|
|
14752
|
+
let matchLen = 0;
|
|
14753
|
+
let matchWidth = 0;
|
|
14754
|
+
while (low < high) {
|
|
14755
|
+
const mid = low + high >>> 1;
|
|
14756
|
+
const w = width(start, start + mid + 1);
|
|
14757
|
+
if (w <= maxWidth) {
|
|
14758
|
+
low = mid + 1;
|
|
14759
|
+
matchLen = mid + 1;
|
|
14760
|
+
matchWidth = w;
|
|
14761
|
+
} else high = mid;
|
|
14762
|
+
}
|
|
14763
|
+
if (matchLen === 0) {
|
|
14764
|
+
matchLen = 1;
|
|
14765
|
+
matchWidth = width(start, start + 1);
|
|
14766
|
+
}
|
|
14767
|
+
return {
|
|
14768
|
+
matchLen,
|
|
14769
|
+
matchWidth
|
|
14770
|
+
};
|
|
14771
|
+
}
|
|
14690
14772
|
layoutParagraph(block, sig, font, style, fixedWidth, maxWidth) {
|
|
14691
|
-
const graphemes =
|
|
14692
|
-
const runOf = [];
|
|
14693
|
-
block.runs.forEach((run, ri) => {
|
|
14694
|
-
for (const g of splitGraphemes(run.t)) {
|
|
14695
|
-
graphemes.push(g);
|
|
14696
|
-
runOf.push(ri);
|
|
14697
|
-
}
|
|
14698
|
-
});
|
|
14773
|
+
const { graphemes, runOf } = flattenBlock(block);
|
|
14699
14774
|
const entry = {
|
|
14700
14775
|
sig,
|
|
14701
14776
|
graphemes,
|
|
@@ -14704,7 +14779,7 @@ var TextLayoutEngine = class {
|
|
|
14704
14779
|
};
|
|
14705
14780
|
const n = graphemes.length;
|
|
14706
14781
|
const spacing = style.letterSpacing;
|
|
14707
|
-
const width = (a, b) => this.rangeWidth(entry,
|
|
14782
|
+
const width = (a, b) => this.rangeWidth(entry, a, b, font, spacing);
|
|
14708
14783
|
const shouldWrap = style.wrap !== "none";
|
|
14709
14784
|
const wrapAtWord = style.wrap !== "char" && shouldWrap;
|
|
14710
14785
|
const whole = width(0, n);
|
|
@@ -14719,26 +14794,7 @@ var TextLayoutEngine = class {
|
|
|
14719
14794
|
}
|
|
14720
14795
|
let start = 0;
|
|
14721
14796
|
while (start < n) {
|
|
14722
|
-
let
|
|
14723
|
-
let high = n - start;
|
|
14724
|
-
let probe = Math.min(high, 32);
|
|
14725
|
-
while (probe < high && width(start, start + probe) <= maxWidth) probe = Math.min(high, probe * 2);
|
|
14726
|
-
high = probe;
|
|
14727
|
-
let matchLen = 0;
|
|
14728
|
-
let matchWidth = 0;
|
|
14729
|
-
while (low < high) {
|
|
14730
|
-
const mid = low + high >>> 1;
|
|
14731
|
-
const w = width(start, start + mid + 1);
|
|
14732
|
-
if (w <= maxWidth) {
|
|
14733
|
-
low = mid + 1;
|
|
14734
|
-
matchLen = mid + 1;
|
|
14735
|
-
matchWidth = w;
|
|
14736
|
-
} else high = mid;
|
|
14737
|
-
}
|
|
14738
|
-
if (matchLen === 0) {
|
|
14739
|
-
matchLen = 1;
|
|
14740
|
-
matchWidth = width(start, start + 1);
|
|
14741
|
-
}
|
|
14797
|
+
let { matchLen, matchWidth } = this.longestFit(start, n, maxWidth, width);
|
|
14742
14798
|
if (start + matchLen >= n) {
|
|
14743
14799
|
entry.lines.push({
|
|
14744
14800
|
startG: start,
|
|
@@ -14749,32 +14805,22 @@ var TextLayoutEngine = class {
|
|
|
14749
14805
|
return entry;
|
|
14750
14806
|
}
|
|
14751
14807
|
if (wrapAtWord) {
|
|
14752
|
-
const
|
|
14753
|
-
|
|
14754
|
-
|
|
14755
|
-
if (nextIsSpaceOrDash && matchWidth <= maxWidth) wrapIndex = matchLen;
|
|
14756
|
-
else {
|
|
14757
|
-
const seg = graphemes.slice(start, start + matchLen);
|
|
14758
|
-
wrapIndex = Math.max(seg.lastIndexOf(" "), seg.lastIndexOf("-")) + 1;
|
|
14759
|
-
}
|
|
14760
|
-
if (wrapIndex > 0) {
|
|
14761
|
-
matchLen = wrapIndex;
|
|
14808
|
+
const wrapped = wordWrapIndex(graphemes, start, matchLen, matchWidth, maxWidth);
|
|
14809
|
+
if (wrapped > 0) {
|
|
14810
|
+
matchLen = wrapped;
|
|
14762
14811
|
matchWidth = width(start, start + matchLen);
|
|
14763
14812
|
}
|
|
14764
14813
|
}
|
|
14765
|
-
|
|
14766
|
-
let trimmedEnd = end;
|
|
14767
|
-
while (trimmedEnd > start && WS.test(graphemes[trimmedEnd - 1])) trimmedEnd--;
|
|
14814
|
+
const end = start + matchLen;
|
|
14768
14815
|
entry.lines.push({
|
|
14769
14816
|
startG: start,
|
|
14770
|
-
endG:
|
|
14817
|
+
endG: trimTrailingSpace(graphemes, start, end),
|
|
14771
14818
|
measuredWidth: matchWidth,
|
|
14772
14819
|
lastInParagraph: false
|
|
14773
14820
|
});
|
|
14774
|
-
|
|
14775
|
-
start = end;
|
|
14821
|
+
start = skipSpace(graphemes, end);
|
|
14776
14822
|
}
|
|
14777
|
-
const last = entry.lines
|
|
14823
|
+
const last = entry.lines.at(-1);
|
|
14778
14824
|
if (last) last.lastInParagraph = true;
|
|
14779
14825
|
return entry;
|
|
14780
14826
|
}
|
|
@@ -14836,8 +14882,6 @@ var WeaveTextV2Shape = class extends Konva.Shape {
|
|
|
14836
14882
|
this.on(LAYOUT_ATTRS.map((a) => `${a}Change.konva`).join(" "), () => {
|
|
14837
14883
|
this.layoutCache = null;
|
|
14838
14884
|
});
|
|
14839
|
-
this.sceneFunc(this._paint);
|
|
14840
|
-
this.hitFunc(this._hit);
|
|
14841
14885
|
}
|
|
14842
14886
|
text(value) {
|
|
14843
14887
|
if (value === void 0) return typeof this.attrs.text === "string" ? this.attrs.text : blocksToText(this.getBlocks());
|
|
@@ -15029,18 +15073,12 @@ var WeaveTextV2Shape = class extends Konva.Shape {
|
|
|
15029
15073
|
y2: Math.max(...pts.map((p) => p.y))
|
|
15030
15074
|
};
|
|
15031
15075
|
}
|
|
15032
|
-
|
|
15076
|
+
_sceneFunc = (ctx, shape) => {
|
|
15033
15077
|
const self = shape;
|
|
15034
15078
|
const layout = self.ensureLayout();
|
|
15035
15079
|
if (layout.lines.length === 0) return;
|
|
15036
|
-
const fontSize = self.fontSize();
|
|
15037
15080
|
const padding = self.padding();
|
|
15038
15081
|
const lineHeightPx = layout.lineHeightPx;
|
|
15039
|
-
const decoration = self.textDecoration();
|
|
15040
|
-
const underline = decoration.includes("underline");
|
|
15041
|
-
const lineThrough = decoration.includes("line-through");
|
|
15042
|
-
const spacing = self.letterSpacing();
|
|
15043
|
-
const fill = self.fill();
|
|
15044
15082
|
let baseline = "middle";
|
|
15045
15083
|
let translateY = lineHeightPx / 2;
|
|
15046
15084
|
if (!Konva.legacyTextRendering) {
|
|
@@ -15051,62 +15089,63 @@ var WeaveTextV2Shape = class extends Konva.Shape {
|
|
|
15051
15089
|
ctx.setAttr("font", fontString(self.style()));
|
|
15052
15090
|
ctx.setAttr("textBaseline", baseline);
|
|
15053
15091
|
ctx.setAttr("textAlign", "left");
|
|
15054
|
-
|
|
15055
|
-
const va = self.verticalAlign();
|
|
15056
|
-
const used = layout.lines.length * lineHeightPx + padding * 2;
|
|
15057
|
-
if (va === "middle") alignY = (self.getHeight() - used) / 2;
|
|
15058
|
-
else if (va === "bottom") alignY = self.getHeight() - used;
|
|
15092
|
+
const alignY = self.verticalOffset(layout);
|
|
15059
15093
|
ctx.translate(padding, alignY + padding);
|
|
15060
15094
|
const range = self.visibleRange();
|
|
15061
|
-
const
|
|
15095
|
+
const top = alignY + padding;
|
|
15062
15096
|
for (let n = 0; n < layout.lines.length; n++) {
|
|
15063
|
-
const
|
|
15064
|
-
|
|
15065
|
-
|
|
15066
|
-
ctx.save();
|
|
15067
|
-
const baseX = line.offsetX;
|
|
15068
|
-
if (underline) {
|
|
15069
|
-
ctx.save();
|
|
15070
|
-
ctx.beginPath();
|
|
15071
|
-
const uy = y + Math.round(fontSize / 4);
|
|
15072
|
-
ctx.moveTo(baseX, uy);
|
|
15073
|
-
ctx.lineTo(baseX + Math.round(line.width), uy);
|
|
15074
|
-
ctx.lineWidth = fontSize / 15;
|
|
15075
|
-
ctx.strokeStyle = fill;
|
|
15076
|
-
ctx.stroke();
|
|
15077
|
-
ctx.restore();
|
|
15078
|
-
}
|
|
15079
|
-
for (const seg of line.segments) {
|
|
15080
|
-
let x = baseX + seg.x;
|
|
15081
|
-
if (spacing !== 0) for (const ch of Array.from(seg.t)) {
|
|
15082
|
-
paintSelf._partialText = ch;
|
|
15083
|
-
paintSelf._partialTextX = x;
|
|
15084
|
-
paintSelf._partialTextY = y;
|
|
15085
|
-
ctx.fillStrokeShape(self);
|
|
15086
|
-
x += self.measureSize(ch).width + spacing;
|
|
15087
|
-
}
|
|
15088
|
-
else {
|
|
15089
|
-
paintSelf._partialText = seg.t;
|
|
15090
|
-
paintSelf._partialTextX = x;
|
|
15091
|
-
paintSelf._partialTextY = y;
|
|
15092
|
-
ctx.fillStrokeShape(self);
|
|
15093
|
-
}
|
|
15094
|
-
}
|
|
15095
|
-
if (lineThrough) {
|
|
15096
|
-
ctx.save();
|
|
15097
|
-
ctx.beginPath();
|
|
15098
|
-
const ly = y - Math.round(fontSize / 4);
|
|
15099
|
-
ctx.moveTo(baseX, ly);
|
|
15100
|
-
ctx.lineTo(baseX + Math.round(line.width), ly);
|
|
15101
|
-
ctx.lineWidth = fontSize / 15;
|
|
15102
|
-
ctx.strokeStyle = fill;
|
|
15103
|
-
ctx.stroke();
|
|
15104
|
-
ctx.restore();
|
|
15105
|
-
}
|
|
15106
|
-
ctx.restore();
|
|
15097
|
+
const lineTop = top + n * lineHeightPx;
|
|
15098
|
+
if (range && (lineTop + lineHeightPx < range.y1 - lineHeightPx || lineTop > range.y2 + lineHeightPx)) continue;
|
|
15099
|
+
self.paintLine(ctx, layout.lines[n], translateY + n * lineHeightPx);
|
|
15107
15100
|
}
|
|
15108
15101
|
};
|
|
15109
|
-
|
|
15102
|
+
/** Vertical offset of the text block inside the box (verticalAlign). */
|
|
15103
|
+
verticalOffset(layout) {
|
|
15104
|
+
const used = layout.lines.length * layout.lineHeightPx + this.padding() * 2;
|
|
15105
|
+
const va = this.verticalAlign();
|
|
15106
|
+
if (va === "middle") return (this.getHeight() - used) / 2;
|
|
15107
|
+
if (va === "bottom") return this.getHeight() - used;
|
|
15108
|
+
return 0;
|
|
15109
|
+
}
|
|
15110
|
+
paintLine(ctx, line, y) {
|
|
15111
|
+
const decoration = this.textDecoration();
|
|
15112
|
+
const fontSize = this.fontSize();
|
|
15113
|
+
ctx.save();
|
|
15114
|
+
if (decoration.includes("underline")) this.strokeDecoration(ctx, line, y + Math.round(fontSize / 4));
|
|
15115
|
+
for (const seg of line.segments) this.paintSegment(ctx, seg.t, line.offsetX + seg.x, y);
|
|
15116
|
+
if (decoration.includes("line-through")) this.strokeDecoration(ctx, line, y - Math.round(fontSize / 4));
|
|
15117
|
+
ctx.restore();
|
|
15118
|
+
}
|
|
15119
|
+
strokeDecoration(ctx, line, y) {
|
|
15120
|
+
ctx.save();
|
|
15121
|
+
ctx.beginPath();
|
|
15122
|
+
ctx.moveTo(line.offsetX, y);
|
|
15123
|
+
ctx.lineTo(line.offsetX + Math.round(line.width), y);
|
|
15124
|
+
ctx.lineWidth = this.fontSize() / 15;
|
|
15125
|
+
ctx.strokeStyle = this.fill();
|
|
15126
|
+
ctx.stroke();
|
|
15127
|
+
ctx.restore();
|
|
15128
|
+
}
|
|
15129
|
+
paintSegment(ctx, text, x, y) {
|
|
15130
|
+
const spacing = this.letterSpacing();
|
|
15131
|
+
if (spacing === 0) {
|
|
15132
|
+
this.fillText(ctx, text, x, y);
|
|
15133
|
+
return;
|
|
15134
|
+
}
|
|
15135
|
+
let cx = x;
|
|
15136
|
+
for (const ch of Array.from(text)) {
|
|
15137
|
+
this.fillText(ctx, ch, cx, y);
|
|
15138
|
+
cx += this.measureSize(ch).width + spacing;
|
|
15139
|
+
}
|
|
15140
|
+
}
|
|
15141
|
+
fillText(ctx, text, x, y) {
|
|
15142
|
+
const self = this;
|
|
15143
|
+
self._partialText = text;
|
|
15144
|
+
self._partialTextX = x;
|
|
15145
|
+
self._partialTextY = y;
|
|
15146
|
+
ctx.fillStrokeShape(this);
|
|
15147
|
+
}
|
|
15148
|
+
_hitFunc = (ctx, shape) => {
|
|
15110
15149
|
ctx.beginPath();
|
|
15111
15150
|
const self = shape;
|
|
15112
15151
|
ctx.rect(0, 0, self.getWidth(), self.getHeight());
|
|
@@ -15214,7 +15253,7 @@ function lineIndexAt(layout, offset) {
|
|
|
15214
15253
|
if (l.start <= offset) fallback = i;
|
|
15215
15254
|
if (offset >= l.start && offset <= l.end) {
|
|
15216
15255
|
const next = lines[i + 1];
|
|
15217
|
-
if (offset === l.end && !l.lastInParagraph && next
|
|
15256
|
+
if (offset === l.end && !l.lastInParagraph && next?.start === offset) continue;
|
|
15218
15257
|
return i;
|
|
15219
15258
|
}
|
|
15220
15259
|
}
|
|
@@ -15263,10 +15302,7 @@ function offsetInLine(line, x, measure) {
|
|
|
15263
15302
|
function moveVertical(layout, offset, dir, desiredX, measure) {
|
|
15264
15303
|
const j = lineIndexAt(layout, offset) + dir;
|
|
15265
15304
|
if (j < 0) return 0;
|
|
15266
|
-
if (j >= layout.lines.length)
|
|
15267
|
-
const last = layout.lines[layout.lines.length - 1];
|
|
15268
|
-
return last ? last.end : 0;
|
|
15269
|
-
}
|
|
15305
|
+
if (j >= layout.lines.length) return layout.lines.at(-1)?.end ?? 0;
|
|
15270
15306
|
return offsetInLine(layout.lines[j], desiredX, measure);
|
|
15271
15307
|
}
|
|
15272
15308
|
function lineHome(layout, offset) {
|
|
@@ -15496,9 +15532,10 @@ var TextEditSession = class {
|
|
|
15496
15532
|
capture: true
|
|
15497
15533
|
});
|
|
15498
15534
|
window.weaveTextEditing = {
|
|
15499
|
-
...window.weaveTextEditing
|
|
15535
|
+
...window.weaveTextEditing,
|
|
15500
15536
|
[this.id]: this.id
|
|
15501
15537
|
};
|
|
15538
|
+
if (this.host.selectAllOnStart) this.model.selectAll();
|
|
15502
15539
|
this.syncTextarea();
|
|
15503
15540
|
ta.focus();
|
|
15504
15541
|
this.positionTextarea();
|
|
@@ -15602,41 +15639,43 @@ var TextEditSession = class {
|
|
|
15602
15639
|
this.afterSelectionChange();
|
|
15603
15640
|
}
|
|
15604
15641
|
};
|
|
15605
|
-
|
|
15606
|
-
|
|
15642
|
+
/** Keys the session handles itself; everything else stays native. */
|
|
15643
|
+
handleSessionKey(e) {
|
|
15607
15644
|
const mod = e.ctrlKey || e.metaKey;
|
|
15608
15645
|
const key = e.key.toLowerCase();
|
|
15609
|
-
|
|
15610
|
-
|
|
15611
|
-
|
|
15612
|
-
|
|
15613
|
-
|
|
15614
|
-
if (
|
|
15615
|
-
|
|
15616
|
-
|
|
15617
|
-
|
|
15646
|
+
const isUndo = mod && key === "z" && !e.shiftKey;
|
|
15647
|
+
const isRedo = mod && (key === "y" || key === "z" && e.shiftKey);
|
|
15648
|
+
if (e.key === "Escape") this.host.onRequestExit("escape");
|
|
15649
|
+
else if (isUndo) this.undo();
|
|
15650
|
+
else if (isRedo) this.redo();
|
|
15651
|
+
else if (e.key === "Tab") return true;
|
|
15652
|
+
else return false;
|
|
15653
|
+
return true;
|
|
15654
|
+
}
|
|
15655
|
+
handleNavigationKey(e) {
|
|
15656
|
+
if (e.ctrlKey || e.metaKey) return false;
|
|
15657
|
+
if ((e.key === "ArrowUp" || e.key === "ArrowDown") && !e.altKey) {
|
|
15658
|
+
this.moveVertically(e.key === "ArrowUp" ? -1 : 1, e.shiftKey);
|
|
15659
|
+
return true;
|
|
15618
15660
|
}
|
|
15619
|
-
if (
|
|
15620
|
-
|
|
15621
|
-
this.
|
|
15622
|
-
|
|
15661
|
+
if (e.key === "Home" || e.key === "End") {
|
|
15662
|
+
const layout = this.target.getLayout();
|
|
15663
|
+
const to = e.key === "Home" ? lineHome(layout, this.model.focus) : lineEnd(layout, this.model.focus);
|
|
15664
|
+
this.model.moveTo(to, e.shiftKey);
|
|
15665
|
+
this.afterSelectionChange();
|
|
15666
|
+
return true;
|
|
15623
15667
|
}
|
|
15624
|
-
|
|
15668
|
+
return false;
|
|
15669
|
+
}
|
|
15670
|
+
onKeyDown = (e) => {
|
|
15671
|
+
e.stopPropagation();
|
|
15672
|
+
if (this.handleSessionKey(e)) {
|
|
15625
15673
|
e.preventDefault();
|
|
15626
15674
|
return;
|
|
15627
15675
|
}
|
|
15628
15676
|
if (this.composing) return;
|
|
15629
|
-
if ((e
|
|
15677
|
+
if (this.handleNavigationKey(e)) {
|
|
15630
15678
|
e.preventDefault();
|
|
15631
|
-
this.moveVertically(e.key === "ArrowUp" ? -1 : 1, e.shiftKey);
|
|
15632
|
-
return;
|
|
15633
|
-
}
|
|
15634
|
-
if ((e.key === "Home" || e.key === "End") && !mod) {
|
|
15635
|
-
e.preventDefault();
|
|
15636
|
-
const layout = this.target.getLayout();
|
|
15637
|
-
const to = e.key === "Home" ? lineHome(layout, this.model.focus) : lineEnd(layout, this.model.focus);
|
|
15638
|
-
this.model.moveTo(to, e.shiftKey);
|
|
15639
|
-
this.afterSelectionChange();
|
|
15640
15679
|
return;
|
|
15641
15680
|
}
|
|
15642
15681
|
setTimeout(this.syncFromTextarea, 0);
|
|
@@ -15650,7 +15689,7 @@ var TextEditSession = class {
|
|
|
15650
15689
|
};
|
|
15651
15690
|
moveVertically(dir, extend) {
|
|
15652
15691
|
const layout = this.target.getLayout();
|
|
15653
|
-
|
|
15692
|
+
this.model.desiredX ??= caretRect(layout, this.model.focus, this.target.measure).x;
|
|
15654
15693
|
const to = moveVertical(layout, this.model.focus, dir, this.model.desiredX, this.target.measure);
|
|
15655
15694
|
this.model.moveTo(to, extend, true);
|
|
15656
15695
|
this.afterSelectionChange();
|
|
@@ -15668,11 +15707,17 @@ var TextEditSession = class {
|
|
|
15668
15707
|
while (s < max - p && oldText[oldText.length - 1 - s] === newText[newText.length - 1 - s]) s++;
|
|
15669
15708
|
const inserted = newText.slice(p, newText.length - s);
|
|
15670
15709
|
const inputType = e.inputType ?? "";
|
|
15671
|
-
const kind = this.
|
|
15710
|
+
const kind = this.editKindFor(inputType);
|
|
15672
15711
|
this.model.replaceRange(p, oldText.length - s, inserted, kind);
|
|
15673
15712
|
this.model.anchor = this.model.focus = Math.min(ta.selectionEnd, this.model.getText().length);
|
|
15674
15713
|
this.afterContentChange(inserted.length);
|
|
15675
15714
|
};
|
|
15715
|
+
editKindFor(inputType) {
|
|
15716
|
+
if (this.composing || inputType.includes("Composition")) return "ime";
|
|
15717
|
+
if (inputType.startsWith("delete")) return "delete";
|
|
15718
|
+
if (inputType === "insertFromPaste") return "paste";
|
|
15719
|
+
return "type";
|
|
15720
|
+
}
|
|
15676
15721
|
onPaste = (e) => {
|
|
15677
15722
|
e.stopPropagation();
|
|
15678
15723
|
e.preventDefault();
|
|
@@ -15819,6 +15864,17 @@ var TextEditSession = class {
|
|
|
15819
15864
|
const o = this.target.getContentOffset();
|
|
15820
15865
|
ctx.save();
|
|
15821
15866
|
ctx.transform(rel.m[0], rel.m[1], rel.m[2], rel.m[3], rel.m[4], rel.m[5]);
|
|
15867
|
+
if (this.host.outlineColor) {
|
|
15868
|
+
const scale = Math.hypot(abs.m[0], abs.m[1]) || 1;
|
|
15869
|
+
const lw = (this.host.outlineWidth ?? 1) / scale;
|
|
15870
|
+
const { width, height } = this.target.getSize();
|
|
15871
|
+
ctx.setAttr("strokeStyle", this.host.outlineColor);
|
|
15872
|
+
ctx.setAttr("lineWidth", lw);
|
|
15873
|
+
ctx.beginPath();
|
|
15874
|
+
const pad = (this.host.outlinePadding ?? 0) / scale;
|
|
15875
|
+
ctx.rect(-pad, -pad, width + pad * 2, height + pad * 2);
|
|
15876
|
+
ctx.stroke();
|
|
15877
|
+
}
|
|
15822
15878
|
ctx.translate(o.x, o.y);
|
|
15823
15879
|
const { start, end } = this.model.getSelection();
|
|
15824
15880
|
if (start !== end) {
|
|
@@ -15862,6 +15918,12 @@ const WEAVE_TEXT_V2_SIZE_WARNING_THRESHOLD = 2e5;
|
|
|
15862
15918
|
const WEAVE_TEXT_V2_SELECTION_COLOR = "rgba(66, 133, 244, 0.35)";
|
|
15863
15919
|
const WEAVE_TEXT_V2_DEFAULT_CONFIG = {
|
|
15864
15920
|
...WEAVE_TEXT_NODE_DEFAULT_CONFIG,
|
|
15921
|
+
edition: { outline: {
|
|
15922
|
+
enabled: true,
|
|
15923
|
+
color: "#0074ff",
|
|
15924
|
+
width: 1,
|
|
15925
|
+
padding: 0
|
|
15926
|
+
} },
|
|
15865
15927
|
sizeWarning: { threshold: WEAVE_TEXT_V2_SIZE_WARNING_THRESHOLD }
|
|
15866
15928
|
};
|
|
15867
15929
|
//#endregion
|
|
@@ -15873,6 +15935,8 @@ const CORNER_ANCHORS = [
|
|
|
15873
15935
|
"bottom-right"
|
|
15874
15936
|
];
|
|
15875
15937
|
const SIDE_ANCHORS = ["middle-right", "middle-left"];
|
|
15938
|
+
const CORNER_ANCHOR_SET = new Set(CORNER_ANCHORS);
|
|
15939
|
+
const SIDE_ANCHOR_SET = new Set(SIDE_ANCHORS);
|
|
15876
15940
|
/**
|
|
15877
15941
|
* Drop-in replacement for `WeaveTextNode`. Same `nodeType` (`'text'`), so
|
|
15878
15942
|
* existing documents load unchanged; register it INSTEAD of `WeaveTextNode`
|
|
@@ -16106,8 +16170,14 @@ var WeaveTextV2Node = class extends WeaveNode {
|
|
|
16106
16170
|
y: p.y * sy
|
|
16107
16171
|
};
|
|
16108
16172
|
},
|
|
16173
|
+
selectAllOnStart: !create,
|
|
16109
16174
|
caretColor: this.config.cursor.color,
|
|
16110
16175
|
selectionColor: WEAVE_TEXT_V2_SELECTION_COLOR,
|
|
16176
|
+
...this.config.edition.outline.enabled && {
|
|
16177
|
+
outlineColor: this.config.edition.outline.color,
|
|
16178
|
+
outlineWidth: this.config.edition.outline.width,
|
|
16179
|
+
outlinePadding: this.config.edition.outline.padding
|
|
16180
|
+
},
|
|
16111
16181
|
signal: this.instance.getEventsController().signal,
|
|
16112
16182
|
onChange: (blocks) => this.checkSize(shape, blocks),
|
|
16113
16183
|
onRequestExit: () => this.exitEditMode(shape)
|
|
@@ -16173,8 +16243,8 @@ var WeaveTextV2Node = class extends WeaveNode {
|
|
|
16173
16243
|
}
|
|
16174
16244
|
setupTransform(text) {
|
|
16175
16245
|
let actualAnchor = void 0;
|
|
16176
|
-
const isSide = () =>
|
|
16177
|
-
const isCorner = () =>
|
|
16246
|
+
const isSide = () => SIDE_ANCHOR_SET.has(actualAnchor ?? "");
|
|
16247
|
+
const isCorner = () => CORNER_ANCHOR_SET.has(actualAnchor ?? "");
|
|
16178
16248
|
const autoWidthLayout = () => [TEXT_LAYOUT.AUTO_HEIGHT, TEXT_LAYOUT.SMART].includes(text.getAttrs().layout);
|
|
16179
16249
|
text.on("transformstart", (e) => {
|
|
16180
16250
|
const ctrlOrMeta = e.evt.ctrlKey || e.evt.metaKey;
|
|
@@ -16271,6 +16341,7 @@ var WeaveTextV2Node = class extends WeaveNode {
|
|
|
16271
16341
|
serialize(instance) {
|
|
16272
16342
|
const attrs = instance.getAttrs();
|
|
16273
16343
|
const cleanedAttrs = { ...attrs };
|
|
16344
|
+
for (const key of Object.keys(cleanedAttrs)) if (typeof cleanedAttrs[key] === "function") delete cleanedAttrs[key];
|
|
16274
16345
|
delete cleanedAttrs.mutexLocked;
|
|
16275
16346
|
delete cleanedAttrs.mutexUserId;
|
|
16276
16347
|
delete cleanedAttrs.draggable;
|