@use-kona/editor 0.1.2 → 0.1.4

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 (226) hide show
  1. package/README.md +28 -17
  2. package/dist/index.d.ts +0 -1
  3. package/dist/index.js +1 -2
  4. package/dist/plugins/CodeBlockPlugin/CodeBlockPlugin.js +38 -37
  5. package/dist/plugins/CodeBlockPlugin/index.d.ts +1 -0
  6. package/dist/plugins/EmojiPlugin/EmojiPlugin.d.ts +28 -0
  7. package/dist/plugins/EmojiPlugin/EmojiPlugin.js +83 -0
  8. package/dist/plugins/EmojiPlugin/Menu.d.ts +7 -0
  9. package/dist/plugins/EmojiPlugin/Menu.js +51 -0
  10. package/dist/plugins/EmojiPlugin/index.d.ts +1 -0
  11. package/dist/plugins/EmojiPlugin/index.js +2 -0
  12. package/dist/plugins/EmojiPlugin/styles.module.js +7 -0
  13. package/dist/plugins/EmojiPlugin/styles_module.css +11 -0
  14. package/dist/plugins/EmojiPlugin/types.d.ts +7 -0
  15. package/dist/plugins/FloatingMenuPlugin/FloatingMenu.js +15 -28
  16. package/dist/plugins/FloatingMenuPlugin/types.d.ts +4 -1
  17. package/dist/plugins/HighlightsPlugin/HighlightsPlugin.d.ts +1 -0
  18. package/dist/plugins/HighlightsPlugin/HighlightsPlugin.js +3 -0
  19. package/dist/plugins/ListsPlugin/styles_module.css +4 -0
  20. package/dist/plugins/PlaceholderPlugin/PlaceholderPlugin.js +6 -3
  21. package/dist/plugins/PlaceholderPlugin/styles.module.js +1 -0
  22. package/dist/plugins/PlaceholderPlugin/styles_module.css +4 -0
  23. package/dist/plugins/index.d.ts +2 -1
  24. package/dist/plugins/index.js +2 -1
  25. package/package.json +12 -8
  26. package/src/index.ts +0 -1
  27. package/src/plugins/CodeBlockPlugin/CodeBlockPlugin.tsx +51 -48
  28. package/src/plugins/CodeBlockPlugin/index.ts +1 -0
  29. package/src/plugins/EmojiPlugin/EmojiPlugin.tsx +116 -0
  30. package/src/plugins/EmojiPlugin/Menu.tsx +74 -0
  31. package/src/plugins/EmojiPlugin/index.ts +1 -0
  32. package/src/plugins/EmojiPlugin/styles.module.css +10 -0
  33. package/src/plugins/EmojiPlugin/types.ts +5 -0
  34. package/src/plugins/FloatingMenuPlugin/FloatingMenu.tsx +13 -22
  35. package/src/plugins/FloatingMenuPlugin/types.ts +4 -1
  36. package/src/plugins/HighlightsPlugin/HighlightsPlugin.tsx +4 -0
  37. package/src/plugins/ListsPlugin/styles.module.css +4 -0
  38. package/src/plugins/PlaceholderPlugin/PlaceholderPlugin.tsx +13 -3
  39. package/src/plugins/PlaceholderPlugin/styles.module.css +2 -2
  40. package/src/plugins/index.ts +2 -1
  41. package/dist/examples/Backdrop.d.ts +0 -5
  42. package/dist/examples/Backdrop.js +0 -13
  43. package/dist/examples/Backdrop.module.js +0 -5
  44. package/dist/examples/Backdrop_module.css +0 -6
  45. package/dist/examples/CodeBlock.d.ts +0 -12
  46. package/dist/examples/CodeBlock.js +0 -163
  47. package/dist/examples/CodeBlock.module.js +0 -9
  48. package/dist/examples/CodeBlock_module.css +0 -66
  49. package/dist/examples/DragBlock.d.ts +0 -11
  50. package/dist/examples/DragBlock.js +0 -38
  51. package/dist/examples/DragBlock.module.js +0 -9
  52. package/dist/examples/DragBlock_module.css +0 -43
  53. package/dist/examples/DragHandler.d.ts +0 -2
  54. package/dist/examples/DragHandler.js +0 -44
  55. package/dist/examples/DragHandler.module.js +0 -8
  56. package/dist/examples/DragHandler_module.css +0 -18
  57. package/dist/examples/Editor.d.ts +0 -8
  58. package/dist/examples/Editor.js +0 -44
  59. package/dist/examples/Editor.module.js +0 -12
  60. package/dist/examples/Editor_module.css +0 -127
  61. package/dist/examples/FloatingMenu.d.ts +0 -17
  62. package/dist/examples/FloatingMenu.js +0 -244
  63. package/dist/examples/FloatingMenu.module.js +0 -9
  64. package/dist/examples/FloatingMenu_module.css +0 -75
  65. package/dist/examples/LinksHint.d.ts +0 -7
  66. package/dist/examples/LinksHint.js +0 -50
  67. package/dist/examples/LinksHint.module.js +0 -6
  68. package/dist/examples/LinksHint_module.css +0 -28
  69. package/dist/examples/Menu.d.ts +0 -6
  70. package/dist/examples/Menu.js +0 -79
  71. package/dist/examples/Menu.module.js +0 -8
  72. package/dist/examples/Menu_module.css +0 -38
  73. package/dist/examples/colors.d.ts +0 -10
  74. package/dist/examples/colors.js +0 -12
  75. package/dist/examples/getCommands.d.ts +0 -2
  76. package/dist/examples/getCommands.js +0 -87
  77. package/dist/examples/getPlugins.d.ts +0 -2
  78. package/dist/examples/getPlugins.js +0 -127
  79. package/dist/examples/getShortcuts.d.ts +0 -2
  80. package/dist/examples/getShortcuts.js +0 -90
  81. package/dist/examples/icons/bold.d.ts +0 -2
  82. package/dist/examples/icons/bold.js +0 -27
  83. package/dist/examples/icons/check.d.ts +0 -2
  84. package/dist/examples/icons/check.js +0 -24
  85. package/dist/examples/icons/chevronRight.d.ts +0 -2
  86. package/dist/examples/icons/chevronRight.js +0 -24
  87. package/dist/examples/icons/color.d.ts +0 -2
  88. package/dist/examples/icons/color.js +0 -30
  89. package/dist/examples/icons/copy.d.ts +0 -2
  90. package/dist/examples/icons/copy.js +0 -27
  91. package/dist/examples/icons/cross.d.ts +0 -2
  92. package/dist/examples/icons/cross.js +0 -27
  93. package/dist/examples/icons/drag.d.ts +0 -2
  94. package/dist/examples/icons/drag.js +0 -39
  95. package/dist/examples/icons/edit.d.ts +0 -2
  96. package/dist/examples/icons/edit.js +0 -30
  97. package/dist/examples/icons/external.d.ts +0 -2
  98. package/dist/examples/icons/external.js +0 -30
  99. package/dist/examples/icons/heading1.d.ts +0 -2
  100. package/dist/examples/icons/heading1.js +0 -45
  101. package/dist/examples/icons/heading2.d.ts +0 -2
  102. package/dist/examples/icons/heading2.js +0 -45
  103. package/dist/examples/icons/heading3.d.ts +0 -2
  104. package/dist/examples/icons/heading3.js +0 -48
  105. package/dist/examples/icons/italic.d.ts +0 -2
  106. package/dist/examples/icons/italic.js +0 -30
  107. package/dist/examples/icons/link.d.ts +0 -2
  108. package/dist/examples/icons/link.js +0 -30
  109. package/dist/examples/icons/ol.d.ts +0 -2
  110. package/dist/examples/icons/ol.js +0 -36
  111. package/dist/examples/icons/strikethrough.d.ts +0 -2
  112. package/dist/examples/icons/strikethrough.js +0 -27
  113. package/dist/examples/icons/text.d.ts +0 -2
  114. package/dist/examples/icons/text.js +0 -22
  115. package/dist/examples/icons/types.d.ts +0 -3
  116. package/dist/examples/icons/ul.d.ts +0 -2
  117. package/dist/examples/icons/ul.js +0 -39
  118. package/dist/examples/icons/underline.d.ts +0 -2
  119. package/dist/examples/icons/underline.js +0 -27
  120. package/dist/examples/store.d.ts +0 -8
  121. package/dist/examples/store.js +0 -6
  122. package/dist/examples/styles.module.js +0 -11
  123. package/dist/examples/styles_module.css +0 -78
  124. package/dist/examples/text.d.ts +0 -3
  125. package/dist/examples/text.js +0 -60
  126. package/dist/examples/ui/Button/Button.d.ts +0 -8
  127. package/dist/examples/ui/Button/Button.js +0 -15
  128. package/dist/examples/ui/Button/ButtonWrapper.d.ts +0 -4
  129. package/dist/examples/ui/Button/ButtonWrapper.js +0 -14
  130. package/dist/examples/ui/Button/index.d.ts +0 -2
  131. package/dist/examples/ui/Button/index.js +0 -3
  132. package/dist/examples/ui/Button/styles.module.js +0 -10
  133. package/dist/examples/ui/Button/styles_module.css +0 -72
  134. package/dist/examples/ui/Button/types.d.ts +0 -1
  135. package/dist/examples/ui/Button/types.js +0 -0
  136. package/dist/examples/ui/Dropdown/Dropdown.d.ts +0 -16
  137. package/dist/examples/ui/Dropdown/Dropdown.js +0 -75
  138. package/dist/examples/ui/Dropdown/index.d.ts +0 -1
  139. package/dist/examples/ui/Dropdown/index.js +0 -2
  140. package/dist/examples/ui/Menu/Menu.d.ts +0 -41
  141. package/dist/examples/ui/Menu/Menu.js +0 -404
  142. package/dist/examples/ui/Menu/MenuDelimiter.d.ts +0 -1
  143. package/dist/examples/ui/Menu/MenuDelimiter.js +0 -6
  144. package/dist/examples/ui/Menu/MenuHotkey.d.ts +0 -6
  145. package/dist/examples/ui/Menu/MenuHotkey.js +0 -12
  146. package/dist/examples/ui/Menu/MenuIcon.d.ts +0 -6
  147. package/dist/examples/ui/Menu/MenuIcon.js +0 -12
  148. package/dist/examples/ui/Menu/MenuItem.d.ts +0 -6
  149. package/dist/examples/ui/Menu/MenuItem.js +0 -17
  150. package/dist/examples/ui/Menu/MenuTitle.d.ts +0 -6
  151. package/dist/examples/ui/Menu/MenuTitle.js +0 -12
  152. package/dist/examples/ui/Menu/SafeSpace.d.ts +0 -6
  153. package/dist/examples/ui/Menu/SafeSpace.js +0 -65
  154. package/dist/examples/ui/Menu/index.d.ts +0 -2
  155. package/dist/examples/ui/Menu/index.js +0 -2
  156. package/dist/examples/ui/Menu/styles.module.js +0 -21
  157. package/dist/examples/ui/Menu/styles_module.css +0 -140
  158. package/dist/examples/ui/Menu/types.d.ts +0 -16
  159. package/dist/examples/ui/Menu/types.js +0 -0
  160. package/dist/examples/ui/useMenuPosition.d.ts +0 -18
  161. package/dist/examples/ui/useMenuPosition.js +0 -51
  162. package/dist/examples/ui/useMergeRefs.d.ts +0 -23
  163. package/dist/examples/ui/useMergeRefs.js +0 -11
  164. package/src/examples/Backdrop.module.css +0 -8
  165. package/src/examples/Backdrop.tsx +0 -16
  166. package/src/examples/CodeBlock.module.css +0 -65
  167. package/src/examples/CodeBlock.tsx +0 -109
  168. package/src/examples/DragBlock.module.css +0 -42
  169. package/src/examples/DragBlock.tsx +0 -57
  170. package/src/examples/DragHandler.module.css +0 -17
  171. package/src/examples/DragHandler.tsx +0 -39
  172. package/src/examples/Editor.module.css +0 -129
  173. package/src/examples/Editor.tsx +0 -68
  174. package/src/examples/FloatingMenu.module.css +0 -74
  175. package/src/examples/FloatingMenu.tsx +0 -274
  176. package/src/examples/LinksHint.module.css +0 -27
  177. package/src/examples/LinksHint.tsx +0 -58
  178. package/src/examples/Menu.module.css +0 -37
  179. package/src/examples/Menu.tsx +0 -80
  180. package/src/examples/colors.ts +0 -11
  181. package/src/examples/getCommands.tsx +0 -76
  182. package/src/examples/getPlugins.tsx +0 -143
  183. package/src/examples/getShortcuts.ts +0 -107
  184. package/src/examples/icons/bold.tsx +0 -20
  185. package/src/examples/icons/check.tsx +0 -19
  186. package/src/examples/icons/chevronRight.tsx +0 -19
  187. package/src/examples/icons/color.tsx +0 -23
  188. package/src/examples/icons/copy.tsx +0 -20
  189. package/src/examples/icons/cross.tsx +0 -20
  190. package/src/examples/icons/drag.tsx +0 -24
  191. package/src/examples/icons/edit.tsx +0 -21
  192. package/src/examples/icons/external.tsx +0 -21
  193. package/src/examples/icons/heading1.tsx +0 -26
  194. package/src/examples/icons/heading2.tsx +0 -26
  195. package/src/examples/icons/heading3.tsx +0 -27
  196. package/src/examples/icons/italic.tsx +0 -21
  197. package/src/examples/icons/link.tsx +0 -21
  198. package/src/examples/icons/ol.tsx +0 -23
  199. package/src/examples/icons/strikethrough.tsx +0 -20
  200. package/src/examples/icons/text.tsx +0 -18
  201. package/src/examples/icons/types.ts +0 -3
  202. package/src/examples/icons/ul.tsx +0 -24
  203. package/src/examples/icons/underline.tsx +0 -20
  204. package/src/examples/store.ts +0 -14
  205. package/src/examples/styles.module.css +0 -77
  206. package/src/examples/text.tsx +0 -133
  207. package/src/examples/ui/Button/Button.tsx +0 -34
  208. package/src/examples/ui/Button/ButtonWrapper.tsx +0 -22
  209. package/src/examples/ui/Button/index.ts +0 -2
  210. package/src/examples/ui/Button/styles.module.css +0 -75
  211. package/src/examples/ui/Button/types.ts +0 -1
  212. package/src/examples/ui/Dropdown/Dropdown.tsx +0 -101
  213. package/src/examples/ui/Dropdown/index.ts +0 -1
  214. package/src/examples/ui/Menu/Menu.tsx +0 -576
  215. package/src/examples/ui/Menu/MenuDelimiter.tsx +0 -3
  216. package/src/examples/ui/Menu/MenuHotkey.tsx +0 -17
  217. package/src/examples/ui/Menu/MenuIcon.tsx +0 -17
  218. package/src/examples/ui/Menu/MenuItem.tsx +0 -45
  219. package/src/examples/ui/Menu/MenuTitle.tsx +0 -17
  220. package/src/examples/ui/Menu/SafeSpace.tsx +0 -84
  221. package/src/examples/ui/Menu/index.ts +0 -2
  222. package/src/examples/ui/Menu/styles.module.css +0 -143
  223. package/src/examples/ui/Menu/types.ts +0 -18
  224. package/src/examples/ui/useMenuPosition.ts +0 -72
  225. package/src/examples/ui/useMergeRefs.ts +0 -39
  226. /package/dist/{examples/icons → plugins/EmojiPlugin}/types.js +0 -0
