@stll/folio-react 0.5.0 → 0.7.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 (31) hide show
  1. package/dist/{CommentsSidebar-BMD21hiD.js → CommentsSidebar-B8X5a8JW.js} +126 -129
  2. package/dist/{FindReplaceDialog-By2OhOPu.js → FindReplaceDialog-Bx7QaFQ_.js} +26 -19
  3. package/dist/FootnotePropertiesDialog-2lmpg9m8.js +646 -0
  4. package/dist/ImagePositionDialog-D3MileYL.js +842 -0
  5. package/dist/ImagePropertiesDialog-CzK8HCaW.js +465 -0
  6. package/dist/InsertSymbolDialog-Df9dyLvn.js +376 -0
  7. package/dist/PageSetupDialog-PSs9YdPb.js +684 -0
  8. package/dist/TablePropertiesDialog-PQxKKM0Y.js +344 -0
  9. package/dist/{TextContextMenu-CG0V37wi.js → TextContextMenu-Ci7-M4oU.js} +199 -79
  10. package/dist/compat/eigenpal.d.ts +1 -1
  11. package/dist/compat/eigenpal.js +89 -17
  12. package/dist/dialogChrome-BoGYPgeu.js +26 -0
  13. package/dist/dialogs-DK8OVUT_.d.ts +330 -0
  14. package/dist/dialogs-DsHnfN0g.js +1272 -0
  15. package/dist/dialogs.d.ts +2 -0
  16. package/dist/dialogs.js +9 -0
  17. package/dist/editor.css +1 -1
  18. package/dist/folio-ui-C-85DSuK.js +1011 -0
  19. package/dist/index.d.ts +6 -3
  20. package/dist/index.js +13 -3
  21. package/dist/messages.js +1 -26
  22. package/dist/{renderAsync-C_Jb8BBI.d.ts → renderAsync-ChQI9UJG.d.ts} +14 -5
  23. package/dist/{renderAsync-B4SrVWHb.js → renderAsync-evdyE_GW.js} +5302 -3794
  24. package/dist/rolldown-runtime-BBjsoOtd.js +27 -0
  25. package/dist/standalone.css +1 -1
  26. package/package.json +12 -6
  27. package/dist/FootnotePropertiesDialog-CoPGKND_.js +0 -265
  28. package/dist/ImagePositionDialog-B_md0l56.js +0 -393
  29. package/dist/ImagePropertiesDialog-UcGv8qr3.js +0 -196
  30. package/dist/PageSetupDialog-Ba7bs6m3.js +0 -310
  31. package/dist/TablePropertiesDialog-Ci6h1tk2.js +0 -157
