vuetify
Version:
Vue Material Component Framework
144 lines (143 loc) • 4.84 kB
JavaScript
import { createVNode as _createVNode, mergeProps as _mergeProps } from "vue";
// Styles
import "./VDialog.css";
// Components
import { VDialogTransition } from "../transitions/index.js";
import { VDefaultsProvider } from "../VDefaultsProvider/index.js";
import { VOverlay } from "../VOverlay/index.js";
import { makeVOverlayProps } from "../VOverlay/VOverlay.js"; // Composables
import { forwardRefs } from "../../composables/forwardRefs.js";
import { useProxiedModel } from "../../composables/proxiedModel.js";
import { useScopeId } from "../../composables/scopeId.js"; // Utilities
import { mergeProps, nextTick, onBeforeUnmount, ref, watch } from 'vue';
import { focusableChildren, genericComponent, IN_BROWSER, propsFactory, useRender } from "../../util/index.js"; // Types
export const makeVDialogProps = propsFactory({
fullscreen: Boolean,
retainFocus: {
type: Boolean,
default: true
},
scrollable: Boolean,
...makeVOverlayProps({
origin: 'center center',
scrollStrategy: 'block',
transition: {
component: VDialogTransition
},
zIndex: 2400
})
}, 'VDialog');
export const VDialog = genericComponent()({
name: 'VDialog',
props: makeVDialogProps(),
emits: {
'update:modelValue': value => true,
afterEnter: () => true,
afterLeave: () => true
},
setup(props, _ref) {
let {
emit,
slots
} = _ref;
const isActive = useProxiedModel(props, 'modelValue');
const {
scopeId
} = useScopeId();
const overlay = ref();
function onFocusin(e) {
const before = e.relatedTarget;
const after = e.target;
if (before !== after && overlay.value?.contentEl &&
// We're the topmost dialog
overlay.value?.globalTop &&
// It isn't the document or the dialog body
![document, overlay.value.contentEl].includes(after) &&
// It isn't inside the dialog body
!overlay.value.contentEl.contains(after)) {
const focusable = focusableChildren(overlay.value.contentEl);
if (!focusable.length) return;
const firstElement = focusable[0];
const lastElement = focusable[focusable.length - 1];
if (before === firstElement) {
lastElement.focus();
} else {
firstElement.focus();
}
}
}
onBeforeUnmount(() => {
document.removeEventListener('focusin', onFocusin);
});
if (IN_BROWSER) {
watch(() => isActive.value && props.retainFocus, val => {
val ? document.addEventListener('focusin', onFocusin) : document.removeEventListener('focusin', onFocusin);
}, {
immediate: true
});
}
function onAfterEnter() {
emit('afterEnter');
if ((props.scrim || props.retainFocus) && overlay.value?.contentEl && !overlay.value.contentEl.contains(document.activeElement)) {
overlay.value.contentEl.focus({
preventScroll: true
});
}
}
function onAfterLeave() {
emit('afterLeave');
}
watch(isActive, async val => {
if (!val) {
await nextTick();
overlay.value.activatorEl?.focus({
preventScroll: true
});
}
});
useRender(() => {
const overlayProps = VOverlay.filterProps(props);
const activatorProps = mergeProps({
'aria-haspopup': 'dialog'
}, props.activatorProps);
const contentProps = mergeProps({
tabindex: -1
}, props.contentProps);
return _createVNode(VOverlay, _mergeProps({
"ref": overlay,
"class": ['v-dialog', {
'v-dialog--fullscreen': props.fullscreen,
'v-dialog--scrollable': props.scrollable
}, props.class],
"style": props.style
}, overlayProps, {
"modelValue": isActive.value,
"onUpdate:modelValue": $event => isActive.value = $event,
"aria-modal": "true",
"activatorProps": activatorProps,
"contentProps": contentProps,
"height": !props.fullscreen ? props.height : undefined,
"width": !props.fullscreen ? props.width : undefined,
"maxHeight": !props.fullscreen ? props.maxHeight : undefined,
"maxWidth": !props.fullscreen ? props.maxWidth : undefined,
"role": "dialog",
"onAfterEnter": onAfterEnter,
"onAfterLeave": onAfterLeave
}, scopeId), {
activator: slots.activator,
default: function () {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _createVNode(VDefaultsProvider, {
"root": "VDialog"
}, {
default: () => [slots.default?.(...args)]
});
}
});
});
return forwardRefs({}, overlay);
}
});
//# sourceMappingURL=VDialog.js.map