@ablogcms/block-editor 3.2.28-beta.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 (267) hide show
  1. package/README.md +21 -0
  2. package/dist/chunk-4KUPYKHV.mjs +34 -0
  3. package/dist/chunk-4KUPYKHV.mjs.map +1 -0
  4. package/dist/chunk-57Q3DEDF.mjs +23 -0
  5. package/dist/chunk-57Q3DEDF.mjs.map +1 -0
  6. package/dist/chunk-DUT25D7Z.mjs +20 -0
  7. package/dist/chunk-DUT25D7Z.mjs.map +1 -0
  8. package/dist/chunk-EM5TLDPY.mjs +17 -0
  9. package/dist/chunk-EM5TLDPY.mjs.map +1 -0
  10. package/dist/chunk-GIHTGDIW.mjs +23 -0
  11. package/dist/chunk-GIHTGDIW.mjs.map +1 -0
  12. package/dist/chunk-HNSTT2Z4.mjs +87 -0
  13. package/dist/chunk-HNSTT2Z4.mjs.map +1 -0
  14. package/dist/chunk-JYUNKG2P.mjs +88 -0
  15. package/dist/chunk-JYUNKG2P.mjs.map +1 -0
  16. package/dist/chunk-OFWQRNO2.mjs +56 -0
  17. package/dist/chunk-OFWQRNO2.mjs.map +1 -0
  18. package/dist/chunk-OZG2BL6F.mjs +61 -0
  19. package/dist/chunk-OZG2BL6F.mjs.map +1 -0
  20. package/dist/chunk-S24TRRWW.mjs +3126 -0
  21. package/dist/chunk-S24TRRWW.mjs.map +1 -0
  22. package/dist/chunk-TKSGCO5Z.mjs +2813 -0
  23. package/dist/chunk-TKSGCO5Z.mjs.map +1 -0
  24. package/dist/chunk-XGAKMQH4.mjs +627 -0
  25. package/dist/chunk-XGAKMQH4.mjs.map +1 -0
  26. package/dist/components/BlockEditor/BlockEditor.d.ts +36 -0
  27. package/dist/components/BlockEditor/BlockEditor.mjs +19 -0
  28. package/dist/components/BlockEditor/BlockEditor.mjs.map +1 -0
  29. package/dist/components/BlockEditor/index.d.ts +1 -0
  30. package/dist/components/BlockEditor/types.d.ts +10 -0
  31. package/dist/components/menus/ContentItemMenu/ContentItemMenu.d.ts +10 -0
  32. package/dist/components/menus/ContentItemMenu/components/BlockMenus.d.ts +8 -0
  33. package/dist/components/menus/ContentItemMenu/components/IdEditor.d.ts +5 -0
  34. package/dist/components/menus/ContentItemMenu/hooks/useContentItemActions.d.ts +17 -0
  35. package/dist/components/menus/ContentItemMenu/hooks/useData.d.ts +13 -0
  36. package/dist/components/menus/ContentItemMenu/index.d.ts +1 -0
  37. package/dist/components/menus/LinkMenu/LinkMenu.d.ts +4 -0
  38. package/dist/components/menus/LinkMenu/index.d.ts +1 -0
  39. package/dist/components/menus/TextMenu/TextMenu.d.ts +6 -0
  40. package/dist/components/menus/TextMenu/components/ContentTypePicker.d.ts +8 -0
  41. package/dist/components/menus/TextMenu/components/CustomClassPicker.d.ts +6 -0
  42. package/dist/components/menus/TextMenu/components/EditLinkPopover.d.ts +8 -0
  43. package/dist/components/menus/TextMenu/components/FontFamilyPicker.d.ts +5 -0
  44. package/dist/components/menus/TextMenu/components/FontSizePicker.d.ts +5 -0
  45. package/dist/components/menus/TextMenu/hooks/useTextmenuCommands.d.ts +25 -0
  46. package/dist/components/menus/TextMenu/hooks/useTextmenuStates.d.ts +22 -0
  47. package/dist/components/menus/TextMenu/index.d.ts +1 -0
  48. package/dist/components/menus/index.d.ts +3 -0
  49. package/dist/components/menus/types.d.ts +18 -0
  50. package/dist/components/panels/AlignPicker/AlignPicker.d.ts +5 -0
  51. package/dist/components/panels/AlignPicker/AlignPicker.mjs +12 -0
  52. package/dist/components/panels/AlignPicker/AlignPicker.mjs.map +1 -0
  53. package/dist/components/panels/AlignPicker/index.d.ts +1 -0
  54. package/dist/components/panels/Colorpicker/ColorButton.d.ts +6 -0
  55. package/dist/components/panels/Colorpicker/ColorButton.mjs +10 -0
  56. package/dist/components/panels/Colorpicker/ColorButton.mjs.map +1 -0
  57. package/dist/components/panels/Colorpicker/Colorpicker.d.ts +6 -0
  58. package/dist/components/panels/Colorpicker/index.d.ts +1 -0
  59. package/dist/components/panels/LinkEditorPanel/LinkEditorPanel.d.ts +17 -0
  60. package/dist/components/panels/LinkEditorPanel/index.d.ts +1 -0
  61. package/dist/components/panels/LinkPreviewPanel/LinkPreviewPanel.d.ts +6 -0
  62. package/dist/components/panels/LinkPreviewPanel/index.d.ts +1 -0
  63. package/dist/components/panels/index.d.ts +4 -0
  64. package/dist/components/ui/Icon.d.ts +5 -0
  65. package/dist/components/ui/Icon.mjs +7 -0
  66. package/dist/components/ui/Icon.mjs.map +1 -0
  67. package/dist/components/ui/Surface.d.ts +6 -0
  68. package/dist/components/ui/Surface.mjs +10 -0
  69. package/dist/components/ui/Surface.mjs.map +1 -0
  70. package/dist/components/ui/Toolbar.d.ts +45 -0
  71. package/dist/components/ui/Toolbar.mjs +11 -0
  72. package/dist/components/ui/Toolbar.mjs.map +1 -0
  73. package/dist/config/blockMenuCategories.d.ts +22 -0
  74. package/dist/config/blockMenuCategories.mjs +19 -0
  75. package/dist/config/blockMenuCategories.mjs.map +1 -0
  76. package/dist/config/blocks/__tests__/createMockEditor.d.ts +29 -0
  77. package/dist/config/blocks/blockquote.d.ts +3 -0
  78. package/dist/config/blocks/bulletList.d.ts +3 -0
  79. package/dist/config/blocks/codeBlock.d.ts +3 -0
  80. package/dist/config/blocks/columns1.d.ts +3 -0
  81. package/dist/config/blocks/columns2.d.ts +3 -0
  82. package/dist/config/blocks/columns3.d.ts +3 -0
  83. package/dist/config/blocks/createHeadingActions.d.ts +7 -0
  84. package/dist/config/blocks/file.d.ts +3 -0
  85. package/dist/config/blocks/heading1.d.ts +3 -0
  86. package/dist/config/blocks/heading2.d.ts +3 -0
  87. package/dist/config/blocks/heading3.d.ts +3 -0
  88. package/dist/config/blocks/heading4.d.ts +3 -0
  89. package/dist/config/blocks/heading5.d.ts +3 -0
  90. package/dist/config/blocks/heading6.d.ts +3 -0
  91. package/dist/config/blocks/horizontalRule.d.ts +3 -0
  92. package/dist/config/blocks/image.d.ts +3 -0
  93. package/dist/config/blocks/index.d.ts +13 -0
  94. package/dist/config/blocks/linkButton.d.ts +3 -0
  95. package/dist/config/blocks/numberedList.d.ts +3 -0
  96. package/dist/config/blocks/paragraph.d.ts +3 -0
  97. package/dist/config/blocks/table.d.ts +3 -0
  98. package/dist/context/EditorExtensions.d.ts +12 -0
  99. package/dist/context/EditorExtensions.mjs +18 -0
  100. package/dist/context/EditorExtensions.mjs.map +1 -0
  101. package/dist/context/EditorSettings.d.ts +7 -0
  102. package/dist/context/EditorSettings.mjs +12 -0
  103. package/dist/context/EditorSettings.mjs.map +1 -0
  104. package/dist/dataview/column-type.d.ts +11 -0
  105. package/dist/dataview/column-type.mjs +14 -0
  106. package/dist/dataview/column-type.mjs.map +1 -0
  107. package/dist/extensions/BaseBlock/BaseBlock.d.ts +12 -0
  108. package/dist/extensions/BaseBlock/index.d.ts +1 -0
  109. package/dist/extensions/BlockquoteFigure/BlockquoteFigure.d.ts +11 -0
  110. package/dist/extensions/BlockquoteFigure/Quote/Quote.d.ts +3 -0
  111. package/dist/extensions/BlockquoteFigure/Quote/index.d.ts +1 -0
  112. package/dist/extensions/BlockquoteFigure/QuoteCaption/QuoteCaption.d.ts +3 -0
  113. package/dist/extensions/BlockquoteFigure/QuoteCaption/index.d.ts +1 -0
  114. package/dist/extensions/BlockquoteFigure/index.d.ts +1 -0
  115. package/dist/extensions/CustomConvertBlock/CustomConvertBlock.d.ts +14 -0
  116. package/dist/extensions/CustomConvertBlock/index.d.ts +1 -0
  117. package/dist/extensions/CustomMark/CustomMark.d.ts +3 -0
  118. package/dist/extensions/CustomMark/index.d.ts +1 -0
  119. package/dist/extensions/Document/Document.d.ts +2 -0
  120. package/dist/extensions/Document/index.d.ts +1 -0
  121. package/dist/extensions/Figcaption/Figcaption.d.ts +5 -0
  122. package/dist/extensions/Figcaption/index.d.ts +1 -0
  123. package/dist/extensions/Figure/Figure.d.ts +5 -0
  124. package/dist/extensions/Figure/index.d.ts +1 -0
  125. package/dist/extensions/FileBlock/FileBlock.d.ts +25 -0
  126. package/dist/extensions/FileBlock/components/FileBlockCaption.d.ts +6 -0
  127. package/dist/extensions/FileBlock/components/FileBlockMenu.d.ts +4 -0
  128. package/dist/extensions/FileBlock/components/FileBlockView.d.ts +9 -0
  129. package/dist/extensions/FileBlock/index.d.ts +1 -0
  130. package/dist/extensions/FileBlock/mediaUpdateHooks.d.ts +10 -0
  131. package/dist/extensions/FontStyle/FontStyle.d.ts +20 -0
  132. package/dist/extensions/FontStyle/index.d.ts +1 -0
  133. package/dist/extensions/Heading/Heading.d.ts +2 -0
  134. package/dist/extensions/Heading/index.d.ts +1 -0
  135. package/dist/extensions/HorizontalRule/HorizontalRule.d.ts +2 -0
  136. package/dist/extensions/HorizontalRule/index.d.ts +1 -0
  137. package/dist/extensions/Image/Image.d.ts +2 -0
  138. package/dist/extensions/Image/index.d.ts +1 -0
  139. package/dist/extensions/ImageBlock/ImageBlock.d.ts +34 -0
  140. package/dist/extensions/ImageBlock/components/ImageBlockCaption.d.ts +6 -0
  141. package/dist/extensions/ImageBlock/components/ImageBlockLink.d.ts +6 -0
  142. package/dist/extensions/ImageBlock/components/ImageBlockMenu.d.ts +4 -0
  143. package/dist/extensions/ImageBlock/components/ImageBlockView.d.ts +9 -0
  144. package/dist/extensions/ImageBlock/components/ImageBlockWidth.d.ts +5 -0
  145. package/dist/extensions/ImageBlock/index.d.ts +1 -0
  146. package/dist/extensions/ImageBlock/mediaUpdateHooks.d.ts +10 -0
  147. package/dist/extensions/Link/Link.d.ts +4 -0
  148. package/dist/extensions/Link/index.d.ts +1 -0
  149. package/dist/extensions/LinkButton/LinkButton.d.ts +15 -0
  150. package/dist/extensions/LinkButton/components/LinkButtonMenu.d.ts +4 -0
  151. package/dist/extensions/LinkButton/components/LinkButtonView.d.ts +7 -0
  152. package/dist/extensions/LinkButton/index.d.ts +1 -0
  153. package/dist/extensions/MediaUpload/MediaUpload.d.ts +12 -0
  154. package/dist/extensions/MediaUpload/index.d.ts +1 -0
  155. package/dist/extensions/MediaUpload/view/Dropzone.d.ts +7 -0
  156. package/dist/extensions/MediaUpload/view/filterFilesByMediaType.d.ts +10 -0
  157. package/dist/extensions/MediaUpload/view/hooks.d.ts +26 -0
  158. package/dist/extensions/MediaUpload/view/index.d.ts +1 -0
  159. package/dist/extensions/MediaUpload/view/insertMediaBlocks.d.ts +22 -0
  160. package/dist/extensions/MultiColumn/Column.d.ts +3 -0
  161. package/dist/extensions/MultiColumn/Columns.d.ts +16 -0
  162. package/dist/extensions/MultiColumn/index.d.ts +2 -0
  163. package/dist/extensions/PasteHandler/PasteHandler.d.ts +4 -0
  164. package/dist/extensions/PasteHandler/index.d.ts +1 -0
  165. package/dist/extensions/Selection/Selection.d.ts +3 -0
  166. package/dist/extensions/Selection/index.d.ts +1 -0
  167. package/dist/extensions/SlashCommand/BlockMenu.d.ts +9 -0
  168. package/dist/extensions/SlashCommand/SlashCommand.d.ts +18 -0
  169. package/dist/extensions/SlashCommand/index.d.ts +1 -0
  170. package/dist/extensions/Table/Cell.d.ts +12 -0
  171. package/dist/extensions/Table/Header.d.ts +9 -0
  172. package/dist/extensions/Table/Row.d.ts +2 -0
  173. package/dist/extensions/Table/Table.d.ts +9 -0
  174. package/dist/extensions/Table/index.d.ts +4 -0
  175. package/dist/extensions/Table/menus/ColorPicker.d.ts +4 -0
  176. package/dist/extensions/Table/menus/TableColumn/index.d.ts +4 -0
  177. package/dist/extensions/Table/menus/TableColumn/utils.d.ts +8 -0
  178. package/dist/extensions/Table/menus/TableMenu/index.d.ts +4 -0
  179. package/dist/extensions/Table/menus/TableRow/index.d.ts +4 -0
  180. package/dist/extensions/Table/menus/TableRow/utils.d.ts +8 -0
  181. package/dist/extensions/Table/menus/hooks.d.ts +5 -0
  182. package/dist/extensions/Table/menus/index.d.ts +3 -0
  183. package/dist/extensions/Table/utils.d.ts +44 -0
  184. package/dist/extensions/TrailingNode/index.d.ts +1 -0
  185. package/dist/extensions/TrailingNode/trailing-node.d.ts +11 -0
  186. package/dist/extensions/extension-kit.d.ts +10 -0
  187. package/dist/extensions/index.d.ts +34 -0
  188. package/dist/extensions/mediaBlockContent.d.ts +41 -0
  189. package/dist/hooks/resolveCommands.d.ts +10 -0
  190. package/dist/hooks/useBlockEditor.d.ts +27 -0
  191. package/dist/hooks/useBlockMenus.d.ts +17 -0
  192. package/dist/hooks/useEditorViewDom.d.ts +15 -0
  193. package/dist/hooks/useFrequentlyUsed.d.ts +6 -0
  194. package/dist/hooks/useSettings.d.ts +10 -0
  195. package/dist/index.d.ts +5 -0
  196. package/dist/index.mjs +33 -0
  197. package/dist/index.mjs.map +1 -0
  198. package/dist/lib/utils/commandUsageStorage.d.ts +14 -0
  199. package/dist/lib/utils/index.d.ts +5 -0
  200. package/dist/lib/utils/isCustomNodeSelected.d.ts +4 -0
  201. package/dist/lib/utils/isTextSelected.d.ts +5 -0
  202. package/dist/tiptap/core.d.ts +1 -0
  203. package/dist/tiptap/core.mjs +3 -0
  204. package/dist/tiptap/core.mjs.map +1 -0
  205. package/dist/tiptap/pm/changeset.d.ts +1 -0
  206. package/dist/tiptap/pm/changeset.mjs +3 -0
  207. package/dist/tiptap/pm/changeset.mjs.map +1 -0
  208. package/dist/tiptap/pm/commands.d.ts +1 -0
  209. package/dist/tiptap/pm/commands.mjs +3 -0
  210. package/dist/tiptap/pm/commands.mjs.map +1 -0
  211. package/dist/tiptap/pm/dropcursor.d.ts +1 -0
  212. package/dist/tiptap/pm/dropcursor.mjs +3 -0
  213. package/dist/tiptap/pm/dropcursor.mjs.map +1 -0
  214. package/dist/tiptap/pm/gapcursor.d.ts +1 -0
  215. package/dist/tiptap/pm/gapcursor.mjs +3 -0
  216. package/dist/tiptap/pm/gapcursor.mjs.map +1 -0
  217. package/dist/tiptap/pm/history.d.ts +1 -0
  218. package/dist/tiptap/pm/history.mjs +3 -0
  219. package/dist/tiptap/pm/history.mjs.map +1 -0
  220. package/dist/tiptap/pm/inputrules.d.ts +1 -0
  221. package/dist/tiptap/pm/inputrules.mjs +3 -0
  222. package/dist/tiptap/pm/inputrules.mjs.map +1 -0
  223. package/dist/tiptap/pm/keymap.d.ts +1 -0
  224. package/dist/tiptap/pm/keymap.mjs +3 -0
  225. package/dist/tiptap/pm/keymap.mjs.map +1 -0
  226. package/dist/tiptap/pm/model.d.ts +1 -0
  227. package/dist/tiptap/pm/model.mjs +3 -0
  228. package/dist/tiptap/pm/model.mjs.map +1 -0
  229. package/dist/tiptap/pm/schema-list.d.ts +1 -0
  230. package/dist/tiptap/pm/schema-list.mjs +3 -0
  231. package/dist/tiptap/pm/schema-list.mjs.map +1 -0
  232. package/dist/tiptap/pm/state.d.ts +1 -0
  233. package/dist/tiptap/pm/state.mjs +3 -0
  234. package/dist/tiptap/pm/state.mjs.map +1 -0
  235. package/dist/tiptap/pm/tables.d.ts +1 -0
  236. package/dist/tiptap/pm/tables.mjs +3 -0
  237. package/dist/tiptap/pm/tables.mjs.map +1 -0
  238. package/dist/tiptap/pm/transform.d.ts +1 -0
  239. package/dist/tiptap/pm/transform.mjs +3 -0
  240. package/dist/tiptap/pm/transform.mjs.map +1 -0
  241. package/dist/tiptap/pm/view.d.ts +1 -0
  242. package/dist/tiptap/pm/view.mjs +3 -0
  243. package/dist/tiptap/pm/view.mjs.map +1 -0
  244. package/dist/tiptap/react.d.ts +1 -0
  245. package/dist/tiptap/react.mjs +3 -0
  246. package/dist/tiptap/react.mjs.map +1 -0
  247. package/dist/tiptap/suggestion.d.ts +3 -0
  248. package/dist/tiptap/suggestion.mjs +8 -0
  249. package/dist/tiptap/suggestion.mjs.map +1 -0
  250. package/dist/tiptap/tiptap.d.ts +48 -0
  251. package/dist/tiptap/tiptap.mjs +41 -0
  252. package/dist/tiptap/tiptap.mjs.map +1 -0
  253. package/dist/types/index.d.ts +149 -0
  254. package/dist/types/index.mjs +1 -0
  255. package/dist/types/index.mjs.map +1 -0
  256. package/dist/utils/createBlockMenu.d.ts +30 -0
  257. package/dist/utils/createProps.d.ts +7 -0
  258. package/dist/utils/createProps.mjs +7 -0
  259. package/dist/utils/createProps.mjs.map +1 -0
  260. package/dist/utils/mergeBlockDefinitions.d.ts +10 -0
  261. package/dist/utils/mergeBlockDefinitions.mjs +8 -0
  262. package/dist/utils/mergeBlockDefinitions.mjs.map +1 -0
  263. package/dist/utils/mergeSettings.d.ts +11 -0
  264. package/dist/utils/normalizeSettings.d.ts +28 -0
  265. package/dist/utils/normalizeSettings.mjs +13 -0
  266. package/dist/utils/normalizeSettings.mjs.map +1 -0
  267. package/package.json +243 -0
