@pixerate/editor 0.21.0 → 0.22.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.
Files changed (70) hide show
  1. package/README.md +20 -11
  2. package/dist/agent/index.cjs +8 -8
  3. package/dist/agent/index.d.cts +2 -2
  4. package/dist/agent/index.d.ts +2 -2
  5. package/dist/agent/index.js +2 -2
  6. package/dist/canvas/index.cjs +1269 -13
  7. package/dist/canvas/index.cjs.map +1 -1
  8. package/dist/canvas/index.d.cts +432 -6
  9. package/dist/canvas/index.d.ts +432 -6
  10. package/dist/canvas/index.js +1264 -8
  11. package/dist/canvas/index.js.map +1 -1
  12. package/dist/{chunk-U6NDQFOK.cjs → chunk-6M3BCTBD.cjs} +427 -138
  13. package/dist/chunk-6M3BCTBD.cjs.map +1 -0
  14. package/dist/{chunk-TVRC4KVT.cjs → chunk-AA4ZEVCC.cjs} +845 -90
  15. package/dist/chunk-AA4ZEVCC.cjs.map +1 -0
  16. package/dist/{chunk-LA7PEGU3.cjs → chunk-CL37JGFW.cjs} +4 -4
  17. package/dist/{chunk-LA7PEGU3.cjs.map → chunk-CL37JGFW.cjs.map} +1 -1
  18. package/dist/{chunk-A7DKIA72.js → chunk-DENSCKFC.js} +642 -69
  19. package/dist/chunk-DENSCKFC.js.map +1 -0
  20. package/dist/{chunk-4QPLEUL2.cjs → chunk-GVSMRPHB.cjs} +1046 -54
  21. package/dist/chunk-GVSMRPHB.cjs.map +1 -0
  22. package/dist/{chunk-KYRZDWM4.js → chunk-JJDLPEWL.js} +2 -2
  23. package/dist/{chunk-3TYMNULT.js → chunk-MJZBNWG7.js} +807 -52
  24. package/dist/chunk-MJZBNWG7.js.map +1 -0
  25. package/dist/{chunk-CYFJCKC4.js → chunk-QGHGJ56O.js} +997 -5
  26. package/dist/chunk-QGHGJ56O.js.map +1 -0
  27. package/dist/{chunk-GVW4P7BG.js → chunk-RU52I7QO.js} +305 -16
  28. package/dist/chunk-RU52I7QO.js.map +1 -0
  29. package/dist/{chunk-JYRIOFEN.cjs → chunk-SAZRENEZ.cjs} +647 -74
  30. package/dist/chunk-SAZRENEZ.cjs.map +1 -0
  31. package/dist/{controller-OUdxPY-X.d.ts → controller-B7GIybc4.d.cts} +139 -7
  32. package/dist/{controller-OUdxPY-X.d.cts → controller-B7GIybc4.d.ts} +139 -7
  33. package/dist/extensions/index.cjs +14 -4
  34. package/dist/extensions/index.cjs.map +1 -1
  35. package/dist/extensions/index.d.cts +3 -3
  36. package/dist/extensions/index.d.ts +3 -3
  37. package/dist/extensions/index.js +13 -3
  38. package/dist/{index-k3mFbPx_.d.cts → index-CCr_z9kF.d.cts} +3 -3
  39. package/dist/{index-Ng1pG7JE.d.ts → index-Ck6ajwXh.d.ts} +3 -3
  40. package/dist/index.cjs +250 -16
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.cts +294 -8
  43. package/dist/index.d.ts +294 -8
  44. package/dist/index.js +241 -7
  45. package/dist/index.js.map +1 -1
  46. package/dist/{registry-iAHbqkYt.d.cts → registry-GJI4gToU.d.cts} +15 -4
  47. package/dist/{registry-iAHbqkYt.d.ts → registry-GJI4gToU.d.ts} +15 -4
  48. package/dist/serializers/index.cjs +3 -3
  49. package/dist/serializers/index.d.cts +1 -1
  50. package/dist/serializers/index.d.ts +1 -1
  51. package/dist/serializers/index.js +2 -2
  52. package/dist/spreadsheet/index.cjs +7 -3
  53. package/dist/spreadsheet/index.cjs.map +1 -1
  54. package/dist/spreadsheet/index.d.cts +33 -4
  55. package/dist/spreadsheet/index.d.ts +33 -4
  56. package/dist/spreadsheet/index.js +6 -2
  57. package/dist/{track-changes-G8JcWB8b.d.cts → track-changes-BSF58RK0.d.cts} +92 -9
  58. package/dist/{track-changes-G8JcWB8b.d.ts → track-changes-BSF58RK0.d.ts} +92 -9
  59. package/dist/{types-DMe0vFB1.d.cts → types-CJ4U-HHI.d.cts} +1 -1
  60. package/dist/{types-DMe0vFB1.d.ts → types-CJ4U-HHI.d.ts} +1 -1
  61. package/package.json +1 -1
  62. package/dist/chunk-3TYMNULT.js.map +0 -1
  63. package/dist/chunk-4QPLEUL2.cjs.map +0 -1
  64. package/dist/chunk-A7DKIA72.js.map +0 -1
  65. package/dist/chunk-CYFJCKC4.js.map +0 -1
  66. package/dist/chunk-GVW4P7BG.js.map +0 -1
  67. package/dist/chunk-JYRIOFEN.cjs.map +0 -1
  68. package/dist/chunk-TVRC4KVT.cjs.map +0 -1
  69. package/dist/chunk-U6NDQFOK.cjs.map +0 -1
  70. /package/dist/{chunk-KYRZDWM4.js.map → chunk-JJDLPEWL.js.map} +0 -0
