StoryBook: Fully support themes in pop-up components

This commit is contained in:
Ken Powers 2020-02-06 14:28:01 -05:00 committed by GitHub
parent 6a9d8b86d8
commit 0fc178d887
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 11 deletions

View File

@ -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')}>
{contents}
</div>
<ThemedProvider themes={['dark']}>
<div
className={classnames(styles.darkTheme, styles.panel, 'dark-theme')}
>
{contents}
</div>
</ThemedProvider>
</div>
);
});

View File

@ -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 ./",

View File

@ -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;

View 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>
);
};