@notum-cz/strapi-plugin-tiptap-editor 1.0.1

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 (104) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +160 -0
  3. package/dist/_chunks/AccentCursive-CpAPpH9C.mjs +3383 -0
  4. package/dist/_chunks/AccentCursive-CpAPpH9C.mjs.map +1 -0
  5. package/dist/_chunks/AccentCursive-D6sTlhub.js +3384 -0
  6. package/dist/_chunks/AccentCursive-D6sTlhub.js.map +1 -0
  7. package/dist/_chunks/FormattedHeadingInput-DycgfIze.mjs +101 -0
  8. package/dist/_chunks/FormattedHeadingInput-DycgfIze.mjs.map +1 -0
  9. package/dist/_chunks/FormattedHeadingInput-FFjiRSEJ.js +101 -0
  10. package/dist/_chunks/FormattedHeadingInput-FFjiRSEJ.js.map +1 -0
  11. package/dist/_chunks/RichTextInput-BZQ2iVqa.mjs +4481 -0
  12. package/dist/_chunks/RichTextInput-BZQ2iVqa.mjs.map +1 -0
  13. package/dist/_chunks/RichTextInput-BbbQxPc-.js +4414 -0
  14. package/dist/_chunks/RichTextInput-BbbQxPc-.js.map +1 -0
  15. package/dist/_chunks/RichTextInput-BjLR2pi0.js +4416 -0
  16. package/dist/_chunks/RichTextInput-BjLR2pi0.js.map +1 -0
  17. package/dist/_chunks/RichTextInput-BlxoJMa2.js +4488 -0
  18. package/dist/_chunks/RichTextInput-BlxoJMa2.js.map +1 -0
  19. package/dist/_chunks/RichTextInput-Bm3X8fR2.mjs +4400 -0
  20. package/dist/_chunks/RichTextInput-Bm3X8fR2.mjs.map +1 -0
  21. package/dist/_chunks/RichTextInput-Bms-gSvK.js +4407 -0
  22. package/dist/_chunks/RichTextInput-Bms-gSvK.js.map +1 -0
  23. package/dist/_chunks/RichTextInput-BtNjPJRN.mjs +4400 -0
  24. package/dist/_chunks/RichTextInput-BtNjPJRN.mjs.map +1 -0
  25. package/dist/_chunks/RichTextInput-Bw3tcXfp.js +4407 -0
  26. package/dist/_chunks/RichTextInput-Bw3tcXfp.js.map +1 -0
  27. package/dist/_chunks/RichTextInput-CsgNpoxq.mjs +4409 -0
  28. package/dist/_chunks/RichTextInput-CsgNpoxq.mjs.map +1 -0
  29. package/dist/_chunks/RichTextInput-CwTvEMda.js +4407 -0
  30. package/dist/_chunks/RichTextInput-CwTvEMda.js.map +1 -0
  31. package/dist/_chunks/RichTextInput-DG-36krM.js +1181 -0
  32. package/dist/_chunks/RichTextInput-DG-36krM.js.map +1 -0
  33. package/dist/_chunks/RichTextInput-DLac-zNQ.mjs +4400 -0
  34. package/dist/_chunks/RichTextInput-DLac-zNQ.mjs.map +1 -0
  35. package/dist/_chunks/RichTextInput-DSXttrvi.js +4407 -0
  36. package/dist/_chunks/RichTextInput-DSXttrvi.js.map +1 -0
  37. package/dist/_chunks/RichTextInput-DeJ6Exto.mjs +4400 -0
  38. package/dist/_chunks/RichTextInput-DeJ6Exto.mjs.map +1 -0
  39. package/dist/_chunks/RichTextInput-DgT88AkO.mjs +1175 -0
  40. package/dist/_chunks/RichTextInput-DgT88AkO.mjs.map +1 -0
  41. package/dist/_chunks/RichTextInput-DlMaDJQF.mjs +4400 -0
  42. package/dist/_chunks/RichTextInput-DlMaDJQF.mjs.map +1 -0
  43. package/dist/_chunks/RichTextInput-DtaYdjCs.mjs +4400 -0
  44. package/dist/_chunks/RichTextInput-DtaYdjCs.mjs.map +1 -0
  45. package/dist/_chunks/RichTextInput-YTKXo5oq.js +4407 -0
  46. package/dist/_chunks/RichTextInput-YTKXo5oq.js.map +1 -0
  47. package/dist/_chunks/RichTextInput-tmg-oMJk.mjs +4407 -0
  48. package/dist/_chunks/RichTextInput-tmg-oMJk.mjs.map +1 -0
  49. package/dist/_chunks/RichTextInput-umhMsI5o.js +4407 -0
  50. package/dist/_chunks/RichTextInput-umhMsI5o.js.map +1 -0
  51. package/dist/_chunks/en-B4KWt_jN.js +5 -0
  52. package/dist/_chunks/en-B4KWt_jN.js.map +1 -0
  53. package/dist/_chunks/en-Byx4XI2L.mjs +5 -0
  54. package/dist/_chunks/en-Byx4XI2L.mjs.map +1 -0
  55. package/dist/admin/index.js +71 -0
  56. package/dist/admin/index.js.map +1 -0
  57. package/dist/admin/index.mjs +72 -0
  58. package/dist/admin/index.mjs.map +1 -0
  59. package/dist/admin/src/components/BaseTiptapInput.d.ts +12 -0
  60. package/dist/admin/src/components/FormattedHeadingInput.d.ts +4 -0
  61. package/dist/admin/src/components/Initializer.d.ts +5 -0
  62. package/dist/admin/src/components/LinkDialog.d.ts +14 -0
  63. package/dist/admin/src/components/RichTextInput.d.ts +4 -0
  64. package/dist/admin/src/components/Spacer.d.ts +3 -0
  65. package/dist/admin/src/components/TableSizeDialog.d.ts +10 -0
  66. package/dist/admin/src/components/TiptapInput.d.ts +7 -0
  67. package/dist/admin/src/components/TiptapInputStyles.d.ts +2 -0
  68. package/dist/admin/src/components/ToolbarButton.d.ts +11 -0
  69. package/dist/admin/src/extensions/AccentCursive.d.ts +18 -0
  70. package/dist/admin/src/extensions/Heading.d.ts +8 -0
  71. package/dist/admin/src/extensions/Link.d.ts +7 -0
  72. package/dist/admin/src/extensions/Script.d.ts +7 -0
  73. package/dist/admin/src/extensions/StarterKit.d.ts +13 -0
  74. package/dist/admin/src/extensions/Table.d.ts +11 -0
  75. package/dist/admin/src/extensions/TextAlign.d.ts +9 -0
  76. package/dist/admin/src/fields/formattedHeadingField.d.ts +20 -0
  77. package/dist/admin/src/fields/richTextField.d.ts +20 -0
  78. package/dist/admin/src/icons/TextAlignCenter.d.ts +2 -0
  79. package/dist/admin/src/icons/TextAlignJustify.d.ts +2 -0
  80. package/dist/admin/src/icons/TextAlignLeft.d.ts +2 -0
  81. package/dist/admin/src/icons/TextAlignRight.d.ts +2 -0
  82. package/dist/admin/src/index.d.ts +10 -0
  83. package/dist/admin/src/pluginId.d.ts +1 -0
  84. package/dist/admin/src/utils/getTranslation.d.ts +2 -0
  85. package/dist/admin/src/utils/tiptapUtils.d.ts +18 -0
  86. package/dist/server/index.js +44 -0
  87. package/dist/server/index.js.map +1 -0
  88. package/dist/server/index.mjs +45 -0
  89. package/dist/server/index.mjs.map +1 -0
  90. package/dist/server/src/bootstrap.d.ts +5 -0
  91. package/dist/server/src/config/index.d.ts +5 -0
  92. package/dist/server/src/content-types/index.d.ts +2 -0
  93. package/dist/server/src/controllers/index.d.ts +2 -0
  94. package/dist/server/src/destroy.d.ts +5 -0
  95. package/dist/server/src/fields/richTextField.d.ts +2 -0
  96. package/dist/server/src/index.d.ts +25 -0
  97. package/dist/server/src/middlewares/index.d.ts +2 -0
  98. package/dist/server/src/policies/index.d.ts +2 -0
  99. package/dist/server/src/register.d.ts +5 -0
  100. package/dist/server/src/routes/index.d.ts +2 -0
  101. package/dist/server/src/services/index.d.ts +2 -0
  102. package/dist/shared/fields.d.ts +1 -0
  103. package/dist/shared/pluginId.d.ts +1 -0
  104. package/package.json +80 -0