package/README.md CHANGED
@@ -108,18 +108,20 @@ editor.commands.resolveComment(id); // also deleteComment, setActiveComment, foc
108
108
  store.subscribe((snapshot) => save(store.toJSON()));
109
109
 
110
110
  editor.commands.toggleTrackChanges();
111
- getTrackedChanges(editor); // [{ id, type: "insertion" | "deletion", author, from, to, text, … }]
111
+ getTrackedChanges(editor); // [{ id, type: "insertion" | "deletion" | "format" | "block", author, from, to, text, description, … }]
112
112
  editor.commands.acceptChange(id); // rejectChange, acceptAllChanges, rejectAllChanges: one undo step each
113
113
  ```
114
114
 
115
115
  - **Comments** are `comment` marks holding a thread id; thread content lives in the headless `CommentStore` (`subscribe` / `getSnapshot`, cached snapshots, `toJSON` / `load`). Threads whose text is deleted are flagged `orphaned` and re-attach on undo.
116
- - **Track changes** marks typed and pasted text with an `insertion` mark and keeps deleted text with a `deletion` mark (struck through). Deleting your own insertion really deletes it. IME composition is tracked once it ends. Not tracked: formatting-only changes, block-structure changes (splitting/joining paragraphs, lists) and edits inside code blocks. Set the `TRACK_CHANGES_SKIP_META` transaction meta to apply a change untracked (e.g. `setContent`).
117
- - **Serializers** render tracked content as if all changes were accepted: `getEditorText`, `htmlToPlainText` and `getEditorMarkdown` drop deleted text by default. Pass `{ trackedChanges: "original" }` (as if rejected) or `"all"` (both). `resolveTrackedChanges(doc, view)` returns a resolved document. TipTap's own `editor.getText()` still includes deleted text.
118
- - Both extensions are also available as `createRichTextPreset({ comments: true, trackChanges: true })`. Mark styles use Tailwind classes; override them via `commentClass` / `activeClass` and `insertionHTMLAttributes` / `deletionHTMLAttributes`.
116
+ - **Track changes** marks typed and pasted text with an `insertion` mark and keeps deleted text with a `deletion` mark (struck through). Deleting your own insertion really deletes it. IME composition is tracked once it ends. Insertions and deletions inside code blocks are tracked too (`trackCodeBlocks: false` turns that off). Set the `TRACK_CHANGES_SKIP_META` transaction meta to apply a change untracked (e.g. `setContent`).
117
+ - **Tracked formatting** (`trackFormatting`, on by default): adding or removing marks (bold, italic, links, highlight, font size, …) on existing text records a `formatChange` mark holding the author, id and the `before` / `after` formatting, shown as a dotted underline. Descriptions read `Formatted: Bold`, `Removed formatting: Italic` or `Changed formatting: Font size`. Accept keeps the new formatting; reject restores the old. Adjacent or repeated formatting by the same author merges into one change, changing it back drops the record, and formatting a tracked insertion stays part of the insertion. Review marks, comments and bookmarks are never formatting (add more with `ignoredMarks`).
118
+ - **Tracked block changes** (`trackBlocks`, on by default): changing a textblock's type or attributes (paragraph ↔ heading, heading level, code block, alignment) or its wrappers (bulleted/numbered/task lists, indenting, outdenting, quotes) stores the previous state in a `blockChange` node attribute on `blockTypes` (paragraph, heading, code block), shown with a margin bar. Descriptions read `Changed Paragraph to Heading 2`, `Wrapped in Bulleted list`, `Changed alignment to Center`. Reject restores the type, attributes and nesting. Paragraph splits and joins are not tracked (a split-off block does not inherit the record). `describeFormatChange` and `describeBlockChange` build the descriptions.
119
+ - **Serializers** render tracked content as if all changes were accepted: `getEditorText`, `htmlToPlainText` and `getEditorMarkdown` drop deleted text and use the new formatting and block types by default. Pass `{ trackedChanges: "original" }` (as if rejected) or `"all"` (both). `resolveTrackedChanges(doc, view)` returns a resolved document. TipTap's own `editor.getText()` still includes deleted text.
120
+ - Both extensions are also available as `createRichTextPreset({ comments: true, trackChanges: true })`. Mark styles use Tailwind classes; override them via `commentClass` / `activeClass` and `insertionHTMLAttributes` / `deletionHTMLAttributes` / `formatChangeHTMLAttributes` / `blockChangeClass`.
119
121
 
120
122
  ## File import and rich clipboard
121
123
 
122
- An import adapter registry maps file types (MIME types and extensions) to converters. Built-in `document` adapters cover markdown (`.md`, `.markdown`, `.mdown`, `.mkdn`, `.mkd`, `.Rmd`, `.md.txt`), HTML (sanitized with the same allowlist as markdown), plain text (`.txt`) and RTF (best-effort text extraction). The longest matching extension wins, then exact MIME types, then `priority`, then the most recent registration.
124
+ An import adapter registry maps file types (MIME types and extensions) to converters. Built-in `document` adapters cover markdown (`.md`, `.markdown`, `.mdown`, `.mkdn`, `.mkd`, `.Rmd`, `.md.txt`), HTML (sanitized with the same allowlist as markdown), plain text (`.txt`), RTF (best-effort text extraction) and DOCX (`.docx`, `.docm`, `.dotx`). The longest matching extension wins, then exact MIME types, then `priority`, then the most recent registration.
123
125
 
124
126
  ```ts
