@bigbinary/neeto-editor 0.1.16 → 0.2.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bigbinary/neeto-editor",
3
- "version": "0.1.16",
3
+ "version": "0.2.2",
4
4
  "main": "./index.js",
5
5
  "description": "Neeto Editor is the library that drives the rich text experience in all Neeto products built at BigBinary",
6
6
  "keywords": [
@@ -12,26 +12,40 @@
12
12
  "author": "BigBinary",
13
13
  "license": "MIT",
14
14
  "dependencies": {
15
+ "@bigbinary/neeto-icons": "^1.8.6",
15
16
  "@risingstack/react-easy-state": "^6.3.0",
16
17
  "@tailwindcss/typography": "^0.4.0",
18
+ "@tippyjs/react": "^4.2.6",
17
19
  "@tiptap/extension-bubble-menu": "^2.0.0-beta.18",
18
20
  "@tiptap/extension-code-block-lowlight": "^2.0.0-beta.24",
21
+ "@tiptap/extension-color": "^2.0.0-beta.3",
22
+ "@tiptap/extension-document": "^2.0.0-beta.15",
19
23
  "@tiptap/extension-dropcursor": "^2.0.0-beta.13",
20
24
  "@tiptap/extension-highlight": "^2.0.0-beta.13",
21
25
  "@tiptap/extension-image": "^2.0.0-beta.13",
22
26
  "@tiptap/extension-link": "^2.0.0-beta.18",
27
+ "@tiptap/extension-mention": "^2.0.0-beta.80",
23
28
  "@tiptap/extension-placeholder": "^2.0.0-beta.18",
29
+ "@tiptap/extension-text-style": "^2.0.0-beta.17",
24
30
  "@tiptap/extension-typography": "^2.0.0-beta.11",
31
+ "@tiptap/extension-underline": "^2.0.0-beta.21",
25
32
  "@tiptap/react": "^2.0.0-beta.37",
26
33
  "@tiptap/starter-kit": "^2.0.0-beta.57",
27
34
  "@tiptap/suggestion": "^2.0.0-beta.55",
28
- "@uppy/core": "^1.18.1",
29
- "@uppy/react": "^1.11.8",
30
- "@uppy/xhr-upload": "^1.7.2",
35
+ "@uppy/core": "^2.1.2",
36
+ "@uppy/react": "^2.1.1",
37
+ "@uppy/url": "^2.0.4",
38
+ "@uppy/xhr-upload": "^2.0.5",
31
39
  "classnames": "^2.3.1",
40
+ "lodash.isempty": "^4.4.0",
41
+ "lodash.isplainobject": "^4.0.6",
32
42
  "lowlight": "^1.20.0",
33
43
  "peer-deps-externals-webpack-plugin": "1.0.4",
44
+ "react-hotkeys-hook": "^3.4.4",
34
45
  "react-icons": "^4.2.0",
46
+ "react-outside-click-handler": "^1.3.0",
47
+ "react-popper": "^2.2.5",
48
+ "react-router-dom": "^6.0.2",
35
49
  "tippy.js": "^6.3.1"
36
50
  },
37
51
  "devDependencies": {
package/webpack.config.js CHANGED
@@ -1,7 +1,8 @@
1
1
  const PeerDepsExternalsPlugin = require("peer-deps-externals-webpack-plugin");
2
+ const path = require("path");
2
3
 
3
4
  module.exports = {
4
- entry: "./src/Editor/index.js",
5
+ entry: "./lib/index.js",
5
6
  module: {
6
7
  rules: [
7
8
  {
@@ -40,4 +41,11 @@ module.exports = {
40
41
  libraryTarget: "umd",
41
42
  },
42
43
  plugins: [new PeerDepsExternalsPlugin()],
44
+ resolve: {
45
+ alias: {
46
+ common: path.resolve(__dirname, "/lib/components/Common"),
47
+ hooks: path.resolve(__dirname, "/lib/hooks"),
48
+ constants: path.resolve(__dirname, "/lib/constants"),
49
+ },
50
+ },
43
51
  };
@@ -1,7 +1,8 @@
1
1
  const HtmlWebPackPlugin = require("html-webpack-plugin");
2
+ const path = require("path");
2
3
 
3
4
  module.exports = {
4
- entry: "./src/index.js",
5
+ entry: "./example/index.js",
5
6
  devtool:
6
7
  process.env.NODE_ENV === "production"
7
8
  ? "source-map"
@@ -58,4 +59,11 @@ module.exports = {
58
59
  filename: "./index.html",
59
60
  }),
60
61
  ],
62
+ resolve: {
63
+ alias: {
64
+ common: path.resolve(__dirname, "/lib/components/Common"),
65
+ hooks: path.resolve(__dirname, "/lib/hooks"),
66
+ constants: path.resolve(__dirname, "/lib/constants"),
67
+ },
68
+ },
61
69
  };
Binary file
Binary file
package/src/App.js DELETED
@@ -1,31 +0,0 @@
1
- import React, { Component } from "react";
2
- import Editor from "./Editor/index";
3
- import "./index.scss";
4
-
5
- export default class App extends Component {
6
- ref = React.createRef();
7
-
8
- getHTML = () => {
9
- return this.ref.current.editor.getHTML();
10
- };
11
-
12
- render() {
13
- return (
14
- <div style={{ width: 720, margin: "48px auto" }}>
15
- <div className="flex justify-end">
16
- <button
17
- className="px-3 py-1 text-sm font-medium border border-gray-200 rounded shadow-sm"
18
- onClick={() => {
19
- // eslint-disable-next-line no-console
20
- console.log(this.getHTML());
21
- }}
22
- >
23
- Print output to console
24
- </button>
25
- </div>
26
- <hr className="my-2 border-gray-100" />
27
- <Editor ref={this.ref} />
28
- </div>
29
- );
30
- }
31
- }
@@ -1,85 +0,0 @@
1
- import React from "react";
2
- import classnames from "classnames";
3
- import { BubbleMenu } from "@tiptap/react";
4
- import {
5
- FaBold,
6
- FaItalic,
7
- FaStrikethrough,
8
- FaHighlighter,
9
- FaCode,
10
- FaLink,
11
- } from "react-icons/fa";
12
-
13
- export default function index({ editor, formatterOptions }) {
14
- if (!editor) {
15
- return null;
16
- }
17
- const options = [
18
- {
19
- Icon: FaBold,
20
- command: () => editor.chain().focus().toggleBold().run(),
21
- active: editor.isActive("bold"),
22
- optionName: "bold",
23
- },
24
- {
25
- Icon: FaItalic,
26
- command: () => editor.chain().focus().toggleItalic().run(),
27
- active: editor.isActive("italic"),
28
- optionName: "italic",
29
- },
30
- {
31
- Icon: FaStrikethrough,
32
- command: () => editor.chain().focus().toggleStrike().run(),
33
- active: editor.isActive("strike"),
34
- optionName: "strike",
35
- },
36
- {
37
- Icon: FaLink,
38
- command: () => {
39
- if (editor.isActive("link")) {
40
- editor.chain().focus().unsetLink().run();
41
- } else {
42
- const url = window.prompt("Please enter your URL");
43
- editor.chain().focus().setLink({ href: url }).run();
44
- }
45
- },
46
- active: editor.isActive("link"),
47
- optionName: "link",
48
- },
49
- {
50
- Icon: FaCode,
51
- command: () => editor.chain().focus().toggleCode().run(),
52
- active: editor.isActive("code"),
53
- optionName: "code",
54
- },
55
- {
56
- Icon: FaHighlighter,
57
- command: () => editor.chain().focus().toggleHighlight().run(),
58
- active: editor.isActive("highlight"),
59
- optionName: "highlight",
60
- },
61
- ];
62
- return (
63
- <BubbleMenu editor={editor}>
64
- <div className="relative flex items-center overflow-hidden bg-gray-900 rounded shadow">
65
- {options
66
- .filter(({ optionName }) => formatterOptions.includes(optionName))
67
- .map((option) => (
68
- <Option {...option} key={option.optionName} />
69
- ))}
70
- </div>
71
- </BubbleMenu>
72
- );
73
- }
74
-
75
- const Option = ({ Icon, command, active, iconSize }) => (
76
- <div
77
- className={classnames("p-3 cursor-pointer hover:bg-gray-800", {
78
- "text-gray-400": !active,
79
- "text-white": active,
80
- })}
81
- onClick={command}
82
- >
83
- <Icon size={iconSize || 15} />
84
- </div>
85
- );
@@ -1,12 +0,0 @@
1
- import React from "react";
2
- import { NodeViewWrapper, NodeViewContent } from "@tiptap/react";
3
-
4
- export default function index() {
5
- return (
6
- <NodeViewWrapper>
7
- <pre>
8
- <NodeViewContent as="code" />
9
- </pre>
10
- </NodeViewWrapper>
11
- );
12
- }
@@ -1,10 +0,0 @@
1
- import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
2
- import { ReactNodeViewRenderer } from "@tiptap/react";
3
- import CodeBlockComponent from "./CodeBlockComponent";
4
- import lowlight from "lowlight";
5
-
6
- export default CodeBlockLowlight.extend({
7
- addNodeView() {
8
- return new ReactNodeViewRenderer(CodeBlockComponent);
9
- },
10
- }).configure({ lowlight });
@@ -1,70 +0,0 @@
1
- import { Node, mergeAttributes } from "@tiptap/core";
2
-
3
- export default Node.create({
4
- name: "external-video",
5
-
6
- defaultOptions: {
7
- inline: false,
8
- HTMLAttributes: {},
9
- },
10
-
11
- inline() {
12
- return this.options.inline;
13
- },
14
-
15
- group() {
16
- return this.options.inline ? "inline" : "block";
17
- },
18
-
19
- draggable: true,
20
-
21
- addAttributes() {
22
- return {
23
- src: {
24
- default: null,
25
- },
26
- title: {
27
- default: null,
28
- },
29
- frameborder: {
30
- default: "0",
31
- },
32
- allow: {
33
- default:
34
- "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
35
- },
36
- allowfullscreen: {
37
- default: "allowfullscreen",
38
- },
39
- };
40
- },
41
-
42
- parseHTML() {
43
- return [
44
- {
45
- tag: "iframe[src]",
46
- },
47
- ];
48
- },
49
-
50
- renderHTML({ HTMLAttributes }) {
51
- return [
52
- "div",
53
- { class: "video-wrapper" },
54
- ["iframe", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)],
55
- ];
56
- },
57
-
58
- addCommands() {
59
- return {
60
- setExternalVideo:
61
- (options) =>
62
- ({ commands }) => {
63
- return commands.insertContent({
64
- type: this.name,
65
- attrs: options,
66
- });
67
- },
68
- };
69
- },
70
- });
@@ -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,41 +0,0 @@
1
- import React from "react";
2
- import { view } from "@risingstack/react-easy-state";
3
- import Uppy from "@uppy/core";
4
- import { DashboardModal } from "@uppy/react";
5
- import XHRUpload from "@uppy/xhr-upload";
6
- import "@uppy/core/dist/style.css";
7
- import "@uppy/dashboard/dist/style.css";
8
- import sharedState from "../../sharedState";
9
-
10
- const ImageUpload = ({ editor, imageUploadUrl }) => {
11
- const uppy = new Uppy({
12
- allowMultipleUploads: false,
13
- autoProceed: true,
14
- debug: true,
15
- });
16
-
17
- uppy.use(XHRUpload, {
18
- endpoint: imageUploadUrl || "/api/v1/direct_uploads",
19
- formData: true,
20
- fieldName: "blob",
21
- });
22
-
23
- uppy.on("upload-success", (file, response) => {
24
- const url = response.body.imageURL;
25
- editor.chain().focus().setImage({ src: url }).run();
26
- });
27
-
28
- return (
29
- <div>
30
- <DashboardModal
31
- uppy={uppy}
32
- proudlyDisplayPoweredByUppy={false}
33
- closeModalOnClickOutside
34
- open={sharedState.showImageUpload}
35
- onRequestClose={() => (sharedState.showImageUpload = false)}
36
- />
37
- </div>
38
- );
39
- };
40
-
41
- export default view(ImageUpload);
@@ -1,25 +0,0 @@
1
- import { Extension } from "@tiptap/core";
2
- import Suggestion from "@tiptap/suggestion";
3
-
4
- export default Extension.create({
5
- name: "mention",
6
-
7
- defaultOptions: {
8
- suggestion: {
9
- char: "/",
10
- startOfLine: false,
11
- command: ({ editor, range, props }) => {
12
- props.command({ editor, range });
13
- },
14
- },
15
- },
16
-
17
- addProseMirrorPlugins() {
18
- return [
19
- Suggestion({
20
- editor: this.editor,
21
- ...this.options.suggestion,
22
- }),
23
- ];
24
- },
25
- });
@@ -1,110 +0,0 @@
1
- import React from "react";
2
- import classnames from "classnames";
3
- import "../../styles/CommandsList.scss";
4
-
5
- class CommandsList extends React.Component {
6
- constructor(props) {
7
- super(props);
8
-
9
- this.state = {
10
- selectedIndex: 0,
11
- };
12
- }
13
-
14
- componentDidUpdate(oldProps) {
15
- if (this.props.items !== oldProps.items) {
16
- this.setState({
17
- selectedIndex: 0,
18
- });
19
- }
20
- }
21
-
22
- onKeyDown({ event }) {
23
- if (event.key === "ArrowUp") {
24
- this.upHandler();
25
- return true;
26
- }
27
-
28
- if (event.key === "ArrowDown") {
29
- this.downHandler();
30
- return true;
31
- }
32
-
33
- if (event.key === "Enter") {
34
- this.enterHandler();
35
- return true;
36
- }
37
-
38
- return false;
39
- }
40
-
41
- upHandler() {
42
- this.setState({
43
- selectedIndex:
44
- (this.state.selectedIndex + this.props.items.length - 1) %
45
- this.props.items.length,
46
- });
47
- }
48
-
49
- downHandler() {
50
- this.setState({
51
- selectedIndex: (this.state.selectedIndex + 1) % this.props.items.length,
52
- });
53
- }
54
-
55
- enterHandler() {
56
- this.selectItem(this.state.selectedIndex);
57
- }
58
-
59
- selectItem(index) {
60
- const item = this.props.items[index];
61
-
62
- if (item) {
63
- const { editor, range } = this.props;
64
- item.command({ editor, range });
65
- }
66
- }
67
-
68
- render() {
69
- return (
70
- <div className="relative py-2 overflow-hidden bg-gray-900 rounded shadow">
71
- {this.props.items.map((item, index) => (
72
- <Item
73
- key={item.title}
74
- item={item}
75
- index={index}
76
- selectedIndex={this.state.selectedIndex}
77
- selectItem={this.selectItem}
78
- />
79
- ))}
80
- </div>
81
- );
82
- }
83
- }
84
-
85
- const Item = ({ item, selectedIndex, index, selectItem }) => {
86
- const Icon = item.Icon;
87
- return (
88
- <div
89
- className={classnames(
90
- "flex items-center w-full px-4 py-2 space-x-4 transition-all duration-100",
91
- {
92
- "bg-gray-800": index === selectedIndex,
93
- }
94
- )}
95
- onClick={() => selectItem(index)}
96
- >
97
- {Icon && (
98
- <div className="p-1 text-gray-100 bg-gray-800 rounded-sm">
99
- <Icon size={18} />
100
- </div>
101
- )}
102
- <div className="flex flex-col text-gray-100">
103
- <span className="text-sm font-semibold">{item.title}</span>
104
- <span className="text-xs text-gray-300">{item.description}</span>
105
- </div>
106
- </div>
107
- );
108
- };
109
-
110
- export default CommandsList;