@embedpdf/core-annotation 3.0.0-next.12 → 3.0.0-next.13
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/index.cjs +365 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +102 -2
- package/dist/index.d.ts +102 -2
- package/dist/index.js +354 -39
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -206,6 +206,18 @@ const TEXT_PROPS = [
|
|
|
206
206
|
key: "fontColor",
|
|
207
207
|
label: "Text color"
|
|
208
208
|
},
|
|
209
|
+
{
|
|
210
|
+
key: "bold",
|
|
211
|
+
label: "Bold"
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
key: "italic",
|
|
215
|
+
label: "Italic"
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
key: "underline",
|
|
219
|
+
label: "Underline"
|
|
220
|
+
},
|
|
209
221
|
{
|
|
210
222
|
key: "textAlign",
|
|
211
223
|
label: "Align"
|
|
@@ -2686,41 +2698,60 @@ function geomDragHandle(g, handle, to) {
|
|
|
2686
2698
|
}
|
|
2687
2699
|
return g;
|
|
2688
2700
|
}
|
|
2701
|
+
/**
|
|
2702
|
+
* The text PLATE inset of a free-text box: twice the border width. The plate
|
|
2703
|
+
* — where text lays out, clips and scrolls — is the box deflated by this on
|
|
2704
|
+
* every side: the ink band and an equal breathing band, so the text never
|
|
2705
|
+
* touches the stroke. Acrobat's rule, measured 1–12 pt on plain boxes and
|
|
2706
|
+
* 1–7 pt on callouts (plan `2026-09-15-free-text-plate-inset.md`); the
|
|
2707
|
+
* engine's `FreeTextPlate` is the same formula, so the live editor sits
|
|
2708
|
+
* exactly where the baked text lands. Acrobat's thinnest border is 1 pt; a
|
|
2709
|
+
* width of 0 is ours alone and gives no inset (the plate is the box).
|
|
2710
|
+
*/
|
|
2711
|
+
function textPlateInset(strokeWidth) {
|
|
2712
|
+
return 2 * Math.max(0, strokeWidth);
|
|
2713
|
+
}
|
|
2714
|
+
/** A callout's leader (open polyline, its connection point extended under
|
|
2715
|
+
* the box border by half the stroke — the AP generator's `adjusted_conn` —
|
|
2716
|
+
* so the leader meets the border ink without an angular gap) + the arrow at
|
|
2717
|
+
* its tip. */
|
|
2718
|
+
function calloutLeaderNodes(g, callout, strokeWidth) {
|
|
2719
|
+
const pts = [...calloutLinePoints(g)];
|
|
2720
|
+
if (strokeWidth > 0 && pts.length >= 2) {
|
|
2721
|
+
const last = pts[pts.length - 1];
|
|
2722
|
+
const prev = pts[pts.length - 2];
|
|
2723
|
+
const dx = last.x - prev.x;
|
|
2724
|
+
const dy = last.y - prev.y;
|
|
2725
|
+
const len = Math.hypot(dx, dy);
|
|
2726
|
+
if (len > 0) pts[pts.length - 1] = {
|
|
2727
|
+
x: last.x + dx / len * (strokeWidth / 2),
|
|
2728
|
+
y: last.y + dy / len * (strokeWidth / 2)
|
|
2729
|
+
};
|
|
2730
|
+
}
|
|
2731
|
+
const nodes = [{
|
|
2732
|
+
kind: "poly",
|
|
2733
|
+
points: pts,
|
|
2734
|
+
closed: false
|
|
2735
|
+
}];
|
|
2736
|
+
const seg = calloutEndingSeg(pts, callout.ending);
|
|
2737
|
+
if (seg) nodes.push(...endingNodes(seg.tip, seg.angle, seg.ending, strokeWidth));
|
|
2738
|
+
return nodes;
|
|
2739
|
+
}
|
|
2689
2740
|
function geomScene(g, strokeWidth = 0, border) {
|
|
2690
2741
|
if (g.t === "text") {
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
const dy = last.y - prev.y;
|
|
2698
|
-
const len = Math.hypot(dx, dy);
|
|
2699
|
-
if (len > 0) pts[pts.length - 1] = {
|
|
2700
|
-
x: last.x + dx / len * (strokeWidth / 2),
|
|
2701
|
-
y: last.y + dy / len * (strokeWidth / 2)
|
|
2702
|
-
};
|
|
2703
|
-
}
|
|
2704
|
-
const nodes = [{
|
|
2742
|
+
const nodes = [];
|
|
2743
|
+
if (g.callout) nodes.push(...calloutLeaderNodes(g, g.callout, strokeWidth));
|
|
2744
|
+
const r = insetRect(g.rect, strokeWidth / 2);
|
|
2745
|
+
const rot = g.rot ?? 0;
|
|
2746
|
+
const c = rectCenter(g.rect);
|
|
2747
|
+
nodes.push(rot ? {
|
|
2705
2748
|
kind: "poly",
|
|
2706
|
-
points:
|
|
2707
|
-
closed:
|
|
2708
|
-
}
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
const r = insetRect(g.rect, strokeWidth / 2);
|
|
2713
|
-
const rot = g.rot ?? 0;
|
|
2714
|
-
const c = rectCenter(g.rect);
|
|
2715
|
-
nodes.push(rot ? {
|
|
2716
|
-
kind: "poly",
|
|
2717
|
-
points: rectCornerPoints(r).map((p) => rotatePoint(p, c, rot)),
|
|
2718
|
-
closed: true
|
|
2719
|
-
} : {
|
|
2720
|
-
kind: "rect",
|
|
2721
|
-
rect: r
|
|
2722
|
-
});
|
|
2723
|
-
}
|
|
2749
|
+
points: rectCornerPoints(r).map((p) => rotatePoint(p, c, rot)),
|
|
2750
|
+
closed: true
|
|
2751
|
+
} : {
|
|
2752
|
+
kind: "rect",
|
|
2753
|
+
rect: r
|
|
2754
|
+
});
|
|
2724
2755
|
return nodes;
|
|
2725
2756
|
}
|
|
2726
2757
|
if (g.t === "caret") {
|
|
@@ -3226,7 +3257,10 @@ const textStyleFromProps = (p) => ({
|
|
|
3226
3257
|
fontFamily: p.fontFamily,
|
|
3227
3258
|
fontSize: p.fontSize,
|
|
3228
3259
|
fontColor: p.fontColor,
|
|
3229
|
-
textAlign: p.textAlign
|
|
3260
|
+
textAlign: p.textAlign,
|
|
3261
|
+
...p.bold !== void 0 ? { bold: p.bold } : {},
|
|
3262
|
+
...p.italic !== void 0 ? { italic: p.italic } : {},
|
|
3263
|
+
...p.underline !== void 0 ? { underline: p.underline } : {}
|
|
3230
3264
|
});
|
|
3231
3265
|
/** Does this kind's prop table declare `link` (attachable link)? The link
|
|
3232
3266
|
* KIND itself also declares it, but stores its own `/A` instead. */
|
|
@@ -3252,6 +3286,9 @@ function readProp(a, key) {
|
|
|
3252
3286
|
case "fontSize": return a.text?.fontSize;
|
|
3253
3287
|
case "fontColor": return a.text?.fontColor;
|
|
3254
3288
|
case "textAlign": return a.text?.textAlign;
|
|
3289
|
+
case "bold": return a.text ? a.text.bold ?? false : void 0;
|
|
3290
|
+
case "italic": return a.text ? a.text.italic ?? false : void 0;
|
|
3291
|
+
case "underline": return a.text ? a.text.underline ?? false : void 0;
|
|
3255
3292
|
case "icon": return a.icon;
|
|
3256
3293
|
case "link": return a.link;
|
|
3257
3294
|
}
|
|
@@ -3339,6 +3376,17 @@ function applyProps(a, patch) {
|
|
|
3339
3376
|
text.textAlign = patch.textAlign;
|
|
3340
3377
|
textChanged = true;
|
|
3341
3378
|
}
|
|
3379
|
+
for (const key of [
|
|
3380
|
+
"bold",
|
|
3381
|
+
"italic",
|
|
3382
|
+
"underline"
|
|
3383
|
+
]) {
|
|
3384
|
+
const value = patch[key];
|
|
3385
|
+
if (value !== void 0 && takes.has(key) && (text[key] ?? false) !== value) {
|
|
3386
|
+
text[key] = value;
|
|
3387
|
+
textChanged = true;
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3342
3390
|
if (textChanged) next = {
|
|
3343
3391
|
...next,
|
|
3344
3392
|
text
|
|
@@ -3468,6 +3516,236 @@ function clickCreateGeom(subtype, placement, def) {
|
|
|
3468
3516
|
return null;
|
|
3469
3517
|
}
|
|
3470
3518
|
//#endregion
|
|
3519
|
+
//#region src/richtext.ts
|
|
3520
|
+
/** Length of the plain projection. */
|
|
3521
|
+
function richTextLength(doc) {
|
|
3522
|
+
let n = 0;
|
|
3523
|
+
doc.paragraphs.forEach((p, i) => {
|
|
3524
|
+
if (i > 0) n += 1;
|
|
3525
|
+
for (const r of p.runs) n += r.text.length;
|
|
3526
|
+
});
|
|
3527
|
+
return n;
|
|
3528
|
+
}
|
|
3529
|
+
const DELTA_KEYS = [
|
|
3530
|
+
"family",
|
|
3531
|
+
"weight",
|
|
3532
|
+
"italic",
|
|
3533
|
+
"size",
|
|
3534
|
+
"color",
|
|
3535
|
+
"decoration",
|
|
3536
|
+
"script",
|
|
3537
|
+
"letterSpacing",
|
|
3538
|
+
"horizontalScale",
|
|
3539
|
+
"unknown"
|
|
3540
|
+
];
|
|
3541
|
+
function sameDecoration(a, b) {
|
|
3542
|
+
if (a === b) return true;
|
|
3543
|
+
if (!a || !b || a.length !== b.length) return false;
|
|
3544
|
+
const sorted = (x) => [...x].sort();
|
|
3545
|
+
const sa = sorted(a);
|
|
3546
|
+
const sb = sorted(b);
|
|
3547
|
+
return sa.every((v, i) => v === sb[i]);
|
|
3548
|
+
}
|
|
3549
|
+
/** Two deltas override the same properties with the same values. */
|
|
3550
|
+
function sameStyleDelta(a, b) {
|
|
3551
|
+
const da = a ?? {};
|
|
3552
|
+
const db = b ?? {};
|
|
3553
|
+
for (const key of DELTA_KEYS) if (key === "decoration") {
|
|
3554
|
+
if (!sameDecoration(da.decoration, db.decoration)) return false;
|
|
3555
|
+
} else if (da[key] !== db[key]) return false;
|
|
3556
|
+
return true;
|
|
3557
|
+
}
|
|
3558
|
+
/** A delta with every `undefined` member removed; `undefined` when empty. */
|
|
3559
|
+
function cleanDelta(delta) {
|
|
3560
|
+
if (!delta) return void 0;
|
|
3561
|
+
const out = {};
|
|
3562
|
+
let any = false;
|
|
3563
|
+
for (const key of DELTA_KEYS) {
|
|
3564
|
+
const value = delta[key];
|
|
3565
|
+
if (value !== void 0) {
|
|
3566
|
+
out[key] = value;
|
|
3567
|
+
any = true;
|
|
3568
|
+
}
|
|
3569
|
+
}
|
|
3570
|
+
return any ? out : void 0;
|
|
3571
|
+
}
|
|
3572
|
+
/**
|
|
3573
|
+
* Merge adjacent runs whose deltas agree, drop empty runs, strip empty
|
|
3574
|
+
* deltas. A paragraph with no text keeps a single empty run so the editor
|
|
3575
|
+
* has somewhere to put the caret.
|
|
3576
|
+
*/
|
|
3577
|
+
function normalizeRuns(doc) {
|
|
3578
|
+
const paragraphs = doc.paragraphs.map((p) => {
|
|
3579
|
+
const runs = [];
|
|
3580
|
+
for (const run of p.runs) {
|
|
3581
|
+
if (run.text.length === 0) continue;
|
|
3582
|
+
const style = cleanDelta(run.style);
|
|
3583
|
+
const last = runs[runs.length - 1];
|
|
3584
|
+
if (last && sameStyleDelta(last.style, style)) runs[runs.length - 1] = {
|
|
3585
|
+
...last,
|
|
3586
|
+
text: last.text + run.text
|
|
3587
|
+
};
|
|
3588
|
+
else runs.push(style ? {
|
|
3589
|
+
text: run.text,
|
|
3590
|
+
style
|
|
3591
|
+
} : { text: run.text });
|
|
3592
|
+
}
|
|
3593
|
+
if (runs.length === 0) runs.push({ text: "" });
|
|
3594
|
+
return {
|
|
3595
|
+
...p,
|
|
3596
|
+
runs
|
|
3597
|
+
};
|
|
3598
|
+
});
|
|
3599
|
+
return {
|
|
3600
|
+
...doc,
|
|
3601
|
+
paragraphs
|
|
3602
|
+
};
|
|
3603
|
+
}
|
|
3604
|
+
/** Where a flat offset falls: paragraph index and offset within it (the
|
|
3605
|
+
* separator between paragraphs belongs to the end of the earlier one). */
|
|
3606
|
+
function locateOffset(doc, offset) {
|
|
3607
|
+
let pos = 0;
|
|
3608
|
+
for (let i = 0; i < doc.paragraphs.length; i++) {
|
|
3609
|
+
const length = doc.paragraphs[i].runs.reduce((n, r) => n + r.text.length, 0);
|
|
3610
|
+
if (offset <= pos + length || i === doc.paragraphs.length - 1) return {
|
|
3611
|
+
paragraph: i,
|
|
3612
|
+
offset: Math.max(0, Math.min(length, offset - pos))
|
|
3613
|
+
};
|
|
3614
|
+
pos += length + 1;
|
|
3615
|
+
}
|
|
3616
|
+
return {
|
|
3617
|
+
paragraph: 0,
|
|
3618
|
+
offset: 0
|
|
3619
|
+
};
|
|
3620
|
+
}
|
|
3621
|
+
/** The paragraph with a run boundary guaranteed at a local offset. */
|
|
3622
|
+
function splitRunsAt(paragraph, offset) {
|
|
3623
|
+
const runs = [];
|
|
3624
|
+
let pos = 0;
|
|
3625
|
+
for (const run of paragraph.runs) {
|
|
3626
|
+
const end = pos + run.text.length;
|
|
3627
|
+
if (offset > pos && offset < end) {
|
|
3628
|
+
const cut = offset - pos;
|
|
3629
|
+
runs.push({
|
|
3630
|
+
...run,
|
|
3631
|
+
text: run.text.slice(0, cut)
|
|
3632
|
+
});
|
|
3633
|
+
runs.push({
|
|
3634
|
+
...run,
|
|
3635
|
+
text: run.text.slice(cut)
|
|
3636
|
+
});
|
|
3637
|
+
} else runs.push(run);
|
|
3638
|
+
pos = end;
|
|
3639
|
+
}
|
|
3640
|
+
return {
|
|
3641
|
+
...paragraph,
|
|
3642
|
+
runs
|
|
3643
|
+
};
|
|
3644
|
+
}
|
|
3645
|
+
/**
|
|
3646
|
+
* Apply a style delta to every character of a range: the runs it touches are
|
|
3647
|
+
* split at its boundaries, the covered pieces take the delta on top of what
|
|
3648
|
+
* they already override (`clear` names properties to stop overriding, so
|
|
3649
|
+
* they follow the body again), and the result is normalised. An empty range
|
|
3650
|
+
* is a no-op.
|
|
3651
|
+
*/
|
|
3652
|
+
function applyStyleToRange(doc, range, delta, clear = []) {
|
|
3653
|
+
const start = Math.max(0, Math.min(range.start, range.end));
|
|
3654
|
+
const end = Math.max(range.start, range.end);
|
|
3655
|
+
if (end <= start) return doc;
|
|
3656
|
+
const from = locateOffset(doc, start);
|
|
3657
|
+
const to = locateOffset(doc, end);
|
|
3658
|
+
const paragraphs = doc.paragraphs.map((paragraph, index) => {
|
|
3659
|
+
if (index < from.paragraph || index > to.paragraph) return paragraph;
|
|
3660
|
+
const localStart = index === from.paragraph ? from.offset : 0;
|
|
3661
|
+
const localEnd = index === to.paragraph ? to.offset : paragraph.runs.reduce((n, r) => n + r.text.length, 0);
|
|
3662
|
+
if (localEnd <= localStart) return paragraph;
|
|
3663
|
+
const split = splitRunsAt(splitRunsAt(paragraph, localStart), localEnd);
|
|
3664
|
+
let pos = 0;
|
|
3665
|
+
const runs = split.runs.map((run) => {
|
|
3666
|
+
const runStart = pos;
|
|
3667
|
+
pos += run.text.length;
|
|
3668
|
+
if (runStart < localStart || runStart >= localEnd || run.text.length === 0) return run;
|
|
3669
|
+
const style = {
|
|
3670
|
+
...run.style ?? {},
|
|
3671
|
+
...delta
|
|
3672
|
+
};
|
|
3673
|
+
for (const key of clear) delete style[key];
|
|
3674
|
+
return {
|
|
3675
|
+
...run,
|
|
3676
|
+
style
|
|
3677
|
+
};
|
|
3678
|
+
});
|
|
3679
|
+
return {
|
|
3680
|
+
...split,
|
|
3681
|
+
runs
|
|
3682
|
+
};
|
|
3683
|
+
});
|
|
3684
|
+
return normalizeRuns({
|
|
3685
|
+
...doc,
|
|
3686
|
+
paragraphs
|
|
3687
|
+
});
|
|
3688
|
+
}
|
|
3689
|
+
/**
|
|
3690
|
+
* The delta in force at a caret: the run the offset falls in, or, at a run
|
|
3691
|
+
* boundary, the run before it (what typing there would inherit). Undefined
|
|
3692
|
+
* for an empty document.
|
|
3693
|
+
*/
|
|
3694
|
+
function styleAt(doc, offset) {
|
|
3695
|
+
const at = locateOffset(doc, offset);
|
|
3696
|
+
const paragraph = doc.paragraphs[at.paragraph];
|
|
3697
|
+
if (!paragraph) return void 0;
|
|
3698
|
+
let pos = 0;
|
|
3699
|
+
let previous;
|
|
3700
|
+
for (const run of paragraph.runs) {
|
|
3701
|
+
const end = pos + run.text.length;
|
|
3702
|
+
if (at.offset > pos && at.offset <= end) return run.style ?? {};
|
|
3703
|
+
if (at.offset === pos && pos === 0) return run.style ?? {};
|
|
3704
|
+
previous = run;
|
|
3705
|
+
pos = end;
|
|
3706
|
+
}
|
|
3707
|
+
return previous?.style ?? {};
|
|
3708
|
+
}
|
|
3709
|
+
/** Every run overlapping the range satisfies `predicate` (an empty range
|
|
3710
|
+
* tests the caret's style). */
|
|
3711
|
+
function rangeHasStyle(doc, range, predicate) {
|
|
3712
|
+
const start = Math.min(range.start, range.end);
|
|
3713
|
+
const end = Math.max(range.start, range.end);
|
|
3714
|
+
if (end <= start) return predicate(styleAt(doc, start) ?? {});
|
|
3715
|
+
const from = locateOffset(doc, start);
|
|
3716
|
+
const to = locateOffset(doc, end);
|
|
3717
|
+
let any = false;
|
|
3718
|
+
for (let index = from.paragraph; index <= to.paragraph; index++) {
|
|
3719
|
+
const paragraph = doc.paragraphs[index];
|
|
3720
|
+
const localStart = index === from.paragraph ? from.offset : 0;
|
|
3721
|
+
const localEnd = index === to.paragraph ? to.offset : paragraph.runs.reduce((n, r) => n + r.text.length, 0);
|
|
3722
|
+
let pos = 0;
|
|
3723
|
+
for (const run of paragraph.runs) {
|
|
3724
|
+
const runEnd = pos + run.text.length;
|
|
3725
|
+
if (runEnd > localStart && pos < localEnd && run.text.length > 0) {
|
|
3726
|
+
any = true;
|
|
3727
|
+
if (!predicate(run.style ?? {})) return false;
|
|
3728
|
+
}
|
|
3729
|
+
pos = runEnd;
|
|
3730
|
+
}
|
|
3731
|
+
}
|
|
3732
|
+
return any;
|
|
3733
|
+
}
|
|
3734
|
+
/** Plain paragraphs from text: one per line break, one unstyled run each. */
|
|
3735
|
+
function paragraphsFromPlainText(text) {
|
|
3736
|
+
return text.split(/\r\n|\r|\n/).map((line) => ({ runs: [{ text: line }] }));
|
|
3737
|
+
}
|
|
3738
|
+
/** The plain projection: paragraphs joined by `\r`, runs concatenated. */
|
|
3739
|
+
function plainTextOf(doc) {
|
|
3740
|
+
return doc.paragraphs.map((p) => p.runs.map((r) => r.text).join("")).join("\r");
|
|
3741
|
+
}
|
|
3742
|
+
/** True when nothing in the document overrides the body: no run delta, no
|
|
3743
|
+
* paragraph property. Such a document commits as plain `contents`. */
|
|
3744
|
+
function isPlainRichText(doc) {
|
|
3745
|
+
if (doc.body && Object.keys(doc.body).length > 0) return false;
|
|
3746
|
+
return doc.paragraphs.every((p) => p.align === void 0 && p.dir === void 0 && p.lineHeight === void 0 && p.margins === void 0 && p.textIndent === void 0 && p.unknown === void 0 && p.runs.every((r) => cleanDelta(r.style) === void 0));
|
|
3747
|
+
}
|
|
3748
|
+
//#endregion
|
|
3471
3749
|
//#region src/snap.ts
|
|
3472
3750
|
/**
|
|
3473
3751
|
* Pure alignment snapping for the move gesture. Compares the moving selection's
|
|
@@ -3901,6 +4179,7 @@ function update(m, msg) {
|
|
|
3901
4179
|
draft: null
|
|
3902
4180
|
}, []] : [m, []];
|
|
3903
4181
|
case "setText": return setText(m, msg.id, msg.text);
|
|
4182
|
+
case "setRichText": return setRichText(m, msg.id, msg.doc);
|
|
3904
4183
|
case "endTextEdit": return m.editing ? [{
|
|
3905
4184
|
...m,
|
|
3906
4185
|
editing: null
|
|
@@ -3914,12 +4193,49 @@ function update(m, msg) {
|
|
|
3914
4193
|
function setText(m, id, text) {
|
|
3915
4194
|
const a = m.byId[id];
|
|
3916
4195
|
if (!a) return [m, []];
|
|
4196
|
+
const data = a.data && a.data.subtype === "free-text" ? {
|
|
4197
|
+
...a.data,
|
|
4198
|
+
contents: text,
|
|
4199
|
+
richText: {
|
|
4200
|
+
...a.data.richText,
|
|
4201
|
+
paragraphs: paragraphsFromPlainText(text)
|
|
4202
|
+
}
|
|
4203
|
+
} : a.data ? {
|
|
4204
|
+
...a.data,
|
|
4205
|
+
contents: text
|
|
4206
|
+
} : a.data;
|
|
4207
|
+
const next = toVector({
|
|
4208
|
+
...a,
|
|
4209
|
+
data
|
|
4210
|
+
});
|
|
4211
|
+
return [{
|
|
4212
|
+
...m,
|
|
4213
|
+
byId: {
|
|
4214
|
+
...m.byId,
|
|
4215
|
+
[id]: next
|
|
4216
|
+
}
|
|
4217
|
+
}, []];
|
|
4218
|
+
}
|
|
4219
|
+
/** Apply the editor's rich document optimistically. The DTO's body is kept
|
|
4220
|
+
* (a partial input body layers on it); `contents` is the projection. */
|
|
4221
|
+
function setRichText(m, id, doc) {
|
|
4222
|
+
const a = m.byId[id];
|
|
4223
|
+
if (!a || !a.data || a.data.subtype !== "free-text") return [m, []];
|
|
4224
|
+
const normalized = normalizeRuns(doc);
|
|
4225
|
+
const richText = {
|
|
4226
|
+
body: {
|
|
4227
|
+
...a.data.richText.body,
|
|
4228
|
+
...normalized.body ?? {}
|
|
4229
|
+
},
|
|
4230
|
+
paragraphs: normalized.paragraphs
|
|
4231
|
+
};
|
|
3917
4232
|
const next = toVector({
|
|
3918
4233
|
...a,
|
|
3919
|
-
data:
|
|
4234
|
+
data: {
|
|
3920
4235
|
...a.data,
|
|
3921
|
-
|
|
3922
|
-
|
|
4236
|
+
richText,
|
|
4237
|
+
contents: plainTextOf(richText)
|
|
4238
|
+
}
|
|
3923
4239
|
});
|
|
3924
4240
|
return [{
|
|
3925
4241
|
...m,
|
|
@@ -5521,7 +5837,7 @@ function effAp(m, id, view) {
|
|
|
5521
5837
|
function effSource(m, id) {
|
|
5522
5838
|
const a = m.byId[id];
|
|
5523
5839
|
if (capsFor(a.subtype).opaqueBody) return a.source;
|
|
5524
|
-
if (m.editing === id && a.geom.t === "text"
|
|
5840
|
+
if (m.editing === id && a.geom.t === "text") return "vector";
|
|
5525
5841
|
const d = m.draft;
|
|
5526
5842
|
if (d?.g === "handle" && d.id === id) return "vector";
|
|
5527
5843
|
if ((d?.g === "rotate" || d?.g === "group") && d.ids.includes(id)) return "vector";
|
|
@@ -5537,7 +5853,6 @@ function pageItems(m, pon, view) {
|
|
|
5537
5853
|
const items = [];
|
|
5538
5854
|
for (const id of paintOrder(m, pon)) {
|
|
5539
5855
|
const a = m.byId[id];
|
|
5540
|
-
if (a.geom.t === "text" && !a.geom.callout && textIsLive(m, id)) continue;
|
|
5541
5856
|
const geom = effGeom(m, id, view);
|
|
5542
5857
|
const style = effStyle(a, view);
|
|
5543
5858
|
const ap = effAp(m, id, view);
|
|
@@ -5913,6 +6228,6 @@ function creationDraftAnchor(m) {
|
|
|
5913
6228
|
};
|
|
5914
6229
|
}
|
|
5915
6230
|
//#endregion
|
|
5916
|
-
export { DEFAULT_CHROME_GEOM, DRAWN_FLAGS, FLAG_KEYS, KINDS, MIN_DRAG, MITER_LIMIT, NO_ANNOTATION_FLAGS, RECT_HANDLES, ROTATE_KNOB_OFFSET, anchorModeOf, anchorOf, anchoredBox, anchoredGeom, anchoredStrokeWidth, annotContentsEditable, annotDeletable, annotInteractive, annotTransformable, applyProps, calloutConnection, calloutLinePoints, canMove, capsFor, caretGeomFromAnchor, caretRectFromAnchor, caretRectFromTextEnd, centroidOf, chrome, clampRectToBox, clickCreateGeom, cloudyBorderExtent, cloudyPath, computeMoveSnap, contentToPdfPoint, contentToPdfRect, creationDraftAnchor, cursorAt, defaultsFor, expandGroups, fitStampBox, flagsEqual, geomBounds, geomDragHandle, geomHandles, geomHit, geomPdfBounds, geomResetRotation, geomRotateAbout, geomRotation, geomScaleAbout, geomScene, geomTranslate, geomVisualBounds, groupCaps, groupKeyOf, groupMembers, groupResizeAnchor, groupResizeBox, groupResizeFactors, hitTest, initialModel, initialStyle, initialTextStyle, interactive, isAttachedLink, isConversationOnly, isRotatableGeom, isSelectable, isSubstrateOnly, linkChildrenOf, linkOf, mergeFlags, normalizeDeg, obbFromGeom, pageItems, pdfToContentPoint, pdfToContentRect, placeRotateKnob, pointInQuad, propsFor, quadIntersectsRect, readProp, rectFromPoints, resolveClickPlacement, rotateDraftDelta, rotateKnob, rotatedAabb, rotatedHandleCursor, scene, selectedItems, selectionAnchor, selectionBounds, selectionBoundsOnPage, selectionCenter, selectionKnob, selectionQuad, shapeRectFor, sharedProps, straightenInkStroke, styleFromProps, textBoxes, textStyleFromProps, transposedAboutCenter, unanchoredGeom, unionRect, update, uprightAnchoredRect, uprightRotation, viewable };
|
|
6231
|
+
export { DEFAULT_CHROME_GEOM, DRAWN_FLAGS, FLAG_KEYS, KINDS, MIN_DRAG, MITER_LIMIT, NO_ANNOTATION_FLAGS, RECT_HANDLES, ROTATE_KNOB_OFFSET, anchorModeOf, anchorOf, anchoredBox, anchoredGeom, anchoredStrokeWidth, annotContentsEditable, annotDeletable, annotInteractive, annotTransformable, applyProps, applyStyleToRange, calloutConnection, calloutLinePoints, canMove, capsFor, caretGeomFromAnchor, caretRectFromAnchor, caretRectFromTextEnd, centroidOf, chrome, clampRectToBox, clickCreateGeom, cloudyBorderExtent, cloudyPath, computeMoveSnap, contentToPdfPoint, contentToPdfRect, creationDraftAnchor, cursorAt, defaultsFor, expandGroups, fitStampBox, flagsEqual, geomBounds, geomDragHandle, geomHandles, geomHit, geomPdfBounds, geomResetRotation, geomRotateAbout, geomRotation, geomScaleAbout, geomScene, geomTranslate, geomVisualBounds, groupCaps, groupKeyOf, groupMembers, groupResizeAnchor, groupResizeBox, groupResizeFactors, hitTest, initialModel, initialStyle, initialTextStyle, interactive, isAttachedLink, isConversationOnly, isPlainRichText, isRotatableGeom, isSelectable, isSubstrateOnly, linkChildrenOf, linkOf, locateOffset, mergeFlags, normalizeDeg, normalizeRuns, obbFromGeom, pageItems, paragraphsFromPlainText, pdfToContentPoint, pdfToContentRect, placeRotateKnob, plainTextOf, pointInQuad, propsFor, quadIntersectsRect, rangeHasStyle, readProp, rectFromPoints, resolveClickPlacement, richTextLength, rotateDraftDelta, rotateKnob, rotatedAabb, rotatedHandleCursor, sameStyleDelta, scene, selectedItems, selectionAnchor, selectionBounds, selectionBoundsOnPage, selectionCenter, selectionKnob, selectionQuad, shapeRectFor, sharedProps, splitRunsAt, straightenInkStroke, styleAt, styleFromProps, textBoxes, textPlateInset, textStyleFromProps, transposedAboutCenter, unanchoredGeom, unionRect, update, uprightAnchoredRect, uprightRotation, viewable };
|
|
5917
6232
|
|
|
5918
6233
|
//# sourceMappingURL=index.js.map
|