@@ -0,0 +1,1175 @@
1
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
+ import { t as toolbarButton, N as Node3, b as textblockTypeInputRule, m as mergeAttributes, E as Extension, c as callOrReturn, g as getExtensionField, i as isNodeEmpty, d as isNodeSelection, u as useTiptapEditor, e as useAccentCursive, B as BaseTiptapInput, s as spacer, A as AccentCursiveMark } from "./AccentCursive-CpAPpH9C.mjs";
3
+ import StarterKit from "@tiptap/starter-kit";
4
+ import { useEditorState } from "@tiptap/react";
5
+ import { Quotes, Code, NumberList, BulletList, StrikeThrough, Underline, Italic, Bold, Link, GridNine } from "@strapi/icons";
6
+ import React, { useState, useRef, useEffect, forwardRef } from "react";
7
+ import { Dialog, Field, TextInput, Button, SingleSelect, SingleSelectOption, Flex } from "@strapi/design-system";
8
+ import Superscript from "@tiptap/extension-superscript";
9
+ import Subscript from "@tiptap/extension-subscript";
10
+ import { TableKit } from "@tiptap/extension-table";
11
+ import { Plugin, PluginKey } from "@tiptap/pm/state";
12
+ import { dropCursor } from "@tiptap/pm/dropcursor";
13
+ import { DecorationSet, Decoration } from "@tiptap/pm/view";
14
+ import { gapCursor } from "@tiptap/pm/gapcursor";
15
+ import { history, redo, undo } from "@tiptap/pm/history";
16
+ import TextAlign from "@tiptap/extension-text-align";
17
+ function useStarterKit(editor, props = { disabled: false }) {
18
+ const editorState = useEditorState({
19
+ editor,
20
+ selector: (ctx) => {
21
+ return {
22
+ isBold: ctx.editor.isActive("bold") ?? false,
23
+ canBold: ctx.editor.can().chain().toggleBold().run() ?? false,
24
+ isItalic: ctx.editor.isActive("italic") ?? false,
25
+ canItalic: ctx.editor.can().chain().toggleItalic().run() ?? false,
26
+ isUnderline: ctx.editor.isActive("underline") ?? false,
27
+ canUnderline: ctx.editor.can().chain().toggleUnderline().run() ?? false,
28
+ isStrike: ctx.editor.isActive("strike") ?? false,
29
+ canStrike: ctx.editor.can().chain().toggleStrike().run() ?? false,
30
+ isCode: ctx.editor.isActive("code") ?? false,
31
+ canCode: ctx.editor.can().chain().toggleCode().run() ?? false,
32
+ isBulletList: ctx.editor.isActive("bulletList") ?? false,
33
+ canToggleBulletList: ctx.editor.can().chain().toggleBulletList().run() ?? false,
34
+ isOrderedList: ctx.editor.isActive("orderedList") ?? false,
35
+ canToggleOrderedList: ctx.editor.can().chain().toggleOrderedList().run() ?? false,
36
+ isBlockquote: ctx.editor.isActive("blockquote") ?? false,
37
+ canToggleBlockquote: ctx.editor.can().chain().toggleBlockquote().run() ?? false
38
+ };
39
+ }
40
+ });
41
+ const toggleBold = () => editor?.chain().focus().toggleBold().run();
42
+ const toggleItalic = () => editor?.chain().focus().toggleItalic().run();
43
+ const toggleUnderline = () => editor?.chain().focus().toggleUnderline().run();
44
+ const toggleStrike = () => editor?.chain().focus().toggleStrike().run();
45
+ const toggleCode = () => editor?.chain().focus().toggleCode().run();
46
+ const toggleBulletList = () => editor?.chain().focus().toggleBulletList().run();
47
+ const toggleOrderedList = () => editor?.chain().focus().toggleOrderedList().run();
48
+ const toggleBlockquote = () => editor?.chain().focus().toggleBlockquote().run();
49
+ return {
50
+ boldButton: toolbarButton("bold", {
51
+ onClick: toggleBold,
52
+ icon: /* @__PURE__ */ jsx(Bold, {}),
53
+ active: editorState.isBold,
54
+ disabled: props.disabled || !editor || !editorState.canBold,
55
+ tooltip: "Bold"
56
+ }),
57
+ italicButton: toolbarButton("italic", {
58
+ onClick: toggleItalic,
59
+ icon: /* @__PURE__ */ jsx(Italic, {}),
60
+ active: editorState.isItalic,
61
+ disabled: props.disabled || !editor || !editorState.canItalic,
62
+ tooltip: "Italic"
63
+ }),
64
+ underlineButton: toolbarButton("underline", {
65
+ onClick: toggleUnderline,
66
+ icon: /* @__PURE__ */ jsx(Underline, {}),
67
+ active: editorState.isUnderline,
68
+ disabled: props.disabled || !editor || !editorState.canUnderline,
69
+ tooltip: "Underline"
70
+ }),
71
+ strikeButton: toolbarButton("strike", {
72
+ onClick: toggleStrike,
73
+ icon: /* @__PURE__ */ jsx(StrikeThrough, {}),
74
+ active: editorState.isStrike,
75
+ disabled: props.disabled || !editor || !editorState.canStrike,
76
+ tooltip: "Strikethrough"
77
+ }),
78
+ bulletButton: toolbarButton("bullet", {
79
+ onClick: toggleBulletList,
80
+ icon: /* @__PURE__ */ jsx(BulletList, {}),
81
+ active: editorState.isBulletList,
82
+ disabled: props.disabled || !editor || !editorState.canToggleBulletList,
83
+ tooltip: "Bullet list"
84
+ }),
85
+ orderedButton: toolbarButton("ordered", {
86
+ onClick: toggleOrderedList,
87
+ icon: /* @__PURE__ */ jsx(NumberList, {}),
88
+ active: editorState.isOrderedList,
89
+ disabled: props.disabled || !editor || !editorState.canToggleOrderedList,
90
+ tooltip: "Numbered list"
91
+ }),
92
+ codeButton: toolbarButton("code", {
93
+ onClick: toggleCode,
94
+ icon: /* @__PURE__ */ jsx(Code, {}),
95
+ active: editorState.isCode,
96
+ disabled: props.disabled || !editor || !editorState.canCode,
97
+ tooltip: "Inline code"
98
+ }),
99
+ blockquoteButton: toolbarButton("quote", {
100
+ onClick: toggleBlockquote,
101
+ icon: /* @__PURE__ */ jsx(Quotes, {}),
102
+ active: editorState.isBlockquote,
103
+ disabled: props.disabled || !editor || !editorState.canToggleBlockquote,
104
+ tooltip: "Quote"
105
+ })
106
+ };
107
+ }
108
+ const LinkDialog = ({
109
+ open,
110
+ url,
111
+ mode,
112
+ onClose,
113
+ onSave,
114
+ onRemove
115
+ }) => {
116
+ const [value, setValue] = React.useState(url || "");
117
+ React.useEffect(() => {
118
+ if (open) {
119
+ setValue(url || "");
120
+ }
121
+ }, [open, url, mode]);
122
+ const handleSave = () => {
123
+ onSave({ url: value.trim() });
124
+ };
125
+ const isSaveDisabled = mode === "add" ? value.trim() === "" : false;
126
+ return /* @__PURE__ */ jsx(
127
+ Dialog.Root,
128
+ {
129
+ open,
130
+ onOpenChange: (v) => {
131
+ if (!v) onClose();
132
+ },
133
+ children: open && /* @__PURE__ */ jsxs(Dialog.Content, { children: [
134
+ /* @__PURE__ */ jsx(Dialog.Header, { children: mode === "add" ? "Add link" : "Edit link" }),
135
+ /* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Field.Root, { width: "100%", children: [
136
+ /* @__PURE__ */ jsx(Field.Label, { children: "URL" }),
137
+ /* @__PURE__ */ jsx(
138
+ TextInput,
139
+ {
140
+ name: "link-url",
141
+ placeholder: "https://example.com",
142
+ value,
143
+ onChange: (e) => setValue(e.target.value)
144
+ }
145
+ )
146
+ ] }) }),
147
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
148
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, onClick: onClose, children: "Cancel" }) }),
149
+ mode === "edit" && /* @__PURE__ */ jsx(Button, { variant: "danger-light", fullWidth: true, onClick: onRemove, children: "Remove link" }),
150
+ /* @__PURE__ */ jsx(Dialog.Action, { children: /* @__PURE__ */ jsx(
151
+ Button,
152
+ {
153
+ fullWidth: true,
154
+ variant: "success-light",
155
+ onClick: handleSave,
156
+ disabled: isSaveDisabled,
157
+ children: "Save"
158
+ }
159
+ ) })
160
+ ] })
161
+ ] })
162
+ }
163
+ );
164
+ };
165
+ function useLink(editor, props = { disabled: false }) {
166
+ const editorState = useEditorState({
167
+ editor,
168
+ selector: (ctx) => {
169
+ return {
170
+ isLink: ctx.editor.isActive("link") ?? false,
171
+ canSetLink: ctx.editor.can().setLink?.({ href: "https://example.com" }) ?? true
172
+ };
173
+ }
174
+ });
175
+ const [showLinkDialog, setShowLinkDialog] = useState(false);
176
+ const [currentLinkUrl, setCurrentLinkUrl] = useState("");
177
+ const [linkDialogMode, setLinkDialogMode] = useState("add");
178
+ const selectionRef = useRef(null);
179
+ const openAddLinkDialog = () => {
180
+ if (!editor) return;
181
+ const { from, to } = editor.state.selection;
182
+ selectionRef.current = { from, to };
183
+ setCurrentLinkUrl("");
184
+ setLinkDialogMode("add");
185
+ setShowLinkDialog(true);
186
+ };
187
+ const openEditLinkDialog = () => {
188
+ if (!editor) return;
189
+ const { from, to } = editor.state.selection;
190
+ selectionRef.current = { from, to };
191
+ const currentHref = editor.getAttributes("link").href || "";
192
+ setCurrentLinkUrl(currentHref);
193
+ setLinkDialogMode("edit");
194
+ setShowLinkDialog(true);
195
+ };
196
+ const toggleLink = () => {
197
+ if (!editor) return;
198
+ if (editorState.isLink) {
199
+ openEditLinkDialog();
200
+ } else {
201
+ openAddLinkDialog();
202
+ }
203
+ };
204
+ const restoreSelection = () => {
205
+ if (!editor) return;
206
+ const sel = selectionRef.current;
207
+ if (sel) {
208
+ editor.chain().setTextSelection({ from: sel.from, to: sel.to }).run();
209
+ }
210
+ };
211
+ const handleSaveEditedLink = ({ url }) => {
212
+ if (!editor) return;
213
+ restoreSelection();
214
+ const chain = editor.chain().focus().extendMarkRange("link");
215
+ if (url === "") {
216
+ chain.unsetLink().run();
217
+ } else {
218
+ chain.updateAttributes("link", { href: url }).run();
219
+ }
220
+ setShowLinkDialog(false);
221
+ };
222
+ const handleRemoveLink = () => {
223
+ if (!editor) return;
224
+ restoreSelection();
225
+ editor.chain().focus().extendMarkRange("link").unsetLink().run();
226
+ setShowLinkDialog(false);
227
+ };
228
+ const handleSaveNewLink = ({ url }) => {
229
+ if (!editor) return;
230
+ restoreSelection();
231
+ editor.chain().focus().setLink({ href: url }).run();
232
+ setShowLinkDialog(false);
233
+ };
234
+ return {
235
+ linkButton: toolbarButton("link", {
236
+ onClick: toggleLink,
237
+ icon: /* @__PURE__ */ jsx(Link, {}),
238
+ active: editorState.isLink,
239
+ disabled: props.disabled || !editor || !editorState.canSetLink,
240
+ tooltip: editorState.isLink ? "Edit or remove link" : "Add link"
241
+ }),
242
+ linkDialog: /* @__PURE__ */ jsx(
243
+ LinkDialog,
244
+ {
245
+ open: showLinkDialog,
246
+ url: currentLinkUrl,
247
+ mode: linkDialogMode,
248
+ onClose: () => setShowLinkDialog(false),
249
+ onSave: linkDialogMode === "add" ? handleSaveNewLink : handleSaveEditedLink,
250
+ onRemove: handleRemoveLink
251
+ }
252
+ )
253
+ };
254
+ }
255
+ var Heading = Node3.create({
256
+ name: "heading",
257
+ addOptions() {
258
+ return {
259
+ levels: [1, 2, 3, 4, 5, 6],
260
+ HTMLAttributes: {}
261
+ };
262
+ },
263
+ content: "inline*",
264
+ group: "block",
265
+ defining: true,
266
+ addAttributes() {
267
+ return {
268
+ level: {
269
+ default: 1,
270
+ rendered: false
271
+ }
272
+ };
273
+ },
274
+ parseHTML() {
275
+ return this.options.levels.map((level) => ({
276
+ tag: `h${level}`,
277
+ attrs: { level }
278
+ }));
279
+ },
280
+ renderHTML({ node, HTMLAttributes }) {
281
+ const hasLevel = this.options.levels.includes(node.attrs.level);
282
+ const level = hasLevel ? node.attrs.level : this.options.levels[0];
283
+ return [`h${level}`, mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
284
+ },
285
+ parseMarkdown: (token, helpers) => {
286
+ return helpers.createNode("heading", { level: token.depth || 1 }, helpers.parseInline(token.tokens || []));
287
+ },
288
+ renderMarkdown: (node, h) => {
289
+ var _a;
290
+ const level = ((_a = node.attrs) == null ? void 0 : _a.level) ? parseInt(node.attrs.level, 10) : 1;
291
+ const headingChars = "#".repeat(level);
292
+ if (!node.content) {
293
+ return "";
294
+ }
295
+ return `${headingChars} ${h.renderChildren(node.content)}`;
296
+ },
297
+ addCommands() {
298
+ return {
299
+ setHeading: (attributes) => ({ commands }) => {
300
+ if (!this.options.levels.includes(attributes.level)) {
301
+ return false;
302
+ }
303
+ return commands.setNode(this.name, attributes);
304
+ },
305
+ toggleHeading: (attributes) => ({ commands }) => {
306
+ if (!this.options.levels.includes(attributes.level)) {
307
+ return false;
308
+ }
309
+ return commands.toggleNode(this.name, "paragraph", attributes);
310
+ }
311
+ };
312
+ },
313
+ addKeyboardShortcuts() {
314
+ return this.options.levels.reduce(
315
+ (items, level) => ({
316
+ ...items,
317
+ ...{
318
+ [`Mod-Alt-${level}`]: () => this.editor.commands.toggleHeading({ level })
319
+ }
320
+ }),
321
+ {}
322
+ );
323
+ },
324
+ addInputRules() {
325
+ return this.options.levels.map((level) => {
326
+ return textblockTypeInputRule({
327
+ find: new RegExp(`^(#{${Math.min(...this.options.levels)},${level}})\\s$`),
328
+ type: this.type,
329
+ getAttributes: {
330
+ level
331
+ }
332
+ });
333
+ });
334
+ }
335
+ });
336
+ var index_default = Heading;
337
+ const HeadingWithSEOTag = index_default.extend({
338
+ addAttributes() {
339
+ return {
340
+ ...this.parent?.(),
341
+ // must cast to any to avoid TS error
342
+ tag: { default: null }
343
+ };
344
+ }
345
+ }).configure({ levels: [1, 2, 3, 4] });
346
+ function useHeading(editor, props = { disabled: false }) {
347
+ const editorState = useEditorState({
348
+ editor,
349
+ selector: (ctx) => {
350
+ return {
351
+ headingLevel: ctx.editor.getAttributes("heading").level,
352
+ headingTag: ctx.editor.getAttributes("heading").tag,
353
+ isParagraph: ctx.editor.isActive("paragraph") ?? false
354
+ };
355
+ }
356
+ });
357
+ const onChangeHeading = (value) => {
358
+ if (!editor) return;
359
+ editor.chain().focus();
360
+ if (value === "p") {
361
+ editor.chain().focus().setParagraph().run();
362
+ return;
363
+ }
364
+ const level = Number(value[1]);
365
+ editor.chain().focus().setHeading({ level }).run();
366
+ if (!editorState.headingTag) {
367
+ editor.chain().focus().updateAttributes("heading", { tag: `h${level}` }).run();
368
+ }
369
+ };
370
+ const onChangeHeadingTag = (value) => {
371
+ if (!editor) return;
372
+ if (!editorState.headingLevel) return;
373
+ editor.chain().focus().updateAttributes("heading", { tag: value }).run();
374
+ };
375
+ return {
376
+ headingSelect: /* @__PURE__ */ jsxs(
377
+ SingleSelect,
378
+ {
379
+ placeholder: "Style",
380
+ "aria-label": "Text style",
381
+ value: editorState.headingLevel ? `h${editorState.headingLevel}` : "p",
382
+ onChange: (v) => v && onChangeHeading(v),
383
+ disabled: !editor || props.disabled,
384
+ size: "S",
385
+ children: [
386
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "p", children: "Paragraph" }),
387
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "h1", children: "Heading 1" }),
388
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "h2", children: "Heading 2" }),
389
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "h3", children: "Heading 3" }),
390
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "h4", children: "Heading 4" })
391
+ ]
392
+ }
393
+ ),
394
+ headingTagSelect: /* @__PURE__ */ jsxs(
395
+ SingleSelect,
396
+ {
397
+ placeholder: "SEO Tag",
398
+ "aria-label": "Heading's HTML tag for SEO purposes",
399
+ value: editorState.headingTag,
400
+ onChange: (v) => v && onChangeHeadingTag(v),
401
+ disabled: !editor || props.disabled || !editorState.headingLevel,
402
+ size: "S",
403
+ children: [
404
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "h1", children: "h1" }),
405
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "h2", children: "h2" }),
406
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "h3", children: "h3" }),
407
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "h4", children: "h4" }),
408
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "h5", children: "h5" }),
409
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "h6", children: "h6" })
410
+ ]
411
+ }
412
+ )
413
+ };
414
+ }
415
+ function useScript(editor, props = { disabled: false }) {
416
+ const editorState = useEditorState({
417
+ editor,
418
+ selector: (ctx) => {
419
+ return {
420
+ isSuperscript: ctx.editor.isActive("superscript") ?? false,
421
+ canToggleSuperscript: ctx.editor.can().chain().toggleSuperscript().run() ?? false,
422
+ isSubscript: ctx.editor.isActive("subscript") ?? false,
423
+ canToggleSubscript: ctx.editor.can().chain().toggleSubscript().run() ?? false
424
+ };
425
+ }
426
+ });
427
+ const toggleSuperscript = () => {
428
+ editor?.chain().focus().toggleSuperscript().run();
429
+ };
430
+ const toggleSubscript = () => {
431
+ editor?.chain().focus().toggleSubscript().run();
432
+ };
433
+ return {
434
+ superscriptButton: toolbarButton("superscript", {
435
+ onClick: toggleSuperscript,
436
+ icon: /* @__PURE__ */ jsxs(Fragment, { children: [
437
+ "x",
438
+ /* @__PURE__ */ jsx("sup", { children: "2" })
439
+ ] }),
440
+ active: editorState.isSuperscript,
441
+ disabled: props.disabled || !editor || !editorState.canToggleSuperscript,
442
+ tooltip: "Superscript"
443
+ }),
444
+ subscriptButton: toolbarButton("subscript", {
445
+ onClick: toggleSubscript,
446
+ icon: /* @__PURE__ */ jsxs(Fragment, { children: [
447
+ "x",
448
+ /* @__PURE__ */ jsx("sub", { children: "2" })
449
+ ] }),
450
+ active: editorState.isSubscript,
451
+ disabled: props.disabled || !editor || !editorState.canToggleSubscript,
452
+ tooltip: "Subscript"
453
+ })
454
+ };
455
+ }
456
+ Extension.create({
457
+ name: "characterCount",
458
+ addOptions() {
459
+ return {
460
+ limit: null,
461
+ mode: "textSize",
462
+ textCounter: (text) => text.length,
463
+ wordCounter: (text) => text.split(" ").filter((word) => word !== "").length
464
+ };
465
+ },
466
+ addStorage() {
467
+ return {
468
+ characters: () => 0,
469
+ words: () => 0
470
+ };
471
+ },
472
+ onBeforeCreate() {
473
+ this.storage.characters = (options) => {
474
+ const node = (options == null ? void 0 : options.node) || this.editor.state.doc;
475
+ const mode = (options == null ? void 0 : options.mode) || this.options.mode;
476
+ if (mode === "textSize") {
477
+ const text = node.textBetween(0, node.content.size, void 0, " ");
478
+ return this.options.textCounter(text);
479
+ }
480
+ return node.nodeSize;
481
+ };
482
+ this.storage.words = (options) => {
483
+ const node = (options == null ? void 0 : options.node) || this.editor.state.doc;
484
+ const text = node.textBetween(0, node.content.size, " ", " ");
485
+ return this.options.wordCounter(text);
486
+ };
487
+ },
488
+ addProseMirrorPlugins() {
489
+ let initialEvaluationDone = false;
490
+ return [
491
+ new Plugin({
492
+ key: new PluginKey("characterCount"),
493
+ appendTransaction: (transactions, oldState, newState) => {
494
+ if (initialEvaluationDone) {
495
+ return;
496
+ }
497
+ const limit = this.options.limit;
498
+ if (limit === null || limit === void 0 || limit === 0) {
499
+ initialEvaluationDone = true;
500
+ return;
501
+ }
502
+ const initialContentSize = this.storage.characters({ node: newState.doc });
503
+ if (initialContentSize > limit) {
504
+ const over = initialContentSize - limit;
505
+ const from = 0;
506
+ const to = over;
507
+ console.warn(
508
+ `[CharacterCount] Initial content exceeded limit of ${limit} characters. Content was automatically trimmed.`
509
+ );
510
+ const tr = newState.tr.deleteRange(from, to);
511
+ initialEvaluationDone = true;
512
+ return tr;
513
+ }
514
+ initialEvaluationDone = true;
515
+ },
516
+ filterTransaction: (transaction, state) => {
517
+ const limit = this.options.limit;
518
+ if (!transaction.docChanged || limit === 0 || limit === null || limit === void 0) {
519
+ return true;
520
+ }
521
+ const oldSize = this.storage.characters({ node: state.doc });
522
+ const newSize = this.storage.characters({ node: transaction.doc });
523
+ if (newSize <= limit) {
524
+ return true;
525
+ }
526
+ if (oldSize > limit && newSize > limit && newSize <= oldSize) {
527
+ return true;
528
+ }
529
+ if (oldSize > limit && newSize > limit && newSize > oldSize) {
530
+ return false;
531
+ }
532
+ const isPaste = transaction.getMeta("paste");
533
+ if (!isPaste) {
534
+ return false;
535
+ }
536
+ const pos = transaction.selection.$head.pos;
537
+ const over = newSize - limit;
538
+ const from = pos - over;
539
+ const to = pos;
540
+ transaction.deleteRange(from, to);
541
+ const updatedSize = this.storage.characters({ node: transaction.doc });
542
+ if (updatedSize > limit) {
543
+ return false;
544
+ }
545
+ return true;
546
+ }
547
+ })
548
+ ];
549
+ }
550
+ });
551
+ Extension.create({
552
+ name: "dropCursor",
553
+ addOptions() {
554
+ return {
555
+ color: "currentColor",
556
+ width: 1,
557
+ class: void 0
558
+ };
559
+ },
560
+ addProseMirrorPlugins() {
561
+ return [dropCursor(this.options)];
562
+ }
563
+ });
564
+ Extension.create({
565
+ name: "focus",
566
+ addOptions() {
567
+ return {
568
+ className: "has-focus",
569
+ mode: "all"
570
+ };
571
+ },
572
+ addProseMirrorPlugins() {
573
+ return [
574
+ new Plugin({
575
+ key: new PluginKey("focus"),
576
+ props: {
577
+ decorations: ({ doc, selection }) => {
578
+ const { isEditable, isFocused } = this.editor;
579
+ const { anchor } = selection;
580
+ const decorations = [];
581
+ if (!isEditable || !isFocused) {
582
+ return DecorationSet.create(doc, []);
583
+ }
584
+ let maxLevels = 0;
585
+ if (this.options.mode === "deepest") {
586
+ doc.descendants((node, pos) => {
587
+ if (node.isText) {
588
+ return;
589
+ }
590
+ const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
591
+ if (!isCurrent) {
592
+ return false;
593
+ }
594
+ maxLevels += 1;
595
+ });
596
+ }
597
+ let currentLevel = 0;
598
+ doc.descendants((node, pos) => {
599
+ if (node.isText) {
600
+ return false;
601
+ }
602
+ const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
603
+ if (!isCurrent) {
604
+ return false;
605
+ }
606
+ currentLevel += 1;
607
+ const outOfScope = this.options.mode === "deepest" && maxLevels - currentLevel > 0 || this.options.mode === "shallowest" && currentLevel > 1;
608
+ if (outOfScope) {
609
+ return this.options.mode === "deepest";
610
+ }
611
+ decorations.push(
612
+ Decoration.node(pos, pos + node.nodeSize, {
613
+ class: this.options.className
614
+ })
615
+ );
616
+ });
617
+ return DecorationSet.create(doc, decorations);
618
+ }
619
+ }
620
+ })
621
+ ];
622
+ }
623
+ });
624
+ var Gapcursor = Extension.create({
625
+ name: "gapCursor",
626
+ addProseMirrorPlugins() {
627
+ return [gapCursor()];
628
+ },
629
+ extendNodeSchema(extension) {
630
+ var _a;
631
+ const context = {
632
+ name: extension.name,
633
+ options: extension.options,
634
+ storage: extension.storage
635
+ };
636
+ return {
637
+ allowGapCursor: (_a = callOrReturn(getExtensionField(extension, "allowGapCursor", context))) != null ? _a : null
638
+ };
639
+ }
640
+ });
641
+ var DEFAULT_DATA_ATTRIBUTE = "placeholder";
642
+ function preparePlaceholderAttribute(attr) {
643
+ return attr.replace(/\s+/g, "-").replace(/[^a-zA-Z0-9-]/g, "").replace(/^[0-9-]+/, "").replace(/^-+/, "").toLowerCase();
644
+ }
645
+ Extension.create({
646
+ name: "placeholder",
647
+ addOptions() {
648
+ return {
649
+ emptyEditorClass: "is-editor-empty",
650
+ emptyNodeClass: "is-empty",
651
+ dataAttribute: DEFAULT_DATA_ATTRIBUTE,
652
+ placeholder: "Write something …",
653
+ showOnlyWhenEditable: true,
654
+ showOnlyCurrent: true,
655
+ includeChildren: false
656
+ };
657
+ },
658
+ addProseMirrorPlugins() {
659
+ const dataAttribute = this.options.dataAttribute ? `data-${preparePlaceholderAttribute(this.options.dataAttribute)}` : `data-${DEFAULT_DATA_ATTRIBUTE}`;
660
+ return [
661
+ new Plugin({
662
+ key: new PluginKey("placeholder"),
663
+ props: {
664
+ decorations: ({ doc, selection }) => {
665
+ const active = this.editor.isEditable || !this.options.showOnlyWhenEditable;
666
+ const { anchor } = selection;
667
+ const decorations = [];
668
+ if (!active) {
669
+ return null;
670
+ }
671
+ const isEmptyDoc = this.editor.isEmpty;
672
+ doc.descendants((node, pos) => {
673
+ const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
674
+ const isEmpty = !node.isLeaf && isNodeEmpty(node);
675
+ if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
676
+ const classes = [this.options.emptyNodeClass];
677
+ if (isEmptyDoc) {
678
+ classes.push(this.options.emptyEditorClass);
679
+ }
680
+ const decoration = Decoration.node(pos, pos + node.nodeSize, {
681
+ class: classes.join(" "),
682
+ [dataAttribute]: typeof this.options.placeholder === "function" ? this.options.placeholder({
683
+ editor: this.editor,
684
+ node,
685
+ pos,
686
+ hasAnchor
687
+ }) : this.options.placeholder
688
+ });
689
+ decorations.push(decoration);
690
+ }
691
+ return this.options.includeChildren;
692
+ });
693
+ return DecorationSet.create(doc, decorations);
694
+ }
695
+ }
696
+ })
697
+ ];
698
+ }
699
+ });
700
+ Extension.create({
701
+ name: "selection",
702
+ addOptions() {
703
+ return {
704
+ className: "selection"
705
+ };
706
+ },
707
+ addProseMirrorPlugins() {
708
+ const { editor, options } = this;
709
+ return [
710
+ new Plugin({
711
+ key: new PluginKey("selection"),
712
+ props: {
713
+ decorations(state) {
714
+ if (state.selection.empty || editor.isFocused || !editor.isEditable || isNodeSelection(state.selection) || editor.view.dragging) {
715
+ return null;
716
+ }
717
+ return DecorationSet.create(state.doc, [
718
+ Decoration.inline(state.selection.from, state.selection.to, {
719
+ class: options.className
720
+ })
721
+ ]);
722
+ }
723
+ }
724
+ })
725
+ ];
726
+ }
727
+ });
728
+ function nodeEqualsType({ types, node }) {
729
+ return node && Array.isArray(types) && types.includes(node.type) || (node == null ? void 0 : node.type) === types;
730
+ }
731
+ Extension.create({
732
+ name: "trailingNode",
733
+ addOptions() {
734
+ return {
735
+ node: void 0,
736
+ notAfter: []
737
+ };
738
+ },
739
+ addProseMirrorPlugins() {
740
+ var _a;
741
+ const plugin = new PluginKey(this.name);
742
+ const defaultNode = this.options.node || ((_a = this.editor.schema.topNodeType.contentMatch.defaultType) == null ? void 0 : _a.name) || "paragraph";
743
+ const disabledNodes = Object.entries(this.editor.schema.nodes).map(([, value]) => value).filter((node) => (this.options.notAfter || []).concat(defaultNode).includes(node.name));
744
+ return [
745
+ new Plugin({
746
+ key: plugin,
747
+ appendTransaction: (_, __, state) => {
748
+ const { doc, tr, schema } = state;
749
+ const shouldInsertNodeAtEnd = plugin.getState(state);
750
+ const endPosition = doc.content.size;
751
+ const type = schema.nodes[defaultNode];
752
+ if (!shouldInsertNodeAtEnd) {
753
+ return;
754
+ }
755
+ return tr.insert(endPosition, type.create());
756
+ },
757
+ state: {
758
+ init: (_, state) => {
759
+ const lastNode = state.tr.doc.lastChild;
760
+ return !nodeEqualsType({ node: lastNode, types: disabledNodes });
761
+ },
762
+ apply: (tr, value) => {
763
+ if (!tr.docChanged) {
764
+ return value;
765
+ }
766
+ if (tr.getMeta("__uniqueIDTransaction")) {
767
+ return value;
768
+ }
769
+ const lastNode = tr.doc.lastChild;
770
+ return !nodeEqualsType({ node: lastNode, types: disabledNodes });
771
+ }
772
+ }
773
+ })
774
+ ];
775
+ }
776
+ });
777
+ Extension.create({
778
+ name: "undoRedo",
779
+ addOptions() {
780
+ return {
781
+ depth: 100,
782
+ newGroupDelay: 500
783
+ };
784
+ },
785
+ addCommands() {
786
+ return {
787
+ undo: () => ({ state, dispatch }) => {
788
+ return undo(state, dispatch);
789
+ },
790
+ redo: () => ({ state, dispatch }) => {
791
+ return redo(state, dispatch);
792
+ }
793
+ };
794
+ },
795
+ addProseMirrorPlugins() {
796
+ return [history(this.options)];
797
+ },
798
+ addKeyboardShortcuts() {
799
+ return {
800
+ "Mod-z": () => this.editor.commands.undo(),
801
+ "Shift-Mod-z": () => this.editor.commands.redo(),
802
+ "Mod-y": () => this.editor.commands.redo(),
803
+ // Russian keyboard layouts
804
+ "Mod-я": () => this.editor.commands.undo(),
805
+ "Shift-Mod-я": () => this.editor.commands.redo()
806
+ };
807
+ }
808
+ });
809
+ const clamp = (val, min, max) => Math.max(min, Math.min(max, val));
810
+ const parseNum = (value, fallback) => {
811
+ const n = Number(value);
812
+ return Number.isFinite(n) ? n : fallback;
813
+ };
814
+ const TableSizeDialog = ({
815
+ open,
816
+ defaultRows = 3,
817
+ defaultCols = 3,
818
+ onClose,
819
+ onSave
820
+ }) => {
821
+ const [rows, setRows] = useState(defaultRows);
822
+ const [cols, setCols] = useState(defaultCols);
823
+ useEffect(() => {
824
+ if (open) {
825
+ setRows(defaultRows);
826
+ setCols(defaultCols);
827
+ }
828
+ }, [open, defaultRows, defaultCols]);
829
+ const min = 1;
830
+ const max = 10;
831
+ const isValid = rows >= min && rows <= max && cols >= min && cols <= max;
832
+ const handleSave = () => {
833
+ if (!isValid) return;
834
+ onSave(clamp(rows, min, max), clamp(cols, min, max));
835
+ };
836
+ return /* @__PURE__ */ jsx(
837
+ Dialog.Root,
838
+ {
839
+ open,
840
+ onOpenChange: (v) => {
841
+ if (!v) onClose();
842
+ },
843
+ children: open && /* @__PURE__ */ jsxs(Dialog.Content, { children: [
844
+ /* @__PURE__ */ jsx(Dialog.Header, { children: "Insert table" }),
845
+ /* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { gap: 4, alignItems: "flex-end", children: [
846
+ /* @__PURE__ */ jsxs(Field.Root, { width: "100%", children: [
847
+ /* @__PURE__ */ jsx(Field.Label, { children: "Rows" }),
848
+ /* @__PURE__ */ jsx(
849
+ TextInput,
850
+ {
851
+ name: "table-rows",
852
+ type: "number",
853
+ value: String(rows),
854
+ onChange: (e) => setRows(clamp(parseNum(e.target.value, rows), min, max)),
855
+ placeholder: String(defaultRows)
856
+ }
857
+ ),
858
+ /* @__PURE__ */ jsxs(Field.Hint, { children: [
859
+ "Min ",
860
+ min,
861
+ ", max ",
862
+ max
863
+ ] })
864
+ ] }),
865
+ /* @__PURE__ */ jsxs(Field.Root, { width: "100%", children: [
866
+ /* @__PURE__ */ jsx(Field.Label, { children: "Columns" }),
867
+ /* @__PURE__ */ jsx(
868
+ TextInput,
869
+ {
870
+ name: "table-cols",
871
+ type: "number",
872
+ value: String(cols),
873
+ onChange: (e) => setCols(clamp(parseNum(e.target.value, cols), min, max)),
874
+ placeholder: String(defaultCols)
875
+ }
876
+ ),
877
+ /* @__PURE__ */ jsxs(Field.Hint, { children: [
878
+ "Min ",
879
+ min,
880
+ ", max ",
881
+ max
882
+ ] })
883
+ ] })
884
+ ] }) }),
885
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
886
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, onClick: onClose, children: "Cancel" }) }),
887
+ /* @__PURE__ */ jsx(Dialog.Action, { children: /* @__PURE__ */ jsx(Button, { fullWidth: true, variant: "success-light", onClick: handleSave, disabled: !isValid, children: "Insert" }) })
888
+ ] })
889
+ ] })
890
+ }
891
+ );
892
+ };
893
+ function useTable(editor, props = { disabled: false }) {
894
+ const editorState = useEditorState({
895
+ editor,
896
+ selector: (ctx) => {
897
+ return {
898
+ isTable: ctx.editor.isActive("table") ?? false,
899
+ canInsertTable: ctx.editor.can().chain().insertTable().run() ?? false,
900
+ canAddColumn: ctx.editor.can().chain().addColumnAfter().run() ?? false,
901
+ canDeleteColumn: ctx.editor.can().chain().deleteColumn().run() ?? false,
902
+ canAddRow: ctx.editor.can().chain().addRowAfter().run() ?? false,
903
+ canDeleteRow: ctx.editor.can().chain().deleteRow().run() ?? false
904
+ };
905
+ }
906
+ });
907
+ const [open, setOpen] = useState(false);
908
+ const handleOpenDialog = () => {
909
+ if (!editor) return;
910
+ setOpen(true);
911
+ };
912
+ const handleInsert = (rows, cols) => {
913
+ if (!editor) return;
914
+ editor.chain().focus().insertTable({ rows, cols, withHeaderRow: true }).run();
915
+ setOpen(false);
916
+ };
917
+ const addColumn = () => editor?.chain().focus().addColumnAfter().run();
918
+ const removeColumn = () => editor?.chain().focus().deleteColumn().run();
919
+ const addRow = () => editor?.chain().focus().addRowAfter().run();
920
+ const removeRow = () => editor?.chain().focus().deleteRow().run();
921
+ return {
922
+ tableButton: toolbarButton("table", {
923
+ onClick: handleOpenDialog,
924
+ icon: /* @__PURE__ */ jsx(GridNine, {}),
925
+ active: editorState.isTable,
926
+ disabled: props.disabled || !editor || !editorState.canInsertTable,
927
+ tooltip: "Table"
928
+ }),
929
+ // Adding table manipulation buttons
930
+ addColumnButton: toolbarButton("tableAddColumn", {
931
+ onClick: addColumn,
932
+ icon: /* @__PURE__ */ jsx(Fragment, { children: "+Col" }),
933
+ active: false,
934
+ hidden: props.disabled || !editor || !editorState.canAddColumn,
935
+ tooltip: "Add column (to the right)"
936
+ }),
937
+ removeColumnButton: toolbarButton("tableRemoveColumn", {
938
+ onClick: removeColumn,
939
+ icon: /* @__PURE__ */ jsx(Fragment, { children: "-Col" }),
940
+ active: false,
941
+ hidden: props.disabled || !editor || !editorState.canDeleteColumn,
942
+ tooltip: "Remove column"
943
+ }),
944
+ addRowButton: toolbarButton("tableAddRow", {
945
+ onClick: addRow,
946
+ icon: /* @__PURE__ */ jsx(Fragment, { children: "+Row" }),
947
+ active: false,
948
+ hidden: props.disabled || !editor || !editorState.canAddRow,
949
+ tooltip: "Add row (below)"
950
+ }),
951
+ removeRowButton: toolbarButton("tableRemoveRow", {
952
+ onClick: removeRow,
953
+ icon: /* @__PURE__ */ jsx(Fragment, { children: "-Row" }),
954
+ active: false,
955
+ hidden: props.disabled || !editor || !editorState.canDeleteRow,
956
+ tooltip: "Remove row"
957
+ }),
958
+ tableDialog: /* @__PURE__ */ jsx(
959
+ TableSizeDialog,
960
+ {
961
+ open,
962
+ onClose: () => setOpen(false),
963
+ onSave: handleInsert,
964
+ defaultRows: 3,
965
+ defaultCols: 3
966
+ }
967
+ )
968
+ };
969
+ }
970
+ function TextAlignLeft(props) {
971
+ return /* @__PURE__ */ jsx(
972
+ "svg",
973
+ {
974
+ width: "16",
975
+ height: "16",
976
+ viewBox: "0 0 24 24",
977
+ fill: "currentColor",
978
+ xmlns: "http://www.w3.org/2000/svg",
979
+ ...props,
980
+ children: /* @__PURE__ */ jsx(
981
+ "path",
982
+ {
983
+ d: "M3 10H16M3 14H21M3 18H16M3 6H21",
984
+ stroke: "#000000",
985
+ "stroke-width": "2",
986
+ "stroke-linecap": "round",
987
+ "stroke-linejoin": "round"
988
+ }
989
+ )
990
+ }
991
+ );
992
+ }
993
+ function TextAlignJustify(props) {
994
+ return /* @__PURE__ */ jsx(
995
+ "svg",
996
+ {
997
+ width: "16",
998
+ height: "16",
999
+ viewBox: "0 0 24 24",
1000
+ fill: "currentColor",
1001
+ xmlns: "http://www.w3.org/2000/svg",
1002
+ ...props,
1003
+ children: /* @__PURE__ */ jsx(
1004
+ "path",
1005
+ {
1006
+ d: "M3 10H21M3 14H21M3 18H21M3 6H21",
1007
+ stroke: "#000000",
1008
+ "stroke-width": "2",
1009
+ "stroke-linecap": "round",
1010
+ "stroke-linejoin": "round"
1011
+ }
1012
+ )
1013
+ }
1014
+ );
1015
+ }
1016
+ function TextAlignRight(props) {
1017
+ return /* @__PURE__ */ jsx(
1018
+ "svg",
1019
+ {
1020
+ width: "16",
1021
+ height: "16",
1022
+ viewBox: "0 0 24 24",
1023
+ fill: "currentColor",
1024
+ xmlns: "http://www.w3.org/2000/svg",
1025
+ ...props,
1026
+ children: /* @__PURE__ */ jsx(
1027
+ "path",
1028
+ {
1029
+ d: "M8 10H21M3 14H21M8 18H21M3 6H21",
1030
+ stroke: "#000000",
1031
+ "stroke-width": "2",
1032
+ "stroke-linecap": "round",
1033
+ "stroke-linejoin": "round"
1034
+ }
1035
+ )
1036
+ }
1037
+ );
1038
+ }
1039
+ function TextAlignCenter(props) {
1040
+ return /* @__PURE__ */ jsx(
1041
+ "svg",
1042
+ {
1043
+ width: "16",
1044
+ height: "16",
1045
+ viewBox: "0 0 24 24",
1046
+ fill: "currentColor",
1047
+ xmlns: "http://www.w3.org/2000/svg",
1048
+ ...props,
1049
+ children: /* @__PURE__ */ jsx(
1050
+ "path",
1051
+ {
1052
+ d: "M3 6H21M3 14H21M17 10H7M17 18H7",
1053
+ stroke: "#000000",
1054
+ "stroke-width": "2",
1055
+ "stroke-linecap": "round",
1056
+ "stroke-linejoin": "round"
1057
+ }
1058
+ )
1059
+ }
1060
+ );
1061
+ }
1062
+ function useTextAlign(editor, props = { disabled: false }) {
1063
+ const editorState = useEditorState({
1064
+ editor,
1065
+ selector: (ctx) => {
1066
+ return {
1067
+ isTextAlignLeft: ctx.editor.isActive({ textAlign: "left" }) ?? false,
1068
+ isTextAlignRight: ctx.editor.isActive({ textAlign: "right" }) ?? false,
1069
+ isTextAlignCenter: ctx.editor.isActive({ textAlign: "center" }) ?? false,
1070
+ isTextAlignJustify: ctx.editor.isActive({ textAlign: "justify" }) ?? false,
1071
+ canToggleAlign: ctx.editor.can().chain().setTextAlign("left").run() ?? false
1072
+ };
1073
+ }
1074
+ });
1075
+ const setTextAlign = (alignment) => {
1076
+ editor.chain().focus().setTextAlign(alignment).run();
1077
+ };
1078
+ return {
1079
+ textAlignLeftButton: toolbarButton("text-align-left", {
1080
+ onClick: () => setTextAlign("left"),
1081
+ icon: /* @__PURE__ */ jsx(TextAlignLeft, {}),
1082
+ active: editorState.isTextAlignLeft,
1083
+ disabled: props.disabled || !editor || !editorState.canToggleAlign,
1084
+ tooltip: "Text Align Left"
1085
+ }),
1086
+ textAlignCenterButton: toolbarButton("text-align-center", {
1087
+ onClick: () => setTextAlign("center"),
1088
+ icon: /* @__PURE__ */ jsx(TextAlignCenter, {}),
1089
+ active: editorState.isTextAlignCenter,
1090
+ disabled: props.disabled || !editor || !editorState.canToggleAlign,
1091
+ tooltip: "Text Align Center"
1092
+ }),
1093
+ textAlignRightButton: toolbarButton("text-align-right", {
1094
+ onClick: () => setTextAlign("right"),
1095
+ icon: /* @__PURE__ */ jsx(TextAlignRight, {}),
1096
+ active: editorState.isTextAlignRight,
1097
+ disabled: props.disabled || !editor || !editorState.canToggleAlign,
1098
+ tooltip: "Text Align Right"
1099
+ }),
1100
+ textAlignJustifyButton: toolbarButton("text-align-justify", {
1101
+ onClick: () => setTextAlign("justify"),
1102
+ icon: /* @__PURE__ */ jsx(TextAlignJustify, {}),
1103
+ active: editorState.isTextAlignJustify,
1104
+ disabled: props.disabled || !editor || !editorState.canToggleAlign,
1105
+ tooltip: "Text Align Justify"
1106
+ })
1107
+ };
1108
+ }
1109
+ const extensions = [
1110
+ StarterKit.configure({
1111
+ heading: false,
1112
+ // disable default so we can use our custom version
1113
+ link: {
1114
+ openOnClick: false
1115
+ }
1116
+ }),
1117
+ HeadingWithSEOTag,
1118
+ AccentCursiveMark,
1119
+ Superscript,
1120
+ Subscript,
1121
+ Gapcursor,
1122
+ // cursor for resizing tables
1123
+ TableKit.configure({
1124
+ table: { resizable: true }
1125
+ }),
1126
+ TextAlign.configure({
1127
+ types: ["heading", "paragraph"]
1128
+ })
1129
+ ];
1130
+ const RichTextInput = forwardRef((props, forwardedRef) => {
1131
+ const { editor, field } = useTiptapEditor(props.name, "", extensions);
1132
+ const starterKit = useStarterKit(editor, { disabled: props.disabled });
1133
+ const heading = useHeading(editor, { disabled: props.disabled });
1134
+ const accentCursive = useAccentCursive(editor, { disabled: props.disabled });
1135
+ const link = useLink(editor, { disabled: props.disabled });
1136
+ const script = useScript(editor, { disabled: props.disabled });
1137
+ const table = useTable(editor, { disabled: props.disabled });
1138
+ const textAlign = useTextAlign(editor, { disabled: props.disabled });
1139
+ return /* @__PURE__ */ jsxs(BaseTiptapInput, { editor, field, ...props, ref: forwardedRef, children: [
1140
+ heading.headingSelect,
1141
+ heading.headingTagSelect,
1142
+ spacer(8),
1143
+ starterKit.boldButton,
1144
+ starterKit.italicButton,
1145
+ accentCursive.button,
1146
+ starterKit.underlineButton,
1147
+ starterKit.strikeButton,
1148
+ script.superscriptButton,
1149
+ script.subscriptButton,
1150
+ spacer(8),
1151
+ textAlign.textAlignLeftButton,
1152
+ textAlign.textAlignCenterButton,
1153
+ textAlign.textAlignRightButton,
1154
+ textAlign.textAlignJustifyButton,
1155
+ spacer(8),
1156
+ starterKit.bulletButton,
1157
+ starterKit.orderedButton,
1158
+ spacer(8),
1159
+ starterKit.codeButton,
1160
+ starterKit.blockquoteButton,
1161
+ link.linkButton,
1162
+ link.linkDialog,
1163
+ spacer(8),
1164
+ table.tableButton,
1165
+ table.addColumnButton,
1166
+ table.removeColumnButton,
1167
+ table.addRowButton,
1168
+ table.removeRowButton,
1169
+ table.tableDialog
1170
+ ] });
1171
+ });
1172
+ export {
1173
+ RichTextInput as default
1174
+ };
1175
+ //# sourceMappingURL=RichTextInput-DgT88AkO.mjs.map