Skip to content

Instantly share code, notes, and snippets.

@cassiozen
Created January 21, 2022 16:19
Show Gist options
  • Save cassiozen/57754b298f361caa056268fbf5b39274 to your computer and use it in GitHub Desktop.
Save cassiozen/57754b298f361caa056268fbf5b39274 to your computer and use it in GitHub Desktop.
import React, { createContext, Fragment, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
function MyComponent({ name, show }: { name: string; show: boolean }) {
const [isEnabled, setIsEnabled] = useState<boolean>(false);
return (
<Fragment>
<p>hi {show ? name : 'stranger'}</p>
</Fragment>
);
}
const useDeepEffect = useEffect;
const getReactPath = () => 'test';
type ModalContextType<ComponentType extends ModalTypeToExtend> = {
component: ComponentType;
hideModal: (callback?: () => void) => void;
props: ModalPropsTypeToExtend<ComponentType>;
showModal: <ModalType extends ModalTypeToExtend, ModalPropsType extends ModalPropsTypeToExtend<ComponentType>>(
modal: ModalType,
modalProps?: ModalPropsType,
) => void;
};
export const ModalContext = createContext<ModalContextType<any>>({
component: () => {
return <Fragment />;
},
props: {},
showModal: () => {},
hideModal: () => {},
});
type ModalTypeToExtend = React.JSXElementConstructor<any>;
type ModalPropsTypeToExtend<T extends ModalTypeToExtend> = React.ComponentProps<T>;
type ModalProviderProps = {
children: React.ReactNode;
};
export const ModalProvider = ({ children }: ModalProviderProps) => {
const [component, setComponent] = useState<ModalTypeToExtend>(() => {
return <Fragment />;
});
const [props, setProps] = useState<ModalPropsTypeToExtend>({ keepOpen: false });
const showModal = <ModalType extends ModalTypeToExtend, ModalPropsType extends ModalPropsTypeToExtend<ModalType>>(
modal: ModalType,
modalProps?: ModalPropsType,
) => {
setProps(modalProps);
// We cannot pass a functional component directly to useState
// because it will try to invoke it as a function
if (modal) setComponent(() => modal);
};
showModal(MyComponent)
const hideModal = (callback?: () => void) => {
setComponent(() => {
return <Fragment />;
});
setProps({ keepOpen: false });
if (callback) callback();
};
const [value, setValue] = useState({
component,
props,
showModal,
hideModal,
});
useDeepEffect(() => {
setValue({
component,
props,
showModal,
hideModal,
});
}, [component, props]);
const path = getReactPath();
useEffect(() => {
if (!props.keepOpen) {
hideModal();
}
}, [path]);
return <ModalContext.Provider value={value}>{children}</ModalContext.Provider>;
};
type ModalRootProps = {
announceLiveMessage: (arg0?: string) => {};
};
export const ModalRoot = ({ announceLiveMessage }: ModalRootProps) => (
<ModalContext.Consumer>
{({ component: Component, props, hideModal }) =>
Component ? (
<Component
{...props}
onRequestClose={(message?: string) => {
hideModal(() => {
if (message && typeof message === 'string') announceLiveMessage(message);
});
}}
/>
) : null
}
</ModalContext.Consumer>
);
ModalRoot.propTypes = {
announceLiveMessage: PropTypes.func.isRequired,
};
export const ModalConsumer = ModalContext.Consumer;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment