@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/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.597.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());
|
|
@@ -14999,48 +15043,47 @@ var WeaveTextV2Shape = class extends Konva.Shape {
|
|
|
14999
15043
|
setViewport(range) {
|
|
15000
15044
|
this.viewport = range;
|
|
15001
15045
|
}
|
|
15002
|
-
|
|
15046
|
+
/**
|
|
15047
|
+
* Visible y-range in local coordinates, derived from the context being
|
|
15048
|
+
* painted (current transform + backing canvas size) instead of the stage.
|
|
15049
|
+
* The stage is not the paint target during export (off-screen canvases,
|
|
15050
|
+
* tiles, server-side), so using it culled visible lines. Returns null (paint
|
|
15051
|
+
* everything) when the transform cannot be read.
|
|
15052
|
+
*/
|
|
15053
|
+
visibleRange(ctx) {
|
|
15003
15054
|
if (this.viewport) return this.viewport;
|
|
15004
|
-
const
|
|
15005
|
-
|
|
15006
|
-
|
|
15007
|
-
const
|
|
15008
|
-
|
|
15009
|
-
const
|
|
15010
|
-
|
|
15011
|
-
|
|
15012
|
-
|
|
15013
|
-
|
|
15014
|
-
|
|
15015
|
-
|
|
15016
|
-
|
|
15017
|
-
|
|
15018
|
-
|
|
15019
|
-
|
|
15020
|
-
|
|
15021
|
-
|
|
15022
|
-
|
|
15023
|
-
|
|
15024
|
-
|
|
15025
|
-
})
|
|
15026
|
-
];
|
|
15055
|
+
const native = ctx._context;
|
|
15056
|
+
const m = native.getTransform?.() ?? native.currentTransform;
|
|
15057
|
+
if (!m) return null;
|
|
15058
|
+
const det = m.a * m.d - m.b * m.c;
|
|
15059
|
+
if (!det || !Number.isFinite(det)) return null;
|
|
15060
|
+
const canvas = ctx.getCanvas();
|
|
15061
|
+
const w = canvas.getWidth();
|
|
15062
|
+
const h = canvas.getHeight();
|
|
15063
|
+
if (!(w > 0) || !(h > 0)) return null;
|
|
15064
|
+
let y1 = Infinity;
|
|
15065
|
+
let y2 = -Infinity;
|
|
15066
|
+
for (const [px, py] of [
|
|
15067
|
+
[0, 0],
|
|
15068
|
+
[w, 0],
|
|
15069
|
+
[0, h],
|
|
15070
|
+
[w, h]
|
|
15071
|
+
]) {
|
|
15072
|
+
const y = (m.a * (py - m.f) - m.b * (px - m.e)) / det;
|
|
15073
|
+
if (y < y1) y1 = y;
|
|
15074
|
+
if (y > y2) y2 = y;
|
|
15075
|
+
}
|
|
15027
15076
|
return {
|
|
15028
|
-
y1
|
|
15029
|
-
y2
|
|
15077
|
+
y1,
|
|
15078
|
+
y2
|
|
15030
15079
|
};
|
|
15031
15080
|
}
|
|
15032
|
-
|
|
15081
|
+
_sceneFunc = (ctx, shape) => {
|
|
15033
15082
|
const self = shape;
|
|
15034
15083
|
const layout = self.ensureLayout();
|
|
15035
15084
|
if (layout.lines.length === 0) return;
|
|
15036
|
-
const fontSize = self.fontSize();
|
|
15037
15085
|
const padding = self.padding();
|
|
15038
15086
|
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
15087
|
let baseline = "middle";
|
|
15045
15088
|
let translateY = lineHeightPx / 2;
|
|
15046
15089
|
if (!Konva.legacyTextRendering) {
|
|
@@ -15051,62 +15094,63 @@ var WeaveTextV2Shape = class extends Konva.Shape {
|
|
|
15051
15094
|
ctx.setAttr("font", fontString(self.style()));
|
|
15052
15095
|
ctx.setAttr("textBaseline", baseline);
|
|
15053
15096
|
ctx.setAttr("textAlign", "left");
|
|
15054
|
-
|
|
15055
|
-
const
|
|
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;
|
|
15097
|
+
const alignY = self.verticalOffset(layout);
|
|
15098
|
+
const range = self.visibleRange(ctx);
|
|
15059
15099
|
ctx.translate(padding, alignY + padding);
|
|
15060
|
-
const
|
|
15061
|
-
const paintSelf = self;
|
|
15100
|
+
const top = alignY + padding;
|
|
15062
15101
|
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();
|
|
15102
|
+
const lineTop = top + n * lineHeightPx;
|
|
15103
|
+
if (range && (lineTop + lineHeightPx < range.y1 - lineHeightPx || lineTop > range.y2 + lineHeightPx)) continue;
|
|
15104
|
+
self.paintLine(ctx, layout.lines[n], translateY + n * lineHeightPx);
|
|
15107
15105
|
}
|
|
15108
15106
|
};
|
|
15109
|
-
|
|
15107
|
+
/** Vertical offset of the text block inside the box (verticalAlign). */
|
|
15108
|
+
verticalOffset(layout) {
|
|
15109
|
+
const used = layout.lines.length * layout.lineHeightPx + this.padding() * 2;
|
|
15110
|
+
const va = this.verticalAlign();
|
|
15111
|
+
if (va === "middle") return (this.getHeight() - used) / 2;
|
|
15112
|
+
if (va === "bottom") return this.getHeight() - used;
|
|
15113
|
+
return 0;
|
|
15114
|
+
}
|
|
15115
|
+
paintLine(ctx, line, y) {
|
|
15116
|
+
const decoration = this.textDecoration();
|
|
15117
|
+
const fontSize = this.fontSize();
|
|
15118
|
+
ctx.save();
|
|
15119
|
+
if (decoration.includes("underline")) this.strokeDecoration(ctx, line, y + Math.round(fontSize / 4));
|
|
15120
|
+
for (const seg of line.segments) this.paintSegment(ctx, seg.t, line.offsetX + seg.x, y);
|
|
15121
|
+
if (decoration.includes("line-through")) this.strokeDecoration(ctx, line, y - Math.round(fontSize / 4));
|
|
15122
|
+
ctx.restore();
|
|
15123
|
+
}
|
|
15124
|
+
strokeDecoration(ctx, line, y) {
|
|
15125
|
+
ctx.save();
|
|
15126
|
+
ctx.beginPath();
|
|
15127
|
+
ctx.moveTo(line.offsetX, y);
|
|
15128
|
+
ctx.lineTo(line.offsetX + Math.round(line.width), y);
|
|
15129
|
+
ctx.lineWidth = this.fontSize() / 15;
|
|
15130
|
+
ctx.strokeStyle = this.fill();
|
|
15131
|
+
ctx.stroke();
|
|
15132
|
+
ctx.restore();
|
|
15133
|
+
}
|
|
15134
|
+
paintSegment(ctx, text, x, y) {
|
|
15135
|
+
const spacing = this.letterSpacing();
|
|
15136
|
+
if (spacing === 0) {
|
|
15137
|
+
this.fillText(ctx, text, x, y);
|
|
15138
|
+
return;
|
|
15139
|
+
}
|
|
15140
|
+
let cx = x;
|
|
15141
|
+
for (const ch of Array.from(text)) {
|
|
15142
|
+
this.fillText(ctx, ch, cx, y);
|
|
15143
|
+
cx += this.measureSize(ch).width + spacing;
|
|
15144
|
+
}
|
|
15145
|
+
}
|
|
15146
|
+
fillText(ctx, text, x, y) {
|
|
15147
|
+
const self = this;
|
|
15148
|
+
self._partialText = text;
|
|
15149
|
+
self._partialTextX = x;
|
|
15150
|
+
self._partialTextY = y;
|
|
15151
|
+
ctx.fillStrokeShape(this);
|
|
15152
|
+
}
|
|
15153
|
+
_hitFunc = (ctx, shape) => {
|
|
15110
15154
|
ctx.beginPath();
|
|
15111
15155
|
const self = shape;
|
|
15112
15156
|
ctx.rect(0, 0, self.getWidth(), self.getHeight());
|
|
@@ -15214,7 +15258,7 @@ function lineIndexAt(layout, offset) {
|
|
|
15214
15258
|
if (l.start <= offset) fallback = i;
|
|
15215
15259
|
if (offset >= l.start && offset <= l.end) {
|
|
15216
15260
|
const next = lines[i + 1];
|
|
15217
|
-
if (offset === l.end && !l.lastInParagraph && next
|
|
15261
|
+
if (offset === l.end && !l.lastInParagraph && next?.start === offset) continue;
|
|
15218
15262
|
return i;
|
|
15219
15263
|
}
|
|
15220
15264
|
}
|
|
@@ -15263,10 +15307,7 @@ function offsetInLine(line, x, measure) {
|
|
|
15263
15307
|
function moveVertical(layout, offset, dir, desiredX, measure) {
|
|
15264
15308
|
const j = lineIndexAt(layout, offset) + dir;
|
|
15265
15309
|
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
|
-
}
|
|
15310
|
+
if (j >= layout.lines.length) return layout.lines.at(-1)?.end ?? 0;
|
|
15270
15311
|
return offsetInLine(layout.lines[j], desiredX, measure);
|
|
15271
15312
|
}
|
|
15272
15313
|
function lineHome(layout, offset) {
|
|
@@ -15496,9 +15537,10 @@ var TextEditSession = class {
|
|
|
15496
15537
|
capture: true
|
|
15497
15538
|
});
|
|
15498
15539
|
window.weaveTextEditing = {
|
|
15499
|
-
...window.weaveTextEditing
|
|
15540
|
+
...window.weaveTextEditing,
|
|
15500
15541
|
[this.id]: this.id
|
|
15501
15542
|
};
|
|
15543
|
+
if (this.host.selectAllOnStart) this.model.selectAll();
|
|
15502
15544
|
this.syncTextarea();
|
|
15503
15545
|
ta.focus();
|
|
15504
15546
|
this.positionTextarea();
|
|
@@ -15602,41 +15644,43 @@ var TextEditSession = class {
|
|
|
15602
15644
|
this.afterSelectionChange();
|
|
15603
15645
|
}
|
|
15604
15646
|
};
|
|
15605
|
-
|
|
15606
|
-
|
|
15647
|
+
/** Keys the session handles itself; everything else stays native. */
|
|
15648
|
+
handleSessionKey(e) {
|
|
15607
15649
|
const mod = e.ctrlKey || e.metaKey;
|
|
15608
15650
|
const key = e.key.toLowerCase();
|
|
15609
|
-
|
|
15610
|
-
|
|
15611
|
-
|
|
15612
|
-
|
|
15613
|
-
|
|
15614
|
-
if (
|
|
15615
|
-
|
|
15616
|
-
|
|
15617
|
-
|
|
15651
|
+
const isUndo = mod && key === "z" && !e.shiftKey;
|
|
15652
|
+
const isRedo = mod && (key === "y" || key === "z" && e.shiftKey);
|
|
15653
|
+
if (e.key === "Escape") this.host.onRequestExit("escape");
|
|
15654
|
+
else if (isUndo) this.undo();
|
|
15655
|
+
else if (isRedo) this.redo();
|
|
15656
|
+
else if (e.key === "Tab") return true;
|
|
15657
|
+
else return false;
|
|
15658
|
+
return true;
|
|
15659
|
+
}
|
|
15660
|
+
handleNavigationKey(e) {
|
|
15661
|
+
if (e.ctrlKey || e.metaKey) return false;
|
|
15662
|
+
if ((e.key === "ArrowUp" || e.key === "ArrowDown") && !e.altKey) {
|
|
15663
|
+
this.moveVertically(e.key === "ArrowUp" ? -1 : 1, e.shiftKey);
|
|
15664
|
+
return true;
|
|
15618
15665
|
}
|
|
15619
|
-
if (
|
|
15620
|
-
|
|
15621
|
-
this.
|
|
15622
|
-
|
|
15666
|
+
if (e.key === "Home" || e.key === "End") {
|
|
15667
|
+
const layout = this.target.getLayout();
|
|
15668
|
+
const to = e.key === "Home" ? lineHome(layout, this.model.focus) : lineEnd(layout, this.model.focus);
|
|
15669
|
+
this.model.moveTo(to, e.shiftKey);
|
|
15670
|
+
this.afterSelectionChange();
|
|
15671
|
+
return true;
|
|
15623
15672
|
}
|
|
15624
|
-
|
|
15673
|
+
return false;
|
|
15674
|
+
}
|
|
15675
|
+
onKeyDown = (e) => {
|
|
15676
|
+
e.stopPropagation();
|
|
15677
|
+
if (this.handleSessionKey(e)) {
|
|
15625
15678
|
e.preventDefault();
|
|
15626
15679
|
return;
|
|
15627
15680
|
}
|
|
15628
15681
|
if (this.composing) return;
|
|
15629
|
-
if ((e
|
|
15682
|
+
if (this.handleNavigationKey(e)) {
|
|
15630
15683
|
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
15684
|
return;
|
|
15641
15685
|
}
|
|
15642
15686
|
setTimeout(this.syncFromTextarea, 0);
|
|
@@ -15650,7 +15694,7 @@ var TextEditSession = class {
|
|
|
15650
15694
|
};
|
|
15651
15695
|
moveVertically(dir, extend) {
|
|
15652
15696
|
const layout = this.target.getLayout();
|
|
15653
|
-
|
|
15697
|
+
this.model.desiredX ??= caretRect(layout, this.model.focus, this.target.measure).x;
|
|
15654
15698
|
const to = moveVertical(layout, this.model.focus, dir, this.model.desiredX, this.target.measure);
|
|
15655
15699
|
this.model.moveTo(to, extend, true);
|
|
15656
15700
|
this.afterSelectionChange();
|
|
@@ -15668,11 +15712,17 @@ var TextEditSession = class {
|
|
|
15668
15712
|
while (s < max - p && oldText[oldText.length - 1 - s] === newText[newText.length - 1 - s]) s++;
|
|
15669
15713
|
const inserted = newText.slice(p, newText.length - s);
|
|
15670
15714
|
const inputType = e.inputType ?? "";
|
|
15671
|
-
const kind = this.
|
|
15715
|
+
const kind = this.editKindFor(inputType);
|
|
15672
15716
|
this.model.replaceRange(p, oldText.length - s, inserted, kind);
|
|
15673
15717
|
this.model.anchor = this.model.focus = Math.min(ta.selectionEnd, this.model.getText().length);
|
|
15674
15718
|
this.afterContentChange(inserted.length);
|
|
15675
15719
|
};
|
|
15720
|
+
editKindFor(inputType) {
|
|
15721
|
+
if (this.composing || inputType.includes("Composition")) return "ime";
|
|
15722
|
+
if (inputType.startsWith("delete")) return "delete";
|
|
15723
|
+
if (inputType === "insertFromPaste") return "paste";
|
|
15724
|
+
return "type";
|
|
15725
|
+
}
|
|
15676
15726
|
onPaste = (e) => {
|
|
15677
15727
|
e.stopPropagation();
|
|
15678
15728
|
e.preventDefault();
|
|
@@ -15819,6 +15869,17 @@ var TextEditSession = class {
|
|
|
15819
15869
|
const o = this.target.getContentOffset();
|
|
15820
15870
|
ctx.save();
|
|
15821
15871
|
ctx.transform(rel.m[0], rel.m[1], rel.m[2], rel.m[3], rel.m[4], rel.m[5]);
|
|
15872
|
+
if (this.host.outlineColor) {
|
|
15873
|
+
const scale = Math.hypot(abs.m[0], abs.m[1]) || 1;
|
|
15874
|
+
const lw = (this.host.outlineWidth ?? 1) / scale;
|
|
15875
|
+
const { width, height } = this.target.getSize();
|
|
15876
|
+
ctx.setAttr("strokeStyle", this.host.outlineColor);
|
|
15877
|
+
ctx.setAttr("lineWidth", lw);
|
|
15878
|
+
ctx.beginPath();
|
|
15879
|
+
const pad = (this.host.outlinePadding ?? 0) / scale;
|
|
15880
|
+
ctx.rect(-pad, -pad, width + pad * 2, height + pad * 2);
|
|
15881
|
+
ctx.stroke();
|
|
15882
|
+
}
|
|
15822
15883
|
ctx.translate(o.x, o.y);
|
|
15823
15884
|
const { start, end } = this.model.getSelection();
|
|
15824
15885
|
if (start !== end) {
|
|
@@ -15862,6 +15923,12 @@ const WEAVE_TEXT_V2_SIZE_WARNING_THRESHOLD = 2e5;
|
|
|
15862
15923
|
const WEAVE_TEXT_V2_SELECTION_COLOR = "rgba(66, 133, 244, 0.35)";
|
|
15863
15924
|
const WEAVE_TEXT_V2_DEFAULT_CONFIG = {
|
|
15864
15925
|
...WEAVE_TEXT_NODE_DEFAULT_CONFIG,
|
|
15926
|
+
edition: { outline: {
|
|
15927
|
+
enabled: true,
|
|
15928
|
+
color: "#0074ff",
|
|
15929
|
+
width: 1,
|
|
15930
|
+
padding: 0
|
|
15931
|
+
} },
|
|
15865
15932
|
sizeWarning: { threshold: WEAVE_TEXT_V2_SIZE_WARNING_THRESHOLD }
|
|
15866
15933
|
};
|
|
15867
15934
|
//#endregion
|
|
@@ -15873,6 +15940,8 @@ const CORNER_ANCHORS = [
|
|
|
15873
15940
|
"bottom-right"
|
|
15874
15941
|
];
|
|
15875
15942
|
const SIDE_ANCHORS = ["middle-right", "middle-left"];
|
|
15943
|
+
const CORNER_ANCHOR_SET = new Set(CORNER_ANCHORS);
|
|
15944
|
+
const SIDE_ANCHOR_SET = new Set(SIDE_ANCHORS);
|
|
15876
15945
|
/**
|
|
15877
15946
|
* Drop-in replacement for `WeaveTextNode`. Same `nodeType` (`'text'`), so
|
|
15878
15947
|
* existing documents load unchanged; register it INSTEAD of `WeaveTextNode`
|
|
@@ -16106,8 +16175,14 @@ var WeaveTextV2Node = class extends WeaveNode {
|
|
|
16106
16175
|
y: p.y * sy
|
|
16107
16176
|
};
|
|
16108
16177
|
},
|
|
16178
|
+
selectAllOnStart: !create,
|
|
16109
16179
|
caretColor: this.config.cursor.color,
|
|
16110
16180
|
selectionColor: WEAVE_TEXT_V2_SELECTION_COLOR,
|
|
16181
|
+
...this.config.edition.outline.enabled && {
|
|
16182
|
+
outlineColor: this.config.edition.outline.color,
|
|
16183
|
+
outlineWidth: this.config.edition.outline.width,
|
|
16184
|
+
outlinePadding: this.config.edition.outline.padding
|
|
16185
|
+
},
|
|
16111
16186
|
signal: this.instance.getEventsController().signal,
|
|
16112
16187
|
onChange: (blocks) => this.checkSize(shape, blocks),
|
|
16113
16188
|
onRequestExit: () => this.exitEditMode(shape)
|
|
@@ -16173,8 +16248,8 @@ var WeaveTextV2Node = class extends WeaveNode {
|
|
|
16173
16248
|
}
|
|
16174
16249
|
setupTransform(text) {
|
|
16175
16250
|
let actualAnchor = void 0;
|
|
16176
|
-
const isSide = () =>
|
|
16177
|
-
const isCorner = () =>
|
|
16251
|
+
const isSide = () => SIDE_ANCHOR_SET.has(actualAnchor ?? "");
|
|
16252
|
+
const isCorner = () => CORNER_ANCHOR_SET.has(actualAnchor ?? "");
|
|
16178
16253
|
const autoWidthLayout = () => [TEXT_LAYOUT.AUTO_HEIGHT, TEXT_LAYOUT.SMART].includes(text.getAttrs().layout);
|
|
16179
16254
|
text.on("transformstart", (e) => {
|
|
16180
16255
|
const ctrlOrMeta = e.evt.ctrlKey || e.evt.metaKey;
|
|
@@ -16271,6 +16346,7 @@ var WeaveTextV2Node = class extends WeaveNode {
|
|
|
16271
16346
|
serialize(instance) {
|
|
16272
16347
|
const attrs = instance.getAttrs();
|
|
16273
16348
|
const cleanedAttrs = { ...attrs };
|
|
16349
|
+
for (const key of Object.keys(cleanedAttrs)) if (typeof cleanedAttrs[key] === "function") delete cleanedAttrs[key];
|
|
16274
16350
|
delete cleanedAttrs.mutexLocked;
|
|
16275
16351
|
delete cleanedAttrs.mutexUserId;
|
|
16276
16352
|
delete cleanedAttrs.draggable;
|