From 40425963ee15ac4009cc3f930cecb8ef49f6768f Mon Sep 17 00:00:00 2001 From: Yuurilee Date: Sat, 3 Apr 2021 22:29:12 +0900 Subject: [PATCH 01/10] =?UTF-8?q?Chore:=20draft-js=20package=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 ++ yarn.lock | 71 +++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index d9668f98..cc11e915 100644 --- a/package.json +++ b/package.json @@ -55,9 +55,11 @@ "@storybook/addon-links": "^6.1.21", "@storybook/preset-create-react-app": "^3.1.7", "@storybook/react": "^6.1.21", + "@types/draft-js": "^0.11.1", "@types/react": "^17.0.2", "@types/react-dom": "^17.0.1", "@types/react-router-dom": "^5.1.7", + "draft-js": "^0.11.7", "eslint-config-naver": "^2.1.0", "eslint-config-prettier": "^8.1.0", "eslint-plugin-prettier": "^3.3.1", diff --git a/yarn.lock b/yarn.lock index e8610d6d..d52e7b15 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2713,6 +2713,14 @@ resolved "https://registry.yarnpkg.com/@types/braces/-/braces-3.0.0.tgz#7da1c0d44ff1c7eb660a36ec078ea61ba7eb42cb" integrity sha512-TbH79tcyi9FHwbyboOKeRachRq63mSuWYXOflsNO9ZyE5ClQ/JaozNKl+aWUq87qPNsXasXxi2AbgfwIJ+8GQw== +"@types/draft-js@^0.11.1": + version "0.11.1" + resolved "https://registry.yarnpkg.com/@types/draft-js/-/draft-js-0.11.1.tgz#f67920c9583054143e263704e250dd3086de3ef3" + integrity sha512-jV4LAXYdVvS0ahIROZehkKqHgfLxaDBl3fzfEVqho8NxFAtEaObdIiu7FpPUu/Y97PlJVxGajar7aSikQqz9sQ== + dependencies: + "@types/react" "*" + immutable "~3.7.4" + "@types/eslint@^7.2.6": version "7.2.6" resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.2.6.tgz#5e9aff555a975596c03a98b59ecd103decc70c3c" @@ -3679,7 +3687,7 @@ arrify@^2.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== -asap@~2.0.6: +asap@~2.0.3, asap@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= @@ -5268,6 +5276,11 @@ core-js@^3.0.1, core-js@^3.0.4: resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.9.1.tgz#cec8de593db8eb2a85ffb0dbdeb312cb6e5460ae" integrity sha512-gSjRvzkxQc1zjM/5paAmL4idJBFzuJoo+jDjF1tStYFMV2ERfD02HhahhCGXUyHxQRG4yFKVSdO6g62eoRMcDg== +core-js@^3.6.4: + version "3.10.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.10.0.tgz#9a020547c8b6879f929306949e31496bbe2ae9b3" + integrity sha512-MQx/7TLgmmDVamSyfE+O+5BHvG1aUGj/gHhLn1wVtm2B5u1eVIPvh7vkfjwWKNCjrTJB8+He99IntSQ1qP+vYQ== + core-js@^3.6.5: version "3.9.0" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.9.0.tgz#790b1bb11553a2272b36e2625c7179db345492f8" @@ -5374,6 +5387,13 @@ create-react-context@0.3.0: gud "^1.0.0" warning "^4.0.3" +cross-fetch@^3.0.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39" + integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ== + dependencies: + node-fetch "2.6.1" + cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.2: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -6099,6 +6119,15 @@ downshift@^6.0.6: prop-types "^15.7.2" react-is "^17.0.1" +draft-js@^0.11.7: + version "0.11.7" + resolved "https://registry.yarnpkg.com/draft-js/-/draft-js-0.11.7.tgz#be293aaa255c46d8a6647f3860aa4c178484a206" + integrity sha512-ne7yFfN4sEL82QPQEn80xnADR8/Q6ALVworbC5UOSzOvjffmYfFsr3xSZtxbIirti14R7Y33EZC5rivpLgIbsg== + dependencies: + fbjs "^2.0.0" + immutable "~3.7.4" + object-assign "^4.1.1" + duplexer@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" @@ -7018,6 +7047,25 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" +fbjs-css-vars@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8" + integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== + +fbjs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-2.0.0.tgz#01fb812138d7e31831ed3e374afe27b9169ef442" + integrity sha512-8XA8ny9ifxrAWlyhAbexXcs3rRMtxWcs3M0lctLfB49jRDHiaxj+Mo0XxbwE7nKZYzgCFoq64FS+WFd4IycPPQ== + dependencies: + core-js "^3.6.4" + cross-fetch "^3.0.4" + fbjs-css-vars "^1.0.0" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.18" + figgy-pudding@^3.5.1: version "3.5.2" resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" @@ -8114,6 +8162,11 @@ immer@8.0.1: resolved "https://registry.yarnpkg.com/immer/-/immer-8.0.1.tgz#9c73db683e2b3975c424fb0572af5889877ae656" integrity sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA== +immutable@~3.7.4: + version "3.7.6" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b" + integrity sha1-E7TTyxK++hVIKib+Gy665kAHHks= + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" @@ -10307,7 +10360,7 @@ node-dir@^0.1.10: dependencies: minimatch "^3.0.2" -node-fetch@^2.6.0: +node-fetch@2.6.1, node-fetch@^2.6.0: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== @@ -11865,6 +11918,13 @@ promise.prototype.finally@^3.1.0: es-abstract "^1.17.0-next.0" function-bind "^1.1.1" +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + promise@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/promise/-/promise-8.1.0.tgz#697c25c3dfe7435dd79fcd58c38a135888eaf05e" @@ -13247,7 +13307,7 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" -setimmediate@^1.0.4: +setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= @@ -14434,6 +14494,11 @@ typescript@4.1.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== +ua-parser-js@^0.7.18: + version "0.7.27" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.27.tgz#b54f8ce9eb6c7abf3584edeaf9a3d8b3bd92edba" + integrity sha512-eXMaRYK2skomGocoX0x9sBXzx5A1ZVQgXfrW4mTc8dT0zS7olEcyfudAzRC5tIIRgLxQ69B6jut3DI+n5hslPA== + unbox-primitive@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" From 002e78fa8d74ea02091913a4f540f011cc76992d Mon Sep 17 00:00:00 2001 From: Yuurilee Date: Sat, 3 Apr 2021 22:38:37 +0900 Subject: [PATCH 02/10] =?UTF-8?q?Chore:=20@draft-js-plugins/editor=20packa?= =?UTF-8?q?ge=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + yarn.lock | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/package.json b/package.json index cc11e915..64087ec0 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ ] }, "devDependencies": { + "@draft-js-plugins/editor": "^4.1.0", "@storybook/addon-actions": "^6.1.21", "@storybook/addon-docs": "^6.1.21", "@storybook/addon-knobs": "^6.1.21", diff --git a/yarn.lock b/yarn.lock index d52e7b15..82901c7a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1448,6 +1448,14 @@ resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-10.1.0.tgz#f0950bba18819512d42f7197e56c518aa491cf18" integrity sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg== +"@draft-js-plugins/editor@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@draft-js-plugins/editor/-/editor-4.1.0.tgz#1861fb257ba51ecbd031b8a3d84ee0809de1504e" + integrity sha512-i95uGF1GOFwP99qRCjtocGAYanULtkX9/XPeXKwjKx65vnOt/0dvBBdSvzSgrJ9pncHHLUqDfFQKXy/09fTmvg== + dependencies: + immutable "~3.7.4" + prop-types "^15.5.8" + "@emotion/cache@^10.0.27", "@emotion/cache@^10.0.9": version "10.0.29" resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0" From c7021225325546141b4135197f80cbc867828da5 Mon Sep 17 00:00:00 2001 From: Yuurilee Date: Sat, 3 Apr 2021 22:49:00 +0900 Subject: [PATCH 03/10] =?UTF-8?q?Feat:=20Pattern=20component=EC=97=90=20Ed?= =?UTF-8?q?itor=20component=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/CreateDesign/Pattern/index.tsx | 26 ++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/pages/CreateDesign/Pattern/index.tsx b/src/pages/CreateDesign/Pattern/index.tsx index d8bbfacf..fcb6449c 100644 --- a/src/pages/CreateDesign/Pattern/index.tsx +++ b/src/pages/CreateDesign/Pattern/index.tsx @@ -1,7 +1,29 @@ -import React from 'react'; +import Editor from '@draft-js-plugins/editor'; +import { EditorState } from 'draft-js'; +import { useRef, useState } from 'react'; const Pattern = (): React.ReactElement => { - return
도안 작성 페이지
; + const [editorState, setEditorState] = useState( + EditorState.createEmpty(), + ); + const editor = useRef(null); + + const focusEditor = (): void => { + editor?.current?.focus(); + }; + + return ( +
+
+ +
+
+ ); }; export default Pattern; From c8ae3ad6eb43fbb72b37e9d84d8f6b3829e66b8d Mon Sep 17 00:00:00 2001 From: Yuurilee Date: Sun, 4 Apr 2021 00:01:36 +0900 Subject: [PATCH 04/10] =?UTF-8?q?Design:=20Editor=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/dumbs/Layout/index.tsx | 16 +++++-- src/pages/CreateDesign/Pattern/index.tsx | 55 +++++++++++++++++++----- 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/dumbs/Layout/index.tsx b/src/dumbs/Layout/index.tsx index b656b9f6..8f5b1a76 100644 --- a/src/dumbs/Layout/index.tsx +++ b/src/dumbs/Layout/index.tsx @@ -1,5 +1,6 @@ import React from 'react'; import styled from 'styled-components'; +import { theme } from 'themes'; interface Props { children: React.ReactNode; @@ -7,14 +8,21 @@ interface Props { const Content = styled.section` max-width: 1100px; - margin: 36px auto; + height: 100vh; + display: flex; + margin: auto; + + > div { + margin: ${theme.spacing(4)} 0; + width: 100%; + } `; const Layout = ({ children }: Props): React.ReactElement => { return ( - <> - {children} - + +
{children}
+
); }; diff --git a/src/pages/CreateDesign/Pattern/index.tsx b/src/pages/CreateDesign/Pattern/index.tsx index fcb6449c..872e5bbe 100644 --- a/src/pages/CreateDesign/Pattern/index.tsx +++ b/src/pages/CreateDesign/Pattern/index.tsx @@ -1,11 +1,46 @@ import Editor from '@draft-js-plugins/editor'; import { EditorState } from 'draft-js'; import { useRef, useState } from 'react'; +import styled, { css } from 'styled-components'; +import { theme } from 'themes'; +import { palette } from 'themes/palatte'; + +interface EditorWrapperProps { + isFocused: boolean; +} + +const EditorWrapper = styled.div` + min-height: 50%; + padding: ${theme.spacing(1.5)}; + margin: ${theme.spacing(4, 1.5)}; + border: 1.5px solid transparent; + border-radius: ${theme.spacing(1)}; + background: ${palette.grey[200]}; + + ${({ isFocused }) => + isFocused && + css` + border: 1.5px solid ${palette.grey[400]}; + `} + + .public-DraftEditorPlaceholder-root { + display: inline; + div { + display: inline; + } + color: ${palette.action.active}; + } + + .DraftEditor-editorContainer { + display: inline-block; + } +`; const Pattern = (): React.ReactElement => { const [editorState, setEditorState] = useState( EditorState.createEmpty(), ); + const [isFocused, setIsFocused] = useState(false); const editor = useRef(null); const focusEditor = (): void => { @@ -13,16 +48,16 @@ const Pattern = (): React.ReactElement => { }; return ( -
-
- -
-
+ + setIsFocused(true)} + onBlur={(): void => setIsFocused(false)} + placeholder="도안을 입력하세요" + /> + ); }; From ab9dcf4ce509a045525eabfdb4f364a9ac988332 Mon Sep 17 00:00:00 2001 From: Yuurilee Date: Sun, 4 Apr 2021 04:44:28 +0900 Subject: [PATCH 05/10] =?UTF-8?q?Feat:=20=EC=88=AB=EC=9E=90=20+=20?= =?UTF-8?q?=EB=8B=A8=EC=9C=84=EB=A5=BC=20=EC=9E=85=EB=A0=A5=EC=8B=9C=20?= =?UTF-8?q?=EC=8A=A4=ED=83=80=EC=9D=BC=EC=9D=B4=20=EC=BB=A4=EC=8A=A4?= =?UTF-8?q?=ED=85=80=EB=90=98=EB=8A=94=20UnitDecorator=20plugin=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/unitDecorator/index.tsx | 34 +++++++ src/plugins/unitDecorator/types.ts | 11 +++ src/plugins/unitDecorator/unitDecorator.tsx | 92 +++++++++++++++++++ .../unitDecorator/unitDecoratorStrategy.ts | 18 ++++ .../utils/extractUnitDecorator.ts | 50 ++++++++++ .../unitDecorator/utils/unitDecoratorRegex.ts | 13 +++ 6 files changed, 218 insertions(+) create mode 100644 src/plugins/unitDecorator/index.tsx create mode 100644 src/plugins/unitDecorator/types.ts create mode 100644 src/plugins/unitDecorator/unitDecorator.tsx create mode 100644 src/plugins/unitDecorator/unitDecoratorStrategy.ts create mode 100644 src/plugins/unitDecorator/utils/extractUnitDecorator.ts create mode 100644 src/plugins/unitDecorator/utils/unitDecoratorRegex.ts diff --git a/src/plugins/unitDecorator/index.tsx b/src/plugins/unitDecorator/index.tsx new file mode 100644 index 00000000..4d7a7e7b --- /dev/null +++ b/src/plugins/unitDecorator/index.tsx @@ -0,0 +1,34 @@ +import { EditorPlugin } from '@draft-js-plugins/editor'; +import { ContentBlock } from 'draft-js'; +import { ComponentType, ReactElement } from 'react'; + +import UnitDecorator, { UnitDecoratorProps } from './unitDecorator'; +import unitDecoratorStrategy from './unitDecoratorStrategy'; + +export type { UnitDecoratorProps }; +export interface UnitDecoratorPluginConfig { + unit?: string; + unitDecoratorComponent?: ComponentType; +} + +export default (config: UnitDecoratorPluginConfig = {}): EditorPlugin => { + const { + unit = '#', + unitDecoratorComponent: UnitDecoratorComponent = UnitDecorator, + } = config; + const DecoratedUnitDecorator = (props: UnitDecoratorProps): ReactElement => ( + + ); + + return { + decorators: [ + { + strategy: ( + contentBlock: ContentBlock, + callback: (begin: number, end: number) => void, + ) => unitDecoratorStrategy(unit, contentBlock, callback), + component: DecoratedUnitDecorator, + }, + ], + }; +}; diff --git a/src/plugins/unitDecorator/types.ts b/src/plugins/unitDecorator/types.ts new file mode 100644 index 00000000..2b078091 --- /dev/null +++ b/src/plugins/unitDecorator/types.ts @@ -0,0 +1,11 @@ +export const CustomInline = { + NOT_CALCULATE: 'NOT_CALCULATE', +}; + +export const UnitDecoratorStyleMap = { + NOT_CALCULATE: { + background: 'transparent', + margin: '0', + padding: '0', + }, +}; diff --git a/src/plugins/unitDecorator/unitDecorator.tsx b/src/plugins/unitDecorator/unitDecorator.tsx new file mode 100644 index 00000000..0ac7becb --- /dev/null +++ b/src/plugins/unitDecorator/unitDecorator.tsx @@ -0,0 +1,92 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { ContentState, EditorState, RichUtils } from 'draft-js'; +import { ReactElement, ReactNode } from 'react'; +import styled from 'styled-components'; +import { theme } from 'themes'; +import { palette } from 'themes/palatte'; + +import { CustomInline } from './types'; + +export interface UnitDecoratorProps { + className?: string; + children?: ReactNode; + + unit?: string; + decoratedText?: string; + dir?: null; + entityKey?: string | null; + offsetKey?: string; + contentState?: ContentState; + blockKey?: string; + start?: number; + end?: number; + + setEditorState?(editorState: EditorState): void; + getEditorState?(): EditorState; +} + +const DecoratorWrapper = styled.span` + > span { + background: ${palette.grey[400]}; + margin: ${theme.spacing(0, 0.5)}; + padding: ${theme.spacing(0.5, 1)}; + border-radius: ${theme.spacing(1)}; + cursor: pointer; + } +`; + +export default function UnitDecorator(props: UnitDecoratorProps): ReactElement { + const { + className, + children, + unit, + decoratedText, + dir, + entityKey, + getEditorState, + offsetKey, + setEditorState, + contentState, + blockKey, + start, + end, + ...otherProps + } = props; + + const handleClick = (): void => { + const editorState = getEditorState?.(); + + if (editorState != null && children != null && setEditorState != null) { + const selectionState = editorState.getSelection(); + const newSelection = selectionState.merge({ + anchorOffset: start, + focusOffset: end, + }); + + const editorStateWithNewSelection = EditorState.forceSelection( + editorState, + newSelection, + ); + const editorStateWithStyles = RichUtils.toggleInlineStyle( + editorStateWithNewSelection, + CustomInline.NOT_CALCULATE, + ); + const editorStateWithStylesAndPreviousSelection = EditorState.forceSelection( + editorStateWithStyles, + selectionState, + ); + + setEditorState(editorStateWithStylesAndPreviousSelection); + } + }; + + return ( + + {children} + + ); +} diff --git a/src/plugins/unitDecorator/unitDecoratorStrategy.ts b/src/plugins/unitDecorator/unitDecoratorStrategy.ts new file mode 100644 index 00000000..18cdaec9 --- /dev/null +++ b/src/plugins/unitDecorator/unitDecoratorStrategy.ts @@ -0,0 +1,18 @@ +import { ContentBlock } from 'draft-js'; + +import { extractUnitDecoratorsWithIndices } from './utils/extractUnitDecorator'; + +export default ( + unit: string, + contentBlock: ContentBlock, + callback: (begin: number, end: number) => void, +): void => { + const text = contentBlock.getText(); + const results = extractUnitDecoratorsWithIndices(unit, text); + + results.forEach((unitDecorator) => { + const { indices } = unitDecorator; + + callback(indices[0], indices[1]); + }); +}; diff --git a/src/plugins/unitDecorator/utils/extractUnitDecorator.ts b/src/plugins/unitDecorator/utils/extractUnitDecorator.ts new file mode 100644 index 00000000..2ebee2ab --- /dev/null +++ b/src/plugins/unitDecorator/utils/extractUnitDecorator.ts @@ -0,0 +1,50 @@ +import { + getEndHashtagMatch, + getHashSigns, + getUnitDecoratorBoundary, +} from './unitDecoratorRegex'; + +interface UnitDecoratorIndice { + unitDecorator: string; + indices: [number, number]; +} + +export function extractUnitDecoratorsWithIndices( + unit: string, + text: string, +): UnitDecoratorIndice[] { + if (!text || !text.match(getHashSigns(unit))) { + return []; + } + + const tags: UnitDecoratorIndice[] = []; + + function replacer( + match: string, + before: string, + _hash: string, + hashText: string, + offset: number, + chunk: string, + ): string { + const after = chunk.slice(offset + match.length); + + if (after.match(getEndHashtagMatch(unit))) { + return ''; + } + + const startPosition = offset + before.length; + const endPosition = + startPosition + (offset === 0 ? match.length : match.length - 1); + + tags.push({ + unitDecorator: hashText, + indices: [startPosition, endPosition], + }); + return ''; + } + + text.replace(getUnitDecoratorBoundary(unit), replacer); + + return tags; +} diff --git a/src/plugins/unitDecorator/utils/unitDecoratorRegex.ts b/src/plugins/unitDecorator/utils/unitDecoratorRegex.ts new file mode 100644 index 00000000..64d13c15 --- /dev/null +++ b/src/plugins/unitDecorator/utils/unitDecoratorRegex.ts @@ -0,0 +1,13 @@ +/* eslint-disable */ +const numbers = '0-9'; + +export const getEndHashtagMatch = (unit: string) => + new RegExp(`^(?:[${numbers}]+[${unit}]|:\/\/)`); + +export const getHashSigns = (unit: string) => new RegExp(unit); + +export const getUnitDecoratorBoundary = (unit: string) => + new RegExp( + `((?:^|$|[^${numbers}]))([${numbers}]*)([${numbers}]+[${unit}])`, + 'gi', + ); From 2e60740defb22bf69f2169cfbfcafdcd9682f325 Mon Sep 17 00:00:00 2001 From: Yuurilee Date: Sun, 4 Apr 2021 04:48:57 +0900 Subject: [PATCH 06/10] =?UTF-8?q?Feat:=20Pattern=20component=EC=97=90=20un?= =?UTF-8?q?itDecorator=20plugin=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/CreateDesign/Pattern/index.tsx | 35 +++++++++++++++++------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/pages/CreateDesign/Pattern/index.tsx b/src/pages/CreateDesign/Pattern/index.tsx index 872e5bbe..73177eb9 100644 --- a/src/pages/CreateDesign/Pattern/index.tsx +++ b/src/pages/CreateDesign/Pattern/index.tsx @@ -1,10 +1,15 @@ import Editor from '@draft-js-plugins/editor'; import { EditorState } from 'draft-js'; +import createUnitDecoratorPlugin from 'plugins/unitDecorator'; +import { UnitDecoratorStyleMap } from 'plugins/unitDecorator/types'; import { useRef, useState } from 'react'; import styled, { css } from 'styled-components'; import { theme } from 'themes'; import { palette } from 'themes/palatte'; +const stitcheDecoratorPlugin = createUnitDecoratorPlugin({ unit: '코' }); +const rowDecoratorPlugin = createUnitDecoratorPlugin({ unit: '단' }); + interface EditorWrapperProps { isFocused: boolean; } @@ -43,21 +48,31 @@ const Pattern = (): React.ReactElement => { const [isFocused, setIsFocused] = useState(false); const editor = useRef(null); + const plugins = [stitcheDecoratorPlugin, rowDecoratorPlugin]; + const focusEditor = (): void => { editor?.current?.focus(); }; + const customStyleMap = { + ...UnitDecoratorStyleMap, + }; + return ( - - setIsFocused(true)} - onBlur={(): void => setIsFocused(false)} - placeholder="도안을 입력하세요" - /> - + <> + + setIsFocused(true)} + onBlur={(): void => setIsFocused(false)} + placeholder="도안을 입력하세요" + /> + + ); }; From 05644e52a6bc1f993874c6ad30eb6cba491dfd0d Mon Sep 17 00:00:00 2001 From: Yuurilee Date: Tue, 6 Apr 2021 23:22:45 +0900 Subject: [PATCH 07/10] =?UTF-8?q?Refactor:=20unitDecorator=20unit=20defaul?= =?UTF-8?q?tValue=20"=EC=BD=94"=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/unitDecorator/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/unitDecorator/index.tsx b/src/plugins/unitDecorator/index.tsx index 4d7a7e7b..5f855254 100644 --- a/src/plugins/unitDecorator/index.tsx +++ b/src/plugins/unitDecorator/index.tsx @@ -13,7 +13,7 @@ export interface UnitDecoratorPluginConfig { export default (config: UnitDecoratorPluginConfig = {}): EditorPlugin => { const { - unit = '#', + unit = '코', unitDecoratorComponent: UnitDecoratorComponent = UnitDecorator, } = config; const DecoratedUnitDecorator = (props: UnitDecoratorProps): ReactElement => ( From 369babdb880707ff46d09b3e184bb1d8d6c5e3b5 Mon Sep 17 00:00:00 2001 From: Yuurilee Date: Tue, 6 Apr 2021 23:23:54 +0900 Subject: [PATCH 08/10] =?UTF-8?q?Refactor:=20unitDecorator=20entityKey=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95,=20=ED=95=84=EC=9A=94?= =?UTF-8?q?=EC=97=86=EB=8A=94=20dir=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/unitDecorator/unitDecorator.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/unitDecorator/unitDecorator.tsx b/src/plugins/unitDecorator/unitDecorator.tsx index 0ac7becb..19de2e92 100644 --- a/src/plugins/unitDecorator/unitDecorator.tsx +++ b/src/plugins/unitDecorator/unitDecorator.tsx @@ -13,8 +13,7 @@ export interface UnitDecoratorProps { unit?: string; decoratedText?: string; - dir?: null; - entityKey?: string | null; + entityKey?: string; offsetKey?: string; contentState?: ContentState; blockKey?: string; @@ -41,7 +40,6 @@ export default function UnitDecorator(props: UnitDecoratorProps): ReactElement { children, unit, decoratedText, - dir, entityKey, getEditorState, offsetKey, From 2118b17f98365b309c256b4c05e24bdf3c47505e Mon Sep 17 00:00:00 2001 From: Yuurilee Date: Tue, 6 Apr 2021 23:24:49 +0900 Subject: [PATCH 09/10] =?UTF-8?q?Refactor:=20unitDecoratorRegex=20-=20esli?= =?UTF-8?q?nt=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/unitDecorator/utils/unitDecoratorRegex.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/unitDecorator/utils/unitDecoratorRegex.ts b/src/plugins/unitDecorator/utils/unitDecoratorRegex.ts index 64d13c15..092551a1 100644 --- a/src/plugins/unitDecorator/utils/unitDecoratorRegex.ts +++ b/src/plugins/unitDecorator/utils/unitDecoratorRegex.ts @@ -1,12 +1,12 @@ -/* eslint-disable */ const numbers = '0-9'; -export const getEndHashtagMatch = (unit: string) => +export const getEndHashtagMatch = (unit: string): RegExp => + // eslint-disable-next-line no-useless-escape new RegExp(`^(?:[${numbers}]+[${unit}]|:\/\/)`); -export const getHashSigns = (unit: string) => new RegExp(unit); +export const getHashSigns = (unit: string): RegExp => new RegExp(unit); -export const getUnitDecoratorBoundary = (unit: string) => +export const getUnitDecoratorBoundary = (unit: string): RegExp => new RegExp( `((?:^|$|[^${numbers}]))([${numbers}]*)([${numbers}]+[${unit}])`, 'gi', From 806721af85158d880b8ba510ec8d9d857dd2488b Mon Sep 17 00:00:00 2001 From: Yuurilee Date: Sat, 10 Apr 2021 19:00:32 +0900 Subject: [PATCH 10/10] =?UTF-8?q?Design:=20=EC=88=AB=EC=9E=90=20+=20?= =?UTF-8?q?=EB=8B=A8=EC=9C=84=20=EA=B3=84=EC=82=B0/=EA=B3=84=EC=82=B0=20x?= =?UTF-8?q?=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/unitDecorator/types.ts | 7 ++++--- src/plugins/unitDecorator/unitDecorator.tsx | 10 ++++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/plugins/unitDecorator/types.ts b/src/plugins/unitDecorator/types.ts index 2b078091..691e1700 100644 --- a/src/plugins/unitDecorator/types.ts +++ b/src/plugins/unitDecorator/types.ts @@ -1,11 +1,12 @@ +import { palette } from 'themes/palatte'; + export const CustomInline = { NOT_CALCULATE: 'NOT_CALCULATE', }; export const UnitDecoratorStyleMap = { NOT_CALCULATE: { - background: 'transparent', - margin: '0', - padding: '0', + background: palette.action.disabledBackground, + color: palette.text.primary, }, }; diff --git a/src/plugins/unitDecorator/unitDecorator.tsx b/src/plugins/unitDecorator/unitDecorator.tsx index 19de2e92..9f34e193 100644 --- a/src/plugins/unitDecorator/unitDecorator.tsx +++ b/src/plugins/unitDecorator/unitDecorator.tsx @@ -26,11 +26,17 @@ export interface UnitDecoratorProps { const DecoratorWrapper = styled.span` > span { - background: ${palette.grey[400]}; + background: ${palette.primary.main}; margin: ${theme.spacing(0, 0.5)}; padding: ${theme.spacing(0.5, 1)}; - border-radius: ${theme.spacing(1)}; + border-radius: ${theme.spacing(0.5)}; + color: ${theme.palette.background.paper}; + box-shadow: ${theme.shadows[2]}; cursor: pointer; + + &:hover { + box-shadow: ${theme.shadows[4]}; + } } `;