@onodocs/canvas 0.4.0 → 0.5.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 +12 -4
- package/LICENSING.md +19 -3
- package/README.md +25 -7
- package/SDK.md +25 -7
- package/agreement-review.md +1 -1
- package/application-integration.md +5 -3
- package/document-collaboration.md +6 -2
- package/document-forms.md +5 -5
- package/document-modes.md +2 -2
- package/editor.md +39 -0
- package/index.js +51 -17
- package/package.json +3 -2
- package/proposal.md +4 -4
- package/templates.md +3 -3
- package/types/canvas/presentation.d.ts +1 -0
- package/types/render-api/page-display-list.d.ts +4 -0
package/LICENSE
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
OnoDocs SDK
|
|
1
|
+
OnoDocs SDK and Canvas
|
|
2
2
|
All rights reserved, except for the permissions below and separately licensed third-party components.
|
|
3
3
|
|
|
4
|
+
These terms apply to @onodocs/sdk and @onodocs/canvas. OnoDocs-authored @onodocs/editor source is separately licensed under MIT, including its interface, application sessions, form and template controls, and collaboration client. These commercial terms do not restrict the MIT rights to use, modify or redistribute that editor code. The editor's MIT license does not grant production or redistribution rights in SDK or Canvas dependencies. Third-party code retains its own license.
|
|
5
|
+
|
|
4
6
|
Free evaluation permits installation, development, testing, and internal demonstrations for the purpose of evaluating OnoDocs. It has no time limit. It does not permit production use, including internal production workflows or services supplied to others. Preserve evaluation notices and watermarks. A signed trial license permits watermark-free evaluation for 30 days from issuance; it does not grant production rights.
|
|
5
7
|
|
|
6
|
-
Production use requires a commercial license issued by OnoDocs. The named licensee may use and deploy
|
|
8
|
+
Production use requires a commercial license issued by OnoDocs. The named licensee may use and deploy OnoDocs within the application scope recorded in that license and the associated purchase agreement. One application license covers the SDK and Canvas packages and all capabilities serving that named product, including its frontend, backend, workers and self-hosted collaboration. Backend-only document automation also counts as an application. The same product's domains, environments, tenants and customer-hosted installations are included. A shared backend serving three distinct products requires scope covering three applications. Developers, users and processed documents are unlimited within the covered application scope.
|
|
9
|
+
|
|
10
|
+
Ordinary embedding and custom branding within a covered application are included. A finished document editor sold to end users is permitted under an ordinary application license. Reselling a reusable component containing the SDK or Canvas, granting independent downstream development rights to those packages, or selling a general document-processing API using them to developers requires a separate written redistribution agreement with OnoDocs. An agency or its client may be the named licensee, with the client application identified in the agreed scope.
|
|
11
|
+
|
|
12
|
+
Generated DOCX and PDF files and extracted data may be distributed without OnoDocs royalties or recipient licenses. Recipients who run SDK or Canvas in their own software must have that use covered by an application license or separate redistribution agreement. Evaluation notices and watermarks must still be preserved.
|
|
13
|
+
|
|
14
|
+
Covered releases may be used perpetually. The initial purchase includes 12 months of updates and email support for product issues. The updates-through date includes releases published on that UTC date; it is not a runtime expiry. Renewal is optional and grants further updates and support under the purchase agreement.
|
|
7
15
|
|
|
8
|
-
Do not use another customer's key or remove licensing checks or evaluation notices to obtain unlicensed production use. The same terms apply to low-level stage APIs, custom adapters, browser applications
|
|
16
|
+
Do not use another customer's key or remove licensing checks or evaluation notices to obtain unlicensed production use. The same terms apply to low-level stage APIs, custom adapters, browser applications and server processing. A publicly downloadable package does not grant production rights.
|
|
9
17
|
|
|
10
|
-
|
|
18
|
+
OnoDocs is provided as is, without warranties, except as expressly agreed in a commercial agreement. Third-party components retain their respective licenses.
|
package/LICENSING.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Offline licensing
|
|
2
2
|
|
|
3
|
-
The OnoDocs SDK and Canvas packages support evaluation, trial and commercial use under the
|
|
3
|
+
The OnoDocs SDK and Canvas packages support evaluation, trial and commercial use under the terms below. OnoDocs-authored `@onodocs/editor` code is licensed under MIT, including its UI, application sessions, form/template controls and collaboration client. You may use, modify and redistribute that editor code in commercial products under MIT. Preserve its copyright notice and applicable third-party notices. MIT rights in Editor do not grant production or redistribution rights in the commercial SDK and Canvas dependencies. Editor has no separate entitlement. Packages can be installed from an npm registry or supplied archives and copied into an offline environment. Runtime licensing makes no network requests.
|
|
4
4
|
|
|
5
5
|
| Mode | Behavior |
|
|
6
6
|
| --- | --- |
|
|
@@ -9,6 +9,18 @@ The OnoDocs SDK and Canvas packages support evaluation, trial and commercial use
|
|
|
9
9
|
| Commercial | Signed key permits the purchased scope and removes evaluation notices. Covered releases work indefinitely. |
|
|
10
10
|
| Demo | OnoDocs website demonstrations only. Valid for at most 24 hours at one exact browser origin; not valid for backend use. |
|
|
11
11
|
|
|
12
|
+
## Application scope
|
|
13
|
+
|
|
14
|
+
One application license covers SDK and Canvas and all capabilities serving one named product, including frontend, backend, workers and self-hosted collaboration. Backend-only document automation counts as an application. Multiple domains, environments, tenants and customer-hosted installations of that same product are included. A shared backend serving three distinct products needs scope covering three applications. Developers, users and documents are unlimited within that scope.
|
|
15
|
+
|
|
16
|
+
Ordinary embedding and custom branding are included, as is selling a finished document editor to end users. Reselling reusable components containing SDK or Canvas, granting independent downstream development rights to those commercial packages, or selling a general document-processing API using them to developers requires a separately quoted written redistribution agreement. Redistribution of the MIT editor code itself remains permitted under MIT. For agency work, identify the client application and whether the agency or client is the license holder in the purchase agreement.
|
|
17
|
+
|
|
18
|
+
Generated DOCX, PDF and extracted data can be distributed without OnoDocs royalties or recipient licenses. A recipient running SDK or Canvas in their own software needs covered application scope or a separate redistribution agreement. Preserve evaluation notices and watermarks. DOCX export does not add a watermark or restrict document content.
|
|
19
|
+
|
|
20
|
+
A one-application license costs $999 and a five-application license costs $2,499. Both include all capabilities, perpetual use of covered releases, and 12 months of updates and email product-issue support. Optional renewals cost $499 and $1,249 respectively. Renewals extend updates and support; covered releases continue working without renewal.
|
|
21
|
+
|
|
22
|
+
## Runtime configuration
|
|
23
|
+
|
|
12
24
|
Pass the issued token as `licenseKey` when opening a document:
|
|
13
25
|
|
|
14
26
|
```ts
|
|
@@ -24,10 +36,14 @@ The default Node analysis entry point accepts the same option. With `@onodocs/sd
|
|
|
24
36
|
|
|
25
37
|
Missing or invalid keys preserve document functionality and return evaluation mode with a `reason`: `missing-key`, `invalid-key`, `verification-unavailable`, `not-yet-valid`, `trial-expired`, or `release-not-covered`. Trial expiry is checked on opening, status access and rendering. Already produced images remain unchanged. Browsers need HTTPS or a secure local context for native signature verification; no internet connection is needed. The headless renderer supplies its own isolated secure context.
|
|
26
38
|
|
|
27
|
-
Commercial keys contain an inclusive `updatesThrough` date. A key covering 2027-10-04 permits releases published on or before that UTC date forever. Renew to use later releases and receive further support. `sdkReleaseDate`, exported from
|
|
39
|
+
Commercial keys contain an inclusive `updatesThrough` date. A key covering 2027-10-04 permits releases published on or before that UTC date forever. Renew to use later releases and receive further support. `sdkReleaseDate`, exported from the SDK analysis, browser and server entry points, identifies the running release date. Scope is recorded in the key and purchase agreement; it is not inferred from a hostname or tracked online.
|
|
28
40
|
|
|
29
41
|
Canvas, mounted views, PNG, JPEG and PDF receive the same evaluation watermark. Queries, source models, layouts and display lists remain complete. Low-level stage APIs and custom adapters are covered by the same terms; custom evaluation presentations must preserve an evaluation notice. Offline JavaScript checks can be bypassed by changing code or the clock; they do not provide immediate revocation or seat counting.
|
|
30
42
|
|
|
31
43
|
Demo licenses also report `demo-expired` or `origin-not-covered`. The website handles early renewal; the SDK continues to verify locally without contacting a license server. They do not grant customer production rights.
|
|
32
44
|
|
|
33
|
-
|
|
45
|
+
SDK and Canvas include the commercial `LICENSE`; Editor includes the MIT `LICENSE`. Third-party components retain their respective licenses.
|
|
46
|
+
|
|
47
|
+
Editor and application sessions accept the key through `document: { licenseKey }`. Form views and designers use the same document option. Collaborative browser sessions use `editor: { document: { licenseKey } }`; their host service accepts `createCollaborationService({ licenseKey, authorize, storage })`. Configure both sides of the named application. Templates retain their opening key when generating documents, and data-only forms use their supplied document's entitlement. The HTTP service forwards its `document` options to the renderer.
|
|
48
|
+
|
|
49
|
+
Application counts and redistribution permissions are contractual. The verifier checks signed identity, trial expiry and release coverage, with no application counter or customer host binding. The origin restriction applies only to short-lived OnoDocs website demo keys. Existing commercial keys remain valid within their agreed scope.
|
package/README.md
CHANGED
|
@@ -8,11 +8,11 @@ For form authoring, controlled answer regions and completed DOCX plus structured
|
|
|
8
8
|
|
|
9
9
|
For application events, autosave, recovery, framework lifecycle and self-hosted HTTP, see [application integration](application-integration.md).
|
|
10
10
|
|
|
11
|
-
`@onodocs/sdk` processes Word documents. Its default entry performs analysis in Node or a browser; `/browser` adds layout and immutable page publication using browser font services; `/server` runs that processing in headless Chromium. `@onodocs/canvas` paints prepared pages and provides the viewer, selection and DOM attachments. The Canvas package runs independently of the parser, semantic engine and layout engine.
|
|
11
|
+
`@onodocs/sdk` processes Word documents. Its default entry performs analysis in Node or a browser; `/browser` adds layout and immutable page publication using browser font services; `/server` runs that processing in headless Chromium. `@onodocs/canvas` paints prepared pages and provides the viewer, selection and DOM attachments. The Canvas package runs independently of the parser, semantic engine and layout engine. `@onodocs/editor` provides the ready-made editor and its UI workflows through public SDK and Canvas APIs. See the [editor package and migration guide](editor.md).
|
|
12
12
|
|
|
13
13
|
Supported Word inputs are DOCX, DOCM, DOTX and DOTM. Macro-enabled files are rendered without executing VBA. Older binary DOC/DOT files and RTF are not supported.
|
|
14
14
|
|
|
15
|
-
Install with `npm install @onodocs/sdk @onodocs/canvas`. Use matching versions of both packages. A backend can install only the SDK; a frontend receiving prepared pages can install only Canvas. Both packages include TypeScript declarations and this guide. Archives are also available from the [public releases](https://github.com/onodocs/onodocs/releases). Server rendering requires an installed Chromium-family browser. The server adapter includes the Canvas runtime it uses for image and PDF export.
|
|
15
|
+
Install with `npm install @onodocs/sdk @onodocs/canvas`. Use matching versions of both packages. A backend performing data operations can install only the SDK; a frontend receiving prepared pages can install only Canvas. Both packages include TypeScript declarations and this guide. Archives are also available from the [public releases](https://github.com/onodocs/onodocs/releases). Server rendering requires `npm install @onodocs/sdk playwright-core` and an installed Chromium-family browser. Playwright is an optional peer dependency, so browser and data-only installs do not install it. The server adapter includes the Canvas runtime it uses for image and PDF export.
|
|
16
16
|
|
|
17
17
|
Without a key, the SDK runs in free, non-production evaluation mode with full features and a watermark on rendered output. Pass `{ licenseKey }` to `openDocument` for a 30-day trial or commercial entitlement; this works in all three entry points. Verification is entirely offline. Commercial keys permit covered releases indefinitely, with renewal for later releases and support. Browser verification requires HTTPS or a secure local context. See the included `LICENSING.md` and `LICENSE` for details.
|
|
18
18
|
|
|
@@ -87,7 +87,7 @@ The [report review example](https://github.com/ionoy/onodocs/blob/main/docs/ai-r
|
|
|
87
87
|
|
|
88
88
|
## Design and generate Word templates
|
|
89
89
|
|
|
90
|
-
Use `createTemplateEditor` from `@onodocs/
|
|
90
|
+
Use `createTemplateEditor` from `@onodocs/editor` for visual field authoring and preview. `openTemplate` and `templateTag` from the default SDK and browser entries support fields, repeated content, conditions, images, formatted values, reusable sections and batch generation. See [Word templates and generation](templates.md) for the binding model, authoring commands and output workflow.
|
|
91
91
|
|
|
92
92
|
## Replace text and fill templates
|
|
93
93
|
|
|
@@ -171,7 +171,7 @@ Node and browser documents expose `edit`; server documents forward the same oper
|
|
|
171
171
|
## Embed the Word editor
|
|
172
172
|
|
|
173
173
|
```js
|
|
174
|
-
import { createEditor } from "@onodocs/
|
|
174
|
+
import { createEditor } from "@onodocs/editor";
|
|
175
175
|
|
|
176
176
|
const editor = createEditor({ container: document.querySelector("#editor") });
|
|
177
177
|
await editor.newDocument();
|
|
@@ -181,9 +181,23 @@ editor.dispose();
|
|
|
181
181
|
|
|
182
182
|
The component includes file opening, a new-document command, formatting, imported paragraph styles, lists, regular tables, paragraph images, links, page settings, default headers and footers, find/replace, clipboard operations, undo/redo and Word/PDF downloads. It runs in the browser. `examples/browser-editor/` is the standalone application; run `npm run example:editor` from the source workspace.
|
|
183
183
|
|
|
184
|
-
|
|
184
|
+
Use `toolbar` to choose which controls are available in the ribbon, or pass `false` to supply your own controls. The editor groups controls into File, Home, Insert and Layout tabs, with Table and Picture tabs for the selected content. Available names are `open`, `new`, `save`, `pdf`, `undo`, `redo`, `bold`, `italic`, `underline`, `strike`, `font`, `size`, `color`, `alignment`, `style`, `list`, `table`, `tableTools`, `link`, `image`, `imageTools`, `page`, `header`, `footer`, `find` and `replace`. `fonts` supplies font-family choices; `styles` supplies `{ id, label }` choices using existing Word style IDs. `onChange` receives the editor after committed changes; `onError` reports queued operation failures. Use `document` for browser SDK options such as licensing and font sources, and `readOnly: true` to disable authoring.
|
|
185
185
|
|
|
186
|
-
|
|
186
|
+
`commands` adds application actions to the Home tab. Set a command's `ribbon` metadata to place it in a named tab and group. Include its ID when restricting `toolbar` to a list of controls.
|
|
187
|
+
|
|
188
|
+
```js
|
|
189
|
+
const editor = createEditor({
|
|
190
|
+
container: document.querySelector("#editor"),
|
|
191
|
+
commands: [{
|
|
192
|
+
id: "save-to-project",
|
|
193
|
+
label: "Save to project",
|
|
194
|
+
ribbon: { tab: "File", group: "Project" },
|
|
195
|
+
execute: async editor => saveToProject(await editor.save()),
|
|
196
|
+
}],
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
The editor supports native text selection and IME input. F6 switches between the document and ribbon, Escape focuses the ribbon, and Shift+Tab leaves the editing area. Arrow keys move between ribbon tabs. On touch screens, tap to place the caret, hold to select a word, and drag the selection endpoints. Narrow ribbons scroll horizontally. Mounted pages expose text and headings to browser accessibility tools, including pages whose canvases have been evicted.
|
|
187
201
|
|
|
188
202
|
Each instance has isolated styles and history. Customize `--onodocs-color`, `--onodocs-background`, `--onodocs-toolbar-background`, `--onodocs-accent` and `--onodocs-selection` on the host container. The `toolbar`, `pages` and `status` shadow parts are available for host styling. Call `dispose()` when removing an editor.
|
|
189
203
|
|
|
@@ -221,7 +235,7 @@ input.name = "customerName";
|
|
|
221
235
|
const attachment = view.attach(input, { anchor: doc.geometry.fragments(field)[0] });
|
|
222
236
|
```
|
|
223
237
|
|
|
224
|
-
The example requires a tagged control that produces one visible fragment. Call `doc.geometry.fragments(field)` for content spanning lines, pages, or repeated stories, and attach to an explicitly chosen fragment. Fragments retain transforms and clipping. Table/cell anchors use their final physical rectangles. `offset` and `size` optionally adjust attachment placement in page units. Values, validation, submission, focus, and accessibility labels belong to the application. Attaching an element moves it into the view. Detachment removes it and restores its original inline style. Reattaching the same HTML element disposes its previous attachment; old handles become inert. An attachment exposes its disposed state.
|
|
238
|
+
The example requires a tagged control that produces one visible fragment. Call `doc.geometry.fragments(field)` for content spanning lines, pages, or repeated stories, and attach to an explicitly chosen fragment. Fragments retain transforms and clipping. Table/cell anchors use their final physical rectangles. `offset` and `size` optionally adjust attachment placement in page units. Use `interactive: false` for decorative overlays so clicks reach the document underneath. Values, validation, submission, focus, and accessibility labels belong to the application. Attaching an element moves it into the view. Detachment removes it and restores its original inline style. Reattaching the same HTML element disposes its previous attachment; old handles become inert. An attachment exposes its disposed state.
|
|
225
239
|
|
|
226
240
|
Pages are anchors too. Placement avoids manual rectangle arithmetic:
|
|
227
241
|
|
|
@@ -383,6 +397,8 @@ Open with `revisionView: "accepted"` when editing current text. `readReview()` i
|
|
|
383
397
|
|
|
384
398
|
Enable the editor panel with `review: { identity: () => identity, history }`. The optional `history` object implements `list(signal)`, `load(id, signal)` and `save(version, bytes, signal)`. Your application stores the complete Word bytes and version metadata. The SDK adds no persistence service or user account system. Restoring a version is undoable and raises the editor's change event, so application autosave can persist it. `compareDocuments(savedBytes, doc)` returns paragraph text and formatting differences without modifying the document.
|
|
385
399
|
|
|
400
|
+
Browser and server opening options accept `commentDisplay: "hidden"` to hide comment indicators in rendered pages and PDF exports. Comments remain available through `readReview()` and in saved Word files. The editor uses this display by default and shows comments in its Review pane. Set `document: { commentDisplay: "markers" }` to display indicators in the editor; SDK rendering defaults to markers.
|
|
401
|
+
|
|
386
402
|
## Searchable PDF in the browser
|
|
387
403
|
|
|
388
404
|
```js
|
|
@@ -405,3 +421,5 @@ try {
|
|
|
405
421
|
PDF export runs locally and uses the same implementation as server `doc.pdf()`. It waits for earlier edits to finish. Pass `signal` to cancel an export without closing the document. The PDF writer loads on demand; deploy the browser entry's generated chunks alongside it. Text extraction order for bidirectional paragraphs and selection across complex clusters depend on the PDF reader. Solid graphics use vector PDF paths where supported. Native text and complex effects retain browser rendering in cropped lossless image layers, including evaluation marks. Higher DPI increases the sharpness, file size and temporary memory use of those layers; compressed output remains in memory until export finishes.
|
|
406
422
|
|
|
407
423
|
The PDF includes tagged headings, paragraphs, nested lists, tables, header cells, merged-cell row/column spans, authored figure descriptions and links, plus heading and bookmark navigation. Set `title` and `language` for reader metadata. DrawingML descriptions use `wp:docPr/@descr`, falling back to `title`; VML uses authored `alt` text. Undescribed graphics remain artifacts. Reader support varies. Firefox PDF.js exposes named images, list nesting and table spans in its accessibility tree. This does not claim PDF/UA conformance or validation with every screen reader.
|
|
424
|
+
|
|
425
|
+
One named-application license covers SDK and Canvas, including the application's backend and self-hosted collaboration. Finished editors for end users are included. Editor source is separately licensed under MIT. See [application scope, output rights and redistribution terms](licensing.md).
|
package/SDK.md
CHANGED
|
@@ -8,11 +8,11 @@ For form authoring, controlled answer regions and completed DOCX plus structured
|
|
|
8
8
|
|
|
9
9
|
For application events, autosave, recovery, framework lifecycle and self-hosted HTTP, see [application integration](application-integration.md).
|
|
10
10
|
|
|
11
|
-
`@onodocs/sdk` processes Word documents. Its default entry performs analysis in Node or a browser; `/browser` adds layout and immutable page publication using browser font services; `/server` runs that processing in headless Chromium. `@onodocs/canvas` paints prepared pages and provides the viewer, selection and DOM attachments. The Canvas package runs independently of the parser, semantic engine and layout engine.
|
|
11
|
+
`@onodocs/sdk` processes Word documents. Its default entry performs analysis in Node or a browser; `/browser` adds layout and immutable page publication using browser font services; `/server` runs that processing in headless Chromium. `@onodocs/canvas` paints prepared pages and provides the viewer, selection and DOM attachments. The Canvas package runs independently of the parser, semantic engine and layout engine. `@onodocs/editor` provides the ready-made editor and its UI workflows through public SDK and Canvas APIs. See the [editor package and migration guide](editor.md).
|
|
12
12
|
|
|
13
13
|
Supported Word inputs are DOCX, DOCM, DOTX and DOTM. Macro-enabled files are rendered without executing VBA. Older binary DOC/DOT files and RTF are not supported.
|
|
14
14
|
|
|
15
|
-
Install with `npm install @onodocs/sdk @onodocs/canvas`. Use matching versions of both packages. A backend can install only the SDK; a frontend receiving prepared pages can install only Canvas. Both packages include TypeScript declarations and this guide. Archives are also available from the [public releases](https://github.com/onodocs/onodocs/releases). Server rendering requires an installed Chromium-family browser. The server adapter includes the Canvas runtime it uses for image and PDF export.
|
|
15
|
+
Install with `npm install @onodocs/sdk @onodocs/canvas`. Use matching versions of both packages. A backend performing data operations can install only the SDK; a frontend receiving prepared pages can install only Canvas. Both packages include TypeScript declarations and this guide. Archives are also available from the [public releases](https://github.com/onodocs/onodocs/releases). Server rendering requires `npm install @onodocs/sdk playwright-core` and an installed Chromium-family browser. Playwright is an optional peer dependency, so browser and data-only installs do not install it. The server adapter includes the Canvas runtime it uses for image and PDF export.
|
|
16
16
|
|
|
17
17
|
Without a key, the SDK runs in free, non-production evaluation mode with full features and a watermark on rendered output. Pass `{ licenseKey }` to `openDocument` for a 30-day trial or commercial entitlement; this works in all three entry points. Verification is entirely offline. Commercial keys permit covered releases indefinitely, with renewal for later releases and support. Browser verification requires HTTPS or a secure local context. See the included `LICENSING.md` and `LICENSE` for details.
|
|
18
18
|
|
|
@@ -87,7 +87,7 @@ The [report review example](https://github.com/ionoy/onodocs/blob/main/docs/ai-r
|
|
|
87
87
|
|
|
88
88
|
## Design and generate Word templates
|
|
89
89
|
|
|
90
|
-
Use `createTemplateEditor` from `@onodocs/
|
|
90
|
+
Use `createTemplateEditor` from `@onodocs/editor` for visual field authoring and preview. `openTemplate` and `templateTag` from the default SDK and browser entries support fields, repeated content, conditions, images, formatted values, reusable sections and batch generation. See [Word templates and generation](templates.md) for the binding model, authoring commands and output workflow.
|
|
91
91
|
|
|
92
92
|
## Replace text and fill templates
|
|
93
93
|
|
|
@@ -171,7 +171,7 @@ Node and browser documents expose `edit`; server documents forward the same oper
|
|
|
171
171
|
## Embed the Word editor
|
|
172
172
|
|
|
173
173
|
```js
|
|
174
|
-
import { createEditor } from "@onodocs/
|
|
174
|
+
import { createEditor } from "@onodocs/editor";
|
|
175
175
|
|
|
176
176
|
const editor = createEditor({ container: document.querySelector("#editor") });
|
|
177
177
|
await editor.newDocument();
|
|
@@ -181,9 +181,23 @@ editor.dispose();
|
|
|
181
181
|
|
|
182
182
|
The component includes file opening, a new-document command, formatting, imported paragraph styles, lists, regular tables, paragraph images, links, page settings, default headers and footers, find/replace, clipboard operations, undo/redo and Word/PDF downloads. It runs in the browser. `examples/browser-editor/` is the standalone application; run `npm run example:editor` from the source workspace.
|
|
183
183
|
|
|
184
|
-
|
|
184
|
+
Use `toolbar` to choose which controls are available in the ribbon, or pass `false` to supply your own controls. The editor groups controls into File, Home, Insert and Layout tabs, with Table and Picture tabs for the selected content. Available names are `open`, `new`, `save`, `pdf`, `undo`, `redo`, `bold`, `italic`, `underline`, `strike`, `font`, `size`, `color`, `alignment`, `style`, `list`, `table`, `tableTools`, `link`, `image`, `imageTools`, `page`, `header`, `footer`, `find` and `replace`. `fonts` supplies font-family choices; `styles` supplies `{ id, label }` choices using existing Word style IDs. `onChange` receives the editor after committed changes; `onError` reports queued operation failures. Use `document` for browser SDK options such as licensing and font sources, and `readOnly: true` to disable authoring.
|
|
185
185
|
|
|
186
|
-
|
|
186
|
+
`commands` adds application actions to the Home tab. Set a command's `ribbon` metadata to place it in a named tab and group. Include its ID when restricting `toolbar` to a list of controls.
|
|
187
|
+
|
|
188
|
+
```js
|
|
189
|
+
const editor = createEditor({
|
|
190
|
+
container: document.querySelector("#editor"),
|
|
191
|
+
commands: [{
|
|
192
|
+
id: "save-to-project",
|
|
193
|
+
label: "Save to project",
|
|
194
|
+
ribbon: { tab: "File", group: "Project" },
|
|
195
|
+
execute: async editor => saveToProject(await editor.save()),
|
|
196
|
+
}],
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
The editor supports native text selection and IME input. F6 switches between the document and ribbon, Escape focuses the ribbon, and Shift+Tab leaves the editing area. Arrow keys move between ribbon tabs. On touch screens, tap to place the caret, hold to select a word, and drag the selection endpoints. Narrow ribbons scroll horizontally. Mounted pages expose text and headings to browser accessibility tools, including pages whose canvases have been evicted.
|
|
187
201
|
|
|
188
202
|
Each instance has isolated styles and history. Customize `--onodocs-color`, `--onodocs-background`, `--onodocs-toolbar-background`, `--onodocs-accent` and `--onodocs-selection` on the host container. The `toolbar`, `pages` and `status` shadow parts are available for host styling. Call `dispose()` when removing an editor.
|
|
189
203
|
|
|
@@ -221,7 +235,7 @@ input.name = "customerName";
|
|
|
221
235
|
const attachment = view.attach(input, { anchor: doc.geometry.fragments(field)[0] });
|
|
222
236
|
```
|
|
223
237
|
|
|
224
|
-
The example requires a tagged control that produces one visible fragment. Call `doc.geometry.fragments(field)` for content spanning lines, pages, or repeated stories, and attach to an explicitly chosen fragment. Fragments retain transforms and clipping. Table/cell anchors use their final physical rectangles. `offset` and `size` optionally adjust attachment placement in page units. Values, validation, submission, focus, and accessibility labels belong to the application. Attaching an element moves it into the view. Detachment removes it and restores its original inline style. Reattaching the same HTML element disposes its previous attachment; old handles become inert. An attachment exposes its disposed state.
|
|
238
|
+
The example requires a tagged control that produces one visible fragment. Call `doc.geometry.fragments(field)` for content spanning lines, pages, or repeated stories, and attach to an explicitly chosen fragment. Fragments retain transforms and clipping. Table/cell anchors use their final physical rectangles. `offset` and `size` optionally adjust attachment placement in page units. Use `interactive: false` for decorative overlays so clicks reach the document underneath. Values, validation, submission, focus, and accessibility labels belong to the application. Attaching an element moves it into the view. Detachment removes it and restores its original inline style. Reattaching the same HTML element disposes its previous attachment; old handles become inert. An attachment exposes its disposed state.
|
|
225
239
|
|
|
226
240
|
Pages are anchors too. Placement avoids manual rectangle arithmetic:
|
|
227
241
|
|
|
@@ -383,6 +397,8 @@ Open with `revisionView: "accepted"` when editing current text. `readReview()` i
|
|
|
383
397
|
|
|
384
398
|
Enable the editor panel with `review: { identity: () => identity, history }`. The optional `history` object implements `list(signal)`, `load(id, signal)` and `save(version, bytes, signal)`. Your application stores the complete Word bytes and version metadata. The SDK adds no persistence service or user account system. Restoring a version is undoable and raises the editor's change event, so application autosave can persist it. `compareDocuments(savedBytes, doc)` returns paragraph text and formatting differences without modifying the document.
|
|
385
399
|
|
|
400
|
+
Browser and server opening options accept `commentDisplay: "hidden"` to hide comment indicators in rendered pages and PDF exports. Comments remain available through `readReview()` and in saved Word files. The editor uses this display by default and shows comments in its Review pane. Set `document: { commentDisplay: "markers" }` to display indicators in the editor; SDK rendering defaults to markers.
|
|
401
|
+
|
|
386
402
|
## Searchable PDF in the browser
|
|
387
403
|
|
|
388
404
|
```js
|
|
@@ -405,3 +421,5 @@ try {
|
|
|
405
421
|
PDF export runs locally and uses the same implementation as server `doc.pdf()`. It waits for earlier edits to finish. Pass `signal` to cancel an export without closing the document. The PDF writer loads on demand; deploy the browser entry's generated chunks alongside it. Text extraction order for bidirectional paragraphs and selection across complex clusters depend on the PDF reader. Solid graphics use vector PDF paths where supported. Native text and complex effects retain browser rendering in cropped lossless image layers, including evaluation marks. Higher DPI increases the sharpness, file size and temporary memory use of those layers; compressed output remains in memory until export finishes.
|
|
406
422
|
|
|
407
423
|
The PDF includes tagged headings, paragraphs, nested lists, tables, header cells, merged-cell row/column spans, authored figure descriptions and links, plus heading and bookmark navigation. Set `title` and `language` for reader metadata. DrawingML descriptions use `wp:docPr/@descr`, falling back to `title`; VML uses authored `alt` text. Undescribed graphics remain artifacts. Reader support varies. Firefox PDF.js exposes named images, list nesting and table spans in its accessibility tree. This does not claim PDF/UA conformance or validation with every screen reader.
|
|
424
|
+
|
|
425
|
+
One named-application license covers SDK and Canvas, including the application's backend and self-hosted collaboration. Finished editors for end users are included. Editor source is separately licensed under MIT. See [application scope, output rights and redistribution terms](licensing.md).
|
package/agreement-review.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Agreement review
|
|
2
2
|
|
|
3
|
-
Run `npm run build`, then `npm run example:agreement-review` and open the printed local address. From an installed
|
|
3
|
+
Run `npm run build`, then `npm run example:agreement-review` and open the printed local address. From an installed Editor package, install `esbuild` alongside `@onodocs/editor` and run `node node_modules/@onodocs/editor/examples/agreement-review/serve.mjs`.
|
|
4
4
|
|
|
5
5
|
Choose a clause and add a comment in the review panel. Switch reviewer identity to reply as the other fictional party. Select Suggest wording, edit the clause, and submit. The review panel shows the deletion and insertion separately. Accept all or Reject all decides the entire replacement; individual buttons decide one revision at a time. Compare with original shows the current text against the original agreement.
|
|
6
6
|
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
The session accepts the editor's [document modes](document-modes.md). A mode change preserves session revision and dirty state; edits, review actions and filled answers use the same committed-change and autosave path.
|
|
4
4
|
|
|
5
|
-
`@onodocs/
|
|
5
|
+
`@onodocs/editor/application` embeds the existing Word editor with application saving and recovery. Use matching SDK and Canvas packages built with these entry points. Older published packages do not include them.
|
|
6
6
|
|
|
7
7
|
```js
|
|
8
|
-
import { openApplicationEditor } from "@onodocs/
|
|
8
|
+
import { openApplicationEditor } from "@onodocs/editor/application";
|
|
9
9
|
import { recoveryStore } from "./recovery.js";
|
|
10
10
|
|
|
11
11
|
const application = await openApplicationEditor({
|
|
@@ -59,7 +59,7 @@ Abort source fetching when unmounting. Do not invoke mounting during SSR. The he
|
|
|
59
59
|
|
|
60
60
|
`@onodocs/sdk/http` exports `createHttpService({ renderer, authorize, document?, onError? })`. It wraps the existing server renderer and backend-viewer manifest/page contract. Authorization returns a stable application-controlled principal string or undefined. Every request authenticates; each document belongs to its principal. Call service.handle from a Node HTTP listener. Stop requests, await service.dispose, then dispose the renderer. TypeScript backends should install @types/node and include node in their compiler types.
|
|
61
61
|
|
|
62
|
-
Run `npm run build`, set `ONODOCS_SERVICE_TOKEN`, then run `npm run example:http`. The sample in `examples/http-service/server.mjs` defaults to loopback port 5191 and Chrome. HOST, PORT, CHROMIUM_PATH and ONODOCS_LICENSE_KEY configure it. Keep its bearer credential on the backend. Browsers should use an application-owned authenticated gateway. For installed-package use,
|
|
62
|
+
Run `npm run build`, set `ONODOCS_SERVICE_TOKEN`, then run `npm run example:http`. The sample in `examples/http-service/server.mjs` defaults to loopback port 5191 and Chrome. HOST, PORT, CHROMIUM_PATH and ONODOCS_LICENSE_KEY configure it. Keep its bearer credential on the backend. Browsers should use an application-owned authenticated gateway. For installed-package use, install `@onodocs/sdk playwright-core` and run `node node_modules/@onodocs/sdk/examples/http-service/server.mjs`.
|
|
63
63
|
|
|
64
64
|
| Request | Response |
|
|
65
65
|
| --- | --- |
|
|
@@ -85,3 +85,5 @@ These clients upload, export and delete. They use ONODOCS_SERVICE_TOKEN and opti
|
|
|
85
85
|
Deploy behind your application's TLS proxy on a private interface using an unprivileged account. Install Node, Chromium and the required fonts; keep browser sandbox support enabled. Use a supervisor that sends SIGTERM and permits cleanup. Inject secrets through its protected environment. Verify an authenticated upload/export/delete after startup to check browser and font availability. This work supplies deployment code and guidance without publishing or changing a production deployment.
|
|
86
86
|
|
|
87
87
|
Browser builds must deploy generated lazy PDF chunks alongside the entry bundle. Serve over HTTPS with a content security policy that permits required font/image sources and Blob/data resources. Authentication, durable storage, draft retention and backups remain application-owned.
|
|
88
|
+
|
|
89
|
+
Install `@onodocs/sdk playwright-core` for server rendering and the HTTP service example. Browser editor sessions use `@onodocs/editor/application` and do not require Playwright.
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# Shared document sessions
|
|
2
2
|
|
|
3
|
-
Use `@onodocs/sdk/collaboration` for a customer-hosted shared document service and `@onodocs/
|
|
3
|
+
Use `@onodocs/sdk/collaboration` for a customer-hosted shared document service and `@onodocs/editor/collaboration` for the browser editor. Collaboration is optional. Ordinary browser editing and rendering need neither entry point nor a network service.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
import { createCollaborationService } from "@onodocs/sdk/collaboration";
|
|
7
7
|
|
|
8
8
|
const service = createCollaborationService({
|
|
9
|
+
licenseKey,
|
|
9
10
|
authorize: async (documentId, requestContext) => {
|
|
10
11
|
const user = await authenticate(requestContext);
|
|
11
12
|
return await documentPermission(documentId, user);
|
|
@@ -29,9 +30,10 @@ import {
|
|
|
29
30
|
openCollaborativeEditor,
|
|
30
31
|
createCollaborationTransport,
|
|
31
32
|
createCollaborationRecovery,
|
|
32
|
-
} from "@onodocs/
|
|
33
|
+
} from "@onodocs/editor/collaboration";
|
|
33
34
|
|
|
34
35
|
const session = await openCollaborativeEditor({
|
|
36
|
+
editor: { document: { licenseKey } },
|
|
35
37
|
container: document.querySelector("main")!,
|
|
36
38
|
exchange: createCollaborationTransport("/documents/brief/collaboration"),
|
|
37
39
|
recovery: createCollaborationRecovery(`${documentId}:${userId}:${tabId}`),
|
|
@@ -48,3 +50,5 @@ Synchronization clears local snapshot undo history at each shared checkpoint. Ot
|
|
|
48
50
|
Use the collaboration composition's editor for authoring. Direct mutations through `editor.document` bypass its journal and are trusted host operations. Opening another document through that editor is also a host lifecycle operation, not a shared replacement; close the session and open the other document's session instead. `WordEditor.synchronize` runs a host callback within the editor queue. Return `{bytes, allowedModes}` to publish a new checkpoint. Never call another queued editor operation from that callback or from an awaited `onChange`; use the underlying document's `save()` when capturing bytes.
|
|
49
51
|
|
|
50
52
|
Run `npm run example:collaboration` after building. Open `http://127.0.0.1:5195/?user=alex` and `?user=sam` in separate browser profiles, or `?user=jo` for review-only access. The sample uses fixed demo identities, loopback HTTP and a local SQLite database under the user's temporary OnoDocs directory. Replace its identity picker with customer authentication for production. Run `npm run validate:collaboration` for the independent browser feature suite.
|
|
53
|
+
|
|
54
|
+
Configure the application license on both the service and browser editor as shown above. Self-hosted collaboration is included in the same named-application scope. Omitting a key preserves non-production evaluation behavior. See [licensing](licensing.md).
|
package/document-forms.md
CHANGED
|
@@ -38,7 +38,7 @@ Blank answers are `null`. Each field requires a distinct `id` and `tag`, a `labe
|
|
|
38
38
|
## Browser filling and authoring
|
|
39
39
|
|
|
40
40
|
```js
|
|
41
|
-
import { openForm, createFormDesigner } from "@onodocs/
|
|
41
|
+
import { openForm, createFormDesigner } from "@onodocs/editor/forms";
|
|
42
42
|
|
|
43
43
|
const view = await openForm({
|
|
44
44
|
container, input: templateBytes, definition,
|
|
@@ -56,7 +56,7 @@ view.dispose();
|
|
|
56
56
|
|
|
57
57
|
The designer writes native Word content controls with a protected container and editable contents. These controls remain readable in Word. The form's type rules and read-only policy belong to the host definition. They are not document encryption or a tamper-proof restriction in external editors. Applications accepting submissions should use their trusted definition and enforce their own authorization and validation.
|
|
58
58
|
|
|
59
|
-
Run `npm run build` followed by `npm run example:forms` for the equipment-request example at localhost port 5192. It supports template and definition downloads, browser-local drafts, and completed DOCX plus answers JSON downloads.
|
|
59
|
+
Run `npm run build` followed by `npm run example:forms` for the equipment-request example at localhost port 5192. It supports template and definition downloads, browser-local drafts, and completed DOCX plus answers JSON downloads. The Editor package includes the form example and its shared recovery helper; install `@onodocs/editor esbuild` and run `node node_modules/@onodocs/editor/examples/document-forms/serve.mjs`. No hosted service is required.
|
|
60
60
|
|
|
61
61
|
## Try the equipment-request workflow
|
|
62
62
|
|
|
@@ -72,11 +72,11 @@ Drafts use the shared IndexedDB recovery example. The storage key includes a dig
|
|
|
72
72
|
|
|
73
73
|
Open **Developer tools & template authoring** to edit the template, import a Word document and matching definition, or download both source files. Authoring intentionally permits document changes; the filling preview only permits the defined answers. Field changes create a separate draft identity. This panel is an evaluation tool, not a user authorization boundary.
|
|
74
74
|
|
|
75
|
-
To run the shipped example directly from an installed
|
|
75
|
+
To run the shipped example directly from an installed Editor package:
|
|
76
76
|
|
|
77
77
|
```powershell
|
|
78
|
-
npm install @onodocs/
|
|
79
|
-
node node_modules/@onodocs/
|
|
78
|
+
npm install @onodocs/editor esbuild
|
|
79
|
+
node node_modules/@onodocs/editor/examples/document-forms/serve.mjs
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
Evaluation mode adds a watermark. For licensed use, provide the license key in the `document` options passed to both `openForm` and `createFormDesigner`, following the SDK licensing guide.
|
package/document-modes.md
CHANGED
|
@@ -12,7 +12,7 @@ Configure `createEditor` or `openApplicationEditor` with `mode` and `allowedMode
|
|
|
12
12
|
Save and PDF export are available in every mode. Review mode requires `review` options, including the host's reviewer identity callback. Form mode requires a `FormDefinition`. [Document forms](document-forms.md) describes field rules and answer types. [Application integration](application-integration.md) describes saving, recovery and host lifecycle.
|
|
13
13
|
|
|
14
14
|
```js
|
|
15
|
-
import { openApplicationEditor } from "@onodocs/
|
|
15
|
+
import { openApplicationEditor } from "@onodocs/editor/application";
|
|
16
16
|
|
|
17
17
|
const application = await openApplicationEditor({
|
|
18
18
|
container, input: bytes,
|
|
@@ -41,4 +41,4 @@ History is retained across modes. Viewing cannot undo or redo. Form and review m
|
|
|
41
41
|
|
|
42
42
|
Derive the allowed modes from your application's permissions. This is an interface and editor-operation policy, not application authorization, file encryption or a restriction on external Word editors. The low-level `editor.document` API remains available to trusted application code and is not filtered by editor mode. The host must authorize storage, review identity, history and submissions. If permissions change, preserve permitted draft work and create a session with the new allowed modes; merely switching to viewing does not revoke modes already offered by that session.
|
|
43
43
|
|
|
44
|
-
Run `npm run build` and `npm run example:modes` for the local four-mode request at port 5196. Its Save draft stores bytes only in memory for the current session. The
|
|
44
|
+
Run `npm run build` and `npm run example:modes` for the local four-mode request at port 5196. Its Save draft stores bytes only in memory for the current session. The Editor package includes the mode example and its shared form assets. Install `@onodocs/editor esbuild`, then run `node node_modules/@onodocs/editor/examples/document-modes/serve.mjs`.
|
package/editor.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# OnoDocs Editor
|
|
2
|
+
|
|
3
|
+
`@onodocs/editor` provides the browser editor, template and form authoring, review controls, application sessions and collaborative editing UI. It uses the public document operations in `@onodocs/sdk` and presentation in `@onodocs/canvas`. Installing Editor installs matching SDK and Canvas versions. OnoDocs-authored Editor code is licensed under MIT, including its UI, application sessions, forms, templates and collaboration client. You may modify and redistribute that code, including in commercial products, while preserving the MIT notice and applicable third-party notices. SDK and Canvas remain separately commercially licensed; their production use requires covered application scope. Editor has no separate entitlement or purchase.
|
|
4
|
+
|
|
5
|
+
The [editor source](https://github.com/onodocs/onodocs/tree/main/packages/editor) and runnable examples are maintained in the public OnoDocs repository. MIT permission for the editor does not grant production or redistribution rights in its SDK and Canvas dependencies.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @onodocs/editor
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import { createEditor } from "@onodocs/editor";
|
|
13
|
+
|
|
14
|
+
const editor = createEditor({ container, document: { licenseKey } });
|
|
15
|
+
await editor.open(bytes);
|
|
16
|
+
const saved = await editor.save();
|
|
17
|
+
editor.dispose();
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Use `createTemplateEditor` from the same entry for template authoring. `@onodocs/editor/application` provides autosave, recovery and host lifecycle. `@onodocs/editor/forms` provides controlled form filling and the form designer. `@onodocs/editor/collaboration` provides the collaborative editor, browser recovery and transport client. The host supplies authentication, persistence and collaboration service endpoints.
|
|
21
|
+
|
|
22
|
+
`createFormDesigner` includes a Forms tab for adding fields and opening their sidebar settings. Supply `onPreview(designer)` and `onExportProject(designer)` to expose your host's preview and project-export actions there. Both callbacks can call `designer.save()` to obtain matching Word bytes and field rules. Set `ribbon: false` to keep only the standard editor tabs and field sidebar. The complete document-forms example connects these actions to its existing fill and ZIP export workflows.
|
|
23
|
+
|
|
24
|
+
The installed package includes complete browser-editor, template-editor, proposal, form, agreement-review, document-mode and collaboration examples. Install `esbuild`, then run `node node_modules/@onodocs/editor/examples/browser-editor/serve.mjs` to start the standalone editor. See the SDK guide and the included workflow guides for supported document operations and limitations.
|
|
25
|
+
|
|
26
|
+
## Migration from 0.4
|
|
27
|
+
|
|
28
|
+
| Previous import | Current import |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| `@onodocs/sdk/editor` | `@onodocs/editor` |
|
|
31
|
+
| `@onodocs/sdk/application` | `@onodocs/editor/application` |
|
|
32
|
+
| `@onodocs/sdk/forms/browser` | `@onodocs/editor/forms` |
|
|
33
|
+
| `@onodocs/sdk/collaboration/browser` | `@onodocs/editor/collaboration` |
|
|
34
|
+
|
|
35
|
+
Function names and supported behavior remain the same. The previous SDK entry points are removed. Document operations stay in `@onodocs/sdk`, `/browser` and `/server`. Form definitions, answers and validation stay in `@onodocs/sdk/forms`; the collaboration service and protocol stay in `@onodocs/sdk/collaboration`. HTTP integration stays in `@onodocs/sdk/http`. Canvas imports remain unchanged.
|
|
36
|
+
|
|
37
|
+
For backend rendering, install `@onodocs/sdk playwright-core` and provide a Chromium-family browser. Playwright is an optional SDK peer dependency; browser and data-only installations do not need it. The server adapter, HTTP service, form data operations and collaboration service have independent entry points and do not load the editor UI.
|
|
38
|
+
|
|
39
|
+
One named-application license covers commercial SDK and Canvas use, including the application's backend and self-hosted collaboration. Finished editors for end users are included. Editor source remains available under MIT. See [application scope, output rights and redistribution terms](licensing.md).
|
package/index.js
CHANGED
|
@@ -2365,7 +2365,7 @@ function mountDocument(document2, container, options = {}, onDispose) {
|
|
|
2365
2365
|
const [anchorX, anchorY, elementX, elementY] = placementPoints[options2.placement ?? "overlay"];
|
|
2366
2366
|
const x = r.x + anchorX * r.width - elementX * size.width + (1 - 2 * anchorX) * inset + (anchorX - elementX) * gap2 + (options2.offset?.x ?? 0);
|
|
2367
2367
|
const y = r.y + anchorY * r.height - elementY * size.height + (1 - 2 * anchorY) * inset + (anchorY - elementY) * gap2 + (options2.offset?.y ?? 0);
|
|
2368
|
-
Object.assign(box.style, { position: "absolute", left: "0", top: "0", width: `${size.width * cssScale}px`, height: `${size.height * cssScale}px`, transformOrigin: "0 0", transform: `matrix(${t.a},${t.b},${t.c},${t.d},${(t.a * x + t.c * y + t.e) * cssScale},${(t.b * x + t.d * y + t.f) * cssScale})`, pointerEvents: "auto" });
|
|
2368
|
+
Object.assign(box.style, { position: "absolute", left: "0", top: "0", width: `${size.width * cssScale}px`, height: `${size.height * cssScale}px`, transformOrigin: "0 0", transform: `matrix(${t.a},${t.b},${t.c},${t.d},${(t.a * x + t.c * y + t.e) * cssScale},${(t.b * x + t.d * y + t.f) * cssScale})`, pointerEvents: options2.interactive === false ? "none" : "auto" });
|
|
2369
2369
|
attachedElements.get(node)?.dispose();
|
|
2370
2370
|
const oldStyle = node.getAttribute("style");
|
|
2371
2371
|
Object.assign(node.style, { width: "100%", height: "100%", boxSizing: "border-box", margin: "0" });
|
|
@@ -2546,7 +2546,11 @@ function createDocument(source, options = {}) {
|
|
|
2546
2546
|
const lifetime = new AbortController();
|
|
2547
2547
|
const views = /* @__PURE__ */ new Set();
|
|
2548
2548
|
const faces = /* @__PURE__ */ new Map();
|
|
2549
|
-
const
|
|
2549
|
+
const fontCleanup = /* @__PURE__ */ new Set();
|
|
2550
|
+
const fontFinalizer = new FinalizationRegistry((close) => {
|
|
2551
|
+
close();
|
|
2552
|
+
fontCleanup.delete(close);
|
|
2553
|
+
});
|
|
2550
2554
|
let pages = [];
|
|
2551
2555
|
let disposed = false;
|
|
2552
2556
|
let mounted;
|
|
@@ -2569,6 +2573,9 @@ function createDocument(source, options = {}) {
|
|
|
2569
2573
|
},
|
|
2570
2574
|
refresh() {
|
|
2571
2575
|
checkOpen();
|
|
2576
|
+
const fonts = createFontResources(faces, checkOpen);
|
|
2577
|
+
fontCleanup.add(fonts.dispose);
|
|
2578
|
+
fontFinalizer.register(fonts, fonts.dispose);
|
|
2572
2579
|
pages = source.pages.map((page) => ({ index: page.index, size: page.size, get interaction() {
|
|
2573
2580
|
return page.interaction;
|
|
2574
2581
|
}, async render(canvas, options2 = {}) {
|
|
@@ -2579,7 +2586,7 @@ function createDocument(source, options = {}) {
|
|
|
2579
2586
|
if (!Number.isFinite(dpi) || dpi <= 0) throw new RangeError("dpi must be positive and finite.");
|
|
2580
2587
|
const data = await page.load(signal);
|
|
2581
2588
|
signal.throwIfAborted();
|
|
2582
|
-
await Promise.all((data.fonts ?? []).map(
|
|
2589
|
+
await Promise.all((data.fonts ?? []).map((resource) => fonts.load(resource)));
|
|
2583
2590
|
signal.throwIfAborted();
|
|
2584
2591
|
const images = data.images && await materializeImageResources(data.images, signal);
|
|
2585
2592
|
try {
|
|
@@ -2608,10 +2615,9 @@ function createDocument(source, options = {}) {
|
|
|
2608
2615
|
lifetime.abort();
|
|
2609
2616
|
unsubscribe?.();
|
|
2610
2617
|
for (const view of views) view.dispose();
|
|
2611
|
-
for (const
|
|
2618
|
+
for (const close of fontCleanup) close();
|
|
2612
2619
|
views.clear();
|
|
2613
|
-
|
|
2614
|
-
faces.clear();
|
|
2620
|
+
fontCleanup.clear();
|
|
2615
2621
|
}
|
|
2616
2622
|
};
|
|
2617
2623
|
unsubscribe = source.subscribe?.(() => source.disposed ? result.dispose() : result.refresh());
|
|
@@ -2627,24 +2633,52 @@ function createDocument(source, options = {}) {
|
|
|
2627
2633
|
if (disposed || source.disposed) throw new Error("Canvas document is disposed.");
|
|
2628
2634
|
}
|
|
2629
2635
|
__name(checkOpen, "checkOpen");
|
|
2630
|
-
|
|
2636
|
+
}
|
|
2637
|
+
__name(createDocument, "createDocument");
|
|
2638
|
+
function createFontResources(faces, checkOpen) {
|
|
2639
|
+
const acquired = /* @__PURE__ */ new Map();
|
|
2640
|
+
let disposed = false;
|
|
2641
|
+
function load(resource) {
|
|
2642
|
+
checkOpen();
|
|
2643
|
+
if (disposed) return Promise.reject(new Error("Canvas font resources are disposed."));
|
|
2631
2644
|
const key = JSON.stringify([resource.family, resource.descriptors]);
|
|
2632
|
-
let
|
|
2633
|
-
if (!
|
|
2645
|
+
let entry = faces.get(key);
|
|
2646
|
+
if (!entry) {
|
|
2634
2647
|
const face = new FontFace(resource.family, typeof resource.source === "string" ? resource.source : resource.source.slice().buffer, resource.descriptors);
|
|
2635
|
-
pending = face.load().then(() => {
|
|
2648
|
+
const pending = { face, users: 0, ready: face.load().then(() => {
|
|
2636
2649
|
checkOpen();
|
|
2637
|
-
document.fonts.add(face);
|
|
2638
|
-
|
|
2639
|
-
});
|
|
2650
|
+
if (pending.users) document.fonts.add(face);
|
|
2651
|
+
}) };
|
|
2640
2652
|
faces.set(key, pending);
|
|
2641
|
-
|
|
2653
|
+
entry = pending;
|
|
2654
|
+
void pending.ready.catch(() => {
|
|
2655
|
+
if (faces.get(key) === pending) faces.delete(key);
|
|
2656
|
+
});
|
|
2657
|
+
}
|
|
2658
|
+
const previous = acquired.get(key);
|
|
2659
|
+
if (previous !== entry) {
|
|
2660
|
+
if (previous) release(key, previous);
|
|
2661
|
+
acquired.set(key, entry);
|
|
2662
|
+
entry.users++;
|
|
2642
2663
|
}
|
|
2643
|
-
return
|
|
2664
|
+
return entry.ready;
|
|
2644
2665
|
}
|
|
2645
|
-
__name(
|
|
2666
|
+
__name(load, "load");
|
|
2667
|
+
function release(key, entry) {
|
|
2668
|
+
if (--entry.users === 0) {
|
|
2669
|
+
document.fonts.delete(entry.face);
|
|
2670
|
+
if (faces.get(key) === entry) faces.delete(key);
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2673
|
+
__name(release, "release");
|
|
2674
|
+
return { load, dispose() {
|
|
2675
|
+
if (disposed) return;
|
|
2676
|
+
disposed = true;
|
|
2677
|
+
for (const [key, entry] of acquired) release(key, entry);
|
|
2678
|
+
acquired.clear();
|
|
2679
|
+
} };
|
|
2646
2680
|
}
|
|
2647
|
-
__name(
|
|
2681
|
+
__name(createFontResources, "createFontResources");
|
|
2648
2682
|
async function openDocument(url, options = {}) {
|
|
2649
2683
|
const endpoint = new URL(url, document.baseURI);
|
|
2650
2684
|
const manifest = await load(endpoint, options.signal);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onodocs/canvas",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "OnoDocs canvas viewer, selection and HTML attachments for prepared Word document pages.",
|
|
6
6
|
"homepage": "https://onodocs.com/developers/",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"types",
|
|
34
34
|
"README.md",
|
|
35
35
|
"SDK.md",
|
|
36
|
+
"editor.md",
|
|
36
37
|
"templates.md",
|
|
37
38
|
"proposal.md",
|
|
38
39
|
"agreement-review.md",
|
|
@@ -48,5 +49,5 @@
|
|
|
48
49
|
"type": "git",
|
|
49
50
|
"url": "https://github.com/onodocs/onodocs.git"
|
|
50
51
|
},
|
|
51
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "a4043b6b334e0090f9cc2439d74120357a59aa76"
|
|
52
53
|
}
|
package/proposal.md
CHANGED
|
@@ -11,14 +11,14 @@ npm run example:proposal
|
|
|
11
11
|
|
|
12
12
|
Open `http://127.0.0.1:5196`. Use `PORT` to choose another local port.
|
|
13
13
|
|
|
14
|
-
## Run from an installed
|
|
14
|
+
## Run from an installed Editor
|
|
15
15
|
|
|
16
16
|
```powershell
|
|
17
|
-
npm install @onodocs/
|
|
18
|
-
node node_modules/@onodocs/
|
|
17
|
+
npm install @onodocs/editor esbuild
|
|
18
|
+
node node_modules/@onodocs/editor/examples/proposal/serve.mjs
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
The
|
|
21
|
+
The Editor package includes the HTML, CSS, JavaScript and reusable `sample.docx`. Evaluation mode adds a watermark. For licensed use, pass your license key in the browser options supplied to both `openTemplate` and `createEditor` in `main.js`, following the SDK licensing guide.
|
|
22
22
|
|
|
23
23
|
## Try the workflow
|
|
24
24
|
|
package/templates.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Word templates and document generation
|
|
2
2
|
|
|
3
|
-
Use `createTemplateEditor` from `@onodocs/
|
|
3
|
+
Use `createTemplateEditor` from `@onodocs/editor` to design reusable DOCX templates. Run `npm run example:templates` in the source workspace for the invoice example at localhost port 5193. The designer uses the ordinary Word editor for layout, formatting and generated-document adjustments.
|
|
4
4
|
|
|
5
5
|
For a complete business-data-to-export journey, run `npm run example:proposal`. The [proposal studio guide](proposal.md) covers setup, repeating fee rows, wording edits and Word/PDF downloads.
|
|
6
6
|
|
|
7
7
|
```ts
|
|
8
|
-
import { createTemplateEditor } from "@onodocs/
|
|
8
|
+
import { createTemplateEditor } from "@onodocs/editor";
|
|
9
9
|
|
|
10
10
|
const designer = createTemplateEditor({
|
|
11
11
|
container: document.querySelector("#templates"),
|
|
@@ -64,7 +64,7 @@ The command supports `selection`, `paragraph`, `row` and `table` scopes. Inline
|
|
|
64
64
|
| `section` | `name` | Reusable content definition, omitted from output |
|
|
65
65
|
| `include` | `name`, optional `path` | Section inserted with the current context or selected subrecord |
|
|
66
66
|
|
|
67
|
-
Paths are arrays of own-property names, not executable expressions. An empty path selects the current record. Missing data, wrong value types and recursive sections report an error. Currency options are ordinary `Intl.NumberFormatOptions`, for example `{ style: "currency", currency: "USD" }`. Date values can be a `Date`, timestamp or ISO date string; use an explicit offset for timestamps. The default locale is `en-US` and the default date time zone is UTC.
|
|
67
|
+
Paths are arrays of own-property names, not executable expressions. An empty path selects the current record. Missing data, wrong value types and recursive sections report an error. Currency options are ordinary `Intl.NumberFormatOptions`, for example `{ style: "currency", currency: "USD" }`. Date values can be a `Date`, timestamp or ISO date string; use an explicit offset for timestamps. Formatting uses JavaScript `Date` conversion and rejects invalid timestamps. It does not strictly validate calendar strings: for example, `2026-02-30` converts to 2 March 2026. Validate calendar dates in the host application if strict rejection is required. The default locale is `en-US` and the default date time zone is UTC.
|
|
68
68
|
|
|
69
69
|
Formatting comes from the first run of a text placeholder. Unrelated Word content and package resources are preserved. Generation refreshes supported sequence and bookmark-reference fields. The browser template API also lays out the generated document to refresh page numbers, page references and supported tables of contents. Node callers can supply a `finalize` callback that opens the generated bytes with the server renderer and returns `document.save(options)`.
|
|
70
70
|
|
|
@@ -7,6 +7,10 @@ import type { GeometryPathOperation } from "../foundation/index.js";
|
|
|
7
7
|
/** Spec: spec/document/body/drawing/vml/gradient-fills.md */
|
|
8
8
|
/** Spec: `spec/pipeline/render/page-display-list/_index.md`; `spec/pipeline/render/page-display-list/positioned-text/shading.md#positioned-text-shading-compilation`; `spec/pipeline/render/page-display-list/positioned-text/highlight.md#highlight-command-compilation`; `spec/pipeline/render/page-display-list/positioned-text/decoration.md#strike-command-compilation`. */
|
|
9
9
|
import type { RasterColorEffectPlan, RasterSourceRectangle, VectorShapeFill, VectorShapePath } from "../foundation/index.js";
|
|
10
|
+
/** Spec: pipeline.render.page-display-list.comment-projection */
|
|
11
|
+
export interface PageDisplayListOptions {
|
|
12
|
+
readonly commentDisplay?: "markers" | "hidden";
|
|
13
|
+
}
|
|
10
14
|
export interface PaintRectangle {
|
|
11
15
|
readonly x: bigint;
|
|
12
16
|
readonly y: bigint;
|