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