@langeditor/plugin-docx 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,16 @@
1
+ //#region \0rolldown/runtime.js
2
+ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescriptor, r = Object.getOwnPropertyNames, i = Object.getPrototypeOf, a = Object.prototype.hasOwnProperty, o = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), s = (e, i, o, s) => {
3
+ if (i && typeof i == "object" || typeof i == "function") for (var c = r(i), l = 0, u = c.length, d; l < u; l++) d = c[l], !a.call(e, d) && d !== o && t(e, d, {
4
+ get: ((e) => i[e]).bind(null, d),
5
+ enumerable: !(s = n(i, d)) || s.enumerable
6
+ });
7
+ return e;
8
+ }, c = (n, r, o) => (o = n == null ? {} : e(i(n)), s(r || !n || !n.__esModule || !a.call(n, "default") ? t(o, "default", {
9
+ value: n,
10
+ enumerable: !0
11
+ }) : o, n)), l = /* @__PURE__ */ ((e) => typeof require < "u" ? require : typeof Proxy < "u" ? new Proxy(e, { get: (e, t) => (typeof require < "u" ? require : e)[t] }) : e)(function(e) {
12
+ if (typeof require < "u") return require.apply(this, arguments);
13
+ throw Error("Calling `require` for \"" + e + "\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.");
14
+ });
15
+ //#endregion
16
+ export { l as n, c as r, o as t };
@@ -0,0 +1,19 @@
1
+ import { Extension, GeneralOptions } from '../../../../..';
2
+ import { ExportDocxOptions } from './docx';
3
+ declare module '@tiptap/core' {
4
+ interface Commands<ReturnType> {
5
+ exportWord: {
6
+ exportToWord: (fileName?: string) => ReturnType;
7
+ };
8
+ }
9
+ }
10
+ export interface ExportWordOptions extends GeneralOptions<ExportWordOptions>, ExportDocxOptions {
11
+ fileName: string;
12
+ }
13
+ export declare const ExportWord: Extension<ExportWordOptions, any>;
14
+ /**
15
+ * Lazily loads the DOCX serializer for consumers that need direct access.
16
+ * Keeping this wrapper async prevents Word dependencies from entering the
17
+ * editor's initial bundle.
18
+ */
19
+ export declare function createDocxDocument(...args: Parameters<(typeof import('./docx'))['createDocxDocument']>): Promise<import('docx').Document>;
@@ -0,0 +1,6 @@
1
+ import { EditorInstance as Editor, WordComment } from '../../../../..';
2
+ export interface ExportDocxOptions {
3
+ resolveImage?: (src: string) => Promise<Uint8Array>;
4
+ comments?: WordComment[];
5
+ }
6
+ export declare function createDocxDocument(editor: Editor, options?: ExportDocxOptions): Promise<import('docx').Document>;
@@ -0,0 +1,24 @@
1
+ import { Node as ProseMirrorNode } from '@tiptap/pm/model';
2
+ export interface WordExportFallbackContent {
3
+ title: string;
4
+ description?: string;
5
+ href?: string;
6
+ actionLabel?: string;
7
+ }
8
+ export interface WordExportFallbackDefinition {
9
+ /** Stable globally unique registration ID. */
10
+ id: string;
11
+ /** Tiptap node type handled by this fallback. */
12
+ nodeType: string;
13
+ /** Resolves a portable, non-interactive representation for DOCX output. */
14
+ resolve: (node: ProseMirrorNode) => WordExportFallbackContent | null;
15
+ }
16
+ /**
17
+ * Registers a portable DOCX fallback for one plugin-owned Tiptap node.
18
+ *
19
+ * The fallback is intentionally data-only. It keeps commercial and optional
20
+ * packages independent from the DOCX runtime while ensuring unsupported nodes
21
+ * never disappear or fail export without a useful representation.
22
+ */
23
+ export declare function registerWordExportFallback(definition: WordExportFallbackDefinition): () => void;
24
+ export declare function getWordExportFallbacks(): WordExportFallbackDefinition[];
@@ -0,0 +1,2 @@
1
+ export * from './ExportWord';
2
+ export * from './fallback';
@@ -0,0 +1,20 @@
1
+ import { Extension, GeneralOptions } from '../../../../..';
2
+ export interface WordImageUploadResult {
3
+ src: string;
4
+ }
5
+ export interface ImportWordOptions extends GeneralOptions<ImportWordOptions> {
6
+ /** Uploads imported DOCX images and returns their stable application URLs. */
7
+ upload?: (files: File[]) => Promise<WordImageUploadResult[]>;
8
+ /** Maximum DOCX size accepted by the browser parser. */
9
+ limit: number;
10
+ }
11
+ declare module '@tiptap/core' {
12
+ interface Commands<ReturnType> {
13
+ importWord: {
14
+ toggleImportWord: () => ReturnType;
15
+ };
16
+ }
17
+ }
18
+ export declare const ImportWord: Extension<ImportWordOptions, any>;
19
+ /** Lazily loads the DOCX parser for direct consumers. */
20
+ export declare function parseDocx(...args: Parameters<(typeof import('./docx'))['parseDocx']>): Promise<import('./docx').DocxImportResult>;
@@ -0,0 +1,13 @@
1
+ import { JSONContent, WordComment } from '../../../../..';
2
+ export interface DocxImageAsset {
3
+ file: File;
4
+ dataUrl: string;
5
+ target: string;
6
+ }
7
+ export interface DocxImportResult {
8
+ content: JSONContent;
9
+ images: DocxImageAsset[];
10
+ comments: WordComment[];
11
+ warnings: string[];
12
+ }
13
+ export declare function parseDocx(file: File): Promise<DocxImportResult>;
@@ -0,0 +1 @@
1
+ export * from './ImportWord';
@@ -0,0 +1,4 @@
1
+ export * from './manifest';
2
+ export * from './plugin';
3
+ export * from './extensions/ExportWord';
4
+ export * from './extensions/ImportWord';
@@ -0,0 +1,226 @@
1
+ import { ActionButton as e, Extension as t, registerEditorPlugin as n, useLocale as r, useToast as i } from "@langeditor/core";
2
+ import { computed as a, getCurrentScope as o, onScopeDispose as s, readonly as c, ref as l, toValue as u, watchEffect as d } from "vue";
3
+ //#region src/extensions/ExportWord/ExportWord.ts
4
+ function f(e, t) {
5
+ let n = URL.createObjectURL(e), r = document.createElement("a");
6
+ r.href = n, r.download = t, r.click(), queueMicrotask(() => URL.revokeObjectURL(n));
7
+ }
8
+ var p = t.create({
9
+ name: "exportWord",
10
+ addOptions() {
11
+ return {
12
+ ...this.parent?.(),
13
+ fileName: "document.docx",
14
+ resolveImage: void 0,
15
+ button: ({ editor: t, t: n }) => ({
16
+ component: e,
17
+ componentProps: {
18
+ action: () => t.commands.exportToWord(),
19
+ icon: "FileDown",
20
+ tooltip: n("editor.exportWord.tooltip")
21
+ }
22
+ })
23
+ };
24
+ },
25
+ addCommands() {
26
+ return { exportToWord: (e) => ({ editor: t }) => (Promise.all([import("./chunks/dist-CCgJdXY1.js"), import("./chunks/docx-LNMvqtvT.js")]).then(async ([{ Packer: e }, { createDocxDocument: n }]) => e.toBlob(await n(t, this.options))).then((t) => {
27
+ if (!t.size) throw Error("The Word document is empty");
28
+ f(t, e || this.options.fileName);
29
+ }).catch((e) => console.error("Failed to export Word document:", e)), !0) };
30
+ }
31
+ });
32
+ async function m(...e) {
33
+ return (await import("./chunks/docx-LNMvqtvT.js")).createDocxDocument(...e);
34
+ }
35
+ //#endregion
36
+ //#region src/extensions/ExportWord/fallback.ts
37
+ var h = "__LANGEDITOR_WORD_EXPORT_FALLBACKS__";
38
+ function g() {
39
+ let e = globalThis;
40
+ return e[h] ??= /* @__PURE__ */ new Map(), e[h];
41
+ }
42
+ function _(e) {
43
+ if (!e.id || !e.nodeType || typeof e.resolve != "function") throw Error("Invalid LangEditor Word export fallback definition");
44
+ let t = g();
45
+ return t.set(e.id, e), () => {
46
+ t.get(e.id) === e && t.delete(e.id);
47
+ };
48
+ }
49
+ function v() {
50
+ return Array.from(g().values());
51
+ }
52
+ //#endregion
53
+ //#region ../../node_modules/.pnpm/@vueuse+shared@14.4.0_vue@3.5.41_typescript@6.0.3_/node_modules/@vueuse/shared/dist/index.js
54
+ function y(e, t) {
55
+ return o() ? (s(e, t), !0) : !1;
56
+ }
57
+ function b() {
58
+ let e = /* @__PURE__ */ new Set(), t = (t) => {
59
+ e.delete(t);
60
+ };
61
+ return {
62
+ on: (n) => {
63
+ e.add(n);
64
+ let r = () => t(n);
65
+ return y(r), { off: r };
66
+ },
67
+ off: t,
68
+ trigger: (...t) => Promise.all(Array.from(e).map((e) => e(...t))),
69
+ clear: () => {
70
+ e.clear();
71
+ }
72
+ };
73
+ }
74
+ var x = typeof window < "u" && typeof document < "u";
75
+ typeof WorkerGlobalScope < "u" && globalThis instanceof WorkerGlobalScope;
76
+ var S = (e, t) => Object.hasOwn(e, t), C = x ? window.document : void 0;
77
+ x && window.navigator, x && window.location;
78
+ function w(e) {
79
+ let t = u(e);
80
+ return t?.$el ?? t;
81
+ }
82
+ var T = {
83
+ multiple: !0,
84
+ accept: "*",
85
+ reset: !1,
86
+ directory: !1
87
+ };
88
+ function E(e) {
89
+ if (!e) return null;
90
+ if (e instanceof FileList) return e;
91
+ let t = new DataTransfer();
92
+ for (let n of e) t.items.add(n);
93
+ return t.files;
94
+ }
95
+ function D(e = {}) {
96
+ let { document: t = C } = e, n = l(E(e.initialFiles)), { on: r, trigger: i } = b(), { on: o, trigger: s } = b(), f = a(() => {
97
+ let r = w(e.input) ?? (t ? t.createElement("input") : void 0);
98
+ return r && (r.type = "file", r.onchange = (e) => {
99
+ let t = e.target;
100
+ n.value = t.files, i(n.value);
101
+ }, r.oncancel = () => {
102
+ s();
103
+ }), r;
104
+ }), p = () => {
105
+ n.value = null, f.value && f.value.value && (f.value.value = "", i(null));
106
+ }, m = (e) => {
107
+ let t = f.value;
108
+ t && (t.multiple = u(e.multiple), t.accept = u(e.accept), t.webkitdirectory = u(e.directory), S(e, "capture") && (t.capture = u(e.capture)));
109
+ };
110
+ return d(() => {
111
+ m(e);
112
+ }), {
113
+ files: c(n),
114
+ open: (t) => {
115
+ let n = f.value;
116
+ if (!n) return;
117
+ let r = {
118
+ ...T,
119
+ ...e,
120
+ ...t
121
+ };
122
+ m(r), u(r.reset) && p(), n.click();
123
+ },
124
+ reset: p,
125
+ onCancel: o,
126
+ onChange: r
127
+ };
128
+ }
129
+ //#endregion
130
+ //#region src/extensions/ImportWord/ImportWord.ts
131
+ function O(e, t, n) {
132
+ let r = new Map(t.map((e, t) => [e.dataUrl, n[t]?.src]).filter((e) => !!e[1])), i = (e) => {
133
+ e.type === "image" && typeof e.attrs?.src == "string" && (e.attrs.src = r.get(e.attrs.src) || e.attrs.src);
134
+ for (let t of e.content ?? []) i(t);
135
+ };
136
+ i(e);
137
+ }
138
+ var k = t.create({
139
+ name: "importWord",
140
+ addOptions() {
141
+ return {
142
+ ...this.parent?.(),
143
+ upload: void 0,
144
+ limit: 26214400,
145
+ button: ({ editor: t, t: n }) => ({
146
+ component: e,
147
+ componentProps: {
148
+ action: () => t.commands.toggleImportWord(),
149
+ disabled: !t.can().setHorizontalRule(),
150
+ icon: "FileUp",
151
+ tooltip: n("editor.importWord.tooltip")
152
+ }
153
+ })
154
+ };
155
+ },
156
+ addCommands() {
157
+ return { toggleImportWord: () => ({ editor: e }) => {
158
+ let { toast: t } = i(), { t: n } = r(), { open: a, onChange: o } = D({
159
+ accept: ".docx,application/vnd.openxmlformats-officedocument.wordprocessingml.document",
160
+ reset: !0,
161
+ multiple: !1
162
+ });
163
+ return a(), o(async (r) => {
164
+ let i = r?.[0];
165
+ if (i) {
166
+ if (!i.name.toLowerCase().endsWith(".docx")) {
167
+ t({
168
+ title: n.value("editor.importWord.error"),
169
+ variant: "destructive"
170
+ });
171
+ return;
172
+ }
173
+ if (i.size > this.options.limit) {
174
+ t({
175
+ title: n.value("editor.importWord.fileTooLarge"),
176
+ variant: "destructive"
177
+ });
178
+ return;
179
+ }
180
+ try {
181
+ let { parseDocx: r } = await import("./chunks/docx-CTc58_gh.js"), a = await r(i), o = this.options.upload;
182
+ if (o && a.images.length) {
183
+ let e = await o(a.images.map((e) => e.file));
184
+ O(a.content, a.images, e);
185
+ }
186
+ e.commands.setContent(a.content, { emitUpdate: !0 }), e.view.dispatch(e.state.tr.setMeta("word-comments:import", a.comments)), a.warnings.length && console.warn("[LangEditor] DOCX import warnings:", a.warnings), t({ title: n.value("editor.importWord.success") });
187
+ } catch (e) {
188
+ console.error("Failed to import DOCX:", e), t({
189
+ title: n.value("editor.importWord.error"),
190
+ variant: "destructive"
191
+ });
192
+ }
193
+ }
194
+ }), !1;
195
+ } };
196
+ }
197
+ });
198
+ async function A(...e) {
199
+ return (await import("./chunks/docx-CTc58_gh.js")).parseDocx(...e);
200
+ }
201
+ //#endregion
202
+ //#region src/manifest.ts
203
+ var j = "@langeditor/plugin-docx", M = {
204
+ id: j,
205
+ version: "1.0.0",
206
+ coreRange: ">=1.1.0 <2.0.0",
207
+ requires: [],
208
+ conflicts: [],
209
+ provides: [
210
+ "serializer:docx",
211
+ "import:docx",
212
+ "export:docx"
213
+ ],
214
+ enhances: ["document:word-comments", "document:word-pages"]
215
+ };
216
+ //#endregion
217
+ //#region src/plugin.ts
218
+ function N(e = {}) {
219
+ return [k.configure(e.importWord ?? {}), p.configure(e.exportWord ?? {})];
220
+ }
221
+ var P = n({
222
+ ...M,
223
+ create: ({ options: e }) => ({ extensions: N(e.docx ?? {}) })
224
+ });
225
+ //#endregion
226
+ export { j as DOCX_PLUGIN_ID, p as ExportWord, k as ImportWord, m as createDocxDocument, N as createDocxExtensions, M as docxManifest, v as getWordExportFallbacks, A as parseDocx, _ as registerWordExportFallback, P as unregisterDocxPlugin };
@@ -0,0 +1,10 @@
1
+ export declare const DOCX_PLUGIN_ID = "@langeditor/plugin-docx";
2
+ export declare const docxManifest: {
3
+ id: string;
4
+ version: string;
5
+ coreRange: string;
6
+ requires: string[];
7
+ conflicts: string[];
8
+ provides: string[];
9
+ enhances: string[];
10
+ };
@@ -0,0 +1,9 @@
1
+ import { ExportWordOptions } from './extensions/ExportWord';
2
+ import { ImportWordOptions } from './extensions/ImportWord';
3
+ export interface DocxPluginOptions {
4
+ importWord?: Partial<ImportWordOptions>;
5
+ exportWord?: Partial<ExportWordOptions>;
6
+ }
7
+ declare function createDocxExtensions(options?: DocxPluginOptions): (import('@tiptap/core').Extension<ExportWordOptions, any> | import('@tiptap/core').Extension<ImportWordOptions, any>)[];
8
+ export declare const unregisterDocxPlugin: () => void;
9
+ export { createDocxExtensions };
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@langeditor/plugin-docx",
3
+ "version": "1.0.0",
4
+ "description": "DOCX import and export extensions for LangEditor.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": [
8
+ "./dist/index.es.js"
9
+ ],
10
+ "main": "./dist/index.es.js",
11
+ "module": "./dist/index.es.js",
12
+ "types": "./dist/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.es.js"
17
+ },
18
+ "./package.json": "./package.json"
19
+ },
20
+ "scripts": {
21
+ "build": "vite build",
22
+ "typecheck": "vue-tsc --noEmit -p tsconfig.json"
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "README.md",
27
+ "PRD.md",
28
+ "LICENSE",
29
+ "package.json"
30
+ ],
31
+ "peerDependencies": {
32
+ "@langeditor/core": ">=1.1.0 <2.0.0",
33
+ "@tiptap/core": "^3.30.2",
34
+ "vue": ">=3.5.0"
35
+ },
36
+ "dependencies": {
37
+ "@vueuse/core": "^14.4.0",
38
+ "docx": "^9.7.1",
39
+ "jszip": "^3.10.1",
40
+ "prosemirror-docx": "^0.6.1"
41
+ },
42
+ "devDependencies": {
43
+ "@langeditor/core": "workspace:*",
44
+ "@tailwindcss/vite": "^4.3.3",
45
+ "@vitejs/plugin-vue": "^6.0.8",
46
+ "tailwindcss": "^4.3.3",
47
+ "typescript": "~6.0.2",
48
+ "vite": "^8.2.2",
49
+ "vite-plugin-dts": "^5.0.3",
50
+ "vue": "^3.5.41",
51
+ "vue-tsc": "^3.1.0"
52
+ },
53
+ "publishConfig": {
54
+ "access": "public"
55
+ }
56
+ }