@antscorp/antsomi-ui 2.0.84 → 2.0.86-text-editor-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/es/assets/css/main.scss +4 -2
  2. package/es/components/index.scss +2 -0
  3. package/es/components/molecules/EmojiPopover/EmojiPopover.js +5 -1
  4. package/es/components/molecules/FontSizeInput/FontSizeInput.d.ts +3 -0
  5. package/es/components/molecules/FontSizeInput/FontSizeInput.js +128 -0
  6. package/es/components/molecules/FontSizeInput/components/FontSizeControl.d.ts +8 -0
  7. package/es/components/molecules/FontSizeInput/components/FontSizeControl.js +14 -0
  8. package/es/components/molecules/FontSizeInput/components/FontSizeDropdown.d.ts +20 -0
  9. package/es/components/molecules/FontSizeInput/components/FontSizeDropdown.js +17 -0
  10. package/es/components/molecules/FontSizeInput/constants.d.ts +2 -0
  11. package/es/components/molecules/FontSizeInput/constants.js +5 -0
  12. package/es/components/molecules/FontSizeInput/index.d.ts +2 -0
  13. package/es/components/molecules/FontSizeInput/index.js +1 -0
  14. package/es/components/molecules/FontSizeInput/styled.d.ts +3 -0
  15. package/es/components/molecules/FontSizeInput/styled.js +22 -0
  16. package/es/components/molecules/FontSizeInput/styles.scss +15 -0
  17. package/es/components/molecules/FontSizeInput/types.d.ts +24 -0
  18. package/es/components/molecules/FontSizeInput/types.js +1 -0
  19. package/es/components/molecules/FontSizeInput/utils.d.ts +7 -0
  20. package/es/components/molecules/FontSizeInput/utils.js +9 -0
  21. package/es/components/molecules/TagifyInput/TagifyInput.js +20 -14
  22. package/es/components/molecules/TagifyInput/utils.d.ts +10 -1
  23. package/es/components/molecules/TagifyInput/utils.js +64 -6
  24. package/es/components/molecules/VirtualizedMenu/VirtualizedMenu.d.ts +6 -3
  25. package/es/components/molecules/VirtualizedMenu/__mocks__/index.js +2550 -938
  26. package/es/components/molecules/VirtualizedMenu/components/Item/Item.d.ts +13 -3
  27. package/es/components/molecules/VirtualizedMenu/components/Item/Item.js +53 -25
  28. package/es/components/molecules/VirtualizedMenu/components/Item/index.d.ts +1 -1
  29. package/es/components/molecules/VirtualizedMenu/components/MenuInline/MenuInline.d.ts +8 -5
  30. package/es/components/molecules/VirtualizedMenu/components/MenuInline/MenuInline.js +289 -46
  31. package/es/components/molecules/VirtualizedMenu/components/MenuInline/index.js +1 -0
  32. package/es/components/molecules/VirtualizedMenu/styled.d.ts +1 -1
  33. package/es/components/molecules/VirtualizedMenu/styled.js +23 -4
  34. package/es/components/molecules/VirtualizedMenu/types.d.ts +6 -9
  35. package/es/components/molecules/VirtualizedMenu/utils.d.ts +8 -5
  36. package/es/components/molecules/VirtualizedMenu/utils.js +13 -18
  37. package/es/components/molecules/index.d.ts +1 -0
  38. package/es/components/molecules/index.js +1 -0
  39. package/es/components/molecules/index.scss +1 -0
  40. package/es/components/organism/ActivityTimeline/__mocks__/event_tracking.json +1290 -0
  41. package/es/components/organism/ActivityTimeline/__mocks__/timeline.json +3059 -0
  42. package/es/components/organism/TextEditor/TextEditor.d.ts +3 -0
  43. package/es/components/organism/TextEditor/TextEditor.js +251 -0
  44. package/es/components/organism/TextEditor/__mocks__/text-block.settings.json +320 -0
  45. package/es/components/organism/TextEditor/__mocks__/text-contennt.d.ts +1 -0
  46. package/es/components/organism/TextEditor/__mocks__/text-contennt.js +38 -0
  47. package/es/components/organism/TextEditor/constants.d.ts +135 -0
  48. package/es/components/organism/TextEditor/constants.js +280 -0
  49. package/es/components/organism/TextEditor/extensions/BackgroundColor.d.ts +25 -0
  50. package/es/components/organism/TextEditor/extensions/BackgroundColor.js +46 -0
  51. package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu-plugin.d.ts +130 -0
  52. package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu-plugin.js +247 -0
  53. package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu.d.ts +15 -0
  54. package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu.js +31 -0
  55. package/es/components/organism/TextEditor/extensions/BubbleMenu/index.d.ts +2 -0
  56. package/es/components/organism/TextEditor/extensions/BubbleMenu/index.js +2 -0
  57. package/es/components/organism/TextEditor/extensions/Color.d.ts +6 -0
  58. package/es/components/organism/TextEditor/extensions/Color.js +41 -0
  59. package/es/components/organism/TextEditor/extensions/Emoji.d.ts +57 -0
  60. package/es/components/organism/TextEditor/extensions/Emoji.js +184 -0
  61. package/es/components/organism/TextEditor/extensions/FontFamily.d.ts +6 -0
  62. package/es/components/organism/TextEditor/extensions/FontFamily.js +43 -0
  63. package/es/components/organism/TextEditor/extensions/FontSize.d.ts +32 -0
  64. package/es/components/organism/TextEditor/extensions/FontSize.js +47 -0
  65. package/es/components/organism/TextEditor/extensions/FontWeight.d.ts +23 -0
  66. package/es/components/organism/TextEditor/extensions/FontWeight.js +41 -0
  67. package/es/components/organism/TextEditor/extensions/Highlight.d.ts +1 -0
  68. package/es/components/organism/TextEditor/extensions/Highlight.js +14 -0
  69. package/es/components/organism/TextEditor/extensions/Indent.d.ts +28 -0
  70. package/es/components/organism/TextEditor/extensions/Indent.js +68 -0
  71. package/es/components/organism/TextEditor/extensions/LineHeight.d.ts +20 -0
  72. package/es/components/organism/TextEditor/extensions/LineHeight.js +36 -0
  73. package/es/components/organism/TextEditor/extensions/Link.d.ts +15 -0
  74. package/es/components/organism/TextEditor/extensions/Link.js +50 -0
  75. package/es/components/organism/TextEditor/extensions/ListItemMarker.d.ts +13 -0
  76. package/es/components/organism/TextEditor/extensions/ListItemMarker.js +174 -0
  77. package/es/components/organism/TextEditor/extensions/Selection.d.ts +6 -0
  78. package/es/components/organism/TextEditor/extensions/Selection.js +40 -0
  79. package/es/components/organism/TextEditor/extensions/SmartTag.d.ts +39 -0
  80. package/es/components/organism/TextEditor/extensions/SmartTag.js +167 -0
  81. package/es/components/organism/TextEditor/extensions/StyleMemory.d.ts +36 -0
  82. package/es/components/organism/TextEditor/extensions/StyleMemory.js +163 -0
  83. package/es/components/organism/TextEditor/extensions/TextTransform.d.ts +31 -0
  84. package/es/components/organism/TextEditor/extensions/TextTransform.js +37 -0
  85. package/es/components/organism/TextEditor/hooks/index.d.ts +6 -0
  86. package/es/components/organism/TextEditor/hooks/index.js +6 -0
  87. package/es/components/organism/TextEditor/hooks/useDocumentState.d.ts +18 -0
  88. package/es/components/organism/TextEditor/hooks/useDocumentState.js +42 -0
  89. package/es/components/organism/TextEditor/hooks/useLinkHandler.d.ts +10 -0
  90. package/es/components/organism/TextEditor/hooks/useLinkHandler.js +223 -0
  91. package/es/components/organism/TextEditor/hooks/useMarkTracking.d.ts +26 -0
  92. package/es/components/organism/TextEditor/hooks/useMarkTracking.js +68 -0
  93. package/es/components/organism/TextEditor/hooks/usePersistence.d.ts +31 -0
  94. package/es/components/organism/TextEditor/hooks/usePersistence.js +169 -0
  95. package/es/components/organism/TextEditor/hooks/useStyleMemory.d.ts +6 -0
  96. package/es/components/organism/TextEditor/hooks/useStyleMemory.js +42 -0
  97. package/es/components/organism/TextEditor/hooks/useStylePresets.d.ts +34 -0
  98. package/es/components/organism/TextEditor/hooks/useStylePresets.js +83 -0
  99. package/es/components/organism/TextEditor/index.d.ts +14 -0
  100. package/es/components/organism/TextEditor/index.js +6 -0
  101. package/es/components/organism/TextEditor/index.scss +61 -0
  102. package/es/components/organism/TextEditor/provider.d.ts +10 -0
  103. package/es/components/organism/TextEditor/provider.js +20 -0
  104. package/es/components/organism/TextEditor/store.d.ts +11 -0
  105. package/es/components/organism/TextEditor/store.js +12 -0
  106. package/es/components/organism/TextEditor/styled.d.ts +8 -0
  107. package/es/components/organism/TextEditor/styled.js +90 -0
  108. package/es/components/organism/TextEditor/types.d.ts +92 -0
  109. package/es/components/organism/TextEditor/types.js +1 -0
  110. package/es/components/organism/TextEditor/ui/BubbleMenu/BubbleMenu.d.ts +6 -0
  111. package/es/components/organism/TextEditor/ui/BubbleMenu/BubbleMenu.js +78 -0
  112. package/es/components/organism/TextEditor/ui/BubbleMenu/index.d.ts +1 -0
  113. package/es/components/organism/TextEditor/ui/BubbleMenu/index.js +1 -0
  114. package/es/components/organism/TextEditor/ui/ColorPicker/ColorPicker.d.ts +43 -0
  115. package/es/components/organism/TextEditor/ui/ColorPicker/ColorPicker.js +120 -0
  116. package/es/components/organism/TextEditor/ui/ColorPicker/index.d.ts +1 -0
  117. package/es/components/organism/TextEditor/ui/ColorPicker/index.js +1 -0
  118. package/es/components/organism/TextEditor/ui/Emoji/EmojiList.d.ts +11 -0
  119. package/es/components/organism/TextEditor/ui/Emoji/EmojiList.js +66 -0
  120. package/es/components/organism/TextEditor/ui/Emoji/index.d.ts +2 -0
  121. package/es/components/organism/TextEditor/ui/Emoji/index.js +2 -0
  122. package/es/components/organism/TextEditor/ui/Emoji/suggestion.d.ts +4 -0
  123. package/es/components/organism/TextEditor/ui/Emoji/suggestion.js +71 -0
  124. package/es/components/organism/TextEditor/ui/FontPopover/FontPopover.d.ts +12 -0
  125. package/es/components/organism/TextEditor/ui/FontPopover/FontPopover.js +69 -0
  126. package/es/components/organism/TextEditor/ui/FontPopover/styled.d.ts +1 -0
  127. package/es/components/organism/TextEditor/ui/FontPopover/styled.js +20 -0
  128. package/es/components/organism/TextEditor/ui/Popover/Popover.d.ts +6 -0
  129. package/es/components/organism/TextEditor/ui/Popover/Popover.js +7 -0
  130. package/es/components/organism/TextEditor/ui/Popover/index.d.ts +1 -0
  131. package/es/components/organism/TextEditor/ui/Popover/index.js +1 -0
  132. package/es/components/organism/TextEditor/ui/Select/Select.d.ts +4 -0
  133. package/es/components/organism/TextEditor/ui/Select/Select.js +7 -0
  134. package/es/components/organism/TextEditor/ui/Select/index.d.ts +1 -0
  135. package/es/components/organism/TextEditor/ui/Select/index.js +1 -0
  136. package/es/components/organism/TextEditor/ui/TextAlignSelect/TextAlignSelect.d.ts +30 -0
  137. package/es/components/organism/TextEditor/ui/TextAlignSelect/TextAlignSelect.js +49 -0
  138. package/es/components/organism/TextEditor/ui/TextAlignSelect/index.d.ts +1 -0
  139. package/es/components/organism/TextEditor/ui/TextAlignSelect/index.js +1 -0
  140. package/es/components/organism/TextEditor/ui/Toolbar/Toolbar.d.ts +14 -0
  141. package/es/components/organism/TextEditor/ui/Toolbar/Toolbar.js +42 -0
  142. package/es/components/organism/TextEditor/ui/Toolbar/actions/BoldAction.d.ts +5 -0
  143. package/es/components/organism/TextEditor/ui/Toolbar/actions/BoldAction.js +7 -0
  144. package/es/components/organism/TextEditor/ui/Toolbar/actions/BulletListAction.d.ts +5 -0
  145. package/es/components/organism/TextEditor/ui/Toolbar/actions/BulletListAction.js +7 -0
  146. package/es/components/organism/TextEditor/ui/Toolbar/actions/ClearFormattingAction.d.ts +5 -0
  147. package/es/components/organism/TextEditor/ui/Toolbar/actions/ClearFormattingAction.js +18 -0
  148. package/es/components/organism/TextEditor/ui/Toolbar/actions/EmojiAction.d.ts +4 -0
  149. package/es/components/organism/TextEditor/ui/Toolbar/actions/EmojiAction.js +13 -0
  150. package/es/components/organism/TextEditor/ui/Toolbar/actions/FontFamilyAction.d.ts +7 -0
  151. package/es/components/organism/TextEditor/ui/Toolbar/actions/FontFamilyAction.js +18 -0
  152. package/es/components/organism/TextEditor/ui/Toolbar/actions/FontSizeAction.d.ts +7 -0
  153. package/es/components/organism/TextEditor/ui/Toolbar/actions/FontSizeAction.js +37 -0
  154. package/es/components/organism/TextEditor/ui/Toolbar/actions/HighlightAction.d.ts +5 -0
  155. package/es/components/organism/TextEditor/ui/Toolbar/actions/HighlightAction.js +7 -0
  156. package/es/components/organism/TextEditor/ui/Toolbar/actions/IndentAction.d.ts +5 -0
  157. package/es/components/organism/TextEditor/ui/Toolbar/actions/IndentAction.js +7 -0
  158. package/es/components/organism/TextEditor/ui/Toolbar/actions/ItalicAction.d.ts +5 -0
  159. package/es/components/organism/TextEditor/ui/Toolbar/actions/ItalicAction.js +7 -0
  160. package/es/components/organism/TextEditor/ui/Toolbar/actions/LinkAction.d.ts +6 -0
  161. package/es/components/organism/TextEditor/ui/Toolbar/actions/LinkAction.js +4 -0
  162. package/es/components/organism/TextEditor/ui/Toolbar/actions/OrderedListAction.d.ts +5 -0
  163. package/es/components/organism/TextEditor/ui/Toolbar/actions/OrderedListAction.js +7 -0
  164. package/es/components/organism/TextEditor/ui/Toolbar/actions/OutdentAction.d.ts +5 -0
  165. package/es/components/organism/TextEditor/ui/Toolbar/actions/OutdentAction.js +7 -0
  166. package/es/components/organism/TextEditor/ui/Toolbar/actions/SmartTagAction.d.ts +7 -0
  167. package/es/components/organism/TextEditor/ui/Toolbar/actions/SmartTagAction.js +9 -0
  168. package/es/components/organism/TextEditor/ui/Toolbar/actions/SpacingAction.d.ts +9 -0
  169. package/es/components/organism/TextEditor/ui/Toolbar/actions/SpacingAction.js +22 -0
  170. package/es/components/organism/TextEditor/ui/Toolbar/actions/StrikeAction.d.ts +5 -0
  171. package/es/components/organism/TextEditor/ui/Toolbar/actions/StrikeAction.js +7 -0
  172. package/es/components/organism/TextEditor/ui/Toolbar/actions/SubscriptAction.d.ts +5 -0
  173. package/es/components/organism/TextEditor/ui/Toolbar/actions/SubscriptAction.js +13 -0
  174. package/es/components/organism/TextEditor/ui/Toolbar/actions/SuperscriptAction.d.ts +5 -0
  175. package/es/components/organism/TextEditor/ui/Toolbar/actions/SuperscriptAction.js +13 -0
  176. package/es/components/organism/TextEditor/ui/Toolbar/actions/TextAlignAction.d.ts +5 -0
  177. package/es/components/organism/TextEditor/ui/Toolbar/actions/TextAlignAction.js +3 -0
  178. package/es/components/organism/TextEditor/ui/Toolbar/actions/TextBackgroundColorAction.d.ts +7 -0
  179. package/es/components/organism/TextEditor/ui/Toolbar/actions/TextBackgroundColorAction.js +19 -0
  180. package/es/components/organism/TextEditor/ui/Toolbar/actions/TextColorAction.d.ts +15 -0
  181. package/es/components/organism/TextEditor/ui/Toolbar/actions/TextColorAction.js +14 -0
  182. package/es/components/organism/TextEditor/ui/Toolbar/actions/TextTransformAction.d.ts +5 -0
  183. package/es/components/organism/TextEditor/ui/Toolbar/actions/TextTransformAction.js +30 -0
  184. package/es/components/organism/TextEditor/ui/Toolbar/actions/UnderlineAction.d.ts +5 -0
  185. package/es/components/organism/TextEditor/ui/Toolbar/actions/UnderlineAction.js +5 -0
  186. package/es/components/organism/TextEditor/ui/Toolbar/actions/UnsetLink.d.ts +6 -0
  187. package/es/components/organism/TextEditor/ui/Toolbar/actions/UnsetLink.js +10 -0
  188. package/es/components/organism/TextEditor/ui/Toolbar/actions/index.d.ts +20 -0
  189. package/es/components/organism/TextEditor/ui/Toolbar/actions/index.js +20 -0
  190. package/es/components/organism/TextEditor/ui/Toolbar/index.d.ts +1 -0
  191. package/es/components/organism/TextEditor/ui/Toolbar/index.js +1 -0
  192. package/es/components/organism/TextEditor/utils/documentState.d.ts +57 -0
  193. package/es/components/organism/TextEditor/utils/documentState.js +100 -0
  194. package/es/components/organism/TextEditor/utils/font.d.ts +84 -0
  195. package/es/components/organism/TextEditor/utils/font.js +175 -0
  196. package/es/components/organism/TextEditor/utils/htmlProcessing.d.ts +63 -0
  197. package/es/components/organism/TextEditor/utils/htmlProcessing.js +321 -0
  198. package/es/components/organism/TextEditor/utils/index.d.ts +8 -0
  199. package/es/components/organism/TextEditor/utils/index.js +16 -0
  200. package/es/components/organism/TextEditor/utils/link.d.ts +100 -0
  201. package/es/components/organism/TextEditor/utils/link.js +149 -0
  202. package/es/components/organism/TextEditor/utils/menu.d.ts +134 -0
  203. package/es/components/organism/TextEditor/utils/menu.js +317 -0
  204. package/es/components/organism/TextEditor/utils/selection.d.ts +25 -0
  205. package/es/components/organism/TextEditor/utils/selection.js +57 -0
  206. package/es/components/organism/TextEditor/utils/smartTag.d.ts +49 -0
  207. package/es/components/organism/TextEditor/utils/smartTag.js +89 -0
  208. package/es/components/organism/TextEditor/utils/style.d.ts +78 -0
  209. package/es/components/organism/TextEditor/utils/style.js +193 -0
  210. package/es/components/organism/index.d.ts +1 -0
  211. package/es/components/organism/index.js +1 -0
  212. package/es/components/organism/index.scss +1 -0
  213. package/es/config/index.d.ts +1 -0
  214. package/es/config/index.js +1 -0
  215. package/es/constants/api.d.ts +10 -0
  216. package/es/constants/api.js +10 -0
  217. package/es/hooks/index.d.ts +1 -0
  218. package/es/hooks/index.js +1 -0
  219. package/es/hooks/useBroadcastedLocalStorage.d.ts +5 -0
  220. package/es/hooks/useBroadcastedLocalStorage.js +71 -0
  221. package/es/hooks/useElementSize.d.ts +7 -0
  222. package/es/hooks/useElementSize.js +56 -0
  223. package/es/utils/common.d.ts +6 -9
  224. package/es/utils/common.js +44 -23
  225. package/es/utils/index.d.ts +1 -0
  226. package/es/utils/index.js +1 -0
  227. package/es/utils/tree.d.ts +225 -0
  228. package/es/utils/tree.js +469 -0
  229. package/es/utils/web.d.ts +4 -0
  230. package/es/utils/web.js +25 -0
  231. package/package.json +29 -3
