@flozy/editor 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. package/.eslintignore +4 -0
  2. package/.eslintrc.json +6 -0
  3. package/.github/workflows/npm-publish.yml +33 -0
  4. package/.husky/pre-commit +1 -0
  5. package/.storybook/main.js +20 -0
  6. package/.storybook/preview.js +14 -0
  7. package/.vscode/extensions.json +7 -0
  8. package/.vscode/launch.json +15 -0
  9. package/.vscode/settings.json +22 -0
  10. package/README.md +2 -0
  11. package/craco.config.js +16 -0
  12. package/package.json +107 -0
  13. package/public/favicon.ico +0 -0
  14. package/public/index.html +43 -0
  15. package/public/logo192.png +0 -0
  16. package/public/logo512.png +0 -0
  17. package/public/manifest.json +25 -0
  18. package/public/robots.txt +3 -0
  19. package/src/components/Editor/CollaborativeEditor.js +119 -0
  20. package/src/components/Editor/CommonEditor.js +549 -0
  21. package/src/components/Editor/Editor.css +115 -0
  22. package/src/components/Editor/Elements/CodeToText/CodeToText.css +57 -0
  23. package/src/components/Editor/Elements/CodeToText/CodeToText.jsx +115 -0
  24. package/src/components/Editor/Elements/CodeToText/CodeToTextButton.jsx +16 -0
  25. package/src/components/Editor/Elements/CodeToText/HtmlCode.jsx +59 -0
  26. package/src/components/Editor/Elements/CodeToText/HtmlContextMenu.jsx +39 -0
  27. package/src/components/Editor/Elements/Color Picker/ColorPicker.css +38 -0
  28. package/src/components/Editor/Elements/Color Picker/ColorPicker.jsx +110 -0
  29. package/src/components/Editor/Elements/Color Picker/defaultColors.js +34 -0
  30. package/src/components/Editor/Elements/Embed/Embed.css +14 -0
  31. package/src/components/Editor/Elements/Embed/Embed.jsx +74 -0
  32. package/src/components/Editor/Elements/Embed/Image.jsx +82 -0
  33. package/src/components/Editor/Elements/Embed/Video.jsx +65 -0
  34. package/src/components/Editor/Elements/Equation/Equation.jsx +19 -0
  35. package/src/components/Editor/Elements/Equation/EquationButton.jsx +59 -0
  36. package/src/components/Editor/Elements/Equation/styles.css +4 -0
  37. package/src/components/Editor/Elements/Grid/Grid.js +48 -0
  38. package/src/components/Editor/Elements/Grid/GridButton.js +21 -0
  39. package/src/components/Editor/Elements/Grid/GridItem.js +57 -0
  40. package/src/components/Editor/Elements/ID/Id.jsx +56 -0
  41. package/src/components/Editor/Elements/Link/Link.jsx +24 -0
  42. package/src/components/Editor/Elements/Link/LinkButton.jsx +71 -0
  43. package/src/components/Editor/Elements/Link/styles.css +20 -0
  44. package/src/components/Editor/Elements/Mentions/Mentions.jsx +37 -0
  45. package/src/components/Editor/Elements/NewLine/NewLineButton.js +29 -0
  46. package/src/components/Editor/Elements/Table/Table.jsx +13 -0
  47. package/src/components/Editor/Elements/Table/TableSelector.css +18 -0
  48. package/src/components/Editor/Elements/Table/TableSelector.jsx +76 -0
  49. package/src/components/Editor/Elements/TableContextMenu/TableContextMenu.jsx +97 -0
  50. package/src/components/Editor/Elements/TableContextMenu/styles.css +18 -0
  51. package/src/components/Editor/RemoteCursorOverlay/Overlay.js +78 -0
  52. package/src/components/Editor/Toolbar/Toolbar.jsx +167 -0
  53. package/src/components/Editor/Toolbar/styles.css +28 -0
  54. package/src/components/Editor/Toolbar/toolbarGroups.js +167 -0
  55. package/src/components/Editor/Toolbar/toolbarIcons/align-center.svg +1 -0
  56. package/src/components/Editor/Toolbar/toolbarIcons/align-left.svg +1 -0
  57. package/src/components/Editor/Toolbar/toolbarIcons/align-right.svg +1 -0
  58. package/src/components/Editor/Toolbar/toolbarIcons/blockquote.svg +1 -0
  59. package/src/components/Editor/Toolbar/toolbarIcons/bold.png +0 -0
  60. package/src/components/Editor/Toolbar/toolbarIcons/fontColor.svg +4 -0
  61. package/src/components/Editor/Toolbar/toolbarIcons/headingOne.svg +3 -0
  62. package/src/components/Editor/Toolbar/toolbarIcons/headingTwo.svg +3 -0
  63. package/src/components/Editor/Toolbar/toolbarIcons/italic.png +0 -0
  64. package/src/components/Editor/Toolbar/toolbarIcons/link.svg +1 -0
  65. package/src/components/Editor/Toolbar/toolbarIcons/orderedList.svg +1 -0
  66. package/src/components/Editor/Toolbar/toolbarIcons/strikethrough.png +0 -0
  67. package/src/components/Editor/Toolbar/toolbarIcons/subscript.svg +1 -0
  68. package/src/components/Editor/Toolbar/toolbarIcons/superscript.svg +1 -0
  69. package/src/components/Editor/Toolbar/toolbarIcons/textColor.png +0 -0
  70. package/src/components/Editor/Toolbar/toolbarIcons/underline.png +0 -0
  71. package/src/components/Editor/Toolbar/toolbarIcons/unlink.svg +1 -0
  72. package/src/components/Editor/Toolbar/toolbarIcons/unorderedList.svg +1 -0
  73. package/src/components/Editor/YjsProvider.js +11 -0
  74. package/src/components/Editor/common/Button.jsx +12 -0
  75. package/src/components/Editor/common/Icon.jsx +82 -0
  76. package/src/components/Editor/common/MentionsPopup.jsx +56 -0
  77. package/src/components/Editor/hooks/useMentions.js +44 -0
  78. package/src/components/Editor/hooks/withCollaborative.js +15 -0
  79. package/src/components/Editor/hooks/withCommon.js +17 -0
  80. package/src/components/Editor/plugins/withEmbeds.js +36 -0
  81. package/src/components/Editor/plugins/withEquation.js +8 -0
  82. package/src/components/Editor/plugins/withLinks.js +9 -0
  83. package/src/components/Editor/plugins/withMentions.js +19 -0
  84. package/src/components/Editor/plugins/withTable.js +74 -0
  85. package/src/components/Editor/utils/SlateUtilityFunctions.js +273 -0
  86. package/src/components/Editor/utils/customHooks/useContextMenu.js +42 -0
  87. package/src/components/Editor/utils/customHooks/useFormat.js +26 -0
  88. package/src/components/Editor/utils/customHooks/usePopup.jsx +26 -0
  89. package/src/components/Editor/utils/customHooks/useResize.js +41 -0
  90. package/src/components/Editor/utils/draftToSlate.js +104 -0
  91. package/src/components/Editor/utils/embed.js +18 -0
  92. package/src/components/Editor/utils/equation.js +22 -0
  93. package/src/components/Editor/utils/events.js +56 -0
  94. package/src/components/Editor/utils/grid.js +12 -0
  95. package/src/components/Editor/utils/gridItem.js +19 -0
  96. package/src/components/Editor/utils/link.js +53 -0
  97. package/src/components/Editor/utils/mentions.js +11 -0
  98. package/src/components/Editor/utils/paragraph.js +4 -0
  99. package/src/components/Editor/utils/serializer.js +32 -0
  100. package/src/components/Editor/utils/table.js +151 -0
  101. package/src/components/index.js +5 -0
  102. package/src/index.js +1 -0
  103. package/src/stories/CollaborativeEditor.stories.js +30 -0
  104. package/src/stories/Editor.stories.js +24 -0
  105. package/src/stories/EditorSampleProps/ChatSample.js +43 -0
  106. package/src/stories/EditorSampleProps/LayoutOne.js +551 -0
