From 920c653239b54772e00a774db62bbb86c5aaaa62 Mon Sep 17 00:00:00 2001 From: ssi02014 Date: Tue, 29 Aug 2023 00:10:43 +0900 Subject: [PATCH] chore: Support cjs, esm --- README.md | 42 ------ babel.config.js | 2 +- package.json | 12 +- rollup.config.mjs | 9 +- src/components/ColorPicker/index.tsx | 51 +++++--- src/components/Layout/styled.tsx | 5 +- src/components/Portal/index.tsx | 92 ------------- src/css/reset.tsx | 184 ++++++++++++++++++++++++++ src/lib/ThumbnailGenerator.tsx | 188 +-------------------------- tsconfig.paths.json | 1 + yarn.lock | 61 ++++++++- 11 files changed, 297 insertions(+), 350 deletions(-) delete mode 100644 src/components/Portal/index.tsx create mode 100644 src/css/reset.tsx diff --git a/README.md b/README.md index 79813e3..2d5143e 100644 --- a/README.md +++ b/README.md @@ -146,48 +146,6 @@ const App = () => { } ``` -
- -## How to use Next(v13) 😊 -### STEP 1️⃣ -- Install Package -``` -yarn add react-thumbnail-generator next-transpile-modules -or -npm install react-thumbnail-generator next-transpile-modules -``` - -
- -### STEP 2️⃣ -- Modify `next.config` -```js -/** @type {import('next').NextConfig} */ -const nextConfig = { - reactStrictMode: true, - transpilePackages: ["react-thumbnail-generator"], // (*) -}; - -module.exports = nextConfig; -``` - -
- -### STEP 3️⃣ -- Add `` component. - -```jsx -import ThumbnailGenerator from 'react-thumbnail-generator'; - -export default function Home() { - return ( - - ); -} - -``` - -
## How to add Web fonts 😊 diff --git a/babel.config.js b/babel.config.js index d76cddb..026e085 100644 --- a/babel.config.js +++ b/babel.config.js @@ -3,6 +3,6 @@ module.exports = { ['@babel/preset-env', { useBuiltIns: 'usage', corejs: 3 }], '@babel/preset-typescript', '@babel/preset-react', + '@emotion/babel-preset-css-prop', ], - plugins: ['@emotion/babel-plugin'], }; diff --git a/package.json b/package.json index 0e91dcd..398c520 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,12 @@ { "name": "react-thumbnail-generator", - "version": "3.0.4", + "version": "3.1.0", "description": "react-thumbnail-generator", - "main": "dist/index.js", - "module": "dist/index.js", + "main": "dist/cjs/index.js", + "module": "dist/esm/index.js", + "files": [ + "dist" + ], "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "rm -rf dist && rollup -c", @@ -26,7 +29,8 @@ "@babel/preset-env": "^7.22.4", "@babel/preset-react": "^7.22.3", "@babel/preset-typescript": "^7.21.5", - "@emotion/babel-plugin": "^11.11.0", + "@devgrace/react": "^0.1.2", + "@emotion/babel-preset-css-prop": "^11.11.0", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@rollup/plugin-alias": "^5.0.0", diff --git a/rollup.config.mjs b/rollup.config.mjs index 23cf6e9..cdc4bb4 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -18,8 +18,13 @@ export default { output: [ { file: pkg.main, - format: 'esm', sourcemap: false, + format: 'cjs', + }, + { + file: pkg.module, + sourcemap: false, + format: 'esm', }, ], external: ['react', 'react-dom'], @@ -34,7 +39,7 @@ export default { extensions, include: ['src/**/*'], }), - typescript({ tsconfig: './tsconfig.json' }), + typescript({ tsconfig: './tsconfig.json', exclude: ['**/*.stories.tsx'] }), alias({ entries: [{ find: '@', replacement: path.resolve(__dirname, './src') }], }), diff --git a/src/components/ColorPicker/index.tsx b/src/components/ColorPicker/index.tsx index 3495393..99bddf9 100644 --- a/src/components/ColorPicker/index.tsx +++ b/src/components/ColorPicker/index.tsx @@ -8,6 +8,7 @@ import React, { } from 'react'; import { Color, ColorPicker as PaletteColorPicker } from 'react-color-palette'; import { IconButton } from '../Icon/styled'; +import { Portal } from '@devgrace/react'; interface ColorPickerProps { children: React.ReactNode; @@ -24,6 +25,7 @@ const ColorPicker = ({ }: ColorPickerProps) => { const [isOpenColorPicker, setIsOpenColorPicker] = useState(false); const colorRef = useRef(null); + const [coordinates, setCoordinates] = useState({ x: 0, y: 0 }); const handleCloseColorPicker = useCallback( (e: any) => { @@ -39,10 +41,16 @@ const ColorPicker = ({ [isOpenColorPicker, toggleIsBlockEvent] ); - const handleOpenColorPicker = useCallback(() => { - setIsOpenColorPicker((prev) => !prev); - toggleIsBlockEvent(); - }, [toggleIsBlockEvent]); + const handleOpenColorPicker = useCallback( + (e: React.MouseEvent) => { + const { x, y } = e.currentTarget.getBoundingClientRect(); + + setCoordinates({ x, y }); + setIsOpenColorPicker((prev) => !prev); + toggleIsBlockEvent(); + }, + [toggleIsBlockEvent] + ); useEffect(() => { document.addEventListener('mousedown', handleCloseColorPicker); @@ -61,11 +69,12 @@ const ColorPicker = ({ const colorPickerWrapperStyle: CSSProperties = useMemo(() => { return { position: 'absolute', - left: '50%', - bottom: '40px', + left: `${coordinates.x}px`, + top: `${coordinates.y - 300}px`, transform: 'translateX(-50%)', + zIndex: '9999', }; - }, []); + }, [coordinates]); return (
@@ -75,19 +84,21 @@ const ColorPicker = ({ isBorder={true}> {children} - {isOpenColorPicker && ( -
- -
- )} + + {isOpenColorPicker && ( +
+ +
+ )} +
); }; diff --git a/src/components/Layout/styled.tsx b/src/components/Layout/styled.tsx index 7bd14e6..c207f46 100644 --- a/src/components/Layout/styled.tsx +++ b/src/components/Layout/styled.tsx @@ -29,13 +29,10 @@ export const BodyWrapper = styled.section<{ min-width: ${({ isFullWidth }) => (isFullWidth ? '100%' : '600px')}; border-radius: 7px; box-shadow: 1px 1px 10px #cccccc; - z-index: 9999; + z-index: 100; background-color: #ffffff; flex-direction: column; - overflow: hidden; - font-family: Arial; - * { box-sizing: border-box; } diff --git a/src/components/Portal/index.tsx b/src/components/Portal/index.tsx deleted file mode 100644 index 1866491..0000000 --- a/src/components/Portal/index.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import React from 'react'; -import { - createContext, - useCallback, - useContext, - useLayoutEffect, - useMemo, -} from 'react'; -import { createPortal } from 'react-dom'; -import { useIsMounted } from '../../hooks/useIsMounted'; - -interface PortalProps { - children: React.ReactNode; - className?: string; - containerRef?: React.RefObject; -} - -const portalContext = createContext<{ parentPortal: HTMLElement | null }>({ - parentPortal: null, -}); - -const PORTAL_DEFAULT_CLASS = 'thumbnail-generator'; - -function RenderPortal({ children, className, containerRef }: PortalProps) { - const { parentPortal } = useContext(portalContext); - - const getPortalNode = useCallback( - (mountNode: HTMLElement) => { - const portalNode = mountNode.ownerDocument.createElement('div'); - portalNode.classList.add(className || PORTAL_DEFAULT_CLASS); - - return portalNode; - }, - [className] - ); - - /** - * This is the mount node to render portal nodes. - * The mountNode has the value "containerRef.current" if it has a "containerRef", or the parent portal node if it is a nested portal. - * By default, it has "document.body". - */ - const mountNode = useMemo(() => { - if (parentPortal) { - return parentPortal; - } - - if (containerRef?.current) { - return containerRef.current; - } - - return document.body; - }, [parentPortal, containerRef]); - - const portalNode = useMemo( - () => getPortalNode(mountNode), - [getPortalNode, mountNode] - ); - - useLayoutEffect(() => { - mountNode.appendChild(portalNode); - - /** - * "portalNode" is removed from "mountNode" on unmount. - */ - return () => { - if (mountNode.contains(portalNode)) { - mountNode.removeChild(portalNode); - } - }; - }, [portalNode, mountNode]); - - return createPortal( - - {children} - , - portalNode - ); -} - -/** @tossdocs-ignore */ -export default function Portal({ children, ...restProps }: PortalProps) { - const isMounted = useIsMounted(); - - /** - * With this code, it is possible to solve the "window is not defined" and "Hydration Error" that can occur in SSR. - */ - if (!isMounted) { - return <>; - } - - return {children}; -} diff --git a/src/css/reset.tsx b/src/css/reset.tsx new file mode 100644 index 0000000..86085f5 --- /dev/null +++ b/src/css/reset.tsx @@ -0,0 +1,184 @@ +import { css } from '@emotion/react'; + +const reset = css` + * { + margin: 0; + padding: 0; + box-sizing: border-box; + } + .rcp-light { + --rcp-background: #ffffff; + --rcp-input-text: #111111; + --rcp-input-border: rgba(0, 0, 0, 0.1); + --rcp-input-label: #717171; + } + + .rcp-dark { + --rcp-background: #181818; + --rcp-input-text: #f3f3f3; + --rcp-input-border: rgba(255, 255, 255, 0.1); + --rcp-input-label: #999999; + } + + .rcp { + display: flex; + flex-direction: column; + align-items: center; + + background-color: var(--rcp-background); + border-radius: 10px; + } + + .rcp-body { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 20px; + width: 100%; + + box-sizing: border-box; + + padding: 20px; + } + + .rcp-saturation { + position: relative; + + width: 100%; + background-image: linear-gradient(transparent, black), + linear-gradient(to right, white, transparent); + border-radius: 10px 10px 0 0; + + user-select: none; + } + + .rcp-saturation-cursor { + position: absolute; + + width: 20px; + height: 20px; + + border: 2px solid #ffffff; + border-radius: 50%; + box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.15); + box-sizing: border-box; + + transform: translate(-10px, -10px); + } + + .rcp-hue { + position: relative; + + width: 100%; + height: 12px; + + background-image: linear-gradient( + to right, + rgb(255, 0, 0), + rgb(255, 255, 0), + rgb(0, 255, 0), + rgb(0, 255, 255), + rgb(0, 0, 255), + rgb(255, 0, 255), + rgb(255, 0, 0) + ); + border-radius: 10px; + + user-select: none; + } + + .rcp-hue-cursor { + position: absolute; + + width: 20px; + height: 20px; + + border: 2px solid #ffffff; + border-radius: 50%; + box-shadow: rgba(0, 0, 0, 0.2) 0px 0px 0px 0.5px; + box-sizing: border-box; + + transform: translate(-10px, -4px); + } + + .rcp-alpha { + position: relative; + + width: 100%; + height: 12px; + + border-radius: 10px; + + user-select: none; + } + + .rcp-alpha-cursor { + position: absolute; + + width: 20px; + height: 20px; + + border: 2px solid #ffffff; + border-radius: 50%; + box-shadow: rgba(0, 0, 0, 0.2) 0px 0px 0px 0.5px; + box-sizing: border-box; + + transform: translate(-10px, -4px); + } + + .rcp-fields { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 10px; + + width: 100%; + } + + .rcp-fields-element { + display: flex; + flex-direction: column; + align-items: center; + gap: 5px; + + width: 100%; + } + + .hex-element { + grid-row: 1; + } + + .hex-element:nth-child(3n) { + grid-column: 1 / -1; + } + + .rcp-fields-element-input { + width: 100%; + + font-size: 14px; + font-weight: 600; + + color: var(--rcp-input-text); + text-align: center; + + background: none; + border: 2px solid; + border-color: var(--rcp-input-border); + border-radius: 5px; + box-sizing: border-box; + + outline: none; + + padding: 10px; + } + + .rcp-fields-element-label { + font-size: 14px; + font-weight: 600; + + color: var(--rcp-input-label); + text-transform: uppercase; + } +`; + +export default reset; diff --git a/src/lib/ThumbnailGenerator.tsx b/src/lib/ThumbnailGenerator.tsx index e557c53..348a685 100644 --- a/src/lib/ThumbnailGenerator.tsx +++ b/src/lib/ThumbnailGenerator.tsx @@ -3,9 +3,10 @@ import TG from '@components/TG'; import { TGOpenButton } from '@components/TG.styled'; import { toggleButton } from '@assets/icons'; import { Position, getIconSize } from '@utils/style'; -import Portal from '@components/Portal'; +import { Portal } from '@devgrace/react'; import Icon from '@components/Icon'; -import { Global, css } from '@emotion/react'; +import { Global } from '@emotion/react'; +import reset from '@css/reset'; interface ThumbnailGeneratorProps { isDefaultOpen?: boolean; @@ -36,188 +37,7 @@ const ThumbnailGenerator = ({ return ( <> - + {isOpen ? (