@embedpdf/plugin-annotation 3.0.0-next.13 → 3.0.0-next.15

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.
Files changed (61) hide show
  1. package/README.md +129 -0
  2. package/dist/authoring.cjs +12 -2
  3. package/dist/authoring.d.cts +2 -2
  4. package/dist/authoring.d.ts +2 -2
  5. package/dist/authoring.js +2 -3
  6. package/dist/contract/host.cjs +18 -2
  7. package/dist/contract/host.d.cts +3 -2
  8. package/dist/contract/host.d.ts +3 -2
  9. package/dist/contract/host.js +3 -2
  10. package/dist/contract-BK4LHe9v.d.cts +1127 -0
  11. package/dist/contract-BOo9iZKo.d.ts +1127 -0
  12. package/dist/contract-CPzpRG3h.cjs +692 -0
  13. package/dist/contract-CPzpRG3h.cjs.map +1 -0
  14. package/dist/contract-b2e_LZvu.js +651 -0
  15. package/dist/contract-b2e_LZvu.js.map +1 -0
  16. package/dist/contract.cjs +11 -10
  17. package/dist/contract.d.cts +2 -3
  18. package/dist/contract.d.ts +2 -3
  19. package/dist/contract.js +2 -4
  20. package/dist/host-contract-BbjhS_Fo.d.ts +310 -0
  21. package/dist/host-contract-CxrQPcPj.js +52 -0
  22. package/dist/host-contract-CxrQPcPj.js.map +1 -0
  23. package/dist/{contract-a4eaQWga.cjs → host-contract-DY9jFPPF.cjs} +36 -16
  24. package/dist/host-contract-DY9jFPPF.cjs.map +1 -0
  25. package/dist/host-contract-Nzxwh0XS.d.cts +310 -0
  26. package/dist/index.cjs +4995 -414
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +12 -17
  29. package/dist/index.d.ts +12 -17
  30. package/dist/index.js +4949 -388
  31. package/dist/index.js.map +1 -1
  32. package/package.json +11 -14
  33. package/dist/authoring-BhtyfsMx.d.cts +0 -37
  34. package/dist/authoring-R4ezdnXd.d.ts +0 -37
  35. package/dist/capability-B_dkoB1K.js +0 -3041
  36. package/dist/capability-B_dkoB1K.js.map +0 -1
  37. package/dist/capability-DVx1NmTe.cjs +0 -3064
  38. package/dist/capability-DVx1NmTe.cjs.map +0 -1
  39. package/dist/contract-CgAcfAE7.d.cts +0 -34
  40. package/dist/contract-CiG2_HBq.d.ts +0 -34
  41. package/dist/contract-DtXE1hjY.js +0 -32
  42. package/dist/contract-DtXE1hjY.js.map +0 -1
  43. package/dist/contract-a4eaQWga.cjs.map +0 -1
  44. package/dist/internal.cjs +0 -8
  45. package/dist/internal.d.cts +0 -14
  46. package/dist/internal.d.ts +0 -14
  47. package/dist/internal.js +0 -5
  48. package/dist/seam-6pJeKOOJ.cjs +0 -296
  49. package/dist/seam-6pJeKOOJ.cjs.map +0 -1
  50. package/dist/seam-C4L_7rDt.js +0 -225
  51. package/dist/seam-C4L_7rDt.js.map +0 -1
  52. package/dist/tools-0NI3b9z8.cjs +0 -536
  53. package/dist/tools-0NI3b9z8.cjs.map +0 -1
  54. package/dist/tools-DBEYx3-c.js +0 -513
  55. package/dist/tools-DBEYx3-c.js.map +0 -1
  56. package/dist/types-BvB1vUKb.js +0 -20
  57. package/dist/types-BvB1vUKb.js.map +0 -1
  58. package/dist/types-D5V0TIwk.d.ts +0 -1200
  59. package/dist/types-Dlhdw2k_.cjs +0 -31
  60. package/dist/types-Dlhdw2k_.cjs.map +0 -1
  61. package/dist/types-ObcPYc3-.d.cts +0 -1200