@@ -249,57 +249,60 @@ export class CodeBlockPlugin implements IPlugin {
249
249
  }
250
250
 
251
251
  static toggleCodeBlock = (editor: Editor) => {
252
- Editor.withoutNormalizing(editor, () => {
253
- const node = Editor.above<CustomElement>(editor, {
252
+ if (!editor.selection) {
253
+ return;
254
+ }
255
+
256
+ const node = Editor.above<CustomElement>(editor, {
257
+ match: (n) =>
258
+ !Editor.isEditor(n) &&
259
+ (n as CustomElement).type === CodeBlockPlugin.CODE_ELEMENT,
260
+ mode: 'highest',
261
+ });
262
+
263
+ if (node) {
264
+ Transforms.setNodes(
265
+ editor,
266
+ { type: 'paragraph' },
267
+ {
268
+ at: node[1],
269
+ match: (n) =>
270
+ (n as CustomElement).type === CodeBlockPlugin.CODE_LINE_ELEMENT,
271
+ mode: 'lowest',
272
+ },
273
+ );
274
+ Transforms.unwrapNodes(editor, {
275
+ at: node[1],
254
276
  match: (n) =>
255
- !Editor.isEditor(n) &&
256
277
  (n as CustomElement).type === CodeBlockPlugin.CODE_ELEMENT,
257
- mode: 'highest',
278
+ split: true,
258
279
  });
259
-
260
- if (node) {
261
- Transforms.setNodes(
262
- editor,
263
- { type: 'paragraph' },
264
- {
265
- at: node[1],
266
- match: (n) =>
267
- (n as CustomElement).type === CodeBlockPlugin.CODE_LINE_ELEMENT,
268
- mode: 'lowest',
269
- },
270
- );
271
- Transforms.unwrapNodes(editor, {
272
- at: node[1],
280
+ } else {
281
+ Transforms.setNodes(
282
+ editor,
283
+ {
284
+ type: CodeBlockPlugin.CODE_LINE_ELEMENT,
285
+ children: [{ text: '' }],
286
+ },
287
+ {
288
+ mode: 'lowest',
289
+ },
290
+ );
291
+
292
+ Transforms.wrapNodes(
293
+ editor,
294
+ {
295
+ type: CodeBlockPlugin.CODE_ELEMENT,
296
+ language: 'javascript',
297
+ children: [],
298
+ } as CodeElement,
299
+ {
300
+ mode: 'highest',
273
301
  match: (n) =>
274
- (n as CustomElement).type === CodeBlockPlugin.CODE_ELEMENT,
275
- split: true,
276
- });
277
- } else {
278
- Transforms.setNodes(
279
- editor,
280
- {
281
- type: CodeBlockPlugin.CODE_LINE_ELEMENT,
282
- children: [{ text: '' }],
283
- },
284
- {
285
- match: (n) =>
286
- Editor.isBlock(editor, n as CustomElement) &&
287
- (n as CustomElement).type === 'paragraph',
288
- },
289
- );
290
- Transforms.wrapNodes(
291
- editor,
292
- {
293
- type: CodeBlockPlugin.CODE_ELEMENT,
294
- language: 'javascript',
295
- children: [],
296
- } as CodeElement,
297
- {
298
- match: (n) =>
299
- (n as CustomElement).type === CodeBlockPlugin.CODE_LINE_ELEMENT,
300
- },
301
- );
302
- }
303
- });
302
+ (n as CustomElement).type === CodeBlockPlugin.CODE_LINE_ELEMENT,
303
+ at: editor.selection.focus,
304
+ },
305
+ );
306
+ }
304
307
  };
305
308
  }
@@ -1 +1,2 @@
1
1
  export { CodeBlockPlugin } from './CodeBlockPlugin';
2
+ export type { CodeElement } from './types';
@@ -0,0 +1,116 @@
1
+ import { useStore } from '@nanostores/react';
2
+ import { type MapStore, map } from 'nanostores';
3
+ import type { ReactNode } from 'react';
4
+ import { Editor, Node, Transforms } from 'slate';
5
+ import type { CustomElement } from '../../../types';
6
+ import type { IPlugin } from '../../types';
7
+ import { Menu } from './Menu';
8
+ import styles from './styles.module.css';
9
+ import type { EmojiElement } from './types';
10
+
11
+ type Options = {
12
+ onSearch: (query: string) => void;
13
+ renderMenu: (actions: {
14
+ insertEmoji: (emoji: string, query: string, editor: Editor) => void;
15
+ }) => ReactNode;
16
+ renderEmoji: (emoji: string) => ReactNode;
17
+ ignoreNodes?: string[];
18
+ };
19
+
20
+ export class EmojiPlugin implements IPlugin {
21
+ options: Options;
22
+ $store: MapStore<{ isOpen: boolean }>;
23
+
24
+ constructor(options: Options) {
25
+ this.options = options;
26
+ this.$store = map({
27
+ isOpen: false,
28
+ });
29
+ }
30
+
31
+ blocks = [
32
+ {
33
+ isInline: true,
34
+ isVoid: true,
35
+ type: 'emoji',
36
+ render: (props) => {
37
+ const children = this.options.renderEmoji(props.element.emoji);
38
+
39
+ return (
40
+ <span {...props.attributes} className={styles.emojiRoot}>
41
+ {children}
42
+ </span>
43
+ );
44
+ },
45
+ },
46
+ ];
47
+
48
+ init(editor) {
49
+ const { insertText, onChange } = editor;
50
+
51
+ editor.insertText = (text: string) => {
52
+ if (text === ':') {
53
+ this.$store.setKey('isOpen', true);
54
+ }
55
+
56
+ insertText(text);
57
+ };
58
+
59
+ editor.onChange = (...args) => {
60
+ if (this.$store.get().isOpen) {
61
+ const query = /:([^:]*$)/.exec(getCurrentText(editor));
62
+ if (query?.[0]) {
63
+ this.options.onSearch(query[1]);
64
+ } else {
65
+ this.$store.setKey('isOpen', false);
66
+ }
67
+ }
68
+
69
+ return onChange(...args);
70
+ };
71
+
72
+ return editor;
73
+ }
74
+
75
+ ui() {
76
+ const { isOpen } = useStore(this.$store);
77
+
78
+ if (!isOpen) {
79
+ return null;
80
+ }
81
+
82
+ return (
83
+ <Menu isOpen={isOpen}>
84
+ {this.options.renderMenu({
85
+ insertEmoji: (emoji, query, editor) => {
86
+ this.$store.setKey('isOpen', false);
87
+ Transforms.delete(editor, {
88
+ at: editor.selection?.focus,
89
+ distance: query.length + 1,
90
+ reverse: true,
91
+ unit: 'character',
92
+ });
93
+ Transforms.insertNodes(editor, {
94
+ type: 'emoji',
95
+ emoji,
96
+ children: [{ text: '' }],
97
+ } as EmojiElement);
98
+ Transforms.move(editor);
99
+ },
100
+ })}
101
+ </Menu>
102
+ );
103
+ }
104
+ }
105
+
106
+ const getCurrentText = (editor: Editor) => {
107
+ const entry = Editor.above(editor, {
108
+ match: (n) => Editor.isBlock(editor, n as CustomElement),
109
+ });
110
+
111
+ if (entry) {
112
+ return Node.string(entry[0]);
113
+ } else {
114
+ return '';
115
+ }
116
+ };
@@ -0,0 +1,74 @@
1
+ import {
2
+ type CSSProperties,
3
+ type ReactNode,
4
+ useLayoutEffect,
5
+ useState,
6
+ } from 'react';
7
+ import { createPortal } from 'react-dom';
8
+ import { useFocused, useSlateSelection } from 'slate-react';
9
+ import styles from './styles.module.css';
10
+
11
+ type Props = {
12
+ isOpen: boolean;
13
+ children: ReactNode;
14
+ };
15
+
16
+ export const Menu = (props: Props) => {
17
+ const { isOpen, children } = props;
18
+
19
+ const isFocused = useFocused();
20
+ const selection = useSlateSelection();
21
+
22
+ const [style, setStyle] = useState<CSSProperties | undefined>({});
23
+
24
+ useLayoutEffect(() => {
25
+ if (!selection || !isFocused) {
26
+ setStyle(undefined);
27
+ return;
28
+ }
29
+
30
+ setTimeout(() => {
31
+ const domSelection = window.getSelection();
32
+ const domRange = domSelection?.getRangeAt(0);
33
+ const rect = domRange?.getBoundingClientRect();
34
+
35
+ if (isOpen) {
36
+ setStyle({
37
+ opacity: 1,
38
+ transform: 'scale(1)',
39
+ top: `${(rect?.top || 0) + window.scrollY + (rect?.height || 0) + 2}px`,
40
+ left: `${(rect?.left || 0) + window.scrollX + (rect?.width || 0) / 2}px`,
41
+ });
42
+ } else {
43
+ setStyle({
44
+ opacity: 0,
45
+ transform: 'scale(0.9)',
46
+ });
47
+ }
48
+ }, 0);
49
+ }, [selection, isFocused, isOpen]);
50
+
51
+ const handleMenuLayout = (element: HTMLDivElement) => {
52
+ if (element) {
53
+ const { height, top } = element.getBoundingClientRect();
54
+
55
+ const domSelection = window.getSelection();
56
+ const domRange = domSelection?.getRangeAt(0);
57
+ const rect = domRange?.getBoundingClientRect();
58
+
59
+ if (top + height >= window.innerHeight) {
60
+ setStyle((style) => ({
61
+ ...style,
62
+ top: `${top - height - (rect?.height ?? 22)}px`,
63
+ }));
64
+ }
65
+ }
66
+ };
67
+
68
+ return createPortal(
69
+ <div ref={handleMenuLayout} style={style} className={styles.root}>
70
+ {children}
71
+ </div>,
72
+ document.body,
73
+ );
74
+ };
@@ -0,0 +1 @@
1
+ export { EmojiPlugin } from './EmojiPlugin';
@@ -0,0 +1,10 @@
1
+ .root {
2
+ position: absolute;
3
+ z-index: 2;
4
+ }
5
+
6
+ .emoji-root {
7
+ vertical-align: text-bottom;
8
+ height: 24px;
9
+ display: inline-flex;
10
+ }
@@ -0,0 +1,5 @@
1
+ export type EmojiElement = {
2
+ type: 'emoji';
3
+ emoji: string;
4
+ children: [{ text: string }];
5
+ };
@@ -117,28 +117,19 @@ export const FloatingMenu = (props: Props) => {
117
117
  }
118
118
 
119
119
  return createPortal(
120
- <>
121
- <div
122
- onMouseDown={() => {
123
- setStyle(undefined);
124
- }}
125
- >
126
- {options.renderBackdrop?.({ onClose, onUpdate: handleUpdate })}
127
- </div>
128
- <div
129
- ref={ref}
130
- style={{
131
- ...style,
132
- display: 'block',
133
- }}
134
- className={styles.root}
135
- onMouseDown={(event) => {
136
- event.preventDefault();
137
- }}
138
- >
139
- {options.renderMenu(editor, { onClose, onUpdate: handleUpdate })}
140
- </div>
141
- </>,
120
+ <div
121
+ ref={ref}
122
+ style={{
123
+ ...style,
124
+ display: 'block',
125
+ }}
126
+ className={styles.root}
127
+ onMouseDown={(event) => {
128
+ event.preventDefault();
129
+ }}
130
+ >
131
+ {options.renderMenu(editor, { onClose, onUpdate: handleUpdate })}
132
+ </div>,
142
133
  document.body,
143
134
  );
144
135
  };
