@antscorp/antsomi-ui 1.3.7-beta.6 → 1.3.7-beta.60

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 (158) hide show
  1. package/es/components/atoms/InputDynamic/InputDynamic.js +3 -3
  2. package/es/components/icons/LazyIcon/LazyIcon.d.ts +2 -0
  3. package/es/components/icons/LazyIcon/LazyIcon.js +2 -0
  4. package/es/components/icons/QRCodeManagementIcon.d.ts +3 -0
  5. package/es/components/icons/QRCodeManagementIcon.js +7 -0
  6. package/es/components/icons/QRSetDashboardIcon.d.ts +3 -0
  7. package/es/components/icons/QRSetDashboardIcon.js +7 -0
  8. package/es/components/icons/index.d.ts +2 -0
  9. package/es/components/icons/index.js +2 -0
  10. package/es/components/molecules/AddDynamicContent/AddDynamicContent.js +28 -2
  11. package/es/components/molecules/AddDynamicContent/constants.d.ts +2 -0
  12. package/es/components/molecules/AddDynamicContent/constants.js +2 -0
  13. package/es/components/molecules/ColorPicker/index.d.ts +2 -0
  14. package/es/components/molecules/ColorPicker/index.js +8 -3
  15. package/es/components/molecules/EmojiPopover/EmojiPopover.d.ts +1 -0
  16. package/es/components/molecules/EmojiPopover/EmojiPopover.js +2 -2
  17. package/es/components/molecules/EmojiPopover/styled.d.ts +2 -2
  18. package/es/components/molecules/EmojiPopover/styled.js +1 -1
  19. package/es/components/molecules/HeaderV2/HeaderV2.d.ts +1 -1
  20. package/es/components/molecules/Modal/Modal.js +7 -1
  21. package/es/components/molecules/SearchPopover/SearchPopover.js +2 -2
  22. package/es/components/molecules/SearchPopover/styled.d.ts +12 -1
  23. package/es/components/molecules/SearchPopover/styled.js +1 -2
  24. package/es/components/molecules/SearchPopover/types.d.ts +4 -3
  25. package/es/components/molecules/Select/Select.js +1 -1
  26. package/es/components/molecules/ShareAccess/ShareAccess.d.ts +2 -1
  27. package/es/components/molecules/ShareAccess/ShareAccess.js +12 -9
  28. package/es/components/molecules/ShareAccess/components/LayoutContent/LayoutContent.js +5 -5
  29. package/es/components/molecules/ShareAccess/components/PeopleAccess/PeopleAccess.js +2 -2
  30. package/es/components/molecules/ShareAccess/hooks/useShareAccess.d.ts +2 -1
  31. package/es/components/molecules/ShareAccess/index.d.ts +1 -0
  32. package/es/components/molecules/ShareAccess/reducer.d.ts +1 -1
  33. package/es/components/molecules/ShareAccess/reducer.js +7 -4
  34. package/es/components/molecules/ShareAccess/types.d.ts +22 -0
  35. package/es/components/molecules/ShareAccess/utils.d.ts +3 -1
  36. package/es/components/molecules/ShareAccess/utils.js +35 -2
  37. package/es/components/molecules/TagifyInput/TagifyInput.js +48 -27
  38. package/es/components/molecules/TagifyInput/types.d.ts +14 -8
  39. package/es/components/molecules/TagifyInput/utils.d.ts +6 -1
  40. package/es/components/molecules/TagifyInput/utils.js +19 -0
  41. package/es/components/molecules/VirtualizedMenu/VirtualizedMenu.d.ts +1 -0
  42. package/es/components/molecules/VirtualizedMenu/components/Item/Item.js +3 -7
  43. package/es/components/molecules/VirtualizedMenu/components/MenuInline/MenuInline.d.ts +10 -10
  44. package/es/components/molecules/VirtualizedMenu/components/MenuInline/MenuInline.js +46 -327
  45. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/index.d.ts +9 -0
  46. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/index.js +5 -0
  47. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useFocusManagement.d.ts +23 -0
  48. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useFocusManagement.js +81 -0
  49. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useItemInteraction.d.ts +24 -0
  50. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useItemInteraction.js +32 -0
  51. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useKeyboardNavigation.d.ts +26 -0
  52. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useKeyboardNavigation.js +93 -0
  53. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useTreeState.d.ts +24 -0
  54. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useTreeState.js +94 -0
  55. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useVisibleItems.d.ts +7 -0
  56. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useVisibleItems.js +132 -0
  57. package/es/components/molecules/VirtualizedMenu/styled.js +14 -3
  58. package/es/components/molecules/VirtualizedMenu/types.d.ts +1 -0
  59. package/es/components/molecules/VirtualizedMenu/utils.d.ts +1 -0
  60. package/es/components/molecules/VirtualizedMenu/utils.js +1 -0
  61. package/es/components/molecules/index.d.ts +1 -0
  62. package/es/components/organism/AccountSharing/AccountSharing.d.ts +1 -0
  63. package/es/components/organism/AccountSharing/AccountSharing.js +11 -4
  64. package/es/components/organism/AccountSharing/styled.js +1 -1
  65. package/es/components/organism/ActivityTimeline/ActivityTimeline.js +3 -3
  66. package/es/components/organism/ActivityTimeline/constants.d.ts +9 -9
  67. package/es/components/organism/ActivityTimeline/constants.js +3 -3
  68. package/es/components/organism/ActivityTimeline/index.d.ts +530 -1
  69. package/es/components/organism/ActivityTimeline/index.js +9 -1
  70. package/es/components/organism/ActivityTimeline/utils.js +175 -8
  71. package/es/components/organism/LeftMenu/LeftMenu.js +3 -3
  72. package/es/components/organism/LeftMenu/hooks/usePermission.js +1 -1
  73. package/es/components/organism/LeftMenu/types/index.d.ts +7 -0
  74. package/es/components/organism/LeftMenu/utils/index.js +1 -1
  75. package/es/components/organism/Login/Login.js +12 -3
  76. package/es/components/organism/Login/components/SignIn/SignIn.js +2 -2
  77. package/es/components/organism/Login/types/index.d.ts +2 -0
  78. package/es/components/organism/TextEditor/TextEditor.d.ts +9 -2
  79. package/es/components/organism/TextEditor/TextEditor.js +203 -42
  80. package/es/components/organism/TextEditor/constants.d.ts +9 -0
  81. package/es/components/organism/TextEditor/constants.js +66 -0
  82. package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu-plugin.d.ts +6 -128
  83. package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu-plugin.js +7 -292
  84. package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu.d.ts +1 -1
  85. package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu.js +4 -0
  86. package/es/components/organism/TextEditor/extensions/Link.js +33 -14
  87. package/es/components/organism/TextEditor/extensions/ListItem.d.ts +10 -0
  88. package/es/components/organism/TextEditor/extensions/ListItem.js +93 -0
  89. package/es/components/organism/TextEditor/extensions/SmartTag.d.ts +5 -6
  90. package/es/components/organism/TextEditor/extensions/SmartTag.js +96 -4
  91. package/es/components/organism/TextEditor/hooks/useColorSet.js +7 -0
  92. package/es/components/organism/TextEditor/hooks/useMarkTracking.js +2 -1
  93. package/es/components/organism/TextEditor/index.d.ts +7 -5
  94. package/es/components/organism/TextEditor/index.scss +4 -7
  95. package/es/components/organism/TextEditor/provider.d.ts +1 -0
  96. package/es/components/organism/TextEditor/provider.js +6 -3
  97. package/es/components/organism/TextEditor/store.d.ts +11 -4
  98. package/es/components/organism/TextEditor/store.js +22 -2
  99. package/es/components/organism/TextEditor/stories/WithOldDynAndLink/froala-legacy-format.settings.json +95 -0
  100. package/es/components/organism/TextEditor/stories/WithOldDynAndLink/shared.d.ts +111 -0
  101. package/es/components/organism/TextEditor/stories/WithOldDynAndLink/shared.js +82 -0
  102. package/es/components/organism/TextEditor/stories/shared.d.ts +64 -0
  103. package/es/components/organism/TextEditor/stories/shared.js +57 -0
  104. package/es/components/organism/TextEditor/styled.d.ts +1 -1
  105. package/es/components/organism/TextEditor/styled.js +1 -0
  106. package/es/components/organism/TextEditor/types.d.ts +161 -11
  107. package/es/components/organism/TextEditor/types.js +1 -0
  108. package/es/components/organism/TextEditor/ui/BubbleMenu/BubbleMenu.d.ts +2 -1
  109. package/es/components/organism/TextEditor/ui/BubbleMenu/BubbleMenu.js +80 -51
  110. package/es/components/organism/TextEditor/ui/Emoji/EmojiList.js +1 -1
  111. package/es/components/organism/TextEditor/ui/Emoji/suggestion.d.ts +1 -1
  112. package/es/components/organism/TextEditor/ui/Emoji/suggestion.js +2 -2
  113. package/es/components/organism/TextEditor/ui/FontPopover/FontPopover.js +12 -2
  114. package/es/components/organism/TextEditor/ui/LinkInsertForm/LinkInsertForm.d.ts +16 -0
  115. package/es/components/organism/TextEditor/ui/LinkInsertForm/LinkInsertForm.js +61 -0
  116. package/es/components/organism/TextEditor/ui/LinkInsertForm/index.d.ts +2 -0
  117. package/es/components/organism/TextEditor/ui/LinkInsertForm/index.js +1 -0
  118. package/es/components/organism/TextEditor/ui/LinkPopover/LinkPopover.d.ts +9 -0
  119. package/es/components/organism/TextEditor/ui/LinkPopover/LinkPopover.js +126 -0
  120. package/es/components/organism/TextEditor/ui/LinkPopover/index.d.ts +2 -0
  121. package/es/components/organism/TextEditor/ui/LinkPopover/index.js +1 -0
  122. package/es/components/organism/TextEditor/ui/Popover/Popover.js +1 -1
  123. package/es/components/organism/TextEditor/ui/TextAlignSelect/TextAlignSelect.js +1 -3
  124. package/es/components/organism/TextEditor/ui/Toolbar/{Toolbar.d.ts → FormattingToolbar.d.ts} +3 -4
  125. package/es/components/organism/TextEditor/ui/Toolbar/FormattingToolbar.js +90 -0
  126. package/es/components/organism/TextEditor/ui/Toolbar/LinkPreviewToolbar.d.ts +10 -0
  127. package/es/components/organism/TextEditor/ui/Toolbar/LinkPreviewToolbar.js +39 -0
  128. package/es/components/organism/TextEditor/ui/Toolbar/actions/EmojiAction.js +4 -3
  129. package/es/components/organism/TextEditor/ui/Toolbar/actions/FontFamilyAction.d.ts +1 -0
  130. package/es/components/organism/TextEditor/ui/Toolbar/actions/FontFamilyAction.js +2 -2
  131. package/es/components/organism/TextEditor/ui/Toolbar/actions/FontSizeAction.js +6 -1
  132. package/es/components/organism/TextEditor/ui/Toolbar/index.d.ts +2 -1
  133. package/es/components/organism/TextEditor/ui/Toolbar/index.js +2 -1
  134. package/es/components/organism/TextEditor/utils/documentState.d.ts +14 -0
  135. package/es/components/organism/TextEditor/utils/documentState.js +25 -0
  136. package/es/components/organism/TextEditor/utils/htmlProcessing.js +60 -0
  137. package/es/components/organism/TextEditor/utils/link.d.ts +10 -1
  138. package/es/components/organism/TextEditor/utils/link.js +161 -7
  139. package/es/components/organism/TextEditor/utils/menu.js +2 -1
  140. package/es/components/organism/TextEditor/utils/selection.js +3 -2
  141. package/es/components/organism/TextEditor/utils/smartTag.js +2 -1
  142. package/es/components/organism/index.d.ts +1 -1
  143. package/es/hooks/index.d.ts +1 -1
  144. package/es/hooks/index.js +1 -1
  145. package/es/providers/ConfigProvider/ConfigProvider.d.ts +4 -0
  146. package/es/providers/ConfigProvider/ConfigProvider.js +2 -3
  147. package/es/providers/ConfigProvider/GlobalStyle.d.ts +2 -2
  148. package/es/providers/ConfigProvider/GlobalStyle.js +67 -64
  149. package/es/services/MediaTemplateDesign/UploadFile/index.js +4 -4
  150. package/es/utils/common.d.ts +1 -1
  151. package/es/utils/common.js +3 -3
  152. package/es/utils/cookie.js +2 -1
  153. package/package.json +18 -23
  154. package/es/components/organism/TextEditor/ui/BubbleToolbar/BubbleToolbar.d.ts +0 -1
  155. package/es/components/organism/TextEditor/ui/BubbleToolbar/BubbleToolbar.js +0 -1
  156. package/es/components/organism/TextEditor/ui/BubbleToolbar/index.d.ts +0 -0
  157. package/es/components/organism/TextEditor/ui/BubbleToolbar/index.js +0 -1
  158. package/es/components/organism/TextEditor/ui/Toolbar/Toolbar.js +0 -39
