@use-kona/editor 0.1.2 → 0.1.3
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.
- package/README.md +28 -17
- package/dist/examples/Emoji.d.ts +5 -0
- package/dist/examples/Emoji.js +8 -0
- package/dist/examples/EmojiSelector.d.ts +16 -0
- package/dist/examples/EmojiSelector.js +91 -0
- package/dist/examples/EmojiSelector.module.js +7 -0
- package/dist/examples/EmojiSelector_module.css +36 -0
- package/dist/examples/FloatingMenu.d.ts +2 -0
- package/dist/examples/Menu.js +16 -1
- package/dist/examples/getCommands.js +14 -1
- package/dist/examples/getPlugins.d.ts +2 -2
- package/dist/examples/getPlugins.js +18 -1
- package/dist/examples/icons/code.d.ts +2 -0
- package/dist/examples/icons/code.js +30 -0
- package/dist/examples/icons/drag.d.ts +1 -1
- package/dist/examples/store.d.ts +1 -0
- package/dist/examples/store.js +2 -1
- package/dist/examples/text.js +7 -2
- package/dist/plugins/CodeBlockPlugin/CodeBlockPlugin.js +38 -37
- package/dist/plugins/EmojiPlugin/EmojiPlugin.d.ts +28 -0
- package/dist/plugins/EmojiPlugin/EmojiPlugin.js +83 -0
- package/dist/plugins/EmojiPlugin/Menu.d.ts +7 -0
- package/dist/plugins/EmojiPlugin/Menu.js +51 -0
- package/dist/plugins/EmojiPlugin/index.d.ts +1 -0
- package/dist/plugins/EmojiPlugin/index.js +2 -0
- package/dist/plugins/EmojiPlugin/styles.module.js +7 -0
- package/dist/plugins/EmojiPlugin/styles_module.css +11 -0
- package/dist/plugins/EmojiPlugin/types.d.ts +7 -0
- package/dist/plugins/EmojiPlugin/types.js +0 -0
- package/dist/plugins/ListsPlugin/styles_module.css +4 -0
- package/dist/plugins/PlaceholderPlugin/PlaceholderPlugin.js +6 -3
- package/dist/plugins/PlaceholderPlugin/styles.module.js +1 -0
- package/dist/plugins/PlaceholderPlugin/styles_module.css +4 -0
- package/dist/plugins/index.d.ts +1 -0
- package/dist/plugins/index.js +2 -1
- package/package.json +4 -1
- package/src/examples/Emoji.tsx +9 -0
- package/src/examples/EmojiSelector.module.css +35 -0
- package/src/examples/EmojiSelector.tsx +115 -0
- package/src/examples/FloatingMenu.tsx +9 -5
- package/src/examples/Menu.tsx +15 -1
- package/src/examples/getCommands.tsx +17 -1
- package/src/examples/getPlugins.tsx +21 -0
- package/src/examples/icons/code.tsx +21 -0
- package/src/examples/icons/drag.tsx +1 -1
- package/src/examples/store.ts +2 -0
- package/src/examples/text.tsx +5 -0
- package/src/plugins/CodeBlockPlugin/CodeBlockPlugin.tsx +51 -48
- package/src/plugins/EmojiPlugin/EmojiPlugin.tsx +116 -0
- package/src/plugins/EmojiPlugin/Menu.tsx +74 -0
- package/src/plugins/EmojiPlugin/index.ts +1 -0
- package/src/plugins/EmojiPlugin/styles.module.css +10 -0
- package/src/plugins/EmojiPlugin/types.ts +5 -0
- package/src/plugins/ListsPlugin/styles.module.css +4 -0
- package/src/plugins/PlaceholderPlugin/PlaceholderPlugin.tsx +13 -3
- package/src/plugins/PlaceholderPlugin/styles.module.css +2 -2
- package/src/plugins/index.ts +1 -0
package/README.md
CHANGED
|
@@ -1,23 +1,34 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Kona Editor
|
|
2
2
|
|
|
3
|
-
##
|
|
4
|
-
|
|
5
|
-
Install the dependencies:
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
pnpm install
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Get started
|
|
12
|
-
|
|
13
|
-
Build the library:
|
|
3
|
+
## Installing
|
|
14
4
|
|
|
15
5
|
```bash
|
|
16
|
-
|
|
6
|
+
npm install @use-kona/editor
|
|
17
7
|
```
|
|
18
8
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
|
|
9
|
+
## Using
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import {
|
|
13
|
+
KonaEditor,
|
|
14
|
+
BasicFormattingPlugin,
|
|
15
|
+
/* rest of the plugins */
|
|
16
|
+
} from "@use-kona/editor";
|
|
17
|
+
|
|
18
|
+
const defaultValue = [
|
|
19
|
+
{ type: 'paragraph', children: [{ text: '' }]}
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
export const Editor = () => {
|
|
23
|
+
return (
|
|
24
|
+
<KonaEditor
|
|
25
|
+
plugins={[
|
|
26
|
+
new BasicFormattingPlugin(),
|
|
27
|
+
// rest of the plugins
|
|
28
|
+
]}
|
|
29
|
+
initialValue={defaultValue}
|
|
30
|
+
onChange={console.log}
|
|
31
|
+
/>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
23
34
|
```
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
declare module 'react/jsx-runtime' {
|
|
2
|
+
namespace JSX {
|
|
3
|
+
interface IntrinsicElements {
|
|
4
|
+
'em-emoji': {
|
|
5
|
+
id: string;
|
|
6
|
+
size: string | number;
|
|
7
|
+
class?: string;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
type Props = {
|
|
13
|
+
onConfirm: (emoji: any, query: any, editor: any) => void;
|
|
14
|
+
};
|
|
15
|
+
export declare const EmojiSelector: (props: Props) => import("react/jsx-runtime").JSX.Element | null;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import data from "@emoji-mart/data";
|
|
3
|
+
import { useStore } from "@nanostores/react";
|
|
4
|
+
import clsx from "clsx";
|
|
5
|
+
import { SearchIndex, init } from "emoji-mart";
|
|
6
|
+
import { useEffect, useState } from "react";
|
|
7
|
+
import { useSlateStatic } from "slate-react";
|
|
8
|
+
import EmojiSelector_module from "./EmojiSelector.module.js";
|
|
9
|
+
import { $store } from "./store.js";
|
|
10
|
+
init({
|
|
11
|
+
data: data,
|
|
12
|
+
set: 'apple',
|
|
13
|
+
custom: [
|
|
14
|
+
{
|
|
15
|
+
id: 'custom',
|
|
16
|
+
name: 'Custom',
|
|
17
|
+
emojis: [
|
|
18
|
+
{
|
|
19
|
+
id: 'kona',
|
|
20
|
+
name: 'Kona',
|
|
21
|
+
keywords: [
|
|
22
|
+
'kona'
|
|
23
|
+
],
|
|
24
|
+
skins: [
|
|
25
|
+
{
|
|
26
|
+
src: '/kona.svg'
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
});
|
|
34
|
+
const EmojiSelector = (props)=>{
|
|
35
|
+
const { onConfirm } = props;
|
|
36
|
+
const editor = useSlateStatic();
|
|
37
|
+
const { emojiSearch } = useStore($store);
|
|
38
|
+
const [index, setIndex] = useState(-1);
|
|
39
|
+
const [items, setItems] = useState([]);
|
|
40
|
+
useEffect(()=>{
|
|
41
|
+
const search = async ()=>{
|
|
42
|
+
const emojis = await SearchIndex.search(emojiSearch);
|
|
43
|
+
setItems(emojis.slice(0, 10));
|
|
44
|
+
setIndex(0);
|
|
45
|
+
};
|
|
46
|
+
search();
|
|
47
|
+
}, [
|
|
48
|
+
emojiSearch
|
|
49
|
+
]);
|
|
50
|
+
useEffect(()=>{
|
|
51
|
+
const handleKeyDown = (event)=>{
|
|
52
|
+
switch(event.key){
|
|
53
|
+
case 'ArrowRight':
|
|
54
|
+
event.preventDefault();
|
|
55
|
+
setIndex((index)=>(index + 1) % items.length);
|
|
56
|
+
break;
|
|
57
|
+
case 'ArrowLeft':
|
|
58
|
+
event.preventDefault();
|
|
59
|
+
setIndex((index)=>(index - 1 + items.length) % items.length);
|
|
60
|
+
break;
|
|
61
|
+
case 'Enter':
|
|
62
|
+
event.preventDefault();
|
|
63
|
+
onConfirm(items[index]?.id, emojiSearch, editor);
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
document.addEventListener('keydown', handleKeyDown, true);
|
|
68
|
+
return ()=>{
|
|
69
|
+
document.removeEventListener('keydown', handleKeyDown, true);
|
|
70
|
+
};
|
|
71
|
+
}, [
|
|
72
|
+
items,
|
|
73
|
+
index,
|
|
74
|
+
emojiSearch
|
|
75
|
+
]);
|
|
76
|
+
if (!items.length) return null;
|
|
77
|
+
return /*#__PURE__*/ jsx("div", {
|
|
78
|
+
className: EmojiSelector_module.root,
|
|
79
|
+
children: items.map((item, idx)=>/*#__PURE__*/ jsx("span", {
|
|
80
|
+
className: clsx(EmojiSelector_module.emoji, {
|
|
81
|
+
[EmojiSelector_module.selected]: idx === index
|
|
82
|
+
}),
|
|
83
|
+
children: /*#__PURE__*/ jsx("em-emoji", {
|
|
84
|
+
class: EmojiSelector_module.emoji,
|
|
85
|
+
id: item.id,
|
|
86
|
+
size: "20px"
|
|
87
|
+
})
|
|
88
|
+
}, item.id))
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
export { EmojiSelector };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
.root-f7KjwY {
|
|
2
|
+
background-color: var(--kona-editor-background-color);
|
|
3
|
+
border: 1px solid var(--kona-editor-border-color);
|
|
4
|
+
border-radius: 8px;
|
|
5
|
+
gap: 4px;
|
|
6
|
+
padding: 4px;
|
|
7
|
+
display: flex;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.emoji-kNlwVt {
|
|
11
|
+
cursor: pointer;
|
|
12
|
+
vertical-align: text-bottom;
|
|
13
|
+
border-radius: 4px;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
align-items: center;
|
|
16
|
+
width: 24px;
|
|
17
|
+
height: 24px;
|
|
18
|
+
display: inline-flex;
|
|
19
|
+
|
|
20
|
+
& span {
|
|
21
|
+
justify-content: center;
|
|
22
|
+
align-items: center;
|
|
23
|
+
width: 20px;
|
|
24
|
+
height: 20px;
|
|
25
|
+
display: inline-flex;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&:hover {
|
|
29
|
+
background-color: var(--kona-editor-alt-background-color);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.selected-ONnfU2 {
|
|
34
|
+
background-color: var(--kona-editor-alt-background-color);
|
|
35
|
+
}
|
|
36
|
+
|
package/dist/examples/Menu.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { HeadingsPlugin, ListsPlugin } from "../plugins/index.js";
|
|
2
|
+
import { CodeBlockPlugin, HeadingsPlugin, ListsPlugin } from "../plugins/index.js";
|
|
3
|
+
import { CodeIcon } from "./icons/code.js";
|
|
3
4
|
import { Heading1Icon } from "./icons/heading1.js";
|
|
4
5
|
import { Heading2Icon } from "./icons/heading2.js";
|
|
5
6
|
import { Heading3Icon } from "./icons/heading3.js";
|
|
@@ -68,6 +69,20 @@ const Menu = (props)=>{
|
|
|
68
69
|
children: /*#__PURE__*/ jsx(OlIcon, {
|
|
69
70
|
size: 16
|
|
70
71
|
})
|
|
72
|
+
}),
|
|
73
|
+
/*#__PURE__*/ jsx("span", {
|
|
74
|
+
className: Menu_module.divider
|
|
75
|
+
}),
|
|
76
|
+
/*#__PURE__*/ jsx("button", {
|
|
77
|
+
type: "button",
|
|
78
|
+
className: getButtonClassName(CodeBlockPlugin.isCodeBlockActive(editor)),
|
|
79
|
+
onMouseDown: (event)=>{
|
|
80
|
+
event.preventDefault();
|
|
81
|
+
CodeBlockPlugin.toggleCodeBlock(editor);
|
|
82
|
+
},
|
|
83
|
+
children: /*#__PURE__*/ jsx(CodeIcon, {
|
|
84
|
+
size: 16
|
|
85
|
+
})
|
|
71
86
|
})
|
|
72
87
|
]
|
|
73
88
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import { HeadingsPlugin, ListsPlugin } from "../plugins/index.js";
|
|
2
|
+
import { CodeBlockPlugin, HeadingsPlugin, ListsPlugin } from "../plugins/index.js";
|
|
3
|
+
import { CodeIcon } from "./icons/code.js";
|
|
3
4
|
import { Heading1Icon } from "./icons/heading1.js";
|
|
4
5
|
import { Heading2Icon } from "./icons/heading2.js";
|
|
5
6
|
import { Heading3Icon } from "./icons/heading3.js";
|
|
@@ -82,6 +83,18 @@ const getCommands = ()=>[
|
|
|
82
83
|
actions.removeCommand();
|
|
83
84
|
ListsPlugin.toggleList(editor, ListsPlugin.NUMBERED_LIST_ELEMENT, ListsPlugin.LIST_ITEM_ELEMENT);
|
|
84
85
|
}
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'code',
|
|
89
|
+
title: 'Code',
|
|
90
|
+
commandName: 'code',
|
|
91
|
+
icon: /*#__PURE__*/ jsx(CodeIcon, {
|
|
92
|
+
size: 16
|
|
93
|
+
}),
|
|
94
|
+
action: (actions, editor)=>{
|
|
95
|
+
actions.removeCommand();
|
|
96
|
+
CodeBlockPlugin.toggleCodeBlock(editor);
|
|
97
|
+
}
|
|
85
98
|
}
|
|
86
99
|
];
|
|
87
100
|
export { getCommands };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { BasicFormattingPlugin, BreaksPlugin, CodeBlockPlugin, CommandsPlugin, DnDPlugin, FloatingMenuPlugin, HeadingsPlugin, HighlightsPlugin, LinksPlugin, ListsPlugin, MenuPlugin, NodeIdPlugin, PlaceholderPlugin, ShortcutsPlugin, TableOfContentsPlugin } from '../plugins';
|
|
2
|
-
export declare const getPlugins: () => (BasicFormattingPlugin | BreaksPlugin | CodeBlockPlugin | CommandsPlugin | DnDPlugin | FloatingMenuPlugin | HeadingsPlugin | HighlightsPlugin | LinksPlugin | ListsPlugin | MenuPlugin | NodeIdPlugin | PlaceholderPlugin | ShortcutsPlugin | TableOfContentsPlugin)[];
|
|
1
|
+
import { BasicFormattingPlugin, BreaksPlugin, CodeBlockPlugin, CommandsPlugin, DnDPlugin, EmojiPlugin, FloatingMenuPlugin, HeadingsPlugin, HighlightsPlugin, LinksPlugin, ListsPlugin, MenuPlugin, NodeIdPlugin, PlaceholderPlugin, ShortcutsPlugin, TableOfContentsPlugin } from '../plugins';
|
|
2
|
+
export declare const getPlugins: () => (BasicFormattingPlugin | BreaksPlugin | CodeBlockPlugin | CommandsPlugin | DnDPlugin | EmojiPlugin | FloatingMenuPlugin | HeadingsPlugin | HighlightsPlugin | LinksPlugin | ListsPlugin | MenuPlugin | NodeIdPlugin | PlaceholderPlugin | ShortcutsPlugin | TableOfContentsPlugin)[];
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import { BasicFormattingPlugin, BreaksPlugin, CodeBlockPlugin, CommandsPlugin, DnDPlugin, FloatingMenuPlugin, HeadingsPlugin, HighlightsPlugin, LinksPlugin, ListsPlugin, MenuPlugin, NodeIdPlugin, PlaceholderPlugin, ShortcutsPlugin, TableOfContentsPlugin } from "../plugins/index.js";
|
|
2
|
+
import { BasicFormattingPlugin, BreaksPlugin, CodeBlockPlugin, CommandsPlugin, DnDPlugin, EmojiPlugin, FloatingMenuPlugin, HeadingsPlugin, HighlightsPlugin, LinksPlugin, ListsPlugin, MenuPlugin, NodeIdPlugin, PlaceholderPlugin, ShortcutsPlugin, TableOfContentsPlugin } from "../plugins/index.js";
|
|
3
3
|
import { Backdrop } from "./Backdrop.js";
|
|
4
4
|
import { CodeBlock } from "./CodeBlock.js";
|
|
5
5
|
import { colors } from "./colors.js";
|
|
6
6
|
import { DragBlock } from "./DragBlock.js";
|
|
7
|
+
import { Emoji } from "./Emoji.js";
|
|
8
|
+
import { EmojiSelector } from "./EmojiSelector.js";
|
|
7
9
|
import { FloatingMenu } from "./FloatingMenu.js";
|
|
8
10
|
import { getCommands } from "./getCommands.js";
|
|
9
11
|
import { getShortcuts } from "./getShortcuts.js";
|
|
@@ -44,6 +46,21 @@ const getPlugins = ()=>{
|
|
|
44
46
|
});
|
|
45
47
|
return [
|
|
46
48
|
new BasicFormattingPlugin(),
|
|
49
|
+
new EmojiPlugin({
|
|
50
|
+
ignoreNodes: [
|
|
51
|
+
CodeBlockPlugin.CODE_LINE_ELEMENT
|
|
52
|
+
],
|
|
53
|
+
onSearch: (query)=>$store.setKey('emojiSearch', query),
|
|
54
|
+
renderMenu: ({ insertEmoji })=>/*#__PURE__*/ jsx(EmojiSelector, {
|
|
55
|
+
onConfirm: (...params)=>{
|
|
56
|
+
insertEmoji(...params);
|
|
57
|
+
$store.setKey('emojiSearch', '');
|
|
58
|
+
}
|
|
59
|
+
}),
|
|
60
|
+
renderEmoji: (emoji)=>/*#__PURE__*/ jsx(Emoji, {
|
|
61
|
+
id: emoji
|
|
62
|
+
})
|
|
63
|
+
}),
|
|
47
64
|
new PlaceholderPlugin({
|
|
48
65
|
focused: 'Write / to open command menu',
|
|
49
66
|
unfocused: 'Write / to open command menu',
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
const CodeIcon = ({ size })=>/*#__PURE__*/ jsxs("svg", {
|
|
3
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4
|
+
width: size,
|
|
5
|
+
height: size,
|
|
6
|
+
viewBox: "0 0 24 24",
|
|
7
|
+
fill: "none",
|
|
8
|
+
stroke: "currentColor",
|
|
9
|
+
strokeWidth: 1.5,
|
|
10
|
+
strokeLinecap: "round",
|
|
11
|
+
strokeLinejoin: "round",
|
|
12
|
+
className: "icon icon-tabler icons-tabler-outline icon-tabler-code",
|
|
13
|
+
children: [
|
|
14
|
+
/*#__PURE__*/ jsx("path", {
|
|
15
|
+
stroke: "none",
|
|
16
|
+
d: "M0 0h24v24H0z",
|
|
17
|
+
fill: "none"
|
|
18
|
+
}),
|
|
19
|
+
/*#__PURE__*/ jsx("path", {
|
|
20
|
+
d: "M7 8l-4 4l4 4"
|
|
21
|
+
}),
|
|
22
|
+
/*#__PURE__*/ jsx("path", {
|
|
23
|
+
d: "M17 8l4 4l-4 4"
|
|
24
|
+
}),
|
|
25
|
+
/*#__PURE__*/ jsx("path", {
|
|
26
|
+
d: "M14 4l-4 16"
|
|
27
|
+
})
|
|
28
|
+
]
|
|
29
|
+
});
|
|
30
|
+
export { CodeIcon };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { IconProps } from './types';
|
|
1
|
+
import type { IconProps } from './types';
|
|
2
2
|
export declare const DragIcon: ({ size }: IconProps) => import("react/jsx-runtime").JSX.Element;
|
package/dist/examples/store.d.ts
CHANGED
package/dist/examples/store.js
CHANGED
package/dist/examples/text.js
CHANGED
|
@@ -30,6 +30,9 @@ const text_elements = {
|
|
|
30
30
|
},
|
|
31
31
|
hlink: {
|
|
32
32
|
type: LinksPlugin.LINK_TYPE
|
|
33
|
+
},
|
|
34
|
+
hemoji: {
|
|
35
|
+
type: 'emoji'
|
|
33
36
|
}
|
|
34
37
|
};
|
|
35
38
|
const creators = {
|
|
@@ -42,7 +45,9 @@ const jsx = createHyperscript({
|
|
|
42
45
|
const text_text = /*#__PURE__*/ jsx("fragment", null, /*#__PURE__*/ jsx("heading1", null, "About"), /*#__PURE__*/ jsx("paragraph", null, /*#__PURE__*/ jsx("htext", {
|
|
43
46
|
bold: true,
|
|
44
47
|
italic: true
|
|
45
|
-
}, "Kona Editor"), ' ', "is a text editor based on Slate.js that I use in", ' ', /*#__PURE__*/ jsx("
|
|
48
|
+
}, "Kona Editor"), ' ', "is a text editor based on Slate.js that I use in", ' ', /*#__PURE__*/ jsx("hemoji", {
|
|
49
|
+
emoji: "kona"
|
|
50
|
+
}, "'"), /*#__PURE__*/ jsx("hlink", {
|
|
46
51
|
url: "https://kona.to"
|
|
47
52
|
}, "Kona calendar"), " for notes and event descriptions. I decided to open-source the editor for a few reasons:"), /*#__PURE__*/ jsx("numberedList", null, /*#__PURE__*/ jsx("listItem", null, "I had a lot of ", /*#__PURE__*/ jsx("htext", {
|
|
48
53
|
strikethrough: true
|
|
@@ -56,5 +61,5 @@ const text_text = /*#__PURE__*/ jsx("fragment", null, /*#__PURE__*/ jsx("heading
|
|
|
56
61
|
underline: true
|
|
57
62
|
}, "underlined"), " and", ' ', /*#__PURE__*/ jsx("htext", {
|
|
58
63
|
strikethrough: true
|
|
59
|
-
}, "strikethrough"), " text"), /*#__PURE__*/ jsx("heading3", null, "BreaksPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Overrides default Slate behavior by breaking custom block types when user presses Enter."), /*#__PURE__*/ jsx("heading3", null, "CodeBlockPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Adds support for code blocks."), /*#__PURE__*/ jsx("heading3", null, "CommandsPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Adds Notion-style menu with custom list of commands"), /*#__PURE__*/ jsx("heading3", null, "DnDPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Allows reordering blocks by drag'n'dropping them"), /*#__PURE__*/ jsx("heading3", null, "FloatingMenuPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Adds menu which is shown when user selects a text"), /*#__PURE__*/ jsx("heading3", null, "HeadingsPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Adds three levels of headings"), /*#__PURE__*/ jsx("heading3", null, "HighlightsPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Allows highlighting selected text with a custom color"), /*#__PURE__*/ jsx("heading3", null, "LinksPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Gives user ability to convert the selected text into a link"), /*#__PURE__*/ jsx("heading3", null, "MenuPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Adds pinned to the top menu with custom commands"), /*#__PURE__*/ jsx("heading3", null, "NodeIdPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Assigns a unique id to each block"), /*#__PURE__*/ jsx("heading3", null, "PlaceholderPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Allows to setup a custom placeholder for the selected line"), /*#__PURE__*/ jsx("heading3", null, "ShortcutsPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Converts some popular markdown shortcuts to a custom node"), /*#__PURE__*/ jsx("heading3", null, "TableOfContentsPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Shows a quick map of headings inside the document"));
|
|
64
|
+
}, "strikethrough"), " text"), /*#__PURE__*/ jsx("heading3", null, "BreaksPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Overrides default Slate behavior by breaking custom block types when user presses Enter."), /*#__PURE__*/ jsx("heading3", null, "CodeBlockPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Adds support for code blocks."), /*#__PURE__*/ jsx("heading3", null, "CommandsPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Adds Notion-style menu with custom list of commands"), /*#__PURE__*/ jsx("heading3", null, "DnDPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Allows reordering blocks by drag'n'dropping them"), /*#__PURE__*/ jsx("heading3", null, "FloatingMenuPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Adds menu which is shown when user selects a text"), /*#__PURE__*/ jsx("heading3", null, "HeadingsPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Adds three levels of headings"), /*#__PURE__*/ jsx("heading3", null, "HighlightsPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Allows highlighting selected text with a custom color"), /*#__PURE__*/ jsx("heading3", null, "LinksPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Gives user ability to convert the selected text into a link"), /*#__PURE__*/ jsx("heading3", null, "MenuPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Adds pinned to the top menu with custom commands"), /*#__PURE__*/ jsx("heading3", null, "NodeIdPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Assigns a unique id to each block"), /*#__PURE__*/ jsx("heading3", null, "PlaceholderPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Allows to setup a custom placeholder for the selected line"), /*#__PURE__*/ jsx("heading3", null, "ShortcutsPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Converts some popular markdown shortcuts to a custom node"), /*#__PURE__*/ jsx("heading3", null, "TableOfContentsPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Shows a quick map of headings inside the document"), /*#__PURE__*/ jsx("heading3", null, "EmojiPlugin"), /*#__PURE__*/ jsx("paragraph", null, "Allows paste emoji to the text"));
|
|
60
65
|
export { text_text as text };
|
|
@@ -185,44 +185,45 @@ class CodeBlockPlugin {
|
|
|
185
185
|
return !!match;
|
|
186
186
|
}
|
|
187
187
|
static toggleCodeBlock = (editor)=>{
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
});
|
|
193
|
-
if (node) {
|
|
194
|
-
Transforms.setNodes(editor, {
|
|
195
|
-
type: 'paragraph'
|
|
196
|
-
}, {
|
|
197
|
-
at: node[1],
|
|
198
|
-
match: (n)=>n.type === CodeBlockPlugin.CODE_LINE_ELEMENT,
|
|
199
|
-
mode: 'lowest'
|
|
200
|
-
});
|
|
201
|
-
Transforms.unwrapNodes(editor, {
|
|
202
|
-
at: node[1],
|
|
203
|
-
match: (n)=>n.type === CodeBlockPlugin.CODE_ELEMENT,
|
|
204
|
-
split: true
|
|
205
|
-
});
|
|
206
|
-
} else {
|
|
207
|
-
Transforms.setNodes(editor, {
|
|
208
|
-
type: CodeBlockPlugin.CODE_LINE_ELEMENT,
|
|
209
|
-
children: [
|
|
210
|
-
{
|
|
211
|
-
text: ''
|
|
212
|
-
}
|
|
213
|
-
]
|
|
214
|
-
}, {
|
|
215
|
-
match: (n)=>Editor.isBlock(editor, n) && 'paragraph' === n.type
|
|
216
|
-
});
|
|
217
|
-
Transforms.wrapNodes(editor, {
|
|
218
|
-
type: CodeBlockPlugin.CODE_ELEMENT,
|
|
219
|
-
language: "javascript",
|
|
220
|
-
children: []
|
|
221
|
-
}, {
|
|
222
|
-
match: (n)=>n.type === CodeBlockPlugin.CODE_LINE_ELEMENT
|
|
223
|
-
});
|
|
224
|
-
}
|
|
188
|
+
if (!editor.selection) return;
|
|
189
|
+
const node = Editor.above(editor, {
|
|
190
|
+
match: (n)=>!Editor.isEditor(n) && n.type === CodeBlockPlugin.CODE_ELEMENT,
|
|
191
|
+
mode: 'highest'
|
|
225
192
|
});
|
|
193
|
+
if (node) {
|
|
194
|
+
Transforms.setNodes(editor, {
|
|
195
|
+
type: 'paragraph'
|
|
196
|
+
}, {
|
|
197
|
+
at: node[1],
|
|
198
|
+
match: (n)=>n.type === CodeBlockPlugin.CODE_LINE_ELEMENT,
|
|
199
|
+
mode: 'lowest'
|
|
200
|
+
});
|
|
201
|
+
Transforms.unwrapNodes(editor, {
|
|
202
|
+
at: node[1],
|
|
203
|
+
match: (n)=>n.type === CodeBlockPlugin.CODE_ELEMENT,
|
|
204
|
+
split: true
|
|
205
|
+
});
|
|
206
|
+
} else {
|
|
207
|
+
Transforms.setNodes(editor, {
|
|
208
|
+
type: CodeBlockPlugin.CODE_LINE_ELEMENT,
|
|
209
|
+
children: [
|
|
210
|
+
{
|
|
211
|
+
text: ''
|
|
212
|
+
}
|
|
213
|
+
]
|
|
214
|
+
}, {
|
|
215
|
+
mode: 'lowest'
|
|
216
|
+
});
|
|
217
|
+
Transforms.wrapNodes(editor, {
|
|
218
|
+
type: CodeBlockPlugin.CODE_ELEMENT,
|
|
219
|
+
language: "javascript",
|
|
220
|
+
children: []
|
|
221
|
+
}, {
|
|
222
|
+
mode: 'highest',
|
|
223
|
+
match: (n)=>n.type === CodeBlockPlugin.CODE_LINE_ELEMENT,
|
|
224
|
+
at: editor.selection.focus
|
|
225
|
+
});
|
|
226
|
+
}
|
|
226
227
|
};
|
|
227
228
|
}
|
|
228
229
|
export { CodeBlockPlugin };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type MapStore } from 'nanostores';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
import { Editor } from 'slate';
|
|
4
|
+
import type { IPlugin } from '../../types';
|
|
5
|
+
type Options = {
|
|
6
|
+
onSearch: (query: string) => void;
|
|
7
|
+
renderMenu: (actions: {
|
|
8
|
+
insertEmoji: (emoji: string, query: string, editor: Editor) => void;
|
|
9
|
+
}) => ReactNode;
|
|
10
|
+
renderEmoji: (emoji: string) => ReactNode;
|
|
11
|
+
ignoreNodes?: string[];
|
|
12
|
+
};
|
|
13
|
+
export declare class EmojiPlugin implements IPlugin {
|
|
14
|
+
options: Options;
|
|
15
|
+
$store: MapStore<{
|
|
16
|
+
isOpen: boolean;
|
|
17
|
+
}>;
|
|
18
|
+
constructor(options: Options);
|
|
19
|
+
blocks: {
|
|
20
|
+
isInline: boolean;
|
|
21
|
+
isVoid: boolean;
|
|
22
|
+
type: string;
|
|
23
|
+
render: (props: any) => import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
}[];
|
|
25
|
+
init(editor: any): any;
|
|
26
|
+
ui(): import("react/jsx-runtime").JSX.Element | null;
|
|
27
|
+
}
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useStore } from "@nanostores/react";
|
|
3
|
+
import { map } from "nanostores";
|
|
4
|
+
import { Editor, Node, Transforms } from "slate";
|
|
5
|
+
import { Menu } from "./Menu.js";
|
|
6
|
+
import styles_module from "./styles.module.js";
|
|
7
|
+
class EmojiPlugin {
|
|
8
|
+
options;
|
|
9
|
+
$store;
|
|
10
|
+
constructor(options){
|
|
11
|
+
this.options = options;
|
|
12
|
+
this.$store = map({
|
|
13
|
+
isOpen: false
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
blocks = [
|
|
17
|
+
{
|
|
18
|
+
isInline: true,
|
|
19
|
+
isVoid: true,
|
|
20
|
+
type: 'emoji',
|
|
21
|
+
render: (props)=>{
|
|
22
|
+
const children = this.options.renderEmoji(props.element.emoji);
|
|
23
|
+
return /*#__PURE__*/ jsx("span", {
|
|
24
|
+
...props.attributes,
|
|
25
|
+
className: styles_module.emojiRoot,
|
|
26
|
+
children: children
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
];
|
|
31
|
+
init(editor) {
|
|
32
|
+
const { insertText, onChange } = editor;
|
|
33
|
+
editor.insertText = (text)=>{
|
|
34
|
+
if (':' === text) this.$store.setKey('isOpen', true);
|
|
35
|
+
insertText(text);
|
|
36
|
+
};
|
|
37
|
+
editor.onChange = (...args)=>{
|
|
38
|
+
if (this.$store.get().isOpen) {
|
|
39
|
+
const query = /:([^:]*$)/.exec(getCurrentText(editor));
|
|
40
|
+
if (query?.[0]) this.options.onSearch(query[1]);
|
|
41
|
+
else this.$store.setKey('isOpen', false);
|
|
42
|
+
}
|
|
43
|
+
return onChange(...args);
|
|
44
|
+
};
|
|
45
|
+
return editor;
|
|
46
|
+
}
|
|
47
|
+
ui() {
|
|
48
|
+
const { isOpen } = useStore(this.$store);
|
|
49
|
+
if (!isOpen) return null;
|
|
50
|
+
return /*#__PURE__*/ jsx(Menu, {
|
|
51
|
+
isOpen: isOpen,
|
|
52
|
+
children: this.options.renderMenu({
|
|
53
|
+
insertEmoji: (emoji, query, editor)=>{
|
|
54
|
+
this.$store.setKey('isOpen', false);
|
|
55
|
+
Transforms["delete"](editor, {
|
|
56
|
+
at: editor.selection?.focus,
|
|
57
|
+
distance: query.length + 1,
|
|
58
|
+
reverse: true,
|
|
59
|
+
unit: 'character'
|
|
60
|
+
});
|
|
61
|
+
Transforms.insertNodes(editor, {
|
|
62
|
+
type: 'emoji',
|
|
63
|
+
emoji,
|
|
64
|
+
children: [
|
|
65
|
+
{
|
|
66
|
+
text: ''
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
});
|
|
70
|
+
Transforms.move(editor);
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const getCurrentText = (editor)=>{
|
|
77
|
+
const entry = Editor.above(editor, {
|
|
78
|
+
match: (n)=>Editor.isBlock(editor, n)
|
|
79
|
+
});
|
|
80
|
+
if (entry) return Node.string(entry[0]);
|
|
81
|
+
return '';
|
|
82
|
+
};
|
|
83
|
+
export { EmojiPlugin };
|