125
127
  import { importFile, registerImportAdapter, getImportAccept } from "@pixerate/editor";
@@ -127,20 +129,27 @@ import { importFile, registerImportAdapter, getImportAccept } from "@pixerate/ed
127
129
  const { adapterId, result } = await importFile(file); // result: { html, text }
128
130
  input.accept = getImportAccept("document");
129
131
 
130
- // DOCX, PDF, zipped exports or CSV → spreadsheet are pluggable:
132
+ // Other formats are pluggable:
131
133
  registerImportAdapter({
132
- id: "docx",
133
- label: "Word",
134
- mimeTypes: ["application/vnd.openxmlformats-officedocument.wordprocessingml.document"],
135
- extensions: [".docx"],
134
+ id: "odt",
135
+ label: "OpenDocument text",
136
+ mimeTypes: ["application/vnd.oasis.opendocument.text"],
137
+ extensions: [".odt"],
136
138
  target: "document",
137
139
  async import(_file, ctx) {
138
- const html = await myDocxToHtml(await ctx.readArrayBuffer());
140
+ const html = await myOdtToHtml(await ctx.readArrayBuffer());
139
141
  return { html, text: htmlToPlainText(html) };
140
142
  },
141
143
  });
142
144
  ```
143
145
 
146
+ ### DOCX, PDF and zipped exports (no extra dependencies)
147
+
148
+ - **DOCX** (built in): `docxImportAdapter` reads `word/document.xml` (located via `_rels/.rels`), styles, numbering, relationships and footnotes / endnotes with the platform `DOMParser`, and maps headings (`Heading1`–`6`, `Title`, outline levels), bold / italic / underline / strike / super- and subscript, hyperlinks (including `HYPERLINK` fields), nested bulleted / numbered lists, tables (`colspan` / `rowspan`, header rows), line breaks, tabs and embedded PNG / JPEG / GIF / WebP images (as data URLs; dropped by the editor when the image extension is off). Output goes through `sanitizeImportedHtml`. **Tracked changes are imported as if accepted** (`w:ins` kept, `w:del` dropped); `createDocxImportAdapter({ trackedChanges: "original" })` imports them as if rejected. Text boxes, shapes, charts, equations, comments and layout are not imported. Without a global `DOMParser` (plain Node) it throws `ImportError("unsupported_environment")`; pass one with `createDocxImportAdapter({ DOMParser })`. Other options: `images`, `maxImageSize` (10 MiB), `zip` limits.
149
+ - **PDF** (opt-in, bring your own pdf.js): `registerImportAdapter(createPdfImportAdapter(pdfjs))` with any object shaped like `pdfjs-dist` (`getDocument({ data }).promise`, `page.getTextContent()`). Text items are grouped into lines by baseline and into paragraphs by larger-than-usual vertical gaps or blank lines; options `paragraphGap`, `maxPages`, `documentParams`. Text only. `pdfTextItemsToParagraphs` is exported for custom adapters.
150
+ - **Zipped exports** (opt-in): `registerImportAdapter(zipImportAdapter)` imports a `.zip` of markdown / HTML / text / DOCX files (Notion, Confluence, Obsidian exports) with the registry's other adapters — index / README files first, then natural path order — with a heading per file (Notion ids stripped from titles). The result adds `files` and `skipped` (unsupported types, nested archives, failures). Not registered by default because `.zip` is a generic container: claiming every dropped archive would steal drops from other handlers. `createZipImportAdapter({ headings, headingLevel, maxFiles, registry, zip })` customizes it.
151
+ - **ZIP reader**: `readZip(bytes, { maxEntries, maxTotalSize, unsafePaths })` parses the central directory (ZIP64 included) and lazily extracts stored / deflate entries via `DecompressionStream("deflate-raw")` (browsers, Node 18+), verifying CRC-32. It rejects encrypted entries, `..` / absolute names and archives over the entry or uncompressed-size caps (default 10 000 entries / 256 MiB, enforced on inflated bytes) with typed `ZipError`s. DOCX reads use 100 MiB / 5 000 entries.
152
+
144
153
  `FileImport` (or `createRichTextPreset({ fileImport: true })`) inserts dropped or pasted files at the drop position, and `FileImportController` / `pickImportFiles` back file-picker buttons. `RichClipboard` (or `richClipboard: true`) also writes copied content as `application/x.pixerate.document+json` (ProseMirror slice JSON plus a schema signature) and prefers it on paste when the schemas match, falling back to HTML / plain text. Both are opt-in, and `EditorController` keeps them on plain text in `plainTextMode`.
145
154
 
146
155
  ## Agent tool registry
@@ -2,12 +2,12 @@
2
2
 
3
3
 
4
4
 
5
- var _chunkTVRC4KVTcjs = require('../chunk-TVRC4KVT.cjs');
5
+ var _chunkAA4ZEVCCcjs = require('../chunk-AA4ZEVCC.cjs');
6
6
 
7
7
 
8
8
 
9
9
 
10
- var _chunkJYRIOFENcjs = require('../chunk-JYRIOFEN.cjs');
10
+ var _chunkSAZRENEZcjs = require('../chunk-SAZRENEZ.cjs');
11
11
 
12
12
 
13
13
 
@@ -762,7 +762,7 @@ function createToolRegistry(options) {
762
762
  var toEditor = (target) => "commands" in target ? target : target.editor;
763
763
  function replaceWithText(editor, from, to, text) {
764
764
  const { state, view } = editor;
765
- const tr = /[\r\n]/.test(text) ? state.tr.replace(from, to, _chunkTVRC4KVTcjs.plainTextToSlice.call(void 0, text, state.schema)) : text ? state.tr.insertText(text, from, to) : state.tr.delete(from, to);
765
+ const tr = /[\r\n]/.test(text) ? state.tr.replace(from, to, _chunkAA4ZEVCCcjs.plainTextToSlice.call(void 0, text, state.schema)) : text ? state.tr.insertText(text, from, to) : state.tr.delete(from, to);
766
766
  view.dispatch(tr.scrollIntoView());
767
767
  }
768
768
  function selectionInfo(editor) {
@@ -788,7 +788,7 @@ function createRichTextToolProvider(target, options) {
788
788
  annotations: { readOnlyHint: true },
789
789
  handler: ({ format = "text" }) => {
790
790
  const ed = editor();
791
- const content = format === "html" ? ed.getHTML() : format === "markdown" ? _chunkTVRC4KVTcjs.getEditorMarkdown.call(void 0, ed) : _chunkTVRC4KVTcjs.getEditorText.call(void 0, ed);
791
+ const content = format === "html" ? ed.getHTML() : format === "markdown" ? _chunkAA4ZEVCCcjs.getEditorMarkdown.call(void 0, ed) : _chunkAA4ZEVCCcjs.getEditorText.call(void 0, ed);
792
792
  return { format, content, selection: selectionInfo(ed), size: ed.state.doc.content.size };
793
793
  }
794
794
  };
@@ -855,7 +855,7 @@ var CELL_REF_REGEX = /^\$?([A-Za-z]{1,3})\$?(\d{1,7})$/;
855
855
  function parseCell(ref) {
856
856
  const match = CELL_REF_REGEX.exec(ref.trim());
857
857
  if (!match) throw new Error(`Invalid cell reference "${ref}". Use A1 notation, e.g. "B3".`);
858
- return { col: _chunkJYRIOFENcjs.colNameToIndex.call(void 0, match[1].toUpperCase()), row: parseInt(match[2], 10) - 1 };
858
+ return { col: _chunkSAZRENEZcjs.colNameToIndex.call(void 0, match[1].toUpperCase()), row: parseInt(match[2], 10) - 1 };
859
859
  }
860
860
  function createSpreadsheetToolProvider(controller, options) {
861
861
  const lookup = (row, col) => {
@@ -896,14 +896,14 @@ function createSpreadsheetToolProvider(controller, options) {
896
896
  const cell = controller.getCell(found.rowDef.id, found.colDef.id);
897
897
  valueRow.push(_nullishCoalesce(cell.error, () => ( cell.value)));
898
898
  rawRow.push(cell.raw);
899
- const error = _nullishCoalesce(cell.error, () => ( (_chunkJYRIOFENcjs.isFormulaError.call(void 0, cell.value) ? cell.value : void 0)));
900
- if (error) errors.push({ cell: `${_chunkJYRIOFENcjs.indexToColName.call(void 0, c)}${r + 1}`, error });
899
+ const error = _nullishCoalesce(cell.error, () => ( (_chunkSAZRENEZcjs.isFormulaError.call(void 0, cell.value) ? cell.value : void 0)));
900
+ if (error) errors.push({ cell: `${_chunkSAZRENEZcjs.indexToColName.call(void 0, c)}${r + 1}`, error });
901
901
  }
902
902
  values.push(valueRow);
903
903
  raw.push(rawRow);
904
904
  }
905
905
  return {
906
- range: values.length && values[0].length ? `${_chunkJYRIOFENcjs.indexToColName.call(void 0, c0)}${r0 + 1}:${_chunkJYRIOFENcjs.indexToColName.call(void 0, c1)}${r1 + 1}` : null,
906
+ range: values.length && values[0].length ? `${_chunkSAZRENEZcjs.indexToColName.call(void 0, c0)}${r0 + 1}:${_chunkSAZRENEZcjs.indexToColName.call(void 0, c1)}${r1 + 1}` : null,
907
907
  values,
908
908
  raw,
909
909
  errors,
@@ -1,6 +1,6 @@
1
- import { C as CanvasNode, a as CanvasEdge, X as XYPosition, S as Side } from '../types-DMe0vFB1.cjs';
1
+ import { C as CanvasNode, a as CanvasEdge, X as XYPosition, S as Side } from '../types-CJ4U-HHI.cjs';
2
2
  import { Editor } from '@tiptap/core';
3
- import { W as SpreadsheetController } from '../controller-OUdxPY-X.cjs';
3
+ import { S as SpreadsheetController } from '../controller-B7GIybc4.cjs';
4
4
 
5
5
  /**
6
6
  * Agent presence state for visual multiplayer/agent choreography.
@@ -1,6 +1,6 @@
1
- import { C as CanvasNode, a as CanvasEdge, X as XYPosition, S as Side } from '../types-DMe0vFB1.js';
1
+ import { C as CanvasNode, a as CanvasEdge, X as XYPosition, S as Side } from '../types-CJ4U-HHI.js';
2
2
  import { Editor } from '@tiptap/core';
3
- import { W as SpreadsheetController } from '../controller-OUdxPY-X.js';
3
+ import { S as SpreadsheetController } from '../controller-B7GIybc4.js';
4
4
 
5
5
  /**
6
6
  * Agent presence state for visual multiplayer/agent choreography.
@@ -2,12 +2,12 @@ import {
2
2
  getEditorMarkdown,
3
3
  getEditorText,
4
4
  plainTextToSlice
5
- } from "../chunk-3TYMNULT.js";
5
+ } from "../chunk-MJZBNWG7.js";
6
6
  import {
7
7
  colNameToIndex,
8
8
  indexToColName,
9
9
  isFormulaError
10
- } from "../chunk-A7DKIA72.js";
10
+ } from "../chunk-DENSCKFC.js";
11
11
  import {
12
12
  ensureLayout,
13
13
  getLayoutedNodes,