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