@oruga-ui/oruga-next
Version:
UI components for Vue.js and CSS framework agnostic
1 lines • 16.5 kB
Source Map (JSON)
{"version":3,"file":"modal.cjs","sources":["../../src/components/modal/Modal.vue","../../src/components/modal/useModalProgrammatic.ts","../../src/components/modal/index.ts"],"sourcesContent":["<script setup lang=\"ts\" generic=\"C extends Component\">\nimport {\n ref,\n computed,\n watch,\n nextTick,\n onMounted,\n useTemplateRef,\n type Component,\n} from \"vue\";\n\nimport OIcon from \"../icon/Icon.vue\";\n\nimport { getDefault } from \"@/utils/config\";\nimport { toCssDimension } from \"@/utils/helpers\";\nimport { isClient } from \"@/utils/ssr\";\nimport {\n defineClasses,\n useClickOutside,\n useMatchMedia,\n usePreventScrolling,\n getTeleportDefault,\n useTrapFocus,\n} from \"@/composables\";\nimport type { CloseEventArgs } from \"../programmatic\";\n\nimport type { ModalProps } from \"./props\";\n\n/**\n * Classic modal overlay to include any content you may need.\n * @displayName Modal\n * @style _modal.scss\n */\ndefineOptions({\n isOruga: true,\n name: \"OModal\",\n configField: \"modal\",\n inheritAttrs: false,\n});\n\nconst props = withDefaults(defineProps<ModalProps<C>>(), {\n override: undefined,\n active: false,\n fullScreen: false,\n content: undefined,\n width: () => getDefault(\"modal.width\", 960),\n animation: () => getDefault(\"modal.animation\", \"zoom-out\"),\n overlay: () => getDefault(\"modal.overlay\", true),\n cancelable: () =>\n getDefault(\"modal.cancelable\", [\"escape\", \"x\", \"outside\"]),\n trapFocus: () => getDefault(\"modal.trapFocus\", true),\n alert: () => getDefault(\"modal.alert\", false),\n ariaLabel: () => getDefault(\"modal.ariaLabel\"),\n autoFocus: () => getDefault(\"modal.autoFocus\", true),\n closeIcon: () => getDefault(\"modal.closeIcon\", \"close\"),\n closeIconSize: () => getDefault(\"modal.closeIconSize\", \"medium\"),\n ariaCloseLabel: () => getDefault(\"modal.ariaCloseLabel\", \"Close\"),\n mobileBreakpoint: () => getDefault(\"modal.mobileBreakpoint\"),\n teleport: () => getDefault(\"modal.teleport\", false),\n clipScroll: () => getDefault(\"modal.clipScroll\", false),\n component: undefined,\n props: undefined,\n events: undefined,\n});\n\nconst emits = defineEmits<{\n /**\n * active prop two-way binding\n * @param value {boolean} - updated active prop\n */\n \"update:active\": [value: boolean];\n /**\n * on component close event\n * @param value {string} - close event method\n */\n close: [...args: [] | [string] | CloseEventArgs<C>];\n}>();\n\nconst { vTrapFocus } = useTrapFocus();\n\nconst rootRef = useTemplateRef(\"rootElement\");\nconst contentRef = useTemplateRef(\"contentElement\");\n\nconst isActive = defineModel<boolean>(\"active\", { default: false });\n\nconst { isMobile } = useMatchMedia(props.mobileBreakpoint);\n\nconst _teleport = computed(() =>\n typeof props.teleport === \"boolean\"\n ? { to: getTeleportDefault(), disabled: !props.teleport }\n : { to: props.teleport, disabled: false },\n);\n\nconst showX = computed(() =>\n Array.isArray(props.cancelable)\n ? props.cancelable.indexOf(\"x\") >= 0\n : props.cancelable,\n);\n\nconst customStyle = computed(() =>\n !props.fullScreen ? { maxWidth: toCssDimension(props.width) } : null,\n);\n\nconst toggleScroll = usePreventScrolling(props.clipScroll);\n\nwatch(isActive, (value) => {\n if (props.overlay) toggleScroll(value);\n // if autoFocus focus the element\n if (value && props.autoFocus)\n nextTick(() => {\n if (rootRef.value) rootRef.value.focus();\n });\n});\n\nonMounted(() => {\n if (isActive.value && props.overlay) toggleScroll(isActive.value);\n});\n\n// --- Events Feature ---\n\nif (isClient)\n if (!props.overlay)\n // register outside click event listener when is active\n useClickOutside(contentRef, onClickedOutside, {\n trigger: isActive,\n });\n\n/** Close fixed sidebar if clicked outside. */\nfunction onClickedOutside(event: Event): void {\n if (!isActive.value || isAnimating.value) return;\n if (\n props.overlay ||\n (contentRef.value && !event.composedPath().includes(contentRef.value))\n )\n event.preventDefault();\n cancel(\"outside\");\n}\n\n/** Escape key press event bound to the component root. */\nfunction onEscapePress(): void {\n if (!isActive.value) return;\n cancel(\"escape\");\n}\n\n/**\n * Check if method is cancelable.\n * Call close() with action `cancel`.\n * @param method Cancel method\n */\nfunction cancel(method: string): void {\n // check if method is cancelable\n if (\n (typeof props.cancelable === \"boolean\" && !props.cancelable) ||\n !props.cancelable ||\n (Array.isArray(props.cancelable) && !props.cancelable.includes(method))\n )\n return;\n close(method);\n}\n\n/** set active to false and emit close event */\nfunction close(...args: [] | [string] | CloseEventArgs<C>): void {\n isActive.value = false;\n emits(\"close\", ...args);\n}\n\n// --- Animation Feature ---\n\nconst isAnimating = ref(!props.active);\n\n/** Transition after-enter hook */\nfunction afterEnter(): void {\n isAnimating.value = false;\n}\n\n/** Transition before-leave hook */\nfunction beforeLeave(): void {\n isAnimating.value = true;\n}\n\n// --- Computed Component Classes ---\n\nconst rootClasses = defineClasses(\n [\"rootClass\", \"o-modal\"],\n [\"mobileClass\", \"o-modal--mobile\", null, isMobile],\n [\"activeClass\", \"o-modal--active\", null, isActive],\n);\n\nconst overlayClasses = defineClasses([\"overlayClass\", \"o-modal__overlay\"]);\n\nconst contentClasses = defineClasses(\n [\"contentClass\", \"o-modal__content\"],\n [\n \"fullScreenClass\",\n \"o-modal__content--full-screen\",\n null,\n computed(() => props.fullScreen),\n ],\n);\n\nconst closeClasses = defineClasses([\"closeClass\", \"o-modal__close\"]);\n\n// --- Expose Public Functionalities ---\n\n/** expose functionalities for programmatic usage */\ndefineExpose({ close });\n</script>\n\n<template>\n <Teleport :to=\"_teleport.to\" :disabled=\"_teleport.disabled\">\n <transition\n :name=\"animation\"\n @after-enter=\"afterEnter\"\n @before-leave=\"beforeLeave\">\n <div\n v-show=\"isActive\"\n ref=\"rootElement\"\n v-bind=\"$attrs\"\n v-trap-focus=\"trapFocus && isActive\"\n data-oruga=\"modal\"\n :class=\"rootClasses\"\n :tabindex=\"-1\"\n :role=\"alert ? 'alertdialog' : 'dialog'\"\n :aria-label=\"ariaLabel\"\n :aria-modal=\"isActive\"\n @keyup.escape=\"onEscapePress\">\n <div\n v-if=\"overlay\"\n :class=\"overlayClasses\"\n tabindex=\"-1\"\n @click=\"onClickedOutside\" />\n\n <div\n ref=\"contentElement\"\n :class=\"contentClasses\"\n :style=\"customStyle\">\n <!-- injected component for programmatic usage -->\n <component\n :is=\"component\"\n v-if=\"component\"\n v-bind=\"$props.props\"\n v-on=\"$props.events || {}\"\n @close=\"close\" />\n <!--\n @slot Modal default content, default is content prop\n @binding {(...args): void} close - function to close the component\n -->\n <slot v-else :close=\"close\">\n <div v-if=\"content\">{{ content }}</div>\n </slot>\n\n <o-icon\n v-if=\"showX\"\n v-show=\"!isAnimating\"\n :class=\"closeClasses\"\n :icon=\"closeIcon\"\n :size=\"closeIconSize\"\n clickable\n :aria-label=\"ariaCloseLabel\"\n @click=\"cancel('x')\" />\n </div>\n </div>\n </transition>\n </Teleport>\n</template>\n","import {\n type Component,\n type ComponentInternalInstance,\n type MaybeRefOrGetter,\n} from \"vue\";\nimport {\n InstanceRegistry,\n ComponentProgrammatic,\n type ProgrammaticComponentOptions,\n type ProgrammaticExpose,\n} from \"../programmatic\";\n\nimport Modal from \"./Modal.vue\";\n\nimport type { ModalProps } from \"./props\";\n\ndeclare module \"../../index\" {\n interface OrugaProgrammatic {\n modal: typeof ModalProgrammatic;\n }\n}\n\n/** modal component programmatic instance registry **/\nconst registry = new InstanceRegistry<ComponentInternalInstance>();\n\n/** useModalProgrammatic composable options */\nexport type ModalProgrammaticOptions<C extends Component> = Readonly<\n ModalProps<C>\n> &\n ProgrammaticComponentOptions<typeof Modal<C>>;\n\nconst ModalProgrammatic = {\n /** Returns the number of registered active instances. */\n count: registry.count,\n /**\n * Create a new programmatic modal component instance.\n * @param options modal content string or modal component props object\n * @param target specify a target the component get rendered into - default is `document.body`\n * @returns ProgrammaticExpose\n */\n open<C extends Component>(\n options: string | ModalProgrammaticOptions<C>,\n target?: MaybeRefOrGetter<string | HTMLElement | null>,\n ): ProgrammaticExpose<typeof Modal<C>> {\n const _options: ModalProgrammaticOptions<C> =\n typeof options === \"string\" ? { content: options } : options;\n\n const componentProps: ModalProps<C> = {\n active: true, // set the active default state to true\n ...(_options as ModalProps<C>),\n };\n\n // create programmatic component\n return ComponentProgrammatic.open(Modal, {\n registry, // custom programmatic instance registry\n target, // target the component get rendered into\n props: componentProps, // component specific props\n onClose: _options.onClose, // on close event handler\n });\n },\n /** Close the last registred instance in the modal programmatic instance registry. */\n close(...args: unknown[]): void {\n registry.last()?.exposed?.close(...args);\n },\n /** Close all instances in the programmatic modal instance registry. */\n closeAll(...args: unknown[]): void {\n registry.walk((entry) => entry.exposed?.close(...args));\n },\n};\n\nexport default ModalProgrammatic;\n","import type { App, Plugin } from \"vue\";\n\nimport Modal from \"./Modal.vue\";\nimport ModalProgrammatic from \"./useModalProgrammatic\";\n\nimport {\n registerComponent,\n registerComponentProgrammatic,\n} from \"@/utils/plugins\";\n\n/** export modal specific types */\nexport type { ModalProgrammaticOptions } from \"./useModalProgrammatic\";\n\n/** export modal plugin */\nexport default {\n install(app: App) {\n registerComponent(app, Modal);\n registerComponentProgrammatic(app, \"modal\", ModalProgrammatic);\n },\n} as Plugin;\n\n/** export modal components & composables */\nexport { Modal as OModal, ModalProgrammatic };\n"],"names":["useTrapFocus","useTemplateRef","_useModel","useMatchMedia","computed","getTeleportDefault","toCssDimension","usePreventScrolling","watch","nextTick","onMounted","isClient","useClickOutside","ref","defineClasses","_createBlock","_Teleport","_createVNode","_Transition","animation","_withDirectives","_openBlock","_createElementBlock","_mergeProps","$attrs","_unref","alert","ariaLabel","overlay","_createElementVNode","component","_resolveDynamicComponent","$props","_toHandlers","_renderSlot","content","OIcon","closeIcon","closeIconSize","ariaCloseLabel","trapFocus","InstanceRegistry","ComponentProgrammatic","Modal","registerComponent","registerComponentProgrammatic"],"mappings":"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"}