@bigbinary/neeto-editor 0.2.1 → 0.2.5

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 (78) hide show
  1. package/index.js +9 -9
  2. package/package.json +2 -3
  3. package/tailwind.config.js +13 -9
  4. package/webpack.config.js +5 -3
  5. package/webpack.dev.config.js +5 -3
  6. package/public/favicon.ico +0 -0
  7. package/public/index.html +0 -28
  8. package/public/robots.txt +0 -3
  9. package/src/App.js +0 -8
  10. package/src/Common/Avatar.js +0 -168
  11. package/src/Common/Button.js +0 -95
  12. package/src/Common/CodeBlock.js +0 -11
  13. package/src/Common/Description.js +0 -8
  14. package/src/Common/Dropdown/index.js +0 -122
  15. package/src/Common/Heading.js +0 -13
  16. package/src/Common/HighlightText.js +0 -7
  17. package/src/Common/Icons/HashtagFilled.js +0 -59
  18. package/src/Common/Icons/TextColor.js +0 -35
  19. package/src/Common/Icons/index.js +0 -2
  20. package/src/Common/Input.js +0 -70
  21. package/src/Common/Label.js +0 -45
  22. package/src/Common/ListItems.js +0 -17
  23. package/src/Common/Modal.js +0 -91
  24. package/src/Common/Tab.js +0 -79
  25. package/src/Common/ToolTip.js +0 -37
  26. package/src/Editor/CustomExtensions/BubbleMenu/index.js +0 -92
  27. package/src/Editor/CustomExtensions/CodeBlock/CodeBlockComponent.js +0 -12
  28. package/src/Editor/CustomExtensions/CodeBlock/ExtensionConfig.js +0 -10
  29. package/src/Editor/CustomExtensions/Embeds.js +0 -72
  30. package/src/Editor/CustomExtensions/FixedMenu/FontSizeOption.js +0 -32
  31. package/src/Editor/CustomExtensions/FixedMenu/TextColorOption.js +0 -29
  32. package/src/Editor/CustomExtensions/FixedMenu/constants.js +0 -3
  33. package/src/Editor/CustomExtensions/FixedMenu/index.js +0 -183
  34. package/src/Editor/CustomExtensions/Image/ExtensionConfig.js +0 -47
  35. package/src/Editor/CustomExtensions/Image/LinkUploader/URLForm.js +0 -39
  36. package/src/Editor/CustomExtensions/Image/LocalUploader.js +0 -21
  37. package/src/Editor/CustomExtensions/Image/ProgressBar.js +0 -34
  38. package/src/Editor/CustomExtensions/Image/Uploader.js +0 -82
  39. package/src/Editor/CustomExtensions/Image/constants.js +0 -5
  40. package/src/Editor/CustomExtensions/Mention/ExtensionConfig.js +0 -66
  41. package/src/Editor/CustomExtensions/Mention/MentionList.js +0 -96
  42. package/src/Editor/CustomExtensions/Mention/helpers.js +0 -23
  43. package/src/Editor/CustomExtensions/Placeholder/ExtensionConfig.js +0 -81
  44. package/src/Editor/CustomExtensions/Placeholder/helpers.js +0 -18
  45. package/src/Editor/CustomExtensions/SlashCommands/Commands.js +0 -20
  46. package/src/Editor/CustomExtensions/SlashCommands/CommandsList.js +0 -109
  47. package/src/Editor/CustomExtensions/SlashCommands/ExtensionConfig.js +0 -209
  48. package/src/Editor/CustomExtensions/Variable/ExtensionConfig.js +0 -208
  49. package/src/Editor/CustomExtensions/Variable/VariableList.js +0 -45
  50. package/src/Editor/CustomExtensions/Variable/VariableSuggestion.js +0 -20
  51. package/src/Editor/CustomExtensions/Variable/helpers.js +0 -31
  52. package/src/Editor/CustomExtensions/Variable/index.js +0 -35
  53. package/src/Editor/CustomExtensions/useCustomExtensions.js +0 -88
  54. package/src/Editor/index.js +0 -104
  55. package/src/Editor/sharedState.js +0 -8
  56. package/src/constants/regexp.js +0 -1
  57. package/src/examples/constants.js +0 -95
  58. package/src/examples/index.js +0 -186
  59. package/src/hooks/useOutsideClick.js +0 -19
  60. package/src/hooks/useTabBar.js +0 -9
  61. package/src/index.js +0 -10
  62. package/src/index.scss +0 -46
  63. package/src/styles/abstracts/_mixins.scss +0 -20
  64. package/src/styles/abstracts/_neeto-ui-variables.scss +0 -107
  65. package/src/styles/abstracts/_variables.scss +0 -13
  66. package/src/styles/components/_avatar.scss +0 -105
  67. package/src/styles/components/_button.scss +0 -161
  68. package/src/styles/components/_codeblock.scss +0 -16
  69. package/src/styles/components/_command-list.scss +0 -19
  70. package/src/styles/components/_dropdown.scss +0 -69
  71. package/src/styles/components/_editor-variables.scss +0 -12
  72. package/src/styles/components/_editor.scss +0 -102
  73. package/src/styles/components/_fixed-menu.scss +0 -17
  74. package/src/styles/components/_image-uploader.scss +0 -109
  75. package/src/styles/components/_input.scss +0 -165
  76. package/src/styles/components/_tab.scss +0 -74
  77. package/src/styles/components/_tooltip.scss +0 -152
  78. package/src/utils/common.js +0 -13
