Files
Liam DeBeasi 6fcb3a62b1 refactor(vue): drop support for "on" prefixed overlay events and bump minimum required version of vue to 3.0.6 (#23229)
refactor(vue): drop support for "on" prefixed overlay events and bump minimum required version of vue to 3.0.6

BREAKING CHANGE:

- Dropped support for prefixed overlay events in favor of non prefixed events (I.e. `@onDidDismiss` becomes `@didDismiss`).
- Minimum required version of Vue is now Vue v3.0.6 or newer.
2021-04-23 13:06:22 -04:00

116 lines
2.9 KiB
TypeScript

import { defineComponent, h, ref, VNode } from 'vue';
export interface OverlayProps {
isOpen?: boolean;
}
export const defineOverlayContainer = <Props extends object>(name: string, componentProps: string[] = [], controller: any) => {
const eventListeners = [
{ componentEv: `${name}-will-present`, frameworkEv: 'willPresent' },
{ componentEv: `${name}-did-present`, frameworkEv: 'didPresent' },
{ componentEv: `${name}-will-dismiss`, frameworkEv: 'willDismiss' },
{ componentEv: `${name}-did-dismiss`, frameworkEv: 'didDismiss' },
];
const Container = defineComponent<Props & OverlayProps>((props, { slots, emit }) => {
const overlay = ref();
const onVnodeMounted = async () => {
const isOpen = props.isOpen;
isOpen && (await present(props))
}
const onVnodeUpdated = async (node: VNode, prevNode: VNode) => {
const isOpen = node.props!.isOpen;
const prevIsOpen = prevNode.props!.isOpen;
/**
* Do not do anything if this prop
* did not change.
*/
if (isOpen === prevIsOpen) return;
if (isOpen) {
await present(props);
} else {
await dismiss();
}
}
const onVnodeBeforeUnmount = async () => {
await dismiss();
}
const dismiss = async () => {
if (!overlay.value) return;
await overlay.value;
overlay.value = overlay.value.dismiss();
await overlay.value;
overlay.value = undefined;
}
const present = async (props: Readonly<Props>) => {
/**
* Do not open another instance
* if one is already opened.
*/
if (overlay.value) {
await overlay.value;
}
if (overlay.value?.present) {
await overlay.value.present();
return;
}
/**
* These are getting passed as props.
* Potentially a Vue bug with Web Components?
*/
const restOfProps = { ...(props as any) };
delete restOfProps.onWillPresent;
delete restOfProps.onDidPresent;
delete restOfProps.onWillDismiss;
delete restOfProps.onDidDismiss;
const component = slots.default && slots.default()[0];
overlay.value = controller.create({
...restOfProps,
component
});
overlay.value = await overlay.value;
eventListeners.forEach(eventListener => {
overlay.value.addEventListener(eventListener.componentEv, () => {
emit(eventListener.frameworkEv);
});
})
await overlay.value.present();
}
return () => {
return h(
'div',
{
style: { display: 'none' },
onVnodeMounted,
onVnodeUpdated,
onVnodeBeforeUnmount,
isOpen: props.isOpen
}
);
}
});
Container.displayName = name;
Container.props = [...componentProps, 'isOpen'];
Container.emits = ['willPresent', 'didPresent', 'willDismiss', 'didDismiss'];
return Container;
}