@docx-editor.dev/pro 0.0.1-placeholder → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +121 -0
- package/README.md +136 -2
- package/THIRD_PARTY_NOTICES.md +22 -0
- package/dist/chunk-NZOS3H23.js +1 -0
- package/dist/chunk-TNSHSAA4.cjs +1 -0
- package/dist/define-custom-node-CkkDPdB0.d.cts +191 -0
- package/dist/define-custom-node-CkkDPdB0.d.ts +191 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +175 -0
- package/dist/index.d.ts +175 -0
- package/dist/index.js +1 -0
- package/dist/react/index.cjs +2 -0
- package/dist/react/index.d.cts +592 -0
- package/dist/react/index.d.ts +592 -0
- package/dist/react/index.js +2 -0
- package/package.json +72 -7
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
|
-
|
|
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
|
-
|
|
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 };
|