@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,3126 @@
1
+ import {
2
+ AlignPicker
3
+ } from "./chunk-OFWQRNO2.mjs";
4
+ import {
5
+ ColorButton
6
+ } from "./chunk-GIHTGDIW.mjs";
7
+ import {
8
+ Toolbar
9
+ } from "./chunk-HNSTT2Z4.mjs";
10
+ import {
11
+ Column,
12
+ CustomConvertBlock,
13
+ CustomMark,
14
+ Document,
15
+ Dropcursor,
16
+ Figcaption,
17
+ FileBlock,
18
+ Focus,
19
+ FontStyle,
20
+ Heading,
21
+ Highlight,
22
+ HorizontalRule,
23
+ ImageBlock,
24
+ Link,
25
+ LinkButton,
26
+ MediaUpload,
27
+ PasteHandler,
28
+ Placeholder,
29
+ Selection,
30
+ SlashCommand_default,
31
+ StarterKit,
32
+ Subscript,
33
+ Superscript,
34
+ Table,
35
+ TableCell,
36
+ TableHeader,
37
+ TableRow,
38
+ TextAlign,
39
+ TextStyle,
40
+ TrailingNode,
41
+ Typography,
42
+ Underline,
43
+ isAllowedBlockEditorLinkUri,
44
+ isCellSelection,
45
+ isCustomNodeSelected,
46
+ isTextSelected,
47
+ useMediaSelect
48
+ } from "./chunk-TKSGCO5Z.mjs";
49
+ import {
50
+ Icon
51
+ } from "./chunk-57Q3DEDF.mjs";
52
+ import {
53
+ SettingsProvider,
54
+ useSettingsContext
55
+ } from "./chunk-DUT25D7Z.mjs";
56
+ import {
57
+ DEFAULT_EDITOR_SETTINGS,
58
+ buildIdentifier
59
+ } from "./chunk-JYUNKG2P.mjs";
60
+ import {
61
+ blocks_default,
62
+ mergeBlockDefinitions
63
+ } from "./chunk-XGAKMQH4.mjs";
64
+ import {
65
+ Columns
66
+ } from "./chunk-OZG2BL6F.mjs";
67
+
68
+ // src/components/BlockEditor/BlockEditor.tsx
69
+ import { EditorContent } from "@tiptap/react";
70
+ import { useRef as useRef14 } from "react";
71
+ import { Slot } from "@ablogcms/components/slot-fill";
72
+ import { Tooltip } from "@ablogcms/components/tooltip";
73
+
74
+ // src/components/menus/LinkMenu/LinkMenu.tsx
75
+ import { BubbleMenu as BaseBubbleMenu } from "@tiptap/react/menus";
76
+ import { useCallback as useCallback3, useMemo as useMemo2, useState as useState3 } from "react";
77
+ import { Popover, PopoverContent } from "@ablogcms/components/popover";
78
+
79
+ // src/components/panels/LinkPreviewPanel/LinkPreviewPanel.tsx
80
+ import { jsx, jsxs } from "react/jsx-runtime";
81
+ function LinkPreviewPanel({ onClear, onEdit, url }) {
82
+ return /* @__PURE__ */ jsxs("div", { className: "acms-admin-block-editor-link-preview", children: [
83
+ /* @__PURE__ */ jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", className: "acms-admin-block-editor-link-preview-url", children: url }),
84
+ /* @__PURE__ */ jsx(Toolbar.Divider, {}),
85
+ /* @__PURE__ */ jsx(Toolbar.Button, { type: "button", onClick: onEdit, "aria-label": "\u30EA\u30F3\u30AF\u3092\u7DE8\u96C6", children: /* @__PURE__ */ jsx(Icon, { name: "edit" }) }),
86
+ /* @__PURE__ */ jsx(Toolbar.Button, { type: "button", onClick: onClear, "aria-label": "\u30EA\u30F3\u30AF\u3092\u524A\u9664", children: /* @__PURE__ */ jsx(Icon, { name: "delete" }) })
87
+ ] });
88
+ }
89
+
90
+ // src/components/panels/Colorpicker/Colorpicker.tsx
91
+ import { useCallback, useState, useEffect, useRef, useMemo } from "react";
92
+ import { HexColorPicker } from "react-colorful";
93
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
94
+ var isHex = (v) => /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(v);
95
+ function ColorPicker({ color, onChange, onClear }) {
96
+ const { colorPalette } = useSettingsContext();
97
+ const [colorInputValue, setColorInputValue] = useState(color ?? "");
98
+ const lastValidColorRef = useRef(isHex(color ?? "") ? color : "#000000");
99
+ useEffect(() => {
100
+ if (typeof color === "string") {
101
+ setColorInputValue(color);
102
+ if (isHex(color)) lastValidColorRef.current = color;
103
+ }
104
+ }, [color]);
105
+ const handleInputChange = useCallback(
106
+ (e) => {
107
+ const next = e.target.value.trim();
108
+ setColorInputValue(next);
109
+ if (isHex(next)) {
110
+ lastValidColorRef.current = next;
111
+ onChange?.(next);
112
+ }
113
+ },
114
+ [onChange]
115
+ );
116
+ const handleInputBlur = useCallback(() => {
117
+ if (!isHex(colorInputValue)) {
118
+ setColorInputValue(lastValidColorRef.current);
119
+ return;
120
+ }
121
+ onChange?.(colorInputValue);
122
+ }, [colorInputValue, onChange]);
123
+ const handlePickerChange = useCallback(
124
+ (hex) => {
125
+ lastValidColorRef.current = hex;
126
+ setColorInputValue(hex);
127
+ onChange?.(hex);
128
+ },
129
+ [onChange]
130
+ );
131
+ const handlePalettePick = useCallback(
132
+ (hex) => {
133
+ lastValidColorRef.current = hex;
134
+ setColorInputValue(hex);
135
+ onChange?.(hex);
136
+ },
137
+ [onChange]
138
+ );
139
+ const handleClear = useCallback(() => {
140
+ setColorInputValue("");
141
+ onClear?.();
142
+ }, [onClear]);
143
+ const pickerColor = useMemo(() => {
144
+ return isHex(colorInputValue) ? colorInputValue : lastValidColorRef.current;
145
+ }, [colorInputValue]);
146
+ return /* @__PURE__ */ jsxs2("div", { className: "acms-admin-block-editor-text-menu-color-picker-container", children: [
147
+ /* @__PURE__ */ jsx2(
148
+ HexColorPicker,
149
+ {
150
+ className: "acms-admin-block-editor-text-menu-color-picker-input",
151
+ color: pickerColor,
152
+ onChange: handlePickerChange
153
+ }
154
+ ),
155
+ /* @__PURE__ */ jsx2(
156
+ "input",
157
+ {
158
+ type: "text",
159
+ className: "acms-admin-block-editor-text-menu-color-picker-text-input",
160
+ placeholder: "#000000",
161
+ value: colorInputValue,
162
+ onChange: handleInputChange,
163
+ onBlur: handleInputBlur,
164
+ "aria-label": "\u30AB\u30E9\u30FC\u30B3\u30FC\u30C9\uFF08#RRGGBB \u307E\u305F\u306F #RGB\uFF09"
165
+ }
166
+ ),
167
+ /* @__PURE__ */ jsxs2("div", { className: "acms-admin-block-editor-text-menu-color-picker-palette", children: [
168
+ colorPalette?.map((currentColor) => /* @__PURE__ */ jsx2(
169
+ ColorButton,
170
+ {
171
+ active: currentColor === color,
172
+ color: currentColor,
173
+ onColorChange: handlePalettePick
174
+ },
175
+ currentColor
176
+ )),
177
+ /* @__PURE__ */ jsx2(Toolbar.Button, { type: "button", tooltip: "Reset color to default", onClick: handleClear, "aria-label": "\u8272\u3092\u30EA\u30BB\u30C3\u30C8", children: /* @__PURE__ */ jsx2(Icon, { name: "undo" }) })
178
+ ] })
179
+ ] });
180
+ }
181
+
182
+ // src/components/panels/LinkEditorPanel/LinkEditorPanel.tsx
183
+ import { useState as useState2, useCallback as useCallback2 } from "react";
184
+ import { ButtonV2 } from "@ablogcms/components/button-v2";
185
+ import { isValidUrl } from "@ablogcms/utils";
186
+ import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
187
+ var useLinkEditorState = ({ initialUrl, initialOpenInNewTab, onSetLink }) => {
188
+ const [url, setUrl] = useState2(initialUrl || "");
189
+ const [openInNewTab, setOpenInNewTab] = useState2(initialOpenInNewTab || false);
190
+ const onChange = useCallback2((event) => {
191
+ setUrl(event.target.value);
192
+ }, []);
193
+ const handleSubmit = useCallback2(
194
+ (e) => {
195
+ e.preventDefault();
196
+ if (isValidUrl(url)) {
197
+ onSetLink(url, openInNewTab);
198
+ } else {
199
+ alert("\u6709\u52B9\u306AURL\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
200
+ }
201
+ },
202
+ [url, openInNewTab, onSetLink]
203
+ );
204
+ return {
205
+ url,
206
+ setUrl,
207
+ openInNewTab,
208
+ setOpenInNewTab,
209
+ onChange,
210
+ handleSubmit,
211
+ isValidUrl
212
+ };
213
+ };
214
+ function LinkEditorPanel({ onSetLink, onClear, initialOpenInNewTab, initialUrl }) {
215
+ const state = useLinkEditorState({ onSetLink, initialOpenInNewTab, initialUrl });
216
+ const handleClear = useCallback2(() => {
217
+ onClear?.();
218
+ state.setUrl("");
219
+ state.setOpenInNewTab(false);
220
+ }, [onClear, state]);
221
+ return /* @__PURE__ */ jsx3("div", { className: "acms-admin-form acms-admin-block-editor-link-editor acms-admin-block-editor-popover-form", children: /* @__PURE__ */ jsxs3("form", { onSubmit: state.handleSubmit, children: [
222
+ /* @__PURE__ */ jsx3("div", { className: "acms-admin-block-editor-popover-form-item", children: /* @__PURE__ */ jsxs3("label", { className: "acms-admin-form-block", children: [
223
+ /* @__PURE__ */ jsx3("span", { className: "acms-admin-block-editor-popover-form-item-label", children: "\u30EA\u30F3\u30AF\u5148URL" }),
224
+ /* @__PURE__ */ jsx3(
225
+ "input",
226
+ {
227
+ type: "text",
228
+ className: "acms-admin-form-width-full",
229
+ placeholder: "URL\u3092\u5165\u529B",
230
+ value: state.url,
231
+ onChange: state.onChange
232
+ }
233
+ )
234
+ ] }) }),
235
+ /* @__PURE__ */ jsx3("div", { className: "acms-admin-block-editor-popover-form-item", children: /* @__PURE__ */ jsxs3("div", { className: "acms-admin-form-checkbox", children: [
236
+ /* @__PURE__ */ jsx3(
237
+ "input",
238
+ {
239
+ type: "checkbox",
240
+ id: "openInNewTab",
241
+ value: "true",
242
+ checked: state.openInNewTab,
243
+ onChange: (prev) => {
244
+ state.setOpenInNewTab(prev.target.checked);
245
+ }
246
+ }
247
+ ),
248
+ /* @__PURE__ */ jsxs3("label", { htmlFor: "openInNewTab", children: [
249
+ /* @__PURE__ */ jsx3("i", { className: "acms-admin-ico-checkbox" }),
250
+ "\u30EA\u30F3\u30AF\u5148\u3092\u5225\u30BF\u30D6\u3067\u958B\u304F"
251
+ ] })
252
+ ] }) }),
253
+ /* @__PURE__ */ jsx3("div", { className: "acms-admin-block-editor-popover-form-button-group", children: initialUrl ? /* @__PURE__ */ jsxs3(Fragment, { children: [
254
+ /* @__PURE__ */ jsxs3(ButtonV2, { variant: "outlined", size: "small", type: "submit", children: [
255
+ /* @__PURE__ */ jsx3(Icon, { name: "sync" }),
256
+ "\u5909\u66F4"
257
+ ] }),
258
+ /* @__PURE__ */ jsxs3(ButtonV2, { variant: "filled", size: "small", type: "button", onClick: handleClear, children: [
259
+ /* @__PURE__ */ jsx3(Icon, { name: "delete" }),
260
+ "\u89E3\u9664"
261
+ ] })
262
+ ] }) : /* @__PURE__ */ jsx3(ButtonV2, { variant: "filled", size: "small", type: "submit", children: "\u8FFD\u52A0" }) })
263
+ ] }) });
264
+ }
265
+
266
+ // src/components/menus/LinkMenu/LinkMenu.tsx
267
+ import { jsx as jsx4 } from "react/jsx-runtime";
268
+ function LinkMenu({ editor, appendTo }) {
269
+ const [showEdit, setShowEdit] = useState3(false);
270
+ const [isOpen, setIsOpen] = useState3(false);
271
+ const shouldShow = useCallback3(({ editor: editor2 }) => {
272
+ const isActive = editor2.isActive("link");
273
+ const isShow = isActive && !isTextSelected({ editor: editor2 });
274
+ setIsOpen(isShow);
275
+ return isShow;
276
+ }, []);
277
+ const { href: link, target } = editor.getAttributes("link");
278
+ const handleEdit = useCallback3(() => {
279
+ setShowEdit(true);
280
+ }, []);
281
+ const onSetLink = useCallback3(
282
+ (url, openInNewTab) => {
283
+ editor.chain().focus().extendMarkRange("link").setLink({
284
+ href: url,
285
+ target: openInNewTab ? "_blank" : null,
286
+ rel: openInNewTab ? "noopener noreferrer" : null
287
+ }).run();
288
+ setShowEdit(false);
289
+ },
290
+ [editor]
291
+ );
292
+ const onUnsetLink = useCallback3(() => {
293
+ editor.chain().focus().extendMarkRange("link").unsetLink().run();
294
+ setShowEdit(false);
295
+ return null;
296
+ }, [editor]);
297
+ const getAnchorRect = useCallback3(() => {
298
+ const { view } = editor;
299
+ const { state } = editor;
300
+ const { $from } = state.selection;
301
+ const pos = $from.before($from.depth);
302
+ const dom = view.nodeDOM(pos);
303
+ if (dom instanceof HTMLElement) {
304
+ return dom.getBoundingClientRect();
305
+ }
306
+ return null;
307
+ }, [editor]);
308
+ const handleHide = useCallback3(() => {
309
+ setShowEdit(false);
310
+ }, []);
311
+ const bubbleMenuAppendTo = useCallback3(() => appendTo?.current, [appendTo]);
312
+ const bubbleMenuOptions = useMemo2(
313
+ () => ({
314
+ placement: "bottom-start",
315
+ onHide: handleHide
316
+ }),
317
+ [handleHide]
318
+ );
319
+ return /* @__PURE__ */ jsx4(
320
+ BaseBubbleMenu,
321
+ {
322
+ editor,
323
+ pluginKey: "linkMenu",
324
+ shouldShow,
325
+ updateDelay: 0,
326
+ appendTo: bubbleMenuAppendTo,
327
+ options: bubbleMenuOptions,
328
+ children: /* @__PURE__ */ jsx4(Popover, { modal: true, isOpen, getAnchorRect, children: /* @__PURE__ */ jsx4(PopoverContent, { "data-elevation": "2", size: showEdit ? "default" : "small", children: showEdit ? /* @__PURE__ */ jsx4(
329
+ LinkEditorPanel,
330
+ {
331
+ initialUrl: link,
332
+ initialOpenInNewTab: target === "_blank",
333
+ onSetLink,
334
+ onClear: onUnsetLink
335
+ }
336
+ ) : /* @__PURE__ */ jsx4(LinkPreviewPanel, { url: link, onClear: onUnsetLink, onEdit: handleEdit }) }) })
337
+ }
338
+ );
339
+ }
340
+
341
+ // src/components/menus/TextMenu/TextMenu.tsx
342
+ import { BubbleMenu } from "@tiptap/react/menus";
343
+ import { memo, useEffect as useEffect5, useState as useState7, useRef as useRef4, useMemo as useMemo7, useCallback as useCallback11 } from "react";
344
+ import { Popover as Popover3, PopoverTrigger as PopoverTrigger2, PopoverContent as PopoverContent3 } from "@ablogcms/components/popover";
345
+
346
+ // src/hooks/useBlockMenus.ts
347
+ import { useCallback as useCallback4, useEffect as useEffect2, useRef as useRef2, useMemo as useMemo3 } from "react";
348
+
349
+ // src/hooks/useFrequentlyUsed.ts
350
+ import { useState as useState4 } from "react";
351
+
352
+ // src/lib/utils/commandUsageStorage.ts
353
+ var STORAGE_KEY_PREFIX = "acms-frequently-used-commands";
354
+ var FREQUENT_BLOCKS_MAX_ITEMS = 30;
355
+ var FREQUENCY_WEIGHT = 0.3;
356
+ var RECENCY_WEIGHT = 0.5;
357
+ var RECENCY_HALFLIFE_DAYS = 7;
358
+ var getKey = () => {
359
+ return `${STORAGE_KEY_PREFIX}-setid-${ACMS.Config.editorSetId}-root-${ACMS.Config.root}-suid-${ACMS.Config.suid}`;
360
+ };
361
+ var getCommandKey = (command) => {
362
+ return command.class ? `${command.name}:${command.class}` : command.name;
363
+ };
364
+ var loadUsageData = () => {
365
+ const key = getKey();
366
+ const raw = localStorage.getItem(key);
367
+ if (!raw) return {};
368
+ try {
369
+ const parsed = JSON.parse(raw);
370
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
371
+ return parsed;
372
+ }
373
+ } catch (e) {
374
+ console.error("Error parsing usage data from localStorage:", e);
375
+ }
376
+ return {};
377
+ };
378
+ var saveUsageData = (data) => {
379
+ const key = getKey();
380
+ localStorage.setItem(key, JSON.stringify(data));
381
+ };
382
+ var recordCommandUsage = (command) => {
383
+ const data = loadUsageData();
384
+ const commandKey = getCommandKey({ name: command.name, class: command.class });
385
+ const now = Date.now();
386
+ const existing = data[commandKey];
387
+ data[commandKey] = {
388
+ count: (existing?.count ?? 0) + 1,
389
+ lastUsed: now
390
+ };
391
+ const trimmedEntries = Object.entries(data).toSorted((a, b) => (b[1].lastUsed ?? 0) - (a[1].lastUsed ?? 0)).slice(0, FREQUENT_BLOCKS_MAX_ITEMS);
392
+ const trimmedData = Object.fromEntries(trimmedEntries);
393
+ saveUsageData(trimmedData);
394
+ };
395
+ var calculateScore = (record, now) => {
396
+ const useCount = record.count;
397
+ const { lastUsed } = record;
398
+ const frequencyScore = Math.log(useCount + 1);
399
+ const daysSinceLastUse = (now - lastUsed) / (1e3 * 60 * 60 * 24);
400
+ const recencyScore = Math.exp(-daysSinceLastUse / RECENCY_HALFLIFE_DAYS);
401
+ return frequencyScore * FREQUENCY_WEIGHT + recencyScore * RECENCY_WEIGHT;
402
+ };
403
+ var getSortedCommandEntries = (data, limit, now) => {
404
+ const entriesWithScore = Object.entries(data).map(([id, record]) => {
405
+ const score = calculateScore(record, now);
406
+ return [id, { ...record, score }];
407
+ });
408
+ return entriesWithScore.toSorted((a, b) => {
409
+ const scoreA = a[1].score ?? 0;
410
+ const scoreB = b[1].score ?? 0;
411
+ return scoreB - scoreA;
412
+ }).slice(0, limit);
413
+ };
414
+ var getFrequentlyUsedCommands = (limit = 5) => {
415
+ const data = loadUsageData();
416
+ const now = Date.now();
417
+ const sortedEntries = getSortedCommandEntries(data, FREQUENT_BLOCKS_MAX_ITEMS, now);
418
+ return sortedEntries.slice(0, limit).map(([commandKey]) => {
419
+ const colonIndex = commandKey.indexOf(":");
420
+ if (colonIndex !== -1) {
421
+ return {
422
+ name: commandKey.substring(0, colonIndex),
423
+ class: commandKey.substring(colonIndex + 1)
424
+ };
425
+ }
426
+ return { name: commandKey };
427
+ });
428
+ };
429
+
430
+ // src/hooks/useFrequentlyUsed.ts
431
+ var maxItem = 5;
432
+ var useFrequentlyUsed = () => {
433
+ const [frequentlyUsed, setFrequentlyUsed] = useState4(() => getFrequentlyUsedCommands(maxItem));
434
+ const recordUsage = (command) => {
435
+ recordCommandUsage(command);
436
+ setFrequentlyUsed(getFrequentlyUsedCommands(maxItem));
437
+ };
438
+ return { frequentlyUsed, recordUsage };
439
+ };
440
+
441
+ // src/hooks/resolveCommands.ts
442
+ function resolveCommands(commands, recordUsage, additionalDefinitions) {
443
+ const masters = mergeBlockDefinitions(additionalDefinitions);
444
+ return commands.flatMap((cmd) => {
445
+ const def = masters[cmd.name];
446
+ if (!def) {
447
+ return [];
448
+ }
449
+ return [
450
+ {
451
+ ...cmd,
452
+ ...def.createActions(cmd, { recordUsage })
453
+ }
454
+ ];
455
+ });
456
+ }
457
+
458
+ // src/hooks/useBlockMenus.ts
459
+ function useBlockMenus({ blockMenus, blockDefinitions }) {
460
+ const { frequentlyUsed, recordUsage } = useFrequentlyUsed();
461
+ const itemsRef = useRef2([]);
462
+ useEffect2(() => {
463
+ itemsRef.current = blockMenus ?? [];
464
+ }, [blockMenus]);
465
+ const getFilteredBlockMenus = useCallback4(
466
+ ({ query, editor }) => {
467
+ const currentItems = itemsRef.current;
468
+ if (!currentItems || currentItems.length === 0) {
469
+ return [];
470
+ }
471
+ const withFilteredCommands = currentItems.map((group) => ({
472
+ ...group,
473
+ commands: group.commands.filter((item) => {
474
+ const labelNormalized = item.label.toLowerCase().trim();
475
+ const queryNormalized = query.toLowerCase().trim();
476
+ if (item.aliases) {
477
+ const aliases = item.aliases.map((alias) => alias.toLowerCase().trim());
478
+ return labelNormalized.includes(queryNormalized) || aliases.some((alias) => alias.includes(queryNormalized));
479
+ }
480
+ return labelNormalized.includes(queryNormalized);
481
+ }).filter((command) => {
482
+ if (!command.shouldBeHidden) {
483
+ return true;
484
+ }
485
+ return !command.shouldBeHidden(editor);
486
+ })
487
+ }));
488
+ const withoutEmptyGroups = withFilteredCommands.filter((group) => {
489
+ if (group.commands.length > 0) {
490
+ return true;
491
+ }
492
+ return false;
493
+ });
494
+ const withEnabledSettings = withoutEmptyGroups.map((group) => ({
495
+ ...group,
496
+ commands: group.commands.map((command) => ({
497
+ ...command,
498
+ isEnabled: true
499
+ }))
500
+ }));
501
+ const resolvedGroups = withEnabledSettings.map((group) => ({
502
+ ...group,
503
+ commands: resolveCommands(group.commands, recordUsage, blockDefinitions)
504
+ }));
505
+ if (frequentlyUsed.length > 0) {
506
+ const frequentlyUsedMap = /* @__PURE__ */ new Map();
507
+ frequentlyUsed.forEach((f, index) => {
508
+ const key = `${f.name}:${f.class ?? ""}`;
509
+ frequentlyUsedMap.set(key, index);
510
+ });
511
+ const frequentlyUsedCommands = resolvedGroups.flatMap((group) => group.commands).filter((cmd, index, self) => {
512
+ const key = `${cmd.name}:${cmd.class ?? ""}`;
513
+ const isFrequentlyUsed = frequentlyUsedMap.has(key);
514
+ const firstIndex = self.findIndex((c) => c.name === cmd.name && (c.class ?? "") === (cmd.class ?? ""));
515
+ return isFrequentlyUsed && firstIndex === index;
516
+ }).toSorted((a, b) => {
517
+ const aKey = `${a.name}:${a.class ?? ""}`;
518
+ const bKey = `${b.name}:${b.class ?? ""}`;
519
+ const aIndex = frequentlyUsedMap.get(aKey) ?? Infinity;
520
+ const bIndex = frequentlyUsedMap.get(bKey) ?? Infinity;
521
+ return aIndex - bIndex;
522
+ });
523
+ if (frequentlyUsedCommands.length > 0) {
524
+ const frequentlyUsedGroup = {
525
+ title: "\u3088\u304F\u4F7F\u3046\u30D6\u30ED\u30C3\u30AF",
526
+ name: "frequently-used",
527
+ commands: frequentlyUsedCommands
528
+ };
529
+ return [frequentlyUsedGroup, ...resolvedGroups];
530
+ }
531
+ }
532
+ return resolvedGroups;
533
+ },
534
+ [recordUsage, frequentlyUsed, blockDefinitions]
535
+ );
536
+ return {
537
+ groups: blockMenus ?? [],
538
+ getFilteredBlockMenus
539
+ };
540
+ }
541
+ function useFilteredCommands(menus, editor, currentPos) {
542
+ return useMemo3(() => {
543
+ return menus.map((item) => {
544
+ const filteredCommands = item.commands.filter((cmd) => !cmd.isDisabled(editor, currentPos));
545
+ return {
546
+ ...item,
547
+ commands: filteredCommands
548
+ };
549
+ }).filter((item) => item.commands.length > 0 && item.name !== "frequently-used");
550
+ }, [menus, editor, currentPos]);
551
+ }
552
+
553
+ // src/hooks/useEditorViewDom.ts
554
+ import { useEffect as useEffect3, useState as useState5 } from "react";
555
+ function useEditorViewDom(editor) {
556
+ const [dom, setDom] = useState5(
557
+ () => editor.isInitialized ? editor.view.dom : null
558
+ );
559
+ useEffect3(() => {
560
+ if (editor.isInitialized) {
561
+ setDom(editor.view.dom);
562
+ return void 0;
563
+ }
564
+ const handleCreate = () => setDom(editor.view.dom);
565
+ editor.on("create", handleCreate);
566
+ return () => {
567
+ editor.off("create", handleCreate);
568
+ };
569
+ }, [editor]);
570
+ return dom;
571
+ }
572
+
573
+ // src/components/menus/TextMenu/hooks/useTextmenuCommands.ts
574
+ import { useCallback as useCallback5 } from "react";
575
+ var useTextmenuCommands = (editor) => {
576
+ const onBold = useCallback5(() => editor.chain().focus().toggleBold().run(), [editor]);
577
+ const onItalic = useCallback5(() => editor.chain().focus().toggleItalic().run(), [editor]);
578
+ const onStrike = useCallback5(() => editor.chain().focus().toggleStrike().run(), [editor]);
579
+ const onUnderline = useCallback5(() => editor.chain().focus().toggleUnderline().run(), [editor]);
580
+ const onCode = useCallback5(() => editor.chain().focus().toggleCode().run(), [editor]);
581
+ const onCodeBlock = useCallback5(() => editor.chain().focus().toggleCodeBlock().run(), [editor]);
582
+ const onSubscript = useCallback5(() => editor.chain().focus().toggleSubscript().run(), [editor]);
583
+ const onSuperscript = useCallback5(() => editor.chain().focus().toggleSuperscript().run(), [editor]);
584
+ const onAlignLeft = useCallback5(() => editor.chain().focus().setTextAlign("left").run(), [editor]);
585
+ const onAlignCenter = useCallback5(() => editor.chain().focus().setTextAlign("center").run(), [editor]);
586
+ const onAlignRight = useCallback5(() => editor.chain().focus().setTextAlign("right").run(), [editor]);
587
+ const onAlignJustify = useCallback5(() => editor.chain().focus().setTextAlign("justify").run(), [editor]);
588
+ const onChangeColor = useCallback5((color) => editor.chain().setFontColor(color).run(), [editor]);
589
+ const onClearColor = useCallback5(() => editor.chain().focus().unsetFontColor().run(), [editor]);
590
+ const onChangeHighlight = useCallback5((color) => editor.chain().setHighlight({ color }).run(), [editor]);
591
+ const onClearHighlight = useCallback5(() => editor.chain().focus().unsetHighlight().run(), [editor]);
592
+ const onLink = useCallback5(
593
+ (url, inNewTab) => editor.chain().focus().setLink({ href: url, target: inNewTab ? "_blank" : "" }).run(),
594
+ [editor]
595
+ );
596
+ const onUnsetLink = useCallback5(() => {
597
+ editor.chain().focus().unsetLink().run();
598
+ }, [editor]);
599
+ const onSetFont = useCallback5(
600
+ (font) => {
601
+ if (!font || font.length === 0) {
602
+ return editor.chain().focus().unsetFontFamily().run();
603
+ }
604
+ return editor.chain().focus().setFontFamily(font).run();
605
+ },
606
+ [editor]
607
+ );
608
+ const onSetFontSize = useCallback5(
609
+ (fontSize) => {
610
+ if (!fontSize || fontSize.length === 0) {
611
+ return editor.chain().focus().unsetFontSize().run();
612
+ }
613
+ return editor.chain().focus().setFontSize(fontSize).run();
614
+ },
615
+ [editor]
616
+ );
617
+ const onCustomClass = useCallback5(
618
+ (className) => {
619
+ editor.commands.setMark("customMark", { class: className });
620
+ },
621
+ [editor]
622
+ );
623
+ const removeCustomClass = useCallback5(() => {
624
+ editor.commands.unsetMark("customMark");
625
+ }, [editor]);
626
+ return {
627
+ onBold,
628
+ onItalic,
629
+ onStrike,
630
+ onUnderline,
631
+ onCode,
632
+ onCodeBlock,
633
+ onSubscript,
634
+ onSuperscript,
635
+ onAlignLeft,
636
+ onAlignCenter,
637
+ onAlignRight,
638
+ onAlignJustify,
639
+ onChangeColor,
640
+ onClearColor,
641
+ onChangeHighlight,
642
+ onClearHighlight,
643
+ onSetFont,
644
+ onSetFontSize,
645
+ onLink,
646
+ onUnsetLink,
647
+ onCustomClass,
648
+ removeCustomClass
649
+ };
650
+ };
651
+
652
+ // src/components/menus/TextMenu/hooks/useTextmenuStates.ts
653
+ import { useCallback as useCallback6 } from "react";
654
+ var useTextmenuStates = (editor) => {
655
+ const shouldShow = useCallback6(
656
+ ({ view, state, from }) => {
657
+ if (!view || !state) {
658
+ return false;
659
+ }
660
+ if (isCellSelection(state.selection)) {
661
+ return false;
662
+ }
663
+ const domAtPos = view.domAtPos(from || 0).node;
664
+ const nodeDOM = view.nodeDOM(from || 0);
665
+ const node = nodeDOM || domAtPos;
666
+ if (isCustomNodeSelected(editor, node)) {
667
+ return false;
668
+ }
669
+ return isTextSelected({ editor });
670
+ },
671
+ [editor]
672
+ );
673
+ return {
674
+ isLink: editor.isActive("link"),
675
+ isBold: editor.isActive("bold"),
676
+ isItalic: editor.isActive("italic"),
677
+ isStrike: editor.isActive("strike"),
678
+ isUnderline: editor.isActive("underline"),
679
+ isCode: editor.isActive("code"),
680
+ isSubscript: editor.isActive("subscript"),
681
+ isSuperscript: editor.isActive("superscript"),
682
+ isAlignLeft: editor.isActive({ textAlign: "left" }),
683
+ isAlignCenter: editor.isActive({ textAlign: "center" }),
684
+ isAlignRight: editor.isActive({ textAlign: "right" }),
685
+ isAlignJustify: editor.isActive({ textAlign: "justify" }),
686
+ currentColor: editor.getAttributes("textStyle")?.color || void 0,
687
+ currentHighlight: editor.getAttributes("highlight")?.color || void 0,
688
+ currentFont: editor.getAttributes("textStyle")?.fontFamily || void 0,
689
+ currentSize: editor.getAttributes("textStyle")?.fontSize || void 0,
690
+ currentCustomClass: editor.getAttributes("customMark")?.class || void 0,
691
+ shouldShow
692
+ };
693
+ };
694
+
695
+ // src/components/menus/TextMenu/components/ContentTypePicker.tsx
696
+ import { useMemo as useMemo4 } from "react";
697
+ import { Menu, MenuTrigger, MenuList, MenuItem, MenuGroup, MenuPopover } from "@ablogcms/components/dropdown-menu";
698
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
699
+ function ContentTypePicker({ menus, editor, currentPos }) {
700
+ const activeItem = useMemo4(() => {
701
+ return menus.flatMap((item) => item.commands).find((cmd) => (cmd.isActive?.(editor) ?? false) && cmd.isTextMenu === true);
702
+ }, [menus, editor]);
703
+ const filteredCommands = useFilteredCommands(menus, editor, currentPos);
704
+ return /* @__PURE__ */ jsxs4(Menu, { children: [
705
+ activeItem && /* @__PURE__ */ jsxs4(Fragment2, { children: [
706
+ /* @__PURE__ */ jsx5(MenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs4(Toolbar.Button, { type: "button", tooltip: "\u30D6\u30ED\u30C3\u30AF\u30BF\u30A4\u30D7", "aria-label": "\u30D6\u30ED\u30C3\u30AF\u30BF\u30A4\u30D7\u3092\u9078\u629E", children: [
707
+ /* @__PURE__ */ jsx5(Icon, { name: activeItem.iconName }),
708
+ activeItem.label,
709
+ /* @__PURE__ */ jsx5(Icon, { name: "keyboard_arrow_down" })
710
+ ] }) }),
711
+ /* @__PURE__ */ jsx5(Toolbar.Divider, {})
712
+ ] }),
713
+ /* @__PURE__ */ jsx5(MenuPopover, { scrollable: true, "data-elevation": "3", children: /* @__PURE__ */ jsx5(MenuList, { children: filteredCommands.map((group) => /* @__PURE__ */ jsx5(MenuGroup, { title: group.title, children: group.commands.map((command) => /* @__PURE__ */ jsx5(
714
+ MenuItem,
715
+ {
716
+ icon: /* @__PURE__ */ jsx5(Icon, { name: command.iconName }),
717
+ onSelect: command.convert ? () => command.convert(editor, currentPos) : () => {
718
+ },
719
+ children: command.label
720
+ },
721
+ `${command.name}_${command.label}`
722
+ )) }, group.title)) }) })
723
+ ] });
724
+ }
725
+
726
+ // src/components/menus/TextMenu/components/FontFamilyPicker.tsx
727
+ import { useCallback as useCallback7, useMemo as useMemo5 } from "react";
728
+ import {
729
+ Menu as Menu2,
730
+ MenuTrigger as MenuTrigger2,
731
+ MenuList as MenuList2,
732
+ MenuGroup as MenuGroup2,
733
+ MenuItemRadio,
734
+ MenuItemRadioGroup,
735
+ MenuPopover as MenuPopover2
736
+ } from "@ablogcms/components/dropdown-menu";
737
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
738
+ function FontFamilyPicker({ onChange, value }) {
739
+ const { fontFamily } = useSettingsContext();
740
+ const currentValue = useMemo5(() => fontFamily?.find((family) => family.value === value), [fontFamily, value]);
741
+ const currentFontLabel = useMemo5(() => currentValue?.label || "\u30C7\u30D5\u30A9\u30EB\u30C8", [currentValue]);
742
+ const selectFont = useCallback7((font) => onChange(font), [onChange]);
743
+ return /* @__PURE__ */ jsxs5(Menu2, { closeOnSelect: true, children: [
744
+ /* @__PURE__ */ jsx6(MenuTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs5(
745
+ Toolbar.Button,
746
+ {
747
+ type: "button",
748
+ tooltip: "\u30D5\u30A9\u30F3\u30C8\u30D5\u30A1\u30DF\u30EA\u30FC",
749
+ active: !!currentValue?.value,
750
+ "aria-label": "\u30D5\u30A9\u30F3\u30C8\u30D5\u30A1\u30DF\u30EA\u30FC\u3092\u8A2D\u5B9A",
751
+ children: [
752
+ /* @__PURE__ */ jsx6(Icon, { name: "slab_serif" }),
753
+ currentFontLabel,
754
+ /* @__PURE__ */ jsx6(Icon, { name: "keyboard_arrow_down" })
755
+ ]
756
+ }
757
+ ) }),
758
+ /* @__PURE__ */ jsx6(MenuPopover2, { "data-elevation": "3", children: /* @__PURE__ */ jsx6(MenuList2, { children: fontFamily?.length > 0 && /* @__PURE__ */ jsx6(MenuGroup2, { title: "\u30D5\u30A9\u30F3\u30C8\u30D5\u30A1\u30DF\u30EA\u30FC", children: /* @__PURE__ */ jsx6(MenuItemRadioGroup, { defaultValue: currentValue?.value, onValueChange: selectFont, children: fontFamily.map((item) => /* @__PURE__ */ jsx6(MenuItemRadio, { value: item.value, children: /* @__PURE__ */ jsx6("span", { style: { fontFamily: item.value }, children: item.label }) }, `${item.label}_${item.value}`)) }) }) }) })
759
+ ] });
760
+ }
761
+
762
+ // src/components/menus/TextMenu/components/FontSizePicker.tsx
763
+ import { useCallback as useCallback8, useMemo as useMemo6 } from "react";
764
+ import {
765
+ Menu as Menu3,
766
+ MenuTrigger as MenuTrigger3,
767
+ MenuList as MenuList3,
768
+ MenuGroup as MenuGroup3,
769
+ MenuItemRadio as MenuItemRadio2,
770
+ MenuItemRadioGroup as MenuItemRadioGroup2,
771
+ MenuPopover as MenuPopover3
772
+ } from "@ablogcms/components/dropdown-menu";
773
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
774
+ function FontSizePicker({ onChange, value }) {
775
+ const { fontSize } = useSettingsContext();
776
+ const currentValue = useMemo6(() => fontSize?.find((size) => size.value === value), [fontSize, value]);
777
+ const currentSizeLabel = useMemo6(() => currentValue?.label.split(" ")[0] || "\u6A19\u6E96", [currentValue]);
778
+ const selectSize = useCallback8((size) => onChange(size), [onChange]);
779
+ return /* @__PURE__ */ jsxs6(Menu3, { closeOnSelect: true, children: [
780
+ /* @__PURE__ */ jsx7(MenuTrigger3, { asChild: true, children: /* @__PURE__ */ jsxs6(
781
+ Toolbar.Button,
782
+ {
783
+ type: "button",
784
+ tooltip: "\u30D5\u30A9\u30F3\u30C8\u30B5\u30A4\u30BA",
785
+ active: !!currentValue?.value,
786
+ "aria-label": "\u30D5\u30A9\u30F3\u30C8\u30B5\u30A4\u30BA\u3092\u8A2D\u5B9A",
787
+ children: [
788
+ /* @__PURE__ */ jsx7(Icon, { name: "format_size" }),
789
+ currentSizeLabel,
790
+ /* @__PURE__ */ jsx7(Icon, { name: "keyboard_arrow_down" })
791
+ ]
792
+ }
793
+ ) }),
794
+ /* @__PURE__ */ jsx7(MenuPopover3, { "data-elevation": "3", children: /* @__PURE__ */ jsx7(MenuList3, { children: fontSize?.length > 0 && /* @__PURE__ */ jsx7(MenuGroup3, { title: "\u30D5\u30A9\u30F3\u30C8\u30B5\u30A4\u30BA", children: /* @__PURE__ */ jsx7(MenuItemRadioGroup2, { defaultValue: currentValue?.value, onValueChange: selectSize, children: fontSize.map((item) => /* @__PURE__ */ jsx7(MenuItemRadio2, { value: item.value, children: /* @__PURE__ */ jsx7("span", { style: { fontSize: item.value }, children: item.label }) }, `${item.label}_${item.value}`)) }) }) }) })
795
+ ] });
796
+ }
797
+
798
+ // src/components/menus/TextMenu/components/CustomClassPicker.tsx
799
+ import { useCallback as useCallback9, useEffect as useEffect4, useState as useState6 } from "react";
800
+ import {
801
+ Menu as Menu4,
802
+ MenuItem as MenuItem2,
803
+ MenuTrigger as MenuTrigger4,
804
+ MenuList as MenuList4,
805
+ MenuGroup as MenuGroup4,
806
+ MenuItemRadio as MenuItemRadio3,
807
+ MenuItemRadioGroup as MenuItemRadioGroup3,
808
+ MenuPopover as MenuPopover4
809
+ } from "@ablogcms/components/dropdown-menu";
810
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
811
+ function CustomClassPicker({ onChange, onRemove, value }) {
812
+ const { customClass } = useSettingsContext();
813
+ const [currentValue, setCurrentValue] = useState6(null);
814
+ useEffect4(() => {
815
+ const currentValue2 = customClass.find((item) => item.value === value.replace("custom-mark ", ""));
816
+ setCurrentValue(currentValue2 || null);
817
+ }, [customClass, value]);
818
+ const selectClass = useCallback9(
819
+ (className) => {
820
+ onChange(`custom-mark ${className}`);
821
+ },
822
+ [onChange]
823
+ );
824
+ return /* @__PURE__ */ jsxs7(Menu4, { closeOnSelect: true, children: [
825
+ /* @__PURE__ */ jsx8(MenuTrigger4, { asChild: true, children: /* @__PURE__ */ jsxs7(
826
+ Toolbar.Button,
827
+ {
828
+ type: "button",
829
+ tooltip: "\u30AB\u30B9\u30BF\u30E0\u30AF\u30E9\u30B9",
830
+ active: !!currentValue?.value,
831
+ "aria-label": "\u30AB\u30B9\u30BF\u30E0\u30AF\u30E9\u30B9\u3092\u8A2D\u5B9A",
832
+ children: [
833
+ /* @__PURE__ */ jsx8(Icon, { name: "build" }),
834
+ currentValue?.label || "\u30AB\u30B9\u30BF\u30E0\u30AF\u30E9\u30B9",
835
+ /* @__PURE__ */ jsx8(Icon, { name: "keyboard_arrow_down" })
836
+ ]
837
+ }
838
+ ) }),
839
+ /* @__PURE__ */ jsx8(MenuPopover4, { "data-elevation": "3", children: /* @__PURE__ */ jsx8(MenuList4, { children: /* @__PURE__ */ jsx8(MenuGroup4, { title: "\u30AB\u30B9\u30BF\u30E0\u30AF\u30E9\u30B9", children: /* @__PURE__ */ jsxs7(MenuItemRadioGroup3, { defaultValue: currentValue?.value, onValueChange: selectClass, children: [
840
+ customClass?.map((item) => /* @__PURE__ */ jsx8(MenuItemRadio3, { value: item.value, icon: /* @__PURE__ */ jsx8(Icon, { name: "build" }), children: item.label }, `${item.label}_${item.value}`)),
841
+ /* @__PURE__ */ jsx8(MenuItem2, { variant: "danger", icon: /* @__PURE__ */ jsx8(Icon, { name: "delete" }), onSelect: onRemove, children: "\u30AB\u30B9\u30BF\u30E0\u30AF\u30E9\u30B9\u3092\u89E3\u9664" })
842
+ ] }) }) }) })
843
+ ] });
844
+ }
845
+
846
+ // src/components/menus/TextMenu/components/EditLinkPopover.tsx
847
+ import { Popover as Popover2, PopoverTrigger, PopoverContent as PopoverContent2 } from "@ablogcms/components/popover";
848
+ import { useCallback as useCallback10, useRef as useRef3 } from "react";
849
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
850
+ function EditLinkPopover({ editor, onSetLink, onClearLink, isActive }) {
851
+ const popoverRef = useRef3(null);
852
+ const { href: link, target } = editor.getAttributes("link");
853
+ const handleSetLink = useCallback10(
854
+ (link2, openInNewTab) => {
855
+ onSetLink(link2, openInNewTab);
856
+ popoverRef.current?.closePopover();
857
+ },
858
+ [onSetLink]
859
+ );
860
+ const handleClearLink = useCallback10(() => {
861
+ onClearLink();
862
+ popoverRef.current?.closePopover();
863
+ }, [onClearLink]);
864
+ return /* @__PURE__ */ jsxs8(Popover2, { modal: true, ref: popoverRef, children: [
865
+ /* @__PURE__ */ jsx9(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx9(Toolbar.Button, { type: "button", tooltip: "\u30EA\u30F3\u30AF", "aria-label": "\u30EA\u30F3\u30AF\u3092\u8A2D\u5B9A", active: isActive, children: /* @__PURE__ */ jsx9(Icon, { name: "link" }) }) }),
866
+ /* @__PURE__ */ jsx9(PopoverContent2, { "data-elevation": "2", children: /* @__PURE__ */ jsx9(
867
+ LinkEditorPanel,
868
+ {
869
+ initialUrl: link,
870
+ initialOpenInNewTab: target === "_blank",
871
+ onSetLink: handleSetLink,
872
+ onClear: handleClearLink
873
+ }
874
+ ) })
875
+ ] });
876
+ }
877
+
878
+ // src/components/menus/TextMenu/TextMenu.tsx
879
+ import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
880
+ var MemoButton = memo(Toolbar.Button);
881
+ var MemoContentTypePicker = memo(ContentTypePicker);
882
+ var MemoColorPicker = memo(ColorPicker);
883
+ var MemoFontFamilyPicker = memo(FontFamilyPicker);
884
+ var MemoFontSizePicker = memo(FontSizePicker);
885
+ var MemoCustomClassPicker = memo(CustomClassPicker);
886
+ var SHORTCUT_BOLD = ["Mod", "B"];
887
+ var SHORTCUT_ITALIC = ["Mod", "I"];
888
+ var SHORTCUT_UNDERLINE = ["Mod", "U"];
889
+ var SHORTCUT_STRIKE = ["Mod", "Shift", "S"];
890
+ var SHORTCUT_CODE = ["Mod", "E"];
891
+ var SHORTCUT_SUBSCRIPT = ["Mod", ","];
892
+ var SHORTCUT_SUPERSCRIPT = ["Mod", "."];
893
+ function TextMenu({ editor, appendTo }) {
894
+ const viewDom = useEditorViewDom(editor);
895
+ const commands = useTextmenuCommands(editor);
896
+ const states = useTextmenuStates(editor);
897
+ const { features, blockMenus } = useSettingsContext();
898
+ const { getFilteredBlockMenus } = useBlockMenus({ blockMenus });
899
+ const menuRef = useRef4(null);
900
+ const [showLeft, setShowLeft] = useState7(false);
901
+ const [showRight, setShowRight] = useState7(false);
902
+ const updateScrollButtons = useCallback11(() => {
903
+ const el = menuRef.current;
904
+ if (!el) return;
905
+ setShowLeft(el.scrollLeft > 0);
906
+ setShowRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
907
+ }, []);
908
+ const scrollLeft = () => {
909
+ menuRef.current?.scrollBy({ left: -150, behavior: "smooth" });
910
+ };
911
+ const scrollRight = () => {
912
+ menuRef.current?.scrollBy({ left: 150, behavior: "smooth" });
913
+ };
914
+ const align = useMemo7(() => {
915
+ if (states.isAlignLeft) {
916
+ return "left";
917
+ }
918
+ if (states.isAlignCenter) {
919
+ return "center";
920
+ }
921
+ if (states.isAlignRight) {
922
+ return "right";
923
+ }
924
+ return "left";
925
+ }, [states.isAlignLeft, states.isAlignCenter, states.isAlignRight]);
926
+ const handleAlign = (newAlign) => {
927
+ if (newAlign === "left") {
928
+ commands.onAlignLeft();
929
+ } else if (newAlign === "center") {
930
+ commands.onAlignCenter();
931
+ } else if (newAlign === "right") {
932
+ commands.onAlignRight();
933
+ }
934
+ };
935
+ useEffect5(() => {
936
+ const el = menuRef.current;
937
+ if (!el) return;
938
+ el.addEventListener("scroll", updateScrollButtons, { passive: true });
939
+ document.addEventListener("resize", updateScrollButtons);
940
+ return () => {
941
+ el.removeEventListener("scroll", updateScrollButtons);
942
+ document.removeEventListener("resize", updateScrollButtons);
943
+ };
944
+ }, [editor, updateScrollButtons]);
945
+ useEffect5(() => {
946
+ const handleKeyDown = (event) => {
947
+ if (event.key === "Tab") {
948
+ const toolbar = menuRef.current;
949
+ if (toolbar) {
950
+ toolbar.focus();
951
+ }
952
+ }
953
+ };
954
+ if (viewDom === null) {
955
+ return void 0;
956
+ }
957
+ viewDom.addEventListener("keydown", handleKeyDown, { capture: true });
958
+ return () => {
959
+ viewDom.removeEventListener("keydown", handleKeyDown, { capture: true });
960
+ };
961
+ }, [viewDom]);
962
+ const handleToolbarKeyDown = (event) => {
963
+ if (event.key === "Tab") {
964
+ editor.commands.focus();
965
+ }
966
+ };
967
+ const bubbleMenuAppendTo = useCallback11(() => appendTo?.current ?? document.body, [appendTo]);
968
+ const bubbleMenuOptions = useMemo7(
969
+ () => ({
970
+ placement: "top-start",
971
+ shift: {
972
+ boundary: appendTo?.current ?? void 0,
973
+ padding: 8
974
+ },
975
+ flip: {
976
+ fallbackPlacements: ["bottom-start", "top"]
977
+ },
978
+ onShow: () => {
979
+ requestAnimationFrame(() => {
980
+ updateScrollButtons();
981
+ });
982
+ }
983
+ }),
984
+ [appendTo, updateScrollButtons]
985
+ );
986
+ return /* @__PURE__ */ jsx10(
987
+ BubbleMenu,
988
+ {
989
+ editor,
990
+ pluginKey: "textMenu",
991
+ shouldShow: states.shouldShow,
992
+ updateDelay: 100,
993
+ appendTo: bubbleMenuAppendTo,
994
+ "data-theme": "text-menu",
995
+ style: { zIndex: 100018 },
996
+ options: bubbleMenuOptions,
997
+ children: /* @__PURE__ */ jsxs9(
998
+ Toolbar,
999
+ {
1000
+ ref: menuRef,
1001
+ className: "acms-admin-block-editor-toolbar-scrollable",
1002
+ onKeyDownCapture: handleToolbarKeyDown,
1003
+ children: [
1004
+ /* @__PURE__ */ jsx10(
1005
+ MemoContentTypePicker,
1006
+ {
1007
+ menus: getFilteredBlockMenus({ query: "", editor }),
1008
+ editor,
1009
+ currentPos: editor.state.selection.$from.before(1)
1010
+ }
1011
+ ),
1012
+ /* @__PURE__ */ jsx10(
1013
+ MemoButton,
1014
+ {
1015
+ type: "button",
1016
+ tooltip: "\u592A\u5B57",
1017
+ tooltipShortcut: SHORTCUT_BOLD,
1018
+ onClick: commands.onBold,
1019
+ active: states.isBold,
1020
+ "aria-label": "\u592A\u5B57",
1021
+ children: /* @__PURE__ */ jsx10(Icon, { name: "format_bold" })
1022
+ }
1023
+ ),
1024
+ features?.textItalic && /* @__PURE__ */ jsx10(
1025
+ MemoButton,
1026
+ {
1027
+ type: "button",
1028
+ tooltip: "\u659C\u4F53",
1029
+ tooltipShortcut: SHORTCUT_ITALIC,
1030
+ onClick: commands.onItalic,
1031
+ active: states.isItalic,
1032
+ "aria-label": "\u659C\u4F53",
1033
+ children: /* @__PURE__ */ jsx10(Icon, { name: "format_italic" })
1034
+ }
1035
+ ),
1036
+ features?.textUnderline && /* @__PURE__ */ jsx10(
1037
+ MemoButton,
1038
+ {
1039
+ type: "button",
1040
+ tooltip: "\u4E0B\u7DDA",
1041
+ tooltipShortcut: SHORTCUT_UNDERLINE,
1042
+ onClick: commands.onUnderline,
1043
+ active: states.isUnderline,
1044
+ "aria-label": "\u4E0B\u7DDA",
1045
+ children: /* @__PURE__ */ jsx10(Icon, { name: "format_underlined" })
1046
+ }
1047
+ ),
1048
+ features?.textStrike && /* @__PURE__ */ jsx10(
1049
+ MemoButton,
1050
+ {
1051
+ type: "button",
1052
+ tooltip: "\u6253\u3061\u6D88\u3057\u7DDA",
1053
+ tooltipShortcut: SHORTCUT_STRIKE,
1054
+ onClick: commands.onStrike,
1055
+ active: states.isStrike,
1056
+ "aria-label": "\u6253\u3061\u6D88\u3057\u7DDA",
1057
+ children: /* @__PURE__ */ jsx10(Icon, { name: "format_strikethrough" })
1058
+ }
1059
+ ),
1060
+ features?.textCode && /* @__PURE__ */ jsx10(
1061
+ MemoButton,
1062
+ {
1063
+ type: "button",
1064
+ tooltip: "\u30B3\u30FC\u30C9",
1065
+ tooltipShortcut: SHORTCUT_CODE,
1066
+ onClick: commands.onCode,
1067
+ active: states.isCode,
1068
+ "aria-label": "\u30B3\u30FC\u30C9",
1069
+ children: /* @__PURE__ */ jsx10(Icon, { name: "code" })
1070
+ }
1071
+ ),
1072
+ /* @__PURE__ */ jsx10(
1073
+ EditLinkPopover,
1074
+ {
1075
+ editor,
1076
+ onSetLink: commands.onLink,
1077
+ onClearLink: commands.onUnsetLink,
1078
+ isActive: states.isLink
1079
+ }
1080
+ ),
1081
+ /* @__PURE__ */ jsx10(AlignPicker, { align, onChange: handleAlign }),
1082
+ features?.textMarker && /* @__PURE__ */ jsxs9(Popover3, { modal: true, placement: "top-start", children: [
1083
+ /* @__PURE__ */ jsx10(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsx10(MemoButton, { type: "button", tooltip: "\u30DE\u30FC\u30AB\u30FC", active: !!states.currentHighlight, "aria-label": "\u30DE\u30FC\u30AB\u30FC", children: /* @__PURE__ */ jsx10(Icon, { name: "format_ink_highlighter" }) }) }),
1084
+ /* @__PURE__ */ jsx10(PopoverContent3, { "data-elevation": "3", children: /* @__PURE__ */ jsx10(
1085
+ MemoColorPicker,
1086
+ {
1087
+ color: states.currentHighlight,
1088
+ onChange: commands.onChangeHighlight,
1089
+ onClear: commands.onClearHighlight
1090
+ }
1091
+ ) })
1092
+ ] }),
1093
+ features?.textColor && /* @__PURE__ */ jsxs9(Popover3, { modal: true, placement: "top-start", children: [
1094
+ /* @__PURE__ */ jsx10(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsx10(MemoButton, { type: "button", active: !!states.currentColor, tooltip: "\u6587\u5B57\u8272", "aria-label": "\u6587\u5B57\u8272", children: /* @__PURE__ */ jsx10(Icon, { name: "format_color_text" }) }) }),
1095
+ /* @__PURE__ */ jsx10(PopoverContent3, { "data-elevation": "3", children: /* @__PURE__ */ jsx10(
1096
+ MemoColorPicker,
1097
+ {
1098
+ color: states.currentColor,
1099
+ onChange: commands.onChangeColor,
1100
+ onClear: commands.onClearColor
1101
+ }
1102
+ ) })
1103
+ ] }),
1104
+ features?.textSubscript && /* @__PURE__ */ jsx10(
1105
+ MemoButton,
1106
+ {
1107
+ type: "button",
1108
+ tooltip: "\u4E0B\u4ED8\u304D\u6587\u5B57",
1109
+ tooltipShortcut: SHORTCUT_SUBSCRIPT,
1110
+ onClick: commands.onSubscript,
1111
+ active: states.isSubscript,
1112
+ "aria-label": "\u4E0B\u4ED8\u304D\u6587\u5B57",
1113
+ children: /* @__PURE__ */ jsx10(Icon, { name: "subscript" })
1114
+ }
1115
+ ),
1116
+ features?.textSuperscript && /* @__PURE__ */ jsx10(
1117
+ MemoButton,
1118
+ {
1119
+ type: "button",
1120
+ tooltip: "\u4E0A\u4ED8\u304D\u6587\u5B57",
1121
+ tooltipShortcut: SHORTCUT_SUPERSCRIPT,
1122
+ onClick: commands.onSuperscript,
1123
+ active: states.isSuperscript,
1124
+ "aria-label": "\u4E0A\u4ED8\u304D\u6587\u5B57",
1125
+ children: /* @__PURE__ */ jsx10(Icon, { name: "superscript" })
1126
+ }
1127
+ ),
1128
+ features?.fontSize && /* @__PURE__ */ jsxs9(Fragment3, { children: [
1129
+ /* @__PURE__ */ jsx10(Toolbar.Divider, {}),
1130
+ /* @__PURE__ */ jsx10(MemoFontSizePicker, { onChange: commands.onSetFontSize, value: states.currentSize || "" })
1131
+ ] }),
1132
+ features?.fontFamily && /* @__PURE__ */ jsxs9(Fragment3, { children: [
1133
+ /* @__PURE__ */ jsx10(Toolbar.Divider, {}),
1134
+ /* @__PURE__ */ jsx10(MemoFontFamilyPicker, { onChange: commands.onSetFont, value: states.currentFont || "" })
1135
+ ] }),
1136
+ features?.customClass && /* @__PURE__ */ jsxs9(Fragment3, { children: [
1137
+ /* @__PURE__ */ jsx10(Toolbar.Divider, {}),
1138
+ /* @__PURE__ */ jsx10(
1139
+ MemoCustomClassPicker,
1140
+ {
1141
+ onChange: commands.onCustomClass,
1142
+ onRemove: commands.removeCustomClass,
1143
+ value: states.currentCustomClass || ""
1144
+ }
1145
+ )
1146
+ ] }),
1147
+ showLeft && /* @__PURE__ */ jsx10(
1148
+ "button",
1149
+ {
1150
+ type: "button",
1151
+ onClick: scrollLeft,
1152
+ "aria-label": "\u5DE6\u306B\u30B9\u30AF\u30ED\u30FC\u30EB",
1153
+ className: "acms-admin-block-editor-toolbar-arrow acms-admin-block-editor-toolbar-arrow-left",
1154
+ children: /* @__PURE__ */ jsx10(Icon, { name: "chevron_left" })
1155
+ }
1156
+ ),
1157
+ showRight && /* @__PURE__ */ jsx10(
1158
+ "button",
1159
+ {
1160
+ type: "button",
1161
+ onClick: scrollRight,
1162
+ "aria-label": "\u53F3\u306B\u30B9\u30AF\u30ED\u30FC\u30EB",
1163
+ className: "acms-admin-block-editor-toolbar-arrow acms-admin-block-editor-toolbar-arrow-right",
1164
+ children: /* @__PURE__ */ jsx10(Icon, { name: "chevron_right" })
1165
+ }
1166
+ )
1167
+ ]
1168
+ }
1169
+ )
1170
+ }
1171
+ );
1172
+ }
1173
+
1174
+ // src/components/menus/ContentItemMenu/ContentItemMenu.tsx
1175
+ import { useEffect as useEffect6, useRef as useRef5, useState as useState10, memo as memo2, useCallback as useCallback14 } from "react";
1176
+ import { DragHandle } from "@tiptap/extension-drag-handle-react";
1177
+ import { NodeSelection as NodeSelection2, TextSelection } from "@tiptap/pm/state";
1178
+ import { Menu as Menu6, MenuList as MenuList6, MenuItem as MenuItem5, MenuDivider, MenuPopover as MenuPopover6 } from "@ablogcms/components/dropdown-menu";
1179
+
1180
+ // src/components/menus/ContentItemMenu/hooks/useContentItemActions.tsx
1181
+ import { NodeSelection } from "@tiptap/pm/state";
1182
+ import { useCallback as useCallback12 } from "react";
1183
+ var useContentItemActions = (editor, currentNode, currentNodePos) => {
1184
+ const getCurrentNode = useCallback12(
1185
+ (curNodeProp, curNodePosProp) => {
1186
+ const { state } = editor;
1187
+ const { selection } = state;
1188
+ const { $from } = selection;
1189
+ let curNode = curNodeProp ?? null;
1190
+ let curPos = curNodePosProp ?? null;
1191
+ if (!curNode || !curPos) {
1192
+ if (selection instanceof NodeSelection) {
1193
+ curNode = selection.node;
1194
+ curPos = selection.from;
1195
+ } else {
1196
+ const depth = $from.depth >= 1 ? 1 : $from.depth;
1197
+ curNode = $from.node(depth);
1198
+ if (depth > 0) {
1199
+ curPos = $from.before(depth);
1200
+ } else {
1201
+ return {
1202
+ curNode: null,
1203
+ curPos: -1
1204
+ };
1205
+ }
1206
+ }
1207
+ }
1208
+ return {
1209
+ curNode,
1210
+ curPos
1211
+ };
1212
+ },
1213
+ [editor]
1214
+ );
1215
+ const resetTextFormatting = useCallback12(
1216
+ (curNodeProp, curNodePosProp) => {
1217
+ const { curNode, curPos } = getCurrentNode(curNodeProp, curNodePosProp);
1218
+ if (!curNode || curPos === -1) return;
1219
+ const chain = editor.chain();
1220
+ chain.setBlockAttrs(curPos, { id: null, class: null });
1221
+ chain.setNodeSelection(curPos).unsetAllMarks();
1222
+ if (curNode?.type.name !== "paragraph") {
1223
+ chain.focus().setParagraph();
1224
+ }
1225
+ chain.run();
1226
+ },
1227
+ [editor, getCurrentNode]
1228
+ );
1229
+ const duplicateNode = useCallback12(
1230
+ (curNodeProp, curNodePosProp) => {
1231
+ const { curNode, curPos } = getCurrentNode(curNodeProp, curNodePosProp);
1232
+ if (!curNode || curPos === -1) return;
1233
+ const nodeJSON = curNode.toJSON();
1234
+ editor.chain().setMeta("hideDragHandle", true).insertContentAt(curPos + (curNode?.nodeSize || 0), {
1235
+ type: nodeJSON.type,
1236
+ attrs: { ...nodeJSON.attrs, id: null },
1237
+ // ID属性を削除
1238
+ content: nodeJSON.content || []
1239
+ }).run();
1240
+ },
1241
+ [editor, getCurrentNode]
1242
+ );
1243
+ const copyNodeToClipboard = useCallback12(() => {
1244
+ const nodeText = currentNode?.textContent || "";
1245
+ navigator.clipboard.writeText(nodeText).catch((err) => {
1246
+ console.error("Clipboard copy failed:", err);
1247
+ });
1248
+ }, [currentNode]);
1249
+ const deleteNode = useCallback12(
1250
+ (curNodeProp, curNodePosProp) => {
1251
+ const { curNode, curPos } = getCurrentNode(curNodeProp, curNodePosProp);
1252
+ if (!curNode || curPos === -1) return;
1253
+ editor.chain().setMeta("hideDragHandle", true).setNodeSelection(curPos).deleteSelection().run();
1254
+ },
1255
+ [editor, getCurrentNode]
1256
+ );
1257
+ const handleAdd = useCallback12(() => {
1258
+ if (currentNodePos !== -1) {
1259
+ const currentNodeSize = currentNode?.nodeSize || 0;
1260
+ const insertPos = currentNodePos + currentNodeSize;
1261
+ const currentNodeIsEmptyParagraph = currentNode?.type.name === "paragraph" && currentNode?.content?.size === 0;
1262
+ const focusPos = currentNodeIsEmptyParagraph ? currentNodePos + 2 : insertPos + 2;
1263
+ editor.chain().command(({ dispatch, tr, state }) => {
1264
+ if (dispatch) {
1265
+ if (currentNodeIsEmptyParagraph) {
1266
+ tr.insertText("/", currentNodePos, currentNodePos + 1);
1267
+ } else {
1268
+ tr.insert(insertPos, state.schema.nodes.paragraph.create(null, [state.schema.text("/")]));
1269
+ }
1270
+ return dispatch(tr);
1271
+ }
1272
+ return true;
1273
+ }).focus(focusPos).run();
1274
+ }
1275
+ }, [currentNode, currentNodePos, editor]);
1276
+ const setHeadingId = useCallback12(
1277
+ (id) => {
1278
+ editor.chain().setBlockAttrs(currentNodePos, { id }).run();
1279
+ },
1280
+ [currentNodePos, editor]
1281
+ );
1282
+ const setBlockAttrs = useCallback12(
1283
+ (attrs) => {
1284
+ editor.chain().setBlockAttrs(currentNodePos, attrs).run();
1285
+ },
1286
+ [currentNodePos, editor]
1287
+ );
1288
+ const moveBlockUp = useCallback12(
1289
+ (curNodeProp, curNodePosProp) => {
1290
+ const { state } = editor;
1291
+ const { $from } = state.selection;
1292
+ const { curNode, curPos } = getCurrentNode(curNodeProp, curNodePosProp);
1293
+ if (!curNode || curPos === -1) return;
1294
+ const { nodeSize } = curNode;
1295
+ const index = $from.index(0);
1296
+ if (index === 0) return;
1297
+ const prevNode = state.doc.child(index - 1);
1298
+ if (!prevNode) return;
1299
+ const nodeJSON = curNode.toJSON();
1300
+ editor.chain().deleteRange({ from: curPos, to: curPos + nodeSize }).insertContentAt(curPos - prevNode.nodeSize, nodeJSON).run();
1301
+ },
1302
+ [editor, getCurrentNode]
1303
+ );
1304
+ const moveBlockDown = useCallback12(
1305
+ (curNodeProp, curNodePosProp) => {
1306
+ const { state } = editor;
1307
+ const { curNode, curPos } = getCurrentNode(curNodeProp, curNodePosProp);
1308
+ if (!curNode || curPos === -1) return;
1309
+ const { nodeSize } = curNode;
1310
+ const nextPos = curPos + nodeSize;
1311
+ const nextNode = state.doc.resolve(nextPos).nodeAfter;
1312
+ if (!nextNode) return;
1313
+ const nextNodeSize = nextNode.nodeSize;
1314
+ const nodeJSON = curNode.toJSON();
1315
+ editor.chain().deleteRange({ from: curPos, to: curPos + nodeSize }).insertContentAt(curPos + nextNodeSize, nodeJSON).run();
1316
+ },
1317
+ [editor, getCurrentNode]
1318
+ );
1319
+ return {
1320
+ resetTextFormatting,
1321
+ duplicateNode,
1322
+ copyNodeToClipboard,
1323
+ deleteNode,
1324
+ handleAdd,
1325
+ setHeadingId,
1326
+ setBlockAttrs,
1327
+ moveBlockUp,
1328
+ moveBlockDown
1329
+ };
1330
+ };
1331
+ var useContentItemActions_default = useContentItemActions;
1332
+
1333
+ // src/components/menus/ContentItemMenu/components/IdEditor.tsx
1334
+ import { useState as useState8 } from "react";
1335
+ import { ButtonV2 as ButtonV22 } from "@ablogcms/components/button-v2";
1336
+ import { Popover as Popover4, PopoverContent as PopoverContent4, PopoverTrigger as PopoverTrigger3 } from "@ablogcms/components/popover";
1337
+ import { MenuItem as MenuItem3 } from "@ablogcms/components/dropdown-menu";
1338
+ import { VStack } from "@ablogcms/components/stack";
1339
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1340
+ function IdEditor({ onChange, value }) {
1341
+ const [isOpen, setIsOpen] = useState8(false);
1342
+ const handleSubmit = (e) => {
1343
+ e.preventDefault();
1344
+ if (!(e.target instanceof HTMLFormElement)) {
1345
+ return;
1346
+ }
1347
+ const formData = new FormData(e.target);
1348
+ const id = formData.get("id");
1349
+ setIsOpen(false);
1350
+ onChange(id);
1351
+ };
1352
+ return /* @__PURE__ */ jsxs10(Popover4, { isOpen, onOpenChange: setIsOpen, modal: true, placement: "right", children: [
1353
+ /* @__PURE__ */ jsx11(PopoverTrigger3, { asChild: true, children: /* @__PURE__ */ jsxs10(MenuItem3, { icon: /* @__PURE__ */ jsx11(Icon, { name: "grid_3x3" }), onSelect: () => setIsOpen((prev) => !prev), closeOnSelect: false, children: [
1354
+ value || "ID\u3092\u8A2D\u5B9A",
1355
+ value && /* @__PURE__ */ jsx11("span", { style: { marginLeft: "auto" }, children: /* @__PURE__ */ jsx11(Icon, { name: "edit" }) })
1356
+ ] }) }),
1357
+ /* @__PURE__ */ jsx11(PopoverContent4, { "data-elevation": "3", className: "acms-admin-block-editor-id-editor", children: /* @__PURE__ */ jsx11("div", { children: /* @__PURE__ */ jsx11("form", { onSubmit: handleSubmit, className: "acms-admin-form", children: /* @__PURE__ */ jsxs10(VStack, { spacing: "0.5rem", align: "start", children: [
1358
+ /* @__PURE__ */ jsxs10(VStack, { align: "start", className: "acms-admin-width-max", children: [
1359
+ /* @__PURE__ */ jsx11("label", { htmlFor: "input-text-id-editor", children: "ID\u3092\u8A2D\u5B9A" }),
1360
+ /* @__PURE__ */ jsx11(
1361
+ "input",
1362
+ {
1363
+ id: "input-text-id-editor",
1364
+ name: "id",
1365
+ pattern: "^[a-zA-Z0-9_\\-]+$",
1366
+ type: "text",
1367
+ className: "acms-admin-form-width-full",
1368
+ defaultValue: value,
1369
+ onKeyDown: (e) => e.stopPropagation()
1370
+ }
1371
+ )
1372
+ ] }),
1373
+ /* @__PURE__ */ jsx11(ButtonV22, { variant: "filled", size: "small", type: "submit", children: "\u9069\u7528" })
1374
+ ] }) }) }) })
1375
+ ] });
1376
+ }
1377
+
1378
+ // src/components/menus/ContentItemMenu/components/BlockMenus.tsx
1379
+ import {
1380
+ Menu as Menu5,
1381
+ SubmenuTriggerItem,
1382
+ MenuList as MenuList5,
1383
+ MenuItem as MenuItem4,
1384
+ MenuGroup as MenuGroup5,
1385
+ MenuPopover as MenuPopover5
1386
+ } from "@ablogcms/components/dropdown-menu";
1387
+ import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
1388
+ function BlockMenus({ menus, editor, currentPos }) {
1389
+ const filteredCommands = useFilteredCommands(menus, editor, currentPos);
1390
+ return filteredCommands.length > 0 ? /* @__PURE__ */ jsxs11(Menu5, { children: [
1391
+ /* @__PURE__ */ jsx12(SubmenuTriggerItem, { icon: /* @__PURE__ */ jsx12(Icon, { name: "sync" }), children: "\u30D6\u30ED\u30C3\u30AF\u30BF\u30A4\u30D7\u5909\u63DB" }),
1392
+ /* @__PURE__ */ jsx12(MenuPopover5, { "data-elevation": "3", children: /* @__PURE__ */ jsx12(MenuList5, { children: filteredCommands.map((group) => /* @__PURE__ */ jsx12(MenuGroup5, { title: group.title, children: group.commands.map((command) => /* @__PURE__ */ jsx12(
1393
+ MenuItem4,
1394
+ {
1395
+ icon: /* @__PURE__ */ jsx12(Icon, { name: command.iconName }),
1396
+ onSelect: command.convert ? () => command.convert(editor, currentPos) : () => {
1397
+ },
1398
+ children: command.label
1399
+ },
1400
+ `${command.name}_${command.label}`
1401
+ )) }, group.title)) }) })
1402
+ ] }) : null;
1403
+ }
1404
+
1405
+ // src/components/menus/ContentItemMenu/hooks/useData.tsx
1406
+ import { useCallback as useCallback13, useState as useState9 } from "react";
1407
+ var useData = () => {
1408
+ const [currentNode, setCurrentNode] = useState9(null);
1409
+ const [currentNodePos, setCurrentNodePos] = useState9(-1);
1410
+ const handleNodeChange = useCallback13(
1411
+ (data) => {
1412
+ if (data.node) {
1413
+ setCurrentNode(data.node);
1414
+ }
1415
+ setCurrentNodePos(data.pos);
1416
+ },
1417
+ [setCurrentNodePos, setCurrentNode]
1418
+ );
1419
+ return {
1420
+ currentNode,
1421
+ currentNodePos,
1422
+ setCurrentNode,
1423
+ setCurrentNodePos,
1424
+ handleNodeChange
1425
+ };
1426
+ };
1427
+
1428
+ // src/components/menus/ContentItemMenu/ContentItemMenu.tsx
1429
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
1430
+ function ContentItemMenu({ editor, getFilteredBlockMenus }) {
1431
+ const menuAnchorRef = useRef5(null);
1432
+ const [menuOpen, setMenuOpen] = useState10(false);
1433
+ const viewDom = useEditorViewDom(editor);
1434
+ const { currentNode, currentNodePos, handleNodeChange } = useData();
1435
+ const actions = useContentItemActions_default(editor, currentNode, currentNodePos);
1436
+ const MemoIdEditor = memo2(IdEditor);
1437
+ const MemoBlockMenus = memo2(BlockMenus);
1438
+ const getAnchorRect = useCallback14(() => menuAnchorRef.current.getBoundingClientRect(), []);
1439
+ useEffect6(() => {
1440
+ const dom = viewDom;
1441
+ if (dom === null) {
1442
+ return void 0;
1443
+ }
1444
+ const handleKeyDown = (e) => {
1445
+ const isMod = e.metaKey || e.ctrlKey;
1446
+ if (isMod && e.altKey && e.key === "ArrowUp") {
1447
+ e.preventDefault();
1448
+ e.stopPropagation();
1449
+ actions.moveBlockUp();
1450
+ }
1451
+ if (isMod && e.altKey && e.key === "ArrowDown") {
1452
+ e.preventDefault();
1453
+ e.stopPropagation();
1454
+ actions.moveBlockDown();
1455
+ }
1456
+ if (isMod && e.shiftKey && e.key.toLowerCase() === "d") {
1457
+ e.preventDefault();
1458
+ e.stopPropagation();
1459
+ actions.duplicateNode();
1460
+ }
1461
+ if (isMod && e.shiftKey && e.key.toLowerCase() === "x") {
1462
+ e.preventDefault();
1463
+ e.stopPropagation();
1464
+ actions.resetTextFormatting();
1465
+ }
1466
+ if (isMod && e.shiftKey && e.key.toLowerCase() === "backspace") {
1467
+ e.preventDefault();
1468
+ e.stopPropagation();
1469
+ actions.deleteNode();
1470
+ }
1471
+ };
1472
+ dom.addEventListener("keydown", handleKeyDown);
1473
+ return () => dom.removeEventListener("keydown", handleKeyDown);
1474
+ }, [viewDom, actions]);
1475
+ const onChangeId = useCallback14(
1476
+ (id) => {
1477
+ actions.setHeadingId(id);
1478
+ },
1479
+ [actions]
1480
+ );
1481
+ return /* @__PURE__ */ jsx13(DragHandle, { pluginKey: "ContentItemMenu", editor, onNodeChange: handleNodeChange, children: /* @__PURE__ */ jsxs12("div", { className: "acms-admin-block-editor-content-item-menu", children: [
1482
+ /* @__PURE__ */ jsx13(
1483
+ Toolbar.Button,
1484
+ {
1485
+ type: "button",
1486
+ size: "small",
1487
+ variant: "secondary",
1488
+ onClick: actions.handleAdd,
1489
+ "aria-label": "\u65B0\u898F\u30D6\u30ED\u30C3\u30AF\u3092\u8FFD\u52A0",
1490
+ children: /* @__PURE__ */ jsx13(Icon, { name: "add" })
1491
+ }
1492
+ ),
1493
+ /* @__PURE__ */ jsxs12(
1494
+ Menu6,
1495
+ {
1496
+ isOpen: menuOpen,
1497
+ onOpenChange: (open) => {
1498
+ setMenuOpen(open);
1499
+ editor.commands.setMeta("lockDragHandle", open);
1500
+ },
1501
+ getAnchorRect,
1502
+ children: [
1503
+ /* @__PURE__ */ jsx13(
1504
+ Toolbar.Button,
1505
+ {
1506
+ type: "button",
1507
+ size: "small",
1508
+ variant: "secondary",
1509
+ ref: menuAnchorRef,
1510
+ "aria-label": "\u30D6\u30ED\u30C3\u30AF\u30E1\u30CB\u30E5\u30FC\u3092\u958B\u304F",
1511
+ onClick: () => {
1512
+ const { state } = editor;
1513
+ const { tr } = state;
1514
+ const node = editor.state.doc.nodeAt(currentNodePos);
1515
+ if (!node) return;
1516
+ if (node.isTextblock) {
1517
+ const textSelection = TextSelection.create(state.doc, currentNodePos + 1);
1518
+ editor.view.dispatch(tr.setSelection(textSelection).scrollIntoView());
1519
+ } else {
1520
+ const nodeSelection = NodeSelection2.create(state.doc, currentNodePos);
1521
+ editor.view.dispatch(tr.setSelection(nodeSelection).scrollIntoView());
1522
+ }
1523
+ const newOpen = !menuOpen;
1524
+ setMenuOpen(newOpen);
1525
+ editor.commands.setMeta("lockDragHandle", newOpen);
1526
+ },
1527
+ children: /* @__PURE__ */ jsx13(Icon, { name: "drag_indicator" })
1528
+ }
1529
+ ),
1530
+ /* @__PURE__ */ jsx13(MenuPopover6, { size: "large", "data-elevation": "3", children: /* @__PURE__ */ jsxs12(MenuList6, { children: [
1531
+ /* @__PURE__ */ jsx13(
1532
+ MemoBlockMenus,
1533
+ {
1534
+ menus: getFilteredBlockMenus({ query: "", editor }),
1535
+ editor,
1536
+ currentPos: currentNodePos
1537
+ }
1538
+ ),
1539
+ /* @__PURE__ */ jsx13(
1540
+ MenuItem5,
1541
+ {
1542
+ icon: /* @__PURE__ */ jsx13(Icon, { name: "keyboard_arrow_up" }),
1543
+ shortcut: ["Mod", "Alt", "ArrowUp"],
1544
+ onSelect: () => actions.moveBlockUp(currentNode, currentNodePos),
1545
+ children: "\u4E0A\u306B\u79FB\u52D5"
1546
+ }
1547
+ ),
1548
+ /* @__PURE__ */ jsx13(
1549
+ MenuItem5,
1550
+ {
1551
+ icon: /* @__PURE__ */ jsx13(Icon, { name: "keyboard_arrow_down" }),
1552
+ shortcut: ["Mod", "Alt", "ArrowDown"],
1553
+ onSelect: () => actions.moveBlockDown(currentNode, currentNodePos),
1554
+ children: "\u4E0B\u306B\u79FB\u52D5"
1555
+ }
1556
+ ),
1557
+ /* @__PURE__ */ jsx13(
1558
+ MenuItem5,
1559
+ {
1560
+ icon: /* @__PURE__ */ jsx13(Icon, { name: "library_add" }),
1561
+ shortcut: ["Mod", "Shift", "D"],
1562
+ onSelect: () => actions.duplicateNode(currentNode, currentNodePos),
1563
+ children: "\u8907\u88FD"
1564
+ }
1565
+ ),
1566
+ /* @__PURE__ */ jsx13(MenuItem5, { icon: /* @__PURE__ */ jsx13(Icon, { name: "content_copy" }), onSelect: actions.copyNodeToClipboard, children: "\u30B3\u30D4\u30FC" }),
1567
+ /* @__PURE__ */ jsx13(
1568
+ MenuItem5,
1569
+ {
1570
+ icon: /* @__PURE__ */ jsx13(Icon, { name: "format_clear" }),
1571
+ shortcut: ["Mod", "Shift", "X"],
1572
+ onSelect: () => actions.resetTextFormatting(currentNode, currentNodePos),
1573
+ children: "\u66F8\u5F0F\u3092\u30AF\u30EA\u30A2"
1574
+ }
1575
+ ),
1576
+ /* @__PURE__ */ jsx13(
1577
+ MenuItem5,
1578
+ {
1579
+ variant: "danger",
1580
+ icon: /* @__PURE__ */ jsx13(Icon, { name: "delete" }),
1581
+ shortcut: ["Mod", "Shift", "Backspace"],
1582
+ onSelect: () => actions.deleteNode(currentNode, currentNodePos),
1583
+ children: "\u524A\u9664"
1584
+ }
1585
+ ),
1586
+ /* @__PURE__ */ jsx13(MenuDivider, {}),
1587
+ /* @__PURE__ */ jsx13(MemoIdEditor, { onChange: onChangeId, value: currentNode?.attrs.id })
1588
+ ] }) })
1589
+ ]
1590
+ }
1591
+ )
1592
+ ] }) });
1593
+ }
1594
+
1595
+ // src/hooks/useBlockEditor.ts
1596
+ import { useEditor } from "@tiptap/react";
1597
+ import { useMemo as useMemo8, useRef as useRef6 } from "react";
1598
+
1599
+ // src/extensions/BaseBlock/BaseBlock.ts
1600
+ import { Extension } from "@tiptap/core";
1601
+ import { Plugin, TextSelection as TextSelection2 } from "@tiptap/pm/state";
1602
+ var BlockAttributes = Extension.create({
1603
+ name: "blockAttributes",
1604
+ addGlobalAttributes() {
1605
+ return [
1606
+ {
1607
+ types: [
1608
+ "heading",
1609
+ "paragraph",
1610
+ "bulletList",
1611
+ "orderedList",
1612
+ "MediaUpload",
1613
+ "imageBlock",
1614
+ "fileBlock",
1615
+ "linkButton",
1616
+ "table",
1617
+ "blockquote",
1618
+ "codeBlock",
1619
+ "bulletList",
1620
+ "orderedList",
1621
+ "horizontalRule",
1622
+ "columns"
1623
+ ],
1624
+ attributes: {
1625
+ id: {
1626
+ default: null,
1627
+ parseHTML: (element) => element.getAttribute("id"),
1628
+ renderHTML: (attributes) => attributes.id ? { id: attributes.id } : {},
1629
+ keepOnSplit: false
1630
+ // コピー&ペースト時に属性を保持しない
1631
+ },
1632
+ class: {
1633
+ default: null,
1634
+ parseHTML: (element) => element.getAttribute("class"),
1635
+ renderHTML: (attributes) => attributes.class ? { class: attributes.class } : {}
1636
+ }
1637
+ }
1638
+ }
1639
+ ];
1640
+ },
1641
+ addCommands() {
1642
+ return {
1643
+ // ノードの属性を設定する
1644
+ setBlockAttrs: (pos, attrs) => ({ state, dispatch }) => {
1645
+ const { tr, selection } = state;
1646
+ const { $from } = selection;
1647
+ let targetPos;
1648
+ if (typeof pos === "number") {
1649
+ targetPos = pos;
1650
+ } else if ($from.depth > 0) {
1651
+ targetPos = $from.before(1);
1652
+ } else {
1653
+ targetPos = null;
1654
+ }
1655
+ if (targetPos === null) return false;
1656
+ const node = state.doc.nodeAt(targetPos);
1657
+ if (!node || !dispatch) return false;
1658
+ if (node && dispatch) {
1659
+ dispatch(tr.setNodeMarkup(targetPos, void 0, { ...node.attrs, ...attrs }));
1660
+ return true;
1661
+ }
1662
+ return false;
1663
+ }
1664
+ };
1665
+ },
1666
+ addProseMirrorPlugins() {
1667
+ const isMac = typeof navigator !== "undefined" && /Mac/.test(navigator.platform);
1668
+ return [
1669
+ new Plugin({
1670
+ props: {
1671
+ handlePaste(view, event) {
1672
+ const { state, dispatch } = view;
1673
+ const { selection } = state;
1674
+ const { parent } = selection.$from;
1675
+ if (parent.type.name === "codeBlock") {
1676
+ const text = event.clipboardData?.getData("text/plain");
1677
+ if (text) {
1678
+ dispatch(state.tr.insertText(text, selection.from, selection.to));
1679
+ return true;
1680
+ }
1681
+ }
1682
+ return false;
1683
+ },
1684
+ handleKeyDown(view, event) {
1685
+ const { state, dispatch } = view;
1686
+ const { selection } = state;
1687
+ const { $from } = selection;
1688
+ if ($from.parent.type.name !== "codeBlock") return false;
1689
+ if (event.metaKey && event.key === "a" || !isMac && event.ctrlKey && event.key === "a") {
1690
+ event.preventDefault();
1691
+ const start = $from.start();
1692
+ const end = $from.end();
1693
+ dispatch(state.tr.setSelection(TextSelection2.create(state.doc, start, end)));
1694
+ return true;
1695
+ }
1696
+ if (isMac && event.ctrlKey && event.key === "a") {
1697
+ event.preventDefault();
1698
+ const pos = selection.from;
1699
+ const textBefore = $from.parent.textContent.slice(0, $from.parentOffset);
1700
+ const offsetToLineStart = textBefore.lastIndexOf("\n") + 1;
1701
+ const newPos = pos - ($from.parentOffset - offsetToLineStart);
1702
+ dispatch(state.tr.setSelection(TextSelection2.create(state.doc, newPos)));
1703
+ return true;
1704
+ }
1705
+ if (isMac && event.ctrlKey && event.key === "e") {
1706
+ event.preventDefault();
1707
+ const pos = selection.from;
1708
+ const parentText = $from.parent.textContent;
1709
+ const offsetToLineEnd = parentText.indexOf("\n", $from.parentOffset);
1710
+ const lineEndOffset = offsetToLineEnd === -1 ? parentText.length : offsetToLineEnd;
1711
+ const lineEndPos = pos + (lineEndOffset - $from.parentOffset);
1712
+ dispatch(state.tr.setSelection(TextSelection2.create(state.doc, lineEndPos)));
1713
+ return true;
1714
+ }
1715
+ return false;
1716
+ }
1717
+ }
1718
+ })
1719
+ ];
1720
+ }
1721
+ });
1722
+
1723
+ // src/extensions/extension-kit.ts
1724
+ import { UndoRedo } from "@tiptap/extensions";
1725
+ var ExtensionKit = ({ getImageDefaultLightbox } = {}) => {
1726
+ return [
1727
+ StarterKit.configure({
1728
+ document: false,
1729
+ dropcursor: false,
1730
+ heading: false,
1731
+ horizontalRule: false,
1732
+ undoRedo: false,
1733
+ // v3 の StarterKit は Link / Underline / ListKeymap / TrailingNode を新たに同梱するため、
1734
+ // 下記で個別登録している独自拡張・独自設定と二重登録にならないよう無効化する
1735
+ link: false,
1736
+ underline: false,
1737
+ trailingNode: false,
1738
+ listKeymap: false
1739
+ }),
1740
+ UndoRedo,
1741
+ Document,
1742
+ Columns,
1743
+ Column,
1744
+ Selection,
1745
+ Heading.configure({
1746
+ levels: [1, 2, 3, 4, 5, 6]
1747
+ }),
1748
+ HorizontalRule,
1749
+ TextStyle,
1750
+ FontStyle,
1751
+ TrailingNode,
1752
+ Link.configure({
1753
+ openOnClick: false,
1754
+ isAllowedUri: (url, { protocols }) => !!isAllowedBlockEditorLinkUri(url, protocols),
1755
+ HTMLAttributes: {
1756
+ // Change rel to different value
1757
+ // Allow search engines to follow links(remove nofollow)
1758
+ rel: "noopener noreferrer",
1759
+ // Remove target entirely so links open in current tab
1760
+ target: null
1761
+ }
1762
+ }),
1763
+ Highlight.configure({ multicolor: true }),
1764
+ Underline,
1765
+ MediaUpload,
1766
+ CustomMark,
1767
+ CustomConvertBlock,
1768
+ ImageBlock.configure({
1769
+ getImageDefaultLightbox: getImageDefaultLightbox ?? (() => true)
1770
+ }),
1771
+ FileBlock,
1772
+ PasteHandler,
1773
+ LinkButton,
1774
+ TextAlign.extend({
1775
+ addKeyboardShortcuts() {
1776
+ return {};
1777
+ }
1778
+ }).configure({
1779
+ types: ["heading", "paragraph"]
1780
+ }),
1781
+ Subscript,
1782
+ Superscript,
1783
+ Table,
1784
+ TableCell,
1785
+ TableHeader,
1786
+ TableRow,
1787
+ Typography,
1788
+ Placeholder.configure({
1789
+ includeChildren: true,
1790
+ showOnlyCurrent: false,
1791
+ placeholder: () => ""
1792
+ }),
1793
+ Focus,
1794
+ Figcaption,
1795
+ Dropcursor.configure({
1796
+ width: 4,
1797
+ color: "#a3c0ef",
1798
+ class: "acms-admin-dropcursor"
1799
+ })
1800
+ ];
1801
+ };
1802
+
1803
+ // src/hooks/useBlockEditor.ts
1804
+ var useBlockEditor = ({
1805
+ defaultValue = "",
1806
+ onUpdate = () => {
1807
+ },
1808
+ blockMenus = [],
1809
+ imageDefaultLightbox = true,
1810
+ extensions: extraExtensions,
1811
+ blockDefinitions,
1812
+ ...editorOptions
1813
+ }) => {
1814
+ const { getFilteredBlockMenus } = useBlockMenus({ blockMenus, blockDefinitions });
1815
+ const getItemsRef = useRef6(getFilteredBlockMenus);
1816
+ getItemsRef.current = getFilteredBlockMenus;
1817
+ const imageDefaultLightboxRef = useRef6(imageDefaultLightbox);
1818
+ imageDefaultLightboxRef.current = imageDefaultLightbox;
1819
+ const extensions = useMemo8(
1820
+ () => [
1821
+ ...ExtensionKit({ getImageDefaultLightbox: () => imageDefaultLightboxRef.current }),
1822
+ BlockAttributes,
1823
+ SlashCommand_default.configure({
1824
+ getItems: ({ query, editor: editor2 }) => getItemsRef.current({ query, editor: editor2 })
1825
+ }),
1826
+ ...extraExtensions ?? []
1827
+ ],
1828
+ // Tiptap は動的な拡張変更をサポートしないため、初回マウント時に確定する既存設計を踏襲する(extraExtensions も同様)
1829
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1830
+ []
1831
+ );
1832
+ const editor = useEditor(
1833
+ {
1834
+ autofocus: false,
1835
+ // v3 は既定で false(トランザクション毎の再描画を行わない)。
1836
+ // TextMenu/ContentItemMenu 等が editor.isActive()/getAttributes() を再描画のたびに
1837
+ // 直接参照する v2 由来の設計のため、これまで通り毎トランザクション再描画する挙動を維持する。
1838
+ shouldRerenderOnTransaction: true,
1839
+ onCreate: ({ editor: editor2 }) => {
1840
+ if (editor2.isEmpty) {
1841
+ editor2.commands.setContent(defaultValue || "");
1842
+ }
1843
+ },
1844
+ onUpdate: ({ editor: editor2 }) => {
1845
+ const html = editor2.getHTML();
1846
+ onUpdate(html);
1847
+ },
1848
+ extensions,
1849
+ ...editorOptions,
1850
+ editorProps: {
1851
+ ...editorOptions.editorProps,
1852
+ attributes: (...args) => {
1853
+ const attributes = {
1854
+ autocomplete: "off",
1855
+ autocorrect: "off",
1856
+ autocapitalize: "off"
1857
+ };
1858
+ const overrideAttributes = typeof editorOptions.editorProps?.attributes === "function" ? editorOptions.editorProps.attributes(...args) : editorOptions.editorProps?.attributes;
1859
+ return {
1860
+ ...attributes,
1861
+ ...overrideAttributes
1862
+ };
1863
+ }
1864
+ }
1865
+ },
1866
+ []
1867
+ );
1868
+ return { editor, getFilteredBlockMenus };
1869
+ };
1870
+
1871
+ // src/extensions/Table/menus/TableMenu/index.tsx
1872
+ import { BubbleMenu as BaseBubbleMenu2 } from "@tiptap/react/menus";
1873
+ import { useCallback as useCallback16, useMemo as useMemo9, useRef as useRef7, useState as useState11 } from "react";
1874
+ import { v4 as uuid } from "uuid";
1875
+ import { Popover as Popover5, PopoverTrigger as PopoverTrigger4, PopoverContent as PopoverContent5 } from "@ablogcms/components/popover";
1876
+
1877
+ // src/extensions/Table/menus/TableColumn/utils.ts
1878
+ var isColumnGripSelected = ({ editor, view, from }) => {
1879
+ const domAtPos = view.domAtPos(from).node;
1880
+ const nodeDOM = view.nodeDOM(from);
1881
+ const node = nodeDOM || domAtPos;
1882
+ if (!editor.isActive(Table.name) || !node) {
1883
+ return false;
1884
+ }
1885
+ let container = node;
1886
+ while (container && !["TD", "TH"].includes(container.tagName)) {
1887
+ container = container.parentElement;
1888
+ }
1889
+ const gripColumn = container && container.querySelector && container.querySelector("button.grip-column.selected");
1890
+ return !!gripColumn;
1891
+ };
1892
+
1893
+ // src/extensions/Table/menus/TableRow/utils.ts
1894
+ var isRowGripSelected = ({ editor, view, from }) => {
1895
+ const domAtPos = view.domAtPos(from).node;
1896
+ const nodeDOM = view.nodeDOM(from);
1897
+ const node = nodeDOM || domAtPos;
1898
+ if (!editor.isActive(Table.name) || !node) {
1899
+ return false;
1900
+ }
1901
+ let container = node;
1902
+ while (container && !["TD", "TH"].includes(container.tagName)) {
1903
+ container = container.parentElement;
1904
+ }
1905
+ const gripRow = container && container.querySelector && container.querySelector("button.grip-row.selected");
1906
+ return !!gripRow;
1907
+ };
1908
+
1909
+ // src/extensions/Table/menus/hooks.ts
1910
+ import { useCallback as useCallback15 } from "react";
1911
+ var useTableStyle = (editor) => {
1912
+ const handleSetBgColor = useCallback15(
1913
+ (color) => {
1914
+ editor.chain().setCellBackgroundColor(color).run();
1915
+ editor.chain().setHeaderBackgroundColor(color).run();
1916
+ },
1917
+ [editor]
1918
+ );
1919
+ const handleClearBgColor = useCallback15(() => {
1920
+ editor.chain().setCellBackgroundColor("").run();
1921
+ editor.chain().setHeaderBackgroundColor("").run();
1922
+ }, [editor]);
1923
+ return {
1924
+ handleSetBgColor,
1925
+ handleClearBgColor
1926
+ };
1927
+ };
1928
+
1929
+ // src/extensions/Table/menus/TableMenu/index.tsx
1930
+ import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
1931
+ function TableMenu({ editor, appendTo }) {
1932
+ const menuRef = useRef7(null);
1933
+ const pluginKeyRef = useRef7(`table-menu-${uuid()}`);
1934
+ const [isOpen, setIsOpen] = useState11(false);
1935
+ const { handleSetBgColor, handleClearBgColor } = useTableStyle(editor);
1936
+ const { features } = useSettingsContext();
1937
+ const shouldShow = useCallback16(
1938
+ ({ view, state, from }) => {
1939
+ if (!state || !from) {
1940
+ return false;
1941
+ }
1942
+ const hasTextSelection = !state.selection.empty && !isCellSelection(state.selection);
1943
+ return editor.isActive("table") && !hasTextSelection && !isColumnGripSelected({ editor, view, from: from || 0 }) && !isRowGripSelected({ editor, view, from });
1944
+ },
1945
+ [editor]
1946
+ );
1947
+ const bubbleMenuAppendTo = useCallback16(() => appendTo?.current, [appendTo]);
1948
+ const getReferencedVirtualElement = useCallback16(() => {
1949
+ const { view } = editor;
1950
+ const { state } = editor;
1951
+ const { $from } = state.selection;
1952
+ for (let { depth } = $from; depth > 0; depth--) {
1953
+ const node = $from.node(depth);
1954
+ if (node.type.name === "table") {
1955
+ const pos = $from.before(depth);
1956
+ const dom = view.nodeDOM(pos);
1957
+ if (dom instanceof HTMLElement) {
1958
+ return { getBoundingClientRect: () => dom.getBoundingClientRect() };
1959
+ }
1960
+ }
1961
+ }
1962
+ const rect = editor.view.dom.getBoundingClientRect();
1963
+ return { getBoundingClientRect: () => rect };
1964
+ }, [editor]);
1965
+ const bubbleMenuStyle = useMemo9(() => ({ zIndex: 100019 }), []);
1966
+ const bubbleMenuOptions = useMemo9(() => ({ offset: 15, flip: true }), []);
1967
+ return /* @__PURE__ */ jsx14(
1968
+ BaseBubbleMenu2,
1969
+ {
1970
+ editor,
1971
+ pluginKey: pluginKeyRef.current,
1972
+ shouldShow,
1973
+ updateDelay: 0,
1974
+ appendTo: bubbleMenuAppendTo,
1975
+ style: bubbleMenuStyle,
1976
+ getReferencedVirtualElement,
1977
+ options: bubbleMenuOptions,
1978
+ children: /* @__PURE__ */ jsxs13(Toolbar, { ref: menuRef, children: [
1979
+ /* @__PURE__ */ jsx14(
1980
+ Toolbar.Button,
1981
+ {
1982
+ type: "button",
1983
+ tooltip: "\u30BB\u30EB\u3092\u7D50\u5408",
1984
+ "aria-label": "\u30BB\u30EB\u3092\u7D50\u5408",
1985
+ onClick: () => editor.chain().focus().mergeCells().run(),
1986
+ children: /* @__PURE__ */ jsx14(Icon, { name: "cell_merge" })
1987
+ }
1988
+ ),
1989
+ /* @__PURE__ */ jsx14(
1990
+ Toolbar.Button,
1991
+ {
1992
+ type: "button",
1993
+ tooltip: "\u30BB\u30EB\u3092\u5206\u96E2",
1994
+ "aria-label": "\u30BB\u30EB\u3092\u5206\u96E2",
1995
+ onClick: () => editor.chain().focus().splitCell().run(),
1996
+ children: /* @__PURE__ */ jsx14(Icon, { name: "arrows_outward" })
1997
+ }
1998
+ ),
1999
+ /* @__PURE__ */ jsx14(
2000
+ Toolbar.Button,
2001
+ {
2002
+ type: "button",
2003
+ tooltip: "\u30B9\u30AF\u30ED\u30FC\u30EB\u3055\u305B\u308B",
2004
+ "aria-label": "\u30C6\u30FC\u30D6\u30EB\u3092\u30B9\u30AF\u30ED\u30FC\u30EB\u3055\u305B\u308B",
2005
+ active: editor.getAttributes("table").scrollable,
2006
+ onClick: () => editor.chain().focus().toggleTableScrollable().run(),
2007
+ children: /* @__PURE__ */ jsx14(Icon, { name: "swipe" })
2008
+ }
2009
+ ),
2010
+ features?.tableBgColor && /* @__PURE__ */ jsxs13(Popover5, { modal: true, isOpen, onOpenChange: setIsOpen, placement: "top", children: [
2011
+ /* @__PURE__ */ jsx14(Toolbar.Divider, {}),
2012
+ /* @__PURE__ */ jsx14(PopoverTrigger4, { asChild: true, children: /* @__PURE__ */ jsx14(
2013
+ Toolbar.Button,
2014
+ {
2015
+ type: "button",
2016
+ tooltip: "\u30BB\u30EB\u306E\u80CC\u666F\u8272",
2017
+ active: false,
2018
+ "aria-label": "\u30BB\u30EB\u306E\u80CC\u666F\u8272\u3092\u8A2D\u5B9A",
2019
+ onClick: () => setIsOpen((prev) => !prev),
2020
+ children: /* @__PURE__ */ jsx14(Icon, { name: "format_color_fill" })
2021
+ }
2022
+ ) }),
2023
+ /* @__PURE__ */ jsx14(PopoverContent5, { "data-elevation": "3", children: /* @__PURE__ */ jsx14(
2024
+ ColorPicker,
2025
+ {
2026
+ onChange: (color) => {
2027
+ if (/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(color)) {
2028
+ handleSetBgColor(color);
2029
+ }
2030
+ },
2031
+ onClear: () => {
2032
+ handleClearBgColor();
2033
+ setIsOpen(false);
2034
+ }
2035
+ }
2036
+ ) })
2037
+ ] })
2038
+ ] })
2039
+ }
2040
+ );
2041
+ }
2042
+
2043
+ // src/extensions/Table/menus/TableColumn/index.tsx
2044
+ import { BubbleMenu as BaseBubbleMenu3 } from "@tiptap/react/menus";
2045
+ import React, { useCallback as useCallback17, useMemo as useMemo10, useState as useState12 } from "react";
2046
+ import { Menu as Menu7, MenuList as MenuList7, MenuItem as MenuItem7, MenuPopover as MenuPopover7, MenuDivider as MenuDivider2 } from "@ablogcms/components/dropdown-menu";
2047
+
2048
+ // src/extensions/Table/menus/ColorPicker.tsx
2049
+ import { memo as memo3, useRef as useRef8 } from "react";
2050
+ import { MenuItem as MenuItem6 } from "@ablogcms/components/dropdown-menu";
2051
+ import { Popover as Popover6, PopoverTrigger as PopoverTrigger5, PopoverContent as PopoverContent6 } from "@ablogcms/components/popover";
2052
+ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
2053
+ var TableColorPicker = memo3(({ editor }) => {
2054
+ const popoverRef = useRef8(null);
2055
+ const { handleSetBgColor, handleClearBgColor } = useTableStyle(editor);
2056
+ return /* @__PURE__ */ jsxs14(Popover6, { ref: popoverRef, modal: true, placement: "bottom-start", children: [
2057
+ /* @__PURE__ */ jsx15(PopoverTrigger5, { asChild: true, children: /* @__PURE__ */ jsx15(MenuItem6, { icon: /* @__PURE__ */ jsx15(Icon, { name: "format_color_fill" }), onSelect: () => popoverRef.current?.togglePopover(), children: "\u80CC\u666F\u8272" }) }),
2058
+ /* @__PURE__ */ jsx15(PopoverContent6, { "data-elevation": "3", children: /* @__PURE__ */ jsx15(
2059
+ ColorPicker,
2060
+ {
2061
+ onChange: (color) => {
2062
+ if (/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(color)) {
2063
+ handleSetBgColor(color);
2064
+ }
2065
+ },
2066
+ onClear: () => {
2067
+ handleClearBgColor();
2068
+ }
2069
+ }
2070
+ ) })
2071
+ ] });
2072
+ });
2073
+ TableColorPicker.displayName = "TableColorPicker";
2074
+
2075
+ // src/extensions/Table/menus/TableColumn/index.tsx
2076
+ import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
2077
+ var TableColumnMenu = React.memo(({ editor, appendTo }) => {
2078
+ const { features } = useSettingsContext();
2079
+ const [isOpen, setIsOpen] = useState12(false);
2080
+ const [menuRect, setMenuRect] = useState12(null);
2081
+ const shouldShow = useCallback17(
2082
+ ({ view, state, from }) => {
2083
+ if (!state) {
2084
+ setIsOpen(false);
2085
+ return false;
2086
+ }
2087
+ const show = isColumnGripSelected({ editor, view, from: from || 0 });
2088
+ setIsOpen(show);
2089
+ return show;
2090
+ },
2091
+ [editor]
2092
+ );
2093
+ const bubbleMenuAppendTo = useCallback17(() => appendTo?.current, [appendTo]);
2094
+ const getReferencedVirtualElement = useCallback17(() => {
2095
+ const { view } = editor;
2096
+ const { state } = editor;
2097
+ const { $from } = state.selection;
2098
+ const pos = $from.before($from.depth);
2099
+ const dom = view.nodeDOM(pos);
2100
+ if (dom instanceof HTMLElement) {
2101
+ const rect2 = dom.getBoundingClientRect();
2102
+ setMenuRect(rect2);
2103
+ return { getBoundingClientRect: () => rect2 };
2104
+ }
2105
+ const rect = editor.view.dom.getBoundingClientRect();
2106
+ setMenuRect(rect);
2107
+ return { getBoundingClientRect: () => rect };
2108
+ }, [editor]);
2109
+ const bubbleMenuStyle = useMemo10(() => ({ zIndex: 100019 }), []);
2110
+ const bubbleMenuOptions = useMemo10(() => ({ placement: "bottom-end", offset: 15, flip: false }), []);
2111
+ return /* @__PURE__ */ jsx16(
2112
+ BaseBubbleMenu3,
2113
+ {
2114
+ editor,
2115
+ pluginKey: "tableColumnMenu",
2116
+ updateDelay: 0,
2117
+ appendTo: bubbleMenuAppendTo,
2118
+ style: bubbleMenuStyle,
2119
+ getReferencedVirtualElement,
2120
+ options: bubbleMenuOptions,
2121
+ shouldShow,
2122
+ children: /* @__PURE__ */ jsx16(Menu7, { isOpen, getAnchorRect: () => menuRect, children: /* @__PURE__ */ jsx16(MenuPopover7, { size: "small", "data-elevation": "3", children: /* @__PURE__ */ jsxs15(MenuList7, { children: [
2123
+ /* @__PURE__ */ jsx16(
2124
+ MenuItem7,
2125
+ {
2126
+ icon: /* @__PURE__ */ jsx16(Icon, { name: "splitscreen_left" }),
2127
+ onSelect: () => editor.chain().focus().toggleHeaderCell().run(),
2128
+ children: "\u5217\u898B\u51FA\u3057"
2129
+ }
2130
+ ),
2131
+ /* @__PURE__ */ jsx16(MenuDivider2, {}),
2132
+ /* @__PURE__ */ jsx16(MenuItem7, { icon: /* @__PURE__ */ jsx16(Icon, { name: "arrow_back" }), onSelect: () => editor.chain().focus().addColumnBefore().run(), children: "\u5DE6\u306B\u633F\u5165" }),
2133
+ /* @__PURE__ */ jsx16(
2134
+ MenuItem7,
2135
+ {
2136
+ icon: /* @__PURE__ */ jsx16(Icon, { name: "arrow_forward" }),
2137
+ onSelect: () => editor.chain().focus().addColumnAfter().run(),
2138
+ children: "\u53F3\u306B\u633F\u5165"
2139
+ }
2140
+ ),
2141
+ /* @__PURE__ */ jsx16(MenuItem7, { icon: /* @__PURE__ */ jsx16(Icon, { name: "cell_merge" }), onSelect: () => editor.chain().focus().mergeCells().run(), children: "\u30BB\u30EB\u3092\u7D50\u5408" }),
2142
+ /* @__PURE__ */ jsx16(MenuItem7, { icon: /* @__PURE__ */ jsx16(Icon, { name: "arrows_outward" }), onSelect: () => editor.chain().focus().splitCell().run(), children: "\u30BB\u30EB\u3092\u5206\u96E2" }),
2143
+ features?.tableBgColor && /* @__PURE__ */ jsx16(TableColorPicker, { editor }),
2144
+ /* @__PURE__ */ jsx16(
2145
+ MenuItem7,
2146
+ {
2147
+ variant: "danger",
2148
+ icon: /* @__PURE__ */ jsx16(Icon, { name: "delete" }),
2149
+ onSelect: () => editor.chain().focus().deleteColumn().run(),
2150
+ children: "\u524A\u9664"
2151
+ }
2152
+ )
2153
+ ] }) }) })
2154
+ }
2155
+ );
2156
+ });
2157
+ TableColumnMenu.displayName = "TableColumnMenu";
2158
+
2159
+ // src/extensions/Table/menus/TableRow/index.tsx
2160
+ import { BubbleMenu as BaseBubbleMenu4 } from "@tiptap/react/menus";
2161
+ import React2, { useCallback as useCallback18, useMemo as useMemo11, useState as useState13 } from "react";
2162
+ import { Menu as Menu8, MenuList as MenuList8, MenuItem as MenuItem8, MenuPopover as MenuPopover8, MenuDivider as MenuDivider3 } from "@ablogcms/components/dropdown-menu";
2163
+ import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
2164
+ var TableRowMenu = React2.memo(({ editor, appendTo }) => {
2165
+ const { features } = useSettingsContext();
2166
+ const [isOpen, setIsOpen] = useState13(false);
2167
+ const [menuRect, setMenuRect] = useState13(null);
2168
+ const shouldShow = useCallback18(
2169
+ ({ view, state, from }) => {
2170
+ if (!state || !from) {
2171
+ setIsOpen(false);
2172
+ return false;
2173
+ }
2174
+ const show = isRowGripSelected({ editor, view, from });
2175
+ setIsOpen(show);
2176
+ return show;
2177
+ },
2178
+ [editor]
2179
+ );
2180
+ const bubbleMenuAppendTo = useCallback18(() => appendTo?.current, [appendTo]);
2181
+ const getReferencedVirtualElement = useCallback18(() => {
2182
+ const { view } = editor;
2183
+ const { state } = editor;
2184
+ const { $from } = state.selection;
2185
+ const pos = $from.before($from.depth);
2186
+ const dom = view.nodeDOM(pos);
2187
+ if (dom instanceof HTMLElement) {
2188
+ const rect2 = dom.getBoundingClientRect();
2189
+ setMenuRect(rect2);
2190
+ return { getBoundingClientRect: () => rect2 };
2191
+ }
2192
+ const rect = editor.view.dom.getBoundingClientRect();
2193
+ setMenuRect(rect);
2194
+ return { getBoundingClientRect: () => rect };
2195
+ }, [editor]);
2196
+ const bubbleMenuStyle = useMemo11(() => ({ zIndex: 100019 }), []);
2197
+ const bubbleMenuOptions = useMemo11(() => ({ placement: "bottom-end", offset: 15, flip: false }), []);
2198
+ return /* @__PURE__ */ jsx17(
2199
+ BaseBubbleMenu4,
2200
+ {
2201
+ editor,
2202
+ pluginKey: "tableRowMenu",
2203
+ updateDelay: 0,
2204
+ appendTo: bubbleMenuAppendTo,
2205
+ style: bubbleMenuStyle,
2206
+ getReferencedVirtualElement,
2207
+ options: bubbleMenuOptions,
2208
+ shouldShow,
2209
+ children: /* @__PURE__ */ jsx17(Menu8, { isOpen, getAnchorRect: () => menuRect, children: /* @__PURE__ */ jsx17(MenuPopover8, { size: "small", "data-elevation": "3", children: /* @__PURE__ */ jsxs16(MenuList8, { children: [
2210
+ /* @__PURE__ */ jsx17(
2211
+ MenuItem8,
2212
+ {
2213
+ icon: /* @__PURE__ */ jsx17(Icon, { name: "splitscreen_top" }),
2214
+ onSelect: () => editor.chain().focus().toggleHeaderCell().run(),
2215
+ children: "\u884C\u898B\u51FA\u3057"
2216
+ }
2217
+ ),
2218
+ /* @__PURE__ */ jsx17(MenuDivider3, {}),
2219
+ /* @__PURE__ */ jsx17(MenuItem8, { icon: /* @__PURE__ */ jsx17(Icon, { name: "arrow_upward" }), onSelect: () => editor.chain().focus().addRowBefore().run(), children: "\u4E0A\u306B\u633F\u5165" }),
2220
+ /* @__PURE__ */ jsx17(MenuItem8, { icon: /* @__PURE__ */ jsx17(Icon, { name: "arrow_downward" }), onSelect: () => editor.chain().focus().addRowAfter().run(), children: "\u4E0B\u306B\u633F\u5165" }),
2221
+ /* @__PURE__ */ jsx17(MenuItem8, { icon: /* @__PURE__ */ jsx17(Icon, { name: "cell_merge" }), onSelect: () => editor.chain().focus().mergeCells().run(), children: "\u30BB\u30EB\u3092\u7D50\u5408" }),
2222
+ /* @__PURE__ */ jsx17(MenuItem8, { icon: /* @__PURE__ */ jsx17(Icon, { name: "arrows_outward" }), onSelect: () => editor.chain().focus().splitCell().run(), children: "\u30BB\u30EB\u3092\u5206\u96E2" }),
2223
+ features?.tableBgColor && /* @__PURE__ */ jsx17(TableColorPicker, { editor }),
2224
+ /* @__PURE__ */ jsx17(
2225
+ MenuItem8,
2226
+ {
2227
+ variant: "danger",
2228
+ icon: /* @__PURE__ */ jsx17(Icon, { name: "delete" }),
2229
+ onSelect: () => editor.chain().focus().deleteRow().run(),
2230
+ children: "\u524A\u9664"
2231
+ }
2232
+ )
2233
+ ] }) }) })
2234
+ }
2235
+ );
2236
+ });
2237
+ TableRowMenu.displayName = "TableRowMenu";
2238
+
2239
+ // src/extensions/ImageBlock/components/ImageBlockMenu.tsx
2240
+ import { BubbleMenu as BaseBubbleMenu5 } from "@tiptap/react/menus";
2241
+ import { NodeSelection as NodeSelection3 } from "@tiptap/pm/state";
2242
+ import { useCallback as useCallback21, useMemo as useMemo12, useRef as useRef10, useState as useState17, useEffect as useEffect8 } from "react";
2243
+ import { v4 as uuid2 } from "uuid";
2244
+ import { emit } from "@ablogcms/events";
2245
+ import MediaInsert from "@ablogcms/media/components/media-insert/media-insert";
2246
+ import MediaUpdate from "@ablogcms/media/components/media-update/media-update";
2247
+ import { useMediaSelect as useMediaSelect2 } from "@ablogcms/react-hooks/use-media";
2248
+
2249
+ // src/extensions/ImageBlock/components/ImageBlockWidth.tsx
2250
+ import { memo as memo4, useCallback as useCallback19, useEffect as useEffect7, useState as useState14 } from "react";
2251
+ import {
2252
+ Menu as Menu9,
2253
+ MenuTrigger as MenuTrigger5,
2254
+ MenuList as MenuList9,
2255
+ MenuGroup as MenuGroup6,
2256
+ MenuItemRadio as MenuItemRadio4,
2257
+ MenuItemRadioGroup as MenuItemRadioGroup4,
2258
+ MenuPopover as MenuPopover9
2259
+ } from "@ablogcms/components/dropdown-menu";
2260
+ import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
2261
+ var ImageBlockWidth = memo4(({ onChange, value }) => {
2262
+ const { imageSizes } = useSettingsContext();
2263
+ const [currentValue, setCurrentValue] = useState14(null);
2264
+ useEffect7(() => {
2265
+ const sizeItem = imageSizes.find((item) => item.value === value) || imageSizes[0];
2266
+ setCurrentValue(sizeItem);
2267
+ }, [imageSizes, value]);
2268
+ const handleChange = useCallback19(
2269
+ (value2) => {
2270
+ onChange(value2);
2271
+ },
2272
+ [onChange]
2273
+ );
2274
+ return /* @__PURE__ */ jsxs17(Menu9, { closeOnSelect: true, children: [
2275
+ /* @__PURE__ */ jsx18(MenuTrigger5, { asChild: true, children: /* @__PURE__ */ jsxs17(Toolbar.Button, { type: "button", tooltip: "\u753B\u50CF\u30B5\u30A4\u30BA", "aria-label": "\u753B\u50CF\u30B5\u30A4\u30BA\u3092\u8A2D\u5B9A", children: [
2276
+ /* @__PURE__ */ jsx18(Icon, { name: "crop_free" }),
2277
+ currentValue?.label || "1/1 (100%)",
2278
+ /* @__PURE__ */ jsx18(Icon, { name: "keyboard_arrow_down" })
2279
+ ] }) }),
2280
+ /* @__PURE__ */ jsx18(MenuPopover9, { size: "medium", "data-elevation": "3", children: /* @__PURE__ */ jsx18(MenuList9, { children: /* @__PURE__ */ jsx18(MenuGroup6, { title: "\u753B\u50CF\u30B5\u30A4\u30BA", children: /* @__PURE__ */ jsx18(MenuItemRadioGroup4, { defaultValue: value, onValueChange: handleChange, children: imageSizes?.map((item) => /* @__PURE__ */ jsx18(MenuItemRadio4, { value: item.value, children: item.label }, `${item.label}_${item.value}`)) }) }) }) })
2281
+ ] });
2282
+ });
2283
+ ImageBlockWidth.displayName = "ImageBlockWidth";
2284
+
2285
+ // src/extensions/ImageBlock/components/ImageBlockCaption.tsx
2286
+ import { memo as memo5, useRef as useRef9 } from "react";
2287
+ import { Popover as Popover7, PopoverTrigger as PopoverTrigger6, PopoverContent as PopoverContent7, PopoverClose } from "@ablogcms/components/popover";
2288
+ import { ButtonV2 as ButtonV23 } from "@ablogcms/components/button-v2";
2289
+ import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
2290
+ var ImageBlockCaption = memo5(({ caption, alt, onChange }) => {
2291
+ const captionRef = useRef9(null);
2292
+ const altRef = useRef9(null);
2293
+ return /* @__PURE__ */ jsxs18(Popover7, { modal: true, children: [
2294
+ /* @__PURE__ */ jsx19(PopoverTrigger6, { asChild: true, children: /* @__PURE__ */ jsx19(
2295
+ Toolbar.Button,
2296
+ {
2297
+ tooltip: "\u30AD\u30E3\u30D7\u30B7\u30E7\u30F3\u3092\u7DE8\u96C6",
2298
+ type: "button",
2299
+ active: !!caption || !!alt,
2300
+ "aria-label": "\u30AD\u30E3\u30D7\u30B7\u30E7\u30F3\u3092\u7DE8\u96C6",
2301
+ children: /* @__PURE__ */ jsx19(Icon, { name: "closed_caption" })
2302
+ }
2303
+ ) }),
2304
+ /* @__PURE__ */ jsx19(PopoverContent7, { "data-elevation": "3", children: /* @__PURE__ */ jsxs18(
2305
+ "form",
2306
+ {
2307
+ className: "acms-admin-form acms-admin-block-editor-popover-form",
2308
+ onSubmit: () => onChange(captionRef.current?.value ?? "", altRef.current?.value ?? ""),
2309
+ children: [
2310
+ /* @__PURE__ */ jsxs18("div", { className: "acms-admin-block-editor-popover-form-item", children: [
2311
+ /* @__PURE__ */ jsx19("label", { htmlFor: "captionText", className: "acms-admin-block-editor-popover-form-item-label", children: "\u30AD\u30E3\u30D7\u30B7\u30E7\u30F3" }),
2312
+ /* @__PURE__ */ jsx19(
2313
+ "input",
2314
+ {
2315
+ type: "text",
2316
+ id: "captionText",
2317
+ className: "acms-admin-form-width-full",
2318
+ defaultValue: caption,
2319
+ ref: captionRef,
2320
+ placeholder: ""
2321
+ }
2322
+ )
2323
+ ] }),
2324
+ /* @__PURE__ */ jsxs18("div", { className: "acms-admin-block-editor-popover-form-item", children: [
2325
+ /* @__PURE__ */ jsx19("label", { htmlFor: "altText", className: "acms-admin-block-editor-popover-form-item-label", children: "Alt\uFF08\u4EE3\u66FF\u30C6\u30AD\u30B9\u30C8\uFF09" }),
2326
+ /* @__PURE__ */ jsx19(
2327
+ "textarea",
2328
+ {
2329
+ id: "altText",
2330
+ defaultValue: alt,
2331
+ ref: altRef,
2332
+ className: "acms-admin-form-width-full",
2333
+ placeholder: ""
2334
+ }
2335
+ )
2336
+ ] }),
2337
+ /* @__PURE__ */ jsx19("div", { className: "acms-admin-block-editor-popover-form-button-group", children: /* @__PURE__ */ jsx19(PopoverClose, { asChild: true, children: /* @__PURE__ */ jsx19(
2338
+ ButtonV23,
2339
+ {
2340
+ variant: "filled",
2341
+ size: "small",
2342
+ type: "submit",
2343
+ "aria-label": "\u30AD\u30E3\u30D7\u30B7\u30E7\u30F3\u3092\u9069\u7528",
2344
+ onClick: () => {
2345
+ onChange(captionRef.current?.value ?? "", altRef.current?.value ?? "");
2346
+ },
2347
+ children: "\u9069\u7528"
2348
+ }
2349
+ ) }) })
2350
+ ]
2351
+ }
2352
+ ) })
2353
+ ] });
2354
+ });
2355
+ ImageBlockCaption.displayName = "ImageBlockCaption";
2356
+
2357
+ // src/extensions/ImageBlock/components/ImageBlockLink.tsx
2358
+ import { memo as memo6, useState as useState15 } from "react";
2359
+ import { Popover as Popover8, PopoverTrigger as PopoverTrigger7, PopoverContent as PopoverContent8 } from "@ablogcms/components/popover";
2360
+ import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
2361
+ var ImageBlockLink = memo6(({ initialUrl, initialOpenInNewTab, onChange }) => {
2362
+ const [isOpen, setIsOpen] = useState15(false);
2363
+ return /* @__PURE__ */ jsxs19(Popover8, { modal: true, isOpen, onOpenChange: setIsOpen, children: [
2364
+ /* @__PURE__ */ jsx20(PopoverTrigger7, { asChild: true, children: /* @__PURE__ */ jsx20(
2365
+ Toolbar.Button,
2366
+ {
2367
+ tooltip: "\u30EA\u30F3\u30AF\u3092\u8A2D\u5B9A",
2368
+ type: "button",
2369
+ active: !!initialUrl,
2370
+ onClick: () => setIsOpen((prev) => !prev),
2371
+ "alia-label": "\u30EA\u30F3\u30AF\u3092\u8A2D\u5B9A",
2372
+ children: /* @__PURE__ */ jsx20(Icon, { name: "link" })
2373
+ }
2374
+ ) }),
2375
+ /* @__PURE__ */ jsx20(PopoverContent8, { "data-elevation": "3", children: /* @__PURE__ */ jsx20(
2376
+ LinkEditorPanel,
2377
+ {
2378
+ initialUrl,
2379
+ initialOpenInNewTab,
2380
+ onSetLink: (link, openInNewTab) => {
2381
+ onChange(link, openInNewTab);
2382
+ setIsOpen(false);
2383
+ },
2384
+ onClear: () => {
2385
+ onChange("", false);
2386
+ setIsOpen(false);
2387
+ }
2388
+ }
2389
+ ) })
2390
+ ] });
2391
+ });
2392
+ ImageBlockLink.displayName = "ImageBlockLink";
2393
+
2394
+ // src/extensions/ImageBlock/mediaUpdateHooks.ts
2395
+ import { useState as useState16, useCallback as useCallback20 } from "react";
2396
+ var useMediaUpdate = ({ inspectMedia }) => {
2397
+ const [isUpdateModalOpen, setIsUpdateModalOpen] = useState16(false);
2398
+ const targetMediaId = inspectMedia()?.attrs?.mediaId || null;
2399
+ const imageSrc = inspectMedia()?.attrs?.src || null;
2400
+ let selfImgSrc = null;
2401
+ if (imageSrc && !/^(?:[a-z]+:)?\/\//i.test(imageSrc)) {
2402
+ selfImgSrc = imageSrc;
2403
+ }
2404
+ const handleUpdateModalClose = useCallback20(() => {
2405
+ setIsUpdateModalOpen(false);
2406
+ }, []);
2407
+ const handleUpdateClick = useCallback20(() => {
2408
+ setIsUpdateModalOpen(true);
2409
+ }, []);
2410
+ return {
2411
+ targetMediaId,
2412
+ selfImgSrc,
2413
+ isUpdateModalOpen,
2414
+ handleUpdateModalClose,
2415
+ handleUpdateClick
2416
+ };
2417
+ };
2418
+
2419
+ // src/extensions/ImageBlock/components/ImageBlockMenu.tsx
2420
+ import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
2421
+ function ImageBlockMenu({ editor, appendTo }) {
2422
+ const menuRef = useRef10(null);
2423
+ const pluginKeyRef = useRef10(`imageBlockMenu-${uuid2()}`);
2424
+ const [hasMainImageField, setHasMainImageField] = useState17(false);
2425
+ const [isMainImageActive, setIsMainImageActive] = useState17(false);
2426
+ const inspectMedia = useCallback21(() => {
2427
+ const { selection } = editor.state;
2428
+ if (selection instanceof NodeSelection3) {
2429
+ const selectedNode = selection.node;
2430
+ if (selectedNode.type.name === "imageBlock") {
2431
+ return selectedNode;
2432
+ }
2433
+ }
2434
+ }, [editor]);
2435
+ const { isInsertModalOpen, tab, files, handleModalClose, handleSelectClick, uploadFile } = useMediaSelect2();
2436
+ const { targetMediaId, selfImgSrc, isUpdateModalOpen, handleUpdateModalClose, handleUpdateClick } = useMediaUpdate({
2437
+ inspectMedia
2438
+ });
2439
+ const handleInsertMedia = useCallback21(
2440
+ (items) => {
2441
+ const [item] = items;
2442
+ if (item.media_thumbnail) {
2443
+ editor.chain().focus(void 0, { scrollIntoView: false }).updateMediaImageBlock(item).run();
2444
+ }
2445
+ handleModalClose();
2446
+ },
2447
+ [editor, handleModalClose]
2448
+ );
2449
+ const handleUpdateMedia = useCallback21(
2450
+ (item) => {
2451
+ if (item.media_thumbnail) {
2452
+ editor.chain().focus(void 0, { scrollIntoView: false }).updateMediaImageBlock(item).run();
2453
+ }
2454
+ handleUpdateModalClose();
2455
+ },
2456
+ [editor, handleUpdateModalClose]
2457
+ );
2458
+ const shouldShow = useCallback21(() => {
2459
+ const isActive = editor.isActive("imageBlock");
2460
+ return isActive;
2461
+ }, [editor]);
2462
+ const bubbleMenuAppendTo = useCallback21(() => appendTo?.current ?? document.body, [appendTo]);
2463
+ const bubbleMenuOptions = useMemo12(() => ({ offset: 8 }), []);
2464
+ const onWidthChange = useCallback21(
2465
+ (value) => {
2466
+ editor.chain().focus(void 0, { scrollIntoView: false }).setImageBlockWidth(value).run();
2467
+ },
2468
+ [editor]
2469
+ );
2470
+ const handleUploadClick = useCallback21(async () => {
2471
+ const res = await fetch(selfImgSrc);
2472
+ const blob = await res.blob();
2473
+ const filename = selfImgSrc.split("/").pop() || "";
2474
+ const ext = blob.type.split("/")[1] || "jpg";
2475
+ const name = filename.includes(".") ? filename : `${filename}.${ext}`;
2476
+ const file = new File([blob], name, { type: blob.type });
2477
+ uploadFile([file]);
2478
+ }, [uploadFile, selfImgSrc]);
2479
+ const handleSetMainImage = useCallback21(() => {
2480
+ const mainImageValues = document.querySelectorAll(
2481
+ ACMS.Config.blockEditorConfig.setMainImageMark || ".js-block-editor-set-main-image"
2482
+ );
2483
+ if (mainImageValues && mainImageValues.length > 0) {
2484
+ [].forEach.call(mainImageValues, (mainImageValue) => {
2485
+ setIsMainImageActive(true);
2486
+ mainImageValue.dispatchEvent(new Event("change", { bubbles: true }));
2487
+ void emit("entry.main-image.change", {
2488
+ target: mainImageValue,
2489
+ mediaId: editor.getAttributes("imageBlock").mediaId,
2490
+ thumbnail: editor.getAttributes("imageBlock").src
2491
+ });
2492
+ mainImageValue?.dispatchEvent(
2493
+ new CustomEvent("acms.set-main-image", {
2494
+ detail: {
2495
+ media_id: editor.getAttributes("imageBlock").mediaId,
2496
+ media_thumbnail: editor.getAttributes("imageBlock").src,
2497
+ media_type: "image"
2498
+ }
2499
+ })
2500
+ );
2501
+ });
2502
+ }
2503
+ }, [editor]);
2504
+ useEffect8(() => {
2505
+ const mainImageValues = document.querySelectorAll(
2506
+ ACMS.Config.blockEditorConfig.setMainImageMark || ".js-block-editor-set-main-image"
2507
+ );
2508
+ if (mainImageValues && mainImageValues.length > 0) {
2509
+ const mainImageMids = Array.from(mainImageValues).map((mainImageValue) => mainImageValue.value);
2510
+ setHasMainImageField(true);
2511
+ setIsMainImageActive(mainImageMids.includes(String(editor.getAttributes("imageBlock").mediaId)));
2512
+ }
2513
+ }, [editor, editor.state]);
2514
+ return /* @__PURE__ */ jsxs20(
2515
+ BaseBubbleMenu5,
2516
+ {
2517
+ editor,
2518
+ pluginKey: pluginKeyRef.current,
2519
+ shouldShow,
2520
+ updateDelay: 0,
2521
+ appendTo: bubbleMenuAppendTo,
2522
+ options: bubbleMenuOptions,
2523
+ children: [
2524
+ /* @__PURE__ */ jsxs20(Toolbar, { shouldShowContent: shouldShow(), ref: menuRef, children: [
2525
+ /* @__PURE__ */ jsx21(Toolbar.Button, { type: "button", tooltip: "\u30E1\u30C7\u30A3\u30A2\u9078\u629E", onClick: handleSelectClick, "aria-label": "\u30E1\u30C7\u30A3\u30A2\u3092\u9078\u629E", children: /* @__PURE__ */ jsx21(Icon, { name: "perm_media" }) }),
2526
+ targetMediaId != null && targetMediaId > 0 && /* @__PURE__ */ jsx21(
2527
+ Toolbar.Button,
2528
+ {
2529
+ type: "button",
2530
+ tooltip: "\u30E1\u30C7\u30A3\u30A2\u3092\u7DE8\u96C6",
2531
+ onClick: handleUpdateClick,
2532
+ "aria-label": "\u30E1\u30C7\u30A3\u30A2\u3092\u7DE8\u96C6",
2533
+ children: /* @__PURE__ */ jsx21(Icon, { name: "edit" })
2534
+ }
2535
+ ),
2536
+ targetMediaId == null && selfImgSrc && /* @__PURE__ */ jsx21(
2537
+ Toolbar.Button,
2538
+ {
2539
+ type: "button",
2540
+ tooltip: "\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9",
2541
+ onClick: handleUploadClick,
2542
+ "aria-label": "\u753B\u50CF\u3092\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9",
2543
+ children: /* @__PURE__ */ jsx21(Icon, { name: "upload" })
2544
+ }
2545
+ ),
2546
+ /* @__PURE__ */ jsx21(Toolbar.Divider, {}),
2547
+ /* @__PURE__ */ jsx21(
2548
+ ImageBlockLink,
2549
+ {
2550
+ initialUrl: editor.getAttributes("imageBlock").link,
2551
+ initialOpenInNewTab: editor.getAttributes("imageBlock").target === "_blank",
2552
+ onChange: (link, openInNewTab) => {
2553
+ editor.chain().focus(void 0, { scrollIntoView: false }).setImageBlockLink(link, openInNewTab).run();
2554
+ }
2555
+ }
2556
+ ),
2557
+ /* @__PURE__ */ jsx21(
2558
+ ImageBlockCaption,
2559
+ {
2560
+ caption: editor.getAttributes("imageBlock").caption,
2561
+ alt: editor.getAttributes("imageBlock").alt,
2562
+ onChange: (caption, alt) => {
2563
+ editor.chain().focus(void 0, { scrollIntoView: false }).setImageBlockCaption(caption).setImageBlockAlt(alt).run();
2564
+ }
2565
+ }
2566
+ ),
2567
+ /* @__PURE__ */ jsx21(
2568
+ AlignPicker,
2569
+ {
2570
+ align: editor.getAttributes("imageBlock").align,
2571
+ onChange: (align) => {
2572
+ editor.chain().focus(void 0, { scrollIntoView: false }).setImageBlockAlign(align).run();
2573
+ }
2574
+ }
2575
+ ),
2576
+ /* @__PURE__ */ jsx21(
2577
+ Toolbar.Button,
2578
+ {
2579
+ type: "button",
2580
+ tooltip: "\u62E1\u5927\u8868\u793A\u3057\u306A\u3044",
2581
+ "aria-label": "\u753B\u50CF\u3092\u62E1\u5927\u8868\u793A\u3057\u306A\u3044",
2582
+ onClick: () => {
2583
+ editor.chain().focus(void 0, { scrollIntoView: false }).toggleImageBlockLightbox().run();
2584
+ },
2585
+ active: editor.getAttributes("imageBlock").noLightbox === "true",
2586
+ children: /* @__PURE__ */ jsx21(Icon, { name: "search_off" })
2587
+ }
2588
+ ),
2589
+ hasMainImageField && targetMediaId && /* @__PURE__ */ jsx21(
2590
+ Toolbar.Button,
2591
+ {
2592
+ type: "button",
2593
+ tooltip: "\u30E1\u30A4\u30F3\u753B\u50CF\u306B\u8A2D\u5B9A",
2594
+ onClick: handleSetMainImage,
2595
+ active: isMainImageActive,
2596
+ "aria-label": "\u30E1\u30A4\u30F3\u753B\u50CF\u306B\u8A2D\u5B9A",
2597
+ children: /* @__PURE__ */ jsx21(Icon, { name: "imagesmode" })
2598
+ }
2599
+ ),
2600
+ /* @__PURE__ */ jsx21(Toolbar.Divider, {}),
2601
+ /* @__PURE__ */ jsx21(ImageBlockWidth, { onChange: onWidthChange, value: editor.getAttributes("imageBlock").displayWidth })
2602
+ ] }),
2603
+ /* @__PURE__ */ jsx21(
2604
+ MediaInsert,
2605
+ {
2606
+ isOpen: isInsertModalOpen,
2607
+ onInsert: handleInsertMedia,
2608
+ onClose: handleModalClose,
2609
+ tab,
2610
+ files,
2611
+ filetype: "image"
2612
+ }
2613
+ ),
2614
+ targetMediaId != null && targetMediaId > 0 && /* @__PURE__ */ jsx21(
2615
+ MediaUpdate,
2616
+ {
2617
+ isOpen: isUpdateModalOpen,
2618
+ mid: targetMediaId,
2619
+ onClose: handleUpdateModalClose,
2620
+ onUpdate: handleUpdateMedia
2621
+ }
2622
+ )
2623
+ ]
2624
+ }
2625
+ );
2626
+ }
2627
+ var ImageBlockMenu_default = ImageBlockMenu;
2628
+
2629
+ // src/extensions/FileBlock/components/FileBlockMenu.tsx
2630
+ import { BubbleMenu as BaseBubbleMenu6 } from "@tiptap/react/menus";
2631
+ import { NodeSelection as NodeSelection4 } from "@tiptap/pm/state";
2632
+ import { useCallback as useCallback22, useMemo as useMemo13, useRef as useRef12 } from "react";
2633
+ import { v4 as uuid3 } from "uuid";
2634
+ import MediaInsert2 from "@ablogcms/media/components/media-insert/media-insert";
2635
+ import MediaUpdate2 from "@ablogcms/media/components/media-update/media-update";
2636
+
2637
+ // src/extensions/FileBlock/components/FileBlockCaption.tsx
2638
+ import { memo as memo7, useRef as useRef11 } from "react";
2639
+ import { Popover as Popover9, PopoverTrigger as PopoverTrigger8, PopoverContent as PopoverContent9, PopoverClose as PopoverClose2 } from "@ablogcms/components/popover";
2640
+ import { ButtonV2 as ButtonV24 } from "@ablogcms/components/button-v2";
2641
+ import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
2642
+ var FileBlockCaption = memo7(({ caption, alt, onChange }) => {
2643
+ const captionRef = useRef11(null);
2644
+ const altRef = useRef11(null);
2645
+ return /* @__PURE__ */ jsxs21(Popover9, { modal: true, children: [
2646
+ /* @__PURE__ */ jsx22(PopoverTrigger8, { asChild: true, children: /* @__PURE__ */ jsx22(
2647
+ Toolbar.Button,
2648
+ {
2649
+ tooltip: "\u30AD\u30E3\u30D7\u30B7\u30E7\u30F3\u3092\u7DE8\u96C6",
2650
+ type: "button",
2651
+ active: !!caption || !!alt,
2652
+ "aria-label": "\u30AD\u30E3\u30D7\u30B7\u30E7\u30F3\u3092\u7DE8\u96C6",
2653
+ children: /* @__PURE__ */ jsx22(Icon, { name: "closed_caption" })
2654
+ }
2655
+ ) }),
2656
+ /* @__PURE__ */ jsx22(PopoverContent9, { "data-elevation": "3", children: /* @__PURE__ */ jsxs21(
2657
+ "form",
2658
+ {
2659
+ className: "acms-admin-form acms-admin-block-editor-popover-form",
2660
+ onSubmit: () => onChange(captionRef.current?.value ?? "", altRef.current?.value ?? ""),
2661
+ children: [
2662
+ /* @__PURE__ */ jsxs21("div", { className: "acms-admin-block-editor-popover-form-item", children: [
2663
+ /* @__PURE__ */ jsx22("label", { htmlFor: "captionText", className: "acms-admin-block-editor-popover-form-item-label", children: "\u30AD\u30E3\u30D7\u30B7\u30E7\u30F3" }),
2664
+ /* @__PURE__ */ jsx22(
2665
+ "input",
2666
+ {
2667
+ type: "text",
2668
+ id: "captionText",
2669
+ className: "acms-admin-form-width-full",
2670
+ defaultValue: caption,
2671
+ ref: captionRef,
2672
+ placeholder: ""
2673
+ }
2674
+ )
2675
+ ] }),
2676
+ /* @__PURE__ */ jsxs21("div", { className: "acms-admin-block-editor-popover-form-item", children: [
2677
+ /* @__PURE__ */ jsx22("label", { htmlFor: "altText", className: "acms-admin-block-editor-popover-form-item-label", children: "Alt\uFF08\u4EE3\u66FF\u30C6\u30AD\u30B9\u30C8\uFF09" }),
2678
+ /* @__PURE__ */ jsx22(
2679
+ "textarea",
2680
+ {
2681
+ id: "altText",
2682
+ defaultValue: alt,
2683
+ ref: altRef,
2684
+ className: "acms-admin-form-width-full",
2685
+ placeholder: ""
2686
+ }
2687
+ )
2688
+ ] }),
2689
+ /* @__PURE__ */ jsx22("div", { className: "acms-admin-block-editor-popover-form-button-group", children: /* @__PURE__ */ jsx22(PopoverClose2, { asChild: true, children: /* @__PURE__ */ jsx22(
2690
+ ButtonV24,
2691
+ {
2692
+ variant: "filled",
2693
+ size: "small",
2694
+ type: "submit",
2695
+ "aria-label": "\u30AD\u30E3\u30D7\u30B7\u30E7\u30F3\u3092\u9069\u7528",
2696
+ onClick: () => {
2697
+ onChange(captionRef.current?.value ?? "", altRef.current?.value ?? "");
2698
+ },
2699
+ children: "\u9069\u7528"
2700
+ }
2701
+ ) }) })
2702
+ ]
2703
+ }
2704
+ ) })
2705
+ ] });
2706
+ });
2707
+ FileBlockCaption.displayName = "FileBlockCaption";
2708
+
2709
+ // src/extensions/FileBlock/components/FileBlockMenu.tsx
2710
+ import { jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
2711
+ function FileBlockMenu({ editor, appendTo }) {
2712
+ const menuRef = useRef12(null);
2713
+ const pluginKeyRef = useRef12(`fileBlockMenu-${uuid3()}`);
2714
+ const inspectMedia = useCallback22(() => {
2715
+ const { selection } = editor.state;
2716
+ if (selection instanceof NodeSelection4) {
2717
+ const selectedNode = selection.node;
2718
+ if (selectedNode.type.name === "fileBlock") {
2719
+ return selectedNode;
2720
+ }
2721
+ }
2722
+ }, [editor]);
2723
+ const { isInsertModalOpen, tab, files, handleModalClose, handleSelectClick } = useMediaSelect();
2724
+ const { targetMediaId, isUpdateModalOpen, handleUpdateModalClose, handleUpdateClick } = useMediaUpdate({
2725
+ inspectMedia
2726
+ });
2727
+ const handleInsertMedia = useCallback22(
2728
+ (items) => {
2729
+ const [item] = items;
2730
+ if (item.media_permalink) {
2731
+ editor.chain().focus(void 0, { scrollIntoView: false }).updateMediaFileBlock(item).run();
2732
+ }
2733
+ handleModalClose();
2734
+ },
2735
+ [editor, handleModalClose]
2736
+ );
2737
+ const handleUpdateMedia = useCallback22(
2738
+ (item) => {
2739
+ if (item.media_permalink) {
2740
+ editor.chain().focus(void 0, { scrollIntoView: false }).updateMediaFileBlock(item).run();
2741
+ }
2742
+ handleUpdateModalClose();
2743
+ },
2744
+ [editor, handleUpdateModalClose]
2745
+ );
2746
+ const shouldShow = useCallback22(() => {
2747
+ const isActive = editor.isActive("fileBlock");
2748
+ return isActive;
2749
+ }, [editor]);
2750
+ const bubbleMenuAppendTo = useCallback22(() => appendTo?.current ?? document.body, [appendTo]);
2751
+ const bubbleMenuOptions = useMemo13(() => ({ offset: 8 }), []);
2752
+ return /* @__PURE__ */ jsxs22(
2753
+ BaseBubbleMenu6,
2754
+ {
2755
+ editor,
2756
+ pluginKey: pluginKeyRef.current,
2757
+ shouldShow,
2758
+ updateDelay: 0,
2759
+ appendTo: bubbleMenuAppendTo,
2760
+ options: bubbleMenuOptions,
2761
+ children: [
2762
+ /* @__PURE__ */ jsxs22(Toolbar, { shouldShowContent: shouldShow(), ref: menuRef, children: [
2763
+ /* @__PURE__ */ jsx23(Toolbar.Button, { type: "button", tooltip: "\u30E1\u30C7\u30A3\u30A2\u9078\u629E", onClick: handleSelectClick, "aria-label": "\u30E1\u30C7\u30A3\u30A2\u3092\u9078\u629E", children: /* @__PURE__ */ jsx23(Icon, { name: "perm_media" }) }),
2764
+ targetMediaId != null && targetMediaId > 0 && /* @__PURE__ */ jsx23(
2765
+ Toolbar.Button,
2766
+ {
2767
+ type: "button",
2768
+ tooltip: "\u30E1\u30C7\u30A3\u30A2\u3092\u7DE8\u96C6",
2769
+ onClick: handleUpdateClick,
2770
+ "aria-label": "\u30E1\u30C7\u30A3\u30A2\u3092\u7DE8\u96C6",
2771
+ children: /* @__PURE__ */ jsx23(Icon, { name: "edit" })
2772
+ }
2773
+ ),
2774
+ /* @__PURE__ */ jsx23(Toolbar.Divider, {}),
2775
+ /* @__PURE__ */ jsx23(
2776
+ FileBlockCaption,
2777
+ {
2778
+ caption: editor.getAttributes("fileBlock").caption ?? "",
2779
+ alt: editor.getAttributes("fileBlock").alt ?? "",
2780
+ onChange: (caption, alt) => {
2781
+ editor.chain().focus(void 0, { scrollIntoView: false }).setFileBlockCaption(caption).setFileBlockAlt(alt).run();
2782
+ }
2783
+ }
2784
+ ),
2785
+ /* @__PURE__ */ jsx23(
2786
+ AlignPicker,
2787
+ {
2788
+ align: editor.getAttributes("fileBlock").align,
2789
+ onChange: (align) => {
2790
+ editor.chain().focus(void 0, { scrollIntoView: false }).setFileBlockAlign(align).run();
2791
+ }
2792
+ }
2793
+ ),
2794
+ /* @__PURE__ */ jsx23(
2795
+ Toolbar.Button,
2796
+ {
2797
+ type: "button",
2798
+ tooltip: "\u30DC\u30BF\u30F3\u3067\u8868\u793A",
2799
+ "aria-label": "\u30DC\u30BF\u30F3\u3067\u8868\u793A",
2800
+ onClick: () => {
2801
+ const newDisplayType = editor.getAttributes("fileBlock").displayType === "button" ? "icon" : "button";
2802
+ editor.chain().focus(void 0, { scrollIntoView: false }).setFileBlockDisplayType(newDisplayType).run();
2803
+ },
2804
+ disabled: !editor.getAttributes("fileBlock").caption,
2805
+ active: editor.getAttributes("fileBlock").displayType === "button",
2806
+ children: /* @__PURE__ */ jsx23(Icon, { name: "variable_insert" })
2807
+ }
2808
+ ),
2809
+ /* @__PURE__ */ jsx23(
2810
+ Toolbar.Button,
2811
+ {
2812
+ tooltip: "\u30EA\u30F3\u30AF\u3092\u78BA\u8A8D",
2813
+ onClick: () => {
2814
+ window.open(editor.getAttributes("fileBlock").href, "_blank", "noopener,noreferrer");
2815
+ },
2816
+ "aria-label": "\u30EA\u30F3\u30AF\u3092\u78BA\u8A8D",
2817
+ disabled: !editor.getAttributes("fileBlock").href,
2818
+ children: /* @__PURE__ */ jsx23(Icon, { name: "visibility" })
2819
+ }
2820
+ ),
2821
+ /* @__PURE__ */ jsx23(
2822
+ Toolbar.Button,
2823
+ {
2824
+ type: "button",
2825
+ tooltip: "\u5225\u30BF\u30D6\u3067\u958B\u304F",
2826
+ "aria-label": "\u5225\u30BF\u30D6\u3067\u958B\u304F",
2827
+ onClick: () => {
2828
+ editor.chain().focus(void 0, { scrollIntoView: false }).toggleFileBlockTarget().run();
2829
+ },
2830
+ active: editor.getAttributes("fileBlock").target === "_blank",
2831
+ children: /* @__PURE__ */ jsx23(Icon, { name: "open_in_new" })
2832
+ }
2833
+ )
2834
+ ] }),
2835
+ /* @__PURE__ */ jsx23(
2836
+ MediaInsert2,
2837
+ {
2838
+ isOpen: isInsertModalOpen,
2839
+ onInsert: handleInsertMedia,
2840
+ onClose: handleModalClose,
2841
+ tab,
2842
+ files,
2843
+ filetype: "file",
2844
+ radioMode: true
2845
+ }
2846
+ ),
2847
+ targetMediaId != null && targetMediaId > 0 && /* @__PURE__ */ jsx23(
2848
+ MediaUpdate2,
2849
+ {
2850
+ isOpen: isUpdateModalOpen,
2851
+ mid: targetMediaId,
2852
+ onClose: handleUpdateModalClose,
2853
+ onUpdate: handleUpdateMedia
2854
+ }
2855
+ )
2856
+ ]
2857
+ }
2858
+ );
2859
+ }
2860
+ var FileBlockMenu_default = FileBlockMenu;
2861
+
2862
+ // src/extensions/LinkButton/components/LinkButtonMenu.tsx
2863
+ import { BubbleMenu as BaseBubbleMenu7 } from "@tiptap/react/menus";
2864
+ import { useCallback as useCallback23, useMemo as useMemo14, useRef as useRef13 } from "react";
2865
+ import { v4 as uuid4 } from "uuid";
2866
+ import { jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
2867
+ function LinkButtonMenu({ editor, appendTo }) {
2868
+ const menuRef = useRef13(null);
2869
+ const pluginKeyRef = useRef13(`linkButtonMenu-${uuid4()}`);
2870
+ const linkButtonBlock = useCallback23(() => {
2871
+ const { selection } = editor.state;
2872
+ const { $from } = selection;
2873
+ for (let { depth } = $from; depth >= 0; depth--) {
2874
+ const node = $from.node(depth);
2875
+ if (node.type.name === "linkButton") {
2876
+ return {
2877
+ node,
2878
+ pos: $from.before(depth)
2879
+ // ノードの先頭位置も一緒に返すと便利
2880
+ };
2881
+ }
2882
+ }
2883
+ return null;
2884
+ }, [editor]);
2885
+ const shouldShow = useCallback23(() => {
2886
+ const isActive = editor.isActive("linkButton");
2887
+ return isActive;
2888
+ }, [editor]);
2889
+ const bubbleMenuAppendTo = useCallback23(() => appendTo?.current ?? document.body, [appendTo]);
2890
+ const getReferencedVirtualElement = useCallback23(() => {
2891
+ const result = linkButtonBlock();
2892
+ if (!result) return null;
2893
+ const { pos } = result;
2894
+ const dom = editor.view.nodeDOM(pos);
2895
+ if (!dom || !dom.getBoundingClientRect) return null;
2896
+ return { getBoundingClientRect: () => dom.getBoundingClientRect() };
2897
+ }, [editor, linkButtonBlock]);
2898
+ const bubbleMenuOptions = useMemo14(() => ({ offset: 18 }), []);
2899
+ return /* @__PURE__ */ jsx24(
2900
+ BaseBubbleMenu7,
2901
+ {
2902
+ editor,
2903
+ pluginKey: pluginKeyRef.current,
2904
+ shouldShow,
2905
+ updateDelay: 0,
2906
+ appendTo: bubbleMenuAppendTo,
2907
+ getReferencedVirtualElement,
2908
+ options: bubbleMenuOptions,
2909
+ children: /* @__PURE__ */ jsxs23(Toolbar, { shouldShowContent: shouldShow(), ref: menuRef, children: [
2910
+ /* @__PURE__ */ jsx24(
2911
+ ImageBlockLink,
2912
+ {
2913
+ initialUrl: editor.getAttributes("linkButton").href,
2914
+ initialOpenInNewTab: editor.getAttributes("linkButton").target === "_blank",
2915
+ onChange: (link, openInNewTab) => {
2916
+ editor.chain().focus(void 0, { scrollIntoView: false }).setLinkButtonBlockLink(link, openInNewTab).run();
2917
+ }
2918
+ }
2919
+ ),
2920
+ /* @__PURE__ */ jsx24(
2921
+ Toolbar.Button,
2922
+ {
2923
+ tooltip: "\u30EA\u30F3\u30AF\u3092\u78BA\u8A8D",
2924
+ onClick: () => {
2925
+ window.open(editor.getAttributes("linkButton").href, "_blank", "noopener,noreferrer");
2926
+ },
2927
+ "aria-label": "\u30EA\u30F3\u30AF\u3092\u78BA\u8A8D",
2928
+ disabled: !editor.getAttributes("linkButton").href,
2929
+ children: /* @__PURE__ */ jsx24(Icon, { name: "visibility" })
2930
+ }
2931
+ ),
2932
+ /* @__PURE__ */ jsx24(
2933
+ AlignPicker,
2934
+ {
2935
+ align: editor.getAttributes("linkButton").align,
2936
+ onChange: (align) => {
2937
+ editor.chain().focus(void 0, { scrollIntoView: false }).setLinkButtonBlockAlign(align).run();
2938
+ }
2939
+ }
2940
+ )
2941
+ ] })
2942
+ }
2943
+ );
2944
+ }
2945
+ var LinkButtonMenu_default = LinkButtonMenu;
2946
+
2947
+ // src/hooks/useSettings.ts
2948
+ import { useMemo as useMemo15 } from "react";
2949
+
2950
+ // src/utils/mergeSettings.ts
2951
+ var isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2952
+ var identifierOf = (cmd) => cmd.identifier ?? cmd.name;
2953
+ var FALLBACK_GROUP_TITLE = "\u305D\u306E\u4ED6";
2954
+ var flattenBlockMenus = (blockMenus) => {
2955
+ const commands = /* @__PURE__ */ new Map();
2956
+ const groupMetaByTitle = /* @__PURE__ */ new Map();
2957
+ const baseGroupOrder = [];
2958
+ for (const group of blockMenus) {
2959
+ if (!groupMetaByTitle.has(group.title)) {
2960
+ groupMetaByTitle.set(group.title, { name: group.name, title: group.title });
2961
+ baseGroupOrder.push(group.title);
2962
+ }
2963
+ for (const command of group.commands) {
2964
+ commands.set(identifierOf(command), { group: group.title, command });
2965
+ }
2966
+ }
2967
+ return { commands, groupMetaByTitle, baseGroupOrder };
2968
+ };
2969
+ var applyAllowDenyFilter = (baseCommands, override) => {
2970
+ let working = new Map(baseCommands);
2971
+ if (Array.isArray(override.allow)) {
2972
+ const allowed = new Set(override.allow);
2973
+ working = new Map(Array.from(working).filter(([identifier]) => allowed.has(identifier)));
2974
+ }
2975
+ if (Array.isArray(override.deny)) {
2976
+ const denied = new Set(override.deny);
2977
+ for (const identifier of Array.from(working.keys())) {
2978
+ if (denied.has(identifier)) {
2979
+ working.delete(identifier);
2980
+ }
2981
+ }
2982
+ }
2983
+ return working;
2984
+ };
2985
+ var regroupCommands = (filtered, groupMetaByTitle, baseGroupOrder) => {
2986
+ const groupCommands = /* @__PURE__ */ new Map();
2987
+ const appearanceOrder = [];
2988
+ for (const entry of filtered.values()) {
2989
+ if (!groupCommands.has(entry.group)) {
2990
+ groupCommands.set(entry.group, []);
2991
+ appearanceOrder.push(entry.group);
2992
+ }
2993
+ groupCommands.get(entry.group).push(entry.command);
2994
+ }
2995
+ const orderedTitles = [
2996
+ ...baseGroupOrder.filter((title) => groupCommands.has(title)),
2997
+ ...appearanceOrder.filter((title) => !baseGroupOrder.includes(title))
2998
+ ];
2999
+ return orderedTitles.map((title) => {
3000
+ const meta = groupMetaByTitle.get(title) ?? { name: title, title };
3001
+ return {
3002
+ name: meta.name,
3003
+ title: meta.title,
3004
+ commands: groupCommands.get(title) ?? []
3005
+ };
3006
+ });
3007
+ };
3008
+ var buildFromBlocksOverride = (entries) => {
3009
+ const byIdentifier = /* @__PURE__ */ new Map();
3010
+ let currentGroup = FALLBACK_GROUP_TITLE;
3011
+ for (const entry of entries) {
3012
+ if (!isPlainObject(entry) || typeof entry.type !== "string" || entry.type === "") {
3013
+ continue;
3014
+ }
3015
+ const master = blocks_default[entry.type];
3016
+ if (!master) {
3017
+ continue;
3018
+ }
3019
+ if (typeof entry.group === "string" && entry.group !== "" && entry.group !== currentGroup) {
3020
+ currentGroup = entry.group;
3021
+ }
3022
+ const className = entry.class || void 0;
3023
+ const identifier = buildIdentifier(entry.type, className);
3024
+ const command = {
3025
+ name: entry.type,
3026
+ identifier,
3027
+ label: entry.label || master.label,
3028
+ description: master.description,
3029
+ iconName: entry.icon ?? master.icon,
3030
+ aliases: master.aliases,
3031
+ isTextMenu: master.isTextMenu,
3032
+ class: className,
3033
+ isDisabled: () => false
3034
+ };
3035
+ byIdentifier.delete(identifier);
3036
+ byIdentifier.set(identifier, { group: currentGroup, command });
3037
+ }
3038
+ const commandsByGroup = /* @__PURE__ */ new Map();
3039
+ const groupOrder = [];
3040
+ for (const { group, command } of byIdentifier.values()) {
3041
+ if (!commandsByGroup.has(group)) {
3042
+ commandsByGroup.set(group, []);
3043
+ groupOrder.push(group);
3044
+ }
3045
+ commandsByGroup.get(group).push(command);
3046
+ }
3047
+ return groupOrder.map((title, index) => ({
3048
+ name: `group-${index + 1}`,
3049
+ title,
3050
+ commands: commandsByGroup.get(title) ?? []
3051
+ }));
3052
+ };
3053
+ var mergeBlockMenus = (base, override) => {
3054
+ if (Array.isArray(override.blocks)) {
3055
+ return buildFromBlocksOverride(override.blocks);
3056
+ }
3057
+ const flattened = flattenBlockMenus(base);
3058
+ const filtered = applyAllowDenyFilter(flattened.commands, override);
3059
+ return regroupCommands(filtered, flattened.groupMetaByTitle, flattened.baseGroupOrder);
3060
+ };
3061
+ function mergeSettings(base, override) {
3062
+ if (!isPlainObject(override)) {
3063
+ return base;
3064
+ }
3065
+ return {
3066
+ features: { ...base.features, ...isPlainObject(override.features) ? override.features : {} },
3067
+ blockMenus: isPlainObject(override.blockMenus) ? mergeBlockMenus(base.blockMenus, override.blockMenus) : base.blockMenus,
3068
+ fontSize: Array.isArray(override.fontSize) ? override.fontSize : base.fontSize,
3069
+ fontFamily: Array.isArray(override.fontFamily) ? override.fontFamily : base.fontFamily,
3070
+ customClass: Array.isArray(override.customClass) ? override.customClass : base.customClass,
3071
+ imageSizes: Array.isArray(override.imageSizes) ? override.imageSizes : base.imageSizes,
3072
+ colorPalette: Array.isArray(override.colorPalette) ? override.colorPalette : base.colorPalette
3073
+ };
3074
+ }
3075
+
3076
+ // src/hooks/useSettings.ts
3077
+ function useSettings(editorSettings, override) {
3078
+ return useMemo15(
3079
+ () => mergeSettings(editorSettings ?? DEFAULT_EDITOR_SETTINGS, override),
3080
+ [editorSettings, override]
3081
+ );
3082
+ }
3083
+
3084
+ // src/components/BlockEditor/BlockEditor.tsx
3085
+ import { jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
3086
+ function BlockEditor({ settings: settingsOverride, editorSettings, ...props }) {
3087
+ const menuContainerRef = useRef14(null);
3088
+ const settings = useSettings(editorSettings, settingsOverride);
3089
+ const { editor, getFilteredBlockMenus } = useBlockEditor({
3090
+ ...props,
3091
+ blockMenus: settings.blockMenus,
3092
+ imageDefaultLightbox: settings.features.imageDefaultLightbox
3093
+ });
3094
+ if (!editor) {
3095
+ return null;
3096
+ }
3097
+ return /* @__PURE__ */ jsxs24(SettingsProvider, { settings, children: [
3098
+ /* @__PURE__ */ jsx25("div", { className: "acms-admin-block-editor-container", children: /* @__PURE__ */ jsxs24("div", { className: "acms-admin-block-editor", ref: menuContainerRef, children: [
3099
+ /* @__PURE__ */ jsx25(EditorContent, { editor, className: "acms-admin-block-editor-content" }),
3100
+ /* @__PURE__ */ jsx25(ContentItemMenu, { editor, getFilteredBlockMenus }),
3101
+ /* @__PURE__ */ jsx25(LinkMenu, { editor, appendTo: menuContainerRef }),
3102
+ /* @__PURE__ */ jsx25(TextMenu, { editor, appendTo: menuContainerRef }),
3103
+ /* @__PURE__ */ jsx25(TableMenu, { editor, appendTo: menuContainerRef }),
3104
+ /* @__PURE__ */ jsx25(TableRowMenu, { editor, appendTo: menuContainerRef }),
3105
+ /* @__PURE__ */ jsx25(TableColumnMenu, { editor, appendTo: menuContainerRef }),
3106
+ /* @__PURE__ */ jsx25(ImageBlockMenu_default, { editor, appendTo: menuContainerRef }),
3107
+ /* @__PURE__ */ jsx25(FileBlockMenu_default, { editor, appendTo: menuContainerRef }),
3108
+ /* @__PURE__ */ jsx25(LinkButtonMenu_default, { editor, appendTo: menuContainerRef }),
3109
+ /* @__PURE__ */ jsx25(
3110
+ Slot,
3111
+ {
3112
+ name: "block-editor.menus",
3113
+ fillProps: { editor, appendTo: menuContainerRef }
3114
+ }
3115
+ )
3116
+ ] }) }),
3117
+ /* @__PURE__ */ jsx25(Tooltip, { id: "block-editor-shared-tooltip", delayShow: 150 })
3118
+ ] });
3119
+ }
3120
+ var BlockEditor_default = BlockEditor;
3121
+
3122
+ export {
3123
+ BlockEditor,
3124
+ BlockEditor_default
3125
+ };
3126
+ //# sourceMappingURL=chunk-S24TRRWW.mjs.map