myrole-docx-editor 0.1.4 → 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-DZeo_8qT.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-EQQZFx30.js.map
42
+ //# sourceMappingURL=vars-blockly-BQPk_GUT.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"vars-blockly-EQQZFx30.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-DZeo_8qT.js";
2
- import { d as R, g as b, h as U, j, s as A } from "./chunks/sdk-DZeo_8qT.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,52 +1,54 @@
1
1
  import { jsx as h } from "react/jsx-runtime";
2
- import { forwardRef as v, useRef as f, useEffect as n } from "react";
3
- import { d as S } from "./chunks/sdk-DZeo_8qT.js";
4
- const s = v(function({ src: u, className: o, style: g, onReady: y, ...e }, d) {
5
- const l = f(null), c = f(null), t = f(e);
6
- t.current = e;
2
+ import { forwardRef as v, useRef as o, useEffect as a } from "react";
3
+ import { d as y } from "./chunks/sdk-BM5tI24s.js";
4
+ const s = v(function({ src: u, className: b, style: S, onReady: g, ...e }, f) {
5
+ const l = o(null), c = o(null), n = o(e);
6
+ n.current = e;
7
7
  const m = (r) => {
8
- typeof d == "function" ? d(r) : d && (d.current = r);
8
+ typeof f == "function" ? f(r) : f && (f.current = r);
9
9
  };
10
- return n(() => {
11
- const r = S(l.current, {
10
+ return a(() => {
11
+ const r = y(l.current, {
12
12
  ...e,
13
- onSave: e.onSave ? (a) => t.current.onSave(a) : void 0,
14
- onError: (a) => t.current.onError?.(a),
15
- onSaveState: (a) => t.current.onSaveState?.(a),
16
- onChange: () => t.current.onChange?.(),
13
+ onSave: e.onSave ? (t, d) => n.current.onSave(t, d) : void 0,
14
+ onError: (t) => n.current.onError?.(t),
15
+ onSaveState: (t) => n.current.onSaveState?.(t),
16
+ onLockState: (t) => n.current.onLockState?.(t),
17
+ onChange: () => n.current.onChange?.(),
17
18
  feedback: typeof e.feedback == "object" ? {
18
19
  ...e.feedback,
19
- onSubmit: e.feedback.onSubmit ? (a) => {
20
- const b = t.current.feedback;
21
- if (typeof b != "object" || !b.onSubmit) throw new Error("Feedback submission handler is no longer configured");
22
- return b.onSubmit(a);
20
+ onSubmit: e.feedback.onSubmit ? (t) => {
21
+ const d = n.current.feedback;
22
+ if (typeof d != "object" || !d.onSubmit) throw new Error("Feedback submission handler is no longer configured");
23
+ return d.onSubmit(t);
23
24
  } : void 0
24
25
  } : e.feedback
25
26
  });
26
- return c.current = r, m(r), y?.(r), () => {
27
+ return c.current = r, m(r), g?.(r), () => {
27
28
  r.destroy(), c.current = null, m(null);
28
29
  };
29
- }, [e.draftKey, e.chrome, !!e.onSave]), n(() => {
30
- u && c.current && c.current.load(u).catch((r) => t.current.onError?.(r));
31
- }, [u, e.draftKey, e.chrome, !!e.onSave]), n(() => {
30
+ }, [e.draftKey, e.chrome, !!e.onSave]), a(() => {
31
+ u && c.current && c.current.load(u).catch((r) => n.current.onError?.(r));
32
+ }, [u, e.draftKey, e.chrome, !!e.onSave]), a(() => {
32
33
  e.theme && c.current?.setTheme(e.theme);
33
- }, [e.theme]), n(() => {
34
+ }, [e.theme]), a(() => {
34
35
  c.current?.setReadOnly(e.readOnly ?? !1);
35
- }, [e.readOnly]), n(() => {
36
+ }, [e.readOnly]), a(() => {
36
37
  e.zoom !== void 0 && c.current?.setZoom(e.zoom);
37
- }, [e.zoom]), n(() => {
38
+ }, [e.zoom]), a(() => {
38
39
  e.badges !== void 0 && c.current?.variables.setDisplay(e.badges);
39
- }, [typeof e.badges == "boolean" ? e.badges : e.badges?.variables, typeof e.badges == "boolean" ? e.badges : e.badges?.expressions]), /* @__PURE__ */ h("div", { ref: l, className: o, style: { height: "100%", minHeight: 320, minWidth: 0, ...g } });
40
+ }, [typeof e.badges == "boolean" ? e.badges : e.badges?.variables, typeof e.badges == "boolean" ? e.badges : e.badges?.expressions]), /* @__PURE__ */ h("div", { ref: l, className: b, style: { height: "100%", minHeight: 320, minWidth: 0, ...S } });
40
41
  });
41
42
  function D() {
42
- return f(null);
43
+ return o(null);
43
44
  }
44
- const w = v(function(u, o) {
45
- return /* @__PURE__ */ h(s, { ...u, ref: o, chrome: "viewer", readOnly: !0 });
46
- });
45
+ const O = v(function(u, b) {
46
+ return /* @__PURE__ */ h(s, { ...u, ref: b, chrome: "viewer", readOnly: !0 });
47
+ }), w = 1;
47
48
  export {
49
+ w as DOCX_LOCKING_VERSION,
48
50
  s as DocxEditor,
49
- w as DocxViewer,
51
+ O as DocxViewer,
50
52
  D as useDocxEditor
51
53
  };
52
54
  //# sourceMappingURL=react.js.map
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"react.js","sources":["../src/react.tsx"],"sourcesContent":["/**\n * The React face of the SDK.\n *\n * <DocxEditor src={file} onSave={(bytes) => upload(bytes)} style={{ height: '100vh' }} />\n *\n * The component owns one `createDocxEditor` for its lifetime; `src` changes\n * reload the document in place, every other option is read at mount. React is\n * an optional peer: nothing here runs unless `myrole-docx-editor/react` is\n * imported.\n */\nimport { useEffect, useRef, forwardRef, type CSSProperties } from 'react'\nimport { createDocxEditor, type DocxEditorHandle, type DocxEditorOptions } from './sdk'\n\nexport interface DocxEditorProps extends Omit<DocxEditorOptions, 'onReady'> {\n /** the document: bytes, a Blob/File, or a URL */\n src?: ArrayBuffer | Uint8Array | Blob | string\n className?: string\n style?: CSSProperties\n /** the handle, once mounted */\n onReady?: (editor: DocxEditorHandle) => void\n}\n\nexport const DocxEditor = forwardRef<DocxEditorHandle | null, DocxEditorProps>(function DocxEditor(\n { src, className, style, onReady, ...options }, ref,\n) {\n const host = useRef<HTMLDivElement>(null)\n const handle = useRef<DocxEditorHandle | null>(null)\n // The latest callbacks, without remounting the editor when they change.\n const latest = useRef(options)\n latest.current = options\n\n // The forwarded ref is filled HERE, not by useImperativeHandle: that one\n // runs in the layout phase, before this effect has created anything, and\n // would hand the parent a null for the component's whole life.\n const give = (h: DocxEditorHandle | null) => {\n if (typeof ref === 'function') ref(h)\n else if (ref) ref.current = h\n }\n\n useEffect(() => {\n const h = createDocxEditor(host.current!, {\n ...options,\n onSave: options.onSave ? (b) => latest.current.onSave!(b) : undefined,\n onError: e => latest.current.onError?.(e),\n onSaveState: state => latest.current.onSaveState?.(state),\n onChange: () => latest.current.onChange?.(),\n feedback: typeof options.feedback === 'object' ? {\n ...options.feedback,\n onSubmit: options.feedback.onSubmit ? report => {\n const feedback = latest.current.feedback\n if (typeof feedback !== 'object' || !feedback.onSubmit) throw new Error('Feedback submission handler is no longer configured')\n return feedback.onSubmit(report)\n } : undefined,\n } : options.feedback,\n })\n handle.current = h\n give(h)\n onReady?.(h)\n return () => { h.destroy(); handle.current = null; give(null) }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [options.draftKey, options.chrome, !!options.onSave])\n\n useEffect(() => {\n if (src && handle.current) void handle.current.load(src).catch(e => latest.current.onError?.(e))\n }, [src, options.draftKey, options.chrome, !!options.onSave])\n useEffect(() => { if (options.theme) handle.current?.setTheme(options.theme) }, [options.theme])\n useEffect(() => { handle.current?.setReadOnly(options.readOnly ?? false) }, [options.readOnly])\n useEffect(() => { if (options.zoom !== undefined) handle.current?.setZoom(options.zoom) }, [options.zoom])\n useEffect(() => { if (options.badges !== undefined) handle.current?.variables.setDisplay(options.badges) }, [typeof options.badges === 'boolean' ? options.badges : options.badges?.variables, typeof options.badges === 'boolean' ? options.badges : options.badges?.expressions])\n\n return <div ref={host} className={className} style={{ height: '100%', minHeight: 320, minWidth: 0, ...style }} />\n})\n\n/** A ref to hand to `<DocxEditor ref={…}>`, and the handle once it exists. */\nexport function useDocxEditor() {\n return useRef<DocxEditorHandle | null>(null)\n}\n\nexport type { DocxEditorHandle, DocxEditorOptions } from './sdk'\n\n/** Read-only companion, with the same rendering and lifecycle as the editor. */\nexport const DocxViewer = forwardRef<DocxEditorHandle | null, DocxEditorProps>(function DocxViewer(props, ref) {\n return <DocxEditor {...props} ref={ref} chrome=\"viewer\" readOnly />\n})\n"],"names":["DocxEditor","forwardRef","src","className","style","onReady","options","ref","host","useRef","handle","latest","give","h","useEffect","createDocxEditor","b","e","state","report","feedback","jsx","useDocxEditor","DocxViewer","props"],"mappings":";;;AAsBO,MAAMA,IAAaC,EAAqD,SAC7E,EAAE,KAAAC,GAAK,WAAAC,GAAW,OAAAC,GAAO,SAAAC,GAAS,GAAGC,EAAA,GAAWC,GAChD;AACA,QAAMC,IAAOC,EAAuB,IAAI,GAClCC,IAASD,EAAgC,IAAI,GAE7CE,IAASF,EAAOH,CAAO;AAC7B,EAAAK,EAAO,UAAUL;AAKjB,QAAMM,IAAO,CAACC,MAA+B;AAC3C,IAAI,OAAON,KAAQ,aAAYA,EAAIM,CAAC,IAC3BN,QAAS,UAAUM;AAAA,EAC9B;AAEA,SAAAC,EAAU,MAAM;AACd,UAAMD,IAAIE,EAAiBP,EAAK,SAAU;AAAA,MACxC,GAAGF;AAAA,MACH,QAAQA,EAAQ,SAAS,CAACU,MAAML,EAAO,QAAQ,OAAQK,CAAC,IAAI;AAAA,MAC5D,SAAS,CAAAC,MAAKN,EAAO,QAAQ,UAAUM,CAAC;AAAA,MACxC,aAAa,CAAAC,MAASP,EAAO,QAAQ,cAAcO,CAAK;AAAA,MACxD,UAAU,MAAMP,EAAO,QAAQ,WAAA;AAAA,MAC/B,UAAU,OAAOL,EAAQ,YAAa,WAAW;AAAA,QAC/C,GAAGA,EAAQ;AAAA,QACX,UAAUA,EAAQ,SAAS,WAAW,CAAAa,MAAU;AAC9C,gBAAMC,IAAWT,EAAO,QAAQ;AAChC,cAAI,OAAOS,KAAa,YAAY,CAACA,EAAS,SAAU,OAAM,IAAI,MAAM,qDAAqD;AAC7H,iBAAOA,EAAS,SAASD,CAAM;AAAA,QACjC,IAAI;AAAA,MAAA,IACFb,EAAQ;AAAA,IAAA,CACb;AACD,WAAAI,EAAO,UAAUG,GACjBD,EAAKC,CAAC,GACNR,IAAUQ,CAAC,GACJ,MAAM;AAAE,MAAAA,EAAE,QAAA,GAAWH,EAAO,UAAU,MAAME,EAAK,IAAI;AAAA,IAAE;AAAA,EAEhE,GAAG,CAACN,EAAQ,UAAUA,EAAQ,QAAQ,CAAC,CAACA,EAAQ,MAAM,CAAC,GAEvDQ,EAAU,MAAM;AACd,IAAIZ,KAAOQ,EAAO,WAAcA,EAAO,QAAQ,KAAKR,CAAG,EAAE,MAAM,CAAAe,MAAKN,EAAO,QAAQ,UAAUM,CAAC,CAAC;AAAA,EACjG,GAAG,CAACf,GAAKI,EAAQ,UAAUA,EAAQ,QAAQ,CAAC,CAACA,EAAQ,MAAM,CAAC,GAC5DQ,EAAU,MAAM;AAAE,IAAIR,EAAQ,SAAOI,EAAO,SAAS,SAASJ,EAAQ,KAAK;AAAA,EAAE,GAAG,CAACA,EAAQ,KAAK,CAAC,GAC/FQ,EAAU,MAAM;AAAE,IAAAJ,EAAO,SAAS,YAAYJ,EAAQ,YAAY,EAAK;AAAA,EAAE,GAAG,CAACA,EAAQ,QAAQ,CAAC,GAC9FQ,EAAU,MAAM;AAAE,IAAIR,EAAQ,SAAS,YAAkB,SAAS,QAAQA,EAAQ,IAAI;AAAA,EAAE,GAAG,CAACA,EAAQ,IAAI,CAAC,GACzGQ,EAAU,MAAM;AAAE,IAAIR,EAAQ,WAAW,UAAWI,EAAO,SAAS,UAAU,WAAWJ,EAAQ,MAAM;AAAA,EAAE,GAAG,CAAC,OAAOA,EAAQ,UAAW,YAAYA,EAAQ,SAASA,EAAQ,QAAQ,WAAW,OAAOA,EAAQ,UAAW,YAAYA,EAAQ,SAASA,EAAQ,QAAQ,WAAW,CAAC,GAE3Q,gBAAAe,EAAC,OAAA,EAAI,KAAKb,GAAM,WAAAL,GAAsB,OAAO,EAAE,QAAQ,QAAQ,WAAW,KAAK,UAAU,GAAG,GAAGC,KAAS;AACjH,CAAC;AAGM,SAASkB,IAAgB;AAC9B,SAAOb,EAAgC,IAAI;AAC7C;AAKO,MAAMc,IAAatB,EAAqD,SAAoBuB,GAAOjB,GAAK;AAC7G,SAAO,gBAAAc,EAACrB,KAAY,GAAGwB,GAAO,KAAAjB,GAAU,QAAO,UAAS,UAAQ,IAAC;AACnE,CAAC;"}
1
+ {"version":3,"file":"react.js","sources":["../src/react.tsx"],"sourcesContent":["/**\n * The React face of the SDK.\n *\n * <DocxEditor src={file} onSave={(bytes) => upload(bytes)} style={{ height: '100vh' }} />\n *\n * The component owns one `createDocxEditor` for its lifetime; `src` changes\n * reload the document in place, every other option is read at mount. React is\n * an optional peer: nothing here runs unless `myrole-docx-editor/react` is\n * imported.\n */\nimport { useEffect, useRef, forwardRef, type CSSProperties } from 'react'\nimport { createDocxEditor, type DocxEditorHandle, type DocxEditorOptions } from './sdk'\n\nexport interface DocxEditorProps extends Omit<DocxEditorOptions, 'onReady'> {\n /** the document: bytes, a Blob/File, or a URL */\n src?: ArrayBuffer | Uint8Array | Blob | string\n className?: string\n style?: CSSProperties\n /** the handle, once mounted */\n onReady?: (editor: DocxEditorHandle) => void\n}\n\nexport const DocxEditor = forwardRef<DocxEditorHandle | null, DocxEditorProps>(function DocxEditor(\n { src, className, style, onReady, ...options }, ref,\n) {\n const host = useRef<HTMLDivElement>(null)\n const handle = useRef<DocxEditorHandle | null>(null)\n // The latest callbacks, without remounting the editor when they change.\n const latest = useRef(options)\n latest.current = options\n\n // The forwarded ref is filled HERE, not by useImperativeHandle: that one\n // runs in the layout phase, before this effect has created anything, and\n // would hand the parent a null for the component's whole life.\n const give = (h: DocxEditorHandle | null) => {\n if (typeof ref === 'function') ref(h)\n else if (ref) ref.current = h\n }\n\n useEffect(() => {\n const h = createDocxEditor(host.current!, {\n ...options,\n onSave: options.onSave ? (b, context) => latest.current.onSave!(b, context) : undefined,\n onError: e => latest.current.onError?.(e),\n onSaveState: state => latest.current.onSaveState?.(state),\n onLockState: state => latest.current.onLockState?.(state),\n onChange: () => latest.current.onChange?.(),\n feedback: typeof options.feedback === 'object' ? {\n ...options.feedback,\n onSubmit: options.feedback.onSubmit ? report => {\n const feedback = latest.current.feedback\n if (typeof feedback !== 'object' || !feedback.onSubmit) throw new Error('Feedback submission handler is no longer configured')\n return feedback.onSubmit(report)\n } : undefined,\n } : options.feedback,\n })\n handle.current = h\n give(h)\n onReady?.(h)\n return () => { h.destroy(); handle.current = null; give(null) }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [options.draftKey, options.chrome, !!options.onSave])\n\n useEffect(() => {\n if (src && handle.current) void handle.current.load(src).catch(e => latest.current.onError?.(e))\n }, [src, options.draftKey, options.chrome, !!options.onSave])\n useEffect(() => { if (options.theme) handle.current?.setTheme(options.theme) }, [options.theme])\n useEffect(() => { handle.current?.setReadOnly(options.readOnly ?? false) }, [options.readOnly])\n useEffect(() => { if (options.zoom !== undefined) handle.current?.setZoom(options.zoom) }, [options.zoom])\n useEffect(() => { if (options.badges !== undefined) handle.current?.variables.setDisplay(options.badges) }, [typeof options.badges === 'boolean' ? options.badges : options.badges?.variables, typeof options.badges === 'boolean' ? options.badges : options.badges?.expressions])\n\n return <div ref={host} className={className} style={{ height: '100%', minHeight: 320, minWidth: 0, ...style }} />\n})\n\n/** A ref to hand to `<DocxEditor ref={…}>`, and the handle once it exists. */\nexport function useDocxEditor() {\n return useRef<DocxEditorHandle | null>(null)\n}\n\nexport type { DocxEditorHandle, DocxEditorOptions } from './sdk'\n\n/** Read-only companion, with the same rendering and lifecycle as the editor. */\nexport const DocxViewer = forwardRef<DocxEditorHandle | null, DocxEditorProps>(function DocxViewer(props, ref) {\n return <DocxEditor {...props} ref={ref} chrome=\"viewer\" readOnly />\n})\n\nexport const DOCX_LOCKING_VERSION = 1\n"],"names":["DocxEditor","forwardRef","src","className","style","onReady","options","ref","host","useRef","handle","latest","give","h","useEffect","createDocxEditor","b","context","e","state","report","feedback","jsx","useDocxEditor","DocxViewer","props","DOCX_LOCKING_VERSION"],"mappings":"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"}
@@ -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
  *
@@ -23,3 +23,4 @@ export type { BadgeDisplay } from './variables';
23
23
  export type { Draft } from './drafts';
24
24
  export type { Panel } from './ui/shell';
25
25
  export { createDocxViewer } from './sdk';
26
+ export type { DocxLockAdapter, DocxLockState, DocxLockResult } from './locking';
@@ -0,0 +1,37 @@
1
+ export type DocxLockState = {
2
+ status: 'idle' | 'acquiring' | 'held' | 'blocked' | 'lost' | 'released' | 'releasing';
3
+ owner?: string;
4
+ message?: string;
5
+ };
6
+ export type DocxLockResult = {
7
+ acquired: true;
8
+ ttlMs: number;
9
+ } | {
10
+ acquired: false;
11
+ owner?: string;
12
+ };
13
+ export interface DocxLockAdapter {
14
+ acquire(sessionId: string): Promise<DocxLockResult>;
15
+ renew(sessionId: string): Promise<DocxLockResult>;
16
+ release(sessionId: string): Promise<void>;
17
+ read(sessionId: string): Promise<Uint8Array>;
18
+ }
19
+ export declare function createDocxLock(adapter: DocxLockAdapter, host: {
20
+ dirty(): boolean;
21
+ load(bytes: Uint8Array): Promise<void>;
22
+ save(): Promise<void>;
23
+ changed(state: DocxLockState): void;
24
+ }): {
25
+ id: `${string}-${string}-${string}-${string}-${string}`;
26
+ state: () => {
27
+ status: "idle" | "acquiring" | "held" | "blocked" | "lost" | "released" | "releasing";
28
+ owner?: string;
29
+ message?: string;
30
+ };
31
+ writable: () => boolean;
32
+ acquire: () => Promise<void>;
33
+ release: () => Promise<void>;
34
+ stopRenewing: () => void;
35
+ lost: (message?: string) => void;
36
+ destroy(): Promise<void>;
37
+ };
@@ -24,3 +24,4 @@ export declare function useDocxEditor(): import("react").RefObject<DocxEditorHan
24
24
  export type { DocxEditorHandle, DocxEditorOptions } from './sdk';
25
25
  /** Read-only companion, with the same rendering and lifecycle as the editor. */
26
26
  export declare const DocxViewer: import("react").ForwardRefExoticComponent<DocxEditorProps & import("react").RefAttributes<DocxEditorHandle | null>>;
27
+ export declare const DOCX_LOCKING_VERSION = 1;
@@ -1,3 +1,4 @@
1
+ import { type DocxLockAdapter, type DocxLockState } from './locking';
1
2
  /**
2
3
  * The SDK: one call mounts the Word-like editor in an element.
3
4
  *
@@ -23,20 +24,24 @@ import { type FeedbackOptions } from './feedback';
23
24
  export type ChromeMode = 'full' | 'viewer' | 'none';
24
25
  export type Theme = 'light' | 'dark' | 'system';
25
26
  export type { DocxEditorUiOptions } from './ui/shell';
26
- export type DocxEditorEvent = 'load' | 'change' | 'selection' | 'render' | 'save' | 'context' | 'zoom' | 'saveState' | 'error' | 'command';
27
+ export type DocxEditorEvent = 'load' | 'change' | 'selection' | 'render' | 'save' | 'context' | 'zoom' | 'saveState' | 'error' | 'command' | 'lock';
27
28
  export interface DocxEditorOptions {
28
29
  /** `full`: ribbon, rulers, panels. `viewer`: read-only pages under a slim header. `none`: pages only. */
29
30
  /** Development host compatibility only; npm instances expose no window globals or IDs. */
30
31
  debug?: boolean;
31
32
  chrome?: ChromeMode;
32
33
  readOnly?: boolean;
34
+ lock?: DocxLockAdapter;
35
+ onLockState?: (state: DocxLockState) => void;
33
36
  theme?: Theme;
34
37
  /** directory that holds `ttf/` — see `fonts.ts` */
35
38
  fontsUrl?: string | URL;
36
39
  /** hard cap on the page count — a guard against a runaway layout, never an alignment */
37
40
  maxPages?: number;
38
41
  /** the document after a quiet period, and on tab change — where autosave goes */
39
- onSave?: (bytes: Uint8Array) => void | Promise<void>;
42
+ onSave?: (bytes: Uint8Array, context: {
43
+ lockId?: string;
44
+ }) => void | Promise<void>;
40
45
  onChange?: () => void;
41
46
  onError?: (error: Error) => void;
42
47
  onSaveState?: (state: string) => void;
@@ -90,11 +95,19 @@ export interface DocxEditorHandle {
90
95
  getZoom(): number;
91
96
  setTheme(t: Theme): void;
92
97
  setReadOnly(on: boolean): void;
98
+ lock: {
99
+ state(): DocxLockState;
100
+ acquire(): Promise<void>;
101
+ release(): Promise<void>;
102
+ } | null;
93
103
  showPanel(p: Panel | null): void;
94
104
  /** Open the feedback form; requires feedback to be enabled and a loaded document. */
95
105
  openFeedback(): void;
96
106
  /** Word's comments of the open document, with their ranges */
97
107
  comments(): CommentRange[];
108
+ addComment(text: string, author?: string): string | null;
109
+ updateComment(id: string, text: string): boolean;
110
+ deleteComment(id: string): boolean;
98
111
  showComments(on: boolean): void;
99
112
  variables: {
100
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.4",
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",
@@ -47,8 +47,8 @@
47
47
  "vite": "^6.4.3",
48
48
  "@myrole/docx-model": "0.0.0",
49
49
  "@myrole/docx-vars": "0.0.0",
50
- "@myrole/docx-render": "0.0.0",
51
50
  "@myrole/fonts": "0.1.0",
51
+ "@myrole/docx-render": "0.0.0",
52
52
  "@myrole/docx-tags": "0.0.0"
53
53
  },
54
54
  "publishConfig": {
@@ -57,7 +57,7 @@
57
57
  "scripts": {
58
58
  "fonts": "node scripts/pack-fonts.mjs",
59
59
  "build": "node scripts/pack-fonts.mjs && vite build && node scripts/types.mjs",
60
- "check": "node scripts/pack-fonts.mjs && tsc -p tsconfig.json",
60
+ "check": "node scripts/pack-fonts.mjs && tsc -p tsconfig.json && tsx scripts/locking.test.ts",
61
61
  "types": "node scripts/types.mjs"
62
62
  },
63
63
  "typesVersions": {