@@ -1,183 +0,0 @@
1
- import React from "react";
2
- import {
3
- TextBold,
4
- TextItalic,
5
- Underline,
6
- TextCross,
7
- Link,
8
- Code,
9
- ListDot,
10
- ListNumber,
11
- Image,
12
- Quote,
13
- Undo,
14
- Redo,
15
- } from "@bigbinary/neeto-icons";
16
-
17
- import TextColorOption from "./TextColorOption";
18
- import FontSizeOption from "./FontSizeOption";
19
-
20
- import { ICON_COLOR_ACTIVE, ICON_COLOR_INACTIVE } from "./constants";
21
- import Variables from "../Variable";
22
-
23
- const FixedMenu = ({ editor, variables, setImageUploadVisible }) => {
24
- if (!editor) {
25
- return null;
26
- }
27
-
28
- const fontStyleOptions = [
29
- {
30
- Icon: TextBold,
31
- command: () => editor.chain().focus().toggleBold().run(),
32
- active: editor.isActive("bold"),
33
- optionName: "bold",
34
- },
35
- {
36
- Icon: TextItalic,
37
- command: () => editor.chain().focus().toggleItalic().run(),
38
- active: editor.isActive("italic"),
39
- optionName: "italic",
40
- },
41
- {
42
- Icon: Underline,
43
- command: () => editor.chain().focus().toggleUnderline().run(),
44
- active: editor.isActive("underline"),
45
- optionName: "underline",
46
- size: 27,
47
- },
48
- {
49
- Icon: TextCross,
50
- command: () => editor.chain().focus().toggleStrike().run(),
51
- active: editor.isActive("strike"),
52
- optionName: "strike",
53
- },
54
- ];
55
-
56
- const blockStyleOptions = [
57
- {
58
- Icon: Link,
59
- command: () => {
60
- if (editor.isActive("link")) {
61
- editor.chain().focus().unsetLink().run();
62
- } else {
63
- const url = window.prompt("Please enter your URL");
64
- editor.chain().focus().setLink({ href: url }).run();
65
- }
66
- },
67
- active: editor.isActive("link"),
68
- optionName: "link",
69
- },
70
- {
71
- Icon: Quote,
72
- command: () => editor.chain().focus().toggleBlockquote().run(),
73
- active: editor.isActive("blockquote"),
74
- optionName: "block-quote",
75
- },
76
- {
77
- Icon: Code,
78
- command: () => editor.chain().focus().toggleCode().run(),
79
- active: editor.isActive("code"),
80
- optionName: "code",
81
- },
82
- {
83
- Icon: Image,
84
- command: () => setImageUploadVisible(true),
85
- optionName: "image-upload",
86
- },
87
- ];
88
-
89
- const listStyleOptions = [
90
- {
91
- Icon: ListDot,
92
- command: () => editor.chain().focus().toggleBulletList().run(),
93
- active: editor.isActive("bulletList"),
94
- optionName: "bullet-list",
95
- },
96
- {
97
- Icon: ListNumber,
98
- command: () => editor.chain().focus().toggleOrderedList().run(),
99
- active: editor.isActive("orderedList"),
100
- optionName: "ordered-list",
101
- },
102
- ];
103
-
104
- const editorOptions = [
105
- {
106
- Icon: Undo,
107
- command: () => editor.chain().focus().undo().run(),
108
- optionName: "undo",
109
- disabled: !editor.can().undo(),
110
- active: editor.can().undo(),
111
- },
112
- {
113
- Icon: Redo,
114
- command: () => editor.chain().focus().redo().run(),
115
- optionName: "redo",
116
- disabled: !editor.can().redo(),
117
- active: editor.can().redo(),
118
- },
119
- ];
120
-
121
- const handleTextSizeChange = (value) => {
122
- switch (value) {
123
- case "large": {
124
- editor.chain().focus().setHeading({ level: 2 }).run();
125
- break;
126
- }
127
- case "medium": {
128
- editor.chain().focus().setHeading({ level: 3 }).run();
129
- break;
130
- }
131
- case "normal": {
132
- editor.chain().focus().setParagraph().run();
133
- break;
134
- }
135
- }
136
- };
137
-
138
- const renderOptionButton = ({
139
- Icon,
140
- command,
141
- active,
142
- optionName,
143
- disabled,
144
- ...rest
145
- }) => (
146
- <button
147
- disabled={disabled}
148
- onClick={command}
149
- key={optionName}
150
- className="p-3 transition-colors cursor-pointer editor-fixed-menu--item"
151
- >
152
- <Icon
153
- color={active ? ICON_COLOR_ACTIVE : ICON_COLOR_INACTIVE}
154
- {...rest}
155
- />
156
- </button>
157
- );
158
-
159
- return (
160
- <div className="flex space-x-6 border-t border-l border-r editor-fixed-menu--root">
161
- <div className="flex">
162
- <TextColorOption
163
- color={editor.getAttributes("textStyle").color}
164
- onChange={(color) => editor.chain().focus().setColor(color).run()}
165
- />
166
- <FontSizeOption onChange={handleTextSizeChange} />
167
- {fontStyleOptions.map(renderOptionButton)}
168
- </div>
169
- {[blockStyleOptions, listStyleOptions, editorOptions].map(
170
- (optionGroup, index) => (
171
- <div className="flex" key={index}>
172
- {optionGroup.map(renderOptionButton)}
173
- </div>
174
- )
175
- )}
176
- <div className="flex justify-end flex-1">
177
- <Variables editor={editor} variables={variables} />
178
- </div>
179
- </div>
180
- );
181
- };
182
-
183
- export default FixedMenu;
@@ -1,47 +0,0 @@
1
- import Image from "@tiptap/extension-image";
2
- import { mergeAttributes } from "@tiptap/core";
3
-
4
- export default Image.extend({
5
- name: "image",
6
-
7
- addAttributes() {
8
- return {
9
- ...Image.config.addAttributes(),
10
- size: {
11
- default: "small",
12
- rendered: false,
13
- },
14
- float: {
15
- default: "none",
16
- rendered: false,
17
- },
18
- };
19
- },
20
-
21
- addCommands() {
22
- return {
23
- setImage:
24
- (options) =>
25
- ({ tr, commands }) => {
26
- if (tr.selection?.node?.type?.name == "image") {
27
- return commands.updateAttributes("image", options);
28
- } else {
29
- return commands.insertContent({
30
- type: this.name,
31
- attrs: options,
32
- });
33
- }
34
- },
35
- };
36
- },
37
-
38
- renderHTML({ node, HTMLAttributes }) {
39
- HTMLAttributes.class = " image-" + node.attrs.size;
40
- HTMLAttributes.class += " image-float-" + node.attrs.float;
41
-
42
- return [
43
- "img",
44
- mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
45
- ];
46
- },
47
- });
@@ -1,39 +0,0 @@
1
- import React, { useState } from "react";
2
-
3
- import Input from "common/Input";
4
- import Button from "common/Button";
5
-
6
- import { UrlRegExp } from "../../../../constants/regexp";
7
-
8
- const URLField = ({ onSubmit }) => {
9
- const [urlString, setUrlString] = useState("");
10
- const [error, setError] = useState("");
11
-
12
- return (
13
- <form
14
- onSubmit={(e) => {
15
- e.preventDefault();
16
- if (UrlRegExp.test(urlString)) {
17
- onSubmit(urlString);
18
- } else {
19
- setError("Please provide a valid image url");
20
- }
21
- }}
22
- className="flex flex-col items-center justify-center flex-1 mx-10"
23
- >
24
- <div className="flex-row w-full mb-4">
25
- <Input
26
- name="url"
27
- value={urlString}
28
- placeholder="Paste the image link"
29
- onFocus={() => setError("")}
30
- error={error}
31
- onChange={({ target: { value } }) => setUrlString(value)}
32
- />
33
- </div>
34
- <Button type="submit" label="Upload Image" />
35
- </form>
36
- );
37
- };
38
-
39
- export default URLField;
@@ -1,21 +0,0 @@
1
- import React from "react";
2
-
3
- import { DragDrop } from "@uppy/react";
4
-
5
- const LocalUploader = ({ uppy }) => {
6
- return (
7
- <DragDrop
8
- note="Max. File Size: 5MB"
9
- uppy={uppy}
10
- locale={{
11
- strings: {
12
- dropHereOr: "Drop your file(s) here or %{browse}",
13
- browse: "Browse",
14
- },
15
- }}
16
- className="local-upload__root"
17
- />
18
- );
19
- };
20
-
21
- export default LocalUploader;
@@ -1,34 +0,0 @@
1
- import React, { useState, useEffect } from "react";
2
-
3
- import { Close } from "@bigbinary/neeto-icons";
4
-
5
- const ProgressBar = ({ uppy }) => {
6
- const [progress, setProgress] = useState(0);
7
-
8
- useEffect(() => {
9
- uppy.on("progress", setProgress);
10
- }, [uppy]);
11
-
12
- const progressPercentage = `${progress}%`;
13
-
14
- return (
15
- <div className="progress-bar__root">
16
- <div className="flex items-center justify-between">
17
- <span className="progress-bar__percent-text">{progressPercentage}</span>
18
- <button onClick={uppy.cancelAll}>
19
- <Close size={16} />
20
- </button>
21
- </div>
22
- <div className="progress-bar__indicator">
23
- <div className="flex h-full">
24
- <div
25
- style={{ width: progressPercentage }}
26
- className="flex flex-col justify-center text-center text-white shadow-none whitespace-nowrap progress-bar__indicator-inner"
27
- ></div>
28
- </div>
29
- </div>
30
- </div>
31
- );
32
- };
33
-
34
- export default ProgressBar;
@@ -1,82 +0,0 @@
1
- import React, { useState, useMemo } from "react";
2
- import { view } from "@risingstack/react-easy-state";
3
- import Uppy from "@uppy/core";
4
- import XHRUpload from "@uppy/xhr-upload";
5
- import Modal from "common/Modal";
6
- import Tab from "common/Tab";
7
- import useTabBar from "hooks/useTabBar";
8
-
9
- import LocalUploader from "./LocalUploader";
10
- import ProgressBar from "./ProgressBar";
11
-
12
- import URLForm from "./LinkUploader/URLForm";
13
-
14
- import { IMAGE_UPLOAD_OPTIONS } from "./constants";
15
-
16
- const ImageUpload = ({ editor, imageUploadUrl, isVisible, setIsVisible }) => {
17
- const [isUploading, setIsUploading] = useState(false);
18
- const [activeTab, setActiveTab] = useTabBar(IMAGE_UPLOAD_OPTIONS);
19
-
20
- const uppy = useMemo(
21
- () =>
22
- new Uppy({
23
- allowMultipleUploads: false,
24
- autoProceed: true,
25
- debug: true,
26
- })
27
- .use(XHRUpload, {
28
- endpoint: imageUploadUrl || "/api/v1/direct_uploads",
29
- formData: true,
30
- fieldName: "blob",
31
- })
32
- .on("upload", () => setIsUploading(true))
33
- .on("upload-success", (file, response) => {
34
- const url = response.body.imageURL;
35
- editor.chain().focus().setImage({ src: url }).run();
36
- setIsVisible(false);
37
- })
38
- .on("cancel-all", () => setIsUploading(false))
39
- .on("complete", () => setIsUploading(false)),
40
- [editor]
41
- );
42
-
43
- const handleUrlFormSubmit = (url) => {
44
- editor.chain().focus().setImage({ src: url }).run();
45
- setIsVisible(false);
46
- };
47
-
48
- return (
49
- <Modal isVisible={isVisible} onClose={() => setIsVisible(false)}>
50
- <div className="image-uploader__root">
51
- <Tab>
52
- {IMAGE_UPLOAD_OPTIONS.map((option) => (
53
- <Tab.Item
54
- active={activeTab === option.key}
55
- onClick={() => setActiveTab(option)}
56
- >
57
- {option.title}
58
- </Tab.Item>
59
- ))}
60
- </Tab>
61
-
62
- <div className="image-uploader__content">
63
- {isUploading ? (
64
- <div className="flex flex-col items-center justify-center flex-1 text-center">
65
- <span className="label--primary">Uploading...</span>
66
- <span className="label--secondary">
67
- {uppy.getFiles()[0]?.name}
68
- </span>
69
- <ProgressBar uppy={uppy} />
70
- </div>
71
- ) : activeTab === "local" ? (
72
- <LocalUploader uppy={uppy} />
73
- ) : activeTab === "link" ? (
74
- <URLForm onSubmit={handleUrlFormSubmit} />
75
- ) : null}
76
- </div>
77
- </div>
78
- </Modal>
79
- );
80
- };
81
-
82
- export default view(ImageUpload);
@@ -1,5 +0,0 @@
1
- export const IMAGE_UPLOAD_OPTIONS = [
2
- { title: "Upload", key: "local" },
3
- { title: "Link", key: "link" },
4
- { title: "Unsplash", key: "unsplash" },
5
- ];
@@ -1,66 +0,0 @@
1
- import Mention from "@tiptap/extension-mention";
2
- import tippy from "tippy.js";
3
- import { ReactRenderer } from "@tiptap/react";
4
-
5
- import { MentionList } from "./MentionList";
6
-
7
- import { createMentionSuggestions } from "./helpers";
8
-
9
- const suggestion = {
10
- render: () => {
11
- let reactRenderer;
12
- let popup;
13
-
14
- return {
15
- onStart: (props) => {
16
- reactRenderer = new ReactRenderer(MentionList, {
17
- props,
18
- editor: props.editor,
19
- });
20
-
21
- popup = tippy("body", {
22
- getReferenceClientRect: props.clientRect,
23
- appendTo: () => document.body,
24
- content: reactRenderer.element,
25
- showOnCreate: true,
26
- interactive: true,
27
- trigger: "manual",
28
- placement: "bottom-start",
29
- });
30
- },
31
-
32
- onUpdate(props) {
33
- reactRenderer.updateProps(props);
34
-
35
- popup[0].setProps({
36
- getReferenceClientRect: props.clientRect,
37
- });
38
- },
39
-
40
- onKeyDown(props) {
41
- if (props.event.key === "Escape") {
42
- popup[0].hide();
43
-
44
- return true;
45
- }
46
-
47
- return reactRenderer.ref?.onKeyDown(props);
48
- },
49
-
50
- onExit() {
51
- popup[0].destroy();
52
- reactRenderer.destroy();
53
- },
54
- };
55
- },
56
- };
57
-
58
- export default {
59
- configure: ({ suggestion: suggestionConfig = {}, ...otherConfig }) =>
60
- Mention.configure({
61
- ...otherConfig,
62
- suggestion: { ...suggestion, ...suggestionConfig },
63
- }),
64
- };
65
-
66
- export { createMentionSuggestions };
@@ -1,96 +0,0 @@
1
- import React from "react";
2
- import classNames from "classnames";
3
-
4
- import Avatar from "common/Avatar";
5
-
6
- export class MentionList extends React.Component {
7
- state = { selectedIndex: 0 };
8
-
9
- componentDidUpdate(prevProps) {
10
- const { items } = this.props;
11
- if (items !== prevProps.items) {
12
- this.setState({ selectedIndex: 0 });
13
- }
14
- }
15
-
16
- selectItem = (index) => {
17
- const { items, command } = this.props;
18
- const item = items[index];
19
-
20
- if (item) {
21
- command({ label: item.label, id: item.key });
22
- }
23
- };
24
-
25
- upHandler = () => {
26
- const { items } = this.props;
27
- this.setState((prevState) => {
28
- const { selectedIndex } = prevState;
29
- const nextSelectedIndex =
30
- (selectedIndex + items.length - 1) % items.length;
31
- return {
32
- selectedIndex: nextSelectedIndex,
33
- };
34
- });
35
- };
36
-
37
- downHandler = () => {
38
- const { items } = this.props;
39
- this.setState((prevState) => {
40
- const { selectedIndex } = prevState;
41
- const nextSelectedIndex = (selectedIndex + 1) % items.length;
42
- return {
43
- selectedIndex: nextSelectedIndex,
44
- };
45
- });
46
- };
47
-
48
- enterHandler = () => {
49
- const { selectedIndex } = this.state;
50
- this.selectItem(selectedIndex);
51
- };
52
-
53
- onKeyDown = ({ event }) => {
54
- const keyDownHandlers = {
55
- ArrowUp: this.upHandler,
56
- ArrowDown: this.downHandler,
57
- Enter: this.enterHandler,
58
- };
59
-
60
- if (keyDownHandlers.hasOwnProperty(event.key)) {
61
- keyDownHandlers[event.key]();
62
- return true;
63
- }
64
-
65
- return false;
66
- };
67
-
68
- render() {
69
- const { selectedIndex } = this.state;
70
- const { items } = this.props;
71
-
72
- const containerClassName =
73
- "relative p-2 space-y-1 overflow-hidden rounded shadow editor-command-list--root";
74
- const itemClassName =
75
- "flex items-center w-full px-4 py-2 transition-all duration-100 ease-in-out cursor-pointer text-xs text-white rounded editor-command-list--item";
76
-
77
- return (
78
- <div className={containerClassName}>
79
- {items.map(({ label, imageUrl, showImage }, index) => (
80
- <button
81
- className={classNames(itemClassName, {
82
- selected_item: index === selectedIndex,
83
- })}
84
- key={label}
85
- onClick={() => this.selectItem(index)}
86
- >
87
- {showImage ? (
88
- <Avatar user={{ name: label, imageUrl }} className="mr-2" />
89
- ) : null}
90
- <span>{label}</span>
91
- </button>
92
- ))}
93
- </div>
94
- );
95
- }
96
- }
@@ -1,23 +0,0 @@
1
- export const createMentionSuggestions = (
2
- items = [],
3
- { limit = 5, showImage = false } = {}
4
- ) => {
5
- const allSuggestions = items.map((item) => {
6
- let suggestionObj;
7
- if (typeof item === "string") {
8
- suggestionObj = { key: item, label: item };
9
- } else if (typeof item === "object") {
10
- suggestionObj = { ...item };
11
- }
12
- suggestionObj.showImage = showImage;
13
-
14
- return suggestionObj;
15
- });
16
-
17
- return ({ query }) =>
18
- allSuggestions
19
- .filter((suggestion) =>
20
- suggestion.label.toLowerCase().startsWith(query.toLowerCase())
21
- )
22
- .slice(0, limit);
23
- };
@@ -1,81 +0,0 @@
1
- import { Extension } from "@tiptap/core";
2
- import { Decoration, DecorationSet } from "prosemirror-view";
3
- import { Plugin } from "prosemirror-state";
4
-
5
- import { placeholderGenerator } from "./helpers";
6
-
7
- export default Extension.create({
8
- name: "placeholder",
9
-
10
- addOptions() {
11
- return {
12
- excludeNodeTypes: ["variable"],
13
- emptyEditorClass: "is-editor-empty",
14
- emptyNodeClass: "is-empty",
15
- placeholder: "Write something …",
16
- showOnlyWhenEditable: true,
17
- showOnlyCurrent: true,
18
- includeChildren: false,
19
- };
20
- },
21
-
22
- addProseMirrorPlugins() {
23
- return [
24
- new Plugin({
25
- props: {
26
- decorations: ({ doc, selection }) => {
27
- const active =
28
- this.editor.isEditable || !this.options.showOnlyWhenEditable;
29
- const { anchor } = selection;
30
- const decorations = [];
31
-
32
- if (!active) {
33
- return;
34
- }
35
-
36
- doc.descendants((node, pos) => {
37
- const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
38
- const isEmpty = !node.isLeaf && !node.childCount;
39
-
40
- const isExcluded = this.options.excludeNodeTypes.includes(
41
- node.type.name
42
- );
43
-
44
- if (
45
- (hasAnchor || !this.options.showOnlyCurrent) &&
46
- !isExcluded &&
47
- isEmpty
48
- ) {
49
- const classes = [this.options.emptyNodeClass];
50
-
51
- if (this.editor.isEmpty) {
52
- classes.push(this.options.emptyEditorClass);
53
- }
54
-
55
- const decoration = Decoration.node(pos, pos + node.nodeSize, {
56
- class: classes.join(" "),
57
- "data-placeholder":
58
- typeof this.options.placeholder === "function"
59
- ? this.options.placeholder({
60
- editor: this.editor,
61
- node,
62
- pos,
63
- })
64
- : this.options.placeholder,
65
- });
66
-
67
- decorations.push(decoration);
68
- }
69
-
70
- return this.options.includeChildren;
71
- });
72
-
73
- return DecorationSet.create(doc, decorations);
74
- },
75
- },
76
- }),
77
- ];
78
- },
79
- });
80
-
81
- export { placeholderGenerator };
@@ -1,18 +0,0 @@
1
- import isPlainObject from "lodash.isplainobject";
2
-
3
- export const placeholderGenerator = (placeholder) => {
4
- const type = typeof placeholder;
5
-
6
- if (type === "string" || type === "funtion") {
7
- return placeholder;
8
- }
9
-
10
- if (isPlainObject(placeholder)) {
11
- return ({ node }) => {
12
- const { name } = node.type;
13
- return placeholder[name];
14
- };
15
- }
16
-
17
- return "";
18
- };