myrole-docx-editor 0.1.5 → 0.2.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.
@@ -1,5 +1,5 @@
1
1
  import * as s from "blockly";
2
- import { k as p, T as u, m, n as f, o as g, q as h } from "./sdk-BVyUd7P0.js";
2
+ import { k as p, T as u, m, n as f, o as g, q as h } from "./sdk-BM5tI24s.js";
3
3
  let r = !1;
4
4
  function b(o, n, i) {
5
5
  r || (p(), r = !0), o.replaceChildren();
@@ -39,4 +39,4 @@ function b(o, n, i) {
39
39
  export {
40
40
  b as mountBlockly
41
41
  };
42
- //# sourceMappingURL=vars-blockly-CBeNXS0X.js.map
42
+ //# sourceMappingURL=vars-blockly-BQPk_GUT.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"vars-blockly-CBeNXS0X.js","sources":["../../src/vars-blockly.ts"],"sourcesContent":["import * as Blockly from 'blockly'\nimport {\n decorate, defineBlocks, fieldLibrary, setFields, THEME, TOOLBOX,\n type BlockJson,\n} from '@myrole/docx-vars'\nimport type { Tag } from '@myrole/docx-tags'\n\n/**\n * Le mode Blockly, chargé à la demande.\n *\n * Le canvas ne se replie pas — c'est ce qui a fait choisir le rendu DOM par\n * défaut — mais il sait ce que le DOM ne fait pas encore aussi bien :\n * restructurer librement une expression au glisser-déposer, avec sa poubelle,\n * son annulation et ses connexions typées.\n *\n * Il vit dans son propre module pour ne peser que si on l'ouvre : un\n * mégaoctet et demi qu'un utilisateur qui ne bascule jamais ne télécharge pas.\n */\n\nlet defined = false\n\nexport interface BlocklyView {\n load(tree: BlockJson): void\n read(): BlockJson | null\n resize(): void\n dispose(): void\n}\n\nexport function mountBlockly(\n holder: HTMLElement, onChange: () => void, tags: () => Tag[],\n): BlocklyView {\n if (!defined) { defineBlocks(); defined = true }\n holder.replaceChildren()\n const host = document.createElement('div')\n host.className = 'vp-canvas-host'\n holder.append(host)\n\n const ws = Blockly.inject(host, {\n // La boîte à outils : sans elle, on peut lire une expression et la\n // rebrancher, mais pas y AJOUTER quoi que ce soit — c'est la moitié de ce\n // qu'on vient chercher dans un canvas de blocs.\n toolbox: TOOLBOX,\n theme: THEME,\n renderer: 'geras',\n trashcan: true,\n sounds: false,\n grid: { spacing: 20, length: 1, colour: '#e8e9ed', snap: false },\n zoom: { controls: true, wheel: true, startScale: 0.95, minScale: 0.3, maxScale: 2 },\n move: { scrollbars: true, drag: true, wheel: true },\n })\n ws.addChangeListener((e) => { if (!e.isUiEvent) onChange() })\n\n return {\n load(tree) {\n // `setFields` alimente le sélecteur du bloc « champ » : sans lui, un clic\n // sur un champ n'ouvre rien.\n const groups = fieldLibrary(tags())\n setFields(groups.flatMap((g) => g.fields.map((f) => ({ path: f.path, label: f.label }))))\n Blockly.serialization.workspaces.load({ blocks: { languageVersion: 0, blocks: [tree] } }, ws)\n decorate(ws)\n Blockly.svgResize(ws)\n },\n read() {\n const state = Blockly.serialization.workspaces.save(ws) as {\n blocks?: { blocks?: BlockJson[] }\n }\n return state?.blocks?.blocks?.[0] ?? null\n },\n resize() { Blockly.svgResize(ws) },\n dispose() { ws.dispose() },\n }\n}\n"],"names":["defined","mountBlockly","holder","onChange","tags","defineBlocks","host","ws","Blockly","TOOLBOX","THEME","e","tree","groups","fieldLibrary","setFields","g","f","decorate"],"mappings":";;AAmBA,IAAIA,IAAU;AASP,SAASC,EACdC,GAAqBC,GAAsBC,GAC9B;AACb,EAAKJ,MAAWK,EAAA,GAAgBL,IAAU,KAC1CE,EAAO,gBAAA;AACP,QAAMI,IAAO,SAAS,cAAc,KAAK;AACzC,EAAAA,EAAK,YAAY,kBACjBJ,EAAO,OAAOI,CAAI;AAElB,QAAMC,IAAKC,EAAQ,OAAOF,GAAM;AAAA;AAAA;AAAA;AAAA,IAI9B,SAASG;AAAA,IACT,OAAOC;AAAA,IACP,UAAU;AAAA,IACV,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,MAAM,EAAE,SAAS,IAAI,QAAQ,GAAG,QAAQ,WAAW,MAAM,GAAA;AAAA,IACzD,MAAM,EAAE,UAAU,IAAM,OAAO,IAAM,YAAY,MAAM,UAAU,KAAK,UAAU,EAAA;AAAA,IAChF,MAAM,EAAE,YAAY,IAAM,MAAM,IAAM,OAAO,GAAA;AAAA,EAAK,CACnD;AACD,SAAAH,EAAG,kBAAkB,CAACI,MAAM;AAAE,IAAKA,EAAE,aAAWR,EAAA;AAAA,EAAW,CAAC,GAErD;AAAA,IACL,KAAKS,GAAM;AAGT,YAAMC,IAASC,EAAaV,GAAM;AAClC,MAAAW,EAAUF,EAAO,QAAQ,CAACG,MAAMA,EAAE,OAAO,IAAI,CAACC,OAAO,EAAE,MAAMA,EAAE,MAAM,OAAOA,EAAE,MAAA,EAAQ,CAAC,CAAC,GACxFT,EAAQ,cAAc,WAAW,KAAK,EAAE,QAAQ,EAAE,iBAAiB,GAAG,QAAQ,CAACI,CAAI,EAAA,EAAE,GAAKL,CAAE,GAC5FW,EAASX,CAAE,GACXC,EAAQ,UAAUD,CAAE;AAAA,IACtB;AAAA,IACA,OAAO;AAIL,aAHcC,EAAQ,cAAc,WAAW,KAAKD,CAAE,GAGxC,QAAQ,SAAS,CAAC,KAAK;AAAA,IACvC;AAAA,IACA,SAAS;AAAE,MAAAC,EAAQ,UAAUD,CAAE;AAAA,IAAE;AAAA,IACjC,UAAU;AAAE,MAAAA,EAAG,QAAA;AAAA,IAAU;AAAA,EAAA;AAE7B;"}
1
+ {"version":3,"file":"vars-blockly-BQPk_GUT.js","sources":["../../src/vars-blockly.ts"],"sourcesContent":["import * as Blockly from 'blockly'\nimport {\n decorate, defineBlocks, fieldLibrary, setFields, THEME, TOOLBOX,\n type BlockJson,\n} from '@myrole/docx-vars'\nimport type { Tag } from '@myrole/docx-tags'\n\n/**\n * Le mode Blockly, chargé à la demande.\n *\n * Le canvas ne se replie pas — c'est ce qui a fait choisir le rendu DOM par\n * défaut — mais il sait ce que le DOM ne fait pas encore aussi bien :\n * restructurer librement une expression au glisser-déposer, avec sa poubelle,\n * son annulation et ses connexions typées.\n *\n * Il vit dans son propre module pour ne peser que si on l'ouvre : un\n * mégaoctet et demi qu'un utilisateur qui ne bascule jamais ne télécharge pas.\n */\n\nlet defined = false\n\nexport interface BlocklyView {\n load(tree: BlockJson): void\n read(): BlockJson | null\n resize(): void\n dispose(): void\n}\n\nexport function mountBlockly(\n holder: HTMLElement, onChange: () => void, tags: () => Tag[],\n): BlocklyView {\n if (!defined) { defineBlocks(); defined = true }\n holder.replaceChildren()\n const host = document.createElement('div')\n host.className = 'vp-canvas-host'\n holder.append(host)\n\n const ws = Blockly.inject(host, {\n // La boîte à outils : sans elle, on peut lire une expression et la\n // rebrancher, mais pas y AJOUTER quoi que ce soit — c'est la moitié de ce\n // qu'on vient chercher dans un canvas de blocs.\n toolbox: TOOLBOX,\n theme: THEME,\n renderer: 'geras',\n trashcan: true,\n sounds: false,\n grid: { spacing: 20, length: 1, colour: '#e8e9ed', snap: false },\n zoom: { controls: true, wheel: true, startScale: 0.95, minScale: 0.3, maxScale: 2 },\n move: { scrollbars: true, drag: true, wheel: true },\n })\n ws.addChangeListener((e) => { if (!e.isUiEvent) onChange() })\n\n return {\n load(tree) {\n // `setFields` alimente le sélecteur du bloc « champ » : sans lui, un clic\n // sur un champ n'ouvre rien.\n const groups = fieldLibrary(tags())\n setFields(groups.flatMap((g) => g.fields.map((f) => ({ path: f.path, label: f.label }))))\n Blockly.serialization.workspaces.load({ blocks: { languageVersion: 0, blocks: [tree] } }, ws)\n decorate(ws)\n Blockly.svgResize(ws)\n },\n read() {\n const state = Blockly.serialization.workspaces.save(ws) as {\n blocks?: { blocks?: BlockJson[] }\n }\n return state?.blocks?.blocks?.[0] ?? null\n },\n resize() { Blockly.svgResize(ws) },\n dispose() { ws.dispose() },\n }\n}\n"],"names":["defined","mountBlockly","holder","onChange","tags","defineBlocks","host","ws","Blockly","TOOLBOX","THEME","e","tree","groups","fieldLibrary","setFields","g","f","decorate"],"mappings":";;AAmBA,IAAIA,IAAU;AASP,SAASC,EACdC,GAAqBC,GAAsBC,GAC9B;AACb,EAAKJ,MAAWK,EAAA,GAAgBL,IAAU,KAC1CE,EAAO,gBAAA;AACP,QAAMI,IAAO,SAAS,cAAc,KAAK;AACzC,EAAAA,EAAK,YAAY,kBACjBJ,EAAO,OAAOI,CAAI;AAElB,QAAMC,IAAKC,EAAQ,OAAOF,GAAM;AAAA;AAAA;AAAA;AAAA,IAI9B,SAASG;AAAA,IACT,OAAOC;AAAA,IACP,UAAU;AAAA,IACV,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,MAAM,EAAE,SAAS,IAAI,QAAQ,GAAG,QAAQ,WAAW,MAAM,GAAA;AAAA,IACzD,MAAM,EAAE,UAAU,IAAM,OAAO,IAAM,YAAY,MAAM,UAAU,KAAK,UAAU,EAAA;AAAA,IAChF,MAAM,EAAE,YAAY,IAAM,MAAM,IAAM,OAAO,GAAA;AAAA,EAAK,CACnD;AACD,SAAAH,EAAG,kBAAkB,CAACI,MAAM;AAAE,IAAKA,EAAE,aAAWR,EAAA;AAAA,EAAW,CAAC,GAErD;AAAA,IACL,KAAKS,GAAM;AAGT,YAAMC,IAASC,EAAaV,GAAM;AAClC,MAAAW,EAAUF,EAAO,QAAQ,CAACG,MAAMA,EAAE,OAAO,IAAI,CAACC,OAAO,EAAE,MAAMA,EAAE,MAAM,OAAOA,EAAE,MAAA,EAAQ,CAAC,CAAC,GACxFT,EAAQ,cAAc,WAAW,KAAK,EAAE,QAAQ,EAAE,iBAAiB,GAAG,QAAQ,CAACI,CAAI,EAAA,EAAE,GAAKL,CAAE,GAC5FW,EAASX,CAAE,GACXC,EAAQ,UAAUD,CAAE;AAAA,IACtB;AAAA,IACA,OAAO;AAIL,aAHcC,EAAQ,cAAc,WAAW,KAAKD,CAAE,GAGxC,QAAQ,SAAS,CAAC,KAAK;AAAA,IACvC;AAAA,IACA,SAAS;AAAE,MAAAC,EAAQ,UAAUD,CAAE;AAAA,IAAE;AAAA,IACjC,UAAU;AAAE,MAAAA,EAAG,QAAA;AAAA,IAAU;AAAA,EAAA;AAE7B;"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { i as f, r as m, e as w, f as p, p as u, l as y, a as g, b as h, c as x } from "./chunks/sdk-BVyUd7P0.js";
2
- import { d as R, g as b, h as U, j, s as A } from "./chunks/sdk-BVyUd7P0.js";
1
+ import { i as f, r as m, e as w, f as p, p as u, l as y, a as g, b as h, c as x } from "./chunks/sdk-BM5tI24s.js";
2
+ import { d as R, g as b, h as U, j, s as A } from "./chunks/sdk-BM5tI24s.js";
3
3
  async function P(a, o, r = {}) {
4
4
  const i = performance.now(), [c] = await Promise.all([
5
5
  typeof a == "string" ? fetch(a).then((e) => e.ok ? e.arrayBuffer() : Promise.reject(new Error(`${e.status} ${a}`))) : Promise.resolve(a),
package/dist/react.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { jsx as h } from "react/jsx-runtime";
2
2
  import { forwardRef as v, useRef as o, useEffect as a } from "react";
3
- import { d as y } from "./chunks/sdk-BVyUd7P0.js";
3
+ import { d as y } from "./chunks/sdk-BM5tI24s.js";
4
4
  const s = v(function({ src: u, className: b, style: S, onReady: g, ...e }, f) {
5
5
  const l = o(null), c = o(null), n = o(e);
6
6
  n.current = e;
@@ -0,0 +1,3 @@
1
+ import type { Editor } from './editor';
2
+ export declare function editLink(editor: Editor): void;
3
+ export declare function editStyle(editor: Editor, update?: boolean): void;
@@ -0,0 +1,4 @@
1
+ import type { Comment } from './comments';
2
+ import type { Editor } from './editor';
3
+ /** Comments use the same scoped popover and command path as the ribbon. */
4
+ export declare function editComment(editor: Editor, existing?: Comment, author?: string): void;
@@ -1,24 +1,2 @@
1
- /**
2
- * Word's comments, and where they sit in the text.
3
- *
4
- * `word/comments.xml` holds the comments; the body marks each range with
5
- * `w:commentRangeStart` / `w:commentRangeEnd` between the runs. The offsets
6
- * are counted the way `paragraphText` counts — `w:t` text, a tab, a break —
7
- * so a comment's range is addressable by the editor like any selection.
8
- */
9
- import { type DocxDocument } from '../../docx-model/src/index';
10
- export interface Comment {
11
- id: string;
12
- author: string;
13
- date?: string;
14
- text: string;
15
- }
16
- export interface CommentRange extends Comment {
17
- para: number;
18
- from: number;
19
- to: number;
20
- }
21
- /** The comments, in the order comments.xml declares them. */
22
- export declare function commentsOf(doc: DocxDocument): Comment[];
23
- /** Each comment with its range in the body — a comment whose range is not in the flow is left out. */
24
- export declare function commentRanges(doc: DocxDocument): CommentRange[];
1
+ export { commentsOf, commentRanges } from '../../docx-model/src/index';
2
+ export type { Comment, CommentRange } from '../../docx-model/src/index';
@@ -169,6 +169,14 @@ export declare function createEditor(setup: EditorSetup): {
169
169
  from: number;
170
170
  to: number;
171
171
  } | null;
172
+ addComment(text: string, author?: string): string | null;
173
+ updateComment: (id: string, text: string) => boolean;
174
+ deleteComment: (id: string) => boolean;
175
+ defineStyle(name: string, id?: string): string | null;
176
+ link: () => string | null;
177
+ setLink(target: string | null): boolean;
178
+ setListLevel(level: number): void;
179
+ restartList(start?: number): boolean;
172
180
  setList(ordered: boolean | null): void;
173
181
  formatCell(patch: CellPatch): boolean;
174
182
  mergeNextCell(): boolean;
@@ -262,7 +270,7 @@ export type Editor = ReturnType<typeof createEditor>;
262
270
  * déplacement du curseur, `render` après chaque composition, `context` avec
263
271
  * l'état complet sous le curseur, `commands` quand le registre bouge.
264
272
  */
265
- export type EditorEvent = 'change' | 'selection' | 'render' | 'context' | 'commands' | 'load' | 'save' | 'command';
273
+ export type EditorEvent = 'change' | 'selection' | 'render' | 'context' | 'commands' | 'styles' | 'load' | 'save' | 'command';
266
274
  /**
267
275
  * Une commande ajoutée par l'hôte ou par une extension.
268
276
  *
@@ -105,6 +105,9 @@ export interface DocxEditorHandle {
105
105
  openFeedback(): void;
106
106
  /** Word's comments of the open document, with their ranges */
107
107
  comments(): CommentRange[];
108
+ addComment(text: string, author?: string): string | null;
109
+ updateComment(id: string, text: string): boolean;
110
+ deleteComment(id: string): boolean;
108
111
  showComments(on: boolean): void;
109
112
  variables: {
110
113
  tags(): Tag[];
@@ -0,0 +1,10 @@
1
+ import { type DocxDocument } from './index';
2
+ import { type DocPos } from './editor';
3
+ /** Create a paragraph style from the selection, or update an existing style to match it. */
4
+ export declare function defineParagraphStyle(doc: DocxDocument, at: DocPos, name: string, id?: string): string | null;
5
+ /** Read a link at the caret using the same inline address as its writer. */
6
+ export declare function hyperlinkTarget(doc: DocxDocument, at: DocPos): string | null;
7
+ /** Set or remove a hyperlink in one inline container without flattening its content. */
8
+ export declare function setHyperlink(doc: DocxDocument, a: DocPos, b: DocPos, target: string | null): boolean;
9
+ /** Restart from this paragraph, keeping the following contiguous items in the same new list. */
10
+ export declare function restartList(doc: DocxDocument, at: DocPos, start?: number): number | null;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Word's comments, and where they sit in the text.
3
+ *
4
+ * `word/comments.xml` holds the comments; the body marks each range with
5
+ * `w:commentRangeStart` / `w:commentRangeEnd` between the runs. The offsets
6
+ * are counted the way `paragraphText` counts — `w:t` text, a tab, a break —
7
+ * so a comment's range is addressable by the editor like any selection.
8
+ */
9
+ import { type DocxDocument } from './index';
10
+ import { type DocPos } from './editor';
11
+ export interface Comment {
12
+ id: string;
13
+ author: string;
14
+ date?: string;
15
+ text: string;
16
+ }
17
+ export interface CommentRange extends Comment {
18
+ para: number;
19
+ from: number;
20
+ to: number;
21
+ }
22
+ /** The comments, in the order comments.xml declares them. */
23
+ export declare function commentsOf(doc: DocxDocument): Comment[];
24
+ /** Each comment with its range in the body — a comment whose range is not in the flow is left out. */
25
+ export declare function commentRanges(doc: DocxDocument): CommentRange[];
26
+ /** Add a classic Word comment to a nonempty body selection, keeping existing parts intact. */
27
+ export declare function addComment(doc: DocxDocument, a: DocPos, b: DocPos, text: string, author?: string): string | null;
28
+ export declare function updateComment(doc: DocxDocument, id: string, text: string): boolean;
29
+ /** Remove this comment's definition and anchors; unrelated annotations remain intact. */
30
+ export declare function deleteComment(doc: DocxDocument, id: string): boolean;
@@ -53,7 +53,7 @@ export declare function splitParagraph(doc: DocxDocument, pos: DocPos): DocPos |
53
53
  *
54
54
  * Renvoie la position de la soudure, là où le curseur doit rester.
55
55
  */
56
- export declare function joinParagraph(doc: DocxDocument, para: number): DocPos | null;
56
+ export declare function joinParagraph(doc: DocxDocument, para: number, part?: string): DocPos | null;
57
57
  /**
58
58
  * Insère un tableau vide au caret en coupant le paragraphe en deux.
59
59
  *
@@ -112,3 +112,5 @@ export * from './insert';
112
112
  export * from './paste';
113
113
  export * from './fonts';
114
114
  export * from './textbox';
115
+ export * from './comments';
116
+ export * from './authoring';
@@ -1,5 +1,12 @@
1
- import { type DocxDocument } from './index';
1
+ import { type DocxDocument, type XmlNode } from './index';
2
2
  import { type DocPos, type RunPatch } from './editor';
3
+ /** Prochain identifiant de relation libre pour une part. */
4
+ export declare function nextRelId(rels: XmlNode[]): string;
5
+ /** Le tableau des relations d'une part, créé s'il n'existe pas. */
6
+ export declare function relsOf(doc: DocxDocument, part: string): {
7
+ path: string;
8
+ list: XmlNode[];
9
+ };
3
10
  export interface InsertedImage {
4
11
  /** où le curseur se retrouve, après l'image */
5
12
  pos: DocPos;
@@ -30,6 +30,12 @@ export type PastedBlock = {
30
30
  widthPt: number;
31
31
  heightPt: number;
32
32
  };
33
+ /** Déclare une part dans `[Content_Types].xml` par son chemin. */
34
+ export declare function ensureOverride(doc: DocxDocument, part: string, mime: string): void;
35
+ /** Relation du document vers une part interne, créée si elle manque. */
36
+ export declare function ensureRel(doc: DocxDocument, type: string, target: string): void;
37
+ /** Add a missing level to this list instance without changing other lists' abstract definitions. */
38
+ export declare function ensureListLevel(doc: DocxDocument, numId: number, level: number): boolean;
33
39
  /**
34
40
  * Un `w:numId` bon pour une liste collée — trouvé, ou créé.
35
41
  *
@@ -49,6 +49,8 @@ export interface RunSpan {
49
49
  start: number;
50
50
  end: number;
51
51
  }
52
+ /** Keep zero-width markup and objects between text runs when replacing their text. */
53
+ export declare function interveningMarkup(first: RunSpan, last: RunSpan): XmlNode[];
52
54
  /**
53
55
  * Découpe un paragraphe en runs adressables, dans l'ordre de lecture.
54
56
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myrole-docx-editor",
3
- "version": "0.1.5",
3
+ "version": "0.2.0",
4
4
  "description": "Word-faithful .docx editor and renderer on canvas — the MyRole engine as an embeddable SDK, with a React component.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -46,10 +46,10 @@
46
46
  "react-dom": "^19.2.8",
47
47
  "vite": "^6.4.3",
48
48
  "@myrole/docx-model": "0.0.0",
49
- "@myrole/docx-render": "0.0.0",
50
- "@myrole/docx-tags": "0.0.0",
49
+ "@myrole/docx-vars": "0.0.0",
51
50
  "@myrole/fonts": "0.1.0",
52
- "@myrole/docx-vars": "0.0.0"
51
+ "@myrole/docx-render": "0.0.0",
52
+ "@myrole/docx-tags": "0.0.0"
53
53
  },
54
54
  "publishConfig": {
55
55
  "access": "public"