@inditextech/weave-sdk 5.7.0-SNAPSHOT.595.1 → 5.7.0-SNAPSHOT.597.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 +278 -202
- package/dist/sdk.node.js +278 -202
- package/dist/sdk.node.stats.html +1 -1
- package/dist/sdk.stats.html +1 -1
- package/dist/types.d.ts +46 -7
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +278 -202
- 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.597.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());
|
|
@@ -15039,48 +15083,47 @@ var WeaveTextV2Shape = class extends Konva.Shape {
|
|
|
15039
15083
|
setViewport(range) {
|
|
15040
15084
|
this.viewport = range;
|
|
15041
15085
|
}
|
|
15042
|
-
|
|
15086
|
+
/**
|
|
15087
|
+
* Visible y-range in local coordinates, derived from the context being
|
|
15088
|
+
* painted (current transform + backing canvas size) instead of the stage.
|
|
15089
|
+
* The stage is not the paint target during export (off-screen canvases,
|
|
15090
|
+
* tiles, server-side), so using it culled visible lines. Returns null (paint
|
|
15091
|
+
* everything) when the transform cannot be read.
|
|
15092
|
+
*/
|
|
15093
|
+
visibleRange(ctx) {
|
|
15043
15094
|
if (this.viewport) return this.viewport;
|
|
15044
|
-
const
|
|
15045
|
-
|
|
15046
|
-
|
|
15047
|
-
const
|
|
15048
|
-
|
|
15049
|
-
const
|
|
15050
|
-
|
|
15051
|
-
|
|
15052
|
-
|
|
15053
|
-
|
|
15054
|
-
|
|
15055
|
-
|
|
15056
|
-
|
|
15057
|
-
|
|
15058
|
-
|
|
15059
|
-
|
|
15060
|
-
|
|
15061
|
-
|
|
15062
|
-
|
|
15063
|
-
|
|
15064
|
-
|
|
15065
|
-
})
|
|
15066
|
-
];
|
|
15095
|
+
const native = ctx._context;
|
|
15096
|
+
const m = native.getTransform?.() ?? native.currentTransform;
|
|
15097
|
+
if (!m) return null;
|
|
15098
|
+
const det = m.a * m.d - m.b * m.c;
|
|
15099
|
+
if (!det || !Number.isFinite(det)) return null;
|
|
15100
|
+
const canvas = ctx.getCanvas();
|
|
15101
|
+
const w = canvas.getWidth();
|
|
15102
|
+
const h = canvas.getHeight();
|
|
15103
|
+
if (!(w > 0) || !(h > 0)) return null;
|
|
15104
|
+
let y1 = Infinity;
|
|
15105
|
+
let y2 = -Infinity;
|
|
15106
|
+
for (const [px, py] of [
|
|
15107
|
+
[0, 0],
|
|
15108
|
+
[w, 0],
|
|
15109
|
+
[0, h],
|
|
15110
|
+
[w, h]
|
|
15111
|
+
]) {
|
|
15112
|
+
const y = (m.a * (py - m.f) - m.b * (px - m.e)) / det;
|
|
15113
|
+
if (y < y1) y1 = y;
|
|
15114
|
+
if (y > y2) y2 = y;
|
|
15115
|
+
}
|
|
15067
15116
|
return {
|
|
15068
|
-
y1
|
|
15069
|
-
y2
|
|
15117
|
+
y1,
|
|
15118
|
+
y2
|
|
15070
15119
|
};
|
|
15071
15120
|
}
|
|
15072
|
-
|
|
15121
|
+
_sceneFunc = (ctx, shape) => {
|
|
15073
15122
|
const self = shape;
|
|
15074
15123
|
const layout = self.ensureLayout();
|
|
15075
15124
|
if (layout.lines.length === 0) return;
|
|
15076
|
-
const fontSize = self.fontSize();
|
|
15077
15125
|
const padding = self.padding();
|
|
15078
15126
|
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
15127
|
let baseline = "middle";
|
|
15085
15128
|
let translateY = lineHeightPx / 2;
|
|
15086
15129
|
if (!Konva.legacyTextRendering) {
|
|
@@ -15091,62 +15134,63 @@ var WeaveTextV2Shape = class extends Konva.Shape {
|
|
|
15091
15134
|
ctx.setAttr("font", fontString(self.style()));
|
|
15092
15135
|
ctx.setAttr("textBaseline", baseline);
|
|
15093
15136
|
ctx.setAttr("textAlign", "left");
|
|
15094
|
-
|
|
15095
|
-
const
|
|
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;
|
|
15137
|
+
const alignY = self.verticalOffset(layout);
|
|
15138
|
+
const range = self.visibleRange(ctx);
|
|
15099
15139
|
ctx.translate(padding, alignY + padding);
|
|
15100
|
-
const
|
|
15101
|
-
const paintSelf = self;
|
|
15140
|
+
const top = alignY + padding;
|
|
15102
15141
|
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();
|
|
15142
|
+
const lineTop = top + n * lineHeightPx;
|
|
15143
|
+
if (range && (lineTop + lineHeightPx < range.y1 - lineHeightPx || lineTop > range.y2 + lineHeightPx)) continue;
|
|
15144
|
+
self.paintLine(ctx, layout.lines[n], translateY + n * lineHeightPx);
|
|
15147
15145
|
}
|
|
15148
15146
|
};
|
|
15149
|
-
|
|
15147
|
+
/** Vertical offset of the text block inside the box (verticalAlign). */
|
|
15148
|
+
verticalOffset(layout) {
|
|
15149
|
+
const used = layout.lines.length * layout.lineHeightPx + this.padding() * 2;
|
|
15150
|
+
const va = this.verticalAlign();
|
|
15151
|
+
if (va === "middle") return (this.getHeight() - used) / 2;
|
|
15152
|
+
if (va === "bottom") return this.getHeight() - used;
|
|
15153
|
+
return 0;
|
|
15154
|
+
}
|
|
15155
|
+
paintLine(ctx, line, y) {
|
|
15156
|
+
const decoration = this.textDecoration();
|
|
15157
|
+
const fontSize = this.fontSize();
|
|
15158
|
+
ctx.save();
|
|
15159
|
+
if (decoration.includes("underline")) this.strokeDecoration(ctx, line, y + Math.round(fontSize / 4));
|
|
15160
|
+
for (const seg of line.segments) this.paintSegment(ctx, seg.t, line.offsetX + seg.x, y);
|
|
15161
|
+
if (decoration.includes("line-through")) this.strokeDecoration(ctx, line, y - Math.round(fontSize / 4));
|
|
15162
|
+
ctx.restore();
|
|
15163
|
+
}
|
|
15164
|
+
strokeDecoration(ctx, line, y) {
|
|
15165
|
+
ctx.save();
|
|
15166
|
+
ctx.beginPath();
|
|
15167
|
+
ctx.moveTo(line.offsetX, y);
|
|
15168
|
+
ctx.lineTo(line.offsetX + Math.round(line.width), y);
|
|
15169
|
+
ctx.lineWidth = this.fontSize() / 15;
|
|
15170
|
+
ctx.strokeStyle = this.fill();
|
|
15171
|
+
ctx.stroke();
|
|
15172
|
+
ctx.restore();
|
|
15173
|
+
}
|
|
15174
|
+
paintSegment(ctx, text, x, y) {
|
|
15175
|
+
const spacing = this.letterSpacing();
|
|
15176
|
+
if (spacing === 0) {
|
|
15177
|
+
this.fillText(ctx, text, x, y);
|
|
15178
|
+
return;
|
|
15179
|
+
}
|
|
15180
|
+
let cx = x;
|
|
15181
|
+
for (const ch of Array.from(text)) {
|
|
15182
|
+
this.fillText(ctx, ch, cx, y);
|
|
15183
|
+
cx += this.measureSize(ch).width + spacing;
|
|
15184
|
+
}
|
|
15185
|
+
}
|
|
15186
|
+
fillText(ctx, text, x, y) {
|
|
15187
|
+
const self = this;
|
|
15188
|
+
self._partialText = text;
|
|
15189
|
+
self._partialTextX = x;
|
|
15190
|
+
self._partialTextY = y;
|
|
15191
|
+
ctx.fillStrokeShape(this);
|
|
15192
|
+
}
|
|
15193
|
+
_hitFunc = (ctx, shape) => {
|
|
15150
15194
|
ctx.beginPath();
|
|
15151
15195
|
const self = shape;
|
|
15152
15196
|
ctx.rect(0, 0, self.getWidth(), self.getHeight());
|
|
@@ -15254,7 +15298,7 @@ function lineIndexAt(layout, offset) {
|
|
|
15254
15298
|
if (l.start <= offset) fallback = i;
|
|
15255
15299
|
if (offset >= l.start && offset <= l.end) {
|
|
15256
15300
|
const next = lines[i + 1];
|
|
15257
|
-
if (offset === l.end && !l.lastInParagraph && next
|
|
15301
|
+
if (offset === l.end && !l.lastInParagraph && next?.start === offset) continue;
|
|
15258
15302
|
return i;
|
|
15259
15303
|
}
|
|
15260
15304
|
}
|
|
@@ -15303,10 +15347,7 @@ function offsetInLine(line, x, measure) {
|
|
|
15303
15347
|
function moveVertical(layout, offset, dir, desiredX, measure) {
|
|
15304
15348
|
const j = lineIndexAt(layout, offset) + dir;
|
|
15305
15349
|
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
|
-
}
|
|
15350
|
+
if (j >= layout.lines.length) return layout.lines.at(-1)?.end ?? 0;
|
|
15310
15351
|
return offsetInLine(layout.lines[j], desiredX, measure);
|
|
15311
15352
|
}
|
|
15312
15353
|
function lineHome(layout, offset) {
|
|
@@ -15536,9 +15577,10 @@ var TextEditSession = class {
|
|
|
15536
15577
|
capture: true
|
|
15537
15578
|
});
|
|
15538
15579
|
window.weaveTextEditing = {
|
|
15539
|
-
...window.weaveTextEditing
|
|
15580
|
+
...window.weaveTextEditing,
|
|
15540
15581
|
[this.id]: this.id
|
|
15541
15582
|
};
|
|
15583
|
+
if (this.host.selectAllOnStart) this.model.selectAll();
|
|
15542
15584
|
this.syncTextarea();
|
|
15543
15585
|
ta.focus();
|
|
15544
15586
|
this.positionTextarea();
|
|
@@ -15642,41 +15684,43 @@ var TextEditSession = class {
|
|
|
15642
15684
|
this.afterSelectionChange();
|
|
15643
15685
|
}
|
|
15644
15686
|
};
|
|
15645
|
-
|
|
15646
|
-
|
|
15687
|
+
/** Keys the session handles itself; everything else stays native. */
|
|
15688
|
+
handleSessionKey(e) {
|
|
15647
15689
|
const mod = e.ctrlKey || e.metaKey;
|
|
15648
15690
|
const key = e.key.toLowerCase();
|
|
15649
|
-
|
|
15650
|
-
|
|
15651
|
-
|
|
15652
|
-
|
|
15653
|
-
|
|
15654
|
-
if (
|
|
15655
|
-
|
|
15656
|
-
|
|
15657
|
-
|
|
15691
|
+
const isUndo = mod && key === "z" && !e.shiftKey;
|
|
15692
|
+
const isRedo = mod && (key === "y" || key === "z" && e.shiftKey);
|
|
15693
|
+
if (e.key === "Escape") this.host.onRequestExit("escape");
|
|
15694
|
+
else if (isUndo) this.undo();
|
|
15695
|
+
else if (isRedo) this.redo();
|
|
15696
|
+
else if (e.key === "Tab") return true;
|
|
15697
|
+
else return false;
|
|
15698
|
+
return true;
|
|
15699
|
+
}
|
|
15700
|
+
handleNavigationKey(e) {
|
|
15701
|
+
if (e.ctrlKey || e.metaKey) return false;
|
|
15702
|
+
if ((e.key === "ArrowUp" || e.key === "ArrowDown") && !e.altKey) {
|
|
15703
|
+
this.moveVertically(e.key === "ArrowUp" ? -1 : 1, e.shiftKey);
|
|
15704
|
+
return true;
|
|
15658
15705
|
}
|
|
15659
|
-
if (
|
|
15660
|
-
|
|
15661
|
-
this.
|
|
15662
|
-
|
|
15706
|
+
if (e.key === "Home" || e.key === "End") {
|
|
15707
|
+
const layout = this.target.getLayout();
|
|
15708
|
+
const to = e.key === "Home" ? lineHome(layout, this.model.focus) : lineEnd(layout, this.model.focus);
|
|
15709
|
+
this.model.moveTo(to, e.shiftKey);
|
|
15710
|
+
this.afterSelectionChange();
|
|
15711
|
+
return true;
|
|
15663
15712
|
}
|
|
15664
|
-
|
|
15713
|
+
return false;
|
|
15714
|
+
}
|
|
15715
|
+
onKeyDown = (e) => {
|
|
15716
|
+
e.stopPropagation();
|
|
15717
|
+
if (this.handleSessionKey(e)) {
|
|
15665
15718
|
e.preventDefault();
|
|
15666
15719
|
return;
|
|
15667
15720
|
}
|
|
15668
15721
|
if (this.composing) return;
|
|
15669
|
-
if ((e
|
|
15722
|
+
if (this.handleNavigationKey(e)) {
|
|
15670
15723
|
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
15724
|
return;
|
|
15681
15725
|
}
|
|
15682
15726
|
setTimeout(this.syncFromTextarea, 0);
|
|
@@ -15690,7 +15734,7 @@ var TextEditSession = class {
|
|
|
15690
15734
|
};
|
|
15691
15735
|
moveVertically(dir, extend) {
|
|
15692
15736
|
const layout = this.target.getLayout();
|
|
15693
|
-
|
|
15737
|
+
this.model.desiredX ??= caretRect(layout, this.model.focus, this.target.measure).x;
|
|
15694
15738
|
const to = moveVertical(layout, this.model.focus, dir, this.model.desiredX, this.target.measure);
|
|
15695
15739
|
this.model.moveTo(to, extend, true);
|
|
15696
15740
|
this.afterSelectionChange();
|
|
@@ -15708,11 +15752,17 @@ var TextEditSession = class {
|
|
|
15708
15752
|
while (s < max - p && oldText[oldText.length - 1 - s] === newText[newText.length - 1 - s]) s++;
|
|
15709
15753
|
const inserted = newText.slice(p, newText.length - s);
|
|
15710
15754
|
const inputType = e.inputType ?? "";
|
|
15711
|
-
const kind = this.
|
|
15755
|
+
const kind = this.editKindFor(inputType);
|
|
15712
15756
|
this.model.replaceRange(p, oldText.length - s, inserted, kind);
|
|
15713
15757
|
this.model.anchor = this.model.focus = Math.min(ta.selectionEnd, this.model.getText().length);
|
|
15714
15758
|
this.afterContentChange(inserted.length);
|
|
15715
15759
|
};
|
|
15760
|
+
editKindFor(inputType) {
|
|
15761
|
+
if (this.composing || inputType.includes("Composition")) return "ime";
|
|
15762
|
+
if (inputType.startsWith("delete")) return "delete";
|
|
15763
|
+
if (inputType === "insertFromPaste") return "paste";
|
|
15764
|
+
return "type";
|
|
15765
|
+
}
|
|
15716
15766
|
onPaste = (e) => {
|
|
15717
15767
|
e.stopPropagation();
|
|
15718
15768
|
e.preventDefault();
|
|
@@ -15859,6 +15909,17 @@ var TextEditSession = class {
|
|
|
15859
15909
|
const o = this.target.getContentOffset();
|
|
15860
15910
|
ctx.save();
|
|
15861
15911
|
ctx.transform(rel.m[0], rel.m[1], rel.m[2], rel.m[3], rel.m[4], rel.m[5]);
|
|
15912
|
+
if (this.host.outlineColor) {
|
|
15913
|
+
const scale = Math.hypot(abs.m[0], abs.m[1]) || 1;
|
|
15914
|
+
const lw = (this.host.outlineWidth ?? 1) / scale;
|
|
15915
|
+
const { width, height } = this.target.getSize();
|
|
15916
|
+
ctx.setAttr("strokeStyle", this.host.outlineColor);
|
|
15917
|
+
ctx.setAttr("lineWidth", lw);
|
|
15918
|
+
ctx.beginPath();
|
|
15919
|
+
const pad = (this.host.outlinePadding ?? 0) / scale;
|
|
15920
|
+
ctx.rect(-pad, -pad, width + pad * 2, height + pad * 2);
|
|
15921
|
+
ctx.stroke();
|
|
15922
|
+
}
|
|
15862
15923
|
ctx.translate(o.x, o.y);
|
|
15863
15924
|
const { start, end } = this.model.getSelection();
|
|
15864
15925
|
if (start !== end) {
|
|
@@ -15902,6 +15963,12 @@ const WEAVE_TEXT_V2_SIZE_WARNING_THRESHOLD = 2e5;
|
|
|
15902
15963
|
const WEAVE_TEXT_V2_SELECTION_COLOR = "rgba(66, 133, 244, 0.35)";
|
|
15903
15964
|
const WEAVE_TEXT_V2_DEFAULT_CONFIG = {
|
|
15904
15965
|
...WEAVE_TEXT_NODE_DEFAULT_CONFIG,
|
|
15966
|
+
edition: { outline: {
|
|
15967
|
+
enabled: true,
|
|
15968
|
+
color: "#0074ff",
|
|
15969
|
+
width: 1,
|
|
15970
|
+
padding: 0
|
|
15971
|
+
} },
|
|
15905
15972
|
sizeWarning: { threshold: WEAVE_TEXT_V2_SIZE_WARNING_THRESHOLD }
|
|
15906
15973
|
};
|
|
15907
15974
|
//#endregion
|
|
@@ -15913,6 +15980,8 @@ const CORNER_ANCHORS = [
|
|
|
15913
15980
|
"bottom-right"
|
|
15914
15981
|
];
|
|
15915
15982
|
const SIDE_ANCHORS = ["middle-right", "middle-left"];
|
|
15983
|
+
const CORNER_ANCHOR_SET = new Set(CORNER_ANCHORS);
|
|
15984
|
+
const SIDE_ANCHOR_SET = new Set(SIDE_ANCHORS);
|
|
15916
15985
|
/**
|
|
15917
15986
|
* Drop-in replacement for `WeaveTextNode`. Same `nodeType` (`'text'`), so
|
|
15918
15987
|
* existing documents load unchanged; register it INSTEAD of `WeaveTextNode`
|
|
@@ -16146,8 +16215,14 @@ var WeaveTextV2Node = class extends WeaveNode {
|
|
|
16146
16215
|
y: p.y * sy
|
|
16147
16216
|
};
|
|
16148
16217
|
},
|
|
16218
|
+
selectAllOnStart: !create,
|
|
16149
16219
|
caretColor: this.config.cursor.color,
|
|
16150
16220
|
selectionColor: WEAVE_TEXT_V2_SELECTION_COLOR,
|
|
16221
|
+
...this.config.edition.outline.enabled && {
|
|
16222
|
+
outlineColor: this.config.edition.outline.color,
|
|
16223
|
+
outlineWidth: this.config.edition.outline.width,
|
|
16224
|
+
outlinePadding: this.config.edition.outline.padding
|
|
16225
|
+
},
|
|
16151
16226
|
signal: this.instance.getEventsController().signal,
|
|
16152
16227
|
onChange: (blocks) => this.checkSize(shape, blocks),
|
|
16153
16228
|
onRequestExit: () => this.exitEditMode(shape)
|
|
@@ -16213,8 +16288,8 @@ var WeaveTextV2Node = class extends WeaveNode {
|
|
|
16213
16288
|
}
|
|
16214
16289
|
setupTransform(text) {
|
|
16215
16290
|
let actualAnchor = void 0;
|
|
16216
|
-
const isSide = () =>
|
|
16217
|
-
const isCorner = () =>
|
|
16291
|
+
const isSide = () => SIDE_ANCHOR_SET.has(actualAnchor ?? "");
|
|
16292
|
+
const isCorner = () => CORNER_ANCHOR_SET.has(actualAnchor ?? "");
|
|
16218
16293
|
const autoWidthLayout = () => [TEXT_LAYOUT.AUTO_HEIGHT, TEXT_LAYOUT.SMART].includes(text.getAttrs().layout);
|
|
16219
16294
|
text.on("transformstart", (e) => {
|
|
16220
16295
|
const ctrlOrMeta = e.evt.ctrlKey || e.evt.metaKey;
|
|
@@ -16311,6 +16386,7 @@ var WeaveTextV2Node = class extends WeaveNode {
|
|
|
16311
16386
|
serialize(instance) {
|
|
16312
16387
|
const attrs = instance.getAttrs();
|
|
16313
16388
|
const cleanedAttrs = { ...attrs };
|
|
16389
|
+
for (const key of Object.keys(cleanedAttrs)) if (typeof cleanedAttrs[key] === "function") delete cleanedAttrs[key];
|
|
16314
16390
|
delete cleanedAttrs.mutexLocked;
|
|
16315
16391
|
delete cleanedAttrs.mutexUserId;
|
|
16316
16392
|
delete cleanedAttrs.draggable;
|