@docx-editor.dev/pro 2.0.1 → 2.1.1

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.
@@ -0,0 +1,500 @@
1
+ import { EditorModule } from '@docx-editor.dev/core/editor';
2
+ import { OoxmlPart } from '@docx-editor.dev/core/store';
3
+
4
+ /**
5
+ * Licensing, v1: honor system.
6
+ *
7
+ * The key is accepted and remembered so that adding offline (Ed25519)
8
+ * verification later is not a breaking change — but nothing validates it,
9
+ * nothing warns, nothing renders differently, and NOTHING EVER LEAVES THE
10
+ * PROCESS: no network request is made for licensing, ever. That last property
11
+ * is a spec requirement (`pro-licensing`), not an implementation detail.
12
+ */
13
+ /** Accepted by every pro entry point. */
14
+ interface ProLicenseOptions {
15
+ /**
16
+ * Your license key from docx-editor.dev. Optional in v1: unlicensed use in
17
+ * development and evaluation is permitted, production use requires a
18
+ * license (see LICENSE.md) — the package trusts you either way.
19
+ */
20
+ readonly licenseKey?: string;
21
+ }
22
+
23
+ /**
24
+ * The review module: comments, tracked changes, and markup rendering as an
25
+ * `EditorModule` for `createDocxEditor({ modules })`.
26
+ *
27
+ * Registering it is the whole enablement story: the review chrome slots light
28
+ * up through the same `toolbarCommandState` they were disabled by, suggesting
29
+ * mode becomes reachable, and the editor renders revisions in markup rather
30
+ * than the free tier's final-state projection.
31
+ */
32
+
33
+ /**
34
+ * How {@link reviewModule} is configured. Carries only the licence key today, so
35
+ * `reviewModule()` with no argument is the ordinary call.
36
+ *
37
+ * @public
38
+ */
39
+ interface ReviewModuleOptions extends ProLicenseOptions {
40
+ }
41
+ /** Build the review module. Construction never validates the key and never touches the network. */
42
+ declare function reviewModule(options?: ReviewModuleOptions): EditorModule;
43
+
44
+ /**
45
+ * The Standard Schema interface, vendored.
46
+ *
47
+ * Any zod, valibot or arktype schema satisfies it. See https://standardschema.dev.
48
+ *
49
+ * Reduced to the parts used here rather than copied: the spec's namespace, `Props`,
50
+ * `SuccessResult`/`FailureResult`, `PathSegment` and `InferInput` are all absent. Assignability
51
+ * with a real schema is what matters, and is checked against zod in the tests.
52
+ */
53
+ interface StandardSchemaV1<Input = unknown, Output = Input> {
54
+ readonly '~standard': {
55
+ readonly version: 1;
56
+ readonly vendor: string;
57
+ readonly validate: (value: unknown) => StandardSchemaResult<Output> | Promise<StandardSchemaResult<Output>>;
58
+ readonly types?: {
59
+ readonly input: Input;
60
+ readonly output: Output;
61
+ } | undefined;
62
+ };
63
+ }
64
+ /** What a Standard Schema validation answers. */
65
+ type StandardSchemaResult<Output> = {
66
+ readonly value: Output;
67
+ readonly issues?: undefined;
68
+ } | {
69
+ readonly issues: readonly StandardSchemaIssue[];
70
+ };
71
+ /** One validation failure. `path` is what tells a host WHICH field was wrong. */
72
+ interface StandardSchemaIssue {
73
+ readonly message: string;
74
+ readonly path?: readonly (PropertyKey | {
75
+ readonly key: PropertyKey;
76
+ })[] | undefined;
77
+ }
78
+ /**
79
+ * The type a schema produces, for a definition to hand back to its host.
80
+ *
81
+ * `unknown` for a definition with no schema, which is the honest description of an unchecked
82
+ * payload — not `never`, which would make the field unusable rather than merely unguaranteed.
83
+ */
84
+ type InferSchemaOutput<Schema> = 0 extends 1 & Schema ? any : Schema extends StandardSchemaV1<unknown, infer Output> ? Output : unknown;
85
+ /**
86
+ * The type a schema ACCEPTS, which is what a write has to satisfy.
87
+ *
88
+ * Different from the output whenever the schema transforms — a zod `.default()` or `.transform()`
89
+ * takes one shape and produces another — so a write typed by the output would reject the very
90
+ * value the schema was written to accept.
91
+ */
92
+ type InferSchemaInput<Schema> = 0 extends 1 & Schema ? any : Schema extends StandardSchemaV1<infer Input, unknown> ? Input : unknown;
93
+ /**
94
+ * Why a payload was refused.
95
+ *
96
+ * `malformed` is not valid JSON at all; `invalid` parsed but did not match the schema; `async`
97
+ * is a schema whose validation returns a promise, which cannot be used here (see below).
98
+ */
99
+ type CustomNodeDataRejection = 'malformed' | 'invalid' | 'async';
100
+ /** What {@link parseCustomNodeData} answers. */
101
+ type CustomNodeDataResult<Output> = {
102
+ readonly ok: true;
103
+ readonly value: Output;
104
+ } | {
105
+ readonly ok: false;
106
+ readonly reason: CustomNodeDataRejection;
107
+ /** Human-readable, for a host to log. Never rendered as markup by this package. */
108
+ readonly issues: readonly string[];
109
+ };
110
+ /**
111
+ * The largest payload this will parse, in UTF-16 code units.
112
+ *
113
+ * A file-supplied length must never reach an allocation, and `JSON.parse` on a hostile string
114
+ * is the allocation. 256 KB is far past any legitimate chip payload and far short of anything
115
+ * that hurts.
116
+ */
117
+ declare const MAX_CUSTOM_NODE_DATA_LENGTH: number;
118
+ /**
119
+ * Parse a payload out of a data part and validate it against the definition's schema.
120
+ *
121
+ * Synchronous on purpose. This runs inside the read path, where recognition happens for every
122
+ * node in the document before anything paints, and an async boundary there would mean a
123
+ * document that renders its chips a frame later than its text. A schema with an async refinement
124
+ * is refused (`async`) rather than awaited, so the limitation is visible instead of silent.
125
+ *
126
+ * A payload with no schema comes back as the parsed JSON, typed `unknown` — the host asked for
127
+ * no guarantees and gets none, rather than getting a lie. It is also a NULL-PROTOTYPE object on
128
+ * that path, where a schema-validated one is whatever the validator rebuilt: `hasOwnProperty`
129
+ * and `instanceof Object` do not hold on the former.
130
+ */
131
+ declare function parseCustomNodeData<Schema extends StandardSchemaV1 | undefined>(schema: Schema, raw: string): CustomNodeDataResult<Schema extends StandardSchemaV1 ? InferSchemaOutput<Schema> : unknown>;
132
+ /**
133
+ * Serialize a payload for a data part. Refuses what cannot round-trip through JSON.
134
+ *
135
+ * NOT symmetric with {@link parseCustomNodeData}: a key named `__proto__`, `constructor` or
136
+ * `prototype` is written here and dropped on the way back, because a payload arriving from a
137
+ * file is the hazard and a payload leaving this process is not. A host that needs those keys
138
+ * needs a different name for them.
139
+ */
140
+ declare function serializeCustomNodeData(value: unknown): CustomNodeDataResult<string>;
141
+
142
+ /** A recognized custom node: one inline SDT whose tag matched a definition. */
143
+ interface RecognizedCustomNode {
144
+ /** The definition's `name`. */
145
+ readonly name: string;
146
+ /** Attrs after the definition's `fromDocx` had its say. Untrusted input. */
147
+ readonly attrs: Readonly<Record<string, string>>;
148
+ /** The SDT's literal content text — what Word users see and may have edited. */
149
+ readonly text: string;
150
+ /** The SDT node's stable id in the canonical tree. */
151
+ readonly nodeId: string;
152
+ /** The raw `w:tag` the node was recognized from. */
153
+ readonly tag: string;
154
+ /**
155
+ * The payload the node's control binds to, validated against the definition's `schema`.
156
+ *
157
+ * `undefined` when the node carries none, when the binding named a store node the document
158
+ * does not hold, or when the payload failed its schema — the last of which is reported
159
+ * through {@link customNodesModule}'s `onDiagnostic` rather than swallowed. A chip that
160
+ * vanished because one field was wrong would be worse than a chip with no data.
161
+ *
162
+ * With a schema declared this is that schema's output type; without one it is whatever JSON
163
+ * the file held, which is the honest description of an unchecked payload.
164
+ */
165
+ readonly data?: unknown;
166
+ }
167
+ /** A payload as the store holds it, before any schema has looked at it. Untrusted file input. */
168
+ interface CustomNodePayloadSource {
169
+ readonly nodeId: string;
170
+ readonly label: string;
171
+ readonly data: string;
172
+ }
173
+ /**
174
+ * Something worth telling an integrator about a document, which is never worth throwing over.
175
+ *
176
+ * A payload arrives from a file the sender wrote, so "it did not match the schema" is an
177
+ * ordinary property of an ordinary document — not an exception. It is reported and the node
178
+ * still renders.
179
+ */
180
+ interface CustomNodeDiagnostic {
181
+ /**
182
+ * `payload-invalid` — a payload was found and did not match the schema.
183
+ * `payload-missing` — the control's binding names a store node the document does not hold.
184
+ *
185
+ * The second is what a half-stripped export or a hand-edited file leaves behind, and it used
186
+ * to be indistinguishable from "this node carries no payload": both arrive as `data:
187
+ * undefined` and neither said anything.
188
+ */
189
+ readonly code: 'payload-invalid' | 'payload-missing';
190
+ /** The definition whose schema refused it. */
191
+ readonly name: string;
192
+ /** The control's canonical node id, so a host can locate it. */
193
+ readonly nodeId: string;
194
+ /** Human-readable, one per failing field. Never rendered as markup by this package. */
195
+ readonly issues: readonly string[];
196
+ }
197
+ /**
198
+ * One integrator-defined inline node, anchored on a run-level SDT whose `w:tag` carries its
199
+ * identity.
200
+ *
201
+ * A definition claims a tag PREFIX, so `acme` recognizes every `acme:*` tag. An SDT whose prefix
202
+ * no definition claims stays literal — which is also what the free tier and Word itself render,
203
+ * so an unrecognized node never loses content or locks editing.
204
+ *
205
+ * Build one with {@link defineCustomNode}, which validates the shape, then register it through
206
+ * {@link customNodesModule}.
207
+ *
208
+ * @example
209
+ * ```ts
210
+ * const citation = defineCustomNode({
211
+ * name: 'citation',
212
+ * tagPrefix: 'acme',
213
+ * chrome: { color: '#2563eb' },
214
+ * onClick: (node) => openCitation(node.attrs.key),
215
+ * });
216
+ * ```
217
+ *
218
+ * @public
219
+ */
220
+ interface CustomNodeDefinition<Schema extends StandardSchemaV1 | undefined = any> {
221
+ /** Node type name — the second segment of the tag (`<prefix>:<name>?…`). */
222
+ readonly name: string;
223
+ /** Tag prefix this definition claims (`acme` claims `acme:*`). No colons. */
224
+ readonly tagPrefix: string;
225
+ /**
226
+ * What the document SHOWS for this node, from its payload.
227
+ *
228
+ * The one thing most definitions need beyond an identity and a schema:
229
+ *
230
+ * ```ts
231
+ * defineCustomNode({
232
+ * name: 'citation',
233
+ * tagPrefix: 'docx',
234
+ * schema: CitationData,
235
+ * text: (data) => `(${data.authors[0]} ${data.year})`,
236
+ * });
237
+ * ```
238
+ *
239
+ * With it, a write takes the payload alone — `insertCustomNode(editor, Citation, { data })` —
240
+ * and the words in the paragraph are computed, so they cannot drift from the data they
241
+ * describe. Without it, pass `text` on every call and keep the two in step yourself.
242
+ *
243
+ * Word paints a bound control's text from the payload and will not let a user type into it,
244
+ * so this is the only thing that decides what a reader sees.
245
+ */
246
+ readonly text?: (data: InferSchemaOutput<Schema>) => string;
247
+ /**
248
+ * Extra identity to put in the `w:tag`, from the payload. Rarely needed.
249
+ *
250
+ * The tag already carries `<prefix>:<name>`, which is what recognition matches on, so most
251
+ * nodes need nothing here. Add it when a reader that opens the document WITHOUT the payload
252
+ * store should still be able to tell which one this is — a `sourceId` on a citation, say.
253
+ *
254
+ * Word caps the encoded tag at 64 characters, prefix and name included.
255
+ */
256
+ readonly tagAttrs?: (data: InferSchemaOutput<Schema>) => Readonly<Record<string, string>>;
257
+ /**
258
+ * Recognition hook. Receives the decoded attrs and the SDT's literal text
259
+ * (so label drift from Word edits is visible) and returns the attrs the node
260
+ * should carry — or null to leave this SDT unrecognized and literal.
261
+ *
262
+ * Every input value originates in a file an attacker controls; treat it as
263
+ * untrusted and never build DOM or URLs from it without sanitizing.
264
+ */
265
+ readonly fromDocx?: (input: {
266
+ readonly attrs: Readonly<Record<string, string>>;
267
+ readonly text: string;
268
+ /**
269
+ * The bound payload, already through `schema` — so this is the type the definition
270
+ * declared, not `unknown`. Undefined when the node carries none or it did not match.
271
+ */
272
+ readonly data?: InferSchemaOutput<Schema>;
273
+ }) => Readonly<Record<string, string>> | null;
274
+ /**
275
+ * Chip appearance, HOST-authored (never file data). `color` tints the chip
276
+ * and its border; applied by `CustomNodeChrome` from `@docx-editor.dev/pro/react`.
277
+ */
278
+ readonly chrome?: {
279
+ readonly color?: string;
280
+ };
281
+ /** Click on the painted chip. UI state belongs in `CustomNodeChrome`'s `onNodeClick`. */
282
+ readonly onClick?: (node: ActivatedCustomNode) => void;
283
+ /** Pointer enters the painted chip. */
284
+ readonly onHover?: (node: ActivatedCustomNode) => void;
285
+ /**
286
+ * Contribute a card to the review sidebar for every recognized node of this
287
+ * definition, anchored at the node's range. Return null to skip one node.
288
+ *
289
+ * `attrs` and `text` originate in the file — untrusted; the returned strings
290
+ * are rendered as TEXT by the pane, never markup. The context-menu section
291
+ * reuses this hook for its info block and may invoke it with `text: ''` when
292
+ * no review module is registered (the DOM decode alone cannot see the text).
293
+ */
294
+ readonly reviewCard?: (node: {
295
+ readonly attrs: Readonly<Record<string, string>>;
296
+ readonly text: string;
297
+ /** The bound payload, already through `schema` — see {@link CustomNodeDefinition.fromDocx}. */
298
+ readonly data?: InferSchemaOutput<Schema>;
299
+ }) => {
300
+ readonly title: string;
301
+ readonly detail?: string;
302
+ } | null;
303
+ /**
304
+ * The "Edit {label}" row the context menu shows at the top when the
305
+ * right-click lands on the node's chip. The HOST owns the dialog.
306
+ *
307
+ * Re-author with `updateCustomNode(editor, definition, node.nodeId, attrs, text, { data })`:
308
+ * one transaction, one undo step. The activation carries `nodeId`, the node's `text` and its
309
+ * `data`, which is everything a prefilled form needs.
310
+ */
311
+ readonly onEdit?: (node: ActivatedCustomNode) => void;
312
+ /**
313
+ * Display name for chrome — the "Edit {label}" context-menu row. Defaults to
314
+ * `name`. Host-authored, never file data; provide a localized string.
315
+ */
316
+ readonly label?: string;
317
+ /**
318
+ * The shape of this node's payload, as a zod (or valibot, or arktype) schema.
319
+ *
320
+ * A payload lives in a customXml data part, so it arrives from a file the sender controls.
321
+ * Declaring the shape means it is parsed and checked ONCE, at the read boundary, after which
322
+ * the `data` handed to the hooks is the type that was asked for rather than something every
323
+ * caller has to re-guard. Without one, `data` is whatever JSON the file held, typed
324
+ * `unknown`, which is the honest description of an unchecked payload.
325
+ *
326
+ * Any Standard Schema satisfies this, which is what zod produces:
327
+ *
328
+ * ```ts
329
+ * const Citation = z.object({ sourceId: z.string(), year: z.number() });
330
+ * defineCustomNode({ name: 'citation', tagPrefix: 'acme', schema: Citation });
331
+ * ```
332
+ *
333
+ * Validated on the way IN as well as on the way out, so a payload that does not match is
334
+ * refused at the insert rather than written and rejected on the next open.
335
+ */
336
+ readonly schema?: Schema;
337
+ /**
338
+ * The customXml store this definition's payloads live in.
339
+ *
340
+ * One store per namespace, per document, so this is what decides whether two definitions
341
+ * share a store or get one each. Defaults to a namespace derived from `tagPrefix`, which
342
+ * means a host that never thinks about it still gets one store per prefix and never collides
343
+ * with another integrator's.
344
+ *
345
+ * Set it to interoperate with something that already reads a namespace of its own. Whatever
346
+ * it is, it must be free of quotes and angle brackets: it is written into an XPath prefix
347
+ * declaration, where there is no escape for either.
348
+ */
349
+ readonly payloadNamespace?: string;
350
+ /**
351
+ * What happens to this node when a document is exported OUTSIDE the system that made it.
352
+ *
353
+ * A host may not want its own markup travelling in a file its users download: a `w:tag`
354
+ * naming the tool, or a payload with no meaning anywhere else. This declares the fate, and
355
+ * the save that applies it picks the pipeline — so one document can serialize one way at
356
+ * rest and another on the way out.
357
+ *
358
+ * - `true` (default) — the node and its payload survive untouched.
359
+ * - `'text'` — the control is unwrapped: a reader still sees the words, while the tag, the
360
+ * binding and the payload are gone. Right for a citation, whose text is the point of it.
361
+ * - `false` — the node goes, and takes its content with it.
362
+ *
363
+ * Applied by `prepareForExport`, which is a pipeline of its own rather than something
364
+ * `save()` does — that is what lets one document serialize one way at rest and another on the
365
+ * way out.
366
+ *
367
+ * IT DOES NOT MAKE A DOCUMENT ANONYMOUS. It removes this library's markup and nothing else. A
368
+ * `.docx` carries its origin in `docProps/app.xml`, `docProps/core.xml`, comment and revision
369
+ * authors, rsids and custom document properties.
370
+ */
371
+ readonly preserveOnExport?: boolean | 'text';
372
+ }
373
+ /**
374
+ * A definition, plus what {@link defineCustomNode} attaches to it.
375
+ *
376
+ * You author a {@link CustomNodeDefinition}; you are handed one of these. The difference is
377
+ * `dataOf`, which cannot be written by hand because it closes over the schema you just declared.
378
+ */
379
+ interface CustomNode<Schema extends StandardSchemaV1 | undefined = any> extends CustomNodeDefinition<Schema> {
380
+ /**
381
+ * This node's payload, from a surface that carries every definition's under one type.
382
+ *
383
+ * `RecognizedCustomNode.data`, `ActivatedCustomNode.data` and `ReviewCustomItem.data` are all
384
+ * `unknown`, because each of those can be any registered definition's node. This narrows one
385
+ * to THIS definition and validates its payload against THIS schema, so a host reads a typed
386
+ * value without importing its own validator at the call site:
387
+ *
388
+ * ```ts
389
+ * const survey = Iceberg.dataOf(node); // IcebergData | undefined
390
+ * ```
391
+ *
392
+ * `undefined` when the node is a different definition's, carries no payload, or holds one the
393
+ * schema rejects — the three cases a caller has to handle anyway.
394
+ *
395
+ * `name` is checked when present and never required, so this also works on a host's own object
396
+ * that kept only the payload:
397
+ *
398
+ * ```ts
399
+ * const survey = Iceberg.dataOf(popoverState); // { data } is enough
400
+ * ```
401
+ */
402
+ readonly dataOf: (node: {
403
+ readonly name?: string;
404
+ readonly data?: unknown;
405
+ } | null | undefined) => InferSchemaOutput<Schema> | undefined;
406
+ }
407
+ /**
408
+ * A definition of any payload shape, spelled out.
409
+ *
410
+ * The AUTHORED shape, which is what every collection and every internal helper takes: they read
411
+ * `name`, `schema`, `text` and `preserveOnExport` and never need `dataOf`. A {@link CustomNode}
412
+ * is assignable to it, so `defineCustomNode`'s result goes wherever this is asked for.
413
+ *
414
+ * The same thing bare `CustomNodeDefinition` already means — the interface defaults its
415
+ * parameter to `any` for exactly this reason. `CustomNodeDefinition<Schema>` is INVARIANT in
416
+ * `Schema`, because the schema's output type appears in the PARAMETER of `fromDocx` and
417
+ * `reviewCard`; that is what makes those hooks typed, and it also means two definitions with
418
+ * different schemas are not assignable to one another. Had the default been `undefined`, the
419
+ * obvious annotation — `const nodes: CustomNodeDefinition[] = [citation, figure]` — would fail
420
+ * with a message naming neither the cause nor this alias.
421
+ *
422
+ * The cost, stated plainly: `data` is unchecked wherever a definition is held under this type.
423
+ * Pull one out of a registry and `insertCustomNode(editor, def, attrs, text, { data })` accepts
424
+ * any shape at all. Payload typing lives where the definition is WRITTEN — `defineCustomNode`
425
+ * infers the schema, and its hooks are typed from it.
426
+ */
427
+ type AnyCustomNodeDefinition = CustomNodeDefinition;
428
+ /**
429
+ * A chip activation: identity + attrs, plus where it sits.
430
+ *
431
+ * `attrs` are the definition's OWN shape — the raw tag decode has already been
432
+ * through `fromDocx`, exactly as the review derivation runs it, so every
433
+ * surface (click, hover, edit, cards) sees one attrs vocabulary. `text` and
434
+ * `nodeId` are present when the surface could resolve them (a registered
435
+ * review module resolves both).
436
+ */
437
+ interface ActivatedCustomNode {
438
+ readonly name: string;
439
+ readonly attrs: Readonly<Record<string, string>>;
440
+ readonly tag: string;
441
+ /** Viewport-relative rect of the chip's boundary, for anchoring host UI. */
442
+ readonly rect: DOMRect;
443
+ /** The SDT node's canonical id — the address `removeContentControl` takes. */
444
+ readonly nodeId?: string;
445
+ /** The node's literal content text, when resolvable. */
446
+ readonly text?: string;
447
+ /**
448
+ * The node's payload, when the surface could resolve one.
449
+ *
450
+ * Present only where the review derivation has already run — a chip's own click and hover
451
+ * resolve through the review item, which is what carries the payload. Undefined otherwise,
452
+ * and undefined for a node whose payload failed its schema.
453
+ */
454
+ readonly data?: unknown;
455
+ }
456
+ /**
457
+ * Whether an opaque registry value is a custom-node definition.
458
+ *
459
+ * The engine carries registered definitions as unknowns (`getCustomNodeDefinitions`), so
460
+ * every pro surface that reads them back narrows through this ONE guard.
461
+ */
462
+ declare function isCustomNodeDefinition(candidate: unknown): candidate is AnyCustomNodeDefinition;
463
+ /** Validate and freeze a definition. Throws on a shape mistake — author error, not file input. */
464
+ declare function defineCustomNode<Schema extends StandardSchemaV1 | undefined = undefined>(definition: CustomNodeDefinition<Schema>): CustomNode<Schema>;
465
+ /**
466
+ * How {@link customNodesModule} is configured.
467
+ *
468
+ * @public
469
+ */
470
+ interface CustomNodesModuleOptions extends ProLicenseOptions {
471
+ /** The definitions this editor recognizes. A tag prefix no definition claims stays literal. */
472
+ readonly nodes: readonly AnyCustomNodeDefinition[];
473
+ /**
474
+ * Told about a document, never about a bug: a payload that failed its schema, so far.
475
+ *
476
+ * A payload comes from a file the sender wrote, so a mismatch is an ordinary property of an
477
+ * ordinary document. The node still renders, without its `data`; this is how an integrator
478
+ * finds out rather than wondering why one chip's dialog is empty.
479
+ */
480
+ readonly onDiagnostic?: (diagnostic: CustomNodeDiagnostic) => void;
481
+ }
482
+ /** Register custom node definitions with `createDocxEditor({ modules })`. */
483
+ declare function customNodesModule(options: CustomNodesModuleOptions): EditorModule;
484
+ /**
485
+ * Every recognized custom node in one story, in document order.
486
+ *
487
+ * Tag-prefix keyed, exactly as the change specifies: an inline SDT whose tag
488
+ * decodes to a registered `<prefix>:<name>` pair is offered to that
489
+ * definition's `fromDocx`; everything else — foreign tags, unregistered
490
+ * prefixes, a `fromDocx` veto — stays a literal SDT.
491
+ */
492
+ interface RecognizeCustomNodesOptions {
493
+ /** The payload each control binds, from `customNodePayloadsByControl`. */
494
+ readonly payloads?: ReadonlyMap<string, CustomNodePayloadSource>;
495
+ /** Told about a node whose payload could not be read. Omitted, nothing is reported. */
496
+ readonly onDiagnostic?: (diagnostic: CustomNodeDiagnostic) => void;
497
+ }
498
+ declare function recognizeCustomNodes(part: OoxmlPart, definitions: readonly AnyCustomNodeDefinition[], options?: RecognizeCustomNodesOptions): RecognizedCustomNode[];
499
+
500
+ export { type AnyCustomNodeDefinition as A, type CustomNodeDiagnostic as C, type InferSchemaInput as I, MAX_CUSTOM_NODE_DATA_LENGTH as M, type ProLicenseOptions as P, type RecognizedCustomNode as R, type StandardSchemaV1 as S, type CustomNodeDefinition as a, type ActivatedCustomNode as b, type CustomNode as c, type CustomNodeDataRejection as d, type CustomNodeDataResult as e, type CustomNodePayloadSource as f, type CustomNodesModuleOptions as g, type InferSchemaOutput as h, type RecognizeCustomNodesOptions as i, type ReviewModuleOptions as j, type StandardSchemaIssue as k, type StandardSchemaResult as l, customNodesModule as m, defineCustomNode as n, isCustomNodeDefinition as o, parseCustomNodeData as p, reviewModule as q, recognizeCustomNodes as r, serializeCustomNodeData as s };
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- 'use strict';var chunkTNSHSAA4_cjs=require('./chunk-TNSHSAA4.cjs'),store=require('@docx-editor.dev/core/store');function x(e){return e.surface??null}function v(e,n,a,t,o={}){let r=x(e);if(!r)return {ok:false,code:"notFound",reason:"no document is mounted"};let s=chunkTNSHSAA4_cjs.b(n.tagPrefix,n.name,a);if(!s.ok)return {ok:false,code:"invalidArgs",reason:`the encoded tag is ${s.length} characters; Word caps w:tag at 64 \u2014 shorten the attrs (the customXml data-part escape hatch is not built yet)`};let i=o.at??r.state().selection.head,c=o.lock===void 0?"contentLocked":o.lock,u=r.session.applyTreeOps([{op:"insertInlineContentControl",paragraphId:i.paragraphId,offset:i.offset,tag:s.tag,text:t,...o.alias===void 0?{}:{alias:o.alias},...c===false?{}:{lock:c}}]);return u.committed?{ok:true,changed:true}:{ok:false,code:"unsupported",reason:typeof u.reason=="string"?u.reason:"the insert was refused"}}function m(e){return e.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F]/g,"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}function R(e,n,a,t={}){if(!chunkTNSHSAA4_cjs.e.test(e.tagPrefix)||!chunkTNSHSAA4_cjs.e.test(e.name))return {ok:false,code:"invalidArgs",reason:"the definition identity must match defineCustomNode\u2019s charset ([A-Za-z0-9_.-])"};let o=chunkTNSHSAA4_cjs.b(e.tagPrefix,e.name,n);if(!o.ok)return {ok:false,code:"invalidArgs",reason:`the encoded tag is ${o.length} characters; Word caps w:tag at 64 \u2014 shorten the attrs`};let r=t.lock===void 0?"contentLocked":t.lock,s=t.id!==void 0&&Number.isInteger(t.id)&&t.id>0?t.id:store.fnv1a32(`${o.tag}\0${a}`)&2147483647||1,i=(t.alias!==void 0?`<w:alias w:val="${m(t.alias)}"/>`:"")+`<w:tag w:val="${m(o.tag)}"/><w:id w:val="${s}"/>`+(r===false?"":`<w:lock w:val="${r}"/>`),c=`<w:r><w:t xml:space="preserve">${m(a)}</w:t></w:r>`;return {ok:true,xml:`<w:sdt><w:sdtPr>${i}</w:sdtPr><w:sdtContent>${c}</w:sdtContent></w:sdt>`}}Object.defineProperty(exports,"MAX_TAG_LENGTH",{enumerable:true,get:function(){return chunkTNSHSAA4_cjs.a}});Object.defineProperty(exports,"customNodesModule",{enumerable:true,get:function(){return chunkTNSHSAA4_cjs.g}});Object.defineProperty(exports,"decodeCustomNodeTag",{enumerable:true,get:function(){return chunkTNSHSAA4_cjs.c}});Object.defineProperty(exports,"defineCustomNode",{enumerable:true,get:function(){return chunkTNSHSAA4_cjs.f}});Object.defineProperty(exports,"encodeCustomNodeTag",{enumerable:true,get:function(){return chunkTNSHSAA4_cjs.b}});Object.defineProperty(exports,"isCustomNodeDefinition",{enumerable:true,get:function(){return chunkTNSHSAA4_cjs.d}});Object.defineProperty(exports,"recognizeCustomNodes",{enumerable:true,get:function(){return chunkTNSHSAA4_cjs.h}});Object.defineProperty(exports,"removeCustomNode",{enumerable:true,get:function(){return chunkTNSHSAA4_cjs.j}});Object.defineProperty(exports,"reviewModule",{enumerable:true,get:function(){return chunkTNSHSAA4_cjs.i}});Object.defineProperty(exports,"updateCustomNode",{enumerable:true,get:function(){return chunkTNSHSAA4_cjs.k}});exports.customNodeXml=R;exports.insertCustomNode=v;
1
+ 'use strict';var chunkMNK6DXJQ_cjs=require('./chunk-MNK6DXJQ.cjs'),store=require('@docx-editor.dev/core/store');function b(e,o={}){let r=U(e);if(!r)return [];let t=o.nodes??e.getCustomNodeDefinitions().filter(chunkMNK6DXJQ_cjs.j);if(t.length===0)return [];let s=r.session.part();return chunkMNK6DXJQ_cjs.n(s,t,{payloads:store.customNodePayloadsByControl(r.session.currentPackage(),s.name),onDiagnostic:o.onDiagnostic??(d=>{e.reportCustomNodeDiagnostic(d);})})}function U(e){return e.surface??null}function E(e,o,r={}){if(r.destination==="internal")return {ok:true,bytes:e,unwrapped:0,removed:0};let t=store.readOoxmlPackage(e);if(!t.ok)return {ok:false,reason:`the document could not be read: ${t.reason}`};let s=new Map;for(let i of o)s.set(`${i.tagPrefix}:${i.name}`,i);let d=i=>{let m=chunkMNK6DXJQ_cjs.c(i);if(!m)return "keep";let x=s.get(`${m.prefix}:${m.name}`);return x?x.preserveOnExport==="text"?"text":x.preserveOnExport===false?"remove":"keep":"keep"},p=[...new Set(o.filter(i=>i.preserveOnExport!==void 0).filter(i=>i.preserveOnExport!==true).map(chunkMNK6DXJQ_cjs.h))],n=t.package,u=0,c=0,g=B(n);for(let i of g){let m=store.withExportedCustomNodes(n,{storyPartName:i,namespaces:[],decide:d});if(!m.ok)return {ok:false,reason:m.reason};n=m.pkg,u+=m.unwrapped,c+=m.removed;}let l=store.withExportedCustomNodes(n,{storyPartName:n.mainDocumentPart,namespaces:p,decide:()=>"keep"});return l.ok?(n=l.pkg,{ok:true,bytes:store.writeOoxmlPackage(n),unwrapped:u,removed:c}):{ok:false,reason:l.reason}}function B(e){let o=[];for(let[r,t]of e.parts)r!==e.mainDocumentPart&&store.storyRootsOf(t).length!==0&&o.push(r);return [e.mainDocumentPart,...o]}async function V(e,o={}){let r=o.nodes??e.getCustomNodeDefinitions().filter(chunkMNK6DXJQ_cjs.j),t=await e.save();return E(new Uint8Array(t),r,{...o.destination===void 0?{}:{destination:o.destination}})}function a(e){return e.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F]/g,"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}function J(e,o,r,t={}){if(!chunkMNK6DXJQ_cjs.k.test(e.tagPrefix)||!chunkMNK6DXJQ_cjs.k.test(e.name))return {ok:false,code:"invalidArgs",reason:"the definition identity must match defineCustomNode\u2019s charset ([A-Za-z0-9_.-])"};let s=chunkMNK6DXJQ_cjs.b(e.tagPrefix,e.name,o);if(!s.ok)return {ok:false,code:"invalidArgs",reason:`the encoded tag is ${s.length} characters; Word caps w:tag at 64 \u2014 shorten the attrs`};let d=t.lock===void 0?"contentLocked":t.lock,p=t.id!==void 0&&Number.isInteger(t.id)&&t.id>0?t.id:store.fnv1a32(`${s.tag}\0${r}`)&2147483647||1,n=t.data===void 0?null:K(e,t,r);if(n&&"reason"in n)return {ok:false,code:"invalidArgs",reason:n.reason};let u=(t.alias!==void 0?`<w:alias w:val="${a(t.alias)}"/>`:"")+`<w:tag w:val="${a(s.tag)}"/><w:id w:val="${p}"/>`+(d===false?"":`<w:lock w:val="${d}"/>`)+(n?`<w:dataBinding w:prefixMappings="${a(n.binding.prefixMappings)}" w:xpath="${a(n.binding.xpath)}" w:storeItemID="${a(n.binding.storeItemId)}"/>`:""),c=`<w:r><w:t xml:space="preserve">${a(r)}</w:t></w:r>`;return {ok:true,xml:`<w:sdt><w:sdtPr>${u}</w:sdtPr><w:sdtContent>${c}</w:sdtContent></w:sdt>`,...n?{store:n.store}:{}}}function K(e,o,r){let t=chunkMNK6DXJQ_cjs.i(e,o.data);if(!t.ok)return {reason:t.reason};let s=chunkMNK6DXJQ_cjs.h(e),d=o.storeIndex!==void 0&&Number.isInteger(o.storeIndex)&&o.storeIndex>0?o.storeIndex:1,p=o.nodeId??"cx1",n=`/customXml/item${String(d)}.xml`,u=`/customXml/itemProps${String(d)}.xml`,c=store.datastoreItemIdFor(`${s} ${n} ${p}`),g=store.customNodeBinding({partName:n,propsPartName:u,itemId:c,namespaceUri:s},chunkMNK6DXJQ_cjs.g,p);if(!g)return {reason:`the payload cannot be addressed by an XPath: check nodeId (${p}) and payloadNamespace`};let l=r===r.trim()?`<label>${a(r)}</label>`:`<label xml:space="preserve">${a(r)}</label>`;return {binding:g,store:{itemPartName:n,itemXml:`<${chunkMNK6DXJQ_cjs.g} xmlns="${a(s)}"><node id="${a(p)}">${l}<data>${a(t.data)}</data></node></${chunkMNK6DXJQ_cjs.g}>`,propsPartName:u,propsXml:`<ds:datastoreItem ds:itemID="${a(c)}" xmlns:ds="${store.DATASTORE_NAMESPACE_URI}"><ds:schemaRefs><ds:schemaRef ds:uri="${a(s)}"/></ds:schemaRefs></ds:datastoreItem>`,storeItemId:c,relationships:[{from:"/word/document.xml",type:store.CUSTOM_XML_REL,target:`../customXml/item${String(d)}.xml`},{from:n,type:store.CUSTOM_XML_PROPS_REL,target:`itemProps${String(d)}.xml`}],contentTypeOverride:{partName:u,contentType:store.CUSTOM_XML_PROPS_TYPE}}}}Object.defineProperty(exports,"CUSTOM_NODE_STORE_ROOT",{enumerable:true,get:function(){return chunkMNK6DXJQ_cjs.g}});Object.defineProperty(exports,"MAX_CUSTOM_NODE_DATA_LENGTH",{enumerable:true,get:function(){return chunkMNK6DXJQ_cjs.d}});Object.defineProperty(exports,"MAX_TAG_LENGTH",{enumerable:true,get:function(){return chunkMNK6DXJQ_cjs.a}});Object.defineProperty(exports,"customNodeNamespace",{enumerable:true,get:function(){return chunkMNK6DXJQ_cjs.h}});Object.defineProperty(exports,"customNodesModule",{enumerable:true,get:function(){return chunkMNK6DXJQ_cjs.m}});Object.defineProperty(exports,"decodeCustomNodeTag",{enumerable:true,get:function(){return chunkMNK6DXJQ_cjs.c}});Object.defineProperty(exports,"defineCustomNode",{enumerable:true,get:function(){return chunkMNK6DXJQ_cjs.l}});Object.defineProperty(exports,"encodeCustomNodeTag",{enumerable:true,get:function(){return chunkMNK6DXJQ_cjs.b}});Object.defineProperty(exports,"insertCustomNode",{enumerable:true,get:function(){return chunkMNK6DXJQ_cjs.p}});Object.defineProperty(exports,"isCustomNodeDefinition",{enumerable:true,get:function(){return chunkMNK6DXJQ_cjs.j}});Object.defineProperty(exports,"parseCustomNodeData",{enumerable:true,get:function(){return chunkMNK6DXJQ_cjs.e}});Object.defineProperty(exports,"recognizeCustomNodes",{enumerable:true,get:function(){return chunkMNK6DXJQ_cjs.n}});Object.defineProperty(exports,"removeCustomNode",{enumerable:true,get:function(){return chunkMNK6DXJQ_cjs.q}});Object.defineProperty(exports,"reviewModule",{enumerable:true,get:function(){return chunkMNK6DXJQ_cjs.o}});Object.defineProperty(exports,"serializeCustomNodeData",{enumerable:true,get:function(){return chunkMNK6DXJQ_cjs.f}});Object.defineProperty(exports,"updateCustomNode",{enumerable:true,get:function(){return chunkMNK6DXJQ_cjs.r}});exports.customNodeXml=J;exports.customNodesOf=b;exports.prepareForExport=E;exports.saveForExport=V;