@windoc/react 0.1.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 (73) hide show
  1. package/dist/index.d.mts +393 -0
  2. package/dist/index.d.ts +393 -0
  3. package/dist/index.js +1661 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/index.mjs +1582 -0
  6. package/dist/index.mjs.map +1 -0
  7. package/package.json +39 -0
  8. package/src/styles/editor.css +1786 -0
  9. package/src/styles/images/alignment.svg +1 -0
  10. package/src/styles/images/arrow-left.svg +1 -0
  11. package/src/styles/images/arrow-right.svg +1 -0
  12. package/src/styles/images/block.svg +1 -0
  13. package/src/styles/images/bold.svg +1 -0
  14. package/src/styles/images/catalog.svg +1 -0
  15. package/src/styles/images/center.svg +1 -0
  16. package/src/styles/images/checkbox.svg +1 -0
  17. package/src/styles/images/close.svg +1 -0
  18. package/src/styles/images/codeblock.svg +1 -0
  19. package/src/styles/images/color.svg +1 -0
  20. package/src/styles/images/column.svg +4 -0
  21. package/src/styles/images/control.svg +1 -0
  22. package/src/styles/images/date.svg +1 -0
  23. package/src/styles/images/exit-fullscreen.svg +1 -0
  24. package/src/styles/images/format.svg +1 -0
  25. package/src/styles/images/highlight.svg +1 -0
  26. package/src/styles/images/hyperlink.svg +1 -0
  27. package/src/styles/images/image.svg +1 -0
  28. package/src/styles/images/insert-element.svg +5 -0
  29. package/src/styles/images/italic.svg +1 -0
  30. package/src/styles/images/justify.svg +7 -0
  31. package/src/styles/images/latex.svg +1 -0
  32. package/src/styles/images/left.svg +1 -0
  33. package/src/styles/images/line-dash-dot-dot.svg +1 -0
  34. package/src/styles/images/line-dash-dot.svg +1 -0
  35. package/src/styles/images/line-dash-large-gap.svg +1 -0
  36. package/src/styles/images/line-dash-small-gap.svg +1 -0
  37. package/src/styles/images/line-dot.svg +1 -0
  38. package/src/styles/images/line-double.svg +1 -0
  39. package/src/styles/images/line-height.svg +8 -0
  40. package/src/styles/images/line-single.svg +1 -0
  41. package/src/styles/images/line-wavy.svg +1 -0
  42. package/src/styles/images/list.svg +1 -0
  43. package/src/styles/images/option.svg +1 -0
  44. package/src/styles/images/page-break.svg +1 -0
  45. package/src/styles/images/page-mode.svg +1 -0
  46. package/src/styles/images/page-scale-add.svg +1 -0
  47. package/src/styles/images/page-scale-minus.svg +1 -0
  48. package/src/styles/images/painter.svg +1 -0
  49. package/src/styles/images/paper-direction.svg +1 -0
  50. package/src/styles/images/paper-margin.svg +1 -0
  51. package/src/styles/images/paper-size.svg +1 -0
  52. package/src/styles/images/print.svg +1 -0
  53. package/src/styles/images/radio.svg +4 -0
  54. package/src/styles/images/redo.svg +1 -0
  55. package/src/styles/images/request-fullscreen.svg +1 -0
  56. package/src/styles/images/right.svg +1 -0
  57. package/src/styles/images/row-margin.svg +1 -0
  58. package/src/styles/images/search.svg +1 -0
  59. package/src/styles/images/separator.svg +1 -0
  60. package/src/styles/images/signature-undo.svg +1 -0
  61. package/src/styles/images/signature.svg +1 -0
  62. package/src/styles/images/size-add.svg +1 -0
  63. package/src/styles/images/size-minus.svg +1 -0
  64. package/src/styles/images/strikeout.svg +1 -0
  65. package/src/styles/images/subscript.svg +1 -0
  66. package/src/styles/images/superscript.svg +1 -0
  67. package/src/styles/images/table.svg +1 -0
  68. package/src/styles/images/title.svg +1 -0
  69. package/src/styles/images/trash.svg +1 -0
  70. package/src/styles/images/underline.svg +1 -0
  71. package/src/styles/images/undo.svg +1 -0
  72. package/src/styles/images/watermark.svg +1 -0
  73. package/src/styles/images/word-tool.svg +1 -0
