From c532dc1ba5b618da5b958cf5f503087abba677f0 Mon Sep 17 00:00:00 2001 From: surya darma Date: Sat, 2 Jan 2021 14:22:23 +0800 Subject: [PATCH 01/13] init package --- slate-mention-plugin/.prettierrc | 8 +++ slate-mention-plugin/package.json | 20 +++++++ slate-mention-plugin/src/index.ts | 7 +++ slate-mention-plugin/tsconfig.json | 68 +++++++++++++++++++++ slate-mention-plugin/yarn.lock | 94 ++++++++++++++++++++++++++++++ 5 files changed, 197 insertions(+) create mode 100644 slate-mention-plugin/.prettierrc create mode 100644 slate-mention-plugin/package.json create mode 100644 slate-mention-plugin/src/index.ts create mode 100644 slate-mention-plugin/tsconfig.json create mode 100644 slate-mention-plugin/yarn.lock diff --git a/slate-mention-plugin/.prettierrc b/slate-mention-plugin/.prettierrc new file mode 100644 index 0000000..e396c2c --- /dev/null +++ b/slate-mention-plugin/.prettierrc @@ -0,0 +1,8 @@ +{ + "endOfLine": "lf", + "semi": false, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "bracketSpacing": false +} diff --git a/slate-mention-plugin/package.json b/slate-mention-plugin/package.json new file mode 100644 index 0000000..9a01969 --- /dev/null +++ b/slate-mention-plugin/package.json @@ -0,0 +1,20 @@ +{ + "name": "slate-mention-plugin", + "version": "0.0.1", + "main": "dist/index.js", + "author": "imdbsd", + "license": "MIT", + "scripts": { + "build": "tsc -p .", + "prepublish": "rm -rf ./dist && yarn build", + "publish:major": "yarn publish --major --message Release", + "publish:patch": "yarn publish --patch --message 'Release patch'" + }, + "dependencies": { + "slate": "^0.59.0", + "slate-react": "^0.59.0" + }, + "devDependencies": { + "typescript": "^4.1.3" + } +} diff --git a/slate-mention-plugin/src/index.ts b/slate-mention-plugin/src/index.ts new file mode 100644 index 0000000..6b59b56 --- /dev/null +++ b/slate-mention-plugin/src/index.ts @@ -0,0 +1,7 @@ +import {Editor} from 'slate' + +const withMention = (editor: Editor) => { + return editor +} + +export default withMention diff --git a/slate-mention-plugin/tsconfig.json b/slate-mention-plugin/tsconfig.json new file mode 100644 index 0000000..1c206dd --- /dev/null +++ b/slate-mention-plugin/tsconfig.json @@ -0,0 +1,68 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, + "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./dist" /* Redirect output structure to the directory. */, + "rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + /* Strict Type-Checking Options */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + /* Advanced Options */ + "skipLibCheck": true /* Skip type checking of declaration files. */, + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + }, + "exclude": [ + "node_modules", + "__tests__", + "dist" + ] +} \ No newline at end of file diff --git a/slate-mention-plugin/yarn.lock b/slate-mention-plugin/yarn.lock new file mode 100644 index 0000000..81e456b --- /dev/null +++ b/slate-mention-plugin/yarn.lock @@ -0,0 +1,94 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/esrever@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@types/esrever/-/esrever-0.2.0.tgz#96404a2284b2c7527f08a1e957f8a31705f9880f" + integrity sha512-5NI6TeGzVEy/iBcuYtcPzzIC6EqlfQ2+UZ54vT0ulq8bPNGAy8UJD+XcsAyEOcnYFUjOVWuUV+k4/rVkxt9/XQ== + +"@types/is-hotkey@^0.1.1": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@types/is-hotkey/-/is-hotkey-0.1.2.tgz#94f00793b5a297a7f7e69c1ef49613da2243a987" + integrity sha512-SUw9LpI3AIwbRNXS7FYy9AlXrTPIdBZGI7y4XxfIEYqgSW1UfFCUM9cMwHE/yCfTl0qeI0UQ/q8TdIxsIFgKPg== + +"@types/lodash@^4.14.149": + version "4.14.167" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.167.tgz#ce7d78553e3c886d4ea643c37ec7edc20f16765e" + integrity sha512-w7tQPjARrvdeBkX/Rwg95S592JwxqOjmms3zWQ0XZgSyxSLdzWaYH3vErBhdVS/lRBX7F8aBYcYJYTr5TMGOzw== + +compute-scroll-into-view@^1.0.16: + version "1.0.16" + resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.16.tgz#5b7bf4f7127ea2c19b750353d7ce6776a90ee088" + integrity sha512-a85LHKY81oQnikatZYA90pufpZ6sQx++BoCxOEMsjpZx+ZnaKGQnCyCehTRr/1p9GBIAHTjcU9k71kSYWloLiQ== + +direction@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/direction/-/direction-1.0.4.tgz#2b86fb686967e987088caf8b89059370d4837442" + integrity sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ== + +esrever@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/esrever/-/esrever-0.2.0.tgz#96e9d28f4f1b1a76784cd5d490eaae010e7407b8" + integrity sha1-lunSj08bGnZ4TNXUkOquAQ50B7g= + +immer@^5.0.0: + version "5.3.6" + resolved "https://registry.yarnpkg.com/immer/-/immer-5.3.6.tgz#51eab8cbbeb13075fe2244250f221598818cac04" + integrity sha512-pqWQ6ozVfNOUDjrLfm4Pt7q4Q12cGw2HUZgry4Q5+Myxu9nmHRkWBpI0J4+MK0AxbdFtdMTwEGVl7Vd+vEiK+A== + +is-hotkey@^0.1.6: + version "0.1.8" + resolved "https://registry.yarnpkg.com/is-hotkey/-/is-hotkey-0.1.8.tgz#6b1f4b2d0e5639934e20c05ed24d623a21d36d25" + integrity sha512-qs3NZ1INIS+H+yeo7cD9pDfwYV/jqRh1JG9S9zYrNudkoUQg7OL7ziXqRKu+InFjUIDoP2o6HIkLYMh1pcWgyQ== + +is-plain-object@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.1.tgz#662d92d24c0aa4302407b0d45d21f2251c85f85b" + integrity sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g== + +lodash@^4.17.4: + version "4.17.20" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + +scroll-into-view-if-needed@^2.2.20: + version "2.2.26" + resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.26.tgz#e4917da0c820135ff65ad6f7e4b7d7af568c4f13" + integrity sha512-SQ6AOKfABaSchokAmmaxVnL9IArxEnLEX9j4wAZw+x4iUTb40q7irtHG3z4GtAWz5veVZcCnubXDBRyLVQaohw== + dependencies: + compute-scroll-into-view "^1.0.16" + +slate-react@^0.59.0: + version "0.59.0" + resolved "https://registry.yarnpkg.com/slate-react/-/slate-react-0.59.0.tgz#c8043dce7ea71279f314d9951c32e4f548b1ea0b" + integrity sha512-Fx5vfTi0s1fY5PaXzPH8uA9mW8aevVVYrGGvqX/k363tlPDnQSs/QTibIyFl1Y3MPJ+GdocoyOGjAaZMUIXfIg== + dependencies: + "@types/is-hotkey" "^0.1.1" + "@types/lodash" "^4.14.149" + direction "^1.0.3" + is-hotkey "^0.1.6" + is-plain-object "^3.0.0" + lodash "^4.17.4" + scroll-into-view-if-needed "^2.2.20" + +slate@^0.59.0: + version "0.59.0" + resolved "https://registry.yarnpkg.com/slate/-/slate-0.59.0.tgz#3169daf2f036e84aa149f60e0d12ef2fc4c0839e" + integrity sha512-M4UTMkXExxuq8tCD+knn7BtV2pmY8pepay++EF59rmg/v4RB6X1gNzA0xP3aw2rqYl8TmWdOBdy9InFrm3WyXw== + dependencies: + "@types/esrever" "^0.2.0" + esrever "^0.2.0" + immer "^5.0.0" + is-plain-object "^3.0.0" + tiny-warning "^1.0.3" + +tiny-warning@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" + integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== + +typescript@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" + integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== From c31e3c1c9738ba358b5f349caa777344468a14f8 Mon Sep 17 00:00:00 2001 From: surya darma Date: Sat, 2 Jan 2021 14:31:55 +0800 Subject: [PATCH 02/13] init stories --- package.json | 1 + playground/package.json | 1 + playground/src/SlateMentionPlugin.stories.tsx | 13 ++++++ playground/src/SlateMentionPlugin.tsx | 41 +++++++++++++++++++ 4 files changed, 56 insertions(+) create mode 100644 playground/src/SlateMentionPlugin.stories.tsx create mode 100644 playground/src/SlateMentionPlugin.tsx diff --git a/package.json b/package.json index 50e8784..41f3d96 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "private": true, "workspaces": [ + "slate-mention-plugin", "slate-string-deserialize", "slate-paste-url-plugin", "playground" diff --git a/playground/package.json b/playground/package.json index e1f53f5..6f5443c 100644 --- a/playground/package.json +++ b/playground/package.json @@ -16,6 +16,7 @@ "slate": "^0.59.0", "slate-history": "^0.59.0", "slate-react": "^0.59.0", + "slate-mention-plugin": "0.0.1", "slate-paste-url-plugin": "0.0.1", "slate-string-deserialize": "1.0.4", "typescript": "^4.0.3", diff --git a/playground/src/SlateMentionPlugin.stories.tsx b/playground/src/SlateMentionPlugin.stories.tsx new file mode 100644 index 0000000..d3458c7 --- /dev/null +++ b/playground/src/SlateMentionPlugin.stories.tsx @@ -0,0 +1,13 @@ +import React from 'react' +import {Story, Meta} from '@storybook/react/types-6-0' +import Editor from './SlateMentionPlugin' + +export default { + component: Editor, + title: 'slate-mention-plugin', +} as Meta + +const Template: Story = (args) => + +export const Default = Template.bind({}) +Default.args = {} diff --git a/playground/src/SlateMentionPlugin.tsx b/playground/src/SlateMentionPlugin.tsx new file mode 100644 index 0000000..df7890e --- /dev/null +++ b/playground/src/SlateMentionPlugin.tsx @@ -0,0 +1,41 @@ +import {useState, useMemo, FC} from 'react' +import {createEditor, Node} from 'slate' +import {Slate, Editable, withReact} from 'slate-react' +// @ts-ignore +import withMention from 'slate-mention-plugin' + +const Editor: FC = () => { + const editor = useMemo(() => withMention(withReact(createEditor())), []) + const [value, setValue] = useState([ + { + type: 'paragraph', + children: [ + { + text: `Slate paste url example, try block some text and paste url or github url to the blocked text. + `, + }, + ], + }, + { + type: 'paragraph', + children: [ + { + text: + 'To change how the url rendered, edit the renderElement in SlatePasteUrl.tsx', + }, + ], + }, + ]) + + return ( + setValue(newValue)} + > + + + ) +} + +export default Editor From f5f38d1e6571816fd3a4f4eecdb9d4904c643e93 Mon Sep 17 00:00:00 2001 From: surya darma Date: Sat, 2 Jan 2021 15:13:53 +0800 Subject: [PATCH 03/13] init decorate --- slate-mention-plugin/src/decorate.ts | 29 +++++++++++++++++++++++++ slate-mention-plugin/src/index.ts | 9 +++----- slate-mention-plugin/src/withMention.ts | 15 +++++++++++++ 3 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 slate-mention-plugin/src/decorate.ts create mode 100644 slate-mention-plugin/src/withMention.ts diff --git a/slate-mention-plugin/src/decorate.ts b/slate-mention-plugin/src/decorate.ts new file mode 100644 index 0000000..363a9fb --- /dev/null +++ b/slate-mention-plugin/src/decorate.ts @@ -0,0 +1,29 @@ +import {NodeEntry, Text, Node, Editor, Range} from 'slate' +import {ReactEditor} from 'slate-react' +import {MENTION_LEAF} from './index' + +const MENTION_CAPTURE = /@(\S*)$/ + +const decorate = (editor: ReactEditor | Editor) => (entry: NodeEntry) => { + const [node] = entry + if (!Text.isText(node)) return [] + const content = Node.string(node) + const result = MENTION_CAPTURE.exec(content) + if (!result) return [] + const mentionTo = result[0] + + if (!editor.selection) return [] + + return [ + { + anchor: { + ...editor.selection.anchor, + offset: editor.selection.anchor.offset - (mentionTo.length + 1), + }, + focus: editor.selection.focus, + type: MENTION_LEAF, + }, + ] as Range[] +} + +export default decorate diff --git a/slate-mention-plugin/src/index.ts b/slate-mention-plugin/src/index.ts index 6b59b56..64d25f0 100644 --- a/slate-mention-plugin/src/index.ts +++ b/slate-mention-plugin/src/index.ts @@ -1,7 +1,4 @@ -import {Editor} from 'slate' +export const MENTION_LEAF = 'mention-leaf' -const withMention = (editor: Editor) => { - return editor -} - -export default withMention +export {default as withMention} from './withMention' +export {default as decorate} from './decorate' diff --git a/slate-mention-plugin/src/withMention.ts b/slate-mention-plugin/src/withMention.ts new file mode 100644 index 0000000..d8b7ab8 --- /dev/null +++ b/slate-mention-plugin/src/withMention.ts @@ -0,0 +1,15 @@ +import {Editor} from 'slate' +import {ReactEditor} from 'slate-react' + +const MENTION_NODE = 'mention' + +const withMention = (editor: Editor) => { + const {onChange} = editor + editor.onChange = () => { + console.log('change') + return onChange + } + return editor +} + +export default withMention From 64b7561e1d1c67650a6ae6fa016eac4c50c80679 Mon Sep 17 00:00:00 2001 From: surya darma Date: Sat, 2 Jan 2021 15:37:18 +0800 Subject: [PATCH 04/13] update story --- playground/src/SlateMentionPlugin.tsx | 30 +++++++++++++-------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/playground/src/SlateMentionPlugin.tsx b/playground/src/SlateMentionPlugin.tsx index df7890e..9554915 100644 --- a/playground/src/SlateMentionPlugin.tsx +++ b/playground/src/SlateMentionPlugin.tsx @@ -1,27 +1,16 @@ import {useState, useMemo, FC} from 'react' import {createEditor, Node} from 'slate' -import {Slate, Editable, withReact} from 'slate-react' -// @ts-ignore -import withMention from 'slate-mention-plugin' +import {Slate, Editable, withReact, DefaultLeaf} from 'slate-react' +import {decorate, RenderLeaf} from 'slate-mention-plugin' const Editor: FC = () => { - const editor = useMemo(() => withMention(withReact(createEditor())), []) + const editor = useMemo(() => withReact(createEditor()), []) const [value, setValue] = useState([ { type: 'paragraph', children: [ { - text: `Slate paste url example, try block some text and paste url or github url to the blocked text. - `, - }, - ], - }, - { - type: 'paragraph', - children: [ - { - text: - 'To change how the url rendered, edit the renderElement in SlatePasteUrl.tsx', + text: `coba mention `, }, ], }, @@ -33,7 +22,16 @@ const Editor: FC = () => { value={value} onChange={(newValue) => setValue(newValue)} > - + { + return || + }} + decorate={(entry) => { + const range = decorate(editor)(entry) + console.log({range}) + return range + }} + /> ) } From aa1faeea30395bc37d0b84e4eaa149bac15f4489 Mon Sep 17 00:00:00 2001 From: surya darma Date: Sat, 2 Jan 2021 15:37:30 +0800 Subject: [PATCH 05/13] update deps --- slate-mention-plugin/package.json | 11 ++++++----- slate-mention-plugin/tsconfig.json | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/slate-mention-plugin/package.json b/slate-mention-plugin/package.json index 9a01969..65fe55b 100644 --- a/slate-mention-plugin/package.json +++ b/slate-mention-plugin/package.json @@ -5,16 +5,17 @@ "author": "imdbsd", "license": "MIT", "scripts": { - "build": "tsc -p .", + "build": "rm -rf ./dist && tsc -p .", "prepublish": "rm -rf ./dist && yarn build", "publish:major": "yarn publish --major --message Release", "publish:patch": "yarn publish --patch --message 'Release patch'" }, - "dependencies": { - "slate": "^0.59.0", - "slate-react": "^0.59.0" - }, "devDependencies": { "typescript": "^4.1.3" + }, + "peerDependencies": { + "react": "^17.0.1", + "slate": "^0.59.0", + "slate-react": "^0.59.0" } } diff --git a/slate-mention-plugin/tsconfig.json b/slate-mention-plugin/tsconfig.json index 1c206dd..0ad8342 100644 --- a/slate-mention-plugin/tsconfig.json +++ b/slate-mention-plugin/tsconfig.json @@ -8,7 +8,7 @@ // "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ - // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ "declaration": true, /* Generates corresponding '.d.ts' file. */ // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ // "sourceMap": true, /* Generates corresponding '.map' file. */ From e161b13897bf7757df4c7864f5f9d3fc3f874bff Mon Sep 17 00:00:00 2001 From: surya darma Date: Sat, 2 Jan 2021 15:37:37 +0800 Subject: [PATCH 06/13] adding default renderLeaf --- slate-mention-plugin/src/RenderLeaf.tsx | 17 +++++++++++++++++ slate-mention-plugin/src/index.ts | 1 + 2 files changed, 18 insertions(+) create mode 100644 slate-mention-plugin/src/RenderLeaf.tsx diff --git a/slate-mention-plugin/src/RenderLeaf.tsx b/slate-mention-plugin/src/RenderLeaf.tsx new file mode 100644 index 0000000..61a2aba --- /dev/null +++ b/slate-mention-plugin/src/RenderLeaf.tsx @@ -0,0 +1,17 @@ +import * as React from 'react' +import {RenderLeafProps} from 'slate-react' +import {MENTION_LEAF} from './index' + +const RenderLeaf: React.FC = (props) => { + console.log({props}) + if (props.leaf.type === MENTION_LEAF) { + return ( + + {props.children} + + ) + } + return null +} + +export default RenderLeaf diff --git a/slate-mention-plugin/src/index.ts b/slate-mention-plugin/src/index.ts index 64d25f0..23480f7 100644 --- a/slate-mention-plugin/src/index.ts +++ b/slate-mention-plugin/src/index.ts @@ -1,4 +1,5 @@ export const MENTION_LEAF = 'mention-leaf' +export {default as RenderLeaf} from './RenderLeaf' export {default as withMention} from './withMention' export {default as decorate} from './decorate' From 2bc3d552f063086d9677977bce231ea102b3d1bb Mon Sep 17 00:00:00 2001 From: surya darma Date: Sun, 3 Jan 2021 14:52:04 +0800 Subject: [PATCH 07/13] fix build and remove withMention --- slate-mention-plugin/src/index.ts | 1 - slate-mention-plugin/src/withMention.ts | 15 --------------- slate-mention-plugin/tsconfig.json | 2 +- 3 files changed, 1 insertion(+), 17 deletions(-) delete mode 100644 slate-mention-plugin/src/withMention.ts diff --git a/slate-mention-plugin/src/index.ts b/slate-mention-plugin/src/index.ts index 23480f7..517e72a 100644 --- a/slate-mention-plugin/src/index.ts +++ b/slate-mention-plugin/src/index.ts @@ -1,5 +1,4 @@ export const MENTION_LEAF = 'mention-leaf' export {default as RenderLeaf} from './RenderLeaf' -export {default as withMention} from './withMention' export {default as decorate} from './decorate' diff --git a/slate-mention-plugin/src/withMention.ts b/slate-mention-plugin/src/withMention.ts deleted file mode 100644 index d8b7ab8..0000000 --- a/slate-mention-plugin/src/withMention.ts +++ /dev/null @@ -1,15 +0,0 @@ -import {Editor} from 'slate' -import {ReactEditor} from 'slate-react' - -const MENTION_NODE = 'mention' - -const withMention = (editor: Editor) => { - const {onChange} = editor - editor.onChange = () => { - console.log('change') - return onChange - } - return editor -} - -export default withMention diff --git a/slate-mention-plugin/tsconfig.json b/slate-mention-plugin/tsconfig.json index 0ad8342..e5ad355 100644 --- a/slate-mention-plugin/tsconfig.json +++ b/slate-mention-plugin/tsconfig.json @@ -8,7 +8,7 @@ // "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ - "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + "jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ "declaration": true, /* Generates corresponding '.d.ts' file. */ // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ // "sourceMap": true, /* Generates corresponding '.map' file. */ From 62d3fa98a2e9f3eebca4246bcf103c0286e07ad9 Mon Sep 17 00:00:00 2001 From: surya darma Date: Sun, 3 Jan 2021 15:00:08 +0800 Subject: [PATCH 08/13] improve renderLeaf --- slate-mention-plugin/src/RenderLeaf.tsx | 14 +++++--------- slate-mention-plugin/src/index.ts | 1 + slate-mention-plugin/src/renderLeafFN.tsx | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 slate-mention-plugin/src/renderLeafFN.tsx diff --git a/slate-mention-plugin/src/RenderLeaf.tsx b/slate-mention-plugin/src/RenderLeaf.tsx index 61a2aba..0374bf9 100644 --- a/slate-mention-plugin/src/RenderLeaf.tsx +++ b/slate-mention-plugin/src/RenderLeaf.tsx @@ -1,17 +1,13 @@ import * as React from 'react' import {RenderLeafProps} from 'slate-react' -import {MENTION_LEAF} from './index' const RenderLeaf: React.FC = (props) => { console.log({props}) - if (props.leaf.type === MENTION_LEAF) { - return ( - - {props.children} - - ) - } - return null + return ( + + {props.children} + + ) } export default RenderLeaf diff --git a/slate-mention-plugin/src/index.ts b/slate-mention-plugin/src/index.ts index 517e72a..e597e6b 100644 --- a/slate-mention-plugin/src/index.ts +++ b/slate-mention-plugin/src/index.ts @@ -1,4 +1,5 @@ export const MENTION_LEAF = 'mention-leaf' +export {default as renderLeafFN} from './renderLeafFN' export {default as RenderLeaf} from './RenderLeaf' export {default as decorate} from './decorate' diff --git a/slate-mention-plugin/src/renderLeafFN.tsx b/slate-mention-plugin/src/renderLeafFN.tsx new file mode 100644 index 0000000..ea39b09 --- /dev/null +++ b/slate-mention-plugin/src/renderLeafFN.tsx @@ -0,0 +1,15 @@ +import * as React from 'react' +import {RenderLeafProps} from 'slate-react' +import RenderLeaf from './RenderLeaf' +import {MENTION_LEAF} from './index' + +const renderLeafFN = ( + props: RenderLeafProps +): null | React.ReactElement => { + if (props.leaf.type === MENTION_LEAF) { + return + } + return null +} + +export default renderLeafFN From 17e05427ff7f1a0f9f6daabff2e02bb4e0089ada Mon Sep 17 00:00:00 2001 From: surya darma Date: Sun, 3 Jan 2021 15:58:47 +0800 Subject: [PATCH 09/13] update --- playground/src/SlateMentionPlugin.tsx | 12 +++++- slate-mention-plugin/package.json | 2 +- slate-mention-plugin/src/MentionModal.tsx | 51 +++++++++++++++++++++++ slate-mention-plugin/src/RenderLeaf.tsx | 8 ++-- slate-mention-plugin/src/renderLeafFN.tsx | 5 ++- slate-mention-plugin/src/styles.css | 9 ++++ 6 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 slate-mention-plugin/src/MentionModal.tsx create mode 100644 slate-mention-plugin/src/styles.css diff --git a/playground/src/SlateMentionPlugin.tsx b/playground/src/SlateMentionPlugin.tsx index 9554915..ae91083 100644 --- a/playground/src/SlateMentionPlugin.tsx +++ b/playground/src/SlateMentionPlugin.tsx @@ -1,7 +1,9 @@ import {useState, useMemo, FC} from 'react' import {createEditor, Node} from 'slate' import {Slate, Editable, withReact, DefaultLeaf} from 'slate-react' -import {decorate, RenderLeaf} from 'slate-mention-plugin' +import {decorate, renderLeafFN} from 'slate-mention-plugin' + +// const user = const Editor: FC = () => { const editor = useMemo(() => withReact(createEditor()), []) @@ -24,7 +26,13 @@ const Editor: FC = () => { > { - return || + const mentionLeaf = renderLeafFN({ + fetchMention: (mention: string) => { + console.log({mention}) + return Promise.resolve([]) + }, + })(props) + return mentionLeaf || }} decorate={(entry) => { const range = decorate(editor)(entry) diff --git a/slate-mention-plugin/package.json b/slate-mention-plugin/package.json index 65fe55b..72fbb12 100644 --- a/slate-mention-plugin/package.json +++ b/slate-mention-plugin/package.json @@ -5,7 +5,7 @@ "author": "imdbsd", "license": "MIT", "scripts": { - "build": "rm -rf ./dist && tsc -p .", + "build": "rm -rf ./dist && tsc -p . && cp ./src/styles.css ./dist/styles.css", "prepublish": "rm -rf ./dist && yarn build", "publish:major": "yarn publish --major --message Release", "publish:patch": "yarn publish --patch --message 'Release patch'" diff --git a/slate-mention-plugin/src/MentionModal.tsx b/slate-mention-plugin/src/MentionModal.tsx new file mode 100644 index 0000000..2b65fd5 --- /dev/null +++ b/slate-mention-plugin/src/MentionModal.tsx @@ -0,0 +1,51 @@ +import * as React from 'react' +import './styles.css' + +type Suggestion = { + label: string + value: any +} + +export type FetchFN = (mentionAt: string) => Promise + +export type Props = { + fetchMention: FetchFN +} + +const MentionModal: React.FC = (props) => { + console.log({props}) + const [loading, setLoading] = React.useState(false) + const [suggestions, setSuggestions] = React.useState([]) + const fetchTimeout = React.useRef(null) + + const renderSuggestions = React.useCallback(() => { + if (loading) { + return 'loading...' + } + if (!loading && suggestions.length === 0) { + return 'not found.' + } + return 'render here' + }, [suggestions, loading]) + + React.useEffect(() => { + if (fetchTimeout.current) { + clearTimeout(fetchTimeout.current) + } + fetchTimeout.current = setTimeout(() => { + setLoading(true) + props.fetchMention(props.mentionAt).then((result) => { + setSuggestions(result) + }) + setLoading(false) + }, 500) + }, [props.mentionAt, props.fetchMention]) + + return ( +
+ {renderSuggestions()} +
+ ) +} + +export default MentionModal diff --git a/slate-mention-plugin/src/RenderLeaf.tsx b/slate-mention-plugin/src/RenderLeaf.tsx index 0374bf9..53d4609 100644 --- a/slate-mention-plugin/src/RenderLeaf.tsx +++ b/slate-mention-plugin/src/RenderLeaf.tsx @@ -1,11 +1,13 @@ import * as React from 'react' import {RenderLeafProps} from 'slate-react' +import MentionModal, {Props} from './MentionModal' -const RenderLeaf: React.FC = (props) => { - console.log({props}) +const RenderLeaf: React.FC = (props) => { + const mentionAt = props.leaf.text.substr(1) // removing '@' return ( - + {props.children} + ) } diff --git a/slate-mention-plugin/src/renderLeafFN.tsx b/slate-mention-plugin/src/renderLeafFN.tsx index ea39b09..f0eae03 100644 --- a/slate-mention-plugin/src/renderLeafFN.tsx +++ b/slate-mention-plugin/src/renderLeafFN.tsx @@ -1,13 +1,14 @@ import * as React from 'react' import {RenderLeafProps} from 'slate-react' import RenderLeaf from './RenderLeaf' +import {Props} from './MentionModal' import {MENTION_LEAF} from './index' -const renderLeafFN = ( +const renderLeafFN = (mentionProps: Props) => ( props: RenderLeafProps ): null | React.ReactElement => { if (props.leaf.type === MENTION_LEAF) { - return + return } return null } diff --git a/slate-mention-plugin/src/styles.css b/slate-mention-plugin/src/styles.css new file mode 100644 index 0000000..75d1def --- /dev/null +++ b/slate-mention-plugin/src/styles.css @@ -0,0 +1,9 @@ +.mention-modal { + min-width: 100px; + position: absolute; + left: 0; + border: 1px solid #cfcfcf; + background-color: white; + border-radius: 5px; + padding: 10px; +} From 832d52d3d10b5adf20c6d9ea64487f76abe09e90 Mon Sep 17 00:00:00 2001 From: imdbsd Date: Sun, 3 Jan 2021 22:05:03 +0800 Subject: [PATCH 10/13] bump --- slate-mention-plugin/package.json | 2 +- slate-mention-plugin/src/MentionModal.tsx | 51 ------------------- .../src/MentionModal/Loader.tsx | 5 ++ .../src/MentionModal/Modal.tsx | 41 +++++++++++++++ .../src/MentionModal/Suggestion.tsx | 5 ++ .../src/MentionModal/styles.css | 25 +++++++++ .../src/MentionModal/useFetchSuggestions.ts | 32 ++++++++++++ slate-mention-plugin/src/RenderLeaf.tsx | 7 ++- slate-mention-plugin/src/renderLeafFN.tsx | 2 +- slate-mention-plugin/src/styles.css | 9 ---- 10 files changed, 115 insertions(+), 64 deletions(-) delete mode 100644 slate-mention-plugin/src/MentionModal.tsx create mode 100644 slate-mention-plugin/src/MentionModal/Loader.tsx create mode 100644 slate-mention-plugin/src/MentionModal/Modal.tsx create mode 100644 slate-mention-plugin/src/MentionModal/Suggestion.tsx create mode 100644 slate-mention-plugin/src/MentionModal/styles.css create mode 100644 slate-mention-plugin/src/MentionModal/useFetchSuggestions.ts delete mode 100644 slate-mention-plugin/src/styles.css diff --git a/slate-mention-plugin/package.json b/slate-mention-plugin/package.json index 72fbb12..91d1f5f 100644 --- a/slate-mention-plugin/package.json +++ b/slate-mention-plugin/package.json @@ -5,7 +5,7 @@ "author": "imdbsd", "license": "MIT", "scripts": { - "build": "rm -rf ./dist && tsc -p . && cp ./src/styles.css ./dist/styles.css", + "build": "rm -rf ./dist && tsc -p . && cp ./src/MentionModal/styles.css ./dist/MentionModal/styles.css", "prepublish": "rm -rf ./dist && yarn build", "publish:major": "yarn publish --major --message Release", "publish:patch": "yarn publish --patch --message 'Release patch'" diff --git a/slate-mention-plugin/src/MentionModal.tsx b/slate-mention-plugin/src/MentionModal.tsx deleted file mode 100644 index 2b65fd5..0000000 --- a/slate-mention-plugin/src/MentionModal.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import * as React from 'react' -import './styles.css' - -type Suggestion = { - label: string - value: any -} - -export type FetchFN = (mentionAt: string) => Promise - -export type Props = { - fetchMention: FetchFN -} - -const MentionModal: React.FC = (props) => { - console.log({props}) - const [loading, setLoading] = React.useState(false) - const [suggestions, setSuggestions] = React.useState([]) - const fetchTimeout = React.useRef(null) - - const renderSuggestions = React.useCallback(() => { - if (loading) { - return 'loading...' - } - if (!loading && suggestions.length === 0) { - return 'not found.' - } - return 'render here' - }, [suggestions, loading]) - - React.useEffect(() => { - if (fetchTimeout.current) { - clearTimeout(fetchTimeout.current) - } - fetchTimeout.current = setTimeout(() => { - setLoading(true) - props.fetchMention(props.mentionAt).then((result) => { - setSuggestions(result) - }) - setLoading(false) - }, 500) - }, [props.mentionAt, props.fetchMention]) - - return ( -
- {renderSuggestions()} -
- ) -} - -export default MentionModal diff --git a/slate-mention-plugin/src/MentionModal/Loader.tsx b/slate-mention-plugin/src/MentionModal/Loader.tsx new file mode 100644 index 0000000..5d4e64f --- /dev/null +++ b/slate-mention-plugin/src/MentionModal/Loader.tsx @@ -0,0 +1,5 @@ +import * as React from 'react' + +const Loader = () =>
+ +export default Loader diff --git a/slate-mention-plugin/src/MentionModal/Modal.tsx b/slate-mention-plugin/src/MentionModal/Modal.tsx new file mode 100644 index 0000000..168426c --- /dev/null +++ b/slate-mention-plugin/src/MentionModal/Modal.tsx @@ -0,0 +1,41 @@ +import * as React from 'react' +import useFetchSuggestions from './useFetchSuggestions' +import Loader from './Loader' +import './styles.css' + +export type Suggestion = { + label: string + value: any +} + +export type FetchFN = (mentionAt: string) => Promise + +export type Props = { + fetchSuggestion: FetchFN +} + +const Modal: React.FC = (props) => { + console.log({props}) + const [loading, suggestions] = useFetchSuggestions( + props.fetchSuggestion, + props.mentionAt + ) + + const renderSuggestions = React.useCallback(() => { + if (loading) { + return + } + if (!loading && suggestions.length === 0) { + return 'not found.' + } + return 'render here' + }, [suggestions, loading]) + + return ( +
+ {renderSuggestions()} +
+ ) +} + +export default Modal diff --git a/slate-mention-plugin/src/MentionModal/Suggestion.tsx b/slate-mention-plugin/src/MentionModal/Suggestion.tsx new file mode 100644 index 0000000..61bf2e1 --- /dev/null +++ b/slate-mention-plugin/src/MentionModal/Suggestion.tsx @@ -0,0 +1,5 @@ +import * as React from 'react' + +const Suggestion = () => {} + +export default Suggestion diff --git a/slate-mention-plugin/src/MentionModal/styles.css b/slate-mention-plugin/src/MentionModal/styles.css new file mode 100644 index 0000000..9e7fe2b --- /dev/null +++ b/slate-mention-plugin/src/MentionModal/styles.css @@ -0,0 +1,25 @@ +.mention-modal { + min-width: 100px; + position: absolute; + left: 0; + border: 1px solid #cfcfcf; + background-color: white; + border-radius: 5px; + padding: 10px; + display: flex; + justify-content: center; +} + +.mention-modal__loader { + border: 5px solid #f3f3f3; /* Light grey */ + border-top: 5px solid #3498db; /* Blue */ + border-radius: 50%; + width: 15px; + height: 15px; + animation: spin 2s linear infinite; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} \ No newline at end of file diff --git a/slate-mention-plugin/src/MentionModal/useFetchSuggestions.ts b/slate-mention-plugin/src/MentionModal/useFetchSuggestions.ts new file mode 100644 index 0000000..2606824 --- /dev/null +++ b/slate-mention-plugin/src/MentionModal/useFetchSuggestions.ts @@ -0,0 +1,32 @@ +import * as React from 'react' +import {Suggestion, FetchFN} from './Modal' + +const useFetchSuggestions = ( + fetchSuggestion: FetchFN, + mentionAt: string +): [loading: boolean, suggestions: Suggestion[]] => { + const [loading, setLoading] = React.useState(false) + const [suggestions, setSuggestions] = React.useState([]) + const fetchTimeout = React.useRef() + + const handleFetchSuggestions = React.useCallback(() => { + setLoading(true) + fetchSuggestion(mentionAt).then((result) => { + setSuggestions(result) + }) + setLoading(false) + }, [fetchSuggestion, mentionAt]) + + React.useEffect(() => { + if (fetchTimeout.current) { + clearTimeout(fetchTimeout.current) + } + fetchTimeout.current = setTimeout(() => { + handleFetchSuggestions() + }, 500) + }, [handleFetchSuggestions]) + + return [loading, suggestions] +} + +export default useFetchSuggestions diff --git a/slate-mention-plugin/src/RenderLeaf.tsx b/slate-mention-plugin/src/RenderLeaf.tsx index 53d4609..22ffdb6 100644 --- a/slate-mention-plugin/src/RenderLeaf.tsx +++ b/slate-mention-plugin/src/RenderLeaf.tsx @@ -1,13 +1,16 @@ import * as React from 'react' import {RenderLeafProps} from 'slate-react' -import MentionModal, {Props} from './MentionModal' +import MentionModal, {Props} from './MentionModal/Modal' const RenderLeaf: React.FC = (props) => { const mentionAt = props.leaf.text.substr(1) // removing '@' return ( {props.children} - + ) } diff --git a/slate-mention-plugin/src/renderLeafFN.tsx b/slate-mention-plugin/src/renderLeafFN.tsx index f0eae03..4e346a8 100644 --- a/slate-mention-plugin/src/renderLeafFN.tsx +++ b/slate-mention-plugin/src/renderLeafFN.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import {RenderLeafProps} from 'slate-react' import RenderLeaf from './RenderLeaf' -import {Props} from './MentionModal' +import {Props} from './MentionModal/Modal' import {MENTION_LEAF} from './index' const renderLeafFN = (mentionProps: Props) => ( diff --git a/slate-mention-plugin/src/styles.css b/slate-mention-plugin/src/styles.css deleted file mode 100644 index 75d1def..0000000 --- a/slate-mention-plugin/src/styles.css +++ /dev/null @@ -1,9 +0,0 @@ -.mention-modal { - min-width: 100px; - position: absolute; - left: 0; - border: 1px solid #cfcfcf; - background-color: white; - border-radius: 5px; - padding: 10px; -} From 10dee4b72b84f96f8f59e400ed90aefa39c73763 Mon Sep 17 00:00:00 2001 From: imdbsd Date: Sun, 3 Jan 2021 23:22:52 +0800 Subject: [PATCH 11/13] bump --- .../src/MentionModal/Modal.tsx | 22 +++++----- .../src/MentionModal/Suggestion.tsx | 25 +++++++++++- .../src/MentionModal/styles.css | 40 ++++++++++++++++++- .../src/MentionModal/useFetchSuggestions.ts | 7 ++-- slate-mention-plugin/src/commands.ts | 3 ++ slate-mention-plugin/src/decorate.ts | 2 +- 6 files changed, 83 insertions(+), 16 deletions(-) create mode 100644 slate-mention-plugin/src/commands.ts diff --git a/slate-mention-plugin/src/MentionModal/Modal.tsx b/slate-mention-plugin/src/MentionModal/Modal.tsx index 168426c..cee55dc 100644 --- a/slate-mention-plugin/src/MentionModal/Modal.tsx +++ b/slate-mention-plugin/src/MentionModal/Modal.tsx @@ -1,21 +1,16 @@ import * as React from 'react' import useFetchSuggestions from './useFetchSuggestions' import Loader from './Loader' +import Suggestion, {SuggestionType} from './Suggestion' import './styles.css' -export type Suggestion = { - label: string - value: any -} - -export type FetchFN = (mentionAt: string) => Promise +export type FetchFN = (mentionAt: string) => Promise export type Props = { fetchSuggestion: FetchFN } const Modal: React.FC = (props) => { - console.log({props}) const [loading, suggestions] = useFetchSuggestions( props.fetchSuggestion, props.mentionAt @@ -26,9 +21,18 @@ const Modal: React.FC = (props) => { return } if (!loading && suggestions.length === 0) { - return 'not found.' + return not found... } - return 'render here' + return ( + + {suggestions.map((suggestion) => ( + + ))} + + ) }, [suggestions, loading]) return ( diff --git a/slate-mention-plugin/src/MentionModal/Suggestion.tsx b/slate-mention-plugin/src/MentionModal/Suggestion.tsx index 61bf2e1..d5ee596 100644 --- a/slate-mention-plugin/src/MentionModal/Suggestion.tsx +++ b/slate-mention-plugin/src/MentionModal/Suggestion.tsx @@ -1,5 +1,28 @@ import * as React from 'react' +import {insertMention} from '../commands' -const Suggestion = () => {} +export type SuggestionType = { + label: string + value: any +} + +type Props = SuggestionType + +const Suggestion: React.FC = (props) => { + const {label, value} = props + const handleOnClick = React.useCallback( + (event: React.MouseEvent) => { + event.preventDefault() + console.log({label, value}) + insertMention() + }, + [label, value] + ) + return ( +
+ {label} +
+ ) +} export default Suggestion diff --git a/slate-mention-plugin/src/MentionModal/styles.css b/slate-mention-plugin/src/MentionModal/styles.css index 9e7fe2b..98fcf59 100644 --- a/slate-mention-plugin/src/MentionModal/styles.css +++ b/slate-mention-plugin/src/MentionModal/styles.css @@ -8,6 +8,13 @@ padding: 10px; display: flex; justify-content: center; + margin-top: 5px; + flex-direction: column; +} + +.mention-modal__not-found { + color: gray; + font-family: inherit; } .mention-modal__loader { @@ -20,6 +27,35 @@ } @keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +.mention-modal__suggestion { + color: black; + font-family: inherit; + margin-left: -10px; + margin-right: -10px; + padding: 10px; +} + +.mention-modal__suggestion:first-child { + margin-top: -10px; + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} + +.mention-modal__suggestion:last-child { + margin-bottom: -10px; + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; +} + +.mention-modal__suggestion:hover { + background-color: #f3f3f3; + cursor: pointer; } \ No newline at end of file diff --git a/slate-mention-plugin/src/MentionModal/useFetchSuggestions.ts b/slate-mention-plugin/src/MentionModal/useFetchSuggestions.ts index 2606824..358cbfc 100644 --- a/slate-mention-plugin/src/MentionModal/useFetchSuggestions.ts +++ b/slate-mention-plugin/src/MentionModal/useFetchSuggestions.ts @@ -1,12 +1,13 @@ import * as React from 'react' -import {Suggestion, FetchFN} from './Modal' +import {FetchFN} from './Modal' +import {SuggestionType} from './Suggestion' const useFetchSuggestions = ( fetchSuggestion: FetchFN, mentionAt: string -): [loading: boolean, suggestions: Suggestion[]] => { +): [loading: boolean, suggestions: SuggestionType[]] => { const [loading, setLoading] = React.useState(false) - const [suggestions, setSuggestions] = React.useState([]) + const [suggestions, setSuggestions] = React.useState([]) const fetchTimeout = React.useRef() const handleFetchSuggestions = React.useCallback(() => { diff --git a/slate-mention-plugin/src/commands.ts b/slate-mention-plugin/src/commands.ts new file mode 100644 index 0000000..4a99324 --- /dev/null +++ b/slate-mention-plugin/src/commands.ts @@ -0,0 +1,3 @@ +import {Transforms} from 'slate' + +export const insertMention = () => {} diff --git a/slate-mention-plugin/src/decorate.ts b/slate-mention-plugin/src/decorate.ts index 363a9fb..1930747 100644 --- a/slate-mention-plugin/src/decorate.ts +++ b/slate-mention-plugin/src/decorate.ts @@ -18,7 +18,7 @@ const decorate = (editor: ReactEditor | Editor) => (entry: NodeEntry) => { { anchor: { ...editor.selection.anchor, - offset: editor.selection.anchor.offset - (mentionTo.length + 1), + offset: editor.selection.anchor.offset - mentionTo.length, }, focus: editor.selection.focus, type: MENTION_LEAF, From ef5e9cbce052a95354d8729544536a00db2b8821 Mon Sep 17 00:00:00 2001 From: imdbsd Date: Sun, 3 Jan 2021 23:32:35 +0800 Subject: [PATCH 12/13] update story --- playground/src/SlateMentionPlugin.tsx | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/playground/src/SlateMentionPlugin.tsx b/playground/src/SlateMentionPlugin.tsx index ae91083..129bca5 100644 --- a/playground/src/SlateMentionPlugin.tsx +++ b/playground/src/SlateMentionPlugin.tsx @@ -3,7 +3,17 @@ import {createEditor, Node} from 'slate' import {Slate, Editable, withReact, DefaultLeaf} from 'slate-react' import {decorate, renderLeafFN} from 'slate-mention-plugin' -// const user = +const users = ['Mallory', 'Amanda', 'Adele', 'Moira', 'Cassie'] +const fetchSuggestion = async (mention: string) => { + return users + .filter((user) => user.toLowerCase().indexOf(mention) !== -1) + .map((user) => ({ + label: user, + value: { + user, + }, + })) +} const Editor: FC = () => { const editor = useMemo(() => withReact(createEditor()), []) @@ -27,18 +37,11 @@ const Editor: FC = () => { { const mentionLeaf = renderLeafFN({ - fetchMention: (mention: string) => { - console.log({mention}) - return Promise.resolve([]) - }, + fetchSuggestion, })(props) return mentionLeaf || }} - decorate={(entry) => { - const range = decorate(editor)(entry) - console.log({range}) - return range - }} + decorate={decorate(editor)} /> ) From 50af04e5f938c2dfc570871f28e6b3195f4d3eeb Mon Sep 17 00:00:00 2001 From: surya darma Date: Sat, 6 Feb 2021 14:46:30 +0800 Subject: [PATCH 13/13] bump --- playground/.eslintcache | 2 +- .../src/MentionModal/Modal.tsx | 20 ++++++++++++ .../src/MentionModal/Suggestion.tsx | 15 ++++++--- slate-mention-plugin/src/commands.ts | 32 +++++++++++++++++-- slate-mention-plugin/src/index.ts | 1 + 5 files changed, 63 insertions(+), 7 deletions(-) diff --git a/playground/.eslintcache b/playground/.eslintcache index 54f6480..ac0517f 100644 --- a/playground/.eslintcache +++ b/playground/.eslintcache @@ -1 +1 @@ -[{"/Users/temporary/Works/personal/slate-plugin/playground/src/App.tsx":"1","/Users/temporary/Works/personal/slate-plugin/playground/src/Stories/SlateStringDeserialize.tsx":"2","/Users/temporary/Works/personal/slate-plugin/playground/src/Stories/Button.tsx":"3"},{"size":556,"mtime":1609048817928,"results":"4","hashOfConfig":"5"},{"size":598,"mtime":1609049567508,"results":"6","hashOfConfig":"5"},{"size":941,"mtime":1609050074641,"results":"7","hashOfConfig":"5"},{"filePath":"8","messages":"9","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"yzs728",{"filePath":"10","messages":"11","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12","messages":"13","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/Users/temporary/Works/personal/slate-plugin/playground/src/App.tsx",[],"/Users/temporary/Works/personal/slate-plugin/playground/src/Stories/SlateStringDeserialize.tsx",[],"/Users/temporary/Works/personal/slate-plugin/playground/src/Stories/Button.tsx",[]] \ No newline at end of file +[{"/Users/temporary/Works/personal/slate-plugin/playground/src/SlateMentionPlugin.stories.tsx":"1","/Users/temporary/Works/personal/slate-plugin/playground/src/SlatePasteUrl.stories.tsx":"2","/Users/temporary/Works/personal/slate-plugin/playground/src/SlateStringDeserialize.stories.tsx":"3","/Users/temporary/Works/personal/slate-plugin/playground/src/SlateStringDeserialize.tsx":"4","/Users/temporary/Works/personal/slate-plugin/playground/src/SlatePasteUrl.tsx":"5","/Users/temporary/Works/personal/slate-plugin/playground/src/SlateMentionPlugin.tsx":"6"},{"size":326,"mtime":1609569098831,"results":"7","hashOfConfig":"8"},{"size":444,"mtime":1609567894988,"results":"9","hashOfConfig":"8"},{"size":543,"mtime":1609054016105,"results":"10","hashOfConfig":"8"},{"size":788,"mtime":1609054016105,"results":"11","hashOfConfig":"8"},{"size":2425,"mtime":1609567894989,"results":"12","hashOfConfig":"8"},{"size":1188,"mtime":1609772574601,"results":"13","hashOfConfig":"8"},{"filePath":"14","messages":"15","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"16"},"1wli3a0",{"filePath":"17","messages":"18","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"16"},{"filePath":"19","messages":"20","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"16"},{"filePath":"21","messages":"22","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"16"},{"filePath":"23","messages":"24","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"25"},{"filePath":"26","messages":"27","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"16"},"/Users/temporary/Works/personal/slate-plugin/playground/src/SlateMentionPlugin.stories.tsx",[],["28","29"],"/Users/temporary/Works/personal/slate-plugin/playground/src/SlatePasteUrl.stories.tsx",[],"/Users/temporary/Works/personal/slate-plugin/playground/src/SlateStringDeserialize.stories.tsx",[],"/Users/temporary/Works/personal/slate-plugin/playground/src/SlateStringDeserialize.tsx",[],"/Users/temporary/Works/personal/slate-plugin/playground/src/SlatePasteUrl.tsx",["30"],"import {useState, useMemo, FC} from 'react'\nimport {createEditor, Node} from 'slate'\nimport {Slate, Editable, withReact, DefaultElement} from 'slate-react'\nimport {usePasteUrl, Options} from 'slate-paste-url-plugin'\n\nexport type Props = {\n defaultType?: string\n patterns?:\n | {capture: string; type?: string}\n | {capture: string; type?: string}[]\n}\n\nconst Editor: FC = (props) => {\n const options: Options = {\n defaultType: props.defaultType,\n patterns: props.patterns\n ? Array.isArray(props.patterns)\n ? props.patterns.map((pattern) => ({\n type: pattern.type,\n capture: new RegExp(pattern.capture, 'i'),\n }))\n : {\n type: props.patterns.type,\n capture: new RegExp(props.patterns.capture, 'i'),\n }\n : undefined,\n }\n const withPasteUrl = usePasteUrl(options)\n const editor = useMemo(() => withPasteUrl(withReact(createEditor())), [])\n const [value, setValue] = useState([\n {\n type: 'paragraph',\n children: [\n {\n text: `Slate paste url example, try block some text and paste url or github url to the blocked text.\n `,\n },\n ],\n },\n {\n type: 'paragraph',\n children: [\n {\n text:\n 'To change how the url rendered, edit the renderElement in SlatePasteUrl.tsx',\n },\n ],\n },\n ])\n\n return (\n setValue(newValue)}\n >\n {\n switch (props.element.type) {\n case 'link': {\n return (\n \n {props.children}\n \n )\n }\n case 'github_link': {\n return (\n \n {props.children}\n \n )\n }\n default: {\n return \n }\n }\n }}\n />\n \n )\n}\n\nexport default Editor\n","/Users/temporary/Works/personal/slate-plugin/playground/src/SlateMentionPlugin.tsx",[],{"ruleId":"31","replacedBy":"32"},{"ruleId":"33","replacedBy":"34"},{"ruleId":"35","severity":1,"message":"36","line":29,"column":73,"nodeType":"37","endLine":29,"endColumn":75,"suggestions":"38"},"no-native-reassign",["39"],"no-negated-in-lhs",["40"],"react-hooks/exhaustive-deps","React Hook useMemo has a missing dependency: 'withPasteUrl'. Either include it or remove the dependency array.","ArrayExpression",["41"],"no-global-assign","no-unsafe-negation",{"desc":"42","fix":"43"},"Update the dependencies array to be: [withPasteUrl]",{"range":"44","text":"45"},[939,941],"[withPasteUrl]"] \ No newline at end of file diff --git a/slate-mention-plugin/src/MentionModal/Modal.tsx b/slate-mention-plugin/src/MentionModal/Modal.tsx index cee55dc..ec3de37 100644 --- a/slate-mention-plugin/src/MentionModal/Modal.tsx +++ b/slate-mention-plugin/src/MentionModal/Modal.tsx @@ -1,8 +1,10 @@ import * as React from 'react' +import {useEditor} from 'slate-react' import useFetchSuggestions from './useFetchSuggestions' import Loader from './Loader' import Suggestion, {SuggestionType} from './Suggestion' import './styles.css' +import {Editor} from 'slate' export type FetchFN = (mentionAt: string) => Promise @@ -11,6 +13,23 @@ export type Props = { } const Modal: React.FC = (props) => { + const editor = useEditor() + const mentionPathRef = React.useMemo(() => { + if (editor.selection) { + return Editor.rangeRef( + editor, + { + anchor: editor.selection.anchor, + focus: editor.selection.focus, + type: 'mention-ref', + }, + { + affinity: 'inward', + } + ) + } + }, [editor]) + console.log({mentionPathRef}) const [loading, suggestions] = useFetchSuggestions( props.fetchSuggestion, props.mentionAt @@ -28,6 +47,7 @@ const Modal: React.FC = (props) => { {suggestions.map((suggestion) => ( ))} diff --git a/slate-mention-plugin/src/MentionModal/Suggestion.tsx b/slate-mention-plugin/src/MentionModal/Suggestion.tsx index d5ee596..739b614 100644 --- a/slate-mention-plugin/src/MentionModal/Suggestion.tsx +++ b/slate-mention-plugin/src/MentionModal/Suggestion.tsx @@ -1,4 +1,6 @@ import * as React from 'react' +import {RangeRef} from 'slate' +import {useEditor, useSlate} from 'slate-react' import {insertMention} from '../commands' export type SuggestionType = { @@ -6,17 +8,22 @@ export type SuggestionType = { value: any } -type Props = SuggestionType +type Props = SuggestionType & { + mentionAt: string +} const Suggestion: React.FC = (props) => { - const {label, value} = props + const {label, value, mentionAt} = props + const editor = useEditor() + console.log('editor: ', editor.selection) const handleOnClick = React.useCallback( (event: React.MouseEvent) => { event.preventDefault() console.log({label, value}) - insertMention() + console.log('editor on click', editor.selection) + insertMention(editor, mentionAt, label, value) }, - [label, value] + [label, value, editor] ) return (
diff --git a/slate-mention-plugin/src/commands.ts b/slate-mention-plugin/src/commands.ts index 4a99324..0c776ef 100644 --- a/slate-mention-plugin/src/commands.ts +++ b/slate-mention-plugin/src/commands.ts @@ -1,3 +1,31 @@ -import {Transforms} from 'slate' +import {Transforms, Editor} from 'slate' +import {MENTION_ELEMENT} from './index' -export const insertMention = () => {} +export const insertMention = ( + editor: Editor, + mentionAt: string, + text: string, + mentionValue: any +) => { + console.log(editor.selection) + if (editor.selection) { + Transforms.delete(editor, { + at: { + anchor: { + path: editor.selection.anchor.path, + offset: editor.selection.anchor.offset - (mentionAt.length + 1), + }, + focus: editor.selection.focus, + }, + }) + Transforms.insertNodes(editor, { + type: MENTION_ELEMENT, + mentionValue, + children: [ + { + text, + }, + ], + }) + } +} diff --git a/slate-mention-plugin/src/index.ts b/slate-mention-plugin/src/index.ts index e597e6b..a09d645 100644 --- a/slate-mention-plugin/src/index.ts +++ b/slate-mention-plugin/src/index.ts @@ -1,4 +1,5 @@ export const MENTION_LEAF = 'mention-leaf' +export const MENTION_ELEMENT = 'mention-element' export {default as renderLeafFN} from './renderLeafFN' export {default as RenderLeaf} from './RenderLeaf'