@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.
package/LICENSE.md ADDED
@@ -0,0 +1,121 @@
1
+ # EigenPal Pro Evaluation License 1.0
2
+
3
+ Copyright (c) 2026 EigenPal, Inc. All rights reserved.
4
+
5
+ By copying, modifying, or using the Software, you agree to these terms.
6
+
7
+ ## 1. Covered Software
8
+
9
+ “Software” means all source code, object code, documentation, assets, and other
10
+ materials contained in the “packages/pro/” directory of the EigenPal DOCX
11
+ Editor repository, except for any material that expressly states that it is
12
+ subject to a different license.
13
+
14
+ ## 2. Evaluation Permission; Modifications
15
+
16
+ Subject to these terms, EigenPal, Inc. grants you a limited, non-exclusive,
17
+ non-transferable, non-sublicensable, royalty-free license to:
18
+
19
+ 1. view, clone, and copy the Software;
20
+ 2. run the Software internally in a non-production environment solely to
21
+    evaluate its suitability for your intended application; and
22
+ 3. modify the Software solely as reasonably necessary for that internal,
23
+    non-production evaluation.
24
+
25
+ For any such modification, the following applies:
26
+
27
+ You may keep any modification to yourself. If you do not disclose it to EigenPal, Inc. or to anyone else, it remains yours
28
+ If you disclose a modification to EigenPal, Inc. or to any third party, in any form, you assign all right, title, and interest in it to EigenPal, Inc. at the moment of disclosure. The same applies to any feedback you give EigenPal, Inc. You will promptly send EigenPal, Inc. the source code of any modification you disclose, and will sign any document needed to record the assignment.
29
+ Disclosing a modification to a third party grants that third party no rights in it or in the Software. You will not license or purport to license any modification to anyone.
30
+ You may continue using an assigned modification for the internal, non-production evaluation permitted by Section 2 for as long as this license is in effect. EigenPal, Inc. is not obliged to use or support any modification or feedback, and owes you nothing for it.
31
+ You confirm that any modification or feedback you disclose is yours to assign and is not subject to any license that would impose obligations on EigenPal, Inc. or grant rights to any third party.
32
+
33
+
34
+ No other rights are granted.
35
+
36
+ ## 3. No Production Use
37
+
38
+ You may not use the Software for Production Use.
39
+
40
+ “Production Use” means any use of the Software:
41
+
42
+ 1. in a live, operational, or customer-facing environment;
43
+ 2. to provide, operate, support, or enhance a product or service for another
44
+    person or organization;
45
+ 3. to process live, customer, or business-operational data; or
46
+ 4. as part of your ordinary internal business operations, other than evaluation
47
+    and testing.
48
+
49
+ For the avoidance of doubt, Production Use includes embedding the Software in a product made available to
50
+ others, offering the Software through a hosted or managed service, and using it
51
+ in a customer pilot or paid proof of concept.
52
+
53
+ ## 4. No Distribution or Sublicensing
54
+
55
+ You may not sell, sublicense, distribute, publish, transfer, or otherwise make
56
+ the Software or modifications to the Software available to any third party.
57
+
58
+ You may allow your employees and contractors to access the Software solely for
59
+ your evaluation, provided they are bound by restrictions at least as protective
60
+ as these terms. You are responsible for their compliance.
61
+
62
+ ## 5. Commercial Rights
63
+
64
+ Production Use and any rights not expressly granted by this license require a
65
+ separate written commercial agreement signed by EigenPal, Inc.
66
+
67
+ Commercial licenses are available by contacting licensing@eigenpal.com.
68
+
69
+ Access to the Software, correspondence with EigenPal, Inc., or payment of an
70
+ invoice does not by itself grant production or commercial rights unless those
71
+ rights are set out in a written agreement signed by EigenPal, Inc.
72
+
73
+ ## 6. Ownership
74
+
75
+ EigenPal, Inc. and its licensors retain all rights, title, and interest in the
76
+ Software. This license does not transfer ownership or grant any rights by
77
+ implication.
78
+
79
+ Modifying the Software does not grant you the right to use the Software or those
80
+ modifications in production.
81
+
82
+ ## 7. Termination
83
+
84
+ Your rights under this license terminate automatically if you breach these
85
+ terms or if EigenPal terminates this license.
86
+
87
+ Following termination, you must stop using the Software and delete your copies
88
+ and modifications, except for copies that you are legally required to retain.
89
+ EigenPal, Inc. may reinstate your rights in writing.
90
+
91
+ ## 8. No Warranty
92
+
93
+ TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED “AS IS” AND
94
+ WITHOUT WARRANTIES OF ANY KIND, WHETHER EXPRESS, IMPLIED, OR STATUTORY,
95
+ INCLUDING WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
96
+ TITLE, AND NON-INFRINGEMENT.
97
+
98
+ ## 9. Limitation of Liability
99
+
100
+ TO THE MAXIMUM EXTENT PERMITTED BY LAW, EIGENPAL, INC. AND ITS LICENSORS WILL NOT BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, EXEMPLARY, OR PUNITIVE DAMAGES, OR FOR ANY LOSS OF DATA, REVENUE, PROFITS, OR BUSINESS, ARISING FROM OR RELATING TO THE SOFTWARE OR THIS LICENSE. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE TOTAL AGGREGATE LIABILITY OF EIGENPAL, INC. AND ITS LICENSORS FOR ALL CLAIMS ARISING FROM OR RELATING TO THE SOFTWARE OR THIS LICENSE, WHETHER IN CONTRACT, TORT, STRICT LIABILITY, OR ANY OTHER THEORY, WILL NOT EXCEED TEN UNITED STATES DOLLARS (US$10). THE FOREGOING LIMITATIONS APPLY EVEN IF EIGENPAL, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES AND EVEN IF ANY LIMITED REMEDY IS FOUND TO HAVE FAILED OF ITS ESSENTIAL PURPOSE.
101
+
102
+ ## 10. Trademarks
103
+
104
+ This license does not grant permission to use the names, trademarks, service
105
+ marks, or logos of EigenPal, Inc., except to identify the origin of an
106
+ unmodified copy of the Software.
107
+
108
+ ## 11. Governing Law and Jurisdiction
109
+
110
+ This license is governed by the laws of the State of California, without regard
111
+ to its conflict-of-laws rules.
112
+
113
+ Any dispute arising from or relating to this license will be subject to the
114
+ exclusive jurisdiction of the state and federal courts located in California,
115
+ and you consent to their jurisdiction.
116
+
117
+ ## 12. Separate Commercial Agreements
118
+
119
+ If EigenPal, Inc. and you enter into a separate written commercial agreement,
120
+ that agreement controls to the extent it grants additional rights or conflicts
121
+ with this license.
package/README.md CHANGED
@@ -1,5 +1,139 @@
1
+ <p align="center">
2
+ <a href="https://www.docx-editor.dev/">
3
+ <img src="https://raw.githubusercontent.com/eigenpal/docx-editor/main/.github/assets/header.png" alt="DOCX Editor — .docx in, .docx out. Open source, client-side." width="500" />
4
+ </a>
5
+ </p>
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/@docx-editor.dev/pro"><img src="https://img.shields.io/npm/v/@docx-editor.dev/pro.svg?style=flat-square&color=3B5BDB" alt="npm version" /></a>
9
+ <a href="https://github.com/eigenpal/docx-editor/blob/main/packages/pro/LICENSE.md"><img src="https://img.shields.io/badge/license-EigenPal_Pro_Evaluation_1.0-blue.svg?style=flat-square&color=3B5BDB" alt="license" /></a>
10
+ <a href="https://docx-editor.dev/editor"><img src="https://img.shields.io/badge/Live_Demo-3B5BDB?style=flat-square&logo=vercel&logoColor=white" alt="Demo" /></a>
11
+ <a href="https://www.docx-editor.dev/docs/2.x/pro"><img src="https://img.shields.io/badge/Docs-3B5BDB?style=flat-square&logo=readthedocs&logoColor=white" alt="Documentation" /></a>
12
+ </p>
13
+
1
14
  # @docx-editor.dev/pro