@@ -1,16 +1,16 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { ANTSOMI_COMPONENT_PREFIX_CLS } from '@antscorp/antsomi-ui/es/constants';
3
- import { useDeepCompareMemo } from '@antscorp/antsomi-ui/es/hooks';
3
+ import { useDeepCompareEffect, useDeepCompareMemo } from '@antscorp/antsomi-ui/es/hooks';
4
4
  import SubScript from '@tiptap/extension-subscript';
5
5
  import Superscript from '@tiptap/extension-superscript';
6
6
  import TextAlign from '@tiptap/extension-text-align';
7
7
  import { TextStyleKit } from '@tiptap/extension-text-style';
8
- import { Selection } from '@tiptap/extensions';
8
+ import { Selection, Focus } from '@tiptap/extensions';
9
9
  import { useEditor } from '@tiptap/react';
10
10
  import StarterKit from '@tiptap/starter-kit';
11
11
  import clsx from 'clsx';
12
- import { isBoolean, omit } from 'lodash';
13
- import { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useRef, } from 'react';
12
+ import { isBoolean } from 'lodash';
13
+ import { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, } from 'react';
14
14
  import { useDebouncedCallback } from 'use-debounce';
15
15
  import { DEFAULT_TEXT_STYLE } from './constants';
16
16
  import { BackgroundColor } from './extensions/BackgroundColor';
