@embedpdf/core-annotation 3.0.0-next.11 → 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.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
- if (!g.callout) return [];
2692
- const pts = [...calloutLinePoints(g)];
2693
- if (strokeWidth > 0 && pts.length >= 2) {
2694
- const last = pts[pts.length - 1];
2695
- const prev = pts[pts.length - 2];
2696
- const dx = last.x - prev.x;
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: pts,
2707
- closed: false
2708
- }];
2709
- const seg = calloutEndingSeg(pts, g.callout.ending);
2710
- if (seg) nodes.push(...endingNodes(seg.tip, seg.angle, seg.ending, strokeWidth));
2711
- if (strokeWidth > 0) {
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: a.data ? {
4234
+ data: {
3920
4235
  ...a.data,
3921
- contents: text
3922
- } : a.data
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" && a.geom.callout) return "vector";
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