package/.eslintignore ADDED
@@ -0,0 +1,4 @@
1
+ .storybook/*.js
2
+ .husky
3
+ .vscode
4
+ node_modules
package/.eslintrc.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": [ "react-app" ],
3
+ "rules": {
4
+ "react-hooks/exhaustive-deps": "off"
5
+ }
6
+ }
@@ -0,0 +1,33 @@
1
+ # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
2
+ # For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
3
+
4
+ name: FLOZY APP - EDITOR - Semantic Release
5
+
6
+ on:
7
+ release:
8
+ types: [created]
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v3
15
+ - uses: actions/setup-node@v3
16
+ with:
17
+ node-version: 16
18
+ - run: npm ci
19
+ - run: npm test
20
+
21
+ publish-npm:
22
+ needs: build
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - uses: actions/checkout@v3
26
+ - uses: actions/setup-node@v3
27
+ with:
28
+ node-version: 16
29
+ registry-url: https://registry.npmjs.org/
30
+ - run: npm ci
31
+ - run: npm publish --access public
32
+ env:
33
+ NODE_AUTH_TOKEN: ${{secrets.NPM_PUBLISH_TOKEN}}
@@ -0,0 +1 @@
1
+ npx lint-staged
@@ -0,0 +1,20 @@
1
+ /** @type { import('@storybook/react-webpack5').StorybookConfig } */
2
+ const config = {
3
+ stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
4
+ addons: [
5
+ "@storybook/addon-links",
6
+ "@storybook/addon-essentials",
7
+ "@storybook/preset-create-react-app",
8
+ "@storybook/addon-onboarding",
9
+ "@storybook/addon-interactions",
10
+ ],
11
+ framework: {
12
+ name: "@storybook/react-webpack5",
13
+ options: {},
14
+ },
15
+ docs: {
16
+ autodocs: "tag",
17
+ },
18
+ staticDirs: ["../public"],
19
+ };
20
+ export default config;
@@ -0,0 +1,14 @@
1
+ /** @type { import('@storybook/react').Preview } */
2
+ const preview = {
3
+ parameters: {
4
+ actions: { argTypesRegex: "^on[A-Z].*" },
5
+ controls: {
6
+ matchers: {
7
+ color: /(background|color)$/i,
8
+ date: /Date$/,
9
+ },
10
+ },
11
+ },
12
+ };
13
+
14
+ export default preview;
@@ -0,0 +1,7 @@
1
+ {
2
+ "recommendations": [
3
+ "dbaeumer.vscode-eslint",
4
+ "esbenp.prettier-vscode",
5
+ "mikoz.black-py"
6
+ ]
7
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "version": "0.2.0",
3
+ "configurations": [
4
+ {
5
+ "name": "Chrome",
6
+ "type": "chrome",
7
+ "request": "launch",
8
+ "url": "http://localhost:3000",
9
+ "webRoot": "${workspaceFolder}/client/src",
10
+ "sourceMapPathOverrides": {
11
+ "webpack:///src/*": "${webRoot}/*"
12
+ }
13
+ }
14
+ ]
15
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "[javascript]": {
3
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
4
+ "editor.formatOnSave": true
5
+ },
6
+ "[javascriptreact]": {
7
+ "editor.formatOnSave": true,
8
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
9
+ },
10
+ "[json]": {
11
+ "editor.formatOnSave": true,
12
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
13
+ },
14
+ "[python]": {
15
+ "editor.defaultFormatter": "ms-python.black-formatter",
16
+ "editor.formatOnSave": true
17
+ },
18
+ "[markdown]": {
19
+ "editor.formatOnSave": true,
20
+ "editor.formatOnPaste": true
21
+ }
22
+ }
package/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # editor
2
+ A brain document editor
@@ -0,0 +1,16 @@
1
+ module.exports = {
2
+ webpack: {
3
+ configure: {
4
+ module: {
5
+ rules: [
6
+ {
7
+ test: /\.m?js$/,
8
+ resolve: {
9
+ fullySpecified: false,
10
+ },
11
+ },
12
+ ],
13
+ },
14
+ },
15
+ },
16
+ };
package/package.json ADDED
@@ -0,0 +1,107 @@
1
+ {
2
+ "name": "@flozy/editor",
3
+ "version": "1.0.0",
4
+ "description": "An Editor for flozy app brain",
5
+ "dependencies": {
6
+ "@emotion/react": "^11.11.1",
7
+ "@emotion/styled": "^11.11.0",
8
+ "@hocuspocus/provider": "^2.5.0",
9
+ "@mui/icons-material": "^5.14.3",
10
+ "@mui/material": "^5.14.1",
11
+ "@mui/styled-engine-sc": "^5.12.0",
12
+ "@slate-yjs/core": "^1.0.2",
13
+ "@slate-yjs/react": "^1.1.0",
14
+ "@testing-library/jest-dom": "^5.16.5",
15
+ "@testing-library/react": "^13.4.0",
16
+ "@testing-library/user-event": "^13.5.0",
17
+ "husky": "^8.0.3",
18
+ "interweave": "^13.1.0",
19
+ "lint-staged": "^13.2.3",
20
+ "prettier": "^3.0.1",
21
+ "react": "^18.2.0",
22
+ "react-dom": "^18.2.0",
23
+ "react-icons": "^4.10.1",
24
+ "react-katex": "^3.0.1",
25
+ "react-scripts": "5.0.1",
26
+ "slate": "^0.94.1",
27
+ "slate-history": "^0.93.0",
28
+ "slate-react": "^0.98.3",
29
+ "styled-components": "^5.3.11",
30
+ "web-vitals": "^2.1.4",
31
+ "y-websocket": "^1.5.0",
32
+ "yjs": "^13.6.8"
33
+ },
34
+ "scripts": {
35
+ "prepare": "husky install .husky",
36
+ "lint": "./node_modules/.bin/eslint --ignore-path .gitignore . --fix",
37
+ "start": "craco start",
38
+ "build": "craco build",
39
+ "test": "craco test --passWithNoTests",
40
+ "eject": "react-scripts eject",
41
+ "storybook": "storybook dev -p 6006",
42
+ "build-storybook": "storybook build"
43
+ },
44
+ "eslintConfig": {
45
+ "extends": [
46
+ "react-app",
47
+ "react-app/jest",
48
+ "plugin:storybook/recommended"
49
+ ]
50
+ },
51
+ "browserslist": {
52
+ "production": [
53
+ ">0.2%",
54
+ "not dead",
55
+ "not op_mini all"
56
+ ],
57
+ "development": [
58
+ "last 1 chrome version",
59
+ "last 1 firefox version",
60
+ "last 1 safari version"
61
+ ]
62
+ },
63
+ "husky": {
64
+ "hooks": {
65
+ "pre-commit": "lint-staged"
66
+ }
67
+ },
68
+ "lint-staged": {
69
+ "*.{js,jsx}": [
70
+ "./node_modules/.bin/eslint --max-warnings=2"
71
+ ]
72
+ },
73
+ "devDependencies": {
74
+ "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
75
+ "@craco/craco": "^7.1.0",
76
+ "@storybook/addon-essentials": "^7.4.0",
77
+ "@storybook/addon-interactions": "^7.4.0",
78
+ "@storybook/addon-links": "^7.4.0",
79
+ "@storybook/addon-onboarding": "^1.0.8",
80
+ "@storybook/blocks": "^7.4.0",
81
+ "@storybook/preset-create-react-app": "^7.4.0",
82
+ "@storybook/react": "^7.4.0",
83
+ "@storybook/react-webpack5": "^7.4.0",
84
+ "@storybook/testing-library": "^0.2.0",
85
+ "babel-plugin-named-exports-order": "^0.0.2",
86
+ "eslint-plugin-storybook": "^0.6.13",
87
+ "prop-types": "^15.8.1",
88
+ "storybook": "^7.4.0",
89
+ "webpack": "^5.88.2"
90
+ },
91
+ "overrides": {
92
+ "react-refresh": "0.11.0"
93
+ },
94
+ "repository": {
95
+ "type": "git",
96
+ "url": "git+https://github.com/Flozy-App/editor.git"
97
+ },
98
+ "keywords": [
99
+ "flozy-editor",
100
+ "flozy-brain"
101
+ ],
102
+ "author": "tech@agenciflow.com",
103
+ "license": "ISC",
104
+ "bugs": {
105
+ "url": "https://github.com/Flozy-App/editor/issues"
106
+ }
107
+ }
Binary file
@@ -0,0 +1,43 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ <meta name="theme-color" content="#000000" />
8
+ <meta
9
+ name="description"
10
+ content="Web site created using create-react-app"
11
+ />
12
+ <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
13
+ <!--
14
+ manifest.json provides metadata used when your web app is installed on a
15
+ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
16
+ -->
17
+ <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
18
+ <!--
19
+ Notice the use of %PUBLIC_URL% in the tags above.
20
+ It will be replaced with the URL of the `public` folder during the build.
21
+ Only files inside the `public` folder can be referenced from the HTML.
22
+
23
+ Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
24
+ work correctly both with client-side routing and a non-root public URL.
25
+ Learn how to configure a non-root public URL by running `npm run build`.
26
+ -->
27
+ <title>FLOZY APP - Editor</title>
28
+ </head>
29
+ <body>
30
+ <noscript>You need to enable JavaScript to run this app.</noscript>
31
+ <div id="root"></div>
32
+ <!--
33
+ This HTML file is a template.
34
+ If you open it directly in the browser, you will see an empty page.
35
+
36
+ You can add webfonts, meta tags, or analytics to this file.
37
+ The build step will place the bundled scripts into the <body> tag.
38
+
39
+ To begin the development, run `npm start` or `yarn start`.
40
+ To create a production bundle, use `npm run build` or `yarn build`.
41
+ -->
42
+ </body>
43
+ </html>
Binary file
Binary file
@@ -0,0 +1,25 @@
1
+ {
2
+ "short_name": "React App",
3
+ "name": "Create React App Sample",
4
+ "icons": [
5
+ {
6
+ "src": "favicon.ico",
7
+ "sizes": "64x64 32x32 24x24 16x16",
8
+ "type": "image/x-icon"
9
+ },
10
+ {
11
+ "src": "logo192.png",
12
+ "type": "image/png",
13
+ "sizes": "192x192"
14
+ },
15
+ {
16
+ "src": "logo512.png",
17
+ "type": "image/png",
18
+ "sizes": "512x512"
19
+ }
20
+ ],
21
+ "start_url": ".",
22
+ "display": "standalone",
23
+ "theme_color": "#000000",
24
+ "background_color": "#ffffff"
25
+ }
@@ -0,0 +1,3 @@
1
+ # https://www.robotstxt.org/robotstxt.html
2
+ User-agent: *
3
+ Disallow:
@@ -0,0 +1,119 @@
1
+ import React, { useEffect, useMemo, useState } from "react";
2
+ import * as Y from "yjs";
3
+ import { HocuspocusProvider } from "@hocuspocus/provider";
4
+ import { Editor, Transforms } from "slate";
5
+ import { YjsEditor } from "@slate-yjs/core";
6
+ import "./Editor.css";
7
+ import { draftToSlate } from "./utils/draftToSlate";
8
+ import withCommon from "./hooks/withCommon";
9
+ import withCollaborative from "./hooks/withCollaborative";
10
+ import CommonEditor from "./CommonEditor";
11
+
12
+ const CollaborativeEditor = (props) => {
13
+ const { id, content, onSave, user, socketURL } = props;
14
+ const convertedContent = draftToSlate({ data: content });
15
+ const [value] = useState(convertedContent);
16
+ const [connected, setConnected] = useState(null);
17
+ const [authenticated, setAuthenticated] = useState({
18
+ status: null,
19
+ scope: null,
20
+ });
21
+
22
+ const provider = useMemo(() => {
23
+ return new HocuspocusProvider({
24
+ url: socketURL,
25
+ name: `document-${id}`,
26
+ connect: false,
27
+ token: user?.token,
28
+ });
29
+ }, []);
30
+
31
+ // setup changes for Yjs
32
+ const editor = useMemo(() => {
33
+ if (!connected) return null;
34
+ const sharedType = provider.document.get("content", Y.XmlText);
35
+ const e = withCommon(
36
+ withCollaborative({
37
+ provider,
38
+ sharedType,
39
+ data: user,
40
+ })
41
+ );
42
+
43
+ // Ensure editor always has at least 1 valid child
44
+ const { normalizeNode } = e;
45
+ e.normalizeNode = (entry) => {
46
+ const [node] = entry;
47
+
48
+ if (!Editor.isEditor(node) || node.children.length > 0) {
49
+ return normalizeNode(entry);
50
+ }
51
+
52
+ Transforms.insertNodes(editor, value, { at: [0] });
53
+ };
54
+
55
+ return e;
56
+ }, [provider.document, provider.awareness, connected]);
57
+
58
+ // connect Yjs
59
+ useEffect(() => {
60
+ provider.connect();
61
+ return () => {
62
+ provider.disconnect(editor);
63
+ };
64
+ }, [provider]);
65
+
66
+ // connect to editor
67
+ useEffect(() => {
68
+ if (editor) {
69
+ YjsEditor.connect(editor);
70
+ }
71
+ return () => {
72
+ if (editor) {
73
+ YjsEditor.disconnect(editor);
74
+ }
75
+ };
76
+ }, [editor]);
77
+
78
+ provider.on("authenticated", () => {
79
+ setAuthenticated({
80
+ status: true,
81
+ scope: provider.authorizedScope,
82
+ });
83
+ });
84
+
85
+ provider.on("authenticationFailed", () => {
86
+ setAuthenticated({
87
+ status: false,
88
+ scope: null,
89
+ });
90
+ });
91
+
92
+ provider.on("synced", () => {
93
+ setConnected(true);
94
+ });
95
+
96
+ provider.on("disconnect", () => {
97
+ setConnected(false);
98
+ });
99
+
100
+ provider.on("close", () => {
101
+ setConnected(false);
102
+ });
103
+
104
+ if (authenticated.status === null || !connected === null || !editor) {
105
+ return <h1 data-status={connected}>Loading...</h1>;
106
+ }
107
+
108
+ return (
109
+ <CommonEditor
110
+ editor={editor}
111
+ id={id}
112
+ content={[]}
113
+ onSave={onSave}
114
+ readOnly={authenticated.scope}
115
+ />
116
+ );
117
+ };
118
+
119
+ export default CollaborativeEditor;