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

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 (159) hide show
  1. package/es/components/atoms/Input/Input.js +3 -1
  2. package/es/components/atoms/InputDynamic/InputDynamic.js +3 -3
  3. package/es/components/icons/LazyIcon/LazyIcon.d.ts +2 -0
  4. package/es/components/icons/LazyIcon/LazyIcon.js +2 -0
  5. package/es/components/icons/QRCodeManagementIcon.d.ts +3 -0
  6. package/es/components/icons/QRCodeManagementIcon.js +7 -0
  7. package/es/components/icons/QRSetDashboardIcon.d.ts +3 -0
  8. package/es/components/icons/QRSetDashboardIcon.js +7 -0
  9. package/es/components/icons/index.d.ts +2 -0
  10. package/es/components/icons/index.js +2 -0
  11. package/es/components/molecules/AddDynamicContent/AddDynamicContent.js +28 -2
  12. package/es/components/molecules/AddDynamicContent/constants.d.ts +2 -0
  13. package/es/components/molecules/AddDynamicContent/constants.js +2 -0
  14. package/es/components/molecules/ColorPicker/index.d.ts +2 -0
  15. package/es/components/molecules/ColorPicker/index.js +8 -3
  16. package/es/components/molecules/EmojiPopover/EmojiPopover.d.ts +1 -0
  17. package/es/components/molecules/EmojiPopover/EmojiPopover.js +2 -2
  18. package/es/components/molecules/EmojiPopover/styled.d.ts +2 -2
  19. package/es/components/molecules/EmojiPopover/styled.js +1 -1
  20. package/es/components/molecules/HeaderV2/HeaderV2.d.ts +1 -1
  21. package/es/components/molecules/Modal/Modal.js +7 -1
  22. package/es/components/molecules/SearchPopover/SearchPopover.js +2 -2
  23. package/es/components/molecules/SearchPopover/styled.d.ts +12 -1
  24. package/es/components/molecules/SearchPopover/styled.js +1 -2
  25. package/es/components/molecules/SearchPopover/types.d.ts +4 -3
  26. package/es/components/molecules/Select/Select.js +1 -1
  27. package/es/components/molecules/ShareAccess/ShareAccess.d.ts +2 -1
  28. package/es/components/molecules/ShareAccess/ShareAccess.js +12 -9
  29. package/es/components/molecules/ShareAccess/components/LayoutContent/LayoutContent.js +5 -5
  30. package/es/components/molecules/ShareAccess/components/PeopleAccess/PeopleAccess.js +2 -2
  31. package/es/components/molecules/ShareAccess/hooks/useShareAccess.d.ts +2 -1
  32. package/es/components/molecules/ShareAccess/index.d.ts +1 -0
  33. package/es/components/molecules/ShareAccess/reducer.d.ts +1 -1
  34. package/es/components/molecules/ShareAccess/reducer.js +7 -4
  35. package/es/components/molecules/ShareAccess/types.d.ts +22 -0
  36. package/es/components/molecules/ShareAccess/utils.d.ts +3 -1
  37. package/es/components/molecules/ShareAccess/utils.js +35 -2
  38. package/es/components/molecules/TagifyInput/TagifyInput.js +48 -27
  39. package/es/components/molecules/TagifyInput/types.d.ts +14 -8
  40. package/es/components/molecules/TagifyInput/utils.d.ts +6 -1
  41. package/es/components/molecules/TagifyInput/utils.js +19 -0
  42. package/es/components/molecules/VirtualizedMenu/VirtualizedMenu.d.ts +1 -0
  43. package/es/components/molecules/VirtualizedMenu/components/Item/Item.js +3 -7
  44. package/es/components/molecules/VirtualizedMenu/components/MenuInline/MenuInline.d.ts +10 -10
  45. package/es/components/molecules/VirtualizedMenu/components/MenuInline/MenuInline.js +46 -327
  46. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/index.d.ts +9 -0
  47. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/index.js +5 -0
  48. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useFocusManagement.d.ts +23 -0
  49. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useFocusManagement.js +81 -0
  50. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useItemInteraction.d.ts +24 -0
  51. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useItemInteraction.js +32 -0
  52. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useKeyboardNavigation.d.ts +26 -0
  53. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useKeyboardNavigation.js +93 -0
  54. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useTreeState.d.ts +24 -0
  55. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useTreeState.js +94 -0
  56. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useVisibleItems.d.ts +7 -0
  57. package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useVisibleItems.js +132 -0
  58. package/es/components/molecules/VirtualizedMenu/styled.js +14 -3
  59. package/es/components/molecules/VirtualizedMenu/types.d.ts +1 -0
  60. package/es/components/molecules/VirtualizedMenu/utils.d.ts +1 -0
  61. package/es/components/molecules/VirtualizedMenu/utils.js +1 -0
  62. package/es/components/molecules/index.d.ts +1 -0
  63. package/es/components/organism/AccountSharing/AccountSharing.d.ts +1 -0
  64. package/es/components/organism/AccountSharing/AccountSharing.js +11 -4
  65. package/es/components/organism/AccountSharing/styled.js +1 -1
  66. package/es/components/organism/ActivityTimeline/ActivityTimeline.js +3 -3
  67. package/es/components/organism/ActivityTimeline/constants.d.ts +9 -9
  68. package/es/components/organism/ActivityTimeline/constants.js +3 -3
  69. package/es/components/organism/ActivityTimeline/index.d.ts +530 -1
  70. package/es/components/organism/ActivityTimeline/index.js +9 -1
  71. package/es/components/organism/ActivityTimeline/utils.js +175 -8
  72. package/es/components/organism/LeftMenu/LeftMenu.js +3 -3
  73. package/es/components/organism/LeftMenu/hooks/usePermission.js +1 -1
  74. package/es/components/organism/LeftMenu/types/index.d.ts +7 -0
  75. package/es/components/organism/LeftMenu/utils/index.js +1 -1
  76. package/es/components/organism/Login/Login.js +12 -3
  77. package/es/components/organism/Login/components/SignIn/SignIn.js +2 -2
  78. package/es/components/organism/Login/types/index.d.ts +2 -0
  79. package/es/components/organism/TextEditor/TextEditor.d.ts +9 -2
  80. package/es/components/organism/TextEditor/TextEditor.js +203 -42
  81. package/es/components/organism/TextEditor/constants.d.ts +9 -0
  82. package/es/components/organism/TextEditor/constants.js +66 -0
  83. package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu-plugin.d.ts +6 -128
  84. package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu-plugin.js +7 -292
  85. package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu.d.ts +1 -1
  86. package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu.js +4 -0
  87. package/es/components/organism/TextEditor/extensions/Link.js +33 -14
  88. package/es/components/organism/TextEditor/extensions/ListItem.d.ts +10 -0
  89. package/es/components/organism/TextEditor/extensions/ListItem.js +93 -0
  90. package/es/components/organism/TextEditor/extensions/SmartTag.d.ts +5 -6
  91. package/es/components/organism/TextEditor/extensions/SmartTag.js +96 -4
  92. package/es/components/organism/TextEditor/hooks/useColorSet.js +7 -0
  93. package/es/components/organism/TextEditor/hooks/useMarkTracking.js +2 -1
  94. package/es/components/organism/TextEditor/index.d.ts +7 -5
  95. package/es/components/organism/TextEditor/index.scss +4 -7
  96. package/es/components/organism/TextEditor/provider.d.ts +1 -0
  97. package/es/components/organism/TextEditor/provider.js +6 -3
  98. package/es/components/organism/TextEditor/store.d.ts +11 -4
  99. package/es/components/organism/TextEditor/store.js +22 -2
  100. package/es/components/organism/TextEditor/stories/WithOldDynAndLink/froala-legacy-format.settings.json +95 -0
  101. package/es/components/organism/TextEditor/stories/WithOldDynAndLink/shared.d.ts +111 -0
  102. package/es/components/organism/TextEditor/stories/WithOldDynAndLink/shared.js +82 -0
  103. package/es/components/organism/TextEditor/stories/shared.d.ts +64 -0
  104. package/es/components/organism/TextEditor/stories/shared.js +57 -0
  105. package/es/components/organism/TextEditor/styled.d.ts +1 -1
  106. package/es/components/organism/TextEditor/styled.js +1 -0
  107. package/es/components/organism/TextEditor/types.d.ts +161 -11
  108. package/es/components/organism/TextEditor/types.js +1 -0
  109. package/es/components/organism/TextEditor/ui/BubbleMenu/BubbleMenu.d.ts +2 -1
  110. package/es/components/organism/TextEditor/ui/BubbleMenu/BubbleMenu.js +80 -51
  111. package/es/components/organism/TextEditor/ui/Emoji/EmojiList.js +1 -1
  112. package/es/components/organism/TextEditor/ui/Emoji/suggestion.d.ts +1 -1
  113. package/es/components/organism/TextEditor/ui/Emoji/suggestion.js +2 -2
  114. package/es/components/organism/TextEditor/ui/FontPopover/FontPopover.js +12 -2
  115. package/es/components/organism/TextEditor/ui/LinkInsertForm/LinkInsertForm.d.ts +16 -0
  116. package/es/components/organism/TextEditor/ui/LinkInsertForm/LinkInsertForm.js +61 -0
  117. package/es/components/organism/TextEditor/ui/LinkInsertForm/index.d.ts +2 -0
  118. package/es/components/organism/TextEditor/ui/LinkInsertForm/index.js +1 -0
  119. package/es/components/organism/TextEditor/ui/LinkPopover/LinkPopover.d.ts +9 -0
  120. package/es/components/organism/TextEditor/ui/LinkPopover/LinkPopover.js +126 -0
  121. package/es/components/organism/TextEditor/ui/LinkPopover/index.d.ts +2 -0
  122. package/es/components/organism/TextEditor/ui/LinkPopover/index.js +1 -0
  123. package/es/components/organism/TextEditor/ui/Popover/Popover.js +1 -1
  124. package/es/components/organism/TextEditor/ui/TextAlignSelect/TextAlignSelect.js +1 -3
  125. package/es/components/organism/TextEditor/ui/Toolbar/{Toolbar.d.ts → FormattingToolbar.d.ts} +3 -4
  126. package/es/components/organism/TextEditor/ui/Toolbar/FormattingToolbar.js +90 -0
  127. package/es/components/organism/TextEditor/ui/Toolbar/LinkPreviewToolbar.d.ts +10 -0
  128. package/es/components/organism/TextEditor/ui/Toolbar/LinkPreviewToolbar.js +39 -0
  129. package/es/components/organism/TextEditor/ui/Toolbar/actions/EmojiAction.js +4 -3
  130. package/es/components/organism/TextEditor/ui/Toolbar/actions/FontFamilyAction.d.ts +1 -0
  131. package/es/components/organism/TextEditor/ui/Toolbar/actions/FontFamilyAction.js +2 -2
  132. package/es/components/organism/TextEditor/ui/Toolbar/actions/FontSizeAction.js +6 -1
  133. package/es/components/organism/TextEditor/ui/Toolbar/index.d.ts +2 -1
  134. package/es/components/organism/TextEditor/ui/Toolbar/index.js +2 -1
  135. package/es/components/organism/TextEditor/utils/documentState.d.ts +14 -0
  136. package/es/components/organism/TextEditor/utils/documentState.js +25 -0
  137. package/es/components/organism/TextEditor/utils/htmlProcessing.js +60 -0
  138. package/es/components/organism/TextEditor/utils/link.d.ts +10 -1
  139. package/es/components/organism/TextEditor/utils/link.js +161 -7
  140. package/es/components/organism/TextEditor/utils/menu.js +2 -1
  141. package/es/components/organism/TextEditor/utils/selection.js +3 -2
  142. package/es/components/organism/TextEditor/utils/smartTag.js +2 -1
  143. package/es/components/organism/index.d.ts +1 -1
  144. package/es/hooks/index.d.ts +1 -1
  145. package/es/hooks/index.js +1 -1
  146. package/es/providers/ConfigProvider/ConfigProvider.d.ts +4 -0
  147. package/es/providers/ConfigProvider/ConfigProvider.js +2 -3
  148. package/es/providers/ConfigProvider/GlobalStyle.d.ts +2 -2
  149. package/es/providers/ConfigProvider/GlobalStyle.js +67 -64
  150. package/es/services/MediaTemplateDesign/UploadFile/index.js +4 -4
  151. package/es/utils/common.d.ts +1 -1
  152. package/es/utils/common.js +3 -3
  153. package/es/utils/cookie.js +2 -1
  154. package/package.json +18 -23
  155. package/es/components/organism/TextEditor/ui/BubbleToolbar/BubbleToolbar.d.ts +0 -1
  156. package/es/components/organism/TextEditor/ui/BubbleToolbar/BubbleToolbar.js +0 -1
  157. package/es/components/organism/TextEditor/ui/BubbleToolbar/index.d.ts +0 -0
  158. package/es/components/organism/TextEditor/ui/BubbleToolbar/index.js +0 -1
  159. package/es/components/organism/TextEditor/ui/Toolbar/Toolbar.js +0 -39
