@docx-editor.dev/pro 0.0.1-placeholder → 2.0.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,191 @@
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
+ /** A recognized custom node: one inline SDT whose tag matched a definition. */
45
+ interface RecognizedCustomNode {
46
+ /** The definition's `name`. */
47
+ readonly name: string;
48
+ /** Attrs after the definition's `fromDocx` had its say. Untrusted input. */
49
+ readonly attrs: Readonly<Record<string, string>>;
50
+ /** The SDT's literal content text — what Word users see and may have edited. */
51
+ readonly text: string;
52
+ /** The SDT node's stable id in the canonical tree. */
53
+ readonly nodeId: string;
54
+ /** The raw `w:tag` the node was recognized from. */
55
+ readonly tag: string;
56
+ }
57
+ /**
58
+ * One integrator-defined inline node, anchored on a run-level SDT whose `w:tag` carries its
59
+ * identity.
60
+ *
61
+ * A definition claims a tag PREFIX, so `acme` recognizes every `acme:*` tag. An SDT whose prefix
62
+ * no definition claims stays literal — which is also what the free tier and Word itself render,
63
+ * so an unrecognized node never loses content or locks editing.
64
+ *
65
+ * Build one with {@link defineCustomNode}, which validates the shape, then register it through
66
+ * {@link customNodesModule}.
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * const citation = defineCustomNode({
71
+ * name: 'citation',
72
+ * tagPrefix: 'acme',
73
+ * chrome: { color: '#2563eb' },
74
+ * onClick: (node) => openCitation(node.attrs.key),
75
+ * });
76
+ * ```
77
+ *
78
+ * @public
79
+ */
80
+ interface CustomNodeDefinition {
81
+ /** Node type name — the second segment of the tag (`<prefix>:<name>?…`). */
82
+ readonly name: string;
83
+ /** Tag prefix this definition claims (`acme` claims `acme:*`). No colons. */
84
+ readonly tagPrefix: string;
85
+ /**
86
+ * Recognition hook. Receives the decoded attrs and the SDT's literal text
87
+ * (so label drift from Word edits is visible) and returns the attrs the node
88
+ * should carry — or null to leave this SDT unrecognized and literal.
89
+ *
90
+ * Every input value originates in a file an attacker controls; treat it as
91
+ * untrusted and never build DOM or URLs from it without sanitizing.
92
+ */
93
+ readonly fromDocx?: (input: {
94
+ readonly attrs: Readonly<Record<string, string>>;
95
+ readonly text: string;
96
+ }) => Readonly<Record<string, string>> | null;
97
+ /**
98
+ * Chip appearance, HOST-authored (never file data). `color` tints the chip
99
+ * and its border; applied by `CustomNodeChrome` from `@docx-editor.dev/pro/react`.
100
+ */
101
+ readonly chrome?: {
102
+ readonly color?: string;
103
+ };
104
+ /** Click on the painted chip. UI state belongs in `CustomNodeChrome`'s `onNodeClick`. */
105
+ readonly onClick?: (node: ActivatedCustomNode) => void;
106
+ /** Pointer enters the painted chip. */
107
+ readonly onHover?: (node: ActivatedCustomNode) => void;
108
+ /**
109
+ * Contribute a card to the review sidebar for every recognized node of this
110
+ * definition, anchored at the node's range. Return null to skip one node.
111
+ *
112
+ * `attrs` and `text` originate in the file — untrusted; the returned strings
113
+ * are rendered as TEXT by the pane, never markup. The context-menu section
114
+ * reuses this hook for its info block and may invoke it with `text: ''` when
115
+ * no review module is registered (the DOM decode alone cannot see the text).
116
+ */
117
+ readonly reviewCard?: (node: {
118
+ readonly attrs: Readonly<Record<string, string>>;
119
+ readonly text: string;
120
+ }) => {
121
+ readonly title: string;
122
+ readonly detail?: string;
123
+ } | null;
124
+ /**
125
+ * The "Edit {label}" row the context menu shows at the top when the
126
+ * right-click lands on the node's chip. The HOST owns the dialog.
127
+ *
128
+ * HONEST LIMIT: there is no in-place update call yet — re-authoring is
129
+ * `removeContentControl` + `insertCustomNode` at the node's range (the
130
+ * activation carries `nodeId` and, when a review module is registered, the
131
+ * current `text` to prefill a form). Schema-driven edit forms are the planned
132
+ * follow-up.
133
+ */
134
+ readonly onEdit?: (node: ActivatedCustomNode) => void;
135
+ /**
136
+ * Display name for chrome — the "Edit {label}" context-menu row. Defaults to
137
+ * `name`. Host-authored, never file data; provide a localized string.
138
+ */
139
+ readonly label?: string;
140
+ }
141
+ /**
142
+ * A chip activation: identity + attrs, plus where it sits.
143
+ *
144
+ * `attrs` are the definition's OWN shape — the raw tag decode has already been
145
+ * through `fromDocx`, exactly as the review derivation runs it, so every
146
+ * surface (click, hover, edit, cards) sees one attrs vocabulary. `text` and
147
+ * `nodeId` are present when the surface could resolve them (a registered
148
+ * review module resolves both).
149
+ */
150
+ interface ActivatedCustomNode {
151
+ readonly name: string;
152
+ readonly attrs: Readonly<Record<string, string>>;
153
+ readonly tag: string;
154
+ /** Viewport-relative rect of the chip's boundary, for anchoring host UI. */
155
+ readonly rect: DOMRect;
156
+ /** The SDT node's canonical id — the address `removeContentControl` takes. */
157
+ readonly nodeId?: string;
158
+ /** The node's literal content text, when resolvable. */
159
+ readonly text?: string;
160
+ }
161
+ /**
162
+ * Whether an opaque registry value is a custom-node definition.
163
+ *
164
+ * The engine carries registered definitions as unknowns (`getCustomNodeDefinitions`), so
165
+ * every pro surface that reads them back narrows through this ONE guard.
166
+ */
167
+ declare function isCustomNodeDefinition(candidate: unknown): candidate is CustomNodeDefinition;
168
+ /** Validate and freeze a definition. Throws on a shape mistake — author error, not file input. */
169
+ declare function defineCustomNode(definition: CustomNodeDefinition): CustomNodeDefinition;
170
+ /**
171
+ * How {@link customNodesModule} is configured.
172
+ *
173
+ * @public
174
+ */
175
+ interface CustomNodesModuleOptions extends ProLicenseOptions {
176
+ /** The definitions this editor recognizes. A tag prefix no definition claims stays literal. */
177
+ readonly nodes: readonly CustomNodeDefinition[];
178
+ }
179
+ /** Register custom node definitions with `createDocxEditor({ modules })`. */
180
+ declare function customNodesModule(options: CustomNodesModuleOptions): EditorModule;
181
+ /**
182
+ * Every recognized custom node in one story, in document order.
183
+ *
184
+ * Tag-prefix keyed, exactly as the change specifies: an inline SDT whose tag
185
+ * decodes to a registered `<prefix>:<name>` pair is offered to that
186
+ * definition's `fromDocx`; everything else — foreign tags, unregistered
187
+ * prefixes, a `fromDocx` veto — stays a literal SDT.
188
+ */
189
+ declare function recognizeCustomNodes(part: OoxmlPart, definitions: readonly CustomNodeDefinition[]): RecognizedCustomNode[];
190
+
191
+ export { type ActivatedCustomNode as A, type CustomNodeDefinition as C, type ProLicenseOptions as P, type RecognizedCustomNode as R, type CustomNodesModuleOptions as a, type ReviewModuleOptions as b, customNodesModule as c, defineCustomNode as d, reviewModule as e, isCustomNodeDefinition as i, recognizeCustomNodes as r };
package/dist/index.cjs ADDED
@@ -0,0 +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;
@@ -0,0 +1,175 @@
1
+ import { C as CustomNodeDefinition } from './define-custom-node-CkkDPdB0.cjs';
2
+ export { A as ActivatedCustomNode, a as CustomNodesModuleOptions, P as ProLicenseOptions, R as RecognizedCustomNode, b as ReviewModuleOptions, c as customNodesModule, d as defineCustomNode, i as isCustomNodeDefinition, r as recognizeCustomNodes, e as reviewModule } from './define-custom-node-CkkDPdB0.cjs';
3
+ import { Editor, ExecResult } from '@docx-editor.dev/core/contracts/editor';
4
+ import '@docx-editor.dev/core/editor';
5
+ import '@docx-editor.dev/core/store';
6
+
7
+ /** Word refuses to store more than 64 characters in `w:tag`. */
8
+ declare const MAX_TAG_LENGTH = 64;
9
+ /**
10
+ * What {@link encodeCustomNodeTag} answers: the encoded tag, or a refusal.
11
+ *
12
+ * The only refusal is `tag-overflow`. Word stores at most {@link MAX_TAG_LENGTH} characters in
13
+ * `w:tag`, and truncating would silently change a node's IDENTITY, so an oversized payload is
14
+ * reported with its `length` rather than trimmed.
15
+ *
16
+ * @public
17
+ */
18
+ type EncodeTagResult = {
19
+ readonly ok: true;
20
+ readonly tag: string;
21
+ } | {
22
+ readonly ok: false;
23
+ readonly reason: 'tag-overflow';
24
+ readonly length: number;
25
+ };
26
+ /** Encode a node identity into a `w:tag` value, refusing the Word length cap. */
27
+ declare function encodeCustomNodeTag(prefix: string, name: string, attrs: Readonly<Record<string, string>>): EncodeTagResult;
28
+ /**
29
+ * A `w:tag` value parsed back into the identity it encodes.
30
+ *
31
+ * Everything here comes from a file an attacker fully controls. `attrs` is a null-prototype
32
+ * object and the decoder refuses the prototype-polluting names outright, but the VALUES are still
33
+ * untrusted: never build DOM, URLs or CSS from them without sanitizing.
34
+ *
35
+ * @public
36
+ */
37
+ interface DecodedCustomNodeTag {
38
+ /** The prefix segment — which definition claims this node. */
39
+ readonly prefix: string;
40
+ /** The node type name, matching a {@link CustomNodeDefinition.name}. */
41
+ readonly name: string;
42
+ /** Query-string attrs, on a null-prototype object. Untrusted file input. */
43
+ readonly attrs: Readonly<Record<string, string>>;
44
+ }
45
+ /**
46
+ * Decode a `w:tag` value, or null when it is not a custom-node tag.
47
+ *
48
+ * Null rather than throwing: every inline SDT in every opened document flows
49
+ * through this, and most SDTs in the wild are ordinary Word content controls
50
+ * whose tags mean something else entirely.
51
+ */
52
+ declare function decodeCustomNodeTag(tag: string): DecodedCustomNodeTag | null;
53
+
54
+ /**
55
+ * How {@link insertCustomNode} places a node.
56
+ *
57
+ * Every field is optional: the ordinary call inserts at the caret with `contentLocked`, which is
58
+ * the behaviour that keeps a chip's label from drifting out of sync with its attrs while leaving
59
+ * the node deletable as one unit.
60
+ *
61
+ * @public
62
+ */
63
+ interface InsertCustomNodeOptions {
64
+ /**
65
+ * Where to insert. Omitted, the node lands at the current selection HEAD —
66
+ * the programmatic mirror of "type a citation at the caret".
67
+ */
68
+ readonly at?: {
69
+ readonly paragraphId: string;
70
+ readonly offset: number;
71
+ };
72
+ /**
73
+ * The `w:lock` written on the control. Defaults to `contentLocked` — the text
74
+ * is locked so the label cannot drift out of sync with the attrs by inline
75
+ * typing (editing goes through the `onEdit` flow), while the node itself stays
76
+ * DELETABLE as one unit, in the editor and in Word alike. `false` writes no
77
+ * lock; `sdtContentLocked` also forbids deleting the node.
78
+ */
79
+ readonly lock?: false | 'sdtLocked' | 'sdtContentLocked' | 'contentLocked';
80
+ /**
81
+ * `w:alias` — the human title Word shows on the control, and what the
82
+ * engine's control chrome uses as its floating label.
83
+ */
84
+ readonly alias?: string;
85
+ }
86
+ /**
87
+ * Insert one custom node. Returns the engine's typed result: refusals carry the
88
+ * engine's own reason (tag overflow, offset out of range, viewing mode, …).
89
+ *
90
+ * ```ts
91
+ * insertCustomNode(editor, citation, { sourceId: 'src_9f3' }, '(Smith 2024)');
92
+ * ```
93
+ */
94
+ declare function insertCustomNode(editor: Editor, definition: CustomNodeDefinition, attrs: Readonly<Record<string, string>>, text: string, options?: InsertCustomNodeOptions): ExecResult;
95
+
96
+ /**
97
+ * Delete one custom node — wrapper AND content, one undo step.
98
+ *
99
+ * The default `contentLocked` chip deletes fine (the lock guards its characters, not its
100
+ * existence); a `sdtLocked`/`sdtContentLocked` wrapper refuses with the engine's reason.
101
+ */
102
+ declare function removeCustomNode(editor: Editor, nodeId: string): ExecResult;
103
+ /**
104
+ * How {@link updateCustomNode} rewrites the control it replaces.
105
+ *
106
+ * @public
107
+ */
108
+ interface UpdateCustomNodeOptions {
109
+ /** `w:alias` for the rewritten control. */
110
+ readonly alias?: string;
111
+ /** `w:lock` for the rewritten control. Defaults to `contentLocked`, like the insert. */
112
+ readonly lock?: false | 'sdtLocked' | 'sdtContentLocked' | 'contentLocked';
113
+ }
114
+ /**
115
+ * Replace one custom node's attrs and text in place: the node is removed and a fresh one
116
+ * with the new tag and label is inserted at its own span — ONE transaction, one undo step,
117
+ * recognized by construction like `insertCustomNode`.
118
+ *
119
+ * ```ts
120
+ * updateCustomNode(editor, citation, node.nodeId, { sourceId: 'src_2' }, '(Jones 2025)');
121
+ * ```
122
+ */
123
+ declare function updateCustomNode(editor: Editor, definition: CustomNodeDefinition, nodeId: string, attrs: Readonly<Record<string, string>>, text: string, options?: UpdateCustomNodeOptions): ExecResult;
124
+
125
+ /**
126
+ * How {@link customNodeXml} writes the control, for server-side templating where there is no
127
+ * editor instance to insert through.
128
+ *
129
+ * @public
130
+ */
131
+ interface CustomNodeXmlOptions {
132
+ /** `w:alias` — the human title Word shows on the control. */
133
+ readonly alias?: string;
134
+ /** `w:lock`. Defaults to `contentLocked`, matching `insertCustomNode`. `false` omits it. */
135
+ readonly lock?: false | 'sdtLocked' | 'sdtContentLocked' | 'contentLocked';
136
+ /**
137
+ * `w:id` — Word's own numeric control identity (positive, non-zero). Defaults to a
138
+ * deterministic FNV-1a over the tag and text; pass one to control it. Two IDENTICAL
139
+ * nodes in one document then share an id — Word tolerates this and regenerates on
140
+ * open, but a caller splicing many copies of the same node can pass distinct ids.
141
+ */
142
+ readonly id?: number;
143
+ }
144
+ /**
145
+ * What {@link customNodeXml} answers: the `w:sdt` markup, or a refusal.
146
+ *
147
+ * Refuses exactly what `insertCustomNode` refuses — chiefly the 64-character `w:tag` cap — so a
148
+ * server cannot author a chip the editor itself would not have accepted.
149
+ *
150
+ * @public
151
+ */
152
+ type CustomNodeXmlResult = {
153
+ readonly ok: true;
154
+ readonly xml: string;
155
+ } | {
156
+ readonly ok: false;
157
+ readonly code: 'invalidArgs';
158
+ readonly reason: string;
159
+ };
160
+ /**
161
+ * The run-level `w:sdt` markup for one custom node, ready to splice between runs inside a
162
+ * `w:p` (the `w` prefix must be bound to the WordprocessingML main namespace, as it is in
163
+ * every `word/document.xml`).
164
+ *
165
+ * Refuses the same inputs `insertCustomNode` refuses (the 64-character `w:tag` cap), so a
166
+ * server cannot author a chip the editor would not have.
167
+ *
168
+ * ```ts
169
+ * const sdt = customNodeXml(citation, { sourceId: 'src_9f3' }, '(Smith 2024)');
170
+ * if (sdt.ok) template.replace('{{citation}}', sdt.xml);
171
+ * ```
172
+ */
173
+ declare function customNodeXml(definition: CustomNodeDefinition, attrs: Readonly<Record<string, string>>, text: string, options?: CustomNodeXmlOptions): CustomNodeXmlResult;
174
+
175
+ export { CustomNodeDefinition, type CustomNodeXmlOptions, type CustomNodeXmlResult, type DecodedCustomNodeTag, type EncodeTagResult, type InsertCustomNodeOptions, MAX_TAG_LENGTH, type UpdateCustomNodeOptions, customNodeXml, decodeCustomNodeTag, encodeCustomNodeTag, insertCustomNode, removeCustomNode, updateCustomNode };
@@ -0,0 +1,175 @@
1
+ import { C as CustomNodeDefinition } from './define-custom-node-CkkDPdB0.js';
2
+ export { A as ActivatedCustomNode, a as CustomNodesModuleOptions, P as ProLicenseOptions, R as RecognizedCustomNode, b as ReviewModuleOptions, c as customNodesModule, d as defineCustomNode, i as isCustomNodeDefinition, r as recognizeCustomNodes, e as reviewModule } from './define-custom-node-CkkDPdB0.js';
3
+ import { Editor, ExecResult } from '@docx-editor.dev/core/contracts/editor';
4
+ import '@docx-editor.dev/core/editor';
5
+ import '@docx-editor.dev/core/store';
6
+
7
+ /** Word refuses to store more than 64 characters in `w:tag`. */
8
+ declare const MAX_TAG_LENGTH = 64;
9
+ /**
10
+ * What {@link encodeCustomNodeTag} answers: the encoded tag, or a refusal.
11
+ *
12
+ * The only refusal is `tag-overflow`. Word stores at most {@link MAX_TAG_LENGTH} characters in
13
+ * `w:tag`, and truncating would silently change a node's IDENTITY, so an oversized payload is
14
+ * reported with its `length` rather than trimmed.
15
+ *
16
+ * @public
17
+ */
18
+ type EncodeTagResult = {
19
+ readonly ok: true;
20
+ readonly tag: string;
21
+ } | {
22
+ readonly ok: false;
23
+ readonly reason: 'tag-overflow';
24
+ readonly length: number;
25
+ };
26
+ /** Encode a node identity into a `w:tag` value, refusing the Word length cap. */
27
+ declare function encodeCustomNodeTag(prefix: string, name: string, attrs: Readonly<Record<string, string>>): EncodeTagResult;
28
+ /**
29
+ * A `w:tag` value parsed back into the identity it encodes.
30
+ *
31
+ * Everything here comes from a file an attacker fully controls. `attrs` is a null-prototype
32
+ * object and the decoder refuses the prototype-polluting names outright, but the VALUES are still
33
+ * untrusted: never build DOM, URLs or CSS from them without sanitizing.
34
+ *
35
+ * @public
36
+ */
37
+ interface DecodedCustomNodeTag {
38
+ /** The prefix segment — which definition claims this node. */
39
+ readonly prefix: string;
40
+ /** The node type name, matching a {@link CustomNodeDefinition.name}. */
41
+ readonly name: string;
42
+ /** Query-string attrs, on a null-prototype object. Untrusted file input. */
43
+ readonly attrs: Readonly<Record<string, string>>;
44
+ }
45
+ /**
46
+ * Decode a `w:tag` value, or null when it is not a custom-node tag.
47
+ *
48
+ * Null rather than throwing: every inline SDT in every opened document flows
49
+ * through this, and most SDTs in the wild are ordinary Word content controls
50
+ * whose tags mean something else entirely.
51
+ */
52
+ declare function decodeCustomNodeTag(tag: string): DecodedCustomNodeTag | null;
53
+
54
+ /**
55
+ * How {@link insertCustomNode} places a node.
56
+ *
57
+ * Every field is optional: the ordinary call inserts at the caret with `contentLocked`, which is
58
+ * the behaviour that keeps a chip's label from drifting out of sync with its attrs while leaving
59
+ * the node deletable as one unit.
60
+ *
61
+ * @public
62
+ */
63
+ interface InsertCustomNodeOptions {
64
+ /**
65
+ * Where to insert. Omitted, the node lands at the current selection HEAD —
66
+ * the programmatic mirror of "type a citation at the caret".
67
+ */
68
+ readonly at?: {
69
+ readonly paragraphId: string;
70
+ readonly offset: number;
71
+ };
72
+ /**
73
+ * The `w:lock` written on the control. Defaults to `contentLocked` — the text
74
+ * is locked so the label cannot drift out of sync with the attrs by inline
75
+ * typing (editing goes through the `onEdit` flow), while the node itself stays
76
+ * DELETABLE as one unit, in the editor and in Word alike. `false` writes no
77
+ * lock; `sdtContentLocked` also forbids deleting the node.
78
+ */
79
+ readonly lock?: false | 'sdtLocked' | 'sdtContentLocked' | 'contentLocked';
80
+ /**
81
+ * `w:alias` — the human title Word shows on the control, and what the
82
+ * engine's control chrome uses as its floating label.
83
+ */
84
+ readonly alias?: string;
85
+ }
86
+ /**
87
+ * Insert one custom node. Returns the engine's typed result: refusals carry the
88
+ * engine's own reason (tag overflow, offset out of range, viewing mode, …).
89
+ *
90
+ * ```ts
91
+ * insertCustomNode(editor, citation, { sourceId: 'src_9f3' }, '(Smith 2024)');
92
+ * ```
93
+ */
94
+ declare function insertCustomNode(editor: Editor, definition: CustomNodeDefinition, attrs: Readonly<Record<string, string>>, text: string, options?: InsertCustomNodeOptions): ExecResult;
95
+
96
+ /**
97
+ * Delete one custom node — wrapper AND content, one undo step.
98
+ *
99
+ * The default `contentLocked` chip deletes fine (the lock guards its characters, not its
100
+ * existence); a `sdtLocked`/`sdtContentLocked` wrapper refuses with the engine's reason.
101
+ */
102
+ declare function removeCustomNode(editor: Editor, nodeId: string): ExecResult;
103
+ /**
104
+ * How {@link updateCustomNode} rewrites the control it replaces.
105
+ *
106
+ * @public
107
+ */
108
+ interface UpdateCustomNodeOptions {
109
+ /** `w:alias` for the rewritten control. */
110
+ readonly alias?: string;
111
+ /** `w:lock` for the rewritten control. Defaults to `contentLocked`, like the insert. */
112
+ readonly lock?: false | 'sdtLocked' | 'sdtContentLocked' | 'contentLocked';
113
+ }
114
+ /**
115
+ * Replace one custom node's attrs and text in place: the node is removed and a fresh one
116
+ * with the new tag and label is inserted at its own span — ONE transaction, one undo step,
117
+ * recognized by construction like `insertCustomNode`.
118
+ *
119
+ * ```ts
120
+ * updateCustomNode(editor, citation, node.nodeId, { sourceId: 'src_2' }, '(Jones 2025)');
121
+ * ```
122
+ */
123
+ declare function updateCustomNode(editor: Editor, definition: CustomNodeDefinition, nodeId: string, attrs: Readonly<Record<string, string>>, text: string, options?: UpdateCustomNodeOptions): ExecResult;
124
+
125
+ /**
126
+ * How {@link customNodeXml} writes the control, for server-side templating where there is no
127
+ * editor instance to insert through.
128
+ *
129
+ * @public
130
+ */
131
+ interface CustomNodeXmlOptions {
132
+ /** `w:alias` — the human title Word shows on the control. */
133
+ readonly alias?: string;
134
+ /** `w:lock`. Defaults to `contentLocked`, matching `insertCustomNode`. `false` omits it. */
135
+ readonly lock?: false | 'sdtLocked' | 'sdtContentLocked' | 'contentLocked';
136
+ /**
137
+ * `w:id` — Word's own numeric control identity (positive, non-zero). Defaults to a
138
+ * deterministic FNV-1a over the tag and text; pass one to control it. Two IDENTICAL
139
+ * nodes in one document then share an id — Word tolerates this and regenerates on
140
+ * open, but a caller splicing many copies of the same node can pass distinct ids.
141
+ */
142
+ readonly id?: number;
143
+ }
144
+ /**
145
+ * What {@link customNodeXml} answers: the `w:sdt` markup, or a refusal.
146
+ *
147
+ * Refuses exactly what `insertCustomNode` refuses — chiefly the 64-character `w:tag` cap — so a
148
+ * server cannot author a chip the editor itself would not have accepted.
149
+ *
150
+ * @public
151
+ */
152
+ type CustomNodeXmlResult = {
153
+ readonly ok: true;
154
+ readonly xml: string;
155
+ } | {
156
+ readonly ok: false;
157
+ readonly code: 'invalidArgs';
158
+ readonly reason: string;
159
+ };
160
+ /**
161
+ * The run-level `w:sdt` markup for one custom node, ready to splice between runs inside a
162
+ * `w:p` (the `w` prefix must be bound to the WordprocessingML main namespace, as it is in
163
+ * every `word/document.xml`).
164
+ *
165
+ * Refuses the same inputs `insertCustomNode` refuses (the 64-character `w:tag` cap), so a
166
+ * server cannot author a chip the editor would not have.
167
+ *
168
+ * ```ts
169
+ * const sdt = customNodeXml(citation, { sourceId: 'src_9f3' }, '(Smith 2024)');
170
+ * if (sdt.ok) template.replace('{{citation}}', sdt.xml);
171
+ * ```
172
+ */
173
+ declare function customNodeXml(definition: CustomNodeDefinition, attrs: Readonly<Record<string, string>>, text: string, options?: CustomNodeXmlOptions): CustomNodeXmlResult;
174
+
175
+ export { CustomNodeDefinition, type CustomNodeXmlOptions, type CustomNodeXmlResult, type DecodedCustomNodeTag, type EncodeTagResult, type InsertCustomNodeOptions, MAX_TAG_LENGTH, type UpdateCustomNodeOptions, customNodeXml, decodeCustomNodeTag, encodeCustomNodeTag, insertCustomNode, removeCustomNode, updateCustomNode };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import {b,e}from'./chunk-NZOS3H23.js';export{a as MAX_TAG_LENGTH,g as customNodesModule,c as decodeCustomNodeTag,f as defineCustomNode,b as encodeCustomNodeTag,d as isCustomNodeDefinition,h as recognizeCustomNodes,j as removeCustomNode,i as reviewModule,k as updateCustomNode}from'./chunk-NZOS3H23.js';import {fnv1a32}from'@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=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$1,n,a,t={}){if(!e.test(e$1.tagPrefix)||!e.test(e$1.name))return {ok:false,code:"invalidArgs",reason:"the definition identity must match defineCustomNode\u2019s charset ([A-Za-z0-9_.-])"};let o=b(e$1.tagPrefix,e$1.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: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>`}}export{R as customNodeXml,v as insertCustomNode};
@@ -0,0 +1,2 @@
1
+ 'use strict';var chunkTNSHSAA4_cjs=require('../chunk-TNSHSAA4.cjs'),react=require('react'),react$1=require('@docx-editor.dev/react'),jsxRuntime=require('react/jsx-runtime');function me(e){let r=react$1.useDocxEditor();return nt(r,e)}function nt(e,r){let l=react.useCallback(p=>{if(!e)return ()=>{};let y=e.on("change",p),P=e.on("selectionChange",p);return ()=>{y(),P();}},[e]),s=react.useSyncExternalStore(l,()=>e?`${e.getReviewRevision()}`:"none",()=>"none"),t=react.useMemo(()=>e?e.getReviewItems(r):[],[e,s,r]),o=react.useMemo(()=>t.find(p=>p.isActive)?.key??null,[t]),i=react.useCallback(p=>{e?.setActiveReviewItem(p);},[e]),n=react.useCallback(p=>{p.kind!=="revision"||p.readOnly||e?.acceptReviewItem(p.key);},[e]),d=react.useCallback(p=>{p.kind!=="revision"||p.readOnly||e?.rejectReviewItem(p.key);},[e]),c=react.useCallback(p=>!e||p.kind==="custom"||p.kind==="revision"&&p.readOnly?false:e.deleteReviewItem(p.key).ok,[e]),v=react.useCallback((p,y,P)=>y.trim().length===0||!e?false:e.replyToReviewItem(p.key,y,P).ok,[e]),b=react.useMemo(()=>e?e.getSelectionPlacement()?.anchorY??null:null,[e,s]),R=react.useCallback((p,y)=>p.trim().length===0||!e?false:e.addComment(p,y).ok,[e]),w=react.useMemo(()=>e?e.isReviewPaneOpen():true,[e,s]),f=react.useCallback(p=>{!e||e.isReviewPaneOpen()===p||e.exec({type:"toggleReviewPane"});},[e]);return react.useMemo(()=>({items:t,activeKey:o,setActive:i,accept:n,reject:d,remove:c,reply:v,selectionAnchorY:b,comment:R,paneOpen:w,setPaneOpen:f,ready:e!==null}),[t,o,i,n,d,c,v,b,R,w,f,e])}function ht(e,r,l={}){let s=l.gap??8,t=l.scale??1,o=l.defaultHeight??0;return react.useMemo(()=>{let i=new Map,n=Number.NEGATIVE_INFINITY;for(let d of e){if(d.anchorY===null)continue;let c=Math.max(d.anchorY,n);i.set(d.key,c),n=c+((r.get(d.key)??o)+s)/t;}return i},[e,r,s,t,o])}var Pe=react.createContext(null),k=react.createContext(null);function Pt(){return react.useContext(k)}var It={scale:96/72,top:0,left:null},kt=16,ve="\0compose",ot=600,it=8,At=72,Mt=64,Tt=480,Dt=Object.freeze({placement:false});function Ie(e,r){return e.kind!=="comment"?false:e.parentId!==void 0?r.has(e.parentId):e.parentRevisionId!==void 0?r.has(e.parentRevisionId):false}function ke(e){return new Set(e.map(r=>r.id))}function F(e){let r=e.target?.tagName;r==="INPUT"||r==="SELECT"||r==="TEXTAREA"||e.preventDefault();}function O(){let e=react.useContext(Pe);return e||St}function Y(){let{t:e}=react.useContext(Pe)??{},{t:r}=react$1.useTranslation();return react.useCallback(l=>e?.(l)??r(l),[e,r])}var St={t:void 0,cardClassName:void 0,review:{items:[],activeKey:null,setActive:()=>{},accept:()=>{},reject:()=>{},remove:()=>false,reply:()=>false,selectionAnchorY:null,comment:()=>false,paneOpen:true,setPaneOpen:()=>{},ready:false},allItems:[],authorSlots:new Map,byId:new Map,measure:()=>{},beginDraft:()=>{},endDraft:()=>{}},re=e=>jsxRuntime.jsx("svg",{viewBox:"0 -960 960 960",width:16,height:16,"aria-hidden":"true",focusable:"false",children:jsxRuntime.jsx("path",{d:e,fill:"currentColor"})}),Lt="M440-400h80v-120h120v-80H520v-120h-80v120H320v80h120v120ZM80-80v-720q0-33 23.5-56.5T160-880h640q33 0 56.5 23.5T880-800v480q0 33-23.5 56.5T800-240H240L80-80Zm126-240h594v-480H160v525l46-45Zm-46 0v-480 480Z",Ot="M240-400h480v-80H240v80Zm0-120h480v-80H240v80Zm0-120h480v-80H240v80ZM880-80 720-240H160q-33 0-56.5-23.5T80-320v-480q0-33 23.5-56.5T160-880h640q33 0 56.5 23.5T880-800v720ZM160-320h594l46 45v-525H160v480Zm0 0v-480 480Z",$t="M382-240 154-468l57-57 171 171 367-367 57 57-424 424Z",Ht="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z",Vt="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z";function Kt({className:e,furniture:r,asChild:l,hidden:s,children:t,t:o,card:i,preset:n=true,stack:d=true,gap:c=8,filter:v,structural:b=false,formatting:R=false}){let w=react$1.useDocxEditor(),f=react.useMemo(()=>{let m=[];return b||m.push("structural"),R||m.push("format"),m.length>0?m:void 0},[b,R]),p=react.useMemo(()=>f?{excludeRevisionKinds:f}:void 0,[f]),y=me(Dt),P=me(p),I=P.setPaneOpen,{t:E}=react$1.useTranslation(),C=react.useCallback(m=>o?.(m)??E(m),[o,E]),_=react.useRef(null),$=react.useContext(react$1.ReviewRailContext);react.useEffect(()=>$?.register(),[$]);let q=P.paneOpen,M=react.useMemo(()=>v?P.items.filter(m=>v(m)):P.items,[P.items,v]),ee=react.useMemo(()=>{let m=new Map;for(let u of M)u.author&&!m.has(u.author)&&m.set(u.author,m.size);return m},[M]),Ke=react.useMemo(()=>{let m=new Map;for(let u of M)m.set(u.id,u);return m},[M]),[Ye,vt]=react.useState(()=>new Map),ye=react.useCallback((m,u)=>{u<=0||vt(x=>{if(x.get(m)===u)return x;let N=new Map(x);return N.set(m,u),N});},[]),be=react.useRef(new WeakMap),te=react.useRef(null),Be=react.useCallback((m,u)=>{!m||typeof ResizeObserver>"u"||(ye(u,m.offsetHeight),te.current??(te.current=new ResizeObserver(x=>{for(let N of x){let g=be.current.get(N.target);g&&ye(g,N.target.offsetHeight);}})),be.current.get(m)!==u&&(be.current.set(m,u),te.current.observe(m)));},[ye]);react.useEffect(()=>()=>te.current?.disconnect(),[]);let[D,ft]=react.useState(It);react.useEffect(()=>{let m=_.current;if(!w||!m)return;let u=m.offsetParent,x=u?.querySelector(".docx-paginated-surface")??null,N=()=>{ft(T=>{let H=x&&u?x.getBoundingClientRect():null,L=H&&u?u.getBoundingClientRect():null,V={scale:w.getRenderScale(),top:H&&L&&u?H.top-L.top-u.clientTop+u.scrollTop:0,left:H&&L&&u?H.right-L.left-u.clientLeft+u.scrollLeft+kt:null};return T.scale===V.scale&&T.top===V.top&&T.left===V.left?T:V});};N();let g=new ResizeObserver(N);return u&&g.observe(u),x&&g.observe(x),()=>g.disconnect()},[w,M]),react.useEffect(()=>{let m=_.current;if(!w||!m)return;let u=x=>{let N=x.target;if(!(N instanceof Node)||m.contains(N))return;let g=m.offsetParent;!g||!g.contains(N)||g.querySelector(".docx-paginated-surface")?.contains(N)||w.setActiveReviewItem(null);};return document.addEventListener("mousedown",u,true),()=>document.removeEventListener("mousedown",u,true)},[w]);let[xe,pt]=react.useState(null);react.useEffect(()=>{let m=_.current,u=m?.offsetParent;if(!u)return;let x=0,N=()=>{x=0,pt(L=>{let V=u.scrollTop-ot,ue=u.scrollTop+u.clientHeight+ot;return L&&L.top===V&&L.bottom===ue?L:{top:V,bottom:ue}});},g=0,T=()=>{x===0&&(x=requestAnimationFrame(N)),m?.setAttribute("data-scrolling",""),window.clearTimeout(g),g=window.setTimeout(()=>m?.removeAttribute("data-scrolling"),150);};N(),u.addEventListener("scroll",T,{passive:true});let H=new ResizeObserver(T);return H.observe(u),()=>{x!==0&&cancelAnimationFrame(x),window.clearTimeout(g),u.removeEventListener("scroll",T),H.disconnect();}},[w]);let[B,he]=react.useState(null),je=react.useCallback(()=>{w&&(w.surface?.retainSelection(),I(true),he(w.getSelectionPlacement()?.anchorY??null));},[w,I]),Ze=react.useCallback(()=>{w?.surface?.releaseSelection(),he(null),w?.focus();},[w]);react.useEffect(()=>{q||B===null||(w?.surface?.releaseSelection(),he(null));},[q,B,w]);let Fe=B??P.selectionAnchorY,U=react.useMemo(()=>{let m=ke(M);return M.filter(u=>!Ie(u,m))},[M]),qe=react.useMemo(()=>{if(B===null)return U;let m=U.findIndex(x=>x.anchorY!==null&&x.anchorY>B),u={key:ve,anchorY:B};return m===-1?[...U,u]:[...U.slice(0,m),u,...U.slice(m)]},[U,B]),Ue=react.useMemo(()=>{let m=new Map(Ye);for(let u of U){if(m.has(u.key))continue;let x=u.text.length+(u.kind==="revision"?u.replacedText?.length??0:0),N=Math.min(6,Math.max(1,Math.ceil(x/36)));m.set(u.key,64+N*20);}return m},[Ye,U]),{stacked:ge,collapsedKeys:ze}=react.useMemo(()=>{let m=D.scale,u=new Map,x=new Set,N=Number.NEGATIVE_INFINITY;for(let g of qe){let T=g.anchorY===null?Number.isFinite(N)?N:0:Math.max(g.anchorY,N);u.set(g.key,T);let H=g.anchorY===null?0:(T-g.anchorY)*m,L="isActive"in g&&g.isActive,V=H>Tt&&!L&&g.key!==ve;V&&x.add(g.key);let ue=V?Mt:Ue.get(g.key)??At;N=T+(ue+c)/m;}return {stacked:u,collapsedKeys:x}},[qe,Ue,c,D.scale]),Ne=Fe===null?null:D.top+(ge.get(ve)??Fe)*D.scale,Qe=i?.className,wt=react.useMemo(()=>({t:o,cardClassName:Qe,review:{...P,items:M},allItems:y.items,authorSlots:ee,byId:Ke,measure:Be,beginDraft:je,endDraft:Ze}),[o,Qe,P,y.items,M,ee,Ke,Be,je,Ze]);if(s)return null;let Ge={ref:_,className:`docx-review${e?` ${e}`:""}`,"data-testid":"review-rail","data-count":M.length,"data-open":q?"":void 0,role:"complementary","aria-label":C("review.ariaLabel"),onMouseDown:F,style:D.left===null?void 0:{left:D.left,right:"auto"}},We=typeof t=="function"?{}:at(t),ne=(m,u)=>m in We?We[m]:u,Xe=n?jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[ne("AddComment",jsxRuntime.jsx(Me,{top:Ne,drafting:B!==null})),!q||B===null||Ne===null?null:ne("Draft",jsxRuntime.jsx(Te,{top:Ne})),ne("Balloon",jsxRuntime.jsx(De,{}))]}):null,Rt=n?q?ne("List",jsxRuntime.jsx(fe,{stack:d,positions:ge,collapsed:ze,scale:D.scale,offset:D.top,window:xe,children:t})):ne("Markers",jsxRuntime.jsx(Ae,{scale:D.scale,offset:D.top,window:xe})):typeof t=="function"?null:t;return jsxRuntime.jsx(Pe.Provider,{value:wt,children:l&&react.isValidElement(t)?jsxRuntime.jsx(react$1.Slot,{...Ge,children:react.cloneElement(t,void 0,t.props.children,n?jsxRuntime.jsx(fe,{stack:d,positions:ge,collapsed:ze,scale:D.scale,offset:D.top,window:xe}):null,Xe)}):jsxRuntime.jsxs("aside",{...Ge,children:[q&&r!==void 0?jsxRuntime.jsx("div",{className:"docx-review__furniture","data-testid":"review-furniture",children:r}):null,Rt,Xe]})})}function fe({stack:e=true,positions:r,collapsed:l,scale:s=1,offset:t=0,window:o=null,children:i,className:n,hidden:d}){let{review:c,measure:v,cardClassName:b}=O();if(d)return null;let R=ke(c.items),w=c.items.filter(f=>!Ie(f,R));return w.length===0?typeof i=="function"?null:jsxRuntime.jsx(Se,{}):jsxRuntime.jsx("div",{className:`docx-review__list${n?` ${n}`:""}`,children:w.map(f=>{let p=e?r?.get(f.key)??f.anchorY:f.anchorY,y=p==null?null:t+p*s;if(y!==null&&o&&(y<o.top||y>o.bottom))return null;let P=y===null?{}:{position:"absolute",top:y};return jsxRuntime.jsx(k.Provider,{value:f,children:jsxRuntime.jsx("div",{className:"docx-review__slot",style:P,...l?.has(f.key)?{"data-collapsed":""}:{},ref:I=>{v(I,f.key);},children:typeof i=="function"?i(f):jsxRuntime.jsx(Le,{...b?{className:b}:{},children:i})})},f.key)})})}fe.docxReviewPart="List";function Ae({scale:e=1,offset:r=0,window:l=null,className:s,hidden:t}){let{review:o}=O(),i=Y();if(t)return null;let n=ke(o.items),d=o.items.filter(c=>!Ie(c,n));return jsxRuntime.jsx("div",{className:`docx-review__markers${s?` ${s}`:""}`,children:d.map(c=>{if(c.anchorY===null)return null;let v=r+c.anchorY*e;return l&&(v<l.top||v>l.bottom)?null:jsxRuntime.jsx("button",{type:"button",className:"docx-review__marker","data-testid":"review-marker","data-kind":c.kind==="revision"?c.revisionKind:c.kind,style:{position:"absolute",top:v},title:c.author?`${c.author}: ${c.text}`:c.text,"aria-label":`${i("review.showPane")}: ${c.author?`${c.author}. `:""}${c.text}`,onMouseDown:F,onClick:()=>{o.setPaneOpen(true),o.setActive(c.key);},children:re(Ot)},c.key)})})}Ae.docxReviewPart="Markers";function Me({top:e,drafting:r=false,className:l,hidden:s,children:t}){let{beginDraft:o}=O(),i=Y();if(s||r||e===null)return null;let n={type:"button",className:`docx-review__add${l?` ${l}`:""}`,"data-testid":"review-add-comment",style:{position:"absolute",top:e},"aria-label":i("common.comment"),title:i("common.comment"),onMouseDown:F,onClick:o};return t?jsxRuntime.jsx(react$1.Slot,{...n,children:t}):jsxRuntime.jsx("button",{...n,children:re(Lt)})}Me.docxReviewPart="AddComment";function Te({top:e,className:r,hidden:l}){let{review:s,endDraft:t,measure:o}=O(),i=Y(),[n,d]=react.useState(""),[c,v]=react.useState(false),b=react.useRef(null),R=react.useId();react.useEffect(()=>{b.current?.focus({preventScroll:true});},[]);let w=react.useCallback(()=>{if(n.trim().length===0)return;let f=s.comment(n.trim());v(!f),f&&(d(""),t());},[n,s,t]);return l?null:jsxRuntime.jsx("div",{className:`docx-review__slot${r?` ${r}`:""}`,style:{position:"absolute",top:e},ref:f=>{o(f,ve);},children:jsxRuntime.jsx("div",{className:"docx-review__card","data-testid":"review-draft","data-draft":"",children:jsxRuntime.jsxs("form",{className:"docx-review__reply-box",onSubmit:f=>{f.preventDefault(),w();},children:[jsxRuntime.jsx("label",{className:"ep-sr-only",htmlFor:R,children:i("comments.addComment")}),jsxRuntime.jsx("input",{id:R,ref:b,"data-testid":"review-draft-input",className:"docx-review__input",value:n,placeholder:i("comments.addComment"),...c?{"aria-invalid":true}:{},onChange:f=>{v(false),d(f.target.value);},onKeyDown:f=>{if(f.key==="Escape"){f.preventDefault(),t();return}f.key==="Enter"&&(f.preventDefault(),w());}}),jsxRuntime.jsxs("div",{className:"docx-review__reply-actions",children:[jsxRuntime.jsx("button",{type:"button","data-testid":"review-draft-cancel",className:"docx-review__text-button",onMouseDown:F,onClick:t,children:i("common.cancel")}),jsxRuntime.jsx("button",{type:"submit","data-testid":"review-draft-submit",className:"docx-review__submit",disabled:n.trim().length===0,children:i("common.comment")})]}),c?jsxRuntime.jsx("span",{className:"docx-review__refused",role:"alert",children:i("review.commentRefused")}):null]})})})}Te.docxReviewPart="Draft";function De({className:e,hidden:r}){let{review:l,allItems:s,authorSlots:t}=O(),o=Y(),i=react.useRef(null),[n,d]=react.useState(null),c=react.useRef(false);c.current=n!==null,react.useEffect(()=>{let f=i.current,p=f?.closest(".docx-review"),y=p?.closest(".docx-editor__scroll-container")??p?.offsetParent;if(!f||!p||!y)return;let P=(E,C)=>{let _=p.getBoundingClientRect(),$=E.getBoundingClientRect(),q=E.ownerDocument.defaultView?.innerHeight??1/0,M=Number(E.dataset.start),ee=Number(E.dataset.end);d({revisionId:E.dataset.revisionId,author:E.dataset.revisionAuthor??"",...E.dataset.revisionDate!==void 0?{date:E.dataset.revisionDate}:{},...E.dataset.revisionKind!==void 0?{kind:E.dataset.revisionKind}:{},structuralSite:C,...E.dataset.paragraphId!==void 0?{paragraphId:E.dataset.paragraphId}:{},...Number.isFinite(M)?{start:M}:{},...Number.isFinite(ee)?{end:ee}:{},left:$.left-_.left,top:$.top-_.top,bottom:$.bottom-_.top,above:$.bottom+220>q});},I=E=>{let C=E.target;if(!(C instanceof Element)||f.contains(C))return;let _=C.closest("[data-revision-id]");if(_ instanceof HTMLElement&&y.contains(_)){let $=_.classList.contains("docx-table-row--revision");if(_.dataset.revisionKind==="format"||$){P(_,$);return}}c.current&&d(null);};return y.addEventListener("pointerdown",I,true),y.addEventListener("mousedown",I,true),()=>{y.removeEventListener("pointerdown",I,true),y.removeEventListener("mousedown",I,true);}},[]);let v=react.useMemo(()=>{if(!n)return null;let f=null,p=false,y=null,P=false,I=null,E=false;for(let C of s)if(!(C.kind!=="revision"||C.item.kind!=="revision")){for(let _ of C.item.addresses)if(_.id===n.revisionId){if(_.author===n.author){if(_.date===n.date)return C;f===null?f=C:f!==C&&(p=true);}y===null?y=C:y!==C&&(P=true);}if(n.paragraphId!==void 0&&n.start!==void 0&&n.end!==void 0&&(C.revisionKind==="format"||C.revisionKind==="structural")){for(let _ of C.item.ranges)if(_.start.paragraphId===n.paragraphId&&_.start.offset<n.end&&_.end.offset>n.start){I===null?I=C:I!==C&&(E=true);break}}}return f!==null&&!p?f:y!==null&&!P?y:I!==null&&!E?I:null},[s,n]),b=v&&(v.revisionKind==="format"||v.revisionKind==="structural")?v:null,R=react.useRef(false);if(react.useEffect(()=>{if(b){R.current=true;return}R.current&&(R.current=false,d(null));},[b]),r)return null;let w=n?.kind==="format"?"format":"structural";return jsxRuntime.jsx("div",{ref:i,className:`docx-review__balloon-root${e?` ${e}`:""}`,children:n===null?null:jsxRuntime.jsx("div",{className:"docx-review__balloon","data-testid":"review-balloon",style:{left:n.left,top:n.above?n.top-6:n.bottom+6,transform:n.above?"translateY(-100%)":void 0},onMouseDown:F,children:b?jsxRuntime.jsx(k.Provider,{value:b,children:jsxRuntime.jsxs("div",{className:"docx-review__card","data-testid":"review-balloon-card","data-kind":b.revisionKind??"revision",style:{"--doc-review-author":`var(--doc-review-author-${(t.get(b.author)??0)%it})`},onClick:()=>l.setActive(b.key),children:[jsxRuntime.jsxs("div",{className:"docx-review__head",children:[jsxRuntime.jsx(ie,{}),jsxRuntime.jsxs("div",{className:"docx-review__meta",children:[jsxRuntime.jsx(ae,{}),jsxRuntime.jsx(se,{})]}),b.kind==="revision"&&!b.readOnly?jsxRuntime.jsxs("div",{className:"docx-review__actions",children:[jsxRuntime.jsx(pe,{}),jsxRuntime.jsx(we,{})]}):null]}),jsxRuntime.jsx(le,{})]})}):jsxRuntime.jsxs("div",{className:"docx-review__card","data-testid":"review-balloon-card","data-kind":w,children:[jsxRuntime.jsxs("div",{className:"docx-review__head",children:[jsxRuntime.jsx("span",{className:"docx-review__avatar","aria-hidden":"true",children:Yt(n.author)}),jsxRuntime.jsxs("div",{className:"docx-review__meta",children:[jsxRuntime.jsx("span",{className:"docx-review__author",children:n.author||o("comments.unknown")}),n.date?jsxRuntime.jsx(Bt,{raw:n.date}):null]})]}),jsxRuntime.jsx("div",{className:"docx-review__summary",children:jsxRuntime.jsx("span",{className:"docx-review__label","data-kind":w,children:o(lt(w))})})]})})})}De.docxReviewPart="Balloon";function Yt(e){let r=e.trim().split(/\s+/).filter(Boolean);return r.length===0?"?":r.slice(0,2).map(l=>l[0].toUpperCase()).join("")}function Bt({raw:e}){let r=new Date(e);return Number.isNaN(r.getTime())?null:jsxRuntime.jsx("time",{className:"docx-review__time",dateTime:e,children:st.format(r)})}function Se({className:e,hidden:r,children:l}){let s=Y();return r?null:jsxRuntime.jsx("div",{className:`docx-review__empty${e?` ${e}`:""}`,"data-testid":"review-empty",children:l??s("review.empty")})}Se.docxReviewPart="Empty";function Le({className:e,asChild:r,hidden:l,children:s}){let{review:t,authorSlots:o}=O(),i=react.useContext(k),n=react.useId();if(l||!i)return null;let d=o.get(i.author)??0,c={className:`docx-review__card${e?` ${e}`:""}`,"data-testid":"review-card","aria-labelledby":`${n}-author ${n}-summary`,"data-kind":i.kind==="revision"?i.revisionKind??"revision":i.kind,...i.kind==="custom"&&i.item.kind==="custom"?{"data-node-name":i.item.name}:{},...i.isActive?{"data-active":""}:{},...i.kind==="comment"&&i.resolved?{"data-resolved":""}:{},style:{"--doc-review-author":`var(--doc-review-author-${d%it})`},tabIndex:0,role:"button",id:n,onMouseDown:v=>{v.target?.closest("[data-review-selectable]")||v.currentTarget.focus({preventScroll:true});},onClick:()=>t.setActive(i.key),onKeyDown:v=>{v.target===v.currentTarget&&(v.key!=="Enter"&&v.key!==" "||(v.preventDefault(),t.setActive(i.key)));}};return r?jsxRuntime.jsx(react$1.Slot,{...c,children:s}):jsxRuntime.jsx("div",{...c,children:jsxRuntime.jsx(jt,{children:s})})}Le.docxReviewPart="Card";function jt({children:e}){let r=react.useContext(k),l=react.useMemo(()=>at(e),[e]),s=(o,i)=>o in l?l[o]:i;if(!r)return null;if(r.kind==="custom"&&r.item.kind==="custom"){let o=r.item;return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsxs("div",{className:"docx-review__head",children:[s("Avatar",null),jsxRuntime.jsx("div",{className:"docx-review__meta",children:s("Author",jsxRuntime.jsx("span",{className:"docx-review__author","data-testid":"review-custom-title",children:o.title}))})]}),s("Summary",o.detail?jsxRuntime.jsx("div",{className:"docx-review__summary","data-testid":"review-summary","data-review-selectable":"",children:jsxRuntime.jsx("span",{className:"docx-review__text",children:o.detail})}):null),l.__extra]})}let t=r.kind==="revision"&&!r.readOnly;return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsxs("div",{className:"docx-review__head",children:[s("Avatar",jsxRuntime.jsx(ie,{})),jsxRuntime.jsxs("div",{className:"docx-review__meta",children:[s("Author",jsxRuntime.jsx(ae,{})),s("Time",jsxRuntime.jsx(se,{}))]}),t||r.kind==="comment"?jsxRuntime.jsxs("div",{className:"docx-review__actions",children:[s("Accept",jsxRuntime.jsx(pe,{})),s("Reject",jsxRuntime.jsx(we,{})),s("Delete",jsxRuntime.jsx(Re,{}))]}):null]}),s("Summary",jsxRuntime.jsx(le,{})),s("Replies",jsxRuntime.jsx(Oe,{})),s("Reply",jsxRuntime.jsx($e,{})),l.__extra]})}function at(e){let r={},l=[],s=t=>{if(Array.isArray(t)){t.forEach(s);return}if(!t||typeof t!="object"||!("type"in t)){t&&l.push(t);return}if(t.type===react.Fragment){s(t.props.children);return}let o=t.type.docxReviewPart;o?r[o]=t:l.push(t);};return s(e),l.length>0&&(r.__extra=l),r}function ie({className:e,asChild:r,hidden:l,children:s}){let t=react.useContext(k);if(l||!t||s===void 0&&!t.initials)return null;let o={className:`docx-review__avatar${e?` ${e}`:""}`,"data-testid":"review-avatar","aria-hidden":true};return r?jsxRuntime.jsx(react$1.Slot,{...o,children:s}):jsxRuntime.jsx("span",{...o,children:s??t.initials})}ie.docxReviewPart="Avatar";function ae({className:e,asChild:r,hidden:l,children:s}){let t=react.useContext(k),o=Y();if(l||!t)return null;let i=t.author||o("comments.unknown"),n={className:`docx-review__author${e?` ${e}`:""}`,"data-testid":"review-author"};return r?jsxRuntime.jsx(react$1.Slot,{...n,children:s}):jsxRuntime.jsx("span",{...n,children:s??i})}ae.docxReviewPart="Author";function se({className:e,asChild:r,hidden:l,children:s}){let t=react.useContext(k);if(l||!t)return null;let o=t.date;if(!o)return null;let i=new Date(o);if(Number.isNaN(i.getTime()))return null;let n={className:`docx-review__time${e?` ${e}`:""}`,"data-testid":"review-time",dateTime:o};return r?jsxRuntime.jsx(react$1.Slot,{...n,children:s}):jsxRuntime.jsx("time",{...n,children:s??st.format(i)})}se.docxReviewPart="Time";var st=new Intl.DateTimeFormat(void 0,{month:"short",day:"numeric",hour:"numeric",minute:"2-digit"});function le({className:e,asChild:r,hidden:l,children:s}){let t=react.useContext(k),o=Y();if(l||!t)return null;let i=t.text,n=t.kind!=="revision"?null:o(lt(t.revisionKind)),d=t.kind==="revision"&&t.revisionKind==="replace",c={className:`docx-review__summary${e?` ${e}`:""}`,"data-testid":"review-summary","data-review-selectable":""};return r?jsxRuntime.jsx(react$1.Slot,{...c,children:s}):jsxRuntime.jsx("div",{...c,children:s??(d?jsxRuntime.jsxs("span",{className:"docx-review__text",children:[o("review.replaced")," ",jsxRuntime.jsxs("span",{className:"docx-review__removed",children:['"',t.replacedText,'"']})," ",o("review.replacedWith")," ",jsxRuntime.jsxs("span",{className:"docx-review__added",children:['"',i,'"']})]}):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[n?jsxRuntime.jsx("span",{className:"docx-review__label","data-kind":t.kind==="revision"?t.revisionKind:"revision",children:n}):null,i?jsxRuntime.jsx("span",{className:"docx-review__text",children:i}):null]}))})}le.docxReviewPart="Summary";function lt(e){switch(e){case "insert":return "review.inserted";case "delete":return "review.deleted";case "replace":return "review.replaced";case "moveFrom":return "review.movedFrom";case "moveTo":return "review.movedTo";case "format":return "revisions.runPropertiesChanged";case "paragraphMark":return "revisions.paragraphMarkInserted";default:return "review.structural"}}function pe({className:e,asChild:r,hidden:l,children:s,icon:t}){let{review:o}=O(),i=react.useContext(k),n=Y();if(l||!i||i.kind!=="revision"||i.readOnly)return null;let d=n("review.accept"),c={type:"button",className:`docx-review__action${e?` ${e}`:""}`,"data-testid":"review-accept","aria-label":d,title:d,onMouseDown:F,onClick:v=>{v.stopPropagation(),o.accept(i);}};return r?jsxRuntime.jsx(react$1.Slot,{...c,children:s}):jsxRuntime.jsx("button",{...c,children:t??s??re($t)})}pe.docxReviewPart="Accept";function we({className:e,asChild:r,hidden:l,children:s,icon:t}){let{review:o}=O(),i=react.useContext(k),n=Y();if(l||!i||i.kind!=="revision"||i.readOnly)return null;let d=n("review.reject"),c={type:"button",className:`docx-review__action${e?` ${e}`:""}`,"data-testid":"review-reject","aria-label":d,title:d,onMouseDown:F,onClick:v=>{v.stopPropagation(),o.reject(i);}};return r?jsxRuntime.jsx(react$1.Slot,{...c,children:s}):jsxRuntime.jsx("button",{...c,children:t??s??re(Ht)})}we.docxReviewPart="Reject";function Re({className:e,asChild:r,hidden:l,children:s,icon:t}){let{review:o}=O(),i=react.useContext(k),{t:n}=react$1.useTranslation();if(l||!i||i.kind==="custom"||i.kind==="revision"&&i.readOnly)return null;let d=i.kind==="comment"?n("review.deleteComment"):n("review.discardChange"),c={type:"button",className:`docx-review__action${e?` ${e}`:""}`,"data-testid":"review-delete","aria-label":d,title:d,onMouseDown:F,onClick:v=>{v.stopPropagation(),o.remove(i);}};return r?jsxRuntime.jsx(react$1.Slot,{...c,children:s}):jsxRuntime.jsx("button",{...c,children:t??s??re(Vt)})}Re.docxReviewPart="Delete";function Oe({className:e,hidden:r}){let{byId:l}=O(),s=react.useContext(k);if(r||!s||s.kind==="custom")return null;let t=s.replyIds.map(o=>l.get(o)).filter(o=>o!==void 0);return t.length===0?null:jsxRuntime.jsx("ol",{className:`docx-review__replies${e?` ${e}`:""}`,children:t.map(o=>jsxRuntime.jsx(k.Provider,{value:o,children:jsxRuntime.jsxs("li",{className:"docx-review__reply","data-testid":"review-reply",children:[jsxRuntime.jsxs("div",{className:"docx-review__head",children:[jsxRuntime.jsx(ie,{}),jsxRuntime.jsxs("div",{className:"docx-review__meta",children:[jsxRuntime.jsx(ae,{}),jsxRuntime.jsx(se,{})]}),jsxRuntime.jsx("div",{className:"docx-review__actions",children:jsxRuntime.jsx(Re,{})})]}),jsxRuntime.jsx(le,{})]})},o.key))})}Oe.docxReviewPart="Replies";function $e({className:e,hidden:r,children:l}){let{review:s}=O(),t=react.useContext(k),o=Y(),[i,n]=react.useState(""),[d,c]=react.useState(false),v=react.useId(),b=react.useCallback(()=>{if(!t||i.trim().length===0)return;let R=s.reply(t,i.trim());c(!R),R&&n("");},[t,i,s]);return r||!t||!t.isActive?null:l?jsxRuntime.jsx(jsxRuntime.Fragment,{children:l}):jsxRuntime.jsxs("form",{className:`docx-review__reply-box${e?` ${e}`:""}`,onSubmit:R=>{R.preventDefault(),b();},children:[jsxRuntime.jsx("label",{className:"ep-sr-only",htmlFor:v,children:o("comments.replyPlaceholder")}),jsxRuntime.jsx("input",{id:v,"data-testid":"review-reply-input",className:"docx-review__input",value:i,placeholder:o("comments.replyPlaceholder"),...d?{"aria-invalid":true,"data-refused":""}:{},onChange:R=>{c(false),n(R.target.value);},onClick:R=>R.stopPropagation(),onKeyDown:R=>{R.key==="Enter"&&(R.preventDefault(),b());}}),jsxRuntime.jsxs("div",{className:"docx-review__reply-actions",children:[jsxRuntime.jsx("button",{type:"button","data-testid":"review-reply-cancel",className:"docx-review__text-button",onMouseDown:F,onClick:R=>{R.stopPropagation(),n(""),c(false),s.setActive(null);},children:o("common.cancel")}),jsxRuntime.jsx("button",{type:"submit","data-testid":"review-reply-submit",className:"docx-review__submit",disabled:i.trim().length===0,children:o("review.reply")})]}),d?jsxRuntime.jsx("span",{className:"docx-review__refused",role:"alert","data-testid":"review-reply-refused",children:o("review.replyRefused")}):null]})}$e.docxReviewPart="Reply";var Zt=Object.assign(Kt,{List:fe,Empty:Se,Card:Le,Avatar:ie,Author:ae,Time:se,Summary:le,Accept:pe,Reject:we,Delete:Re,Replies:Oe,Reply:$e,Markers:Ae,AddComment:Me,Draft:Te,Balloon:De});function ce(e){let r=react$1.useDocxEditor();return react.useMemo(()=>e||(r?.getCustomNodeDefinitions()??[]).filter(chunkTNSHSAA4_cjs.d),[e,r])}var Ut=".docx-content-control-boundary";function X(e,r){let{node:l,definition:s,controlId:t}=e,o=t?r?.getReviewItems().find(n=>n.kind==="custom"&&n.item.id===t):void 0;if(o&&o.kind==="custom"){let n=o.item;return {...l,attrs:n.attrs,text:n.text,...t?{nodeId:t}:{}}}let i=s.fromDocx?s.fromDocx({attrs:l.attrs,text:""}):l.attrs;return i===null?null:{...l,attrs:i,...t?{nodeId:t}:{}}}function J(e,r){let l=e?.closest?.(Ut),s=l?.closest(".docx-content-control-chrome"),t=s?.getAttribute("data-tag"),o=t?chunkTNSHSAA4_cjs.c(t):null;if(!l||!o||!t)return null;let i=r.find(n=>n.tagPrefix===o.prefix&&n.name===o.name);return i?{node:{name:o.name,attrs:o.attrs,tag:t,rect:l.getBoundingClientRect()},definition:i,controlId:s?.getAttribute("data-docx-content-control")??null}:null}var He=".docx-content-control-boundary",Qt=e=>{if(!chunkTNSHSAA4_cjs.e.test(e.tagPrefix)||!chunkTNSHSAA4_cjs.e.test(e.name))return [];let r=`${e.tagPrefix}:${e.name}`;return [`.docx-content-control-chrome[data-tag="${r}"]`,`.docx-content-control-chrome[data-tag^="${r}?"]`]};function Gt(e){let{onNodeClick:r,onNodeHover:l}=e,s=react$1.useDocxEditor(),t=ce(e.nodes);return react.useEffect(()=>{let o=document.createElement("style"),i=[];for(let n of t){let d=Qt(n);if(d.length===0)continue;let c=n.chrome?.color!==void 0&&CSS.supports("color",n.chrome.color)?n.chrome.color:"#2563eb";i.push(`${d.map(v=>`${v} ${He}`).join(", ")} {`," pointer-events: auto !important;"," opacity: 1;"," border: none;",` background: color-mix(in srgb, ${c} 12%, transparent);`," border-radius: 6px;"," cursor: default;","}");}return o.textContent=i.join(`
2
+ `),document.head.append(o),()=>o.remove()},[t]),react.useEffect(()=>{let o=n=>{let d=J(n.target,t);if(!d)return;let c=X(d,s);c&&(d.definition.onClick?.(c),r?.(c));},i=n=>{let d=J(n.target,t);if(!d||n.relatedTarget?.closest?.(He)===n.target.closest(He))return;let v=X(d,s);v&&(d.definition.onHover?.(v),l?.(v));};return document.addEventListener("click",o),document.addEventListener("mouseover",i),()=>{document.removeEventListener("click",o),document.removeEventListener("mouseover",i);}},[t,s,r,l]),null}function mt(e){let{onEditNode:r,remove:l=true}=e,s=ce(e.nodes),t=react$1.useContextMenuTarget(),o=react$1.useDocxEditor(),{t:i}=react$1.useTranslation(),n=react.useMemo(()=>t?J(t,s):null,[t,s]),d=react.useMemo(()=>n?X(n,o):null,[n,o]),c=react.useMemo(()=>!n?.definition.reviewCard||!d?null:n.definition.reviewCard({attrs:d.attrs,text:d.text??""}),[n,d]);if(!n||!d)return null;let{definition:v}=n,b=v.label??v.name,R=v.onEdit!==void 0||r!==void 0,w=l&&d.nodeId!==void 0&&o!==null;return !c&&!R&&!w?null:jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[c?jsxRuntime.jsxs("div",{className:"docx-contextmenu__custom-info","data-testid":"custom-node-info",children:[jsxRuntime.jsx("span",{className:"docx-contextmenu__custom-title",children:c.title}),c.detail?jsxRuntime.jsx("span",{className:"docx-contextmenu__custom-detail",children:c.detail}):null]}):null,R?jsxRuntime.jsx(react$1.ContextMenuItem,{label:i("contextMenu.editCustomNode",{label:b}),className:"docx-contextmenu__custom-edit",onSelect:()=>{v.onEdit?.(d),r?.(d,v);}}):null,w?jsxRuntime.jsx(react$1.ContextMenuItem,{label:i("contextMenu.removeCustomNode",{label:b}),className:"docx-contextmenu__custom-remove",onSelect:()=>{chunkTNSHSAA4_cjs.j(o,d.nodeId);}}):null,jsxRuntime.jsx("div",{role:"separator",className:"docx-toolbar__menu-separator"})]})}mt.docxRowPlacement="start";Object.defineProperty(exports,"reviewModule",{enumerable:true,get:function(){return chunkTNSHSAA4_cjs.i}});exports.CustomNodeChrome=Gt;exports.CustomNodeContextMenu=mt;exports.DocxEditorReview=Zt;exports.activatedCustomNodeOf=X;exports.resolveCustomNodeActivation=J;exports.useCustomNodeDefinitions=ce;exports.useReview=me;exports.useReviewItem=Pt;exports.useReviewOf=nt;exports.useStackedReviewPositions=ht;