@ingcreators/annot-core 0.2.0 → 0.3.0
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/CHANGELOG.md +147 -0
- package/README.md +1 -1
- package/dist/editor/index.d.ts +1 -0
- package/dist/editor/overlay-pick-types.d.ts +35 -0
- package/dist/editor/tool-registry.d.ts +1 -1
- package/dist/element-tree/index.d.ts +4 -0
- package/dist/element-tree/json.d.ts +21 -0
- package/dist/element-tree/types.d.ts +96 -0
- package/dist/element-tree/walk.d.ts +49 -0
- package/dist/element-tree/yaml.d.ts +22 -0
- package/dist/headless.d.ts +3 -1
- package/dist/index.js +1884 -621
- package/dist/storage/path.d.ts +17 -0
- package/dist/storage/types.d.ts +71 -87
- package/dist/xmp/element-tree-payload.d.ts +32 -0
- package/dist/xmp/xmp-browser.d.ts +1 -1
- package/dist/xmp/xmp-bytes.d.ts +29 -0
- package/dist/xmp-bytes.js +265 -0
- package/package.json +9 -3
- package/styles/editor.css +6 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,152 @@
|
|
|
1
1
|
# @ingcreators/annot-core
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 691bec5: **Add `flattenEditablePng(pngBytes) → pngBytes`** — Phase 3j of
|
|
8
|
+
`docs/plans/living-spec-authoring-roadmap.md` (Phase 3
|
|
9
|
+
follow-up #2). The editor's editable-PNG format embeds the
|
|
10
|
+
original un-annotated capture + the annotations SVG in PNG
|
|
11
|
+
ancillary chunks for re-edit; "flatten" drops those chunks and
|
|
12
|
+
keeps just the visible (already-annotated) bytes.
|
|
13
|
+
|
|
14
|
+
### `@ingcreators/annot-annotator` — new public surface
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { flattenEditablePng } from "@ingcreators/annot-annotator";
|
|
18
|
+
|
|
19
|
+
const flat = flattenEditablePng(editablePngBytes);
|
|
20
|
+
// → flat PNG: same visible pixels, no Adobe XMP iTXt chunk,
|
|
21
|
+
// no custom svGo chunk. `readEditablePngBytes(flat)` returns
|
|
22
|
+
// null. File size drops significantly (the editable layer
|
|
23
|
+
// roughly doubled the bytes).
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### `@ingcreators/annot-core/xmp-bytes` — new public surface
|
|
27
|
+
|
|
28
|
+
The implementation lives in `@ingcreators/annot-core` as
|
|
29
|
+
`stripPngEditableLayer` — the same chunk-walking helper that
|
|
30
|
+
`writePngWithMetadata` / `writePngWithTagsOnly` already used
|
|
31
|
+
internally to clean stale metadata before re-injecting. Now
|
|
32
|
+
exported so other Tier A consumers (not just annotator) can
|
|
33
|
+
use it directly.
|
|
34
|
+
|
|
35
|
+
annotator's `flattenEditablePng` is a one-line wrapper that
|
|
36
|
+
calls `stripPngEditableLayer` under a more user-facing name.
|
|
37
|
+
|
|
38
|
+
### Why this is metadata removal, not re-rasterization
|
|
39
|
+
|
|
40
|
+
`toEditablePng` rasterizes the SVG fragment onto the base image
|
|
41
|
+
FIRST and embeds the editable layer as ancillary PNG chunks
|
|
42
|
+
(`iTXt` carrying Adobe XMP + custom `svGo` chunk). The visible
|
|
43
|
+
bytes are already the annotated bitmap. Flattening strips the
|
|
44
|
+
ancillary chunks; the IDAT pixel data stays byte-identical.
|
|
45
|
+
No decode, no re-encode, no `@napi-rs/canvas` round-trip.
|
|
46
|
+
|
|
47
|
+
### Use cases
|
|
48
|
+
- **Publish-flat** — editor session → distribution-ready PNG;
|
|
49
|
+
the editable layer is dead weight for downstream consumers
|
|
50
|
+
(Slack drop, third-party viewers).
|
|
51
|
+
- **File size** — editable PNG roughly doubles in bytes
|
|
52
|
+
(original + SVG embedded); flattening drops the overhead.
|
|
53
|
+
- **Privacy hardening** — `burnRedactions` is the strong
|
|
54
|
+
version for _redact_ regions; flattening drops the
|
|
55
|
+
recoverable original entirely for _all_ annotations,
|
|
56
|
+
including non-redact ones whose annotated visual the
|
|
57
|
+
publisher wants to keep but whose original capture they
|
|
58
|
+
don't want shippable.
|
|
59
|
+
|
|
60
|
+
### Internal rename in annot-core
|
|
61
|
+
|
|
62
|
+
The private `removePngMetadata` helper in
|
|
63
|
+
`@ingcreators/annot-core/xmp-bytes` is renamed to
|
|
64
|
+
`stripPngEditableLayer` (clearer name describing what it does
|
|
65
|
+
rather than how it's used). Internal callers in the same
|
|
66
|
+
module updated. No external API change for the rename itself;
|
|
67
|
+
`writePngWithMetadata` + `writePngWithTagsOnly` keep their
|
|
68
|
+
existing signatures + behaviour.
|
|
69
|
+
|
|
70
|
+
### Compatibility
|
|
71
|
+
|
|
72
|
+
Additive on annotator + core. No behaviour change for existing
|
|
73
|
+
callers (the only internal rename is a private helper).
|
|
74
|
+
|
|
75
|
+
## 0.2.1
|
|
76
|
+
|
|
77
|
+
### Patch Changes
|
|
78
|
+
|
|
79
|
+
- f485646: **Expose `./xmp-bytes` subpath on the published tarball.**
|
|
80
|
+
The workspace `package.json#exports` declared
|
|
81
|
+
`"./xmp-bytes": "./src/xmp/xmp-bytes.ts"` from day one, but
|
|
82
|
+
`publishConfig.exports` only declared `.` + `./styles/*` —
|
|
83
|
+
so every workspace subpath (`./headless`, `./editor/*`,
|
|
84
|
+
`./xmp-bytes`, etc.) was stripped from the published
|
|
85
|
+
tarball.
|
|
86
|
+
|
|
87
|
+
This patch unblocks the `./xmp-bytes` subpath specifically.
|
|
88
|
+
`@ingcreators/annot-product-docs-astro@0.2.1`'s playwright
|
|
89
|
+
fixture imports `@ingcreators/annot-core/xmp-bytes` (via
|
|
90
|
+
the bundled `writePngWithTagsOnly` helper); without this
|
|
91
|
+
patch, any consumer doing
|
|
92
|
+
`import { test } from "@ingcreators/annot-product-docs-astro/playwright"`
|
|
93
|
+
hits `Package subpath './xmp-bytes' is not defined`.
|
|
94
|
+
|
|
95
|
+
## Fix
|
|
96
|
+
|
|
97
|
+
`vite.config.ts` switches to multi-entry library mode:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
lib: {
|
|
101
|
+
entry: {
|
|
102
|
+
index: resolve(__dirname, "src/index.ts"),
|
|
103
|
+
"xmp-bytes": resolve(__dirname, "src/xmp/xmp-bytes.ts"),
|
|
104
|
+
},
|
|
105
|
+
formats: ["es"],
|
|
106
|
+
},
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`package.json#publishConfig.exports` gains the matching
|
|
110
|
+
`./xmp-bytes` entry:
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
"./xmp-bytes": {
|
|
114
|
+
"types": "./dist/xmp/xmp-bytes.d.ts",
|
|
115
|
+
"default": "./dist/xmp-bytes.js"
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Bundle landing in the tarball:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
dist/xmp-bytes.js 7.55 kB │ gzip: 2.67 kB
|
|
123
|
+
dist/xmp/xmp-bytes.d.ts declarations colocated by the dts plugin
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Other subpaths still missing
|
|
127
|
+
|
|
128
|
+
The workspace `exports` map declares 17+ subpaths (`./headless`,
|
|
129
|
+
`./editor`, `./editor/*`, `./icons`, `./xmp`, `./zip`,
|
|
130
|
+
`./utils`, `./desktop-bridge`, `./storage`, `./encode/*`,
|
|
131
|
+
`./auto-capture-options`, …). Most are Tier C (browser-only)
|
|
132
|
+
and shouldn't ship as standalone published bundles — Tier C
|
|
133
|
+
code lives in `@ingcreators/annot-editor` / `-render` for
|
|
134
|
+
npm consumers. The few Tier A subpaths that DO make sense
|
|
135
|
+
on npm (`./headless`, `./storage`, `./utils`, `./zip`,
|
|
136
|
+
`./zip-bytes`) can ship in a separate follow-up patch
|
|
137
|
+
when a concrete downstream consumer needs them.
|
|
138
|
+
|
|
139
|
+
## After this PR republishes
|
|
140
|
+
|
|
141
|
+
`@ingcreators/annot-product-docs-astro` needs a `0.2.2`
|
|
142
|
+
republish that bumps its `@ingcreators/annot-core` dep
|
|
143
|
+
from `0.2.0` to `^0.2.1` so the playwright fixture can
|
|
144
|
+
finally resolve `./xmp-bytes` at consumer install time.
|
|
145
|
+
Once both land, the `examples/workflow-app/` tour can
|
|
146
|
+
migrate from the hybrid `captureScreen + page.screenshot`
|
|
147
|
+
pair to the unified `page.screenshot({ annot: { mdx } })`
|
|
148
|
+
single call.
|
|
149
|
+
|
|
3
150
|
## 0.2.0
|
|
4
151
|
|
|
5
152
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ headless tool against the SDK.
|
|
|
40
40
|
|---------|------|---------|---|
|
|
41
41
|
| `@ingcreators/annot-core` | A | Re-exports everything from `/headless` — DOM-free root entry | ✅ |
|
|
42
42
|
| `@ingcreators/annot-core/headless` | A | Same as root, kept as an alias for callers that want to be explicit | workspace only (v0.1.0) |
|
|
43
|
-
| `@ingcreators/annot-core/storage` | A | `ImageRecord`, `FolderRecord`, `
|
|
43
|
+
| `@ingcreators/annot-core/storage` | A | `ImageRecord`, `FolderRecord`, `StorageProvider` | workspace only (v0.1.0) |
|
|
44
44
|
| `@ingcreators/annot-core/utils` | A | `assertNonNull`, `computeDasharray`, `newIdB58`, defaults | workspace only (v0.1.0) |
|
|
45
45
|
| `@ingcreators/annot-core/zip` | A | ZIP builder used by PPTX export | workspace only (v0.1.0) |
|
|
46
46
|
| `@ingcreators/annot-core/encode` | A | Image encode helpers | workspace only (v0.1.0) |
|
package/dist/editor/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { createHistoryCore, DEFAULT_HISTORY_DEPTH, type HistoryCore, type HistoryHooks, } from './history-core.js';
|
|
2
|
+
export type { OverlayRegionPickDetail } from './overlay-pick-types.js';
|
|
2
3
|
export { CATEGORY_CONTROL_SHAPE, classifyPropertyElement, classifyPropertySelection, PROPERTY_CONTROL_IDS, PROPERTY_CONTROLS, PROPERTY_EFFECT_IDS, type PropertyCategory, type PropertyControlDef, type PropertyControlId, type PropertyControlOption, type PropertyControlType, type PropertyEffectId, } from './property-schema.js';
|
|
3
4
|
export { computeSnap, cursorForAngle, type Rect, rotateAround, type SnapGuide, type SnapInput, type SnapResult, } from './selection-geometry.js';
|
|
4
5
|
export { ANNOT_SVG_VERSION, ANNOT_SVG_VERSION_ATTR, ANNOT_SVG_VERSION_UNSTAMPED, getAnnotVersionFromString, readAnnotVersion, stampAnnotVersion, } from './svg-format.js';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the snapshot region pick flow — Phase 4d of
|
|
3
|
+
* [`docs/plans/living-spec-authoring-roadmap.md`](../../../../docs/plans/living-spec-authoring-roadmap.md).
|
|
4
|
+
*
|
|
5
|
+
* The `<annot-snapshot-overlay>` Lit element (host-ui) and the
|
|
6
|
+
* `OverlayTool` (editor) both deal with snapshot-region picks but
|
|
7
|
+
* live in packages that don't depend on each other (host-ui →
|
|
8
|
+
* editor, not the reverse). Lifting the detail type into Tier A
|
|
9
|
+
* core lets both sides import it without forcing a cycle.
|
|
10
|
+
*
|
|
11
|
+
* Pure data types — no DOM, no Node-specific APIs.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Payload of the `overlay-region-pick` CustomEvent fired by
|
|
15
|
+
* `<annot-snapshot-overlay>` when the user clicks a region.
|
|
16
|
+
* Consumed by `OverlayTool` to build an `OverlayProposal` for the
|
|
17
|
+
* intent picker dialog.
|
|
18
|
+
*/
|
|
19
|
+
export interface OverlayRegionPickDetail {
|
|
20
|
+
/** Tree-unique identifier of the picked node (e.g. `"e3"`).
|
|
21
|
+
* Stable within one capture only — annotation persistence keys
|
|
22
|
+
* on `match: { role, name }` instead. */
|
|
23
|
+
ref: string;
|
|
24
|
+
/** ARIA role of the picked node. Always present. */
|
|
25
|
+
role: string;
|
|
26
|
+
/** Accessible name, when the node carries one. */
|
|
27
|
+
name?: string;
|
|
28
|
+
/** Page-space bounding box of the picked node. CSS px. */
|
|
29
|
+
bbox: {
|
|
30
|
+
x: number;
|
|
31
|
+
y: number;
|
|
32
|
+
width: number;
|
|
33
|
+
height: number;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -316,5 +316,5 @@ export declare function normalizeVariantSideFields(toolId: string, newVariant: s
|
|
|
316
316
|
export declare const TOOL_REGISTRY: Readonly<Record<string, ToolRegistryEntry>>;
|
|
317
317
|
/** All tool ids the toolbar exposes. Frozen tuple form for tests
|
|
318
318
|
* that assert the registry covers exactly this set. */
|
|
319
|
-
export declare const TOOL_REGISTRY_IDS: readonly ["arrow", "shape", "highlight", "text", "freehand", "marker", "redact", "crop"];
|
|
319
|
+
export declare const TOOL_REGISTRY_IDS: readonly ["arrow", "shape", "highlight", "text", "freehand", "marker", "redact", "crop", "overlay"];
|
|
320
320
|
export type ToolRegistryId = (typeof TOOL_REGISTRY_IDS)[number];
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { parseElementTreeFromJson, serializeElementTreeToJson, validateElementTree, } from './json.js';
|
|
2
|
+
export { type BBox, type ElementNode, type ElementTree, type ElementTreeSource, type ElementTreeViewport, isElementTreeShape, } from './types.js';
|
|
3
|
+
export { type ElementMatch, type ElementTreeVisitor, findByMatch, findByRef, flattenTree, walkTree, } from './walk.js';
|
|
4
|
+
export { parseElementTreeFromYaml, serializeElementTreeToYaml } from './yaml.js';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ElementTree } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Serialize an ElementTree to a JSON string. Uses 2-space indent for
|
|
4
|
+
* readability; pass `compact: true` for a single-line minified
|
|
5
|
+
* form. Optional / undefined fields are omitted from the output to
|
|
6
|
+
* keep the serialization round-trip stable.
|
|
7
|
+
*/
|
|
8
|
+
export declare function serializeElementTreeToJson(tree: ElementTree, options?: {
|
|
9
|
+
compact?: boolean;
|
|
10
|
+
}): string;
|
|
11
|
+
/**
|
|
12
|
+
* Parse a JSON string into an ElementTree. Throws `Error` with a
|
|
13
|
+
* descriptive message on malformed input — the parser is strict to
|
|
14
|
+
* surface schema drift early.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseElementTreeFromJson(json: string): ElementTree;
|
|
17
|
+
/**
|
|
18
|
+
* Strict structural validation of a parsed `unknown` payload.
|
|
19
|
+
* Exported so the YAML parser can share the same validation pass.
|
|
20
|
+
*/
|
|
21
|
+
export declare function validateElementTree(value: unknown): ElementTree;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Top-level ElementTree wire format. Stored in PNG XMP as iTXt
|
|
3
|
+
* (`annot:elementTree` keyword, deflate-compressed YAML by default —
|
|
4
|
+
* see `@ingcreators/annot-core/xmp` extension landed in Phase 1d).
|
|
5
|
+
*/
|
|
6
|
+
export interface ElementTree {
|
|
7
|
+
/** Schema version. Currently 1. Reader version-dispatches; writers
|
|
8
|
+
* always emit the current schema. */
|
|
9
|
+
version: 1;
|
|
10
|
+
/** Metadata about who produced this capture. */
|
|
11
|
+
source: ElementTreeSource;
|
|
12
|
+
/** Capture viewport. CSS px; `scale` is the device-pixel-ratio. */
|
|
13
|
+
viewport: ElementTreeViewport;
|
|
14
|
+
/** Root node. Always present. Often `role: "main"` or `"document"`
|
|
15
|
+
* for browser captures; for partial captures (area / element-scoped)
|
|
16
|
+
* the root is the captured element itself. */
|
|
17
|
+
root: ElementNode;
|
|
18
|
+
}
|
|
19
|
+
export interface ElementTreeSource {
|
|
20
|
+
/** Which capture tool produced this tree. Common values:
|
|
21
|
+
* `"extension"` (browser extension MAIN-world walker),
|
|
22
|
+
* `"playwright"` (ariaSnapshot adapter). Open-ended so future
|
|
23
|
+
* Figma / screen-recorder / OCR adapters slot in cleanly. */
|
|
24
|
+
kind: "extension" | "playwright" | (string & {});
|
|
25
|
+
/** ISO 8601 timestamp of when the tree was produced. */
|
|
26
|
+
capturedAt: string;
|
|
27
|
+
/** Optional human-readable tool identifier (e.g.
|
|
28
|
+
* `"annot-playwright@0.4.0"`). Used in `annot show-xmp` output for
|
|
29
|
+
* debug; not consumed programmatically. */
|
|
30
|
+
agent?: string;
|
|
31
|
+
/** Source page URL at capture time, if applicable. */
|
|
32
|
+
url?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface ElementTreeViewport {
|
|
35
|
+
/** Viewport width in CSS px. */
|
|
36
|
+
width: number;
|
|
37
|
+
/** Viewport height in CSS px. */
|
|
38
|
+
height: number;
|
|
39
|
+
/** `window.devicePixelRatio` (or equivalent) at capture time. Used
|
|
40
|
+
* to map CSS-px bboxes onto device-px screenshot coordinates. */
|
|
41
|
+
scale: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Per-node payload. Children are nested in `children`; the tree is
|
|
45
|
+
* walked depth-first.
|
|
46
|
+
*/
|
|
47
|
+
export interface ElementNode {
|
|
48
|
+
/** ARIA role. Always present — decorative nodes use `"generic"` or
|
|
49
|
+
* `"presentation"`. Browser captures fall back to the implicit
|
|
50
|
+
* role for the underlying tag when ARIA doesn't apply. */
|
|
51
|
+
role: string;
|
|
52
|
+
/** Accessible name. Omitted when empty. */
|
|
53
|
+
name?: string;
|
|
54
|
+
/** Page-space bounding box in CSS px. Omitted for hidden / abstract
|
|
55
|
+
* nodes (e.g. document root with no measurable extent). */
|
|
56
|
+
bbox?: BBox;
|
|
57
|
+
/** Tree-unique identifier in `e<n>` format (depth-first numbering
|
|
58
|
+
* starting at `e1`). Stable WITHIN one capture; NOT stable across
|
|
59
|
+
* re-captures — see OQ-11 in the roadmap. */
|
|
60
|
+
ref: string;
|
|
61
|
+
/** ARIA-derived state tokens. Single tokens like `"checked"`,
|
|
62
|
+
* `"pressed"`, `"expanded"`, `"selected"`, `"disabled"`,
|
|
63
|
+
* `"required"`, `"invalid"`. Also accepts `key=value` tokens for
|
|
64
|
+
* scalar states: `"level=2"`, `"valuetext=10"`. */
|
|
65
|
+
states?: readonly string[];
|
|
66
|
+
/** HTML attribute snapshot (whitelist-filtered at capture time).
|
|
67
|
+
* Keys are lowercase attribute names; values are the attribute
|
|
68
|
+
* strings. Empty when no attributes were captured. */
|
|
69
|
+
attributes?: Readonly<Record<string, string>>;
|
|
70
|
+
/** Direct text content (heading body, paragraph text, textbox
|
|
71
|
+
* value). Distinct from `name` for elements where they differ
|
|
72
|
+
* (e.g. a textbox with placeholder `"Email"` and current value
|
|
73
|
+
* `"alice@example.com"` has `name: "Email"`, `text:
|
|
74
|
+
* "alice@example.com"`). */
|
|
75
|
+
text?: string;
|
|
76
|
+
/** Children in document order. Omitted for leaf nodes. */
|
|
77
|
+
children?: readonly ElementNode[];
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Axis-aligned bounding box. CSS px, page-space coordinates.
|
|
81
|
+
*/
|
|
82
|
+
export interface BBox {
|
|
83
|
+
x: number;
|
|
84
|
+
y: number;
|
|
85
|
+
width: number;
|
|
86
|
+
height: number;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Convenience type guard for callers that receive `unknown` payloads
|
|
90
|
+
* and need to check whether they look like an ElementTree before
|
|
91
|
+
* narrowing. Light validation only — checks for the presence of the
|
|
92
|
+
* three required top-level keys plus `version === 1`. The full
|
|
93
|
+
* parsers (`parseElementTreeFromYaml` / `parseElementTreeFromJson`)
|
|
94
|
+
* do exhaustive structural validation.
|
|
95
|
+
*/
|
|
96
|
+
export declare function isElementTreeShape(value: unknown): value is ElementTree;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ElementNode, ElementTree } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Visitor callback. Return `false` to stop traversal early; return
|
|
4
|
+
* `void` / `true` to keep walking. The `parents` array gives the
|
|
5
|
+
* ancestor chain from the root down to (but excluding) the visited
|
|
6
|
+
* node — empty for the root itself.
|
|
7
|
+
*/
|
|
8
|
+
export type ElementTreeVisitor = (node: ElementNode, parents: readonly ElementNode[]) => boolean | void;
|
|
9
|
+
/**
|
|
10
|
+
* Depth-first walk over every node in the tree. Stops early when the
|
|
11
|
+
* visitor returns `false`.
|
|
12
|
+
*/
|
|
13
|
+
export declare function walkTree(tree: ElementTree, visit: ElementTreeVisitor): void;
|
|
14
|
+
/**
|
|
15
|
+
* Find the unique node with the given `ref`, or `null` if none.
|
|
16
|
+
* Refs are tree-unique within one capture (depth-first numbering),
|
|
17
|
+
* so the first match is the only match.
|
|
18
|
+
*/
|
|
19
|
+
export declare function findByRef(tree: ElementTree, ref: string): ElementNode | null;
|
|
20
|
+
/**
|
|
21
|
+
* Match descriptor used by annotation yaml's `match: { role, name }`
|
|
22
|
+
* resolver. Both fields optional independently — a `{ role: "main" }`
|
|
23
|
+
* match catches every node with that role regardless of name; a
|
|
24
|
+
* `{ name: "Sign in" }` catches every node with that name regardless
|
|
25
|
+
* of role. When both are set, both must match (AND semantics). `name`
|
|
26
|
+
* comparison is exact.
|
|
27
|
+
*/
|
|
28
|
+
export interface ElementMatch {
|
|
29
|
+
role?: string;
|
|
30
|
+
name?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Find every node satisfying the match. Returns nodes in
|
|
34
|
+
* depth-first document order.
|
|
35
|
+
*
|
|
36
|
+
* Returning all matches (not just the first) lets callers detect
|
|
37
|
+
* ambiguity — drift detection flags `duplicated` when a unique
|
|
38
|
+
* `match` resolves to more than one node.
|
|
39
|
+
*/
|
|
40
|
+
export declare function findByMatch(tree: ElementTree, match: ElementMatch): ElementNode[];
|
|
41
|
+
/**
|
|
42
|
+
* Produce a flat array of every node in depth-first document order.
|
|
43
|
+
* Each entry is the live `ElementNode` reference (no copying); the
|
|
44
|
+
* caller must treat the result as read-only.
|
|
45
|
+
*
|
|
46
|
+
* Useful for consumers that prefer flat iteration (search index
|
|
47
|
+
* builders, etc.). Prefer `walkTree` when ancestor context matters.
|
|
48
|
+
*/
|
|
49
|
+
export declare function flattenTree(tree: ElementTree): ElementNode[];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ElementTree } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Serialize an ElementTree to YAML.
|
|
4
|
+
*
|
|
5
|
+
* The output uses 2-space indent, sorted top-level keys, and
|
|
6
|
+
* deterministic field ordering inside each node so the same tree
|
|
7
|
+
* always serializes to byte-identical YAML. This is important for
|
|
8
|
+
* the XMP write path — re-saving a PNG without semantic changes
|
|
9
|
+
* must produce identical bytes, otherwise git history thrashes
|
|
10
|
+
* pointlessly.
|
|
11
|
+
*
|
|
12
|
+
* Empty optional fields (`states`, `attributes`, `children`) are
|
|
13
|
+
* omitted entirely. The reader treats absence and empty as
|
|
14
|
+
* equivalent.
|
|
15
|
+
*/
|
|
16
|
+
export declare function serializeElementTreeToYaml(tree: ElementTree): string;
|
|
17
|
+
/**
|
|
18
|
+
* Parse a YAML string into an ElementTree. Throws `Error` with a
|
|
19
|
+
* descriptive message on malformed input (parse failure or schema
|
|
20
|
+
* mismatch).
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseElementTreeFromYaml(yaml: string): ElementTree;
|
package/dist/headless.d.ts
CHANGED
|
@@ -14,16 +14,18 @@ export { normalizeVariantSideFields, TOOL_PANEL_EXTRA_CONTROL_IDS, TOOL_REGISTRY
|
|
|
14
14
|
export { readUniversalStyleAttrs, resolveStyleReadSource, } from './editor/tool-style-reader.js';
|
|
15
15
|
export { writeUniversalStyleAttrs } from './editor/tool-style-writer.js';
|
|
16
16
|
export { type AffineMatrix, applyInverseAffine, clampZoom, computeFitZoom, computeRenderedSize, DEFAULT_MAX_ZOOM, DEFAULT_MIN_ZOOM, FIT_VIEW_PADDING, } from './editor/viewport-math.js';
|
|
17
|
+
export { type BBox, type ElementMatch, type ElementNode, type ElementTree, type ElementTreeSource, type ElementTreeViewport, type ElementTreeVisitor, findByMatch, findByRef, flattenTree, isElementTreeShape, parseElementTreeFromJson, parseElementTreeFromYaml, serializeElementTreeToJson, serializeElementTreeToYaml, validateElementTree, walkTree, } from './element-tree/index.js';
|
|
17
18
|
export { builtinIcon, type IconSpec, isBuiltinIcon, isSvgIcon, isUrlIcon, svgIcon, urlIcon, } from './icons/types.js';
|
|
18
19
|
export { StorageConflictError, StorageError, type StorageErrorCode, StorageNotFoundError, StoragePermissionError, StorageQuotaError, } from './storage/errors.js';
|
|
19
20
|
export { type ListingEntry, type ListingEntryKind, type MetadataCache, MetadataCacheError, MetadataCacheQuotaError, type StorageWithMetadataCache, supportsMetadataCache, } from './storage/metadata-cache.js';
|
|
20
21
|
export { ancestorPaths, getFilename, getParentPath, isDescendantOrSame, joinPath, ROOT_PATH, rewritePathPrefix, splitExt, splitPath, uniquifyFilename, uniquifyFilenameAsync, validateName, } from './storage/path.js';
|
|
21
22
|
export { type CachedThumbnail, type ThumbnailCache, ThumbnailCacheError, type ThumbnailCacheGetRequest, ThumbnailCacheQuotaError, } from './storage/thumbnail-cache.js';
|
|
22
|
-
export type { DocumentRecord, DocumentRecordUpdate, FolderRecord, ImageRecord, ImageRecordUpdate,
|
|
23
|
+
export type { DocumentRecord, DocumentRecordUpdate, FolderRecord, ImageRecord, ImageRecordUpdate, StorageProvider, StorageWithDocuments, StorageWithForceRefresh, StorageWithInit, StorageWithRateLimit, StorageWithResync, StorageWithTokenRefresher, } from './storage/types.js';
|
|
23
24
|
export { supportsDocuments, supportsForceRefresh, supportsInit, supportsRateLimit, supportsResync, supportsTokenRefresher, } from './storage/types.js';
|
|
24
25
|
export { assertNonNull } from './utils/assert.js';
|
|
25
26
|
export { DEFAULT_FILL_COLOR, DEFAULT_FONT_SIZE, DEFAULT_STROKE_COLOR, DEFAULT_STROKE_WIDTH, JPEG_QUALITY, MOSAIC_BLOCK_SIZE, } from './utils/constants.js';
|
|
26
27
|
export { computeDasharray, detectDashKey } from './utils/dash-utils.js';
|
|
27
28
|
export { ANNOT_FILENAME_PREFIX, defaultAnnotFilenameStem, defaultAnnotImageFilename, formatLocalTimestamp, } from './utils/filename.js';
|
|
28
29
|
export { newIdB58 } from './utils/id.js';
|
|
30
|
+
export { ELEMENT_TREE_ITXT_KEYWORD, hasElementTreePng, readElementTreePng, writeElementTreePng, } from './xmp/element-tree-payload.js';
|
|
29
31
|
export { buildZip, dataUrlExt, dataUrlToBytes } from './zip/zip-builder.js';
|