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