@@ -23,29 +23,54 @@ import { Indent } from './extensions/Indent';
23
23
  import { LetterSpacing } from './extensions/LetterSpacing';
24
24
  import { LineHeight } from './extensions/LineHeight';
25
25
  import { CustomLink } from './extensions/Link';
26
+ import { CustomListItem } from './extensions/ListItem';
26
27
  import { CustomOrderedList } from './extensions/OrderedList';
27
28
  import { SmartTag } from './extensions/SmartTag';
28
29
  import { TextTransform } from './extensions/TextTransform';
29
30
  import { CustomUnorderedList } from './extensions/UnorderedList';
30
31
  import { ClearFormatting } from './extensions/ClearFormatting';
31
- import { useTextEditorStore } from './provider';
32
+ import { TextEditorProvider, useTextEditorStore, } from './provider';
32
33
  import { StyledEditorContent } from './styled';
34
+ import { isSmartTagNode, } from './types';
33
35
  import { emojiSuggestion } from './ui/Emoji';
34
- import { Toolbar } from './ui/Toolbar';
35
- import { analyzeFont, defaultShouldShowBubbleMenu, handleLinkAction, handleSmartTagAction, isShowLinkToolbar, safeParseHTMLContent, htmlSerializerForOutput, } from './utils';
36
+ import { LinkPreviewToolbar, FormattingToolbar } from './ui/Toolbar';
37
+ import { analyzeFont, defaultShouldShowBubbleMenu, getAllFullLinkGroups, handleLinkAction, handleSmartTagAction, isShowLinkToolbar, safeParseHTMLContent, htmlSerializerForOutput, } from './utils';
36
38
  import { BubbleMenu } from './ui/BubbleMenu';
