@vuetify/v0 0.0.18 → 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -47
- package/dist/browser/index.js +1645 -1128
- package/dist/components/index.d.mts +3 -3
- package/dist/components/index.mjs +4 -4
- package/dist/{components-DRdenC8b.mjs → components-BomyjmT3.mjs} +24 -3
- package/dist/composables/index.d.mts +4 -4
- package/dist/composables/index.mjs +5 -5
- package/dist/{composables-DG1MHp-R.mjs → composables-CbAPZabd.mjs} +276 -29
- package/dist/constants/index.mjs +1 -1
- package/dist/{globals-BGVqrlN7.mjs → globals-C3JrEDXZ.mjs} +2 -1
- package/dist/index-4jSy8KIt.d.mts +73 -0
- package/dist/{index-oQuVnpOj.d.mts → index-B0QJdwz9.d.mts} +254 -208
- package/dist/index-CxeZr8jO.d.mts +270 -0
- package/dist/{index-DaX9-kmY.d.mts → index-MLb3LH9a.d.mts} +9 -7
- package/dist/{index-CH7DpIK8.d.mts → index-OU0IRbIS.d.mts} +127 -10
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +6 -6
- package/dist/types/index.d.mts +1 -1
- package/dist/{useStep-DC_JvZpy.mjs → useStep-CfgBbrJB.mjs} +1088 -1070
- package/dist/utilities/index.d.mts +2 -2
- package/dist/utilities/index.mjs +1 -1
- package/dist/utilities-CjDz-Xvn.mjs +369 -0
- package/package.json +3 -21
- package/dist/index-B-jVvwsm.d.mts +0 -71
- package/dist/index-C5LQZd3v.d.mts +0 -11
- package/dist/utilities-JxCe-nF2.mjs +0 -139
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { _ as range, d as isObject, h as isUndefined, l as isNullOrUndefined, m as isSymbol, o as isFunction, p as isString, r as genId, s as isNaN } from "./utilities-
|
|
2
|
-
import { a as SUPPORTS_OBSERVER, s as __LOGGER_ENABLED__, t as IN_BROWSER } from "./globals-
|
|
3
|
-
import { computed, getCurrentInstance, inject, isRef, onScopeDispose, provide, reactive, shallowReactive, shallowReadonly, shallowRef, toRef, toValue, watch } from "vue";
|
|
1
|
+
import { _ as range, c as isNull, d as isObject, h as isUndefined, i as isArray, l as isNullOrUndefined, m as isSymbol, o as isFunction, p as isString, r as genId, s as isNaN, t as clamp } from "./utilities-CjDz-Xvn.mjs";
|
|
2
|
+
import { a as SUPPORTS_OBSERVER, s as __LOGGER_ENABLED__, t as IN_BROWSER } from "./globals-C3JrEDXZ.mjs";
|
|
3
|
+
import { computed, getCurrentInstance, inject, isRef, onScopeDispose, provide, reactive, shallowReactive, shallowReadonly, shallowRef, toRef, toValue, watch, watchEffect } from "vue";
|
|
4
4
|
|
|
5
5
|
//#region src/composables/createContext/index.ts
|
|
6
6
|
/**
|
|
@@ -302,10 +302,12 @@ var Vuetify0LoggerAdapter = class {
|
|
|
302
302
|
}
|
|
303
303
|
timestamp() {
|
|
304
304
|
if (!IN_BROWSER) return (/* @__PURE__ */ new Date()).toISOString();
|
|
305
|
+
/* v8 ignore next -- defensive fallback, toTimeString always returns valid format */
|
|
305
306
|
return (/* @__PURE__ */ new Date()).toTimeString().split(" ")[0] ?? "";
|
|
306
307
|
}
|
|
307
308
|
style(level) {
|
|
308
309
|
if (!this.colors || !IN_BROWSER) return "";
|
|
310
|
+
/* v8 ignore next -- LogLevel union is exhaustive */
|
|
309
311
|
return {
|
|
310
312
|
trace: "color: #64748b",
|
|
311
313
|
debug: "color: #3b82f6",
|
|
@@ -560,6 +562,8 @@ function useLogger(namespace = "v0:logger") {
|
|
|
560
562
|
/**
|
|
561
563
|
* @module useRegistry
|
|
562
564
|
*
|
|
565
|
+
* @see https://0.vuetifyjs.com/composables/registration/use-registry
|
|
566
|
+
*
|
|
563
567
|
* @remarks
|
|
564
568
|
* A foundational composable for managing collections of items (tickets) with:
|
|
565
569
|
* - Unique ID-based access
|
|
@@ -616,17 +620,21 @@ function useRegistry(options) {
|
|
|
616
620
|
}
|
|
617
621
|
function on(event, cb) {
|
|
618
622
|
if (!events) {
|
|
619
|
-
logger.warn(`
|
|
623
|
+
logger.warn(`Events are disabled. Initialize with \`useRegistry({ events: true })\` to enable.`);
|
|
620
624
|
return;
|
|
621
625
|
}
|
|
622
626
|
if (!listeners.has(event)) listeners.set(event, /* @__PURE__ */ new Set());
|
|
623
627
|
listeners.get(event).add(cb);
|
|
624
628
|
}
|
|
625
629
|
function off(event, cb) {
|
|
630
|
+
if (!events) {
|
|
631
|
+
logger.warn(`Events are disabled. Initialize with \`useRegistry({ events: true })\` to enable.`);
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
626
634
|
listeners.get(event)?.delete(cb);
|
|
627
635
|
}
|
|
628
636
|
function dispose() {
|
|
629
|
-
|
|
637
|
+
listeners.clear();
|
|
630
638
|
clear();
|
|
631
639
|
}
|
|
632
640
|
function get(id) {
|
|
@@ -715,9 +723,9 @@ function useRegistry(options) {
|
|
|
715
723
|
return entries$1;
|
|
716
724
|
}
|
|
717
725
|
function clear() {
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
726
|
+
collection.clear();
|
|
727
|
+
catalog.clear();
|
|
728
|
+
directory.clear();
|
|
721
729
|
invalidate();
|
|
722
730
|
indexDependentCount = 0;
|
|
723
731
|
needsReindex = false;
|
|
@@ -726,7 +734,7 @@ function useRegistry(options) {
|
|
|
726
734
|
}
|
|
727
735
|
function invalidate() {
|
|
728
736
|
if (batching) return;
|
|
729
|
-
|
|
737
|
+
cache.clear();
|
|
730
738
|
}
|
|
731
739
|
function queueEmit(event, data) {
|
|
732
740
|
if (batching) pendingEmits.push({
|
|
@@ -741,7 +749,7 @@ function useRegistry(options) {
|
|
|
741
749
|
pendingEmits = [];
|
|
742
750
|
try {
|
|
743
751
|
const result = fn();
|
|
744
|
-
|
|
752
|
+
cache.clear();
|
|
745
753
|
for (const { event, data } of pendingEmits) emit(event, data);
|
|
746
754
|
return result;
|
|
747
755
|
} finally {
|
|
@@ -752,8 +760,8 @@ function useRegistry(options) {
|
|
|
752
760
|
function reindex() {
|
|
753
761
|
const startIndex = minDirtyIndex === Infinity ? 0 : minDirtyIndex;
|
|
754
762
|
if (startIndex === 0) {
|
|
755
|
-
|
|
756
|
-
|
|
763
|
+
catalog.clear();
|
|
764
|
+
directory.clear();
|
|
757
765
|
}
|
|
758
766
|
invalidate();
|
|
759
767
|
let index = 0;
|
|
@@ -780,7 +788,7 @@ function useRegistry(options) {
|
|
|
780
788
|
const size = collection.size;
|
|
781
789
|
const id = registration.id ?? /* @__PURE__ */ genId();
|
|
782
790
|
if (has(id)) {
|
|
783
|
-
logger.warn(`Ticket
|
|
791
|
+
logger.warn(`Ticket "${id}" already exists. Use \`upsert()\` to update or check \`has()\` before registering.`);
|
|
784
792
|
return get(id);
|
|
785
793
|
}
|
|
786
794
|
const valueIsUndefined = /* @__PURE__ */ isUndefined(registration.value);
|
|
@@ -830,14 +838,18 @@ function useRegistry(options) {
|
|
|
830
838
|
}
|
|
831
839
|
if (removed.length === 0) return;
|
|
832
840
|
invalidate();
|
|
833
|
-
|
|
841
|
+
for (const ticket of removed) queueEmit("unregister:ticket", ticket);
|
|
834
842
|
needsReindex = true;
|
|
835
843
|
}
|
|
836
844
|
function seek(direction = "first", from, predicate) {
|
|
837
845
|
if (collection.size === 0) return void 0;
|
|
838
846
|
if (needsReindex) reindex();
|
|
847
|
+
if (!predicate && /* @__PURE__ */ isUndefined(from)) {
|
|
848
|
+
const tickets$1 = values();
|
|
849
|
+
return direction === "first" ? tickets$1[0] : tickets$1.at(-1);
|
|
850
|
+
}
|
|
839
851
|
const tickets = values();
|
|
840
|
-
const index = /* @__PURE__ */ isUndefined(from) ? void 0 :
|
|
852
|
+
const index = /* @__PURE__ */ isUndefined(from) ? void 0 : /* @__PURE__ */ clamp(from, 0, tickets.length - 1);
|
|
841
853
|
if (direction === "last") {
|
|
842
854
|
const start = /* @__PURE__ */ isUndefined(index) ? tickets.length - 1 : index;
|
|
843
855
|
for (let i = start; i >= 0; i--) {
|
|
@@ -1170,7 +1182,7 @@ function useSelection(namespace = "v0:selection") {
|
|
|
1170
1182
|
* ```
|
|
1171
1183
|
*/
|
|
1172
1184
|
function toArray(value) {
|
|
1173
|
-
return /* @__PURE__ */ isNullOrUndefined(value) ? [] :
|
|
1185
|
+
return /* @__PURE__ */ isNullOrUndefined(value) ? [] : /* @__PURE__ */ isArray(value) ? value : [value];
|
|
1174
1186
|
}
|
|
1175
1187
|
|
|
1176
1188
|
//#endregion
|
|
@@ -1262,7 +1274,8 @@ function useProxyModel(registry, model, options) {
|
|
|
1262
1274
|
flush: "sync",
|
|
1263
1275
|
deep: multiple
|
|
1264
1276
|
});
|
|
1265
|
-
function onRegister(
|
|
1277
|
+
function onRegister(data) {
|
|
1278
|
+
const ticket = data;
|
|
1266
1279
|
if (!pending.has(ticket.value) || ticket.disabled) return;
|
|
1267
1280
|
registryWatch.pause();
|
|
1268
1281
|
modelWatch.pause();
|
|
@@ -1632,1345 +1645,1350 @@ function useGroup(namespace = "v0:group") {
|
|
|
1632
1645
|
}
|
|
1633
1646
|
|
|
1634
1647
|
//#endregion
|
|
1635
|
-
//#region src/composables/
|
|
1648
|
+
//#region src/composables/useSingle/index.ts
|
|
1636
1649
|
/**
|
|
1637
|
-
* @module
|
|
1638
|
-
*
|
|
1639
|
-
* @see https://0.vuetifyjs.com/composables/plugins/use-hydration
|
|
1650
|
+
* @module useSingle
|
|
1640
1651
|
*
|
|
1641
1652
|
* @remarks
|
|
1642
|
-
*
|
|
1653
|
+
* Single-selection composable that extends useSelection to enforce only one selected item.
|
|
1643
1654
|
*
|
|
1644
1655
|
* Key features:
|
|
1645
|
-
* -
|
|
1646
|
-
* -
|
|
1647
|
-
* -
|
|
1648
|
-
* - Plugin installation support
|
|
1649
|
-
* - Perfect for hydration-safe rendering
|
|
1656
|
+
* - Auto-clears previous selection when selecting new item
|
|
1657
|
+
* - Singular computed properties (selectedId, selectedItem, selectedIndex, selectedValue)
|
|
1658
|
+
* - Perfect for tabs, radio buttons, theme selectors
|
|
1650
1659
|
*
|
|
1651
|
-
*
|
|
1660
|
+
* Inheritance chain: useRegistry → useSelection → useSingle
|
|
1652
1661
|
*/
|
|
1653
1662
|
/**
|
|
1654
|
-
* Creates a new
|
|
1663
|
+
* Creates a new single selection instance that enforces only one selected item at a time.
|
|
1655
1664
|
*
|
|
1656
|
-
*
|
|
1665
|
+
* Extends `createSelection` by automatically clearing previous selections when a new item is selected.
|
|
1666
|
+
* Adds computed singular properties: `selectedId`, `selectedItem`, `selectedIndex`, `selectedValue`.
|
|
1657
1667
|
*
|
|
1658
|
-
* @
|
|
1668
|
+
* @param options The options for the single selection instance.
|
|
1669
|
+
* @template Z The type of the single selection ticket.
|
|
1670
|
+
* @template E The type of the single selection context.
|
|
1671
|
+
* @returns A new single selection instance with single-selection enforcement.
|
|
1659
1672
|
*
|
|
1660
|
-
* @
|
|
1661
|
-
*
|
|
1662
|
-
*
|
|
1673
|
+
* @remarks
|
|
1674
|
+
* **Key Differences from `createSelection`:**
|
|
1675
|
+
* - Automatically clears `selectedIds` before selecting a new item (enforces single selection)
|
|
1676
|
+
* - Provides singular computed properties instead of plural sets
|
|
1677
|
+
* - Perfect for tabs, radio buttons, theme selectors, and other single-choice UI components
|
|
1663
1678
|
*
|
|
1664
|
-
*
|
|
1665
|
-
*
|
|
1666
|
-
*
|
|
1667
|
-
*
|
|
1668
|
-
*
|
|
1669
|
-
*/
|
|
1670
|
-
function createHydration() {
|
|
1671
|
-
const isHydrated = shallowRef(false);
|
|
1672
|
-
function hydrate() {
|
|
1673
|
-
isHydrated.value = true;
|
|
1674
|
-
}
|
|
1675
|
-
return {
|
|
1676
|
-
isHydrated: shallowReadonly(isHydrated),
|
|
1677
|
-
hydrate
|
|
1678
|
-
};
|
|
1679
|
-
}
|
|
1680
|
-
function createFallbackHydration() {
|
|
1681
|
-
return {
|
|
1682
|
-
isHydrated: shallowReadonly(shallowRef(true)),
|
|
1683
|
-
hydrate: () => {}
|
|
1684
|
-
};
|
|
1685
|
-
}
|
|
1686
|
-
/**
|
|
1687
|
-
* Creates a new hydration context trinity.
|
|
1679
|
+
* **Computed Properties:**
|
|
1680
|
+
* - `selectedId`: The ID of the selected item (undefined if none selected)
|
|
1681
|
+
* - `selectedItem`: The selected ticket object (undefined if none selected)
|
|
1682
|
+
* - `selectedIndex`: The index of the selected item (-1 if none selected)
|
|
1683
|
+
* - `selectedValue`: The value of the selected item (undefined if none selected)
|
|
1688
1684
|
*
|
|
1689
|
-
*
|
|
1690
|
-
*
|
|
1691
|
-
* @returns A new hydration context trinity.
|
|
1685
|
+
* **Inheritance Chain:**
|
|
1686
|
+
* `useRegistry` → `createSelection` → `createSingle` → `createStep`
|
|
1692
1687
|
*
|
|
1693
|
-
* @see https://0.vuetifyjs.com/composables/
|
|
1688
|
+
* @see https://0.vuetifyjs.com/composables/selection/use-single
|
|
1694
1689
|
*
|
|
1695
1690
|
* @example
|
|
1696
1691
|
* ```ts
|
|
1697
|
-
* import {
|
|
1692
|
+
* import { createSingle } from '@vuetify/v0'
|
|
1698
1693
|
*
|
|
1699
|
-
*
|
|
1700
|
-
*
|
|
1701
|
-
*
|
|
1694
|
+
* const tabs = createSingle({ mandatory: true })
|
|
1695
|
+
*
|
|
1696
|
+
* tabs.onboard([
|
|
1697
|
+
* { id: 'home', value: 'Home' },
|
|
1698
|
+
* { id: 'about', value: 'About' },
|
|
1699
|
+
* { id: 'contact', value: 'Contact' },
|
|
1700
|
+
* ])
|
|
1701
|
+
*
|
|
1702
|
+
* tabs.first() // Select first tab
|
|
1703
|
+
*
|
|
1704
|
+
* console.log(tabs.selectedId.value) // 'home'
|
|
1705
|
+
* console.log(tabs.selectedIndex.value) // 0
|
|
1706
|
+
*
|
|
1707
|
+
* tabs.select('about') // Switch to about tab
|
|
1708
|
+
* console.log(tabs.selectedId.value) // 'about'
|
|
1709
|
+
* console.log(tabs.selectedIds.size) // 1 (always enforces single selection)
|
|
1702
1710
|
* ```
|
|
1703
1711
|
*/
|
|
1704
|
-
function
|
|
1705
|
-
const {
|
|
1706
|
-
const
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1712
|
+
function createSingle(_options = {}) {
|
|
1713
|
+
const { mandatory = false, multiple = false, ...options } = _options;
|
|
1714
|
+
const registry = createSelection({
|
|
1715
|
+
...options,
|
|
1716
|
+
mandatory,
|
|
1717
|
+
multiple
|
|
1718
|
+
});
|
|
1719
|
+
const selectedId = computed(() => registry.selectedIds.values().next().value);
|
|
1720
|
+
const selectedItem = computed(() => registry.selectedItems.value.values().next().value);
|
|
1721
|
+
const selectedIndex = computed(() => selectedItem.value?.index ?? -1);
|
|
1722
|
+
const selectedValue = computed(() => selectedItem.value?.value);
|
|
1723
|
+
function unselect(id) {
|
|
1724
|
+
if (mandatory && registry.selectedIds.size === 1) return;
|
|
1725
|
+
registry.selectedIds.delete(id);
|
|
1710
1726
|
}
|
|
1711
|
-
|
|
1727
|
+
function toggle(id) {
|
|
1728
|
+
if (registry.selectedIds.has(id)) unselect(id);
|
|
1729
|
+
else registry.select(id);
|
|
1730
|
+
}
|
|
1731
|
+
return {
|
|
1732
|
+
...registry,
|
|
1733
|
+
selectedId,
|
|
1734
|
+
selectedItem,
|
|
1735
|
+
selectedIndex,
|
|
1736
|
+
selectedValue,
|
|
1737
|
+
unselect,
|
|
1738
|
+
toggle,
|
|
1739
|
+
get size() {
|
|
1740
|
+
return registry.size;
|
|
1741
|
+
}
|
|
1742
|
+
};
|
|
1712
1743
|
}
|
|
1713
1744
|
/**
|
|
1714
|
-
* Creates a new
|
|
1745
|
+
* Creates a new single selection context.
|
|
1715
1746
|
*
|
|
1716
|
-
* @param options The options for the
|
|
1717
|
-
* @template
|
|
1718
|
-
* @
|
|
1747
|
+
* @param options The options for the single selection context.
|
|
1748
|
+
* @template Z The type of the single selection ticket.
|
|
1749
|
+
* @template E The type of the single selection context.
|
|
1750
|
+
* @returns A new single selection context.
|
|
1719
1751
|
*
|
|
1720
|
-
* @see https://0.vuetifyjs.com/composables/
|
|
1752
|
+
* @see https://0.vuetifyjs.com/composables/selection/use-single
|
|
1721
1753
|
*
|
|
1722
1754
|
* @example
|
|
1723
1755
|
* ```ts
|
|
1724
|
-
* import {
|
|
1725
|
-
* import { createHydrationPlugin } from '@vuetify/v0'
|
|
1726
|
-
* import App from './App.vue'
|
|
1756
|
+
* import { createSingleContext } from '@vuetify/v0'
|
|
1727
1757
|
*
|
|
1728
|
-
*
|
|
1758
|
+
* // With default namespace 'v0:single'
|
|
1759
|
+
* export const [useSingle, provideSingle, context] = createSingleContext()
|
|
1729
1760
|
*
|
|
1730
|
-
*
|
|
1761
|
+
* // In a parent component:
|
|
1762
|
+
* provideSingle()
|
|
1731
1763
|
*
|
|
1732
|
-
*
|
|
1764
|
+
* // In a child component:
|
|
1765
|
+
* const single = useSingle()
|
|
1766
|
+
* single.select('tab-1')
|
|
1733
1767
|
* ```
|
|
1734
1768
|
*/
|
|
1735
|
-
function
|
|
1736
|
-
const { namespace = "v0:
|
|
1737
|
-
const [,
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
provide: (app) => {
|
|
1744
|
-
provideHydrationContext(context, app);
|
|
1745
|
-
},
|
|
1746
|
-
setup: (app) => {
|
|
1747
|
-
app.mixin({ mounted() {
|
|
1748
|
-
if (this.$parent !== null) return;
|
|
1749
|
-
context.hydrate();
|
|
1750
|
-
} });
|
|
1751
|
-
}
|
|
1752
|
-
});
|
|
1769
|
+
function createSingleContext(_options = {}) {
|
|
1770
|
+
const { namespace = "v0:single", ...options } = _options;
|
|
1771
|
+
const [useSingleContext, _provideSingleContext] = createContext(namespace);
|
|
1772
|
+
const context = createSingle(options);
|
|
1773
|
+
function provideSingleContext(_context = context, app) {
|
|
1774
|
+
return _provideSingleContext(_context, app);
|
|
1775
|
+
}
|
|
1776
|
+
return createTrinity(useSingleContext, provideSingleContext, context);
|
|
1753
1777
|
}
|
|
1754
1778
|
/**
|
|
1755
|
-
* Returns the current
|
|
1779
|
+
* Returns the current single selection instance.
|
|
1756
1780
|
*
|
|
1757
|
-
* @param namespace The namespace for the
|
|
1758
|
-
* @returns The current
|
|
1781
|
+
* @param namespace The namespace for the single selection context. Defaults to `'v0:single'`.
|
|
1782
|
+
* @returns The current single selection instance.
|
|
1759
1783
|
*
|
|
1760
|
-
* @see https://0.vuetifyjs.com/composables/
|
|
1784
|
+
* @see https://0.vuetifyjs.com/composables/selection/use-single
|
|
1761
1785
|
*
|
|
1762
1786
|
* @example
|
|
1763
1787
|
* ```vue
|
|
1764
1788
|
* <script setup lang="ts">
|
|
1765
|
-
* import {
|
|
1789
|
+
* import { useSingle } from '@vuetify/v0'
|
|
1766
1790
|
*
|
|
1767
|
-
* const
|
|
1791
|
+
* const tabs = useSingle()
|
|
1768
1792
|
* <\/script>
|
|
1769
1793
|
*
|
|
1770
1794
|
* <template>
|
|
1771
1795
|
* <div>
|
|
1772
|
-
* <p>
|
|
1796
|
+
* <p>Selected: {{ tabs.selectedId }}</p>
|
|
1773
1797
|
* </div>
|
|
1774
1798
|
* </template>
|
|
1775
1799
|
* ```
|
|
1776
1800
|
*/
|
|
1777
|
-
function
|
|
1778
|
-
|
|
1779
|
-
if (!getCurrentInstance()) return fallback;
|
|
1780
|
-
try {
|
|
1781
|
-
return useContext(namespace, fallback);
|
|
1782
|
-
} catch {
|
|
1783
|
-
return fallback;
|
|
1784
|
-
}
|
|
1801
|
+
function useSingle(namespace = "v0:single") {
|
|
1802
|
+
return useContext(namespace);
|
|
1785
1803
|
}
|
|
1786
1804
|
|
|
1787
1805
|
//#endregion
|
|
1788
|
-
//#region src/composables/
|
|
1806
|
+
//#region src/composables/useTokens/index.ts
|
|
1789
1807
|
/**
|
|
1790
|
-
* @module
|
|
1808
|
+
* @module useTokens
|
|
1809
|
+
*
|
|
1810
|
+
* @see https://0.vuetifyjs.com/composables/registration/use-tokens
|
|
1791
1811
|
*
|
|
1792
1812
|
* @remarks
|
|
1793
|
-
*
|
|
1813
|
+
* Design token registry with alias resolution and W3C Design Tokens format support.
|
|
1794
1814
|
*
|
|
1795
1815
|
* Key features:
|
|
1796
|
-
* -
|
|
1797
|
-
* -
|
|
1798
|
-
* -
|
|
1799
|
-
* -
|
|
1800
|
-
* -
|
|
1801
|
-
* - Box model options (content-box/border-box)
|
|
1816
|
+
* - Alias resolution with circular reference detection
|
|
1817
|
+
* - Nested token flattening with dot notation
|
|
1818
|
+
* - W3C Design Tokens format ($value, $type, $description, $extensions)
|
|
1819
|
+
* - Path-based resolution (e.g., {colors}.blue.500)
|
|
1820
|
+
* - Resolution caching for performance (~28,590 ops/sec)
|
|
1802
1821
|
*
|
|
1803
|
-
*
|
|
1822
|
+
* Used by useTheme, useLocale, and useFeatures for token-based configuration.
|
|
1804
1823
|
*/
|
|
1805
1824
|
/**
|
|
1806
|
-
*
|
|
1807
|
-
* size changes.
|
|
1825
|
+
* Creates a new token instance.
|
|
1808
1826
|
*
|
|
1809
|
-
* @param
|
|
1810
|
-
* @param
|
|
1811
|
-
* @
|
|
1812
|
-
* @
|
|
1827
|
+
* @param tokens The tokens to use.
|
|
1828
|
+
* @param options The options for the token instance.
|
|
1829
|
+
* @template Z The type of the token ticket.
|
|
1830
|
+
* @template E The type of the token context.
|
|
1831
|
+
* @returns A new token instance.
|
|
1813
1832
|
*
|
|
1814
|
-
* @see https://
|
|
1815
|
-
* @see https://0.vuetifyjs.com/composables/
|
|
1833
|
+
* @see https://www.designtokens.org/tr/drafts/format/
|
|
1834
|
+
* @see https://0.vuetifyjs.com/composables/registration/use-tokens
|
|
1816
1835
|
*
|
|
1817
1836
|
* @example
|
|
1818
1837
|
* ```ts
|
|
1819
|
-
* import {
|
|
1820
|
-
* import { useResizeObserver } from '@vuetify/v0'
|
|
1821
|
-
*
|
|
1822
|
-
* const el = ref<HTMLElement>()
|
|
1823
|
-
* const width = ref(0)
|
|
1824
|
-
* const height = ref(0)
|
|
1838
|
+
* import { useTokens } from '@vuetify/v0'
|
|
1825
1839
|
*
|
|
1826
|
-
* const
|
|
1827
|
-
*
|
|
1828
|
-
*
|
|
1829
|
-
*
|
|
1830
|
-
* if (entry) {
|
|
1831
|
-
* width.value = entry.contentRect.width
|
|
1832
|
-
* height.value = entry.contentRect.height
|
|
1833
|
-
* console.log('Size changed:', width.value, 'x', height.value)
|
|
1834
|
-
* }
|
|
1840
|
+
* const tokens = useTokens({
|
|
1841
|
+
* colors: {
|
|
1842
|
+
* primary: '#3b82f6',
|
|
1843
|
+
* secondary: '{colors.primary}', // Alias reference
|
|
1835
1844
|
* },
|
|
1836
|
-
*
|
|
1837
|
-
* )
|
|
1838
|
-
*
|
|
1839
|
-
* // Pause observation
|
|
1840
|
-
* pause()
|
|
1845
|
+
* })
|
|
1841
1846
|
*
|
|
1842
|
-
* //
|
|
1843
|
-
*
|
|
1847
|
+
* console.log(tokens.resolve('{colors.primary}')) // '#3b82f6'
|
|
1848
|
+
* console.log(tokens.resolve('{colors.secondary}')) // '#3b82f6'
|
|
1844
1849
|
* ```
|
|
1845
1850
|
*/
|
|
1846
|
-
function
|
|
1847
|
-
const
|
|
1848
|
-
const
|
|
1849
|
-
const
|
|
1850
|
-
|
|
1851
|
-
function
|
|
1852
|
-
|
|
1853
|
-
observer.value = new ResizeObserver((entries) => {
|
|
1854
|
-
callback(entries.map((entry) => ({
|
|
1855
|
-
contentRect: {
|
|
1856
|
-
width: entry.contentRect.width,
|
|
1857
|
-
height: entry.contentRect.height,
|
|
1858
|
-
top: entry.contentRect.top,
|
|
1859
|
-
left: entry.contentRect.left
|
|
1860
|
-
},
|
|
1861
|
-
target: entry.target
|
|
1862
|
-
})));
|
|
1863
|
-
});
|
|
1864
|
-
observer.value.observe(target.value, { box: options.box || "content-box" });
|
|
1865
|
-
if (options.immediate) {
|
|
1866
|
-
const rect = target.value.getBoundingClientRect();
|
|
1867
|
-
callback([{
|
|
1868
|
-
contentRect: {
|
|
1869
|
-
width: rect.width,
|
|
1870
|
-
height: rect.height,
|
|
1871
|
-
top: rect.top,
|
|
1872
|
-
left: rect.left
|
|
1873
|
-
},
|
|
1874
|
-
target: target.value
|
|
1875
|
-
}]);
|
|
1876
|
-
}
|
|
1877
|
-
}
|
|
1878
|
-
watch([isHydrated, target], () => {
|
|
1879
|
-
cleanup();
|
|
1880
|
-
setup();
|
|
1881
|
-
}, { immediate: true });
|
|
1882
|
-
function cleanup() {
|
|
1883
|
-
if (observer.value) {
|
|
1884
|
-
observer.value.disconnect();
|
|
1885
|
-
observer.value = void 0;
|
|
1886
|
-
}
|
|
1887
|
-
}
|
|
1888
|
-
function pause() {
|
|
1889
|
-
isPaused.value = true;
|
|
1890
|
-
observer.value?.disconnect();
|
|
1851
|
+
function createTokens(tokens = {}, options = {}) {
|
|
1852
|
+
const logger = useLogger();
|
|
1853
|
+
const registry = useRegistry(options);
|
|
1854
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1855
|
+
registry.onboard(flatten(tokens, options.prefix, !!options.flat));
|
|
1856
|
+
function isAlias(token) {
|
|
1857
|
+
return /* @__PURE__ */ isString(token) && token.length > 2 && token[0] === "{" && token.at(-1) === "}";
|
|
1891
1858
|
}
|
|
1892
|
-
function
|
|
1893
|
-
|
|
1894
|
-
setup();
|
|
1859
|
+
function isTokenAlias(value) {
|
|
1860
|
+
return /* @__PURE__ */ isObject(value) && "$value" in value;
|
|
1895
1861
|
}
|
|
1896
|
-
function
|
|
1897
|
-
|
|
1862
|
+
function resolve(token, visited = /* @__PURE__ */ new Set()) {
|
|
1863
|
+
const cacheKey = /* @__PURE__ */ isString(token) ? token : JSON.stringify(token);
|
|
1864
|
+
const cached = cache.get(cacheKey);
|
|
1865
|
+
if (!/* @__PURE__ */ isUndefined(cached)) return cached;
|
|
1866
|
+
const reference = isTokenAlias(token) ? token.$value : token;
|
|
1867
|
+
const isAliasReference = /* @__PURE__ */ isString(reference) && isAlias(reference);
|
|
1868
|
+
const clean = isAliasReference ? reference.slice(1, -1) : String(reference);
|
|
1869
|
+
if (visited.has(clean)) {
|
|
1870
|
+
logger.warn(`Circular alias detected for "${clean}"`);
|
|
1871
|
+
cache.set(cacheKey, void 0);
|
|
1872
|
+
return;
|
|
1873
|
+
}
|
|
1874
|
+
visited.add(clean);
|
|
1875
|
+
let found = registry.get(clean);
|
|
1876
|
+
let segments = [];
|
|
1877
|
+
if (!found && clean.includes(".")) {
|
|
1878
|
+
const parts = clean.split(".");
|
|
1879
|
+
for (let i = parts.length - 1; i > 0; i--) {
|
|
1880
|
+
const prefix = parts.slice(0, i).join(".");
|
|
1881
|
+
const suffix = parts.slice(i);
|
|
1882
|
+
const candidate = registry.get(prefix);
|
|
1883
|
+
if (!/* @__PURE__ */ isUndefined(candidate?.value)) {
|
|
1884
|
+
found = candidate;
|
|
1885
|
+
segments = suffix;
|
|
1886
|
+
break;
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
if (/* @__PURE__ */ isUndefined(found?.value)) {
|
|
1891
|
+
if (isAliasReference) logger.warn(`Alias not found for "${String(reference)}"`);
|
|
1892
|
+
cache.set(cacheKey, void 0);
|
|
1893
|
+
return;
|
|
1894
|
+
}
|
|
1895
|
+
let result;
|
|
1896
|
+
let current = found.value;
|
|
1897
|
+
if (segments.length > 0) {
|
|
1898
|
+
if (isTokenAlias(current)) current = current.$value;
|
|
1899
|
+
for (const segment of segments) {
|
|
1900
|
+
if (!/* @__PURE__ */ isObject(current) || !(segment in current)) {
|
|
1901
|
+
current = void 0;
|
|
1902
|
+
break;
|
|
1903
|
+
}
|
|
1904
|
+
current = current[segment];
|
|
1905
|
+
if (isTokenAlias(current)) current = current.$value;
|
|
1906
|
+
}
|
|
1907
|
+
if (/* @__PURE__ */ isUndefined(current)) {
|
|
1908
|
+
logger.warn(`Path not found inside "${clean}": ${segments.join(".")}`);
|
|
1909
|
+
cache.set(cacheKey, void 0);
|
|
1910
|
+
return;
|
|
1911
|
+
}
|
|
1912
|
+
result = current;
|
|
1913
|
+
} else if (isTokenAlias(current)) {
|
|
1914
|
+
const inner = current.$value;
|
|
1915
|
+
if (/* @__PURE__ */ isString(inner) && isAlias(inner)) return resolve(inner, visited);
|
|
1916
|
+
result = inner;
|
|
1917
|
+
} else if (/* @__PURE__ */ isString(current) && isAlias(current)) return resolve(current, visited);
|
|
1918
|
+
else result = current;
|
|
1919
|
+
cache.set(cacheKey, result);
|
|
1920
|
+
return result;
|
|
1898
1921
|
}
|
|
1899
|
-
onScopeDispose(stop, true);
|
|
1900
1922
|
return {
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1923
|
+
...registry,
|
|
1924
|
+
resolve,
|
|
1925
|
+
isAlias,
|
|
1926
|
+
get size() {
|
|
1927
|
+
return registry.size;
|
|
1928
|
+
}
|
|
1906
1929
|
};
|
|
1907
1930
|
}
|
|
1908
1931
|
/**
|
|
1909
|
-
*
|
|
1910
|
-
* element's size.
|
|
1932
|
+
* Creates a new token context.
|
|
1911
1933
|
*
|
|
1912
|
-
* @param
|
|
1913
|
-
* @
|
|
1934
|
+
* @param namespace The namespace for the token context.
|
|
1935
|
+
* @param tokens The tokens to use.
|
|
1936
|
+
* @template Z The type of the token ticket.
|
|
1937
|
+
* @template E The type of the token context.
|
|
1938
|
+
* @returns A new token context.
|
|
1914
1939
|
*
|
|
1915
|
-
* @see https://0.vuetifyjs.com/composables/
|
|
1940
|
+
* @see https://0.vuetifyjs.com/composables/registration/use-tokens
|
|
1916
1941
|
*
|
|
1917
1942
|
* @example
|
|
1918
1943
|
* ```ts
|
|
1919
|
-
* import {
|
|
1920
|
-
* import { useElementSize } from '@vuetify/v0'
|
|
1921
|
-
*
|
|
1922
|
-
* const box = ref<HTMLElement>()
|
|
1923
|
-
* const { width, height } = useElementSize(box)
|
|
1944
|
+
* import { createTokensContext } from '@vuetify/v0'
|
|
1924
1945
|
*
|
|
1925
|
-
*
|
|
1926
|
-
*
|
|
1927
|
-
*
|
|
1946
|
+
* export const [useTokens, provideTokens, context] = createTokensContext({
|
|
1947
|
+
* namespace: 'v0:tokens',
|
|
1948
|
+
* tokens: {
|
|
1949
|
+
* colors: {
|
|
1950
|
+
* primary: '#3b82f6',
|
|
1951
|
+
* secondary: '{colors.primary}', // Alias reference
|
|
1952
|
+
* },
|
|
1953
|
+
* },
|
|
1928
1954
|
* })
|
|
1929
1955
|
* ```
|
|
1930
1956
|
*/
|
|
1931
|
-
function
|
|
1932
|
-
const
|
|
1933
|
-
const
|
|
1934
|
-
const
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
width.value = entry.contentRect.width;
|
|
1938
|
-
height.value = entry.contentRect.height;
|
|
1939
|
-
}
|
|
1940
|
-
}, { immediate: true });
|
|
1941
|
-
function pause() {
|
|
1942
|
-
width.value = 0;
|
|
1943
|
-
height.value = 0;
|
|
1944
|
-
_pause();
|
|
1957
|
+
function createTokensContext(_options) {
|
|
1958
|
+
const { namespace = "v0:tokens", tokens = {}, ...options } = _options;
|
|
1959
|
+
const [useTokensContext, _provideTokensContext] = createContext(namespace);
|
|
1960
|
+
const context = createTokens(tokens, options);
|
|
1961
|
+
function provideTokensContext(_context = context, app) {
|
|
1962
|
+
return _provideTokensContext(_context, app);
|
|
1945
1963
|
}
|
|
1946
|
-
return
|
|
1947
|
-
width,
|
|
1948
|
-
height,
|
|
1949
|
-
isActive,
|
|
1950
|
-
isPaused,
|
|
1951
|
-
pause,
|
|
1952
|
-
resume,
|
|
1953
|
-
stop
|
|
1954
|
-
};
|
|
1964
|
+
return createTrinity(useTokensContext, provideTokensContext, context);
|
|
1955
1965
|
}
|
|
1956
|
-
|
|
1957
|
-
//#endregion
|
|
1958
|
-
//#region src/composables/useOverflow/index.ts
|
|
1959
1966
|
/**
|
|
1960
|
-
*
|
|
1961
|
-
*
|
|
1962
|
-
* @remarks
|
|
1963
|
-
* Composable for computing how many items fit in a container based on available width.
|
|
1964
|
-
* Enables responsive truncation logic for Pagination, Breadcrumbs, and similar components.
|
|
1965
|
-
*
|
|
1966
|
-
* Key features:
|
|
1967
|
-
* - Container width tracking via ResizeObserver
|
|
1968
|
-
* - Two modes: variable-width (per-item) or uniform-width (sample-based)
|
|
1969
|
-
* - Computes capacity (how many items fit)
|
|
1970
|
-
* - SSR-safe with Infinity fallback
|
|
1971
|
-
* - Supports reserved space for nav buttons, ellipsis, etc.
|
|
1967
|
+
* Returns the current tokens instance.
|
|
1972
1968
|
*
|
|
1973
|
-
*
|
|
1974
|
-
*
|
|
1975
|
-
*/
|
|
1976
|
-
/**
|
|
1977
|
-
* Creates a new overflow context for computing how many items fit in a container.
|
|
1969
|
+
* @param namespace The namespace for the tokens context. Defaults to `'v0:tokens'`.
|
|
1970
|
+
* @returns The current tokens instance.
|
|
1978
1971
|
*
|
|
1979
|
-
* @
|
|
1980
|
-
* @returns Overflow context with container ref, capacity, and measurement functions
|
|
1972
|
+
* @see https://0.vuetifyjs.com/composables/registration/use-tokens
|
|
1981
1973
|
*
|
|
1982
|
-
* @example
|
|
1974
|
+
* @example
|
|
1983
1975
|
* ```vue
|
|
1984
|
-
* <script lang="ts"
|
|
1985
|
-
* import {
|
|
1986
|
-
* import { createOverflow } from '@vuetify/v0'
|
|
1976
|
+
* <script setup lang="ts">
|
|
1977
|
+
* import { useTokens } from '@vuetify/v0'
|
|
1987
1978
|
*
|
|
1988
|
-
* const
|
|
1989
|
-
* const overflow = createOverflow({
|
|
1990
|
-
* container: containerRef,
|
|
1991
|
-
* gap: 8,
|
|
1992
|
-
* reserved: 40,
|
|
1993
|
-
* })
|
|
1979
|
+
* const tokens = useTokens()
|
|
1994
1980
|
* <\/script>
|
|
1995
|
-
*
|
|
1996
|
-
* <template>
|
|
1997
|
-
* <div ref="container">
|
|
1998
|
-
* <span
|
|
1999
|
-
* v-for="(item, i) in items.slice(0, overflow.capacity.value)"
|
|
2000
|
-
* :key="i"
|
|
2001
|
-
* :ref="el => overflow.measure(i, el)"
|
|
2002
|
-
* >
|
|
2003
|
-
* {{ item }}
|
|
2004
|
-
* </span>
|
|
2005
|
-
* <span v-if="overflow.isOverflowing.value">...</span>
|
|
2006
|
-
* </div>
|
|
2007
|
-
* </template>
|
|
2008
|
-
* ```
|
|
2009
|
-
*
|
|
2010
|
-
* @example Uniform-width mode (Pagination)
|
|
2011
|
-
* ```ts
|
|
2012
|
-
* const overflow = createOverflow({
|
|
2013
|
-
* container: () => atom.value?.element,
|
|
2014
|
-
* itemWidth: buttonWidth,
|
|
2015
|
-
* reserved: () => buttonWidth.value * 4,
|
|
2016
|
-
* })
|
|
2017
1981
|
* ```
|
|
2018
1982
|
*/
|
|
2019
|
-
function
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
1983
|
+
function useTokens(namespace = "v0:tokens") {
|
|
1984
|
+
return useContext(namespace);
|
|
1985
|
+
}
|
|
1986
|
+
/**
|
|
1987
|
+
* Flattens a nested collection of tokens into a flat array of tokens.
|
|
1988
|
+
* Each token is represented by an object containing its ID & value.
|
|
1989
|
+
* @param tokens The collection of tokens to flatten.
|
|
1990
|
+
* @param prefix An optional prefix to prepend to each token ID.
|
|
1991
|
+
* @returns An array of flattened tokens, each with an ID and value.
|
|
1992
|
+
*/
|
|
1993
|
+
function flatten(tokens, prefix = "", flat = false) {
|
|
1994
|
+
const flattened = [];
|
|
1995
|
+
const stack = [{
|
|
1996
|
+
tokens,
|
|
1997
|
+
prefix,
|
|
1998
|
+
flat
|
|
1999
|
+
}];
|
|
2000
|
+
while (stack.length > 0) {
|
|
2001
|
+
const { tokens: currentTokens, prefix: currentPrefix, flat: flat$1 } = stack.pop();
|
|
2002
|
+
const meta = {};
|
|
2003
|
+
for (const k in currentTokens) if (k.startsWith("$")) meta[k] = currentTokens[k];
|
|
2004
|
+
if (Object.keys(meta).length > 0 && currentPrefix) flattened.push({
|
|
2005
|
+
id: currentPrefix,
|
|
2006
|
+
value: meta
|
|
2007
|
+
});
|
|
2008
|
+
for (const key in currentTokens) {
|
|
2009
|
+
if (key.startsWith("$")) continue;
|
|
2010
|
+
const value = currentTokens[key];
|
|
2011
|
+
const id = currentPrefix ? `${currentPrefix}.${key}` : key;
|
|
2012
|
+
if (!/* @__PURE__ */ isObject(value)) {
|
|
2013
|
+
flattened.push({
|
|
2014
|
+
id,
|
|
2015
|
+
value
|
|
2016
|
+
});
|
|
2017
|
+
continue;
|
|
2030
2018
|
}
|
|
2031
|
-
|
|
2019
|
+
if ("$value" in value) {
|
|
2020
|
+
flattened.push({
|
|
2021
|
+
id,
|
|
2022
|
+
value
|
|
2023
|
+
});
|
|
2024
|
+
const inner = value.$value;
|
|
2025
|
+
if (/* @__PURE__ */ isObject(inner) && !flat$1) for (const innerKey in inner) {
|
|
2026
|
+
if (innerKey.startsWith("$")) continue;
|
|
2027
|
+
const child = inner[innerKey];
|
|
2028
|
+
const childId = `${id}.${innerKey}`;
|
|
2029
|
+
if (!/* @__PURE__ */ isObject(child)) flattened.push({
|
|
2030
|
+
id: childId,
|
|
2031
|
+
value: child
|
|
2032
|
+
});
|
|
2033
|
+
else if ("$value" in child) flattened.push({
|
|
2034
|
+
id: childId,
|
|
2035
|
+
value: child
|
|
2036
|
+
});
|
|
2037
|
+
else stack.push({
|
|
2038
|
+
tokens: child,
|
|
2039
|
+
prefix: childId,
|
|
2040
|
+
flat: flat$1
|
|
2041
|
+
});
|
|
2042
|
+
}
|
|
2043
|
+
continue;
|
|
2044
|
+
}
|
|
2045
|
+
if (flat$1) {
|
|
2046
|
+
flattened.push({
|
|
2047
|
+
id,
|
|
2048
|
+
value
|
|
2049
|
+
});
|
|
2050
|
+
continue;
|
|
2051
|
+
}
|
|
2052
|
+
stack.push({
|
|
2053
|
+
tokens: value,
|
|
2054
|
+
prefix: id,
|
|
2055
|
+
flat: flat$1
|
|
2056
|
+
});
|
|
2032
2057
|
}
|
|
2033
|
-
const style = getComputedStyle(el);
|
|
2034
|
-
const marginX = Number.parseFloat(style.marginLeft) + Number.parseFloat(style.marginRight);
|
|
2035
|
-
const w = el.offsetWidth + marginX;
|
|
2036
|
-
if (widths.value.get(index) !== w) widths.value = new Map(widths.value).set(index, w);
|
|
2037
2058
|
}
|
|
2038
|
-
|
|
2039
|
-
|
|
2059
|
+
return flattened;
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
//#endregion
|
|
2063
|
+
//#region src/composables/useLocale/adapters/v0.ts
|
|
2064
|
+
/**
|
|
2065
|
+
* Vuetify0.x locale adapter implementation
|
|
2066
|
+
*
|
|
2067
|
+
* This adapter provides translation and number formatting
|
|
2068
|
+
* capabilities using the Intl API and supports both
|
|
2069
|
+
* numbered ({0}, {1}) and named ({name}) variables in translation strings.
|
|
2070
|
+
*/
|
|
2071
|
+
var Vuetify0LocaleAdapter = class {
|
|
2072
|
+
t(message, ...params) {
|
|
2073
|
+
let resolvedMessage = message;
|
|
2074
|
+
if (params.length > 0 && /* @__PURE__ */ isObject(params[0])) {
|
|
2075
|
+
const variables = params[0];
|
|
2076
|
+
resolvedMessage = resolvedMessage.replace(/{([a-zA-Z][a-zA-Z0-9_]*)}/g, (match, name) => {
|
|
2077
|
+
return /* @__PURE__ */ isUndefined(variables[name]) ? match : String(variables[name]);
|
|
2078
|
+
});
|
|
2079
|
+
params = params.slice(1);
|
|
2080
|
+
}
|
|
2081
|
+
resolvedMessage = resolvedMessage.replace(/\{(\d+)\}/g, (match, index) => {
|
|
2082
|
+
const idx = Number.parseInt(index, 10);
|
|
2083
|
+
if (!/* @__PURE__ */ isUndefined(params[idx])) return String(params[idx]);
|
|
2084
|
+
return match;
|
|
2085
|
+
});
|
|
2086
|
+
return resolvedMessage;
|
|
2040
2087
|
}
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2088
|
+
n(value, locale, ...params) {
|
|
2089
|
+
if (!IN_BROWSER || !locale) return value.toString();
|
|
2090
|
+
const options = params[0];
|
|
2091
|
+
return new Intl.NumberFormat(String(locale), options).format(value);
|
|
2092
|
+
}
|
|
2093
|
+
};
|
|
2094
|
+
|
|
2095
|
+
//#endregion
|
|
2096
|
+
//#region src/composables/useLocale/index.ts
|
|
2097
|
+
/**
|
|
2098
|
+
* @module useLocale
|
|
2099
|
+
*
|
|
2100
|
+
* @remarks
|
|
2101
|
+
* Internationalization (i18n) composable with adapter pattern for message translation.
|
|
2102
|
+
*
|
|
2103
|
+
* Key features:
|
|
2104
|
+
* - Locale selection with createSingle
|
|
2105
|
+
* - Token-based message storage with useTokens
|
|
2106
|
+
* - Numbered and named placeholder support ({0}, {name})
|
|
2107
|
+
* - Number formatting with Intl.NumberFormat
|
|
2108
|
+
* - Adapter pattern for integration with i18n providers
|
|
2109
|
+
*
|
|
2110
|
+
* Integrates with createSingle for locale selection and useTokens for message resolution.
|
|
2111
|
+
*/
|
|
2112
|
+
/**
|
|
2113
|
+
* Creates a new locale instance.
|
|
2114
|
+
*
|
|
2115
|
+
* @param options The options for the locale instance.
|
|
2116
|
+
* @template Z The type of the locale ticket.
|
|
2117
|
+
* @template E The type of the locale context.
|
|
2118
|
+
* @returns A new locale instance.
|
|
2119
|
+
*
|
|
2120
|
+
* @see https://0.vuetifyjs.com/composables/plugins/use-locale
|
|
2121
|
+
*/
|
|
2122
|
+
function createLocale(_options = {}) {
|
|
2123
|
+
const { adapter = new Vuetify0LocaleAdapter(), messages = {}, ...options } = _options;
|
|
2124
|
+
const tokens = createTokens(messages);
|
|
2125
|
+
const registry = createSingle(options);
|
|
2126
|
+
for (const id in messages) {
|
|
2127
|
+
registry.register({ id });
|
|
2128
|
+
if (id === options.default && !registry.selectedId.value) registry.select(id);
|
|
2129
|
+
}
|
|
2130
|
+
function t(key, params, fallback) {
|
|
2131
|
+
const locale = registry.selectedId.value;
|
|
2132
|
+
const args = toArray(params);
|
|
2133
|
+
if (!locale) return adapter.t(fallback ?? key, ...args);
|
|
2134
|
+
const path = `${locale}.${key}`;
|
|
2135
|
+
const message = tokens.get(path)?.value;
|
|
2136
|
+
const template = /* @__PURE__ */ isString(message) ? resolve(locale, message) : fallback ?? key;
|
|
2137
|
+
return adapter.t(template, ...args);
|
|
2138
|
+
}
|
|
2139
|
+
function n(value, ...params) {
|
|
2140
|
+
return adapter.n(value, registry.selectedId.value, ...params);
|
|
2141
|
+
}
|
|
2142
|
+
function resolve(locale, str) {
|
|
2143
|
+
return str.replace(/{([a-zA-Z0-9.-_]+)}/g, (match, key) => {
|
|
2144
|
+
const [prefix, ...rest] = key.split(".");
|
|
2145
|
+
const target = registry.has(prefix) ? prefix : locale;
|
|
2146
|
+
const path = `${target}.${registry.has(prefix) ? rest.join(".") : key}`;
|
|
2147
|
+
const resolved = tokens.get(path)?.value;
|
|
2148
|
+
if (/* @__PURE__ */ isString(resolved)) return resolve(target, resolved);
|
|
2149
|
+
return match;
|
|
2150
|
+
});
|
|
2151
|
+
}
|
|
2152
|
+
return {
|
|
2153
|
+
...registry,
|
|
2154
|
+
t,
|
|
2155
|
+
n,
|
|
2156
|
+
get size() {
|
|
2157
|
+
return registry.size;
|
|
2048
2158
|
}
|
|
2049
|
-
|
|
2050
|
-
|
|
2159
|
+
};
|
|
2160
|
+
}
|
|
2161
|
+
function createLocaleFallback() {
|
|
2051
2162
|
return {
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
const available = width.value - toValue(reserved);
|
|
2056
|
-
if (width.value === 0) return Infinity;
|
|
2057
|
-
if (available <= 0) return 0;
|
|
2058
|
-
const g = toValue(gap);
|
|
2059
|
-
const uniformWidth = toValue(itemWidth);
|
|
2060
|
-
if (uniformWidth && uniformWidth > 0) {
|
|
2061
|
-
const first = uniformWidth;
|
|
2062
|
-
const subsequent = uniformWidth + g;
|
|
2063
|
-
if (available < first) return 0;
|
|
2064
|
-
return Math.max(1, Math.floor((available - first) / subsequent) + 1);
|
|
2065
|
-
}
|
|
2066
|
-
const entries = [...widths.value.entries()].toSorted((a, b) => a[0] - b[0]);
|
|
2067
|
-
if (toValue(reverse)) entries.reverse();
|
|
2068
|
-
let sum = 0;
|
|
2069
|
-
let count = 0;
|
|
2070
|
-
for (const [, w] of entries) {
|
|
2071
|
-
const next = sum + w + (count > 0 ? g : 0);
|
|
2072
|
-
if (next > available) break;
|
|
2073
|
-
sum = next;
|
|
2074
|
-
count++;
|
|
2075
|
-
}
|
|
2076
|
-
return count;
|
|
2077
|
-
}),
|
|
2078
|
-
total,
|
|
2079
|
-
isOverflowing: toRef(() => {
|
|
2080
|
-
return total.value > width.value - toValue(reserved);
|
|
2081
|
-
}),
|
|
2082
|
-
measure,
|
|
2083
|
-
reset
|
|
2163
|
+
size: 0,
|
|
2164
|
+
t: (key, _params, fallback) => fallback ?? key,
|
|
2165
|
+
n: String
|
|
2084
2166
|
};
|
|
2085
2167
|
}
|
|
2086
2168
|
/**
|
|
2087
|
-
* Creates
|
|
2169
|
+
* Creates a new locale context.
|
|
2088
2170
|
*
|
|
2089
|
-
* @param options
|
|
2090
|
-
* @
|
|
2171
|
+
* @param options The options for the locale context.
|
|
2172
|
+
* @template Z The type of the locale ticket.
|
|
2173
|
+
* @template E The type of the locale context.
|
|
2174
|
+
* @returns A new locale context.
|
|
2175
|
+
*
|
|
2176
|
+
* @see https://0.vuetifyjs.com/composables/plugins/use-locale
|
|
2091
2177
|
*
|
|
2092
2178
|
* @example
|
|
2093
2179
|
* ```ts
|
|
2094
|
-
*
|
|
2095
|
-
*
|
|
2096
|
-
*
|
|
2097
|
-
*
|
|
2098
|
-
*
|
|
2180
|
+
* import { createLocaleContext } from '@vuetify/v0'
|
|
2181
|
+
*
|
|
2182
|
+
* export const [useAppLocale, provideAppLocale, appLocale] = createLocaleContext({
|
|
2183
|
+
* namespace: 'app:locale',
|
|
2184
|
+
* messages: {
|
|
2185
|
+
* en: { hello: 'Hello' },
|
|
2186
|
+
* es: { hello: 'Hola' },
|
|
2187
|
+
* },
|
|
2099
2188
|
* })
|
|
2100
2189
|
*
|
|
2101
|
-
* // In parent component
|
|
2102
|
-
*
|
|
2190
|
+
* // In a parent component:
|
|
2191
|
+
* provideAppLocale()
|
|
2103
2192
|
*
|
|
2104
|
-
* // In child component
|
|
2105
|
-
* const
|
|
2193
|
+
* // In a child component:
|
|
2194
|
+
* const locale = useAppLocale()
|
|
2195
|
+
* locale.select('es')
|
|
2106
2196
|
* ```
|
|
2107
2197
|
*/
|
|
2108
|
-
function
|
|
2109
|
-
const { namespace = "v0:
|
|
2110
|
-
const [
|
|
2111
|
-
const context =
|
|
2112
|
-
function
|
|
2113
|
-
return
|
|
2198
|
+
function createLocaleContext(_options = {}) {
|
|
2199
|
+
const { namespace = "v0:locale", ...options } = _options;
|
|
2200
|
+
const [useLocaleContext, _provideLocaleContext] = createContext(namespace);
|
|
2201
|
+
const context = createLocale(options);
|
|
2202
|
+
function provideLocaleContext(_context = context, app) {
|
|
2203
|
+
return _provideLocaleContext(_context, app);
|
|
2114
2204
|
}
|
|
2115
|
-
return createTrinity(
|
|
2205
|
+
return createTrinity(useLocaleContext, provideLocaleContext, context);
|
|
2206
|
+
}
|
|
2207
|
+
/**
|
|
2208
|
+
* Creates a new locale plugin.
|
|
2209
|
+
*
|
|
2210
|
+
* @param options The options for the locale plugin.
|
|
2211
|
+
* @template Z The type of the locale ticket.
|
|
2212
|
+
* @template E The type of the locale context.
|
|
2213
|
+
* @template R The type of the token ticket.
|
|
2214
|
+
* @template O The type of the token context.
|
|
2215
|
+
* @returns A new locale plugin.
|
|
2216
|
+
*
|
|
2217
|
+
* @see https://0.vuetifyjs.com/composables/plugins/use-locale
|
|
2218
|
+
*/
|
|
2219
|
+
function createLocalePlugin(_options = {}) {
|
|
2220
|
+
const { namespace = "v0:locale", adapter = new Vuetify0LocaleAdapter(), messages = {}, ...options } = _options;
|
|
2221
|
+
const [, provideLocaleContext, context] = createLocaleContext({
|
|
2222
|
+
...options,
|
|
2223
|
+
namespace,
|
|
2224
|
+
adapter,
|
|
2225
|
+
messages
|
|
2226
|
+
});
|
|
2227
|
+
return createPlugin({
|
|
2228
|
+
namespace,
|
|
2229
|
+
provide: (app) => {
|
|
2230
|
+
provideLocaleContext(context, app);
|
|
2231
|
+
}
|
|
2232
|
+
});
|
|
2116
2233
|
}
|
|
2117
2234
|
/**
|
|
2118
|
-
* Returns the current
|
|
2119
|
-
*
|
|
2120
|
-
* @param namespace The namespace for the overflow context. Defaults to `v0:overflow`.
|
|
2121
|
-
* @returns The current overflow context.
|
|
2122
|
-
*
|
|
2123
|
-
* @example
|
|
2124
|
-
* ```vue
|
|
2125
|
-
* <script lang="ts" setup>
|
|
2126
|
-
* import { useOverflow } from '@vuetify/v0'
|
|
2235
|
+
* Returns the current locale instance.
|
|
2127
2236
|
*
|
|
2128
|
-
*
|
|
2129
|
-
* const overflow = useOverflow()
|
|
2130
|
-
* <\/script>
|
|
2237
|
+
* @returns The current locale instance.
|
|
2131
2238
|
*
|
|
2132
|
-
*
|
|
2133
|
-
* <div>
|
|
2134
|
-
* <p>Capacity: {{ overflow.capacity.value }}</p>
|
|
2135
|
-
* </div>
|
|
2136
|
-
* </template>
|
|
2137
|
-
* ```
|
|
2239
|
+
* @see https://0.vuetifyjs.com/composables/plugins/use-locale
|
|
2138
2240
|
*/
|
|
2139
|
-
function
|
|
2140
|
-
|
|
2241
|
+
function useLocale(namespace = "v0:locale") {
|
|
2242
|
+
const fallback = createLocaleFallback();
|
|
2243
|
+
if (!getCurrentInstance()) return fallback;
|
|
2244
|
+
try {
|
|
2245
|
+
return useContext(namespace, fallback);
|
|
2246
|
+
} catch {
|
|
2247
|
+
return fallback;
|
|
2248
|
+
}
|
|
2141
2249
|
}
|
|
2142
2250
|
|
|
2143
2251
|
//#endregion
|
|
2144
|
-
//#region src/composables/
|
|
2252
|
+
//#region src/composables/useHydration/index.ts
|
|
2145
2253
|
/**
|
|
2146
|
-
* @module
|
|
2254
|
+
* @module useHydration
|
|
2255
|
+
*
|
|
2256
|
+
* @see https://0.vuetifyjs.com/composables/plugins/use-hydration
|
|
2147
2257
|
*
|
|
2148
2258
|
* @remarks
|
|
2149
|
-
*
|
|
2259
|
+
* SSR hydration state management composable.
|
|
2150
2260
|
*
|
|
2151
2261
|
* Key features:
|
|
2152
|
-
* -
|
|
2153
|
-
* -
|
|
2154
|
-
* -
|
|
2155
|
-
* -
|
|
2156
|
-
* -
|
|
2262
|
+
* - Hydration state detection (browser vs SSR)
|
|
2263
|
+
* - Root component detection
|
|
2264
|
+
* - Readonly hydration state refs
|
|
2265
|
+
* - Plugin installation support
|
|
2266
|
+
* - Perfect for hydration-safe rendering
|
|
2157
2267
|
*
|
|
2158
|
-
*
|
|
2159
|
-
* within a range, making it efficient for large page counts.
|
|
2268
|
+
* Essential for composables that need to behave differently during SSR vs client-side.
|
|
2160
2269
|
*/
|
|
2161
2270
|
/**
|
|
2162
|
-
* Creates a
|
|
2271
|
+
* Creates a new hydration instance.
|
|
2163
2272
|
*
|
|
2164
|
-
* @
|
|
2165
|
-
*
|
|
2273
|
+
* @returns A new hydration instance.
|
|
2274
|
+
*
|
|
2275
|
+
* @see https://0.vuetifyjs.com/composables/plugins/use-hydration
|
|
2166
2276
|
*
|
|
2167
2277
|
* @example
|
|
2168
2278
|
* ```ts
|
|
2169
|
-
* import {
|
|
2170
|
-
*
|
|
2171
|
-
* // Basic usage
|
|
2172
|
-
* const pagination = createPagination({ size: 100 })
|
|
2173
|
-
* pagination.next()
|
|
2174
|
-
* pagination.items.value // [{ type: 'page', value: 1 }, { type: 'page', value: 2 }, ...]
|
|
2279
|
+
* import { createHydration } from '@vuetify/v0'
|
|
2175
2280
|
*
|
|
2176
|
-
*
|
|
2177
|
-
*
|
|
2178
|
-
*
|
|
2179
|
-
*
|
|
2281
|
+
* const hydration = createHydration()
|
|
2282
|
+
* console.log(hydration.isHydrated.value) // false
|
|
2283
|
+
* hydration.hydrate()
|
|
2284
|
+
* console.log(hydration.isHydrated.value) // true
|
|
2180
2285
|
* ```
|
|
2181
2286
|
*/
|
|
2182
|
-
function
|
|
2183
|
-
const
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
const size = toValue(_size);
|
|
2187
|
-
const perPage = toValue(_itemsPerPage);
|
|
2188
|
-
if (size <= 0 || /* @__PURE__ */ isNaN(size)) return 0;
|
|
2189
|
-
return Math.ceil(size / perPage);
|
|
2190
|
-
});
|
|
2191
|
-
function first() {
|
|
2192
|
-
page.value = 1;
|
|
2193
|
-
}
|
|
2194
|
-
function last() {
|
|
2195
|
-
page.value = Math.max(1, pages.value);
|
|
2196
|
-
}
|
|
2197
|
-
function next() {
|
|
2198
|
-
if (page.value < pages.value) page.value++;
|
|
2199
|
-
}
|
|
2200
|
-
function prev() {
|
|
2201
|
-
if (page.value > 1) page.value--;
|
|
2202
|
-
}
|
|
2203
|
-
function select(value) {
|
|
2204
|
-
if (value < 1) page.value = 1;
|
|
2205
|
-
else if (value > pages.value) page.value = Math.max(1, pages.value);
|
|
2206
|
-
else page.value = value;
|
|
2207
|
-
}
|
|
2208
|
-
const isFirst = computed(() => page.value <= 1);
|
|
2209
|
-
const isLast = computed(() => page.value >= pages.value);
|
|
2210
|
-
const pageStart = computed(() => (page.value - 1) * toValue(_itemsPerPage));
|
|
2211
|
-
const pageStop = computed(() => Math.min(pageStart.value + toValue(_itemsPerPage), toValue(_size)));
|
|
2212
|
-
function toPage(value) {
|
|
2213
|
-
return {
|
|
2214
|
-
type: "page",
|
|
2215
|
-
value
|
|
2216
|
-
};
|
|
2217
|
-
}
|
|
2218
|
-
function toEllipsis() {
|
|
2219
|
-
return ellipsis === false ? false : {
|
|
2220
|
-
type: "ellipsis",
|
|
2221
|
-
value: ellipsis
|
|
2222
|
-
};
|
|
2223
|
-
}
|
|
2224
|
-
function filter(array) {
|
|
2225
|
-
return array.filter((item) => item !== false);
|
|
2287
|
+
function createHydration() {
|
|
2288
|
+
const isHydrated = shallowRef(false);
|
|
2289
|
+
function hydrate() {
|
|
2290
|
+
isHydrated.value = true;
|
|
2226
2291
|
}
|
|
2227
2292
|
return {
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
if (visible <= 2) return [toPage(current)];
|
|
2237
|
-
if (pageCount <= visible) return (/* @__PURE__ */ range(pageCount, 1)).map(toPage);
|
|
2238
|
-
if (visible === 3) {
|
|
2239
|
-
const mid = current <= 1 ? 2 : current >= pageCount ? pageCount - 1 : current;
|
|
2240
|
-
return [
|
|
2241
|
-
toPage(1),
|
|
2242
|
-
toPage(mid),
|
|
2243
|
-
toPage(pageCount)
|
|
2244
|
-
];
|
|
2245
|
-
}
|
|
2246
|
-
const boundary = visible - 2;
|
|
2247
|
-
const middle = visible - 4;
|
|
2248
|
-
if (middle <= 0) {
|
|
2249
|
-
if (current <= boundary) return filter([
|
|
2250
|
-
...(/* @__PURE__ */ range(boundary, 1)).map(toPage),
|
|
2251
|
-
toEllipsis(),
|
|
2252
|
-
toPage(pageCount)
|
|
2253
|
-
]);
|
|
2254
|
-
if (current > pageCount - boundary) return filter([
|
|
2255
|
-
toPage(1),
|
|
2256
|
-
toEllipsis(),
|
|
2257
|
-
...(/* @__PURE__ */ range(boundary, pageCount - boundary + 1)).map(toPage)
|
|
2258
|
-
]);
|
|
2259
|
-
return current <= Math.ceil(pageCount / 2) ? filter([
|
|
2260
|
-
toPage(1),
|
|
2261
|
-
toPage(current),
|
|
2262
|
-
toEllipsis(),
|
|
2263
|
-
toPage(pageCount)
|
|
2264
|
-
]) : filter([
|
|
2265
|
-
toPage(1),
|
|
2266
|
-
toEllipsis(),
|
|
2267
|
-
toPage(current),
|
|
2268
|
-
toPage(pageCount)
|
|
2269
|
-
]);
|
|
2270
|
-
}
|
|
2271
|
-
const leftThreshold = boundary - 1;
|
|
2272
|
-
const rightThreshold = pageCount - boundary + 2;
|
|
2273
|
-
if (current <= leftThreshold) return filter([
|
|
2274
|
-
...(/* @__PURE__ */ range(boundary, 1)).map(toPage),
|
|
2275
|
-
toEllipsis(),
|
|
2276
|
-
toPage(pageCount)
|
|
2277
|
-
]);
|
|
2278
|
-
else if (current >= rightThreshold) return filter([
|
|
2279
|
-
toPage(1),
|
|
2280
|
-
toEllipsis(),
|
|
2281
|
-
...(/* @__PURE__ */ range(boundary, pageCount - boundary + 1)).map(toPage)
|
|
2282
|
-
]);
|
|
2283
|
-
else {
|
|
2284
|
-
const start = current - Math.floor(middle / 2);
|
|
2285
|
-
return filter([
|
|
2286
|
-
toPage(1),
|
|
2287
|
-
toEllipsis(),
|
|
2288
|
-
...(/* @__PURE__ */ range(middle, start)).map(toPage),
|
|
2289
|
-
toEllipsis(),
|
|
2290
|
-
toPage(pageCount)
|
|
2291
|
-
]);
|
|
2292
|
-
}
|
|
2293
|
-
}),
|
|
2294
|
-
pageStart,
|
|
2295
|
-
pageStop,
|
|
2296
|
-
isFirst,
|
|
2297
|
-
isLast,
|
|
2298
|
-
first,
|
|
2299
|
-
last,
|
|
2300
|
-
next,
|
|
2301
|
-
prev,
|
|
2302
|
-
select,
|
|
2303
|
-
get itemsPerPage() {
|
|
2304
|
-
return toValue(_itemsPerPage);
|
|
2305
|
-
},
|
|
2306
|
-
get size() {
|
|
2307
|
-
return toValue(_size);
|
|
2308
|
-
},
|
|
2309
|
-
get pages() {
|
|
2310
|
-
return pages.value;
|
|
2311
|
-
}
|
|
2293
|
+
isHydrated: shallowReadonly(isHydrated),
|
|
2294
|
+
hydrate
|
|
2295
|
+
};
|
|
2296
|
+
}
|
|
2297
|
+
function createFallbackHydration() {
|
|
2298
|
+
return {
|
|
2299
|
+
isHydrated: shallowReadonly(shallowRef(true)),
|
|
2300
|
+
hydrate: () => {}
|
|
2312
2301
|
};
|
|
2313
2302
|
}
|
|
2314
2303
|
/**
|
|
2315
|
-
* Creates a
|
|
2304
|
+
* Creates a new hydration context trinity.
|
|
2305
|
+
*
|
|
2306
|
+
* @param options Options for creating the hydration context.
|
|
2307
|
+
* @template E The type of the hydration context.
|
|
2308
|
+
* @returns A new hydration context trinity.
|
|
2309
|
+
*
|
|
2310
|
+
* @see https://0.vuetifyjs.com/composables/plugins/use-hydration
|
|
2311
|
+
*
|
|
2312
|
+
* @example
|
|
2313
|
+
* ```ts
|
|
2314
|
+
* import { createHydrationContext } from '@vuetify/v0'
|
|
2315
|
+
*
|
|
2316
|
+
* export const [useHydrationContext, provideHydrationContext, context] = createHydrationContext({
|
|
2317
|
+
* namespace: 'app:hydration',
|
|
2318
|
+
* })
|
|
2319
|
+
* ```
|
|
2320
|
+
*/
|
|
2321
|
+
function createHydrationContext(_options = {}) {
|
|
2322
|
+
const { namespace = "v0:hydration" } = _options;
|
|
2323
|
+
const [useHydrationContext, _provideHydrationContext] = createContext(namespace);
|
|
2324
|
+
const context = createHydration();
|
|
2325
|
+
function provideHydrationContext(_context = context, app) {
|
|
2326
|
+
return _provideHydrationContext(_context, app);
|
|
2327
|
+
}
|
|
2328
|
+
return createTrinity(useHydrationContext, provideHydrationContext, context);
|
|
2329
|
+
}
|
|
2330
|
+
/**
|
|
2331
|
+
* Creates a new hydration plugin.
|
|
2332
|
+
*
|
|
2333
|
+
* @param options The options for the hydration plugin.
|
|
2334
|
+
* @template E The type of the hydration context.
|
|
2335
|
+
* @returns A new hydration plugin.
|
|
2316
2336
|
*
|
|
2317
|
-
* @
|
|
2318
|
-
* @returns A trinity: [usePagination, providePagination, defaultContext]
|
|
2337
|
+
* @see https://0.vuetifyjs.com/composables/plugins/use-hydration
|
|
2319
2338
|
*
|
|
2320
2339
|
* @example
|
|
2321
2340
|
* ```ts
|
|
2322
|
-
*
|
|
2323
|
-
*
|
|
2341
|
+
* import { createApp } from 'vue'
|
|
2342
|
+
* import { createHydrationPlugin } from '@vuetify/v0'
|
|
2343
|
+
* import App from './App.vue'
|
|
2324
2344
|
*
|
|
2325
|
-
*
|
|
2326
|
-
* const [usePagination, providePaginationContext] = createPaginationContext({
|
|
2327
|
-
* namespace: 'my-pagination',
|
|
2328
|
-
* size: 50,
|
|
2329
|
-
* })
|
|
2345
|
+
* const app = createApp(App)
|
|
2330
2346
|
*
|
|
2331
|
-
*
|
|
2332
|
-
* providePaginationContext()
|
|
2347
|
+
* app.use(createHydrationPlugin())
|
|
2333
2348
|
*
|
|
2334
|
-
*
|
|
2335
|
-
* const pagination = usePagination()
|
|
2336
|
-
* pagination.next()
|
|
2349
|
+
* app.mount('#app')
|
|
2337
2350
|
* ```
|
|
2338
2351
|
*/
|
|
2339
|
-
function
|
|
2340
|
-
const { namespace = "v0:
|
|
2341
|
-
const [
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2352
|
+
function createHydrationPlugin(_options = {}) {
|
|
2353
|
+
const { namespace = "v0:hydration", ...options } = _options;
|
|
2354
|
+
const [, provideHydrationContext, context] = createHydrationContext({
|
|
2355
|
+
...options,
|
|
2356
|
+
namespace
|
|
2357
|
+
});
|
|
2358
|
+
return createPlugin({
|
|
2359
|
+
namespace,
|
|
2360
|
+
provide: (app) => {
|
|
2361
|
+
provideHydrationContext(context, app);
|
|
2362
|
+
},
|
|
2363
|
+
setup: (app) => {
|
|
2364
|
+
app.mixin({ mounted() {
|
|
2365
|
+
if (!/* @__PURE__ */ isNull(this.$parent)) return;
|
|
2366
|
+
context.hydrate();
|
|
2367
|
+
} });
|
|
2368
|
+
}
|
|
2369
|
+
});
|
|
2347
2370
|
}
|
|
2348
2371
|
/**
|
|
2349
|
-
* Returns the current
|
|
2372
|
+
* Returns the current hydration instance.
|
|
2350
2373
|
*
|
|
2351
|
-
* @param namespace The namespace.
|
|
2352
|
-
* @returns The
|
|
2374
|
+
* @param namespace The namespace for the hydration context. Defaults to `v0:hydration`.
|
|
2375
|
+
* @returns The current hydration instance.
|
|
2376
|
+
*
|
|
2377
|
+
* @see https://0.vuetifyjs.com/composables/plugins/use-hydration
|
|
2353
2378
|
*
|
|
2354
2379
|
* @example
|
|
2355
2380
|
* ```vue
|
|
2356
|
-
* <script setup>
|
|
2357
|
-
*
|
|
2381
|
+
* <script setup lang="ts">
|
|
2382
|
+
* import { useHydration } from '@vuetify/v0'
|
|
2358
2383
|
*
|
|
2359
|
-
*
|
|
2384
|
+
* const hydration = useHydration()
|
|
2360
2385
|
* <\/script>
|
|
2361
2386
|
*
|
|
2362
2387
|
* <template>
|
|
2363
|
-
* <
|
|
2364
|
-
*
|
|
2388
|
+
* <div>
|
|
2389
|
+
* <p>Is hydrated: {{ hydration.isHydrated.value }}</p>
|
|
2390
|
+
* </div>
|
|
2365
2391
|
* </template>
|
|
2366
2392
|
* ```
|
|
2367
2393
|
*/
|
|
2368
|
-
function
|
|
2369
|
-
|
|
2394
|
+
function useHydration(namespace = "v0:hydration") {
|
|
2395
|
+
const fallback = createFallbackHydration();
|
|
2396
|
+
if (!getCurrentInstance()) return fallback;
|
|
2397
|
+
try {
|
|
2398
|
+
return useContext(namespace, fallback);
|
|
2399
|
+
} catch {
|
|
2400
|
+
return fallback;
|
|
2401
|
+
}
|
|
2370
2402
|
}
|
|
2371
2403
|
|
|
2372
2404
|
//#endregion
|
|
2373
|
-
//#region src/composables/
|
|
2405
|
+
//#region src/composables/useResizeObserver/index.ts
|
|
2374
2406
|
/**
|
|
2375
|
-
* @module
|
|
2407
|
+
* @module useResizeObserver
|
|
2376
2408
|
*
|
|
2377
2409
|
* @remarks
|
|
2378
|
-
*
|
|
2410
|
+
* ResizeObserver composable with lifecycle management.
|
|
2379
2411
|
*
|
|
2380
2412
|
* Key features:
|
|
2381
|
-
* -
|
|
2382
|
-
* -
|
|
2383
|
-
* -
|
|
2413
|
+
* - ResizeObserver API wrapper
|
|
2414
|
+
* - Pause/resume/stop functionality
|
|
2415
|
+
* - Automatic cleanup on unmount
|
|
2416
|
+
* - SSR-safe (checks SUPPORTS_OBSERVER)
|
|
2417
|
+
* - Hydration-aware
|
|
2418
|
+
* - Box model options (content-box/border-box)
|
|
2384
2419
|
*
|
|
2385
|
-
*
|
|
2420
|
+
* Perfect for responsive components and size-based rendering.
|
|
2386
2421
|
*/
|
|
2387
2422
|
/**
|
|
2388
|
-
*
|
|
2389
|
-
*
|
|
2390
|
-
* Extends `createSelection` by automatically clearing previous selections when a new item is selected.
|
|
2391
|
-
* Adds computed singular properties: `selectedId`, `selectedItem`, `selectedIndex`, `selectedValue`.
|
|
2392
|
-
*
|
|
2393
|
-
* @param options The options for the single selection instance.
|
|
2394
|
-
* @template Z The type of the single selection ticket.
|
|
2395
|
-
* @template E The type of the single selection context.
|
|
2396
|
-
* @returns A new single selection instance with single-selection enforcement.
|
|
2397
|
-
*
|
|
2398
|
-
* @remarks
|
|
2399
|
-
* **Key Differences from `createSelection`:**
|
|
2400
|
-
* - Automatically clears `selectedIds` before selecting a new item (enforces single selection)
|
|
2401
|
-
* - Provides singular computed properties instead of plural sets
|
|
2402
|
-
* - Perfect for tabs, radio buttons, theme selectors, and other single-choice UI components
|
|
2403
|
-
*
|
|
2404
|
-
* **Computed Properties:**
|
|
2405
|
-
* - `selectedId`: The ID of the selected item (undefined if none selected)
|
|
2406
|
-
* - `selectedItem`: The selected ticket object (undefined if none selected)
|
|
2407
|
-
* - `selectedIndex`: The index of the selected item (-1 if none selected)
|
|
2408
|
-
* - `selectedValue`: The value of the selected item (undefined if none selected)
|
|
2423
|
+
* A composable that uses the Resize Observer API to detect when an element's
|
|
2424
|
+
* size changes.
|
|
2409
2425
|
*
|
|
2410
|
-
*
|
|
2411
|
-
*
|
|
2426
|
+
* @param target The element to observe.
|
|
2427
|
+
* @param callback The callback to execute when the element's size changes.
|
|
2428
|
+
* @param options The options for the Resize Observer.
|
|
2429
|
+
* @returns An object with methods to control the observer.
|
|
2412
2430
|
*
|
|
2413
|
-
* @see https://
|
|
2431
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver
|
|
2432
|
+
* @see https://0.vuetifyjs.com/composables/system/use-resize-observer
|
|
2414
2433
|
*
|
|
2415
2434
|
* @example
|
|
2416
2435
|
* ```ts
|
|
2417
|
-
* import {
|
|
2418
|
-
*
|
|
2419
|
-
* const tabs = createSingle({ mandatory: true })
|
|
2436
|
+
* import { ref } from 'vue'
|
|
2437
|
+
* import { useResizeObserver } from '@vuetify/v0'
|
|
2420
2438
|
*
|
|
2421
|
-
*
|
|
2422
|
-
*
|
|
2423
|
-
*
|
|
2424
|
-
* { id: 'contact', value: 'Contact' },
|
|
2425
|
-
* ])
|
|
2439
|
+
* const el = ref<HTMLElement>()
|
|
2440
|
+
* const width = ref(0)
|
|
2441
|
+
* const height = ref(0)
|
|
2426
2442
|
*
|
|
2427
|
-
*
|
|
2443
|
+
* const { pause, resume, isPaused } = useResizeObserver(
|
|
2444
|
+
* el,
|
|
2445
|
+
* (entries) => {
|
|
2446
|
+
* const entry = entries[0]
|
|
2447
|
+
* if (entry) {
|
|
2448
|
+
* width.value = entry.contentRect.width
|
|
2449
|
+
* height.value = entry.contentRect.height
|
|
2450
|
+
* console.log('Size changed:', width.value, 'x', height.value)
|
|
2451
|
+
* }
|
|
2452
|
+
* },
|
|
2453
|
+
* { immediate: true }
|
|
2454
|
+
* )
|
|
2428
2455
|
*
|
|
2429
|
-
*
|
|
2430
|
-
*
|
|
2456
|
+
* // Pause observation
|
|
2457
|
+
* pause()
|
|
2431
2458
|
*
|
|
2432
|
-
*
|
|
2433
|
-
*
|
|
2434
|
-
* console.log(tabs.selectedIds.size) // 1 (always enforces single selection)
|
|
2459
|
+
* // Resume observation
|
|
2460
|
+
* resume()
|
|
2435
2461
|
* ```
|
|
2436
2462
|
*/
|
|
2437
|
-
function
|
|
2438
|
-
const {
|
|
2439
|
-
const
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2463
|
+
function useResizeObserver(target, callback, options = {}) {
|
|
2464
|
+
const { isHydrated } = useHydration();
|
|
2465
|
+
const observer = shallowRef();
|
|
2466
|
+
const isPaused = shallowRef(false);
|
|
2467
|
+
const isActive = toRef(() => !!observer.value);
|
|
2468
|
+
function setup() {
|
|
2469
|
+
if (/* @__PURE__ */ isNull(observer.value)) return;
|
|
2470
|
+
if (!isHydrated.value || !SUPPORTS_OBSERVER || !target.value || isPaused.value) return;
|
|
2471
|
+
observer.value = new ResizeObserver((entries) => {
|
|
2472
|
+
callback(entries.map((entry) => ({
|
|
2473
|
+
contentRect: {
|
|
2474
|
+
width: entry.contentRect.width,
|
|
2475
|
+
height: entry.contentRect.height,
|
|
2476
|
+
top: entry.contentRect.top,
|
|
2477
|
+
left: entry.contentRect.left
|
|
2478
|
+
},
|
|
2479
|
+
target: entry.target
|
|
2480
|
+
})));
|
|
2481
|
+
if (options.once) stop();
|
|
2482
|
+
});
|
|
2483
|
+
observer.value.observe(target.value, { box: options.box || "content-box" });
|
|
2484
|
+
if (options.immediate) {
|
|
2485
|
+
const rect = target.value.getBoundingClientRect();
|
|
2486
|
+
callback([{
|
|
2487
|
+
contentRect: {
|
|
2488
|
+
width: rect.width,
|
|
2489
|
+
height: rect.height,
|
|
2490
|
+
top: rect.top,
|
|
2491
|
+
left: rect.left
|
|
2492
|
+
},
|
|
2493
|
+
target: target.value
|
|
2494
|
+
}]);
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
watchEffect(() => {
|
|
2498
|
+
const hydrated = isHydrated.value;
|
|
2499
|
+
const el = target.value;
|
|
2500
|
+
cleanup();
|
|
2501
|
+
if (hydrated && el) setup();
|
|
2502
|
+
});
|
|
2503
|
+
function cleanup() {
|
|
2504
|
+
if (observer.value) {
|
|
2505
|
+
observer.value.disconnect();
|
|
2506
|
+
observer.value = void 0;
|
|
2466
2507
|
}
|
|
2467
|
-
};
|
|
2468
|
-
}
|
|
2469
|
-
/**
|
|
2470
|
-
* Creates a new single selection context.
|
|
2471
|
-
*
|
|
2472
|
-
* @param options The options for the single selection context.
|
|
2473
|
-
* @template Z The type of the single selection ticket.
|
|
2474
|
-
* @template E The type of the single selection context.
|
|
2475
|
-
* @returns A new single selection context.
|
|
2476
|
-
*
|
|
2477
|
-
* @see https://0.vuetifyjs.com/composables/selection/use-single
|
|
2478
|
-
*
|
|
2479
|
-
* @example
|
|
2480
|
-
* ```ts
|
|
2481
|
-
* import { createSingleContext } from '@vuetify/v0'
|
|
2482
|
-
*
|
|
2483
|
-
* // With default namespace 'v0:single'
|
|
2484
|
-
* export const [useSingle, provideSingle, context] = createSingleContext()
|
|
2485
|
-
*
|
|
2486
|
-
* // In a parent component:
|
|
2487
|
-
* provideSingle()
|
|
2488
|
-
*
|
|
2489
|
-
* // In a child component:
|
|
2490
|
-
* const single = useSingle()
|
|
2491
|
-
* single.select('tab-1')
|
|
2492
|
-
* ```
|
|
2493
|
-
*/
|
|
2494
|
-
function createSingleContext(_options = {}) {
|
|
2495
|
-
const { namespace = "v0:single", ...options } = _options;
|
|
2496
|
-
const [useSingleContext, _provideSingleContext] = createContext(namespace);
|
|
2497
|
-
const context = createSingle(options);
|
|
2498
|
-
function provideSingleContext(_context = context, app) {
|
|
2499
|
-
return _provideSingleContext(_context, app);
|
|
2500
2508
|
}
|
|
2501
|
-
|
|
2509
|
+
function pause() {
|
|
2510
|
+
isPaused.value = true;
|
|
2511
|
+
observer.value?.disconnect();
|
|
2512
|
+
}
|
|
2513
|
+
function resume() {
|
|
2514
|
+
isPaused.value = false;
|
|
2515
|
+
setup();
|
|
2516
|
+
}
|
|
2517
|
+
function stop() {
|
|
2518
|
+
cleanup();
|
|
2519
|
+
observer.value = null;
|
|
2520
|
+
}
|
|
2521
|
+
onScopeDispose(stop, true);
|
|
2522
|
+
return {
|
|
2523
|
+
isActive: shallowReadonly(isActive),
|
|
2524
|
+
isPaused: shallowReadonly(isPaused),
|
|
2525
|
+
pause,
|
|
2526
|
+
resume,
|
|
2527
|
+
stop
|
|
2528
|
+
};
|
|
2502
2529
|
}
|
|
2503
2530
|
/**
|
|
2504
|
-
*
|
|
2531
|
+
* A convenience composable that uses the Resize Observer API to track an
|
|
2532
|
+
* element's size.
|
|
2505
2533
|
*
|
|
2506
|
-
* @param
|
|
2507
|
-
* @returns
|
|
2534
|
+
* @param target The element to observe.
|
|
2535
|
+
* @returns An object with the element's width and height.
|
|
2508
2536
|
*
|
|
2509
|
-
* @see https://0.vuetifyjs.com/composables/
|
|
2537
|
+
* @see https://0.vuetifyjs.com/composables/system/use-resize-observer#use-element-size
|
|
2510
2538
|
*
|
|
2511
2539
|
* @example
|
|
2512
|
-
* ```
|
|
2513
|
-
*
|
|
2514
|
-
*
|
|
2540
|
+
* ```ts
|
|
2541
|
+
* import { ref, watchEffect } from 'vue'
|
|
2542
|
+
* import { useElementSize } from '@vuetify/v0'
|
|
2515
2543
|
*
|
|
2516
|
-
*
|
|
2517
|
-
*
|
|
2544
|
+
* const box = ref<HTMLElement>()
|
|
2545
|
+
* const { width, height } = useElementSize(box)
|
|
2518
2546
|
*
|
|
2519
|
-
*
|
|
2520
|
-
*
|
|
2521
|
-
*
|
|
2522
|
-
*
|
|
2523
|
-
* </template>
|
|
2547
|
+
* // Width and height are reactive refs
|
|
2548
|
+
* watchEffect(() => {
|
|
2549
|
+
* console.log('Box size:', width.value, 'x', height.value)
|
|
2550
|
+
* })
|
|
2524
2551
|
* ```
|
|
2525
2552
|
*/
|
|
2526
|
-
function
|
|
2527
|
-
|
|
2553
|
+
function useElementSize(target) {
|
|
2554
|
+
const width = shallowRef(0);
|
|
2555
|
+
const height = shallowRef(0);
|
|
2556
|
+
const { pause: _pause, resume, stop, isActive, isPaused } = useResizeObserver(target, (entries) => {
|
|
2557
|
+
const entry = entries[0];
|
|
2558
|
+
if (entry) {
|
|
2559
|
+
width.value = entry.contentRect.width;
|
|
2560
|
+
height.value = entry.contentRect.height;
|
|
2561
|
+
}
|
|
2562
|
+
}, { immediate: true });
|
|
2563
|
+
function pause() {
|
|
2564
|
+
width.value = 0;
|
|
2565
|
+
height.value = 0;
|
|
2566
|
+
_pause();
|
|
2567
|
+
}
|
|
2568
|
+
return {
|
|
2569
|
+
width,
|
|
2570
|
+
height,
|
|
2571
|
+
isActive,
|
|
2572
|
+
isPaused,
|
|
2573
|
+
pause,
|
|
2574
|
+
resume,
|
|
2575
|
+
stop
|
|
2576
|
+
};
|
|
2528
2577
|
}
|
|
2529
2578
|
|
|
2530
2579
|
//#endregion
|
|
2531
|
-
//#region src/composables/
|
|
2580
|
+
//#region src/composables/useOverflow/index.ts
|
|
2532
2581
|
/**
|
|
2533
|
-
* @module
|
|
2534
|
-
*
|
|
2535
|
-
* @see https://0.vuetifyjs.com/composables/registration/use-tokens
|
|
2582
|
+
* @module useOverflow
|
|
2536
2583
|
*
|
|
2537
2584
|
* @remarks
|
|
2538
|
-
*
|
|
2585
|
+
* Composable for computing how many items fit in a container based on available width.
|
|
2586
|
+
* Enables responsive truncation logic for Pagination, Breadcrumbs, and similar components.
|
|
2539
2587
|
*
|
|
2540
2588
|
* Key features:
|
|
2541
|
-
* -
|
|
2542
|
-
* -
|
|
2543
|
-
* -
|
|
2544
|
-
* -
|
|
2545
|
-
* -
|
|
2589
|
+
* - Container width tracking via ResizeObserver
|
|
2590
|
+
* - Two modes: variable-width (per-item) or uniform-width (sample-based)
|
|
2591
|
+
* - Computes capacity (how many items fit)
|
|
2592
|
+
* - SSR-safe with Infinity fallback
|
|
2593
|
+
* - Supports reserved space for nav buttons, ellipsis, etc.
|
|
2546
2594
|
*
|
|
2547
|
-
*
|
|
2595
|
+
* Use variable mode (default) for items with different widths like Breadcrumbs.
|
|
2596
|
+
* Use uniform mode (itemWidth option) for same-width items like Pagination buttons.
|
|
2548
2597
|
*/
|
|
2549
2598
|
/**
|
|
2550
|
-
* Creates a new
|
|
2599
|
+
* Creates a new overflow context for computing how many items fit in a container.
|
|
2551
2600
|
*
|
|
2552
|
-
* @param
|
|
2553
|
-
* @
|
|
2554
|
-
* @template Z The type of the token ticket.
|
|
2555
|
-
* @template E The type of the token context.
|
|
2556
|
-
* @returns A new token instance.
|
|
2601
|
+
* @param options Configuration options
|
|
2602
|
+
* @returns Overflow context with container ref, capacity, and measurement functions
|
|
2557
2603
|
*
|
|
2558
|
-
* @
|
|
2559
|
-
*
|
|
2604
|
+
* @example Variable-width mode (Breadcrumbs)
|
|
2605
|
+
* ```vue
|
|
2606
|
+
* <script lang="ts" setup>
|
|
2607
|
+
* import { useTemplateRef } from 'vue'
|
|
2608
|
+
* import { createOverflow } from '@vuetify/v0'
|
|
2560
2609
|
*
|
|
2561
|
-
*
|
|
2562
|
-
*
|
|
2563
|
-
*
|
|
2610
|
+
* const containerRef = useTemplateRef('container')
|
|
2611
|
+
* const overflow = createOverflow({
|
|
2612
|
+
* container: containerRef,
|
|
2613
|
+
* gap: 8,
|
|
2614
|
+
* reserved: 40,
|
|
2615
|
+
* })
|
|
2616
|
+
* <\/script>
|
|
2564
2617
|
*
|
|
2565
|
-
*
|
|
2566
|
-
*
|
|
2567
|
-
*
|
|
2568
|
-
*
|
|
2569
|
-
*
|
|
2570
|
-
*
|
|
2618
|
+
* <template>
|
|
2619
|
+
* <div ref="container">
|
|
2620
|
+
* <span
|
|
2621
|
+
* v-for="(item, i) in items.slice(0, overflow.capacity.value)"
|
|
2622
|
+
* :key="i"
|
|
2623
|
+
* :ref="el => overflow.measure(i, el)"
|
|
2624
|
+
* >
|
|
2625
|
+
* {{ item }}
|
|
2626
|
+
* </span>
|
|
2627
|
+
* <span v-if="overflow.isOverflowing.value">...</span>
|
|
2628
|
+
* </div>
|
|
2629
|
+
* </template>
|
|
2630
|
+
* ```
|
|
2571
2631
|
*
|
|
2572
|
-
*
|
|
2573
|
-
*
|
|
2632
|
+
* @example Uniform-width mode (Pagination)
|
|
2633
|
+
* ```ts
|
|
2634
|
+
* const overflow = createOverflow({
|
|
2635
|
+
* container: () => atom.value?.element,
|
|
2636
|
+
* itemWidth: buttonWidth,
|
|
2637
|
+
* reserved: () => buttonWidth.value * 4,
|
|
2638
|
+
* })
|
|
2574
2639
|
* ```
|
|
2575
2640
|
*/
|
|
2576
|
-
function
|
|
2577
|
-
const
|
|
2578
|
-
const
|
|
2579
|
-
const
|
|
2580
|
-
|
|
2581
|
-
function
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
function resolve(token, visited = /* @__PURE__ */ new Set()) {
|
|
2588
|
-
const cacheKey = /* @__PURE__ */ isString(token) ? token : JSON.stringify(token);
|
|
2589
|
-
const cached = cache.get(cacheKey);
|
|
2590
|
-
if (!/* @__PURE__ */ isUndefined(cached)) return cached;
|
|
2591
|
-
const reference = isTokenAlias(token) ? token.$value : token;
|
|
2592
|
-
const isAliasReference = /* @__PURE__ */ isString(reference) && isAlias(reference);
|
|
2593
|
-
const clean = isAliasReference ? reference.slice(1, -1) : String(reference);
|
|
2594
|
-
if (visited.has(clean)) {
|
|
2595
|
-
logger.warn(`Circular alias detected for "${clean}"`);
|
|
2596
|
-
cache.set(cacheKey, void 0);
|
|
2597
|
-
return;
|
|
2598
|
-
}
|
|
2599
|
-
visited.add(clean);
|
|
2600
|
-
let found = registry.get(clean);
|
|
2601
|
-
let segments = [];
|
|
2602
|
-
if (!found && clean.includes(".")) {
|
|
2603
|
-
const parts = clean.split(".");
|
|
2604
|
-
for (let i = parts.length - 1; i > 0; i--) {
|
|
2605
|
-
const prefix = parts.slice(0, i).join(".");
|
|
2606
|
-
const suffix = parts.slice(i);
|
|
2607
|
-
const candidate = registry.get(prefix);
|
|
2608
|
-
if (!/* @__PURE__ */ isUndefined(candidate?.value)) {
|
|
2609
|
-
found = candidate;
|
|
2610
|
-
segments = suffix;
|
|
2611
|
-
break;
|
|
2612
|
-
}
|
|
2641
|
+
function createOverflow(options = {}) {
|
|
2642
|
+
const { container: _container, gap = 0, reserved = 0, itemWidth, reverse } = options;
|
|
2643
|
+
const container = /* @__PURE__ */ isUndefined(_container) ? shallowRef() : toRef(_container);
|
|
2644
|
+
const widths = shallowRef(/* @__PURE__ */ new Map());
|
|
2645
|
+
const { width } = useElementSize(container);
|
|
2646
|
+
function measure(index, el) {
|
|
2647
|
+
if (!el) {
|
|
2648
|
+
if (widths.value.has(index)) {
|
|
2649
|
+
const next = new Map(widths.value);
|
|
2650
|
+
next.delete(index);
|
|
2651
|
+
widths.value = next;
|
|
2613
2652
|
}
|
|
2614
|
-
}
|
|
2615
|
-
if (/* @__PURE__ */ isUndefined(found?.value)) {
|
|
2616
|
-
if (isAliasReference) logger.warn(`Alias not found for "${String(reference)}"`);
|
|
2617
|
-
cache.set(cacheKey, void 0);
|
|
2618
2653
|
return;
|
|
2619
2654
|
}
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2655
|
+
const style = getComputedStyle(el);
|
|
2656
|
+
const marginX = Number.parseFloat(style.marginLeft) + Number.parseFloat(style.marginRight);
|
|
2657
|
+
const w = el.offsetWidth + marginX;
|
|
2658
|
+
if (widths.value.get(index) !== w) widths.value = new Map(widths.value).set(index, w);
|
|
2659
|
+
}
|
|
2660
|
+
function reset() {
|
|
2661
|
+
widths.value = /* @__PURE__ */ new Map();
|
|
2662
|
+
}
|
|
2663
|
+
const total = computed(() => {
|
|
2664
|
+
const g = toValue(gap);
|
|
2665
|
+
let sum = 0;
|
|
2666
|
+
let count = 0;
|
|
2667
|
+
for (const w of widths.value.values()) {
|
|
2668
|
+
sum += w + (count > 0 ? g : 0);
|
|
2669
|
+
count++;
|
|
2670
|
+
}
|
|
2671
|
+
return sum;
|
|
2672
|
+
});
|
|
2673
|
+
return {
|
|
2674
|
+
container,
|
|
2675
|
+
width,
|
|
2676
|
+
capacity: computed(() => {
|
|
2677
|
+
const available = width.value - toValue(reserved);
|
|
2678
|
+
if (width.value === 0) return Infinity;
|
|
2679
|
+
if (available <= 0) return 0;
|
|
2680
|
+
const g = toValue(gap);
|
|
2681
|
+
const uniformWidth = toValue(itemWidth);
|
|
2682
|
+
if (uniformWidth && uniformWidth > 0) {
|
|
2683
|
+
const first = uniformWidth;
|
|
2684
|
+
const subsequent = uniformWidth + g;
|
|
2685
|
+
if (available < first) return 0;
|
|
2686
|
+
return Math.max(1, Math.floor((available - first) / subsequent) + 1);
|
|
2631
2687
|
}
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2688
|
+
const entries = [...widths.value.entries()].toSorted((a, b) => a[0] - b[0]);
|
|
2689
|
+
if (toValue(reverse)) entries.reverse();
|
|
2690
|
+
let sum = 0;
|
|
2691
|
+
let count = 0;
|
|
2692
|
+
for (const [, w] of entries) {
|
|
2693
|
+
const next = sum + w + (count > 0 ? g : 0);
|
|
2694
|
+
if (next > available) break;
|
|
2695
|
+
sum = next;
|
|
2696
|
+
count++;
|
|
2636
2697
|
}
|
|
2637
|
-
|
|
2638
|
-
}
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
}
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
return result;
|
|
2646
|
-
}
|
|
2647
|
-
return {
|
|
2648
|
-
...registry,
|
|
2649
|
-
resolve,
|
|
2650
|
-
isAlias,
|
|
2651
|
-
get size() {
|
|
2652
|
-
return registry.size;
|
|
2653
|
-
}
|
|
2698
|
+
return count;
|
|
2699
|
+
}),
|
|
2700
|
+
total,
|
|
2701
|
+
isOverflowing: toRef(() => {
|
|
2702
|
+
return total.value > width.value - toValue(reserved);
|
|
2703
|
+
}),
|
|
2704
|
+
measure,
|
|
2705
|
+
reset
|
|
2654
2706
|
};
|
|
2655
2707
|
}
|
|
2656
2708
|
/**
|
|
2657
|
-
* Creates
|
|
2658
|
-
*
|
|
2659
|
-
* @param namespace The namespace for the token context.
|
|
2660
|
-
* @param tokens The tokens to use.
|
|
2661
|
-
* @template Z The type of the token ticket.
|
|
2662
|
-
* @template E The type of the token context.
|
|
2663
|
-
* @returns A new token context.
|
|
2709
|
+
* Creates an overflow context with dependency injection support.
|
|
2664
2710
|
*
|
|
2665
|
-
* @
|
|
2711
|
+
* @param options Configuration options including namespace
|
|
2712
|
+
* @returns Trinity tuple: [useContext, provideContext, defaultContext]
|
|
2666
2713
|
*
|
|
2667
2714
|
* @example
|
|
2668
2715
|
* ```ts
|
|
2669
|
-
*
|
|
2670
|
-
*
|
|
2671
|
-
*
|
|
2672
|
-
*
|
|
2673
|
-
*
|
|
2674
|
-
* colors: {
|
|
2675
|
-
* primary: '#3b82f6',
|
|
2676
|
-
* secondary: '{colors.primary}', // Alias reference
|
|
2677
|
-
* },
|
|
2678
|
-
* },
|
|
2716
|
+
* // Create injectable context
|
|
2717
|
+
* const [useOverflow, provideOverflow, overflow] = createOverflowContext({
|
|
2718
|
+
* namespace: 'my-overflow',
|
|
2719
|
+
* gap: 8,
|
|
2720
|
+
* reserved: 160,
|
|
2679
2721
|
* })
|
|
2722
|
+
*
|
|
2723
|
+
* // In parent component
|
|
2724
|
+
* provideOverflow()
|
|
2725
|
+
*
|
|
2726
|
+
* // In child component
|
|
2727
|
+
* const overflow = useOverflow()
|
|
2680
2728
|
* ```
|
|
2681
2729
|
*/
|
|
2682
|
-
function
|
|
2683
|
-
const { namespace = "v0:
|
|
2684
|
-
const [
|
|
2685
|
-
const context =
|
|
2686
|
-
function
|
|
2687
|
-
return
|
|
2730
|
+
function createOverflowContext(_options = {}) {
|
|
2731
|
+
const { namespace = "v0:overflow", ...options } = _options;
|
|
2732
|
+
const [useOverflowContext, _provideOverflowContext] = createContext(namespace);
|
|
2733
|
+
const context = createOverflow(options);
|
|
2734
|
+
function provideOverflowContext(_context = context, app) {
|
|
2735
|
+
return _provideOverflowContext(_context, app);
|
|
2688
2736
|
}
|
|
2689
|
-
return createTrinity(
|
|
2737
|
+
return createTrinity(useOverflowContext, provideOverflowContext, context);
|
|
2690
2738
|
}
|
|
2691
2739
|
/**
|
|
2692
|
-
* Returns the current
|
|
2693
|
-
*
|
|
2694
|
-
* @param namespace The namespace for the tokens context. Defaults to `'v0:tokens'`.
|
|
2695
|
-
* @returns The current tokens instance.
|
|
2740
|
+
* Returns the current overflow context from dependency injection.
|
|
2696
2741
|
*
|
|
2697
|
-
* @
|
|
2742
|
+
* @param namespace The namespace for the overflow context. Defaults to `v0:overflow`.
|
|
2743
|
+
* @returns The current overflow context.
|
|
2698
2744
|
*
|
|
2699
2745
|
* @example
|
|
2700
2746
|
* ```vue
|
|
2701
|
-
* <script
|
|
2702
|
-
* import {
|
|
2747
|
+
* <script lang="ts" setup>
|
|
2748
|
+
* import { useOverflow } from '@vuetify/v0'
|
|
2703
2749
|
*
|
|
2704
|
-
*
|
|
2750
|
+
* // Inject overflow context provided by parent
|
|
2751
|
+
* const overflow = useOverflow()
|
|
2705
2752
|
* <\/script>
|
|
2753
|
+
*
|
|
2754
|
+
* <template>
|
|
2755
|
+
* <div>
|
|
2756
|
+
* <p>Capacity: {{ overflow.capacity.value }}</p>
|
|
2757
|
+
* </div>
|
|
2758
|
+
* </template>
|
|
2706
2759
|
* ```
|
|
2707
2760
|
*/
|
|
2708
|
-
function
|
|
2761
|
+
function useOverflow(namespace = "v0:overflow") {
|
|
2709
2762
|
return useContext(namespace);
|
|
2710
2763
|
}
|
|
2711
|
-
/**
|
|
2712
|
-
* Flattens a nested collection of tokens into a flat array of tokens.
|
|
2713
|
-
* Each token is represented by an object containing its ID & value.
|
|
2714
|
-
* @param tokens The collection of tokens to flatten.
|
|
2715
|
-
* @param prefix An optional prefix to prepend to each token ID.
|
|
2716
|
-
* @returns An array of flattened tokens, each with an ID and value.
|
|
2717
|
-
*/
|
|
2718
|
-
function flatten(tokens, prefix = "", flat = false) {
|
|
2719
|
-
const flattened = [];
|
|
2720
|
-
const stack = [{
|
|
2721
|
-
tokens,
|
|
2722
|
-
prefix,
|
|
2723
|
-
flat
|
|
2724
|
-
}];
|
|
2725
|
-
while (stack.length > 0) {
|
|
2726
|
-
const { tokens: currentTokens, prefix: currentPrefix, flat: flat$1 } = stack.pop();
|
|
2727
|
-
const meta = {};
|
|
2728
|
-
for (const k in currentTokens) if (k.startsWith("$")) meta[k] = currentTokens[k];
|
|
2729
|
-
if (Object.keys(meta).length > 0 && currentPrefix) flattened.push({
|
|
2730
|
-
id: currentPrefix,
|
|
2731
|
-
value: meta
|
|
2732
|
-
});
|
|
2733
|
-
for (const key in currentTokens) {
|
|
2734
|
-
if (key.startsWith("$")) continue;
|
|
2735
|
-
const value = currentTokens[key];
|
|
2736
|
-
const id = currentPrefix ? `${currentPrefix}.${key}` : key;
|
|
2737
|
-
if (!/* @__PURE__ */ isObject(value)) {
|
|
2738
|
-
flattened.push({
|
|
2739
|
-
id,
|
|
2740
|
-
value
|
|
2741
|
-
});
|
|
2742
|
-
continue;
|
|
2743
|
-
}
|
|
2744
|
-
if ("$value" in value) {
|
|
2745
|
-
flattened.push({
|
|
2746
|
-
id,
|
|
2747
|
-
value
|
|
2748
|
-
});
|
|
2749
|
-
const inner = value.$value;
|
|
2750
|
-
if (/* @__PURE__ */ isObject(inner) && !flat$1) for (const innerKey in inner) {
|
|
2751
|
-
if (innerKey.startsWith("$")) continue;
|
|
2752
|
-
const child = inner[innerKey];
|
|
2753
|
-
const childId = `${id}.${innerKey}`;
|
|
2754
|
-
if (!/* @__PURE__ */ isObject(child)) flattened.push({
|
|
2755
|
-
id: childId,
|
|
2756
|
-
value: child
|
|
2757
|
-
});
|
|
2758
|
-
else if ("$value" in child) flattened.push({
|
|
2759
|
-
id: childId,
|
|
2760
|
-
value: child
|
|
2761
|
-
});
|
|
2762
|
-
else stack.push({
|
|
2763
|
-
tokens: child,
|
|
2764
|
-
prefix: childId,
|
|
2765
|
-
flat: flat$1
|
|
2766
|
-
});
|
|
2767
|
-
}
|
|
2768
|
-
continue;
|
|
2769
|
-
}
|
|
2770
|
-
if (flat$1) {
|
|
2771
|
-
flattened.push({
|
|
2772
|
-
id,
|
|
2773
|
-
value
|
|
2774
|
-
});
|
|
2775
|
-
continue;
|
|
2776
|
-
}
|
|
2777
|
-
stack.push({
|
|
2778
|
-
tokens: value,
|
|
2779
|
-
prefix: id,
|
|
2780
|
-
flat: flat$1
|
|
2781
|
-
});
|
|
2782
|
-
}
|
|
2783
|
-
}
|
|
2784
|
-
return flattened;
|
|
2785
|
-
}
|
|
2786
|
-
|
|
2787
|
-
//#endregion
|
|
2788
|
-
//#region src/composables/useLocale/adapters/v0.ts
|
|
2789
|
-
/**
|
|
2790
|
-
* Vuetify0.x locale adapter implementation
|
|
2791
|
-
*
|
|
2792
|
-
* This adapter provides translation and number formatting
|
|
2793
|
-
* capabilities using the Intl API and supports both
|
|
2794
|
-
* numbered ({0}, {1}) and named ({name}) variables in translation strings.
|
|
2795
|
-
*/
|
|
2796
|
-
var Vuetify0LocaleAdapter = class {
|
|
2797
|
-
t(message, ...params) {
|
|
2798
|
-
let resolvedMessage = message;
|
|
2799
|
-
if (params.length > 0 && /* @__PURE__ */ isObject(params[0])) {
|
|
2800
|
-
const variables = params[0];
|
|
2801
|
-
resolvedMessage = resolvedMessage.replace(/{([a-zA-Z][a-zA-Z0-9_]*)}/g, (match, name) => {
|
|
2802
|
-
return /* @__PURE__ */ isUndefined(variables[name]) ? match : String(variables[name]);
|
|
2803
|
-
});
|
|
2804
|
-
params = params.slice(1);
|
|
2805
|
-
}
|
|
2806
|
-
resolvedMessage = resolvedMessage.replace(/\{(\d+)\}/g, (match, index) => {
|
|
2807
|
-
const idx = Number.parseInt(index, 10);
|
|
2808
|
-
if (!/* @__PURE__ */ isUndefined(params[idx])) return String(params[idx]);
|
|
2809
|
-
return match;
|
|
2810
|
-
});
|
|
2811
|
-
return resolvedMessage;
|
|
2812
|
-
}
|
|
2813
|
-
n(value, locale, ...params) {
|
|
2814
|
-
if (!IN_BROWSER || !locale) return value.toString();
|
|
2815
|
-
const options = params[0];
|
|
2816
|
-
return new Intl.NumberFormat(String(locale), options).format(value);
|
|
2817
|
-
}
|
|
2818
|
-
};
|
|
2819
2764
|
|
|
2820
2765
|
//#endregion
|
|
2821
|
-
//#region src/composables/
|
|
2766
|
+
//#region src/composables/usePagination/index.ts
|
|
2822
2767
|
/**
|
|
2823
|
-
* @module
|
|
2768
|
+
* @module usePagination
|
|
2824
2769
|
*
|
|
2825
2770
|
* @remarks
|
|
2826
|
-
*
|
|
2771
|
+
* Lightweight pagination composable for navigating through pages.
|
|
2827
2772
|
*
|
|
2828
2773
|
* Key features:
|
|
2829
|
-
* -
|
|
2830
|
-
* -
|
|
2831
|
-
* -
|
|
2832
|
-
* -
|
|
2833
|
-
* -
|
|
2774
|
+
* - No registry overhead - just a bounded integer
|
|
2775
|
+
* - Direct ref support for v-model compatibility
|
|
2776
|
+
* - Navigation methods: next, prev, first, last
|
|
2777
|
+
* - Computed visible items with ellipsis
|
|
2778
|
+
* - Trinity pattern for dependency injection
|
|
2834
2779
|
*
|
|
2835
|
-
*
|
|
2780
|
+
* Unlike registry-based composables, pagination tracks a single number
|
|
2781
|
+
* within a range, making it efficient for large page counts.
|
|
2836
2782
|
*/
|
|
2837
2783
|
/**
|
|
2838
|
-
* Creates a
|
|
2784
|
+
* Creates a pagination instance.
|
|
2839
2785
|
*
|
|
2840
|
-
* @param options The options for the
|
|
2841
|
-
* @
|
|
2842
|
-
* @template E The type of the locale context.
|
|
2843
|
-
* @returns A new locale instance.
|
|
2786
|
+
* @param options The options for the pagination instance.
|
|
2787
|
+
* @returns A pagination context with navigation methods.
|
|
2844
2788
|
*
|
|
2845
|
-
* @
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2789
|
+
* @example
|
|
2790
|
+
* ```ts
|
|
2791
|
+
* import { createPagination } from '@vuetify/v0'
|
|
2792
|
+
*
|
|
2793
|
+
* // Basic usage
|
|
2794
|
+
* const pagination = createPagination({ size: 100 })
|
|
2795
|
+
* pagination.next()
|
|
2796
|
+
* pagination.items.value // [{ type: 'page', value: 1 }, { type: 'page', value: 2 }, ...]
|
|
2797
|
+
*
|
|
2798
|
+
* // With v-model (pass a ref)
|
|
2799
|
+
* const page = ref(1)
|
|
2800
|
+
* const pagination = createPagination({ page, size: 100 })
|
|
2801
|
+
* // Mutating pagination.page or the passed ref syncs both
|
|
2802
|
+
* ```
|
|
2803
|
+
*/
|
|
2804
|
+
function createPagination(_options = {}) {
|
|
2805
|
+
const { page: _page = 1, itemsPerPage: _itemsPerPage = 10, size: _size = 0, visible: _visible = 7, ellipsis = "..." } = _options;
|
|
2806
|
+
const page = isRef(_page) ? _page : shallowRef(_page);
|
|
2807
|
+
const pages = computed(() => {
|
|
2808
|
+
const size = toValue(_size);
|
|
2809
|
+
const perPage = toValue(_itemsPerPage);
|
|
2810
|
+
if (size <= 0 || /* @__PURE__ */ isNaN(size)) return 0;
|
|
2811
|
+
return Math.ceil(size / perPage);
|
|
2812
|
+
});
|
|
2813
|
+
function first() {
|
|
2814
|
+
page.value = 1;
|
|
2854
2815
|
}
|
|
2855
|
-
function
|
|
2856
|
-
|
|
2857
|
-
const args = toArray(params);
|
|
2858
|
-
if (!locale) return adapter.t(fallback ?? key, ...args);
|
|
2859
|
-
const path = `${locale}.${key}`;
|
|
2860
|
-
const message = tokens.get(path)?.value;
|
|
2861
|
-
const template = /* @__PURE__ */ isString(message) ? resolve(locale, message) : fallback ?? key;
|
|
2862
|
-
return adapter.t(template, ...args);
|
|
2816
|
+
function last() {
|
|
2817
|
+
page.value = Math.max(1, pages.value);
|
|
2863
2818
|
}
|
|
2864
|
-
function
|
|
2865
|
-
|
|
2819
|
+
function next() {
|
|
2820
|
+
if (page.value < pages.value) page.value++;
|
|
2866
2821
|
}
|
|
2867
|
-
function
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2822
|
+
function prev() {
|
|
2823
|
+
if (page.value > 1) page.value--;
|
|
2824
|
+
}
|
|
2825
|
+
function select(value) {
|
|
2826
|
+
if (value < 1) page.value = 1;
|
|
2827
|
+
else if (value > pages.value) page.value = Math.max(1, pages.value);
|
|
2828
|
+
else page.value = value;
|
|
2829
|
+
}
|
|
2830
|
+
const isFirst = computed(() => page.value <= 1);
|
|
2831
|
+
const isLast = computed(() => page.value >= pages.value);
|
|
2832
|
+
const pageStart = computed(() => (page.value - 1) * toValue(_itemsPerPage));
|
|
2833
|
+
const pageStop = computed(() => Math.min(pageStart.value + toValue(_itemsPerPage), toValue(_size)));
|
|
2834
|
+
function toPage(value) {
|
|
2835
|
+
return {
|
|
2836
|
+
type: "page",
|
|
2837
|
+
value
|
|
2838
|
+
};
|
|
2839
|
+
}
|
|
2840
|
+
function toEllipsis() {
|
|
2841
|
+
return ellipsis === false ? false : {
|
|
2842
|
+
type: "ellipsis",
|
|
2843
|
+
value: ellipsis
|
|
2844
|
+
};
|
|
2845
|
+
}
|
|
2846
|
+
function filter(array) {
|
|
2847
|
+
return array.filter((item) => item !== false);
|
|
2876
2848
|
}
|
|
2877
2849
|
return {
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2850
|
+
page,
|
|
2851
|
+
ellipsis,
|
|
2852
|
+
items: computed(() => {
|
|
2853
|
+
const pageCount = pages.value;
|
|
2854
|
+
const visible = toValue(_visible);
|
|
2855
|
+
const current = page.value;
|
|
2856
|
+
if (pageCount <= 0 || /* @__PURE__ */ isNaN(pageCount) || pageCount > Number.MAX_SAFE_INTEGER) return [];
|
|
2857
|
+
if (visible <= 0) return [];
|
|
2858
|
+
if (visible <= 2) return [toPage(current)];
|
|
2859
|
+
if (pageCount <= visible) return (/* @__PURE__ */ range(pageCount, 1)).map(toPage);
|
|
2860
|
+
if (visible === 3) {
|
|
2861
|
+
const mid = current <= 1 ? 2 : current >= pageCount ? pageCount - 1 : current;
|
|
2862
|
+
return [
|
|
2863
|
+
toPage(1),
|
|
2864
|
+
toPage(mid),
|
|
2865
|
+
toPage(pageCount)
|
|
2866
|
+
];
|
|
2867
|
+
}
|
|
2868
|
+
const boundary = visible - 2;
|
|
2869
|
+
const middle = visible - 4;
|
|
2870
|
+
if (middle <= 0) {
|
|
2871
|
+
if (current <= boundary) return filter([
|
|
2872
|
+
...(/* @__PURE__ */ range(boundary, 1)).map(toPage),
|
|
2873
|
+
toEllipsis(),
|
|
2874
|
+
toPage(pageCount)
|
|
2875
|
+
]);
|
|
2876
|
+
if (current > pageCount - boundary) return filter([
|
|
2877
|
+
toPage(1),
|
|
2878
|
+
toEllipsis(),
|
|
2879
|
+
...(/* @__PURE__ */ range(boundary, pageCount - boundary + 1)).map(toPage)
|
|
2880
|
+
]);
|
|
2881
|
+
return current <= Math.ceil(pageCount / 2) ? filter([
|
|
2882
|
+
toPage(1),
|
|
2883
|
+
toPage(current),
|
|
2884
|
+
toEllipsis(),
|
|
2885
|
+
toPage(pageCount)
|
|
2886
|
+
]) : filter([
|
|
2887
|
+
toPage(1),
|
|
2888
|
+
toEllipsis(),
|
|
2889
|
+
toPage(current),
|
|
2890
|
+
toPage(pageCount)
|
|
2891
|
+
]);
|
|
2892
|
+
}
|
|
2893
|
+
const leftThreshold = boundary - 1;
|
|
2894
|
+
const rightThreshold = pageCount - boundary + 2;
|
|
2895
|
+
if (current <= leftThreshold) return filter([
|
|
2896
|
+
...(/* @__PURE__ */ range(boundary, 1)).map(toPage),
|
|
2897
|
+
toEllipsis(),
|
|
2898
|
+
toPage(pageCount)
|
|
2899
|
+
]);
|
|
2900
|
+
else if (current >= rightThreshold) return filter([
|
|
2901
|
+
toPage(1),
|
|
2902
|
+
toEllipsis(),
|
|
2903
|
+
...(/* @__PURE__ */ range(boundary, pageCount - boundary + 1)).map(toPage)
|
|
2904
|
+
]);
|
|
2905
|
+
else {
|
|
2906
|
+
const start = current - Math.floor(middle / 2);
|
|
2907
|
+
return filter([
|
|
2908
|
+
toPage(1),
|
|
2909
|
+
toEllipsis(),
|
|
2910
|
+
...(/* @__PURE__ */ range(middle, start)).map(toPage),
|
|
2911
|
+
toEllipsis(),
|
|
2912
|
+
toPage(pageCount)
|
|
2913
|
+
]);
|
|
2914
|
+
}
|
|
2915
|
+
}),
|
|
2916
|
+
pageStart,
|
|
2917
|
+
pageStop,
|
|
2918
|
+
isFirst,
|
|
2919
|
+
isLast,
|
|
2920
|
+
first,
|
|
2921
|
+
last,
|
|
2922
|
+
next,
|
|
2923
|
+
prev,
|
|
2924
|
+
select,
|
|
2925
|
+
get itemsPerPage() {
|
|
2926
|
+
return toValue(_itemsPerPage);
|
|
2927
|
+
},
|
|
2881
2928
|
get size() {
|
|
2882
|
-
return
|
|
2929
|
+
return toValue(_size);
|
|
2930
|
+
},
|
|
2931
|
+
get pages() {
|
|
2932
|
+
return pages.value;
|
|
2883
2933
|
}
|
|
2884
2934
|
};
|
|
2885
2935
|
}
|
|
2886
|
-
function createLocaleFallback() {
|
|
2887
|
-
return {
|
|
2888
|
-
size: 0,
|
|
2889
|
-
t: (key, _params, fallback) => fallback ?? key,
|
|
2890
|
-
n: String
|
|
2891
|
-
};
|
|
2892
|
-
}
|
|
2893
2936
|
/**
|
|
2894
|
-
* Creates a
|
|
2895
|
-
*
|
|
2896
|
-
* @param options The options for the locale context.
|
|
2897
|
-
* @template Z The type of the locale ticket.
|
|
2898
|
-
* @template E The type of the locale context.
|
|
2899
|
-
* @returns A new locale context.
|
|
2937
|
+
* Creates a pagination context for dependency injection.
|
|
2900
2938
|
*
|
|
2901
|
-
* @
|
|
2939
|
+
* @param options The options including namespace.
|
|
2940
|
+
* @returns A trinity: [usePagination, providePagination, defaultContext]
|
|
2902
2941
|
*
|
|
2903
2942
|
* @example
|
|
2904
2943
|
* ```ts
|
|
2905
|
-
*
|
|
2944
|
+
* // With default namespace 'v0:pagination'
|
|
2945
|
+
* const [usePagination, providePaginationContext] = createPaginationContext({ size: 50 })
|
|
2906
2946
|
*
|
|
2907
|
-
*
|
|
2908
|
-
*
|
|
2909
|
-
*
|
|
2910
|
-
*
|
|
2911
|
-
* es: { hello: 'Hola' },
|
|
2912
|
-
* },
|
|
2947
|
+
* // Or with custom namespace
|
|
2948
|
+
* const [usePagination, providePaginationContext] = createPaginationContext({
|
|
2949
|
+
* namespace: 'my-pagination',
|
|
2950
|
+
* size: 50,
|
|
2913
2951
|
* })
|
|
2914
2952
|
*
|
|
2915
|
-
* //
|
|
2916
|
-
*
|
|
2953
|
+
* // Parent component
|
|
2954
|
+
* providePaginationContext()
|
|
2917
2955
|
*
|
|
2918
|
-
* //
|
|
2919
|
-
* const
|
|
2920
|
-
*
|
|
2956
|
+
* // Child component
|
|
2957
|
+
* const pagination = usePagination()
|
|
2958
|
+
* pagination.next()
|
|
2921
2959
|
* ```
|
|
2922
2960
|
*/
|
|
2923
|
-
function
|
|
2924
|
-
const { namespace = "v0:
|
|
2925
|
-
const [
|
|
2926
|
-
const context =
|
|
2927
|
-
function
|
|
2928
|
-
return
|
|
2961
|
+
function createPaginationContext(_options = {}) {
|
|
2962
|
+
const { namespace = "v0:pagination", ...options } = _options;
|
|
2963
|
+
const [usePaginationContext, _providePaginationContext] = createContext(namespace);
|
|
2964
|
+
const context = createPagination(options);
|
|
2965
|
+
function providePaginationContext(_context = context, app) {
|
|
2966
|
+
return _providePaginationContext(_context, app);
|
|
2929
2967
|
}
|
|
2930
|
-
return createTrinity(
|
|
2968
|
+
return createTrinity(usePaginationContext, providePaginationContext, context);
|
|
2931
2969
|
}
|
|
2932
2970
|
/**
|
|
2933
|
-
*
|
|
2971
|
+
* Returns the current pagination instance from context.
|
|
2934
2972
|
*
|
|
2935
|
-
* @param
|
|
2936
|
-
* @
|
|
2937
|
-
* @template E The type of the locale context.
|
|
2938
|
-
* @template R The type of the token ticket.
|
|
2939
|
-
* @template O The type of the token context.
|
|
2940
|
-
* @returns A new locale plugin.
|
|
2973
|
+
* @param namespace The namespace. @default 'v0:pagination'
|
|
2974
|
+
* @returns The pagination context.
|
|
2941
2975
|
*
|
|
2942
|
-
* @
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
const [, provideLocaleContext, context] = createLocaleContext({
|
|
2947
|
-
...options,
|
|
2948
|
-
namespace,
|
|
2949
|
-
adapter,
|
|
2950
|
-
messages
|
|
2951
|
-
});
|
|
2952
|
-
return createPlugin({
|
|
2953
|
-
namespace,
|
|
2954
|
-
provide: (app) => {
|
|
2955
|
-
provideLocaleContext(context, app);
|
|
2956
|
-
}
|
|
2957
|
-
});
|
|
2958
|
-
}
|
|
2959
|
-
/**
|
|
2960
|
-
* Returns the current locale instance.
|
|
2976
|
+
* @example
|
|
2977
|
+
* ```vue
|
|
2978
|
+
* <script setup lang="ts">
|
|
2979
|
+
* import { usePagination } from '@vuetify/v0'
|
|
2961
2980
|
*
|
|
2962
|
-
*
|
|
2981
|
+
* const pagination = usePagination()
|
|
2982
|
+
* <\/script>
|
|
2963
2983
|
*
|
|
2964
|
-
*
|
|
2984
|
+
* <template>
|
|
2985
|
+
* <button @click="pagination.prev()" :disabled="pagination.isFirst.value">Prev</button>
|
|
2986
|
+
* <button @click="pagination.next()" :disabled="pagination.isLast.value">Next</button>
|
|
2987
|
+
* </template>
|
|
2988
|
+
* ```
|
|
2965
2989
|
*/
|
|
2966
|
-
function
|
|
2967
|
-
|
|
2968
|
-
if (!getCurrentInstance()) return fallback;
|
|
2969
|
-
try {
|
|
2970
|
-
return useContext(namespace, fallback);
|
|
2971
|
-
} catch {
|
|
2972
|
-
return fallback;
|
|
2973
|
-
}
|
|
2990
|
+
function usePagination(namespace = "v0:pagination") {
|
|
2991
|
+
return useContext(namespace);
|
|
2974
2992
|
}
|
|
2975
2993
|
|
|
2976
2994
|
//#endregion
|
|
@@ -3171,4 +3189,4 @@ function useStep(namespace = "v0:step") {
|
|
|
3171
3189
|
}
|
|
3172
3190
|
|
|
3173
3191
|
//#endregion
|
|
3174
|
-
export { createGroupContext as A, createLogger as B,
|
|
3192
|
+
export { createGroupContext as A, createLogger as B, createTokens as C, createSingleContext as D, createSingle as E, createSelection as F, PinoLoggerAdapter as G, createLoggerPlugin as H, createSelectionContext as I, createTrinity as J, ConsolaLoggerAdapter as K, useSelection as L, useProxyRegistry as M, useProxyModel as N, useSingle as O, toArray as P, createRegistryContext as R, Vuetify0LocaleAdapter as S, useTokens as T, useLogger as U, createLoggerContext as V, Vuetify0LoggerAdapter as W, provideContext as X, createContext as Y, useContext as Z, createLocale as _, createPaginationContext as a, createLocalePlugin as b, createOverflowContext as c, useResizeObserver as d, createFallbackHydration as f, useHydration as g, createHydrationPlugin as h, createPagination as i, useGroup as j, createGroup as k, useOverflow as l, createHydrationContext as m, createStepContext as n, usePagination as o, createHydration as p, createPlugin as q, useStep as r, createOverflow as s, createStep as t, useElementSize as u, createLocaleContext as v, createTokensContext as w, useLocale as x, createLocaleFallback as y, useRegistry as z };
|