diff --git a/.storybook/config.js b/.storybook/config.js index 23584c9ebe37..9bd434504d35 100644 --- a/.storybook/config.js +++ b/.storybook/config.js @@ -5,6 +5,7 @@ import classnames from 'classnames'; import * as styles from './styles.scss'; import messages from '../_locales/en/messages.json'; import { I18n } from '../sticker-creator/util/i18n'; +import { ThemedProvider } from '../ts/components/PopperRootContext'; addDecorator(withKnobs); @@ -14,9 +15,13 @@ addDecorator((storyFn /* , context */) => { return (
{contents}
-
- {contents} -
+ +
+ {contents} +
+
); }); diff --git a/package.json b/package.json index 08e7ffdf1567..8d1b20f1e177 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "styleguide": "styleguidist server", "ready": "yarn clean-transpile && yarn grunt && yarn lint && yarn test-node && yarn test-electron && yarn lint-deps", "dev": "run-p --print-label dev:*", + "dev:grunt": "yarn grunt dev", "dev:webpack": "NODE_ENV=development webpack-dev-server --hot", "dev:typed-scss": "yarn build:typed-scss -w", "dev:storybook": "start-storybook -p 6006 -s ./", diff --git a/sticker-creator/components/StickerFrame.tsx b/sticker-creator/components/StickerFrame.tsx index 8c4b928c67d3..3c4386aa4c57 100644 --- a/sticker-creator/components/StickerFrame.tsx +++ b/sticker-creator/components/StickerFrame.tsx @@ -17,6 +17,7 @@ import { Props as EmojiPickerProps, } from '../../ts/components/emoji/EmojiPicker'; import { Emoji } from '../../ts/components/emoji/Emoji'; +import { PopperRootContext } from '../../ts/components/PopperRootContext'; import { useI18n } from '../util/i18n'; export type Mode = 'removable' | 'pick-emoji' | 'add'; @@ -117,12 +118,13 @@ export const StickerFrame = React.memo( [timerRef] ); + const { createRoot, removeRoot } = React.useContext(PopperRootContext); + // Create popper root and handle outside clicks React.useEffect(() => { if (emojiPickerOpen) { - const root = document.createElement('div'); + const root = createRoot(); setEmojiPopperRoot(root); - document.body.appendChild(root); const handleOutsideClick = ({ target }: MouseEvent) => { if (!root.contains(target as Node)) { setEmojiPickerOpen(false); @@ -131,27 +133,39 @@ export const StickerFrame = React.memo( document.addEventListener('click', handleOutsideClick); return () => { - document.body.removeChild(root); + removeRoot(root); document.removeEventListener('click', handleOutsideClick); }; } return noop; - }, [emojiPickerOpen, setEmojiPickerOpen, setEmojiPopperRoot]); + }, [ + createRoot, + emojiPickerOpen, + removeRoot, + setEmojiPickerOpen, + setEmojiPopperRoot, + ]); React.useEffect(() => { if (mode !== 'pick-emoji' && image && previewActive) { - const root = document.createElement('div'); + const root = createRoot(); setPreviewPopperRoot(root); - document.body.appendChild(root); return () => { - document.body.removeChild(root); + removeRoot(root); }; } return noop; - }, [mode, image, previewActive, setPreviewPopperRoot]); + }, [ + createRoot, + image, + mode, + previewActive, + removeRoot, + setPreviewPopperRoot, + ]); const [dragActive, setDragActive] = React.useState(false); const containerClass = dragActive ? styles.dragActive : styles.container; diff --git a/ts/components/PopperRootContext.tsx b/ts/components/PopperRootContext.tsx new file mode 100644 index 000000000000..2a58014cf93f --- /dev/null +++ b/ts/components/PopperRootContext.tsx @@ -0,0 +1,40 @@ +import * as React from 'react'; + +const makeApi = (themes?: Array) => ({ + createRoot: () => { + const div = document.createElement('div'); + + if (themes) { + themes.forEach(theme => { + div.classList.add(`${theme}-theme`); + }); + } + + document.body.appendChild(div); + + return div; + }, + removeRoot: (root: HTMLElement) => { + document.body.removeChild(root); + }, +}); + +export const PopperRootContext = React.createContext(makeApi()); + +export type ThemedProviderProps = { + themes?: Array; + children?: React.ReactChildren; +}; + +export const ThemedProvider: React.FunctionComponent = ({ + themes, + children, +}) => { + const api = React.useMemo(() => makeApi(themes), [themes]); + + return ( + + {children} + + ); +};