@@ -0,0 +1,1272 @@
1
+ import { r as useFolioUI } from "./folio-ui-C-85DSuK.js";
2
+ import { a as DIALOG_LABEL_CLASS, c as DIALOG_SECONDARY_BUTTON_CLASS, i as DIALOG_INPUT_CLASS, l as DIALOG_TITLE_CLASS, n as DIALOG_BODY_CLASS, o as DIALOG_POPUP_CLASS, r as DIALOG_FOOTER_CLASS, s as DIALOG_PRIMARY_BUTTON_CLASS, t as DIALOG_BACKDROP_CLASS, u as useCloseOnDialogOpenChange } from "./dialogChrome-BoGYPgeu.js";
3
+ import { c } from "react-compiler-runtime";
4
+ import { useEffect, useId, useState } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/components/dialogs/HyperlinkDialog.tsx
7
+ function HyperlinkDialog({ isOpen, onClose, onSubmit, onRemove, currentData, selectedText, bookmarks = [] }) {
8
+ const { Root: Dialog, Portal: DialogPortal, Backdrop: DialogBackdrop, Popup: DialogPopup, Title: DialogTitle, Close: DialogClose } = useFolioUI().Dialog;
9
+ const handleOpenChange = useCloseOnDialogOpenChange(onClose);
10
+ const id = useId();
11
+ const [targetType, setTargetType] = useState("url");
12
+ const [url, setUrl] = useState("");
13
+ const [bookmark, setBookmark] = useState("");
14
+ const [displayText, setDisplayText] = useState("");
15
+ const [tooltip, setTooltip] = useState("");
16
+ const [touched, setTouched] = useState(false);
17
+ useEffect(() => {
18
+ if (!isOpen) {
19
+ setTouched(false);
20
+ return;
21
+ }
22
+ const href = currentData?.href ?? "";
23
+ if (href.startsWith("#")) {
24
+ setTargetType("bookmark");
25
+ setBookmark(href.slice(1));
26
+ setUrl("");
27
+ } else {
28
+ setTargetType("url");
29
+ setUrl(href);
30
+ setBookmark("");
31
+ }
32
+ setDisplayText(currentData?.displayText ?? selectedText ?? "");
33
+ setTooltip(currentData?.tooltip ?? "");
34
+ }, [
35
+ isOpen,
36
+ currentData,
37
+ selectedText
38
+ ]);
39
+ const urlError = targetType === "url" ? getUrlError(url) : "";
40
+ const canSubmit = targetType === "bookmark" ? bookmark.trim().length > 0 : url.trim().length > 0 && urlError.length === 0;
41
+ const isEditing = Boolean(currentData?.href);
42
+ const fieldIds = {
43
+ targetType: `${id}-hyperlink-target-type`,
44
+ url: `${id}-hyperlink-url`,
45
+ bookmark: `${id}-hyperlink-bookmark`,
46
+ displayText: `${id}-hyperlink-display-text`,
47
+ tooltip: `${id}-hyperlink-tooltip`
48
+ };
49
+ const handleSubmit = () => {
50
+ setTouched(true);
51
+ if (!canSubmit) return;
52
+ const href_0 = targetType === "bookmark" ? `#${bookmark.trim()}` : normalizeUrl(url);
53
+ onSubmit({
54
+ href: href_0,
55
+ displayText: displayText.trim() || href_0,
56
+ ...tooltip.trim() ? { tooltip: tooltip.trim() } : {}
57
+ });
58
+ onClose();
59
+ };
60
+ const handleRemove = () => {
61
+ onRemove?.();
62
+ onClose();
63
+ };
64
+ return /* @__PURE__ */ jsx(Dialog, {
65
+ open: isOpen,
66
+ onOpenChange: handleOpenChange,
67
+ children: /* @__PURE__ */ jsxs(DialogPortal, { children: [/* @__PURE__ */ jsx(DialogBackdrop, { className: DIALOG_BACKDROP_CLASS }), /* @__PURE__ */ jsxs(DialogPopup, {
68
+ className: DIALOG_POPUP_CLASS,
69
+ children: [
70
+ /* @__PURE__ */ jsx(DialogTitle, {
71
+ className: DIALOG_TITLE_CLASS,
72
+ children: isEditing ? "Edit Hyperlink" : "Insert Hyperlink"
73
+ }),
74
+ /* @__PURE__ */ jsxs("div", {
75
+ className: DIALOG_BODY_CLASS,
76
+ children: [
77
+ (bookmarks.length > 0 || targetType === "bookmark") && /* @__PURE__ */ jsxs("label", {
78
+ className: "flex flex-col gap-1",
79
+ htmlFor: fieldIds.targetType,
80
+ children: [/* @__PURE__ */ jsx("span", {
81
+ className: "text-muted-foreground text-[13px]",
82
+ children: "Link to"
83
+ }), /* @__PURE__ */ jsxs("select", {
84
+ className: "border-input bg-background text-foreground rounded border px-2 py-1.5 text-[13px] outline-none",
85
+ id: fieldIds.targetType,
86
+ onChange: (e) => setTargetType(toTargetType(e.target.value)),
87
+ value: targetType,
88
+ children: [/* @__PURE__ */ jsx("option", {
89
+ value: "url",
90
+ children: "Web address"
91
+ }), /* @__PURE__ */ jsx("option", {
92
+ value: "bookmark",
93
+ children: "Bookmark"
94
+ })]
95
+ })]
96
+ }),
97
+ targetType === "url" && /* @__PURE__ */ jsxs("label", {
98
+ className: "flex flex-col gap-1",
99
+ htmlFor: fieldIds.url,
100
+ children: [
101
+ /* @__PURE__ */ jsx("span", {
102
+ className: "text-muted-foreground text-[13px]",
103
+ children: "Address"
104
+ }),
105
+ /* @__PURE__ */ jsx("input", {
106
+ "aria-invalid": touched && urlError.length > 0,
107
+ className: "border-input bg-background text-foreground rounded border px-2 py-1.5 text-[13px] outline-none",
108
+ id: fieldIds.url,
109
+ onBlur: () => setTouched(true),
110
+ onChange: (e_0) => setUrl(e_0.target.value),
111
+ placeholder: "https://example.com",
112
+ value: url
113
+ }),
114
+ touched && urlError.length > 0 && /* @__PURE__ */ jsx("span", {
115
+ className: "text-destructive text-xs",
116
+ children: urlError
117
+ })
118
+ ]
119
+ }),
120
+ targetType === "bookmark" && /* @__PURE__ */ jsxs("label", {
121
+ className: "flex flex-col gap-1",
122
+ htmlFor: fieldIds.bookmark,
123
+ children: [/* @__PURE__ */ jsx("span", {
124
+ className: "text-muted-foreground text-[13px]",
125
+ children: "Bookmark"
126
+ }), /* @__PURE__ */ jsxs("select", {
127
+ className: "border-input bg-background text-foreground rounded border px-2 py-1.5 text-[13px] outline-none",
128
+ id: fieldIds.bookmark,
129
+ onChange: (e_1) => setBookmark(e_1.target.value),
130
+ value: bookmark,
131
+ children: [/* @__PURE__ */ jsx("option", {
132
+ value: "",
133
+ children: "Select a bookmark"
134
+ }), bookmarks.map((option) => /* @__PURE__ */ jsx("option", {
135
+ value: option.name,
136
+ children: option.label ?? option.name
137
+ }, option.name))]
138
+ })]
139
+ }),
140
+ /* @__PURE__ */ jsxs("label", {
141
+ className: "flex flex-col gap-1",
142
+ htmlFor: fieldIds.displayText,
143
+ children: [/* @__PURE__ */ jsx("span", {
144
+ className: DIALOG_LABEL_CLASS,
145
+ children: "Text to display"
146
+ }), /* @__PURE__ */ jsx("input", {
147
+ className: DIALOG_INPUT_CLASS,
148
+ id: fieldIds.displayText,
149
+ onChange: (e_2) => setDisplayText(e_2.target.value),
150
+ value: displayText
151
+ })]
152
+ }),
153
+ /* @__PURE__ */ jsxs("label", {
154
+ className: "flex flex-col gap-1",
155
+ htmlFor: fieldIds.tooltip,
156
+ children: [/* @__PURE__ */ jsx("span", {
157
+ className: DIALOG_LABEL_CLASS,
158
+ children: "Screen tip"
159
+ }), /* @__PURE__ */ jsx("input", {
160
+ className: DIALOG_INPUT_CLASS,
161
+ id: fieldIds.tooltip,
162
+ onChange: (e_3) => setTooltip(e_3.target.value),
163
+ value: tooltip
164
+ })]
165
+ })
166
+ ]
167
+ }),
168
+ /* @__PURE__ */ jsxs("div", {
169
+ className: DIALOG_FOOTER_CLASS,
170
+ children: [
171
+ isEditing && onRemove && /* @__PURE__ */ jsx("button", {
172
+ className: "text-destructive me-auto rounded px-4 py-1.5 text-[13px]",
173
+ onClick: handleRemove,
174
+ type: "button",
175
+ children: "Remove"
176
+ }),
177
+ /* @__PURE__ */ jsx(DialogClose, {
178
+ className: DIALOG_SECONDARY_BUTTON_CLASS,
179
+ children: "Cancel"
180
+ }),
181
+ /* @__PURE__ */ jsx("button", {
182
+ className: DIALOG_PRIMARY_BUTTON_CLASS,
183
+ disabled: !canSubmit,
184
+ onClick: handleSubmit,
185
+ type: "button",
186
+ children: isEditing ? "Update" : "Insert"
187
+ })
188
+ ]
189
+ })
190
+ ]
191
+ })] })
192
+ });
193
+ }
194
+ function toTargetType(value) {
195
+ return value === "bookmark" ? "bookmark" : "url";
196
+ }
197
+ function getUrlError(value) {
198
+ const trimmed = value.trim();
199
+ if (!trimmed) return "Enter an address.";
200
+ if (/^(mailto:|tel:)/iu.test(trimmed)) return trimmed.replace(/^(mailto:|tel:)/iu, "").length > 0 ? "" : "Enter an address.";
201
+ if (/^ftp:\/\//iu.test(trimmed)) return trimmed.length > 6 ? "" : "Enter an address.";
202
+ try {
203
+ const parsed = new URL(/^https?:\/\//iu.test(trimmed) ? trimmed : `https://${trimmed}`);
204
+ return parsed.protocol === "http:" || parsed.protocol === "https:" ? "" : "Use a web address.";
205
+ } catch {
206
+ return "Enter a valid address.";
207
+ }
208
+ }
209
+ function normalizeUrl(value) {
210
+ const trimmed = value.trim();
211
+ if (/^(https?:\/\/|mailto:|tel:|ftp:\/\/)/iu.test(trimmed)) return trimmed;
212
+ return `https://${trimmed}`;
213
+ }
214
+ //#endregion
215
+ //#region src/components/dialogs/InsertImageDialog.tsx
216
+ function InsertImageDialog({ isOpen, onClose, onInsert, accept = "image/png,image/jpeg,image/gif,image/webp" }) {
217
+ const { Root: Dialog, Portal: DialogPortal, Backdrop: DialogBackdrop, Popup: DialogPopup, Title: DialogTitle, Close: DialogClose } = useFolioUI().Dialog;
218
+ const handleOpenChange = useCloseOnDialogOpenChange(onClose);
219
+ const id = useId();
220
+ const [file, setFile] = useState(null);
221
+ const [alt, setAlt] = useState("");
222
+ const [width, setWidth] = useState("");
223
+ const [height, setHeight] = useState("");
224
+ useEffect(() => {
225
+ if (!isOpen) return;
226
+ setFile(null);
227
+ setAlt("");
228
+ setWidth("");
229
+ setHeight("");
230
+ }, [isOpen]);
231
+ const fieldIds = {
232
+ file: `${id}-insert-image-file`,
233
+ alt: `${id}-insert-image-alt`,
234
+ width: `${id}-insert-image-width`,
235
+ height: `${id}-insert-image-height`
236
+ };
237
+ const handleInsert = () => {
238
+ if (!file) return;
239
+ const parsedWidth = toPositiveNumber(width);
240
+ const parsedHeight = toPositiveNumber(height);
241
+ onInsert({
242
+ file,
243
+ ...alt.trim() ? { alt: alt.trim() } : {},
244
+ ...parsedWidth ? { width: parsedWidth } : {},
245
+ ...parsedHeight ? { height: parsedHeight } : {}
246
+ });
247
+ onClose();
248
+ };
249
+ return /* @__PURE__ */ jsx(Dialog, {
250
+ open: isOpen,
251
+ onOpenChange: handleOpenChange,
252
+ children: /* @__PURE__ */ jsxs(DialogPortal, { children: [/* @__PURE__ */ jsx(DialogBackdrop, { className: DIALOG_BACKDROP_CLASS }), /* @__PURE__ */ jsxs(DialogPopup, {
253
+ className: DIALOG_POPUP_CLASS,
254
+ children: [
255
+ /* @__PURE__ */ jsx(DialogTitle, {
256
+ className: DIALOG_TITLE_CLASS,
257
+ children: "Insert Image"
258
+ }),
259
+ /* @__PURE__ */ jsxs("div", {
260
+ className: DIALOG_BODY_CLASS,
261
+ children: [
262
+ /* @__PURE__ */ jsxs("label", {
263
+ className: "flex flex-col gap-1",
264
+ htmlFor: fieldIds.file,
265
+ children: [/* @__PURE__ */ jsx("span", {
266
+ className: DIALOG_LABEL_CLASS,
267
+ children: "Image file"
268
+ }), /* @__PURE__ */ jsx("input", {
269
+ accept,
270
+ className: DIALOG_INPUT_CLASS,
271
+ id: fieldIds.file,
272
+ onChange: (e) => setFile(e.target.files?.[0] ?? null),
273
+ type: "file"
274
+ })]
275
+ }),
276
+ /* @__PURE__ */ jsxs("label", {
277
+ className: "flex flex-col gap-1",
278
+ htmlFor: fieldIds.alt,
279
+ children: [/* @__PURE__ */ jsx("span", {
280
+ className: DIALOG_LABEL_CLASS,
281
+ children: "Alt text"
282
+ }), /* @__PURE__ */ jsx("input", {
283
+ className: DIALOG_INPUT_CLASS,
284
+ id: fieldIds.alt,
285
+ onChange: (e_0) => setAlt(e_0.target.value),
286
+ placeholder: file?.name ?? "",
287
+ value: alt
288
+ })]
289
+ }),
290
+ /* @__PURE__ */ jsxs("div", {
291
+ className: "grid grid-cols-2 gap-3",
292
+ children: [/* @__PURE__ */ jsxs("label", {
293
+ className: "flex flex-col gap-1",
294
+ htmlFor: fieldIds.width,
295
+ children: [/* @__PURE__ */ jsx("span", {
296
+ className: DIALOG_LABEL_CLASS,
297
+ children: "Width"
298
+ }), /* @__PURE__ */ jsx("input", {
299
+ className: DIALOG_INPUT_CLASS,
300
+ id: fieldIds.width,
301
+ min: 1,
302
+ onChange: (e_1) => setWidth(e_1.target.value),
303
+ placeholder: "Auto",
304
+ type: "number",
305
+ value: width
306
+ })]
307
+ }), /* @__PURE__ */ jsxs("label", {
308
+ className: "flex flex-col gap-1",
309
+ htmlFor: fieldIds.height,
310
+ children: [/* @__PURE__ */ jsx("span", {
311
+ className: DIALOG_LABEL_CLASS,
312
+ children: "Height"
313
+ }), /* @__PURE__ */ jsx("input", {
314
+ className: DIALOG_INPUT_CLASS,
315
+ id: fieldIds.height,
316
+ min: 1,
317
+ onChange: (e_2) => setHeight(e_2.target.value),
318
+ placeholder: "Auto",
319
+ type: "number",
320
+ value: height
321
+ })]
322
+ })]
323
+ })
324
+ ]
325
+ }),
326
+ /* @__PURE__ */ jsxs("div", {
327
+ className: DIALOG_FOOTER_CLASS,
328
+ children: [/* @__PURE__ */ jsx(DialogClose, {
329
+ className: DIALOG_SECONDARY_BUTTON_CLASS,
330
+ children: "Cancel"
331
+ }), /* @__PURE__ */ jsx("button", {
332
+ className: DIALOG_PRIMARY_BUTTON_CLASS,
333
+ disabled: !file,
334
+ onClick: handleInsert,
335
+ type: "button",
336
+ children: "Insert"
337
+ })]
338
+ })
339
+ ]
340
+ })] })
341
+ });
342
+ }
343
+ function toPositiveNumber(value) {
344
+ const parsed = Number(value);
345
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
346
+ }
347
+ //#endregion
348
+ //#region src/components/dialogs/InsertTableDialog.tsx
349
+ const GRID_ROWS = 8;
350
+ const GRID_COLUMNS = 10;
351
+ const MIN_ROWS = 1;
352
+ const MAX_ROWS = 100;
353
+ const MIN_COLUMNS = 1;
354
+ const MAX_COLUMNS = 20;
355
+ const DEFAULT_STYLE_OPTIONS = [
356
+ {
357
+ id: "TableGrid",
358
+ name: "Table Grid"
359
+ },
360
+ {
361
+ id: "TableNormal",
362
+ name: "Normal Table"
363
+ },
364
+ {
365
+ id: "TableGridLight",
366
+ name: "Grid Table Light"
367
+ }
368
+ ];
369
+ function InsertTableDialog({ isOpen, onClose, onInsert, defaultRows = 3, defaultColumns = 3, styleOptions = DEFAULT_STYLE_OPTIONS }) {
370
+ const { Root: Dialog, Portal: DialogPortal, Backdrop: DialogBackdrop, Popup: DialogPopup, Title: DialogTitle, Close: DialogClose } = useFolioUI().Dialog;
371
+ const handleOpenChange = useCloseOnDialogOpenChange(onClose);
372
+ const id = useId();
373
+ const [rows, setRows] = useState(defaultRows);
374
+ const [columns, setColumns] = useState(defaultColumns);
375
+ const [hoverRows, setHoverRows] = useState(0);
376
+ const [hoverColumns, setHoverColumns] = useState(0);
377
+ const [autofit, setAutofit] = useState(false);
378
+ const [styleId, setStyleId] = useState("");
379
+ useEffect(() => {
380
+ if (!isOpen) return;
381
+ setRows(defaultRows);
382
+ setColumns(defaultColumns);
383
+ setHoverRows(0);
384
+ setHoverColumns(0);
385
+ setAutofit(false);
386
+ setStyleId("");
387
+ }, [
388
+ isOpen,
389
+ defaultRows,
390
+ defaultColumns
391
+ ]);
392
+ const normalizedRows = clampInteger$1(rows, MIN_ROWS, MAX_ROWS);
393
+ const normalizedColumns = clampInteger$1(columns, MIN_COLUMNS, MAX_COLUMNS);
394
+ const canInsert = Number.isFinite(rows) && Number.isFinite(columns);
395
+ const fieldIds = {
396
+ rows: `${id}-insert-table-rows`,
397
+ columns: `${id}-insert-table-columns`,
398
+ autofit: `${id}-insert-table-autofit`,
399
+ style: `${id}-insert-table-style`
400
+ };
401
+ const handleInsert = () => {
402
+ if (!canInsert) return;
403
+ onInsert({
404
+ rows: normalizedRows,
405
+ columns: normalizedColumns,
406
+ autofit,
407
+ ...styleId ? { styleId } : {}
408
+ });
409
+ onClose();
410
+ };
411
+ return /* @__PURE__ */ jsx(Dialog, {
412
+ open: isOpen,
413
+ onOpenChange: handleOpenChange,
414
+ children: /* @__PURE__ */ jsxs(DialogPortal, { children: [/* @__PURE__ */ jsx(DialogBackdrop, { className: DIALOG_BACKDROP_CLASS }), /* @__PURE__ */ jsxs(DialogPopup, {
415
+ className: DIALOG_POPUP_CLASS,
416
+ children: [
417
+ /* @__PURE__ */ jsx(DialogTitle, {
418
+ className: DIALOG_TITLE_CLASS,
419
+ children: "Insert Table"
420
+ }),
421
+ /* @__PURE__ */ jsxs("div", {
422
+ className: DIALOG_BODY_CLASS,
423
+ children: [
424
+ /* @__PURE__ */ jsx("div", {
425
+ className: "grid w-max grid-cols-10 gap-1",
426
+ onMouseLeave: () => {
427
+ setHoverRows(0);
428
+ setHoverColumns(0);
429
+ },
430
+ children: Array.from({ length: GRID_ROWS }).map((_, rowIndex) => Array.from({ length: GRID_COLUMNS }).map((__, columnIndex) => {
431
+ const row = rowIndex + 1;
432
+ const column = columnIndex + 1;
433
+ const active = row <= hoverRows && column <= hoverColumns;
434
+ return /* @__PURE__ */ jsx("button", {
435
+ "aria-label": `${row} by ${column} table`,
436
+ className: `h-5 w-5 rounded-sm border ${active ? "border-primary bg-primary/20" : "border-input bg-background"}`,
437
+ onClick: () => {
438
+ setRows(row);
439
+ setColumns(column);
440
+ },
441
+ onMouseEnter: () => {
442
+ setHoverRows(row);
443
+ setHoverColumns(column);
444
+ },
445
+ type: "button"
446
+ }, `${row}-${column}`);
447
+ }))
448
+ }),
449
+ /* @__PURE__ */ jsx("div", {
450
+ className: "text-muted-foreground text-xs",
451
+ children: hoverRows > 0 ? `${hoverColumns} columns x ${hoverRows} rows` : `${normalizedColumns} columns x ${normalizedRows} rows`
452
+ }),
453
+ /* @__PURE__ */ jsxs("div", {
454
+ className: "grid grid-cols-2 gap-3",
455
+ children: [/* @__PURE__ */ jsxs("label", {
456
+ className: "flex flex-col gap-1",
457
+ htmlFor: fieldIds.rows,
458
+ children: [/* @__PURE__ */ jsx("span", {
459
+ className: DIALOG_LABEL_CLASS,
460
+ children: "Rows"
461
+ }), /* @__PURE__ */ jsx("input", {
462
+ className: DIALOG_INPUT_CLASS,
463
+ id: fieldIds.rows,
464
+ max: MAX_ROWS,
465
+ min: MIN_ROWS,
466
+ onChange: (e) => setRows(Number(e.target.value) || MIN_ROWS),
467
+ type: "number",
468
+ value: rows
469
+ })]
470
+ }), /* @__PURE__ */ jsxs("label", {
471
+ className: "flex flex-col gap-1",
472
+ htmlFor: fieldIds.columns,
473
+ children: [/* @__PURE__ */ jsx("span", {
474
+ className: DIALOG_LABEL_CLASS,
475
+ children: "Columns"
476
+ }), /* @__PURE__ */ jsx("input", {
477
+ className: DIALOG_INPUT_CLASS,
478
+ id: fieldIds.columns,
479
+ max: MAX_COLUMNS,
480
+ min: MIN_COLUMNS,
481
+ onChange: (e_0) => setColumns(Number(e_0.target.value) || MIN_COLUMNS),
482
+ type: "number",
483
+ value: columns
484
+ })]
485
+ })]
486
+ }),
487
+ /* @__PURE__ */ jsxs("label", {
488
+ className: "flex items-center gap-2",
489
+ htmlFor: fieldIds.autofit,
490
+ children: [/* @__PURE__ */ jsx("input", {
491
+ checked: autofit,
492
+ id: fieldIds.autofit,
493
+ onChange: (e_1) => setAutofit(e_1.target.checked),
494
+ type: "checkbox"
495
+ }), /* @__PURE__ */ jsx("span", {
496
+ className: DIALOG_LABEL_CLASS,
497
+ children: "Autofit to contents"
498
+ })]
499
+ }),
500
+ styleOptions.length > 0 && /* @__PURE__ */ jsxs("label", {
501
+ className: "flex flex-col gap-1",
502
+ htmlFor: fieldIds.style,
503
+ children: [/* @__PURE__ */ jsx("span", {
504
+ className: "text-muted-foreground text-[13px]",
505
+ children: "Style"
506
+ }), /* @__PURE__ */ jsxs("select", {
507
+ className: "border-input bg-background text-foreground rounded border px-2 py-1.5 text-[13px] outline-none",
508
+ id: fieldIds.style,
509
+ onChange: (e_2) => setStyleId(e_2.target.value),
510
+ value: styleId,
511
+ children: [/* @__PURE__ */ jsx("option", {
512
+ value: "",
513
+ children: "Plain table"
514
+ }), styleOptions.map((style) => /* @__PURE__ */ jsx("option", {
515
+ value: style.id,
516
+ children: style.name
517
+ }, style.id))]
518
+ })]
519
+ })
520
+ ]
521
+ }),
522
+ /* @__PURE__ */ jsxs("div", {
523
+ className: DIALOG_FOOTER_CLASS,
524
+ children: [/* @__PURE__ */ jsx(DialogClose, {
525
+ className: DIALOG_SECONDARY_BUTTON_CLASS,
526
+ children: "Cancel"
527
+ }), /* @__PURE__ */ jsx("button", {
528
+ className: DIALOG_PRIMARY_BUTTON_CLASS,
529
+ disabled: !canInsert,
530
+ onClick: handleInsert,
531
+ type: "button",
532
+ children: "Insert"
533
+ })]
534
+ })
535
+ ]
536
+ })] })
537
+ });
538
+ }
539
+ function clampInteger$1(value, min, max) {
540
+ return Math.min(max, Math.max(min, Math.trunc(value)));
541
+ }
542
+ //#endregion
543
+ //#region src/components/dialogs/PasteSpecialDialog.tsx
544
+ const PASTE_MODES = [
545
+ {
546
+ value: "keepFormatting",
547
+ label: "Keep source formatting",
548
+ description: "Preserve styles, links, and inline formatting from the clipboard."
549
+ },
550
+ {
551
+ value: "mergeFormatting",
552
+ label: "Merge formatting",
553
+ description: "Keep useful inline formatting while matching the destination paragraph."
554
+ },
555
+ {
556
+ value: "plainText",
557
+ label: "Unformatted text",
558
+ description: "Paste text only and use the destination formatting."
559
+ }
560
+ ];
561
+ function PasteSpecialDialog({ isOpen, onClose, onPaste, defaultMode = "plainText" }) {
562
+ const { Root: Dialog, Portal: DialogPortal, Backdrop: DialogBackdrop, Popup: DialogPopup, Title: DialogTitle, Close: DialogClose } = useFolioUI().Dialog;
563
+ const handleOpenChange = useCloseOnDialogOpenChange(onClose);
564
+ const id = useId();
565
+ const [mode, setMode] = useState(defaultMode);
566
+ useEffect(() => {
567
+ if (isOpen) setMode(defaultMode);
568
+ }, [isOpen, defaultMode]);
569
+ const handlePaste = () => {
570
+ onPaste(mode);
571
+ onClose();
572
+ };
573
+ return /* @__PURE__ */ jsx(Dialog, {
574
+ open: isOpen,
575
+ onOpenChange: handleOpenChange,
576
+ children: /* @__PURE__ */ jsxs(DialogPortal, { children: [/* @__PURE__ */ jsx(DialogBackdrop, { className: DIALOG_BACKDROP_CLASS }), /* @__PURE__ */ jsxs(DialogPopup, {
577
+ className: DIALOG_POPUP_CLASS,
578
+ children: [
579
+ /* @__PURE__ */ jsx(DialogTitle, {
580
+ className: DIALOG_TITLE_CLASS,
581
+ children: "Paste Special"
582
+ }),
583
+ /* @__PURE__ */ jsx("div", {
584
+ className: DIALOG_BODY_CLASS,
585
+ children: /* @__PURE__ */ jsxs("fieldset", {
586
+ className: "flex flex-col gap-3",
587
+ children: [/* @__PURE__ */ jsx("legend", {
588
+ className: DIALOG_LABEL_CLASS,
589
+ children: "Paste mode"
590
+ }), PASTE_MODES.map((option) => {
591
+ const optionId = `${id}-paste-special-${option.value}`;
592
+ return /* @__PURE__ */ jsxs("label", {
593
+ className: "flex items-start gap-3",
594
+ htmlFor: optionId,
595
+ children: [/* @__PURE__ */ jsx("input", {
596
+ checked: mode === option.value,
597
+ id: optionId,
598
+ onChange: () => setMode(option.value),
599
+ type: "radio"
600
+ }), /* @__PURE__ */ jsxs("span", {
601
+ className: "flex flex-col gap-1",
602
+ children: [/* @__PURE__ */ jsx("span", {
603
+ className: "text-foreground text-[13px] font-medium",
604
+ children: option.label
605
+ }), /* @__PURE__ */ jsx("span", {
606
+ className: "text-muted-foreground text-xs",
607
+ children: option.description
608
+ })]
609
+ })]
610
+ }, option.value);
611
+ })]
612
+ })
613
+ }),
614
+ /* @__PURE__ */ jsxs("div", {
615
+ className: DIALOG_FOOTER_CLASS,
616
+ children: [/* @__PURE__ */ jsx(DialogClose, {
617
+ className: DIALOG_SECONDARY_BUTTON_CLASS,
618
+ children: "Cancel"
619
+ }), /* @__PURE__ */ jsx("button", {
620
+ className: DIALOG_PRIMARY_BUTTON_CLASS,
621
+ onClick: handlePaste,
622
+ type: "button",
623
+ children: "Paste"
624
+ })]
625
+ })
626
+ ]
627
+ })] })
628
+ });
629
+ }
630
+ //#endregion
631
+ //#region src/components/dialogs/SplitCellDialog.tsx
632
+ const MIN_PARTS = 1;
633
+ const MAX_PARTS = 63;
634
+ function SplitCellDialog({ isOpen, onClose, onSplit, defaultRows = 1, defaultColumns = 2 }) {
635
+ const { Root: Dialog, Portal: DialogPortal, Backdrop: DialogBackdrop, Popup: DialogPopup, Title: DialogTitle, Close: DialogClose } = useFolioUI().Dialog;
636
+ const handleOpenChange = useCloseOnDialogOpenChange(onClose);
637
+ const id = useId();
638
+ const [rows, setRows] = useState(defaultRows);
639
+ const [columns, setColumns] = useState(defaultColumns);
640
+ const [mergeBeforeSplit, setMergeBeforeSplit] = useState(false);
641
+ useEffect(() => {
642
+ if (!isOpen) return;
643
+ setRows(defaultRows);
644
+ setColumns(defaultColumns);
645
+ setMergeBeforeSplit(false);
646
+ }, [
647
+ isOpen,
648
+ defaultRows,
649
+ defaultColumns
650
+ ]);
651
+ const normalizedRows = clampInteger(rows);
652
+ const normalizedColumns = clampInteger(columns);
653
+ const canSplit = normalizedRows > 1 || normalizedColumns > 1;
654
+ const fieldIds = {
655
+ rows: `${id}-split-cell-rows`,
656
+ columns: `${id}-split-cell-columns`,
657
+ mergeBeforeSplit: `${id}-split-cell-merge-before-split`
658
+ };
659
+ const handleSplit = () => {
660
+ if (!canSplit) return;
661
+ onSplit({
662
+ rows: normalizedRows,
663
+ columns: normalizedColumns,
664
+ mergeBeforeSplit
665
+ });
666
+ onClose();
667
+ };
668
+ return /* @__PURE__ */ jsx(Dialog, {
669
+ open: isOpen,
670
+ onOpenChange: handleOpenChange,
671
+ children: /* @__PURE__ */ jsxs(DialogPortal, { children: [/* @__PURE__ */ jsx(DialogBackdrop, { className: DIALOG_BACKDROP_CLASS }), /* @__PURE__ */ jsxs(DialogPopup, {
672
+ className: DIALOG_POPUP_CLASS,
673
+ children: [
674
+ /* @__PURE__ */ jsx(DialogTitle, {
675
+ className: DIALOG_TITLE_CLASS,
676
+ children: "Split Cell"
677
+ }),
678
+ /* @__PURE__ */ jsxs("div", {
679
+ className: DIALOG_BODY_CLASS,
680
+ children: [/* @__PURE__ */ jsxs("div", {
681
+ className: "grid grid-cols-2 gap-3",
682
+ children: [/* @__PURE__ */ jsxs("label", {
683
+ className: "flex flex-col gap-1",
684
+ htmlFor: fieldIds.columns,
685
+ children: [/* @__PURE__ */ jsx("span", {
686
+ className: DIALOG_LABEL_CLASS,
687
+ children: "Columns"
688
+ }), /* @__PURE__ */ jsx("input", {
689
+ className: DIALOG_INPUT_CLASS,
690
+ id: fieldIds.columns,
691
+ max: MAX_PARTS,
692
+ min: MIN_PARTS,
693
+ onChange: (e) => setColumns(Number(e.target.value) || MIN_PARTS),
694
+ type: "number",
695
+ value: columns
696
+ })]
697
+ }), /* @__PURE__ */ jsxs("label", {
698
+ className: "flex flex-col gap-1",
699
+ htmlFor: fieldIds.rows,
700
+ children: [/* @__PURE__ */ jsx("span", {
701
+ className: DIALOG_LABEL_CLASS,
702
+ children: "Rows"
703
+ }), /* @__PURE__ */ jsx("input", {
704
+ className: DIALOG_INPUT_CLASS,
705
+ id: fieldIds.rows,
706
+ max: MAX_PARTS,
707
+ min: MIN_PARTS,
708
+ onChange: (e_0) => setRows(Number(e_0.target.value) || MIN_PARTS),
709
+ type: "number",
710
+ value: rows
711
+ })]
712
+ })]
713
+ }), /* @__PURE__ */ jsxs("label", {
714
+ className: "flex items-center gap-2",
715
+ htmlFor: fieldIds.mergeBeforeSplit,
716
+ children: [/* @__PURE__ */ jsx("input", {
717
+ checked: mergeBeforeSplit,
718
+ id: fieldIds.mergeBeforeSplit,
719
+ onChange: (e_1) => setMergeBeforeSplit(e_1.target.checked),
720
+ type: "checkbox"
721
+ }), /* @__PURE__ */ jsx("span", {
722
+ className: DIALOG_LABEL_CLASS,
723
+ children: "Merge selected cells before splitting"
724
+ })]
725
+ })]
726
+ }),
727
+ /* @__PURE__ */ jsxs("div", {
728
+ className: DIALOG_FOOTER_CLASS,
729
+ children: [/* @__PURE__ */ jsx(DialogClose, {
730
+ className: DIALOG_SECONDARY_BUTTON_CLASS,
731
+ children: "Cancel"
732
+ }), /* @__PURE__ */ jsx("button", {
733
+ className: DIALOG_PRIMARY_BUTTON_CLASS,
734
+ disabled: !canSplit,
735
+ onClick: handleSplit,
736
+ type: "button",
737
+ children: "Split"
738
+ })]
739
+ })
740
+ ]
741
+ })] })
742
+ });
743
+ }
744
+ function clampInteger(value) {
745
+ return Math.min(MAX_PARTS, Math.max(MIN_PARTS, Math.trunc(value)));
746
+ }
747
+ //#endregion
748
+ //#region src/components/dialogs/WatermarkDialog.tsx
749
+ const DEFAULT_TEXT_COLOR = "#C0C0C0";
750
+ function WatermarkDialog(t0) {
751
+ const $ = c(100);
752
+ const { isOpen, onClose, onApply, currentWatermark } = t0;
753
+ const { Root: Dialog, Portal: DialogPortal, Backdrop: DialogBackdrop, Popup: DialogPopup, Title: DialogTitle, Close: DialogClose } = useFolioUI().Dialog;
754
+ const handleOpenChange = useCloseOnDialogOpenChange(onClose);
755
+ const id = useId();
756
+ const [mode, setMode] = useState("text");
757
+ const [text, setText] = useState("CONFIDENTIAL");
758
+ const [font, setFont] = useState("Calibri");
759
+ const [color, setColor] = useState(DEFAULT_TEXT_COLOR);
760
+ const [diagonal, setDiagonal] = useState(true);
761
+ const [opacityPercent, setOpacityPercent] = useState(50);
762
+ const [imageRId, setImageRId] = useState("");
763
+ const [imageTarget, setImageTarget] = useState("");
764
+ const [imageTargetExternal, setImageTargetExternal] = useState(false);
765
+ const [scalePercent, setScalePercent] = useState(100);
766
+ const [washout, setWashout] = useState(true);
767
+ let t1;
768
+ let t2;
769
+ if ($[0] !== currentWatermark || $[1] !== isOpen) {
770
+ t1 = () => {
771
+ if (!isOpen) return;
772
+ if (!currentWatermark) {
773
+ setMode("text");
774
+ setText("CONFIDENTIAL");
775
+ setFont("Calibri");
776
+ setColor(DEFAULT_TEXT_COLOR);
777
+ setDiagonal(true);
778
+ setOpacityPercent(50);
779
+ setImageRId("");
780
+ setImageTarget("");
781
+ setImageTargetExternal(false);
782
+ setScalePercent(100);
783
+ setWashout(true);
784
+ return;
785
+ }
786
+ setMode(currentWatermark.kind);
787
+ if (currentWatermark.kind === "text") {
788
+ setText(currentWatermark.text);
789
+ setFont(currentWatermark.font ?? "Calibri");
790
+ setColor(toColorInputValue(currentWatermark.color));
791
+ setDiagonal(currentWatermark.diagonal ?? true);
792
+ setOpacityPercent(Math.round((currentWatermark.opacity ?? .5) * 100));
793
+ return;
794
+ }
795
+ setImageRId(currentWatermark.imageRId);
796
+ setImageTarget(currentWatermark.imageTarget ?? "");
797
+ setImageTargetExternal(currentWatermark.imageTargetExternal ?? false);
798
+ setScalePercent(Math.round((currentWatermark.scale ?? 1) * 100));
799
+ setWashout(currentWatermark.washout ?? true);
800
+ };
801
+ t2 = [isOpen, currentWatermark];
802
+ $[0] = currentWatermark;
803
+ $[1] = isOpen;
804
+ $[2] = t1;
805
+ $[3] = t2;
806
+ } else {
807
+ t1 = $[2];
808
+ t2 = $[3];
809
+ }
810
+ useEffect(t1, t2);
811
+ const t3 = `${id}-watermark-mode`;
812
+ const t4 = `${id}-watermark-text`;
813
+ const t5 = `${id}-watermark-font`;
814
+ const t6 = `${id}-watermark-color`;
815
+ const t7 = `${id}-watermark-diagonal`;
816
+ const t8 = `${id}-watermark-opacity`;
817
+ const t9 = `${id}-watermark-image-rid`;
818
+ const t10 = `${id}-watermark-image-target`;
819
+ const t11 = `${id}-watermark-image-external`;
820
+ const t12 = `${id}-watermark-scale`;
821
+ const t13 = `${id}-watermark-washout`;
822
+ let t14;
823
+ if ($[4] !== t10 || $[5] !== t11 || $[6] !== t12 || $[7] !== t13 || $[8] !== t3 || $[9] !== t4 || $[10] !== t5 || $[11] !== t6 || $[12] !== t7 || $[13] !== t8 || $[14] !== t9) {
824
+ t14 = {
825
+ mode: t3,
826
+ text: t4,
827
+ font: t5,
828
+ color: t6,
829
+ diagonal: t7,
830
+ opacity: t8,
831
+ imageRId: t9,
832
+ imageTarget: t10,
833
+ imageTargetExternal: t11,
834
+ scale: t12,
835
+ washout: t13
836
+ };
837
+ $[4] = t10;
838
+ $[5] = t11;
839
+ $[6] = t12;
840
+ $[7] = t13;
841
+ $[8] = t3;
842
+ $[9] = t4;
843
+ $[10] = t5;
844
+ $[11] = t6;
845
+ $[12] = t7;
846
+ $[13] = t8;
847
+ $[14] = t9;
848
+ $[15] = t14;
849
+ } else t14 = $[15];
850
+ const fieldIds = t14;
851
+ let t15;
852
+ if ($[16] !== imageRId || $[17] !== mode || $[18] !== text) {
853
+ t15 = mode === "none" || mode === "text" && text.trim().length > 0 || mode === "picture" && imageRId.trim().length > 0;
854
+ $[16] = imageRId;
855
+ $[17] = mode;
856
+ $[18] = text;
857
+ $[19] = t15;
858
+ } else t15 = $[19];
859
+ const canApply = t15;
860
+ let t16;
861
+ if ($[20] !== canApply || $[21] !== color || $[22] !== diagonal || $[23] !== font || $[24] !== imageRId || $[25] !== imageTarget || $[26] !== imageTargetExternal || $[27] !== mode || $[28] !== onApply || $[29] !== onClose || $[30] !== opacityPercent || $[31] !== scalePercent || $[32] !== text || $[33] !== washout) {
862
+ t16 = () => {
863
+ if (!canApply) return;
864
+ if (mode === "none") {
865
+ onApply(void 0);
866
+ onClose();
867
+ return;
868
+ }
869
+ if (mode === "text") {
870
+ onApply({
871
+ kind: "text",
872
+ text: text.trim(),
873
+ ...font.trim() ? { font: font.trim() } : {},
874
+ color: stripHash(color),
875
+ diagonal,
876
+ opacity: clampPercent(opacityPercent) / 100
877
+ });
878
+ onClose();
879
+ return;
880
+ }
881
+ onApply({
882
+ kind: "picture",
883
+ imageRId: imageRId.trim(),
884
+ ...imageTarget.trim() ? { imageTarget: imageTarget.trim() } : {},
885
+ ...imageTarget.trim() ? { imageTargetExternal } : {},
886
+ scale: clampScalePercent(scalePercent) / 100,
887
+ washout
888
+ });
889
+ onClose();
890
+ };
891
+ $[20] = canApply;
892
+ $[21] = color;
893
+ $[22] = diagonal;
894
+ $[23] = font;
895
+ $[24] = imageRId;
896
+ $[25] = imageTarget;
897
+ $[26] = imageTargetExternal;
898
+ $[27] = mode;
899
+ $[28] = onApply;
900
+ $[29] = onClose;
901
+ $[30] = opacityPercent;
902
+ $[31] = scalePercent;
903
+ $[32] = text;
904
+ $[33] = washout;
905
+ $[34] = t16;
906
+ } else t16 = $[34];
907
+ const handleApply = t16;
908
+ let t17;
909
+ if ($[35] !== DialogBackdrop) {
910
+ t17 = /* @__PURE__ */ jsx(DialogBackdrop, { className: DIALOG_BACKDROP_CLASS });
911
+ $[35] = DialogBackdrop;
912
+ $[36] = t17;
913
+ } else t17 = $[36];
914
+ let t18;
915
+ if ($[37] !== DialogTitle) {
916
+ t18 = /* @__PURE__ */ jsx(DialogTitle, {
917
+ className: DIALOG_TITLE_CLASS,
918
+ children: "Watermark"
919
+ });
920
+ $[37] = DialogTitle;
921
+ $[38] = t18;
922
+ } else t18 = $[38];
923
+ let t19;
924
+ if ($[39] === Symbol.for("react.memo_cache_sentinel")) {
925
+ t19 = /* @__PURE__ */ jsx("span", {
926
+ className: DIALOG_LABEL_CLASS,
927
+ children: "Type"
928
+ });
929
+ $[39] = t19;
930
+ } else t19 = $[39];
931
+ let t20;
932
+ if ($[40] === Symbol.for("react.memo_cache_sentinel")) {
933
+ t20 = (e) => setMode(toWatermarkMode(e.target.value));
934
+ $[40] = t20;
935
+ } else t20 = $[40];
936
+ let t21;
937
+ let t22;
938
+ let t23;
939
+ if ($[41] === Symbol.for("react.memo_cache_sentinel")) {
940
+ t21 = /* @__PURE__ */ jsx("option", {
941
+ value: "text",
942
+ children: "Text watermark"
943
+ });
944
+ t22 = /* @__PURE__ */ jsx("option", {
945
+ value: "picture",
946
+ children: "Picture watermark"
947
+ });
948
+ t23 = /* @__PURE__ */ jsx("option", {
949
+ value: "none",
950
+ children: "No watermark"
951
+ });
952
+ $[41] = t21;
953
+ $[42] = t22;
954
+ $[43] = t23;
955
+ } else {
956
+ t21 = $[41];
957
+ t22 = $[42];
958
+ t23 = $[43];
959
+ }
960
+ let t24;
961
+ if ($[44] !== fieldIds.mode || $[45] !== mode) {
962
+ t24 = /* @__PURE__ */ jsxs("select", {
963
+ className: DIALOG_INPUT_CLASS,
964
+ id: fieldIds.mode,
965
+ onChange: t20,
966
+ value: mode,
967
+ children: [
968
+ t21,
969
+ t22,
970
+ t23
971
+ ]
972
+ });
973
+ $[44] = fieldIds.mode;
974
+ $[45] = mode;
975
+ $[46] = t24;
976
+ } else t24 = $[46];
977
+ let t25;
978
+ if ($[47] !== fieldIds.mode || $[48] !== t24) {
979
+ t25 = /* @__PURE__ */ jsxs("label", {
980
+ className: "flex flex-col gap-1",
981
+ htmlFor: fieldIds.mode,
982
+ children: [t19, t24]
983
+ });
984
+ $[47] = fieldIds.mode;
985
+ $[48] = t24;
986
+ $[49] = t25;
987
+ } else t25 = $[49];
988
+ let t26;
989
+ if ($[50] !== color || $[51] !== diagonal || $[52] !== fieldIds.color || $[53] !== fieldIds.diagonal || $[54] !== fieldIds.font || $[55] !== fieldIds.opacity || $[56] !== fieldIds.text || $[57] !== font || $[58] !== mode || $[59] !== opacityPercent || $[60] !== text) {
990
+ t26 = mode === "text" && /* @__PURE__ */ jsxs("div", {
991
+ className: "grid grid-cols-2 gap-3",
992
+ children: [
993
+ /* @__PURE__ */ jsxs("label", {
994
+ className: "col-span-2 flex flex-col gap-1",
995
+ htmlFor: fieldIds.text,
996
+ children: [/* @__PURE__ */ jsx("span", {
997
+ className: "text-muted-foreground text-[13px]",
998
+ children: "Text"
999
+ }), /* @__PURE__ */ jsx("input", {
1000
+ className: "border-input bg-background text-foreground rounded border px-2 py-1.5 text-[13px] outline-none",
1001
+ id: fieldIds.text,
1002
+ onChange: (e_0) => setText(e_0.target.value),
1003
+ value: text
1004
+ })]
1005
+ }),
1006
+ /* @__PURE__ */ jsxs("label", {
1007
+ className: "flex flex-col gap-1",
1008
+ htmlFor: fieldIds.font,
1009
+ children: [/* @__PURE__ */ jsx("span", {
1010
+ className: "text-muted-foreground text-[13px]",
1011
+ children: "Font"
1012
+ }), /* @__PURE__ */ jsx("input", {
1013
+ className: "border-input bg-background text-foreground rounded border px-2 py-1.5 text-[13px] outline-none",
1014
+ id: fieldIds.font,
1015
+ onChange: (e_1) => setFont(e_1.target.value),
1016
+ value: font
1017
+ })]
1018
+ }),
1019
+ /* @__PURE__ */ jsxs("label", {
1020
+ className: "flex flex-col gap-1",
1021
+ htmlFor: fieldIds.color,
1022
+ children: [/* @__PURE__ */ jsx("span", {
1023
+ className: "text-muted-foreground text-[13px]",
1024
+ children: "Color"
1025
+ }), /* @__PURE__ */ jsx("input", {
1026
+ className: `border-input bg-background text-foreground rounded border px-2 py-1.5 text-[13px] outline-none h-[34px]`,
1027
+ id: fieldIds.color,
1028
+ onChange: (e_2) => setColor(e_2.target.value),
1029
+ type: "color",
1030
+ value: color
1031
+ })]
1032
+ }),
1033
+ /* @__PURE__ */ jsxs("label", {
1034
+ className: "flex flex-col gap-1",
1035
+ htmlFor: fieldIds.opacity,
1036
+ children: [/* @__PURE__ */ jsx("span", {
1037
+ className: "text-muted-foreground text-[13px]",
1038
+ children: "Opacity"
1039
+ }), /* @__PURE__ */ jsx("input", {
1040
+ className: "border-input bg-background text-foreground rounded border px-2 py-1.5 text-[13px] outline-none",
1041
+ id: fieldIds.opacity,
1042
+ max: 100,
1043
+ min: 0,
1044
+ onChange: (e_3) => setOpacityPercent(Number(e_3.target.value) || 0),
1045
+ type: "number",
1046
+ value: opacityPercent
1047
+ })]
1048
+ }),
1049
+ /* @__PURE__ */ jsxs("label", {
1050
+ className: "flex items-center gap-2 pt-6",
1051
+ htmlFor: fieldIds.diagonal,
1052
+ children: [/* @__PURE__ */ jsx("input", {
1053
+ checked: diagonal,
1054
+ id: fieldIds.diagonal,
1055
+ onChange: (e_4) => setDiagonal(e_4.target.checked),
1056
+ type: "checkbox"
1057
+ }), /* @__PURE__ */ jsx("span", {
1058
+ className: "text-muted-foreground text-[13px]",
1059
+ children: "Diagonal"
1060
+ })]
1061
+ })
1062
+ ]
1063
+ });
1064
+ $[50] = color;
1065
+ $[51] = diagonal;
1066
+ $[52] = fieldIds.color;
1067
+ $[53] = fieldIds.diagonal;
1068
+ $[54] = fieldIds.font;
1069
+ $[55] = fieldIds.opacity;
1070
+ $[56] = fieldIds.text;
1071
+ $[57] = font;
1072
+ $[58] = mode;
1073
+ $[59] = opacityPercent;
1074
+ $[60] = text;
1075
+ $[61] = t26;
1076
+ } else t26 = $[61];
1077
+ let t27;
1078
+ if ($[62] !== fieldIds.imageRId || $[63] !== fieldIds.imageTarget || $[64] !== fieldIds.imageTargetExternal || $[65] !== fieldIds.scale || $[66] !== fieldIds.washout || $[67] !== imageRId || $[68] !== imageTarget || $[69] !== imageTargetExternal || $[70] !== mode || $[71] !== scalePercent || $[72] !== washout) {
1079
+ t27 = mode === "picture" && /* @__PURE__ */ jsxs("div", {
1080
+ className: "grid grid-cols-2 gap-3",
1081
+ children: [
1082
+ /* @__PURE__ */ jsxs("label", {
1083
+ className: "col-span-2 flex flex-col gap-1",
1084
+ htmlFor: fieldIds.imageRId,
1085
+ children: [/* @__PURE__ */ jsx("span", {
1086
+ className: "text-muted-foreground text-[13px]",
1087
+ children: "Header image relationship id"
1088
+ }), /* @__PURE__ */ jsx("input", {
1089
+ className: "border-input bg-background text-foreground rounded border px-2 py-1.5 text-[13px] outline-none",
1090
+ id: fieldIds.imageRId,
1091
+ onChange: (e_5) => setImageRId(e_5.target.value),
1092
+ placeholder: "rId12",
1093
+ value: imageRId
1094
+ })]
1095
+ }),
1096
+ /* @__PURE__ */ jsxs("label", {
1097
+ className: "col-span-2 flex flex-col gap-1",
1098
+ htmlFor: fieldIds.imageTarget,
1099
+ children: [/* @__PURE__ */ jsx("span", {
1100
+ className: "text-muted-foreground text-[13px]",
1101
+ children: "Image target"
1102
+ }), /* @__PURE__ */ jsx("input", {
1103
+ className: "border-input bg-background text-foreground rounded border px-2 py-1.5 text-[13px] outline-none",
1104
+ id: fieldIds.imageTarget,
1105
+ onChange: (e_6) => setImageTarget(e_6.target.value),
1106
+ placeholder: "word/media/image1.png",
1107
+ value: imageTarget
1108
+ })]
1109
+ }),
1110
+ /* @__PURE__ */ jsxs("label", {
1111
+ className: "flex flex-col gap-1",
1112
+ htmlFor: fieldIds.scale,
1113
+ children: [/* @__PURE__ */ jsx("span", {
1114
+ className: "text-muted-foreground text-[13px]",
1115
+ children: "Scale"
1116
+ }), /* @__PURE__ */ jsx("input", {
1117
+ className: "border-input bg-background text-foreground rounded border px-2 py-1.5 text-[13px] outline-none",
1118
+ id: fieldIds.scale,
1119
+ max: 300,
1120
+ min: 1,
1121
+ onChange: (e_7) => setScalePercent(Number(e_7.target.value) || 1),
1122
+ type: "number",
1123
+ value: scalePercent
1124
+ })]
1125
+ }),
1126
+ /* @__PURE__ */ jsxs("label", {
1127
+ className: "flex items-center gap-2 pt-6",
1128
+ htmlFor: fieldIds.washout,
1129
+ children: [/* @__PURE__ */ jsx("input", {
1130
+ checked: washout,
1131
+ id: fieldIds.washout,
1132
+ onChange: (e_8) => setWashout(e_8.target.checked),
1133
+ type: "checkbox"
1134
+ }), /* @__PURE__ */ jsx("span", {
1135
+ className: "text-muted-foreground text-[13px]",
1136
+ children: "Washout"
1137
+ })]
1138
+ }),
1139
+ /* @__PURE__ */ jsxs("label", {
1140
+ className: "col-span-2 flex items-center gap-2",
1141
+ htmlFor: fieldIds.imageTargetExternal,
1142
+ children: [/* @__PURE__ */ jsx("input", {
1143
+ checked: imageTargetExternal,
1144
+ id: fieldIds.imageTargetExternal,
1145
+ onChange: (e_9) => setImageTargetExternal(e_9.target.checked),
1146
+ type: "checkbox"
1147
+ }), /* @__PURE__ */ jsx("span", {
1148
+ className: "text-muted-foreground text-[13px]",
1149
+ children: "Target is an external URL"
1150
+ })]
1151
+ })
1152
+ ]
1153
+ });
1154
+ $[62] = fieldIds.imageRId;
1155
+ $[63] = fieldIds.imageTarget;
1156
+ $[64] = fieldIds.imageTargetExternal;
1157
+ $[65] = fieldIds.scale;
1158
+ $[66] = fieldIds.washout;
1159
+ $[67] = imageRId;
1160
+ $[68] = imageTarget;
1161
+ $[69] = imageTargetExternal;
1162
+ $[70] = mode;
1163
+ $[71] = scalePercent;
1164
+ $[72] = washout;
1165
+ $[73] = t27;
1166
+ } else t27 = $[73];
1167
+ let t28;
1168
+ if ($[74] !== t25 || $[75] !== t26 || $[76] !== t27) {
1169
+ t28 = /* @__PURE__ */ jsxs("div", {
1170
+ className: DIALOG_BODY_CLASS,
1171
+ children: [
1172
+ t25,
1173
+ t26,
1174
+ t27
1175
+ ]
1176
+ });
1177
+ $[74] = t25;
1178
+ $[75] = t26;
1179
+ $[76] = t27;
1180
+ $[77] = t28;
1181
+ } else t28 = $[77];
1182
+ let t29;
1183
+ if ($[78] !== DialogClose) {
1184
+ t29 = /* @__PURE__ */ jsx(DialogClose, {
1185
+ className: DIALOG_SECONDARY_BUTTON_CLASS,
1186
+ children: "Cancel"
1187
+ });
1188
+ $[78] = DialogClose;
1189
+ $[79] = t29;
1190
+ } else t29 = $[79];
1191
+ const t30 = !canApply;
1192
+ let t31;
1193
+ if ($[80] !== handleApply || $[81] !== t30) {
1194
+ t31 = /* @__PURE__ */ jsx("button", {
1195
+ className: DIALOG_PRIMARY_BUTTON_CLASS,
1196
+ disabled: t30,
1197
+ onClick: handleApply,
1198
+ type: "button",
1199
+ children: "Apply"
1200
+ });
1201
+ $[80] = handleApply;
1202
+ $[81] = t30;
1203
+ $[82] = t31;
1204
+ } else t31 = $[82];
1205
+ let t32;
1206
+ if ($[83] !== t29 || $[84] !== t31) {
1207
+ t32 = /* @__PURE__ */ jsxs("div", {
1208
+ className: DIALOG_FOOTER_CLASS,
1209
+ children: [t29, t31]
1210
+ });
1211
+ $[83] = t29;
1212
+ $[84] = t31;
1213
+ $[85] = t32;
1214
+ } else t32 = $[85];
1215
+ let t33;
1216
+ if ($[86] !== DialogPopup || $[87] !== t18 || $[88] !== t28 || $[89] !== t32) {
1217
+ t33 = /* @__PURE__ */ jsxs(DialogPopup, {
1218
+ className: DIALOG_POPUP_CLASS,
1219
+ children: [
1220
+ t18,
1221
+ t28,
1222
+ t32
1223
+ ]
1224
+ });
1225
+ $[86] = DialogPopup;
1226
+ $[87] = t18;
1227
+ $[88] = t28;
1228
+ $[89] = t32;
1229
+ $[90] = t33;
1230
+ } else t33 = $[90];
1231
+ let t34;
1232
+ if ($[91] !== DialogPortal || $[92] !== t17 || $[93] !== t33) {
1233
+ t34 = /* @__PURE__ */ jsxs(DialogPortal, { children: [t17, t33] });
1234
+ $[91] = DialogPortal;
1235
+ $[92] = t17;
1236
+ $[93] = t33;
1237
+ $[94] = t34;
1238
+ } else t34 = $[94];
1239
+ let t35;
1240
+ if ($[95] !== Dialog || $[96] !== handleOpenChange || $[97] !== isOpen || $[98] !== t34) {
1241
+ t35 = /* @__PURE__ */ jsx(Dialog, {
1242
+ open: isOpen,
1243
+ onOpenChange: handleOpenChange,
1244
+ children: t34
1245
+ });
1246
+ $[95] = Dialog;
1247
+ $[96] = handleOpenChange;
1248
+ $[97] = isOpen;
1249
+ $[98] = t34;
1250
+ $[99] = t35;
1251
+ } else t35 = $[99];
1252
+ return t35;
1253
+ }
1254
+ function toWatermarkMode(value) {
1255
+ if (value === "none" || value === "picture" || value === "text") return value;
1256
+ return "text";
1257
+ }
1258
+ function clampPercent(value) {
1259
+ return Math.min(100, Math.max(0, value));
1260
+ }
1261
+ function clampScalePercent(value) {
1262
+ return Math.min(300, Math.max(1, value));
1263
+ }
1264
+ function stripHash(value) {
1265
+ return value.startsWith("#") ? value.slice(1) : value;
1266
+ }
1267
+ function toColorInputValue(value) {
1268
+ if (!value || value === "auto") return DEFAULT_TEXT_COLOR;
1269
+ return value.startsWith("#") ? value : `#${value}`;
1270
+ }
1271
+ //#endregion
1272
+ export { InsertImageDialog as a, InsertTableDialog as i, SplitCellDialog as n, HyperlinkDialog as o, PasteSpecialDialog as r, WatermarkDialog as t };