@@ -1,123 +1,8 @@
1
- import { arrow, autoPlacement, computePosition, flip, hide, inline, offset, shift, size, } from '@floating-ui/dom';
2
- import { isTextSelection, posToDOMRect } from '@tiptap/core';
1
+ import { BubbleMenuView as TiptapBubbleMenuView } from '@tiptap/extension-bubble-menu';
3
2
  import { Plugin, PluginKey } from '@tiptap/pm/state';
4
- import { CellSelection } from '@tiptap/pm/tables';
5
- function combineDOMRects(rect1, rect2) {
6
- const top = Math.min(rect1.top, rect2.top);
7
- const bottom = Math.max(rect1.bottom, rect2.bottom);
8
- const left = Math.min(rect1.left, rect2.left);
9
- const right = Math.max(rect1.right, rect2.right);
10
- const width = right - left;
11
- const height = bottom - top;
12
- const x = left;
13
- const y = top;
14
- return new DOMRect(x, y, width, height);
15
- }
16
- export class BubbleMenuView {
17
- get middlewares() {
18
- const middlewares = [];
19
- if (this.floatingUIOptions.flip) {
20
- middlewares.push(flip(typeof this.floatingUIOptions.flip !== 'boolean'
21
- ? this.floatingUIOptions.flip
22
- : undefined));
23
- }
24
- if (this.floatingUIOptions.shift) {
25
- middlewares.push(shift(typeof this.floatingUIOptions.shift !== 'boolean'
26
- ? this.floatingUIOptions.shift
27
- : undefined));
28
- }
29
- if (this.floatingUIOptions.offset) {
30
- middlewares.push(offset(typeof this.floatingUIOptions.offset !== 'boolean'
31
- ? this.floatingUIOptions.offset
32
- : undefined));
33
- }
34
- if (this.floatingUIOptions.arrow) {
35
- middlewares.push(arrow(this.floatingUIOptions.arrow));
36
- }
37
- if (this.floatingUIOptions.size) {
38
- middlewares.push(size(typeof this.floatingUIOptions.size !== 'boolean'
39
- ? this.floatingUIOptions.size
40
- : undefined));
41
- }
42
- if (this.floatingUIOptions.autoPlacement) {
43
- middlewares.push(autoPlacement(typeof this.floatingUIOptions.autoPlacement !== 'boolean'
44
- ? this.floatingUIOptions.autoPlacement
45
- : undefined));
46
- }
47
- if (this.floatingUIOptions.hide) {
48
- middlewares.push(hide(typeof this.floatingUIOptions.hide !== 'boolean'
49
- ? this.floatingUIOptions.hide
50
- : undefined));
51
- }
52
- if (this.floatingUIOptions.inline) {
53
- middlewares.push(inline(typeof this.floatingUIOptions.inline !== 'boolean'
54
- ? this.floatingUIOptions.inline
55
- : undefined));
56
- }
57
- return middlewares;
58
- }
59
- constructor({ editor, element, view, updateDelay = 250, resizeDelay = 60, container, shouldShow, options, }) {
60
- this.preventHide = false;
61
- this.isVisible = false;
62
- this.floatingUIOptions = {
63
- strategy: 'absolute',
64
- placement: 'top',
65
- offset: 8,
66
- flip: {},
67
- shift: {},
68
- arrow: false,
69
- size: false,
70
- autoPlacement: false,
71
- hide: false,
72
- inline: false,
73
- onShow: undefined,
74
- onHide: undefined,
75
- onUpdate: undefined,
76
- onDestroy: undefined,
77
- };
78
- this.shouldShow = ({ view, state, from, to, }) => {
79
- const { doc, selection } = state;
80
- const { empty } = selection;
81
- // Sometime check for `empty` is not enough.
82
- // Doubleclick an empty paragraph returns a node size of 2.
83
- // So we check also for an empty text size.
84
- const isEmptyTextBlock = !doc.textBetween(from, to).length && isTextSelection(state.selection);
85
- // When clicking on a element inside the bubble menu the editor "blur" event
86
- // is called and the bubble menu item is focussed. In this case we should
87
- // consider the menu as part of the editor and keep showing the menu
88
- const isChildOfMenu = this.element.contains(document.activeElement);
89
- const hasEditorFocus = view.hasFocus() || isChildOfMenu;
90
- if (!hasEditorFocus || empty || isEmptyTextBlock || !this.editor.isEditable) {
91
- return false;
92
- }
93
- return true;
94
- };
95
- this.mousedownHandler = () => {
96
- this.preventHide = true;
97
- };
98
- this.dragstartHandler = () => {
99
- this.hide();
100
- };
101
- /**
102
- * Handles the window resize event and element resize event to update the position of the bubble menu.
103
- * It uses a debounce mechanism to prevent excessive updates.
104
- * The delay is defined by the `resizeDelay` property.
105
- */
106
- this.resizeHandler = (delay = this.resizeDelay) => {
107
- if (this.resizeDebounceTimer) {
108
- clearTimeout(this.resizeDebounceTimer);
109
- }
110
- this.resizeDebounceTimer = window.setTimeout(() => {
111
- this.updatePosition();
112
- }, delay);
113
- };
114
- /**
115
- * Window resize handler that uses the default resize delay.
116
- * This is a separate function to maintain the same reference for addEventListener/removeEventListener.
117
- */
118
- this.windowResizeHandler = () => {
119
- this.resizeHandler();
120
- };
3
+ export class BubbleMenuView extends TiptapBubbleMenuView {
4
+ constructor(props) {
5
+ super(props);
121
6
  /**
122
7
  * Sets up ResizeObserver to watch for bubble menu element size changes.
123
8
  * This ensures the bubble menu position is updated when the element resizes
@@ -131,7 +16,7 @@ export class BubbleMenuView {
131
16
  // Timer for debouncing the visibility restoration after resize
132
17
  let resizeTimer = null;
133
18
  // Time to wait before showing the element again after resize stops
134
- const DEBOUNCE_TIME = 100;
19
+ const DEBOUNCE_TIME = this.resizeDelay + 50;
135
20
  this.resizeObserver = new ResizeObserver(entries => {
136
21
  for (const entry of entries) {
137
22
  // Only handle resize events for the bubble menu element itself
@@ -145,7 +30,7 @@ export class BubbleMenuView {
145
30
  clearTimeout(resizeTimer);
146
31
  }
147
32
  // Immediately update the position with no delay for responsive positioning
148
- this.resizeHandler(0);
33
+ this.resizeHandler();
149
34
  // Set up a debounced timer to restore visibility after resize activity stops
150
35
  resizeTimer = setTimeout(() => {
151
36
  // Use requestAnimationFrame to ensure the position update is complete
@@ -165,36 +50,6 @@ export class BubbleMenuView {
165
50
  // Also observe the editor view DOM element for editor size changes
166
51
  this.resizeObserver.observe(this.view.dom);
167
52
  };
168
- this.focusHandler = () => {
169
- // we use `setTimeout` to make sure `selection` is already updated
170
- setTimeout(() => this.update(this.editor.view));
171
- };
172
- this.blurHandler = ({ event }) => {
173
- if (this.preventHide) {
174
- this.preventHide = false;
175
- return;
176
- }
177
- if (event?.relatedTarget && this.element.parentNode?.contains(event.relatedTarget)) {
178
- return;
179
- }
180
- if (event?.relatedTarget === this.editor.view.dom) {
181
- return;
182
- }
183
- this.hide();
184
- };
185
- this.handleDebouncedUpdate = (view, oldState) => {
186
- const selectionChanged = !oldState?.selection.eq(view.state.selection);
187
- const docChanged = !oldState?.doc.eq(view.state.doc);
188
- if (!selectionChanged && !docChanged) {
189
- return;
190
- }
191
- if (this.updateDebounceTimer) {
192
- clearTimeout(this.updateDebounceTimer);
193
- }
194
- this.updateDebounceTimer = window.setTimeout(() => {
195
- this.updateHandler(view, selectionChanged, docChanged, oldState);
196
- }, this.updateDelay);
197
- };
198
53
  this.updateHandler = (view, selectionChanged, docChanged, oldState) => {
199
54
  const { composing } = view;
200
55
  const isSame = !selectionChanged && !docChanged;
@@ -209,155 +64,15 @@ export class BubbleMenuView {
209
64
  this.show();
210
65
  this.updatePosition();
211
66
  };
212
- this.editor = editor;
213
- this.element = element;
214
- this.view = view;
215
- this.updateDelay = updateDelay;
216
- this.resizeDelay = resizeDelay;
217
- this.container = container;
218
- this.floatingUIOptions = {
219
- ...this.floatingUIOptions,
220
- ...options,
221
- };
222
- this.element.tabIndex = 0;
223
- if (shouldShow) {
224
- this.shouldShow = shouldShow;
225
- }
226
- const containerElement = this.getContainer();
227
- if (containerElement === document.body) {
228
- this.element.style.zIndex = '9999';
229
- }
230
- this.element.addEventListener('mousedown', this.mousedownHandler, { capture: true });
231
- this.view.dom.addEventListener('dragstart', this.dragstartHandler);
232
- this.editor.on('focus', this.focusHandler);
233
- this.editor.on('blur', this.blurHandler);
234
- window.addEventListener('resize', this.windowResizeHandler);
235
67
  this.setupResizeObserver();
236
- this.update(view, view.state);
237
- if (this.getShouldShow()) {
238
- this.show();
239
- }
240
- }
241
- updatePosition() {
242
- const { selection } = this.editor.state;
243
- const domRect = posToDOMRect(this.view, selection.from, selection.to);
244
- let virtualElement = {
245
- getBoundingClientRect: () => domRect,
246
- getClientRects: () => [domRect],
247
- };
248
- // this is a special case for cell selections
249
- if (selection instanceof CellSelection) {
250
- const { $anchorCell, $headCell } = selection;
251
- const from = $anchorCell ? $anchorCell.pos : $headCell.pos;
252
- const to = $headCell ? $headCell.pos : $anchorCell.pos;
253
- const fromDOM = this.view.nodeDOM(from);
254
- const toDOM = this.view.nodeDOM(to);
255
- if (!fromDOM || !toDOM) {
256
- return;
257
- }
258
- const clientRect = fromDOM === toDOM
259
- ? fromDOM.getBoundingClientRect()
260
- : combineDOMRects(fromDOM.getBoundingClientRect(), toDOM.getBoundingClientRect());
261
- virtualElement = {
262
- getBoundingClientRect: () => clientRect,
263
- getClientRects: () => [clientRect],
264
- };
265
- }
266
- computePosition(virtualElement, this.element, {
267
- placement: this.floatingUIOptions.placement,
268
- strategy: this.floatingUIOptions.strategy,
269
- middleware: this.middlewares,
270
- }).then(({ x, y, strategy }) => {
271
- this.element.style.width = 'max-content';
272
- this.element.style.position = strategy;
273
- this.element.style.left = `${x}px`;
274
- this.element.style.top = `${y}px`;
275
- if (this.isVisible && this.floatingUIOptions.onUpdate) {
276
- this.floatingUIOptions.onUpdate();
277
- }
278
- });
279
- }
280
- update(view, oldState) {
281
- const { state } = view;
282
- const hasValidSelection = state.selection.from !== state.selection.to;
283
- if (this.updateDelay > 0 && hasValidSelection) {
284
- this.handleDebouncedUpdate(view, oldState);
285
- return;
286
- }
287
- const selectionChanged = !oldState?.selection.eq(view.state.selection);
288
- const docChanged = !oldState?.doc.eq(view.state.doc);
289
- this.updateHandler(view, selectionChanged, docChanged, oldState);
290
- }
291
- getShouldShow(oldState) {
292
- const { state } = this.view;
293
- const { selection } = state;
294
- // support for CellSelections
295
- const { ranges } = selection;
296
- const from = Math.min(...ranges.map(range => range.$from.pos));
297
- const to = Math.max(...ranges.map(range => range.$to.pos));
298
- const shouldShow = this.shouldShow?.({
299
- editor: this.editor,
300
- element: this.element,
301
- view: this.view,
302
- state,
303
- oldState,
304
- from,
305
- to,
306
- });
307
- return shouldShow;
308
- }
309
- getContainer() {
310
- if (!this.container) {
311
- return this.view.dom.parentElement;
312
- }
313
- if (typeof this.container === 'function') {
314
- return this.container();
315
- }
316
- return this.container;
317
- }
318
- show() {
319
- if (this.isVisible) {
320
- return;
321
- }
322
- this.element.style.visibility = 'visible';
323
- this.element.style.opacity = '1';
324
- const container = this.getContainer();
325
- if (container) {
326
- container.appendChild(this.element);
327
- }
328
- if (this.floatingUIOptions.onShow) {
329
- this.floatingUIOptions.onShow();
330
- }
331
- this.isVisible = true;
332
- }
333
- hide() {
334
- if (!this.isVisible) {
335
- return;
336
- }
337
- this.element.style.visibility = 'hidden';
338
- this.element.style.opacity = '0';
339
- // remove from the parent element
340
- this.element.remove();
341
- if (this.floatingUIOptions.onHide) {
342
- this.floatingUIOptions.onHide();
343
- }
344
- this.isVisible = false;
345
68
  }
346
69
  destroy() {
347
- this.hide();
348
- this.element.removeEventListener('mousedown', this.mousedownHandler, { capture: true });
349
- this.view.dom.removeEventListener('dragstart', this.dragstartHandler);
350
- window.removeEventListener('resize', this.windowResizeHandler);
351
- this.editor.off('focus', this.focusHandler);
352
- this.editor.off('blur', this.blurHandler);
70
+ super.destroy();
353
71
  // Cleanup ResizeObserver
354
72
  if (this.resizeObserver) {
355
73
  this.resizeObserver.disconnect();
356
74
  this.resizeObserver = undefined;
357
75
  }
358
- if (this.floatingUIOptions.onDestroy) {
359
- this.floatingUIOptions.onDestroy();
360
- }
361
76
  }
362
77
  }
363
78
  export const BubbleMenuPlugin = (options) => new Plugin({
@@ -1,5 +1,5 @@
1
1
  import { Extension } from '@tiptap/core';
2
- import type { BubbleMenuPluginProps } from './bubble-menu-plugin';
2
+ import { type BubbleMenuPluginProps } from '@tiptap/extension-bubble-menu';
3
3
  export type BubbleMenuOptions = Omit<BubbleMenuPluginProps, 'editor' | 'element'> & {
4
4
  /**
5
5
  * The DOM element that contains your menu.
@@ -11,6 +11,7 @@ export const BubbleMenu = Extension.create({
11
11
  element: null,
12
12
  pluginKey: 'bubbleMenu',
13
13
  updateDelay: undefined,
14
+ appendTo: undefined,
14
15
  shouldShow: null,
15
16
  };
16
17
  },
@@ -24,6 +25,9 @@ export const BubbleMenu = Extension.create({
24
25
  editor: this.editor,
25
26
  element: this.options.element,
26
27
  updateDelay: this.options.updateDelay,
28
+ options: this.options.options,
29
+ appendTo: this.options.appendTo,
30
+ getReferencedVirtualElement: this.options.getReferencedVirtualElement,
27
31
  shouldShow: this.options.shouldShow,
28
32
  }),
29
33
  ];
@@ -3,7 +3,7 @@ import { CUSTOM_LINK_EXTENSION_NAME, LINK_TEXT_COLOR } from '../constants';
3
3
  import { TextSelection } from '@tiptap/pm/state';
4
4
  import { dataAttrArrayToObject } from '@antscorp/antsomi-ui/es/utils';
5
5
  import { isEmpty, isEqual, map, toString } from 'lodash';
6
- import { getLinkMarkRanges, getLinkRange, isLinkColor } from '../utils';
6
+ import { getLinkMarkRanges, getLinkRange, isLinkColor, textBetween } from '../utils';
7
7
  import { mergeAdjacentRanges } from '../utils/shared';
8
8
  export const CustomLink = TiptapLinkExtension.extend({
9
9
  name: CUSTOM_LINK_EXTENSION_NAME,
@@ -40,22 +40,41 @@ export const CustomLink = TiptapLinkExtension.extend({
40
40
  setCustomLink: ({ attrs, content }) => ({ state, chain }) => {
41
41
  const { selection } = state;
42
42
  const { from, to } = selection;
43
- let linkContent = state.doc.textBetween(from, to);
44
- if (content && linkContent !== content) {
45
- linkContent = content;
43
+ // Check if custom content is provided and different from current text
44
+ const currentText = textBetween(state, from, to);
45
+ const shouldUseCustomContent = content && currentText !== content;
46
+ if (shouldUseCustomContent) {
47
+ // Use custom content as string (replace content)
48
+ return chain()
49
+ .focus()
50
+ .deleteSelection()
51
+ .insertContent(content)
52
+ .command(({ tr }) => {
53
+ const endPos = tr.selection.from;
54
+ const startPos = endPos - content.length;
55
+ tr.setSelection(TextSelection.create(tr.doc, startPos, endPos));
56
+ return true;
57
+ })
58
+ .setLink({
59
+ ...attrs,
60
+ href: attrs?.href || './',
61
+ })
62
+ .command(({ tr }) => {
63
+ const endPos = tr.selection.to;
64
+ tr.setSelection(TextSelection.create(tr.doc, endPos, endPos));
65
+ return true;
66
+ })
67
+ .run();
46
68
  }
47
- return (chain()
69
+ // Preserve existing content structure (atom nodes like smartTag)
70
+ // Just apply link mark on current selection without modifying content
71
+ return chain()
48
72
  .focus()
49
- .deleteSelection()
50
- .insertContent(linkContent)
51
73
  .command(({ tr }) => {
52
- const endPos = tr.selection.from;
53
- const startPos = endPos - linkContent.length;
54
- tr.setSelection(TextSelection.create(tr.doc, startPos, endPos));
74
+ // Ensure selection is set correctly
75
+ tr.setSelection(TextSelection.create(tr.doc, from, to));
55
76
  return true;
56
77
  })
57
- // .setUnderline()
58
- // .setColor(LINK_TEXT_COLOR)
59
78
  .setLink({
60
79
  ...attrs,
61
80
  href: attrs?.href || './',
@@ -65,7 +84,7 @@ export const CustomLink = TiptapLinkExtension.extend({
65
84
  tr.setSelection(TextSelection.create(tr.doc, endPos, endPos));
66
85
  return true;
67
86
  })
68
- .run());
87
+ .run();
69
88
  },
70
89
  deleteCustomLink: predicate => ({ state, chain }) => {
71
90
  const { doc } = state;
@@ -146,7 +165,7 @@ export const CustomLink = TiptapLinkExtension.extend({
146
165
  to: state.doc.content.size,
147
166
  }).filter(range => predicate(range.mark.attrs));
148
167
  mergeAdjacentRanges(linkMarkRanges, (existingRanges, candidateRange) => existingRanges.some(range => mergeAdjacentEqualFn(range.mark.attrs, candidateRange.mark.attrs))).forEach(range => {
149
- const currentText = state.doc.textBetween(range.from, range.to);
168
+ const currentText = textBetween(state, range.from, range.to);
150
169
  const updatedText = updated(currentText);
151
170
  if (currentText === updatedText)
152
171
  return;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Custom ListItem extension that extends the default TipTap ListItem
3
+ * with custom Backspace behavior to prevent merging paragraphs into lists
4
+ *
5
+ * This extension only overrides keyboard shortcuts while maintaining
6
+ * all other default ListItem functionality (HTML parsing, rendering, etc.)
7
+ *
8
+ * @see https://www.tiptap.dev/api/nodes/list-item
9
+ */
10
+ export declare const CustomListItem: import("@tiptap/core").Node<import("@tiptap/extension-list").ListItemOptions, any>;
@@ -0,0 +1,93 @@
1
+ import { ListItem } from '@tiptap/extension-list-item';
2
+ /**
3
+ * Custom ListItem extension that extends the default TipTap ListItem
4
+ * with custom Backspace behavior to prevent merging paragraphs into lists
5
+ *
6
+ * This extension only overrides keyboard shortcuts while maintaining
7
+ * all other default ListItem functionality (HTML parsing, rendering, etc.)
8
+ *
9
+ * @see https://www.tiptap.dev/api/nodes/list-item
10
+ */
11
+ export const CustomListItem = ListItem.extend({
12
+ addOptions() {
13
+ return {
14
+ HTMLAttributes: {
15
+ style: 'line-height:normal;',
16
+ },
17
+ bulletListTypeName: 'customUnorderedList',
18
+ orderedListTypeName: 'customOrderedList',
19
+ };
20
+ },
21
+ addKeyboardShortcuts() {
22
+ return {
23
+ // Keep default keyboard shortcuts from parent ListItem
24
+ Enter: () => this.editor.commands.splitListItem(this.name),
25
+ Tab: () => this.editor.commands.sinkListItem(this.name),
26
+ 'Shift-Tab': () => this.editor.commands.liftListItem(this.name),
27
+ /**
28
+ * Custom Backspace handler to prevent merging empty paragraphs into lists
29
+ *
30
+ * Behavior:
31
+ * 1. Check if cursor is at the start of a paragraph
32
+ * 2. Check if the node before is a list (ordered or unordered)
33
+ * 3. If both conditions are true and paragraph is empty, delete the paragraph
34
+ * 4. Otherwise, use default backspace behavior
35
+ */
36
+ Backspace: () => {
37
+ const { state } = this.editor;
38
+ const { selection } = state;
39
+ const { $from, empty } = selection;
40
+ // Only handle if selection is empty (cursor position, not text selection)
41
+ if (!empty) {
42
+ return false;
43
+ }
44
+ // Check if cursor is at the start of current node
45
+ const isAtStart = $from.parentOffset === 0;
46
+ if (!isAtStart) {
47
+ return false;
48
+ }
49
+ // Get current node (should be a paragraph)
50
+ const currentNode = $from.parent;
51
+ // Only handle paragraphs
52
+ if (currentNode.type.name !== 'paragraph') {
53
+ return false;
54
+ }
55
+ // Get the index of current paragraph in its parent (usually doc)
56
+ const paragraphDepth = $from.depth;
57
+ const indexInParent = $from.index(paragraphDepth - 1);
58
+ // Check if there's a node before (index > 0)
59
+ if (indexInParent === 0) {
60
+ return false;
61
+ }
62
+ // Get parent node (usually doc) and the node before current paragraph
63
+ const parent = $from.node(paragraphDepth - 1);
64
+ const nodeBefore = parent.child(indexInParent - 1);
65
+ if (!nodeBefore) {
66
+ return false;
67
+ }
68
+ // Check if the node before is a list (ordered or unordered)
69
+ const isListBefore = nodeBefore.type.name === this.options.orderedListTypeName ||
70
+ nodeBefore.type.name === this.options.bulletListTypeName;
71
+ if (!isListBefore) {
72
+ return false;
73
+ }
74
+ // Check if current paragraph is empty
75
+ const isParagraphEmpty = currentNode.content.size === 0;
76
+ if (!isParagraphEmpty) {
77
+ // If paragraph has content, allow default backspace to handle
78
+ return false;
79
+ }
80
+ // Calculate the exact positions of the paragraph node
81
+ // We need to delete from the position before the paragraph open tag
82
+ // to the position after the paragraph close tag
83
+ const paragraphPos = $from.before();
84
+ const paragraphEndPos = $from.after();
85
+ // Delete the entire paragraph node using deleteRange
86
+ return this.editor.commands.deleteRange({
87
+ from: paragraphPos,
88
+ to: paragraphEndPos,
89
+ });
90
+ },
91
+ };
92
+ },
93
+ });
@@ -1,16 +1,15 @@
1
1
  import { Node } from '@tiptap/core';
2
2
  import { Attrs } from '@tiptap/pm/model';
3
- export type SmartTagAttrs = {
4
- id: string;
5
- } & Partial<{
6
- content: string;
7
- tag: string;
8
- }>;
9
3
  /**
10
4
  * Represents the options for the SmartTag node.
11
5
  */
12
6
  export interface SmartTagOptions {
13
7
  HTMLAttributes: Record<string, unknown>;
8
+ /**
9
+ * Custom function to generate unique IDs for smart tags
10
+ * If not provided, falls back to uniqid library
11
+ */
12
+ generateSmartTagId?: () => string;
14
13
  }
15
14
  /**
16
15
  * Represents the options for the SmartTag node.