@@ -0,0 +1,2813 @@
1
+ import {
2
+ Icon
3
+ } from "./chunk-57Q3DEDF.mjs";
4
+
5
+ // src/lib/utils/index.ts
6
+ import classnames from "classnames";
7
+
8
+ // src/extensions/index.ts
9
+ import { StarterKit } from "@tiptap/starter-kit";
10
+ import { Highlight } from "@tiptap/extension-highlight";
11
+ import { Underline } from "@tiptap/extension-underline";
12
+ import { TextAlign } from "@tiptap/extension-text-align";
13
+ import { TextStyle } from "@tiptap/extension-text-style";
14
+ import { Typography } from "@tiptap/extension-typography";
15
+ import { Subscript } from "@tiptap/extension-subscript";
16
+ import { Superscript } from "@tiptap/extension-superscript";
17
+ import { Paragraph } from "@tiptap/extension-paragraph";
18
+ import { CodeBlock } from "@tiptap/extension-code-block";
19
+ import { BulletList, OrderedList } from "@tiptap/extension-list";
20
+ import { Placeholder, Focus, Dropcursor } from "@tiptap/extensions";
21
+
22
+ // src/extensions/Selection/Selection.ts
23
+ import { Extension } from "@tiptap/core";
24
+ import { Plugin, PluginKey } from "@tiptap/pm/state";
25
+ import { Decoration, DecorationSet } from "@tiptap/pm/view";
26
+ var Selection = Extension.create({
27
+ name: "selection",
28
+ addProseMirrorPlugins() {
29
+ const { editor } = this;
30
+ return [
31
+ new Plugin({
32
+ key: new PluginKey("selection"),
33
+ props: {
34
+ decorations(state) {
35
+ if (state.selection.empty) {
36
+ return null;
37
+ }
38
+ if (editor.isFocused === true) {
39
+ return null;
40
+ }
41
+ return DecorationSet.create(state.doc, [
42
+ Decoration.inline(state.selection.from, state.selection.to, {
43
+ class: "selection"
44
+ })
45
+ ]);
46
+ }
47
+ }
48
+ })
49
+ ];
50
+ }
51
+ });
52
+
53
+ // src/extensions/Table/Table.ts
54
+ import { Table as TiptapTable } from "@tiptap/extension-table";
55
+ import { mergeAttributes } from "@tiptap/core";
56
+ var Table = TiptapTable.extend({
57
+ addAttributes() {
58
+ return {
59
+ scrollable: {
60
+ default: true,
61
+ parseHTML: (element) => {
62
+ return !!element.getAttribute("data-scrollable");
63
+ },
64
+ renderHTML: (attributes) => {
65
+ return {
66
+ "data-scrollable": attributes.scrollable ? true : null
67
+ };
68
+ }
69
+ }
70
+ };
71
+ },
72
+ renderHTML({ HTMLAttributes }) {
73
+ const scrollable = HTMLAttributes["data-scrollable"];
74
+ const scrollableWrapperClass = scrollable ? ACMS.Config.blockEditorConfig.tableScrollableWrapperClass : "";
75
+ const scrollableTableClass = ACMS.Config.blockEditorConfig.tableScrollableClass || "";
76
+ const tableAttrs = mergeAttributes(this.options.HTMLAttributes, HTMLAttributes);
77
+ const originalClass = tableAttrs.class || "";
78
+ const classList = originalClass.split(/\s+/).filter((cls) => cls && cls !== scrollableTableClass);
79
+ if (scrollable) {
80
+ classList.push(scrollableTableClass);
81
+ }
82
+ tableAttrs.class = classList.join(" ");
83
+ return ["div", { class: `tableWrapper ${scrollableWrapperClass}`.trim() }, ["table", tableAttrs, ["tbody", 0]]];
84
+ },
85
+ addCommands() {
86
+ return {
87
+ ...this.parent?.(),
88
+ toggleTableScrollable: () => ({ commands, editor }) => {
89
+ const { state } = editor;
90
+ const { from, to } = state.selection;
91
+ let found = false;
92
+ state.doc.nodesBetween(from, to, (node) => {
93
+ if (node.type.name === "table") {
94
+ found = true;
95
+ const { scrollable } = node.attrs;
96
+ commands.updateAttributes("table", { scrollable: !scrollable });
97
+ return false;
98
+ }
99
+ });
100
+ return found;
101
+ }
102
+ };
103
+ }
104
+ }).configure({
105
+ resizable: false
106
+ });
107
+
108
+ // src/extensions/Table/Cell.ts
109
+ import { mergeAttributes as mergeAttributes2, Node } from "@tiptap/core";
110
+ import { Plugin as Plugin2 } from "@tiptap/pm/state";
111
+ import { Decoration as Decoration2, DecorationSet as DecorationSet2 } from "@tiptap/pm/view";
112
+
113
+ // src/extensions/Table/utils.ts
114
+ import { findParentNode } from "@tiptap/core";
115
+ import { CellSelection, TableMap } from "@tiptap/pm/tables";
116
+ var isRectSelected = (rect) => (selection) => {
117
+ const map = TableMap.get(selection.$anchorCell.node(-1));
118
+ const start = selection.$anchorCell.start(-1);
119
+ const cells = map.cellsInRect(rect);
120
+ const selectedCells = map.cellsInRect(
121
+ map.rectBetween(selection.$anchorCell.pos - start, selection.$headCell.pos - start)
122
+ );
123
+ for (let i = 0, count = cells.length; i < count; i += 1) {
124
+ if (selectedCells.indexOf(cells[i]) === -1) {
125
+ return false;
126
+ }
127
+ }
128
+ return true;
129
+ };
130
+ var findTable = (selection) => findParentNode((node) => node.type.spec.tableRole && node.type.spec.tableRole === "table")(selection);
131
+ var isCellSelection = (selection) => selection instanceof CellSelection;
132
+ var isColumnSelected = (columnIndex) => (selection) => {
133
+ if (isCellSelection(selection)) {
134
+ const map = TableMap.get(selection.$anchorCell.node(-1));
135
+ return isRectSelected({
136
+ left: columnIndex,
137
+ right: columnIndex + 1,
138
+ top: 0,
139
+ bottom: map.height
140
+ })(selection);
141
+ }
142
+ return false;
143
+ };
144
+ var isRowSelected = (rowIndex) => (selection) => {
145
+ if (isCellSelection(selection)) {
146
+ const map = TableMap.get(selection.$anchorCell.node(-1));
147
+ return isRectSelected({
148
+ left: 0,
149
+ right: map.width,
150
+ top: rowIndex,
151
+ bottom: rowIndex + 1
152
+ })(selection);
153
+ }
154
+ return false;
155
+ };
156
+ var getCellsInColumn = (columnIndex) => (selection) => {
157
+ const table = findTable(selection);
158
+ if (table) {
159
+ const map = TableMap.get(table.node);
160
+ const indexes = Array.isArray(columnIndex) ? columnIndex : Array.from([columnIndex]);
161
+ return indexes.reduce(
162
+ (acc, index) => {
163
+ if (index >= 0 && index <= map.width - 1) {
164
+ const cells = map.cellsInRect({
165
+ left: index,
166
+ right: index + 1,
167
+ top: 0,
168
+ bottom: map.height
169
+ });
170
+ return acc.concat(
171
+ cells.map((nodePos) => {
172
+ const node = table.node.nodeAt(nodePos);
173
+ const pos = nodePos + table.start;
174
+ return { pos, start: pos + 1, node };
175
+ })
176
+ );
177
+ }
178
+ return acc;
179
+ },
180
+ []
181
+ );
182
+ }
183
+ return null;
184
+ };
185
+ var getCellsInRow = (rowIndex) => (selection) => {
186
+ const table = findTable(selection);
187
+ if (table) {
188
+ const map = TableMap.get(table.node);
189
+ const indexes = Array.isArray(rowIndex) ? rowIndex : Array.from([rowIndex]);
190
+ return indexes.reduce(
191
+ (acc, index) => {
192
+ if (index >= 0 && index <= map.height - 1) {
193
+ const cells = map.cellsInRect({
194
+ left: 0,
195
+ right: map.width,
196
+ top: index,
197
+ bottom: index + 1
198
+ });
199
+ return acc.concat(
200
+ cells.map((nodePos) => {
201
+ const node = table.node.nodeAt(nodePos);
202
+ const pos = nodePos + table.start;
203
+ return { pos, start: pos + 1, node };
204
+ })
205
+ );
206
+ }
207
+ return acc;
208
+ },
209
+ []
210
+ );
211
+ }
212
+ return null;
213
+ };
214
+ var select = (type) => (index) => (tr) => {
215
+ const table = findTable(tr.selection);
216
+ const isRowSelection = type === "row";
217
+ if (table) {
218
+ const map = TableMap.get(table.node);
219
+ if (index >= 0 && index < (isRowSelection ? map.height : map.width)) {
220
+ const left = isRowSelection ? 0 : index;
221
+ const top = isRowSelection ? index : 0;
222
+ const right = isRowSelection ? map.width : index + 1;
223
+ const bottom = isRowSelection ? index + 1 : map.height;
224
+ const cellsInFirstRow = map.cellsInRect({
225
+ left,
226
+ top,
227
+ right: isRowSelection ? right : left + 1,
228
+ bottom: isRowSelection ? top + 1 : bottom
229
+ });
230
+ const cellsInLastRow = bottom - top === 1 ? cellsInFirstRow : map.cellsInRect({
231
+ left: isRowSelection ? left : right - 1,
232
+ top: isRowSelection ? bottom - 1 : top,
233
+ right,
234
+ bottom
235
+ });
236
+ const head = table.start + cellsInFirstRow[0];
237
+ const anchor = table.start + cellsInLastRow[cellsInLastRow.length - 1];
238
+ const $head = tr.doc.resolve(head);
239
+ const $anchor = tr.doc.resolve(anchor);
240
+ return tr.setSelection(new CellSelection($anchor, $head));
241
+ }
242
+ }
243
+ return tr;
244
+ };
245
+ var selectColumn = select("column");
246
+ var selectRow = select("row");
247
+
248
+ // src/extensions/Table/Cell.ts
249
+ var TableCell = Node.create({
250
+ name: "tableCell",
251
+ content: "block+",
252
+ // TODO: Do not allow table in table
253
+ tableRole: "cell",
254
+ isolating: true,
255
+ addOptions() {
256
+ return {
257
+ HTMLAttributes: {}
258
+ };
259
+ },
260
+ parseHTML() {
261
+ return [{ tag: "td" }];
262
+ },
263
+ renderHTML({ HTMLAttributes }) {
264
+ return ["td", mergeAttributes2(this.options.HTMLAttributes, HTMLAttributes), 0];
265
+ },
266
+ addAttributes() {
267
+ return {
268
+ colspan: {
269
+ default: 1,
270
+ parseHTML: (element) => {
271
+ const colspan = element.getAttribute("colspan");
272
+ const value = colspan ? parseInt(colspan, 10) : 1;
273
+ return value;
274
+ }
275
+ },
276
+ rowspan: {
277
+ default: 1,
278
+ parseHTML: (element) => {
279
+ const rowspan = element.getAttribute("rowspan");
280
+ const value = rowspan ? parseInt(rowspan, 10) : 1;
281
+ return value;
282
+ }
283
+ },
284
+ colwidth: {
285
+ default: null,
286
+ parseHTML: (element) => {
287
+ const colwidth = element.getAttribute("colwidth");
288
+ const value = colwidth ? [parseInt(colwidth, 10)] : null;
289
+ return value;
290
+ }
291
+ },
292
+ backgroundColor: {
293
+ default: null,
294
+ parseHTML: (element) => {
295
+ const style = element.getAttribute("style");
296
+ if (!style) return null;
297
+ const match = style.match(/background-color:\s*([^;]+)/i);
298
+ return match ? match[1] : null;
299
+ },
300
+ renderHTML: (attributes) => {
301
+ if (!attributes.backgroundColor) return {};
302
+ return {
303
+ style: `background-color: ${attributes.backgroundColor}`
304
+ };
305
+ }
306
+ }
307
+ };
308
+ },
309
+ addCommands() {
310
+ return {
311
+ setCellBackgroundColor: (color) => ({ commands }) => {
312
+ return commands.updateAttributes("tableCell", {
313
+ backgroundColor: color
314
+ });
315
+ }
316
+ };
317
+ },
318
+ addProseMirrorPlugins() {
319
+ const { isEditable } = this.editor;
320
+ return [
321
+ new Plugin2({
322
+ props: {
323
+ decorations: (state) => {
324
+ if (!isEditable) {
325
+ return DecorationSet2.empty;
326
+ }
327
+ const { doc, selection } = state;
328
+ const decorations = [];
329
+ const cells = getCellsInColumn(0)(selection);
330
+ if (cells) {
331
+ cells.forEach(({ pos }, index) => {
332
+ decorations.push(
333
+ Decoration2.widget(pos + 1, () => {
334
+ const rowSelected = isRowSelected(index)(selection);
335
+ let className = "grip-row";
336
+ if (rowSelected) {
337
+ className += " selected";
338
+ }
339
+ if (index === 0) {
340
+ className += " first";
341
+ }
342
+ if (index === cells.length - 1) {
343
+ className += " last";
344
+ }
345
+ const grip = document.createElement("button");
346
+ const icon = document.createElement("span");
347
+ icon.className = "material-symbols-outlined acms-admin-block-editor-icon grip-icon";
348
+ icon.textContent = "more_vert";
349
+ icon.setAttribute("aria-hidden", "true");
350
+ grip.appendChild(icon);
351
+ grip.className = className;
352
+ grip.type = "button";
353
+ grip.addEventListener("mousedown", (event) => {
354
+ event.preventDefault();
355
+ event.stopImmediatePropagation();
356
+ this.editor.view.dispatch(selectRow(index)(this.editor.state.tr));
357
+ });
358
+ return grip;
359
+ })
360
+ );
361
+ });
362
+ }
363
+ return DecorationSet2.create(doc, decorations);
364
+ }
365
+ }
366
+ })
367
+ ];
368
+ }
369
+ });
370
+
371
+ // src/extensions/Table/Row.ts
372
+ import { TableRow as TiptapTableRow } from "@tiptap/extension-table";
373
+ var TableRow = TiptapTableRow.extend({
374
+ allowGapCursor: false,
375
+ content: "(tableCell | tableHeader)*"
376
+ });
377
+
378
+ // src/extensions/Table/Header.ts
379
+ import { TableHeader as TiptapTableHeader } from "@tiptap/extension-table";
380
+ import { Plugin as Plugin3 } from "@tiptap/pm/state";
381
+ import { Decoration as Decoration3, DecorationSet as DecorationSet3 } from "@tiptap/pm/view";
382
+ var TableHeader = TiptapTableHeader.extend({
383
+ addAttributes() {
384
+ return {
385
+ colspan: {
386
+ default: 1
387
+ },
388
+ rowspan: {
389
+ default: 1
390
+ },
391
+ colwidth: {
392
+ default: null,
393
+ parseHTML: (element) => {
394
+ const colwidth = element.getAttribute("colwidth");
395
+ const value = colwidth ? colwidth.split(",").map((item) => parseInt(item, 10)) : null;
396
+ return value;
397
+ }
398
+ },
399
+ backgroundColor: {
400
+ default: null,
401
+ parseHTML: (element) => {
402
+ const style = element.getAttribute("style");
403
+ if (!style) return null;
404
+ const match = style.match(/background-color:\s*([^;]+)/i);
405
+ return match ? match[1] : null;
406
+ },
407
+ renderHTML: (attributes) => {
408
+ if (!attributes.backgroundColor) return {};
409
+ return {
410
+ style: `background-color: ${attributes.backgroundColor}`
411
+ };
412
+ }
413
+ }
414
+ };
415
+ },
416
+ addCommands() {
417
+ return {
418
+ setHeaderBackgroundColor: (color) => ({ commands }) => {
419
+ return commands.updateAttributes("tableHeader", {
420
+ backgroundColor: color
421
+ });
422
+ }
423
+ };
424
+ },
425
+ addProseMirrorPlugins() {
426
+ const { isEditable } = this.editor;
427
+ return [
428
+ new Plugin3({
429
+ props: {
430
+ decorations: (state) => {
431
+ if (!isEditable) {
432
+ return DecorationSet3.empty;
433
+ }
434
+ const { doc, selection } = state;
435
+ const decorations = [];
436
+ const cells = getCellsInRow(0)(selection);
437
+ if (cells) {
438
+ cells.forEach(({ pos }, index) => {
439
+ decorations.push(
440
+ Decoration3.widget(pos + 1, () => {
441
+ const colSelected = isColumnSelected(index)(selection);
442
+ let className = "grip-column";
443
+ if (colSelected) {
444
+ className += " selected";
445
+ }
446
+ if (index === 0) {
447
+ className += " first";
448
+ }
449
+ if (index === cells.length - 1) {
450
+ className += " last";
451
+ }
452
+ const grip = document.createElement("button");
453
+ const icon = document.createElement("span");
454
+ icon.className = "material-symbols-outlined acms-admin-block-editor-icon grip-icon";
455
+ icon.textContent = "more_horiz";
456
+ icon.setAttribute("aria-hidden", "true");
457
+ grip.appendChild(icon);
458
+ grip.className = className;
459
+ grip.type = "button";
460
+ grip.addEventListener("mousedown", (event) => {
461
+ event.preventDefault();
462
+ event.stopImmediatePropagation();
463
+ this.editor.view.dispatch(selectColumn(index)(this.editor.state.tr));
464
+ });
465
+ return grip;
466
+ })
467
+ );
468
+ });
469
+ }
470
+ return DecorationSet3.create(doc, decorations);
471
+ }
472
+ }
473
+ })
474
+ ];
475
+ }
476
+ });
477
+
478
+ // src/extensions/HorizontalRule/HorizontalRule.ts
479
+ import { mergeAttributes as mergeAttributes3 } from "@tiptap/core";
480
+ import { HorizontalRule as TiptapHorizontalRule } from "@tiptap/extension-horizontal-rule";
481
+ var HorizontalRule = TiptapHorizontalRule.extend({
482
+ renderHTML({ HTMLAttributes }) {
483
+ const attrs = mergeAttributes3(this.options.HTMLAttributes, HTMLAttributes);
484
+ return ["div", { "data-type": this.name }, ["hr", attrs]];
485
+ }
486
+ });
487
+
488
+ // src/extensions/Heading/Heading.ts
489
+ import { Heading as TiptapHeading } from "@tiptap/extension-heading";
490
+ var Heading = TiptapHeading.extend({
491
+ addAttributes() {
492
+ return {
493
+ ...this.parent?.()
494
+ };
495
+ }
496
+ });
497
+
498
+ // src/extensions/Document/Document.ts
499
+ import { Document as TiptapDocument } from "@tiptap/extension-document";
500
+ var Document = TiptapDocument.extend({
501
+ content: "(block|columns)+"
502
+ });
503
+
504
+ // src/extensions/TrailingNode/trailing-node.ts
505
+ import { Extension as Extension2 } from "@tiptap/core";
506
+ import { Plugin as Plugin4, PluginKey as PluginKey2 } from "@tiptap/pm/state";
507
+ function nodeEqualsType({ types, node }) {
508
+ return Array.isArray(types) && types.includes(node.type) || node.type === types;
509
+ }
510
+ var TrailingNode = Extension2.create({
511
+ name: "trailingNode",
512
+ addOptions() {
513
+ return {
514
+ node: "paragraph",
515
+ notAfter: ["paragraph"]
516
+ };
517
+ },
518
+ addProseMirrorPlugins() {
519
+ const plugin = new PluginKey2(this.name);
520
+ const disabledNodes = Object.entries(this.editor.schema.nodes).map(([, value]) => value).filter((node) => this.options.notAfter.includes(node.name));
521
+ return [
522
+ new Plugin4({
523
+ key: plugin,
524
+ appendTransaction: (_, __, state) => {
525
+ const { doc, tr, schema } = state;
526
+ const shouldInsertNodeAtEnd = plugin.getState(state);
527
+ const endPosition = doc.content.size;
528
+ const type = schema.nodes[this.options.node];
529
+ if (!shouldInsertNodeAtEnd) {
530
+ return;
531
+ }
532
+ return tr.insert(endPosition, type.create());
533
+ },
534
+ state: {
535
+ init: (_, state) => {
536
+ const lastNode = state.tr.doc.lastChild;
537
+ return !nodeEqualsType({ node: lastNode, types: disabledNodes });
538
+ },
539
+ apply: (tr, value) => {
540
+ if (!tr.docChanged) {
541
+ return value;
542
+ }
543
+ const lastNode = tr.doc.lastChild;
544
+ return !nodeEqualsType({ node: lastNode, types: disabledNodes });
545
+ }
546
+ }
547
+ })
548
+ ];
549
+ }
550
+ });
551
+
552
+ // src/extensions/SlashCommand/SlashCommand.ts
553
+ import { Extension as Extension3 } from "@tiptap/core";
554
+ import { ReactRenderer } from "@tiptap/react";
555
+ import Suggestion from "@tiptap/suggestion";
556
+ import { PluginKey as PluginKey3 } from "@tiptap/pm/state";
557
+
558
+ // src/extensions/SlashCommand/BlockMenu.tsx
559
+ import React, { useCallback, useEffect, useRef, useState } from "react";
560
+ import { Menu, MenuGroup, MenuItem, MenuList, MenuPopover } from "@ablogcms/components/dropdown-menu";
561
+ import { jsx } from "react/jsx-runtime";
562
+ var BlockMenu = React.forwardRef(({ items, command, ...menuProps }, ref) => {
563
+ const scrollContainer = useRef(null);
564
+ const itemRefs = useRef([]);
565
+ const [selectedGroupIndex, setSelectedGroupIndex] = useState(0);
566
+ const [selectedCommandIndex, setSelectedCommandIndex] = useState(0);
567
+ useEffect(() => {
568
+ itemRefs.current = items.map((group) => new Array(group.commands.length).fill(null));
569
+ setSelectedGroupIndex(0);
570
+ setSelectedCommandIndex(0);
571
+ }, [items]);
572
+ const selectItem = useCallback(
573
+ (groupIndex, commandIndex) => {
574
+ const selectedCommand = items[groupIndex].commands[commandIndex];
575
+ command(selectedCommand);
576
+ },
577
+ [items, command]
578
+ );
579
+ React.useImperativeHandle(ref, () => ({
580
+ onKeyDown: ({ event }) => {
581
+ if (event.key === "ArrowDown") {
582
+ if (!items.length) {
583
+ return false;
584
+ }
585
+ const { commands } = items[selectedGroupIndex];
586
+ let newCommandIndex = selectedCommandIndex + 1;
587
+ let newGroupIndex = selectedGroupIndex;
588
+ if (commands.length - 1 < newCommandIndex) {
589
+ newCommandIndex = 0;
590
+ newGroupIndex = selectedGroupIndex + 1;
591
+ }
592
+ if (items.length - 1 < newGroupIndex) {
593
+ newGroupIndex = 0;
594
+ }
595
+ setSelectedCommandIndex(newCommandIndex);
596
+ setSelectedGroupIndex(newGroupIndex);
597
+ return true;
598
+ }
599
+ if (event.key === "ArrowUp") {
600
+ if (!items.length) {
601
+ return false;
602
+ }
603
+ let newCommandIndex = selectedCommandIndex - 1;
604
+ let newGroupIndex = selectedGroupIndex;
605
+ if (newCommandIndex < 0) {
606
+ newGroupIndex = selectedGroupIndex - 1;
607
+ const commandLength = items[newGroupIndex]?.commands?.length || 0;
608
+ newCommandIndex = commandLength > 0 ? commandLength - 1 : 0;
609
+ }
610
+ if (newGroupIndex < 0) {
611
+ newGroupIndex = items.length - 1;
612
+ newCommandIndex = items[newGroupIndex].commands.length - 1;
613
+ }
614
+ setSelectedCommandIndex(newCommandIndex);
615
+ setSelectedGroupIndex(newGroupIndex);
616
+ return true;
617
+ }
618
+ if (event.key === "Enter") {
619
+ if (!items.length || selectedGroupIndex === -1 || selectedCommandIndex === -1) {
620
+ return false;
621
+ }
622
+ selectItem(selectedGroupIndex, selectedCommandIndex);
623
+ return true;
624
+ }
625
+ return false;
626
+ }
627
+ }));
628
+ useEffect(() => {
629
+ const el = itemRefs.current[selectedGroupIndex]?.[selectedCommandIndex];
630
+ if (el) {
631
+ el.scrollIntoView({
632
+ block: "nearest",
633
+ behavior: "auto"
634
+ });
635
+ }
636
+ }, [selectedCommandIndex, selectedGroupIndex]);
637
+ const createCommandClickHandler = useCallback(
638
+ (groupIndex, commandIndex) => () => {
639
+ selectItem(groupIndex, commandIndex);
640
+ },
641
+ [selectItem]
642
+ );
643
+ if (!items.length) {
644
+ return null;
645
+ }
646
+ return /* @__PURE__ */ jsx(
647
+ Menu,
648
+ {
649
+ ...menuProps,
650
+ focusManagerOptions: { initialFocus: -1 },
651
+ listNavigationOptions: { enabled: false },
652
+ children: /* @__PURE__ */ jsx(MenuPopover, { ref: scrollContainer, scrollable: true, "data-elevation": "3", children: /* @__PURE__ */ jsx(MenuList, { children: items.map((group, groupIndex) => /* @__PURE__ */ jsx(MenuGroup, { title: group.title, children: group.commands.map((command2, commandIndex) => /* @__PURE__ */ jsx(
653
+ MenuItem,
654
+ {
655
+ ref: (el) => {
656
+ if (!itemRefs.current[groupIndex]) {
657
+ itemRefs.current[groupIndex] = [];
658
+ }
659
+ itemRefs.current[groupIndex][commandIndex] = el;
660
+ },
661
+ isActive: selectedGroupIndex === groupIndex && selectedCommandIndex === commandIndex,
662
+ onSelect: createCommandClickHandler(groupIndex, commandIndex),
663
+ icon: /* @__PURE__ */ jsx(Icon, { name: command2.iconName }),
664
+ children: command2.label
665
+ },
666
+ `${command2.label}`
667
+ )) }, `${group.title}-group`)) }) })
668
+ }
669
+ );
670
+ });
671
+ BlockMenu.displayName = "BlockMenu";
672
+ var BlockMenu_default = BlockMenu;
673
+
674
+ // src/extensions/SlashCommand/SlashCommand.ts
675
+ var commonMenuProps = {
676
+ isOpen: true,
677
+ strategy: "fixed",
678
+ placement: "bottom-start",
679
+ focusManagerOptions: {
680
+ initialFocus: -1
681
+ }
682
+ };
683
+ var extensionName = "slashCommand";
684
+ var SlashCommand = Extension3.create({
685
+ name: extensionName,
686
+ priority: 200,
687
+ addOptions() {
688
+ return {
689
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars -- configure() の getItems とシグネチャを一致させ options 型を正しく推論させるための引数
690
+ getItems: (_props) => []
691
+ };
692
+ },
693
+ addProseMirrorPlugins() {
694
+ return [
695
+ Suggestion({
696
+ editor: this.editor,
697
+ char: "/",
698
+ allowSpaces: true,
699
+ startOfLine: true,
700
+ pluginKey: new PluginKey3(extensionName),
701
+ allow: ({ state, range }) => {
702
+ const $from = state.doc.resolve(range.from);
703
+ const isRootDepth = $from.depth === 1;
704
+ const isParagraph = $from.parent.type.name === "paragraph";
705
+ const isStartOfNode = $from.parent.textContent?.charAt(0) === "/";
706
+ const isInColumn = this.editor.isActive("column");
707
+ const afterContent = $from.parent.textContent?.substring($from.parent.textContent?.indexOf("/"));
708
+ const isValidAfterContent = !afterContent?.endsWith(" ");
709
+ return (isRootDepth && isParagraph && isStartOfNode || isInColumn && isParagraph && isStartOfNode) && isValidAfterContent;
710
+ },
711
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
712
+ command: ({ editor, props }) => {
713
+ const { view, state } = editor;
714
+ const { $head, $from } = view.state.selection;
715
+ const end = $from.pos;
716
+ const from = $head?.nodeBefore ? end - ($head.nodeBefore.text?.substring($head.nodeBefore.text?.indexOf("/")).length ?? 0) : $from.start();
717
+ const tr = state.tr.deleteRange(from, end);
718
+ view.dispatch(tr);
719
+ props.action(editor);
720
+ view.focus();
721
+ },
722
+ items: ({ query, editor }) => {
723
+ return this.options.getItems({ query, editor });
724
+ },
725
+ render: () => {
726
+ let component = null;
727
+ let scrollHandler = null;
728
+ return {
729
+ onStart: (props) => {
730
+ component = new ReactRenderer(BlockMenu_default, {
731
+ props,
732
+ editor: props.editor
733
+ });
734
+ const { view } = props.editor;
735
+ const getAnchorRect = () => {
736
+ if (!props.clientRect) {
737
+ return props.editor.storage[extensionName].rect;
738
+ }
739
+ const rect = props.clientRect();
740
+ if (!rect) {
741
+ return props.editor.storage[extensionName].rect;
742
+ }
743
+ if (component === null) {
744
+ return props.editor.storage[extensionName].rect;
745
+ }
746
+ const { element } = component;
747
+ if (!(element instanceof HTMLElement)) {
748
+ return props.editor.storage[extensionName].rect;
749
+ }
750
+ let yPos = rect.y;
751
+ if (rect.top + element.offsetHeight + 40 > window.innerHeight) {
752
+ const diff = rect.top + element.offsetHeight - window.innerHeight + 40;
753
+ yPos = rect.y - diff;
754
+ }
755
+ return new DOMRect(rect.x, yPos, rect.width, rect.height);
756
+ };
757
+ scrollHandler = () => {
758
+ if (component === null) {
759
+ return;
760
+ }
761
+ const newProps = {
762
+ ...props,
763
+ ...commonMenuProps,
764
+ getAnchorRect
765
+ };
766
+ component.updateProps(newProps);
767
+ };
768
+ view.dom.parentElement?.addEventListener("scroll", scrollHandler);
769
+ component.updateProps({
770
+ ...props,
771
+ ...commonMenuProps,
772
+ getAnchorRect
773
+ });
774
+ },
775
+ onUpdate(props) {
776
+ if (component === null) {
777
+ return;
778
+ }
779
+ component.updateProps(props);
780
+ const { view } = props.editor;
781
+ const getAnchorRect = () => {
782
+ if (!props.clientRect) {
783
+ return props.editor.storage[extensionName].rect;
784
+ }
785
+ const rect = props.clientRect();
786
+ if (!rect) {
787
+ return props.editor.storage[extensionName].rect;
788
+ }
789
+ return new DOMRect(rect.x, rect.y, rect.width, rect.height);
790
+ };
791
+ const scrollHandler2 = () => {
792
+ if (component === null) {
793
+ return;
794
+ }
795
+ component.updateProps({
796
+ ...props,
797
+ isOpen: true,
798
+ getAnchorRect
799
+ });
800
+ };
801
+ view.dom.parentElement?.addEventListener("scroll", scrollHandler2);
802
+ props.editor.storage[extensionName].rect = props.clientRect ? getAnchorRect() : {
803
+ width: 0,
804
+ height: 0,
805
+ left: 0,
806
+ top: 0,
807
+ right: 0,
808
+ bottom: 0
809
+ };
810
+ const newProps = {
811
+ ...props,
812
+ ...commonMenuProps,
813
+ getAnchorRect
814
+ };
815
+ component.updateProps(newProps);
816
+ },
817
+ onKeyDown(props) {
818
+ if (props.event.key === "Escape") {
819
+ const newProps = {
820
+ isOpen: false
821
+ };
822
+ component?.updateProps(newProps);
823
+ return true;
824
+ }
825
+ return component?.ref?.onKeyDown(props) || false;
826
+ },
827
+ onExit(props) {
828
+ if (scrollHandler) {
829
+ const { view } = props.editor;
830
+ view.dom.parentElement?.removeEventListener("scroll", scrollHandler);
831
+ }
832
+ if (component) {
833
+ component.destroy();
834
+ }
835
+ }
836
+ };
837
+ }
838
+ })
839
+ ];
840
+ },
841
+ addStorage() {
842
+ return {
843
+ rect: {
844
+ width: 0,
845
+ height: 0,
846
+ left: 0,
847
+ top: 0,
848
+ right: 0,
849
+ bottom: 0
850
+ }
851
+ };
852
+ }
853
+ });
854
+ var SlashCommand_default = SlashCommand;
855
+
856
+ // src/extensions/FontStyle/FontStyle.ts
857
+ import { Extension as Extension4 } from "@tiptap/core";
858
+ import "@tiptap/extension-text-style";
859
+ var FontStyle = Extension4.create({
860
+ name: "fontStyle",
861
+ addOptions() {
862
+ return {
863
+ types: ["textStyle"]
864
+ };
865
+ },
866
+ addGlobalAttributes() {
867
+ return [
868
+ {
869
+ types: ["paragraph"],
870
+ attributes: {
871
+ class: {}
872
+ }
873
+ },
874
+ {
875
+ types: this.options.types,
876
+ attributes: {
877
+ fontSize: {
878
+ parseHTML: (element) => {
879
+ return element.getAttribute("data-font-size") || null;
880
+ },
881
+ renderHTML: (attributes) => {
882
+ if (!attributes.fontSize) {
883
+ return {};
884
+ }
885
+ return {
886
+ style: `font-size: ${attributes.fontSize}`,
887
+ // 表示用
888
+ "data-font-size": attributes.fontSize
889
+ // 復元用
890
+ };
891
+ }
892
+ },
893
+ fontFamily: {
894
+ parseHTML: (element) => element.getAttribute("data-font-family") || null,
895
+ renderHTML: (attributes) => {
896
+ if (!attributes.fontFamily) return {};
897
+ return {
898
+ style: `font-family: ${attributes.fontFamily.replace(/"/g, "'")}`,
899
+ "data-font-family": attributes.fontFamily.replace(/"/g, "'")
900
+ };
901
+ }
902
+ },
903
+ fontColor: {
904
+ parseHTML: (element) => element.getAttribute("data-font-color") || null,
905
+ renderHTML: (attributes) => {
906
+ if (!attributes.fontColor) return {};
907
+ return {
908
+ style: `color: ${attributes.fontColor}`,
909
+ "data-font-color": attributes.fontColor
910
+ };
911
+ }
912
+ }
913
+ }
914
+ }
915
+ ];
916
+ },
917
+ addCommands() {
918
+ return {
919
+ setFontSize: (fontSize) => ({ chain }) => chain().setMark("textStyle", { fontSize }).run(),
920
+ unsetFontSize: () => ({ chain }) => chain().setMark("textStyle", { fontSize: null }).removeEmptyTextStyle().run(),
921
+ setFontFamily: (family) => ({ chain }) => chain().setMark("textStyle", { fontFamily: family }).run(),
922
+ unsetFontFamily: () => ({ chain }) => chain().setMark("textStyle", { fontFamily: null }).removeEmptyTextStyle().run(),
923
+ setFontColor: (color) => ({ chain }) => chain().setMark("textStyle", { fontColor: color }).run(),
924
+ unsetFontColor: () => ({ chain }) => chain().setMark("textStyle", { fontColor: null }).removeEmptyTextStyle().run()
925
+ };
926
+ }
927
+ });
928
+
929
+ // src/extensions/Figcaption/Figcaption.ts
930
+ import { mergeAttributes as mergeAttributes4, Node as Node2 } from "@tiptap/core";
931
+
932
+ // src/extensions/Image/Image.ts
933
+ import { Image as BaseImage } from "@tiptap/extension-image";
934
+ var Image = BaseImage.extend({
935
+ group: "block"
936
+ });
937
+
938
+ // src/extensions/Figcaption/Figcaption.ts
939
+ var Figcaption = Node2.create({
940
+ name: "figcaption",
941
+ addOptions() {
942
+ return {
943
+ HTMLAttributes: {}
944
+ };
945
+ },
946
+ content: "inline*",
947
+ selectable: false,
948
+ draggable: false,
949
+ marks: "link",
950
+ parseHTML() {
951
+ return [
952
+ {
953
+ tag: "figcaption"
954
+ }
955
+ ];
956
+ },
957
+ addKeyboardShortcuts() {
958
+ return {
959
+ // On Enter at the end of line, create new paragraph and focus
960
+ Enter: ({ editor }) => {
961
+ const {
962
+ state: {
963
+ selection: { $from, empty }
964
+ }
965
+ } = editor;
966
+ if (!empty || $from.parent.type !== this.type) {
967
+ return false;
968
+ }
969
+ const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2;
970
+ if (!isAtEnd) {
971
+ return false;
972
+ }
973
+ const pos = editor.state.selection.$from.end();
974
+ return editor.chain().focus(pos).insertContentAt(pos, { type: "paragraph" }).run();
975
+ },
976
+ // On Backspace at the beginning of line,
977
+ // dont delete content of image before
978
+ Backspace: ({ editor }) => {
979
+ const {
980
+ state: {
981
+ selection: { $from, empty }
982
+ }
983
+ } = editor;
984
+ if (!empty || $from.parent.type !== this.type) {
985
+ return false;
986
+ }
987
+ const isAtStart = $from.parentOffset === 0;
988
+ if (!isAtStart) {
989
+ return false;
990
+ }
991
+ const nodeBefore = editor.state.doc.nodeAt($from.pos - 2);
992
+ if (nodeBefore?.type.name === Image.name) {
993
+ return true;
994
+ }
995
+ return false;
996
+ }
997
+ };
998
+ },
999
+ renderHTML({ HTMLAttributes }) {
1000
+ return ["figcaption", mergeAttributes4(HTMLAttributes), 0];
1001
+ }
1002
+ });
1003
+
1004
+ // src/extensions/Link/Link.ts
1005
+ import { mergeAttributes as mergeAttributes5 } from "@tiptap/core";
1006
+ import { Link as TiptapLink } from "@tiptap/extension-link";
1007
+ import { Plugin as Plugin5 } from "@tiptap/pm/state";
1008
+ var ATTRIBUTE_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g;
1009
+ var DEFAULT_ALLOWED_PROTOCOLS = ["http", "https", "ftp", "ftps", "mailto", "tel", "callto", "sms", "cid", "xmpp"];
1010
+ var escapeRegExp = (value) => value.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
1011
+ function isAllowedBlockEditorLinkUri(uri, protocols) {
1012
+ const allowedProtocols = [...DEFAULT_ALLOWED_PROTOCOLS];
1013
+ if (protocols) {
1014
+ protocols.forEach((protocol) => {
1015
+ const nextProtocol = typeof protocol === "string" ? protocol : protocol.scheme;
1016
+ if (nextProtocol) {
1017
+ allowedProtocols.push(nextProtocol);
1018
+ }
1019
+ });
1020
+ }
1021
+ return !uri || uri.replace(ATTRIBUTE_WHITESPACE, "").match(
1022
+ new RegExp(
1023
+ `^(?:(?:${allowedProtocols.map(escapeRegExp).join("|")}):|[^a-z]|[a-z0-9+.\\-]+(?:[^a-z+.\\-:]|$))`,
1024
+ "i"
1025
+ )
1026
+ );
1027
+ }
1028
+ var Link = TiptapLink.extend({
1029
+ inclusive: false,
1030
+ parseHTML() {
1031
+ return [{ tag: 'a[href]:not([data-type="button"]):not([href *= "javascript:" i])' }];
1032
+ },
1033
+ renderHTML({ HTMLAttributes }) {
1034
+ const attrs = mergeAttributes5(this.options.HTMLAttributes, HTMLAttributes, { class: "link" });
1035
+ if (!attrs.target) {
1036
+ delete attrs.target;
1037
+ delete attrs.rel;
1038
+ }
1039
+ return ["a", attrs, 0];
1040
+ },
1041
+ addProseMirrorPlugins() {
1042
+ const { editor } = this;
1043
+ return [
1044
+ ...this.parent?.() || [],
1045
+ new Plugin5({
1046
+ props: {
1047
+ handleKeyDown: (view, event) => {
1048
+ const { selection } = editor.state;
1049
+ if (event.key === "Escape" && selection.empty !== true) {
1050
+ editor.commands.focus(selection.to, { scrollIntoView: false });
1051
+ }
1052
+ return false;
1053
+ }
1054
+ }
1055
+ })
1056
+ ];
1057
+ }
1058
+ });
1059
+
1060
+ // src/extensions/ImageBlock/ImageBlock.ts
1061
+ import { ReactNodeViewRenderer } from "@tiptap/react";
1062
+
1063
+ // src/extensions/ImageBlock/components/ImageBlockView.tsx
1064
+ import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2 } from "react";
1065
+ import { NodeViewWrapper } from "@tiptap/react";
1066
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
1067
+ function ImageBlockView(props) {
1068
+ const { editor, getPos, node } = props;
1069
+ const imageWrapperRef = useRef2(null);
1070
+ const { src, alt, caption, width, height, displayWidth, mediaId, align, link, target, entryId } = node.attrs;
1071
+ const wrapperClassName = cn("media-image-block", `align-${align || "left"}`);
1072
+ const figureClassName = cn(node.attrs.class);
1073
+ const onClick = useCallback2(() => {
1074
+ const pos = getPos();
1075
+ if (pos === void 0) return;
1076
+ editor.commands.setNodeSelection(pos);
1077
+ }, [getPos, editor.commands]);
1078
+ useEffect2(() => {
1079
+ const listener = (event) => {
1080
+ if (!(event instanceof CustomEvent)) {
1081
+ return;
1082
+ }
1083
+ const media = event.detail.data;
1084
+ if (parseInt(mediaId, 10) === media.media_id) {
1085
+ if (media.media_thumbnail) {
1086
+ editor.chain().updateAllMediaImageBlocks(media).run();
1087
+ }
1088
+ }
1089
+ };
1090
+ document.addEventListener("acms.media-updated", listener);
1091
+ return () => {
1092
+ document.removeEventListener("acms.media-updated", listener);
1093
+ };
1094
+ }, [mediaId, editor]);
1095
+ return /* @__PURE__ */ jsx2(
1096
+ NodeViewWrapper,
1097
+ {
1098
+ contentEditable: false,
1099
+ className: wrapperClassName,
1100
+ "data-type": "imageBlock",
1101
+ "data-align": align || "left",
1102
+ "data-link": link || null,
1103
+ "data-width": displayWidth || "100%",
1104
+ "data-eid": entryId || (typeof ACMS !== "undefined" ? ACMS.Config.eid : void 0),
1105
+ "data-no-lightbox": node.attrs.noLightbox === "true" ? "true" : "false",
1106
+ children: /* @__PURE__ */ jsxs(
1107
+ "figure",
1108
+ {
1109
+ className: figureClassName,
1110
+ contentEditable: false,
1111
+ ref: imageWrapperRef,
1112
+ style: { maxWidth: displayWidth },
1113
+ children: [
1114
+ link ? /* @__PURE__ */ jsx2(
1115
+ "a",
1116
+ {
1117
+ href: link,
1118
+ target: target || void 0,
1119
+ rel: target ? "noopener noreferrer" : void 0,
1120
+ onClick,
1121
+ children: /* @__PURE__ */ jsx2(
1122
+ "img",
1123
+ {
1124
+ src,
1125
+ className: `unit-id-${entryId || (typeof ACMS !== "undefined" ? ACMS.Config.eid : "")}`,
1126
+ width: width || void 0,
1127
+ height: height || void 0,
1128
+ alt: alt || "",
1129
+ loading: "lazy",
1130
+ decoding: "async",
1131
+ "data-mid": mediaId || void 0,
1132
+ draggable: false
1133
+ }
1134
+ )
1135
+ }
1136
+ ) : node.attrs.noLightbox !== "true" ? /* @__PURE__ */ jsx2("a", { href: src, onClick, children: /* @__PURE__ */ jsx2(
1137
+ "img",
1138
+ {
1139
+ src,
1140
+ className: `unit-id-${entryId || (typeof ACMS !== "undefined" ? ACMS.Config.eid : "")}`,
1141
+ width: width || void 0,
1142
+ height: height || void 0,
1143
+ alt: alt || "",
1144
+ loading: "lazy",
1145
+ decoding: "async",
1146
+ "data-mid": mediaId || void 0,
1147
+ draggable: false
1148
+ }
1149
+ ) }) : /* @__PURE__ */ jsx2(
1150
+ "img",
1151
+ {
1152
+ src,
1153
+ className: `unit-id-${entryId || (typeof ACMS !== "undefined" ? ACMS.Config.eid : "")}`,
1154
+ width: width || void 0,
1155
+ height: height || void 0,
1156
+ alt: alt || "",
1157
+ loading: "lazy",
1158
+ decoding: "async",
1159
+ "data-mid": mediaId || void 0,
1160
+ draggable: false,
1161
+ role: "button",
1162
+ tabIndex: 0,
1163
+ onClick,
1164
+ onKeyDown: (e) => {
1165
+ if (e.key === "Enter" || e.key === " ") {
1166
+ onClick();
1167
+ }
1168
+ }
1169
+ }
1170
+ ),
1171
+ caption && /* @__PURE__ */ jsx2("figcaption", { className: "caption", children: caption })
1172
+ ]
1173
+ }
1174
+ )
1175
+ }
1176
+ );
1177
+ }
1178
+
1179
+ // src/extensions/mediaBlockContent.ts
1180
+ var createImageBlockAttrs = (mediaItem, className) => {
1181
+ let width = null;
1182
+ let height = null;
1183
+ if (mediaItem.media_size.includes("x")) {
1184
+ const [tempX, tempY] = mediaItem.media_size.split("x");
1185
+ width = parseInt(tempX.trim(), 10);
1186
+ height = parseInt(tempY.trim(), 10);
1187
+ }
1188
+ return {
1189
+ src: mediaItem.media_root_path,
1190
+ class: className || null,
1191
+ mediaId: mediaItem.media_id,
1192
+ entryId: ACMS.Config.eid,
1193
+ width,
1194
+ height,
1195
+ link: mediaItem.media_link ?? null,
1196
+ caption: mediaItem.media_caption ?? null,
1197
+ alt: mediaItem.media_alt ?? null
1198
+ };
1199
+ };
1200
+ var createFileBlockAttrs = (mediaItem, className) => ({
1201
+ href: mediaItem.media_permalink,
1202
+ icon: mediaItem.media_icon,
1203
+ iconWidth: mediaItem.media_icon_width || "100",
1204
+ iconHeight: mediaItem.media_icon_height || "100",
1205
+ class: className || null,
1206
+ mediaId: mediaItem.media_id,
1207
+ caption: mediaItem.media_caption || mediaItem.media_title || null,
1208
+ alt: mediaItem.media_alt || null,
1209
+ extension: mediaItem.media_ext || null,
1210
+ fileSize: mediaItem.media_filesize || null
1211
+ });
1212
+ var buildMediaBlockContent = (mediaItem, className, noLightbox) => {
1213
+ if (mediaItem.media_type === "file") {
1214
+ return { type: "fileBlock", attrs: createFileBlockAttrs(mediaItem, className) };
1215
+ }
1216
+ return { type: "imageBlock", attrs: { ...createImageBlockAttrs(mediaItem, className), noLightbox } };
1217
+ };
1218
+
1219
+ // src/extensions/ImageBlock/ImageBlock.ts
1220
+ var ImageBlock = Image.extend({
1221
+ name: "imageBlock",
1222
+ group: "block",
1223
+ atom: true,
1224
+ defining: true,
1225
+ isolating: true,
1226
+ addOptions() {
1227
+ return {
1228
+ ...this.parent?.(),
1229
+ getImageDefaultLightbox: () => true
1230
+ };
1231
+ },
1232
+ addAttributes() {
1233
+ return {
1234
+ src: {
1235
+ default: "",
1236
+ renderHTML: (attributes) => ({
1237
+ src: attributes.src
1238
+ })
1239
+ },
1240
+ align: {
1241
+ default: "center",
1242
+ renderHTML: (attributes) => ({
1243
+ "data-align": attributes.align
1244
+ })
1245
+ },
1246
+ link: {
1247
+ default: null,
1248
+ renderHTML: (attributes) => ({
1249
+ "data-link": attributes.link
1250
+ })
1251
+ },
1252
+ target: {
1253
+ default: null,
1254
+ renderHTML: (attributes) => ({
1255
+ "data-target": attributes.target
1256
+ })
1257
+ },
1258
+ caption: {
1259
+ default: void 0,
1260
+ renderHTML: (attributes) => ({
1261
+ "data-caption": attributes.caption
1262
+ })
1263
+ },
1264
+ alt: {
1265
+ default: void 0,
1266
+ renderHTML: (attributes) => ({
1267
+ alt: attributes.alt
1268
+ })
1269
+ },
1270
+ width: {
1271
+ default: null,
1272
+ renderHTML: (attributes) => ({
1273
+ width: attributes.width
1274
+ })
1275
+ },
1276
+ height: {
1277
+ default: null,
1278
+ renderHTML: (attributes) => ({
1279
+ height: attributes.height
1280
+ })
1281
+ },
1282
+ displayWidth: {
1283
+ default: "100%",
1284
+ renderHTML: (attributes) => ({
1285
+ "data-width": attributes.displayWidth
1286
+ })
1287
+ },
1288
+ mediaId: {
1289
+ default: null,
1290
+ renderHTML: (attributes) => ({
1291
+ "data-mid": attributes.mediaId || null
1292
+ })
1293
+ },
1294
+ entryId: {
1295
+ default: null,
1296
+ renderHTML: (attributes) => ({
1297
+ "data-eid": attributes.entryId || ACMS.Config.eid
1298
+ })
1299
+ },
1300
+ noLightbox: {
1301
+ default: "false",
1302
+ renderHTML: (attributes) => ({
1303
+ "data-no-lightbox": attributes.noLightbox === "true" ? "true" : "false"
1304
+ })
1305
+ }
1306
+ };
1307
+ },
1308
+ parseHTML() {
1309
+ return [
1310
+ {
1311
+ tag: "figure",
1312
+ getAttrs: (element) => {
1313
+ const img = element.querySelector("img");
1314
+ const figcaption = element.querySelector("figcaption");
1315
+ const parent = element.closest(`[data-type="${this.name}"]`);
1316
+ const link = parent?.querySelector("a");
1317
+ return {
1318
+ src: img?.getAttribute("src"),
1319
+ align: parent?.getAttribute("data-align") || "center",
1320
+ link: parent?.getAttribute("data-link"),
1321
+ target: link?.target || null,
1322
+ caption: figcaption?.textContent?.trim() || "",
1323
+ alt: img?.getAttribute("alt"),
1324
+ width: img?.getAttribute("width"),
1325
+ height: img?.getAttribute("height"),
1326
+ displayWidth: parent?.getAttribute("data-width"),
1327
+ mediaId: img?.getAttribute("data-mid"),
1328
+ entryId: parent?.getAttribute("data-eid"),
1329
+ noLightbox: parent?.getAttribute("data-no-lightbox") === "true" ? "true" : "false"
1330
+ };
1331
+ }
1332
+ },
1333
+ {
1334
+ tag: "img",
1335
+ getAttrs: (element) => {
1336
+ if (element.closest('[data-type="fileBlock"]')) {
1337
+ return false;
1338
+ }
1339
+ return {
1340
+ src: element.getAttribute("src"),
1341
+ align: "center",
1342
+ link: "",
1343
+ target: null,
1344
+ caption: "",
1345
+ alt: element.getAttribute("alt"),
1346
+ width: element.getAttribute("width"),
1347
+ height: element.getAttribute("height"),
1348
+ displayWidth: "",
1349
+ mediaId: null,
1350
+ entryId: null,
1351
+ noLightbox: "false"
1352
+ };
1353
+ }
1354
+ }
1355
+ ];
1356
+ },
1357
+ renderHTML({ HTMLAttributes }) {
1358
+ const id = HTMLAttributes.id || null;
1359
+ const className = HTMLAttributes.class || "";
1360
+ const src = HTMLAttributes.src || "";
1361
+ const align = HTMLAttributes["data-align"] || "left";
1362
+ const link = HTMLAttributes["data-link"] || null;
1363
+ const target = HTMLAttributes["data-target"] || null;
1364
+ const caption = HTMLAttributes["data-caption"] || null;
1365
+ const alt = HTMLAttributes.alt || null;
1366
+ const width = HTMLAttributes.width || null;
1367
+ const height = HTMLAttributes.height || null;
1368
+ const displayWidth = HTMLAttributes["data-width"] || "100%";
1369
+ const mediaId = HTMLAttributes["data-mid"] || null;
1370
+ const eid = HTMLAttributes["data-eid"] || ACMS.Config.eid;
1371
+ const shouldUseLightbox = HTMLAttributes["data-no-lightbox"] !== "true";
1372
+ const img = [
1373
+ "img",
1374
+ {
1375
+ src,
1376
+ class: `unit-id-${eid}`,
1377
+ width,
1378
+ height,
1379
+ alt,
1380
+ loading: "lazy",
1381
+ decoding: "async",
1382
+ "data-mid": mediaId || null
1383
+ }
1384
+ ];
1385
+ let anchor = img;
1386
+ if (link) {
1387
+ anchor = [
1388
+ "a",
1389
+ {
1390
+ href: link,
1391
+ ...target ? {
1392
+ target,
1393
+ rel: "noopener noreferrer"
1394
+ } : {}
1395
+ },
1396
+ img
1397
+ ];
1398
+ } else if (shouldUseLightbox) {
1399
+ anchor = [
1400
+ "a",
1401
+ {
1402
+ href: src
1403
+ },
1404
+ img
1405
+ ];
1406
+ }
1407
+ const figureChildren = [anchor];
1408
+ if (caption) {
1409
+ figureChildren.push([
1410
+ "figcaption",
1411
+ {
1412
+ class: "caption"
1413
+ },
1414
+ caption
1415
+ ]);
1416
+ }
1417
+ return [
1418
+ "div",
1419
+ {
1420
+ class: `media-image-block align-${align}`,
1421
+ "data-type": this.name,
1422
+ "data-align": align,
1423
+ "data-link": link || null,
1424
+ "data-width": displayWidth,
1425
+ "data-eid": eid,
1426
+ "data-no-lightbox": shouldUseLightbox ? "false" : "true"
1427
+ },
1428
+ [
1429
+ "figure",
1430
+ {
1431
+ id,
1432
+ class: className,
1433
+ style: `max-width: ${displayWidth};`
1434
+ },
1435
+ ...figureChildren
1436
+ ]
1437
+ ];
1438
+ },
1439
+ addCommands() {
1440
+ const defaultNoLightbox = () => this.options.getImageDefaultLightbox() ? "false" : "true";
1441
+ return {
1442
+ setImageBlock: (attrs) => ({ commands }) => commands.insertContent({ type: "imageBlock", attrs: { src: attrs.src, noLightbox: defaultNoLightbox() } }),
1443
+ setImageBlockAt: (attrs) => ({ commands }) => commands.insertContentAt(attrs.pos, {
1444
+ type: "imageBlock",
1445
+ attrs: { src: attrs.src, noLightbox: defaultNoLightbox() }
1446
+ }),
1447
+ setImageBlockAlign: (align) => ({ commands }) => commands.updateAttributes("imageBlock", { align }),
1448
+ setImageBlockWidth: (width) => ({ commands }) => commands.updateAttributes("imageBlock", { displayWidth: width }),
1449
+ setImageBlockLink: (link, openInNewTab = false) => ({ commands }) => commands.updateAttributes("imageBlock", { link, target: openInNewTab ? "_blank" : null }),
1450
+ setImageBlockCaption: (caption) => ({ commands }) => commands.updateAttributes("imageBlock", { caption }),
1451
+ setImageBlockAlt: (alt) => ({ commands }) => commands.updateAttributes("imageBlock", { alt }),
1452
+ setMediaImageBlock: (mediaItem, className) => ({ commands }) => commands.insertContent({
1453
+ type: "imageBlock",
1454
+ attrs: { ...createImageBlockAttrs(mediaItem, className), noLightbox: defaultNoLightbox() }
1455
+ }),
1456
+ updateMediaImageBlock: (mediaItem) => ({ commands }) => commands.updateAttributes("imageBlock", createImageBlockAttrs(mediaItem)),
1457
+ updateAllMediaImageBlocks: (mediaItem) => ({ state, dispatch }) => {
1458
+ if (!dispatch) return false;
1459
+ const newAttrs = createImageBlockAttrs(mediaItem);
1460
+ const targetMediaId = mediaItem.media_id;
1461
+ const positions = [];
1462
+ state.doc.descendants((node, pos) => {
1463
+ if (node.type.name === "imageBlock") {
1464
+ const nodeMediaId = typeof node.attrs.mediaId === "string" ? parseInt(node.attrs.mediaId, 10) : node.attrs.mediaId;
1465
+ if (nodeMediaId === targetMediaId) {
1466
+ positions.push(pos);
1467
+ }
1468
+ }
1469
+ });
1470
+ if (positions.length > 0) {
1471
+ const { tr } = state;
1472
+ positions.forEach((pos) => {
1473
+ const node = state.doc.nodeAt(pos);
1474
+ if (node && node.type.name === "imageBlock") {
1475
+ tr.setNodeMarkup(pos, void 0, { ...node.attrs, ...newAttrs });
1476
+ }
1477
+ });
1478
+ dispatch(tr);
1479
+ return true;
1480
+ }
1481
+ return false;
1482
+ },
1483
+ toggleImageBlockLightbox: () => ({ editor, commands }) => {
1484
+ const { noLightbox } = editor.getAttributes("imageBlock");
1485
+ return commands.updateAttributes("imageBlock", {
1486
+ noLightbox: noLightbox === "true" ? "false" : "true"
1487
+ });
1488
+ }
1489
+ };
1490
+ },
1491
+ addNodeView() {
1492
+ return ReactNodeViewRenderer(ImageBlockView);
1493
+ }
1494
+ });
1495
+
1496
+ // src/extensions/FileBlock/FileBlock.ts
1497
+ import { ReactNodeViewRenderer as ReactNodeViewRenderer2 } from "@tiptap/react";
1498
+
1499
+ // src/extensions/FileBlock/components/FileBlockView.tsx
1500
+ import { useCallback as useCallback3, useEffect as useEffect3, useRef as useRef3 } from "react";
1501
+ import { NodeViewWrapper as NodeViewWrapper2 } from "@tiptap/react";
1502
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1503
+ function FileBlockView(props) {
1504
+ const { editor, getPos, node } = props;
1505
+ const fileWrapperRef = useRef3(null);
1506
+ const {
1507
+ displayType,
1508
+ href,
1509
+ target,
1510
+ icon,
1511
+ iconWidth,
1512
+ iconHeight,
1513
+ extension,
1514
+ fileSize,
1515
+ mediaId,
1516
+ alt,
1517
+ caption,
1518
+ align,
1519
+ id
1520
+ } = node.attrs;
1521
+ const cleanedClassNames = String(node.attrs.class ?? "").split(/\s+/).filter((cls) => !["align-left", "align-center", "align-right"].includes(cls)).join(" ").trim();
1522
+ const wrapperClassName = cn("media-file-block", `align-${align || "left"}`, cleanedClassNames);
1523
+ const onClick = useCallback3(
1524
+ (event) => {
1525
+ event.preventDefault();
1526
+ const pos = getPos();
1527
+ if (pos === void 0) return;
1528
+ editor.commands.setNodeSelection(pos);
1529
+ },
1530
+ [getPos, editor.commands]
1531
+ );
1532
+ useEffect3(() => {
1533
+ const listener = (event) => {
1534
+ if (!(event instanceof CustomEvent)) {
1535
+ return;
1536
+ }
1537
+ const media = event.detail.data;
1538
+ if (parseInt(mediaId, 10) === media.media_id) {
1539
+ editor.chain().updateAllMediaFileBlocks(media).run();
1540
+ }
1541
+ };
1542
+ document.addEventListener("acms.media-updated", listener);
1543
+ return () => {
1544
+ document.removeEventListener("acms.media-updated", listener);
1545
+ };
1546
+ }, [mediaId, editor]);
1547
+ return /* @__PURE__ */ jsx3(
1548
+ NodeViewWrapper2,
1549
+ {
1550
+ contentEditable: false,
1551
+ "data-type": "fileBlock",
1552
+ id,
1553
+ className: wrapperClassName,
1554
+ "data-display-type": displayType || "icon",
1555
+ "data-icon": icon || "",
1556
+ "data-icon-width": iconWidth || "100",
1557
+ "data-icon-height": iconHeight || "100",
1558
+ "data-alt": alt ?? void 0,
1559
+ "data-caption": caption ?? void 0,
1560
+ "data-align": align || "left",
1561
+ "data-mid": mediaId ?? void 0,
1562
+ "data-extension": extension ?? void 0,
1563
+ "data-file-size": fileSize ?? void 0,
1564
+ children: /* @__PURE__ */ jsx3("div", { className: "acms-admin-block-editor-file", contentEditable: false, ref: fileWrapperRef, children: displayType === "button" ? /* @__PURE__ */ jsxs2(
1565
+ "a",
1566
+ {
1567
+ href,
1568
+ target: target || void 0,
1569
+ rel: target ? "noopener noreferrer" : void 0,
1570
+ onClick,
1571
+ children: [
1572
+ /* @__PURE__ */ jsx3(
1573
+ "img",
1574
+ {
1575
+ src: icon,
1576
+ width: iconWidth,
1577
+ height: iconHeight,
1578
+ alt: alt || "",
1579
+ loading: "lazy",
1580
+ decoding: "async",
1581
+ draggable: false
1582
+ }
1583
+ ),
1584
+ /* @__PURE__ */ jsx3("p", { className: "caption", children: caption || "" })
1585
+ ]
1586
+ }
1587
+ ) : /* @__PURE__ */ jsxs2(Fragment, { children: [
1588
+ /* @__PURE__ */ jsx3(
1589
+ "a",
1590
+ {
1591
+ href,
1592
+ target: target || void 0,
1593
+ rel: target ? "noopener noreferrer" : void 0,
1594
+ onClick,
1595
+ children: /* @__PURE__ */ jsx3(
1596
+ "img",
1597
+ {
1598
+ src: icon,
1599
+ width: iconWidth,
1600
+ height: iconHeight,
1601
+ alt: alt || "",
1602
+ loading: "lazy",
1603
+ decoding: "async",
1604
+ draggable: false
1605
+ }
1606
+ )
1607
+ }
1608
+ ),
1609
+ caption && /* @__PURE__ */ jsx3("p", { className: "caption", children: caption })
1610
+ ] }) })
1611
+ }
1612
+ );
1613
+ }
1614
+
1615
+ // src/extensions/FileBlock/FileBlock.ts
1616
+ var FileBlock = ImageBlock.extend({
1617
+ name: "fileBlock",
1618
+ group: "block",
1619
+ atom: true,
1620
+ defining: true,
1621
+ isolating: true,
1622
+ addAttributes() {
1623
+ return {
1624
+ displayType: {
1625
+ default: "icon",
1626
+ renderHTML: (attrs) => ({
1627
+ "data-display-type": attrs.displayType || "icon"
1628
+ })
1629
+ },
1630
+ href: {
1631
+ default: "",
1632
+ renderHTML: (attrs) => ({
1633
+ "data-href": attrs.href || ""
1634
+ })
1635
+ },
1636
+ icon: {
1637
+ default: "",
1638
+ renderHTML: (attrs) => ({
1639
+ "data-icon": attrs.icon || ""
1640
+ })
1641
+ },
1642
+ iconWidth: {
1643
+ default: "",
1644
+ renderHTML: (attrs) => ({
1645
+ "data-icon-width": attrs.iconWidth || ""
1646
+ })
1647
+ },
1648
+ iconHeight: {
1649
+ default: "",
1650
+ renderHTML: (attrs) => ({
1651
+ "data-icon-height": attrs.iconHeight || ""
1652
+ })
1653
+ },
1654
+ extension: {
1655
+ default: null,
1656
+ renderHTML: (attrs) => ({
1657
+ "data-extension": attrs.extension ?? null
1658
+ })
1659
+ },
1660
+ fileSize: {
1661
+ default: null,
1662
+ renderHTML: (attrs) => ({
1663
+ "data-file-size": attrs.fileSize ?? null
1664
+ })
1665
+ },
1666
+ align: {
1667
+ default: "left",
1668
+ renderHTML: (attrs) => ({
1669
+ "data-align": attrs.align ?? "left"
1670
+ })
1671
+ },
1672
+ target: {
1673
+ default: null,
1674
+ renderHTML: (attrs) => ({
1675
+ "data-target": attrs.target ?? null
1676
+ })
1677
+ },
1678
+ caption: {
1679
+ default: null,
1680
+ renderHTML: (attrs) => ({
1681
+ "data-caption": attrs.caption ?? ""
1682
+ })
1683
+ },
1684
+ alt: {
1685
+ default: null,
1686
+ renderHTML: (attrs) => ({
1687
+ "data-alt": attrs.alt ?? ""
1688
+ })
1689
+ },
1690
+ mediaId: {
1691
+ default: null,
1692
+ renderHTML: (attrs) => ({
1693
+ "data-mid": attrs.mediaId ?? null
1694
+ })
1695
+ }
1696
+ };
1697
+ },
1698
+ parseHTML() {
1699
+ return [
1700
+ {
1701
+ tag: `div[data-type="${this.name}"]`,
1702
+ getAttrs: (element) => {
1703
+ const link = element.querySelector("a");
1704
+ return {
1705
+ displayType: element?.getAttribute("data-display-type") || "icon",
1706
+ href: link?.getAttribute("href"),
1707
+ icon: element?.getAttribute("data-icon") || "",
1708
+ iconWidth: element?.getAttribute("data-icon-width") || "100",
1709
+ iconHeight: element?.getAttribute("data-icon-height") || "100",
1710
+ extension: element?.getAttribute("data-extension") ?? null,
1711
+ fileSize: element?.getAttribute("data-file-size") ?? null,
1712
+ align: element?.getAttribute("data-align") || "center",
1713
+ target: link?.target || null,
1714
+ caption: element?.getAttribute("data-caption") || null,
1715
+ alt: element?.getAttribute("data-alt"),
1716
+ mediaId: element?.getAttribute("data-mid")
1717
+ };
1718
+ }
1719
+ }
1720
+ ];
1721
+ },
1722
+ renderHTML({ HTMLAttributes }) {
1723
+ const id = HTMLAttributes.id || null;
1724
+ const className = HTMLAttributes.class || "";
1725
+ const displayType = HTMLAttributes["data-display-type"] || "icon";
1726
+ const href = HTMLAttributes["data-href"] || "";
1727
+ const icon = HTMLAttributes["data-icon"] || "";
1728
+ const iconWidth = HTMLAttributes["data-icon-width"] || "100";
1729
+ const iconHeight = HTMLAttributes["data-icon-height"] || "100";
1730
+ const extension = HTMLAttributes["data-extension"] || null;
1731
+ const fileSize = HTMLAttributes["data-file-size"] || null;
1732
+ const align = HTMLAttributes["data-align"] || "left";
1733
+ const target = HTMLAttributes["data-target"] || null;
1734
+ const caption = HTMLAttributes["data-caption"] || null;
1735
+ const alt = HTMLAttributes["data-alt"] || null;
1736
+ const mediaId = HTMLAttributes["data-mid"] || null;
1737
+ const iconLink = [
1738
+ [
1739
+ "a",
1740
+ {
1741
+ href,
1742
+ ...target ? {
1743
+ target,
1744
+ rel: "noopener noreferrer"
1745
+ } : {}
1746
+ },
1747
+ [
1748
+ "img",
1749
+ {
1750
+ src: icon,
1751
+ width: iconWidth,
1752
+ height: iconHeight,
1753
+ alt: alt || "",
1754
+ loading: "lazy",
1755
+ decoding: "async"
1756
+ }
1757
+ ]
1758
+ ]
1759
+ ];
1760
+ if (caption) {
1761
+ iconLink.push(["p", { class: "caption" }, caption]);
1762
+ }
1763
+ const buttonLink = [
1764
+ [
1765
+ "a",
1766
+ {
1767
+ href,
1768
+ ...target ? {
1769
+ target,
1770
+ rel: "noopener noreferrer"
1771
+ } : {}
1772
+ },
1773
+ [
1774
+ "img",
1775
+ {
1776
+ src: icon,
1777
+ width: iconWidth,
1778
+ height: iconHeight,
1779
+ alt: alt || "",
1780
+ loading: "lazy",
1781
+ decoding: "async"
1782
+ }
1783
+ ],
1784
+ ["p", { class: "caption" }, caption || ""]
1785
+ ]
1786
+ ];
1787
+ const cleanedClassNames = className.split(/\s+/).filter((cls) => !["align-left", "align-center", "align-right"].includes(cls));
1788
+ const classList = /* @__PURE__ */ new Set(["media-file-block", `align-${align}`, ...cleanedClassNames]);
1789
+ const finalClass = Array.from(classList).join(" ");
1790
+ const html = displayType === "button" ? buttonLink : iconLink;
1791
+ return [
1792
+ "div",
1793
+ {
1794
+ id,
1795
+ class: finalClass,
1796
+ "data-type": this.name,
1797
+ "data-display-type": displayType,
1798
+ "data-icon": icon,
1799
+ "data-icon-width": iconWidth,
1800
+ "data-icon-height": iconHeight,
1801
+ "data-alt": alt,
1802
+ "data-caption": caption,
1803
+ "data-align": align,
1804
+ "data-mid": mediaId,
1805
+ "data-extension": extension,
1806
+ "data-file-size": fileSize
1807
+ },
1808
+ ["div", {}, ...html]
1809
+ ];
1810
+ },
1811
+ addCommands() {
1812
+ return {
1813
+ setFileBlock: (attrs) => ({ commands }) => commands.insertContent({ type: "fileBlock", attrs: { src: attrs.src } }),
1814
+ setFileBlockAt: (attrs) => ({ commands }) => commands.insertContentAt(attrs.pos, { type: "fileBlock", attrs: { src: attrs.src } }),
1815
+ setFileBlockDisplayType: (displayType) => ({ commands }) => commands.updateAttributes("fileBlock", { displayType }),
1816
+ setFileBlockAlign: (align) => ({ commands }) => commands.updateAttributes("fileBlock", { align }),
1817
+ setFileBlockCaption: (caption) => ({ commands }) => commands.updateAttributes("fileBlock", { caption }),
1818
+ setFileBlockAlt: (alt) => ({ commands }) => commands.updateAttributes("fileBlock", { alt }),
1819
+ setMediaFileBlock: (mediaItem, className) => ({ commands }) => commands.insertContent({
1820
+ type: "fileBlock",
1821
+ attrs: createFileBlockAttrs(mediaItem, className)
1822
+ }),
1823
+ updateMediaFileBlock: (mediaItem) => ({ commands }) => commands.updateAttributes("fileBlock", createFileBlockAttrs(mediaItem)),
1824
+ updateAllMediaFileBlocks: (mediaItem) => ({ state, dispatch }) => {
1825
+ if (!dispatch) return false;
1826
+ const newAttrs = createFileBlockAttrs(mediaItem);
1827
+ const targetMediaId = mediaItem.media_id;
1828
+ const positions = [];
1829
+ state.doc.descendants((node, pos) => {
1830
+ if (node.type.name === "fileBlock") {
1831
+ const nodeMediaId = typeof node.attrs.mediaId === "string" ? parseInt(node.attrs.mediaId, 10) : node.attrs.mediaId;
1832
+ if (nodeMediaId === targetMediaId) {
1833
+ positions.push(pos);
1834
+ }
1835
+ }
1836
+ });
1837
+ if (positions.length > 0) {
1838
+ const { tr } = state;
1839
+ positions.forEach((pos) => {
1840
+ const node = state.doc.nodeAt(pos);
1841
+ if (node && node.type.name === "fileBlock") {
1842
+ tr.setNodeMarkup(pos, void 0, { ...node.attrs, ...newAttrs });
1843
+ }
1844
+ });
1845
+ dispatch(tr);
1846
+ return true;
1847
+ }
1848
+ return false;
1849
+ },
1850
+ toggleFileBlockTarget: () => ({ commands }) => {
1851
+ const { target } = this.editor.getAttributes("fileBlock");
1852
+ const newTarget = target === "_blank" ? null : "_blank";
1853
+ return commands.updateAttributes("fileBlock", { target: newTarget });
1854
+ }
1855
+ };
1856
+ },
1857
+ addNodeView() {
1858
+ return ReactNodeViewRenderer2(FileBlockView);
1859
+ }
1860
+ });
1861
+
1862
+ // src/extensions/PasteHandler/PasteHandler.ts
1863
+ import { Extension as Extension5 } from "@tiptap/core";
1864
+ import { Plugin as Plugin6 } from "@tiptap/pm/state";
1865
+ import { DOMParser as PMDOMParser } from "@tiptap/pm/model";
1866
+ import { fetchClient } from "@ablogcms/fetch-client";
1867
+ async function convertImgSrcToRelative(img) {
1868
+ const src = img.getAttribute("src");
1869
+ if (!src || !/^https?:\/\//i.test(src)) {
1870
+ return;
1871
+ }
1872
+ try {
1873
+ const root = ACMS.Config.root.replace(/\/$/, "");
1874
+ const url = new URL(src);
1875
+ const relativePath = url.pathname;
1876
+ const checkUrl = `${location.origin}${root}${relativePath}`;
1877
+ const res = await fetch(checkUrl, { method: "HEAD" });
1878
+ if (res.ok) {
1879
+ img.setAttribute("src", `${root}${relativePath}`);
1880
+ }
1881
+ } catch (e) {
1882
+ console.warn("\u30DA\u30FC\u30B9\u30C8\u753B\u50CF\u306EURL\u5909\u63DB\u51E6\u7406\u306B\u5931\u6557\u3057\u307E\u3057\u305F:", e);
1883
+ }
1884
+ }
1885
+ async function fetchMediaItem(mediaId) {
1886
+ const endpoint = ACMS.Library.acmsLink({
1887
+ tpl: "ajax/edit/media-edit.json",
1888
+ bid: ACMS.Config.bid,
1889
+ searchParams: { _mid: mediaId }
1890
+ });
1891
+ try {
1892
+ const res = await fetchClient.get(
1893
+ endpoint
1894
+ );
1895
+ return res.data.status === "success" ? res.data.item : null;
1896
+ } catch {
1897
+ return null;
1898
+ }
1899
+ }
1900
+ function stripResizePrefix(imgPath) {
1901
+ const lastSlash = imgPath.lastIndexOf("/");
1902
+ const dir = lastSlash >= 0 ? imgPath.slice(0, lastSlash + 1) : "";
1903
+ const basename = lastSlash >= 0 ? imgPath.slice(lastSlash + 1) : imgPath;
1904
+ const match = basename.match(/^mode\d+_[^-]*-(.+)$/);
1905
+ if (!match) return imgPath;
1906
+ return dir + match[1];
1907
+ }
1908
+ async function checkImgMediaExists(img) {
1909
+ const mediaId = img.getAttribute("data-mid");
1910
+ if (!mediaId) {
1911
+ return null;
1912
+ }
1913
+ const item = await fetchMediaItem(parseInt(mediaId, 10));
1914
+ if (!item) {
1915
+ return null;
1916
+ }
1917
+ const mediaPath = item.media_root_path.split("?")[0];
1918
+ const imgPath = (img.getAttribute("src") ?? "").split("?")[0];
1919
+ if (mediaPath === imgPath || mediaPath === stripResizePrefix(imgPath)) {
1920
+ return item;
1921
+ }
1922
+ return null;
1923
+ }
1924
+ async function checkFileMediaExists(el) {
1925
+ const mediaId = el.getAttribute("data-mid");
1926
+ if (!mediaId) {
1927
+ return false;
1928
+ }
1929
+ const item = await fetchMediaItem(parseInt(mediaId, 10));
1930
+ if (!item) {
1931
+ return false;
1932
+ }
1933
+ const permalink = item.media_permalink.split("?")[0];
1934
+ const link = el.querySelector("a");
1935
+ if (link === null) {
1936
+ return false;
1937
+ }
1938
+ const href = (link.getAttribute("href") ?? "").split("?")[0];
1939
+ if (permalink !== href) {
1940
+ return false;
1941
+ }
1942
+ return true;
1943
+ }
1944
+ var pastePlugin = (editor) => new Plugin6({
1945
+ props: {
1946
+ handlePaste(view, event) {
1947
+ const html = event.clipboardData?.getData("text/html");
1948
+ if (!html) {
1949
+ return false;
1950
+ }
1951
+ const parser = new DOMParser();
1952
+ const doc = parser.parseFromString(html, "text/html");
1953
+ const fileBlocks = Array.from(doc.querySelectorAll('div[data-type="fileBlock"]'));
1954
+ const imgs = Array.from(doc.querySelectorAll("img"));
1955
+ if (fileBlocks.length === 0 && imgs.length === 0) {
1956
+ return false;
1957
+ }
1958
+ const fileBlockChecks = fileBlocks.map(async (el) => {
1959
+ if (el.hasAttribute("data-mid")) {
1960
+ const mediaExists = await checkFileMediaExists(el);
1961
+ if (!mediaExists) {
1962
+ el.removeAttribute("data-mid");
1963
+ }
1964
+ }
1965
+ });
1966
+ const standaloneImgs = imgs.filter((img) => !img.closest('div[data-type="fileBlock"]'));
1967
+ const imgChecks = standaloneImgs.map(async (img) => {
1968
+ await convertImgSrcToRelative(img);
1969
+ if (img.hasAttribute("data-mid")) {
1970
+ const mediaItem = await checkImgMediaExists(img);
1971
+ if (mediaItem !== null) {
1972
+ img.setAttribute("src", mediaItem.media_root_path);
1973
+ } else {
1974
+ img.removeAttribute("data-mid");
1975
+ }
1976
+ }
1977
+ });
1978
+ Promise.all([...fileBlockChecks, ...imgChecks]).then(() => {
1979
+ const slice = PMDOMParser.fromSchema(editor.schema).parseSlice(doc.body);
1980
+ const transaction = view.state.tr.replaceSelection(slice);
1981
+ view.dispatch(transaction);
1982
+ });
1983
+ return true;
1984
+ }
1985
+ }
1986
+ });
1987
+ var PasteHandler = Extension5.create({
1988
+ name: "pasteHandler",
1989
+ addProseMirrorPlugins() {
1990
+ return [pastePlugin(this.editor)];
1991
+ }
1992
+ });
1993
+
1994
+ // src/extensions/LinkButton/LinkButton.ts
1995
+ import { ReactNodeViewRenderer as ReactNodeViewRenderer3 } from "@tiptap/react";
1996
+ import { Selection as Selection2 } from "@tiptap/pm/state";
1997
+
1998
+ // src/extensions/LinkButton/components/LinkButtonView.tsx
1999
+ import { NodeViewWrapper as NodeViewWrapper3, NodeViewContent } from "@tiptap/react";
2000
+ import { jsx as jsx4 } from "react/jsx-runtime";
2001
+ var SpanNodeViewContent = NodeViewContent;
2002
+ function LinkButtonView(props) {
2003
+ const { node } = props;
2004
+ const { href, align, target } = node.attrs;
2005
+ const cleanedClassNames = String(node.attrs.class ?? "").split(/\s+/).filter((cls) => !["align-left", "align-center", "align-right"].includes(cls)).join(" ").trim();
2006
+ const wrapperClassName = cn(
2007
+ "link-button-block",
2008
+ "acms-admin-block-editor-link-button",
2009
+ // 3.2.0 ~ 3.2.7 互換性のために残しておく
2010
+ `align-${align || "center"}`,
2011
+ cleanedClassNames
2012
+ );
2013
+ const showPlaceholder = node.content.size === 0;
2014
+ const justifyContentMap = {
2015
+ left: "flex-start",
2016
+ center: "center",
2017
+ right: "flex-end"
2018
+ };
2019
+ const wrapperStyle = {
2020
+ display: "flex",
2021
+ justifyContent: justifyContentMap[align || "center"]
2022
+ };
2023
+ return /* @__PURE__ */ jsx4(
2024
+ NodeViewWrapper3,
2025
+ {
2026
+ className: wrapperClassName,
2027
+ style: wrapperStyle,
2028
+ "data-type": "linkButton",
2029
+ "data-align": align || "center",
2030
+ children: /* @__PURE__ */ jsx4(
2031
+ "a",
2032
+ {
2033
+ href: href || "",
2034
+ className: "link-button-block-link acms-admin-block-editor-link-button-link",
2035
+ "data-type": "button",
2036
+ target: target || void 0,
2037
+ rel: target ? "noopener noreferrer" : void 0,
2038
+ children: /* @__PURE__ */ jsx4(
2039
+ SpanNodeViewContent,
2040
+ {
2041
+ as: "span",
2042
+ style: showPlaceholder ? { minWidth: "1px" } : void 0,
2043
+ className: showPlaceholder ? "is-empty" : void 0
2044
+ }
2045
+ )
2046
+ }
2047
+ )
2048
+ }
2049
+ );
2050
+ }
2051
+
2052
+ // src/extensions/LinkButton/LinkButton.ts
2053
+ var LinkButton = ImageBlock.extend({
2054
+ name: "linkButton",
2055
+ group: "block",
2056
+ content: "inline*",
2057
+ atom: false,
2058
+ selectable: true,
2059
+ defining: true,
2060
+ isolating: true,
2061
+ addAttributes() {
2062
+ return {
2063
+ href: {
2064
+ default: "",
2065
+ renderHTML: (attrs) => ({
2066
+ "data-href": attrs.href || ""
2067
+ })
2068
+ },
2069
+ align: {
2070
+ default: "center",
2071
+ renderHTML: (attrs) => ({
2072
+ "data-align": attrs.align ?? "center"
2073
+ })
2074
+ },
2075
+ target: {
2076
+ default: null,
2077
+ renderHTML: (attrs) => ({
2078
+ "data-target": attrs.target ?? null
2079
+ })
2080
+ }
2081
+ };
2082
+ },
2083
+ parseHTML() {
2084
+ return [
2085
+ {
2086
+ tag: `div[data-type="${this.name}"]`,
2087
+ getAttrs: (element) => {
2088
+ const link = element.querySelector("a");
2089
+ return {
2090
+ href: link?.getAttribute("href"),
2091
+ align: element?.getAttribute("data-align") || "center",
2092
+ target: link?.target || null
2093
+ };
2094
+ }
2095
+ }
2096
+ ];
2097
+ },
2098
+ renderHTML({ HTMLAttributes }) {
2099
+ const id = HTMLAttributes.id || null;
2100
+ const className = HTMLAttributes.class || "";
2101
+ const href = HTMLAttributes["data-href"] || "";
2102
+ const align = HTMLAttributes["data-align"] || "center";
2103
+ const target = HTMLAttributes["data-target"] || null;
2104
+ const linkButton = [
2105
+ "a",
2106
+ {
2107
+ href,
2108
+ class: "link-button-block-link",
2109
+ "data-type": "button",
2110
+ ...target ? {
2111
+ target,
2112
+ rel: "noopener noreferrer"
2113
+ } : {}
2114
+ },
2115
+ 0
2116
+ ];
2117
+ const cleanedClassNames = className.split(/\s+/).filter((cls) => !["align-left", "align-center", "align-right"].includes(cls));
2118
+ const classList = /* @__PURE__ */ new Set(["link-button-block", `align-${align}`, ...cleanedClassNames]);
2119
+ const finalClass = Array.from(classList).join(" ");
2120
+ return [
2121
+ "div",
2122
+ {
2123
+ id,
2124
+ class: finalClass,
2125
+ "data-type": this.name,
2126
+ "data-align": align
2127
+ },
2128
+ linkButton
2129
+ ];
2130
+ },
2131
+ addCommands() {
2132
+ return {
2133
+ setLinkButtonBlock: () => ({ commands }) => commands.insertContent({ type: "linkButton" }),
2134
+ setLinkButtonBlockAt: (attrs) => ({ commands }) => commands.insertContentAt(attrs.pos, { type: "linkButton" }),
2135
+ setLinkButtonBlockAlign: (align) => ({ commands }) => commands.updateAttributes("linkButton", { align }),
2136
+ setLinkButtonBlockLink: (link, openInNewTab = false) => ({ commands }) => commands.updateAttributes("linkButton", { href: link, target: openInNewTab ? "_blank" : null })
2137
+ };
2138
+ },
2139
+ addKeyboardShortcuts() {
2140
+ return {
2141
+ Enter: ({ editor }) => {
2142
+ const { state, dispatch } = editor.view;
2143
+ const { tr, selection } = state;
2144
+ const { $from } = selection;
2145
+ for (let { depth } = $from; depth >= 0; depth--) {
2146
+ const node = $from.node(depth);
2147
+ if (node.type.name === "linkButton") {
2148
+ const pos = $from.after(depth);
2149
+ const paragraph = editor.schema.nodes.paragraph.create();
2150
+ tr.insert(pos, paragraph);
2151
+ const resolvedPos = tr.doc.resolve(pos);
2152
+ const newSelection = Selection2.near(resolvedPos);
2153
+ tr.setSelection(newSelection).scrollIntoView();
2154
+ dispatch(tr);
2155
+ return true;
2156
+ }
2157
+ }
2158
+ return false;
2159
+ },
2160
+ Backspace: ({ editor }) => {
2161
+ const { state, dispatch } = editor.view;
2162
+ const { selection } = state;
2163
+ const { $from } = selection;
2164
+ for (let { depth } = $from; depth >= 0; depth--) {
2165
+ const node = $from.node(depth);
2166
+ if (node.type.name === "linkButton") {
2167
+ const pos = $from.before(depth);
2168
+ const isEmpty = node.content.size === 0;
2169
+ const isAtStart = $from.pos === pos + 1;
2170
+ if (isEmpty && isAtStart) {
2171
+ const tr = state.tr.delete(pos, pos + node.nodeSize);
2172
+ dispatch(tr.scrollIntoView());
2173
+ return true;
2174
+ }
2175
+ }
2176
+ }
2177
+ return false;
2178
+ }
2179
+ };
2180
+ },
2181
+ addNodeView() {
2182
+ return ReactNodeViewRenderer3(LinkButtonView);
2183
+ }
2184
+ });
2185
+
2186
+ // src/extensions/MultiColumn/Column.ts
2187
+ import { Node as Node3, mergeAttributes as mergeAttributes6 } from "@tiptap/core";
2188
+ var Column = Node3.create({
2189
+ name: "column",
2190
+ content: "block+",
2191
+ isolating: true,
2192
+ addAttributes() {
2193
+ return {
2194
+ position: {
2195
+ default: "",
2196
+ parseHTML: (element) => element.getAttribute("data-position"),
2197
+ renderHTML: (attributes) => ({ "data-position": attributes.position })
2198
+ }
2199
+ };
2200
+ },
2201
+ renderHTML({ HTMLAttributes }) {
2202
+ return ["div", mergeAttributes6(HTMLAttributes, { "data-type": "column" }), 0];
2203
+ },
2204
+ parseHTML() {
2205
+ return [
2206
+ {
2207
+ tag: 'div[data-type="column"]'
2208
+ }
2209
+ ];
2210
+ }
2211
+ });
2212
+
2213
+ // src/extensions/MediaUpload/MediaUpload.ts
2214
+ import { Node as Node4, ReactNodeViewRenderer as ReactNodeViewRenderer4 } from "@tiptap/react";
2215
+ import { Plugin as Plugin7 } from "@tiptap/pm/state";
2216
+
2217
+ // src/extensions/MediaUpload/view/Dropzone.tsx
2218
+ import { useCallback as useCallback5, useEffect as useEffect4, useMemo } from "react";
2219
+ import { NodeViewWrapper as NodeViewWrapper4 } from "@tiptap/react";
2220
+ import MediaInsert from "@ablogcms/media/components/media-insert/media-insert";
2221
+ import { ButtonV2 as Button } from "@ablogcms/components/button-v2";
2222
+ import { DropZone } from "@ablogcms/components/drop-zone";
2223
+
2224
+ // src/extensions/MediaUpload/view/hooks.ts
2225
+ import { useState as useState2, useCallback as useCallback4, useRef as useRef4 } from "react";
2226
+ var useMediaSelect = () => {
2227
+ const [dropAreaState, setDropAreaState] = useState2({
2228
+ isInsertModalOpen: false,
2229
+ files: [],
2230
+ tab: "upload"
2231
+ });
2232
+ const uploadFile = useCallback4((files) => {
2233
+ setDropAreaState((prevState) => ({
2234
+ ...prevState,
2235
+ isInsertModalOpen: true,
2236
+ files,
2237
+ tab: "upload"
2238
+ }));
2239
+ }, []);
2240
+ const handleModalClose = () => {
2241
+ setDropAreaState((prevState) => ({
2242
+ ...prevState,
2243
+ isInsertModalOpen: false
2244
+ }));
2245
+ };
2246
+ const handleSelectClick = useCallback4(() => {
2247
+ setDropAreaState((prevState) => ({
2248
+ ...prevState,
2249
+ isInsertModalOpen: true,
2250
+ files: [],
2251
+ tab: "select"
2252
+ }));
2253
+ }, []);
2254
+ return {
2255
+ isInsertModalOpen: dropAreaState.isInsertModalOpen,
2256
+ files: dropAreaState.files,
2257
+ tab: dropAreaState.tab,
2258
+ uploadFile,
2259
+ handleModalClose,
2260
+ handleSelectClick
2261
+ };
2262
+ };
2263
+ var useFileUpload = ({ uploader }) => {
2264
+ const fileInputRef = useRef4(null);
2265
+ const handleUploadClick = useCallback4(() => {
2266
+ fileInputRef.current?.click();
2267
+ }, []);
2268
+ const handleUploadFile = (e) => {
2269
+ const { files } = e.target;
2270
+ if (files && files instanceof FileList) {
2271
+ uploader(Array.from(files));
2272
+ }
2273
+ };
2274
+ return { fileInputRef, handleUploadClick, handleUploadFile };
2275
+ };
2276
+ var useDropZone = ({ uploader }) => {
2277
+ const onDrop = (files) => {
2278
+ uploader(files.map((item) => item.file));
2279
+ };
2280
+ return { onDrop };
2281
+ };
2282
+
2283
+ // src/extensions/MediaUpload/view/insertMediaBlocks.ts
2284
+ var isImageMedia = (item) => item.media_type === "image" || item.media_type === "svg";
2285
+ var selectInsertableMedia = (items, accept) => items.filter((item) => {
2286
+ if (accept === "image") {
2287
+ return isImageMedia(item) && Boolean(item.media_thumbnail);
2288
+ }
2289
+ if (accept === "file") {
2290
+ return !isImageMedia(item);
2291
+ }
2292
+ return isImageMedia(item) ? Boolean(item.media_thumbnail) : true;
2293
+ });
2294
+ var getImageDefaultNoLightbox = (editor) => {
2295
+ const extension = editor.extensionManager.extensions.find((ext) => ext.name === "imageBlock");
2296
+ const getter = extension?.options?.getImageDefaultLightbox;
2297
+ return typeof getter === "function" && getter() ? "false" : "true";
2298
+ };
2299
+ var insertMediaBlocks = (editor, items, accept, className, range) => {
2300
+ const targets = selectInsertableMedia(items, accept);
2301
+ if (targets.length === 0) {
2302
+ return 0;
2303
+ }
2304
+ const noLightbox = getImageDefaultNoLightbox(editor);
2305
+ const contents = targets.map((item) => buildMediaBlockContent(item, className, noLightbox));
2306
+ editor.chain().insertContentAt(range, contents).focus().run();
2307
+ return targets.length;
2308
+ };
2309
+
2310
+ // src/extensions/MediaUpload/view/filterFilesByMediaType.ts
2311
+ import { isImageFile } from "@ablogcms/lib/read-files";
2312
+ var filterFilesByMediaType = (files, accept) => {
2313
+ if (accept === "image") {
2314
+ return files.filter((file) => isImageFile(file));
2315
+ }
2316
+ if (accept === "file") {
2317
+ return files.filter((file) => !isImageFile(file));
2318
+ }
2319
+ return [...files];
2320
+ };
2321
+
2322
+ // src/extensions/MediaUpload/view/Dropzone.tsx
2323
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
2324
+ function Dropzone({
2325
+ getPos,
2326
+ editor,
2327
+ node
2328
+ }) {
2329
+ const className = node?.attrs?.class || "";
2330
+ const { isInsertModalOpen, files, tab, uploadFile, handleModalClose, handleSelectClick } = useMediaSelect();
2331
+ const pastedFiles = useMemo(() => {
2332
+ return node.attrs.__pastedFiles || [];
2333
+ }, [node.attrs.__pastedFiles]);
2334
+ const mediaType = useMemo(() => {
2335
+ if (node.attrs.__mediaType === "file") return "file";
2336
+ if (node.attrs.__mediaType === "all") return "all";
2337
+ return "image";
2338
+ }, [node.attrs.__mediaType]);
2339
+ const acceptUpload = useCallback5(
2340
+ (uploadingFiles) => {
2341
+ const accepted = filterFilesByMediaType(uploadingFiles, mediaType);
2342
+ if (accepted.length > 0) {
2343
+ uploadFile(accepted);
2344
+ }
2345
+ },
2346
+ [mediaType, uploadFile]
2347
+ );
2348
+ const { fileInputRef, handleUploadClick, handleUploadFile } = useFileUpload({ uploader: acceptUpload });
2349
+ const { onDrop } = useDropZone({ uploader: acceptUpload });
2350
+ useEffect4(() => {
2351
+ if (pastedFiles.length > 0) {
2352
+ acceptUpload(pastedFiles);
2353
+ }
2354
+ }, [pastedFiles, acceptUpload]);
2355
+ const handleInsertMedia = useCallback5(
2356
+ (items) => {
2357
+ const from = getPos();
2358
+ if (from === void 0) return;
2359
+ const to = from + node.nodeSize;
2360
+ insertMediaBlocks(editor, items, mediaType, className, { from, to });
2361
+ handleModalClose();
2362
+ },
2363
+ [editor, mediaType, getPos, node, handleModalClose, className]
2364
+ );
2365
+ return /* @__PURE__ */ jsxs3(NodeViewWrapper4, { children: [
2366
+ pastedFiles.length === 0 && /* @__PURE__ */ jsx5(DropZone, { onComplete: onDrop, children: /* @__PURE__ */ jsxs3("div", { className: "acms-admin-block-editor-image-drop", style: { width: "100%" }, children: [
2367
+ /* @__PURE__ */ jsxs3("p", { className: "acms-admin-block-editor-image-drop-text", children: [
2368
+ mediaType === "image" && /* @__PURE__ */ jsx5("span", { className: "acms-admin-block-editor-image-drop-text-main", children: "\u3053\u3053\u306B\u753B\u50CF\u3092\u30C9\u30E9\u30C3\u30B0" }),
2369
+ mediaType === "file" && /* @__PURE__ */ jsx5("span", { className: "acms-admin-block-editor-image-drop-text-main", children: "\u3053\u3053\u306B\u30D5\u30A1\u30A4\u30EB\u3092\u30C9\u30E9\u30C3\u30B0" }),
2370
+ /* @__PURE__ */ jsx5("span", { className: "acms-admin-block-editor-image-drop-text-sub", children: "\u307E\u305F\u306F" })
2371
+ ] }),
2372
+ /* @__PURE__ */ jsxs3("div", { className: "acms-admin-block-editor-button-group", children: [
2373
+ /* @__PURE__ */ jsxs3(Button, { onClick: handleSelectClick, variant: "outlined", size: "default", type: "button", children: [
2374
+ /* @__PURE__ */ jsx5(Icon, { name: "perm_media" }),
2375
+ "\u30E1\u30C7\u30A3\u30A2\u9078\u629E"
2376
+ ] }),
2377
+ /* @__PURE__ */ jsxs3(Button, { onClick: handleUploadClick, variant: "filled", size: "default", type: "button", children: [
2378
+ /* @__PURE__ */ jsx5(Icon, { name: "upload" }),
2379
+ "\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9"
2380
+ ] })
2381
+ ] }),
2382
+ /* @__PURE__ */ jsx5(
2383
+ "input",
2384
+ {
2385
+ id: "media-upload-input",
2386
+ ref: fileInputRef,
2387
+ type: "file",
2388
+ multiple: true,
2389
+ accept: mediaType === "image" ? "image/*" : void 0,
2390
+ onChange: handleUploadFile,
2391
+ style: { display: "none" }
2392
+ }
2393
+ )
2394
+ ] }) }),
2395
+ /* @__PURE__ */ jsx5(
2396
+ MediaInsert,
2397
+ {
2398
+ isOpen: isInsertModalOpen,
2399
+ onInsert: handleInsertMedia,
2400
+ files,
2401
+ onClose: handleModalClose,
2402
+ tab,
2403
+ filetype: mediaType
2404
+ }
2405
+ )
2406
+ ] });
2407
+ }
2408
+
2409
+ // src/extensions/MediaUpload/MediaUpload.ts
2410
+ var imagePastePlugin = (editor) => new Plugin7({
2411
+ props: {
2412
+ handlePaste(view, event) {
2413
+ const files = event.clipboardData?.files;
2414
+ if (files && files.length > 0) {
2415
+ const images = Array.from(files).filter((file) => file.type.startsWith("image/"));
2416
+ if (images.length === 0) return false;
2417
+ event.preventDefault();
2418
+ editor.commands.uploadMediaImage(images);
2419
+ return true;
2420
+ }
2421
+ return false;
2422
+ }
2423
+ }
2424
+ });
2425
+ var mediaDropPlugin = (editor) => new Plugin7({
2426
+ props: {
2427
+ handleDrop(view, event) {
2428
+ const files = event.dataTransfer?.files;
2429
+ if (!files || files.length === 0) {
2430
+ return false;
2431
+ }
2432
+ const coordinates = view.posAtCoords({ left: event.clientX, top: event.clientY });
2433
+ if (!coordinates) {
2434
+ return false;
2435
+ }
2436
+ const $pos = view.state.doc.resolve(coordinates.pos);
2437
+ for (let { depth } = $pos; depth > 0; depth -= 1) {
2438
+ if ($pos.node(depth).type.name === "MediaUpload") {
2439
+ return false;
2440
+ }
2441
+ }
2442
+ event.preventDefault();
2443
+ editor.chain().focus().setTextSelection(coordinates.pos).uploadMedia(Array.from(files)).run();
2444
+ return true;
2445
+ }
2446
+ }
2447
+ });
2448
+ var MediaUpload = Node4.create({
2449
+ name: "MediaUpload",
2450
+ isolating: true,
2451
+ defining: true,
2452
+ group: "block",
2453
+ draggable: false,
2454
+ selectable: true,
2455
+ inline: false,
2456
+ addAttributes() {
2457
+ return {
2458
+ __pastedFiles: {
2459
+ default: [],
2460
+ parseHTML: () => [],
2461
+ renderHTML: () => null
2462
+ },
2463
+ __mediaType: {
2464
+ default: "image",
2465
+ // 'image' or 'file'
2466
+ parseHTML: (element) => element.getAttribute("data-media-type") || "image",
2467
+ renderHTML: (attrs) => ({ "data-media-type": attrs.__mediaType })
2468
+ }
2469
+ };
2470
+ },
2471
+ parseHTML() {
2472
+ return [
2473
+ {
2474
+ tag: `div[data-type="${this.name}"]`,
2475
+ getAttrs: () => ({})
2476
+ }
2477
+ ];
2478
+ },
2479
+ renderHTML({ HTMLAttributes }) {
2480
+ return ["div", { "data-type": this.name, ...HTMLAttributes }];
2481
+ },
2482
+ addCommands() {
2483
+ return {
2484
+ uploadMediaImage: (files) => ({ commands }) => commands.insertContent({
2485
+ type: this.name,
2486
+ attrs: {
2487
+ __pastedFiles: files ?? [],
2488
+ __mediaType: "image"
2489
+ }
2490
+ }),
2491
+ uploadMediaFile: (files) => ({ commands }) => commands.insertContent({
2492
+ type: this.name,
2493
+ attrs: {
2494
+ __pastedFiles: files ?? [],
2495
+ __mediaType: "file"
2496
+ }
2497
+ }),
2498
+ uploadMedia: (files) => ({ commands }) => commands.insertContent({
2499
+ type: this.name,
2500
+ attrs: {
2501
+ __pastedFiles: files ?? [],
2502
+ __mediaType: "all"
2503
+ }
2504
+ })
2505
+ };
2506
+ },
2507
+ addNodeView() {
2508
+ return ReactNodeViewRenderer4(Dropzone);
2509
+ },
2510
+ addProseMirrorPlugins() {
2511
+ return [imagePastePlugin(this.editor), mediaDropPlugin(this.editor)];
2512
+ }
2513
+ });
2514
+
2515
+ // src/extensions/CustomMark/CustomMark.ts
2516
+ import { Mark } from "@tiptap/core";
2517
+ var CustomMark = Mark.create({
2518
+ name: "customMark",
2519
+ // マークの名前
2520
+ // 属性の定義
2521
+ addAttributes() {
2522
+ return {
2523
+ class: {
2524
+ default: null,
2525
+ // デフォルトはnull
2526
+ parseHTML: (element) => element.getAttribute("class"),
2527
+ // HTMLからクラスを取得
2528
+ renderHTML: (attributes) => {
2529
+ if (!attributes.class) {
2530
+ return {};
2531
+ }
2532
+ return {
2533
+ class: attributes.class
2534
+ // HTMLにクラスを追加
2535
+ };
2536
+ }
2537
+ }
2538
+ };
2539
+ },
2540
+ // HTMLのパース処理
2541
+ parseHTML() {
2542
+ return [
2543
+ {
2544
+ tag: "span.custom-mark"
2545
+ // マークのHTMLタグを定義
2546
+ }
2547
+ ];
2548
+ },
2549
+ // HTMLのレンダリング処理
2550
+ renderHTML({ HTMLAttributes }) {
2551
+ return ["span", HTMLAttributes, 0];
2552
+ }
2553
+ });
2554
+
2555
+ // src/extensions/CustomConvertBlock/CustomConvertBlock.ts
2556
+ import { Extension as Extension6 } from "@tiptap/core";
2557
+ import { TextSelection } from "@tiptap/pm/state";
2558
+ var collectParagraphTexts = (node, paragraphType) => {
2559
+ const texts = [];
2560
+ if (node.type === paragraphType) {
2561
+ texts.push(node.textContent);
2562
+ }
2563
+ node.forEach((child) => {
2564
+ texts.push(...collectParagraphTexts(child, paragraphType));
2565
+ });
2566
+ return texts;
2567
+ };
2568
+ var CustomConvertBlock = Extension6.create({
2569
+ name: "CustomConvertBlock",
2570
+ addCommands() {
2571
+ return {
2572
+ removeList: (pos) => ({ state, dispatch }) => {
2573
+ const { doc, schema } = state;
2574
+ const { bulletList, orderedList, paragraph, hardBreak } = schema.nodes;
2575
+ const newParagraphs = [];
2576
+ const listNode = doc.nodeAt(pos);
2577
+ if (!listNode || listNode.type !== bulletList && listNode.type !== orderedList) {
2578
+ return false;
2579
+ }
2580
+ listNode.forEach((listItemNode) => {
2581
+ newParagraphs.push(...collectParagraphTexts(listItemNode, paragraph));
2582
+ });
2583
+ const textNodes = newParagraphs.flatMap((line, index, arr) => {
2584
+ const nodes = [schema.text(line)];
2585
+ if (index < arr.length - 1) {
2586
+ nodes.push(hardBreak.create());
2587
+ }
2588
+ return nodes;
2589
+ });
2590
+ const paragraphNode = paragraph.create({}, textNodes);
2591
+ const tr = state.tr.replaceWith(pos, pos + listNode.nodeSize, paragraphNode);
2592
+ if (dispatch && tr.docChanged) {
2593
+ dispatch(tr);
2594
+ return true;
2595
+ }
2596
+ return false;
2597
+ },
2598
+ removeListAsParagraphs: (pos) => ({ state, dispatch }) => {
2599
+ const { doc, schema } = state;
2600
+ const { bulletList, orderedList, paragraph } = schema.nodes;
2601
+ const listNode = doc.nodeAt(pos);
2602
+ if (!listNode || listNode.type !== bulletList && listNode.type !== orderedList) {
2603
+ return false;
2604
+ }
2605
+ const paragraphs = [];
2606
+ listNode.forEach((listItemNode) => {
2607
+ listItemNode.forEach((child) => {
2608
+ if (child.type === paragraph) {
2609
+ const text = child.textContent;
2610
+ const lines = text.split(/\r?\n/);
2611
+ lines.forEach((line) => {
2612
+ paragraphs.push(paragraph.create({}, schema.text(line)));
2613
+ });
2614
+ } else {
2615
+ paragraphs.push(child);
2616
+ }
2617
+ });
2618
+ });
2619
+ if (paragraphs.length === 0) {
2620
+ return false;
2621
+ }
2622
+ const tr = state.tr.replaceWith(pos, pos + listNode.nodeSize, paragraphs);
2623
+ if (dispatch && tr.docChanged) {
2624
+ dispatch(tr);
2625
+ return true;
2626
+ }
2627
+ return false;
2628
+ },
2629
+ unwrapList: () => ({ state, dispatch }) => {
2630
+ const { selection, tr } = state;
2631
+ const { $from } = selection;
2632
+ let lifted = false;
2633
+ for (let { depth } = $from; depth > 0; depth--) {
2634
+ const node = $from.node(depth);
2635
+ if (node.type.name === "listItem") {
2636
+ const pos = $from.before(depth);
2637
+ tr.setNodeMarkup(pos, state.schema.nodes.paragraph);
2638
+ lifted = true;
2639
+ break;
2640
+ }
2641
+ }
2642
+ if (lifted && dispatch) {
2643
+ dispatch(tr);
2644
+ return true;
2645
+ }
2646
+ return false;
2647
+ },
2648
+ removeBlockquote: (pos) => ({ state, dispatch }) => {
2649
+ const { doc, schema } = state;
2650
+ const { blockquote } = schema.nodes;
2651
+ const node = doc.nodeAt(pos);
2652
+ if (!node || node.type !== blockquote) {
2653
+ return false;
2654
+ }
2655
+ const { content } = node;
2656
+ const tr = state.tr.replaceWith(pos, pos + node.nodeSize, content);
2657
+ if (dispatch && tr.docChanged) {
2658
+ dispatch(tr);
2659
+ return true;
2660
+ }
2661
+ return false;
2662
+ },
2663
+ splitBulletList: (pos) => ({ state, dispatch }) => {
2664
+ const { doc, schema } = state;
2665
+ const { bulletList, listItem, paragraph, hardBreak } = schema.nodes;
2666
+ const node = doc.nodeAt(pos);
2667
+ if (!node || node.type !== paragraph) {
2668
+ return false;
2669
+ }
2670
+ const items = [[]];
2671
+ node.content.forEach((child) => {
2672
+ if (child.type === hardBreak) {
2673
+ items.push([]);
2674
+ } else {
2675
+ items[items.length - 1].push(child);
2676
+ }
2677
+ });
2678
+ const listItems = items.filter((content) => content.length > 0).map((content) => listItem.create({}, paragraph.create({}, content)));
2679
+ if (listItems.length === 0) {
2680
+ return false;
2681
+ }
2682
+ const newList = bulletList.create({}, listItems);
2683
+ const tr = state.tr.replaceWith(pos, pos + node.nodeSize, newList);
2684
+ const selection = TextSelection.near(tr.doc.resolve(pos + 1));
2685
+ if (dispatch && tr.docChanged) {
2686
+ dispatch(tr.setSelection(selection));
2687
+ return true;
2688
+ }
2689
+ return false;
2690
+ },
2691
+ splitOrderedList: (pos) => ({ state, dispatch }) => {
2692
+ const { doc, schema } = state;
2693
+ const { orderedList, listItem, paragraph, hardBreak } = schema.nodes;
2694
+ const node = doc.nodeAt(pos);
2695
+ if (!node || node.type !== paragraph) {
2696
+ return false;
2697
+ }
2698
+ const items = [[]];
2699
+ node.content.forEach((child) => {
2700
+ if (child.type === hardBreak) {
2701
+ items.push([]);
2702
+ } else {
2703
+ items[items.length - 1].push(child);
2704
+ }
2705
+ });
2706
+ const listItems = items.filter((content) => content.length > 0).map((content) => listItem.create({}, paragraph.create({}, content)));
2707
+ if (listItems.length === 0) {
2708
+ return false;
2709
+ }
2710
+ const newList = orderedList.create({}, listItems);
2711
+ const tr = state.tr.replaceWith(pos, pos + node.nodeSize, newList);
2712
+ const selection = TextSelection.near(tr.doc.resolve(pos + 1));
2713
+ if (dispatch && tr.docChanged) {
2714
+ dispatch(tr.setSelection(selection));
2715
+ return true;
2716
+ }
2717
+ return false;
2718
+ }
2719
+ };
2720
+ }
2721
+ });
2722
+
2723
+ // src/lib/utils/isCustomNodeSelected.ts
2724
+ var isTableGripSelected = (node) => {
2725
+ let container = node;
2726
+ while (container && !["TD", "TH"].includes(container.tagName)) {
2727
+ container = container.parentElement;
2728
+ }
2729
+ const gripColumn = container && container.querySelector && container.querySelector("button.grip-column.selected");
2730
+ const gripRow = container && container.querySelector && container.querySelector("button.grip-row.selected");
2731
+ if (gripColumn || gripRow) {
2732
+ return true;
2733
+ }
2734
+ return false;
2735
+ };
2736
+ var isCustomNodeSelected = (editor, node) => {
2737
+ const customNodes = [
2738
+ HorizontalRule.name,
2739
+ ImageBlock.name,
2740
+ MediaUpload.name,
2741
+ CodeBlock.name,
2742
+ ImageBlock.name,
2743
+ FileBlock.name,
2744
+ LinkButton.name,
2745
+ // Link.name,
2746
+ Figcaption.name
2747
+ ];
2748
+ return customNodes.some((type) => editor.isActive(type)) || isTableGripSelected(node);
2749
+ };
2750
+
2751
+ // src/lib/utils/isTextSelected.ts
2752
+ import { isTextSelection } from "@tiptap/core";
2753
+ var isTextSelected = ({ editor }) => {
2754
+ const {
2755
+ state: {
2756
+ doc,
2757
+ selection,
2758
+ selection: { empty, from, to }
2759
+ }
2760
+ } = editor;
2761
+ const isEmptyTextBlock = !doc.textBetween(from, to).length && isTextSelection(selection);
2762
+ if (empty || isEmptyTextBlock || !editor.isEditable) {
2763
+ return false;
2764
+ }
2765
+ return true;
2766
+ };
2767
+
2768
+ // src/lib/utils/index.ts
2769
+ function cn(...inputs) {
2770
+ return classnames(...inputs);
2771
+ }
2772
+
2773
+ export {
2774
+ Selection,
2775
+ Table,
2776
+ isCellSelection,
2777
+ TableCell,
2778
+ TableRow,
2779
+ TableHeader,
2780
+ HorizontalRule,
2781
+ Heading,
2782
+ Document,
2783
+ TrailingNode,
2784
+ SlashCommand_default,
2785
+ FontStyle,
2786
+ Figcaption,
2787
+ isAllowedBlockEditorLinkUri,
2788
+ Link,
2789
+ ImageBlock,
2790
+ FileBlock,
2791
+ PasteHandler,
2792
+ LinkButton,
2793
+ Column,
2794
+ useMediaSelect,
2795
+ MediaUpload,
2796
+ CustomMark,
2797
+ CustomConvertBlock,
2798
+ StarterKit,
2799
+ Highlight,
2800
+ Underline,
2801
+ TextAlign,
2802
+ TextStyle,
2803
+ Typography,
2804
+ Subscript,
2805
+ Superscript,
2806
+ Placeholder,
2807
+ Focus,
2808
+ Dropcursor,
2809
+ isCustomNodeSelected,
2810
+ isTextSelected,
2811
+ cn
2812
+ };
2813
+ //# sourceMappingURL=chunk-TKSGCO5Z.mjs.map