@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 ADDED
@@ -0,0 +1,90 @@
1
+ # @embedpdf/core-annotation
2
+
3
+ The pure annotation core: gestures, geometry, hit-testing and the scene, as
4
+ plain functions. No DOM, no engine, no framework, no clock. The annotation
5
+ plugin ([`@embedpdf/plugin-annotation`](../../plugin/annotation/README.md))
6
+ runs it against the engine.
7
+
8
+ ## The contract
9
+
10
+ ```ts
11
+ update(model: Model, message: Message): UpdateResult;
12
+
13
+ interface UpdateResult {
14
+ session: Session; // selection, hover, the gesture in progress, tool settings
15
+ change: ChangeSet; // { put: records the message changed or created, drop: ids it deleted }
16
+ effects: Effect[]; // the engine work to do: create, patch, flags, text, delete, …
17
+ }
18
+
19
+ type Model = Session & AnnotationView; // AnnotationView = { byId, order }
20
+ ```
21
+
22
+ A message goes in with the model it acts on; the next session, the records it
23
+ changed and the work to do come out. The core never stores a record: the
24
+ records in `model.byId` are what the plugin shows (the engine's records with
25
+ this session's pending changes on top), and the change set says what this
26
+ message changed about them. The plugin turns the effects into one change for
27
+ the engine, which it shows until the engine answers.
28
+
29
+ Consequences worth knowing:
30
+
31
+ - A message that changes no record returns `EMPTY_CHANGE`, and a pointer move
32
+ during a drag changes only the session (the gesture's `draft`), so it costs
33
+ one comparison.
34
+ - A record the core creates takes the first object number the session holds
35
+ (`Session.objectNumbers`): its ref, and so its key, is final from its first
36
+ frame, and it is marked `unconfirmed` until the engine wrote it. The plugin
37
+ hands the session the numbers a message may need before it runs
38
+ (`newRecordsAtMost`); the core refuses to make a record it can't name. A
39
+ replace-text strikeout answers its caret by the caret's number, so both are
40
+ written in one change. When records leave the view, the plugin sends
41
+ `forget`.
42
+ - How a record is drawn after a change is one rule, in `src/appearance.ts`,
43
+ for gestures, sidebar edits and code edits alike: a move keeps the raster
44
+ and moves it, any other visible change draws live, and stamps and form
45
+ widgets always show their raster (a stamp's at its own proportions, as the
46
+ engine fits it `contain`). It asks the engine's own verdict
47
+ (`appearanceChangeOf`), so the view keeps an appearance exactly where the
48
+ engine does. Whether the engine's re-baked raster changed is the engine's
49
+ answer, never the core's.
50
+
51
+ ## Where each message is handled
52
+
53
+ `src/update/` holds one module per kind of work. `update/index.ts` is the
54
+ entry and the message switch.
55
+
56
+ | Module | Messages |
57
+ | -------------------- | -------------------------------------------------------------------------- |
58
+ | `edit.ts` | `editPointer` down and move: select, move, resize, rotate, caption, leader |
59
+ | `edit-commit.ts` | `editPointer` up: the gesture's result becomes the records' geometry |
60
+ | `marquee.ts` | `marqueePointer`: rubber-band selection |
61
+ | `draw.ts` | `createPointer`, `finishInkDraft`, `finishCreationDraft` |
62
+ | `draw-callout.ts` | the free-text callout gesture |
63
+ | `draw-distance.ts` | the distance measurement gesture |
64
+ | `text-markup.ts` | `createMarkup`, `createCaret`, `createReplaceText`, the markup preview |
65
+ | `selection-edits.ts` | `setFields`, `setFlags`, `rotateSelection`, `resetRotation`, `delete` |
66
+ | `text.ts` | `setText`, `setRichText` |
67
+ | `session.ts` | the initial session, tool defaults, `forget` |
68
+ | `changes.ts` | what every record-changing transition shares |
69
+ | `page-bound.ts` | keeping gestures inside the page they started on |
70
+
71
+ The reads (`view.ts`, `hit.ts`, `scene.ts`, `geometry.ts`, …) take the same
72
+ `Model` and never change it.
73
+
74
+ ## What a create gesture makes
75
+
76
+ A create tool answers one question: if the gesture ended now, what would
77
+ exist? `placement.ts` answers where: `gesturePlacement` gives the dragged box
78
+ or segment once the gesture is a drag, else the tool's click default
79
+ (`resolveClickPlacement`: its size, and which part lands on the click). Each
80
+ shape family answers what (`ShapeFamily.placed`, through `placedShape`): a
81
+ box, a circle, a text box, a line with the tool's endings, a round radio
82
+ button. The commit (`draw.ts`), the drawing in progress (`view.ts`) and the
83
+ tool's ghost (the plugin's `tools/ghost.ts`) make these same calls, and
84
+ `unmadeItem` paints an annotation not made yet as the made one will paint.
85
+
86
+ ## Tests
87
+
88
+ `test/support.ts` drives the core the way the plugin does: `modelWith(records)`
89
+ builds a model, and `step(model, message)` applies a message's result (its
90
+ session, and its change set on the records).