2
15
 
3
- Placeholder package reserving this name.
16
+ Three capabilities for the [docx-editor.dev](https://docx-editor.dev) React editor:
17
+
18
+ - **Tracked changes** — suggesting mode, markup rendering, accept and reject
19
+ - **Comments** — threads anchored to a range, with replies
20
+ - **Custom nodes** — your own inline node types, stored as Word content controls
21
+
22
+ ```bash
23
+ npm install @docx-editor.dev/react @docx-editor.dev/pro
24
+ ```
25
+
26
+ The framework-neutral entry is `@docx-editor.dev/pro`; React chrome lives at
27
+ `@docx-editor.dev/pro/react`.
28
+
29
+ ## Register a module
30
+
31
+ Capabilities are modules passed to the editor root. Registration happens at construction, so
32
+ the array identity must be stable. Build it outside render, or the editor rebuilds every time.
33
+
34
+ ```tsx
35
+ import { DocxEditor } from '@docx-editor.dev/react';
36
+ import { reviewModule, DocxEditorReview } from '@docx-editor.dev/pro/react';
37
+
38
+ const MODULES = [reviewModule()];
39
+
40
+ export function Reviewer({ bytes }: { bytes: Uint8Array }) {
41
+ return (
42
+ <DocxEditor.Root document={bytes} modules={MODULES} author="Jess Lin">
43
+ <DocxEditor.Toolbar />
44
+ <DocxEditor.Viewport>
45
+ <DocxEditor.Content />
46
+ {/* Tracked changes and comments as cards beside the page. */}
47
+ <DocxEditorReview />
48
+ </DocxEditor.Viewport>
49
+ </DocxEditor.Root>
50
+ );
51
+ }
52
+ ```
53
+
54
+ `author` is what lands in `w:author`. OOXML requires it, so the engine refuses a comment or
55
+ reply with no author rather than writing an empty attribute.
56
+
57
+ Without a review module the editor still opens a document containing revisions and comments and
58
+ still saves them back untouched. It renders revisions in their final state and offers no review
59
+ UI; the module is what makes them visible and actionable.
60
+
61
+ ## Chrome or hooks
62
+
63
+ Everything the packaged sidebar renders is reachable from `useReview()`. Take the sidebar for
64
+ Word-like cards out of the box; take the hook for your own markup.
65
+
66
+ ```tsx
67
+ import { useReview } from '@docx-editor.dev/pro/react';
68
+
69
+ function ChangeList() {
70
+ const { items, accept, reject, ready } = useReview();
71
+ if (!ready) return null;
72
+
73
+ return (
74
+ <ul>
75
+ {items.map((item) => (
76
+ <li key={item.key}>
77
+ {/* File-derived. Render as text, never as markup. */}
78
+ {item.text} — {item.author}
79
+ {!item.readOnly && (
80
+ <>
81
+ <button onClick={() => accept(item)}>Accept</button>
82
+ <button onClick={() => reject(item)}>Reject</button>
83
+ </>
84
+ )}
85
+ </li>
86
+ ))}
87
+ </ul>
88
+ );
89
+ }
90
+ ```
91
+
92
+ Items come from the document tree rather than from what is currently painted, and each anchor
93
+ comes from layout records rather than measured DOM, so a sidebar built on this does not lag a
94
+ repaint behind the page or break during pagination.
95
+
96
+ ## Custom nodes
97
+
98
+ An inline node type you define — a citation, a mention, a merge field — stored as a Word content
99
+ control whose `w:tag` carries your identity and attributes. Word opens the document, shows the
100
+ node's text, and gives it back unchanged.
101
+
102
+ ```ts
103
+ import { defineCustomNode, customNodesModule } from '@docx-editor.dev/pro';
104
+
105
+ const Citation = defineCustomNode({
106
+ name: 'citation',
107
+ tagPrefix: 'docx',
108
+ label: 'Citation',
109
+ chrome: { color: '#7c3aed' },
110
+ fromDocx: ({ attrs, text }) => ({ ...attrs, label: text }),
111
+ });
112
+
113
+ const MODULES = [customNodesModule({ nodes: [Citation] })];
114
+ ```
115
+
116
+ Every value reaching `fromDocx` came out of a `.docx`, so treat `attrs` and `text` as untrusted.
117
+
118
+ `insertCustomNode`, `updateCustomNode`, and `removeCustomNode` author them from code, and
119
+ `customNodeXml` builds the same content control on a server with no editor and no DOM.
120
+
121
+ ## Licensing
122
+
123
+ Not Apache 2.0 like the editor packages. Licensed under the
124
+ [EigenPal Pro Evaluation License 1.0](https://github.com/eigenpal/docx-editor/blob/main/packages/pro/LICENSE.md):
125
+ free to read, run, and modify internally to evaluate. Production use — a live or customer-facing
126
+ environment, business-operational data, or this package inside something you offer to others —
127
+ requires a written commercial agreement, and so does redistribution.
128
+
129
+ Commercial licensing: [licensing@eigenpal.com](mailto:licensing@eigenpal.com)
130
+
131
+ Both module factories accept an optional `licenseKey`. Construction never validates it and never
132
+ touches the network.
133
+
134
+ ## Documentation
4
135
 
5
- See [docx-editor.dev](https://docx-editor.dev/) for docs.
136
+ - [Pro overview](https://www.docx-editor.dev/docs/2.x/pro)
137
+ - [Tracked changes](https://www.docx-editor.dev/docs/2.x/pro/tracked-changes)
138
+ - [Comments](https://www.docx-editor.dev/docs/2.x/pro/comments)
139
+ - [Custom nodes](https://www.docx-editor.dev/docs/2.x/pro/custom-nodes)
@@ -0,0 +1,22 @@
1
+ # Third-party notices
2
+
3
+ `@docx-editor.dev/pro` is distributed under LicenseRef-EigenPal-Pro-Evaluation-1.0. Its published bundles also contain
4
+ source from the open-source packages listed below, redistributed here under
5
+ their own licenses, reproduced in full.
6
+
7
+ Those copies are not verbatim. The build inlines, minifies and tree-shakes
8
+ them, and includes only the parts each bundle reaches, so what ships is a
9
+ modified form of the original source.
10
+
11
+ The terms of LicenseRef-EigenPal-Pro-Evaluation-1.0 do not apply to the portions of these bundles
12
+ derived from the packages listed below. Those portions are licensed to you
13
+ under their own terms.
14
+
15
+ This file covers code copied INTO the published bundles. Packages this one
16
+ declares as `dependencies` or `peerDependencies` are installed separately by
17
+ the consumer and are not repeated here.
18
+
19
+ Generated by `bun run notices:generate` from the build's esbuild metafile.
20
+ Do not edit by hand.
21
+
22
+ No third-party code is bundled into this package.
@@ -0,0 +1 @@
1
+ import {findNode,revisionItemsOf,collectReviewItems,paragraphOrderOfPart,locateSites,segmentsOf}from'@docx-editor.dev/core/store';import {reviewItemPositionRank}from'@docx-editor.dev/core/layout';function f(e){}var z=64,I=new Set(["__proto__","constructor","prototype"]);function p(e,i,r){let s=new URLSearchParams;for(let[o,d]of Object.entries(r))s.set(o,d);let a=s.toString(),t=a.length>0?`${e}:${i}?${a}`:`${e}:${i}`;return t.length>64?{ok:false,reason:"tag-overflow",length:t.length}:{ok:true,tag:t}}function g(e){if(e.length>64)return null;let i=e.indexOf(":");if(i<=0)return null;let r=e.slice(0,i),s=e.slice(i+1),a=s.indexOf("?"),t=a===-1?s:s.slice(0,a);if(t.length===0)return null;let o=Object.create(null);if(a!==-1)for(let[d,n]of new URLSearchParams(s.slice(a+1))){if(I.has(d))return null;o[d]=n;}return {prefix:r,name:t,attrs:o}}function x(e){return typeof e=="object"&&e!==null&&typeof e.name=="string"&&typeof e.tagPrefix=="string"}var y=/^[A-Za-z0-9_.-]+$/;function U(e){if(!y.test(e.name??""))throw new Error(`defineCustomNode: invalid name ${JSON.stringify(e.name)}`);if(!y.test(e.tagPrefix??""))throw new Error(`defineCustomNode: invalid tagPrefix ${JSON.stringify(e.tagPrefix)}`);return Object.freeze({...e})}function F(e){return f(e.licenseKey),{id:"custom-nodes",customNodes:e.nodes}}function k(e){for(let i of e.children)if(!(i.kind==="textValue"||i.localName!=="sdtPr")){for(let r of i.children)if(!(r.kind==="textValue"||r.localName!=="tag")){for(let s of r.attributes)if(s.localName==="val")return s.value}}}function v(e){if(e.kind==="textValue")return e.value;let i="";for(let r of e.children)i+=v(r);return i}function N(e,i){if(i.length===0)return [];let r=new Map;for(let t of i){let o=`${t.tagPrefix}:${t.name}`;if(r.has(o))throw new Error(`recognizeCustomNodes: duplicate definition for ${JSON.stringify(o)}`);r.set(o,t);}let s=[],a=(t,o)=>{if(!(t.kind==="textValue"||o>64)){if(t.kind==="contentControl"){let d=k(t),n=d!==void 0?g(d):null,l=n?r.get(`${n.prefix}:${n.name}`):void 0;if(n&&l&&d!==void 0){let c=v(t),u=l.fromDocx?l.fromDocx({attrs:n.attrs,text:c}):n.attrs;if(u!==null){s.push({name:l.name,attrs:u,text:c,nodeId:t.id,tag:d});return}}}for(let d of t.children)a(d,o+1);}};return a(e.root,0),s}function R(e,i){let r=findNode(e,i);return !r||r.kind!=="paragraph"?[]:revisionItemsOf({id:e.id,name:e.name,contentType:e.contentType,root:r})}function b(e,i){let r=i.filter(o=>o.reviewCard);if(r.length===0)return [];let s=N(e,r);if(s.length===0)return [];let a=locateSites(e),t=[];for(let o of s){let d=r.find(c=>c.name===o.name&&o.tag.startsWith(`${c.tagPrefix}:`));if(!d)continue;let n=d.reviewCard({attrs:o.attrs,text:o.text});if(n===null)continue;let l=a.get(o.nodeId);t.push({kind:"custom",id:o.nodeId,name:o.name,tag:o.tag,attrs:o.attrs,text:o.text,title:n.title,...n.detail!==void 0?{detail:n.detail}:{},range:l?{partName:e.name,start:{paragraphId:l.paragraphId,offset:l.start},end:{paragraphId:l.paragraphId,offset:l.end}}:null});}return t}function O(e){let i=collectReviewItems(e),r=(e.customNodes??[]).filter(x);if(r.length===0)return i;let s=[e.storyPart],a=new Set([e.storyPart.name]);for(let n of e.furnitureParts??[])a.has(n.name)||(a.add(n.name),s.push(n));let t=[],o=new Map;for(let n of s){t.push(...b(n,r));let l=o.size;for(let[c,u]of paragraphOrderOfPart(n))o.has(c)||o.set(c,l+u);}return t.length===0?i:[...i,...t].sort((n,l)=>reviewItemPositionRank(n,o)-reviewItemPositionRank(l,o))}function se(e={}){return f(e.licenseKey),{id:"review",review:{displayModes:["all-markup","proposed","original"],collectReviewItems:O,revisionItemsOfParagraph:R}}}function w(e){return e.surface??null}function _(e,i){let r=null,s=t=>t.id===i?true:t.kind==="textValue"?false:t.children.some(s),a=(t,o)=>{if(!(r||t.kind==="textValue"||o>64)){if(t.kind==="paragraph"){s(t)&&(r=t);return}for(let d of t.children)a(d,o+1);}};return a(e.root,0),r}function A(e,i){let r=new Set,s=n=>{if(r.add(n.id),n.kind!=="textValue")for(let l of n.children)s(l);},a=n=>{if(n.id===i)return n;if(n.kind==="textValue")return null;for(let l of n.children){let c=a(l);if(c)return c}return null},t=a(e);if(!t)return null;s(t);let o=Number.MAX_SAFE_INTEGER,d=-1;for(let n of segmentsOf(e))r.has(n.runId)&&(n.start<o&&(o=n.start),n.end>d&&(d=n.end));return d<0?null:{start:o,end:d}}function ce(e,i){let r=w(e);if(!r)return {ok:false,code:"notFound",reason:"no document is mounted"};let s=r.session.applyTreeOps([{op:"removeContentControl",controlId:i,keepContent:false}]);return s.committed?{ok:true,changed:true}:{ok:false,code:"unsupported",reason:typeof s.reason=="string"?s.reason:"the removal was refused"}}function ue(e,i,r,s,a,t={}){let o=w(e);if(!o)return {ok:false,code:"notFound",reason:"no document is mounted"};let d=p(i.tagPrefix,i.name,s);if(!d.ok)return {ok:false,code:"invalidArgs",reason:`the encoded tag is ${d.length} characters; Word caps w:tag at 64 \u2014 shorten the attrs`};let n=o.session.part(),l=_(n,r),c=l?A(l,r):null;if(!l||!c)return {ok:false,code:"notFound",reason:"no custom node with that id"};let u=t.lock===void 0?"contentLocked":t.lock,m=o.session.applyTreeOps([{op:"removeContentControl",controlId:r,keepContent:false},{op:"insertInlineContentControl",paragraphId:l.id,offset:c.start,tag:d.tag,text:a,...t.alias===void 0?{}:{alias:t.alias},...u===false?{}:{lock:u}}]);return m.committed?{ok:true,changed:true}:{ok:false,code:"unsupported",reason:typeof m.reason=="string"?m.reason:"the update was refused"}}export{z as a,p as b,g as c,x as d,y as e,U as f,F as g,N as h,se as i,ce as j,ue as k};
@@ -0,0 +1 @@
1
+ 'use strict';var store=require('@docx-editor.dev/core/store'),layout=require('@docx-editor.dev/core/layout');function f(e){}var z=64,I=new Set(["__proto__","constructor","prototype"]);function p(e,i,r){let s=new URLSearchParams;for(let[o,d]of Object.entries(r))s.set(o,d);let a=s.toString(),t=a.length>0?`${e}:${i}?${a}`:`${e}:${i}`;return t.length>64?{ok:false,reason:"tag-overflow",length:t.length}:{ok:true,tag:t}}function g(e){if(e.length>64)return null;let i=e.indexOf(":");if(i<=0)return null;let r=e.slice(0,i),s=e.slice(i+1),a=s.indexOf("?"),t=a===-1?s:s.slice(0,a);if(t.length===0)return null;let o=Object.create(null);if(a!==-1)for(let[d,n]of new URLSearchParams(s.slice(a+1))){if(I.has(d))return null;o[d]=n;}return {prefix:r,name:t,attrs:o}}function x(e){return typeof e=="object"&&e!==null&&typeof e.name=="string"&&typeof e.tagPrefix=="string"}var y=/^[A-Za-z0-9_.-]+$/;function U(e){if(!y.test(e.name??""))throw new Error(`defineCustomNode: invalid name ${JSON.stringify(e.name)}`);if(!y.test(e.tagPrefix??""))throw new Error(`defineCustomNode: invalid tagPrefix ${JSON.stringify(e.tagPrefix)}`);return Object.freeze({...e})}function F(e){return f(e.licenseKey),{id:"custom-nodes",customNodes:e.nodes}}function k(e){for(let i of e.children)if(!(i.kind==="textValue"||i.localName!=="sdtPr")){for(let r of i.children)if(!(r.kind==="textValue"||r.localName!=="tag")){for(let s of r.attributes)if(s.localName==="val")return s.value}}}function v(e){if(e.kind==="textValue")return e.value;let i="";for(let r of e.children)i+=v(r);return i}function N(e,i){if(i.length===0)return [];let r=new Map;for(let t of i){let o=`${t.tagPrefix}:${t.name}`;if(r.has(o))throw new Error(`recognizeCustomNodes: duplicate definition for ${JSON.stringify(o)}`);r.set(o,t);}let s=[],a=(t,o)=>{if(!(t.kind==="textValue"||o>64)){if(t.kind==="contentControl"){let d=k(t),n=d!==void 0?g(d):null,l=n?r.get(`${n.prefix}:${n.name}`):void 0;if(n&&l&&d!==void 0){let c=v(t),u=l.fromDocx?l.fromDocx({attrs:n.attrs,text:c}):n.attrs;if(u!==null){s.push({name:l.name,attrs:u,text:c,nodeId:t.id,tag:d});return}}}for(let d of t.children)a(d,o+1);}};return a(e.root,0),s}function R(e,i){let r=store.findNode(e,i);return !r||r.kind!=="paragraph"?[]:store.revisionItemsOf({id:e.id,name:e.name,contentType:e.contentType,root:r})}function b(e,i){let r=i.filter(o=>o.reviewCard);if(r.length===0)return [];let s=N(e,r);if(s.length===0)return [];let a=store.locateSites(e),t=[];for(let o of s){let d=r.find(c=>c.name===o.name&&o.tag.startsWith(`${c.tagPrefix}:`));if(!d)continue;let n=d.reviewCard({attrs:o.attrs,text:o.text});if(n===null)continue;let l=a.get(o.nodeId);t.push({kind:"custom",id:o.nodeId,name:o.name,tag:o.tag,attrs:o.attrs,text:o.text,title:n.title,...n.detail!==void 0?{detail:n.detail}:{},range:l?{partName:e.name,start:{paragraphId:l.paragraphId,offset:l.start},end:{paragraphId:l.paragraphId,offset:l.end}}:null});}return t}function O(e){let i=store.collectReviewItems(e),r=(e.customNodes??[]).filter(x);if(r.length===0)return i;let s=[e.storyPart],a=new Set([e.storyPart.name]);for(let n of e.furnitureParts??[])a.has(n.name)||(a.add(n.name),s.push(n));let t=[],o=new Map;for(let n of s){t.push(...b(n,r));let l=o.size;for(let[c,u]of store.paragraphOrderOfPart(n))o.has(c)||o.set(c,l+u);}return t.length===0?i:[...i,...t].sort((n,l)=>layout.reviewItemPositionRank(n,o)-layout.reviewItemPositionRank(l,o))}function se(e={}){return f(e.licenseKey),{id:"review",review:{displayModes:["all-markup","proposed","original"],collectReviewItems:O,revisionItemsOfParagraph:R}}}function w(e){return e.surface??null}function _(e,i){let r=null,s=t=>t.id===i?true:t.kind==="textValue"?false:t.children.some(s),a=(t,o)=>{if(!(r||t.kind==="textValue"||o>64)){if(t.kind==="paragraph"){s(t)&&(r=t);return}for(let d of t.children)a(d,o+1);}};return a(e.root,0),r}function A(e,i){let r=new Set,s=n=>{if(r.add(n.id),n.kind!=="textValue")for(let l of n.children)s(l);},a=n=>{if(n.id===i)return n;if(n.kind==="textValue")return null;for(let l of n.children){let c=a(l);if(c)return c}return null},t=a(e);if(!t)return null;s(t);let o=Number.MAX_SAFE_INTEGER,d=-1;for(let n of store.segmentsOf(e))r.has(n.runId)&&(n.start<o&&(o=n.start),n.end>d&&(d=n.end));return d<0?null:{start:o,end:d}}function ce(e,i){let r=w(e);if(!r)return {ok:false,code:"notFound",reason:"no document is mounted"};let s=r.session.applyTreeOps([{op:"removeContentControl",controlId:i,keepContent:false}]);return s.committed?{ok:true,changed:true}:{ok:false,code:"unsupported",reason:typeof s.reason=="string"?s.reason:"the removal was refused"}}function ue(e,i,r,s,a,t={}){let o=w(e);if(!o)return {ok:false,code:"notFound",reason:"no document is mounted"};let d=p(i.tagPrefix,i.name,s);if(!d.ok)return {ok:false,code:"invalidArgs",reason:`the encoded tag is ${d.length} characters; Word caps w:tag at 64 \u2014 shorten the attrs`};let n=o.session.part(),l=_(n,r),c=l?A(l,r):null;if(!l||!c)return {ok:false,code:"notFound",reason:"no custom node with that id"};let u=t.lock===void 0?"contentLocked":t.lock,m=o.session.applyTreeOps([{op:"removeContentControl",controlId:r,keepContent:false},{op:"insertInlineContentControl",paragraphId:l.id,offset:c.start,tag:d.tag,text:a,...t.alias===void 0?{}:{alias:t.alias},...u===false?{}:{lock:u}}]);return m.committed?{ok:true,changed:true}:{ok:false,code:"unsupported",reason:typeof m.reason=="string"?m.reason:"the update was refused"}}exports.a=z;exports.b=p;exports.c=g;exports.d=x;exports.e=y;exports.f=U;exports.g=F;exports.h=N;exports.i=se;exports.j=ce;exports.k=ue;
@@ -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 };