UNPKG

vuetify

Version:

Vue Material Component Framework

1,678 lines (1,569 loc) 963 kB
/*! * Vuetify v3.8.4 * Forged by John Leider * Released under the MIT License. */ import { shallowRef, reactive, watchEffect, toRef, capitalize, unref, Fragment, isVNode, Comment, warn, getCurrentInstance as getCurrentInstance$1, ref, computed, provide, inject as inject$1, defineComponent as defineComponent$1, h, camelize, onBeforeUnmount, watch, readonly, onMounted, useId, onDeactivated, onActivated, onScopeDispose, effectScope, toRaw, createVNode, TransitionGroup, Transition, mergeProps, toRefs, toValue, isRef, onBeforeMount, nextTick, withDirectives, resolveDirective, vShow, onUpdated, Text, resolveDynamicComponent, toDisplayString, markRaw, Teleport, cloneVNode, createTextVNode, onUnmounted, onBeforeUpdate, withModifiers, vModelText, resolveComponent, render } from 'vue'; // Types // eslint-disable-line vue/prefer-import-from-vue /** * Creates a factory function for props definitions. * This is used to define props in a composable then override * default values in an implementing component. * * @example Simplified signature * (props: Props) => (defaults?: Record<keyof props, any>) => Props * * @example Usage * const makeProps = propsFactory({ * foo: String, * }) * * defineComponent({ * props: { * ...makeProps({ * foo: 'a', * }), * }, * setup (props) { * // would be "string | undefined", now "string" because a default has been provided * props.foo * }, * } */ function propsFactory(props, source) { return defaults => { return Object.keys(props).reduce((obj, prop) => { const isObjectDefinition = typeof props[prop] === 'object' && props[prop] != null && !Array.isArray(props[prop]); const definition = isObjectDefinition ? props[prop] : { type: props[prop] }; if (defaults && prop in defaults) { obj[prop] = { ...definition, default: defaults[prop] }; } else { obj[prop] = definition; } if (source && !obj[prop].source) { obj[prop].source = source; } return obj; }, {}); }; } /** * Like `Partial<T>` but doesn't care what the value is */ // Copied from Vue // Utilities // Types // Composables const makeComponentProps = propsFactory({ class: [String, Array, Object], style: { type: [String, Array, Object], default: null } }, 'component'); const IN_BROWSER = typeof window !== 'undefined'; const SUPPORTS_INTERSECTION = IN_BROWSER && 'IntersectionObserver' in window; const SUPPORTS_TOUCH = IN_BROWSER && ('ontouchstart' in window || window.navigator.maxTouchPoints > 0); const SUPPORTS_EYE_DROPPER = IN_BROWSER && 'EyeDropper' in window; function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); } function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); } function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; } function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); } function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); } // Types function getNestedValue(obj, path, fallback) { const last = path.length - 1; if (last < 0) return obj === undefined ? fallback : obj; for (let i = 0; i < last; i++) { if (obj == null) { return fallback; } obj = obj[path[i]]; } if (obj == null) return fallback; return obj[path[last]] === undefined ? fallback : obj[path[last]]; } function deepEqual(a, b) { if (a === b) return true; if (a instanceof Date && b instanceof Date && a.getTime() !== b.getTime()) { // If the values are Date, compare them as timestamps return false; } if (a !== Object(a) || b !== Object(b)) { // If the values aren't objects, they were already checked for equality return false; } const props = Object.keys(a); if (props.length !== Object.keys(b).length) { // Different number of props, don't bother to check return false; } return props.every(p => deepEqual(a[p], b[p])); } function getObjectValueByPath(obj, path, fallback) { // credit: http://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key#comment55278413_6491621 if (obj == null || !path || typeof path !== 'string') return fallback; if (obj[path] !== undefined) return obj[path]; path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties path = path.replace(/^\./, ''); // strip a leading dot return getNestedValue(obj, path.split('.'), fallback); } function getPropertyFromItem(item, property, fallback) { if (property === true) return item === undefined ? fallback : item; if (property == null || typeof property === 'boolean') return fallback; if (item !== Object(item)) { if (typeof property !== 'function') return fallback; const value = property(item, fallback); return typeof value === 'undefined' ? fallback : value; } if (typeof property === 'string') return getObjectValueByPath(item, property, fallback); if (Array.isArray(property)) return getNestedValue(item, property, fallback); if (typeof property !== 'function') return fallback; const value = property(item, fallback); return typeof value === 'undefined' ? fallback : value; } function createRange(length) { let start = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; return Array.from({ length }, (v, k) => start + k); } function convertToUnit(str) { let unit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'px'; if (str == null || str === '') { return undefined; } const num = Number(str); if (isNaN(num)) { return String(str); } else if (!isFinite(num)) { return undefined; } else { return `${num}${unit}`; } } function isObject(obj) { return obj !== null && typeof obj === 'object' && !Array.isArray(obj); } function isPlainObject(obj) { let proto; return obj !== null && typeof obj === 'object' && ((proto = Object.getPrototypeOf(obj)) === Object.prototype || proto === null); } function refElement(obj) { if (obj && '$el' in obj) { const el = obj.$el; if (el?.nodeType === Node.TEXT_NODE) { // Multi-root component, use the first element return el.nextElementSibling; } return el; } return obj; } // KeyboardEvent.keyCode aliases const keyCodes = Object.freeze({ enter: 13, tab: 9, delete: 46, esc: 27, space: 32, up: 38, down: 40, left: 37, right: 39, end: 35, home: 36, del: 46, backspace: 8, insert: 45, pageup: 33, pagedown: 34, shift: 16 }); const keyValues = Object.freeze({ enter: 'Enter', tab: 'Tab', delete: 'Delete', esc: 'Escape', space: 'Space', up: 'ArrowUp', down: 'ArrowDown', left: 'ArrowLeft', right: 'ArrowRight', end: 'End', home: 'Home', del: 'Delete', backspace: 'Backspace', insert: 'Insert', pageup: 'PageUp', pagedown: 'PageDown', shift: 'Shift' }); function keys(o) { return Object.keys(o); } function has(obj, key) { return key.every(k => obj.hasOwnProperty(k)); } // Array of keys function pick(obj, paths) { const found = {}; for (const key of paths) { if (Object.prototype.hasOwnProperty.call(obj, key)) { found[key] = obj[key]; } } return found; } // Array of keys // Array of keys or RegExp to test keys against function pickWithRest(obj, paths, exclude) { const found = Object.create(null); const rest = Object.create(null); for (const key in obj) { if (paths.some(path => path instanceof RegExp ? path.test(key) : path === key) && true) { found[key] = obj[key]; } else { rest[key] = obj[key]; } } return [found, rest]; } function omit(obj, exclude) { const clone = { ...obj }; exclude.forEach(prop => delete clone[prop]); return clone; } const onRE = /^on[^a-z]/; const isOn = key => onRE.test(key); const bubblingEvents = ['onAfterscriptexecute', 'onAnimationcancel', 'onAnimationend', 'onAnimationiteration', 'onAnimationstart', 'onAuxclick', 'onBeforeinput', 'onBeforescriptexecute', 'onChange', 'onClick', 'onCompositionend', 'onCompositionstart', 'onCompositionupdate', 'onContextmenu', 'onCopy', 'onCut', 'onDblclick', 'onFocusin', 'onFocusout', 'onFullscreenchange', 'onFullscreenerror', 'onGesturechange', 'onGestureend', 'onGesturestart', 'onGotpointercapture', 'onInput', 'onKeydown', 'onKeypress', 'onKeyup', 'onLostpointercapture', 'onMousedown', 'onMousemove', 'onMouseout', 'onMouseover', 'onMouseup', 'onMousewheel', 'onPaste', 'onPointercancel', 'onPointerdown', 'onPointerenter', 'onPointerleave', 'onPointermove', 'onPointerout', 'onPointerover', 'onPointerup', 'onReset', 'onSelect', 'onSubmit', 'onTouchcancel', 'onTouchend', 'onTouchmove', 'onTouchstart', 'onTransitioncancel', 'onTransitionend', 'onTransitionrun', 'onTransitionstart', 'onWheel']; const compositionIgnoreKeys = ['ArrowUp', 'ArrowDown', 'ArrowRight', 'ArrowLeft', 'Enter', 'Escape', 'Tab', ' ']; function isComposingIgnoreKey(e) { return e.isComposing && compositionIgnoreKeys.includes(e.key); } /** * Filter attributes that should be applied to * the root element of an input component. Remaining * attributes should be passed to the <input> element inside. */ function filterInputAttrs(attrs) { const [events, props] = pickWithRest(attrs, [onRE]); const inputEvents = omit(events, bubblingEvents); const [rootAttrs, inputAttrs] = pickWithRest(props, ['class', 'style', 'id', /^data-/]); Object.assign(rootAttrs, events); Object.assign(inputAttrs, inputEvents); return [rootAttrs, inputAttrs]; } function wrapInArray(v) { return v == null ? [] : Array.isArray(v) ? v : [v]; } function debounce(fn, delay) { let timeoutId = 0; const wrap = function () { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } clearTimeout(timeoutId); timeoutId = setTimeout(() => fn(...args), unref(delay)); }; wrap.clear = () => { clearTimeout(timeoutId); }; wrap.immediate = fn; return wrap; } function clamp(value) { let min = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; let max = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1; return Math.max(min, Math.min(max, value)); } function getDecimals(value) { const trimmedStr = value.toString().trim(); return trimmedStr.includes('.') ? trimmedStr.length - trimmedStr.indexOf('.') - 1 : 0; } function padEnd(str, length) { let char = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '0'; return str + char.repeat(Math.max(0, length - str.length)); } function padStart(str, length) { let char = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '0'; return char.repeat(Math.max(0, length - str.length)) + str; } function chunk(str) { let size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; const chunked = []; let index = 0; while (index < str.length) { chunked.push(str.substr(index, size)); index += size; } return chunked; } function chunkArray(array) { let size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; return Array.from({ length: Math.ceil(array.length / size) }, (v, i) => array.slice(i * size, i * size + size)); } function humanReadableFileSize(bytes) { let base = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1000; if (bytes < base) { return `${bytes} B`; } const prefix = base === 1024 ? ['Ki', 'Mi', 'Gi'] : ['k', 'M', 'G']; let unit = -1; while (Math.abs(bytes) >= base && unit < prefix.length - 1) { bytes /= base; ++unit; } return `${bytes.toFixed(1)} ${prefix[unit]}B`; } function mergeDeep() { let source = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; let arrayFn = arguments.length > 2 ? arguments[2] : undefined; const out = {}; for (const key in source) { out[key] = source[key]; } for (const key in target) { const sourceProperty = source[key]; const targetProperty = target[key]; // Only continue deep merging if // both properties are plain objects if (isPlainObject(sourceProperty) && isPlainObject(targetProperty)) { out[key] = mergeDeep(sourceProperty, targetProperty, arrayFn); continue; } if (arrayFn && Array.isArray(sourceProperty) && Array.isArray(targetProperty)) { out[key] = arrayFn(sourceProperty, targetProperty); continue; } out[key] = targetProperty; } return out; } function flattenFragments(nodes) { return nodes.map(node => { if (node.type === Fragment) { return flattenFragments(node.children); } else { return node; } }).flat(); } function toKebabCase() { let str = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; if (toKebabCase.cache.has(str)) return toKebabCase.cache.get(str); const kebab = str.replace(/[^a-z]/gi, '-').replace(/\B([A-Z])/g, '-$1').toLowerCase(); toKebabCase.cache.set(str, kebab); return kebab; } toKebabCase.cache = new Map(); function findChildrenWithProvide(key, vnode) { if (!vnode || typeof vnode !== 'object') return []; if (Array.isArray(vnode)) { return vnode.map(child => findChildrenWithProvide(key, child)).flat(1); } else if (vnode.suspense) { return findChildrenWithProvide(key, vnode.ssContent); } else if (Array.isArray(vnode.children)) { return vnode.children.map(child => findChildrenWithProvide(key, child)).flat(1); } else if (vnode.component) { if (Object.getOwnPropertySymbols(vnode.component.provides).includes(key)) { return [vnode.component]; } else if (vnode.component.subTree) { return findChildrenWithProvide(key, vnode.component.subTree).flat(1); } } return []; } var _arr = /*#__PURE__*/new WeakMap(); var _pointer = /*#__PURE__*/new WeakMap(); class CircularBuffer { constructor(size) { _classPrivateFieldInitSpec(this, _arr, []); _classPrivateFieldInitSpec(this, _pointer, 0); this.size = size; } get isFull() { return _classPrivateFieldGet(_arr, this).length === this.size; } push(val) { _classPrivateFieldGet(_arr, this)[_classPrivateFieldGet(_pointer, this)] = val; _classPrivateFieldSet(_pointer, this, (_classPrivateFieldGet(_pointer, this) + 1) % this.size); } values() { return _classPrivateFieldGet(_arr, this).slice(_classPrivateFieldGet(_pointer, this)).concat(_classPrivateFieldGet(_arr, this).slice(0, _classPrivateFieldGet(_pointer, this))); } clear() { _classPrivateFieldGet(_arr, this).length = 0; _classPrivateFieldSet(_pointer, this, 0); } } function getEventCoordinates(e) { if ('touches' in e) { return { clientX: e.touches[0].clientX, clientY: e.touches[0].clientY }; } return { clientX: e.clientX, clientY: e.clientY }; } // Only allow a single return type /** * Convert a computed ref to a record of refs. * The getter function must always return an object with the same keys. */ function destructComputed(getter) { const refs = reactive({}); watchEffect(() => { const base = getter(); for (const key in base) { refs[key] = base[key]; } }, { flush: 'sync' }); const obj = {}; for (const key in refs) { obj[key] = toRef(() => refs[key]); } return obj; } /** Array.includes but value can be any type */ function includes(arr, val) { return arr.includes(val); } function eventName(propName) { return propName[2].toLowerCase() + propName.slice(3); } // TODO: this should be an array but vue's types don't accept arrays: vuejs/core#8025 const EventProp = () => [Function, Array]; function hasEvent(props, name) { name = 'on' + capitalize(name); return !!(props[name] || props[`${name}Once`] || props[`${name}Capture`] || props[`${name}OnceCapture`] || props[`${name}CaptureOnce`]); } function callEvent(handler) { for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { args[_key2 - 1] = arguments[_key2]; } if (Array.isArray(handler)) { for (const h of handler) { h(...args); } } else if (typeof handler === 'function') { handler(...args); } } function focusableChildren(el) { let filterByTabIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; const targets = ['button', '[href]', 'input:not([type="hidden"])', 'select', 'textarea', '[tabindex]'].map(s => `${s}${filterByTabIndex ? ':not([tabindex="-1"])' : ''}:not([disabled])`).join(', '); return [...el.querySelectorAll(targets)]; } function getNextElement(elements, location, condition) { let _el; let idx = elements.indexOf(document.activeElement); const inc = location === 'next' ? 1 : -1; do { idx += inc; _el = elements[idx]; } while ((!_el || _el.offsetParent == null || !(condition?.(_el) ?? true)) && idx < elements.length && idx >= 0); return _el; } function focusChild(el, location) { const focusable = focusableChildren(el); if (!location) { if (el === document.activeElement || !el.contains(document.activeElement)) { focusable[0]?.focus(); } } else if (location === 'first') { focusable[0]?.focus(); } else if (location === 'last') { focusable.at(-1)?.focus(); } else if (typeof location === 'number') { focusable[location]?.focus(); } else { const _el = getNextElement(focusable, location); if (_el) _el.focus();else focusChild(el, location === 'next' ? 'first' : 'last'); } } function isEmpty(val) { return val === null || val === undefined || typeof val === 'string' && val.trim() === ''; } function noop() {} /** Returns null if the selector is not supported or we can't check */ function matchesSelector(el, selector) { const supportsSelector = IN_BROWSER && typeof CSS !== 'undefined' && typeof CSS.supports !== 'undefined' && CSS.supports(`selector(${selector})`); if (!supportsSelector) return null; try { return !!el && el.matches(selector); } catch (err) { return null; } } function ensureValidVNode(vnodes) { return vnodes.some(child => { if (!isVNode(child)) return true; if (child.type === Comment) return false; return child.type !== Fragment || ensureValidVNode(child.children); }) ? vnodes : null; } function defer(timeout, cb) { if (!IN_BROWSER || timeout === 0) { cb(); return () => {}; } const timeoutId = window.setTimeout(cb, timeout); return () => window.clearTimeout(timeoutId); } function isClickInsideElement(event, targetDiv) { const mouseX = event.clientX; const mouseY = event.clientY; const divRect = targetDiv.getBoundingClientRect(); const divLeft = divRect.left; const divTop = divRect.top; const divRight = divRect.right; const divBottom = divRect.bottom; return mouseX >= divLeft && mouseX <= divRight && mouseY >= divTop && mouseY <= divBottom; } function templateRef() { const el = shallowRef(); const fn = target => { el.value = target; }; Object.defineProperty(fn, 'value', { enumerable: true, get: () => el.value, set: val => el.value = val }); Object.defineProperty(fn, 'el', { enumerable: true, get: () => refElement(el.value) }); return fn; } function checkPrintable(e) { const isPrintableChar = e.key.length === 1; const noModifier = !e.ctrlKey && !e.metaKey && !e.altKey; return isPrintableChar && noModifier; } function isPrimitive(value) { return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint'; } // Utilities const block = ['top', 'bottom']; const inline = ['start', 'end', 'left', 'right']; /** Parse a raw anchor string into an object */ function parseAnchor(anchor, isRtl) { let [side, align] = anchor.split(' '); if (!align) { align = includes(block, side) ? 'start' : includes(inline, side) ? 'top' : 'center'; } return { side: toPhysical(side, isRtl), align: toPhysical(align, isRtl) }; } function toPhysical(str, isRtl) { if (str === 'start') return isRtl ? 'right' : 'left'; if (str === 'end') return isRtl ? 'left' : 'right'; return str; } function flipSide(anchor) { return { side: { center: 'center', top: 'bottom', bottom: 'top', left: 'right', right: 'left' }[anchor.side], align: anchor.align }; } function flipAlign(anchor) { return { side: anchor.side, align: { center: 'center', top: 'bottom', bottom: 'top', left: 'right', right: 'left' }[anchor.align] }; } function flipCorner(anchor) { return { side: anchor.align, align: anchor.side }; } function getAxis(anchor) { return includes(block, anchor.side) ? 'y' : 'x'; } class Box { constructor(_ref) { let { x, y, width, height } = _ref; this.x = x; this.y = y; this.width = width; this.height = height; } get top() { return this.y; } get bottom() { return this.y + this.height; } get left() { return this.x; } get right() { return this.x + this.width; } } function getOverflow(a, b) { return { x: { before: Math.max(0, b.left - a.left), after: Math.max(0, a.right - b.right) }, y: { before: Math.max(0, b.top - a.top), after: Math.max(0, a.bottom - b.bottom) } }; } function getTargetBox(target) { if (Array.isArray(target)) { return new Box({ x: target[0], y: target[1], width: 0, height: 0 }); } else { return target.getBoundingClientRect(); } } // Utilities /** @see https://stackoverflow.com/a/57876601/2074736 */ function nullifyTransforms(el) { const rect = el.getBoundingClientRect(); const style = getComputedStyle(el); const tx = style.transform; if (tx) { let ta, sx, sy, dx, dy; if (tx.startsWith('matrix3d(')) { ta = tx.slice(9, -1).split(/, /); sx = Number(ta[0]); sy = Number(ta[5]); dx = Number(ta[12]); dy = Number(ta[13]); } else if (tx.startsWith('matrix(')) { ta = tx.slice(7, -1).split(/, /); sx = Number(ta[0]); sy = Number(ta[3]); dx = Number(ta[4]); dy = Number(ta[5]); } else { return new Box(rect); } const to = style.transformOrigin; const x = rect.x - dx - (1 - sx) * parseFloat(to); const y = rect.y - dy - (1 - sy) * parseFloat(to.slice(to.indexOf(' ') + 1)); const w = sx ? rect.width / sx : el.offsetWidth + 1; const h = sy ? rect.height / sy : el.offsetHeight + 1; return new Box({ x, y, width: w, height: h }); } else { return new Box(rect); } } function animate(el, keyframes, options) { if (typeof el.animate === 'undefined') return { finished: Promise.resolve() }; let animation; try { animation = el.animate(keyframes, options); } catch (err) { return { finished: Promise.resolve() }; } if (typeof animation.finished === 'undefined') { animation.finished = new Promise(resolve => { animation.onfinish = () => { resolve(animation); }; }); } return animation; } // Utilities const handlers = new WeakMap(); function bindProps(el, props) { Object.keys(props).forEach(k => { if (isOn(k)) { const name = eventName(k); const handler = handlers.get(el); if (props[k] == null) { handler?.forEach(v => { const [n, fn] = v; if (n === name) { el.removeEventListener(name, fn); handler.delete(v); } }); } else if (!handler || ![...handler]?.some(v => v[0] === name && v[1] === props[k])) { el.addEventListener(name, props[k]); const _handler = handler || new Set(); _handler.add([name, props[k]]); if (!handlers.has(el)) handlers.set(el, _handler); } } else { if (props[k] == null) { el.removeAttribute(k); } else { el.setAttribute(k, props[k]); } } }); } function unbindProps(el, props) { Object.keys(props).forEach(k => { if (isOn(k)) { const name = eventName(k); const handler = handlers.get(el); handler?.forEach(v => { const [n, fn] = v; if (n === name) { el.removeEventListener(name, fn); handler.delete(v); } }); } else { el.removeAttribute(k); } }); } /** * WCAG 3.0 APCA perceptual contrast algorithm from https://github.com/Myndex/SAPC-APCA * @licence https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document * @see https://www.w3.org/WAI/GL/task-forces/silver/wiki/Visual_Contrast_of_Text_Subgroup */ // Types // MAGICAL NUMBERS // sRGB Conversion to Relative Luminance (Y) // Transfer Curve (aka "Gamma") for sRGB linearization // Simple power curve vs piecewise described in docs // Essentially, 2.4 best models actual display // characteristics in combination with the total method const mainTRC = 2.4; const Rco = 0.2126729; // sRGB Red Coefficient (from matrix) const Gco = 0.7151522; // sRGB Green Coefficient (from matrix) const Bco = 0.0721750; // sRGB Blue Coefficient (from matrix) // For Finding Raw SAPC Contrast from Relative Luminance (Y) // Constants for SAPC Power Curve Exponents // One pair for normal text, and one for reverse // These are the "beating heart" of SAPC const normBG = 0.55; const normTXT = 0.58; const revTXT = 0.57; const revBG = 0.62; // For Clamping and Scaling Values const blkThrs = 0.03; // Level that triggers the soft black clamp const blkClmp = 1.45; // Exponent for the soft black clamp curve const deltaYmin = 0.0005; // Lint trap const scaleBoW = 1.25; // Scaling for dark text on light const scaleWoB = 1.25; // Scaling for light text on dark const loConThresh = 0.078; // Threshold for new simple offset scale const loConFactor = 12.82051282051282; // = 1/0.078, const loConOffset = 0.06; // The simple offset const loClip = 0.001; // Output clip (lint trap #2) function APCAcontrast(text, background) { // Linearize sRGB const Rtxt = (text.r / 255) ** mainTRC; const Gtxt = (text.g / 255) ** mainTRC; const Btxt = (text.b / 255) ** mainTRC; const Rbg = (background.r / 255) ** mainTRC; const Gbg = (background.g / 255) ** mainTRC; const Bbg = (background.b / 255) ** mainTRC; // Apply the standard coefficients and sum to Y let Ytxt = Rtxt * Rco + Gtxt * Gco + Btxt * Bco; let Ybg = Rbg * Rco + Gbg * Gco + Bbg * Bco; // Soft clamp Y when near black. // Now clamping all colors to prevent crossover errors if (Ytxt <= blkThrs) Ytxt += (blkThrs - Ytxt) ** blkClmp; if (Ybg <= blkThrs) Ybg += (blkThrs - Ybg) ** blkClmp; // Return 0 Early for extremely low ∆Y (lint trap #1) if (Math.abs(Ybg - Ytxt) < deltaYmin) return 0.0; // SAPC CONTRAST let outputContrast; // For weighted final values if (Ybg > Ytxt) { // For normal polarity, black text on white // Calculate the SAPC contrast value and scale const SAPC = (Ybg ** normBG - Ytxt ** normTXT) * scaleBoW; // NEW! SAPC SmoothScale™ // Low Contrast Smooth Scale Rollout to prevent polarity reversal // and also a low clip for very low contrasts (lint trap #2) // much of this is for very low contrasts, less than 10 // therefore for most reversing needs, only loConOffset is important outputContrast = SAPC < loClip ? 0.0 : SAPC < loConThresh ? SAPC - SAPC * loConFactor * loConOffset : SAPC - loConOffset; } else { // For reverse polarity, light text on dark // WoB should always return negative value. const SAPC = (Ybg ** revBG - Ytxt ** revTXT) * scaleWoB; outputContrast = SAPC > -1e-3 ? 0.0 : SAPC > -0.078 ? SAPC - SAPC * loConFactor * loConOffset : SAPC + loConOffset; } return outputContrast * 100; } /* eslint-disable no-console */ function consoleWarn(message) { warn(`Vuetify: ${message}`); } function consoleError(message) { warn(`Vuetify error: ${message}`); } function deprecate(original, replacement) { replacement = Array.isArray(replacement) ? replacement.slice(0, -1).map(s => `'${s}'`).join(', ') + ` or '${replacement.at(-1)}'` : `'${replacement}'`; warn(`[Vuetify UPGRADE] '${original}' is deprecated, use ${replacement} instead.`); } // Types const delta = 0.20689655172413793; // 6÷29 const cielabForwardTransform = t => t > delta ** 3 ? Math.cbrt(t) : t / (3 * delta ** 2) + 4 / 29; const cielabReverseTransform = t => t > delta ? t ** 3 : 3 * delta ** 2 * (t - 4 / 29); function fromXYZ$1(xyz) { const transform = cielabForwardTransform; const transformedY = transform(xyz[1]); return [116 * transformedY - 16, 500 * (transform(xyz[0] / 0.95047) - transformedY), 200 * (transformedY - transform(xyz[2] / 1.08883))]; } function toXYZ$1(lab) { const transform = cielabReverseTransform; const Ln = (lab[0] + 16) / 116; return [transform(Ln + lab[1] / 500) * 0.95047, transform(Ln), transform(Ln - lab[2] / 200) * 1.08883]; } // Utilities // Types // For converting XYZ to sRGB const srgbForwardMatrix = [[3.2406, -1.5372, -0.4986], [-0.9689, 1.8758, 0.0415], [0.0557, -0.204, 1.0570]]; // Forward gamma adjust const srgbForwardTransform = C => C <= 0.0031308 ? C * 12.92 : 1.055 * C ** (1 / 2.4) - 0.055; // For converting sRGB to XYZ const srgbReverseMatrix = [[0.4124, 0.3576, 0.1805], [0.2126, 0.7152, 0.0722], [0.0193, 0.1192, 0.9505]]; // Reverse gamma adjust const srgbReverseTransform = C => C <= 0.04045 ? C / 12.92 : ((C + 0.055) / 1.055) ** 2.4; function fromXYZ(xyz) { const rgb = Array(3); const transform = srgbForwardTransform; const matrix = srgbForwardMatrix; // Matrix transform, then gamma adjustment for (let i = 0; i < 3; ++i) { // Rescale back to [0, 255] rgb[i] = Math.round(clamp(transform(matrix[i][0] * xyz[0] + matrix[i][1] * xyz[1] + matrix[i][2] * xyz[2])) * 255); } return { r: rgb[0], g: rgb[1], b: rgb[2] }; } function toXYZ(_ref) { let { r, g, b } = _ref; const xyz = [0, 0, 0]; const transform = srgbReverseTransform; const matrix = srgbReverseMatrix; // Rescale from [0, 255] to [0, 1] then adjust sRGB gamma to linear RGB r = transform(r / 255); g = transform(g / 255); b = transform(b / 255); // Matrix color space transform for (let i = 0; i < 3; ++i) { xyz[i] = matrix[i][0] * r + matrix[i][1] * g + matrix[i][2] * b; } return xyz; } // Utilities // Types function isCssColor(color) { return !!color && /^(#|var\(--|(rgb|hsl)a?\()/.test(color); } function isParsableColor(color) { return isCssColor(color) && !/^((rgb|hsl)a?\()?var\(--/.test(color); } const cssColorRe = /^(?<fn>(?:rgb|hsl)a?)\((?<values>.+)\)/; const mappers = { rgb: (r, g, b, a) => ({ r, g, b, a }), rgba: (r, g, b, a) => ({ r, g, b, a }), hsl: (h, s, l, a) => HSLtoRGB({ h, s, l, a }), hsla: (h, s, l, a) => HSLtoRGB({ h, s, l, a }), hsv: (h, s, v, a) => HSVtoRGB({ h, s, v, a }), hsva: (h, s, v, a) => HSVtoRGB({ h, s, v, a }) }; function parseColor(color) { if (typeof color === 'number') { if (isNaN(color) || color < 0 || color > 0xFFFFFF) { // int can't have opacity consoleWarn(`'${color}' is not a valid hex color`); } return { r: (color & 0xFF0000) >> 16, g: (color & 0xFF00) >> 8, b: color & 0xFF }; } else if (typeof color === 'string' && cssColorRe.test(color)) { const { groups } = color.match(cssColorRe); const { fn, values } = groups; const realValues = values.split(/,\s*|\s*\/\s*|\s+/).map((v, i) => { if (v.endsWith('%') || // unitless slv are % i > 0 && i < 3 && ['hsl', 'hsla', 'hsv', 'hsva'].includes(fn)) { return parseFloat(v) / 100; } else { return parseFloat(v); } }); return mappers[fn](...realValues); } else if (typeof color === 'string') { let hex = color.startsWith('#') ? color.slice(1) : color; if ([3, 4].includes(hex.length)) { hex = hex.split('').map(char => char + char).join(''); } else if (![6, 8].includes(hex.length)) { consoleWarn(`'${color}' is not a valid hex(a) color`); } const int = parseInt(hex, 16); if (isNaN(int) || int < 0 || int > 0xFFFFFFFF) { consoleWarn(`'${color}' is not a valid hex(a) color`); } return HexToRGB(hex); } else if (typeof color === 'object') { if (has(color, ['r', 'g', 'b'])) { return color; } else if (has(color, ['h', 's', 'l'])) { return HSVtoRGB(HSLtoHSV(color)); } else if (has(color, ['h', 's', 'v'])) { return HSVtoRGB(color); } } throw new TypeError(`Invalid color: ${color == null ? color : String(color) || color.constructor.name}\nExpected #hex, #hexa, rgb(), rgba(), hsl(), hsla(), object or number`); } /** Converts HSVA to RGBA. Based on formula from https://en.wikipedia.org/wiki/HSL_and_HSV */ function HSVtoRGB(hsva) { const { h, s, v, a } = hsva; const f = n => { const k = (n + h / 60) % 6; return v - v * s * Math.max(Math.min(k, 4 - k, 1), 0); }; const rgb = [f(5), f(3), f(1)].map(v => Math.round(v * 255)); return { r: rgb[0], g: rgb[1], b: rgb[2], a }; } function HSLtoRGB(hsla) { return HSVtoRGB(HSLtoHSV(hsla)); } /** Converts RGBA to HSVA. Based on formula from https://en.wikipedia.org/wiki/HSL_and_HSV */ function RGBtoHSV(rgba) { if (!rgba) return { h: 0, s: 1, v: 1, a: 1 }; const r = rgba.r / 255; const g = rgba.g / 255; const b = rgba.b / 255; const max = Math.max(r, g, b); const min = Math.min(r, g, b); let h = 0; if (max !== min) { if (max === r) { h = 60 * (0 + (g - b) / (max - min)); } else if (max === g) { h = 60 * (2 + (b - r) / (max - min)); } else if (max === b) { h = 60 * (4 + (r - g) / (max - min)); } } if (h < 0) h = h + 360; const s = max === 0 ? 0 : (max - min) / max; const hsv = [h, s, max]; return { h: hsv[0], s: hsv[1], v: hsv[2], a: rgba.a }; } function HSVtoHSL(hsva) { const { h, s, v, a } = hsva; const l = v - v * s / 2; const sprime = l === 1 || l === 0 ? 0 : (v - l) / Math.min(l, 1 - l); return { h, s: sprime, l, a }; } function HSLtoHSV(hsl) { const { h, s, l, a } = hsl; const v = l + s * Math.min(l, 1 - l); const sprime = v === 0 ? 0 : 2 - 2 * l / v; return { h, s: sprime, v, a }; } function RGBtoCSS(_ref) { let { r, g, b, a } = _ref; return a === undefined ? `rgb(${r}, ${g}, ${b})` : `rgba(${r}, ${g}, ${b}, ${a})`; } function HSVtoCSS(hsva) { return RGBtoCSS(HSVtoRGB(hsva)); } function toHex(v) { const h = Math.round(v).toString(16); return ('00'.substr(0, 2 - h.length) + h).toUpperCase(); } function RGBtoHex(_ref2) { let { r, g, b, a } = _ref2; return `#${[toHex(r), toHex(g), toHex(b), a !== undefined ? toHex(Math.round(a * 255)) : ''].join('')}`; } function HexToRGB(hex) { hex = parseHex(hex); let [r, g, b, a] = chunk(hex, 2).map(c => parseInt(c, 16)); a = a === undefined ? a : a / 255; return { r, g, b, a }; } function HexToHSV(hex) { const rgb = HexToRGB(hex); return RGBtoHSV(rgb); } function HSVtoHex(hsva) { return RGBtoHex(HSVtoRGB(hsva)); } function parseHex(hex) { if (hex.startsWith('#')) { hex = hex.slice(1); } hex = hex.replace(/([^0-9a-f])/gi, 'F'); if (hex.length === 3 || hex.length === 4) { hex = hex.split('').map(x => x + x).join(''); } if (hex.length !== 6) { hex = padEnd(padEnd(hex, 6), 8, 'F'); } return hex; } function lighten(value, amount) { const lab = fromXYZ$1(toXYZ(value)); lab[0] = lab[0] + amount * 10; return fromXYZ(toXYZ$1(lab)); } function darken(value, amount) { const lab = fromXYZ$1(toXYZ(value)); lab[0] = lab[0] - amount * 10; return fromXYZ(toXYZ$1(lab)); } /** * Calculate the relative luminance of a given color * @see https://www.w3.org/TR/WCAG20/#relativeluminancedef */ function getLuma(color) { const rgb = parseColor(color); return toXYZ(rgb)[1]; } /** * Returns the contrast ratio (1-21) between two colors. * @see https://www.w3.org/TR/WCAG20/#contrast-ratiodef */ function getContrast(first, second) { const l1 = getLuma(first); const l2 = getLuma(second); const light = Math.max(l1, l2); const dark = Math.min(l1, l2); return (light + 0.05) / (dark + 0.05); } function getForeground(color) { const blackContrast = Math.abs(APCAcontrast(parseColor(0), parseColor(color))); const whiteContrast = Math.abs(APCAcontrast(parseColor(0xffffff), parseColor(color))); // TODO: warn about poor color selections // const contrastAsText = Math.abs(APCAcontrast(colorVal, colorToInt(theme.colors.background))) // const minContrast = Math.max(blackContrast, whiteContrast) // if (minContrast < 60) { // consoleInfo(`${key} theme color ${color} has poor contrast (${minContrast.toFixed()}%)`) // } else if (contrastAsText < 60 && !['background', 'surface'].includes(color)) { // consoleInfo(`${key} theme color ${color} has poor contrast as text (${contrastAsText.toFixed()}%)`) // } // Prefer white text if both have an acceptable contrast ratio return whiteContrast > Math.min(blackContrast, 50) ? '#fff' : '#000'; } // Utilities function getCurrentInstance(name, message) { const vm = getCurrentInstance$1(); if (!vm) { throw new Error(`[Vuetify] ${name} ${'must be called from inside a setup function'}`); } return vm; } function getCurrentInstanceName() { let name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'composables'; const vm = getCurrentInstance(name).type; return toKebabCase(vm?.aliasName || vm?.name); } // Utilities // Types function injectSelf(key) { let vm = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getCurrentInstance('injectSelf'); const { provides } = vm; if (provides && key in provides) { // TS doesn't allow symbol as index type return provides[key]; } return undefined; } // Utilities // Types const DefaultsSymbol = Symbol.for('vuetify:defaults'); function createDefaults(options) { return ref(options); } function injectDefaults() { const defaults = inject$1(DefaultsSymbol); if (!defaults) throw new Error('[Vuetify] Could not find defaults instance'); return defaults; } function provideDefaults(defaults, options) { const injectedDefaults = injectDefaults(); const providedDefaults = ref(defaults); const newDefaults = computed(() => { const disabled = unref(options?.disabled); if (disabled) return injectedDefaults.value; const scoped = unref(options?.scoped); const reset = unref(options?.reset); const root = unref(options?.root); if (providedDefaults.value == null && !(scoped || reset || root)) return injectedDefaults.value; let properties = mergeDeep(providedDefaults.value, { prev: injectedDefaults.value }); if (scoped) return properties; if (reset || root) { const len = Number(reset || Infinity); for (let i = 0; i <= len; i++) { if (!properties || !('prev' in properties)) { break; } properties = properties.prev; } if (properties && typeof root === 'string' && root in properties) { properties = mergeDeep(mergeDeep(properties, { prev: properties }), properties[root]); } return properties; } return properties.prev ? mergeDeep(properties.prev, properties) : properties; }); provide(DefaultsSymbol, newDefaults); return newDefaults; } function propIsDefined(vnode, prop) { return vnode.props && (typeof vnode.props[prop] !== 'undefined' || typeof vnode.props[toKebabCase(prop)] !== 'undefined'); } function internalUseDefaults() { let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; let name = arguments.length > 1 ? arguments[1] : undefined; let defaults = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : injectDefaults(); const vm = getCurrentInstance('useDefaults'); name = name ?? vm.type.name ?? vm.type.__name; if (!name) { throw new Error('[Vuetify] Could not determine component name'); } const componentDefaults = computed(() => defaults.value?.[props._as ?? name]); const _props = new Proxy(props, { get(target, prop) { const propValue = Reflect.get(target, prop); if (prop === 'class' || prop === 'style') { return [componentDefaults.value?.[prop], propValue].filter(v => v != null); } if (propIsDefined(vm.vnode, prop)) return propValue; const _componentDefault = componentDefaults.value?.[prop]; if (_componentDefault !== undefined) return _componentDefault; const _globalDefault = defaults.value?.global?.[prop]; if (_globalDefault !== undefined) return _globalDefault; return propValue; } }); const _subcomponentDefaults = shallowRef(); watchEffect(() => { if (componentDefaults.value) { const subComponents = Object.entries(componentDefaults.value).filter(_ref => { let [key] = _ref; return key.startsWith(key[0].toUpperCase()); }); _subcomponentDefaults.value = subComponents.length ? Object.fromEntries(subComponents) : undefined; } else { _subcomponentDefaults.value = undefined; } }); function provideSubDefaults() { const injected = injectSelf(DefaultsSymbol, vm); provide(DefaultsSymbol, computed(() => { return _subcomponentDefaults.value ? mergeDeep(injected?.value ?? {}, _subcomponentDefaults.value) : injected?.value; })); } return { props: _props, provideSubDefaults }; } function useDefaults() { let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; let name = arguments.length > 1 ? arguments[1] : undefined; const { props: _props, provideSubDefaults } = internalUseDefaults(props, name); provideSubDefaults(); return _props; } // Composables // Types // No props // Object Props // Implementation function defineComponent(options) { options._setup = options._setup ?? options.setup; if (!options.name) { consoleWarn('The component is missing an explicit name, unable to generate default prop value'); return options; } if (options._setup) { options.props = propsFactory(options.props ?? {}, options.name)(); const propKeys = Object.keys(options.props).filter(key => key !== 'class' && key !== 'style'); options.filterProps = function filterProps(props) { return pick(props, propKeys); }; options.props._as = String; options.setup = function setup(props, ctx) { const defaults = injectDefaults(); // Skip props proxy if defaults are not provided if (!defaults.value) return options._setup(props, ctx); const { props: _props, provideSubDefaults } = internalUseDefaults(props, props._as ?? options.name, defaults); const setupBindings = options._setup(_props, ctx); provideSubDefaults(); return setupBindings; }; } return options; } // No argument - simple default slot // Generic constructor argument - generic props and slots // Slots argument - simple slots // Implementation function genericComponent() { let exposeDefaults = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; return options => (exposeDefaults ? defineComponent : defineComponent$1)(options); } function defineFunctionalComponent(props, render) { render.props = props; return render; } // Adds a filterProps method to the component options // https://github.com/vuejs/core/pull/10557 // not a vue Component // Composables function createSimpleFunctional(klass) { let tag = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'div'; let name = arguments.length > 2 ? arguments[2] : undefined; return genericComponent()({ name: name ?? capitalize(camelize(klass.replace(/__/g, '-'))), props: { tag: { type: String, default: tag }, ...makeComponentProps() }, setup(props, _ref) { let { slots } = _ref; return () => { return h(props.tag, { class: [klass, props.class], style: props.style }, slots.default?.()); }; } }); } /** * Returns: * - 'null' if the node is not attached to the DOM * - the root node (HTMLDocument | ShadowRoot) otherwise */ function attachedRoot(node) { /* istanbul ignore next */ if (typeof node.getRootNode !== 'function') { // Shadow DOM not supported (IE11), lets find the root of this node while (node.parentNode) node = node.parentNode; // The root parent is the document if the node is attached to the DOM if (node !== document) return null; return document; } const root = node.getRootNode(); // The composed root node is the document if the node is attached to the DOM if (root !== document && root.getRootNode({ composed: true }) !== document) return null; return root; } const standardEasing = 'cubic-bezier(0.4, 0, 0.2, 1)'; const deceleratedEasing = 'cubic-bezier(0.0, 0, 0.2, 1)'; // Entering const acceleratedEasing = 'cubic-bezier(0.4, 0, 1, 1)'; // Leaving // Utilities function getPrefixedEventHandlers(attrs, suffix, getData) { return Object.keys(attrs).filter(key => isOn(key) && key.endsWith(suffix)).reduce((acc, key) => { acc[key.slice(0, -suffix.length)] = event => attrs[key](event, getData(event)); return acc; }, {}); } function getScrollParent(el) { let includeHidden = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; while (el) { if (includeHidden ? isPotentiallyScrollable(el) : hasScrollbar(el)) return el; el = el.parentElement; } return document.scrollingElement; } function getScrollParents(el, stopAt) { const elements = []; if (stopAt && el && !stopAt.contains(el)) return elements; while (el) { if (hasScrollbar(el)) elements.push(el); if (el === stopAt) break; el = el.parentElement; } return elements; } function hasScrollbar(el) { if (!el || el.nodeType !== Node.ELEMENT_NODE) return false; const style = window.getComputedStyle(el); return style.overflowY === 'scroll' || style.overflowY === 'auto' && el.scrollHeight > el.clientHeight; } function isPotentiallyScrollable(el) { if (!el || el.nodeType !== Node.ELEMENT_NODE) return false; const style = window.getComputedStyle(el); return ['scroll', 'auto'].includes(style.overflowY); } function isFixedPosition(el) { while (el) { if (window.getComputedStyle(el).position === 'fixed') { return true; } el = el.offsetParent; } return false; } // Utilities // Types function useRender(render) { const vm = getCurrentInstance('useRender'); vm.render = render; } // Utilities // Types function useResizeObserver(callback) { let box = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'content'; const resizeRef = templateRef(); const contentRect = ref(); if (IN_BROWSER) { const observer = new ResizeObserver(entries => { callback?.(entries, observer); if (!entries.length) return; if (box === 'content') { contentRect.value = entries[0].contentRect; } else { contentRect.value = entries[0].target.getBoundingClientRect(); } }); onBeforeUnmount(() => { observer.disconnect(); }); watch(() => resizeRef.el, (newValue, oldValue) => { if (oldValue) { observer.unobserve(oldValue); contentRect.value = undefined; } if (newValue) observer.observe(newValue); }, { flush: 'post' }); } return { resizeRef, contentRect: readonly(contentRect) }; } // Composables // Types const VuetifyLayoutKey = Symbol.for('vuetify:layout'); const VuetifyLayoutItemKey = Symbol.for('vuetify:layout-item'); const ROOT_ZINDEX = 1000; const makeLayoutProps = propsFactory({ overlaps: { type: Array, default: () => [] }, fullHeight: Boolean }, 'layout'); // Composables const makeLayoutItemProps = propsFactory({ name: { type: String }, order: { type: [Number, String], default: 0 }, absolute: Boolean }, 'layout-item'); function useLayout() { const layout = inject$1(VuetifyLayoutKey); if (!layout) throw new Error('[Vuetify] Could not find injected layout'); return { getLayoutItem: layout.getLayoutItem, mainRect: layout.mainRect, mainStyles: layout.mainStyles }; } function useLayoutItem(options) { const layout = inject$1(VuetifyLayoutKey); if (!layout) throw new Error('[Vuetify] Could not find injected layout'); const id = options.id ?? `layout-item-${useId()}`; const vm = getCurrentInstance('useLayoutItem'); provide(VuetifyLayoutItemKey, { id }); const isKeptAlive = shallowRef(false); onDeactivated(() => isKeptAlive.value = true); onActivated(() => isKeptAlive.value = false); const { layoutItemStyles, layoutItemScrimStyles } = layout.register(vm, { ...options, active: computed(() => isKeptAlive.value ? false : options.active.value), id }); onBeforeUnmount(() => layout.unregister(id)); return { layoutItemStyles, layoutRect: layout.layoutRect, layoutItemScrimStyles }; } const generateLayers = (layout, positions, layoutSizes, activeIte