UNPKG

vuetify

Version:

Vue Material Component Framework

42,520 lines 1.42 MB
/*!
* Vuetify v4.1.11
* Forged by John Leider
* Released under the MIT License.
*/

(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vue')) :
  typeof define === 'function' && define.amd ? define(['exports', 'vue'], factory) :
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Vuetify = {}, global.Vue));
})(this, (function (exports, vue) { 'use strict';

  /* eslint-disable no-console */

  function consoleWarn(message) {
    vue.warn(`Vuetify: ${message}`);
  }
  function consoleError(message) {
    vue.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}'`;
    vue.warn(`[Vuetify UPGRADE] '${original}' is deprecated, use ${replacement} instead.`);
  }

  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;
  const SUPPORTS_MATCH_MEDIA = IN_BROWSER && 'matchMedia' in window && typeof window.matchMedia === 'function';
  const PREFERS_REDUCED_MOTION = () => SUPPORTS_MATCH_MEDIA && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  const IS_WEBKIT = IN_BROWSER && CSS?.supports?.('-webkit-backdrop-filter', 'none');

  // Utilities

  // 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 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, start = 0) {
    return Array.from({
      length
    }, (v, k) => start + k);
  }
  function convertToUnit(str, unit = '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;
  }
  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', 'inert', /^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 = (...args) => {
      clearTimeout(timeoutId);
      timeoutId = setTimeout(() => fn(...args), vue.unref(delay));
    };
    wrap.clear = () => {
      clearTimeout(timeoutId);
    };
    wrap.immediate = fn;
    return wrap;
  }
  function clamp(value, min = 0, max = 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, char = '0') {
    return str + char.repeat(Math.max(0, length - str.length));
  }
  function padStart(str, length, char = '0') {
    return char.repeat(Math.max(0, length - str.length)) + str;
  }
  function chunk(str, size = 1) {
    const chunked = [];
    let index = 0;
    while (index < str.length) {
      chunked.push(str.substr(index, size));
      index += size;
    }
    return chunked;
  }
  function chunkArray(array, size = 1) {
    return Array.from({
      length: Math.ceil(array.length / size)
    }, (v, i) => array.slice(i * size, i * size + size));
  }
  function humanReadableFileSize(bytes, base = 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(source = {}, target = {}, arrayFn, targetCondition) {
    const out = {};
    for (const key in source) {
      out[key] = source[key];
    }
    for (const key in target) {
      const targetProperty = target[key];
      if (targetCondition && !targetCondition(key, targetProperty)) {
        continue;
      }
      const sourceProperty = source[key];

      // Only continue deep merging if
      // both properties are plain objects
      if (isPlainObject(sourceProperty) && isPlainObject(targetProperty)) {
        out[key] = mergeDeep(sourceProperty, targetProperty, arrayFn, targetCondition);
        continue;
      }
      out[key] = targetProperty;
    }
    return out;
  }
  function flattenFragments(nodes) {
    return nodes.map(node => {
      if (node.type === vue.Fragment) {
        return flattenFragments(node.children);
      } else {
        return node;
      }
    }).flat();
  }
  function toKebabCase(str = '') {
    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.getOwnPropertyDescriptor(vnode.component.provides, key)) {
        return [vnode.component];
      } else if (vnode.component.subTree) {
        return findChildrenWithProvide(key, vnode.component.subTree).flat(1);
      }
    }
    return [];
  }
  class CircularBuffer {
    #arr = [];
    #pointer = 0;
    constructor(size) {
      this.size = size;
    }
    get isFull() {
      return this.#arr.length === this.size;
    }
    push(val) {
      this.#arr[this.#pointer] = val;
      this.#pointer = (this.#pointer + 1) % this.size;
    }
    values() {
      return this.#arr.slice(this.#pointer).concat(this.#arr.slice(0, this.#pointer));
    }
    clear() {
      this.#arr.length = 0;
      this.#pointer = 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 = vue.reactive({});
    vue.watchEffect(() => {
      const base = getter();
      for (const key in base) {
        refs[key] = base[key];
      }
    }, {
      flush: 'sync'
    });
    const obj = {};
    for (const key in refs) {
      obj[key] = vue.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' + vue.capitalize(name);
    return !!(props[name] || props[`${name}Once`] || props[`${name}Capture`] || props[`${name}OnceCapture`] || props[`${name}CaptureOnce`]);
  }
  function callEvent(handler, ...args) {
    if (Array.isArray(handler)) {
      for (const h of handler) {
        h(...args);
      }
    } else if (typeof handler === 'function') {
      handler(...args);
    }
  }
  function focusableChildren(el, filterByTabIndex = true) {
    const targets = ['button', '[href]', 'input:not([type="hidden"])', 'select', 'textarea', 'details:not(:has(> summary))', 'details > summary', '[tabindex]', '[contenteditable]:not([contenteditable="false"])', 'audio[controls]', 'video[controls]'].map(s => `${s}${filterByTabIndex ? ':not([tabindex="-1"])' : ''}:not([disabled], [inert])`).join(', ');
    let elements;
    try {
      elements = [...el.querySelectorAll(targets)];
    } catch (err) {
      consoleError(String(err));
      return [];
    }
    return elements.filter(x => !x.closest('[inert]')) // does not have inert parent
    .filter(x => !!x.offsetParent || x.getClientRects().length > 0) // is rendered
    .filter(x => !x.parentElement?.closest('details:not([open])') || x.tagName === 'SUMMARY' && x.parentElement?.tagName === 'DETAILS');
  }
  function getActiveElement() {
    let active = document.activeElement;
    while (active?.shadowRoot?.activeElement) {
      active = active.shadowRoot.activeElement;
    }
    return active;
  }
  function getNextElement(elements, location, condition) {
    let _el;
    let idx = elements.indexOf(getActiveElement());
    if (idx < 0) {
      idx = elements.findIndex(el => el.getAttribute('aria-selected') === 'true');
    }
    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, options) {
    const focusable = focusableChildren(el);
    if (location == null) {
      const active = getActiveElement();
      if (el === active || !el.contains(active)) {
        focusable[0]?.focus(options);
      }
    } else if (location === 'first') {
      focusable[0]?.focus(options);
    } else if (location === 'last') {
      focusable.at(-1)?.focus(options);
    } else if (typeof location === 'number') {
      focusable[location]?.focus(options);
    } else {
      const _el = getNextElement(focusable, location);
      if (_el) _el.focus();else focusChild(el, location === 'next' ? 'first' : 'last', options);
    }
  }
  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 (!vue.isVNode(child)) return true;
      if (child.type === vue.Comment) return false;
      return child.type !== vue.Fragment || ensureValidVNode(child.children);
    }) ? vnodes : null;
  }
  function renderSlot(slot, props, fallback) {
    // TODO: check if slot returns elements: #18308
    return slot?.(props) ?? fallback?.(props);
  }
  function defer(timeout, cb) {
    if (!IN_BROWSER || timeout === 0) {
      cb();
      return () => {};
    }
    const timeoutId = window.setTimeout(cb, timeout);
    return () => window.clearTimeout(timeoutId);
  }
  function templateRef() {
    const el = vue.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';
  }
  function escapeForRegex(sign) {
    return '\\^$*+?.()|{}[]'.includes(sign) ? `\\${sign}` : sign;
  }
  function normalizeMinusSign(text) {
    return text.replace(/−/g, '-');
  }
  function extractNumber(text, decimalDigitsLimit, decimalSeparator) {
    const onlyValidCharacters = new RegExp(`[\\d\\-${escapeForRegex(decimalSeparator)}]`);
    const cleanText = normalizeMinusSign(text).split('').filter(x => onlyValidCharacters.test(x)).filter((x, i, all) => i === 0 && /[-]/.test(x) ||
    // sign allowed at the start
    x === decimalSeparator && i === all.indexOf(x) ||
    // decimal separator allowed only once
    /\d/.test(x)).join('');
    if (decimalDigitsLimit === 0) {
      return cleanText.split(decimalSeparator)[0];
    }
    const decimalPart = new RegExp(`${escapeForRegex(decimalSeparator)}\\d`);
    if (decimalDigitsLimit !== null && decimalPart.test(cleanText)) {
      const parts = cleanText.split(decimalSeparator);
      return [parts[0], parts[1].substring(0, decimalDigitsLimit)].join(decimalSeparator);
    }
    return cleanText;
  }
  function camelizeProps(props) {
    const out = {};
    for (const prop in props) {
      out[vue.camelize(prop)] = props[prop];
    }
    return out;
  }
  function onlyDefinedProps(props) {
    const booleanAttributes = ['checked', 'disabled'];
    return Object.fromEntries(Object.entries(props).filter(([key, v]) => booleanAttributes.includes(key) ? !!v : v !== undefined));
  }
  function deepToRaw(value) {
    const objectIterator = input => {
      if (Array.isArray(input)) {
        return input.map(item => objectIterator(item));
      }
      if (vue.isRef(input) || vue.isReactive(input) || vue.isProxy(input)) {
        return objectIterator(vue.toRaw(input));
      }
      if (isPlainObject(input)) {
        return Object.keys(input).reduce((acc, key) => {
          acc[key] = objectIterator(input[key]);
          return acc;
        }, {});
      }
      return input;
    };
    return objectIterator(value);
  }

  // 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(args) {
      const pageScale = document.body.currentCSSZoom ?? 1;
      const isElement = args instanceof Element;
      const factor = isElement ? 1 + (1 - pageScale) / pageScale : 1;
      const {
        x,
        y,
        width,
        height
      } = isElement ? args.getBoundingClientRect() : args;
      this.x = x * factor;
      this.y = y * factor;
      this.width = width * factor;
      this.height = height * factor;
    }
    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)) {
      const pageScale = document.body.currentCSSZoom ?? 1;
      const factor = 1 + (1 - pageScale) / pageScale;
      return new Box({
        x: target[0] * factor,
        y: target[1] * factor,
        width: 0 * factor,
        height: 0 * factor
      });
    } else {
      return new Box(target);
    }
  }
  function getElementBox(el) {
    if (el === document.documentElement) {
      if (!visualViewport) {
        return new Box({
          x: 0,
          y: 0,
          width: document.documentElement.clientWidth,
          height: document.documentElement.clientHeight
        });
      } else {
        return new Box({
          x: visualViewport.scale > 1 || IS_WEBKIT ? 0 : visualViewport.offsetLeft,
          y: visualViewport.scale > 1 || IS_WEBKIT ? 0 : visualViewport.offsetTop,
          width: document.documentElement.clientWidth,
          height: document.documentElement.clientHeight
        });
      }
    } else {
      return new Box(el);
    }
  }

  // Utilities

  /** @see https://stackoverflow.com/a/57876601/2074736 */
  function nullifyTransforms(el) {
    const rect = new Box(el);
    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 > -loClip ? 0.0 : SAPC > -loConThresh ? SAPC - SAPC * loConFactor * loConOffset : SAPC + loConOffset;
    }
    return outputContrast * 100;
  }

  // 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({
    r,
    g,
    b
  }) {
    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({
    r,
    g,
    b,
    a
  }) {
    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({
    r,
    g,
    b,
    a
  }) {
    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 hasLightForeground(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);
  }

  // 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

  // TODO: import from vue once upstream PR is merged
  // https://github.com/vuejs/core/pull/14441

  // Composables
  const makeComponentProps = propsFactory({
    class: [String, Array, Object],
    style: {
      type: [String, Array, Object],
      default: null
    }
  }, 'component');

  // Utilities
  function getCurrentInstance(name, message) {
    const vm = vue.getCurrentInstance();
    if (!vm) {
      throw new Error(`[Vuetify] ${name} ${'must be called from inside a setup function'}`);
    }
    return vm;
  }
  function getCurrentInstanceName(name = 'composables') {
    const vm = getCurrentInstance(name).type;
    return toKebabCase(vm?.aliasName || vm?.name);
  }

  // Utilities

  // Types

  function injectSelf(key, vm = 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 vue.ref(options);
  }
  function injectDefaults() {
    const defaults = vue.inject(DefaultsSymbol);
    if (!defaults) throw new Error('[Vuetify] Could not find defaults instance');
    return defaults;
  }
  function provideDefaults(defaults, options) {
    const injectedDefaults = injectDefaults();
    const providedDefaults = vue.ref(defaults);
    const newDefaults = vue.computed(() => {
      const disabled = vue.unref(options?.disabled);
      if (disabled) return injectedDefaults.value;
      const scoped = vue.unref(options?.scoped);
      const reset = vue.unref(options?.reset);
      const root = vue.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);
        const rootDefaults = typeof root === 'string' ? properties.prev?.[root] : undefined;
        for (let i = 0; i <= len; i++) {
          if (!properties || !('prev' in properties)) {
            break;
          }
          properties = properties.prev;
        }
        if (properties && rootDefaults) {
          properties = mergeDeep(mergeDeep(properties, {
            prev: properties
          }), rootDefaults);
        }
        return properties;
      }
      return properties.prev ? mergeDeep(properties.prev, properties, undefined, (_, v) => v !== undefined) : properties;
    });
    vue.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(props = {}, name, defaults = 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 = vue.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 = vue.shallowRef();
    vue.watchEffect(() => {
      if (componentDefaults.value) {
        const subComponents = Object.entries(componentDefaults.value).filter(([key]) => key.startsWith(key[0].toUpperCase()));
        _subcomponentDefaults.value = subComponents.length ? Object.fromEntries(subComponents) : undefined;
      } else {
        _subcomponentDefaults.value = undefined;
      }
    });
    function provideSubDefaults() {
      const injected = injectSelf(DefaultsSymbol, vm);
      vue.provide(DefaultsSymbol, vue.computed(() => {
        return _subcomponentDefaults.value ? mergeDeep(injected?.value ?? {}, _subcomponentDefaults.value) : injected?.value;
      }));
    }
    return {
      props: _props,
      provideSubDefaults
    };
  }
  function useDefaults(props = {}, name) {
    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(exposeDefaults = true) {
    return options => (exposeDefaults ? defineComponent : vue.defineComponent)(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, tag = 'div', name) {
    return genericComponent()({
      name: name ?? vue.capitalize(vue.camelize(klass.replace(/__/g, '-'))),
      props: {
        tag: {
          type: String,
          default: tag
        },
        ...makeComponentProps()
      },
      setup(props, {
        slots
      }) {
        return () => {
          return vue.h(props.tag, {
            class: [klass, props.class],
            style: props.style
          }, slots.default?.());
        };
      }
    });
  }

  function updateRecursionCache(a, b, cache, result) {
    if (!cache || isPrimitive(a) || isPrimitive(b)) return;
    const visitedObject = cache.get(a);
    if (visitedObject) {
      visitedObject.set(b, result);
    } else {
      const newCacheItem = new WeakMap();
      newCacheItem.set(b, result);
      cache.set(a, newCacheItem);
    }
  }
  function findCachedComparison(a, b, cache) {
    if (!cache || isPrimitive(a) || isPrimitive(b)) return null;
    const r1 = cache.get(a)?.get(b);
    if (typeof r1 === 'boolean') return r1;
    const r2 = cache.get(b)?.get(a);
    if (typeof r2 === 'boolean') return r2;
    return null;
  }
  function deepEqual(a, b, recursionCache = new WeakMap()) {
    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;
    }
    const cachedComparisonResult = findCachedComparison(a, b, recursionCache);
    if (cachedComparisonResult) {
      return cachedComparisonResult;
    }
    updateRecursionCache(a, b, recursionCache, true);
    return props.every(p => deepEqual(a[p], b[p], recursionCache));
  }

  /**
   * 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;
  }

  // Utilities

  // Types

  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

  const easingPatterns = {
    linear: t => t,
    easeInQuad: t => t ** 2,
    easeOutQuad: t => t * (2 - t),
    easeInOutQuad: t => t < 0.5 ? 2 * t ** 2 : -1 + (4 - 2 * t) * t,
    easeInCubic: t => t ** 3,
    easeOutCubic: t => --t ** 3 + 1,
    easeInOutCubic: t => t < 0.5 ? 4 * t ** 3 : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1,
    easeInQuart: t => t ** 4,
    easeOutQuart: t => 1 - --t ** 4,
    easeInOutQuart: t => t < 0.5 ? 8 * t ** 4 : 1 - 8 * --t ** 4,
    easeInQuint: t => t ** 5,
    easeOutQuint: t => 1 + --t ** 5,
    easeInOutQuint: t => t < 0.5 ? 16 * t ** 5 : 1 + 16 * --t ** 5,
    instant: t => 1
  };
  function useTransition(source, options) {
    const defaultTransition = {
      duration: 300,
      transition: easingPatterns.easeInOutCubic
    };
    let raf = -1;
    const outputRef = vue.shallowRef(vue.toValue(source));
    vue.watch(() => vue.toValue(source), async to => {
      cancelAnimationFrame(raf);
      const easing = {
        ...defaultTransition,
        ...vue.toValue(options)
      };
      await executeTransition(outputRef, outputRef.value, to, easing);
    });
    function executeTransition(out, from, to, options) {
      const startTime = performance.now();
      const ease = PREFERS_REDUCED_MOTION() ? easingPatterns.instant : options.transition ?? easingPatterns.easeInOutCubic;
      return new Promise(resolve => {
        raf = requestAnimationFrame(function step(currentTime) {
          const timeElapsed = currentTime - startTime;
          const progress = timeElapsed / options.duration;
          out.value = from + (to - from) * ease(clamp(progress, 0, 1));
          if (progress < 1) {
            raf = requestAnimationFrame(step);
          } else {
            out.value = to;
            resolve();
          }
        });
      });
    }
    return vue.computed(() => outputRef.value);
  }

  // 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 => callEvent(attrs[key], event, getData(event));
      return acc;
    }, {});
  }

  function getScrollParent(el, includeHidden = 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);
    const hasVerticalScrollbar = style.overflowY === 'scroll' || style.overflowY === 'auto' && el.scrollHeight > el.clientHeight;
    const hasHorizontalScrollbar = style.overflowX === 'scroll' || style.overflowX === 'auto' && el.scrollWidth > el.clientWidth;
    return hasVerticalScrollbar || hasHorizontalScrollbar;
  }
  function isPotentiallyScrollable(el) {
    if (!el || el.nodeType !== Node.ELEMENT_NODE) return false;
    const style = window.getComputedStyle(el);
    return ['scroll', 'auto'].includes(style.overflowY);
  }

  // Types

  function getIndentLines({
    depth,
    isLast,
    isLastGroup,
    leafLinks,
    separateRoots,
    parentIndentLines,
    variant
  }) {
    const isLastLeaf = isLast && (!isLastGroup || separateRoots || depth > 1);
    if (!parentIndentLines || !depth) {
      return {
        leaf: undefined,
        node: undefined,
        children: parentIndentLines,
        footer: parentIndentLines && (!isLastLeaf || variant === 'simple') ? [...parentIndentLines, separateRoots ? 'none' : 'line'] : ['none']
      };
    }
    if (variant === 'simple') {
      return {
        leaf: [...parentIndentLines, 'line'],
        node: [...parentIndentLines, 'line'],
        children: [...parentIndentLines, 'line'],
        footer: [...parentIndentLines, 'line', 'line']
      };
    }
    return {
      leaf: [...parentIndentLines, isLastLeaf ? 'last-leaf' : 'leaf', ...(leafLinks ? ['leaf-link'] : [])],
      node: [...parentIndentLines, isLastLeaf ? 'last-leaf' : 'leaf'],
      children: [...parentIndentLines, isLastLeaf ? 'none' : 'line'],
      footer: [...parentIndentLines, isLastLeaf ? 'none' : 'line']
    };
  }

  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;
  }

  function throttle(fn, delay, options = {
    leading: true,
    trailing: true
  }) {
    let timeoutId = 0;
    let lastExec = 0;
    let throttling = false;
    let start = 0;
    function clear() {
      clearTimeout(timeoutId);
      throttling = false;
      start = 0;
    }
    const wrap = (...args) => {
      clearTimeout(timeoutId);
      const now = Date.now();
      if (!start) start = now;
      const elapsed = now - Math.max(start, lastExec);
      function invoke() {
        lastExec = Date.now();
        timeoutId = setTimeout(clear, delay);
        fn(...args);
      }
      if (!throttling) {
        throttling = true;
        if (options.leading) {
          invoke();
        }
      } else if (elapsed >= delay) {
        invoke();
      } else if (options.trailing) {
        timeoutId = setTimeout(invoke, delay - elapsed);
      }
    };
    wrap.clear = clear;
    wrap.immediate = fn;
    return wrap;
  }

  // Utilities

  // Types

  const IconValue = [String, Function, Object, Array];
  const IconSymbol = Symbol.for('vuetify:icons');
  const makeIconProps = propsFactory({
    icon: {
      type: IconValue
    },
    // Could not remove this and use makeTagProps, types complained because it is not required
    tag: {
      type: [String, Object, Function],
      required: true
    }
  }, 'icon');
  const VComponentIcon = genericComponent()({
    name: 'VComponentIcon',
    props: makeIconProps(),
    setup(props, {
      slots
    }) {
      return () => {
        const Icon = props.icon;
        return vue.createVNode(props.tag, null, {
          default: () => [props.icon ? vue.createVNode(Icon, null, null) : slots.default?.()]
        });
      };
    }
  });
  const VSvgIcon = defineComponent({
    name: 'VSvgIcon',
    inheritAttrs: false,
    props: makeIconProps(),
    setup(props, {
      attrs
    }) {
      return () => {
        return vue.createVNode(props.tag, vue.mergeProps(attrs, {
          "style": null
        }), {
          default: () => [vue.createElementVNode("svg", {
            "class": "v-icon__svg",
            "xmlns": "http://www.w3.org/2000/svg",
            "viewBox": "0 0 24 24",
            "role": "img",
            "aria-hidden": "true"
          }, [Array.isArray(props.icon) ? props.icon.map(path => Array.isArray(path) ? vue.createElementVNode("path", {
            "d": path[0],
            "fill-opacity": path[1]
          }, null) : vue.createElementVNode("path", {
            "d": path
          }, null)) : vue.createElementVNode("path", {
            "d": props.icon
          }, null)])]
        });
      };
    }
  });
  const VLigatureIcon = defineComponent({
    name: 'VLigatureIcon',
    props: makeIconProps(),
    setup(props) {
      return () => {
        return vue.createVNode(props.tag, null, {
          default: () => [props.icon]
        });
      };
    }
  });
  const VClassIcon = defineComponent({
    name: 'VClassIcon',
    props: makeIconProps(),
    setup(props) {
      return () => {
        return vue.createVNode(props.tag, {
          "class": vue.normalizeClass(props.icon)
        }, null);
      };
    }
  });
  const useIcon = props => {
    const icons = vue.inject(IconSymbol);
    if (!icons) throw new Error('Missing Vuetify Icons provide!');
    const iconData = vue.computed(() => {
      const iconAlias = vue.toValue(props);
      if (!iconAlias) return {
        component: VComponentIcon
      };
      let icon = iconAlias;
      if (typeof icon === 'string') {
        icon = icon.trim();
        if (icon.startsWith('$')) {
          icon = icons.aliases?.[icon.slice(1)];
        }
      }
      if (!icon) consoleWarn(`Could not find aliased icon "${iconAlias}"`);
      if (Array.isArray(icon)) {
        return {
          component: VSvgIcon,
          icon
        };
      } else if (typeof icon !== 'string') {
        return {
          component: VComponentIcon,
          icon
        };
      }
      const iconSetName = Object.keys(icons.sets).find(setName => typeof icon === 'string' && icon.startsWith(`${setName}:`));
      const iconName = iconSetName ? icon.slice(iconSetName.length + 1) : icon;
      const iconSet = icons.sets[iconSetName ?? icons.defaultSet];
      return {
        component: iconSet.component,
        icon: iconName
      };
    });
    return {
      iconData
    };
  };

  // Composables

  // Types

  const aliases = {
    collapse: 'mdi-chevron-up',
    complete: 'mdi-check',
    cancel: 'mdi-close-circle',
    close: 'mdi-close',
    delete: 'mdi-close-circle',
    // delete (e.g. v-chip close)
    clear: 'mdi-close-circle',
    success: 'mdi-check-circle',
    info: 'mdi-information',
    warning: 'mdi-alert-circle',
    error: 'mdi-close-circle',
    prev: 'mdi-chevron-left',
    next: 'mdi-chevron-right',
    checkboxOn: 'mdi-checkbox-marked',
    checkboxOff: 'mdi-checkbox-blank-outline',
    checkboxIndeterminate: 'mdi-minus-box',
    delimiter: 'mdi-circle',
    // for carousel
    sortAsc: 'mdi-arrow-up',
    sortDesc: 'mdi-arrow-down',
    expand: 'mdi-chevron-down',
    menu: 'mdi-menu',
    subgroup: 'mdi-menu-down',
    dropdown: 'mdi-menu-down',
    radioOn: 'mdi-radiobox-marked',
    radioOff: 'mdi-radiobox-blank',
    edit: 'mdi-pencil',
    ratingEmpty: 'mdi-star-outline',
    ratingFull: 'mdi-star',
    ratingHalf: 'mdi-star-half-full',
    loading: 'mdi-cached',
    first: 'mdi-page-first',
    last: 'mdi-page-last',
    unfold: 'mdi-unfold-more-horizontal',
    file: 'mdi-paperclip',
    plus: 'mdi-plus',
    minus: 'mdi-minus',
    calendar: 'mdi-calendar',
    treeviewCollapse: 'mdi-menu-down',
    treeviewExpand: 'mdi-menu-right',
    tableGroupCollapse: 'mdi-chevron-down',
    tableGroupExpand: 'mdi-chevron-right',
    eyeDropper: 'mdi-eyedropper',
    upload: 'mdi-cloud-upload',
    color: 'mdi-palette',
    command: 'mdi-apple-keyboard-command',
    ctrl: 'mdi-apple-keyboard-control',
    space: 'mdi-keyboard-space',
    shift: 'mdi-apple-keyboard-shift',
    alt: 'mdi-apple-keyboard-option',
    enter: 'mdi-keyboard-return',
    arrowup: 'mdi-arrow-up',
    arrowdown: 'mdi-arrow-down',
    arrowleft: 'mdi-arrow-left',
    arrowright: 'mdi-arrow-right',
    backspace: 'mdi-backspace',
    play: 'mdi-play',
    pause: 'mdi-pause',
    fullscreen: 'mdi-fullscreen',
    fullscreenExit: 'mdi-fullscreen-exit',
    volumeHigh: 'mdi-volume-high',
    volumeMedium: 'mdi-volume-medium',
    volumeLow: 'mdi-volume-low',
    volumeOff: 'mdi-volume-variant-off',
    search: 'mdi-magnify'
  };
  const mdi = {
    // Not using mergeProps here, functional components merge props by default (?)
    component: props => vue.h(VClassIcon, {
      ...props,
      class: 'mdi'
    })
  };

  // Icons

  // Types

  const md1 = {
    defaults: {
      global: {
        rounded: 'sm'
      },
      VAvatar: {
        rounded: 'circle'
      },
      VAutocomplete: {
        variant: 'underlined'
      },
      VBanner: {
        color: 'primary'
      },
      VBtn: {
        class: 'text-uppercase',
        color: 'primary',
        rounded: 0
      },
      VCheckbox: {
        color: 'secondary',
        indentDetails: false
      },
      VCombobox: {
        variant: 'underlined'
      },
      VDatePicker: {
        color: 'primary',
        controlHeight: 44,
        elevation: 1,
        rounded: 0,
        controlVariant: 'modal',
        VBtn: {
          color: 'high-emphasis',
          rounded: 'circle'
        }
      },
      VSelect: {
        variant: 'underlined'
      },
      VSlider: {
        color: 'primary',
        indentDetails: false
      },
      VSwitch: {
        indentDetails: false
      },
      VRadioGroup: {
        indentDetails: false
      },
      VRangeSlider: {
        indentDetails: false
      },
      VTabs: {
        color: 'primary'
      },
      VTextarea: {
        variant: 'underlined'
      },
      VTextField: {
        variant: 'underlined'
      },
      VToolbar: {
        VBtn: {
          color: null
        }
      }
    },
    icons: {
      defaultSet: 'mdi',
      sets: {
        mdi
      }
    },
    theme: {
      themes: {
        light: {
          colors: {
            primary: '#3F51B5',
            'primary-darken-1': '#303F9F',
            'primary-lighten-1': '#C5CAE9',
            secondary: '#FF4081',
            'secondary-darken-1': '#F50057',
            'secondary-lighten-1': '#FF80AB',
            accent: '#009688'
          }
        }
      }
    }
  };

  // Icons

  // Types

  const md2 = {
    defaults: {
      VAvatar: {
        rounded: 'circle'
      },
      VAutocomplete: {
        variant: 'filled'
      },
      VBanner: {
        color: 'primary'
      },
      VBtn: {
        class: 'text-uppercase',
        color: 'primary'
      },
      VCheckbox: {
        color: 'secondary',
        indentDetails: true
      },
      VCombobox: {
        variant: 'filled'
      },
      VDatePicker: {
        color: 'primary',
        controlHeight: 56,
        elevation: 2,
        rounded: 'md',
        controlVariant: 'modal',
        VBtn: {
          color: 'high-emphasis',
          rounded: 'circle'
        }
      },
      VRadioGroup: {
        indentDetails: true
      },
      VSelect: {
        variant: 'filled'
      },
      VSlider: {
        color: 'primary',
        indentDetails: true
      },
      VRangeSlider: {
        indentDetails: true
      },
      VSwitch: {
        indentDetails: true
      },
      VTabs: {
        color: 'primary'
      },
      VTextarea: {
        variant: 'filled'
      },
      VTextField: {
        variant: 'filled'
      },
      VToolbar: {
        VBtn: {
          color: null
        }
      }
    },
    icons: {
      defaultSet: 'mdi',
      sets: {
        mdi
      }
    },
    theme: {
      themes: {
        light: {
          colors: {
            primary: '#6200EE',
            'primary-darken-1': '#3700B3',
            secondary: '#03DAC6',
            'secondary-darken-1': '#018786',
            error: '#B00020'
          }
        }
      }
    }
  };

  // Icons

  // Types

  const md3 = {
    defaults: {
      VAppBar: {
        flat: true
      },
      VAutocomplete: {
        variant: 'outlined'
      },
      VBanner: {
        color: 'primary'
      },
      VBottomSheet: {
        contentClass: 'rounded-t-xl overflow-hidden'
      },
      VBtn: {
        color: 'primary',
        rounded: 'xl'
      },
      VBtnGroup: {
        rounded: 'xl',
        VBtn: {
          rounded: null
        }
      },
      VCard: {
        rounded: 'lg'
      },
      VCheckbox: {
        color: 'secondary',
        inset: true,
        indentDetails: true
      },
      VChip: {
        rounded: 'sm'
      },
      VCombobox: {
        variant: 'outlined'
      },
      VDateInput: {
        variant: 'outlined'
      },
      VDatePicker: {
        controlHeight: 48,
        color: 'primary',
        divided: true,
        headerColor: '',
        elevation: 1,
        rounded: 'xl',
        VBtn: {
          color: 'high-emphasis',
          rounded: 'circle'
        }
      },
      VFileInput: {
        variant: 'outlined'
      },
      VList: {
        prependGap: 16
      },
      VNavigationDrawer: {
        // VList: {
        //   nav: true,
        //   VListItem: {
        //     rounded: 'xl',
        //   },
        // },
      },
      VNumberInput: {
        variant: 'outlined',
        VBtn: {
          color: undefined,
          rounded: undefined
        }
      },
      VRadioGroup: {
        indentDetails: true
      },
      VSelect: {
        variant: 'outlined'
      },
      VSlider: {
        color: 'primary',
        indentDetails: true
      },
      VRangeSlider: {
        indentDetails: true
      },
      VSwitch: {
        indentDetails: true
      },
      VTabs: {
        color: 'primary'
      },
      VTextarea: {
        variant: 'outlined'
      },
      VTextField: {
        variant: 'outlined'
      },
      VToolbar: {
        VBtn: {
          color: null
        }
      }
    },
    icons: {
      defaultSet: 'mdi',
      sets: {
        mdi
      }
    },
    theme: {
      themes: {
        light: {
          colors: {
            primary: '#6750a4',
            secondary: '#b4b0bb',
            tertiary: '#7d5260',
            error: '#b3261e',
            surface: '#fffbfe'
          }
        }
      }
    }
  };

  var index = /*#__PURE__*/Object.freeze({
    __proto__: null,
    md1: md1,
    md2: md2,
    md3: md3
  });

  // Utilities

  // Types

  function useResizeObserver(callback, box = 'content') {
    const resizeRef = templateRef();
    const contentRect = vue.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 {
          // borderBoxSize ignores CSS transforms (e.g. VDialogTransition scale-in)
          const border = entries[0].borderBoxSize?.[0];
          const el = entries[0].target;
          contentRect.value = new Box({
            x: 0,
            y: 0,
            width: border?.inlineSize ?? el.offsetWidth,
            height: border?.blockSize ?? el.offsetHeight
          });
        }
      });
      vue.onBeforeUnmount(() => {
        observer.disconnect();
      });
      vue.watch(() => resizeRef.el, (newValue, oldValue) => {
        if (oldValue) {
          observer.unobserve(oldValue);
          contentRect.value = undefined;
        }
        if (newValue) observer.observe(newValue);
      }, {
        flush: 'post'
      });
    }
    return {
      resizeRef,
      contentRect: vue.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 = vue.inject(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 = vue.inject(VuetifyLayoutKey);
    if (!layout) throw new Error('[Vuetify] Could not find injected layout');
    const id = options.id ?? `layout-item-${vue.useId()}`;
    const vm = getCurrentInstance('useLayoutItem');
    vue.provide(VuetifyLayoutItemKey, {
      id
    });
    const isKeptAlive = vue.shallowRef(false);
    vue.onDeactivated(() => isKeptAlive.value = true);
    vue.onActivated(() => isKeptAlive.value = false);
    const {
      layoutItemStyles,
      layoutItemScrimStyles
    } = layout.register(vm, {
      ...options,
      active: vue.computed(() => isKeptAlive.value ? false : options.active.value),
      id
    });
    vue.onBeforeUnmount(() => layout.unregister(id));
    return {
      layoutItemStyles,
      layoutRect: layout.layoutRect,
      layoutItemScrimStyles
    };
  }
  const generateLayers = (layout, positions, layoutSizes, activeItems) => {
    let previousLayer = {
      top: 0,
      left: 0,
      right: 0,
      bottom: 0
    };
    const layers = [{
      id: '',
      layer: {
        ...previousLayer
      }
    }];
    for (const id of layout) {
      const position = positions.get(id);
      const amount = layoutSizes.get(id);
      const active = activeItems.get(id);
      if (!position || !amount || !active) continue;
      const layer = {
        ...previousLayer,
        [position.value]: parseInt(previousLayer[position.value], 10) + (active.value ? parseInt(amount.value, 10) : 0)
      };
      layers.push({
        id,
        layer
      });
      previousLayer = layer;
    }
    return layers;
  };
  function createLayout(props) {
    const parentLayout = vue.inject(VuetifyLayoutKey, null);
    const rootZIndex = vue.computed(() => parentLayout ? parentLayout.rootZIndex.value - 100 : ROOT_ZINDEX);
    const registered = vue.ref([]);
    const positions = vue.reactive(new Map());
    const layoutSizes = vue.reactive(new Map());
    const priorities = vue.reactive(new Map());
    const activeItems = vue.reactive(new Map());
    const disabledTransitions = vue.reactive(new Map());
    const {
      resizeRef,
      contentRect: layoutRect
    } = useResizeObserver();
    const computedOverlaps = vue.computed(() => {
      const map = new Map();
      const overlaps = props.overlaps ?? [];
      for (const overlap of overlaps.filter(item => item.includes(':'))) {
        const [top, bottom] = overlap.split(':');
        if (!registered.value.includes(top) || !registered.value.includes(bottom)) continue;
        const topPosition = positions.get(top);
        const bottomPosition = positions.get(bottom);
        const topAmount = layoutSizes.get(top);
        const bottomAmount = layoutSizes.get(bottom);
        if (!topPosition || !bottomPosition || !topAmount || !bottomAmount) continue;
        map.set(bottom, {
          position: topPosition.value,
          amount: parseInt(topAmount.value, 10)
        });
        map.set(top, {
          position: bottomPosition.value,
          amount: -parseInt(bottomAmount.value, 10)
        });
      }
      return map;
    });
    const layers = vue.computed(() => {
      const uniquePriorities = [...new Set([...priorities.values()].map(p => p.value))].sort((a, b) => a - b);
      const layout = [];
      for (const p of uniquePriorities) {
        const items = registered.value.filter(id => priorities.get(id)?.value === p);
        layout.push(...items);
      }
      return generateLayers(layout, positions, layoutSizes, activeItems);
    });
    const transitionsEnabled = vue.computed(() => {
      return !Array.from(disabledTransitions.values()).some(ref => ref.value);
    });
    const mainRect = vue.computed(() => {
      return layers.value[layers.value.length - 1].layer;
    });
    const mainStyles = vue.toRef(() => {
      return {
        '--v-layout-left': convertToUnit(mainRect.value.left),
        '--v-layout-right': convertToUnit(mainRect.value.right),
        '--v-layout-top': convertToUnit(mainRect.value.top),
        '--v-layout-bottom': convertToUnit(mainRect.value.bottom),
        ...(transitionsEnabled.value ? undefined : {
          transition: 'none'
        })
      };
    });
    const items = vue.computed(() => {
      return layers.value.slice(1).map(({
        id
      }, index) => {
        const {
          layer
        } = layers.value[index];
        const size = layoutSizes.get(id);
        const position = positions.get(id);
        return {
          id,
          ...layer,
          size: Number(size.value),
          position: position.value
        };
      });
    });
    const getLayoutItem = id => {
      return items.value.find(item => item.id === id);
    };
    const rootVm = getCurrentInstance('createLayout');
    const isMounted = vue.shallowRef(false);
    vue.onMounted(() => {
      isMounted.value = true;
    });
    vue.provide(VuetifyLayoutKey, {
      register: (vm, {
        id,
        order,
        position,
        layoutSize,
        elementSize,
        active,
        disableTransitions,
        absolute
      }) => {
        priorities.set(id, order);
        positions.set(id, position);
        layoutSizes.set(id, layoutSize);
        activeItems.set(id, active);
        disableTransitions && disabledTransitions.set(id, disableTransitions);
        const instances = findChildrenWithProvide(VuetifyLayoutItemKey, rootVm?.vnode);
        const instanceIndex = instances.indexOf(vm);
        if (instanceIndex > -1) registered.value.splice(instanceIndex, 0, id);else registered.value.push(id);
        const index = vue.computed(() => items.value.findIndex(i => i.id === id));
        const zIndex = vue.computed(() => rootZIndex.value + layers.value.length * 2 - index.value * 2);
        const layoutItemStyles = vue.computed(() => {
          const isHorizontal = position.value === 'left' || position.value === 'right';
          const isOppositeHorizontal = position.value === 'right';
          const isOppositeVertical = position.value === 'bottom';
          const size = Number(elementSize.value ?? layoutSize.value);
          const transformFunction = `translate${isHorizontal ? 'X' : 'Y'}`;
          const transformValue = active.value ? 0 : (size === 0 ? 100 : size + 1) * (isOppositeHorizontal || isOppositeVertical ? 1 : -1);
          const unit = size === 0 ? '%' : 'px';
          const styles = {
            [position.value]: 0,
            zIndex: zIndex.value,
            transform: `${transformFunction}(${transformValue}${unit})`,
            position: absolute.value || rootZIndex.value !== ROOT_ZINDEX ? 'absolute' : 'fixed',
            ...(transitionsEnabled.value ? undefined : {
              transition: 'none'
            })
          };
          if (!isMounted.value) return styles;
          const item = items.value[index.value];
          if (!item) consoleWarn(`[Vuetify] Could not find layout item "${id}"`);
          const overlap = computedOverlaps.value.get(id);
          if (overlap) {
            item[overlap.position] += overlap.amount;
          }
          return {
            ...styles,
            height: isHorizontal ? `calc(100% - ${item.top}px - ${item.bottom}px)` : elementSize.value ? `${elementSize.value}px` : undefined,
            left: isOppositeHorizontal ? undefined : `${item.left}px`,
            right: isOppositeHorizontal ? `${item.right}px` : undefined,
            top: position.value !== 'bottom' ? `${item.top}px` : undefined,
            bottom: position.value !== 'top' ? `${item.bottom}px` : undefined,
            width: !isHorizontal ? `calc(100% - ${item.left}px - ${item.right}px)` : elementSize.value ? `${elementSize.value}px` : undefined
          };
        });
        const layoutItemScrimStyles = vue.computed(() => ({
          zIndex: zIndex.value - 1
        }));
        return {
          layoutItemStyles,
          layoutItemScrimStyles,
          zIndex
        };
      },
      unregister: id => {
        priorities.delete(id);
        positions.delete(id);
        layoutSizes.delete(id);
        activeItems.delete(id);
        disabledTransitions.delete(id);
        registered.value = registered.value.filter(v => v !== id);
      },
      mainRect,
      mainStyles,
      getLayoutItem,
      items,
      layoutRect,
      rootZIndex
    });
    const layoutClasses = vue.toRef(() => ['v-layout', {
      'v-layout--full-height': props.fullHeight
    }]);
    const layoutStyles = vue.toRef(() => ({
      zIndex: parentLayout ? rootZIndex.value : undefined,
      position: parentLayout ? 'relative' : undefined,
      overflow: parentLayout ? 'hidden' : undefined
    }));
    return {
      layoutClasses,
      layoutStyles,
      getLayoutItem,
      items,
      layoutRect,
      layoutRef: resizeRef
    };
  }

  // Utilities

  // Types

  function useToggleScope(source, fn) {
    let scope;
    function start() {
      scope = vue.effectScope();
      scope.run(() => fn.length ? fn(() => {
        scope?.stop();
        start();
      }) : fn());
    }
    vue.watch(source, active => {
      if (active && !scope) {
        start();
      } else if (!active) {
        scope?.stop();
        scope = undefined;
      }
    }, {
      immediate: true
    });
    vue.onScopeDispose(() => {
      scope?.stop();
    });
  }

  // Composables

  // Types

  // Composables
  function useProxiedModel(props, prop, defaultValue, transformIn = v => v, transformOut = v => v) {
    const vm = getCurrentInstance('useProxiedModel');
    const internal = vue.ref(props[prop] !== undefined ? props[prop] : defaultValue);
    const kebabProp = toKebabCase(prop);
    const checkKebab = kebabProp !== prop;
    const isControlled = checkKebab ? vue.computed(() => {
      void props[prop];
      return !!((vm.vnode.props?.hasOwnProperty(prop) || vm.vnode.props?.hasOwnProperty(kebabProp)) && (vm.vnode.props?.hasOwnProperty(`onUpdate:${prop}`) || vm.vnode.props?.hasOwnProperty(`onUpdate:${kebabProp}`)));
    }) : vue.computed(() => {
      void props[prop];
      return !!(vm.vnode.props?.hasOwnProperty(prop) && vm.vnode.props?.hasOwnProperty(`onUpdate:${prop}`));
    });
    useToggleScope(() => !isControlled.value, () => {
      vue.watch(() => props[prop], val => {
        internal.value = val;
      });
    });
    const model = vue.computed({
      get() {
        const externalValue = props[prop];
        return transformIn(isControlled.value ? externalValue : internal.value);
      },
      set(internalValue) {
        const newValue = transformOut(internalValue);
        const value = vue.toRaw(isControlled.value ? props[prop] : internal.value);
        if (value === newValue || transformIn(value) === internalValue) {
          return;
        }
        internal.value = newValue;
        vm?.emit(`update:${prop}`, newValue);
      }
    });
    Object.defineProperty(model, 'externalValue', {
      get: () => isControlled.value ? props[prop] : internal.value
    });
    return model;
  }

  var en = {
    badge: 'Badge',
    open: 'Open',
    close: 'Close',
    dismiss: 'Dismiss',
    confirmEdit: {
      ok: 'OK',
      cancel: 'Cancel'
    },
    dataIterator: {
      noResultsText: 'No matching records found',
      loadingText: 'Loading items...'
    },
    dataTable: {
      itemsPerPageText: 'Rows per page:',
      ariaLabel: {
        sortDescending: 'Sorted descending.',
        sortAscending: 'Sorted ascending.',
        sortNone: 'Not sorted.',
        activateNone: 'Activate to remove sorting.',
        activateDescending: 'Activate to sort descending.',
        activateAscending: 'Activate to sort ascending.',
        selectRow: 'Select row',
        selectAll: 'Select all',
        selectGroup: 'Select group'
      },
      sortBy: 'Sort by'
    },
    dataFooter: {
      itemsPerPageText: 'Items per page:',
      itemsPerPageAll: 'All',
      nextPage: 'Next page',
      prevPage: 'Previous page',
      firstPage: 'First page',
      lastPage: 'Last page',
      pageText: '{0}-{1} of {2}'
    },
    dateRangeInput: {
      divider: 'to'
    },
    monthPicker: {
      title: 'Select month',
      itemsSelected: '{0} selected',
      header: 'Enter month',
      range: {
        title: 'Enter months'
      },
      ariaLabel: {
        previousYear: 'Previous year',
        nextYear: 'Next year',
        selectYear: 'Select year',
        currentMonth: 'Current month, {0}'
      }
    },
    datePicker: {
      itemsSelected: '{0} selected',
      range: {
        title: 'Select dates',
        header: 'Enter dates'
      },
      title: 'Select date',
      header: 'Enter date',
      input: {
        placeholder: 'Enter date'
      },
      ariaLabel: {
        previousMonth: 'Previous month',
        nextMonth: 'Next month',
        selectYear: 'Select year',
        previousYear: 'Previous year',
        nextYear: 'Next year',
        selectMonth: 'Select month',
        selectDate: '{0}',
        // Full date format
        currentDate: 'Today, {0}'
      }
    },
    noDataText: 'No data available',
    carousel: {
      prev: 'Previous visual',
      next: 'Next visual',
      ariaLabel: {
        delimiter: 'Carousel slide {0} of {1}'
      }
    },
    calendar: {
      moreEvents: '{0} more',
      today: 'Today'
    },
    heatmap: {
      less: 'Less',
      more: 'More'
    },
    input: {
      clear: 'Clear {0}',
      prependAction: '{0} prepended action',
      appendAction: '{0} appended action',
      otp: 'Enter verification code'
    },
    fileInput: {
      counter: '{0} files',
      counterSize: '{0} files ({1} in total)'
    },
    fileUpload: {
      title: 'Drag and drop files here',
      divider: 'or',
      browse: 'Browse Files'
    },
    timePicker: {
      am: 'AM',
      pm: 'PM',
      title: 'Select Time',
      hour: 'Hour',
      minute: 'Minute',
      second: 'Second',
      notAllowed: 'Value is not allowed'
    },
    pagination: {
      ariaLabel: {
        root: 'Pagination Navigation',
        next: 'Next page',
        previous: 'Previous page',
        page: 'Go to page {0}',
        currentPage: 'Page {0}, Current page',
        first: 'First page',
        last: 'Last page'
      }
    },
    stepper: {
      next: 'Next',
      prev: 'Previous'
    },
    rating: {
      ariaLabel: {
        item: 'Rating {0} of {1}'
      }
    },
    loading: 'Loading...',
    infiniteScroll: {
      loadMore: 'Load more',
      empty: 'No more'
    },
    rules: {
      required: 'This field is required',
      email: 'Please enter a valid email',
      number: 'This field can only contain numbers',
      integer: 'This field can only contain integer values',
      capital: 'This field can only contain uppercase letters',
      maxLength: 'You must enter a maximum of {0} characters',
      minLength: 'You must enter a minimum of {0} characters',
      strictLength: 'The length of the entered field is invalid',
      exclude: 'The {0} character is not allowed',
      notEmpty: 'Please choose at least one value',
      pattern: 'Invalid format'
    },
    command: {
      search: 'Type a command or search...'
    },
    hotkey: {
      then: 'then',
      ctrl: 'Ctrl',
      command: 'Command',
      space: 'Space',
      shift: 'Shift',
      alt: 'Alt',
      enter: 'Enter',
      escape: 'Escape',
      upArrow: 'Up Arrow',
      downArrow: 'Down Arrow',
      leftArrow: 'Left Arrow',
      rightArrow: 'Right Arrow',
      backspace: 'Backspace',
      option: 'Option',
      plus: 'plus',
      shortcut: 'Keyboard shortcut: {0}',
      or: 'or'
    },
    video: {
      play: 'Play',
      pause: 'Pause',
      seek: 'Seek',
      volume: 'Volume',
      showVolume: 'Show volume control',
      mute: 'Mute',
      unmute: 'Unmute',
      enterFullscreen: 'Full screen',
      exitFullscreen: 'Exit full screen'
    },
    colorPicker: {
      ariaLabel: {
        eyedropper: 'Select color with eyedropper',
        hueSlider: 'Hue',
        alphaSlider: 'Alpha',
        redInput: 'Red value',
        greenInput: 'Green value',
        blueInput: 'Blue value',
        alphaInput: 'Alpha value',
        hueInput: 'Hue value',
        saturationInput: 'Saturation value',
        lightnessInput: 'Lightness value',
        hexInput: 'HEX value',
        hexaInput: 'HEX with alpha value',
        changeFormat: 'Change color format'
      }
    }
  };

  // Composables

  // Types

  const LANG_PREFIX = '$vuetify.';
  const replace = (str, params) => {
    return str.replace(/\{(\d+)\}/g, (match, index) => {
      return String(params[Number(index)]);
    });
  };
  const createTranslateFunction = (current, fallback, messages) => {
    return (key, ...params) => {
      if (!key.startsWith(LANG_PREFIX)) {
        return replace(key, params);
      }
      const shortKey = key.replace(LANG_PREFIX, '');
      const currentLocale = current.value && messages.value[current.value];
      const fallbackLocale = fallback.value && messages.value[fallback.value];
      let str = getObjectValueByPath(currentLocale, shortKey, null);
      if (!str) {
        consoleWarn(`Translation key "${key}" not found in "${current.value}", trying fallback locale`);
        str = getObjectValueByPath(fallbackLocale, shortKey, null);
      }
      if (!str) {
        consoleError(`Translation key "${key}" not found in fallback`);
        str = key;
      }
      if (typeof str !== 'string') {
        consoleError(`Translation key "${key}" has a non-string value`);
        str = key;
      }
      return replace(str, params);
    };
  };
  function createNumberFunction(current, fallback) {
    return (value, options) => {
      const numberFormat = new Intl.NumberFormat([current.value, fallback.value], options);
      return numberFormat.format(value);
    };
  }
  function inferDecimalSeparator(current, fallback) {
    const format = createNumberFunction(current, fallback);
    return format(0.1).includes(',') ? ',' : '.';
  }
  function inferNumericGroupSeparator(current, fallback) {
    return new Intl.NumberFormat([current.value, fallback.value], {
      useGrouping: true
    }).formatToParts(10000).find(p => p.type === 'group')?.value ?? ' ';
  }
  function useProvided(props, prop, provided) {
    const internal = useProxiedModel(props, prop, props[prop] ?? provided.value);

    // TODO: Remove when defaultValue works
    internal.value = props[prop] ?? provided.value;
    vue.watch(provided, v => {
      if (props[prop] == null) {
        internal.value = provided.value;
      }
    });
    return internal;
  }
  function createProvideFunction(state) {
    return props => {
      const current = useProvided(props, 'locale', state.current);
      const fallback = useProvided(props, 'fallback', state.fallback);
      const messages = useProvided(props, 'messages', state.messages);
      return {
        name: 'vuetify',
        current,
        fallback,
        messages,
        decimalSeparator: vue.toRef(() => inferDecimalSeparator(current, fallback)),
        numericGroupSeparator: vue.toRef(() => inferNumericGroupSeparator(current, fallback)),
        t: createTranslateFunction(current, fallback, messages),
        n: createNumberFunction(current, fallback),
        provide: createProvideFunction({
          current,
          fallback,
          messages
        })
      };
    };
  }
  function createVuetifyAdapter(options) {
    const current = vue.shallowRef(options?.locale ?? 'en');
    const fallback = vue.shallowRef(options?.fallback ?? 'en');
    const messages = vue.ref({
      en,
      ...options?.messages
    });
    return {
      name: 'vuetify',
      current,
      fallback,
      messages,
      decimalSeparator: vue.toRef(() => options?.decimalSeparator ?? inferDecimalSeparator(current, fallback)),
      numericGroupSeparator: vue.toRef(() => options?.numericGroupSeparator ?? inferNumericGroupSeparator(current, fallback)),
      t: createTranslateFunction(current, fallback, messages),
      n: createNumberFunction(current, fallback),
      provide: createProvideFunction({
        current,
        fallback,
        messages
      })
    };
  }

  // Utilities

  // Types

  const LocaleSymbol = Symbol.for('vuetify:locale');
  function isLocaleInstance(obj) {
    return obj.name != null;
  }
  function createLocale(options) {
    const i18n = options?.adapter && isLocaleInstance(options?.adapter) ? options?.adapter : createVuetifyAdapter(options);
    const rtl = createRtl(i18n, options);
    return {
      ...i18n,
      ...rtl
    };
  }
  function useLocale() {
    const locale = vue.inject(LocaleSymbol);
    if (!locale) throw new Error('[Vuetify] Could not find injected locale instance');
    return locale;
  }
  function provideLocale(props) {
    const locale = vue.inject(LocaleSymbol);
    if (!locale) throw new Error('[Vuetify] Could not find injected locale instance');
    const i18n = locale.provide(props);
    const rtl = provideRtl(i18n, locale.rtl, props);
    const data = {
      ...i18n,
      ...rtl
    };
    vue.provide(LocaleSymbol, data);
    return data;
  }
  function genDefaults$3() {
    return {
      af: false,
      ar: true,
      bg: false,
      ca: false,
      ckb: true,
      cs: false,
      de: false,
      el: false,
      en: false,
      es: false,
      et: false,
      fa: true,
      fi: false,
      fr: false,
      hr: false,
      hu: false,
      he: true,
      id: false,
      it: false,
      ja: false,
      km: false,
      ko: false,
      lv: false,
      lt: false,
      nl: false,
      no: false,
      pl: false,
      pt: false,
      ro: false,
      ru: false,
      sk: false,
      sl: false,
      srCyrl: false,
      srLatn: false,
      sv: false,
      th: false,
      tr: false,
      az: false,
      uk: false,
      vi: false,
      zhHans: false,
      zhHant: false
    };
  }
  function createRtl(i18n, options) {
    const rtl = vue.ref(options?.rtl ?? genDefaults$3());
    const isRtl = vue.computed(() => rtl.value[i18n.current.value] ?? false);
    return {
      isRtl,
      rtl,
      rtlClasses: vue.toRef(() => `v-locale--is-${isRtl.value ? 'rtl' : 'ltr'}`)
    };
  }
  function provideRtl(locale, rtl, props) {
    const isRtl = vue.computed(() => props.rtl ?? rtl.value[locale.current.value] ?? false);
    return {
      isRtl,
      rtl,
      rtlClasses: vue.toRef(() => `v-locale--is-${isRtl.value ? 'rtl' : 'ltr'}`)
    };
  }
  function useRtl() {
    const locale = vue.inject(LocaleSymbol);
    if (!locale) throw new Error('[Vuetify] Could not find injected rtl instance');
    return {
      isRtl: locale.isRtl,
      rtlClasses: locale.rtlClasses
    };
  }

  // Utilities

  // Types

  const ThemeSymbol = Symbol.for('vuetify:theme');
  const makeThemeProps = propsFactory({
    theme: String
  }, 'theme');
  function genDefaults$2() {
    return {
      defaultTheme: 'system',
      prefix: 'v-',
      variations: {
        colors: [],
        lighten: 0,
        darken: 0
      },
      themes: {
        light: {
          dark: false,
          colors: {
            background: '#FFFFFF',
            surface: '#FFFFFF',
            'surface-bright': '#FFFFFF',
            'surface-light': '#EEEEEE',
            'surface-variant': '#424242',
            'on-surface-variant': '#EEEEEE',
            primary: '#1867C0',
            'primary-darken-1': '#1F5592',
            secondary: '#48A9A6',
            'secondary-darken-1': '#018786',
            error: '#B00020',
            info: '#2196F3',
            success: '#4CAF50',
            warning: '#FB8C00'
          },
          variables: {
            'border-color': '#000000',
            'border-opacity': 0.12,
            'shadow-color': '#000000',
            'high-emphasis-opacity': 0.87,
            'medium-emphasis-opacity': 0.60,
            'disabled-opacity': 0.38,
            'idle-opacity': 0.04,
            'hover-opacity': 0.04,
            'focus-opacity': 0.12,
            'selected-opacity': 0.08,
            'activated-opacity': 0.12,
            'pressed-opacity': 0.12,
            'dragged-opacity': 0.08,
            'theme-kbd': '#EEEEEE',
            'theme-on-kbd': '#000000',
            'theme-code': '#F5F5F5',
            'theme-on-code': '#000000',
            'theme-on-dark': '#FFF',
            'theme-on-light': '#000',
            'elevation-overlay-color': 'black',
            'elevation-overlay-opacity-step': '2%',
            'highlight-opacity': '8%'
          }
        },
        dark: {
          dark: true,
          colors: {
            background: '#121212',
            surface: '#212121',
            'surface-bright': '#ccbfd6',
            'surface-light': '#424242',
            'surface-variant': '#c8c8c8',
            'on-surface-variant': '#000000',
            primary: '#2196F3',
            'primary-darken-1': '#277CC1',
            secondary: '#54B6B2',
            'secondary-darken-1': '#48A9A6',
            error: '#CF6679',
            info: '#2196F3',
            success: '#4CAF50',
            warning: '#FB8C00'
          },
          variables: {
            'border-color': '#FFFFFF',
            'border-opacity': 0.12,
            'shadow-color': '#000000',
            'high-emphasis-opacity': 1,
            'medium-emphasis-opacity': 0.70,
            'disabled-opacity': 0.50,
            'idle-opacity': 0.10,
            'hover-opacity': 0.04,
            'focus-opacity': 0.12,
            'selected-opacity': 0.08,
            'activated-opacity': 0.12,
            'pressed-opacity': 0.16,
            'dragged-opacity': 0.08,
            'theme-kbd': '#424242',
            'theme-on-kbd': '#FFFFFF',
            'theme-code': '#343434',
            'theme-on-code': '#CCCCCC',
            'theme-on-dark': '#FFF',
            'theme-on-light': '#000',
            'elevation-overlay-color': 'white',
            'elevation-overlay-opacity-step': '2%',
            'highlight-opacity': '20%'
          }
        }
      },
      stylesheetId: 'vuetify-theme-stylesheet',
      scoped: false,
      utilities: true,
      transition: false
    };
  }
  function parseThemeOptions(options = genDefaults$2()) {
    const defaults = genDefaults$2();
    if (!options) return {
      ...defaults,
      isDisabled: true
    };
    return mergeDeep(defaults, options);
  }
  function createCssClass(lines, selector, content, scope) {
    lines.push(`${getScopedSelector(selector, scope)} {\n`, ...content.map(line => `  ${line};\n`), '}\n');
  }
  function genCssVariables(theme, prefix) {
    const lightOverlay = theme.dark ? 2 : 1;
    const darkOverlay = theme.dark ? 1 : 2;
    const variables = [];
    for (const [key, value] of Object.entries(theme.colors)) {
      const rgb = parseColor(value);
      variables.push(`--${prefix}theme-${key}: ${rgb.r},${rgb.g},${rgb.b}` + (rgb.a == null ? '' : `,${rgb.a}`));
      if (!key.startsWith('on-')) {
        variables.push(`--${prefix}theme-${key}-overlay-multiplier: ${getLuma(value) > 0.18 ? lightOverlay : darkOverlay}`);
      }
    }
    for (const [key, value] of Object.entries(theme.variables)) {
      const color = typeof value === 'string' && value.startsWith('#') ? parseColor(value) : undefined;
      const rgb = color ? `${color.r}, ${color.g}, ${color.b}` + (color.a == null ? '' : `, ${color.a}`) : undefined;
      variables.push(`--${prefix}${key}: ${rgb ?? value}`);
    }
    return variables;
  }
  function genVariation(name, color, variations) {
    const object = {};
    if (variations) {
      for (const variation of ['lighten', 'darken']) {
        const fn = variation === 'lighten' ? lighten : darken;
        for (const amount of createRange(variations[variation], 1)) {
          object[`${name}-${variation}-${amount}`] = RGBtoHex(fn(parseColor(color), amount));
        }
      }
    }
    return object;
  }
  function genVariations(colors, variations) {
    if (!variations) return {};
    let variationColors = {};
    for (const name of variations.colors) {
      const color = colors[name];
      if (!color) continue;
      variationColors = {
        ...variationColors,
        ...genVariation(name, color, variations)
      };
    }
    return variationColors;
  }
  function genOnColors(colors, variables) {
    const onColors = {};
    for (const color of Object.keys(colors)) {
      if (color.startsWith('on-') || colors[`on-${color}`]) continue;
      const onColor = `on-${color}`;
      const colorVal = parseColor(colors[color]);
      onColors[onColor] = hasLightForeground(colorVal) ? variables['theme-on-dark'] : variables['theme-on-light'];
    }
    return onColors;
  }
  function getScopedSelector(selector, scope) {
    if (!scope) return selector;
    const scopeSelector = `:where(${scope})`;
    return selector === ':root' ? scopeSelector : `${scopeSelector} ${selector}`;
  }
  function upsertStyles(id, cspNonce, styles) {
    const styleEl = getOrCreateStyleElement(id, cspNonce);
    if (!styleEl) return;
    styleEl.innerHTML = styles;
  }
  function getOrCreateStyleElement(id, cspNonce) {
    if (!IN_BROWSER) return null;
    let style = document.getElementById(id);
    if (!style) {
      style = document.createElement('style');
      style.id = id;
      style.type = 'text/css';
      if (cspNonce) style.setAttribute('nonce', cspNonce);
      document.head.appendChild(style);
    }
    return style;
  }

  // Composables
  function createTheme(options) {
    const parsedOptions = parseThemeOptions(options);
    const _name = vue.shallowRef(parsedOptions.defaultTheme);
    const themes = vue.ref(parsedOptions.themes);
    const systemName = vue.shallowRef('light');
    const name = vue.computed({
      get() {
        return _name.value === 'system' ? systemName.value : _name.value;
      },
      set(val) {
        _name.value = val;
      }
    });
    const computedThemes = vue.computed(() => {
      const acc = {};
      for (const [name, original] of Object.entries(themes.value)) {
        const defaultTheme = original.dark || name === 'dark' ? themes.value.dark : themes.value.light;
        const merged = mergeDeep(defaultTheme, original);
        const colors = {
          ...merged.colors,
          ...genVariations(merged.colors, parsedOptions.variations)
        };
        acc[name] = {
          ...merged,
          colors: {
            ...colors,
            ...genOnColors(colors, merged.variables)
          }
        };
      }
      return acc;
    });
    const current = vue.toRef(() => computedThemes.value[name.value]);
    const isSystem = vue.toRef(() => _name.value === 'system');
    const styles = vue.computed(() => {
      const lines = [];
      const scoped = parsedOptions.scoped ? parsedOptions.prefix : '';
      lines.push('@layer theme-base {\n');
      createCssClass(lines, ':root', [`color-scheme: ${current.value?.dark ? 'dark' : 'light'}`], parsedOptions.scope);
      createCssClass(lines, ':root', genCssVariables(current.value, parsedOptions.prefix), parsedOptions.scope);
      for (const [themeName, theme] of Object.entries(computedThemes.value)) {
        createCssClass(lines, `.${parsedOptions.prefix}theme--${themeName}`, [`color-scheme: ${theme.dark ? 'dark' : 'light'}`, ...genCssVariables(theme, parsedOptions.prefix)], parsedOptions.scope);
      }
      lines.push('}\n');
      if (parsedOptions.utilities) {
        const bgLines = [];
        const fgLines = [];
        const colors = new Set(Object.values(computedThemes.value).flatMap(theme => Object.keys(theme.colors)));
        for (const key of colors) {
          if (key.startsWith('on-')) {
            createCssClass(fgLines, `.${key}`, [`color: rgb(var(--${parsedOptions.prefix}theme-${key}))`], parsedOptions.scope);
          } else {
            createCssClass(bgLines, `.${scoped}bg-${key}`, [`--${parsedOptions.prefix}theme-overlay-multiplier: var(--${parsedOptions.prefix}theme-${key}-overlay-multiplier)`, `background-color: rgb(var(--${parsedOptions.prefix}theme-${key}))`, `color: rgb(var(--${parsedOptions.prefix}theme-on-${key}))`], parsedOptions.scope);
            createCssClass(fgLines, `.${scoped}text-${key}`, [`color: rgb(var(--${parsedOptions.prefix}theme-${key}))`], parsedOptions.scope);
            createCssClass(fgLines, `.${scoped}border-${key}`, [`--${parsedOptions.prefix}border-color: var(--${parsedOptions.prefix}theme-${key})`], parsedOptions.scope);
          }
        }
        lines.push('@layer theme-background {\n', ...bgLines.map(v => `  ${v}`), '}\n', '@layer theme-foreground {\n', ...fgLines.map(v => `  ${v}`), '}\n');
      }
      return '@layer vuetify-utilities {\n' + lines.map(v => `  ${v}`).join('') + '\n}';
    });
    const themeClasses = vue.toRef(() => parsedOptions.isDisabled ? undefined : `${parsedOptions.prefix}theme--${name.value}`);
    const themeNames = vue.toRef(() => Object.keys(computedThemes.value));
    if (SUPPORTS_MATCH_MEDIA) {
      const media = window.matchMedia('(prefers-color-scheme: dark)');
      function updateSystemName() {
        systemName.value = media.matches ? 'dark' : 'light';
      }
      updateSystemName();
      media.addEventListener('change', updateSystemName, {
        passive: true
      });
      if (vue.getCurrentScope()) {
        vue.onScopeDispose(() => {
          media.removeEventListener('change', updateSystemName);
        });
      }
    }
    function install(app) {
      if (parsedOptions.isDisabled) return;
      const head = app._context.provides.usehead;
      if (head) {
        function getHead() {
          return {
            style: [{
              textContent: styles.value,
              id: parsedOptions.stylesheetId,
              nonce: parsedOptions.cspNonce || false,
              tagPosition: 'bodyOpen'
            }]
          };
        }
        if (head.push) {
          const entry = head.push(getHead);
          if (IN_BROWSER) {
            vue.watch(styles, () => {
              entry.patch(getHead);
            });
          }
        } else {
          if (IN_BROWSER) {
            head.addHeadObjs(vue.toRef(getHead));
            vue.watchEffect(() => head.updateDOM());
          } else {
            head.addHeadObjs(getHead());
          }
        }
      } else {
        if (IN_BROWSER) {
          vue.watch(styles, updateStyles, {
            immediate: true
          });
        } else {
          updateStyles();
        }
        function updateStyles() {
          upsertStyles(parsedOptions.stylesheetId, parsedOptions.cspNonce, styles.value);
        }
      }
    }
    let _transitionOrigin;
    function setTransitionOrigin(e) {
      if (!e) {
        _transitionOrigin = null;
        return;
      }
      let x;
      let y;
      if (e instanceof Element) {
        const box = new Box(e);
        x = box.left + box.width / 2;
        y = box.top + box.height / 2;
      } else {
        x = e.clientX;
        y = e.clientY;
      }
      const originX = Math.min(98.9, 100 * x / window.innerWidth); // clip to avoid glitches
      const originY = 100 * y / window.innerHeight;
      _transitionOrigin = `${originX.toFixed(2)}% ${originY.toFixed(2)}%`;
    }
    function resolveTransitionOptions(transition) {
      const opt = transition ?? parsedOptions.transition;
      if (!opt && !_transitionOrigin) return false;
      const global = typeof parsedOptions.transition === 'object' ? parsedOptions.transition : {};
      const local = typeof transition === 'object' ? transition : {};
      return {
        origin: local.origin ?? _transitionOrigin ?? global.origin,
        duration: local.duration ?? global.duration
      };
    }
    function withPageTransition(callback, options) {
      if (!IN_BROWSER || !document.startViewTransition || PREFERS_REDUCED_MOTION()) {
        callback();
        return Promise.resolve();
      }
      const origin = options.origin ?? '50% 0%';
      const duration = options.duration ?? '500ms';
      const style = document.createElement('style');
      style.textContent = `html:active-view-transition-type(vuetify-theme)::view-transition-old(root) { animation: none; }` + `html:active-view-transition-type(vuetify-theme)::view-transition-new(root) { animation: v-circle-in ${duration} ease-in-out; }` + `@keyframes v-circle-in {` + `  from { clip-path: circle(0% at ${origin}); }` + `  to { clip-path: circle(150% at ${origin}); }` + `}`;
      document.head.appendChild(style);
      const transition = document.startViewTransition({
        update: () => callback(),
        types: ['vuetify-theme']
      });
      transition.finished.then(() => {
        _transitionOrigin = null;
        style.remove();
      });
      return transition.updateCallbackDone;
    }
    function change(themeName, transition) {
      if (themeName !== 'system' && !themeNames.value.includes(themeName)) {
        consoleWarn(`Theme "${themeName}" not found on the Vuetify theme instance`);
        return Promise.resolve();
      }
      const apply = () => {
        name.value = themeName;
      };
      const transitionOptions = resolveTransitionOptions(transition);
      if (transitionOptions) {
        return withPageTransition(apply, transitionOptions);
      }
      apply();
      return Promise.resolve();
    }
    function cycle(themeArray = themeNames.value, transition) {
      const currentIndex = themeArray.indexOf(name.value);
      const nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % themeArray.length;
      return change(themeArray[nextIndex], transition);
    }
    function toggle(themeArray = ['light', 'dark'], transition) {
      return cycle(themeArray, transition);
    }
    const globalName = new Proxy(name, {
      get(target, prop) {
        return Reflect.get(target, prop);
      },
      set(target, prop, val) {
        if (prop === 'value') {
          deprecate(`theme.global.name.value = ${val}`, `theme.change('${val}')`);
        }
        return Reflect.set(target, prop, val);
      }
    });
    return {
      install,
      change,
      cycle,
      toggle,
      setTransitionOrigin,
      isDisabled: parsedOptions.isDisabled,
      isSystem,
      name,
      themes,
      current,
      computedThemes,
      prefix: parsedOptions.prefix,
      themeClasses,
      styles,
      global: {
        name: globalName,
        current
      }
    };
  }
  function provideTheme(props) {
    getCurrentInstance('provideTheme');
    const theme = vue.inject(ThemeSymbol, null);
    if (!theme) throw new Error('Could not find Vuetify theme injection');
    const name = vue.toRef(() => props.theme ?? theme.name.value);
    const current = vue.toRef(() => theme.computedThemes.value[name.value]);
    const themeClasses = vue.toRef(() => theme.isDisabled ? undefined : `${theme.prefix}theme--${name.value}`);
    const newTheme = {
      ...theme,
      name,
      current,
      themeClasses
    };
    vue.provide(ThemeSymbol, newTheme);
    return newTheme;
  }
  function useTheme() {
    getCurrentInstance('useTheme');
    const theme = vue.inject(ThemeSymbol, null);
    if (!theme) throw new Error('Could not find Vuetify theme injection');
    return theme;
  }

  const makeVAppProps = propsFactory({
    ...makeComponentProps(),
    ...omit(makeLayoutProps(), ['fullHeight']),
    ...makeThemeProps()
  }, 'VApp');
  const VApp = genericComponent()({
    name: 'VApp',
    props: makeVAppProps(),
    setup(props, {
      slots
    }) {
      const theme = provideTheme(props);
      const {
        layoutClasses,
        getLayoutItem,
        items,
        layoutRef
      } = createLayout({
        ...props,
        fullHeight: true
      });
      const {
        rtlClasses
      } = useRtl();
      useRender(() => vue.createElementVNode("div", {
        "ref": layoutRef,
        "class": vue.normalizeClass(['v-application', theme.themeClasses.value, layoutClasses.value, rtlClasses.value, props.class]),
        "style": vue.normalizeStyle([props.style])
      }, [vue.createElementVNode("div", {
        "class": "v-application__wrap"
      }, [slots.default?.()])]));
      return {
        getLayoutItem,
        items,
        theme
      };
    }
  });

  // Utilities

  // Types

  // Types

  // Composables
  const makeTagProps = propsFactory({
    tag: {
      type: [String, Object, Function],
      default: 'div'
    }
  }, 'tag');

  const makeVToolbarTitleProps = propsFactory({
    text: String,
    ...makeComponentProps(),
    ...makeTagProps()
  }, 'VToolbarTitle');
  const VToolbarTitle = genericComponent()({
    name: 'VToolbarTitle',
    props: makeVToolbarTitleProps(),
    setup(props, {
      slots
    }) {
      useRender(() => {
        const hasText = !!(slots.default || slots.text || props.text);
        return vue.createVNode(props.tag, {
          "class": vue.normalizeClass(['v-toolbar-title', props.class]),
          "style": vue.normalizeStyle(props.style)
        }, {
          default: () => [hasText && vue.createElementVNode("div", {
            "class": "v-toolbar-title__placeholder"
          }, [slots.text ? slots.text() : props.text, slots.default?.()])]
        });
      });
      return {};
    }
  });

  // Utilities

  // Types

  const makeTransitionProps$1 = propsFactory({
    disabled: Boolean,
    group: Boolean,
    hideOnLeave: Boolean,
    leaveAbsolute: Boolean,
    mode: String,
    origin: String
  }, 'transition');
  function createCssTransition(name, origin, mode) {
    return genericComponent()({
      name,
      props: makeTransitionProps$1({
        mode,
        origin
      }),
      setup(props, {
        slots
      }) {
        const functions = {
          onBeforeEnter(el) {
            if (props.origin) {
              el.style.transformOrigin = props.origin;
            }
          },
          onLeave(el) {
            if (props.leaveAbsolute) {
              const {
                offsetTop,
                offsetLeft,
                offsetWidth,
                offsetHeight
              } = el;
              el._transitionInitialStyles = {
                position: el.style.position,
                top: el.style.top,
                left: el.style.left,
                width: el.style.width,
                height: el.style.height
              };
              el.style.position = 'absolute';
              el.style.top = `${offsetTop}px`;
              el.style.left = `${offsetLeft}px`;
              el.style.width = `${offsetWidth}px`;
              el.style.height = `${offsetHeight}px`;
            }
            if (props.hideOnLeave) {
              el.style.setProperty('display', 'none', 'important');
            }
          },
          onAfterLeave(el) {
            if (props.leaveAbsolute && el?._transitionInitialStyles) {
              const {
                position,
                top,
                left,
                width,
                height
              } = el._transitionInitialStyles;
              delete el._transitionInitialStyles;
              el.style.position = position || '';
              el.style.top = top || '';
              el.style.left = left || '';
              el.style.width = width || '';
              el.style.height = height || '';
            }
          }
        };
        return () => {
          const tag = props.group ? vue.TransitionGroup : vue.Transition;
          return vue.h(tag, {
            name: props.disabled ? '' : name,
            css: !props.disabled,
            ...(props.group ? undefined : {
              mode: props.mode
            }),
            ...(props.disabled ? {} : functions)
          }, slots.default);
        };
      }
    });
  }
  function createJavascriptTransition(name, functions, mode = 'in-out') {
    return genericComponent()({
      name,
      props: {
        mode: {
          type: String,
          default: mode
        },
        disabled: {
          type: Boolean,
          default: PREFERS_REDUCED_MOTION()
        },
        group: Boolean,
        hideOnLeave: Boolean
      },
      setup(props, {
        slots
      }) {
        const tag = props.group ? vue.TransitionGroup : vue.Transition;
        return () => {
          return vue.h(tag, {
            name: props.disabled ? '' : name,
            css: !props.disabled,
            // mode: props.mode, // TODO: vuejs/vue-next#3104
            ...(props.disabled ? {} : {
              ...functions,
              onLeave: el => {
                if (props.hideOnLeave) {
                  el.style.setProperty('display', 'none', 'important');
                } else {
                  functions.onLeave?.(el);
                }
              }
            })
          }, slots.default);
        };
      }
    });
  }

  function ExpandTransitionGenerator (expandedParentClass = '', type = 'y') {
    return {
      onBeforeEnter(el) {
        el._parent = el.parentNode;
        el._initialStyle = {
          transition: el.style.transition,
          overflow: el.style.overflow,
          width: el.style.width,
          height: el.style.height
        };
      },
      onEnter(el) {
        const initialStyle = el._initialStyle;
        if (!initialStyle) return;
        el.style.setProperty('transition', 'none', 'important');
        // Hide overflow to account for collapsed margins in the calculated height
        el.style.overflow = 'hidden';
        const offsetWidth = `${el.offsetWidth}px`;
        const offsetHeight = `${el.offsetHeight}px`;
        if (['x', 'both'].includes(type)) el.style.width = '0';
        if (['y', 'both'].includes(type)) el.style.height = '0';
        void el.offsetHeight; // force reflow

        el.style.transition = initialStyle.transition;
        if (expandedParentClass && el._parent) {
          el._parent.classList.add(expandedParentClass);
        }
        requestAnimationFrame(() => {
          if (['x', 'both'].includes(type)) el.style.width = offsetWidth;
          if (['y', 'both'].includes(type)) el.style.height = offsetHeight;
        });
      },
      onAfterEnter: resetStyles,
      onEnterCancelled: resetStyles,
      onLeave(el) {
        el._initialStyle = {
          transition: '',
          overflow: el.style.overflow,
          width: el.style.width,
          height: el.style.height
        };
        el.style.overflow = 'hidden';
        if (['x', 'both'].includes(type)) el.style.width = `${el.offsetWidth}px`;
        if (['y', 'both'].includes(type)) el.style.height = `${el.offsetHeight}px`;
        void el.offsetHeight; // force reflow

        requestAnimationFrame(() => {
          if (['x', 'both'].includes(type)) el.style.width = '0';
          if (['y', 'both'].includes(type)) el.style.height = '0';
        });
      },
      onAfterLeave,
      onLeaveCancelled: onAfterLeave
    };
    function onAfterLeave(el) {
      if (expandedParentClass && el._parent) {
        el._parent.classList.remove(expandedParentClass);
      }
      resetStyles(el);
    }
    function resetStyles(el) {
      if (!el._initialStyle) return;
      const {
        width: w,
        height: h
      } = el._initialStyle;
      el.style.overflow = el._initialStyle.overflow;
      if (w != null && ['x', 'both'].includes(type)) el.style.width = w;
      if (h != null && ['y', 'both'].includes(type)) el.style.height = h;
      delete el._initialStyle;
    }
  }

  // Utilities

  // Types

  const makeVDialogTransitionProps = propsFactory({
    target: [Object, Array]
  }, 'v-dialog-transition');
  const saved = new WeakMap();
  const VDialogTransition = genericComponent()({
    name: 'VDialogTransition',
    props: makeVDialogTransitionProps(),
    setup(props, {
      slots
    }) {
      const functions = {
        onBeforeEnter(el) {
          el.style.pointerEvents = 'none';
          el.style.visibility = 'hidden';
        },
        async onEnter(el, done) {
          await new Promise(resolve => requestAnimationFrame(resolve));
          await new Promise(resolve => requestAnimationFrame(resolve));
          el.style.visibility = '';
          const dimensions = getDimensions(props.target, el);
          const {
            x,
            y,
            sx,
            sy,
            speed
          } = dimensions;
          saved.set(el, dimensions);
          if (PREFERS_REDUCED_MOTION()) {
            animate(el, [{
              opacity: 0
            }, {}], {
              duration: 125 * speed,
              easing: deceleratedEasing
            }).finished.then(() => done());
          } else {
            const animation = animate(el, [{
              transform: `translate(${x}px, ${y}px) scale(${sx}, ${sy})`,
              opacity: 0
            }, {}], {
              duration: 225 * speed,
              easing: deceleratedEasing
            });
            getChildren(el)?.forEach(el => {
              animate(el, [{
                opacity: 0
              }, {
                opacity: 0,
                offset: 0.33
              }, {}], {
                duration: 225 * 2 * speed,
                easing: standardEasing
              });
            });
            animation.finished.then(() => done());
          }
        },
        onAfterEnter(el) {
          el.style.removeProperty('pointer-events');
        },
        onBeforeLeave(el) {
          el.style.pointerEvents = 'none';
        },
        async onLeave(el, done) {
          await new Promise(resolve => requestAnimationFrame(resolve));
          let dimensions;
          if (!saved.has(el) || Array.isArray(props.target) || props.target.offsetParent || props.target.getClientRects().length) {
            dimensions = getDimensions(props.target, el);
          } else {
            dimensions = saved.get(el);
          }
          const {
            x,
            y,
            sx,
            sy,
            speed
          } = dimensions;
          if (PREFERS_REDUCED_MOTION()) {
            animate(el, [{}, {
              opacity: 0
            }], {
              duration: 85 * speed,
              easing: acceleratedEasing
            }).finished.then(() => done());
          } else {
            const animation = animate(el, [{}, {
              transform: `translate(${x}px, ${y}px) scale(${sx}, ${sy})`,
              opacity: 0
            }], {
              duration: 125 * speed,
              easing: acceleratedEasing
            });
            animation.finished.then(() => done());
            getChildren(el)?.forEach(el => {
              animate(el, [{}, {
                opacity: 0,
                offset: 0.2
              }, {
                opacity: 0
              }], {
                duration: 125 * 2 * speed,
                easing: standardEasing
              });
            });
          }
        },
        onAfterLeave(el) {
          el.style.removeProperty('pointer-events');
        }
      };
      return () => {
        return props.target ? vue.createVNode(vue.Transition, vue.mergeProps({
          "name": "dialog-transition"
        }, functions, {
          "css": false
        }), slots) : vue.createVNode(vue.Transition, {
          "name": "dialog-transition"
        }, slots);
      };
    }
  });

  /** Animatable children (card, sheet, list) */
  function getChildren(el) {
    const els = el.querySelector(':scope > .v-card, :scope > .v-sheet, :scope > .v-list')?.children;
    return els && [...els];
  }
  function getDimensions(target, el) {
    const targetBox = getTargetBox(target);
    const elBox = nullifyTransforms(el);
    const [originX, originY] = getComputedStyle(el).transformOrigin.split(' ').map(v => parseFloat(v));
    const [anchorSide, anchorOffset] = getComputedStyle(el).getPropertyValue('--v-overlay-anchor-origin').split(' ');
    let offsetX = targetBox.left + targetBox.width / 2;
    if (anchorSide === 'left' || anchorOffset === 'left') {
      offsetX -= targetBox.width / 2;
    } else if (anchorSide === 'right' || anchorOffset === 'right') {
      offsetX += targetBox.width / 2;
    }
    let offsetY = targetBox.top + targetBox.height / 2;
    if (anchorSide === 'top' || anchorOffset === 'top') {
      offsetY -= targetBox.height / 2;
    } else if (anchorSide === 'bottom' || anchorOffset === 'bottom') {
      offsetY += targetBox.height / 2;
    }
    const tsx = targetBox.width / elBox.width;
    const tsy = targetBox.height / elBox.height;
    const maxs = Math.max(1, tsx, tsy);
    const sx = tsx / maxs || 0;
    const sy = tsy / maxs || 0;

    // Animate elements larger than 12% of the screen area up to 1.5x slower
    const asa = elBox.width * elBox.height / (window.innerWidth * window.innerHeight);
    const speed = asa > 0.12 ? Math.min(1.5, (asa - 0.12) * 10 + 1) : 1;
    return {
      x: offsetX - (originX + elBox.left),
      y: offsetY - (originY + elBox.top),
      sx,
      sy,
      speed
    };
  }

  // Component specific transitions
  const VFabTransition = createCssTransition('fab-transition', 'center center', 'out-in');

  // Generic transitions
  const VDialogBottomTransition = createCssTransition('dialog-bottom-transition');
  const VDialogTopTransition = createCssTransition('dialog-top-transition');
  const VFadeTransition = createCssTransition('fade-transition');
  const VScaleTransition = createCssTransition('scale-transition');
  const VScrollXTransition = createCssTransition('scroll-x-transition');
  const VScrollXReverseTransition = createCssTransition('scroll-x-reverse-transition');
  const VScrollYTransition = createCssTransition('scroll-y-transition');
  const VScrollYReverseTransition = createCssTransition('scroll-y-reverse-transition');
  const VSlideXTransition = createCssTransition('slide-x-transition');
  const VSlideXReverseTransition = createCssTransition('slide-x-reverse-transition');
  const VSlideYTransition = createCssTransition('slide-y-transition');
  const VSlideYReverseTransition = createCssTransition('slide-y-reverse-transition');

  // Javascript transitions
  const VExpandTransition = createJavascriptTransition('expand-transition', ExpandTransitionGenerator());
  const VExpandXTransition = createJavascriptTransition('expand-x-transition', ExpandTransitionGenerator('', 'x'));
  const VExpandBothTransition = createJavascriptTransition('expand-both-transition', ExpandTransitionGenerator('', 'both'));

  // Composables

  // Types

  const makeVDefaultsProviderProps = propsFactory({
    defaults: Object,
    disabled: Boolean,
    reset: [Number, String],
    root: [Boolean, String],
    scoped: Boolean
  }, 'VDefaultsProvider');
  const VDefaultsProvider = genericComponent(false)({
    name: 'VDefaultsProvider',
    props: makeVDefaultsProviderProps(),
    setup(props, {
      slots
    }) {
      const {
        defaults,
        disabled,
        reset,
        root,
        scoped
      } = vue.toRefs(props);
      provideDefaults(defaults, {
        reset,
        root,
        scoped,
        disabled
      });
      return () => slots.default?.();
    }
  });

  // Utilities

  // Types

  // Composables
  const makeDimensionProps = propsFactory({
    height: [Number, String],
    maxHeight: [Number, String],
    maxWidth: [Number, String],
    minHeight: [Number, String],
    minWidth: [Number, String],
    width: [Number, String]
  }, 'dimension');
  function useDimension(props) {
    const dimensionStyles = vue.computed(() => {
      const styles = {};
      const height = convertToUnit(props.height);
      const maxHeight = convertToUnit(props.maxHeight);
      const maxWidth = convertToUnit(props.maxWidth);
      const minHeight = convertToUnit(props.minHeight);
      const minWidth = convertToUnit(props.minWidth);
      const width = convertToUnit(props.width);
      if (height != null) styles.height = height;
      if (maxHeight != null) styles.maxHeight = maxHeight;
      if (maxWidth != null) styles.maxWidth = maxWidth;
      if (minHeight != null) styles.minHeight = minHeight;
      if (minWidth != null) styles.minWidth = minWidth;
      if (width != null) styles.width = width;
      return styles;
    });
    return {
      dimensionStyles
    };
  }

  function useAspectStyles(props) {
    return {
      aspectStyles: vue.computed(() => {
        const ratio = Number(props.aspectRatio);
        return ratio ? {
          paddingBottom: String(1 / ratio * 100) + '%'
        } : undefined;
      })
    };
  }
  const makeVResponsiveProps = propsFactory({
    aspectRatio: [String, Number],
    contentClass: null,
    inline: Boolean,
    ...makeComponentProps(),
    ...makeDimensionProps()
  }, 'VResponsive');
  const VResponsive = genericComponent()({
    name: 'VResponsive',
    props: makeVResponsiveProps(),
    setup(props, {
      slots
    }) {
      const {
        aspectStyles
      } = useAspectStyles(props);
      const {
        dimensionStyles
      } = useDimension(props);
      useRender(() => vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-responsive', {
          'v-responsive--inline': props.inline
        }, props.class]),
        "style": vue.normalizeStyle([dimensionStyles.value, props.style])
      }, [vue.createElementVNode("div", {
        "class": "v-responsive__sizer",
        "style": vue.normalizeStyle(aspectStyles.value)
      }, null), slots.additional?.(), slots.default && vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-responsive__content', props.contentClass])
      }, [slots.default()])]));
      return {};
    }
  });

  // Utilities

  // Types

  // Composables
  function useColor(colors) {
    return destructComputed(() => {
      const {
        class: colorClasses,
        style: colorStyles
      } = computeColor(colors);
      return {
        colorClasses,
        colorStyles
      };
    });
  }
  function useTextColor(color) {
    const {
      colorClasses: textColorClasses,
      colorStyles: textColorStyles
    } = useColor(() => ({
      text: vue.toValue(color)
    }));
    return {
      textColorClasses,
      textColorStyles
    };
  }
  function useBackgroundColor(color) {
    const {
      colorClasses: backgroundColorClasses,
      colorStyles: backgroundColorStyles
    } = useColor(() => ({
      background: vue.toValue(color)
    }));
    return {
      backgroundColorClasses,
      backgroundColorStyles
    };
  }
  function normalizeColors(colors) {
    return {
      text: typeof colors.text === 'string' ? colors.text.replace(/^text-/, '') : colors.text,
      background: typeof colors.background === 'string' ? colors.background.replace(/^bg-/, '') : colors.background
    };
  }
  function computeColor(colors) {
    const _colors = normalizeColors(vue.toValue(colors));
    const classes = [];
    const styles = {};
    if (_colors.background) {
      if (isCssColor(_colors.background)) {
        styles.backgroundColor = _colors.background;
        if (!_colors.text && isParsableColor(_colors.background)) {
          const backgroundColor = parseColor(_colors.background);
          if (backgroundColor.a == null || backgroundColor.a === 1) {
            classes.push(hasLightForeground(backgroundColor) ? 'v-theme-on-dark' : 'v-theme-on-light');
          }
        }
      } else {
        classes.push(`bg-${_colors.background}`);
      }
    }
    if (_colors.text) {
      if (isCssColor(_colors.text)) {
        styles.color = _colors.text;
        styles.caretColor = _colors.text;
      } else {
        classes.push(`text-${_colors.text}`);
      }
    }
    return {
      class: classes,
      style: styles
    };
  }

  // Utilities

  // Types

  const CSS_LENGTH = /^-?\d*\.?\d+([a-z%]{0,4})$/i;
  function splitTokens(v) {
    return String(v).trim().split(/\s+/);
  }
  function isCssLength(token) {
    return token.toLowerCase().match(CSS_LENGTH)?.at(1)?.startsWith('x') === false;
  }
  function isCssValue(v) {
    return typeof v === 'string' && !!v && (v.includes('(') || splitTokens(v).every(isCssLength));
  }

  // Composables
  const makeRoundedProps = propsFactory({
    rounded: {
      type: [Boolean, Number, String],
      default: undefined
    },
    tile: Boolean
  }, 'rounded');
  function useRounded(props, name = getCurrentInstanceName()) {
    const roundedClasses = vue.computed(() => {
      const rounded = vue.isRef(props) ? props.value : props.rounded;
      const tile = vue.isRef(props) ? false : props.tile;
      const classes = [];
      if (tile || rounded === false || String(rounded) === '0') {
        classes.push('rounded-0');
      } else if (rounded === true || rounded === '') {
        classes.push(`${name}--rounded`);
      } else if (typeof rounded === 'string' && !isCssValue(rounded)) {
        for (const value of splitTokens(rounded)) {
          classes.push(`rounded-${value}`);
        }
      }
      return classes;
    });
    const roundedStyles = vue.computed(() => {
      const rounded = vue.isRef(props) ? props.value : props.rounded;
      if ((!isCssValue(rounded) || String(rounded) === '0') && !(typeof rounded === 'number' && rounded !== 0)) {
        return {};
      }
      return {
        borderRadius: convertToUnit(rounded)
      };
    });
    return {
      roundedClasses,
      roundedStyles
    };
  }

  // Utilities

  // Types

  const makeTransitionProps = propsFactory({
    transition: {
      type: null,
      default: 'fade-transition',
      validator: val => val !== true
    }
  }, 'transition');
  const MaybeTransition = (props, {
    slots
  }) => {
    const {
      transition,
      disabled,
      group,
      target,
      ...rest
    } = props;
    const {
      component = group ? vue.TransitionGroup : vue.Transition,
      ...customProps
    } = isObject(transition) ? transition : {};
    let transitionProps;
    if (isObject(transition)) {
      transitionProps = vue.mergeProps(customProps, onlyDefinedProps({
        disabled,
        group,
        target
      }), rest);
    } else {
      transitionProps = vue.mergeProps({
        name: disabled || !transition ? '' : transition
      }, rest);
    }
    return vue.h(component, transitionProps, slots);
  };

  // Utilities

  // Types

  function mounted$5(el, binding) {
    if (!SUPPORTS_INTERSECTION) return;
    const modifiers = binding.modifiers || {};
    const value = binding.value;
    const {
      handler,
      options
    } = typeof value === 'object' ? value : {
      handler: value,
      options: {}
    };
    const observer = new IntersectionObserver((entries = [], observer) => {
      const _observe = el._observe?.[binding.instance.$.uid];
      if (!_observe) return; // Just in case, should never fire

      const isIntersecting = entries.some(entry => entry.isIntersecting);

      // If is not quiet or has already been
      // initted, invoke the user callback
      if (handler && (!modifiers.quiet || _observe.init) && (!modifiers.once || isIntersecting || _observe.init)) {
        handler(isIntersecting, entries, observer);
      }
      if (isIntersecting && modifiers.once) unmounted$5(el, binding);else _observe.init = true;
    }, options);
    el._observe = Object(el._observe);
    el._observe[binding.instance.$.uid] = {
      init: false,
      observer
    };
    observer.observe(el);
  }
  function unmounted$5(el, binding) {
    const observe = el._observe?.[binding.instance.$.uid];
    if (!observe) return;
    observe.observer.unobserve(el);
    delete el._observe[binding.instance.$.uid];
  }
  const Intersect = {
    mounted: mounted$5,
    unmounted: unmounted$5,
    updated: (el, binding) => {
      if (el._observe?.[binding.instance.$.uid]) {
        unmounted$5(el, binding);
        mounted$5(el, binding);
      }
    }
  };

  // Types

  // not intended for public use, this is passed in by vuetify-loader

  const makeVImgProps = propsFactory({
    absolute: Boolean,
    alt: String,
    cover: Boolean,
    color: String,
    draggable: {
      type: [Boolean, String],
      default: undefined
    },
    eager: Boolean,
    gradient: String,
    imageClass: null,
    lazySrc: String,
    options: {
      type: Object,
      // For more information on types, navigate to:
      // https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
      default: () => ({
        root: undefined,
        rootMargin: undefined,
        threshold: undefined
      })
    },
    sizes: String,
    src: {
      type: [String, Object],
      default: ''
    },
    crossorigin: String,
    referrerpolicy: String,
    srcset: String,
    position: String,
    ...makeVResponsiveProps(),
    ...makeComponentProps(),
    ...makeRoundedProps(),
    ...makeTransitionProps()
  }, 'VImg');
  const VImg = genericComponent()({
    name: 'VImg',
    directives: {
      vIntersect: Intersect
    },
    inheritAttrs: false,
    props: makeVImgProps(),
    emits: {
      loadstart: value => true,
      load: value => true,
      error: value => true
    },
    setup(props, {
      attrs,
      emit,
      slots
    }) {
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.color);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const vm = getCurrentInstance('VImg');
      const currentSrc = vue.shallowRef(''); // Set from srcset
      const image = vue.ref();
      const state = vue.shallowRef(props.eager ? 'loading' : 'idle');
      const naturalWidth = vue.shallowRef();
      const naturalHeight = vue.shallowRef();
      let deferredLoadEmit = false;
      const normalisedSrc = vue.computed(() => {
        return props.src && typeof props.src === 'object' ? {
          src: props.src.src,
          srcset: props.srcset || props.src.srcset,
          lazySrc: props.lazySrc || props.src.lazySrc,
          aspect: Number(props.aspectRatio || props.src.aspect || 0)
        } : {
          src: props.src,
          srcset: props.srcset,
          lazySrc: props.lazySrc,
          aspect: Number(props.aspectRatio || 0)
        };
      });
      const aspectRatio = vue.computed(() => {
        return normalisedSrc.value.aspect || naturalWidth.value / naturalHeight.value || 0;
      });
      vue.watch(() => props.src, () => {
        init(state.value !== 'idle');
      });
      vue.watch(aspectRatio, (val, oldVal) => {
        if (!val && oldVal && image.value) {
          pollForSize(image.value);
        }
      });
      vue.watch(image, img => {
        if (!img || state.value === 'idle') return;
        if (!aspectRatio.value) pollForSize(img);
        getSrc(img);
        if (deferredLoadEmit) {
          deferredLoadEmit = false;
          emit('load', img.currentSrc || normalisedSrc.value.src);
        }
      });

      // TODO: getSrc when window width changes

      vue.onBeforeMount(() => init());
      function init(isIntersecting) {
        if (props.eager && isIntersecting) return;
        if (SUPPORTS_INTERSECTION && !isIntersecting && !props.eager) return;
        state.value = 'loading';
        if (normalisedSrc.value.lazySrc) {
          const lazyImg = new Image();
          lazyImg.src = normalisedSrc.value.lazySrc;
          pollForSize(lazyImg, null);
        }
        if (!normalisedSrc.value.src) return;
        vue.nextTick(() => {
          emit('loadstart', image.value?.currentSrc || normalisedSrc.value.src);
          setTimeout(() => {
            if (vm.isUnmounted) return;
            if (image.value?.complete) {
              if (!image.value.naturalWidth) {
                onError();
              }
              if (state.value === 'error') return;
              if (!aspectRatio.value) pollForSize(image.value, null);
              if (state.value === 'loading') onLoad();
            } else if (image.value) {
              if (!aspectRatio.value) pollForSize(image.value);
              getSrc(image.value);
            }
          });
        });
      }
      function onLoad() {
        if (vm.isUnmounted) return;
        if (image.value) {
          getSrc(image.value);
          pollForSize(image.value);
          emit('load', image.value.currentSrc || normalisedSrc.value.src);
        } else {
          deferredLoadEmit = true;
        }
        state.value = 'loaded';
      }
      function onError() {
        if (vm.isUnmounted) return;
        state.value = 'error';
        emit('error', image.value?.currentSrc || normalisedSrc.value.src);
      }
      function getSrc(img) {
        currentSrc.value = img.currentSrc || img.src;
      }
      let timer = -1;
      vue.onBeforeUnmount(() => {
        clearTimeout(timer);
      });
      function pollForSize(img, timeout = 100) {
        const poll = () => {
          clearTimeout(timer);
          if (vm.isUnmounted) return;
          const {
            naturalHeight: imgHeight,
            naturalWidth: imgWidth
          } = img;
          if (imgHeight || imgWidth) {
            naturalWidth.value = imgWidth;
            naturalHeight.value = imgHeight;
          } else if (!img.complete && state.value === 'loading' && timeout != null) {
            timer = window.setTimeout(poll, timeout);
          } else if (img.currentSrc.endsWith('.svg') || img.currentSrc.startsWith('data:image/svg+xml')) {
            naturalWidth.value = 1;
            naturalHeight.value = 1;
          }
        };
        poll();
      }
      const containClasses = vue.toRef(() => ({
        'v-img__img--cover': props.cover,
        'v-img__img--contain': !props.cover
      }));
      const __image = () => {
        if (!normalisedSrc.value.src || state.value === 'idle') return null;
        const img = vue.createElementVNode("img", {
          "class": vue.normalizeClass(['v-img__img', containClasses.value, props.imageClass]),
          "style": {
            objectPosition: props.position
          },
          "crossorigin": props.crossorigin,
          "src": normalisedSrc.value.src,
          "srcset": normalisedSrc.value.srcset,
          "alt": props.alt,
          "referrerpolicy": props.referrerpolicy,
          "draggable": props.draggable,
          "sizes": props.sizes,
          "ref": image,
          "onLoad": onLoad,
          "onError": onError
        }, null);
        const sources = slots.sources?.();
        return vue.createVNode(MaybeTransition, {
          "transition": props.transition,
          "appear": true
        }, {
          default: () => [vue.withDirectives(sources ? vue.createElementVNode("picture", {
            "class": "v-img__picture"
          }, [sources, img]) : img, [[vue.vShow, state.value === 'loaded']])]
        });
      };
      const __preloadImage = () => vue.createVNode(MaybeTransition, {
        "transition": props.transition
      }, {
        default: () => [normalisedSrc.value.lazySrc && state.value !== 'loaded' && vue.createElementVNode("img", {
          "class": vue.normalizeClass(['v-img__img', 'v-img__img--preload', containClasses.value]),
          "style": {
            objectPosition: props.position
          },
          "crossorigin": props.crossorigin,
          "src": normalisedSrc.value.lazySrc,
          "alt": props.alt,
          "referrerpolicy": props.referrerpolicy,
          "draggable": props.draggable
        }, null)]
      });
      const __placeholder = () => {
        if (!slots.placeholder) return null;
        return vue.createVNode(MaybeTransition, {
          "transition": props.transition,
          "appear": true
        }, {
          default: () => [(state.value === 'loading' || state.value === 'error' && !slots.error) && vue.createElementVNode("div", {
            "class": "v-img__placeholder"
          }, [slots.placeholder()])]
        });
      };
      const __error = () => {
        if (!slots.error) return null;
        return vue.createVNode(MaybeTransition, {
          "transition": props.transition,
          "appear": true
        }, {
          default: () => [state.value === 'error' && vue.createElementVNode("div", {
            "class": "v-img__error"
          }, [slots.error()])]
        });
      };
      const __gradient = () => {
        if (!props.gradient) return null;
        return vue.createElementVNode("div", {
          "class": "v-img__gradient",
          "style": {
            backgroundImage: `linear-gradient(${props.gradient})`
          }
        }, null);
      };
      const isBooted = vue.shallowRef(false);
      {
        const stop = vue.watch(aspectRatio, val => {
          if (val) {
            // Doesn't work with nextTick, idk why
            requestAnimationFrame(() => {
              requestAnimationFrame(() => {
                isBooted.value = true;
              });
            });
            stop();
          }
        });
      }
      useRender(() => {
        const responsiveProps = VResponsive.filterProps(props);
        const [rootAttrs, imageAttrs] = filterInputAttrs(attrs);
        return vue.withDirectives(vue.createVNode(VResponsive, vue.mergeProps({
          "class": ['v-img', {
            'v-img--absolute': props.absolute,
            'v-img--booting': !isBooted.value,
            'v-img--fit-content': props.width === 'fit-content'
          }, backgroundColorClasses.value, roundedClasses.value, props.class],
          "style": [{
            width: convertToUnit(props.width === 'auto' ? naturalWidth.value : props.width)
          }, backgroundColorStyles.value, roundedStyles.value, props.style]
        }, responsiveProps, rootAttrs, {
          "aspectRatio": aspectRatio.value,
          "aria-label": props.alt || undefined,
          "role": props.alt ? 'img' : undefined
        }), {
          additional: () => vue.createElementVNode(vue.Fragment, null, [vue.createVNode(__image, imageAttrs, null), vue.createVNode(__preloadImage, null, null), vue.createVNode(__gradient, null, null), vue.createVNode(__placeholder, null, null), vue.createVNode(__error, null, null)]),
          default: slots.default
        }), [[Intersect, {
          handler: init,
          options: props.options
        }, null, {
          once: true
        }]]);
      });
      return {
        currentSrc,
        image,
        state,
        naturalWidth,
        naturalHeight
      };
    }
  });

  // Utilities

  // Types

  // Composables
  const makeBorderProps = propsFactory({
    border: [Boolean, Number, String]
  }, 'border');
  function useBorder(props, name = getCurrentInstanceName()) {
    const borderClasses = vue.computed(() => {
      const border = props.border;
      if (border === true || border === '') {
        return `${name}--border`;
      } else if (typeof border === 'string' || border === 0) {
        return String(border).split(' ').map(v => `border-${v}`);
      }
      return [];
    });
    return {
      borderClasses
    };
  }

  // Utilities

  // Types

  // Composables
  const makeElevationProps = propsFactory({
    elevation: {
      type: [Number, String],
      // no limit to allow both 0-6 (MD3) and legacy 0-24 (MD2)
      validator: value => parseInt(value) >= 0
    },
    hoverElevation: {
      type: [Number, String],
      validator: value => parseInt(value) >= 0
    }
  }, 'elevation');
  function useElevation(props) {
    const elevationClasses = vue.toRef(() => {
      const elevation = vue.isRef(props) ? props.value : props.elevation;
      const hoverElevation = vue.isRef(props) ? null : props.hoverElevation;
      return [...(elevation == null ? [] : [`elevation-${parseInt(elevation)}`]), ...(hoverElevation == null ? [] : [`hover-elevation-${parseInt(hoverElevation)}`])];
    });
    return {
      elevationClasses
    };
  }

  // Composables

  // Types

  const oppositeMap = {
    center: 'center',
    top: 'bottom',
    bottom: 'top',
    left: 'right',
    right: 'left'
  };
  const makeLocationProps = propsFactory({
    location: String
  }, 'location');
  function useLocation(props, opposite = false, offset) {
    const {
      isRtl
    } = useRtl();
    const locationStyles = vue.computed(() => {
      if (!props.location) return {};
      const {
        side,
        align
      } = parseAnchor(props.location.split(' ').length > 1 ? props.location : `${props.location} center`, isRtl.value);
      function getOffset(side) {
        return offset ? offset(side) : 0;
      }
      const styles = {};
      if (side !== 'center') {
        if (opposite) styles[oppositeMap[side]] = `calc(100% - ${getOffset(side)}px)`;else styles[side] = 0;
      }
      if (align !== 'center') {
        if (opposite) styles[oppositeMap[align]] = `calc(100% - ${getOffset(align)}px)`;else styles[align] = 0;
      } else {
        if (side === 'center') styles.top = styles.left = '50%';else {
          styles[{
            top: 'left',
            bottom: 'left',
            left: 'top',
            right: 'top'
          }[side]] = '50%';
        }
        styles.transform = {
          top: 'translateX(-50%)',
          bottom: 'translateX(-50%)',
          left: 'translateY(-50%)',
          right: 'translateY(-50%)',
          center: 'translate(-50%, -50%)'
        }[side];
      }
      return styles;
    });
    return {
      locationStyles
    };
  }

  // Types

  const allowedDensities$1 = [null, 'prominent', 'default', 'comfortable', 'compact'];
  const makeVToolbarProps = propsFactory({
    absolute: Boolean,
    collapse: Boolean,
    collapsePosition: {
      type: String,
      default: 'start'
    },
    color: String,
    density: {
      type: String,
      default: 'default',
      validator: v => allowedDensities$1.includes(v)
    },
    extended: {
      type: Boolean,
      default: null
    },
    extensionHeight: {
      type: [Number, String],
      default: 48
    },
    flat: Boolean,
    floating: Boolean,
    height: {
      type: [Number, String],
      default: 64
    },
    image: String,
    title: String,
    ...makeBorderProps(),
    ...makeComponentProps(),
    ...makeElevationProps(),
    ...makeLocationProps(),
    ...makeRoundedProps(),
    ...makeTagProps({
      tag: 'header'
    }),
    ...makeThemeProps()
  }, 'VToolbar');
  const VToolbar = genericComponent()({
    name: 'VToolbar',
    props: makeVToolbarProps(),
    setup(props, {
      slots
    }) {
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.color);
      const {
        borderClasses
      } = useBorder(props);
      const {
        elevationClasses
      } = useElevation(props);
      const {
        locationStyles
      } = useLocation(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const {
        themeClasses
      } = provideTheme(props);
      const {
        rtlClasses
      } = useRtl();
      const isExtended = vue.shallowRef(props.extended === null ? !!slots.extension?.() : props.extended);
      const contentHeight = vue.computed(() => parseInt(Number(props.height) + (props.density === 'prominent' ? Number(props.height) : 0) - (props.density === 'comfortable' ? 8 : 0) - (props.density === 'compact' ? 16 : 0), 10));
      const extensionHeight = vue.computed(() => isExtended.value ? parseInt(Number(props.extensionHeight) + (props.density === 'prominent' ? Number(props.extensionHeight) : 0) - (props.density === 'comfortable' ? 4 : 0) - (props.density === 'compact' ? 8 : 0), 10) : 0);
      provideDefaults({
        VBtn: {
          variant: 'text'
        }
      });
      useRender(() => {
        const hasTitle = !!(props.title || slots.title);
        const hasImage = !!(slots.image || props.image);
        const extension = slots.extension?.();
        isExtended.value = props.extended === null ? !!extension : props.extended;
        return vue.createVNode(props.tag, {
          "class": vue.normalizeClass(['v-toolbar', `v-toolbar--collapse-${props.collapsePosition}`, {
            'v-toolbar--absolute': props.absolute,
            'v-toolbar--collapse': props.collapse,
            'v-toolbar--flat': props.flat,
            'v-toolbar--floating': props.floating,
            [`v-toolbar--density-${props.density}`]: true
          }, backgroundColorClasses.value, borderClasses.value, elevationClasses.value, roundedClasses.value, themeClasses.value, rtlClasses.value, props.class]),
          "style": vue.normalizeStyle([backgroundColorStyles.value, locationStyles.value, roundedStyles.value, props.style])
        }, {
          default: () => [hasImage && vue.createElementVNode("div", {
            "key": "image",
            "class": "v-toolbar__image"
          }, [!slots.image ? vue.createVNode(VImg, {
            "key": "image-img",
            "cover": true,
            "src": props.image
          }, null) : vue.createVNode(VDefaultsProvider, {
            "key": "image-defaults",
            "disabled": !props.image,
            "defaults": {
              VImg: {
                cover: true,
                src: props.image
              }
            }
          }, slots.image)]), vue.createVNode(VDefaultsProvider, {
            "defaults": {
              VTabs: {
                height: convertToUnit(contentHeight.value)
              }
            }
          }, {
            default: () => [vue.createElementVNode("div", {
              "class": "v-toolbar__content",
              "style": {
                height: convertToUnit(contentHeight.value)
              }
            }, [slots.prepend && vue.createElementVNode("div", {
              "class": "v-toolbar__prepend"
            }, [slots.prepend?.()]), hasTitle && vue.createVNode(VToolbarTitle, {
              "key": "title",
              "text": props.title
            }, {
              text: slots.title
            }), slots.default?.(), slots.append && vue.createElementVNode("div", {
              "class": "v-toolbar__append"
            }, [slots.append?.()])])]
          }), vue.createVNode(VDefaultsProvider, {
            "defaults": {
              VTabs: {
                height: convertToUnit(extensionHeight.value)
              }
            }
          }, {
            default: () => [vue.createVNode(VExpandTransition, null, {
              default: () => [isExtended.value && vue.createElementVNode("div", {
                "class": "v-toolbar__extension",
                "style": {
                  height: convertToUnit(extensionHeight.value)
                }
              }, [extension])]
            })]
          })]
        });
      });
      return {
        contentHeight,
        extensionHeight
      };
    }
  });

  // Utilities

  // Types

  // Composables
  const makeScrollProps = propsFactory({
    scrollTarget: {
      type: String
    },
    scrollThreshold: {
      type: [String, Number],
      default: 300
    }
  }, 'scroll');
  function useScroll(props, args = {}) {
    const {
      canScroll,
      layoutSize
    } = args;
    let previousScroll = 0;
    let previousScrollHeight = 0;
    const target = vue.ref(null);
    const currentScroll = vue.shallowRef(0);
    const savedScroll = vue.shallowRef(0);
    const currentThreshold = vue.shallowRef(0);
    const isScrollActive = vue.shallowRef(false);
    const isScrollingUp = vue.shallowRef(false);
    const isAtBottom = vue.shallowRef(false);
    const reachedBottomWhileScrollingDown = vue.shallowRef(false);
    const hasEnoughScrollableSpace = vue.shallowRef(true);
    const scrollThreshold = vue.computed(() => {
      return Number(props.scrollThreshold);
    });

    /**
     * 1: at top
     * 0: at threshold
     */
    const scrollRatio = vue.computed(() => {
      return clamp((scrollThreshold.value - currentScroll.value) / scrollThreshold.value || 0);
    });
    function getScrollMetrics(targetEl) {
      const clientHeight = 'window' in targetEl ? window.innerHeight : targetEl.clientHeight;
      const scrollHeight = 'window' in targetEl ? document.documentElement.scrollHeight : targetEl.scrollHeight;
      return {
        clientHeight,
        scrollHeight
      };
    }
    function checkScrollableSpace() {
      const targetEl = target.value;
      if (!targetEl) return;
      const {
        clientHeight,
        scrollHeight
      } = getScrollMetrics(targetEl);
      const maxScrollableDistance = scrollHeight - clientHeight;

      // When the scroll-hide element (like AppBar) hides, it causes the page to grow
      // We need extra scrollable space beyond the threshold to prevent bouncing
      // Add the element's height to the required minimum distance
      const elementHeight = layoutSize?.value || 0;
      const minRequiredDistance = scrollThreshold.value + elementHeight;

      // Only enable scroll-hide if there's enough scrollable space
      hasEnoughScrollableSpace.value = maxScrollableDistance > minRequiredDistance;
    }
    function onResize() {
      checkScrollableSpace();
    }
    function onScroll() {
      const targetEl = target.value;
      if (!targetEl || canScroll && !canScroll.value) return;
      previousScroll = currentScroll.value;
      currentScroll.value = 'window' in targetEl ? targetEl.pageYOffset : targetEl.scrollTop;
      const currentScrollHeight = targetEl instanceof Window ? document.documentElement.scrollHeight : targetEl.scrollHeight;
      if (previousScrollHeight !== currentScrollHeight) {
        // If page is growing (content loading), recalculate scrollable space
        // If page is shrinking (likely due to navbar animation), don't recalculate
        if (currentScrollHeight > previousScrollHeight) {
          checkScrollableSpace();
        }
        previousScrollHeight = currentScrollHeight;
      }
      isScrollingUp.value = currentScroll.value < previousScroll;
      currentThreshold.value = Math.abs(currentScroll.value - scrollThreshold.value);

      // Detect if at bottom of page
      const {
        clientHeight,
        scrollHeight
      } = getScrollMetrics(targetEl);
      const atBottom = currentScroll.value + clientHeight >= scrollHeight - 5;

      // Track when bottom is reached during downward scroll
      // Only set flag if ALL conditions are met:
      // 1. Scrolled past threshold (navbar is hiding)
      // 2. Page has enough scrollable space for scroll-hide
      // This prevents activation on short pages or edge cases
      if (!isScrollingUp.value && atBottom && currentScroll.value >= scrollThreshold.value && hasEnoughScrollableSpace.value) {
        reachedBottomWhileScrollingDown.value = true;
      }

      // Reset the flag when:
      // 1. Scrolling up away from bottom (with small tolerance for touchpad/momentum scrolling)
      // 2. Scroll position jumped significantly (e.g., navigation, scroll restoration)
      // 3. Scroll is at the very top (page navigation resets to top)
      const scrollJumped = Math.abs(currentScroll.value - previousScroll) > 100;
      const atTop = currentScroll.value <= 5;
      const scrolledUpSignificantly = isScrollingUp.value && previousScroll - currentScroll.value > 1;
      if (scrolledUpSignificantly && !atBottom || scrollJumped && currentScroll.value < scrollThreshold.value || atTop) {
        reachedBottomWhileScrollingDown.value = false;
      }

      // Update state
      isAtBottom.value = atBottom;
    }
    vue.watch(isScrollingUp, () => {
      savedScroll.value = savedScroll.value || currentScroll.value;
    });
    vue.watch(isScrollActive, () => {
      savedScroll.value = 0;
    });
    vue.onMounted(() => {
      vue.watch(() => props.scrollTarget, scrollTarget => {
        const newTarget = scrollTarget ? document.querySelector(scrollTarget) : window;
        if (!newTarget) {
          consoleWarn(`Unable to locate element with identifier ${scrollTarget}`);
          return;
        }
        if (newTarget === target.value) return;
        target.value?.removeEventListener('scroll', onScroll);
        target.value = newTarget;
        target.value.addEventListener('scroll', onScroll, {
          passive: true
        });

        // Check scrollable space when target is set
        Promise.resolve().then(() => {
          checkScrollableSpace();
        });
      }, {
        immediate: true
      });

      // Listen to window resize to recalculate scrollable space
      window.addEventListener('resize', onResize, {
        passive: true
      });
    });
    vue.onBeforeUnmount(() => {
      target.value?.removeEventListener('scroll', onScroll);
      window.removeEventListener('resize', onResize);
    });

    // Do we need this? If yes - seems that
    // there's no need to expose onScroll
    canScroll && vue.watch(canScroll, onScroll, {
      immediate: true
    });
    return {
      scrollThreshold,
      currentScroll,
      currentThreshold,
      isScrollActive,
      scrollRatio,
      // required only for testing
      // probably can be removed
      // later (2 chars chlng)
      isScrollingUp,
      savedScroll,
      isAtBottom,
      reachedBottomWhileScrollingDown,
      hasEnoughScrollableSpace
    };
  }

  // Utilities

  // Composables
  function useSsrBoot() {
    const isBooted = vue.shallowRef(false);
    vue.onMounted(() => {
      window.requestAnimationFrame(() => {
        isBooted.value = true;
      });
    });
    const ssrBootStyles = vue.toRef(() => !isBooted.value ? {
      transition: 'none !important'
    } : undefined);
    return {
      ssrBootStyles,
      isBooted: vue.readonly(isBooted)
    };
  }

  // Types

  const makeVAppBarProps = propsFactory({
    scrollBehavior: String,
    modelValue: {
      type: Boolean,
      default: true
    },
    location: {
      type: String,
      default: 'top',
      validator: value => ['top', 'bottom'].includes(value)
    },
    ...omit(makeVToolbarProps(), ['location']),
    ...makeLayoutItemProps(),
    ...makeScrollProps(),
    height: {
      type: [Number, String],
      default: 64
    }
  }, 'VAppBar');
  const VAppBar = genericComponent()({
    name: 'VAppBar',
    props: makeVAppBarProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const vToolbarRef = vue.ref();
      const isActive = useProxiedModel(props, 'modelValue');
      const scrollBehavior = vue.computed(() => {
        const behavior = new Set(props.scrollBehavior?.split(' ') ?? []);
        return {
          hide: behavior.has('hide'),
          fullyHide: behavior.has('fully-hide'),
          inverted: behavior.has('inverted'),
          collapse: behavior.has('collapse'),
          elevate: behavior.has('elevate'),
          fadeImage: behavior.has('fade-image')
          // shrink: behavior.has('shrink'),
        };
      });
      const canScroll = vue.computed(() => {
        const behavior = scrollBehavior.value;
        return behavior.hide || behavior.fullyHide || behavior.inverted || behavior.collapse || behavior.elevate || behavior.fadeImage ||
        // behavior.shrink ||
        !isActive.value;
      });
      const appBarHeight = vue.computed(() => {
        const height = vToolbarRef.value?.contentHeight ?? 0;
        const extensionHeight = vToolbarRef.value?.extensionHeight ?? 0;
        return height + extensionHeight;
      });
      const {
        currentScroll,
        scrollThreshold,
        isScrollingUp,
        scrollRatio,
        isAtBottom,
        reachedBottomWhileScrollingDown,
        hasEnoughScrollableSpace
      } = useScroll(props, {
        canScroll,
        layoutSize: appBarHeight
      });
      const canHide = vue.toRef(() => scrollBehavior.value.hide || scrollBehavior.value.fullyHide);
      const isCollapsed = vue.computed(() => props.collapse || scrollBehavior.value.collapse && (scrollBehavior.value.inverted ? scrollRatio.value > 0 : scrollRatio.value === 0));
      const isFlat = vue.computed(() => props.flat || scrollBehavior.value.fullyHide && !isActive.value || scrollBehavior.value.elevate && (scrollBehavior.value.inverted ? currentScroll.value > 0 : currentScroll.value === 0));
      const opacity = vue.computed(() => scrollBehavior.value.fadeImage ? scrollBehavior.value.inverted ? 1 - scrollRatio.value : scrollRatio.value : undefined);
      const height = vue.computed(() => {
        if (scrollBehavior.value.hide && scrollBehavior.value.inverted) return 0;
        const height = vToolbarRef.value?.contentHeight ?? 0;
        const extensionHeight = vToolbarRef.value?.extensionHeight ?? 0;
        if (!canHide.value) return height + extensionHeight;
        return currentScroll.value < scrollThreshold.value || scrollBehavior.value.fullyHide ? height + extensionHeight : height;
      });
      useToggleScope(() => !!props.scrollBehavior, () => {
        vue.watchEffect(() => {
          if (!canHide.value) {
            isActive.value = true;
            return;
          }
          if (scrollBehavior.value.inverted) {
            isActive.value = currentScroll.value > scrollThreshold.value;
            return;
          }

          // If there's not enough scrollable space, don't apply scroll-hide behavior at all
          // This prevents flickering/bouncing animations on short pages
          if (!hasEnoughScrollableSpace.value) {
            isActive.value = true;
            return;
          }

          // Prevent navbar from showing when we reached bottom while scrolling down
          // This handles the case where scroll momentum causes to hit bottom during hide transition
          if (reachedBottomWhileScrollingDown.value) {
            isActive.value = false;
            return;
          }

          // Normal behavior: show when scrolling up (and not at bottom) or above threshold
          isActive.value = isScrollingUp.value && !isAtBottom.value || currentScroll.value < scrollThreshold.value;
        });
      });
      const {
        ssrBootStyles
      } = useSsrBoot();
      const {
        layoutItemStyles
      } = useLayoutItem({
        id: props.name,
        order: vue.computed(() => parseInt(props.order, 10)),
        position: vue.toRef(() => props.location),
        layoutSize: height,
        elementSize: vue.shallowRef(undefined),
        active: isActive,
        absolute: vue.toRef(() => props.absolute)
      });
      useRender(() => {
        const toolbarProps = omit(VToolbar.filterProps(props), ['location']);
        return vue.createVNode(VToolbar, vue.mergeProps({
          "ref": vToolbarRef,
          "class": ['v-app-bar', {
            'v-app-bar--bottom': props.location === 'bottom'
          }, props.class],
          "style": [{
            ...layoutItemStyles.value,
            '--v-toolbar-image-opacity': opacity.value,
            height: undefined,
            ...ssrBootStyles.value
          }, props.style]
        }, toolbarProps, {
          "collapse": isCollapsed.value,
          "flat": isFlat.value
        }), slots);
      });
      return {};
    }
  });

  // Utilities

  // Types

  const allowedDensities = [null, 'default', 'comfortable', 'compact'];

  // typeof allowedDensities[number] evaluates to any
  // when generating api types for whatever reason.

  // Composables
  const makeDensityProps = propsFactory({
    density: {
      type: String,
      default: 'default',
      validator: v => allowedDensities.includes(v)
    }
  }, 'density');
  function useDensity(props, name = getCurrentInstanceName()) {
    const densityClasses = vue.toRef(() => {
      return `${name}--density-${props.density}`;
    });
    return {
      densityClasses
    };
  }

  // Types

  const allowedVariants$3 = ['elevated', 'flat', 'tonal', 'outlined', 'text', 'plain'];
  function genOverlays(isClickable, name) {
    return vue.createElementVNode(vue.Fragment, null, [isClickable && vue.createElementVNode("span", {
      "key": "overlay",
      "class": vue.normalizeClass(`${name}__overlay`)
    }, null), vue.createElementVNode("span", {
      "key": "underlay",
      "class": vue.normalizeClass(`${name}__underlay`)
    }, null)]);
  }
  const makeVariantProps = propsFactory({
    color: String,
    variant: {
      type: String,
      default: 'elevated',
      validator: v => allowedVariants$3.includes(v)
    }
  }, 'variant');
  function useVariant(props, name = getCurrentInstanceName()) {
    const variantClasses = vue.toRef(() => {
      const {
        variant
      } = vue.toValue(props);
      return `${name}--variant-${variant}`;
    });
    const {
      colorClasses,
      colorStyles
    } = useColor(() => {
      const {
        variant,
        color
      } = vue.toValue(props);
      return {
        [['elevated', 'flat'].includes(variant) ? 'background' : 'text']: color
      };
    });
    return {
      colorClasses,
      colorStyles,
      variantClasses
    };
  }

  // Types

  const makeVBtnGroupProps = propsFactory({
    baseColor: String,
    divided: Boolean,
    direction: {
      type: String,
      default: 'horizontal'
    },
    ...makeBorderProps(),
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...makeElevationProps(),
    ...makeRoundedProps(),
    ...makeTagProps(),
    ...makeThemeProps(),
    ...makeVariantProps()
  }, 'VBtnGroup');
  const VBtnGroup = genericComponent()({
    name: 'VBtnGroup',
    props: makeVBtnGroupProps(),
    setup(props, {
      slots
    }) {
      const {
        themeClasses
      } = provideTheme(props);
      const {
        densityClasses
      } = useDensity(props);
      const {
        borderClasses
      } = useBorder(props);
      const {
        elevationClasses
      } = useElevation(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      provideDefaults({
        VBtn: {
          height: vue.toRef(() => props.direction === 'horizontal' ? 'auto' : null),
          baseColor: vue.toRef(() => props.baseColor),
          color: vue.toRef(() => props.color),
          density: vue.toRef(() => props.density),
          flat: true,
          variant: vue.toRef(() => props.variant)
        }
      });
      useRender(() => {
        return vue.createVNode(props.tag, {
          "class": vue.normalizeClass(['v-btn-group', `v-btn-group--${props.direction}`, {
            'v-btn-group--divided': props.divided
          }, themeClasses.value, borderClasses.value, densityClasses.value, elevationClasses.value, roundedClasses.value, props.class]),
          "style": vue.normalizeStyle([roundedStyles.value, props.style])
        }, slots);
      });
    }
  });

  // Composables

  // Types

  const makeGroupProps = propsFactory({
    modelValue: {
      type: null,
      default: undefined
    },
    multiple: Boolean,
    mandatory: [Boolean, String],
    max: Number,
    selectedClass: String,
    disabled: Boolean
  }, 'group');
  const makeGroupItemProps = propsFactory({
    value: null,
    disabled: Boolean,
    selectedClass: String
  }, 'group-item');

  // Composables

  function useGroupItem(props, injectKey, required = true) {
    const vm = getCurrentInstance('useGroupItem');
    if (!vm) {
      throw new Error('[Vuetify] useGroupItem composable must be used inside a component setup function');
    }
    const id = vue.useId();
    vue.provide(Symbol.for(`${injectKey.description}:id`), id);
    const group = vue.inject(injectKey, null);
    if (!group) {
      if (!required) return group;
      throw new Error(`[Vuetify] Could not find useGroup injection with symbol ${injectKey.description}`);
    }
    const value = vue.toRef(() => props.value);
    const disabled = vue.computed(() => !!(group.disabled.value || props.disabled));
    function register() {
      group?.register({
        id,
        value,
        disabled
      }, vm);
    }
    function unregister() {
      group?.unregister(id);
    }
    register();
    vue.onBeforeUnmount(() => unregister());
    const isSelected = vue.computed(() => {
      return group.isSelected(id);
    });
    const isFirst = vue.computed(() => {
      return group.items.value[0].id === id;
    });
    const isLast = vue.computed(() => {
      return group.items.value[group.items.value.length - 1].id === id;
    });
    const selectedClass = vue.computed(() => isSelected.value && [group.selectedClass.value, props.selectedClass]);
    vue.watch(isSelected, value => {
      vm.emit('group:selected', {
        value
      });
    }, {
      flush: 'sync'
    });
    return {
      id,
      isSelected,
      isFirst,
      isLast,
      toggle: () => group.select(id, !isSelected.value),
      select: value => group.select(id, value),
      selectedClass,
      value,
      disabled,
      group,
      register,
      unregister
    };
  }
  function useGroup(props, injectKey) {
    let isUnmounted = false;
    const items = vue.reactive([]);
    const selected = useProxiedModel(props, 'modelValue', [], v => {
      if (v === undefined) return [];
      return getIds(items, v === null ? [null] : wrapInArray(v));
    }, v => {
      const arr = getValues(items, v);
      return props.multiple ? arr : arr[0];
    });
    const groupVm = getCurrentInstance('useGroup');
    function register(item, vm) {
      // Is there a better way to fix this typing?
      const unwrapped = item;
      const key = Symbol.for(`${injectKey.description}:id`);
      const children = findChildrenWithProvide(key, groupVm?.vnode);
      const index = children.indexOf(vm);
      if (vue.unref(unwrapped.value) === undefined) {
        unwrapped.value = index;
        unwrapped.useIndexAsValue = true;
      }
      if (index > -1) {
        items.splice(index, 0, unwrapped);
      } else {
        items.push(unwrapped);
      }
    }
    function unregister(id) {
      if (isUnmounted) return;

      // TODO: re-evaluate this line's importance in the future
      // should we only modify the model if mandatory is set.
      // selected.value = selected.value.filter(v => v !== id)

      forceMandatoryValue();
      const index = items.findIndex(item => item.id === id);
      items.splice(index, 1);
    }

    // If mandatory and nothing is selected, then select first non-disabled item
    function forceMandatoryValue() {
      const item = items.find(item => !item.disabled);
      if (item && props.mandatory === 'force' && !selected.value.length) {
        selected.value = [item.id];
      }
    }
    vue.onMounted(() => {
      forceMandatoryValue();
    });
    vue.onBeforeUnmount(() => {
      isUnmounted = true;
    });
    vue.onUpdated(() => {
      // #19655 update the items that use the index as the value.
      for (let i = 0; i < items.length; i++) {
        if (items[i].useIndexAsValue) {
          items[i].value = i;
        }
      }
    });
    function select(id, value) {
      const item = items.find(item => item.id === id);
      if (value && item?.disabled) return;
      if (props.multiple) {
        const internalValue = selected.value.slice();
        const index = internalValue.findIndex(v => v === id);
        const isSelected = ~index;
        value = value ?? !isSelected;

        // We can't remove value if group is
        // mandatory, value already exists,
        // and it is the only value
        if (isSelected && props.mandatory && internalValue.length <= 1) return;

        // We can't add value if it would
        // cause max limit to be exceeded
        if (!isSelected && props.max != null && internalValue.length + 1 > props.max) return;
        if (index < 0 && value) internalValue.push(id);else if (index >= 0 && !value) internalValue.splice(index, 1);
        selected.value = internalValue;
      } else {
        const isSelected = selected.value.includes(id);
        if (props.mandatory && isSelected) return;
        if (!isSelected && !value) return;
        selected.value = value ?? !isSelected ? [id] : [];
      }
    }
    function step(offset) {
      // getting an offset from selected value obviously won't work with multiple values
      if (props.multiple) consoleWarn('This method is not supported when using "multiple" prop');
      if (!selected.value.length) {
        const item = items.find(item => !item.disabled);
        item && (selected.value = [item.id]);
      } else {
        const currentId = selected.value[0];
        const currentIndex = items.findIndex(i => i.id === currentId);
        let newIndex = (currentIndex + offset) % items.length;
        let newItem = items[newIndex];
        while (newItem.disabled && newIndex !== currentIndex) {
          newIndex = (newIndex + offset) % items.length;
          newItem = items[newIndex];
        }
        if (newItem.disabled) return;
        selected.value = [items[newIndex].id];
      }
    }
    const state = {
      register,
      unregister,
      selected,
      select,
      disabled: vue.toRef(() => props.disabled),
      prev: () => step(items.length - 1),
      next: () => step(1),
      isSelected: id => selected.value.includes(id),
      selectedClass: vue.toRef(() => props.selectedClass),
      items: vue.toRef(() => items),
      getItemIndex: value => getItemIndex(items, value)
    };
    vue.provide(injectKey, state);
    return state;
  }
  function getItemIndex(items, value) {
    const ids = getIds(items, [value]);
    if (!ids.length) return -1;
    return items.findIndex(item => item.id === ids[0]);
  }
  function getIds(items, modelValue) {
    const ids = [];
    modelValue.forEach(value => {
      const item = items.find(item => deepEqual(value, item.value));
      const itemByIndex = items[value];
      if (item?.value !== undefined) {
        ids.push(item.id);
      } else if (itemByIndex?.useIndexAsValue) {
        ids.push(itemByIndex.id);
      }
    });
    return ids;
  }
  function getValues(items, ids) {
    const values = [];
    ids.forEach(id => {
      const itemIndex = items.findIndex(item => item.id === id);
      if (~itemIndex) {
        const item = items[itemIndex];
        values.push(item.value !== undefined ? item.value : itemIndex);
      }
    });
    return values;
  }

  // Types

  const VBtnToggleSymbol = Symbol.for('vuetify:v-btn-toggle');
  const makeVBtnToggleProps = propsFactory({
    ...makeVBtnGroupProps(),
    ...makeGroupProps()
  }, 'VBtnToggle');
  const VBtnToggle = genericComponent()({
    name: 'VBtnToggle',
    props: makeVBtnToggleProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const {
        isSelected,
        next,
        prev,
        select,
        selected
      } = useGroup(props, VBtnToggleSymbol);
      useRender(() => {
        const btnGroupProps = VBtnGroup.filterProps(props);
        return vue.createVNode(VBtnGroup, vue.mergeProps({
          "class": ['v-btn-toggle', {
            'v-btn-toggle--has-color': !!props.color
          }, props.class]
        }, btnGroupProps, {
          "style": props.style
        }), {
          default: () => [slots.default?.({
            isSelected,
            next,
            prev,
            select,
            selected
          })]
        });
      });
      return {
        next,
        prev,
        select
      };
    }
  });

  // Utilities

  // Types
  const predefinedSizes$1 = ['x-small', 'small', 'default', 'large', 'x-large'];
  // Composables
  const makeSizeProps = propsFactory({
    size: {
      type: [String, Number],
      default: 'default'
    }
  }, 'size');
  function useSize(props, name = getCurrentInstanceName()) {
    return destructComputed(() => {
      const size = props.size;
      let sizeClasses;
      let sizeStyles;
      if (includes(predefinedSizes$1, size)) {
        sizeClasses = `${name}--size-${size}`;
      } else if (size) {
        sizeStyles = {
          width: convertToUnit(size),
          height: convertToUnit(size)
        };
      }
      return {
        sizeClasses,
        sizeStyles
      };
    });
  }

  const makeVIconProps = propsFactory({
    color: String,
    disabled: Boolean,
    start: Boolean,
    end: Boolean,
    icon: IconValue,
    opacity: [String, Number],
    ...makeComponentProps(),
    ...makeSizeProps(),
    ...makeTagProps({
      tag: 'i'
    }),
    ...makeThemeProps()
  }, 'VIcon');
  const VIcon = genericComponent()({
    name: 'VIcon',
    props: makeVIconProps(),
    setup(props, {
      attrs,
      slots
    }) {
      const slotIcon = vue.shallowRef();
      const {
        themeClasses
      } = useTheme();
      const {
        iconData
      } = useIcon(() => slotIcon.value || props.icon);
      const {
        sizeClasses
      } = useSize(props);
      const {
        textColorClasses,
        textColorStyles
      } = useTextColor(() => props.color);
      useRender(() => {
        const slotValue = slots.default?.();
        if (slotValue) {
          slotIcon.value = flattenFragments(slotValue).filter(node => node.type === vue.Text && node.children && typeof node.children === 'string')[0]?.children;
        }
        const hasClick = !!(attrs.onClick || attrs.onClickOnce);
        return vue.createVNode(iconData.value.component, {
          "tag": props.tag,
          "icon": iconData.value.icon,
          "class": vue.normalizeClass(['v-icon', 'notranslate', themeClasses.value, sizeClasses.value, textColorClasses.value, {
            'v-icon--clickable': hasClick,
            'v-icon--disabled': props.disabled,
            'v-icon--start': props.start,
            'v-icon--end': props.end
          }, props.class]),
          "style": vue.normalizeStyle([{
            '--v-icon-opacity': props.opacity
          }, !sizeClasses.value ? {
            fontSize: convertToUnit(props.size),
            height: convertToUnit(props.size),
            width: convertToUnit(props.size)
          } : undefined, textColorStyles.value, props.style]),
          "role": hasClick ? 'button' : undefined,
          "aria-hidden": !hasClick,
          "tabindex": hasClick ? props.disabled ? -1 : 0 : undefined
        }, {
          default: () => [slotValue]
        });
      });
      return {};
    }
  });

  // Utilities
  function useIntersectionObserver(callback, options) {
    const intersectionRef = vue.ref();
    const isIntersecting = vue.shallowRef(false);
    if (SUPPORTS_INTERSECTION) {
      const observer = new IntersectionObserver(entries => {
        isIntersecting.value = !!entries.find(entry => entry.isIntersecting);
      }, options);
      vue.onScopeDispose(() => {
        observer.disconnect();
      });
      vue.watch(intersectionRef, (newValue, oldValue) => {
        if (oldValue) {
          observer.unobserve(oldValue);
          isIntersecting.value = false;
        }
        if (newValue) observer.observe(newValue);
      }, {
        flush: 'post'
      });
    }
    return {
      intersectionRef,
      isIntersecting
    };
  }

  // Utilities

  // Types

  // Types

  // Composables
  const makeRevealProps = propsFactory({
    reveal: {
      type: [Boolean, Object],
      default: false
    }
  }, 'reveal');
  function useReveal(props) {
    const defaultDuration = 900;
    const duration = vue.toRef(() => typeof props.reveal === 'object' ? Math.max(0, Number(props.reveal.duration ?? defaultDuration)) : defaultDuration);
    const state = vue.shallowRef(props.reveal ? 'initial' : 'disabled');
    vue.onMounted(async () => {
      if (props.reveal) {
        state.value = 'initial';
        await new Promise(resolve => requestAnimationFrame(resolve));
        state.value = 'pending';
        await new Promise(resolve => setTimeout(resolve, duration.value));
        state.value = 'done';
      }
    });
    return {
      duration,
      state
    };
  }

  // Types

  const makeVProgressCircularProps = propsFactory({
    bgColor: String,
    color: String,
    indeterminate: [Boolean, String],
    rounded: Boolean,
    modelValue: {
      type: [Number, String],
      default: 0
    },
    rotate: {
      type: [Number, String],
      default: 0
    },
    width: {
      type: [Number, String],
      default: 4
    },
    ...makeComponentProps(),
    ...makeRevealProps(),
    ...makeSizeProps(),
    ...makeTagProps({
      tag: 'div'
    }),
    ...makeThemeProps()
  }, 'VProgressCircular');
  const VProgressCircular = genericComponent()({
    name: 'VProgressCircular',
    props: makeVProgressCircularProps(),
    setup(props, {
      slots
    }) {
      const MAGIC_RADIUS_CONSTANT = 20;
      const CIRCUMFERENCE = 2 * Math.PI * MAGIC_RADIUS_CONSTANT;
      const root = vue.ref();
      const {
        themeClasses
      } = provideTheme(props);
      const {
        sizeClasses,
        sizeStyles
      } = useSize(props);
      const {
        textColorClasses,
        textColorStyles
      } = useTextColor(() => props.color);
      const {
        textColorClasses: underlayColorClasses,
        textColorStyles: underlayColorStyles
      } = useTextColor(() => props.bgColor);
      const {
        intersectionRef,
        isIntersecting
      } = useIntersectionObserver();
      const {
        resizeRef,
        contentRect
      } = useResizeObserver();
      const {
        state: revealState,
        duration: revealDuration
      } = useReveal(props);
      const normalizedValue = vue.toRef(() => revealState.value === 'initial' ? 0 : clamp(parseFloat(props.modelValue), 0, 100));
      const width = vue.toRef(() => Number(props.width));
      const size = vue.toRef(() => {
        // Get size from element if size prop value is small, large etc
        return sizeStyles.value ? Number(props.size) : contentRect.value ? contentRect.value.width : Math.max(width.value, 32);
      });
      const diameter = vue.toRef(() => MAGIC_RADIUS_CONSTANT / (1 - width.value / size.value) * 2);
      const strokeWidth = vue.toRef(() => width.value / size.value * diameter.value);
      const strokeDashOffset = vue.toRef(() => {
        const baseLength = (100 - normalizedValue.value) / 100 * CIRCUMFERENCE;
        return props.rounded && normalizedValue.value > 0 && normalizedValue.value < 100 ? convertToUnit(Math.min(CIRCUMFERENCE - 0.01, baseLength + strokeWidth.value)) : convertToUnit(baseLength);
      });
      const startAngle = vue.computed(() => {
        const baseAngle = Number(props.rotate);
        return props.rounded ? baseAngle + strokeWidth.value / 2 / CIRCUMFERENCE * 360 : baseAngle;
      });
      vue.watchEffect(() => {
        intersectionRef.value = root.value;
        resizeRef.value = root.value;
      });
      useRender(() => vue.createVNode(props.tag, {
        "ref": root,
        "class": vue.normalizeClass(['v-progress-circular', {
          'v-progress-circular--indeterminate': !!props.indeterminate,
          'v-progress-circular--visible': isIntersecting.value,
          'v-progress-circular--disable-shrink': props.indeterminate && (props.indeterminate === 'disable-shrink' || PREFERS_REDUCED_MOTION()),
          'v-progress-circular--revealing': ['initial', 'pending'].includes(revealState.value)
        }, themeClasses.value, sizeClasses.value, textColorClasses.value, props.class]),
        "style": vue.normalizeStyle([sizeStyles.value, textColorStyles.value, {
          '--progress-reveal-duration': `${revealDuration.value}ms`
        }, props.style]),
        "role": "progressbar",
        "aria-valuemin": "0",
        "aria-valuemax": "100",
        "aria-valuenow": props.indeterminate ? undefined : normalizedValue.value
      }, {
        default: () => [vue.createElementVNode("svg", {
          "style": {
            transform: `rotate(calc(-90deg + ${startAngle.value}deg))`
          },
          "xmlns": "http://www.w3.org/2000/svg",
          "viewBox": `0 0 ${diameter.value} ${diameter.value}`
        }, [vue.createElementVNode("circle", {
          "class": vue.normalizeClass(['v-progress-circular__underlay', underlayColorClasses.value]),
          "style": vue.normalizeStyle(underlayColorStyles.value),
          "fill": "transparent",
          "cx": "50%",
          "cy": "50%",
          "r": MAGIC_RADIUS_CONSTANT,
          "stroke-width": strokeWidth.value,
          "stroke-dasharray": CIRCUMFERENCE,
          "stroke-dashoffset": 0
        }, null), vue.createElementVNode("circle", {
          "class": "v-progress-circular__overlay",
          "fill": "transparent",
          "cx": "50%",
          "cy": "50%",
          "r": MAGIC_RADIUS_CONSTANT,
          "stroke-width": strokeWidth.value,
          "stroke-dasharray": CIRCUMFERENCE,
          "stroke-dashoffset": strokeDashOffset.value,
          "stroke-linecap": props.rounded ? 'round' : undefined
        }, null)]), slots.default && vue.createElementVNode("div", {
          "class": "v-progress-circular__content"
        }, [slots.default({
          value: normalizedValue.value
        })])]
      }));
      return {};
    }
  });

  // Utilities

  // Types

  // Composables
  const makeChunksProps = propsFactory({
    chunkCount: {
      type: [Number, String],
      default: null
    },
    chunkWidth: {
      type: [Number, String],
      default: null
    },
    chunkGap: {
      type: [Number, String],
      default: 4
    },
    variant: {
      type: String,
      default: undefined,
      validator: v => ['split'].includes(v)
    }
  }, 'chunks');
  function useChunks(props, containerWidth, value, bufferValue, reversed) {
    const isSplit = vue.toRef(() => props.variant === 'split');
    const chunkCount = vue.toRef(() => isSplit.value ? 2 : Number(props.chunkCount) || 0);
    const hasChunks = vue.toRef(() => !isSplit.value && (!!chunkCount.value || !!props.chunkWidth));
    const chunkWidth = vue.computed(() => {
      const containerSize = vue.toValue(containerWidth);
      if (!containerSize) return 0;
      if (chunkCount.value) {
        const availableWidth = containerSize - Number(props.chunkGap) * (chunkCount.value - 1);
        return availableWidth / chunkCount.value;
      }
      return Number(props.chunkWidth);
    });
    const chunkGap = vue.toRef(() => Number(props.chunkGap));
    const chunksMaskStyles = vue.computed(() => {
      if (!hasChunks.value) return {};
      const chunkGapPx = convertToUnit(chunkGap.value);
      const chunkWidthPx = convertToUnit(chunkWidth.value);
      return {
        maskRepeat: 'repeat-x',
        maskImage: `linear-gradient(90deg, #000, #000 ${chunkWidthPx}, transparent ${chunkWidthPx}, transparent)`,
        maskSize: `calc(${chunkWidthPx} + ${chunkGapPx}) 100%`
      };
    });
    const splitStyles = vue.computed(() => {
      if (!isSplit.value) return undefined;
      const halfGap = convertToUnit(chunkGap.value / 2);
      const position = vue.toValue(reversed) ? 'right' : 'left';
      const val = vue.toValue(value);
      if (val <= 0 || val >= 100) return undefined;
      const buffer = vue.toValue(bufferValue);
      const split = convertToUnit(val, '%');
      const hasBuffer = buffer > val && buffer < 100;
      const bufferSplit = convertToUnit(buffer, '%');
      return {
        bar: {
          width: `calc(${split} - ${halfGap})`
        },
        buffer: hasBuffer ? {
          [position]: `calc(${split} + ${halfGap})`,
          width: `calc(${bufferSplit} - ${split} - ${convertToUnit(chunkGap.value)})`
        } : undefined,
        background: {
          [position]: `calc(${hasBuffer ? bufferSplit : split} + ${halfGap})`,
          width: `calc(100% - ${hasBuffer ? bufferSplit : split} - ${halfGap})`
        }
      };
    });
    function snapValueToChunk(val) {
      if (isSplit.value) return val;
      const containerSize = vue.toValue(containerWidth);
      if (!containerSize) return val;
      const gapRelativeSize = 100 * chunkGap.value / containerSize;
      const chunkRelativeSize = 100 * (chunkWidth.value + chunkGap.value) / containerSize;

      // low-effort workaround to floating-point rounding in the division
      const filledChunks = Math.floor((val + gapRelativeSize) / chunkRelativeSize + 1e-9);
      return clamp(filledChunks * chunkRelativeSize - gapRelativeSize / 2, 0, 100);
    }
    return {
      hasChunks: vue.toRef(() => hasChunks.value || isSplit.value),
      isSplit,
      chunkCount,
      chunksMaskStyles,
      splitStyles,
      snapValueToChunk
    };
  }

  const makeVProgressLinearProps = propsFactory({
    absolute: Boolean,
    active: {
      type: Boolean,
      default: true
    },
    bgColor: String,
    bgOpacity: [Number, String],
    bufferValue: {
      type: [Number, String],
      default: 0
    },
    bufferColor: String,
    bufferOpacity: [Number, String],
    clickable: Boolean,
    color: String,
    height: {
      type: [Number, String],
      default: 4
    },
    indeterminate: Boolean,
    max: {
      type: [Number, String],
      default: 100
    },
    modelValue: {
      type: [Number, String],
      default: 0
    },
    opacity: [Number, String],
    reverse: Boolean,
    stream: Boolean,
    striped: Boolean,
    roundedBar: Boolean,
    ...makeChunksProps(),
    ...makeComponentProps(),
    ...makeLocationProps({
      location: 'top'
    }),
    ...makeRoundedProps(),
    ...makeTagProps(),
    ...makeThemeProps()
  }, 'VProgressLinear');
  const VProgressLinear = genericComponent()({
    name: 'VProgressLinear',
    props: makeVProgressLinearProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const root = vue.ref();
      const progress = useProxiedModel(props, 'modelValue');
      const {
        isRtl,
        rtlClasses
      } = useRtl();
      const {
        themeClasses
      } = provideTheme(props);
      const {
        locationStyles
      } = useLocation(props);
      const {
        textColorClasses,
        textColorStyles
      } = useTextColor(() => props.color);
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.bgColor || props.color);
      const {
        backgroundColorClasses: bufferColorClasses,
        backgroundColorStyles: bufferColorStyles
      } = useBackgroundColor(() => props.bufferColor || props.bgColor || props.color);
      const {
        backgroundColorClasses: barColorClasses,
        backgroundColorStyles: barColorStyles
      } = useBackgroundColor(() => props.color);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const {
        intersectionRef,
        isIntersecting
      } = useIntersectionObserver();
      const max = vue.computed(() => parseFloat(props.max));
      const height = vue.computed(() => parseFloat(props.height));
      const normalizedBuffer = vue.computed(() => clamp(parseFloat(props.bufferValue) / max.value * 100, 0, 100));
      const normalizedValue = vue.computed(() => clamp(parseFloat(progress.value) / max.value * 100, 0, 100));
      const isReversed = vue.computed(() => isRtl.value !== props.reverse);
      const transition = vue.computed(() => props.indeterminate ? 'fade-transition' : 'slide-x-transition');
      const containerWidth = vue.shallowRef(0);
      const {
        hasChunks,
        splitStyles,
        chunksMaskStyles,
        snapValueToChunk
      } = useChunks(props, containerWidth, normalizedValue, normalizedBuffer, isReversed);
      useToggleScope(hasChunks, () => {
        const {
          resizeRef
        } = useResizeObserver(entries => containerWidth.value = entries[0].contentRect.width);
        vue.watchEffect(() => resizeRef.value = root.value);
      });
      const bufferWidth = vue.computed(() => {
        return hasChunks.value ? snapValueToChunk(normalizedBuffer.value) : normalizedBuffer.value;
      });
      const barWidth = vue.computed(() => {
        return hasChunks.value ? snapValueToChunk(normalizedValue.value) : normalizedValue.value;
      });
      function handleClick(e) {
        if (!intersectionRef.value) return;
        const {
          left,
          right,
          width
        } = intersectionRef.value.getBoundingClientRect();
        const value = isReversed.value ? width - e.clientX + (right - width) : e.clientX - left;
        progress.value = Math.round(value / width * max.value);
      }
      vue.watchEffect(() => {
        intersectionRef.value = root.value;
      });
      function renderBackgroundBar() {
        return vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-progress-linear__background', backgroundColorClasses.value]),
          "style": vue.normalizeStyle([backgroundColorStyles.value, {
            opacity: props.bgOpacity != null ? parseFloat(props.bgOpacity) : undefined,
            width: props.stream ? 0 : undefined
          }, props.indeterminate ? {} : splitStyles.value?.background])
        }, null);
      }
      useRender(() => vue.createVNode(props.tag, {
        "ref": root,
        "class": vue.normalizeClass(['v-progress-linear', {
          'v-progress-linear--absolute': props.absolute,
          'v-progress-linear--active': props.active && isIntersecting.value,
          'v-progress-linear--reverse': isReversed.value,
          'v-progress-linear--rounded': props.rounded,
          'v-progress-linear--rounded-bar': props.roundedBar,
          'v-progress-linear--striped': props.striped,
          'v-progress-linear--clickable': props.clickable,
          'v-progress-linear--variant-split': props.variant === 'split'
        }, roundedClasses.value, themeClasses.value, rtlClasses.value, props.class]),
        "style": vue.normalizeStyle([{
          bottom: props.location === 'bottom' ? 0 : undefined,
          top: props.location === 'top' ? 0 : undefined,
          height: props.active ? convertToUnit(height.value) : 0,
          '--v-progress-linear-height': convertToUnit(height.value),
          '--v-progress-chunk-gap': convertToUnit(props.chunkGap),
          ...(props.absolute ? locationStyles.value : {})
        }, chunksMaskStyles.value, roundedStyles.value, props.style]),
        "role": "progressbar",
        "aria-hidden": props.active ? 'false' : 'true',
        "aria-valuemin": "0",
        "aria-valuemax": props.max,
        "aria-valuenow": props.indeterminate ? undefined : Math.min(parseFloat(progress.value), max.value),
        "onClick": props.clickable && handleClick
      }, {
        default: () => [props.stream && vue.createElementVNode("div", {
          "key": "stream",
          "class": vue.normalizeClass(['v-progress-linear__stream', textColorClasses.value]),
          "style": {
            ...textColorStyles.value,
            [isReversed.value ? 'left' : 'right']: convertToUnit(-height.value),
            borderTop: `${convertToUnit(height.value / 2)} dotted`,
            opacity: props.bufferOpacity != null ? parseFloat(props.bufferOpacity) : undefined,
            top: `calc(50% - ${convertToUnit(height.value / 4)})`,
            width: convertToUnit(100 - normalizedBuffer.value, '%'),
            '--v-progress-linear-stream-to': convertToUnit(height.value * (isReversed.value ? 1 : -1))
          }
        }, null), (props.variant !== 'split' || !props.indeterminate) && renderBackgroundBar(), vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-progress-linear__buffer', bufferColorClasses.value]),
          "style": vue.normalizeStyle([bufferColorStyles.value, {
            opacity: props.bufferOpacity != null ? parseFloat(props.bufferOpacity) : undefined,
            width: convertToUnit(bufferWidth.value, '%')
          }, splitStyles.value?.buffer])
        }, null), vue.createVNode(vue.Transition, {
          "name": transition.value
        }, {
          default: () => [!props.indeterminate ? vue.createElementVNode("div", {
            "class": vue.normalizeClass(['v-progress-linear__determinate', barColorClasses.value]),
            "style": vue.normalizeStyle([barColorStyles.value, {
              width: convertToUnit(barWidth.value, '%')
            }, splitStyles.value?.bar])
          }, null) : vue.createElementVNode("div", {
            "class": "v-progress-linear__indeterminate"
          }, [props.variant === 'split' && vue.createElementVNode(vue.Fragment, null, [renderBackgroundBar(), renderBackgroundBar(), renderBackgroundBar()]), ['long', 'short'].map(bar => vue.createElementVNode("div", {
            "key": bar,
            "class": vue.normalizeClass(['v-progress-linear__indeterminate', bar, barColorClasses.value]),
            "style": vue.normalizeStyle(barColorStyles.value)
          }, null))])]
        }), slots.default && vue.createElementVNode("div", {
          "class": "v-progress-linear__content"
        }, [slots.default({
          value: normalizedValue.value,
          buffer: normalizedBuffer.value
        })])]
      }));
      return {};
    }
  });

  // Types

  // Composables
  const makeLoaderProps = propsFactory({
    loading: [Boolean, String]
  }, 'loader');
  function useLoader(props, name = getCurrentInstanceName()) {
    const loaderClasses = vue.toRef(() => ({
      [`${name}--loading`]: props.loading
    }));
    return {
      loaderClasses
    };
  }
  function LoaderSlot(props, {
    slots
  }) {
    return vue.createElementVNode("div", {
      "class": vue.normalizeClass(`${props.name}__loader`)
    }, [slots.default?.({
      color: props.color,
      isActive: props.active
    }) || vue.createVNode(VProgressLinear, {
      "absolute": props.absolute,
      "active": props.active,
      "color": props.color,
      "height": "2",
      "indeterminate": true
    }, null)]);
  }

  // Utilities

  // Types

  const positionValues = ['static', 'relative', 'fixed', 'absolute', 'sticky'];
  // Composables
  const makePositionProps = propsFactory({
    position: {
      type: String,
      validator: /* istanbul ignore next */v => positionValues.includes(v)
    }
  }, 'position');
  function usePosition(props, name = getCurrentInstanceName()) {
    const positionClasses = vue.toRef(() => {
      return props.position ? `${name}--${props.position}` : undefined;
    });
    return {
      positionClasses
    };
  }

  // Utilities

  // Types

  function useRoute() {
    const vm = getCurrentInstance('useRoute');
    return vue.computed(() => vm?.proxy?.$route);
  }
  function useRouter() {
    return getCurrentInstance('useRouter')?.proxy?.$router;
  }
  function useLink(props, attrs) {
    const RouterLink = vue.resolveDynamicComponent('RouterLink');
    const isLink = vue.toRef(() => !!(props.href || props.to));
    const isClickable = vue.computed(() => {
      return isLink?.value || hasEvent(attrs, 'click') || hasEvent(props, 'click');
    });
    if (typeof RouterLink === 'string' || !('useLink' in RouterLink)) {
      const href = vue.toRef(() => props.href);
      return {
        isLink,
        isRouterLink: vue.toRef(() => false),
        isClickable,
        href,
        linkProps: vue.reactive({
          href
        }),
        route: vue.toRef(() => undefined),
        navigate: vue.toRef(() => undefined)
      };
    }

    // vue-router useLink `to` prop needs to be reactive and useLink will crash if undefined
    const routerLink = RouterLink.useLink({
      to: vue.toRef(() => props.to || ''),
      replace: vue.toRef(() => props.replace)
    });
    // Actual link needs to be undefined when to prop is not used
    const link = vue.computed(() => props.to ? routerLink : undefined);
    const route = useRoute();
    const isActive = vue.computed(() => {
      if (!link.value) return false;
      // router still resolving initial navigation, according to posva:
      // - START_LOCATION has an empty matched array and its name is undefined (unlike 404 Not Page Found)
      // - if the router is still resolving the initial boot, we bypass the active check and returns
      //   isExactActive ?? false to prevent the flashing overlay on page refresh
      if (route.value && route.value.matched.length === 0 && route.value.name == null) {
        return link.value.isExactActive?.value ?? false;
      }
      if (!props.exact) return link.value.isActive?.value ?? false;
      if (!route.value) return link.value.isExactActive?.value ?? false;
      return link.value.isExactActive?.value && deepEqual(link.value.route.value.query, route.value.query);
    });
    const href = vue.computed(() => props.to ? link.value?.route.value.href : props.href);
    const isRouterLink = vue.toRef(() => !!props.to);
    return {
      isLink,
      isRouterLink,
      isClickable,
      isActive,
      route: vue.toRef(() => link.value?.route.value),
      navigate: vue.toRef(() => link.value?.navigate),
      href,
      linkProps: vue.reactive({
        href,
        'aria-current': vue.toRef(() => isActive.value ? 'page' : undefined),
        'aria-disabled': vue.toRef(() => props.disabled && isLink.value ? 'true' : undefined),
        tabindex: vue.toRef(() => props.disabled && isLink.value ? '-1' : undefined)
      })
    };
  }
  const makeRouterProps = propsFactory({
    href: String,
    replace: Boolean,
    to: [String, Object],
    exact: Boolean
  }, 'router');
  let inTransition = false;
  function useBackButton(router, cb) {
    let popped = false;
    let removeBefore;
    let removeAfter;
    if (IN_BROWSER && router?.beforeEach) {
      vue.nextTick(() => {
        window.addEventListener('popstate', onPopstate);
        removeBefore = router.beforeEach(() => {
          if (!inTransition) {
            inTransition = true;
            return new Promise(resolve => {
              setTimeout(() => resolve(popped ? cb() : undefined));
            });
          }
          return popped ? cb() : undefined;
        });
        removeAfter = router?.afterEach(() => {
          inTransition = false;
        });
      });
      vue.onScopeDispose(() => {
        window.removeEventListener('popstate', onPopstate);
        removeBefore?.();
        removeAfter?.();
      });
    }
    function onPopstate(e) {
      if (e.state?.replaced) return;
      popped = true;
      setTimeout(() => popped = false);
    }
  }

  // Utilities

  // Types

  function useSelectLink(link, select) {
    vue.watch(() => link.isActive?.value, isActive => {
      if (link.isLink.value && isActive != null && select) {
        vue.nextTick(() => {
          select(isActive);
        });
      }
    }, {
      immediate: true
    });
  }

  // Styles

  // Types

  const stopSymbol = Symbol('rippleStop');
  const DELAY_RIPPLE = 80;
  function transform(el, value) {
    el.style.transform = value;
    el.style.webkitTransform = value;
  }
  function isTouchEvent(e) {
    return e.constructor.name === 'TouchEvent';
  }
  function isKeyboardEvent(e) {
    return e.constructor.name === 'KeyboardEvent';
  }
  const calculate = (e, el, value = {}) => {
    let localX = 0;
    let localY = 0;
    if (!isKeyboardEvent(e)) {
      const offset = new Box(el);
      const target = isTouchEvent(e) ? e.touches[e.touches.length - 1] : e;
      const point = getTargetBox([target.clientX, target.clientY]);
      localX = point.x - offset.left;
      localY = point.y - offset.top;
    }
    let radius = 0;
    let scale = 0.3;
    if (el._ripple?.circle) {
      scale = 0.15;
      radius = el.clientWidth / 2;
      radius = value.center ? radius : radius + Math.sqrt((localX - radius) ** 2 + (localY - radius) ** 2) / 4;
    } else {
      radius = Math.sqrt(el.clientWidth ** 2 + el.clientHeight ** 2) / 2;
    }
    const centerX = `${(el.clientWidth - radius * 2) / 2}px`;
    const centerY = `${(el.clientHeight - radius * 2) / 2}px`;
    const x = value.center ? centerX : `${localX - radius}px`;
    const y = value.center ? centerY : `${localY - radius}px`;
    return {
      radius,
      scale,
      x,
      y,
      centerX,
      centerY
    };
  };
  const ripples = {
    /* eslint-disable max-statements */
    show(e, el, value = {}) {
      if (!el?._ripple?.enabled) {
        return;
      }
      const container = document.createElement('span');
      const animation = document.createElement('span');
      container.appendChild(animation);
      container.className = 'v-ripple__container';
      if (value.class) {
        container.className += ` ${value.class}`;
      }
      const {
        radius,
        scale,
        x,
        y,
        centerX,
        centerY
      } = calculate(e, el, value);
      const size = `${radius * 2}px`;
      animation.className = 'v-ripple__animation';
      animation.style.width = size;
      animation.style.height = size;
      el.appendChild(container);
      const computed = window.getComputedStyle(el);
      if (computed && computed.position === 'static') {
        el.style.position = 'relative';
        el.dataset.previousPosition = 'static';
      }
      animation.classList.add('v-ripple__animation--enter');
      animation.classList.add('v-ripple__animation--visible');
      transform(animation, `translate(${x}, ${y}) scale3d(${scale},${scale},${scale})`);
      animation.dataset.activated = String(performance.now());
      requestAnimationFrame(() => {
        requestAnimationFrame(() => {
          animation.classList.remove('v-ripple__animation--enter');
          animation.classList.add('v-ripple__animation--in');
          transform(animation, `translate(${centerX}, ${centerY}) scale3d(1,1,1)`);
        });
      });
    },
    hide(el) {
      if (!el?._ripple?.enabled) return;
      const ripples = el.getElementsByClassName('v-ripple__animation');
      if (ripples.length === 0) return;
      const animation = Array.from(ripples).findLast(ripple => !ripple.dataset.isHiding);
      if (!animation) return;else animation.dataset.isHiding = 'true';
      const diff = performance.now() - Number(animation.dataset.activated);
      const delay = Math.max(250 - diff, 0);
      setTimeout(() => {
        animation.classList.remove('v-ripple__animation--in');
        animation.classList.add('v-ripple__animation--out');
        setTimeout(() => {
          const ripples = el.getElementsByClassName('v-ripple__animation');
          if (ripples.length === 1 && el.dataset.previousPosition) {
            el.style.position = el.dataset.previousPosition;
            delete el.dataset.previousPosition;
          }
          if (animation.parentNode?.parentNode === el) el.removeChild(animation.parentNode);
        }, 300);
      }, delay);
    }
  };
  function isRippleEnabled(value) {
    return typeof value === 'undefined' || !!value;
  }
  function rippleShow(e) {
    const value = {};
    const element = e.currentTarget;
    if (!element?._ripple || element._ripple.touched || e[stopSymbol]) return;

    // Don't allow the event to trigger ripples on any other elements
    e[stopSymbol] = true;
    if (isTouchEvent(e)) {
      element._ripple.touched = true;
      element._ripple.isTouch = true;
    } else {
      // It's possible for touch events to fire
      // as mouse events on Android/iOS, this
      // will skip the event call if it has
      // already been registered as touch
      if (element._ripple.isTouch) return;
    }
    value.center = element._ripple.centered || isKeyboardEvent(e);
    if (element._ripple.class) {
      value.class = element._ripple.class;
    }
    if (isTouchEvent(e)) {
      // already queued that shows or hides the ripple
      if (element._ripple.showTimerCommit) return;
      element._ripple.showTimerCommit = () => {
        ripples.show(e, element, value);
      };
      element._ripple.showTimer = window.setTimeout(() => {
        if (element?._ripple?.showTimerCommit) {
          element._ripple.showTimerCommit();
          element._ripple.showTimerCommit = null;
        }
      }, DELAY_RIPPLE);
    } else {
      ripples.show(e, element, value);
    }
  }
  function rippleStop(e) {
    e[stopSymbol] = true;
  }
  function rippleHide(e) {
    const element = e.currentTarget;
    if (!element?._ripple) return;
    window.clearTimeout(element._ripple.showTimer);

    // The touch interaction occurs before the show timer is triggered.
    // We still want to show ripple effect.
    if (e.type === 'touchend' && element._ripple.showTimerCommit) {
      element._ripple.showTimerCommit();
      element._ripple.showTimerCommit = null;

      // re-queue ripple hiding
      element._ripple.showTimer = window.setTimeout(() => {
        rippleHide(e);
      });
      return;
    }
    window.setTimeout(() => {
      if (element._ripple) {
        element._ripple.touched = false;
      }
    });
    ripples.hide(element);
  }
  function rippleCancelShow(e) {
    const element = e.currentTarget;
    if (!element?._ripple) return;
    if (element._ripple.showTimerCommit) {
      element._ripple.showTimerCommit = null;
    }
    window.clearTimeout(element._ripple.showTimer);
  }
  let keyboardRipple = false;
  function keyboardRippleShow(e, keys) {
    if (!keyboardRipple && keys.includes(e.key)) {
      keyboardRipple = true;
      rippleShow(e);
    }
  }
  function keyboardRippleHide(e) {
    keyboardRipple = false;
    rippleHide(e);
  }
  function focusRippleHide(e) {
    if (keyboardRipple) {
      keyboardRipple = false;
      rippleHide(e);
    }
  }
  function updateRipple(el, binding, wasEnabled) {
    const {
      value,
      modifiers
    } = binding;
    const enabled = isRippleEnabled(value);
    if (!enabled) {
      ripples.hide(el);
    }
    el._ripple = el._ripple ?? {};
    el._ripple.enabled = enabled;
    el._ripple.centered = modifiers.center;
    el._ripple.circle = modifiers.circle;
    const bindingValue = isObject(value) ? value : {};
    if (bindingValue.class) {
      el._ripple.class = bindingValue.class;
    }
    const allowedKeys = bindingValue.keys ?? ['Enter', 'Space'];
    el._ripple.keyDownHandler = e => keyboardRippleShow(e, allowedKeys);
    if (enabled && !wasEnabled) {
      if (modifiers.stop) {
        el.addEventListener('touchstart', rippleStop, {
          passive: true
        });
        el.addEventListener('mousedown', rippleStop);
        return;
      }
      el.addEventListener('touchstart', rippleShow, {
        passive: true
      });
      el.addEventListener('touchend', rippleHide, {
        passive: true
      });
      el.addEventListener('touchmove', rippleCancelShow, {
        passive: true
      });
      el.addEventListener('touchcancel', rippleHide);
      el.addEventListener('mousedown', rippleShow);
      el.addEventListener('mouseup', rippleHide);
      el.addEventListener('mouseleave', rippleHide);
      el.addEventListener('keydown', el._ripple.keyDownHandler);
      el.addEventListener('keyup', keyboardRippleHide);
      el.addEventListener('blur', focusRippleHide);

      // Anchor tags can be dragged, causes other hides to fail - #1537
      el.addEventListener('dragstart', rippleHide, {
        passive: true
      });
    } else if (!enabled && wasEnabled) {
      removeListeners(el);
    }
  }
  function removeListeners(el) {
    el.removeEventListener('touchstart', rippleStop);
    el.removeEventListener('mousedown', rippleStop);
    el.removeEventListener('touchstart', rippleShow);
    el.removeEventListener('touchend', rippleHide);
    el.removeEventListener('touchmove', rippleCancelShow);
    el.removeEventListener('touchcancel', rippleHide);
    el.removeEventListener('mousedown', rippleShow);
    el.removeEventListener('mouseup', rippleHide);
    el.removeEventListener('mouseleave', rippleHide);
    if (el._ripple?.keyDownHandler) {
      el.removeEventListener('keydown', el._ripple.keyDownHandler);
    }
    el.removeEventListener('keyup', keyboardRippleHide);
    el.removeEventListener('blur', focusRippleHide);
    el.removeEventListener('dragstart', rippleHide);
  }
  function mounted$4(el, binding) {
    updateRipple(el, binding, false);
  }
  function unmounted$4(el) {
    removeListeners(el);
    delete el._ripple;
  }
  function updated$1(el, binding) {
    if (binding.value === binding.oldValue) {
      return;
    }
    const wasEnabled = isRippleEnabled(binding.oldValue);
    updateRipple(el, binding, wasEnabled);
  }
  const Ripple = {
    mounted: mounted$4,
    unmounted: unmounted$4,
    updated: updated$1
  };

  // Types

  const makeVBtnProps = propsFactory({
    active: {
      type: Boolean,
      default: undefined
    },
    activeColor: String,
    baseColor: String,
    symbol: {
      type: null,
      default: VBtnToggleSymbol
    },
    flat: Boolean,
    icon: [Boolean, String, Function, Object],
    prependIcon: IconValue,
    appendIcon: IconValue,
    block: Boolean,
    readonly: Boolean,
    slim: Boolean,
    stacked: Boolean,
    spaced: String,
    ripple: {
      type: [Boolean, Object],
      default: true
    },
    text: {
      type: [String, Number, Boolean],
      default: undefined
    },
    ...makeBorderProps(),
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...makeDimensionProps(),
    ...makeElevationProps(),
    ...makeGroupItemProps(),
    ...makeLoaderProps(),
    ...makeLocationProps(),
    ...makePositionProps(),
    ...makeRoundedProps(),
    ...makeRouterProps(),
    ...makeSizeProps(),
    ...makeTagProps({
      tag: 'button'
    }),
    ...makeThemeProps(),
    ...makeVariantProps({
      variant: 'elevated'
    })
  }, 'VBtn');
  const VBtn = genericComponent()({
    name: 'VBtn',
    props: makeVBtnProps(),
    emits: {
      'group:selected': val => true
    },
    setup(props, {
      attrs,
      slots
    }) {
      const {
        themeClasses
      } = provideTheme(props);
      const {
        borderClasses
      } = useBorder(props);
      const {
        densityClasses
      } = useDensity(props);
      const {
        dimensionStyles
      } = useDimension(props);
      const {
        elevationClasses
      } = useElevation(props);
      const {
        loaderClasses
      } = useLoader(props);
      const {
        locationStyles
      } = useLocation(props);
      const {
        positionClasses
      } = usePosition(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const {
        sizeClasses,
        sizeStyles
      } = useSize(props);
      const group = useGroupItem(props, props.symbol, false);
      const link = useLink(props, attrs);
      const isActive = vue.computed(() => {
        if (props.active !== undefined) {
          return props.active;
        }
        if (link.isRouterLink.value) {
          return link.isActive?.value;
        }
        return group?.isSelected.value;
      });
      const color = vue.toRef(() => isActive.value ? props.activeColor ?? props.color : props.color);
      const variantProps = vue.computed(() => {
        const showColor = group?.isSelected.value && (!link.isLink.value || link.isActive?.value) || !group || link.isActive?.value;
        return {
          color: showColor ? color.value ?? props.baseColor : props.baseColor,
          variant: props.variant
        };
      });
      const {
        colorClasses,
        colorStyles,
        variantClasses
      } = useVariant(variantProps);
      const isDisabled = vue.computed(() => group?.disabled.value || props.disabled);
      const isElevated = vue.toRef(() => {
        return props.variant === 'elevated' && !(props.disabled || props.flat || props.border);
      });
      const valueAttr = vue.computed(() => {
        if (props.value === undefined || typeof props.value === 'symbol') return undefined;
        return Object(props.value) === props.value ? JSON.stringify(props.value, null, 0) : props.value;
      });
      function onClick(e) {
        if (isDisabled.value || link.isLink.value && (e.metaKey || e.ctrlKey || e.shiftKey || e.button !== 0 || attrs.target === '_blank')) return;
        if (link.isRouterLink.value) {
          link.navigate.value?.(e);
        } else {
          // Group active state for links is handled by useSelectLink
          group?.toggle();
        }
      }
      useSelectLink(link, group?.select);
      useRender(() => {
        const Tag = link.isLink.value ? 'a' : props.tag;
        const hasPrepend = !!(props.prependIcon || slots.prepend);
        const hasAppend = !!(props.appendIcon || slots.append);
        const hasIcon = !!(props.icon && props.icon !== true);
        return vue.withDirectives(vue.createVNode(Tag, vue.mergeProps(link.linkProps, {
          "type": Tag === 'a' ? undefined : 'button',
          "class": ['v-btn', group?.selectedClass.value, {
            'v-btn--active': isActive.value,
            'v-btn--block': props.block,
            'v-btn--disabled': isDisabled.value,
            'v-btn--elevated': isElevated.value,
            'v-btn--flat': props.flat,
            'v-btn--icon': !!props.icon,
            'v-btn--loading': props.loading,
            'v-btn--readonly': props.readonly,
            'v-btn--slim': props.slim,
            'v-btn--stacked': props.stacked
          }, props.spaced ? ['v-btn--spaced', `v-btn--spaced-${props.spaced}`] : [], themeClasses.value, borderClasses.value, colorClasses.value, densityClasses.value, elevationClasses.value, loaderClasses.value, positionClasses.value, roundedClasses.value, sizeClasses.value, variantClasses.value, props.class],
          "style": [colorStyles.value, dimensionStyles.value, locationStyles.value, sizeStyles.value, roundedStyles.value, props.style],
          "aria-busy": props.loading ? true : undefined,
          "disabled": isDisabled.value && Tag !== 'a' || undefined,
          "tabindex": props.loading || props.readonly ? -1 : undefined,
          "onClick": onClick,
          "value": Tag !== 'a' ? valueAttr.value : undefined
        }), {
          default: () => [genOverlays(true, 'v-btn'), !props.icon && hasPrepend && vue.createElementVNode("span", {
            "key": "prepend",
            "class": "v-btn__prepend"
          }, [!slots.prepend ? vue.createVNode(VIcon, {
            "key": "prepend-icon",
            "icon": props.prependIcon
          }, null) : vue.createVNode(VDefaultsProvider, {
            "key": "prepend-defaults",
            "disabled": !props.prependIcon,
            "defaults": {
              VIcon: {
                icon: props.prependIcon
              }
            }
          }, slots.prepend)]), vue.createElementVNode("span", {
            "class": "v-btn__content",
            "data-no-activator": ""
          }, [!slots.default && hasIcon ? vue.createVNode(VIcon, {
            "key": "content-icon",
            "icon": props.icon
          }, null) : vue.createVNode(VDefaultsProvider, {
            "key": "content-defaults",
            "disabled": !hasIcon,
            "defaults": {
              VIcon: {
                icon: props.icon
              }
            }
          }, {
            default: () => [slots.default?.() ?? vue.toDisplayString(props.text)]
          })]), !props.icon && hasAppend && vue.createElementVNode("span", {
            "key": "append",
            "class": "v-btn__append"
          }, [!slots.append ? vue.createVNode(VIcon, {
            "key": "append-icon",
            "icon": props.appendIcon
          }, null) : vue.createVNode(VDefaultsProvider, {
            "key": "append-defaults",
            "disabled": !props.appendIcon,
            "defaults": {
              VIcon: {
                icon: props.appendIcon
              }
            }
          }, slots.append)]), !!props.loading && vue.createElementVNode("span", {
            "key": "loader",
            "class": "v-btn__loader"
          }, [slots.loader?.() ?? vue.createVNode(VProgressCircular, {
            "color": typeof props.loading === 'boolean' ? undefined : props.loading,
            "indeterminate": true,
            "width": "2"
          }, null)])]
        }), [[Ripple, !isDisabled.value && props.ripple, '', {
          center: !!props.icon
        }]]);
      });
      return {
        group
      };
    }
  });

  // Types

  const makeVAppBarNavIconProps = propsFactory({
    ...omit(makeVBtnProps({
      icon: '$menu',
      variant: 'text'
    }), ['spaced'])
  }, 'VAppBarNavIcon');
  const VAppBarNavIcon = genericComponent()({
    name: 'VAppBarNavIcon',
    props: makeVAppBarNavIconProps(),
    setup(props, {
      slots
    }) {
      useRender(() => vue.createVNode(VBtn, vue.mergeProps(props, {
        "class": ['v-app-bar-nav-icon']
      }), slots));
      return {};
    }
  });

  // Types

  const VAppBarTitle = genericComponent()({
    name: 'VAppBarTitle',
    props: makeVToolbarTitleProps(),
    setup(props, {
      slots
    }) {
      useRender(() => vue.createVNode(VToolbarTitle, vue.mergeProps(props, {
        "class": "v-app-bar-title"
      }), slots));
      return {};
    }
  });

  // Utilities
  const VAlertTitle = createSimpleFunctional('v-alert-title');

  // Utilities

  // Types

  // Types

  // Composables
  const makeIconSizeProps = propsFactory({
    iconSize: [Number, String],
    iconSizes: {
      type: Array,
      default: () => [['x-small', 10], ['small', 16], ['default', 24], ['large', 28], ['x-large', 32]]
    }
  }, 'iconSize');
  function useIconSizes(props, fallback) {
    const iconSize = vue.computed(() => {
      const iconSizeMap = new Map(props.iconSizes);
      const _iconSize = props.iconSize ?? fallback() ?? 'default';
      return iconSizeMap.has(_iconSize) ? iconSizeMap.get(_iconSize) : _iconSize;
    });
    return {
      iconSize
    };
  }

  // Types

  const allowedTypes = ['success', 'info', 'warning', 'error'];
  const makeVAlertProps = propsFactory({
    border: {
      type: [Boolean, String],
      validator: val => {
        return typeof val === 'boolean' || ['top', 'end', 'bottom', 'start'].includes(val);
      }
    },
    borderColor: String,
    closable: Boolean,
    closeIcon: {
      type: IconValue,
      default: '$close'
    },
    closeLabel: {
      type: String,
      default: '$vuetify.close'
    },
    icon: {
      type: [Boolean, String, Function, Object],
      default: null
    },
    modelValue: {
      type: Boolean,
      default: true
    },
    prominent: Boolean,
    title: String,
    text: String,
    type: {
      type: String,
      validator: val => allowedTypes.includes(val)
    },
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...makeDimensionProps(),
    ...makeElevationProps(),
    ...makeIconSizeProps(),
    ...makeLocationProps(),
    ...makePositionProps(),
    ...makeRoundedProps(),
    ...makeTagProps(),
    ...makeThemeProps(),
    ...makeVariantProps({
      variant: 'flat'
    })
  }, 'VAlert');
  const VAlert = genericComponent()({
    name: 'VAlert',
    props: makeVAlertProps(),
    emits: {
      'click:close': e => true,
      'update:modelValue': value => true
    },
    setup(props, {
      emit,
      slots
    }) {
      const isActive = useProxiedModel(props, 'modelValue');
      const icon = vue.toRef(() => {
        if (props.icon === false) return undefined;
        if (!props.type) return props.icon;
        return props.icon ?? `$${props.type}`;
      });
      const {
        iconSize
      } = useIconSizes(props, () => props.prominent ? 44 : undefined);
      const {
        themeClasses
      } = provideTheme(props);
      const {
        colorClasses,
        colorStyles,
        variantClasses
      } = useVariant(() => ({
        color: props.color ?? props.type,
        variant: props.variant
      }));
      const {
        densityClasses
      } = useDensity(props);
      const {
        dimensionStyles
      } = useDimension(props);
      const {
        elevationClasses
      } = useElevation(props);
      const {
        locationStyles
      } = useLocation(props);
      const {
        positionClasses
      } = usePosition(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const {
        textColorClasses,
        textColorStyles
      } = useTextColor(() => props.borderColor);
      const {
        t
      } = useLocale();
      const closeProps = vue.toRef(() => ({
        'aria-label': t(props.closeLabel),
        onClick(e) {
          isActive.value = false;
          emit('click:close', e);
        }
      }));
      return () => {
        const hasPrepend = !!(slots.prepend || icon.value);
        const hasTitle = !!(slots.title || props.title);
        const hasClose = !!(slots.close || props.closable);
        const iconProps = {
          density: props.density,
          icon: icon.value,
          size: props.iconSize || props.prominent ? iconSize.value : undefined
        };
        return isActive.value && vue.createVNode(props.tag, {
          "class": vue.normalizeClass(['v-alert', props.border && {
            'v-alert--border': !!props.border,
            [`v-alert--border-${props.border === true ? 'start' : props.border}`]: true
          }, {
            'v-alert--prominent': props.prominent
          }, themeClasses.value, colorClasses.value, densityClasses.value, elevationClasses.value, positionClasses.value, roundedClasses.value, variantClasses.value, props.class]),
          "style": vue.normalizeStyle([colorStyles.value, dimensionStyles.value, locationStyles.value, roundedStyles.value, props.style]),
          "role": "alert"
        }, {
          default: () => [genOverlays(false, 'v-alert'), props.border && vue.createElementVNode("div", {
            "key": "border",
            "class": vue.normalizeClass(['v-alert__border', textColorClasses.value]),
            "style": vue.normalizeStyle(textColorStyles.value)
          }, null), hasPrepend && vue.createElementVNode("div", {
            "key": "prepend",
            "class": "v-alert__prepend"
          }, [!slots.prepend ? vue.createVNode(VIcon, vue.mergeProps({
            "key": "prepend-icon"
          }, iconProps), null) : vue.createVNode(VDefaultsProvider, {
            "key": "prepend-defaults",
            "disabled": !icon.value,
            "defaults": {
              VIcon: {
                ...iconProps
              }
            }
          }, slots.prepend)]), vue.createElementVNode("div", {
            "class": "v-alert__content"
          }, [hasTitle && vue.createVNode(VAlertTitle, {
            "key": "title"
          }, {
            default: () => [slots.title?.() ?? props.title]
          }), slots.text?.() ?? props.text, slots.default?.()]), slots.append && vue.createElementVNode("div", {
            "key": "append",
            "class": "v-alert__append"
          }, [slots.append()]), hasClose && vue.createElementVNode("div", {
            "key": "close",
            "class": "v-alert__close"
          }, [!slots.close ? vue.createVNode(VBtn, vue.mergeProps({
            "key": "close-btn",
            "icon": props.closeIcon,
            "size": "x-small",
            "variant": "text"
          }, closeProps.value), null) : vue.createVNode(VDefaultsProvider, {
            "key": "close-defaults",
            "defaults": {
              VBtn: {
                icon: props.closeIcon,
                size: 'x-small',
                variant: 'text'
              }
            }
          }, {
            default: () => [slots.close?.({
              props: closeProps.value
            })]
          })])]
        });
      };
    }
  });

  const makeVBadgeProps = propsFactory({
    bordered: Boolean,
    color: String,
    content: [Number, String],
    dot: Boolean,
    dotSize: [Number, String],
    floating: Boolean,
    icon: IconValue,
    inline: Boolean,
    label: {
      type: String,
      default: '$vuetify.badge'
    },
    max: [Number, String],
    modelValue: {
      type: Boolean,
      default: true
    },
    offsetX: [Number, String],
    offsetY: [Number, String],
    textColor: String,
    ...makeComponentProps(),
    ...makeLocationProps({
      location: 'top end'
    }),
    ...makeRoundedProps(),
    ...makeTagProps(),
    ...makeThemeProps(),
    ...makeTransitionProps({
      transition: 'scale-rotate-transition'
    }),
    ...makeDimensionProps()
  }, 'VBadge');
  const VBadge = genericComponent()({
    name: 'VBadge',
    inheritAttrs: false,
    props: makeVBadgeProps(),
    setup(props, ctx) {
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.color);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const {
        t
      } = useLocale();
      const {
        textColorClasses,
        textColorStyles
      } = useTextColor(() => props.textColor);
      const {
        themeClasses
      } = useTheme();
      const {
        locationStyles
      } = useLocation(props, true, side => {
        const base = props.floating ? props.dot ? 2 : 4 : props.dot ? Number(props.dotSize ?? 8) : 12;
        return base + (['top', 'bottom'].includes(side) ? Number(props.offsetY ?? 0) : ['left', 'right'].includes(side) ? Number(props.offsetX ?? 0) : 0);
      });
      const {
        dimensionStyles
      } = useDimension(props);
      useRender(() => {
        const value = Number(props.content);
        const content = !props.max || isNaN(value) ? props.content : value <= Number(props.max) ? value : `${props.max}+`;
        const [badgeAttrs, attrs] = pickWithRest(ctx.attrs, ['aria-atomic', 'aria-label', 'aria-live', 'role', 'title']);
        return vue.createVNode(props.tag, vue.mergeProps({
          "class": ['v-badge', {
            'v-badge--bordered': props.bordered,
            'v-badge--dot': props.dot,
            'v-badge--floating': props.floating,
            'v-badge--inline': props.inline
          }, props.class]
        }, attrs, {
          "style": props.style
        }), {
          default: () => [vue.createElementVNode("div", {
            "class": "v-badge__wrapper"
          }, [ctx.slots.default?.(), vue.createVNode(MaybeTransition, {
            "transition": props.transition
          }, {
            default: () => [vue.withDirectives(vue.createElementVNode("span", vue.mergeProps({
              "class": ['v-badge__badge', themeClasses.value, backgroundColorClasses.value, roundedClasses.value, textColorClasses.value],
              "style": [backgroundColorStyles.value, textColorStyles.value, dimensionStyles.value, props.inline ? {} : locationStyles.value, props.dot && props.dotSize ? {
                width: convertToUnit(props.dotSize),
                height: convertToUnit(props.dotSize)
              } : {}, roundedStyles.value],
              "aria-atomic": "true",
              "aria-label": t(props.label, value),
              "aria-live": "polite",
              "role": "status"
            }, badgeAttrs), [props.dot ? undefined : ctx.slots.badge ? ctx.slots.badge?.() : props.icon ? vue.createVNode(VIcon, {
              "icon": props.icon
            }, null) : content]), [[vue.vShow, props.modelValue]])]
          })])]
        });
      });
      return {};
    }
  });

  // Types

  const makeVAvatarProps = propsFactory({
    badge: {
      type: [Boolean, Object],
      default: false
    },
    start: Boolean,
    end: Boolean,
    icon: IconValue,
    image: String,
    text: String,
    ...makeBorderProps(),
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...makeRoundedProps(),
    ...makeSizeProps(),
    ...makeTagProps(),
    ...makeThemeProps(),
    ...makeVariantProps({
      variant: 'flat'
    })
  }, 'VAvatar');
  const VAvatar = genericComponent()({
    name: 'VAvatar',
    props: makeVAvatarProps(),
    setup(props, {
      slots
    }) {
      const {
        themeClasses
      } = provideTheme(props);
      const {
        borderClasses
      } = useBorder(props);
      const {
        colorClasses,
        colorStyles,
        variantClasses
      } = useVariant(props);
      const {
        densityClasses
      } = useDensity(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const {
        sizeClasses,
        sizeStyles
      } = useSize(props);
      const badgeDotSize = vue.computed(() => {
        switch (props.size) {
          case 'x-small':
            return 8;
          case 'small':
            return 10;
          case 'large':
            return 14;
          case 'x-large':
            return 16;
          default:
            return 12;
        }
      });
      const badgeOffset = vue.computed(() => {
        const {
          floating
        } = isObject(props.badge) ? props.badge : {};
        return (floating ? badgeDotSize.value / 2 : 0) - 1.5;
      });
      const badgeProps = vue.computed(() => {
        return {
          bordered: true,
          dot: !slots.badge,
          dotSize: badgeDotSize.value,
          offsetX: badgeOffset.value,
          offsetY: badgeOffset.value,
          color: typeof props.badge === 'string' ? props.badge : 'primary',
          ...(isObject(props.badge) ? props.badge : {})
        };
      });
      useRender(() => {
        const avatar = vue.createVNode(props.tag, {
          "class": vue.normalizeClass(['v-avatar', {
            'v-avatar--start': props.start,
            'v-avatar--end': props.end
          }, themeClasses.value, borderClasses.value, colorClasses.value, densityClasses.value, roundedClasses.value, sizeClasses.value, variantClasses.value, props.class]),
          "style": vue.normalizeStyle([colorStyles.value, sizeStyles.value, roundedStyles.value, props.style])
        }, {
          default: () => [!slots.default ? props.image ? vue.createVNode(VImg, {
            "key": "image",
            "src": props.image,
            "alt": "",
            "cover": true
          }, null) : props.icon ? vue.createVNode(VIcon, {
            "key": "icon",
            "icon": props.icon
          }, null) : props.text : vue.createVNode(VDefaultsProvider, {
            "key": "content-defaults",
            "defaults": {
              VImg: {
                cover: true,
                src: props.image
              },
              VIcon: {
                icon: props.icon
              }
            }
          }, {
            default: () => [slots.default()]
          }), genOverlays(false, 'v-avatar')]
        });
        return props.badge ? vue.createVNode(VBadge, badgeProps.value, {
          default: () => avatar,
          badge: slots.badge
        }) : avatar;
      });
      return {};
    }
  });

  const makeVLabelProps = propsFactory({
    text: String,
    onClick: EventProp(),
    ...makeComponentProps(),
    ...makeThemeProps()
  }, 'VLabel');
  const VLabel = genericComponent()({
    name: 'VLabel',
    props: makeVLabelProps(),
    setup(props, {
      slots
    }) {
      useRender(() => vue.createElementVNode("label", {
        "class": vue.normalizeClass(['v-label', {
          'v-label--clickable': !!props.onClick
        }, props.class]),
        "style": vue.normalizeStyle(props.style),
        "onClick": props.onClick
      }, [props.text, slots.default?.()]));
      return {};
    }
  });

  // Types

  const VSelectionControlGroupSymbol = Symbol.for('vuetify:selection-control-group');
  const makeSelectionControlGroupProps = propsFactory({
    color: String,
    disabled: {
      type: Boolean,
      default: null
    },
    defaultsTarget: String,
    error: Boolean,
    id: String,
    inline: Boolean,
    falseIcon: IconValue,
    trueIcon: IconValue,
    indeterminateIcon: IconValue,
    ripple: {
      type: [Boolean, Object],
      default: true
    },
    multiple: {
      type: Boolean,
      default: null
    },
    name: String,
    readonly: {
      type: Boolean,
      default: null
    },
    modelValue: null,
    type: String,
    valueComparator: {
      type: Function,
      default: deepEqual
    },
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...makeThemeProps()
  }, 'SelectionControlGroup');
  const makeVSelectionControlGroupProps = propsFactory({
    ...makeSelectionControlGroupProps({
      defaultsTarget: 'VSelectionControl'
    })
  }, 'VSelectionControlGroup');
  const VSelectionControlGroup = genericComponent()({
    name: 'VSelectionControlGroup',
    props: makeVSelectionControlGroupProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const modelValue = useProxiedModel(props, 'modelValue');
      const uid = vue.useId();
      const id = vue.toRef(() => props.id || `v-selection-control-group-${uid}`);
      const name = vue.toRef(() => props.name || id.value);
      const updateHandlers = new Set();
      vue.provide(VSelectionControlGroupSymbol, {
        modelValue,
        forceUpdate: () => {
          updateHandlers.forEach(fn => fn());
        },
        onForceUpdate: cb => {
          updateHandlers.add(cb);
          vue.onScopeDispose(() => {
            updateHandlers.delete(cb);
          });
        }
      });
      provideDefaults({
        [props.defaultsTarget]: {
          color: vue.toRef(() => props.color),
          disabled: vue.toRef(() => props.disabled),
          density: vue.toRef(() => props.density),
          error: vue.toRef(() => props.error),
          inline: vue.toRef(() => props.inline),
          modelValue,
          multiple: vue.toRef(() => !!props.multiple || props.multiple == null && Array.isArray(modelValue.value)),
          name,
          falseIcon: vue.toRef(() => props.falseIcon),
          trueIcon: vue.toRef(() => props.trueIcon),
          readonly: vue.toRef(() => props.readonly),
          ripple: vue.toRef(() => props.ripple),
          type: vue.toRef(() => props.type),
          valueComparator: vue.toRef(() => props.valueComparator)
        }
      });
      useRender(() => vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-selection-control-group', {
          'v-selection-control-group--inline': props.inline
        }, props.class]),
        "style": vue.normalizeStyle(props.style),
        "role": props.type === 'radio' ? 'radiogroup' : undefined
      }, [slots.default?.()]));
      return {};
    }
  });

  // Types

  const makeVSelectionControlProps = propsFactory({
    indeterminate: Boolean,
    label: String,
    baseColor: String,
    trueValue: null,
    falseValue: null,
    value: null,
    ...makeComponentProps(),
    ...makeSelectionControlGroupProps()
  }, 'VSelectionControl');
  function useSelectionControl(props) {
    const group = vue.inject(VSelectionControlGroupSymbol, undefined);
    const {
      densityClasses
    } = useDensity(props);
    const modelValue = useProxiedModel(props, 'modelValue');
    const trueValue = vue.computed(() => props.trueValue !== undefined ? props.trueValue : props.value !== undefined ? props.value : true);
    const falseValue = vue.computed(() => props.falseValue !== undefined ? props.falseValue : false);
    const isMultiple = vue.computed(() => !!props.multiple || props.multiple == null && Array.isArray(modelValue.value));
    const model = vue.computed({
      get() {
        const val = group ? group.modelValue.value : modelValue.value;
        return isMultiple.value ? wrapInArray(val).some(v => props.valueComparator(v, trueValue.value)) : props.valueComparator(val, trueValue.value);
      },
      set(val) {
        if (props.readonly) return;
        const currentValue = val ? trueValue.value : falseValue.value;
        let newVal = currentValue;
        if (isMultiple.value) {
          newVal = val ? [...wrapInArray(modelValue.value), currentValue] : wrapInArray(modelValue.value).filter(item => !props.valueComparator(item, trueValue.value));
        }
        if (group) {
          group.modelValue.value = newVal;
        } else {
          modelValue.value = newVal;
        }
      }
    });
    const isActive = vue.computed(() => model.value || props.indeterminate);
    const {
      textColorClasses,
      textColorStyles
    } = useTextColor(() => {
      if (props.error || props.disabled) return undefined;
      return isActive.value ? props.color : props.baseColor;
    });
    const {
      backgroundColorClasses,
      backgroundColorStyles
    } = useBackgroundColor(() => {
      return isActive.value && !props.error && !props.disabled ? props.color : props.baseColor;
    });
    const icon = vue.computed(() => props.indeterminate ? props.indeterminateIcon : model.value ? props.trueIcon : props.falseIcon);
    return {
      group,
      densityClasses,
      trueValue,
      falseValue,
      model,
      textColorClasses,
      textColorStyles,
      backgroundColorClasses,
      backgroundColorStyles,
      icon
    };
  }
  const VSelectionControl = genericComponent()({
    name: 'VSelectionControl',
    directives: {
      vRipple: Ripple
    },
    inheritAttrs: false,
    props: makeVSelectionControlProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      attrs,
      slots
    }) {
      const {
        group,
        densityClasses,
        icon,
        model,
        textColorClasses,
        textColorStyles,
        backgroundColorClasses,
        backgroundColorStyles,
        trueValue
      } = useSelectionControl(props);
      const uid = vue.useId();
      const isFocused = vue.shallowRef(false);
      const isFocusVisible = vue.shallowRef(false);
      const input = vue.ref();
      const id = vue.toRef(() => props.id || `input-${uid}`);
      const isInteractive = vue.toRef(() => !props.disabled && !props.readonly);
      group?.onForceUpdate(() => {
        if (input.value) {
          input.value.checked = model.value;
        }
      });
      function onFocus(e) {
        if (props.disabled) return;
        isFocused.value = true;
        if (matchesSelector(e.target, ':focus-visible') !== false) {
          isFocusVisible.value = true;
        }
      }
      function onBlur() {
        isFocused.value = false;
        isFocusVisible.value = false;
      }
      function onClickLabel(e) {
        e.stopPropagation();
      }
      function onInput(e) {
        if (!isInteractive.value) {
          if (input.value) {
            // model value is not updated when input is not interactive
            // but the internal checked state of the input is still updated,
            // so here its value is restored
            input.value.checked = model.value;
          }
          return;
        }
        if (props.readonly && group) {
          vue.nextTick(() => group.forceUpdate());
        }
        model.value = e.target.checked;
      }
      useRender(() => {
        const label = slots.label ? slots.label({
          label: props.label,
          props: {
            for: id.value
          }
        }) : props.label;
        const [rootAttrs, inputAttrs] = filterInputAttrs(attrs);
        const inputNode = vue.createElementVNode("input", vue.mergeProps({
          "ref": input,
          "checked": model.value,
          "disabled": !!props.disabled,
          "id": id.value,
          "onBlur": onBlur,
          "onFocus": onFocus,
          "onInput": onInput,
          "aria-disabled": !!props.disabled,
          "aria-label": props.label,
          "type": props.type,
          "value": trueValue.value,
          "name": props.name,
          "aria-checked": props.type === 'checkbox' ? model.value : undefined
        }, inputAttrs), null);
        return vue.createElementVNode("div", vue.mergeProps({
          "class": ['v-selection-control', {
            'v-selection-control--dirty': model.value,
            'v-selection-control--indeterminate': props.indeterminate,
            'v-selection-control--disabled': props.disabled,
            'v-selection-control--error': props.error,
            'v-selection-control--focused': isFocused.value,
            'v-selection-control--focus-visible': isFocusVisible.value,
            'v-selection-control--inline': props.inline
          }, densityClasses.value, props.class]
        }, rootAttrs, {
          "style": props.style
        }), [vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-selection-control__wrapper', textColorClasses.value]),
          "style": vue.normalizeStyle(textColorStyles.value)
        }, [slots.default?.({
          backgroundColorClasses,
          backgroundColorStyles
        }), vue.withDirectives(vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-selection-control__input'])
        }, [slots.input?.({
          model,
          textColorClasses,
          textColorStyles,
          backgroundColorClasses,
          backgroundColorStyles,
          inputNode,
          icon: icon.value,
          props: {
            onFocus,
            onBlur,
            id: id.value
          }
        }) ?? vue.createElementVNode(vue.Fragment, null, [icon.value && vue.createVNode(VIcon, {
          "key": "icon",
          "icon": icon.value
        }, null), inputNode])]), [[Ripple, !props.disabled && !props.readonly && props.ripple, null, {
          center: true,
          circle: true
        }]])]), label && vue.createVNode(VLabel, {
          "for": id.value,
          "onClick": onClickLabel
        }, {
          default: () => [label]
        })]);
      });
      return {
        isFocused,
        input
      };
    }
  });

  // Types

  const makeVCheckboxBtnProps = propsFactory({
    ...makeVSelectionControlProps({
      falseIcon: '$checkboxOff',
      trueIcon: '$checkboxOn',
      indeterminateIcon: '$checkboxIndeterminate'
    })
  }, 'VCheckboxBtn');
  const VCheckboxBtn = genericComponent()({
    name: 'VCheckboxBtn',
    props: makeVCheckboxBtnProps(),
    emits: {
      'update:modelValue': value => true,
      'update:indeterminate': value => true
    },
    setup(props, {
      slots
    }) {
      const indeterminate = useProxiedModel(props, 'indeterminate');
      const model = useProxiedModel(props, 'modelValue');
      function onChange(v) {
        if (indeterminate.value) {
          indeterminate.value = false;
        }
      }
      useRender(() => {
        const controlProps = omit(VSelectionControl.filterProps(props), ['modelValue']);
        return vue.createVNode(VSelectionControl, vue.mergeProps(controlProps, {
          "modelValue": model.value,
          "onUpdate:modelValue": [$event => model.value = $event, onChange],
          "class": ['v-checkbox-btn', props.class],
          "style": props.style,
          "type": "checkbox",
          "aria-checked": indeterminate.value ? 'mixed' : undefined
        }), slots);
      });
      return {};
    }
  });

  // Types

  function useInputIcon(props) {
    const {
      t
    } = useLocale();
    function InputIcon({
      name,
      color,
      ...attrs
    }) {
      const localeKey = {
        prepend: 'prependAction',
        prependInner: 'prependAction',
        append: 'appendAction',
        appendInner: 'appendAction',
        clear: 'clear'
      }[name];
      const listener = props[`onClick:${name}`];
      function onKeydown(e) {
        if (e.key !== 'Enter' && e.key !== ' ') return;
        e.preventDefault();
        e.stopPropagation();
        callEvent(listener, new PointerEvent('click', e));
      }
      const label = listener && localeKey ? t(`$vuetify.input.${localeKey}`, props.label ?? '') : undefined;
      return vue.createVNode(VIcon, vue.mergeProps({
        "icon": props[`${name}Icon`],
        "aria-label": label,
        "onClick": listener,
        "onKeydown": onKeydown,
        "color": color
      }, attrs), null);
    }
    return {
      InputIcon
    };
  }

  // Types

  const makeVMessagesProps = propsFactory({
    active: Boolean,
    color: String,
    messages: {
      type: [Array, String],
      default: () => []
    },
    ...makeComponentProps(),
    ...makeTransitionProps({
      transition: {
        component: VSlideYTransition,
        leaveAbsolute: true,
        group: true
      }
    })
  }, 'VMessages');
  const VMessages = genericComponent()({
    name: 'VMessages',
    props: makeVMessagesProps(),
    setup(props, {
      slots
    }) {
      const messages = vue.computed(() => wrapInArray(props.messages));
      const {
        textColorClasses,
        textColorStyles
      } = useTextColor(() => props.color);
      useRender(() => vue.createVNode(MaybeTransition, {
        "transition": props.transition,
        "tag": "div",
        "class": vue.normalizeClass(['v-messages', textColorClasses.value, props.class]),
        "style": vue.normalizeStyle([textColorStyles.value, props.style])
      }, {
        default: () => [props.active && messages.value.map((message, i) => vue.createElementVNode("div", {
          "class": "v-messages__message",
          "key": `${i}-${messages.value}`
        }, [slots.message ? slots.message({
          message
        }) : message]))]
      }));
      return {};
    }
  });

  // Composables

  // Types

  // Composables
  const makeFocusProps = propsFactory({
    focused: Boolean,
    'onUpdate:focused': EventProp()
  }, 'focus');
  function useFocus(props, name = getCurrentInstanceName()) {
    const isFocused = useProxiedModel(props, 'focused');
    const focusClasses = vue.toRef(() => {
      return {
        [`${name}--focused`]: isFocused.value
      };
    });
    function focus() {
      isFocused.value = true;
    }
    function blur() {
      isFocused.value = false;
    }
    return {
      focusClasses,
      isFocused,
      focus,
      blur
    };
  }

  // Composables

  // Types

  const FormKey = Symbol.for('vuetify:form');
  const makeFormProps = propsFactory({
    disabled: Boolean,
    fastFail: Boolean,
    readonly: Boolean,
    modelValue: {
      type: Boolean,
      default: null
    },
    validateOn: {
      type: String,
      default: 'input'
    }
  }, 'form');
  function createForm(props) {
    const model = useProxiedModel(props, 'modelValue');
    const isDisabled = vue.toRef(() => props.disabled);
    const isReadonly = vue.toRef(() => props.readonly);
    const isValidating = vue.shallowRef(false);
    const items = vue.ref([]);
    const errors = vue.ref([]);
    async function validate() {
      const results = [];
      let valid = true;
      errors.value = [];
      isValidating.value = true;
      for (const item of items.value) {
        const itemErrorMessages = await item.validate();
        if (itemErrorMessages.length > 0) {
          valid = false;
          results.push({
            id: item.id,
            errorMessages: itemErrorMessages
          });
        }
        if (!valid && props.fastFail) break;
      }
      errors.value = results;
      isValidating.value = false;
      return {
        valid,
        errors: errors.value
      };
    }
    function reset() {
      items.value.forEach(item => item.reset());
    }
    function resetValidation() {
      items.value.forEach(item => item.resetValidation());
    }
    vue.watch(items, () => {
      let valid = 0;
      let invalid = 0;
      const results = [];
      for (const item of items.value) {
        if (item.isValid === false) {
          invalid++;
          results.push({
            id: item.id,
            errorMessages: item.errorMessages
          });
        } else if (item.isValid === true) valid++;
      }
      errors.value = results;
      model.value = invalid > 0 ? false : valid === items.value.length ? true : null;
    }, {
      deep: true,
      flush: 'post'
    });
    vue.provide(FormKey, {
      register: ({
        id,
        vm,
        validate,
        reset,
        resetValidation
      }) => {
        if (items.value.some(item => item.id === id)) {
          consoleWarn(`Duplicate input name "${id}"`);
        }
        items.value.push({
          id,
          validate,
          reset,
          resetValidation,
          vm: vue.markRaw(vm),
          isValid: null,
          errorMessages: []
        });
      },
      unregister: id => {
        items.value = items.value.filter(item => {
          return item.id !== id;
        });
      },
      update: (id, isValid, errorMessages) => {
        const found = items.value.find(item => item.id === id);
        if (!found) return;
        found.isValid = isValid;
        found.errorMessages = errorMessages;
      },
      isDisabled,
      isReadonly,
      isValidating,
      isValid: model,
      items,
      validateOn: vue.toRef(() => props.validateOn)
    });
    return {
      errors,
      isDisabled,
      isReadonly,
      isValidating,
      isValid: model,
      items,
      validate,
      reset,
      resetValidation
    };
  }
  function useForm(props) {
    const form = vue.inject(FormKey, null);
    return {
      ...form,
      isReadonly: vue.computed(() => !!(props?.readonly ?? form?.isReadonly.value)),
      isDisabled: vue.computed(() => !!(props?.disabled ?? form?.isDisabled.value))
    };
  }

  // Utilities
  const RulesSymbol = Symbol.for('vuetify:rules');
  function useRules(fn) {
    const rules = vue.inject(RulesSymbol, null);
    if (!fn) {
      if (!rules) {
        throw new Error('Could not find Vuetify rules injection');
      }
      return rules.aliases;
    }
    return rules?.resolve(fn) ?? vue.toRef(fn);
  }

  // Composables

  // Types

  const makeValidationProps = propsFactory({
    disabled: {
      type: Boolean,
      default: null
    },
    error: Boolean,
    errorMessages: {
      type: [Array, String],
      default: () => []
    },
    maxErrors: {
      type: [Number, String],
      default: 1
    },
    name: String,
    label: String,
    readonly: {
      type: Boolean,
      default: null
    },
    rules: {
      type: Array,
      default: () => []
    },
    modelValue: null,
    validateOn: String,
    validationValue: null,
    ...makeFocusProps()
  }, 'validation');
  function useValidation(props, name = getCurrentInstanceName(), id = vue.useId()) {
    const model = useProxiedModel(props, 'modelValue');
    const validationModel = vue.computed(() => props.validationValue === undefined ? model.value : props.validationValue);
    const form = useForm(props);
    const rules = useRules(() => props.rules);
    const internalErrorMessages = vue.ref([]);
    const isPristine = vue.shallowRef(true);
    const isDirty = vue.computed(() => !!(wrapInArray(model.value === '' ? null : model.value).length || wrapInArray(validationModel.value === '' ? null : validationModel.value).length));
    const errorMessages = vue.computed(() => {
      return props.errorMessages?.length ? wrapInArray(props.errorMessages).concat(internalErrorMessages.value).slice(0, Math.max(0, Number(props.maxErrors))) : internalErrorMessages.value;
    });
    const validateOn = vue.computed(() => {
      let value = (props.validateOn ?? form.validateOn?.value) || 'input';
      if (value === 'lazy') value = 'input lazy';
      if (value === 'eager') value = 'input eager';
      const set = new Set(value?.split(' ') ?? []);
      return {
        input: set.has('input'),
        blur: set.has('blur') || set.has('input') || set.has('invalid-input'),
        invalidInput: set.has('invalid-input'),
        lazy: set.has('lazy'),
        eager: set.has('eager')
      };
    });
    const isValid = vue.computed(() => {
      if (props.error || props.errorMessages?.length) return false;
      if (!props.rules.length) return true;
      if (isPristine.value) {
        return internalErrorMessages.value.length || validateOn.value.lazy ? null : true;
      } else {
        return !internalErrorMessages.value.length;
      }
    });
    const isValidating = vue.shallowRef(false);
    let isResetting = false;
    const validationClasses = vue.computed(() => {
      return {
        [`${name}--error`]: isValid.value === false,
        [`${name}--dirty`]: isDirty.value,
        [`${name}--disabled`]: form.isDisabled.value,
        [`${name}--readonly`]: form.isReadonly.value
      };
    });
    const vm = getCurrentInstance('validation');
    const uid = vue.computed(() => props.name ?? vue.unref(id));
    vue.onBeforeMount(() => {
      form.register?.({
        id: uid.value,
        vm,
        validate,
        reset,
        resetValidation
      });
    });
    vue.onBeforeUnmount(() => {
      form.unregister?.(uid.value);
    });
    vue.onMounted(async () => {
      if (!validateOn.value.lazy) {
        await validate(!validateOn.value.eager);
      }
      form.update?.(uid.value, isValid.value, errorMessages.value);
    });
    useToggleScope(() => validateOn.value.input || validateOn.value.invalidInput && isValid.value === false, () => {
      vue.watch(validationModel, () => {
        if (!isResetting) validate();
      });
    });
    useToggleScope(() => validateOn.value.blur, () => {
      vue.watch(() => props.focused, val => {
        if (!val) validate();
      });
    });
    vue.watch([isValid, errorMessages], () => {
      form.update?.(uid.value, isValid.value, errorMessages.value);
    });
    async function reset() {
      isResetting = true;
      model.value = null;
      await vue.nextTick();
      isResetting = false;
      await resetValidation();
    }
    async function resetValidation() {
      isPristine.value = true;
      if (!validateOn.value.lazy) {
        await validate(!validateOn.value.eager);
      } else {
        internalErrorMessages.value = [];
      }
    }
    async function validate(silent = false) {
      const results = [];
      isValidating.value = true;
      for (const rule of rules.value) {
        if (results.length >= Number(props.maxErrors ?? 1)) {
          break;
        }
        const handler = typeof rule === 'function' ? rule : () => rule;
        const result = await handler(validationModel.value);
        if (result === true) continue;
        if (result !== false && typeof result !== 'string') {
          // eslint-disable-next-line no-console
          console.warn(`${result} is not a valid value. Rule functions must return boolean true or a string.`);
          continue;
        }
        results.push(result || '');
      }
      internalErrorMessages.value = results;
      isValidating.value = false;
      isPristine.value = silent;
      return internalErrorMessages.value;
    }
    return {
      errorMessages,
      isDirty,
      isDisabled: form.isDisabled,
      isReadonly: form.isReadonly,
      isPristine,
      isValid,
      isValidating,
      reset,
      resetValidation,
      validate,
      validationClasses
    };
  }

  // Types

  const makeVInputProps = propsFactory({
    id: String,
    appendIcon: IconValue,
    baseColor: String,
    centerAffix: {
      type: Boolean,
      default: true
    },
    color: String,
    glow: Boolean,
    iconColor: [Boolean, String],
    prependIcon: IconValue,
    hideDetails: [Boolean, String],
    hideSpinButtons: Boolean,
    hint: String,
    indentDetails: {
      type: Boolean,
      default: null
    },
    persistentHint: Boolean,
    messages: {
      type: [Array, String],
      default: () => []
    },
    direction: {
      type: String,
      default: 'horizontal',
      validator: v => ['horizontal', 'vertical'].includes(v)
    },
    'onClick:prepend': EventProp(),
    'onClick:append': EventProp(),
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...pick(makeDimensionProps(), ['maxWidth', 'minWidth', 'width']),
    ...makeThemeProps(),
    ...makeValidationProps()
  }, 'VInput');
  const VInput = genericComponent()({
    name: 'VInput',
    props: {
      ...makeVInputProps()
    },
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      attrs,
      slots,
      emit
    }) {
      const {
        densityClasses
      } = useDensity(props);
      const {
        dimensionStyles
      } = useDimension(props);
      const {
        themeClasses
      } = provideTheme(props);
      const {
        rtlClasses
      } = useRtl();
      const {
        InputIcon
      } = useInputIcon(props);
      const uid = vue.useId();
      const id = vue.computed(() => props.id || `input-${uid}`);
      const {
        errorMessages,
        isDirty,
        isDisabled,
        isReadonly,
        isPristine,
        isValid,
        isValidating,
        reset,
        resetValidation,
        validate,
        validationClasses
      } = useValidation(props, 'v-input', id);
      const messages = vue.computed(() => {
        if (props.errorMessages?.length || !isPristine.value && errorMessages.value.length) {
          return errorMessages.value;
        } else if (props.hint && (props.persistentHint || props.focused)) {
          return props.hint;
        } else {
          return props.messages;
        }
      });
      const hasMessages = vue.toRef(() => messages.value.length > 0);
      const hasDetails = vue.toRef(() => !props.hideDetails || props.hideDetails === 'auto' && (hasMessages.value || !!slots.details));
      const messagesId = vue.computed(() => hasDetails.value ? `${id.value}-messages` : undefined);
      const slotProps = vue.computed(() => ({
        id,
        messagesId,
        isDirty,
        isDisabled,
        isReadonly,
        isPristine,
        isValid,
        isValidating,
        hasDetails,
        reset,
        resetValidation,
        validate
      }));
      const color = vue.toRef(() => {
        return props.error || props.disabled ? undefined : props.focused ? props.color : props.baseColor;
      });
      const iconColor = vue.toRef(() => {
        if (!props.iconColor) return undefined;
        return props.iconColor === true ? color.value : props.iconColor;
      });
      useRender(() => {
        const hasPrepend = !!(slots.prepend || props.prependIcon);
        const hasAppend = !!(slots.append || props.appendIcon);
        return vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-input', `v-input--${props.direction}`, {
            'v-input--center-affix': props.centerAffix,
            'v-input--focused': props.focused,
            'v-input--glow': props.glow,
            'v-input--hide-spin-buttons': props.hideSpinButtons,
            'v-input--indent-details': props.indentDetails
          }, densityClasses.value, themeClasses.value, rtlClasses.value, validationClasses.value, props.class]),
          "style": vue.normalizeStyle([dimensionStyles.value, props.style])
        }, [hasPrepend && vue.createElementVNode("div", {
          "key": "prepend",
          "class": "v-input__prepend"
        }, [slots.prepend ? slots.prepend(slotProps.value) : props.prependIcon && vue.createVNode(InputIcon, {
          "key": "prepend-icon",
          "name": "prepend",
          "color": iconColor.value
        }, null)]), slots.default && vue.createElementVNode("div", {
          "class": "v-input__control"
        }, [slots.default?.(slotProps.value)]), hasAppend && vue.createElementVNode("div", {
          "key": "append",
          "class": "v-input__append"
        }, [slots.append ? slots.append(slotProps.value) : props.appendIcon && vue.createVNode(InputIcon, {
          "key": "append-icon",
          "name": "append",
          "color": iconColor.value
        }, null)]), hasDetails.value && vue.createElementVNode("div", {
          "id": messagesId.value,
          "class": "v-input__details",
          "role": "alert",
          "aria-live": "polite"
        }, [vue.createVNode(VMessages, {
          "active": hasMessages.value,
          "messages": messages.value
        }, {
          message: slots.message
        }), slots.details?.(slotProps.value)])]);
      });
      return {
        reset,
        resetValidation,
        validate,
        isValid,
        errorMessages
      };
    }
  });

  // Types

  const Refs = Symbol('Forwarded refs');

  /** Omit properties starting with P */

  /** Omit keyof $props from T */

  function getDescriptor(obj, key) {
    let currentObj = obj;
    while (currentObj) {
      const descriptor = Reflect.getOwnPropertyDescriptor(currentObj, key);
      if (descriptor) return descriptor;
      currentObj = Object.getPrototypeOf(currentObj);
    }
    return undefined;
  }
  function forwardRefs(target, ...refs) {
    target[Refs] = refs;
    return new Proxy(target, {
      get(target, key) {
        if (Reflect.has(target, key)) {
          return Reflect.get(target, key);
        }

        // Skip internal properties
        if (typeof key === 'symbol' || key.startsWith('$') || key.startsWith('__')) return;
        for (const ref of refs) {
          if (ref.value && Reflect.has(ref.value, key)) {
            const val = Reflect.get(ref.value, key);
            return typeof val === 'function' ? val.bind(ref.value) : val;
          }
        }
      },
      has(target, key) {
        if (Reflect.has(target, key)) {
          return true;
        }

        // Skip internal properties
        if (typeof key === 'symbol' || key.startsWith('$') || key.startsWith('__')) return false;
        for (const ref of refs) {
          if (ref.value && Reflect.has(ref.value, key)) {
            return true;
          }
        }
        return false;
      },
      set(target, key, value) {
        if (Reflect.has(target, key)) {
          return Reflect.set(target, key, value);
        }

        // Skip internal properties
        if (typeof key === 'symbol' || key.startsWith('$') || key.startsWith('__')) return false;
        for (const ref of refs) {
          if (ref.value && Reflect.has(ref.value, key)) {
            return Reflect.set(ref.value, key, value);
          }
        }
        return false;
      },
      getOwnPropertyDescriptor(target, key) {
        const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
        if (descriptor) return descriptor;

        // Skip internal properties
        if (typeof key === 'symbol' || key.startsWith('$') || key.startsWith('__')) return;

        // Check each ref's own properties
        for (const ref of refs) {
          if (!ref.value) continue;
          const descriptor = getDescriptor(ref.value, key) ?? ('_' in ref.value ? getDescriptor(ref.value._?.setupState, key) : undefined);
          if (descriptor) return descriptor;
        }

        // Recursive search up each ref's prototype
        for (const ref of refs) {
          const childRefs = ref.value && ref.value[Refs];
          if (!childRefs) continue;
          const queue = childRefs.slice();
          while (queue.length) {
            const ref = queue.shift();
            const descriptor = getDescriptor(ref.value, key);
            if (descriptor) return descriptor;
            const childRefs = ref.value && ref.value[Refs];
            if (childRefs) queue.push(...childRefs);
          }
        }
        return undefined;
      }
    });
  }

  // Types

  const makeVCheckboxProps = propsFactory({
    ...omit(makeVInputProps(), ['direction', 'glow']),
    ...omit(makeVCheckboxBtnProps(), ['inline'])
  }, 'VCheckbox');
  const VCheckbox = genericComponent()({
    name: 'VCheckbox',
    inheritAttrs: false,
    props: makeVCheckboxProps(),
    emits: {
      'update:modelValue': value => true,
      'update:focused': focused => true
    },
    setup(props, {
      attrs,
      slots
    }) {
      const model = useProxiedModel(props, 'modelValue');
      const {
        isFocused,
        focus,
        blur
      } = useFocus(props);
      const inputRef = vue.ref();
      const uid = vue.useId();
      useRender(() => {
        const [rootAttrs, controlAttrs] = filterInputAttrs(attrs);
        const inputProps = VInput.filterProps(props);
        const checkboxProps = VCheckboxBtn.filterProps(props);
        return vue.createVNode(VInput, vue.mergeProps({
          "ref": inputRef,
          "class": ['v-checkbox', props.class]
        }, rootAttrs, inputProps, {
          "modelValue": model.value,
          "onUpdate:modelValue": $event => model.value = $event,
          "id": props.id || `checkbox-${uid}`,
          "focused": isFocused.value,
          "style": props.style
        }), {
          ...slots,
          default: ({
            id,
            messagesId,
            isDisabled,
            isReadonly,
            isValid
          }) => vue.createVNode(VCheckboxBtn, vue.mergeProps(checkboxProps, {
            "id": id.value,
            "aria-describedby": messagesId.value,
            "disabled": isDisabled.value,
            "readonly": isReadonly.value
          }, controlAttrs, {
            "error": isValid.value === false,
            "modelValue": model.value,
            "onUpdate:modelValue": $event => model.value = $event,
            "onFocus": focus,
            "onBlur": blur
          }), slots)
        });
      });
      return forwardRefs({}, inputRef);
    }
  });

  // Utilities

  // Types

  const breakpoints = ['sm', 'md', 'lg', 'xl', 'xxl']; // no xs

  const DisplaySymbol = Symbol.for('vuetify:display');
  const defaultDisplayOptions = {
    mobileBreakpoint: 'lg',
    thresholds: {
      xs: 0,
      sm: 600,
      md: 840,
      lg: 1145,
      xl: 1545,
      xxl: 2138
    }
  };
  const parseDisplayOptions = (options = defaultDisplayOptions) => {
    return mergeDeep(defaultDisplayOptions, options);
  };
  function getClientWidth(ssr) {
    return IN_BROWSER && !ssr ? window.innerWidth : typeof ssr === 'object' && ssr.clientWidth || 0;
  }
  function getClientHeight(ssr) {
    return IN_BROWSER && !ssr ? window.innerHeight : typeof ssr === 'object' && ssr.clientHeight || 0;
  }
  function getPlatform(ssr) {
    const userAgent = IN_BROWSER && !ssr ? window.navigator.userAgent : 'ssr';
    function match(regexp) {
      return Boolean(userAgent.match(regexp));
    }
    const android = match(/android/i);
    const ios = match(/iphone|ipad|ipod/i);
    const cordova = match(/cordova/i);
    const electron = match(/electron/i);
    const chrome = match(/chrome/i);
    const edge = match(/edge/i);
    const firefox = match(/firefox/i);
    const opera = match(/opera/i);
    const win = match(/win/i);
    const mac = match(/mac/i);
    const linux = match(/linux/i);
    return {
      android,
      ios,
      cordova,
      electron,
      chrome,
      edge,
      firefox,
      opera,
      win,
      mac,
      linux,
      touch: SUPPORTS_TOUCH,
      ssr: userAgent === 'ssr'
    };
  }
  function createDisplay(options, ssr) {
    const {
      thresholds,
      mobileBreakpoint
    } = parseDisplayOptions(options);
    const height = vue.shallowRef(getClientHeight(ssr));
    const platform = vue.shallowRef(getPlatform(ssr));
    const state = vue.reactive({});
    const width = vue.shallowRef(getClientWidth(ssr));
    function updateSize() {
      height.value = getClientHeight();
      width.value = getClientWidth();
    }
    function update() {
      updateSize();
      platform.value = getPlatform();
    }

    // eslint-disable-next-line max-statements
    vue.watchEffect(() => {
      const xs = width.value < thresholds.sm;
      const sm = width.value < thresholds.md && !xs;
      const md = width.value < thresholds.lg && !(sm || xs);
      const lg = width.value < thresholds.xl && !(md || sm || xs);
      const xl = width.value < thresholds.xxl && !(lg || md || sm || xs);
      const xxl = width.value >= thresholds.xxl;
      const name = xs ? 'xs' : sm ? 'sm' : md ? 'md' : lg ? 'lg' : xl ? 'xl' : 'xxl';
      const breakpointValue = typeof mobileBreakpoint === 'number' ? mobileBreakpoint : thresholds[mobileBreakpoint];
      const mobile = width.value < breakpointValue;
      state.xs = xs;
      state.sm = sm;
      state.md = md;
      state.lg = lg;
      state.xl = xl;
      state.xxl = xxl;
      state.smAndUp = !xs;
      state.mdAndUp = !(xs || sm);
      state.lgAndUp = !(xs || sm || md);
      state.xlAndUp = !(xs || sm || md || lg);
      state.smAndDown = !(md || lg || xl || xxl);
      state.mdAndDown = !(lg || xl || xxl);
      state.lgAndDown = !(xl || xxl);
      state.xlAndDown = !xxl;
      state.name = name;
      state.height = height.value;
      state.width = width.value;
      state.mobile = mobile;
      state.mobileBreakpoint = mobileBreakpoint;
      state.platform = platform.value;
      state.thresholds = thresholds;
    });
    if (IN_BROWSER) {
      window.addEventListener('resize', updateSize, {
        passive: true
      });
      vue.onScopeDispose(() => {
        window.removeEventListener('resize', updateSize);
      }, true);
    }
    return {
      ...vue.toRefs(state),
      update,
      ssr: !!ssr
    };
  }
  const makeDisplayProps = propsFactory({
    mobile: {
      type: Boolean,
      default: false
    },
    mobileBreakpoint: [Number, String]
  }, 'display');
  function useDisplay(props = {
    mobile: null
  }, name = getCurrentInstanceName()) {
    const display = vue.inject(DisplaySymbol);
    if (!display) throw new Error('Could not find Vuetify display injection');
    const mobile = vue.computed(() => {
      if (props.mobile) {
        return true;
      } else if (typeof props.mobileBreakpoint === 'number') {
        return display.width.value < props.mobileBreakpoint;
      } else if (props.mobileBreakpoint) {
        return display.width.value < display.thresholds.value[props.mobileBreakpoint];
      } else if (props.mobile === null) {
        return display.mobile.value;
      } else {
        return false;
      }
    });
    const displayClasses = vue.toRef(() => {
      if (!name) return {};
      return {
        [`${name}--mobile`]: mobile.value
      };
    });
    return {
      ...display,
      displayClasses,
      mobile
    };
  }

  // Utilities

  // Types

  const GoToSymbol = Symbol.for('vuetify:goto');
  function genDefaults$1() {
    return {
      container: undefined,
      duration: 300,
      layout: false,
      offset: 0,
      easing: 'easeInOutCubic',
      patterns: easingPatterns
    };
  }
  function getContainer(el) {
    return getTarget$1(el) ?? (document.scrollingElement || document.body);
  }
  function getTarget$1(el) {
    return typeof el === 'string' ? document.querySelector(el) : refElement(el);
  }
  function getOffset$2(target, horizontal, rtl) {
    if (typeof target === 'number') return horizontal && rtl ? -target : target;
    let el = getTarget$1(target);
    let totalOffset = 0;
    while (el) {
      totalOffset += horizontal ? el.offsetLeft : el.offsetTop;
      el = el.offsetParent;
    }
    return totalOffset;
  }
  function createGoTo(options, locale) {
    return {
      rtl: locale.isRtl,
      options: mergeDeep(genDefaults$1(), options)
    };
  }
  async function scrollTo(_target, _options, horizontal, goTo) {
    const property = horizontal ? 'scrollLeft' : 'scrollTop';
    const options = mergeDeep(goTo?.options ?? genDefaults$1(), _options);
    const rtl = goTo?.rtl.value;
    const target = (typeof _target === 'number' ? _target : getTarget$1(_target)) ?? 0;
    const container = options.container === 'parent' && target instanceof HTMLElement ? target.parentElement : getContainer(options.container);
    const ease = PREFERS_REDUCED_MOTION() ? options.patterns.instant : typeof options.easing === 'function' ? options.easing : options.patterns[options.easing];
    if (!ease) throw new TypeError(`Easing function "${options.easing}" not found.`);
    let targetLocation;
    if (typeof target === 'number') {
      targetLocation = getOffset$2(target, horizontal, rtl);
    } else {
      targetLocation = getOffset$2(target, horizontal, rtl) - getOffset$2(container, horizontal, rtl);
      if (options.layout) {
        const styles = window.getComputedStyle(target);
        const layoutOffset = styles.getPropertyValue('--v-layout-top');
        if (layoutOffset) targetLocation -= parseInt(layoutOffset, 10);
      }
    }
    targetLocation += options.offset;
    targetLocation = clampTarget(container, targetLocation, !!rtl, !!horizontal);
    const startLocation = container[property] ?? 0;
    if (targetLocation === startLocation) return Promise.resolve(targetLocation);
    const startTime = performance.now();
    return new Promise(resolve => requestAnimationFrame(function step(currentTime) {
      const timeElapsed = currentTime - startTime;
      const progress = timeElapsed / options.duration;
      const location = Math.floor(startLocation + (targetLocation - startLocation) * ease(clamp(progress, 0, 1)));
      container[property] = location;

      // Allow for some jitter if target time has elapsed
      if (progress >= 1 && Math.abs(location - container[property]) < 10) {
        return resolve(targetLocation);
      } else if (progress > 2) {
        // The target might not be reachable
        consoleWarn('Scroll target is not reachable');
        return resolve(container[property]);
      }
      requestAnimationFrame(step);
    }));
  }
  function useGoTo(_options = {}) {
    const goToInstance = vue.inject(GoToSymbol);
    const {
      isRtl
    } = useRtl();
    if (!goToInstance) throw new Error('[Vuetify] Could not find injected goto instance');
    const goTo = {
      ...goToInstance,
      // can be set via VLocaleProvider
      rtl: vue.toRef(() => goToInstance.rtl.value || isRtl.value)
    };
    async function go(target, options) {
      return scrollTo(target, mergeDeep(_options, options), false, goTo);
    }
    go.horizontal = async (target, options) => {
      return scrollTo(target, mergeDeep(_options, options), true, goTo);
    };
    return go;
  }

  /**
   * Clamp target value to achieve a smooth scroll animation
   * when the value goes outside the scroll container size
   */
  function clampTarget(container, value, rtl, horizontal) {
    const {
      scrollWidth,
      scrollHeight
    } = container;
    const [containerWidth, containerHeight] = container === document.scrollingElement ? [window.innerWidth, window.innerHeight] : [container.offsetWidth, container.offsetHeight];
    let min;
    let max;
    if (horizontal) {
      if (rtl) {
        min = -(scrollWidth - containerWidth);
        max = 0;
      } else {
        min = 0;
        max = scrollWidth - containerWidth;
      }
    } else {
      min = 0;
      max = scrollHeight + -containerHeight;
    }
    return clamp(value, min, max);
  }

  function calculateUpdatedTarget({
    selectedElement,
    containerElement,
    isRtl,
    isHorizontal
  }) {
    const containerSize = getOffsetSize(isHorizontal, containerElement);
    const scrollPosition = getScrollPosition(isHorizontal, isRtl, containerElement);
    const childrenSize = getOffsetSize(isHorizontal, selectedElement);
    const childrenStartPosition = getOffsetPosition(isHorizontal, selectedElement);
    const additionalOffset = childrenSize * 0.4;
    if (scrollPosition > childrenStartPosition) {
      return childrenStartPosition - additionalOffset;
    } else if (scrollPosition + containerSize < childrenStartPosition + childrenSize) {
      return childrenStartPosition - containerSize + childrenSize + additionalOffset;
    }
    return scrollPosition;
  }
  function calculateCenteredTarget({
    selectedElement,
    containerElement,
    isHorizontal
  }) {
    const containerOffsetSize = getOffsetSize(isHorizontal, containerElement);
    const childrenOffsetPosition = getOffsetPosition(isHorizontal, selectedElement);
    const childrenOffsetSize = getOffsetSize(isHorizontal, selectedElement);
    return childrenOffsetPosition - containerOffsetSize / 2 + childrenOffsetSize / 2;
  }
  function getScrollSize(isHorizontal, element) {
    const key = isHorizontal ? 'scrollWidth' : 'scrollHeight';
    return element?.[key] || 0;
  }
  function getScrollPosition(isHorizontal, rtl, element) {
    if (!element) {
      return 0;
    }
    const {
      scrollLeft,
      offsetWidth,
      scrollWidth
    } = element;
    if (isHorizontal) {
      return rtl ? scrollWidth - offsetWidth + scrollLeft : scrollLeft;
    }
    return element.scrollTop;
  }
  function getOffsetSize(isHorizontal, element) {
    const key = isHorizontal ? 'offsetWidth' : 'offsetHeight';
    return element?.[key] || 0;
  }
  function getOffsetPosition(isHorizontal, element) {
    const key = isHorizontal ? 'offsetLeft' : 'offsetTop';
    return element?.[key] || 0;
  }

  // Types

  const VSlideGroupSymbol = Symbol.for('vuetify:v-slide-group');
  const makeVSlideGroupProps = propsFactory({
    centerActive: Boolean,
    scrollToActive: {
      type: Boolean,
      default: true
    },
    contentClass: null,
    direction: {
      type: String,
      default: 'horizontal'
    },
    symbol: {
      type: null,
      default: VSlideGroupSymbol
    },
    nextIcon: {
      type: IconValue,
      default: '$next'
    },
    prevIcon: {
      type: IconValue,
      default: '$prev'
    },
    showArrows: {
      type: [Boolean, String],
      validator: v => typeof v === 'boolean' || ['always', 'desktop', 'mobile', 'never'].includes(v)
    },
    ...makeComponentProps(),
    ...makeDisplayProps({
      mobile: null
    }),
    ...makeTagProps(),
    ...makeGroupProps({
      selectedClass: 'v-slide-group-item--active'
    })
  }, 'VSlideGroup');
  const VSlideGroup = genericComponent()({
    name: 'VSlideGroup',
    props: makeVSlideGroupProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const {
        isRtl
      } = useRtl();
      const {
        displayClasses,
        mobile
      } = useDisplay(props);
      const group = useGroup(props, props.symbol);
      const isOverflowing = vue.shallowRef(false);
      const scrollOffset = vue.shallowRef(0);
      const containerSize = vue.shallowRef(0);
      const contentSize = vue.shallowRef(0);
      const isHorizontal = vue.computed(() => props.direction === 'horizontal');
      const {
        resizeRef: containerRef,
        contentRect: containerRect
      } = useResizeObserver();
      const {
        resizeRef: contentRef,
        contentRect
      } = useResizeObserver();
      const goTo = useGoTo();
      const goToOptions = vue.computed(() => {
        return {
          container: containerRef.el,
          duration: 200,
          easing: 'easeOutQuart'
        };
      });
      const firstSelectedIndex = vue.computed(() => {
        if (!group.selected.value.length) return -1;
        return group.items.value.findIndex(item => item.id === group.selected.value[0]);
      });
      const lastSelectedIndex = vue.computed(() => {
        if (!group.selected.value.length) return -1;
        return group.items.value.findIndex(item => item.id === group.selected.value[group.selected.value.length - 1]);
      });
      if (IN_BROWSER) {
        let frame = -1;
        vue.watch(() => [group.selected.value, containerRect.value, contentRect.value, isHorizontal.value], () => {
          cancelAnimationFrame(frame);
          frame = requestAnimationFrame(() => {
            if (containerRect.value && contentRect.value) {
              const sizeProperty = isHorizontal.value ? 'width' : 'height';
              containerSize.value = containerRect.value[sizeProperty];
              contentSize.value = contentRect.value[sizeProperty];
              isOverflowing.value = containerSize.value + 1 < contentSize.value;
            }
            if (props.scrollToActive && firstSelectedIndex.value >= 0 && contentRef.el) {
              // TODO: Is this too naive? Should we store element references in group composable?
              const selectedElement = contentRef.el.children[lastSelectedIndex.value];
              scrollToChildren(selectedElement, props.centerActive);
            }
          });
        });
      }
      const isFocused = vue.shallowRef(false);
      function scrollToChildren(children, center) {
        let target = 0;
        if (center) {
          target = calculateCenteredTarget({
            containerElement: containerRef.el,
            isHorizontal: isHorizontal.value,
            selectedElement: children
          });
        } else {
          target = calculateUpdatedTarget({
            containerElement: containerRef.el,
            isHorizontal: isHorizontal.value,
            isRtl: isRtl.value,
            selectedElement: children
          });
        }
        scrollToPosition(target);
      }
      function scrollToPosition(newPosition) {
        if (!IN_BROWSER || !containerRef.el) return;
        const offsetSize = getOffsetSize(isHorizontal.value, containerRef.el);
        const scrollPosition = getScrollPosition(isHorizontal.value, isRtl.value, containerRef.el);
        const scrollSize = getScrollSize(isHorizontal.value, containerRef.el);
        if (scrollSize <= offsetSize ||
        // Prevent scrolling by only a couple of pixels, which doesn't look smooth
        Math.abs(newPosition - scrollPosition) < 16) return;
        if (isHorizontal.value && isRtl.value && containerRef.el) {
          const {
            scrollWidth,
            offsetWidth: containerWidth
          } = containerRef.el;
          newPosition = scrollWidth - containerWidth - newPosition;
        }
        if (isHorizontal.value) {
          goTo.horizontal(newPosition, goToOptions.value);
        } else {
          goTo(newPosition, goToOptions.value);
        }
      }
      function onScroll(e) {
        const {
          scrollTop,
          scrollLeft
        } = e.target;
        scrollOffset.value = isHorizontal.value ? scrollLeft : scrollTop;
      }
      function onFocusin(e) {
        isFocused.value = true;
        if (!isOverflowing.value || !contentRef.el) return;

        // Focused element is likely to be the root of an item, so a
        // breadth-first search will probably find it in the first iteration
        for (const el of e.composedPath()) {
          for (const item of contentRef.el.children) {
            if (item === el) {
              scrollToChildren(item);
              return;
            }
          }
        }
      }
      function onFocusout(e) {
        isFocused.value = false;
      }

      // Affix clicks produce onFocus that we have to ignore to avoid extra scrollToChildren
      let ignoreFocusEvent = false;
      function onFocus(e) {
        if (!ignoreFocusEvent && !isFocused.value && !(e.relatedTarget && contentRef.el?.contains(e.relatedTarget))) focus();
        ignoreFocusEvent = false;
      }
      function onFocusAffixes() {
        ignoreFocusEvent = true;
      }
      function onKeydown(e) {
        if (!contentRef.el) return;
        function toFocus(location) {
          e.preventDefault();
          focus(location);
        }
        if (isHorizontal.value) {
          if (e.key === 'ArrowRight') {
            toFocus(isRtl.value ? 'prev' : 'next');
          } else if (e.key === 'ArrowLeft') {
            toFocus(isRtl.value ? 'next' : 'prev');
          }
        } else {
          if (e.key === 'ArrowDown') {
            toFocus('next');
          } else if (e.key === 'ArrowUp') {
            toFocus('prev');
          }
        }
        if (e.key === 'Home') {
          toFocus('first');
        } else if (e.key === 'End') {
          toFocus('last');
        }
      }
      function getSiblingElement(el, location) {
        if (!el) return undefined;
        let sibling = el;
        do {
          sibling = sibling?.[location === 'next' ? 'nextElementSibling' : 'previousElementSibling'];
        } while (sibling?.hasAttribute('disabled'));
        return sibling;
      }
      function focus(location) {
        if (!contentRef.el) return;
        let el;
        if (!location) {
          const focusable = focusableChildren(contentRef.el);
          el = focusable[0];
        } else if (location === 'next') {
          el = getSiblingElement(contentRef.el.querySelector(':focus'), location);
          if (!el) return focus('first');
        } else if (location === 'prev') {
          el = getSiblingElement(contentRef.el.querySelector(':focus'), location);
          if (!el) return focus('last');
        } else if (location === 'first') {
          el = contentRef.el.firstElementChild;
          if (el?.hasAttribute('disabled')) el = getSiblingElement(el, 'next');
        } else if (location === 'last') {
          el = contentRef.el.lastElementChild;
          if (el?.hasAttribute('disabled')) el = getSiblingElement(el, 'prev');
        }
        if (el) {
          el.focus({
            preventScroll: true
          });
        }
      }
      function scrollTo(location) {
        const direction = isHorizontal.value && isRtl.value ? -1 : 1;
        const offsetStep = (location === 'prev' ? -direction : direction) * containerSize.value;
        let newPosition = scrollOffset.value + offsetStep;

        // TODO: improve it
        if (isHorizontal.value && isRtl.value && containerRef.el) {
          const {
            scrollWidth,
            offsetWidth: containerWidth
          } = containerRef.el;
          newPosition += scrollWidth - containerWidth;
        }
        scrollToPosition(newPosition);
      }
      const slotProps = vue.computed(() => ({
        next: group.next,
        prev: group.prev,
        select: group.select,
        isSelected: group.isSelected
      }));
      const hasOverflowOrScroll = vue.computed(() => isOverflowing.value || Math.abs(scrollOffset.value) > 0);
      const hasAffixes = vue.computed(() => {
        switch (props.showArrows) {
          case 'never':
            return false;

          // Always show arrows on desktop & mobile
          case 'always':
            return true;

          // Always show arrows on desktop
          case 'desktop':
            return !mobile.value;

          // Show arrows on mobile when overflowing.
          // This matches the default 2.2 behavior
          case true:
            return hasOverflowOrScroll.value;

          // Always show on mobile
          case 'mobile':
            return mobile.value || hasOverflowOrScroll.value;

          // https://material.io/components/tabs#scrollable-tabs
          // Always show arrows when
          // overflowed on desktop
          default:
            return !mobile.value && hasOverflowOrScroll.value;
        }
      });
      const hasPrev = vue.computed(() => {
        // 1 pixel in reserve, may be lost after rounding
        return Math.abs(scrollOffset.value) > 1;
      });
      const hasNext = vue.computed(() => {
        if (!hasOverflowOrScroll.value) return false;
        const scrollSizeMax = contentSize.value - containerSize.value;

        // 1 pixel in reserve, may be lost after rounding
        return scrollSizeMax - Math.abs(scrollOffset.value) > 1;
      });
      useRender(() => vue.createVNode(props.tag, {
        "class": vue.normalizeClass(['v-slide-group', {
          'v-slide-group--vertical': !isHorizontal.value,
          'v-slide-group--has-affixes': hasAffixes.value,
          'v-slide-group--is-overflowing': isOverflowing.value
        }, displayClasses.value, props.class]),
        "style": vue.normalizeStyle(props.style),
        "tabindex": isFocused.value || group.selected.value.length ? -1 : 0,
        "onFocus": onFocus
      }, {
        default: () => [hasAffixes.value && vue.createElementVNode("div", {
          "key": "prev",
          "class": vue.normalizeClass(['v-slide-group__prev', {
            'v-slide-group__prev--disabled': !hasPrev.value
          }]),
          "onMousedown": onFocusAffixes,
          "onClick": () => hasPrev.value && scrollTo('prev')
        }, [slots.prev?.(slotProps.value) ?? vue.createVNode(VFadeTransition, null, {
          default: () => [vue.createVNode(VIcon, {
            "icon": isRtl.value ? props.nextIcon : props.prevIcon
          }, null)]
        })]), vue.createElementVNode("div", {
          "key": "container",
          "ref": containerRef,
          "class": vue.normalizeClass(['v-slide-group__container', props.contentClass]),
          "onScroll": onScroll
        }, [vue.createElementVNode("div", {
          "ref": contentRef,
          "class": "v-slide-group__content",
          "onFocusin": onFocusin,
          "onFocusout": onFocusout,
          "onKeydown": onKeydown
        }, [slots.default?.(slotProps.value)])]), hasAffixes.value && vue.createElementVNode("div", {
          "key": "next",
          "class": vue.normalizeClass(['v-slide-group__next', {
            'v-slide-group__next--disabled': !hasNext.value
          }]),
          "onMousedown": onFocusAffixes,
          "onClick": () => hasNext.value && scrollTo('next')
        }, [slots.next?.(slotProps.value) ?? vue.createVNode(VFadeTransition, null, {
          default: () => [vue.createVNode(VIcon, {
            "icon": isRtl.value ? props.prevIcon : props.nextIcon
          }, null)]
        })])]
      }));
      return {
        selected: group.selected,
        scrollTo,
        scrollOffset,
        focus,
        hasPrev,
        hasNext
      };
    }
  });

  // Types

  const VChipGroupSymbol = Symbol.for('vuetify:v-chip-group');
  const makeVChipGroupProps = propsFactory({
    baseColor: String,
    column: Boolean,
    filter: Boolean,
    valueComparator: {
      type: Function,
      default: deepEqual
    },
    ...makeVSlideGroupProps({
      scrollToActive: false
    }),
    ...makeComponentProps(),
    ...makeGroupProps({
      selectedClass: 'v-chip--selected'
    }),
    ...makeTagProps(),
    ...makeThemeProps(),
    ...makeVariantProps({
      variant: 'tonal'
    })
  }, 'VChipGroup');
  const VChipGroup = genericComponent()({
    name: 'VChipGroup',
    props: makeVChipGroupProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const {
        themeClasses
      } = provideTheme(props);
      const {
        isSelected,
        select,
        next,
        prev,
        selected
      } = useGroup(props, VChipGroupSymbol);
      provideDefaults({
        VChip: {
          baseColor: vue.toRef(() => props.baseColor),
          color: vue.toRef(() => props.color),
          disabled: vue.toRef(() => props.disabled),
          filter: vue.toRef(() => props.filter),
          variant: vue.toRef(() => props.variant)
        }
      });
      useRender(() => {
        const slideGroupProps = VSlideGroup.filterProps(props);
        return vue.createVNode(VSlideGroup, vue.mergeProps(slideGroupProps, {
          "class": ['v-chip-group', {
            'v-chip-group--column': props.column
          }, themeClasses.value, props.class],
          "style": props.style
        }), {
          default: () => [slots.default?.({
            isSelected,
            select,
            next,
            prev,
            selected: selected.value
          })]
        });
      });
      return {};
    }
  });

  // Types

  const makeVChipProps = propsFactory({
    activeClass: String,
    appendAvatar: String,
    appendIcon: IconValue,
    baseColor: String,
    closable: Boolean,
    closeIcon: {
      type: IconValue,
      default: '$delete'
    },
    closeLabel: {
      type: String,
      default: '$vuetify.close'
    },
    draggable: Boolean,
    filter: Boolean,
    filterIcon: {
      type: IconValue,
      default: '$complete'
    },
    label: Boolean,
    link: {
      type: Boolean,
      default: undefined
    },
    pill: Boolean,
    prependAvatar: String,
    prependIcon: IconValue,
    ripple: {
      type: [Boolean, Object],
      default: true
    },
    text: {
      type: [String, Number, Boolean],
      default: undefined
    },
    modelValue: {
      type: Boolean,
      default: true
    },
    onClick: EventProp(),
    onClickOnce: EventProp(),
    ...makeBorderProps(),
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...makeElevationProps(),
    ...makeGroupItemProps(),
    ...makeRoundedProps(),
    ...makeRouterProps(),
    ...makeSizeProps(),
    ...makeTagProps({
      tag: 'span'
    }),
    ...makeThemeProps(),
    ...makeVariantProps({
      variant: 'tonal'
    })
  }, 'VChip');
  const VChip = genericComponent()({
    name: 'VChip',
    directives: {
      vRipple: Ripple
    },
    props: makeVChipProps(),
    emits: {
      'click:close': e => true,
      'update:modelValue': value => true,
      'group:selected': val => true,
      click: e => true
    },
    setup(props, {
      attrs,
      emit,
      slots
    }) {
      const {
        t
      } = useLocale();
      const {
        borderClasses
      } = useBorder(props);
      const {
        densityClasses
      } = useDensity(props);
      const {
        elevationClasses
      } = useElevation(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const {
        sizeClasses
      } = useSize(props);
      const {
        themeClasses
      } = provideTheme(props);
      const isActive = useProxiedModel(props, 'modelValue');
      const group = useGroupItem(props, VChipGroupSymbol, false);
      const slideGroup = useGroupItem(props, VSlideGroupSymbol, false);
      const link = useLink(props, attrs);
      const isLink = vue.toRef(() => props.link !== false && link.isLink.value);
      const isClickable = vue.computed(() => !props.disabled && props.link !== false && (!!group || props.link || link.isClickable.value));
      const closeProps = vue.toRef(() => ({
        'aria-label': t(props.closeLabel),
        disabled: props.disabled,
        onClick(e) {
          e.preventDefault();
          e.stopPropagation();
          isActive.value = false;
          emit('click:close', e);
        }
      }));
      vue.watch(isActive, val => {
        if (val) {
          group?.register();
          slideGroup?.register();
        } else {
          group?.unregister();
          slideGroup?.unregister();
        }
      });
      const {
        colorClasses,
        colorStyles,
        variantClasses
      } = useVariant(() => {
        const showColor = !group || group.isSelected.value;
        return {
          color: showColor ? props.color ?? props.baseColor : props.baseColor,
          variant: props.variant
        };
      });
      function onClick(e) {
        emit('click', e);
        if (!isClickable.value) return;
        link.navigate.value?.(e);
        group?.toggle();
      }
      function onKeyDown(e) {
        if (e.key === 'Enter' || e.key === ' ') {
          e.preventDefault();
          onClick(e);
        }
      }
      return () => {
        const Tag = link.isLink.value ? 'a' : props.tag;
        const hasAppendMedia = !!(props.appendIcon || props.appendAvatar);
        const hasAppend = !!(hasAppendMedia || slots.append);
        const hasClose = !!(slots.close || props.closable);
        const hasFilter = !!(slots.filter || props.filter) && group;
        const hasPrependMedia = !!(props.prependIcon || props.prependAvatar);
        const hasPrepend = !!(hasPrependMedia || slots.prepend);
        return isActive.value && vue.withDirectives(vue.createVNode(Tag, vue.mergeProps(link.linkProps, {
          "class": ['v-chip', {
            'v-chip--disabled': props.disabled,
            'v-chip--label': props.label,
            'v-chip--link': isClickable.value,
            'v-chip--filter': hasFilter,
            'v-chip--pill': props.pill,
            [`${props.activeClass}`]: props.activeClass && link.isActive?.value
          }, themeClasses.value, borderClasses.value, colorClasses.value, densityClasses.value, elevationClasses.value, roundedClasses.value, sizeClasses.value, variantClasses.value, group?.selectedClass.value, props.class],
          "style": [colorStyles.value, roundedStyles.value, props.style],
          "disabled": props.disabled || undefined,
          "draggable": props.draggable,
          "tabindex": isClickable.value ? 0 : undefined,
          "onClick": (isClickable.value || props.onClick || props.onClickOnce) && onClick,
          "onKeydown": isClickable.value && !isLink.value && onKeyDown
        }), {
          default: () => [genOverlays(isClickable.value, 'v-chip'), hasFilter && vue.createVNode(VExpandXTransition, {
            "key": "filter"
          }, {
            default: () => [vue.withDirectives(vue.createElementVNode("div", {
              "class": "v-chip__filter"
            }, [!slots.filter ? vue.createVNode(VIcon, {
              "key": "filter-icon",
              "icon": props.filterIcon
            }, null) : vue.createVNode(VDefaultsProvider, {
              "key": "filter-defaults",
              "disabled": !props.filterIcon,
              "defaults": {
                VIcon: {
                  icon: props.filterIcon
                }
              }
            }, slots.filter)]), [[vue.vShow, group.isSelected.value]])]
          }), hasPrepend && vue.createElementVNode("div", {
            "key": "prepend",
            "class": "v-chip__prepend"
          }, [!slots.prepend ? vue.createElementVNode(vue.Fragment, null, [props.prependIcon && vue.createVNode(VIcon, {
            "key": "prepend-icon",
            "icon": props.prependIcon,
            "start": true
          }, null), props.prependAvatar && vue.createVNode(VAvatar, {
            "key": "prepend-avatar",
            "image": props.prependAvatar,
            "start": true
          }, null)]) : vue.createVNode(VDefaultsProvider, {
            "key": "prepend-defaults",
            "disabled": !hasPrependMedia,
            "defaults": {
              VAvatar: {
                image: props.prependAvatar,
                start: true
              },
              VIcon: {
                icon: props.prependIcon,
                start: true
              }
            }
          }, slots.prepend)]), vue.createElementVNode("div", {
            "class": "v-chip__content",
            "data-no-activator": ""
          }, [slots.default?.({
            isSelected: group?.isSelected.value,
            selectedClass: group?.selectedClass.value,
            select: group?.select,
            toggle: group?.toggle,
            value: group?.value.value,
            disabled: props.disabled
          }) ?? vue.toDisplayString(props.text)]), hasAppend && vue.createElementVNode("div", {
            "key": "append",
            "class": "v-chip__append"
          }, [!slots.append ? vue.createElementVNode(vue.Fragment, null, [props.appendIcon && vue.createVNode(VIcon, {
            "key": "append-icon",
            "end": true,
            "icon": props.appendIcon
          }, null), props.appendAvatar && vue.createVNode(VAvatar, {
            "key": "append-avatar",
            "end": true,
            "image": props.appendAvatar
          }, null)]) : vue.createVNode(VDefaultsProvider, {
            "key": "append-defaults",
            "disabled": !hasAppendMedia,
            "defaults": {
              VAvatar: {
                end: true,
                image: props.appendAvatar
              },
              VIcon: {
                end: true,
                icon: props.appendIcon
              }
            }
          }, slots.append)]), hasClose && vue.createElementVNode("button", vue.mergeProps({
            "key": "close",
            "class": "v-chip__close",
            "type": "button",
            "data-testid": "close-chip"
          }, closeProps.value), [!slots.close ? vue.createVNode(VIcon, {
            "key": "close-icon",
            "icon": props.closeIcon,
            "size": "x-small"
          }, null) : vue.createVNode(VDefaultsProvider, {
            "key": "close-defaults",
            "defaults": {
              VIcon: {
                icon: props.closeIcon,
                size: 'x-small'
              }
            }
          }, slots.close)])]
        }), [[Ripple, isClickable.value && props.ripple, null]]);
      };
    }
  });

  // Types

  const allowedVariants$2 = ['dotted', 'dashed', 'solid', 'double'];
  const makeVDividerProps = propsFactory({
    color: String,
    contentOffset: [Number, String, Array],
    gradient: Boolean,
    inset: Boolean,
    length: [Number, String],
    opacity: [Number, String],
    thickness: [Number, String],
    vertical: Boolean,
    variant: {
      type: String,
      default: 'solid',
      validator: v => allowedVariants$2.includes(v)
    },
    ...makeComponentProps(),
    ...makeThemeProps()
  }, 'VDivider');
  const VDivider = genericComponent()({
    name: 'VDivider',
    props: makeVDividerProps(),
    setup(props, {
      attrs,
      slots
    }) {
      const {
        themeClasses
      } = provideTheme(props);
      const {
        textColorClasses,
        textColorStyles
      } = useTextColor(() => props.color);
      const dividerStyles = vue.computed(() => {
        const styles = {};
        if (props.length) {
          styles[props.vertical ? 'height' : 'width'] = convertToUnit(props.length);
        }
        if (props.thickness) {
          styles[props.vertical ? 'borderRightWidth' : 'borderTopWidth'] = convertToUnit(props.thickness);
        }
        return styles;
      });
      const contentStyles = vue.toRef(() => {
        const margin = Array.isArray(props.contentOffset) ? props.contentOffset[0] : props.contentOffset;
        const shift = Array.isArray(props.contentOffset) ? props.contentOffset[1] : 0;
        return {
          marginBlock: props.vertical && margin ? convertToUnit(margin) : undefined,
          marginInline: !props.vertical && margin ? convertToUnit(margin) : undefined,
          transform: shift ? `translate${props.vertical ? 'X' : 'Y'}(${convertToUnit(shift)})` : undefined
        };
      });
      useRender(() => {
        const role = attrs.role;
        const hasSlot = !!slots.default;
        const divider = vue.createElementVNode("hr", {
          "class": vue.normalizeClass([{
            'v-divider': true,
            'v-divider--gradient': props.gradient && !slots.default,
            'v-divider--inset': props.inset,
            'v-divider--vertical': props.vertical
          }, themeClasses.value, textColorClasses.value, props.class]),
          "style": vue.normalizeStyle([dividerStyles.value, textColorStyles.value, {
            '--v-border-opacity': props.opacity
          }, {
            'border-style': props.variant
          }, props.style]),
          "aria-orientation": !hasSlot && !role ? props.vertical ? 'vertical' : 'horizontal' : undefined,
          "role": !hasSlot ? role : undefined
        }, null);
        if (!hasSlot) return divider;
        return vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-divider__wrapper', {
            'v-divider__wrapper--gradient': props.gradient,
            'v-divider__wrapper--inset': props.inset,
            'v-divider__wrapper--vertical': props.vertical
          }])
        }, [divider, vue.createElementVNode("div", {
          "class": "v-divider__content",
          "style": vue.normalizeStyle(contentStyles.value)
        }, [slots.default()]), divider]);
      });
      return {};
    }
  });

  // Utilities

  // List
  const ListKey = Symbol.for('vuetify:list');
  function createList(options = {
    filterable: false
  }) {
    const parent = vue.inject(ListKey, {
      filterable: false,
      hasPrepend: vue.shallowRef(false),
      updateHasPrepend: () => null,
      trackingIndex: vue.shallowRef(-1),
      navigationStrategy: vue.shallowRef('focus'),
      uid: ''
    });
    const {
      filterable,
      trackingIndex = parent.trackingIndex,
      navigationStrategy = parent.navigationStrategy,
      uid = parent.uid || vue.useId()
    } = options;
    const data = {
      filterable: parent.filterable || filterable,
      hasPrepend: vue.shallowRef(false),
      updateHasPrepend: value => {
        if (value) data.hasPrepend.value = value;
      },
      trackingIndex,
      navigationStrategy,
      uid
    };
    vue.provide(ListKey, data);
    return parent;
  }
  function useList() {
    return vue.inject(ListKey, null);
  }

  /* eslint-disable sonarjs/no-identical-functions */
  // Utilities
  const independentActiveStrategy = mandatory => {
    const strategy = {
      activate: ({
        id,
        value,
        activated
      }) => {
        id = vue.toRaw(id);

        // When mandatory and we're trying to deselect when id
        // is the only currently selected item then do nothing
        if (mandatory && !value && activated.size === 1 && activated.has(id)) return activated;
        if (value) {
          activated.add(id);
        } else {
          activated.delete(id);
        }
        return activated;
      },
      in: (v, children, parents) => {
        let set = new Set();
        if (v != null) {
          for (const id of wrapInArray(v)) {
            set = strategy.activate({
              id,
              value: true,
              activated: new Set(set),
              children,
              parents
            });
          }
        }
        return set;
      },
      out: v => {
        return Array.from(v);
      }
    };
    return strategy;
  };
  const independentSingleActiveStrategy = mandatory => {
    const parentStrategy = independentActiveStrategy(mandatory);
    const strategy = {
      activate: ({
        activated,
        id,
        ...rest
      }) => {
        id = vue.toRaw(id);
        const singleSelected = activated.has(id) ? new Set([id]) : new Set();
        return parentStrategy.activate({
          ...rest,
          id,
          activated: singleSelected
        });
      },
      in: (v, children, parents) => {
        let set = new Set();
        if (v != null) {
          const arr = wrapInArray(v);
          if (arr.length) {
            set = parentStrategy.in(arr.slice(0, 1), children, parents);
          }
        }
        return set;
      },
      out: (v, children, parents) => {
        return parentStrategy.out(v, children, parents);
      }
    };
    return strategy;
  };
  const leafActiveStrategy = mandatory => {
    const parentStrategy = independentActiveStrategy(mandatory);
    const strategy = {
      activate: ({
        id,
        activated,
        children,
        ...rest
      }) => {
        id = vue.toRaw(id);
        if (children.has(id)) return activated;
        return parentStrategy.activate({
          id,
          activated,
          children,
          ...rest
        });
      },
      in: parentStrategy.in,
      out: parentStrategy.out
    };
    return strategy;
  };
  const leafSingleActiveStrategy = mandatory => {
    const parentStrategy = independentSingleActiveStrategy(mandatory);
    const strategy = {
      activate: ({
        id,
        activated,
        children,
        ...rest
      }) => {
        id = vue.toRaw(id);
        if (children.has(id)) return activated;
        return parentStrategy.activate({
          id,
          activated,
          children,
          ...rest
        });
      },
      in: parentStrategy.in,
      out: parentStrategy.out
    };
    return strategy;
  };

  const singleOpenStrategy = {
    open: ({
      id,
      value,
      opened,
      parents
    }) => {
      if (value) {
        const newOpened = new Set();
        newOpened.add(id);
        let parent = parents.get(id);
        while (parent != null) {
          newOpened.add(parent);
          parent = parents.get(parent);
        }
        return newOpened;
      } else {
        opened.delete(id);
        return opened;
      }
    },
    select: () => null
  };
  const multipleOpenStrategy = {
    open: ({
      id,
      value,
      opened,
      parents
    }) => {
      if (value) {
        let parent = parents.get(id);
        opened.add(id);
        while (parent != null && parent !== id) {
          opened.add(parent);
          parent = parents.get(parent);
        }
        return opened;
      } else {
        opened.delete(id);
      }
      return opened;
    },
    select: () => null
  };
  const listOpenStrategy = {
    open: multipleOpenStrategy.open,
    select: ({
      id,
      value,
      opened,
      parents
    }) => {
      if (!value) return opened;
      const path = [];
      let parent = parents.get(id);
      while (parent != null) {
        path.push(parent);
        parent = parents.get(parent);
      }
      return new Set(path);
    }
  };

  /* eslint-disable sonarjs/no-identical-functions */
  // Utilities
  const independentSelectStrategy = mandatory => {
    const strategy = {
      select: ({
        id,
        value,
        selected
      }) => {
        id = vue.toRaw(id);

        // When mandatory and we're trying to deselect when id
        // is the only currently selected item then do nothing
        if (mandatory && !value) {
          const on = Array.from(selected.entries()).reduce((arr, [key, value]) => {
            if (value === 'on') arr.push(key);
            return arr;
          }, []);
          if (on.length === 1 && on[0] === id) return selected;
        }
        selected.set(id, value ? 'on' : 'off');
        return selected;
      },
      in: (v, children, parents, disabled) => {
        const map = new Map();
        for (const id of v || []) {
          strategy.select({
            id,
            value: true,
            selected: map,
            children,
            parents,
            disabled
          });
        }
        return map;
      },
      out: v => {
        const arr = [];
        for (const [key, value] of v.entries()) {
          if (value === 'on') arr.push(key);
        }
        return arr;
      }
    };
    return strategy;
  };
  const independentSingleSelectStrategy = mandatory => {
    const parentStrategy = independentSelectStrategy(mandatory);
    const strategy = {
      select: ({
        selected,
        id,
        ...rest
      }) => {
        id = vue.toRaw(id);
        const singleSelected = selected.has(id) ? new Map([[id, selected.get(id)]]) : new Map();
        return parentStrategy.select({
          ...rest,
          id,
          selected: singleSelected
        });
      },
      in: (v, children, parents, disabled) => {
        if (v?.length) {
          return parentStrategy.in(v.slice(0, 1), children, parents, disabled);
        }
        return new Map();
      },
      out: (v, children, parents) => {
        return parentStrategy.out(v, children, parents);
      }
    };
    return strategy;
  };
  const leafSelectStrategy = mandatory => {
    const parentStrategy = independentSelectStrategy(mandatory);
    const strategy = {
      select: ({
        id,
        selected,
        children,
        ...rest
      }) => {
        id = vue.toRaw(id);
        if (children.has(id)) return selected;
        return parentStrategy.select({
          id,
          selected,
          children,
          ...rest
        });
      },
      in: parentStrategy.in,
      out: parentStrategy.out
    };
    return strategy;
  };
  const leafSingleSelectStrategy = mandatory => {
    const parentStrategy = independentSingleSelectStrategy(mandatory);
    const strategy = {
      select: ({
        id,
        selected,
        children,
        ...rest
      }) => {
        id = vue.toRaw(id);
        if (children.has(id)) return selected;
        return parentStrategy.select({
          id,
          selected,
          children,
          ...rest
        });
      },
      in: parentStrategy.in,
      out: parentStrategy.out
    };
    return strategy;
  };
  const classicSelectStrategy = mandatory => {
    const strategy = {
      select: ({
        id,
        value,
        selected,
        children,
        parents,
        disabled
      }) => {
        id = vue.toRaw(id);
        const original = new Map(selected);
        const items = [id];
        while (items.length) {
          const item = items.shift();
          if (!disabled.has(item)) {
            selected.set(vue.toRaw(item), value ? 'on' : 'off');
          }
          if (children.has(item)) {
            items.push(...children.get(item));
          }
        }
        let parent = vue.toRaw(parents.get(id));
        while (parent) {
          let everySelected = true;
          let noneSelected = true;
          for (const child of children.get(parent)) {
            const cid = vue.toRaw(child);
            if (disabled.has(cid)) continue;
            if (selected.get(cid) !== 'on') everySelected = false;
            if (selected.has(cid) && selected.get(cid) !== 'off') noneSelected = false;
            if (!everySelected && !noneSelected) break;
          }
          selected.set(parent, everySelected ? 'on' : noneSelected ? 'off' : 'indeterminate');
          parent = vue.toRaw(parents.get(parent));
        }

        // If mandatory and planned deselect results in no selected
        // items then we can't do it, so return original state
        if (mandatory && !value) {
          const on = Array.from(selected.entries()).reduce((arr, [key, value]) => {
            if (value === 'on') arr.push(key);
            return arr;
          }, []);
          if (on.length === 0) return original;
        }
        return selected;
      },
      in: (v, children, parents) => {
        let map = new Map();
        for (const id of v || []) {
          map = strategy.select({
            id,
            value: true,
            selected: map,
            children,
            parents,
            disabled: new Set()
          });
        }
        return map;
      },
      out: (v, children) => {
        const arr = [];
        for (const [key, value] of v.entries()) {
          if (value === 'on' && !children.has(key)) arr.push(key);
        }
        return arr;
      }
    };
    return strategy;
  };
  const trunkSelectStrategy = mandatory => {
    const parentStrategy = classicSelectStrategy(mandatory);
    const strategy = {
      select: parentStrategy.select,
      in: parentStrategy.in,
      out: (v, children, parents) => {
        const arr = [];
        for (const [key, value] of v.entries()) {
          if (value === 'on') {
            if (parents.has(key)) {
              const parent = parents.get(key);
              if (v.get(parent) === 'on') continue;
            }
            arr.push(key);
          }
        }
        return arr;
      }
    };
    return strategy;
  };
  const branchSelectStrategy = mandatory => {
    const parentStrategy = classicSelectStrategy(mandatory);
    const strategy = {
      select: parentStrategy.select,
      in: (v, children, parents, disabled) => {
        let map = new Map();
        for (const id of v || []) {
          if (children.has(id)) continue;
          map = strategy.select({
            id,
            value: true,
            selected: map,
            children,
            parents,
            disabled
          });
        }
        return map;
      },
      out: v => {
        const arr = [];
        for (const [key, value] of v.entries()) {
          if (value === 'on' || value === 'indeterminate') {
            arr.push(key);
          }
        }
        return arr;
      }
    };
    return strategy;
  };

  // Composables

  // Types

  const VNestedSymbol = Symbol.for('vuetify:nested');
  const emptyNested = {
    id: vue.shallowRef(),
    root: {
      itemsRegistration: vue.ref('render'),
      register: () => null,
      unregister: () => null,
      updateDisabled: () => null,
      children: vue.ref(new Map()),
      parents: vue.ref(new Map()),
      disabled: vue.ref(new Set()),
      open: () => null,
      openOnSelect: () => null,
      activate: () => null,
      select: () => null,
      activatable: vue.ref(false),
      scrollToActive: vue.ref(false),
      selectable: vue.ref(false),
      opened: vue.ref(new Set()),
      activated: vue.ref(new Set()),
      selected: vue.ref(new Map()),
      selectedValues: vue.ref([]),
      getPath: () => []
    }
  };
  const makeNestedProps = propsFactory({
    activatable: Boolean,
    selectable: Boolean,
    activeStrategy: [String, Function, Object],
    selectStrategy: [String, Function, Object],
    openStrategy: [String, Object],
    opened: null,
    activated: null,
    selected: null,
    mandatory: Boolean,
    itemsRegistration: {
      type: String,
      default: 'render'
    }
  }, 'nested');
  const useNested = (props, {
    items,
    returnObject,
    scrollToActive,
    valueComparator
  }) => {
    let isUnmounted = false;
    const children = vue.shallowRef(new Map());
    const parents = vue.shallowRef(new Map());
    const disabled = vue.shallowRef(new Set());
    const opened = useProxiedModel(props, 'opened', props.opened, v => new Set(Array.isArray(v) ? v.map(i => vue.toRaw(i)) : v), v => [...v.values()]);
    const activeStrategy = vue.computed(() => {
      if (typeof props.activeStrategy === 'object') return props.activeStrategy;
      if (typeof props.activeStrategy === 'function') return props.activeStrategy(props.mandatory);
      switch (props.activeStrategy) {
        case 'leaf':
          return leafActiveStrategy(props.mandatory);
        case 'single-leaf':
          return leafSingleActiveStrategy(props.mandatory);
        case 'independent':
          return independentActiveStrategy(props.mandatory);
        case 'single-independent':
        default:
          return independentSingleActiveStrategy(props.mandatory);
      }
    });
    const selectStrategy = vue.computed(() => {
      if (typeof props.selectStrategy === 'object') return props.selectStrategy;
      if (typeof props.selectStrategy === 'function') return props.selectStrategy(props.mandatory);
      switch (props.selectStrategy) {
        case 'single-leaf':
          return leafSingleSelectStrategy(props.mandatory);
        case 'leaf':
          return leafSelectStrategy(props.mandatory);
        case 'independent':
          return independentSelectStrategy(props.mandatory);
        case 'single-independent':
          return independentSingleSelectStrategy(props.mandatory);
        case 'trunk':
          return trunkSelectStrategy(props.mandatory);
        case 'branch':
          return branchSelectStrategy(props.mandatory);
        case 'classic':
        default:
          return classicSelectStrategy(props.mandatory);
      }
    });
    const openStrategy = vue.computed(() => {
      if (typeof props.openStrategy === 'object') return props.openStrategy;
      switch (props.openStrategy) {
        case 'list':
          return listOpenStrategy;
        case 'single':
          return singleOpenStrategy;
        case 'multiple':
        default:
          return multipleOpenStrategy;
      }
    });
    const flatItems = vue.computed(() => {
      const flat = [];
      const stack = [...items.value];
      while (stack.length) {
        const item = stack.pop();
        flat.push(item);
        if (item.children) stack.push(...item.children);
      }
      return flat;
    });
    function resolveValue(value) {
      const comparator = vue.toValue(valueComparator);
      if (!comparator) return value;
      const _returnObject = vue.toValue(returnObject);
      for (const item of flatItems.value) {
        const itemVal = _returnObject ? vue.toRaw(item.raw) : item.value;
        if (comparator(value, itemVal)) return itemVal;
      }
      return value;
    }
    const activated = useProxiedModel(props, 'activated', props.activated, v => activeStrategy.value.in(Array.isArray(v) ? v.map(resolveValue) : v, children.value, parents.value), v => activeStrategy.value.out(v, children.value, parents.value));
    const selected = useProxiedModel(props, 'selected', props.selected, v => selectStrategy.value.in(Array.isArray(v) ? v.map(resolveValue) : v, children.value, parents.value, disabled.value), v => selectStrategy.value.out(v, children.value, parents.value));
    vue.onBeforeUnmount(() => {
      isUnmounted = true;
    });
    function getPath(id) {
      const path = [];
      let parent = vue.toRaw(id);
      while (parent !== undefined) {
        path.unshift(parent);
        parent = parents.value.get(parent);
      }
      return path;
    }
    const vm = getCurrentInstance('nested');
    const nodeIds = new Set();
    const itemsUpdatePropagation = throttle(() => {
      vue.nextTick(() => {
        children.value = new Map(children.value);
        parents.value = new Map(parents.value);
      });
    }, 100);
    vue.watch(() => [items.value, vue.toValue(returnObject)], () => {
      if (props.itemsRegistration === 'props') {
        updateInternalMaps();
      }
    }, {
      immediate: true
    });
    function updateInternalMaps() {
      const _parents = new Map();
      const _children = new Map();
      const _disabled = new Set();
      const getValue = vue.toValue(returnObject) ? item => vue.toRaw(item.raw) : item => item.value;
      const stack = [...items.value];
      let i = 0;
      while (i < stack.length) {
        const item = stack[i++];
        const itemValue = getValue(item);
        if (item.children) {
          const childValues = [];
          for (const child of item.children) {
            const childValue = getValue(child);
            _parents.set(childValue, itemValue);
            childValues.push(childValue);
            stack.push(child);
          }
          _children.set(itemValue, childValues);
        }
        if (item.props.disabled) {
          _disabled.add(itemValue);
        }
      }
      children.value = _children;
      parents.value = _parents;
      disabled.value = _disabled;
    }
    const nested = {
      id: vue.shallowRef(),
      root: {
        opened,
        activatable: vue.toRef(() => props.activatable),
        scrollToActive: vue.toRef(() => vue.toValue(scrollToActive)),
        selectable: vue.toRef(() => props.selectable),
        activated,
        selected,
        selectedValues: vue.computed(() => {
          const arr = [];
          for (const [key, value] of selected.value.entries()) {
            if (value === 'on') arr.push(key);
          }
          return arr;
        }),
        itemsRegistration: vue.toRef(() => props.itemsRegistration),
        register: (id, parentId, isDisabled, isGroup) => {
          if (nodeIds.has(id)) {
            const path = getPath(id).map(String).join(' -> ');
            const newPath = getPath(parentId).concat(id).map(String).join(' -> ');
            consoleError(`Multiple nodes with the same ID\n\t${path}\n\t${newPath}`);
            return;
          } else {
            nodeIds.add(id);
          }
          parentId && id !== parentId && parents.value.set(id, parentId);
          isDisabled && disabled.value.add(id);
          isGroup && children.value.set(id, []);
          if (parentId != null) {
            children.value.set(parentId, [...(children.value.get(parentId) || []), id]);
          }
          itemsUpdatePropagation();
        },
        unregister: id => {
          if (isUnmounted) return;
          nodeIds.delete(id);
          children.value.delete(id);
          disabled.value.delete(id);
          const parent = parents.value.get(id);
          if (parent) {
            const list = children.value.get(parent) ?? [];
            children.value.set(parent, list.filter(child => child !== id));
          }
          parents.value.delete(id);
          itemsUpdatePropagation();
        },
        updateDisabled: (id, isDisabled) => {
          if (isDisabled) {
            disabled.value.add(id);
          } else {
            disabled.value.delete(id);
          }
          // classic selection requires refresh to re-evaluate on/off/indeterminate but
          // currently it is only run for selection interactions, so it will set new disabled
          // to "off" and the visual state becomes out of sync
          // -- selected.value = new Map(selected.value)
          // it is not clear if the framework should un-select when disabled changed to true
          // more discussion is needed
        },
        open: (id, value, event) => {
          vm.emit('click:open', {
            id,
            value,
            path: getPath(id),
            event
          });
          const newOpened = openStrategy.value.open({
            id,
            value,
            opened: new Set(opened.value),
            children: children.value,
            parents: parents.value,
            event
          });
          newOpened && (opened.value = newOpened);
        },
        openOnSelect: (id, value, event) => {
          const newOpened = openStrategy.value.select({
            id,
            value,
            selected: new Map(selected.value),
            opened: new Set(opened.value),
            children: children.value,
            parents: parents.value,
            event
          });
          newOpened && (opened.value = newOpened);
        },
        select: (id, value, event) => {
          vm.emit('click:select', {
            id,
            value,
            path: getPath(id),
            event
          });
          const newSelected = selectStrategy.value.select({
            id,
            value,
            selected: new Map(selected.value),
            children: children.value,
            parents: parents.value,
            disabled: disabled.value,
            event
          });
          newSelected && (selected.value = newSelected);
          nested.root.openOnSelect(id, value, event);
        },
        activate: (id, value, event) => {
          if (!props.activatable) {
            return nested.root.select(id, true, event);
          }
          vm.emit('click:activate', {
            id,
            value,
            path: getPath(id),
            event
          });
          const newActivated = activeStrategy.value.activate({
            id,
            value,
            activated: new Set(activated.value),
            children: children.value,
            parents: parents.value,
            event
          });
          if (newActivated.size !== activated.value.size) {
            activated.value = newActivated;
          } else {
            for (const value of newActivated) {
              if (!activated.value.has(value)) {
                activated.value = newActivated;
                return;
              }
            }
            for (const value of activated.value) {
              if (!newActivated.has(value)) {
                activated.value = newActivated;
                return;
              }
            }
          }
        },
        children,
        parents,
        disabled,
        getPath
      }
    };
    vue.provide(VNestedSymbol, nested);
    return nested.root;
  };
  const useNestedItem = (id, isDisabled, isGroup) => {
    const parent = vue.inject(VNestedSymbol, emptyNested);
    const uidSymbol = Symbol('nested item');
    const computedId = vue.computed(() => {
      const idValue = vue.toRaw(vue.toValue(id));
      return idValue !== undefined ? idValue : uidSymbol;
    });
    const item = {
      ...parent,
      id: computedId,
      open: (open, e) => parent.root.open(computedId.value, open, e),
      openOnSelect: (open, e) => parent.root.openOnSelect(computedId.value, open, e),
      isOpen: vue.computed(() => parent.root.opened.value.has(computedId.value)),
      parent: vue.computed(() => parent.root.parents.value.get(computedId.value)),
      activate: (activated, e) => parent.root.activate(computedId.value, activated, e),
      isActivated: vue.computed(() => parent.root.activated.value.has(computedId.value)),
      scrollToActive: parent.root.scrollToActive,
      select: (selected, e) => parent.root.select(computedId.value, selected, e),
      isSelected: vue.computed(() => parent.root.selected.value.get(computedId.value) === 'on'),
      isIndeterminate: vue.computed(() => parent.root.selected.value.get(computedId.value) === 'indeterminate'),
      isLeaf: vue.computed(() => !parent.root.children.value.get(computedId.value)),
      isGroupActivator: parent.isGroupActivator
    };
    vue.onBeforeMount(() => {
      if (parent.isGroupActivator || parent.root.itemsRegistration.value === 'props') return;
      vue.nextTick(() => {
        parent.root.register(computedId.value, parent.id.value, vue.toValue(isDisabled), isGroup);
      });
    });
    vue.onBeforeUnmount(() => {
      if (parent.isGroupActivator || parent.root.itemsRegistration.value === 'props') return;
      parent.root.unregister(computedId.value);
    });
    vue.watch(computedId, (val, oldVal) => {
      if (parent.isGroupActivator || parent.root.itemsRegistration.value === 'props') return;
      parent.root.unregister(oldVal);
      vue.nextTick(() => {
        parent.root.register(val, parent.id.value, vue.toValue(isDisabled), isGroup);
      });
    });
    vue.watch(() => vue.toValue(isDisabled), val => {
      parent.root.updateDisabled(computedId.value, val);
    });
    isGroup && vue.provide(VNestedSymbol, item);
    return item;
  };
  const useNestedGroupActivator = () => {
    const parent = vue.inject(VNestedSymbol, emptyNested);
    vue.provide(VNestedSymbol, {
      ...parent,
      isGroupActivator: true
    });
  };

  const VListGroupActivator = defineComponent({
    name: 'VListGroupActivator',
    setup(_, {
      slots
    }) {
      useNestedGroupActivator();
      return () => slots.default?.();
    }
  });
  const makeVListGroupProps = propsFactory({
    /* @deprecated */
    activeColor: String,
    baseColor: String,
    color: String,
    collapseIcon: {
      type: IconValue,
      default: '$collapse'
    },
    disabled: Boolean,
    expandIcon: {
      type: IconValue,
      default: '$expand'
    },
    rawId: [String, Number],
    prependIcon: IconValue,
    appendIcon: IconValue,
    fluid: Boolean,
    subgroup: Boolean,
    title: String,
    value: null,
    ...makeComponentProps(),
    ...makeTagProps()
  }, 'VListGroup');
  const VListGroup = genericComponent()({
    name: 'VListGroup',
    props: makeVListGroupProps(),
    setup(props, {
      slots
    }) {
      const {
        isOpen,
        open,
        id: _id
      } = useNestedItem(() => props.value, () => props.disabled, true);
      const id = vue.computed(() => `v-list-group--id-${String(props.rawId ?? _id.value)}`);
      const list = useList();
      const {
        isBooted
      } = useSsrBoot();
      const parent = vue.inject(VNestedSymbol);
      const renderWhenClosed = vue.toRef(() => parent?.root?.itemsRegistration.value === 'render');
      function onClick(e) {
        if (['INPUT', 'TEXTAREA'].includes(e.target?.tagName)) return;
        open(!isOpen.value, e);
      }
      const activatorProps = vue.computed(() => ({
        onClick,
        class: 'v-list-group__header',
        id: id.value
      }));
      const toggleIcon = vue.computed(() => isOpen.value ? props.collapseIcon : props.expandIcon);
      const activatorDefaults = vue.computed(() => ({
        VListItem: {
          activeColor: props.activeColor,
          baseColor: props.baseColor,
          color: props.color,
          prependIcon: props.prependIcon || props.subgroup && toggleIcon.value,
          appendIcon: props.appendIcon || !props.subgroup && toggleIcon.value,
          title: props.title,
          value: props.value
        }
      }));
      useRender(() => vue.createVNode(props.tag, {
        "class": vue.normalizeClass(['v-list-group', {
          'v-list-group--prepend': list?.hasPrepend.value,
          'v-list-group--fluid': props.fluid,
          'v-list-group--subgroup': props.subgroup,
          'v-list-group--open': isOpen.value
        }, props.class]),
        "style": vue.normalizeStyle(props.style)
      }, {
        default: () => [slots.activator && vue.createVNode(VDefaultsProvider, {
          "defaults": activatorDefaults.value
        }, {
          default: () => [vue.createVNode(VListGroupActivator, null, {
            default: () => [slots.activator({
              props: activatorProps.value,
              isOpen: isOpen.value
            })]
          })]
        }), vue.createVNode(MaybeTransition, {
          "transition": {
            component: VExpandTransition
          },
          "disabled": !isBooted.value
        }, {
          default: () => [renderWhenClosed.value ? vue.withDirectives(vue.createElementVNode("div", {
            "class": "v-list-group__items",
            "role": "group",
            "aria-labelledby": id.value
          }, [slots.default?.()]), [[vue.vShow, isOpen.value]]) : isOpen.value && vue.createElementVNode("div", {
            "class": "v-list-group__items",
            "role": "group",
            "aria-labelledby": id.value
          }, [slots.default?.()])]
        })]
      }));
      return {
        isOpen
      };
    }
  });

  const makeVListItemSubtitleProps = propsFactory({
    opacity: [Number, String],
    ...makeComponentProps(),
    ...makeTagProps()
  }, 'VListItemSubtitle');
  const VListItemSubtitle = genericComponent()({
    name: 'VListItemSubtitle',
    props: makeVListItemSubtitleProps(),
    setup(props, {
      slots
    }) {
      useRender(() => vue.createVNode(props.tag, {
        "class": vue.normalizeClass(['v-list-item-subtitle', props.class]),
        "style": vue.normalizeStyle([{
          '--v-list-item-subtitle-opacity': props.opacity
        }, props.style])
      }, slots));
      return {};
    }
  });

  // Utilities
  const VListItemTitle = createSimpleFunctional('v-list-item-title');

  // Types

  const makeVListItemProps = propsFactory({
    active: {
      type: Boolean,
      default: undefined
    },
    activeClass: String,
    /* @deprecated */
    activeColor: String,
    appendAvatar: String,
    appendIcon: IconValue,
    baseColor: String,
    disabled: Boolean,
    lines: [Boolean, String],
    link: {
      type: Boolean,
      default: undefined
    },
    nav: Boolean,
    prependAvatar: String,
    prependIcon: IconValue,
    ripple: {
      type: [Boolean, Object],
      default: true
    },
    slim: Boolean,
    prependGap: [Number, String],
    subtitle: {
      type: [String, Number, Boolean],
      default: undefined
    },
    title: {
      type: [String, Number, Boolean],
      default: undefined
    },
    value: null,
    index: Number,
    tabindex: [Number, String],
    onClick: EventProp(),
    onClickOnce: EventProp(),
    ...makeBorderProps(),
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...makeDimensionProps(),
    ...makeElevationProps(),
    ...makeRoundedProps(),
    ...makeRouterProps(),
    ...makeTagProps(),
    ...makeThemeProps(),
    ...makeVariantProps({
      variant: 'text'
    })
  }, 'VListItem');
  const VListItem = genericComponent()({
    name: 'VListItem',
    directives: {
      vRipple: Ripple
    },
    props: makeVListItemProps(),
    emits: {
      click: e => true
    },
    setup(props, {
      attrs,
      slots,
      emit
    }) {
      const link = useLink(props, attrs);
      const rootEl = vue.ref();
      const id = vue.computed(() => props.value === undefined ? link.href.value : props.value);
      const {
        activate,
        isActivated,
        select,
        isOpen,
        isSelected,
        isIndeterminate,
        isGroupActivator,
        root,
        parent,
        openOnSelect,
        scrollToActive,
        id: uid
      } = useNestedItem(id, () => props.disabled, false);
      const list = useList();
      const isActive = vue.computed(() => props.active !== false && (props.active || link.isActive?.value || (root.activatable.value ? isActivated.value : isSelected.value)));
      const isLink = vue.toRef(() => props.link !== false && link.isLink.value);
      const isSelectable = vue.computed(() => !!list && (root.selectable.value || root.activatable.value || props.value != null));
      const isClickable = vue.computed(() => !props.disabled && props.link !== false && (props.link || link.isClickable.value || isSelectable.value));
      const isTracked = vue.computed(() => list && list.navigationStrategy.value === 'track' && props.index !== undefined && list.trackingIndex.value === props.index);
      const role = vue.computed(() => list ? isLink.value ? 'link' : isSelectable.value ? 'option' : 'listitem' : undefined);
      const ariaSelected = vue.computed(() => {
        if (!isSelectable.value) return undefined;
        return root.activatable.value ? isActivated.value : root.selectable.value ? isSelected.value : isActive.value;
      });
      const roundedProps = vue.toRef(() => props.rounded || props.nav);
      const color = vue.toRef(() => props.color ?? props.activeColor);
      const variantProps = vue.toRef(() => ({
        color: isActive.value ? color.value ?? props.baseColor : props.baseColor,
        variant: props.variant
      }));

      // useNestedItem doesn't call register until beforeMount,
      // so this can't be an immediate watcher as we don't know parent yet
      vue.watch(() => link.isActive?.value, val => {
        if (!val) return;
        handleActiveLink();
      });
      vue.watch(isActivated, val => {
        if (!val || !scrollToActive) return;
        rootEl.value?.scrollIntoView({
          block: 'nearest',
          behavior: 'instant'
        });
      });
      vue.watch(isTracked, val => {
        if (!val) return;
        rootEl.value?.scrollIntoView({
          block: 'nearest',
          behavior: 'instant'
        });
      });
      vue.onBeforeMount(() => {
        if (link.isActive?.value) {
          vue.nextTick(() => handleActiveLink());
        }
      });
      function handleActiveLink() {
        if (parent.value != null) {
          root.open(parent.value, true);
        }
        openOnSelect(true);
      }
      const {
        themeClasses
      } = provideTheme(props);
      const {
        borderClasses
      } = useBorder(props);
      const {
        colorClasses,
        colorStyles,
        variantClasses
      } = useVariant(variantProps);
      const {
        densityClasses
      } = useDensity(props);
      const {
        dimensionStyles
      } = useDimension(props);
      const {
        elevationClasses
      } = useElevation(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(roundedProps);
      const lineClasses = vue.toRef(() => props.lines ? `v-list-item--${props.lines}-line` : undefined);
      const rippleOptions = vue.toRef(() => props.ripple !== undefined && !!props.ripple && list?.filterable ? {
        keys: ['Enter']
      } : props.ripple);
      const slotProps = vue.computed(() => ({
        isActive: isActive.value,
        select,
        isOpen: isOpen.value,
        isSelected: isSelected.value,
        isIndeterminate: isIndeterminate.value,
        isDisabled: props.disabled
      }));
      function onClick(e) {
        emit('click', e);
        if (['INPUT', 'TEXTAREA'].includes(e.target?.tagName)) return;
        if (!isClickable.value) return;
        link.navigate.value?.(e);
        if (isGroupActivator) return;
        if (root.activatable.value) {
          activate(!isActivated.value, e);
        } else if (root.selectable.value) {
          select(!isSelected.value, e);
        } else if (props.value != null && !isLink.value) {
          select(!isSelected.value, e);
        }
      }
      function onKeyDown(e) {
        const target = e.target;
        if (['INPUT', 'TEXTAREA'].includes(target.tagName)) return;
        if (e.key === 'Enter' || e.key === ' ' && !list?.filterable) {
          e.preventDefault();
          e.stopPropagation();
          e.target.dispatchEvent(new MouseEvent('click', e));
        }
      }
      useRender(() => {
        const Tag = isLink.value ? 'a' : props.tag;
        const hasTitle = slots.title || props.title != null;
        const hasSubtitle = slots.subtitle || props.subtitle != null;
        const hasAppendMedia = !!(props.appendAvatar || props.appendIcon);
        const hasAppend = !!(hasAppendMedia || slots.append);
        const hasPrependMedia = !!(props.prependAvatar || props.prependIcon);
        const hasPrepend = !!(hasPrependMedia || slots.prepend);
        list?.updateHasPrepend(hasPrepend);
        if (props.activeColor) {
          deprecate('active-color', ['color', 'base-color']);
        }
        return vue.withDirectives(vue.createVNode(Tag, vue.mergeProps(link.linkProps, {
          "ref": rootEl,
          "id": props.index !== undefined && list ? `v-list-item-${list.uid}-${props.index}` : undefined,
          "class": ['v-list-item', {
            'v-list-item--active': isActive.value,
            'v-list-item--disabled': props.disabled,
            'v-list-item--link': isClickable.value,
            'v-list-item--nav': props.nav,
            'v-list-item--prepend': !hasPrepend && list?.hasPrepend.value,
            'v-list-item--slim': props.slim,
            'v-list-item--focus-visible': isTracked.value,
            [`${props.activeClass}`]: props.activeClass && isActive.value
          }, themeClasses.value, borderClasses.value, colorClasses.value, densityClasses.value, elevationClasses.value, lineClasses.value, roundedClasses.value, variantClasses.value, props.class],
          "style": [{
            '--v-list-prepend-gap': convertToUnit(props.prependGap)
          }, colorStyles.value, dimensionStyles.value, roundedStyles.value, props.style],
          "tabindex": props.tabindex ?? (isClickable.value ? list ? -2 : 0 : undefined),
          "aria-selected": ariaSelected.value,
          "role": role.value,
          "onClick": (isClickable.value || props.onClick || props.onClickOnce) && onClick,
          "onKeydown": isClickable.value && !isLink.value && onKeyDown
        }), {
          default: () => [genOverlays(isClickable.value || isActive.value, 'v-list-item'), hasPrepend && vue.createElementVNode("div", {
            "key": "prepend",
            "class": "v-list-item__prepend"
          }, [!slots.prepend ? vue.createElementVNode(vue.Fragment, null, [props.prependAvatar && vue.createVNode(VAvatar, {
            "key": "prepend-avatar",
            "density": props.density,
            "image": props.prependAvatar
          }, null), props.prependIcon && vue.createVNode(VIcon, {
            "key": "prepend-icon",
            "density": props.density,
            "icon": props.prependIcon
          }, null)]) : vue.createVNode(VDefaultsProvider, {
            "key": "prepend-defaults",
            "defaults": {
              VAvatar: {
                density: props.density,
                image: props.prependAvatar
              },
              VIcon: {
                density: props.density,
                icon: props.prependIcon
              },
              VListItemAction: {
                start: true
              },
              VCheckboxBtn: {
                density: props.density
              }
            }
          }, {
            default: () => [slots.prepend?.(slotProps.value)]
          }), vue.createElementVNode("div", {
            "class": "v-list-item__spacer"
          }, null)]), vue.createElementVNode("div", {
            "class": "v-list-item__content",
            "data-no-activator": ""
          }, [hasTitle && vue.createVNode(VListItemTitle, {
            "key": "title"
          }, {
            default: () => [slots.title?.({
              title: props.title
            }) ?? vue.toDisplayString(props.title)]
          }), hasSubtitle && vue.createVNode(VListItemSubtitle, {
            "key": "subtitle"
          }, {
            default: () => [slots.subtitle?.({
              subtitle: props.subtitle
            }) ?? vue.toDisplayString(props.subtitle)]
          }), slots.default?.(slotProps.value)]), hasAppend && vue.createElementVNode("div", {
            "key": "append",
            "class": "v-list-item__append"
          }, [!slots.append ? vue.createElementVNode(vue.Fragment, null, [props.appendIcon && vue.createVNode(VIcon, {
            "key": "append-icon",
            "density": props.density,
            "icon": props.appendIcon
          }, null), props.appendAvatar && vue.createVNode(VAvatar, {
            "key": "append-avatar",
            "density": props.density,
            "image": props.appendAvatar
          }, null)]) : vue.createVNode(VDefaultsProvider, {
            "key": "append-defaults",
            "defaults": {
              VAvatar: {
                density: props.density,
                image: props.appendAvatar
              },
              VIcon: {
                density: props.density,
                icon: props.appendIcon
              },
              VListItemAction: {
                end: true
              },
              VCheckboxBtn: {
                density: props.density
              }
            }
          }, {
            default: () => [slots.append?.(slotProps.value)]
          }), vue.createElementVNode("div", {
            "class": "v-list-item__spacer"
          }, null)])]
        }), [[Ripple, isClickable.value && rippleOptions.value]]);
      });
      return {
        activate,
        isActivated,
        isGroupActivator,
        isSelected,
        list,
        select,
        root,
        id: uid,
        link
      };
    }
  });

  const makeVListSubheaderProps = propsFactory({
    color: String,
    inset: Boolean,
    sticky: Boolean,
    title: String,
    ...makeComponentProps(),
    ...makeTagProps()
  }, 'VListSubheader');
  const VListSubheader = genericComponent()({
    name: 'VListSubheader',
    props: makeVListSubheaderProps(),
    setup(props, {
      slots
    }) {
      const {
        textColorClasses,
        textColorStyles
      } = useTextColor(() => props.color);
      useRender(() => {
        const hasText = !!(slots.default || props.title);
        return vue.createVNode(props.tag, {
          "class": vue.normalizeClass(['v-list-subheader', {
            'v-list-subheader--inset': props.inset,
            'v-list-subheader--sticky': props.sticky
          }, textColorClasses.value, props.class]),
          "style": vue.normalizeStyle([{
            textColorStyles
          }, props.style])
        }, {
          default: () => [hasText && vue.createElementVNode("div", {
            "class": "v-list-subheader__text"
          }, [slots.default?.() ?? props.title])]
        });
      });
      return {};
    }
  });

  // Types

  const makeVListChildrenProps = propsFactory({
    items: Array,
    returnObject: Boolean
  }, 'VListChildren');
  const VListChildren = genericComponent()({
    name: 'VListChildren',
    props: makeVListChildrenProps(),
    setup(props, {
      slots
    }) {
      createList();
      return () => slots.default?.() ?? props.items?.map(({
        children,
        props: itemProps,
        type,
        raw: item
      }, index) => {
        if (type === 'divider') {
          return slots.divider?.({
            props: itemProps
          }) ?? vue.createVNode(VDivider, itemProps, null);
        }
        if (type === 'subheader') {
          return slots.subheader?.({
            props: itemProps
          }) ?? vue.createVNode(VListSubheader, itemProps, null);
        }
        const slotsWithItem = {
          subtitle: slots.subtitle ? slotProps => slots.subtitle?.({
            ...slotProps,
            item
          }) : undefined,
          prepend: slots.prepend ? slotProps => slots.prepend?.({
            ...slotProps,
            item
          }) : undefined,
          append: slots.append ? slotProps => slots.append?.({
            ...slotProps,
            item
          }) : undefined,
          title: slots.title ? slotProps => slots.title?.({
            ...slotProps,
            item
          }) : undefined
        };
        const listGroupProps = VListGroup.filterProps(itemProps);
        return children ? vue.createVNode(VListGroup, vue.mergeProps(listGroupProps, {
          "value": props.returnObject ? item : itemProps?.value,
          "rawId": itemProps?.value
        }), {
          activator: ({
            props: activatorProps
          }) => {
            const listItemProps = vue.mergeProps(itemProps, activatorProps, {
              value: props.returnObject ? item : itemProps.value
            });
            return slots.header ? slots.header({
              props: listItemProps
            }) : vue.createVNode(VListItem, vue.mergeProps(listItemProps, {
              "index": index
            }), slotsWithItem);
          },
          default: () => vue.createVNode(VListChildren, {
            "items": children,
            "returnObject": props.returnObject
          }, slots)
        }) : slots.item ? slots.item({
          props: {
            ...itemProps,
            index
          }
        }) : vue.createVNode(VListItem, vue.mergeProps(itemProps, {
          "index": index,
          "value": props.returnObject ? item : itemProps.value
        }), slotsWithItem);
      });
    }
  });

  // Utilities

  // Types

  // Composables
  const makeItemsProps = propsFactory({
    items: {
      type: Array,
      default: () => []
    },
    itemTitle: {
      type: [String, Array, Function],
      default: 'title'
    },
    itemValue: {
      type: [String, Array, Function],
      default: 'value'
    },
    itemChildren: {
      type: [Boolean, String, Array, Function],
      default: 'children'
    },
    itemProps: {
      type: [Boolean, String, Array, Function],
      default: 'props'
    },
    itemType: {
      type: [Boolean, String, Array, Function],
      default: 'type'
    },
    returnObject: Boolean,
    valueComparator: Function
  }, 'list-items');
  const itemTypes$1 = new Set(['item', 'divider', 'subheader']);
  function transformItem$3(props, item) {
    const title = getPropertyFromItem(item, props.itemTitle, item);
    const value = getPropertyFromItem(item, props.itemValue, title);
    const children = getPropertyFromItem(item, props.itemChildren);
    const itemProps = props.itemProps === true ? typeof item === 'object' && item != null && !Array.isArray(item) ? 'children' in item ? omit(item, ['children']) : item : undefined : getPropertyFromItem(item, props.itemProps);
    let type = getPropertyFromItem(item, props.itemType, 'item');
    if (!itemTypes$1.has(type)) {
      type = 'item';
    }
    const _props = {
      title,
      value,
      ...itemProps
    };
    return {
      type,
      title: String(_props.title ?? ''),
      value: _props.value,
      props: _props,
      children: type === 'item' && Array.isArray(children) ? transformItems$3(props, children) : undefined,
      raw: item
    };
  }
  transformItem$3.neededProps = ['itemTitle', 'itemValue', 'itemChildren', 'itemProps', 'itemType'];
  function transformItems$3(props, items) {
    // avoid reactive access in the loop
    const _props = pick(props, transformItem$3.neededProps);
    const array = [];
    for (const item of items) {
      array.push(transformItem$3(_props, item));
    }
    return array;
  }
  function useItems(props) {
    const items = vue.computed(() => transformItems$3(props, props.items));
    const hasNullItem = vue.computed(() => items.value.some(item => item.value === null));
    const itemsMap = vue.shallowRef(new Map());
    const keylessItems = vue.shallowRef([]);
    vue.watchEffect(() => {
      const _items = items.value;
      const map = new Map();
      const keyless = [];
      for (let i = 0; i < _items.length; i++) {
        const item = _items[i];
        if (isPrimitive(item.value) || item.value === null) {
          let values = map.get(item.value);
          if (!values) {
            values = [];
            map.set(item.value, values);
          }
          values.push(item);
        } else {
          keyless.push(item);
        }
      }
      itemsMap.value = map;
      keylessItems.value = keyless;
    });
    function transformIn(value) {
      // Cache unrefed values outside the loop,
      // proxy getters can be slow when you call them a billion times
      const _items = itemsMap.value;
      const _allItems = items.value;
      const _keylessItems = keylessItems.value;
      const _hasNullItem = hasNullItem.value;
      const _returnObject = props.returnObject;
      const hasValueComparator = !!props.valueComparator;
      const valueComparator = props.valueComparator || deepEqual;
      const _props = pick(props, transformItem$3.neededProps);
      const returnValue = [];
      main: for (const v of value) {
        // When the model value is null, return an InternalItem
        // based on null only if null is one of the items
        if (!_hasNullItem && v === null) continue;

        // String model value means value is a custom input value from combobox
        // Don't look up existing items if the model value is a string
        if (_returnObject && typeof v === 'string') {
          returnValue.push(transformItem$3(_props, v));
          continue;
        }

        // Fast path, items with primitive values and no
        // custom valueComparator can use a constant-time
        // map lookup instead of searching the items array
        const fastItems = _items.get(v);

        // Slow path, always use valueComparator.
        // This is O(n^2) so we really don't want to
        // do it for more than a couple hundred items.
        if (hasValueComparator || !fastItems) {
          for (const item of hasValueComparator ? _allItems : _keylessItems) {
            if (valueComparator(v, item.value)) {
              returnValue.push(item);
              continue main;
            }
          }
          // Not an existing item, construct it from the model (#4000)
          returnValue.push(transformItem$3(_props, v));
          continue;
        }
        returnValue.push(...fastItems);
      }
      return returnValue;
    }
    function transformOut(value) {
      return props.returnObject ? value.map(({
        raw
      }) => raw) : value.map(({
        value
      }) => value);
    }
    return {
      items,
      transformIn,
      transformOut
    };
  }

  // Types

  const itemTypes = new Set(['item', 'divider', 'subheader']);
  function transformItem$2(props, item) {
    const title = isPrimitive(item) ? item : getPropertyFromItem(item, props.itemTitle);
    const value = isPrimitive(item) ? item : getPropertyFromItem(item, props.itemValue, undefined);
    const children = getPropertyFromItem(item, props.itemChildren);
    const itemProps = props.itemProps === true ? omit(item, ['children']) : getPropertyFromItem(item, props.itemProps);
    let type = getPropertyFromItem(item, props.itemType, 'item');
    if (!itemTypes.has(type)) {
      type = 'item';
    }
    const _props = {
      title,
      value,
      ...itemProps
    };
    return {
      type,
      title: _props.title,
      value: _props.value,
      props: _props,
      children: type === 'item' && children ? transformItems$2(props, children) : undefined,
      raw: item
    };
  }
  function transformItems$2(props, items) {
    const array = [];
    for (const item of items) {
      array.push(transformItem$2(props, item));
    }
    return array;
  }
  function useListItems(props) {
    const items = vue.computed(() => transformItems$2(props, props.items));
    return {
      items
    };
  }
  const makeVListProps = propsFactory({
    baseColor: String,
    /* @deprecated */
    activeColor: String,
    activeClass: String,
    bgColor: String,
    disabled: Boolean,
    filterable: Boolean,
    expandIcon: IconValue,
    collapseIcon: IconValue,
    lines: {
      type: [Boolean, String],
      default: 'one'
    },
    slim: Boolean,
    prependGap: [Number, String],
    indent: [Number, String],
    nav: Boolean,
    navigationStrategy: {
      type: String,
      default: 'focus'
    },
    navigationIndex: Number,
    'onClick:open': EventProp(),
    'onClick:select': EventProp(),
    'onUpdate:opened': EventProp(),
    ...makeNestedProps({
      selectStrategy: 'single-leaf',
      openStrategy: 'list'
    }),
    ...makeBorderProps(),
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...makeDimensionProps(),
    ...makeElevationProps(),
    ...makeItemsProps(),
    ...makeRoundedProps(),
    ...makeTagProps(),
    ...makeThemeProps(),
    ...makeVariantProps({
      variant: 'text'
    })
  }, 'VList');
  const VList = genericComponent()({
    name: 'VList',
    props: makeVListProps(),
    emits: {
      'update:selected': value => true,
      'update:activated': value => true,
      'update:opened': value => true,
      'update:navigationIndex': value => true,
      'click:open': value => true,
      'click:activate': value => true,
      'click:select': value => true
    },
    setup(props, {
      attrs,
      slots,
      emit
    }) {
      const {
        items
      } = useListItems(props);
      const {
        themeClasses
      } = provideTheme(props);
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.bgColor);
      const {
        borderClasses
      } = useBorder(props);
      const {
        densityClasses
      } = useDensity(props);
      const {
        dimensionStyles
      } = useDimension(props);
      const {
        elevationClasses
      } = useElevation(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const {
        children,
        open,
        parents,
        select,
        getPath
      } = useNested(props, {
        items,
        returnObject: vue.toRef(() => props.returnObject),
        scrollToActive: vue.toRef(() => props.navigationStrategy === 'track'),
        valueComparator: vue.toRef(() => props.valueComparator)
      });
      const lineClasses = vue.toRef(() => props.lines ? `v-list--${props.lines}-line` : undefined);
      const activeColor = vue.toRef(() => props.activeColor);
      const baseColor = vue.toRef(() => props.baseColor);
      const color = vue.toRef(() => props.color);
      const isSelectable = vue.toRef(() => props.selectable || props.activatable);
      const navigationIndex = useProxiedModel(props, 'navigationIndex', -1, v => v ?? -1);
      const uid = vue.useId();
      createList({
        filterable: props.filterable,
        trackingIndex: navigationIndex,
        navigationStrategy: vue.toRef(() => props.navigationStrategy),
        uid
      });
      vue.watch(items, () => {
        if (props.navigationStrategy === 'track') {
          navigationIndex.value = -1;
        }
      });
      provideDefaults({
        VListGroup: {
          activeColor,
          baseColor,
          color,
          expandIcon: vue.toRef(() => props.expandIcon),
          collapseIcon: vue.toRef(() => props.collapseIcon)
        },
        VListItem: {
          activeClass: vue.toRef(() => props.activeClass),
          activeColor,
          baseColor,
          color,
          density: vue.toRef(() => props.density),
          disabled: vue.toRef(() => props.disabled),
          lines: vue.toRef(() => props.lines),
          nav: vue.toRef(() => props.nav),
          slim: vue.toRef(() => props.slim),
          variant: vue.toRef(() => props.variant),
          tabindex: vue.toRef(() => props.navigationStrategy === 'track' ? -1 : undefined)
        }
      });
      const isFocused = vue.shallowRef(false);
      const contentRef = vue.ref();
      function onFocusin(e) {
        isFocused.value = true;
      }
      function onFocusout(e) {
        isFocused.value = false;
      }
      function onFocus(e) {
        if (props.navigationStrategy === 'track') {
          if (!~navigationIndex.value) {
            navigationIndex.value = getNextIndex('first');
          }
        } else if (!isFocused.value && !(e.relatedTarget && contentRef.value?.contains(e.relatedTarget))) focus();
      }
      function onBlur() {
        if (props.navigationStrategy === 'track') {
          navigationIndex.value = -1;
        }
      }
      function getNavigationDirection(key) {
        switch (key) {
          case 'ArrowDown':
            return 'next';
          case 'ArrowUp':
            return 'prev';
          case 'Home':
            return 'first';
          case 'End':
            return 'last';
          default:
            return null;
        }
      }
      function getNextIndex(direction) {
        const itemCount = items.value.length;
        if (itemCount === 0) return -1;
        let nextIndex;
        if (direction === 'first') {
          nextIndex = 0;
        } else if (direction === 'last') {
          nextIndex = itemCount - 1;
        } else {
          nextIndex = navigationIndex.value + (direction === 'next' ? 1 : -1);
          if (nextIndex < 0) nextIndex = itemCount - 1;
          if (nextIndex >= itemCount) nextIndex = 0;
        }
        const startIndex = nextIndex;
        let attempts = 0;
        while (attempts < itemCount) {
          const item = items.value[nextIndex];
          if (item && item.type !== 'divider' && item.type !== 'subheader') {
            return nextIndex;
          }
          nextIndex += direction === 'next' || direction === 'first' ? 1 : -1;
          if (nextIndex < 0) nextIndex = itemCount - 1;
          if (nextIndex >= itemCount) nextIndex = 0;
          if (nextIndex === startIndex) return -1;
          attempts++;
        }
        return -1;
      }
      function onKeydown(e) {
        const target = e.target;
        if (!contentRef.value || target.tagName === 'INPUT' && ['Home', 'End'].includes(e.key) || target.tagName === 'TEXTAREA') {
          return;
        }
        const direction = getNavigationDirection(e.key);
        if (direction !== null) {
          e.preventDefault();
          if (props.navigationStrategy === 'track') {
            const nextIndex = getNextIndex(direction);
            if (nextIndex !== -1) {
              navigationIndex.value = nextIndex;
            }
          } else {
            focus(direction);
          }
        }
      }
      function onMousedown(e) {
        isFocused.value = true;
      }
      function focus(location, options) {
        if (contentRef.value) {
          return focusChild(contentRef.value, location, options);
        }
      }
      useRender(() => {
        const indent = props.indent ?? (props.prependGap ? Number(props.prependGap) + 24 : undefined);
        const ariaMultiselectable = isSelectable.value ? attrs.ariaMultiselectable ?? !String(props.selectStrategy).startsWith('single-') : undefined;
        return vue.createVNode(props.tag, {
          "ref": contentRef,
          "class": vue.normalizeClass(['v-list', {
            'v-list--disabled': props.disabled,
            'v-list--nav': props.nav,
            'v-list--slim': props.slim
          }, themeClasses.value, backgroundColorClasses.value, borderClasses.value, densityClasses.value, elevationClasses.value, lineClasses.value, roundedClasses.value, props.class]),
          "style": vue.normalizeStyle([{
            '--v-list-indent': convertToUnit(indent),
            '--v-list-group-prepend': indent ? '0px' : undefined,
            '--v-list-prepend-gap': convertToUnit(props.prependGap)
          }, backgroundColorStyles.value, dimensionStyles.value, roundedStyles.value, props.style]),
          "tabindex": props.disabled ? -1 : 0,
          "role": isSelectable.value ? 'listbox' : 'list',
          "aria-activedescendant": props.navigationStrategy === 'track' && navigationIndex.value >= 0 ? `v-list-item-${uid}-${navigationIndex.value}` : undefined,
          "aria-multiselectable": ariaMultiselectable,
          "onFocusin": onFocusin,
          "onFocusout": onFocusout,
          "onFocus": onFocus,
          "onBlur": onBlur,
          "onKeydown": onKeydown,
          "onMousedown": onMousedown
        }, {
          default: () => [vue.createVNode(VListChildren, {
            "items": items.value,
            "returnObject": props.returnObject
          }, slots)]
        });
      });
      return {
        open,
        select,
        focus,
        children,
        parents,
        getPath,
        navigationIndex
      };
    }
  });

  // Utilities
  const VListImg = createSimpleFunctional('v-list-img');

  const makeVListItemActionProps = propsFactory({
    start: Boolean,
    end: Boolean,
    ...makeComponentProps(),
    ...makeTagProps()
  }, 'VListItemAction');
  const VListItemAction = genericComponent()({
    name: 'VListItemAction',
    props: makeVListItemActionProps(),
    setup(props, {
      slots
    }) {
      useRender(() => vue.createVNode(props.tag, {
        "class": vue.normalizeClass(['v-list-item-action', {
          'v-list-item-action--start': props.start,
          'v-list-item-action--end': props.end
        }, props.class]),
        "style": vue.normalizeStyle(props.style)
      }, slots));
      return {};
    }
  });

  const makeVListItemMediaProps = propsFactory({
    start: Boolean,
    end: Boolean,
    ...makeComponentProps(),
    ...makeTagProps()
  }, 'VListItemMedia');
  const VListItemMedia = genericComponent()({
    name: 'VListItemMedia',
    props: makeVListItemMediaProps(),
    setup(props, {
      slots
    }) {
      useRender(() => {
        return vue.createVNode(props.tag, {
          "class": vue.normalizeClass(['v-list-item-media', {
            'v-list-item-media--start': props.start,
            'v-list-item-media--end': props.end
          }, props.class]),
          "style": vue.normalizeStyle(props.style)
        }, slots);
      });
      return {};
    }
  });

  // Types

  /** Convert a point in local space to viewport space */
  function elementToViewport(point, offset) {
    return {
      x: point.x + offset.x,
      y: point.y + offset.y
    };
  }

  /** Get the difference between two points */
  function getOffset$1(a, b) {
    return {
      x: a.x - b.x,
      y: a.y - b.y
    };
  }

  /** Convert an anchor object to a point in local space */
  function anchorToPoint(anchor, box) {
    if (anchor.side === 'top' || anchor.side === 'bottom') {
      const {
        side,
        align
      } = anchor;
      const x = align === 'left' ? 0 : align === 'center' ? box.width / 2 : align === 'right' ? box.width : align;
      const y = side === 'top' ? 0 : side === 'bottom' ? box.height : side;
      return elementToViewport({
        x,
        y
      }, box);
    } else if (anchor.side === 'left' || anchor.side === 'right') {
      const {
        side,
        align
      } = anchor;
      const x = side === 'left' ? 0 : side === 'right' ? box.width : side;
      const y = align === 'top' ? 0 : align === 'center' ? box.height / 2 : align === 'bottom' ? box.height : align;
      return elementToViewport({
        x,
        y
      }, box);
    }
    return elementToViewport({
      x: box.width / 2,
      y: box.height / 2
    }, box);
  }

  // Composables

  // Types

  const locationStrategies = {
    static: staticLocationStrategy,
    // specific viewport position, usually centered
    connected: connectedLocationStrategy // connected to a certain element
  };
  const makeLocationStrategyProps = propsFactory({
    locationStrategy: {
      type: [String, Function],
      default: 'static',
      validator: val => typeof val === 'function' || val in locationStrategies
    },
    location: String,
    origin: {
      type: String,
      default: 'auto'
    },
    offset: [Number, String, Array],
    stickToTarget: Boolean,
    viewportMargin: {
      type: [Number, String],
      default: 12
    }
  }, 'VOverlay-location-strategies');
  function useLocationStrategies(props, data) {
    const contentStyles = vue.ref({});
    const updateLocation = vue.ref();
    if (IN_BROWSER) {
      useToggleScope(() => !!(data.isActive.value && props.locationStrategy), reset => {
        vue.watch(() => props.locationStrategy, reset);
        vue.onScopeDispose(() => {
          window.removeEventListener('resize', onResize);
          visualViewport?.removeEventListener('resize', onVisualResize);
          visualViewport?.removeEventListener('scroll', onVisualScroll);
          updateLocation.value = undefined;
          if (data.isActive.value) {
            contentStyles.value = {};
          }
        });
        window.addEventListener('resize', onResize, {
          passive: true
        });
        visualViewport?.addEventListener('resize', onVisualResize, {
          passive: true
        });
        visualViewport?.addEventListener('scroll', onVisualScroll, {
          passive: true
        });
        if (typeof props.locationStrategy === 'function') {
          updateLocation.value = props.locationStrategy(data, props, contentStyles)?.updateLocation;
        } else {
          updateLocation.value = locationStrategies[props.locationStrategy](data, props, contentStyles)?.updateLocation;
        }
      });
    }
    function onResize(e) {
      updateLocation.value?.(e);
    }
    function onVisualResize(e) {
      updateLocation.value?.(e);
    }
    function onVisualScroll(e) {
      updateLocation.value?.(e);
    }
    return {
      contentStyles,
      updateLocation
    };
  }
  function getStaticLocationClasses(location) {
    if (!location) return undefined;
    const normalized = location.includes(' ') ? location : `${location} center`;
    let justify = 'center';
    let align = 'center';
    const inline = {
      left: 'start',
      start: 'start',
      right: 'end',
      end: 'end'
    };
    const block = {
      top: 'start',
      bottom: 'end'
    };
    for (const token of normalized.split(' ')) {
      if (token in inline) justify = inline[token];else if (token in block) align = block[token];
    }
    return {
      [`v-overlay--justify-${justify}`]: true,
      [`v-overlay--align-${align}`]: true
    };
  }
  function staticLocationStrategy(data, props, contentStyles) {
    // Positioning is handled by CSS flexbox alignment on the overlay root, keeping
    // the content's insets `auto` so user utility classes (justify-*, align-*) compose.
    // Here we only forward an explicit `origin` to `transform-origin` for the transition.
    function updateStyles() {
      if (props.origin !== 'auto' && props.origin !== 'overlap') {
        const {
          side,
          align
        } = parseAnchor(props.origin, data.isRtl.value);
        contentStyles.value = {
          transformOrigin: `${side} ${align}`
        };
      } else {
        contentStyles.value = {};
      }
    }
    vue.watch([() => props.origin, data.isRtl], updateStyles, {
      immediate: true
    });
    return {
      updateLocation: () => {}
    };
  }

  /** Resolve a CSS length the browser understands (calc(), min(), vw, …) to pixels */
  function resolveCssLength(value, container, isWidth) {
    const probe = document.createElement('div');
    probe.style.position = 'absolute';
    probe.style.visibility = 'hidden';
    probe.style[isWidth ? 'width' : 'height'] = value;
    container.appendChild(probe);
    const size = isWidth ? probe.offsetWidth : probe.offsetHeight;
    container.removeChild(probe);
    return size > 0 ? size : Infinity;
  }

  /** Get size of element ignoring max-width/max-height */
  function getIntrinsicSize(el, isRtl) {
    // const scrollables = new Map<Element, [number, number]>()
    // el.querySelectorAll('*').forEach(el => {
    //   const x = el.scrollLeft
    //   const y = el.scrollTop
    //   if (x || y) {
    //     scrollables.set(el, [x, y])
    //   }
    // })

    // const initialMaxWidth = el.style.maxWidth
    // const initialMaxHeight = el.style.maxHeight
    // el.style.removeProperty('max-width')
    // el.style.removeProperty('max-height')

    /* eslint-disable-next-line sonarjs/prefer-immediate-return */
    const contentBox = nullifyTransforms(el);
    if (isRtl) {
      contentBox.x += parseFloat(el.style.right || 0);
    } else {
      contentBox.x -= parseFloat(el.style.left || 0);
    }
    contentBox.y -= parseFloat(el.style.top || 0);

    // el.style.maxWidth = initialMaxWidth
    // el.style.maxHeight = initialMaxHeight
    // scrollables.forEach((position, el) => {
    //   el.scrollTo(...position)
    // })

    return contentBox;
  }
  function connectedLocationStrategy(data, props, contentStyles) {
    const activatorFixed = Array.isArray(data.target.value) || isFixedPosition(data.target.value);
    if (activatorFixed) {
      Object.assign(contentStyles.value, {
        position: 'fixed',
        top: 0,
        [data.isRtl.value ? 'right' : 'left']: 0
      });
    }
    const {
      preferredAnchor,
      preferredOrigin
    } = destructComputed(() => {
      const parsedAnchor = parseAnchor(props.location ?? 'bottom', data.isRtl.value);
      const parsedOrigin = props.origin === 'overlap' ? parsedAnchor : props.origin === 'auto' ? flipSide(parsedAnchor) : parseAnchor(props.origin, data.isRtl.value);

      // Some combinations of props may produce an invalid origin
      if (parsedAnchor.side === parsedOrigin.side && parsedAnchor.align === flipAlign(parsedOrigin).align) {
        return {
          preferredAnchor: flipCorner(parsedAnchor),
          preferredOrigin: flipCorner(parsedOrigin)
        };
      } else {
        return {
          preferredAnchor: parsedAnchor,
          preferredOrigin: parsedOrigin
        };
      }
    });
    const [getMinWidth, getMinHeight, getMaxWidth, getMaxHeight] = ['minWidth', 'minHeight', 'maxWidth', 'maxHeight'].map(key => {
      const isWidth = key.endsWith('Width');
      return () => {
        const raw = props[key];
        if (raw == null) return Infinity;
        const container = data.contentEl.value?.parentElement ?? document.documentElement;
        if (typeof raw === 'number' || /^-?[\d.]+(?:px)?$/.test(raw.trim())) {
          return parseFloat(raw);
        }
        if (raw.endsWith('%')) {
          // resolve against the overlay container, like CSS would
          const box = getElementBox(container);
          return parseFloat(raw) * (isWidth ? box.width : box.height) / 100;
        }
        // let the browser resolve viewport units, calc(), min(), max(), clamp(), etc.
        return resolveCssLength(raw, container, isWidth);
      };
    });
    const offset = vue.computed(() => {
      if (Array.isArray(props.offset)) {
        return props.offset;
      }
      if (typeof props.offset === 'string') {
        const offset = props.offset.split(' ').map(parseFloat);
        if (offset.length < 2) offset.push(0);
        return offset;
      }
      return typeof props.offset === 'number' ? [props.offset, 0] : [0, 0];
    });
    let observe = false;
    let lastFrame = -1;
    const flipped = new CircularBuffer(4);
    const observer = new ResizeObserver(() => {
      if (!observe) return;

      // Detect consecutive frames
      requestAnimationFrame(newTime => {
        if (newTime !== lastFrame) flipped.clear();
        requestAnimationFrame(newNewTime => {
          lastFrame = newNewTime;
        });
      });
      if (flipped.isFull) {
        const values = flipped.values();
        if (deepEqual(values.at(-1), values.at(-3)) && !deepEqual(values.at(-1), values.at(-2))) {
          // Flipping is causing a container resize loop
          return;
        }
      }
      const result = updateLocation();
      if (result) flipped.push(result.flipped);
    });
    let targetBox = new Box({
      x: 0,
      y: 0,
      width: 0,
      height: 0
    });
    vue.watch(data.target, (newTarget, oldTarget) => {
      if (oldTarget && !Array.isArray(oldTarget)) observer.unobserve(oldTarget);
      if (!Array.isArray(newTarget)) {
        if (newTarget) observer.observe(newTarget);
      } else if (!deepEqual(newTarget, oldTarget)) {
        updateLocation();
      }
    }, {
      immediate: true
    });
    vue.watch(data.contentEl, (newContentEl, oldContentEl) => {
      if (oldContentEl) observer.unobserve(oldContentEl);
      if (newContentEl) observer.observe(newContentEl);
    }, {
      immediate: true
    });
    vue.onScopeDispose(() => {
      observer.disconnect();
    });

    // eslint-disable-next-line max-statements
    function updateLocation() {
      observe = false;
      requestAnimationFrame(() => observe = true);
      if (!data.target.value || !data.contentEl.value) return;
      if (Array.isArray(data.target.value) || data.target.value.offsetParent || data.target.value.getClientRects().length) {
        targetBox = getTargetBox(data.target.value);
      } // Otherwise target element is hidden, use last known value

      const contentBox = getIntrinsicSize(data.contentEl.value, data.isRtl.value);
      const scrollParents = getScrollParents(data.contentEl.value);
      const viewportMargin = Number(props.viewportMargin);
      const minWidth = getMinWidth();
      const minHeight = getMinHeight();
      const maxWidth = getMaxWidth();
      const maxHeight = getMaxHeight();
      if (!scrollParents.length) {
        scrollParents.push(document.documentElement);
        if (!(data.contentEl.value.style.top && data.contentEl.value.style.left)) {
          contentBox.x -= parseFloat(document.documentElement.style.getPropertyValue('--v-body-scroll-x') || 0);
          contentBox.y -= parseFloat(document.documentElement.style.getPropertyValue('--v-body-scroll-y') || 0);
        }
      }
      const viewport = scrollParents.reduce((box, el) => {
        const scrollBox = getElementBox(el);
        if (box) {
          return new Box({
            x: Math.max(box.left, scrollBox.left),
            y: Math.max(box.top, scrollBox.top),
            width: Math.min(box.right, scrollBox.right) - Math.max(box.left, scrollBox.left),
            height: Math.min(box.bottom, scrollBox.bottom) - Math.max(box.top, scrollBox.top)
          });
        }
        return scrollBox;
      }, undefined);
      if (props.stickToTarget) {
        viewport.x += Math.min(viewportMargin, targetBox.x);
        viewport.y += Math.min(viewportMargin, targetBox.y);
        viewport.width = Math.max(viewport.width - viewportMargin * 2, targetBox.x + targetBox.width - viewportMargin);
        viewport.height = Math.max(viewport.height - viewportMargin * 2, targetBox.y + targetBox.height - viewportMargin);
      } else {
        viewport.x += viewportMargin;
        viewport.y += viewportMargin;
        viewport.width -= viewportMargin * 2;
        viewport.height -= viewportMargin * 2;
      }
      let placement = {
        anchor: preferredAnchor.value,
        origin: preferredOrigin.value
      };
      function checkOverflow(_placement) {
        const box = new Box(contentBox);
        const targetPoint = anchorToPoint(_placement.anchor, targetBox);
        const contentPoint = anchorToPoint(_placement.origin, box);
        let {
          x,
          y
        } = getOffset$1(targetPoint, contentPoint);
        switch (_placement.anchor.side) {
          case 'top':
            y -= offset.value[0];
            break;
          case 'bottom':
            y += offset.value[0];
            break;
          case 'left':
            x -= offset.value[0];
            break;
          case 'right':
            x += offset.value[0];
            break;
        }
        switch (_placement.anchor.align) {
          case 'top':
            y -= offset.value[1];
            break;
          case 'bottom':
            y += offset.value[1];
            break;
          case 'left':
            x -= offset.value[1];
            break;
          case 'right':
            x += offset.value[1];
            break;
        }
        box.x += x;
        box.y += y;
        box.width = Math.min(box.width, maxWidth);
        box.height = Math.min(box.height, maxHeight);
        const overflows = getOverflow(box, viewport);
        return {
          overflows,
          x,
          y
        };
      }
      let x = 0;
      let y = 0;
      const available = {
        x: 0,
        y: 0
      };
      const flipped = {
        x: false,
        y: false
      };
      let resets = -1;
      while (true) {
        if (resets++ > 10) {
          consoleError('Infinite loop detected in connectedLocationStrategy');
          break;
        }
        const {
          x: _x,
          y: _y,
          overflows
        } = checkOverflow(placement);
        x += _x;
        y += _y;
        contentBox.x += _x;
        contentBox.y += _y;

        // flip
        {
          const axis = getAxis(placement.anchor);
          const hasOverflowX = overflows.x.before || overflows.x.after;
          const hasOverflowY = overflows.y.before || overflows.y.after;
          let reset = false;
          ['x', 'y'].forEach(key => {
            if (key === 'x' && hasOverflowX && !flipped.x || key === 'y' && hasOverflowY && !flipped.y) {
              const newPlacement = {
                anchor: {
                  ...placement.anchor
                },
                origin: {
                  ...placement.origin
                }
              };
              const flip = key === 'x' ? axis === 'y' ? flipAlign : flipSide : axis === 'y' ? flipSide : flipAlign;
              newPlacement.anchor = flip(newPlacement.anchor);
              newPlacement.origin = flip(newPlacement.origin);
              const {
                overflows: newOverflows
              } = checkOverflow(newPlacement);
              if (newOverflows[key].before <= overflows[key].before && newOverflows[key].after <= overflows[key].after || newOverflows[key].before + newOverflows[key].after < (overflows[key].before + overflows[key].after) / 2) {
                placement = newPlacement;
                reset = flipped[key] = true;
              }
            }
          });
          if (reset) continue;
        }

        // shift
        if (overflows.x.before) {
          x += overflows.x.before;
          contentBox.x += overflows.x.before;
        }
        if (overflows.x.after) {
          x -= overflows.x.after;
          contentBox.x -= overflows.x.after;
        }
        if (overflows.y.before) {
          y += overflows.y.before;
          contentBox.y += overflows.y.before;
        }
        if (overflows.y.after) {
          y -= overflows.y.after;
          contentBox.y -= overflows.y.after;
        }

        // size
        {
          const overflows = getOverflow(contentBox, viewport);
          available.x = viewport.width - overflows.x.before - overflows.x.after;
          available.y = viewport.height - overflows.y.before - overflows.y.after;
          x += overflows.x.before;
          contentBox.x += overflows.x.before;
          y += overflows.y.before;
          contentBox.y += overflows.y.before;
        }
        break;
      }
      const axis = getAxis(placement.anchor);
      const transformOrigin = props.origin !== 'auto' && props.origin !== 'overlap' ? parseAnchor(props.origin, data.isRtl.value) : placement.origin;
      Object.assign(contentStyles.value, {
        '--v-overlay-anchor-origin': `${placement.anchor.side} ${placement.anchor.align}`,
        transformOrigin: `${transformOrigin.side} ${transformOrigin.align}`,
        // transform: `translate(${pixelRound(x)}px, ${pixelRound(y)}px)`,
        top: convertToUnit(pixelRound(y)),
        left: data.isRtl.value ? undefined : convertToUnit(pixelRound(x)),
        right: data.isRtl.value ? convertToUnit(pixelRound(-x)) : undefined,
        minWidth: convertToUnit(axis === 'y' ? Math.min(minWidth, targetBox.width) : minWidth),
        maxWidth: convertToUnit(pixelCeil(clamp(available.x, minWidth === Infinity ? 0 : minWidth, maxWidth))),
        maxHeight: convertToUnit(pixelCeil(clamp(available.y, minHeight === Infinity ? 0 : minHeight, maxHeight)))
      });
      return {
        available,
        contentBox,
        flipped
      };
    }
    vue.watch(() => [preferredAnchor.value, preferredOrigin.value, props.origin, props.offset, props.minWidth, props.minHeight, props.maxWidth, props.maxHeight], () => updateLocation());
    vue.nextTick(() => {
      const result = updateLocation();

      // TODO: overflowing content should only require a single updateLocation call
      // Icky hack to make sure the content is positioned consistently
      if (!result) return;
      const {
        available,
        contentBox
      } = result;
      if (contentBox.height > available.y) {
        requestAnimationFrame(() => {
          updateLocation();
          requestAnimationFrame(() => {
            updateLocation();
          });
        });
      }
    });
    return {
      updateLocation
    };
  }
  function pixelRound(val) {
    return Math.round(val * devicePixelRatio) / devicePixelRatio;
  }
  function pixelCeil(val) {
    return Math.ceil(val * devicePixelRatio) / devicePixelRatio;
  }

  let clean = true;
  const frames = [];

  /**
   * Schedule a task to run in an animation frame on its own
   * This is useful for heavy tasks that may cause jank if all ran together
   */
  function requestNewFrame(cb) {
    if (!clean || frames.length) {
      frames.push(cb);
      run();
    } else {
      clean = false;
      cb();
      run();
    }
  }
  let raf = -1;
  function run() {
    cancelAnimationFrame(raf);
    raf = requestAnimationFrame(() => {
      const frame = frames.shift();
      if (frame) frame();
      if (frames.length) run();else clean = true;
    });
  }

  // Utilities

  // Types

  const scrollStrategies = {
    none: null,
    close: closeScrollStrategy,
    block: blockScrollStrategy,
    reposition: repositionScrollStrategy
  };
  const makeScrollStrategyProps = propsFactory({
    scrollStrategy: {
      type: [String, Function],
      default: 'block',
      validator: val => typeof val === 'function' || val in scrollStrategies
    }
  }, 'VOverlay-scroll-strategies');
  function useScrollStrategies(props, data) {
    if (!IN_BROWSER) return;
    let scope;
    vue.watchEffect(async () => {
      scope?.stop();
      if (!(data.isActive.value && props.scrollStrategy)) return;
      scope = vue.effectScope();
      await new Promise(resolve => setTimeout(resolve));
      scope.active && scope.run(() => {
        if (typeof props.scrollStrategy === 'function') {
          props.scrollStrategy(data, props, scope);
        } else {
          scrollStrategies[props.scrollStrategy]?.(data, props, scope);
        }
      });
    });
    vue.onScopeDispose(() => {
      scope?.stop();
    });
  }
  function closeScrollStrategy(data) {
    function onScroll(e) {
      data.isActive.value = false;
    }
    bindScroll(getTargetEl(data.target.value, data.contentEl.value), onScroll);
  }
  function blockScrollStrategy(data, props) {
    const offsetParent = data.root.value?.offsetParent;
    const target = getTargetEl(data.target.value, data.contentEl.value);
    const scrollElements = [...new Set([...getScrollParents(target, props.contained ? offsetParent : undefined), ...getScrollParents(data.contentEl.value, props.contained ? offsetParent : undefined)])].filter(el => !el.classList.contains('v-overlay-scroll-blocked'));
    const scrollbarWidth = window.innerWidth - document.documentElement.offsetWidth;
    const scrollableParent = (el => hasScrollbar(el) && el)(offsetParent || document.documentElement);
    if (scrollableParent) {
      data.root.value.classList.add('v-overlay--scroll-blocked');
    }
    scrollElements.forEach((el, i) => {
      el.style.setProperty('--v-body-scroll-x', convertToUnit(-el.scrollLeft));
      el.style.setProperty('--v-body-scroll-y', convertToUnit(-el.scrollTop));
      if (el !== document.documentElement || getComputedStyle(el).overflowY !== 'scroll') {
        el.style.setProperty('--v-scrollbar-offset', convertToUnit(scrollbarWidth));
      }
      el.classList.add('v-overlay-scroll-blocked');
    });
    vue.onScopeDispose(() => {
      scrollElements.forEach((el, i) => {
        const x = parseFloat(el.style.getPropertyValue('--v-body-scroll-x'));
        const y = parseFloat(el.style.getPropertyValue('--v-body-scroll-y'));
        const scrollBehavior = el.style.scrollBehavior;
        el.style.scrollBehavior = 'auto';
        el.style.removeProperty('--v-body-scroll-x');
        el.style.removeProperty('--v-body-scroll-y');
        el.style.removeProperty('--v-scrollbar-offset');
        el.classList.remove('v-overlay-scroll-blocked');
        el.scrollLeft = -x;
        el.scrollTop = -y;
        el.style.scrollBehavior = scrollBehavior;
      });
      if (scrollableParent) {
        data.root.value.classList.remove('v-overlay--scroll-blocked');
      }
    });
  }
  function repositionScrollStrategy(data, props, scope) {
    let slow = false;
    let raf = -1;
    let ric = -1;
    function update(e) {
      requestNewFrame(() => {
        const start = performance.now();
        data.updateLocation.value?.(e);
        const time = performance.now() - start;
        slow = time / (1000 / 60) > 2;
      });
    }
    ric = (typeof requestIdleCallback === 'undefined' ? cb => cb() : requestIdleCallback)(() => {
      scope.run(() => {
        bindScroll(getTargetEl(data.target.value, data.contentEl.value), e => {
          if (slow) {
            // If the position calculation is slow,
            // defer updates until scrolling is finished.
            // Browsers usually fire one scroll event per frame so
            // we just wait until we've got two frames without an event
            cancelAnimationFrame(raf);
            raf = requestAnimationFrame(() => {
              raf = requestAnimationFrame(() => {
                update(e);
              });
            });
          } else {
            update(e);
          }
        });
      });
    });
    vue.onScopeDispose(() => {
      typeof cancelIdleCallback !== 'undefined' && cancelIdleCallback(ric);
      cancelAnimationFrame(raf);
    });
  }
  function getTargetEl(target, contentEl) {
    return Array.isArray(target) ? document.elementsFromPoint(...target).find(el => !contentEl?.contains(el)) : target ?? contentEl;
  }
  function bindScroll(el, onScroll) {
    const scrollElements = [document, ...getScrollParents(el)];
    scrollElements.forEach(el => {
      el.addEventListener('scroll', onScroll, {
        passive: true
      });
    });
    vue.onScopeDispose(() => {
      scrollElements.forEach(el => {
        el.removeEventListener('scroll', onScroll);
      });
    });
  }

  // Types

  const VMenuSymbol = Symbol.for('vuetify:v-menu');

  // Utilities

  // Types

  // Composables
  const makeDelayProps = propsFactory({
    closeDelay: [Number, String],
    openDelay: [Number, String]
  }, 'delay');
  function useDelay(props, cb) {
    let clearDelay = () => {};
    function runDelay(isOpening, options) {
      clearDelay?.();
      const delay = isOpening ? props.openDelay : props.closeDelay;
      const normalizedDelay = Math.max(options?.minDelay ?? 0, Number(delay ?? 0));
      return new Promise(resolve => {
        clearDelay = defer(normalizedDelay, () => {
          cb?.(isOpening);
          resolve(isOpening);
        });
      });
    }
    function runOpenDelay() {
      return runDelay(true);
    }
    function runCloseDelay(options) {
      return runDelay(false, options);
    }
    return {
      clearDelay,
      runOpenDelay,
      runCloseDelay
    };
  }

  // Components

  // Types

  const makeActivatorProps = propsFactory({
    target: [String, Object],
    activator: [String, Object],
    activatorProps: {
      type: Object,
      default: () => ({})
    },
    openOnClick: {
      type: Boolean,
      default: undefined
    },
    openOnHover: Boolean,
    openOnFocus: {
      type: Boolean,
      default: undefined
    },
    closeOnContentClick: Boolean,
    ...makeDelayProps()
  }, 'VOverlay-activator');
  function useActivator(props, {
    isActive,
    isTop,
    contentEl
  }) {
    const vm = getCurrentInstance('useActivator');
    const activatorEl = vue.ref();
    let isHovered = false;
    let isFocused = false;
    let firstEnter = true;
    const openOnFocus = vue.computed(() => props.openOnFocus || props.openOnFocus == null && props.openOnHover);
    const openOnClick = vue.computed(() => props.openOnClick || props.openOnClick == null && !props.openOnHover && !openOnFocus.value);
    const {
      runOpenDelay,
      runCloseDelay
    } = useDelay(props, value => {
      if (value === (props.openOnHover && isHovered || openOnFocus.value && isFocused) && !(props.openOnHover && isActive.value && !isTop.value)) {
        if (isActive.value !== value) {
          firstEnter = true;
        }
        isActive.value = value;
      }
    });
    let reopenLock = false;
    vue.watch(isActive, v => {
      if (v) return;
      reopenLock = true;
      setTimeout(() => reopenLock = false, 50);
    });
    const cursorTarget = vue.ref();
    const availableEvents = {
      onClick: e => {
        if (reopenLock && !isActive.value) return;
        e.stopPropagation();
        activatorEl.value = e.currentTarget || e.target;
        if (!isActive.value) {
          cursorTarget.value = [e.clientX, e.clientY];
        }
        isActive.value = !isActive.value;
      },
      onMouseenter: e => {
        isHovered = true;
        activatorEl.value = e.currentTarget || e.target;
        if (props.target === 'cursor') {
          cursorTarget.value = [e.clientX, e.clientY];
        }
        runOpenDelay();
      },
      onMousemove: e => {
        cursorTarget.value = [e.clientX, e.clientY];
      },
      onMouseleave: e => {
        isHovered = false;
        if (props.target === 'cursor') isFocused = false;
        runCloseDelay();
      },
      onFocus: e => {
        if (reopenLock) return;
        if (matchesSelector(e.target, ':focus-visible') === false) return;
        isFocused = true;
        e.stopPropagation();
        activatorEl.value = e.currentTarget || e.target;
        runOpenDelay();
      },
      onBlur: e => {
        // Body parks from clicks on empty areas inside content also count as "still focused".
        const next = e.relatedTarget;
        if (!next || contentEl.value?.contains(next)) return;
        isFocused = false;
        e.stopPropagation();
        runCloseDelay({
          minDelay: 1
        });
      }
    };
    const activatorEvents = vue.computed(() => {
      const events = {};
      if (openOnClick.value) {
        events.onClick = availableEvents.onClick;
      }
      if (props.openOnHover) {
        events.onMouseenter = availableEvents.onMouseenter;
        events.onMouseleave = availableEvents.onMouseleave;
        if (props.target === 'cursor' && !openOnClick.value) {
          events.onMousemove = availableEvents.onMousemove;
        }
      }
      if (openOnFocus.value) {
        events.onFocus = availableEvents.onFocus;
        events.onBlur = availableEvents.onBlur;
      }
      return events;
    });
    const contentEvents = vue.computed(() => {
      const events = {};
      if (props.openOnHover) {
        events.onMouseenter = () => {
          isHovered = true;
          runOpenDelay();
        };
        events.onMouseleave = () => {
          isHovered = false;
          runCloseDelay();
        };
      }
      if (openOnFocus.value) {
        events.onFocusin = e => {
          if (!e.target.matches(':focus-visible')) return;
          isFocused = true;
          runOpenDelay();
        };
        events.onFocusout = e => {
          const next = e.relatedTarget;
          if (!next || contentEl.value?.contains(next)) return;
          isFocused = false;
          runCloseDelay({
            minDelay: 1
          });
        };
      }
      if (props.closeOnContentClick) {
        const menu = vue.inject(VMenuSymbol, null);
        events.onClick = () => {
          isActive.value = false;
          menu?.closeParents();
        };
      }
      return events;
    });
    const scrimEvents = vue.computed(() => {
      const events = {};
      if (props.openOnHover) {
        events.onMouseenter = () => {
          if (firstEnter) {
            isHovered = true;
            firstEnter = false;
            runOpenDelay();
          }
        };
        events.onMouseleave = () => {
          isHovered = false;
          runCloseDelay();
        };
      }
      return events;
    });
    vue.watch(isTop, val => {
      if (val && (props.openOnHover && !isHovered && (!openOnFocus.value || !isFocused) || openOnFocus.value && !isFocused && (!props.openOnHover || !isHovered)) && !contentEl.value?.contains(getActiveElement())) {
        runCloseDelay();
      }
    });
    vue.watch(isActive, val => {
      if (!val) {
        setTimeout(() => {
          cursorTarget.value = undefined;
        });
      }
    }, {
      flush: 'post'
    });
    const activatorRef = templateRef();
    vue.watchEffect(() => {
      if (!activatorRef.value) return;
      vue.nextTick(() => {
        activatorEl.value = activatorRef.el;
      });
    });
    const targetRef = templateRef();
    const target = vue.computed(() => {
      if (props.target === 'cursor' && cursorTarget.value) return cursorTarget.value;
      if (targetRef.value) return targetRef.el;
      return getTarget(props.target, vm) || activatorEl.value;
    });
    const targetEl = vue.computed(() => {
      return Array.isArray(target.value) ? undefined : target.value;
    });
    let scope;
    vue.watch(() => !!props.activator, val => {
      if (val && IN_BROWSER) {
        scope = vue.effectScope();
        scope.run(() => {
          _useActivator(props, vm, {
            activatorEl,
            activatorEvents
          });
        });
      } else if (scope) {
        scope.stop();
      }
    }, {
      flush: 'post',
      immediate: true
    });
    vue.onScopeDispose(() => {
      scope?.stop();
    });
    return {
      activatorEl,
      activatorRef,
      target,
      targetEl,
      targetRef,
      activatorEvents,
      contentEvents,
      scrimEvents
    };
  }
  function _useActivator(props, vm, {
    activatorEl,
    activatorEvents
  }) {
    vue.watch(() => props.activator, (val, oldVal) => {
      if (oldVal && val !== oldVal) {
        const activator = getActivator(oldVal);
        activator && unbindActivatorProps(activator);
      }
      if (val) {
        vue.nextTick(() => bindActivatorProps());
      }
    }, {
      immediate: true
    });
    vue.watch(() => props.activatorProps, () => {
      bindActivatorProps();
    });
    vue.onScopeDispose(() => {
      unbindActivatorProps();
    });
    function bindActivatorProps(el = getActivator(), _props = props.activatorProps) {
      if (!el) return;
      bindProps(el, vue.mergeProps(activatorEvents.value, _props));
    }
    function unbindActivatorProps(el = getActivator(), _props = props.activatorProps) {
      if (!el) return;
      unbindProps(el, vue.mergeProps(activatorEvents.value, _props));
    }
    function getActivator(selector = props.activator) {
      const activator = getTarget(selector, vm);

      // The activator should only be a valid element (Ignore comments and text nodes)
      activatorEl.value = activator?.nodeType === Node.ELEMENT_NODE ? activator : undefined;
      return activatorEl.value;
    }
  }
  function getTarget(selector, vm) {
    if (!selector) return;
    let target;
    if (selector === 'parent') {
      let el = vm?.proxy?.$el?.parentNode;
      while (el?.hasAttribute('data-no-activator')) {
        el = el.parentNode;
      }
      target = el;
    } else if (typeof selector === 'string') {
      // Selector
      target = document.querySelector(selector);
    } else if ('$el' in selector) {
      // Component (ref)
      target = selector.$el;
    } else {
      // HTMLElement | Element | [x, y]
      target = selector;
    }
    return target;
  }

  // Utilities

  // Types

  // Types

  // Composables
  const makeFocusTrapProps = propsFactory({
    retainFocus: Boolean,
    captureFocus: Boolean,
    /** @deprecated */
    disableInitialFocus: Boolean
  }, 'focusTrap');
  const registry = new Map();
  let subscribers = 0;
  function lastActiveTrap() {
    let el;
    for (const {
      isActive,
      contentEl
    } of registry.values()) {
      if (isActive.value && contentEl.value) el = contentEl.value;
    }
    return el;
  }
  function onKeydown(e) {
    const activeElement = getActiveElement();
    if (e.key !== 'Tab' || !activeElement) return;
    const parentTraps = Array.from(registry.values()).filter(({
      isActive,
      contentEl
    }) => isActive.value && contentEl.value?.contains(activeElement)).map(x => x.contentEl.value);
    let closestTrap;
    let currentNode = activeElement;
    while (currentNode) {
      if (parentTraps.includes(currentNode)) {
        closestTrap = currentNode;
        break;
      }
      currentNode = currentNode.parentElement;
    }
    if (!closestTrap) {
      const trapEl = lastActiveTrap(); // assuming last registered == topmost panel
      if (!trapEl) return;
      const focusable = focusableChildren(trapEl).filter(x => x.tabIndex >= 0);
      e.preventDefault();
      if (!focusable.length) {
        trapEl.focus({
          preventScroll: true
        });
      } else if (e.shiftKey) {
        focusable[focusable.length - 1].focus();
      } else {
        focusable[0].focus();
      }
      return;
    }
    const focusable = focusableChildren(closestTrap)
    // excluding VListItems with tabindex="-2"
    .filter(x => x.tabIndex >= 0);
    if (!focusable.length) return;
    if (focusable.length === 1 && focusable[0].classList.contains('v-list') && focusable[0].contains(activeElement)) {
      e.preventDefault();
      return;
    }
    const firstElement = focusable[0];
    const lastElement = focusable[focusable.length - 1];

    // contentEl wrapper (tabindex=-1) counts as "before first"
    const atFirst = activeElement === firstElement || activeElement === closestTrap || firstElement.classList.contains('v-list') && firstElement.contains(activeElement);
    const atLast = activeElement === lastElement || lastElement.classList.contains('v-list') && lastElement.contains(activeElement);
    if (e.shiftKey && atFirst) {
      e.preventDefault();
      lastElement.focus();
    }
    if (!e.shiftKey && atLast) {
      e.preventDefault();
      firstElement.focus();
    }
  }
  function useFocusTrap(props, {
    isActive,
    localTop,
    contentEl
  }) {
    const trapId = Symbol('trap');
    let focusTrapSuppressed = false;
    let focusTrapSuppressionTimeout = -1;
    async function onPointerdown() {
      focusTrapSuppressed = true;
      focusTrapSuppressionTimeout = window.setTimeout(() => {
        focusTrapSuppressed = false;
      }, 100);
    }
    async function captureOnFocus(e) {
      const before = e.relatedTarget;
      const after = e.target;
      document.removeEventListener('pointerdown', onPointerdown);
      document.removeEventListener('keydown', captureOnKeydown);
      await new Promise(resolve => requestAnimationFrame(resolve));
      if (isActive.value && !focusTrapSuppressed && before !== after && contentEl.value &&
      // We're the menu without open submenus or overlays
      vue.toValue(localTop) &&
      // It isn't the document or the container body
      ![document, contentEl.value].includes(after) &&
      // It isn't inside the container body
      !contentEl.value.contains(after)) {
        const focusable = focusableChildren(contentEl.value);
        focusable[0]?.focus();
      }
    }
    function captureOnKeydown(e) {
      if (e.key !== 'Tab') return;
      document.removeEventListener('keydown', captureOnKeydown);
      if (isActive.value && contentEl.value && e.target && !contentEl.value.contains(e.target)) {
        const allFocusableElements = focusableChildren(document.documentElement);
        if (e.shiftKey && e.target === allFocusableElements.at(0) || !e.shiftKey && e.target === allFocusableElements.at(-1)) {
          const focusable = focusableChildren(contentEl.value);
          if (focusable.length > 0) {
            e.preventDefault();
            focusable[0].focus();
          }
        }
      }
    }
    const shouldCapture = vue.toRef(() => isActive.value && props.captureFocus && !props.disableInitialFocus);
    if (IN_BROWSER) {
      vue.watch(() => props.retainFocus, val => {
        if (val) {
          registry.set(trapId, {
            isActive,
            contentEl
          });
        } else {
          registry.delete(trapId);
        }
      }, {
        immediate: true
      });
      vue.watch(shouldCapture, val => {
        if (val) {
          document.addEventListener('pointerdown', onPointerdown);
          document.addEventListener('focusin', captureOnFocus, {
            once: true
          });
          document.addEventListener('keydown', captureOnKeydown);
        } else {
          document.removeEventListener('pointerdown', onPointerdown);
          document.removeEventListener('focusin', captureOnFocus);
          document.removeEventListener('keydown', captureOnKeydown);
        }
      }, {
        immediate: true
      });
      if (subscribers++ < 1) {
        document.addEventListener('keydown', onKeydown);
      }
    }
    vue.onScopeDispose(() => {
      registry.delete(trapId);
      if (!IN_BROWSER) return;
      clearTimeout(focusTrapSuppressionTimeout);
      document.removeEventListener('pointerdown', onPointerdown);
      document.removeEventListener('focusin', captureOnFocus);
      document.removeEventListener('keydown', captureOnKeydown);
      if (--subscribers < 1) {
        document.removeEventListener('keydown', onKeydown);
      }
    });
  }

  // Composables
  function useHydration() {
    if (!IN_BROWSER) return vue.shallowRef(false);
    const {
      ssr
    } = useDisplay();
    if (ssr) {
      const isMounted = vue.shallowRef(false);
      vue.onMounted(() => {
        isMounted.value = true;
      });
      return isMounted;
    } else {
      return vue.shallowRef(true);
    }
  }

  // Utilities

  // Types

  const makeLazyProps = propsFactory({
    eager: Boolean
  }, 'lazy');
  function useLazy(props, active) {
    const isBooted = vue.shallowRef(false);
    const hasContent = vue.toRef(() => isBooted.value || props.eager || active.value);
    vue.watch(active, () => isBooted.value = true);
    function onAfterLeave() {
      if (!props.eager) isBooted.value = false;
    }
    return {
      isBooted,
      hasContent,
      onAfterLeave
    };
  }

  // Utilities
  function useScopeId() {
    const vm = getCurrentInstance('useScopeId');
    const scopeId = vm.vnode.scopeId;
    return {
      scopeId: scopeId ? {
        [scopeId]: ''
      } : undefined
    };
  }

  // Composables

  // Types

  const StackSymbol = Symbol.for('vuetify:stack');
  const globalStack = vue.reactive([]);
  function useStack(isActive, zIndex, disableGlobalStack) {
    const vm = getCurrentInstance('useStack');
    const createStackEntry = !disableGlobalStack;
    const parent = vue.inject(StackSymbol, undefined);
    const stack = vue.reactive({
      activeChildren: new Set()
    });
    vue.provide(StackSymbol, stack);
    const _zIndex = vue.shallowRef(Number(vue.toValue(zIndex)));
    useToggleScope(isActive, () => {
      const lastZIndex = globalStack.at(-1)?.[1];
      _zIndex.value = lastZIndex ? lastZIndex + 10 : Number(vue.toValue(zIndex));
      if (createStackEntry) {
        globalStack.push([vm.uid, _zIndex.value]);
      }
      parent?.activeChildren.add(vm.uid);
      vue.onScopeDispose(() => {
        if (createStackEntry) {
          const idx = vue.toRaw(globalStack).findIndex(v => v[0] === vm.uid);
          globalStack.splice(idx, 1);
        }
        parent?.activeChildren.delete(vm.uid);
      });
    });
    const globalTop = vue.shallowRef(true);
    if (createStackEntry) {
      vue.watchEffect(() => {
        const _isTop = globalStack.at(-1)?.[0] === vm.uid;
        setTimeout(() => globalTop.value = _isTop);
      });
    }
    const localTop = vue.toRef(() => !stack.activeChildren.size);
    return {
      globalTop: vue.readonly(globalTop),
      localTop,
      stackStyles: vue.toRef(() => ({
        zIndex: _zIndex.value
      }))
    };
  }

  // Utilities
  function useTeleport(target) {
    const teleportTarget = vue.computed(() => {
      const _target = target();
      if (_target === true || !IN_BROWSER) return undefined;
      const targetElement = _target === false ? document.body : typeof _target === 'string' ? document.querySelector(_target) : _target;
      if (targetElement == null) {
        vue.warn(`Unable to locate target ${_target}`);
        return undefined;
      }
      let container = [...targetElement.children].find(el => el.matches('.v-overlay-container'));
      if (!container) {
        container = document.createElement('div');
        container.className = 'v-overlay-container';
        targetElement.appendChild(container);
      }
      return container;
    });
    return {
      teleportTarget
    };
  }

  // Utilities

  // Types

  function defaultConditional() {
    return true;
  }
  function checkEvent(e, el, binding, ignoreActive = false) {
    // The include element callbacks below can be expensive
    // so we should avoid calling them when we're not active.
    // Explicitly check for false to allow fallback compatibility
    // with non-toggleable components
    if (!e || !ignoreActive && checkIsActive(e, binding) === false) return false;

    // If we're clicking inside the shadowroot, then the app root doesn't get the same
    // level of introspection as to _what_ we're clicking. We want to check to see if
    // our target is the shadowroot parent container, and if it is, ignore.
    const root = attachedRoot(el);
    if (typeof ShadowRoot !== 'undefined' && root instanceof ShadowRoot && root.host === e.target) return false;

    // Check if additional elements were passed to be included in check
    // (click must be outside all included elements, if any)
    const elements = (typeof binding.value === 'object' && binding.value.include || (() => []))();
    // Add the root element for the component this directive was defined on
    elements.push(el);

    // Check if it's a click outside our elements, and then if our callback returns true.
    // Non-toggleable components should take action in their callback and return falsy.
    // Toggleable can return true if it wants to deactivate.
    // Note that, because we're in the capture phase, this callback will occur before
    // the bubbling click event on any outside elements.
    return !elements.some(el => el?.contains(e.target));
  }
  function checkIsActive(e, binding) {
    const isActive = typeof binding.value === 'object' && binding.value.closeConditional || defaultConditional;
    return isActive(e);
  }
  function directive(e, el, binding) {
    const handler = typeof binding.value === 'function' ? binding.value : binding.value.handler;

    // Clicks in the Shadow DOM change their target while using setTimeout, so the original target is saved here
    e.shadowTarget = e.target;
    el._clickOutside.lastMousedownWasOutside && checkEvent(e, el, binding) && setTimeout(() => {
      checkIsActive(e, binding) && handler && handler(e);
    }, 0);
  }
  function handleShadow(el, callback) {
    const root = attachedRoot(el);
    callback(document);
    if (typeof ShadowRoot !== 'undefined' && root instanceof ShadowRoot) {
      callback(root);
    }
  }
  const ClickOutside = {
    // [data-app] may not be found
    // if using bind, inserted makes
    // sure that the root element is
    // available, iOS does not support
    // clicks on body
    mounted(el, binding) {
      const onClick = e => directive(e, el, binding);
      const onMousedown = e => {
        // Ignore the active check here so ancestors of the top overlay (e.g. a menu
        // with an open submenu, which isn't localTop) still record that the click
        // landed outside, letting the close cascade propagate. #20003
        el._clickOutside.lastMousedownWasOutside = checkEvent(e, el, binding, true);
      };
      handleShadow(el, app => {
        app.addEventListener('click', onClick, true);
        app.addEventListener('mousedown', onMousedown, true);
      });
      if (!el._clickOutside) {
        el._clickOutside = {
          lastMousedownWasOutside: false
        };
      }
      el._clickOutside[binding.instance.$.uid] = {
        onClick,
        onMousedown
      };
    },
    beforeUnmount(el, binding) {
      if (!el._clickOutside) return;
      handleShadow(el, app => {
        if (!app || !el._clickOutside?.[binding.instance.$.uid]) return;
        const {
          onClick,
          onMousedown
        } = el._clickOutside[binding.instance.$.uid];
        app.removeEventListener('click', onClick, true);
        app.removeEventListener('mousedown', onMousedown, true);
      });
      delete el._clickOutside[binding.instance.$.uid];
    }
  };

  // Types

  const overlayActivators = new WeakMap();
  function Scrim(props) {
    const {
      modelValue,
      color,
      ...rest
    } = props;
    return vue.createVNode(vue.Transition, {
      "name": "fade-transition",
      "appear": true
    }, {
      default: () => [props.modelValue && vue.createElementVNode("div", vue.mergeProps({
        "class": ['v-overlay__scrim', props.color.backgroundColorClasses.value],
        "style": props.color.backgroundColorStyles.value
      }, rest), null)]
    });
  }
  const makeVOverlayProps = propsFactory({
    absolute: Boolean,
    attach: [Boolean, String, Object],
    closeOnBack: {
      type: Boolean,
      default: true
    },
    contained: Boolean,
    contentClass: null,
    contentProps: null,
    disabled: Boolean,
    opacity: [Number, String],
    noClickAnimation: Boolean,
    modelValue: Boolean,
    persistent: Boolean,
    scrim: {
      type: [Boolean, String],
      default: true
    },
    zIndex: {
      type: [Number, String],
      default: 2000
    },
    ...makeActivatorProps(),
    ...makeComponentProps(),
    ...makeDimensionProps(),
    ...makeLazyProps(),
    ...makeLocationStrategyProps(),
    ...makeScrollStrategyProps(),
    ...makeFocusTrapProps(),
    ...makeThemeProps(),
    ...makeTransitionProps()
  }, 'VOverlay');
  const VOverlay = genericComponent()({
    name: 'VOverlay',
    directives: {
      vClickOutside: ClickOutside
    },
    inheritAttrs: false,
    props: {
      _disableGlobalStack: Boolean,
      ...omit(makeVOverlayProps(), ['disableInitialFocus'])
    },
    emits: {
      'click:outside': e => true,
      'update:modelValue': value => true,
      keydown: e => true,
      afterEnter: () => true,
      afterLeave: () => true
    },
    setup(props, {
      slots,
      attrs,
      emit
    }) {
      const vm = getCurrentInstance('VOverlay');
      const root = vue.ref();
      const scrimEl = vue.ref();
      const contentEl = vue.ref();
      const model = useProxiedModel(props, 'modelValue');
      const isActive = vue.computed({
        get: () => model.value,
        set: v => {
          if (!(v && props.disabled)) model.value = v;
        }
      });
      const {
        themeClasses
      } = provideTheme(props);
      const {
        rtlClasses,
        isRtl
      } = useRtl();
      const {
        hasContent,
        onAfterLeave: _onAfterLeave
      } = useLazy(props, isActive);
      const scrimColor = useBackgroundColor(() => {
        return typeof props.scrim === 'string' ? props.scrim : null;
      });
      const {
        globalTop,
        localTop,
        stackStyles
      } = useStack(isActive, () => props.zIndex, props._disableGlobalStack);
      const {
        activatorEl,
        activatorRef,
        target,
        targetEl,
        targetRef,
        activatorEvents,
        contentEvents,
        scrimEvents
      } = useActivator(props, {
        isActive,
        isTop: localTop,
        contentEl
      });
      const {
        teleportTarget
      } = useTeleport(() => {
        const target = props.attach || props.contained;
        if (target) return target;
        const rootNode = activatorEl?.value?.getRootNode() || vm.proxy?.$el?.getRootNode();
        if (rootNode instanceof ShadowRoot) return rootNode;
        return false;
      });
      const {
        dimensionStyles
      } = useDimension(props);
      const isMounted = useHydration();
      const staticLocationClasses = vue.computed(() => {
        return props.locationStrategy === 'static' ? getStaticLocationClasses(props.location) : undefined;
      });
      const {
        scopeId
      } = useScopeId();
      vue.watch(() => props.disabled, v => {
        if (v) isActive.value = false;
      });
      const {
        contentStyles,
        updateLocation
      } = useLocationStrategies(props, {
        isRtl,
        contentEl,
        target,
        isActive
      });
      useScrollStrategies(props, {
        root,
        contentEl,
        targetEl,
        target,
        isActive,
        updateLocation
      });
      function onClickOutside(e) {
        emit('click:outside', e);
        if (!props.persistent) isActive.value = false;else animateClick();
      }
      function closeConditional(e) {
        return isActive.value && localTop.value && (
        // If using scrim, only close if clicking on it rather than anything opened on top
        !props.scrim || e.target === scrimEl.value || e instanceof MouseEvent && e.shadowTarget === scrimEl.value);
      }
      useFocusTrap(props, {
        isActive,
        localTop,
        contentEl
      });
      let openedWithActivatorFocus = false;
      vue.watchEffect(() => {
        if (!contentEl.value) return;
        if (activatorEl.value) overlayActivators.set(contentEl.value, activatorEl.value);else overlayActivators.delete(contentEl.value);
      });
      function ownsFocus(activeElement) {
        let current = activeElement;
        const visited = new Set();
        while (current) {
          const el = current.closest('.v-overlay__content');
          if (!el || visited.has(el)) return false;
          if (el === contentEl.value) return true;
          visited.add(el);
          current = overlayActivators.get(el) ?? null;
        }
        return false;
      }
      function returnFocusToActivator() {
        const el = activatorEl.value;
        if (!el || !el.isConnected) return;
        // Skip submenus; the outermost close in the cascade will restore focus.
        if (el.closest('.v-overlay__content')) return;
        if (contentEl.value?._clickOutside?.lastMousedownWasOutside) return;
        const activeEl = getActiveElement();
        const focusWasInOverlay = (!activeEl || activeEl === document.body) && openedWithActivatorFocus || activeEl === el || el.contains(activeEl) || ownsFocus(activeEl);
        if (!focusWasInOverlay) return;
        const parent = el.parentElement;
        const focusableInParent = parent ? focusableChildren(parent) : [];
        let target;
        if (focusableInParent.includes(el)) {
          target = el;
        } else {
          const focusableWithin = focusableChildren(el);
          target = focusableWithin.find(x => x.tagName === 'INPUT' || x.tagName === 'TEXTAREA') ?? focusableWithin[0];
        }
        target?.focus({
          preventScroll: true
        });
      }
      vue.watch(isActive, val => {
        if (val) {
          const activeEl = getActiveElement();
          const el = activatorEl.value;
          openedWithActivatorFocus = !!el && (activeEl === el || el.contains(activeEl));
          // eager reuses contentEl, so the mousedown that opened us would linger until the next one
          if (contentEl.value?._clickOutside) {
            contentEl.value._clickOutside.lastMousedownWasOutside = false;
          }
        } else {
          returnFocusToActivator();
        }
      }, {
        flush: 'post'
      });
      IN_BROWSER && vue.watch(isActive, val => {
        if (val) {
          window.addEventListener('keydown', onKeydown);
        } else {
          window.removeEventListener('keydown', onKeydown);
        }
      }, {
        immediate: true
      });
      vue.onBeforeUnmount(() => {
        if (!IN_BROWSER) return;
        window.removeEventListener('keydown', onKeydown);
      });
      function onKeydown(e) {
        if (e.key === 'Escape' && globalTop.value) {
          if (!contentEl.value?.contains(getActiveElement())) {
            emit('keydown', e);
          }
          if (!props.persistent) {
            isActive.value = false;
            if (contentEl.value?.contains(getActiveElement())) {
              activatorEl.value?.focus();
            }
          } else animateClick();
        }
      }
      function onKeydownSelf(e) {
        if (e.key === 'Escape' && !globalTop.value) return;
        emit('keydown', e);
      }
      const router = useRouter();
      useToggleScope(() => props.closeOnBack, () => {
        useBackButton(router, () => {
          if (globalTop.value && isActive.value) {
            if (!props.persistent) isActive.value = false;else animateClick();
            return false;
          }
          return undefined;
        });
      });
      const top = vue.ref();
      vue.watch(() => isActive.value && (props.absolute || props.contained) && teleportTarget.value == null, val => {
        if (val) {
          const scrollParent = getScrollParent(root.value);
          if (scrollParent && scrollParent !== document.scrollingElement) {
            top.value = scrollParent.scrollTop;
          }
        }
      });

      // Add a quick "bounce" animation to the content
      function animateClick() {
        if (props.noClickAnimation) return;
        contentEl.value && animate(contentEl.value, [{
          transformOrigin: 'center'
        }, {
          transform: 'scale(1.03)'
        }, {
          transformOrigin: 'center'
        }], {
          duration: 150,
          easing: standardEasing
        });
      }
      function onAfterEnter() {
        emit('afterEnter');
      }
      function onAfterLeave() {
        _onAfterLeave();
        emit('afterLeave');
      }
      useRender(() => vue.createElementVNode(vue.Fragment, null, [slots.activator?.({
        isActive: isActive.value,
        targetRef,
        props: vue.mergeProps({
          ref: activatorRef
        }, activatorEvents.value, props.activatorProps)
      }), isMounted.value && hasContent.value && vue.createVNode(vue.Teleport, {
        "disabled": !teleportTarget.value,
        "to": teleportTarget.value
      }, {
        default: () => [vue.createElementVNode("div", vue.mergeProps({
          "class": ['v-overlay', {
            'v-overlay--absolute': props.absolute || props.contained,
            'v-overlay--active': isActive.value,
            'v-overlay--contained': props.contained
          }, staticLocationClasses.value, themeClasses.value, rtlClasses.value, props.class],
          "style": [stackStyles.value, {
            '--v-overlay-opacity': props.opacity,
            top: convertToUnit(top.value)
          }, props.style],
          "ref": root,
          "onKeydown": onKeydownSelf
        }, scopeId, attrs), [vue.createVNode(Scrim, vue.mergeProps({
          "color": scrimColor,
          "modelValue": isActive.value && !!props.scrim,
          "ref": scrimEl
        }, scrimEvents.value), null), vue.createVNode(MaybeTransition, {
          "appear": true,
          "persisted": true,
          "transition": props.transition,
          "target": target.value,
          "onAfterEnter": onAfterEnter,
          "onAfterLeave": onAfterLeave
        }, {
          default: () => [vue.withDirectives(vue.createElementVNode("div", vue.mergeProps({
            "ref": contentEl,
            "class": ['v-overlay__content', props.contentClass],
            "style": [dimensionStyles.value, contentStyles.value]
          }, contentEvents.value, props.contentProps), [slots.default?.({
            isActive
          })]), [[vue.vShow, isActive.value], [ClickOutside, {
            handler: onClickOutside,
            closeConditional,
            include: () => {
              if (!isActive.value) return [];
              return [activatorEl.value,
              // Submenu clicks count as "inside"; clicks in ancestor overlays (e.g. a host dialog) don't.
              ...Array.from(document.querySelectorAll('.v-overlay__content')).filter(ownsFocus)];
            }
          }]])]
        })])]
      })]));
      return {
        activatorEl,
        scrimEl,
        target,
        animateClick,
        contentEl,
        rootEl: root,
        globalTop,
        localTop,
        updateLocation
      };
    }
  });

  // Types

  const makeVMenuProps = propsFactory({
    // TODO
    // disableKeys: Boolean,
    id: String,
    submenu: Boolean,
    ...omit(makeVOverlayProps({
      captureFocus: true,
      closeDelay: 250,
      closeOnContentClick: true,
      locationStrategy: 'connected',
      location: undefined,
      openDelay: 300,
      scrim: false,
      scrollStrategy: 'reposition',
      transition: {
        component: VDialogTransition
      }
    }), ['absolute'])
  }, 'VMenu');
  const VMenu = genericComponent()({
    name: 'VMenu',
    props: makeVMenuProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const isActive = useProxiedModel(props, 'modelValue');
      const {
        scopeId
      } = useScopeId();
      const {
        isRtl
      } = useRtl();
      const uid = vue.useId();
      const id = vue.toRef(() => props.id || `v-menu-${uid}`);
      const overlay = vue.ref();
      const parent = vue.inject(VMenuSymbol, null);
      const openChildren = vue.shallowRef(new Set());
      vue.provide(VMenuSymbol, {
        register() {
          openChildren.value.add(uid);
        },
        unregister() {
          openChildren.value.delete(uid);
        },
        closeParents(e) {
          const clickedOutside = !e || overlay.value?.contentEl?._clickOutside?.lastMousedownWasOutside;
          setTimeout(() => {
            if (!openChildren.value.size && !props.persistent && clickedOutside) {
              isActive.value = false;
              parent?.closeParents(e);
            }
          }, 40);
        }
      });
      vue.onBeforeUnmount(() => parent?.unregister());
      vue.onDeactivated(() => isActive.value = false);
      vue.watch(isActive, val => {
        val ? parent?.register() : parent?.unregister();
      }, {
        immediate: true
      });
      function onClickOutside(e) {
        parent?.closeParents(e);
      }
      function onKeydown(e) {
        if (props.disabled) return;
        if (e.key === 'Tab') {
          const nextElement = getNextElement(focusableChildren(overlay.value?.contentEl, false), e.shiftKey ? 'prev' : 'next', el => el.tabIndex >= 0);
          if (!nextElement && !props.retainFocus) {
            isActive.value = false;
          }
        } else if (props.submenu && e.key === (isRtl.value ? 'ArrowRight' : 'ArrowLeft')) {
          isActive.value = false;
        }
      }
      function onActivatorKeydown(e) {
        if (props.disabled || e.isComposing) return;
        const el = overlay.value?.contentEl;
        if (el && isActive.value) {
          if (e.key === 'ArrowDown') {
            e.preventDefault();
            e.stopImmediatePropagation();
            focusChild(el, 'next');
          } else if (e.key === 'ArrowUp') {
            e.preventDefault();
            e.stopImmediatePropagation();
            focusChild(el, 'prev');
          } else if (props.submenu) {
            if (e.key === (isRtl.value ? 'ArrowRight' : 'ArrowLeft')) {
              isActive.value = false;
            } else if (e.key === (isRtl.value ? 'ArrowLeft' : 'ArrowRight')) {
              e.preventDefault();
              focusChild(el, 'first');
            }
          }
        } else if (props.submenu ? e.key === (isRtl.value ? 'ArrowLeft' : 'ArrowRight') : ['ArrowDown', 'ArrowUp'].includes(e.key)) {
          isActive.value = true;
          e.preventDefault();
          setTimeout(() => setTimeout(() => onActivatorKeydown(e)));
        }
      }
      const activatorProps = vue.computed(() => vue.mergeProps({
        'aria-haspopup': 'menu',
        'aria-expanded': String(isActive.value),
        'aria-controls': id.value,
        'aria-owns': id.value,
        onKeydown: onActivatorKeydown
      }, props.activatorProps));
      useRender(() => {
        const overlayProps = VOverlay.filterProps(props);
        return vue.createVNode(VOverlay, vue.mergeProps({
          "ref": overlay,
          "id": id.value,
          "class": ['v-menu', props.class],
          "style": props.style
        }, overlayProps, {
          "modelValue": isActive.value,
          "onUpdate:modelValue": $event => isActive.value = $event,
          "absolute": true,
          "activatorProps": activatorProps.value,
          "location": props.location ?? (props.submenu ? 'end' : 'bottom'),
          "onClick:outside": onClickOutside,
          "onKeydown": onKeydown
        }, scopeId), {
          activator: slots.activator,
          default: (...args) => vue.createVNode(VDefaultsProvider, {
            "root": "VMenu"
          }, {
            default: () => [slots.default?.(...args)]
          })
        });
      });
      return forwardRefs({
        id,
        ΨopenChildren: openChildren
      }, overlay);
    }
  });

  const makeVSheetProps = propsFactory({
    color: String,
    ...makeBorderProps(),
    ...makeComponentProps(),
    ...makeDimensionProps(),
    ...makeElevationProps(),
    ...makeLocationProps(),
    ...makePositionProps(),
    ...makeRoundedProps(),
    ...makeTagProps(),
    ...makeThemeProps()
  }, 'VSheet');
  const VSheet = genericComponent()({
    name: 'VSheet',
    props: makeVSheetProps(),
    setup(props, {
      slots
    }) {
      const {
        themeClasses
      } = provideTheme(props);
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.color);
      const {
        borderClasses
      } = useBorder(props);
      const {
        dimensionStyles
      } = useDimension(props);
      const {
        elevationClasses
      } = useElevation(props);
      const {
        locationStyles
      } = useLocation(props);
      const {
        positionClasses
      } = usePosition(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      useRender(() => vue.createVNode(props.tag, {
        "class": vue.normalizeClass(['v-sheet', themeClasses.value, backgroundColorClasses.value, borderClasses.value, elevationClasses.value, positionClasses.value, roundedClasses.value, props.class]),
        "style": vue.normalizeStyle([backgroundColorStyles.value, dimensionStyles.value, locationStyles.value, roundedStyles.value, props.style])
      }, slots));
      return {};
    }
  });

  // Types

  const makeVCounterProps = propsFactory({
    active: Boolean,
    disabled: Boolean,
    max: [Number, String],
    value: {
      type: [Number, String],
      default: 0
    },
    ...makeComponentProps(),
    ...makeTransitionProps({
      transition: {
        component: VSlideYTransition
      }
    })
  }, 'VCounter');
  const VCounter = genericComponent()({
    name: 'VCounter',
    functional: true,
    props: makeVCounterProps(),
    setup(props, {
      slots
    }) {
      const counter = vue.toRef(() => {
        return props.max ? `${props.value} / ${props.max}` : String(props.value);
      });
      useRender(() => vue.createVNode(MaybeTransition, {
        "transition": props.transition
      }, {
        default: () => [vue.withDirectives(vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-counter', {
            'text-error': props.max && !props.disabled && parseFloat(props.value) > parseFloat(props.max)
          }, props.class]),
          "style": vue.normalizeStyle(props.style)
        }, [slots.default ? slots.default({
          counter: counter.value,
          max: props.max,
          value: props.value
        }) : counter.value]), [[vue.vShow, props.active]])]
      }));
      return {};
    }
  });

  const makeVFieldLabelProps = propsFactory({
    floating: Boolean,
    ...makeComponentProps()
  }, 'VFieldLabel');
  const VFieldLabel = genericComponent()({
    name: 'VFieldLabel',
    props: makeVFieldLabelProps(),
    setup(props, {
      slots
    }) {
      useRender(() => vue.createVNode(VLabel, {
        "class": vue.normalizeClass(['v-field-label', {
          'v-field-label--floating': props.floating
        }, props.class]),
        "style": vue.normalizeStyle(props.style)
      }, slots));
      return {};
    }
  });

  // Types

  const allowedVariants$1 = ['underlined', 'outlined', 'filled', 'solo', 'solo-inverted', 'solo-filled', 'plain'];
  const makeVFieldProps = propsFactory({
    appendInnerIcon: IconValue,
    bgColor: String,
    clearable: Boolean,
    clearIcon: {
      type: IconValue,
      default: '$clear'
    },
    active: Boolean,
    centerAffix: {
      type: Boolean,
      default: undefined
    },
    color: String,
    baseColor: String,
    dirty: Boolean,
    disabled: {
      type: Boolean,
      default: null
    },
    glow: Boolean,
    error: Boolean,
    flat: Boolean,
    iconColor: [Boolean, String],
    label: String,
    persistentClear: Boolean,
    prependInnerIcon: IconValue,
    reverse: Boolean,
    singleLine: Boolean,
    variant: {
      type: String,
      default: 'filled',
      validator: v => allowedVariants$1.includes(v)
    },
    'onClick:clear': EventProp(),
    'onClick:appendInner': EventProp(),
    'onClick:prependInner': EventProp(),
    ...makeComponentProps(),
    ...makeLoaderProps(),
    ...makeRoundedProps(),
    ...makeThemeProps()
  }, 'VField');
  const VField = genericComponent()({
    name: 'VField',
    inheritAttrs: false,
    props: {
      id: String,
      details: Boolean,
      labelId: String,
      ...makeFocusProps(),
      ...makeVFieldProps()
    },
    emits: {
      'update:focused': focused => true,
      'update:modelValue': value => true
    },
    setup(props, {
      attrs,
      emit,
      slots
    }) {
      const {
        themeClasses
      } = provideTheme(props);
      const {
        loaderClasses
      } = useLoader(props);
      const {
        focusClasses,
        isFocused,
        focus,
        blur
      } = useFocus(props);
      const {
        InputIcon
      } = useInputIcon(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const {
        rtlClasses
      } = useRtl();
      const isActive = vue.toRef(() => props.dirty || props.active);
      const hasLabel = vue.toRef(() => !!(props.label || slots.label));
      const hasFloatingLabel = vue.toRef(() => !props.singleLine && hasLabel.value);
      const uid = vue.useId();
      const id = vue.computed(() => props.id || `input-${uid}`);
      const messagesId = vue.toRef(() => !props.details ? undefined : `${id.value}-messages`);
      const labelRef = vue.ref();
      const floatingLabelRef = vue.ref();
      const controlRef = vue.ref();
      const isPlainOrUnderlined = vue.computed(() => ['plain', 'underlined'].includes(props.variant));
      const color = vue.computed(() => {
        return props.error || props.disabled ? undefined : isActive.value && isFocused.value ? props.color : props.baseColor;
      });
      const iconColor = vue.computed(() => {
        if (props.iconColor === true || !props.iconColor && props.glow && isFocused.value) return color.value;
        if (!props.iconColor || props.glow && !isFocused.value) return undefined;
        return props.iconColor;
      });
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.bgColor);
      const {
        textColorClasses,
        textColorStyles
      } = useTextColor(color);
      vue.watch(isActive, val => {
        if (hasFloatingLabel.value && !PREFERS_REDUCED_MOTION()) {
          const el = labelRef.value.$el;
          const targetEl = floatingLabelRef.value.$el;
          requestAnimationFrame(() => {
            const rect = nullifyTransforms(el);
            const targetRect = new Box(targetEl);
            const x = targetRect.x - rect.x;
            const y = targetRect.y - rect.y - (rect.height / 2 - targetRect.height / 2);
            const targetWidth = targetRect.width / 0.75;
            const width = Math.abs(targetWidth - rect.width) > 1 ? {
              maxWidth: convertToUnit(targetWidth)
            } : undefined;
            const style = getComputedStyle(el);
            const targetStyle = getComputedStyle(targetEl);
            const duration = parseFloat(style.transitionDuration) * 1000 || 150;
            const scale = parseFloat(targetStyle.getPropertyValue('--v-field-label-scale'));
            const color = targetStyle.getPropertyValue('color');
            el.style.visibility = 'visible';
            targetEl.style.visibility = 'hidden';
            animate(el, {
              transform: `translate(${x}px, ${y}px) scale(${scale})`,
              color,
              ...width
            }, {
              duration,
              easing: standardEasing,
              direction: val ? 'normal' : 'reverse'
            }).finished.then(() => {
              el.style.removeProperty('visibility');
              targetEl.style.removeProperty('visibility');
            });
          });
        }
      }, {
        flush: 'post'
      });
      const slotProps = vue.computed(() => ({
        isActive,
        isFocused,
        controlRef,
        iconColor,
        blur,
        focus
      }));
      const floatingLabelProps = vue.toRef(() => {
        const ariaHidden = !isActive.value;
        return {
          'aria-hidden': ariaHidden,
          for: ariaHidden ? undefined : id.value
        };
      });
      const mainLabelProps = vue.toRef(() => {
        const ariaHidden = hasFloatingLabel.value && isActive.value;
        return {
          'aria-hidden': ariaHidden,
          for: ariaHidden ? undefined : id.value
        };
      });
      function onClick(e) {
        if (e.target !== getActiveElement()) {
          e.preventDefault();
        }
      }
      useRender(() => {
        const isOutlined = props.variant === 'outlined';
        const hasPrepend = !!(slots['prepend-inner'] || props.prependInnerIcon);
        const hasClear = !!(props.clearable || slots.clear) && !props.disabled;
        const hasAppend = !!(slots['append-inner'] || props.appendInnerIcon || hasClear);
        const label = () => slots.label ? slots.label({
          ...slotProps.value,
          label: props.label,
          props: {
            for: id.value
          }
        }) : props.label;
        return vue.createElementVNode("div", vue.mergeProps({
          "class": ['v-field', {
            'v-field--active': isActive.value,
            'v-field--appended': hasAppend,
            'v-field--center-affix': props.centerAffix ?? !isPlainOrUnderlined.value,
            'v-field--disabled': props.disabled,
            'v-field--dirty': props.dirty,
            'v-field--error': props.error,
            'v-field--glow': props.glow,
            'v-field--flat': props.flat,
            'v-field--has-background': !!props.bgColor,
            'v-field--persistent-clear': props.persistentClear,
            'v-field--prepended': hasPrepend,
            'v-field--reverse': props.reverse,
            'v-field--single-line': props.singleLine,
            'v-field--no-label': !label(),
            [`v-field--variant-${props.variant}`]: true
          }, themeClasses.value, backgroundColorClasses.value, focusClasses.value, loaderClasses.value, roundedClasses.value, rtlClasses.value, props.class],
          "style": [backgroundColorStyles.value, roundedStyles.value, props.style],
          "onClick": onClick
        }, attrs), [vue.createElementVNode("div", {
          "class": "v-field__overlay"
        }, null), vue.createVNode(LoaderSlot, {
          "name": "v-field",
          "active": !!props.loading,
          "color": props.error ? 'error' : typeof props.loading === 'string' ? props.loading : props.color
        }, {
          default: slots.loader
        }), hasPrepend && vue.createElementVNode("div", {
          "key": "prepend",
          "class": "v-field__prepend-inner"
        }, [slots['prepend-inner'] ? slots['prepend-inner'](slotProps.value) : props.prependInnerIcon && vue.createVNode(InputIcon, {
          "key": "prepend-icon",
          "name": "prependInner",
          "color": iconColor.value
        }, null)]), vue.createElementVNode("div", {
          "class": "v-field__field",
          "data-no-activator": ""
        }, [['filled', 'solo', 'solo-inverted', 'solo-filled'].includes(props.variant) && hasFloatingLabel.value && vue.createVNode(VFieldLabel, vue.mergeProps({
          "key": "floating-label",
          "ref": floatingLabelRef,
          "class": [textColorClasses.value],
          "floating": true
        }, floatingLabelProps.value, {
          "style": textColorStyles.value
        }), {
          default: () => [label()]
        }), hasLabel.value && vue.createVNode(VFieldLabel, vue.mergeProps({
          "key": "label",
          "ref": labelRef,
          "id": props.labelId
        }, mainLabelProps.value), {
          default: () => [label()]
        }), slots.default?.({
          ...slotProps.value,
          props: {
            id: id.value,
            class: 'v-field__input',
            'aria-describedby': messagesId.value
          },
          focus,
          blur
        }) ?? vue.createElementVNode("div", {
          "id": id.value,
          "class": "v-field__input",
          "aria-describedby": messagesId.value
        }, null)]), hasClear && vue.createVNode(VExpandXTransition, {
          "key": "clear"
        }, {
          default: () => [vue.withDirectives(vue.createElementVNode("div", {
            "class": "v-field__clearable",
            "onMousedown": e => {
              e.preventDefault();
              e.stopPropagation();
            }
          }, [vue.createVNode(VDefaultsProvider, {
            "defaults": {
              VIcon: {
                icon: props.clearIcon
              }
            }
          }, {
            default: () => [slots.clear ? slots.clear({
              ...slotProps.value,
              props: {
                onFocus: focus,
                onBlur: blur,
                onClick: props['onClick:clear'],
                tabindex: -1
              }
            }) : vue.createVNode(InputIcon, {
              "name": "clear",
              "onFocus": focus,
              "onBlur": blur,
              "tabindex": -1
            }, null)]
          })]), [[vue.vShow, props.dirty]])]
        }), hasAppend && vue.createElementVNode("div", {
          "key": "append",
          "class": "v-field__append-inner"
        }, [slots['append-inner'] ? slots['append-inner'](slotProps.value) : props.appendInnerIcon && vue.createVNode(InputIcon, {
          "key": "append-icon",
          "name": "appendInner",
          "color": iconColor.value
        }, null)]), vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-field__outline', textColorClasses.value]),
          "style": vue.normalizeStyle(textColorStyles.value)
        }, [isOutlined && vue.createElementVNode(vue.Fragment, null, [vue.createElementVNode("div", {
          "class": "v-field__outline__start"
        }, null), hasFloatingLabel.value && vue.createElementVNode("div", {
          "class": "v-field__outline__notch"
        }, [vue.createVNode(VFieldLabel, vue.mergeProps({
          "ref": floatingLabelRef,
          "floating": true
        }, floatingLabelProps.value), {
          default: () => [label()]
        })]), vue.createElementVNode("div", {
          "class": "v-field__outline__end"
        }, null)]), isPlainOrUnderlined.value && hasFloatingLabel.value && vue.createVNode(VFieldLabel, vue.mergeProps({
          "ref": floatingLabelRef,
          "floating": true
        }, floatingLabelProps.value), {
          default: () => [label()]
        })])]);
      });
      return {
        controlRef,
        fieldIconColor: iconColor
      };
    }
  });

  // Utilities

  // Types

  // Types

  // Composables
  const makeAutocompleteProps = propsFactory({
    autocomplete: String
  }, 'autocomplete');
  function useAutocomplete(props) {
    const uniqueId = vue.useId();
    const reloadTrigger = vue.shallowRef(0);
    const isSuppressing = vue.toRef(() => props.autocomplete === 'suppress');
    const fieldName = vue.toRef(() => {
      if (!props.name) return undefined;
      return isSuppressing.value ? `${props.name}-${uniqueId}-${reloadTrigger.value}` : props.name;
    });
    const fieldAutocomplete = vue.toRef(() => {
      return isSuppressing.value ? 'off' : props.autocomplete;
    });
    return {
      isSuppressing,
      fieldAutocomplete,
      fieldName,
      update: () => reloadTrigger.value = new Date().getTime()
    };
  }

  function useAutofocus(props) {
    function onIntersect(isIntersecting, entries) {
      if (!props.autofocus || !isIntersecting) return;
      const el = entries[0].target;
      const target = el.matches('input,textarea') ? el : el.querySelector('input,textarea');

      // Defer past overlay enter setup (e.g. VDialogTransition visibility:hidden)
      setTimeout(() => target?.focus(), 50);
    }
    return {
      onIntersect
    };
  }

  // Types

  const activeTypes = ['color', 'file', 'time', 'date', 'datetime-local', 'week', 'month'];
  const makeVTextFieldProps = propsFactory({
    autofocus: Boolean,
    counter: [Boolean, Number, String],
    counterValue: [Number, Function],
    prefix: String,
    placeholder: String,
    persistentPlaceholder: Boolean,
    persistentCounter: Boolean,
    suffix: String,
    role: String,
    type: {
      type: String,
      default: 'text'
    },
    modelModifiers: Object,
    ...makeAutocompleteProps(),
    ...omit(makeVInputProps(), ['direction']),
    ...makeVFieldProps()
  }, 'VTextField');
  const VTextField = genericComponent()({
    name: 'VTextField',
    directives: {
      vIntersect: Intersect
    },
    inheritAttrs: false,
    props: makeVTextFieldProps(),
    emits: {
      'click:control': e => true,
      'mousedown:control': e => true,
      'update:focused': focused => true,
      'update:modelValue': val => true
    },
    setup(props, {
      attrs,
      emit,
      slots
    }) {
      const model = useProxiedModel(props, 'modelValue', undefined, v => {
        if (Object.is(v, -0)) return '-0';
        return v;
      });
      const {
        isFocused,
        focus,
        blur
      } = useFocus(props);
      const {
        onIntersect
      } = useAutofocus(props);
      const counterValue = vue.computed(() => {
        return typeof props.counterValue === 'function' ? props.counterValue(model.value) : typeof props.counterValue === 'number' ? props.counterValue : (model.value ?? '').toString().length;
      });
      const max = vue.computed(() => {
        if (attrs.maxlength) return attrs.maxlength;
        if (!props.counter || typeof props.counter !== 'number' && typeof props.counter !== 'string') return undefined;
        return props.counter;
      });
      const isPlainOrUnderlined = vue.computed(() => ['plain', 'underlined'].includes(props.variant));
      const vInputRef = vue.ref();
      const vFieldRef = vue.ref();
      const inputRef = vue.ref();
      const autocomplete = useAutocomplete(props);
      const isActive = vue.computed(() => activeTypes.includes(props.type) || props.persistentPlaceholder || isFocused.value || props.active);
      function onFocus() {
        if (autocomplete.isSuppressing.value) {
          autocomplete.update();
        }
        if (!isFocused.value) focus();
        vue.nextTick(() => {
          if (inputRef.value !== getActiveElement()) {
            inputRef.value?.focus();
          }
        });
      }
      function onControlMousedown(e) {
        emit('mousedown:control', e);
        if (e.target === inputRef.value) return;
        onFocus();
        e.preventDefault();
      }
      function onControlClick(e) {
        emit('click:control', e);
      }
      function onClear(e, reset) {
        e.stopPropagation();
        onFocus();
        vue.nextTick(() => {
          reset();
          callEvent(props['onClick:clear'], e);
        });
      }
      function onInput(e) {
        const el = e.target;
        if (!(props.modelModifiers?.trim && ['text', 'search', 'password', 'tel', 'url'].includes(props.type))) {
          model.value = el.value;
          return;
        }
        const value = el.value;
        const start = el.selectionStart;
        const end = el.selectionEnd;
        model.value = value;
        vue.nextTick(() => {
          let offset = 0;
          if (value.trimStart().length === el.value.length) {
            // #22307 - Whitespace has been removed from the
            // start, offset the caret position to compensate
            offset = value.length - el.value.length;
          }
          if (start != null) el.selectionStart = start - offset;
          if (end != null) el.selectionEnd = end - offset;
        });
      }
      useRender(() => {
        const hasCounter = !!(slots.counter || props.counter !== false && props.counter != null);
        const hasDetails = props.hideDetails !== true && !!(slots.details || hasCounter && (props.persistentCounter || props.hideDetails === false || isFocused.value));
        const [rootAttrs, inputAttrs] = filterInputAttrs(attrs);
        const {
          modelValue: _,
          ...inputProps
        } = VInput.filterProps(props);
        const fieldProps = VField.filterProps(props);
        return vue.createVNode(VInput, vue.mergeProps({
          "ref": vInputRef,
          "modelValue": model.value,
          "onUpdate:modelValue": $event => model.value = $event,
          "class": ['v-text-field', {
            'v-text-field--prefixed': props.prefix,
            'v-text-field--suffixed': props.suffix,
            'v-input--plain-underlined': isPlainOrUnderlined.value
          }, props.class],
          "style": props.style
        }, rootAttrs, inputProps, {
          "centerAffix": !isPlainOrUnderlined.value,
          "focused": isFocused.value,
          "indentDetails": props.indentDetails ?? !isPlainOrUnderlined.value
        }), {
          ...slots,
          default: ({
            id,
            isDisabled,
            isDirty,
            isReadonly,
            isValid,
            hasDetails,
            reset
          }) => vue.createVNode(VField, vue.mergeProps({
            "ref": vFieldRef,
            "onMousedown": onControlMousedown,
            "onClick": onControlClick,
            "onClick:clear": e => onClear(e, reset),
            "role": props.role
          }, omit(fieldProps, ['onClick:clear']), {
            "id": id.value,
            "labelId": `${id.value}-label`,
            "active": isActive.value || isDirty.value,
            "dirty": isDirty.value || props.dirty,
            "disabled": isDisabled.value,
            "focused": isFocused.value,
            "details": hasDetails.value,
            "error": isValid.value === false
          }), {
            ...slots,
            default: ({
              props: {
                class: fieldClass,
                ...slotProps
              },
              controlRef
            }) => {
              const inputNode = vue.createElementVNode("input", vue.mergeProps({
                "ref": val => inputRef.value = controlRef.value = val,
                "value": model.value,
                "onInput": onInput,
                "autofocus": props.autofocus,
                "readonly": isReadonly.value,
                "disabled": isDisabled.value,
                "name": autocomplete.fieldName.value,
                "autocomplete": autocomplete.fieldAutocomplete.value,
                "placeholder": props.placeholder,
                "size": 1,
                "role": props.role,
                "type": props.type,
                "onFocus": focus,
                "onBlur": blur,
                "aria-labelledby": `${id.value}-label`
              }, slotProps, inputAttrs), null);
              return vue.createElementVNode(vue.Fragment, null, [props.prefix && vue.createElementVNode("span", {
                "class": "v-text-field__prefix"
              }, [vue.createElementVNode("span", {
                "class": "v-text-field__prefix__text"
              }, [props.prefix])]), vue.withDirectives(slots.default ? vue.createElementVNode("div", {
                "class": vue.normalizeClass(fieldClass),
                "data-no-activator": ""
              }, [slots.default({
                id
              }), inputNode]) : vue.cloneVNode(inputNode, {
                class: fieldClass
              }), [[Intersect, onIntersect, null, {
                once: true
              }]]), props.suffix && vue.createElementVNode("span", {
                "class": "v-text-field__suffix"
              }, [vue.createElementVNode("span", {
                "class": "v-text-field__suffix__text"
              }, [props.suffix])])]);
            }
          }),
          details: hasDetails ? slotProps => vue.createElementVNode(vue.Fragment, null, [slots.details?.(slotProps), hasCounter && vue.createElementVNode(vue.Fragment, null, [vue.createElementVNode("span", null, null), vue.createVNode(VCounter, {
            "active": props.persistentCounter || isFocused.value,
            "value": counterValue.value,
            "max": max.value,
            "disabled": props.disabled
          }, slots.counter)])]) : undefined
        });
      });
      return forwardRefs({}, vInputRef, vFieldRef, inputRef);
    }
  });

  // Types

  const makeVVirtualScrollItemProps = propsFactory({
    renderless: Boolean,
    ...makeComponentProps()
  }, 'VVirtualScrollItem');
  const VVirtualScrollItem = genericComponent()({
    name: 'VVirtualScrollItem',
    inheritAttrs: false,
    props: makeVVirtualScrollItemProps(),
    emits: {
      'update:height': height => true
    },
    setup(props, {
      attrs,
      emit,
      slots
    }) {
      const {
        resizeRef,
        contentRect
      } = useResizeObserver(undefined, 'border');
      vue.watch(() => contentRect.value?.height, height => {
        if (height != null) emit('update:height', height);
      });
      useRender(() => props.renderless ? vue.createElementVNode(vue.Fragment, null, [slots.default?.({
        itemRef: resizeRef
      })]) : vue.createElementVNode("div", vue.mergeProps({
        "ref": resizeRef,
        "class": ['v-virtual-scroll__item', props.class],
        "style": props.style
      }, attrs), [slots.default?.()]));
    }
  });

  // Composables

  // Types

  const UP = -1;
  const DOWN = 1;

  /** Determines how large each batch of items should be */
  const BUFFER_PX = 100;
  const makeVirtualProps = propsFactory({
    itemHeight: {
      type: [Number, String],
      default: null
    },
    itemKey: {
      type: [String, Array, Function],
      default: null
    },
    height: [Number, String]
  }, 'virtual');
  function useVirtual(props, items) {
    const display = useDisplay();
    const itemHeight = vue.shallowRef(0);
    vue.watchEffect(() => {
      itemHeight.value = parseFloat(props.itemHeight || 0);
    });
    const first = vue.shallowRef(0);
    const last = vue.shallowRef(Math.ceil(
    // Assume 16px items filling the entire screen height if
    // not provided. This is probably incorrect but it minimises
    // the chance of ending up with empty space at the bottom.
    // The default value is set here to avoid poisoning getSize()
    (parseInt(props.height) || display.height.value) / (itemHeight.value || 16)) || 1);
    const paddingTop = vue.shallowRef(0);
    const paddingBottom = vue.shallowRef(0);

    /** The scrollable element */
    const containerRef = vue.ref();
    /** An element marking the top of the scrollable area,
     * used to add an offset if there's padding or other elements above the virtual list */
    const markerRef = vue.ref();
    /** markerRef's offsetTop, lazily evaluated */
    let markerOffset = 0;
    const {
      resizeRef,
      contentRect
    } = useResizeObserver();
    vue.watchEffect(() => {
      resizeRef.value = containerRef.value;
    });
    const viewportHeight = vue.computed(() => {
      return containerRef.value === document.documentElement ? display.height.value : contentRect.value?.height || parseInt(props.height) || 0;
    });
    /** All static elements have been rendered and we have an assumed item height */
    const hasInitialRender = vue.computed(() => {
      return !!(containerRef.value && markerRef.value && viewportHeight.value && itemHeight.value);
    });
    let sizes = Array.from({
      length: items.value.length
    });
    let offsets = Array.from({
      length: items.value.length
    });
    let heights = new Map();
    const updateTime = vue.shallowRef(0);
    let targetScrollIndex = -1;
    let targetScrollHeight = 0;
    function getSize(index) {
      return sizes[index] || itemHeight.value;
    }
    const updateOffsets = debounce(() => {
      const start = performance.now();
      offsets[0] = 0;
      const length = items.value.length;
      for (let i = 1; i <= length; i++) {
        offsets[i] = (offsets[i - 1] || 0) + getSize(i - 1);
      }
      updateTime.value = Math.max(updateTime.value, performance.now() - start);
      calculateVisibleItems();
    }, updateTime);
    const unwatch = vue.watch(hasInitialRender, v => {
      if (!v) return;
      // First render is complete, update offsets and visible
      // items in case our assumed item height was incorrect

      unwatch();
      markerOffset = markerRef.value.offsetTop;
      updateOffsets.immediate();
      calculateVisibleItems();
      if (!~targetScrollIndex) return;
      vue.nextTick(() => {
        IN_BROWSER && window.requestAnimationFrame(() => {
          if (~targetScrollIndex) scrollToIndex(targetScrollIndex);
        });
      });
    });
    vue.onScopeDispose(() => {
      updateOffsets.clear();
    });
    function estimateItemHeight() {
      let total = 0;
      for (const count of heights.values()) total += count;
      let seen = 0;
      for (const height of [...heights.keys()].sort((a, b) => a - b)) {
        seen += heights.get(height);
        if (seen * 2 >= total) return height;
      }
      return itemHeight.value;
    }
    function handleItemResize(index, height) {
      const prevHeight = sizes[index];
      const prevItemHeight = itemHeight.value;
      if (height > 0) {
        if (prevHeight) {
          const count = heights.get(prevHeight) - 1;
          count ? heights.set(prevHeight, count) : heights.delete(prevHeight);
        }
        heights.set(height, (heights.get(height) ?? 0) + 1);
        itemHeight.value = estimateItemHeight();
      }
      if (prevHeight !== height || prevItemHeight !== itemHeight.value) {
        sizes[index] = height;
        updateOffsets();
      }
    }
    function calculateOffset(index) {
      index = clamp(index, 0, items.value.length);
      const whole = Math.floor(index);
      const fraction = index % 1;
      const next = whole + 1;
      const wholeOffset = offsets[whole] || 0;
      const nextOffset = offsets[next] || wholeOffset;
      return wholeOffset + (nextOffset - wholeOffset) * fraction;
    }
    function calculateIndex(scrollTop) {
      return binaryClosest(offsets, scrollTop);
    }
    let lastScrollTop = 0;
    let scrollVelocity = 0;
    let lastScrollTime = 0;
    vue.watch(viewportHeight, (val, oldVal) => {
      calculateVisibleItems();
      if (val < oldVal) {
        requestAnimationFrame(() => {
          scrollVelocity = 0;
          calculateVisibleItems();
        });
      }
    });
    let scrollTimeout = -1;
    function handleScroll() {
      if (!containerRef.value || !markerRef.value) return;
      const scrollTop = containerRef.value.scrollTop;
      const scrollTime = performance.now();
      const scrollDeltaT = scrollTime - lastScrollTime;
      if (scrollDeltaT > 500) {
        scrollVelocity = Math.sign(scrollTop - lastScrollTop);

        // Not super important, only update at the
        // start of a scroll sequence to avoid reflows
        markerOffset = markerRef.value.offsetTop;
      } else {
        scrollVelocity = scrollTop - lastScrollTop;
      }
      lastScrollTop = scrollTop;
      lastScrollTime = scrollTime;
      window.clearTimeout(scrollTimeout);
      scrollTimeout = window.setTimeout(handleScrollend, 500);
      calculateVisibleItems();
    }
    function handleScrollend() {
      if (!containerRef.value || !markerRef.value) return;
      scrollVelocity = 0;
      lastScrollTime = 0;
      window.clearTimeout(scrollTimeout);
      calculateVisibleItems();
    }
    let raf = -1;
    function calculateVisibleItems() {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(_calculateVisibleItems);
    }
    function _calculateVisibleItems() {
      if (!containerRef.value || !viewportHeight.value || !itemHeight.value) return;
      const scrollTop = lastScrollTop - markerOffset;
      const direction = Math.sign(scrollVelocity);
      const startPx = Math.max(0, scrollTop - BUFFER_PX);
      const start = clamp(calculateIndex(startPx), 0, items.value.length);
      const endPx = scrollTop + viewportHeight.value + BUFFER_PX;
      const end = clamp(calculateIndex(endPx) + 1, start + 1, items.value.length);
      if (
      // Only update the side we're scrolling towards,
      // the other side will be updated incidentally
      (direction !== UP || start < first.value) && (direction !== DOWN || end > last.value)) {
        const topOverflow = calculateOffset(first.value) - calculateOffset(start);
        const bottomOverflow = calculateOffset(end) - calculateOffset(last.value);
        const bufferOverflow = Math.max(topOverflow, bottomOverflow);
        if (bufferOverflow > BUFFER_PX) {
          first.value = start;
          last.value = end;
        } else {
          // Only update the side that's reached its limit if there's still buffer left
          if (start <= 0) first.value = start;
          if (end >= items.value.length) {
            last.value = end;
            first.value = start;
          }
        }
      }
      paddingTop.value = calculateOffset(first.value);
      paddingBottom.value = calculateOffset(items.value.length) - calculateOffset(last.value);
    }
    function scrollToIndex(index) {
      if (targetScrollIndex !== index) targetScrollHeight = 0;
      const offset = calculateOffset(index);
      if (!containerRef.value || index && !offset) {
        targetScrollIndex = index;
        return;
      }

      // Move the window first so paddingTop/Bottom make scrollHeight large enough
      // before we assign scrollTop (otherwise the browser clamps the scroll).
      const itemSize = itemHeight.value || 16;
      const buffer = Math.ceil(BUFFER_PX / itemSize);
      const viewport = Math.max(1, Math.ceil((viewportHeight.value || 0) / itemSize));
      first.value = clamp(index - buffer, 0, Math.max(0, items.value.length - 1));
      last.value = clamp(index + viewport + buffer, first.value + 1, items.value.length);
      paddingTop.value = calculateOffset(first.value);
      paddingBottom.value = calculateOffset(items.value.length) - calculateOffset(last.value);
      scrollVelocity = 0;
      lastScrollTime = 0;
      targetScrollIndex = index;
      vue.nextTick(() => {
        const el = containerRef.value;
        // Superseded by a later scrollToIndex
        if (!el || !~targetScrollIndex || targetScrollIndex !== index) return;
        const top = calculateOffset(index);
        el.scrollTop = top;
        // Resize-driven calculateVisibleItems reads lastScrollTop, not the DOM
        lastScrollTop = el.scrollTop;
        if (index && el.scrollTop < top - 1 && el.scrollHeight > targetScrollHeight) {
          targetScrollHeight = el.scrollHeight;
          IN_BROWSER && requestAnimationFrame(() => {
            if (targetScrollIndex === index) scrollToIndex(index);
          });
        } else {
          targetScrollIndex = -1;
          calculateVisibleItems();
        }
      });
    }
    const computedItems = vue.computed(() => {
      return items.value.slice(first.value, last.value).map((item, index) => {
        const _index = index + first.value;
        return {
          raw: item,
          index: _index,
          key: getPropertyFromItem(item, props.itemKey, _index)
        };
      });
    });
    vue.watch(items, () => {
      sizes = Array.from({
        length: items.value.length
      });
      offsets = Array.from({
        length: items.value.length
      });
      heights = new Map();
      updateOffsets.immediate();
      calculateVisibleItems();
    }, {
      deep: 1
    });
    return {
      calculateVisibleItems,
      containerRef,
      markerRef,
      computedItems,
      paddingTop,
      paddingBottom,
      scrollToIndex,
      handleScroll,
      handleScrollend,
      handleItemResize
    };
  }

  // https://gist.github.com/robertleeplummerjr/1cc657191d34ecd0a324
  function binaryClosest(arr, val) {
    let high = arr.length - 1;
    let low = 0;
    let mid = 0;
    let item = null;
    let target = -1;
    if (arr[high] < val) {
      return high;
    }
    while (low <= high) {
      mid = low + high >> 1;
      item = arr[mid];
      if (item > val) {
        high = mid - 1;
      } else if (item < val) {
        target = mid;
        low = mid + 1;
      } else if (item === val) {
        return mid;
      } else {
        return low;
      }
    }
    return target;
  }

  // Types

  const makeVVirtualScrollProps = propsFactory({
    items: {
      type: Array,
      default: () => []
    },
    renderless: Boolean,
    ...makeVirtualProps(),
    ...makeComponentProps(),
    ...makeDimensionProps()
  }, 'VVirtualScroll');
  const VVirtualScroll = genericComponent()({
    name: 'VVirtualScroll',
    props: makeVVirtualScrollProps(),
    setup(props, {
      slots
    }) {
      const vm = getCurrentInstance('VVirtualScroll');
      const {
        dimensionStyles
      } = useDimension(props);
      const {
        calculateVisibleItems,
        containerRef,
        markerRef,
        handleScroll,
        handleScrollend,
        handleItemResize,
        scrollToIndex,
        paddingTop,
        paddingBottom,
        computedItems
      } = useVirtual(props, vue.toRef(() => props.items));
      useToggleScope(() => props.renderless, () => {
        function handleListeners(add = false) {
          const method = add ? 'addEventListener' : 'removeEventListener';
          if (!IN_BROWSER) return;
          if (containerRef.value === document.documentElement) {
            document[method]('scroll', handleScroll, {
              passive: true
            });
            document[method]('scrollend', handleScrollend);
          } else {
            containerRef.value?.[method]('scroll', handleScroll, {
              passive: true
            });
            containerRef.value?.[method]('scrollend', handleScrollend);
          }
        }
        vue.onMounted(() => {
          containerRef.value = getScrollParent(vm.vnode.el, true);
          handleListeners(true);
        });
        vue.onScopeDispose(handleListeners);
      });
      useRender(() => {
        const children = computedItems.value.map(item => vue.createVNode(VVirtualScrollItem, {
          "key": item.key,
          "renderless": props.renderless,
          "onUpdate:height": height => handleItemResize(item.index, height)
        }, {
          default: slotProps => slots.default?.({
            item: item.raw,
            index: item.index,
            ...slotProps
          })
        }));
        return props.renderless ? vue.createElementVNode(vue.Fragment, null, [vue.createElementVNode("div", {
          "ref": markerRef,
          "class": "v-virtual-scroll__spacer",
          "style": {
            paddingTop: convertToUnit(paddingTop.value)
          }
        }, null), children, vue.createElementVNode("div", {
          "class": "v-virtual-scroll__spacer",
          "style": {
            paddingBottom: convertToUnit(paddingBottom.value)
          }
        }, null)]) : vue.createElementVNode("div", {
          "ref": containerRef,
          "class": vue.normalizeClass(['v-virtual-scroll', props.class]),
          "onScrollPassive": handleScroll,
          "onScrollend": handleScrollend,
          "style": vue.normalizeStyle([dimensionStyles.value, props.style])
        }, [vue.createElementVNode("div", {
          "ref": markerRef,
          "class": "v-virtual-scroll__container",
          "style": {
            paddingTop: convertToUnit(paddingTop.value),
            paddingBottom: convertToUnit(paddingBottom.value)
          }
        }, [children])]);
      });
      return {
        calculateVisibleItems,
        scrollToIndex
      };
    }
  });

  // Utilities

  // Types

  function mergeRanges(ranges) {
    const sorted = ranges.filter(span => span[0] < span[1]).toSorted((a, b) => a[0] - b[0]);
    const merged = [];
    for (const span of sorted) {
      const last = merged.at(-1);
      if (last && span[0] <= last[1]) last[1] = Math.max(last[1], span[1]);else merged.push([span[0], span[1]]);
    }
    return merged;
  }
  function chunkText(text, ranges) {
    const chunks = [];
    let cursor = 0;
    for (const [start, end] of ranges) {
      if (cursor < start) chunks.push({
        text: text.slice(cursor, start),
        match: false
      });
      chunks.push({
        text: text.slice(start, end),
        match: true
      });
      cursor = end;
    }
    if (cursor < text.length) chunks.push({
      text: text.slice(cursor),
      match: false
    });
    return chunks;
  }
  function findRanges(text, query, matchAll, ignoreCase) {
    const terms = wrapInArray(query).filter(Boolean);
    const haystack = ignoreCase ? text.toLocaleLowerCase() : text;
    const spans = [];
    for (const term of terms) {
      const needle = ignoreCase ? term.toLocaleLowerCase() : term;
      let index = haystack.indexOf(needle);
      if (index !== -1) {
        spans.push([index, index + term.length]);
        if (matchAll) {
          index = haystack.indexOf(needle, index + term.length);
          while (index !== -1) {
            spans.push([index, index + term.length]);
            index = haystack.indexOf(needle, index + term.length);
          }
        }
      }
    }
    return mergeRanges(spans);
  }

  // mirror of `toHighlight` from `@vuetify/v0`
  // temporary shim, to be replaced in v5.0
  function toHighlight(text, query, options = {}) {
    const _text = vue.toValue(text);
    const _query = vue.toValue(query);
    const _matches = vue.toValue(options.matches);
    const matchAll = vue.toValue(options.matchAll) ?? false;
    const ignoreCase = vue.toValue(options.ignoreCase) ?? false;
    if (_matches?.length) return chunkText(_text, mergeRanges(_matches));
    if (_query) {
      const ranges = findRanges(_text, _query, matchAll, ignoreCase);
      return ranges.length > 0 ? chunkText(_text, ranges) : [{
        text: _text,
        match: false
      }];
    }
    return [{
      text: _text,
      match: false
    }];
  }

  // Types

  const makeVHighlightProps = propsFactory({
    text: {
      type: String,
      default: ''
    },
    query: [String, Array],
    matches: Array,
    matchAll: Boolean,
    ignoreCase: Boolean,
    color: String,
    opacity: [String, Number],
    markClass: String,
    ...makeTagProps({
      tag: 'span'
    })
  }, 'VHighlight');
  const VHighlight = defineComponent({
    name: 'VHighlight',
    props: makeVHighlightProps(),
    setup(props) {
      const chunks = vue.computed(() => toHighlight(() => props.text, () => props.query, {
        matches: () => props.matches,
        matchAll: () => props.matchAll,
        ignoreCase: () => props.ignoreCase
      }));
      const {
        textColorClasses,
        textColorStyles
      } = useTextColor(() => props.color);
      return () => vue.createVNode(props.tag, {
        "class": "v-highlight"
      }, {
        default: () => [chunks.value.map((chunk, i) => chunk.match ? vue.createElementVNode("mark", {
          "key": i,
          "class": vue.normalizeClass(['v-highlight__mark', textColorClasses.value, props.markClass]),
          "style": vue.normalizeStyle([textColorStyles.value, {
            '--v-highlight-opacity': props.opacity
          }])
        }, [chunk.text]) : vue.createElementVNode("span", {
          "key": i
        }, [chunk.text]))]
      });
    }
  });

  // Utilities

  // Types

  function useFocusRepair(active, content, fallback) {
    return function repairOrphanedFocus(e) {
      if (!e.relatedTarget && document.activeElement === document.body && active.value) {
        requestAnimationFrame(() => {
          if (!active.value) return;
          const el = content();
          const target = (el && focusableChildren(el)[0]) ?? fallback();
          target?.focus({
            preventScroll: true
          });
        });
        return true;
      }
      return false;
    };
  }

  // Utilities

  // Types

  function useScrolling(listRef, textFieldRef) {
    const isScrolling = vue.shallowRef(false);
    let scrollTimeout;
    function onListScroll(e) {
      cancelAnimationFrame(scrollTimeout);
      isScrolling.value = true;
      scrollTimeout = requestAnimationFrame(() => {
        scrollTimeout = requestAnimationFrame(() => {
          isScrolling.value = false;
        });
      });
    }
    async function finishScrolling() {
      await new Promise(resolve => requestAnimationFrame(resolve));
      await new Promise(resolve => requestAnimationFrame(resolve));
      await new Promise(resolve => requestAnimationFrame(resolve));
      await new Promise(resolve => {
        if (isScrolling.value) {
          const stop = vue.watch(isScrolling, () => {
            stop();
            resolve();
          });
        } else resolve();
      });
    }
    async function onListKeydown(e) {
      if (e.key === 'Tab') {
        textFieldRef.value?.focus();
      }
      if (!['PageDown', 'PageUp', 'Home', 'End'].includes(e.key)) return;
      const el = listRef.value?.$el;
      if (!el) return;
      if (e.key === 'Home' || e.key === 'End') {
        el.scrollTo({
          top: e.key === 'Home' ? 0 : el.scrollHeight,
          behavior: 'smooth'
        });
      }
      await finishScrolling();
      const children = el.querySelectorAll(':scope > :not(.v-virtual-scroll__spacer)');
      if (e.key === 'PageDown' || e.key === 'Home') {
        const top = el.getBoundingClientRect().top;
        for (const child of children) {
          if (child.getBoundingClientRect().top >= top) {
            child.focus();
            break;
          }
        }
      } else {
        const bottom = el.getBoundingClientRect().bottom;
        for (const child of [...children].reverse()) {
          if (child.getBoundingClientRect().bottom <= bottom) {
            child.focus();
            break;
          }
        }
      }
    }
    return {
      onScrollPassive: onListScroll,
      onKeydown: onListKeydown
    }; // typescript doesn't know about vue's event merging
  }

  // Utilities

  // Types

  function useFocusGroups({
    groups,
    onLeave
  }) {
    function getContentRef(group) {
      return group.type === 'list' ? group.contentRef.value?.$el : group.contentRef.value;
    }
    function getChildren(group) {
      const contentRef = getContentRef(group);
      return contentRef ? focusableChildren(contentRef) : [];
    }
    function onTabKeydown(e) {
      const target = e.target;
      const direction = e.shiftKey ? 'backward' : 'forward';
      const children = groups.map(getChildren);
      const currentGroupIndex = groups.map(g => g.type === 'list' ? g.contentRef.value?.$el : g.contentRef.value).findIndex(el => el?.contains(target));
      const nextIndex = nextFocusGroup(children, currentGroupIndex, direction, target);
      if (nextIndex === null) {
        const originGroup = groups[currentGroupIndex];
        const origin = children[currentGroupIndex];
        const isListGroup = originGroup.type === 'list';
        const atEdge = isListGroup || (direction === 'forward' ? origin.at(-1) === e.target : origin.at(0) === e.target);
        if (atEdge) {
          onLeave();
        }
      } else {
        e.preventDefault();
        e.stopImmediatePropagation();
        const nextGroup = groups[nextIndex];
        if (nextGroup.type === 'list' && vue.toValue(nextGroup.displayItemsCount) > 0) {
          nextGroup.contentRef.value?.focus(0);
        } else {
          const fromBefore = direction === 'forward';
          children[nextIndex].at(fromBefore ? 0 : -1).focus();
        }
      }
    }
    function nextFocusGroup(children, currentIndex, direction, target) {
      const originGroup = groups[currentIndex];
      const origin = children[currentIndex];

      // List groups always allow leaving (VList manages internal focus)
      // Element groups require being at the edge focusable child
      if (originGroup.type !== 'list') {
        const isAtEdge = direction === 'forward' ? origin.at(-1) === target : origin.at(0) === target;
        if (!isAtEdge) return null;
      }
      const step = direction === 'forward' ? 1 : -1;
      for (let i = currentIndex + step; i >= 0 && i < groups.length; i += step) {
        const group = groups[i];
        if (children[i].length > 0 || group.type === 'list' && vue.toValue(group.displayItemsCount) > 0) {
          return i;
        }
      }
      return null;
    }
    return {
      onTabKeydown
    };
  }

  /* eslint-disable max-statements */
  /* eslint-disable no-labels */


  // Types

  /**
   * - boolean: match without highlight
   * - number: single match (index), length already known
   * - []: single match (start, end)
   * - [][]: multiple matches (start, end), shouldn't overlap
   */

  // Composables
  const defaultFilter = (value, query, item) => {
    if (value == null || query == null) return -1;
    if (!query.length) return 0;
    value = value.toString().toLocaleLowerCase();
    query = query.toString().toLocaleLowerCase();
    const result = [];
    let idx = value.indexOf(query);
    while (~idx) {
      result.push([idx, idx + query.length]);
      idx = value.indexOf(query, idx + query.length);
    }
    return result.length ? result : -1;
  };
  function normaliseMatch(match, query) {
    if (match == null || typeof match === 'boolean' || match === -1) return;
    if (typeof match === 'number') return [[match, match + query.length]];
    if (Array.isArray(match[0])) return match;
    return [match];
  }
  const makeFilterProps = propsFactory({
    customFilter: Function,
    customKeyFilter: Object,
    filterKeys: [Array, String],
    filterMode: {
      type: String,
      default: 'intersection'
    },
    noFilter: Boolean
  }, 'filter');

  // eslint-disable-next-line complexity
  function filterItems(items, query, options) {
    const array = [];
    // always ensure we fall back to a functioning filter
    const filter = options?.default ?? defaultFilter;
    const keys = options?.filterKeys ? wrapInArray(options.filterKeys) : false;
    const customFiltersLength = Object.keys(options?.customKeyFilter ?? {}).length;
    if (!items?.length) return array;
    let lookAheadItems = [];
    loop: for (let i = 0; i < items.length; i++) {
      const [item, transformed = item] = wrapInArray(items[i]);
      const customMatches = {};
      const defaultMatches = {};
      let match = -1;
      if ((query || customFiltersLength > 0) && !options?.noFilter) {
        let hasOnlyCustomFilters = false;
        if (typeof item === 'object') {
          if (item.type === 'divider' || item.type === 'subheader') {
            if (lookAheadItems.at(-1)?.type !== 'divider' || item.type !== 'subheader') {
              // clear unless, divider appears before subheader
              lookAheadItems = [];
            }
            lookAheadItems.push({
              index: i,
              matches: {},
              type: item.type
            });
            continue;
          }
          const filterKeys = keys || Object.keys(transformed);
          hasOnlyCustomFilters = filterKeys.length === customFiltersLength;
          for (const key of filterKeys) {
            const value = getPropertyFromItem(transformed, key);
            const keyFilter = options?.customKeyFilter?.[key];
            match = keyFilter ? keyFilter(value, query, item) : filter(value, query, item);
            if (match !== -1 && match !== false) {
              if (keyFilter) customMatches[key] = normaliseMatch(match, query);else defaultMatches[key] = normaliseMatch(match, query);
            } else if (options?.filterMode === 'every') {
              continue loop;
            }
          }
        } else {
          match = filter(item, query, item);
          if (match !== -1 && match !== false) {
            defaultMatches.title = normaliseMatch(match, query);
          }
        }
        const defaultMatchesLength = Object.keys(defaultMatches).length;
        const customMatchesLength = Object.keys(customMatches).length;
        if (!defaultMatchesLength && !customMatchesLength) continue;
        if (options?.filterMode === 'union' && customMatchesLength !== customFiltersLength && !defaultMatchesLength) continue;
        if (options?.filterMode === 'intersection' && (customMatchesLength !== customFiltersLength || !defaultMatchesLength && customFiltersLength > 0 && !hasOnlyCustomFilters)) continue;
      }
      if (lookAheadItems.length) {
        array.push(...lookAheadItems);
        lookAheadItems = [];
      }
      array.push({
        index: i,
        matches: {
          ...defaultMatches,
          ...customMatches
        }
      });
    }
    return array;
  }
  function useFilter(props, items, query, options) {
    const filteredItems = vue.shallowRef([]);
    const filteredMatches = vue.shallowRef(new Map());
    const transformedItems = vue.computed(() => options?.transform ? vue.unref(items).map(item => [item, options.transform(item)]) : vue.unref(items));
    vue.watchEffect(() => {
      const _query = typeof query === 'function' ? query() : vue.unref(query);
      const strQuery = typeof _query !== 'string' && typeof _query !== 'number' ? '' : String(_query);
      const results = filterItems(transformedItems.value, strQuery, {
        customKeyFilter: {
          ...props.customKeyFilter,
          ...vue.unref(options?.customKeyFilter)
        },
        default: props.customFilter,
        filterKeys: props.filterKeys,
        filterMode: props.filterMode,
        noFilter: props.noFilter
      });
      const originalItems = vue.unref(items);
      const _filteredItems = [];
      const _filteredMatches = new Map();
      results.forEach(({
        index,
        matches
      }) => {
        const item = originalItems[index];
        _filteredItems.push(item);
        if (item.value !== undefined) {
          _filteredMatches.set(item.value, matches);
        }
      });
      filteredItems.value = _filteredItems;
      filteredMatches.value = _filteredMatches;
    });
    function getMatches(item) {
      return filteredMatches.value.get(item.value);
    }
    return {
      filteredItems,
      filteredMatches,
      getMatches
    };
  }

  // Utilities

  // Types

  // Types

  // Composables
  const makeMenuActivatorProps = propsFactory({
    closeText: {
      type: String,
      default: '$vuetify.close'
    },
    openText: {
      type: String,
      default: '$vuetify.open'
    }
  }, 'autocomplete');
  function useMenuActivator(props, isOpen) {
    const uid = vue.useId();
    const menuId = vue.computed(() => `menu-${uid}`);
    const ariaExpanded = vue.toRef(() => vue.toValue(isOpen));
    const ariaControls = vue.toRef(() => menuId.value);
    return {
      menuId,
      ariaExpanded,
      ariaControls
    };
  }

  // Types

  const makeSelectProps = propsFactory({
    chips: Boolean,
    closableChips: Boolean,
    eager: Boolean,
    hideNoData: Boolean,
    hideSelected: Boolean,
    listProps: {
      type: Object
    },
    menu: Boolean,
    menuElevation: [Number, String],
    menuIcon: {
      type: IconValue,
      default: '$dropdown'
    },
    menuProps: {
      type: Object
    },
    multiple: Boolean,
    noDataText: {
      type: String,
      default: '$vuetify.noDataText'
    },
    openOnClear: Boolean,
    itemColor: String,
    noAutoScroll: Boolean,
    ...makeMenuActivatorProps(),
    ...makeItemsProps({
      itemChildren: false
    })
  }, 'Select');
  const makeVSelectProps = propsFactory({
    search: String,
    ...makeFilterProps({
      filterKeys: ['title']
    }),
    ...makeSelectProps(),
    ...omit(makeVTextFieldProps({
      modelValue: null,
      role: 'combobox'
    }), ['validationValue', 'dirty']),
    ...makeTransitionProps({
      transition: {
        component: VDialogTransition
      }
    })
  }, 'VSelect');
  const VSelect = genericComponent()({
    name: 'VSelect',
    props: makeVSelectProps(),
    emits: {
      'update:focused': focused => true,
      'update:modelValue': value => true,
      'update:menu': ue => true,
      'update:search': value => true
    },
    setup(props, {
      slots
    }) {
      const {
        t
      } = useLocale();
      const vTextFieldRef = vue.ref();
      const vMenuRef = vue.ref();
      const headerRef = vue.ref();
      const footerRef = vue.ref();
      const vVirtualScrollRef = vue.ref();
      const {
        items,
        transformIn,
        transformOut
      } = useItems(props);
      const search = useProxiedModel(props, 'search', '');
      const {
        filteredItems,
        getMatches
      } = useFilter(props, items, () => search.value);
      const model = useProxiedModel(props, 'modelValue', [], v => transformIn(v === null ? [null] : wrapInArray(v)), v => {
        const transformed = transformOut(v);
        return props.multiple ? transformed : transformed[0] ?? null;
      });
      const counterValue = vue.computed(() => {
        return typeof props.counterValue === 'function' ? props.counterValue(model.value) : typeof props.counterValue === 'number' ? props.counterValue : model.value.length;
      });
      const form = useForm(props);
      const autocomplete = useAutocomplete(props);
      const selectedValues = vue.computed(() => model.value.map(selection => selection.value));
      const isFocused = vue.shallowRef(false);
      const closableChips = vue.toRef(() => props.closableChips && !form.isReadonly.value && !form.isDisabled.value);
      const {
        InputIcon
      } = useInputIcon(props);
      let keyboardLookupPrefix = '';
      let keyboardLookupIndex = 0;
      let keyboardLookupLastTime;
      let openedByKeyboard = false;
      let openedByArrow = null;
      const displayItems = vue.computed(() => {
        const baseItems = search.value ? filteredItems.value : items.value;
        if (props.hideSelected) {
          return baseItems.filter(item => !model.value.some(s => (props.valueComparator || deepEqual)(s, item)));
        }
        return baseItems;
      });
      const menuDisabled = vue.computed(() => props.hideNoData && !displayItems.value.length || form.isReadonly.value || form.isDisabled.value);
      const _menu = useProxiedModel(props, 'menu');
      const menu = vue.computed({
        get: () => _menu.value,
        set: v => {
          if (_menu.value && !v && vMenuRef.value?.ΨopenChildren.size) return;
          if (v && menuDisabled.value) return;
          _menu.value = v;
        }
      });
      const {
        menuId,
        ariaExpanded,
        ariaControls
      } = useMenuActivator(props, menu);
      const computedMenuProps = vue.computed(() => {
        return {
          ...props.menuProps,
          activatorProps: {
            ...(props.menuProps?.activatorProps || {}),
            'aria-haspopup': 'listbox' // Set aria-haspopup to 'listbox'
          }
        };
      });
      const listRef = vue.ref();
      const listEvents = useScrolling(listRef, vTextFieldRef);
      const repairOrphanedFocus = useFocusRepair(menu, () => vMenuRef.value?.contentEl, () => vTextFieldRef.value?.controlRef);
      const {
        onTabKeydown
      } = useFocusGroups({
        groups: [{
          type: 'element',
          contentRef: headerRef
        }, {
          type: 'list',
          contentRef: listRef,
          displayItemsCount: () => displayItems.value.length
        }, {
          type: 'element',
          contentRef: footerRef
        }],
        onLeave: () => {
          menu.value = false;
          vTextFieldRef.value?.focus();
        }
      });
      function onClear(e) {
        if (props.openOnClear) {
          menu.value = true;
        }
      }
      function onMousedownControl() {
        if (menuDisabled.value) return;
        openedByKeyboard = false;
        openedByArrow = null;
        menu.value = !menu.value;
      }
      function onMenuKeydown(e) {
        if (e.key === 'Tab') {
          onTabKeydown(e);
        }
        if (listRef.value?.$el.contains(e.target) && checkPrintable(e)) {
          onKeydown(e);
        }
      }
      function onKeydown(e) {
        if (!e.key || form.isReadonly.value) return;
        if (['Enter', ' ', 'ArrowDown', 'ArrowUp', 'Home', 'End'].includes(e.key)) {
          e.preventDefault();
        }
        if (['ArrowDown', 'ArrowUp'].includes(e.key)) {
          openedByArrow = e.key === 'ArrowDown' ? 'next' : 'prev';
        } else if (['Enter', ' '].includes(e.key)) {
          openedByArrow = null;
        }
        if (['Enter', 'ArrowDown', ' '].includes(e.key)) {
          openedByKeyboard = true;
          menu.value = true;
        }
        if (['Escape', 'Tab'].includes(e.key)) {
          menu.value = false;
        }
        if (props.clearable && e.key === 'Backspace') {
          e.preventDefault();
          model.value = [];
          onClear();
          return;
        }
        if (e.key === 'Home') {
          listRef.value?.focus('first');
        } else if (e.key === 'End') {
          listRef.value?.focus('last');
        }

        // html select hotkeys
        const KEYBOARD_LOOKUP_THRESHOLD = 1000; // milliseconds

        if (!checkPrintable(e)) return;
        const now = performance.now();
        if (now - keyboardLookupLastTime > KEYBOARD_LOOKUP_THRESHOLD) {
          keyboardLookupPrefix = '';
          keyboardLookupIndex = 0;
        }
        keyboardLookupPrefix += e.key.toLowerCase();
        keyboardLookupLastTime = now;
        const items = displayItems.value;
        function findItem() {
          let result = findItemBase();
          if (result) return result;
          if (keyboardLookupPrefix.at(-1) === keyboardLookupPrefix.at(-2)) {
            // No matches but we have a repeated letter, try the next item with that prefix
            keyboardLookupPrefix = keyboardLookupPrefix.slice(0, -1);
            keyboardLookupIndex++;
            result = findItemBase();
            if (result) return result;
          }

          // Still nothing, wrap around to the top
          keyboardLookupIndex = 0;
          result = findItemBase();
          if (result) return result;

          // Still nothing, try just the new letter
          keyboardLookupPrefix = e.key.toLowerCase();
          return findItemBase();
        }
        function findItemBase() {
          for (let i = keyboardLookupIndex; i < items.length; i++) {
            const _item = items[i];
            if (_item.title.toLowerCase().startsWith(keyboardLookupPrefix)) {
              return [_item, i];
            }
          }
          return undefined;
        }
        const result = findItem();
        if (!result) return;
        const [item, index] = result;
        keyboardLookupIndex = index;
        listRef.value?.focus(index);
        if (!props.multiple) {
          model.value = [item];
        }
      }

      /** @param set - null means toggle */
      function select(item, set = true) {
        if (item.props.disabled) return;
        if (props.multiple) {
          const index = model.value.findIndex(selection => (props.valueComparator || deepEqual)(selection.value, item.value));
          const add = set == null ? !~index : set;
          if (~index) {
            const value = add ? [...model.value, item] : [...model.value];
            value.splice(index, 1);
            model.value = value;
          } else if (add) {
            model.value = [...model.value, item];
          }
        } else {
          const add = set !== false;
          model.value = add ? [item] : [];
          vue.nextTick(() => {
            menu.value = false;
          });
        }
      }
      function onBlur(e) {
        const target = e.target;
        if (!vTextFieldRef.value?.$el.contains(target)) {
          menu.value = false;
        }
      }
      function getSelectedIndex() {
        return displayItems.value.findIndex(item => model.value.some(s => (props.valueComparator || deepEqual)(s.value, item.value)));
      }
      function focusSelectedItem(options) {
        // Virtual list only mounts a window — numeric index into DOM children is wrong
        const selected = listRef.value?.$el?.querySelector?.('[aria-selected="true"]');
        if (!selected) return false;
        selected.focus(options);
        return true;
      }
      function onAfterEnter() {
        if (props.eager) {
          vVirtualScrollRef.value?.calculateVisibleItems();
        }
        if (!listRef.value || !isFocused.value) return;

        // VMenu re-dispatches ArrowUp/Down after open and already moved focus to next/prev
        if (listRef.value.$el?.contains(getActiveElement())) return;
        const opts = {
          focusVisible: false,
          preventScroll: props.noAutoScroll
        };

        // fallback for VMenu's re-dispatch; fires before the virtual list has scrolled
        if (openedByArrow) {
          listRef.value.focus(openedByArrow, opts);
          return;
        }
        if (focusSelectedItem(opts)) return;
        if (openedByKeyboard) {
          listRef.value.focus('first', opts);
        }
      }
      function onAfterLeave() {
        search.value = '';
        if (isFocused.value) {
          if (vMenuRef.value?.contentEl?._clickOutside?.lastMousedownWasOutside) {
            isFocused.value = false;
          } else {
            vTextFieldRef.value?.focus();
          }
        }
      }
      function onFocusin(e) {
        isFocused.value = true;
      }
      function onFocusout(e) {
        if (!vTextFieldRef.value?.$el.contains(e.relatedTarget) && !e.currentTarget.contains(e.relatedTarget)) {
          if (repairOrphanedFocus(e)) return;
          isFocused.value = false;
        }
      }
      function onModelUpdate(v) {
        if (v == null) model.value = [];else if (matchesSelector(vTextFieldRef.value, ':autofill') || matchesSelector(vTextFieldRef.value, ':-webkit-autofill')) {
          const item = items.value.find(item => item.title === v);
          if (item) {
            select(item);
          }
        } else if (vTextFieldRef.value) {
          vTextFieldRef.value.value = '';
        }
      }
      vue.watch(menu, val => {
        if (!val) {
          openedByKeyboard = false;
          openedByArrow = null;
        }
        if (!props.hideSelected && menu.value && model.value.length) {
          const index = getSelectedIndex();
          IN_BROWSER && !props.noAutoScroll && window.requestAnimationFrame(() => {
            index >= 0 && vVirtualScrollRef.value?.scrollToIndex(index);
          });
        }
      });
      vue.watch(items, (newVal, oldVal) => {
        if (menu.value) return;
        if (isFocused.value && props.hideNoData && !oldVal.length && newVal.length) {
          menu.value = true;
        }
      });
      useRender(() => {
        const hasChips = !!(props.chips || slots.chip);
        const hasList = !!(!props.hideNoData || displayItems.value.length || slots['prepend-item'] || slots['append-item'] || slots['no-data']);
        const isDirty = model.value.length > 0;
        const textFieldProps = VTextField.filterProps(props);
        const placeholder = isDirty || !isFocused.value && props.label && !props.persistentPlaceholder ? undefined : props.placeholder;
        const menuSlotProps = {
          search,
          filteredItems: filteredItems.value
        };
        return vue.createVNode(VTextField, vue.mergeProps({
          "ref": vTextFieldRef
        }, textFieldProps, {
          "modelValue": model.value.map(v => v.props.title).join(', '),
          "name": undefined,
          "onUpdate:modelValue": onModelUpdate,
          "focused": isFocused.value,
          "onUpdate:focused": $event => isFocused.value = $event,
          "validationValue": model.externalValue,
          "counterValue": counterValue.value,
          "dirty": isDirty,
          "class": ['v-select', {
            'v-select--active-menu': menu.value,
            'v-select--chips': !!props.chips,
            [`v-select--${props.multiple ? 'multiple' : 'single'}`]: true,
            'v-select--selected': model.value.length,
            'v-select--selection-slot': !!slots.selection
          }, props.class],
          "style": props.style,
          "inputmode": "none",
          "placeholder": placeholder,
          "onClick:clear": onClear,
          "onMousedown:control": onMousedownControl,
          "onBlur": onBlur,
          "onKeydown": onKeydown,
          "aria-expanded": ariaExpanded.value,
          "aria-controls": ariaControls.value
        }), {
          ...slots,
          default: ({
            id
          }) => vue.createElementVNode(vue.Fragment, null, [vue.createElementVNode("select", {
            "hidden": true,
            "multiple": props.multiple,
            "name": autocomplete.fieldName.value
          }, [items.value.map(item => vue.createElementVNode("option", {
            "key": item.value,
            "value": item.value,
            "selected": selectedValues.value.includes(item.value)
          }, null))]), vue.createVNode(VMenu, vue.mergeProps({
            "id": menuId.value,
            "ref": vMenuRef,
            "modelValue": menu.value,
            "onUpdate:modelValue": $event => menu.value = $event,
            "activator": "parent",
            "captureFocus": false,
            "disabled": menuDisabled.value,
            "eager": props.eager,
            "maxHeight": 310,
            "openOnClick": false,
            "closeOnContentClick": false,
            "transition": props.transition,
            "onAfterEnter": onAfterEnter,
            "onAfterLeave": onAfterLeave
          }, computedMenuProps.value, {
            "contentClass": ['v-select__content', computedMenuProps.value.contentClass]
          }), {
            default: () => [vue.createVNode(VSheet, {
              "elevation": props.menuElevation,
              "onFocusin": onFocusin,
              "onFocusout": onFocusout,
              "onKeydown": onMenuKeydown
            }, {
              default: () => [slots['menu-header'] && vue.createElementVNode("header", {
                "ref": headerRef
              }, [slots['menu-header'](menuSlotProps)]), hasList && vue.createVNode(VList, vue.mergeProps({
                "key": "select-list",
                "ref": listRef,
                "selected": selectedValues.value,
                "selectStrategy": props.multiple ? 'independent' : 'single-independent',
                "tabindex": "-1",
                "selectable": !!displayItems.value.length,
                "aria-live": "polite",
                "aria-labelledby": `${id.value}-label`,
                "aria-multiselectable": props.multiple,
                "color": props.itemColor ?? props.color
              }, listEvents, props.listProps), {
                default: () => [slots['prepend-item']?.(), !displayItems.value.length && !props.hideNoData && (slots['no-data']?.() ?? vue.createVNode(VListItem, {
                  "key": "no-data",
                  "title": t(props.noDataText)
                }, null)), vue.createVNode(VVirtualScroll, {
                  "ref": vVirtualScrollRef,
                  "renderless": true,
                  "items": displayItems.value,
                  "itemKey": "value"
                }, {
                  default: ({
                    item,
                    index,
                    itemRef
                  }) => {
                    const camelizedProps = camelizeProps(item.props);
                    const itemProps = vue.mergeProps(item.props, {
                      ref: itemRef,
                      key: item.value,
                      onClick: () => select(item, null),
                      'aria-posinset': index + 1,
                      'aria-setsize': displayItems.value.length
                    });
                    if (item.type === 'divider') {
                      return slots.divider?.({
                        props: item.raw,
                        index
                      }) ?? vue.createVNode(VDivider, vue.mergeProps(item.props, {
                        "ref": itemRef,
                        "key": `divider-${index}`
                      }), null);
                    }
                    if (item.type === 'subheader') {
                      return slots.subheader?.({
                        props: item.raw,
                        index
                      }) ?? vue.createVNode(VListSubheader, vue.mergeProps(item.props, {
                        "ref": itemRef,
                        "key": `subheader-${index}`
                      }), null);
                    }
                    return slots.item?.({
                      item: item.raw,
                      internalItem: item,
                      index,
                      props: itemProps
                    }) ?? vue.createVNode(VListItem, vue.mergeProps(itemProps, {
                      "role": "option"
                    }), {
                      prepend: ({
                        isSelected
                      }) => vue.createElementVNode(vue.Fragment, null, [props.multiple && !props.hideSelected ? vue.createVNode(VCheckboxBtn, {
                        "key": item.value,
                        "modelValue": isSelected,
                        "ripple": false,
                        "tabindex": "-1",
                        "aria-hidden": true,
                        "onClick": event => event.preventDefault()
                      }, null) : undefined, camelizedProps.prependAvatar && vue.createVNode(VAvatar, {
                        "image": camelizedProps.prependAvatar
                      }, null), camelizedProps.prependIcon && vue.createVNode(VIcon, {
                        "icon": camelizedProps.prependIcon
                      }, null)]),
                      title: () => {
                        return search.value ? vue.createVNode(VHighlight, {
                          "text": item.title,
                          "matches": getMatches(item)?.title,
                          "markClass": "v-select__mask",
                          "matchAll": true,
                          "ignoreCase": true
                        }, null) : item.title;
                      }
                    });
                  }
                }), slots['append-item']?.()]
              }), slots['menu-footer'] && vue.createElementVNode("footer", {
                "ref": footerRef
              }, [slots['menu-footer'](menuSlotProps)])]
            })]
          }), model.value.map((item, index) => {
            function onChipClose(e) {
              e.stopPropagation();
              e.preventDefault();
              select(item, false);
            }
            const slotProps = vue.mergeProps(VChip.filterProps(item.props), {
              'onClick:close': onChipClose,
              onKeydown(e) {
                if (e.key !== 'Enter' && e.key !== ' ') return;
                e.preventDefault();
                e.stopPropagation();
                onChipClose(e);
              },
              onMousedown(e) {
                e.preventDefault();
                e.stopPropagation();
              },
              modelValue: true,
              'onUpdate:modelValue': undefined
            });
            const hasSlot = hasChips ? !!slots.chip : !!slots.selection;
            const slotContent = hasSlot ? ensureValidVNode(hasChips ? slots.chip({
              item: item.raw,
              internalItem: item,
              index,
              props: slotProps
            }) : slots.selection({
              item: item.raw,
              internalItem: item,
              index
            })) : undefined;
            if (hasSlot && !slotContent) return undefined;
            return vue.createElementVNode("div", {
              "key": item.value,
              "class": "v-select__selection"
            }, [hasChips ? !slots.chip ? vue.createVNode(VChip, vue.mergeProps({
              "key": "chip",
              "closable": closableChips.value,
              "size": "small",
              "text": item.title,
              "disabled": item.props.disabled
            }, slotProps), null) : vue.createVNode(VDefaultsProvider, {
              "key": "chip-defaults",
              "defaults": {
                VChip: {
                  closable: closableChips.value,
                  size: 'small',
                  text: item.title
                }
              }
            }, {
              default: () => [slotContent]
            }) : slotContent ?? vue.createElementVNode("span", {
              "class": "v-select__selection-text"
            }, [item.title, props.multiple && index < model.value.length - 1 && vue.createElementVNode("span", {
              "class": "v-select__selection-comma"
            }, [vue.createTextVNode(",")])])]);
          })]),
          'append-inner': (...args) => vue.createElementVNode(vue.Fragment, null, [slots['append-inner']?.(...args), props.menuIcon ? vue.createVNode(VIcon, {
            "class": "v-select__menu-icon",
            "color": vTextFieldRef.value?.fieldIconColor,
            "icon": props.menuIcon,
            "aria-hidden": true
          }, null) : undefined, props.appendInnerIcon && vue.createVNode(InputIcon, {
            "key": "append-icon",
            "name": "appendInner",
            "color": args[0].iconColor.value
          }, null)])
        });
      });
      return forwardRefs({
        isFocused,
        menu,
        search,
        filteredItems,
        select
      }, vTextFieldRef);
    }
  });

  // Types

  const makeVAutocompleteProps = propsFactory({
    autoSelectFirst: {
      type: [Boolean, String]
    },
    clearOnSelect: Boolean,
    search: String,
    ...makeFilterProps({
      filterKeys: ['title']
    }),
    ...makeSelectProps(),
    ...omit(makeVTextFieldProps({
      modelValue: null,
      role: 'combobox'
    }), ['validationValue', 'dirty'])
  }, 'VAutocomplete');
  const VAutocomplete = genericComponent()({
    name: 'VAutocomplete',
    props: makeVAutocompleteProps(),
    emits: {
      'update:focused': focused => true,
      'update:search': value => true,
      'update:modelValue': value => true,
      'update:menu': value => true
    },
    setup(props, {
      slots
    }) {
      const {
        t
      } = useLocale();
      const vTextFieldRef = vue.ref();
      const isFocused = vue.shallowRef(false);
      const isPristine = vue.shallowRef(true);
      const listHasFocus = vue.shallowRef(false);
      const vMenuRef = vue.ref();
      const vVirtualScrollRef = vue.ref();
      const selectionIndex = vue.shallowRef(-1);
      const _searchLock = vue.shallowRef(null);
      const {
        items,
        transformIn,
        transformOut
      } = useItems(props);
      const {
        textColorClasses,
        textColorStyles
      } = useTextColor(() => vTextFieldRef.value?.color);
      const {
        InputIcon
      } = useInputIcon(props);
      const search = useProxiedModel(props, 'search', '');
      const model = useProxiedModel(props, 'modelValue', [], v => transformIn(v === null ? [null] : wrapInArray(v)), v => {
        const transformed = transformOut(v);
        return props.multiple ? transformed : transformed[0] ?? null;
      });
      const counterValue = vue.computed(() => {
        return typeof props.counterValue === 'function' ? props.counterValue(model.value) : typeof props.counterValue === 'number' ? props.counterValue : model.value.length;
      });
      const form = useForm(props);
      const {
        filteredItems,
        getMatches
      } = useFilter(props, items, () => _searchLock.value ?? (isPristine.value ? '' : search.value));
      const displayItems = vue.computed(() => {
        if (props.hideSelected && _searchLock.value === null) {
          return filteredItems.value.filter(filteredItem => !model.value.some(s => s.value === filteredItem.value));
        }
        return filteredItems.value;
      });
      const closableChips = vue.toRef(() => props.closableChips && !form.isReadonly.value && !form.isDisabled.value);
      const hasChips = vue.computed(() => !!(props.chips || slots.chip));
      const hasSelectionSlot = vue.computed(() => hasChips.value || !!slots.selection);
      const selectedValues = vue.computed(() => model.value.map(selection => selection.props.value));
      const firstSelectableItem = vue.computed(() => displayItems.value.find(x => x.type === 'item' && !x.props.disabled));
      const highlightFirst = vue.computed(() => {
        const selectFirst = props.autoSelectFirst === true || props.autoSelectFirst === 'exact' && search.value === firstSelectableItem.value?.title;
        return selectFirst && displayItems.value.length > 0 && !isPristine.value && !listHasFocus.value;
      });
      const menuDisabled = vue.computed(() => props.hideNoData && !displayItems.value.length || form.isReadonly.value || form.isDisabled.value);
      const _menu = useProxiedModel(props, 'menu');
      const menu = vue.computed({
        get: () => _menu.value,
        set: v => {
          if (_menu.value && !v && vMenuRef.value?.ΨopenChildren.size) return;
          if (v && menuDisabled.value) return;
          _menu.value = v;
        }
      });
      const {
        menuId,
        ariaExpanded,
        ariaControls
      } = useMenuActivator(props, menu);
      const listRef = vue.ref();
      const headerRef = vue.ref();
      const footerRef = vue.ref();
      const listEvents = useScrolling(listRef, vTextFieldRef);
      const repairOrphanedFocus = useFocusRepair(menu, () => vMenuRef.value?.contentEl, () => vTextFieldRef.value?.controlRef);
      const {
        onTabKeydown
      } = useFocusGroups({
        groups: [{
          type: 'element',
          contentRef: headerRef
        }, {
          type: 'list',
          contentRef: listRef,
          displayItemsCount: () => displayItems.value.length
        }, {
          type: 'element',
          contentRef: footerRef
        }],
        onLeave: () => {
          menu.value = false;
          vTextFieldRef.value?.focus();
        }
      });
      function onClear(e) {
        if (props.openOnClear) {
          menu.value = true;
        }
        search.value = '';
      }
      function onMousedownControl() {
        if (menuDisabled.value) return;
        menu.value = true;
      }
      function onMousedownMenuIcon(e) {
        if (menuDisabled.value) return;
        if (isFocused.value) {
          e.preventDefault();
          e.stopPropagation();
        }
        menu.value = !menu.value;
      }
      function onMenuKeydown(e) {
        if (e.key === 'Tab') {
          onTabKeydown(e);
        }
        if (listRef.value?.$el.contains(e.target) && (checkPrintable(e) || e.key === 'Backspace')) {
          vTextFieldRef.value?.focus();
        }
      }

      // eslint-disable-next-line complexity
      function onKeydown(e) {
        if (isComposingIgnoreKey(e) || form.isReadonly.value) return;
        const selectionStart = vTextFieldRef.value?.selectionStart;
        const length = model.value.length;
        if (['Enter', 'ArrowDown', 'ArrowUp'].includes(e.key)) {
          e.preventDefault();
        }
        if (['Enter', 'ArrowDown'].includes(e.key)) {
          menu.value = true;
        }
        if (['Escape'].includes(e.key)) {
          menu.value = false;
        }
        if (highlightFirst.value && ['Enter', 'Tab'].includes(e.key) && firstSelectableItem.value && !model.value.some(({
          value
        }) => value === firstSelectableItem.value.value)) {
          select(firstSelectableItem.value);
        }
        if (e.key === 'ArrowDown' && highlightFirst.value) {
          listRef.value?.focus('next');
        }
        if (['Backspace', 'Delete'].includes(e.key)) {
          if (!props.multiple && hasSelectionSlot.value && model.value.length > 0 && !search.value) return select(model.value[0], false);
          if (~selectionIndex.value) {
            e.preventDefault();
            const originalSelectionIndex = selectionIndex.value;
            select(model.value[selectionIndex.value], false);
            selectionIndex.value = originalSelectionIndex >= length - 1 ? length - 2 : originalSelectionIndex;
          } else if (e.key === 'Backspace' && !search.value) {
            selectionIndex.value = length - 1;
          }
          return;
        }
        if (!props.multiple) return;
        if (e.key === 'ArrowLeft') {
          if (selectionIndex.value < 0 && selectionStart && selectionStart > 0) return;
          const prev = selectionIndex.value > -1 ? selectionIndex.value - 1 : length - 1;
          if (model.value[prev]) {
            selectionIndex.value = prev;
          } else {
            const searchLength = search.value?.length ?? null;
            selectionIndex.value = -1;
            vTextFieldRef.value?.setSelectionRange(searchLength, searchLength);
          }
        } else if (e.key === 'ArrowRight') {
          if (selectionIndex.value < 0) return;
          const next = selectionIndex.value + 1;
          if (model.value[next]) {
            selectionIndex.value = next;
          } else {
            selectionIndex.value = -1;
            vTextFieldRef.value?.setSelectionRange(0, 0);
          }
        } else if (~selectionIndex.value && checkPrintable(e)) {
          selectionIndex.value = -1;
        }
      }
      function onChange(e) {
        if (matchesSelector(vTextFieldRef.value, ':autofill') || matchesSelector(vTextFieldRef.value, ':-webkit-autofill')) {
          const item = items.value.find(item => item.title === e.target.value);
          if (item) {
            select(item);
          }
        }
      }
      function onAfterEnter() {
        if (props.eager) {
          vVirtualScrollRef.value?.calculateVisibleItems();
        }
      }
      function onAfterLeave() {
        if (isFocused.value) {
          if (vMenuRef.value?.contentEl?._clickOutside?.lastMousedownWasOutside) {
            isFocused.value = false;
          } else {
            isPristine.value = true;
            vTextFieldRef.value?.focus();
          }
        }
        _searchLock.value = null;
      }
      function onFocusin(e) {
        isFocused.value = true;
        setTimeout(() => {
          listHasFocus.value = true;
        });
      }
      function onFocusout(e) {
        listHasFocus.value = false;
        if (!vTextFieldRef.value?.$el.contains(e.relatedTarget)) {
          if (repairOrphanedFocus(e)) return;
          isFocused.value = false;
        }
      }
      function onUpdateModelValue(v) {
        if (v == null || v === '' && !props.multiple && !hasSelectionSlot.value) model.value = [];
      }
      let mousedownInsideContentAt = 0;
      function onMousedownContent() {
        mousedownInsideContentAt = performance.now();
      }
      function onBlur(e) {
        const next = e.relatedTarget;
        const menuContent = vMenuRef.value?.contentEl;
        if (menuContent?.contains(next) || !next && performance.now() - mousedownInsideContentAt < 10) {
          isFocused.value = true;
        }
      }
      const isSelecting = vue.shallowRef(false);

      /** @param set - null means toggle */
      function select(item, set = true) {
        if (!item || item.props.disabled) return;
        if (props.multiple) {
          const index = model.value.findIndex(selection => (props.valueComparator || deepEqual)(selection.value, item.value));
          const add = set == null ? !~index : set;
          if (~index) {
            const value = add ? [...model.value, item] : [...model.value];
            value.splice(index, 1);
            model.value = value;
          } else if (add) {
            model.value = [...model.value, item];
          }
          if (props.clearOnSelect) {
            search.value = '';
          }
        } else {
          const add = set !== false;
          model.value = add ? [item] : [];
          _searchLock.value = isPristine.value ? '' : search.value ?? '';
          search.value = add && !hasSelectionSlot.value ? item.title : '';

          // watch for search watcher to trigger
          vue.nextTick(() => {
            menu.value = false;
            isPristine.value = true;
          });
        }
      }
      vue.watch(isFocused, (val, oldVal) => {
        if (val === oldVal) return;
        if (val) {
          isSelecting.value = true;
          search.value = props.multiple || hasSelectionSlot.value ? '' : String(model.value.at(-1)?.props.title ?? '');
          isPristine.value = true;
          vue.nextTick(() => isSelecting.value = false);
        } else {
          if (!props.multiple && search.value == null) model.value = [];
          menu.value = false;
          if (!isPristine.value && search.value) {
            _searchLock.value = search.value;
          }
          search.value = '';
          selectionIndex.value = -1;
        }
      });
      vue.watch(search, val => {
        if (!isFocused.value || isSelecting.value) return;
        if (val) menu.value = true;
        isPristine.value = !val;
      });
      vue.watch(menu, val => {
        if (!props.hideSelected && val && model.value.length && isPristine.value) {
          const index = displayItems.value.findIndex(item => model.value.some(s => item.value === s.value));
          IN_BROWSER && !props.noAutoScroll && window.requestAnimationFrame(() => {
            index >= 0 && vVirtualScrollRef.value?.scrollToIndex(index);
          });
        }
        if (val) _searchLock.value = null;
      });
      vue.watch(items, (newVal, oldVal) => {
        if (menu.value) return;
        if (isFocused.value && !oldVal.length && newVal.length) {
          menu.value = true;
        }
      });
      useRender(() => {
        const hasList = !!(!props.hideNoData || displayItems.value.length || slots['prepend-item'] || slots['append-item'] || slots['no-data']);
        const isDirty = model.value.length > 0;
        const textFieldProps = VTextField.filterProps(props);
        const menuSlotProps = {
          search,
          filteredItems: filteredItems.value
        };
        return vue.createVNode(VTextField, vue.mergeProps({
          "ref": vTextFieldRef
        }, textFieldProps, {
          "modelValue": search.value,
          "onUpdate:modelValue": [$event => search.value = $event, onUpdateModelValue],
          "focused": isFocused.value,
          "onUpdate:focused": $event => isFocused.value = $event,
          "validationValue": model.externalValue,
          "counterValue": counterValue.value,
          "dirty": isDirty,
          "onChange": onChange,
          "class": ['v-autocomplete', `v-autocomplete--${props.multiple ? 'multiple' : 'single'}`, {
            'v-autocomplete--active-menu': menu.value,
            'v-autocomplete--chips': !!props.chips,
            'v-autocomplete--selection-slot': !!hasSelectionSlot.value,
            'v-autocomplete--selecting-index': selectionIndex.value > -1
          }, props.class],
          "style": props.style,
          "readonly": form.isReadonly.value,
          "placeholder": isDirty ? undefined : props.placeholder,
          "onClick:clear": onClear,
          "onMousedown:control": onMousedownControl,
          "onKeydown": onKeydown,
          "onBlur": onBlur,
          "aria-expanded": ariaExpanded.value,
          "aria-controls": ariaControls.value
        }), {
          ...slots,
          default: ({
            id
          }) => vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VMenu, vue.mergeProps({
            "id": menuId.value,
            "ref": vMenuRef,
            "modelValue": menu.value,
            "onUpdate:modelValue": $event => menu.value = $event,
            "activator": "parent",
            "disabled": menuDisabled.value,
            "eager": props.eager,
            "maxHeight": 310,
            "openOnClick": false,
            "closeOnContentClick": false,
            "onAfterEnter": onAfterEnter,
            "onAfterLeave": onAfterLeave
          }, props.menuProps, {
            "contentClass": ['v-autocomplete__content', props.menuProps?.contentClass]
          }), {
            default: () => [vue.createVNode(VSheet, {
              "elevation": props.menuElevation,
              "onFocusin": onFocusin,
              "onKeydown": onMenuKeydown,
              "onMousedown": onMousedownContent
            }, {
              default: () => [slots['menu-header'] && vue.createElementVNode("header", {
                "ref": headerRef
              }, [slots['menu-header'](menuSlotProps)]), hasList && vue.createVNode(VList, vue.mergeProps({
                "key": "autocomplete-list",
                "ref": listRef,
                "filterable": true,
                "selected": selectedValues.value,
                "selectStrategy": props.multiple ? 'independent' : 'single-independent',
                "onMousedown": e => e.preventDefault(),
                "onFocusout": onFocusout,
                "tabindex": "-1",
                "selectable": !!displayItems.value.length,
                "aria-live": "polite",
                "aria-labelledby": `${id.value}-label`,
                "aria-multiselectable": props.multiple,
                "color": props.itemColor ?? props.color
              }, listEvents, props.listProps), {
                default: () => [slots['prepend-item']?.(), !displayItems.value.length && !props.hideNoData && (slots['no-data']?.() ?? vue.createVNode(VListItem, {
                  "key": "no-data",
                  "title": t(props.noDataText)
                }, null)), vue.createVNode(VVirtualScroll, {
                  "ref": vVirtualScrollRef,
                  "renderless": true,
                  "items": displayItems.value,
                  "itemKey": "value"
                }, {
                  default: ({
                    item,
                    index,
                    itemRef
                  }) => {
                    const camelizedProps = camelizeProps(item.props);
                    const itemProps = vue.mergeProps(item.props, {
                      ref: itemRef,
                      key: item.value,
                      active: highlightFirst.value && item === firstSelectableItem.value ? true : undefined,
                      onClick: () => select(item, null),
                      'aria-posinset': index + 1,
                      'aria-setsize': displayItems.value.length
                    });
                    if (item.type === 'divider') {
                      return slots.divider?.({
                        props: item.raw,
                        index
                      }) ?? vue.createVNode(VDivider, vue.mergeProps(item.props, {
                        "ref": itemRef,
                        "key": `divider-${index}`
                      }), null);
                    }
                    if (item.type === 'subheader') {
                      return slots.subheader?.({
                        props: item.raw,
                        index
                      }) ?? vue.createVNode(VListSubheader, vue.mergeProps(item.props, {
                        "ref": itemRef,
                        "key": `subheader-${index}`
                      }), null);
                    }
                    return slots.item?.({
                      item: item.raw,
                      internalItem: item,
                      index,
                      props: itemProps
                    }) ?? vue.createVNode(VListItem, vue.mergeProps(itemProps, {
                      "role": "option"
                    }), {
                      prepend: ({
                        isSelected
                      }) => vue.createElementVNode(vue.Fragment, null, [props.multiple && !props.hideSelected ? vue.createVNode(VCheckboxBtn, {
                        "key": item.value,
                        "modelValue": isSelected,
                        "ripple": false,
                        "tabindex": "-1",
                        "aria-hidden": true,
                        "onClick": event => event.preventDefault()
                      }, null) : undefined, camelizedProps.prependAvatar && vue.createVNode(VAvatar, {
                        "image": camelizedProps.prependAvatar
                      }, null), camelizedProps.prependIcon && vue.createVNode(VIcon, {
                        "icon": camelizedProps.prependIcon
                      }, null)]),
                      title: () => {
                        return isPristine.value ? item.title : vue.createVNode(VHighlight, {
                          "text": item.title,
                          "matches": getMatches(item)?.title,
                          "markClass": "v-autocomplete__mask",
                          "matchAll": true,
                          "ignoreCase": true
                        }, null);
                      }
                    });
                  }
                }), slots['append-item']?.()]
              }), slots['menu-footer'] && vue.createElementVNode("footer", {
                "ref": footerRef
              }, [slots['menu-footer'](menuSlotProps)])]
            })]
          }), model.value.map((item, index) => {
            function onChipClose(e) {
              e.stopPropagation();
              e.preventDefault();
              select(item, false);
            }
            const slotProps = vue.mergeProps(VChip.filterProps(item.props), {
              'onClick:close': onChipClose,
              onKeydown(e) {
                if (e.key !== 'Enter' && e.key !== ' ') return;
                e.preventDefault();
                e.stopPropagation();
                onChipClose(e);
              },
              onMousedown(e) {
                e.preventDefault();
                e.stopPropagation();
              },
              modelValue: true,
              'onUpdate:modelValue': undefined
            });
            const hasSlot = hasChips.value ? !!slots.chip : !!slots.selection;
            const slotContent = hasSlot ? ensureValidVNode(hasChips.value ? slots.chip({
              item: item.raw,
              internalItem: item,
              index,
              props: slotProps
            }) : slots.selection({
              item: item.raw,
              internalItem: item,
              index
            })) : undefined;
            if (hasSlot && !slotContent) return undefined;
            return vue.createElementVNode("div", {
              "key": item.value,
              "class": vue.normalizeClass(['v-autocomplete__selection', index === selectionIndex.value && ['v-autocomplete__selection--selected', textColorClasses.value]]),
              "style": vue.normalizeStyle(index === selectionIndex.value ? textColorStyles.value : {})
            }, [hasChips.value ? !slots.chip ? vue.createVNode(VChip, vue.mergeProps({
              "key": "chip",
              "closable": closableChips.value,
              "size": "small",
              "text": item.title,
              "disabled": item.props.disabled
            }, slotProps), null) : vue.createVNode(VDefaultsProvider, {
              "key": "chip-defaults",
              "defaults": {
                VChip: {
                  closable: closableChips.value,
                  size: 'small',
                  text: item.title
                }
              }
            }, {
              default: () => [slotContent]
            }) : slotContent ?? vue.createElementVNode("span", {
              "class": "v-autocomplete__selection-text"
            }, [item.title, props.multiple && index < model.value.length - 1 && vue.createElementVNode("span", {
              "class": "v-autocomplete__selection-comma"
            }, [vue.createTextVNode(",")])])]);
          })]),
          'append-inner': (...args) => vue.createElementVNode(vue.Fragment, null, [slots['append-inner']?.(...args), props.menuIcon ? vue.createVNode(VIcon, {
            "class": "v-autocomplete__menu-icon",
            "color": vTextFieldRef.value?.fieldIconColor,
            "icon": props.menuIcon,
            "onMousedown": onMousedownMenuIcon,
            "onClick": noop,
            "aria-hidden": true,
            "tabindex": "-1"
          }, null) : undefined, props.appendInnerIcon && vue.createVNode(InputIcon, {
            "key": "append-icon",
            "name": "appendInner",
            "color": args[0].iconColor.value
          }, null)])
        });
      });
      return forwardRefs({
        isFocused,
        isPristine,
        menu,
        search,
        filteredItems,
        select
      }, vTextFieldRef);
    }
  });

  const makeVBannerActionsProps = propsFactory({
    color: String,
    density: String,
    ...makeComponentProps()
  }, 'VBannerActions');
  const VBannerActions = genericComponent()({
    name: 'VBannerActions',
    props: makeVBannerActionsProps(),
    setup(props, {
      slots
    }) {
      provideDefaults({
        VBtn: {
          color: props.color,
          density: props.density,
          slim: true,
          variant: 'text'
        }
      });
      useRender(() => vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-banner-actions', props.class]),
        "style": vue.normalizeStyle(props.style)
      }, [slots.default?.()]));
      return {};
    }
  });

  // Utilities
  const VBannerText = createSimpleFunctional('v-banner-text');

  // Types

  const makeVBannerProps = propsFactory({
    avatar: String,
    bgColor: String,
    color: String,
    icon: IconValue,
    lines: String,
    stacked: Boolean,
    sticky: Boolean,
    text: String,
    ...makeBorderProps(),
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...makeDimensionProps(),
    ...makeDisplayProps({
      mobile: null
    }),
    ...makeElevationProps(),
    ...makeLocationProps(),
    ...makePositionProps(),
    ...makeRoundedProps(),
    ...makeTagProps(),
    ...makeThemeProps()
  }, 'VBanner');
  const VBanner = genericComponent()({
    name: 'VBanner',
    props: makeVBannerProps(),
    setup(props, {
      slots
    }) {
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.bgColor);
      const {
        borderClasses
      } = useBorder(props);
      const {
        densityClasses
      } = useDensity(props);
      const {
        displayClasses,
        mobile
      } = useDisplay(props);
      const {
        dimensionStyles
      } = useDimension(props);
      const {
        elevationClasses
      } = useElevation(props);
      const {
        locationStyles
      } = useLocation(props);
      const {
        positionClasses
      } = usePosition(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const {
        themeClasses
      } = provideTheme(props);
      const color = vue.toRef(() => props.color);
      const density = vue.toRef(() => props.density);
      provideDefaults({
        VBannerActions: {
          color,
          density
        }
      });
      useRender(() => {
        const hasText = !!(props.text || slots.text);
        const hasPrependMedia = !!(props.avatar || props.icon);
        const hasPrepend = !!(hasPrependMedia || slots.prepend);
        return vue.createVNode(props.tag, {
          "class": vue.normalizeClass(['v-banner', {
            'v-banner--stacked': props.stacked || mobile.value,
            'v-banner--sticky': props.sticky,
            [`v-banner--${props.lines}-line`]: !!props.lines
          }, themeClasses.value, backgroundColorClasses.value, borderClasses.value, densityClasses.value, displayClasses.value, elevationClasses.value, positionClasses.value, roundedClasses.value, props.class]),
          "style": vue.normalizeStyle([backgroundColorStyles.value, dimensionStyles.value, locationStyles.value, roundedStyles.value, props.style]),
          "role": "banner"
        }, {
          default: () => [hasPrepend && vue.createElementVNode("div", {
            "key": "prepend",
            "class": "v-banner__prepend"
          }, [!slots.prepend ? vue.createVNode(VAvatar, {
            "key": "prepend-avatar",
            "color": color.value,
            "density": density.value,
            "icon": props.icon,
            "image": props.avatar
          }, null) : vue.createVNode(VDefaultsProvider, {
            "key": "prepend-defaults",
            "disabled": !hasPrependMedia,
            "defaults": {
              VAvatar: {
                color: color.value,
                density: density.value,
                icon: props.icon,
                image: props.avatar
              }
            }
          }, slots.prepend)]), vue.createElementVNode("div", {
            "class": "v-banner__content"
          }, [hasText && vue.createVNode(VBannerText, {
            "key": "text"
          }, {
            default: () => [slots.text?.() ?? props.text]
          }), slots.default?.()]), slots.actions && vue.createVNode(VBannerActions, {
            "key": "actions"
          }, slots.actions)]
        });
      });
    }
  });

  // Types

  const makeVBottomNavigationProps = propsFactory({
    baseColor: String,
    bgColor: String,
    color: String,
    grow: Boolean,
    mode: {
      type: String,
      validator: v => !v || ['horizontal', 'shift'].includes(v)
    },
    height: {
      type: [Number, String],
      default: 56
    },
    active: {
      type: Boolean,
      default: true
    },
    ...makeBorderProps(),
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...makeElevationProps(),
    ...makeRoundedProps(),
    ...makeLayoutItemProps({
      name: 'bottom-navigation'
    }),
    ...makeTagProps({
      tag: 'header'
    }),
    ...makeGroupProps({
      selectedClass: 'v-btn--selected'
    }),
    ...makeThemeProps()
  }, 'VBottomNavigation');
  const VBottomNavigation = genericComponent()({
    name: 'VBottomNavigation',
    props: makeVBottomNavigationProps(),
    emits: {
      'update:active': value => true,
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const {
        themeClasses
      } = useTheme();
      const {
        borderClasses
      } = useBorder(props);
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.bgColor);
      const {
        densityClasses
      } = useDensity(props);
      const {
        elevationClasses
      } = useElevation(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const {
        ssrBootStyles
      } = useSsrBoot();
      const height = vue.computed(() => Number(props.height) - (props.density === 'comfortable' ? 8 : 0) - (props.density === 'compact' ? 16 : 0));
      const isActive = useProxiedModel(props, 'active', props.active);
      const {
        layoutItemStyles
      } = useLayoutItem({
        id: props.name,
        order: vue.computed(() => parseInt(props.order, 10)),
        position: vue.toRef(() => 'bottom'),
        layoutSize: vue.toRef(() => isActive.value ? height.value : 0),
        elementSize: height,
        active: isActive,
        absolute: vue.toRef(() => props.absolute)
      });
      useGroup(props, VBtnToggleSymbol);
      provideDefaults({
        VBtn: {
          baseColor: vue.toRef(() => props.baseColor),
          color: vue.toRef(() => props.color),
          density: vue.toRef(() => props.density),
          stacked: vue.toRef(() => props.mode !== 'horizontal'),
          variant: 'text'
        }
      }, {
        scoped: true
      });
      useRender(() => {
        return vue.createVNode(props.tag, {
          "class": vue.normalizeClass(['v-bottom-navigation', {
            'v-bottom-navigation--active': isActive.value,
            'v-bottom-navigation--grow': props.grow,
            'v-bottom-navigation--shift': props.mode === 'shift'
          }, themeClasses.value, backgroundColorClasses.value, borderClasses.value, densityClasses.value, elevationClasses.value, roundedClasses.value, props.class]),
          "style": vue.normalizeStyle([backgroundColorStyles.value, layoutItemStyles.value, {
            height: convertToUnit(height.value)
          }, ssrBootStyles.value, roundedStyles.value, props.style])
        }, {
          default: () => [slots.default && vue.createElementVNode("div", {
            "class": "v-bottom-navigation__content"
          }, [slots.default()])]
        });
      });
      return {};
    }
  });

  // Types

  const makeVDialogProps = propsFactory({
    fullscreen: Boolean,
    scrollable: Boolean,
    ...omit(makeVOverlayProps({
      captureFocus: true,
      location: 'center center',
      origin: 'center center',
      scrollStrategy: 'block',
      transition: {
        component: VDialogTransition
      },
      zIndex: 2400,
      retainFocus: true
    }), ['disableInitialFocus'])
  }, 'VDialog');
  const VDialog = genericComponent()({
    name: 'VDialog',
    props: makeVDialogProps(),
    emits: {
      'update:modelValue': value => true,
      afterEnter: () => true,
      afterLeave: () => true
    },
    setup(props, {
      emit,
      slots
    }) {
      const isActive = useProxiedModel(props, 'modelValue');
      const {
        scopeId
      } = useScopeId();
      const overlay = vue.ref();
      function onAfterEnter() {
        emit('afterEnter');
        if ((props.scrim || props.retainFocus) && overlay.value?.contentEl && !overlay.value.contentEl.contains(getActiveElement())) {
          overlay.value.contentEl.focus({
            preventScroll: true
          });
        }
      }
      function onAfterLeave() {
        emit('afterLeave');
      }
      vue.watch(isActive, async val => {
        if (!val) {
          await vue.nextTick();
          overlay.value?.activatorEl?.focus({
            preventScroll: true
          });
        }
      });
      useRender(() => {
        const overlayProps = VOverlay.filterProps(props);
        const activatorProps = vue.mergeProps({
          'aria-haspopup': 'dialog'
        }, props.activatorProps);
        const contentProps = vue.mergeProps({
          tabindex: -1
        }, props.contentProps);
        const locationStrategy = props.fullscreen ? noop : props.locationStrategy;
        return vue.createVNode(VOverlay, vue.mergeProps({
          "ref": overlay,
          "class": ['v-dialog', {
            'v-dialog--fullscreen': props.fullscreen,
            'v-dialog--scrollable': props.scrollable
          }, props.class],
          "style": props.style
        }, overlayProps, {
          "modelValue": isActive.value,
          "onUpdate:modelValue": $event => isActive.value = $event,
          "aria-modal": "true",
          "activatorProps": activatorProps,
          "contentProps": contentProps,
          "height": !props.fullscreen ? props.height : undefined,
          "width": !props.fullscreen ? props.width : undefined,
          "maxHeight": !props.fullscreen ? props.maxHeight : undefined,
          "maxWidth": !props.fullscreen ? props.maxWidth : undefined,
          "locationStrategy": locationStrategy,
          "role": "dialog",
          "onAfterEnter": onAfterEnter,
          "onAfterLeave": onAfterLeave
        }, scopeId), {
          activator: slots.activator,
          default: (...args) => vue.createVNode(VDefaultsProvider, {
            "root": "VDialog"
          }, {
            default: () => [slots.default?.(...args)]
          })
        });
      });
      return forwardRefs({}, overlay);
    }
  });

  // Types

  const makeVBottomSheetProps = propsFactory({
    inset: Boolean,
    ...makeVDialogProps({
      transition: 'bottom-sheet-transition',
      location: 'bottom center',
      origin: 'bottom center',
      viewportMargin: 0
    })
  }, 'VBottomSheet');
  const VBottomSheet = genericComponent()({
    name: 'VBottomSheet',
    props: makeVBottomSheetProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const isActive = useProxiedModel(props, 'modelValue');
      useRender(() => {
        const dialogProps = VDialog.filterProps(props);
        return vue.createVNode(VDialog, vue.mergeProps(dialogProps, {
          "contentClass": ['v-bottom-sheet__content', props.contentClass],
          "modelValue": isActive.value,
          "onUpdate:modelValue": $event => isActive.value = $event,
          "class": ['v-bottom-sheet', {
            'v-bottom-sheet--inset': props.inset
          }, props.class],
          "style": props.style
        }), slots);
      });
      return {};
    }
  });

  const makeVBreadcrumbsDividerProps = propsFactory({
    divider: [Number, String],
    ...makeComponentProps()
  }, 'VBreadcrumbsDivider');
  const VBreadcrumbsDivider = genericComponent()({
    name: 'VBreadcrumbsDivider',
    props: makeVBreadcrumbsDividerProps(),
    setup(props, {
      slots
    }) {
      useRender(() => vue.createElementVNode("li", {
        "aria-hidden": "true",
        "class": vue.normalizeClass(['v-breadcrumbs-divider', props.class]),
        "style": vue.normalizeStyle(props.style)
      }, [slots?.default?.() ?? props.divider]));
      return {};
    }
  });

  const makeVBreadcrumbsItemProps = propsFactory({
    active: Boolean,
    activeClass: String,
    activeColor: String,
    color: String,
    disabled: Boolean,
    title: String,
    ...makeComponentProps(),
    ...pick(makeDimensionProps(), ['width', 'maxWidth']),
    ...makeRouterProps(),
    ...makeTagProps({
      tag: 'li'
    })
  }, 'VBreadcrumbsItem');
  const VBreadcrumbsItem = genericComponent()({
    name: 'VBreadcrumbsItem',
    props: makeVBreadcrumbsItemProps(),
    setup(props, {
      slots,
      attrs
    }) {
      const link = useLink(props, attrs);
      const isActive = vue.computed(() => props.active || link.isActive?.value);
      const {
        dimensionStyles
      } = useDimension(props);
      const {
        textColorClasses,
        textColorStyles
      } = useTextColor(() => isActive.value ? props.activeColor : props.color);
      useRender(() => {
        return vue.createVNode(props.tag, {
          "class": vue.normalizeClass(['v-breadcrumbs-item', {
            'v-breadcrumbs-item--active': isActive.value,
            'v-breadcrumbs-item--disabled': props.disabled,
            [`${props.activeClass}`]: isActive.value && props.activeClass
          }, textColorClasses.value, props.class]),
          "style": vue.normalizeStyle([textColorStyles.value, dimensionStyles.value, props.style]),
          "aria-current": isActive.value ? 'page' : undefined
        }, {
          default: () => [!link.isLink.value ? slots.default?.() ?? props.title : vue.createElementVNode("a", vue.mergeProps({
            "class": "v-breadcrumbs-item--link",
            "onClick": link.navigate.value
          }, link.linkProps), [slots.default?.() ?? props.title])]
        });
      });
      return {};
    }
  });

  // Types

  const makeVBreadcrumbsProps = propsFactory({
    activeClass: String,
    activeColor: String,
    bgColor: String,
    color: String,
    disabled: Boolean,
    divider: {
      type: String,
      default: '/'
    },
    icon: IconValue,
    items: {
      type: Array,
      default: () => []
    },
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...makeRoundedProps(),
    ...makeTagProps({
      tag: 'ul'
    })
  }, 'VBreadcrumbs');
  const VBreadcrumbs = genericComponent()({
    name: 'VBreadcrumbs',
    props: makeVBreadcrumbsProps(),
    setup(props, {
      slots
    }) {
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.bgColor);
      const {
        densityClasses
      } = useDensity(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      provideDefaults({
        VBreadcrumbsDivider: {
          divider: vue.toRef(() => props.divider)
        },
        VBreadcrumbsItem: {
          activeClass: vue.toRef(() => props.activeClass),
          activeColor: vue.toRef(() => props.activeColor),
          color: vue.toRef(() => props.color),
          disabled: vue.toRef(() => props.disabled)
        }
      });
      const items = vue.computed(() => props.items.map(item => {
        return typeof item === 'string' ? {
          item: {
            title: item
          },
          raw: item
        } : {
          item,
          raw: item
        };
      }));
      useRender(() => {
        const hasPrepend = !!(slots.prepend || props.icon);
        return vue.createVNode(props.tag, {
          "class": vue.normalizeClass(['v-breadcrumbs', backgroundColorClasses.value, densityClasses.value, roundedClasses.value, props.class]),
          "style": vue.normalizeStyle([backgroundColorStyles.value, roundedStyles.value, props.style])
        }, {
          default: () => [hasPrepend && vue.createElementVNode("li", {
            "key": "prepend",
            "class": "v-breadcrumbs__prepend"
          }, [!slots.prepend ? vue.createVNode(VIcon, {
            "key": "prepend-icon",
            "start": true,
            "icon": props.icon
          }, null) : vue.createVNode(VDefaultsProvider, {
            "key": "prepend-defaults",
            "disabled": !props.icon,
            "defaults": {
              VIcon: {
                icon: props.icon,
                start: true
              }
            }
          }, slots.prepend)]), items.value.map(({
            item,
            raw
          }, index, array) => vue.createElementVNode(vue.Fragment, null, [slots.item?.({
            item,
            index
          }) ?? vue.createVNode(VBreadcrumbsItem, vue.mergeProps({
            "key": index,
            "disabled": index >= array.length - 1
          }, typeof item === 'string' ? {
            title: item
          } : item), {
            default: slots.title ? () => slots.title?.({
              item,
              index
            }) : undefined
          }), index < array.length - 1 && vue.createVNode(VBreadcrumbsDivider, null, {
            default: slots.divider ? () => slots.divider?.({
              item: raw,
              index
            }) : undefined
          })])), slots.default?.()]
        });
      });
      return {};
    }
  });

  // Types

  const makeVIconBtnProps = propsFactory({
    active: {
      type: Boolean,
      default: undefined
    },
    activeColor: String,
    activeIcon: [String, Function, Object],
    activeVariant: String,
    baseVariant: {
      type: String,
      default: 'tonal'
    },
    disabled: Boolean,
    height: [Number, String],
    width: [Number, String],
    hideOverlay: Boolean,
    icon: [String, Function, Object],
    iconColor: String,
    loading: Boolean,
    opacity: [Number, String],
    readonly: Boolean,
    rotate: [Number, String],
    size: {
      type: [Number, String],
      default: 'default'
    },
    sizes: {
      type: Array,
      default: () => [['x-small', 16], ['small', 24], ['default', 40], ['large', 48], ['x-large', 56]]
    },
    text: {
      type: [String, Number, Boolean],
      default: undefined
    },
    ...makeBorderProps(),
    ...makeComponentProps(),
    ...makeElevationProps(),
    ...makeIconSizeProps(),
    ...makeRoundedProps(),
    ...makeTagProps({
      tag: 'button'
    }),
    ...makeThemeProps(),
    ...makeVariantProps({
      variant: 'flat'
    })
  }, 'VIconBtn');
  const VIconBtn = genericComponent()({
    name: 'VIconBtn',
    props: makeVIconBtnProps(),
    emits: {
      'update:active': value => true
    },
    setup(props, {
      attrs,
      slots
    }) {
      const isActive = useProxiedModel(props, 'active');
      const {
        themeClasses
      } = provideTheme(props);
      const {
        borderClasses
      } = useBorder(props);
      const {
        elevationClasses
      } = useElevation(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const {
        colorClasses,
        colorStyles,
        variantClasses
      } = useVariant(() => ({
        color: (() => {
          if (props.disabled) return undefined;
          if (!isActive.value) return props.color;
          // Use an inline fallback as opposed to setting a default color
          // because non-toggle buttons are default flat whereas toggle
          // buttons are default tonal and active flat. The exact use
          // case for this is a toggle button with no active color.
          return props.activeColor ?? props.color ?? 'surface-variant';
        })(),
        variant: (() => {
          if (isActive.value === undefined) return props.variant;
          if (isActive.value) return props.activeVariant ?? props.variant;
          return props.baseVariant ?? props.variant;
        })()
      }));
      const btnSizeMap = new Map(props.sizes);
      function onClick() {
        if (props.disabled || props.readonly || isActive.value === undefined || props.tag === 'a' && attrs.href) return;
        isActive.value = !isActive.value;
      }
      useRender(() => {
        const icon = isActive.value ? props.activeIcon ?? props.icon : props.icon;
        const _btnSize = props.size;
        const hasNamedSize = btnSizeMap.has(_btnSize);
        const btnSize = hasNamedSize ? btnSizeMap.get(_btnSize) : _btnSize;
        const btnHeight = props.height ?? btnSize;
        const btnWidth = props.width ?? btnSize;
        const {
          iconSize
        } = useIconSizes(props, () => new Map(props.iconSizes).get(_btnSize));
        const iconProps = {
          icon,
          size: iconSize.value,
          color: props.iconColor,
          opacity: props.opacity
        };
        return vue.createVNode(props.tag, {
          "type": props.tag === 'button' ? 'button' : undefined,
          "class": vue.normalizeClass([{
            'v-icon-btn': true,
            'v-icon-btn--active': isActive.value,
            'v-icon-btn--disabled': props.disabled,
            'v-icon-btn--loading': props.loading,
            'v-icon-btn--readonly': props.readonly,
            [`v-icon-btn--${props.size}`]: true
          }, themeClasses.value, colorClasses.value, borderClasses.value, elevationClasses.value, roundedClasses.value, variantClasses.value, props.class]),
          "style": vue.normalizeStyle([{
            '--v-icon-btn-rotate': convertToUnit(props.rotate, 'deg'),
            '--v-icon-btn-height': convertToUnit(btnHeight),
            '--v-icon-btn-width': convertToUnit(btnWidth)
          }, colorStyles.value, roundedStyles.value, props.style]),
          "tabindex": props.disabled || props.readonly ? -1 : 0,
          "onClick": onClick
        }, {
          default: () => [genOverlays(!props.hideOverlay, 'v-icon-btn'), vue.createElementVNode("div", {
            "class": "v-icon-btn__content",
            "data-no-activator": ""
          }, [!slots.default && icon ? vue.createVNode(VIcon, vue.mergeProps({
            "key": "content-icon"
          }, iconProps), null) : vue.createVNode(VDefaultsProvider, {
            "key": "content-defaults",
            "disabled": !icon,
            "defaults": {
              VIcon: {
                ...iconProps
              }
            }
          }, {
            default: () => slots.default?.() ?? vue.toDisplayString(props.text)
          })]), !!props.loading && vue.createElementVNode("span", {
            "key": "loader",
            "class": "v-icon-btn__loader"
          }, [slots.loader?.() ?? vue.createVNode(VProgressCircular, {
            "color": typeof props.loading === 'boolean' ? undefined : props.loading,
            "indeterminate": "disable-shrink",
            "width": "2",
            "size": iconSize.value
          }, null)])]
        });
      });
      return {};
    }
  });

  function isLeapYear(year) {
    return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
  }

  // Types

  const PARSE_REGEX = /^(\d{4})-(\d{1,2})(-(\d{1,2}))?([^\d]+(\d{1,2}))?(:(\d{1,2}))?(:(\d{1,2}))?$/;
  const PARSE_TIME = /(\d\d?)(:(\d\d?)|)(:(\d\d?)|)/;
  const DAYS_IN_MONTH = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
  const DAYS_IN_MONTH_LEAP = [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
  const DAYS_IN_MONTH_MIN = 28;
  const DAYS_IN_MONTH_MAX = 31;
  const MONTH_MAX = 12;
  const MONTH_MIN = 1;
  const DAY_MIN = 1;
  const DAYS_IN_WEEK = 7;
  const MINUTES_IN_HOUR = 60;
  const MINUTE_MAX = 59;
  const MINUTES_IN_DAY = 24 * 60;
  const HOURS_IN_DAY = 24;
  const HOUR_MAX = 23;
  const FIRST_HOUR = 0;
  const OFFSET_YEAR = 10000;
  const OFFSET_MONTH = 100;
  const OFFSET_HOUR = 100;
  const OFFSET_TIME = 10000;
  function getStartOfWeek(timestamp, weekdays, today) {
    const start = copyTimestamp(timestamp);
    findWeekday(start, weekdays[0], prevDay);
    updateFormatted(start);
    if (today) {
      updateRelative(start, today, start.hasTime);
    }
    return start;
  }
  function getEndOfWeek(timestamp, weekdays, today) {
    const end = copyTimestamp(timestamp);
    findWeekday(end, weekdays[weekdays.length - 1]);
    updateFormatted(end);
    if (today) {
      updateRelative(end, today, end.hasTime);
    }
    return end;
  }
  function getStartOfMonth(timestamp) {
    const start = copyTimestamp(timestamp);
    start.day = DAY_MIN;
    updateWeekday(start);
    updateFormatted(start);
    return start;
  }
  function getEndOfMonth(timestamp) {
    const end = copyTimestamp(timestamp);
    end.day = daysInMonth(end.year, end.month);
    updateWeekday(end);
    updateFormatted(end);
    return end;
  }
  function validateNumber(input) {
    return isFinite(parseInt(input));
  }
  function validateTime(input) {
    return typeof input === 'number' && isFinite(input) || !!PARSE_TIME.exec(input) || typeof input === 'object' && isFinite(input.hour) && isFinite(input.minute);
  }
  function parseTime(input) {
    if (typeof input === 'number') {
      // when a number is given, it's minutes since 12:00am
      return input;
    } else if (typeof input === 'string') {
      // when a string is given, it's a hh:mm:ss format where seconds are optional
      const parts = PARSE_TIME.exec(input);
      if (!parts) {
        return false;
      }
      return parseInt(parts[1]) * 60 + parseInt(parts[3] || 0);
    } else if (typeof input === 'object') {
      // when an object is given, it must have hour and minute
      if (typeof input.hour !== 'number' || typeof input.minute !== 'number') {
        return false;
      }
      return input.hour * 60 + input.minute;
    } else {
      // unsupported type
      return false;
    }
  }
  function validateTimestamp(input) {
    return typeof input === 'number' && isFinite(input) || typeof input === 'string' && !!PARSE_REGEX.exec(input) || input instanceof Date;
  }
  function parseTimestamp(input, required = false, now) {
    if (typeof input === 'number' && isFinite(input)) {
      input = new Date(input);
    }
    if (input instanceof Date) {
      const date = parseDate(input);
      return date;
    }
    if (typeof input !== 'string') {
      if (required) {
        throw new Error(`${input} is not a valid timestamp. It must be a Date, number of milliseconds since Epoch, or a string in the format of YYYY-MM-DD or YYYY-MM-DD hh:mm. Zero-padding is optional and seconds are ignored.`);
      }
      return null;
    }

    // YYYY-MM-DD hh:mm:ss
    const parts = PARSE_REGEX.exec(input);
    if (!parts) {
      if (required) {
        throw new Error(`${input} is not a valid timestamp. It must be a Date, number of milliseconds since Epoch, or a string in the format of YYYY-MM-DD or YYYY-MM-DD hh:mm. Zero-padding is optional and seconds are ignored.`);
      }
      return null;
    }
    const timestamp = {
      date: input,
      time: '',
      year: parseInt(parts[1]),
      month: parseInt(parts[2]),
      day: parseInt(parts[4]) || 1,
      hour: parseInt(parts[6]) || 0,
      minute: parseInt(parts[8]) || 0,
      weekday: 0,
      hasDay: !!parts[4],
      hasTime: !!(parts[6] && parts[8]),
      past: false,
      present: false,
      future: false
    };
    updateWeekday(timestamp);
    updateFormatted(timestamp);
    return timestamp;
  }
  function parseDate(date) {
    return updateFormatted({
      date: '',
      time: '',
      year: date.getFullYear(),
      month: date.getMonth() + 1,
      day: date.getDate(),
      weekday: date.getDay(),
      hour: date.getHours(),
      minute: date.getMinutes(),
      hasDay: true,
      hasTime: true,
      past: false,
      present: true,
      future: false
    });
  }
  function getDayIdentifier(timestamp) {
    return timestamp.year * OFFSET_YEAR + timestamp.month * OFFSET_MONTH + timestamp.day;
  }
  function getTimeIdentifier(timestamp) {
    return timestamp.hour * OFFSET_HOUR + timestamp.minute;
  }
  function getTimestampIdentifier(timestamp) {
    return getDayIdentifier(timestamp) * OFFSET_TIME + getTimeIdentifier(timestamp);
  }
  function updateRelative(timestamp, now, time = false) {
    let a = getDayIdentifier(now);
    let b = getDayIdentifier(timestamp);
    let present = a === b;
    if (timestamp.hasTime && time && present) {
      a = getTimeIdentifier(now);
      b = getTimeIdentifier(timestamp);
      present = a === b;
    }
    timestamp.past = b < a;
    timestamp.present = present;
    timestamp.future = b > a;
    return timestamp;
  }
  function isTimedless(input) {
    return input instanceof Date || typeof input === 'number' && isFinite(input);
  }
  function updateHasTime(timestamp, hasTime, now) {
    if (timestamp.hasTime !== hasTime) {
      timestamp.hasTime = hasTime;
      if (!hasTime) {
        timestamp.hour = HOUR_MAX;
        timestamp.minute = MINUTE_MAX;
        timestamp.time = getTime(timestamp);
      }
    }
    return timestamp;
  }
  function updateMinutes(timestamp, minutes, now) {
    timestamp.hasTime = true;
    timestamp.hour = 0;
    timestamp.minute = 0;
    nextMinutes(timestamp, minutes);
    updateFormatted(timestamp);
    if (now) {
      updateRelative(timestamp, now, true);
    }
    return timestamp;
  }
  function updateWeekday(timestamp) {
    timestamp.weekday = getWeekday(timestamp);
    return timestamp;
  }
  function updateFormatted(timestamp) {
    timestamp.time = getTime(timestamp);
    timestamp.date = getDate$1(timestamp);
    return timestamp;
  }
  function getWeekday(timestamp) {
    if (timestamp.hasDay) {
      const _ = Math.floor;
      const k = timestamp.day;
      const m = (timestamp.month + 9) % MONTH_MAX + 1;
      const C = _(timestamp.year / 100);
      const Y = timestamp.year % 100 - (timestamp.month <= 2 ? 1 : 0);
      return ((k + _(2.6 * m - 0.2) - 2 * C + Y + _(Y / 4) + _(C / 4)) % 7 + 7) % 7;
    }
    return timestamp.weekday;
  }
  function daysInMonth(year, month) {
    return isLeapYear(year) ? DAYS_IN_MONTH_LEAP[month] : DAYS_IN_MONTH[month];
  }
  function copyTimestamp(timestamp) {
    if (timestamp == null) return null;
    const {
      date,
      time,
      year,
      month,
      day,
      weekday,
      hour,
      minute,
      hasDay,
      hasTime,
      past,
      present,
      future
    } = timestamp;
    return {
      date,
      time,
      year,
      month,
      day,
      weekday,
      hour,
      minute,
      hasDay,
      hasTime,
      past,
      present,
      future
    };
  }
  function padNumber(x, length) {
    let padded = String(x);
    while (padded.length < length) {
      padded = '0' + padded;
    }
    return padded;
  }
  function getDate$1(timestamp) {
    let str = `${padNumber(timestamp.year, 4)}-${padNumber(timestamp.month, 2)}`;
    if (timestamp.hasDay) str += `-${padNumber(timestamp.day, 2)}`;
    return str;
  }
  function getTime(timestamp) {
    if (!timestamp.hasTime) {
      return '';
    }
    return `${padNumber(timestamp.hour, 2)}:${padNumber(timestamp.minute, 2)}`;
  }
  function nextMinutes(timestamp, minutes) {
    timestamp.minute += minutes;
    while (timestamp.minute >= MINUTES_IN_HOUR) {
      timestamp.minute -= MINUTES_IN_HOUR;
      timestamp.hour++;
      if (timestamp.hour >= HOURS_IN_DAY) {
        nextDay(timestamp);
        timestamp.hour = FIRST_HOUR;
      }
    }
    return timestamp;
  }
  function nextDay(timestamp) {
    timestamp.day++;
    timestamp.weekday = (timestamp.weekday + 1) % DAYS_IN_WEEK;
    if (timestamp.day > DAYS_IN_MONTH_MIN && timestamp.day > daysInMonth(timestamp.year, timestamp.month)) {
      timestamp.day = DAY_MIN;
      timestamp.month++;
      if (timestamp.month > MONTH_MAX) {
        timestamp.month = MONTH_MIN;
        timestamp.year++;
      }
    }
    return timestamp;
  }
  function prevDay(timestamp) {
    timestamp.day--;
    timestamp.weekday = (timestamp.weekday + 6) % DAYS_IN_WEEK;
    if (timestamp.day < DAY_MIN) {
      timestamp.month--;
      if (timestamp.month < MONTH_MIN) {
        timestamp.year--;
        timestamp.month = MONTH_MAX;
      }
      timestamp.day = daysInMonth(timestamp.year, timestamp.month);
    }
    return timestamp;
  }
  function relativeDays(timestamp, mover = nextDay, days = 1) {
    while (--days >= 0) mover(timestamp);
    return timestamp;
  }
  function diffMinutes(min, max) {
    const Y = (max.year - min.year) * 525600;
    const M = (max.month - min.month) * 43800;
    const D = (max.day - min.day) * 1440;
    const h = (max.hour - min.hour) * 60;
    const m = max.minute - min.minute;
    return Y + M + D + h + m;
  }
  function findWeekday(timestamp, weekday, mover = nextDay, maxDays = 6) {
    while (timestamp.weekday !== weekday && --maxDays >= 0) mover(timestamp);
    return timestamp;
  }
  function getWeekdaySkips(weekdays) {
    const skips = [1, 1, 1, 1, 1, 1, 1];
    const filled = [0, 0, 0, 0, 0, 0, 0];
    for (let i = 0; i < weekdays.length; i++) {
      filled[weekdays[i]] = 1;
    }
    for (let k = 0; k < DAYS_IN_WEEK; k++) {
      let skip = 1;
      for (let j = 1; j < DAYS_IN_WEEK; j++) {
        const next = (k + j) % DAYS_IN_WEEK;
        if (filled[next]) {
          break;
        }
        skip++;
      }
      skips[k] = filled[k] * skip;
    }
    return skips;
  }
  function timestampToDate(timestamp) {
    const time = `${padNumber(timestamp.hour, 2)}:${padNumber(timestamp.minute, 2)}`;
    const date = timestamp.date;
    return new Date(`${date}T${time}:00+00:00`);
  }
  function createDayList(start, end, now, weekdaySkips, max = 42, min = 0) {
    const stop = getDayIdentifier(end);
    const days = [];
    let current = copyTimestamp(start);
    let currentIdentifier = 0;
    let stopped = currentIdentifier === stop;
    if (stop < getDayIdentifier(start)) {
      throw new Error('End date is earlier than start date.');
    }
    while ((!stopped || days.length < min) && days.length < max) {
      currentIdentifier = getDayIdentifier(current);
      stopped = stopped || currentIdentifier === stop;
      if (weekdaySkips[current.weekday] === 0) {
        current = nextDay(current);
        continue;
      }
      const day = copyTimestamp(current);
      updateFormatted(day);
      updateRelative(day, now);
      days.push(day);
      current = relativeDays(current, nextDay, weekdaySkips[current.weekday]);
    }
    if (!days.length) throw new Error('No dates found using specified start date, end date, and weekdays.');
    return days;
  }
  function createIntervalList(timestamp, first, minutes, count, now) {
    const intervals = [];
    for (let i = 0; i < count; i++) {
      const mins = first + i * minutes;
      const int = copyTimestamp(timestamp);
      intervals.push(updateMinutes(int, mins, now));
    }
    return intervals;
  }
  function createNativeLocaleFormatter(locale, getOptions) {
    const emptyFormatter = (_t, _s) => '';
    if (typeof Intl === 'undefined' || typeof Intl.DateTimeFormat === 'undefined') {
      return emptyFormatter;
    }
    return (timestamp, short) => {
      try {
        const intlFormatter = new Intl.DateTimeFormat(locale || undefined, getOptions(timestamp, short));
        return intlFormatter.format(timestampToDate(timestamp));
      } catch (e) {
        return '';
      }
    };
  }
  function validateWeekdays(input) {
    if (typeof input === 'string') {
      input = input.split(',');
    }
    if (Array.isArray(input)) {
      const ints = input.map(x => parseInt(x));
      if (ints.length > DAYS_IN_WEEK || ints.length === 0) {
        return false;
      }
      const visited = {};
      let wrapped = false;
      for (let i = 0; i < ints.length; i++) {
        const x = ints[i];
        if (!isFinite(x) || x < 0 || x >= DAYS_IN_WEEK) {
          return false;
        }
        if (i > 0) {
          const d = x - ints[i - 1];
          if (d < 0) {
            if (wrapped) {
              return false;
            }
            wrapped = true;
          } else if (d === 0) {
            return false;
          }
        }
        if (visited[x]) {
          return false;
        }
        visited[x] = true;
      }
      return true;
    }
    return false;
  }

  // Utilities

  // Types

  function useTimes(props) {
    const times = vue.reactive({
      now: parseTimestamp('0000-00-00 00:00', true),
      today: parseTimestamp('0000-00-00', true)
    });
    const parsedNow = vue.computed(() => {
      return props.now && validateTimestamp(props.now) ? parseTimestamp(props.now, true) : null;
    });
    function setPresent() {
      times.now.present = times.today.present = true;
      times.now.past = times.today.past = false;
      times.now.future = times.today.future = false;
    }
    function getNow() {
      return parseDate(new Date());
    }
    function updateDay(now, target) {
      if (now.date !== target.date) {
        target.year = now.year;
        target.month = now.month;
        target.day = now.day;
        target.weekday = now.weekday;
        target.date = now.date;
      }
    }
    function updateTime(now, target) {
      if (now.time !== target.time) {
        target.hour = now.hour;
        target.minute = now.minute;
        target.time = now.time;
      }
    }
    function updateTimes() {
      const now = parsedNow.value || getNow();
      updateDay(now, times.now);
      updateTime(now, times.now);
      updateDay(now, times.today);
    }
    vue.watch(parsedNow, updateTimes);
    updateTimes();
    setPresent();
    return {
      times,
      parsedNow,
      updateTimes,
      setPresent,
      getNow,
      updateDay,
      updateTime
    };
  }

  // Utilities

  // Types

  function weekInfo(locale) {
    // https://simplelocalize.io/data/locales/
    // then `new Intl.Locale(...).getWeekInfo()`
    const code = locale.slice(-2).toUpperCase();
    switch (true) {
      case locale === 'GB-alt-variant':
        {
          return {
            firstDay: 0,
            firstWeekSize: 4
          };
        }
      case locale === '001':
        {
          return {
            firstDay: 1,
            firstWeekSize: 1
          };
        }
      case `AG AS BD BR BS BT BW BZ CA CO DM DO ET GT GU HK HN ID IL IN JM JP KE
    KH KR LA MH MM MO MT MX MZ NI NP PA PE PH PK PR PY SA SG SV TH TT TW UM US
    VE VI WS YE ZA ZW`.includes(code):
        {
          return {
            firstDay: 0,
            firstWeekSize: 1
          };
        }
      case `AI AL AM AR AU AZ BA BM BN BY CL CM CN CR CY EC GE HR KG KZ LB LK LV
    MD ME MK MN MY NZ RO RS SI TJ TM TR UA UY UZ VN XK`.includes(code):
        {
          return {
            firstDay: 1,
            firstWeekSize: 1
          };
        }
      case `AD AN AT AX BE BG CH CZ DE DK EE ES FI FJ FO FR GB GF GP GR HU IE IS
    IT LI LT LU MC MQ NL NO PL RE RU SE SK SM VA`.includes(code):
        {
          return {
            firstDay: 1,
            firstWeekSize: 4
          };
        }
      case `AE AF BH DJ DZ EG IQ IR JO KW LY OM QA SD SY`.includes(code):
        {
          return {
            firstDay: 6,
            firstWeekSize: 1
          };
        }
      case code === 'MV':
        {
          return {
            firstDay: 5,
            firstWeekSize: 1
          };
        }
      case code === 'PT':
        {
          return {
            firstDay: 0,
            firstWeekSize: 4
          };
        }
      default:
        return null;
    }
  }
  function getWeekArray(date, locale, firstDayOfWeek) {
    const weeks = [];
    let currentWeek = [];
    const firstDayOfMonth = startOfMonth(date);
    const lastDayOfMonth = endOfMonth(date);
    const first = firstDayOfWeek ?? weekInfo(locale)?.firstDay ?? 0;
    const firstDayWeekIndex = (firstDayOfMonth.getDay() - first + 7) % 7;
    const lastDayWeekIndex = (lastDayOfMonth.getDay() - first + 7) % 7;
    for (let i = 0; i < firstDayWeekIndex; i++) {
      const adjacentDay = new Date(firstDayOfMonth);
      adjacentDay.setDate(adjacentDay.getDate() - (firstDayWeekIndex - i));
      currentWeek.push(adjacentDay);
    }
    for (let i = 1; i <= lastDayOfMonth.getDate(); i++) {
      const day = new Date(date.getFullYear(), date.getMonth(), i);

      // Add the day to the current week
      currentWeek.push(day);

      // If the current week has 7 days, add it to the weeks array and start a new week
      if (currentWeek.length === 7) {
        weeks.push(currentWeek);
        currentWeek = [];
      }
    }
    for (let i = 1; i < 7 - lastDayWeekIndex; i++) {
      const adjacentDay = new Date(lastDayOfMonth);
      adjacentDay.setDate(adjacentDay.getDate() + i);
      currentWeek.push(adjacentDay);
    }
    if (currentWeek.length > 0) {
      weeks.push(currentWeek);
    }
    return weeks;
  }
  function startOfWeek(date, locale, firstDayOfWeek) {
    let day = (firstDayOfWeek ?? weekInfo(locale)?.firstDay ?? 0) % 7;

    // prevent infinite loop
    if (![0, 1, 2, 3, 4, 5, 6].includes(day)) {
      consoleWarn('Invalid firstDayOfWeek, expected discrete number in range [0-6]');
      day = 0;
    }
    const d = new Date(date);
    while (d.getDay() !== day) {
      d.setDate(d.getDate() - 1);
    }
    return d;
  }
  function endOfWeek(date, locale) {
    const d = new Date(date);
    const lastDay = ((weekInfo(locale)?.firstDay ?? 0) + 6) % 7;
    while (d.getDay() !== lastDay) {
      d.setDate(d.getDate() + 1);
    }
    return d;
  }
  function startOfMonth(date) {
    return new Date(date.getFullYear(), date.getMonth(), 1);
  }
  function endOfMonth(date) {
    return new Date(date.getFullYear(), date.getMonth() + 1, 0);
  }
  function parseLocalDate(value) {
    const parts = value.split('-').map(Number);

    // new Date() uses local time zone when passing individual date component values
    return new Date(parts[0], parts[1] - 1, parts[2]);
  }
  const _YYYMMDD = /^([12]\d{3}-([1-9]|0[1-9]|1[0-2])-([1-9]|0[1-9]|[12]\d|3[01]))$/;
  function date(value) {
    if (value == null) return new Date();
    if (value instanceof Date) return value;
    if (typeof value === 'string') {
      let parsed;
      if (_YYYMMDD.test(value)) {
        return parseLocalDate(value);
      } else {
        parsed = Date.parse(value);
      }
      if (!isNaN(parsed)) return new Date(parsed);
    }
    return null;
  }
  const sundayJanuarySecond2000 = new Date(2000, 0, 2);
  function getWeekdays(locale, firstDayOfWeek, weekdayFormat) {
    const daysFromSunday = firstDayOfWeek ?? weekInfo(locale)?.firstDay ?? 0;
    return createRange(7).map(i => {
      const weekday = new Date(sundayJanuarySecond2000);
      weekday.setDate(sundayJanuarySecond2000.getDate() + daysFromSunday + i);
      return new Intl.DateTimeFormat(locale, {
        weekday: weekdayFormat ?? 'narrow'
      }).format(weekday);
    });
  }
  function format(value, formatString, locale, formats) {
    const newDate = date(value) ?? new Date();
    const customFormat = formats?.[formatString];
    if (typeof customFormat === 'function') {
      return customFormat(newDate, formatString, locale);
    }
    let options = {};
    switch (formatString) {
      case 'fullDate':
        options = {
          year: 'numeric',
          month: 'short',
          day: 'numeric'
        };
        break;
      case 'fullDateWithWeekday':
        options = {
          weekday: 'long',
          year: 'numeric',
          month: 'long',
          day: 'numeric'
        };
        break;
      case 'normalDate':
        const day = newDate.getDate();
        const month = new Intl.DateTimeFormat(locale, {
          month: 'long'
        }).format(newDate);
        return `${day} ${month}`;
      case 'normalDateWithWeekday':
        options = {
          weekday: 'short',
          day: 'numeric',
          month: 'short'
        };
        break;
      case 'shortDate':
        options = {
          month: 'short',
          day: 'numeric'
        };
        break;
      case 'year':
        options = {
          year: 'numeric'
        };
        break;
      case 'month':
        options = {
          month: 'long'
        };
        break;
      case 'monthShort':
        options = {
          month: 'short'
        };
        break;
      case 'monthAndYear':
        options = {
          month: 'long',
          year: 'numeric'
        };
        break;
      case 'monthAndDate':
        options = {
          month: 'long',
          day: 'numeric'
        };
        break;
      case 'weekday':
        options = {
          weekday: 'long'
        };
        break;
      case 'weekdayShort':
        options = {
          weekday: 'short'
        };
        break;
      case 'dayOfMonth':
        return new Intl.NumberFormat(locale).format(newDate.getDate());
      case 'hours12h':
        options = {
          hour: 'numeric',
          hour12: true
        };
        break;
      case 'hours24h':
        options = {
          hour: 'numeric',
          hour12: false
        };
        break;
      case 'minutes':
        options = {
          minute: 'numeric'
        };
        break;
      case 'seconds':
        options = {
          second: 'numeric'
        };
        break;
      case 'fullTime':
        options = {
          hour: 'numeric',
          minute: 'numeric'
        };
        break;
      case 'fullTime12h':
        options = {
          hour: 'numeric',
          minute: 'numeric',
          hour12: true
        };
        break;
      case 'fullTime24h':
        options = {
          hour: 'numeric',
          minute: 'numeric',
          hour12: false
        };
        break;
      case 'fullDateTime':
        options = {
          year: 'numeric',
          month: 'short',
          day: 'numeric',
          hour: 'numeric',
          minute: 'numeric'
        };
        break;
      case 'fullDateTime12h':
        options = {
          year: 'numeric',
          month: 'short',
          day: 'numeric',
          hour: 'numeric',
          minute: 'numeric',
          hour12: true
        };
        break;
      case 'fullDateTime24h':
        options = {
          year: 'numeric',
          month: 'short',
          day: 'numeric',
          hour: 'numeric',
          minute: 'numeric',
          hour12: false
        };
        break;
      case 'keyboardDate':
        options = {
          year: 'numeric',
          month: '2-digit',
          day: '2-digit'
        };
        break;
      case 'keyboardDateTime':
        options = {
          year: 'numeric',
          month: '2-digit',
          day: '2-digit',
          hour: 'numeric',
          minute: 'numeric'
        };
        return new Intl.DateTimeFormat(locale, options).format(newDate).replace(/, /g, ' ');
      case 'keyboardDateTime12h':
        options = {
          year: 'numeric',
          month: '2-digit',
          day: '2-digit',
          hour: 'numeric',
          minute: 'numeric',
          hour12: true
        };
        return new Intl.DateTimeFormat(locale, options).format(newDate).replace(/, /g, ' ');
      case 'keyboardDateTime24h':
        options = {
          year: 'numeric',
          month: '2-digit',
          day: '2-digit',
          hour: 'numeric',
          minute: 'numeric',
          hour12: false
        };
        return new Intl.DateTimeFormat(locale, options).format(newDate).replace(/, /g, ' ');
      default:
        options = customFormat ?? {
          timeZone: 'UTC',
          timeZoneName: 'short'
        };
    }
    return new Intl.DateTimeFormat(locale, options).format(newDate);
  }
  function toISO(adapter, value) {
    const date = adapter.toJsDate(value);
    const year = date.getFullYear();
    const month = padStart(String(date.getMonth() + 1), 2, '0');
    const day = padStart(String(date.getDate()), 2, '0');
    return `${year}-${month}-${day}`;
  }
  function parseISO(value) {
    const [year, month, day] = value.split('-').map(Number);
    return new Date(year, month - 1, day);
  }
  function addMinutes(date, amount) {
    const d = new Date(date);
    d.setMinutes(d.getMinutes() + amount);
    return d;
  }
  function addHours(date, amount) {
    const d = new Date(date);
    d.setHours(d.getHours() + amount);
    return d;
  }
  function addDays(date, amount) {
    const d = new Date(date);
    d.setDate(d.getDate() + amount);
    return d;
  }
  function addWeeks(date, amount) {
    const d = new Date(date);
    d.setDate(d.getDate() + amount * 7);
    return d;
  }
  function addMonths(date, amount) {
    const d = new Date(date);
    d.setDate(1);
    d.setMonth(d.getMonth() + amount);
    return d;
  }
  function getYear(date) {
    return date.getFullYear();
  }
  function getMonth(date) {
    return date.getMonth();
  }
  function getWeek(date, locale, firstDayOfWeek, firstDayOfYear) {
    const weekInfoFromLocale = weekInfo(locale);
    const weekStart = firstDayOfWeek ?? weekInfoFromLocale?.firstDay ?? 0;
    const minWeekSize = weekInfoFromLocale?.firstWeekSize ?? 1;
    return firstDayOfYear !== undefined ? calculateWeekWithFirstDayOfYear(date, locale, weekStart, firstDayOfYear) : calculateWeekWithMinWeekSize(date, locale, weekStart, minWeekSize);
  }
  function calculateWeekWithFirstDayOfYear(date, locale, weekStart, firstDayOfYear) {
    const firstDayOfYearOffset = (7 + firstDayOfYear - weekStart) % 7;
    const currentWeekStart = startOfWeek(date, locale, weekStart);
    const currentWeekEnd = addDays(currentWeekStart, 6);
    function yearStartWeekdayOffset(year) {
      return (7 + new Date(year, 0, 1).getDay() - weekStart) % 7;
    }
    let year = getYear(currentWeekStart);
    if (year < getYear(currentWeekEnd) && yearStartWeekdayOffset(year + 1) <= firstDayOfYearOffset) {
      year++;
    }
    const yearStart = new Date(year, 0, 1);
    const offset = yearStartWeekdayOffset(year);
    const d1w1 = offset <= firstDayOfYearOffset ? addDays(yearStart, -offset) : addDays(yearStart, 7 - offset);
    return 1 + getDiff(endOfDay(currentWeekStart), startOfDay(d1w1), 'weeks');
  }
  function calculateWeekWithMinWeekSize(date, locale, weekStart, minWeekSize) {
    const currentWeekStart = startOfWeek(date, locale, weekStart);
    const currentWeekEnd = addDays(startOfWeek(date, locale, weekStart), 6);
    function firstWeekSize(year) {
      const yearStart = new Date(year, 0, 1);
      return 7 - getDiff(yearStart, startOfWeek(yearStart, locale, weekStart), 'days');
    }
    let year = getYear(currentWeekStart);
    if (year < getYear(currentWeekEnd) && firstWeekSize(year + 1) >= minWeekSize) {
      year++;
    }
    const yearStart = new Date(year, 0, 1);
    const size = firstWeekSize(year);
    const d1w1 = size >= minWeekSize ? addDays(yearStart, size - 7) : addDays(yearStart, size);
    return 1 + getDiff(endOfDay(currentWeekStart), startOfDay(d1w1), 'weeks');
  }
  function getDate(date) {
    return date.getDate();
  }
  function getNextMonth(date) {
    return new Date(date.getFullYear(), date.getMonth() + 1, 1);
  }
  function getPreviousMonth(date) {
    return new Date(date.getFullYear(), date.getMonth() - 1, 1);
  }
  function getHours(date) {
    return date.getHours();
  }
  function getMinutes(date) {
    return date.getMinutes();
  }
  function startOfYear(date) {
    return new Date(date.getFullYear(), 0, 1);
  }
  function endOfYear(date) {
    return new Date(date.getFullYear(), 11, 31);
  }
  function isWithinRange(date, range) {
    return isEqual(date, range[0]) || isEqual(date, range[1]) || isAfter(date, range[0]) && isBefore(date, range[1]);
  }
  function isValid(date) {
    const d = new Date(date);
    return d instanceof Date && !isNaN(d.getTime());
  }
  function isAfter(date, comparing) {
    return date.getTime() > comparing.getTime();
  }
  function isAfterDay(date, comparing) {
    return isAfter(startOfDay(date), startOfDay(comparing));
  }
  function isBefore(date, comparing) {
    return date.getTime() < comparing.getTime();
  }
  function isEqual(date, comparing) {
    return date.getTime() === comparing.getTime();
  }
  function isSameDay(date, comparing) {
    return date.getDate() === comparing.getDate() && date.getMonth() === comparing.getMonth() && date.getFullYear() === comparing.getFullYear();
  }
  function isSameMonth(date, comparing) {
    return date.getMonth() === comparing.getMonth() && date.getFullYear() === comparing.getFullYear();
  }
  function isSameYear(date, comparing) {
    return date.getFullYear() === comparing.getFullYear();
  }
  function getDiff(date, comparing, unit) {
    const d = new Date(date);
    const c = new Date(comparing);
    switch (unit) {
      case 'years':
        return d.getFullYear() - c.getFullYear();
      case 'quarters':
        return Math.floor((d.getMonth() - c.getMonth() + (d.getFullYear() - c.getFullYear()) * 12) / 4);
      case 'months':
        return d.getMonth() - c.getMonth() + (d.getFullYear() - c.getFullYear()) * 12;
      case 'weeks':
        return Math.floor((d.getTime() - c.getTime()) / (1000 * 60 * 60 * 24 * 7));
      case 'days':
        return Math.floor((d.getTime() - c.getTime()) / (1000 * 60 * 60 * 24));
      case 'hours':
        return Math.floor((d.getTime() - c.getTime()) / (1000 * 60 * 60));
      case 'minutes':
        return Math.floor((d.getTime() - c.getTime()) / (1000 * 60));
      case 'seconds':
        return Math.floor((d.getTime() - c.getTime()) / 1000);
      default:
        {
          return d.getTime() - c.getTime();
        }
    }
  }
  function setHours(date, count) {
    const d = new Date(date);
    d.setHours(count);
    return d;
  }
  function setMinutes(date, count) {
    const d = new Date(date);
    d.setMinutes(count);
    return d;
  }
  function setMonth(date, count) {
    const d = new Date(date);
    d.setMonth(count);
    return d;
  }
  function setDate(date, day) {
    const d = new Date(date);
    d.setDate(day);
    return d;
  }
  function setYear(date, year) {
    const d = new Date(date);
    d.setFullYear(year);
    return d;
  }
  function startOfDay(date) {
    return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0);
  }
  function endOfDay(date) {
    return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999);
  }
  class VuetifyDateAdapter {
    constructor(options) {
      this.locale = options.locale;
      this.formats = options.formats;
    }
    date(value) {
      return date(value);
    }
    toJsDate(date) {
      return date;
    }
    toISO(date) {
      return toISO(this, date);
    }
    parseISO(date) {
      return parseISO(date);
    }
    addMinutes(date, amount) {
      return addMinutes(date, amount);
    }
    addHours(date, amount) {
      return addHours(date, amount);
    }
    addDays(date, amount) {
      return addDays(date, amount);
    }
    addWeeks(date, amount) {
      return addWeeks(date, amount);
    }
    addMonths(date, amount) {
      return addMonths(date, amount);
    }
    getWeekArray(date, firstDayOfWeek) {
      const firstDay = firstDayOfWeek !== undefined ? Number(firstDayOfWeek) : undefined;
      return getWeekArray(date, this.locale, firstDay);
    }
    startOfWeek(date, firstDayOfWeek) {
      const firstDay = firstDayOfWeek !== undefined ? Number(firstDayOfWeek) : undefined;
      return startOfWeek(date, this.locale, firstDay);
    }
    endOfWeek(date) {
      return endOfWeek(date, this.locale);
    }
    startOfMonth(date) {
      return startOfMonth(date);
    }
    endOfMonth(date) {
      return endOfMonth(date);
    }
    format(date, formatString) {
      return format(date, formatString, this.locale, this.formats);
    }
    isEqual(date, comparing) {
      return isEqual(date, comparing);
    }
    isValid(date) {
      return isValid(date);
    }
    isWithinRange(date, range) {
      return isWithinRange(date, range);
    }
    isAfter(date, comparing) {
      return isAfter(date, comparing);
    }
    isAfterDay(date, comparing) {
      return isAfterDay(date, comparing);
    }
    isBefore(date, comparing) {
      return !isAfter(date, comparing) && !isEqual(date, comparing);
    }
    isSameDay(date, comparing) {
      return isSameDay(date, comparing);
    }
    isSameMonth(date, comparing) {
      return isSameMonth(date, comparing);
    }
    isSameYear(date, comparing) {
      return isSameYear(date, comparing);
    }
    setMinutes(date, count) {
      return setMinutes(date, count);
    }
    setHours(date, count) {
      return setHours(date, count);
    }
    setMonth(date, count) {
      return setMonth(date, count);
    }
    setDate(date, day) {
      return setDate(date, day);
    }
    setYear(date, year) {
      return setYear(date, year);
    }
    getDiff(date, comparing, unit) {
      return getDiff(date, comparing, unit);
    }
    getWeekdays(firstDayOfWeek, weekdayFormat) {
      const firstDay = firstDayOfWeek !== undefined ? Number(firstDayOfWeek) : undefined;
      return getWeekdays(this.locale, firstDay, weekdayFormat);
    }
    getYear(date) {
      return getYear(date);
    }
    getMonth(date) {
      return getMonth(date);
    }
    getWeek(date, firstDayOfWeek, firstDayOfYear) {
      const firstDay = firstDayOfWeek !== undefined ? Number(firstDayOfWeek) : undefined;
      const firstWeekStart = firstDayOfYear !== undefined ? Number(firstDayOfYear) : undefined;
      return getWeek(date, this.locale, firstDay, firstWeekStart);
    }
    getDate(date) {
      return getDate(date);
    }
    getNextMonth(date) {
      return getNextMonth(date);
    }
    getPreviousMonth(date) {
      return getPreviousMonth(date);
    }
    getHours(date) {
      return getHours(date);
    }
    getMinutes(date) {
      return getMinutes(date);
    }
    startOfDay(date) {
      return startOfDay(date);
    }
    endOfDay(date) {
      return endOfDay(date);
    }
    startOfYear(date) {
      return startOfYear(date);
    }
    endOfYear(date) {
      return endOfYear(date);
    }
  }

  // Composables
  const DateOptionsSymbol = Symbol.for('vuetify:date-options');
  const DateAdapterSymbol = Symbol.for('vuetify:date-adapter');
  function createDate(options, locale) {
    const _options = mergeDeep({
      adapter: VuetifyDateAdapter,
      locale: {
        af: 'af-ZA',
        // ar: '', # not the same value for all variants
        bg: 'bg-BG',
        ca: 'ca-ES',
        ckb: '',
        cs: 'cs-CZ',
        de: 'de-DE',
        el: 'el-GR',
        en: 'en-US',
        // es: '', # not the same value for all variants
        et: 'et-EE',
        fa: 'fa-IR',
        fi: 'fi-FI',
        // fr: '', #not the same value for all variants
        hr: 'hr-HR',
        hu: 'hu-HU',
        he: 'he-IL',
        id: 'id-ID',
        it: 'it-IT',
        ja: 'ja-JP',
        ko: 'ko-KR',
        lv: 'lv-LV',
        lt: 'lt-LT',
        nl: 'nl-NL',
        no: 'no-NO',
        pl: 'pl-PL',
        pt: 'pt-PT',
        ro: 'ro-RO',
        ru: 'ru-RU',
        sk: 'sk-SK',
        sl: 'sl-SI',
        srCyrl: 'sr-SP',
        srLatn: 'sr-SP',
        sv: 'sv-SE',
        th: 'th-TH',
        tr: 'tr-TR',
        az: 'az-AZ',
        uk: 'uk-UA',
        vi: 'vi-VN',
        zhHans: 'zh-CN',
        zhHant: 'zh-TW'
      }
    }, options);
    return {
      options: _options,
      instance: createInstance(_options, locale)
    };
  }
  function daysDiff(adapter, start, stop) {
    const iso = [`${adapter.toISO(stop ?? start).split('T')[0]}T00:00:00Z`, `${adapter.toISO(start).split('T')[0]}T00:00:00Z`];
    return typeof adapter.date() === 'string' ? adapter.getDiff(iso[0], iso[1], 'days') // for StringDateAdapter
    : adapter.getDiff(adapter.date(iso[0]), adapter.date(iso[1]), 'days');
  }
  function createInstance(options, locale) {
    const instance = vue.reactive(typeof options.adapter === 'function'
    // eslint-disable-next-line new-cap
    ? new options.adapter({
      locale: options.locale[locale.current.value] ?? locale.current.value,
      formats: options.formats
    }) : options.adapter);
    vue.watch(locale.current, value => {
      instance.locale = options.locale[value] ?? value ?? instance.locale;
    });
    return instance;
  }
  function useDate() {
    const options = vue.inject(DateOptionsSymbol);
    if (!options) throw new Error('[Vuetify] Could not find injected date options');
    const locale = useLocale();
    return createInstance(options, locale);
  }

  // Composables

  // Types

  const makeCalendarBaseProps = propsFactory({
    start: {
      type: [String, Number, Date],
      validate: validateTimestamp,
      default: () => parseDate(new Date()).date
    },
    end: {
      type: [String, Number, Date],
      validate: validateTimestamp
    },
    weekdays: {
      type: [Array, String],
      default: () => [0, 1, 2, 3, 4, 5, 6],
      validate: validateWeekdays
    },
    firstDayOfWeek: [Number, String],
    firstDayOfYear: [Number, String],
    weekdayFormat: {
      type: Function,
      default: null
    },
    dayFormat: {
      type: Function,
      default: null
    },
    format: String,
    locale: String,
    now: {
      type: String,
      validator: validateTimestamp
    },
    type: {
      type: String,
      default: 'month'
    }
  }, 'VCalendar-base');
  function useCalendarBase(props) {
    const {
      times,
      updateTimes
    } = useTimes({
      now: props.now
    });
    const locale = provideLocale(props);
    const adapter = useDate();
    const parsedStart = vue.computed(() => {
      if (props.type === 'month') {
        return getStartOfMonth(parseTimestamp(props.start, true));
      }
      return parseTimestamp(props.start, true);
    });
    const parsedEnd = vue.computed(() => {
      const start = parsedStart.value;
      const end = props.end ? parseTimestamp(props.end) || start : start;
      const value = getTimestampIdentifier(end) < getTimestampIdentifier(start) ? start : end;
      if (props.type === 'month') {
        return getEndOfMonth(value);
      }
      return value;
    });
    const parsedValue = vue.computed(() => {
      return validateTimestamp(props.modelValue) ? parseTimestamp(props.modelValue, true) : parsedStart.value || times.today;
    });
    const parsedWeekdays = vue.computed(() => {
      const weekdays = Array.isArray(props.weekdays) ? props.weekdays : (props.weekdays || '').split(',').map(x => parseInt(x, 10));
      const first = adapter.toJsDate(adapter.startOfWeek(adapter.date(), props.firstDayOfWeek)).getDay();
      return [...weekdays.toSorted().filter(v => v >= first), ...weekdays.toSorted().filter(v => v < first)];
    });
    const effectiveWeekdays = vue.computed(() => {
      const start = parsedValue.value;
      const days = parseInt(String(props.categoryDays)) || 1;
      switch (props.type) {
        case 'day':
          return [start.weekday];
        case '4day':
          return [start.weekday, (start.weekday + 1) % 7, (start.weekday + 2) % 7, (start.weekday + 3) % 7];
        case 'category':
          return Array.from({
            length: days
          }, (_, i) => (start.weekday + i) % 7);
        default:
          return parsedWeekdays.value;
      }
    });
    const weekdaySkips = vue.computed(() => {
      return getWeekdaySkips(parsedWeekdays.value);
    });
    const days = vue.computed(() => {
      return createDayList(parsedStart.value, parsedEnd.value, times.today, weekdaySkips.value);
    });
    const dayFormatter = vue.computed(() => {
      if (props.dayFormat) {
        return props.dayFormat;
      }
      return createNativeLocaleFormatter(locale.current.value, () => ({
        timeZone: 'UTC',
        day: 'numeric'
      }));
    });
    const weekdayFormatter = vue.computed(() => {
      if (props.weekdayFormat) {
        return props.weekdayFormat;
      }
      return createNativeLocaleFormatter(locale.current.value, (_tms, short) => ({
        timeZone: 'UTC',
        weekday: short ? 'short' : 'long'
      }));
    });
    function getColorProps(colors) {
      return computeColor(colors);
    }
    function getRelativeClasses(timestamp, outside = false) {
      return {
        'v-present': timestamp.present,
        'v-past': timestamp.past,
        'v-future': timestamp.future,
        'v-outside': outside
      };
    }
    function getWeekNumber(timestamp) {
      return adapter.getWeek(adapter.date(timestamp.date), props.firstDayOfWeek, props.firstDayOfYear);
    }
    function _getStartOfWeek(timestamp) {
      return getStartOfWeek(timestamp, parsedWeekdays.value, times.today);
    }
    function _getEndOfWeek(timestamp) {
      return getEndOfWeek(timestamp, parsedWeekdays.value, times.today);
    }
    function getFormatter(options) {
      return createNativeLocaleFormatter(locale.current.value, () => options);
    }
    return {
      times,
      locale,
      parsedValue,
      parsedWeekdays,
      effectiveWeekdays,
      weekdaySkips,
      parsedStart,
      parsedEnd,
      days,
      dayFormatter,
      weekdayFormatter,
      getColorProps,
      getRelativeClasses,
      getWeekNumber,
      getStartOfWeek: _getStartOfWeek,
      getEndOfWeek: _getEndOfWeek,
      getFormatter,
      updateTimes
    };
  }

  // Composables

  // Types

  const makeCalendarWithIntervalsProps = propsFactory({
    maxDays: {
      type: Number,
      default: 7
    },
    intervalHeight: {
      type: [Number, String],
      default: 48,
      validate: validateNumber
    },
    intervalWidth: {
      type: [Number, String],
      default: 60,
      validate: validateNumber
    },
    intervalMinutes: {
      type: [Number, String],
      default: 60,
      validate: validateNumber
    },
    firstInterval: {
      type: [Number, String],
      default: 0,
      validate: validateNumber
    },
    firstTime: {
      type: [Number, String, Object],
      validate: validateTime
    },
    intervalCount: {
      type: [Number, String],
      default: 24,
      validate: validateNumber
    },
    intervalFormat: {
      type: Function,
      default: null
    },
    intervalStyle: {
      type: Function,
      default: null
    },
    showIntervalLabel: {
      type: Function,
      default: null
    }
  }, 'VCalendar-intervals');
  function useCalendarWithIntervals(props) {
    const base = useCalendarBase(props);
    const scrollAreaRef = vue.shallowRef();
    const parsedFirstInterval = vue.computed(() => {
      return parseInt(String(props.firstInterval || 0));
    });
    const parsedIntervalMinutes = vue.computed(() => {
      return parseInt(String(props.intervalMinutes || 60));
    });
    const parsedIntervalCount = vue.computed(() => {
      return parseInt(String(props.intervalCount || 24));
    });
    const parsedIntervalHeight = vue.computed(() => {
      return parseFloat(String(props.intervalHeight || 48));
    });
    const parsedFirstTime = vue.computed(() => {
      return parseTime(props.firstTime);
    });
    const firstMinute = vue.computed(() => {
      const time = parsedFirstTime.value;
      return time !== false && time >= 0 && time <= MINUTES_IN_DAY ? time : parsedFirstInterval.value * parsedIntervalMinutes.value;
    });
    const effectiveIntervalCount = vue.computed(() => {
      const dayLimit = Math.ceil((MINUTES_IN_DAY - firstMinute.value) / parsedIntervalMinutes.value);
      return clamp(parsedIntervalCount.value, 0, dayLimit);
    });
    const bodyHeight = vue.computed(() => {
      return effectiveIntervalCount.value * parsedIntervalHeight.value;
    });
    const days = vue.computed(() => {
      return createDayList(base.parsedStart.value, base.parsedEnd.value, base.times.today, base.weekdaySkips.value, props.maxDays);
    });
    const intervals = vue.computed(() => {
      const daysValue = days.value;
      const first = firstMinute.value;
      const minutes = parsedIntervalMinutes.value;
      const count = effectiveIntervalCount.value;
      const now = base.times.now;
      return daysValue.map(d => createIntervalList(d, first, minutes, count, now));
    });
    const intervalFormatter = vue.computed(() => {
      if (props.intervalFormat) {
        return props.intervalFormat;
      }
      const hour12 = props.format === 'ampm' ? true : props.format === '24hr' ? false : undefined;
      const hourStyle = props.format === '24hr' ? '2-digit' : 'numeric';
      return createNativeLocaleFormatter(base.locale.current.value, (tms, short) => !short ? {
        timeZone: 'UTC',
        hour: '2-digit',
        minute: '2-digit',
        hour12
      } : tms.minute === 0 ? {
        timeZone: 'UTC',
        hour: hourStyle,
        hour12
      } : {
        timeZone: 'UTC',
        hour: hourStyle,
        minute: '2-digit',
        hour12
      });
    });
    function showIntervalLabelDefault(interval) {
      const first = intervals.value[0][0];
      const isFirst = first.hour === interval.hour && first.minute === interval.minute;
      return !isFirst;
    }
    function intervalStyleDefault(_interval) {
      return undefined;
    }
    function getIntervalAtEvent(e) {
      const bounds = new Box(e.currentTarget);
      const touchEvent = e;
      const mouseEvent = e;
      const touches = touchEvent.changedTouches || touchEvent.touches;
      const target = touches && touches[0] ? touches[0] : mouseEvent;
      const point = getTargetBox([target.clientX, target.clientY]);
      return (point.y - bounds.top) / parsedIntervalHeight.value;
    }
    function getTimestampAtEvent(e, day) {
      const timestamp = copyTimestamp(day);
      const addMinutes = Math.floor(getIntervalAtEvent(e) * parsedIntervalMinutes.value);
      const minutes = firstMinute.value + addMinutes;
      return updateMinutes(timestamp, minutes, base.times.now);
    }
    function getSlotScope(timestamp) {
      const scope = copyTimestamp(timestamp);
      scope.timeToY = timeToY;
      scope.timeDelta = timeDelta;
      scope.minutesToPixels = minutesToPixels;
      scope.week = days.value;
      scope.intervalRange = [firstMinute.value, firstMinute.value + effectiveIntervalCount.value * parsedIntervalMinutes.value];
      return scope;
    }
    function scrollToTime(time) {
      const y = timeToY(time);
      const pane = scrollAreaRef.value;
      if (y === false || !pane) {
        return false;
      }
      pane.scrollTop = y;
      return true;
    }
    function minutesToPixels(minutes) {
      return minutes / parsedIntervalMinutes.value * parsedIntervalHeight.value;
    }
    function timeToY(time, targetDateOrClamp = false) {
      const clamp = targetDateOrClamp !== false;
      const targetDate = typeof targetDateOrClamp !== 'boolean' ? targetDateOrClamp : undefined;
      let y = timeDelta(time, targetDate);
      if (y === false) return y;
      y *= bodyHeight.value;
      if (clamp) {
        if (y < 0) {
          y = 0;
        } else if (y > bodyHeight.value) {
          y = bodyHeight.value;
        }
      } else {
        if (y < 0) {
          y = y + bodyHeight.value;
        } else if (y > bodyHeight.value) {
          y = y - bodyHeight.value;
        }
      }
      return y;
    }
    function timeDelta(time, targetDate) {
      let minutes = parseTime(time);
      if (minutes === false) {
        return false;
      }
      const gap = effectiveIntervalCount.value * parsedIntervalMinutes.value;
      if (targetDate && typeof time === 'object' && 'day' in time) {
        const a = getDayIdentifier(time);
        const b = getDayIdentifier(targetDate);
        minutes += (a - b) * gap;
      }
      const min = firstMinute.value;
      return (minutes - min) / gap;
    }
    return {
      ...base,
      scrollAreaRef,
      parsedFirstInterval,
      parsedIntervalMinutes,
      parsedIntervalCount,
      parsedIntervalHeight,
      parsedFirstTime,
      firstMinute,
      bodyHeight,
      days,
      intervals,
      intervalFormatter,
      showIntervalLabelDefault,
      intervalStyleDefault,
      getIntervalAtEvent,
      getTimestampAtEvent,
      getSlotScope,
      scrollToTime,
      minutesToPixels,
      timeToY,
      timeDelta
    };
  }

  // Types

  const makeIntervalHighlightProps = propsFactory({
    intervalHighlight: {
      type: [Boolean, String],
      default: false
    }
  }, 'interval-highlight');
  function useIntervalHighlight(props, base) {
    const hoveredTime = vue.shallowRef(null);

    // The underlay paints `background: currentColor`, so we only need a text color.
    const {
      textColorClasses,
      textColorStyles
    } = useTextColor(() => typeof props.intervalHighlight === 'string' && props.intervalHighlight ? props.intervalHighlight : 'surface-variant');

    // Day columns can overlay the intervals, so snap the cursor to an interval row.
    function getHoveredTimeFromEvent(e) {
      const index = Math.floor(base.getIntervalAtEvent(e));
      const intervals = base.intervals.value[0];
      if (!intervals || index < 0 || index >= intervals.length) return null;
      return intervals[index].time;
    }
    function onMousemove(e) {
      if (!props.intervalHighlight) return;
      hoveredTime.value = getHoveredTimeFromEvent(e);
    }
    function onMouseleave() {
      if (!props.intervalHighlight) return;
      hoveredTime.value = null;
    }
    function isHighlighted(interval) {
      return !!props.intervalHighlight && hoveredTime.value === interval.time;
    }
    function genUnderlay() {
      if (!props.intervalHighlight) return undefined;
      return vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-calendar-daily__day-interval__underlay', textColorClasses.value]),
        "style": vue.normalizeStyle(textColorStyles.value)
      }, null);
    }
    return {
      hoveredTime,
      onMousemove,
      onMouseleave,
      isHighlighted,
      genUnderlay
    };
  }

  // Types

  function mounted$3(el, binding) {
    const handler = binding.value;
    const options = {
      passive: !binding.modifiers?.active
    };
    window.addEventListener('resize', handler, options);
    el._onResize = Object(el._onResize);
    el._onResize[binding.instance.$.uid] = {
      handler,
      options
    };
    if (!binding.modifiers?.quiet) {
      handler();
    }
  }
  function unmounted$3(el, binding) {
    if (!el._onResize?.[binding.instance.$.uid]) return;
    const {
      handler,
      options
    } = el._onResize[binding.instance.$.uid];
    window.removeEventListener('resize', handler, options);
    delete el._onResize[binding.instance.$.uid];
  }
  const Resize = {
    mounted: mounted$3,
    unmounted: unmounted$3
  };

  // Types

  const VCalendarDaily = defineComponent({
    name: 'VCalendarDaily',
    directives: {
      vResize: Resize
    },
    props: {
      color: String,
      shortWeekdays: {
        type: Boolean,
        default: true
      },
      shortIntervals: {
        type: Boolean,
        default: true
      },
      hideHeader: Boolean,
      ...makeIntervalHighlightProps(),
      ...makeCalendarBaseProps(),
      ...makeCalendarWithIntervalsProps()
    },
    setup(props, {
      slots,
      attrs
    }) {
      const scrollPush = vue.ref(0);
      const pane = vue.ref();
      const base = useCalendarWithIntervals(props);
      const highlight = useIntervalHighlight(props, base);
      function init() {
        vue.nextTick(onResize);
      }
      function onResize() {
        scrollPush.value = getScrollPush();
      }
      function getScrollPush() {
        return base.scrollAreaRef.value && pane.value ? base.scrollAreaRef.value.offsetWidth - pane.value.offsetWidth : 0;
      }
      function genHead() {
        return vue.createElementVNode("div", {
          "class": "v-calendar-daily__head",
          "style": {
            marginRight: scrollPush.value + 'px'
          }
        }, [genHeadIntervals(), genHeadDays()]);
      }
      function genHeadIntervals() {
        const width = convertToUnit(props.intervalWidth);
        return vue.createElementVNode("div", {
          "class": "v-calendar-daily__intervals-head",
          "style": {
            width
          }
        }, [slots['interval-header']?.()]);
      }
      function genHeadDays() {
        return base.days.value.map(genHeadDay);
      }
      function genHeadDay(day, index) {
        const events = getPrefixedEventHandlers(attrs, ':day', nativeEvent => ({
          nativeEvent,
          ...base.getSlotScope(day)
        }));
        return vue.createElementVNode("div", vue.mergeProps({
          "key": day.date,
          "class": ['v-calendar-daily_head-day', base.getRelativeClasses(day)]
        }, events), [genHeadWeekday(day), genHeadDayLabel(day), genDayHeader(day, index)]);
      }
      function genDayHeader(day, index) {
        return slots['day-header']?.({
          week: base.days.value,
          ...day,
          index
        }) ?? [];
      }
      function genHeadWeekday(day) {
        const color = day.present ? props.color : undefined;
        return vue.createElementVNode("div", vue.mergeProps(base.getColorProps({
          text: color
        }), {
          "class": "v-calendar-daily_head-weekday"
        }), [base.weekdayFormatter.value(day, props.shortWeekdays)]);
      }
      function genHeadDayLabel(day) {
        return vue.createElementVNode("div", {
          "class": "v-calendar-daily_head-day-label"
        }, [slots['day-label-header']?.(day) ?? genHeadDayButton(day)]);
      }
      function genHeadDayButton(day) {
        const events = getPrefixedEventHandlers(attrs, ':date', nativeEvent => ({
          nativeEvent,
          ...day
        }));
        return vue.createVNode(VIconBtn, vue.mergeProps({
          "active": day.present,
          "activeColor": props.color,
          "variant": "outlined",
          "baseVariant": "text",
          "onUpdate:active": noop
        }, events), {
          default: () => [base.dayFormatter.value(day, false)]
        });
      }
      function genBody() {
        return vue.createElementVNode("div", {
          "class": "v-calendar-daily__body"
        }, [genScrollArea()]);
      }
      function genScrollArea() {
        return vue.createElementVNode("div", {
          "ref": base.scrollAreaRef,
          "class": "v-calendar-daily__scroll-area"
        }, [genPane()]);
      }
      function genPane() {
        return vue.createElementVNode("div", {
          "ref": pane,
          "class": "v-calendar-daily__pane",
          "style": {
            height: convertToUnit(base.bodyHeight.value)
          }
        }, [genDayContainer()]);
      }
      function genDayContainer() {
        return vue.createElementVNode("div", {
          "class": "v-calendar-daily__day-container"
        }, [genBodyIntervals(), slots.days?.() ?? genDays()]);
      }
      function genDays() {
        return base.days.value.map((day, index) => {
          const events = getPrefixedEventHandlers(attrs, ':time', nativeEvent => ({
            nativeEvent,
            ...base.getSlotScope(base.getTimestampAtEvent(nativeEvent, day))
          }));
          return vue.createElementVNode("div", vue.mergeProps({
            "key": day.date,
            "class": ['v-calendar-daily__day', base.getRelativeClasses(day)]
          }, events, {
            "onMousemove": highlight.onMousemove,
            "onMouseleave": highlight.onMouseleave
          }), [genDayIntervals(index), genDayBody(day)]);
        });
      }
      function genDayBody(day) {
        return slots['day-body']?.(base.getSlotScope(day)) ?? [];
      }
      function genDayIntervals(index) {
        return base.intervals.value[index].map(genDayInterval);
      }
      function genDayInterval(interval) {
        const height = convertToUnit(props.intervalHeight);
        const styler = props.intervalStyle || base.intervalStyleDefault;
        return vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-calendar-daily__day-interval', {
            'v-calendar-daily__day-interval--hover': highlight.isHighlighted(interval)
          }]),
          "key": interval.time,
          "style": vue.normalizeStyle([{
            height
          }, styler(interval)])
        }, [highlight.genUnderlay(), slots.interval?.(base.getSlotScope(interval))]);
      }
      function genBodyIntervals() {
        const width = convertToUnit(props.intervalWidth);
        const events = getPrefixedEventHandlers(attrs, ':interval', nativeEvent => ({
          nativeEvent,
          ...base.getTimestampAtEvent(nativeEvent, base.parsedStart.value)
        }));
        return vue.createElementVNode("div", vue.mergeProps({
          "class": "v-calendar-daily__intervals-body",
          "style": {
            width
          }
        }, events), [genIntervalLabels()]);
      }
      function genIntervalLabels() {
        if (!base.intervals.value.length) return null;
        return base.intervals.value[0].map(genIntervalLabel);
      }
      function genIntervalLabel(interval) {
        const height = convertToUnit(props.intervalHeight);
        const short = props.shortIntervals;
        const shower = props.showIntervalLabel || base.showIntervalLabelDefault;
        const show = shower(interval);
        const label = show ? base.intervalFormatter.value(interval, short) : undefined;
        return vue.createElementVNode("div", {
          "key": interval.time,
          "class": "v-calendar-daily__interval",
          "style": {
            height
          }
        }, [vue.createElementVNode("div", {
          "class": "v-calendar-daily__interval-text"
        }, [label])]);
      }
      vue.onMounted(init);
      useRender(() => vue.withDirectives(vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-calendar-daily', attrs.class]),
        "onDragstart": e => e.preventDefault()
      }, [!props.hideHeader ? genHead() : undefined, genBody()]), [[Resize, onResize, void 0, {
        quiet: true
      }]]));
      return {
        ...base,
        scrollPush,
        pane,
        init,
        onResize,
        getScrollPush
      };
    }
  });

  // Types

  function parsedCategoryText(category, categoryText) {
    return typeof categoryText === 'function' ? categoryText(category) : typeof categoryText === 'string' && typeof category === 'object' && category ? category[categoryText] : typeof category === 'string' ? category : '';
  }
  function getParsedCategories(categories, categoryText) {
    if (typeof categories === 'string') return categories.split(/\s*,\s/);
    if (Array.isArray(categories)) {
      return categories.map(category => {
        if (typeof category === 'string') return category;
        const categoryName = typeof category.categoryName === 'string' ? category.categoryName : parsedCategoryText(category, categoryText);
        return {
          ...category,
          categoryName
        };
      });
    }
    return [];
  }

  // Types

  const VCalendarCategory = defineComponent({
    name: 'VCalendarCategory',
    props: {
      categories: {
        type: [Array, String],
        default: ''
      },
      categoryText: [String, Function],
      categoryForInvalid: {
        type: String,
        default: ''
      },
      ...makeIntervalHighlightProps(),
      ...makeCalendarBaseProps(),
      ...makeCalendarWithIntervalsProps()
    },
    setup(props, {
      slots,
      attrs
    }) {
      const base = useCalendarWithIntervals(props);
      const highlight = useIntervalHighlight(props, base);
      const parsedCategories = vue.computed(() => {
        return getParsedCategories(props.categories, props.categoryText);
      });
      function getCategoryScope(scope, category) {
        const cat = typeof category === 'object' && category && category.categoryName === props.categoryForInvalid ? null : category;
        return {
          ...scope,
          category: cat
        };
      }
      function genDayHeader(scope) {
        return vue.createElementVNode("div", {
          "class": "v-calendar-category__columns"
        }, [parsedCategories.value.map(category => {
          return genDayHeaderCategory(scope, getCategoryScope(scope, category));
        })]);
      }
      function genDayHeaderCategory(day, scope) {
        const headerTitle = typeof scope.category === 'object' ? scope.category.categoryName : scope.category;
        const events = getPrefixedEventHandlers(attrs, ':dayCategory', () => {
          return getCategoryScope(base.getSlotScope(day) || day, scope.category);
        });
        return vue.createElementVNode("div", vue.mergeProps({
          "class": "v-calendar-category__column-header"
        }, events), [slots.category?.(scope) ?? genDayHeaderCategoryTitle(headerTitle), slots['day-header']?.(scope)]);
      }
      function genDayHeaderCategoryTitle(categoryName) {
        return vue.createElementVNode("div", {
          "class": "v-calendar-category__category"
        }, [categoryName === null ? props.categoryForInvalid : categoryName]);
      }
      function genDays() {
        const days = [];
        base.days.value.forEach((d, j) => {
          const day = new Array(parsedCategories.value.length || 1);
          day.fill(d);
          days.push(...day.map((v, i) => genDay(v, j, i)));
        });
        return days;
      }
      function genDay(day, index, categoryIndex) {
        const category = parsedCategories.value[categoryIndex];
        const events = getPrefixedEventHandlers(attrs, ':time', e => {
          return base.getSlotScope(base.getTimestampAtEvent(e, day));
        });
        return vue.createElementVNode("div", vue.mergeProps({
          "key": day.date + '-' + categoryIndex,
          "class": ['v-calendar-daily__day', base.getRelativeClasses(day)]
        }, events, {
          "onMousemove": highlight.onMousemove,
          "onMouseleave": highlight.onMouseleave
        }), [genDayIntervals(index, category), genDayBody(day, category)]);
      }
      function genDayIntervals(index, category) {
        return base.intervals.value[index].map(v => genDayInterval(v, category));
      }
      function genDayInterval(interval, category) {
        const height = convertToUnit(props.intervalHeight);
        const styler = props.intervalStyle || base.intervalStyleDefault;
        return vue.createElementVNode("div", {
          "key": interval.time,
          "class": vue.normalizeClass(['v-calendar-daily__day-interval', {
            'v-calendar-daily__day-interval--hover': highlight.isHighlighted(interval)
          }]),
          "style": vue.normalizeStyle([{
            height
          }, styler({
            ...interval,
            category
          })])
        }, [highlight.genUnderlay(), slots.interval?.(getCategoryScope(base.getSlotScope(interval), category))]);
      }
      function genDayBody(day, category) {
        return vue.createElementVNode("div", {
          "class": "v-calendar-category__columns"
        }, [genDayBodyCategory(day, category)]);
      }
      function genDayBodyCategory(day, category) {
        const events = getPrefixedEventHandlers(attrs, ':timeCategory', e => {
          return getCategoryScope(base.getSlotScope(base.getTimestampAtEvent(e, day)), category);
        });
        return vue.createElementVNode("div", vue.mergeProps({
          "class": "v-calendar-category__column"
        }, events), [slots['day-body']?.(getCategoryScope(base.getSlotScope(day), category))]);
      }
      useRender(() => vue.createVNode(VCalendarDaily, vue.mergeProps({
        "class": ['v-calendar-daily', 'v-calendar-category']
      }, props), {
        ...slots,
        days: genDays,
        'day-header': genDayHeader
      }));
      return {
        ...base,
        parsedCategories
      };
    }
  });

  /**
   * Centralized key alias mapping for consistent key normalization across the hotkey system.
   *
   * This maps various user-friendly aliases to canonical key names that match
   * KeyboardEvent.key values (in lowercase) where possible.
   */
  const keyAliasMap = {
    // Modifier aliases (from vue-use, other libraries, and current implementation)
    control: 'ctrl',
    command: 'cmd',
    option: 'alt',
    // Arrow key aliases (common abbreviations)
    up: 'arrowup',
    down: 'arrowdown',
    left: 'arrowleft',
    right: 'arrowright',
    // Other common key aliases
    esc: 'escape',
    spacebar: ' ',
    space: ' ',
    return: 'enter',
    del: 'delete',
    // Symbol aliases (existing from hotkey-parsing.ts)
    plus: '+',
    slash: '/',
    underscore: '_',
    minus: '-',
    hyphen: '-'
  };

  /**
   * Normalizes a key string to its canonical form using the alias map.
   *
   * @param key - The key string to normalize
   * @returns The canonical key name in lowercase
   */
  function normalizeKey(key) {
    const lowerKey = key.toLowerCase();
    return keyAliasMap[lowerKey] || lowerKey;
  }

  // Utilities

  // Types

  class ParseError extends Error {}

  /**
   * Splits a single combination string into individual key parts.
   * Grammar:
   *
   * sequence   = alternate *('-' alternate)
   * alternate  = combo *('/' combo)
   * combo      = key *(('+' | '_') key)
   * key        = /./ *(/[^-/+_ ]/)
   *
   */
  function parseKeyCombination(input) {
    let pos = 0;
    try {
      const result = parseSequence();
      if (!atEnd()) {
        throw new ParseError(`Unexpected character '${peek()}' at position ${pos}`);
      }
      return result;
    } catch (err) {
      if (err instanceof ParseError) {
        consoleWarn(`Invalid hotkey combination: ${err.message}\n  ${input}\n  ${' '.repeat(pos)}^`);
        return '';
      } else {
        throw err;
      }
    }
    function peek(ahead = 0) {
      return pos + ahead < input.length ? input[pos + ahead] : null;
    }
    function consume() {
      if (pos >= input.length) {
        throw new ParseError('Unexpected end of input');
      }
      return input[pos++];
    }
    function atEnd() {
      return pos >= input.length;
    }

    // sequence = alternate *('-' alternate)
    function parseSequence() {
      const parts = [parseAlternate()];
      while (peek() === '-') {
        consume();
        parts.push(parseAlternate());
      }
      if (parts.length === 1) return parts[0];
      return {
        type: 'sequence',
        parts
      };
    }

    // alternate = combo *('/' combo)
    function parseAlternate() {
      const parts = [parseCombo()];
      while (peek() === '/') {
        consume();
        parts.push(parseCombo());
      }
      if (parts.length === 1) return parts[0];
      return {
        type: 'alternate',
        parts
      };
    }

    // combo = key *(('+' | '_') key)
    function parseCombo() {
      const keys = [parseKey()];
      while (includes(['+', '_'], peek())) {
        consume();
        keys.push(parseKey());
      }
      if (keys.length === 1) return keys[0];
      return {
        type: 'combo',
        parts: keys
      };
    }

    // key = /./ *(/[^-/+_ ]/)
    function parseKey() {
      const ch = peek();
      if (ch == null) {
        throw new ParseError('Unexpected end of input');
      }
      const next = peek(1);
      if (isSep(ch) && next != null && !isSep(next)) {
        throw new ParseError(`Unexpected separator '${ch}' at position ${pos}`);
      }
      const first = consume();
      // separator keys are always a single character
      if (isSep(first)) return first;
      const chars = [first];
      while (!atEnd() && !isSep(peek()) && peek() !== ' ') {
        chars.push(consume());
      }
      return normalizeKey(chars.join(''));
    }
  }
  function isSep(char) {
    return includes(['-', '/', '+', '_'], char);
  }

  // Composables

  // Types

  const MODIFIERS = ['ctrl', 'shift', 'alt', 'meta', 'cmd'];
  const modifiersSet = new Set(MODIFIERS);
  function isModifier(key) {
    return modifiersSet.has(key);
  }
  const emptyModifiers = Object.fromEntries(MODIFIERS.map(m => [m, false]));
  function useHotkey(keys, callback, options = {}) {
    if (!IN_BROWSER) return function () {};
    const {
      event = 'keydown',
      inputs = false,
      preventDefault = true,
      sequenceTimeout = 1000
    } = options;
    const isMac = navigator?.userAgent?.includes('Macintosh') ?? false;
    let timeout = 0;
    let keyGroups;
    let isSequence = false;
    let groupIndex = 0;
    function isInputFocused() {
      if (vue.toValue(inputs)) return false;
      const activeElement = getActiveElement();
      return activeElement && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA' || activeElement.isContentEditable || activeElement.contentEditable === 'true');
    }
    function resetSequence() {
      groupIndex = 0;
      clearTimeout(timeout);
    }
    function handler(e) {
      const group = keyGroups[groupIndex];
      if (!group || isInputFocused()) return;
      if (!matchesKeyGroup(e, group, isMac)) {
        if (isSequence) resetSequence();
        return;
      }
      if (vue.toValue(preventDefault)) e.preventDefault();
      if (!isSequence) {
        callback(e);
        return;
      }
      clearTimeout(timeout);
      groupIndex++;
      if (groupIndex === keyGroups.length) {
        callback(e);
        resetSequence();
        return;
      }
      timeout = window.setTimeout(resetSequence, vue.toValue(sequenceTimeout));
    }
    function cleanup() {
      window.removeEventListener(vue.toValue(event), handler);
      clearTimeout(timeout);
    }
    vue.watch(() => vue.toValue(keys), newKeys => {
      cleanup();
      if (newKeys) {
        const parsed = parseKeyCombination(newKeys.toLowerCase());
        if (parsed) {
          const parts = typeof parsed !== 'string' && parsed.type === 'sequence' ? parsed.parts : [parsed];
          isSequence = parts.length > 1;
          keyGroups = parts;
          resetSequence();
          window.addEventListener(vue.toValue(event), handler);
        }
      }
    }, {
      immediate: true
    });

    // Watch for changes in the event type to re-register the listener
    vue.watch(() => vue.toValue(event), (newEvent, oldEvent) => {
      if (oldEvent && keyGroups && keyGroups.length > 0) {
        window.removeEventListener(oldEvent, handler);
        window.addEventListener(newEvent, handler);
      }
    });
    vue.onScopeDispose(cleanup, true);
    return cleanup;
  }
  function matchesKeyGroup(e, group, isMac) {
    if (typeof group !== 'string' && group.type === 'alternate') {
      return group.parts.some(part => matchesKeyGroup(e, part, isMac));
    }
    const {
      modifiers,
      actualKey
    } = parseKeyGroup(group);
    const expectCtrl = modifiers.ctrl || !isMac && (modifiers.cmd || modifiers.meta);
    const expectMeta = isMac && (modifiers.cmd || modifiers.meta);
    return e.ctrlKey === expectCtrl && e.metaKey === expectMeta && e.shiftKey === modifiers.shift && e.altKey === modifiers.alt && e.key.toLowerCase() === actualKey?.toLowerCase();
  }
  function parseKeyGroup(group) {
    const parts = typeof group === 'string' ? [group] : group.parts;
    const modifiers = {
      ...emptyModifiers
    };
    let actualKey;
    for (const part of parts) {
      if (isModifier(part)) {
        modifiers[part] = true;
      } else {
        // TODO: handle multiple keys
        actualKey = part;
      }
    }
    return {
      modifiers,
      actualKey
    };
  }

  // Utilities
  const defaultDelimiters = /[-!$%^&*()_+|~=`{}[\]:";'<>?,./\\ ]/;
  const presets = {
    'credit-card': '#### - #### - #### - ####',
    date: '##/##/####',
    'date-time': '##/##/#### ##:##',
    'iso-date': '####-##-##',
    'iso-date-time': '####-##-## ##:##',
    phone: '(###) ### - ####',
    social: '###-##-####',
    time: '##:##',
    'time-with-seconds': '##:##:##'
  };
  const defaultTokens = {
    '#': {
      pattern: /[0-9]/
    },
    A: {
      pattern: /[A-Z]/i,
      convert: v => v.toUpperCase()
    },
    a: {
      pattern: /[a-z]/i,
      convert: v => v.toLowerCase()
    },
    N: {
      pattern: /[0-9A-Z]/i,
      convert: v => v.toUpperCase()
    },
    n: {
      pattern: /[0-9a-z]/i,
      convert: v => v.toLowerCase()
    },
    X: {
      pattern: defaultDelimiters
    }
  };
  function useMask(props) {
    const mask = vue.computed(() => {
      if (typeof props.mask === 'string') {
        if (props.mask in presets) return presets[props.mask];
        return props.mask;
      }
      return props.mask?.mask ?? '';
    });
    const tokens = vue.computed(() => {
      return {
        ...defaultTokens,
        ...(isObject(props.mask) ? props.mask.tokens : null)
      };
    });
    function isMask(char) {
      return char in tokens.value;
    }
    function maskValidates(mask, char) {
      if (char == null || !isMask(mask)) return false;
      const item = tokens.value[mask];
      if (item.pattern) return item.pattern.test(char);
      return item.test(char);
    }
    function convert(mask, char) {
      const item = tokens.value[mask];
      return item.convert ? item.convert(char) : char;
    }
    function maskText(text) {
      const trimmedText = text?.trim().replace(/\s+/g, ' ');
      if (trimmedText == null) return '';
      if (!mask.value.length || !trimmedText.length) return trimmedText;
      let textIndex = 0;
      let maskIndex = 0;
      let newText = '';
      while (maskIndex < mask.value.length) {
        const mchar = mask.value[maskIndex];
        const tchar = trimmedText[textIndex];

        // Escaped character in mask, the next mask character is inserted
        if (mchar === '\\') {
          newText += mask.value[maskIndex + 1];
          maskIndex += 2;
          continue;
        }
        if (!isMask(mchar)) {
          newText += mchar;
          if (tchar === mchar) {
            textIndex++;
          }
        } else if (maskValidates(mchar, tchar)) {
          newText += convert(mchar, tchar);
          textIndex++;
        } else if (textIndex < trimmedText.length) {
          // No match, try the next input character
          textIndex++;
          continue;
        } else {
          break;
        }
        maskIndex++;
      }
      return newText;
    }
    function unmaskText(text) {
      if (text == null) return null;
      if (!mask.value.length || !text.length) return text;
      let result = '';
      const unmaskMap = getUnmaskMap(text);
      for (let i = 0; i < text.length; i++) {
        if (!unmaskMap[i]) result += text[i];
      }
      return result;
    }
    function isDelimiter(text, index) {
      if (!mask.value.length || !text.length) return false;
      return !!getUnmaskMap(text)[index];
    }
    function getUnmaskMap(text) {
      if (text == null || !mask.value.length || !text.length) return [];
      let textIndex = 0;
      let maskIndex = 0;
      const result = Array.from({
        length: text.length
      }, () => true);
      while (true) {
        const mchar = mask.value[maskIndex];
        const tchar = text[textIndex];
        if (tchar == null) break;
        if (mchar == null) {
          result[textIndex] = false;
          textIndex++;
          continue;
        }

        // Escaped character in mask, skip the next input character
        if (mchar === '\\') {
          if (tchar === mask.value[maskIndex + 1]) {
            textIndex++;
          }
          maskIndex += 2;
          continue;
        }
        if (maskValidates(mchar, tchar)) {
          // masked char
          result[textIndex] = false;
          textIndex++;
          maskIndex++;
          continue;
        } else if (mchar !== tchar) {
          // input doesn't match mask, skip forward until it does
          while (true) {
            const mchar = mask.value[maskIndex++];
            if (mchar == null || maskValidates(mchar, tchar)) break;
          }
          continue;
        }
        textIndex++;
        maskIndex++;
      }
      return result;
    }
    function isValid(text) {
      if (!text) return false;
      return unmaskText(text) === unmaskText(maskText(text));
    }
    function isComplete(text) {
      if (!text) return false;
      const maskedText = maskText(text);
      return maskedText.length === mask.value.length && isValid(text);
    }
    return {
      isDelimiter,
      isValid,
      isComplete,
      mask: maskText,
      unmask: unmaskText
    };
  }

  // Types

  const VCalendarWeekly = defineComponent({
    name: 'VCalendarWeekly',
    props: {
      minWeeks: {
        validate: validateNumber,
        default: 1
      },
      monthFormat: Function,
      showWeek: Boolean,
      color: String,
      shortWeekdays: {
        type: Boolean,
        default: true
      },
      showMonthOnFirst: {
        type: Boolean,
        default: true
      },
      shortMonths: {
        type: Boolean,
        default: true
      },
      hideHeader: Boolean,
      ...makeCalendarBaseProps()
    },
    setup(props, {
      slots,
      attrs
    }) {
      const base = useCalendarBase(props);
      const theme = useTheme();
      const parsedMinWeeks = vue.computed(() => {
        return parseInt(String(props.minWeeks));
      });
      const days = vue.computed(() => {
        const minDays = parsedMinWeeks.value * base.parsedWeekdays.value.length;
        const start = base.getStartOfWeek(base.parsedStart.value);
        const end = base.getEndOfWeek(base.parsedEnd.value);
        return createDayList(start, end, base.times.today, base.weekdaySkips.value, Number.MAX_SAFE_INTEGER, minDays);
      });
      const todayWeek = vue.computed(() => {
        const today = base.times.today;
        const start = base.getStartOfWeek(today);
        const end = base.getEndOfWeek(today);
        return createDayList(start, end, today, base.weekdaySkips.value, base.parsedWeekdays.value.length, base.parsedWeekdays.value.length);
      });
      const monthFormatter = vue.computed(() => {
        if (props.monthFormat) {
          // TODO: what happens when this is a string?
          return props.monthFormat;
        }
        return createNativeLocaleFormatter(base.locale.current.value, (_tms, short) => ({
          timeZone: 'UTC',
          month: short ? 'short' : 'long'
        }));
      });
      function isOutside(day) {
        const dayIdentifier = getDayIdentifier(day);
        return dayIdentifier < getDayIdentifier(base.parsedStart.value) || dayIdentifier > getDayIdentifier(base.parsedEnd.value);
      }
      function genHead() {
        return vue.createElementVNode("div", {
          "class": "v-calendar-weekly__head",
          "role": "row"
        }, [genHeadDays()]);
      }
      function genHeadDays() {
        const header = todayWeek.value.map(genHeadDay);
        if (props.showWeek) {
          header.unshift(vue.createElementVNode("div", {
            "class": "v-calendar-weekly__head-weeknumber"
          }, null));
        }
        return header;
      }
      function genHeadDay(day, index) {
        const outside = isOutside(days.value[index]);
        const color = day.present ? props.color : undefined;
        return vue.createElementVNode("div", vue.mergeProps(base.getColorProps({
          text: color
        }), {
          "key": day.date,
          "class": ['v-calendar-weekly__head-weekday', base.getRelativeClasses(day, outside)],
          "role": "columnheader"
        }), [base.weekdayFormatter.value(day, props.shortWeekdays)]);
      }
      function genWeeks() {
        const daysValue = days.value;
        const weekDays = base.parsedWeekdays.value.length;
        const weeks = [];
        for (let i = 0; i < daysValue.length; i += weekDays) {
          weeks.push(genWeek(daysValue.slice(i, i + weekDays), getWeekNumber(daysValue[i])));
        }
        return weeks;
      }
      function genWeek(week, weekNumber) {
        const weekNodes = week.map((day, index) => genDay(day, index, week));
        if (props.showWeek) {
          weekNodes.unshift(genWeekNumber(weekNumber));
        }
        return vue.createElementVNode("div", {
          "key": week[0].date,
          "class": "v-calendar-weekly__week",
          "role": "row"
        }, [weekNodes]);
      }
      function getWeekNumber(determineDay) {
        return base.getWeekNumber(determineDay);
      }
      function genWeekNumber(weekNumber) {
        return vue.createElementVNode("div", {
          "class": "v-calendar-weekly__weeknumber"
        }, [vue.createElementVNode("small", null, [String(weekNumber)])]);
      }
      function genDay(day, index, week) {
        const outside = isOutside(day);
        const events = getPrefixedEventHandlers(attrs, ':day', nativeEvent => {
          return {
            nativeEvent,
            ...day
          };
        });
        return vue.createElementVNode("div", vue.mergeProps({
          "key": day.date,
          "class": ['v-calendar-weekly__day', base.getRelativeClasses(day, outside)],
          "role": "cell"
        }, events), [genDayLabel(day), slots.day?.({
          outside,
          index,
          week,
          ...day
        })]);
      }
      function genDayLabel(day) {
        return vue.createElementVNode("div", {
          "class": "v-calendar-weekly__day-label"
        }, [slots['day-label']?.(day) ?? genDayLabelButton(day)]);
      }
      function genDayLabelButton(day) {
        const hasMonth = day.day === 1 && props.showMonthOnFirst;
        const events = getPrefixedEventHandlers(attrs, ':date', nativeEvent => ({
          nativeEvent,
          ...day
        }));
        return vue.createVNode(VIconBtn, vue.mergeProps({
          "active": day.present,
          "activeColor": props.color,
          "variant": "outlined",
          "baseVariant": "text",
          "onUpdate:active": noop
        }, events), {
          default: () => [hasMonth ? monthFormatter.value(day, props.shortMonths) + ' ' + base.dayFormatter.value(day, false) : base.dayFormatter.value(day, false)]
        });
      }
      useRender(() => vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-calendar-weekly', theme.themeClasses.value]),
        "onDragstart": e => e.preventDefault()
      }, [!props.hideHeader ? genHead() : undefined, genWeeks()]));
      return {
        ...base,
        days,
        todayWeek,
        monthFormatter,
        isOutside
      };
    }
  });

  // Types

  const MILLIS_IN_DAY = 86400000;
  function getVisuals(events, minStart = 0) {
    const visuals = events.map(event => ({
      event,
      columnCount: 0,
      column: 0,
      left: 0,
      width: 100
    }));
    visuals.sort((a, b) => {
      return Math.max(minStart, a.event.startTimestampIdentifier) - Math.max(minStart, b.event.startTimestampIdentifier) || b.event.endTimestampIdentifier - a.event.endTimestampIdentifier;
    });
    return visuals;
  }
  function hasOverlap(s0, e0, s1, e1, exclude = true) {
    return exclude ? !(s0 >= e1 || e0 <= s1) : !(s0 > e1 || e0 < s1);
  }
  function setColumnCount(groups) {
    groups.forEach(group => {
      group.visuals.forEach(groupVisual => {
        groupVisual.columnCount = groups.length;
      });
    });
  }
  function getRange(event) {
    return [event.startTimestampIdentifier, event.endTimestampIdentifier];
  }
  function getDayRange(event) {
    return [event.startIdentifier, event.endIdentifier];
  }
  function getNormalizedRange(event, dayStart) {
    return [Math.max(dayStart, event.startTimestampIdentifier), Math.min(dayStart + MILLIS_IN_DAY, event.endTimestampIdentifier)];
  }
  function getOpenGroup(groups, start, end, timed) {
    for (let i = 0; i < groups.length; i++) {
      const group = groups[i];
      let intersected = false;
      if (hasOverlap(start, end, group.start, group.end, timed)) {
        for (let k = 0; k < group.visuals.length; k++) {
          const groupVisual = group.visuals[k];
          const [groupStart, groupEnd] = timed ? getRange(groupVisual.event) : getDayRange(groupVisual.event);
          if (hasOverlap(start, end, groupStart, groupEnd, timed)) {
            intersected = true;
            break;
          }
        }
      }
      if (!intersected) {
        return i;
      }
    }
    return -1;
  }
  function getOverlapGroupHandler(firstWeekday) {
    const handler = {
      groups: [],
      min: -1,
      max: -1,
      reset: () => {
        handler.groups = [];
        handler.min = handler.max = -1;
      },
      getVisuals: (day, dayEvents, timed, reset = false) => {
        if (day.weekday === firstWeekday || reset) {
          handler.reset();
        }
        const dayStart = getTimestampIdentifier(day);
        const visuals = getVisuals(dayEvents, dayStart);
        visuals.forEach(visual => {
          const [start, end] = timed ? getRange(visual.event) : getDayRange(visual.event);
          if (handler.groups.length > 0 && !hasOverlap(start, end, handler.min, handler.max, timed)) {
            setColumnCount(handler.groups);
            handler.reset();
          }
          let targetGroup = getOpenGroup(handler.groups, start, end, timed);
          if (targetGroup === -1) {
            targetGroup = handler.groups.length;
            handler.groups.push({
              start,
              end,
              visuals: []
            });
          }
          const target = handler.groups[targetGroup];
          target.visuals.push(visual);
          target.start = Math.min(target.start, start);
          target.end = Math.max(target.end, end);
          visual.column = targetGroup;
          if (handler.min === -1) {
            handler.min = start;
            handler.max = end;
          } else {
            handler.min = Math.min(handler.min, start);
            handler.max = Math.max(handler.max, end);
          }
        });
        setColumnCount(handler.groups);
        if (timed) {
          handler.reset();
        }
        return visuals;
      }
    };
    return handler;
  }

  // Types
  const FULL_WIDTH$1 = 100;
  const column = (events, firstWeekday, overlapThreshold) => {
    const handler = getOverlapGroupHandler(firstWeekday);
    return (day, dayEvents, timed, reset) => {
      const visuals = handler.getVisuals(day, dayEvents, timed, reset);
      if (timed) {
        visuals.forEach(visual => {
          visual.left = visual.column * FULL_WIDTH$1 / visual.columnCount;
          visual.width = FULL_WIDTH$1 / visual.columnCount;
        });
      }
      return visuals;
    };
  };

  // Types
  const FULL_WIDTH = 100;
  const DEFAULT_OFFSET = 5;
  const WIDTH_MULTIPLIER = 1.7;

  /**
   * Variation of column mode where events can be stacked. The priority of this
   * mode is to stack events together taking up the least amount of space while
   * trying to ensure the content of the event is always visible as well as its
   * start and end. A sibling column has intersecting event content and must be
   * placed beside each other. Non-sibling columns are offset by 5% from the
   * previous column. The width is scaled by 1.7 so the events overlap and
   * whitespace is reduced. If there is a hole in columns the event width is
   * scaled up so it intersects with the next column. The columns have equal
   * width in the space they are given. If the event doesn't have any to the
   * right of it that intersect with its content, its right side is extended
   * to the right side.
   */

  const stack = (events, firstWeekday, overlapThreshold) => {
    const handler = getOverlapGroupHandler(firstWeekday);

    // eslint-disable-next-line max-statements
    return (day, dayEvents, timed, reset) => {
      if (!timed) {
        return handler.getVisuals(day, dayEvents, timed, reset);
      }
      const dayStart = getTimestampIdentifier(day);
      const visuals = getVisuals(dayEvents, dayStart);
      const groups = getGroups(visuals, dayStart);
      for (const group of groups) {
        const nodes = [];
        for (const visual of group.visuals) {
          const child = getNode(visual, dayStart);
          const index = getNextIndex(child, nodes);
          if (index === false) {
            const parent = getParent(child, nodes);
            if (parent) {
              child.parent = parent;
              child.sibling = hasOverlap(child.start, child.end, parent.start, addTime(parent.start, overlapThreshold));
              child.index = parent.index + 1;
              parent.children.push(child);
            }
          } else {
            const [parent] = getOverlappingRange(child, nodes, index - 1, index - 1);
            const children = getOverlappingRange(child, nodes, index + 1, index + nodes.length, true);
            child.children = children;
            child.index = index;
            if (parent) {
              child.parent = parent;
              child.sibling = hasOverlap(child.start, child.end, parent.start, addTime(parent.start, overlapThreshold));
              parent.children.push(child);
            }
            for (const grand of children) {
              if (grand.parent === parent) {
                grand.parent = child;
              }
              const grandNext = grand.index - child.index <= 1;
              if (grandNext && child.sibling && hasOverlap(child.start, addTime(child.start, overlapThreshold), grand.start, grand.end)) {
                grand.sibling = true;
              }
            }
          }
          nodes.push(child);
        }
        calculateBounds(nodes, overlapThreshold);
      }
      visuals.sort((a, b) => a.left - b.left || a.event.startTimestampIdentifier - b.event.startTimestampIdentifier);
      return visuals;
    };
  };
  function calculateBounds(nodes, overlapThreshold) {
    for (const node of nodes) {
      const {
        visual,
        parent
      } = node;
      const columns = getMaxChildIndex(node) + 1;
      const spaceLeft = parent ? parent.visual.left : 0;
      const spaceWidth = FULL_WIDTH - spaceLeft;
      const offset = Math.min(DEFAULT_OFFSET, FULL_WIDTH / columns);
      const columnWidthMultiplier = getColumnWidthMultiplier(node, nodes);
      const columnOffset = spaceWidth / (columns - node.index + 1);
      const columnWidth = spaceWidth / (columns - node.index + (node.sibling ? 1 : 0)) * columnWidthMultiplier;
      if (parent) {
        visual.left = node.sibling ? spaceLeft + columnOffset : spaceLeft + offset;
      }
      visual.width = hasFullWidth(node, nodes, overlapThreshold) ? FULL_WIDTH - visual.left : Math.min(FULL_WIDTH - visual.left, columnWidth * WIDTH_MULTIPLIER);
    }
  }
  function getColumnWidthMultiplier(node, nodes) {
    if (!node.children.length) {
      return 1;
    }
    const maxColumn = node.index + nodes.length;
    const minColumn = node.children.reduce((min, c) => Math.min(min, c.index), maxColumn);
    return minColumn - node.index;
  }
  function getOverlappingIndices(node, nodes) {
    const indices = [];
    for (const other of nodes) {
      if (hasOverlap(node.start, node.end, other.start, other.end)) {
        indices.push(other.index);
      }
    }
    return indices;
  }
  function getNextIndex(node, nodes) {
    const indices = getOverlappingIndices(node, nodes);
    indices.sort();
    for (let i = 0; i < indices.length; i++) {
      if (i < indices[i]) {
        return i;
      }
    }
    return false;
  }
  function getOverlappingRange(node, nodes, indexMin, indexMax, returnFirstColumn = false) {
    const overlapping = [];
    for (const other of nodes) {
      if (other.index >= indexMin && other.index <= indexMax && hasOverlap(node.start, node.end, other.start, other.end)) {
        overlapping.push(other);
      }
    }
    if (returnFirstColumn && overlapping.length > 0) {
      const first = overlapping.reduce((min, n) => Math.min(min, n.index), overlapping[0].index);
      return overlapping.filter(n => n.index === first);
    }
    return overlapping;
  }
  function getParent(node, nodes) {
    let parent = null;
    for (const other of nodes) {
      if (hasOverlap(node.start, node.end, other.start, other.end) && (parent === null || other.index > parent.index)) {
        parent = other;
      }
    }
    return parent;
  }
  function hasFullWidth(node, nodes, overlapThreshold) {
    for (const other of nodes) {
      if (other !== node && other.index > node.index && hasOverlap(node.start, addTime(node.start, overlapThreshold), other.start, other.end)) {
        return false;
      }
    }
    return true;
  }
  function getGroups(visuals, dayStart) {
    const groups = [];
    for (const visual of visuals) {
      const [start, end] = getNormalizedRange(visual.event, dayStart);
      let added = false;
      for (const group of groups) {
        if (hasOverlap(start, end, group.start, group.end)) {
          group.visuals.push(visual);
          group.end = Math.max(group.end, end);
          added = true;
          break;
        }
      }
      if (!added) {
        groups.push({
          start,
          end,
          visuals: [visual]
        });
      }
    }
    return groups;
  }
  function getNode(visual, dayStart) {
    const [start, end] = getNormalizedRange(visual.event, dayStart);
    return {
      parent: null,
      sibling: true,
      index: 0,
      visual,
      start,
      end,
      children: []
    };
  }
  function getMaxChildIndex(node) {
    let max = node.index;
    for (const child of node.children) {
      const childMax = getMaxChildIndex(child);
      if (childMax > max) {
        max = childMax;
      }
    }
    return max;
  }
  function addTime(identifier, minutes) {
    const removeMinutes = identifier % 100;
    const totalMinutes = removeMinutes + minutes;
    const addHours = Math.floor(totalMinutes / 60);
    const addMinutes = totalMinutes % 60;
    return identifier - removeMinutes + addHours * 100 + addMinutes;
  }

  // Types
  const CalendarEventOverlapModes = {
    stack,
    column
  };

  // Types

  function parseEvent(input, index, startProperty, endProperty, timed = false, category = false) {
    const startInput = input[startProperty];
    const endInput = input[endProperty];
    const startParsed = parseTimestamp(startInput, true);
    const endParsed = endInput ? parseTimestamp(endInput, true) : startParsed;
    const start = isTimedless(startInput) ? updateHasTime(startParsed, timed) : startParsed;
    const end = isTimedless(endInput) ? updateHasTime(endParsed, timed) : endParsed;
    const startIdentifier = getDayIdentifier(start);
    const startTimestampIdentifier = getTimestampIdentifier(start);
    const endIdentifier = getDayIdentifier(end);
    const endOffset = start.hasTime ? 0 : 2359;
    const endTimestampIdentifier = getTimestampIdentifier(end) + endOffset;
    const allDay = !start.hasTime;
    return {
      input,
      start,
      startIdentifier,
      startTimestampIdentifier,
      end,
      endIdentifier,
      endTimestampIdentifier,
      allDay,
      index,
      category
    };
  }
  function isEventOn(event, dayIdentifier) {
    return dayIdentifier >= event.startIdentifier && dayIdentifier <= event.endIdentifier;
  }
  function isEventOnDay(event, day, inRange) {
    if (inRange) {
      const dayStart = nextMinutes(copyTimestamp(day), inRange[0]);
      const dayEnd = nextMinutes(copyTimestamp(day), inRange[1]);
      const starts = event.startTimestampIdentifier < getTimestampIdentifier(dayEnd);
      const ends = event.endTimestampIdentifier > getTimestampIdentifier(dayStart);
      return starts && ends;
    }
    return isEventOn(event, getDayIdentifier(day));
  }
  function isEventHiddenOn(event, day) {
    return event.end.time === '00:00' && event.end.date === day.date && event.start.date !== day.date;
  }
  function isEventStart(event, day, dayIdentifier, firstWeekday) {
    return dayIdentifier === event.startIdentifier || firstWeekday === day.weekday && isEventOn(event, dayIdentifier);
  }
  function isEventOverlapping(event, startIdentifier, endIdentifier) {
    return startIdentifier <= event.endIdentifier && endIdentifier >= event.startIdentifier;
  }

  // Types

  // Constants
  const WIDTH_FULL = 100;
  const WIDTH_START = 95;
  const makeCalendarWithEventsProps = propsFactory({
    events: {
      type: Array,
      default: () => []
    },
    eventStart: {
      type: String,
      default: 'start'
    },
    eventEnd: {
      type: String,
      default: 'end'
    },
    eventTimed: {
      type: [String, Function],
      default: 'timed'
    },
    eventCategory: {
      type: [String, Function],
      default: 'category'
    },
    eventHeight: {
      type: Number,
      default: 20
    },
    eventColor: {
      type: [String, Function],
      default: 'primary'
    },
    eventTextColor: {
      type: [String, Function]
    },
    eventName: {
      type: [String, Function],
      default: 'name'
    },
    eventOverlapThreshold: {
      type: [String, Number],
      default: 60
    },
    eventOverlapMode: {
      type: [String, Function],
      default: 'stack',
      validate: mode => mode in CalendarEventOverlapModes || typeof mode === 'function'
    },
    eventMore: {
      type: Boolean,
      default: true
    },
    eventMoreText: {
      type: String,
      default: '$vuetify.calendar.moreEvents'
    },
    eventRipple: {
      type: [Boolean, Object],
      default: null
    },
    eventMarginBottom: {
      type: Number,
      default: 1
    }
  }, 'VCalendar-events');
  function useCalendarWithEvents(props, slots, attrs) {
    const base = useCalendarBase(props);
    const noEvents = vue.computed(() => {
      return !Array.isArray(props.events) || props.events.length === 0;
    });
    const categoryMode = vue.computed(() => {
      return props.type === 'category';
    });
    const eventTimedFunction = vue.computed(() => {
      return typeof props.eventTimed === 'function' ? props.eventTimed : event => !!event[props.eventTimed];
    });
    const eventCategoryFunction = vue.computed(() => {
      return typeof props.eventCategory === 'function' ? props.eventCategory : event => event[props.eventCategory];
    });
    const parsedEvents = vue.computed(() => {
      if (!props.events) return [];
      return props.events.map((event, index) => parseEvent(event, index, props.eventStart || '', props.eventEnd || '', eventTimedFunction.value(event), categoryMode.value ? eventCategoryFunction.value(event) : false));
    });
    const parsedEventOverlapThreshold = vue.computed(() => {
      return parseInt(String(props.eventOverlapThreshold || 0));
    });
    const eventTextColorFunction = vue.computed(() => {
      return typeof props.eventTextColor === 'function' ? props.eventTextColor : () => props.eventTextColor;
    });
    const eventNameFunction = vue.computed(() => {
      return typeof props.eventName === 'function' ? props.eventName : (event, timedEvent) => event.input[props.eventName] || '';
    });
    const eventModeFunction = vue.computed(() => {
      return typeof props.eventOverlapMode === 'function' ? props.eventOverlapMode : CalendarEventOverlapModes[props.eventOverlapMode];
    });
    const eventWeekdays = vue.computed(() => {
      return base.effectiveWeekdays.value;
    });
    function eventColorFunction(e) {
      return typeof props.eventColor === 'function' ? props.eventColor(e) : e.color || props.eventColor;
    }
    const eventsRef = vue.ref([]);
    function updateEventVisibility() {
      if (noEvents.value || !props.eventMore) {
        return;
      }
      const eventHeight = props.eventHeight || 0;
      const eventsMap = getEventsMap();
      for (const date in eventsMap) {
        const {
          parent,
          events,
          more
        } = eventsMap[date];
        if (!more) {
          break;
        }
        const parentBounds = parent.getBoundingClientRect();
        const last = events.length - 1;
        const eventsSorted = events.map(event => ({
          event,
          bottom: event.getBoundingClientRect().bottom
        })).sort((a, b) => a.bottom - b.bottom);
        let hidden = 0;
        for (let i = 0; i <= last; i++) {
          const bottom = eventsSorted[i].bottom;
          const hide = i === last ? bottom > parentBounds.bottom : bottom + eventHeight > parentBounds.bottom;
          if (hide) {
            eventsSorted[i].event.style.display = 'none';
            hidden++;
          }
        }

        // TODO: avoid direct DOM manipulation
        if (hidden) {
          more.style.display = '';
          more.innerHTML = base.locale.t(props.eventMoreText, hidden);
        } else {
          more.style.display = 'none';
        }
      }
    }
    function getEventsMap() {
      const eventsMap = {};
      const elements = eventsRef.value;
      if (!elements || !elements.length) {
        return eventsMap;
      }
      elements.forEach(el => {
        const date = el.getAttribute('data-date');
        if (el.parentElement && date) {
          if (!(date in eventsMap)) {
            eventsMap[date] = {
              parent: el.parentElement,
              more: null,
              events: []
            };
          }
          if (el.getAttribute('data-more')) {
            eventsMap[date].more = el;
          } else {
            eventsMap[date].events.push(el);
            el.style.display = '';
          }
        }
      });
      return eventsMap;
    }
    function genDayEvent({
      event
    }, day) {
      const eventHeight = props.eventHeight || 0;
      const eventMarginBottom = props.eventMarginBottom || 0;
      const dayIdentifier = getDayIdentifier(day);
      const week = day.week;
      const start = dayIdentifier === event.startIdentifier;
      let end = dayIdentifier === event.endIdentifier;
      let width = WIDTH_START;
      if (!categoryMode.value) {
        for (let i = day.index + 1; i < week.length; i++) {
          const weekdayIdentifier = getDayIdentifier(week[i]);
          if (event.endIdentifier >= weekdayIdentifier) {
            width += WIDTH_FULL;
            end = end || weekdayIdentifier === event.endIdentifier;
          } else {
            end = true;
            break;
          }
        }
      }
      const scope = {
        eventParsed: event,
        day,
        start,
        end,
        timed: false
      };
      return genEvent(event, scope, false, {
        class: ['v-event', {
          'v-event-start': start,
          'v-event-end': end
        }],
        style: {
          height: `${eventHeight}px`,
          width: `${width}%`,
          marginBottom: `${eventMarginBottom}px`
        },
        'data-date': day.date
      });
    }
    function genTimedEvent({
      event,
      left,
      width
    }, day) {
      const startDelta = day.timeDelta(event.start, day);
      const endDelta = day.timeDelta(event.end, day);
      if (endDelta === false || startDelta === false || endDelta < 0 || startDelta >= 1 || isEventHiddenOn(event, day)) {
        return false;
      }
      const dayIdentifier = getDayIdentifier(day);
      const start = event.startIdentifier >= dayIdentifier;
      const end = event.endIdentifier > dayIdentifier;
      const top = day.timeToY(event.start, day);
      const bottom = day.timeToY(event.end, day);
      const height = Math.max(props.eventHeight || 0, bottom - top);
      const scope = {
        eventParsed: event,
        day,
        start,
        end,
        timed: true
      };
      return genEvent(event, scope, true, {
        class: 'v-event-timed',
        style: {
          top: `${top}px`,
          height: `${height}px`,
          left: `${left}%`,
          width: `${width}%`
        }
      });
    }
    function genEvent(event, scopeInput, timedEvent, data) {
      const slot = slots.event;
      const text = eventTextColorFunction.value(event.input);
      const background = eventColorFunction(event.input);
      const overlapsNoon = event.start.hour < 12 && event.end.hour >= 12;
      const singline = diffMinutes(event.start, event.end) <= parsedEventOverlapThreshold.value;
      const formatTime = (withTime, ampm) => {
        const hour12 = props.format === 'ampm' ? true : props.format === '24hr' ? false : undefined;
        const formatter = base.getFormatter({
          timeZone: 'UTC',
          hour: props.format === '24hr' ? '2-digit' : 'numeric',
          minute: withTime.minute > 0 ? 'numeric' : undefined,
          hour12
        });
        return formatter(withTime, true);
      };
      const timeSummary = () => formatTime(event.start) + ' - ' + formatTime(event.end);
      const eventSummary = () => {
        const name = eventNameFunction.value(event, timedEvent);
        if (event.start.hasTime) {
          if (timedEvent) {
            const time = timeSummary();
            const delimiter = singline ? ', ' : vue.createElementVNode("br", null, null);
            return vue.createElementVNode("span", {
              "class": "v-event-summary"
            }, [vue.createElementVNode("strong", null, [name]), delimiter, time]);
          } else {
            const time = formatTime(event.start);
            return vue.createElementVNode("span", {
              "class": "v-event-summary"
            }, [vue.createElementVNode("strong", null, [time]), vue.createTextVNode(" "), name]);
          }
        }
        return vue.createElementVNode("span", {
          "class": "v-event-summary"
        }, [name]);
      };
      const scope = {
        ...scopeInput,
        event: event.input,
        outside: scopeInput.day.outside,
        singline,
        overlapsNoon,
        formatTime,
        timeSummary,
        eventSummary
      };
      const events = getPrefixedEventHandlers(attrs, ':event', nativeEvent => ({
        ...scope,
        nativeEvent
      }));
      return vue.withDirectives(vue.createElementVNode("div", vue.mergeProps(base.getColorProps({
        text,
        background
      }), events, data, {
        "ref_for": true,
        "ref": eventsRef
      }), [slot?.(scope) ?? genName(eventSummary)]), [[Ripple, props.eventRipple ?? true]]);
    }
    function genName(eventSummary) {
      return vue.createElementVNode("div", {
        "class": "pl-1"
      }, [eventSummary()]);
    }
    function genPlaceholder(day) {
      const height = (props.eventHeight || 0) + (props.eventMarginBottom || 0);
      return vue.createElementVNode("div", {
        "style": {
          height: `${height}px`
        },
        "data-date": day.date,
        "ref_for": true,
        "ref": eventsRef
      }, null);
    }
    function genMore(day) {
      const eventHeight = props.eventHeight || 0;
      const eventMarginBottom = props.eventMarginBottom || 0;
      const events = getPrefixedEventHandlers(attrs, ':more', nativeEvent => ({
        nativeEvent,
        ...day
      }));
      return vue.withDirectives(vue.createElementVNode("div", vue.mergeProps({
        "class": ['v-event-more pl-1', {
          'v-outside': day.outside
        }],
        "data-date": day.date,
        "data-more": "1",
        "style": {
          display: 'none',
          height: `${eventHeight}px`,
          marginBottom: `${eventMarginBottom}px`
        },
        "ref_for": true,
        "ref": eventsRef
      }, events), null), [[Ripple, props.eventRipple ?? true]]);
    }
    function getVisibleEvents() {
      const days = base.days.value;
      const start = getDayIdentifier(days[0]);
      const end = getDayIdentifier(days[days.length - 1]);
      return parsedEvents.value.filter(event => isEventOverlapping(event, start, end));
    }
    function isEventForCategory(event, category) {
      return !categoryMode.value || typeof category === 'object' && category.categoryName && category.categoryName === event.category || typeof event.category === 'string' && category === event.category || typeof event.category !== 'string' && category === null;
    }
    function getEventsForDay(day) {
      const identifier = getDayIdentifier(day);
      const firstWeekday = eventWeekdays.value[0];
      return parsedEvents.value.filter(event => isEventStart(event, day, identifier, firstWeekday));
    }
    function getEventsForDayAll(day) {
      const identifier = getDayIdentifier(day);
      const firstWeekday = eventWeekdays.value[0];
      return parsedEvents.value.filter(event => event.allDay && (categoryMode.value ? isEventOn(event, identifier) : isEventStart(event, day, identifier, firstWeekday)) && isEventForCategory(event, day.category));
    }
    function getEventsForDayTimed(day) {
      return parsedEvents.value.filter(event => !event.allDay && isEventOnDay(event, day, day.intervalRange) && isEventForCategory(event, day.category));
    }
    function getScopedSlots() {
      if (noEvents.value) {
        return {
          ...slots
        };
      }
      const mode = eventModeFunction.value(parsedEvents.value, eventWeekdays.value[0], parsedEventOverlapThreshold.value);
      const isNode = input => !!input;
      const getSlotChildren = (day, getter, mapper, timed) => {
        const events = getter(day);
        const visuals = mode(day, events, timed, categoryMode.value);
        if (timed) {
          return visuals.map(visual => mapper(visual, day)).filter(isNode);
        }
        const children = [];
        visuals.forEach((visual, index) => {
          while (children.length < visual.column) {
            children.push(genPlaceholder(day));
          }
          const mapped = mapper(visual, day);
          if (mapped) {
            children.push(mapped);
          }
        });
        return children;
      };
      return {
        ...slots,
        day: day => {
          let children = getSlotChildren(day, getEventsForDay, genDayEvent, false);
          if (children && children.length > 0 && props.eventMore) {
            children.push(genMore(day));
          }
          if (slots.day) {
            const slot = slots.day(day);
            if (slot) {
              children = children ? children.concat(slot) : slot;
            }
          }
          return children;
        },
        'day-header': day => {
          let children = getSlotChildren(day, getEventsForDayAll, genDayEvent, false);
          if (slots['day-header']) {
            const slot = slots['day-header'](day);
            if (slot) {
              children = children ? children.concat(slot) : slot;
            }
          }
          return children;
        },
        'day-body': day => {
          const events = getSlotChildren(day, getEventsForDayTimed, genTimedEvent, true);
          let children = [vue.createElementVNode("div", {
            "class": "v-event-timed-container"
          }, [events])];
          if (slots['day-body']) {
            const slot = slots['day-body'](day);
            if (slot) {
              children = children.concat(slot);
            }
          }
          return children;
        }
      };
    }
    return {
      ...base,
      noEvents,
      parsedEvents,
      parsedEventOverlapThreshold,
      eventTimedFunction,
      eventCategoryFunction,
      eventTextColorFunction,
      eventNameFunction,
      eventModeFunction,
      eventWeekdays,
      categoryMode,
      eventColorFunction,
      eventsRef,
      updateEventVisibility,
      getEventsMap,
      genDayEvent,
      genTimedEvent,
      genEvent,
      genName,
      genPlaceholder,
      genMore,
      getVisibleEvents,
      isEventForCategory,
      getEventsForDay,
      getEventsForDayAll,
      getEventsForDayTimed,
      getScopedSlots
    };
  }

  // Types

  // Types

  const VCalendar = genericComponent()({
    name: 'VCalendar',
    directives: {
      vResize: Resize
    },
    props: {
      modelValue: {
        type: [String, Number, Date],
        validate: validateTimestamp
      },
      categoryDays: {
        type: [Number, String],
        default: 1,
        validate: x => isFinite(parseInt(x)) && parseInt(x) > 0
      },
      categories: {
        type: [Array, String],
        default: ''
      },
      categoryText: {
        type: [String, Function]
      },
      categoryHideDynamic: {
        type: Boolean
      },
      categoryShowAll: {
        type: Boolean
      },
      categoryForInvalid: {
        type: String,
        default: ''
      },
      ...makeIntervalHighlightProps(),
      ...makeCalendarBaseProps(),
      ...makeCalendarWithEventsProps(),
      ...makeCalendarWithIntervalsProps()
    },
    setup(props, {
      slots,
      attrs,
      emit
    }) {
      const root = vue.ref();
      const base = useCalendarWithEvents(props, slots, attrs);
      const lastStart = vue.ref(null);
      const lastEnd = vue.ref(null);
      const parsedCategoryDays = vue.computed(() => {
        return parseInt(String(props.categoryDays)) || 1;
      });
      const parsedCategories = vue.computed(() => {
        return getParsedCategories(props.categories, props.categoryText);
      });
      const renderProps = vue.computed(() => {
        const around = base.parsedValue.value;
        let component = null;
        let maxDays = props.maxDays;
        let categories = parsedCategories.value;
        let start = around;
        let end = around;
        switch (props.type) {
          case 'month':
            component = VCalendarWeekly;
            start = getStartOfMonth(around);
            end = getEndOfMonth(around);
            break;
          case 'week':
            component = VCalendarDaily;
            start = base.getStartOfWeek(around);
            end = base.getEndOfWeek(around);
            maxDays = 7;
            break;
          case 'day':
            component = VCalendarDaily;
            maxDays = 1;
            break;
          case '4day':
            component = VCalendarDaily;
            end = relativeDays(copyTimestamp(end), nextDay, 3);
            updateFormatted(end);
            maxDays = 4;
            break;
          case 'custom-weekly':
            component = VCalendarWeekly;
            start = base.parsedStart.value || around;
            end = base.parsedEnd.value;
            break;
          case 'custom-daily':
            component = VCalendarDaily;
            start = base.parsedStart.value || around;
            end = base.parsedEnd.value;
            break;
          case 'category':
            const days = parsedCategoryDays.value;
            component = VCalendarCategory;
            end = relativeDays(copyTimestamp(end), nextDay, days);
            updateFormatted(end);
            maxDays = days;
            categories = getCategoryList(categories);
            break;
          default:
            const type = props.type;
            throw new Error(`${type} is not a valid Calendar type`);
        }
        return {
          component,
          start,
          end,
          maxDays,
          categories
        };
      });
      const eventWeekdays = vue.computed(() => {
        return base.effectiveWeekdays.value;
      });
      const categoryMode = vue.computed(() => {
        return props.type === 'category';
      });
      const monthLongFormatter = vue.computed(() => {
        return base.getFormatter({
          timeZone: 'UTC',
          month: 'long'
        });
      });
      const monthShortFormatter = vue.computed(() => {
        return base.getFormatter({
          timeZone: 'UTC',
          month: 'short'
        });
      });
      const title = vue.computed(() => {
        const {
          start,
          end
        } = renderProps.value;
        const spanYears = start.year !== end.year;
        const spanMonths = spanYears || start.month !== end.month;
        if (spanYears) {
          return monthShortFormatter.value(start, true) + ' ' + start.year + ' - ' + monthShortFormatter.value(end, true) + ' ' + end.year;
        }
        if (spanMonths) {
          return monthShortFormatter.value(start, true) + ' - ' + monthShortFormatter.value(end, true) + ' ' + end.year;
        } else {
          return monthLongFormatter.value(start, false) + ' ' + start.year;
        }
      });
      function checkChange() {
        const {
          start,
          end
        } = renderProps.value;
        if (!lastStart.value || !lastEnd.value || start.date !== lastStart.value.date || end.date !== lastEnd.value.date) {
          lastStart.value = start;
          lastEnd.value = end;
          emit('change', {
            start,
            end
          });
        }
      }
      function move(amount = 1) {
        const moved = copyTimestamp(base.parsedValue.value);
        const forward = amount > 0;
        const mover = forward ? nextDay : prevDay;
        const limit = forward ? DAYS_IN_MONTH_MAX : DAY_MIN;
        let times = forward ? amount : -amount;
        while (--times >= 0) {
          switch (props.type) {
            case 'month':
              moved.day = limit;
              mover(moved);
              break;
            case 'week':
              relativeDays(moved, mover, DAYS_IN_WEEK);
              break;
            case 'day':
              relativeDays(moved, mover, 1);
              break;
            case '4day':
              relativeDays(moved, mover, 4);
              break;
            case 'category':
              relativeDays(moved, mover, parsedCategoryDays.value);
              break;
          }
        }
        updateWeekday(moved);
        updateFormatted(moved);
        updateRelative(moved, base.times.now);
        if (props.modelValue instanceof Date) {
          emit('update:modelValue', timestampToDate(moved));
        } else if (typeof props.modelValue === 'number') {
          emit('update:modelValue', timestampToDate(moved).getTime());
        } else {
          emit('update:modelValue', moved.date);
        }
        emit('moved', moved);
      }
      function next(amount = 1) {
        move(amount);
      }
      function prev(amount = 1) {
        move(-amount);
      }
      function getCategoryList(categories) {
        if (!base.noEvents.value) {
          const categoryMap = categories.reduce((map, category, index) => {
            if (typeof category === 'object' && category.categoryName) map[category.categoryName] = {
              index,
              count: 0
            };else if (typeof category === 'string') map[category] = {
              index,
              count: 0
            };
            return map;
          }, {});
          if (!props.categoryHideDynamic || !props.categoryShowAll) {
            let categoryLength = categories.length;
            base.parsedEvents.value.forEach(ev => {
              let category = ev.category;
              if (typeof category !== 'string') {
                category = props.categoryForInvalid;
              }
              if (!category) {
                return;
              }
              if (category in categoryMap) {
                categoryMap[category].count++;
              } else if (!props.categoryHideDynamic) {
                categoryMap[category] = {
                  index: categoryLength++,
                  count: 1
                };
              }
            });
          }
          if (!props.categoryShowAll) {
            for (const category in categoryMap) {
              if (categoryMap[category].count === 0) {
                delete categoryMap[category];
              }
            }
          }
          categories = categories.filter(category => {
            if (typeof category === 'object' && category.categoryName) {
              return categoryMap.hasOwnProperty(category.categoryName);
            } else if (typeof category === 'string') {
              return categoryMap.hasOwnProperty(category);
            }
            return false;
          });
        }
        return categories;
      }
      vue.watch(renderProps, checkChange);
      vue.onMounted(() => {
        base.updateEventVisibility();
        checkChange();
      });
      vue.onUpdated(() => {
        window.requestAnimationFrame(base.updateEventVisibility);
      });
      useRender(() => {
        const {
          start,
          end,
          maxDays,
          component: Component,
          categories
        } = renderProps.value;
        return vue.withDirectives(vue.createVNode(Component, vue.mergeProps({
          "ref": root,
          "class": ['v-calendar', {
            'v-calendar-events': !base.noEvents.value
          }],
          "role": "grid"
        }, Component.filterProps(props), {
          "start": start.date,
          "end": end.date,
          "maxDays": maxDays,
          "weekdays": base.effectiveWeekdays.value,
          "categories": categories,
          "onClick:date": (e, day) => {
            if (attrs['onUpdate:modelValue']) emit('update:modelValue', day.date);
          }
        }), base.getScopedSlots()), [[Resize, base.updateEventVisibility, void 0, {
          quiet: true
        }]]);
      });
      return forwardRefs({
        ...base,
        lastStart,
        lastEnd,
        parsedCategoryDays,
        renderProps,
        eventWeekdays,
        categoryMode,
        title,
        monthLongFormatter,
        monthShortFormatter,
        parsedCategories,
        checkChange,
        move,
        next,
        prev,
        getCategoryList
      }, root);
    }
  });

  const makeVCardActionsProps = propsFactory({
    ...makeComponentProps(),
    ...makeTagProps()
  }, 'VCardActions');
  const VCardActions = genericComponent()({
    name: 'VCardActions',
    props: makeVCardActionsProps(),
    setup(props, {
      slots
    }) {
      provideDefaults({
        VBtn: {
          slim: true,
          variant: 'text'
        }
      });
      useRender(() => vue.createVNode(props.tag, {
        "class": vue.normalizeClass(['v-card-actions', props.class]),
        "style": vue.normalizeStyle(props.style)
      }, slots));
      return {};
    }
  });

  const makeVCardSubtitleProps = propsFactory({
    opacity: [Number, String],
    ...makeComponentProps(),
    ...makeTagProps()
  }, 'VCardSubtitle');
  const VCardSubtitle = genericComponent()({
    name: 'VCardSubtitle',
    props: makeVCardSubtitleProps(),
    setup(props, {
      slots
    }) {
      useRender(() => vue.createVNode(props.tag, {
        "class": vue.normalizeClass(['v-card-subtitle', props.class]),
        "style": vue.normalizeStyle([{
          '--v-card-subtitle-opacity': props.opacity
        }, props.style])
      }, slots));
      return {};
    }
  });

  // Utilities
  const VCardTitle = createSimpleFunctional('v-card-title');

  const makeCardItemProps = propsFactory({
    appendAvatar: String,
    appendIcon: IconValue,
    prependAvatar: String,
    prependIcon: IconValue,
    subtitle: {
      type: [String, Number, Boolean],
      default: undefined
    },
    title: {
      type: [String, Number, Boolean],
      default: undefined
    },
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...makeTagProps()
  }, 'VCardItem');
  const VCardItem = genericComponent()({
    name: 'VCardItem',
    props: makeCardItemProps(),
    setup(props, {
      slots
    }) {
      useRender(() => {
        const hasPrependMedia = !!(props.prependAvatar || props.prependIcon);
        const hasPrepend = !!(hasPrependMedia || slots.prepend);
        const hasAppendMedia = !!(props.appendAvatar || props.appendIcon);
        const hasAppend = !!(hasAppendMedia || slots.append);
        const hasTitle = !!(props.title != null || slots.title);
        const hasSubtitle = !!(props.subtitle != null || slots.subtitle);
        return vue.createVNode(props.tag, {
          "class": vue.normalizeClass(['v-card-item', props.class]),
          "style": vue.normalizeStyle(props.style)
        }, {
          default: () => [hasPrepend && vue.createElementVNode("div", {
            "key": "prepend",
            "class": "v-card-item__prepend"
          }, [!slots.prepend ? vue.createElementVNode(vue.Fragment, null, [props.prependAvatar && vue.createVNode(VAvatar, {
            "key": "prepend-avatar",
            "density": props.density,
            "image": props.prependAvatar
          }, null), props.prependIcon && vue.createVNode(VIcon, {
            "key": "prepend-icon",
            "density": props.density,
            "icon": props.prependIcon
          }, null)]) : vue.createVNode(VDefaultsProvider, {
            "key": "prepend-defaults",
            "disabled": !hasPrependMedia,
            "defaults": {
              VAvatar: {
                density: props.density,
                image: props.prependAvatar
              },
              VIcon: {
                density: props.density,
                icon: props.prependIcon
              }
            }
          }, slots.prepend)]), vue.createElementVNode("div", {
            "class": "v-card-item__content"
          }, [hasTitle && vue.createVNode(VCardTitle, {
            "key": "title"
          }, {
            default: () => [slots.title?.() ?? vue.toDisplayString(props.title)]
          }), hasSubtitle && vue.createVNode(VCardSubtitle, {
            "key": "subtitle"
          }, {
            default: () => [slots.subtitle?.() ?? vue.toDisplayString(props.subtitle)]
          }), slots.default?.()]), hasAppend && vue.createElementVNode("div", {
            "key": "append",
            "class": "v-card-item__append"
          }, [!slots.append ? vue.createElementVNode(vue.Fragment, null, [props.appendIcon && vue.createVNode(VIcon, {
            "key": "append-icon",
            "density": props.density,
            "icon": props.appendIcon
          }, null), props.appendAvatar && vue.createVNode(VAvatar, {
            "key": "append-avatar",
            "density": props.density,
            "image": props.appendAvatar
          }, null)]) : vue.createVNode(VDefaultsProvider, {
            "key": "append-defaults",
            "disabled": !hasAppendMedia,
            "defaults": {
              VAvatar: {
                density: props.density,
                image: props.appendAvatar
              },
              VIcon: {
                density: props.density,
                icon: props.appendIcon
              }
            }
          }, slots.append)])]
        });
      });
      return {};
    }
  });

  const makeVCardTextProps = propsFactory({
    opacity: [Number, String],
    ...makeComponentProps(),
    ...makeTagProps()
  }, 'VCardText');
  const VCardText = genericComponent()({
    name: 'VCardText',
    props: makeVCardTextProps(),
    setup(props, {
      slots
    }) {
      useRender(() => vue.createVNode(props.tag, {
        "class": vue.normalizeClass(['v-card-text', props.class]),
        "style": vue.normalizeStyle([{
          '--v-card-text-opacity': props.opacity
        }, props.style])
      }, slots));
      return {};
    }
  });

  // Types

  const makeVCardProps = propsFactory({
    appendAvatar: String,
    appendIcon: IconValue,
    disabled: Boolean,
    flat: Boolean,
    hover: Boolean,
    image: String,
    link: {
      type: Boolean,
      default: undefined
    },
    prependAvatar: String,
    prependIcon: IconValue,
    ripple: {
      type: [Boolean, Object],
      default: true
    },
    subtitle: {
      type: [String, Number, Boolean],
      default: undefined
    },
    text: {
      type: [String, Number, Boolean],
      default: undefined
    },
    title: {
      type: [String, Number, Boolean],
      default: undefined
    },
    ...makeBorderProps(),
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...makeDimensionProps(),
    ...makeElevationProps(),
    ...makeLoaderProps(),
    ...makeLocationProps(),
    ...makePositionProps(),
    ...makeRoundedProps(),
    ...makeRouterProps(),
    ...makeTagProps(),
    ...makeThemeProps(),
    ...makeVariantProps({
      variant: 'elevated'
    })
  }, 'VCard');
  const VCard = genericComponent()({
    name: 'VCard',
    directives: {
      vRipple: Ripple
    },
    props: makeVCardProps(),
    setup(props, {
      attrs,
      slots
    }) {
      const {
        themeClasses
      } = provideTheme(props);
      const {
        borderClasses
      } = useBorder(props);
      const {
        colorClasses,
        colorStyles,
        variantClasses
      } = useVariant(props);
      const {
        densityClasses
      } = useDensity(props);
      const {
        dimensionStyles
      } = useDimension(props);
      const {
        elevationClasses
      } = useElevation(props);
      const {
        loaderClasses
      } = useLoader(props);
      const {
        locationStyles
      } = useLocation(props);
      const {
        positionClasses
      } = usePosition(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const link = useLink(props, attrs);
      const loadingColor = vue.shallowRef(undefined);
      vue.watch(() => props.loading, (val, old) => {
        loadingColor.value = !val && typeof old === 'string' ? old : typeof val === 'boolean' ? undefined : val;
      }, {
        immediate: true
      });
      useRender(() => {
        const isLink = props.link !== false && link.isLink.value;
        const isClickable = !props.disabled && props.link !== false && (props.link || link.isClickable.value);
        const Tag = isLink ? 'a' : props.tag;
        const hasTitle = !!(slots.title || props.title != null);
        const hasSubtitle = !!(slots.subtitle || props.subtitle != null);
        const hasHeader = hasTitle || hasSubtitle;
        const hasAppend = !!(slots.append || props.appendAvatar || props.appendIcon);
        const hasPrepend = !!(slots.prepend || props.prependAvatar || props.prependIcon);
        const hasImage = !!(slots.image || props.image);
        const hasCardItem = hasHeader || hasPrepend || hasAppend;
        const hasText = !!(slots.text || props.text != null);
        return vue.withDirectives(vue.createVNode(Tag, vue.mergeProps(link.linkProps, {
          "class": ['v-card', {
            'v-card--disabled': props.disabled,
            'v-card--flat': props.flat,
            'v-card--hover': props.hover && !(props.disabled || props.flat),
            'v-card--link': isClickable
          }, themeClasses.value, borderClasses.value, colorClasses.value, densityClasses.value, elevationClasses.value, loaderClasses.value, positionClasses.value, roundedClasses.value, variantClasses.value, props.class],
          "style": [colorStyles.value, dimensionStyles.value, locationStyles.value, {
            '--v-card-height': convertToUnit(props.height)
          }, roundedStyles.value, props.style],
          "onClick": isClickable && link.navigate.value,
          "tabindex": props.disabled ? -1 : undefined
        }), {
          default: () => [hasImage && vue.createElementVNode("div", {
            "key": "image",
            "class": "v-card__image"
          }, [!slots.image ? vue.createVNode(VImg, {
            "key": "image-img",
            "cover": true,
            "src": props.image
          }, null) : vue.createVNode(VDefaultsProvider, {
            "key": "image-defaults",
            "disabled": !props.image,
            "defaults": {
              VImg: {
                cover: true,
                src: props.image
              }
            }
          }, slots.image)]), vue.createVNode(LoaderSlot, {
            "name": "v-card",
            "active": !!props.loading,
            "color": loadingColor.value
          }, {
            default: slots.loader
          }), hasCardItem && vue.createVNode(VCardItem, {
            "key": "item",
            "prependAvatar": props.prependAvatar,
            "prependIcon": props.prependIcon,
            "title": props.title,
            "subtitle": props.subtitle,
            "appendAvatar": props.appendAvatar,
            "appendIcon": props.appendIcon
          }, {
            default: slots.item,
            prepend: slots.prepend,
            title: slots.title,
            subtitle: slots.subtitle,
            append: slots.append
          }), hasText && vue.createVNode(VCardText, {
            "key": "text"
          }, {
            default: () => [slots.text?.() ?? props.text]
          }), slots.default?.(), slots.actions && vue.createVNode(VCardActions, null, {
            default: slots.actions
          }), genOverlays(isClickable, 'v-card')]
        }), [[Ripple, isClickable && props.ripple]]);
      });
      return {};
    }
  });

  // Utilities

  // Types

  const handleGesture = wrapper => {
    const {
      touchstartX,
      touchendX,
      touchstartY,
      touchendY
    } = wrapper;
    const dirRatio = 0.5;
    const minDistance = 16;
    wrapper.offsetX = touchendX - touchstartX;
    wrapper.offsetY = touchendY - touchstartY;
    if (Math.abs(wrapper.offsetY) < dirRatio * Math.abs(wrapper.offsetX)) {
      wrapper.left && touchendX < touchstartX - minDistance && wrapper.left(wrapper);
      wrapper.right && touchendX > touchstartX + minDistance && wrapper.right(wrapper);
    }
    if (Math.abs(wrapper.offsetX) < dirRatio * Math.abs(wrapper.offsetY)) {
      wrapper.up && touchendY < touchstartY - minDistance && wrapper.up(wrapper);
      wrapper.down && touchendY > touchstartY + minDistance && wrapper.down(wrapper);
    }
  };
  function touchstart(event, wrapper) {
    const touch = event.changedTouches[0];
    wrapper.touchstartX = touch.clientX;
    wrapper.touchstartY = touch.clientY;
    wrapper.start?.({
      originalEvent: event,
      ...wrapper
    });
  }
  function touchend(event, wrapper) {
    const touch = event.changedTouches[0];
    wrapper.touchendX = touch.clientX;
    wrapper.touchendY = touch.clientY;
    wrapper.end?.({
      originalEvent: event,
      ...wrapper
    });
    handleGesture(wrapper);
  }
  function touchmove(event, wrapper) {
    const touch = event.changedTouches[0];
    wrapper.touchmoveX = touch.clientX;
    wrapper.touchmoveY = touch.clientY;
    wrapper.move?.({
      originalEvent: event,
      ...wrapper
    });
  }
  function createHandlers(value = {}) {
    const wrapper = {
      touchstartX: 0,
      touchstartY: 0,
      touchendX: 0,
      touchendY: 0,
      touchmoveX: 0,
      touchmoveY: 0,
      offsetX: 0,
      offsetY: 0,
      left: value.left,
      right: value.right,
      up: value.up,
      down: value.down,
      start: value.start,
      move: value.move,
      end: value.end
    };
    return {
      touchstart: e => touchstart(e, wrapper),
      touchend: e => touchend(e, wrapper),
      touchmove: e => touchmove(e, wrapper)
    };
  }
  function mounted$2(el, binding) {
    const value = binding.value;
    const target = value?.parent ? el.parentElement : el;
    const options = value?.options ?? {
      passive: true
    };
    const uid = binding.instance?.$.uid; // TODO: use custom uid generator

    if (!target || uid === undefined) return;
    const handlers = createHandlers(binding.value);
    target._touchHandlers = target._touchHandlers ?? Object.create(null);
    target._touchHandlers[uid] = handlers;
    keys(handlers).forEach(eventName => {
      target.addEventListener(eventName, handlers[eventName], options);
    });
  }
  function unmounted$2(el, binding) {
    const target = binding.value?.parent ? el.parentElement : el;
    const uid = binding.instance?.$.uid;
    if (!target?._touchHandlers || uid === undefined) return;
    const handlers = target._touchHandlers[uid];

    // guard against double teardown: e.g. router & suspence racing
    if (!handlers) return;
    keys(handlers).forEach(eventName => {
      target.removeEventListener(eventName, handlers[eventName]);
    });
    delete target._touchHandlers[uid];
    if (!keys(target._touchHandlers).length) {
      // only relevant if we keep `parent: boolean`
      delete target._touchHandlers;
    }
  }
  const Touch = {
    mounted: mounted$2,
    unmounted: unmounted$2
  };

  // Types

  const VWindowSymbol = Symbol.for('vuetify:v-window');
  const VWindowGroupSymbol = Symbol.for('vuetify:v-window-group');
  const makeVWindowProps = propsFactory({
    continuous: Boolean,
    nextIcon: {
      type: [Boolean, String, Function, Object],
      default: '$next'
    },
    prevIcon: {
      type: [Boolean, String, Function, Object],
      default: '$prev'
    },
    reverse: Boolean,
    showArrows: {
      type: [Boolean, String],
      validator: v => typeof v === 'boolean' || v === 'hover'
    },
    verticalArrows: [Boolean, String],
    touch: {
      type: [Object, Boolean],
      default: undefined
    },
    direction: {
      type: String,
      default: 'horizontal'
    },
    modelValue: null,
    disabled: Boolean,
    selectedClass: {
      type: String,
      default: 'v-window-item--active'
    },
    // TODO: mandatory should probably not be exposed but do this for now
    mandatory: {
      type: [Boolean, String],
      default: 'force'
    },
    crossfade: Boolean,
    transitionDuration: Number,
    ...makeComponentProps(),
    ...makeTagProps(),
    ...makeThemeProps()
  }, 'VWindow');
  const VWindow = genericComponent()({
    name: 'VWindow',
    directives: {
      vTouch: Touch
    },
    props: makeVWindowProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const {
        themeClasses
      } = provideTheme(props);
      const {
        isRtl
      } = useRtl();
      const {
        t
      } = useLocale();
      const group = useGroup(props, VWindowGroupSymbol);
      const rootRef = vue.ref();
      const isRtlReverse = vue.computed(() => isRtl.value ? !props.reverse : props.reverse);
      const isReversed = vue.shallowRef(false);
      const transition = vue.computed(() => {
        if (props.crossfade) {
          return 'v-window-crossfade-transition';
        }
        const axis = props.direction === 'vertical' ? 'y' : 'x';
        const reverse = isRtlReverse.value ? !isReversed.value : isReversed.value;
        const direction = reverse ? '-reverse' : '';
        return `v-window-${axis}${direction}-transition`;
      });
      const transitionCount = vue.shallowRef(0);
      const transitionHeight = vue.ref(undefined);
      const activeIndex = vue.computed(() => {
        return group.items.value.findIndex(item => group.selected.value.includes(item.id));
      });

      // Fix for https://github.com/vuetifyjs/vuetify/issues/18447
      vue.watch(activeIndex, (newVal, oldVal) => {
        let scrollableParent;
        const savedScrollPosition = {
          left: 0,
          top: 0
        };
        if (IN_BROWSER && oldVal >= 0) {
          scrollableParent = getScrollParent(rootRef.value);
          savedScrollPosition.left = scrollableParent?.scrollLeft;
          savedScrollPosition.top = scrollableParent?.scrollTop;
        }
        const itemsLength = group.items.value.length;
        const lastIndex = itemsLength - 1;
        if (itemsLength <= 2) {
          isReversed.value = newVal < oldVal;
        } else if (newVal === lastIndex && oldVal === 0) {
          isReversed.value = false;
        } else if (newVal === 0 && oldVal === lastIndex) {
          isReversed.value = true;
        } else {
          isReversed.value = newVal < oldVal;
        }
        vue.nextTick(() => {
          if (!IN_BROWSER || !scrollableParent) return;
          const currentScrollY = scrollableParent.scrollTop;
          if (currentScrollY !== savedScrollPosition.top) {
            scrollableParent.scrollTo({
              ...savedScrollPosition,
              behavior: 'instant'
            });
          }
          requestAnimationFrame(() => {
            if (!scrollableParent) return;
            const rafScrollY = scrollableParent.scrollTop;
            if (rafScrollY !== savedScrollPosition.top) {
              scrollableParent.scrollTo({
                ...savedScrollPosition,
                behavior: 'instant'
              });
            }
          });
        });
      }, {
        flush: 'sync'
      }); // Run synchronously before DOM updates

      vue.provide(VWindowSymbol, {
        transition,
        isReversed,
        transitionCount,
        transitionHeight,
        rootRef
      });
      const canMoveBack = vue.toRef(() => props.continuous || activeIndex.value !== 0);
      const canMoveForward = vue.toRef(() => props.continuous || activeIndex.value !== group.items.value.length - 1);
      function prev() {
        canMoveBack.value && group.prev();
      }
      function next() {
        canMoveForward.value && group.next();
      }
      const arrows = vue.computed(() => {
        const arrows = [];
        const prevProps = {
          icon: isRtl.value ? props.nextIcon : props.prevIcon,
          class: `v-window__${isRtlReverse.value ? 'right' : 'left'}`,
          onClick: group.prev,
          'aria-label': t('$vuetify.carousel.prev')
        };
        arrows.push(canMoveBack.value ? slots.prev ? slots.prev({
          props: prevProps
        }) : vue.createVNode(VBtn, prevProps, null) : vue.createElementVNode("div", null, null));
        const nextProps = {
          icon: isRtl.value ? props.prevIcon : props.nextIcon,
          class: `v-window__${isRtlReverse.value ? 'left' : 'right'}`,
          onClick: group.next,
          'aria-label': t('$vuetify.carousel.next')
        };
        arrows.push(canMoveForward.value ? slots.next ? slots.next({
          props: nextProps
        }) : vue.createVNode(VBtn, nextProps, null) : vue.createElementVNode("div", null, null));
        return arrows;
      });
      const touchOptions = vue.computed(() => {
        if (props.touch === false) return props.touch;
        const options = {
          left: () => {
            isRtlReverse.value ? prev() : next();
          },
          right: () => {
            isRtlReverse.value ? next() : prev();
          },
          start: ({
            originalEvent
          }) => {
            originalEvent.stopPropagation();
          }
        };
        return {
          ...options,
          ...(props.touch === true ? {} : props.touch)
        };
      });
      function onKeyDown(e) {
        if (props.direction === 'horizontal' && e.key === 'ArrowLeft' || props.direction === 'vertical' && e.key === 'ArrowUp') {
          e.preventDefault();
          prev();
          vue.nextTick(() => {
            canMoveBack.value ? focusArrow(0) : focusArrow(1);
          });
        }
        if (props.direction === 'horizontal' && e.key === 'ArrowRight' || props.direction === 'vertical' && e.key === 'ArrowDown') {
          e.preventDefault();
          next();
          vue.nextTick(() => {
            canMoveForward.value ? focusArrow(1) : focusArrow(0);
          });
        }
      }
      function focusArrow(index) {
        const arrow = arrows.value[index];
        if (!arrow) return;
        const arrowEl = Array.isArray(arrow) ? arrow[0] : arrow;
        arrowEl.el?.focus();
      }
      useRender(() => vue.withDirectives(vue.createVNode(props.tag, {
        "ref": rootRef,
        "class": vue.normalizeClass(['v-window', {
          'v-window--show-arrows-on-hover': props.showArrows === 'hover',
          'v-window--vertical-arrows': !!props.verticalArrows,
          'v-window--crossfade': !!props.crossfade
        }, themeClasses.value, props.class]),
        "style": vue.normalizeStyle([props.style, {
          '--v-window-transition-duration': !PREFERS_REDUCED_MOTION() ? convertToUnit(props.transitionDuration, 'ms') : null
        }])
      }, {
        default: () => [vue.createElementVNode("div", {
          "class": "v-window__container",
          "style": {
            height: transitionHeight.value
          }
        }, [slots.default?.({
          group
        }), props.showArrows !== false && vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-window__controls', {
            'v-window__controls--left': props.verticalArrows === 'left' || props.verticalArrows === true
          }, {
            'v-window__controls--right': props.verticalArrows === 'right'
          }]),
          "onKeydown": onKeyDown
        }, [arrows.value])]), slots.additional?.({
          group
        })]
      }), [[Touch, touchOptions.value]]));
      return {
        group
      };
    }
  });

  // Types

  const makeVCarouselProps = propsFactory({
    color: String,
    cycle: Boolean,
    delimiterIcon: {
      type: IconValue,
      default: '$delimiter'
    },
    height: {
      type: [Number, String],
      default: 500
    },
    hideDelimiters: Boolean,
    hideDelimiterBackground: Boolean,
    interval: {
      type: [Number, String],
      default: 6000,
      validator: value => Number(value) > 0
    },
    progress: [Boolean, String],
    verticalDelimiters: [Boolean, String],
    ...makeVWindowProps({
      continuous: true,
      mandatory: 'force',
      showArrows: true
    })
  }, 'VCarousel');
  const VCarousel = genericComponent()({
    name: 'VCarousel',
    props: makeVCarouselProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const model = useProxiedModel(props, 'modelValue');
      const {
        t
      } = useLocale();
      const windowRef = vue.ref();
      let slideTimeout = -1;
      vue.watch(model, restartTimeout);
      vue.watch(() => props.interval, restartTimeout);
      vue.watch(() => props.cycle, val => {
        if (val) restartTimeout();else window.clearTimeout(slideTimeout);
      });
      vue.onMounted(startTimeout);
      function startTimeout() {
        if (!props.cycle || !windowRef.value) return;
        slideTimeout = window.setTimeout(windowRef.value.group.next, Number(props.interval) > 0 ? Number(props.interval) : 6000);
      }
      function restartTimeout() {
        window.clearTimeout(slideTimeout);
        window.requestAnimationFrame(startTimeout);
      }
      function onDelimiterKeyDown(e, group) {
        if (props.direction === 'horizontal' && e.key === 'ArrowLeft' || props.direction === 'vertical' && e.key === 'ArrowUp') {
          e.preventDefault();
          group.prev();
          vue.nextTick(() => windowRef.value?.$el.querySelector('.v-btn--active')?.focus());
        }
        if (props.direction === 'horizontal' && e.key === 'ArrowRight' || props.direction === 'vertical' && e.key === 'ArrowDown') {
          e.preventDefault();
          group.next();
          vue.nextTick(() => windowRef.value?.$el.querySelector('.v-btn--active')?.focus());
        }
      }
      useRender(() => {
        const windowProps = VWindow.filterProps(props);
        return vue.createVNode(VWindow, vue.mergeProps({
          "ref": windowRef
        }, windowProps, {
          "modelValue": model.value,
          "onUpdate:modelValue": $event => model.value = $event,
          "class": ['v-carousel', {
            'v-carousel--hide-delimiter-background': props.hideDelimiterBackground,
            'v-carousel--vertical-delimiters': props.verticalDelimiters
          }, props.class],
          "style": [{
            height: convertToUnit(props.height)
          }, props.style]
        }), {
          default: slots.default,
          additional: ({
            group
          }) => vue.createElementVNode(vue.Fragment, null, [!props.hideDelimiters && vue.createElementVNode("div", {
            "class": "v-carousel__controls",
            "style": {
              left: props.verticalDelimiters === 'left' && props.verticalDelimiters ? 0 : 'auto',
              right: props.verticalDelimiters === 'right' ? 0 : 'auto'
            }
          }, [group.items.value.length > 0 && vue.createVNode(VDefaultsProvider, {
            "defaults": {
              VBtn: {
                color: props.color,
                icon: props.delimiterIcon,
                size: 'x-small',
                variant: 'text'
              }
            },
            "scoped": true
          }, {
            default: () => [group.items.value.map((item, index) => {
              const props = {
                id: `carousel-item-${item.id}`,
                'aria-label': t('$vuetify.carousel.ariaLabel.delimiter', index + 1, group.items.value.length),
                class: ['v-carousel__controls__item', group.isSelected(item.id) && 'v-btn--active'],
                onClick: () => group.select(item.id, true),
                onKeydown: e => onDelimiterKeyDown(e, group)
              };
              return slots.item ? slots.item({
                props,
                item
              }) : vue.createVNode(VBtn, vue.mergeProps(item, props), null);
            })]
          })]), props.progress && vue.createVNode(VProgressLinear, {
            "absolute": true,
            "class": "v-carousel__progress",
            "color": typeof props.progress === 'string' ? props.progress : undefined,
            "modelValue": (group.getItemIndex(model.value) + 1) / group.items.value.length * 100
          }, null)]),
          prev: slots.prev,
          next: slots.next
        });
      });
      return {};
    }
  });

  const makeVWindowItemProps = propsFactory({
    reverseTransition: {
      type: [Boolean, String],
      default: undefined
    },
    transition: {
      type: [Boolean, String],
      default: undefined
    },
    ...makeComponentProps(),
    ...makeGroupItemProps(),
    ...makeLazyProps()
  }, 'VWindowItem');
  const VWindowItem = genericComponent()({
    name: 'VWindowItem',
    directives: {
      vTouch: Touch
    },
    props: makeVWindowItemProps(),
    emits: {
      'group:selected': val => true
    },
    setup(props, {
      slots
    }) {
      const window = vue.inject(VWindowSymbol);
      const groupItem = useGroupItem(props, VWindowGroupSymbol);
      const {
        isBooted
      } = useSsrBoot();
      if (!window || !groupItem) throw new Error('[Vuetify] VWindowItem must be used inside VWindow');
      const isTransitioning = vue.shallowRef(false);
      const hasTransition = vue.computed(() => isBooted.value && (window.isReversed.value ? props.reverseTransition !== false : props.transition !== false));
      function onAfterTransition() {
        if (!isTransitioning.value || !window) {
          return;
        }

        // Finalize transition state.
        isTransitioning.value = false;
        if (window.transitionCount.value > 0) {
          window.transitionCount.value -= 1;

          // Remove container height if we are out of transition.
          if (window.transitionCount.value === 0) {
            window.transitionHeight.value = undefined;
          }
        }
      }
      function onBeforeTransition() {
        if (isTransitioning.value || !window) {
          return;
        }

        // Initialize transition state here.
        isTransitioning.value = true;
        if (window.transitionCount.value === 0) {
          // Set initial height for height transition.
          window.transitionHeight.value = convertToUnit(window.rootRef.value?.clientHeight);
        }
        window.transitionCount.value += 1;
      }
      function onTransitionCancelled() {
        onAfterTransition(); // This should have the same path as normal transition end.
      }
      function onEnterTransition(el) {
        if (!isTransitioning.value) {
          return;
        }
        vue.nextTick(() => {
          // Do not set height if no transition or cancelled.
          if (!hasTransition.value || !isTransitioning.value || !window) {
            return;
          }

          // Set transition target height.
          window.transitionHeight.value = convertToUnit(el.clientHeight);
        });
      }
      const transition = vue.computed(() => {
        const name = window.isReversed.value ? props.reverseTransition : props.transition;
        return !hasTransition.value ? false : {
          name: typeof name !== 'string' ? window.transition.value : name,
          onBeforeEnter: onBeforeTransition,
          onAfterEnter: onAfterTransition,
          onEnterCancelled: onTransitionCancelled,
          onBeforeLeave: onBeforeTransition,
          onAfterLeave: onAfterTransition,
          onLeaveCancelled: onTransitionCancelled,
          onEnter: onEnterTransition
        };
      });
      const {
        hasContent
      } = useLazy(props, groupItem.isSelected);
      useRender(() => vue.createVNode(MaybeTransition, {
        "transition": transition.value,
        "disabled": !isBooted.value
      }, {
        default: () => [vue.withDirectives(vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-window-item', groupItem.selectedClass.value, props.class]),
          "style": vue.normalizeStyle(props.style)
        }, [hasContent.value && slots.default?.()]), [[vue.vShow, groupItem.isSelected.value]])]
      }));
      return {
        groupItem
      };
    }
  });

  // Types

  const makeVCarouselItemProps = propsFactory({
    ...makeVImgProps(),
    ...makeVWindowItemProps()
  }, 'VCarouselItem');
  const VCarouselItem = genericComponent()({
    name: 'VCarouselItem',
    inheritAttrs: false,
    props: makeVCarouselItemProps(),
    setup(props, {
      slots,
      attrs
    }) {
      useRender(() => {
        const imgProps = VImg.filterProps(props);
        const windowItemProps = VWindowItem.filterProps(props);
        return vue.createVNode(VWindowItem, vue.mergeProps({
          "class": ['v-carousel-item', props.class]
        }, windowItemProps), {
          default: () => [vue.createVNode(VImg, vue.mergeProps(attrs, imgProps), slots)]
        });
      });
    }
  });

  // Styles
  const VCode = createSimpleFunctional('v-code', 'code');

  // Types

  const makeVColorPickerCanvasProps = propsFactory({
    color: {
      type: Object
    },
    disabled: Boolean,
    readonly: Boolean,
    dotSize: {
      type: [Number, String],
      default: 10
    },
    height: {
      type: [Number, String],
      default: 150
    },
    width: {
      type: [Number, String],
      default: 300
    },
    ...makeComponentProps()
  }, 'VColorPickerCanvas');
  const VColorPickerCanvas = defineComponent({
    name: 'VColorPickerCanvas',
    props: makeVColorPickerCanvasProps(),
    emits: {
      'update:color': color => true,
      'update:position': hue => true
    },
    setup(props, {
      emit
    }) {
      const isInteracting = vue.shallowRef(false);
      const canvasRef = vue.ref();
      const canvasWidth = vue.shallowRef(parseFloat(props.width));
      const canvasHeight = vue.shallowRef(parseFloat(props.height));
      const _dotPosition = vue.ref({
        x: 0,
        y: 0
      });
      const isInteractive = vue.toRef(() => !props.disabled && !props.readonly);
      const dotPosition = vue.computed({
        get: () => _dotPosition.value,
        set(val) {
          if (!canvasRef.value) return;
          const {
            x,
            y
          } = val;
          _dotPosition.value = val;
          emit('update:color', {
            h: props.color?.h ?? 0,
            s: clamp(x, 0, canvasWidth.value) / canvasWidth.value,
            v: 1 - clamp(y, 0, canvasHeight.value) / canvasHeight.value,
            a: props.color?.a ?? 1
          });
        }
      });
      const dotStyles = vue.computed(() => {
        const {
          x,
          y
        } = dotPosition.value;
        const radius = parseInt(props.dotSize, 10) / 2;
        return {
          width: convertToUnit(props.dotSize),
          height: convertToUnit(props.dotSize),
          transform: `translate(${convertToUnit(x - radius)}, ${convertToUnit(y - radius)})`
        };
      });
      const {
        resizeRef
      } = useResizeObserver(entries => {
        if (!resizeRef.el?.offsetParent) return;
        const {
          width,
          height
        } = entries[0].contentRect;
        canvasWidth.value = Math.round(width);
        canvasHeight.value = Math.round(height);
      });
      function updateDotPosition(x, y, rect) {
        const {
          left,
          top,
          width,
          height
        } = rect;
        dotPosition.value = {
          x: clamp(x - left, 0, width),
          y: clamp(y - top, 0, height)
        };
      }
      function handleMouseDown(e) {
        if (e.type === 'mousedown') {
          // Prevent text selection while dragging
          e.preventDefault();
        }
        if (!isInteractive.value) return;
        handleMouseMove(e);
        window.addEventListener('mousemove', handleMouseMove);
        window.addEventListener('mouseup', handleMouseUp);
        window.addEventListener('touchmove', handleMouseMove);
        window.addEventListener('touchend', handleMouseUp);
      }
      function handleMouseMove(e) {
        if (!isInteractive.value || !canvasRef.value) return;
        isInteracting.value = true;
        const coords = getEventCoordinates(e);
        const point = getTargetBox([coords.clientX, coords.clientY]);
        updateDotPosition(point.x, point.y, getTargetBox(canvasRef.value));
      }
      function handleMouseUp() {
        window.removeEventListener('mousemove', handleMouseMove);
        window.removeEventListener('mouseup', handleMouseUp);
        window.removeEventListener('touchmove', handleMouseMove);
        window.removeEventListener('touchend', handleMouseUp);
      }
      function updateCanvas() {
        if (!canvasRef.value) return;
        const canvas = canvasRef.value;
        const ctx = canvas.getContext('2d');
        if (!ctx) return;
        const saturationGradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
        saturationGradient.addColorStop(0, 'hsla(0, 0%, 100%, 1)'); // white
        saturationGradient.addColorStop(1, `hsla(${props.color?.h ?? 0}, 100%, 50%, 1)`);
        ctx.fillStyle = saturationGradient;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        const valueGradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
        valueGradient.addColorStop(0, 'hsla(0, 0%, 0%, 0)'); // transparent
        valueGradient.addColorStop(1, 'hsla(0, 0%, 0%, 1)'); // black
        ctx.fillStyle = valueGradient;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
      }
      vue.watch(() => props.color?.h, updateCanvas, {
        immediate: true
      });
      vue.watch(() => [canvasWidth.value, canvasHeight.value], (newVal, oldVal) => {
        updateCanvas();
        _dotPosition.value = {
          x: dotPosition.value.x * newVal[0] / oldVal[0],
          y: dotPosition.value.y * newVal[1] / oldVal[1]
        };
      }, {
        flush: 'post'
      });
      vue.watch(() => props.color, () => {
        if (isInteracting.value) {
          isInteracting.value = false;
          return;
        }
        _dotPosition.value = props.color ? {
          x: props.color.s * canvasWidth.value,
          y: (1 - props.color.v) * canvasHeight.value
        } : {
          x: 0,
          y: 0
        };
      }, {
        deep: true,
        immediate: true
      });
      vue.onMounted(() => updateCanvas());
      useRender(() => vue.createElementVNode("div", {
        "ref": resizeRef,
        "class": vue.normalizeClass(['v-color-picker-canvas', props.class]),
        "style": vue.normalizeStyle(props.style),
        "onMousedown": handleMouseDown,
        "onTouchstartPassive": handleMouseDown
      }, [vue.createElementVNode("canvas", {
        "ref": canvasRef,
        "width": canvasWidth.value,
        "height": canvasHeight.value
      }, null), props.color && vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-color-picker-canvas__dot', {
          'v-color-picker-canvas__dot--disabled': props.disabled
        }]),
        "style": vue.normalizeStyle(dotStyles.value)
      }, null)]));
      return {};
    }
  });

  // Utilities

  // Types

  function stripAlpha(color, stripAlpha) {
    if (stripAlpha) {
      const {
        a,
        ...rest
      } = color;
      return rest;
    }
    return color;
  }
  function extractColor(color, input) {
    if (input == null || typeof input === 'string') {
      const hasA = typeof color.a === 'number' && color.a < 1;
      if (input?.startsWith('rgb(')) {
        const {
          r,
          g,
          b,
          a
        } = HSVtoRGB(color);
        return `rgb(${r} ${g} ${b}` + (hasA ? ` / ${a})` : ')');
      } else if (input?.startsWith('hsl(')) {
        const {
          h,
          s,
          l,
          a
        } = HSVtoHSL(color);
        return `hsl(${h} ${Math.round(s * 100)} ${Math.round(l * 100)}` + (hasA ? ` / ${a})` : ')');
      }
      const hex = HSVtoHex(color);
      if (color.a === 1) return hex.slice(0, 7);else return hex;
    }
    if (typeof input === 'object') {
      let converted;
      if (has(input, ['r', 'g', 'b'])) converted = HSVtoRGB(color);else if (has(input, ['h', 's', 'l'])) converted = HSVtoHSL(color);else if (has(input, ['h', 's', 'v'])) converted = color;
      return stripAlpha(converted, !has(input, ['a']) && color.a === 1);
    }
    return color;
  }
  const nullColor = {
    h: 0,
    s: 0,
    v: 0,
    a: 1
  };
  const rgba = {
    inputProps: {
      type: 'number',
      min: 0
    },
    inputs: [{
      label: 'R',
      max: 255,
      step: 1,
      getValue: c => Math.round(c.r),
      getColor: (c, v) => ({
        ...c,
        r: Number(v)
      }),
      localeKey: 'redInput'
    }, {
      label: 'G',
      max: 255,
      step: 1,
      getValue: c => Math.round(c.g),
      getColor: (c, v) => ({
        ...c,
        g: Number(v)
      }),
      localeKey: 'greenInput'
    }, {
      label: 'B',
      max: 255,
      step: 1,
      getValue: c => Math.round(c.b),
      getColor: (c, v) => ({
        ...c,
        b: Number(v)
      }),
      localeKey: 'blueInput'
    }, {
      label: 'A',
      max: 1,
      step: 0.01,
      getValue: ({
        a
      }) => a != null ? Math.round(a * 100) / 100 : 1,
      getColor: (c, v) => ({
        ...c,
        a: Number(v)
      }),
      localeKey: 'alphaInput'
    }],
    to: HSVtoRGB,
    from: RGBtoHSV
  };
  const rgb = {
    ...rgba,
    inputs: rgba.inputs?.slice(0, 3)
  };
  const hsla = {
    inputProps: {
      type: 'number',
      min: 0
    },
    inputs: [{
      label: 'H',
      max: 360,
      step: 1,
      getValue: c => Math.round(c.h),
      getColor: (c, v) => ({
        ...c,
        h: Number(v)
      }),
      localeKey: 'hueInput'
    }, {
      label: 'S',
      max: 1,
      step: 0.01,
      getValue: c => Math.round(c.s * 100) / 100,
      getColor: (c, v) => ({
        ...c,
        s: Number(v)
      }),
      localeKey: 'saturationInput'
    }, {
      label: 'L',
      max: 1,
      step: 0.01,
      getValue: c => Math.round(c.l * 100) / 100,
      getColor: (c, v) => ({
        ...c,
        l: Number(v)
      }),
      localeKey: 'lightnessInput'
    }, {
      label: 'A',
      max: 1,
      step: 0.01,
      getValue: ({
        a
      }) => a != null ? Math.round(a * 100) / 100 : 1,
      getColor: (c, v) => ({
        ...c,
        a: Number(v)
      }),
      localeKey: 'alphaInput'
    }],
    to: HSVtoHSL,
    from: HSLtoHSV
  };
  const hsl = {
    ...hsla,
    inputs: hsla.inputs.slice(0, 3)
  };
  const hexa = {
    inputProps: {
      type: 'text'
    },
    inputs: [{
      label: 'HEXA',
      getValue: c => c,
      getColor: (c, v) => v,
      localeKey: 'hexaInput'
    }],
    to: HSVtoHex,
    from: HexToHSV
  };
  const hex = {
    ...hexa,
    inputs: [{
      label: 'HEX',
      getValue: c => c.slice(0, 7),
      getColor: (c, v) => v,
      localeKey: 'hexInput'
    }]
  };
  const modes = {
    rgb,
    rgba,
    hsl,
    hsla,
    hex,
    hexa
  };

  // Types

  const VColorPickerInput = ({
    label,
    ...rest
  }) => {
    return vue.createElementVNode("div", {
      "class": "v-color-picker-edit__input"
    }, [vue.createElementVNode("input", vue.normalizeProps(vue.guardReactiveProps(rest)), null), vue.createElementVNode("span", null, [label])]);
  };
  const makeVColorPickerEditProps = propsFactory({
    color: Object,
    disabled: Boolean,
    hideInputLabels: Boolean,
    readonly: Boolean,
    mode: {
      type: String,
      default: 'rgba',
      validator: v => Object.keys(modes).includes(v)
    },
    modes: {
      type: Array,
      default: () => Object.keys(modes),
      validator: v => Array.isArray(v) && v.every(m => Object.keys(modes).includes(m))
    },
    ...makeComponentProps()
  }, 'VColorPickerEdit');
  const VColorPickerEdit = defineComponent({
    name: 'VColorPickerEdit',
    props: makeVColorPickerEditProps(),
    emits: {
      'update:color': color => true,
      'update:mode': mode => true
    },
    setup(props, {
      emit
    }) {
      const {
        t
      } = useLocale();
      const enabledModes = vue.computed(() => {
        return props.modes.map(key => ({
          ...modes[key],
          name: key
        }));
      });
      const inputs = vue.computed(() => {
        const mode = enabledModes.value.find(m => m.name === props.mode);
        if (!mode) return [];
        const color = props.color ? mode.to(props.color) : null;
        return mode.inputs?.map(({
          getValue,
          getColor,
          localeKey,
          ...inputProps
        }) => {
          return {
            ...mode.inputProps,
            ...inputProps,
            ariaLabel: t(`$vuetify.colorPicker.ariaLabel.${localeKey}`),
            disabled: props.disabled,
            readonly: props.readonly,
            value: color && getValue(color),
            onChange: e => {
              const target = e.target;
              if (!target) return;
              emit('update:color', mode.from(getColor(color ?? mode.to(nullColor), target.value)));
            }
          };
        });
      });
      useRender(() => vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-color-picker-edit', props.class]),
        "style": vue.normalizeStyle(props.style)
      }, [inputs.value?.map(inputProps => vue.createVNode(VColorPickerInput, vue.mergeProps(inputProps, {
        "label": props.hideInputLabels ? undefined : inputProps.label
      }), null)), enabledModes.value.length > 1 && vue.createVNode(VBtn, {
        "icon": "$unfold",
        "size": "x-small",
        "variant": "plain",
        "aria-label": t('$vuetify.colorPicker.ariaLabel.changeFormat'),
        "onClick": () => {
          const mi = enabledModes.value.findIndex(m => m.name === props.mode);
          emit('update:mode', enabledModes.value[(mi + 1) % enabledModes.value.length].name);
        }
      }, null)]));
      return {};
    }
  });

  /* eslint-disable max-statements */
  // Composables

  // Types

  const VSliderSymbol = Symbol.for('vuetify:v-slider');
  function getOffset(e, el, direction) {
    const vertical = direction === 'vertical';
    const rect = el.getBoundingClientRect();
    const touch = 'touches' in e ? e.touches[0] : e;
    return vertical ? touch.clientY - (rect.top + rect.height / 2) : touch.clientX - (rect.left + rect.width / 2);
  }
  function getPosition(e, position) {
    if ('touches' in e && e.touches.length) return e.touches[0][position];else if ('changedTouches' in e && e.changedTouches.length) return e.changedTouches[0][position];else return e[position];
  }
  const makeSliderProps = propsFactory({
    disabled: {
      type: Boolean,
      default: null
    },
    error: Boolean,
    readonly: {
      type: Boolean,
      default: null
    },
    max: {
      type: [Number, String],
      default: 100
    },
    min: {
      type: [Number, String],
      default: 0
    },
    step: {
      type: [Number, String],
      default: 0
    },
    thumbColor: String,
    thumbLabel: {
      type: [Boolean, String],
      default: undefined,
      validator: v => typeof v === 'boolean' || v === 'always' || v === 'hover'
    },
    thumbSize: {
      type: [Number, String],
      default: 20
    },
    showTicks: {
      type: [Boolean, String],
      default: false,
      validator: v => typeof v === 'boolean' || v === 'always'
    },
    ticks: {
      type: [Array, Object]
    },
    tickSize: {
      type: [Number, String],
      default: 2
    },
    color: String,
    trackColor: String,
    trackFillColor: String,
    trackSize: {
      type: [Number, String],
      default: 4
    },
    direction: {
      type: String,
      default: 'horizontal',
      validator: v => ['vertical', 'horizontal'].includes(v)
    },
    reverse: Boolean,
    noKeyboard: Boolean,
    ...makeRoundedProps(),
    ...makeElevationProps({
      elevation: 1
    }),
    ripple: {
      type: Boolean,
      default: true
    }
  }, 'Slider');
  const useSteps = props => {
    const min = vue.computed(() => parseFloat(props.min));
    const max = vue.computed(() => parseFloat(props.max));
    const step = vue.computed(() => Number(props.step) > 0 ? parseFloat(props.step) : 0);
    const decimals = vue.computed(() => Math.max(getDecimals(step.value), getDecimals(min.value)));
    function roundValue(value) {
      value = parseFloat(value);
      if (step.value <= 0) return value;
      const clamped = clamp(value, min.value, max.value);
      const offset = min.value % step.value;
      let newValue = Math.round((clamped - offset) / step.value) * step.value + offset;
      if (clamped > newValue && newValue + step.value > max.value) {
        newValue = max.value;
      }
      return parseFloat(Math.min(newValue, max.value).toFixed(decimals.value));
    }
    return {
      min,
      max,
      step,
      decimals,
      roundValue
    };
  };
  const useSlider = ({
    props,
    steps,
    onSliderStart,
    onSliderMove,
    onSliderEnd,
    getActiveThumb
  }) => {
    const form = useForm(props);
    const {
      isRtl
    } = useRtl();
    const isReversed = vue.toRef(() => props.reverse);
    const vertical = vue.computed(() => props.direction === 'vertical');
    const indexFromEnd = vue.computed(() => vertical.value !== isReversed.value);
    const {
      min,
      max,
      step,
      decimals,
      roundValue
    } = steps;
    const thumbSize = vue.computed(() => parseInt(props.thumbSize, 10));
    const tickSize = vue.computed(() => parseInt(props.tickSize, 10));
    const trackSize = vue.computed(() => parseInt(props.trackSize, 10));
    const numTicks = vue.computed(() => (max.value - min.value) / step.value);
    const thumbColor = vue.computed(() => props.error || form.isDisabled.value ? undefined : props.thumbColor ?? props.color);
    const thumbLabelColor = vue.computed(() => props.error || form.isDisabled.value ? undefined : props.thumbColor);
    const trackColor = vue.computed(() => props.error || form.isDisabled.value ? undefined : props.trackColor ?? props.color);
    const trackFillColor = vue.computed(() => props.error || form.isDisabled.value ? undefined : props.trackFillColor ?? props.color);
    const mousePressed = vue.shallowRef(false);
    const startOffset = vue.shallowRef(0);
    const trackContainerRef = vue.ref();
    const activeThumbRef = vue.ref();
    function parseMouseMove(e) {
      const el = trackContainerRef.value?.$el;
      if (!el) return;
      const vertical = props.direction === 'vertical';
      const start = vertical ? 'top' : 'left';
      const length = vertical ? 'height' : 'width';
      const position = vertical ? 'clientY' : 'clientX';
      const {
        [start]: trackStart,
        [length]: trackLength
      } = el.getBoundingClientRect();
      const clickOffset = getPosition(e, position);

      // It is possible for left to be NaN, force to number
      let clickPos = clamp((clickOffset - trackStart - startOffset.value) / trackLength) || 0;
      if (vertical ? indexFromEnd.value : indexFromEnd.value !== isRtl.value) clickPos = 1 - clickPos;
      return roundValue(min.value + clickPos * (max.value - min.value));
    }
    const handleStop = e => {
      const value = parseMouseMove(e);
      if (value != null) {
        onSliderEnd({
          value
        });
      }
      mousePressed.value = false;
      startOffset.value = 0;
    };
    const handleStart = e => {
      const value = parseMouseMove(e);
      activeThumbRef.value = getActiveThumb(e);
      if (!activeThumbRef.value) return;
      mousePressed.value = true;
      if (activeThumbRef.value.contains(e.target)) {
        startOffset.value = getOffset(e, activeThumbRef.value, props.direction);
      } else {
        startOffset.value = 0;
        if (value != null) {
          onSliderMove({
            value
          });
        }
      }
      if (value != null) {
        onSliderStart({
          value
        });
      }
      vue.nextTick(() => activeThumbRef.value?.focus());
    };
    const moveListenerOptions = {
      passive: true,
      capture: true
    };
    function onMouseMove(e) {
      const value = parseMouseMove(e);
      if (value != null) {
        onSliderMove({
          value
        });
      }
    }
    function onSliderMouseUp(e) {
      e.stopPropagation();
      e.preventDefault();
      handleStop(e);
      window.removeEventListener('mousemove', onMouseMove, moveListenerOptions);
      window.removeEventListener('mouseup', onSliderMouseUp);
    }
    function onSliderTouchend(e) {
      handleStop(e);
      window.removeEventListener('touchmove', onMouseMove, moveListenerOptions);
      e.target?.removeEventListener('touchend', onSliderTouchend);
    }
    function onSliderTouchstart(e) {
      handleStart(e);
      window.addEventListener('touchmove', onMouseMove, moveListenerOptions);
      e.target?.addEventListener('touchend', onSliderTouchend, {
        passive: false
      });
    }
    function onSliderMousedown(e) {
      if (e.button !== 0) return;
      e.preventDefault();
      handleStart(e);
      window.addEventListener('mousemove', onMouseMove, moveListenerOptions);
      window.addEventListener('mouseup', onSliderMouseUp, {
        passive: false
      });
    }
    vue.onScopeDispose(() => {
      if (!IN_BROWSER) return;
      window.removeEventListener('touchmove', onMouseMove);
      window.removeEventListener('mousemove', onMouseMove);
      window.removeEventListener('mouseup', onSliderMouseUp);
    });
    const position = val => {
      const percentage = (val - min.value) / (max.value - min.value) * 100;
      return clamp(isNaN(percentage) ? 0 : percentage, 0, 100);
    };
    const showTicks = vue.toRef(() => props.showTicks);
    const parsedTicks = vue.computed(() => {
      if (!showTicks.value) return [];
      if (!props.ticks) {
        return numTicks.value !== Infinity ? createRange(numTicks.value + 1).map(t => {
          const value = min.value + t * step.value;
          return {
            value,
            position: position(value)
          };
        }) : [];
      }
      if (Array.isArray(props.ticks)) return props.ticks.map(t => ({
        value: t,
        position: position(t),
        label: t.toString()
      }));
      return Object.keys(props.ticks).map(key => ({
        value: parseFloat(key),
        position: position(parseFloat(key)),
        label: props.ticks[key]
      }));
    });
    const hasLabels = vue.computed(() => parsedTicks.value.some(({
      label
    }) => !!label));
    const data = {
      activeThumbRef,
      color: vue.toRef(() => props.color),
      decimals,
      disabled: form.isDisabled,
      direction: vue.toRef(() => props.direction),
      elevation: vue.toRef(() => props.elevation),
      hasLabels,
      isReversed,
      indexFromEnd,
      min,
      max,
      mousePressed,
      noKeyboard: vue.toRef(() => props.noKeyboard),
      numTicks,
      onSliderMousedown,
      onSliderTouchstart,
      parsedTicks,
      parseMouseMove,
      position,
      readonly: form.isReadonly,
      rounded: vue.toRef(() => props.rounded),
      roundValue,
      showTicks,
      startOffset,
      step,
      thumbSize,
      thumbColor,
      thumbLabelColor,
      thumbLabel: vue.toRef(() => props.thumbLabel),
      ticks: vue.toRef(() => props.ticks),
      tickSize,
      trackColor,
      trackContainerRef,
      trackFillColor,
      trackSize,
      vertical
    };
    vue.provide(VSliderSymbol, data);
    return data;
  };

  // Types

  const makeVSliderThumbProps = propsFactory({
    focused: Boolean,
    max: {
      type: Number,
      required: true
    },
    min: {
      type: Number,
      required: true
    },
    modelValue: {
      type: Number,
      required: true
    },
    position: {
      type: Number,
      required: true
    },
    ripple: {
      type: [Boolean, Object],
      default: true
    },
    name: String,
    noKeyboard: Boolean,
    ...makeComponentProps()
  }, 'VSliderThumb');
  const VSliderThumb = genericComponent()({
    name: 'VSliderThumb',
    directives: {
      vRipple: Ripple
    },
    props: makeVSliderThumbProps(),
    emits: {
      'update:modelValue': v => true
    },
    setup(props, {
      slots,
      emit
    }) {
      const slider = vue.inject(VSliderSymbol);
      const {
        isRtl,
        rtlClasses
      } = useRtl();
      if (!slider) throw new Error('[Vuetify] v-slider-thumb must be used inside v-slider or v-range-slider');
      const {
        min,
        max,
        thumbColor,
        thumbLabelColor,
        step,
        disabled,
        thumbSize,
        thumbLabel,
        direction,
        isReversed,
        vertical,
        readonly,
        elevation,
        mousePressed,
        decimals,
        indexFromEnd
      } = slider;
      const isHovered = vue.shallowRef(false);
      const isHidden = vue.shallowRef(false);
      const elevationProps = vue.computed(() => !disabled.value ? elevation.value : undefined);
      const {
        elevationClasses
      } = useElevation(elevationProps);
      const {
        textColorClasses,
        textColorStyles
      } = useTextColor(thumbColor);
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(thumbLabelColor);
      const {
        pageup,
        pagedown,
        end,
        home,
        left,
        right,
        down,
        up
      } = keyValues;
      const relevantKeys = [pageup, pagedown, end, home, left, right, down, up];
      const multipliers = vue.computed(() => {
        if (step.value) return [1, 2, 3];else return [1, 5, 10];
      });
      function parseKeydown(e, value) {
        if (props.noKeyboard || disabled.value) return;
        if (!relevantKeys.includes(e.key)) return;
        e.preventDefault();
        const _step = step.value || 0.1;
        const steps = (max.value - min.value) / _step;
        if ([left, right, down, up].includes(e.key)) {
          const increase = vertical.value ? [isRtl.value ? left : right, isReversed.value ? down : up] : indexFromEnd.value !== isRtl.value ? [left, up] : [right, up];
          const direction = increase.includes(e.key) ? 1 : -1;
          const multiplier = e.shiftKey ? 2 : e.ctrlKey ? 1 : 0;
          if (direction === -1 && value === max.value && !multiplier && !Number.isInteger(steps)) {
            value = value - steps % 1 * _step;
          } else {
            value = value + direction * _step * multipliers.value[multiplier];
          }
        } else if (e.key === home) {
          value = min.value;
        } else if (e.key === end) {
          value = max.value;
        } else {
          const direction = e.key === pagedown ? 1 : -1;
          value = value - direction * _step * (steps > 100 ? steps / 10 : 10);
        }
        return Math.max(props.min, Math.min(props.max, value));
      }
      function onKeydown(e) {
        const newValue = parseKeydown(e, props.modelValue);
        if (newValue != null) {
          isHidden.value = false;
          emit('update:modelValue', newValue);
        }
      }
      vue.watch(() => props.focused, val => {
        if (val) {
          isHidden.value = false;
        }
      });
      useRender(() => {
        const positionPercentage = convertToUnit(indexFromEnd.value ? 100 - props.position : props.position, '%');
        const thumbLabelVisible = thumbLabel.value === 'always' || thumbLabel.value === true && props.focused || thumbLabel.value === 'hover' && (isHovered.value || props.focused && !isHidden.value);
        return vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-slider-thumb', {
            'v-slider-thumb--focused': props.focused,
            'v-slider-thumb--pressed': props.focused && mousePressed.value
          }, props.class, rtlClasses.value]),
          "style": vue.normalizeStyle([{
            '--v-slider-thumb-position': positionPercentage,
            '--v-slider-thumb-size': convertToUnit(thumbSize.value)
          }, props.style]),
          "role": "slider",
          "tabindex": disabled.value ? -1 : 0,
          "aria-label": props.name,
          "aria-valuemin": min.value,
          "aria-valuemax": max.value,
          "aria-valuenow": props.modelValue,
          "aria-readonly": !!readonly.value,
          "aria-orientation": direction.value,
          "onKeydown": !readonly.value ? onKeydown : undefined,
          "onMouseenter": () => {
            isHovered.value = true;
          },
          "onMouseleave": () => {
            isHovered.value = false;
            isHidden.value = true;
          }
        }, [vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-slider-thumb__surface', textColorClasses.value, elevationClasses.value]),
          "style": vue.normalizeStyle(textColorStyles.value)
        }, null), vue.withDirectives(vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-slider-thumb__ripple', textColorClasses.value]),
          "style": vue.normalizeStyle(textColorStyles.value)
        }, null), [[Ripple, props.ripple, null, {
          circle: true,
          center: true
        }]]), vue.createVNode(VScaleTransition, {
          "origin": "bottom center"
        }, {
          default: () => [vue.withDirectives(vue.createElementVNode("div", {
            "class": "v-slider-thumb__label-container"
          }, [vue.createElementVNode("div", {
            "class": vue.normalizeClass(['v-slider-thumb__label', backgroundColorClasses.value]),
            "style": vue.normalizeStyle(backgroundColorStyles.value)
          }, [vue.createElementVNode("div", null, [slots['thumb-label']?.({
            modelValue: props.modelValue
          }) ?? props.modelValue.toFixed(step.value ? decimals.value : 1)]), vue.createElementVNode("div", {
            "class": "v-slider-thumb__label-wedge"
          }, null)])]), [[vue.vShow, thumbLabelVisible]])]
        })]);
      });
      return {};
    }
  });

  // Types

  const makeVSliderTrackProps = propsFactory({
    start: {
      type: Number,
      required: true
    },
    stop: {
      type: Number,
      required: true
    },
    ...makeComponentProps()
  }, 'VSliderTrack');
  const VSliderTrack = genericComponent()({
    name: 'VSliderTrack',
    props: makeVSliderTrackProps(),
    emits: {},
    setup(props, {
      slots
    }) {
      const slider = vue.inject(VSliderSymbol);
      if (!slider) throw new Error('[Vuetify] v-slider-track must be inside v-slider or v-range-slider');
      const {
        color,
        parsedTicks,
        rounded,
        showTicks,
        tickSize,
        trackColor,
        trackFillColor,
        trackSize,
        vertical,
        min,
        max,
        indexFromEnd
      } = slider;
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(rounded);
      const {
        backgroundColorClasses: trackFillColorClasses,
        backgroundColorStyles: trackFillColorStyles
      } = useBackgroundColor(trackFillColor);
      const {
        backgroundColorClasses: trackColorClasses,
        backgroundColorStyles: trackColorStyles
      } = useBackgroundColor(trackColor);
      const startDir = vue.computed(() => `inset-${vertical.value ? 'block' : 'inline'}-${indexFromEnd.value ? 'end' : 'start'}`);
      const endDir = vue.computed(() => vertical.value ? 'height' : 'width');
      const backgroundStyles = vue.computed(() => {
        return {
          [startDir.value]: '0%',
          [endDir.value]: '100%'
        };
      });
      const trackFillWidth = vue.computed(() => props.stop - props.start);
      const trackFillStyles = vue.computed(() => {
        return {
          [startDir.value]: convertToUnit(props.start, '%'),
          [endDir.value]: convertToUnit(trackFillWidth.value, '%')
        };
      });
      const computedTicks = vue.computed(() => {
        if (!showTicks.value) return [];
        const ticks = vertical.value ? parsedTicks.value.slice().reverse() : parsedTicks.value;
        return ticks.map((tick, index) => {
          const directionValue = tick.value !== min.value && tick.value !== max.value ? convertToUnit(tick.position, '%') : undefined;
          return vue.createElementVNode("div", {
            "key": tick.value,
            "class": vue.normalizeClass(['v-slider-track__tick', {
              'v-slider-track__tick--filled': tick.position >= props.start && tick.position <= props.stop,
              'v-slider-track__tick--first': tick.value === min.value,
              'v-slider-track__tick--last': tick.value === max.value
            }]),
            "style": {
              [startDir.value]: directionValue
            }
          }, [(tick.label || slots['tick-label']) && vue.createElementVNode("div", {
            "class": "v-slider-track__tick-label"
          }, [slots['tick-label']?.({
            tick,
            index
          }) ?? tick.label])]);
        });
      });
      useRender(() => {
        return vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-slider-track', roundedClasses.value, props.class]),
          "style": vue.normalizeStyle([{
            '--v-slider-track-size': convertToUnit(trackSize.value),
            '--v-slider-tick-size': convertToUnit(tickSize.value)
          }, roundedStyles.value, props.style])
        }, [vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-slider-track__background', trackColorClasses.value, {
            'v-slider-track__background--opacity': !!color.value || !trackFillColor.value
          }]),
          "style": {
            ...backgroundStyles.value,
            ...trackColorStyles.value
          }
        }, null), vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-slider-track__fill', trackFillColorClasses.value]),
          "style": {
            ...trackFillStyles.value,
            ...trackFillColorStyles.value
          }
        }, null), showTicks.value && vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-slider-track__ticks', {
            'v-slider-track__ticks--always-show': showTicks.value === 'always'
          }])
        }, [computedTicks.value])]);
      });
      return {};
    }
  });

  // Types

  const makeVSliderProps = propsFactory({
    ...makeFocusProps(),
    ...makeSliderProps(),
    ...makeVInputProps(),
    modelValue: {
      type: [Number, String],
      default: 0
    }
  }, 'VSlider');
  const VSlider = genericComponent()({
    name: 'VSlider',
    inheritAttrs: false,
    props: makeVSliderProps(),
    emits: {
      'update:focused': value => true,
      'update:modelValue': v => true,
      start: value => true,
      end: value => true
    },
    setup(props, {
      slots,
      emit,
      attrs
    }) {
      const thumbContainerRef = vue.ref();
      const inputRef = vue.ref();
      const {
        rtlClasses
      } = useRtl();
      const steps = useSteps(props);
      const model = useProxiedModel(props, 'modelValue', undefined, value => {
        return steps.roundValue(value == null ? steps.min.value : value);
      });
      const {
        min,
        max,
        mousePressed,
        roundValue,
        onSliderMousedown,
        onSliderTouchstart,
        trackContainerRef,
        position,
        hasLabels,
        disabled,
        readonly,
        noKeyboard
      } = useSlider({
        props,
        steps,
        onSliderStart: () => {
          if (!disabled.value && !readonly.value) {
            emit('start', model.value);
          }
        },
        onSliderEnd: ({
          value
        }) => {
          const roundedValue = roundValue(value);
          if (!disabled.value && !readonly.value) {
            model.value = roundedValue;
          }
          emit('end', roundedValue);
        },
        onSliderMove: ({
          value
        }) => {
          if (!disabled.value && !readonly.value) {
            model.value = roundValue(value);
          }
        },
        getActiveThumb: () => thumbContainerRef.value?.$el
      });
      const {
        isFocused,
        focus,
        blur
      } = useFocus(props);
      const trackStop = vue.computed(() => position(model.value));
      useRender(() => {
        const inputProps = VInput.filterProps(props);
        const [rootAttrs, inputAttrs] = filterInputAttrs(attrs);
        const hasPrepend = !!(props.label || slots.label || slots.prepend);
        return vue.createVNode(VInput, vue.mergeProps({
          "ref": inputRef,
          "class": ['v-slider', {
            'v-slider--has-labels': !!slots['tick-label'] || hasLabels.value,
            'v-slider--focused': isFocused.value,
            'v-slider--pressed': mousePressed.value,
            'v-slider--disabled': disabled.value
          }, rtlClasses.value, props.class],
          "style": props.style
        }, inputProps, rootAttrs, {
          "focused": isFocused.value
        }), {
          ...slots,
          prepend: hasPrepend ? slotProps => vue.createElementVNode(vue.Fragment, null, [slots.label?.(slotProps) ?? (props.label ? vue.createVNode(VLabel, {
            "id": slotProps.id.value,
            "class": "v-slider__label",
            "text": props.label
          }, null) : undefined), slots.prepend?.(slotProps)]) : undefined,
          default: ({
            id,
            messagesId
          }) => vue.createElementVNode("div", {
            "class": "v-slider__container",
            "onMousedown": !readonly.value ? onSliderMousedown : undefined,
            "onTouchstartPassive": !readonly.value ? onSliderTouchstart : undefined
          }, [vue.createElementVNode("input", {
            "id": id.value,
            "name": props.name || id.value,
            "disabled": disabled.value,
            "readonly": readonly.value,
            "tabindex": "-1",
            "value": model.value
          }, null), vue.createVNode(VSliderTrack, {
            "ref": trackContainerRef,
            "start": 0,
            "stop": trackStop.value
          }, {
            'tick-label': slots['tick-label']
          }), vue.createVNode(VSliderThumb, vue.mergeProps({
            "ref": thumbContainerRef,
            "aria-describedby": messagesId.value,
            "focused": isFocused.value,
            "noKeyboard": noKeyboard.value,
            "min": min.value,
            "max": max.value,
            "modelValue": model.value,
            "onUpdate:modelValue": v => model.value = v,
            "position": trackStop.value,
            "elevation": props.elevation,
            "onFocus": focus,
            "onBlur": blur,
            "ripple": props.ripple,
            "name": props.name
          }, inputAttrs), {
            'thumb-label': slots['thumb-label']
          })])
        });
      });
      return forwardRefs({
        focus: () => thumbContainerRef.value?.$el.focus()
      }, inputRef);
    }
  });

  // Types

  const makeVColorPickerPreviewProps = propsFactory({
    color: {
      type: Object
    },
    disabled: Boolean,
    readonly: Boolean,
    hideAlpha: Boolean,
    hideEyeDropper: Boolean,
    eyeDropperIcon: {
      type: IconValue,
      default: '$eyeDropper'
    },
    ...makeComponentProps()
  }, 'VColorPickerPreview');
  const VColorPickerPreview = defineComponent({
    name: 'VColorPickerPreview',
    props: makeVColorPickerPreviewProps(),
    emits: {
      'update:color': color => true
    },
    setup(props, {
      emit
    }) {
      const {
        t
      } = useLocale();
      const abortController = new AbortController();
      const isInteractive = vue.toRef(() => !props.disabled && !props.readonly);
      vue.onUnmounted(() => abortController.abort());
      async function openEyeDropper() {
        if (!SUPPORTS_EYE_DROPPER || !isInteractive.value) return;
        const eyeDropper = new window.EyeDropper();
        try {
          const result = await eyeDropper.open({
            signal: abortController.signal
          });
          const colorHexValue = RGBtoHSV(parseColor(result.sRGBHex));
          emit('update:color', {
            ...(props.color ?? nullColor),
            ...colorHexValue
          });
        } catch (e) {}
      }
      useRender(() => vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-color-picker-preview', {
          'v-color-picker-preview--hide-alpha': props.hideAlpha
        }, props.class]),
        "style": vue.normalizeStyle(props.style)
      }, [SUPPORTS_EYE_DROPPER && !props.hideEyeDropper && vue.createElementVNode("div", {
        "class": "v-color-picker-preview__eye-dropper",
        "key": "eyeDropper"
      }, [vue.createVNode(VBtn, {
        "aria-label": t('$vuetify.colorPicker.ariaLabel.eyedropper'),
        "density": "comfortable",
        "disabled": props.disabled,
        "readonly": props.readonly,
        "icon": props.eyeDropperIcon,
        "variant": "plain",
        "onClick": openEyeDropper
      }, null)]), vue.createElementVNode("div", {
        "class": "v-color-picker-preview__dot"
      }, [vue.createElementVNode("div", {
        "style": {
          background: HSVtoCSS(props.color ?? nullColor)
        }
      }, null)]), vue.createElementVNode("div", {
        "class": "v-color-picker-preview__sliders"
      }, [vue.createVNode(VSlider, {
        "class": "v-color-picker-preview__track v-color-picker-preview__hue",
        "aria-label": t('$vuetify.colorPicker.ariaLabel.hueSlider'),
        "modelValue": props.color?.h,
        "onUpdate:modelValue": h => emit('update:color', {
          ...(props.color ?? nullColor),
          h
        }),
        "step": 1,
        "min": 0,
        "max": 360,
        "disabled": props.disabled,
        "readonly": props.readonly,
        "thumbSize": 14,
        "trackSize": 8,
        "trackFillColor": "white",
        "hideDetails": true
      }, null), !props.hideAlpha && vue.createVNode(VSlider, {
        "class": "v-color-picker-preview__track v-color-picker-preview__alpha",
        "aria-label": t('$vuetify.colorPicker.ariaLabel.alphaSlider'),
        "modelValue": props.color?.a ?? 1,
        "onUpdate:modelValue": a => emit('update:color', {
          ...(props.color ?? nullColor),
          a
        }),
        "step": 0.01,
        "min": 0,
        "max": 1,
        "disabled": props.disabled,
        "readonly": props.readonly,
        "thumbSize": 14,
        "trackSize": 8,
        "trackFillColor": "white",
        "hideDetails": true
      }, null)])]));
      return {};
    }
  });

  const red = {
    base: '#f44336',
    lighten5: '#ffebee',
    lighten4: '#ffcdd2',
    lighten3: '#ef9a9a',
    lighten2: '#e57373',
    lighten1: '#ef5350',
    darken1: '#e53935',
    darken2: '#d32f2f',
    darken3: '#c62828',
    darken4: '#b71c1c',
    accent1: '#ff8a80',
    accent2: '#ff5252',
    accent3: '#ff1744',
    accent4: '#d50000'
  };
  const pink = {
    base: '#e91e63',
    lighten5: '#fce4ec',
    lighten4: '#f8bbd0',
    lighten3: '#f48fb1',
    lighten2: '#f06292',
    lighten1: '#ec407a',
    darken1: '#d81b60',
    darken2: '#c2185b',
    darken3: '#ad1457',
    darken4: '#880e4f',
    accent1: '#ff80ab',
    accent2: '#ff4081',
    accent3: '#f50057',
    accent4: '#c51162'
  };
  const purple = {
    base: '#9c27b0',
    lighten5: '#f3e5f5',
    lighten4: '#e1bee7',
    lighten3: '#ce93d8',
    lighten2: '#ba68c8',
    lighten1: '#ab47bc',
    darken1: '#8e24aa',
    darken2: '#7b1fa2',
    darken3: '#6a1b9a',
    darken4: '#4a148c',
    accent1: '#ea80fc',
    accent2: '#e040fb',
    accent3: '#d500f9',
    accent4: '#aa00ff'
  };
  const deepPurple = {
    base: '#673ab7',
    lighten5: '#ede7f6',
    lighten4: '#d1c4e9',
    lighten3: '#b39ddb',
    lighten2: '#9575cd',
    lighten1: '#7e57c2',
    darken1: '#5e35b1',
    darken2: '#512da8',
    darken3: '#4527a0',
    darken4: '#311b92',
    accent1: '#b388ff',
    accent2: '#7c4dff',
    accent3: '#651fff',
    accent4: '#6200ea'
  };
  const indigo = {
    base: '#3f51b5',
    lighten5: '#e8eaf6',
    lighten4: '#c5cae9',
    lighten3: '#9fa8da',
    lighten2: '#7986cb',
    lighten1: '#5c6bc0',
    darken1: '#3949ab',
    darken2: '#303f9f',
    darken3: '#283593',
    darken4: '#1a237e',
    accent1: '#8c9eff',
    accent2: '#536dfe',
    accent3: '#3d5afe',
    accent4: '#304ffe'
  };
  const blue = {
    base: '#2196f3',
    lighten5: '#e3f2fd',
    lighten4: '#bbdefb',
    lighten3: '#90caf9',
    lighten2: '#64b5f6',
    lighten1: '#42a5f5',
    darken1: '#1e88e5',
    darken2: '#1976d2',
    darken3: '#1565c0',
    darken4: '#0d47a1',
    accent1: '#82b1ff',
    accent2: '#448aff',
    accent3: '#2979ff',
    accent4: '#2962ff'
  };
  const lightBlue = {
    base: '#03a9f4',
    lighten5: '#e1f5fe',
    lighten4: '#b3e5fc',
    lighten3: '#81d4fa',
    lighten2: '#4fc3f7',
    lighten1: '#29b6f6',
    darken1: '#039be5',
    darken2: '#0288d1',
    darken3: '#0277bd',
    darken4: '#01579b',
    accent1: '#80d8ff',
    accent2: '#40c4ff',
    accent3: '#00b0ff',
    accent4: '#0091ea'
  };
  const cyan = {
    base: '#00bcd4',
    lighten5: '#e0f7fa',
    lighten4: '#b2ebf2',
    lighten3: '#80deea',
    lighten2: '#4dd0e1',
    lighten1: '#26c6da',
    darken1: '#00acc1',
    darken2: '#0097a7',
    darken3: '#00838f',
    darken4: '#006064',
    accent1: '#84ffff',
    accent2: '#18ffff',
    accent3: '#00e5ff',
    accent4: '#00b8d4'
  };
  const teal = {
    base: '#009688',
    lighten5: '#e0f2f1',
    lighten4: '#b2dfdb',
    lighten3: '#80cbc4',
    lighten2: '#4db6ac',
    lighten1: '#26a69a',
    darken1: '#00897b',
    darken2: '#00796b',
    darken3: '#00695c',
    darken4: '#004d40',
    accent1: '#a7ffeb',
    accent2: '#64ffda',
    accent3: '#1de9b6',
    accent4: '#00bfa5'
  };
  const green = {
    base: '#4caf50',
    lighten5: '#e8f5e9',
    lighten4: '#c8e6c9',
    lighten3: '#a5d6a7',
    lighten2: '#81c784',
    lighten1: '#66bb6a',
    darken1: '#43a047',
    darken2: '#388e3c',
    darken3: '#2e7d32',
    darken4: '#1b5e20',
    accent1: '#b9f6ca',
    accent2: '#69f0ae',
    accent3: '#00e676',
    accent4: '#00c853'
  };
  const lightGreen = {
    base: '#8bc34a',
    lighten5: '#f1f8e9',
    lighten4: '#dcedc8',
    lighten3: '#c5e1a5',
    lighten2: '#aed581',
    lighten1: '#9ccc65',
    darken1: '#7cb342',
    darken2: '#689f38',
    darken3: '#558b2f',
    darken4: '#33691e',
    accent1: '#ccff90',
    accent2: '#b2ff59',
    accent3: '#76ff03',
    accent4: '#64dd17'
  };
  const lime = {
    base: '#cddc39',
    lighten5: '#f9fbe7',
    lighten4: '#f0f4c3',
    lighten3: '#e6ee9c',
    lighten2: '#dce775',
    lighten1: '#d4e157',
    darken1: '#c0ca33',
    darken2: '#afb42b',
    darken3: '#9e9d24',
    darken4: '#827717',
    accent1: '#f4ff81',
    accent2: '#eeff41',
    accent3: '#c6ff00',
    accent4: '#aeea00'
  };
  const yellow = {
    base: '#ffeb3b',
    lighten5: '#fffde7',
    lighten4: '#fff9c4',
    lighten3: '#fff59d',
    lighten2: '#fff176',
    lighten1: '#ffee58',
    darken1: '#fdd835',
    darken2: '#fbc02d',
    darken3: '#f9a825',
    darken4: '#f57f17',
    accent1: '#ffff8d',
    accent2: '#ffff00',
    accent3: '#ffea00',
    accent4: '#ffd600'
  };
  const amber = {
    base: '#ffc107',
    lighten5: '#fff8e1',
    lighten4: '#ffecb3',
    lighten3: '#ffe082',
    lighten2: '#ffd54f',
    lighten1: '#ffca28',
    darken1: '#ffb300',
    darken2: '#ffa000',
    darken3: '#ff8f00',
    darken4: '#ff6f00',
    accent1: '#ffe57f',
    accent2: '#ffd740',
    accent3: '#ffc400',
    accent4: '#ffab00'
  };
  const orange = {
    base: '#ff9800',
    lighten5: '#fff3e0',
    lighten4: '#ffe0b2',
    lighten3: '#ffcc80',
    lighten2: '#ffb74d',
    lighten1: '#ffa726',
    darken1: '#fb8c00',
    darken2: '#f57c00',
    darken3: '#ef6c00',
    darken4: '#e65100',
    accent1: '#ffd180',
    accent2: '#ffab40',
    accent3: '#ff9100',
    accent4: '#ff6d00'
  };
  const deepOrange = {
    base: '#ff5722',
    lighten5: '#fbe9e7',
    lighten4: '#ffccbc',
    lighten3: '#ffab91',
    lighten2: '#ff8a65',
    lighten1: '#ff7043',
    darken1: '#f4511e',
    darken2: '#e64a19',
    darken3: '#d84315',
    darken4: '#bf360c',
    accent1: '#ff9e80',
    accent2: '#ff6e40',
    accent3: '#ff3d00',
    accent4: '#dd2c00'
  };
  const brown = {
    base: '#795548',
    lighten5: '#efebe9',
    lighten4: '#d7ccc8',
    lighten3: '#bcaaa4',
    lighten2: '#a1887f',
    lighten1: '#8d6e63',
    darken1: '#6d4c41',
    darken2: '#5d4037',
    darken3: '#4e342e',
    darken4: '#3e2723'
  };
  const blueGrey = {
    base: '#607d8b',
    lighten5: '#eceff1',
    lighten4: '#cfd8dc',
    lighten3: '#b0bec5',
    lighten2: '#90a4ae',
    lighten1: '#78909c',
    darken1: '#546e7a',
    darken2: '#455a64',
    darken3: '#37474f',
    darken4: '#263238'
  };
  const grey = {
    base: '#9e9e9e',
    lighten5: '#fafafa',
    lighten4: '#f5f5f5',
    lighten3: '#eeeeee',
    lighten2: '#e0e0e0',
    lighten1: '#bdbdbd',
    darken1: '#757575',
    darken2: '#616161',
    darken3: '#424242',
    darken4: '#212121'
  };
  const shades = {
    black: '#000000',
    white: '#ffffff',
    transparent: '#ffffff00'
  };
  var colors = {
    red,
    pink,
    purple,
    deepPurple,
    indigo,
    blue,
    lightBlue,
    cyan,
    teal,
    green,
    lightGreen,
    lime,
    yellow,
    amber,
    orange,
    deepOrange,
    brown,
    blueGrey,
    grey,
    shades
  };

  // Types

  const makeVColorPickerSwatchesProps = propsFactory({
    swatches: {
      type: Array,
      default: () => parseDefaultColors(colors)
    },
    disabled: Boolean,
    readonly: Boolean,
    color: Object,
    maxHeight: [Number, String],
    ...makeComponentProps()
  }, 'VColorPickerSwatches');
  function parseDefaultColors(colors) {
    return Object.keys(colors).map(key => {
      const color = colors[key];
      return color.base ? [color.base, color.darken4, color.darken3, color.darken2, color.darken1, color.lighten1, color.lighten2, color.lighten3, color.lighten4, color.lighten5] : [color.black, color.white, color.transparent];
    });
  }
  const VColorPickerSwatches = defineComponent({
    name: 'VColorPickerSwatches',
    props: makeVColorPickerSwatchesProps(),
    emits: {
      'update:color': color => true
    },
    setup(props, {
      emit
    }) {
      const isInteractive = vue.toRef(() => !props.disabled && !props.readonly);
      function onSwatchClick(hsva) {
        if (!isInteractive.value || !hsva) {
          return;
        }
        emit('update:color', hsva);
      }
      useRender(() => vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-color-picker-swatches', props.class]),
        "style": vue.normalizeStyle([{
          maxHeight: convertToUnit(props.maxHeight)
        }, props.style])
      }, [vue.createElementVNode("div", null, [props.swatches.map(swatch => vue.createElementVNode("div", {
        "class": "v-color-picker-swatches__swatch"
      }, [swatch.map(color => {
        const rgba = parseColor(color);
        const hsva = RGBtoHSV(rgba);
        const background = RGBtoCSS(rgba);
        return vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-color-picker-swatches__color', {
            'v-color-picker-swatches__color--disabled': props.disabled
          }]),
          "onClick": () => onSwatchClick(hsva)
        }, [vue.createElementVNode("div", {
          "style": {
            background
          }
        }, [props.color && deepEqual(props.color, hsva) ? vue.createVNode(VIcon, {
          "size": "x-small",
          "icon": "$success",
          "color": getContrast(color, '#FFFFFF') > 2 ? 'white' : 'black'
        }, null) : undefined])]);
      })]))])]));
      return {};
    }
  });

  // Utilities
  const VPickerTitle = createSimpleFunctional('v-picker-title');

  // Types

  const makeVPickerProps = propsFactory({
    bgColor: String,
    divided: Boolean,
    landscape: Boolean,
    title: String,
    hideHeader: Boolean,
    hideTitle: Boolean,
    ...makeVSheetProps()
  }, 'VPicker');
  const VPicker = genericComponent()({
    name: 'VPicker',
    props: makeVPickerProps(),
    setup(props, {
      slots
    }) {
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.color);
      useRender(() => {
        const sheetProps = VSheet.filterProps(props);
        const hasTitle = !props.hideTitle && !!(props.title || slots.title);
        return vue.createVNode(VSheet, vue.mergeProps(sheetProps, {
          "color": props.bgColor,
          "class": ['v-picker', {
            'v-picker--divided': props.divided,
            'v-picker--landscape': props.landscape,
            'v-picker--with-actions': !!slots.actions
          }, props.class],
          "style": props.style
        }), {
          default: () => [!props.hideHeader && vue.createElementVNode("div", {
            "key": "header",
            "class": vue.normalizeClass(['v-picker__header-wrapper', backgroundColorClasses.value]),
            "style": vue.normalizeStyle([backgroundColorStyles.value])
          }, [hasTitle && vue.createVNode(VPickerTitle, {
            "key": "picker-title"
          }, {
            default: () => [slots.title?.() ?? props.title]
          }), slots.header && vue.createElementVNode("div", {
            "class": "v-picker__header"
          }, [slots.header()])]), vue.createElementVNode("div", {
            "class": "v-picker__body"
          }, [slots.default?.()]), slots.actions && vue.createVNode(VDefaultsProvider, {
            "defaults": {
              VBtn: {
                slim: true,
                variant: 'text'
              }
            }
          }, {
            default: () => [vue.createElementVNode("div", {
              "class": "v-picker__actions"
            }, [slots.actions()])]
          })]
        });
      });
      return {};
    }
  });

  // Types

  const makeVColorPickerProps = propsFactory({
    canvasHeight: {
      type: [String, Number],
      default: 150
    },
    disabled: Boolean,
    dotSize: {
      type: [Number, String],
      default: 10
    },
    hideCanvas: Boolean,
    hideSliders: Boolean,
    hideInputs: Boolean,
    hideInputLabels: Boolean,
    mode: {
      type: String,
      default: 'rgba',
      validator: v => Object.keys(modes).includes(v)
    },
    modes: {
      type: Array,
      default: () => Object.keys(modes),
      validator: v => Array.isArray(v) && v.every(m => Object.keys(modes).includes(m))
    },
    showSwatches: Boolean,
    readonly: Boolean,
    swatches: Array,
    swatchesMaxHeight: {
      type: [Number, String],
      default: 150
    },
    modelValue: {
      type: [Object, String]
    },
    ...makeVPickerProps({
      hideHeader: true
    }),
    ...pick(makeVColorPickerPreviewProps(), ['hideEyeDropper', 'eyeDropperIcon'])
  }, 'VColorPicker');
  const VColorPicker = defineComponent({
    name: 'VColorPicker',
    props: makeVColorPickerProps(),
    emits: {
      'update:modelValue': color => true,
      'update:mode': mode => true
    },
    setup(props, {
      slots
    }) {
      const mode = useProxiedModel(props, 'mode');
      const hue = vue.ref(null);
      const model = useProxiedModel(props, 'modelValue', undefined, v => {
        if (v == null || v === '') return null;
        let c;
        try {
          c = RGBtoHSV(parseColor(v));
        } catch (err) {
          consoleWarn(err);
          return null;
        }
        return c;
      }, v => {
        if (!v) return null;
        return extractColor(v, props.modelValue);
      });
      const currentColor = vue.computed(() => {
        return model.value ? {
          ...model.value,
          h: hue.value ?? model.value.h
        } : null;
      });
      const {
        rtlClasses
      } = useRtl();
      let externalChange = true;
      vue.watch(model, v => {
        if (!externalChange) {
          // prevent hue shift from rgb conversion inaccuracy
          externalChange = true;
          return;
        }
        if (!v) return;
        hue.value = v.h;
      }, {
        immediate: true
      });
      const updateColor = hsva => {
        externalChange = false;
        hue.value = hsva.h;
        model.value = hsva;
      };
      vue.onBeforeMount(() => {
        if (!props.modes.includes(mode.value)) mode.value = props.modes[0];
      });
      provideDefaults({
        VSlider: {
          color: null,
          trackColor: null,
          trackFillColor: null
        }
      });
      useRender(() => {
        const pickerProps = VPicker.filterProps(props);
        return vue.createVNode(VPicker, vue.mergeProps(pickerProps, {
          "class": ['v-color-picker', rtlClasses.value, props.class],
          "style": [{
            '--v-color-picker-color-hsv': HSVtoCSS({
              ...(currentColor.value ?? nullColor),
              a: 1
            })
          }, props.style]
        }), {
          ...slots,
          default: () => vue.createElementVNode(vue.Fragment, null, [!props.hideCanvas && vue.createVNode(VColorPickerCanvas, {
            "key": "canvas",
            "color": currentColor.value,
            "onUpdate:color": updateColor,
            "disabled": props.disabled,
            "readonly": props.readonly,
            "dotSize": props.dotSize,
            "width": props.width,
            "height": props.canvasHeight
          }, null), (!props.hideSliders || !props.hideInputs) && vue.createElementVNode("div", {
            "key": "controls",
            "class": "v-color-picker__controls"
          }, [!props.hideSliders && vue.createVNode(VColorPickerPreview, {
            "key": "preview",
            "color": currentColor.value,
            "onUpdate:color": updateColor,
            "hideAlpha": !mode.value.endsWith('a'),
            "disabled": props.disabled,
            "readonly": props.readonly,
            "hideEyeDropper": props.hideEyeDropper,
            "eyeDropperIcon": props.eyeDropperIcon
          }, null), !props.hideInputs && vue.createVNode(VColorPickerEdit, {
            "key": "edit",
            "modes": props.modes,
            "mode": mode.value,
            "onUpdate:mode": m => mode.value = m,
            "color": currentColor.value,
            "onUpdate:color": updateColor,
            "disabled": props.disabled,
            "readonly": props.readonly,
            "hideInputLabels": props.hideInputLabels
          }, null)]), props.showSwatches && vue.createVNode(VColorPickerSwatches, {
            "key": "swatches",
            "color": currentColor.value,
            "onUpdate:color": updateColor,
            "maxHeight": props.swatchesMaxHeight,
            "swatches": props.swatches,
            "disabled": props.disabled,
            "readonly": props.readonly
          }, null)])
        });
      });
      return {};
    }
  });

  // Types

  const makeVConfirmEditProps = propsFactory({
    modelValue: null,
    color: String,
    cancelText: {
      type: String,
      default: '$vuetify.confirmEdit.cancel'
    },
    okText: {
      type: String,
      default: '$vuetify.confirmEdit.ok'
    },
    disabled: {
      type: [Boolean, Array],
      default: undefined
    },
    hideActions: Boolean
  }, 'VConfirmEdit');
  const VConfirmEdit = genericComponent()({
    name: 'VConfirmEdit',
    props: makeVConfirmEditProps(),
    emits: {
      cancel: () => true,
      save: value => true,
      'update:modelValue': value => true
    },
    setup(props, {
      emit,
      slots
    }) {
      const model = useProxiedModel(props, 'modelValue');
      const internalModel = vue.ref();
      vue.watchEffect(() => {
        internalModel.value = structuredClone(deepToRaw(model.value));
      });
      const {
        t
      } = useLocale();
      const isPristine = vue.computed(() => {
        return deepEqual(model.value, internalModel.value);
      });
      function isActionDisabled(action) {
        if (typeof props.disabled === 'boolean') {
          return props.disabled;
        }
        if (Array.isArray(props.disabled)) {
          return props.disabled.includes(action);
        }
        return isPristine.value;
      }
      const isSaveDisabled = vue.computed(() => isActionDisabled('save'));
      const isCancelDisabled = vue.computed(() => isActionDisabled('cancel'));
      function save() {
        model.value = internalModel.value;
        emit('save', internalModel.value);
      }
      function cancel() {
        internalModel.value = structuredClone(deepToRaw(model.value));
        emit('cancel');
      }
      function actions(actionsProps) {
        return vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VBtn, vue.mergeProps({
          "disabled": isCancelDisabled.value,
          "variant": "text",
          "color": props.color,
          "onClick": cancel,
          "text": t(props.cancelText)
        }, actionsProps), null), vue.createVNode(VBtn, vue.mergeProps({
          "disabled": isSaveDisabled.value,
          "variant": "text",
          "color": props.color,
          "onClick": save,
          "text": t(props.okText)
        }, actionsProps), null)]);
      }
      let actionsUsed = false;
      useRender(() => {
        return vue.createElementVNode(vue.Fragment, null, [slots.default?.({
          model: internalModel,
          save,
          cancel,
          isPristine: isPristine.value,
          get actions() {
            actionsUsed = true;
            return actions;
          }
        }), !props.hideActions && !actionsUsed && actions()]);
      });
      return {
        save,
        cancel,
        isPristine
      };
    }
  });

  // Types

  const availablePipLocations = ['prepend', 'prepend-inner', 'append', 'append-inner'];
  const makeVColorInputProps = propsFactory({
    hidePip: Boolean,
    colorPip: Boolean,
    menuProps: Object,
    pipIcon: {
      type: String,
      default: '$color'
    },
    pipLocation: {
      type: String,
      default: 'prepend',
      validator: v => availablePipLocations.includes(v)
    },
    pipVariant: {
      type: String,
      default: 'text'
    },
    pickerProps: Object,
    ...makeFocusProps(),
    ...makeVConfirmEditProps(),
    ...makeVTextFieldProps(),
    ...omit(makeVColorPickerProps(), ['location', 'height', 'minHeight', 'maxHeight'])
  }, 'VColorInput');
  const VColorInput = genericComponent()({
    name: 'VColorInput',
    props: makeVColorInputProps(),
    emits: {
      'update:modelValue': val => true
    },
    setup(props, {
      slots
    }) {
      const model = useProxiedModel(props, 'modelValue');
      const menu = vue.shallowRef(false);
      const isFocused = vue.shallowRef(props.focused);
      const isInteractive = vue.computed(() => !props.disabled && !props.readonly);
      const display = vue.computed(() => model.value || null);
      function onKeydown(e) {
        if (e.key !== 'Enter') return;
        if (!menu.value || !isFocused.value) {
          menu.value = true;
          return;
        }
        const target = e.target;
        model.value = target.value;
      }
      function onClick(e) {
        e.preventDefault();
        e.stopPropagation();
        menu.value = true;
      }
      function onSave() {
        menu.value = false;
      }
      function onCancel() {
        menu.value = false;
      }
      useRender(() => {
        const confirmEditProps = VConfirmEdit.filterProps(props);
        const colorPickerProps = {
          ...VColorPicker.filterProps(omit(props, ['active', 'bgColor', 'color', 'rounded', 'maxWidth', 'minWidth', 'width'])),
          ...props.pickerProps
        };
        const textFieldProps = VTextField.filterProps(props);
        const slotWithPip = props.hidePip ? undefined : {
          [props.pipLocation]: arg => vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VAvatar, {
            "class": "v-color-input__pip",
            "color": props.colorPip ? model.value : undefined,
            "variant": props.pipVariant,
            "icon": props.pipIcon
          }, null), slots[props.pipLocation]?.(arg)])
        };
        return vue.createVNode(VTextField, vue.mergeProps(textFieldProps, {
          "class": ['v-color-input', props.class],
          "style": props.style,
          "modelValue": display.value,
          "onKeydown": isInteractive.value ? onKeydown : undefined,
          "focused": menu.value || isFocused.value,
          "onClick:control": !props.disabled ? onClick : undefined,
          "onClick:prependInner": !props.disabled ? onClick : undefined,
          "onUpdate:focused": event => isFocused.value = event,
          "onClick:appendInner": !props.disabled ? onClick : undefined,
          "onUpdate:modelValue": val => {
            model.value = val;
          }
        }), {
          ...slots,
          ...slotWithPip,
          default: () => vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VMenu, vue.mergeProps({
            "modelValue": menu.value,
            "onUpdate:modelValue": $event => menu.value = $event,
            "activator": "parent",
            "minWidth": "0",
            "closeOnContentClick": false,
            "openOnClick": false
          }, props.menuProps), {
            default: () => [vue.createVNode(VConfirmEdit, vue.mergeProps(confirmEditProps, {
              "modelValue": model.value,
              "onUpdate:modelValue": $event => model.value = $event,
              "onSave": onSave,
              "onCancel": onCancel
            }), {
              default: ({
                actions,
                model: proxyModel,
                save,
                cancel,
                isPristine
              }) => {
                function onUpdateModel(value) {
                  if (!props.hideActions) {
                    proxyModel.value = value;
                  } else {
                    model.value = value;
                  }
                }
                return vue.createVNode(VColorPicker, vue.mergeProps(colorPickerProps, {
                  "modelValue": props.hideActions ? model.value : proxyModel.value,
                  "onUpdate:modelValue": value => onUpdateModel(value)
                }), {
                  actions: !props.hideActions ? () => slots.actions?.({
                    save,
                    cancel,
                    isPristine
                  }) ?? actions() : undefined
                });
              }
            })]
          }), slots.default?.()])
        });
      });
    }
  });

  // Types

  const makeVComboboxProps = propsFactory({
    alwaysFilter: Boolean,
    autoSelectFirst: {
      type: [Boolean, String]
    },
    clearOnSelect: {
      type: Boolean,
      default: true
    },
    delimiters: Array,
    ...makeFilterProps({
      filterKeys: ['title']
    }),
    ...makeSelectProps({
      hideNoData: true,
      returnObject: true
    }),
    ...omit(makeVTextFieldProps({
      modelValue: null,
      role: 'combobox'
    }), ['validationValue', 'dirty'])
  }, 'VCombobox');
  const VCombobox = genericComponent()({
    name: 'VCombobox',
    props: makeVComboboxProps(),
    emits: {
      'update:focused': focused => true,
      'update:modelValue': value => true,
      'update:search': value => true,
      'update:menu': value => true
    },
    setup(props, {
      emit,
      slots
    }) {
      const {
        t
      } = useLocale();
      const vTextFieldRef = vue.ref();
      const isFocused = vue.shallowRef(false);
      const isPristine = vue.shallowRef(true);
      const listHasFocus = vue.shallowRef(false);
      const vMenuRef = vue.ref();
      const vVirtualScrollRef = vue.ref();
      const selectionIndex = vue.shallowRef(-1);
      let cleared = false;
      const {
        items,
        transformIn,
        transformOut
      } = useItems(props);
      const {
        textColorClasses,
        textColorStyles
      } = useTextColor(() => vTextFieldRef.value?.color);
      const {
        InputIcon
      } = useInputIcon(props);
      const model = useProxiedModel(props, 'modelValue', [], v => transformIn(wrapInArray(v)), v => {
        const transformed = transformOut(v);
        return props.multiple ? transformed : transformed[0] ?? null;
      });
      const form = useForm(props);
      const closableChips = vue.toRef(() => props.closableChips && !form.isReadonly.value && !form.isDisabled.value);
      const hasChips = vue.computed(() => !!(props.chips || slots.chip));
      const hasSelectionSlot = vue.computed(() => hasChips.value || !!slots.selection);
      const _search = vue.shallowRef(!props.multiple && !hasSelectionSlot.value ? model.value[0]?.title ?? '' : '');
      const _searchLock = vue.shallowRef(null);
      const search = vue.computed({
        get: () => {
          return _search.value;
        },
        set: async val => {
          _search.value = val ?? '';
          if (val === null || val === '' && !props.multiple && !hasSelectionSlot.value) {
            model.value = [];
          } else if (!props.multiple && !hasSelectionSlot.value) {
            model.value = [transformItem$3(props, val)];
            vue.nextTick(() => vVirtualScrollRef.value?.scrollToIndex(0));
          }
          if (val && props.multiple && props.delimiters?.length) {
            const values = splitByDelimiters(val);
            if (values.length > 1) {
              selectMultiple(values);
              _search.value = '';
            }
          }
          if (!val) selectionIndex.value = -1;
          isPristine.value = !val;
        }
      });
      const counterValue = vue.computed(() => {
        return typeof props.counterValue === 'function' ? props.counterValue(model.value) : typeof props.counterValue === 'number' ? props.counterValue : props.multiple ? model.value.length : search.value.length;
      });
      const {
        filteredItems,
        getMatches
      } = useFilter(props, items, () => _searchLock.value ?? (props.alwaysFilter || !isPristine.value ? search.value : ''));
      const displayItems = vue.computed(() => {
        if (props.hideSelected && _searchLock.value === null) {
          return filteredItems.value.filter(filteredItem => !model.value.some(s => s.value === filteredItem.value));
        }
        return filteredItems.value;
      });
      const menuDisabled = vue.computed(() => props.hideNoData && !displayItems.value.length || form.isReadonly.value || form.isDisabled.value);
      const _menu = useProxiedModel(props, 'menu');
      const menu = vue.computed({
        get: () => _menu.value,
        set: v => {
          if (_menu.value && !v && vMenuRef.value?.ΨopenChildren.size) return;
          if (v && menuDisabled.value) return;
          _menu.value = v;
        }
      });
      const {
        menuId,
        ariaExpanded,
        ariaControls
      } = useMenuActivator(props, menu);
      vue.watch(_search, value => {
        if (cleared) {
          // wait for clear to finish, VTextField sets _search to null
          // then search computed triggers and updates _search to ''
          vue.nextTick(() => cleared = false);
        } else if (isFocused.value && !menu.value) {
          menu.value = true;
        }
        emit('update:search', value);
      });
      vue.watch(model, value => {
        if (!props.multiple && !hasSelectionSlot.value) {
          _search.value = value[0]?.title ?? '';
        }
      });
      const selectedValues = vue.computed(() => model.value.map(selection => selection.value));
      const firstSelectableItem = vue.computed(() => displayItems.value.find(x => x.type === 'item' && !x.props.disabled));
      const highlightFirst = vue.computed(() => {
        const selectFirst = props.autoSelectFirst === true || props.autoSelectFirst === 'exact' && search.value === firstSelectableItem.value?.title;
        return selectFirst && displayItems.value.length > 0 && !isPristine.value && !listHasFocus.value;
      });
      const listRef = vue.ref();
      const headerRef = vue.ref();
      const footerRef = vue.ref();
      const listEvents = useScrolling(listRef, vTextFieldRef);
      const repairOrphanedFocus = useFocusRepair(menu, () => vMenuRef.value?.contentEl, () => vTextFieldRef.value?.controlRef);
      const {
        onTabKeydown
      } = useFocusGroups({
        groups: [{
          type: 'element',
          contentRef: headerRef
        }, {
          type: 'list',
          contentRef: listRef,
          displayItemsCount: () => displayItems.value.length
        }, {
          type: 'element',
          contentRef: footerRef
        }],
        onLeave: () => {
          menu.value = false;
          vTextFieldRef.value?.focus();
        }
      });
      function onClear(e) {
        cleared = true;
        vue.nextTick(() => cleared = false);
        if (props.openOnClear) {
          menu.value = true;
        }
      }
      function onMousedownControl() {
        if (menuDisabled.value) return;
        menu.value = true;
      }
      function onMousedownMenuIcon(e) {
        if (menuDisabled.value) return;
        if (isFocused.value) {
          e.preventDefault();
          e.stopPropagation();
        }
        menu.value = !menu.value;
      }
      function onMenuKeydown(e) {
        if (e.key === 'Tab') {
          onTabKeydown(e);
        }
        if (listRef.value?.$el.contains(e.target) && (checkPrintable(e) || e.key === 'Backspace')) {
          vTextFieldRef.value?.focus();
        }
      }

      // eslint-disable-next-line complexity
      function onKeydown(e) {
        if (isComposingIgnoreKey(e) || form.isReadonly.value) return;
        const selectionStart = vTextFieldRef.value?.selectionStart;
        const length = model.value.length;
        if (['Enter', 'ArrowDown', 'ArrowUp'].includes(e.key)) {
          e.preventDefault();
        }
        if (['Enter', 'ArrowDown'].includes(e.key)) {
          menu.value = true;
        }
        if (['Escape'].includes(e.key)) {
          menu.value = false;
        }
        if (highlightFirst.value && ['Enter', 'Tab'].includes(e.key) && firstSelectableItem.value && !model.value.some(({
          value
        }) => value === firstSelectableItem.value.value)) {
          select(firstSelectableItem.value);
        }
        if (e.key === 'ArrowDown' && highlightFirst.value) {
          listRef.value?.focus('next');
        }
        if (e.key === 'Enter' && search.value) {
          select(transformItem$3(props, search.value), true, true);
          if (hasSelectionSlot.value) _search.value = '';
        }
        if (['Backspace', 'Delete'].includes(e.key)) {
          if (!props.multiple && hasSelectionSlot.value && model.value.length > 0 && !search.value) return select(model.value[0], false);
          if (~selectionIndex.value) {
            e.preventDefault();
            const originalSelectionIndex = selectionIndex.value;
            select(model.value[selectionIndex.value], false);
            selectionIndex.value = originalSelectionIndex >= length - 1 ? length - 2 : originalSelectionIndex;
          } else if (e.key === 'Backspace' && !search.value) {
            selectionIndex.value = length - 1;
          }
          return;
        }
        if (!props.multiple) return;
        if (e.key === 'ArrowLeft') {
          if (selectionIndex.value < 0 && selectionStart && selectionStart > 0) return;
          const prev = selectionIndex.value > -1 ? selectionIndex.value - 1 : length - 1;
          if (model.value[prev]) {
            selectionIndex.value = prev;
          } else {
            selectionIndex.value = -1;
            vTextFieldRef.value?.setSelectionRange(search.value.length, search.value.length);
          }
        } else if (e.key === 'ArrowRight') {
          if (selectionIndex.value < 0) return;
          const next = selectionIndex.value + 1;
          if (model.value[next]) {
            selectionIndex.value = next;
          } else {
            selectionIndex.value = -1;
            vTextFieldRef.value?.setSelectionRange(0, 0);
          }
        } else if (~selectionIndex.value && checkPrintable(e)) {
          selectionIndex.value = -1;
        }
      }
      function onPaste(e) {
        const clipboardText = e?.clipboardData?.getData('Text') ?? '';
        const values = splitByDelimiters(clipboardText);
        if (values.length > 1 && props.multiple) {
          e.preventDefault();
          selectMultiple(values);
        }
      }
      function onAfterEnter() {
        if (props.eager) {
          vVirtualScrollRef.value?.calculateVisibleItems();
        }
      }
      function onAfterLeave() {
        if (isFocused.value) {
          if (vMenuRef.value?.contentEl?._clickOutside?.lastMousedownWasOutside) {
            isFocused.value = false;
          } else {
            vTextFieldRef.value?.focus();
          }
        }
        isPristine.value = true;
        _searchLock.value = null;
      }
      /** @param set - null means toggle */
      function select(item, set = true, keepMenu = false) {
        if (!item || item.props.disabled) return;
        if (props.multiple) {
          const index = model.value.findIndex(selection => (props.valueComparator || deepEqual)(selection.value, item.value));
          const add = set == null ? !~index : set;
          if (~index) {
            const value = add ? [...model.value, item] : [...model.value];
            value.splice(index, 1);
            model.value = value;
          } else if (add) {
            model.value = [...model.value, item];
          }
          if (props.clearOnSelect) {
            search.value = '';
          }
        } else {
          const add = set !== false;
          model.value = add ? [item] : [];
          if ((!isPristine.value || props.alwaysFilter) && _search.value) {
            _searchLock.value = _search.value;
          }
          _search.value = add && !hasSelectionSlot.value ? item.title : '';

          // watch for search watcher to trigger
          vue.nextTick(() => {
            menu.value = keepMenu;
            isPristine.value = true;
          });
        }
      }
      function splitByDelimiters(val) {
        const effectiveDelimiters = ['\n', ...(props.delimiters ?? [])];
        const signsToMatch = effectiveDelimiters.map(escapeForRegex).join('|');
        return val.split(new RegExp(`(?:${signsToMatch})+`));
      }
      async function selectMultiple(values) {
        for (let value of values) {
          value = value.trim();
          if (value) {
            select(transformItem$3(props, value));
            await vue.nextTick();
          }
        }
      }
      function onFocusin(e) {
        isFocused.value = true;
        setTimeout(() => {
          listHasFocus.value = true;
        });
      }
      function onFocusout(e) {
        listHasFocus.value = false;
        if (!vTextFieldRef.value?.$el.contains(e.relatedTarget)) {
          if (repairOrphanedFocus(e)) return;
          isFocused.value = false;
        }
      }
      let mousedownInsideContentAt = 0;
      function onMousedownContent() {
        mousedownInsideContentAt = performance.now();
      }
      function onBlur(e) {
        const next = e.relatedTarget;
        const menuContent = vMenuRef.value?.contentEl;
        if (menuContent?.contains(next) || !next && performance.now() - mousedownInsideContentAt < 10) {
          isFocused.value = true;
        }
      }
      vue.watch(isFocused, (val, oldVal) => {
        if (val || val === oldVal) return;
        selectionIndex.value = -1;
        menu.value = false;
        if (search.value) {
          if (props.multiple) {
            select(transformItem$3(props, search.value));
            return;
          }
          if (!hasSelectionSlot.value) return;
          if (model.value.some(({
            title
          }) => title === search.value)) {
            _search.value = '';
          } else {
            select(transformItem$3(props, search.value));
          }
        }
      });
      vue.watch(menu, val => {
        if (!props.hideSelected && val && model.value.length && isPristine.value) {
          const index = displayItems.value.findIndex(item => model.value.some(s => (props.valueComparator || deepEqual)(s.value, item.value)));
          IN_BROWSER && !props.noAutoScroll && window.requestAnimationFrame(() => {
            index >= 0 && vVirtualScrollRef.value?.scrollToIndex(index);
          });
        }
        if (val) _searchLock.value = null;
      });
      vue.watch(items, (newVal, oldVal) => {
        if (menu.value) return;
        if (isFocused.value && !oldVal.length && newVal.length) {
          menu.value = true;
        }
      });
      useRender(() => {
        const hasList = !!(!props.hideNoData || displayItems.value.length || slots['prepend-item'] || slots['append-item'] || slots['no-data']);
        const isDirty = model.value.length > 0;
        const textFieldProps = VTextField.filterProps(props);
        const menuSlotProps = {
          search,
          filteredItems: filteredItems.value
        };
        return vue.createVNode(VTextField, vue.mergeProps({
          "ref": vTextFieldRef
        }, textFieldProps, {
          "modelValue": search.value,
          "onUpdate:modelValue": $event => search.value = $event,
          "focused": isFocused.value,
          "onUpdate:focused": $event => isFocused.value = $event,
          "validationValue": model.externalValue,
          "counterValue": counterValue.value,
          "dirty": isDirty,
          "class": ['v-combobox', {
            'v-combobox--active-menu': menu.value,
            'v-combobox--chips': !!props.chips,
            'v-combobox--selection-slot': !!hasSelectionSlot.value,
            'v-combobox--selecting-index': selectionIndex.value > -1,
            [`v-combobox--${props.multiple ? 'multiple' : 'single'}`]: true
          }, props.class],
          "style": props.style,
          "readonly": form.isReadonly.value,
          "placeholder": isDirty ? undefined : props.placeholder,
          "onClick:clear": onClear,
          "onMousedown:control": onMousedownControl,
          "onKeydown": onKeydown,
          "onPaste": onPaste,
          "onBlur": onBlur,
          "aria-expanded": ariaExpanded.value,
          "aria-controls": ariaControls.value
        }), {
          ...slots,
          default: ({
            id
          }) => vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VMenu, vue.mergeProps({
            "id": menuId.value,
            "ref": vMenuRef,
            "modelValue": menu.value,
            "onUpdate:modelValue": $event => menu.value = $event,
            "activator": "parent",
            "disabled": menuDisabled.value,
            "eager": props.eager,
            "maxHeight": 310,
            "openOnClick": false,
            "closeOnContentClick": false,
            "onAfterEnter": onAfterEnter,
            "onAfterLeave": onAfterLeave
          }, props.menuProps, {
            "contentClass": ['v-combobox__content', props.menuProps?.contentClass]
          }), {
            default: () => [vue.createVNode(VSheet, {
              "elevation": props.menuElevation,
              "onFocusin": onFocusin,
              "onKeydown": onMenuKeydown,
              "onMousedown": onMousedownContent
            }, {
              default: () => [slots['menu-header'] && vue.createElementVNode("header", {
                "ref": headerRef
              }, [slots['menu-header'](menuSlotProps)]), hasList && vue.createVNode(VList, vue.mergeProps({
                "key": "combobox-list",
                "ref": listRef,
                "filterable": true,
                "selected": selectedValues.value,
                "selectStrategy": props.multiple ? 'independent' : 'single-independent',
                "onMousedown": e => e.preventDefault(),
                "selectable": !!displayItems.value.length,
                "onFocusout": onFocusout,
                "tabindex": "-1",
                "aria-live": "polite",
                "aria-labelledby": `${id.value}-label`,
                "aria-multiselectable": props.multiple,
                "color": props.itemColor ?? props.color
              }, listEvents, props.listProps), {
                default: () => [slots['prepend-item']?.(), !displayItems.value.length && !props.hideNoData && (slots['no-data']?.() ?? vue.createVNode(VListItem, {
                  "key": "no-data",
                  "title": t(props.noDataText)
                }, null)), vue.createVNode(VVirtualScroll, {
                  "ref": vVirtualScrollRef,
                  "renderless": true,
                  "items": displayItems.value,
                  "itemKey": "value"
                }, {
                  default: ({
                    item,
                    index,
                    itemRef
                  }) => {
                    const camelizedProps = camelizeProps(item.props);
                    const itemProps = vue.mergeProps(item.props, {
                      ref: itemRef,
                      key: item.value,
                      active: highlightFirst.value && item === firstSelectableItem.value ? true : undefined,
                      onClick: () => select(item, null),
                      'aria-posinset': index + 1,
                      'aria-setsize': displayItems.value.length
                    });
                    if (item.type === 'divider') {
                      return slots.divider?.({
                        props: item.raw,
                        index
                      }) ?? vue.createVNode(VDivider, vue.mergeProps(item.props, {
                        "ref": itemRef,
                        "key": `divider-${index}`
                      }), null);
                    }
                    if (item.type === 'subheader') {
                      return slots.subheader?.({
                        props: item.raw,
                        index
                      }) ?? vue.createVNode(VListSubheader, vue.mergeProps(item.props, {
                        "ref": itemRef,
                        "key": `subheader-${index}`
                      }), null);
                    }
                    return slots.item?.({
                      item: item.raw,
                      internalItem: item,
                      index,
                      props: itemProps
                    }) ?? vue.createVNode(VListItem, vue.mergeProps(itemProps, {
                      "role": "option"
                    }), {
                      prepend: ({
                        isSelected
                      }) => vue.createElementVNode(vue.Fragment, null, [props.multiple && !props.hideSelected ? vue.createVNode(VCheckboxBtn, {
                        "key": item.value,
                        "modelValue": isSelected,
                        "ripple": false,
                        "tabindex": "-1",
                        "aria-hidden": true,
                        "onClick": event => event.preventDefault()
                      }, null) : undefined, camelizedProps.prependAvatar && vue.createVNode(VAvatar, {
                        "image": camelizedProps.prependAvatar
                      }, null), camelizedProps.prependIcon && vue.createVNode(VIcon, {
                        "icon": camelizedProps.prependIcon
                      }, null)]),
                      title: () => {
                        return isPristine.value ? item.title : vue.createVNode(VHighlight, {
                          "text": item.title,
                          "matches": getMatches(item)?.title,
                          "markClass": "v-combobox__mask",
                          "matchAll": true,
                          "ignoreCase": true
                        }, null);
                      }
                    });
                  }
                }), slots['append-item']?.()]
              }), slots['menu-footer'] && vue.createElementVNode("footer", {
                "ref": footerRef
              }, [slots['menu-footer'](menuSlotProps)])]
            })]
          }), model.value.map((item, index) => {
            function onChipClose(e) {
              e.stopPropagation();
              e.preventDefault();
              select(item, false);
            }
            const slotProps = vue.mergeProps(VChip.filterProps(item.props), {
              'onClick:close': onChipClose,
              onKeydown(e) {
                if (e.key !== 'Enter' && e.key !== ' ') return;
                e.preventDefault();
                e.stopPropagation();
                onChipClose(e);
              },
              onMousedown(e) {
                e.preventDefault();
                e.stopPropagation();
              },
              modelValue: true,
              'onUpdate:modelValue': undefined
            });
            const hasSlot = hasChips.value ? !!slots.chip : !!slots.selection;
            const slotContent = hasSlot ? ensureValidVNode(hasChips.value ? slots.chip({
              item: item.raw,
              internalItem: item,
              index,
              props: slotProps
            }) : slots.selection({
              item: item.raw,
              internalItem: item,
              index
            })) : undefined;
            if (hasSlot && !slotContent) return undefined;
            return vue.createElementVNode("div", {
              "key": item.value,
              "class": vue.normalizeClass(['v-combobox__selection', index === selectionIndex.value && ['v-combobox__selection--selected', textColorClasses.value]]),
              "style": vue.normalizeStyle(index === selectionIndex.value ? textColorStyles.value : {})
            }, [hasChips.value ? !slots.chip ? vue.createVNode(VChip, vue.mergeProps({
              "key": "chip",
              "closable": closableChips.value,
              "size": "small",
              "text": item.title,
              "disabled": item.props.disabled
            }, slotProps), null) : vue.createVNode(VDefaultsProvider, {
              "key": "chip-defaults",
              "defaults": {
                VChip: {
                  closable: closableChips.value,
                  size: 'small',
                  text: item.title
                }
              }
            }, {
              default: () => [slotContent]
            }) : slotContent ?? vue.createElementVNode("span", {
              "class": "v-combobox__selection-text"
            }, [item.title, props.multiple && index < model.value.length - 1 && vue.createElementVNode("span", {
              "class": "v-combobox__selection-comma"
            }, [vue.createTextVNode(",")])])]);
          })]),
          'append-inner': (...args) => vue.createElementVNode(vue.Fragment, null, [slots['append-inner']?.(...args), (!props.hideNoData || props.items.length) && props.menuIcon ? vue.createVNode(VIcon, {
            "class": "v-combobox__menu-icon",
            "color": vTextFieldRef.value?.fieldIconColor,
            "icon": props.menuIcon,
            "onMousedown": onMousedownMenuIcon,
            "onClick": noop,
            "aria-hidden": true,
            "tabindex": "-1"
          }, null) : undefined, props.appendInnerIcon && vue.createVNode(InputIcon, {
            "key": "append-icon",
            "name": "appendInner",
            "color": args[0].iconColor.value
          }, null)])
        });
      });
      return forwardRefs({
        isFocused,
        isPristine,
        menu,
        search,
        selectionIndex,
        filteredItems,
        select
      }, vTextFieldRef);
    }
  });

  // Composables

  // Types

  const makeDataTableExpandProps = propsFactory({
    expandOnClick: Boolean,
    showExpand: Boolean,
    expanded: {
      type: Array,
      default: () => []
    },
    expandStrategy: {
      type: String,
      default: 'multiple'
    }
  }, 'DataTable-expand');
  const VDataTableExpandedKey = Symbol.for('vuetify:datatable:expanded');
  function provideExpanded(props) {
    const expandOnClick = vue.toRef(() => props.expandOnClick);
    const expanded = useProxiedModel(props, 'expanded', props.expanded, v => {
      return new Set(v);
    }, v => {
      return [...v.values()];
    });
    function expand(item, value) {
      const rawValue = vue.toRaw(item.value);
      const newExpanded = value && props.expandStrategy === 'single' ? new Set() : new Set(expanded.value);
      if (!value) {
        const existing = [...expanded.value].find(x => vue.toRaw(x) === rawValue);
        newExpanded.delete(existing);
      } else {
        newExpanded.add(item.value);
      }
      expanded.value = newExpanded;
    }
    function isExpanded(item) {
      const rawValue = vue.toRaw(item.value);
      return [...expanded.value].some(x => vue.toRaw(x) === rawValue);
    }
    function toggleExpand(item) {
      expand(item, !isExpanded(item));
    }
    const data = {
      expand,
      expanded,
      expandOnClick,
      isExpanded,
      toggleExpand
    };
    vue.provide(VDataTableExpandedKey, data);
    return data;
  }
  function useExpanded() {
    const data = vue.inject(VDataTableExpandedKey);
    if (!data) throw new Error('foo');
    return data;
  }

  // Composables

  // Types

  const makeDataTableGroupProps = propsFactory({
    groupBy: {
      type: Array,
      default: () => []
    },
    opened: {
      type: Array,
      default: () => []
    },
    openAll: Boolean,
    groupKey: Function
  }, 'DataTable-group');
  const VDataTableGroupSymbol = Symbol.for('vuetify:data-table-group');
  function createGroupBy(props) {
    const groupBy = useProxiedModel(props, 'groupBy');
    const opened = useProxiedModel(props, 'opened');
    const openAll = vue.toRef(() => props.openAll);
    const groupKey = vue.toRef(() => props.groupKey);
    return {
      groupBy,
      opened,
      openAll,
      groupKey
    };
  }
  function provideGroupBy(options) {
    const {
      disableSort,
      groupBy,
      sortBy
    } = options;
    const openedModel = options.opened ?? vue.ref([]);

    // Keep a Set mirror for O(1) lookups; the v-model carries the string[] form.
    const localOpened = vue.shallowRef(new Set(openedModel.value));
    vue.watch(openedModel, val => {
      localOpened.value = new Set(val);
    });
    const opened = vue.computed({
      get: () => localOpened.value,
      set: v => {
        localOpened.value = v;
        openedModel.value = [...v.values()];
      }
    });
    const sortByWithGroups = vue.computed(() => {
      return groupBy.value.map(val => ({
        ...val,
        order: val.order ?? false
      })).concat(disableSort?.value ? [] : sortBy.value);
    });
    function isGroupOpen(group) {
      return opened.value.has(group.id);
    }
    function toggleGroup(group) {
      const newOpened = new Set(opened.value);
      if (isGroupOpen(group)) newOpened.delete(group.id);else newOpened.add(group.id);
      opened.value = newOpened;
    }
    function extractRows(items) {
      function dive(group) {
        const arr = [];
        for (const item of group.items) {
          if ('type' in item && item.type === 'group') {
            arr.push(...dive(item));
          } else {
            arr.push(item);
          }
        }
        return [...new Set(arr)];
      }
      return dive({
        items});
    }
    const data = {
      sortByWithGroups,
      toggleGroup,
      opened,
      groupBy,
      extractRows,
      isGroupOpen
    };
    vue.provide(VDataTableGroupSymbol, data);
    return data;
  }
  function useGroupBy() {
    const data = vue.inject(VDataTableGroupSymbol);
    if (!data) throw new Error('Missing group!');
    return data;
  }
  function groupItemsByProperty(items, groupBy) {
    if (!items.length) return [];
    const groups = new Map();
    for (const item of items) {
      const value = getObjectValueByPath(item.raw, groupBy);
      if (!groups.has(value)) {
        groups.set(value, []);
      }
      groups.get(value).push(item);
    }
    return groups;
  }
  const defaultGroupId = (key, value, parentKey) => `${parentKey}_${key}_${value}`;
  function groupItems(items, groupBy, groupKey, depth = 0, parentKey = 'root') {
    if (!groupBy.length) return [];
    const groupedItems = groupItemsByProperty(items, groupBy[0]);
    const groups = [];
    const rest = groupBy.slice(1);
    groupedItems.forEach((items, value) => {
      const key = groupBy[0];
      const id = groupKey ? groupKey({
        key,
        value,
        parentKey: depth === 0 ? null : parentKey
      }) : defaultGroupId(key, value, parentKey);
      groups.push({
        depth,
        id,
        key,
        value,
        items: rest.length ? groupItems(items, rest, groupKey, depth + 1, id) : items,
        type: 'group'
      });
    });
    return groups;
  }
  function collectGroupIds(groups) {
    return groups.flatMap(group => [group.id, ...collectGroupIds(group.items.filter(item => 'type' in item && item.type === 'group'))]);
  }
  function useOpenAllGroups(opened, openAll, items, groupBy, groupKey) {
    const allIds = vue.computed(() => {
      if (!vue.toValue(openAll) || !groupBy.value.length) return new Set();
      return new Set(collectGroupIds(groupItems(vue.toValue(items), groupBy.value.map(group => group.key), vue.toValue(groupKey))));
    });
    vue.watch(allIds, (newIds, oldIds) => {
      if (!vue.toValue(openAll)) return;
      const current = new Set(opened.value);
      let changed = false;
      for (const id of newIds) {
        if (!oldIds?.has(id) && !current.has(id)) {
          current.add(id);
          changed = true;
        }
      }
      for (const id of oldIds ?? []) {
        if (!newIds.has(id) && current.has(id)) {
          current.delete(id);
          changed = true;
        }
      }
      if (changed) opened.value = current;
    }, {
      immediate: true
    });
  }
  function flattenItems(items, isOpen, hasSummary) {
    const flatItems = [];
    for (const item of items) {
      // TODO: make this better
      if ('type' in item && item.type === 'group') {
        if (item.value != null) {
          flatItems.push(item);
        }
        if (isOpen(item) || item.value == null) {
          flatItems.push(...flattenItems(item.items, isOpen, hasSummary));
          if (hasSummary) {
            flatItems.push({
              ...item,
              type: 'group-summary'
            });
          }
        }
      } else {
        flatItems.push(item);
      }
    }
    return flatItems;
  }
  function useGroupedItems(items, groupBy, opened, hasSummary, isGroupOpen, groupKey) {
    const groups = vue.computed(() => {
      if (!groupBy.value.length) return [];
      return groupItems(vue.toValue(items), groupBy.value.map(item => item.key), vue.toValue(groupKey));
    });
    const isOpen = isGroupOpen ?? (group => opened.value.has(group.id));
    const flatItems = vue.computed(() => {
      if (!groupBy.value.length) return vue.toValue(items);
      return flattenItems(groups.value, isOpen, vue.toValue(hasSummary));
    });
    return {
      groups,
      flatItems
    };
  }

  // Utilities

  // Types

  function useOptions({
    page,
    itemsPerPage,
    sortBy,
    groupBy,
    search
  }) {
    const vm = getCurrentInstance('VDataTable');
    const options = () => ({
      page: page.value,
      itemsPerPage: itemsPerPage.value,
      sortBy: sortBy.value,
      groupBy: groupBy.value,
      search: search.value
    });
    let oldOptions = null;
    vue.watch(options, value => {
      if (deepEqual(oldOptions, value)) return;

      // Reset page when searching
      if (oldOptions && oldOptions.search !== value.search) {
        page.value = 1;
      }
      vm.emit('update:options', value);
      oldOptions = value;
    }, {
      deep: true,
      immediate: true
    });
  }

  // Composables

  // Types

  const makeDataTablePaginateProps = propsFactory({
    page: {
      type: [Number, String],
      default: 1
    },
    itemsPerPage: {
      type: [Number, String],
      default: 10
    },
    pageBy: {
      type: String,
      default: 'any'
    }
  }, 'DataTable-paginate');
  const VDataTablePaginationSymbol = Symbol.for('vuetify:data-table-pagination');
  function createPagination(props) {
    const page = useProxiedModel(props, 'page', undefined, value => Number(value ?? 1));
    const itemsPerPage = useProxiedModel(props, 'itemsPerPage', undefined, value => Number(value ?? 10));
    return {
      page,
      itemsPerPage
    };
  }
  function providePagination(options) {
    const {
      page,
      itemsPerPage,
      itemsLength
    } = options;
    const startIndex = vue.computed(() => {
      if (itemsPerPage.value === -1) return 0;
      return itemsPerPage.value * (page.value - 1);
    });
    const stopIndex = vue.computed(() => {
      if (itemsPerPage.value === -1) return itemsLength.value;
      return Math.min(itemsLength.value, startIndex.value + itemsPerPage.value);
    });
    const pageCount = vue.computed(() => {
      if (itemsPerPage.value === -1 || itemsLength.value === 0) return 1;
      return Math.ceil(itemsLength.value / itemsPerPage.value);
    });

    // Don't run immediately, items may not have been loaded yet: #17966
    vue.watch([page, pageCount], () => {
      if (page.value > pageCount.value) {
        page.value = pageCount.value;
      }
    });
    function setItemsPerPage(value) {
      itemsPerPage.value = value;
      page.value = 1;
    }
    function nextPage() {
      page.value = clamp(page.value + 1, 1, pageCount.value);
    }
    function prevPage() {
      page.value = clamp(page.value - 1, 1, pageCount.value);
    }
    function setPage(value) {
      page.value = clamp(value, 1, pageCount.value);
    }
    const data = {
      page,
      itemsPerPage,
      startIndex,
      stopIndex,
      pageCount,
      itemsLength,
      nextPage,
      prevPage,
      setPage,
      setItemsPerPage
    };
    vue.provide(VDataTablePaginationSymbol, data);
    return data;
  }
  function usePagination() {
    const data = vue.inject(VDataTablePaginationSymbol);
    if (!data) throw new Error('Missing pagination!');
    return data;
  }
  function usePaginatedItems(options) {
    const vm = getCurrentInstance('usePaginatedItems');
    const {
      items,
      startIndex,
      stopIndex,
      itemsPerPage
    } = options;
    const paginatedItems = vue.computed(() => {
      if (itemsPerPage.value <= 0) return vue.toValue(items);
      return vue.toValue(items).slice(startIndex.value, stopIndex.value);
    });
    vue.watch(paginatedItems, val => {
      vm.emit('update:currentItems', val);
    }, {
      immediate: true
    });
    return {
      paginatedItems
    };
  }
  function usePaginatedGroups(options) {
    const {
      sortedItems,
      paginate,
      group
    } = options;
    const pageBy = vue.toValue(options.pageBy); // TODO: make reactive

    if (pageBy === 'item') {
      const {
        paginatedItems,
        pageCount,
        setItemsPerPage,
        prevPage,
        nextPage,
        setPage
      } = paginate(sortedItems);
      const {
        flatItems: paginatedItemsWithGroups
      } = group(paginatedItems);
      return {
        pageCount,
        setItemsPerPage,
        prevPage,
        nextPage,
        setPage,
        paginatedItems: paginatedItemsWithGroups
      };
    }
    if (pageBy === 'group') {
      const {
        flatItems,
        groups
      } = group(sortedItems);
      const {
        paginatedItems: paginatedGroups,
        pageCount,
        setItemsPerPage,
        prevPage,
        nextPage,
        setPage
      } = paginate(groups);
      const paginatedItemsWithGroups = vue.computed(() => {
        if (!paginatedGroups.value.length) return [];
        const firstGroupId = paginatedGroups.value.at(0).id;
        const lastGroupId = paginatedGroups.value.at(-1).id;
        const start = flatItems.value.findIndex(item => item.type === 'group' && item.id === firstGroupId);
        const lastGroupIndex = flatItems.value.findIndex(item => item.type === 'group' && item.id === lastGroupId);
        const stop = flatItems.value.findIndex((item, i) => i > lastGroupIndex && item.type === 'group' && item.depth === 0);
        return flatItems.value.slice(start, stop === -1 ? undefined : stop);
      });
      return {
        pageCount,
        setItemsPerPage,
        prevPage,
        nextPage,
        setPage,
        paginatedItems: paginatedItemsWithGroups
      };
    }
    if (pageBy === 'any') {
      const {
        flatItems
      } = group(sortedItems);
      const {
        paginatedItems: paginatedItemsWithGroups,
        pageCount,
        setItemsPerPage,
        prevPage,
        nextPage,
        setPage
      } = paginate(flatItems);
      return {
        pageCount,
        setItemsPerPage,
        prevPage,
        nextPage,
        setPage,
        paginatedItems: paginatedItemsWithGroups
      };
    }
    throw new Error(`Unrecognized pagination target ${pageBy}`);
  }

  // Composables

  // Types

  const singleSelectStrategy = {
    showSelectAll: false,
    allSelected: () => [],
    select: ({
      items,
      value
    }) => {
      return new Set(value ? [items[0]?.value] : []);
    },
    selectAll: ({
      selected
    }) => selected
  };
  const pageSelectStrategy = {
    showSelectAll: true,
    allSelected: ({
      currentPage
    }) => currentPage,
    select: ({
      items,
      value,
      selected
    }) => {
      for (const item of items) {
        if (value) selected.add(item.value);else selected.delete(item.value);
      }
      return selected;
    },
    selectAll: ({
      value,
      currentPage,
      selected
    }) => pageSelectStrategy.select({
      items: currentPage,
      value,
      selected
    })
  };
  const allSelectStrategy = {
    showSelectAll: true,
    allSelected: ({
      allItems
    }) => allItems,
    select: ({
      items,
      value,
      selected
    }) => {
      for (const item of items) {
        if (value) selected.add(item.value);else selected.delete(item.value);
      }
      return selected;
    },
    selectAll: ({
      value,
      allItems
    }) => {
      return new Set(value ? allItems.map(item => item.value) : []);
    }
  };
  const makeDataTableSelectProps = propsFactory({
    showSelect: Boolean,
    selectStrategy: {
      type: [String, Object],
      default: 'page'
    },
    modelValue: {
      type: Array,
      default: () => []
    },
    valueComparator: Function
  }, 'DataTable-select');
  const VDataTableSelectionSymbol = Symbol.for('vuetify:data-table-selection');
  function provideSelection(props, {
    allItems,
    currentPage
  }) {
    const selected = useProxiedModel(props, 'modelValue', props.modelValue, v => {
      const customComparator = props.valueComparator;
      if (customComparator) {
        return new Set(wrapInArray(v).map(v => {
          return allItems.value.find(item => customComparator(v, item.value))?.value ?? v;
        }));
      }
      return new Set(wrapInArray(v).map(v => {
        return isPrimitive(v) ? allItems.value.find(item => v === item.value)?.value ?? v : allItems.value.find(item => deepEqual(v, item.value))?.value ?? v;
      }));
    }, v => {
      return [...v.values()];
    });
    const allSelectable = vue.computed(() => allItems.value.filter(item => item.selectable));
    const currentPageSelectable = vue.computed(() => vue.toValue(currentPage).filter(item => item.selectable));
    const selectStrategy = vue.computed(() => {
      if (typeof props.selectStrategy === 'object') return props.selectStrategy;
      switch (props.selectStrategy) {
        case 'single':
          return singleSelectStrategy;
        case 'all':
          return allSelectStrategy;
        case 'page':
        default:
          return pageSelectStrategy;
      }
    });
    const lastSelectedIndex = vue.shallowRef(null);
    function isSelected(items) {
      return wrapInArray(items).every(item => selected.value.has(item.value));
    }
    function isSomeSelected(items) {
      return wrapInArray(items).some(item => selected.value.has(item.value));
    }
    function select(items, value) {
      const newSelected = selectStrategy.value.select({
        items,
        value,
        selected: new Set(selected.value)
      });
      selected.value = newSelected;
    }
    function toggleSelect(item, index, event) {
      const items = [];
      const pageItems = vue.toValue(currentPage);
      index = index ?? pageItems.findIndex(i => i.value === item.value);
      if (props.selectStrategy !== 'single' && event?.shiftKey && lastSelectedIndex.value !== null) {
        const [start, end] = [lastSelectedIndex.value, index].sort((a, b) => a - b);
        items.push(...pageItems.slice(start, end + 1).filter(item => item.selectable));
      } else {
        items.push(item);
        lastSelectedIndex.value = index;
      }
      select(items, !isSelected([item]));
    }
    function selectAll(value) {
      const newSelected = selectStrategy.value.selectAll({
        value,
        allItems: allSelectable.value,
        currentPage: currentPageSelectable.value,
        selected: new Set(selected.value)
      });
      selected.value = newSelected;
    }
    const someSelected = vue.computed(() => selected.value.size > 0);
    const allSelected = vue.computed(() => {
      const items = selectStrategy.value.allSelected({
        allItems: allSelectable.value,
        currentPage: currentPageSelectable.value
      });
      return !!items.length && isSelected(items);
    });
    const showSelectAll = vue.toRef(() => selectStrategy.value.showSelectAll);
    const data = {
      toggleSelect,
      select,
      selectAll,
      isSelected,
      isSomeSelected,
      someSelected,
      allSelected,
      showSelectAll,
      lastSelectedIndex,
      selectStrategy
    };
    vue.provide(VDataTableSelectionSymbol, data);
    return data;
  }
  function useSelection() {
    const data = vue.inject(VDataTableSelectionSymbol);
    if (!data) throw new Error('Missing selection!');
    return data;
  }

  // Composables

  // Types

  const makeDataTableSortProps = propsFactory({
    initialSortOrder: {
      type: String,
      default: 'asc',
      validator: v => !v || ['asc', 'desc'].includes(v)
    },
    sortBy: {
      type: Array,
      default: () => []
    },
    customKeySort: Object,
    multiSort: {
      type: [Boolean, Object],
      default: false
    },
    mustSort: Boolean
  }, 'DataTable-sort');
  const VDataTableSortSymbol = Symbol.for('vuetify:data-table-sort');
  function createSort(props) {
    const initialSortOrder = vue.toRef(() => props.initialSortOrder);
    const sortBy = useProxiedModel(props, 'sortBy');
    const mustSort = vue.toRef(() => props.mustSort);
    const multiSort = vue.toRef(() => props.multiSort);
    return {
      initialSortOrder,
      sortBy,
      multiSort,
      mustSort
    };
  }
  function resolveMultiSort(multiSort, event) {
    if (!isObject(multiSort)) {
      return {
        active: !!multiSort
      };
    }
    const {
      key,
      mode,
      modifier
    } = multiSort;
    const reverseMode = modifier === 'alt' && event?.altKey || modifier === 'shift' && event?.shiftKey;
    return {
      active: !key || event?.ctrlKey || event?.metaKey || false,
      mode: reverseMode ? mode === 'append' ? 'prepend' : 'append' : mode
    };
  }
  function provideSort(options) {
    const {
      initialSortOrder,
      sortBy,
      mustSort,
      multiSort,
      page
    } = options;
    const toggleSort = (column, event, mandatory = false) => {
      if (column.key == null) return;
      let newSortBy = sortBy.value.map(x => ({
        ...x
      })) ?? [];
      const item = newSortBy.find(x => x.key === column.key);
      const initialOrder = initialSortOrder.value;
      const secondaryOrder = initialSortOrder.value === 'desc' ? 'asc' : 'desc';
      if (!item) {
        const {
          active,
          mode
        } = resolveMultiSort(multiSort.value, event);
        if (active) {
          if (mode === 'prepend') {
            newSortBy.unshift({
              key: column.key,
              order: initialOrder
            });
          } else {
            newSortBy.push({
              key: column.key,
              order: initialOrder
            });
          }
        } else {
          newSortBy = [{
            key: column.key,
            order: initialOrder
          }];
        }
      } else if (item.order === secondaryOrder) {
        if (mandatory || mustSort.value && newSortBy.length === 1) {
          item.order = initialSortOrder.value;
        } else {
          newSortBy = newSortBy.filter(x => x.key !== column.key);
        }
      } else {
        item.order = secondaryOrder;
      }
      sortBy.value = newSortBy;
      if (page) page.value = 1;
    };
    function isSorted(column) {
      return !!sortBy.value.find(item => item.key === column.key);
    }
    const data = {
      sortBy,
      toggleSort,
      isSorted
    };
    vue.provide(VDataTableSortSymbol, data);
    return data;
  }
  function useSort() {
    const data = vue.inject(VDataTableSortSymbol);
    if (!data) throw new Error('Missing sort!');
    return data;
  }

  // TODO: abstract into project composable
  function useSortedItems(props, items, sortBy, options) {
    const locale = useLocale();
    const sortedItems = vue.computed(() => {
      if (!sortBy.value.length) return items.value;
      return sortItems(items.value, sortBy.value, locale.current.value, {
        transform: options?.transform,
        sortFunctions: {
          ...props.customKeySort,
          ...options?.sortFunctions?.value
        },
        sortRawFunctions: options?.sortRawFunctions?.value
      });
    });
    return {
      sortedItems
    };
  }
  function sortItems(items, sortByItems, locale, options) {
    const stringCollator = new Intl.Collator(locale, {
      sensitivity: 'accent',
      usage: 'sort'
    });
    const transformedItems = items.map(item => [item, options?.transform ? options.transform(item) : item]);
    return transformedItems.sort((a, b) => {
      for (let i = 0; i < sortByItems.length; i++) {
        let hasCustomResult = false;
        const sortKey = sortByItems[i].key;
        const sortOrder = sortByItems[i].order ?? 'asc';
        if (sortOrder === false) continue;
        let sortA = getObjectValueByPath(a[1], sortKey);
        let sortB = getObjectValueByPath(b[1], sortKey);
        let sortARaw = a[0].raw;
        let sortBRaw = b[0].raw;
        if (sortOrder === 'desc') {
          [sortA, sortB] = [sortB, sortA];
          [sortARaw, sortBRaw] = [sortBRaw, sortARaw];
        }
        if (options?.sortRawFunctions?.[sortKey]) {
          const customResult = options.sortRawFunctions[sortKey](sortARaw, sortBRaw);
          if (customResult == null) continue;
          hasCustomResult = true;
          if (customResult) return customResult;
        }
        if (options?.sortFunctions?.[sortKey]) {
          const customResult = options.sortFunctions[sortKey](sortA, sortB);
          if (customResult == null) continue;
          hasCustomResult = true;
          if (customResult) return customResult;
        }
        if (hasCustomResult) continue;

        // Dates should be compared numerically
        if (sortA instanceof Date && sortB instanceof Date) {
          sortA = sortA.getTime();
          sortB = sortB.getTime();
        }
        [sortA, sortB] = [sortA, sortB].map(s => s != null ? s.toString().toLocaleLowerCase() : s);
        if (sortA !== sortB) {
          if (isEmpty(sortA) && isEmpty(sortB)) return 0;
          if (isEmpty(sortA)) return -1;
          if (isEmpty(sortB)) return 1;
          if (!isNaN(sortA) && !isNaN(sortB)) return Number(sortA) - Number(sortB);
          return stringCollator.compare(sortA, sortB);
        }
      }
      return 0;
    }).map(([item]) => item);
  }

  // Utilities

  // Types

  // Composables
  const makeDataIteratorItemsProps = propsFactory({
    items: {
      type: Array,
      default: () => []
    },
    itemValue: {
      type: [String, Array, Function],
      default: 'id'
    },
    itemSelectable: {
      type: [String, Array, Function],
      default: null
    },
    returnObject: Boolean
  }, 'DataIterator-items');
  function transformItem$1(props, item) {
    const value = props.returnObject ? item : getPropertyFromItem(item, props.itemValue);
    const selectable = getPropertyFromItem(item, props.itemSelectable, true);
    return {
      type: 'item',
      value,
      selectable,
      raw: item
    };
  }
  function transformItems$1(props, items) {
    const array = [];
    for (const item of items) {
      array.push(transformItem$1(props, item));
    }
    return array;
  }
  function useDataIteratorItems(props) {
    const items = vue.computed(() => transformItems$1(props, props.items));
    return {
      items
    };
  }

  // Types

  const makeVDataIteratorProps = propsFactory({
    search: String,
    loading: Boolean,
    itemsLength: [Number, String],
    ...makeComponentProps(),
    ...makeDataIteratorItemsProps(),
    ...makeDataTableSelectProps(),
    ...makeDataTableSortProps(),
    ...makeDataTablePaginateProps({
      itemsPerPage: 5
    }),
    ...makeDataTableExpandProps(),
    ...makeDataTableGroupProps(),
    ...makeFilterProps(),
    ...makeTagProps(),
    ...makeTransitionProps({
      transition: {
        component: VFadeTransition,
        hideOnLeave: true
      }
    })
  }, 'VDataIterator');
  const VDataIterator = genericComponent()({
    name: 'VDataIterator',
    props: makeVDataIteratorProps(),
    emits: {
      'update:modelValue': value => true,
      'update:groupBy': value => true,
      'update:page': value => true,
      'update:itemsPerPage': value => true,
      'update:sortBy': value => true,
      'update:options': value => true,
      'update:expanded': value => true,
      'update:opened': value => true,
      'update:currentItems': value => true
    },
    setup(props, {
      slots
    }) {
      const {
        groupBy,
        opened,
        openAll,
        groupKey
      } = createGroupBy(props);
      const search = vue.toRef(() => props.search);
      const {
        items
      } = useDataIteratorItems(props);
      const {
        filteredItems
      } = useFilter(props, items, search, {
        transform: item => item.raw
      });
      const {
        initialSortOrder,
        sortBy,
        multiSort,
        mustSort
      } = createSort(props);
      const {
        page,
        itemsPerPage
      } = createPagination(props);
      const {
        toggleSort
      } = provideSort({
        initialSortOrder,
        sortBy,
        multiSort,
        mustSort,
        page
      });
      const {
        sortByWithGroups,
        opened: openedGroups,
        extractRows,
        isGroupOpen,
        toggleGroup
      } = provideGroupBy({
        groupBy,
        sortBy,
        opened
      });
      const {
        sortedItems
      } = useSortedItems(props, filteredItems, sortByWithGroups, {
        transform: item => item.raw
      });
      useOpenAllGroups(openedGroups, openAll, sortedItems, groupBy, groupKey);
      const {
        flatItems
      } = useGroupedItems(sortedItems, groupBy, openedGroups, false, isGroupOpen, groupKey);
      const manualPagination = vue.toRef(() => !isEmpty(props.itemsLength));
      const itemsLength = vue.toRef(() => manualPagination.value ? Number(props.itemsLength) : flatItems.value.length);
      const {
        startIndex,
        stopIndex,
        pageCount,
        prevPage,
        nextPage,
        setItemsPerPage,
        setPage
      } = providePagination({
        page,
        itemsPerPage,
        itemsLength
      });
      const paginatedItems = vue.shallowRef([]);
      const currentItems = vue.computed(() => manualPagination.value ? flatItems.value : paginatedItems.value);
      useToggleScope(() => !manualPagination.value, () => {
        const {
          paginatedItems: items
        } = usePaginatedItems({
          items: flatItems,
          startIndex,
          stopIndex,
          itemsPerPage
        });
        vue.watchEffect(() => {
          paginatedItems.value = items.value;
        });
      });
      const currentItemsWithoutGroups = vue.computed(() => extractRows(currentItems.value));
      const {
        isSelected,
        select,
        selectAll,
        toggleSelect
      } = provideSelection(props, {
        allItems: items,
        currentPage: currentItemsWithoutGroups
      });
      const {
        isExpanded,
        toggleExpand
      } = provideExpanded(props);
      useOptions({
        page,
        itemsPerPage,
        sortBy,
        groupBy,
        search
      });
      const slotProps = vue.computed(() => ({
        page: page.value,
        itemsPerPage: itemsPerPage.value,
        sortBy: sortBy.value,
        pageCount: pageCount.value,
        toggleSort,
        prevPage,
        nextPage,
        setPage,
        setItemsPerPage,
        isSelected,
        select,
        selectAll,
        toggleSelect,
        isExpanded,
        toggleExpand,
        isGroupOpen,
        toggleGroup,
        items: currentItemsWithoutGroups.value,
        itemsCount: filteredItems.value.length,
        groupedItems: currentItems.value
      }));
      useRender(() => vue.createVNode(props.tag, {
        "class": vue.normalizeClass(['v-data-iterator', {
          'v-data-iterator--loading': props.loading
        }, props.class]),
        "style": vue.normalizeStyle(props.style)
      }, {
        default: () => [slots.header?.(slotProps.value), vue.createVNode(MaybeTransition, {
          "transition": props.transition
        }, {
          default: () => [props.loading ? vue.createVNode(LoaderSlot, {
            "key": "loader",
            "name": "v-data-iterator",
            "active": true
          }, {
            default: slotProps => slots.loader?.(slotProps)
          }) : vue.createElementVNode("div", {
            "key": "items"
          }, [!currentItems.value.length ? slots['no-data']?.() : slots.default?.(slotProps.value)])]
        }), slots.footer?.(slotProps.value)]
      }));
      return {};
    }
  });

  // Utilities

  // Types

  function useRefs() {
    const refs = vue.ref([]);
    vue.onBeforeUpdate(() => refs.value = []);
    function updateRef(e, i) {
      refs.value[i] = e;
    }
    return {
      refs,
      updateRef
    };
  }

  // Types

  const makeVPaginationProps = propsFactory({
    activeColor: String,
    start: {
      type: [Number, String],
      default: 1
    },
    modelValue: {
      type: Number,
      default: props => props.start
    },
    disabled: Boolean,
    length: {
      type: [Number, String],
      default: 1,
      validator: val => val % 1 === 0
    },
    totalVisible: [Number, String],
    firstIcon: {
      type: IconValue,
      default: '$first'
    },
    prevIcon: {
      type: IconValue,
      default: '$prev'
    },
    nextIcon: {
      type: IconValue,
      default: '$next'
    },
    lastIcon: {
      type: IconValue,
      default: '$last'
    },
    ariaLabel: {
      type: String,
      default: '$vuetify.pagination.ariaLabel.root'
    },
    pageAriaLabel: {
      type: String,
      default: '$vuetify.pagination.ariaLabel.page'
    },
    currentPageAriaLabel: {
      type: String,
      default: '$vuetify.pagination.ariaLabel.currentPage'
    },
    firstAriaLabel: {
      type: String,
      default: '$vuetify.pagination.ariaLabel.first'
    },
    previousAriaLabel: {
      type: String,
      default: '$vuetify.pagination.ariaLabel.previous'
    },
    nextAriaLabel: {
      type: String,
      default: '$vuetify.pagination.ariaLabel.next'
    },
    lastAriaLabel: {
      type: String,
      default: '$vuetify.pagination.ariaLabel.last'
    },
    ellipsis: {
      type: String,
      default: '...'
    },
    showFirstLastPage: {
      type: [Boolean, String],
      default: false
    },
    ...makeBorderProps(),
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...makeElevationProps(),
    ...makeRoundedProps(),
    ...makeSizeProps(),
    ...makeTagProps({
      tag: 'nav'
    }),
    ...makeThemeProps(),
    ...makeVariantProps({
      variant: 'text'
    })
  }, 'VPagination');
  const VPagination = genericComponent()({
    name: 'VPagination',
    props: makeVPaginationProps(),
    emits: {
      'update:modelValue': value => true,
      first: value => true,
      prev: value => true,
      next: value => true,
      last: value => true
    },
    setup(props, {
      slots,
      emit
    }) {
      const page = useProxiedModel(props, 'modelValue');
      const {
        t,
        n
      } = useLocale();
      const {
        isRtl
      } = useRtl();
      const {
        themeClasses
      } = provideTheme(props);
      const {
        width
      } = useDisplay();
      const maxButtons = vue.shallowRef(-1);
      provideDefaults(undefined, {
        scoped: true
      });
      const {
        resizeRef
      } = useResizeObserver(entries => {
        if (!entries.length) return;
        const {
          target,
          contentRect
        } = entries[0];
        const firstItem = target.querySelector('.v-pagination__list > *');
        if (!firstItem) return;
        const totalWidth = contentRect.width;
        const itemWidth = firstItem.offsetWidth + parseFloat(getComputedStyle(firstItem).marginRight) * 2;
        maxButtons.value = getMax(totalWidth, itemWidth);
      });
      const length = vue.computed(() => parseInt(props.length, 10));
      const start = vue.computed(() => parseInt(props.start, 10));
      const totalVisible = vue.computed(() => {
        if (props.totalVisible != null) return parseInt(props.totalVisible, 10);else if (maxButtons.value >= 0) return maxButtons.value;
        return getMax(width.value, 58);
      });
      function getMax(totalWidth, itemWidth) {
        const minButtons = props.showFirstLastPage ? 5 : 3;
        return Math.max(0, Math.floor(
        // Round to two decimal places to avoid floating point errors
        Number(((totalWidth - itemWidth * minButtons) / itemWidth).toFixed(2))));
      }
      const range = vue.computed(() => {
        if (length.value <= 0 || isNaN(length.value) || length.value > Number.MAX_SAFE_INTEGER) return [];
        if (props.totalVisible == null && length.value < 3) {
          return createRange(length.value, start.value);
        }
        if (totalVisible.value <= 0) return [];else if (totalVisible.value === 1) return [page.value];
        if (length.value <= totalVisible.value) {
          return createRange(length.value, start.value);
        }
        const even = totalVisible.value % 2 === 0;
        const middle = even ? totalVisible.value / 2 : Math.floor(totalVisible.value / 2);
        const left = even ? middle : middle + 1;
        const right = length.value - middle;
        if (left - page.value >= 0) {
          return [...createRange(Math.max(1, totalVisible.value - 1), start.value), props.ellipsis, length.value];
        } else if (page.value - right >= (even ? 1 : 0)) {
          const rangeLength = totalVisible.value - 1;
          const rangeStart = length.value - rangeLength + start.value;
          return [start.value, props.ellipsis, ...createRange(rangeLength, rangeStart)];
        } else {
          const rangeLength = Math.max(1, totalVisible.value - 2);
          const rangeStart = rangeLength === 1 ? page.value : page.value - Math.ceil(rangeLength / 2) + start.value;
          return [start.value, props.ellipsis, ...createRange(rangeLength, rangeStart), props.ellipsis, length.value];
        }
      });

      // TODO: 'first' | 'prev' | 'next' | 'last' does not work here?
      function setValue(e, value, event) {
        e.preventDefault();
        page.value = value;
        event && emit(event, value);
      }
      const {
        refs,
        updateRef
      } = useRefs();
      provideDefaults({
        VPaginationBtn: {
          color: vue.toRef(() => props.color),
          border: vue.toRef(() => props.border),
          density: vue.toRef(() => props.density),
          size: vue.toRef(() => props.size),
          variant: vue.toRef(() => props.variant),
          rounded: vue.toRef(() => props.rounded),
          elevation: vue.toRef(() => props.elevation)
        }
      });
      const items = vue.computed(() => {
        return range.value.map((item, index) => {
          const ref = e => updateRef(e, index);
          if (typeof item === 'string') {
            return {
              isActive: false,
              key: `ellipsis-${index}`,
              page: item,
              props: {
                ref,
                ellipsis: true,
                icon: true,
                disabled: true
              }
            };
          } else {
            const isActive = item === page.value;
            return {
              isActive,
              key: item,
              page: n(item),
              props: {
                ref,
                ellipsis: false,
                icon: true,
                disabled: !!props.disabled || Number(props.length) < 2,
                color: isActive ? props.activeColor : props.color,
                'aria-current': isActive,
                'aria-label': t(isActive ? props.currentPageAriaLabel : props.pageAriaLabel, item),
                onClick: e => setValue(e, item)
              }
            };
          }
        });
      });
      const controls = vue.computed(() => {
        const prevDisabled = !!props.disabled || page.value <= start.value;
        const nextDisabled = !!props.disabled || page.value >= start.value + length.value - 1;
        return {
          first: [true, 'only-first'].includes(props.showFirstLastPage) ? {
            icon: isRtl.value ? props.lastIcon : props.firstIcon,
            onClick: e => setValue(e, start.value, 'first'),
            disabled: prevDisabled,
            'aria-label': t(props.firstAriaLabel),
            'aria-disabled': prevDisabled
          } : undefined,
          prev: {
            icon: isRtl.value ? props.nextIcon : props.prevIcon,
            onClick: e => setValue(e, page.value - 1, 'prev'),
            disabled: prevDisabled,
            'aria-label': t(props.previousAriaLabel),
            'aria-disabled': prevDisabled
          },
          next: {
            icon: isRtl.value ? props.prevIcon : props.nextIcon,
            onClick: e => setValue(e, page.value + 1, 'next'),
            disabled: nextDisabled,
            'aria-label': t(props.nextAriaLabel),
            'aria-disabled': nextDisabled
          },
          last: props.showFirstLastPage === true ? {
            icon: isRtl.value ? props.firstIcon : props.lastIcon,
            onClick: e => setValue(e, start.value + length.value - 1, 'last'),
            disabled: nextDisabled,
            'aria-label': t(props.lastAriaLabel),
            'aria-disabled': nextDisabled
          } : undefined
        };
      });
      function updateFocus() {
        const currentIndex = page.value - start.value;
        refs.value[currentIndex]?.$el.focus();
      }
      function onKeydown(e) {
        if (e.key === keyValues.left && !props.disabled && page.value > Number(props.start)) {
          page.value = page.value - 1;
          vue.nextTick(updateFocus);
        } else if (e.key === keyValues.right && !props.disabled && page.value < start.value + length.value - 1) {
          page.value = page.value + 1;
          vue.nextTick(updateFocus);
        }
      }
      useRender(() => vue.createVNode(props.tag, {
        "ref": resizeRef,
        "class": vue.normalizeClass(['v-pagination', themeClasses.value, props.class]),
        "style": vue.normalizeStyle(props.style),
        "role": "navigation",
        "aria-label": t(props.ariaLabel),
        "onKeydown": onKeydown,
        "data-testid": "v-pagination-root"
      }, {
        default: () => [vue.createElementVNode("ul", {
          "class": "v-pagination__list"
        }, [[true, 'only-first'].includes(props.showFirstLastPage) && vue.createElementVNode("li", {
          "key": "first",
          "class": "v-pagination__first",
          "data-testid": "v-pagination-first"
        }, [slots.first ? slots.first(controls.value.first) : vue.createVNode(VBtn, vue.mergeProps({
          "_as": "VPaginationBtn"
        }, controls.value.first), null)]), vue.createElementVNode("li", {
          "key": "prev",
          "class": "v-pagination__prev",
          "data-testid": "v-pagination-prev"
        }, [slots.prev ? slots.prev(controls.value.prev) : vue.createVNode(VBtn, vue.mergeProps({
          "_as": "VPaginationBtn"
        }, controls.value.prev), null)]), items.value.map((item, index) => vue.createElementVNode("li", {
          "key": item.key,
          "class": vue.normalizeClass(['v-pagination__item', {
            'v-pagination__item--is-active': item.isActive
          }]),
          "data-testid": "v-pagination-item"
        }, [slots.item ? slots.item(item) : vue.createVNode(VBtn, vue.mergeProps({
          "_as": "VPaginationBtn"
        }, item.props), {
          default: () => [item.page]
        })])), vue.createElementVNode("li", {
          "key": "next",
          "class": "v-pagination__next",
          "data-testid": "v-pagination-next"
        }, [slots.next ? slots.next(controls.value.next) : vue.createVNode(VBtn, vue.mergeProps({
          "_as": "VPaginationBtn"
        }, controls.value.next), null)]), props.showFirstLastPage === true && vue.createElementVNode("li", {
          "key": "last",
          "class": "v-pagination__last",
          "data-testid": "v-pagination-last"
        }, [slots.last ? slots.last(controls.value.last) : vue.createVNode(VBtn, vue.mergeProps({
          "_as": "VPaginationBtn"
        }, controls.value.last), null)])])]
      }));
      return {};
    }
  });

  const makeVDataTableFooterProps = propsFactory({
    color: String,
    prevIcon: {
      type: IconValue,
      default: '$prev'
    },
    nextIcon: {
      type: IconValue,
      default: '$next'
    },
    firstIcon: {
      type: IconValue,
      default: '$first'
    },
    lastIcon: {
      type: IconValue,
      default: '$last'
    },
    itemsPerPageText: {
      type: String,
      default: '$vuetify.dataFooter.itemsPerPageText'
    },
    pageText: {
      type: String,
      default: '$vuetify.dataFooter.pageText'
    },
    firstPageLabel: {
      type: String,
      default: '$vuetify.dataFooter.firstPage'
    },
    prevPageLabel: {
      type: String,
      default: '$vuetify.dataFooter.prevPage'
    },
    nextPageLabel: {
      type: String,
      default: '$vuetify.dataFooter.nextPage'
    },
    lastPageLabel: {
      type: String,
      default: '$vuetify.dataFooter.lastPage'
    },
    itemsPerPageOptions: {
      type: Array,
      default: () => [{
        value: 10,
        title: '10'
      }, {
        value: 25,
        title: '25'
      }, {
        value: 50,
        title: '50'
      }, {
        value: 100,
        title: '100'
      }, {
        value: -1,
        title: '$vuetify.dataFooter.itemsPerPageAll'
      }]
    },
    showCurrentPage: Boolean,
    ...pick(makeVPaginationProps({
      showFirstLastPage: true
    }), ['showFirstLastPage'])
  }, 'VDataTableFooter');
  const VDataTableFooter = genericComponent()({
    name: 'VDataTableFooter',
    props: makeVDataTableFooterProps(),
    setup(props, {
      slots
    }) {
      const {
        t
      } = useLocale();
      const {
        page,
        pageCount,
        startIndex,
        stopIndex,
        itemsLength,
        itemsPerPage,
        setItemsPerPage
      } = usePagination();
      const itemsPerPageOptions = vue.computed(() => props.itemsPerPageOptions.map(option => {
        if (typeof option === 'number') {
          return {
            value: option,
            title: option === -1 ? t('$vuetify.dataFooter.itemsPerPageAll') : String(option)
          };
        }
        return {
          ...option,
          title: !isNaN(Number(option.title)) ? option.title : t(option.title)
        };
      }));
      useRender(() => {
        const paginationProps = VPagination.filterProps(props);
        return vue.createElementVNode("div", {
          "class": "v-data-table-footer"
        }, [slots.prepend?.(), vue.createElementVNode("div", {
          "class": "v-data-table-footer__items-per-page"
        }, [vue.createElementVNode("span", null, [t(props.itemsPerPageText)]), vue.createVNode(VSelect, {
          "items": itemsPerPageOptions.value,
          "itemColor": props.color,
          "modelValue": itemsPerPage.value,
          "onUpdate:modelValue": v => setItemsPerPage(Number(v)),
          "density": "compact",
          "variant": "outlined",
          "aria-label": t(props.itemsPerPageText),
          "hideDetails": true
        }, null)]), vue.createElementVNode("div", {
          "class": "v-data-table-footer__info"
        }, [vue.createElementVNode("div", null, [t(props.pageText, !itemsLength.value ? 0 : startIndex.value + 1, stopIndex.value, itemsLength.value)])]), vue.createElementVNode("div", {
          "class": "v-data-table-footer__pagination"
        }, [vue.createVNode(VPagination, vue.mergeProps({
          "modelValue": page.value,
          "onUpdate:modelValue": $event => page.value = $event,
          "density": "comfortable",
          "firstAriaLabel": props.firstPageLabel,
          "lastAriaLabel": props.lastPageLabel,
          "length": pageCount.value,
          "nextAriaLabel": props.nextPageLabel,
          "previousAriaLabel": props.prevPageLabel,
          "rounded": true,
          "showFirstLastPage": true,
          "totalVisible": props.showCurrentPage ? 1 : 0,
          "variant": "plain"
        }, omit(paginationProps, ['color'])), null)])]);
      });
      return {};
    }
  });

  // Types

  const VDataTableColumn = defineFunctionalComponent({
    align: {
      type: String,
      default: 'start'
    },
    fixed: {
      type: [Boolean, String],
      default: false
    },
    fixedOffset: [Number, String],
    fixedEndOffset: [Number, String],
    height: [Number, String],
    lastFixed: Boolean,
    firstFixedEnd: Boolean,
    noPadding: Boolean,
    indent: [Number, String],
    empty: Boolean,
    tag: String,
    width: [Number, String],
    maxWidth: [Number, String],
    nowrap: Boolean
  }, (props, {
    slots
  }) => {
    const Tag = props.tag ?? 'td';
    const fixedSide = typeof props.fixed === 'string' ? props.fixed : props.fixed ? 'start' : 'none';
    return vue.createVNode(Tag, {
      "class": vue.normalizeClass(['v-data-table__td', {
        'v-data-table-column--fixed': fixedSide === 'start',
        'v-data-table-column--fixed-end': fixedSide === 'end',
        'v-data-table-column--last-fixed': props.lastFixed,
        'v-data-table-column--first-fixed-end': props.firstFixedEnd,
        'v-data-table-column--no-padding': props.noPadding,
        'v-data-table-column--nowrap': props.nowrap,
        'v-data-table-column--empty': props.empty
      }, `v-data-table-column--align-${props.align}`]),
      "style": {
        height: convertToUnit(props.height),
        width: convertToUnit(props.width),
        maxWidth: convertToUnit(props.maxWidth),
        left: fixedSide === 'start' ? convertToUnit(props.fixedOffset || null) : undefined,
        right: fixedSide === 'end' ? convertToUnit(props.fixedEndOffset || null) : undefined,
        paddingInlineStart: props.indent ? convertToUnit(props.indent) : undefined
      }
    }, {
      default: () => [slots.default?.()]
    });
  });

  // Utilities

  // Types

  const makeDataTableHeaderProps = propsFactory({
    headers: Array
  }, 'DataTable-header');
  const VDataTableHeadersSymbol = Symbol.for('vuetify:data-table-headers');
  const defaultHeader = {
    title: '',
    sortable: false
  };
  const defaultActionHeader = {
    ...defaultHeader,
    width: 48
  };
  function priorityQueue(arr = []) {
    const queue = arr.map(element => ({
      element,
      priority: 0
    }));
    return {
      enqueue: (element, priority) => {
        let added = false;
        for (let i = 0; i < queue.length; i++) {
          const item = queue[i];
          if (item.priority > priority) {
            queue.splice(i, 0, {
              element,
              priority
            });
            added = true;
            break;
          }
        }
        if (!added) queue.push({
          element,
          priority
        });
      },
      size: () => queue.length,
      count: () => {
        let count = 0;
        if (!queue.length) return 0;
        const whole = Math.floor(queue[0].priority);
        for (let i = 0; i < queue.length; i++) {
          if (Math.floor(queue[i].priority) === whole) count += 1;
        }
        return count;
      },
      dequeue: () => {
        return queue.shift();
      }
    };
  }
  function extractLeaves(item, columns = []) {
    if (!item.children) {
      columns.push(item);
    } else {
      for (const child of item.children) {
        extractLeaves(child, columns);
      }
    }
    return columns;
  }
  function extractKeys(headers, keys = new Set()) {
    for (const item of headers) {
      if (item.key) keys.add(item.key);
      if (item.children) {
        extractKeys(item.children, keys);
      }
    }
    return keys;
  }
  function getDefaultItem(item) {
    if (!item.key) return undefined;
    if (item.key === 'data-table-group') return defaultHeader;
    if (['data-table-expand', 'data-table-select'].includes(item.key)) return defaultActionHeader;
    return undefined;
  }
  function getDepth(item, depth = 0) {
    if (!item.children) return depth;
    return Math.max(depth, ...item.children.map(child => getDepth(child, depth + 1)));
  }
  function parseFixedColumns(items) {
    let seenFixed = false;
    function setFixed(item, side, parentFixedSide = 'none') {
      if (!item) return;
      if (parentFixedSide !== 'none') {
        item.fixed = parentFixedSide;
      }

      // normalize to simplify logic below
      if (item.fixed === true) {
        item.fixed = 'start';
      }
      if (item.fixed === side) {
        if (item.children) {
          if (side === 'start') {
            for (let i = item.children.length - 1; i >= 0; i--) {
              setFixed(item.children[i], side, side);
            }
          } else {
            for (let i = 0; i < item.children.length; i++) {
              setFixed(item.children[i], side, side);
            }
          }
        } else {
          if (!seenFixed && side === 'start') {
            item.lastFixed = true;
          } else if (!seenFixed && side === 'end') {
            item.firstFixedEnd = true;
          } else if (isNaN(Number(item.width))) {
            consoleError(`Multiple fixed columns should have a static width (key: ${item.key})`);
          } else {
            item.minWidth = Math.max(Number(item.width) || 0, Number(item.minWidth) || 0);
          }
          seenFixed = true;
        }
      } else {
        if (item.children) {
          if (side === 'start') {
            for (let i = item.children.length - 1; i >= 0; i--) {
              setFixed(item.children[i], side);
            }
          } else {
            for (let i = 0; i < item.children.length; i++) {
              setFixed(item.children[i], side);
            }
          }
        } else {
          seenFixed = false;
        }
      }
    }
    for (let i = items.length - 1; i >= 0; i--) {
      setFixed(items[i], 'start');
    }
    for (let i = 0; i < items.length; i++) {
      setFixed(items[i], 'end');
    }
    let fixedOffset = 0;
    for (let i = 0; i < items.length; i++) {
      fixedOffset = setFixedOffset(items[i], fixedOffset);
    }
    let fixedEndOffset = 0;
    for (let i = items.length - 1; i >= 0; i--) {
      fixedEndOffset = setFixedEndOffset(items[i], fixedEndOffset);
    }
  }
  function setFixedOffset(item, offset = 0) {
    if (!item) return offset;
    if (item.children) {
      item.fixedOffset = offset;
      for (const child of item.children) {
        offset = setFixedOffset(child, offset);
      }
    } else if (item.fixed && item.fixed !== 'end') {
      item.fixedOffset = offset;
      offset += parseFloat(item.width || '0') || 0;
    }
    return offset;
  }
  function setFixedEndOffset(item, offset = 0) {
    if (!item) return offset;
    if (item.children) {
      item.fixedEndOffset = offset;
      for (const child of item.children) {
        offset = setFixedEndOffset(child, offset);
      }
    } else if (item.fixed === 'end') {
      item.fixedEndOffset = offset;
      offset += parseFloat(item.width || '0') || 0;
    }
    return offset;
  }
  function parse(items, maxDepth) {
    const headers = [];
    let currentDepth = 0;
    const queue = priorityQueue(items);
    while (queue.size() > 0) {
      let rowSize = queue.count();
      const row = [];
      let fraction = 1;
      while (rowSize > 0) {
        const {
          element: item,
          priority
        } = queue.dequeue();
        const diff = maxDepth - currentDepth - getDepth(item);
        row.push({
          ...item,
          rowspan: diff ?? 1,
          colspan: item.children ? extractLeaves(item).length : 1
        });
        if (item.children) {
          for (const child of item.children) {
            // This internally sorts items that are on the same priority "row"
            const sort = priority % 1 + fraction / Math.pow(10, currentDepth + 2);
            queue.enqueue(child, currentDepth + diff + sort);
          }
        }
        fraction += 1;
        rowSize -= 1;
      }
      currentDepth += 1;
      headers.push(row);
    }
    const columns = items.map(item => extractLeaves(item)).flat();
    return {
      columns,
      headers
    };
  }
  function convertToInternalHeaders(items) {
    const internalHeaders = [];
    for (const item of items) {
      const defaultItem = {
        ...getDefaultItem(item),
        ...item
      };
      const key = defaultItem.key ?? (typeof defaultItem.value === 'string' ? defaultItem.value : null);
      const value = defaultItem.value ?? key ?? null;
      const internalItem = {
        ...defaultItem,
        key,
        value,
        sortable: defaultItem.sortable ?? (defaultItem.key != null || !!defaultItem.sort),
        children: defaultItem.children ? convertToInternalHeaders(defaultItem.children) : undefined
      };
      internalHeaders.push(internalItem);
    }
    return internalHeaders;
  }
  function createHeaders(props, options) {
    const headers = vue.ref([]);
    const columns = vue.ref([]);
    const sortFunctions = vue.ref({});
    const sortRawFunctions = vue.ref({});
    const filterFunctions = vue.ref({});
    vue.watchEffect(() => {
      const _headers = props.headers || Object.keys(props.items[0] ?? {}).map(key => ({
        key,
        title: vue.capitalize(key)
      }));
      const items = _headers.slice();
      const keys = extractKeys(items);
      if (options?.groupBy?.value.length && !keys.has('data-table-group')) {
        items.unshift({
          key: 'data-table-group',
          title: 'Group'
        });
      }
      if (options?.showSelect?.value && !keys.has('data-table-select')) {
        items.unshift({
          key: 'data-table-select'
        });
      }
      if (options?.showExpand?.value && !keys.has('data-table-expand')) {
        items.push({
          key: 'data-table-expand'
        });
      }
      const internalHeaders = convertToInternalHeaders(items);
      parseFixedColumns(internalHeaders);
      const maxDepth = Math.max(...internalHeaders.map(item => getDepth(item))) + 1;
      const parsed = parse(internalHeaders, maxDepth);
      headers.value = parsed.headers;
      columns.value = parsed.columns;
      const flatHeaders = parsed.headers.flat(1);
      sortFunctions.value = {};
      sortRawFunctions.value = {};
      filterFunctions.value = {};
      for (const header of flatHeaders) {
        if (!header.key) continue;
        if (header.sortable) {
          if (header.sort) {
            sortFunctions.value[header.key] = header.sort;
          }
          if (header.sortRaw) {
            sortRawFunctions.value[header.key] = header.sortRaw;
          }
        }
        if (header.filter) {
          filterFunctions.value[header.key] = header.filter;
        }
      }
    });
    const data = {
      headers,
      columns,
      sortFunctions,
      sortRawFunctions,
      filterFunctions
    };
    vue.provide(VDataTableHeadersSymbol, data);
    return data;
  }
  function useHeaders() {
    const data = vue.inject(VDataTableHeadersSymbol);
    if (!data) throw new Error('Missing headers!');
    return data;
  }

  // Utilities

  // Types

  function useLoadingConfig(loading, fallbackColor) {
    const active = vue.computed(() => {
      const v = loading();
      return v != null && v !== false && v !== 'false';
    });
    const side = vue.computed(() => {
      const v = loading();
      if (typeof v === 'object' && v !== null && v.side) return v.side;
      return 'start';
    });
    const color = vue.computed(() => {
      const v = loading();
      if (typeof v === 'object' && v !== null && v.color) return v.color;
      if (typeof v === 'string' && v !== 'true') return v;
      return fallbackColor();
    });
    return {
      active,
      side,
      color
    };
  }

  // Types

  const makeVDataTableHeadersProps = propsFactory({
    color: String,
    disableSort: Boolean,
    fixedHeader: Boolean,
    multiSort: Boolean,
    initialSortOrder: String,
    sortIcon: {
      type: IconValue
      // default: '$sort', // maybe in v4
    },
    sortAscIcon: {
      type: IconValue,
      default: '$sortAsc'
    },
    sortDescIcon: {
      type: IconValue,
      default: '$sortDesc'
    },
    headerProps: {
      type: Object
    },
    selectAllLabel: {
      type: String,
      default: '$vuetify.dataTable.ariaLabel.selectAll'
    },
    /** @deprecated */
    sticky: Boolean,
    ...makeDensityProps(),
    ...makeDisplayProps(),
    ...makeLoaderProps()
  }, 'VDataTableHeaders');
  const VDataTableHeaders = genericComponent()({
    name: 'VDataTableHeaders',
    props: makeVDataTableHeadersProps(),
    setup(props, {
      slots
    }) {
      const {
        t
      } = useLocale();
      const {
        toggleSort,
        sortBy,
        isSorted
      } = useSort();
      const {
        someSelected,
        allSelected,
        selectAll,
        showSelectAll
      } = useSelection();
      const {
        columns,
        headers
      } = useHeaders();
      const {
        loaderClasses
      } = useLoader(props);
      function getFixedStyles(column, y) {
        if (!(props.sticky || props.fixedHeader) && !column.fixed) return undefined;
        const fixedSide = typeof column.fixed === 'string' ? column.fixed : column.fixed ? 'start' : 'none';
        return {
          position: 'sticky',
          left: fixedSide === 'start' ? convertToUnit(column.fixedOffset) : undefined,
          right: fixedSide === 'end' ? convertToUnit(column.fixedEndOffset) : undefined,
          top: props.sticky || props.fixedHeader ? `calc(var(--v-table-header-height) * ${y})` : undefined
        };
      }
      function handleEnterKeyPress(event, column) {
        if (event.key === 'Enter' && !props.disableSort) {
          toggleSort(column, event);
        }
      }
      function getSortIcon(column) {
        const item = sortBy.value.find(item => item.key === column.key);
        switch (item?.order) {
          case 'asc':
            return props.sortAscIcon;
          case 'desc':
            return props.sortDescIcon;
          default:
            return props.sortIcon || (props.initialSortOrder === 'asc' ? props.sortAscIcon : props.sortDescIcon);
        }
      }
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.color);
      const {
        displayClasses,
        mobile
      } = useDisplay(props);
      const loadingConfig = useLoadingConfig(() => props.loading, () => props.color);
      const slotProps = vue.computed(() => ({
        headers: headers.value,
        columns: columns.value,
        toggleSort,
        isSorted,
        sortBy: sortBy.value,
        someSelected: someSelected.value,
        allSelected: allSelected.value,
        selectAll,
        getSortIcon
      }));
      const headerCellClasses = vue.computed(() => ['v-data-table__th', {
        'v-data-table__th--sticky': props.sticky || props.fixedHeader
      }, displayClasses.value, loaderClasses.value]);
      const VDataTableHeaderCell = ({
        column,
        x,
        y
      }) => {
        const noPadding = column.key === 'data-table-select' || column.key === 'data-table-expand';
        const isEmpty = column.key === 'data-table-group' && column.width === 0 && !column.title;
        const headerProps = vue.mergeProps(props.headerProps ?? {}, column.headerProps ?? {});
        const isSortable = column.sortable && !props.disableSort;
        const sortItem = isSortable ? sortBy.value.find(item => item.key === column.key) : undefined;
        const ariaSort = sortItem?.order === 'asc' ? 'ascending' : sortItem?.order === 'desc' ? 'descending' : undefined;
        return vue.createVNode(VDataTableColumn, vue.mergeProps({
          "tag": "th",
          "aria-sort": ariaSort,
          "align": column.align,
          "class": [{
            'v-data-table__th--sortable': isSortable,
            'v-data-table__th--sorted': isSorted(column),
            'v-data-table__th--fixed': column.fixed
          }, ...headerCellClasses.value],
          "style": {
            width: convertToUnit(column.width),
            minWidth: convertToUnit(column.minWidth),
            maxWidth: convertToUnit(column.maxWidth),
            ...getFixedStyles(column, y)
          },
          "colspan": column.colspan,
          "rowspan": column.rowspan,
          "fixed": column.fixed,
          "nowrap": column.nowrap,
          "lastFixed": column.lastFixed,
          "firstFixedEnd": column.firstFixedEnd,
          "noPadding": noPadding,
          "empty": isEmpty,
          "tabindex": isSortable ? 0 : undefined,
          "onClick": isSortable ? event => toggleSort(column, event) : undefined,
          "onKeydown": isSortable ? event => handleEnterKeyPress(event, column) : undefined
        }, headerProps), {
          default: () => {
            const columnSlotName = `header.${column.key}`;
            const columnSlotProps = {
              column,
              selectAll,
              isSorted,
              toggleSort,
              sortBy: sortBy.value,
              someSelected: someSelected.value,
              allSelected: allSelected.value,
              getSortIcon
            };
            if (slots[columnSlotName]) return slots[columnSlotName](columnSlotProps);
            if (isEmpty) return '';
            if (column.key === 'data-table-select') {
              return slots['header.data-table-select']?.(columnSlotProps) ?? (showSelectAll.value && vue.createVNode(VCheckboxBtn, {
                "aria-label": t(props.selectAllLabel),
                "color": props.color,
                "density": props.density,
                "modelValue": allSelected.value,
                "indeterminate": someSelected.value && !allSelected.value,
                "onUpdate:modelValue": selectAll
              }, null));
            }
            return vue.createElementVNode("div", {
              "class": "v-data-table-header__content"
            }, [vue.createElementVNode("span", null, [column.title]), column.sortable && !props.disableSort && vue.createVNode(VIcon, {
              "key": "icon",
              "class": "v-data-table-header__sort-icon",
              "icon": getSortIcon(column)
            }, null), props.multiSort && isSorted(column) && vue.createElementVNode("div", {
              "key": "badge",
              "class": vue.normalizeClass(['v-data-table-header__sort-badge', ...backgroundColorClasses.value]),
              "style": vue.normalizeStyle(backgroundColorStyles.value)
            }, [sortBy.value.findIndex(x => x.key === column.key) + 1])]);
          }
        });
      };
      const VDataTableMobileHeaderCell = () => {
        const sortableColumns = vue.computed(() => {
          return columns.value.filter(column => column?.sortable && !props.disableSort);
        });
        const showSelectColumn = columns.value.find(column => column.key === 'data-table-select');
        const sortingChips = vue.computed({
          get: () => sortableColumns.value.filter(({
            key
          }) => sortBy.value.some(v => v.key === key)),
          set: val => {
            const sortedColumns = wrapInArray(val);
            const activeSortKeys = sortBy.value.map(v => v.key);
            const newColumnsToSort = sortedColumns.filter(({
              key
            }) => !activeSortKeys.includes(key));
            newColumnsToSort.forEach(column => toggleSort(column));
            // sortBy is proxied model, needs nextTick after toggleSort
            vue.nextTick(() => sortBy.value = sortBy.value.filter(({
              key
            }) => sortedColumns.some(c => c.key === key)));
          }
        });
        function renderSortSelect() {
          return vue.createVNode(VSelect, {
            "modelValue": sortingChips.value,
            "onUpdate:modelValue": $event => sortingChips.value = $event,
            "chips": true,
            "color": props.color,
            "class": "v-data-table__td-sort-select",
            "clearable": true,
            "density": "default",
            "items": sortableColumns.value,
            "label": t('$vuetify.dataTable.sortBy'),
            "multiple": props.multiSort,
            "variant": "underlined",
            "returnObject": true,
            "onClick:clear": () => sortBy.value = []
          }, {
            chip: ({
              internalItem
            }) => vue.createVNode(VChip, {
              "onClick": internalItem.raw.sortable ? () => toggleSort(internalItem.raw, undefined, true) : undefined,
              "onMousedown": e => {
                e.preventDefault();
                e.stopPropagation();
              }
            }, {
              default: () => [internalItem.title, vue.createVNode(VIcon, {
                "class": vue.normalizeClass(['v-data-table__td-sort-icon', isSorted(internalItem.raw) && 'v-data-table__td-sort-icon-active']),
                "icon": getSortIcon(internalItem.raw),
                "size": "small"
              }, null)]
            })
          });
        }
        function renderSelectAll() {
          return vue.createVNode(VCheckboxBtn, {
            "aria-label": t(props.selectAllLabel),
            "class": "v-data-table-header__select-all",
            "color": props.color,
            "density": "compact",
            "modelValue": allSelected.value,
            "indeterminate": someSelected.value && !allSelected.value,
            "onUpdate:modelValue": () => selectAll(!allSelected.value)
          }, null);
        }
        return vue.createVNode(VDataTableColumn, vue.mergeProps({
          "tag": "th",
          "class": [...headerCellClasses.value],
          "colspan": headers.value.length + 1
        }, props.headerProps), {
          default: () => [vue.createElementVNode("div", {
            "class": "v-data-table-header__content"
          }, [slots['mobile.header']?.(slotProps.value) ?? vue.createElementVNode(vue.Fragment, null, [sortableColumns.value.length > 0 && renderSortSelect(), showSelectColumn && renderSelectAll()])])]
        });
      };
      const showMobileHeader = vue.computed(() => {
        if (slots['mobile.header']) return true;
        const hasSortableColumns = columns.value.some(column => column?.sortable && !props.disableSort);
        const hasSelectionControl = columns.value.some(column => column.key === 'data-table-select');
        return hasSortableColumns || hasSelectionControl;
      });
      useRender(() => {
        return mobile.value ? vue.createElementVNode(vue.Fragment, null, [showMobileHeader.value && vue.createElementVNode("tr", null, [vue.createVNode(VDataTableMobileHeaderCell, null, null)])]) : vue.createElementVNode(vue.Fragment, null, [slots.headers ? slots.headers(slotProps.value) : headers.value.map((row, y) => vue.createElementVNode("tr", null, [row.map((column, x) => vue.createVNode(VDataTableHeaderCell, {
          "key": column.key ?? x,
          "column": column,
          "x": x,
          "y": y
        }, null))])), loadingConfig.active.value && ['start', 'both'].includes(loadingConfig.side.value) && vue.createElementVNode("tr", {
          "class": "v-data-table-progress"
        }, [vue.createElementVNode("th", {
          "colspan": columns.value.length
        }, [vue.createVNode(LoaderSlot, {
          "name": "v-data-table-progress",
          "absolute": true,
          "active": true,
          "color": loadingConfig.color.value,
          "indeterminate": true
        }, {
          default: slots.loader
        })])])]);
      });
    }
  });

  // Types

  const makeVDataTableGroupHeaderRowProps = propsFactory({
    item: {
      type: Object,
      required: true
    },
    groupCollapseIcon: {
      type: IconValue,
      default: '$tableGroupCollapse'
    },
    groupExpandIcon: {
      type: IconValue,
      default: '$tableGroupExpand'
    },
    selectGroupLabel: {
      type: String,
      default: '$vuetify.dataTable.ariaLabel.selectGroup'
    },
    ...makeDensityProps()
  }, 'VDataTableGroupHeaderRow');
  const VDataTableGroupHeaderRow = genericComponent()({
    name: 'VDataTableGroupHeaderRow',
    props: makeVDataTableGroupHeaderRowProps(),
    setup(props, {
      slots
    }) {
      const {
        t
      } = useLocale();
      const {
        isGroupOpen,
        toggleGroup,
        extractRows
      } = useGroupBy();
      const {
        isSelected,
        isSomeSelected,
        select
      } = useSelection();
      const {
        columns
      } = useHeaders();
      const rows = vue.computed(() => {
        return extractRows([props.item]);
      });
      const colspan = vue.toRef(() => columns.value.length - (columns.value.some(c => c.key === 'data-table-select') ? 1 : 0));
      return () => vue.createElementVNode("tr", {
        "class": "v-data-table-group-header-row",
        "style": {
          '--v-data-table-group-header-row-depth': props.item.depth
        }
      }, [columns.value.map(column => {
        if (column.key === 'data-table-group') {
          const icon = isGroupOpen(props.item) ? props.groupCollapseIcon : props.groupExpandIcon;
          const onClick = () => toggleGroup(props.item);
          return slots['data-table-group']?.({
            item: props.item,
            count: rows.value.length,
            props: {
              icon,
              onClick
            }
          }) ?? vue.createVNode(VDataTableColumn, {
            "class": "v-data-table-group-header-row__column",
            "colspan": colspan.value
          }, {
            default: () => [vue.createVNode(VBtn, {
              "size": "small",
              "variant": "text",
              "icon": icon,
              "onClick": onClick
            }, null), vue.createElementVNode("span", null, [props.item.value]), vue.createElementVNode("span", null, [vue.createTextVNode("("), rows.value.length, vue.createTextVNode(")")])]
          });
        } else if (column.key === 'data-table-select') {
          const selectableRows = rows.value.filter(x => x.selectable);
          const modelValue = selectableRows.length > 0 && isSelected(selectableRows);
          const indeterminate = isSomeSelected(selectableRows) && !modelValue;
          const selectGroup = v => select(selectableRows, v);
          return slots['data-table-select']?.({
            props: {
              modelValue,
              indeterminate,
              'onUpdate:modelValue': selectGroup
            }
          }) ?? vue.createVNode(VDataTableColumn, {
            "class": "v-data-table__td--select-row",
            "noPadding": true
          }, {
            default: () => [vue.createVNode(VCheckboxBtn, {
              "aria-label": t(props.selectGroupLabel),
              "density": props.density,
              "disabled": selectableRows.length === 0,
              "modelValue": modelValue,
              "indeterminate": indeterminate,
              "onUpdate:modelValue": selectGroup
            }, null)]
          });
        }
        return '';
      })]);
    }
  });

  // Types

  const makeVDataTableRowProps = propsFactory({
    color: String,
    index: Number,
    item: Object,
    cellProps: [Object, Function],
    collapseIcon: {
      type: IconValue,
      default: '$collapse'
    },
    expandIcon: {
      type: IconValue,
      default: '$expand'
    },
    selectRowLabel: {
      type: String,
      default: '$vuetify.dataTable.ariaLabel.selectRow'
    },
    getMatches: Function,
    onClick: EventProp(),
    onContextmenu: EventProp(),
    onDblclick: EventProp(),
    ...makeDensityProps(),
    ...makeDisplayProps()
  }, 'VDataTableRow');
  const VDataTableRow = genericComponent()({
    name: 'VDataTableRow',
    props: makeVDataTableRowProps(),
    setup(props, {
      slots
    }) {
      const {
        t
      } = useLocale();
      const {
        displayClasses,
        mobile
      } = useDisplay(props, 'v-data-table__tr');
      const {
        isSelected,
        toggleSelect,
        someSelected,
        allSelected,
        selectAll
      } = useSelection();
      const {
        isExpanded,
        toggleExpand
      } = useExpanded();
      const {
        toggleSort,
        sortBy,
        isSorted
      } = useSort();
      const {
        columns
      } = useHeaders();
      useRender(() => vue.createElementVNode("tr", {
        "class": vue.normalizeClass(['v-data-table__tr', {
          'v-data-table__tr--clickable': !!(props.onClick || props.onContextmenu || props.onDblclick)
        }, displayClasses.value]),
        "onClick": props.onClick,
        "onContextmenu": props.onContextmenu,
        "onDblclick": props.onDblclick
      }, [props.item && columns.value.map((column, i) => {
        const item = props.item;
        const slotName = `item.${column.key}`;
        const headerSlotName = `header.${column.key}`;
        const slotProps = {
          index: props.index,
          item: item.raw,
          internalItem: item,
          value: getObjectValueByPath(item.columns, column.key),
          column,
          isSelected,
          toggleSelect,
          isExpanded,
          toggleExpand
        };
        const columnSlotProps = {
          column,
          selectAll,
          isSorted,
          toggleSort,
          sortBy: sortBy.value,
          someSelected: someSelected.value,
          allSelected: allSelected.value,
          getSortIcon: () => ''
        };
        const cellProps = typeof props.cellProps === 'function' ? props.cellProps({
          index: slotProps.index,
          item: slotProps.item,
          internalItem: slotProps.internalItem,
          value: slotProps.value,
          column
        }) : props.cellProps;
        const columnCellProps = typeof column.cellProps === 'function' ? column.cellProps({
          index: slotProps.index,
          item: slotProps.item,
          internalItem: slotProps.internalItem,
          value: slotProps.value
        }) : column.cellProps;
        const noPadding = column.key === 'data-table-select' || column.key === 'data-table-expand';
        const isEmpty = column.key === 'data-table-group' && column.width === 0 && !column.title;
        return vue.createVNode(VDataTableColumn, vue.mergeProps({
          "key": column.key ?? i,
          "align": column.align,
          "indent": column.indent,
          "class": {
            'v-data-table__td--expanded-row': column.key === 'data-table-expand',
            'v-data-table__td--select-row': column.key === 'data-table-select'
          },
          "fixed": column.fixed,
          "fixedOffset": column.fixedOffset,
          "fixedEndOffset": column.fixedEndOffset,
          "lastFixed": column.lastFixed,
          "firstFixedEnd": column.firstFixedEnd,
          "maxWidth": !mobile.value ? column.maxWidth : undefined,
          "noPadding": noPadding,
          "empty": isEmpty,
          "nowrap": column.nowrap,
          "width": !mobile.value ? column.width : undefined
        }, cellProps, columnCellProps), {
          default: () => {
            if (column.key === 'data-table-select') {
              return slots['item.data-table-select']?.({
                ...slotProps,
                props: {
                  color: props.color,
                  disabled: !item.selectable,
                  modelValue: isSelected([item]),
                  onClick: vue.withModifiers(() => toggleSelect(item), ['stop'])
                }
              }) ?? vue.createVNode(VCheckboxBtn, {
                "aria-label": t(props.selectRowLabel),
                "color": props.color,
                "disabled": !item.selectable,
                "density": props.density,
                "modelValue": isSelected([item]),
                "onClick": vue.withModifiers(event => toggleSelect(item, props.index, event), ['stop'])
              }, null);
            }
            if (column.key === 'data-table-expand') {
              return slots['item.data-table-expand']?.({
                ...slotProps,
                props: {
                  icon: isExpanded(item) ? props.collapseIcon : props.expandIcon,
                  size: 'small',
                  variant: 'text',
                  onClick: vue.withModifiers(() => toggleExpand(item), ['stop'])
                }
              }) ?? vue.createVNode(VBtn, {
                "icon": isExpanded(item) ? props.collapseIcon : props.expandIcon,
                "size": "small",
                "variant": "text",
                "onClick": vue.withModifiers(() => toggleExpand(item), ['stop'])
              }, null);
            }
            if (slots[slotName] && !mobile.value) return slots[slotName](slotProps);
            const text = vue.toDisplayString(slotProps.value);
            const matches = props.getMatches?.(item)?.[column.key];
            const displayValue = matches?.length ? vue.createVNode(VHighlight, {
              "text": text,
              "matches": matches
            }, null) : text;
            return !mobile.value ? displayValue : vue.createElementVNode(vue.Fragment, null, [vue.createElementVNode("div", {
              "class": "v-data-table__td-title"
            }, [slots[headerSlotName]?.(columnSlotProps) ?? column.title]), vue.createElementVNode("div", {
              "class": "v-data-table__td-value"
            }, [slots[slotName]?.(slotProps) ?? displayValue])]);
          }
        });
      })]));
    }
  });

  // Types

  const makeVDataTableRowsProps = propsFactory({
    color: String,
    loading: [Boolean, String, Object],
    loadingText: {
      type: String,
      default: '$vuetify.dataIterator.loadingText'
    },
    hideNoData: Boolean,
    items: {
      type: Array,
      default: () => []
    },
    noDataText: {
      type: String,
      default: '$vuetify.noDataText'
    },
    rowProps: [Object, Function],
    cellProps: [Object, Function],
    expandTransition: {
      type: null,
      default: () => ({
        component: VExpandTransition
      }),
      validator: val => val !== true
    },
    ...pick(makeVDataTableRowProps(), ['collapseIcon', 'expandIcon', 'density', 'getMatches']),
    ...pick(makeVDataTableGroupHeaderRowProps(), ['groupCollapseIcon', 'groupExpandIcon', 'density']),
    ...makeDisplayProps()
  }, 'VDataTableRows');
  const VDataTableRows = genericComponent()({
    name: 'VDataTableRows',
    inheritAttrs: false,
    props: makeVDataTableRowsProps(),
    setup(props, {
      attrs,
      slots
    }) {
      const {
        columns
      } = useHeaders();
      const {
        expandOnClick,
        toggleExpand,
        isExpanded
      } = useExpanded();
      const {
        isSelected,
        toggleSelect
      } = useSelection();
      const {
        toggleGroup,
        isGroupOpen
      } = useGroupBy();
      const {
        t
      } = useLocale();
      const {
        mobile
      } = useDisplay(props);
      useRender(() => {
        const groupHeaderRowProps = pick(props, ['groupCollapseIcon', 'groupExpandIcon', 'density']);
        if (props.loading && (!props.items.length || slots.loading)) {
          return vue.createElementVNode("tr", {
            "class": "v-data-table-rows-loading",
            "key": "loading"
          }, [vue.createElementVNode("td", {
            "colspan": columns.value.length
          }, [slots.loading?.() ?? t(props.loadingText)])]);
        }
        if (!props.loading && !props.items.length && !props.hideNoData) {
          return vue.createElementVNode("tr", {
            "class": "v-data-table-rows-no-data",
            "key": "no-data"
          }, [vue.createElementVNode("td", {
            "colspan": columns.value.length
          }, [slots['no-data']?.() ?? t(props.noDataText)])]);
        }
        return vue.createElementVNode(vue.Fragment, null, [props.items.map((item, index) => {
          if (item.type === 'group') {
            const slotProps = {
              index,
              item,
              columns: columns.value,
              isExpanded,
              toggleExpand,
              isSelected,
              toggleSelect,
              toggleGroup,
              isGroupOpen
            };
            return slots['group-header'] ? slots['group-header'](slotProps) : vue.createVNode(VDataTableGroupHeaderRow, vue.mergeProps({
              "key": `group-header_${item.id}`,
              "item": item
            }, getPrefixedEventHandlers(attrs, ':groupHeader', () => slotProps), groupHeaderRowProps), slots);
          }
          if (item.type === 'group-summary') {
            const slotProps = {
              index,
              item,
              columns: columns.value,
              toggleGroup
            };
            return slots['group-summary']?.(slotProps) ?? '';
          }
          const slotProps = {
            index: item.virtualIndex ?? index,
            item: item.raw,
            internalItem: item,
            columns: columns.value,
            isExpanded,
            toggleExpand,
            isSelected,
            toggleSelect
          };
          const itemSlotProps = {
            ...slotProps,
            props: vue.mergeProps({
              key: `item_${item.key ?? item.index}`,
              onClick: expandOnClick.value ? () => {
                toggleExpand(item);
              } : undefined,
              index,
              item,
              color: props.color,
              cellProps: props.cellProps,
              collapseIcon: props.collapseIcon,
              expandIcon: props.expandIcon,
              density: props.density,
              mobile: mobile.value,
              getMatches: props.getMatches
            }, getPrefixedEventHandlers(attrs, ':row', () => slotProps), typeof props.rowProps === 'function' ? props.rowProps({
              item: slotProps.item,
              index: slotProps.index,
              internalItem: slotProps.internalItem
            }) : props.rowProps)
          };
          return vue.createElementVNode(vue.Fragment, {
            "key": itemSlotProps.props.key
          }, [slots.item ? slots.item(itemSlotProps) : vue.createVNode(VDataTableRow, itemSlotProps.props, slots), slots['expanded-row'] ? isExpanded(item) && slots['expanded-row'](slotProps) : slots.expanded && vue.createElementVNode("tr", {
            "class": "v-data-table__tr--expanded"
          }, [vue.createElementVNode("td", {
            "colspan": columns.value.length
          }, [props.expandTransition ? vue.createVNode(MaybeTransition, {
            "transition": props.expandTransition
          }, {
            default: () => [isExpanded(item) ? vue.createElementVNode("div", null, [slots.expanded(slotProps)]) : null]
          }) // bypass <Transition> to avoid flash when expand-strategy=single
          : isExpanded(item) && vue.createElementVNode("div", null, [slots.expanded(slotProps)])])])]);
        })]);
      });
      return {};
    }
  });

  // Types

  const makeVTableProps = propsFactory({
    gridlines: {
      type: [Boolean, String],
      default: 'horizontal',
      validator: v => typeof v === 'boolean' || ['horizontal', 'vertical', 'all'].includes(v)
    },
    fixedHeader: Boolean,
    fixedFooter: Boolean,
    height: [Number, String],
    hover: Boolean,
    striped: {
      type: String,
      default: null,
      validator: v => ['even', 'odd'].includes(v)
    },
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...makeTagProps(),
    ...makeThemeProps()
  }, 'VTable');
  const VTable = genericComponent()({
    name: 'VTable',
    inheritAttrs: false,
    props: makeVTableProps(),
    setup(props, {
      attrs,
      slots,
      emit
    }) {
      const {
        themeClasses
      } = provideTheme(props);
      const {
        densityClasses
      } = useDensity(props);
      const gridlinesVariant = vue.computed(() => {
        if (props.gridlines === false) return 'none';
        if (props.gridlines === true) return 'all';
        return props.gridlines;
      });
      useRender(() => {
        const [tableAttrs, rootAttrs] = pickWithRest(attrs, [/^aria-label/]);
        return vue.createVNode(props.tag, vue.mergeProps(rootAttrs, {
          "class": ['v-table', `v-table--gridlines-${gridlinesVariant.value}`, {
            'v-table--fixed-height': !!props.height,
            'v-table--fixed-header': props.fixedHeader,
            'v-table--fixed-footer': props.fixedFooter,
            'v-table--has-top': !!slots.top,
            'v-table--has-bottom': !!slots.bottom,
            'v-table--hover': props.hover,
            'v-table--striped-even': props.striped === 'even',
            'v-table--striped-odd': props.striped === 'odd'
          }, themeClasses.value, densityClasses.value, props.class],
          "style": props.style
        }), {
          default: () => [slots.top?.(), slots.default ? vue.createElementVNode("div", {
            "class": "v-table__wrapper",
            "style": {
              height: convertToUnit(props.height)
            }
          }, [vue.createElementVNode("table", vue.normalizeProps(vue.guardReactiveProps(tableAttrs)), [slots.caption?.(), slots.default()])]) : slots.wrapper?.(), slots.bottom?.()]
        });
      });
      return {};
    }
  });

  // Utilities

  // Types

  // Composables
  const makeDataTableItemsProps = propsFactory({
    items: {
      type: Array,
      default: () => []
    },
    itemValue: {
      type: [String, Array, Function],
      default: 'id'
    },
    itemSelectable: {
      type: [String, Array, Function],
      default: null
    },
    rowProps: [Object, Function],
    cellProps: [Object, Function],
    returnObject: Boolean
  }, 'DataTable-items');
  function transformItem(props, item, index, columns) {
    const value = props.returnObject ? item : getPropertyFromItem(item, props.itemValue);
    const selectable = getPropertyFromItem(item, props.itemSelectable, true);
    const itemColumns = columns.reduce((obj, column) => {
      if (column.key != null) obj[column.key] = getPropertyFromItem(item, column.value);
      return obj;
    }, {});
    return {
      type: 'item',
      key: props.returnObject ? getPropertyFromItem(item, props.itemValue) : value,
      index,
      value,
      selectable,
      columns: itemColumns,
      raw: item
    };
  }
  function transformItems(props, items, columns) {
    return items.map((item, index) => transformItem(props, item, index, columns));
  }
  function useDataTableItems(props, columns) {
    const items = vue.computed(() => transformItems(props, props.items, columns.value));
    return {
      items
    };
  }

  // Types

  const makeDataTableProps = propsFactory({
    ...makeVDataTableRowsProps(),
    hideDefaultBody: Boolean,
    hideDefaultFooter: Boolean,
    hideDefaultHeader: Boolean,
    width: [String, Number],
    search: String,
    ...makeDataTableExpandProps(),
    ...makeDataTableGroupProps(),
    ...makeDataTableHeaderProps(),
    ...makeDataTableItemsProps(),
    ...makeDataTableSelectProps(),
    ...makeDataTableSortProps(),
    ...omit(makeVDataTableHeadersProps(), ['multiSort', 'initialSortOrder']),
    ...makeVTableProps()
  }, 'DataTable');
  const makeVDataTableProps = propsFactory({
    ...makeDataTablePaginateProps(),
    ...makeDataTableProps(),
    ...makeFilterProps(),
    ...makeVDataTableFooterProps()
  }, 'VDataTable');
  const VDataTable = genericComponent()({
    name: 'VDataTable',
    props: makeVDataTableProps(),
    emits: {
      'update:modelValue': value => true,
      'update:page': value => true,
      'update:itemsPerPage': value => true,
      'update:sortBy': value => true,
      'update:options': value => true,
      'update:groupBy': value => true,
      'update:expanded': value => true,
      'update:opened': value => true,
      'update:currentItems': value => true
    },
    setup(props, {
      attrs,
      slots
    }) {
      const {
        groupBy,
        opened,
        openAll,
        groupKey
      } = createGroupBy(props);
      const {
        initialSortOrder,
        sortBy,
        multiSort,
        mustSort
      } = createSort(props);
      const {
        page,
        itemsPerPage
      } = createPagination(props);
      const {
        disableSort
      } = vue.toRefs(props);
      const {
        columns,
        headers,
        sortFunctions,
        sortRawFunctions,
        filterFunctions
      } = createHeaders(props, {
        groupBy,
        showSelect: vue.toRef(() => props.showSelect),
        showExpand: vue.toRef(() => props.showExpand)
      });
      const {
        items
      } = useDataTableItems(props, columns);
      const search = vue.toRef(() => props.search);
      const {
        filteredItems,
        getMatches
      } = useFilter(props, items, search, {
        transform: item => item.columns,
        customKeyFilter: filterFunctions
      });
      const {
        toggleSort
      } = provideSort({
        initialSortOrder,
        sortBy,
        multiSort,
        mustSort,
        page
      });
      const {
        sortByWithGroups,
        opened: openedGroups,
        extractRows,
        isGroupOpen,
        toggleGroup
      } = provideGroupBy({
        groupBy,
        sortBy,
        disableSort,
        opened
      });
      const {
        sortedItems
      } = useSortedItems(props, filteredItems, sortByWithGroups, {
        transform: item => ({
          ...item.raw,
          ...item.columns
        }),
        sortFunctions,
        sortRawFunctions
      });
      useOpenAllGroups(openedGroups, openAll, sortedItems, groupBy, groupKey);
      const pageBy = vue.computed(() => {
        if (props.pageBy === 'auto') {
          return props.groupBy.length ? 'group' : 'item';
        }
        return props.pageBy;
      });
      const {
        pageCount,
        setItemsPerPage,
        prevPage,
        nextPage,
        setPage,
        paginatedItems
      } = usePaginatedGroups({
        pageBy,
        sortedItems,
        paginate: items => {
          const itemsLength = vue.computed(() => vue.toValue(items).length);
          const {
            startIndex,
            stopIndex,
            pageCount,
            setItemsPerPage,
            prevPage,
            nextPage,
            setPage
          } = providePagination({
            page,
            itemsPerPage,
            itemsLength
          });
          const {
            paginatedItems
          } = usePaginatedItems({
            items,
            startIndex,
            stopIndex,
            itemsPerPage
          });
          return {
            paginatedItems,
            pageCount,
            setItemsPerPage,
            prevPage,
            nextPage,
            setPage
          };
        },
        group: items => useGroupedItems(items, groupBy, openedGroups, () => !!slots['group-summary'], isGroupOpen, groupKey)
      });
      const paginatedItemsWithoutGroups = vue.computed(() => extractRows(paginatedItems.value));
      const {
        isSelected,
        select,
        selectAll,
        toggleSelect,
        someSelected,
        allSelected
      } = provideSelection(props, {
        allItems: items,
        currentPage: paginatedItemsWithoutGroups
      });
      const {
        isExpanded,
        toggleExpand
      } = provideExpanded(props);
      const loadingConfig = useLoadingConfig(() => props.loading, () => props.color);
      useOptions({
        page,
        itemsPerPage,
        sortBy,
        groupBy,
        search
      });
      provideDefaults({
        VDataTableRows: {
          hideNoData: vue.toRef(() => props.hideNoData),
          noDataText: vue.toRef(() => props.noDataText),
          loading: vue.toRef(() => props.loading),
          loadingText: vue.toRef(() => props.loadingText)
        }
      });
      const slotProps = vue.computed(() => ({
        page: page.value,
        itemsPerPage: itemsPerPage.value,
        itemsLength: filteredItems.value.length,
        sortBy: sortBy.value,
        pageCount: pageCount.value,
        toggleSort,
        setItemsPerPage,
        prevPage,
        nextPage,
        setPage,
        someSelected: someSelected.value,
        allSelected: allSelected.value,
        isSelected,
        select,
        selectAll,
        toggleSelect,
        isExpanded,
        toggleExpand,
        isGroupOpen,
        toggleGroup,
        items: paginatedItemsWithoutGroups.value.map(item => item.raw),
        internalItems: paginatedItemsWithoutGroups.value,
        groupedItems: paginatedItems.value,
        columns: columns.value,
        headers: headers.value
      }));
      useRender(() => {
        const dataTableFooterProps = VDataTableFooter.filterProps(props);
        const dataTableHeadersProps = VDataTableHeaders.filterProps(omit(props, ['multiSort']));
        const dataTableRowsProps = VDataTableRows.filterProps(props);
        const tableProps = VTable.filterProps(props);
        return vue.createVNode(VTable, vue.mergeProps({
          "class": ['v-data-table', {
            'v-data-table--show-select': props.showSelect,
            'v-data-table--loading': props.loading
          }, props.class],
          "style": props.style
        }, tableProps, {
          "fixedHeader": props.fixedHeader || props.sticky
        }), {
          top: () => slots.top?.(slotProps.value),
          caption: slots.caption,
          default: () => slots.default ? slots.default(slotProps.value) : vue.createElementVNode(vue.Fragment, null, [slots.colgroup?.(slotProps.value), !props.hideDefaultHeader && vue.createElementVNode("thead", {
            "key": "thead"
          }, [vue.createVNode(VDataTableHeaders, vue.mergeProps(dataTableHeadersProps, {
            "multiSort": !!props.multiSort
          }), slots)]), slots.thead?.(slotProps.value), !props.hideDefaultBody && vue.createElementVNode("tbody", null, [slots['body.prepend']?.(slotProps.value), slots.body ? slots.body(slotProps.value) : vue.createVNode(VDataTableRows, vue.mergeProps(attrs, dataTableRowsProps, {
            "items": paginatedItems.value,
            "getMatches": getMatches
          }), slots), slots['body.append']?.(slotProps.value), loadingConfig.active.value && ['end', 'both'].includes(loadingConfig.side.value) && vue.createElementVNode("tr", {
            "class": "v-data-table-progress v-data-table-progress--bottom"
          }, [vue.createElementVNode("th", {
            "colspan": columns.value.length
          }, [vue.createVNode(LoaderSlot, {
            "name": "v-data-table-progress",
            "absolute": true,
            "active": true,
            "color": loadingConfig.color.value,
            "indeterminate": true
          }, {
            default: slots.loader
          })])])]), slots.tbody?.(slotProps.value), slots.tfoot?.(slotProps.value)]),
          bottom: () => slots.bottom ? slots.bottom(slotProps.value) : !props.hideDefaultFooter && vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VDivider, null, null), vue.createVNode(VDataTableFooter, dataTableFooterProps, {
            prepend: slots['footer.prepend']
          })])
        });
      });
      return {};
    }
  });

  // Types

  const makeVDataTableVirtualProps = propsFactory({
    ...omit(makeDataTableProps(), ['hideDefaultFooter']),
    ...makeDataTableGroupProps(),
    ...makeVirtualProps(),
    ...makeFilterProps()
  }, 'VDataTableVirtual');
  function elementNodes(nodes) {
    return (nodes ?? []).flatMap(node => Array.isArray(node) ? elementNodes(node) : !vue.isVNode(node) ? [] : node.type === vue.Fragment ? elementNodes(node.children) : typeof node.type === 'symbol' ? [] : [node]);
  }
  const VDataTableVirtual = genericComponent()({
    name: 'VDataTableVirtual',
    props: makeVDataTableVirtualProps(),
    emits: {
      'update:modelValue': value => true,
      'update:sortBy': value => true,
      'update:options': value => true,
      'update:groupBy': value => true,
      'update:expanded': value => true,
      'update:opened': value => true
    },
    setup(props, {
      attrs,
      slots
    }) {
      const {
        groupBy,
        opened,
        openAll,
        groupKey
      } = createGroupBy(props);
      const {
        initialSortOrder,
        sortBy,
        multiSort,
        mustSort
      } = createSort(props);
      const {
        disableSort
      } = vue.toRefs(props);
      const {
        columns,
        headers,
        filterFunctions,
        sortFunctions,
        sortRawFunctions
      } = createHeaders(props, {
        groupBy,
        showSelect: vue.toRef(() => props.showSelect),
        showExpand: vue.toRef(() => props.showExpand)
      });
      const {
        items
      } = useDataTableItems(props, columns);
      const search = vue.toRef(() => props.search);
      const {
        filteredItems,
        getMatches
      } = useFilter(props, items, search, {
        transform: item => item.columns,
        customKeyFilter: filterFunctions
      });
      const {
        toggleSort
      } = provideSort({
        initialSortOrder,
        sortBy,
        multiSort,
        mustSort
      });
      const {
        sortByWithGroups,
        opened: openedGroups,
        extractRows,
        isGroupOpen,
        toggleGroup
      } = provideGroupBy({
        groupBy,
        sortBy,
        disableSort,
        opened
      });
      const {
        sortedItems
      } = useSortedItems(props, filteredItems, sortByWithGroups, {
        transform: item => ({
          ...item.raw,
          ...item.columns
        }),
        sortFunctions,
        sortRawFunctions
      });
      useOpenAllGroups(openedGroups, openAll, sortedItems, groupBy, groupKey);
      const {
        flatItems
      } = useGroupedItems(sortedItems, groupBy, openedGroups, () => !!slots['group-summary'], isGroupOpen, groupKey);
      const allItems = vue.computed(() => extractRows(flatItems.value));
      const {
        isSelected,
        select,
        selectAll,
        toggleSelect,
        someSelected,
        allSelected
      } = provideSelection(props, {
        allItems,
        currentPage: allItems
      });
      const {
        expanded,
        isExpanded,
        toggleExpand
      } = provideExpanded(props);
      const {
        containerRef,
        markerRef,
        paddingTop,
        paddingBottom,
        computedItems,
        handleItemResize,
        handleScroll,
        handleScrollend,
        calculateVisibleItems,
        scrollToIndex
      } = useVirtual(props, flatItems);
      const displayItems = vue.computed(() => computedItems.value.map(item => ({
        ...item.raw,
        virtualIndex: item.index
      })));

      // one virtual size per index = item row + optional expanded rows
      const rowHeights = new Map();
      const expandedHeights = new Map();
      function updateSize(index) {
        const expanded = expandedHeights.get(index)?.reduce((sum, height) => sum + (height || 0), 0) ?? 0;
        handleItemResize(index, (rowHeights.get(index) ?? 0) + expanded);
      }
      function setRowHeight(index, height) {
        rowHeights.set(index, height);
        updateSize(index);
      }
      function setExpandedHeight(index, row, height) {
        const heights = expandedHeights.get(index) ?? [];
        heights[row] = height;
        expandedHeights.set(index, heights);
        updateSize(index);
      }
      function trimExpandedHeights(index, count) {
        const heights = expandedHeights.get(index);
        if (!heights || heights.length <= count) return;
        heights.length = count;
        updateSize(index);
      }
      vue.watch(expanded, () => {
        if (!slots['expanded-row']) return;
        for (const index of [...expandedHeights.keys()]) {
          const item = flatItems.value[index];
          if (item?.type === 'item' && isExpanded(item)) continue;
          expandedHeights.delete(index);
          updateSize(index);
        }
      });
      vue.watch(flatItems, () => {
        rowHeights.clear();
        expandedHeights.clear();
      });
      useOptions({
        sortBy,
        page: vue.shallowRef(1),
        itemsPerPage: vue.shallowRef(-1),
        groupBy,
        search
      });
      provideDefaults({
        VDataTableRows: {
          hideNoData: vue.toRef(() => props.hideNoData),
          noDataText: vue.toRef(() => props.noDataText),
          loading: vue.toRef(() => props.loading),
          loadingText: vue.toRef(() => props.loadingText)
        }
      });
      const slotProps = vue.computed(() => ({
        itemsLength: allItems.value.length,
        sortBy: sortBy.value,
        toggleSort,
        someSelected: someSelected.value,
        allSelected: allSelected.value,
        isSelected,
        select,
        selectAll,
        toggleSelect,
        isExpanded,
        toggleExpand,
        isGroupOpen,
        toggleGroup,
        items: allItems.value.map(item => item.raw),
        internalItems: allItems.value,
        groupedItems: flatItems.value,
        columns: columns.value,
        headers: headers.value
      }));
      useRender(() => {
        const dataTableHeadersProps = VDataTableHeaders.filterProps(omit(props, ['multiSort']));
        const dataTableRowsProps = VDataTableRows.filterProps(props);
        const tableProps = VTable.filterProps(props);
        const [tableAttrs] = pickWithRest(attrs, [/^aria-label/]);
        return vue.createVNode(VTable, vue.mergeProps({
          "class": ['v-data-table', {
            'v-data-table--loading': props.loading
          }, props.class],
          "style": props.style
        }, tableProps, {
          "fixedHeader": props.fixedHeader || props.sticky
        }), {
          top: () => slots.top?.(slotProps.value),
          wrapper: () => vue.createElementVNode("div", {
            "ref": containerRef,
            "onScrollPassive": handleScroll,
            "onScrollend": handleScrollend,
            "class": "v-table__wrapper",
            "style": {
              height: convertToUnit(props.height)
            }
          }, [vue.createElementVNode("table", vue.normalizeProps(vue.guardReactiveProps(tableAttrs)), [slots.caption?.(), slots.colgroup?.(slotProps.value), !props.hideDefaultHeader && vue.createElementVNode("thead", {
            "key": "thead"
          }, [vue.createVNode(VDataTableHeaders, vue.mergeProps(dataTableHeadersProps, {
            "multiSort": !!props.multiSort
          }), slots)]), slots.thead?.(slotProps.value), !props.hideDefaultBody && vue.createElementVNode("tbody", {
            "key": "tbody"
          }, [vue.createElementVNode("tr", {
            "ref": markerRef,
            "style": {
              height: convertToUnit(paddingTop.value),
              border: 0
            }
          }, [vue.createElementVNode("td", {
            "colspan": columns.value.length,
            "style": {
              height: 0,
              border: 0
            }
          }, null)]), slots['body.prepend']?.(slotProps.value), vue.createVNode(VDataTableRows, vue.mergeProps(attrs, dataTableRowsProps, {
            "items": displayItems.value,
            "getMatches": getMatches
          }), {
            ...omit(slots, ['expanded', 'expanded-row']),
            item: itemSlotProps => {
              const {
                props: rowProps,
                ...itemSlot
              } = itemSlotProps;
              const index = itemSlotProps.internalItem.virtualIndex ?? itemSlotProps.internalItem.index;
              const itemExpanded = isExpanded(itemSlotProps.internalItem);
              const expandedRows = props.showExpand && itemExpanded && slots['expanded-row'] ? elementNodes(slots['expanded-row'](itemSlot)) : [];

              // rows that stay never resize, so a shrunk slot reports nothing
              if (slots['expanded-row'] && (expandedHeights.get(index)?.length ?? 0) > expandedRows.length) {
                vue.nextTick(() => trimExpandedHeights(index, expandedRows.length));
              }
              return vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VVirtualScrollItem, {
                "key": index,
                "renderless": true,
                "onUpdate:height": height => setRowHeight(index, height)
              }, {
                default: ({
                  itemRef
                }) => slots.item?.({
                  ...itemSlotProps,
                  itemRef
                }) ?? vue.createVNode(VDataTableRow, vue.mergeProps(rowProps, {
                  "ref": itemRef,
                  "index": itemSlotProps.index,
                  "getMatches": getMatches
                }), slots)
              }), props.showExpand && (slots['expanded-row'] ? expandedRows.map((node, row) => vue.createVNode(VVirtualScrollItem, {
                "key": `${index}-expanded-${row}`,
                "renderless": true,
                "onUpdate:height": height => setExpandedHeight(index, row, height)
              }, {
                default: ({
                  itemRef
                }) => vue.cloneVNode(node, {
                  ref: itemRef
                }, true)
              })) : slots.expanded && vue.createVNode(VVirtualScrollItem, {
                "key": `${index}-expanded`,
                "renderless": true,
                "onUpdate:height": height => setExpandedHeight(index, 0, height)
              }, {
                default: ({
                  itemRef
                }) => vue.createElementVNode("tr", {
                  "class": "v-data-table__tr--expanded",
                  "ref": itemRef
                }, [vue.createElementVNode("td", {
                  "colspan": columns.value.length
                }, [props.expandTransition ? vue.createVNode(MaybeTransition, {
                  "transition": props.expandTransition
                }, {
                  default: () => [itemExpanded ? vue.createElementVNode("div", null, [slots.expanded(itemSlot)]) : null]
                }) // bypass <Transition> to avoid flash when expand-strategy=single
                : itemExpanded && vue.createElementVNode("div", null, [slots.expanded(itemSlot)])])])
              }))]);
            }
          }), slots['body.append']?.(slotProps.value), vue.createElementVNode("tr", {
            "style": {
              height: convertToUnit(paddingBottom.value),
              border: 0
            }
          }, [vue.createElementVNode("td", {
            "colspan": columns.value.length,
            "style": {
              height: 0,
              border: 0
            }
          }, null)])]), slots.tbody?.(slotProps.value), slots.tfoot?.(slotProps.value)])]),
          bottom: () => slots.bottom?.(slotProps.value)
        });
      });
      return {
        calculateVisibleItems,
        scrollToIndex
      };
    }
  });

  // Types

  const makeVDataTableServerProps = propsFactory({
    itemsLength: {
      type: [Number, String],
      required: true
    },
    ...makeDataTablePaginateProps(),
    ...makeDataTableProps(),
    ...makeVDataTableFooterProps()
  }, 'VDataTableServer');
  const VDataTableServer = genericComponent()({
    name: 'VDataTableServer',
    props: makeVDataTableServerProps(),
    emits: {
      'update:modelValue': value => true,
      'update:page': page => true,
      'update:itemsPerPage': page => true,
      'update:sortBy': sortBy => true,
      'update:options': options => true,
      'update:expanded': options => true,
      'update:groupBy': value => true,
      'update:opened': value => true
    },
    setup(props, {
      attrs,
      slots
    }) {
      const {
        groupBy,
        opened,
        openAll,
        groupKey
      } = createGroupBy(props);
      const {
        initialSortOrder,
        sortBy,
        multiSort,
        mustSort
      } = createSort(props);
      const {
        page,
        itemsPerPage
      } = createPagination(props);
      const {
        disableSort
      } = vue.toRefs(props);
      const itemsLength = vue.computed(() => parseInt(props.itemsLength, 10));
      const {
        columns,
        headers
      } = createHeaders(props, {
        groupBy,
        showSelect: vue.toRef(() => props.showSelect),
        showExpand: vue.toRef(() => props.showExpand)
      });
      const {
        items
      } = useDataTableItems(props, columns);
      const {
        toggleSort
      } = provideSort({
        initialSortOrder,
        sortBy,
        multiSort,
        mustSort,
        page
      });
      const {
        opened: openedGroups,
        isGroupOpen,
        toggleGroup,
        extractRows
      } = provideGroupBy({
        groupBy,
        sortBy,
        disableSort,
        opened
      });
      useOpenAllGroups(openedGroups, openAll, items, groupBy, groupKey);
      const {
        pageCount,
        setItemsPerPage,
        prevPage,
        nextPage,
        setPage
      } = providePagination({
        page,
        itemsPerPage,
        itemsLength
      });
      const {
        flatItems
      } = useGroupedItems(items, groupBy, openedGroups, () => !!slots['group-summary'], isGroupOpen, groupKey);
      const {
        isSelected,
        select,
        selectAll,
        toggleSelect,
        someSelected,
        allSelected
      } = provideSelection(props, {
        allItems: items,
        currentPage: items
      });
      const {
        isExpanded,
        toggleExpand
      } = provideExpanded(props);
      const itemsWithoutGroups = vue.computed(() => extractRows(items.value));
      useOptions({
        page,
        itemsPerPage,
        sortBy,
        groupBy,
        search: vue.toRef(() => props.search)
      });
      vue.provide('v-data-table', {
        toggleSort,
        sortBy
      });
      provideDefaults({
        VDataTableRows: {
          hideNoData: vue.toRef(() => props.hideNoData),
          noDataText: vue.toRef(() => props.noDataText),
          loading: vue.toRef(() => props.loading),
          loadingText: vue.toRef(() => props.loadingText)
        }
      });
      const slotProps = vue.computed(() => ({
        page: page.value,
        itemsPerPage: itemsPerPage.value,
        itemsLength: itemsLength.value,
        sortBy: sortBy.value,
        pageCount: pageCount.value,
        toggleSort,
        setItemsPerPage,
        prevPage,
        nextPage,
        setPage,
        someSelected: someSelected.value,
        allSelected: allSelected.value,
        isSelected,
        select,
        selectAll,
        toggleSelect,
        isExpanded,
        toggleExpand,
        isGroupOpen,
        toggleGroup,
        items: itemsWithoutGroups.value.map(item => item.raw),
        internalItems: itemsWithoutGroups.value,
        groupedItems: flatItems.value,
        columns: columns.value,
        headers: headers.value
      }));
      useRender(() => {
        const dataTableFooterProps = VDataTableFooter.filterProps(props);
        const dataTableHeadersProps = VDataTableHeaders.filterProps(omit(props, ['multiSort']));
        const dataTableRowsProps = VDataTableRows.filterProps(props);
        const tableProps = VTable.filterProps(props);
        return vue.createVNode(VTable, vue.mergeProps({
          "class": ['v-data-table', {
            'v-data-table--loading': props.loading
          }, props.class],
          "style": props.style
        }, tableProps, {
          "fixedHeader": props.fixedHeader || props.sticky
        }), {
          top: () => slots.top?.(slotProps.value),
          caption: slots.caption,
          default: () => slots.default ? slots.default(slotProps.value) : vue.createElementVNode(vue.Fragment, null, [slots.colgroup?.(slotProps.value), !props.hideDefaultHeader && vue.createElementVNode("thead", {
            "key": "thead",
            "class": "v-data-table__thead",
            "role": "rowgroup"
          }, [vue.createVNode(VDataTableHeaders, vue.mergeProps(dataTableHeadersProps, {
            "multiSort": !!props.multiSort
          }), slots)]), slots.thead?.(slotProps.value), !props.hideDefaultBody && vue.createElementVNode("tbody", {
            "class": "v-data-table__tbody",
            "role": "rowgroup"
          }, [slots['body.prepend']?.(slotProps.value), slots.body ? slots.body(slotProps.value) : vue.createVNode(VDataTableRows, vue.mergeProps(attrs, dataTableRowsProps, {
            "items": flatItems.value
          }), slots), slots['body.append']?.(slotProps.value)]), slots.tbody?.(slotProps.value), slots.tfoot?.(slotProps.value)]),
          bottom: () => slots.bottom ? slots.bottom(slotProps.value) : !props.hideDefaultFooter && vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VDivider, null, null), vue.createVNode(VDataTableFooter, dataTableFooterProps, {
            prepend: slots['footer.prepend']
          })])
        });
      });
    }
  });

  const makeVContainerProps = propsFactory({
    fluid: {
      type: Boolean,
      default: false
    },
    ...makeComponentProps(),
    ...makeDimensionProps(),
    ...makeTagProps()
  }, 'VContainer');
  const VContainer = genericComponent()({
    name: 'VContainer',
    props: makeVContainerProps(),
    setup(props, {
      slots
    }) {
      const {
        rtlClasses
      } = useRtl();
      const {
        dimensionStyles
      } = useDimension(props);
      useRender(() => vue.createVNode(props.tag, {
        "class": vue.normalizeClass(['v-container', {
          'v-container--fluid': props.fluid
        }, rtlClasses.value, props.class]),
        "style": vue.normalizeStyle([dimensionStyles.value, props.style])
      }, slots));
      return {};
    }
  });

  // Styles

  // Types

  const breakpointProps = (() => {
    return breakpoints.reduce((props, val) => {
      props[val] = {
        type: [Boolean, String, Number],
        default: false
      };
      return props;
    }, {});
  })();
  const offsetProps = (() => {
    return breakpoints.reduce((props, val) => {
      const offsetKey = 'offset' + vue.capitalize(val);
      props[offsetKey] = {
        type: [String, Number],
        default: null
      };
      return props;
    }, {});
  })();
  const propMap$1 = {
    col: keys(breakpointProps),
    offset: keys(offsetProps),
    order: ['order', 'orderSm', 'orderMd', 'orderLg', 'orderXl', 'orderXxl']
  };
  function parseCols(val) {
    if (typeof val === 'string' && val.includes('/')) {
      const [cols, size] = val.split('/');
      return {
        cols: Number(cols),
        size: Number(size)
      };
    }
    return {
      cols: val
    };
  }
  function parseBreakpoint(type, prop, val) {
    if (val == null || val === false) {
      return {};
    }
    const {
      cols,
      size
    } = parseCols(val);
    const breakpoint = prop.replace(type, '').toLowerCase();
    if (type === 'offset') {
      return {
        className: `v-col--offset-${breakpoint}-${cols}`,
        variables: [{
          [`--v-col-offset-base-${breakpoint}`]: size
        }]
      };
    } else if (type === 'order') {
      return {
        className: `order-${breakpoint}-${cols}`
      };
    }

    // Handling the boolean style prop when accepting [Boolean, String, Number]
    // means Vue will not convert <v-col sm></v-col> to sm: true for us.
    // Since the default is false, an empty string indicates the prop's presence.
    return {
      className: cols === '' || cols === true ? `v-col--${breakpoint}` : `v-col--cols-${breakpoint}-${cols}`,
      variables: [{
        [`--v-col-size-base-${breakpoint}`]: size
      }]
    };
  }
  const ALIGN_SELF_VALUES = ['auto', 'start', 'end', 'center', 'baseline', 'stretch'];
  const alignSelfValidator = str => ALIGN_SELF_VALUES.includes(str);
  const makeVColProps = propsFactory({
    cols: {
      type: [Boolean, String, Number],
      default: false
    },
    ...breakpointProps,
    offset: {
      type: [String, Number],
      default: null
    },
    ...offsetProps,
    /** @deprecated use order-* class instead */
    order: {
      type: [String, Number],
      default: null
    },
    /** @deprecated use order-sm-* class instead */
    orderSm: {
      type: [String, Number],
      default: null
    },
    /** @deprecated use order-md-* class instead */
    orderMd: {
      type: [String, Number],
      default: null
    },
    /** @deprecated use order-lg-* class instead */
    orderLg: {
      type: [String, Number],
      default: null
    },
    /** @deprecated use order-xl-* class instead */
    orderXl: {
      type: [String, Number],
      default: null
    },
    /** @deprecated use order-xxl-* class instead */
    orderXxl: {
      type: [String, Number],
      default: null
    },
    /** @deprecated use align-self-* class instead */
    alignSelf: {
      type: String,
      default: null,
      validator: alignSelfValidator
    },
    ...makeComponentProps(),
    ...makeTagProps()
  }, 'VCol');
  const VCol = genericComponent()({
    name: 'VCol',
    props: makeVColProps(),
    setup(props, {
      slots
    }) {
      const sizeBaseOverride = vue.computed(() => parseCols(props.cols).size);
      const offsetBaseOverride = vue.computed(() => parseCols(props.offset).size);
      const responsive = vue.computed(() => {
        const classList = ['v-col'];
        const variablesList = [];

        // Loop through `col`, `offset`, `order` breakpoint props
        let type;
        for (type in propMap$1) {
          propMap$1[type].forEach(prop => {
            const value = props[prop];
            const {
              className,
              variables
            } = parseBreakpoint(type, prop, value);
            if (className) classList.push(className);
            if (variables) variablesList.push(...variables);
          });
        }
        const {
          cols
        } = parseCols(props.cols);
        const {
          cols: offset
        } = parseCols(props.offset);
        classList.push({
          [`v-col--cols-${cols}`]: cols,
          [`v-col--offset-${offset}`]: offset,
          [`order-${props.order}`]: props.order,
          [`align-self-${props.alignSelf}`]: props.alignSelf
        });
        return {
          classes: classList,
          variables: variablesList
        };
      });
      return () => vue.h(props.tag, {
        class: [responsive.value.classes, props.class],
        style: [{
          '--v-col-size-base': sizeBaseOverride.value
        }, {
          '--v-col-offset-base': offsetBaseOverride.value
        }, responsive.value.variables, props.style]
      }, slots.default?.());
    }
  });

  // Styles

  // Types

  const ALIGNMENT = ['start', 'end', 'center'];
  const SPACE = ['space-between', 'space-around', 'space-evenly'];
  const ALIGN_VALUES = [...ALIGNMENT, 'baseline', 'stretch'];
  const alignValidator = str => ALIGN_VALUES.includes(str);
  const JUSTIFY_VALUES = [...ALIGNMENT, ...SPACE];
  const justifyValidator = str => JUSTIFY_VALUES.includes(str);
  const ALIGN_CONTENT_VALUES = [...ALIGNMENT, ...SPACE, 'stretch'];
  const alignContentValidator = str => ALIGN_CONTENT_VALUES.includes(str);
  const propMap = {
    align: ['align', 'alignSm', 'alignMd', 'alignLg', 'alignXl', 'alignXxl'],
    justify: ['justify', 'justifySm', 'justifyMd', 'justifyLg', 'justifyXl', 'justifyXxl'],
    alignContent: ['alignContent', 'alignContentSm', 'alignContentMd', 'alignContentLg', 'alignContentXl', 'alignContentXxl']
  };
  const classMap = {
    align: 'align',
    justify: 'justify',
    alignContent: 'align-content'
  };
  function breakpointClass(type, prop, val) {
    let className = classMap[type];
    if (val == null) {
      return undefined;
    }
    if (prop) {
      // alignSm -> Sm
      const breakpoint = prop.replace(type, '');
      className += `-${breakpoint}`;
    }
    // .align-items-sm-center
    className += `-${val}`;
    return className.toLowerCase();
  }
  const makeVRowProps = propsFactory({
    /** @deprecated use density="compact" instead */
    dense: Boolean,
    /** @deprecated use align-* class instead */
    align: {
      type: String,
      default: null,
      validator: alignValidator
    },
    /** @deprecated use align-sm-* class instead */
    alignSm: {
      type: String,
      default: null,
      validator: alignValidator
    },
    /** @deprecated use align-md-* class instead */
    alignMd: {
      type: String,
      default: null,
      validator: alignValidator
    },
    /** @deprecated use align-lg-* class instead */
    alignLg: {
      type: String,
      default: null,
      validator: alignValidator
    },
    /** @deprecated use align-xl-* class instead */
    alignXl: {
      type: String,
      default: null,
      validator: alignValidator
    },
    /** @deprecated use align-xxl-* class instead */
    alignXxl: {
      type: String,
      default: null,
      validator: alignValidator
    },
    /** @deprecated use justify-* class instead */
    justify: {
      type: String,
      default: null,
      validator: justifyValidator
    },
    /** @deprecated use justify-sm-* class instead */
    justifySm: {
      type: String,
      default: null,
      validator: justifyValidator
    },
    /** @deprecated use justify-md-* class instead */
    justifyMd: {
      type: String,
      default: null,
      validator: justifyValidator
    },
    /** @deprecated use justify-lg-* class instead */
    justifyLg: {
      type: String,
      default: null,
      validator: justifyValidator
    },
    /** @deprecated use justify-xl-* class instead */
    justifyXl: {
      type: String,
      default: null,
      validator: justifyValidator
    },
    /** @deprecated use justify-xxl-* class instead */
    justifyXxl: {
      type: String,
      default: null,
      validator: justifyValidator
    },
    /** @deprecated use align-content-* class instead */
    alignContent: {
      type: String,
      default: null,
      validator: alignContentValidator
    },
    /** @deprecated use align-content-sm-* class instead */
    alignContentSm: {
      type: String,
      default: null,
      validator: alignContentValidator
    },
    /** @deprecated use align-content-md-* class instead */
    alignContentMd: {
      type: String,
      default: null,
      validator: alignContentValidator
    },
    /** @deprecated use align-content-lg-* class instead */
    alignContentLg: {
      type: String,
      default: null,
      validator: alignContentValidator
    },
    /** @deprecated use align-content-xl-* class instead */
    alignContentXl: {
      type: String,
      default: null,
      validator: alignContentValidator
    },
    /** @deprecated use align-content-xxl-* class instead */
    alignContentXxl: {
      type: String,
      default: null,
      validator: alignContentValidator
    },
    noGutters: Boolean,
    gap: [Number, String, Array],
    size: [Number, String],
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...makeTagProps()
  }, 'VRow');
  const VRow = genericComponent()({
    name: 'VRow',
    props: makeVRowProps(),
    setup(props, {
      slots
    }) {
      if (props.dense) {
        deprecate('dense', 'density="compact"');
      }
      const classes = vue.computed(() => {
        const classList = [];

        // Loop through `align`, `justify`, `alignContent` breakpoint props
        let type;
        for (type in propMap) {
          propMap[type].forEach(prop => {
            const value = props[prop];
            const className = breakpointClass(type, prop, value);
            if (className) classList.push(className);
          });
        }
        classList.push({
          'v-row--no-gutters': props.noGutters,
          'v-row--density-default': props.density === 'default' && !props.noGutters && !props.dense,
          'v-row--density-compact': props.density === 'compact' || props.dense,
          'v-row--density-comfortable': props.density === 'comfortable',
          [`align-${props.align}`]: props.align,
          [`justify-${props.justify}`]: props.justify,
          [`align-content-${props.alignContent}`]: props.alignContent
        });
        return classList;
      });
      const horizontalGap = vue.computed(() => {
        return Array.isArray(props.gap) ? convertToUnit(props.gap[0] || 0) : convertToUnit(props.gap);
      });
      const verticalGap = vue.computed(() => {
        return Array.isArray(props.gap) ? convertToUnit(props.gap[1] || 0) : horizontalGap.value;
      });
      return () => vue.h(props.tag, {
        class: ['v-row', classes.value, props.class],
        style: [{
          '--v-col-gap-x': horizontalGap.value,
          '--v-col-gap-y': verticalGap.value,
          '--v-row-columns': props.size
        }, props.style]
      }, slots.default?.());
    }
  });

  // Styles
  const VSpacer = createSimpleFunctional('v-spacer', 'div', 'VSpacer');

  // Types

  const makeVDatePickerControlsProps = propsFactory({
    active: {
      type: [String, Array],
      default: undefined
    },
    controlHeight: [Number, String],
    controlVariant: {
      type: String,
      default: 'docked'
    },
    noMonthPicker: Boolean,
    disabled: {
      type: [Boolean, String, Array],
      default: null
    },
    nextIcon: {
      type: IconValue,
      default: '$next'
    },
    prevIcon: {
      type: IconValue,
      default: '$prev'
    },
    modeIcon: {
      type: IconValue,
      default: '$subgroup'
    },
    text: String,
    monthText: String,
    yearText: String,
    viewMode: {
      type: String,
      default: 'month'
    }
  }, 'VDatePickerControls');
  const VDatePickerControls = genericComponent()({
    name: 'VDatePickerControls',
    props: makeVDatePickerControlsProps(),
    emits: {
      'click:year': () => true,
      'click:month': () => true,
      'click:prev': () => true,
      'click:next': () => true,
      'click:prev-year': () => true,
      'click:next-year': () => true
    },
    setup(props, {
      emit,
      slots
    }) {
      const {
        t
      } = useLocale();
      const disableMonth = vue.computed(() => {
        return Array.isArray(props.disabled) ? props.disabled.includes('text') : !!props.disabled;
      });
      const disableYear = vue.computed(() => {
        return Array.isArray(props.disabled) ? props.disabled.includes('mode') : !!props.disabled;
      });
      const disablePrevMonth = vue.computed(() => {
        return Array.isArray(props.disabled) ? props.disabled.includes('prev-month') : !!props.disabled;
      });
      const disableNextMonth = vue.computed(() => {
        return Array.isArray(props.disabled) ? props.disabled.includes('next-month') : !!props.disabled;
      });
      const disablePrevYear = vue.computed(() => {
        return Array.isArray(props.disabled) ? props.disabled.includes('prev-year') : !!props.disabled;
      });
      const disableNextYear = vue.computed(() => {
        return Array.isArray(props.disabled) ? props.disabled.includes('next-year') : !!props.disabled;
      });
      function onClickPrevMonth() {
        emit('click:prev');
      }
      function onClickNextMonth() {
        emit('click:next');
      }
      function onClickPrevYear() {
        emit('click:prev-year');
      }
      function onClickNextYear() {
        emit('click:next-year');
      }
      function onClickYear() {
        emit('click:year');
      }
      function onClickMonth() {
        emit('click:month');
      }
      useRender(() => {
        const innerDefaults = {
          VBtn: {
            density: 'comfortable',
            variant: 'text'
          }
        };
        const prevMonth = vue.createVNode(VBtn, {
          "data-testid": "prev-month",
          "disabled": disablePrevMonth.value,
          "icon": props.prevIcon,
          "aria-label": t('$vuetify.datePicker.ariaLabel.previousMonth'),
          "onClick": onClickPrevMonth
        }, null);
        const nextMonth = vue.createVNode(VBtn, {
          "data-testid": "next-month",
          "disabled": disableNextMonth.value,
          "icon": props.nextIcon,
          "aria-label": t('$vuetify.datePicker.ariaLabel.nextMonth'),
          "onClick": onClickNextMonth
        }, null);
        const prevYear = vue.createVNode(VBtn, {
          "data-testid": "prev-year",
          "disabled": disablePrevYear.value,
          "icon": props.prevIcon,
          "aria-label": t('$vuetify.datePicker.ariaLabel.previousYear'),
          "onClick": onClickPrevYear
        }, null);
        const nextYear = vue.createVNode(VBtn, {
          "data-testid": "next-year",
          "disabled": disableNextYear.value,
          "icon": props.nextIcon,
          "aria-label": t('$vuetify.datePicker.ariaLabel.nextYear'),
          "onClick": onClickNextYear
        }, null);
        const onlyMonthBtn = vue.createVNode(VBtn, {
          "class": "v-date-picker-controls__only-month-btn",
          "data-testid": "month-btn",
          "density": "default",
          "disabled": disableMonth.value,
          "text": props.monthText,
          "appendIcon": props.modeIcon,
          "rounded": true,
          "aria-label": t('$vuetify.datePicker.ariaLabel.selectMonth'),
          "onClick": onClickMonth
        }, null);
        const onlyYearBtn = vue.createVNode(VBtn, {
          "class": "v-date-picker-controls__only-year-btn",
          "data-testid": "year-btn",
          "density": "default",
          "disabled": disableYear.value,
          "text": props.yearText,
          "appendIcon": props.modeIcon,
          "rounded": true,
          "aria-label": t('$vuetify.datePicker.ariaLabel.selectYear'),
          "onClick": onClickYear
        }, null);
        const monthYearBtn = vue.createVNode(VBtn, {
          "class": "v-date-picker-controls__year-btn",
          "data-testid": "year-btn",
          "density": "default",
          "disabled": disableYear.value,
          "text": props.text,
          "appendIcon": props.modeIcon,
          "rounded": true,
          "aria-label": t('$vuetify.datePicker.ariaLabel.selectYear'),
          "onClick": onClickYear
        }, null);
        const monthYearSplit = vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VBtn, {
          "class": "v-date-picker-controls__month-btn",
          "data-testid": "month-btn",
          "height": "36",
          "disabled": disableMonth.value,
          "text": props.text,
          "rounded": true,
          "aria-label": t('$vuetify.datePicker.ariaLabel.selectMonth'),
          "onClick": onClickMonth
        }, null), vue.createVNode(VBtn, {
          "class": "v-date-picker-controls__mode-btn",
          "data-testid": "year-btn",
          "disabled": disableYear.value,
          "icon": props.modeIcon,
          "aria-label": t('$vuetify.datePicker.ariaLabel.selectYear'),
          "onClick": onClickYear
        }, null)]);
        const slotProps = {
          viewMode: props.viewMode,
          disabled: Array.isArray(props.disabled) ? props.disabled : [],
          monthYearText: props.text ?? '',
          monthText: props.monthText ?? '',
          yearText: props.yearText ?? '',
          openMonths: onClickMonth,
          openYears: onClickYear,
          prevMonth: onClickPrevMonth,
          nextMonth: onClickNextMonth,
          prevYear: onClickPrevYear,
          nextYear: onClickNextYear
        };
        const modalControls = vue.createElementVNode(vue.Fragment, null, [props.noMonthPicker ? monthYearBtn : monthYearSplit, vue.createVNode(VSpacer, null, null), vue.createElementVNode("div", {
          "class": "v-date-picker-controls__month"
        }, [prevMonth, nextMonth])]);
        const dockedControls = vue.createElementVNode(vue.Fragment, null, [vue.createElementVNode("div", {
          "class": "v-date-picker-controls__month"
        }, [prevMonth, onlyMonthBtn, nextMonth]), vue.createVNode(VSpacer, null, null), vue.createElementVNode("div", {
          "class": "v-date-picker-controls__year"
        }, [prevYear, onlyYearBtn, nextYear])]);
        return vue.createVNode(VDefaultsProvider, {
          "defaults": innerDefaults
        }, {
          default: () => [vue.createElementVNode("div", {
            "class": vue.normalizeClass(['v-date-picker-controls', `v-date-picker-controls--variant-${props.controlVariant}`]),
            "style": {
              '--v-date-picker-controls-height': convertToUnit(props.controlHeight)
            }
          }, [slots.default?.(slotProps) ?? vue.createElementVNode(vue.Fragment, null, [props.controlVariant === 'modal' && modalControls, props.controlVariant === 'docked' && dockedControls])])]
        });
      });
      return {};
    }
  });

  // Types

  const makeVDatePickerHeaderProps = propsFactory({
    appendIcon: IconValue,
    color: String,
    header: String,
    transition: String,
    onClick: EventProp(),
    onClickOnce: EventProp()
  }, 'VDatePickerHeader');
  const VDatePickerHeader = genericComponent()({
    name: 'VDatePickerHeader',
    props: makeVDatePickerHeaderProps(),
    emits: {
      click: () => true,
      'click:append': () => true
    },
    setup(props, {
      emit,
      slots
    }) {
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.color);
      function onClick() {
        emit('click');
      }
      function onClickAppend() {
        emit('click:append');
      }
      useRender(() => {
        const hasContent = !!(slots.default || props.header);
        const hasAppend = !!(slots.append || props.appendIcon);
        return vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-date-picker-header', {
            'v-date-picker-header--clickable': !!(props.onClick || props.onClickOnce)
          }, backgroundColorClasses.value]),
          "style": vue.normalizeStyle(backgroundColorStyles.value),
          "onClick": (props.onClick || props.onClickOnce) && onClick
        }, [slots.prepend && vue.createElementVNode("div", {
          "key": "prepend",
          "class": "v-date-picker-header__prepend"
        }, [slots.prepend()]), hasContent && vue.createVNode(MaybeTransition, {
          "key": "content",
          "name": props.transition
        }, {
          default: () => [vue.createElementVNode("div", {
            "key": props.header,
            "class": "v-date-picker-header__content"
          }, [slots.default?.() ?? props.header])]
        }), hasAppend && vue.createElementVNode("div", {
          "class": "v-date-picker-header__append"
        }, [!slots.append ? vue.createVNode(VBtn, {
          "key": "append-btn",
          "icon": props.appendIcon,
          "variant": "text",
          "onClick": onClickAppend
        }, null) : vue.createVNode(VDefaultsProvider, {
          "key": "append-defaults",
          "disabled": !props.appendIcon,
          "defaults": {
            VBtn: {
              icon: props.appendIcon,
              variant: 'text'
            }
          }
        }, {
          default: () => [slots.append?.()]
        })])]);
      });
      return {};
    }
  });

  // Composables

  // Types

  // Types

  // Composables
  const makeCalendarProps = propsFactory({
    allowedDates: [Array, Function],
    disabled: {
      type: Boolean,
      default: null
    },
    displayValue: null,
    modelValue: Array,
    month: [Number, String],
    max: null,
    min: null,
    showAdjacentMonths: Boolean,
    year: [Number, String],
    weekdays: {
      type: Array,
      default: () => [0, 1, 2, 3, 4, 5, 6]
    },
    weeksInMonth: {
      type: String,
      default: 'dynamic'
    },
    firstDayOfWeek: {
      type: [Number, String],
      default: undefined
    },
    firstDayOfYear: {
      type: [Number, String],
      default: undefined
    },
    weekdayFormat: String
  }, 'calendar');
  function useCalendar(props) {
    const adapter = useDate();
    const model = useProxiedModel(props, 'modelValue', [], v => wrapInArray(v).map(i => adapter.date(i)));
    const displayValue = vue.computed(() => {
      if (props.displayValue) return adapter.date(props.displayValue);
      if (model.value.length > 0) return adapter.date(model.value[0]);
      if (props.min) return adapter.date(props.min);
      if (Array.isArray(props.allowedDates)) return adapter.date(props.allowedDates[0]);
      return adapter.date();
    });
    const year = useProxiedModel(props, 'year', undefined, v => {
      const value = v != null ? Number(v) : adapter.getYear(displayValue.value);
      return adapter.startOfYear(adapter.setYear(adapter.date(), value));
    }, v => adapter.getYear(v));
    const month = useProxiedModel(props, 'month', undefined, v => {
      const value = v != null ? Number(v) : adapter.getMonth(displayValue.value);
      const date = adapter.setYear(adapter.startOfMonth(adapter.date()), adapter.getYear(year.value));
      return adapter.setMonth(date, value);
    }, v => adapter.getMonth(v));
    const weekdayLabels = vue.computed(() => {
      const firstDayOfWeek = adapter.toJsDate(adapter.startOfWeek(adapter.date(), props.firstDayOfWeek)).getDay();
      return adapter.getWeekdays(props.firstDayOfWeek, props.weekdayFormat).filter((_, i) => props.weekdays.includes((i + firstDayOfWeek) % 7));
    });
    const weeksInMonth = vue.computed(() => {
      const weeks = adapter.getWeekArray(month.value, props.firstDayOfWeek);
      const days = weeks.flat();

      // Make sure there's always 6 weeks in month (6 * 7 days)
      // if weeksInMonth is 'static'
      const daysInMonth = 6 * 7;
      if (props.weeksInMonth === 'static' && days.length < daysInMonth) {
        const lastDay = days[days.length - 1];
        let week = [];
        for (let day = 1; day <= daysInMonth - days.length; day++) {
          week.push(adapter.addDays(lastDay, day));
          if (day % 7 === 0) {
            weeks.push(week);
            week = [];
          }
        }
      }
      return weeks;
    });
    function genDays(days, today) {
      return days.filter(date => {
        return props.weekdays.includes(adapter.toJsDate(date).getDay());
      }).map((date, index) => {
        const isoDate = adapter.toISO(date);
        const isAdjacent = !adapter.isSameMonth(date, month.value);
        const isStart = adapter.isSameDay(date, adapter.startOfMonth(month.value));
        const isEnd = adapter.isSameDay(date, adapter.endOfMonth(month.value));
        const isSame = adapter.isSameDay(date, month.value);
        const weekdaysCount = props.weekdays.length;
        return {
          date,
          formatted: adapter.format(date, 'keyboardDate'),
          isAdjacent,
          isDisabled: isDisabled(date),
          isEnd,
          isHidden: isAdjacent && !props.showAdjacentMonths,
          isSame,
          isSelected: model.value.some(value => adapter.isSameDay(date, value)),
          isStart,
          isToday: adapter.isSameDay(date, today),
          isWeekEnd: index % weekdaysCount === weekdaysCount - 1,
          isWeekStart: index % weekdaysCount === 0,
          isoDate,
          localized: adapter.format(date, 'dayOfMonth'),
          month: adapter.getMonth(date),
          year: adapter.getYear(date)
        };
      });
    }
    const daysInWeek = vue.computed(() => {
      const lastDay = adapter.startOfWeek(displayValue.value, props.firstDayOfWeek);
      const week = [];
      for (let day = 0; day <= 6; day++) {
        week.push(adapter.addDays(lastDay, day));
      }
      const today = adapter.date();
      return genDays(week, today);
    });
    const daysInMonth = vue.computed(() => {
      const days = weeksInMonth.value.flat();
      const today = adapter.date();
      return genDays(days, today);
    });
    const weekNumbers = vue.computed(() => {
      return weeksInMonth.value.map(week => {
        return week.length ? adapter.getWeek(week[0], props.firstDayOfWeek, props.firstDayOfYear) : null;
      });
    });
    const {
      minDate,
      maxDate
    } = useCalendarRange(props);
    function isDisabled(value) {
      if (props.disabled) return true;
      const date = adapter.date(value);
      if (minDate.value && adapter.isBefore(adapter.endOfDay(date), minDate.value)) return true;
      if (maxDate.value && adapter.isAfter(date, maxDate.value)) return true;
      if (Array.isArray(props.allowedDates) && props.allowedDates.length > 0) {
        return !props.allowedDates.some(d => adapter.isSameDay(adapter.date(d), date));
      }
      if (typeof props.allowedDates === 'function') {
        return !props.allowedDates(date);
      }
      return false;
    }
    return {
      displayValue,
      daysInMonth,
      daysInWeek,
      genDays,
      model,
      weeksInMonth,
      weekdayLabels,
      weekNumbers
    };
  }
  function useCalendarRange(props) {
    const adapter = useDate();
    const minDate = vue.computed(() => {
      if (!props.min) return null;
      const date = adapter.date(props.min);
      return adapter.isValid(date) ? date : null;
    });
    const maxDate = vue.computed(() => {
      if (!props.max) return null;
      const date = adapter.date(props.max);
      return adapter.isValid(date) ? date : null;
    });
    function clampDate(date) {
      if (minDate.value && adapter.isBefore(date, minDate.value)) {
        return minDate.value;
      }
      if (maxDate.value && adapter.isAfter(date, maxDate.value)) {
        return maxDate.value;
      }
      return date;
    }
    function isInAllowedRange(date) {
      return (!minDate.value || adapter.isAfter(date, minDate.value)) && (!maxDate.value || adapter.isBefore(date, maxDate.value));
    }
    return {
      minDate,
      maxDate,
      clampDate,
      isInAllowedRange
    };
  }

  // Utilities

  // Types

  // pulled from v0, should be replaced by direct v0 import in v5.0
  // the only change was adapting to jsDOM by adding `?` in `el.scrollIntoView?.({ block: 'nearest' })`
  function useVirtualFocus(items, options) {
    const {
      control,
      orientation = 'vertical',
      circular = false,
      columns: _columns,
      onHighlight
    } = options;
    const highlightedId = vue.shallowRef();
    let previousEl = null;
    function applyHighlight(id) {
      const item = items().find(i => i.id === id);
      if (!item?.el) return false;
      const el = vue.toValue(item.el);
      if (!el) return false;
      const controlEl = vue.toValue(control);
      if (controlEl) {
        const itemId = el.getAttribute('id');
        if (itemId) controlEl.setAttribute('aria-activedescendant', itemId);
      }
      if (previousEl) delete previousEl.dataset.highlighted;
      el.dataset.highlighted = '';
      previousEl = el;
      el.scrollIntoView?.({
        block: 'nearest'
      });
      onHighlight?.(id);
      return true;
    }
    function mod(n, i) {
      return (i % n + n) % n;
    }
    function indexOf(id) {
      return items().findIndex(item => item.id === id);
    }
    function go(id) {
      highlightedId.value = id;
      applyHighlight(id);
    }
    function step(stride) {
      const all = items();
      if (!all.length) return;
      const current = highlightedId.value == null ? -1 : indexOf(highlightedId.value);
      const dir = stride > 0 ? 1 : -1;
      const abs = Math.abs(stride);
      const maxHops = Math.ceil(all.length / abs);
      let index = current + stride;
      let hops = 0;
      if (circular) {
        index = mod(all.length, index);
      } else if (index < 0 || index >= all.length) {
        return;
      }
      while (hops < maxHops) {
        const item = all[index];
        if (item && !vue.toValue(item.disabled)) {
          go(item.id);
          return;
        }
        hops++;
        index = circular ? mod(all.length, index + stride) : index + dir * abs;
        if (!circular && (index < 0 || index >= all.length)) return;
      }
    }
    function first() {
      const item = items().find(i => !vue.toValue(i.disabled));
      if (item) go(item.id);
    }
    function last() {
      const item = [...items()].reverse().find(i => !vue.toValue(i.disabled));
      if (item) go(item.id);
    }
    function rowFirst() {
      const cols = vue.toValue(_columns) ?? 0;
      if (!cols) return first();
      const all = items();
      const cur = highlightedId.value == null ? 0 : Math.max(0, indexOf(highlightedId.value));
      const start = cur - cur % cols;
      for (let i = start; i < Math.min(start + cols, all.length); i++) {
        if (!vue.toValue(all[i]?.disabled)) {
          go(all[i].id);
          return;
        }
      }
    }
    function rowLast() {
      const cols = vue.toValue(_columns) ?? 0;
      if (!cols) return last();
      const all = items();
      const cur = highlightedId.value == null ? 0 : Math.max(0, indexOf(highlightedId.value));
      const start = cur - cur % cols;
      const end = Math.min(start + cols, all.length);
      for (let i = end - 1; i >= start; i--) {
        if (!vue.toValue(all[i]?.disabled)) {
          go(all[i].id);
          return;
        }
      }
    }
    function highlight(id) {
      const prev = highlightedId.value;
      highlightedId.value = id;
      if (!applyHighlight(id)) highlightedId.value = prev;
    }
    function focusHighlighted() {
      if (highlightedId.value == null) return;
      const item = items().find(i => i.id === highlightedId.value);
      if (!item?.el) return;
      vue.toValue(item.el)?.focus();
    }
    function clear() {
      highlightedId.value = undefined;
      vue.toValue(control)?.removeAttribute('aria-activedescendant');
      if (previousEl) {
        delete previousEl.dataset.highlighted;
        previousEl = null;
      }
    }
    function isRtl(e) {
      const el = e.currentTarget;
      return el ? getComputedStyle(el).direction === 'rtl' : false;
    }
    function onKeydown(e) {
      const cols = vue.toValue(_columns);
      const rtl = isRtl(e);
      if (cols) {
        switch (e.key) {
          case 'ArrowRight':
            e.preventDefault();
            step(rtl ? -1 : 1);
            break;
          case 'ArrowLeft':
            e.preventDefault();
            step(rtl ? 1 : -1);
            break;
          case 'ArrowDown':
            e.preventDefault();
            step(cols);
            break;
          case 'ArrowUp':
            e.preventDefault();
            step(-cols);
            break;
          case 'Home':
            e.preventDefault();
            e.ctrlKey ? first() : rowFirst();
            break;
          case 'End':
            e.preventDefault();
            e.ctrlKey ? last() : rowLast();
            break;
        }
        return;
      }
      const prevKeys = [];
      const nextKeys = [];
      if (orientation === 'vertical' || orientation === 'both') {
        prevKeys.push('ArrowUp');
        nextKeys.push('ArrowDown');
      }
      if (orientation === 'horizontal' || orientation === 'both') {
        prevKeys.push(rtl ? 'ArrowRight' : 'ArrowLeft');
        nextKeys.push(rtl ? 'ArrowLeft' : 'ArrowRight');
      }
      if (prevKeys.includes(e.key)) {
        e.preventDefault();
        step(-1);
      } else if (nextKeys.includes(e.key)) {
        e.preventDefault();
        step(1);
      } else if (e.key === 'Home') {
        e.preventDefault();
        first();
      } else if (e.key === 'End') {
        e.preventDefault();
        last();
      }
    }
    vue.onScopeDispose(clear);
    return {
      highlightedId,
      highlight,
      focusHighlighted,
      clear,
      next: () => step(1),
      prev: () => step(-1),
      first,
      last,
      onKeydown
    };
  }

  // Composables

  // Types

  function keyToDirection(key) {
    switch (key) {
      case 'ArrowUp':
        return 'up';
      case 'ArrowDown':
        return 'down';
      case 'ArrowLeft':
        return 'left';
      case 'ArrowRight':
        return 'right';
      default:
        return null;
    }
  }
  function useGridSelection({
    items,
    columns,
    initialValue,
    itemAttribute,
    onSelect,
    onNavigation,
    onHighlight,
    onEscape
  }) {
    const hasFocusIn = vue.shallowRef(false);
    const containerEl = vue.shallowRef();
    const virtualFocus = useVirtualFocus(() => items().map(item => ({
      id: item.value,
      disabled: item.isDisabled,
      el: () => containerEl.value?.querySelector(`[${itemAttribute}="${item.value}"]`)
    })), {
      control: containerEl,
      columns
    });
    if (onHighlight) {
      vue.watch(virtualFocus.highlightedId, id => onHighlight(id));
    }
    function onFocusin(e) {
      const grid = containerEl.value;
      if (!grid || grid.contains(e.relatedTarget)) return;
      hasFocusIn.value = true;
      const targetEl = e.target;
      const targetId = targetEl?.getAttribute?.(itemAttribute);
      if (targetId != null && items().some(item => String(item.value) === targetId)) {
        virtualFocus.highlight(targetId);
        return;
      }
      const initial = initialValue(virtualFocus.highlightedId.value);
      if (initial != null) virtualFocus.highlight(initial);
      virtualFocus.focusHighlighted();
    }
    function onFocusout(e) {
      if (containerEl.value?.contains(e.relatedTarget)) return;
      hasFocusIn.value = false;
      virtualFocus.clear();
    }
    function onActivate() {
      const id = virtualFocus.highlightedId.value;
      if (id == null) return;
      const item = items().find(x => x.value === id);
      if (item && !item.isDisabled) {
        onSelect(id);
      }
    }
    function selectItem(value) {
      virtualFocus.highlight(value);
      virtualFocus.focusHighlighted();
      onSelect(value);
    }
    function focusItem(value) {
      virtualFocus.highlight(value);
      if (virtualFocus.highlightedId.value == null) virtualFocus.first();
      virtualFocus.focusHighlighted();
    }
    function onContainerKeydown(e) {
      if (e.key === 'Escape') {
        e.preventDefault();
        onEscape?.();
        return;
      }
      if ((e.key === 'Enter' || e.key === ' ') && virtualFocus.highlightedId.value != null) {
        e.preventDefault();
        onActivate();
        return;
      }
      const direction = keyToDirection(e.key);
      if (direction && onNavigation?.(direction, e, virtualFocus.highlightedId.value)) return;
      virtualFocus.onKeydown(e);
      virtualFocus.focusHighlighted();
    }
    const containerProps = vue.computed(() => ({
      ref: el => containerEl.value = el ?? undefined,
      tabindex: hasFocusIn.value ? -1 : 0,
      onKeydown: onContainerKeydown,
      onFocusin,
      onFocusout
    }));
    return {
      containerProps,
      containerEl,
      selectItem,
      focusItem,
      clear: virtualFocus.clear
    };
  }

  // Utilities

  // Types

  function useRangePicker({
    multiple,
    model,
    compare,
    normalizeEnd = v => v,
    previewValue: externalPreview
  }) {
    const rangeStart = vue.computed(() => model.value.length >= 1 ? model.value[0] : undefined);
    const rangeEnd = vue.computed(() => model.value.length >= 2 ? model.value[model.value.length - 1] : undefined);
    const previewValue = externalPreview ?? vue.shallowRef();
    const previewRange = vue.computed(() => {
      if (multiple.value !== 'range') return null;
      if (!rangeStart.value || rangeEnd.value) return null;
      if (!previewValue.value) return null;
      const start = rangeStart.value;
      const preview = previewValue.value;
      if (compare(start, preview) === 0) return null;
      return compare(start, preview) < 0 ? [start, preview] : [preview, start];
    });
    function isSelected(value) {
      if (multiple.value === 'range' && model.value.length === 2) {
        return isWithinRange(value);
      }
      for (const v of model.value) {
        if (compare(v, value) === 0) return true;
      }
      return false;
    }
    function isWithinRange(value) {
      if (multiple.value !== 'range' || model.value.length < 2) return false;
      const [start, end] = [model.value[0], model.value[model.value.length - 1]];
      return compare(value, start) >= 0 && compare(value, end) <= 0;
    }
    function isRangeStart(value) {
      if (multiple.value !== 'range' || model.value.length < 2) return false;
      return compare(value, model.value[0]) === 0;
    }
    function isRangeEnd(value) {
      if (multiple.value !== 'range' || model.value.length < 2) return false;
      return compare(value, model.value[model.value.length - 1]) === 0;
    }
    function isRangeMiddle(value) {
      return isWithinRange(value) && !isRangeStart(value) && !isRangeEnd(value);
    }
    function select(value) {
      if (multiple.value === 'range') {
        onRangeSelect(value);
      } else if (multiple.value) {
        onMultipleSelect(value);
      } else {
        model.value = [value];
      }
    }
    function onRangeSelect(value) {
      if (model.value.length === 0) {
        model.value = [value];
      } else if (model.value.length === 1) {
        const start = model.value[0];
        if (compare(value, start) === 0) {
          model.value = [];
        } else if (compare(value, start) < 0) {
          model.value = [value, normalizeEnd(start)];
        } else {
          model.value = [start, normalizeEnd(value)];
        }
      } else {
        model.value = [value];
      }
    }
    function setPreview(value) {
      previewValue.value = value;
    }
    function clearPreview() {
      previewValue.value = undefined;
    }
    function isPreviewStart(value) {
      const range = previewRange.value;
      if (!range) return false;
      return compare(value, range[0]) === 0;
    }
    function isPreviewEnd(value) {
      const range = previewRange.value;
      if (!range) return false;
      return compare(value, range[1]) === 0;
    }
    function isPreviewMiddle(value) {
      const range = previewRange.value;
      if (!range) return false;
      return compare(value, range[0]) > 0 && compare(value, range[1]) < 0;
    }
    function isInPreviewRange(value) {
      return isPreviewStart(value) || isPreviewEnd(value) || isPreviewMiddle(value);
    }
    function onMultipleSelect(value) {
      const index = model.value.findIndex(v => compare(v, value) === 0);
      if (index === -1) {
        model.value = [...model.value, value];
      } else {
        const copy = [...model.value];
        copy.splice(index, 1);
        model.value = copy;
      }
    }
    return {
      isSelected,
      isRangeStart,
      isRangeEnd,
      isRangeMiddle,
      select,
      setPreview,
      clearPreview,
      isPreviewStart,
      isPreviewEnd,
      isPreviewMiddle,
      isInPreviewRange
    };
  }

  // Types

  const makeVDatePickerMonthProps = propsFactory({
    color: String,
    hideWeekdays: Boolean,
    multiple: [Boolean, Number, String],
    showWeek: Boolean,
    readonly: Boolean,
    transition: {
      type: String,
      default: 'picker-transition'
    },
    reverseTransition: {
      type: String,
      default: 'picker-reverse-transition'
    },
    events: {
      type: [Array, Function, Object],
      default: () => null
    },
    eventColor: {
      type: [Array, Function, Object, String],
      default: () => null
    },
    noAutoNavigation: Boolean,
    previewValue: null,
    ...omit(makeCalendarProps(), ['displayValue'])
  }, 'VDatePickerMonth');
  const VDatePickerMonth = genericComponent()({
    name: 'VDatePickerMonth',
    props: makeVDatePickerMonthProps(),
    emits: {
      'update:modelValue': date => true,
      'update:month': date => true,
      'update:year': date => true,
      'update:previewValue': _value => true,
      'boundary-navigate': _payload => true
    },
    setup(props, {
      emit,
      slots
    }) {
      const uid = vue.useId();
      const {
        t
      } = useLocale();
      const {
        daysInMonth,
        model,
        weekNumbers,
        weekdayLabels
      } = useCalendar(props);
      const adapter = useDate();
      const isReverse = vue.shallowRef(false);
      const transition = vue.toRef(() => {
        return !isReverse.value ? props.transition : props.reverseTransition;
      });
      function compareDays(a, b) {
        if (adapter.isSameDay(a, b)) return 0;
        return adapter.isBefore(a, b) ? -1 : 1;
      }
      const previewValue = useProxiedModel(props, 'previewValue');
      const range = useRangePicker({
        multiple: vue.computed(() => {
          if (props.multiple === 'range') return 'range';
          return !!props.multiple;
        }),
        model,
        compare: compareDays,
        normalizeEnd: value => adapter.endOfDay(value),
        previewValue
      });
      const selectionColor = vue.toRef(() => props.color || 'surface-variant');
      const {
        backgroundColorClasses: rangeColorClasses,
        backgroundColorStyles: rangeColorStyles
      } = useBackgroundColor(selectionColor);
      const atMax = vue.computed(() => {
        const max = ['number', 'string'].includes(typeof props.multiple) ? Number(props.multiple) : Infinity;
        return model.value.length >= max;
      });
      const dayRows = vue.computed(() => {
        return chunkArray(daysInMonth.value, props.weekdays.length);
      });
      function isSelectedDay(item) {
        return range.isSelected(item.date);
      }
      function isDayDisabled(item) {
        return item.isDisabled || item.isHidden || atMax.value && !isSelectedDay(item);
      }
      function getDateAriaLabel(item) {
        const fullDate = adapter.format(item.date, 'fullDateWithWeekday');
        const localeKey = item.isToday ? 'currentDate' : 'selectDate';
        return t(`$vuetify.datePicker.ariaLabel.${localeKey}`, fullDate);
      }
      function onClick(value) {
        range.select(adapter.startOfDay(value));
      }
      function initialFocusDate(current) {
        const isVisible = d => !d.isAdjacent && !d.isDisabled;

        // Preserve existing highlight if it's still pointing to a visible day in the current grid
        if (current != null) {
          const cur = daysInMonth.value.find(d => d.isoDate === current);
          if (cur && !cur.isAdjacent) return current;
        }
        const selected = daysInMonth.value.find(d => isVisible(d) && model.value.some(m => adapter.isSameDay(m, d.date)));
        return (selected ?? daysInMonth.value.find(isVisible))?.isoDate;
      }
      const {
        containerProps,
        containerEl,
        selectItem,
        focusItem,
        clear
      } = useGridSelection({
        items: () => daysInMonth.value.map(d => ({
          value: d.isoDate,
          isDisabled: isDayDisabled(d)
        })),
        columns: () => props.weekdays.length,
        initialValue: initialFocusDate,
        itemAttribute: 'data-v-date',
        onSelect: onDaySelect,
        onNavigation: onNavigationBoundary,
        onEscape
      });
      function onDaySelect(isoDate) {
        const item = daysInMonth.value.find(d => d.isoDate === isoDate);
        if (!item || isDayDisabled(item)) return;
        onClick(item.date);
        if (item.isAdjacent) {
          emit('update:month', adapter.getMonth(item.date));
          emit('update:year', adapter.getYear(item.date));
          vue.nextTick(() => focusItem(isoDate));
        }
      }
      function onNavigationBoundary(direction, e, curId) {
        if (curId == null) return false;
        const cols = props.weekdays.length;
        const rtl = getComputedStyle(e.currentTarget).direction === 'rtl';

        // stride = array-index delta; calendarDays = actual date offset for boundary crossing
        let stride;
        let calendarDays;
        if (direction === 'left') {
          stride = rtl ? 1 : -1;
          calendarDays = stride;
        } else if (direction === 'right') {
          stride = rtl ? -1 : 1;
          calendarDays = stride;
        } else if (direction === 'up') {
          stride = -cols;
          calendarDays = -7;
        } else {
          stride = cols;
          calendarDays = 7;
        }
        const all = daysInMonth.value;
        const curIndex = all.findIndex(d => d.isoDate === curId);
        if (curIndex < 0) return false;
        const targetItem = all[curIndex + stride];

        // isHidden = isAdjacent && !showAdjacentMonths — no button in DOM for this day
        if (targetItem && !targetItem.isHidden) return false;
        e.preventDefault();
        let targetIsoDate;
        if (targetItem) {
          targetIsoDate = targetItem.isoDate;
        } else {
          const step = calendarDays < 0 ? -1 : 1;
          let candidate = adapter.addDays(adapter.date(curId), calendarDays);
          while (!props.weekdays.includes(adapter.toJsDate(candidate).getDay())) {
            candidate = adapter.addDays(candidate, step);
          }
          targetIsoDate = adapter.toISO(candidate);
        }
        if (props.noAutoNavigation) {
          emit('boundary-navigate', {
            direction,
            targetIsoDate
          });
          return true;
        }
        const targetDate = adapter.date(targetIsoDate);
        emit('update:month', adapter.getMonth(targetDate));
        emit('update:year', adapter.getYear(targetDate));
        vue.nextTick(() => focusItem(targetIsoDate));
        return true;
      }
      function onEscape() {
        const rawTarget = model.value[0] ?? adapter.date();
        const targetIso = adapter.toISO(adapter.date(rawTarget));
        const inCurrentMonth = daysInMonth.value.find(d => d.isoDate === targetIso && !d.isAdjacent);
        if (inCurrentMonth) {
          focusItem(targetIso);
          return;
        }
        const targetDate = adapter.date(rawTarget);
        emit('update:month', adapter.getMonth(targetDate));
        emit('update:year', adapter.getYear(targetDate));
        vue.nextTick(() => focusItem(targetIso));
      }
      function onDayClick(item) {
        if (item.isAdjacent) {
          onDaySelect(item.isoDate);
        } else {
          selectItem(item.isoDate);
        }
      }
      function focusGrid() {
        containerEl.value?.focus();
      }
      vue.watch(daysInMonth, (val, oldVal) => {
        if (!oldVal || val[0].isoDate === oldVal[0].isoDate) return; // only clear when the month actually changes

        isReverse.value = adapter.isBefore(val[0].date, oldVal[0].date);
        clear();
      });
      function getEventColors(date) {
        const {
          events,
          eventColor
        } = props;
        let eventData;
        let eventColors = [];
        if (Array.isArray(events)) {
          eventData = events.includes(date);
        } else if (events instanceof Function) {
          eventData = events(date) || false;
        } else if (events) {
          eventData = events[date] || false;
        } else {
          eventData = false;
        }
        if (!eventData) {
          return [];
        } else if (eventData !== true) {
          eventColors = wrapInArray(eventData);
        } else if (typeof eventColor === 'string') {
          eventColors = [eventColor];
        } else if (typeof eventColor === 'function') {
          eventColors = wrapInArray(eventColor(date));
        } else if (Array.isArray(eventColor)) {
          eventColors = eventColor;
        } else if (typeof eventColor === 'object' && eventColor !== null) {
          eventColors = wrapInArray(eventColor[date]);
        }

        // Fallback to default color if no color is found
        return !eventColors.length ? ['surface-variant'] : eventColors.filter(Boolean).map(color => typeof color === 'string' ? color : 'surface-variant');
      }
      function genEvents(date) {
        const eventColors = getEventColors(date);
        if (!eventColors.length) return null;
        return vue.createElementVNode("div", {
          "class": "v-date-picker-month__events"
        }, [eventColors.map(color => vue.createVNode(VBadge, {
          "dot": true,
          "color": color
        }, null))]);
      }
      useRender(() => vue.createElementVNode("div", {
        "class": "v-date-picker-month",
        "style": {
          '--v-date-picker-days-in-week': props.weekdays.length
        }
      }, [props.showWeek && vue.createElementVNode("div", {
        "key": "weeks",
        "class": "v-date-picker-month__weeks"
      }, [!props.hideWeekdays && vue.createElementVNode("div", {
        "key": "hide-week-days",
        "class": "v-date-picker-month__day"
      }, [vue.createTextVNode("\xA0")]), weekNumbers.value.map(week => vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-date-picker-month__day', 'v-date-picker-month__day--adjacent'])
      }, [week]))]), vue.createVNode(MaybeTransition, {
        "name": transition.value
      }, {
        default: () => [vue.createElementVNode("div", vue.mergeProps({
          "key": daysInMonth.value[0].date?.toString(),
          "class": "v-date-picker-month__days",
          "role": "grid",
          "onMouseleave": range.clearPreview
        }, containerProps.value), [!props.hideWeekdays && vue.createElementVNode("div", {
          "key": "weekday-labels",
          "class": "v-date-picker-month__days-row"
        }, [weekdayLabels.value.map(weekDay => vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-date-picker-month__day', 'v-date-picker-month__weekday'])
        }, [weekDay]))]), dayRows.value.map((row, rowIndex) => vue.createElementVNode("div", {
          "class": "v-date-picker-month__days-row",
          "role": "row"
        }, [row.map((item, colIndex) => {
          const i = rowIndex * props.weekdays.length + colIndex;
          const isSelected = isSelectedDay(item);
          const disabled = isDayDisabled(item);
          const rangeStart = range.isRangeStart(item.date);
          const rangeEnd = range.isRangeEnd(item.date);
          const rangeMiddle = range.isRangeMiddle(item.date);
          const previewStart = range.isPreviewStart(item.date);
          const previewEnd = range.isPreviewEnd(item.date);
          const previewMiddle = range.isPreviewMiddle(item.date);
          const slotProps = {
            props: {
              class: 'v-date-picker-month__day-btn',
              color: isSelected && !rangeMiddle || item.isToday ? props.color : undefined,
              disabled,
              readonly: props.readonly,
              icon: true,
              ripple: false,
              tabindex: -1,
              variant: isSelected && !rangeMiddle ? 'flat' : item.isToday ? 'outlined' : 'text',
              'aria-label': getDateAriaLabel(item),
              'aria-current': item.isToday ? 'date' : undefined,
              id: `${uid}-day-${item.isoDate}`,
              'data-v-date': !disabled ? item.isoDate : undefined,
              onMousedown: e => e.preventDefault(),
              // preserve virtual focus
              onClick: () => onDayClick(item),
              onMouseenter: () => range.setPreview(item.date),
              onFocus: () => range.setPreview(item.date),
              onBlur: range.clearPreview
            },
            item,
            i
          };
          const hasRangeBg = rangeStart || rangeEnd || rangeMiddle;
          const hasPreviewBg = previewStart || previewEnd || previewMiddle;
          return vue.createElementVNode("div", {
            "class": vue.normalizeClass(['v-date-picker-month__day', {
              'v-date-picker-month__day--adjacent': item.isAdjacent,
              'v-date-picker-month__day--hide-adjacent': item.isHidden,
              'v-date-picker-month__day--selected': isSelected,
              'v-date-picker-month__day--week-end': item.isWeekEnd,
              'v-date-picker-month__day--week-start': item.isWeekStart,
              'v-date-picker-month__day--range-start': rangeStart,
              'v-date-picker-month__day--range-end': rangeEnd,
              'v-date-picker-month__day--range-middle': rangeMiddle,
              'v-date-picker-month__day--preview-start': previewStart,
              'v-date-picker-month__day--preview-end': previewEnd,
              'v-date-picker-month__day--preview-middle': previewMiddle
            }]),
            "role": "gridcell"
          }, [(hasRangeBg || hasPreviewBg) && vue.createElementVNode("div", {
            "key": "range-bg",
            "class": vue.normalizeClass(['v-date-picker-month__range-bg', hasRangeBg ? 'v-date-picker-month__range-bg--range' : 'v-date-picker-month__range-bg--preview', rangeColorClasses.value]),
            "style": vue.normalizeStyle(rangeColorStyles.value)
          }, null), (props.showAdjacentMonths || !item.isAdjacent) && (slots.day?.(slotProps) ?? vue.createVNode(VBtn, slotProps.props, {
            default: () => [item.localized, genEvents(item.isoDate)]
          }))]);
        })]))])]
      })]));
      return {
        focusGrid,
        focusItem
      };
    }
  });

  // Types

  const makeVDatePickerMonthsProps = propsFactory({
    color: String,
    columns: {
      type: Number,
      default: 2
    },
    height: [String, Number],
    min: null,
    max: null,
    modelValue: Number,
    year: Number,
    allowedMonths: [Array, Function]
  }, 'VDatePickerMonths');
  const VDatePickerMonths = genericComponent()({
    name: 'VDatePickerMonths',
    props: makeVDatePickerMonthsProps(),
    emits: {
      'update:modelValue': date => true,
      escape: () => true
    },
    setup(props, {
      emit,
      slots
    }) {
      const adapter = useDate();
      const model = useProxiedModel(props, 'modelValue');
      const uid = vue.useId();
      const months = vue.computed(() => {
        let date = adapter.startOfYear(adapter.date());
        if (props.year) {
          date = adapter.setYear(date, props.year);
        }
        return createRange(12).map(i => {
          const text = adapter.format(date, 'monthShort');
          const label = adapter.format(date, 'month');
          const isDisabled = !!(!isMonthAllowed(i) || props.min && adapter.isAfter(adapter.startOfMonth(adapter.date(props.min)), date) || props.max && adapter.isAfter(date, adapter.startOfMonth(adapter.date(props.max))));
          date = adapter.getNextMonth(date);
          return {
            isDisabled,
            text,
            label,
            value: i
          };
        });
      });
      vue.watchEffect(() => {
        model.value = model.value ?? adapter.getMonth(adapter.date());
      });
      function isMonthAllowed(month) {
        if (Array.isArray(props.allowedMonths) && props.allowedMonths.length) {
          return props.allowedMonths.includes(month);
        }
        if (typeof props.allowedMonths === 'function') {
          return props.allowedMonths(month);
        }
        return true;
      }
      function onMonthSelect(value) {
        if (model.value === value) emit('update:modelValue', value);else model.value = value;
      }
      const {
        containerProps,
        selectItem
      } = useGridSelection({
        items: () => months.value,
        columns: () => props.columns,
        initialValue: current => current ?? model.value ?? adapter.getMonth(adapter.date()),
        itemAttribute: 'data-v-month',
        onSelect: onMonthSelect,
        onEscape: () => emit('escape')
      });
      useRender(() => vue.createElementVNode("div", {
        "class": "v-date-picker-months",
        "style": {
          height: convertToUnit(props.height)
        }
      }, [vue.createElementVNode("div", vue.mergeProps({
        "class": "v-date-picker-months__content",
        "style": {
          '--v-date-picker-months-columns': props.columns
        }
      }, containerProps.value), [months.value.map((month, i) => {
        const btnProps = {
          id: `${uid}-month-${i}`,
          active: model.value === i,
          ariaLabel: month.label,
          color: model.value === i ? props.color : undefined,
          disabled: month.isDisabled,
          rounded: true,
          tabindex: -1,
          text: month.text,
          variant: model.value === month.value ? 'flat' : 'text',
          'data-v-month': month.value,
          onMousedown: e => e.preventDefault(),
          // preserve virtual focus
          onClick: () => selectItem(i)
        };
        return slots.month?.({
          month,
          i,
          props: btnProps
        }) ?? vue.createVNode(VBtn, vue.mergeProps({
          "key": "month"
        }, btnProps), null);
      })])]));
      return {};
    }
  });

  // Types

  // Types

  const makeVDatePickerYearsProps = propsFactory({
    color: String,
    columns: {
      type: Number,
      default: 3
    },
    height: [String, Number],
    min: null,
    max: null,
    modelValue: Number,
    allowedYears: [Array, Function]
  }, 'VDatePickerYears');
  const VDatePickerYears = genericComponent()({
    name: 'VDatePickerYears',
    props: makeVDatePickerYearsProps(),
    directives: {
      vIntersect: Intersect
    },
    emits: {
      'update:modelValue': year => true,
      escape: () => true
    },
    setup(props, {
      emit,
      slots
    }) {
      const adapter = useDate();
      const model = useProxiedModel(props, 'modelValue');
      const containerRef = templateRef();
      const uid = vue.useId();
      const years = vue.computed(() => {
        const year = adapter.getYear(adapter.date());
        let min = year - 100;
        let max = year + 52;
        if (props.min) {
          min = adapter.getYear(adapter.date(props.min));
        }
        if (props.max) {
          max = adapter.getYear(adapter.date(props.max));
        }
        let date = adapter.startOfYear(adapter.date());
        date = adapter.setYear(date, min);
        return createRange(max - min + 1, min).map(i => {
          const text = adapter.format(date, 'year');
          date = adapter.setYear(date, adapter.getYear(date) + 1);
          return {
            text,
            value: i,
            isDisabled: !isYearAllowed(i)
          };
        });
      });
      vue.watchEffect(() => {
        model.value = model.value ?? adapter.getYear(adapter.date());
      });
      function isYearAllowed(year) {
        if (Array.isArray(props.allowedYears) && props.allowedYears.length) {
          return props.allowedYears.includes(year);
        }
        if (typeof props.allowedYears === 'function') {
          return props.allowedYears(year);
        }
        return true;
      }
      function onYearSelect(value) {
        if (model.value === value) emit('update:modelValue', value);else model.value = value;
      }
      const {
        containerProps,
        containerEl,
        selectItem
      } = useGridSelection({
        items: () => years.value,
        columns: () => props.columns,
        initialValue: current => current ?? model.value ?? adapter.getYear(adapter.date()),
        itemAttribute: 'data-v-year',
        onSelect: onYearSelect,
        onEscape: () => emit('escape')
      });
      function scrollToSelected() {
        const container = containerRef.el;
        const target = containerEl.value?.querySelector(`[data-v-year="${model.value}"]`);
        if (!container || !target) return;
        const containerRect = container.getBoundingClientRect();
        const targetRect = target.getBoundingClientRect();
        container.scrollTop += targetRect.top - containerRect.top - container.clientHeight / 2 + targetRect.height / 2;
      }
      useRender(() => vue.withDirectives(vue.createElementVNode("div", {
        "class": "v-date-picker-years",
        "ref": containerRef,
        "tabindex": -1,
        "style": {
          height: convertToUnit(props.height)
        }
      }, [vue.createElementVNode("div", vue.mergeProps({
        "class": "v-date-picker-years__content",
        "style": {
          '--v-date-picker-years-columns': props.columns
        }
      }, containerProps.value), [years.value.map((year, i) => {
        const btnProps = {
          id: `${uid}-year-${year.value}`,
          active: model.value === year.value,
          color: model.value === year.value ? props.color : undefined,
          rounded: true,
          tabindex: -1,
          text: year.text,
          disabled: year.isDisabled,
          variant: model.value === year.value ? 'flat' : 'text',
          'data-v-year': year.value,
          onMousedown: e => e.preventDefault(),
          // preserve virtual focus
          onClick: () => selectItem(year.value)
        };
        return slots.year?.({
          year,
          i,
          props: btnProps
        }) ?? vue.createVNode(VBtn, vue.mergeProps({
          "key": "month"
        }, btnProps), null);
      })])]), [[Intersect, {
        handler: scrollToSelected
      }, null, {
        once: true
      }]]));
      return {};
    }
  });

  // Types

  // Types

  const makeVDatePickerProps = propsFactory({
    // TODO: implement in v3.5
    // calendarIcon: {
    //   type: String,
    //   default: '$calendar',
    // },
    // keyboardIcon: {
    //   type: String,
    //   default: '$edit',
    // },
    // inputMode: {
    //   type: String as PropType<'calendar' | 'keyboard'>,
    //   default: 'calendar',
    // },
    // inputText: {
    //   type: String,
    //   default: '$vuetify.datePicker.input.placeholder',
    // },
    // inputPlaceholder: {
    //   type: String,
    //   default: 'dd/mm/yyyy',
    // },
    header: {
      type: String,
      default: '$vuetify.datePicker.header'
    },
    headerColor: String,
    headerDateFormat: {
      type: String,
      default: 'normalDateWithWeekday'
    },
    landscapeHeaderWidth: [Number, String],
    ...omit(makeVDatePickerControlsProps(), ['active', 'monthText', 'yearText']),
    ...makeVDatePickerMonthProps({
      weeksInMonth: 'static'
    }),
    ...omit(makeVDatePickerMonthsProps(), ['modelValue', 'columns']),
    ...omit(makeVDatePickerYearsProps(), ['modelValue', 'columns']),
    ...makeVPickerProps({
      title: '$vuetify.datePicker.title'
    }),
    modelValue: null
  }, 'VDatePicker');
  const VDatePicker = genericComponent()({
    name: 'VDatePicker',
    props: makeVDatePickerProps(),
    emits: {
      'update:modelValue': date => true,
      'update:month': date => true,
      'update:year': date => true,
      'update:previewValue': _value => true,
      // 'update:inputMode': (date: any) => true,
      'update:viewMode': date => true,
      'boundary-navigate': _payload => true
    },
    setup(props, {
      emit,
      slots
    }) {
      const adapter = useDate();
      const {
        t
      } = useLocale();
      const {
        rtlClasses
      } = useRtl();
      const model = useProxiedModel(props, 'modelValue', undefined, v => wrapInArray(v).map(i => adapter.date(i)), v => props.multiple ? v : v[0]);
      const viewMode = useProxiedModel(props, 'viewMode');
      // owns the hover preview so VDatePickerMonth isn't handed a prop nobody writes back
      const previewValue = useProxiedModel(props, 'previewValue');
      // const inputMode = useProxiedModel(props, 'inputMode')

      const {
        minDate,
        maxDate,
        clampDate
      } = useCalendarRange(props);
      const internal = vue.computed(() => {
        const today = adapter.date();
        const value = model.value?.[0] ? adapter.date(model.value[0]) : clampDate(today);
        return value && adapter.isValid(value) ? value : today;
      });
      const headerColor = vue.toRef(() => props.headerColor ?? props.color);
      const _month = useProxiedModel(props, 'month');
      const month = vue.computed({
        get: () => Number(_month.value ?? adapter.getMonth(adapter.startOfMonth(internal.value))),
        set: v => _month.value = v
      });
      const _year = useProxiedModel(props, 'year');
      const year = vue.computed({
        get: () => Number(_year.value ?? adapter.getYear(adapter.startOfYear(adapter.setMonth(internal.value, month.value)))),
        set: v => _year.value = v
      });
      const isReversing = vue.shallowRef(false);
      const header = vue.computed(() => {
        if (props.multiple === 'range' && model.value.length === 2) {
          const [startDate, endDate] = model.value;
          const daysBetween = adapter.getDiff(endDate, startDate, 'days') + 1;
          return t('$vuetify.datePicker.itemsSelected', daysBetween);
        }
        if (props.multiple && model.value.length > 1) {
          return t('$vuetify.datePicker.itemsSelected', model.value.length);
        }
        const formattedDate = model.value[0] && adapter.isValid(model.value[0]) ? adapter.format(adapter.date(model.value[0]), props.headerDateFormat) : t(props.header);
        return props.landscape && formattedDate.split(' ').length === 3 ? formattedDate.replace(' ', '\n') : formattedDate;
      });
      const monthStart = vue.toRef(() => {
        let date = adapter.date();
        date = adapter.setDate(date, 1);
        date = adapter.setMonth(date, month.value);
        date = adapter.setYear(date, year.value); // year is not always ISO
        return date;
      });
      const monthYearText = vue.toRef(() => adapter.format(monthStart.value, 'monthAndYear'));
      const monthText = vue.toRef(() => adapter.format(monthStart.value, 'monthShort'));
      const yearText = vue.toRef(() => adapter.format(monthStart.value, 'year'));

      // const headerIcon = toRef(() => props.inputMode === 'calendar' ? props.keyboardIcon : props.calendarIcon)
      const headerTransition = vue.toRef(() => `date-picker-header${isReversing.value ? '-reverse' : ''}-transition`);
      const disabled = vue.computed(() => {
        if (props.disabled) return true;
        const targets = [];
        if (viewMode.value !== 'month') {
          targets.push(...['prev-month', 'next-month', 'prev-year', 'next-year']);
        } else {
          let _date = adapter.date();
          _date = adapter.startOfMonth(_date);
          _date = adapter.setMonth(_date, month.value);
          _date = adapter.setYear(_date, year.value);
          if (minDate.value) {
            const prevMonthEnd = adapter.addDays(adapter.startOfMonth(_date), -1);
            const prevYearEnd = adapter.addDays(adapter.startOfYear(_date), -1);
            adapter.isAfter(minDate.value, prevMonthEnd) && targets.push('prev-month');
            adapter.isAfter(minDate.value, prevYearEnd) && targets.push('prev-year');
          }
          if (maxDate.value) {
            const nextMonthStart = adapter.addDays(adapter.endOfMonth(_date), 1);
            const nextYearStart = adapter.addDays(adapter.endOfYear(_date), 1);
            adapter.isAfter(nextMonthStart, maxDate.value) && targets.push('next-month');
            adapter.isAfter(nextYearStart, maxDate.value) && targets.push('next-year');
          }
        }
        return targets;
      });
      const allowedYears = vue.computed(() => {
        return props.allowedYears || isYearAllowed;
      });
      const allowedMonths = vue.computed(() => {
        return props.allowedMonths || isMonthAllowed;
      });
      function isAllowedInRange(start, end) {
        const allowedDates = props.allowedDates;
        if (typeof allowedDates !== 'function') return true;
        const days = 1 + daysDiff(adapter, start, end);
        for (let i = 0; i < days; i++) {
          if (allowedDates(adapter.addDays(start, i))) return true;
        }
        return false;
      }
      function isYearAllowed(year) {
        if (typeof props.allowedDates === 'function') {
          const startOfYear = adapter.parseISO(`${year}-01-01`);
          return isAllowedInRange(startOfYear, adapter.endOfYear(startOfYear));
        }
        if (Array.isArray(props.allowedDates) && props.allowedDates.length) {
          for (const date of props.allowedDates) {
            if (adapter.getYear(adapter.date(date)) === year) return true;
          }
          return false;
        }
        return true;
      }
      function isMonthAllowed(month) {
        if (typeof props.allowedDates === 'function') {
          const monthTwoDigits = String(month + 1).padStart(2, '0');
          const startOfMonth = adapter.parseISO(`${year.value}-${monthTwoDigits}-01`);
          return isAllowedInRange(startOfMonth, adapter.endOfMonth(startOfMonth));
        }
        if (Array.isArray(props.allowedDates) && props.allowedDates.length) {
          for (const date of props.allowedDates) {
            if (adapter.getYear(adapter.date(date)) === year.value && adapter.getMonth(adapter.date(date)) === month) return true;
          }
          return false;
        }
        return true;
      }

      // function onClickAppend () {
      //   inputMode.value = inputMode.value === 'calendar' ? 'keyboard' : 'calendar'
      // }

      function onClickNextMonth() {
        if (month.value < 11) {
          month.value++;
        } else {
          year.value++;
          month.value = 0;
          onUpdateYear();
        }
        onUpdateMonth();
      }
      function onClickPrevMonth() {
        if (month.value > 0) {
          month.value--;
        } else {
          year.value--;
          month.value = 11;
          onUpdateYear();
        }
        onUpdateMonth();
      }
      function onClickNextYear() {
        year.value++;
        if (maxDate.value) {
          const monthTwoDigits = String(month.value + 1).padStart(2, '0');
          const monthStart = adapter.parseISO(`${year.value}-${monthTwoDigits}-01`);
          if (adapter.isAfter(monthStart, maxDate.value)) {
            month.value = adapter.getMonth(maxDate.value);
          }
        }
        onUpdateYear();
      }
      function onClickPrevYear() {
        year.value--;
        if (minDate.value) {
          const monthTwoDigits = String(month.value + 1).padStart(2, '0');
          const monthStart = adapter.endOfMonth(adapter.parseISO(`${year.value}-${monthTwoDigits}-01`));
          if (adapter.isAfter(minDate.value, monthStart)) {
            month.value = adapter.getMonth(minDate.value);
          }
        }
        onUpdateYear();
      }
      const monthGridRef = vue.shallowRef();
      function focusDate(isoDate) {
        monthGridRef.value?.focusItem(isoDate);
      }
      function onClickDate() {
        viewMode.value = 'month';
      }
      function onEscape() {
        viewMode.value = 'month';
        vue.nextTick(() => monthGridRef.value?.focusGrid());
      }
      function onClickMonth() {
        viewMode.value = viewMode.value === 'months' ? 'month' : 'months';
      }
      function onClickYear() {
        viewMode.value = viewMode.value === 'year' ? 'month' : 'year';
      }
      function onUpdateMonth() {
        if (viewMode.value === 'months') onClickMonth();
      }
      function onUpdateYear() {
        if (viewMode.value === 'year') onClickYear();
      }
      vue.watch(model, (val, oldVal) => {
        if (props.noAutoNavigation) return;
        const arrBefore = wrapInArray(oldVal);
        const arrAfter = wrapInArray(val);
        if (!arrAfter.length) return;
        const before = adapter.date(arrBefore[arrBefore.length - 1]);
        const after = adapter.date(arrAfter[arrAfter.length - 1]);
        if (adapter.isSameDay(before, after)) return;
        const newMonth = adapter.getMonth(after);
        const newYear = adapter.getYear(after);
        if (newMonth !== month.value) {
          month.value = newMonth;
          onUpdateMonth();
        }
        if (newYear !== year.value) {
          year.value = newYear;
          onUpdateYear();
        }
        isReversing.value = adapter.isBefore(before, after);
      });
      useRender(() => {
        const pickerProps = VPicker.filterProps(props);
        const datePickerControlsProps = omit(VDatePickerControls.filterProps(props), ['viewMode']);
        const datePickerHeaderProps = VDatePickerHeader.filterProps(props);
        const datePickerMonthProps = VDatePickerMonth.filterProps(props);
        const datePickerMonthsProps = omit(VDatePickerMonths.filterProps(props), ['modelValue']);
        const datePickerYearsProps = omit(VDatePickerYears.filterProps(props), ['modelValue']);
        const headerProps = {
          color: headerColor.value,
          header: header.value,
          transition: headerTransition.value
        };
        return vue.createVNode(VPicker, vue.mergeProps(pickerProps, {
          "color": headerColor.value,
          "class": ['v-date-picker', `v-date-picker--${viewMode.value}`, {
            'v-date-picker--show-week': props.showWeek
          }, rtlClasses.value, props.class],
          "style": [{
            '--v-date-picker-landscape-header-width': convertToUnit(props.landscapeHeaderWidth)
          }, props.style]
        }), {
          title: () => slots.title?.() ?? vue.createElementVNode("div", {
            "class": "v-date-picker__title"
          }, [t(props.title)]),
          header: () => slots.header ? vue.createVNode(VDefaultsProvider, {
            "defaults": {
              VDatePickerHeader: {
                ...headerProps
              }
            }
          }, {
            default: () => [slots.header?.(headerProps)]
          }) : vue.createVNode(VDatePickerHeader, vue.mergeProps({
            "key": "header"
          }, datePickerHeaderProps, headerProps, {
            "onClick": viewMode.value !== 'month' ? onClickDate : undefined
          }), {
            prepend: slots.prepend,
            append: slots.append
          }),
          default: () => vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VDatePickerControls, vue.mergeProps(datePickerControlsProps, {
            "disabled": disabled.value,
            "viewMode": viewMode.value,
            "text": monthYearText.value,
            "monthText": monthText.value,
            "yearText": yearText.value,
            "onClick:next": onClickNextMonth,
            "onClick:prev": onClickPrevMonth,
            "onClick:nextYear": onClickNextYear,
            "onClick:prevYear": onClickPrevYear,
            "onClick:month": onClickMonth,
            "onClick:year": onClickYear
          }), {
            default: slots.controls
          }), vue.createVNode(VFadeTransition, {
            "hideOnLeave": true
          }, {
            default: () => [viewMode.value === 'months' ? vue.createVNode(VDatePickerMonths, vue.mergeProps({
              "key": "date-picker-months"
            }, datePickerMonthsProps, {
              "modelValue": month.value,
              "onUpdate:modelValue": [$event => month.value = $event, onUpdateMonth],
              "min": minDate.value,
              "max": maxDate.value,
              "year": year.value,
              "allowedMonths": allowedMonths.value,
              "onEscape": onEscape
            }), {
              month: slots.month
            }) : viewMode.value === 'year' ? vue.createVNode(VDatePickerYears, vue.mergeProps({
              "key": "date-picker-years"
            }, datePickerYearsProps, {
              "modelValue": year.value,
              "onUpdate:modelValue": [$event => year.value = $event, onUpdateYear],
              "min": minDate.value,
              "max": maxDate.value,
              "allowedYears": allowedYears.value,
              "onEscape": onEscape
            }), {
              year: slots.year
            }) : vue.createVNode(VDatePickerMonth, vue.mergeProps({
              "ref": monthGridRef,
              "key": "date-picker-month"
            }, datePickerMonthProps, {
              "modelValue": model.value,
              "onUpdate:modelValue": $event => model.value = $event,
              "month": month.value,
              "onUpdate:month": [$event => month.value = $event, onUpdateMonth],
              "year": year.value,
              "onUpdate:year": [$event => year.value = $event, onUpdateYear],
              "previewValue": previewValue.value,
              "onUpdate:previewValue": $event => previewValue.value = $event,
              "onBoundaryNavigate": payload => emit('boundary-navigate', payload),
              "min": minDate.value,
              "max": maxDate.value
            }), {
              day: slots.day
            })]
          })]),
          actions: slots.actions
        });
      });
      return {
        focusDate
      };
    }
  });

  // Composables

  // Types

  // Types

  class DateFormatSpec {
    constructor(order,
    // mdy | dmy | ymd
    separator // / | - | .
    ) {
      this.order = order;
      this.separator = separator;
    }
    get format() {
      return this.order.split('').map(sign => `${sign}${sign}`).join(this.separator).replace('yy', 'yyyy');
    }
    static canBeParsed(v) {
      if (typeof v !== 'string') return false;
      const lowercase = v.toLowerCase();
      return ['y', 'm', 'd'].every(sign => lowercase.includes(sign)) && ['/', '-', '.'].some(sign => v.includes(sign));
    }
    static parse(v) {
      if (!DateFormatSpec.canBeParsed(v)) {
        throw new Error(`[${v}] cannot be parsed into date format specification`);
      }
      const order = v.toLowerCase().split('').filter((c, i, all) => 'dmy'.includes(c) && all.indexOf(c) === i).join('');
      const separator = ['/', '-', '.'].find(sign => v.includes(sign));
      return new DateFormatSpec(order, separator);
    }
  }
  const makeDateFormatProps = propsFactory({
    inputFormat: {
      type: String,
      validator: v => !v || DateFormatSpec.canBeParsed(v)
    }
  }, 'date-format');
  function useDateFormat(props, locale) {
    const adapter = useDate();
    function inferFromLocale() {
      const localeForDateFormat = locale.value ?? 'en-US';
      const formatFromLocale = Intl.DateTimeFormat(localeForDateFormat, {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit'
      }).format(adapter.toJsDate(adapter.parseISO('1999-12-07'))).replace(/(07)|(٠٧)|(٢٩)|(۱۶)|(০৭)/, 'dd').replace(/(12)|(١٢)|(٠٨)|(۰۹)|(১২)/, 'mm').replace(/(1999)|(2542)|(١٩٩٩)|(١٤٢٠)|(۱۳۷۸)|(১৯৯৯)/, 'yyyy').replace(/[^ymd\-/.]/g, '').replace(/\.$/, '');
      if (!DateFormatSpec.canBeParsed(formatFromLocale)) {
        consoleWarn(`Date format inferred from locale [${localeForDateFormat}] is invalid: [${formatFromLocale}]`);
        return 'mm/dd/yyyy';
      }
      return formatFromLocale;
    }
    const currentFormat = vue.toRef(() => {
      return DateFormatSpec.canBeParsed(props.inputFormat) ? DateFormatSpec.parse(props.inputFormat) : DateFormatSpec.parse(inferFromLocale());
    });
    function parseDate(dateString) {
      function parseDateParts(text) {
        const parts = text.trim().split(currentFormat.value.separator);
        return {
          y: Number(parts[currentFormat.value.order.indexOf('y')]),
          m: Number(parts[currentFormat.value.order.indexOf('m')]),
          d: Number(parts[currentFormat.value.order.indexOf('d')])
        };
      }
      function validateDateParts(dateParts) {
        const {
          y: year,
          m: month,
          d: day
        } = dateParts;
        if (!year || !month || !day) return null;
        if (month < 1 || month > 12) return null;
        if (day < 1 || day > 31) return null;
        return {
          year: autoFixYear(year),
          month,
          day
        };
      }
      function autoFixYear(year) {
        const currentYear = adapter.getYear(adapter.date());
        if (year > 100 || currentYear % 100 >= 50) {
          return year;
        }
        const currentCentury = ~~(currentYear / 100) * 100;
        return year < 50 ? currentCentury + year : currentCentury - 100 + year;
      }
      const dateParts = parseDateParts(dateString);
      const validatedParts = validateDateParts(dateParts);
      if (!validatedParts) return null;
      const {
        year,
        month,
        day
      } = validatedParts;
      const pad = v => String(v).padStart(2, '0');
      return adapter.parseISO(`${year}-${pad(month)}-${pad(day)}`);
    }
    function isValid(text) {
      return !!parseDate(text);
    }
    function formatDate(value) {
      const parts = adapter.toISO(value).split('T')[0].split('-');
      return currentFormat.value.order.split('').map(sign => parts['ymd'.indexOf(sign)]).join(currentFormat.value.separator);
    }
    return {
      isValid,
      parseDate,
      formatDate,
      parserFormat: vue.toRef(() => currentFormat.value.format)
    };
  }

  // Types

  // Types

  const makeVDateInputProps = propsFactory({
    displayFormat: {
      type: [Function, String],
      default: undefined
    },
    location: {
      type: String,
      default: 'bottom start'
    },
    menu: Boolean,
    menuProps: Object,
    updateOn: {
      type: Array,
      default: () => ['blur', 'enter']
    },
    pickerProps: Object,
    ...makeDateFormatProps(),
    ...makeDisplayProps({
      mobile: null
    }),
    ...makeFocusProps(),
    ...makeVConfirmEditProps({
      hideActions: true
    }),
    ...makeVTextFieldProps({
      prependIcon: '$calendar'
    }),
    ...omit(makeVDatePickerProps({
      hideHeader: true,
      showAdjacentMonths: true
    }), ['location', 'rounded', 'height', 'minHeight', 'maxHeight'])
  }, 'VDateInput');
  const VDateInput = genericComponent()({
    name: 'VDateInput',
    props: makeVDateInputProps(),
    emits: {
      save: value => true,
      cancel: () => true,
      'update:focused': val => true,
      'update:modelValue': val => true,
      'update:menu': val => true
    },
    setup(props, {
      emit,
      slots
    }) {
      const {
        t
      } = useLocale();
      const adapter = useDate();
      const adapterLocale = vue.computed(() => adapter.locale);
      const {
        isValid,
        parseDate,
        formatDate,
        parserFormat
      } = useDateFormat(props, adapterLocale);
      const {
        mobile
      } = useDisplay(props);
      const {
        InputIcon
      } = useInputIcon(props);
      const {
        clampDate,
        isInAllowedRange
      } = useCalendarRange(props);
      const emptyModelValue = () => props.multiple ? [] : null;
      const model = useProxiedModel(props, 'modelValue', emptyModelValue(), val => Array.isArray(val) ? val.map(item => adapter.toJsDate(item)) : val ? adapter.toJsDate(val) : val, val => Array.isArray(val) ? val.map(item => adapter.date(item)) : val ? adapter.date(val) : val);
      const menu = useProxiedModel(props, 'menu');
      const isEditingInput = vue.shallowRef(false);
      const isFocused = vue.shallowRef(props.focused);
      const vTextFieldRef = vue.ref();
      const disabledActions = vue.ref(['save']);
      function format(date) {
        if (typeof props.displayFormat === 'function') {
          return props.displayFormat(date);
        }
        if (props.displayFormat) {
          return adapter.format(date, props.displayFormat ?? 'keyboardDate');
        }
        return formatDate(date);
      }
      const display = vue.computed(() => {
        const value = wrapInArray(model.value);
        if (!value.length) return null;
        if (props.multiple === true) {
          return t('$vuetify.datePicker.itemsSelected', value.length);
        }
        if (props.multiple === 'range') {
          const start = value[0];
          const end = value[value.length - 1];
          if (!adapter.isValid(start) || !adapter.isValid(end)) return '';
          return `${format(adapter.date(start))} - ${format(adapter.date(end))}`;
        }
        return adapter.isValid(model.value) ? format(adapter.date(model.value)) : '';
      });
      const inputmode = vue.computed(() => {
        if (!mobile.value) return undefined;
        if (isEditingInput.value) return 'text';
        return 'none';
      });
      const isInteractive = vue.computed(() => !props.disabled && !props.readonly);
      const isReadonly = vue.computed(() => {
        if (!props.updateOn.length) return true;
        return !(mobile.value && isEditingInput.value) && props.readonly;
      });
      vue.watch(menu, val => {
        if (val) return;
        isEditingInput.value = false;
        disabledActions.value = ['save'];
      });
      function onKeydown(e) {
        if (e.key !== 'Enter') return;
        if (!menu.value || !isFocused.value) {
          menu.value = true;
        }
        if (props.updateOn.includes('enter') && !props.readonly) {
          onUserInput(e.target);
        }
      }
      function onClick(e) {
        if (props.disabled) return;
        e.preventDefault();
        e.stopPropagation();
        if (menu.value && mobile.value) {
          isEditingInput.value = !props.readonly;
        } else {
          menu.value = true;
        }
      }
      function onCancel() {
        emit('cancel');
        menu.value = false;
        isEditingInput.value = false;
      }
      function onSave(value) {
        emit('save', value);
        menu.value = false;
      }
      function onUpdateDisplayModel(value) {
        if (value != null) return;
        model.value = emptyModelValue();
      }
      function onBlur(e) {
        if (e.relatedTarget?.closest('[data-v-date]')) {
          return; // first click on a day
        }
        if (props.updateOn.includes('blur') && !props.readonly) {
          onUserInput(e.target);
        }

        // When in mobile mode and editing is done (due to keyboard dismissal), close the menu
        if (mobile.value && isEditingInput.value && !isFocused.value) {
          menu.value = false;
          isEditingInput.value = false;
        }
      }
      function onUserInput({
        value
      }) {
        if (!value.trim()) {
          model.value = emptyModelValue();
        } else if (!props.multiple) {
          if (isValid(value)) {
            model.value = clampDate(parseDate(value));
          }
        } else {
          const parts = value.trim().split(/\D+-\D+|[^\d\-/.]+/);
          if (parts.every(isValid)) {
            if (props.multiple === 'range') {
              const [start, stop] = parts.map(parseDate).map(clampDate).toSorted((a, b) => adapter.isAfter(a, b) ? 1 : -1);
              model.value = stop == null ? [start] : [start, adapter.endOfDay(stop)];
            } else {
              model.value = parts.map(parseDate).filter(isInAllowedRange);
            }
          }
        }
      }
      useRender(() => {
        const hasPrepend = !!(props.prependIcon || slots.prepend);
        const confirmEditProps = VConfirmEdit.filterProps(props);
        const datePickerProps = {
          ...VDatePicker.filterProps(omit(props, ['active', 'bgColor', 'color', 'location', 'rounded', 'maxWidth', 'minWidth', 'width'])),
          ...props.pickerProps
        };
        const datePickerSlots = pick(slots, ['title', 'header', 'day', 'month', 'year']);
        const textFieldProps = VTextField.filterProps(omit(props, ['placeholder']));
        return vue.createVNode(VTextField, vue.mergeProps({
          "ref": vTextFieldRef
        }, textFieldProps, {
          "class": ['v-date-input', props.class],
          "style": props.style,
          "modelValue": display.value,
          "inputmode": inputmode.value,
          "placeholder": props.placeholder ?? parserFormat.value,
          "readonly": isReadonly.value,
          "onKeydown": isInteractive.value ? onKeydown : undefined,
          "focused": menu.value || isFocused.value,
          "onBlur": onBlur,
          "validationValue": model.value,
          "onClick:control": onClick,
          "onUpdate:modelValue": onUpdateDisplayModel,
          "onUpdate:focused": event => isFocused.value = event
        }), {
          ...slots,
          default: () => vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VMenu, vue.mergeProps({
            "modelValue": menu.value,
            "onUpdate:modelValue": $event => menu.value = $event,
            "activator": "parent",
            "minWidth": "0",
            "eager": isFocused.value,
            "location": props.location,
            "closeOnContentClick": false,
            "openOnClick": false
          }, props.menuProps), {
            default: () => [vue.createVNode(VConfirmEdit, vue.mergeProps(confirmEditProps, {
              "modelValue": model.value,
              "onUpdate:modelValue": $event => model.value = $event,
              "disabled": disabledActions.value,
              "onSave": onSave,
              "onCancel": onCancel
            }), {
              default: ({
                actions,
                model: proxyModel,
                save,
                cancel,
                isPristine
              }) => {
                function onUpdateModel(value) {
                  if (!props.hideActions) {
                    proxyModel.value = value;
                  } else {
                    model.value = value;
                    if (!props.multiple) {
                      menu.value = false;
                    }
                  }
                  emit('save', value);
                  disabledActions.value = [];
                }
                return vue.createVNode(VDatePicker, vue.mergeProps(datePickerProps, {
                  "modelValue": props.hideActions ? model.value : proxyModel.value,
                  "onUpdate:modelValue": value => onUpdateModel(value),
                  "onMousedown": e => e.preventDefault()
                }), {
                  ...datePickerSlots,
                  actions: !props.hideActions ? () => slots.actions?.({
                    save,
                    cancel,
                    isPristine
                  }) ?? actions() : undefined
                });
              }
            })]
          }), slots.default?.()]),
          prepend: hasPrepend ? prependSlotProps => slots.prepend ? slots.prepend(prependSlotProps) : props.prependIcon && vue.createVNode(InputIcon, {
            "key": "prepend-icon",
            "name": "prepend",
            "tabindex": props['onClick:prepend'] ? undefined : -1,
            "onClick": isInteractive.value ? onClick : undefined
          }, null) : undefined
        });
      });
      return forwardRefs({}, vTextFieldRef);
    }
  });

  // Types

  // Types

  const makeVEmptyStateProps = propsFactory({
    actionText: String,
    bgColor: String,
    color: String,
    icon: IconValue,
    image: String,
    justify: {
      type: String,
      default: 'center'
    },
    headline: String,
    title: String,
    text: String,
    textWidth: {
      type: [Number, String],
      default: 500
    },
    href: String,
    to: String,
    ...makeComponentProps(),
    ...makeDimensionProps(),
    ...makeSizeProps({
      size: undefined
    }),
    ...makeThemeProps()
  }, 'VEmptyState');
  const VEmptyState = genericComponent()({
    name: 'VEmptyState',
    props: makeVEmptyStateProps(),
    emits: {
      'click:action': e => true
    },
    setup(props, {
      emit,
      slots
    }) {
      const {
        themeClasses
      } = provideTheme(props);
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.bgColor);
      const {
        dimensionStyles
      } = useDimension(props);
      const {
        displayClasses
      } = useDisplay();
      function onClickAction(e) {
        emit('click:action', e);
      }
      useRender(() => {
        const hasActions = !!(slots.actions || props.actionText);
        const hasHeadline = !!(slots.headline || props.headline);
        const hasTitle = !!(slots.title || props.title);
        const hasText = !!(slots.text || props.text);
        const hasMedia = !!(slots.media || props.image || props.icon);
        const size = props.size || (props.image ? 200 : 96);
        return vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-empty-state', {
            [`v-empty-state--${props.justify}`]: true
          }, themeClasses.value, backgroundColorClasses.value, displayClasses.value, props.class]),
          "style": vue.normalizeStyle([backgroundColorStyles.value, dimensionStyles.value, props.style])
        }, [hasMedia && vue.createElementVNode("div", {
          "key": "media",
          "class": "v-empty-state__media"
        }, [!slots.media ? vue.createElementVNode(vue.Fragment, null, [props.image ? vue.createVNode(VImg, {
          "key": "image",
          "src": props.image,
          "height": size
        }, null) : props.icon ? vue.createVNode(VIcon, {
          "key": "icon",
          "color": props.color,
          "size": size,
          "icon": props.icon
        }, null) : undefined]) : vue.createVNode(VDefaultsProvider, {
          "key": "media-defaults",
          "defaults": {
            VImg: {
              src: props.image,
              height: size
            },
            VIcon: {
              size,
              icon: props.icon
            }
          }
        }, {
          default: () => [slots.media()]
        })]), hasHeadline && vue.createElementVNode("div", {
          "key": "headline",
          "class": "v-empty-state__headline"
        }, [slots.headline?.() ?? props.headline]), hasTitle && vue.createElementVNode("div", {
          "key": "title",
          "class": "v-empty-state__title"
        }, [slots.title?.() ?? props.title]), hasText && vue.createElementVNode("div", {
          "key": "text",
          "class": "v-empty-state__text",
          "style": {
            maxWidth: convertToUnit(props.textWidth)
          }
        }, [slots.text?.() ?? props.text]), slots.default && vue.createElementVNode("div", {
          "key": "content",
          "class": "v-empty-state__content"
        }, [slots.default()]), hasActions && vue.createElementVNode("div", {
          "key": "actions",
          "class": "v-empty-state__actions"
        }, [vue.createVNode(VDefaultsProvider, {
          "defaults": {
            VBtn: {
              class: 'v-empty-state__action-btn',
              color: props.color ?? 'surface-variant',
              href: props.href,
              text: props.actionText,
              to: props.to
            }
          }
        }, {
          default: () => [slots.actions?.({
            props: {
              onClick: onClickAction
            }
          }) ?? vue.createVNode(VBtn, {
            "onClick": onClickAction
          }, null)]
        })])]);
      });
      return {};
    }
  });

  // Types

  const VExpansionPanelSymbol = Symbol.for('vuetify:v-expansion-panel');

  const makeVExpansionPanelTextProps = propsFactory({
    ...makeComponentProps(),
    ...makeLazyProps()
  }, 'VExpansionPanelText');
  const VExpansionPanelText = genericComponent()({
    name: 'VExpansionPanelText',
    props: makeVExpansionPanelTextProps(),
    setup(props, {
      slots
    }) {
      const expansionPanel = vue.inject(VExpansionPanelSymbol);
      if (!expansionPanel) throw new Error('[Vuetify] v-expansion-panel-text needs to be placed inside v-expansion-panel');
      const {
        hasContent,
        onAfterLeave
      } = useLazy(props, expansionPanel.isSelected);
      useRender(() => vue.createVNode(VExpandTransition, {
        "onAfterLeave": onAfterLeave
      }, {
        default: () => [vue.withDirectives(vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-expansion-panel-text', props.class]),
          "style": vue.normalizeStyle(props.style)
        }, [slots.default && hasContent.value && vue.createElementVNode("div", {
          "class": "v-expansion-panel-text__wrapper"
        }, [slots.default?.()])]), [[vue.vShow, expansionPanel.isSelected.value]])]
      }));
      return {};
    }
  });

  // Types

  const makeVExpansionPanelTitleProps = propsFactory({
    color: String,
    expandIcon: {
      type: IconValue,
      default: '$expand'
    },
    collapseIcon: {
      type: IconValue,
      default: '$collapse'
    },
    hideActions: Boolean,
    focusable: Boolean,
    static: Boolean,
    ripple: {
      type: [Boolean, Object],
      default: false
    },
    readonly: Boolean,
    hover: {
      type: Boolean,
      default: true
    },
    ...makeComponentProps(),
    ...makeDimensionProps()
  }, 'VExpansionPanelTitle');
  const VExpansionPanelTitle = genericComponent()({
    name: 'VExpansionPanelTitle',
    directives: {
      vRipple: Ripple
    },
    props: makeVExpansionPanelTitleProps(),
    setup(props, {
      slots
    }) {
      const expansionPanel = vue.inject(VExpansionPanelSymbol);
      if (!expansionPanel) throw new Error('[Vuetify] v-expansion-panel-title needs to be placed inside v-expansion-panel');
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.color);
      const {
        dimensionStyles
      } = useDimension(props);
      const slotProps = vue.computed(() => ({
        collapseIcon: props.collapseIcon,
        disabled: expansionPanel.disabled.value,
        expanded: expansionPanel.isSelected.value,
        expandIcon: props.expandIcon,
        readonly: props.readonly
      }));
      const icon = vue.toRef(() => expansionPanel.isSelected.value ? props.collapseIcon : props.expandIcon);
      useRender(() => vue.withDirectives(vue.createElementVNode("button", {
        "class": vue.normalizeClass(['v-expansion-panel-title', {
          'v-expansion-panel-title--active': expansionPanel.isSelected.value,
          'v-expansion-panel-title--focusable': props.focusable,
          'v-expansion-panel-title--static': props.static,
          'v-expansion-panel-title--hover': props.hover
        }, backgroundColorClasses.value, props.class]),
        "style": vue.normalizeStyle([backgroundColorStyles.value, dimensionStyles.value, props.style]),
        "type": "button",
        "tabindex": expansionPanel.disabled.value ? -1 : undefined,
        "disabled": expansionPanel.disabled.value,
        "aria-expanded": expansionPanel.isSelected.value,
        "onClick": !props.readonly ? expansionPanel.toggle : undefined
      }, [vue.createElementVNode("span", {
        "class": "v-expansion-panel-title__overlay"
      }, null), slots.default?.(slotProps.value), !props.hideActions && vue.createVNode(VDefaultsProvider, {
        "defaults": {
          VIcon: {
            icon: icon.value
          }
        }
      }, {
        default: () => [vue.createElementVNode("span", {
          "class": "v-expansion-panel-title__icon"
        }, [slots.actions?.(slotProps.value) ?? vue.createVNode(VIcon, null, null)])]
      })]), [[Ripple, props.ripple]]));
      return {};
    }
  });

  const makeVExpansionPanelProps = propsFactory({
    title: String,
    text: String,
    bgColor: String,
    ...makeElevationProps(),
    ...makeGroupItemProps(),
    ...makeRoundedProps(),
    ...makeTagProps(),
    ...makeVExpansionPanelTitleProps(),
    ...makeVExpansionPanelTextProps()
  }, 'VExpansionPanel');
  const VExpansionPanel = genericComponent()({
    name: 'VExpansionPanel',
    props: makeVExpansionPanelProps(),
    emits: {
      'group:selected': val => true
    },
    setup(props, {
      slots
    }) {
      const groupItem = useGroupItem(props, VExpansionPanelSymbol);
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.bgColor);
      const {
        elevationClasses
      } = useElevation(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const isDisabled = vue.toRef(() => groupItem?.disabled.value || props.disabled);
      const selectedIndices = vue.computed(() => groupItem.group.items.value.reduce((arr, item, index) => {
        if (groupItem.group.selected.value.includes(item.id)) arr.push(index);
        return arr;
      }, []));
      const isBeforeSelected = vue.computed(() => {
        const index = groupItem.group.items.value.findIndex(item => item.id === groupItem.id);
        return !groupItem.isSelected.value && selectedIndices.value.some(selectedIndex => selectedIndex - index === 1);
      });
      const isAfterSelected = vue.computed(() => {
        const index = groupItem.group.items.value.findIndex(item => item.id === groupItem.id);
        return !groupItem.isSelected.value && selectedIndices.value.some(selectedIndex => selectedIndex - index === -1);
      });
      vue.provide(VExpansionPanelSymbol, groupItem);
      useRender(() => {
        const hasText = !!(slots.text || props.text);
        const hasTitle = !!(slots.title || props.title);
        const expansionPanelTitleProps = VExpansionPanelTitle.filterProps(props);
        const expansionPanelTextProps = VExpansionPanelText.filterProps(props);
        return vue.createVNode(props.tag, {
          "class": vue.normalizeClass(['v-expansion-panel', {
            'v-expansion-panel--active': groupItem.isSelected.value,
            'v-expansion-panel--before-active': isBeforeSelected.value,
            'v-expansion-panel--after-active': isAfterSelected.value,
            'v-expansion-panel--disabled': isDisabled.value
          }, roundedClasses.value, backgroundColorClasses.value, props.class]),
          "style": vue.normalizeStyle([backgroundColorStyles.value, roundedStyles.value, props.style])
        }, {
          default: () => [vue.createElementVNode("div", {
            "class": vue.normalizeClass(['v-expansion-panel__shadow', ...elevationClasses.value])
          }, null), vue.createVNode(VDefaultsProvider, {
            "defaults": {
              VExpansionPanelTitle: {
                ...expansionPanelTitleProps
              },
              VExpansionPanelText: {
                ...expansionPanelTextProps
              }
            }
          }, {
            default: () => [hasTitle && vue.createVNode(VExpansionPanelTitle, {
              "key": "title"
            }, {
              default: () => [slots.title ? slots.title() : props.title]
            }), hasText && vue.createVNode(VExpansionPanelText, {
              "key": "text"
            }, {
              default: () => [slots.text ? slots.text() : props.text]
            }), slots.default?.()]
          })]
        });
      });
      return {
        groupItem
      };
    }
  });

  // Types

  const allowedVariants = ['default', 'accordion', 'inset', 'popout'];
  const makeVExpansionPanelsProps = propsFactory({
    flat: Boolean,
    gap: [String, Number],
    noDivider: Boolean,
    rounded: [Boolean, Number, String, Array],
    ...makeGroupProps(),
    ...pick(makeVExpansionPanelProps(), ['bgColor', 'collapseIcon', 'color', 'eager', 'elevation', 'expandIcon', 'focusable', 'hideActions', 'hover', 'readonly', 'ripple', 'static', 'tile']),
    ...makeThemeProps(),
    ...makeComponentProps(),
    ...makeTagProps(),
    variant: {
      type: String,
      default: 'default',
      validator: v => allowedVariants.includes(v)
    }
  }, 'VExpansionPanels');
  const VExpansionPanels = genericComponent()({
    name: 'VExpansionPanels',
    props: makeVExpansionPanelsProps(),
    emits: {
      'update:modelValue': val => true
    },
    setup(props, {
      slots
    }) {
      const {
        next,
        prev
      } = useGroup(props, VExpansionPanelSymbol);
      const {
        themeClasses
      } = provideTheme(props);
      const outerRounded = vue.toRef(() => Array.isArray(props.rounded) ? props.rounded[0] : props.rounded);
      const innerRounded = vue.toRef(() => Array.isArray(props.rounded) ? props.rounded[1] : undefined);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(outerRounded);
      const variantClass = vue.toRef(() => props.variant && `v-expansion-panels--variant-${props.variant}`);
      provideDefaults({
        VExpansionPanel: {
          bgColor: vue.toRef(() => props.bgColor),
          collapseIcon: vue.toRef(() => props.collapseIcon),
          color: vue.toRef(() => props.color),
          eager: vue.toRef(() => props.eager),
          elevation: vue.toRef(() => props.elevation),
          expandIcon: vue.toRef(() => props.expandIcon),
          focusable: vue.toRef(() => props.focusable),
          hideActions: vue.toRef(() => props.hideActions),
          hover: vue.toRef(() => props.hover),
          readonly: vue.toRef(() => props.readonly),
          ripple: vue.toRef(() => props.ripple),
          static: vue.toRef(() => props.static)
        }
      });
      useRender(() => vue.createVNode(props.tag, {
        "class": vue.normalizeClass(['v-expansion-panels', {
          'v-expansion-panels--flat': props.flat,
          'v-expansion-panels--tile': props.tile,
          'v-expansion-panels--no-divider': props.noDivider || !!props.gap
        }, themeClasses.value, roundedClasses.value, variantClass.value, props.class]),
        "style": vue.normalizeStyle([roundedStyles.value, {
          '--v-expansion-panels-inner-radius': convertToUnit(innerRounded.value),
          gap: props.gap ? convertToUnit(props.gap) : undefined
        }, props.style])
      }, {
        default: () => [slots.default?.({
          prev,
          next
        })]
      }));
      return {
        next,
        prev
      };
    }
  });

  // Types

  const makeVFabProps = propsFactory({
    app: Boolean,
    appear: Boolean,
    extended: Boolean,
    layout: Boolean,
    offset: Boolean,
    modelValue: {
      type: Boolean,
      default: true
    },
    ...omit(makeVBtnProps({
      active: true
    }), ['location', 'spaced']),
    ...makeLayoutItemProps(),
    ...makeLocationProps(),
    ...makeTransitionProps({
      transition: 'fab-transition'
    })
  }, 'VFab');
  const VFab = genericComponent()({
    name: 'VFab',
    props: makeVFabProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const model = useProxiedModel(props, 'modelValue');
      const height = vue.shallowRef(56);
      const layoutItemStyles = vue.ref();
      const {
        resizeRef
      } = useResizeObserver(entries => {
        if (!entries.length) return;
        height.value = entries[0].target.clientHeight;
      });
      const hasPosition = vue.toRef(() => props.app || props.absolute);
      const position = vue.computed(() => {
        if (!hasPosition.value) return false;
        return props.location?.split(' ').shift() ?? 'bottom';
      });
      const orientation = vue.computed(() => {
        if (!hasPosition.value) return false;
        return props.location?.split(' ')[1] ?? 'end';
      });
      useToggleScope(() => props.app, () => {
        const layout = useLayoutItem({
          id: props.name,
          order: vue.computed(() => parseInt(props.order, 10)),
          position,
          layoutSize: vue.computed(() => props.layout ? height.value + 24 : 0),
          elementSize: vue.computed(() => height.value + 24),
          active: vue.computed(() => props.app && model.value),
          absolute: vue.toRef(() => props.absolute)
        });
        vue.watchEffect(() => {
          layoutItemStyles.value = layout.layoutItemStyles.value;
        });
      });
      const vFabRef = vue.ref();
      useRender(() => {
        const btnProps = VBtn.filterProps(props);
        return vue.createElementVNode("div", {
          "ref": vFabRef,
          "class": vue.normalizeClass(['v-fab', {
            'v-fab--absolute': props.absolute,
            'v-fab--app': !!props.app,
            'v-fab--extended': props.extended,
            'v-fab--offset': props.offset,
            [`v-fab--${position.value}`]: hasPosition.value,
            [`v-fab--${orientation.value}`]: hasPosition.value
          }, props.class]),
          "style": vue.normalizeStyle([props.app ? {
            ...layoutItemStyles.value
          } : {
            height: props.absolute ? '100%' : 'inherit'
          }, props.style])
        }, [vue.createElementVNode("div", {
          "class": "v-fab__container"
        }, [vue.createVNode(MaybeTransition, {
          "appear": props.appear,
          "transition": props.transition
        }, {
          default: () => [vue.withDirectives(vue.createVNode(VBtn, vue.mergeProps({
            "ref": resizeRef
          }, btnProps, {
            "active": undefined,
            "location": undefined
          }), slots), [[vue.vShow, props.active]])]
        })])]);
      });
      return {};
    }
  });

  // Types

  function useFileDrop() {
    function getTransfer(e) {
      return e.dataTransfer ?? e.clipboardData ?? null;
    }
    function hasFilesOrFolders(e) {
      const transfer = getTransfer(e);
      const entries = [...(transfer?.items ?? [])].filter(x => x.kind === 'file').map(x => x.webkitGetAsEntry()).filter(Boolean);
      return entries.length > 0 || [...(transfer?.files ?? [])].length > 0;
    }
    async function handleDrop(e) {
      const transfer = getTransfer(e);
      const result = [];
      const entries = [...(transfer?.items ?? [])].filter(x => x.kind === 'file').map(x => x.webkitGetAsEntry()).filter(Boolean);
      if (entries.length) {
        for (const entry of entries) {
          const files = await traverseFileTree(entry, appendIfDirectory('.', entry));
          result.push(...files.map(x => x.file));
        }
      } else {
        result.push(...[...(transfer?.files ?? [])]);
      }
      return result;
    }
    return {
      handleDrop,
      hasFilesOrFolders
    };
  }
  function traverseFileTree(item, path = '') {
    return new Promise((resolve, reject) => {
      if (item.isFile) {
        const fileEntry = item;
        fileEntry.file(file => resolve([{
          file,
          path
        }]), reject);
      } else if (item.isDirectory) {
        const directoryReader = item.createReader();
        directoryReader.readEntries(async entries => {
          const files = [];
          for (const entry of entries) {
            files.push(...(await traverseFileTree(entry, appendIfDirectory(path, entry))));
          }
          resolve(files);
        });
      }
    });
  }
  function appendIfDirectory(path, item) {
    return item.isDirectory ? `${path}/${item.name}` : path;
  }

  // Utilities
  // Composables
  const makeFileFilterProps = propsFactory({
    filterByType: String
  }, 'file-accept');
  function useFileFilter(props) {
    const fileFilter = vue.computed(() => props.filterByType ? createFilter(props.filterByType) : null);
    function filterAccepted(files) {
      if (fileFilter.value) {
        const accepted = files.filter(fileFilter.value);
        return {
          accepted,
          rejected: files.filter(f => !accepted.includes(f))
        };
      }
      return {
        accepted: files,
        rejected: []
      };
    }
    return {
      filterAccepted
    };
  }
  function createFilter(v) {
    const types = v.split(',').map(x => x.trim().toLowerCase());
    const extensionsToMatch = types.filter(x => x.startsWith('.'));
    const wildcards = types.filter(x => x.endsWith('/*'));
    const typesToMatch = types.filter(x => !extensionsToMatch.includes(x) && !wildcards.includes(x));
    return file => {
      const extension = file.name.split('.').at(-1)?.toLowerCase() ?? '';
      const typeGroup = file.type.split('/').at(0)?.toLowerCase() ?? '';
      return typesToMatch.includes(file.type) || extensionsToMatch.includes(`.${extension}`) || wildcards.includes(`${typeGroup}/*`);
    };
  }

  // Types

  const makeVFileInputProps = propsFactory({
    chips: Boolean,
    counter: Boolean,
    counterSizeString: {
      type: String,
      default: '$vuetify.fileInput.counterSize'
    },
    counterString: {
      type: String,
      default: '$vuetify.fileInput.counter'
    },
    hideInput: Boolean,
    multiple: Boolean,
    showSize: {
      type: [Boolean, Number, String],
      default: false,
      validator: v => {
        return typeof v === 'boolean' || [1000, 1024].includes(Number(v));
      }
    },
    truncateLength: {
      type: [Number, String],
      default: 22
    },
    ...omit(makeVInputProps({
      prependIcon: '$file'
    }), ['direction']),
    modelValue: {
      type: [Array, Object],
      default: props => props.multiple ? [] : null,
      validator: val => {
        return wrapInArray(val).every(v => v != null && typeof v === 'object');
      }
    },
    ...makeFileFilterProps(),
    ...makeVFieldProps({
      clearable: true
    })
  }, 'VFileInput');
  const VFileInput = genericComponent()({
    name: 'VFileInput',
    inheritAttrs: false,
    props: makeVFileInputProps(),
    emits: {
      'click:control': e => true,
      'mousedown:control': e => true,
      'update:focused': focused => true,
      'update:modelValue': files => true,
      rejected: files => true
    },
    setup(props, {
      attrs,
      emit,
      slots
    }) {
      const {
        t
      } = useLocale();
      const {
        filterAccepted
      } = useFileFilter(props);
      const model = useProxiedModel(props, 'modelValue', props.modelValue, val => wrapInArray(val), val => !props.multiple && Array.isArray(val) ? val[0] : val);
      const {
        isFocused,
        focus,
        blur
      } = useFocus(props);
      const base = vue.computed(() => typeof props.showSize !== 'boolean' ? props.showSize : undefined);
      const totalBytes = vue.computed(() => (model.value ?? []).reduce((bytes, {
        size = 0
      }) => bytes + size, 0));
      const totalBytesReadable = vue.computed(() => humanReadableFileSize(totalBytes.value, base.value));
      const fileNames = vue.computed(() => (model.value ?? []).map(file => {
        const {
          name = '',
          size = 0
        } = file;
        const truncatedText = truncateText(name);
        return !props.showSize ? truncatedText : `${truncatedText} (${humanReadableFileSize(size, base.value)})`;
      }));
      const counterValue = vue.computed(() => {
        const fileCount = model.value?.length ?? 0;
        if (props.showSize) return t(props.counterSizeString, fileCount, totalBytesReadable.value);else return t(props.counterString, fileCount);
      });
      const vInputRef = vue.ref();
      const vFieldRef = vue.ref();
      const inputRef = vue.ref();
      const isActive = vue.toRef(() => isFocused.value || props.active);
      const isPlainOrUnderlined = vue.computed(() => ['plain', 'underlined'].includes(props.variant));
      const isDragging = vue.shallowRef(false);
      const {
        handleDrop,
        hasFilesOrFolders
      } = useFileDrop();
      function onFocus() {
        if (inputRef.value !== getActiveElement()) {
          inputRef.value?.focus();
        }
        if (!isFocused.value) focus();
      }
      function onClickPrepend(e) {
        inputRef.value?.click();
      }
      function onControlMousedown(e) {
        emit('mousedown:control', e);
      }
      function onControlClick(e) {
        inputRef.value?.click();
        emit('click:control', e);
      }
      function onClear(e) {
        e.stopPropagation();
        onFocus();
        vue.nextTick(() => {
          model.value = [];
          callEvent(props['onClick:clear'], e);
        });
      }
      function truncateText(str) {
        if (str.length < Number(props.truncateLength)) return str;
        const charsKeepOneSide = Math.floor((Number(props.truncateLength) - 1) / 2);
        return `${str.slice(0, charsKeepOneSide)}…${str.slice(str.length - charsKeepOneSide)}`;
      }
      function onDragover(e) {
        if (props.disabled || props.readonly) return;
        e.preventDefault();
        e.stopImmediatePropagation();
        isDragging.value = true;
      }
      function onDragleave(e) {
        e.preventDefault();
        isDragging.value = false;
      }
      async function onDrop(e) {
        e.preventDefault();
        e.stopImmediatePropagation();
        isDragging.value = false;
        if (!inputRef.value || props.disabled || props.readonly || !hasFilesOrFolders(e)) return;
        const allDroppedFiles = await handleDrop(e);
        selectAccepted(allDroppedFiles);
      }
      async function onPaste(e) {
        if (!inputRef.value || props.disabled || props.readonly || !hasFilesOrFolders(e)) return;
        e.preventDefault();
        const files = await handleDrop(e);
        if (files.length) {
          selectAccepted(files);
        }
      }
      function onFileSelection(e) {
        if (!e.target || e.repack) return; // prevent loop

        if (!props.filterByType) {
          const target = e.target;
          model.value = [...(target.files ?? [])];
        } else {
          selectAccepted([...e.target.files]);
        }
      }
      function selectAccepted(files) {
        const dataTransfer = new DataTransfer();
        const {
          accepted,
          rejected
        } = filterAccepted(files);
        if (rejected.length) {
          emit('rejected', rejected);
        }
        for (const file of accepted) {
          dataTransfer.items.add(file);
        }
        inputRef.value.files = dataTransfer.files;
        model.value = [...dataTransfer.files];
        const event = new Event('change', {
          bubbles: true
        });
        event.repack = true;
        inputRef.value.dispatchEvent(event);
      }
      vue.watch(model, newValue => {
        const hasModelReset = !Array.isArray(newValue) || !newValue.length;
        if (hasModelReset && inputRef.value) {
          inputRef.value.value = '';
        }
      });
      useRender(() => {
        const hasCounter = !!(slots.counter || props.counter);
        const hasDetails = props.hideDetails !== true && !!(slots.details || hasCounter && (props.hideDetails === false || model.value?.length));
        const [rootAttrs, inputAttrs] = filterInputAttrs(attrs);
        const {
          modelValue: _,
          ...inputProps
        } = VInput.filterProps(props);
        const fieldProps = {
          ...VField.filterProps(props),
          'onClick:clear': onClear
        };
        const expectsDirectory = attrs.webkitdirectory !== undefined && attrs.webkitdirectory !== false;
        const acceptFallback = attrs.accept ? String(attrs.accept) : undefined;
        const inputAccept = expectsDirectory ? undefined : props.filterByType ?? acceptFallback;
        return vue.createVNode(VInput, vue.mergeProps({
          "ref": vInputRef,
          "modelValue": props.multiple ? model.value : model.value[0],
          "class": ['v-file-input', {
            'v-file-input--chips': !!props.chips,
            'v-file-input--dragging': isDragging.value,
            'v-file-input--hide': props.hideInput,
            'v-input--plain-underlined': isPlainOrUnderlined.value
          }, props.class],
          "style": props.style,
          "onClick:prepend": onClickPrepend
        }, rootAttrs, inputProps, {
          "centerAffix": !isPlainOrUnderlined.value,
          "focused": isFocused.value,
          "indentDetails": props.indentDetails ?? !isPlainOrUnderlined.value
        }), {
          ...slots,
          default: ({
            id,
            isDisabled,
            isDirty,
            isReadonly,
            isValid,
            hasDetails
          }) => vue.createVNode(VField, vue.mergeProps({
            "ref": vFieldRef,
            "prependIcon": props.prependIcon,
            "onMousedown": onControlMousedown,
            "onClick": onControlClick,
            "onClick:prependInner": props['onClick:prependInner'],
            "onClick:appendInner": props['onClick:appendInner']
          }, fieldProps, {
            "id": id.value,
            "active": isActive.value || isDirty.value,
            "dirty": isDirty.value || props.dirty,
            "disabled": isDisabled.value,
            "focused": isFocused.value,
            "details": hasDetails.value,
            "error": isValid.value === false,
            "onDragover": onDragover,
            "onDrop": onDrop
          }), {
            ...slots,
            default: ({
              props: {
                class: fieldClass,
                ...slotProps
              },
              controlRef
            }) => vue.createElementVNode(vue.Fragment, null, [vue.createElementVNode("input", vue.mergeProps({
              "ref": val => inputRef.value = controlRef.value = val,
              "type": "file",
              "accept": inputAccept,
              "readonly": isReadonly.value,
              "disabled": isDisabled.value,
              "multiple": props.multiple,
              "name": props.name,
              "onClick": e => {
                e.stopPropagation();
                if (isReadonly.value) e.preventDefault();
                onFocus();
              },
              "onChange": onFileSelection,
              "onDragleave": onDragleave,
              "onFocus": onFocus,
              "onBlur": blur,
              "onPaste": onPaste
            }, slotProps, inputAttrs), null), vue.createElementVNode("div", {
              "class": vue.normalizeClass(fieldClass)
            }, [!!model.value?.length && !props.hideInput && (slots.selection ? slots.selection({
              fileNames: fileNames.value,
              totalBytes: totalBytes.value,
              totalBytesReadable: totalBytesReadable.value
            }) : props.chips ? fileNames.value.map(text => vue.createVNode(VChip, {
              "key": text,
              "size": "small",
              "text": text
            }, null)) : fileNames.value.join(', '))])])
          }),
          details: hasDetails ? slotProps => vue.createElementVNode(vue.Fragment, null, [slots.details?.(slotProps), hasCounter && vue.createElementVNode(vue.Fragment, null, [vue.createElementVNode("span", null, null), vue.createVNode(VCounter, {
            "active": !!model.value?.length,
            "value": counterValue.value,
            "disabled": props.disabled
          }, slots.counter)])]) : undefined
        });
      });
      return forwardRefs({}, vInputRef, vFieldRef, inputRef);
    }
  });

  // Types

  const makeVFileUploadItemProps = propsFactory({
    clearable: Boolean,
    file: {
      type: Object,
      default: null
    },
    fileIcon: {
      type: String,
      // TODO: setup up a proper aliased icon
      default: 'mdi-file-document'
    },
    showSize: Boolean,
    ...makeVListItemProps({
      border: true,
      rounded: true,
      lines: 'two'
    })
  }, 'VFileUploadItem');
  const VFileUploadItem = genericComponent()({
    name: 'VFileUploadItem',
    props: makeVFileUploadItemProps(),
    emits: {
      'click:remove': () => true,
      click: e => true
    },
    setup(props, {
      emit,
      slots
    }) {
      const preview = vue.ref();
      const base = vue.computed(() => typeof props.showSize !== 'boolean' ? props.showSize : undefined);
      function onClickRemove() {
        emit('click:remove');
      }
      vue.watchEffect(() => {
        preview.value = props.file?.type.startsWith('image') ? URL.createObjectURL(props.file) : undefined;
      });
      useRender(() => {
        const listItemProps = VListItem.filterProps(props);
        return vue.createVNode(VListItem, vue.mergeProps(listItemProps, {
          "class": ['v-file-upload-item', props.class],
          "title": props.title ?? props.file?.name,
          "subtitle": props.showSize ? humanReadableFileSize(props.file?.size, base.value) : props.file?.type,
          "style": props.style
        }), {
          ...slots,
          title: slots.title ?? (() => props?.title ?? props.file?.name),
          prepend: slotProps => vue.createElementVNode(vue.Fragment, null, [!slots.prepend ? vue.createVNode(VAvatar, {
            "icon": props.fileIcon,
            "image": preview.value,
            "rounded": true
          }, null) : vue.createVNode(VDefaultsProvider, {
            "defaults": {
              VAvatar: {
                image: preview.value,
                icon: !preview.value ? props.fileIcon : undefined,
                rounded: true
              }
            }
          }, {
            default: () => [slots.prepend?.(slotProps) ?? vue.createVNode(VAvatar, null, null)]
          })]),
          append: slotProps => vue.createElementVNode(vue.Fragment, null, [props.clearable && vue.createElementVNode(vue.Fragment, null, [!slots.clear ? vue.createVNode(VBtn, {
            "icon": "$clear",
            "density": "comfortable",
            "variant": "text",
            "onClick": onClickRemove
          }, null) : vue.createVNode(VDefaultsProvider, {
            "defaults": {
              VBtn: {
                icon: '$clear',
                density: 'comfortable',
                variant: 'text'
              }
            }
          }, {
            default: () => [slots.clear?.({
              ...slotProps,
              props: {
                onClick: onClickRemove
              }
            }) ?? vue.createVNode(VBtn, null, null)]
          })]), slots.append?.(slotProps)])
        });
      });
    }
  });

  let nextId = 0;
  const fileIds = new WeakMap();
  function getFileKey(file) {
    let id = fileIds.get(file);
    if (id == null) {
      id = ++nextId;
      fileIds.set(file, id);
    }
    return id;
  }

  // Types

  const VFileUploadKey = Symbol.for('vuetify:file-upload');
  const makeVFileUploadDropzoneProps = propsFactory({
    browseText: {
      type: String,
      default: '$vuetify.fileUpload.browse'
    },
    dividerText: {
      type: String,
      default: '$vuetify.fileUpload.divider'
    },
    title: {
      type: String,
      default: '$vuetify.fileUpload.title'
    },
    subtitle: String,
    icon: {
      type: IconValue,
      default: '$upload'
    },
    clearable: Boolean,
    disabled: Boolean,
    readonly: Boolean,
    error: Boolean,
    hideBrowse: Boolean,
    insetFileList: Boolean,
    multiple: Boolean,
    scrim: {
      type: [Boolean, String],
      default: true
    },
    showSize: Boolean,
    ...makeDelayProps(),
    ...makeDensityProps(),
    ...pick(makeVDividerProps({
      length: 150
    }), ['length', 'thickness', 'opacity']),
    ...makeVSheetProps(),
    modelValue: {
      type: Array,
      default: () => []
    }
  }, 'VFileUploadDropzone');
  const VFileUploadDropzone = genericComponent()({
    name: 'VFileUploadDropzone',
    props: makeVFileUploadDropzoneProps(),
    emits: {
      'click:browse': () => true,
      'click:remove': index => true,
      drop: files => true
    },
    setup(props, {
      emit,
      slots
    }) {
      const {
        t
      } = useLocale();
      const {
        densityClasses
      } = useDensity(props);
      const {
        handleDrop,
        hasFilesOrFolders
      } = useFileDrop();
      const context = vue.inject(VFileUploadKey, null);
      const vSheetRef = vue.ref();
      const isDragging = vue.shallowRef(false);
      const isDisabled = vue.toRef(() => context?.disabled.value ?? props.disabled);
      const isReadonly = vue.toRef(() => context?.readonly.value ?? props.readonly);
      const isInteractive = vue.toRef(() => !isDisabled.value && !isReadonly.value);
      function onDragover(e) {
        if (!isInteractive.value) return;
        e.preventDefault();
        e.stopImmediatePropagation();
        isDragging.value = true;
      }
      function onDragleave(e) {
        e.preventDefault();
        const container = e.currentTarget;
        if (!container.contains(e.relatedTarget)) {
          isDragging.value = false;
        }
      }
      async function onDrop(e) {
        e.preventDefault();
        e.stopImmediatePropagation();
        isDragging.value = false;
        if (!isInteractive.value || !hasFilesOrFolders(e)) return;
        const files = await handleDrop(e);
        if (context) {
          context.onDrop(files);
        } else {
          emit('drop', files);
        }
      }
      function onClickBrowse() {
        if (!isInteractive.value) return;
        if (context) {
          context.onClickBrowse();
        } else {
          emit('click:browse');
        }
      }
      function onKeydown(e) {
        if (!isInteractive.value) return;
        if (e.key === 'Enter' || e.key === ' ') {
          e.preventDefault();
          onClickBrowse();
        }
      }
      function onClickRemove(index) {
        if (!isInteractive.value) return;
        if (context) {
          context.onClickRemove(index);
        } else {
          emit('click:remove', index);
        }
      }
      async function onPaste(e) {
        if (!isInteractive.value || !hasFilesOrFolders(e)) return;
        e.preventDefault();
        const files = await handleDrop(e);
        if (!files.length) return;
        if (context) {
          context.onDrop(files);
        } else {
          emit('drop', files);
        }
      }
      useRender(() => {
        const modelValue = context?.files.value ?? props.modelValue;
        const disabled = isDisabled.value;
        const readonly = isReadonly.value;
        const interactive = isInteractive.value;
        const error = context?.error.value || props.error;
        const hasTitle = !!(slots.title || props.title);
        const hasIcon = !!(slots.icon || props.icon);
        const hasBrowse = !!(!props.hideBrowse && (slots.browse || props.density === 'default'));
        const hasFiles = modelValue.length > 0;
        const isInset = props.insetFileList && hasFiles;
        const sheetProps = VSheet.filterProps(props);
        const dividerProps = VDivider.filterProps(props);
        return vue.createVNode(VSheet, vue.mergeProps({
          "ref": vSheetRef,
          "tabindex": disabled ? -1 : 0
        }, sheetProps, {
          "class": ['v-file-upload-dropzone', {
            'v-file-upload-dropzone--clickable': !hasBrowse,
            'v-file-upload-dropzone--disabled': disabled,
            'v-file-upload-dropzone--readonly': readonly,
            'v-file-upload-dropzone--dragging': isDragging.value,
            'v-file-upload-dropzone--has-files': hasFiles,
            'v-file-upload-dropzone--inset': isInset,
            'v-file-upload-dropzone--error': error
          }, densityClasses.value, props.class],
          "style": props.style,
          "onDragleave": onDragleave,
          "onDragover": onDragover,
          "onDrop": onDrop,
          "onPaste": onPaste,
          "onClick": !hasBrowse && !(isInset && hasFiles) ? onClickBrowse : undefined,
          "onKeydown": onKeydown
        }), {
          default: () => [slots.default?.({
            isDragging: isDragging.value,
            hasFiles,
            files: modelValue,
            props: {
              onClick: onClickBrowse
            }
          }) ?? (isInset ? vue.createElementVNode("div", {
            "key": "inset",
            "class": "v-file-upload-inset"
          }, [modelValue.length === 1 && !props.multiple ? slots.single?.({
            file: modelValue[0],
            props: {
              'onClick:remove': () => onClickRemove(0)
            }
          }) ?? vue.createVNode(VDefaultsProvider, {
            "defaults": {
              VFileUploadItem: {
                file: modelValue[0],
                clearable: props.clearable && !readonly,
                disabled,
                showSize: props.showSize,
                border: false
              }
            }
          }, {
            default: () => [vue.createVNode(VFileUploadItem, {
              "onClick:remove": () => onClickRemove(0)
            }, null)]
          }) : modelValue.map((file, i) => {
            const key = getFileKey(file);
            const slotProps = {
              file,
              props: {
                'onClick:remove': () => onClickRemove(i)
              }
            };
            return vue.createVNode(VDefaultsProvider, {
              "key": key,
              "defaults": {
                VFileUploadItem: {
                  file,
                  clearable: props.clearable && !readonly,
                  disabled,
                  showSize: props.showSize,
                  border: false
                }
              }
            }, {
              default: () => [slots.item?.(slotProps) ?? vue.createVNode(VFileUploadItem, {
                "key": key,
                "onClick:remove": () => onClickRemove(i)
              }, null)]
            });
          }), vue.createVNode(VDivider, null, null), vue.createElementVNode("div", {
            "class": "v-file-upload-inset__action"
          }, [!slots.browse ? vue.createVNode(VBtn, {
            "readonly": !interactive,
            "text": t(props.browseText),
            "variant": "text",
            "onClick": onClickBrowse
          }, null) : vue.createVNode(VDefaultsProvider, {
            "defaults": {
              VBtn: {
                readonly: !interactive,
                text: t(props.browseText),
                variant: 'text'
              }
            }
          }, {
            default: () => [slots.browse({
              props: {
                onClick: onClickBrowse
              }
            })]
          })])]) : vue.createElementVNode(vue.Fragment, null, [hasIcon && vue.createElementVNode("div", {
            "key": "icon",
            "class": "v-file-upload-icon"
          }, [!slots.icon ? vue.createVNode(VIcon, {
            "key": "icon-icon",
            "icon": props.icon
          }, null) : vue.createVNode(VDefaultsProvider, {
            "key": "icon-defaults",
            "defaults": {
              VIcon: {
                icon: props.icon
              }
            }
          }, {
            default: () => [slots.icon()]
          })]), hasTitle && vue.createElementVNode("div", {
            "key": "title",
            "class": "v-file-upload-title"
          }, [slots.title?.() ?? t(props.title)]), props.density === 'default' && vue.createElementVNode(vue.Fragment, null, [hasBrowse && vue.createElementVNode(vue.Fragment, null, [vue.createElementVNode("div", {
            "key": "upload-divider",
            "class": "v-file-upload-divider"
          }, [slots.divider?.() ?? vue.createVNode(VDivider, dividerProps, {
            default: () => [t(props.dividerText)]
          })]), !slots.browse ? vue.createVNode(VBtn, {
            "readonly": !interactive,
            "size": "large",
            "text": t(props.browseText),
            "variant": "tonal",
            "onClick": onClickBrowse
          }, null) : vue.createVNode(VDefaultsProvider, {
            "defaults": {
              VBtn: {
                readonly: !interactive,
                size: 'large',
                text: t(props.browseText),
                variant: 'tonal'
              }
            }
          }, {
            default: () => [slots.browse({
              props: {
                onClick: onClickBrowse
              }
            })]
          })]), props.subtitle && vue.createElementVNode("div", {
            "class": "v-file-upload-subtitle"
          }, [props.subtitle])])])), vue.createVNode(VOverlay, {
            "modelValue": isDragging.value,
            "contained": true,
            "scrim": props.scrim
          }, null), slots.input?.(), slots.loader?.()]
        });
      });
      return forwardRefs({}, vSheetRef);
    }
  });

  // Types

  const makeVFileUploadListProps = propsFactory({
    clearable: Boolean,
    showSize: Boolean,
    files: Array,
    ...makeVListProps({
      border: false,
      elevation: 0,
      lines: false
    })
  }, 'VFileUploadList');
  const VFileUploadList = genericComponent()({
    name: 'VFileUploadList',
    props: makeVFileUploadListProps(),
    setup(props, {
      slots
    }) {
      const context = vue.inject(VFileUploadKey, null);
      useRender(() => {
        const files = props.files ?? context?.files.value ?? [];
        const disabled = context?.disabled.value ?? props.disabled;
        const readonly = context?.readonly.value ?? false;
        const listProps = VList.filterProps(props);
        if (!slots.default && !files.length) return vue.createCommentVNode();
        return vue.createVNode(VList, vue.mergeProps(listProps, {
          "disabled": disabled,
          "class": ['v-file-upload-list', props.class],
          "style": props.style,
          "bgColor": "transparent"
        }), {
          default: () => [slots.default?.({
            files,
            onClickRemove: i => context?.onClickRemove(i)
          }) ?? files.map((file, index) => {
            const key = getFileKey(file);
            const slotProps = {
              file,
              props: {
                'onClick:remove': () => context?.onClickRemove(index)
              }
            };
            return vue.createVNode(VDefaultsProvider, {
              "key": key,
              "defaults": {
                VFileUploadItem: {
                  file,
                  clearable: props.clearable && !readonly,
                  disabled,
                  showSize: props.showSize,
                  variant: 'flat'
                }
              }
            }, {
              default: () => [slots.item?.(slotProps) ?? vue.createVNode(VFileUploadItem, {
                "key": key,
                "onClick:remove": () => context?.onClickRemove(index)
              }, null)]
            });
          })]
        });
      });
    }
  });

  // Types

  const makeVFileUploadProps = propsFactory({
    browseText: {
      type: String,
      default: '$vuetify.fileUpload.browse'
    },
    dividerText: {
      type: String,
      default: '$vuetify.fileUpload.divider'
    },
    title: {
      type: String,
      default: '$vuetify.fileUpload.title'
    },
    subtitle: String,
    icon: {
      type: IconValue,
      default: '$upload'
    },
    clearable: Boolean,
    insetFileList: Boolean,
    hideBrowse: Boolean,
    multiple: Boolean,
    scrim: {
      type: [Boolean, String],
      default: true
    },
    showSize: Boolean,
    ...makeFileFilterProps(),
    ...makeLoaderProps(),
    ...omit(makeVInputProps(), ['direction']),
    modelValue: {
      type: [Array, Object],
      default: null,
      validator: val => {
        return wrapInArray(val).every(v => v != null && typeof v === 'object');
      }
    }
  }, 'VFileUpload');
  const VFileUpload = genericComponent()({
    name: 'VFileUpload',
    inheritAttrs: false,
    props: makeVFileUploadProps(),
    emits: {
      'update:modelValue': files => true,
      'update:focused': focused => true,
      rejected: files => true
    },
    setup(props, {
      attrs,
      emit,
      slots
    }) {
      const {
        filterAccepted
      } = useFileFilter(props);
      const {
        isFocused
      } = useFocus(props);
      const {
        loaderClasses
      } = useLoader(props);
      const form = useForm(props);
      const model = useProxiedModel(props, 'modelValue', props.modelValue, val => wrapInArray(val), val => props.multiple || Array.isArray(props.modelValue) ? val : val[0]);
      const vInputRef = vue.ref();
      const vDropzoneRef = vue.ref();
      const inputRef = vue.ref(null);
      const isError = vue.toRef(() => vInputRef.value?.isValid === false);
      const isInteractive = vue.toRef(() => !form.isDisabled.value && !form.isReadonly.value);
      const loadingColor = vue.shallowRef(undefined);
      vue.watch(() => props.loading, (val, old) => {
        loadingColor.value = !val && typeof old === 'string' ? old : typeof val === 'boolean' ? undefined : val;
      }, {
        immediate: true
      });
      vue.provide(VFileUploadKey, {
        files: model,
        disabled: form.isDisabled,
        readonly: form.isReadonly,
        error: isError,
        onDrop,
        onClickBrowse: onClick,
        onClickRemove
      });
      vue.watch(model, newValue => {
        const hasModelReset = !Array.isArray(newValue) || !newValue.length;
        if (hasModelReset && inputRef.value) {
          inputRef.value.value = '';
        }
      });
      function onDrop(files) {
        if (!isInteractive.value) return;
        selectAccepted(files);
      }
      function onFileSelection(e) {
        if (!e.target || e.repack) return; // prevent loop
        const target = e.target;
        const selectedFiles = [...(target.files ?? [])];
        if (!selectedFiles.length) return;
        if (!props.filterByType) {
          model.value = props.multiple ? [...model.value, ...selectedFiles] : selectedFiles;
        } else {
          selectAccepted(selectedFiles);
        }
      }
      function selectAccepted(files) {
        const dataTransfer = new DataTransfer();
        const {
          accepted,
          rejected
        } = filterAccepted(files);
        if (rejected.length) {
          emit('rejected', rejected);
        }
        for (const file of accepted) {
          dataTransfer.items.add(file);
        }
        inputRef.value.files = dataTransfer.files;
        const newFiles = [...dataTransfer.files];
        model.value = props.multiple ? [...model.value, ...newFiles] : newFiles;
        const event = new Event('change', {
          bubbles: true
        });
        event.repack = true;
        inputRef.value.dispatchEvent(event);
      }
      function onClick() {
        if (!isInteractive.value) return;
        inputRef.value?.click();
      }
      function onClickRemove(index) {
        if (!isInteractive.value) return;
        const newValue = model.value.filter((_, i) => i !== index);
        model.value = newValue;
        if (newValue.length > 0 || !inputRef.value) return;
        inputRef.value.value = '';
      }
      useRender(() => {
        const {
          modelValue: _,
          ...inputProps
        } = VInput.filterProps(props);
        const {
          modelValue: __,
          ...dropzoneProps
        } = VFileUploadDropzone.filterProps(props);
        const [rootAttrs, inputAttrs] = filterInputAttrs(attrs);
        const expectsDirectory = attrs.webkitdirectory !== undefined && attrs.webkitdirectory !== false;
        const acceptFallback = attrs.accept ? String(attrs.accept) : undefined;
        const inputAccept = expectsDirectory ? undefined : props.filterByType ?? acceptFallback;
        const inputNode = vue.createElementVNode("input", vue.mergeProps({
          "ref": inputRef,
          "type": "file",
          "accept": inputAccept,
          "disabled": props.disabled ?? undefined,
          "multiple": props.multiple,
          "name": props.name,
          "onChange": onFileSelection
        }, inputAttrs), null);
        return vue.createVNode(VInput, vue.mergeProps({
          "ref": vInputRef,
          "modelValue": props.multiple ? model.value : model.value[0],
          "onUpdate:modelValue": val => {
            if (val == null || Array.isArray(val) && !val.length) {
              model.value = [];
            }
          },
          "class": ['v-file-upload', loaderClasses.value, props.class],
          "style": props.style,
          "focused": isFocused.value
        }, rootAttrs, inputProps), {
          ...slots,
          default: () => {
            return vue.createElementVNode(vue.Fragment, null, [slots.default ? vue.createElementVNode(vue.Fragment, null, [slots.default(), vue.createElementVNode("input", vue.mergeProps({
              "ref": inputRef,
              "type": "file",
              "accept": inputAccept,
              "disabled": props.disabled ?? undefined,
              "multiple": props.multiple,
              "name": props.name,
              "style": "display: none;",
              "onChange": onFileSelection
            }, inputAttrs), null)]) : vue.createVNode(VFileUploadDropzone, vue.mergeProps({
              "ref": vDropzoneRef
            }, dropzoneProps), {
              browse: slots.browse,
              icon: slots.icon,
              title: slots.title,
              divider: slots.divider,
              single: slots.single,
              item: slots.item,
              input: () => slots.input?.({
                inputNode
              }) ?? inputNode,
              loader: () => vue.createVNode(LoaderSlot, {
                "name": "v-file-upload",
                "active": !!props.loading,
                "color": loadingColor.value
              }, {
                default: slots.loader
              })
            }), !slots.default && !props.insetFileList && vue.createVNode(VDefaultsProvider, {
              "defaults": {
                VFileUploadList: {
                  clearable: props.clearable,
                  showSize: props.showSize
                }
              }
            }, {
              default: () => [vue.createVNode(VFileUploadList, null, {
                item: slots.item
              })]
            })]);
          }
        });
      });
      return forwardRefs({
        controlRef: inputRef
      }, vInputRef, vDropzoneRef);
    }
  });

  const makeVFooterProps = propsFactory({
    app: Boolean,
    color: String,
    height: {
      type: [Number, String],
      default: 'auto'
    },
    ...makeBorderProps(),
    ...makeComponentProps(),
    ...makeElevationProps(),
    ...makeLayoutItemProps(),
    ...makeRoundedProps(),
    ...makeTagProps({
      tag: 'footer'
    }),
    ...makeThemeProps()
  }, 'VFooter');
  const VFooter = genericComponent()({
    name: 'VFooter',
    props: makeVFooterProps(),
    setup(props, {
      slots
    }) {
      const layoutItemStyles = vue.ref();
      const {
        themeClasses
      } = provideTheme(props);
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.color);
      const {
        borderClasses
      } = useBorder(props);
      const {
        elevationClasses
      } = useElevation(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const autoHeight = vue.shallowRef(32);
      const {
        resizeRef
      } = useResizeObserver(entries => {
        if (!entries.length) return;
        autoHeight.value = entries[0].target.clientHeight;
      });
      const height = vue.computed(() => props.height === 'auto' ? autoHeight.value : parseInt(props.height, 10));
      useToggleScope(() => props.app, () => {
        const layout = useLayoutItem({
          id: props.name,
          order: vue.computed(() => parseInt(props.order, 10)),
          position: vue.toRef(() => 'bottom'),
          layoutSize: height,
          elementSize: vue.computed(() => props.height === 'auto' ? undefined : height.value),
          active: vue.toRef(() => props.app),
          absolute: vue.toRef(() => props.absolute)
        });
        vue.watchEffect(() => {
          layoutItemStyles.value = layout.layoutItemStyles.value;
        });
      });
      useRender(() => vue.createVNode(props.tag, {
        "ref": resizeRef,
        "class": vue.normalizeClass(['v-footer', themeClasses.value, backgroundColorClasses.value, borderClasses.value, elevationClasses.value, roundedClasses.value, props.class]),
        "style": vue.normalizeStyle([backgroundColorStyles.value, props.app ? layoutItemStyles.value : {
          height: convertToUnit(props.height)
        }, roundedStyles.value, props.style])
      }, slots));
      return {};
    }
  });

  // Types

  const makeVFormProps = propsFactory({
    ...makeComponentProps(),
    ...makeFormProps()
  }, 'VForm');
  const VForm = genericComponent()({
    name: 'VForm',
    props: makeVFormProps(),
    emits: {
      'update:modelValue': val => true,
      submit: e => true
    },
    setup(props, {
      slots,
      emit
    }) {
      const form = createForm(props);
      const formRef = vue.ref();
      function onReset(e) {
        e.preventDefault();
        form.reset();
      }
      function onSubmit(_e) {
        const e = _e;
        const ready = form.validate();
        e.then = ready.then.bind(ready);
        e.catch = ready.catch.bind(ready);
        e.finally = ready.finally.bind(ready);
        emit('submit', e);
        if (!e.defaultPrevented) {
          ready.then(({
            valid
          }) => {
            if (valid) {
              formRef.value?.submit();
            }
          });
        }
        e.preventDefault();
      }
      useRender(() => vue.createElementVNode("form", {
        "ref": formRef,
        "class": vue.normalizeClass(['v-form', props.class]),
        "style": vue.normalizeStyle(props.style),
        "novalidate": true,
        "onReset": onReset,
        "onSubmit": onSubmit
      }, [slots.default?.({
        get errors() {
          return form.errors.value;
        },
        get isDisabled() {
          return form.isDisabled.value;
        },
        get isReadonly() {
          return form.isReadonly.value;
        },
        get isValidating() {
          return form.isValidating.value;
        },
        get isValid() {
          return form.isValid.value;
        },
        get items() {
          return form.items.value;
        },
        validate: form.validate,
        reset: form.reset,
        resetValidation: form.resetValidation
      })]));
      return forwardRefs(form, formRef);
    }
  });

  const makeVKbdProps = propsFactory({
    color: String,
    ...makeBorderProps(),
    ...makeComponentProps(),
    ...makeRoundedProps(),
    ...makeTagProps({
      tag: 'kbd'
    }),
    ...makeThemeProps(),
    ...makeElevationProps()
  }, 'VKbd');
  const VKbd = genericComponent()({
    name: 'VKbd',
    props: makeVKbdProps(),
    setup(props, {
      slots
    }) {
      const {
        themeClasses
      } = provideTheme(props);
      const {
        borderClasses
      } = useBorder(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.color);
      const {
        elevationClasses
      } = useElevation(props);
      useRender(() => vue.createVNode(props.tag, {
        "class": vue.normalizeClass(['v-kbd', themeClasses.value, backgroundColorClasses.value, borderClasses.value, elevationClasses.value, roundedClasses.value, props.class]),
        "style": vue.normalizeStyle([backgroundColorStyles.value, roundedStyles.value, props.style])
      }, slots));
      return {};
    }
  });

  // Types

  // Display mode types for different visual representations

  // Extended variant type that includes our custom 'contained' variant

  // Key display tuple: [mode, content] where content is string or IconValue

  // Key tuple: [mode, content, keycode] where content is string or IconValue

  function processKey(config, requestedMode, isMac) {
    const keyCfg = isMac && config.mac ? config.mac : config.default;

    // 1. Resolve the safest display mode for the current platform
    const mode = (() => {
      // If the requested mode lacks an asset, fall back to text
      if (requestedMode === 'icon' && !keyCfg.icon) return 'text';
      if (requestedMode === 'symbol' && !keyCfg.symbol) return 'text';
      return requestedMode;
    })();

    // 2. Pick value for the chosen mode, defaulting to text representation
    let value = keyCfg[mode] ?? keyCfg.text;

    // 3. Guard against icon tokens leaking into text mode (e.g. "$ctrl")
    if (mode === 'text' && typeof value === 'string' && value.startsWith('$') && !value.startsWith('$vuetify.')) {
      value = value.slice(1).toUpperCase(); // "$ctrl" → "CTRL"
    }
    return mode === 'icon' ? ['icon', value] : [mode, value];
  }
  const hotkeyMap = {
    ctrl: {
      mac: {
        symbol: '⌃',
        icon: '$ctrl',
        text: '$vuetify.hotkey.ctrl'
      },
      default: {
        text: 'Ctrl'
      }
    },
    meta: {
      mac: {
        symbol: '⌘',
        icon: '$command',
        text: '$vuetify.hotkey.command'
      },
      default: {
        text: 'Ctrl'
      }
    },
    cmd: {
      mac: {
        symbol: '⌘',
        icon: '$command',
        text: '$vuetify.hotkey.command'
      },
      default: {
        text: 'Ctrl'
      }
    },
    shift: {
      mac: {
        symbol: '⇧',
        icon: '$shift',
        text: '$vuetify.hotkey.shift'
      },
      default: {
        text: 'Shift'
      }
    },
    alt: {
      mac: {
        symbol: '⌥',
        icon: '$alt',
        text: '$vuetify.hotkey.option'
      },
      default: {
        text: 'Alt'
      }
    },
    enter: {
      default: {
        symbol: '↵',
        icon: '$enter',
        text: '$vuetify.hotkey.enter'
      }
    },
    arrowup: {
      default: {
        symbol: '↑',
        icon: '$arrowup',
        text: '$vuetify.hotkey.upArrow'
      }
    },
    arrowdown: {
      default: {
        symbol: '↓',
        icon: '$arrowdown',
        text: '$vuetify.hotkey.downArrow'
      }
    },
    arrowleft: {
      default: {
        symbol: '←',
        icon: '$arrowleft',
        text: '$vuetify.hotkey.leftArrow'
      }
    },
    arrowright: {
      default: {
        symbol: '→',
        icon: '$arrowright',
        text: '$vuetify.hotkey.rightArrow'
      }
    },
    backspace: {
      default: {
        symbol: '⌫',
        icon: '$backspace',
        text: '$vuetify.hotkey.backspace'
      }
    },
    escape: {
      default: {
        text: '$vuetify.hotkey.escape'
      }
    },
    ' ': {
      mac: {
        symbol: '␣',
        icon: '$space',
        text: '$vuetify.hotkey.space'
      },
      default: {
        text: '$vuetify.hotkey.space'
      }
    },
    '-': {
      default: {
        text: '-'
      }
    },
    '+': {
      default: {
        text: '+'
      }
    }
  };
  const makeVHotkeyProps = propsFactory({
    // String representing keyboard shortcuts (e.g., "ctrl+k", "meta+shift+p")
    keys: String,
    // How to display keys: 'symbol' uses special characters (⌘, ⌃), 'icon' uses SVG icons, 'text' uses words
    displayMode: {
      type: String,
      default: 'icon'
    },
    // Custom key mapping configuration. Users can import and modify the exported hotkeyMap as needed
    keyMap: {
      type: Object,
      default: () => hotkeyMap
    },
    platform: {
      type: String,
      default: 'auto'
    },
    inline: Boolean,
    disabled: Boolean,
    prefix: String,
    suffix: String,
    variant: {
      type: String,
      default: 'elevated',
      validator: v => ['elevated', 'flat', 'tonal', 'outlined', 'text', 'plain', 'contained'].includes(v)
    },
    ...makeComponentProps(),
    ...makeThemeProps(),
    ...makeBorderProps(),
    ...makeRoundedProps(),
    ...makeElevationProps(),
    color: String
  }, 'VHotkey');
  const AND_DELINEATOR = Symbol('VHotkey:AND_DELINEATOR'); // For +_ separators
  const OR_DELINEATOR = Symbol('VHotkey:OR_DELINEATOR'); // For / separators
  const THEN_DELINEATOR = Symbol('VHotkey:THEN_DELINEATOR'); // For - separators

  function getKeyText(keyMap, key, isMac) {
    const lowerKey = key.toLowerCase();
    if (lowerKey in keyMap) {
      const result = processKey(keyMap[lowerKey], 'text', isMac);
      return typeof result[1] === 'string' ? result[1] : String(result[1]);
    }
    return key.toUpperCase();
  }
  function applyDisplayModeToKey(keyMap, mode, key, isMac) {
    const lowerKey = key.toLowerCase();
    if (lowerKey in keyMap) {
      const result = processKey(keyMap[lowerKey], mode, isMac);
      if (result[0] === 'text' && typeof result[1] === 'string' && result[1].startsWith('$') && !result[1].startsWith('$vuetify.')) {
        return ['text', result[1].replace('$', '').toUpperCase(), key];
      }
      return [...result, key];
    }
    return ['text', key.toUpperCase(), key];
  }
  const VHotkey = genericComponent()({
    name: 'VHotkey',
    props: makeVHotkeyProps(),
    setup(props) {
      const {
        t
      } = useLocale();
      const {
        themeClasses
      } = provideTheme(props);
      const {
        rtlClasses
      } = useRtl();
      const {
        borderClasses
      } = useBorder(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const {
        elevationClasses
      } = useElevation(props);
      const {
        colorClasses,
        colorStyles,
        variantClasses
      } = useVariant(() => ({
        color: props.color,
        variant: props.variant === 'contained' ? 'elevated' : props.variant
      }));
      const isMac = vue.computed(() => props.platform === 'auto' ? typeof navigator !== 'undefined' && /macintosh/i.test(navigator.userAgent) : props.platform === 'mac');
      const keyCombinations = vue.computed(() => {
        if (!props.keys) return [];

        // Split by spaces to handle multiple key combinations
        // Example: "ctrl+k meta+p" -> ["ctrl+k", "meta+p"]
        return props.keys.split(/\b \b/).map(combination => {
          const result = [];
          function visit(node) {
            if (typeof node === 'string') {
              if (node !== '') {
                result.push(applyDisplayModeToKey(props.keyMap, props.displayMode, node, isMac.value));
              }
            } else {
              for (let i = 0; i < node.parts.length; i++) {
                if (i > 0) {
                  if (node.type === 'sequence') {
                    result.push(THEN_DELINEATOR);
                  } else if (node.type === 'alternate') {
                    result.push(OR_DELINEATOR);
                  } else if (node.type === 'combo') {
                    result.push(AND_DELINEATOR);
                  } else ;
                }
                visit(node.parts[i]);
              }
            }
          }
          visit(parseKeyCombination(combination));
          return result;
        });
      });
      const accessibleLabel = vue.computed(() => {
        if (!props.keys) return '';

        // Convert the parsed key combinations into readable text
        const readableShortcuts = keyCombinations.value.map(combination => {
          const readableParts = [];
          for (const key of combination) {
            if (Array.isArray(key)) {
              // Always use text representation for screen readers
              const textKey = key[0] === 'icon' || key[0] === 'symbol' ? applyDisplayModeToKey(mergeDeep(hotkeyMap, props.keyMap), 'text', String(key[1]), isMac.value)[1] : key[1];
              readableParts.push(translateKey(textKey));
            } else {
              if (key === AND_DELINEATOR) {
                readableParts.push(t('$vuetify.hotkey.plus'));
              } else if (key === OR_DELINEATOR) {
                readableParts.push(t('$vuetify.hotkey.or'));
              } else if (key === THEN_DELINEATOR) {
                readableParts.push(t('$vuetify.hotkey.then'));
              }
            }
          }
          return readableParts.join(' ');
        });
        const shortcutText = readableShortcuts.join(', ');
        return t('$vuetify.hotkey.shortcut', shortcutText);
      });
      function translateKey(key) {
        return key.startsWith('$vuetify.') ? t(key) : key;
      }
      function getKeyTooltip(key) {
        if (props.displayMode === 'text') return undefined;
        const textKey = getKeyText(props.keyMap, String(key[2]), isMac.value);
        return translateKey(textKey);
      }
      function renderKey(key, keyIndex) {
        const isContained = props.variant === 'contained';
        const KeyComponent = isContained ? 'kbd' : VKbd;
        const keyClasses = ['v-hotkey__key', `v-hotkey__key-${key[0]}`, ...(isContained ? ['v-hotkey__key--nested'] : [borderClasses.value, roundedClasses.value, elevationClasses.value, colorClasses.value])];
        return vue.createVNode(KeyComponent, {
          "key": keyIndex,
          "class": vue.normalizeClass(keyClasses),
          "style": vue.normalizeStyle(isContained ? undefined : [colorStyles.value, roundedStyles.value]),
          "aria-hidden": "true",
          "title": getKeyTooltip(key)
        }, {
          default: () => [key[0] === 'icon' ? vue.createVNode(VIcon, {
            "icon": key[1],
            "aria-hidden": "true"
          }, null) : translateKey(key[1])]
        });
      }
      function renderDivider(key, keyIndex) {
        return vue.createElementVNode("span", {
          "key": keyIndex,
          "class": "v-hotkey__divider",
          "aria-hidden": "true"
        }, [key === AND_DELINEATOR ? '+' : key === OR_DELINEATOR ? t('$vuetify.hotkey.or') : t('$vuetify.hotkey.then')]);
      }
      useRender(() => {
        const content = vue.createElementVNode(vue.Fragment, null, [props.prefix && vue.createElementVNode("span", {
          "key": "prefix",
          "class": "v-hotkey__prefix"
        }, [props.prefix]), keyCombinations.value.map((combination, comboIndex) => vue.createElementVNode("span", {
          "class": "v-hotkey__combination",
          "key": comboIndex
        }, [combination.map((key, keyIndex) => Array.isArray(key) ? renderKey(key, keyIndex) : renderDivider(key, keyIndex)), comboIndex < keyCombinations.value.length - 1 && vue.createElementVNode("span", {
          "aria-hidden": "true"
        }, [vue.createTextVNode("\xA0")])])), props.suffix && vue.createElementVNode("span", {
          "key": "suffix",
          "class": "v-hotkey__suffix"
        }, [props.suffix])]);
        return vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-hotkey', {
            'v-hotkey--disabled': props.disabled,
            'v-hotkey--inline': props.inline,
            'v-hotkey--contained': props.variant === 'contained'
          }, themeClasses.value, rtlClasses.value, variantClasses.value, props.class]),
          "style": vue.normalizeStyle(props.style),
          "role": "img",
          "aria-label": accessibleLabel.value
        }, [props.variant !== 'contained' ? content : vue.createVNode(VKbd, {
          "key": "contained",
          "class": vue.normalizeClass(['v-hotkey__contained-wrapper', borderClasses.value, roundedClasses.value, elevationClasses.value, colorClasses.value]),
          "style": vue.normalizeStyle([colorStyles.value, roundedStyles.value]),
          "aria-hidden": "true"
        }, {
          default: () => [content]
        })]);
      });
    }
  });

  // Composables
  const makeVHoverProps = propsFactory({
    disabled: Boolean,
    modelValue: {
      type: Boolean,
      default: null
    },
    ...makeDelayProps()
  }, 'VHover');
  const VHover = genericComponent()({
    name: 'VHover',
    props: makeVHoverProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const isHovering = useProxiedModel(props, 'modelValue');

      // track hover state regardless of disabled, so we can reconcile
      const internal = vue.shallowRef(false);
      const {
        runOpenDelay,
        runCloseDelay
      } = useDelay(props, value => {
        internal.value = value;
        if (!props.disabled) {
          isHovering.value = value;
        }
      });
      vue.watch(() => props.disabled, (val, old) => {
        if (old && !val) {
          isHovering.value = internal.value;
        }
      });
      return () => slots.default?.({
        isHovering: isHovering.value,
        props: {
          onMouseenter: runOpenDelay,
          onMouseleave: runCloseDelay
        }
      });
    }
  });

  // Types

  const makeVInfiniteScrollProps = propsFactory({
    color: String,
    direction: {
      type: String,
      default: 'vertical',
      validator: v => ['vertical', 'horizontal'].includes(v)
    },
    side: {
      type: String,
      default: 'end',
      validator: v => ['start', 'end', 'both'].includes(v)
    },
    mode: {
      type: String,
      default: 'intersect',
      validator: v => ['intersect', 'manual'].includes(v)
    },
    margin: [Number, String],
    loadMoreText: {
      type: String,
      default: '$vuetify.infiniteScroll.loadMore'
    },
    emptyText: {
      type: String,
      default: '$vuetify.infiniteScroll.empty'
    },
    ...makeDimensionProps(),
    ...makeTagProps()
  }, 'VInfiniteScroll');
  const VInfiniteScrollIntersect = defineComponent({
    name: 'VInfiniteScrollIntersect',
    props: {
      side: {
        type: String,
        required: true
      },
      rootMargin: String
    },
    emits: {
      intersect: (side, isIntersecting) => true
    },
    setup(props, {
      emit
    }) {
      const {
        intersectionRef,
        isIntersecting
      } = useIntersectionObserver();
      vue.watch(isIntersecting, async val => {
        emit('intersect', props.side, val);
      });
      useRender(() => vue.createElementVNode("div", {
        "class": "v-infinite-scroll-intersect",
        "style": {
          '--v-infinite-margin-size': props.rootMargin
        },
        "ref": intersectionRef
      }, [vue.createTextVNode("\xA0")]));
      return {};
    }
  });
  const VInfiniteScroll = genericComponent()({
    name: 'VInfiniteScroll',
    props: makeVInfiniteScrollProps(),
    emits: {
      load: options => true
    },
    setup(props, {
      slots,
      emit
    }) {
      const rootEl = vue.ref();
      const startStatus = vue.shallowRef('ok');
      const endStatus = vue.shallowRef('ok');
      const margin = vue.computed(() => convertToUnit(props.margin));
      const isIntersecting = vue.shallowRef(false);
      function setScrollAmount(amount) {
        if (!rootEl.value) return;
        const property = props.direction === 'vertical' ? 'scrollTop' : 'scrollLeft';
        rootEl.value[property] = amount;
      }
      function getScrollAmount() {
        if (!rootEl.value) return 0;
        const property = props.direction === 'vertical' ? 'scrollTop' : 'scrollLeft';
        return rootEl.value[property];
      }
      function getScrollSize() {
        if (!rootEl.value) return 0;
        const property = props.direction === 'vertical' ? 'scrollHeight' : 'scrollWidth';
        return rootEl.value[property];
      }
      function getContainerSize() {
        if (!rootEl.value) return 0;
        const property = props.direction === 'vertical' ? 'clientHeight' : 'clientWidth';
        return rootEl.value[property];
      }
      vue.onMounted(() => {
        if (!rootEl.value) return;
        if (props.side === 'start') {
          setScrollAmount(getScrollSize());
        } else if (props.side === 'both') {
          setScrollAmount(getScrollSize() / 2 - getContainerSize() / 2);
        }
      });
      function setStatus(side, status) {
        if (side === 'start') {
          startStatus.value = status;
        } else if (side === 'end') {
          endStatus.value = status;
        } else if (side === 'both') {
          startStatus.value = status;
          endStatus.value = status;
        }
      }
      function getStatus(side) {
        return side === 'start' ? startStatus.value : endStatus.value;
      }
      let previousScrollSize = 0;
      function handleIntersect(side, _isIntersecting) {
        isIntersecting.value = _isIntersecting;
        if (isIntersecting.value) {
          intersecting(side);
        }
      }
      function intersecting(side) {
        if (props.mode !== 'manual' && !isIntersecting.value) return;
        const status = getStatus(side);
        if (!rootEl.value || ['empty', 'loading'].includes(status)) return;
        previousScrollSize = getScrollSize();
        setStatus(side, 'loading');
        function done(status) {
          setStatus(side, status);
          vue.nextTick(() => {
            if (status === 'empty' || status === 'error') return;
            if (status === 'ok' && side === 'start') {
              setScrollAmount(getScrollSize() - previousScrollSize + getScrollAmount());
            }
            if (props.mode !== 'manual') {
              vue.nextTick(() => {
                // Browser takes 2 - 3 animation frames to trigger IntersectionObserver after
                // VInfiniteScrollIntersect leaves the viewpoint. So far I couldn't come up
                // with a better solution than using 3 nested window.requestAnimationFrame. (#17475)
                window.requestAnimationFrame(() => {
                  window.requestAnimationFrame(() => {
                    window.requestAnimationFrame(() => {
                      intersecting(side);
                    });
                  });
                });
              });
            }
          });
        }
        emit('load', {
          side,
          done
        });
      }
      const {
        t
      } = useLocale();
      function renderSide(side, status) {
        if (props.side !== side && props.side !== 'both') return;
        const onClick = () => intersecting(side);
        const slotProps = {
          side,
          props: {
            onClick,
            color: props.color
          }
        };
        if (status === 'error') return slots.error?.(slotProps);
        if (status === 'empty') return slots.empty?.(slotProps) ?? vue.createElementVNode("div", null, [t(props.emptyText)]);
        if (props.mode === 'manual') {
          if (status === 'loading') {
            return slots.loading?.(slotProps) ?? vue.createVNode(VProgressCircular, {
              "indeterminate": true,
              "color": props.color
            }, null);
          }
          return slots['load-more']?.(slotProps) ?? vue.createVNode(VBtn, {
            "variant": "outlined",
            "color": props.color,
            "onClick": onClick
          }, {
            default: () => [t(props.loadMoreText)]
          });
        }
        return slots.loading?.(slotProps) ?? vue.createVNode(VProgressCircular, {
          "indeterminate": true,
          "color": props.color
        }, null);
      }
      const {
        dimensionStyles
      } = useDimension(props);
      useRender(() => {
        const Tag = props.tag;
        const hasStartIntersect = props.side === 'start' || props.side === 'both';
        const hasEndIntersect = props.side === 'end' || props.side === 'both';
        const intersectMode = props.mode === 'intersect';
        return vue.createVNode(Tag, {
          "ref": rootEl,
          "class": vue.normalizeClass(['v-infinite-scroll', `v-infinite-scroll--${props.direction}`, {
            'v-infinite-scroll--start': hasStartIntersect,
            'v-infinite-scroll--end': hasEndIntersect
          }]),
          "style": vue.normalizeStyle(dimensionStyles.value)
        }, {
          default: () => [vue.createElementVNode("div", {
            "class": "v-infinite-scroll__side"
          }, [renderSide('start', startStatus.value)]), hasStartIntersect && intersectMode && vue.createVNode(VInfiniteScrollIntersect, {
            "key": "start",
            "side": "start",
            "onIntersect": handleIntersect,
            "rootMargin": margin.value
          }, null), slots.default?.(), hasEndIntersect && intersectMode && vue.createVNode(VInfiniteScrollIntersect, {
            "key": "end",
            "side": "end",
            "onIntersect": handleIntersect,
            "rootMargin": margin.value
          }, null), vue.createElementVNode("div", {
            "class": "v-infinite-scroll__side"
          }, [renderSide('end', endStatus.value)])]
        });
      });
      function reset(side) {
        const effectiveSide = side ?? props.side;
        setStatus(effectiveSide, 'ok');
        vue.nextTick(() => {
          if (effectiveSide !== 'end') {
            setScrollAmount(getScrollSize() - previousScrollSize + getScrollAmount());
          }
          if (props.mode !== 'manual') {
            vue.nextTick(() => {
              // See #17475
              window.requestAnimationFrame(() => {
                window.requestAnimationFrame(() => {
                  window.requestAnimationFrame(() => {
                    if (effectiveSide === 'both') {
                      intersecting('start');
                      intersecting('end');
                    } else {
                      intersecting(effectiveSide);
                    }
                  });
                });
              });
            });
          }
        });
      }
      return {
        reset
      };
    }
  });

  // Types

  const VItemGroupSymbol = Symbol.for('vuetify:v-item-group');
  const makeVItemGroupProps = propsFactory({
    ...makeComponentProps(),
    ...makeGroupProps({
      selectedClass: 'v-item--selected'
    }),
    ...makeTagProps(),
    ...makeThemeProps()
  }, 'VItemGroup');
  const VItemGroup = genericComponent()({
    name: 'VItemGroup',
    props: makeVItemGroupProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const {
        themeClasses
      } = provideTheme(props);
      const {
        isSelected,
        select,
        next,
        prev,
        selected
      } = useGroup(props, VItemGroupSymbol);
      return () => vue.createVNode(props.tag, {
        "class": vue.normalizeClass(['v-item-group', themeClasses.value, props.class]),
        "style": vue.normalizeStyle(props.style)
      }, {
        default: () => [slots.default?.({
          isSelected,
          select,
          next,
          prev,
          selected: selected.value
        })]
      });
    }
  });

  // Composables
  const VItem = genericComponent()({
    name: 'VItem',
    props: makeGroupItemProps(),
    emits: {
      'group:selected': val => true
    },
    setup(props, {
      slots
    }) {
      const {
        isSelected,
        select,
        toggle,
        selectedClass,
        value,
        disabled
      } = useGroupItem(props, VItemGroupSymbol);
      return () => slots.default?.({
        isSelected: isSelected.value,
        selectedClass: selectedClass.value,
        select,
        toggle,
        value: value.value,
        disabled: disabled.value
      });
    }
  });

  const makeVLayoutProps = propsFactory({
    ...makeComponentProps(),
    ...makeDimensionProps(),
    ...makeLayoutProps()
  }, 'VLayout');
  const VLayout = genericComponent()({
    name: 'VLayout',
    props: makeVLayoutProps(),
    setup(props, {
      slots
    }) {
      const {
        layoutClasses,
        layoutStyles,
        getLayoutItem,
        items,
        layoutRef
      } = createLayout(props);
      const {
        dimensionStyles
      } = useDimension(props);
      useRender(() => vue.createElementVNode("div", {
        "ref": layoutRef,
        "class": vue.normalizeClass([layoutClasses.value, props.class]),
        "style": vue.normalizeStyle([dimensionStyles.value, layoutStyles.value, props.style])
      }, [slots.default?.()]));
      return {
        getLayoutItem,
        items
      };
    }
  });

  // Types

  const makeVLayoutItemProps = propsFactory({
    position: {
      type: String,
      required: true
    },
    size: {
      type: [Number, String],
      default: 300
    },
    modelValue: Boolean,
    ...makeComponentProps(),
    ...makeLayoutItemProps()
  }, 'VLayoutItem');
  const VLayoutItem = genericComponent()({
    name: 'VLayoutItem',
    props: makeVLayoutItemProps(),
    setup(props, {
      slots
    }) {
      const {
        layoutItemStyles
      } = useLayoutItem({
        id: props.name,
        order: vue.computed(() => parseInt(props.order, 10)),
        position: vue.toRef(() => props.position),
        elementSize: vue.toRef(() => props.size),
        layoutSize: vue.toRef(() => props.size),
        active: vue.toRef(() => props.modelValue),
        absolute: vue.toRef(() => props.absolute)
      });
      return () => vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-layout-item', props.class]),
        "style": vue.normalizeStyle([layoutItemStyles.value, props.style])
      }, [slots.default?.()]);
    }
  });

  // Types

  const makeVLazyProps = propsFactory({
    modelValue: Boolean,
    options: {
      type: Object,
      // For more information on types, navigate to:
      // https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
      default: () => ({
        root: undefined,
        rootMargin: undefined,
        threshold: undefined
      })
    },
    ...makeComponentProps(),
    ...makeDimensionProps(),
    ...makeTagProps(),
    ...makeTransitionProps({
      transition: 'fade-transition'
    })
  }, 'VLazy');
  const VLazy = genericComponent()({
    name: 'VLazy',
    directives: {
      vIntersect: Intersect
    },
    props: makeVLazyProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const {
        dimensionStyles
      } = useDimension(props);
      const isActive = useProxiedModel(props, 'modelValue');
      function onIntersect(isIntersecting) {
        if (isActive.value) return;
        isActive.value = isIntersecting;
      }
      useRender(() => vue.withDirectives(vue.createVNode(props.tag, {
        "class": vue.normalizeClass(['v-lazy', props.class]),
        "style": vue.normalizeStyle([dimensionStyles.value, props.style])
      }, {
        default: () => [isActive.value && vue.createVNode(MaybeTransition, {
          "transition": props.transition,
          "appear": true
        }, {
          default: () => [slots.default?.()]
        })]
      }), [[Intersect, {
        handler: onIntersect,
        options: props.options
      }, null]]));
      return {};
    }
  });

  const makeVLocaleProviderProps = propsFactory({
    locale: String,
    fallbackLocale: String,
    messages: Object,
    rtl: {
      type: Boolean,
      default: undefined
    },
    ...makeComponentProps()
  }, 'VLocaleProvider');
  const VLocaleProvider = genericComponent()({
    name: 'VLocaleProvider',
    props: makeVLocaleProviderProps(),
    setup(props, {
      slots
    }) {
      const {
        rtlClasses
      } = provideLocale(props);
      useRender(() => vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-locale-provider', rtlClasses.value, props.class]),
        "style": vue.normalizeStyle(props.style)
      }, [slots.default?.()]));
      return {};
    }
  });

  const makeVMainProps = propsFactory({
    scrollable: Boolean,
    ...makeComponentProps(),
    ...makeDimensionProps(),
    ...makeTagProps({
      tag: 'main'
    })
  }, 'VMain');
  const VMain = genericComponent()({
    name: 'VMain',
    props: makeVMainProps(),
    setup(props, {
      slots
    }) {
      const {
        dimensionStyles
      } = useDimension(props);
      const {
        mainStyles
      } = useLayout();
      const {
        ssrBootStyles
      } = useSsrBoot();
      useRender(() => vue.createVNode(props.tag, {
        "class": vue.normalizeClass(['v-main', {
          'v-main--scrollable': props.scrollable
        }, props.class]),
        "style": vue.normalizeStyle([mainStyles.value, ssrBootStyles.value, dimensionStyles.value, props.style])
      }, {
        default: () => [props.scrollable ? vue.createElementVNode("div", {
          "class": "v-main__scroller"
        }, [slots.default?.()]) : slots.default?.()]
      }));
      return {};
    }
  });

  // Utilities

  // Types

  function useSticky({
    rootEl,
    isSticky,
    layoutItemStyles
  }) {
    const isStuck = vue.shallowRef(false);
    const stuckPosition = vue.shallowRef(0);
    const stickyStyles = vue.computed(() => {
      const side = typeof isStuck.value === 'boolean' ? 'top' : isStuck.value;
      return [isSticky.value ? {
        top: 'auto',
        bottom: 'auto',
        height: undefined
      } : undefined, isStuck.value ? {
        [side]: convertToUnit(stuckPosition.value)
      } : {
        top: layoutItemStyles.value.top
      }];
    });
    vue.onMounted(() => {
      vue.watch(isSticky, val => {
        if (val) {
          window.addEventListener('scroll', onScroll, {
            passive: true
          });
        } else {
          window.removeEventListener('scroll', onScroll);
        }
      }, {
        immediate: true
      });
    });
    vue.onBeforeUnmount(() => {
      window.removeEventListener('scroll', onScroll);
    });
    let lastScrollTop = 0;
    function onScroll() {
      const direction = lastScrollTop > window.scrollY ? 'up' : 'down';
      const rect = rootEl.value.getBoundingClientRect();
      const layoutTop = parseFloat(layoutItemStyles.value.top ?? 0);
      const top = window.scrollY - Math.max(0, stuckPosition.value - layoutTop);
      const bottom = rect.height + Math.max(stuckPosition.value, layoutTop) - window.scrollY - window.innerHeight;
      const bodyScroll = parseFloat(getComputedStyle(rootEl.value).getPropertyValue('--v-body-scroll-y')) || 0;
      if (rect.height < window.innerHeight - layoutTop) {
        isStuck.value = 'top';
        stuckPosition.value = layoutTop;
      } else if (direction === 'up' && isStuck.value === 'bottom' || direction === 'down' && isStuck.value === 'top') {
        stuckPosition.value = window.scrollY + rect.top - bodyScroll;
        isStuck.value = true;
      } else if (direction === 'down' && bottom <= 0) {
        stuckPosition.value = 0;
        isStuck.value = 'bottom';
      } else if (direction === 'up' && top <= 0) {
        if (!bodyScroll) {
          stuckPosition.value = rect.top + top;
          isStuck.value = 'top';
        } else if (isStuck.value !== 'top') {
          stuckPosition.value = -top + bodyScroll + layoutTop;
          isStuck.value = 'top';
        }
      }
      lastScrollTop = window.scrollY;
    }
    return {
      isStuck,
      stickyStyles
    };
  }

  // Utilities
  const HORIZON = 100; // ms
  const HISTORY = 20; // number of samples to keep

  /** @see https://android.googlesource.com/platform/frameworks/native/+/master/libs/input/VelocityTracker.cpp */
  function kineticEnergyToVelocity(work) {
    const sqrt2 = 1.41421356237;
    return (work < 0 ? -1 : 1.0) * Math.sqrt(Math.abs(work)) * sqrt2;
  }

  /**
   * Returns pointer velocity in px/s
   */
  function calculateImpulseVelocity(samples) {
    // The input should be in reversed time order (most recent sample at index i=0)
    if (samples.length < 2) {
      // if 0 or 1 points, velocity is zero
      return 0;
    }
    // if (samples[1].t > samples[0].t) {
    //   // Algorithm will still work, but not perfectly
    //   consoleWarn('Samples provided to calculateImpulseVelocity in the wrong order')
    // }
    if (samples.length === 2) {
      // if 2 points, basic linear calculation
      if (samples[1].t === samples[0].t) {
        // consoleWarn(`Events have identical time stamps t=${samples[0].t}, setting velocity = 0`)
        return 0;
      }
      return (samples[1].d - samples[0].d) / (samples[1].t - samples[0].t);
    }
    // Guaranteed to have at least 3 points here
    // start with the oldest sample and go forward in time
    let work = 0;
    for (let i = samples.length - 1; i > 0; i--) {
      if (samples[i].t === samples[i - 1].t) {
        // consoleWarn(`Events have identical time stamps t=${samples[i].t}, skipping sample`)
        continue;
      }
      const vprev = kineticEnergyToVelocity(work); // v[i-1]
      const vcurr = (samples[i].d - samples[i - 1].d) / (samples[i].t - samples[i - 1].t); // v[i]
      work += (vcurr - vprev) * Math.abs(vcurr);
      if (i === samples.length - 1) {
        work *= 0.5;
      }
    }
    return kineticEnergyToVelocity(work) * 1000;
  }
  function useVelocity() {
    const touches = {};
    function addMovement(e) {
      Array.from(e.changedTouches).forEach(touch => {
        const samples = touches[touch.identifier] ?? (touches[touch.identifier] = new CircularBuffer(HISTORY));
        samples.push([e.timeStamp, touch]);
      });
    }
    function endTouch(e) {
      Array.from(e.changedTouches).forEach(touch => {
        delete touches[touch.identifier];
      });
    }
    function getVelocity(id) {
      const samples = touches[id]?.values().reverse();
      if (!samples) {
        throw new Error(`No samples for touch id ${id}`);
      }
      const newest = samples[0];
      const x = [];
      const y = [];
      for (const val of samples) {
        if (newest[0] - val[0] > HORIZON) break;
        x.push({
          t: val[0],
          d: val[1].clientX
        });
        y.push({
          t: val[0],
          d: val[1].clientY
        });
      }
      return {
        x: calculateImpulseVelocity(x),
        y: calculateImpulseVelocity(y),
        get direction() {
          const {
            x,
            y
          } = this;
          const [absX, absY] = [Math.abs(x), Math.abs(y)];
          return absX > absY && x >= 0 ? 'right' : absX > absY && x <= 0 ? 'left' : absY > absX && y >= 0 ? 'down' : absY > absX && y <= 0 ? 'up' : oops$1();
        }
      };
    }
    return {
      addMovement,
      endTouch,
      getVelocity
    };
  }
  function oops$1() {
    throw new Error();
  }

  // Composables

  // Types

  function useTouch({
    el,
    isActive,
    isTemporary,
    width,
    touchless,
    position
  }) {
    vue.onMounted(() => {
      window.addEventListener('touchstart', onTouchstart, {
        passive: true
      });
      window.addEventListener('touchmove', onTouchmove, {
        passive: false
      });
      window.addEventListener('touchend', onTouchend, {
        passive: true
      });
    });
    vue.onBeforeUnmount(() => {
      window.removeEventListener('touchstart', onTouchstart);
      window.removeEventListener('touchmove', onTouchmove);
      window.removeEventListener('touchend', onTouchend);
    });
    const isHorizontal = vue.computed(() => ['left', 'right'].includes(position.value));
    const {
      addMovement,
      endTouch,
      getVelocity
    } = useVelocity();
    let maybeDragging = false;
    const isDragging = vue.shallowRef(false);
    const dragProgress = vue.shallowRef(0);
    const offset = vue.shallowRef(0);
    let start;
    function getOffset(pos, active) {
      return (position.value === 'left' ? pos : position.value === 'right' ? document.documentElement.clientWidth - pos : position.value === 'top' ? pos : position.value === 'bottom' ? document.documentElement.clientHeight - pos : oops()) - (active ? width.value : 0);
    }
    function getProgress(pos, limit = true) {
      const progress = position.value === 'left' ? (pos - offset.value) / width.value : position.value === 'right' ? (document.documentElement.clientWidth - pos - offset.value) / width.value : position.value === 'top' ? (pos - offset.value) / width.value : position.value === 'bottom' ? (document.documentElement.clientHeight - pos - offset.value) / width.value : oops();
      return limit ? clamp(progress) : progress;
    }
    function onTouchstart(e) {
      if (touchless.value) return;
      const touchX = e.changedTouches[0].clientX;
      const touchY = e.changedTouches[0].clientY;
      const touchZone = 25;
      const inTouchZone = position.value === 'left' ? touchX < touchZone : position.value === 'right' ? touchX > document.documentElement.clientWidth - touchZone : position.value === 'top' ? touchY < touchZone : position.value === 'bottom' ? touchY > document.documentElement.clientHeight - touchZone : oops();
      const inElement = isActive.value && (position.value === 'left' ? touchX < width.value : position.value === 'right' ? touchX > document.documentElement.clientWidth - width.value : position.value === 'top' ? touchY < width.value : position.value === 'bottom' ? touchY > document.documentElement.clientHeight - width.value : oops());
      if (inTouchZone || inElement || isActive.value && isTemporary.value) {
        start = [touchX, touchY];
        offset.value = getOffset(isHorizontal.value ? touchX : touchY, isActive.value);
        dragProgress.value = getProgress(isHorizontal.value ? touchX : touchY);
        maybeDragging = offset.value > -20 && offset.value < 80;
        endTouch(e);
        addMovement(e);
      }
    }
    function onTouchmove(e) {
      const touchX = e.changedTouches[0].clientX;
      const touchY = e.changedTouches[0].clientY;
      if (maybeDragging) {
        if (!e.cancelable) {
          maybeDragging = false;
          return;
        }
        const dx = Math.abs(touchX - start[0]);
        const dy = Math.abs(touchY - start[1]);
        const thresholdMet = isHorizontal.value ? dx > dy && dx > 3 : dy > dx && dy > 3;
        if (thresholdMet) {
          isDragging.value = true;
          maybeDragging = false;
        } else if ((isHorizontal.value ? dy : dx) > 3) {
          maybeDragging = false;
        }
      }
      if (!isDragging.value) return;
      e.preventDefault();
      addMovement(e);
      const progress = getProgress(isHorizontal.value ? touchX : touchY, false);
      dragProgress.value = Math.max(0, Math.min(1, progress));
      if (progress > 1) {
        offset.value = getOffset(isHorizontal.value ? touchX : touchY, true);
      } else if (progress < 0) {
        offset.value = getOffset(isHorizontal.value ? touchX : touchY, false);
      }
    }
    function onTouchend(e) {
      maybeDragging = false;
      if (!isDragging.value) return;
      addMovement(e);
      isDragging.value = false;
      const velocity = getVelocity(e.changedTouches[0].identifier);
      const vx = Math.abs(velocity.x);
      const vy = Math.abs(velocity.y);
      const thresholdMet = isHorizontal.value ? vx > vy && vx > 400 : vy > vx && vy > 3;
      if (thresholdMet) {
        isActive.value = velocity.direction === ({
          left: 'right',
          right: 'left',
          top: 'down',
          bottom: 'up'
        }[position.value] || oops());
      } else {
        isActive.value = dragProgress.value > 0.5;
      }
    }
    const dragStyles = vue.computed(() => {
      return isDragging.value ? {
        transform: position.value === 'left' ? `translateX(calc(-100% + ${dragProgress.value * width.value}px))` : position.value === 'right' ? `translateX(calc(100% - ${dragProgress.value * width.value}px))` : position.value === 'top' ? `translateY(calc(-100% + ${dragProgress.value * width.value}px))` : position.value === 'bottom' ? `translateY(calc(100% - ${dragProgress.value * width.value}px))` : oops(),
        transition: 'none'
      } : undefined;
    });
    useToggleScope(isDragging, () => {
      const transform = el.value?.style.transform ?? null;
      const transition = el.value?.style.transition ?? null;
      vue.watchEffect(() => {
        el.value?.style.setProperty('transform', dragStyles.value?.transform || 'none');
        el.value?.style.setProperty('transition', dragStyles.value?.transition || null);
      });
      vue.onScopeDispose(() => {
        el.value?.style.setProperty('transform', transform);
        el.value?.style.setProperty('transition', transition);
      });
    });
    return {
      isDragging,
      dragProgress,
      dragStyles
    };
  }
  function oops() {
    throw new Error();
  }

  // Types

  const locations = ['start', 'end', 'left', 'right', 'top', 'bottom'];
  const makeVNavigationDrawerProps = propsFactory({
    color: String,
    disableResizeWatcher: Boolean,
    disableRouteWatcher: Boolean,
    expandOnHover: Boolean,
    floating: Boolean,
    modelValue: {
      type: Boolean,
      default: null
    },
    permanent: Boolean,
    rail: {
      type: Boolean,
      default: null
    },
    railWidth: {
      type: [Number, String],
      default: 56
    },
    scrim: {
      type: [Boolean, String],
      default: true
    },
    image: String,
    temporary: Boolean,
    persistent: Boolean,
    touchless: Boolean,
    width: {
      type: [Number, String],
      default: 256
    },
    location: {
      type: String,
      default: 'start',
      validator: value => locations.includes(value)
    },
    sticky: Boolean,
    ...makeBorderProps(),
    ...makeComponentProps(),
    ...makeDelayProps(),
    ...makeDisplayProps({
      mobile: null
    }),
    ...makeElevationProps(),
    ...makeLayoutItemProps(),
    ...makeRoundedProps(),
    ...omit(makeFocusTrapProps(), ['disableInitialFocus']),
    ...makeTagProps({
      tag: 'nav'
    }),
    ...makeThemeProps()
  }, 'VNavigationDrawer');
  const VNavigationDrawer = genericComponent()({
    name: 'VNavigationDrawer',
    props: makeVNavigationDrawerProps(),
    emits: {
      'update:modelValue': val => true,
      'update:rail': val => true
    },
    setup(props, {
      attrs,
      emit,
      slots
    }) {
      const {
        isRtl
      } = useRtl();
      const {
        themeClasses
      } = provideTheme(props);
      const {
        borderClasses
      } = useBorder(props);
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.color);
      const {
        elevationClasses
      } = useElevation(props);
      const {
        displayClasses,
        mobile
      } = useDisplay(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const router = useRouter();
      const isActive = useProxiedModel(props, 'modelValue', null, v => !!v);
      const {
        ssrBootStyles
      } = useSsrBoot();
      const {
        scopeId
      } = useScopeId();
      const rootEl = vue.ref();
      const isHovering = vue.shallowRef(false);
      const {
        runOpenDelay,
        runCloseDelay
      } = useDelay(props, value => {
        isHovering.value = value;
      });
      const width = vue.computed(() => {
        return props.rail && props.expandOnHover && isHovering.value ? Number(props.width) : Number(props.rail ? props.railWidth : props.width);
      });
      const location = vue.computed(() => {
        return toPhysical(props.location, isRtl.value);
      });
      const isPersistent = vue.toRef(() => props.persistent);
      const isTemporary = vue.computed(() => !props.permanent && (mobile.value || props.temporary));
      const isSticky = vue.computed(() => props.sticky && !isTemporary.value && location.value !== 'bottom');
      useFocusTrap(props, {
        isActive,
        localTop: isTemporary,
        contentEl: rootEl
      });
      useToggleScope(() => props.expandOnHover && props.rail != null, () => {
        vue.watch(isHovering, val => emit('update:rail', !val));
      });
      useToggleScope(() => !props.disableResizeWatcher, () => {
        vue.watch(isTemporary, val => !props.permanent && vue.nextTick(() => isActive.value = !val));
      });
      useToggleScope(() => !props.disableRouteWatcher && !!router, () => {
        vue.watch(router.currentRoute, () => isTemporary.value && (isActive.value = false));
      });
      vue.watch(() => props.permanent, val => {
        if (val) isActive.value = true;
      });
      if (props.modelValue == null && !isTemporary.value) {
        isActive.value = props.permanent || !mobile.value;
      }
      const {
        isDragging,
        dragProgress
      } = useTouch({
        el: rootEl,
        isActive,
        isTemporary,
        width,
        touchless: vue.toRef(() => props.touchless),
        position: location
      });
      const layoutSize = vue.computed(() => {
        const size = isTemporary.value ? 0 : props.rail && props.expandOnHover ? Number(props.railWidth) : width.value;
        return isDragging.value ? size * dragProgress.value : size;
      });
      const {
        layoutItemStyles,
        layoutItemScrimStyles
      } = useLayoutItem({
        id: props.name,
        order: vue.computed(() => parseInt(props.order, 10)),
        position: location,
        layoutSize,
        elementSize: width,
        active: vue.readonly(isActive),
        disableTransitions: vue.toRef(() => isDragging.value),
        absolute: vue.computed(() =>
        // eslint-disable-next-line @typescript-eslint/no-use-before-define
        props.absolute || isSticky.value && typeof isStuck.value !== 'string')
      });
      const {
        isStuck,
        stickyStyles
      } = useSticky({
        rootEl,
        isSticky,
        layoutItemStyles
      });
      const scrimColor = useBackgroundColor(() => {
        return typeof props.scrim === 'string' ? props.scrim : null;
      });
      const scrimStyles = vue.computed(() => ({
        ...(isDragging.value ? {
          opacity: dragProgress.value * 0.2,
          transition: 'none'
        } : undefined),
        ...layoutItemScrimStyles.value
      }));
      provideDefaults({
        VList: {
          bgColor: 'transparent'
        }
      });
      useRender(() => {
        const hasImage = slots.image || props.image;
        return vue.createElementVNode(vue.Fragment, null, [vue.createVNode(props.tag, vue.mergeProps({
          "ref": rootEl,
          "onMouseenter": runOpenDelay,
          "onMouseleave": runCloseDelay,
          "class": ['v-navigation-drawer', `v-navigation-drawer--${location.value}`, {
            'v-navigation-drawer--expand-on-hover': props.expandOnHover,
            'v-navigation-drawer--floating': props.floating,
            'v-navigation-drawer--is-hovering': isHovering.value,
            'v-navigation-drawer--rail': props.rail,
            'v-navigation-drawer--temporary': isTemporary.value,
            'v-navigation-drawer--persistent': isPersistent.value,
            'v-navigation-drawer--active': isActive.value,
            'v-navigation-drawer--sticky': isSticky.value
          }, themeClasses.value, backgroundColorClasses.value, borderClasses.value, displayClasses.value, elevationClasses.value, roundedClasses.value, props.class],
          "style": [backgroundColorStyles.value, layoutItemStyles.value, ssrBootStyles.value, stickyStyles.value, roundedStyles.value, props.style],
          "inert": !isActive.value
        }, scopeId, attrs), {
          default: () => [hasImage && vue.createElementVNode("div", {
            "key": "image",
            "class": "v-navigation-drawer__img"
          }, [!slots.image ? vue.createVNode(VImg, {
            "key": "image-img",
            "alt": "",
            "cover": true,
            "height": "inherit",
            "src": props.image
          }, null) : vue.createVNode(VDefaultsProvider, {
            "key": "image-defaults",
            "disabled": !props.image,
            "defaults": {
              VImg: {
                alt: '',
                cover: true,
                height: 'inherit',
                src: props.image
              }
            }
          }, slots.image)]), slots.prepend && vue.createElementVNode("div", {
            "class": "v-navigation-drawer__prepend"
          }, [slots.prepend?.()]), vue.createElementVNode("div", {
            "class": "v-navigation-drawer__content"
          }, [slots.default?.()]), slots.append && vue.createElementVNode("div", {
            "class": "v-navigation-drawer__append"
          }, [slots.append?.()])]
        }), vue.createVNode(vue.Transition, {
          "name": "fade-transition"
        }, {
          default: () => [isTemporary.value && (isDragging.value || isActive.value) && !!props.scrim && vue.createElementVNode("div", vue.mergeProps({
            "class": ['v-navigation-drawer__scrim', scrimColor.backgroundColorClasses.value],
            "style": [scrimStyles.value, scrimColor.backgroundColorStyles.value],
            "onClick": () => {
              if (isPersistent.value) return;
              isActive.value = false;
            }
          }, scopeId), null)]
        })]);
      });
      return {
        isStuck
      };
    }
  });

  // Composables
  const VNoSsr = defineComponent({
    name: 'VNoSsr',
    setup(_, {
      slots
    }) {
      const show = useHydration();
      return () => show.value && slots.default?.();
    }
  });

  const NUMERAL_ZEROS = [0x0660,
  // Arabic-Indic
  0x06F0,
  // Extended Arabic-Indic — Persian, Dari
  0x0966,
  // Devanagari
  0x09E6,
  // Bengali
  0x0A66,
  // Gurmukhi
  0x0AE6,
  // Gujarati
  0x0B66,
  // Oriya
  0x0BE6,
  // Tamil
  0x0C66,
  // Telugu
  0x0CE6,
  // Kannada
  0x0D66,
  // Malayalam
  0x0E50,
  // Thai
  0x0ED0,
  // Lao
  0x0F20,
  // Tibetan
  0x1040,
  // Myanmar
  0x17E0,
  // Khmer
  0x1810,
  // Mongolian
  0xFF10 // Fullwidth
  ];
  function normalizeDigits(str) {
    return str.replace(/[^\x20-\x7F]/g, char => {
      const code = char.codePointAt(0);
      for (const zero of NUMERAL_ZEROS) {
        if (code >= zero && code <= zero + 9) {
          return String(code - zero);
        }
      }
      return char;
    });
  }
  function formatNumber(val, options) {
    const {
      precision,
      minFractionDigits
    } = options;
    const formatter = new Intl.NumberFormat(options.locale, {
      minimumFractionDigits: minFractionDigits && precision != null ? Math.min(minFractionDigits, precision) : minFractionDigits ?? precision ?? undefined,
      maximumFractionDigits: precision ?? 20,
      // Intl defaults are dynamic (0, 2, 3)
      useGrouping: options.useGrouping
    });
    return formatter.formatToParts(val).map(p => {
      if (p.type === 'group') return options.groupSeparator;
      if (p.type === 'decimal') return options.decimalSeparator;
      return normalizeDigits(p.value);
    }).join('');
  }

  // Utilities
  const HOLD_REPEAT = 50;
  const HOLD_DELAY = 500;
  function useHold({
    toggleUpDown
  }) {
    let timeout = -1;
    let interval = -1;
    vue.onScopeDispose(holdStop);
    function holdStart(value) {
      holdStop();
      tick(value);
      window.addEventListener('pointerup', holdStop);
      document.addEventListener('blur', holdStop);
      timeout = window.setTimeout(() => {
        interval = window.setInterval(() => tick(value), HOLD_REPEAT);
      }, HOLD_DELAY);
    }
    function holdStop() {
      if (!IN_BROWSER) return;
      window.clearTimeout(timeout);
      window.clearInterval(interval);
      window.removeEventListener('pointerup', holdStop);
      document.removeEventListener('blur', holdStop);
    }
    vue.onScopeDispose(holdStop);
    function tick(value) {
      toggleUpDown(value === 'up');
    }
    return {
      holdStart,
      holdStop
    };
  }

  /* eslint-disable complexity */

  function localizeMinusSign(text, minusSign) {
    return minusSign === '-' ? text : text.replace('-', minusSign);
  }
  function stripGrouping(text, groupSeparator) {
    return text.replaceAll(groupSeparator, '');
  }

  /** Fallback: fixed 3-digit groups */
  function formatWithoutLocale(digits, groupSeparator, grouping) {
    if (grouping === 'min2' && digits.length <= 4) {
      return digits;
    }
    const groups = [];
    for (let i = digits.length; i > 0; i -= 3) {
      groups.unshift(digits.slice(Math.max(0, i - 3), i));
    }
    return groups.join(groupSeparator);
  }
  function addGrouping(raw, groupSeparator, decimalSeparator, grouping, locale) {
    if (!grouping) return raw;
    const decimalIndex = raw.indexOf(decimalSeparator);
    const integerPart = decimalIndex >= 0 ? raw.slice(0, decimalIndex) : raw;
    const rest = decimalIndex >= 0 ? raw.slice(decimalIndex) : '';
    const sign = integerPart.startsWith('-') ? '-' : '';
    const digits = sign ? integerPart.slice(1) : integerPart;
    if (!digits) return raw;
    if (locale) {
      const num = Number(digits);
      if (!Number.isFinite(num)) return raw;
      const grouped = new Intl.NumberFormat(locale, {
        useGrouping: grouping,
        numberingSystem: 'latn'
      }).formatToParts(num).map(p => p.type === 'group' ? groupSeparator : p.value).join('');
      return sign + grouped + rest;
    }
    return sign + formatWithoutLocale(digits, groupSeparator, grouping) + rest;
  }

  /** Count non-separator characters before displayPosition */
  function toLogicalPosition(text, groupSeparator, displayPosition) {
    let logical = 0;
    for (let i = 0; i < displayPosition && i < text.length; i++) {
      if (text[i] !== groupSeparator) logical++;
    }
    return logical;
  }
  function toDisplayPosition(text, groupSeparator, logicalPosition) {
    let logical = 0;
    for (let i = 0; i <= text.length; i++) {
      if (logical === logicalPosition) return i;
      if (i < text.length && text[i] !== groupSeparator) logical++;
    }
    return text.length;
  }

  /**
   * Process a beforeinput event for plain (non-grouped) number input.
   * Returns { text, cursor } when the input needs correction, or null to let browser handle it.
   */
  function processPlainInput(data, value, selectionStart, selectionEnd, options) {
    if (!data) return null;
    const {
      decimalSeparator,
      precision,
      minusSign
    } = options;
    value = normalizeMinusSign(value);
    const beforePart = value.slice(0, selectionStart);
    let cleanData = extractNumber(data, precision, decimalSeparator);
    if (cleanData.startsWith('-') && beforePart.length > 0) cleanData = cleanData.slice(1);
    if (cleanData.includes(decimalSeparator) && beforePart.includes(decimalSeparator)) {
      cleanData = cleanData.replace(decimalSeparator, '');
    }
    const candidate = beforePart + cleanData + value.slice(selectionEnd);
    const validPattern = new RegExp(`^-?\\d*${escapeForRegex(decimalSeparator)}?\\d*$`);
    if (!validPattern.test(candidate)) {
      return {
        text: localizeMinusSign(extractNumber(candidate, precision, decimalSeparator), minusSign),
        cursor: selectionStart
      };
    }
    if (precision != null && (candidate.split(decimalSeparator)[1]?.length ?? 0) > precision) {
      const text = extractNumber(candidate, precision, decimalSeparator);
      return {
        text: localizeMinusSign(text, minusSign),
        cursor: text === beforePart + value.slice(selectionEnd) ? selectionStart : selectionStart + cleanData.length
      };
    }
    if (cleanData === data) return null;
    return {
      text: localizeMinusSign(candidate, minusSign),
      cursor: selectionStart + cleanData.length
    };
  }

  /**
   * Process a beforeinput event for grouped number input.
   * Returns { text, cursor } to apply, or null for interactions that do not need override
   */
  function processGroupedInput(inputType, data, value, selectionStart, selectionEnd, options) {
    const {
      groupSeparator,
      decimalSeparator,
      precision,
      grouping,
      locale,
      minusSign
    } = options;
    value = normalizeMinusSign(value);
    data = data && normalizeMinusSign(data);
    const raw = stripGrouping(value, groupSeparator);
    const logicalStart = toLogicalPosition(value, groupSeparator, selectionStart);
    const logicalEnd = toLogicalPosition(value, groupSeparator, selectionEnd);
    const hasSelection = logicalStart !== logicalEnd;
    let newRaw;
    let newLogicalCursor;
    switch (inputType) {
      case 'insertText':
        {
          if (!data) return null;
          newRaw = raw.slice(0, logicalStart) + data + raw.slice(logicalEnd);
          newLogicalCursor = logicalStart + data.length;
          break;
        }
      case 'insertFromPaste':
      case 'insertFromDrop':
        {
          if (!data) return null;
          const rawBefore = raw.slice(0, logicalStart);
          let cleanData = extractNumber(data, precision, decimalSeparator);
          if (cleanData.startsWith('-') && rawBefore.length > 0) {
            cleanData = cleanData.slice(1);
          }
          if (cleanData.includes(decimalSeparator) && rawBefore.includes(decimalSeparator)) {
            cleanData = cleanData.replace(decimalSeparator, '');
          }
          newRaw = rawBefore + cleanData + raw.slice(logicalEnd);
          newLogicalCursor = logicalStart + cleanData.length;
          break;
        }
      case 'deleteContentBackward':
        {
          if (hasSelection) {
            newRaw = raw.slice(0, logicalStart) + raw.slice(logicalEnd);
            newLogicalCursor = logicalStart;
          } else if (logicalStart > 0) {
            newRaw = raw.slice(0, logicalStart - 1) + raw.slice(logicalStart);
            newLogicalCursor = logicalStart - 1;
          } else {
            // At the start, nothing to delete
            newRaw = raw;
            newLogicalCursor = 0;
          }
          break;
        }
      case 'deleteContentForward':
        {
          if (hasSelection) {
            newRaw = raw.slice(0, logicalStart) + raw.slice(logicalEnd);
            newLogicalCursor = logicalStart;
          } else if (logicalStart < raw.length) {
            newRaw = raw.slice(0, logicalStart) + raw.slice(logicalStart + 1);
            newLogicalCursor = logicalStart;
          } else {
            // At the end, nothing to delete
            newRaw = raw;
            newLogicalCursor = logicalStart;
          }
          break;
        }
      case 'deleteByCut':
        {
          newRaw = raw.slice(0, logicalStart) + raw.slice(logicalEnd);
          newLogicalCursor = logicalStart;
          break;
        }
      case 'deleteWordBackward':
        {
          if (hasSelection) {
            newRaw = raw.slice(0, logicalStart) + raw.slice(logicalEnd);
            newLogicalCursor = logicalStart;
          } else {
            let deleteEnd = logicalStart;
            // Skip non-digits first (e.g., decimal separator)
            while (deleteEnd > 0 && !/\d/.test(raw[deleteEnd - 1])) deleteEnd--;
            // Then skip digits
            while (deleteEnd > 0 && /\d/.test(raw[deleteEnd - 1])) deleteEnd--;
            newRaw = raw.slice(0, deleteEnd) + raw.slice(logicalStart);
            newLogicalCursor = deleteEnd;
          }
          break;
        }
      case 'deleteWordForward':
        {
          if (hasSelection) {
            newRaw = raw.slice(0, logicalStart) + raw.slice(logicalEnd);
            newLogicalCursor = logicalStart;
          } else {
            let deleteEnd = logicalStart;
            while (deleteEnd < raw.length && !/\d/.test(raw[deleteEnd])) deleteEnd++;
            while (deleteEnd < raw.length && /\d/.test(raw[deleteEnd])) deleteEnd++;
            newRaw = raw.slice(0, logicalStart) + raw.slice(deleteEnd);
            newLogicalCursor = logicalStart;
          }
          break;
        }
      case 'deleteSoftLineBackward':
        {
          newRaw = raw.slice(logicalEnd);
          newLogicalCursor = 0;
          break;
        }
      case 'deleteSoftLineForward':
        {
          newRaw = raw.slice(0, logicalStart);
          newLogicalCursor = logicalStart;
          break;
        }
      default:
        return null;
    }
    const validPattern = new RegExp(`^-?\\d*${escapeForRegex(decimalSeparator)}?\\d*$`);
    if (!validPattern.test(newRaw)) {
      newRaw = extractNumber(newRaw, precision, decimalSeparator);
      newLogicalCursor = Math.min(newLogicalCursor, newRaw.length);
    }
    if (precision != null) {
      const parts = newRaw.split(decimalSeparator);
      if (parts[1]?.length > precision) {
        newRaw = parts[0] + decimalSeparator + parts[1].slice(0, precision);
        newLogicalCursor = Math.min(newLogicalCursor, newRaw.length);
      }
      if (precision === 0 && newRaw.endsWith(decimalSeparator)) {
        newRaw = newRaw.slice(0, -1);
        newLogicalCursor = Math.min(newLogicalCursor, newRaw.length);
      }
    }
    const formatted = addGrouping(newRaw, groupSeparator, decimalSeparator, grouping, locale);
    const cursor = toDisplayPosition(formatted, groupSeparator, newLogicalCursor);
    return {
      text: localizeMinusSign(formatted, minusSign),
      cursor
    };
  }

  // Types

  const makeVNumberInputProps = propsFactory({
    controlVariant: {
      type: String,
      default: 'default'
    },
    inset: Boolean,
    hideInput: Boolean,
    modelValue: {
      type: Number,
      default: null
    },
    min: {
      type: Number,
      default: Number.MIN_SAFE_INTEGER
    },
    max: {
      type: Number,
      default: Number.MAX_SAFE_INTEGER
    },
    step: {
      type: Number,
      default: 1
    },
    precision: {
      type: Number,
      default: 0
    },
    minFractionDigits: {
      type: Number,
      default: null
    },
    decimalSeparator: {
      type: String,
      validator: v => !v || v.length === 1
    },
    grouping: {
      type: [Boolean, String],
      default: false
    },
    groupSeparator: {
      type: String,
      validator: v => !v || v.length === 1 && !/[0-9+-]/.test(v)
    },
    ...omit(makeVTextFieldProps(), ['modelValue', 'validationValue'])
  }, 'VNumberInput');
  const VNumberInput = genericComponent()({
    name: 'VNumberInput',
    props: {
      ...makeVNumberInputProps()
    },
    emits: {
      'update:focused': val => true,
      'update:modelValue': val => true
    },
    setup(props, {
      slots
    }) {
      const vTextFieldRef = vue.ref();
      const {
        holdStart,
        holdStop
      } = useHold({
        toggleUpDown
      });
      const form = useForm(props);
      const controlsDisabled = vue.computed(() => form.isDisabled.value || form.isReadonly.value);
      const isFocused = vue.shallowRef(props.focused);
      const {
        current: locale,
        decimalSeparator: decimalSeparatorFromLocale,
        numericGroupSeparator: numericGroupSeparatorFromLocale
      } = useLocale();
      const decimalSeparator = vue.computed(() => props.decimalSeparator?.[0] || decimalSeparatorFromLocale.value);
      const groupSeparator = vue.computed(() => {
        const separator = props.groupSeparator?.[0] || numericGroupSeparatorFromLocale.value;
        if (separator !== decimalSeparator.value) return separator;
        if (props.grouping) {
          consoleWarn(`decimalSeparator and groupSeparator are both "${separator}", groups will not be separated`);
        }
        return '';
      });
      const minusSign = vue.computed(() => new Intl.NumberFormat(locale.value).formatToParts(-1).find(p => p.type === 'minusSign')?.value ?? '-');
      function toNumber(val) {
        return Number(normalizeMinusSign(val ?? '').replaceAll(groupSeparator.value, '').replace(decimalSeparator.value, '.').replace(/[^0-9.-]/g, ''));
      }
      function correctPrecision(val, precision, trim = true) {
        precision ??= isFocused.value && trim ? undefined : props.precision ?? undefined;
        return formatNumber(val, {
          locale: locale.value,
          precision,
          minFractionDigits: props.minFractionDigits,
          useGrouping: props.grouping,
          decimalSeparator: decimalSeparator.value,
          groupSeparator: groupSeparator.value
        });
      }
      const model = useProxiedModel(props, 'modelValue', null, val => val ?? null, val => val == null ? val ?? null : clamp(Number(val), props.min, props.max));
      const _inputText = vue.shallowRef(null);
      const _lastParsedValue = vue.shallowRef(null);
      vue.watch(model, val => {
        if (isFocused.value && !controlsDisabled.value && toNumber(_inputText.value) === val) ; else if (val == null) {
          _inputText.value = null;
          _lastParsedValue.value = null;
        } else if (!isNaN(val)) {
          _inputText.value = correctPrecision(val);
          _lastParsedValue.value = toNumber(_inputText.value);
        }
      }, {
        immediate: true
      });
      const inputText = vue.computed({
        get: () => _inputText.value,
        set(val) {
          if (val === null || val === '') {
            model.value = null;
            _inputText.value = null;
            _lastParsedValue.value = null;
            return;
          }
          const parsedValue = toNumber(val);
          if (!isNaN(parsedValue)) {
            _inputText.value = val;
            _lastParsedValue.value = parsedValue;
            if (parsedValue <= props.max && parsedValue >= props.min) {
              model.value = parsedValue;
            }
          }
        }
      });
      const isOutOfRange = vue.computed(() => {
        if (_lastParsedValue.value === null) return false;
        const numberFromText = toNumber(_inputText.value);
        return numberFromText !== clamp(numberFromText, props.min, props.max);
      });
      function stepResult(increment) {
        const current = toNumber(inputText.value);
        const stepped = current + (increment ? props.step : -props.step);
        return {
          current,
          stepped,
          next: clamp(stepped, props.min, props.max)
        };
      }
      const canIncrease = vue.computed(() => {
        if (controlsDisabled.value) return false;
        if (model.value == null) return true;
        const {
          current,
          next
        } = stepResult(true);
        return next !== current;
      });
      const canDecrease = vue.computed(() => {
        if (controlsDisabled.value) return false;
        if (model.value == null) return true;
        const {
          current,
          next
        } = stepResult(false);
        return next !== current;
      });
      const controlVariant = vue.computed(() => {
        return props.hideInput ? 'stacked' : props.controlVariant;
      });
      const incrementIcon = vue.toRef(() => controlVariant.value === 'split' ? '$plus' : '$collapse');
      const decrementIcon = vue.toRef(() => controlVariant.value === 'split' ? '$minus' : '$expand');
      const controlNodeSize = vue.toRef(() => controlVariant.value === 'split' ? 'default' : 'small');
      const controlNodeDefaultHeight = vue.toRef(() => controlVariant.value === 'stacked' ? 'auto' : '100%');
      const incrementSlotProps = {
        props: {
          onClick: onControlClick,
          onPointerup: onControlMouseup,
          onPointerdown: onUpControlMousedown,
          onPointercancel: onControlMouseup
        }
      };
      const decrementSlotProps = {
        props: {
          onClick: onControlClick,
          onPointerup: onControlMouseup,
          onPointerdown: onDownControlMousedown,
          onPointercancel: onControlMouseup
        }
      };
      vue.watch(() => [locale.value, decimalSeparator.value, groupSeparator.value, props.precision, props.minFractionDigits], () => formatInputValue());
      function inferPrecision(value) {
        if (value == null) return 0;
        const str = value.toString();
        const idx = str.indexOf('.') + 1;
        return idx ? str.length - idx : 0;
      }
      function emitChange() {
        vTextFieldRef.value?.controlRef?.dispatchEvent(new Event('change', {
          bubbles: true
        }));
      }
      function toggleUpDown(increment = true) {
        if (controlsDisabled.value) return;
        if (increment ? !canIncrease.value : !canDecrease.value) return;
        if (model.value == null) {
          inputText.value = correctPrecision(clamp(0, props.min, props.max));
          emitChange();
          return;
        }
        const {
          current,
          stepped,
          next
        } = stepResult(increment);
        inputText.value = next === stepped ? correctPrecision(next, Math.max(inferPrecision(current), inferPrecision(props.step))) : correctPrecision(next);
        emitChange();
      }
      function onBeforeinput(e) {
        if (controlsDisabled.value) return;
        const inputElement = e.target;
        const result = props.grouping ? processGroupedInput(e.inputType, e.data, inputElement.value ?? '', inputElement.selectionStart ?? 0, inputElement.selectionEnd ?? 0, {
          groupSeparator: groupSeparator.value,
          decimalSeparator: decimalSeparator.value,
          precision: props.precision,
          grouping: props.grouping,
          locale: locale.value,
          minusSign: minusSign.value
        }) : processPlainInput(e.data, inputElement.value ?? '', inputElement.selectionStart ?? 0, inputElement.selectionEnd ?? 0, {
          decimalSeparator: decimalSeparator.value,
          precision: props.precision,
          minusSign: minusSign.value
        });
        if (result === null) return;
        e.preventDefault();
        inputElement.value = result.text;
        inputElement.setSelectionRange(result.cursor, result.cursor);
        vue.nextTick(() => inputText.value = result.text);
      }
      function onKeydown(e) {
        if (['Enter', 'ArrowLeft', 'ArrowRight', 'Backspace', 'Delete', 'Tab'].includes(e.key) || e.ctrlKey) return;
        if (['ArrowDown', 'ArrowUp'].includes(e.key)) {
          e.preventDefault();
          e.stopPropagation();
          toggleUpDown(e.key === 'ArrowUp');
        }
      }
      function onControlClick(e) {
        e.stopPropagation();
      }
      function onControlMouseup(e) {
        const el = e.currentTarget;
        el?.releasePointerCapture(e.pointerId);
        e.preventDefault();
        holdStop();
      }
      function onUpControlMousedown(e) {
        const el = e.currentTarget;
        el?.setPointerCapture(e.pointerId);
        e.preventDefault();
        e.stopPropagation();
        holdStart('up');
      }
      function onDownControlMousedown(e) {
        const el = e.currentTarget;
        el?.setPointerCapture(e.pointerId);
        e.preventDefault();
        e.stopPropagation();
        holdStart('down');
      }
      function clampModel() {
        if (controlsDisabled.value) return;
        if (!vTextFieldRef.value) return;
        const actualText = vTextFieldRef.value.value;
        const parsedValue = toNumber(actualText);
        if (actualText && !isNaN(parsedValue)) {
          inputText.value = correctPrecision(clamp(parsedValue, props.min, props.max));
        } else {
          inputText.value = null;
        }
      }
      function formatInputValue() {
        if (controlsDisabled.value) return;
        inputText.value = model.value !== null && !isNaN(model.value) ? correctPrecision(model.value, props.precision, false) : null;
      }
      function trimDecimalZeros() {
        if (controlsDisabled.value) return;
        if (model.value === null || isNaN(model.value)) {
          inputText.value = null;
          return;
        }
        inputText.value = correctPrecision(model.value);
      }
      function onFocus() {
        trimDecimalZeros();
      }
      function onBlur() {
        clampModel();
      }
      useRender(() => {
        const {
          modelValue: _,
          type,
          ...textFieldProps
        } = VTextField.filterProps(props);
        function incrementControlNode() {
          return !slots.increment ? vue.createVNode(VBtn, {
            "aria-hidden": "true",
            "data-testid": "increment",
            "disabled": !canIncrease.value,
            "height": controlNodeDefaultHeight.value,
            "icon": incrementIcon.value,
            "key": "increment-btn",
            "onClick": onControlClick,
            "onPointerdown": onUpControlMousedown,
            "onPointerup": onControlMouseup,
            "onPointercancel": onControlMouseup,
            "size": controlNodeSize.value,
            "variant": "text",
            "tabindex": "-1"
          }, null) : vue.createVNode(VDefaultsProvider, {
            "key": "increment-defaults",
            "defaults": {
              VBtn: {
                disabled: !canIncrease.value,
                height: controlNodeDefaultHeight.value,
                size: controlNodeSize.value,
                icon: incrementIcon.value,
                variant: 'text'
              }
            }
          }, {
            default: () => [slots.increment(incrementSlotProps)]
          });
        }
        function decrementControlNode() {
          return !slots.decrement ? vue.createVNode(VBtn, {
            "aria-hidden": "true",
            "data-testid": "decrement",
            "disabled": !canDecrease.value,
            "height": controlNodeDefaultHeight.value,
            "icon": decrementIcon.value,
            "key": "decrement-btn",
            "onClick": onControlClick,
            "onPointerdown": onDownControlMousedown,
            "onPointerup": onControlMouseup,
            "onPointercancel": onControlMouseup,
            "size": controlNodeSize.value,
            "variant": "text",
            "tabindex": "-1"
          }, null) : vue.createVNode(VDefaultsProvider, {
            "key": "decrement-defaults",
            "defaults": {
              VBtn: {
                disabled: !canDecrease.value,
                height: controlNodeDefaultHeight.value,
                size: controlNodeSize.value,
                icon: decrementIcon.value,
                variant: 'text'
              }
            }
          }, {
            default: () => [slots.decrement(decrementSlotProps)]
          });
        }
        function controlNode() {
          return vue.createElementVNode("div", {
            "class": "v-number-input__control"
          }, [decrementControlNode(), vue.createVNode(VDivider, {
            "vertical": controlVariant.value !== 'stacked'
          }, null), incrementControlNode()]);
        }
        function dividerNode() {
          return !props.hideInput && !props.inset ? vue.createVNode(VDivider, {
            "vertical": true
          }, null) : undefined;
        }
        const appendInnerControl = controlVariant.value === 'split' ? vue.createElementVNode("div", {
          "class": "v-number-input__control"
        }, [vue.createVNode(VDivider, {
          "vertical": true
        }, null), incrementControlNode()]) : props.reverse || controlVariant.value === 'hidden' ? undefined : vue.createElementVNode(vue.Fragment, null, [dividerNode(), controlNode()]);
        const hasAppendInner = slots['append-inner'] || appendInnerControl;
        const prependInnerControl = controlVariant.value === 'split' ? vue.createElementVNode("div", {
          "class": "v-number-input__control"
        }, [decrementControlNode(), vue.createVNode(VDivider, {
          "vertical": true
        }, null)]) : props.reverse && controlVariant.value !== 'hidden' ? vue.createElementVNode(vue.Fragment, null, [controlNode(), dividerNode()]) : undefined;
        const hasPrependInner = slots['prepend-inner'] || prependInnerControl;
        return vue.createVNode(VTextField, vue.mergeProps({
          "ref": vTextFieldRef
        }, textFieldProps, {
          "modelValue": inputText.value,
          "onUpdate:modelValue": $event => inputText.value = $event,
          "focused": isFocused.value,
          "onUpdate:focused": $event => isFocused.value = $event,
          "validationValue": model.value,
          "error": props.error || isOutOfRange.value || undefined,
          "onBeforeinput": onBeforeinput,
          "onFocus": onFocus,
          "onBlur": onBlur,
          "onKeydown": onKeydown,
          "class": ['v-number-input', {
            'v-number-input--default': controlVariant.value === 'default',
            'v-number-input--hide-input': props.hideInput,
            'v-number-input--inset': props.inset,
            'v-number-input--reverse': props.reverse,
            'v-number-input--split': controlVariant.value === 'split',
            'v-number-input--stacked': controlVariant.value === 'stacked'
          }, props.class],
          "style": props.style,
          "inputmode": "decimal"
        }), {
          ...slots,
          'append-inner': hasAppendInner ? (...args) => vue.createElementVNode(vue.Fragment, null, [slots['append-inner']?.(...args), appendInnerControl]) : undefined,
          'prepend-inner': hasPrependInner ? (...args) => vue.createElementVNode(vue.Fragment, null, [prependInnerControl, slots['prepend-inner']?.(...args)]) : undefined
        });
      });
      return forwardRefs({}, vTextFieldRef);
    }
  });

  // Types

  const VOtpInputSymbol = Symbol.for('vuetify:v-otp-input');

  const makeVOtpFieldProps = propsFactory({
    index: {
      type: Number,
      required: true
    }
  }, 'VOtpField');
  const VOtpField = genericComponent()({
    name: 'VOtpField',
    props: makeVOtpFieldProps(),
    setup(props) {
      const otpInput = vue.inject(VOtpInputSymbol);
      if (!otpInput) {
        throw new Error('[Vuetify] VOtpField must be used inside VOtpInput');
      }
      const slot = vue.computed(() => otpInput.otpSlots.value[props.index]);
      const isHighlighted = vue.computed(() => otpInput.isFocused.value && otpInput.focusAll.value && !slot.value?.isActive);
      useRender(() => {
        if (!slot.value) return vue.createCommentVNode();
        return vue.createVNode(VField, {
          "data-otp-index": props.index,
          "focused": slot.value.isActive || isHighlighted.value,
          "class": vue.normalizeClass({
            'v-otp-input__field--highlighted': isHighlighted.value
          }),
          "onMousedown": e => e.preventDefault(),
          "onClick": () => otpInput.focusAt(props.index)
        }, {
          loader: undefined,
          default: () => vue.createElementVNode("div", {
            "class": "v-otp-input__field"
          }, [vue.createElementVNode("input", {
            "class": "v-otp-input__spacer",
            "aria-hidden": "true",
            "tabindex": "-1"
          }, null), slot.value.compositionChar ? vue.createElementVNode("span", {
            "class": "v-otp-input__composition"
          }, [slot.value.compositionChar]) : slot.value.hasFakeCaret ? vue.createElementVNode("span", {
            "class": "v-otp-input__caret"
          }, null) : vue.createElementVNode("span", {
            "class": vue.normalizeClass(!slot.value.char ? 'v-otp-input__placeholder' : undefined)
          }, [slot.value.char ?? slot.value.placeholderChar ?? ''])])
        });
      });
    }
  });

  // Utilities

  // Types

  function countSlotChildren(vnodes) {
    let count = 0;
    for (const vnode of vnodes) {
      if (vnode.type === vue.Fragment && Array.isArray(vnode.children)) {
        count += countSlotChildren(vnode.children);
      } else {
        count++;
      }
    }
    return count;
  }
  const makeVOtpGroupProps = propsFactory({
    merged: {
      type: Boolean,
      default: null
    }
  }, 'VOtpGroup');
  const VOtpGroup = genericComponent()({
    name: 'VOtpGroup',
    props: makeVOtpGroupProps(),
    setup(props, {
      slots
    }) {
      const otpInput = vue.inject(VOtpInputSymbol);
      const isMerged = vue.computed(() => props.merged ?? otpInput?.merged.value ?? false);
      useRender(() => {
        const children = slots.default?.() ?? [];
        return vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-otp-group', {
            'v-otp-group--merged': isMerged.value
          }]),
          "style": vue.normalizeStyle(isMerged.value ? {
            flex: countSlotChildren(children)
          } : undefined)
        }, [children]);
      });
    }
  });

  // Utilities
  const VOtpSeparator = createSimpleFunctional('v-otp-input__divider');

  // to be replaced by v0 implementation in v5.0


  // Types

  const OtpInputPatterns = {
    numeric: /[0-9]/,
    alpha: /[a-zA-Z]/,
    alphanumeric: /[a-zA-Z0-9]/,
    'unicode-alpha': /\p{L}/u,
    'unicode-alphanumeric': /[\p{L}\p{N}]/u
  };
  const IME_SCRIPT_RE = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Bopomofo}]/u;
  const graphemeSegmenter = /* @__PURE__ */new Intl.Segmenter(undefined, {
    granularity: 'grapheme'
  });
  function useOtpInput(options) {
    const {
      value,
      length: _length = 6,
      pattern,
      type = 'number',
      masked = false,
      placeholder,
      isFocused = vue.shallowRef(false)
    } = options;
    const selection = vue.shallowRef(null);
    const composition = vue.shallowRef('');
    const isComposing = vue.shallowRef(false);
    let prevSelection = null;
    // Shift+Arrow anchor/focus tracked in grapheme space.
    let anchorG = null;
    let focusG = null;
    const length = vue.toRef(() => Number(vue.toValue(_length)));
    const isMasked = vue.toRef(() => vue.toValue(masked) || vue.toValue(type) === 'password');
    const effectivePattern = vue.toRef(() => {
      const p = vue.toValue(pattern);
      if (p instanceof RegExp) return p;
      if (p != null) return OtpInputPatterns[p] ?? null;
      if (vue.toValue(type) === 'number') return OtpInputPatterns.numeric;
      return null;
    });
    const inputMode = vue.toRef(() => effectivePattern.value === OtpInputPatterns.numeric ? 'numeric' : 'text');

    // Selection is stored in code units (for `setSelectionRange`), but every slot
    // boundary works in grapheme space so emoji, ZWJ sequences and skin-tone
    // modifiers each occupy one slot.
    function graphemes(s) {
      return Array.from(graphemeSegmenter.segment(s), seg => seg.segment);
    }
    function codeUnitsToGraphemeIndex(s, pos) {
      let count = 0;
      for (const seg of graphemeSegmenter.segment(s)) {
        if (seg.index >= pos) break;
        count++;
      }
      return count;
    }
    function graphemeIndexToCodeUnits(s, gIndex) {
      if (gIndex <= 0) return 0;
      let count = 0;
      for (const seg of graphemeSegmenter.segment(s)) {
        if (count === gIndex) return seg.index;
        count++;
      }
      return s.length;
    }
    const slots = vue.computed(() => {
      const chars = graphemes(value.value);
      const compositionChars = graphemes(composition.value);
      const placeholderChar = vue.toValue(placeholder) ?? null;
      const currentSelection = selection.value;
      const startG = currentSelection ? codeUnitsToGraphemeIndex(value.value, currentSelection.start) : null;
      const endG = currentSelection ? codeUnitsToGraphemeIndex(value.value, currentSelection.end) : null;
      const compositionStart = startG ?? chars.length;
      return Array.from({
        length: length.value
      }, (_, i) => {
        const char = chars[i] ?? null;
        const displayChar = char !== null && isMasked.value ? '•' : char;
        let compositionChar = null;
        if (composition.value && i >= compositionStart) {
          const offset = i - compositionStart;
          const c = compositionChars[offset];
          if (c != null) compositionChar = isMasked.value ? '•' : c;
        }
        const isActive = isFocused.value && startG !== null && endG !== null && (startG === endG && i === startG || i >= startG && i < endG);
        return {
          char: displayChar,
          compositionChar,
          placeholderChar,
          isActive,
          hasFakeCaret: isActive && char === null && compositionChar === null
        };
      });
    });
    function filter(text) {
      const re = effectivePattern.value;
      if (!re) return text;
      return graphemes(text).filter(c => re.test(c)).join('');
    }
    function clampGraphemes(text, max) {
      const chars = graphemes(text);
      if (chars.length <= max) return text;
      return chars.slice(0, max).join('');
    }
    function isImeText(text) {
      return IME_SCRIPT_RE.test(text);
    }
    function setValue(text) {
      const next = clampGraphemes(filter(text), length.value);
      value.value = next;
      return next;
    }
    function insert(text, range) {
      const current = value.value;
      const start = range?.start ?? current.length;
      const end = range?.end ?? current.length;
      const filtered = filter(text);
      const next = clampGraphemes(current.slice(0, start) + filtered + current.slice(end), length.value);
      value.value = next;
      const insertEnd = Math.min(start + filtered.length, next.length);
      const insertEndG = codeUnitsToGraphemeIndex(next, insertEnd);
      const cursorG = Math.min(insertEndG, length.value - 1);
      const cursor = graphemeIndexToCodeUnits(next, cursorG);
      setSelection(cursor, insertEnd, 'forward');
      return next;
    }
    function deleteRange(start, end) {
      const current = value.value;
      const next = current.slice(0, start) + current.slice(end);
      value.value = next;
      const newEnd = Math.min(start + 1, next.length);
      setSelection(start, newEnd, 'forward');
      return next;
    }
    function bulkDelete(isBackward) {
      const current = value.value;
      const currentSelection = selection.value;
      const next = isBackward ? current.slice(currentSelection?.end ?? current.length) : current.slice(0, currentSelection?.start ?? 0);
      value.value = next;
      if (next.length === 0) setSelection(0, 0, 'none');else if (isBackward) setSelection(0, 1, 'forward');else setSelection(next.length, next.length, 'none');
      return next;
    }
    function setSelection(start, end, direction = 'none') {
      if (start === null || end === null) {
        selection.value = null;
        anchorG = null;
        focusG = null;
        return;
      }
      const next = {
        start,
        end,
        direction
      };
      selection.value = next;
      prevSelection = next;
      const startG = codeUnitsToGraphemeIndex(value.value, start);
      anchorG = startG;
      focusG = startG;
    }
    function clearSelection() {
      selection.value = null;
      anchorG = null;
      focusG = null;
    }
    function selectAtEnd() {
      const current = value.value;
      const graphemeCount = graphemes(current).length;
      let start;
      let end;
      if (graphemeCount >= length.value) {
        // Full: range over the last slot so it renders as active.
        start = graphemeIndexToCodeUnits(current, length.value - 1);
        end = current.length;
      } else {
        // Partial: single caret at the end of the typed content.
        start = current.length;
        end = current.length;
      }
      const next = {
        start,
        end,
        direction: 'forward'
      };
      selection.value = next;
      prevSelection = next;
      anchorG = graphemeCount >= length.value ? length.value - 1 : graphemeCount;
      focusG = anchorG;
      return next;
    }
    function selectSlot(index) {
      const current = value.value;
      const graphemeCount = graphemes(current).length;
      const clamped = Math.min(index, graphemeCount);
      const start = graphemeIndexToCodeUnits(current, clamped);
      const end = clamped < graphemeCount ? graphemeIndexToCodeUnits(current, clamped + 1) : current.length;
      const next = {
        start,
        end,
        direction: 'forward'
      };
      selection.value = next;
      prevSelection = next;
      anchorG = clamped;
      focusG = clamped;
      return next;
    }
    function moveCaret(direction) {
      const current = value.value;
      if (graphemes(current).length === 0) return null;
      const currentSelection = selection.value;
      const currentG = currentSelection ? codeUnitsToGraphemeIndex(current, currentSelection.start) : 0;
      return selectSlot(Math.max(0, currentG + direction));
    }
    function extendSelection(direction) {
      const current = value.value;
      const valueG = graphemes(current).length;
      if (valueG === 0) return null;
      const maxFocus = Math.min(length.value - 1, valueG);

      // Fallback when Shift+Arrow fires before anchor/focus were tracked.
      if (anchorG === null || focusG === null) {
        const currentSelection = selection.value;
        if (!currentSelection) return null;
        const selectionStartG = codeUnitsToGraphemeIndex(current, currentSelection.start);
        const selectionEndG = codeUnitsToGraphemeIndex(current, currentSelection.end);
        if (selectionEndG - selectionStartG <= 1) {
          anchorG = selectionStartG;
          focusG = selectionStartG;
        } else if (currentSelection.direction === 'backward') {
          anchorG = selectionEndG - 1;
          focusG = selectionStartG;
        } else {
          anchorG = selectionStartG;
          focusG = selectionEndG - 1;
        }
      }
      const newFocus = Math.max(0, Math.min(maxFocus, focusG + direction));
      focusG = newFocus;
      const minG = Math.min(anchorG, newFocus);
      const maxG = Math.max(anchorG, newFocus);
      const start = graphemeIndexToCodeUnits(current, minG);
      const end = maxG + 1 >= valueG ? current.length : graphemeIndexToCodeUnits(current, maxG + 1);
      const newDirection = newFocus < anchorG ? 'backward' : 'forward';
      const next = {
        start,
        end,
        direction: newDirection
      };
      selection.value = next;
      prevSelection = next;
      return next;
    }

    // Force the rendered selection to always cover at least one slot, so a slot
    // stays "active" when a caret would otherwise be between two.
    function syncSelection(raw) {
      if (isComposing.value) return selection.value;
      const {
        value: inputValue,
        selectionStart,
        selectionEnd,
        selectionDirection,
        maxLength
      } = raw;
      if (selectionStart === null || selectionEnd === null) {
        selection.value = null;
        prevSelection = null;
        return null;
      }
      const valueG = graphemes(inputValue).length;
      const startG = codeUnitsToGraphemeIndex(inputValue, selectionStart);
      const endG = codeUnitsToGraphemeIndex(inputValue, selectionEnd);
      let outStartG = -1;
      let outEndG = -1;
      let direction;
      if (valueG !== 0) {
        const isSingleCaret = startG === endG;
        const isInsertMode = startG === valueG && valueG < maxLength;
        if (isSingleCaret && !isInsertMode) {
          if (startG === 0) {
            outStartG = 0;
            outEndG = 1;
            direction = 'forward';
          } else if (startG === maxLength) {
            outStartG = startG - 1;
            outEndG = startG;
            direction = 'backward';
          } else if (maxLength > 1 && valueG > 1) {
            let offset = 0;
            if (prevSelection !== null) {
              const prevStartG = codeUnitsToGraphemeIndex(inputValue, prevSelection.start);
              const prevEndG = codeUnitsToGraphemeIndex(inputValue, prevSelection.end);
              direction = startG < prevEndG ? 'backward' : 'forward';
              const wasPreviouslyInserting = prevStartG === prevEndG && prevStartG < maxLength;
              // Multi-slot collapse: caret landed at an edge of the prior range,
              // user didn't navigate between slots, so don't shift the slot back.
              const wasMultiSlot = prevEndG - prevStartG > 1;
              if (direction === 'backward' && !wasPreviouslyInserting && !wasMultiSlot) {
                offset = -1;
              }
            }
            outStartG = offset + startG;
            outEndG = offset + startG + 1;
          }
        }
      }
      const finalStartG = outStartG !== -1 ? outStartG : startG;
      const finalEndG = outEndG !== -1 ? outEndG : endG;
      const finalStart = graphemeIndexToCodeUnits(inputValue, finalStartG);
      const finalEnd = graphemeIndexToCodeUnits(inputValue, finalEndG);
      const finalDirection = direction ?? selectionDirection ?? 'none';
      const next = {
        start: finalStart,
        end: finalEnd,
        direction: finalDirection
      };
      selection.value = next;
      prevSelection = next;
      // Reset anchor on plain navigation; preserve it during extendSelection's round-trip.
      if (finalEndG - finalStartG <= 1) {
        anchorG = finalStartG;
        focusG = finalStartG;
      }
      return next;
    }
    function startComposition() {
      isComposing.value = true;
      composition.value = '';
    }
    function updateComposition(data) {
      composition.value = IME_SCRIPT_RE.test(data) ? data : '';
    }
    function endComposition() {
      isComposing.value = false;
      composition.value = '';
    }
    function reset() {
      value.value = '';
      selection.value = null;
      composition.value = '';
      isComposing.value = false;
      prevSelection = null;
      anchorG = null;
      focusG = null;
    }
    return {
      value,
      length,
      slots,
      selection,
      composition,
      isComposing,
      isFocused,
      effectivePattern,
      inputMode,
      filter,
      isImeText,
      setValue,
      insert,
      deleteRange,
      bulkDelete,
      syncSelection,
      setSelection,
      clearSelection,
      selectAtEnd,
      selectSlot,
      moveCaret,
      extendSelection,
      startComposition,
      updateComposition,
      endComposition,
      reset
    };
  }

  const makeVOtpInputProps = propsFactory({
    autofocus: Boolean,
    divider: String,
    focusAll: Boolean,
    merged: Boolean,
    label: {
      type: String,
      default: '$vuetify.input.otp'
    },
    length: {
      type: [Number, String],
      default: 6
    },
    masked: Boolean,
    modelValue: {
      type: [Number, String],
      default: undefined
    },
    pattern: {
      type: [String, Object],
      default: undefined
    },
    placeholder: String,
    type: {
      type: String,
      default: 'number'
    },
    ...makeDensityProps(),
    ...makeDimensionProps(),
    ...makeFocusProps(),
    ...pick(makeVFieldProps({
      variant: 'outlined'
    }), ['baseColor', 'bgColor', 'class', 'color', 'disabled', 'error', 'loading', 'rounded', 'style', 'theme', 'variant'])
  }, 'VOtpInput');
  const VOtpInput = genericComponent()({
    name: 'VOtpInput',
    props: makeVOtpInputProps(),
    emits: {
      finish: value => true,
      'update:focused': value => true,
      'update:modelValue': value => true
    },
    setup(props, {
      attrs,
      emit,
      slots
    }) {
      const {
        densityClasses
      } = useDensity(props);
      const {
        dimensionStyles
      } = useDimension(props);
      const {
        isFocused
      } = useFocus(props);
      const {
        t
      } = useLocale();
      const {
        isRtl
      } = useRtl();
      const model = useProxiedModel(props, 'modelValue', '', val => val == null ? '' : String(val));
      const inputRef = vue.ref();
      const length = vue.toRef(() => Number(props.length));
      let focusAtPending = false;
      const otp = useOtpInput({
        value: model,
        length,
        pattern: () => props.pattern,
        type: () => props.type,
        masked: () => props.masked,
        placeholder: () => props.placeholder,
        isFocused
      });
      function applySelection() {
        const input = inputRef.value;
        const selection = otp.selection.value;
        if (!input || !selection) return;
        input.setSelectionRange(selection.start, selection.end, selection.direction);
      }
      function syncDOM() {
        const input = inputRef.value;
        if (!input) return;
        if (input.value !== otp.value.value) input.value = otp.value.value;
        applySelection();
      }
      function onSelectionChange() {
        const input = inputRef.value;
        if (!input) {
          otp.clearSelection();
          return;
        }
        const result = otp.syncSelection({
          value: input.value,
          selectionStart: input.selectionStart,
          selectionEnd: input.selectionEnd,
          selectionDirection: input.selectionDirection,
          // Slot count, not `input.maxLength` (code units).
          maxLength: length.value
        });
        if (!result) return;
        if (input.selectionStart !== result.start || input.selectionEnd !== result.end) {
          input.setSelectionRange(result.start, result.end, result.direction);
        }
      }
      function onInput(e) {
        const ev = e;
        const target = e.target;
        const composing = ev.isComposing || otp.isComposing.value;

        // CJK composition renders via the overlay until compositionend.
        if (composing && otp.isImeText(target.value)) return;

        // Non-CJK composition (dead keys, Samsung predictive, Chrome OTP autofill)
        // commits into the model now; don't end composition early or selection
        // will advance past the model length on the next selectionchange.
        const next = otp.setValue(target.value);
        if (target.value !== next) target.value = next;
      }
      function onCompositionstart() {
        otp.startComposition();
      }
      function onCompositionupdate(e) {
        otp.updateComposition(e.data ?? '');
      }
      function onCompositionend(e) {
        otp.endComposition();
        onInput(e);
      }
      function onFocus() {
        isFocused.value = true;
        if (focusAtPending) return;
        if (!inputRef.value) return;
        otp.selectAtEnd();
        applySelection();
      }
      function onBlur() {
        isFocused.value = false;
        otp.clearSelection();
      }
      function onKeydown(e) {
        if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
          const direction = (e.key === 'ArrowLeft' ? -1 : 1) * (isRtl.value ? -1 : 1);
          const moved = e.shiftKey ? otp.extendSelection(direction) : otp.moveCaret(direction);
          if (moved) {
            e.preventDefault();
            syncDOM();
          }
          return;
        }
        if (e.key !== 'Backspace' && e.key !== 'Delete') return;
        if (!e.metaKey && !e.ctrlKey && !e.altKey) return;
        e.preventDefault();
        otp.bulkDelete(e.key === 'Backspace');
        syncDOM();
      }
      function onBeforeinput(e) {
        if (e.inputType === 'insertText' && e.data && otp.effectivePattern.value && !otp.effectivePattern.value.test(e.data)) {
          e.preventDefault();
          return;
        }
        if (e.inputType === 'deleteContentForward') {
          e.preventDefault();
          const input = inputRef.value;
          if (!input) return;
          const selection = otp.selection.value;
          const start = selection?.start ?? 0;
          const end = selection?.end ?? input.value.length;
          otp.deleteRange(start, end);
          syncDOM();
          return;
        }
        const isBackward = ['deleteWordBackward', 'deleteSoftLineBackward', 'deleteHardLineBackward'].includes(e.inputType);
        const isForward = ['deleteWordForward', 'deleteSoftLineForward', 'deleteHardLineForward'].includes(e.inputType);
        if (!isBackward && !isForward) return;
        e.preventDefault();
        otp.bulkDelete(isBackward);
        syncDOM();
      }
      function onPaste(e) {
        e.preventDefault();
        const input = inputRef.value;
        if (!input) return;
        const text = e.clipboardData?.getData('text/plain').trim() ?? '';
        const selection = otp.selection.value;
        otp.insert(text, {
          start: selection?.start ?? 0,
          end: selection?.end ?? input.value.length
        });
        syncDOM();
      }
      function focusAt(index) {
        const input = inputRef.value;
        if (!input) return;
        focusAtPending = true;
        input.focus();
        focusAtPending = false;
        otp.selectSlot(index);
        applySelection();
      }
      function slotIndexAtPoint(x, y) {
        const slot = document.elementsFromPoint(x, y).find(el => el.hasAttribute('data-otp-index'));
        const index = slot ? Number(slot.getAttribute('data-otp-index')) : NaN;
        return Number.isNaN(index) ? null : index;
      }
      function onClick(e) {
        const index = slotIndexAtPoint(e.clientX, e.clientY);
        if (index != null) focusAt(index);
      }

      // selectionchange is not in InputHTMLAttributes types
      vue.watch(inputRef, (input, _, onCleanup) => {
        if (!input) return;
        input.addEventListener('selectionchange', onSelectionChange);
        onCleanup(() => input.removeEventListener('selectionchange', onSelectionChange));
      }, {
        immediate: true
      });
      useToggleScope(() => props.autofocus, () => {
        const intersectScope = vue.effectScope();
        intersectScope.run(() => {
          const {
            intersectionRef,
            isIntersecting
          } = useIntersectionObserver();
          vue.watchEffect(() => {
            intersectionRef.value = inputRef.value;
          });
          vue.watch(isIntersecting, v => {
            if (!v) return;
            intersectionRef.value?.focus();
            intersectScope.stop();
          });
        });
      });
      vue.watch(model, val => {
        if (otp.isComposing.value) return;
        if (val.length === length.value) emit('finish', val);
      });
      provideDefaults({
        VField: {
          color: vue.toRef(() => props.color),
          bgColor: vue.toRef(() => props.color),
          baseColor: vue.toRef(() => props.baseColor),
          disabled: vue.toRef(() => props.disabled),
          error: vue.toRef(() => props.error),
          variant: vue.toRef(() => props.variant),
          rounded: vue.toRef(() => props.rounded)
        }
      }, {
        scoped: true
      });
      vue.provide(VOtpInputSymbol, {
        otpSlots: otp.slots,
        isFocused,
        focusAll: vue.toRef(() => props.focusAll),
        divider: vue.toRef(() => props.divider),
        merged: vue.toRef(() => props.merged),
        focusAt
      });
      useRender(() => {
        const [rootAttrs, inputAttrs] = filterInputAttrs(attrs);
        return vue.createElementVNode("div", vue.mergeProps({
          "class": ['v-otp-input', {
            'v-otp-input--divided': !!props.divider
          }, densityClasses.value, props.class],
          "style": [props.style]
        }, rootAttrs), [vue.createElementVNode("div", {
          "class": "v-otp-input__content",
          "style": vue.normalizeStyle([dimensionStyles.value])
        }, [slots.fields ? slots.fields() : props.merged ? vue.createVNode(VOtpGroup, {
          "merged": true
        }, {
          default: () => [Array.from({
            length: length.value
          }, (_, i) => vue.createVNode(VOtpField, {
            "index": i,
            "key": i
          }, null))]
        }) : Array.from({
          length: length.value
        }, (_, i) => vue.createElementVNode(vue.Fragment, null, [(props.divider || slots.divider) && i !== 0 && vue.createVNode(VOtpSeparator, {
          "key": `d-${i}`
        }, {
          default: () => [slots.divider?.({
            index: i - 1
          }) ?? props.divider]
        }), vue.createVNode(VOtpField, {
          "index": i,
          "key": i
        }, null)])), vue.createElementVNode("input", vue.mergeProps({
          "ref": inputRef,
          "class": "v-otp-input__input",
          "type": "text",
          "inputmode": otp.inputMode.value,
          "dir": isRtl.value ? 'rtl' : 'ltr',
          "autocomplete": "one-time-code",
          "autocorrect": "off",
          "autocapitalize": "off",
          "spellcheck": false,
          "disabled": props.disabled,
          "aria-label": t(props.label),
          "value": model.value
        }, inputAttrs, {
          "onClick": onClick,
          "onInput": onInput,
          "onKeydown": onKeydown,
          "onBeforeinput": onBeforeinput,
          "onFocus": onFocus,
          "onBlur": onBlur,
          "onPaste": onPaste,
          "onCompositionstart": onCompositionstart,
          "onCompositionupdate": onCompositionupdate,
          "onCompositionend": onCompositionend
        }), null), vue.createVNode(VOverlay, {
          "contained": true,
          "contentClass": "v-otp-input__loader",
          "modelValue": !!props.loading,
          "persistent": true
        }, {
          default: () => [slots.loader?.() ?? vue.createVNode(VProgressCircular, {
            "color": typeof props.loading === 'boolean' ? undefined : props.loading,
            "indeterminate": true,
            "size": "24",
            "width": "2"
          }, null)]
        }), slots.default?.()])]);
      });
      return {
        blur: () => {
          inputRef.value?.blur();
        },
        focus: () => {
          inputRef.value?.focus();
        },
        reset: otp.reset,
        isFocused
      };
    }
  });

  // Types

  function floor(val) {
    return Math.floor(Math.abs(val)) * Math.sign(val);
  }
  const makeVParallaxProps = propsFactory({
    scale: {
      type: [Number, String],
      default: 0.5
    },
    ...makeComponentProps()
  }, 'VParallax');
  const VParallax = genericComponent()({
    name: 'VParallax',
    props: makeVParallaxProps(),
    setup(props, {
      slots
    }) {
      const {
        intersectionRef,
        isIntersecting
      } = useIntersectionObserver();
      const {
        resizeRef,
        contentRect
      } = useResizeObserver();
      const {
        height: displayHeight
      } = useDisplay();
      const root = vue.ref();
      vue.watchEffect(() => {
        intersectionRef.value = resizeRef.value = root.value?.$el;
      });
      let scrollParent;
      vue.watch(isIntersecting, val => {
        if (val) {
          scrollParent = getScrollParent(intersectionRef.value);
          scrollParent = scrollParent === document.scrollingElement ? document : scrollParent;
          scrollParent.addEventListener('scroll', onScroll, {
            passive: true
          });
          onScroll();
        } else {
          scrollParent.removeEventListener('scroll', onScroll);
        }
      });
      vue.onBeforeUnmount(() => {
        scrollParent?.removeEventListener('scroll', onScroll);
      });
      vue.watch(displayHeight, onScroll);
      vue.watch(() => contentRect.value?.height, onScroll);
      const scale = vue.computed(() => {
        return 1 - clamp(Number(props.scale));
      });
      let frame = -1;
      function onScroll() {
        if (!isIntersecting.value || PREFERS_REDUCED_MOTION()) return;
        cancelAnimationFrame(frame);
        frame = requestAnimationFrame(() => {
          const el = (root.value?.$el).querySelector('.v-img__img');
          if (!el) return;
          const scrollHeight = scrollParent instanceof Document ? document.documentElement.clientHeight : scrollParent.clientHeight;
          const scrollPos = scrollParent instanceof Document ? window.scrollY : scrollParent.scrollTop;
          const top = intersectionRef.value.getBoundingClientRect().top + scrollPos;
          const height = contentRect.value.height;
          const center = top + (height - scrollHeight) / 2;
          const translate = floor((scrollPos - center) * scale.value);
          const sizeScale = Math.max(1, (scale.value * (scrollHeight - height) + height) / height);
          el.style.setProperty('transform', `translateY(${translate}px) scale(${sizeScale})`);
        });
      }
      useRender(() => vue.createVNode(VImg, {
        "class": vue.normalizeClass(['v-parallax', {
          'v-parallax--active': isIntersecting.value
        }, props.class]),
        "style": vue.normalizeStyle(props.style),
        "ref": root,
        "cover": true,
        "onLoadstart": onScroll,
        "onLoad": onScroll
      }, slots));
      return {};
    }
  });

  const VPullToRefresh = genericComponent()({
    name: 'VPullToRefresh',
    props: {
      disabled: Boolean,
      pullDownThreshold: {
        type: Number,
        default: 64
      }
    },
    emits: {
      load: options => true
    },
    setup(props, {
      slots,
      emit
    }) {
      let touchstartY = 0;
      let scrollParents = [];
      const touchDiff = vue.shallowRef(0);
      const containerRef = vue.ref();
      const refreshing = vue.shallowRef(false);
      const goingUp = vue.shallowRef(false);
      const touching = vue.shallowRef(false);
      const canRefresh = vue.computed(() => touchDiff.value >= props.pullDownThreshold && !refreshing.value);
      const topOffset = vue.computed(() => clamp(touchDiff.value, 0, props.pullDownThreshold));
      function onTouchstart(e) {
        if (refreshing.value || props.disabled) return;
        touching.value = true;
        touchstartY = 'clientY' in e ? e.clientY : e.touches[0].clientY;
      }
      function onTouchmove(e) {
        if (refreshing.value || !touching.value || props.disabled) return;
        const touchY = 'clientY' in e ? e.clientY : e.touches[0].clientY;
        if (scrollParents.length && !scrollParents[0].scrollTop) {
          touchDiff.value = touchY - touchstartY;
        }
      }
      function onTouchend(e) {
        if (refreshing.value || props.disabled) return;
        touching.value = false;
        if (canRefresh.value) {
          function done() {
            if (!refreshing.value) return;
            touchDiff.value = 0;
            refreshing.value = false;
          }
          emit('load', {
            done
          });
          refreshing.value = true;
        } else {
          touchDiff.value = 0;
        }
      }
      vue.onMounted(() => {
        scrollParents = getScrollParents(containerRef.value);
      });
      vue.watch([topOffset, refreshing], () => {
        if (scrollParents.length) {
          const stopScrolling = topOffset.value && !refreshing.value;
          scrollParents.forEach(p => p.style.overflow = stopScrolling ? 'hidden' : 'auto');
        }
      });
      vue.watch(topOffset, (newVal, oldVal) => {
        goingUp.value = newVal < oldVal;
      });
      useRender(() => {
        return vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-pull-to-refresh']),
          "onTouchstart": onTouchstart,
          "onTouchmove": onTouchmove,
          "onTouchend": onTouchend,
          "onMousedown": onTouchstart,
          "onMouseup": onTouchend,
          "onMouseleave": onTouchend,
          "onMousemove": onTouchmove,
          "ref": containerRef
        }, [vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-pull-to-refresh__pull-down', {
            'v-pull-to-refresh__pull-down--touching': touching.value
          }]),
          "style": {
            top: convertToUnit(-1 * props.pullDownThreshold + topOffset.value),
            height: convertToUnit(props.pullDownThreshold)
          }
        }, [slots.pullDownPanel ? slots.pullDownPanel({
          canRefresh: canRefresh.value,
          goingUp: goingUp.value,
          refreshing: refreshing.value
        }) : vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-pull-to-refresh__pull-down-default'])
        }, [refreshing.value ? vue.createVNode(VProgressCircular, {
          "indeterminate": true,
          "active": false
        }, null) : vue.createVNode(VIcon, {
          "icon": canRefresh.value || goingUp.value ? '$sortAsc' : '$sortDesc'
        }, null)])]), vue.createElementVNode("div", {
          "class": vue.normalizeClass(['v-pull-to-refresh__scroll-container', {
            'v-pull-to-refresh__scroll-container--touching': touching.value
          }]),
          "style": {
            top: convertToUnit(topOffset.value)
          }
        }, [slots.default?.()])]);
      });
    }
  });

  // Types

  const makeVRadioProps = propsFactory({
    ...omit(makeVSelectionControlProps({
      falseIcon: '$radioOff',
      trueIcon: '$radioOn'
    }), ['indeterminate', 'indeterminateIcon'])
  }, 'VRadio');
  const VRadio = genericComponent()({
    name: 'VRadio',
    props: makeVRadioProps(),
    setup(props, {
      slots
    }) {
      useRender(() => {
        const controlProps = VSelectionControl.filterProps(props);
        return vue.createVNode(VSelectionControl, vue.mergeProps(controlProps, {
          "class": ['v-radio', props.class],
          "style": props.style,
          "type": "radio"
        }), slots);
      });
      return {};
    }
  });

  // Types

  const makeVRadioGroupProps = propsFactory({
    height: {
      type: [Number, String],
      default: 'auto'
    },
    ...omit(makeVInputProps(), ['direction', 'glow']),
    ...omit(makeSelectionControlGroupProps(), ['multiple']),
    trueIcon: {
      type: IconValue,
      default: '$radioOn'
    },
    falseIcon: {
      type: IconValue,
      default: '$radioOff'
    },
    type: {
      type: String,
      default: 'radio'
    }
  }, 'VRadioGroup');
  const VRadioGroup = genericComponent()({
    name: 'VRadioGroup',
    inheritAttrs: false,
    props: makeVRadioGroupProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      attrs,
      slots
    }) {
      const uid = vue.useId();
      const id = vue.computed(() => props.id || `radio-group-${uid}`);
      const model = useProxiedModel(props, 'modelValue');
      const inputRef = vue.ref();
      useRender(() => {
        const [rootAttrs, controlAttrs] = filterInputAttrs(attrs);
        const inputProps = VInput.filterProps(props);
        const controlProps = VSelectionControl.filterProps(props);
        const label = slots.label ? slots.label({
          label: props.label,
          props: {
            for: id.value
          }
        }) : props.label;
        return vue.createVNode(VInput, vue.mergeProps({
          "ref": inputRef,
          "class": ['v-radio-group', props.class],
          "style": props.style
        }, rootAttrs, inputProps, {
          "modelValue": model.value,
          "onUpdate:modelValue": $event => model.value = $event,
          "id": id.value
        }), {
          ...slots,
          default: ({
            id,
            messagesId,
            isDisabled,
            isReadonly
          }) => vue.createElementVNode(vue.Fragment, null, [label && vue.createVNode(VLabel, {
            "id": id.value
          }, {
            default: () => [label]
          }), vue.createVNode(VSelectionControlGroup, vue.mergeProps(controlProps, {
            "id": id.value,
            "aria-describedby": messagesId.value,
            "defaultsTarget": "VRadio",
            "trueIcon": props.trueIcon,
            "falseIcon": props.falseIcon,
            "type": props.type,
            "disabled": isDisabled.value,
            "readonly": isReadonly.value,
            "aria-labelledby": label ? id.value : undefined,
            "multiple": false
          }, controlAttrs, {
            "modelValue": model.value,
            "onUpdate:modelValue": $event => model.value = $event
          }), slots)])
        });
      });
      return forwardRefs({}, inputRef);
    }
  });

  // Types

  const makeVRangeSliderProps = propsFactory({
    ...makeFocusProps(),
    ...makeVInputProps(),
    ...makeSliderProps(),
    strict: Boolean,
    modelValue: {
      type: Array,
      default: () => [0, 0]
    }
  }, 'VRangeSlider');
  const VRangeSlider = genericComponent()({
    name: 'VRangeSlider',
    inheritAttrs: false,
    props: makeVRangeSliderProps(),
    emits: {
      'update:focused': value => true,
      'update:modelValue': value => true,
      end: value => true,
      start: value => true
    },
    setup(props, {
      slots,
      emit,
      attrs
    }) {
      const startThumbRef = vue.ref();
      const stopThumbRef = vue.ref();
      const inputRef = vue.ref();
      const {
        rtlClasses
      } = useRtl();
      function getActiveThumb(e) {
        if (!startThumbRef.value || !stopThumbRef.value) return;
        const startOffset = getOffset(e, startThumbRef.value.$el, props.direction);
        const stopOffset = getOffset(e, stopThumbRef.value.$el, props.direction);
        const a = Math.abs(startOffset);
        const b = Math.abs(stopOffset);
        return a < b || a === b && startOffset < 0 ? startThumbRef.value.$el : stopThumbRef.value.$el;
      }
      const steps = useSteps(props);
      const model = useProxiedModel(props, 'modelValue', undefined, arr => {
        if (!arr?.length) return [0, 0];
        return arr.map(value => steps.roundValue(value));
      });
      const {
        activeThumbRef,
        hasLabels,
        max,
        min,
        mousePressed,
        onSliderMousedown,
        onSliderTouchstart,
        position,
        trackContainerRef,
        disabled,
        readonly
      } = useSlider({
        props,
        steps,
        onSliderStart: () => {
          if (disabled.value || readonly.value) {
            activeThumbRef.value?.blur();
            return;
          }
          emit('start', model.value);
        },
        onSliderEnd: ({
          value
        }) => {
          if (disabled.value || readonly.value) {
            activeThumbRef.value?.blur();
          } else {
            const newValue = activeThumbRef.value === startThumbRef.value?.$el ? [value, model.value[1]] : [model.value[0], value];
            if (!props.strict && newValue[0] < newValue[1]) {
              model.value = newValue;
            }
          }
          emit('end', model.value);
        },
        onSliderMove: ({
          value
        }) => {
          const [start, stop] = model.value;
          if (disabled.value || readonly.value) {
            activeThumbRef.value?.blur();
            return;
          }
          if (!props.strict && start === stop && start !== min.value) {
            activeThumbRef.value = value > start ? stopThumbRef.value?.$el : startThumbRef.value?.$el;
            activeThumbRef.value?.focus();
          }
          if (activeThumbRef.value === startThumbRef.value?.$el) {
            model.value = [Math.min(value, stop), stop];
          } else {
            model.value = [start, Math.max(start, value)];
          }
        },
        getActiveThumb
      });
      const {
        isFocused,
        focus,
        blur
      } = useFocus(props);
      const trackStart = vue.computed(() => position(model.value[0]));
      const trackStop = vue.computed(() => position(model.value[1]));
      useRender(() => {
        const inputProps = VInput.filterProps(props);
        const [rootAttrs, inputAttrs] = filterInputAttrs(attrs);
        const hasPrepend = !!(props.label || slots.label || slots.prepend);
        return vue.createVNode(VInput, vue.mergeProps({
          "class": ['v-slider', 'v-range-slider', {
            'v-slider--has-labels': !!slots['tick-label'] || hasLabels.value,
            'v-slider--focused': isFocused.value,
            'v-slider--pressed': mousePressed.value,
            'v-slider--disabled': disabled.value
          }, rtlClasses.value, props.class],
          "style": props.style,
          "ref": inputRef
        }, inputProps, rootAttrs, {
          "focused": isFocused.value
        }), {
          ...slots,
          prepend: hasPrepend ? slotProps => vue.createElementVNode(vue.Fragment, null, [slots.label?.(slotProps) ?? (props.label ? vue.createVNode(VLabel, {
            "class": "v-slider__label",
            "text": props.label
          }, null) : undefined), slots.prepend?.(slotProps)]) : undefined,
          default: ({
            id,
            messagesId
          }) => vue.createElementVNode("div", {
            "class": "v-slider__container",
            "onMousedown": !readonly.value ? onSliderMousedown : undefined,
            "onTouchstartPassive": !readonly.value ? onSliderTouchstart : undefined
          }, [vue.createElementVNode("input", {
            "id": `${id.value}_start`,
            "name": props.name || id.value,
            "disabled": disabled.value,
            "readonly": readonly.value,
            "tabindex": "-1",
            "value": model.value[0]
          }, null), vue.createElementVNode("input", {
            "id": `${id.value}_stop`,
            "name": props.name || id.value,
            "disabled": disabled.value,
            "readonly": readonly.value,
            "tabindex": "-1",
            "value": model.value[1]
          }, null), vue.createVNode(VSliderTrack, {
            "ref": trackContainerRef,
            "start": trackStart.value,
            "stop": trackStop.value
          }, {
            'tick-label': slots['tick-label']
          }), vue.createVNode(VSliderThumb, vue.mergeProps({
            "ref": startThumbRef,
            "aria-describedby": messagesId.value,
            "focused": isFocused && activeThumbRef.value === startThumbRef.value?.$el,
            "modelValue": model.value[0],
            "onUpdate:modelValue": v => model.value = [v, model.value[1]],
            "onFocus": e => {
              focus();
              activeThumbRef.value = startThumbRef.value?.$el;

              // Make sure second thumb is focused if
              // the thumbs are on top of each other
              // and they are both at minimum value
              // but only if focused from outside.
              if (max.value !== min.value && model.value[0] === model.value[1] && model.value[1] === min.value && e.relatedTarget !== stopThumbRef.value?.$el) {
                startThumbRef.value?.$el.blur();
                stopThumbRef.value?.$el.focus();
              }
            },
            "onBlur": () => {
              blur();
              activeThumbRef.value = undefined;
            },
            "min": min.value,
            "max": model.value[1],
            "position": trackStart.value,
            "ripple": props.ripple
          }, inputAttrs), {
            'thumb-label': slots['thumb-label']
          }), vue.createVNode(VSliderThumb, vue.mergeProps({
            "ref": stopThumbRef,
            "aria-describedby": messagesId.value,
            "focused": isFocused && activeThumbRef.value === stopThumbRef.value?.$el,
            "modelValue": model.value[1],
            "onUpdate:modelValue": v => model.value = [model.value[0], v],
            "onFocus": e => {
              focus();
              activeThumbRef.value = stopThumbRef.value?.$el;

              // Make sure first thumb is focused if
              // the thumbs are on top of each other
              // and they are both at maximum value
              // but only if focused from outside.
              if (max.value !== min.value && model.value[0] === model.value[1] && model.value[0] === max.value && e.relatedTarget !== startThumbRef.value?.$el) {
                stopThumbRef.value?.$el.blur();
                startThumbRef.value?.$el.focus();
              }
            },
            "onBlur": () => {
              blur();
              activeThumbRef.value = undefined;
            },
            "min": model.value[0],
            "max": max.value,
            "position": trackStop.value,
            "ripple": props.ripple
          }, inputAttrs), {
            'thumb-label': slots['thumb-label']
          })])
        });
      });
      return forwardRefs({
        focus: () => startThumbRef.value?.$el.focus()
      }, inputRef);
    }
  });

  // Types

  const makeVRatingProps = propsFactory({
    name: String,
    itemAriaLabel: {
      type: String,
      default: '$vuetify.rating.ariaLabel.item'
    },
    activeColor: String,
    color: String,
    clearable: Boolean,
    disabled: Boolean,
    emptyIcon: {
      type: IconValue,
      default: '$ratingEmpty'
    },
    fullIcon: {
      type: IconValue,
      default: '$ratingFull'
    },
    halfIncrements: Boolean,
    hover: Boolean,
    length: {
      type: [Number, String],
      default: 5
    },
    readonly: Boolean,
    modelValue: {
      type: [Number, String],
      default: 0
    },
    itemLabels: Array,
    itemLabelPosition: {
      type: String,
      default: 'top',
      validator: v => ['top', 'bottom'].includes(v)
    },
    ripple: Boolean,
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...makeSizeProps(),
    ...makeTagProps(),
    ...makeThemeProps()
  }, 'VRating');
  const VRating = genericComponent()({
    name: 'VRating',
    props: makeVRatingProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const {
        t
      } = useLocale();
      const {
        themeClasses
      } = provideTheme(props);
      const root = vue.ref();
      const rating = useProxiedModel(props, 'modelValue');
      const normalizedValue = vue.computed(() => clamp(parseFloat(rating.value), 0, Number(props.length)));
      const range = vue.computed(() => createRange(Number(props.length), 1));
      const increments = vue.computed(() => range.value.flatMap(v => props.halfIncrements ? [v - 0.5, v] : [v]));
      const hoverIndex = vue.shallowRef(-1);
      const itemState = vue.computed(() => increments.value.map(value => {
        const isHovering = props.hover && hoverIndex.value > -1;
        const isFilled = normalizedValue.value >= value;
        const isHovered = hoverIndex.value >= value;
        const isFullIcon = isHovering ? isHovered : isFilled;
        const icon = isFullIcon ? props.fullIcon : props.emptyIcon;
        const activeColor = props.activeColor ?? props.color;
        const color = isFilled || isHovered ? activeColor : props.color;
        return {
          isFilled,
          isHovered,
          icon,
          color,
          activeColor
        };
      }));
      const eventState = vue.computed(() => [0, ...increments.value].map(value => {
        function onMouseenter() {
          hoverIndex.value = value;
        }
        function onMouseleave() {
          hoverIndex.value = -1;
        }
        function onClick() {
          if (props.disabled || props.readonly) return;
          rating.value = normalizedValue.value === value && props.clearable ? 0 : value;
        }
        return {
          onMouseenter: props.hover ? onMouseenter : undefined,
          onMouseleave: props.hover ? onMouseleave : undefined,
          onClick
        };
      }));
      const currentItemIndex = vue.computed(() => {
        return props.halfIncrements ? 1 + Math.floor(Math.max(0, Number(rating.value ?? 0) - 0.5)) * 2 : Math.floor(Math.max(0, Number(rating.value ?? 0) - 1));
      });
      function moveCurrentFocus() {
        const currentItem = root.value?.querySelector('[tabindex="0"]');
        currentItem?.focus();
      }
      function onItemKeydown(event) {
        if (props.disabled || props.readonly) return;
        if (event.ctrlKey || event.altKey) return;
        const step = props.halfIncrements ? 0.5 : 1;
        if (event.key === 'ArrowRight') {
          const newValue = Math.min(Number(props.length), Number(rating.value ?? 0) + step);
          rating.value = newValue;
          vue.nextTick(() => moveCurrentFocus());
        }
        if (event.key === 'ArrowLeft') {
          const newValue = Math.max(0, Number(rating.value ?? 0) - step);
          rating.value = newValue;
          vue.nextTick(() => moveCurrentFocus());
        }
      }
      const uid = vue.useId();
      const name = vue.computed(() => props.name ?? `v-rating-${uid}`);
      function VRatingItem({
        value,
        index,
        showStar = true
      }) {
        const {
          onMouseenter,
          onMouseleave,
          onClick
        } = eventState.value[index + 1];
        const id = `${name.value}-${String(value).replace('.', '-')}`;
        const isFocusable = index === currentItemIndex.value;
        const btnProps = {
          color: itemState.value[index]?.color,
          density: props.density,
          disabled: props.disabled,
          icon: itemState.value[index]?.icon,
          ripple: props.ripple,
          size: props.size,
          variant: 'plain',
          tabindex: isFocusable ? 0 : -1,
          onKeydown: onItemKeydown
        };
        return vue.createElementVNode(vue.Fragment, null, [vue.createElementVNode("label", {
          "for": id,
          "class": vue.normalizeClass({
            'v-rating__item--half': props.halfIncrements && value % 1 > 0,
            'v-rating__item--full': props.halfIncrements && value % 1 === 0
          }),
          "onMouseenter": onMouseenter,
          "onMouseleave": onMouseleave,
          "onClick": onClick
        }, [vue.createElementVNode("span", {
          "class": "v-rating__hidden"
        }, [t(props.itemAriaLabel, value, props.length)]), !showStar ? undefined : slots.item ? slots.item({
          ...itemState.value[index],
          props: btnProps,
          value,
          index,
          rating: normalizedValue.value
        }) : vue.createVNode(VBtn, vue.mergeProps({
          "aria-label": t(props.itemAriaLabel, value, props.length)
        }, btnProps), null)]), vue.createElementVNode("input", {
          "class": "v-rating__hidden",
          "name": name.value,
          "id": id,
          "type": "radio",
          "value": value,
          "checked": normalizedValue.value === value,
          "tabindex": -1,
          "readonly": props.readonly,
          "disabled": props.disabled
        }, null)]);
      }
      function createLabel(labelProps) {
        if (slots['item-label']) return slots['item-label'](labelProps);
        if (labelProps.label) return vue.createElementVNode("span", null, [labelProps.label]);
        return vue.createElementVNode("span", null, [vue.createTextVNode("\xA0")]);
      }
      useRender(() => {
        const hasLabels = !!props.itemLabels?.length || slots['item-label'];
        return vue.createVNode(props.tag, {
          "class": vue.normalizeClass(['v-rating', {
            'v-rating--hover': props.hover,
            'v-rating--readonly': props.readonly
          }, themeClasses.value, props.class]),
          "style": vue.normalizeStyle(props.style),
          "ref": root
        }, {
          default: () => [vue.createVNode(VRatingItem, {
            "value": 0,
            "index": -1,
            "showStar": false
          }, null), range.value.map((value, i) => vue.createElementVNode("div", {
            "class": "v-rating__wrapper"
          }, [hasLabels && props.itemLabelPosition === 'top' ? createLabel({
            value,
            index: i,
            label: props.itemLabels?.[i]
          }) : undefined, vue.createElementVNode("div", {
            "class": "v-rating__item"
          }, [props.halfIncrements ? vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VRatingItem, {
            "value": value - 0.5,
            "index": i * 2
          }, null), vue.createVNode(VRatingItem, {
            "value": value,
            "index": i * 2 + 1
          }, null)]) : vue.createVNode(VRatingItem, {
            "value": value,
            "index": i
          }, null)]), hasLabels && props.itemLabelPosition === 'bottom' ? createLabel({
            value,
            index: i,
            label: props.itemLabels?.[i]
          }) : undefined]))]
        });
      });
      return {};
    }
  });

  // Types

  const rootTypes = {
    actions: 'button@2',
    article: 'heading, paragraph',
    avatar: 'avatar',
    button: 'button',
    card: 'image, heading',
    'card-avatar': 'image, list-item-avatar',
    chip: 'chip',
    'date-picker': 'list-item, heading, divider, date-picker-options, date-picker-days, actions',
    'date-picker-options': 'text, avatar@2',
    'date-picker-days': 'avatar@28',
    divider: 'divider',
    heading: 'heading',
    image: 'image',
    'list-item': 'text',
    'list-item-avatar': 'avatar, text',
    'list-item-two-line': 'sentences',
    'list-item-avatar-two-line': 'avatar, sentences',
    'list-item-three-line': 'paragraph',
    'list-item-avatar-three-line': 'avatar, paragraph',
    ossein: 'ossein',
    paragraph: 'text@3',
    sentences: 'text@2',
    subtitle: 'text',
    table: 'table-heading, table-thead, table-tbody, table-tfoot',
    'table-heading': 'chip, text',
    'table-thead': 'heading@6',
    'table-tbody': 'table-row-divider@6',
    'table-row-divider': 'table-row, divider',
    'table-row': 'text@6',
    'table-tfoot': 'text@2, avatar@2',
    text: 'text'
  };
  function genBone(type, children = []) {
    return vue.createElementVNode("div", {
      "class": vue.normalizeClass(['v-skeleton-loader__bone', `v-skeleton-loader__${type}`])
    }, [children]);
  }
  function genBones(bone) {
    // e.g. 'text@3'
    const [type, length] = bone.split('@');

    // Generate a length array based upon
    // value after @ in the bone string
    return Array.from({
      length
    }).map(() => genStructure(type));
  }
  function genStructure(type) {
    let children = [];
    if (!type) return children;

    // TODO: figure out a better way to type this
    const bone = rootTypes[type];

    // End of recursion, do nothing
    /* eslint-disable-next-line no-empty, brace-style */
    if (type === bone) ;
    // Array of values - e.g. 'heading, paragraph, text@2'
    else if (type.includes(',')) return mapBones(type);
    // Array of values - e.g. 'paragraph@4'
    else if (type.includes('@')) return genBones(type);
    // Array of values - e.g. 'card@2'
    else if (bone.includes(',')) children = mapBones(bone);
    // Array of values - e.g. 'list-item@2'
    else if (bone.includes('@')) children = genBones(bone);
    // Single value - e.g. 'card-heading'
    else if (bone) children.push(genStructure(bone));
    return [genBone(type, children)];
  }
  function mapBones(bones) {
    // Remove spaces and return array of structures
    return bones.replace(/\s/g, '').split(',').map(genStructure);
  }
  const makeVSkeletonLoaderProps = propsFactory({
    boilerplate: Boolean,
    color: String,
    loading: Boolean,
    loadingText: {
      type: String,
      default: '$vuetify.loading'
    },
    type: {
      type: [String, Array],
      default: 'ossein'
    },
    ...makeDimensionProps(),
    ...makeElevationProps(),
    ...makeThemeProps()
  }, 'VSkeletonLoader');
  const VSkeletonLoader = genericComponent()({
    name: 'VSkeletonLoader',
    inheritAttrs: false,
    props: makeVSkeletonLoaderProps(),
    setup(props, {
      attrs,
      slots
    }) {
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.color);
      const {
        dimensionStyles
      } = useDimension(props);
      const {
        elevationClasses
      } = useElevation(props);
      const {
        themeClasses
      } = provideTheme(props);
      const {
        t
      } = useLocale();
      const items = vue.computed(() => genStructure(wrapInArray(props.type).join(',')));
      useRender(() => {
        const isLoading = !slots.default || props.loading;
        const loadingProps = props.boilerplate || !isLoading ? {} : {
          ariaLive: 'polite',
          ariaLabel: t(props.loadingText),
          role: 'alert'
        };
        return isLoading ? vue.createElementVNode("div", vue.mergeProps({
          "class": ['v-skeleton-loader', {
            'v-skeleton-loader--boilerplate': props.boilerplate
          }, themeClasses.value, backgroundColorClasses.value, elevationClasses.value],
          "style": [backgroundColorStyles.value, dimensionStyles.value]
        }, loadingProps, attrs), [items.value]) : vue.createElementVNode(vue.Fragment, null, [slots.default?.()]);
      });
      return {};
    }
  });

  // Composables

  // Types

  const VSlideGroupItem = genericComponent()({
    name: 'VSlideGroupItem',
    props: makeGroupItemProps(),
    emits: {
      'group:selected': val => true
    },
    setup(props, {
      slots
    }) {
      const slideGroupItem = useGroupItem(props, VSlideGroupSymbol);
      return () => slots.default?.({
        isSelected: slideGroupItem.isSelected.value,
        select: slideGroupItem.select,
        toggle: slideGroupItem.toggle,
        selectedClass: slideGroupItem.selectedClass.value
      });
    }
  });

  // Composables

  // Types

  const VSnackbarQueueSymbol = Symbol.for('vuetify:v-snackbar-queue');
  function useSnackbarQueue(props) {
    const items = vue.ref(new Map());
    const gap = vue.toRef(() => Number(props.gap));
    function register(id) {
      items.value.set(id, {
        height: 0,
        width: 0
      });
    }
    function unregister(id) {
      items.value.delete(id);
    }
    function setSize(id, height, width) {
      const item = items.value.get(id);
      if (!item || item.height === height && item.width === width) return;
      item.height = height;
      item.width = width;
    }
    const lastItemSize = vue.computed(() => {
      for (const {
        width,
        height
      } of [...items.value.values()].toReversed()) {
        if (!width || !height) continue;
        return {
          width,
          height
        };
      }
      return {
        width: 0,
        height: 0
      };
    });
    function getOffset(id) {
      if (!items.value.has(id)) return null;
      let offset = 0;
      for (const [itemId, state] of [...items.value.entries()].toReversed()) {
        if (itemId === id) break;
        offset += state.height + gap.value;
      }
      return offset;
    }
    const state = {
      register,
      unregister,
      setSize,
      getOffset,
      items,
      gap,
      lastItemSize
    };
    vue.provide(VSnackbarQueueSymbol, state);
    return state;
  }
  function useSnackbarItem(isActive, contentEl) {
    const queue = vue.inject(VSnackbarQueueSymbol, null);
    if (!queue) return null;
    const id = vue.useId();
    queue.register(id);
    vue.onBeforeUnmount(() => queue.unregister(id));
    vue.watch(isActive, val => !val && queue.unregister(id), {
      flush: 'sync'
    });
    const {
      resizeRef,
      contentRect
    } = useResizeObserver();
    vue.watch(contentEl, el => {
      resizeRef.value = el ?? null;
    });
    vue.watch(contentRect, rect => {
      if (rect?.width) queue.setSize(id, rect.height, rect.width);
    });
    const offset = vue.computed(() => queue.getOffset(id));
    return {
      id,
      offset
    };
  }

  // Types

  function useCountdown(milliseconds) {
    const time = vue.shallowRef(milliseconds());
    let timer = -1;
    function clear() {
      clearInterval(timer);
    }
    function reset() {
      clear();
      vue.nextTick(() => time.value = milliseconds());
    }
    function start(el) {
      const style = el ? getComputedStyle(el) : {
        transitionDuration: 0.2
      };
      const interval = parseFloat(style.transitionDuration) * 1000 || 200;
      clear();
      if (time.value <= 0) return;
      const startTime = performance.now();
      timer = window.setInterval(() => {
        const elapsed = performance.now() - startTime + interval;
        time.value = Math.max(milliseconds() - elapsed, 0);
        if (time.value <= 0) clear();
      }, interval);
    }
    vue.onScopeDispose(clear);
    return {
      clear,
      time,
      start,
      reset
    };
  }
  const makeVSnackbarProps = propsFactory({
    collapsed: Object,
    loading: Boolean,
    prependAvatar: String,
    prependIcon: IconValue,
    queueGap: Number,
    queueIndex: Number,
    title: String,
    text: String,
    reverseTimer: Boolean,
    timer: {
      type: [Boolean, String],
      default: false
    },
    timerColor: String,
    timeout: {
      type: [Number, String],
      default: 5000
    },
    vertical: Boolean,
    ...makeLocationProps({
      location: 'bottom center'
    }),
    ...makePositionProps(),
    ...makeRoundedProps(),
    ...makeVariantProps(),
    ...makeThemeProps(),
    ...omit(makeVOverlayProps({
      closeOnBack: false,
      locationStrategy: null,
      transition: 'v-snackbar-transition'
    }), ['persistent', 'noClickAnimation', 'offset', 'retainFocus', 'captureFocus', 'disableInitialFocus', 'location', 'scrim', 'scrollStrategy', 'stickToTarget', 'viewportMargin'])
  }, 'VSnackbar');
  const VSnackbar = genericComponent()({
    name: 'VSnackbar',
    props: makeVSnackbarProps(),
    emits: {
      'update:modelValue': v => true
    },
    setup(props, {
      slots
    }) {
      const isActive = useProxiedModel(props, 'modelValue');
      const {
        positionClasses
      } = usePosition(props);
      const {
        scopeId
      } = useScopeId();
      const {
        themeClasses
      } = provideTheme(props);
      const {
        colorClasses,
        colorStyles,
        variantClasses
      } = useVariant(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const countdown = useCountdown(() => Number(props.timeout));
      const overlay = vue.ref();
      const queueItem = useSnackbarItem(isActive, () => overlay.value?.contentEl);
      let _lastOffset;
      const timerRef = vue.ref();
      const isHovering = vue.shallowRef(false);
      const isFocused = vue.shallowRef(false);
      const startY = vue.shallowRef(0);
      const mainStyles = vue.ref();
      const hasLayout = vue.inject(VuetifyLayoutKey, undefined);
      useToggleScope(() => !!hasLayout, () => {
        const layout = useLayout();
        vue.watchEffect(() => {
          mainStyles.value = layout.mainStyles.value;
        });
      });
      vue.watch(isActive, startTimeout);
      vue.watch(() => props.timeout, startTimeout);
      vue.onMounted(() => {
        if (isActive.value) startTimeout();
      });
      let activeTimeout = -1;
      function startTimeout() {
        countdown.clear();
        window.clearTimeout(activeTimeout);
        const timeout = Number(props.timeout);
        if (!isActive.value || timeout === -1) return;
        countdown.reset();
        const element = refElement(timerRef.value);
        vue.nextTick(() => countdown.start(element));
        activeTimeout = window.setTimeout(() => {
          isActive.value = false;
        }, timeout);
      }
      function clearTimeout() {
        countdown.reset();
        window.clearTimeout(activeTimeout);
      }
      function onPointerenter() {
        isHovering.value = true;
        clearTimeout();
      }
      function onPointerleave() {
        isHovering.value = false;
        if (!isFocused.value) startTimeout();
      }
      function onFocusin() {
        isFocused.value = true;
        clearTimeout();
      }
      function onFocusout(event) {
        const contentEl = overlay.value?.contentEl;
        if (contentEl?.contains(event.relatedTarget)) {
          return;
        }
        isFocused.value = false;
        if (!isHovering.value) startTimeout();
      }
      function onTouchstart(event) {
        startY.value = event.touches[0].clientY;
      }
      function onTouchend(event) {
        if (Math.abs(startY.value - event.changedTouches[0].clientY) > 50) {
          isActive.value = false;
        }
      }
      function onAfterLeave() {
        if (isHovering.value) onPointerleave();
        isFocused.value = false;
      }
      const locationClasses = vue.computed(() => {
        return props.location.split(' ').reduce((acc, loc) => {
          acc[`v-snackbar--${loc}`] = true;
          return acc;
        }, {});
      });
      const queueDirection = vue.computed(() => {
        const [side, align] = props.location.split(' ');
        return side === 'bottom' || ['left', 'right'].includes(side) && align === 'end' ? -1 : 1;
      });
      const collapsedStyles = vue.computed(() => {
        if (!props.collapsed) return null;
        return {
          '--v-snackbar-collapsed-height': convertToUnit(props.collapsed.height),
          '--v-snackbar-collapsed-width': convertToUnit(props.collapsed.width)
        };
      });
      const offset = vue.computed(() => {
        if (!queueItem) return undefined;
        if (queueItem.offset.value === null) {
          return _lastOffset;
        }
        return _lastOffset = convertToUnit(queueItem.offset.value);
      });
      const transition = vue.computed(() => {
        if (typeof props.transition !== 'string' || !props.transition.endsWith('-auto')) {
          return props.transition;
        }
        const prefix = props.transition.replace('-auto', '');
        const [side, align] = props.location.split(' ');
        const axis = ['start', 'end', 'left', 'right'].includes(align) || ['left', 'right'].includes(side) ? 'x' : 'y';
        const reverse = ['end', 'right'].includes(align) || !['start', 'left'].includes(align) && ['bottom', 'right'].includes(side) ? '-reverse' : '';
        return `${prefix}-${axis}${reverse}-transition`;
      });
      useRender(() => {
        const overlayProps = VOverlay.filterProps({
          ...props,
          location: props.location,
          locationStrategy: props.locationStrategy ?? noop
        });
        const hasPrependMedia = !!(props.prependAvatar || props.prependIcon);
        const hasPrepend = !!(hasPrependMedia || props.loading || slots.prepend);
        const hasContent = !!(slots.default || slots.text || slots.title || props.text || props.title);
        return vue.createVNode(VOverlay, vue.mergeProps({
          "ref": overlay,
          "class": ['v-snackbar', {
            'v-snackbar--active': isActive.value,
            'v-snackbar--collapsed': !!props.collapsed,
            'v-snackbar--timer': !!props.timer,
            'v-snackbar--vertical': props.vertical
          }, locationClasses.value, positionClasses.value, props.class],
          "style": [mainStyles.value, {
            '--v-snackbar-offset': offset.value,
            '--v-snackbar-gap': convertToUnit(props.queueGap),
            '--v-snackbar-index': props.queueIndex,
            '--v-snackbar-direction': queueDirection.value
          }, collapsedStyles.value, props.style]
        }, overlayProps, {
          "transition": transition.value,
          "modelValue": isActive.value,
          "onUpdate:modelValue": $event => isActive.value = $event,
          "contentProps": vue.mergeProps({
            class: ['v-snackbar__wrapper', themeClasses.value, colorClasses.value, roundedClasses.value, variantClasses.value],
            style: [colorStyles.value, roundedStyles.value],
            onPointerenter,
            onPointerleave,
            onFocusin,
            onFocusout
          }, overlayProps.contentProps),
          "persistent": true,
          "noClickAnimation": true,
          "scrim": false,
          "scrollStrategy": "none",
          "onTouchstartPassive": onTouchstart,
          "onTouchend": onTouchend,
          "onAfterLeave": onAfterLeave
        }, scopeId), {
          default: () => [genOverlays(false, 'v-snackbar'), slots.header && vue.createElementVNode("div", {
            "class": "v-snackbar__header"
          }, [slots.header?.()]), props.timer && Number(props.timeout) > 0 && !isHovering.value && vue.createElementVNode("div", {
            "key": "timer",
            "class": vue.normalizeClass(['v-snackbar__timer', `v-snackbar__timer--${props.timer === 'bottom' ? 'bottom' : 'top'}`])
          }, [vue.createVNode(VProgressLinear, {
            "ref": timerRef,
            "color": props.timerColor ?? 'info',
            "max": props.timeout,
            "modelValue": props.reverseTimer ? Number(props.timeout) - countdown.time.value : countdown.time.value
          }, null)]), hasPrepend && vue.createVNode(VDefaultsProvider, {
            "key": "prepend-defaults",
            "disabled": !hasPrependMedia && !props.loading,
            "defaults": {
              VAvatar: {
                image: props.prependAvatar
              },
              VIcon: {
                icon: props.prependIcon
              },
              VProgressCircular: {
                indeterminate: true,
                size: 24,
                width: 3
              }
            }
          }, {
            default: () => [vue.createElementVNode("div", {
              "class": "v-snackbar__prepend"
            }, [slots.prepend ? slots.prepend() : vue.createElementVNode(vue.Fragment, null, [props.loading && vue.createVNode(VProgressCircular, null, null), !props.loading && props.prependAvatar && vue.createVNode(VAvatar, null, null), !props.loading && props.prependIcon && vue.createVNode(VIcon, null, null)])])]
          }), hasContent && vue.createElementVNode("div", {
            "key": "content",
            "class": "v-snackbar__content",
            "role": "status",
            "aria-live": "polite"
          }, [slots.title?.() ?? (props.title ? vue.createElementVNode("div", {
            "class": "v-snackbar__title",
            "key": "title"
          }, [props.title]) : ''), slots.text?.() ?? props.text, slots.default?.()]), slots.actions && vue.createVNode(VDefaultsProvider, {
            "defaults": {
              VBtn: {
                variant: 'text',
                ripple: false,
                slim: true
              }
            }
          }, {
            default: () => [vue.createElementVNode("div", {
              "class": "v-snackbar__actions"
            }, [slots.actions({
              isActive
            })])]
          })],
          activator: slots.activator
        });
      });
      return forwardRefs({}, overlay);
    }
  });

  // Utilities
  function useDocumentVisibility() {
    const visibility = vue.shallowRef(IN_BROWSER ? document.visibilityState : 'visible');
    if (IN_BROWSER) {
      const onVisibilityChange = () => {
        visibility.value = document.visibilityState;
      };
      document.addEventListener('visibilitychange', onVisibilityChange, {
        passive: true
      });
      vue.onBeforeUnmount(() => {
        document.removeEventListener('visibilitychange', onVisibilityChange);
      });
    }
    return visibility;
  }

  // Types

  const makeVSnackbarQueueProps = propsFactory({
    // TODO: Port this to Snackbar on dev
    closable: [Boolean, String],
    closeText: {
      type: String,
      default: '$vuetify.dismiss'
    },
    collapsed: Boolean,
    displayStrategy: {
      type: String,
      default: 'hold'
    },
    modelValue: {
      type: Array,
      default: () => []
    },
    totalVisible: {
      type: [Number, String],
      default: 1
    },
    gap: {
      type: [Number, String],
      default: 8
    },
    ...omit(makeVSnackbarProps(), ['modelValue', 'collapsed', 'queueIndex', 'queueGap'])
  }, 'VSnackbarQueue');
  const VSnackbarQueue = genericComponent()({
    name: 'VSnackbarQueue',
    inheritAttrs: false,
    props: makeVSnackbarQueueProps(),
    emits: {
      'update:modelValue': val => true
    },
    setup(props, {
      attrs,
      emit,
      slots
    }) {
      const {
        t
      } = useLocale();
      const documentVisibility = useDocumentVisibility();
      const queue = useSnackbarQueue(props);
      const isHovered = vue.shallowRef(false);
      const {
        runOpenDelay,
        runCloseDelay
      } = useDelay({
        openDelay: 0,
        closeDelay: 500
      }, val => {
        isHovered.value = val;
        updateDynamicProps();
      });
      let _lastId = 0;
      const visibleItems = vue.ref([]);
      const limit = vue.toRef(() => Number(props.totalVisible));
      vue.watch(() => props.modelValue.length, showNext);
      function removeItem(id) {
        visibleItems.value = visibleItems.value.filter(x => x.id !== id);
        if (visibleItems.value.length === 0) {
          isHovered.value = false;
        }
        showNext();
      }
      function showNext() {
        if (!props.modelValue.length) return;
        const activeCount = visibleItems.value.filter(x => x.active).length;
        if (activeCount >= limit.value) {
          if (props.displayStrategy !== 'overflow') return;

          // Dismiss oldest active items to make room
          visibleItems.value.filter(x => x.active).slice(limit.value - 1).forEach(item => {
            item.active = false;
            item.onDismiss?.('overflow');
          });
        }
        const [next, ...rest] = props.modelValue;
        emit('update:modelValue', rest);
        const item = typeof next === 'string' ? {
          text: next
        } : next;
        const {
          promise,
          success,
          error,
          onDismiss,
          ...itemProps
        } = item;
        const newItem = {
          id: _lastId++,
          item: {
            ...(promise ? {
              timeout: -1,
              loading: true
            } : {}),
            ...itemProps
          },
          active: true,
          onDismiss
        };
        visibleItems.value.unshift(newItem);
        updateDynamicProps();
        promise?.then(data => {
          if (!newItem.active) return;
          newItem.item = success?.(data) ?? {
            ...newItem.item,
            timeout: 1
          };
          updateDynamicProps();
          vue.triggerRef(visibleItems);
        }, data => {
          if (!newItem.active) return;
          newItem.item = error?.(data) ?? {
            ...newItem.item,
            timeout: 1
          };
          updateDynamicProps();
          vue.triggerRef(visibleItems);
        });
      }
      function dismiss(id, reason) {
        const item = visibleItems.value.find(x => x.id === id);
        if (!item) return;
        item.active = false;
        item.onDismiss?.(reason);
        updateDynamicProps();
      }
      function clear() {
        emit('update:modelValue', []);
        visibleItems.value.toReversed().forEach((item, i) => setTimeout(() => {
          item.active = false;
          item.onDismiss?.('cleared');
        }, 100 * i));
      }
      const btnProps = vue.computed(() => ({
        color: typeof props.closable === 'string' ? props.closable : undefined,
        text: t(props.closeText)
      }));
      function updateDynamicProps() {
        let activeIndex = 0;
        visibleItems.value.forEach(({
          item,
          active
        }) => {
          item.queueIndex = activeIndex;
          if (active) activeIndex++;
        });
        if (!props.collapsed || isHovered.value) {
          visibleItems.value.forEach(({
            item
          }) => item.collapsed = undefined);
          return;
        }
        for (const {
          item
        } of visibleItems.value) {
          item.collapsed = item.queueIndex > 0 ? {
            width: queue.lastItemSize.value.width,
            height: queue.lastItemSize.value.height
          } : undefined;
        }
      }
      vue.watch(queue.lastItemSize, updateDynamicProps);
      vue.watch(() => props.collapsed, updateDynamicProps);
      useRender(() => {
        const hasActions = !!(props.closable || slots.actions);
        const snackbarProps = omit(VSnackbar.filterProps(props), ['modelValue', 'collapsed']);
        const pauseAll = documentVisibility.value === 'hidden' || props.collapsed && isHovered.value;
        return vue.createElementVNode(vue.Fragment, null, [visibleItems.value.map(({
          id,
          item,
          active
        }) => slots.item ? vue.createVNode(VDefaultsProvider, {
          "defaults": {
            VSnackbar: item
          }
        }, {
          default: () => [slots.item({
            item
          })]
        }) : vue.createVNode(VSnackbar, vue.mergeProps({
          "key": id
        }, attrs, snackbarProps, item, pauseAll ? {
          timeout: -1
        } : {}, {
          "queueGap": Number(props.gap),
          "contentProps": vue.mergeProps(snackbarProps.contentProps, {
            onMouseenter: runOpenDelay,
            onMouseleave: () => runCloseDelay()
          }),
          "modelValue": active,
          "onUpdate:modelValue": () => dismiss(id, 'auto'),
          "onAfterLeave": () => removeItem(id)
        }), {
          header: slots.header ? () => slots.header?.({
            item
          }) : undefined,
          text: slots.text ? () => slots.text?.({
            item
          }) : undefined,
          actions: hasActions ? () => vue.createElementVNode(vue.Fragment, null, [!slots.actions ? vue.createVNode(VBtn, vue.mergeProps(btnProps.value, {
            "onClick": () => dismiss(id, 'dismissed')
          }), null) : vue.createVNode(VDefaultsProvider, {
            "defaults": {
              VBtn: btnProps.value
            }
          }, {
            default: () => [slots.actions({
              item,
              props: {
                onClick: () => dismiss(id, 'dismissed')
              }
            })]
          })]) : undefined
        }))]);
      });
      return {
        clear
      };
    }
  });

  // Types

  const makeVTooltipProps = propsFactory({
    id: String,
    interactive: Boolean,
    text: String,
    color: String,
    ...omit(makeVOverlayProps({
      closeOnBack: false,
      location: 'end',
      locationStrategy: 'connected',
      eager: true,
      minWidth: 0,
      offset: 10,
      openOnClick: false,
      openOnHover: true,
      origin: 'auto',
      scrim: false,
      scrollStrategy: 'reposition',
      transition: null
    }), ['absolute', 'retainFocus', 'captureFocus', 'disableInitialFocus'])
  }, 'VTooltip');
  const VTooltip = genericComponent()({
    name: 'VTooltip',
    props: makeVTooltipProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const isActive = useProxiedModel(props, 'modelValue');
      const {
        scopeId
      } = useScopeId();
      const {
        colorClasses,
        colorStyles
      } = useColor(() => ({
        background: props.color
      }));
      const uid = vue.useId();
      const id = vue.toRef(() => props.id || `v-tooltip-${uid}`);
      const overlay = vue.ref();
      const location = vue.computed(() => {
        return props.location.split(' ').length > 1 ? props.location : props.location + ' center';
      });
      const origin = vue.computed(() => {
        return props.origin === 'auto' || props.origin === 'overlap' || props.origin.split(' ').length > 1 || props.location.split(' ').length > 1 ? props.origin : props.origin + ' center';
      });
      const transition = vue.toRef(() => {
        if (props.transition != null) return props.transition;
        return isActive.value ? 'scale-transition' : 'fade-transition';
      });
      const activatorProps = vue.computed(() => vue.mergeProps({
        'aria-describedby': id.value
      }, props.activatorProps));
      useRender(() => {
        const overlayProps = VOverlay.filterProps(props);
        return vue.createVNode(VOverlay, vue.mergeProps({
          "ref": overlay,
          "class": ['v-tooltip', {
            'v-tooltip--interactive': props.interactive
          }, props.class],
          "style": [props.style],
          "id": id.value
        }, overlayProps, {
          "contentClass": [colorClasses.value, props.contentClass],
          "contentProps": vue.mergeProps({
            style: [colorStyles.value]
          }, props.contentProps),
          "modelValue": isActive.value,
          "onUpdate:modelValue": $event => isActive.value = $event,
          "transition": transition.value,
          "absolute": true,
          "location": location.value,
          "origin": origin.value,
          "role": "tooltip",
          "activatorProps": activatorProps.value,
          "_disableGlobalStack": true
        }, scopeId), {
          activator: slots.activator,
          default: (...args) => slots.default?.(...args) ?? props.text
        });
      });
      return forwardRefs({}, overlay);
    }
  });

  // Types

  const makeVSparklineTooltipProps = propsFactory({
    modelValue: Boolean,
    target: Object,
    index: {
      type: Number,
      default: null
    },
    value: {
      type: Number,
      default: 0
    },
    titleFormat: {
      type: Function,
      default: item => String(item.value)
    },
    offset: Number,
    contentClass: null,
    location: String
  }, 'VSparklineTooltip');
  const VSparklineTooltip = genericComponent()({
    name: 'VSparklineTooltip',
    props: makeVSparklineTooltipProps(),
    emits: {
      afterLeave: () => true
    },
    setup(props, {
      slots,
      emit
    }) {
      return () => vue.createVNode(VTooltip, {
        "modelValue": props.modelValue,
        "target": props.target,
        "offset": props.offset,
        "contentClass": props.contentClass,
        "location": props.location,
        "onAfterLeave": () => emit('afterLeave')
      }, {
        default: () => [props.index !== null && (slots.default?.({
          index: props.index,
          value: props.value
        }) ?? props.titleFormat({
          index: props.index,
          value: props.value
        }))]
      });
    }
  });

  // Types

  /**
   * Monotone cubic Hermite interpolation (Fritsch-Carlson) converted to cubic Bezier.
   * Prevents overshoot at local extrema (e.g. consecutive equal min/max values)
   * by zeroing tangents at turning points and applying an alpha-beta constraint.
   *
   * `smooth` controls tension: 0 = straight lines, 8 (default true) = full curve.
   */
  function genMonotonePath(points, smooth, fill = false, height = 75) {
    if (points.length === 0) return '';
    const start = points[0];
    const end = points[points.length - 1];
    const prefix = fill ? `M${start.x} ${height - start.x + 2} L${start.x} ${start.y}` : `M${start.x} ${start.y}`;
    const suffix = fill ? `L${end.x} ${height - start.x + 2} Z` : '';
    if (smooth === 0 || points.length < 3) {
      return prefix + points.slice(1).map(point => `L${point.x} ${point.y}`).join('') + suffix;
    }
    const tension = Math.min(smooth / 8, 1);
    const n = points.length;
    const delta = [];
    for (let i = 0; i < n - 1; i++) {
      const dx = points[i + 1].x - points[i].x;
      delta[i] = dx === 0 ? 0 : (points[i + 1].y - points[i].y) / dx;
    }
    const tangent = new Array(n);
    tangent[0] = delta[0];
    tangent[n - 1] = delta[n - 2];
    for (let i = 1; i < n - 1; i++) {
      if (delta[i - 1] === 0 || delta[i] === 0 || delta[i - 1] > 0 !== delta[i] > 0) {
        tangent[i] = 0;
      } else {
        tangent[i] = (delta[i - 1] + delta[i]) / 2;
      }
    }
    for (let i = 0; i < n - 1; i++) {
      if (delta[i] === 0) {
        tangent[i] = 0;
        tangent[i + 1] = 0;
      } else {
        const alpha = tangent[i] / delta[i];
        const beta = tangent[i + 1] / delta[i];
        const squaredSum = alpha * alpha + beta * beta;
        if (squaredSum > 9) {
          const tau = 3 / Math.sqrt(squaredSum);
          tangent[i] = tau * alpha * delta[i];
          tangent[i + 1] = tau * beta * delta[i];
        }
      }
    }
    const curves = points.slice(1).map((curr, index) => {
      const prev = points[index];
      const dx = curr.x - prev.x;
      const controlPoint1X = prev.x + dx * tension / 3;
      const controlPoint1Y = prev.y + tangent[index] * dx * tension / 3;
      const controlPoint2X = curr.x - dx * tension / 3;
      const controlPoint2Y = curr.y - tangent[index + 1] * dx * tension / 3;
      return `C${controlPoint1X} ${controlPoint1Y} ${controlPoint2X} ${controlPoint2Y} ${curr.x} ${curr.y}`;
    });
    return prefix + curves.join('') + suffix;
  }

  // @ts-nocheck
  /* eslint-disable */

  // import { checkCollinear, getDistance, moveTo } from './math'

  /**
   * From https://github.com/unsplash/react-trend/blob/master/src/helpers/DOM.helpers.js#L18
   */
  function genRoundedPath(points, radius, fill = false, height = 75, consistentStructure = false) {
    if (points.length === 0) return '';
    const start = points.shift();
    const end = points[points.length - 1];
    return (fill ? `M${start.x} ${height - start.x + 2} L${start.x} ${start.y}` : `M${start.x} ${start.y}`) + points.map((point, index) => {
      const next = points[index + 1];
      const prev = points[index - 1] || start;
      const isCollinear = next && checkCollinear(next, point, prev);
      if (!next) {
        return consistentStructure ? `L${point.x} ${point.y}S${point.x} ${point.y} ${point.x} ${point.y}` : `L${point.x} ${point.y}`;
      }
      if (isCollinear && !consistentStructure) {
        return `L${point.x} ${point.y}`;
      }
      const threshold = Math.min(getDistance(prev, point), getDistance(next, point));
      const isTooCloseForRadius = threshold / 2 < radius;
      const radiusForPoint = isTooCloseForRadius ? threshold / 2 : radius;
      const before = moveTo(prev, point, radiusForPoint);
      const after = moveTo(next, point, radiusForPoint);
      return `L${before.x} ${before.y}S${point.x} ${point.y} ${after.x} ${after.y}`;
    }).join('') + (fill ? `L${end.x} ${height - start.x + 2} Z` : '');
  }
  function int(value) {
    return parseInt(value, 10);
  }

  /**
   * https://en.wikipedia.org/wiki/Collinearity
   * x=(x1+x2)/2
   * y=(y1+y2)/2
   */
  function checkCollinear(p0, p1, p2) {
    return int(p0.x + p2.x) === int(2 * p1.x) && int(p0.y + p2.y) === int(2 * p1.y);
  }
  function getDistance(p1, p2) {
    return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
  }
  function moveTo(to, from, radius) {
    const vector = {
      x: to.x - from.x,
      y: to.y - from.y
    };
    const length = Math.sqrt(vector.x * vector.x + vector.y * vector.y);
    const unitVector = {
      x: vector.x / length,
      y: vector.y / length
    };
    return {
      x: from.x + unitVector.x * radius,
      y: from.y + unitVector.y * radius
    };
  }

  // Utilities

  // Types

  const makeLineProps = propsFactory({
    animation: {
      type: [Boolean, Object],
      default: false
    },
    autoDraw: {
      type: [Boolean, String],
      default: false
    },
    autoDrawDuration: [Number, String],
    autoDrawEasing: {
      type: String,
      default: 'ease'
    },
    color: String,
    gradient: {
      type: Array,
      default: () => []
    },
    gradientDirection: {
      type: String,
      validator: val => ['top', 'bottom', 'left', 'right'].includes(val),
      default: 'top'
    },
    height: {
      type: [String, Number],
      default: 75
    },
    labels: {
      type: Array,
      default: () => []
    },
    labelSize: {
      type: [Number, String],
      default: 7
    },
    lineWidth: {
      type: [String, Number],
      default: 4
    },
    id: String,
    itemValue: {
      type: String,
      default: 'value'
    },
    modelValue: {
      type: Array,
      default: () => []
    },
    min: [String, Number],
    max: [String, Number],
    padding: {
      type: [String, Number],
      default: 8
    },
    markerSize: {
      type: [Number, String],
      default: 8
    },
    markerStroke: {
      type: String,
      default: '#fff'
    },
    inset: Boolean,
    showLabels: Boolean,
    showMarkers: Boolean,
    smooth: [Boolean, String, Number],
    smoothMode: {
      type: String,
      default: 'default'
    },
    interactive: Boolean,
    tooltip: {
      type: [Boolean, Object],
      default: false
    },
    width: {
      type: [Number, String],
      default: 300
    }
  }, 'Line');
  function resample(values, targetCount) {
    const length = values.length;
    if (length === 0) return Array(targetCount).fill(0);
    if (length === 1) return Array(targetCount).fill(values[0]);
    const result = [];
    for (let i = 0; i < targetCount; i++) {
      const t = i / (targetCount - 1) * (length - 1);
      const low = Math.floor(t);
      const high = Math.min(low + 1, length - 1);
      const fraction = t - low;
      result.push(values[low] + (values[high] - values[low]) * fraction);
    }
    return result;
  }
  function extendPoints(points, inset, totalWidth) {
    if (!inset || points.length < 2) return points;
    const first = points[0];
    const second = points[1];
    const last = points[points.length - 1];
    const secondLast = points[points.length - 2];
    const slopeStart = (second.y - first.y) / (second.x - first.x);
    const slopeEnd = (last.y - secondLast.y) / (last.x - secondLast.x);
    const ghostStart = {
      x: 0,
      y: first.y - first.x * slopeStart,
      value: first.value
    };
    const ghostEnd = {
      x: totalWidth,
      y: last.y + (totalWidth - last.x) * slopeEnd,
      value: last.value
    };
    return [ghostStart, ...points, ghostEnd];
  }
  function buildPath(points, options) {
    const smoothValue = typeof options.smooth === 'boolean' ? options.smooth ? 8 : 0 : Number(options.smooth ?? 0);

    // genRoundedPath mutates via shift(); slice defensively so callers don't have to
    const copy = points.slice();
    if (options.smoothMode === 'monotone') {
      return genMonotonePath(copy, smoothValue, options.fill, options.height);
    }
    return genRoundedPath(copy, smoothValue, options.fill, options.height, options.animation);
  }

  // Types

  const makeVBarlineProps = propsFactory({
    autoLineWidth: Boolean,
    ...makeLineProps()
  }, 'VBarline');
  const VBarline = genericComponent()({
    name: 'VBarline',
    inheritAttrs: false,
    props: makeVBarlineProps(),
    emits: {
      'update:currentIndex': _index => true
    },
    setup(props, {
      slots,
      attrs,
      emit
    }) {
      const uid = vue.useId();
      const id = vue.computed(() => props.id || `barline-${uid}`);
      const autoDrawDuration = vue.computed(() => Number(props.autoDrawDuration) || 500);
      const hasDrawn = vue.ref(false);
      const clipRects = vue.shallowRef([]);
      const animationDuration = vue.computed(() => typeof props.animation === 'object' ? props.animation.duration ?? 300 : 300);
      const animationEasing = vue.computed(() => typeof props.animation === 'object' ? props.animation.easing ?? 'ease' : 'ease');
      const hasLabels = vue.computed(() => {
        return Boolean(props.showLabels || props.labels.length > 0 || !!slots?.label);
      });
      const lineWidth = vue.computed(() => parseFloat(props.lineWidth) || 4);
      const items = vue.computed(() => props.modelValue.map(item => getPropertyFromItem(item, props.itemValue, item)));
      const totalWidth = vue.computed(() => Math.max(items.value.length * lineWidth.value, Number(props.width)));
      const boundary = vue.computed(() => {
        return {
          minX: 0,
          maxX: totalWidth.value,
          minY: 0,
          maxY: parseInt(props.height, 10)
        };
      });
      function genBars(values, boundary) {
        const {
          minX,
          maxX,
          minY,
          maxY
        } = boundary;
        const totalValues = values.length;
        let maxValue = props.max != null ? Number(props.max) : Math.max(...values);
        let minValue = props.min != null ? Number(props.min) : Math.min(...values);
        if (minValue > 0 && props.min == null) minValue = 0;
        if (maxValue < 0 && props.max == null) maxValue = 0;
        const gridX = maxX / (totalValues === 1 ? 2 : totalValues);
        const gridY = (maxY - minY) / (maxValue - minValue || 1);
        const horizonY = maxY - Math.abs(minValue * gridY);
        return values.map((value, index) => {
          const height = Math.abs(gridY * value);
          return {
            x: minX + index * gridX,
            y: horizonY - height + Number(value < 0) * height,
            height,
            value
          };
        });
      }
      const bars = vue.computed(() => genBars(items.value, boundary.value));
      const prevBarCount = vue.ref(0);
      function applyTransition(el, duration, easing) {
        el.style.transition = `y ${duration}ms ${easing}, height ${duration}ms ${easing}`;
      }
      function collapseNewBars(bars, fromIndex, duration, easing) {
        for (let i = fromIndex; i < bars.length; i++) {
          const el = clipRects.value[i];
          if (!el) continue;

          // Snap to collapsed at bar's baseline
          el.style.transition = 'none';
          el.setAttribute('y', String(bars[i].y + bars[i].height));
          el.setAttribute('height', '0');
          el.getBoundingClientRect();

          // Animate to final state
          applyTransition(el, duration, easing);
          el.setAttribute('y', String(bars[i].y));
          el.setAttribute('height', String(bars[i].height));
        }
      }
      function applyBarsTransition(oldCount) {
        if (!props.animation) return;
        clipRects.value.forEach(el => {
          if (el) applyTransition(el, animationDuration.value, animationEasing.value);
        });
        if (bars.value.length > oldCount && oldCount > 0) {
          collapseNewBars(bars.value, oldCount, animationDuration.value, animationEasing.value);
        }
      }
      vue.watch(() => props.modelValue, async () => {
        await vue.nextTick();
        if (PREFERS_REDUCED_MOTION() || !clipRects.value.length) return;
        const oldCount = prevBarCount.value;
        prevBarCount.value = bars.value.length;

        // Animation-only mode (no auto-draw), or draw-once after first draw: just ensure transition is set
        if (!props.autoDraw || props.autoDraw === 'once' && hasDrawn.value) {
          applyBarsTransition(oldCount);
          return;
        }
        hasDrawn.value = true;
        const shouldDrawOnce = props.autoDraw === 'once';
        clipRects.value.forEach((el, i) => {
          const bar = bars.value[i];
          if (!el || !bar) return;

          // Snap to collapsed state
          el.style.transition = 'none';
          el.setAttribute('y', String(bar.y + bar.height));
          el.setAttribute('height', '0');
          el.getBoundingClientRect();

          // Animate to final state
          applyTransition(el, autoDrawDuration.value, props.autoDrawEasing);
          el.setAttribute('y', String(bar.y));
          el.setAttribute('height', String(bar.height));

          // After initial draw, switch to animation timing for subsequent changes
          if (shouldDrawOnce && props.animation) {
            el.addEventListener('transitionend', () => {
              applyTransition(el, animationDuration.value, animationEasing.value);
            }, {
              once: true
            });
          }
        });
      }, {
        immediate: true
      });
      const parsedLabels = vue.computed(() => {
        return bars.value.map((bar, i) => ({
          x: bar.x,
          value: String(props.labels[i] ?? bar.value)
        }));
      });
      const offsetX = vue.computed(() => bars.value.length === 1 ? (boundary.value.maxX - lineWidth.value) / 2 : (Math.abs(bars.value[0].x - bars.value[1].x) - lineWidth.value) / 2);
      const smooth = vue.computed(() => typeof props.smooth === 'boolean' ? props.smooth ? 2 : 0 : Number(props.smooth));
      const columnWidth = vue.computed(() => {
        const len = bars.value.length;
        return totalWidth.value / (len === 1 ? 2 : len);
      });

      // Hover / tooltip state
      const svgRef = vue.shallowRef(null);
      const currentIndex = vue.shallowRef(null);
      const tooltipVisible = vue.shallowRef(false);
      const targetX = vue.shallowRef(0);
      const targetY = vue.shallowRef(0);
      const targetHeight = vue.shallowRef(0);
      vue.watch(currentIndex, index => {
        if (index === null) return;
        const bar = bars.value[index];
        if (!bar) return;
        targetX.value = bar.x + offsetX.value;
        targetY.value = bar.y;
        targetHeight.value = bar.height;
      });
      const transitionOptions = {
        duration: 150,
        transition: easingPatterns.easeOutQuad
      };
      const animatedX = useTransition(targetX, transitionOptions);
      const animatedY = useTransition(targetY, transitionOptions);
      const tooltipTarget = vue.computed(() => {
        if (currentIndex.value === null || !svgRef.value) return undefined;
        const ctm = svgRef.value.getScreenCTM();
        if (!ctm) return undefined;
        const svgPoint = svgRef.value.createSVGPoint();
        svgPoint.x = animatedX.value + lineWidth.value / 2;
        svgPoint.y = animatedY.value;
        const {
          x,
          y
        } = svgPoint.matrixTransform(ctm);
        return [x, y];
      });
      const tooltipConfig = vue.computed(() => ({
        showCrosshair: false,
        titleFormat: item => String(item.value),
        ...(typeof props.tooltip === 'object' ? props.tooltip : {})
      }));
      let frame = -1;
      function onSvgMousemove(e) {
        const target = e.currentTarget;
        cancelAnimationFrame(frame);
        frame = requestAnimationFrame(() => {
          const rect = target.getBoundingClientRect();
          const svgX = (e.clientX - rect.left) / rect.width * totalWidth.value;
          let nearest = 0;
          let minDist = Infinity;
          bars.value.forEach((bar, i) => {
            const barCenter = bar.x + offsetX.value + lineWidth.value / 2;
            const dist = Math.abs(barCenter - svgX);
            if (dist < minDist) {
              minDist = dist;
              nearest = i;
            }
          });
          currentIndex.value = nearest;
          emit('update:currentIndex', nearest);
          tooltipVisible.value = true;
        });
      }
      function onSvgMouseleave() {
        cancelAnimationFrame(frame);
        tooltipVisible.value = false;
        if (!props.tooltip) {
          currentIndex.value = null;
          emit('update:currentIndex', null);
        }
      }
      function onTooltipAfterLeave() {
        currentIndex.value = null;
        emit('update:currentIndex', null);
      }
      function setIndex(index) {
        currentIndex.value = index;
        emit('update:currentIndex', index);
        tooltipVisible.value = index !== null;
      }
      function onSvgFocus() {
        if (!bars.value.length) return;
        setIndex(bars.value.length - 1);
      }
      function onSvgBlur() {
        tooltipVisible.value = false;
        if (!props.tooltip) {
          setIndex(null);
        }
      }
      function onSvgKeydown(e) {
        if (!bars.value.length) return;
        const len = bars.value.length;
        if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
          e.preventDefault();
          const direction = e.key === 'ArrowLeft' ? -1 : 1;
          const current = currentIndex.value ?? (direction === 1 ? -1 : len);
          const next = Math.max(0, Math.min(len - 1, current + direction));
          setIndex(next);
        }
      }
      useRender(() => {
        const gradientData = !props.gradient.slice().length ? [''] : props.gradient.slice().reverse();
        return vue.createElementVNode(vue.Fragment, null, [vue.createElementVNode("svg", vue.mergeProps({
          "ref": svgRef,
          "display": "block",
          "tabindex": props.interactive ? 0 : undefined,
          "onMousemove": props.interactive ? onSvgMousemove : undefined,
          "onMouseleave": props.interactive ? onSvgMouseleave : undefined,
          "onFocus": props.interactive ? onSvgFocus : undefined,
          "onBlur": props.interactive ? onSvgBlur : undefined,
          "onKeydown": props.interactive ? onSvgKeydown : undefined
        }, attrs), [vue.createElementVNode("defs", null, [vue.createElementVNode("linearGradient", {
          "id": id.value,
          "gradientUnits": "userSpaceOnUse",
          "x1": props.gradientDirection === 'left' ? '100%' : '0',
          "y1": props.gradientDirection === 'top' ? '100%' : '0',
          "x2": props.gradientDirection === 'right' ? '100%' : '0',
          "y2": props.gradientDirection === 'bottom' ? '100%' : '0'
        }, [gradientData.map((color, index) => vue.createElementVNode("stop", {
          "offset": index / Math.max(gradientData.length - 1, 1),
          "stop-color": color || 'currentColor'
        }, null))])]), vue.createElementVNode("clipPath", {
          "id": `${id.value}-clip`
        }, [bars.value.map((item, i) => vue.createElementVNode("rect", {
          "ref": el => {
            if (el) clipRects.value[i] = el;
          },
          "x": item.x + offsetX.value,
          "y": item.y,
          "width": lineWidth.value,
          "height": item.height,
          "rx": smooth.value,
          "ry": smooth.value
        }, null))]), hasLabels.value && vue.createElementVNode("g", {
          "key": "labels",
          "style": {
            textAnchor: 'middle',
            dominantBaseline: 'mathematical',
            fill: 'currentColor'
          }
        }, [parsedLabels.value.map((item, i) => vue.createElementVNode("text", {
          "x": item.x + offsetX.value + lineWidth.value / 2,
          "y": parseInt(props.height, 10) - 2 + (parseInt(props.labelSize, 10) || 7 * 0.75),
          "font-size": Number(props.labelSize) || 7
        }, [slots.label?.({
          index: i,
          value: item.value
        }) ?? item.value]))]), props.interactive && currentIndex.value !== null && vue.createElementVNode("rect", {
          "key": "highlight",
          "x": animatedX.value - offsetX.value,
          "y": 0,
          "width": columnWidth.value,
          "height": props.height,
          "fill": "currentColor",
          "opacity": 0.1,
          "pointer-events": "none"
        }, null), vue.createElementVNode("g", {
          "clip-path": `url(#${id.value}-clip)`,
          "fill": `url(#${id.value})`
        }, [vue.createElementVNode("rect", {
          "x": 0,
          "y": 0,
          "width": totalWidth.value,
          "height": props.height
        }, null)])]), !!props.tooltip && vue.createVNode(VSparklineTooltip, {
          "key": "tooltip",
          "modelValue": tooltipVisible.value,
          "target": tooltipTarget.value,
          "index": currentIndex.value,
          "value": currentIndex.value !== null ? bars.value[currentIndex.value].value : 0,
          "offset": tooltipConfig.value.offset,
          "contentClass": tooltipConfig.value.class,
          "titleFormat": tooltipConfig.value.titleFormat,
          "location": "top center",
          "onAfterLeave": onTooltipAfterLeave
        }, {
          default: slots.tooltip
        })]);
      });
    }
  });

  // Types

  const makeVTrendlineProps = propsFactory({
    fill: Boolean,
    ...makeLineProps()
  }, 'VTrendline');
  const VTrendline = genericComponent()({
    name: 'VTrendline',
    inheritAttrs: false,
    props: makeVTrendlineProps(),
    emits: {
      'update:currentIndex': _index => true
    },
    setup(props, {
      slots,
      attrs,
      emit
    }) {
      const uid = vue.useId();
      const id = vue.computed(() => props.id || `trendline-${uid}`);
      const autoDrawDuration = vue.computed(() => Number(props.autoDrawDuration) || (props.fill ? 500 : 2000));
      const hasDrawn = vue.ref(false);
      const fillPath = vue.ref(null);
      const strokePath = vue.ref(null);
      const animationDuration = vue.computed(() => typeof props.animation === 'object' ? props.animation.duration ?? 300 : 300);
      const animationEasing = vue.computed(() => typeof props.animation === 'object' ? props.animation.easing ?? 'ease' : 'ease');
      function genPoints(values, boundary) {
        const {
          minX,
          maxX,
          minY,
          maxY
        } = boundary;
        if (values.length === 1) {
          values = [values[0], values[0]];
        }
        const totalValues = values.length;
        const maxValue = props.max != null ? Number(props.max) : Math.max(...values);
        const minValue = props.min != null ? Number(props.min) : Math.min(...values);
        const gridX = (maxX - minX) / (totalValues - 1);
        const gridY = (maxY - minY) / (maxValue - minValue || 1);
        return values.map((value, index) => ({
          x: minX + index * gridX,
          y: maxY - (value - minValue) * gridY,
          value
        }));
      }
      const hasLabels = vue.computed(() => {
        return Boolean(props.showLabels || props.labels.length > 0 || !!slots?.label);
      });
      const totalWidth = vue.computed(() => Number(props.width));
      const boundary = vue.computed(() => {
        const padding = Number(props.padding);
        return {
          minX: padding,
          maxX: totalWidth.value - padding,
          minY: padding,
          maxY: parseInt(props.height, 10) - padding
        };
      });
      const items = vue.computed(() => props.modelValue.map(item => getPropertyFromItem(item, props.itemValue, item)));

      // When animation is enabled, resample to a consistent point count
      // so the SVG path always has the same number of commands for CSS d transitions
      const sampleCount = vue.ref(0);

      // When sampleCount grows (new dataset is longer than any seen before),
      // manually patch the DOM path to old-data-at-new-count before Vue re-renders,
      // so the browser sees same-structure paths and can CSS-transition between them.
      vue.watch(items, (newVal, oldVal) => {
        if (!props.animation) return;
        const prevCount = sampleCount.value;
        if (newVal.length > prevCount) {
          sampleCount.value = newVal.length;
          if (prevCount > 0 && oldVal) {
            const oldResampled = resample(oldVal, sampleCount.value);
            for (const [pathRef, fill] of [[strokePath, false], [fillPath, true]]) {
              const path = pathRef.value;
              if (!path) continue;
              path.setAttribute('d', genPath(oldResampled, fill));
            }
          }
        }
      }, {
        immediate: true
      });
      const normalizedItems = vue.computed(() => {
        if (!props.animation || !sampleCount.value || items.value.length === sampleCount.value) {
          return items.value;
        }
        return resample(items.value, sampleCount.value);
      });
      const points = vue.computed(() => genPoints(normalizedItems.value, boundary.value));
      const extendedPoints = vue.computed(() => extendPoints(points.value, props.inset, totalWidth.value));
      function genPath(input, fill) {
        const points = typeof input[0] === 'number' ? extendPoints(genPoints(input, boundary.value), props.inset, totalWidth.value) : input;
        return buildPath(points, {
          smooth: props.smooth,
          smoothMode: props.smoothMode,
          height: parseInt(props.height, 10),
          fill,
          animation: !!props.animation
        });
      }
      const parsedLabels = vue.computed(() => {
        const labels = [];
        const len = points.value.length;
        for (let i = 0; labels.length < len; i++) {
          const point = points.value[i];
          let value = props.labels[i];
          if (!value) {
            value = point.value;
          }
          labels.push({
            x: point.x,
            value: String(value)
          });
        }
        return labels;
      });
      function applyDTransition(path, duration, easing) {
        path.style.transition = `d ${duration}ms ${easing}`;
      }
      vue.watch(() => props.modelValue, async () => {
        await vue.nextTick();
        if (PREFERS_REDUCED_MOTION()) return;

        // Animation-only mode (no auto-draw): just ensure d transition is set
        if (!props.autoDraw) {
          if (props.animation && strokePath.value) {
            for (const path of [fillPath.value, strokePath.value]) {
              if (path) applyDTransition(path, animationDuration.value, animationEasing.value);
            }
          }
          return;
        }
        if (!strokePath.value) return;
        if (props.autoDraw === 'once' && hasDrawn.value) return;
        hasDrawn.value = true;
        const shouldDrawOnce = props.autoDraw === 'once';
        if (!props.fill) {
          const path = strokePath.value;
          const length = path.getTotalLength();
          path.style.transition = 'none';
          path.style.strokeDasharray = `${length}`;
          path.style.strokeDashoffset = `${length}`;
          path.getBoundingClientRect();
          const dTransition = props.animation ? `, d ${animationDuration.value}ms ${animationEasing.value}` : '';
          path.style.transition = `stroke-dashoffset ${autoDrawDuration.value}ms ${props.autoDrawEasing}${dTransition}`;
          path.style.strokeDashoffset = '0';
          if (shouldDrawOnce) {
            path.addEventListener('transitionend', e => {
              if (e.propertyName !== 'stroke-dashoffset') return;
              path.style.strokeDasharray = '';
              path.style.strokeDashoffset = '';
              if (props.animation) {
                applyDTransition(path, animationDuration.value, animationEasing.value);
              } else {
                path.style.transition = '';
              }
            }, {
              once: true
            });
          }
        } else {
          for (const path of [fillPath.value, strokePath.value]) {
            if (!path) continue;
            path.style.transformOrigin = 'bottom center';
            path.style.transition = 'none';
            path.style.transform = `scaleY(0)`;
            path.getBoundingClientRect();
            const dTransition = props.animation ? `, d ${animationDuration.value}ms ${animationEasing.value}` : '';
            path.style.transition = `transform ${autoDrawDuration.value}ms ${props.autoDrawEasing}${dTransition}`;
            path.style.transform = `scaleY(1)`;
            if (shouldDrawOnce) {
              path.addEventListener('transitionend', e => {
                if (e.propertyName !== 'transform') return;
                path.style.transform = '';
                path.style.transformOrigin = '';
                if (props.animation) {
                  applyDTransition(path, animationDuration.value, animationEasing.value);
                } else {
                  path.style.transition = '';
                }
              }, {
                once: true
              });
            }
          }
        }
      }, {
        immediate: true
      });

      // Hover / tooltip state
      const svgRef = vue.shallowRef(null);
      const currentIndex = vue.shallowRef(null);
      const tooltipVisible = vue.shallowRef(false);
      const currentPoint = vue.computed(() => currentIndex.value !== null ? points.value[currentIndex.value] : null);
      function getPathLengthAtX(svgPath, targetX) {
        const total = svgPath.getTotalLength();
        let low = 0;
        let high = total;
        // 32 bisections ≈ sub-pixel accuracy on any reasonable chart width
        for (let i = 0; i < 32; i++) {
          const mid = (low + high) / 2;
          if (svgPath.getPointAtLength(mid).x < targetX) low = mid;else high = mid;
        }
        return (low + high) / 2;
      }
      const markerPathLength = vue.shallowRef(0);
      vue.watch(currentPoint, point => {
        if (!point || !strokePath.value) return;
        markerPathLength.value = getPathLengthAtX(strokePath.value, point.x);
      });
      const animatedLength = useTransition(markerPathLength, {
        duration: 150,
        transition: easingPatterns.easeOutQuad
      });
      const markerPoint = vue.computed(() => {
        const {
          x,
          y
        } = strokePath.value?.getPointAtLength(animatedLength.value) ?? {
          x: 0,
          y: 0
        };
        return {
          x,
          y
        };
      });
      const tooltipTarget = vue.computed(() => {
        if (!currentPoint.value || !svgRef.value) return undefined;
        const matrix = svgRef.value.getScreenCTM();
        if (!matrix) return undefined;
        const svgPoint = svgRef.value.createSVGPoint();
        svgPoint.x = markerPoint.value.x;
        svgPoint.y = markerPoint.value.y;
        const {
          x,
          y
        } = svgPoint.matrixTransform(matrix);
        return [x, y];
      });
      const tooltipConfig = vue.computed(() => ({
        showCrosshair: true,
        offset: 16,
        titleFormat: item => String(item.value),
        ...(typeof props.tooltip === 'object' ? props.tooltip : {})
      }));
      let frame = -1;
      function onSvgMousemove(e) {
        const target = e.currentTarget;
        cancelAnimationFrame(frame);
        frame = requestAnimationFrame(() => {
          const rect = target.getBoundingClientRect();
          const svgX = (e.clientX - rect.left) / rect.width * Number(props.width);
          let nearest = 0;
          let minDist = Infinity;
          points.value.forEach((point, index) => {
            const dist = Math.abs(point.x - svgX);
            if (dist < minDist) {
              minDist = dist;
              nearest = index;
            }
          });
          currentIndex.value = nearest;
          emit('update:currentIndex', nearest);
          tooltipVisible.value = true;
        });
      }
      function onSvgMouseleave() {
        cancelAnimationFrame(frame);
        tooltipVisible.value = false;
        if (!props.tooltip) {
          currentIndex.value = null;
          emit('update:currentIndex', null);
        }
      }
      function onTooltipAfterLeave() {
        currentIndex.value = null;
        emit('update:currentIndex', null);
      }
      function setIndex(index) {
        currentIndex.value = index;
        emit('update:currentIndex', index);
        tooltipVisible.value = index !== null;
      }
      function onSvgFocus() {
        if (!points.value.length) return;
        setIndex(points.value.length - 1);
      }
      function onSvgBlur() {
        tooltipVisible.value = false;
        if (!props.tooltip) {
          setIndex(null);
        }
      }
      function onSvgKeydown(e) {
        if (!points.value.length) return;
        const length = points.value.length;
        if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
          e.preventDefault();
          const direction = e.key === 'ArrowLeft' ? -1 : 1;
          const current = currentIndex.value ?? (direction === 1 ? -1 : length);
          const next = Math.max(0, Math.min(length - 1, current + direction));
          setIndex(next);
        }
      }
      useRender(() => {
        const gradientData = !props.gradient.slice().length ? [''] : props.gradient.slice().reverse();
        const markerRadius = (parseFloat(props.markerSize) || 8) / 2;
        return vue.createElementVNode(vue.Fragment, null, [vue.createElementVNode("svg", vue.mergeProps({
          "ref": svgRef,
          "display": "block",
          "stroke-width": parseFloat(props.lineWidth) ?? 4,
          "tabindex": props.interactive ? 0 : undefined,
          "onMousemove": props.interactive ? onSvgMousemove : undefined,
          "onMouseleave": props.interactive ? onSvgMouseleave : undefined,
          "onFocus": props.interactive ? onSvgFocus : undefined,
          "onBlur": props.interactive ? onSvgBlur : undefined,
          "onKeydown": props.interactive ? onSvgKeydown : undefined
        }, attrs), [vue.createElementVNode("defs", null, [vue.createElementVNode("linearGradient", {
          "id": id.value,
          "gradientUnits": "userSpaceOnUse",
          "x1": props.gradientDirection === 'left' ? '100%' : '0',
          "y1": props.gradientDirection === 'top' ? '100%' : '0',
          "x2": props.gradientDirection === 'right' ? '100%' : '0',
          "y2": props.gradientDirection === 'bottom' ? '100%' : '0'
        }, [gradientData.map((color, index) => vue.createElementVNode("stop", {
          "offset": index / Math.max(gradientData.length - 1, 1),
          "stop-color": color || 'currentColor'
        }, null))])]), hasLabels.value && vue.createElementVNode("g", {
          "key": "labels",
          "style": {
            textAnchor: 'middle',
            dominantBaseline: 'mathematical',
            fill: 'currentColor'
          }
        }, [parsedLabels.value.map((item, i) => vue.createElementVNode("text", {
          "x": item.x,
          "y": parseInt(props.height, 10) - 4 + (parseInt(props.labelSize, 10) || 7 * 0.75),
          "font-size": Number(props.labelSize) || 7
        }, [slots.label?.({
          index: i,
          value: item.value
        }) ?? item.value]))]), vue.createElementVNode("path", {
          "key": "fill",
          "ref": props.fill ? fillPath : strokePath,
          "d": genPath(extendedPoints.value, props.fill),
          "fill": props.fill ? `url(#${id.value})` : 'none',
          "stroke": props.fill ? 'none' : `url(#${id.value})`
        }, null), props.fill && vue.createElementVNode("path", {
          "key": "trendline",
          "ref": strokePath,
          "d": genPath(extendedPoints.value, false),
          "fill": "none",
          "stroke": "currentColor"
        }, null), props.showMarkers && vue.createElementVNode("g", {
          "key": "markers"
        }, [points.value.map((point, i) => vue.createElementVNode("circle", {
          "key": i,
          "cx": point.x,
          "cy": point.y,
          "r": markerRadius,
          "fill": "currentColor",
          "stroke": props.markerStroke,
          "stroke-width": 2,
          "pointer-events": "none"
        }, null))]), props.interactive && currentPoint.value && vue.createElementVNode("g", {
          "key": "hover",
          "pointer-events": "none"
        }, [tooltipConfig.value.showCrosshair && vue.createElementVNode("line", {
          "key": "crosshair-line",
          "x1": markerPoint.value.x,
          "y1": props.inset ? 0 : boundary.value.minY,
          "x2": markerPoint.value.x,
          "y2": props.inset ? parseInt(props.height, 10) : boundary.value.maxY,
          "stroke": "currentColor",
          "stroke-width": 1,
          "stroke-dasharray": "4 2",
          "opacity": 0.5
        }, null), vue.createElementVNode("circle", {
          "key": "marker",
          "cx": markerPoint.value.x,
          "cy": markerPoint.value.y,
          "r": markerRadius,
          "fill": "currentColor",
          "stroke": props.markerStroke,
          "stroke-width": 2
        }, null)])]), !!props.tooltip && vue.createVNode(VSparklineTooltip, {
          "key": "tooltip",
          "modelValue": tooltipVisible.value,
          "target": tooltipTarget.value,
          "index": currentIndex.value,
          "value": currentIndex.value !== null ? points.value[currentIndex.value].value : 0,
          "offset": tooltipConfig.value.offset,
          "contentClass": tooltipConfig.value.class,
          "titleFormat": tooltipConfig.value.titleFormat,
          "onAfterLeave": onTooltipAfterLeave
        }, {
          default: slots.tooltip
        })]);
      });
    }
  });

  // Types

  const makeVSparklineProps = propsFactory({
    type: {
      type: String,
      default: 'trend'
    },
    ...makeVBarlineProps(),
    ...makeVTrendlineProps()
  }, 'VSparkline');
  const VSparkline = genericComponent()({
    name: 'VSparkline',
    props: makeVSparklineProps(),
    emits: {
      'update:currentIndex': _index => true
    },
    setup(props, {
      slots,
      emit
    }) {
      const {
        textColorClasses,
        textColorStyles
      } = useTextColor(() => props.color);
      const hasLabels = vue.computed(() => {
        return Boolean(props.showLabels || props.labels.length > 0 || !!slots?.label);
      });
      const totalHeight = vue.computed(() => {
        let height = parseInt(props.height, 10);
        if (hasLabels.value) height += parseInt(props.labelSize, 10) * 1.5;
        return height;
      });
      useRender(() => {
        const Tag = props.type === 'trend' ? VTrendline : VBarline;
        const lineProps = props.type === 'trend' ? VTrendline.filterProps(props) : VBarline.filterProps(props);
        return vue.createVNode(Tag, vue.mergeProps({
          "key": props.type,
          "class": textColorClasses.value,
          "style": textColorStyles.value,
          "viewBox": `0 0 ${props.width} ${totalHeight.value}`
        }, lineProps, {
          "onUpdate:currentIndex": v => emit('update:currentIndex', v)
        }), slots);
      });
    }
  });

  // Types

  const makeVSpeedDialProps = propsFactory({
    ...makeComponentProps(),
    ...makeVMenuProps({
      offset: 8,
      minWidth: 0,
      openDelay: 0,
      closeDelay: 100,
      location: 'top center',
      transition: 'scale-transition'
    })
  }, 'VSpeedDial');
  const VSpeedDial = genericComponent()({
    name: 'VSpeedDial',
    props: makeVSpeedDialProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const model = useProxiedModel(props, 'modelValue');
      const menuRef = vue.ref();
      const location = vue.computed(() => {
        const [y, x = 'center'] = props.location?.split(' ') ?? [];
        return `${y} ${x}`;
      });
      const locationClasses = vue.computed(() => ({
        [`v-speed-dial__content--${location.value.replace(' ', '-')}`]: true
      }));
      useRender(() => {
        const menuProps = VMenu.filterProps(props);
        return vue.createVNode(VMenu, vue.mergeProps(menuProps, {
          "modelValue": model.value,
          "onUpdate:modelValue": $event => model.value = $event,
          "class": props.class,
          "style": props.style,
          "contentClass": ['v-speed-dial__content', locationClasses.value, props.contentClass],
          "location": location.value,
          "ref": menuRef,
          "transition": "fade-transition"
        }), {
          ...slots,
          default: slotProps => vue.createVNode(VDefaultsProvider, {
            "defaults": {
              VBtn: {
                size: 'small'
              }
            }
          }, {
            default: () => [vue.createVNode(MaybeTransition, {
              "appear": true,
              "group": true,
              "transition": props.transition
            }, {
              default: () => [slots.default?.(slotProps)]
            })]
          })
        });
      });
      return {};
    }
  });

  // Types

  const VStepperSymbol = Symbol.for('vuetify:v-stepper');

  // Types

  const makeVStepperActionsProps = propsFactory({
    color: String,
    disabled: {
      type: [Boolean, String],
      default: false
    },
    prevText: {
      type: String,
      default: '$vuetify.stepper.prev'
    },
    nextText: {
      type: String,
      default: '$vuetify.stepper.next'
    }
  }, 'VStepperActions');
  const VStepperActions = genericComponent()({
    name: 'VStepperActions',
    props: makeVStepperActionsProps(),
    emits: {
      'click:prev': () => true,
      'click:next': () => true
    },
    setup(props, {
      emit,
      slots
    }) {
      const {
        t
      } = useLocale();
      function onClickPrev() {
        emit('click:prev');
      }
      function onClickNext() {
        emit('click:next');
      }
      useRender(() => {
        const prevSlotProps = {
          onClick: onClickPrev
        };
        const nextSlotProps = {
          onClick: onClickNext
        };
        return vue.createElementVNode("div", {
          "class": "v-stepper-actions"
        }, [vue.createVNode(VDefaultsProvider, {
          "defaults": {
            VBtn: {
              disabled: ['prev', true].includes(props.disabled),
              text: t(props.prevText),
              variant: 'text'
            }
          }
        }, {
          default: () => [slots.prev?.({
            props: prevSlotProps
          }) ?? vue.createVNode(VBtn, prevSlotProps, null)]
        }), vue.createVNode(VDefaultsProvider, {
          "defaults": {
            VBtn: {
              color: props.color,
              disabled: ['next', true].includes(props.disabled),
              text: t(props.nextText),
              variant: 'tonal'
            }
          }
        }, {
          default: () => [slots.next?.({
            props: nextSlotProps
          }) ?? vue.createVNode(VBtn, nextSlotProps, null)]
        })]);
      });
      return {};
    }
  });

  // Utilities
  const VStepperHeader = createSimpleFunctional('v-stepper-header');

  // Types

  const makeStepperItemProps = propsFactory({
    color: String,
    title: String,
    subtitle: String,
    complete: Boolean,
    completeIcon: {
      type: IconValue,
      default: '$complete'
    },
    editable: Boolean,
    editIcon: {
      type: IconValue,
      default: '$edit'
    },
    error: Boolean,
    errorIcon: {
      type: IconValue,
      default: '$error'
    },
    icon: IconValue,
    ripple: {
      type: [Boolean, Object],
      default: true
    },
    rules: {
      type: Array,
      default: () => []
    }
  }, 'StepperItem');
  const makeVStepperItemProps = propsFactory({
    ...makeStepperItemProps(),
    ...makeGroupItemProps()
  }, 'VStepperItem');
  const VStepperItem = genericComponent()({
    name: 'VStepperItem',
    directives: {
      vRipple: Ripple
    },
    props: makeVStepperItemProps(),
    emits: {
      'group:selected': val => true
    },
    setup(props, {
      slots
    }) {
      const group = useGroupItem(props, VStepperSymbol, true);
      const step = vue.computed(() => group?.value.value ?? props.value);
      const isValid = vue.computed(() => props.rules.every(handler => handler() === true));
      const isClickable = vue.computed(() => !props.disabled && props.editable);
      const canEdit = vue.computed(() => !props.disabled && props.editable);
      const hasError = vue.computed(() => props.error || !isValid.value);
      const hasCompleted = vue.computed(() => props.complete || props.rules.length > 0 && isValid.value);
      const icon = vue.computed(() => {
        if (hasError.value) return props.errorIcon;
        if (hasCompleted.value) return props.completeIcon;
        if (group.isSelected.value && props.editable) return props.editIcon;
        return props.icon;
      });
      const slotProps = vue.computed(() => ({
        canEdit: canEdit.value,
        hasError: hasError.value,
        hasCompleted: hasCompleted.value,
        title: props.title,
        subtitle: props.subtitle,
        step: step.value,
        value: props.value
      }));
      useRender(() => {
        const hasColor = (!group || group.isSelected.value || hasCompleted.value || canEdit.value) && !hasError.value && !props.disabled;
        const hasTitle = !!(props.title != null || slots.title);
        const hasSubtitle = !!(props.subtitle != null || slots.subtitle);
        function onClick() {
          group?.toggle();
        }
        return vue.withDirectives(vue.createElementVNode("button", {
          "class": vue.normalizeClass(['v-stepper-item', {
            'v-stepper-item--complete': hasCompleted.value,
            'v-stepper-item--disabled': props.disabled,
            'v-stepper-item--error': hasError.value
          }, group?.selectedClass.value]),
          "disabled": !props.editable,
          "type": "button",
          "onClick": onClick
        }, [isClickable.value && genOverlays(true, 'v-stepper-item'), vue.createVNode(VAvatar, {
          "key": "stepper-avatar",
          "class": "v-stepper-item__avatar",
          "color": hasColor ? props.color : undefined,
          "size": 24
        }, {
          default: () => [slots.icon?.(slotProps.value) ?? (icon.value ? vue.createVNode(VIcon, {
            "icon": icon.value
          }, null) : step.value)]
        }), vue.createElementVNode("div", {
          "class": "v-stepper-item__content"
        }, [hasTitle && vue.createElementVNode("div", {
          "key": "title",
          "class": "v-stepper-item__title"
        }, [slots.title?.(slotProps.value) ?? props.title]), hasSubtitle && vue.createElementVNode("div", {
          "key": "subtitle",
          "class": "v-stepper-item__subtitle"
        }, [slots.subtitle?.(slotProps.value) ?? props.subtitle]), slots.default?.(slotProps.value)])]), [[Ripple, props.editable && props.ripple, null]]);
      });
      return {};
    }
  });

  // Types

  const makeVStepperWindowProps = propsFactory({
    ...omit(makeVWindowProps(), ['continuous', 'nextIcon', 'prevIcon', 'showArrows', 'touch', 'mandatory'])
  }, 'VStepperWindow');
  const VStepperWindow = genericComponent()({
    name: 'VStepperWindow',
    props: makeVStepperWindowProps(),
    emits: {
      'update:modelValue': v => true
    },
    setup(props, {
      slots
    }) {
      const group = vue.inject(VStepperSymbol, null);
      const _model = useProxiedModel(props, 'modelValue');
      const model = vue.computed({
        get() {
          // Always return modelValue if defined
          // or if not within a VStepper group
          if (_model.value != null || !group) return _model.value;

          // If inside of a VStepper, find the currently selected
          // item by id. Item value may be assigned by its index
          return group.items.value.find(item => group.selected.value.includes(item.id))?.value;
        },
        set(val) {
          _model.value = val;
        }
      });
      useRender(() => {
        const windowProps = VWindow.filterProps(props);
        return vue.createVNode(VWindow, vue.mergeProps({
          "_as": "VStepperWindow"
        }, windowProps, {
          "modelValue": model.value,
          "onUpdate:modelValue": $event => model.value = $event,
          "class": ['v-stepper-window', props.class],
          "style": props.style,
          "mandatory": false,
          "touch": false
        }), slots);
      });
      return {};
    }
  });

  const makeVStepperWindowItemProps = propsFactory({
    ...makeVWindowItemProps()
  }, 'VStepperWindowItem');
  const VStepperWindowItem = genericComponent()({
    name: 'VStepperWindowItem',
    props: makeVStepperWindowItemProps(),
    setup(props, {
      slots
    }) {
      useRender(() => {
        const windowItemProps = VWindowItem.filterProps(props);
        return vue.createVNode(VWindowItem, vue.mergeProps({
          "_as": "VStepperWindowItem"
        }, windowItemProps, {
          "class": ['v-stepper-window-item', props.class],
          "style": props.style
        }), slots);
      });
      return {};
    }
  });

  // Types

  const makeStepperProps = propsFactory({
    altLabels: Boolean,
    bgColor: String,
    completeIcon: IconValue,
    editIcon: IconValue,
    editable: Boolean,
    errorIcon: IconValue,
    hideActions: Boolean,
    items: {
      type: Array,
      default: () => []
    },
    itemTitle: {
      type: [String, Array, Function],
      default: 'title'
    },
    itemValue: {
      type: [String, Array, Function],
      default: 'value'
    },
    itemProps: {
      type: [Boolean, String, Array, Function],
      default: 'props'
    },
    nonLinear: Boolean,
    flat: Boolean,
    ...makeDisplayProps()
  }, 'Stepper');
  const makeVStepperProps = propsFactory({
    ...makeStepperProps(),
    ...makeGroupProps({
      mandatory: 'force',
      selectedClass: 'v-stepper-item--selected'
    }),
    ...makeVSheetProps(),
    ...pick(makeVStepperActionsProps(), ['prevText', 'nextText'])
  }, 'VStepper');
  const VStepper = genericComponent()({
    name: 'VStepper',
    props: makeVStepperProps(),
    emits: {
      'update:modelValue': v => true
    },
    setup(props, {
      slots
    }) {
      const {
        items: _items,
        next,
        prev,
        selected
      } = useGroup(props, VStepperSymbol);
      const {
        displayClasses,
        mobile
      } = useDisplay(props);
      const {
        completeIcon,
        editIcon,
        errorIcon,
        color,
        editable,
        prevText,
        nextText
      } = vue.toRefs(props);
      const items = vue.computed(() => props.items.map((item, index) => {
        const title = getPropertyFromItem(item, props.itemTitle, item);
        const value = getPropertyFromItem(item, props.itemValue, index + 1);
        const itemProps = props.itemProps === true ? item : getPropertyFromItem(item, props.itemProps);
        const _props = {
          title,
          value,
          ...itemProps
        };
        return {
          title: _props.title,
          value: _props.value,
          props: _props,
          raw: item
        };
      }));
      const activeIndex = vue.computed(() => {
        return _items.value.findIndex(item => selected.value.includes(item.id));
      });
      const disabled = vue.computed(() => {
        if (props.disabled) return props.disabled;
        if (activeIndex.value === 0) return 'prev';
        if (activeIndex.value === _items.value.length - 1) return 'next';
        return false;
      });
      provideDefaults({
        VStepperItem: {
          editable,
          errorIcon,
          completeIcon,
          editIcon,
          prevText,
          nextText
        },
        VStepperActions: {
          color,
          disabled,
          prevText,
          nextText
        }
      });
      useRender(() => {
        const sheetProps = VSheet.filterProps(props);
        const hasHeader = !!(slots.header || props.items.length);
        const hasWindow = props.items.length > 0;
        const hasActions = !props.hideActions && !!(hasWindow || slots.actions);
        return vue.createVNode(VSheet, vue.mergeProps(sheetProps, {
          "color": props.bgColor,
          "class": ['v-stepper', {
            'v-stepper--alt-labels': props.altLabels,
            'v-stepper--flat': props.flat,
            'v-stepper--non-linear': props.nonLinear,
            'v-stepper--mobile': mobile.value
          }, displayClasses.value, props.class],
          "style": props.style
        }), {
          default: () => [hasHeader && vue.createVNode(VStepperHeader, {
            "key": "stepper-header"
          }, {
            default: () => [items.value.map(({
              raw,
              ...item
            }, index) => vue.createElementVNode(vue.Fragment, null, [!!index && vue.createVNode(VDivider, null, null), vue.createVNode(VStepperItem, item.props, {
              default: slots[`header-item.${item.value}`] ?? slots.header,
              icon: slots.icon,
              title: slots.title,
              subtitle: slots.subtitle
            })]))]
          }), hasWindow && vue.createVNode(VStepperWindow, {
            "key": "stepper-window"
          }, {
            default: () => [items.value.map(item => vue.createVNode(VStepperWindowItem, {
              "value": item.value
            }, {
              default: () => slots[`item.${item.value}`]?.(item) ?? slots.item?.(item)
            }))]
          }), slots.default?.({
            prev,
            next
          }), hasActions && (slots.actions?.({
            next,
            prev
          }) ?? vue.createVNode(VStepperActions, {
            "key": "stepper-actions",
            "onClick:prev": prev,
            "onClick:next": next
          }, slots))]
        });
      });
      return {
        prev,
        next
      };
    }
  });

  // Types

  const makeVStepperVerticalActionsProps = propsFactory({
    ...makeVStepperActionsProps()
  }, 'VStepperActions');
  const VStepperVerticalActions = genericComponent()({
    name: 'VStepperVerticalActions',
    props: makeVStepperVerticalActionsProps(),
    emits: {
      'click:prev': () => true,
      'click:next': () => true
    },
    setup(props, {
      emit,
      slots
    }) {
      function onClickPrev() {
        emit('click:prev');
      }
      function onClickNext() {
        emit('click:next');
      }
      useRender(() => {
        const stepperActionsProps = VStepperActions.filterProps(props);
        return vue.createVNode(VStepperActions, vue.mergeProps({
          "class": "v-stepper-vertical-actions"
        }, stepperActionsProps, {
          "onClick:prev": onClickPrev,
          "onClick:next": onClickNext
        }), slots);
      });
      return {};
    }
  });

  // Types

  const makeVStepperVerticalItemProps = propsFactory({
    hideActions: Boolean,
    ...makeStepperItemProps(),
    ...omit(makeVExpansionPanelProps({
      expandIcon: '',
      collapseIcon: ''
    }), ['hideActions'])
  }, 'VStepperVerticalItem');
  const VStepperVerticalItem = genericComponent()({
    name: 'VStepperVerticalItem',
    props: makeVStepperVerticalItemProps(),
    emits: {
      'click:next': () => true,
      'click:prev': () => true,
      'click:finish': () => true
    },
    setup(props, {
      emit,
      slots
    }) {
      const vExpansionPanelRef = vue.ref();
      const step = vue.computed(() => !isNaN(parseInt(props.value)) ? Number(props.value) : props.value);
      const groupItem = vue.computed(() => vExpansionPanelRef.value?.groupItem);
      const isValid = vue.computed(() => props.rules.every(handler => handler() === true));
      const canEdit = vue.computed(() => !props.disabled && props.editable);
      const hasError = vue.computed(() => props.error || !isValid.value);
      const hasCompleted = vue.computed(() => props.complete || props.rules.length > 0 && isValid.value);
      const disabled = vue.computed(() => {
        if (props.disabled) return props.disabled;
        if (groupItem.value?.isFirst.value) return 'prev';
        return false;
      });
      const icon = vue.computed(() => {
        if (hasError.value) return props.errorIcon;
        if (hasCompleted.value) return props.completeIcon;
        if (groupItem.value?.isSelected.value && props.editable) return props.editIcon;
        return props.icon;
      });
      const slotProps = vue.computed(() => ({
        canEdit: canEdit.value,
        hasError: hasError.value,
        hasCompleted: hasCompleted.value,
        title: props.title,
        subtitle: props.subtitle,
        step: step.value
      }));
      const actionProps = vue.computed(() => ({
        ...slotProps.value,
        prev: onClickPrev,
        next: onClickNext
      }));
      function onClickNext() {
        emit('click:next');
        if (groupItem.value?.isLast.value) return;
        groupItem.value.group.next();
      }
      function onClickPrev() {
        emit('click:prev');
        groupItem.value.group.prev();
      }
      useRender(() => {
        const hasColor = (!groupItem.value || groupItem.value?.isSelected.value || hasCompleted.value || canEdit.value) && !hasError.value && !props.disabled;
        const hasActions = !props.hideActions || !!slots.actions;
        const expansionPanelProps = VExpansionPanel.filterProps(props);
        return vue.createVNode(VExpansionPanel, vue.mergeProps({
          "_as": "VStepperVerticalItem",
          "ref": vExpansionPanelRef
        }, expansionPanelProps, {
          "class": ['v-stepper-vertical-item', {
            'v-stepper-vertical-item--complete': hasCompleted.value,
            'v-stepper-vertical-item--disabled': props.disabled,
            'v-stepper-vertical-item--editable': canEdit.value,
            'v-stepper-vertical-item--error': hasError.value
          }, props.class],
          "readonly": !props.editable,
          "style": props.style,
          "color": "",
          "hideActions": false,
          "value": step.value
        }), {
          title: () => vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VAvatar, {
            "key": "stepper-avatar",
            "class": "v-stepper-vertical-item__avatar",
            "color": hasColor ? props.color : undefined,
            "size": 24,
            "start": true
          }, {
            default: () => [slots.icon?.(slotProps.value) ?? (icon.value ? vue.createVNode(VIcon, {
              "icon": icon.value
            }, null) : step.value)]
          }), vue.createElementVNode("div", null, [vue.createElementVNode("div", {
            "class": "v-stepper-vertical-item__title"
          }, [slots.title?.(slotProps.value) ?? props.title]), vue.createElementVNode("div", {
            "class": "v-stepper-vertical-item__subtitle"
          }, [slots.subtitle?.(slotProps.value) ?? props.subtitle])])]),
          text: () => vue.createElementVNode(vue.Fragment, null, [slots.default?.(slotProps.value) ?? props.text, hasActions && vue.createVNode(VDefaultsProvider, {
            "defaults": {
              VStepperVerticalActions: {
                disabled: disabled.value,
                finish: groupItem.value?.isLast.value
              }
            }
          }, {
            default: () => [slots.actions?.(actionProps.value) ?? vue.createVNode(VStepperVerticalActions, {
              "onClick:next": onClickNext,
              "onClick:prev": onClickPrev
            }, {
              prev: slots.prev ? () => slots.prev?.(actionProps.value) : undefined,
              next: slots.next ? () => slots.next?.(actionProps.value) : undefined
            })]
          })])
        });
      });
      return {};
    }
  });

  // Types

  const makeVStepperVerticalProps = propsFactory({
    prevText: {
      type: String,
      default: '$vuetify.stepper.prev'
    },
    nextText: {
      type: String,
      default: '$vuetify.stepper.next'
    },
    ...makeStepperProps(),
    ...omit(makeVExpansionPanelsProps({
      mandatory: 'force',
      variant: 'accordion'
    }), ['static'])
  }, 'VStepperVertical');
  const VStepperVertical = genericComponent()({
    name: 'VStepperVertical',
    props: makeVStepperVerticalProps(),
    emits: {
      'update:modelValue': val => true
    },
    setup(props, {
      slots
    }) {
      const vExpansionPanelsRef = vue.ref();
      const {
        color,
        eager,
        editable,
        prevText,
        nextText,
        hideActions
      } = vue.toRefs(props);
      const model = useProxiedModel(props, 'modelValue');
      const items = vue.computed(() => props.items.map((item, index) => {
        const title = getPropertyFromItem(item, props.itemTitle, item);
        const value = getPropertyFromItem(item, props.itemValue, index + 1);
        const itemProps = props.itemProps === true ? item : getPropertyFromItem(item, props.itemProps);
        const _props = {
          title,
          value,
          ...itemProps
        };
        return {
          title: _props.title,
          value: _props.value,
          props: _props,
          raw: item
        };
      }));
      provideDefaults({
        VStepperVerticalItem: {
          color,
          eager,
          editable,
          hideActions,
          static: true
        },
        VStepperVerticalActions: {
          color,
          nextText,
          prevText
        }
      });
      useRender(() => {
        const expansionPanelProps = VExpansionPanels.filterProps(props);
        return vue.createVNode(VExpansionPanels, vue.mergeProps(expansionPanelProps, {
          "modelValue": model.value,
          "onUpdate:modelValue": $event => model.value = $event,
          "ref": vExpansionPanelsRef,
          "class": ['v-stepper', {
            'v-stepper--alt-labels': props.altLabels,
            'v-stepper--flat': props.flat,
            'v-stepper--non-linear': props.nonLinear,
            'v-stepper--mobile': props.mobile
          }, props.class],
          "style": props.style
        }), {
          ...slots,
          default: ({
            prev,
            next
          }) => {
            return vue.createElementVNode(vue.Fragment, null, [items.value.map(({
              raw,
              ...item
            }) => vue.createVNode(VStepperVerticalItem, item.props, {
              ...slots,
              default: slots[`item.${item.value}`]
            })), slots.default?.({
              prev,
              next,
              step: model.value
            })]);
          }
        });
      });
      return {};
    }
  });

  // Types

  const makeVSwitchProps = propsFactory({
    inset: {
      type: [Boolean, String],
      default: false
    },
    flat: Boolean,
    thumbColor: String,
    loading: {
      type: [Boolean, String],
      default: false
    },
    ...omit(makeVInputProps(), ['glow']),
    ...makeVSelectionControlProps(),
    ...makeSizeProps()
  }, 'VSwitch');
  const predefinedSizes = ['x-small', 'small', 'default', 'large', 'x-large'];
  const iconSizes = {
    'x-small': 11,
    small: 14,
    default: 16,
    large: 18,
    'x-large': 22
  };
  const VSwitch = genericComponent()({
    name: 'VSwitch',
    inheritAttrs: false,
    props: makeVSwitchProps(),
    emits: {
      'update:focused': focused => true,
      'update:modelValue': value => true,
      'update:indeterminate': value => true
    },
    setup(props, {
      attrs,
      slots
    }) {
      const indeterminate = useProxiedModel(props, 'indeterminate');
      const model = useProxiedModel(props, 'modelValue');
      const {
        loaderClasses
      } = useLoader(props);
      const {
        isFocused,
        focus,
        blur
      } = useFocus(props);
      const {
        backgroundColorClasses: thumbColorClasses,
        backgroundColorStyles: thumbColorStyles
      } = useBackgroundColor(() => props.thumbColor);
      const control = vue.ref();
      const inputRef = vue.ref();
      const isForcedColorsModeActive = SUPPORTS_MATCH_MEDIA && window.matchMedia('(forced-colors: active)').matches;
      const loaderColor = vue.toRef(() => {
        return typeof props.loading === 'string' && props.loading !== '' ? props.loading : props.color;
      });
      const uid = vue.useId();
      const id = vue.toRef(() => props.id || `switch-${uid}`);
      const isPredefinedSize = vue.toRef(() => predefinedSizes.includes(props.size));
      const iconSize = vue.toRef(() => {
        return isPredefinedSize.value ? iconSizes[props.size] : Math.round(16 * Number(props.size) / 32);
      });
      function onChange() {
        if (indeterminate.value) {
          indeterminate.value = false;
        }
      }
      function onTrackClick(e) {
        e.stopPropagation();
        e.preventDefault();
        control.value?.input?.click();
      }
      useRender(() => {
        const [rootAttrs, controlAttrs] = filterInputAttrs(attrs);
        const inputProps = VInput.filterProps(props);
        const controlProps = VSelectionControl.filterProps(props);
        const isMaterial = ['material', 'square'].includes(String(props.inset));
        const hasThumbColor = !isForcedColorsModeActive && !!props.thumbColor;
        return vue.createVNode(VInput, vue.mergeProps({
          "ref": inputRef,
          "class": ['v-switch', {
            'v-switch--flat': props.flat
          }, {
            'v-switch--inset': !!props.inset
          }, {
            'v-switch--inset-material': isMaterial
          }, {
            'v-switch--inset-square': props.inset === 'square'
          }, {
            'v-switch--indeterminate': indeterminate.value
          }, isPredefinedSize.value ? `v-switch--size-${props.size}` : undefined, loaderClasses.value, props.class]
        }, rootAttrs, inputProps, {
          "modelValue": model.value,
          "onUpdate:modelValue": $event => model.value = $event,
          "id": id.value,
          "focused": isFocused.value,
          "style": [{
            '--v-switch-scale': isPredefinedSize.value ? undefined : Number(props.size) / 32
          }, props.style]
        }), {
          ...slots,
          default: ({
            id,
            messagesId,
            isDisabled,
            isReadonly,
            isValid
          }) => {
            const slotProps = {
              model,
              isValid
            };
            return vue.createVNode(VSelectionControl, vue.mergeProps({
              "ref": control
            }, controlProps, {
              "modelValue": model.value,
              "onUpdate:modelValue": [$event => model.value = $event, onChange],
              "id": id.value,
              "aria-describedby": messagesId.value,
              "type": "checkbox",
              "aria-checked": indeterminate.value ? 'mixed' : undefined,
              "disabled": isDisabled.value,
              "readonly": isReadonly.value,
              "onFocus": focus,
              "onBlur": blur
            }, controlAttrs), {
              ...slots,
              default: ({
                backgroundColorClasses,
                backgroundColorStyles
              }) => vue.createElementVNode("div", {
                "class": vue.normalizeClass(['v-switch__track', !isForcedColorsModeActive ? backgroundColorClasses.value : undefined]),
                "style": vue.normalizeStyle(backgroundColorStyles.value),
                "onClick": onTrackClick
              }, [slots['track-true'] && vue.createElementVNode("div", {
                "key": "prepend",
                "class": "v-switch__track-true"
              }, [slots['track-true'](slotProps)]), slots['track-false'] && vue.createElementVNode("div", {
                "key": "append",
                "class": "v-switch__track-false"
              }, [slots['track-false'](slotProps)])]),
              input: ({
                inputNode,
                icon,
                model: isSelected,
                backgroundColorClasses,
                backgroundColorStyles,
                textColorClasses,
                textColorStyles
              }) => vue.createElementVNode(vue.Fragment, null, [inputNode, vue.createElementVNode("div", {
                "class": vue.normalizeClass(['v-switch__thumb', {
                  'v-switch__thumb--filled': icon || props.loading
                }, isForcedColorsModeActive ? undefined : hasThumbColor && isSelected.value ? thumbColorClasses.value : isMaterial ? backgroundColorClasses.value : props.inset ? undefined : backgroundColorClasses.value]),
                "style": vue.normalizeStyle([hasThumbColor && isSelected.value ? thumbColorStyles.value : isMaterial ? backgroundColorClasses.value.length || backgroundColorStyles.value.backgroundColor ? {
                  backgroundColor: 'currentColor'
                } : undefined : props.inset ? undefined : backgroundColorStyles.value])
              }, [slots.thumb ? vue.createVNode(VDefaultsProvider, {
                "defaults": {
                  VIcon: {
                    icon,
                    size: isMaterial ? iconSize.value : 'x-small'
                  }
                }
              }, {
                default: () => [slots.thumb({
                  ...slotProps,
                  icon
                })]
              }) : vue.createVNode(VScaleTransition, null, {
                default: () => [!props.loading ? icon && vue.createVNode(VIcon, {
                  "key": String(icon),
                  "class": vue.normalizeClass(isMaterial ? textColorClasses.value : undefined),
                  "style": vue.normalizeStyle(isMaterial ? textColorStyles.value : undefined),
                  "icon": icon,
                  "size": isMaterial ? iconSize.value : 'x-small'
                }, null) : vue.createVNode(LoaderSlot, {
                  "name": "v-switch",
                  "active": true,
                  "color": isValid.value === false ? undefined : loaderColor.value
                }, {
                  default: slotProps => slots.loader ? slots.loader(slotProps) : vue.createVNode(VProgressCircular, {
                    "active": slotProps.isActive,
                    "color": slotProps.color,
                    "indeterminate": true,
                    "size": iconSize.value,
                    "width": "2"
                  }, null)
                })]
              })])])
            });
          }
        });
      });
      return forwardRefs({}, inputRef);
    }
  });

  const makeVSystemBarProps = propsFactory({
    color: String,
    height: [Number, String],
    window: Boolean,
    ...makeComponentProps(),
    ...makeElevationProps(),
    ...makeLayoutItemProps(),
    ...makeRoundedProps(),
    ...makeTagProps(),
    ...makeThemeProps()
  }, 'VSystemBar');
  const VSystemBar = genericComponent()({
    name: 'VSystemBar',
    props: makeVSystemBarProps(),
    setup(props, {
      slots
    }) {
      const {
        themeClasses
      } = provideTheme(props);
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.color);
      const {
        elevationClasses
      } = useElevation(props);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props);
      const {
        ssrBootStyles
      } = useSsrBoot();
      const height = vue.computed(() => props.height ?? (props.window ? 32 : 24));
      const {
        layoutItemStyles
      } = useLayoutItem({
        id: props.name,
        order: vue.computed(() => parseInt(props.order, 10)),
        position: vue.shallowRef('top'),
        layoutSize: height,
        elementSize: height,
        active: vue.computed(() => true),
        absolute: vue.toRef(() => props.absolute)
      });
      useRender(() => vue.createVNode(props.tag, {
        "class": vue.normalizeClass(['v-system-bar', {
          'v-system-bar--window': props.window
        }, themeClasses.value, backgroundColorClasses.value, elevationClasses.value, roundedClasses.value, props.class]),
        "style": vue.normalizeStyle([backgroundColorStyles.value, layoutItemStyles.value, ssrBootStyles.value, roundedStyles.value, props.style])
      }, slots));
      return {};
    }
  });

  // Types

  const VTabsSymbol = Symbol.for('vuetify:v-tabs');

  // Types

  const makeVTabProps = propsFactory({
    fixed: Boolean,
    sliderColor: String,
    sliderTransition: String,
    sliderTransitionDuration: [String, Number],
    hideSlider: Boolean,
    inset: Boolean,
    direction: {
      type: String,
      default: 'horizontal'
    },
    ...omit(makeVBtnProps({
      selectedClass: 'v-tab--selected',
      variant: 'text'
    }), ['active', 'block', 'flat', 'location', 'position', 'symbol'])
  }, 'VTab');
  const VTab = genericComponent()({
    name: 'VTab',
    props: makeVTabProps(),
    setup(props, {
      slots,
      attrs
    }) {
      const {
        textColorClasses: sliderColorClasses,
        textColorStyles: sliderColorStyles
      } = useTextColor(() => props.sliderColor);
      const {
        backgroundColorClasses: insetColorClasses,
        backgroundColorStyles: insetColorStyles
      } = useBackgroundColor(() => props.sliderColor);
      const rootEl = vue.ref();
      const sliderEl = vue.ref();
      const isHorizontal = vue.computed(() => props.direction === 'horizontal');
      const isSelected = vue.computed(() => rootEl.value?.group?.isSelected.value ?? false);
      function fade(nextEl, prevEl) {
        return {
          opacity: [0, 1]
        };
      }
      function grow(nextEl, prevEl) {
        return props.direction === 'vertical' ? {
          transform: ['scaleY(0)', 'scaleY(1)']
        } : {
          transform: ['scaleX(0)', 'scaleX(1)']
        };
      }
      function shift(nextEl, prevEl) {
        const prevBox = prevEl.getBoundingClientRect();
        const nextBox = nextEl.getBoundingClientRect();
        const xy = isHorizontal.value ? 'x' : 'y';
        const XY = isHorizontal.value ? 'X' : 'Y';
        const rightBottom = isHorizontal.value ? 'right' : 'bottom';
        const widthHeight = isHorizontal.value ? 'width' : 'height';
        const prevPos = prevBox[xy];
        const nextPos = nextBox[xy];
        const delta = prevPos > nextPos ? prevBox[rightBottom] - nextBox[rightBottom] : prevBox[xy] - nextBox[xy];
        const origin = Math.sign(delta) > 0 ? isHorizontal.value ? 'right' : 'bottom' : Math.sign(delta) < 0 ? isHorizontal.value ? 'left' : 'top' : 'center';
        const size = Math.abs(delta) + (Math.sign(delta) < 0 ? prevBox[widthHeight] : nextBox[widthHeight]);
        const scale = size / Math.max(prevBox[widthHeight], nextBox[widthHeight]) || 0;
        const initialScale = prevBox[widthHeight] / nextBox[widthHeight] || 0;
        const sigma = 1.5;
        return {
          transform: [`translate${XY}(${delta}px) scale${XY}(${initialScale})`, `translate${XY}(${delta / sigma}px) scale${XY}(${(scale - 1) / sigma + 1})`, 'none'],
          transformOrigin: Array(3).fill(origin)
        };
      }
      function updateSlider({
        value
      }) {
        if (value) {
          const prevEl = rootEl.value?.$el.parentElement?.querySelector('.v-tab--selected .v-tab__slider');
          const nextEl = sliderEl.value;
          if (!prevEl || !nextEl) return;
          const color = getComputedStyle(prevEl).backgroundColor;
          const keyframes = {
            fade,
            grow,
            shift
          }[props.sliderTransition ?? 'shift'] ?? shift;
          const duration = Number(props.sliderTransitionDuration) || ({
            fade: 400,
            grow: 350,
            shift: 225
          }[props.sliderTransition ?? 'shift'] ?? 225);
          animate(nextEl, {
            backgroundColor: [color, color],
            ...keyframes(nextEl, prevEl)
          }, {
            duration,
            easing: standardEasing
          });
        }
      }
      useRender(() => {
        const btnProps = VBtn.filterProps(props);
        return vue.createVNode(VBtn, vue.mergeProps({
          "symbol": VTabsSymbol,
          "ref": rootEl,
          "class": ['v-tab', props.class, isSelected.value && props.inset ? insetColorClasses.value : []],
          "style": [props.style, isSelected.value && props.inset ? insetColorStyles.value : [], {
            backgroundColor: isSelected.value && props.inset ? 'transparent !important' : undefined
          }],
          "tabindex": isSelected.value ? 0 : -1,
          "role": "tab",
          "aria-selected": String(isSelected.value),
          "active": false
        }, btnProps, attrs, {
          "block": props.fixed,
          "maxWidth": props.fixed ? 300 : undefined,
          "onGroup:selected": updateSlider
        }), {
          ...slots,
          default: () => vue.createElementVNode(vue.Fragment, null, [slots.default?.() ?? props.text, !props.hideSlider && vue.createElementVNode("div", {
            "ref": sliderEl,
            "class": vue.normalizeClass(['v-tab__slider', props.inset ? insetColorClasses.value : sliderColorClasses.value]),
            "style": vue.normalizeStyle([sliderColorStyles.value, props.inset ? insetColorStyles.value : sliderColorClasses.value])
          }, null)])
        });
      });
      return forwardRefs({}, rootEl);
    }
  });

  const makeVTabsWindowProps = propsFactory({
    ...omit(makeVWindowProps(), ['continuous', 'nextIcon', 'prevIcon', 'showArrows', 'touch', 'mandatory'])
  }, 'VTabsWindow');
  const VTabsWindow = genericComponent()({
    name: 'VTabsWindow',
    props: makeVTabsWindowProps(),
    emits: {
      'update:modelValue': v => true
    },
    setup(props, {
      slots
    }) {
      const group = vue.inject(VTabsSymbol, null);
      const _model = useProxiedModel(props, 'modelValue');
      const model = vue.computed({
        get() {
          // Always return modelValue if defined
          // or if not within a VTabs group
          if (_model.value != null || !group) return _model.value;

          // If inside of a VTabs, find the currently selected
          // item by id. Item value may be assigned by its index
          return group.items.value.find(item => group.selected.value.includes(item.id))?.value;
        },
        set(val) {
          _model.value = val;
        }
      });
      useRender(() => {
        const windowProps = VWindow.filterProps(props);
        return vue.createVNode(VWindow, vue.mergeProps({
          "_as": "VTabsWindow"
        }, windowProps, {
          "modelValue": model.value,
          "onUpdate:modelValue": $event => model.value = $event,
          "class": ['v-tabs-window', props.class],
          "style": props.style,
          "mandatory": false,
          "touch": false
        }), slots);
      });
      return {};
    }
  });

  const makeVTabsWindowItemProps = propsFactory({
    ...makeVWindowItemProps()
  }, 'VTabsWindowItem');
  const VTabsWindowItem = genericComponent()({
    name: 'VTabsWindowItem',
    props: makeVTabsWindowItemProps(),
    setup(props, {
      slots
    }) {
      useRender(() => {
        const windowItemProps = VWindowItem.filterProps(props);
        return vue.createVNode(VWindowItem, vue.mergeProps({
          "_as": "VTabsWindowItem"
        }, windowItemProps, {
          "class": ['v-tabs-window-item', props.class],
          "style": props.style
        }), slots);
      });
      return {};
    }
  });

  // Types

  function parseItems(items) {
    if (!items) return [];
    return items.map(item => {
      if (!isObject(item)) return {
        text: item,
        value: item
      };
      return item;
    });
  }
  const makeVTabsProps = propsFactory({
    alignTabs: {
      type: String,
      default: 'start'
    },
    color: String,
    fixedTabs: Boolean,
    items: {
      type: Array,
      default: () => []
    },
    stacked: Boolean,
    bgColor: String,
    grow: Boolean,
    height: {
      type: [Number, String],
      default: undefined
    },
    hideSlider: Boolean,
    inset: Boolean,
    insetPadding: [String, Number],
    insetRadius: [String, Number],
    sliderColor: String,
    ...pick(makeVTabProps(), ['spaced', 'sliderTransition', 'sliderTransitionDuration']),
    ...makeVSlideGroupProps({
      mandatory: 'force',
      selectedClass: 'v-tab-item--selected'
    }),
    ...makeDensityProps(),
    ...makeTagProps()
  }, 'VTabs');
  const VTabs = genericComponent()({
    name: 'VTabs',
    props: makeVTabsProps(),
    emits: {
      'update:modelValue': v => true
    },
    setup(props, {
      attrs,
      slots
    }) {
      const model = useProxiedModel(props, 'modelValue');
      const items = vue.computed(() => parseItems(props.items));
      const {
        densityClasses
      } = useDensity(props);
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.bgColor);
      const {
        scopeId
      } = useScopeId();
      provideDefaults({
        VTab: {
          color: vue.toRef(props, 'color'),
          direction: vue.toRef(props, 'direction'),
          stacked: vue.toRef(props, 'stacked'),
          fixed: vue.toRef(props, 'fixedTabs'),
          inset: vue.toRef(props, 'inset'),
          sliderColor: vue.toRef(props, 'sliderColor'),
          sliderTransition: vue.toRef(props, 'sliderTransition'),
          sliderTransitionDuration: vue.toRef(props, 'sliderTransitionDuration'),
          hideSlider: vue.toRef(props, 'hideSlider')
        }
      });
      useRender(() => {
        const slideGroupProps = VSlideGroup.filterProps(props);
        const hasWindow = !!(slots.window || props.items.length > 0);
        return vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VSlideGroup, vue.mergeProps(slideGroupProps, {
          "modelValue": model.value,
          "onUpdate:modelValue": $event => model.value = $event,
          "class": ['v-tabs', `v-tabs--${props.direction}`, `v-tabs--align-tabs-${props.alignTabs}`, {
            'v-tabs--fixed-tabs': props.fixedTabs,
            'v-tabs--grow': props.grow,
            'v-tabs--inset': props.inset,
            'v-tabs--stacked': props.stacked
          }, densityClasses.value, backgroundColorClasses.value, props.class],
          "style": [{
            '--v-tabs-height': convertToUnit(props.height),
            '--v-tabs-inset-padding': props.inset ? convertToUnit(props.insetPadding) : undefined,
            '--v-tabs-inset-radius': props.inset ? convertToUnit(props.insetRadius) : undefined
          }, backgroundColorStyles.value, props.style],
          "role": "tablist",
          "symbol": VTabsSymbol
        }, scopeId, attrs), {
          default: slots.default ?? (() => items.value.map(item => slots.tab?.({
            item
          }) ?? vue.createVNode(VTab, vue.mergeProps(item, {
            "key": item.text,
            "value": item.value,
            "spaced": props.spaced
          }), {
            default: slots[`tab.${item.value}`] ? () => slots[`tab.${item.value}`]?.({
              item
            }) : undefined
          }))),
          prev: slots.prev,
          next: slots.next
        }), hasWindow && vue.createVNode(VTabsWindow, vue.mergeProps({
          "modelValue": model.value,
          "onUpdate:modelValue": $event => model.value = $event,
          "key": "tabs-window"
        }, scopeId), {
          default: () => [items.value.map(item => slots.item?.({
            item
          }) ?? vue.createVNode(VTabsWindowItem, {
            "value": item.value
          }, {
            default: () => slots[`item.${item.value}`]?.({
              item
            })
          })), slots.window?.()]
        })]);
      });
      return {};
    }
  });

  // Types

  const makeVTextareaProps = propsFactory({
    autoGrow: Boolean,
    autofocus: Boolean,
    counter: [Boolean, Number, String],
    counterValue: Function,
    prefix: String,
    placeholder: String,
    persistentPlaceholder: Boolean,
    persistentCounter: Boolean,
    noResize: Boolean,
    rows: {
      type: [Number, String],
      default: 5,
      validator: v => !isNaN(parseFloat(v))
    },
    maxHeight: {
      type: [Number, String],
      validator: v => !isNaN(parseFloat(v))
    },
    maxRows: {
      type: [Number, String],
      validator: v => !isNaN(parseFloat(v))
    },
    suffix: String,
    modelModifiers: Object,
    ...makeAutocompleteProps(),
    ...omit(makeVInputProps(), ['direction']),
    ...makeVFieldProps()
  }, 'VTextarea');
  const VTextarea = genericComponent()({
    name: 'VTextarea',
    directives: {
      vIntersect: Intersect
    },
    inheritAttrs: false,
    props: makeVTextareaProps(),
    emits: {
      'click:control': e => true,
      'mousedown:control': e => true,
      'update:focused': focused => true,
      'update:modelValue': val => true,
      'update:rows': rows => true
    },
    setup(props, {
      attrs,
      emit,
      slots
    }) {
      const model = useProxiedModel(props, 'modelValue');
      const {
        isFocused,
        focus,
        blur
      } = useFocus(props);
      const {
        onIntersect
      } = useAutofocus(props);
      const counterValue = vue.computed(() => {
        return typeof props.counterValue === 'function' ? props.counterValue(model.value) : (model.value || '').toString().length;
      });
      const max = vue.computed(() => {
        if (attrs.maxlength) return attrs.maxlength;
        if (!props.counter || typeof props.counter !== 'number' && typeof props.counter !== 'string') return undefined;
        return props.counter;
      });
      const vInputRef = vue.ref();
      const vFieldRef = vue.ref();
      const controlHeight = vue.shallowRef('');
      const textareaRef = vue.ref();
      const scrollbarWidth = vue.ref(0);
      const {
        platform
      } = useDisplay();
      const autocomplete = useAutocomplete(props);
      const isActive = vue.computed(() => props.persistentPlaceholder || isFocused.value || props.active);
      function onFocus() {
        if (autocomplete.isSuppressing.value) {
          autocomplete.update();
        }
        if (textareaRef.value !== getActiveElement()) {
          textareaRef.value?.focus();
        }
        if (!isFocused.value) focus();
      }
      function onControlClick(e) {
        onFocus();
        emit('click:control', e);
      }
      function onControlMousedown(e) {
        emit('mousedown:control', e);
      }
      function onClear(e) {
        e.stopPropagation();
        onFocus();
        vue.nextTick(() => {
          model.value = '';
          callEvent(props['onClick:clear'], e);
        });
      }
      function onInput(e) {
        const el = e.target;
        if (!props.modelModifiers?.trim) {
          model.value = el.value;
          return;
        }
        const value = el.value;
        const start = el.selectionStart;
        const end = el.selectionEnd;
        model.value = value;
        vue.nextTick(() => {
          let offset = 0;
          if (value.trimStart().length === el.value.length) {
            // #22307 - Whitespace has been removed from the
            // start, offset the caret position to compensate
            offset = value.length - el.value.length;
          }
          if (start != null) el.selectionStart = start - offset;
          if (end != null) el.selectionEnd = end - offset;
        });
      }
      const sizerRef = vue.ref();
      const rows = vue.ref(Number(props.rows));
      const isPlainOrUnderlined = vue.computed(() => ['plain', 'underlined'].includes(props.variant));
      vue.watchEffect(() => {
        if (!props.autoGrow) rows.value = Number(props.rows);
      });
      function calculateInputHeight() {
        vue.nextTick(() => {
          if (!textareaRef.value) return;
          if (platform.value.firefox) {
            scrollbarWidth.value = 12;
            return;
          }
          const {
            offsetWidth,
            clientWidth
          } = textareaRef.value;
          scrollbarWidth.value = Math.max(0, offsetWidth - clientWidth);
        });
        if (!props.autoGrow) return;
        vue.nextTick(() => {
          if (!sizerRef.value || !vFieldRef.value) return;
          const style = getComputedStyle(sizerRef.value);
          const fieldStyle = getComputedStyle(vFieldRef.value.$el);
          const padding = parseFloat(style.getPropertyValue('--v-field-padding-top')) + parseFloat(style.getPropertyValue('--v-input-padding-top')) + parseFloat(style.getPropertyValue('--v-field-padding-bottom'));
          const height = sizerRef.value.scrollHeight;
          const lineHeight = parseFloat(style.lineHeight);
          const minHeight = Math.max(parseFloat(props.rows) * lineHeight + padding, parseFloat(fieldStyle.getPropertyValue('--v-input-control-height')));
          const maxHeight = props.maxHeight ? parseFloat(props.maxHeight) : parseFloat(props.maxRows) * lineHeight + padding || Infinity;
          const newHeight = clamp(height ?? 0, minHeight, maxHeight);
          rows.value = Math.floor((newHeight - padding) / lineHeight);
          controlHeight.value = convertToUnit(newHeight);
        });
      }
      vue.onMounted(calculateInputHeight);
      vue.watch(model, calculateInputHeight);
      vue.watch(() => props.rows, calculateInputHeight);
      vue.watch(() => props.maxHeight, calculateInputHeight);
      vue.watch(() => props.maxRows, calculateInputHeight);
      vue.watch(() => props.density, calculateInputHeight);
      vue.watch(rows, val => {
        emit('update:rows', val);
      });
      let observer;
      vue.watch(sizerRef, val => {
        if (val) {
          observer = new ResizeObserver(calculateInputHeight);
          observer.observe(sizerRef.value);
        } else {
          observer?.disconnect();
        }
      });
      vue.onBeforeUnmount(() => {
        observer?.disconnect();
      });
      useRender(() => {
        const hasCounter = !!(slots.counter || props.counter || props.counterValue);
        const hasDetails = props.hideDetails !== true && !!(slots.details || hasCounter && (props.persistentCounter || props.hideDetails === false || isFocused.value));
        const [rootAttrs, inputAttrs] = filterInputAttrs(attrs);
        const {
          modelValue: _,
          ...inputProps
        } = VInput.filterProps(props);
        const fieldProps = {
          ...VField.filterProps(props),
          'onClick:clear': onClear
        };
        return vue.createVNode(VInput, vue.mergeProps({
          "ref": vInputRef,
          "modelValue": model.value,
          "onUpdate:modelValue": $event => model.value = $event,
          "class": ['v-textarea v-text-field', {
            'v-textarea--prefixed': props.prefix,
            'v-textarea--suffixed': props.suffix,
            'v-text-field--prefixed': props.prefix,
            'v-text-field--suffixed': props.suffix,
            'v-textarea--auto-grow': props.autoGrow,
            'v-textarea--no-resize': props.noResize || props.autoGrow,
            'v-input--plain-underlined': isPlainOrUnderlined.value
          }, props.class],
          "style": [{
            '--v-textarea-max-height': props.maxHeight ? convertToUnit(props.maxHeight) : undefined,
            '--v-textarea-scroll-bar-width': convertToUnit(scrollbarWidth.value)
          }, props.style]
        }, rootAttrs, inputProps, {
          "centerAffix": rows.value === 1 && !isPlainOrUnderlined.value,
          "focused": isFocused.value,
          "indentDetails": props.indentDetails ?? !isPlainOrUnderlined.value
        }), {
          ...slots,
          default: ({
            id,
            isDisabled,
            isDirty,
            isReadonly,
            isValid,
            hasDetails
          }) => vue.createVNode(VField, vue.mergeProps({
            "ref": vFieldRef,
            "style": {
              '--v-textarea-control-height': controlHeight.value
            },
            "onClick": onControlClick,
            "onMousedown": onControlMousedown,
            "onClick:prependInner": props['onClick:prependInner'],
            "onClick:appendInner": props['onClick:appendInner']
          }, fieldProps, {
            "id": id.value,
            "active": isActive.value || isDirty.value,
            "labelId": `${id.value}-label`,
            "centerAffix": rows.value === 1 && !isPlainOrUnderlined.value,
            "dirty": isDirty.value || props.dirty,
            "disabled": isDisabled.value,
            "focused": isFocused.value,
            "details": hasDetails.value,
            "error": isValid.value === false
          }), {
            ...slots,
            default: ({
              props: {
                class: fieldClass,
                ...slotProps
              },
              controlRef
            }) => vue.createElementVNode(vue.Fragment, null, [props.prefix && vue.createElementVNode("span", {
              "class": "v-text-field__prefix"
            }, [props.prefix]), vue.withDirectives(vue.createElementVNode("textarea", vue.mergeProps({
              "ref": val => textareaRef.value = controlRef.value = val,
              "class": fieldClass,
              "value": model.value,
              "onInput": onInput,
              "autofocus": props.autofocus,
              "readonly": isReadonly.value,
              "disabled": isDisabled.value,
              "placeholder": props.placeholder,
              "rows": props.rows,
              "name": autocomplete.fieldName.value,
              "autocomplete": autocomplete.fieldAutocomplete.value,
              "onFocus": onFocus,
              "onBlur": blur,
              "aria-labelledby": `${id.value}-label`
            }, slotProps, inputAttrs), null), [[Intersect, {
              handler: onIntersect
            }, null, {
              once: true
            }]]), props.autoGrow && vue.withDirectives(vue.createElementVNode("textarea", {
              "class": vue.normalizeClass([fieldClass, 'v-textarea__sizer']),
              "id": `${slotProps.id}-sizer`,
              "onUpdate:modelValue": $event => model.value = $event,
              "ref": sizerRef,
              "readonly": true,
              "aria-hidden": "true"
            }, null), [[vue.vModelText, model.value]]), props.suffix && vue.createElementVNode("span", {
              "class": "v-text-field__suffix"
            }, [props.suffix])])
          }),
          details: hasDetails ? slotProps => vue.createElementVNode(vue.Fragment, null, [slots.details?.(slotProps), hasCounter && vue.createElementVNode(vue.Fragment, null, [vue.createElementVNode("span", null, null), vue.createVNode(VCounter, {
            "active": props.persistentCounter || isFocused.value,
            "value": counterValue.value,
            "max": max.value,
            "disabled": props.disabled
          }, slots.counter)])]) : undefined
        });
      });
      return forwardRefs({}, vInputRef, vFieldRef, textareaRef);
    }
  });

  const makeVThemeProviderProps = propsFactory({
    withBackground: Boolean,
    ...makeComponentProps(),
    ...makeThemeProps(),
    ...makeTagProps()
  }, 'VThemeProvider');
  const VThemeProvider = genericComponent()({
    name: 'VThemeProvider',
    props: makeVThemeProviderProps(),
    setup(props, {
      slots
    }) {
      const {
        themeClasses
      } = provideTheme(props);
      return () => {
        if (!props.withBackground) return slots.default?.();
        return vue.createVNode(props.tag, {
          "class": vue.normalizeClass(['v-theme-provider', themeClasses.value, props.class]),
          "style": vue.normalizeStyle(props.style)
        }, {
          default: () => [slots.default?.()]
        });
      };
    }
  });

  const makeVTimelineDividerProps = propsFactory({
    dotColor: String,
    fillDot: Boolean,
    hideDot: Boolean,
    icon: IconValue,
    iconColor: String,
    lineColor: String,
    ...makeComponentProps(),
    ...makeRoundedProps(),
    ...makeSizeProps(),
    ...makeElevationProps()
  }, 'VTimelineDivider');
  const VTimelineDivider = genericComponent()({
    name: 'VTimelineDivider',
    props: makeVTimelineDividerProps(),
    setup(props, {
      slots
    }) {
      const {
        sizeClasses,
        sizeStyles
      } = useSize(props, 'v-timeline-divider__dot');
      const {
        backgroundColorStyles,
        backgroundColorClasses
      } = useBackgroundColor(() => props.dotColor);
      const {
        roundedClasses,
        roundedStyles
      } = useRounded(props, 'v-timeline-divider__dot');
      const {
        elevationClasses
      } = useElevation(props);
      const {
        backgroundColorClasses: lineColorClasses,
        backgroundColorStyles: lineColorStyles
      } = useBackgroundColor(() => props.lineColor);
      useRender(() => vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-timeline-divider', {
          'v-timeline-divider--fill-dot': props.fillDot
        }, props.class]),
        "style": vue.normalizeStyle(props.style)
      }, [vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-timeline-divider__before', lineColorClasses.value]),
        "style": vue.normalizeStyle(lineColorStyles.value)
      }, null), !props.hideDot && vue.createElementVNode("div", {
        "key": "dot",
        "class": vue.normalizeClass(['v-timeline-divider__dot', elevationClasses.value, roundedClasses.value, sizeClasses.value]),
        "style": vue.normalizeStyle([sizeStyles.value, roundedStyles.value])
      }, [vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-timeline-divider__inner-dot', backgroundColorClasses.value, roundedClasses.value]),
        "style": vue.normalizeStyle([backgroundColorStyles.value, roundedStyles.value])
      }, [!slots.default ? vue.createVNode(VIcon, {
        "key": "icon",
        "color": props.iconColor,
        "icon": props.icon,
        "size": props.size
      }, null) : vue.createVNode(VDefaultsProvider, {
        "key": "icon-defaults",
        "disabled": !props.icon,
        "defaults": {
          VIcon: {
            color: props.iconColor,
            icon: props.icon,
            size: props.size
          }
        }
      }, slots.default)])]), vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-timeline-divider__after', lineColorClasses.value]),
        "style": vue.normalizeStyle(lineColorStyles.value)
      }, null)]));
      return {};
    }
  });

  // Types

  // Types

  const makeVTimelineItemProps = propsFactory({
    density: String,
    dotColor: String,
    fillDot: Boolean,
    hideDot: Boolean,
    hideOpposite: {
      type: Boolean,
      default: undefined
    },
    icon: IconValue,
    iconColor: String,
    lineInset: [Number, String],
    side: {
      type: String,
      validator: v => v == null || ['start', 'end'].includes(v)
    },
    ...makeComponentProps(),
    ...makeDimensionProps(),
    ...makeElevationProps(),
    ...makeRoundedProps(),
    ...makeSizeProps(),
    ...makeTagProps()
  }, 'VTimelineItem');
  const VTimelineItem = genericComponent()({
    name: 'VTimelineItem',
    props: makeVTimelineItemProps(),
    setup(props, {
      slots
    }) {
      const {
        dimensionStyles
      } = useDimension(props);
      const dotSize = vue.shallowRef(0);
      const dotRef = vue.ref();
      vue.watch(dotRef, newValue => {
        if (!newValue) return;
        dotSize.value = newValue.$el.querySelector('.v-timeline-divider__dot')?.getBoundingClientRect().width ?? 0;
      }, {
        flush: 'post'
      });
      useRender(() => vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-timeline-item', {
          'v-timeline-item--fill-dot': props.fillDot,
          'v-timeline-item--side-start': props.side === 'start',
          'v-timeline-item--side-end': props.side === 'end'
        }, props.class]),
        "style": vue.normalizeStyle([{
          '--v-timeline-dot-size': convertToUnit(dotSize.value),
          '--v-timeline-line-inset': props.lineInset ? `calc(var(--v-timeline-dot-size) / 2 + ${convertToUnit(props.lineInset)})` : convertToUnit(0)
        }, props.style])
      }, [vue.createElementVNode("div", {
        "class": "v-timeline-item__body",
        "style": vue.normalizeStyle(dimensionStyles.value)
      }, [slots.default?.()]), vue.createVNode(VTimelineDivider, {
        "ref": dotRef,
        "hideDot": props.hideDot,
        "icon": props.icon,
        "iconColor": props.iconColor,
        "size": props.size,
        "elevation": props.elevation,
        "dotColor": props.dotColor,
        "fillDot": props.fillDot,
        "rounded": props.rounded
      }, {
        default: slots.icon
      }), props.density !== 'compact' && vue.createElementVNode("div", {
        "class": "v-timeline-item__opposite"
      }, [!props.hideOpposite && slots.opposite?.()])]));
      return {};
    }
  });

  const makeVTimelineProps = propsFactory({
    align: {
      type: String,
      default: 'center',
      validator: v => ['center', 'start'].includes(v)
    },
    direction: {
      type: String,
      default: 'vertical',
      validator: v => ['vertical', 'horizontal'].includes(v)
    },
    justify: {
      type: String,
      default: 'auto',
      validator: v => ['auto', 'center'].includes(v)
    },
    side: {
      type: String,
      validator: v => v == null || ['start', 'end'].includes(v)
    },
    lineThickness: {
      type: [String, Number],
      default: 2
    },
    lineColor: String,
    truncateLine: {
      type: String,
      validator: v => ['start', 'end', 'both'].includes(v)
    },
    ...pick(makeVTimelineItemProps({
      lineInset: 0
    }), ['dotColor', 'fillDot', 'hideOpposite', 'iconColor', 'lineInset', 'size']),
    ...makeComponentProps(),
    ...makeDensityProps(),
    ...makeTagProps(),
    ...makeThemeProps()
  }, 'VTimeline');
  const VTimeline = genericComponent()({
    name: 'VTimeline',
    props: makeVTimelineProps(),
    setup(props, {
      slots
    }) {
      const {
        themeClasses
      } = provideTheme(props);
      const {
        densityClasses
      } = useDensity(props);
      const {
        rtlClasses
      } = useRtl();
      provideDefaults({
        VTimelineDivider: {
          lineColor: vue.toRef(() => props.lineColor)
        },
        VTimelineItem: {
          density: vue.toRef(() => props.density),
          dotColor: vue.toRef(() => props.dotColor),
          fillDot: vue.toRef(() => props.fillDot),
          hideOpposite: vue.toRef(() => props.hideOpposite),
          iconColor: vue.toRef(() => props.iconColor),
          lineColor: vue.toRef(() => props.lineColor),
          lineInset: vue.toRef(() => props.lineInset),
          size: vue.toRef(() => props.size)
        }
      });
      const sideClasses = vue.computed(() => {
        const side = props.side ? props.side : props.density !== 'default' ? 'end' : null;
        return side && `v-timeline--side-${side}`;
      });
      const truncateClasses = vue.computed(() => {
        const classes = ['v-timeline--truncate-line-start', 'v-timeline--truncate-line-end'];
        switch (props.truncateLine) {
          case 'both':
            return classes;
          case 'start':
            return classes[0];
          case 'end':
            return classes[1];
          default:
            return null;
        }
      });
      useRender(() => vue.createVNode(props.tag, {
        "class": vue.normalizeClass(['v-timeline', `v-timeline--${props.direction}`, `v-timeline--align-${props.align}`, `v-timeline--justify-${props.justify}`, truncateClasses.value, {
          'v-timeline--inset-line': !!props.lineInset
        }, themeClasses.value, densityClasses.value, sideClasses.value, rtlClasses.value, props.class]),
        "style": vue.normalizeStyle([{
          '--v-timeline-line-thickness': convertToUnit(props.lineThickness)
        }, props.style])
      }, slots));
      return {};
    }
  });

  // Types

  const makeVTimePickerClockProps = propsFactory({
    allowedValues: Function,
    ampm: Boolean,
    color: String,
    disabled: Boolean,
    displayedValue: null,
    double: Boolean,
    format: {
      type: Function,
      default: val => val
    },
    max: {
      type: Number,
      required: true
    },
    min: {
      type: Number,
      required: true
    },
    scrollable: Boolean,
    readonly: Boolean,
    rotate: {
      type: Number,
      default: 0
    },
    step: {
      type: Number,
      default: 1
    },
    modelValue: {
      type: Number
    }
  }, 'VTimePickerClock');
  const VTimePickerClock = genericComponent()({
    name: 'VTimePickerClock',
    props: makeVTimePickerClockProps(),
    emits: {
      change: val => true,
      input: val => true
    },
    setup(props, {
      emit
    }) {
      const clockRef = vue.ref(null);
      const innerClockRef = vue.ref(null);
      const inputValue = vue.ref(undefined);
      const isDragging = vue.ref(false);
      const valueOnMouseDown = vue.ref(null);
      const valueOnMouseUp = vue.ref(null);
      const emitChangeDebounced = debounce(value => emit('change', value), 750);
      const {
        textColorClasses,
        textColorStyles
      } = useTextColor(() => props.color);
      const {
        backgroundColorClasses,
        backgroundColorStyles
      } = useBackgroundColor(() => props.color);
      const count = vue.computed(() => props.max - props.min + 1);
      const roundCount = vue.computed(() => props.double ? count.value / 2 : count.value);
      const degreesPerUnit = vue.computed(() => 360 / roundCount.value);
      const degrees = vue.computed(() => degreesPerUnit.value * Math.PI / 180);
      const displayedValue = vue.computed(() => props.modelValue == null ? props.min : props.modelValue);
      const innerRadiusScale = vue.computed(() => 0.62);
      const genChildren = vue.computed(() => {
        const children = [];
        for (let value = props.min; value <= props.max; value = value + props.step) {
          children.push(value);
        }
        return children;
      });
      vue.watch(() => props.modelValue, val => {
        inputValue.value = val;
      });
      function update(value) {
        if (inputValue.value !== value) {
          inputValue.value = value;
        }
        emit('input', value);
      }
      function isAllowed(value) {
        return !props.allowedValues || props.allowedValues(value);
      }
      function wheel(e) {
        if (!props.scrollable || props.disabled) return;
        e.preventDefault();
        const delta = Math.sign(-e.deltaY || 1);
        let value = displayedValue.value;
        do {
          value = value + delta;
          value = (value - props.min + count.value) % count.value + props.min;
        } while (!isAllowed(value) && value !== displayedValue.value);
        if (value !== props.displayedValue) {
          update(value);
        }
        emitChangeDebounced(value);
      }
      function isInner(value) {
        return props.double && value - props.min >= roundCount.value;
      }
      function handScale(value) {
        return isInner(value) ? innerRadiusScale.value : 1;
      }
      function getPosition(value) {
        const rotateRadians = props.rotate * Math.PI / 180;
        return {
          x: Math.sin((value - props.min) * degrees.value + rotateRadians) * handScale(value),
          y: -Math.cos((value - props.min) * degrees.value + rotateRadians) * handScale(value)
        };
      }
      function angleToValue(angle, insideClick) {
        const value = (Math.round(angle / degreesPerUnit.value) + (insideClick ? roundCount.value : 0)) % count.value + props.min;

        // Necessary to fix edge case when selecting left part of the value(s) at 12 o'clock
        if (angle < 360 - degreesPerUnit.value / 2) return value;
        return insideClick ? props.max - roundCount.value + 1 : props.min;
      }
      function getTransform(i) {
        const {
          x,
          y
        } = getPosition(i);
        return {
          left: `${Math.round(50 + x * 50)}%`,
          top: `${Math.round(50 + y * 50)}%`
        };
      }
      function euclidean(p0, p1) {
        const dx = p1.x - p0.x;
        const dy = p1.y - p0.y;
        return Math.sqrt(dx * dx + dy * dy);
      }
      function angle(center, p1) {
        const value = 2 * Math.atan2(p1.y - center.y - euclidean(center, p1), p1.x - center.x);
        return Math.abs(value * 180 / Math.PI);
      }
      function setMouseDownValue(value) {
        if (valueOnMouseDown.value === null) {
          valueOnMouseDown.value = value;
        }
        valueOnMouseUp.value = value;
        update(value);
      }
      function onDragMove(e) {
        e.preventDefault();
        if (!isDragging.value && e.type !== 'click' || !clockRef.value) return;
        const {
          width,
          top,
          left
        } = clockRef.value?.getBoundingClientRect();
        const {
          width: innerWidth
        } = innerClockRef.value?.getBoundingClientRect() ?? {
          width: 0
        };
        const {
          clientX,
          clientY
        } = 'touches' in e ? e.touches[0] : e;
        const center = {
          x: width / 2,
          y: -width / 2
        };
        const coords = {
          x: clientX - left,
          y: top - clientY
        };
        const handAngle = Math.round(angle(center, coords) - props.rotate + 360) % 360;
        const insideClick = props.double && euclidean(center, coords) < (innerWidth + innerWidth * innerRadiusScale.value) / 4;
        const checksCount = Math.ceil(15 / degreesPerUnit.value);
        let value;
        for (let i = 0; i < checksCount; i++) {
          value = angleToValue(handAngle + i * degreesPerUnit.value, insideClick);
          if (isAllowed(value)) return setMouseDownValue(value);
          value = angleToValue(handAngle - i * degreesPerUnit.value, insideClick);
          if (isAllowed(value)) return setMouseDownValue(value);
        }
      }
      function onMouseDown(e) {
        if (props.disabled) return;
        e.preventDefault();
        window.addEventListener('mousemove', onDragMove);
        window.addEventListener('touchmove', onDragMove);
        window.addEventListener('mouseup', onMouseUp);
        window.addEventListener('touchend', onMouseUp);
        valueOnMouseDown.value = null;
        valueOnMouseUp.value = null;
        isDragging.value = true;
        onDragMove(e);
      }
      function onMouseUp(e) {
        e.stopPropagation();
        removeListeners();
        isDragging.value = false;
        if (valueOnMouseUp.value !== null && isAllowed(valueOnMouseUp.value)) {
          emit('change', valueOnMouseUp.value);
        }
      }
      function removeListeners() {
        if (!IN_BROWSER) return;
        window.removeEventListener('mousemove', onDragMove);
        window.removeEventListener('touchmove', onDragMove);
        window.removeEventListener('mouseup', onMouseUp);
        window.removeEventListener('touchend', onMouseUp);
      }
      vue.onScopeDispose(removeListeners);
      useRender(() => {
        return vue.createElementVNode("div", {
          "class": vue.normalizeClass([{
            'v-time-picker-clock': true,
            'v-time-picker-clock--indeterminate': props.modelValue == null,
            'v-time-picker-clock--readonly': props.readonly
          }]),
          "onMousedown": onMouseDown,
          "onTouchstart": onMouseDown,
          "onWheel": wheel,
          "ref": clockRef
        }, [vue.createElementVNode("div", {
          "class": "v-time-picker-clock__inner",
          "ref": innerClockRef
        }, [vue.createElementVNode("div", {
          "class": vue.normalizeClass([{
            'v-time-picker-clock__hand': true,
            'v-time-picker-clock__hand--inner': isInner(props.modelValue)
          }, textColorClasses.value]),
          "style": vue.normalizeStyle([{
            transform: `rotate(${props.rotate + degreesPerUnit.value * (displayedValue.value - props.min)}deg) scaleY(${handScale(displayedValue.value)})`
          }, textColorStyles.value])
        }, null), genChildren.value.map(value => {
          const isActive = value === displayedValue.value;
          return vue.createElementVNode("div", {
            "class": vue.normalizeClass([{
              'v-time-picker-clock__item': true,
              'v-time-picker-clock__item--active': isActive,
              'v-time-picker-clock__item--disabled': props.disabled || !isAllowed(value)
            }, isActive && backgroundColorClasses.value]),
            "style": vue.normalizeStyle([getTransform(value), isActive && backgroundColorStyles.value])
          }, [vue.createElementVNode("span", null, [props.format(value)])]);
        })])]);
      });
    }
  });

  // Types

  const makeVTimePickerFieldProps = propsFactory({
    active: Boolean,
    color: String,
    disabled: Boolean,
    label: String,
    modelValue: String,
    error: String,
    showHint: Boolean,
    readonly: Boolean
  }, 'VTimePickerField');
  const VTimePickerField = genericComponent()({
    name: 'VTimePickerField',
    props: makeVTimePickerFieldProps(),
    emits: {
      'update:modelValue': v => true
    },
    setup(props, {
      emit
    }) {
      const {
        textColorClasses,
        textColorStyles
      } = useTextColor(() => props.color);
      const vTextInputRef = vue.ref();
      const isFocused = vue.shallowRef(false);
      function onKeydown(e) {
        if (['Backspace', 'Delete'].includes(e.key)) {
          e.preventDefault();
          const target = e.target;
          target.value = '';
          emit('update:modelValue', null);
        }
      }
      useRender(() => {
        return vue.createVNode(VTextField, {
          "ref": vTextInputRef,
          "_as": "VTimePickerField",
          "autocomplete": "off",
          "class": vue.normalizeClass(['v-time-picker-controls__time__field', {
            'v-time-picker-controls__time__field--active': props.active
          }, props.active ? textColorClasses.value : []]),
          "style": vue.normalizeStyle(props.active ? textColorStyles.value : []),
          "disabled": props.disabled,
          "variant": "solo-filled",
          "inputmode": "numeric",
          "hideDetails": "auto",
          "aria-label": props.label,
          "aria-invalid": !!props.error,
          "aria-errormessage": props.error,
          "error": !!props.error,
          "hint": props.showHint ? props.label : undefined,
          "persistentHint": true,
          "flat": true,
          "modelValue": props.modelValue ?? (isFocused.value ? '' : '--'),
          "onUpdate:modelValue": v => emit('update:modelValue', v),
          "onKeydown": onKeydown,
          "onFocus": () => isFocused.value = true,
          "onBlur": () => isFocused.value = false
        }, null);
      });
      return forwardRefs({}, vTextInputRef);
    }
  });

  // Types

  function pad(n, length = 2) {
    return String(n).padStart(length, '0');
  }
  function convert24to12(hour) {
    return hour ? (hour - 1) % 12 + 1 : 12;
  }
  function convert12to24(hour, period) {
    return hour % 12 + (period === 'pm' ? 12 : 0);
  }
  function extractInteger(v) {
    const digits = v.replaceAll(/\D/g, '');
    return digits.length > 0 ? Number(digits) : null;
  }
  function incrementHour(hour, increment, period) {
    {
      if (hour === 23 && increment) {
        return {
          value: 0
        };
      }
      if (hour === 0 && !increment) {
        return {
          value: 23
        };
      }
    }
    return {
      value: hour + (increment ? 1 : -1)
    };
  }
  function incrementMinuteOrSecond(val, increment) {
    if (val === 59 && increment) return 0;
    if (val === 0 && !increment) return 59;
    return val + (increment ? 1 : -1);
  }

  // Utilities

  // Types

  const makeTimeValidationProps = propsFactory({
    allowedHours: [Function, Array],
    allowedMinutes: [Function, Array],
    allowedSeconds: [Function, Array],
    max: String,
    min: String
  }, 'time-validation');
  function useTimeValidation(props) {
    const isAllowedHour = vue.computed(() => {
      const minHour = props.min ? Number(props.min.split(':')[0]) : 0;
      const maxHour = props.max ? Number(props.max.split(':')[0]) : 23;
      return val => {
        if (val < minHour) return false;
        if (val > maxHour) return false;
        if (Array.isArray(props.allowedHours)) return props.allowedHours.includes(val);
        if (typeof props.allowedHours === 'function') return props.allowedHours(val);
        return true;
      };
    });
    const isAllowedMinute = vue.computed(() => {
      const [minHour, minMinute] = props.min ? props.min.split(':').map(Number) : [0, 0];
      const [maxHour, maxMinute] = props.max ? props.max.split(':').map(Number) : [23, 59];
      const minTime = minHour * 60 + minMinute;
      const maxTime = maxHour * 60 + maxMinute;
      return (hour24hr, val) => {
        if (hour24hr !== null) {
          const time = 60 * hour24hr + val;
          if (time < minTime) return false;
          if (time > maxTime) return false;
        }
        if (Array.isArray(props.allowedMinutes)) return props.allowedMinutes.includes(val);
        if (typeof props.allowedMinutes === 'function') return props.allowedMinutes(val);
        return true;
      };
    });
    const isAllowedSecond = vue.computed(() => {
      const [minHour, minMinute, minSecond] = props.min ? props.min.split(':').map(Number) : [0, 0, 0];
      const [maxHour, maxMinute, maxSecond] = props.max ? props.max.split(':').map(Number) : [23, 59, 59];
      const minTime = minHour * 3600 + minMinute * 60 + (minSecond || 0);
      const maxTime = maxHour * 3600 + maxMinute * 60 + (maxSecond || 0);
      return (hour24hr, minute, val) => {
        if (hour24hr !== null && minute !== null) {
          const time = 3600 * hour24hr + 60 * minute + val;
          if (time < minTime) return false;
          if (time > maxTime) return false;
        }
        if (Array.isArray(props.allowedSeconds)) return props.allowedSeconds.includes(val);
        if (typeof props.allowedSeconds === 'function') return props.allowedSeconds(val);
        return true;
      };
    });
    function findNextAllowed(type, value, increment, currentHour = null, currentMinute = null) {
      const isAllowed = type === 'hour' ? isAllowedHour.value : type === 'minute' ? v => isAllowedMinute.value(currentHour, v) : v => isAllowedSecond.value(currentHour, currentMinute, v);
      const nextValue = type === 'hour' ? v => incrementHour(v, increment).value : v => incrementMinuteOrSecond(v, increment);
      const limit = type === 'hour' ? 24 : 60;
      for (let i = 1; i <= limit; i++) {
        value = nextValue(value);
        if (isAllowed(value)) break;
      }
      return value;
    }
    return {
      isAllowedHour,
      isAllowedMinute,
      isAllowedSecond,
      findNextAllowed
    };
  }

  // Types

  const makeVTimePickerControlsProps = propsFactory({
    ampm: Boolean,
    color: String,
    disabled: Boolean,
    inputHints: Boolean,
    hour: [Number, String],
    minute: [Number, String],
    second: [Number, String],
    period: String,
    readonly: Boolean,
    useSeconds: Boolean,
    value: Number,
    viewMode: String,
    ...makeTimeValidationProps()
  }, 'VTimePickerControls');
  const VTimePickerControls = genericComponent()({
    name: 'VTimePickerControls',
    props: makeVTimePickerControlsProps(),
    emits: {
      'update:period': data => true,
      'update:viewMode': data => true,
      'update:hour': v => true,
      'update:minute': v => true,
      'update:second': v => true
    },
    setup(props, {
      emit
    }) {
      const {
        t
      } = useLocale();
      const {
        isAllowedHour,
        isAllowedMinute,
        isAllowedSecond,
        findNextAllowed
      } = useTimeValidation(props);
      const currentHour = vue.computed(() => props.hour !== null ? props.ampm ? convert12to24(Number(props.hour), props.period ?? 'am') : Number(props.hour) : null);
      const currentMinute = vue.computed(() => props.minute !== null ? Number(props.minute) : null);
      const isHourValid = vue.computed(() => {
        if (props.hour === null) return true;
        return isAllowedHour.value?.(Number(currentHour.value)) ?? true;
      });
      const isMinuteValid = vue.computed(() => {
        if (props.minute === null) return true;
        return isAllowedMinute.value?.(currentHour.value, Number(props.minute)) ?? true;
      });
      const isSecondValid = vue.computed(() => {
        if (props.second === null) return true;
        return isAllowedSecond.value?.(currentHour.value, currentMinute.value, Number(props.second)) ?? true;
      });
      const transformHours = {
        in: v => {
          if (v == null || isNaN(Number(v))) return null;
          const val = Number(v);
          return props.ampm ? pad(convert24to12(val)) : pad(val);
        },
        out: v => {
          if (isNaN(Number(v)) || v == null || v === '') return null;
          const val = typeof v === 'string' ? extractInteger(v) : Number(v);
          if (val === null) return null;
          return props.ampm ? convert12to24(val, props.period ?? 'am') : clamp(val, 0, 23);
        }
      };
      const hour = useProxiedModel(props, 'hour', undefined, transformHours.in, transformHours.out);
      const transformMinutesOrSeconds = {
        in: v => v != null && !isNaN(Number(v)) ? pad(`${v}`) : null,
        out: v => {
          if (isNaN(Number(v)) || v == null || v === '') return null;
          const val = typeof v === 'string' ? extractInteger(v) : Number(v);
          return val !== null ? clamp(val, 0, 59) : null;
        }
      };
      const minute = useProxiedModel(props, 'minute', undefined, transformMinutesOrSeconds.in, transformMinutesOrSeconds.out);
      const second = useProxiedModel(props, 'second', undefined, transformMinutesOrSeconds.in, transformMinutesOrSeconds.out);
      function onHourFieldKeydown(e) {
        if (!['ArrowUp', 'ArrowDown'].includes(e.key)) return;
        e.preventDefault();
        e.stopPropagation();
        const isAm = props.period === 'am';
        const current = props.ampm ? convert12to24(Number(hour.value ?? 0), isAm ? 'am' : 'pm') : Number(hour.value ?? 0);
        const next = findNextAllowed('hour', current, e.key === 'ArrowUp');
        const togglePeriod = isAm && next >= 12 || !isAm && next < 12;
        if (props.ampm && togglePeriod) {
          emit('update:period', props.period === 'am' ? 'pm' : 'am');
          vue.nextTick(() => hour.value = pad(next));
        } else {
          hour.value = pad(next);
        }
      }
      function onMinuteFieldKeydown(e) {
        if (!['ArrowUp', 'ArrowDown'].includes(e.key)) return;
        e.preventDefault();
        e.stopPropagation();
        const current = Number(minute.value ?? 0);
        const next = findNextAllowed('minute', current, e.key === 'ArrowUp', currentHour.value);
        minute.value = pad(next);
      }
      function onSecondFieldKeydown(e) {
        if (!['ArrowUp', 'ArrowDown'].includes(e.key)) return;
        e.preventDefault();
        e.stopPropagation();
        const current = Number(second.value ?? 0);
        const next = findNextAllowed('second', current, e.key === 'ArrowUp', currentHour.value, currentMinute.value);
        second.value = pad(next);
      }
      function createInputInterceptor(valueTransformOut, compare, apply) {
        return e => {
          if (!e.data) return;
          const inputElement = e.target;
          const {
            value: existingTxt,
            selectionStart,
            selectionEnd
          } = inputElement ?? {};
          if (extractInteger(e.data) === null) {
            e.preventDefault();
            return;
          }
          const potentialNewInputVal = existingTxt ? existingTxt.slice(0, selectionStart) + e.data + existingTxt.slice(selectionEnd) : e.data;
          if (potentialNewInputVal.length > 2) {
            if (selectionStart === selectionEnd && selectionEnd === 0 && e.data.trim().startsWith('0')) {
              e.preventDefault();
              inputElement.value = potentialNewInputVal.trim().substring(0, 2);
              apply(inputElement.value);
              if (e.data.trim().length === 1) {
                inputElement.setSelectionRange(1, 1);
              }
              return;
            }
            if (selectionStart === selectionEnd && selectionEnd === 1 && existingTxt.startsWith('0')) {
              e.preventDefault();
              inputElement.value = potentialNewInputVal.trim().substring(0, 2);
              apply(inputElement.value);
              return;
            }
            const maxValue = props.viewMode === 'hour' ? props.ampm ? 12 : 23 : 59;
            const value = extractInteger(potentialNewInputVal);
            if (value > maxValue) {
              e.preventDefault();
              inputElement.value = pad(String(extractInteger(e.data)).substring(0, 2));
              apply(inputElement.value);
              return;
            }
          }
          const potentialNewNumber = valueTransformOut(potentialNewInputVal);
          if (compare(potentialNewNumber)) {
            // ignore input when results in the same number
            // prevents typing more digits
            e.preventDefault();
          }
        };
      }
      function setPeriod(val) {
        emit('update:period', val);
      }
      const hourInputRef = vue.ref();
      const minuteInputRef = vue.ref();
      const secondInputRef = vue.ref();
      vue.watch(() => props.viewMode, (_, old) => {
        switch (old) {
          case 'hour':
            hourInputRef.value.blur();
            break;
          case 'minute':
            minuteInputRef.value.blur();
            break;
          case 'second':
            secondInputRef.value.blur();
            break;
        }
      });
      const hourInputFilter = createInputInterceptor(transformHours.out, v => transformHours.in(v) === hour.value, v => hour.value = v);
      const minuteInputFilter = createInputInterceptor(transformMinutesOrSeconds.out, v => transformMinutesOrSeconds.in(v) === minute.value, v => minute.value = v);
      const secondInputFilter = createInputInterceptor(transformMinutesOrSeconds.out, v => transformMinutesOrSeconds.in(v) === second.value, v => second.value = v);
      useRender(() => {
        return vue.createElementVNode("div", {
          "class": "v-time-picker-controls"
        }, [vue.createElementVNode("div", {
          "class": vue.normalizeClass({
            'v-time-picker-controls__time': true,
            'v-time-picker-controls__time--with-ampm': props.ampm,
            'v-time-picker-controls__time--with-seconds': props.useSeconds
          })
        }, [vue.createVNode(VTimePickerField, {
          "ref": hourInputRef,
          "active": props.viewMode === 'hour',
          "color": props.color,
          "disabled": props.disabled,
          "label": t('$vuetify.timePicker.hour'),
          "showHint": props.inputHints,
          "error": isHourValid.value ? undefined : t('$vuetify.timePicker.notAllowed'),
          "modelValue": hour.value,
          "onUpdate:modelValue": v => hour.value = v,
          "onKeydown": onHourFieldKeydown,
          "onBeforeinput": hourInputFilter,
          "onFocus": () => emit('update:viewMode', 'hour')
        }, null), vue.createElementVNode("span", {
          "class": "v-time-picker-controls__time__separator"
        }, [vue.createTextVNode(":")]), vue.createVNode(VTimePickerField, {
          "ref": minuteInputRef,
          "active": props.viewMode === 'minute',
          "color": props.color,
          "disabled": props.disabled,
          "label": t('$vuetify.timePicker.minute'),
          "showHint": props.inputHints,
          "error": isMinuteValid.value ? undefined : t('$vuetify.timePicker.notAllowed'),
          "modelValue": minute.value,
          "onUpdate:modelValue": v => minute.value = v,
          "onKeydown": onMinuteFieldKeydown,
          "onBeforeinput": minuteInputFilter,
          "onFocus": () => emit('update:viewMode', 'minute')
        }, null), props.useSeconds && vue.createElementVNode("span", {
          "key": "secondsDivider",
          "class": "v-time-picker-controls__time__separator"
        }, [vue.createTextVNode(":")]), props.useSeconds && vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VTimePickerField, {
          "key": "secondsVal",
          "ref": secondInputRef,
          "active": props.viewMode === 'second',
          "color": props.color,
          "disabled": props.disabled,
          "label": t('$vuetify.timePicker.second'),
          "showHint": props.inputHints,
          "error": isSecondValid.value ? undefined : t('$vuetify.timePicker.notAllowed'),
          "modelValue": second.value,
          "onUpdate:modelValue": v => second.value = v,
          "onKeydown": onSecondFieldKeydown,
          "onBeforeinput": secondInputFilter,
          "onFocus": () => emit('update:viewMode', 'second')
        }, null)]), props.ampm && vue.createElementVNode("div", {
          "class": "v-time-picker-controls__ampm"
        }, [vue.createVNode(VBtn, {
          "active": props.period === 'am',
          "color": props.period === 'am' ? props.color : undefined,
          "class": vue.normalizeClass({
            'v-time-picker-controls__ampm__am': true,
            'v-time-picker-controls__ampm__btn': true,
            'v-time-picker-controls__ampm__btn__active': props.period === 'am'
          }),
          "disabled": props.disabled,
          "text": t('$vuetify.timePicker.am'),
          "variant": props.disabled && props.period === 'am' ? 'elevated' : 'tonal',
          "onClick": () => props.period !== 'am' ? setPeriod('am') : null
        }, null), vue.createVNode(VBtn, {
          "active": props.period === 'pm',
          "color": props.period === 'pm' ? props.color : undefined,
          "class": vue.normalizeClass({
            'v-time-picker-controls__ampm__pm': true,
            'v-time-picker-controls__ampm__btn': true,
            'v-time-picker-controls__ampm__btn__active': props.period === 'pm'
          }),
          "disabled": props.disabled,
          "text": t('$vuetify.timePicker.pm'),
          "variant": props.disabled && props.period === 'pm' ? 'elevated' : 'tonal',
          "onClick": () => props.period !== 'pm' ? setPeriod('pm') : null
        }, null)])])]);
      });
      return {};
    }
  });

  // Types

  const makeVTimePickerProps = propsFactory({
    disabled: Boolean,
    format: {
      type: String,
      default: 'ampm'
    },
    viewMode: {
      type: String,
      default: 'hour'
    },
    period: {
      type: String,
      default: 'am',
      validator: v => ['am', 'pm'].includes(v)
    },
    modelValue: null,
    readonly: Boolean,
    scrollable: Boolean,
    useSeconds: Boolean,
    variant: {
      type: String,
      default: 'dial'
    },
    ...makeTimeValidationProps(),
    ...omit(makeVPickerProps({
      title: '$vuetify.timePicker.title'
    }), ['landscape']),
    ...makeDensityProps()
  }, 'VTimePicker');
  const VTimePicker = genericComponent()({
    name: 'VTimePicker',
    props: makeVTimePickerProps(),
    emits: {
      'update:hour': val => true,
      'update:minute': val => true,
      'update:period': val => true,
      'update:second': val => true,
      'update:modelValue': val => true,
      'update:viewMode': val => true
    },
    setup(props, {
      emit,
      slots
    }) {
      const {
        t
      } = useLocale();
      const {
        densityClasses
      } = useDensity(props);
      const inputHour = vue.ref(null);
      const inputMinute = vue.ref(null);
      const inputSecond = vue.ref(null);
      const lazyInputHour = vue.ref(null);
      const lazyInputMinute = vue.ref(null);
      const lazyInputSecond = vue.ref(null);
      const period = useProxiedModel(props, 'period', 'am');
      const viewMode = useProxiedModel(props, 'viewMode', 'hour');
      const controlsRef = vue.ref(null);
      const clockRef = vue.ref(null);
      const isAmPm = vue.computed(() => {
        return props.format === 'ampm';
      });
      const {
        isAllowedHour,
        isAllowedMinute,
        isAllowedSecond
      } = useTimeValidation(props);
      const shouldClear = vue.toRef(() => {
        return props.modelValue !== null && inputHour.value === null && inputMinute.value === null && (!props.useSeconds || inputSecond.value === null);
      });
      function emitValue() {
        const value = genValue();
        if (value !== null && value !== props.modelValue) {
          emit('update:modelValue', value);
        }
        if (shouldClear.value) {
          emit('update:modelValue', null);
        }
      }
      vue.watch(inputHour, emitValue);
      vue.watch(inputMinute, emitValue);
      vue.watch(inputSecond, emitValue);
      vue.watch(period, (newPeriod, oldPeriod) => {
        if (inputHour.value == null || newPeriod === oldPeriod) return;
        if (newPeriod === 'pm' && inputHour.value < 12) {
          inputHour.value = inputHour.value + 12;
        } else if (newPeriod === 'am' && inputHour.value >= 12) {
          inputHour.value = inputHour.value - 12;
        }
      });
      vue.watch(() => props.modelValue, val => setInputData(val));
      vue.watch(() => props.useSeconds, (val, old) => {
        if (old && !val && viewMode.value === 'second') {
          viewMode.value = 'minute';
        }
        if (!val && inputSecond.value !== null) {
          inputSecond.value = null;
        }
      });
      vue.onMounted(() => {
        setInputData(props.modelValue);
      });
      function genValue() {
        if (inputHour.value != null && inputMinute.value != null && (!props.useSeconds || inputSecond.value != null)) {
          return `${pad(inputHour.value)}:${pad(inputMinute.value)}` + (props.useSeconds ? `:${pad(inputSecond.value)}` : '');
        }
        return null;
      }
      function setInputData(value) {
        if (value == null || value === '') {
          inputHour.value = null;
          inputMinute.value = null;
          inputSecond.value = null;
        } else if (value instanceof Date) {
          inputHour.value = value.getHours();
          inputMinute.value = value.getMinutes();
          inputSecond.value = value.getSeconds();
        } else {
          const [hour,, minute,, second, period] = value.trim().toLowerCase().match(/^(\d+):(\d+)(:(\d+))?([ap]m)?$/) || new Array(6);
          inputHour.value = period ? convert12to24(parseInt(hour, 10), period) : parseInt(hour, 10);
          inputMinute.value = parseInt(minute, 10);
          inputSecond.value = parseInt(second || 0, 10);
        }
        period.value = inputHour.value == null || inputHour.value < 12 ? 'am' : 'pm';
      }
      function onInput(value) {
        if (viewMode.value === 'hour') {
          inputHour.value = isAmPm.value ? convert12to24(value, period.value) : value;
        } else if (viewMode.value === 'minute') {
          inputMinute.value = value;
        } else {
          inputSecond.value = value;
        }
      }
      function onChange(value) {
        switch (viewMode.value || 'hour') {
          case 'hour':
            emit('update:hour', value);
            break;
          case 'minute':
            emit('update:minute', value);
            break;
          case 'second':
            emit('update:second', value);
            break;
        }
        const emitChange = inputHour.value !== null && inputMinute.value !== null && (props.useSeconds ? inputSecond.value !== null : true);
        if (viewMode.value === 'hour') {
          viewMode.value = 'minute';
        } else if (props.useSeconds && viewMode.value === 'minute') {
          viewMode.value = 'second';
        }
        if (inputHour.value === lazyInputHour.value && inputMinute.value === lazyInputMinute.value && (!props.useSeconds || inputSecond.value === lazyInputSecond.value)) return;
        const time = genValue();
        if (time === null) return;
        lazyInputHour.value = inputHour.value;
        lazyInputMinute.value = inputMinute.value;
        props.useSeconds && (lazyInputSecond.value = inputSecond.value);
        emitChange && emitValue();
      }
      useRender(() => {
        const pickerProps = omit(VPicker.filterProps(props), ['hideHeader']);
        const timePickerControlsProps = VTimePickerControls.filterProps(props);
        const timePickerClockProps = VTimePickerClock.filterProps(omit(props, ['format', 'modelValue', 'min', 'max']));
        const clockValidation = viewMode.value === 'hour' ? isAllowedHour.value : viewMode.value === 'minute' ? v => isAllowedMinute.value(inputHour.value, v) : v => isAllowedSecond.value(inputHour.value, inputMinute.value, v);
        return vue.createVNode(VPicker, vue.mergeProps(pickerProps, {
          "color": undefined,
          "class": ['v-time-picker', `v-time-picker--variant-${props.variant}`, props.class, densityClasses.value],
          "hideHeader": props.hideHeader && props.variant !== 'input',
          "style": props.style
        }), {
          title: () => slots.title?.() ?? vue.createElementVNode("div", {
            "class": "v-time-picker__title"
          }, [t(props.title)]),
          header: () => vue.createVNode(VTimePickerControls, vue.mergeProps(timePickerControlsProps, {
            "ampm": isAmPm.value,
            "hour": inputHour.value,
            "minute": inputMinute.value,
            "period": period.value,
            "second": inputSecond.value,
            "viewMode": viewMode.value,
            "inputHints": props.variant === 'input',
            "onUpdate:hour": val => inputHour.value = val,
            "onUpdate:minute": val => inputMinute.value = val,
            "onUpdate:second": val => inputSecond.value = val,
            "onUpdate:period": val => period.value = val,
            "onUpdate:viewMode": value => viewMode.value = value,
            "ref": controlsRef
          }), null),
          default: () => vue.createVNode(VTimePickerClock, vue.mergeProps(timePickerClockProps, {
            "allowedValues": clockValidation,
            "double": viewMode.value === 'hour' && !isAmPm.value,
            "format": viewMode.value === 'hour' ? isAmPm.value ? convert24to12 : val => val : val => pad(val, 2),
            "max": viewMode.value === 'hour' ? isAmPm.value && period.value === 'am' ? 11 : 23 : 59,
            "min": viewMode.value === 'hour' && isAmPm.value && period.value === 'pm' ? 12 : 0,
            "size": 20,
            "step": viewMode.value === 'hour' ? 1 : 5,
            "modelValue": viewMode.value === 'hour' ? inputHour.value : viewMode.value === 'minute' ? inputMinute.value : inputSecond.value,
            "onChange": onChange,
            "onInput": onInput,
            "ref": clockRef
          }), null),
          actions: slots.actions
        });
      });
    }
  });

  const makeVToolbarItemsProps = propsFactory({
    ...makeComponentProps(),
    ...makeVariantProps({
      variant: 'text'
    })
  }, 'VToolbarItems');
  const VToolbarItems = genericComponent()({
    name: 'VToolbarItems',
    props: makeVToolbarItemsProps(),
    setup(props, {
      slots
    }) {
      provideDefaults({
        VBtn: {
          color: vue.toRef(() => props.color),
          height: 'inherit',
          variant: vue.toRef(() => props.variant)
        }
      });
      useRender(() => vue.createElementVNode("div", {
        "class": vue.normalizeClass(['v-toolbar-items', props.class]),
        "style": vue.normalizeStyle(props.style)
      }, [slots.default?.()]));
      return {};
    }
  });

  // Types

  const makeVTreeviewGroupProps = propsFactory({
    ...omit(makeVListGroupProps({
      collapseIcon: '$treeviewCollapse',
      expandIcon: '$treeviewExpand'
    }), ['subgroup'])
  }, 'VTreeviewGroup');
  const VTreeviewGroup = genericComponent()({
    name: 'VTreeviewGroup',
    props: makeVTreeviewGroupProps(),
    setup(props, {
      slots
    }) {
      const vListGroupRef = vue.ref();
      const toggleIcon = vue.computed(() => vListGroupRef.value?.isOpen ? props.collapseIcon : props.expandIcon);
      const activatorDefaults = vue.computed(() => ({
        VTreeviewItem: {
          prependIcon: undefined,
          appendIcon: undefined,
          toggleIcon: toggleIcon.value
        }
      }));
      useRender(() => {
        const listGroupProps = VListGroup.filterProps(props);
        return vue.createVNode(VListGroup, vue.mergeProps(listGroupProps, {
          "ref": vListGroupRef,
          "class": ['v-treeview-group', props.class],
          "subgroup": true
        }), {
          ...slots,
          activator: slots.activator ? slotProps => vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VDefaultsProvider, {
            "defaults": activatorDefaults.value
          }, {
            default: () => [slots.activator?.(slotProps)]
          })]) : undefined
        });
      });
      return {};
    }
  });

  // Types

  const VTreeviewSymbol = Symbol.for('vuetify:v-treeview');

  // Types

  const makeVTreeviewItemProps = propsFactory({
    loading: Boolean,
    hideActions: Boolean,
    hasCustomPrepend: Boolean,
    indentLines: Array,
    toggleIcon: IconValue,
    ...makeVListItemProps({
      slim: true
    })
  }, 'VTreeviewItem');
  const VTreeviewItem = genericComponent()({
    name: 'VTreeviewItem',
    props: makeVTreeviewItemProps(),
    emits: {
      toggleExpand: value => true
    },
    setup(props, {
      slots,
      emit
    }) {
      const visibleIds = vue.inject(VTreeviewSymbol, {
        visibleIds: vue.ref()
      }).visibleIds;
      const vListItemRef = vue.ref();
      const isActivatableGroupActivator = vue.computed(() => vListItemRef.value?.root.activatable.value && vListItemRef.value?.isGroupActivator);
      const isActivatable = vue.computed(() => !props.disabled && props.link !== false && isActivatableGroupActivator.value);
      const isFiltered = vue.computed(() => visibleIds.value && !visibleIds.value.has(vue.toRaw(vListItemRef.value?.id)));
      function activateGroupActivator(e) {
        vListItemRef.value?.activate(!vListItemRef.value?.isActivated, e);
      }
      function onClickAction(e) {
        e.preventDefault();
        e.stopPropagation();
        emit('toggleExpand', e);
      }
      useRender(() => {
        const listItemProps = VListItem.filterProps(props);
        const hasPrepend = slots.prepend || props.toggleIcon || props.indentLines || props.prependIcon || props.prependAvatar;
        return vue.createVNode(VListItem, vue.mergeProps({
          "ref": vListItemRef
        }, listItemProps, {
          "active": vListItemRef.value?.isActivated || undefined,
          "class": ['v-treeview-item', {
            'v-treeview-item--activatable-group-activator': isActivatableGroupActivator.value,
            'v-treeview-item--filtered': isFiltered.value
          }, props.class],
          "role": "treeitem",
          "ripple": false,
          "onClick": isActivatable.value ? activateGroupActivator : undefined
        }), {
          ...slots,
          prepend: hasPrepend ? slotProps => {
            return vue.createElementVNode(vue.Fragment, null, [props.indentLines && props.indentLines.length > 0 ? vue.createElementVNode("div", {
              "key": "indent-lines",
              "class": "v-treeview-indent-lines",
              "style": {
                '--v-indent-parts': props.indentLines.length
              }
            }, [props.indentLines.map(type => vue.createElementVNode("div", {
              "class": vue.normalizeClass(`v-treeview-indent-line v-treeview-indent-line--${type}`)
            }, null))]) : '', !props.hideActions && vue.createVNode(VListItemAction, {
              "start": true
            }, {
              default: () => [props.toggleIcon ? vue.createElementVNode(vue.Fragment, null, [!slots.toggle ? vue.createVNode(VBtn, {
                "key": "prepend-toggle",
                "density": "compact",
                "icon": props.toggleIcon,
                "loading": props.loading,
                "variant": "text",
                "onClick": onClickAction
              }, {
                loader: () => vue.createVNode(VProgressCircular, {
                  "indeterminate": "disable-shrink",
                  "size": "20",
                  "width": "2"
                }, null)
              }) : vue.createVNode(VDefaultsProvider, {
                "key": "prepend-defaults",
                "defaults": {
                  VBtn: {
                    density: 'compact',
                    icon: props.toggleIcon,
                    variant: 'text',
                    loading: props.loading
                  },
                  VProgressCircular: {
                    indeterminate: 'disable-shrink',
                    size: 20,
                    width: 2
                  }
                }
              }, {
                default: () => [slots.toggle({
                  ...slotProps,
                  loading: props.loading,
                  props: {
                    onClick: onClickAction
                  }
                })]
              })]) : vue.createElementVNode("div", {
                "class": "v-treeview-item__level"
              }, null)]
            }), !props.hasCustomPrepend ? vue.createElementVNode(vue.Fragment, null, [slots.prepend?.(slotProps), props.prependAvatar && vue.createVNode(VAvatar, {
              "key": "prepend-avatar",
              "density": props.density,
              "image": props.prependAvatar
            }, null), props.prependIcon && vue.createVNode(VIcon, {
              "key": "prepend-icon",
              "density": props.density,
              "icon": props.prependIcon
            }, null)]) : vue.createVNode(VDefaultsProvider, {
              "key": "prepend-defaults",
              "defaults": {
                VAvatar: {
                  density: props.density,
                  image: props.appendAvatar
                },
                VIcon: {
                  density: props.density,
                  icon: props.appendIcon
                },
                VListItemAction: {
                  start: true
                }
              }
            }, {
              default: () => [slots.prepend?.(slotProps)]
            })]);
          } : undefined
        });
      });
      return forwardRefs({}, vListItemRef);
    }
  });

  // Types

  const makeVTreeviewChildrenProps = propsFactory({
    fluid: Boolean,
    disabled: Boolean,
    loadChildren: Function,
    loadingIcon: {
      type: String,
      default: '$loading'
    },
    items: Array,
    openOnClick: {
      type: Boolean,
      default: undefined
    },
    indeterminateIcon: {
      type: IconValue,
      default: '$checkboxIndeterminate'
    },
    falseIcon: IconValue,
    trueIcon: IconValue,
    returnObject: Boolean,
    activatable: Boolean,
    selectable: Boolean,
    selectedColor: String,
    selectStrategy: [String, Function, Object],
    index: Number,
    isLastGroup: Boolean,
    separateRoots: Boolean,
    parentIndentLines: Array,
    indentLinesVariant: String,
    path: {
      type: Array,
      default: () => []
    },
    ...pick(makeVTreeviewItemProps(), ['hideActions']),
    ...makeDensityProps()
  }, 'VTreeviewChildren');
  const VTreeviewChildren = genericComponent()({
    name: 'VTreeviewChildren',
    props: makeVTreeviewChildrenProps(),
    setup(props, {
      slots
    }) {
      const isLoading = vue.reactive(new Set());
      const activatorItems = vue.ref([]);
      const isClickOnOpen = vue.computed(() => !props.disabled && (props.openOnClick != null ? props.openOnClick : props.selectable && !props.activatable));
      async function checkChildren(item) {
        try {
          if (!props.items?.length || !props.loadChildren) return;
          if (item?.children?.length === 0) {
            isLoading.add(item.value);
            await props.loadChildren(item.raw);
          }
        } finally {
          isLoading.delete(item.value);
        }
      }
      function selectItem(select, isSelected) {
        if (props.selectable) {
          select(isSelected);
        }
      }
      return () => slots.default?.() ?? props.items?.map((item, index, items) => {
        const {
          children,
          props: itemProps
        } = item;
        const loading = isLoading.has(item.value);
        const nextItemHasChildren = !!items.at(index + 1)?.children;
        const depth = props.path?.length ?? 0;
        const isLast = items.length - 1 === index;
        const nodePositionProps = {
          index,
          depth,
          isFirst: index === 0,
          isLast,
          path: [...props.path, index]
        };
        const indentLines = getIndentLines({
          depth,
          isLast,
          isLastGroup: props.isLastGroup,
          leafLinks: !props.hideActions && !props.fluid,
          separateRoots: props.separateRoots,
          parentIndentLines: props.parentIndentLines,
          variant: props.indentLinesVariant
        });
        const treeItemProps = {
          ...itemProps,
          hideActions: props.hideActions,
          indentLines: children ? indentLines.node : indentLines.leaf
        };
        const slotsWithItem = {
          toggle: slots.toggle ? slotProps => slots.toggle?.({
            ...slotProps,
            ...nodePositionProps,
            item: item.raw,
            internalItem: item,
            loading
          }) : undefined,
          prepend: slotProps => vue.createElementVNode(vue.Fragment, null, [props.selectable && (!children || children && !['leaf', 'single-leaf'].includes(props.selectStrategy)) && vue.createVNode(VListItemAction, {
            "start": true
          }, {
            default: () => [vue.createVNode(VCheckboxBtn, {
              "key": item.value,
              "modelValue": slotProps.isSelected,
              "disabled": props.disabled || itemProps.disabled,
              "loading": loading,
              "color": props.selectedColor,
              "density": props.density,
              "indeterminate": slotProps.isIndeterminate,
              "indeterminateIcon": props.indeterminateIcon,
              "falseIcon": props.falseIcon,
              "trueIcon": props.trueIcon,
              "onUpdate:modelValue": v => selectItem(slotProps.select, v),
              "onClick": e => e.stopPropagation(),
              "onKeydown": e => {
                if (!['Enter', 'Space'].includes(e.key)) return;
                e.stopPropagation();
                selectItem(slotProps.select, slotProps.isSelected);
              }
            }, null)]
          }), slots.prepend?.({
            ...slotProps,
            ...nodePositionProps,
            item: item.raw,
            internalItem: item
          })]),
          append: slots.append ? slotProps => slots.append?.({
            ...slotProps,
            ...nodePositionProps,
            item: item.raw,
            internalItem: item
          }) : undefined,
          title: slots.title ? slotProps => slots.title?.({
            ...slotProps,
            item: item.raw,
            internalItem: item
          }) : undefined,
          subtitle: slots.subtitle ? slotProps => slots.subtitle?.({
            ...slotProps,
            item: item.raw,
            internalItem: item
          }) : undefined
        };
        const treeviewGroupProps = VTreeviewGroup.filterProps(itemProps);
        const treeviewChildrenProps = VTreeviewChildren.filterProps({
          ...props,
          ...nodePositionProps
        });
        const footerProps = {
          hideActions: props.hideActions,
          indentLines: indentLines.footer
        };
        return children ? vue.createVNode(VTreeviewGroup, vue.mergeProps(treeviewGroupProps, {
          "value": props.returnObject ? item.raw : treeviewGroupProps?.value,
          "rawId": treeviewGroupProps?.value
        }), {
          activator: ({
            props: activatorProps,
            isOpen
          }) => {
            const listItemProps = {
              ...treeItemProps,
              ...activatorProps,
              value: treeItemProps?.value,
              ariaExpanded: isOpen,
              onToggleExpand: [() => checkChildren(item), activatorProps.onClick],
              onClick: props.disabled || treeItemProps.disabled ? undefined : isClickOnOpen.value ? [() => checkChildren(item), activatorProps.onClick] : () => selectItem(activatorItems.value[index]?.select, !activatorItems.value[index]?.isSelected)
            };
            return renderSlot(slots.header, {
              props: listItemProps,
              item: item.raw,
              internalItem: item,
              loading
            }, () => vue.createVNode(VTreeviewItem, vue.mergeProps({
              "ref": el => activatorItems.value[index] = el
            }, listItemProps, {
              "hasCustomPrepend": !!slots.prepend,
              "value": props.returnObject ? item.raw : itemProps.value,
              "loading": loading
            }), slotsWithItem));
          },
          default: () => vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VTreeviewChildren, vue.mergeProps(treeviewChildrenProps, {
            "items": children,
            "indentLinesVariant": props.indentLinesVariant,
            "parentIndentLines": indentLines.children,
            "isLastGroup": nextItemHasChildren,
            "returnObject": props.returnObject
          }), slots), slots.footer?.({
            props: footerProps,
            item: item.raw,
            internalItem: item,
            loading
          })])
        }) : renderSlot(slots.item, {
          props: treeItemProps,
          item: item.raw,
          internalItem: item,
          ...nodePositionProps
        }, () => {
          if (item.type === 'divider') {
            return renderSlot(slots.divider, {
              props: item.raw
            }, () => vue.createVNode(VDivider, item.props, null));
          }
          if (item.type === 'subheader') {
            return renderSlot(slots.subheader, {
              props: item.raw
            }, () => vue.createVNode(VListSubheader, item.props, null));
          }
          return vue.createVNode(VTreeviewItem, vue.mergeProps(treeItemProps, {
            "hasCustomPrepend": !!slots.prepend,
            "value": props.returnObject ? vue.toRaw(item.raw) : treeItemProps.value
          }), slotsWithItem);
        });
      });
    }
  });

  function flatten(items, flat = []) {
    for (const item of items) {
      flat.push(item);
      if (item.children) flatten(item.children, flat);
    }
    return flat;
  }
  const makeVTreeviewProps = propsFactory({
    openAll: Boolean,
    indentLines: [Boolean, String],
    indentLinesColor: String,
    indentLinesOpacity: [String, Number],
    search: String,
    hideNoData: Boolean,
    noDataText: {
      type: String,
      default: '$vuetify.noDataText'
    },
    ...makeFilterProps({
      filterKeys: ['title']
    }),
    ...omit(makeVTreeviewChildrenProps(), ['index', 'path', 'indentLinesVariant', 'parentIndentLines', 'isLastGroup']),
    ...omit(makeVListProps({
      collapseIcon: '$treeviewCollapse',
      expandIcon: '$treeviewExpand',
      slim: true
    }), ['nav', 'openStrategy']),
    modelValue: Array
  }, 'VTreeview');
  const VTreeview = genericComponent()({
    name: 'VTreeview',
    props: makeVTreeviewProps(),
    emits: {
      'update:opened': val => true,
      'update:activated': val => true,
      'update:selected': val => true,
      'update:modelValue': val => true,
      'click:open': value => true,
      'click:select': value => true
    },
    setup(props, {
      slots,
      emit
    }) {
      const {
        t
      } = useLocale();
      const {
        items
      } = useListItems(props);
      const activeColor = vue.toRef(() => props.activeColor);
      const baseColor = vue.toRef(() => props.baseColor);
      const color = vue.toRef(() => props.color);
      const activated = useProxiedModel(props, 'activated');
      const _selected = useProxiedModel(props, 'selected');
      const selected = vue.computed({
        get: () => props.modelValue ?? _selected.value,
        set(val) {
          _selected.value = val;
          emit('update:modelValue', val);
        }
      });
      const vListRef = vue.ref();
      const opened = vue.computed(() => props.openAll ? openAll(items.value) : props.opened);
      const flatItems = vue.computed(() => flatten(items.value));
      const search = vue.toRef(() => props.search);
      const {
        filteredItems
      } = useFilter(props, flatItems, search);
      const visibleIds = vue.computed(() => {
        if (!search.value) return null;
        const getPath = vListRef.value?.getPath;
        if (!getPath) return null;
        return new Set(filteredItems.value.flatMap(item => {
          const itemVal = props.returnObject ? item.raw : item.props.value;
          return [...getPath(itemVal), ...getChildren(itemVal)].map(vue.toRaw);
        }));
      });
      function getChildren(id) {
        const arr = [];
        const queue = (vListRef.value?.children.get(vue.toRaw(id)) ?? []).slice();
        while (queue.length) {
          const child = queue.shift();
          if (!child) continue;
          arr.push(child);
          queue.push(...(vListRef.value?.children.get(child) ?? []).slice());
        }
        return arr;
      }
      function openAll(items) {
        let ids = [];
        for (const i of items) {
          if (!i.children) continue;
          ids.push(props.returnObject ? vue.toRaw(i.raw) : i.value);
          if (i.children) {
            ids = ids.concat(openAll(i.children));
          }
        }
        return ids;
      }
      vue.provide(VTreeviewSymbol, {
        visibleIds
      });
      provideDefaults({
        VTreeviewGroup: {
          activeColor,
          baseColor,
          color,
          collapseIcon: vue.toRef(() => props.collapseIcon),
          expandIcon: vue.toRef(() => props.expandIcon)
        },
        VTreeviewItem: {
          activeClass: vue.toRef(() => props.activeClass),
          activeColor,
          baseColor,
          color,
          density: vue.toRef(() => props.density),
          disabled: vue.toRef(() => props.disabled),
          lines: vue.toRef(() => props.lines),
          variant: vue.toRef(() => props.variant)
        }
      });
      useRender(() => {
        const listProps = VList.filterProps(props);
        const treeviewChildrenProps = VTreeviewChildren.filterProps(props);
        const indentLinesVariant = typeof props.indentLines === 'boolean' ? 'default' : props.indentLines;
        return vue.createVNode(VList, vue.mergeProps({
          "ref": vListRef
        }, listProps, {
          "class": ['v-treeview', {
            'v-treeview--fluid': props.fluid
          }, props.class],
          "role": "tree",
          "openStrategy": "multiple",
          "style": [{
            '--v-treeview-indent-line-color': props.indentLinesColor,
            '--v-treeview-indent-line-opacity': props.indentLinesOpacity
          }, props.style],
          "opened": opened.value,
          "activated": activated.value,
          "onUpdate:activated": $event => activated.value = $event,
          "selected": selected.value,
          "onUpdate:selected": $event => selected.value = $event
        }), {
          default: () => [visibleIds.value?.size === 0 && !props.hideNoData && (slots['no-data']?.() ?? vue.createVNode(VListItem, {
            "key": "no-data",
            "title": t(props.noDataText)
          }, null)), vue.createVNode(VTreeviewChildren, vue.mergeProps(treeviewChildrenProps, {
            "density": props.density,
            "returnObject": props.returnObject,
            "items": items.value,
            "parentIndentLines": props.indentLines ? [] : undefined,
            "indentLinesVariant": indentLinesVariant
          }), slots)]
        });
      });
      return {};
    }
  });

  // Composables

  // Types

  const VValidation = genericComponent()({
    name: 'VValidation',
    props: makeValidationProps(),
    emits: {
      'update:modelValue': value => true
    },
    setup(props, {
      slots
    }) {
      const validation = useValidation(props, 'validation');
      return () => slots.default?.(validation);
    }
  });

  var components = /*#__PURE__*/Object.freeze({
    __proto__: null,
    VAlert: VAlert,
    VAlertTitle: VAlertTitle,
    VApp: VApp,
    VAppBar: VAppBar,
    VAppBarNavIcon: VAppBarNavIcon,
    VAppBarTitle: VAppBarTitle,
    VAutocomplete: VAutocomplete,
    VAvatar: VAvatar,
    VBadge: VBadge,
    VBanner: VBanner,
    VBannerActions: VBannerActions,
    VBannerText: VBannerText,
    VBottomNavigation: VBottomNavigation,
    VBottomSheet: VBottomSheet,
    VBreadcrumbs: VBreadcrumbs,
    VBreadcrumbsDivider: VBreadcrumbsDivider,
    VBreadcrumbsItem: VBreadcrumbsItem,
    VBtn: VBtn,
    VBtnGroup: VBtnGroup,
    VBtnToggle: VBtnToggle,
    VCalendar: VCalendar,
    VCard: VCard,
    VCardActions: VCardActions,
    VCardItem: VCardItem,
    VCardSubtitle: VCardSubtitle,
    VCardText: VCardText,
    VCardTitle: VCardTitle,
    VCarousel: VCarousel,
    VCarouselItem: VCarouselItem,
    VCheckbox: VCheckbox,
    VCheckboxBtn: VCheckboxBtn,
    VChip: VChip,
    VChipGroup: VChipGroup,
    VClassIcon: VClassIcon,
    VCode: VCode,
    VCol: VCol,
    VColorInput: VColorInput,
    VColorPicker: VColorPicker,
    VCombobox: VCombobox,
    VComponentIcon: VComponentIcon,
    VConfirmEdit: VConfirmEdit,
    VContainer: VContainer,
    VCounter: VCounter,
    VDataIterator: VDataIterator,
    VDataTable: VDataTable,
    VDataTableFooter: VDataTableFooter,
    VDataTableHeaders: VDataTableHeaders,
    VDataTableRow: VDataTableRow,
    VDataTableRows: VDataTableRows,
    VDataTableServer: VDataTableServer,
    VDataTableVirtual: VDataTableVirtual,
    VDateInput: VDateInput,
    VDatePicker: VDatePicker,
    VDatePickerControls: VDatePickerControls,
    VDatePickerHeader: VDatePickerHeader,
    VDatePickerMonth: VDatePickerMonth,
    VDatePickerMonths: VDatePickerMonths,
    VDatePickerYears: VDatePickerYears,
    VDefaultsProvider: VDefaultsProvider,
    VDialog: VDialog,
    VDialogBottomTransition: VDialogBottomTransition,
    VDialogTopTransition: VDialogTopTransition,
    VDialogTransition: VDialogTransition,
    VDivider: VDivider,
    VEmptyState: VEmptyState,
    VExpandBothTransition: VExpandBothTransition,
    VExpandTransition: VExpandTransition,
    VExpandXTransition: VExpandXTransition,
    VExpansionPanel: VExpansionPanel,
    VExpansionPanelText: VExpansionPanelText,
    VExpansionPanelTitle: VExpansionPanelTitle,
    VExpansionPanels: VExpansionPanels,
    VFab: VFab,
    VFabTransition: VFabTransition,
    VFadeTransition: VFadeTransition,
    VField: VField,
    VFieldLabel: VFieldLabel,
    VFileInput: VFileInput,
    VFileUpload: VFileUpload,
    VFileUploadDropzone: VFileUploadDropzone,
    VFileUploadItem: VFileUploadItem,
    VFileUploadList: VFileUploadList,
    VFooter: VFooter,
    VForm: VForm,
    VHotkey: VHotkey,
    VHover: VHover,
    VIcon: VIcon,
    VIconBtn: VIconBtn,
    VImg: VImg,
    VInfiniteScroll: VInfiniteScroll,
    VInput: VInput,
    VItem: VItem,
    VItemGroup: VItemGroup,
    VKbd: VKbd,
    VLabel: VLabel,
    VLayout: VLayout,
    VLayoutItem: VLayoutItem,
    VLazy: VLazy,
    VLigatureIcon: VLigatureIcon,
    VList: VList,
    VListGroup: VListGroup,
    VListImg: VListImg,
    VListItem: VListItem,
    VListItemAction: VListItemAction,
    VListItemMedia: VListItemMedia,
    VListItemSubtitle: VListItemSubtitle,
    VListItemTitle: VListItemTitle,
    VListSubheader: VListSubheader,
    VLocaleProvider: VLocaleProvider,
    VMain: VMain,
    VMenu: VMenu,
    VMessages: VMessages,
    VNavigationDrawer: VNavigationDrawer,
    VNoSsr: VNoSsr,
    VNumberInput: VNumberInput,
    VOtpField: VOtpField,
    VOtpGroup: VOtpGroup,
    VOtpInput: VOtpInput,
    VOtpSeparator: VOtpSeparator,
    VOverlay: VOverlay,
    VPagination: VPagination,
    VParallax: VParallax,
    VPicker: VPicker,
    VPickerTitle: VPickerTitle,
    VProgressCircular: VProgressCircular,
    VProgressLinear: VProgressLinear,
    VPullToRefresh: VPullToRefresh,
    VRadio: VRadio,
    VRadioGroup: VRadioGroup,
    VRangeSlider: VRangeSlider,
    VRating: VRating,
    VResponsive: VResponsive,
    VRow: VRow,
    VScaleTransition: VScaleTransition,
    VScrollXReverseTransition: VScrollXReverseTransition,
    VScrollXTransition: VScrollXTransition,
    VScrollYReverseTransition: VScrollYReverseTransition,
    VScrollYTransition: VScrollYTransition,
    VSelect: VSelect,
    VSelectionControl: VSelectionControl,
    VSelectionControlGroup: VSelectionControlGroup,
    VSheet: VSheet,
    VSkeletonLoader: VSkeletonLoader,
    VSlideGroup: VSlideGroup,
    VSlideGroupItem: VSlideGroupItem,
    VSlideXReverseTransition: VSlideXReverseTransition,
    VSlideXTransition: VSlideXTransition,
    VSlideYReverseTransition: VSlideYReverseTransition,
    VSlideYTransition: VSlideYTransition,
    VSlider: VSlider,
    VSnackbar: VSnackbar,
    VSnackbarQueue: VSnackbarQueue,
    VSpacer: VSpacer,
    VSparkline: VSparkline,
    VSparklineTooltip: VSparklineTooltip,
    VSpeedDial: VSpeedDial,
    VStepper: VStepper,
    VStepperActions: VStepperActions,
    VStepperHeader: VStepperHeader,
    VStepperItem: VStepperItem,
    VStepperVertical: VStepperVertical,
    VStepperVerticalActions: VStepperVerticalActions,
    VStepperVerticalItem: VStepperVerticalItem,
    VStepperWindow: VStepperWindow,
    VStepperWindowItem: VStepperWindowItem,
    VSvgIcon: VSvgIcon,
    VSwitch: VSwitch,
    VSystemBar: VSystemBar,
    VTab: VTab,
    VTable: VTable,
    VTabs: VTabs,
    VTabsWindow: VTabsWindow,
    VTabsWindowItem: VTabsWindowItem,
    VTextField: VTextField,
    VTextarea: VTextarea,
    VThemeProvider: VThemeProvider,
    VTimePicker: VTimePicker,
    VTimePickerClock: VTimePickerClock,
    VTimePickerControls: VTimePickerControls,
    VTimeline: VTimeline,
    VTimelineItem: VTimelineItem,
    VToolbar: VToolbar,
    VToolbarItems: VToolbarItems,
    VToolbarTitle: VToolbarTitle,
    VTooltip: VTooltip,
    VTreeview: VTreeview,
    VTreeviewGroup: VTreeviewGroup,
    VTreeviewItem: VTreeviewItem,
    VValidation: VValidation,
    VVirtualScroll: VVirtualScroll,
    VWindow: VWindow,
    VWindowItem: VWindowItem
  });

  // Types

  function mounted$1(el, binding) {
    const modifiers = binding.modifiers || {};
    const value = binding.value;
    const {
      once,
      immediate,
      ...modifierKeys
    } = modifiers;
    const defaultValue = !Object.keys(modifierKeys).length;
    const {
      handler,
      options
    } = typeof value === 'object' ? value : {
      handler: value,
      options: {
        attributes: modifierKeys?.attr ?? defaultValue,
        characterData: modifierKeys?.char ?? defaultValue,
        childList: modifierKeys?.child ?? defaultValue,
        subtree: modifierKeys?.sub ?? defaultValue
      }
    };
    const observer = new MutationObserver((mutations = [], observer) => {
      handler?.(mutations, observer);
      if (once) unmounted$1(el, binding);
    });
    if (immediate) handler?.([], observer);
    el._mutate = Object(el._mutate);
    el._mutate[binding.instance.$.uid] = {
      observer
    };
    observer.observe(el, options);
  }
  function unmounted$1(el, binding) {
    if (!el._mutate?.[binding.instance.$.uid]) return;
    el._mutate[binding.instance.$.uid].observer.disconnect();
    delete el._mutate[binding.instance.$.uid];
  }
  const Mutate = {
    mounted: mounted$1,
    unmounted: unmounted$1
  };

  // Types

  function mounted(el, binding) {
    const {
      self = false
    } = binding.modifiers ?? {};
    const value = binding.value;
    const options = typeof value === 'object' && value.options || {
      passive: true
    };
    const handler = typeof value === 'function' || 'handleEvent' in value ? value : value.handler;
    const target = self ? el : binding.arg ? document.querySelector(binding.arg) : window;
    if (!target) return;
    target.addEventListener('scroll', handler, options);
    el._onScroll = Object(el._onScroll);
    el._onScroll[binding.instance.$.uid] = {
      handler,
      options,
      // Don't reference self
      target: self ? undefined : target
    };
  }
  function unmounted(el, binding) {
    if (!el._onScroll?.[binding.instance.$.uid]) return;
    const {
      handler,
      options,
      target = el
    } = el._onScroll[binding.instance.$.uid];
    target.removeEventListener('scroll', handler, options);
    delete el._onScroll[binding.instance.$.uid];
  }
  function updated(el, binding) {
    if (binding.value === binding.oldValue) return;
    unmounted(el, binding);
    mounted(el, binding);
  }
  const Scroll = {
    mounted,
    unmounted,
    updated
  };

  // Utilities

  // Types

  function useDirectiveComponent(component, props) {
    const concreteComponent = typeof component === 'string' ? vue.resolveComponent(component) : component;
    const hook = mountComponent(concreteComponent, props);
    return {
      mounted: hook,
      updated: hook,
      unmounted(el) {
        vue.render(null, el);
      }
    };
  }
  function mountComponent(component, props) {
    return function (el, binding, vnode) {
      const _props = typeof props === 'function' ? props(binding) : props;
      const text = binding.value?.text ?? binding.value ?? _props?.text;
      const value = isObject(binding.value) ? binding.value : {};

      // Get the children from the props or directive value, or the element's children
      const children = () => text ?? el.textContent;

      // If vnode.ctx is the same as the instance, then we're bound to a plain element
      // and need to find the nearest parent component instance to inherit provides from
      const provides = (vnode.ctx === binding.instance.$ ? findComponentParent(vnode, binding.instance.$)?.provides : vnode.ctx?.provides) ?? binding.instance.$.provides;
      const node = vue.h(component, vue.mergeProps(_props, value), children);
      node.appContext = Object.assign(Object.create(null), binding.instance.$.appContext, {
        provides
      });
      vue.render(node, el);
    };
  }
  function findComponentParent(vnode, root) {
    // Walk the tree from root until we find the child vnode
    const stack = new Set();
    const walk = children => {
      for (const child of children) {
        if (!child) continue;
        if (child === vnode || child.el && vnode.el && child.el === vnode.el) {
          return true;
        }
        stack.add(child);
        let result;
        if (child.suspense) {
          result = walk([child.ssContent]);
        } else if (Array.isArray(child.children)) {
          result = walk(child.children);
        } else if (child.component?.vnode) {
          result = walk([child.component?.subTree]);
        }
        if (result) {
          return result;
        }
        stack.delete(child);
      }
      return false;
    };
    if (!walk([root.subTree])) {
      consoleError('Could not find original vnode, component will not inherit provides');
      return root;
    }

    // Return the first component parent
    const result = Array.from(stack).reverse();
    for (const child of result) {
      if (child.component) {
        return child.component;
      }
    }
    return root;
  }

  // Components

  // Types

  const Tooltip = useDirectiveComponent(VTooltip, binding => {
    const disabled = isObject(binding.value) ? !binding.value.text : ['', false, null].includes(binding.value); // undefined means true

    return {
      activator: disabled ? null : 'parent',
      location: binding.arg?.replace('-', ' '),
      text: typeof binding.value === 'boolean' ? undefined : binding.value
    };
  });

  var directives = /*#__PURE__*/Object.freeze({
    __proto__: null,
    ClickOutside: ClickOutside,
    Intersect: Intersect,
    Mutate: Mutate,
    Resize: Resize,
    Ripple: Ripple,
    Scroll: Scroll,
    Tooltip: Tooltip,
    Touch: Touch
  });

  // Composables

  // Types

  function genDefaults() {
    return {
      svg: {
        component: VSvgIcon
      },
      class: {
        component: VClassIcon
      }
    };
  }
  function createIcons(options) {
    const sets = genDefaults();
    const defaultSet = options?.defaultSet ?? 'mdi';
    if (defaultSet === 'mdi' && !sets.mdi) {
      sets.mdi = mdi;
    }
    return mergeDeep({
      defaultSet,
      sets,
      aliases: {
        ...aliases,
        /* eslint-disable max-len */
        vuetify: ['M8.2241 14.2009L12 21L22 3H14.4459L8.2241 14.2009Z', ['M7.26303 12.4733L7.00113 12L2 3H12.5261C12.5261 3 12.5261 3 12.5261 3L7.26303 12.4733Z', 0.6]],
        'vuetify-outline': 'svg:M7.26 12.47 12.53 3H2L7.26 12.47ZM14.45 3 8.22 14.2 12 21 22 3H14.45ZM18.6 5 12 16.88 10.51 14.2 15.62 5ZM7.26 8.35 5.4 5H9.13L7.26 8.35Z',
        'vuetify-play': ['m6.376 13.184-4.11-7.192C1.505 4.66 2.467 3 4.003 3h8.532l-.953 1.576-.006.01-.396.677c-.429.732-.214 1.507.194 2.015.404.503 1.092.878 1.869.806a3.72 3.72 0 0 1 1.005.022c.276.053.434.143.523.237.138.146.38.635-.25 2.09-.893 1.63-1.553 1.722-1.847 1.677-.213-.033-.468-.158-.756-.406a4.95 4.95 0 0 1-.8-.927c-.39-.564-1.04-.84-1.66-.846-.625-.006-1.316.27-1.693.921l-.478.826-.911 1.506Z', ['M9.093 11.552c.046-.079.144-.15.32-.148a.53.53 0 0 1 .43.207c.285.414.636.847 1.046 1.2.405.35.914.662 1.516.754 1.334.205 2.502-.698 3.48-2.495l.014-.028.013-.03c.687-1.574.774-2.852-.005-3.675-.37-.391-.861-.586-1.333-.676a5.243 5.243 0 0 0-1.447-.044c-.173.016-.393-.073-.54-.257-.145-.18-.127-.316-.082-.392l.393-.672L14.287 3h5.71c1.536 0 2.499 1.659 1.737 2.992l-7.997 13.996c-.768 1.344-2.706 1.344-3.473 0l-3.037-5.314 1.377-2.278.004-.006.004-.007.481-.831Z', 0.6]]
        /* eslint-enable max-len */
      }
    }, options);
  }

  // Composables
  function createVuetify$1(vuetify = {}) {
    const {
      blueprint,
      ...rest
    } = vuetify;
    const options = mergeDeep(blueprint, rest);
    const {
      aliases = {},
      components = {},
      directives = {}
    } = options;
    const scope = vue.effectScope();
    return scope.run(() => {
      const defaults = createDefaults(options.defaults);
      const display = createDisplay(options.display, options.ssr);
      const theme = createTheme(options.theme);
      const icons = createIcons(options.icons);
      const locale = createLocale(options.locale);
      const date = createDate(options.date, locale);
      const goTo = createGoTo(options.goTo, locale);
      function install(app) {
        for (const key in directives) {
          app.directive(key, directives[key]);
        }
        for (const key in components) {
          app.component(key, components[key]);
        }
        for (const key in aliases) {
          app.component(key, defineComponent({
            ...aliases[key],
            name: key,
            aliasName: aliases[key].name
          }));
        }
        const appScope = vue.effectScope();
        appScope.run(() => {
          theme.install(app);
        });
        app.onUnmount(() => appScope.stop());
        app.provide(DefaultsSymbol, defaults);
        app.provide(DisplaySymbol, display);
        app.provide(ThemeSymbol, theme);
        app.provide(IconSymbol, icons);
        app.provide(LocaleSymbol, locale);
        app.provide(DateOptionsSymbol, date.options);
        app.provide(DateAdapterSymbol, date.instance);
        app.provide(GoToSymbol, goTo);
        if (IN_BROWSER && options.ssr) {
          if (app.$nuxt) {
            app.$nuxt.hook('app:suspense:resolve', () => {
              display.update();
            });
          } else {
            const {
              mount
            } = app;
            app.mount = (...args) => {
              const vm = mount(...args);
              vue.nextTick(() => display.update());
              app.mount = mount;
              return vm;
            };
          }
        }
        if (typeof __VUE_OPTIONS_API__ !== 'boolean' || __VUE_OPTIONS_API__) {
          app.mixin({
            computed: {
              $vuetify() {
                return vue.reactive({
                  defaults: inject.call(this, DefaultsSymbol),
                  display: inject.call(this, DisplaySymbol),
                  theme: inject.call(this, ThemeSymbol),
                  icons: inject.call(this, IconSymbol),
                  locale: inject.call(this, LocaleSymbol),
                  date: inject.call(this, DateAdapterSymbol)
                });
              }
            }
          });
        }
      }
      function unmount() {
        scope.stop();
      }
      return {
        install,
        unmount,
        defaults,
        display,
        theme,
        icons,
        locale,
        date,
        goTo
      };
    });
  }
  const version$1 = "4.1.11";
  createVuetify$1.version = version$1;

  // Vue's inject() can only be used in setup
  function inject(key) {
    const vm = this.$;
    const provides = vm.parent?.provides ?? vm.vnode.appContext?.provides;
    if (provides && key in provides) {
      return provides[key];
    }
  }

  /* eslint-disable local-rules/sort-imports */


  // Types

  const createVuetify = (options = {}) => {
    return createVuetify$1({
      components,
      directives,
      ...options
    });
  };
  const version = "4.1.11";
  createVuetify.version = version;

  exports.blueprints = index;
  exports.components = components;
  exports.createVuetify = createVuetify;
  exports.directives = directives;
  exports.useDate = useDate;
  exports.useDefaults = useDefaults;
  exports.useDisplay = useDisplay;
  exports.useGoTo = useGoTo;
  exports.useHotkey = useHotkey;
  exports.useLayout = useLayout;
  exports.useLocale = useLocale;
  exports.useMask = useMask;
  exports.useRtl = useRtl;
  exports.useTheme = useTheme;
  exports.version = version;

}));
//# sourceMappingURL=vuetify.cjs.map