StoryBook: Fully support themes in pop-up components
This commit is contained in:
parent
6a9d8b86d8
commit
0fc178d887
4 changed files with 71 additions and 11 deletions
|
@ -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 (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.panel}>{contents}</div>
|
||||
<div className={classnames(styles.darkTheme, styles.panel, 'dark-theme')}>
|
||||
<ThemedProvider themes={['dark']}>
|
||||
<div
|
||||
className={classnames(styles.darkTheme, styles.panel, 'dark-theme')}
|
||||
>
|
||||
{contents}
|
||||
</div>
|
||||
</ThemedProvider>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -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 ./",
|
||||
|
|
|
@ -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<boolean>(false);
|
||||
const containerClass = dragActive ? styles.dragActive : styles.container;
|
||||
|
|
40
ts/components/PopperRootContext.tsx
Normal file
40
ts/components/PopperRootContext.tsx
Normal file
|
@ -0,0 +1,40 @@
|
|||
import * as React from 'react';
|
||||
|
||||
const makeApi = (themes?: Array<string>) => ({
|
||||
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<string>;
|
||||
children?: React.ReactChildren;
|
||||
};
|
||||
|
||||
export const ThemedProvider: React.FunctionComponent<ThemedProviderProps> = ({
|
||||
themes,
|
||||
children,
|
||||
}) => {
|
||||
const api = React.useMemo(() => makeApi(themes), [themes]);
|
||||
|
||||
return (
|
||||
<PopperRootContext.Provider value={api}>
|
||||
{children}
|
||||
</PopperRootContext.Provider>
|
||||
);
|
||||
};
|
Loading…
Reference in a new issue