@embedpdf/core-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.
- package/README.md +90 -0
- package/dist/index.cjs +8812 -5255
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1668 -962
- package/dist/index.d.ts +1668 -962
- package/dist/index.js +8719 -5234
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.cts
CHANGED
|
@@ -1,71 +1,391 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
/** All ten flags, for iteration/equality — kept in the primitives' order. */
|
|
9
|
-
declare const FLAG_KEYS: ReadonlyArray<keyof AnnotationFlags>;
|
|
10
|
-
declare const flagsEqual: (a: AnnotationFlags, b: AnnotationFlags) => boolean;
|
|
11
|
-
/** Merge a partial write over the current flags. */
|
|
12
|
-
declare const mergeFlags: (base: AnnotationFlags, patch: Partial<AnnotationFlags>) => AnnotationFlags;
|
|
1
|
+
import { PageRotation, Point, Point as Point$1, Quad, Quad as Quad$1, QuadRing, Rect as Rect$1, Size } from "@embedpdf/core-geometry";
|
|
2
|
+
import { Annotation, AnnotationBorderStyle, AnnotationDraft, AnnotationFlags, AnnotationFlags as AnnotationFlags$1, AnnotationPatch, AnnotationRef, AnnotationSubtype, BlendMode, BlendMode as BlendMode$1, Color, FaceRequest, FileAttachmentIcon, FontHandle, InkIntent, LineEnding, LineEnding as LineEnding$1, LineEndings, LineEndings as LineEndings$1, NO_ANNOTATION_FLAGS, NoteIcon, PageRef, PdfLinkTarget, PdfLinkTargetWritable, RichTextBody, RichTextDocument, RichTextDocumentInput, RichTextParagraph, RichTextRunStyle, STANDARD_FACES, WidgetAppearance } from "@embedpdf/engine-core/runtime";
|
|
3
|
+
//#region src/editable.d.ts
|
|
4
|
+
/** The intents a measurement goes by in {@link EditableKinds}. */
|
|
5
|
+
type MeasurementIntent = 'line-dimension' | 'polyline-dimension' | 'polygon-dimension';
|
|
6
|
+
/** What {@link EditableKinds} names an annotation by: {@link editableKindOf}. */
|
|
7
|
+
type EditableKind = AnnotationSubtype | MeasurementIntent;
|
|
13
8
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
9
|
+
* Which annotations people may change by hand: `true`, every one; `false`,
|
|
10
|
+
* none; a list, the annotations of the kinds it names, each by its subtype,
|
|
11
|
+
* or a measurement by its intent (so measurements and the shapes they're
|
|
12
|
+
* drawn as are told apart).
|
|
17
13
|
*/
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
declare
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
14
|
+
type EditableKinds = boolean | readonly EditableKind[];
|
|
15
|
+
/** The name {@link EditableKinds} knows an annotation by: a measurement's intent, else its subtype. */
|
|
16
|
+
declare function editableKindOf(annotation: Annotation): EditableKind;
|
|
17
|
+
/** Whether the session's rule lets people change this annotation by hand. */
|
|
18
|
+
declare function isEditableByHand(model: Pick<Session, 'editable'>, annotation: Annotation): boolean;
|
|
19
|
+
/** Whether people may move, resize, turn, reshape or restyle the record by hand now. */
|
|
20
|
+
declare const isTransformableByHand: (model: Pick<Session, "editable">, record: ModelAnnotation) => boolean;
|
|
21
|
+
/** Whether people may delete the record by hand now. */
|
|
22
|
+
declare const isDeletableByHand: (model: Pick<Session, "editable">, record: ModelAnnotation) => boolean;
|
|
23
|
+
/** Whether people may edit the record's text in place now. */
|
|
24
|
+
declare const isContentsEditableByHand: (model: Pick<Session, "editable">, record: ModelAnnotation) => boolean;
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/painted.d.ts
|
|
27
|
+
/** One piece of what an annotation paints, in page space. */
|
|
28
|
+
type PaintedPiece =
|
|
29
|
+
/** Ink along a path, `halfWidth` either side of it; `closed` runs it back to the first point. */
|
|
30
|
+
{
|
|
31
|
+
readonly kind: 'stroke';
|
|
32
|
+
readonly points: readonly Point[];
|
|
33
|
+
readonly closed: boolean;
|
|
34
|
+
readonly halfWidth: number;
|
|
35
|
+
} |
|
|
36
|
+
/** A filled polygon (even-odd). A margin doesn't grow it: ink around it does. */
|
|
37
|
+
{
|
|
38
|
+
readonly kind: 'area';
|
|
39
|
+
readonly ring: readonly Point[];
|
|
40
|
+
} |
|
|
41
|
+
/**
|
|
42
|
+
* An ellipse turned `rotation` degrees clockwise about `center`: its ink,
|
|
43
|
+
* `halfWidth` either side of it, and its inside when `filled`. The ink's
|
|
44
|
+
* width is measured in radii along the smaller radius, so a long ellipse's
|
|
45
|
+
* ink is a little wider at its ends.
|
|
46
|
+
*/
|
|
47
|
+
{
|
|
48
|
+
readonly kind: 'oval';
|
|
49
|
+
readonly center: Point;
|
|
50
|
+
readonly rx: number;
|
|
51
|
+
readonly ry: number;
|
|
52
|
+
readonly rotation: number;
|
|
53
|
+
readonly halfWidth: number;
|
|
54
|
+
readonly filled: boolean;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* A solid body: anything inside the ring, and anything within a margin of
|
|
58
|
+
* its edge (a rim of ink with no width). A text box, a caret and a
|
|
59
|
+
* measurement's caption are hit this way.
|
|
60
|
+
*/
|
|
61
|
+
declare const bodyPieces: (ring: readonly Point[]) => PaintedPiece[];
|
|
62
|
+
/** Is `point` within `margin` of what the pieces paint? */
|
|
63
|
+
declare const paintedNear: (pieces: readonly PaintedPiece[], point: Point, margin: number) => boolean;
|
|
64
|
+
/** Does the rect touch what the pieces paint: cross its ink, or lie on its fill? */
|
|
65
|
+
declare const paintedTouches: (pieces: readonly PaintedPiece[], rect: Rect) => boolean;
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region src/measurement-shape.d.ts
|
|
68
|
+
type ShapeAnnotation = Extract<Annotation, {
|
|
69
|
+
subtype: 'polygon' | 'polyline';
|
|
70
|
+
}>;
|
|
71
|
+
/**
|
|
72
|
+
* A perimeter's or area's measurement: the engine's own fields for its scale,
|
|
73
|
+
* whether its caption shows, and its label (`contents`, which the engine
|
|
74
|
+
* works out). Where the caption sits is the shape's `captionCenter`.
|
|
75
|
+
*/
|
|
76
|
+
type ShapeMeasurementAppearance = {
|
|
77
|
+
intent: 'polyline-dimension' | 'polygon-dimension';
|
|
78
|
+
} & Pick<ShapeAnnotation, 'measure' | 'captionEnabled' | 'contents'>;
|
|
79
|
+
interface ShapeMeasurementLayout {
|
|
80
|
+
caption: DistanceCaptionLayout | null;
|
|
81
|
+
visualBounds: Rect;
|
|
82
|
+
selectionPoints: Point[];
|
|
83
|
+
}
|
|
84
|
+
declare function shapeMeasurementReadout(geometry: Shape, appearance: ShapeMeasurementAppearance): import("@embedpdf/engine-core/runtime").MeasurementReadout | import("@embedpdf/engine-core/runtime").MeasurementUnavailable;
|
|
85
|
+
declare function shapeMeasurementLabel(geometry: Shape, appearance: ShapeMeasurementAppearance): string;
|
|
86
|
+
/** Match the native shape-caption anchor, including an interior fallback for concave areas. */
|
|
87
|
+
declare function automaticShapeCaptionCenter(points: readonly Point[], closed: boolean): Point;
|
|
88
|
+
declare function shapeMeasurementLayout(geometry: Shape, appearance: ShapeMeasurementAppearance, style: Style): ShapeMeasurementLayout | null;
|
|
89
|
+
declare function measurementLayout(geometry: Shape, appearance: MeasurementAppearance, style: Style): ShapeMeasurementLayout | null;
|
|
90
|
+
declare function measurementSelectionQuad(geometry: Shape, appearance: MeasurementAppearance, style: Style): QuadRing;
|
|
91
|
+
/**
|
|
92
|
+
* The caption dragged by `delta`: a distance's caption offset changes (its
|
|
93
|
+
* measurement), a perimeter's or area's caption center (its shape, kept
|
|
94
|
+
* upright with the vertices).
|
|
95
|
+
*/
|
|
96
|
+
declare function moveMeasurementCaption(geometry: Shape, appearance: MeasurementAppearance, delta: Point, style: Style): {
|
|
97
|
+
geometry: Shape;
|
|
98
|
+
measure: MeasurementAppearance;
|
|
99
|
+
};
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/measurement.d.ts
|
|
102
|
+
type MeasurementAppearance = DistanceAppearance | ShapeMeasurementAppearance;
|
|
103
|
+
type LineAnnotation = Extract<Annotation, {
|
|
104
|
+
subtype: 'line';
|
|
105
|
+
}>;
|
|
106
|
+
/**
|
|
107
|
+
* A distance's measurement: the engine's own fields for its scale, its
|
|
108
|
+
* caption (on or off, its position, and its offset in the line's own axes),
|
|
109
|
+
* its leader and its label (`contents`, which the engine works out).
|
|
110
|
+
*/
|
|
111
|
+
type DistanceAppearance = {
|
|
112
|
+
intent: 'line-dimension';
|
|
113
|
+
} & Pick<LineAnnotation, 'measure' | 'captionEnabled' | 'captionPosition' | 'captionOffset' | 'leader' | 'contents'>;
|
|
114
|
+
/**
|
|
115
|
+
* The annotation's measurement, when it is one: a line measuring a
|
|
116
|
+
* distance, a polyline a perimeter, a polygon an area, as its intent says.
|
|
117
|
+
* Its measurement fields, read off it for drawing and hit-testing.
|
|
118
|
+
*/
|
|
119
|
+
declare function measurementOf(annotation: Annotation): MeasurementAppearance | undefined;
|
|
120
|
+
/**
|
|
121
|
+
* What a new measurement states beside its points: its intent, its scale
|
|
122
|
+
* (one the engine can write), its caption and leader as it has them, and its
|
|
123
|
+
* subject. Its label is the engine's: it works it out from the points and
|
|
124
|
+
* the scale.
|
|
125
|
+
*/
|
|
126
|
+
declare function measurementDraftFields(appearance: MeasurementAppearance): FieldValues;
|
|
127
|
+
interface DistanceSegment {
|
|
128
|
+
from: Point;
|
|
129
|
+
to: Point;
|
|
130
|
+
}
|
|
131
|
+
interface DistanceCaptionLayout {
|
|
132
|
+
text: string;
|
|
133
|
+
center: Point;
|
|
134
|
+
along: Point;
|
|
135
|
+
normal: Point;
|
|
136
|
+
width: number;
|
|
137
|
+
height: number;
|
|
138
|
+
bounds: QuadRing;
|
|
139
|
+
}
|
|
140
|
+
/** One layout drives the preview, selection, handles, and hit testing. */
|
|
141
|
+
interface DistanceLayout {
|
|
142
|
+
along: Point;
|
|
143
|
+
normal: Point;
|
|
144
|
+
length: number;
|
|
145
|
+
measuredStart: Point;
|
|
146
|
+
measuredEnd: Point;
|
|
147
|
+
dimensionStart: Point;
|
|
148
|
+
dimensionEnd: Point;
|
|
149
|
+
dimensionSegments: DistanceSegment[];
|
|
150
|
+
leaderSegments: DistanceSegment[];
|
|
151
|
+
captionConnector: DistanceSegment[];
|
|
152
|
+
caption: DistanceCaptionLayout | null;
|
|
153
|
+
arrowPlacement: 'inside' | 'outside';
|
|
154
|
+
endings: RenderNode[];
|
|
155
|
+
selectionPoints: Point[];
|
|
156
|
+
visualBounds: Rect;
|
|
157
|
+
}
|
|
158
|
+
declare function distanceLabel(geometry: Shape, appearance: DistanceAppearance): string;
|
|
159
|
+
declare function distanceLayout(geometry: Shape, appearance: DistanceAppearance, strokeWidth: number): DistanceLayout | null;
|
|
160
|
+
declare function expandDistanceBounds(bounds: Rect, padding: number): Rect;
|
|
161
|
+
declare function distanceSelectionQuad(geometry: Shape, appearance: DistanceAppearance, strokeWidth: number): QuadRing;
|
|
162
|
+
declare function distanceHandles(layout: DistanceLayout): Handle[];
|
|
163
|
+
declare function distanceCaptionHit(layout: {
|
|
164
|
+
caption: DistanceCaptionLayout | null;
|
|
165
|
+
}, point: Point, margin?: number): boolean;
|
|
166
|
+
/** What a measurement's caption paints: its box, grabbed anywhere in it and near its edge. */
|
|
167
|
+
declare const captionPainted: (caption: DistanceCaptionLayout | null) => PaintedPiece[];
|
|
168
|
+
/**
|
|
169
|
+
* What a distance measurement paints: its caption, the ink of its dimension
|
|
170
|
+
* line, leaders and caption connector, and its endings.
|
|
171
|
+
*/
|
|
172
|
+
declare function distancePainted(layout: DistanceLayout, strokeWidth: number): PaintedPiece[];
|
|
173
|
+
declare function distanceCaptionAt(geometry: Shape, appearance: DistanceAppearance, width: number): Point | null;
|
|
174
|
+
declare function distanceLeaderLength(geometry: Shape, point: Point): number;
|
|
175
|
+
declare function moveDistanceCaption(geometry: Shape, appearance: DistanceAppearance, delta: Point): DistanceAppearance;
|
|
176
|
+
/**
|
|
177
|
+
* The upright box around all a distance paints: its dimension line, leader
|
|
178
|
+
* and connector lines and its endings stroked at `strokeWidth` (what
|
|
179
|
+
* `distanceScene` draws), and its caption's box.
|
|
180
|
+
*/
|
|
181
|
+
declare function distanceDrawnBounds(layout: DistanceLayout, strokeWidth: number): Rect;
|
|
182
|
+
declare function distanceScene(geometry: Shape, appearance: DistanceAppearance, style: Style): SceneNode[];
|
|
183
|
+
declare function measurementCaptionScene(caption: DistanceCaptionLayout | null, style: Style): SceneNode[];
|
|
184
|
+
//#endregion
|
|
185
|
+
//#region src/shapes/family.d.ts
|
|
186
|
+
/** A box's four corners as the page shows them: nw, ne, se, sw. */
|
|
187
|
+
type Corners = [Point, Point, Point, Point];
|
|
188
|
+
interface ShapeFamily<S extends Shape = Shape> {
|
|
189
|
+
/** The shape, read off an annotation of a kind in this family. */
|
|
190
|
+
read(annotation: Annotation): S;
|
|
191
|
+
/** The engine fields that state `shape` on an annotation of `subtype`. */
|
|
192
|
+
write(shape: S, subtype: string): FieldValues;
|
|
193
|
+
/**
|
|
194
|
+
* The shape a create gesture makes at `placement` (a clicked or dragged box
|
|
195
|
+
* or segment, `placement.ts`) for `annotation`, what the tool creates before
|
|
196
|
+
* it has a shape; `null` when this family's kinds aren't made that way.
|
|
197
|
+
*/
|
|
198
|
+
placed(placement: Placement, annotation: Annotation): S | null;
|
|
199
|
+
/** The box around its box or points, the stroke left out. */
|
|
200
|
+
bounds(shape: S): Rect;
|
|
201
|
+
/**
|
|
202
|
+
* The box the live drawing is painted into (the stroke, endings, a cloud's
|
|
203
|
+
* bumps): a box's or caret's own, before its turn (the renderer turns it),
|
|
204
|
+
* the page's for the rest.
|
|
205
|
+
*/
|
|
206
|
+
drawnBounds(shape: S, stroke: Stroke): Rect;
|
|
207
|
+
/** The upright page box around all it paints: the engine's `rect`, as it measures its appearance. */
|
|
208
|
+
rect(shape: S, stroke: Stroke): Rect;
|
|
209
|
+
/** The box a selection wraps: where its handles sit, and where a selected shape is grabbed. */
|
|
210
|
+
selectionBounds(shape: S, stroke: Stroke): Rect;
|
|
211
|
+
/** Does the shape have a turned box of its own, which a selection outlines turned? */
|
|
212
|
+
oriented(shape: S): boolean;
|
|
213
|
+
/** That turned box's corners, or `null` when the shape has none. */
|
|
214
|
+
turnedCorners(shape: S, stroke: Stroke): Corners | null;
|
|
215
|
+
/** Where a turn of the shape pivots, as the engine turns it. */
|
|
216
|
+
pivot(shape: S): Point;
|
|
217
|
+
/** The shape moved by `delta`. */
|
|
218
|
+
translate(shape: S, delta: Point): S;
|
|
219
|
+
/** The shape turned `degrees` clockwise about `pivot`; unchanged when it doesn't turn. */
|
|
220
|
+
rotateAbout(shape: S, pivot: Point, degrees: number): S;
|
|
221
|
+
/**
|
|
222
|
+
* The shape scaled about `anchor` by `(sx, sy)`, exactly. A resize passes
|
|
223
|
+
* its limit, `minSize`: a box then ends up no smaller than that.
|
|
224
|
+
*/
|
|
225
|
+
scaleAbout(shape: S, anchor: Point, sx: number, sy: number, minSize?: number): S;
|
|
226
|
+
/** The shape with its turn cleared, turned back about `pivot` where that matters. */
|
|
227
|
+
upright(shape: S, pivot?: Point): S;
|
|
228
|
+
/** Its handles: resize corners and sides, or vertices. */
|
|
229
|
+
handles(shape: S): Handle[];
|
|
230
|
+
/** The shape with `handle` dragged to `to`. */
|
|
231
|
+
drag(shape: S, handle: string, to: Point): S;
|
|
232
|
+
/**
|
|
233
|
+
* What it paints (`painted.ts`): its ink, and its inside when `filled`. A
|
|
234
|
+
* click and the marquee both read these pieces.
|
|
235
|
+
*/
|
|
236
|
+
painted(shape: S, stroke: Stroke, filled: boolean): PaintedPiece[];
|
|
237
|
+
/** What it draws, for the live (vector) view. */
|
|
238
|
+
scene(shape: S, stroke: Stroke): RenderNode[];
|
|
239
|
+
}
|
|
240
|
+
//#endregion
|
|
241
|
+
//#region src/shapes/box.d.ts
|
|
242
|
+
/** A box and its turn, as the engine keeps them. */
|
|
243
|
+
interface TurnedBox {
|
|
244
|
+
/** The box before any turn: the engine's `box`, or its `rect` for a kind that never turns. */
|
|
245
|
+
box: Rect;
|
|
246
|
+
/** Degrees clockwise about the middle of `box`; 0 when upright. */
|
|
247
|
+
rotation: number;
|
|
248
|
+
}
|
|
249
|
+
/** A box family record's shape: the engine's box and its turn. */
|
|
250
|
+
interface BoxShape extends TurnedBox {
|
|
251
|
+
kind: 'box';
|
|
252
|
+
/** Drawn as the ellipse in `box`: a circle. */
|
|
253
|
+
ellipse: boolean;
|
|
254
|
+
}
|
|
255
|
+
/** The box family: a box and its turn, drawn as a rectangle, an ellipse or a cloud. */
|
|
256
|
+
declare const boxFamily: ShapeFamily<BoxShape>;
|
|
257
|
+
//#endregion
|
|
258
|
+
//#region src/shapes/caret.d.ts
|
|
259
|
+
/** A caret record's shape: the engine's box and its turn. */
|
|
260
|
+
interface CaretShape extends TurnedBox {
|
|
261
|
+
kind: 'caret';
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* The caret box for a text-edit anchor, upright: half the glyph's ink height,
|
|
265
|
+
* centred on the trailing baseline corner in reading direction (`advance`
|
|
266
|
+
* decides which end, so a right-to-left caret lands on the visual left),
|
|
267
|
+
* sitting on the baseline. {@link caretFromAnchor} gives the turned caret.
|
|
268
|
+
*/
|
|
269
|
+
declare function caretRectFromAnchor(anchor: TextEndAnchor): Rect;
|
|
270
|
+
/**
|
|
271
|
+
* The caret for a text-edit anchor: a box whose middle sits half a caret size
|
|
272
|
+
* toward the ascent from the trailing baseline corner, turned by the text's
|
|
273
|
+
* baseline tilt (degrees clockwise), so the mark hugs the turned baseline and
|
|
274
|
+
* points at its text. For upright text this is exactly
|
|
275
|
+
* {@link caretRectFromAnchor} with no turn.
|
|
276
|
+
*/
|
|
277
|
+
declare function caretFromAnchor(anchor: TextEndAnchor): CaretShape;
|
|
278
|
+
/**
|
|
279
|
+
* The caret family: a mark in a turned box that follows its text. It moves
|
|
280
|
+
* and scales with a selection, but no gesture turns, resizes or drags it.
|
|
281
|
+
*/
|
|
282
|
+
declare const caretFamily: ShapeFamily<CaretShape>;
|
|
283
|
+
//#endregion
|
|
284
|
+
//#region src/shapes/points.d.ts
|
|
285
|
+
/** A line: its two ends upright, and their endings. */
|
|
286
|
+
interface LineShape {
|
|
287
|
+
kind: 'line';
|
|
288
|
+
linePoints: {
|
|
289
|
+
start: Point;
|
|
290
|
+
end: Point;
|
|
30
291
|
};
|
|
292
|
+
lineEndings?: LineEndings$1;
|
|
293
|
+
/** Degrees clockwise about the middle of the box around the upright points; 0 when upright. */
|
|
294
|
+
rotation: number;
|
|
295
|
+
}
|
|
296
|
+
/** A polygon (`closed`) or polyline: its vertices upright, and a polyline's endings. */
|
|
297
|
+
interface PolyShape {
|
|
298
|
+
kind: 'poly';
|
|
299
|
+
vertices: Point[];
|
|
300
|
+
closed: boolean;
|
|
301
|
+
lineEndings?: LineEndings$1;
|
|
302
|
+
/** A measurement's caption center, upright with the vertices; `null` places it automatically. */
|
|
303
|
+
captionCenter?: Point | null;
|
|
304
|
+
/** Degrees clockwise about the middle of the box around the upright points; 0 when upright. */
|
|
305
|
+
rotation: number;
|
|
306
|
+
}
|
|
307
|
+
/** Ink: its strokes upright. */
|
|
308
|
+
interface InkShape {
|
|
309
|
+
kind: 'ink';
|
|
310
|
+
inkList: Point[][];
|
|
311
|
+
/** Degrees clockwise about the middle of the box around the upright points; 0 when upright. */
|
|
312
|
+
rotation: number;
|
|
313
|
+
}
|
|
314
|
+
/** A points family record's shape. */
|
|
315
|
+
type PointsShape = LineShape | PolyShape | InkShape;
|
|
316
|
+
/** A line's or polyline's endings; none for an annotation that has none. */
|
|
317
|
+
declare const lineEndingsOf: (annotation: Annotation) => LineEndings$1;
|
|
318
|
+
/** Where the points are drawn: the upright ones turned by `rotation`. The same lists for the same shape. */
|
|
319
|
+
declare function drawnStrokesOf(shape: PointsShape): Point[][];
|
|
320
|
+
/** Miter limit shared by the bounds math and the SVG renderer (`stroke-miterlimit`),
|
|
321
|
+
* so the computed box and the drawn stroke always agree on where a sharp join
|
|
322
|
+
* bevels instead of spiking. 10 = the PDF default (also what the baked /AP uses). */
|
|
323
|
+
declare const MITER_LIMIT = 10;
|
|
324
|
+
/** The points family: points kept upright and the turn that draws them. */
|
|
325
|
+
declare const pointsFamily: ShapeFamily<PointsShape>;
|
|
326
|
+
//#endregion
|
|
327
|
+
//#region src/shapes/quads.d.ts
|
|
328
|
+
/** A quads family record's shape: its text's quads. */
|
|
329
|
+
interface QuadsShape {
|
|
330
|
+
kind: 'quads';
|
|
331
|
+
quadPoints: Quad$1[];
|
|
31
332
|
}
|
|
32
|
-
/** Interaction gate for a concrete annotation: widget kinds ignore `readOnly`
|
|
33
|
-
* (ISO 32000 — a ReadOnly form field must still be movable by a form designer;
|
|
34
|
-
* the form-filling layer enforces field ReadOnly itself). */
|
|
35
|
-
declare const annotInteractive: (a: FlagBearer) => boolean;
|
|
36
333
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* the record. One predicate for hit-test, chrome, and props alike, so a
|
|
40
|
-
* record you may not edit renders and behaves exactly like a locked one.
|
|
334
|
+
* The quads family: marks bound to their text. They move with a selection,
|
|
335
|
+
* but no gesture turns, scales or drags them, and they have no turned box.
|
|
41
336
|
*/
|
|
42
|
-
declare const
|
|
43
|
-
/** Deletion — the delete half of the authority split (a narrowed grant can
|
|
44
|
-
* allow update but not delete, or vice versa). Flags gate like transforms. */
|
|
45
|
-
declare const annotDeletable: (a: FlagBearer) => boolean;
|
|
46
|
-
/** `/Contents` text edits — the contents counterpart of `locked`. */
|
|
47
|
-
declare const annotContentsEditable: (a: FlagBearer) => boolean;
|
|
337
|
+
declare const quadsFamily: ShapeFamily<QuadsShape>;
|
|
48
338
|
//#endregion
|
|
49
|
-
//#region src/
|
|
339
|
+
//#region src/shapes/text-box.d.ts
|
|
340
|
+
type FreeTextAnnotation = Extract<Annotation, {
|
|
341
|
+
subtype: 'free-text';
|
|
342
|
+
}>;
|
|
343
|
+
/** A callout's line: its tip, its knee when it bends, and where it meets the box. */
|
|
344
|
+
type CalloutLine = NonNullable<FreeTextAnnotation['calloutLine']>;
|
|
345
|
+
/** A free text's shape: the engine's box, turn, and a callout's line. */
|
|
346
|
+
interface TextBoxShape extends TurnedBox {
|
|
347
|
+
kind: 'text-box';
|
|
348
|
+
/** A callout's line; `null` for a plain text box. */
|
|
349
|
+
calloutLine: CalloutLine | null;
|
|
350
|
+
/** The ending at a callout's tip. */
|
|
351
|
+
lineEnding: LineEnding$1 | null;
|
|
352
|
+
}
|
|
50
353
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* the
|
|
354
|
+
* Where a callout's line meets its box: the middle of the side `toward` (the
|
|
355
|
+
* knee, else the tip) lies beyond, chosen by which way it is farther from the
|
|
356
|
+
* box's middle, across or up and down. A turned box decides in its own frame,
|
|
357
|
+
* and the point lands on the turned side, the one the page shows. The
|
|
358
|
+
* engine's rule, in page space.
|
|
55
359
|
*/
|
|
56
|
-
|
|
360
|
+
declare function calloutEnd(box: Rect, toward: Point, rotation?: number): Point;
|
|
361
|
+
/**
|
|
362
|
+
* The text box family: a free text's box and turn, and a callout's line.
|
|
363
|
+
* Only a plain box turns; a callout's box keeps the turn it was made with,
|
|
364
|
+
* and a selection outlines everything it paints, upright.
|
|
365
|
+
*/
|
|
366
|
+
declare const textBoxFamily: ShapeFamily<TextBoxShape>;
|
|
367
|
+
/**
|
|
368
|
+
* The text plate inset of a free-text box: twice the border width. The plate
|
|
369
|
+
* — where text lays out, clips and scrolls — is the box deflated by this on
|
|
370
|
+
* every side: the ink band and an equal breathing band, so the text never
|
|
371
|
+
* touches the stroke. Acrobat's rule, measured 1–12 pt on plain boxes and
|
|
372
|
+
* 1–7 pt on callouts; the engine's `FreeTextPlate` is the same formula, so
|
|
373
|
+
* the live editor sits exactly where the baked text lands. Acrobat's thinnest
|
|
374
|
+
* border is 1 pt; a width of 0 is ours alone and gives no inset (the plate is
|
|
375
|
+
* the box).
|
|
376
|
+
*/
|
|
377
|
+
declare function textPlateInset(strokeWidth: number): number;
|
|
378
|
+
//#endregion
|
|
379
|
+
//#region src/types.d.ts
|
|
57
380
|
type Rect = Rect$1;
|
|
58
|
-
/** Four POSITIONAL content-space points — selection chrome / OBB corners.
|
|
59
|
-
* Text-markup geometry uses the corner-NAMED {@link TextQuad} instead. */
|
|
60
|
-
type Quad = [Vec, Vec, Vec, Vec];
|
|
61
381
|
/**
|
|
62
382
|
* Where a text-edit annotation (caret / replace-text) anchors: the boundary
|
|
63
|
-
* glyph's oriented cell plus the
|
|
64
|
-
* (+1 = toward
|
|
65
|
-
* from geometry).
|
|
383
|
+
* glyph's oriented cell plus the reading direction along its baseline
|
|
384
|
+
* (+1 = toward the right end, −1 = toward the left end — sequence-derived,
|
|
385
|
+
* never inferred from geometry).
|
|
66
386
|
*/
|
|
67
387
|
interface TextEndAnchor {
|
|
68
|
-
glyphQuad:
|
|
388
|
+
glyphQuad: Quad$1;
|
|
69
389
|
advance: 1 | -1;
|
|
70
390
|
}
|
|
71
391
|
type Id = string;
|
|
@@ -73,128 +393,80 @@ type Cursor = string;
|
|
|
73
393
|
type PolySubtype = 'polygon' | 'polyline';
|
|
74
394
|
/**
|
|
75
395
|
* The per-page view environment the screen-anchor projection consumes:
|
|
76
|
-
* `zoom` — the page's zoom
|
|
396
|
+
* `zoom` — the page's zoom relative to its 100% baseline (dimensionless;
|
|
77
397
|
* 1 = Acrobat's 100% = `viewUnitsPerPoint × userUnit` view px per point) —
|
|
78
|
-
* and the
|
|
79
|
-
* Deliberately
|
|
80
|
-
* 100%-zoom size", a statement about zoom
|
|
81
|
-
*
|
|
398
|
+
* and the total display rotation (document /Rotate + view rotation).
|
|
399
|
+
* Deliberately not a px-per-point scale: `noZoom` means "hold the body at its
|
|
400
|
+
* 100%-zoom size", a statement about zoom; a units conversion here would
|
|
401
|
+
* shrink bodies at 100%. Per-event / per-call context (the
|
|
82
402
|
* `pageBox` pattern) — never stored on the model; the pointer drafts capture
|
|
83
|
-
* it at
|
|
403
|
+
* it at down so anchored gestures project and commit with the view they
|
|
84
404
|
* started under. See anchor.ts.
|
|
85
405
|
*/
|
|
86
406
|
interface ViewEnv {
|
|
87
407
|
zoom: number;
|
|
88
408
|
rotation: PageRotation;
|
|
89
409
|
}
|
|
90
|
-
type Subtype = 'highlight' | 'underline' | 'squiggly' | 'strikeout' | 'square' | 'circle' | 'line' | 'polygon' | 'polyline' | 'caret' | 'ink' | 'stamp' | 'text' | 'file-attachment' | 'redact' | 'link' | (string & {});
|
|
91
|
-
/**
|
|
92
|
-
* Content-space geometry — the ONE thing hit-testing, editing, and rendering work
|
|
93
|
-
* on. A small closed union covers every kind: shapes (rect/ellipse), line,
|
|
94
|
-
* polygon/polyline (poly), text markup (quads), and caret.
|
|
95
|
-
*/
|
|
96
410
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
* point where the leader meets the text box (the third `/CL` point) is NEVER
|
|
100
|
-
* stored — it is DERIVED from the box + the knee (see `calloutConnection`), so it
|
|
101
|
-
* can't drift when the box or knee moves. Content space (y-down).
|
|
411
|
+
* An annotation kind's name (`kinds/`): its PDF subtype, a widget's field
|
|
412
|
+
* family (`widget-text`…), or a free text's callout (`free-text-callout`).
|
|
102
413
|
*/
|
|
103
|
-
|
|
104
|
-
tip: Vec;
|
|
105
|
-
knee?: Vec;
|
|
106
|
-
ending: LineEnding;
|
|
107
|
-
}
|
|
414
|
+
type KindName = 'highlight' | 'underline' | 'squiggly' | 'strikeout' | 'square' | 'circle' | 'line' | 'polygon' | 'polyline' | 'caret' | 'ink' | 'stamp' | 'text' | 'file-attachment' | 'redact' | 'link' | (string & {});
|
|
108
415
|
/**
|
|
109
|
-
*
|
|
110
|
-
* the
|
|
111
|
-
* the
|
|
416
|
+
* An annotation's shape: what hit-testing, gestures and drawing work on, read
|
|
417
|
+
* off the annotation by its kind's family (`shapeOf`). One arm per family,
|
|
418
|
+
* each the engine's own fields
|
|
419
|
+
* ({@link BoxShape}, {@link TextBoxShape}, {@link PointsShape},
|
|
420
|
+
* {@link QuadsShape}, {@link CaretShape}).
|
|
112
421
|
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
* user applied since authoring. It lets EmbedPDF reconstruct an oriented
|
|
120
|
-
* selection box (`obbFromTheta`) and offer reset-to-0; it is inert for
|
|
121
|
-
* rendering (PDFium ignores a lone `Rotation` with no `UnrotatedRect`).
|
|
122
|
-
*/
|
|
123
|
-
type Geom = {
|
|
124
|
-
t: 'rect';
|
|
125
|
-
rect: Rect;
|
|
126
|
-
ellipse: boolean;
|
|
127
|
-
rot?: number;
|
|
128
|
-
} | {
|
|
129
|
-
t: 'line';
|
|
130
|
-
a: Vec;
|
|
131
|
-
b: Vec;
|
|
132
|
-
ends?: LineEndings;
|
|
133
|
-
rot?: number;
|
|
134
|
-
} | {
|
|
135
|
-
t: 'poly';
|
|
136
|
-
points: Vec[];
|
|
137
|
-
closed: boolean;
|
|
138
|
-
ends?: LineEndings;
|
|
139
|
-
rot?: number;
|
|
140
|
-
} | {
|
|
141
|
-
t: 'quads';
|
|
142
|
-
quads: TextQuad$1[];
|
|
143
|
-
} | {
|
|
144
|
-
t: 'caret';
|
|
145
|
-
rect: Rect;
|
|
146
|
-
rot?: number;
|
|
147
|
-
} | {
|
|
148
|
-
t: 'ink';
|
|
149
|
-
strokes: Vec[][];
|
|
150
|
-
rot?: number;
|
|
151
|
-
} | {
|
|
152
|
-
t: 'text';
|
|
153
|
-
rect: Rect;
|
|
154
|
-
callout?: Callout;
|
|
155
|
-
rot?: number;
|
|
156
|
-
};
|
|
422
|
+
* Rotation is degrees clockwise in page space, normalized `[0,360)`, and
|
|
423
|
+
* works the same way for every family that turns: the shape is kept upright
|
|
424
|
+
* (a box, or points), and `rotation` turns it about its middle. The engine
|
|
425
|
+
* works out `/Rect` around the turned drawing, so PDFium bakes a portable `/AP`.
|
|
426
|
+
*/
|
|
427
|
+
type Shape = BoxShape | PointsShape | QuadsShape | CaretShape | TextBoxShape;
|
|
157
428
|
/**
|
|
158
|
-
* How
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
* (`
|
|
162
|
-
*
|
|
429
|
+
* How an annotation is drawn, by the engine's field names: its colours, its
|
|
430
|
+
* stroke and its border, with its kind's fill-ins (a highlight strokes
|
|
431
|
+
* nothing, a caret draws 1 pt). A view its kind works out from the
|
|
432
|
+
* annotation (`styleOf`, `kinds/styles.ts`) for drawing, bounding and
|
|
433
|
+
* hit-testing: nothing is written back through it.
|
|
163
434
|
*/
|
|
164
|
-
type Border = {
|
|
165
|
-
kind: 'solid';
|
|
166
|
-
} | {
|
|
167
|
-
kind: 'dashed';
|
|
168
|
-
dash: number[];
|
|
169
|
-
} | {
|
|
170
|
-
kind: 'cloudy';
|
|
171
|
-
intensity: number;
|
|
172
|
-
};
|
|
173
435
|
interface Style {
|
|
174
|
-
/**
|
|
175
|
-
color:
|
|
176
|
-
/**
|
|
177
|
-
interiorColor:
|
|
436
|
+
/** The stroke for a drawn kind, a markup's colour, a free text's border. */
|
|
437
|
+
color: Color;
|
|
438
|
+
/** The fill; `null` when the annotation has none. */
|
|
439
|
+
interiorColor: Color | null;
|
|
178
440
|
strokeWidth: number;
|
|
179
441
|
opacity: number;
|
|
180
|
-
/** Effective blend mode of the annotation's normal appearance. */
|
|
181
442
|
blendMode: BlendMode$1;
|
|
182
|
-
|
|
183
|
-
border
|
|
443
|
+
borderStyle: AnnotationBorderStyle;
|
|
444
|
+
/** A dashed border's pattern; `null` draws the engine's default dash. */
|
|
445
|
+
dashArray: number[] | null;
|
|
446
|
+
/** A cloudy border's intensity; `null` without a cloud. A cloud wins over a dash. */
|
|
447
|
+
cloudyIntensity: number | null;
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* What a shape's bounds, hit test and drawing depend on besides the shape:
|
|
451
|
+
* how wide its stroke is, and a cloud's intensity. A {@link Style} is one.
|
|
452
|
+
*/
|
|
453
|
+
interface Stroke {
|
|
454
|
+
strokeWidth: number;
|
|
455
|
+
cloudyIntensity?: number | null;
|
|
184
456
|
}
|
|
185
457
|
type TextAlign = 'left' | 'center' | 'right';
|
|
186
458
|
/**
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
* `
|
|
459
|
+
* How an annotation's text is set, by the engine's field names: its font,
|
|
460
|
+
* size, colour and alignment, and a free text's bold, italic and underline.
|
|
461
|
+
* A view its kind works out from the annotation (`textOf`,
|
|
462
|
+
* `kinds/texts.ts`): nothing is written back through it.
|
|
191
463
|
*/
|
|
192
464
|
interface TextStyle {
|
|
193
465
|
/** A PDF standard font name or a registered font key. */
|
|
194
466
|
fontFamily: string;
|
|
195
|
-
/**
|
|
467
|
+
/** Page units (PDF points); 0 fits a form field's or a redaction label's box. */
|
|
196
468
|
fontSize: number;
|
|
197
|
-
fontColor:
|
|
469
|
+
fontColor: Color;
|
|
198
470
|
textAlign: TextAlign;
|
|
199
471
|
/**
|
|
200
472
|
* The rich body's formatting (free text only): bold = body weight ≥ 600,
|
|
@@ -207,81 +479,40 @@ interface TextStyle {
|
|
|
207
479
|
underline?: boolean;
|
|
208
480
|
}
|
|
209
481
|
/**
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
|
|
482
|
+
* Engine fields by name, as a create or an update states them: a tool's
|
|
483
|
+
* defaults (a draft without its shape), or what a selection edit writes to
|
|
484
|
+
* each member. The kind table's {@link AnnotationProperty} lists say which a style panel edits.
|
|
485
|
+
*/
|
|
486
|
+
type FieldValues = Readonly<Record<string, unknown>>;
|
|
487
|
+
/**
|
|
488
|
+
* One annotation as the core works on it: the engine's record, and how it is
|
|
489
|
+
* drawn right now. The record is the only data: its ref, page, kind and
|
|
490
|
+
* relationships are read off it (`refOf`, `kindOf`, `irtOf`, `groupOf`), so
|
|
491
|
+
* is its shape (`shapeOf`), and an edit writes engine fields back
|
|
492
|
+
* (`withShape`, `withValues`; record/).
|
|
214
493
|
*/
|
|
215
|
-
interface
|
|
216
|
-
/** `/LE` endings (line / polyline). */
|
|
217
|
-
lineEndings: LineEndings;
|
|
494
|
+
interface ModelAnnotation {
|
|
218
495
|
/**
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
* value. Valid values are the `options` of the kind's `icon` PropSpec.
|
|
496
|
+
* The record's key: `annotationKey(annotation.ref)`, for life. A record
|
|
497
|
+
* this session creates has its final ref from the start: the object number
|
|
498
|
+
* its create names.
|
|
223
499
|
*/
|
|
224
|
-
|
|
500
|
+
id: Id;
|
|
225
501
|
/**
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
* link kind it is the annotation's OWN target (`/A`); on every other
|
|
229
|
-
* linkable kind it is the target of the ATTACHED link child(ren) —
|
|
230
|
-
* grouped `/Link` annotations the model folds into their parent (the
|
|
231
|
-
* serialization the PDF spec forces, since only Link annotations are
|
|
232
|
-
* clickable). Writing it creates/retargets/deletes those children through
|
|
233
|
-
* the ONE `syncLink` seam.
|
|
502
|
+
* A record this session created that the engine hasn't written yet: it
|
|
503
|
+
* has its ref, but no raster of its appearance.
|
|
234
504
|
*/
|
|
235
|
-
|
|
236
|
-
}
|
|
237
|
-
type PropKey = keyof AnnotationProps;
|
|
238
|
-
/**
|
|
239
|
-
* What a committed edit CHANGED — carried on the `patch` effect so the shell
|
|
240
|
-
* emits exactly that intent (repository `toScopedPatch`) instead of
|
|
241
|
-
* reconstructing a full projection. `geometry` covers every gesture commit
|
|
242
|
-
* (move/resize/rotate/vertex edit); `props` forwards the user's patch keys
|
|
243
|
-
* verbatim. Text content never rides this effect (the debounced text-edit
|
|
244
|
-
* write owns `contents`).
|
|
245
|
-
*/
|
|
246
|
-
type PatchScope = {
|
|
247
|
-
kind: 'geometry';
|
|
248
|
-
} | {
|
|
249
|
-
kind: 'props';
|
|
250
|
-
keys: PropKey[];
|
|
251
|
-
};
|
|
252
|
-
/** A partial property write. `lineEndings` merges per side (set just `end`
|
|
253
|
-
* without knowing `start`); every other key overwrites. */
|
|
254
|
-
type AnnotationPropsPatch = { [K in PropKey]?: K extends 'lineEndings' ? Partial<LineEndings> : AnnotationProps[K]; };
|
|
255
|
-
interface Annot {
|
|
256
|
-
id: Id;
|
|
257
|
-
ref: AnnotationRef | null;
|
|
258
|
-
pon: PageObjectNumber;
|
|
259
|
-
subtype: Subtype;
|
|
260
|
-
geom: Geom;
|
|
261
|
-
style: Style;
|
|
262
|
-
/** Text styling — present only for text-editable kinds (free text). Like
|
|
263
|
-
* `style`, a content-space projection of `data`, editable via `setProps`. */
|
|
264
|
-
text?: TextStyle;
|
|
265
|
-
/** Redaction label (`/OverlayText` + `/Repeat`) — redact kind only. A
|
|
266
|
-
* projection of `data` like `text`; the hover preview scene draws it. */
|
|
267
|
-
label?: {
|
|
268
|
-
text: string;
|
|
269
|
-
repeat: boolean;
|
|
270
|
-
};
|
|
271
|
-
/** `/Name` icon — present only for icon kinds (text note, file attachment).
|
|
272
|
-
* Like `style`, a projection of `data`, editable via `setProps`. */
|
|
273
|
-
icon?: string;
|
|
505
|
+
unconfirmed?: true;
|
|
274
506
|
/**
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
507
|
+
* How the record renders: `baked` blits the engine's appearance raster,
|
|
508
|
+
* `vector` draws it live from its geometry and style. The core sets
|
|
509
|
+
* `vector` when an edit makes the raster stale (a resize, a restyle,
|
|
510
|
+
* typing); a move keeps the raster. The plugin decides it for confirmed
|
|
511
|
+
* records: this session's edits stay live, another session's are baked.
|
|
280
512
|
*/
|
|
281
|
-
flags: AnnotationFlags$1;
|
|
282
513
|
source: 'baked' | 'vector';
|
|
283
514
|
/**
|
|
284
|
-
*
|
|
515
|
+
* Page-space box of the engine appearance raster (the AP `/Rect`), set when
|
|
285
516
|
* the annotation is derived from a DTO. While `source === 'baked'` the renderer
|
|
286
517
|
* blits the engine bitmap into this box; a move translates it (a rigid shift
|
|
287
518
|
* keeps the raster valid), so the bitmap rides along without re-rendering.
|
|
@@ -289,72 +520,58 @@ interface Annot {
|
|
|
289
520
|
*/
|
|
290
521
|
apBox?: Rect;
|
|
291
522
|
/**
|
|
292
|
-
* Rotation (deg, CW) that was
|
|
293
|
-
* when the engine rendered this appearance rotation-free (
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
523
|
+
* Rotation (deg, CW) that was stripped from the baked raster — present only
|
|
524
|
+
* when the engine rendered this appearance rotation-free (`appearanceTurnOf`:
|
|
525
|
+
* a box kind drawn turned, inside its turned box; `apBox` is then its `box`).
|
|
526
|
+
* The blit re-applies it as a view transform about the box centre. Vertex
|
|
527
|
+
* kinds pre-rotate their geometry, so this stays unset there and their
|
|
528
|
+
* rasters blit untransformed.
|
|
298
529
|
*/
|
|
299
530
|
apRot?: number;
|
|
300
531
|
/**
|
|
301
|
-
*
|
|
532
|
+
* The version of the engine's picture of it (absent ≡ 0). The picture a baked
|
|
302
533
|
* annotation shows depends on exactly this and the render scale — never on
|
|
303
534
|
* position (`apBox` translates the blit) or rotation (`apRot` transforms it) —
|
|
304
|
-
* so the shell re-fetches
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
* remote edit folding in. A move or rotate leaves it untouched: the old raster
|
|
308
|
-
* is still pixel-exact, so those cost zero re-renders.
|
|
535
|
+
* so the shell re-fetches pictures precisely when it changes. Owned by the
|
|
536
|
+
* plugin's confirmed records, which advance it when the engine reports a
|
|
537
|
+
* re-baked appearance; the core only reads it.
|
|
309
538
|
*/
|
|
310
|
-
|
|
539
|
+
pictureVersion?: number;
|
|
311
540
|
/**
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
*
|
|
541
|
+
* A lent record's live drawing, from its lender (a form widget, drawn by the
|
|
542
|
+
* form's painter): the record drawn upright in `box`, in page space. It
|
|
543
|
+
* gives a kind with no live drawing of its own one (`drawsLive`), so the
|
|
544
|
+
* record draws live while a gesture reshapes it, as a square does.
|
|
545
|
+
*/
|
|
546
|
+
painter?: (box: Rect) => readonly SceneNode[];
|
|
547
|
+
/**
|
|
548
|
+
* This session's authority over this record (see permissions.md), set by the
|
|
549
|
+
* plugin from the security service; the core only reads it. Fused into
|
|
315
550
|
* `annotTransformable`/`annotDeletable`, so a record the session may not
|
|
316
551
|
* edit renders and behaves exactly like a `locked` one (bare outline, no
|
|
317
|
-
* handles, no drag). Absent = unstamped (a
|
|
318
|
-
* engine, tests) and treated as allowed — the client gate
|
|
319
|
-
* that keeps the UI truthful; the engine independently enforces.
|
|
552
|
+
* handles, no drag). Absent = unstamped (a record created in this session,
|
|
553
|
+
* a wildcard local engine, tests) and treated as allowed — the client gate
|
|
554
|
+
* is a courtesy that keeps the UI truthful; the engine independently enforces.
|
|
320
555
|
*/
|
|
321
556
|
authority?: {
|
|
322
557
|
update: boolean;
|
|
323
558
|
delete: boolean;
|
|
324
559
|
};
|
|
325
560
|
/**
|
|
326
|
-
* The
|
|
327
|
-
*
|
|
328
|
-
*
|
|
329
|
-
*
|
|
330
|
-
*
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
/** Normalized PDF `/IT` for intent-bearing annotations authored before a DTO exists. */
|
|
334
|
-
intent?: CaretIntent | StrikeoutIntent | InkIntent;
|
|
335
|
-
/**
|
|
336
|
-
* The link KIND's own `/A` target (see {@link AnnotationProps.link}) —
|
|
337
|
-
* present only on `subtype: 'link'`. Every OTHER kind's link is an
|
|
338
|
-
* attached child annotation in the substrate, read through the `linkOf`
|
|
339
|
-
* lens and materialized by the shell's `syncLink` reconciler; parents
|
|
340
|
-
* store nothing.
|
|
561
|
+
* The annotation's data in the engine's shape: what the engine will read
|
|
562
|
+
* back once this session's writes land. A confirmed record's is the
|
|
563
|
+
* engine's own read; a record this session created reads as its create
|
|
564
|
+
* writes it (`newRecord`); an edit merges the fields it changed, and
|
|
565
|
+
* `update` applies them as the engine will, a drawn kind's `rect`
|
|
566
|
+
* included (`record/written.ts`). Its attribution waits for the engine's
|
|
567
|
+
* answer.
|
|
341
568
|
*/
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Relationship to another annotation. `irt` ("in reply to") links a child to a
|
|
345
|
-
* parent — a reply in a comment thread, or a caret bound to its strikeout in a
|
|
346
|
-
* replace-text pair. `group` ties a set into one composite unit (created and,
|
|
347
|
-
* typically, deleted together). Both are unused until comments / replace-text
|
|
348
|
-
* land, but the field lives here from the start so select/delete/persistence
|
|
349
|
-
* never have to be retrofitted around it.
|
|
350
|
-
*/
|
|
351
|
-
irt?: Id;
|
|
352
|
-
group?: string;
|
|
569
|
+
annotation: Annotation;
|
|
353
570
|
}
|
|
354
571
|
/** A draggable handle: a resize corner/edge (rect) or a vertex (line/poly). */
|
|
355
572
|
interface Handle {
|
|
356
573
|
id: string;
|
|
357
|
-
at:
|
|
574
|
+
at: Point$1;
|
|
358
575
|
cursor: Cursor;
|
|
359
576
|
}
|
|
360
577
|
/** An alignment guide produced by move-snapping: a vertical (`axis: 'x'`) or
|
|
@@ -365,198 +582,297 @@ interface Guide {
|
|
|
365
582
|
lo: number;
|
|
366
583
|
hi: number;
|
|
367
584
|
}
|
|
368
|
-
/**
|
|
369
|
-
*
|
|
585
|
+
/**
|
|
586
|
+
* Snapping: to other annotations and the page while moving, and to angles
|
|
587
|
+
* while turning. The plugin keeps it in its settings and hands it in with
|
|
588
|
+
* `setSnap`.
|
|
589
|
+
*/
|
|
370
590
|
interface SnapSettings {
|
|
371
|
-
/**
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
|
|
591
|
+
/** Snap to the edges and centres of other annotations and of the page while moving. */
|
|
592
|
+
readonly alignment: boolean;
|
|
593
|
+
/**
|
|
594
|
+
* How close a move comes before it snaps, in screen pixels: each pointer
|
|
595
|
+
* sample converts it by its `scale`. Without one it is in page units.
|
|
596
|
+
*/
|
|
597
|
+
readonly alignmentThreshold: number;
|
|
598
|
+
/** Snap a turn onto `rotationAngles`. */
|
|
599
|
+
readonly rotation: boolean;
|
|
600
|
+
/** The angles a turn snaps to, in degrees clockwise. */
|
|
601
|
+
readonly rotationAngles: readonly number[];
|
|
602
|
+
/** How close a turn comes before it snaps, in degrees. */
|
|
603
|
+
readonly rotationThreshold: number;
|
|
380
604
|
}
|
|
381
605
|
/**
|
|
382
606
|
* The `defaults` key a creation draft resolves its props from — the authoring
|
|
383
|
-
*
|
|
607
|
+
* tool that started it, which may differ from the PDF `subtype`. Two tools can
|
|
384
608
|
* share a subtype but carry distinct defaults (an "arrow" is a `line` with an
|
|
385
609
|
* arrowhead default); the preset keeps them apart. Absent → fall back to
|
|
386
610
|
* `subtype` (a headless / programmatic caller that isn't tool-driven), so the
|
|
387
|
-
* built-in tools where preset === subtype
|
|
611
|
+
* built-in tools where preset === subtype resolve from their subtype.
|
|
388
612
|
*/
|
|
389
613
|
type Draft = {
|
|
390
|
-
|
|
391
|
-
subtype:
|
|
614
|
+
kind: 'create-rect';
|
|
615
|
+
subtype: KindName;
|
|
392
616
|
preset?: string;
|
|
393
|
-
|
|
394
|
-
from:
|
|
395
|
-
to:
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
* page), so the commit counter-rotates against what the author SAW even
|
|
617
|
+
page: PageRef;
|
|
618
|
+
from: Point$1;
|
|
619
|
+
to: Point$1;
|
|
620
|
+
/** Display rotation + upright policy captured at down (the gesture's home
|
|
621
|
+
* page), so the commit counter-rotates against what the author saw even
|
|
399
622
|
* if the up sample resolves elsewhere. See {@link PointerInput}. */
|
|
400
623
|
displayRotation?: PageRotation;
|
|
401
624
|
upright?: boolean;
|
|
402
|
-
/** The tool's click-create policy, captured at
|
|
625
|
+
/** The tool's click-create policy, captured at down like `upright`. */
|
|
403
626
|
clickCreate?: ClickCreate | false;
|
|
404
|
-
/** The tool's `/F` seed, captured at
|
|
627
|
+
/** The tool's `/F` seed, captured at down like `upright` — merged over
|
|
405
628
|
* {@link DRAWN_FLAGS} at commit (a note tool sets noZoom/noRotate). */
|
|
406
629
|
flags?: Partial<AnnotationFlags$1>;
|
|
407
630
|
} | {
|
|
408
|
-
|
|
409
|
-
|
|
631
|
+
kind: 'create-distance';
|
|
632
|
+
step: 'endpoints' | 'offset';
|
|
633
|
+
subtype: 'line';
|
|
634
|
+
preset: string;
|
|
635
|
+
page: PageRef;
|
|
636
|
+
from: Point$1;
|
|
637
|
+
to: Point$1;
|
|
638
|
+
measure: DistanceAppearance;
|
|
639
|
+
flags?: Partial<AnnotationFlags$1>;
|
|
640
|
+
} | {
|
|
641
|
+
kind: 'create-line';
|
|
642
|
+
measure?: MeasurementAppearance;
|
|
643
|
+
capture?: string;
|
|
644
|
+
subtype: KindName;
|
|
410
645
|
preset?: string;
|
|
411
|
-
|
|
412
|
-
from:
|
|
413
|
-
to:
|
|
414
|
-
/**
|
|
646
|
+
page: PageRef;
|
|
647
|
+
from: Point$1;
|
|
648
|
+
to: Point$1;
|
|
649
|
+
/** Display rotation + upright policy captured at down (see the rect
|
|
650
|
+
* draft): an upright tool's click lays its line as the author saw the page. */
|
|
651
|
+
displayRotation?: PageRotation;
|
|
652
|
+
upright?: boolean;
|
|
653
|
+
/** The tool's click-create policy, captured at down like `upright`. */
|
|
415
654
|
clickCreate?: ClickCreate | false;
|
|
416
|
-
/** The tool's `/F` seed, captured at
|
|
655
|
+
/** The tool's `/F` seed, captured at down (see the rect draft). */
|
|
417
656
|
flags?: Partial<AnnotationFlags$1>;
|
|
418
657
|
} | {
|
|
419
|
-
|
|
420
|
-
|
|
658
|
+
kind: 'create-poly';
|
|
659
|
+
measure?: ShapeMeasurementAppearance;
|
|
660
|
+
subtype: KindName;
|
|
421
661
|
preset?: string;
|
|
422
|
-
|
|
423
|
-
points:
|
|
424
|
-
|
|
662
|
+
page: PageRef;
|
|
663
|
+
points: Point$1[];
|
|
664
|
+
current: Point$1;
|
|
425
665
|
closed: boolean;
|
|
426
|
-
/** The tool's `/F` seed, captured at
|
|
666
|
+
/** The tool's `/F` seed, captured at down (see the rect draft). */
|
|
427
667
|
flags?: Partial<AnnotationFlags$1>;
|
|
428
668
|
} | {
|
|
429
|
-
|
|
430
|
-
subtype:
|
|
669
|
+
kind: 'create-ink';
|
|
670
|
+
subtype: KindName;
|
|
431
671
|
preset?: string;
|
|
432
|
-
|
|
433
|
-
strokes:
|
|
672
|
+
page: PageRef;
|
|
673
|
+
strokes: Point$1[][];
|
|
434
674
|
intent?: InkIntent;
|
|
435
|
-
/** The tool's `/F` seed, captured at
|
|
675
|
+
/** The tool's `/F` seed, captured at down (see the rect draft). */
|
|
436
676
|
flags?: Partial<AnnotationFlags$1>;
|
|
437
677
|
} | {
|
|
438
|
-
|
|
439
|
-
subtype:
|
|
678
|
+
kind: 'create-callout';
|
|
679
|
+
subtype: KindName;
|
|
440
680
|
preset?: string;
|
|
441
|
-
|
|
681
|
+
page: PageRef;
|
|
442
682
|
step: 'knee' | 'box';
|
|
443
|
-
tip:
|
|
444
|
-
knee?:
|
|
445
|
-
|
|
446
|
-
boxFrom?:
|
|
447
|
-
boxTo?:
|
|
448
|
-
/**
|
|
449
|
-
*
|
|
683
|
+
tip: Point$1;
|
|
684
|
+
knee?: Point$1;
|
|
685
|
+
current: Point$1;
|
|
686
|
+
boxFrom?: Point$1;
|
|
687
|
+
boxTo?: Point$1;
|
|
688
|
+
/** Home-page box captured at the tip click. The default text box slides
|
|
689
|
+
* fully inside it; a drag is already point-clamped and ignores this. */
|
|
690
|
+
pageBox?: Rect;
|
|
691
|
+
/** Display rotation + upright policy captured at the tip click (the
|
|
692
|
+
* gesture's home page) — the text box commits counter-rotated so it
|
|
450
693
|
* reads upright; the leader (tip/knee) is page-space and never turns.
|
|
451
694
|
* Same capture rule as the rect draft. */
|
|
452
695
|
displayRotation?: PageRotation;
|
|
453
696
|
upright?: boolean;
|
|
454
|
-
/** The tool's `/F` seed, captured at
|
|
697
|
+
/** The tool's `/F` seed, captured at down (see the rect draft). */
|
|
455
698
|
flags?: Partial<AnnotationFlags$1>;
|
|
456
699
|
} | {
|
|
457
|
-
|
|
700
|
+
kind: 'move';
|
|
458
701
|
ids: Id[];
|
|
459
|
-
start:
|
|
460
|
-
delta:
|
|
702
|
+
start: Point$1;
|
|
703
|
+
delta: Point$1;
|
|
461
704
|
guides: Guide[];
|
|
462
705
|
} | {
|
|
463
|
-
|
|
706
|
+
kind: 'handle';
|
|
464
707
|
id: Id;
|
|
465
708
|
handle: string;
|
|
466
|
-
base:
|
|
467
|
-
|
|
709
|
+
base: Shape;
|
|
710
|
+
current: Shape;
|
|
468
711
|
view?: ViewEnv;
|
|
469
712
|
} | {
|
|
470
|
-
|
|
713
|
+
kind: 'rotate';
|
|
471
714
|
ids: Id[];
|
|
472
|
-
pivot:
|
|
473
|
-
start:
|
|
474
|
-
|
|
715
|
+
pivot: Point$1;
|
|
716
|
+
start: Point$1;
|
|
717
|
+
current: Point$1;
|
|
475
718
|
free?: boolean;
|
|
476
719
|
view?: ViewEnv;
|
|
477
720
|
} | {
|
|
478
|
-
|
|
721
|
+
kind: 'group';
|
|
479
722
|
op: 'resize';
|
|
480
723
|
ids: Id[];
|
|
481
724
|
handle: string;
|
|
482
|
-
anchor:
|
|
725
|
+
anchor: Point$1;
|
|
483
726
|
base: Rect;
|
|
484
|
-
|
|
727
|
+
current: Rect;
|
|
485
728
|
view?: ViewEnv;
|
|
486
729
|
} | {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
730
|
+
kind: 'caption';
|
|
731
|
+
id: Id;
|
|
732
|
+
start: Point$1;
|
|
733
|
+
delta: Point$1;
|
|
734
|
+
} | {
|
|
735
|
+
kind: 'leader';
|
|
736
|
+
id: Id;
|
|
737
|
+
start: Point$1;
|
|
738
|
+
delta: number;
|
|
739
|
+
} | {
|
|
740
|
+
kind: 'marquee';
|
|
741
|
+
page: PageRef;
|
|
742
|
+
from: Point$1;
|
|
743
|
+
to: Point$1;
|
|
491
744
|
};
|
|
492
745
|
/** A live text-markup preview (the in-progress selection rendered as the markup it
|
|
493
746
|
* will become). Per page, since a selection can span pages. */
|
|
494
747
|
interface MarkupPreview {
|
|
495
|
-
subtype:
|
|
748
|
+
subtype: KindName;
|
|
496
749
|
/** Defaults key, distinct from subtype for presets such as replace-text. */
|
|
497
750
|
preset: string;
|
|
498
|
-
|
|
751
|
+
/** Keyed by `page.pageObjectNumber` (an internal lookup, not an address). */
|
|
752
|
+
byPage: Record<number, Quad$1[]>;
|
|
499
753
|
}
|
|
500
754
|
/** Anchor + affordance state for UI that controls an in-progress creation draft. */
|
|
755
|
+
/**
|
|
756
|
+
* A rotation in progress, for the badge that follows the pointer: the page
|
|
757
|
+
* it runs on, the pointer there (page space) and the selection's angle as the
|
|
758
|
+
* commit will apply it (degrees clockwise, whole degrees).
|
|
759
|
+
*/
|
|
760
|
+
interface RotationAnchor {
|
|
761
|
+
page: PageRef;
|
|
762
|
+
at: Point$1;
|
|
763
|
+
angle: number;
|
|
764
|
+
}
|
|
501
765
|
interface CreationDraftAnchor {
|
|
502
766
|
kind: 'poly';
|
|
503
767
|
subtype: PolySubtype;
|
|
504
|
-
|
|
768
|
+
page: PageRef;
|
|
505
769
|
bounds: Rect;
|
|
506
770
|
pointCount: number;
|
|
507
771
|
minPoints: number;
|
|
508
772
|
canFinish: boolean;
|
|
509
773
|
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
774
|
+
/**
|
|
775
|
+
* What the core owns: everything about the user's session that is not a
|
|
776
|
+
* record. `update` returns the next session; the plugin stores it.
|
|
777
|
+
*/
|
|
778
|
+
interface Session {
|
|
513
779
|
selected: Id[];
|
|
514
780
|
/** The annotation under the pointer (topmost hit), or null. View-model
|
|
515
781
|
* state like `selected` — drives hover affordances (a redaction mark's
|
|
516
|
-
* applied-look preview) purely from the scene. Updated on
|
|
782
|
+
* applied-look preview) purely from the scene. Updated on change only
|
|
517
783
|
* (enter/leave cadence, never per-move). */
|
|
518
784
|
hovered: Id | null;
|
|
785
|
+
/** The gesture in progress (a move, a resize, a shape being drawn), or null. */
|
|
519
786
|
draft: Draft | null;
|
|
520
787
|
/** Transient ghost of an in-progress markup selection (null when idle). */
|
|
521
788
|
preview: MarkupPreview | null;
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
*
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
/**
|
|
789
|
+
/**
|
|
790
|
+
* The object numbers this session holds for the records it creates next: a
|
|
791
|
+
* message's first new record takes the first, and so on. The plugin hands
|
|
792
|
+
* the session numbers from the document's pool before a message that may
|
|
793
|
+
* create (`newRecordsAtMost`).
|
|
794
|
+
*/
|
|
795
|
+
objectNumbers: readonly number[];
|
|
796
|
+
/**
|
|
797
|
+
* Each tool's defaults for the annotations it draws, keyed by the tool's
|
|
798
|
+
* preset: the engine fields its creates state. The engine's own defaults
|
|
799
|
+
* fill in what they leave out.
|
|
800
|
+
*/
|
|
801
|
+
defaults: Record<string, FieldValues>;
|
|
802
|
+
/**
|
|
803
|
+
* Extra clickable margin around what an annotation paints, in screen
|
|
804
|
+
* pixels: converted by the page's view scale, so a click reaches as far at
|
|
805
|
+
* every zoom. Bump it for touch.
|
|
806
|
+
*/
|
|
530
807
|
hitMargin: number;
|
|
531
|
-
/** The free-text annotation currently in
|
|
808
|
+
/** The free-text annotation currently in text-edit mode (its `contentEditable`
|
|
532
809
|
* is focused), or null. Distinct from `selected`: you select to move/resize,
|
|
533
810
|
* you edit to type. */
|
|
534
811
|
editing: Id | null;
|
|
535
812
|
/** Snapping behaviour (alignment guides + rotation). */
|
|
536
813
|
snap: SnapSettings;
|
|
814
|
+
/** Which annotations people may change by hand (editable.ts): the plugin sets it from its settings. */
|
|
815
|
+
editable: EditableKinds;
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* The records a gesture works on, read-only: what the engine confirmed with
|
|
819
|
+
* this session's pending changes on top. The plugin builds it; the core never
|
|
820
|
+
* stores a record.
|
|
821
|
+
*/
|
|
822
|
+
interface AnnotationView {
|
|
823
|
+
byId: Record<Id, ModelAnnotation>;
|
|
824
|
+
/** Paint order: the document's order, then records created in this session. */
|
|
825
|
+
order: Id[];
|
|
537
826
|
}
|
|
827
|
+
/** What every transition and read takes: the session composed with the records it works on. */
|
|
828
|
+
type Model = Session & AnnotationView;
|
|
538
829
|
/**
|
|
539
|
-
*
|
|
830
|
+
* What one message changed in the records. `put` holds new or changed records
|
|
831
|
+
* as the user produced them; `drop` holds the ids the user deleted. The plugin
|
|
832
|
+
* shows them until the engine writes that carry them settle.
|
|
833
|
+
*/
|
|
834
|
+
interface ChangeSet {
|
|
835
|
+
readonly put: readonly ModelAnnotation[];
|
|
836
|
+
readonly drop: readonly Id[];
|
|
837
|
+
/**
|
|
838
|
+
* What each changed record's change means to the engine, by id: the fields
|
|
839
|
+
* it changed, as `update` takes them. None for a new record (its create
|
|
840
|
+
* writes it) or for a change the engine keeps nothing of (a record handed
|
|
841
|
+
* to live rendering, a value set to what it was).
|
|
842
|
+
*/
|
|
843
|
+
readonly patches: Readonly<Record<Id, AnnotationPatch>>;
|
|
844
|
+
}
|
|
845
|
+
/** The result of one message: the next session, the records it changed, and the engine work to do. */
|
|
846
|
+
interface UpdateResult {
|
|
847
|
+
readonly session: Session;
|
|
848
|
+
readonly change: ChangeSet;
|
|
849
|
+
readonly effects: readonly Effect[];
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Selection-chrome geometry in content units — the grab zones and the knob
|
|
540
853
|
* stalk. The core is unit-agnostic and zoom-free: callers own the px→content
|
|
541
854
|
* conversion (settings are CSS px; divide by the page's view scale), so grab
|
|
542
855
|
* zones stay screen-constant across zoom.
|
|
543
856
|
*/
|
|
544
|
-
interface
|
|
857
|
+
interface ChromeGeometry {
|
|
545
858
|
/** Half-side of a resize/vertex handle's square grab zone. */
|
|
546
859
|
handleTol: number;
|
|
547
860
|
/** Half-side of the rotate knob's square grab zone. */
|
|
548
861
|
knobTol: number;
|
|
549
862
|
/** How far the rotate knob hangs off the selection edge. */
|
|
550
863
|
knobOffset: number;
|
|
864
|
+
/** `false`: the selection has no rotation handle to grab (it isn't drawn either). */
|
|
865
|
+
rotationHandle?: boolean;
|
|
551
866
|
}
|
|
552
867
|
interface PointerInput {
|
|
553
|
-
|
|
554
|
-
|
|
868
|
+
/** The page the sample resolved against (its own page-space frame). */
|
|
869
|
+
page: PageRef;
|
|
870
|
+
point: Point$1;
|
|
555
871
|
shift: boolean;
|
|
556
872
|
finish?: boolean;
|
|
557
873
|
/**
|
|
558
874
|
* The page's content box (`{0, 0, crop.width, crop.height}`) — when present,
|
|
559
|
-
* gestures are
|
|
875
|
+
* gestures are clamped to it: a move keeps the selection's bounds inside the
|
|
560
876
|
* page (sliding along the edge when the pointer overshoots), resize/create
|
|
561
877
|
* points pin to the edge. Annotations are page-bound; the pointer isn't.
|
|
562
878
|
*/
|
|
@@ -566,34 +882,41 @@ interface PointerInput {
|
|
|
566
882
|
* exactly like `pageBox` (the caller converts its CSS-px settings by the
|
|
567
883
|
* page's view scale at dispatch). Absent → `DEFAULT_CHROME_GEOM`.
|
|
568
884
|
*/
|
|
569
|
-
chrome?:
|
|
885
|
+
chrome?: ChromeGeometry;
|
|
570
886
|
/**
|
|
571
|
-
* The page's
|
|
572
|
-
* gesture — per-event environmental context like `pageBox`. A creation
|
|
887
|
+
* The page's total display rotation (document /Rotate + view rotation) at the
|
|
888
|
+
* gesture — per-event environmental context like `pageBox`. A creation down
|
|
573
889
|
* captures it on the draft (an `upright` commit counter-rotates against how
|
|
574
|
-
* the page was
|
|
890
|
+
* the page was displayed); edit gestures read it per sample, paired with
|
|
575
891
|
* `scale`, so screen-anchored (`noZoom`/`noRotate`) annotations hit-test and
|
|
576
|
-
* clamp at their
|
|
892
|
+
* clamp at their effective geometry. Page space itself never rotates.
|
|
577
893
|
*/
|
|
578
894
|
displayRotation?: PageRotation;
|
|
579
895
|
/**
|
|
580
|
-
*
|
|
896
|
+
* Screen pixels per page unit at the event: the page's view scale. A
|
|
897
|
+
* setting in screen pixels (`snap.alignmentThreshold`) is converted by it,
|
|
898
|
+
* so snapping feels the same at every zoom. Absent → 1.
|
|
899
|
+
*/
|
|
900
|
+
scale?: number;
|
|
901
|
+
/**
|
|
902
|
+
* The page's zoom relative to its 100% baseline at the event — the other
|
|
581
903
|
* half of the {@link ViewEnv} pair with `displayRotation` (dimensionless,
|
|
582
|
-
* `transform.zoom`;
|
|
904
|
+
* `transform.zoom`; not the px-per-point scale the caller uses for its
|
|
583
905
|
* CSS-px chrome conversion). Absent → 1 (headless callers; screen-anchored
|
|
584
906
|
* bodies then hit-test at rect size).
|
|
585
907
|
*/
|
|
586
908
|
zoom?: number;
|
|
587
909
|
/**
|
|
588
|
-
*
|
|
589
|
-
* `displayRotation` — the authoring
|
|
590
|
-
* caller (the core knows subtypes, not tools).
|
|
591
|
-
*
|
|
592
|
-
*
|
|
910
|
+
* Lay the created annotation out as the author sees the page at
|
|
911
|
+
* `displayRotation` — the authoring tool's `upright` policy, resolved by the
|
|
912
|
+
* caller (the core knows subtypes, not tools). A box counter-rotates so it
|
|
913
|
+
* reads upright (free text, stamps); a clicked line points the way its
|
|
914
|
+
* `ClickCreate` says on screen. A dragged line and a callout's leader
|
|
915
|
+
* follow the pointer and ignore it.
|
|
593
916
|
*/
|
|
594
917
|
upright?: boolean;
|
|
595
918
|
/**
|
|
596
|
-
* Ids invisible to hit-testing and marquee for
|
|
919
|
+
* Ids invisible to hit-testing and marquee for this event — per-event
|
|
597
920
|
* environmental context like `pageBox`. The caller (plugin shell) resolves
|
|
598
921
|
* its engaged Behaviors (form widgets under a fill tool render their own
|
|
599
922
|
* DOM and must not select/move), so the core stays behavior-agnostic.
|
|
@@ -601,17 +924,19 @@ interface PointerInput {
|
|
|
601
924
|
inert?: ReadonlySet<Id>;
|
|
602
925
|
}
|
|
603
926
|
/**
|
|
604
|
-
* What a bare
|
|
605
|
-
* tool
|
|
606
|
-
*
|
|
607
|
-
*
|
|
608
|
-
*
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
*
|
|
612
|
-
*
|
|
613
|
-
*
|
|
614
|
-
*
|
|
927
|
+
* What a bare click (a press-release under the drag threshold) creates for a
|
|
928
|
+
* tool, in PDF points:
|
|
929
|
+
* - a box, `width` × `height`, whose `anchor` sits on the click: its middle
|
|
930
|
+
* (`center`, the default) or its top-left corner (`top-left`: free text
|
|
931
|
+
* hangs where you'll type);
|
|
932
|
+
* - a line, `length` long, pointing `rotation` degrees clockwise from
|
|
933
|
+
* rightward, whose `anchor` sits on the click: its middle (`center`, the
|
|
934
|
+
* default), its start, or its end (an arrow's tip).
|
|
935
|
+
* Under an `upright` tool the anchor, the box's sides and the line's
|
|
936
|
+
* direction are as the person sees the turned page. Resolved from the tool
|
|
937
|
+
* by the caller and passed on the message: the core knows kinds, not tools.
|
|
938
|
+
* The same policy drives the commit, the tool's ghost and a form field's
|
|
939
|
+
* placement (see `resolveClickPlacement`).
|
|
615
940
|
*/
|
|
616
941
|
type ClickCreate = {
|
|
617
942
|
width: number;
|
|
@@ -619,20 +944,40 @@ type ClickCreate = {
|
|
|
619
944
|
anchor?: 'center' | 'top-left';
|
|
620
945
|
} | {
|
|
621
946
|
length: number;
|
|
622
|
-
|
|
947
|
+
rotation?: number;
|
|
948
|
+
anchor?: 'center' | 'start' | 'end';
|
|
623
949
|
};
|
|
624
|
-
|
|
625
|
-
|
|
950
|
+
/**
|
|
951
|
+
* Where a create gesture puts what it makes, on the page and slid inside it:
|
|
952
|
+
* a box and the turn an `upright` tool gives it (degrees clockwise, 0 for
|
|
953
|
+
* none), or a segment from `a` to `b`. A click's comes from the tool's
|
|
954
|
+
* {@link ClickCreate}, a drag's from the dragged points. It says nothing of
|
|
955
|
+
* what is drawn there: each shape family turns it into its shape
|
|
956
|
+
* (`ShapeFamily.placed`), and a form field takes the box as its bounds.
|
|
957
|
+
*/
|
|
958
|
+
type Placement = {
|
|
959
|
+
kind: 'box';
|
|
960
|
+
rect: Rect;
|
|
961
|
+
rot: number;
|
|
962
|
+
} | {
|
|
963
|
+
kind: 'segment';
|
|
964
|
+
a: Point$1;
|
|
965
|
+
b: Point$1;
|
|
966
|
+
};
|
|
967
|
+
type Message = {
|
|
968
|
+
type: 'editPointer';
|
|
626
969
|
phase: 'down' | 'move' | 'up';
|
|
627
970
|
in: PointerInput;
|
|
628
971
|
} | {
|
|
629
|
-
|
|
972
|
+
type: 'marqueePointer';
|
|
630
973
|
phase: 'down' | 'move' | 'up';
|
|
631
974
|
in: PointerInput;
|
|
632
975
|
} | {
|
|
633
|
-
|
|
976
|
+
type: 'createPointer';
|
|
977
|
+
measure?: MeasurementAppearance;
|
|
978
|
+
capture?: string;
|
|
634
979
|
phase: 'down' | 'move' | 'up';
|
|
635
|
-
subtype:
|
|
980
|
+
subtype: KindName;
|
|
636
981
|
/** The authoring tool's `defaults` key (see {@link Draft}). Defaults to `subtype`. */
|
|
637
982
|
preset?: string;
|
|
638
983
|
/** PDF intent carried by an ink authoring preset. */
|
|
@@ -648,190 +993,171 @@ type Msg = {
|
|
|
648
993
|
straightenInk?: InkStraightenOptions;
|
|
649
994
|
in: PointerInput;
|
|
650
995
|
} | {
|
|
651
|
-
|
|
996
|
+
type: 'finishInkDraft';
|
|
652
997
|
} | {
|
|
653
|
-
|
|
998
|
+
type: 'finishCreationDraft';
|
|
654
999
|
} | {
|
|
655
|
-
|
|
656
|
-
|
|
1000
|
+
type: 'createCaret';
|
|
1001
|
+
page: PageRef;
|
|
657
1002
|
anchor: TextEndAnchor;
|
|
658
1003
|
flags?: Partial<AnnotationFlags$1>;
|
|
659
1004
|
} | {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
quads:
|
|
1005
|
+
type: 'createReplaceText';
|
|
1006
|
+
page: PageRef;
|
|
1007
|
+
quads: Quad$1[];
|
|
663
1008
|
anchor: TextEndAnchor;
|
|
664
1009
|
preset?: string;
|
|
665
1010
|
} | {
|
|
666
|
-
|
|
667
|
-
subtype:
|
|
668
|
-
|
|
669
|
-
quads:
|
|
1011
|
+
type: 'createMarkup';
|
|
1012
|
+
subtype: KindName;
|
|
1013
|
+
page: PageRef;
|
|
1014
|
+
quads: Quad$1[];
|
|
670
1015
|
preset?: string;
|
|
671
1016
|
/** The tool's `/F` seed — merged over {@link DRAWN_FLAGS} at commit. */
|
|
672
1017
|
flags?: Partial<AnnotationFlags$1>;
|
|
673
1018
|
} | {
|
|
674
|
-
|
|
675
|
-
subtype:
|
|
676
|
-
|
|
1019
|
+
type: 'setMarkupPreview';
|
|
1020
|
+
subtype: KindName;
|
|
1021
|
+
/** Per-page quads keyed by `page.pageObjectNumber` (a lookup, not an address). */
|
|
1022
|
+
quadsByPage: Record<number, Quad$1[]>;
|
|
677
1023
|
preset?: string;
|
|
678
1024
|
} | {
|
|
679
|
-
|
|
1025
|
+
type: 'clearMarkupPreview';
|
|
680
1026
|
} | {
|
|
681
|
-
|
|
1027
|
+
type: 'deselect';
|
|
682
1028
|
ids?: Id[];
|
|
683
1029
|
} |
|
|
684
1030
|
/** Pointer entered/left an annotation (topmost hit id, or null). Pure state. */
|
|
685
1031
|
{
|
|
686
|
-
|
|
1032
|
+
type: 'hover';
|
|
687
1033
|
id: Id | null;
|
|
688
|
-
} |
|
|
689
|
-
|
|
690
|
-
* plane's Hide sink). Hiding also clears transient engagement (selection,
|
|
691
|
-
* editing, hover) for the hidden ids. Unknown ids no-op. Zero effects. */
|
|
692
|
-
/** Drop overrides for truly DELETED annotations (never for reloads). */
|
|
693
|
-
{
|
|
694
|
-
t: 'select';
|
|
1034
|
+
} | {
|
|
1035
|
+
type: 'select';
|
|
695
1036
|
ids: Id[];
|
|
696
1037
|
add?: boolean;
|
|
697
1038
|
} | {
|
|
698
|
-
|
|
699
|
-
|
|
1039
|
+
type: 'setFields';
|
|
1040
|
+
patches: Readonly<Record<Id, FieldValues>>;
|
|
1041
|
+
} | {
|
|
1042
|
+
type: 'setTextFormat';
|
|
1043
|
+
format: 'bold' | 'italic' | 'underline';
|
|
1044
|
+
on: boolean;
|
|
1045
|
+
} | {
|
|
1046
|
+
type: 'setLink';
|
|
1047
|
+
target: PdfLinkTarget | null;
|
|
700
1048
|
} | {
|
|
701
|
-
|
|
1049
|
+
type: 'setFlags';
|
|
702
1050
|
patch: Partial<AnnotationFlags$1>;
|
|
703
1051
|
ids?: Id[];
|
|
704
1052
|
} | {
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
patch:
|
|
1053
|
+
type: 'setDefaults';
|
|
1054
|
+
preset: string;
|
|
1055
|
+
patch: FieldValues;
|
|
708
1056
|
} | {
|
|
709
|
-
|
|
1057
|
+
type: 'setSnap';
|
|
710
1058
|
patch: Partial<SnapSettings>;
|
|
711
1059
|
} | {
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
t: 'resetRotation';
|
|
1060
|
+
type: 'rotateSelection';
|
|
1061
|
+
degrees: 90 | -90;
|
|
715
1062
|
} | {
|
|
716
|
-
|
|
1063
|
+
type: 'resetRotation';
|
|
717
1064
|
} | {
|
|
718
|
-
|
|
1065
|
+
type: 'delete';
|
|
719
1066
|
} | {
|
|
720
|
-
|
|
721
|
-
annots: Annot[];
|
|
1067
|
+
type: 'cancel';
|
|
722
1068
|
} |
|
|
723
|
-
/**
|
|
724
|
-
* Whole-document hydration ingest (and desync re-ingest): the snapshot is
|
|
725
|
-
* the committed TRUTH. Incoming annots overwrite by id (gesture-locked ids
|
|
726
|
-
* excepted, as in `upsert`); committed model entries ABSENT from the
|
|
727
|
-
* snapshot are reaped — they were deleted while we could not watch.
|
|
728
|
-
* Uncommitted `tmp:` drafts and gesture-locked ids are never reaped, and
|
|
729
|
-
* an in-progress draft survives (unlike `remove`). `bumpAp` marks a
|
|
730
|
-
* desync re-ingest: rasters may have changed invisibly during the gap,
|
|
731
|
-
* so every replaced annotation re-fetches once.
|
|
732
|
-
*/
|
|
1069
|
+
/** These records left the view (deleted elsewhere, a refused create): drop every reference to them. */
|
|
733
1070
|
{
|
|
734
|
-
|
|
735
|
-
annots: Annot[];
|
|
736
|
-
bumpAp?: boolean;
|
|
737
|
-
} | {
|
|
738
|
-
t: 'created';
|
|
739
|
-
tempId: Id;
|
|
740
|
-
id: Id;
|
|
741
|
-
ref: AnnotationRef;
|
|
742
|
-
} | {
|
|
743
|
-
t: 'createFailed';
|
|
744
|
-
tempId: Id;
|
|
745
|
-
} | {
|
|
746
|
-
t: 'upsert';
|
|
747
|
-
annots: Annot[];
|
|
748
|
-
bumpAp?: boolean;
|
|
749
|
-
} | {
|
|
750
|
-
t: 'bumpAp';
|
|
751
|
-
ids: Id[];
|
|
752
|
-
} | {
|
|
753
|
-
t: 'remove';
|
|
1071
|
+
type: 'forget';
|
|
754
1072
|
ids: Id[];
|
|
755
1073
|
} | {
|
|
756
|
-
|
|
1074
|
+
type: 'beginTextEdit';
|
|
757
1075
|
id: Id;
|
|
758
1076
|
} | {
|
|
759
|
-
|
|
1077
|
+
type: 'setText';
|
|
760
1078
|
id: Id;
|
|
761
1079
|
text: string;
|
|
762
1080
|
} | {
|
|
763
|
-
|
|
1081
|
+
type: 'setRichText';
|
|
764
1082
|
id: Id;
|
|
765
1083
|
doc: RichTextDocumentInput;
|
|
766
1084
|
} | {
|
|
767
|
-
|
|
1085
|
+
type: 'endTextEdit';
|
|
768
1086
|
};
|
|
769
1087
|
type Effect = {
|
|
770
|
-
|
|
1088
|
+
type: 'captured';
|
|
1089
|
+
tool: string;
|
|
1090
|
+
page: PageRef;
|
|
1091
|
+
geometry: Shape;
|
|
1092
|
+
} |
|
|
1093
|
+
/** Write a new record: the draft its annotation was read from. Its ref names the object number it takes. */
|
|
1094
|
+
{
|
|
1095
|
+
type: 'create';
|
|
771
1096
|
id: Id;
|
|
772
|
-
|
|
773
|
-
fx: 'createGroup';
|
|
774
|
-
primary: Id;
|
|
775
|
-
members: Id[];
|
|
1097
|
+
draft: AnnotationDraft;
|
|
776
1098
|
} |
|
|
777
|
-
/**
|
|
778
|
-
*
|
|
779
|
-
*
|
|
780
|
-
*
|
|
781
|
-
* an `upsert` with `bumpAp`. Absent for everything else — moves/rotations
|
|
782
|
-
* (the blit repositions the same pixels) and any kind that flipped to
|
|
783
|
-
* `vector` (it renders live; the raster stops mattering) — so those keep the
|
|
784
|
-
* bare `{ fx, id }` shape and trigger no appearance re-fetch. */
|
|
1099
|
+
/** Write one record's change: its entry in the change set's `patches`. `update`
|
|
1100
|
+
* asks for it for every changed record that has one, except typed text, which
|
|
1101
|
+
* its `text` effect writes. Whether the engine's re-baked appearance differs
|
|
1102
|
+
* is the engine's answer, not the core's guess. */
|
|
785
1103
|
{
|
|
786
|
-
|
|
1104
|
+
type: 'patch';
|
|
787
1105
|
id: Id;
|
|
788
|
-
|
|
789
|
-
apChanged?: true;
|
|
1106
|
+
patch: AnnotationPatch;
|
|
790
1107
|
} |
|
|
791
|
-
/**
|
|
792
|
-
*
|
|
793
|
-
*
|
|
1108
|
+
/** Write the edited text of one free-text record. While the user types, the
|
|
1109
|
+
* plugin keeps amending one change with the latest text, and sends it after
|
|
1110
|
+
* a pause. */
|
|
794
1111
|
{
|
|
795
|
-
|
|
1112
|
+
type: 'text';
|
|
796
1113
|
id: Id;
|
|
797
1114
|
} |
|
|
798
|
-
/** The parent's `link` prop changed on a
|
|
799
|
-
* attached link children (create / retarget / delete)
|
|
800
|
-
*
|
|
801
|
-
*
|
|
802
|
-
*
|
|
803
|
-
*
|
|
1115
|
+
/** The parent's `link` prop changed on a non-link kind: reconcile its
|
|
1116
|
+
* attached link children (create / retarget / delete) toward `target`
|
|
1117
|
+
* (null = remove them). Declarative — the plugin's reconciler is the only
|
|
1118
|
+
* code that spells out child operations; parents store no link value, the
|
|
1119
|
+
* committed children are the truth (`linkOf` reads them back). Geometry
|
|
1120
|
+
* commits don't emit this: the plugin's write of a `patch` brings an
|
|
1121
|
+
* annotation's attached children along. */
|
|
804
1122
|
{
|
|
805
|
-
|
|
1123
|
+
type: 'syncLink';
|
|
806
1124
|
id: Id;
|
|
807
1125
|
target: PdfLinkTarget | null;
|
|
808
|
-
} |
|
|
809
|
-
|
|
810
|
-
|
|
1126
|
+
} |
|
|
1127
|
+
/** Delete one record from the document. */
|
|
1128
|
+
{
|
|
1129
|
+
type: 'delete';
|
|
1130
|
+
id: Id;
|
|
811
1131
|
};
|
|
812
1132
|
/** Per-annotation render data — its content geometry + style + live state. */
|
|
813
1133
|
interface RenderItem {
|
|
814
1134
|
id: Id;
|
|
815
1135
|
ref: AnnotationRef | null;
|
|
816
|
-
subtype: Subtype;
|
|
817
|
-
geom: Geom;
|
|
818
1136
|
/**
|
|
819
|
-
* The
|
|
820
|
-
*
|
|
821
|
-
*
|
|
822
|
-
|
|
1137
|
+
* The annotation it draws, as the user sees it (the record's, a gesture
|
|
1138
|
+
* in progress aside: that is in `geometry` and `box`). Absent for what isn't
|
|
1139
|
+
* made yet: a drawing in progress or a tool's ghost.
|
|
1140
|
+
*/
|
|
1141
|
+
annotation?: Annotation;
|
|
1142
|
+
subtype: KindName;
|
|
1143
|
+
geometry: Shape;
|
|
1144
|
+
/**
|
|
1145
|
+
* The box the live drawing is painted into (its family's `drawnBounds`:
|
|
1146
|
+
* geometry, stroke, endings, cloud): a box's or caret's own, before its
|
|
1147
|
+
* turn (`rot`), the page's for the rest. The renderer paints into this box
|
|
1148
|
+
* and does no bounds math of its own.
|
|
823
1149
|
*/
|
|
824
1150
|
box: Rect;
|
|
825
1151
|
/**
|
|
826
|
-
*
|
|
1152
|
+
* Page-space box the engine appearance raster occupies (the AP `/Rect`),
|
|
827
1153
|
* with the live move gesture applied — so a baked annotation's bitmap follows
|
|
828
1154
|
* a drag. Only meaningful when `source === 'baked'`; absent otherwise.
|
|
829
1155
|
*/
|
|
830
1156
|
apBox?: Rect;
|
|
831
1157
|
/**
|
|
832
1158
|
* Rotation (deg, CW) to apply to the baked raster as a view transform —
|
|
833
|
-
* exactly the rotation the engine
|
|
834
|
-
* Live for `
|
|
1159
|
+
* exactly the rotation the engine stripped from it (see `ModelAnnotation.apRot`).
|
|
1160
|
+
* Live for `rasterOnly` kinds (a stamp spins with the rotate gesture);
|
|
835
1161
|
* absent when the raster already contains its rotation (vertex kinds).
|
|
836
1162
|
*/
|
|
837
1163
|
apRot?: number;
|
|
@@ -840,21 +1166,67 @@ interface RenderItem {
|
|
|
840
1166
|
* text, text/choice widgets). Lets a behavior renderer's focused editor
|
|
841
1167
|
* match the baked appearance's font. */
|
|
842
1168
|
text?: TextStyle;
|
|
843
|
-
|
|
1169
|
+
/**
|
|
1170
|
+
* How it paints: the engine's raster (`baked`), live from its description
|
|
1171
|
+
* (`vector`), or an annotation not made yet, drawn as it will be: a drawing
|
|
1172
|
+
* in progress (`draft`, solid) or the tool's ghost, what a click would
|
|
1173
|
+
* place (`ghost`, see-through by `ghostOpacity`).
|
|
1174
|
+
*/
|
|
1175
|
+
source: 'baked' | 'vector' | 'draft' | 'ghost';
|
|
1176
|
+
/**
|
|
1177
|
+
* The version of the record's engine picture (`ModelAnnotation.pictureVersion`):
|
|
1178
|
+
* a picture drawn at another version shows another look of it. Absent for
|
|
1179
|
+
* what isn't made yet.
|
|
1180
|
+
*/
|
|
1181
|
+
pictureVersion?: number;
|
|
1182
|
+
/**
|
|
1183
|
+
* A lent record's live drawing, by its lender (`ModelAnnotation.painter`),
|
|
1184
|
+
* upright in `box` (where a gesture has it): `scene(item)` draws it in place
|
|
1185
|
+
* of the kind's own. Made when it's first asked for, not before.
|
|
1186
|
+
*/
|
|
1187
|
+
lentScene?: () => readonly SceneNode[];
|
|
1188
|
+
/** How opaque a ghost paints (0–1); a painter lets `--epdf-ghost-opacity` win over it. */
|
|
1189
|
+
ghostOpacity?: number;
|
|
844
1190
|
selected: boolean;
|
|
845
1191
|
/** The pointer is over this annotation — scene-level hover affordances
|
|
846
1192
|
* (e.g. a redaction mark previews its applied look). */
|
|
847
1193
|
hovered?: boolean;
|
|
848
|
-
/** Redaction label projection (redact kind only) — see {@link
|
|
1194
|
+
/** Redaction label projection (redact kind only) — see {@link ModelAnnotation.label}. */
|
|
849
1195
|
label?: {
|
|
850
1196
|
text: string;
|
|
851
1197
|
repeat: boolean;
|
|
852
1198
|
};
|
|
853
1199
|
/**
|
|
854
|
-
*
|
|
855
|
-
*
|
|
856
|
-
*
|
|
857
|
-
*
|
|
1200
|
+
* The box a painter draws into: `box` before its turn, and that turn,
|
|
1201
|
+
* degrees clockwise about the box's middle. Everything the item draws sits
|
|
1202
|
+
* upright inside it: its scene, a custom look, or its raster (`raster`).
|
|
1203
|
+
* `scale` is how large the page draws the item relative to its own size:
|
|
1204
|
+
* 1, except for a body that keeps its size on screen (`noZoom`), drawn
|
|
1205
|
+
* smaller on the page as people zoom in. Made from `box` and `rot` by the
|
|
1206
|
+
* core; painters read this, not `rot`.
|
|
1207
|
+
*/
|
|
1208
|
+
frame: {
|
|
1209
|
+
box: Rect;
|
|
1210
|
+
rotation: number;
|
|
1211
|
+
scale: number;
|
|
1212
|
+
};
|
|
1213
|
+
/**
|
|
1214
|
+
* The engine's raster inside the frame, for an item that has one: its box
|
|
1215
|
+
* relative to the frame's top-left before the frame's turn, and its own turn
|
|
1216
|
+
* about its middle. Made from `apBox` and `apRot`; null without a raster box.
|
|
1217
|
+
*/
|
|
1218
|
+
raster: {
|
|
1219
|
+
box: Rect;
|
|
1220
|
+
rotation: number;
|
|
1221
|
+
} | null;
|
|
1222
|
+
/** A note's or file attachment's icon (`/Name`), which its live drawing draws. */
|
|
1223
|
+
icon?: NoteIcon | FileAttachmentIcon;
|
|
1224
|
+
measure?: MeasurementAppearance;
|
|
1225
|
+
/**
|
|
1226
|
+
* Applied rotation (deg, CW), or 0/undefined. For box kinds (`box`/`text-box`)
|
|
1227
|
+
* `box` is the unrotated visual box and the renderer applies this rotation
|
|
1228
|
+
* about its centre (CSS/SVG transform). For vertex kinds the geometry is
|
|
1229
|
+
* already rotated, so this is advisory only — the renderer must not re-apply it.
|
|
858
1230
|
*/
|
|
859
1231
|
rot?: number;
|
|
860
1232
|
/**
|
|
@@ -864,8 +1236,8 @@ interface RenderItem {
|
|
|
864
1236
|
*/
|
|
865
1237
|
blend?: Exclude<BlendMode$1, 'normal'>;
|
|
866
1238
|
}
|
|
867
|
-
/** The dumb draw vocabulary the framework renderer maps to SVG (
|
|
868
|
-
* A
|
|
1239
|
+
/** The dumb draw vocabulary the framework renderer maps to SVG (page space).
|
|
1240
|
+
* A closed node (rect, ellipse, closed poly) takes the annotation's fill colour;
|
|
869
1241
|
* an open node (line, open poly — open arrows, butt, slash) is stroke-only. The
|
|
870
1242
|
* stroke colour applies to every node. Closed-ness is the only fill signal. */
|
|
871
1243
|
type RenderNode = {
|
|
@@ -876,11 +1248,11 @@ type RenderNode = {
|
|
|
876
1248
|
rect: Rect;
|
|
877
1249
|
} | {
|
|
878
1250
|
kind: 'line';
|
|
879
|
-
a:
|
|
880
|
-
b:
|
|
1251
|
+
a: Point$1;
|
|
1252
|
+
b: Point$1;
|
|
881
1253
|
} | {
|
|
882
1254
|
kind: 'poly';
|
|
883
|
-
points:
|
|
1255
|
+
points: Point$1[];
|
|
884
1256
|
closed: boolean;
|
|
885
1257
|
} | {
|
|
886
1258
|
kind: 'path';
|
|
@@ -888,7 +1260,7 @@ type RenderNode = {
|
|
|
888
1260
|
};
|
|
889
1261
|
/**
|
|
890
1262
|
* How to paint one node. The pure core fills this in (per kind/subtype), and a
|
|
891
|
-
* framework renderer applies it verbatim — so
|
|
1263
|
+
* framework renderer applies it verbatim — so all appearance logic (markup fill vs
|
|
892
1264
|
* stroke, blend, dash, derived widths) lives once, in the portable core, not in
|
|
893
1265
|
* every framework. Omitted `fill`/`stroke` mean none.
|
|
894
1266
|
*/
|
|
@@ -899,16 +1271,17 @@ interface Paint {
|
|
|
899
1271
|
opacity?: number;
|
|
900
1272
|
dash?: number[];
|
|
901
1273
|
blend?: Exclude<BlendMode$1, 'normal'>;
|
|
902
|
-
|
|
1274
|
+
lineCap?: 'round';
|
|
903
1275
|
join?: 'round';
|
|
1276
|
+
fillRule?: 'evenodd';
|
|
904
1277
|
}
|
|
905
1278
|
/**
|
|
906
1279
|
* A fully-painted draw node: geometry + paint. `scene(item)` returns these and a
|
|
907
|
-
* per-framework painter maps each to
|
|
1280
|
+
* per-framework painter maps each to one element, applying `paint` — the entire
|
|
908
1281
|
* surface a new framework renderer must implement. Supersedes the geometry-only
|
|
909
1282
|
* `RenderNode` for rendering; `geomScene` stays the internal geometry helper.
|
|
910
1283
|
*/
|
|
911
|
-
type SceneNode = {
|
|
1284
|
+
type SceneNode = ({
|
|
912
1285
|
kind: 'rect';
|
|
913
1286
|
rect: Rect;
|
|
914
1287
|
paint: Paint;
|
|
@@ -918,12 +1291,12 @@ type SceneNode = {
|
|
|
918
1291
|
paint: Paint;
|
|
919
1292
|
} | {
|
|
920
1293
|
kind: 'line';
|
|
921
|
-
a:
|
|
922
|
-
b:
|
|
1294
|
+
a: Point$1;
|
|
1295
|
+
b: Point$1;
|
|
923
1296
|
paint: Paint;
|
|
924
1297
|
} | {
|
|
925
1298
|
kind: 'poly';
|
|
926
|
-
points:
|
|
1299
|
+
points: Point$1[];
|
|
927
1300
|
closed: boolean;
|
|
928
1301
|
paint: Paint;
|
|
929
1302
|
} | {
|
|
@@ -931,17 +1304,49 @@ type SceneNode = {
|
|
|
931
1304
|
d: string;
|
|
932
1305
|
paint: Paint;
|
|
933
1306
|
} |
|
|
934
|
-
/** Painted (non-interactive) text — `at` is the
|
|
1307
|
+
/** Painted (non-interactive) text — `at` is the baseline start point in
|
|
935
1308
|
* content units. Editable text (free text) stays a framework element;
|
|
936
1309
|
* this is for pure pixels, e.g. a redaction label preview. */
|
|
937
1310
|
{
|
|
938
1311
|
kind: 'text';
|
|
939
|
-
at:
|
|
1312
|
+
at: Point$1;
|
|
940
1313
|
text: string;
|
|
941
1314
|
fontSize: number;
|
|
942
1315
|
fontFamily?: string;
|
|
1316
|
+
rotation?: number;
|
|
1317
|
+
paint: Paint;
|
|
1318
|
+
} |
|
|
1319
|
+
/** Painted text placed character by character: `offsets[i]` is how far
|
|
1320
|
+
* along the baseline from `at` character `i` starts, so each glyph lands
|
|
1321
|
+
* where the PDF puts it (a form widget's painted text). `rotation` turns
|
|
1322
|
+
* the run about `at`, degrees clockwise. `program` is the face it draws
|
|
1323
|
+
* in, for whatever draws it to mount (`fontFamily` names it first). */
|
|
1324
|
+
{
|
|
1325
|
+
kind: 'glyphs';
|
|
1326
|
+
at: Point$1;
|
|
1327
|
+
text: string;
|
|
1328
|
+
offsets: number[];
|
|
1329
|
+
fontSize: number;
|
|
1330
|
+
fontFamily: string;
|
|
1331
|
+
fontWeight?: number;
|
|
1332
|
+
fontStyle?: 'normal' | 'italic';
|
|
1333
|
+
rotation?: number;
|
|
1334
|
+
program?: SceneFontProgram;
|
|
943
1335
|
paint: Paint;
|
|
1336
|
+
}) & {
|
|
1337
|
+
/** Drawn only inside this upright rectangle (a widget's text box). */
|
|
1338
|
+
clip?: Rect;
|
|
944
1339
|
};
|
|
1340
|
+
/**
|
|
1341
|
+
* A font program a scene's text draws in: mounted under its own family, in
|
|
1342
|
+
* its own weight and style, so the browser takes it as it is.
|
|
1343
|
+
*/
|
|
1344
|
+
interface SceneFontProgram {
|
|
1345
|
+
readonly family: string;
|
|
1346
|
+
readonly weight: number;
|
|
1347
|
+
readonly style: 'normal' | 'italic';
|
|
1348
|
+
load(): Promise<Uint8Array>;
|
|
1349
|
+
}
|
|
945
1350
|
/** Pure geometry settings for recognising and axis-snapping a freehand stroke. */
|
|
946
1351
|
interface InkStraightenOptions {
|
|
947
1352
|
/** Maximum `max perpendicular deviation / endpoint distance`. */
|
|
@@ -949,39 +1354,39 @@ interface InkStraightenOptions {
|
|
|
949
1354
|
/** Degrees from horizontal/vertical within which the line snaps to that axis. */
|
|
950
1355
|
axisSnapDegrees: number;
|
|
951
1356
|
}
|
|
1357
|
+
/** What a selection handle reshapes: a box's corner or side, or one point of a line or a polygon. */
|
|
1358
|
+
type HandleRole = 'corner' | 'side' | 'point';
|
|
952
1359
|
type ChromeNode = {
|
|
953
1360
|
kind: 'outline';
|
|
954
1361
|
rect: Rect;
|
|
955
1362
|
} | {
|
|
956
1363
|
kind: 'obb';
|
|
957
|
-
corners: [
|
|
1364
|
+
corners: [Point$1, Point$1, Point$1, Point$1];
|
|
958
1365
|
angle: number;
|
|
959
1366
|
} | {
|
|
960
1367
|
kind: 'handle';
|
|
961
|
-
at:
|
|
1368
|
+
at: Point$1;
|
|
962
1369
|
cursor: Cursor;
|
|
963
1370
|
rot?: number;
|
|
1371
|
+
role: HandleRole;
|
|
1372
|
+
active: boolean;
|
|
964
1373
|
} | {
|
|
965
1374
|
kind: 'rotate-knob';
|
|
966
|
-
at:
|
|
967
|
-
from:
|
|
1375
|
+
at: Point$1;
|
|
1376
|
+
from: Point$1;
|
|
968
1377
|
} | {
|
|
969
1378
|
kind: 'guide';
|
|
970
1379
|
axis: 'x' | 'y';
|
|
971
1380
|
at: number;
|
|
972
1381
|
lo: number;
|
|
973
1382
|
hi: number;
|
|
974
|
-
} | {
|
|
975
|
-
kind: 'angle-chip';
|
|
976
|
-
at: Vec;
|
|
977
|
-
angle: number;
|
|
978
1383
|
} | {
|
|
979
1384
|
kind: 'rotate-guides';
|
|
980
|
-
center:
|
|
1385
|
+
center: Point$1;
|
|
981
1386
|
angle: number;
|
|
982
1387
|
lines: Array<{
|
|
983
|
-
a:
|
|
984
|
-
b:
|
|
1388
|
+
a: Point$1;
|
|
1389
|
+
b: Point$1;
|
|
985
1390
|
role: 'axis' | 'indicator';
|
|
986
1391
|
}>;
|
|
987
1392
|
} | {
|
|
@@ -989,6 +1394,79 @@ type ChromeNode = {
|
|
|
989
1394
|
rect: Rect;
|
|
990
1395
|
};
|
|
991
1396
|
//#endregion
|
|
1397
|
+
//#region src/update/session.d.ts
|
|
1398
|
+
declare const initialSession: Session;
|
|
1399
|
+
/** A tool's defaults, by its preset: the engine fields its creates state. */
|
|
1400
|
+
declare const defaultsFor: (model: Model, preset: string) => FieldValues;
|
|
1401
|
+
/**
|
|
1402
|
+
* What a create from a tool starts from, before it has a shape: the tool's
|
|
1403
|
+
* defaults (by its preset) over the engine's for its `kind`, read as an
|
|
1404
|
+
* annotation. A ghost is drawn with its style (`styleOf`).
|
|
1405
|
+
*/
|
|
1406
|
+
declare const toolAnnotation: (model: Model, kind: string, preset?: string) => Annotation;
|
|
1407
|
+
//#endregion
|
|
1408
|
+
//#region src/update/edit.d.ts
|
|
1409
|
+
/**
|
|
1410
|
+
* The live rotation of a rotate draft, snapping applied — the one angle rule
|
|
1411
|
+
* shared by the preview (`effGeom`), the commit (`editUp`) and the angle chip,
|
|
1412
|
+
* so they can never disagree. The selection's absolute angle (a single member's
|
|
1413
|
+
* `rot` + the raw pointer delta; a group's raw delta from 0) locks onto the
|
|
1414
|
+
* configured angles within the threshold; `free` (shift held) bypasses.
|
|
1415
|
+
* `delta` is what `geomRotateAbout` applies; `angle` is what the chip shows.
|
|
1416
|
+
*/
|
|
1417
|
+
declare function rotateDraftDelta(model: Model, draft: Extract<Draft, {
|
|
1418
|
+
kind: 'rotate';
|
|
1419
|
+
}>): {
|
|
1420
|
+
delta: number;
|
|
1421
|
+
angle: number;
|
|
1422
|
+
snapped: boolean;
|
|
1423
|
+
};
|
|
1424
|
+
//#endregion
|
|
1425
|
+
//#region src/flags.d.ts
|
|
1426
|
+
/** The `/F` every freshly drawn annotation starts with: `print` set (Acrobat
|
|
1427
|
+
* parity — without it the annotation silently disappears when printed). */
|
|
1428
|
+
declare const DRAWN_FLAGS: AnnotationFlags;
|
|
1429
|
+
/** All ten flags, for iteration/equality — kept in the primitives' order. */
|
|
1430
|
+
declare const FLAG_KEYS: ReadonlyArray<keyof AnnotationFlags>;
|
|
1431
|
+
declare const flagsEqual: (left: AnnotationFlags, right: AnnotationFlags) => boolean;
|
|
1432
|
+
/** Merge a partial write over the current flags. */
|
|
1433
|
+
declare const mergeFlags: (base: AnnotationFlags, patch: Partial<AnnotationFlags>) => AnnotationFlags;
|
|
1434
|
+
/**
|
|
1435
|
+
* On-screen visibility. `hidden` beats everything; `noView` hides unless
|
|
1436
|
+
* `toggleNoView` and the annotation is engaged — the spec says hover/selection,
|
|
1437
|
+
* and v1 uses selection (the model tracks no hover).
|
|
1438
|
+
*/
|
|
1439
|
+
declare const viewable: (flags: AnnotationFlags, engaged?: boolean) => boolean;
|
|
1440
|
+
/** Any pointer interaction (click-to-select, hover). ReadOnly kills it. */
|
|
1441
|
+
declare const interactive: (flags: AnnotationFlags) => boolean;
|
|
1442
|
+
/** The part of a ModelAnnotation these predicates read. */
|
|
1443
|
+
interface FlagBearer {
|
|
1444
|
+
/** The record's annotation: its kind and `/F` flags are read off it. */
|
|
1445
|
+
annotation: Annotation;
|
|
1446
|
+
/** Session authority projected at ingest (permissions.md). Absent =
|
|
1447
|
+
* unstamped (drafts, wildcard local engines, tests) = allowed. */
|
|
1448
|
+
authority?: {
|
|
1449
|
+
update: boolean;
|
|
1450
|
+
delete: boolean;
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
/** Interaction gate for a concrete annotation: widget kinds ignore `readOnly`
|
|
1454
|
+
* (ISO 32000 — a ReadOnly form field must still be movable by a form designer;
|
|
1455
|
+
* the form-filling layer enforces field ReadOnly itself). */
|
|
1456
|
+
declare const annotInteractive: (record: FlagBearer) => boolean;
|
|
1457
|
+
/**
|
|
1458
|
+
* Geometry/style mutations — `locked` freezes the object, not its contents
|
|
1459
|
+
* (that's `lockedContents`), and the session must hold update authority over
|
|
1460
|
+
* the record. One predicate for hit-test, chrome, and props alike, so a
|
|
1461
|
+
* record you may not edit renders and behaves exactly like a locked one.
|
|
1462
|
+
*/
|
|
1463
|
+
declare const annotTransformable: (record: FlagBearer) => boolean;
|
|
1464
|
+
/** Deletion — the delete half of the authority split (a narrowed grant can
|
|
1465
|
+
* allow update but not delete, or vice versa). Flags gate like transforms. */
|
|
1466
|
+
declare const annotDeletable: (record: FlagBearer) => boolean;
|
|
1467
|
+
/** `/Contents` text edits — the contents counterpart of `locked`. */
|
|
1468
|
+
declare const annotContentsEditable: (record: FlagBearer) => boolean;
|
|
1469
|
+
//#endregion
|
|
992
1470
|
//#region src/anchor.d.ts
|
|
993
1471
|
/** Which display factors this annotation is exempt from: `zoom` =
|
|
994
1472
|
* screen-constant size, `upright` = screen-constant orientation. */
|
|
@@ -997,46 +1475,46 @@ interface AnchorMode {
|
|
|
997
1475
|
upright: boolean;
|
|
998
1476
|
}
|
|
999
1477
|
/**
|
|
1000
|
-
* The anchor behaviors of one annotation: its `/F` flags
|
|
1478
|
+
* The anchor behaviors of one annotation: its `/F` flags or'd with the kind's
|
|
1001
1479
|
* statics — the spec's "Text (note) annotations behave as if NoZoom and
|
|
1002
|
-
* NoRotate are
|
|
1480
|
+
* NoRotate are always set", expressed as kind caps. Null when not anchored.
|
|
1003
1481
|
*/
|
|
1004
|
-
declare function anchorModeOf(
|
|
1005
|
-
/** The fixed page point: the geometry's bounds top-left in
|
|
1006
|
-
* (y-down) — which
|
|
1482
|
+
declare function anchorModeOf(record: FlagBearer): AnchorMode | null;
|
|
1483
|
+
/** The fixed page point: the geometry's bounds top-left in page space
|
|
1484
|
+
* (y-down) — which is the spec's "upper-left corner of the annotation
|
|
1007
1485
|
* rectangle", since `/Rect` is emitted from these bounds. */
|
|
1008
|
-
declare const anchorOf: (
|
|
1486
|
+
declare const anchorOf: (geometry: Shape) => Point;
|
|
1009
1487
|
/**
|
|
1010
|
-
*
|
|
1488
|
+
* The effective page-space geometry of a screen-anchored body at `view`:
|
|
1011
1489
|
* the stored geometry scaled by `1/max(zoom, 1)` about the anchor (`zoom`
|
|
1012
1490
|
* exemption, Adobe-clamped) and counter-rotated by `-rotation` about it
|
|
1013
1491
|
* (`upright`), so that after the page's own display transform the body reads
|
|
1014
1492
|
* at its 100%-zoom size and its authored tilt, hanging from the fixed anchor.
|
|
1015
|
-
* Returns `
|
|
1493
|
+
* Returns `geometry` unchanged when there is nothing to do — callers apply it
|
|
1016
1494
|
* unconditionally.
|
|
1017
1495
|
*/
|
|
1018
|
-
declare function anchoredGeom(
|
|
1496
|
+
declare function anchoredGeom(geometry: Shape, mode: AnchorMode | null, view: ViewEnv | undefined): Shape;
|
|
1019
1497
|
/**
|
|
1020
|
-
* The exact inverse of {@link anchoredGeom} for a
|
|
1021
|
-
* gesture produced: the stored geometry whose
|
|
1498
|
+
* The exact inverse of {@link anchoredGeom} for a view-space geometry a
|
|
1499
|
+
* gesture produced: the stored geometry whose own projection is `target`.
|
|
1022
1500
|
*
|
|
1023
1501
|
* Solving `anchoredGeom(stored) = target` where the projection anchors at
|
|
1024
1502
|
* `stored`'s (unknown) bounds top-left `a` gives a closed form: map `target`
|
|
1025
1503
|
* through the pure linear part (scale `s` + rotate `r` about the origin),
|
|
1026
1504
|
* then translate so the result's bounds top-left `b` lands where the
|
|
1027
1505
|
* projection needs it — at `a = R(-r)·b / s`, the unique fixed point. This is
|
|
1028
|
-
* what makes a released gesture commit
|
|
1506
|
+
* what makes a released gesture commit exactly what its preview showed.
|
|
1029
1507
|
*/
|
|
1030
|
-
declare function unanchoredGeom(target:
|
|
1508
|
+
declare function unanchoredGeom(target: Shape, mode: AnchorMode | null, view: ViewEnv | undefined): Shape;
|
|
1031
1509
|
/** Stroke width in the projected (view) space: a `noZoom` body's line weight
|
|
1032
|
-
* scales with its geometry so it stays screen-constant — through the
|
|
1510
|
+
* scales with its geometry so it stays screen-constant — through the same
|
|
1033
1511
|
* factors (incl. the ≤100% clamp) the geometry projects with. */
|
|
1034
1512
|
declare const anchoredStrokeWidth: (width: number, mode: AnchorMode | null, view: ViewEnv | undefined) => number;
|
|
1035
1513
|
/**
|
|
1036
1514
|
* The similarity image of an axis-aligned box (a baked raster's AP `/Rect`)
|
|
1037
1515
|
* under the anchor projection, as the blit vocabulary expects it: an
|
|
1038
|
-
*
|
|
1039
|
-
* re-apply about its centre. `anchor` is the
|
|
1516
|
+
* unrotated box (the projected centre + scaled size) plus the rotation to
|
|
1517
|
+
* re-apply about its centre. `anchor` is the owning geometry's anchor — the
|
|
1040
1518
|
* raster rides its annotation's projection, it doesn't anchor itself. Null
|
|
1041
1519
|
* when the projection is the identity.
|
|
1042
1520
|
*/
|
|
@@ -1045,7 +1523,7 @@ declare function anchoredBox(box: {
|
|
|
1045
1523
|
y: number;
|
|
1046
1524
|
width: number;
|
|
1047
1525
|
height: number;
|
|
1048
|
-
}, anchor:
|
|
1526
|
+
}, anchor: Point, mode: AnchorMode | null, view: ViewEnv | undefined): {
|
|
1049
1527
|
box: {
|
|
1050
1528
|
x: number;
|
|
1051
1529
|
y: number;
|
|
@@ -1055,75 +1533,84 @@ declare function anchoredBox(box: {
|
|
|
1055
1533
|
rot: number;
|
|
1056
1534
|
} | null;
|
|
1057
1535
|
//#endregion
|
|
1058
|
-
//#region src/update.d.ts
|
|
1059
|
-
/**
|
|
1060
|
-
*
|
|
1061
|
-
*
|
|
1062
|
-
|
|
1063
|
-
|
|
1536
|
+
//#region src/update/marquee.d.ts
|
|
1537
|
+
/**
|
|
1538
|
+
* What a box on `page` selects: every annotation it touches
|
|
1539
|
+
* ({@link annotsInBox}), and the rest of the group of each. The marquee and
|
|
1540
|
+
* the capability's `selectInRect` both select this.
|
|
1541
|
+
*/
|
|
1542
|
+
declare function selectionInBox(model: Model, page: PageRef, box: Rect, inert?: ReadonlySet<Id>, view?: ViewEnv): Id[];
|
|
1543
|
+
//#endregion
|
|
1544
|
+
//#region src/update/index.d.ts
|
|
1545
|
+
/** The model before any record or gesture: an empty view over the initial session. */
|
|
1064
1546
|
declare const initialModel: Model;
|
|
1065
1547
|
/**
|
|
1066
|
-
*
|
|
1067
|
-
*
|
|
1068
|
-
* what a defaults-editing UI reads, and what creation projects `style`/`text`
|
|
1069
|
-
* from (`styleFromProps` / `textStyleFromProps`).
|
|
1548
|
+
* Run one message. The session is returned whole; the records are returned
|
|
1549
|
+
* as the difference the message made, so the caller decides where they live.
|
|
1070
1550
|
*/
|
|
1071
|
-
declare function
|
|
1551
|
+
declare function update(model: Model, message: Message): UpdateResult;
|
|
1072
1552
|
/**
|
|
1073
|
-
* The
|
|
1074
|
-
*
|
|
1075
|
-
*
|
|
1076
|
-
* `rot` + the raw pointer delta; a group's raw delta from 0) locks onto the
|
|
1077
|
-
* configured angles within the threshold; `free` (shift held) bypasses.
|
|
1078
|
-
* `delta` is what `geomRotateAbout` applies; `angle` is what the chip shows.
|
|
1553
|
+
* The most records `message` can create: how many object numbers the session
|
|
1554
|
+
* must hold before it runs (`Session.objectNumbers`). A pointer press or
|
|
1555
|
+
* release of a creating tool can finish a drawing; a move never does.
|
|
1079
1556
|
*/
|
|
1080
|
-
declare function
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
snapped: boolean;
|
|
1086
|
-
};
|
|
1087
|
-
declare function update(m: Model, msg: Msg): [Model, Effect[]];
|
|
1557
|
+
declare function newRecordsAtMost(message: Message): number;
|
|
1558
|
+
/** True when every session field is the same value: a message that changed nothing. */
|
|
1559
|
+
declare const sameSession: (left: Session, right: Session) => boolean;
|
|
1560
|
+
/** The change set of a message that changed no record. */
|
|
1561
|
+
declare const EMPTY_CHANGE: ChangeSet;
|
|
1088
1562
|
//#endregion
|
|
1089
1563
|
//#region src/placement.d.ts
|
|
1090
|
-
/**
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1564
|
+
/** The click ↔ drag threshold (content units): a press-release that stays
|
|
1565
|
+
* under it is a click. Every gesture owner (the draw handler, the form
|
|
1566
|
+
* plugin's place handler) shares this one definition. */
|
|
1567
|
+
declare const MIN_DRAG = 3;
|
|
1568
|
+
/** What a create gesture lays: a box (shapes, text boxes, form fields) or a segment (lines). */
|
|
1569
|
+
type GestureForm = 'box' | 'segment';
|
|
1570
|
+
/** The page a placement is made on, and how the person sees it. */
|
|
1571
|
+
interface PlacementFrame {
|
|
1572
|
+
/** The page's content box: a placement slides inside it. */
|
|
1573
|
+
pageBox?: Rect;
|
|
1574
|
+
/** Lay it out as the person sees the page: the tool's `upright`. */
|
|
1575
|
+
upright?: boolean;
|
|
1576
|
+
/** How far the page shows turned (document /Rotate + view rotation, degrees clockwise). */
|
|
1577
|
+
displayRotation?: PageRotation;
|
|
1578
|
+
}
|
|
1101
1579
|
/** Slide a rect (as a unit) to sit inside `box`; pins at the origin edge when
|
|
1102
1580
|
* it doesn't fit. Placements are page-bound; the pointer isn't. */
|
|
1103
|
-
declare const clampRectToBox: (
|
|
1581
|
+
declare const clampRectToBox: (rect: Rect, box: Rect | undefined) => Rect;
|
|
1582
|
+
/** Whether a gesture from `from` to `to` is a drag: a segment once it is
|
|
1583
|
+
* `MIN_DRAG` long, a box once either side is. */
|
|
1584
|
+
declare function isDrag(form: GestureForm, from: Point, to: Point): boolean;
|
|
1104
1585
|
/**
|
|
1105
|
-
*
|
|
1106
|
-
*
|
|
1107
|
-
*
|
|
1108
|
-
*
|
|
1586
|
+
* Where a create gesture from `from` to `to` puts what it makes: the dragged
|
|
1587
|
+
* box or segment once it is a drag, else the tool's click default at `from`
|
|
1588
|
+
* (`null` when a click makes nothing). A drag stays on the page: its points
|
|
1589
|
+
* pin to the edge. An upright drag keeps the region the author dragged: under
|
|
1590
|
+
* a quarter turn the box before its turn is the dragged one with its sides
|
|
1591
|
+
* swapped about its middle, so the turn lands it back on that region.
|
|
1109
1592
|
*/
|
|
1110
|
-
declare function
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1593
|
+
declare function gesturePlacement(form: GestureForm, from: Point, to: Point, clickCreate: ClickCreate | false | undefined, frame?: PlacementFrame): Placement | null;
|
|
1594
|
+
/**
|
|
1595
|
+
* Where a bare click at `point` puts what the tool makes (see
|
|
1596
|
+
* {@link ClickCreate}), slid inside the page. Under `upright` it is laid out
|
|
1597
|
+
* as the person sees the page: a line's direction and a box's top-left corner
|
|
1598
|
+
* are the screen's, and a box turns to read upright, showing `width` ×
|
|
1599
|
+
* `height` as configured.
|
|
1600
|
+
*/
|
|
1601
|
+
declare function resolveClickPlacement(point: Point, policy: ClickCreate, frame?: PlacementFrame): Placement;
|
|
1115
1602
|
/**
|
|
1116
|
-
*
|
|
1117
|
-
* the
|
|
1118
|
-
*
|
|
1119
|
-
*
|
|
1120
|
-
*
|
|
1603
|
+
* What a create from a tool makes at `placement`: its kind's shape there, as
|
|
1604
|
+
* the kind's shape family lays it (`ShapeFamily.placed`), or `null` when the
|
|
1605
|
+
* kind can't be made that way (a line from a box). `annotation` is what the
|
|
1606
|
+
* tool creates before it has a shape (`toolAnnotation`): its kind, and what
|
|
1607
|
+
* the shape takes from it (a line's endings, a circle's roundness).
|
|
1121
1608
|
*/
|
|
1122
|
-
declare function
|
|
1609
|
+
declare function placedShape(annotation: Annotation, placement: Placement): Shape | null;
|
|
1123
1610
|
//#endregion
|
|
1124
1611
|
//#region src/snap.d.ts
|
|
1125
1612
|
interface SnapResult {
|
|
1126
|
-
delta:
|
|
1613
|
+
delta: Point;
|
|
1127
1614
|
guides: Guide[];
|
|
1128
1615
|
}
|
|
1129
1616
|
/**
|
|
@@ -1132,10 +1619,20 @@ interface SnapResult {
|
|
|
1132
1619
|
* closest in-threshold pair per axis as an adjustment. Targets are the page box
|
|
1133
1620
|
* (edges + center) and every non-moving annotation on the page.
|
|
1134
1621
|
*/
|
|
1135
|
-
declare function computeMoveSnap(
|
|
1622
|
+
declare function computeMoveSnap(model: Model, ids: Id[], page: PageRef, raw: Point, threshold: number, pageBox: Rect | undefined): SnapResult;
|
|
1136
1623
|
//#endregion
|
|
1137
1624
|
//#region src/view.d.ts
|
|
1138
|
-
|
|
1625
|
+
/** A note's or file attachment's icon: what its live drawing draws. */
|
|
1626
|
+
declare const iconOf: (annotation: Annotation) => Pick<RenderItem, "icon">;
|
|
1627
|
+
/**
|
|
1628
|
+
* How an annotation not made yet paints, drawn as it will be once made: a
|
|
1629
|
+
* drawing in progress (`draft`) or the tool's ghost (`ghost`, what a click
|
|
1630
|
+
* would place). `annotation` is what the tool creates, its defaults and
|
|
1631
|
+
* flags; `shape` is where it goes, as the made one will store it, so a
|
|
1632
|
+
* screen-anchored icon shows at its size on screen, as a made one does.
|
|
1633
|
+
*/
|
|
1634
|
+
declare function unmadeItem(id: Id, annotation: Annotation, shape: Shape, source: 'draft' | 'ghost', view?: ViewEnv, measure?: MeasurementAppearance): RenderItem;
|
|
1635
|
+
declare function pageItems(model: Model, page: PageRef, view?: ViewEnv): RenderItem[];
|
|
1139
1636
|
/** One free-text box, geometry only (the live move/resize gesture applied), with
|
|
1140
1637
|
* its edit flag. The framework renders an editable element here; the plugin
|
|
1141
1638
|
* layers the DTO-derived text style on top. */
|
|
@@ -1143,95 +1640,125 @@ interface TextBox {
|
|
|
1143
1640
|
id: Id;
|
|
1144
1641
|
box: Rect;
|
|
1145
1642
|
editing: boolean;
|
|
1146
|
-
/** Applied rotation (deg, CW). `box` is the
|
|
1643
|
+
/** Applied rotation (deg, CW). `box` is the unrotated text box; the framework
|
|
1147
1644
|
* rotates the editable element about its centre by this. 0/undefined = none. */
|
|
1148
1645
|
rot?: number;
|
|
1149
1646
|
}
|
|
1150
1647
|
/** The free-text boxes on a page — the text counterpart of `pageItems`. */
|
|
1151
|
-
declare function textBoxes(
|
|
1648
|
+
declare function textBoxes(model: Model, page: PageRef, view?: ViewEnv): TextBox[];
|
|
1152
1649
|
/** The currently selected annotations as render items (live gesture applied) —
|
|
1153
1650
|
* cross-page, for selection-aware toolbars (style + line-ending editing). */
|
|
1154
|
-
declare function selectedItems(
|
|
1651
|
+
declare function selectedItems(model: Model, view?: ViewEnv): RenderItem[];
|
|
1155
1652
|
/**
|
|
1156
|
-
* The rotate knob for the current selection on `
|
|
1653
|
+
* The rotate knob for the current selection on `page` — the same knob `chrome`
|
|
1157
1654
|
* draws — or null when the selection has none (non-rotatable single, or a group
|
|
1158
1655
|
* whose caps aren't rotatable). A single shape's knob hangs off its OBB top edge;
|
|
1159
|
-
* a group's off the union box. With `pageBox` the knob is placed
|
|
1656
|
+
* a group's off the union box. With `pageBox` the knob is placed page-bound
|
|
1160
1657
|
* (`placeRotateKnob`: flip below / clamp inside) — off-page it would be visible
|
|
1161
1658
|
* but unreachable, since pointer dispatch resolves pages by containment. Shared
|
|
1162
1659
|
* by `chrome` (to draw) and `selectionAnchor` (to push the menu clear of it), so
|
|
1163
1660
|
* the two can never disagree on where it is.
|
|
1164
1661
|
*
|
|
1165
|
-
* The placement
|
|
1662
|
+
* The placement decision is made at rest; a gesture never re-decides — it rides.
|
|
1166
1663
|
* During a live rotate the knob starts exactly where it was grabbed (the rest
|
|
1167
|
-
* placement on the
|
|
1664
|
+
* placement on the committed geometry) and turns rigidly about the pivot by the
|
|
1168
1665
|
* same snapped delta the shape uses; the policy re-evaluates only on release.
|
|
1169
1666
|
* Re-deciding per frame would jump at grab and side-switch mid-spin.
|
|
1170
1667
|
*/
|
|
1171
|
-
declare function selectionKnob(
|
|
1172
|
-
at:
|
|
1173
|
-
from:
|
|
1668
|
+
declare function selectionKnob(model: Model, page: PageRef, pageBox?: Rect, knobOffset?: number, view?: ViewEnv): {
|
|
1669
|
+
at: Point;
|
|
1670
|
+
from: Point;
|
|
1174
1671
|
} | null;
|
|
1175
|
-
declare function chrome(
|
|
1176
|
-
/** The
|
|
1177
|
-
* the page holds none. This is the
|
|
1672
|
+
declare function chrome(model: Model, page: PageRef, pageBox?: Rect, knobOffset?: number, view?: ViewEnv): ChromeNode[];
|
|
1673
|
+
/** The page-space union of the selectable selected items on `page`, or null if
|
|
1674
|
+
* the page holds none. This is the same box the chrome outline draws, so a
|
|
1178
1675
|
* floating menu sits exactly on the selection. */
|
|
1179
|
-
declare function selectionBoundsOnPage(
|
|
1180
|
-
/** The anchor for a selection-aware floating menu: the
|
|
1676
|
+
declare function selectionBoundsOnPage(model: Model, page: PageRef, view?: ViewEnv): Rect | null;
|
|
1677
|
+
/** The anchor for a selection-aware floating menu: the primary page (the first
|
|
1181
1678
|
* selectable selected id) + the union box of the selection on that page (content
|
|
1182
1679
|
* space). Null when nothing selectable is selected. A cross-page selection
|
|
1183
1680
|
* anchors to its primary page, so there is exactly one menu. `pageBoxOf` is a
|
|
1184
1681
|
* lookup (the anchor resolves its own page) feeding the page-bound knob
|
|
1185
|
-
* placement — the menu then dodges the knob where it
|
|
1186
|
-
declare function selectionAnchor(
|
|
1187
|
-
|
|
1682
|
+
* placement — the menu then dodges the knob where it actually sits. */
|
|
1683
|
+
declare function selectionAnchor(model: Model, pageBoxOf?: (page: PageRef) => Rect | undefined, knobOffsetOf?: (page: PageRef) => number | undefined, viewOf?: (page: PageRef) => ViewEnv | undefined): {
|
|
1684
|
+
page: PageRef;
|
|
1188
1685
|
bounds: Rect;
|
|
1189
|
-
knob?:
|
|
1686
|
+
knob?: Point;
|
|
1190
1687
|
} | null;
|
|
1191
1688
|
/** Anchor for controls that finish/cancel an active multi-click creation draft.
|
|
1192
1689
|
* It is rect-based like selectionAnchor, using the committed vertices only so
|
|
1193
1690
|
* the menu remains stable while the hover preview follows the pointer. */
|
|
1194
|
-
|
|
1691
|
+
/**
|
|
1692
|
+
* The rotation in progress, for the badge that follows the pointer: `null`
|
|
1693
|
+
* when nothing is being turned. The badge is a screen overlay, so it stays
|
|
1694
|
+
* upright however the page is shown.
|
|
1695
|
+
*/
|
|
1696
|
+
declare function rotationAnchor(model: Model): RotationAnchor | null;
|
|
1697
|
+
declare function creationDraftAnchor(model: Model): CreationDraftAnchor | null;
|
|
1698
|
+
/**
|
|
1699
|
+
* Where UI attaches to one annotation: its page and the box around what it
|
|
1700
|
+
* shows, a gesture in progress included, so an overlay follows a drag. `null`
|
|
1701
|
+
* for a record the model doesn't have.
|
|
1702
|
+
*/
|
|
1703
|
+
declare function annotationAnchor(model: Model, id: Id, view?: ViewEnv): {
|
|
1704
|
+
page: PageRef;
|
|
1705
|
+
bounds: Rect;
|
|
1706
|
+
} | null;
|
|
1195
1707
|
//#endregion
|
|
1196
1708
|
//#region src/hit.d.ts
|
|
1197
1709
|
type Target = {
|
|
1198
|
-
|
|
1710
|
+
kind: 'handle';
|
|
1199
1711
|
id: Id;
|
|
1200
1712
|
handle: string;
|
|
1201
1713
|
cursor: Cursor;
|
|
1202
1714
|
} | {
|
|
1203
|
-
|
|
1715
|
+
kind: 'rotate';
|
|
1204
1716
|
ids: Id[];
|
|
1205
|
-
pivot:
|
|
1717
|
+
pivot: Point;
|
|
1206
1718
|
} | {
|
|
1207
|
-
|
|
1719
|
+
kind: 'group-handle';
|
|
1208
1720
|
ids: Id[];
|
|
1209
1721
|
handle: string;
|
|
1210
1722
|
cursor: Cursor;
|
|
1211
1723
|
box: Rect;
|
|
1212
1724
|
} | {
|
|
1213
|
-
|
|
1725
|
+
kind: 'annot';
|
|
1214
1726
|
id: Id;
|
|
1215
1727
|
} | {
|
|
1216
|
-
|
|
1728
|
+
kind: 'empty';
|
|
1217
1729
|
};
|
|
1218
1730
|
/** Can this annotation be clicked to select? (`/F` interaction flags override
|
|
1219
|
-
* all caps — hidden/noView/readOnly are inert;
|
|
1731
|
+
* all caps — hidden/noView/readOnly are inert; locked stays selectable, it
|
|
1220
1732
|
* just won't transform.) */
|
|
1221
|
-
declare const isSelectable: (
|
|
1222
|
-
/** Can this annotation be dragged by its body to move? (`locked`
|
|
1223
|
-
|
|
1733
|
+
declare const isSelectable: (model: Model, id: Id) => boolean;
|
|
1734
|
+
/** Can this annotation be dragged by its body to move? (`locked` and the
|
|
1735
|
+
* session's `editable` rule freeze it.) */
|
|
1736
|
+
declare const canMove: (model: Model, id: Id) => boolean;
|
|
1737
|
+
/**
|
|
1738
|
+
* What an annotation paints where the pointer meets it (`painted.ts`): its
|
|
1739
|
+
* shape's pieces, projected as a screen-anchored body shows at `view`, and a
|
|
1740
|
+
* measurement's caption, dimension line and leaders. A click and the marquee
|
|
1741
|
+
* both read this.
|
|
1742
|
+
*/
|
|
1743
|
+
declare function paintedOf(record: ModelAnnotation, view?: ViewEnv): readonly PaintedPiece[];
|
|
1224
1744
|
/**
|
|
1225
|
-
*
|
|
1745
|
+
* Is `point` on a text box's own box, where its text is? Not on a callout's
|
|
1746
|
+
* line, and not in the empty rest of its frame. `margin` reaches the resize
|
|
1747
|
+
* handles on its border. The box is tested where the page shows it, as a
|
|
1748
|
+
* click tests it.
|
|
1749
|
+
*/
|
|
1750
|
+
declare function isOnTextBox(record: ModelAnnotation, point: Point, margin: number, view?: ViewEnv): boolean;
|
|
1751
|
+
/**
|
|
1752
|
+
* What's under the page point.
|
|
1226
1753
|
* 1. a resize/vertex handle of the single selection,
|
|
1227
|
-
* 2. an editable annotation body — a
|
|
1228
|
-
* can drag to move it), an
|
|
1754
|
+
* 2. an editable annotation body — a selected one anywhere in its bounds (so you
|
|
1755
|
+
* can drag to move it), an unselected one only on its stroke/fill (margin-aware,
|
|
1229
1756
|
* so an unfilled circle is grabbed only on its outline),
|
|
1230
1757
|
* 3. else empty.
|
|
1231
1758
|
*/
|
|
1232
|
-
declare function hitTest(
|
|
1759
|
+
declare function hitTest(model: Model, page: PageRef, point: Point, chromeGeometry: ChromeGeometry, strokeMargin: number, pageBox?: Rect, inert?: ReadonlySet<Id>, view?: ViewEnv): Target;
|
|
1233
1760
|
/** The cursor to show on hover: a resize cursor over a handle, move/pointer over a body. */
|
|
1234
|
-
declare function cursorAt(
|
|
1761
|
+
declare function cursorAt(model: Model, page: PageRef, point: Point, geometry: ChromeGeometry, strokeMargin: number, pageBox?: Rect, inert?: ReadonlySet<Id>, view?: ViewEnv): Cursor | null;
|
|
1235
1762
|
//#endregion
|
|
1236
1763
|
//#region src/richtext.d.ts
|
|
1237
1764
|
type RichTextStyleDelta = Partial<RichTextRunStyle>;
|
|
@@ -1245,7 +1772,7 @@ declare function richTextLength(doc: {
|
|
|
1245
1772
|
paragraphs: readonly RichTextParagraph[];
|
|
1246
1773
|
}): number;
|
|
1247
1774
|
/** Two deltas override the same properties with the same values. */
|
|
1248
|
-
declare function sameStyleDelta(
|
|
1775
|
+
declare function sameStyleDelta(left: RichTextStyleDelta | undefined, right: RichTextStyleDelta | undefined): boolean;
|
|
1249
1776
|
/**
|
|
1250
1777
|
* Merge adjacent runs whose deltas agree, drop empty runs, strip empty
|
|
1251
1778
|
* deltas. A paragraph with no text keeps a single empty run so the editor
|
|
@@ -1296,13 +1823,38 @@ declare function plainTextOf(doc: {
|
|
|
1296
1823
|
/** True when nothing in the document overrides the body: no run delta, no
|
|
1297
1824
|
* paragraph property. Such a document commits as plain `contents`. */
|
|
1298
1825
|
declare function isPlainRichText(doc: RichTextDocumentInput): boolean;
|
|
1826
|
+
/** The registered fonts an engine knows (the local engine's `fonts.list()`;
|
|
1827
|
+
* none on the cloud engine). */
|
|
1828
|
+
type FontLookup = () => readonly FontHandle[];
|
|
1829
|
+
/** The face a DTO font names: a standard font's family, weight and italic, a
|
|
1830
|
+
* registered key's identity, else the string itself as a family. */
|
|
1831
|
+
declare const faceForFont: (font: string, fonts?: FontLookup) => FaceRequest;
|
|
1832
|
+
/** The rich body the `/DA` text style describes (a draft's body before its
|
|
1833
|
+
* DTO exists; also the fallback for a DTO without `richText`). */
|
|
1834
|
+
declare function bodyFromTextStyle(style: TextStyle, fonts?: FontLookup): RichTextBody;
|
|
1835
|
+
/** The annotation's rich document: a free text's own, else one made from
|
|
1836
|
+
* its plain text and how its text is set. */
|
|
1837
|
+
declare function richDocOf(annotation: Annotation, fonts?: FontLookup): RichTextDocument;
|
|
1838
|
+
//#endregion
|
|
1839
|
+
//#region src/font-css.d.ts
|
|
1840
|
+
type StandardFamily = (typeof STANDARD_FACES)[keyof typeof STANDARD_FACES]['family'];
|
|
1841
|
+
/** Web stacks with the standard families' metrics. */
|
|
1842
|
+
declare const STANDARD_FONT_STACKS: Readonly<Record<StandardFamily, string>>;
|
|
1843
|
+
/**
|
|
1844
|
+
* The family `mountWebFont` (`@embedpdf/web`) mounts a registered font's key
|
|
1845
|
+
* under: namespaced, so a page's own family of the same name never stands in
|
|
1846
|
+
* for it.
|
|
1847
|
+
*/
|
|
1848
|
+
declare const mountedFontFamily: (key: string) => string;
|
|
1849
|
+
/** The CSS family list for a DTO font: a standard kebab name or a registered key. */
|
|
1850
|
+
declare function cssFontFamilyForFont(font: string): string;
|
|
1299
1851
|
//#endregion
|
|
1300
1852
|
//#region src/group.d.ts
|
|
1301
1853
|
/**
|
|
1302
1854
|
* The transform capabilities of a multi-target (group) selection: a group can
|
|
1303
|
-
* move/resize/rotate only if
|
|
1304
|
-
* member is locked. This is the
|
|
1305
|
-
*
|
|
1855
|
+
* move/resize/rotate only if every member's kind allows that group op and no
|
|
1856
|
+
* member is locked or frozen by the session's `editable` rule. This is the single resolver every adapter consumes, so no
|
|
1857
|
+
* framework component re-derives the rule. The iso-vs-
|
|
1306
1858
|
* aniso resize choice is computed separately, per-gesture, since it depends on
|
|
1307
1859
|
* the live `rot` of the members, not the static caps.
|
|
1308
1860
|
*/
|
|
@@ -1311,135 +1863,162 @@ interface GroupCaps {
|
|
|
1311
1863
|
resizable: boolean;
|
|
1312
1864
|
rotatable: boolean;
|
|
1313
1865
|
}
|
|
1314
|
-
declare function groupCaps(
|
|
1866
|
+
declare function groupCaps(model: Model, ids: Id[]): GroupCaps;
|
|
1315
1867
|
/**
|
|
1316
1868
|
* The key of the group `id` belongs to, or `null` when it is ungrouped. A
|
|
1317
|
-
* subordinate's key is its `
|
|
1318
|
-
*
|
|
1869
|
+
* subordinate's key is its `groupOf`; a primary's key is its own id (it is the
|
|
1870
|
+
* target of at least one member's `groupOf`). An annotation that is neither a
|
|
1319
1871
|
* subordinate nor the target of any subordinate is ungrouped.
|
|
1320
1872
|
*/
|
|
1321
|
-
declare function groupKeyOf(
|
|
1873
|
+
declare function groupKeyOf(model: Model, id: Id): Id | null;
|
|
1322
1874
|
/**
|
|
1323
1875
|
* Every member of the group containing `id` (primary first), or just `[id]`
|
|
1324
1876
|
* when it is ungrouped. The primary is the annotation whose id is the key; the
|
|
1325
|
-
* rest are everything whose `
|
|
1877
|
+
* rest are everything whose `groupOf` equals the key, in `order`.
|
|
1326
1878
|
*/
|
|
1327
|
-
declare function groupMembers(
|
|
1879
|
+
declare function groupMembers(model: Model, id: Id): Id[];
|
|
1328
1880
|
/** Union of every id's full group — the selection seen as whole groups. */
|
|
1329
|
-
declare function expandGroups(
|
|
1881
|
+
declare function expandGroups(model: Model, ids: Id[]): Id[];
|
|
1330
1882
|
//#endregion
|
|
1331
1883
|
//#region src/plane.d.ts
|
|
1332
1884
|
/** True when this annotation belongs to the conversation plane only —
|
|
1333
1885
|
* never painted, hit, marquee-selected, or counted into a page's
|
|
1334
1886
|
* appearance epoch. */
|
|
1335
|
-
declare function isConversationOnly(
|
|
1887
|
+
declare function isConversationOnly(record: Pick<ModelAnnotation, 'annotation'>): boolean;
|
|
1336
1888
|
/**
|
|
1337
|
-
* A link
|
|
1889
|
+
* A link child attached to another annotation — a `/Link` grouped
|
|
1338
1890
|
* (`/IRT` + `/RT /Group`) under a non-link parent. Pure substrate: it is
|
|
1339
|
-
* the parent's `link`
|
|
1891
|
+
* the parent's `link` property while authoring (derived via `linkOf`) and
|
|
1340
1892
|
* the navigation plane's anchor while reading — never painted, never hit
|
|
1341
|
-
* as itself. Its rect is
|
|
1893
|
+
* as itself. Its rect is reconciled from the parent's geometry, so direct
|
|
1342
1894
|
* manipulation would be overwritten anyway.
|
|
1343
1895
|
*/
|
|
1344
|
-
declare function isAttachedLink(
|
|
1896
|
+
declare function isAttachedLink(record: Pick<ModelAnnotation, 'annotation'>): boolean;
|
|
1345
1897
|
/**
|
|
1346
|
-
* The
|
|
1898
|
+
* The one page-surface cull: everything that lives in the substrate but is
|
|
1347
1899
|
* not a page visual of its own — conversation members (replies, review
|
|
1348
1900
|
* states) and attached link children. Paint order, hit-testing, marquee
|
|
1349
|
-
* and the appearance epoch all filter through
|
|
1901
|
+
* and the appearance epoch all filter through this, never the parts.
|
|
1350
1902
|
*/
|
|
1351
|
-
declare function isSubstrateOnly(
|
|
1903
|
+
declare function isSubstrateOnly(record: Pick<ModelAnnotation, 'annotation'>): boolean;
|
|
1352
1904
|
//#endregion
|
|
1353
1905
|
//#region src/links.d.ts
|
|
1354
1906
|
/** Every attached link child of `parentId`, in z-order (multi-segment
|
|
1355
1907
|
* markup parents carry several children with one shared target). */
|
|
1356
|
-
declare function linkChildrenOf(
|
|
1908
|
+
declare function linkChildrenOf(model: Model, parentId: Id): ModelAnnotation[];
|
|
1357
1909
|
/** The parent's link target, derived from its first attached child — the
|
|
1358
1910
|
* read side of the `syncLink` reconciler. Null when no child exists. */
|
|
1359
|
-
declare function linkOf(
|
|
1911
|
+
declare function linkOf(model: Model, parentId: Id): PdfLinkTarget | null;
|
|
1912
|
+
//#endregion
|
|
1913
|
+
//#region src/shapes/index.d.ts
|
|
1914
|
+
/**
|
|
1915
|
+
* The family that answers for `shape`. Each family works on its own shapes
|
|
1916
|
+
* only; looking it up by the shape's `kind` is what hands it one.
|
|
1917
|
+
*/
|
|
1918
|
+
declare const familyOf: (shape: Shape) => ShapeFamily;
|
|
1919
|
+
/**
|
|
1920
|
+
* The family of a kind whose annotation says which shape it has: `pick`
|
|
1921
|
+
* names the family that reads it, and the shape's own family does the rest.
|
|
1922
|
+
*/
|
|
1923
|
+
declare function familyChosenBy(pick: (annotation: Annotation) => ShapeFamily): ShapeFamily;
|
|
1360
1924
|
//#endregion
|
|
1361
|
-
//#region src/kinds.d.ts
|
|
1925
|
+
//#region src/kinds/define.d.ts
|
|
1926
|
+
/** The flags an annotation carries, each a `flag` property of every kind. */
|
|
1927
|
+
type FlagKey = 'invisible' | 'hidden' | 'print' | 'noZoom' | 'noRotate' | 'noView' | 'readOnly' | 'locked' | 'toggleNoView' | 'lockedContents';
|
|
1928
|
+
/**
|
|
1929
|
+
* One choice of a `choice` property, as a picker shows it: the value it
|
|
1930
|
+
* writes, and its name, `label` in English and `labelKey` to translate it
|
|
1931
|
+
* (`annotation.lineEndings.openArrow`).
|
|
1932
|
+
*/
|
|
1933
|
+
interface AnnotationOption {
|
|
1934
|
+
readonly value: string;
|
|
1935
|
+
readonly label: string;
|
|
1936
|
+
readonly labelKey: string;
|
|
1937
|
+
}
|
|
1362
1938
|
/**
|
|
1363
|
-
* One
|
|
1364
|
-
*
|
|
1365
|
-
*
|
|
1366
|
-
*
|
|
1367
|
-
*
|
|
1939
|
+
* One property a style panel edits, as a UI contract: which field, edited
|
|
1940
|
+
* with which control, labelled what. A panel switches on `control` (or on
|
|
1941
|
+
* `key`, for a richer editor of its own), reads `values[property.key]` and
|
|
1942
|
+
* writes `{ [property.key]: value }`, so each kind's list is its property
|
|
1943
|
+
* schema, kept in the library so every consumer gets it for free.
|
|
1368
1944
|
*
|
|
1369
|
-
* `
|
|
1370
|
-
*
|
|
1945
|
+
* `key` is the engine's field name, with three exceptions: the border's
|
|
1946
|
+
* `borderStyle` reads and writes `borderStyle`, `dashArray` and
|
|
1947
|
+
* `cloudyIntensity` together; `bold`, `italic` and `underline` are the rich
|
|
1948
|
+
* body's formatting; and `link` is an attached link, not a field of the
|
|
1949
|
+
* annotation.
|
|
1950
|
+
*
|
|
1951
|
+
* `label` is the English name and `labelKey` its translation key: a panel
|
|
1952
|
+
* shows `t(property.labelKey, { fallback: property.label })`, as a command's
|
|
1953
|
+
* label reads. The key names the wording, not the field, since one field is
|
|
1954
|
+
* called different things by different kinds: `color` is
|
|
1955
|
+
* `annotation.style.stroke` on a shape and `annotation.style.outline` on a
|
|
1956
|
+
* redaction mark. A `choice` property's options carry the same pair. Array
|
|
1957
|
+
* order is display order.
|
|
1371
1958
|
*/
|
|
1372
|
-
type
|
|
1373
|
-
key: 'color';
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
label: string;
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
max: number;
|
|
1386
|
-
step: number;
|
|
1387
|
-
} | {
|
|
1388
|
-
key: 'strokeWidth';
|
|
1389
|
-
label: string;
|
|
1390
|
-
min: number;
|
|
1391
|
-
max: number;
|
|
1392
|
-
step: number;
|
|
1393
|
-
} | {
|
|
1394
|
-
key: 'fontSize';
|
|
1395
|
-
label: string;
|
|
1396
|
-
min: number;
|
|
1397
|
-
max: number;
|
|
1398
|
-
step: number;
|
|
1959
|
+
type AnnotationProperty = {
|
|
1960
|
+
readonly key: 'color' | 'interiorColor' | 'fontColor';
|
|
1961
|
+
readonly control: 'color';
|
|
1962
|
+
readonly label: string;
|
|
1963
|
+
readonly labelKey: string;
|
|
1964
|
+
} | {
|
|
1965
|
+
readonly key: 'opacity' | 'strokeWidth' | 'fontSize';
|
|
1966
|
+
readonly control: 'number';
|
|
1967
|
+
readonly label: string;
|
|
1968
|
+
readonly labelKey: string;
|
|
1969
|
+
readonly min: number;
|
|
1970
|
+
readonly max: number;
|
|
1971
|
+
readonly step: number;
|
|
1399
1972
|
} |
|
|
1400
|
-
/**
|
|
1973
|
+
/** The border over `borderStyle`, `dashArray` and `cloudyIntensity`;
|
|
1974
|
+
* `cloudy` says whether this kind takes a cloudy border. */
|
|
1401
1975
|
{
|
|
1402
|
-
key: '
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
} | {
|
|
1409
|
-
key: 'fontFamily';
|
|
1410
|
-
label: string;
|
|
1411
|
-
} | {
|
|
1412
|
-
key: 'textAlign';
|
|
1413
|
-
label: string;
|
|
1976
|
+
readonly key: 'borderStyle';
|
|
1977
|
+
readonly control: 'choice';
|
|
1978
|
+
readonly label: string;
|
|
1979
|
+
readonly labelKey: string;
|
|
1980
|
+
readonly options: readonly AnnotationOption[];
|
|
1981
|
+
readonly cloudy: boolean;
|
|
1414
1982
|
} |
|
|
1415
|
-
/**
|
|
1416
|
-
* while the text editor has a range — that range's runs. */
|
|
1983
|
+
/** A value from a list: line endings, a font, an alignment, a blend mode, an icon. */
|
|
1417
1984
|
{
|
|
1418
|
-
key: '
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
} |
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
label: string;
|
|
1985
|
+
readonly key: 'lineEndings' | 'fontFamily' | 'textAlign' | 'blendMode' | 'icon';
|
|
1986
|
+
readonly control: 'choice';
|
|
1987
|
+
readonly label: string;
|
|
1988
|
+
readonly labelKey: string;
|
|
1989
|
+
readonly options: readonly AnnotationOption[];
|
|
1990
|
+
} |
|
|
1991
|
+
/** One of the annotation's flags, on or off. */
|
|
1992
|
+
{
|
|
1993
|
+
readonly key: FlagKey;
|
|
1994
|
+
readonly control: 'flag';
|
|
1995
|
+
readonly label: string;
|
|
1996
|
+
readonly labelKey: string;
|
|
1997
|
+
} |
|
|
1998
|
+
/** Free text, such as a redaction's label. */
|
|
1999
|
+
{
|
|
2000
|
+
readonly key: 'overlayText';
|
|
2001
|
+
readonly control: 'text';
|
|
2002
|
+
readonly label: string;
|
|
2003
|
+
readonly labelKey: string;
|
|
1429
2004
|
} |
|
|
1430
|
-
/**
|
|
2005
|
+
/** Bold, italic or underline of a text box: the body's formatting, or,
|
|
2006
|
+
* while the text editor has a range, that range's runs. */
|
|
1431
2007
|
{
|
|
1432
|
-
key: '
|
|
1433
|
-
|
|
1434
|
-
|
|
2008
|
+
readonly key: 'bold' | 'italic' | 'underline';
|
|
2009
|
+
readonly control: 'textFormat';
|
|
2010
|
+
readonly label: string;
|
|
2011
|
+
readonly labelKey: string;
|
|
2012
|
+
readonly format: 'bold' | 'italic' | 'underline';
|
|
1435
2013
|
} |
|
|
1436
|
-
/**
|
|
1437
|
-
*
|
|
1438
|
-
*
|
|
1439
|
-
* `applyProps` drops the key and menus never show the control. */
|
|
2014
|
+
/** Where it links to (a website or a page). Declared by the link kind (its
|
|
2015
|
+
* own target) and by every kind that may carry an attached link; kinds
|
|
2016
|
+
* that omit it (widgets, caret, redaction…) can't be links. */
|
|
1440
2017
|
{
|
|
1441
|
-
key: 'link';
|
|
1442
|
-
|
|
2018
|
+
readonly key: 'link';
|
|
2019
|
+
readonly control: 'link';
|
|
2020
|
+
readonly label: string;
|
|
2021
|
+
readonly labelKey: string;
|
|
1443
2022
|
};
|
|
1444
2023
|
/** Orthogonal capability flags. Static data — the annotation's `/F` flags are
|
|
1445
2024
|
* the runtime overrides (a locked annotation is never transformable, a hidden
|
|
@@ -1455,13 +2034,13 @@ interface KindCaps {
|
|
|
1455
2034
|
vertexEditable: boolean;
|
|
1456
2035
|
/** Can be rotated (shapes, free text, lines/polys/ink). */
|
|
1457
2036
|
rotatable: boolean;
|
|
1458
|
-
/** Can be
|
|
2037
|
+
/** Can be moved as part of a multi-target (group) transform. */
|
|
1459
2038
|
groupMovable: boolean;
|
|
1460
|
-
/** Can be uniformly
|
|
2039
|
+
/** Can be uniformly scaled as part of a multi-target (group) transform — on
|
|
1461
2040
|
* even for vertex kinds that have no single-shape box resize (their handles
|
|
1462
|
-
*
|
|
2041
|
+
* are the vertices; in a group they scale fine). */
|
|
1463
2042
|
groupResizable: boolean;
|
|
1464
|
-
/** Can be
|
|
2043
|
+
/** Can be rotated as part of a multi-target (group) transform. */
|
|
1465
2044
|
groupRotatable: boolean;
|
|
1466
2045
|
/** Carries editable text content (free text, the comment popup). */
|
|
1467
2046
|
textEditable: boolean;
|
|
@@ -1471,6 +2050,8 @@ interface KindCaps {
|
|
|
1471
2050
|
hasPopup: boolean;
|
|
1472
2051
|
/** Bound to underlying text (markup, caret) — never freely moved/resized. */
|
|
1473
2052
|
anchored: boolean;
|
|
2053
|
+
/** Paints with the page's text, beneath every other kind (text markup, redaction marks). */
|
|
2054
|
+
paintsBeneath: boolean;
|
|
1474
2055
|
/** Has an interior fill (`/IC`). */
|
|
1475
2056
|
hasFill: boolean;
|
|
1476
2057
|
/** Has line endings (`/LE` — line, polyline). */
|
|
@@ -1478,10 +2059,15 @@ interface KindCaps {
|
|
|
1478
2059
|
/** Can take a cloudy border effect (`/BE` — shapes). */
|
|
1479
2060
|
hasCloudy: boolean;
|
|
1480
2061
|
/** The whole body is visible content, so hit-testing grabs anywhere inside
|
|
1481
|
-
* the box (stamp images) —
|
|
2062
|
+
* the box (stamp images, note icons) — not just the stroke/fill like
|
|
2063
|
+
* outline shapes. */
|
|
1482
2064
|
opaqueBody: boolean;
|
|
1483
|
-
/**
|
|
1484
|
-
*
|
|
2065
|
+
/** Its raster is its drawing, drawn where its shape is: the kind draws none
|
|
2066
|
+
* of it live (a stamp's image, a form widget, a link's border). A lent
|
|
2067
|
+
* record can still draw live with its lender's painter (`drawsLive`). */
|
|
2068
|
+
rasterOnly: boolean;
|
|
2069
|
+
/** The `/F` ReadOnly flag is ignored for this kind (ISO 32000: widgets — a
|
|
2070
|
+
* ReadOnly form field must still be movable by a form designer; the
|
|
1485
2071
|
* form-filling layer enforces field ReadOnly itself). */
|
|
1486
2072
|
ignoresReadOnly: boolean;
|
|
1487
2073
|
/** Behaves as if `/F` NoZoom is always set (screen-constant size — the
|
|
@@ -1491,270 +2077,240 @@ interface KindCaps {
|
|
|
1491
2077
|
* rule for Text/note icons). See anchor.ts. */
|
|
1492
2078
|
noRotate: boolean;
|
|
1493
2079
|
}
|
|
2080
|
+
/** No capability at all: a kind spreads this and turns on what it can do. */
|
|
2081
|
+
declare const NO_CAPS: KindCaps;
|
|
2082
|
+
/** One annotation kind: what it is, and what a user can do to it. */
|
|
1494
2083
|
interface AnnotationKind {
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
2084
|
+
/** Its name: the PDF subtype, or a widget's field family (`widget-text`…). */
|
|
2085
|
+
readonly name: string;
|
|
2086
|
+
/**
|
|
2087
|
+
* The shape family that reads its shape off the annotation (`shapes/`).
|
|
2088
|
+
* The shape's family then hits, handles, moves and draws it.
|
|
2089
|
+
*/
|
|
2090
|
+
readonly family: ShapeFamily;
|
|
2091
|
+
/**
|
|
2092
|
+
* How it is drawn: its colours, stroke and border, read off the annotation
|
|
2093
|
+
* with its kind's fill-ins (`styles.ts`).
|
|
2094
|
+
*/
|
|
2095
|
+
readonly style: (annotation: Annotation) => Style;
|
|
2096
|
+
/**
|
|
2097
|
+
* How its text is set, for a kind with text: its font, size, colour and
|
|
2098
|
+
* alignment, read off the annotation (`texts.ts`).
|
|
2099
|
+
*/
|
|
2100
|
+
readonly text?: (annotation: Annotation) => TextStyle;
|
|
2101
|
+
/** What a user can do to it. The annotation's `/F` flags override these at runtime (flags.ts). */
|
|
2102
|
+
readonly caps: KindCaps;
|
|
2103
|
+
/**
|
|
2104
|
+
* What a style panel edits, in display order, keyed by the engine's field
|
|
2105
|
+
* names. The flags every kind has are added by `propertiesOf`.
|
|
2106
|
+
*/
|
|
2107
|
+
readonly properties: readonly AnnotationProperty[];
|
|
1503
2108
|
}
|
|
1504
|
-
/**
|
|
1505
|
-
*
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
declare const
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
2109
|
+
/**
|
|
2110
|
+
* Declares a kind. It returns the kind exactly as written: nothing is
|
|
2111
|
+
* registered and nothing is filled in. `index.ts` lists every kind.
|
|
2112
|
+
*/
|
|
2113
|
+
declare const defineKind: <const Kind extends AnnotationKind>(kind: Kind) => Kind;
|
|
2114
|
+
//#endregion
|
|
2115
|
+
//#region src/kinds/index.d.ts
|
|
2116
|
+
/** The kinds, by name. */
|
|
2117
|
+
declare const KINDS: Readonly<Record<string, AnnotationKind>>;
|
|
2118
|
+
/** The kind named `name`; a name no kind has reads as one that is only shown. */
|
|
2119
|
+
declare function kindNamed(name: string): AnnotationKind;
|
|
1512
2120
|
//#endregion
|
|
1513
2121
|
//#region src/props.d.ts
|
|
1514
2122
|
/** Base text styling for kinds/tools with no explicit defaults. */
|
|
1515
2123
|
declare const initialTextStyle: TextStyle;
|
|
1516
|
-
/**
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
2124
|
+
/** Does this kind's property table declare `link` (attachable link)? The link
|
|
2125
|
+
* kind itself also declares it, but stores its own `/A` instead. */
|
|
2126
|
+
declare const kindTakesLink: (kind: AnnotationKind) => boolean;
|
|
2127
|
+
/**
|
|
2128
|
+
* Everything a style panel edits for one kind: its own properties, then the
|
|
2129
|
+
* flags every kind has. The same array for a kind on every call.
|
|
2130
|
+
*/
|
|
2131
|
+
declare function propertiesOf(kind: AnnotationKind): readonly AnnotationProperty[];
|
|
1520
2132
|
/**
|
|
1521
|
-
*
|
|
1522
|
-
*
|
|
1523
|
-
*
|
|
2133
|
+
* The ordered properties every given kind has: the schema for a mixed
|
|
2134
|
+
* selection, in the first kind's display order. One kind: its own list
|
|
2135
|
+
* (`propertiesOf`), the same array every time.
|
|
1524
2136
|
*/
|
|
1525
|
-
declare function
|
|
2137
|
+
declare function sharedProperties(kinds: readonly AnnotationKind[]): readonly AnnotationProperty[];
|
|
2138
|
+
//#endregion
|
|
2139
|
+
//#region src/kinds/fields.d.ts
|
|
2140
|
+
/** Every line ending the engine draws. */
|
|
2141
|
+
declare const LINE_ENDING_NAMES: readonly ["none", "square", "circle", "diamond", "open-arrow", "closed-arrow", "butt", "r-open-arrow", "r-closed-arrow", "slash"];
|
|
2142
|
+
/** The flags every kind has, in the order a panel lists them. */
|
|
2143
|
+
declare const FLAG_PROPERTIES: readonly AnnotationProperty[];
|
|
2144
|
+
//#endregion
|
|
2145
|
+
//#region src/record/defaults.d.ts
|
|
2146
|
+
/** The engine subtype a client kind creates: a callout is a free text, a form tool's kind a widget. */
|
|
2147
|
+
declare const engineSubtypeOf: (kind: string) => AnnotationSubtype;
|
|
1526
2148
|
/**
|
|
1527
|
-
*
|
|
1528
|
-
*
|
|
1529
|
-
*
|
|
1530
|
-
* caller emits no spurious engine write. Flags themselves are NOT props: they
|
|
1531
|
-
* write through the `setFlags` message, which is deliberately not gated here
|
|
1532
|
-
* (unlocking must work on a locked annotation).
|
|
2149
|
+
* A tool's `defaults` over the engine's defaults for `kind`: what a create
|
|
2150
|
+
* from the tool starts from. A form tool's reads as a widget of its field
|
|
2151
|
+
* family, so it reads as the tool's own kind (a radio tool's is round).
|
|
1533
2152
|
*/
|
|
1534
|
-
declare function
|
|
2153
|
+
declare function readOfDefaults(kind: string, defaults: FieldValues): Annotation;
|
|
1535
2154
|
/**
|
|
1536
|
-
*
|
|
1537
|
-
*
|
|
2155
|
+
* A form tool's defaults as the engine's widget appearance for `doc.forms`
|
|
2156
|
+
* authoring: the widget's style fields among them, as they are. Absent fields
|
|
2157
|
+
* stay absent (the engine writes nothing for them).
|
|
1538
2158
|
*/
|
|
1539
|
-
declare function
|
|
2159
|
+
declare function widgetAppearanceOf(defaults: FieldValues): WidgetAppearance;
|
|
1540
2160
|
//#endregion
|
|
1541
2161
|
//#region src/geometry.d.ts
|
|
1542
|
-
type RectHandle = 'nw' | 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w';
|
|
1543
|
-
declare const RECT_HANDLES: RectHandle[];
|
|
1544
|
-
/** The resize cursor for a handle on a box tilted by `rot` deg: rotate the
|
|
1545
|
-
* handle's compass direction with the box and pick the nearest 45° sector.
|
|
1546
|
-
* At `rot = 0` this reproduces {@link RECT_CURSOR} exactly. */
|
|
1547
|
-
declare const rotatedHandleCursor: (h: RectHandle, rot: number) => Cursor;
|
|
1548
|
-
declare const rectFromPoints: (a: Vec, b: Vec) => Rect;
|
|
1549
|
-
declare function unionRect(pts: Vec[]): Rect;
|
|
1550
2162
|
/** How far (content units) the rotate knob hangs off the top edge of the box. */
|
|
1551
2163
|
declare const ROTATE_KNOB_OFFSET = 24;
|
|
1552
2164
|
/** Fallback chrome geometry (content units) when the caller supplies none —
|
|
1553
2165
|
* the pre-settings behavior, so bare-core callers and tests stay stable. */
|
|
1554
|
-
declare const
|
|
2166
|
+
declare const DEFAULT_CHROME_GEOMETRY: {
|
|
1555
2167
|
readonly handleTol: 6;
|
|
1556
2168
|
readonly knobTol: 6;
|
|
1557
2169
|
readonly knobOffset: 24;
|
|
1558
2170
|
};
|
|
1559
|
-
/**
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
*
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
*
|
|
1568
|
-
*
|
|
1569
|
-
*
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
declare function centroidOf(g: Geom): Vec;
|
|
2171
|
+
/** A geom's applied rotation (deg), or 0 for text markup. A caret's turn is
|
|
2172
|
+
* its text's baseline tilt: reported here so the renderer and selection
|
|
2173
|
+
* chrome follow it, while the caret's caps (not movable/resizable) keep
|
|
2174
|
+
* every rotate gesture away from it. */
|
|
2175
|
+
declare function geomRotation(geometry: Shape): number;
|
|
2176
|
+
/**
|
|
2177
|
+
* Where a turn of a single shape pivots, as the engine turns it: a box about
|
|
2178
|
+
* its own `rect` centre; a line, polygon, polyline or ink about the middle of
|
|
2179
|
+
* the box around its points upright. A turn then changes only the angle, never
|
|
2180
|
+
* where the upright points are, and a caption or an arrowhead never moves the
|
|
2181
|
+
* pivot.
|
|
2182
|
+
*/
|
|
2183
|
+
declare const turnPivotOf: (geometry: Shape) => Point;
|
|
1573
2184
|
/** Does the geometry carry a meaningful `rot` (an oriented local box exists)?
|
|
1574
|
-
*
|
|
2185
|
+
* Orientation is a geometry fact; whether the user may rotate is the separate
|
|
1575
2186
|
* `caps.rotatable` gate — a caret is oriented (it rides its text's tilt) yet
|
|
1576
2187
|
* offers no rotate gesture. */
|
|
1577
|
-
declare
|
|
1578
|
-
/**
|
|
1579
|
-
* Rotate a geom by `deltaDeg` (clockwise) about `pivot
|
|
1580
|
-
*
|
|
1581
|
-
*
|
|
1582
|
-
*
|
|
1583
|
-
*
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
* also the caret — oriented (`isRotatableGeom`) but text-anchored, so its tilt
|
|
1587
|
-
* is authoring metadata that no gesture edits (`geomResetRotation` still
|
|
1588
|
-
* clears it).
|
|
1589
|
-
*/
|
|
1590
|
-
declare function geomRotateAbout(g: Geom, pivot: Vec, deltaDeg: number): Geom;
|
|
1591
|
-
/** The AABB of `rect` rotated `deg` about its own centre. */
|
|
1592
|
-
declare function rotatedAabb(rect: Rect, deg: number): Rect;
|
|
2188
|
+
declare const isRotatableGeom: (geometry: Shape) => boolean;
|
|
2189
|
+
/**
|
|
2190
|
+
* Rotate a geom by `deltaDeg` (clockwise) about `pivot`: a box's middle
|
|
2191
|
+
* orbits the pivot and its turn grows, and so does a points shape's. A shape
|
|
2192
|
+
* without a rotate verb comes back unchanged: quads, a callout, and the
|
|
2193
|
+
* caret (oriented, but it follows its text; `geomResetRotation` still clears
|
|
2194
|
+
* its turn).
|
|
2195
|
+
*/
|
|
2196
|
+
declare function geomRotateAbout(geometry: Shape, pivot: Point, deltaDeg: number): Shape;
|
|
1593
2197
|
/**
|
|
1594
2198
|
* The counter-rotation (CW content degrees) that makes an annotation read
|
|
1595
2199
|
* upright at `displayRotation`: on screen the two compose to 0.
|
|
1596
2200
|
*/
|
|
1597
2201
|
declare const uprightRotation: (displayRotation: number) => number;
|
|
1598
|
-
/** `rect` with width↔height swapped about its own centre — the unrotated box
|
|
1599
|
-
* whose quarter-turn AABB is exactly `rect` again. */
|
|
1600
|
-
declare function transposedAboutCenter(rect: Rect): Rect;
|
|
1601
2202
|
/**
|
|
1602
|
-
* The unrotated content rect for a
|
|
2203
|
+
* The unrotated content rect for a default-size upright box "placed at" a
|
|
1603
2204
|
* point: positioned so that, after the upright counter-rotation, the box shows
|
|
1604
|
-
* `width`×`height` with its
|
|
2205
|
+
* `width`×`height` with its top-left at `anchor` in the rotated view — the
|
|
1605
2206
|
* same on-screen feel as the rotation-0 `{ x: anchor.x, y: anchor.y }` box at
|
|
1606
2207
|
* every quarter-turn (a click-created free-text box always opens down-right of
|
|
1607
2208
|
* the cursor as the author sees it). Derived by placing the box in the display
|
|
1608
2209
|
* frame and pulling its AABB back through the quarter-turn; the page dims
|
|
1609
2210
|
* cancel, so no page box is needed.
|
|
1610
2211
|
*/
|
|
1611
|
-
declare function uprightAnchoredRect(anchor:
|
|
2212
|
+
declare function uprightAnchoredRect(anchor: Point, width: number, height: number, displayRotation: number): Rect;
|
|
1612
2213
|
/**
|
|
1613
|
-
* The
|
|
2214
|
+
* The logical (unrotated) page-space box for a stamp placed at `center`,
|
|
1614
2215
|
* sized `desired` (points), fit onto the page and clamped fully within it —
|
|
1615
|
-
* the
|
|
2216
|
+
* the rubber-stamp rule: keep the image's own size unless it would overflow
|
|
1616
2217
|
* the page, then scale down (aspect preserved, never up) so it just fits.
|
|
1617
2218
|
*
|
|
1618
|
-
* Under an upright quarter-turn the on-page
|
|
1619
|
-
* (w↔h), so
|
|
2219
|
+
* Under an upright quarter-turn the on-page footprint is the box transposed
|
|
2220
|
+
* (w↔h), so both the fit and the edge clamp use that footprint — a landscape
|
|
1620
2221
|
* stamp uprighted onto a portrait page fits by its rotated silhouette, not its
|
|
1621
2222
|
* logical box. The box centre and its footprint AABB centre coincide (rotation
|
|
1622
2223
|
* is about the centre), so clamping one clamps the other.
|
|
1623
2224
|
*/
|
|
1624
|
-
declare function fitStampBox(center:
|
|
1625
|
-
/** Reset a geom to its as-authored orientation (
|
|
1626
|
-
*
|
|
1627
|
-
*
|
|
1628
|
-
declare function geomResetRotation(
|
|
2225
|
+
declare function fitStampBox(center: Point, desired: Size, page: Size, rotCW: number): Rect;
|
|
2226
|
+
/** Reset a geom to its as-authored orientation (turn → 0). Box: drop the turn.
|
|
2227
|
+
* Points: turn back about `pivot` (the middle of the upright points by
|
|
2228
|
+
* default, which only clears the turn). */
|
|
2229
|
+
declare function geomResetRotation(geometry: Shape, pivot?: Point): Shape;
|
|
1629
2230
|
/**
|
|
1630
2231
|
* The oriented selection box (OBB) of a rotatable geom: four corners (in order
|
|
1631
|
-
* nw, ne, se, sw of the
|
|
1632
|
-
* the
|
|
1633
|
-
*
|
|
1634
|
-
* shape, take that tight local box, then rotate it back — giving the snug tilted
|
|
2232
|
+
* nw, ne, se, sw of the local box, transformed) + the angle. For a box this is
|
|
2233
|
+
* the box rotated about its centre; for a points shape it is the drawn bounds
|
|
2234
|
+
* of its upright points, turned about their middle — the snug tilted
|
|
1635
2235
|
* rectangle. Returns null for non-rotatable kinds.
|
|
1636
2236
|
*/
|
|
1637
|
-
declare function obbFromGeom(
|
|
1638
|
-
corners: [
|
|
2237
|
+
declare function obbFromGeom(geometry: Shape, stroke: Stroke): {
|
|
2238
|
+
corners: [Point, Point, Point, Point];
|
|
1639
2239
|
angle: number;
|
|
1640
2240
|
} | null;
|
|
1641
|
-
/** The fixed point of a group resize: the
|
|
1642
|
-
declare function groupResizeAnchor(base: Rect, handle: string):
|
|
2241
|
+
/** The fixed point of a group resize: the opposite handle's point on the box. */
|
|
2242
|
+
declare function groupResizeAnchor(base: Rect, handle: string): Point;
|
|
1643
2243
|
/**
|
|
1644
2244
|
* The live group resize box for a drag. Anisotropic = the plain axis-aligned
|
|
1645
2245
|
* `resizeRect`; isotropic = a uniform scale of `base` about the anchor by the
|
|
1646
2246
|
* larger of the two drag ratios (so the preview matches the committed scale and
|
|
1647
2247
|
* never shears a rotated member).
|
|
1648
2248
|
*/
|
|
1649
|
-
declare function groupResizeBox(base: Rect, handle: string, to:
|
|
2249
|
+
declare function groupResizeBox(base: Rect, handle: string, to: Point, isotropic: boolean): Rect;
|
|
1650
2250
|
/** The (sx, sy) factors a `base`→`cur` group resize applied about its anchor. */
|
|
1651
|
-
declare function groupResizeFactors(base: Rect,
|
|
2251
|
+
declare function groupResizeFactors(base: Rect, current: Rect): {
|
|
1652
2252
|
sx: number;
|
|
1653
2253
|
sy: number;
|
|
1654
2254
|
};
|
|
1655
2255
|
/**
|
|
1656
|
-
* Scale a geom about `anchor` by `(sx, sy)
|
|
1657
|
-
* `sx === sy`) the unrotated
|
|
1658
|
-
* preserved (a uniform scale commutes with rotation). For unrotated
|
|
1659
|
-
* (the anisotropic case) every point/extent scales directly.
|
|
2256
|
+
* Scale a geom about `anchor` by `(sx, sy)`, exactly. For a rotated box (iso
|
|
2257
|
+
* scale, so `sx === sy`) the unrotated box is scaled about the anchor and its
|
|
2258
|
+
* turn is preserved (a uniform scale commutes with rotation). For unrotated
|
|
2259
|
+
* members (the anisotropic case) every point/extent scales directly. A resize
|
|
2260
|
+
* passes `minSize`, the smallest a box may end up.
|
|
1660
2261
|
*/
|
|
1661
|
-
declare function geomScaleAbout(
|
|
2262
|
+
declare function geomScaleAbout(geometry: Shape, anchor: Point, sx: number, sy: number, minSize?: number): Shape;
|
|
1662
2263
|
/** Where the rotate knob sits, given the OBB corners (nw, ne, se, sw) and the
|
|
1663
2264
|
* outward offset (content units). `from` is the top-edge midpoint the connector
|
|
1664
2265
|
* stalk anchors to; `at` is the grab dot, offset along the outward normal. */
|
|
1665
|
-
declare function rotateKnob(corners: [
|
|
1666
|
-
at:
|
|
1667
|
-
from:
|
|
2266
|
+
declare function rotateKnob(corners: [Point, Point, Point, Point], offset: number): {
|
|
2267
|
+
at: Point;
|
|
2268
|
+
from: Point;
|
|
1668
2269
|
};
|
|
1669
2270
|
/**
|
|
1670
|
-
* `rotateKnob` with a
|
|
2271
|
+
* `rotateKnob` with a total page-bound placement policy: annotations, gestures
|
|
1671
2272
|
* and chrome are all page-bound, so the grab dot must land inside `pageBox` —
|
|
1672
2273
|
* off-page it is unreachable (the pointer dispatch resolves pages by
|
|
1673
|
-
* containment). Policy: top edge (the default) →
|
|
1674
|
-
* the stalk exits the page →
|
|
2274
|
+
* containment). Policy: top edge (the default) → flip to the bottom edge when
|
|
2275
|
+
* the stalk exits the page → clamp the top candidate inside (degenerate: the
|
|
1675
2276
|
* selection spans ~the whole page; the knob may then overlap the shape, and
|
|
1676
2277
|
* hit-testing checks it first so it stays grabbable). Both render (`chrome`)
|
|
1677
|
-
* and hit-test (`hitTest`) place the knob through
|
|
2278
|
+
* and hit-test (`hitTest`) place the knob through this function, so what you
|
|
1678
2279
|
* see is what you can grab — by construction. No `pageBox` → the raw knob.
|
|
1679
2280
|
*/
|
|
1680
|
-
declare function placeRotateKnob(corners: [
|
|
1681
|
-
at:
|
|
1682
|
-
from:
|
|
2281
|
+
declare function placeRotateKnob(corners: [Point, Point, Point, Point], offset: number, pageBox?: Rect): {
|
|
2282
|
+
at: Point;
|
|
2283
|
+
from: Point;
|
|
1683
2284
|
};
|
|
1684
|
-
/** The box-edge midpoint the leader connects to: the side `ref` (the knee, else
|
|
1685
|
-
* the tip) points toward, by horizontal/vertical dominance vs the box centre.
|
|
1686
|
-
* With `rot` (a callout box tilted by the upright policy) the decision runs in
|
|
1687
|
-
* the box's LOCAL frame and the midpoint lands back on the ROTATED edge — the
|
|
1688
|
-
* edge the user actually sees. Mirror of v2's `computeCalloutConnectionPoint`. */
|
|
1689
|
-
declare function calloutConnection(box: Rect, ref: Vec, rot?: number): Vec;
|
|
1690
|
-
/** The leader polyline `[tip, knee?, conn]`, with `conn` derived from the box
|
|
1691
|
-
* (its ROTATED footprint when the box carries `rot`). */
|
|
1692
|
-
declare function calloutLinePoints(g: Extract<Geom, {
|
|
1693
|
-
t: 'text';
|
|
1694
|
-
}>): Vec[];
|
|
1695
|
-
/**
|
|
1696
|
-
* The stored `rect` for a freshly-drawn shape, given the box the user dragged. A
|
|
1697
|
-
* cloudy border stores the OUTER box (dragged + cloud extent), so the dragged box
|
|
1698
|
-
* is its inner edge and the scallops bulge out to the stored box — just like a
|
|
1699
|
-
* solid shape, whose /Rect is the dragged box. So `g.rect` is ALWAYS the outer box;
|
|
1700
|
-
* the cloud-vs-solid difference lives only here, at creation.
|
|
1701
|
-
*/
|
|
1702
|
-
declare function shapeRectFor(dragged: Rect, ellipse: boolean, style: Style): Rect;
|
|
1703
|
-
declare function caretRectFromTextEnd(lineRect: Rect): Rect;
|
|
1704
|
-
/**
|
|
1705
|
-
* Caret box for a text-edit anchor: half the glyph's ink height, centered on
|
|
1706
|
-
* the TRAILING baseline corner in READING direction (`advance` decides which
|
|
1707
|
-
* end — RTL carets land on the visual left), sitting on the baseline. The box
|
|
1708
|
-
* stays axis-aligned; use {@link caretGeomFromAnchor} for the tilt-carrying
|
|
1709
|
-
* geometry.
|
|
1710
|
-
*/
|
|
1711
|
-
declare function caretRectFromAnchor(anchor: TextEndAnchor): Rect;
|
|
1712
2285
|
/**
|
|
1713
|
-
*
|
|
1714
|
-
*
|
|
1715
|
-
* baseline corner, plus `rot` = the text's baseline tilt (deg, CW in y-down
|
|
1716
|
-
* content space). Rotating the box about its centre by `rot` lands it
|
|
1717
|
-
* hugging the rotated baseline, symbol pointing at its text. For upright
|
|
1718
|
-
* anchors this degenerates EXACTLY to {@link caretRectFromAnchor} with no
|
|
1719
|
-
* `rot` key — the dominant case is byte-identical.
|
|
1720
|
-
*/
|
|
1721
|
-
declare function caretGeomFromAnchor(anchor: TextEndAnchor): Extract<Geom, {
|
|
1722
|
-
t: 'caret';
|
|
1723
|
-
}>;
|
|
1724
|
-
/** Miter limit shared by the bounds math AND the SVG renderer (`stroke-miterlimit`),
|
|
1725
|
-
* so the computed box and the drawn stroke always agree on where a sharp join
|
|
1726
|
-
* bevels instead of spiking. 10 = the PDF default (also what the baked /AP uses). */
|
|
1727
|
-
declare const MITER_LIMIT = 10;
|
|
1728
|
-
/**
|
|
1729
|
-
* A geom's VISUAL bounds: the rect that encloses the drawn appearance, so the
|
|
1730
|
-
* baked /AP is never clipped and the selection outline wraps exactly what's drawn.
|
|
2286
|
+
* A geom's visual bounds: the rect that encloses the drawn appearance, so the
|
|
2287
|
+
* baked /AP is never clipped.
|
|
1731
2288
|
*
|
|
1732
|
-
* A
|
|
1733
|
-
*
|
|
1734
|
-
*
|
|
1735
|
-
* the
|
|
1736
|
-
*
|
|
1737
|
-
* `geomScene`, so the visual box and what's drawn always agree.
|
|
2289
|
+
* A box's strokes draw inside it; a cloudy border's bumps reach out from it,
|
|
2290
|
+
* so its bounds grow by the cloud's reach (`boxDrawnBounds`), before its
|
|
2291
|
+
* turn. Lines / polylines / ink have no box, so they expand by the stroke
|
|
2292
|
+
* (+ endings) — the same math feeds `geomScene`, so the visual box and what's
|
|
2293
|
+
* drawn always agree.
|
|
1738
2294
|
*
|
|
1739
|
-
*
|
|
1740
|
-
* are centred on the vertex path and reach
|
|
1741
|
-
*
|
|
1742
|
-
*
|
|
2295
|
+
* The stroke's cloud matters too: a box's, and a closed poly's, whose curls
|
|
2296
|
+
* are centred on the vertex path and reach outward — the bounds grow by the
|
|
2297
|
+
* cloud extent, and the engine's `rect` grows with them so the baked scallops
|
|
2298
|
+
* are never clipped.
|
|
1743
2299
|
*/
|
|
1744
|
-
declare
|
|
2300
|
+
declare const geomVisualBounds: (geometry: Shape, stroke: Stroke) => Rect;
|
|
1745
2301
|
/**
|
|
1746
|
-
* The rect the
|
|
2302
|
+
* The rect the selection wraps — and the region a selected annotation can be grabbed
|
|
1747
2303
|
* from. Centre-line geometries (line / polyline / polygon / ink) straddle their path,
|
|
1748
|
-
* so this is their
|
|
2304
|
+
* so this is their visual bounds (the join-aware stroke outline + endings) — a
|
|
1749
2305
|
* polygon's outline wraps its stroke exactly like a polyline. Box kinds (square /
|
|
1750
|
-
* circle / free-text) sit tight on their
|
|
1751
|
-
* so the 8 resize handles land on
|
|
2306
|
+
* circle / free-text) sit tight on their box (a stroke draws inside it, and a
|
|
2307
|
+
* cloud's bumps reach past it), so the 8 resize handles land on its corners. The chrome outline and the selected
|
|
1752
2308
|
* hit-test both call this, so what you see highlighted is exactly what you can grab —
|
|
1753
2309
|
* they can never drift.
|
|
1754
2310
|
*/
|
|
1755
|
-
declare
|
|
2311
|
+
declare const selectionBounds: (geometry: Shape, stroke: Stroke) => Rect;
|
|
1756
2312
|
/**
|
|
1757
|
-
* The four corners of the
|
|
2313
|
+
* The four corners of the oriented selection box — the same quad `chrome` draws.
|
|
1758
2314
|
* For a rotatable kind this is the OBB (the tilted box, from `obbFromGeom`); at
|
|
1759
2315
|
* `rot == 0` those are just the axis-aligned corners of `selectionBounds`, and
|
|
1760
2316
|
* for non-rotatable kinds (markup quads, callouts) it falls back to the rect
|
|
@@ -1762,77 +2318,227 @@ declare function selectionBounds(g: Geom, strokeWidth: number, border?: Border):
|
|
|
1762
2318
|
* all consume this, so what you can grab / where the menu sits never drifts from
|
|
1763
2319
|
* the outline you see.
|
|
1764
2320
|
*/
|
|
1765
|
-
declare function selectionQuad(
|
|
2321
|
+
declare function selectionQuad(geometry: Shape, stroke: Stroke): [Point, Point, Point, Point];
|
|
1766
2322
|
/** Is the point inside the (convex) selection quad? Even-odd ring test. */
|
|
1767
|
-
declare const pointInQuad: (
|
|
2323
|
+
declare const pointInQuad: (point: Point, quad: [Point, Point, Point, Point]) => boolean;
|
|
2324
|
+
/** The box around the shape's own box or points, the stroke left out. */
|
|
2325
|
+
declare const geomBounds: (geometry: Shape) => Rect;
|
|
2326
|
+
/**
|
|
2327
|
+
* Is the page point on what the shape paints ({@link geomPainted}): within
|
|
2328
|
+
* `margin` of its ink, which widens with the stroke width, or inside it when
|
|
2329
|
+
* `filled`. A cloudy border is hit on its curves.
|
|
2330
|
+
*/
|
|
2331
|
+
declare function geomHit(geometry: Shape, point: Point, margin: number, filled: boolean, stroke: Stroke): boolean;
|
|
2332
|
+
/**
|
|
2333
|
+
* What the shape paints (`painted.ts`): its ink for `stroke`, and its inside
|
|
2334
|
+
* when `filled`. Kept per shape object for the stroke and fill last asked
|
|
2335
|
+
* about, since a hover asks again on every pointer move.
|
|
2336
|
+
*/
|
|
2337
|
+
declare function geomPainted(geometry: Shape, stroke: Stroke, filled: boolean): readonly PaintedPiece[];
|
|
2338
|
+
/** The shape's handles: resize corners and sides, a callout's tip and knee, or vertices. */
|
|
2339
|
+
declare const geomHandles: (geometry: Shape) => Handle[];
|
|
2340
|
+
declare const geomTranslate: (geometry: Shape, delta: Point) => Shape;
|
|
2341
|
+
declare const geomDragHandle: (geometry: Shape, handle: string, to: Point) => Shape;
|
|
2342
|
+
/**
|
|
2343
|
+
* What the shape draws for the live view. A text box's box — its fill and
|
|
2344
|
+
* its border — is the scene's, plain box and callout alike, so the live view
|
|
2345
|
+
* paints exactly what the AP generator bakes; the framework's editable
|
|
2346
|
+
* element owns only the text.
|
|
2347
|
+
*/
|
|
2348
|
+
declare const geomScene: (geometry: Shape, stroke: Stroke) => RenderNode[];
|
|
2349
|
+
//#endregion
|
|
2350
|
+
//#region src/rect.d.ts
|
|
2351
|
+
type RectHandle = 'nw' | 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w';
|
|
2352
|
+
declare const RECT_HANDLES: RectHandle[];
|
|
2353
|
+
/** The resize cursor for a handle on a box tilted by `rot` deg: rotate the
|
|
2354
|
+
* handle's compass direction with the box and pick the nearest 45° sector.
|
|
2355
|
+
* At `rot = 0` this reproduces {@link RECT_CURSOR} exactly. */
|
|
2356
|
+
declare const rotatedHandleCursor: (handle: RectHandle, rot: number) => Cursor;
|
|
2357
|
+
declare const rectFromPoints: (from: Point, to: Point) => Rect;
|
|
2358
|
+
declare function unionRect(points: Point[]): Rect;
|
|
2359
|
+
/** Normalize degrees into `[0, 360)`. */
|
|
2360
|
+
declare const normalizeDeg: (degrees: number) => number;
|
|
2361
|
+
/** `rect` with width↔height swapped about its own centre — the unrotated box
|
|
2362
|
+
* whose quarter-turn AABB is exactly `rect` again. */
|
|
2363
|
+
declare function transposedAboutCenter(rect: Rect): Rect;
|
|
2364
|
+
/** The AABB of `rect` rotated `deg` about `pivot` (its own centre unless given). */
|
|
2365
|
+
declare function rotatedAabb(rect: Rect, deg: number, pivot?: Point): Rect;
|
|
2366
|
+
//#endregion
|
|
2367
|
+
//#region src/record/identity.d.ts
|
|
2368
|
+
/**
|
|
2369
|
+
* An annotation's kind (`kinds/`): the one its subtype names; for a widget,
|
|
2370
|
+
* the one its field family picks (`widget-text`…); for a free text with the
|
|
2371
|
+
* callout intent, the callout.
|
|
2372
|
+
*/
|
|
2373
|
+
declare function kindOf(annotation: Annotation): AnnotationKind;
|
|
2374
|
+
/**
|
|
2375
|
+
* A record's engine ref, a new one's included (it names the object number
|
|
2376
|
+
* its create takes); `null` for a record the view doesn't hold.
|
|
2377
|
+
*/
|
|
2378
|
+
declare const refOf: (record: ModelAnnotation | undefined) => AnnotationRef | null;
|
|
2379
|
+
/**
|
|
2380
|
+
* The key of the annotation an annotation answers (`/IRT`): a comment reply's
|
|
2381
|
+
* parent, or a group member's primary.
|
|
2382
|
+
*/
|
|
2383
|
+
declare const irtOf: (annotation: Annotation) => Id | undefined;
|
|
1768
2384
|
/**
|
|
1769
|
-
*
|
|
1770
|
-
*
|
|
1771
|
-
*
|
|
1772
|
-
* (touching counts). This is the marquee's predicate: it must catch a tilted
|
|
1773
|
-
* shape by the ORIENTED box that is actually drawn — the AABB of that quad has
|
|
1774
|
-
* empty corners covering most of the unrotated footprint, so testing it selects
|
|
1775
|
-
* shapes the marquee never touched. At `rot 0` the quad is axis-aligned and
|
|
1776
|
-
* this degenerates to exactly `rectsIntersect`.
|
|
2385
|
+
* The key of the group an annotation belongs to: its primary's, for a
|
|
2386
|
+
* `/RT /Group` member only (a visual group acts as a unit; a comment reply
|
|
2387
|
+
* answers its parent but is not part of it).
|
|
1777
2388
|
*/
|
|
1778
|
-
declare
|
|
2389
|
+
declare const groupOf: (annotation: Annotation) => Id | undefined;
|
|
2390
|
+
//#endregion
|
|
2391
|
+
//#region src/record/shape.d.ts
|
|
1779
2392
|
/**
|
|
1780
|
-
* The
|
|
1781
|
-
*
|
|
1782
|
-
*
|
|
1783
|
-
* than swinging it about the off-centre vertex mean (`centroidOf`).
|
|
2393
|
+
* The annotation's shape (`shapes/`), read by its kind's family. The same
|
|
2394
|
+
* shape for the same annotation, so what is worked out from a shape once
|
|
2395
|
+
* (where its points are drawn) is kept.
|
|
1784
2396
|
*/
|
|
1785
|
-
declare function
|
|
1786
|
-
declare function geomBounds(g: Geom): Rect;
|
|
2397
|
+
declare function shapeOf(annotation: Annotation): Shape;
|
|
1787
2398
|
/**
|
|
1788
|
-
*
|
|
1789
|
-
*
|
|
2399
|
+
* The record with its shape changed: the engine fields that state `shape`,
|
|
2400
|
+
* written through `withValues`. The same record when the shape is the one
|
|
2401
|
+
* it has, or when the record may not change now.
|
|
2402
|
+
*/
|
|
2403
|
+
declare const withShape: (record: ModelAnnotation, shape: Shape) => ModelAnnotation;
|
|
2404
|
+
//#endregion
|
|
2405
|
+
//#region src/record/style.d.ts
|
|
2406
|
+
/**
|
|
2407
|
+
* How the annotation is drawn: its colours, stroke and border, by the
|
|
2408
|
+
* engine's names, with its kind's fill-ins. A view: nothing is written back
|
|
2409
|
+
* through it. The same style for the same annotation.
|
|
2410
|
+
*/
|
|
2411
|
+
declare function styleOf(annotation: Annotation): Style;
|
|
2412
|
+
//#endregion
|
|
2413
|
+
//#region src/record/text.d.ts
|
|
2414
|
+
/**
|
|
2415
|
+
* How the annotation's text is set: its font, size, colour and alignment by
|
|
2416
|
+
* the engine's names, and a free text's bold, italic and underline. A view:
|
|
2417
|
+
* nothing is written back through it. `undefined` for a kind without text.
|
|
2418
|
+
* The same value for the same annotation.
|
|
2419
|
+
*/
|
|
2420
|
+
declare function textOf(annotation: Annotation): TextStyle | undefined;
|
|
2421
|
+
//#endregion
|
|
2422
|
+
//#region src/record/values.d.ts
|
|
2423
|
+
/**
|
|
2424
|
+
* The record with engine `values` written, as far as it takes them:
|
|
1790
2425
|
*
|
|
1791
|
-
*
|
|
1792
|
-
*
|
|
1793
|
-
*
|
|
1794
|
-
*
|
|
2426
|
+
* 1. Only the fields its kind has and this session may change now
|
|
2427
|
+
* (`mayWrite`). The rest are ignored, so one set of values restyles a
|
|
2428
|
+
* mixed selection.
|
|
2429
|
+
* 2. A `rect` is a command, resolved as the engine resolves it
|
|
2430
|
+
* (`resolveRectCommand`): it becomes the shape that puts the drawing
|
|
2431
|
+
* there, and one the engine would refuse throws.
|
|
2432
|
+
* 3. Merged into its annotation as given. The engine's follow rules (a
|
|
2433
|
+
* measurement's label, a callout's end) run once, where the change is
|
|
2434
|
+
* applied (`applyChange`).
|
|
2435
|
+
*
|
|
2436
|
+
* A value set to what it was is no change: the same record comes back.
|
|
1795
2437
|
*/
|
|
1796
|
-
declare function
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
declare function geomDragHandle(g: Geom, handle: string, to: Vec): Geom;
|
|
2438
|
+
declare function withValues(record: ModelAnnotation, values: FieldValues): ModelAnnotation;
|
|
2439
|
+
//#endregion
|
|
2440
|
+
//#region src/record/links.d.ts
|
|
1800
2441
|
/**
|
|
1801
|
-
* The
|
|
1802
|
-
* —
|
|
1803
|
-
*
|
|
1804
|
-
*
|
|
1805
|
-
*
|
|
1806
|
-
*
|
|
1807
|
-
*
|
|
1808
|
-
*
|
|
2442
|
+
* The desired hit rects (page space) of a parent's attached link
|
|
2443
|
+
* children — derived fresh from the parent's committed geometry, never
|
|
2444
|
+
* tracked: markup gets one child per quad (per-line hit areas), a text box
|
|
2445
|
+
* one child over its box, every other kind one child over its visual bounds.
|
|
2446
|
+
* The reconciler and the navigation lens both read this, so the clickable
|
|
2447
|
+
* area and the written `/Rect`s can never disagree.
|
|
2448
|
+
*
|
|
2449
|
+
* A link's `/Rect` is axis-aligned by spec (no rotation exists for links),
|
|
2450
|
+
* so a rotated parent gets the AABB of its rotated footprint — the
|
|
2451
|
+
* `selectionQuad` corners (rotation + stroke included), the same envelope
|
|
2452
|
+
* the selection chrome outlines. A text box's link covers only its turned
|
|
2453
|
+
* box: a callout's frame also takes in its line, and a link that size
|
|
2454
|
+
* would make the empty space around the line clickable. Exact rotated hit
|
|
2455
|
+
* regions need `/QuadPoints` (tier 2).
|
|
1809
2456
|
*/
|
|
1810
|
-
declare function
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
declare
|
|
1815
|
-
declare const contentToPdfRect: (r: Rect, crop: PdfRect) => PdfRect;
|
|
1816
|
-
/** A geom's VISUAL bounding box (geometry + stroke + line endings) as a PdfRect —
|
|
1817
|
-
* the engine requires an explicit `rect` that encloses the baked /AP. */
|
|
1818
|
-
declare const geomPdfBounds: (g: Geom, strokeWidth: number, crop: PdfRect, border?: Border) => PdfRect;
|
|
2457
|
+
declare function linkChildRects(shape: Shape, style: Style): Rect[];
|
|
2458
|
+
/** The writable projection of a `link` value: `goto`/`uri` pass through,
|
|
2459
|
+
* read-only arms (`javascript`, `named`, `goto-remote`, `launch`,
|
|
2460
|
+
* `unsupported`) yield `null` — they can be carried, never (re)written. */
|
|
2461
|
+
declare function writableTarget(target: PdfLinkTarget | null | undefined): PdfLinkTargetWritable | null;
|
|
1819
2462
|
//#endregion
|
|
1820
|
-
//#region src/
|
|
2463
|
+
//#region src/record/written.d.ts
|
|
1821
2464
|
/**
|
|
1822
|
-
* The
|
|
1823
|
-
*
|
|
1824
|
-
*
|
|
1825
|
-
* box edge: the box remains the annotation's outer boundary.
|
|
2465
|
+
* The annotation `draft` creates, as the engine reads it back: the draft's
|
|
2466
|
+
* fields as the engine states them, and a drawn kind's `rect` the box around
|
|
2467
|
+
* its drawing. `at` names the ref it will have.
|
|
1826
2468
|
*/
|
|
1827
|
-
declare function
|
|
2469
|
+
declare function annotationOfNew(draft: AnnotationDraft, at: {
|
|
2470
|
+
readonly ref: AnnotationRef;
|
|
2471
|
+
}): Annotation;
|
|
1828
2472
|
/**
|
|
1829
|
-
*
|
|
1830
|
-
*
|
|
1831
|
-
*
|
|
2473
|
+
* `annotation` after `patch`, as the engine reads it back: the patch applied
|
|
2474
|
+
* by the engine's own rules, and the fields the engine works out as its
|
|
2475
|
+
* verdict on the change says (the table at the top of this file). Throws, as
|
|
2476
|
+
* the engine does, for a patch its rules refuse without its schemas
|
|
2477
|
+
* (`resolveAnnotationPatch`); values only the schemas refuse are applied, and
|
|
2478
|
+
* the engine refuses them when the patch reaches it.
|
|
2479
|
+
*/
|
|
2480
|
+
declare function annotationAfter(annotation: Annotation, patch: AnnotationPatch): Annotation;
|
|
2481
|
+
//#endregion
|
|
2482
|
+
//#region src/record/index.d.ts
|
|
2483
|
+
/**
|
|
2484
|
+
* The record an engine annotation reads as: keyed by its ref, drawn from the
|
|
2485
|
+
* engine's appearance raster (`source: 'baked'`, placed by `apBox`). Whether
|
|
2486
|
+
* this session draws it live instead is the appearance rule's
|
|
2487
|
+
* (appearance.ts).
|
|
2488
|
+
*/
|
|
2489
|
+
declare function fromDTO(dto: Annotation): ModelAnnotation;
|
|
2490
|
+
//#endregion
|
|
2491
|
+
//#region src/cloudy.d.ts
|
|
2492
|
+
/**
|
|
2493
|
+
* SVG path data for a cloudy square (rect) or circle (ellipse), in absolute
|
|
2494
|
+
* content coordinates. The scallops are generated on `box` and bulge out
|
|
2495
|
+
* from it.
|
|
1832
2496
|
*/
|
|
1833
2497
|
declare function cloudyPath(box: Rect, ellipse: boolean, intensity: number, strokeWidth: number): string;
|
|
1834
2498
|
//#endregion
|
|
2499
|
+
//#region src/appearance.d.ts
|
|
2500
|
+
/** The part of a record that says how it is drawn. */
|
|
2501
|
+
type DrawState = Pick<ModelAnnotation, 'source' | 'apBox'>;
|
|
2502
|
+
/** How a record this session creates is drawn at first. */
|
|
2503
|
+
declare const sourceOfNew: (annotation: Annotation) => ModelAnnotation["source"];
|
|
2504
|
+
/**
|
|
2505
|
+
* How a record the engine reports is drawn: live when this session drew it
|
|
2506
|
+
* live (`vector`, the plugin's preference) or when the file holds no
|
|
2507
|
+
* appearance for it; otherwise from the engine's raster.
|
|
2508
|
+
*/
|
|
2509
|
+
declare const sourceOfConfirmed: (annotation: Annotation, vector: boolean) => ModelAnnotation["source"];
|
|
2510
|
+
/**
|
|
2511
|
+
* What changes in how `record` is drawn once `patch` is written: the rule at
|
|
2512
|
+
* the top of this file. Only the fields that change. The engine judges the
|
|
2513
|
+
* patch as it will write it: a `rect` command is the shape it moves to by
|
|
2514
|
+
* then.
|
|
2515
|
+
*/
|
|
2516
|
+
declare function drawnAfter(record: ModelAnnotation, patch: AnnotationPatch): Partial<DrawState>;
|
|
2517
|
+
//#endregion
|
|
2518
|
+
//#region src/selection.d.ts
|
|
2519
|
+
interface SelectionFrame {
|
|
2520
|
+
corners: QuadRing;
|
|
2521
|
+
center: Point;
|
|
2522
|
+
angle: number;
|
|
2523
|
+
}
|
|
2524
|
+
/**
|
|
2525
|
+
* The frame of `record` as it is drawn, or with `live` fields laid over its
|
|
2526
|
+
* own (a gesture's geometry, a screen-anchored stroke).
|
|
2527
|
+
*/
|
|
2528
|
+
declare function annotationSelectionFrame(record: ModelAnnotation, view?: ViewEnv, live?: {
|
|
2529
|
+
geometry?: Shape;
|
|
2530
|
+
style?: Style;
|
|
2531
|
+
measure?: MeasurementAppearance;
|
|
2532
|
+
}): SelectionFrame;
|
|
2533
|
+
//#endregion
|
|
1835
2534
|
//#region src/scene.d.ts
|
|
2535
|
+
/**
|
|
2536
|
+
* Whether the item can be drawn live now (`scene(item)`): anything not
|
|
2537
|
+
* drawn from the engine's picture, a kind with a live drawing, and a lent
|
|
2538
|
+
* record its lender draws. A stamp or a link can't: its picture is its
|
|
2539
|
+
* drawing.
|
|
2540
|
+
*/
|
|
2541
|
+
declare const hasLiveDrawing: (item: RenderItem) => boolean;
|
|
1836
2542
|
/** The full painted scene for one annotation. */
|
|
1837
2543
|
declare function scene(item: RenderItem): SceneNode[];
|
|
1838
2544
|
//#endregion
|
|
@@ -1842,7 +2548,7 @@ declare function scene(item: RenderItem): SceneNode[];
|
|
|
1842
2548
|
* close to horizontal or vertical. Diagonal strokes remain untouched: this is
|
|
1843
2549
|
* a highlighter aid, not a general line simplifier.
|
|
1844
2550
|
*/
|
|
1845
|
-
declare function straightenInkStroke(points: readonly
|
|
2551
|
+
declare function straightenInkStroke(points: readonly Point[], options: InkStraightenOptions): Point[];
|
|
1846
2552
|
//#endregion
|
|
1847
|
-
export { type AnchorMode, type
|
|
2553
|
+
export { type AnchorMode, type AnnotationFlags, type AnnotationKind, type AnnotationOption, type AnnotationProperty, type AnnotationView, type BlendMode, type BoxShape, type CalloutLine, type CaretShape, type ChangeSet, type ChromeGeometry, type ChromeNode, type ClickCreate, type Corners, type CreationDraftAnchor, type Cursor, DEFAULT_CHROME_GEOMETRY, DRAWN_FLAGS, DistanceAppearance, DistanceCaptionLayout, DistanceLayout, DistanceSegment, type Draft, type DrawState, EMPTY_CHANGE, type EditableKind, type EditableKinds, type Effect, FLAG_KEYS, FLAG_PROPERTIES, type FieldValues, type FlagBearer, type FlagKey, type FontLookup, type GestureForm, type GroupCaps, type Guide, type Handle, type HandleRole, type Id, type InkShape, type InkStraightenOptions, KINDS, type KindCaps, type KindName, LINE_ENDING_NAMES, type LineEnding, type LineEndings, type LineShape, MIN_DRAG, MITER_LIMIT, MeasurementAppearance, type MeasurementIntent, type Message, type Model, type ModelAnnotation, NO_ANNOTATION_FLAGS, NO_CAPS, type Paint, type PaintedPiece, type Placement, type PlacementFrame, type Point, type PointerInput, type PointsShape, type PolyShape, type Quad, type QuadRing, type QuadsShape, RECT_HANDLES, ROTATE_KNOB_OFFSET, type Rect, type RectHandle, type RenderItem, type RenderNode, type RichTextRange, type RichTextStyleDelta, type RotationAnchor, STANDARD_FONT_STACKS, type SceneFontProgram, type SceneNode, type SelectionFrame, type Session, type Shape, type ShapeFamily, ShapeMeasurementAppearance, ShapeMeasurementLayout, type SnapResult, type SnapSettings, type Stroke, type Style, type Target, type TextAlign, type TextBox, type TextBoxShape, type TextEndAnchor, type TextStyle, type TurnedBox, type UpdateResult, type ViewEnv, anchorModeOf, anchorOf, anchoredBox, anchoredGeom, anchoredStrokeWidth, annotContentsEditable, annotDeletable, annotInteractive, annotTransformable, annotationAfter, annotationAnchor, annotationOfNew, annotationSelectionFrame, applyStyleToRange, automaticShapeCaptionCenter, bodyFromTextStyle, bodyPieces, boxFamily, calloutEnd, canMove, captionPainted, caretFamily, caretFromAnchor, caretRectFromAnchor, chrome, clampRectToBox, cloudyPath, computeMoveSnap, creationDraftAnchor, cssFontFamilyForFont, cursorAt, defaultsFor, defineKind, distanceCaptionAt, distanceCaptionHit, distanceDrawnBounds, distanceHandles, distanceLabel, distanceLayout, distanceLeaderLength, distancePainted, distanceScene, distanceSelectionQuad, drawnAfter, drawnStrokesOf, editableKindOf, engineSubtypeOf, expandDistanceBounds, expandGroups, faceForFont, familyChosenBy, familyOf, fitStampBox, flagsEqual, fromDTO, geomBounds, geomDragHandle, geomHandles, geomHit, geomPainted, geomResetRotation, geomRotateAbout, geomRotation, geomScaleAbout, geomScene, geomTranslate, geomVisualBounds, gesturePlacement, groupCaps, groupKeyOf, groupMembers, groupOf, groupResizeAnchor, groupResizeBox, groupResizeFactors, hasLiveDrawing, hitTest, iconOf, initialModel, initialSession, initialTextStyle, interactive, irtOf, isAttachedLink, isContentsEditableByHand, isConversationOnly, isDeletableByHand, isDrag, isEditableByHand, isOnTextBox, isPlainRichText, isRotatableGeom, isSelectable, isSubstrateOnly, isTransformableByHand, kindNamed, kindOf, kindTakesLink, lineEndingsOf, linkChildRects, linkChildrenOf, linkOf, locateOffset, measurementCaptionScene, measurementDraftFields, measurementLayout, measurementOf, measurementSelectionQuad, mergeFlags, mountedFontFamily, moveDistanceCaption, moveMeasurementCaption, newRecordsAtMost, normalizeDeg, normalizeRuns, obbFromGeom, pageItems, paintedNear, paintedOf, paintedTouches, paragraphsFromPlainText, placeRotateKnob, placedShape, plainTextOf, pointInQuad, pointsFamily, propertiesOf, quadsFamily, rangeHasStyle, readOfDefaults, rectFromPoints, refOf, resolveClickPlacement, richDocOf, richTextLength, rotateDraftDelta, rotateKnob, rotatedAabb, rotatedHandleCursor, rotationAnchor, sameSession, sameStyleDelta, scene, selectedItems, selectionAnchor, selectionBounds, selectionBoundsOnPage, selectionInBox, selectionKnob, selectionQuad, shapeMeasurementLabel, shapeMeasurementLayout, shapeMeasurementReadout, shapeOf, sharedProperties, sourceOfConfirmed, sourceOfNew, splitRunsAt, straightenInkStroke, styleAt, styleOf, textBoxFamily, textBoxes, textOf, textPlateInset, toolAnnotation, transposedAboutCenter, turnPivotOf, unanchoredGeom, unionRect, unmadeItem, update, uprightAnchoredRect, uprightRotation, viewable, widgetAppearanceOf, withShape, withValues, writableTarget };
|
|
1848
2554
|
//# sourceMappingURL=index.d.cts.map
|