@@ -4,7 +4,10 @@ import type { Editor } from 'slate';
4
4
  export type Options = {
5
5
  ignoreNodes?: string[];
6
6
  renderMenu: (editor: Editor, commands: Commands) => ReactNode;
7
- renderBackdrop: (commands: {
7
+ /**
8
+ * @deprecated
9
+ */
10
+ renderBackdrop?: (commands: {
8
11
  onClose: () => void;
9
12
  onUpdate: () => void;
10
13
  }) => ReactNode;
@@ -27,6 +27,10 @@ export class HighlightsPlugin implements IPlugin {
27
27
  return marks ? marks.highlight === color : false;
28
28
  }
29
29
 
30
+ static removeHighlight(editor: Editor) {
31
+ Editor.removeMark(editor, 'highlight');
32
+ }
33
+
30
34
  leafs = [
31
35
  {
32
36
  render: (props: RenderLeafProps) => {
@@ -1,5 +1,9 @@
1
1
  .list {
2
2
  padding: 0;
3
+
4
+ & & {
5
+ margin-left: 32px;
6
+ }
3
7
  }
4
8
 
5
9
  .listItem {
@@ -1,4 +1,4 @@
1
- import { Editor, Node } from 'slate';
1
+ import { type Descendant, Editor, type Element, Node } from 'slate';
2
2
  import {
3
3
  type RenderLeafProps,
4
4
  useFocused,
@@ -26,7 +26,9 @@ export class PlaceholderPlugin implements IPlugin {
26
26
  const isFocused = useFocused();
27
27
 
28
28
  const entity = Editor.above<CustomElement>(editor, {
29
+ at: editor.selection?.focus,
29
30
  mode: 'lowest',
31
+ voids: true,
30
32
  });
31
33
 
32
34
  const firstEntity = Editor.above(editor, {
@@ -38,7 +40,15 @@ export class PlaceholderPlugin implements IPlugin {
38
40
  return props.children;
39
41
  }
40
42
 
41
- const isEmpty = !entity || Node.string(entity[0]) === '';
43
+ const hasVoids = entity?.[0].children.some((n: Descendant) => {
44
+ return Editor.isVoid(editor, n as Element);
45
+ });
46
+
47
+ const isEmpty =
48
+ (!entity || Node.string(entity[0]) === '') &&
49
+ !hasVoids &&
50
+ !Editor.isVoid(editor, entity?.[0] as Element);
51
+
42
52
  const isEditorEmpty =
43
53
  !firstEntity ||
44
54
  (Node.string(firstEntity[0]) === '' && editor.children.length <= 1);
@@ -50,7 +60,7 @@ export class PlaceholderPlugin implements IPlugin {
50
60
  <>
51
61
  <span {...props.attributes}>
52
62
  <span
53
- className={isVisible ? styles.placeholder : undefined}
63
+ className={isVisible ? styles.placeholder : styles.hidden}
54
64
  data-placeholder={
55
65
  isFocused ? this.options.focused : this.options.unfocused
56
66
  }
@@ -1,5 +1,5 @@
1
- .absolute {
2
- /*position: absolute;*/
1
+ .hidden.placeholder {
2
+ display: none;
3
3
  }
4
4
 
5
5
  .placeholder {
@@ -1,9 +1,10 @@
1
1
  export { AttachmentsPlugin } from './AttachmentsPlugin';
2
2
  export { BasicFormattingPlugin } from './BasicFormattingPlugin';
3
3
  export { BreaksPlugin } from './BreaksPlugin';
4
- export { CodeBlockPlugin } from './CodeBlockPlugin';
4
+ export { CodeBlockPlugin, type CodeElement } from './CodeBlockPlugin';
5
5
  export { type Command, CommandsPlugin } from './CommandsPlugin';
6
6
  export { DnDPlugin } from './DnDPlugin';
7
+ export { EmojiPlugin } from './EmojiPlugin';
7
8
  export { type Commands, FloatingMenuPlugin } from './FloatingMenuPlugin';
8
9
  export { HeadingsPlugin } from './HeadingsPlugin';
9
10
  export { HighlightsPlugin } from './HighlightsPlugin';
@@ -1,5 +0,0 @@
1
- type Props = {
2
- onClose: () => void;
3
- };
4
- export declare const Backdrop: (props: Props) => import("react/jsx-runtime").JSX.Element | null;
5
- export {};
@@ -1,13 +0,0 @@
1
- import { jsx } from "react/jsx-runtime";
2
- import { useStore } from "@nanostores/react";
3
- import Backdrop_module from "./Backdrop.module.js";
4
- import { $store } from "./store.js";
5
- const Backdrop = (props)=>{
6
- const { isFloatingMenuOpen } = useStore($store);
7
- const { onClose } = props;
8
- return isFloatingMenuOpen ? /*#__PURE__*/ jsx("div", {
9
- className: Backdrop_module.root,
10
- onClick: onClose
11
- }) : null;
12
- };
13
- export { Backdrop };
@@ -1,5 +0,0 @@
1
- import "./Backdrop_module.css";
2
- const Backdrop_module = {
3
- root: "root-f5Zwn7"
4
- };
5
- export { Backdrop_module as default };
@@ -1,6 +0,0 @@
1
- .root-f5Zwn7 {
2
- z-index: 1;
3
- position: fixed;
4
- inset: 0;
5
- }
6
-
@@ -1,12 +0,0 @@
1
- import { type ReactNode } from 'react';
2
- import type { CustomElement } from '../../types';
3
- type Props = {
4
- value: string;
5
- onChange: (value: string) => void;
6
- params: {
7
- element: CustomElement;
8
- Content: () => ReactNode;
9
- };
10
- };
11
- export declare const CodeBlock: (props: Props) => import("react/jsx-runtime").JSX.Element;
12
- export {};
@@ -1,163 +0,0 @@
1
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import { forwardRef, useMemo } from "react";
3
- import { Node } from "slate";
4
- import CodeBlock_module from "./CodeBlock.module.js";
5
- import { CheckIcon } from "./icons/check.js";
6
- import { CopyIcon } from "./icons/copy.js";
7
- import { Button } from "./ui/Button/index.js";
8
- import { Dropdown } from "./ui/Dropdown/index.js";
9
- import { Menu } from "./ui/Menu/index.js";
10
- const languages = [
11
- {
12
- value: "javascript",
13
- label: 'JavaScript'
14
- },
15
- {
16
- value: "typescript",
17
- label: 'TypeScript'
18
- },
19
- {
20
- value: 'jsx',
21
- label: 'JSX'
22
- },
23
- {
24
- value: 'tsx',
25
- label: 'TSX'
26
- },
27
- {
28
- value: 'html',
29
- label: 'HTML'
30
- },
31
- {
32
- value: 'css',
33
- label: 'CSS'
34
- },
35
- {
36
- value: 'json',
37
- label: 'JSON'
38
- },
39
- {
40
- value: 'python',
41
- label: 'Python'
42
- },
43
- {
44
- value: 'java',
45
- label: 'Java'
46
- },
47
- {
48
- value: 'c',
49
- label: 'C'
50
- },
51
- {
52
- value: 'cpp',
53
- label: 'C++'
54
- },
55
- {
56
- value: 'csharp',
57
- label: 'C#'
58
- },
59
- {
60
- value: 'go',
61
- label: 'Go'
62
- },
63
- {
64
- value: 'rust',
65
- label: 'Rust'
66
- },
67
- {
68
- value: 'ruby',
69
- label: 'Ruby'
70
- },
71
- {
72
- value: 'php',
73
- label: 'PHP'
74
- },
75
- {
76
- value: 'bash',
77
- label: 'Bash'
78
- },
79
- {
80
- value: 'sql',
81
- label: 'SQL'
82
- },
83
- {
84
- value: 'markdown',
85
- label: 'Markdown'
86
- },
87
- {
88
- value: 'yaml',
89
- label: 'YAML'
90
- },
91
- {
92
- value: 'plaintext',
93
- label: 'Plain Text'
94
- }
95
- ];
96
- const CodeBlock = (props)=>{
97
- const { value: language, onChange, params: { element, Content } } = props;
98
- const handleCopyClick = ()=>{
99
- const text = Array.from(Node.texts(element)).map((nodeEntry)=>nodeEntry[0].text).join('\n');
100
- navigator.clipboard.writeText(text);
101
- };
102
- const menuConfig = useMemo(()=>({
103
- items: languages.map(({ label, value })=>({
104
- render: ()=>/*#__PURE__*/ jsxs(Fragment, {
105
- children: [
106
- /*#__PURE__*/ jsx(Menu.Icon, {
107
- children: value === language && /*#__PURE__*/ jsx(CheckIcon, {
108
- size: 16
109
- })
110
- }),
111
- /*#__PURE__*/ jsx(Menu.Title, {
112
- children: label
113
- })
114
- ]
115
- }),
116
- onSelect: ()=>{
117
- onChange(value);
118
- }
119
- }))
120
- }), [
121
- language
122
- ]);
123
- return /*#__PURE__*/ jsxs("div", {
124
- className: CodeBlock_module.root,
125
- children: [
126
- /*#__PURE__*/ jsxs("div", {
127
- className: CodeBlock_module.menu,
128
- children: [
129
- /*#__PURE__*/ jsx(Dropdown, {
130
- config: menuConfig,
131
- Menu: /*#__PURE__*/ forwardRef((props, ref)=>/*#__PURE__*/ jsx("div", {
132
- ...props,
133
- ref: ref,
134
- className: [
135
- CodeBlock_module.customMenu,
136
- props.className
137
- ].join(' ')
138
- })),
139
- children: ({ ref, onClick })=>/*#__PURE__*/ jsx(Button, {
140
- ref: ref,
141
- size: "sm",
142
- onClick: onClick,
143
- children: languages.find((l)=>l.value === language)?.label || 'Select language'
144
- })
145
- }),
146
- /*#__PURE__*/ jsx(Button, {
147
- size: "sm",
148
- type: "button",
149
- onClick: handleCopyClick,
150
- children: /*#__PURE__*/ jsx(CopyIcon, {
151
- size: 16
152
- })
153
- })
154
- ]
155
- }),
156
- /*#__PURE__*/ jsx("div", {
157
- className: CodeBlock_module.content,
158
- children: /*#__PURE__*/ jsx(Content, {})
159
- })
160
- ]
161
- });
162
- };
163
- export { CodeBlock };