package/dist/index.mjs ADDED
@@ -0,0 +1,1582 @@
1
+ // src/Editor.tsx
2
+ import { useEffect as useEffect7, useRef as useRef7, useState as useState21 } from "react";
3
+
4
+ // src/EditorContext.tsx
5
+ import { createContext, useContext, useEffect, useState } from "react";
6
+ import { jsx } from "react/jsx-runtime";
7
+ var EditorContext = createContext(null);
8
+ function EditorProvider({
9
+ editorRef,
10
+ rangeStyle,
11
+ children
12
+ }) {
13
+ const [isApple, setIsApple] = useState(false);
14
+ useEffect(() => {
15
+ setIsApple(/Mac OS X/.test(navigator.userAgent));
16
+ }, []);
17
+ return /* @__PURE__ */ jsx(EditorContext.Provider, { value: { editorRef, isApple, rangeStyle }, children });
18
+ }
19
+ function useEditor() {
20
+ const ctx = useContext(EditorContext);
21
+ if (!ctx) throw new Error("useEditor must be used within EditorProvider");
22
+ return ctx;
23
+ }
24
+
25
+ // src/FooterContext.tsx
26
+ import { createContext as createContext2, useContext as useContext2, useState as useState2 } from "react";
27
+ import { jsx as jsx2 } from "react/jsx-runtime";
28
+ var FooterContext = createContext2(null);
29
+ function FooterProvider({
30
+ handleToggleCatalogAction,
31
+ children
32
+ }) {
33
+ const [pageNoList, setPageNoList] = useState2("1");
34
+ const [pageNo, setPageNo] = useState2(1);
35
+ const [pageSize, setPageSize] = useState2(1);
36
+ const [wordCount, setWordCount] = useState2(0);
37
+ const [rowNo, setRowNo] = useState2(0);
38
+ const [colNo, setColNo] = useState2(0);
39
+ const [pageScale, setPageScale] = useState2(100);
40
+ return /* @__PURE__ */ jsx2(FooterContext.Provider, { value: {
41
+ pageNoList,
42
+ pageNo,
43
+ pageSize,
44
+ wordCount,
45
+ rowNo,
46
+ colNo,
47
+ pageScale,
48
+ setPageNoList,
49
+ setPageNo,
50
+ setPageSize,
51
+ setWordCount,
52
+ setRowNo,
53
+ setColNo,
54
+ setPageScale,
55
+ handleToggleCatalogAction
56
+ }, children });
57
+ }
58
+ function useFooter() {
59
+ const ctx = useContext2(FooterContext);
60
+ if (!ctx) throw new Error("useFooter must be used within FooterProvider");
61
+ return ctx;
62
+ }
63
+
64
+ // src/toolbar/UndoTool.tsx
65
+ import { Undo } from "lucide-react";
66
+ import { jsx as jsx3 } from "react/jsx-runtime";
67
+ function UndoTool() {
68
+ const { editorRef, isApple, rangeStyle } = useEditor();
69
+ const isDisabled = rangeStyle ? !rangeStyle.undo : true;
70
+ return /* @__PURE__ */ jsx3(
71
+ "div",
72
+ {
73
+ className: `menu-item__undo${isDisabled ? " disabled" : ""}`,
74
+ title: `Undo(${isApple ? "\u2318" : "Ctrl"}+Z)`,
75
+ onClick: () => {
76
+ if (!isDisabled) editorRef.current?.command.executeUndo();
77
+ },
78
+ children: /* @__PURE__ */ jsx3(Undo, { size: 16 })
79
+ }
80
+ );
81
+ }
82
+
83
+ // src/toolbar/RedoTool.tsx
84
+ import { Redo } from "lucide-react";
85
+ import { jsx as jsx4 } from "react/jsx-runtime";
86
+ function RedoTool() {
87
+ const { editorRef, isApple, rangeStyle } = useEditor();
88
+ const isDisabled = rangeStyle ? !rangeStyle.redo : true;
89
+ return /* @__PURE__ */ jsx4(
90
+ "div",
91
+ {
92
+ className: `menu-item__redo${isDisabled ? " disabled" : ""}`,
93
+ title: `Redo(${isApple ? "\u2318" : "Ctrl"}+Y)`,
94
+ onClick: () => {
95
+ if (!isDisabled) editorRef.current?.command.executeRedo();
96
+ },
97
+ children: /* @__PURE__ */ jsx4(Redo, { size: 16 })
98
+ }
99
+ );
100
+ }
101
+
102
+ // src/toolbar/ColumnTool.tsx
103
+ import { useState as useState3 } from "react";
104
+ import { Fragment, jsx as jsx5, jsxs } from "react/jsx-runtime";
105
+ function ColumnTool() {
106
+ const { editorRef } = useEditor();
107
+ const [visible, setVisible] = useState3(false);
108
+ const [currentColumns, setCurrentColumns] = useState3(1);
109
+ const [gap, setGap] = useState3(20);
110
+ const handleColumn = (col) => {
111
+ editorRef.current?.command.executeColumnCount(col);
112
+ setCurrentColumns(col);
113
+ setVisible(false);
114
+ };
115
+ const handleGapChange = (value) => {
116
+ const clampedValue = Math.max(0, Math.min(100, value));
117
+ setGap(clampedValue);
118
+ editorRef.current?.command.executeColumnGap(clampedValue);
119
+ };
120
+ return /* @__PURE__ */ jsxs("div", { className: "menu-item__column", onClick: () => setVisible(!visible), children: [
121
+ /* @__PURE__ */ jsx5("span", { className: "select", title: "Column Layout", children: currentColumns === 1 ? "1 Column" : `${currentColumns} Columns` }),
122
+ /* @__PURE__ */ jsxs(
123
+ "div",
124
+ {
125
+ className: `options ${visible ? "visible" : ""}`,
126
+ onClick: (e) => e.stopPropagation(),
127
+ children: [
128
+ /* @__PURE__ */ jsxs("ul", { children: [
129
+ /* @__PURE__ */ jsx5("li", { onClick: () => handleColumn(1), children: "1 Column" }),
130
+ /* @__PURE__ */ jsx5("li", { onClick: () => handleColumn(2), children: "2 Columns" })
131
+ ] }),
132
+ currentColumns > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
133
+ /* @__PURE__ */ jsx5("div", { className: "option-divider" }),
134
+ /* @__PURE__ */ jsxs("div", { className: "option-row", children: [
135
+ /* @__PURE__ */ jsx5("label", { children: "Gap (px)" }),
136
+ /* @__PURE__ */ jsx5(
137
+ "input",
138
+ {
139
+ type: "number",
140
+ min: 0,
141
+ max: 100,
142
+ value: gap,
143
+ onChange: (e) => handleGapChange(Number(e.target.value)),
144
+ onClick: (e) => e.stopPropagation()
145
+ }
146
+ )
147
+ ] })
148
+ ] })
149
+ ]
150
+ }
151
+ )
152
+ ] });
153
+ }
154
+
155
+ // src/toolbar/TableTool.tsx
156
+ import { useState as useState4, useEffect as useEffect2, useRef } from "react";
157
+ import { Table } from "lucide-react";
158
+ import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
159
+ function TableTool() {
160
+ const { editorRef } = useEditor();
161
+ const [visible, setVisible] = useState4(false);
162
+ const [hoverRow, setHoverRow] = useState4(0);
163
+ const [hoverCol, setHoverCol] = useState4(0);
164
+ const containerRef = useRef(null);
165
+ useEffect2(() => {
166
+ if (!visible) return;
167
+ const handleClickOutside = (e) => {
168
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
169
+ setVisible(false);
170
+ setHoverRow(0);
171
+ setHoverCol(0);
172
+ }
173
+ };
174
+ document.addEventListener("mousedown", handleClickOutside);
175
+ return () => document.removeEventListener("mousedown", handleClickOutside);
176
+ }, [visible]);
177
+ const handleInsertTable = () => {
178
+ if (hoverRow > 0 && hoverCol > 0) {
179
+ editorRef.current?.command.executeInsertTable(hoverRow, hoverCol);
180
+ }
181
+ setVisible(false);
182
+ setHoverRow(0);
183
+ setHoverCol(0);
184
+ };
185
+ return /* @__PURE__ */ jsxs2("div", { ref: containerRef, className: "menu-item__table", title: "Table", children: [
186
+ /* @__PURE__ */ jsx6(Table, { size: 16, onClick: () => setVisible(!visible), style: { cursor: "pointer" } }),
187
+ visible && /* @__PURE__ */ jsxs2("div", { className: "table-dropdown", children: [
188
+ /* @__PURE__ */ jsx6("div", { className: "table-dropdown-header", children: /* @__PURE__ */ jsx6("span", { children: hoverRow > 0 ? `${hoverRow} \xD7 ${hoverCol}` : "Insert Table" }) }),
189
+ /* @__PURE__ */ jsx6("div", { className: "table-dropdown-grid", onClick: handleInsertTable, children: Array.from({ length: 8 }).map((_, rowIdx) => /* @__PURE__ */ jsx6("div", { className: "table-dropdown-row", children: Array.from({ length: 8 }).map((_2, colIdx) => /* @__PURE__ */ jsx6(
190
+ "div",
191
+ {
192
+ className: `table-dropdown-cell ${rowIdx < hoverRow && colIdx < hoverCol ? "active" : ""}`,
193
+ onMouseEnter: () => {
194
+ setHoverRow(rowIdx + 1);
195
+ setHoverCol(colIdx + 1);
196
+ }
197
+ },
198
+ colIdx
199
+ )) }, rowIdx)) })
200
+ ] })
201
+ ] });
202
+ }
203
+
204
+ // src/toolbar/TitleTool.tsx
205
+ import { useState as useState5 } from "react";
206
+ import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
207
+ var LEVELS = [
208
+ { level: null, label: "Body" },
209
+ { level: "first", label: "Heading 1" },
210
+ { level: "second", label: "Heading 2" },
211
+ { level: "third", label: "Heading 3" },
212
+ { level: "fourth", label: "Heading 4" },
213
+ { level: "fifth", label: "Heading 5" },
214
+ { level: "sixth", label: "Heading 6" }
215
+ ];
216
+ function TitleTool() {
217
+ const { editorRef, rangeStyle } = useEditor();
218
+ const [visible, setVisible] = useState5(false);
219
+ const activeLevel = rangeStyle?.level || null;
220
+ const activeLabel = LEVELS.find((l) => l.level === activeLevel)?.label || "Body";
221
+ const handleTitle = (level) => {
222
+ editorRef.current?.command.executeTitle(level);
223
+ setVisible(false);
224
+ };
225
+ return /* @__PURE__ */ jsxs3("div", { className: "menu-item__title", onClick: () => setVisible(!visible), children: [
226
+ /* @__PURE__ */ jsx7("span", { className: "select", title: "Toggle Heading", children: activeLabel }),
227
+ /* @__PURE__ */ jsx7("div", { className: `options ${visible ? "visible" : ""}`, children: /* @__PURE__ */ jsx7("ul", { children: LEVELS.map(({ level, label }) => /* @__PURE__ */ jsx7(
228
+ "li",
229
+ {
230
+ className: activeLevel === level ? "active" : "",
231
+ ...level ? { "data-level": level } : {},
232
+ onClick: () => handleTitle(level),
233
+ children: label
234
+ },
235
+ label
236
+ )) }) })
237
+ ] });
238
+ }
239
+
240
+ // src/toolbar/FontTool.tsx
241
+ import { useState as useState6 } from "react";
242
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
243
+ var FONTS = [
244
+ { family: "Arial", label: "Sans Serif" },
245
+ { family: "Times New Roman", label: "Serif" }
246
+ ];
247
+ function FontTool() {
248
+ const { editorRef, rangeStyle } = useEditor();
249
+ const [visible, setVisible] = useState6(false);
250
+ const activeFont = rangeStyle?.font || "Arial";
251
+ const activeLabel = FONTS.find((f) => f.family === activeFont)?.label || activeFont;
252
+ const handleFont = (family) => {
253
+ editorRef.current?.command.executeFont(family);
254
+ setVisible(false);
255
+ };
256
+ return /* @__PURE__ */ jsxs4("div", { className: "menu-item__font", onClick: () => setVisible(!visible), children: [
257
+ /* @__PURE__ */ jsx8("span", { className: "select", title: "Font", children: activeLabel }),
258
+ /* @__PURE__ */ jsx8("div", { className: `options ${visible ? "visible" : ""}`, children: /* @__PURE__ */ jsx8("ul", { children: FONTS.map(({ family, label }) => /* @__PURE__ */ jsx8(
259
+ "li",
260
+ {
261
+ "data-family": family,
262
+ className: activeFont === family ? "active" : "",
263
+ style: { fontFamily: family },
264
+ onClick: () => handleFont(family),
265
+ children: label
266
+ },
267
+ family
268
+ )) }) })
269
+ ] });
270
+ }
271
+
272
+ // src/toolbar/FontSizeTool.tsx
273
+ import { useState as useState7 } from "react";
274
+ import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
275
+ var SIZES = [56, 48, 34, 32, 29, 24, 21, 20, 18, 16, 14, 12, 10, 8];
276
+ function FontSizeTool() {
277
+ const { editorRef, rangeStyle } = useEditor();
278
+ const [visible, setVisible] = useState7(false);
279
+ const activeSize = rangeStyle?.size ?? 16;
280
+ const handleSize = (size) => {
281
+ editorRef.current?.command.executeSize(size);
282
+ setVisible(false);
283
+ };
284
+ return /* @__PURE__ */ jsxs5("div", { className: "menu-item__size", onClick: () => setVisible(!visible), children: [
285
+ /* @__PURE__ */ jsx9("span", { className: "select", title: "Font Size", children: activeSize }),
286
+ /* @__PURE__ */ jsx9("div", { className: `options ${visible ? "visible" : ""}`, children: /* @__PURE__ */ jsx9("ul", { children: SIZES.map((size) => /* @__PURE__ */ jsx9(
287
+ "li",
288
+ {
289
+ className: activeSize === size ? "active" : "",
290
+ onClick: () => handleSize(size),
291
+ children: size
292
+ },
293
+ size
294
+ )) }) })
295
+ ] });
296
+ }
297
+
298
+ // src/toolbar/LineHeightTool.tsx
299
+ import { useState as useState8 } from "react";
300
+ import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
301
+ var LINE_HEIGHTS = ["1.0", "1.15", "1.5", "2.0", "2.5"];
302
+ function LineHeightTool() {
303
+ const { editorRef, rangeStyle } = useEditor();
304
+ const [visible, setVisible] = useState8(false);
305
+ const activeMargin = rangeStyle?.rowMargin ?? 1;
306
+ const activeLabel = Number.isInteger(activeMargin) ? `${activeMargin}.0` : String(activeMargin);
307
+ const handleLineHeight = (value) => {
308
+ editorRef.current?.command.executeRowMargin(Number(value));
309
+ setVisible(false);
310
+ };
311
+ return /* @__PURE__ */ jsxs6("div", { className: "menu-item__line-height", onClick: () => setVisible(!visible), children: [
312
+ /* @__PURE__ */ jsx10("span", { className: "select", title: "Line Height", children: activeLabel }),
313
+ /* @__PURE__ */ jsx10("div", { className: `options ${visible ? "visible" : ""}`, children: /* @__PURE__ */ jsx10("ul", { children: LINE_HEIGHTS.map((h) => /* @__PURE__ */ jsx10(
314
+ "li",
315
+ {
316
+ className: String(activeMargin) === h || activeLabel === h ? "active" : "",
317
+ onClick: () => handleLineHeight(h),
318
+ children: h
319
+ },
320
+ h
321
+ )) }) })
322
+ ] });
323
+ }
324
+
325
+ // src/toolbar/ColorTool.tsx
326
+ import { useState as useState9, useRef as useRef2, useEffect as useEffect3 } from "react";
327
+ import { Baseline, RotateCcw } from "lucide-react";
328
+ import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
329
+ var COLOR_PALETTE = [
330
+ ["#000000", "#434343", "#666666", "#999999", "#b7b7b7", "#cccccc", "#d9d9d9", "#efefef", "#f3f3f3", "#ffffff"],
331
+ ["#980000", "#ff0000", "#ff9900", "#ffff00", "#00ff00", "#00ffff", "#4a86e8", "#0000ff", "#9900ff", "#ff00ff"],
332
+ ["#e6b8af", "#f4cccc", "#fce5cd", "#fff2cc", "#d9ead3", "#d0e0e3", "#c9daf8", "#cfe2f3", "#d9d2e9", "#ead1dc"],
333
+ ["#dd7e6b", "#ea9999", "#f9cb9c", "#ffe599", "#b6d7a8", "#a2c4c9", "#a4c2f4", "#9fc5e8", "#b4a7d6", "#d5a6bd"],
334
+ ["#cc4125", "#e06666", "#f6b26b", "#ffd966", "#93c47d", "#76a5af", "#6d9eeb", "#6fa8dc", "#8e7cc3", "#c27ba0"],
335
+ ["#a61c00", "#cc0000", "#e69138", "#f1c232", "#6aa84f", "#45818e", "#3c78d8", "#3d85c6", "#674ea7", "#a64d79"],
336
+ ["#85200c", "#990000", "#b45f06", "#bf9000", "#38761d", "#134f5c", "#1155cc", "#0b5394", "#351c75", "#741b47"],
337
+ ["#5b0f00", "#660000", "#783f04", "#7f6000", "#274e13", "#0c343d", "#1c4587", "#073763", "#20124d", "#4c1130"]
338
+ ];
339
+ function ColorTool() {
340
+ const { editorRef, rangeStyle } = useEditor();
341
+ const [visible, setVisible] = useState9(false);
342
+ const containerRef = useRef2(null);
343
+ const activeColor = rangeStyle?.color || "#000000";
344
+ useEffect3(() => {
345
+ if (!visible) return;
346
+ const handler = (e) => {
347
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
348
+ setVisible(false);
349
+ }
350
+ };
351
+ document.addEventListener("mousedown", handler);
352
+ return () => document.removeEventListener("mousedown", handler);
353
+ }, [visible]);
354
+ const handleColor = (color) => {
355
+ editorRef.current?.command.executeColor(color);
356
+ setVisible(false);
357
+ };
358
+ const handleReset = () => {
359
+ editorRef.current?.command.executeColor(null);
360
+ setVisible(false);
361
+ };
362
+ return /* @__PURE__ */ jsxs7("div", { className: "menu-item__color", ref: containerRef, title: "Font Color", onClick: () => setVisible(!visible), children: [
363
+ /* @__PURE__ */ jsx11(Baseline, { size: 16 }),
364
+ /* @__PURE__ */ jsx11("span", { style: { backgroundColor: activeColor } }),
365
+ /* @__PURE__ */ jsx11("input", { id: "color", type: "color", readOnly: true, tabIndex: -1 }),
366
+ visible && /* @__PURE__ */ jsxs7("div", { className: "color-palette-dropdown", onClick: (e) => e.stopPropagation(), children: [
367
+ /* @__PURE__ */ jsxs7("button", { className: "color-palette-reset", onClick: handleReset, children: [
368
+ /* @__PURE__ */ jsx11(RotateCcw, { size: 12 }),
369
+ "Reset"
370
+ ] }),
371
+ /* @__PURE__ */ jsx11("div", { className: "color-palette-grid", children: COLOR_PALETTE.map((row, ri) => /* @__PURE__ */ jsx11("div", { className: "color-palette-row", children: row.map((color) => /* @__PURE__ */ jsx11(
372
+ "div",
373
+ {
374
+ className: `color-palette-swatch${activeColor.toLowerCase() === color.toLowerCase() ? " active" : ""}`,
375
+ style: { backgroundColor: color },
376
+ onClick: () => handleColor(color),
377
+ title: color
378
+ },
379
+ color
380
+ )) }, ri)) })
381
+ ] })
382
+ ] });
383
+ }
384
+
385
+ // src/toolbar/HighlightTool.tsx
386
+ import { useState as useState10, useRef as useRef3, useEffect as useEffect4 } from "react";
387
+ import { Highlighter, RotateCcw as RotateCcw2 } from "lucide-react";
388
+ import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
389
+ var HIGHLIGHT_PALETTE = [
390
+ ["#000000", "#434343", "#666666", "#999999", "#b7b7b7", "#cccccc", "#d9d9d9", "#efefef", "#f3f3f3", "#ffffff"],
391
+ ["#980000", "#ff0000", "#ff9900", "#ffff00", "#00ff00", "#00ffff", "#4a86e8", "#0000ff", "#9900ff", "#ff00ff"],
392
+ ["#e6b8af", "#f4cccc", "#fce5cd", "#fff2cc", "#d9ead3", "#d0e0e3", "#c9daf8", "#cfe2f3", "#d9d2e9", "#ead1dc"],
393
+ ["#dd7e6b", "#ea9999", "#f9cb9c", "#ffe599", "#b6d7a8", "#a2c4c9", "#a4c2f4", "#9fc5e8", "#b4a7d6", "#d5a6bd"],
394
+ ["#cc4125", "#e06666", "#f6b26b", "#ffd966", "#93c47d", "#76a5af", "#6d9eeb", "#6fa8dc", "#8e7cc3", "#c27ba0"],
395
+ ["#a61c00", "#cc0000", "#e69138", "#f1c232", "#6aa84f", "#45818e", "#3c78d8", "#3d85c6", "#674ea7", "#a64d79"],
396
+ ["#85200c", "#990000", "#b45f06", "#bf9000", "#38761d", "#134f5c", "#1155cc", "#0b5394", "#351c75", "#741b47"],
397
+ ["#5b0f00", "#660000", "#783f04", "#7f6000", "#274e13", "#0c343d", "#1c4587", "#073763", "#20124d", "#4c1130"]
398
+ ];
399
+ function HighlightTool() {
400
+ const { editorRef, rangeStyle } = useEditor();
401
+ const [visible, setVisible] = useState10(false);
402
+ const containerRef = useRef3(null);
403
+ const activeColor = rangeStyle?.highlight || "";
404
+ useEffect4(() => {
405
+ if (!visible) return;
406
+ const handler = (e) => {
407
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
408
+ setVisible(false);
409
+ }
410
+ };
411
+ document.addEventListener("mousedown", handler);
412
+ return () => document.removeEventListener("mousedown", handler);
413
+ }, [visible]);
414
+ const handleColor = (color) => {
415
+ editorRef.current?.command.executeHighlight(color);
416
+ setVisible(false);
417
+ };
418
+ const handleReset = () => {
419
+ editorRef.current?.command.executeHighlight(null);
420
+ setVisible(false);
421
+ };
422
+ return /* @__PURE__ */ jsxs8("div", { className: "menu-item__highlight", ref: containerRef, title: "Highlight", onClick: () => setVisible(!visible), children: [
423
+ /* @__PURE__ */ jsx12(Highlighter, { size: 16 }),
424
+ /* @__PURE__ */ jsx12("span", { style: { backgroundColor: activeColor || "#ffff00" } }),
425
+ /* @__PURE__ */ jsx12("input", { id: "highlight", type: "color", readOnly: true, tabIndex: -1 }),
426
+ visible && /* @__PURE__ */ jsxs8("div", { className: "color-palette-dropdown", onClick: (e) => e.stopPropagation(), children: [
427
+ /* @__PURE__ */ jsxs8("button", { className: "color-palette-reset", onClick: handleReset, children: [
428
+ /* @__PURE__ */ jsx12(RotateCcw2, { size: 12 }),
429
+ "None"
430
+ ] }),
431
+ /* @__PURE__ */ jsx12("div", { className: "color-palette-grid", children: HIGHLIGHT_PALETTE.map((row, ri) => /* @__PURE__ */ jsx12("div", { className: "color-palette-row", children: row.map((color) => /* @__PURE__ */ jsx12(
432
+ "div",
433
+ {
434
+ className: `color-palette-swatch${activeColor && activeColor.toLowerCase() === color.toLowerCase() ? " active" : ""}`,
435
+ style: { backgroundColor: color },
436
+ onClick: () => handleColor(color),
437
+ title: color
438
+ },
439
+ color
440
+ )) }, ri)) })
441
+ ] })
442
+ ] });
443
+ }
444
+
445
+ // src/toolbar/BoldTool.tsx
446
+ import { Bold } from "lucide-react";
447
+ import { jsx as jsx13 } from "react/jsx-runtime";
448
+ function BoldTool() {
449
+ const { editorRef, isApple, rangeStyle } = useEditor();
450
+ const isActive = rangeStyle?.bold === true;
451
+ return /* @__PURE__ */ jsx13("div", { className: `menu-item__bold ${isActive ? "active" : ""}`, title: `Bold(${isApple ? "\u2318" : "Ctrl"}+B)`, onClick: () => editorRef.current?.command.executeBold(), children: /* @__PURE__ */ jsx13(Bold, { size: 16 }) });
452
+ }
453
+
454
+ // src/toolbar/ItalicTool.tsx
455
+ import { Italic } from "lucide-react";
456
+ import { jsx as jsx14 } from "react/jsx-runtime";
457
+ function ItalicTool() {
458
+ const { editorRef, isApple, rangeStyle } = useEditor();
459
+ const isActive = rangeStyle?.italic === true;
460
+ return /* @__PURE__ */ jsx14("div", { className: `menu-item__italic ${isActive ? "active" : ""}`, title: `Italic(${isApple ? "\u2318" : "Ctrl"}+I)`, onClick: () => editorRef.current?.command.executeItalic(), children: /* @__PURE__ */ jsx14(Italic, { size: 16 }) });
461
+ }
462
+
463
+ // src/toolbar/UnderlineTool.tsx
464
+ import { useState as useState11 } from "react";
465
+ import { Underline as UnderlineIcon } from "lucide-react";
466
+ import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
467
+ var STYLES = ["solid", "double", "dashed", "dotted", "wavy"];
468
+ function UnderlineTool() {
469
+ const { editorRef, isApple, rangeStyle } = useEditor();
470
+ const [visible, setVisible] = useState11(false);
471
+ const isActive = rangeStyle?.underline === true;
472
+ return /* @__PURE__ */ jsxs9("div", { className: `menu-item__underline ${isActive ? "active" : ""}`, title: `Underline(${isApple ? "\u2318" : "Ctrl"}+U)`, children: [
473
+ /* @__PURE__ */ jsx15(UnderlineIcon, { size: 16, onClick: () => editorRef.current?.command.executeUnderline(), style: { cursor: "pointer" } }),
474
+ /* @__PURE__ */ jsx15("span", { className: "select", onClick: () => setVisible(!visible) }),
475
+ /* @__PURE__ */ jsx15("div", { className: `options ${visible ? "visible" : ""}`, children: /* @__PURE__ */ jsx15("ul", { children: STYLES.map((style) => /* @__PURE__ */ jsx15("li", { "data-decoration-style": style, onClick: () => {
476
+ editorRef.current?.command.executeUnderline({ style });
477
+ setVisible(false);
478
+ }, children: /* @__PURE__ */ jsx15("i", {}) }, style)) }) })
479
+ ] });
480
+ }
481
+
482
+ // src/toolbar/StrikeoutTool.tsx
483
+ import { Strikethrough } from "lucide-react";
484
+ import { jsx as jsx16 } from "react/jsx-runtime";
485
+ function StrikeoutTool() {
486
+ const { editorRef, rangeStyle } = useEditor();
487
+ const isActive = rangeStyle?.strikeout === true;
488
+ return /* @__PURE__ */ jsx16("div", { className: `menu-item__strikeout ${isActive ? "active" : ""}`, title: "Strikethrough", onClick: () => editorRef.current?.command.executeStrikeout(), children: /* @__PURE__ */ jsx16(Strikethrough, { size: 16 }) });
489
+ }
490
+
491
+ // src/toolbar/LeftAlignTool.tsx
492
+ import { AlignLeft } from "lucide-react";
493
+ import { jsx as jsx17 } from "react/jsx-runtime";
494
+ function LeftAlignTool() {
495
+ const { editorRef, isApple, rangeStyle } = useEditor();
496
+ const isActive = !rangeStyle?.rowFlex || rangeStyle.rowFlex === "left";
497
+ return /* @__PURE__ */ jsx17("div", { className: `menu-item__left ${isActive ? "active" : ""}`, title: `Left align(${isApple ? "\u2318" : "Ctrl"}+L)`, onClick: () => editorRef.current?.command.executeRowFlex("left"), children: /* @__PURE__ */ jsx17(AlignLeft, { size: 16 }) });
498
+ }
499
+
500
+ // src/toolbar/CenterAlignTool.tsx
501
+ import { AlignCenter } from "lucide-react";
502
+ import { jsx as jsx18 } from "react/jsx-runtime";
503
+ function CenterAlignTool() {
504
+ const { editorRef, isApple, rangeStyle } = useEditor();
505
+ const isActive = rangeStyle?.rowFlex === "center";
506
+ return /* @__PURE__ */ jsx18("div", { className: `menu-item__center ${isActive ? "active" : ""}`, title: `Center align(${isApple ? "\u2318" : "Ctrl"}+E)`, onClick: () => editorRef.current?.command.executeRowFlex("center"), children: /* @__PURE__ */ jsx18(AlignCenter, { size: 16 }) });
507
+ }
508
+
509
+ // src/toolbar/RightAlignTool.tsx
510
+ import { AlignRight } from "lucide-react";
511
+ import { jsx as jsx19 } from "react/jsx-runtime";
512
+ function RightAlignTool() {
513
+ const { editorRef, isApple, rangeStyle } = useEditor();
514
+ const isActive = rangeStyle?.rowFlex === "right";
515
+ return /* @__PURE__ */ jsx19("div", { className: `menu-item__right ${isActive ? "active" : ""}`, title: `Right align(${isApple ? "\u2318" : "Ctrl"}+R)`, onClick: () => editorRef.current?.command.executeRowFlex("right"), children: /* @__PURE__ */ jsx19(AlignRight, { size: 16 }) });
516
+ }
517
+
518
+ // src/toolbar/JustifyTool.tsx
519
+ import { AlignJustify } from "lucide-react";
520
+ import { jsx as jsx20 } from "react/jsx-runtime";
521
+ function JustifyTool() {
522
+ const { editorRef, isApple, rangeStyle } = useEditor();
523
+ const isActive = rangeStyle?.rowFlex === "justify" || rangeStyle?.rowFlex === "alignment";
524
+ return /* @__PURE__ */ jsx20("div", { className: `menu-item__justify ${isActive ? "active" : ""}`, title: `Distribute(${isApple ? "\u2318" : "Ctrl"}+Shift+J)`, onClick: () => editorRef.current?.command.executeRowFlex("justify"), children: /* @__PURE__ */ jsx20(AlignJustify, { size: 16 }) });
525
+ }
526
+
527
+ // src/toolbar/ListTool.tsx
528
+ import { useState as useState12, useRef as useRef4, useEffect as useEffect5 } from "react";
529
+ import { List, ListOrdered, Indent, Outdent } from "lucide-react";
530
+ import { jsx as jsx21, jsxs as jsxs10 } from "react/jsx-runtime";
531
+ var OL_PRESETS = [
532
+ { preset: "olDefault", label: "Default", preview: ["1.", "a.", "i."] },
533
+ { preset: "olParen", label: "Parenthesis", preview: ["1)", "a)", "i)"] },
534
+ { preset: "olOutline", label: "Outline", preview: ["1.", "1.1.", "1.1.1."] },
535
+ { preset: "olUpperA", label: "Upper Alpha", preview: ["A.", "a.", "i."] },
536
+ { preset: "olRoman", label: "Roman", preview: ["I.", "A.", "1."] },
537
+ { preset: "olZeroPad", label: "Zero Pad", preview: ["01.", "a.", "i."] }
538
+ ];
539
+ var UL_PRESETS = [
540
+ { preset: "ulDefault", label: "Default", preview: ["\u25CF", "\u25CB", "\u25A0"] },
541
+ { preset: "ulDiamond", label: "Diamond", preview: ["\u25C6", "\u27A4", "\u25A0"] },
542
+ { preset: "ulHollowSq", label: "Hollow Square", preview: ["\u25A1", "\u25A1", "\u25A1"] },
543
+ { preset: "ulArrow", label: "Arrow", preview: ["\u2192", "\u25C6", "\u25CF"] },
544
+ { preset: "ulStar", label: "Star", preview: ["\u2605", "\u25CB", "\u25A0"] },
545
+ { preset: "ulCheckArr", label: "Check Arrow", preview: ["\u27A4", "\u25CB", "\u25A0"] }
546
+ ];
547
+ function PresetCell({ option, onClick }) {
548
+ return /* @__PURE__ */ jsx21(
549
+ "div",
550
+ {
551
+ onClick,
552
+ className: "list-preset-cell",
553
+ title: option.label,
554
+ children: option.preview.map((item, i) => /* @__PURE__ */ jsxs10("div", { className: "list-preset-line", style: { paddingLeft: `${i * 10}px` }, children: [
555
+ /* @__PURE__ */ jsx21("span", { className: "list-preset-marker", children: item }),
556
+ /* @__PURE__ */ jsx21("span", { className: "list-preset-text" })
557
+ ] }, i))
558
+ }
559
+ );
560
+ }
561
+ function ListTool() {
562
+ const { editorRef, isApple, rangeStyle } = useEditor();
563
+ const [visible, setVisible] = useState12(false);
564
+ const containerRef = useRef4(null);
565
+ const optionsRef = useRef4(null);
566
+ const isActive = !!rangeStyle?.listType;
567
+ useEffect5(() => {
568
+ if (!visible) return;
569
+ const handler = (e) => {
570
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
571
+ setVisible(false);
572
+ }
573
+ };
574
+ document.addEventListener("mousedown", handler);
575
+ return () => document.removeEventListener("mousedown", handler);
576
+ }, [visible]);
577
+ useEffect5(() => {
578
+ if (!visible || !optionsRef.current) return;
579
+ const el = optionsRef.current;
580
+ el.style.left = "";
581
+ el.style.right = "";
582
+ const rect = el.getBoundingClientRect();
583
+ if (rect.right > window.innerWidth) {
584
+ const overflow = rect.right - window.innerWidth + 8;
585
+ el.style.left = `-${overflow}px`;
586
+ } else if (rect.left < 0) {
587
+ el.style.left = `${-rect.left + 8}px`;
588
+ }
589
+ }, [visible]);
590
+ const handleList = (type, style) => {
591
+ editorRef.current?.command.executeList(type, style);
592
+ setVisible(false);
593
+ };
594
+ const handlePreset = (type, preset) => {
595
+ const style = type === "ol" ? "decimal" : "disc";
596
+ editorRef.current?.command.executeListWithPreset(type, style, preset);
597
+ setVisible(false);
598
+ };
599
+ const handleIndent = (e) => {
600
+ e.stopPropagation();
601
+ editorRef.current?.command.executeListIndent();
602
+ };
603
+ const handleOutdent = (e) => {
604
+ e.stopPropagation();
605
+ editorRef.current?.command.executeListOutdent();
606
+ };
607
+ return /* @__PURE__ */ jsxs10("div", { ref: containerRef, className: `menu-item__list ${isActive ? "active" : ""}`, title: `List(${isApple ? "\u2318" : "Ctrl"}+Shift+U)`, children: [
608
+ /* @__PURE__ */ jsx21(List, { size: 16, onClick: () => setVisible(!visible), style: { cursor: "pointer" } }),
609
+ /* @__PURE__ */ jsxs10("div", { ref: optionsRef, className: `options ${visible ? "visible" : ""}`, style: { padding: "8px", width: "320px" }, children: [
610
+ /* @__PURE__ */ jsxs10("div", { style: { display: "flex", gap: "4px", marginBottom: "8px" }, children: [
611
+ /* @__PURE__ */ jsx21(
612
+ "button",
613
+ {
614
+ onClick: () => handleList("ul", "checkbox"),
615
+ className: "list-quick-btn",
616
+ children: "Checkbox"
617
+ }
618
+ ),
619
+ /* @__PURE__ */ jsx21("button", { onClick: handleIndent, className: "list-quick-btn", title: "Indent (Tab)", children: /* @__PURE__ */ jsx21(Indent, { size: 14 }) }),
620
+ /* @__PURE__ */ jsx21("button", { onClick: handleOutdent, className: "list-quick-btn", title: "Outdent (Shift+Tab)", children: /* @__PURE__ */ jsx21(Outdent, { size: 14 }) })
621
+ ] }),
622
+ /* @__PURE__ */ jsxs10("div", { style: { marginBottom: "8px" }, children: [
623
+ /* @__PURE__ */ jsxs10("div", { style: { display: "flex", alignItems: "center", gap: "4px", fontSize: "11px", color: "#667085", marginBottom: "6px", fontWeight: 500 }, children: [
624
+ /* @__PURE__ */ jsx21(ListOrdered, { size: 12 }),
625
+ "Ordered List"
626
+ ] }),
627
+ /* @__PURE__ */ jsx21("div", { className: "list-preset-grid", children: OL_PRESETS.map((option) => /* @__PURE__ */ jsx21(
628
+ PresetCell,
629
+ {
630
+ option,
631
+ onClick: () => handlePreset("ol", option.preset)
632
+ },
633
+ option.preset
634
+ )) })
635
+ ] }),
636
+ /* @__PURE__ */ jsxs10("div", { children: [
637
+ /* @__PURE__ */ jsxs10("div", { style: { display: "flex", alignItems: "center", gap: "4px", fontSize: "11px", color: "#667085", marginBottom: "6px", fontWeight: 500 }, children: [
638
+ /* @__PURE__ */ jsx21(List, { size: 12 }),
639
+ "Unordered List"
640
+ ] }),
641
+ /* @__PURE__ */ jsx21("div", { className: "list-preset-grid", children: UL_PRESETS.map((option) => /* @__PURE__ */ jsx21(
642
+ PresetCell,
643
+ {
644
+ option,
645
+ onClick: () => handlePreset("ul", option.preset)
646
+ },
647
+ option.preset
648
+ )) })
649
+ ] })
650
+ ] })
651
+ ] });
652
+ }
653
+
654
+ // src/toolbar/ImageTool.tsx
655
+ import { Image as ImageIcon } from "lucide-react";
656
+ import { jsx as jsx22, jsxs as jsxs11 } from "react/jsx-runtime";
657
+ function ImageTool() {
658
+ const { editorRef } = useEditor();
659
+ const handleImageUpload = (e) => {
660
+ const file = e.target.files?.[0];
661
+ if (!file) return;
662
+ const reader = new FileReader();
663
+ reader.readAsDataURL(file);
664
+ reader.onload = () => {
665
+ const img = new Image();
666
+ img.src = reader.result;
667
+ img.onload = () => {
668
+ editorRef.current?.command.executeImage({
669
+ value: reader.result,
670
+ width: img.width,
671
+ height: img.height
672
+ });
673
+ };
674
+ };
675
+ e.target.value = "";
676
+ };
677
+ return /* @__PURE__ */ jsxs11("div", { className: "menu-item__image", onClick: () => document.getElementById("image")?.click(), children: [
678
+ /* @__PURE__ */ jsx22(ImageIcon, { size: 16 }),
679
+ /* @__PURE__ */ jsx22("input", { type: "file", id: "image", accept: ".png, .jpg, .jpeg, .svg, .gif", onChange: handleImageUpload })
680
+ ] });
681
+ }
682
+
683
+ // src/toolbar/SeparatorTool.tsx
684
+ import { useState as useState13 } from "react";
685
+ import { Minus } from "lucide-react";
686
+ import { jsx as jsx23, jsxs as jsxs12 } from "react/jsx-runtime";
687
+ var DASH_STYLES = [
688
+ { label: "Solid", dashArray: [] },
689
+ { label: "Dotted", dashArray: [1, 1] },
690
+ { label: "Dashed", dashArray: [3, 1] },
691
+ { label: "Long Dash", dashArray: [4, 4] }
692
+ ];
693
+ var LINE_WIDTHS = [
694
+ { label: "Thin", value: 1 },
695
+ { label: "Medium", value: 2 },
696
+ { label: "Thick", value: 4 }
697
+ ];
698
+ function SeparatorTool() {
699
+ const { editorRef } = useEditor();
700
+ const [visible, setVisible] = useState13(false);
701
+ const [selectedWidth, setSelectedWidth] = useState13(1);
702
+ const lineColor = "#344054";
703
+ const handleSeparator = (dashArray) => {
704
+ editorRef.current?.command.executeSeparator(dashArray, { lineWidth: selectedWidth });
705
+ setVisible(false);
706
+ };
707
+ return /* @__PURE__ */ jsxs12("div", { className: "menu-item__separator", title: "Separator", children: [
708
+ /* @__PURE__ */ jsx23(Minus, { size: 16, onClick: () => setVisible(!visible), style: { cursor: "pointer" } }),
709
+ /* @__PURE__ */ jsxs12("div", { className: `options ${visible ? "visible" : ""}`, style: { padding: "8px 10px 10px", width: "200px" }, children: [
710
+ /* @__PURE__ */ jsx23("ul", { style: { margin: 0, padding: 0, listStyle: "none" }, children: DASH_STYLES.map(({ label, dashArray }) => /* @__PURE__ */ jsxs12(
711
+ "li",
712
+ {
713
+ onClick: () => handleSeparator(dashArray),
714
+ style: { display: "flex", alignItems: "center", gap: "10px", padding: "5px 6px", cursor: "pointer", borderRadius: "4px" },
715
+ children: [
716
+ /* @__PURE__ */ jsx23("svg", { style: { flex: 1, minWidth: 0, overflow: "hidden" }, height: "8", children: /* @__PURE__ */ jsx23(
717
+ "line",
718
+ {
719
+ x1: "0",
720
+ y1: "4",
721
+ x2: "100%",
722
+ y2: "4",
723
+ stroke: lineColor,
724
+ strokeWidth: selectedWidth,
725
+ strokeDasharray: dashArray.length ? dashArray.join(",") : "none"
726
+ }
727
+ ) }),
728
+ /* @__PURE__ */ jsx23("span", { style: { fontSize: "11px", color: "#475467", whiteSpace: "nowrap", flexShrink: 0 }, children: label })
729
+ ]
730
+ },
731
+ label
732
+ )) }),
733
+ /* @__PURE__ */ jsxs12("div", { style: { borderTop: "1px solid #e4e7ec", marginTop: "8px", paddingTop: "8px" }, children: [
734
+ /* @__PURE__ */ jsx23("div", { style: { fontSize: "11px", color: "#667085", marginBottom: "6px", fontWeight: 500 }, children: "Line Width" }),
735
+ /* @__PURE__ */ jsx23("div", { style: { display: "flex", gap: "4px" }, children: LINE_WIDTHS.map(({ label, value }) => /* @__PURE__ */ jsx23(
736
+ "button",
737
+ {
738
+ onClick: (e) => {
739
+ e.stopPropagation();
740
+ setSelectedWidth(value);
741
+ },
742
+ style: {
743
+ flex: 1,
744
+ padding: "3px 6px",
745
+ fontSize: "11px",
746
+ border: `1px solid ${selectedWidth === value ? "#3b82f6" : "#d0d5dd"}`,
747
+ borderRadius: "4px",
748
+ background: selectedWidth === value ? "#eff6ff" : "#fff",
749
+ color: selectedWidth === value ? "#3b82f6" : "#475467",
750
+ cursor: "pointer",
751
+ fontWeight: selectedWidth === value ? 600 : 400
752
+ },
753
+ children: label
754
+ },
755
+ value
756
+ )) })
757
+ ] })
758
+ ] })
759
+ ] });
760
+ }
761
+
762
+ // src/toolbar/WatermarkTool.tsx
763
+ import { useState as useState14 } from "react";
764
+ import { jsx as jsx24, jsxs as jsxs13 } from "react/jsx-runtime";
765
+ function InsertElementTool() {
766
+ const { editorRef } = useEditor();
767
+ const [visible, setVisible] = useState14(false);
768
+ const handleHeader = () => {
769
+ if (!editorRef.current) return;
770
+ const options = editorRef.current.command.getOptions();
771
+ if (options.header.disabled) {
772
+ options.header.disabled = false;
773
+ editorRef.current.command.executeForceUpdate();
774
+ }
775
+ editorRef.current.command.executeSetZone("header");
776
+ setVisible(false);
777
+ };
778
+ return /* @__PURE__ */ jsxs13("div", { className: "menu-item__insert-element", onClick: () => setVisible(!visible), children: [
779
+ /* @__PURE__ */ jsx24("i", { title: "Insert Element" }),
780
+ /* @__PURE__ */ jsx24("div", { className: `options ${visible ? "visible" : ""}`, children: /* @__PURE__ */ jsx24("ul", { children: /* @__PURE__ */ jsx24("li", { onClick: handleHeader, children: "Add Header" }) }) })
781
+ ] });
782
+ }
783
+
784
+ // src/toolbar/PageBreakTool.tsx
785
+ import { useState as useState15 } from "react";
786
+ import { jsx as jsx25, jsxs as jsxs14 } from "react/jsx-runtime";
787
+ function PageBreakTool() {
788
+ const { editorRef } = useEditor();
789
+ const [visible, setVisible] = useState15(false);
790
+ const handlePageBreak = () => {
791
+ editorRef.current?.command.executePageBreak();
792
+ setVisible(false);
793
+ };
794
+ const handleColumnBreak = () => {
795
+ editorRef.current?.command.executeColumnBreak();
796
+ setVisible(false);
797
+ };
798
+ return /* @__PURE__ */ jsxs14(
799
+ "div",
800
+ {
801
+ className: "menu-item__page-break",
802
+ onClick: () => setVisible(!visible),
803
+ children: [
804
+ /* @__PURE__ */ jsx25("i", { title: "Break" }),
805
+ /* @__PURE__ */ jsx25("div", { className: `options ${visible ? "visible" : ""}`, children: /* @__PURE__ */ jsxs14("ul", { children: [
806
+ /* @__PURE__ */ jsx25("li", { onClick: handlePageBreak, children: "Page Break" }),
807
+ /* @__PURE__ */ jsx25("li", { onClick: handleColumnBreak, children: "Column Break" })
808
+ ] }) })
809
+ ]
810
+ }
811
+ );
812
+ }
813
+
814
+ // src/EditorToolbar.tsx
815
+ import { jsx as jsx26, jsxs as jsxs15 } from "react/jsx-runtime";
816
+ function EditorToolbar() {
817
+ return /* @__PURE__ */ jsxs15("div", { className: "menu", "editor-component": "menu", children: [
818
+ /* @__PURE__ */ jsxs15("div", { className: "menu-item", children: [
819
+ /* @__PURE__ */ jsx26(UndoTool, {}),
820
+ /* @__PURE__ */ jsx26(RedoTool, {})
821
+ ] }),
822
+ /* @__PURE__ */ jsx26("div", { className: "menu-divider" }),
823
+ /* @__PURE__ */ jsx26("div", { className: "menu-item", children: /* @__PURE__ */ jsx26(ColumnTool, {}) }),
824
+ /* @__PURE__ */ jsx26("div", { className: "menu-divider" }),
825
+ /* @__PURE__ */ jsxs15("div", { className: "menu-item", children: [
826
+ /* @__PURE__ */ jsx26(PageBreakTool, {}),
827
+ /* @__PURE__ */ jsx26(SeparatorTool, {})
828
+ ] }),
829
+ /* @__PURE__ */ jsx26("div", { className: "menu-divider" }),
830
+ /* @__PURE__ */ jsx26("div", { className: "menu-item", children: /* @__PURE__ */ jsx26(TableTool, {}) }),
831
+ /* @__PURE__ */ jsx26("div", { className: "menu-divider" }),
832
+ /* @__PURE__ */ jsxs15("div", { className: "menu-item", children: [
833
+ /* @__PURE__ */ jsx26(TitleTool, {}),
834
+ /* @__PURE__ */ jsx26(FontTool, {}),
835
+ /* @__PURE__ */ jsx26(FontSizeTool, {}),
836
+ /* @__PURE__ */ jsx26(LineHeightTool, {})
837
+ ] }),
838
+ /* @__PURE__ */ jsx26("div", { className: "menu-divider" }),
839
+ /* @__PURE__ */ jsxs15("div", { className: "menu-item", children: [
840
+ /* @__PURE__ */ jsx26(ColorTool, {}),
841
+ /* @__PURE__ */ jsx26(HighlightTool, {}),
842
+ /* @__PURE__ */ jsx26(BoldTool, {}),
843
+ /* @__PURE__ */ jsx26(ItalicTool, {}),
844
+ /* @__PURE__ */ jsx26(UnderlineTool, {}),
845
+ /* @__PURE__ */ jsx26(StrikeoutTool, {})
846
+ ] }),
847
+ /* @__PURE__ */ jsx26("div", { className: "menu-divider" }),
848
+ /* @__PURE__ */ jsxs15("div", { className: "menu-item", children: [
849
+ /* @__PURE__ */ jsx26(LeftAlignTool, {}),
850
+ /* @__PURE__ */ jsx26(CenterAlignTool, {}),
851
+ /* @__PURE__ */ jsx26(RightAlignTool, {}),
852
+ /* @__PURE__ */ jsx26(JustifyTool, {})
853
+ ] }),
854
+ /* @__PURE__ */ jsx26("div", { className: "menu-divider" }),
855
+ /* @__PURE__ */ jsx26("div", { className: "menu-item", children: /* @__PURE__ */ jsx26(ListTool, {}) }),
856
+ /* @__PURE__ */ jsx26("div", { className: "menu-divider" }),
857
+ /* @__PURE__ */ jsx26("div", { className: "menu-item", children: /* @__PURE__ */ jsx26(ImageTool, {}) }),
858
+ /* @__PURE__ */ jsx26("div", { className: "menu-item", children: /* @__PURE__ */ jsx26(InsertElementTool, {}) })
859
+ ] });
860
+ }
861
+
862
+ // src/footer/CatalogToggleTool.tsx
863
+ import { jsx as jsx27 } from "react/jsx-runtime";
864
+ function CatalogToggleTool() {
865
+ const { handleToggleCatalogAction } = useFooter();
866
+ return /* @__PURE__ */ jsx27("div", { className: "catalog-mode", title: "Catalog", onClick: handleToggleCatalogAction, children: /* @__PURE__ */ jsx27("i", {}) });
867
+ }
868
+
869
+ // src/footer/PageModeTool.tsx
870
+ import { useState as useState16 } from "react";
871
+ import { jsx as jsx28, jsxs as jsxs16 } from "react/jsx-runtime";
872
+ function PageModeTool() {
873
+ const { editorRef } = useEditor();
874
+ const [visible, setVisible] = useState16(false);
875
+ const handlePageMode = (mode) => {
876
+ editorRef.current?.command.executePageMode(mode);
877
+ setVisible(false);
878
+ };
879
+ return /* @__PURE__ */ jsxs16("div", { className: "page-mode", onClick: () => setVisible(!visible), children: [
880
+ /* @__PURE__ */ jsx28("i", { title: "Page Mode" }),
881
+ /* @__PURE__ */ jsx28("div", { className: `options ${visible ? "visible" : ""}`, children: /* @__PURE__ */ jsxs16("ul", { children: [
882
+ /* @__PURE__ */ jsx28("li", { onClick: () => handlePageMode("paging"), className: "active", children: "Paging" }),
883
+ /* @__PURE__ */ jsx28("li", { onClick: () => handlePageMode("continuity"), children: "Continuity" })
884
+ ] }) })
885
+ ] });
886
+ }
887
+
888
+ // src/footer/FooterStatus.tsx
889
+ import { Fragment as Fragment2, jsx as jsx29, jsxs as jsxs17 } from "react/jsx-runtime";
890
+ function FooterStatus() {
891
+ const { pageNoList, pageNo, pageSize, wordCount, rowNo, colNo } = useFooter();
892
+ return /* @__PURE__ */ jsxs17(Fragment2, { children: [
893
+ /* @__PURE__ */ jsxs17("span", { children: [
894
+ "Visible Pages: ",
895
+ /* @__PURE__ */ jsx29("span", { className: "page-no-list", children: pageNoList })
896
+ ] }),
897
+ /* @__PURE__ */ jsx29("span", { className: "footer-divider" }),
898
+ /* @__PURE__ */ jsxs17("span", { children: [
899
+ "Pages: ",
900
+ /* @__PURE__ */ jsx29("span", { className: "page-no", children: pageNo }),
901
+ "/",
902
+ /* @__PURE__ */ jsx29("span", { className: "page-size", children: pageSize })
903
+ ] }),
904
+ /* @__PURE__ */ jsx29("span", { className: "footer-divider" }),
905
+ /* @__PURE__ */ jsxs17("span", { children: [
906
+ "Words: ",
907
+ /* @__PURE__ */ jsx29("span", { className: "word-count", children: wordCount })
908
+ ] }),
909
+ /* @__PURE__ */ jsx29("span", { className: "footer-divider" }),
910
+ /* @__PURE__ */ jsxs17("span", { children: [
911
+ "Row: ",
912
+ /* @__PURE__ */ jsx29("span", { className: "row-no", children: rowNo })
913
+ ] }),
914
+ /* @__PURE__ */ jsx29("span", { className: "footer-divider" }),
915
+ /* @__PURE__ */ jsxs17("span", { children: [
916
+ "Column: ",
917
+ /* @__PURE__ */ jsx29("span", { className: "col-no", children: colNo })
918
+ ] })
919
+ ] });
920
+ }
921
+
922
+ // src/footer/EditorModeTool.tsx
923
+ import { useState as useState17, useRef as useRef5 } from "react";
924
+ import { jsx as jsx30 } from "react/jsx-runtime";
925
+ var MODE_LIST = [
926
+ { mode: "edit", name: "Edit Mode" },
927
+ { mode: "clean", name: "Clean Mode" },
928
+ { mode: "readonly", name: "Read-only Mode" },
929
+ { mode: "form", name: "Form Mode" },
930
+ { mode: "print", name: "Print Mode" },
931
+ { mode: "design", name: "Design Mode" },
932
+ { mode: "graffiti", name: "Graffiti Mode" }
933
+ ];
934
+ function EditorModeTool() {
935
+ const { editorRef } = useEditor();
936
+ const [editorMode, setEditorMode] = useState17("Edit Mode");
937
+ const modeIndexRef = useRef5(0);
938
+ const handleModeChange = () => {
939
+ modeIndexRef.current = modeIndexRef.current === MODE_LIST.length - 1 ? 0 : modeIndexRef.current + 1;
940
+ const { name, mode } = MODE_LIST[modeIndexRef.current];
941
+ setEditorMode(name);
942
+ editorRef.current?.command.executeMode(mode);
943
+ const isReadonly = mode === "readonly";
944
+ const enableMenuList = ["search", "print"];
945
+ document.querySelectorAll(".menu-item>div").forEach((dom) => {
946
+ const menu = dom.dataset.menu;
947
+ if (isReadonly && (!menu || !enableMenuList.includes(menu))) {
948
+ dom.classList.add("disable");
949
+ } else {
950
+ dom.classList.remove("disable");
951
+ }
952
+ });
953
+ };
954
+ return /* @__PURE__ */ jsx30("div", { className: "editor-mode", title: "Click to change mode", onClick: handleModeChange, children: editorMode });
955
+ }
956
+
957
+ // src/footer/PageScaleMinusTool.tsx
958
+ import { jsx as jsx31 } from "react/jsx-runtime";
959
+ function PageScaleMinusTool() {
960
+ const { editorRef } = useEditor();
961
+ return /* @__PURE__ */ jsx31("div", { className: "page-scale-minus", title: "Zoom Out (Ctrl+-)", onClick: () => editorRef.current?.command.executePageScaleMinus(), children: /* @__PURE__ */ jsx31("i", {}) });
962
+ }
963
+
964
+ // src/footer/PageScalePercentageTool.tsx
965
+ import { jsxs as jsxs18 } from "react/jsx-runtime";
966
+ function PageScalePercentageTool() {
967
+ const { editorRef } = useEditor();
968
+ const { pageScale } = useFooter();
969
+ return /* @__PURE__ */ jsxs18("span", { className: "page-scale-percentage", title: "Zoom Level", onClick: () => editorRef.current?.command.executePageScaleRecovery(), children: [
970
+ pageScale,
971
+ "%"
972
+ ] });
973
+ }
974
+
975
+ // src/footer/PageScaleAddTool.tsx
976
+ import { jsx as jsx32 } from "react/jsx-runtime";
977
+ function PageScaleAddTool() {
978
+ const { editorRef } = useEditor();
979
+ return /* @__PURE__ */ jsx32("div", { className: "page-scale-add", title: "Zoom In (Ctrl+=)", onClick: () => editorRef.current?.command.executePageScaleAdd(), children: /* @__PURE__ */ jsx32("i", {}) });
980
+ }
981
+
982
+ // src/footer/PaperSizeTool.tsx
983
+ import { useState as useState18 } from "react";
984
+ import { jsx as jsx33, jsxs as jsxs19 } from "react/jsx-runtime";
985
+ var SIZES2 = [
986
+ { label: "A4", width: 794, height: 1123, active: true },
987
+ { label: "A2", width: 1593, height: 2251 },
988
+ { label: "A3", width: 1125, height: 1593 },
989
+ { label: "A5", width: 565, height: 796 }
990
+ ];
991
+ function PaperSizeTool() {
992
+ const { editorRef } = useEditor();
993
+ const [visible, setVisible] = useState18(false);
994
+ const handlePaperSize = (width, height) => {
995
+ editorRef.current?.command.executePaperSize(width, height);
996
+ setVisible(false);
997
+ };
998
+ return /* @__PURE__ */ jsxs19("div", { className: "paper-size", onClick: () => setVisible(!visible), children: [
999
+ /* @__PURE__ */ jsx33("i", { title: "Paper Type" }),
1000
+ /* @__PURE__ */ jsx33("div", { className: `options ${visible ? "visible" : ""}`, children: /* @__PURE__ */ jsx33("ul", { children: SIZES2.map(({ label, width, height, active }) => /* @__PURE__ */ jsx33("li", { onClick: () => handlePaperSize(width, height), className: active ? "active" : "", children: label }, label)) }) })
1001
+ ] });
1002
+ }
1003
+
1004
+ // src/footer/PaperDirectionTool.tsx
1005
+ import { useState as useState19 } from "react";
1006
+ import { jsx as jsx34, jsxs as jsxs20 } from "react/jsx-runtime";
1007
+ function PaperDirectionTool() {
1008
+ const { editorRef } = useEditor();
1009
+ const [visible, setVisible] = useState19(false);
1010
+ const handlePaperDirection = (direction) => {
1011
+ editorRef.current?.command.executePaperDirection(direction);
1012
+ setVisible(false);
1013
+ };
1014
+ return /* @__PURE__ */ jsxs20("div", { className: "paper-direction", onClick: () => setVisible(!visible), children: [
1015
+ /* @__PURE__ */ jsx34("i", { title: "Paper Direction" }),
1016
+ /* @__PURE__ */ jsx34("div", { className: `options ${visible ? "visible" : ""}`, children: /* @__PURE__ */ jsxs20("ul", { children: [
1017
+ /* @__PURE__ */ jsx34("li", { onClick: () => handlePaperDirection("vertical"), className: "active", children: "Portrait" }),
1018
+ /* @__PURE__ */ jsx34("li", { onClick: () => handlePaperDirection("horizontal"), children: "Landscape" })
1019
+ ] }) })
1020
+ ] });
1021
+ }
1022
+
1023
+ // src/footer/PaperMarginTool.tsx
1024
+ import { jsx as jsx35 } from "react/jsx-runtime";
1025
+ function PaperMarginTool() {
1026
+ const { editorRef } = useEditor();
1027
+ const handlePaperMargin = async () => {
1028
+ if (!editorRef.current) return;
1029
+ const { Dialog } = await import("@windoc/core");
1030
+ const [topMargin, rightMargin, bottomMargin, leftMargin] = editorRef.current.command.getPaperMargin();
1031
+ new Dialog({
1032
+ title: "Page Margins",
1033
+ data: [
1034
+ { type: "text", label: "Top Margin", name: "top", required: true, value: `${topMargin}`, placeholder: "Please enter top margin" },
1035
+ { type: "text", label: "Bottom Margin", name: "bottom", required: true, value: `${bottomMargin}`, placeholder: "Please enter bottom margin" },
1036
+ { type: "text", label: "Left Margin", name: "left", required: true, value: `${leftMargin}`, placeholder: "Please enter left margin" },
1037
+ { type: "text", label: "Right Margin", name: "right", required: true, value: `${rightMargin}`, placeholder: "Please enter right margin" }
1038
+ ],
1039
+ onConfirm: (payload) => {
1040
+ const top = payload.find((p) => p.name === "top")?.value;
1041
+ if (!top) return;
1042
+ const bottom = payload.find((p) => p.name === "bottom")?.value;
1043
+ if (!bottom) return;
1044
+ const left = payload.find((p) => p.name === "left")?.value;
1045
+ if (!left) return;
1046
+ const right = payload.find((p) => p.name === "right")?.value;
1047
+ if (!right) return;
1048
+ editorRef.current?.command.executeSetPaperMargin([
1049
+ Number(top),
1050
+ Number(right),
1051
+ Number(bottom),
1052
+ Number(left)
1053
+ ]);
1054
+ }
1055
+ });
1056
+ };
1057
+ return /* @__PURE__ */ jsx35("div", { className: "paper-margin", title: "Page Margins", onClick: handlePaperMargin, children: /* @__PURE__ */ jsx35("i", {}) });
1058
+ }
1059
+
1060
+ // src/footer/FullscreenTool.tsx
1061
+ import { jsx as jsx36 } from "react/jsx-runtime";
1062
+ function FullscreenTool() {
1063
+ const handleFullscreen = () => {
1064
+ if (!document.fullscreenElement) {
1065
+ document.documentElement.requestFullscreen();
1066
+ } else {
1067
+ document.exitFullscreen();
1068
+ }
1069
+ };
1070
+ return /* @__PURE__ */ jsx36("div", { className: "fullscreen", title: "Fullscreen", onClick: handleFullscreen, children: /* @__PURE__ */ jsx36("i", {}) });
1071
+ }
1072
+
1073
+ // src/footer/EditorOptionTool.tsx
1074
+ import { jsx as jsx37 } from "react/jsx-runtime";
1075
+ function EditorOptionTool() {
1076
+ const { editorRef } = useEditor();
1077
+ const handleEditorOption = async () => {
1078
+ if (!editorRef.current) return;
1079
+ const { Dialog } = await import("@windoc/core");
1080
+ const options = editorRef.current.command.getOptions();
1081
+ new Dialog({
1082
+ title: "Editor Configuration",
1083
+ data: [
1084
+ {
1085
+ type: "textarea",
1086
+ name: "option",
1087
+ width: 350,
1088
+ height: 300,
1089
+ required: true,
1090
+ value: JSON.stringify(options, null, 2),
1091
+ placeholder: "Please enter editor configuration"
1092
+ }
1093
+ ],
1094
+ onConfirm: (payload) => {
1095
+ const newOptionValue = payload.find((p) => p.name === "option")?.value;
1096
+ if (!newOptionValue) return;
1097
+ const newOption = JSON.parse(newOptionValue);
1098
+ editorRef.current?.command.executeUpdateOptions(newOption);
1099
+ }
1100
+ });
1101
+ };
1102
+ return /* @__PURE__ */ jsx37("div", { className: "editor-option", title: "Editor Settings", onClick: handleEditorOption, children: /* @__PURE__ */ jsx37("i", {}) });
1103
+ }
1104
+
1105
+ // src/footer/WatermarkFooterTool.tsx
1106
+ import { useState as useState20, useRef as useRef6, useEffect as useEffect6, useCallback } from "react";
1107
+ import { Fragment as Fragment3, jsx as jsx38, jsxs as jsxs21 } from "react/jsx-runtime";
1108
+ var COLOR_PALETTE2 = [
1109
+ ["#000000", "#434343", "#666666", "#999999", "#b7b7b7", "#cccccc"],
1110
+ ["#980000", "#ff0000", "#ff9900", "#ffff00", "#00ff00", "#00ffff"],
1111
+ ["#4a86e8", "#0000ff", "#9900ff", "#ff00ff", "#e6b8af", "#f4cccc"]
1112
+ ];
1113
+ var FONTS2 = [
1114
+ { family: "Arial", label: "Sans Serif" },
1115
+ { family: "Times New Roman", label: "Serif" }
1116
+ ];
1117
+ function WatermarkFooterTool() {
1118
+ const { editorRef } = useEditor();
1119
+ const [visible, setVisible] = useState20(false);
1120
+ const [tab, setTab] = useState20("text");
1121
+ const containerRef = useRef6(null);
1122
+ const panelRef = useRef6(null);
1123
+ const fileInputRef = useRef6(null);
1124
+ const [text, setText] = useState20("WATERMARK");
1125
+ const [font, setFont] = useState20("Arial");
1126
+ const [color, setColor] = useState20("#AEB5C0");
1127
+ const [opacity, setOpacity] = useState20(30);
1128
+ const [rotation, setRotation] = useState20(-45);
1129
+ const [inFront, setInFront] = useState20(false);
1130
+ const [imageData, setImageData] = useState20("");
1131
+ const [imgWidth, setImgWidth] = useState20(200);
1132
+ const [imgHeight, setImgHeight] = useState20(200);
1133
+ useEffect6(() => {
1134
+ if (!visible) return;
1135
+ const handler = (e) => {
1136
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
1137
+ setVisible(false);
1138
+ }
1139
+ };
1140
+ document.addEventListener("mousedown", handler);
1141
+ return () => document.removeEventListener("mousedown", handler);
1142
+ }, [visible]);
1143
+ useEffect6(() => {
1144
+ if (!visible || !panelRef.current) return;
1145
+ const el = panelRef.current;
1146
+ el.style.right = "";
1147
+ el.style.left = "";
1148
+ const rect = el.getBoundingClientRect();
1149
+ if (rect.right > window.innerWidth) {
1150
+ el.style.left = "unset";
1151
+ el.style.right = "0";
1152
+ }
1153
+ if (rect.left < 0) {
1154
+ el.style.left = `${-rect.left + 4}px`;
1155
+ }
1156
+ }, [visible]);
1157
+ const handleFileUpload = useCallback((e) => {
1158
+ const file = e.target.files?.[0];
1159
+ if (!file) return;
1160
+ const reader = new FileReader();
1161
+ reader.onload = () => {
1162
+ const result = reader.result;
1163
+ setImageData(result);
1164
+ const img = new Image();
1165
+ img.onload = () => {
1166
+ const maxDim = 300;
1167
+ let w = img.naturalWidth;
1168
+ let h = img.naturalHeight;
1169
+ if (w > maxDim || h > maxDim) {
1170
+ const ratio = Math.min(maxDim / w, maxDim / h);
1171
+ w = Math.round(w * ratio);
1172
+ h = Math.round(h * ratio);
1173
+ }
1174
+ setImgWidth(w);
1175
+ setImgHeight(h);
1176
+ };
1177
+ img.src = result;
1178
+ };
1179
+ reader.readAsDataURL(file);
1180
+ }, []);
1181
+ const handleApply = () => {
1182
+ if (!editorRef.current) return;
1183
+ if (tab === "text") {
1184
+ if (!text.trim()) return;
1185
+ editorRef.current.command.executeAddWatermark({
1186
+ data: text,
1187
+ type: "text",
1188
+ color,
1189
+ opacity: opacity / 100,
1190
+ size: 120,
1191
+ font,
1192
+ rotation,
1193
+ inFront
1194
+ });
1195
+ } else {
1196
+ if (!imageData) return;
1197
+ editorRef.current.command.executeAddWatermark({
1198
+ data: imageData,
1199
+ type: "image",
1200
+ opacity: opacity / 100,
1201
+ rotation,
1202
+ inFront,
1203
+ width: imgWidth,
1204
+ height: imgHeight
1205
+ });
1206
+ }
1207
+ setVisible(false);
1208
+ };
1209
+ const handleDelete = () => {
1210
+ editorRef.current?.command.executeDeleteWatermark();
1211
+ setVisible(false);
1212
+ };
1213
+ return /* @__PURE__ */ jsxs21("div", { className: "watermark-footer", ref: containerRef, onClick: () => setVisible(!visible), children: [
1214
+ /* @__PURE__ */ jsx38("i", { title: "Watermark" }),
1215
+ visible && /* @__PURE__ */ jsxs21("div", { className: "watermark-footer-panel", ref: panelRef, onClick: (e) => e.stopPropagation(), children: [
1216
+ /* @__PURE__ */ jsxs21("div", { className: "wm-panel-tabs", children: [
1217
+ /* @__PURE__ */ jsx38("button", { className: `wm-panel-tab ${tab === "text" ? "active" : ""}`, onClick: () => setTab("text"), children: "Text" }),
1218
+ /* @__PURE__ */ jsx38("button", { className: `wm-panel-tab ${tab === "image" ? "active" : ""}`, onClick: () => setTab("image"), children: "Image" })
1219
+ ] }),
1220
+ /* @__PURE__ */ jsxs21("div", { className: "wm-panel-body", children: [
1221
+ tab === "text" ? /* @__PURE__ */ jsxs21(Fragment3, { children: [
1222
+ /* @__PURE__ */ jsxs21("div", { className: "wm-panel-field", children: [
1223
+ /* @__PURE__ */ jsx38("label", { children: "Text" }),
1224
+ /* @__PURE__ */ jsx38("input", { type: "text", value: text, onChange: (e) => setText(e.target.value), placeholder: "Watermark text" })
1225
+ ] }),
1226
+ /* @__PURE__ */ jsxs21("div", { className: "wm-panel-field", children: [
1227
+ /* @__PURE__ */ jsx38("label", { children: "Font" }),
1228
+ /* @__PURE__ */ jsx38("select", { value: font, onChange: (e) => setFont(e.target.value), children: FONTS2.map((f) => /* @__PURE__ */ jsx38("option", { value: f.family, children: f.label }, f.family)) })
1229
+ ] }),
1230
+ /* @__PURE__ */ jsxs21("div", { className: "wm-panel-field", children: [
1231
+ /* @__PURE__ */ jsx38("label", { children: "Color" }),
1232
+ /* @__PURE__ */ jsx38("div", { className: "wm-panel-colors", children: COLOR_PALETTE2.flat().map((c) => /* @__PURE__ */ jsx38(
1233
+ "div",
1234
+ {
1235
+ className: `wm-panel-color ${color.toLowerCase() === c.toLowerCase() ? "active" : ""}`,
1236
+ style: { backgroundColor: c },
1237
+ onClick: () => setColor(c)
1238
+ },
1239
+ c
1240
+ )) })
1241
+ ] })
1242
+ ] }) : /* @__PURE__ */ jsxs21(Fragment3, { children: [
1243
+ /* @__PURE__ */ jsxs21("div", { className: "wm-panel-field", children: [
1244
+ /* @__PURE__ */ jsx38("label", { children: "Image" }),
1245
+ /* @__PURE__ */ jsxs21("div", { style: { display: "flex", alignItems: "center", gap: "6px" }, children: [
1246
+ /* @__PURE__ */ jsx38("button", { className: "wm-panel-upload", onClick: () => fileInputRef.current?.click(), children: "Choose File" }),
1247
+ /* @__PURE__ */ jsx38("input", { ref: fileInputRef, type: "file", accept: "image/*", style: { display: "none" }, onChange: handleFileUpload }),
1248
+ imageData && /* @__PURE__ */ jsx38("span", { style: { fontSize: "11px", color: "#667085" }, children: "Loaded" })
1249
+ ] })
1250
+ ] }),
1251
+ imageData && /* @__PURE__ */ jsx38("div", { className: "wm-panel-field", children: /* @__PURE__ */ jsx38("div", { className: "wm-panel-preview", children: /* @__PURE__ */ jsx38("img", { src: imageData, alt: "preview", style: { maxWidth: "100%", maxHeight: "48px", objectFit: "contain" } }) }) }),
1252
+ /* @__PURE__ */ jsxs21("div", { className: "wm-panel-field-row", children: [
1253
+ /* @__PURE__ */ jsxs21("div", { className: "wm-panel-field wm-panel-field-half", children: [
1254
+ /* @__PURE__ */ jsx38("label", { children: "W" }),
1255
+ /* @__PURE__ */ jsx38("input", { type: "number", value: imgWidth, min: 10, onChange: (e) => setImgWidth(Number(e.target.value)) })
1256
+ ] }),
1257
+ /* @__PURE__ */ jsxs21("div", { className: "wm-panel-field wm-panel-field-half", children: [
1258
+ /* @__PURE__ */ jsx38("label", { children: "H" }),
1259
+ /* @__PURE__ */ jsx38("input", { type: "number", value: imgHeight, min: 10, onChange: (e) => setImgHeight(Number(e.target.value)) })
1260
+ ] })
1261
+ ] })
1262
+ ] }),
1263
+ /* @__PURE__ */ jsxs21("div", { className: "wm-panel-field", children: [
1264
+ /* @__PURE__ */ jsxs21("label", { children: [
1265
+ "Opacity ",
1266
+ /* @__PURE__ */ jsxs21("span", { className: "wm-panel-value", children: [
1267
+ opacity,
1268
+ "%"
1269
+ ] })
1270
+ ] }),
1271
+ /* @__PURE__ */ jsx38("input", { type: "range", min: 0, max: 100, value: opacity, onChange: (e) => setOpacity(Number(e.target.value)), className: "wm-panel-slider" })
1272
+ ] }),
1273
+ /* @__PURE__ */ jsxs21("div", { className: "wm-panel-field", children: [
1274
+ /* @__PURE__ */ jsxs21("label", { children: [
1275
+ "Rotation ",
1276
+ /* @__PURE__ */ jsxs21("span", { className: "wm-panel-value", children: [
1277
+ rotation,
1278
+ "\xB0"
1279
+ ] })
1280
+ ] }),
1281
+ /* @__PURE__ */ jsx38("input", { type: "range", min: -90, max: 90, value: rotation, onChange: (e) => setRotation(Number(e.target.value)), className: "wm-panel-slider" })
1282
+ ] }),
1283
+ /* @__PURE__ */ jsxs21("div", { className: "wm-panel-field", children: [
1284
+ /* @__PURE__ */ jsx38("label", { children: "Position" }),
1285
+ /* @__PURE__ */ jsxs21("div", { className: "wm-panel-toggle", children: [
1286
+ /* @__PURE__ */ jsx38("button", { className: !inFront ? "active" : "", onClick: () => setInFront(false), children: "Behind" }),
1287
+ /* @__PURE__ */ jsx38("button", { className: inFront ? "active" : "", onClick: () => setInFront(true), children: "In Front" })
1288
+ ] })
1289
+ ] })
1290
+ ] }),
1291
+ /* @__PURE__ */ jsxs21("div", { className: "wm-panel-actions", children: [
1292
+ /* @__PURE__ */ jsx38("button", { className: "wm-panel-btn-delete", onClick: handleDelete, children: "Remove" }),
1293
+ /* @__PURE__ */ jsx38("button", { className: "wm-panel-btn-apply", onClick: handleApply, children: "Apply" })
1294
+ ] })
1295
+ ] })
1296
+ ] });
1297
+ }
1298
+
1299
+ // src/EditorFooter.tsx
1300
+ import { jsx as jsx39, jsxs as jsxs22 } from "react/jsx-runtime";
1301
+ function EditorFooter() {
1302
+ return /* @__PURE__ */ jsxs22("div", { className: "footer", "editor-component": "footer", children: [
1303
+ /* @__PURE__ */ jsxs22("div", { children: [
1304
+ /* @__PURE__ */ jsx39(CatalogToggleTool, {}),
1305
+ /* @__PURE__ */ jsx39(PageModeTool, {}),
1306
+ /* @__PURE__ */ jsx39(FooterStatus, {})
1307
+ ] }),
1308
+ /* @__PURE__ */ jsx39(EditorModeTool, {}),
1309
+ /* @__PURE__ */ jsxs22("div", { children: [
1310
+ /* @__PURE__ */ jsx39(PageScaleMinusTool, {}),
1311
+ /* @__PURE__ */ jsx39(PageScalePercentageTool, {}),
1312
+ /* @__PURE__ */ jsx39(PageScaleAddTool, {}),
1313
+ /* @__PURE__ */ jsx39(PaperSizeTool, {}),
1314
+ /* @__PURE__ */ jsx39(PaperDirectionTool, {}),
1315
+ /* @__PURE__ */ jsx39(PaperMarginTool, {}),
1316
+ /* @__PURE__ */ jsx39(WatermarkFooterTool, {}),
1317
+ /* @__PURE__ */ jsx39(FullscreenTool, {}),
1318
+ /* @__PURE__ */ jsx39(EditorOptionTool, {})
1319
+ ] })
1320
+ ] });
1321
+ }
1322
+
1323
+ // src/Editor.tsx
1324
+ import { jsx as jsx40, jsxs as jsxs23 } from "react/jsx-runtime";
1325
+ function Editor({
1326
+ defaultValue,
1327
+ options: userOptions,
1328
+ onChange,
1329
+ onReady,
1330
+ toolbar = true,
1331
+ footer = true,
1332
+ renderToolbar,
1333
+ renderFooter,
1334
+ children,
1335
+ className,
1336
+ style,
1337
+ onDrop: userOnDrop
1338
+ }) {
1339
+ return /* @__PURE__ */ jsx40(FooterProvider, { children: /* @__PURE__ */ jsx40(
1340
+ EditorInner,
1341
+ {
1342
+ defaultValue,
1343
+ options: userOptions,
1344
+ onChange,
1345
+ onReady,
1346
+ toolbar,
1347
+ footer,
1348
+ renderToolbar,
1349
+ renderFooter,
1350
+ className,
1351
+ style,
1352
+ onDrop: userOnDrop,
1353
+ children
1354
+ }
1355
+ ) });
1356
+ }
1357
+ function EditorInner({
1358
+ defaultValue,
1359
+ options: userOptions,
1360
+ onChange,
1361
+ onReady,
1362
+ toolbar = true,
1363
+ footer = true,
1364
+ renderToolbar,
1365
+ renderFooter,
1366
+ children,
1367
+ className,
1368
+ style,
1369
+ onDrop: userOnDrop
1370
+ }) {
1371
+ const containerRef = useRef7(null);
1372
+ const editorRef = useRef7(null);
1373
+ const [rangeStyle, setRangeStyle] = useState21(null);
1374
+ const {
1375
+ setPageNoList,
1376
+ setPageNo,
1377
+ setPageSize,
1378
+ setWordCount,
1379
+ setRowNo,
1380
+ setColNo,
1381
+ setPageScale
1382
+ } = useFooter();
1383
+ useEffect7(() => {
1384
+ let instance = null;
1385
+ const initEditor = async () => {
1386
+ if (!containerRef.current) return;
1387
+ const {
1388
+ default: EditorClass,
1389
+ KeyMap,
1390
+ EditorMode,
1391
+ EditorZone,
1392
+ ElementType,
1393
+ Dialog,
1394
+ Signature
1395
+ } = await import("@windoc/core");
1396
+ const data = defaultValue ?? { main: [] };
1397
+ instance = new EditorClass(
1398
+ containerRef.current,
1399
+ data,
1400
+ userOptions ?? {}
1401
+ );
1402
+ editorRef.current = instance;
1403
+ instance.listener.rangeStyleChange = (payload) => {
1404
+ setRangeStyle(payload);
1405
+ const rangeContext = instance?.command.getRangeContext();
1406
+ if (rangeContext) {
1407
+ setRowNo(rangeContext.startRowNo + 1);
1408
+ setColNo(rangeContext.startColNo + 1);
1409
+ }
1410
+ };
1411
+ instance.listener.visiblePageNoListChange = (payload) => {
1412
+ setPageNoList(payload.map((i) => i + 1).join(", "));
1413
+ };
1414
+ instance.listener.pageSizeChange = (payload) => {
1415
+ setPageSize(payload);
1416
+ };
1417
+ instance.listener.intersectionPageNoChange = (payload) => {
1418
+ setPageNo(payload + 1);
1419
+ };
1420
+ instance.listener.pageScaleChange = (payload) => {
1421
+ setPageScale(Math.floor(payload * 10 * 10));
1422
+ };
1423
+ instance.listener.contentChange = async () => {
1424
+ const count2 = await instance?.command.getWordCount();
1425
+ setWordCount(count2 || 0);
1426
+ if (onChange) {
1427
+ const value = instance?.command.getValue();
1428
+ if (value) onChange(value);
1429
+ }
1430
+ };
1431
+ instance.register.shortcutList([
1432
+ {
1433
+ key: KeyMap.P,
1434
+ mod: true,
1435
+ isGlobal: true,
1436
+ callback: (command) => {
1437
+ command.executePrint();
1438
+ }
1439
+ },
1440
+ {
1441
+ key: KeyMap.MINUS,
1442
+ ctrl: true,
1443
+ isGlobal: true,
1444
+ callback: (command) => {
1445
+ command.executePageScaleMinus();
1446
+ }
1447
+ },
1448
+ {
1449
+ key: KeyMap.EQUAL,
1450
+ ctrl: true,
1451
+ isGlobal: true,
1452
+ callback: (command) => {
1453
+ command.executePageScaleAdd();
1454
+ }
1455
+ },
1456
+ {
1457
+ key: KeyMap.ZERO,
1458
+ ctrl: true,
1459
+ isGlobal: true,
1460
+ callback: (command) => {
1461
+ command.executePageScaleRecovery();
1462
+ }
1463
+ }
1464
+ ]);
1465
+ instance.register.contextMenuList([
1466
+ {
1467
+ name: "Signature",
1468
+ icon: "signature",
1469
+ when: (payload) => {
1470
+ return !payload.isReadonly && payload.editorTextFocus;
1471
+ },
1472
+ callback: (command) => {
1473
+ new Signature({
1474
+ onConfirm(payload) {
1475
+ if (!payload) return;
1476
+ const { value, width, height } = payload;
1477
+ if (!value || !width || !height) return;
1478
+ command.executeInsertElementList([
1479
+ { value, width, height, type: ElementType.IMAGE }
1480
+ ]);
1481
+ }
1482
+ });
1483
+ }
1484
+ },
1485
+ {
1486
+ name: "Format Cleanup",
1487
+ icon: "word-tool",
1488
+ when: (payload) => !payload.isReadonly,
1489
+ callback: (command) => {
1490
+ command.executeWordTool();
1491
+ }
1492
+ }
1493
+ ]);
1494
+ const closeDropdowns = (evt) => {
1495
+ const visibleDom = document.querySelector(".visible");
1496
+ if (!visibleDom || visibleDom.contains(evt.target)) return;
1497
+ visibleDom.classList.remove("visible");
1498
+ };
1499
+ window.addEventListener("click", closeDropdowns, { capture: true });
1500
+ const count = await instance.command.getWordCount();
1501
+ setWordCount(count || 0);
1502
+ onReady?.(instance);
1503
+ };
1504
+ initEditor();
1505
+ return () => {
1506
+ instance?.destroy();
1507
+ };
1508
+ }, []);
1509
+ const handleDrop = (e) => {
1510
+ e.preventDefault();
1511
+ if (userOnDrop && editorRef.current) {
1512
+ userOnDrop(e, editorRef.current);
1513
+ }
1514
+ };
1515
+ const handleDragOver = (e) => {
1516
+ e.preventDefault();
1517
+ e.dataTransfer.dropEffect = "copy";
1518
+ };
1519
+ return /* @__PURE__ */ jsxs23(EditorProvider, { editorRef, rangeStyle, children: [
1520
+ toolbar && !renderToolbar && /* @__PURE__ */ jsx40(EditorToolbar, {}),
1521
+ renderToolbar,
1522
+ children,
1523
+ /* @__PURE__ */ jsx40(
1524
+ "div",
1525
+ {
1526
+ className: className ?? "editor",
1527
+ style: style ?? { flex: 1, minHeight: 0, overflow: "auto" },
1528
+ ref: containerRef,
1529
+ onDrop: handleDrop,
1530
+ onDragOver: handleDragOver
1531
+ }
1532
+ ),
1533
+ footer && !renderFooter && /* @__PURE__ */ jsx40(EditorFooter, {}),
1534
+ renderFooter
1535
+ ] });
1536
+ }
1537
+ export {
1538
+ BoldTool,
1539
+ CatalogToggleTool,
1540
+ CenterAlignTool,
1541
+ ColorTool,
1542
+ ColumnTool,
1543
+ Editor,
1544
+ EditorFooter,
1545
+ EditorModeTool,
1546
+ EditorOptionTool,
1547
+ EditorProvider,
1548
+ EditorToolbar,
1549
+ FontSizeTool,
1550
+ FontTool,
1551
+ FooterProvider,
1552
+ FooterStatus,
1553
+ FullscreenTool,
1554
+ HighlightTool,
1555
+ ImageTool,
1556
+ ItalicTool,
1557
+ JustifyTool,
1558
+ LeftAlignTool,
1559
+ LineHeightTool,
1560
+ ListTool,
1561
+ PageBreakTool,
1562
+ PageModeTool,
1563
+ PageScaleAddTool,
1564
+ PageScaleMinusTool,
1565
+ PageScalePercentageTool,
1566
+ PaperDirectionTool,
1567
+ PaperMarginTool,
1568
+ PaperSizeTool,
1569
+ RedoTool,
1570
+ RightAlignTool,
1571
+ SeparatorTool,
1572
+ StrikeoutTool,
1573
+ TableTool,
1574
+ TitleTool,
1575
+ UnderlineTool,
1576
+ UndoTool,
1577
+ WatermarkFooterTool,
1578
+ InsertElementTool as WatermarkTool,
1579
+ useEditor,
1580
+ useFooter
1581
+ };
1582
+ //# sourceMappingURL=index.mjs.map