@oruga-ui/oruga-next
Version:
UI components for Vue.js and CSS framework agnostic
1 lines • 868 kB
Source Map (JSON)
{"version":3,"file":"oruga.mjs","sources":["../src/utils/helpers.ts","../src/utils/programmatic.ts","../src/utils/plugins.ts","../src/utils/ssr.ts","../src/utils/config.ts","../src/utils/icons.ts","../src/composables/unrefElement.ts","../src/composables/defineClasses.ts","../src/composables/useEventListener.ts","../src/composables/useMatchMedia.ts","../src/components/field/fieldInjection.ts","../src/composables/useInputHandler.ts","../src/composables/useDebounce.ts","../src/composables/useSequentialId.ts","../src/composables/useParentProvider.ts","../src/composables/useClickOutside.ts","../src/composables/useScrollingParent.ts","../src/composables/useOptions.ts","../src/composables/usePreventScrolling.ts","../src/composables/useConfig.ts","../src/composables/useTrapFocus.ts","../src/components/icon/Icon.vue","../src/components/input/Input.vue","../src/components/dropdown/DropdownItem.vue","../src/components/utils/PositionWrapper.vue","../src/composables/useScrollHelper.ts","../src/composables/useInfiniteScroll.ts","../src/components/dropdown/Dropdown.vue","../src/components/autocomplete/Autocomplete.vue","../src/components/autocomplete/index.ts","../src/components/breadcrumb/Breadcrumb.vue","../src/components/breadcrumb/BreadcrumbItem.vue","../src/components/breadcrumb/index.ts","../src/components/button/Button.vue","../src/components/button/index.ts","../src/components/carousel/Carousel.vue","../src/components/carousel/CarouselItem.vue","../src/components/carousel/index.ts","../src/components/checkbox/Checkbox.vue","../src/components/checkbox/index.ts","../src/components/collapse/Collapse.vue","../src/components/collapse/index.ts","../src/components/select/Select.vue","../src/components/utils/PickerWrapper.vue","../src/components/datepicker/utils.ts","../src/components/datepicker/useDatepickerMixins.ts","../src/components/datepicker/DatepickerTableRow.vue","../src/components/datepicker/DatepickerTable.vue","../src/components/datepicker/DatepickerMonth.vue","../src/components/datepicker/Datepicker.vue","../src/components/datepicker/index.ts","../src/components/timepicker/useTimepickerMixins.ts","../src/components/timepicker/Timepicker.vue","../src/components/datetimepicker/useDatetimepickerMixin.ts","../src/components/datetimepicker/Datetimepicker.vue","../src/components/datetimepicker/index.ts","../src/components/dropdown/index.ts","../src/components/field/Field.vue","../src/components/field/index.ts","../src/components/icon/index.ts","../src/components/input/index.ts","../src/components/loading/Loading.vue","../src/components/programmatic/InstanceRegistry.ts","../src/components/programmatic/ProgrammaticComponent.ts","../src/components/programmatic/useProgrammatic.ts","../src/components/programmatic/index.ts","../src/components/loading/useLoadingProgrammatic.ts","../src/components/loading/index.ts","../src/components/utils/PlainButton.ts","../src/components/menu/MenuItem.vue","../src/components/menu/Menu.vue","../src/components/menu/index.ts","../src/components/modal/Modal.vue","../src/components/modal/useModalProgrammatic.ts","../src/components/modal/index.ts","../src/components/notification/Notification.vue","../src/components/notification/NotificationNotice.vue","../src/components/notification/useNotificationProgrammatic.ts","../src/components/notification/index.ts","../src/components/pagination/PaginationButton.vue","../src/components/pagination/Pagination.vue","../src/components/pagination/index.ts","../src/components/radio/Radio.vue","../src/components/radio/index.ts","../src/components/select/index.ts","../src/components/skeleton/Skeleton.vue","../src/components/skeleton/index.ts","../src/components/sidebar/Sidebar.vue","../src/components/sidebar/useSidebarProgrammatic.ts","../src/components/sidebar/index.ts","../src/components/tooltip/Tooltip.vue","../src/components/slider/SliderThumb.vue","../src/components/slider/SliderTick.vue","../src/components/slider/Slider.vue","../src/components/slider/index.ts","../src/components/steps/StepItem.vue","../src/components/steps/Steps.vue","../src/components/steps/index.ts","../src/components/switch/Switch.vue","../src/components/switch/index.ts","../src/components/utils/SlotComponent.ts","../src/components/table/TableMobileSort.vue","../src/components/table/TableColumn.vue","../src/components/table/TablePagination.vue","../src/components/table/Table.vue","../src/components/table/index.ts","../src/components/tabs/TabItem.vue","../src/components/tabs/Tabs.vue","../src/components/tabs/index.ts","../src/components/tag/Tag.vue","../src/components/tag/index.ts","../src/components/taginput/Taginput.vue","../src/components/taginput/index.ts","../src/components/timepicker/index.ts","../src/components/tooltip/index.ts","../src/components/upload/Upload.vue","../src/components/upload/index.ts","../src/index.ts"],"sourcesContent":["import { Comment, Fragment, Text } from \"vue\";\nimport type { DeepKeys, DeepType } from \"@/types\";\n\n/**\n * +/- function to native math sign\n */\nfunction signPoly(value: number): number {\n if (value < 0) return -1;\n return value > 0 ? 1 : 0;\n}\nexport const sign = Math.sign || signPoly;\n\n/**\n * Native modulo bug with negative numbers\n * @param n\n * @param mod\n * @returns {number}\n */\nexport const mod = (n: number, mod: number): number => ((n % mod) + mod) % mod;\n\n/** add a prefix `0` to a 1 digit number */\nexport const pad = (value: number): string => (value < 10 ? \"0\" : \"\") + value;\n\n/**\n * Asserts a value is beetween min and max\n * @param val\n * @param min\n * @param max\n * @returns {number}\n */\nexport function bound(val: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, val));\n}\n\n/**\n * checks if the value is of type object\n */\nexport const isObject = (value: unknown): value is object =>\n !!value && typeof value === \"object\" && !Array.isArray(value);\n\n/**\n * checks if the value is of type date\n */\nexport const isDate = (value: unknown): value is Date =>\n !!value && value instanceof Date && !isNaN(value.getTime());\n\n/**\n * checks if the value is not null or undefined\n */\nexport const isDefined = <T>(value: T | undefined | null): value is T =>\n value !== null && typeof value !== \"undefined\";\n\n/**\n * Determines if the value of a prop that is either present (true) or not\n * present (undefined). For example, the prop disabled should disable\n * by just existing, but what if it is set to the string \"false\" — then it\n * should not be disabled.\n *\n * @param value - Value to check for undefined.\n * @returns boolean\n */\nexport const isTrueish = (value: unknown): boolean =>\n isDefined(value) && value !== \"false\" && value !== false;\n\nexport const blankIfUndefined = (value: string | null | undefined): string =>\n isDefined(value) ? value : \"\";\n\nexport const defaultIfUndefined = <T>(\n value: T | undefined,\n defaultValue: T,\n): T => (isDefined(value) ? value : defaultValue);\n\nexport const toCssDimension = (\n width: string | number | undefined,\n dimension: string = \"px\",\n): string | undefined =>\n !isDefined(width)\n ? undefined\n : isNaN(width as number)\n ? String(width)\n : String(width) + dimension;\n\n/**\n * Sort an array by key without mutating original data.\n * Call the user sort function if it was passed.\n */\nexport function sortBy<T extends object>(\n array: T[],\n key: DeepKeys<T>,\n fn?: (a: T, b: T, asc: boolean) => number,\n isAsc: boolean = false,\n mutate: boolean = false,\n): T[] {\n // Sorting without mutating original data\n if (fn && typeof fn === \"function\") {\n return (mutate ? array : [...array]).sort((a, b) => fn(a, b, isAsc));\n } else {\n return (mutate ? array : [...array]).sort((a, b) => {\n // Get nested values from objects\n let newA: any = isObject(a) ? getValueByPath(a, key) : a;\n let newB: any = isObject(b) ? getValueByPath(b, key) : b;\n\n // sort boolean type\n if (typeof newA === \"boolean\" && typeof newB === \"boolean\") {\n return isAsc ? (newA > newB ? 1 : -1) : newA > newB ? -1 : 1;\n }\n\n if (!newA && newA !== 0) return 1;\n if (!newB && newB !== 0) return -1;\n if (newA === newB) return 0;\n\n newA = typeof newA === \"string\" ? newA.toUpperCase() : newA;\n newB = typeof newB === \"string\" ? newB.toUpperCase() : newB;\n\n return isAsc ? (newA > newB ? 1 : -1) : newA > newB ? -1 : 1;\n });\n }\n}\n\n/**\n * Deeply check if two values are equal\n */\nexport function isEqual(valueA: unknown, valueB: unknown): boolean {\n // Check if only one value is empty.\n if ((!valueA && !!valueB) || (!!valueA && !valueB)) return false;\n\n // If both objects are identical, return true.\n if (valueA === valueB) return true;\n\n // Check if both values are objecs.\n if (isObject(valueA) && isObject(valueB)) {\n // Get the keys of both objects.\n const keys1 = Object.keys(valueA);\n const keys2 = Object.keys(valueB);\n\n // Check if the number of keys is the same.\n if (keys1.length !== keys2.length) return false;\n\n // Iterate through the keys and compare their values recursively.\n for (const key of keys1) {\n const val1 = valueA[key];\n const val2 = valueB[key];\n const areObjects = isObject(val1) && isObject(val2);\n if (\n (areObjects && !isEqual(val1, val2)) ||\n (!areObjects && val1 !== val2)\n )\n return false;\n }\n // If all checks pass, the objects are deep equal.\n return true;\n }\n\n // Check if both values are arrays.\n if (Array.isArray(valueA) && Array.isArray(valueB)) {\n // Check if the number of keys is the same.\n if (valueA.length !== valueB.length) return false;\n // Check if each value of the array is the same.\n if (!valueA.every((val, index) => val === valueB[index])) return false;\n // If all checks pass, the arrays are deep equal.\n return true;\n }\n\n return false;\n}\n\n/**\n * @deprecated not used\n * Returns true if it is a DOM element\n * @source https://stackoverflow.com/questions/384286/how-do-you-check-if-a-javascript-object-is-a-dom-object\n */\nexport function isElement(el: any): el is Element {\n return typeof HTMLElement === \"object\"\n ? el instanceof HTMLElement //DOM2\n : el &&\n typeof el === \"object\" &&\n el !== null &&\n el.nodeType === 1 &&\n typeof el.nodeName === \"string\";\n}\n\n/**\n * Merge function to replace Object.assign with deep merging possibility\n */\nexport function merge(target: any, source: any, deep = false): any {\n if (!isObject(target) || !isObject(source)) return source;\n if (!deep) return Object.assign(target, source);\n else return mergeDeep(target, source);\n}\n\n/**\n * Performs a deep merge of `source` into `target`.\n * Mutates `target` only but not its objects and arrays.\n *\n * @author inspired by [jhildenbiddle](https://stackoverflow.com/a/48218209).\n */\nexport function mergeDeep(target: any, source: any): any {\n if (!isObject(target) || !isObject(source)) return source;\n\n Object.getOwnPropertyNames(source).forEach((key) => {\n const targetValue = target[key];\n const sourceValue = source[key];\n\n if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {\n target[key] = targetValue.concat(sourceValue);\n } else if (isObject(targetValue) && isObject(sourceValue)) {\n target[key] = mergeDeep(\n Object.assign({}, targetValue),\n sourceValue,\n );\n } else {\n target[key] = sourceValue;\n }\n });\n\n return target;\n}\n\n/**\n * Return display text for an option.\n * If option is an object, get the property from path based on given field, or else just the property.\n * Apply a formatter function to the property if given.\n * Return the display label.\n *\n * @param obj Object to get the label for\n * @param field Property path of the object to use as display text\n * @param formatter Function to format the property to a string\n */\nexport function getPropertyValue<\n O,\n K extends DeepKeys<O>,\n D extends DeepType<O, K>,\n>(obj: O, field?: K, formatter?: (value: D, option: O) => string): string {\n if (!obj) return \"\";\n\n const property = (field ? getValueByPath<O, K, D>(obj, field) : obj) as D;\n\n const label =\n typeof formatter === \"function\" ? formatter(property, obj) : property;\n\n return String(label || \"\");\n}\n\n/**\n * Get a value of an object property/path even if it's nested\n */\nexport function getValueByPath<\n O,\n K extends DeepKeys<O>,\n D extends DeepType<O, K>,\n>(obj: O, path: K | (string & {})): D | undefined;\nexport function getValueByPath<\n O,\n K extends DeepKeys<O>,\n D extends DeepType<O, K>,\n>(obj: O, path: K | (string & {}), defaultValue: D): D;\nexport function getValueByPath<\n O,\n K extends DeepKeys<O>,\n D extends DeepType<O, K>,\n>(obj: O, path: K | (string & {}), defaultValue?: D): D | undefined;\nexport function getValueByPath<\n O,\n K extends DeepKeys<O>,\n D extends DeepType<O, K>,\n>(obj: O, path: K | (string & {}), defaultValue?: D): D | undefined {\n if (!obj || typeof obj !== \"object\" || typeof path !== \"string\")\n return defaultValue;\n\n const value: any = path\n .split(\".\")\n .reduce((o, i) => (typeof o !== \"undefined\" ? o[i] : undefined), obj);\n\n return typeof value !== \"undefined\" ? value : defaultValue;\n}\n\n/**\n * Set a value of an object property/path even if it's nested\n */\nexport function setValueByPath<O, K extends DeepKeys<O>>(\n obj: O,\n path: K,\n value: DeepType<O, K>,\n): void {\n if (typeof path !== \"string\") return;\n\n const p = path.split(\".\");\n if (p.length === 1) {\n obj[p[0]] = value;\n return;\n }\n const field = p[0];\n if (typeof obj[field] === \"undefined\") obj[field] = {};\n return setValueByPath(obj[field], p.slice(1).join(\".\"), value);\n}\n\nexport function removeElement(el: Element): void {\n if (typeof el.remove !== \"undefined\") {\n el.remove();\n } else if (typeof el.parentNode !== \"undefined\" && el.parentNode !== null) {\n el.parentNode.removeChild(el);\n }\n}\n\n/**\n * Escape regex characters\n * http://stackoverflow.com/a/6969486\n */\nexport function escapeRegExpChars(value: string): string {\n if (!value) return value;\n\n return value.replace(/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g, \"\\\\$&\");\n}\n\n/**\n * Remove accents/diacritics in a string\n * https://stackoverflow.com/a/37511463\n */\nexport function removeDiacriticsFromString(value: string): string {\n if (!value) return value;\n return value.normalize(\"NFD\").replace(/[\\u0300-\\u036f]/g, \"\");\n}\n\n/** checks if a vue vnode is empty */\nexport function isVNodeEmpty(vnode): boolean {\n if (!vnode) return true;\n if (vnode.type === Comment) return true;\n if (vnode.type === Text && !vnode.children.trim()) return true;\n if (vnode.type === Fragment && isVNodeEmpty(vnode.children)) return true;\n return false;\n}\n\n/**\n * Mobile detection\n * https://www.abeautifulsite.net/detecting-mobile-devices-with-javascript\n */\nexport const isMobileAgent = {\n Android: (): boolean =>\n typeof window !== \"undefined\" &&\n !!window.navigator.userAgent.match(/Android/i),\n BlackBerry: (): boolean =>\n typeof window !== \"undefined\" &&\n !!window.navigator.userAgent.match(/BlackBerry/i),\n iOS: (): boolean =>\n typeof window !== \"undefined\" &&\n !!window.navigator.userAgent.match(/iPhone|iPad|iPod/i),\n Opera: (): boolean =>\n typeof window !== \"undefined\" &&\n !!window.navigator.userAgent.match(/Opera Mini/i),\n Windows: (): boolean =>\n typeof window !== \"undefined\" &&\n !!window.navigator.userAgent.match(/IEMobile/i),\n any: (): boolean =>\n isMobileAgent.Android() ||\n isMobileAgent.BlackBerry() ||\n isMobileAgent.iOS() ||\n isMobileAgent.Opera() ||\n isMobileAgent.Windows(),\n};\n","import { ref } from \"vue\";\n\nexport interface OrugaProgrammatic {\n [key: string]: Record<string, any>;\n}\n\n/** Oruga object for programmatic components */\nconst oruga = ref<OrugaProgrammatic>({} as OrugaProgrammatic);\n\n/** Add components to the oruga object */\nexport function addProgrammatic(property: string, component: object): void {\n oruga.value[property] = component;\n}\n\n/** Composable for internal and external usage of programmatic components*/\nexport function useOruga(): OrugaProgrammatic {\n return oruga.value;\n}\n","import type { App, Component, Plugin, defineComponent } from \"vue\";\nimport { useOruga, addProgrammatic } from \"./programmatic\";\n\nexport let VueInstance: App | undefined;\n\n/** set the global vue instance */\nexport const setVueInstance = (Vue: App): void => {\n VueInstance = Vue;\n};\n\n/** register a plugin to the vue app instance */\nexport const registerPlugin = (app: App, plugin: Plugin): void => {\n app.use(plugin);\n};\n\n/** register a component to the vue app instance */\nexport const registerComponent = (\n app: App,\n component: ReturnType<typeof defineComponent>, // type Component isn't correct since vue 3.5 any more\n): void => {\n app.component(component.name, component);\n};\n\n/** register a global programmatic component to the oruga object */\nexport const registerComponentProgrammatic = (\n app: App,\n property: string,\n component: Component,\n): void => {\n // set global vue instance\n setVueInstance(app);\n // use composable for unified access to programmatic oruga object\n const oruga = useOruga();\n // add component (manipulates the programmatic oruga object)\n addProgrammatic(property, component);\n\n // add provide and $oruga (only needed once)\n if (!(app._context.provides && app._context.provides.oruga))\n app.provide(\"oruga\", oruga);\n if (!app.config.globalProperties.$oruga)\n app.config.globalProperties.$oruga = oruga;\n};\n","// Polyfills for SSR\n\nexport const isClient = typeof window !== \"undefined\";\nexport const isSSR = typeof window === \"undefined\";\n\nexport const HTMLElement = isSSR ? Object : window.HTMLElement;\nexport const HTMLInputElement = isSSR ? Object : window.HTMLInputElement;\nexport const File = isSSR ? Object : window.File;\n","import { ref, toRaw, type App } from \"vue\";\nimport { getValueByPath, merge, setValueByPath } from \"./helpers\";\nimport { setVueInstance } from \"./plugins\";\nimport { isClient } from \"./ssr\";\nimport type { DeepKeys, DeepType, OrugaOptions } from \"@/types\";\n\ndeclare module \"../index\" {\n interface OrugaProgrammatic {\n config: typeof ConfigProgrammatic;\n }\n}\n\nconst globalOptions = ref<OrugaOptions>({\n iconPack: \"mdi\",\n useHtml5Validation: true,\n statusIcon: true,\n transformClasses: undefined,\n mobileBreakpoint: \"1023px\",\n teleportTarget: () => (isClient ? document.body : \"body\"),\n});\n\nexport const setOptions = (options: OrugaOptions): void => {\n globalOptions.value = options;\n};\n\nexport const getOptions = (): OrugaOptions => {\n return Object.assign({}, toRaw(globalOptions.value));\n};\n\n/** get an option by option path with an optional default if not set */\nexport function getOption<\n K extends DeepKeys<OrugaOptions>,\n D extends DeepType<OrugaOptions, K>,\n>(path: K | (string & {}), defaultValue: D): D;\nexport function getOption<\n K extends DeepKeys<OrugaOptions>,\n D extends DeepType<OrugaOptions, K>,\n>(path: K | (string & {}), defaultValue?: D): D | undefined;\nexport function getOption<\n K extends DeepKeys<OrugaOptions>,\n D extends DeepType<OrugaOptions, K>,\n>(path: K | (string & {}), defaultValue?: D): D | undefined {\n return getValueByPath<OrugaOptions, K, D>(\n globalOptions.value,\n path,\n defaultValue,\n );\n}\n\n/** less type strict version of getOption for component props defaults */\nexport const getDefault = <T>(\n path: DeepKeys<OrugaOptions>,\n defaultValue?: T,\n): T => {\n return getValueByPath(globalOptions.value, path, defaultValue) as T & {};\n};\n\nexport const setOption = <K extends DeepKeys<OrugaOptions>>(\n path: K,\n value: DeepType<OrugaOptions, K>,\n): void => {\n setValueByPath(globalOptions.value, path, value);\n};\n\nexport const ConfigProgrammatic = {\n getOption,\n getOptions,\n setOption,\n setOptions(options: OrugaOptions): void {\n setOptions(merge(getOptions(), options, true));\n },\n};\n\nexport const OrugaConfig = {\n install(app: App, options?: OrugaOptions): void {\n // set global vue instance\n setVueInstance(app);\n // set options\n setOptions(merge(getOptions(), options, true));\n },\n};\n","import { getOption } from \"./config\";\nimport { merge } from \"./helpers\";\n\nexport type IconConfig = {\n sizes?: { default: string; [key: string]: string };\n iconPrefix?: string;\n internalIcons?: Record<string, string>;\n};\n\nconst mdiIcons = {\n sizes: {\n default: \"mdi-24px\",\n small: \"\",\n medium: \"mdi-36px\",\n large: \"mdi-48px\",\n },\n iconPrefix: \"mdi-\",\n};\n\nconst faIcons = (): IconConfig => {\n const iconComponent = getOption(\"iconComponent\");\n const faIconPrefix = iconComponent ? \"\" : \"fa-\";\n return {\n sizes: {\n default: \"\",\n small: \"sm\",\n medium: \"lg\",\n large: \"xl\",\n },\n iconPrefix: faIconPrefix,\n internalIcons: {\n check: \"check\",\n information: \"info-circle\",\n alert: \"exclamation-triangle\",\n \"alert-circle\": \"exclamation-circle\",\n \"arrow-up\": \"arrow-up\",\n \"chevron-right\": \"angle-right\",\n \"chevron-left\": \"angle-left\",\n \"chevron-down\": \"angle-down\",\n \"chevron-up\": \"angle-up\",\n eye: \"eye\",\n \"eye-off\": \"eye-slash\",\n \"caret-down\": \"caret-down\",\n \"caret-up\": \"caret-up\",\n \"close-circle\": \"times-circle\",\n close: \"times\",\n loading: \"circle-notch\",\n \"emoticon-sad\": \"frown\",\n },\n };\n};\n\nconst getIcons = (): Record<string, IconConfig> => {\n let icons: Record<string, IconConfig> = {\n mdi: mdiIcons,\n fa: faIcons(),\n fas: faIcons(),\n far: faIcons(),\n fad: faIcons(),\n fab: faIcons(),\n fal: faIcons(),\n };\n\n const customIconPacks = getOption(\"customIconPacks\");\n if (customIconPacks) icons = merge(icons, customIconPacks, true);\n\n return icons;\n};\n\nexport default getIcons;\n","import {\n toValue,\n type ComponentPublicInstance,\n type MaybeRefOrGetter,\n type MaybeRef,\n type Component,\n} from \"vue\";\n\nexport type MaybeElement =\n | Element\n | Document\n | Window\n | HTMLElement\n | SVGElement\n | Component\n | ComponentPublicInstance\n | undefined\n | null;\n\nexport type UnRefElementReturn<T extends MaybeElement = MaybeElement> =\n T extends ComponentPublicInstance\n ? Exclude<MaybeElement, ComponentPublicInstance>\n : T extends Component\n ? HTMLElement\n : T | undefined;\n\n/** Get the dom element of a ref of element or Vue component instance */\nexport function unrefElement<T extends MaybeElement>(\n elRef: MaybeRefOrGetter<T> | MaybeRef<T>,\n): UnRefElementReturn<T> {\n const plain = toValue(elRef);\n return (plain as ComponentPublicInstance)?.$el ?? plain;\n}\n\n/** Resolve an HTML element based on query selector or an explizit dom element */\nexport function resolveElement(\n target: MaybeRefOrGetter<HTMLElement | string>,\n): HTMLElement | null {\n const targetQuery = toValue(target);\n // query element if target is a string\n if (typeof targetQuery === \"string\")\n return document.querySelector<HTMLElement>(targetQuery);\n // else unwrap element\n else return unrefElement(targetQuery);\n}\n","import {\n ref,\n watch,\n isRef,\n toValue,\n getCurrentInstance,\n effectScope,\n onScopeDispose,\n getCurrentScope,\n type MaybeRefOrGetter,\n type Ref,\n type ComponentInternalInstance,\n type EffectScope,\n} from \"vue\";\n\nimport { getOptions } from \"@/utils/config\";\nimport { isDefined, blankIfUndefined, getValueByPath } from \"@/utils/helpers\";\n\nimport type {\n ClassBind,\n ComponentClass,\n ComponentProps,\n TransformFunction,\n} from \"@/types\";\n\n// named tuple as prop definition\ntype ComputedClass = readonly [\n className: string,\n defaultClass: string,\n suffix?: MaybeRefOrGetter<string | undefined> | null,\n apply?: MaybeRefOrGetter<boolean> | null,\n];\n\n/** Helper function to get all active classes from a class binding list */\nexport const getActiveClasses = (\n classes: MaybeRefOrGetter<ClassBind[]>,\n): string[] => {\n const values = toValue(classes);\n if (!values) return [];\n return values.flatMap((bind) =>\n Object.keys(bind)\n .filter((key) => key && bind[key])\n .flatMap((v) => v.split(\" \")),\n );\n};\n\ntype DefineClassesOptions = {\n /**\n * Pass a custom effect scope.\n * By default a new effect scope is created.\n * An error will be thrown if no current scope or a custom scope is given.\n * @default effectScope()\n */\n scope?: EffectScope;\n /**\n * Pass a custom props object which will be watched on additionaly to the current component instance props.\n * this will recompute the class bind property when the class property change.\n * @default vm.proxy?.$props\n */\n props?: Record<string, any>;\n};\n\nexport function defineClasses(\n ...args: [...ComputedClass[], DefineClassesOptions]\n): Ref<ClassBind[]>;\n\nexport function defineClasses(...args: [...ComputedClass[]]): Ref<ClassBind[]>;\n\n/**\n * Calculate dynamic classes based on class definitions\n */\nexport function defineClasses(\n ...args: ComputedClass[] | [...ComputedClass[], DefineClassesOptions]\n): Ref<ClassBind[]> {\n // extract last argument if its the option object\n const options = Array.isArray(args.at(-1))\n ? undefined\n : (args.at(-1) as DefineClassesOptions);\n\n // get class defintion list based on options are given or not\n const classDefinitions = (\n Array.isArray(args.at(-1)) ? args : args.slice(0, -1)\n ) as ComputedClass[];\n\n // getting a hold of the internal instance of the component in setup()\n const vm = getCurrentInstance();\n if (!vm)\n throw new Error(\n \"defineClasses must be called within a component setup function.\",\n );\n // check if there is no current active effect scope given\n if (!getCurrentScope() && !options?.scope)\n throw new Error(\n \"defineClasses must be called within a current active effect scope.\",\n );\n\n // create an effect scope object to capture reactive effects\n const scope = options?.scope || effectScope();\n\n // check if there is a current active effect scope\n if (getCurrentScope())\n // Registers a dispose callback on the current active effect scope.\n // The callback will be invoked when the associated effect scope is stopped.\n onScopeDispose(() => {\n // stop all effects when appropriate\n if (scope) scope.stop();\n });\n\n // reactive classes container\n const classes = ref<ClassBind[]>([]);\n\n classes.value = classDefinitions.map((defintion, index) => {\n const className = defintion[0];\n const defaultClass = defintion[1];\n const suffix = defintion[2];\n const apply = defintion[3];\n\n function getClassBind(): ClassBind {\n // compute class based on definition parameter\n const computedClass = computeClass(\n vm!,\n className,\n defaultClass,\n toValue(suffix) || undefined,\n );\n\n // if apply is not defined or true\n const applied = !isDefined(apply) || toValue(apply);\n\n // return class bind property\n return { [computedClass]: applied };\n }\n\n // run all watcher and computed properties in an active effect scope\n scope.run(() => {\n // recompute the class bind property when the class property change\n watch(\n [\n () => vm.proxy?.$props[className],\n () => (options?.props ? options?.props[className] : null),\n ],\n () => {\n // recompute the class bind property\n const classBind = getClassBind();\n // update class binding property by class index\n classes.value[index] = classBind;\n },\n );\n\n // if suffix is defined, watch suffix changed and recalculate class\n if (isDefined(suffix) && isRef(suffix)) {\n watch(suffix, (value, oldValue) => {\n // only recompute when value has really changed\n if (value === oldValue) return;\n // recompute the class bind property\n const classBind = getClassBind();\n // update class binding property by class index\n classes.value[index] = classBind;\n });\n }\n\n // if apply is defined, watch apply changed and update apply state (no need of recalculation here)\n if (isDefined(apply) && isRef(apply)) {\n watch(apply, (applied, oldValue) => {\n // only change apply when value has really changed\n if (applied === oldValue) return;\n // get class binding property by class index\n const classBind = classes.value[index];\n // update the apply class binding state\n Object.keys(classBind).forEach(\n (key) => (classBind[key] = applied),\n );\n // update the class binding property by class index\n classes.value[index] = classBind;\n });\n }\n });\n\n // return computed class based on parameter\n return getClassBind();\n });\n\n // return reactive classes\n return classes;\n}\n\n/**\n * Compute a class by a field name\n */\nfunction computeClass(\n vm: ComponentInternalInstance,\n field: string,\n defaultValue: string,\n suffix = \"\",\n): string {\n // get component props\n const props = getProps(vm);\n\n const componentKey: string = vm.proxy?.$options.configField;\n if (!componentKey)\n throw new Error(\"component must define the 'configField' option.\");\n\n // get component instance override property\n const config = props.override === true ? {} : getOptions();\n\n // --- Classes Definition ---\n\n // get component config class definition\n let globalClass: ComponentClass | undefined =\n getValueByPath(config, `${componentKey}.${field}.class`) ||\n getValueByPath(config, `${componentKey}.${field}`);\n\n // get instance class definition\n let localClass: ComponentClass | undefined = getValueByPath(props, field);\n\n // procsess local instance class\n if (Array.isArray(localClass)) {\n localClass = localClass.join(\" \");\n }\n if (typeof localClass === \"function\") {\n const props = getProps(vm);\n localClass = localClass(suffix, props);\n } else {\n localClass = suffixProcessor(localClass ?? \"\", suffix);\n }\n\n // process global config class\n if (Array.isArray(globalClass)) {\n globalClass = globalClass.join(\" \");\n }\n if (typeof globalClass === \"function\") {\n const props = getProps(vm);\n globalClass = globalClass(suffix, props);\n } else {\n globalClass = suffixProcessor(globalClass ?? \"\", suffix);\n }\n\n // process component instance default value\n if (defaultValue.includes(\"{*}\")) {\n defaultValue = defaultValue.replace(\n /\\{\\*\\}/g,\n blankIfUndefined(suffix),\n );\n } else {\n defaultValue = defaultValue + blankIfUndefined(suffix);\n }\n\n // --- Override Definition ---\n\n // get instance or global config override property\n const globalOverride =\n props.override || getValueByPath(config, \"override\", false);\n // get component config override property\n const localOverride = getValueByPath(\n config,\n `${componentKey}.override`,\n globalOverride,\n );\n // get component field config override property\n const overrideClass = getValueByPath(\n config,\n `${componentKey}.${field}.override`,\n localOverride,\n );\n\n // --- Define Applied Classes ---\n\n // if override is false add default value\n // add global config classes\n // add instance classes\n let appliedClasses = (\n `${!overrideClass ? defaultValue : \"\"} ` +\n `${blankIfUndefined(globalClass)} ` +\n `${blankIfUndefined(localClass)}`\n )\n .trim()\n .replace(/\\s\\s+/g, \" \");\n\n // --- Tranform Classes ---\n\n // get global config tranform class\n const globalTransformClasses: TransformFunction | undefined =\n getValueByPath(config, \"transformClasses\");\n // get component config tranform class\n const localTransformClasses: TransformFunction | undefined = getValueByPath(\n config,\n `${componentKey}.transformClasses`,\n );\n\n // apply component local transformclass if available\n if (localTransformClasses) {\n appliedClasses = localTransformClasses(appliedClasses);\n }\n // else apply global transformclass if available\n else if (globalTransformClasses) {\n appliedClasses = globalTransformClasses(appliedClasses);\n }\n\n return appliedClasses;\n}\n\nfunction suffixProcessor(input: string, suffix: string): string {\n return blankIfUndefined(input)\n .split(\" \")\n .filter((cls) => cls.length > 0)\n .map((cls) => cls + blankIfUndefined(suffix))\n .join(\" \");\n}\n\nconst getProps = (vm: ComponentInternalInstance): ComponentProps => {\n let props = vm.proxy?.$props || {};\n\n // get all props which ends with \"Props\", these are compressed parent props\n // append these parent props as root level prop\n props = Object.keys(props)\n .filter((key) => key.endsWith(\"Props\"))\n .map((key) => props[key])\n .reduce((a, b) => ({ ...a, ...b }), props);\n\n return props;\n};\n","import {\n onMounted,\n watch,\n getCurrentScope,\n onScopeDispose,\n type MaybeRefOrGetter,\n type Ref,\n type Component,\n} from \"vue\";\nimport { isObject } from \"@/utils/helpers\";\nimport { unrefElement } from \"./unrefElement\";\n\nexport type EventTarget = Element | Document | Window | Component;\nexport type EventListenerOptions = AddEventListenerOptions & {\n /** Register event listener immediate or on mounted hook. */\n immediate?: boolean;\n /** Trigger when the listener get registered and removed */\n trigger?: Ref<boolean>;\n};\n\n/**\n * Register DOM events using addEventListener on mounted, and removeEventListener automatically on unmounted.\n * Adaption of {@link https://vueuse.org/core/useEventListener}\n *\n * @param element DOM element to add the listener to\n * @param event Event name\n * @param handler Event handler function\n * @param options EventListenerOptions\n * @return stop function\n */\nexport function useEventListener(\n element: MaybeRefOrGetter<EventTarget>,\n event: string,\n handler: (evt?: any) => void,\n options?: EventListenerOptions,\n): () => void {\n let cleanup: () => void;\n\n const register = (): void => {\n if (!element) return;\n\n const target = unrefElement(element);\n // create a clone of options, to avoid it being changed reactively on removal\n const optionsClone = isObject(options) ? { ...options } : options;\n // register listener with timeout to prevent animation collision\n setTimeout(() => {\n target.addEventListener(event, handler, optionsClone);\n cleanup = (): void => {\n target.removeEventListener(event, handler, optionsClone);\n };\n });\n };\n\n let stopWatch: () => void;\n\n if (typeof options?.trigger !== \"undefined\") {\n stopWatch = watch(\n options.trigger,\n (value) => {\n // toggle listener\n if (value) register();\n else if (typeof cleanup === \"function\") cleanup();\n },\n { flush: \"post\" },\n );\n }\n\n if (options?.immediate) register();\n else if (getCurrentScope()) {\n // register listener on mount\n onMounted(() => {\n if (\n typeof options?.trigger === \"undefined\" ||\n options.trigger.value\n )\n register();\n });\n }\n\n const stop = (): void => {\n // remove listener before unmounting\n if (typeof stopWatch === \"function\") stopWatch();\n if (typeof cleanup === \"function\") cleanup();\n };\n\n if (getCurrentScope()) onScopeDispose(stop);\n\n return stop;\n}\n","import { getCurrentInstance, ref, type Ref } from \"vue\";\nimport { getOption } from \"@/utils/config\";\nimport { useEventListener } from \"./useEventListener\";\nimport { isClient } from \"@/utils/ssr\";\n\n/**\n * Checks if the match media is mobile.\n * @param mobileBreakpoint px breakpoint\n */\nexport function useMatchMedia(mobileBreakpoint?: string): {\n isMobile: Ref<boolean>;\n} {\n const isMobile = ref(false);\n const mediaQuery = ref<MediaQueryList>();\n\n // getting a hold of the internal instance in setup()\n const vm = getCurrentInstance();\n if (!vm)\n throw new Error(\n \"useMatchMedia must be called within a component setup function.\",\n );\n // get component props\n const props = vm.props;\n\n const componentKey = vm.proxy?.$options.configField;\n if (!componentKey)\n throw new Error(\"component must define the 'configField' option.\");\n\n // get mobileBreakpoint width value\n let width = props.mobileBreakpoint;\n if (!width) {\n const defaultWidth = getOption(`mobileBreakpoint`, mobileBreakpoint);\n width = getOption(`${componentKey}.mobileBreakpoint`, defaultWidth);\n }\n if (!width) return { isMobile };\n\n // define match media query ref\n mediaQuery.value = isClient\n ? window.matchMedia(`(max-width: ${width})`)\n : undefined;\n\n if (mediaQuery.value) {\n isMobile.value = mediaQuery.value.matches;\n useEventListener(mediaQuery.value, \"change\", onMatchMedia);\n } else {\n isMobile.value = false;\n }\n\n function onMatchMedia(event: any): void {\n isMobile.value = event.matches;\n }\n\n return { isMobile };\n}\n","import {\n computed,\n inject,\n provide,\n type ComputedRef,\n type InjectionKey,\n} from \"vue\";\n\nimport { getOption } from \"@/utils/config\";\nimport type { FieldProps } from \"./props\";\n\nexport type FieldData = {\n $el: Element | null;\n props: FieldProps;\n hasInnerField: boolean;\n variant?: string;\n message?: string | string[];\n labelId: string;\n inputAttrs: object;\n addInnerField: () => void;\n setInputId: (value: string) => void;\n setFocus: (value: boolean) => void;\n setFilled: (value: boolean) => void;\n setVariant: (value?: string) => void;\n setMessage: (value?: string | string[]) => void;\n};\n\n/** provide/inject type */\ntype ProvidedField = ComputedRef<FieldData | undefined>;\n\n/** provide/inject key */\nconst $FieldKey: InjectionKey<ProvidedField> = Symbol(\"FielData\");\n\n/**\n * Provide field component data via dependency injection.\n * Provided data is a computed ref to ensure reactivity.\n */\nexport function provideField(data: ProvidedField): void {\n provide($FieldKey, data);\n}\n\n/** Inject parent field component if used inside one. **/\nexport function injectField(): {\n parentField: ComputedRef<FieldData | undefined>;\n statusVariantIcon: ComputedRef<string>;\n statusVariant: ComputedRef<string | undefined>;\n statusMessage: ComputedRef<string | string[] | undefined>;\n} {\n const parentField = inject(\n $FieldKey,\n computed(() => undefined),\n );\n\n /** Get the message prop from parent if it's a Field. */\n const statusMessage = computed<string | string[] | undefined>(() => {\n if (\n (Array.isArray(parentField?.value?.message) &&\n !parentField?.value?.message.length) ||\n (!Array.isArray(parentField?.value?.message) &&\n !parentField?.value?.message)\n )\n return undefined;\n return parentField?.value.message;\n });\n\n /** Get the type prop from parent if it's a Field. */\n const statusVariant = computed<string | undefined>(() => {\n if (!parentField?.value?.variant) return undefined;\n if (typeof parentField.value.variant === \"string\")\n return parentField.value.variant;\n if (Array.isArray(parentField.value.variant)) {\n for (const key in parentField.value.variant as any) {\n if (parentField.value.variant[key]) return key;\n }\n }\n return undefined;\n });\n\n const statusVariantIconConfig = getOption(\"statusVariantIcon\", {\n success: \"check\",\n danger: \"alert-circle\",\n info: \"information\",\n warning: \"alert\",\n });\n\n /** Icon name based on the variant. */\n const statusVariantIcon = computed<string>(() => {\n if (!statusVariant.value || !statusVariantIconConfig) return \"\";\n return statusVariantIconConfig[statusVariant.value] || \"\";\n });\n\n return {\n parentField,\n statusVariant,\n statusVariantIcon,\n statusMessage,\n };\n}\n","import {\n nextTick,\n ref,\n computed,\n triggerRef,\n watch,\n watchEffect,\n type ExtractPropTypes,\n type MaybeRefOrGetter,\n type Component,\n} from \"vue\";\nimport { injectField } from \"@/components/field/fieldInjection\";\nimport { unrefElement } from \"./unrefElement\";\nimport { getOption } from \"@/utils/config\";\nimport { isSSR } from \"@/utils/ssr\";\nimport { isDefined } from \"@/utils/helpers\";\n\n// This should cover all types of HTML elements that have properties related to\n// HTML constraint validation, e.g. .form and .validity.\nconst validatableFormElementTypes = isSSR\n ? []\n : [\n HTMLButtonElement,\n HTMLFieldSetElement,\n HTMLInputElement,\n HTMLObjectElement,\n HTMLOutputElement,\n HTMLSelectElement,\n HTMLTextAreaElement,\n ];\n\nexport type ValidatableFormElement = InstanceType<\n (typeof validatableFormElementTypes)[number]\n>;\n\nfunction asValidatableFormElement(el: unknown): ValidatableFormElement | null {\n return validatableFormElementTypes.some((t) => el instanceof t)\n ? (el as ValidatableFormElement)\n : null;\n}\n\nconst constraintValidationAttributes = [\n \"disabled\",\n \"required\",\n \"pattern\",\n \"maxlength\",\n \"minlength\",\n \"max\",\n \"min\",\n \"step\",\n];\n\n/**\n * Form input handler functionalities\n */\nexport function useInputHandler<T extends ValidatableFormElement>(\n /** input ref element - can be a html element or a vue component*/\n inputRef: Readonly<MaybeRefOrGetter<T | Component>>,\n /** emitted input events */\n emits: {\n /** on input focus event */\n (e: \"focus\", value: Event): void;\n /** on input blur event */\n (e: \"blur\", value: Event): void;\n /** on input invalid event */\n (e: \"invalid\", value: Event): void;\n },\n /** validation configuration props */\n props: Readonly<\n ExtractPropTypes<{\n modelValue?: unknown;\n useHtml5Validation?: boolean;\n customValidity?:\n | string\n | ((currentValue: any, v: ValidityState) => string);\n }>\n >,\n) {\n // inject parent field component if used inside one\n const { parentField } = injectField();\n\n /// Allows access to the native element in cases where it might be missing,\n /// e.g. because the component hasn't been mounted yet or has been suspended\n /// by a <KeepAlive>\n const maybeElement = computed<T | undefined>(() => {\n const el = unrefElement<Component | HTMLElement>(inputRef);\n if (!el) return undefined;\n\n if (el.getAttribute(\"data-oruga-input\"))\n // if element is the input element\n return el as T;\n\n const inputs = el.querySelector(\"[data-oruga-input]\");\n\n if (!inputs) {\n console.warn(\n \"useInputHandler: Underlaying Oruga input component not found\",\n );\n return undefined;\n }\n // return underlaying the input element\n return inputs as T;\n });\n\n /// Should be used for most accesses to the native element; we generally\n /// expect it to be present, especially in event handlers.\n const element = computed(() => {\n const el = maybeElement.value;\n if (!el) console.warn(\"useInputHandler: inputRef contains no element\");\n return el;\n });\n\n // --- Input Focus Feature ---\n\n const isFocused = ref(false);\n\n /** Focus the underlaying input element. */\n function setFocus(): void {\n nextTick(() => {\n if (element.value) element.value.focus();\n });\n }\n\n /** Click the underlaying input element. */\n function doClick(): void {\n nextTick(() => {\n if (element.value) element.value.click();\n });\n }\n\n /** Unset focused and emit blur event. */\n function onBlur(event?: Event): void {\n isFocused.value = false;\n if (parentField?.value) parentField.value.setFocus(false);\n emits(\"blur\", event ? event : new Event(\"blur\"));\n checkHtml5Validity();\n }\n\n /** Set focused and emit focus event. */\n function onFocus(event?: Event): void {\n isFocused.value = true;\n if (parentField?.value) parentField.value.setFocus(true);\n emits(\"focus\", event ? event : new Event(\"focus\"));\n }\n\n // --- Validation Feature ---\n\n const isValid = ref(true);\n\n function setFieldValidity(variant, message): void {\n nextTick(() => {\n if (parentField?.value) {\n // Set type only if not defined\n if (!parentField.value.props.variant)\n parentField.value.setVariant(variant);\n\n // Set message only if not defined\n if (!parentField.value.props.message)\n parentField.value.setMessage(message);\n }\n });\n }\n\n /**\n * Check HTML5 validation, set isValid property.\n * If validation fail, send 'danger' type,\n * and error message to parent if it's a Field.\n */\n function checkHtml5Validity(): void {\n if (!props.useHtml5Validation) return;\n if (!element.value) return;\n\n if (element.value.validity.valid) {\n setFieldValidity(null, null);\n isValid.value = true;\n } else {\n setInvalid();\n isValid.value = false;\n }\n }\n\n function setInvalid(): void {\n const variant = \"danger\";\n const message = element.value?.validationMessage;\n setFieldValidity(variant, message);\n }\n\n function onInvalid(event: Event): void {\n checkHtml5Validity();\n const validatable = asValidatableFormElement(event.target);\n\n if (validatable && parentField?.value && props.useHtml5Validation) {\n // We provide our own error message on the field, so we should suppress the browser's default tooltip.\n // We still want to focus the form's first invalid input, though.\n event.preventDefault();\n\n let isFirstInvalid = false;\n\n if (validatable.form != null) {\n const formElements = validatable.form.elements;\n for (let i = 0; i < formElements.length; ++i) {\n const element = asValidatableFormElement(\n formElements.item(i),\n );\n if (eleme