@@ -0,0 +1,223 @@
1
+ import { useCallback } from 'react';
2
+ import { TextSelection } from '@tiptap/pm/state';
3
+ import { getLinkMark, getLinkMarkRanges, getLinkRange, isLinkColor } from '../utils';
4
+ import { TEXT_EDITOR_CONSTANTS } from '../constants';
5
+ const { LINK_TEXT_COLOR } = TEXT_EDITOR_CONSTANTS;
6
+ export function useLinkHandler(params) {
7
+ const { editor } = params;
8
+ const setLink = useCallback(attrs => {
9
+ if (!editor)
10
+ return;
11
+ const { selection } = editor?.state;
12
+ const { from, to } = selection;
13
+ let linkContent = editor.state.doc.textBetween(from, to);
14
+ if (attrs.content && linkContent !== attrs.content) {
15
+ linkContent = attrs.content;
16
+ }
17
+ editor
18
+ .chain()
19
+ .focus()
20
+ .deleteSelection()
21
+ .insertContent(linkContent)
22
+ .command(({ tr }) => {
23
+ const endPos = tr.selection.from;
24
+ const startPos = endPos - linkContent.length;
25
+ tr.setSelection(TextSelection.create(tr.doc, startPos, endPos));
26
+ return true;
27
+ })
28
+ .setUnderline()
29
+ .setColor(LINK_TEXT_COLOR)
30
+ .setLink(attrs)
31
+ .command(({ tr }) => {
32
+ const endPos = tr.selection.to;
33
+ tr.setSelection(TextSelection.create(tr.doc, endPos, endPos));
34
+ return true;
35
+ })
36
+ .run();
37
+ }, [editor]);
38
+ const deleteLink = useCallback((id) => {
39
+ if (!editor)
40
+ return;
41
+ const { state } = editor;
42
+ const { doc } = state;
43
+ let linkMark;
44
+ doc.descendants((node, pos) => {
45
+ if (linkMark)
46
+ return;
47
+ linkMark = getLinkMarkRanges({
48
+ state,
49
+ from: pos,
50
+ to: pos + node.nodeSize,
51
+ }).find(range => range.mark.attrs.id === id);
52
+ });
53
+ if (linkMark) {
54
+ editor
55
+ .chain()
56
+ .deleteRange({
57
+ from: linkMark.from,
58
+ to: linkMark.to,
59
+ })
60
+ .run();
61
+ }
62
+ }, [editor]);
63
+ const updateLinkAttrsGlobally = useCallback((updateFn) => {
64
+ if (!editor)
65
+ return;
66
+ const { state, view } = editor;
67
+ const { doc, schema, tr } = state;
68
+ const linkType = schema.marks.link;
69
+ let somethingChanged = false;
70
+ doc.descendants((node, pos) => {
71
+ // Get all link mark ranges within this node
72
+ const linkMarkRanges = getLinkMarkRanges({
73
+ state,
74
+ from: pos,
75
+ to: pos + node.nodeSize,
76
+ });
77
+ linkMarkRanges.forEach(markRange => {
78
+ const updatedAttrs = updateFn(markRange.mark.attrs);
79
+ if (updatedAttrs) {
80
+ // Remove the old mark
81
+ tr.removeMark(markRange.from, markRange.to, markRange.mark);
82
+ // Create a new mark with updated attributes and add it
83
+ const newMark = linkType.create({
84
+ ...markRange.mark.attrs,
85
+ ...updatedAttrs,
86
+ });
87
+ tr.addMark(markRange.from, markRange.to, newMark);
88
+ somethingChanged = true;
89
+ }
90
+ });
91
+ });
92
+ if (somethingChanged) {
93
+ view.dispatch(tr);
94
+ }
95
+ }, [editor]);
96
+ const updateLinkTextGlobally = useCallback((updateFn) => {
97
+ if (!editor)
98
+ return;
99
+ const { state, view } = editor;
100
+ const { doc, schema, tr } = state;
101
+ const linkType = schema.marks.link;
102
+ const underlineType = schema.marks.underline; // Assuming you have an underline mark
103
+ const textStyleType = schema.marks.textStyle; // Assuming textStyle mark handles color
104
+ const boldType = schema.marks.bold; // Assuming bold mark
105
+ const italicType = schema.marks.italic; // Assuming italic mark
106
+ const rangesToProcess = [];
107
+ // Collect all unique extended link ranges
108
+ doc.descendants((node, pos) => {
109
+ if (!node.isText)
110
+ return;
111
+ const linkMark = linkType.isInSet(node.marks);
112
+ if (linkMark) {
113
+ const linkRange = getLinkRange({ state, pos });
114
+ if (linkRange) {
115
+ // Check if this extended range has already been added
116
+ const isProcessed = rangesToProcess.some(pr => pr.from === linkRange.from && pr.to === linkRange.to);
117
+ if (!isProcessed) {
118
+ // Find the first link mark in the range to get original attributes
119
+ const originalLinkMark = getLinkMark({
120
+ state,
121
+ from: linkRange.from,
122
+ to: linkRange.to,
123
+ });
124
+ if (originalLinkMark) {
125
+ rangesToProcess.push({
126
+ from: linkRange.from,
127
+ to: linkRange.to,
128
+ originalAttrs: originalLinkMark.attrs,
129
+ });
130
+ }
131
+ }
132
+ }
133
+ }
134
+ });
135
+ // Sort ranges in descending order to avoid issues with position shifts during deletion
136
+ rangesToProcess.sort((a, b) => b.from - a.from);
137
+ let hasChanged = false;
138
+ const applyLinkMarks = (from, to, originalAttrs, originalMarks) => {
139
+ // Apply the link mark with original attributes
140
+ const newLinkMark = linkType.create({
141
+ ...originalAttrs,
142
+ href: originalAttrs.href, // Ensure href is included
143
+ });
144
+ tr.addMark(from, to, newLinkMark);
145
+ // Apply underline mark
146
+ if (underlineType) {
147
+ const newUnderlineMark = underlineType.create();
148
+ tr.addMark(from, to, newUnderlineMark);
149
+ }
150
+ // Apply blue color mark (#0066CC) by finding the existing textStyle mark or creating a new one
151
+ if (textStyleType) {
152
+ const originalTextStyle = originalMarks.find(m => m.type === textStyleType);
153
+ const newColorMark = textStyleType.create({
154
+ ...originalTextStyle?.attrs,
155
+ color: LINK_TEXT_COLOR,
156
+ });
157
+ tr.addMark(from, to, newColorMark);
158
+ }
159
+ // Apply bold mark if it existed
160
+ if (boldType) {
161
+ const originalBoldMark = originalMarks.find(m => m.type === boldType);
162
+ if (originalBoldMark) {
163
+ tr.addMark(from, to, originalBoldMark);
164
+ }
165
+ }
166
+ // Apply italic mark if it existed
167
+ if (italicType) {
168
+ const originalItalicMark = originalMarks.find(m => m.type === italicType);
169
+ if (originalItalicMark) {
170
+ tr.addMark(from, to, originalItalicMark);
171
+ }
172
+ }
173
+ };
174
+ rangesToProcess.forEach(({ from, to, originalAttrs }) => {
175
+ const currentTextContent = state.doc.textBetween(from, to);
176
+ const updatedText = updateFn({
177
+ currentText: currentTextContent,
178
+ attrs: originalAttrs,
179
+ });
180
+ if (updatedText !== undefined) {
181
+ hasChanged = true;
182
+ // Get the marks from the node at the start of the link range
183
+ const originalMarks = state.doc.resolve(from).marks();
184
+ // Delete the old content
185
+ tr.delete(from, to);
186
+ // Insert the new text node
187
+ const newTextNode = schema.text(updatedText);
188
+ tr.insert(from, newTextNode);
189
+ // Apply the desired marks to the new text range
190
+ applyLinkMarks(from, from + updatedText.length, originalAttrs, originalMarks);
191
+ }
192
+ });
193
+ if (hasChanged) {
194
+ view.dispatch(tr);
195
+ }
196
+ }, [editor]);
197
+ const unsetLink = useCallback(() => {
198
+ if (!editor)
199
+ return;
200
+ const { state } = editor;
201
+ const linkRange = getLinkRange({ state, pos: state.selection.from });
202
+ if (!linkRange)
203
+ return;
204
+ const command = editor
205
+ .chain()
206
+ .setTextSelection({
207
+ from: linkRange.from,
208
+ to: linkRange.to,
209
+ })
210
+ .unsetUnderline()
211
+ .unsetLink();
212
+ if (isLinkColor(editor.getAttributes('textStyle').color)) {
213
+ command.unsetColor();
214
+ }
215
+ command.run();
216
+ }, [editor]);
217
+ return {
218
+ setLink,
219
+ deleteLink,
220
+ unsetLink,
221
+ updateLinkAttrsGlobally,
222
+ };
223
+ }
@@ -0,0 +1,26 @@
1
+ import { Editor } from '@tiptap/react';
2
+ import { Mark } from '@tiptap/pm/model';
3
+ export interface MarkSnapshot {
4
+ marks: Mark[];
5
+ position: number;
6
+ timestamp: number;
7
+ textContent: string;
8
+ }
9
+ export interface UseMarkTrackingOptions {
10
+ /** Maximum number of snapshots to keep */
11
+ maxSnapshots?: number;
12
+ /** Marks to exclude from tracking */
13
+ excludeMarks?: string[];
14
+ /** Debounce delay for tracking (ms) */
15
+ debounceDelay?: number;
16
+ /** Auto-capture snapshots */
17
+ autoCapture?: boolean;
18
+ }
19
+ export declare function useMarkTracking(editor: Editor | null, options?: UseMarkTrackingOptions): {
20
+ snapshots: MarkSnapshot[];
21
+ currentMarks: Mark[];
22
+ captureMarkSnapshot: () => void;
23
+ applySnapshot: (index: number) => void;
24
+ getSimilarSnapshots: (targetMarks?: Mark[]) => MarkSnapshot[];
25
+ clearSnapshots: () => void;
26
+ };
@@ -0,0 +1,68 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+ export function useMarkTracking(editor, options = {}) {
3
+ const { maxSnapshots = 10, excludeMarks = ['link', 'smartTag'], debounceDelay = 500, autoCapture = true, } = options;
4
+ const [snapshots, setSnapshots] = useState([]);
5
+ const [currentMarks, setCurrentMarks] = useState([]);
6
+ // Capture current mark state
7
+ const captureMarkSnapshot = useCallback(() => {
8
+ if (!editor)
9
+ return;
10
+ const { selection, storedMarks } = editor.state;
11
+ const { $from } = selection;
12
+ const marks = (storedMarks || $from.marks()).filter(mark => !excludeMarks.includes(mark.type.name));
13
+ const snapshot = {
14
+ marks,
15
+ position: $from.pos,
16
+ timestamp: Date.now(),
17
+ textContent: editor.state.doc.textBetween(Math.max(0, $from.pos - 50), Math.min(editor.state.doc.content.size, $from.pos + 50)),
18
+ };
19
+ setSnapshots(prev => {
20
+ const updated = [snapshot, ...prev];
21
+ return updated.slice(0, maxSnapshots);
22
+ });
23
+ setCurrentMarks(marks);
24
+ }, [editor, excludeMarks, maxSnapshots]);
25
+ // Apply marks from snapshot
26
+ const applySnapshot = useCallback((index) => {
27
+ if (!editor || !snapshots[index])
28
+ return;
29
+ const snapshot = snapshots[index];
30
+ // Clear current marks
31
+ editor.chain().unsetAllMarks().run();
32
+ // Apply snapshot marks
33
+ snapshot.marks.forEach(mark => {
34
+ editor.chain().setMark(mark.type.name, mark.attrs).run();
35
+ });
36
+ }, [editor, snapshots]);
37
+ // Get similar snapshots based on marks
38
+ const getSimilarSnapshots = useCallback((targetMarks = currentMarks) => snapshots.filter(snapshot => {
39
+ const markNames = snapshot.marks.map(m => m.type.name).sort();
40
+ const targetNames = targetMarks.map(m => m.type.name).sort();
41
+ return JSON.stringify(markNames) === JSON.stringify(targetNames);
42
+ }), [snapshots, currentMarks]);
43
+ // Auto-capture setup
44
+ useEffect(() => {
45
+ if (!editor || !autoCapture)
46
+ return;
47
+ let timeoutId;
48
+ const handleUpdate = () => {
49
+ clearTimeout(timeoutId);
50
+ timeoutId = setTimeout(captureMarkSnapshot, debounceDelay);
51
+ };
52
+ editor.on('selectionUpdate', handleUpdate);
53
+ editor.on('update', handleUpdate);
54
+ return () => {
55
+ clearTimeout(timeoutId);
56
+ editor.off('selectionUpdate', handleUpdate);
57
+ editor.off('update', handleUpdate);
58
+ };
59
+ }, [editor, autoCapture, debounceDelay, captureMarkSnapshot]);
60
+ return {
61
+ snapshots,
62
+ currentMarks,
63
+ captureMarkSnapshot,
64
+ applySnapshot,
65
+ getSimilarSnapshots,
66
+ clearSnapshots: () => setSnapshots([]),
67
+ };
68
+ }
@@ -0,0 +1,31 @@
1
+ import { Editor } from '@tiptap/react';
2
+ export interface PersistenceConfig {
3
+ /** Storage key */
4
+ key: string;
5
+ /** Storage type */
6
+ storage?: 'localStorage' | 'sessionStorage' | 'indexedDB';
7
+ /** Auto-save delay */
8
+ autoSaveDelay?: number;
9
+ /** Version for data migration */
10
+ version?: number;
11
+ /** Compression */
12
+ compress?: boolean;
13
+ /** Encryption key */
14
+ encryptionKey?: string;
15
+ }
16
+ export interface PersistentData {
17
+ content: string;
18
+ marks: any[];
19
+ metadata: {
20
+ timestamp: number;
21
+ version: number;
22
+ wordCount: number;
23
+ characterCount: number;
24
+ };
25
+ }
26
+ export declare function usePersistence(editor: Editor | null, config: PersistenceConfig): {
27
+ save: () => Promise<void>;
28
+ load: () => Promise<boolean>;
29
+ saveToStorage: (data: PersistentData) => Promise<void>;
30
+ loadFromStorage: () => Promise<PersistentData | null>;
31
+ };
@@ -0,0 +1,169 @@
1
+ import { useCallback, useEffect, useRef } from 'react';
2
+ import { useDebouncedCallback } from 'use-debounce';
3
+ // Helper functions (simplified implementations)
4
+ async function compressString(str) {
5
+ // Implement compression logic
6
+ return str;
7
+ }
8
+ async function decompressString(str) {
9
+ // Implement decompression logic
10
+ return str;
11
+ }
12
+ async function encryptString(str, _key) {
13
+ // Implement encryption logic
14
+ return str;
15
+ }
16
+ async function decryptString(str, _key) {
17
+ // Implement decryption logic
18
+ return str;
19
+ }
20
+ async function saveToIndexedDB(_key, _data) {
21
+ // Implement IndexedDB save
22
+ }
23
+ async function loadFromIndexedDB(_key) {
24
+ // Implement IndexedDB load
25
+ return null;
26
+ }
27
+ function migrateData(data, _targetVersion) {
28
+ // Implement data migration logic
29
+ return data;
30
+ }
31
+ export function usePersistence(editor, config) {
32
+ const { key, storage = 'localStorage', autoSaveDelay = 2000, version = 1, compress = false, encryptionKey, } = config;
33
+ const lastSavedContent = useRef('');
34
+ // Storage operations
35
+ const saveToStorage = useCallback(async (data) => {
36
+ try {
37
+ let serializedData = JSON.stringify(data);
38
+ // Apply compression if enabled
39
+ if (compress && 'CompressionStream' in window) {
40
+ // Use browser compression API if available
41
+ serializedData = await compressString(serializedData);
42
+ }
43
+ // Apply encryption if key provided
44
+ if (encryptionKey) {
45
+ serializedData = await encryptString(serializedData, encryptionKey);
46
+ }
47
+ switch (storage) {
48
+ case 'localStorage':
49
+ localStorage.setItem(key, serializedData);
50
+ break;
51
+ case 'sessionStorage':
52
+ sessionStorage.setItem(key, serializedData);
53
+ break;
54
+ case 'indexedDB':
55
+ await saveToIndexedDB(key, serializedData);
56
+ break;
57
+ default:
58
+ break;
59
+ }
60
+ }
61
+ catch (error) {
62
+ // eslint-disable-next-line no-console
63
+ console.error('Failed to save to storage:', error);
64
+ }
65
+ }, [key, storage, compress, encryptionKey]);
66
+ const loadFromStorage = useCallback(async () => {
67
+ try {
68
+ let serializedData = null;
69
+ switch (storage) {
70
+ case 'localStorage':
71
+ serializedData = localStorage.getItem(key);
72
+ break;
73
+ case 'sessionStorage':
74
+ serializedData = sessionStorage.getItem(key);
75
+ break;
76
+ case 'indexedDB':
77
+ serializedData = await loadFromIndexedDB(key);
78
+ break;
79
+ default:
80
+ break;
81
+ }
82
+ if (!serializedData)
83
+ return null;
84
+ // Apply decryption if key provided
85
+ if (encryptionKey) {
86
+ serializedData = await decryptString(serializedData, encryptionKey);
87
+ }
88
+ // Apply decompression if enabled
89
+ if (compress && 'DecompressionStream' in window) {
90
+ serializedData = await decompressString(serializedData);
91
+ }
92
+ const data = JSON.parse(serializedData);
93
+ // Handle version migration
94
+ if (data.metadata.version !== version) {
95
+ return migrateData(data, version);
96
+ }
97
+ return data;
98
+ }
99
+ catch (error) {
100
+ // eslint-disable-next-line no-console
101
+ console.error('Failed to load from storage:', error);
102
+ return null;
103
+ }
104
+ }, [key, storage, compress, encryptionKey, version]);
105
+ // Auto-save debounced function
106
+ const debouncedSave = useDebouncedCallback(async () => {
107
+ if (!editor)
108
+ return;
109
+ const currentContent = editor.getHTML();
110
+ // Only save if content changed
111
+ if (currentContent === lastSavedContent.current)
112
+ return;
113
+ const { selection, storedMarks } = editor.state;
114
+ const marks = storedMarks || selection.$from.marks();
115
+ const data = {
116
+ content: currentContent,
117
+ marks: marks.map(mark => ({
118
+ type: mark.type.name,
119
+ attrs: mark.attrs,
120
+ })),
121
+ metadata: {
122
+ timestamp: Date.now(),
123
+ version,
124
+ wordCount: editor.state.doc.textContent.split(/\s+/).length,
125
+ characterCount: editor.state.doc.textContent.length,
126
+ },
127
+ };
128
+ await saveToStorage(data);
129
+ lastSavedContent.current = currentContent;
130
+ }, autoSaveDelay);
131
+ // Manual save
132
+ const save = useCallback(async () => {
133
+ debouncedSave.flush();
134
+ }, [debouncedSave]);
135
+ // Load data
136
+ const load = useCallback(async () => {
137
+ if (!editor)
138
+ return false;
139
+ const data = await loadFromStorage();
140
+ if (!data)
141
+ return false;
142
+ // Set content
143
+ editor.commands.setContent(data.content);
144
+ // Restore marks if available
145
+ if (data.marks.length > 0) {
146
+ data.marks.forEach(({ type, attrs }) => {
147
+ editor.commands.setMark(type, attrs);
148
+ });
149
+ }
150
+ lastSavedContent.current = data.content;
151
+ return true;
152
+ }, [editor, loadFromStorage]);
153
+ // Auto-save setup
154
+ useEffect(() => {
155
+ if (!editor)
156
+ return;
157
+ editor.on('update', debouncedSave);
158
+ return () => {
159
+ editor.off('update', debouncedSave);
160
+ debouncedSave.flush(); // Save any pending changes
161
+ };
162
+ }, [editor, debouncedSave]);
163
+ return {
164
+ save,
165
+ load,
166
+ saveToStorage,
167
+ loadFromStorage,
168
+ };
169
+ }
@@ -0,0 +1,6 @@
1
+ import { Editor } from '@tiptap/react';
2
+ export declare function useStyleMemory(editor: Editor | null): {
3
+ storeCurrentMarks: () => void;
4
+ clearStoredMarks: () => void;
5
+ applyStoredMarks: () => void;
6
+ };
@@ -0,0 +1,42 @@
1
+ import { useCallback, useEffect } from 'react';
2
+ export function useStyleMemory(editor) {
3
+ // Store current marks manually
4
+ const storeCurrentMarks = useCallback(() => {
5
+ editor?.commands.storeCurrentMarks();
6
+ }, [editor]);
7
+ // Clear stored marks
8
+ const clearStoredMarks = useCallback(() => {
9
+ editor?.commands.clearStoredMarks();
10
+ }, [editor]);
11
+ // Apply stored marks
12
+ const applyStoredMarks = useCallback(() => {
13
+ editor?.commands.applyStoredMarks();
14
+ }, [editor]);
15
+ // Auto-store marks when selection changes
16
+ useEffect(() => {
17
+ if (!editor)
18
+ return;
19
+ const handleSelectionUpdate = () => {
20
+ const { selection, doc } = editor.state;
21
+ // Only store if editor has content and selection has marks
22
+ if (doc.content.size > 4 && !selection.empty) {
23
+ const { $from } = selection;
24
+ const marks = editor.state.storedMarks || $from.marks();
25
+ if (marks.length > 0) {
26
+ storeCurrentMarks();
27
+ }
28
+ }
29
+ };
30
+ editor.on('selectionUpdate', handleSelectionUpdate);
31
+ editor.on('update', handleSelectionUpdate);
32
+ return () => {
33
+ editor.off('selectionUpdate', handleSelectionUpdate);
34
+ editor.off('update', handleSelectionUpdate);
35
+ };
36
+ }, [editor, storeCurrentMarks]);
37
+ return {
38
+ storeCurrentMarks,
39
+ clearStoredMarks,
40
+ applyStoredMarks,
41
+ };
42
+ }
@@ -0,0 +1,34 @@
1
+ import { Editor } from '@tiptap/react';
2
+ export interface StylePreset {
3
+ id: string;
4
+ name: string;
5
+ description?: string;
6
+ marks: Array<{
7
+ type: string;
8
+ attrs: Record<string, any>;
9
+ }>;
10
+ textStyle: {
11
+ fontSize?: string;
12
+ fontFamily?: string;
13
+ color?: string;
14
+ backgroundColor?: string;
15
+ fontWeight?: string | number;
16
+ };
17
+ createdAt: number;
18
+ usageCount: number;
19
+ }
20
+ export interface UseStylePresetsOptions {
21
+ /** Storage key for presets */
22
+ storageKey?: string;
23
+ /** Maximum number of presets */
24
+ maxPresets?: number;
25
+ /** Default presets */
26
+ defaultPresets?: Omit<StylePreset, 'id' | 'createdAt' | 'usageCount'>[];
27
+ }
28
+ export declare function useStylePresets(editor: Editor | null, options?: UseStylePresetsOptions): {
29
+ presets: StylePreset[];
30
+ createPreset: (name: string, description?: string) => StylePreset | undefined;
31
+ applyPreset: (presetId: string) => void;
32
+ deletePreset: (presetId: string) => void;
33
+ getPopularPresets: (limit?: number) => StylePreset[];
34
+ };
@@ -0,0 +1,83 @@
1
+ // Use case**: Template systems, corporate branding, user productivity
2
+ import { useCallback } from 'react';
3
+ import { useBroadcastedLocalStorage } from '@antscorp/antsomi-ui/es/hooks/useBroadcastedLocalStorage';
4
+ export function useStylePresets(editor, options = {}) {
5
+ const { storageKey = 'text-editor-style-presets', maxPresets = 20, defaultPresets = [], } = options;
6
+ const { value: presets, setValue: setPresets } = useBroadcastedLocalStorage(storageKey, defaultPresets.map((preset, index) => ({
7
+ ...preset,
8
+ id: `default-${index}`,
9
+ createdAt: Date.now(),
10
+ usageCount: 0,
11
+ })));
12
+ // Create preset from current style
13
+ const createPreset = useCallback((name, description) => {
14
+ if (!editor)
15
+ return;
16
+ const { selection, storedMarks } = editor.state;
17
+ const { $from } = selection;
18
+ const marks = (storedMarks || $from.marks()).map(mark => ({
19
+ type: mark.type.name,
20
+ attrs: mark.attrs,
21
+ }));
22
+ const textStyle = editor.getAttributes('textStyle');
23
+ const preset = {
24
+ id: `preset-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
25
+ name,
26
+ description,
27
+ marks,
28
+ textStyle,
29
+ createdAt: Date.now(),
30
+ usageCount: 0,
31
+ };
32
+ setPresets(prev => {
33
+ const updated = [preset, ...prev];
34
+ return updated.slice(0, maxPresets);
35
+ });
36
+ return preset;
37
+ }, [editor, maxPresets, setPresets]);
38
+ // Apply preset
39
+ const applyPreset = useCallback((presetId) => {
40
+ if (!editor)
41
+ return;
42
+ const preset = presets.find(p => p.id === presetId);
43
+ if (!preset)
44
+ return;
45
+ // Clear current formatting
46
+ editor.chain().focus().unsetAllMarks().run();
47
+ // Apply text style attributes
48
+ if (preset.textStyle.fontSize) {
49
+ editor.chain().setFontSize(preset.textStyle.fontSize).run();
50
+ }
51
+ if (preset.textStyle.fontFamily) {
52
+ editor.chain().setFontFamily(preset.textStyle.fontFamily).run();
53
+ }
54
+ if (preset.textStyle.color) {
55
+ editor.chain().setColor(preset.textStyle.color).run();
56
+ }
57
+ if (preset.textStyle.backgroundColor) {
58
+ editor.chain().setBackgroundColor(preset.textStyle.backgroundColor).run();
59
+ }
60
+ if (preset.textStyle.fontWeight) {
61
+ editor.chain().setFontWeight(preset.textStyle.fontWeight).run();
62
+ }
63
+ // Apply marks
64
+ preset.marks.forEach(({ type, attrs }) => {
65
+ editor.chain().setMark(type, attrs).run();
66
+ });
67
+ // Update usage count
68
+ setPresets(prev => prev.map(p => (p.id === presetId ? { ...p, usageCount: p.usageCount + 1 } : p)));
69
+ }, [editor, presets, setPresets]);
70
+ // Delete preset
71
+ const deletePreset = useCallback((presetId) => {
72
+ setPresets(prev => prev.filter(p => p.id !== presetId));
73
+ }, [setPresets]);
74
+ // Get popular presets
75
+ const getPopularPresets = useCallback((limit = 5) => [...presets].sort((a, b) => b.usageCount - a.usageCount).slice(0, limit), [presets]);
76
+ return {
77
+ presets,
78
+ createPreset,
79
+ applyPreset,
80
+ deletePreset,
81
+ getPopularPresets,
82
+ };
83
+ }