@@ -1,225 +0,0 @@
1
- import { contentToPdfPoint, contentToPdfRect, contentToPdfRect as contentToPdfRect$1, normalizeDeg, pdfToContentPoint as pdfToContentPoint$1, pdfToContentRect, pdfToContentRect as pdfToContentRect$1, rotatedAabb } from "@embedpdf/core-annotation";
2
- //#region src/repository/seam.ts
3
- function refKey(ref) {
4
- return ref.kind === "objectNumber" ? `obj:${ref.annotObjectNumber}` : ref.kind === "nm" ? `nm:${ref.nm}` : `idx:${ref.pageObjectNumber}:${ref.index}`;
5
- }
6
- const h2 = (n) => Math.max(0, Math.min(255, Math.round(n))).toString(16).padStart(2, "0");
7
- const colorToCss = (c) => `#${h2(c.r)}${h2(c.g)}${h2(c.b)}`;
8
- function cssToColor(css) {
9
- const s = css.trim();
10
- const m6 = /^#?([0-9a-f]{6})$/i.exec(s);
11
- if (m6) {
12
- const n = parseInt(m6[1], 16);
13
- return {
14
- r: n >> 16 & 255,
15
- g: n >> 8 & 255,
16
- b: n & 255
17
- };
18
- }
19
- const m3 = /^#?([0-9a-f]{3})$/i.exec(s);
20
- if (m3) {
21
- const [a, b, c] = m3[1];
22
- return {
23
- r: parseInt(a + a, 16),
24
- g: parseInt(b + b, 16),
25
- b: parseInt(c + c, 16)
26
- };
27
- }
28
- return {
29
- r: 0,
30
- g: 0,
31
- b: 0
32
- };
33
- }
34
- const toPdfRotation = (rotCW) => normalizeDeg(-rotCW);
35
- const fromPdfRotation = (rotPdf) => normalizeDeg(-rotPdf);
36
- /** Advisory `rot` for a vertex geom, from a DTO's (PDF-convention) `rotation`.
37
- * Absent → no `rot` key (kept off the geom so unrotated shapes stay clean). */
38
- const rotFromDTO = (rotation) => rotation ? { rot: fromPdfRotation(rotation) } : {};
39
- /**
40
- * Geometry/rotation fields for a BOX kind (square/circle/plain free-text). The
41
- * model's `rect` is the UNROTATED logical box and `rot` the applied tilt, so:
42
- * - rot == 0 → `/Rect` IS the box; the transform pair is stated as `null`
43
- * (TOTAL projection — the engine's tri-state writes preserve omissions, so
44
- * an omitted field would keep a stale rotation instead of flattening it).
45
- * - rot != 0 → `/Rect` is the rotated visual AABB (PDFium clips the baked /AP
46
- * to it), `unrotatedRect` the logical box, `rotation` the PDF angle.
47
- */
48
- function boxGeomFields(rect, rot, crop) {
49
- if (!rot) return {
50
- rect: contentToPdfRect(rect, crop),
51
- rotation: null,
52
- unrotatedRect: null
53
- };
54
- return {
55
- rect: contentToPdfRect(rotatedAabb(rect, rot), crop),
56
- unrotatedRect: contentToPdfRect(rect, crop),
57
- rotation: toPdfRotation(rot)
58
- };
59
- }
60
- /** A box geom (square/circle/stamp) from its DTO: when rotated, the LOCAL box
61
- * is the stored `unrotatedRect` (the AABB `/Rect` is the rendered envelope)
62
- * and `rot` the converted tilt; unrotated, `/Rect` IS the box. */
63
- function boxGeomFromDTO(dto, rotation, unrotatedRect, crop, ellipse) {
64
- const rot = rotation ? fromPdfRotation(rotation) : 0;
65
- return {
66
- t: "rect",
67
- rect: pdfToContentRect(rot && unrotatedRect ? unrotatedRect : dto.rect, crop),
68
- ellipse,
69
- ...rot ? { rot } : {}
70
- };
71
- }
72
- /** Inset a PdfRect by a `/RD` (PDF user space, y-up: all four are non-negative
73
- * insets from the matching `/Rect` edge). Used to recover the callout text box. */
74
- const insetPdfRectByRD = (r, rd) => rd ? {
75
- left: r.left + rd.left,
76
- bottom: r.bottom + rd.bottom,
77
- right: r.right - rd.right,
78
- top: r.top - rd.top
79
- } : r;
80
- /** Engine border fields (`/BS /S`, `/BS /D`, `/BE /I`) → the `Border` union. A
81
- * cloudy effect wins over the underlying border style (which stays solid). */
82
- function borderFromDTO(d) {
83
- if ((d.cloudyIntensity ?? 0) > 0) return {
84
- kind: "cloudy",
85
- intensity: d.cloudyIntensity
86
- };
87
- if (d.borderStyle === "dashed") return {
88
- kind: "dashed",
89
- dash: d.dashArray?.length ? d.dashArray : [3, 3]
90
- };
91
- return { kind: "solid" };
92
- }
93
- /** The writable projection of a `link` value: `goto`/`uri` pass through,
94
- * read-only arms (`javascript`, `named`, `goto-remote`, `launch`,
95
- * `unsupported`) yield `null` — they can be carried, never (re)written. */
96
- function writableTarget(t) {
97
- return t && (t.kind === "goto" || t.kind === "uri") ? t : null;
98
- }
99
- const TEXT_MARKUP = /* @__PURE__ */ new Set([
100
- "highlight",
101
- "underline",
102
- "squiggly",
103
- "strikeout"
104
- ]);
105
- const STROKE_KINDS = /* @__PURE__ */ new Set([
106
- "square",
107
- "circle",
108
- "line",
109
- "polygon",
110
- "polyline",
111
- "ink"
112
- ]);
113
- /** Engine DTO → content-space `Style` (CSS colours, `Border` union). Exported so
114
- * selection-aware UIs can read display values straight off a {@link AnnotationDTO}
115
- * without re-deriving the colour/border mapping. */
116
- function styleFromDTO(dto) {
117
- if (dto.subtype === "widget") return {
118
- color: dto.color ? colorToCss(dto.color) : "#1a1a1a",
119
- interiorColor: dto.interiorColor ? colorToCss(dto.interiorColor) : null,
120
- strokeWidth: dto.strokeWidth,
121
- opacity: 1,
122
- blendMode: dto.blendMode,
123
- border: dto.borderStyle === "dashed" ? {
124
- kind: "dashed",
125
- dash: [3, 3]
126
- } : { kind: "solid" }
127
- };
128
- if (STROKE_KINDS.has(dto.subtype)) {
129
- const d = dto;
130
- return {
131
- color: colorToCss(d.color),
132
- interiorColor: d.interiorColor ? colorToCss(d.interiorColor) : null,
133
- strokeWidth: d.strokeWidth,
134
- opacity: d.opacity,
135
- blendMode: dto.blendMode,
136
- border: borderFromDTO(d)
137
- };
138
- }
139
- if (TEXT_MARKUP.has(dto.subtype)) {
140
- const d = dto;
141
- return {
142
- color: colorToCss(d.color),
143
- interiorColor: null,
144
- strokeWidth: 0,
145
- opacity: d.opacity,
146
- blendMode: dto.blendMode,
147
- border: { kind: "solid" }
148
- };
149
- }
150
- if (dto.subtype === "caret") {
151
- const d = dto;
152
- return {
153
- color: colorToCss(d.color),
154
- interiorColor: null,
155
- strokeWidth: 1,
156
- opacity: d.opacity,
157
- blendMode: dto.blendMode,
158
- border: { kind: "solid" }
159
- };
160
- }
161
- if (dto.subtype === "free-text") {
162
- const d = dto;
163
- return {
164
- color: colorToCss(d.color),
165
- interiorColor: d.interiorColor ? colorToCss(d.interiorColor) : null,
166
- strokeWidth: d.strokeWidth,
167
- opacity: d.opacity,
168
- blendMode: dto.blendMode,
169
- border: borderFromDTO(d)
170
- };
171
- }
172
- if (dto.subtype === "redact") {
173
- const d = dto;
174
- return {
175
- color: colorToCss(d.color),
176
- interiorColor: d.interiorColor ? colorToCss(d.interiorColor) : null,
177
- strokeWidth: 1.5,
178
- opacity: d.opacity,
179
- blendMode: dto.blendMode,
180
- border: { kind: "solid" }
181
- };
182
- }
183
- if (dto.subtype === "text" || dto.subtype === "file-attachment") {
184
- const d = dto;
185
- return {
186
- color: colorToCss(d.color),
187
- interiorColor: null,
188
- strokeWidth: 1,
189
- opacity: d.opacity,
190
- blendMode: dto.blendMode,
191
- border: { kind: "solid" }
192
- };
193
- }
194
- return {
195
- color: "#444444",
196
- interiorColor: null,
197
- strokeWidth: 1,
198
- opacity: 1,
199
- blendMode: dto.blendMode,
200
- border: { kind: "solid" }
201
- };
202
- }
203
- /**
204
- * The flat props vocabulary (CSS colours, house keys) → the engine's widget
205
- * appearance for `doc.forms` authoring — the SAME mapping the widget patch
206
- * lowering uses, exported as a boundary utility so the form plugin can style
207
- * `placeField` from a tool's `currentDefaults` without growing a second CSS
208
- * parser. Absent keys stay absent (the engine writes nothing for them).
209
- */
210
- function widgetAppearanceFromProps(props) {
211
- return {
212
- ...props.color !== void 0 ? { color: cssToColor(props.color) } : {},
213
- ...props.interiorColor !== void 0 ? { interiorColor: props.interiorColor ? cssToColor(props.interiorColor) : null } : {},
214
- ...props.strokeWidth !== void 0 ? { strokeWidth: props.strokeWidth } : {},
215
- ...props.border !== void 0 ? { borderStyle: props.border.kind === "dashed" ? "dashed" : "solid" } : {},
216
- ...props.fontFamily !== void 0 ? { fontFamily: props.fontFamily } : {},
217
- ...props.fontSize !== void 0 ? { fontSize: props.fontSize } : {},
218
- ...props.fontColor !== void 0 ? { fontColor: cssToColor(props.fontColor) } : {},
219
- ...props.textAlign !== void 0 ? { textAlign: props.textAlign } : {}
220
- };
221
- }
222
- //#endregion
223
- export { contentToPdfRect$1 as a, insetPdfRectByRD as c, refKey as d, rotFromDTO as f, writableTarget as g, widgetAppearanceFromProps as h, contentToPdfPoint as i, pdfToContentPoint$1 as l, toPdfRotation as m, boxGeomFromDTO as n, cssToColor as o, styleFromDTO as p, colorToCss as r, fromPdfRotation as s, boxGeomFields as t, pdfToContentRect$1 as u };
224
-
225
- //# sourceMappingURL=seam-C4L_7rDt.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"seam-C4L_7rDt.js","names":[],"sources":["../src/repository/seam.ts"],"sourcesContent":["/**\n * The geometry/colour/rotation SEAM between the engine's PDF-space wire\n * vocabulary and the core's content-space model. Every conversion between the\n * two worlds lives here — kind modules speak through these helpers and never\n * hand-roll a convention flip.\n */\nimport type {\n AnnotationDTO,\n AnnotationRef,\n Color,\n PdfLinkTarget,\n PdfLinkTargetWritable,\n PdfRect,\n PdfRectDifferences,\n StandardFont,\n WidgetAppearance,\n} from '@embedpdf/engine-core/runtime';\nimport {\n contentToPdfRect,\n normalizeDeg,\n pdfToContentRect,\n rotatedAabb,\n type AnnotationPropsPatch,\n type Border,\n type Geom,\n type Rect,\n type Style,\n} from '@embedpdf/core-annotation';\n\n// The content↔PDF bridge, re-exported so kind modules cross the seam through\n// ONE import point and never reach into the core's geometry directly.\nexport {\n contentToPdfPoint,\n contentToPdfRect,\n pdfToContentPoint,\n pdfToContentRect,\n} from '@embedpdf/core-annotation';\n\nexport function refKey(ref: AnnotationRef): string {\n return ref.kind === 'objectNumber'\n ? `obj:${ref.annotObjectNumber}`\n : ref.kind === 'nm'\n ? `nm:${ref.nm}`\n : `idx:${ref.pageObjectNumber}:${ref.index}`;\n}\n\n/* ── colour seam (engine Color ↔ CSS hex) ─────────────────────────────────── */\n\nconst h2 = (n: number) =>\n Math.max(0, Math.min(255, Math.round(n)))\n .toString(16)\n .padStart(2, '0');\nexport const colorToCss = (c: Color): string => `#${h2(c.r)}${h2(c.g)}${h2(c.b)}`;\nexport function cssToColor(css: string): Color {\n const s = css.trim();\n const m6 = /^#?([0-9a-f]{6})$/i.exec(s);\n if (m6) {\n const n = parseInt(m6[1], 16);\n return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 };\n }\n const m3 = /^#?([0-9a-f]{3})$/i.exec(s);\n if (m3) {\n const [a, b, c] = m3[1];\n return { r: parseInt(a + a, 16), g: parseInt(b + b, 16), b: parseInt(c + c, 16) };\n }\n return { r: 0, g: 0, b: 0 };\n}\n\n/* ── rotation seam (CW content ↔ PDF convention) ──────────────────────────────\n * The model's `rot` is CLOCKWISE in content space (y-down). PDF user space is\n * y-up, so the y-flip at this boundary turns a CW content tilt into a CCW PDF\n * tilt of the same magnitude — i.e. the stored `/EMBD_Metadata/Rotation` is the\n * NEGATION (mod 360). This is the ONE place the convention is converted; every\n * layer above speaks CW-content and the engine/PDFium speaks the PDF angle.\n */\nexport const toPdfRotation = (rotCW: number): number => normalizeDeg(-rotCW);\nexport const fromPdfRotation = (rotPdf: number): number => normalizeDeg(-rotPdf);\n\n/** Advisory `rot` for a vertex geom, from a DTO's (PDF-convention) `rotation`.\n * Absent → no `rot` key (kept off the geom so unrotated shapes stay clean). */\nexport const rotFromDTO = (rotation?: number): { rot?: number } =>\n rotation ? { rot: fromPdfRotation(rotation) } : {};\n\n/**\n * Geometry/rotation fields for a BOX kind (square/circle/plain free-text). The\n * model's `rect` is the UNROTATED logical box and `rot` the applied tilt, so:\n * - rot == 0 → `/Rect` IS the box; the transform pair is stated as `null`\n * (TOTAL projection — the engine's tri-state writes preserve omissions, so\n * an omitted field would keep a stale rotation instead of flattening it).\n * - rot != 0 → `/Rect` is the rotated visual AABB (PDFium clips the baked /AP\n * to it), `unrotatedRect` the logical box, `rotation` the PDF angle.\n */\nexport function boxGeomFields(\n rect: Rect,\n rot: number,\n crop: PdfRect,\n): { rect: PdfRect; unrotatedRect: PdfRect | null; rotation: number | null } {\n if (!rot) return { rect: contentToPdfRect(rect, crop), rotation: null, unrotatedRect: null };\n return {\n rect: contentToPdfRect(rotatedAabb(rect, rot), crop),\n unrotatedRect: contentToPdfRect(rect, crop),\n rotation: toPdfRotation(rot),\n };\n}\n\n/** A box geom (square/circle/stamp) from its DTO: when rotated, the LOCAL box\n * is the stored `unrotatedRect` (the AABB `/Rect` is the rendered envelope)\n * and `rot` the converted tilt; unrotated, `/Rect` IS the box. */\nexport function boxGeomFromDTO(\n dto: { rect: PdfRect },\n rotation: number | undefined,\n unrotatedRect: PdfRect | undefined,\n crop: PdfRect,\n ellipse: boolean,\n): Geom {\n const rot = rotation ? fromPdfRotation(rotation) : 0;\n const box = rot && unrotatedRect ? unrotatedRect : dto.rect;\n return { t: 'rect', rect: pdfToContentRect(box, crop), ellipse, ...(rot ? { rot } : {}) };\n}\n\n/** Inset a PdfRect by a `/RD` (PDF user space, y-up: all four are non-negative\n * insets from the matching `/Rect` edge). Used to recover the callout text box. */\nexport const insetPdfRectByRD = (r: PdfRect, rd?: PdfRectDifferences | null): PdfRect =>\n rd\n ? {\n left: r.left + rd.left,\n bottom: r.bottom + rd.bottom,\n right: r.right - rd.right,\n top: r.top - rd.top,\n }\n : r;\n\n/** Engine border fields (`/BS /S`, `/BS /D`, `/BE /I`) → the `Border` union. A\n * cloudy effect wins over the underlying border style (which stays solid). */\nexport function borderFromDTO(d: {\n borderStyle?: string;\n dashArray?: number[];\n cloudyIntensity?: number | null;\n}): Border {\n if ((d.cloudyIntensity ?? 0) > 0) return { kind: 'cloudy', intensity: d.cloudyIntensity! };\n if (d.borderStyle === 'dashed')\n return { kind: 'dashed', dash: d.dashArray?.length ? d.dashArray : [3, 3] };\n return { kind: 'solid' };\n}\n\n/** The writable projection of a `link` value: `goto`/`uri` pass through,\n * read-only arms (`javascript`, `named`, `goto-remote`, `launch`,\n * `unsupported`) yield `null` — they can be carried, never (re)written. */\nexport function writableTarget(t: PdfLinkTarget | null | undefined): PdfLinkTargetWritable | null {\n return t && (t.kind === 'goto' || t.kind === 'uri') ? t : null;\n}\n\nexport const TEXT_MARKUP = new Set(['highlight', 'underline', 'squiggly', 'strikeout']);\n// Geometric kinds that carry the `/C` stroke colour + `/BS` border. Ink belongs\n// here too (it has a stroke but no `/IC`, so its interiorColor reads back null).\nconst STROKE_KINDS = new Set(['square', 'circle', 'line', 'polygon', 'polyline', 'ink']);\n\n/** Engine DTO → content-space `Style` (CSS colours, `Border` union). Exported so\n * selection-aware UIs can read display values straight off a {@link AnnotationDTO}\n * without re-deriving the colour/border mapping. */\nexport function styleFromDTO(dto: AnnotationDTO): Style {\n if (dto.subtype === 'widget') {\n return {\n color: dto.color ? colorToCss(dto.color) : '#1a1a1a',\n interiorColor: dto.interiorColor ? colorToCss(dto.interiorColor) : null,\n strokeWidth: dto.strokeWidth,\n opacity: 1,\n blendMode: dto.blendMode,\n border: dto.borderStyle === 'dashed' ? { kind: 'dashed', dash: [3, 3] } : { kind: 'solid' },\n };\n }\n if (STROKE_KINDS.has(dto.subtype)) {\n const d = dto as Extract<\n AnnotationDTO,\n { interiorColor: Color | null; opacity: number; strokeWidth: number }\n >;\n return {\n color: colorToCss(d.color),\n interiorColor: d.interiorColor ? colorToCss(d.interiorColor) : null,\n strokeWidth: d.strokeWidth,\n opacity: d.opacity,\n blendMode: dto.blendMode,\n border: borderFromDTO(d),\n };\n }\n if (TEXT_MARKUP.has(dto.subtype)) {\n const d = dto as Extract<AnnotationDTO, { color: Color }>;\n return {\n color: colorToCss(d.color),\n interiorColor: null,\n strokeWidth: 0,\n opacity: d.opacity,\n blendMode: dto.blendMode,\n border: { kind: 'solid' },\n };\n }\n if (dto.subtype === 'caret') {\n const d = dto as Extract<AnnotationDTO, { color: Color; opacity: number }>;\n return {\n color: colorToCss(d.color),\n interiorColor: null,\n strokeWidth: 1,\n opacity: d.opacity,\n blendMode: dto.blendMode,\n border: { kind: 'solid' },\n };\n }\n if (dto.subtype === 'free-text') {\n // `/DA` colour is the border + leader stroke; `/C` is the box background; `/BS`\n // gives the width. A plain text box draws no vector scene, so these only matter\n // for a callout's leader/arrow/box-border (and the style toolbar's readout).\n const d = dto as Extract<AnnotationDTO, { subtype: 'free-text' }>;\n return {\n color: colorToCss(d.color),\n interiorColor: d.interiorColor ? colorToCss(d.interiorColor) : null,\n strokeWidth: d.strokeWidth,\n opacity: d.opacity,\n blendMode: dto.blendMode,\n border: borderFromDTO(d),\n };\n }\n if (dto.subtype === 'redact') {\n // `/C` is the marking-stage outline; `/IC` the fill painted on apply.\n // No `/BS` on redact — the outline weight is a client rendering choice.\n const d = dto as Extract<AnnotationDTO, { subtype: 'redact' }>;\n return {\n color: colorToCss(d.color),\n interiorColor: d.interiorColor ? colorToCss(d.interiorColor) : null,\n strokeWidth: 1.5,\n opacity: d.opacity,\n blendMode: dto.blendMode,\n border: { kind: 'solid' },\n };\n }\n if (dto.subtype === 'text' || dto.subtype === 'file-attachment') {\n // Icon kinds: /C is the icon fill, /CA its opacity — no stroke/fill split.\n const d = dto as Extract<AnnotationDTO, { color: Color; opacity: number }>;\n return {\n color: colorToCss(d.color),\n interiorColor: null,\n strokeWidth: 1,\n opacity: d.opacity,\n blendMode: dto.blendMode,\n border: { kind: 'solid' },\n };\n }\n return {\n color: '#444444',\n interiorColor: null,\n strokeWidth: 1,\n opacity: 1,\n blendMode: dto.blendMode,\n border: { kind: 'solid' },\n };\n}\n\n/**\n * The flat props vocabulary (CSS colours, house keys) → the engine's widget\n * appearance for `doc.forms` authoring — the SAME mapping the widget patch\n * lowering uses, exported as a boundary utility so the form plugin can style\n * `placeField` from a tool's `currentDefaults` without growing a second CSS\n * parser. Absent keys stay absent (the engine writes nothing for them).\n */\nexport function widgetAppearanceFromProps(props: AnnotationPropsPatch): WidgetAppearance {\n return {\n ...(props.color !== undefined ? { color: cssToColor(props.color) } : {}),\n ...(props.interiorColor !== undefined\n ? { interiorColor: props.interiorColor ? cssToColor(props.interiorColor) : null }\n : {}),\n ...(props.strokeWidth !== undefined ? { strokeWidth: props.strokeWidth } : {}),\n ...(props.border !== undefined\n ? { borderStyle: props.border.kind === 'dashed' ? ('dashed' as const) : ('solid' as const) }\n : {}),\n ...(props.fontFamily !== undefined ? { fontFamily: props.fontFamily as StandardFont } : {}),\n ...(props.fontSize !== undefined ? { fontSize: props.fontSize } : {}),\n ...(props.fontColor !== undefined ? { fontColor: cssToColor(props.fontColor) } : {}),\n ...(props.textAlign !== undefined ? { textAlign: props.textAlign } : {}),\n };\n}\n"],"mappings":"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"}