37
- export const TextEditor = memo(forwardRef((props, ref) => {
38
- const { id, className, config, editable = true, initialContent = '', dataAttributes, onUpdateDebounced = 400, defaultTextStyle: defaultTextStyleProp, linkHandler: outerLinkHandler, smartTagHandler: outerSmartTagHandler, bubbleMenuProps, style, render, onUpdate, onFocus, onChangeFont, } = props;
39
- const isShowBubbleMenu = useTextEditorStore(state => state.isShowBubbleMenu);
39
+ import { LinkPopover } from './ui/LinkPopover';
40
+ const TextEditorInternal = memo(forwardRef((props, ref) => {
41
+ const { id, className, config, editable = true, initialContent = '', dataAttributes, onUpdateDebounced = 300, defaultTextStyle: defaultTextStyleProp, linkHandler: outerLinkHandler, smartTagHandler: outerSmartTagHandler, bubbleMenuProps, style, render, onUpdate, onFocus, onCreate, onChangeFont, } = props;
42
+ // Initialize bubbleMenuContainer with default value (document.body)
43
+ // This ensures BubbleMenu receives a valid appendTo prop on first render
44
+ const bubbleMenuContainer = useRef((() => {
45
+ const appendTo = bubbleMenuProps?.appendTo;
46
+ if (!appendTo)
47
+ return document.body;
48
+ return typeof appendTo === 'function' ? appendTo() : appendTo;
49
+ })());
50
+ const linkFormVisible = useTextEditorStore(state => state.linkFormState?.isVisible);
40
51
  const setBubbleMenuContainer = useTextEditorStore(state => state.setBubbleMenuContainer);
52
+ const showLinkForm = useTextEditorStore(state => state.showLinkForm);
41
53
  const defaultTextStyle = useDeepCompareMemo(() => ({
42
54
  ...DEFAULT_TEXT_STYLE,
43
55
  ...defaultTextStyleProp,
44
56
  }), [defaultTextStyleProp]);
57
+ useEffect(() => {
58
+ const bubbleMenuAppendTo = bubbleMenuProps?.appendTo;
59
+ // Default to document.body when no appendTo is provided
60
+ // This prevents bubble menu from being clipped by overflow containers
61
+ const el = bubbleMenuAppendTo
62
+ ? typeof bubbleMenuAppendTo === 'function'
63
+ ? bubbleMenuAppendTo()
64
+ : bubbleMenuAppendTo
65
+ : document.body;
66
+ setBubbleMenuContainer(el);
67
+ bubbleMenuContainer.current = el;
68
+ }, [bubbleMenuProps?.appendTo, setBubbleMenuContainer]);
45
69
  const handleOnUpdateDebounce = useDebouncedCallback((editor) => {
46
- const html = editor.getHTML();
47
70
  const text = editor.getText();
48
71
  const json = editor.getJSON();
72
+ const html = editor.getHTML();
73
+ // console.log(id, { text });
49
74
  onUpdate?.({
50
75
  html: htmlSerializerForOutput(html),
51
76
  text,
@@ -53,21 +78,40 @@ export const TextEditor = memo(forwardRef((props, ref) => {
53
78
  });
54
79
  }, onUpdateDebounced);
55
80
  const contentRef = useRef(null);
81
+ // Compose linkHandler: merge outerLinkHandler with default handlers
82
+ // Allows partial override - user can provide only setNew or only edit
83
+ const linkHandler = useMemo(() => {
84
+ const defaultSetNew = ({ selectionText }) => {
85
+ showLinkForm('insert', {
86
+ url: '',
87
+ text: selectionText,
88
+ openInNewTab: false,
89
+ });
90
+ };
91
+ const defaultEdit = ({ attrs, selectionText, }) => {
92
+ showLinkForm('edit', {
93
+ url: attrs.href || '',
94
+ text: selectionText,
95
+ openInNewTab: attrs.target === '_blank',
96
+ });
97
+ };
98
+ return {
99
+ setNew: outerLinkHandler?.setNew || defaultSetNew,
100
+ edit: outerLinkHandler?.edit || defaultEdit,
101
+ };
102
+ }, [outerLinkHandler, showLinkForm]);
56
103
  const editor = useEditor({
57
104
  extensions: [
58
105
  StarterKit.configure({
59
106
  link: false,
60
107
  bulletList: false,
61
108
  orderedList: false,
62
- listItem: {
63
- HTMLAttributes: {
64
- style: 'line-height:normal;',
65
- },
66
- },
67
- undoRedo: {
109
+ listItem: false,
110
+ undoRedo: config?.UndoRedo && {
68
111
  depth: 100,
69
112
  },
70
113
  }),
114
+ CustomListItem,
71
115
  CustomUnorderedList,
72
116
  CustomOrderedList,
73
117
  FontWeight.configure({
@@ -107,7 +151,12 @@ export const TextEditor = memo(forwardRef((props, ref) => {
107
151
  Selection.configure({
108
152
  className: 'selection',
109
153
  }),
110
- SmartTag,
154
+ Focus.configure({
155
+ className: 'has-focused',
156
+ }),
157
+ SmartTag.configure({
158
+ generateSmartTagId: config?.SmartTag?.generateId,
159
+ }),
111
160
  TextAlign.configure({
112
161
  types: ['heading', 'paragraph'],
113
162
  }),
@@ -121,7 +170,7 @@ export const TextEditor = memo(forwardRef((props, ref) => {
121
170
  Indent,
122
171
  Emoji.configure({
123
172
  suggestion: emojiSuggestion({
124
- container: bubbleMenuProps?.container,
173
+ container: bubbleMenuContainer.current,
125
174
  }),
126
175
  }),
127
176
  ClearFormatting.configure({
@@ -138,9 +187,22 @@ export const TextEditor = memo(forwardRef((props, ref) => {
138
187
  wrapperElement: contentRef.current.parentElement,
139
188
  defaultStyle: defaultTextStyle,
140
189
  });
190
+ // console.log(
191
+ // '[ONCREATE] safeParseContent !== initialContent:',
192
+ // safeParseContent !== initialContent,
193
+ // );
141
194
  if (safeParseContent !== initialContent) {
195
+ // console.log('[ONCREATE] Calling setContent - this RESETS editor content!');
142
196
  editor.commands.setContent(safeParseContent);
143
197
  }
198
+ const text = editor.getText();
199
+ const json = editor.getJSON();
200
+ const html = editor.getHTML();
201
+ onCreate?.({
202
+ html: htmlSerializerForOutput(html),
203
+ text,
204
+ json,
205
+ });
144
206
  },
145
207
  onUpdate: ({ editor }) => {
146
208
  handleOnUpdateDebounce(editor);
@@ -154,7 +216,7 @@ export const TextEditor = memo(forwardRef((props, ref) => {
154
216
  if (event.ctrlKey && event.key === 'k') {
155
217
  // Add this line to prevent browser's default behavior.
156
218
  event.preventDefault();
157
- handleLinkAction(view, outerLinkHandler);
219
+ handleLinkAction(view, linkHandler);
158
220
  }
159
221
  },
160
222
  },
@@ -183,10 +245,15 @@ export const TextEditor = memo(forwardRef((props, ref) => {
183
245
  return updatedAttrs;
184
246
  })
185
247
  .run(), [editor]);
186
- const shouldShowBubbleMenu = useCallback((params) => {
248
+ const shouldShowLinkPreview = useCallback((params) => {
249
+ const { state } = params;
250
+ return isShowLinkToolbar(state);
251
+ }, []);
252
+ const shouldShowFormattingToolbar = useCallback((params) => {
187
253
  const { state, view, element } = params;
254
+ // Don't show if link preview is visible
188
255
  if (isShowLinkToolbar(state)) {
189
- return true;
256
+ return false;
190
257
  }
191
258
  return defaultShouldShowBubbleMenu({
192
259
  state,
@@ -203,10 +270,25 @@ export const TextEditor = memo(forwardRef((props, ref) => {
203
270
  editor?.chain().blur().setTextSelection({ from: 0, to: 0 }).run();
204
271
  }
205
272
  }, [editor]);
206
- const handleBubbleMenuRef = useCallback((htmlElement) => {
207
- setBubbleMenuContainer(htmlElement);
208
- }, [setBubbleMenuContainer]);
273
+ const handleEachLinkGroup = useCallback(callback => {
274
+ if (!editor)
275
+ return;
276
+ const linkGroups = getAllFullLinkGroups(editor.state);
277
+ linkGroups.forEach(callback);
278
+ }, [editor]);
279
+ const handleEachSmartag = useCallback(callback => {
280
+ if (!editor)
281
+ return;
282
+ const { state } = editor;
283
+ const { doc } = state;
284
+ doc.descendants(node => {
285
+ if (isSmartTagNode(node)) {
286
+ callback(node.attrs);
287
+ }
288
+ });
289
+ }, [editor]);
209
290
  useImperativeHandle(ref, () => ({
291
+ editor,
210
292
  setLink: params => {
211
293
  editor?.chain().setCustomLink(params).run();
212
294
  },
@@ -226,33 +308,112 @@ export const TextEditor = memo(forwardRef((props, ref) => {
226
308
  })
227
309
  .run();
228
310
  },
311
+ getHTML: () => htmlSerializerForOutput(editor.getHTML()),
312
+ eachLinkGroup: handleEachLinkGroup,
313
+ eachSmartag: handleEachSmartag,
229
314
  setSmartTag: handleSetSmartTag,
230
315
  deleteSmartTag: handleDeleteSmartTag,
231
316
  updateSmartTagAttrs: handleUpdateSmartTagAttrs,
232
317
  blur: handleBlur,
318
+ focus() {
319
+ editor.chain().focus().run();
320
+ },
321
+ setContent: editor.commands.setContent,
233
322
  style: contentRef.current?.style,
234
- editor,
235
323
  }));
236
324
  if (!editor) {
237
325
  return null;
238
326
  }
327
+ const bubbleMenus = (bubbleMenuProps?.enabled ?? true) ? (_jsxs(_Fragment, { children: [_jsx(LinkPopover, { editor: editor }), !linkFormVisible && (_jsxs(_Fragment, { children: [_jsx(BubbleMenu, { pluginKey: "linkPreviewBubbleMenu", ...bubbleMenuProps, appendTo: bubbleMenuContainer.current, editor: editor, shouldShow: shouldShowLinkPreview, children: _jsx(LinkPreviewToolbar, { editor: editor, linkHanlder: {
328
+ onUpsert: () => {
329
+ handleLinkAction(editor.view, linkHandler);
330
+ },
331
+ }, render: render }) }), _jsx(BubbleMenu, { pluginKey: "formattingBubbleMenu", ...bubbleMenuProps, appendTo: bubbleMenuContainer.current, editor: editor, shouldShow: shouldShowFormattingToolbar, children: _jsx(FormattingToolbar, { config: config, editor: editor, defaultTextStyle: defaultTextStyle, linkHanlder: {
332
+ onUpsert: () => {
333
+ handleLinkAction(editor.view, linkHandler);
334
+ },
335
+ }, smartTagHandler: {
336
+ onUpsert: (event) => {
337
+ handleSmartTagAction(event, editor.view, outerSmartTagHandler);
338
+ },
339
+ }, onChangeFont: ({ font, weight }) => {
340
+ onChangeFont?.({
341
+ font,
342
+ weight,
343
+ analysis: analyzeFont(font),
344
+ });
345
+ } }) })] }))] })) : null;
239
346
  return (_jsxs(_Fragment, { children: [_jsx(StyledEditorContent, { className: clsx(`${ANTSOMI_COMPONENT_PREFIX_CLS}-text-editor`, className), "$textStyle": defaultTextStyle, style: {
240
347
  // Inline styles apply to inner html elements (support email client)
241
- ...omit(defaultTextStyle, ['fontSize']),
348
+ ...defaultTextStyle,
242
349
  ...style,
243
- }, id: id, ref: contentRef, editor: editor, ...dataAttributes }), _jsx(BubbleMenu, { ref: handleBubbleMenuRef, editor: editor, shouldShow: shouldShowBubbleMenu, resizeDelay: 700, ...bubbleMenuProps, children: isShowBubbleMenu && (_jsx(Toolbar, { config: config, editor: editor, defaultTextStyle: defaultTextStyle, linkHanlder: {
244
- onUpsert: () => {
245
- handleLinkAction(editor.view, outerLinkHandler);
246
- },
247
- }, smartTagHandler: {
248
- onUpsert: (event) => {
249
- handleSmartTagAction(event, editor.view, outerSmartTagHandler);
250
- },
251
- }, render: render, onChangeFont: ({ font, weight }) => {
252
- onChangeFont?.({
253
- font,
254
- weight,
255
- analysis: analyzeFont(font),
256
- });
257
- } })) })] }));
350
+ }, id: id, ref: contentRef, editor: editor, ...dataAttributes }), bubbleMenus] }));
258
351
  }));
352
+ TextEditorInternal.displayName = 'TextEditorInternal';
353
+ const TextEditorWithProvider = forwardRef((props, ref) => {
354
+ const { colors, onChangeColors, ...editorProps } = props;
355
+ const providerRef = useRef(null);
356
+ const editorRef = useRef(null);
357
+ // Sync external colors to internal store
358
+ useDeepCompareEffect(() => {
359
+ if (colors !== undefined) {
360
+ providerRef.current?.updateColors?.(colors);
361
+ }
362
+ }, [colors]);
363
+ useImperativeHandle(ref, () => ({
364
+ // Forward TextEditorRef methods - accessed at call time
365
+ get editor() {
366
+ return editorRef.current?.editor;
367
+ },
368
+ get style() {
369
+ return editorRef.current?.style;
370
+ },
371
+ get getHTML() {
372
+ return editorRef.current.getHTML;
373
+ },
374
+ get setLink() {
375
+ return editorRef.current.setLink;
376
+ },
377
+ get deleteLink() {
378
+ return editorRef.current.deleteLink;
379
+ },
380
+ get updateLinkAttrs() {
381
+ return editorRef.current.updateLinkAttrs;
382
+ },
383
+ get updateLinkText() {
384
+ return editorRef.current.updateLinkText;
385
+ },
386
+ get eachLinkGroup() {
387
+ return editorRef.current.eachLinkGroup;
388
+ },
389
+ get eachSmartag() {
390
+ return editorRef.current.eachSmartag;
391
+ },
392
+ get setSmartTag() {
393
+ return editorRef.current.setSmartTag;
394
+ },
395
+ get deleteSmartTag() {
396
+ return editorRef.current.deleteSmartTag;
397
+ },
398
+ get updateSmartTagAttrs() {
399
+ return editorRef.current.updateSmartTagAttrs;
400
+ },
401
+ get blur() {
402
+ return editorRef.current.blur;
403
+ },
404
+ get focus() {
405
+ return editorRef.current.focus;
406
+ },
407
+ get setContent() {
408
+ return editorRef.current.setContent;
409
+ },
410
+ // Forward TextEditorProviderRefHandler methods
411
+ updateColors: colors => providerRef.current?.updateColors?.(colors),
412
+ }), []);
413
+ return (_jsx(TextEditorProvider, { ref: providerRef, colors: colors, onChangeColors: onChangeColors, children: _jsx(TextEditorInternal, { ...editorProps, ref: editorRef }) }));
414
+ });
415
+ TextEditorWithProvider.displayName = 'TextEditorWithProvider';
416
+ export const TextEditor = Object.assign(TextEditorWithProvider, {
417
+ Provider: TextEditorProvider,
418
+ Internal: TextEditorInternal,
419
+ });
@@ -185,3 +185,12 @@ export declare const DEFAULT_FONT_GROUPING: {
185
185
  readonly label: "Non-standard";
186
186
  };
187
187
  };
188
+ /**
189
+ * All available toolbar actions in default order
190
+ */
191
+ export declare const ALL_TOOLBAR_ACTIONS: readonly ["fontFamily", "fontSize", "bold", "italic", "underline", "link", "strike", "superscript", "subscript", "textTransform", "textColor", "backgroundColor", "emoji", "smartTag", "bulletList", "orderedList", "textAlign", "lineSpacing", "letterSpacing", "indent", "outdent", "history", "clearFormatting"];
192
+ /**
193
+ * Default grouping of toolbar actions into rows
194
+ */
195
+ export declare const DEFAULT_TOOLBAR_GROUPING: readonly [readonly ["fontFamily", "fontSize", "bold", "italic", "underline", "link", "strike", "superscript", "subscript", "textTransform", "textColor", "backgroundColor", "emoji", "smartTag"], readonly ["bulletList", "orderedList", "textAlign", "lineSpacing", "letterSpacing", "indent", "outdent", "history", "clearFormatting"]];
196
+ export declare const ATTR_WHITESPACE: RegExp;
@@ -330,3 +330,69 @@ export const DEFAULT_FONT_GROUPING = {
330
330
  label: 'Non-standard',
331
331
  },
332
332
  };
333
+ /**
334
+ * All available toolbar actions in default order
335
+ */
336
+ export const ALL_TOOLBAR_ACTIONS = [
337
+ // Row 1: Text formatting and styling
338
+ 'fontFamily',
339
+ 'fontSize',
340
+ 'bold',
341
+ 'italic',
342
+ 'underline',
343
+ 'link',
344
+ 'strike',
345
+ 'superscript',
346
+ 'subscript',
347
+ 'textTransform',
348
+ 'textColor',
349
+ 'backgroundColor',
350
+ 'emoji',
351
+ 'smartTag',
352
+ // Row 2: Lists, alignment, and utilities
353
+ 'bulletList',
354
+ 'orderedList',
355
+ 'textAlign',
356
+ 'lineSpacing',
357
+ 'letterSpacing',
358
+ 'indent',
359
+ 'outdent',
360
+ 'history',
361
+ 'clearFormatting',
362
+ ];
363
+ /**
364
+ * Default grouping of toolbar actions into rows
365
+ */
366
+ export const DEFAULT_TOOLBAR_GROUPING = [
367
+ // Row 1
368
+ [
369
+ 'fontFamily',
370
+ 'fontSize',
371
+ 'bold',
372
+ 'italic',
373
+ 'underline',
374
+ 'link',
375
+ 'strike',
376
+ 'superscript',
377
+ 'subscript',
378
+ 'textTransform',
379
+ 'textColor',
380
+ 'backgroundColor',
381
+ 'emoji',
382
+ 'smartTag',
383
+ ],
384
+ // Row 2
385
+ [
386
+ 'bulletList',
387
+ 'orderedList',
388
+ 'textAlign',
389
+ 'lineSpacing',
390
+ 'letterSpacing',
391
+ 'indent',
392
+ 'outdent',
393
+ 'history',
394
+ 'clearFormatting',
395
+ ],
396
+ ];
397
+ // eslint-disable-next-line no-control-regex
398
+ export const ATTR_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g;
@@ -1,140 +1,18 @@
1
- import { arrow, autoPlacement, flip, hide, inline, offset, shift, size } from '@floating-ui/dom';
2
- import type { Editor } from '@tiptap/core';
3
- import type { EditorState, PluginView } from '@tiptap/pm/state';
4
- import { Plugin, PluginKey } from '@tiptap/pm/state';
1
+ import type { EditorState } from '@tiptap/pm/state';
2
+ import { BubbleMenuView as TiptapBubbleMenuView } from '@tiptap/extension-bubble-menu';
3
+ import { Plugin } from '@tiptap/pm/state';
5
4
  import type { EditorView } from '@tiptap/pm/view';
6
- export interface BubbleMenuPluginProps {
7
- /**
8
- * The plugin key.
9
- * @type {PluginKey | string}
10
- * @default 'bubbleMenu'
11
- */
12
- pluginKey: PluginKey | string;
13
- /**
14
- * The editor instance.
15
- */
16
- editor: Editor;
17
- /**
18
- * The DOM element that contains your menu.
19
- * @type {HTMLElement}
20
- * @default null
21
- */
22
- element: HTMLElement;
23
- container?: HTMLElement | (() => HTMLElement) | null;
24
- /**
25
- * The delay in milliseconds before the menu should be updated.
26
- * This can be useful to prevent performance issues.
27
- * @type {number}
28
- * @default 250
29
- */
30
- updateDelay?: number;
31
- /**
32
- * The delay in milliseconds before the menu position should be updated on window resize.
33
- * This can be useful to prevent performance issues.
34
- * @type {number}
35
- * @default 60
36
- */
37
- resizeDelay?: number;
38
- /**
39
- * A function that determines whether the menu should be shown or not.
40
- * If this function returns `false`, the menu will be hidden, otherwise it will be shown.
41
- */
42
- shouldShow?: ((props: {
43
- editor: Editor;
44
- element: HTMLElement;
45
- view: EditorView;
46
- state: EditorState;
47
- oldState?: EditorState;
48
- from: number;
49
- to: number;
50
- }) => boolean) | null;
51
- /**
52
- * The options for the bubble menu. Those are passed to Floating UI and include options for the placement, offset, flip, shift, arrow, size, autoPlacement,
53
- * hide, and inline middlewares.
54
- * @default {}
55
- * @see https://floating-ui.com/docs/computePosition#options
56
- */
57
- options?: {
58
- strategy?: 'absolute' | 'fixed';
59
- placement?: 'top' | 'right' | 'bottom' | 'left' | 'top-start' | 'top-end' | 'right-start' | 'right-end' | 'bottom-start' | 'bottom-end' | 'left-start' | 'left-end';
60
- offset?: Parameters<typeof offset>[0] | boolean;
61
- flip?: Parameters<typeof flip>[0] | boolean;
62
- shift?: Parameters<typeof shift>[0] | boolean;
63
- arrow?: Parameters<typeof arrow>[0] | false;
64
- size?: Parameters<typeof size>[0] | boolean;
65
- autoPlacement?: Parameters<typeof autoPlacement>[0] | boolean;
66
- hide?: Parameters<typeof hide>[0] | boolean;
67
- inline?: Parameters<typeof inline>[0] | boolean;
68
- onShow?: () => void;
69
- onHide?: () => void;
70
- onUpdate?: () => void;
71
- onDestroy?: () => void;
72
- };
73
- }
74
- export type BubbleMenuViewProps = BubbleMenuPluginProps & {
75
- view: EditorView;
76
- };
77
- export declare class BubbleMenuView implements PluginView {
78
- editor: Editor;
79
- element: HTMLElement;
80
- container?: HTMLElement | (() => HTMLElement) | null;
81
- view: EditorView;
82
- preventHide: boolean;
83
- updateDelay: number;
84
- resizeDelay: number;
85
- private updateDebounceTimer;
86
- private resizeDebounceTimer;
5
+ import type { BubbleMenuPluginProps, BubbleMenuViewProps } from '@tiptap/extension-bubble-menu';
6
+ export declare class BubbleMenuView extends TiptapBubbleMenuView {
87
7
  private resizeObserver;
88
- private isVisible;
89
- private floatingUIOptions;
90
- shouldShow: Exclude<BubbleMenuPluginProps['shouldShow'], null>;
91
- get middlewares(): {
92
- name: string;
93
- options?: any;
94
- fn: (state: {
95
- x: number;
96
- y: number;
97
- platform: import("@floating-ui/core").Platform;
98
- placement: import("@floating-ui/utils").Placement;
99
- initialPlacement: import("@floating-ui/utils").Placement;
100
- strategy: import("@floating-ui/utils").Strategy;
101
- middlewareData: import("@floating-ui/core").MiddlewareData;
102
- rects: import("@floating-ui/utils").ElementRects;
103
- elements: import("@floating-ui/dom").Elements;
104
- }) => import("@floating-ui/core").MiddlewareReturn | Promise<import("@floating-ui/core").MiddlewareReturn>;
105
- }[];
106
- constructor({ editor, element, view, updateDelay, resizeDelay, container, shouldShow, options, }: BubbleMenuViewProps);
107
- mousedownHandler: () => void;
108
- dragstartHandler: () => void;
109
- /**
110
- * Handles the window resize event and element resize event to update the position of the bubble menu.
111
- * It uses a debounce mechanism to prevent excessive updates.
112
- * The delay is defined by the `resizeDelay` property.
113
- */
114
- resizeHandler: (delay?: number) => void;
115
- /**
116
- * Window resize handler that uses the default resize delay.
117
- * This is a separate function to maintain the same reference for addEventListener/removeEventListener.
118
- */
119
- windowResizeHandler: () => void;
8
+ constructor(props: BubbleMenuViewProps);
120
9
  /**
121
10
  * Sets up ResizeObserver to watch for bubble menu element size changes.
122
11
  * This ensures the bubble menu position is updated when the element resizes
123
12
  * due to React component rendering different children, not just when the window resizes.
124
13
  */
125
14
  setupResizeObserver: () => void;
126
- focusHandler: () => void;
127
- blurHandler: ({ event }: {
128
- event: FocusEvent;
129
- }) => void;
130
- updatePosition(): void;
131
- update(view: EditorView, oldState?: EditorState): void;
132
- handleDebouncedUpdate: (view: EditorView, oldState?: EditorState) => void;
133
- getShouldShow(oldState?: EditorState): boolean | undefined;
134
15
  updateHandler: (view: EditorView, selectionChanged: boolean, docChanged: boolean, oldState?: EditorState) => void;
135
- private getContainer;
136
- show(): void;
137
- hide(): void;
138
16
  destroy(): void;
139
17
  }
140
18
  export declare const BubbleMenuPlugin: (options: BubbleMenuPluginProps) => Plugin<any>;