@vuetify/v0 0.0.24-beta.1 → 0.1.0
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 +2 -2
- package/dist/adapter-L4Php1_S.d.mts +97 -0
- package/dist/browser/index.js +1318 -842
- package/dist/components/index.d.mts +4 -4
- package/dist/components/index.mjs +6 -6
- package/dist/{components-Dd4KKVtk.mjs → components-V4KaMfn-.mjs} +442 -117
- package/dist/composables/index.d.mts +5 -4
- package/dist/composables/index.mjs +4 -4
- package/dist/constants/index.d.mts +1 -1
- package/dist/constants/index.mjs +3 -3
- package/dist/date/index.d.mts +124 -0
- package/dist/date/index.mjs +7514 -0
- package/dist/{globals-CiCJWcbb.mjs → globals-CgcVstn0.mjs} +1 -1
- package/dist/{index-CAEB2sxS.d.mts → index-CSjKBMhp.d.mts} +738 -349
- package/dist/{index-C8YcMooA.d.mts → index-CoO8LW8o.d.mts} +13 -9
- package/dist/{index-DYSwiS9k.d.mts → index-DlxrzbvZ.d.mts} +21 -1
- package/dist/{index-rcTqb9U3.d.mts → index-DsiFkTD8.d.mts} +662 -306
- package/dist/{index-Bby5ljat.d.mts → index-t-t6sAn3.d.mts} +222 -41
- package/dist/index.d.mts +8 -7
- package/dist/index.mjs +7 -7
- package/dist/json/attributes.json +104 -0
- package/dist/json/importMap.json +20 -0
- package/dist/json/tags.json +46 -0
- package/dist/json/web-types.json +309 -9
- package/dist/types/index.d.mts +2 -2
- package/dist/{useClickOutside-BfEvdnA4.mjs → useClickOutside-Cj8CguMD.mjs} +844 -699
- package/dist/utilities/index.d.mts +3 -3
- package/dist/utilities/index.mjs +2 -2
- package/dist/{utilities-9i1hJnMd.mjs → utilities-B58TiS_S.mjs} +41 -34
- package/package.json +21 -3
- /package/dist/{constants-3l8TGg5J.mjs → constants-DHKqjdjH.mjs} +0 -0
- /package/dist/{htmlElements-CXObxj0V.mjs → htmlElements-DO9n35bD.mjs} +0 -0
- /package/dist/{index-DMQJJUrv.d.mts → index-cPmI99rd.d.mts} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { _ as
|
|
2
|
-
import { a as SUPPORTS_OBSERVER, i as SUPPORTS_MUTATION_OBSERVER, n as SUPPORTS_INTERSECTION_OBSERVER, r as SUPPORTS_MATCH_MEDIA, s as __LOGGER_ENABLED__, t as IN_BROWSER } from "./globals-
|
|
3
|
-
import { computed, effectScope, inject, isRef, onScopeDispose, provide, reactive, readonly, ref, shallowReactive, shallowReadonly, shallowRef, toRef, toValue, unref, watch, watchEffect } from "vue";
|
|
4
|
-
import
|
|
1
|
+
import { _ as useId$1, a as isFunction, c as isNullOrUndefined, f as isString, g as range, h as mergeDeep, i as isBoolean, l as isNumber, m as isUndefined, o as isNaN, p as isSymbol, r as isArray, s as isNull, t as clamp, u as isObject, v as instanceExists } from "./utilities-B58TiS_S.mjs";
|
|
2
|
+
import { a as SUPPORTS_OBSERVER, i as SUPPORTS_MUTATION_OBSERVER, n as SUPPORTS_INTERSECTION_OBSERVER, r as SUPPORTS_MATCH_MEDIA, s as __LOGGER_ENABLED__, t as IN_BROWSER } from "./globals-CgcVstn0.mjs";
|
|
3
|
+
import { computed, effectScope, inject, isRef, nextTick, onScopeDispose, provide, reactive, readonly, ref, shallowReactive, shallowReadonly, shallowRef, toRef, toValue, unref, watch, watchEffect } from "vue";
|
|
4
|
+
import flagsmith from "flagsmith";
|
|
5
5
|
|
|
6
6
|
//#region src/composables/createContext/index.ts
|
|
7
7
|
/**
|
|
@@ -602,12 +602,13 @@ function useLogger(namespace = "v0:logger") {
|
|
|
602
602
|
*/
|
|
603
603
|
function createRegistry(options) {
|
|
604
604
|
const logger$1 = useLogger();
|
|
605
|
-
const
|
|
605
|
+
const events = options?.events ?? false;
|
|
606
|
+
const reactive$1 = options?.reactive ?? false;
|
|
607
|
+
const collection = reactive$1 ? shallowReactive(/* @__PURE__ */ new Map()) : /* @__PURE__ */ new Map();
|
|
606
608
|
const catalog = /* @__PURE__ */ new Map();
|
|
607
609
|
const directory = /* @__PURE__ */ new Map();
|
|
608
610
|
const cache = /* @__PURE__ */ new Map();
|
|
609
611
|
const listeners = /* @__PURE__ */ new Map();
|
|
610
|
-
const events = options?.events ?? false;
|
|
611
612
|
let indexDependentCount = 0;
|
|
612
613
|
let needsReindex = false;
|
|
613
614
|
let minDirtyIndex = Infinity;
|
|
@@ -787,7 +788,7 @@ function createRegistry(options) {
|
|
|
787
788
|
}
|
|
788
789
|
function register(registration = {}) {
|
|
789
790
|
const size = collection.size;
|
|
790
|
-
const id = registration.id ?? /* @__PURE__ */
|
|
791
|
+
const id = registration.id ?? /* @__PURE__ */ useId$1();
|
|
791
792
|
if (has(id)) {
|
|
792
793
|
logger$1.warn(`Ticket "${id}" already exists. Use \`upsert()\` to update or check \`has()\` before registering.`);
|
|
793
794
|
return get(id);
|
|
@@ -797,13 +798,14 @@ function createRegistry(options) {
|
|
|
797
798
|
const value = valueIsUndefined ? index : registration.value;
|
|
798
799
|
const valueIsIndex = valueIsUndefined;
|
|
799
800
|
if (valueIsIndex) indexDependentCount++;
|
|
800
|
-
const
|
|
801
|
+
const rawTicket = {
|
|
801
802
|
...registration,
|
|
802
803
|
id,
|
|
803
804
|
index,
|
|
804
805
|
value,
|
|
805
806
|
valueIsIndex
|
|
806
807
|
};
|
|
808
|
+
const ticket = reactive$1 ? shallowReactive(rawTicket) : rawTicket;
|
|
807
809
|
collection.set(ticket.id, ticket);
|
|
808
810
|
directory.set(ticket.index, ticket.id);
|
|
809
811
|
assign(ticket.value, ticket.id);
|
|
@@ -956,8 +958,9 @@ function createRegistryContext(_options = {}) {
|
|
|
956
958
|
* Supports disabled items, mandatory selection enforcement, and auto-enrollment.
|
|
957
959
|
*
|
|
958
960
|
* @param options The options for the selection instance.
|
|
959
|
-
* @template Z The type
|
|
960
|
-
* @template E The type
|
|
961
|
+
* @template Z The input ticket type - what users provide to register(). Extend SelectionTicketInput to add custom properties.
|
|
962
|
+
* @template E The output ticket type - what users receive from get(). Automatically includes selection methods.
|
|
963
|
+
* @template R The context type. Defaults to SelectionContext<Z, E>.
|
|
961
964
|
* @returns A new selection instance with selection management methods.
|
|
962
965
|
*
|
|
963
966
|
* @remarks
|
|
@@ -980,6 +983,7 @@ function createRegistryContext(_options = {}) {
|
|
|
980
983
|
* ```ts
|
|
981
984
|
* import { createSelection } from '@vuetify/v0'
|
|
982
985
|
*
|
|
986
|
+
* // Basic usage
|
|
983
987
|
* const selection = createSelection({ mandatory: true })
|
|
984
988
|
*
|
|
985
989
|
* selection.onboard([
|
|
@@ -994,6 +998,23 @@ function createRegistryContext(_options = {}) {
|
|
|
994
998
|
* console.log(selection.selectedIds) // Set { 'item-1', 'item-3' }
|
|
995
999
|
* console.log(Array.from(selection.selectedValues.value)) // ['Item 1', 'Item 3']
|
|
996
1000
|
* ```
|
|
1001
|
+
*
|
|
1002
|
+
* @example
|
|
1003
|
+
* ```ts
|
|
1004
|
+
* // With custom ticket type
|
|
1005
|
+
* interface MyTicket extends SelectionTicketInput {
|
|
1006
|
+
* label: string
|
|
1007
|
+
* icon?: string
|
|
1008
|
+
* }
|
|
1009
|
+
*
|
|
1010
|
+
* const tabs = createSelection<MyTicket>()
|
|
1011
|
+
*
|
|
1012
|
+
* tabs.register({ label: 'Home', icon: 'mdi-home' })
|
|
1013
|
+
* tabs.register({ label: 'Settings' })
|
|
1014
|
+
*
|
|
1015
|
+
* const ticket = tabs.get('...')
|
|
1016
|
+
* // ticket has: label, icon, isSelected, select(), unselect(), toggle()
|
|
1017
|
+
* ```
|
|
997
1018
|
*/
|
|
998
1019
|
function createSelection(_options = {}) {
|
|
999
1020
|
const { disabled = false, enroll = false, mandatory = false, multiple = false, ...options } = _options;
|
|
@@ -1034,7 +1055,7 @@ function createSelection(_options = {}) {
|
|
|
1034
1055
|
return selectedIds.has(id);
|
|
1035
1056
|
}
|
|
1036
1057
|
function register(registration = {}) {
|
|
1037
|
-
const id = registration.id ?? /* @__PURE__ */
|
|
1058
|
+
const id = registration.id ?? /* @__PURE__ */ useId$1();
|
|
1038
1059
|
const item = {
|
|
1039
1060
|
disabled: false,
|
|
1040
1061
|
select: () => select(id),
|
|
@@ -1091,8 +1112,9 @@ function createSelection(_options = {}) {
|
|
|
1091
1112
|
* Creates a new selection context.
|
|
1092
1113
|
*
|
|
1093
1114
|
* @param options The options for the selection context.
|
|
1094
|
-
* @template Z The type
|
|
1095
|
-
* @template E The type
|
|
1115
|
+
* @template Z The input ticket type - what users provide to register().
|
|
1116
|
+
* @template E The output ticket type - what users receive from get().
|
|
1117
|
+
* @template R The context type. Defaults to SelectionContext<Z, E>.
|
|
1096
1118
|
* @returns A new selection context.
|
|
1097
1119
|
*
|
|
1098
1120
|
* @see https://0.vuetifyjs.com/composables/selection/use-selection
|
|
@@ -1114,6 +1136,17 @@ function createSelection(_options = {}) {
|
|
|
1114
1136
|
* const checkboxes = useCheckboxes()
|
|
1115
1137
|
* checkboxes.select('checkbox-1')
|
|
1116
1138
|
* ```
|
|
1139
|
+
*
|
|
1140
|
+
* @example
|
|
1141
|
+
* ```ts
|
|
1142
|
+
* // With custom ticket type
|
|
1143
|
+
* interface TabTicket extends SelectionTicketInput {
|
|
1144
|
+
* label: string
|
|
1145
|
+
* icon?: string
|
|
1146
|
+
* }
|
|
1147
|
+
*
|
|
1148
|
+
* export const [useTabs, provideTabs, tabs] = createSelectionContext<TabTicket>()
|
|
1149
|
+
* ```
|
|
1117
1150
|
*/
|
|
1118
1151
|
function createSelectionContext(_options = {}) {
|
|
1119
1152
|
const { namespace = "v0:selection", ...options } = _options;
|
|
@@ -1128,6 +1161,9 @@ function createSelectionContext(_options = {}) {
|
|
|
1128
1161
|
* Returns the current selection instance.
|
|
1129
1162
|
*
|
|
1130
1163
|
* @param namespace The namespace for the selection context. Defaults to `'v0:selection'`.
|
|
1164
|
+
* @template Z The input ticket type.
|
|
1165
|
+
* @template E The output ticket type.
|
|
1166
|
+
* @template R The context type.
|
|
1131
1167
|
* @returns The current selection instance.
|
|
1132
1168
|
*
|
|
1133
1169
|
* @see https://0.vuetifyjs.com/composables/selection/use-selection
|
|
@@ -1388,7 +1424,7 @@ function createGroup(_options = {}) {
|
|
|
1388
1424
|
else selection.toggle(id);
|
|
1389
1425
|
}
|
|
1390
1426
|
function register(registration = {}) {
|
|
1391
|
-
const id = registration.id ?? /* @__PURE__ */
|
|
1427
|
+
const id = registration.id ?? /* @__PURE__ */ useId$1();
|
|
1392
1428
|
const item = {
|
|
1393
1429
|
...registration,
|
|
1394
1430
|
id,
|
|
@@ -1477,8 +1513,9 @@ function createGroup(_options = {}) {
|
|
|
1477
1513
|
* Creates a new group context.
|
|
1478
1514
|
*
|
|
1479
1515
|
* @param options The options for the group context.
|
|
1480
|
-
* @template Z The
|
|
1481
|
-
* @template E The
|
|
1516
|
+
* @template Z The input ticket type.
|
|
1517
|
+
* @template E The output ticket type.
|
|
1518
|
+
* @template R The context type.
|
|
1482
1519
|
* @returns A new group context.
|
|
1483
1520
|
*
|
|
1484
1521
|
* @see https://0.vuetifyjs.com/composables/selection/use-group
|
|
@@ -1513,6 +1550,9 @@ function createGroupContext(_options = {}) {
|
|
|
1513
1550
|
* Returns the current group instance.
|
|
1514
1551
|
*
|
|
1515
1552
|
* @param namespace The namespace for the group context. Defaults to `'v0:group'`.
|
|
1553
|
+
* @template Z The input ticket type.
|
|
1554
|
+
* @template E The output ticket type.
|
|
1555
|
+
* @template R The context type.
|
|
1516
1556
|
* @returns The current group instance.
|
|
1517
1557
|
*
|
|
1518
1558
|
* @see https://0.vuetifyjs.com/composables/selection/use-group
|
|
@@ -1819,18 +1859,26 @@ function toReactive(objectRef) {
|
|
|
1819
1859
|
*/
|
|
1820
1860
|
function createHydration() {
|
|
1821
1861
|
const isHydrated = shallowRef(false);
|
|
1862
|
+
const isSettled = shallowRef(false);
|
|
1822
1863
|
function hydrate() {
|
|
1823
1864
|
isHydrated.value = true;
|
|
1824
1865
|
}
|
|
1866
|
+
function settle() {
|
|
1867
|
+
isSettled.value = true;
|
|
1868
|
+
}
|
|
1825
1869
|
return {
|
|
1826
1870
|
isHydrated: shallowReadonly(isHydrated),
|
|
1827
|
-
|
|
1871
|
+
isSettled: shallowReadonly(isSettled),
|
|
1872
|
+
hydrate,
|
|
1873
|
+
settle
|
|
1828
1874
|
};
|
|
1829
1875
|
}
|
|
1830
1876
|
function createFallbackHydration() {
|
|
1831
1877
|
return {
|
|
1832
1878
|
isHydrated: shallowReadonly(shallowRef(true)),
|
|
1833
|
-
|
|
1879
|
+
isSettled: shallowReadonly(shallowRef(true)),
|
|
1880
|
+
hydrate: () => {},
|
|
1881
|
+
settle: () => {}
|
|
1834
1882
|
};
|
|
1835
1883
|
}
|
|
1836
1884
|
/**
|
|
@@ -1894,9 +1942,11 @@ function createHydrationPlugin(_options = {}) {
|
|
|
1894
1942
|
provideHydrationContext(context, app);
|
|
1895
1943
|
},
|
|
1896
1944
|
setup: (app) => {
|
|
1897
|
-
app.mixin({ mounted() {
|
|
1945
|
+
app.mixin({ async mounted() {
|
|
1898
1946
|
if (!/* @__PURE__ */ isNull(this.$parent)) return;
|
|
1899
1947
|
context.hydrate();
|
|
1948
|
+
await nextTick();
|
|
1949
|
+
context.settle();
|
|
1900
1950
|
} });
|
|
1901
1951
|
}
|
|
1902
1952
|
});
|
|
@@ -1914,13 +1964,16 @@ function createHydrationPlugin(_options = {}) {
|
|
|
1914
1964
|
* <script setup lang="ts">
|
|
1915
1965
|
* import { useHydration } from '@vuetify/v0'
|
|
1916
1966
|
*
|
|
1917
|
-
* const
|
|
1967
|
+
* const { isHydrated, isSettled } = useHydration()
|
|
1968
|
+
*
|
|
1969
|
+
* // Use isSettled to gate animations after state restoration
|
|
1970
|
+
* const transition = computed(() => isSettled.value ? 'fade' : undefined)
|
|
1918
1971
|
* <\/script>
|
|
1919
1972
|
*
|
|
1920
1973
|
* <template>
|
|
1921
|
-
* <
|
|
1922
|
-
* <
|
|
1923
|
-
* </
|
|
1974
|
+
* <Transition :name="transition">
|
|
1975
|
+
* <div v-if="show">Animates only after hydration settles</div>
|
|
1976
|
+
* </Transition>
|
|
1924
1977
|
* </template>
|
|
1925
1978
|
* ```
|
|
1926
1979
|
*/
|
|
@@ -2221,8 +2274,9 @@ function useBreakpoints(namespace = "v0:breakpoints") {
|
|
|
2221
2274
|
* Adds computed singular properties: `selectedId`, `selectedItem`, `selectedIndex`, `selectedValue`.
|
|
2222
2275
|
*
|
|
2223
2276
|
* @param options The options for the single selection instance.
|
|
2224
|
-
* @template Z The type
|
|
2225
|
-
* @template E The type
|
|
2277
|
+
* @template Z The input ticket type - what users provide to register().
|
|
2278
|
+
* @template E The output ticket type - what users receive from get().
|
|
2279
|
+
* @template R The context type.
|
|
2226
2280
|
* @returns A new single selection instance with single-selection enforcement.
|
|
2227
2281
|
*
|
|
2228
2282
|
* @remarks
|
|
@@ -2263,6 +2317,18 @@ function useBreakpoints(namespace = "v0:breakpoints") {
|
|
|
2263
2317
|
* console.log(tabs.selectedId.value) // 'about'
|
|
2264
2318
|
* console.log(tabs.selectedIds.size) // 1 (always enforces single selection)
|
|
2265
2319
|
* ```
|
|
2320
|
+
*
|
|
2321
|
+
* @example
|
|
2322
|
+
* ```ts
|
|
2323
|
+
* // With custom ticket type
|
|
2324
|
+
* interface TabTicket extends SingleTicketInput {
|
|
2325
|
+
* label: string
|
|
2326
|
+
* icon?: string
|
|
2327
|
+
* }
|
|
2328
|
+
*
|
|
2329
|
+
* const tabs = createSingle<TabTicket>()
|
|
2330
|
+
* tabs.register({ label: 'Home', icon: 'mdi-home' })
|
|
2331
|
+
* ```
|
|
2266
2332
|
*/
|
|
2267
2333
|
function createSingle(_options = {}) {
|
|
2268
2334
|
const { mandatory = false, multiple = false, ...options } = _options;
|
|
@@ -2300,8 +2366,9 @@ function createSingle(_options = {}) {
|
|
|
2300
2366
|
* Creates a new single selection context.
|
|
2301
2367
|
*
|
|
2302
2368
|
* @param options The options for the single selection context.
|
|
2303
|
-
* @template Z The
|
|
2304
|
-
* @template E The
|
|
2369
|
+
* @template Z The input ticket type.
|
|
2370
|
+
* @template E The output ticket type.
|
|
2371
|
+
* @template R The context type.
|
|
2305
2372
|
* @returns A new single selection context.
|
|
2306
2373
|
*
|
|
2307
2374
|
* @see https://0.vuetifyjs.com/composables/selection/use-single
|
|
@@ -2334,6 +2401,9 @@ function createSingleContext(_options = {}) {
|
|
|
2334
2401
|
* Returns the current single selection instance.
|
|
2335
2402
|
*
|
|
2336
2403
|
* @param namespace The namespace for the single selection context. Defaults to `'v0:single'`.
|
|
2404
|
+
* @template Z The input ticket type.
|
|
2405
|
+
* @template E The output ticket type.
|
|
2406
|
+
* @template R The context type.
|
|
2337
2407
|
* @returns The current single selection instance.
|
|
2338
2408
|
*
|
|
2339
2409
|
* @see https://0.vuetifyjs.com/composables/selection/use-single
|
|
@@ -2803,585 +2873,6 @@ function useLocale(namespace = "v0:locale") {
|
|
|
2803
2873
|
}
|
|
2804
2874
|
}
|
|
2805
2875
|
|
|
2806
|
-
//#endregion
|
|
2807
|
-
//#region src/composables/useDate/adapters/v0.ts
|
|
2808
|
-
/**
|
|
2809
|
-
* @module Vuetify0DateAdapter
|
|
2810
|
-
*
|
|
2811
|
-
* @remarks
|
|
2812
|
-
* Default DateAdapter for v0, built on the Temporal API.
|
|
2813
|
-
* Uses Temporal.PlainDateTime as the primary date type.
|
|
2814
|
-
*
|
|
2815
|
-
* Implements the full date-io IUtils interface for industry compatibility.
|
|
2816
|
-
*
|
|
2817
|
-
* Requires native Temporal support or @js-temporal/polyfill.
|
|
2818
|
-
*
|
|
2819
|
-
* @see https://tc39.es/proposal-temporal/docs/
|
|
2820
|
-
* @see https://github.com/dmtrKovalenko/date-io
|
|
2821
|
-
*/
|
|
2822
|
-
/** Single regex for token replacement in formatByString */
|
|
2823
|
-
const FORMAT_TOKEN_REGEX = /YYYY|YY|MMMM|MMM|MM|M|dddd|ddd|DD|D|HH|H|hh|h|mm|m|ss|s|A|a/g;
|
|
2824
|
-
/** Maximum cache size to prevent memory leaks */
|
|
2825
|
-
const MAX_CACHE_SIZE = 50;
|
|
2826
|
-
var Vuetify0DateAdapter = class {
|
|
2827
|
-
_locale;
|
|
2828
|
-
/** Cache for Intl.DateTimeFormat instances, keyed by locale + options */
|
|
2829
|
-
formatCache = /* @__PURE__ */ new Map();
|
|
2830
|
-
/** Cache for Intl.NumberFormat instances, keyed by locale */
|
|
2831
|
-
numberFormatCache = /* @__PURE__ */ new Map();
|
|
2832
|
-
constructor(locale = "en-US") {
|
|
2833
|
-
this._locale = locale;
|
|
2834
|
-
}
|
|
2835
|
-
/** Current locale. Setting a new locale clears format caches. */
|
|
2836
|
-
get locale() {
|
|
2837
|
-
return this._locale;
|
|
2838
|
-
}
|
|
2839
|
-
set locale(value) {
|
|
2840
|
-
if (this._locale !== value) {
|
|
2841
|
-
this._locale = value;
|
|
2842
|
-
this.formatCache.clear();
|
|
2843
|
-
this.numberFormatCache.clear();
|
|
2844
|
-
}
|
|
2845
|
-
}
|
|
2846
|
-
/**
|
|
2847
|
-
* Create a date from various input types.
|
|
2848
|
-
*
|
|
2849
|
-
* @param value - Date value (PlainDateTime, PlainDate, ZonedDateTime, Date, ISO string, timestamp)
|
|
2850
|
-
* @returns PlainDateTime or null if invalid
|
|
2851
|
-
*
|
|
2852
|
-
* @remarks
|
|
2853
|
-
* **SSR Safety:** When called without arguments:
|
|
2854
|
-
* - Browser: Returns current time via `Temporal.Now.plainDateTimeISO()`
|
|
2855
|
-
* - Server: Returns epoch (1970-01-01T00:00:00) for deterministic rendering
|
|
2856
|
-
*
|
|
2857
|
-
* For SSR apps needing current time, pass `Date.now()` explicitly and handle
|
|
2858
|
-
* hydration via `<ClientOnly>` (Nuxt) or `v-if` + `onMounted` pattern.
|
|
2859
|
-
*/
|
|
2860
|
-
date(value) {
|
|
2861
|
-
if (/* @__PURE__ */ isNullOrUndefined(value)) return IN_BROWSER ? Temporal.Now.plainDateTimeISO() : Temporal.PlainDateTime.from({
|
|
2862
|
-
year: 1970,
|
|
2863
|
-
month: 1,
|
|
2864
|
-
day: 1,
|
|
2865
|
-
hour: 0,
|
|
2866
|
-
minute: 0,
|
|
2867
|
-
second: 0
|
|
2868
|
-
});
|
|
2869
|
-
if (value instanceof Temporal.PlainDateTime) return value;
|
|
2870
|
-
if (value instanceof Temporal.PlainDate) return value.toPlainDateTime();
|
|
2871
|
-
if (value instanceof Temporal.ZonedDateTime) return value.toPlainDateTime();
|
|
2872
|
-
if (value instanceof Date) return Temporal.PlainDateTime.from({
|
|
2873
|
-
year: value.getFullYear(),
|
|
2874
|
-
month: value.getMonth() + 1,
|
|
2875
|
-
day: value.getDate(),
|
|
2876
|
-
hour: value.getHours(),
|
|
2877
|
-
minute: value.getMinutes(),
|
|
2878
|
-
second: value.getSeconds(),
|
|
2879
|
-
millisecond: value.getMilliseconds()
|
|
2880
|
-
});
|
|
2881
|
-
if (/* @__PURE__ */ isString(value)) try {
|
|
2882
|
-
return Temporal.PlainDateTime.from(value);
|
|
2883
|
-
} catch {
|
|
2884
|
-
try {
|
|
2885
|
-
return this.parseISO(value);
|
|
2886
|
-
} catch {
|
|
2887
|
-
return null;
|
|
2888
|
-
}
|
|
2889
|
-
}
|
|
2890
|
-
if (/* @__PURE__ */ isNumber(value)) {
|
|
2891
|
-
const date = new Date(value);
|
|
2892
|
-
return Temporal.PlainDateTime.from({
|
|
2893
|
-
year: date.getFullYear(),
|
|
2894
|
-
month: date.getMonth() + 1,
|
|
2895
|
-
day: date.getDate(),
|
|
2896
|
-
hour: date.getHours(),
|
|
2897
|
-
minute: date.getMinutes(),
|
|
2898
|
-
second: date.getSeconds(),
|
|
2899
|
-
millisecond: date.getMilliseconds()
|
|
2900
|
-
});
|
|
2901
|
-
}
|
|
2902
|
-
return null;
|
|
2903
|
-
}
|
|
2904
|
-
toJsDate(value) {
|
|
2905
|
-
return new Date(value.year, value.month - 1, value.day, value.hour, value.minute, value.second, value.millisecond);
|
|
2906
|
-
}
|
|
2907
|
-
parseISO(dateString) {
|
|
2908
|
-
if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) return Temporal.PlainDate.from(dateString).toPlainDateTime();
|
|
2909
|
-
if (dateString.includes("Z") || /[+-]\d{2}:\d{2}$/.test(dateString)) return Temporal.Instant.from(dateString).toZonedDateTimeISO("UTC").toPlainDateTime();
|
|
2910
|
-
return Temporal.PlainDateTime.from(dateString);
|
|
2911
|
-
}
|
|
2912
|
-
toISO(date) {
|
|
2913
|
-
return date.toString();
|
|
2914
|
-
}
|
|
2915
|
-
/**
|
|
2916
|
-
* Parses a date string into a PlainDateTime.
|
|
2917
|
-
*
|
|
2918
|
-
* **Known limitation**: The `format` parameter is currently ignored.
|
|
2919
|
-
* Temporal API doesn't provide built-in format parsing, and implementing
|
|
2920
|
-
* full format string parsing (e.g., 'MM/DD/YYYY') would require a
|
|
2921
|
-
* substantial custom parser. This method delegates to `date()` which
|
|
2922
|
-
* handles ISO 8601 strings and common formats.
|
|
2923
|
-
*
|
|
2924
|
-
* For custom format parsing, consider using a library like date-fns or
|
|
2925
|
-
* luxon with a custom adapter.
|
|
2926
|
-
*
|
|
2927
|
-
* @param value - The date string to parse
|
|
2928
|
-
* @param _format - Format hint (currently ignored)
|
|
2929
|
-
* @returns Parsed PlainDateTime or null if invalid
|
|
2930
|
-
*/
|
|
2931
|
-
parse(value, _format) {
|
|
2932
|
-
try {
|
|
2933
|
-
return this.date(value);
|
|
2934
|
-
} catch {
|
|
2935
|
-
return null;
|
|
2936
|
-
}
|
|
2937
|
-
}
|
|
2938
|
-
isValid(date) {
|
|
2939
|
-
if (/* @__PURE__ */ isNullOrUndefined(date)) return false;
|
|
2940
|
-
if (date instanceof Temporal.PlainDateTime) return true;
|
|
2941
|
-
if (date instanceof Temporal.PlainDate) return true;
|
|
2942
|
-
if (date instanceof Temporal.ZonedDateTime) return true;
|
|
2943
|
-
if (date instanceof Date) return !Number.isNaN(date.getTime());
|
|
2944
|
-
if (/* @__PURE__ */ isString(date)) try {
|
|
2945
|
-
Temporal.PlainDateTime.from(date);
|
|
2946
|
-
return true;
|
|
2947
|
-
} catch {
|
|
2948
|
-
try {
|
|
2949
|
-
Temporal.PlainDate.from(date);
|
|
2950
|
-
return true;
|
|
2951
|
-
} catch {
|
|
2952
|
-
return false;
|
|
2953
|
-
}
|
|
2954
|
-
}
|
|
2955
|
-
return false;
|
|
2956
|
-
}
|
|
2957
|
-
isNull(value) {
|
|
2958
|
-
return /* @__PURE__ */ isNullOrUndefined(value);
|
|
2959
|
-
}
|
|
2960
|
-
getCurrentLocaleCode() {
|
|
2961
|
-
return this.locale;
|
|
2962
|
-
}
|
|
2963
|
-
is12HourCycleInCurrentLocale() {
|
|
2964
|
-
return new Intl.DateTimeFormat(this.locale, { hour: "numeric" }).resolvedOptions().hour12 ?? false;
|
|
2965
|
-
}
|
|
2966
|
-
format(date, formatString) {
|
|
2967
|
-
const jsDate = this.toJsDate(date);
|
|
2968
|
-
const options = {
|
|
2969
|
-
fullDate: { dateStyle: "full" },
|
|
2970
|
-
fullDateWithWeekday: {
|
|
2971
|
-
weekday: "long",
|
|
2972
|
-
year: "numeric",
|
|
2973
|
-
month: "long",
|
|
2974
|
-
day: "numeric"
|
|
2975
|
-
},
|
|
2976
|
-
normalDate: { dateStyle: "medium" },
|
|
2977
|
-
shortDate: { dateStyle: "short" },
|
|
2978
|
-
year: { year: "numeric" },
|
|
2979
|
-
month: { month: "long" },
|
|
2980
|
-
monthShort: { month: "short" },
|
|
2981
|
-
monthAndYear: {
|
|
2982
|
-
year: "numeric",
|
|
2983
|
-
month: "long"
|
|
2984
|
-
},
|
|
2985
|
-
monthAndDate: {
|
|
2986
|
-
month: "long",
|
|
2987
|
-
day: "numeric"
|
|
2988
|
-
},
|
|
2989
|
-
weekday: { weekday: "long" },
|
|
2990
|
-
weekdayShort: { weekday: "short" },
|
|
2991
|
-
dayOfMonth: { day: "numeric" },
|
|
2992
|
-
hours12h: {
|
|
2993
|
-
hour: "numeric",
|
|
2994
|
-
hour12: true
|
|
2995
|
-
},
|
|
2996
|
-
hours24h: {
|
|
2997
|
-
hour: "numeric",
|
|
2998
|
-
hour12: false
|
|
2999
|
-
},
|
|
3000
|
-
minutes: { minute: "numeric" },
|
|
3001
|
-
seconds: { second: "numeric" },
|
|
3002
|
-
fullTime: { timeStyle: "medium" },
|
|
3003
|
-
fullTime12h: {
|
|
3004
|
-
hour: "numeric",
|
|
3005
|
-
minute: "numeric",
|
|
3006
|
-
second: "numeric",
|
|
3007
|
-
hour12: true
|
|
3008
|
-
},
|
|
3009
|
-
fullTime24h: {
|
|
3010
|
-
hour: "numeric",
|
|
3011
|
-
minute: "numeric",
|
|
3012
|
-
second: "numeric",
|
|
3013
|
-
hour12: false
|
|
3014
|
-
},
|
|
3015
|
-
fullDateTime: {
|
|
3016
|
-
dateStyle: "full",
|
|
3017
|
-
timeStyle: "short"
|
|
3018
|
-
},
|
|
3019
|
-
fullDateTime12h: {
|
|
3020
|
-
dateStyle: "full",
|
|
3021
|
-
hour: "numeric",
|
|
3022
|
-
minute: "numeric",
|
|
3023
|
-
hour12: true
|
|
3024
|
-
},
|
|
3025
|
-
fullDateTime24h: {
|
|
3026
|
-
dateStyle: "full",
|
|
3027
|
-
hour: "numeric",
|
|
3028
|
-
minute: "numeric",
|
|
3029
|
-
hour12: false
|
|
3030
|
-
},
|
|
3031
|
-
keyboardDate: {
|
|
3032
|
-
year: "numeric",
|
|
3033
|
-
month: "2-digit",
|
|
3034
|
-
day: "2-digit"
|
|
3035
|
-
},
|
|
3036
|
-
keyboardDateTime: {
|
|
3037
|
-
year: "numeric",
|
|
3038
|
-
month: "2-digit",
|
|
3039
|
-
day: "2-digit",
|
|
3040
|
-
hour: "numeric",
|
|
3041
|
-
minute: "numeric"
|
|
3042
|
-
},
|
|
3043
|
-
keyboardDateTime12h: {
|
|
3044
|
-
year: "numeric",
|
|
3045
|
-
month: "2-digit",
|
|
3046
|
-
day: "2-digit",
|
|
3047
|
-
hour: "numeric",
|
|
3048
|
-
minute: "numeric",
|
|
3049
|
-
hour12: true
|
|
3050
|
-
},
|
|
3051
|
-
keyboardDateTime24h: {
|
|
3052
|
-
year: "numeric",
|
|
3053
|
-
month: "2-digit",
|
|
3054
|
-
day: "2-digit",
|
|
3055
|
-
hour: "numeric",
|
|
3056
|
-
minute: "numeric",
|
|
3057
|
-
hour12: false
|
|
3058
|
-
}
|
|
3059
|
-
}[formatString];
|
|
3060
|
-
if (options) return this.getFormatter(options).format(jsDate);
|
|
3061
|
-
return this.getFormatter({}).format(jsDate);
|
|
3062
|
-
}
|
|
3063
|
-
formatByString(date, formatString) {
|
|
3064
|
-
const jsDate = this.toJsDate(date);
|
|
3065
|
-
const getTokenValue = (token) => {
|
|
3066
|
-
switch (token) {
|
|
3067
|
-
case "YYYY": return String(date.year);
|
|
3068
|
-
case "YY": return String(date.year).slice(-2);
|
|
3069
|
-
case "MM": return String(date.month).padStart(2, "0");
|
|
3070
|
-
case "M": return String(date.month);
|
|
3071
|
-
case "DD": return String(date.day).padStart(2, "0");
|
|
3072
|
-
case "D": return String(date.day);
|
|
3073
|
-
case "HH": return String(date.hour).padStart(2, "0");
|
|
3074
|
-
case "H": return String(date.hour);
|
|
3075
|
-
case "hh": return String(date.hour % 12 || 12).padStart(2, "0");
|
|
3076
|
-
case "h": return String(date.hour % 12 || 12);
|
|
3077
|
-
case "mm": return String(date.minute).padStart(2, "0");
|
|
3078
|
-
case "m": return String(date.minute);
|
|
3079
|
-
case "ss": return String(date.second).padStart(2, "0");
|
|
3080
|
-
case "s": return String(date.second);
|
|
3081
|
-
case "A": return date.hour < 12 ? "AM" : "PM";
|
|
3082
|
-
case "a": return date.hour < 12 ? "am" : "pm";
|
|
3083
|
-
case "MMMM": return this.getFormatter({ month: "long" }).format(jsDate);
|
|
3084
|
-
case "MMM": return this.getFormatter({ month: "short" }).format(jsDate);
|
|
3085
|
-
case "dddd": return this.getFormatter({ weekday: "long" }).format(jsDate);
|
|
3086
|
-
case "ddd": return this.getFormatter({ weekday: "short" }).format(jsDate);
|
|
3087
|
-
default: return token;
|
|
3088
|
-
}
|
|
3089
|
-
};
|
|
3090
|
-
return formatString.replace(FORMAT_TOKEN_REGEX, (match) => getTokenValue(match));
|
|
3091
|
-
}
|
|
3092
|
-
getFormatHelperText(format) {
|
|
3093
|
-
return {
|
|
3094
|
-
keyboardDate: "mm/dd/yyyy",
|
|
3095
|
-
keyboardDateTime: "mm/dd/yyyy hh:mm",
|
|
3096
|
-
keyboardDateTime12h: "mm/dd/yyyy hh:mm am/pm",
|
|
3097
|
-
keyboardDateTime24h: "mm/dd/yyyy hh:mm"
|
|
3098
|
-
}[format] ?? format.replace(/YYYY/g, "yyyy").replace(/MM/g, "mm").replace(/DD/g, "dd").replace(/HH/g, "hh").replace(/mm/g, "mm").replace(/ss/g, "ss");
|
|
3099
|
-
}
|
|
3100
|
-
formatNumber(numberToFormat) {
|
|
3101
|
-
return this.getNumberFormatter().format(Number(numberToFormat));
|
|
3102
|
-
}
|
|
3103
|
-
getMeridiemText(ampm) {
|
|
3104
|
-
const date = ampm === "am" ? new Date(2020, 0, 1, 9, 0) : new Date(2020, 0, 1, 15, 0);
|
|
3105
|
-
const match = this.getFormatter({
|
|
3106
|
-
hour: "numeric",
|
|
3107
|
-
hour12: true
|
|
3108
|
-
}).format(date).match(/[AP]M|[ap]m|午前|午後|上午|下午/i);
|
|
3109
|
-
return match ? match[0] : ampm.toUpperCase();
|
|
3110
|
-
}
|
|
3111
|
-
startOfDay(date) {
|
|
3112
|
-
return date.with({
|
|
3113
|
-
hour: 0,
|
|
3114
|
-
minute: 0,
|
|
3115
|
-
second: 0,
|
|
3116
|
-
millisecond: 0,
|
|
3117
|
-
microsecond: 0,
|
|
3118
|
-
nanosecond: 0
|
|
3119
|
-
});
|
|
3120
|
-
}
|
|
3121
|
-
endOfDay(date) {
|
|
3122
|
-
return date.with({
|
|
3123
|
-
hour: 23,
|
|
3124
|
-
minute: 59,
|
|
3125
|
-
second: 59,
|
|
3126
|
-
millisecond: 999,
|
|
3127
|
-
microsecond: 999,
|
|
3128
|
-
nanosecond: 999
|
|
3129
|
-
});
|
|
3130
|
-
}
|
|
3131
|
-
startOfWeek(date, firstDayOfWeek = 0) {
|
|
3132
|
-
const diff = (date.dayOfWeek % 7 - firstDayOfWeek + 7) % 7;
|
|
3133
|
-
return this.startOfDay(date.subtract({ days: diff }));
|
|
3134
|
-
}
|
|
3135
|
-
endOfWeek(date, firstDayOfWeek = 0) {
|
|
3136
|
-
const start = this.startOfWeek(date, firstDayOfWeek);
|
|
3137
|
-
return this.endOfDay(start.add({ days: 6 }));
|
|
3138
|
-
}
|
|
3139
|
-
startOfMonth(date) {
|
|
3140
|
-
return this.startOfDay(date.with({ day: 1 }));
|
|
3141
|
-
}
|
|
3142
|
-
endOfMonth(date) {
|
|
3143
|
-
return this.endOfDay(date.with({ day: date.daysInMonth }));
|
|
3144
|
-
}
|
|
3145
|
-
startOfYear(date) {
|
|
3146
|
-
return this.startOfDay(date.with({
|
|
3147
|
-
month: 1,
|
|
3148
|
-
day: 1
|
|
3149
|
-
}));
|
|
3150
|
-
}
|
|
3151
|
-
endOfYear(date) {
|
|
3152
|
-
return this.endOfDay(date.with({
|
|
3153
|
-
month: 12,
|
|
3154
|
-
day: 31
|
|
3155
|
-
}));
|
|
3156
|
-
}
|
|
3157
|
-
addSeconds(date, amount) {
|
|
3158
|
-
return date.add({ seconds: amount });
|
|
3159
|
-
}
|
|
3160
|
-
addMinutes(date, amount) {
|
|
3161
|
-
return date.add({ minutes: amount });
|
|
3162
|
-
}
|
|
3163
|
-
addHours(date, amount) {
|
|
3164
|
-
return date.add({ hours: amount });
|
|
3165
|
-
}
|
|
3166
|
-
addDays(date, amount) {
|
|
3167
|
-
return date.add({ days: amount });
|
|
3168
|
-
}
|
|
3169
|
-
addWeeks(date, amount) {
|
|
3170
|
-
return date.add({ weeks: amount });
|
|
3171
|
-
}
|
|
3172
|
-
addMonths(date, amount) {
|
|
3173
|
-
return date.add({ months: amount });
|
|
3174
|
-
}
|
|
3175
|
-
addYears(date, amount) {
|
|
3176
|
-
return date.add({ years: amount });
|
|
3177
|
-
}
|
|
3178
|
-
isAfter(date, comparing) {
|
|
3179
|
-
return Temporal.PlainDateTime.compare(date, comparing) > 0;
|
|
3180
|
-
}
|
|
3181
|
-
isAfterDay(date, comparing) {
|
|
3182
|
-
return Temporal.PlainDate.compare(date.toPlainDate(), comparing.toPlainDate()) > 0;
|
|
3183
|
-
}
|
|
3184
|
-
isAfterMonth(date, comparing) {
|
|
3185
|
-
if (date.year !== comparing.year) return date.year > comparing.year;
|
|
3186
|
-
return date.month > comparing.month;
|
|
3187
|
-
}
|
|
3188
|
-
isAfterYear(date, comparing) {
|
|
3189
|
-
return date.year > comparing.year;
|
|
3190
|
-
}
|
|
3191
|
-
isBefore(date, comparing) {
|
|
3192
|
-
return Temporal.PlainDateTime.compare(date, comparing) < 0;
|
|
3193
|
-
}
|
|
3194
|
-
isBeforeDay(date, comparing) {
|
|
3195
|
-
return Temporal.PlainDate.compare(date.toPlainDate(), comparing.toPlainDate()) < 0;
|
|
3196
|
-
}
|
|
3197
|
-
isBeforeMonth(date, comparing) {
|
|
3198
|
-
if (date.year !== comparing.year) return date.year < comparing.year;
|
|
3199
|
-
return date.month < comparing.month;
|
|
3200
|
-
}
|
|
3201
|
-
isBeforeYear(date, comparing) {
|
|
3202
|
-
return date.year < comparing.year;
|
|
3203
|
-
}
|
|
3204
|
-
isEqual(date, comparing) {
|
|
3205
|
-
return Temporal.PlainDateTime.compare(date, comparing) === 0;
|
|
3206
|
-
}
|
|
3207
|
-
isSameDay(date, comparing) {
|
|
3208
|
-
return Temporal.PlainDate.compare(date.toPlainDate(), comparing.toPlainDate()) === 0;
|
|
3209
|
-
}
|
|
3210
|
-
isSameMonth(date, comparing) {
|
|
3211
|
-
return date.year === comparing.year && date.month === comparing.month;
|
|
3212
|
-
}
|
|
3213
|
-
isSameYear(date, comparing) {
|
|
3214
|
-
return date.year === comparing.year;
|
|
3215
|
-
}
|
|
3216
|
-
isSameHour(date, comparing) {
|
|
3217
|
-
return date.year === comparing.year && date.month === comparing.month && date.day === comparing.day && date.hour === comparing.hour;
|
|
3218
|
-
}
|
|
3219
|
-
isWithinRange(date, [start, end]) {
|
|
3220
|
-
return Temporal.PlainDateTime.compare(date, start) >= 0 && Temporal.PlainDateTime.compare(date, end) <= 0;
|
|
3221
|
-
}
|
|
3222
|
-
getYear(date) {
|
|
3223
|
-
return date.year;
|
|
3224
|
-
}
|
|
3225
|
-
getMonth(date) {
|
|
3226
|
-
return date.month - 1;
|
|
3227
|
-
}
|
|
3228
|
-
getDate(date) {
|
|
3229
|
-
return date.day;
|
|
3230
|
-
}
|
|
3231
|
-
getHours(date) {
|
|
3232
|
-
return date.hour;
|
|
3233
|
-
}
|
|
3234
|
-
getMinutes(date) {
|
|
3235
|
-
return date.minute;
|
|
3236
|
-
}
|
|
3237
|
-
getSeconds(date) {
|
|
3238
|
-
return date.second;
|
|
3239
|
-
}
|
|
3240
|
-
getDiff(date, comparing, unit) {
|
|
3241
|
-
const unitKey = unit ?? "days";
|
|
3242
|
-
const comp = /* @__PURE__ */ isString(comparing) ? this.date(comparing) : comparing;
|
|
3243
|
-
if (/* @__PURE__ */ isNull(comp)) return 0;
|
|
3244
|
-
const duration = date.since(comp, { largestUnit: unitKey });
|
|
3245
|
-
switch (unitKey) {
|
|
3246
|
-
case "years": return duration.years;
|
|
3247
|
-
case "months": return duration.months + duration.years * 12;
|
|
3248
|
-
case "weeks": return duration.weeks + Math.floor(duration.days / 7);
|
|
3249
|
-
case "days": return duration.days + duration.weeks * 7;
|
|
3250
|
-
case "hours": return Math.round(duration.total({ unit: "hours" }));
|
|
3251
|
-
case "minutes": return Math.round(duration.total({ unit: "minutes" }));
|
|
3252
|
-
case "seconds": return Math.round(duration.total({ unit: "seconds" }));
|
|
3253
|
-
default: return duration.days;
|
|
3254
|
-
}
|
|
3255
|
-
}
|
|
3256
|
-
getWeek(date, firstDayOfWeek = 0, minimalDays = 1) {
|
|
3257
|
-
const startOfYear = this.startOfYear(date);
|
|
3258
|
-
const startOfFirstWeek = this.startOfWeek(startOfYear, firstDayOfWeek);
|
|
3259
|
-
let firstWeekStart = startOfFirstWeek;
|
|
3260
|
-
if (startOfYear.day - startOfFirstWeek.day < minimalDays) firstWeekStart = startOfFirstWeek.add({ weeks: 1 });
|
|
3261
|
-
const startOfCurrentWeek = this.startOfWeek(date, firstDayOfWeek);
|
|
3262
|
-
const diff = this.getDiff(startOfCurrentWeek, firstWeekStart, "weeks");
|
|
3263
|
-
return Math.max(1, diff + 1);
|
|
3264
|
-
}
|
|
3265
|
-
getDaysInMonth(date) {
|
|
3266
|
-
return date.daysInMonth;
|
|
3267
|
-
}
|
|
3268
|
-
setYear(date, year) {
|
|
3269
|
-
return date.with({ year });
|
|
3270
|
-
}
|
|
3271
|
-
setMonth(date, month) {
|
|
3272
|
-
return date.with({ month: month + 1 });
|
|
3273
|
-
}
|
|
3274
|
-
setDate(date, day) {
|
|
3275
|
-
return date.with({ day });
|
|
3276
|
-
}
|
|
3277
|
-
setHours(date, hours) {
|
|
3278
|
-
return date.with({ hour: hours });
|
|
3279
|
-
}
|
|
3280
|
-
setMinutes(date, minutes) {
|
|
3281
|
-
return date.with({ minute: minutes });
|
|
3282
|
-
}
|
|
3283
|
-
setSeconds(date, seconds) {
|
|
3284
|
-
return date.with({ second: seconds });
|
|
3285
|
-
}
|
|
3286
|
-
getWeekdays(firstDayOfWeek = 0, format = "short") {
|
|
3287
|
-
const weekdays = [];
|
|
3288
|
-
const refDate = Temporal.PlainDate.from("2015-01-04");
|
|
3289
|
-
const formatter = this.getFormatter({ weekday: format });
|
|
3290
|
-
for (let i = 0; i < 7; i++) {
|
|
3291
|
-
const day = refDate.add({ days: (i + firstDayOfWeek) % 7 });
|
|
3292
|
-
const jsDate = new Date(day.year, day.month - 1, day.day);
|
|
3293
|
-
weekdays.push(formatter.format(jsDate));
|
|
3294
|
-
}
|
|
3295
|
-
return weekdays;
|
|
3296
|
-
}
|
|
3297
|
-
getWeekArray(date, firstDayOfWeek = 0) {
|
|
3298
|
-
const weeks = [];
|
|
3299
|
-
const monthStart = this.startOfMonth(date);
|
|
3300
|
-
const monthEnd = this.endOfMonth(date);
|
|
3301
|
-
let current = this.startOfWeek(monthStart, firstDayOfWeek);
|
|
3302
|
-
const end = this.endOfWeek(monthEnd);
|
|
3303
|
-
while (Temporal.PlainDateTime.compare(current, end) <= 0) {
|
|
3304
|
-
const week = [];
|
|
3305
|
-
for (let i = 0; i < 7; i++) {
|
|
3306
|
-
week.push(current);
|
|
3307
|
-
current = current.add({ days: 1 });
|
|
3308
|
-
}
|
|
3309
|
-
weeks.push(week);
|
|
3310
|
-
}
|
|
3311
|
-
return weeks;
|
|
3312
|
-
}
|
|
3313
|
-
getMonthArray(date) {
|
|
3314
|
-
const year = date.year;
|
|
3315
|
-
const months = [];
|
|
3316
|
-
for (let month = 1; month <= 12; month++) months.push(Temporal.PlainDateTime.from({
|
|
3317
|
-
year,
|
|
3318
|
-
month,
|
|
3319
|
-
day: 1
|
|
3320
|
-
}));
|
|
3321
|
-
return months;
|
|
3322
|
-
}
|
|
3323
|
-
getYearRange(start, end) {
|
|
3324
|
-
const years = [];
|
|
3325
|
-
let current = start.year;
|
|
3326
|
-
while (current <= end.year) {
|
|
3327
|
-
years.push(Temporal.PlainDateTime.from({
|
|
3328
|
-
year: current,
|
|
3329
|
-
month: 1,
|
|
3330
|
-
day: 1
|
|
3331
|
-
}));
|
|
3332
|
-
current++;
|
|
3333
|
-
}
|
|
3334
|
-
return years;
|
|
3335
|
-
}
|
|
3336
|
-
getNextMonth(date) {
|
|
3337
|
-
return this.startOfMonth(date.add({ months: 1 }));
|
|
3338
|
-
}
|
|
3339
|
-
getPreviousMonth(date) {
|
|
3340
|
-
return this.startOfMonth(date.subtract({ months: 1 }));
|
|
3341
|
-
}
|
|
3342
|
-
mergeDateAndTime(date, time) {
|
|
3343
|
-
return date.with({
|
|
3344
|
-
hour: time.hour,
|
|
3345
|
-
minute: time.minute,
|
|
3346
|
-
second: time.second,
|
|
3347
|
-
millisecond: time.millisecond
|
|
3348
|
-
});
|
|
3349
|
-
}
|
|
3350
|
-
/**
|
|
3351
|
-
* Gets a cached Intl.DateTimeFormat instance or creates one if not cached.
|
|
3352
|
-
* Cache is limited to MAX_CACHE_SIZE entries to prevent memory leaks.
|
|
3353
|
-
*/
|
|
3354
|
-
getFormatter(options) {
|
|
3355
|
-
const key = `${this.locale}:${JSON.stringify(options)}`;
|
|
3356
|
-
let formatter = this.formatCache.get(key);
|
|
3357
|
-
if (!formatter) {
|
|
3358
|
-
if (this.formatCache.size >= MAX_CACHE_SIZE) {
|
|
3359
|
-
const firstKey = this.formatCache.keys().next().value;
|
|
3360
|
-
if (firstKey) this.formatCache.delete(firstKey);
|
|
3361
|
-
}
|
|
3362
|
-
formatter = new Intl.DateTimeFormat(this.locale, options);
|
|
3363
|
-
this.formatCache.set(key, formatter);
|
|
3364
|
-
}
|
|
3365
|
-
return formatter;
|
|
3366
|
-
}
|
|
3367
|
-
/**
|
|
3368
|
-
* Gets a cached Intl.NumberFormat instance or creates one if not cached.
|
|
3369
|
-
* Cache is limited to MAX_CACHE_SIZE entries to prevent memory leaks.
|
|
3370
|
-
*/
|
|
3371
|
-
getNumberFormatter() {
|
|
3372
|
-
let formatter = this.numberFormatCache.get(this.locale);
|
|
3373
|
-
if (!formatter) {
|
|
3374
|
-
if (this.numberFormatCache.size >= MAX_CACHE_SIZE) {
|
|
3375
|
-
const firstKey = this.numberFormatCache.keys().next().value;
|
|
3376
|
-
if (firstKey) this.numberFormatCache.delete(firstKey);
|
|
3377
|
-
}
|
|
3378
|
-
formatter = new Intl.NumberFormat(this.locale);
|
|
3379
|
-
this.numberFormatCache.set(this.locale, formatter);
|
|
3380
|
-
}
|
|
3381
|
-
return formatter;
|
|
3382
|
-
}
|
|
3383
|
-
};
|
|
3384
|
-
|
|
3385
2876
|
//#endregion
|
|
3386
2877
|
//#region src/composables/useDate/index.ts
|
|
3387
2878
|
/**
|
|
@@ -3392,16 +2883,16 @@ var Vuetify0DateAdapter = class {
|
|
|
3392
2883
|
*
|
|
3393
2884
|
* Key features:
|
|
3394
2885
|
* - Adapter pattern for date library abstraction
|
|
3395
|
-
* - Temporal API as default adapter (modern, immutable dates)
|
|
3396
2886
|
* - Locale-aware formatting via Intl.DateTimeFormat
|
|
3397
2887
|
* - Integration with useLocale for automatic locale sync
|
|
3398
2888
|
*
|
|
3399
|
-
* @example
|
|
2889
|
+
* @example Using the built-in Temporal adapter
|
|
3400
2890
|
* ```ts
|
|
2891
|
+
* import { Vuetify0DateAdapter } from '@vuetify/v0/date'
|
|
3401
2892
|
* import { createDatePlugin } from '@vuetify/v0'
|
|
3402
2893
|
*
|
|
3403
2894
|
* const app = createApp(App)
|
|
3404
|
-
* app.use(createDatePlugin())
|
|
2895
|
+
* app.use(createDatePlugin({ adapter: new Vuetify0DateAdapter() }))
|
|
3405
2896
|
*
|
|
3406
2897
|
* // In a component:
|
|
3407
2898
|
* const { adapter } = useDate()
|
|
@@ -3417,7 +2908,7 @@ var Vuetify0DateAdapter = class {
|
|
|
3417
2908
|
* // ... implementation
|
|
3418
2909
|
* }
|
|
3419
2910
|
*
|
|
3420
|
-
*
|
|
2911
|
+
* app.use(createDatePlugin({ adapter: new DateFnsAdapter() }))
|
|
3421
2912
|
* ```
|
|
3422
2913
|
*/
|
|
3423
2914
|
/**
|
|
@@ -3440,7 +2931,8 @@ const defaultLocales = {
|
|
|
3440
2931
|
/**
|
|
3441
2932
|
* Creates a new date context.
|
|
3442
2933
|
*
|
|
3443
|
-
* @param options
|
|
2934
|
+
* @param options Adapter and locale configuration.
|
|
2935
|
+
* @template Z The date type used by the adapter.
|
|
3444
2936
|
* @template E The date context type.
|
|
3445
2937
|
* @returns A date context.
|
|
3446
2938
|
*
|
|
@@ -3448,18 +2940,20 @@ const defaultLocales = {
|
|
|
3448
2940
|
*
|
|
3449
2941
|
* @example
|
|
3450
2942
|
* ```ts
|
|
3451
|
-
*
|
|
3452
|
-
* const today = adapter.date() // Temporal.PlainDateTime
|
|
2943
|
+
* import { Vuetify0DateAdapter } from '@vuetify/v0/date'
|
|
3453
2944
|
*
|
|
3454
|
-
*
|
|
3455
|
-
* const
|
|
2945
|
+
* const { adapter } = createDate({ adapter: new Vuetify0DateAdapter() })
|
|
2946
|
+
* const today = adapter.date()
|
|
3456
2947
|
*
|
|
3457
|
-
* // With
|
|
3458
|
-
* const { adapter } = createDate({
|
|
2948
|
+
* // With locale options
|
|
2949
|
+
* const { adapter } = createDate({
|
|
2950
|
+
* adapter: new Vuetify0DateAdapter(),
|
|
2951
|
+
* locale: 'de-DE',
|
|
2952
|
+
* })
|
|
3459
2953
|
* ```
|
|
3460
2954
|
*/
|
|
3461
|
-
function createDate(options
|
|
3462
|
-
const { locales = defaultLocales, adapter
|
|
2955
|
+
function createDate(options) {
|
|
2956
|
+
const { locales = defaultLocales, adapter, locale: initialLocale } = options;
|
|
3463
2957
|
let selectedId;
|
|
3464
2958
|
try {
|
|
3465
2959
|
if (instanceExists()) selectedId = useLocale().selectedId;
|
|
@@ -3487,22 +2981,10 @@ function createDate(options = {}) {
|
|
|
3487
2981
|
};
|
|
3488
2982
|
}
|
|
3489
2983
|
/**
|
|
3490
|
-
* Creates a fallback date context for when useDate is called outside of a Vue component.
|
|
3491
|
-
*
|
|
3492
|
-
* @returns A fallback date context with Vuetify0DateAdapter.
|
|
3493
|
-
* @internal
|
|
3494
|
-
*/
|
|
3495
|
-
function createDateFallback() {
|
|
3496
|
-
const adapter = new Vuetify0DateAdapter();
|
|
3497
|
-
return {
|
|
3498
|
-
adapter,
|
|
3499
|
-
locale: computed(() => adapter.locale ?? "en-US")
|
|
3500
|
-
};
|
|
3501
|
-
}
|
|
3502
|
-
/**
|
|
3503
2984
|
* Creates a new date context trinity.
|
|
3504
2985
|
*
|
|
3505
|
-
* @param options
|
|
2986
|
+
* @param options Adapter, locale, and namespace configuration.
|
|
2987
|
+
* @template Z The date type used by the adapter.
|
|
3506
2988
|
* @template E The date context type.
|
|
3507
2989
|
* @returns A trinity [useContext, provideContext, defaultContext].
|
|
3508
2990
|
*
|
|
@@ -3510,18 +2992,15 @@ function createDateFallback() {
|
|
|
3510
2992
|
*
|
|
3511
2993
|
* @example
|
|
3512
2994
|
* ```ts
|
|
3513
|
-
*
|
|
3514
|
-
* namespace: 'app:date',
|
|
3515
|
-
* })
|
|
2995
|
+
* import { Vuetify0DateAdapter } from '@vuetify/v0/date'
|
|
3516
2996
|
*
|
|
3517
|
-
* // With custom adapter
|
|
3518
2997
|
* const [useAppDate, provideAppDate] = createDateContext({
|
|
3519
|
-
* adapter: new
|
|
2998
|
+
* adapter: new Vuetify0DateAdapter(),
|
|
3520
2999
|
* namespace: 'app:date',
|
|
3521
3000
|
* })
|
|
3522
3001
|
* ```
|
|
3523
3002
|
*/
|
|
3524
|
-
function createDateContext(options
|
|
3003
|
+
function createDateContext(options) {
|
|
3525
3004
|
const { namespace = "v0:date", ...dateOptions } = options;
|
|
3526
3005
|
const [useDateContext, _provideDateContext] = createContext(namespace);
|
|
3527
3006
|
const context = createDate(dateOptions);
|
|
@@ -3533,7 +3012,8 @@ function createDateContext(options = {}) {
|
|
|
3533
3012
|
/**
|
|
3534
3013
|
* Creates a new date plugin.
|
|
3535
3014
|
*
|
|
3536
|
-
* @param options
|
|
3015
|
+
* @param options Adapter, locale, and namespace configuration.
|
|
3016
|
+
* @template Z The date type used by the adapter.
|
|
3537
3017
|
* @template E The date context type.
|
|
3538
3018
|
* @returns A Vue plugin.
|
|
3539
3019
|
*
|
|
@@ -3541,17 +3021,19 @@ function createDateContext(options = {}) {
|
|
|
3541
3021
|
*
|
|
3542
3022
|
* @example
|
|
3543
3023
|
* ```ts
|
|
3544
|
-
*
|
|
3545
|
-
* app.use(createDatePlugin())
|
|
3024
|
+
* import { Vuetify0DateAdapter } from '@vuetify/v0/date'
|
|
3546
3025
|
*
|
|
3547
|
-
*
|
|
3548
|
-
* app.use(createDatePlugin({
|
|
3026
|
+
* const app = createApp(App)
|
|
3027
|
+
* app.use(createDatePlugin({ adapter: new Vuetify0DateAdapter() }))
|
|
3549
3028
|
*
|
|
3550
|
-
* // With
|
|
3551
|
-
* app.use(createDatePlugin({
|
|
3029
|
+
* // With locale options
|
|
3030
|
+
* app.use(createDatePlugin({
|
|
3031
|
+
* adapter: new Vuetify0DateAdapter(),
|
|
3032
|
+
* locale: 'de-DE',
|
|
3033
|
+
* }))
|
|
3552
3034
|
* ```
|
|
3553
3035
|
*/
|
|
3554
|
-
function createDatePlugin(options
|
|
3036
|
+
function createDatePlugin(options) {
|
|
3555
3037
|
const { namespace = "v0:date", ...dateOptions } = options;
|
|
3556
3038
|
const [, provideDateContext, context] = createDateContext({
|
|
3557
3039
|
namespace,
|
|
@@ -3567,16 +3049,26 @@ function createDatePlugin(options = {}) {
|
|
|
3567
3049
|
/**
|
|
3568
3050
|
* Returns the current date context.
|
|
3569
3051
|
*
|
|
3570
|
-
*
|
|
3571
|
-
* returns that context. Otherwise, returns a fallback context with Vuetify0DateAdapter.
|
|
3052
|
+
* Requires `createDatePlugin` to be installed with an adapter.
|
|
3572
3053
|
*
|
|
3573
3054
|
* @param namespace The namespace to look up (defaults to 'v0:date').
|
|
3055
|
+
* @template Z The date type used by the adapter.
|
|
3574
3056
|
* @template E The date context type.
|
|
3575
3057
|
* @returns The current date context.
|
|
3058
|
+
* @throws If called outside a component or without a date plugin installed.
|
|
3576
3059
|
*
|
|
3577
3060
|
* @see https://0.vuetifyjs.com/composables/plugins/use-date
|
|
3578
3061
|
*
|
|
3579
3062
|
* @example
|
|
3063
|
+
* ```ts
|
|
3064
|
+
* // main.ts
|
|
3065
|
+
* import { Vuetify0DateAdapter } from '@vuetify/v0/date'
|
|
3066
|
+
* import { createDatePlugin } from '@vuetify/v0'
|
|
3067
|
+
*
|
|
3068
|
+
* app.use(createDatePlugin({ adapter: new Vuetify0DateAdapter() }))
|
|
3069
|
+
* ```
|
|
3070
|
+
*
|
|
3071
|
+
* @example
|
|
3580
3072
|
* ```vue
|
|
3581
3073
|
* <script setup lang="ts">
|
|
3582
3074
|
* import { useDate } from '@vuetify/v0'
|
|
@@ -3587,15 +3079,126 @@ function createDatePlugin(options = {}) {
|
|
|
3587
3079
|
* ```
|
|
3588
3080
|
*/
|
|
3589
3081
|
function useDate(namespace = "v0:date") {
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
try {
|
|
3593
|
-
return useContext(namespace, fallback);
|
|
3594
|
-
} catch {
|
|
3595
|
-
return fallback;
|
|
3596
|
-
}
|
|
3082
|
+
if (!instanceExists()) throw new Error("[v0] useDate() must be called inside a Vue component with createDatePlugin installed.\n\nExample:\n import { Vuetify0DateAdapter } from '@vuetify/v0/date'\n import { createDatePlugin } from '@vuetify/v0'\n\n app.use(createDatePlugin({ adapter: new Vuetify0DateAdapter() }))");
|
|
3083
|
+
return useContext(namespace);
|
|
3597
3084
|
}
|
|
3598
3085
|
|
|
3086
|
+
//#endregion
|
|
3087
|
+
//#region src/composables/useFeatures/adapters/generic/index.ts
|
|
3088
|
+
var FeaturesAdapter = class {};
|
|
3089
|
+
|
|
3090
|
+
//#endregion
|
|
3091
|
+
//#region src/composables/useFeatures/adapters/flagsmith/index.ts
|
|
3092
|
+
/**
|
|
3093
|
+
* @module FlagsmithFeatureAdapter
|
|
3094
|
+
*
|
|
3095
|
+
* @remarks
|
|
3096
|
+
* Flagsmith adapter for feature flags.
|
|
3097
|
+
*/
|
|
3098
|
+
var FlagsmithFeatureAdapter = class {
|
|
3099
|
+
client;
|
|
3100
|
+
options;
|
|
3101
|
+
constructor(client = flagsmith, options) {
|
|
3102
|
+
this.client = client;
|
|
3103
|
+
this.options = options;
|
|
3104
|
+
}
|
|
3105
|
+
setup(onUpdate) {
|
|
3106
|
+
const updateFlags = () => {
|
|
3107
|
+
const flags = this.client.getAllFlags();
|
|
3108
|
+
const adapterFlags = {};
|
|
3109
|
+
if (flags) for (const [key, flag] of Object.entries(flags)) {
|
|
3110
|
+
const isEnabled = flag.enabled;
|
|
3111
|
+
const variation = flag.value;
|
|
3112
|
+
adapterFlags[key] = variation !== null && variation !== void 0 ? {
|
|
3113
|
+
$value: isEnabled,
|
|
3114
|
+
$variation: variation
|
|
3115
|
+
} : isEnabled;
|
|
3116
|
+
}
|
|
3117
|
+
return adapterFlags;
|
|
3118
|
+
};
|
|
3119
|
+
this.client.init({
|
|
3120
|
+
...this.options,
|
|
3121
|
+
onChange: (oldFlags, params, loadingState) => {
|
|
3122
|
+
onUpdate(updateFlags());
|
|
3123
|
+
this.options.onChange?.(oldFlags, params, loadingState);
|
|
3124
|
+
}
|
|
3125
|
+
});
|
|
3126
|
+
this.disposeFn = () => this.client.stopListening();
|
|
3127
|
+
return updateFlags();
|
|
3128
|
+
}
|
|
3129
|
+
dispose() {
|
|
3130
|
+
this.disposeFn();
|
|
3131
|
+
}
|
|
3132
|
+
disposeFn = () => {};
|
|
3133
|
+
};
|
|
3134
|
+
|
|
3135
|
+
//#endregion
|
|
3136
|
+
//#region src/composables/useFeatures/adapters/launchdarkly/index.ts
|
|
3137
|
+
var LaunchDarklyFeatureAdapter = class {
|
|
3138
|
+
constructor(client) {
|
|
3139
|
+
this.client = client;
|
|
3140
|
+
}
|
|
3141
|
+
setup(onUpdate) {
|
|
3142
|
+
const updateFlags = () => {
|
|
3143
|
+
const allFlags = this.client.allFlags();
|
|
3144
|
+
const flags = {};
|
|
3145
|
+
for (const [key, value] of Object.entries(allFlags)) flags[key] = typeof value === "boolean" ? value : {
|
|
3146
|
+
$value: true,
|
|
3147
|
+
$variation: value
|
|
3148
|
+
};
|
|
3149
|
+
onUpdate(flags);
|
|
3150
|
+
return flags;
|
|
3151
|
+
};
|
|
3152
|
+
this.client.on("change", updateFlags);
|
|
3153
|
+
this.disposeFn = () => this.client.off("change", updateFlags);
|
|
3154
|
+
return updateFlags();
|
|
3155
|
+
}
|
|
3156
|
+
dispose() {
|
|
3157
|
+
this.disposeFn();
|
|
3158
|
+
}
|
|
3159
|
+
disposeFn = () => {};
|
|
3160
|
+
};
|
|
3161
|
+
|
|
3162
|
+
//#endregion
|
|
3163
|
+
//#region src/composables/useFeatures/adapters/posthog/index.ts
|
|
3164
|
+
var PostHogFeatureAdapter = class {
|
|
3165
|
+
constructor(client) {
|
|
3166
|
+
this.client = client;
|
|
3167
|
+
}
|
|
3168
|
+
setup(onUpdate) {
|
|
3169
|
+
const updateFlags = () => {
|
|
3170
|
+
const flags = {};
|
|
3171
|
+
const activeFlags = this.client.featureFlags.getFlags();
|
|
3172
|
+
if (activeFlags) {
|
|
3173
|
+
for (const key of activeFlags) {
|
|
3174
|
+
const isEnabled = this.client.isFeatureEnabled(key) ?? false;
|
|
3175
|
+
const payload = this.client.getFeatureFlagPayload(key);
|
|
3176
|
+
if (payload !== void 0 && payload !== null) flags[key] = {
|
|
3177
|
+
$value: isEnabled,
|
|
3178
|
+
$variation: payload
|
|
3179
|
+
};
|
|
3180
|
+
else {
|
|
3181
|
+
const variant = this.client.getFeatureFlag(key);
|
|
3182
|
+
flags[key] = variant !== true && variant !== false && variant !== void 0 && variant !== null ? {
|
|
3183
|
+
$value: true,
|
|
3184
|
+
$variation: variant
|
|
3185
|
+
} : isEnabled;
|
|
3186
|
+
}
|
|
3187
|
+
}
|
|
3188
|
+
onUpdate(flags);
|
|
3189
|
+
return flags;
|
|
3190
|
+
}
|
|
3191
|
+
return {};
|
|
3192
|
+
};
|
|
3193
|
+
this.disposeFn = this.client.onFeatureFlags(updateFlags);
|
|
3194
|
+
return updateFlags();
|
|
3195
|
+
}
|
|
3196
|
+
dispose() {
|
|
3197
|
+
this.disposeFn();
|
|
3198
|
+
}
|
|
3199
|
+
disposeFn = () => {};
|
|
3200
|
+
};
|
|
3201
|
+
|
|
3599
3202
|
//#endregion
|
|
3600
3203
|
//#region src/composables/useFeatures/index.ts
|
|
3601
3204
|
/**
|
|
@@ -3612,6 +3215,7 @@ function useDate(namespace = "v0:date") {
|
|
|
3612
3215
|
* - Auto-selection of enabled features
|
|
3613
3216
|
* - Multi-select support for feature combinations
|
|
3614
3217
|
* - Perfect for A/B testing, progressive rollout, feature toggles
|
|
3218
|
+
* - Adapter pattern for external feature flag services
|
|
3615
3219
|
*
|
|
3616
3220
|
* Inheritance chain: useRegistry → createSelection → createGroup → createFeatures
|
|
3617
3221
|
* Integrates with useTokens for token-based features.
|
|
@@ -3642,7 +3246,10 @@ function useDate(namespace = "v0:date") {
|
|
|
3642
3246
|
function createFeatures(_options = {}) {
|
|
3643
3247
|
const { features, ...options } = _options;
|
|
3644
3248
|
const tokens = createTokens(features, { flat: true });
|
|
3645
|
-
const registry = createGroup(
|
|
3249
|
+
const registry = createGroup({
|
|
3250
|
+
...options,
|
|
3251
|
+
reactive: true
|
|
3252
|
+
});
|
|
3646
3253
|
for (const [id, { value }] of tokens.entries()) register({
|
|
3647
3254
|
id,
|
|
3648
3255
|
value
|
|
@@ -3661,10 +3268,22 @@ function createFeatures(_options = {}) {
|
|
|
3661
3268
|
if (/* @__PURE__ */ isBoolean(ticket.value) && ticket.value === true || /* @__PURE__ */ isObject(ticket.value) && /* @__PURE__ */ isBoolean(ticket.value.$value) && ticket.value.$value === true) registry.select(ticket.id);
|
|
3662
3269
|
return ticket;
|
|
3663
3270
|
}
|
|
3271
|
+
function sync(flags) {
|
|
3272
|
+
for (const [id, value] of Object.entries(flags)) if (registry.get(id)) {
|
|
3273
|
+
const shouldSelect = /* @__PURE__ */ isBoolean(value) ? value === true : /* @__PURE__ */ isObject(value) && /* @__PURE__ */ isBoolean(value.$value) && value.$value === true;
|
|
3274
|
+
registry.upsert(id, { value });
|
|
3275
|
+
if (shouldSelect) registry.select(id);
|
|
3276
|
+
else registry.unselect(id);
|
|
3277
|
+
} else register({
|
|
3278
|
+
id,
|
|
3279
|
+
value
|
|
3280
|
+
});
|
|
3281
|
+
}
|
|
3664
3282
|
return {
|
|
3665
3283
|
...registry,
|
|
3666
3284
|
variation,
|
|
3667
3285
|
register,
|
|
3286
|
+
sync,
|
|
3668
3287
|
get size() {
|
|
3669
3288
|
return registry.size;
|
|
3670
3289
|
}
|
|
@@ -3733,7 +3352,7 @@ function createFeaturesContext(_options = {}) {
|
|
|
3733
3352
|
* ```
|
|
3734
3353
|
*/
|
|
3735
3354
|
function createFeaturesPlugin(_options = {}) {
|
|
3736
|
-
const { namespace = "v0:features", ...options } = _options;
|
|
3355
|
+
const { namespace = "v0:features", adapter, ...options } = _options;
|
|
3737
3356
|
const [, provideFeaturesContext, context] = createFeaturesContext({
|
|
3738
3357
|
...options,
|
|
3739
3358
|
namespace
|
|
@@ -3742,6 +3361,17 @@ function createFeaturesPlugin(_options = {}) {
|
|
|
3742
3361
|
namespace,
|
|
3743
3362
|
provide: (app) => {
|
|
3744
3363
|
provideFeaturesContext(context, app);
|
|
3364
|
+
},
|
|
3365
|
+
setup: (app) => {
|
|
3366
|
+
if (!adapter) return;
|
|
3367
|
+
const adapters = /* @__PURE__ */ isArray(adapter) ? adapter : [adapter];
|
|
3368
|
+
for (const adapter$1 of adapters) {
|
|
3369
|
+
const initialFlags = adapter$1.setup((flags) => {
|
|
3370
|
+
context.sync(flags);
|
|
3371
|
+
});
|
|
3372
|
+
context.sync(initialFlags);
|
|
3373
|
+
if (/* @__PURE__ */ isFunction(adapter$1.dispose)) app.onUnmount(() => adapter$1.dispose());
|
|
3374
|
+
}
|
|
3745
3375
|
}
|
|
3746
3376
|
});
|
|
3747
3377
|
}
|
|
@@ -4593,7 +4223,7 @@ function matchesKeyGroup(e, group, platformIsMac) {
|
|
|
4593
4223
|
*/
|
|
4594
4224
|
function useIntersectionObserver(target, callback, options = {}) {
|
|
4595
4225
|
const { isHydrated } = useHydration();
|
|
4596
|
-
const targetRef =
|
|
4226
|
+
const targetRef = toRef(target);
|
|
4597
4227
|
const observer = shallowRef();
|
|
4598
4228
|
const isPaused = shallowRef(false);
|
|
4599
4229
|
const isIntersecting = shallowRef(false);
|
|
@@ -4632,17 +4262,17 @@ function useIntersectionObserver(target, callback, options = {}) {
|
|
|
4632
4262
|
}]);
|
|
4633
4263
|
}
|
|
4634
4264
|
watch(() => targetRef.value, (el, oldEl) => {
|
|
4635
|
-
if (oldEl) cleanup();
|
|
4265
|
+
if (oldEl || observer.value) cleanup();
|
|
4636
4266
|
if (isHydrated.value && el) setup();
|
|
4637
4267
|
}, { immediate: true });
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
}
|
|
4645
|
-
}
|
|
4268
|
+
let stopHydrationWatch;
|
|
4269
|
+
if (!isHydrated.value) stopHydrationWatch = watch(() => isHydrated.value, (hydrated) => {
|
|
4270
|
+
if (hydrated && targetRef.value && !observer.value) {
|
|
4271
|
+
setup();
|
|
4272
|
+
stopHydrationWatch?.();
|
|
4273
|
+
stopHydrationWatch = void 0;
|
|
4274
|
+
}
|
|
4275
|
+
});
|
|
4646
4276
|
function cleanup() {
|
|
4647
4277
|
if (observer.value) {
|
|
4648
4278
|
observer.value.disconnect();
|
|
@@ -4659,6 +4289,8 @@ function useIntersectionObserver(target, callback, options = {}) {
|
|
|
4659
4289
|
setup();
|
|
4660
4290
|
}
|
|
4661
4291
|
function stop() {
|
|
4292
|
+
stopHydrationWatch?.();
|
|
4293
|
+
stopHydrationWatch = void 0;
|
|
4662
4294
|
cleanup();
|
|
4663
4295
|
observer.value = null;
|
|
4664
4296
|
}
|
|
@@ -4994,6 +4626,7 @@ function usePrefersContrast() {
|
|
|
4994
4626
|
*/
|
|
4995
4627
|
function useMutationObserver(target, callback, options = {}) {
|
|
4996
4628
|
const { isHydrated } = useHydration();
|
|
4629
|
+
const targetRef = toRef(target);
|
|
4997
4630
|
const observer = shallowRef();
|
|
4998
4631
|
const isPaused = shallowRef(false);
|
|
4999
4632
|
const isActive = toRef(() => !!observer.value);
|
|
@@ -5008,7 +4641,7 @@ function useMutationObserver(target, callback, options = {}) {
|
|
|
5008
4641
|
};
|
|
5009
4642
|
function setup() {
|
|
5010
4643
|
if (/* @__PURE__ */ isNull(observer.value)) return;
|
|
5011
|
-
if (!isHydrated.value || !SUPPORTS_MUTATION_OBSERVER || !
|
|
4644
|
+
if (!isHydrated.value || !SUPPORTS_MUTATION_OBSERVER || !targetRef.value || isPaused.value) return;
|
|
5012
4645
|
observer.value = new MutationObserver((mutations) => {
|
|
5013
4646
|
callback(mutations.map((mutation) => ({
|
|
5014
4647
|
type: mutation.type,
|
|
@@ -5023,7 +4656,7 @@ function useMutationObserver(target, callback, options = {}) {
|
|
|
5023
4656
|
})));
|
|
5024
4657
|
if (options.once) stop();
|
|
5025
4658
|
});
|
|
5026
|
-
observer.value.observe(
|
|
4659
|
+
observer.value.observe(targetRef.value, observerOptions);
|
|
5027
4660
|
if (options.immediate) {
|
|
5028
4661
|
const emptyNodeList = {
|
|
5029
4662
|
length: 0,
|
|
@@ -5033,7 +4666,7 @@ function useMutationObserver(target, callback, options = {}) {
|
|
|
5033
4666
|
};
|
|
5034
4667
|
callback([{
|
|
5035
4668
|
type: "childList",
|
|
5036
|
-
target:
|
|
4669
|
+
target: targetRef.value,
|
|
5037
4670
|
addedNodes: emptyNodeList,
|
|
5038
4671
|
removedNodes: emptyNodeList,
|
|
5039
4672
|
previousSibling: null,
|
|
@@ -5045,18 +4678,18 @@ function useMutationObserver(target, callback, options = {}) {
|
|
|
5045
4678
|
if (options.once) stop();
|
|
5046
4679
|
}
|
|
5047
4680
|
}
|
|
5048
|
-
watch(() =>
|
|
5049
|
-
if (oldEl) cleanup();
|
|
4681
|
+
watch(() => targetRef.value, (el, oldEl) => {
|
|
4682
|
+
if (oldEl || observer.value) cleanup();
|
|
5050
4683
|
if (isHydrated.value && el) setup();
|
|
5051
4684
|
}, { immediate: true });
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
}
|
|
5059
|
-
}
|
|
4685
|
+
let stopHydrationWatch;
|
|
4686
|
+
if (!isHydrated.value) stopHydrationWatch = watch(() => isHydrated.value, (hydrated) => {
|
|
4687
|
+
if (hydrated && targetRef.value && !observer.value) {
|
|
4688
|
+
setup();
|
|
4689
|
+
stopHydrationWatch?.();
|
|
4690
|
+
stopHydrationWatch = void 0;
|
|
4691
|
+
}
|
|
4692
|
+
});
|
|
5060
4693
|
function cleanup() {
|
|
5061
4694
|
if (observer.value) {
|
|
5062
4695
|
observer.value.disconnect();
|
|
@@ -5072,6 +4705,8 @@ function useMutationObserver(target, callback, options = {}) {
|
|
|
5072
4705
|
setup();
|
|
5073
4706
|
}
|
|
5074
4707
|
function stop() {
|
|
4708
|
+
stopHydrationWatch?.();
|
|
4709
|
+
stopHydrationWatch = void 0;
|
|
5075
4710
|
cleanup();
|
|
5076
4711
|
observer.value = null;
|
|
5077
4712
|
}
|
|
@@ -5085,6 +4720,509 @@ function useMutationObserver(target, callback, options = {}) {
|
|
|
5085
4720
|
};
|
|
5086
4721
|
}
|
|
5087
4722
|
|
|
4723
|
+
//#endregion
|
|
4724
|
+
//#region src/composables/createNested/strategies.ts
|
|
4725
|
+
/**
|
|
4726
|
+
* Multiple open strategy: allows multiple nodes to be open simultaneously.
|
|
4727
|
+
*
|
|
4728
|
+
* @remarks
|
|
4729
|
+
* Perfect for tree views, file explorers, and nested menus where users expect
|
|
4730
|
+
* to keep multiple sections expanded at once.
|
|
4731
|
+
*
|
|
4732
|
+
* @example
|
|
4733
|
+
* ```ts
|
|
4734
|
+
* const tree = createNested({ openStrategy: multipleOpenStrategy })
|
|
4735
|
+
* tree.open('node-1')
|
|
4736
|
+
* tree.open('node-2')
|
|
4737
|
+
* // Both nodes are now open
|
|
4738
|
+
* ```
|
|
4739
|
+
*/
|
|
4740
|
+
const multipleOpenStrategy = {
|
|
4741
|
+
onOpen: void 0,
|
|
4742
|
+
onClose: void 0
|
|
4743
|
+
};
|
|
4744
|
+
/**
|
|
4745
|
+
* Single open strategy: only one node can be open at a time (accordion behavior).
|
|
4746
|
+
*
|
|
4747
|
+
* @remarks
|
|
4748
|
+
* Perfect for accordions, single-select navigation, and contexts where only
|
|
4749
|
+
* one section should be visible at a time.
|
|
4750
|
+
*
|
|
4751
|
+
* @example
|
|
4752
|
+
* ```ts
|
|
4753
|
+
* const tree = createNested({ openStrategy: singleOpenStrategy })
|
|
4754
|
+
* tree.open('node-1') // node-1 opens
|
|
4755
|
+
* tree.open('node-2') // node-1 closes, node-2 opens
|
|
4756
|
+
* ```
|
|
4757
|
+
*/
|
|
4758
|
+
const singleOpenStrategy = {
|
|
4759
|
+
onOpen: (id, context) => {
|
|
4760
|
+
for (const openedId of context.openedIds) if (openedId !== id) context.openedIds.delete(openedId);
|
|
4761
|
+
},
|
|
4762
|
+
onClose: void 0
|
|
4763
|
+
};
|
|
4764
|
+
|
|
4765
|
+
//#endregion
|
|
4766
|
+
//#region src/composables/createNested/index.ts
|
|
4767
|
+
/**
|
|
4768
|
+
* @module createNested
|
|
4769
|
+
*
|
|
4770
|
+
* @remarks
|
|
4771
|
+
* Hierarchical tree management composable extending createGroup with:
|
|
4772
|
+
* - Parent-child relationship tracking (children/parents Maps)
|
|
4773
|
+
* - Open/close state management
|
|
4774
|
+
* - Tree traversal utilities (getPath, getDescendants, etc.)
|
|
4775
|
+
* - Pluggable open strategies
|
|
4776
|
+
*
|
|
4777
|
+
* Inheritance chain: createSelection → createGroup → createNested
|
|
4778
|
+
*/
|
|
4779
|
+
/**
|
|
4780
|
+
* Resolves open mode to an OpenStrategy.
|
|
4781
|
+
*/
|
|
4782
|
+
function resolveOpenStrategy(open = "multiple") {
|
|
4783
|
+
return open === "single" ? singleOpenStrategy : multipleOpenStrategy;
|
|
4784
|
+
}
|
|
4785
|
+
/**
|
|
4786
|
+
* Creates a new nested tree instance with hierarchical management.
|
|
4787
|
+
*
|
|
4788
|
+
* Extends `createGroup` to support parent-child relationships, tree traversal,
|
|
4789
|
+
* and open/close state management. Perfect for tree views, nested navigation,
|
|
4790
|
+
* and hierarchical data structures.
|
|
4791
|
+
*
|
|
4792
|
+
* @param options The options for the nested instance.
|
|
4793
|
+
* @template Z The type of the nested ticket.
|
|
4794
|
+
* @template E The type of the nested context.
|
|
4795
|
+
* @returns A new nested instance with tree management capabilities.
|
|
4796
|
+
*
|
|
4797
|
+
* @remarks
|
|
4798
|
+
* **Key Differences from `createGroup`:**
|
|
4799
|
+
* - `register()` accepts `parentId` for establishing parent-child relationships
|
|
4800
|
+
* - `unregister()` accepts optional `cascade` parameter for cascading deletions
|
|
4801
|
+
* - Adds tree traversal methods: `getPath()`, `getAncestors()`, `getDescendants()`
|
|
4802
|
+
* - Adds computed properties: `roots`, `leaves`, `isLeaf()`, `getDepth()`
|
|
4803
|
+
* - Adds open state management: `open()`, `close()`, `flip()`, `opened()`
|
|
4804
|
+
*
|
|
4805
|
+
* @see https://0.vuetifyjs.com/composables/selection/use-nested
|
|
4806
|
+
*
|
|
4807
|
+
* @example
|
|
4808
|
+
* ```ts
|
|
4809
|
+
* import { createNested } from '@vuetify/v0'
|
|
4810
|
+
*
|
|
4811
|
+
* const tree = createNested()
|
|
4812
|
+
*
|
|
4813
|
+
* const root = tree.register({ id: 'root', value: 'Root' })
|
|
4814
|
+
* const child1 = tree.register({ id: 'child-1', value: 'Child 1', parentId: 'root' })
|
|
4815
|
+
* const child2 = tree.register({ id: 'child-2', value: 'Child 2', parentId: 'root' })
|
|
4816
|
+
*
|
|
4817
|
+
* console.log(tree.getPath('child-1')) // ['root', 'child-1']
|
|
4818
|
+
* console.log(tree.getDescendants('root')) // ['child-1', 'child-2']
|
|
4819
|
+
* console.log(tree.isLeaf('child-2')) // true
|
|
4820
|
+
*
|
|
4821
|
+
* tree.open('root')
|
|
4822
|
+
* console.log(tree.opened('root')) // true
|
|
4823
|
+
* ```
|
|
4824
|
+
*/
|
|
4825
|
+
function createNested(_options = {}) {
|
|
4826
|
+
const { open: openMode = "multiple", openAll = false, reveal: revealOnOpen = false, selection: selectionMode = "cascade", openStrategy, ...options } = _options;
|
|
4827
|
+
const resolvedOpenStrategy = openStrategy ?? resolveOpenStrategy(openMode);
|
|
4828
|
+
const group = createGroup(options);
|
|
4829
|
+
const logger$1 = useLogger();
|
|
4830
|
+
const children = shallowReactive(/* @__PURE__ */ new Map());
|
|
4831
|
+
const parents = shallowReactive(/* @__PURE__ */ new Map());
|
|
4832
|
+
const openedIds = shallowReactive(/* @__PURE__ */ new Set());
|
|
4833
|
+
const openedItems = computed(() => {
|
|
4834
|
+
return new Set(Array.from(openedIds).map((id) => group.get(id)).filter((item) => !/* @__PURE__ */ isUndefined(item)));
|
|
4835
|
+
});
|
|
4836
|
+
const roots = computed(() => {
|
|
4837
|
+
return group.values().filter((item) => /* @__PURE__ */ isUndefined(parents.get(item.id)));
|
|
4838
|
+
});
|
|
4839
|
+
const leaves = computed(() => {
|
|
4840
|
+
return group.values().filter((item) => {
|
|
4841
|
+
const childList = children.get(item.id);
|
|
4842
|
+
return /* @__PURE__ */ isUndefined(childList) || childList.length === 0;
|
|
4843
|
+
});
|
|
4844
|
+
});
|
|
4845
|
+
function opened(id) {
|
|
4846
|
+
return openedIds.has(id);
|
|
4847
|
+
}
|
|
4848
|
+
function open(ids) {
|
|
4849
|
+
for (const id of toArray(ids)) {
|
|
4850
|
+
if (!group.has(id)) continue;
|
|
4851
|
+
if (revealOnOpen) {
|
|
4852
|
+
let parentId = parents.get(id);
|
|
4853
|
+
while (!/* @__PURE__ */ isUndefined(parentId)) {
|
|
4854
|
+
openedIds.add(parentId);
|
|
4855
|
+
parentId = parents.get(parentId);
|
|
4856
|
+
}
|
|
4857
|
+
}
|
|
4858
|
+
openedIds.add(id);
|
|
4859
|
+
resolvedOpenStrategy.onOpen?.(id, context);
|
|
4860
|
+
}
|
|
4861
|
+
}
|
|
4862
|
+
function close(ids) {
|
|
4863
|
+
for (const id of toArray(ids)) {
|
|
4864
|
+
if (!group.has(id)) continue;
|
|
4865
|
+
openedIds.delete(id);
|
|
4866
|
+
resolvedOpenStrategy.onClose?.(id, context);
|
|
4867
|
+
}
|
|
4868
|
+
}
|
|
4869
|
+
function flip(ids) {
|
|
4870
|
+
for (const id of toArray(ids)) {
|
|
4871
|
+
if (!group.has(id)) continue;
|
|
4872
|
+
if (opened(id)) close(id);
|
|
4873
|
+
else open(id);
|
|
4874
|
+
}
|
|
4875
|
+
}
|
|
4876
|
+
/**
|
|
4877
|
+
* Open node(s) and their immediate non-leaf children.
|
|
4878
|
+
* Useful for expanding a section with its immediate subcategories.
|
|
4879
|
+
*/
|
|
4880
|
+
function unfold(ids) {
|
|
4881
|
+
for (const id of toArray(ids)) {
|
|
4882
|
+
if (!group.has(id)) continue;
|
|
4883
|
+
open(id);
|
|
4884
|
+
const childIds = children.get(id) ?? [];
|
|
4885
|
+
for (const childId of childIds) if (!isLeaf(childId)) open(childId);
|
|
4886
|
+
}
|
|
4887
|
+
}
|
|
4888
|
+
/**
|
|
4889
|
+
* Reveal a node by opening all its ancestors.
|
|
4890
|
+
* Makes the node visible in a collapsed tree without opening the node itself.
|
|
4891
|
+
*/
|
|
4892
|
+
function reveal(ids) {
|
|
4893
|
+
for (const id of toArray(ids)) {
|
|
4894
|
+
if (!group.has(id)) continue;
|
|
4895
|
+
const ancestorIds = getAncestors(id);
|
|
4896
|
+
if (ancestorIds.length > 0) open(ancestorIds);
|
|
4897
|
+
}
|
|
4898
|
+
}
|
|
4899
|
+
/**
|
|
4900
|
+
* Fully expand a node and all its non-leaf descendants.
|
|
4901
|
+
* Opens the entire subtree rooted at the given node.
|
|
4902
|
+
*/
|
|
4903
|
+
function expand(ids) {
|
|
4904
|
+
for (const id of toArray(ids)) {
|
|
4905
|
+
if (!group.has(id)) continue;
|
|
4906
|
+
if (!isLeaf(id)) open(id);
|
|
4907
|
+
for (const descendantId of getDescendants(id)) if (!isLeaf(descendantId)) open(descendantId);
|
|
4908
|
+
}
|
|
4909
|
+
}
|
|
4910
|
+
function expandAll() {
|
|
4911
|
+
for (const id of group.keys()) if (!isLeaf(id)) openedIds.add(id);
|
|
4912
|
+
}
|
|
4913
|
+
function collapseAll() {
|
|
4914
|
+
openedIds.clear();
|
|
4915
|
+
}
|
|
4916
|
+
function getPath(id) {
|
|
4917
|
+
const path = [];
|
|
4918
|
+
let currentId = id;
|
|
4919
|
+
while (!/* @__PURE__ */ isUndefined(currentId)) {
|
|
4920
|
+
path.unshift(currentId);
|
|
4921
|
+
currentId = parents.get(currentId);
|
|
4922
|
+
}
|
|
4923
|
+
return path;
|
|
4924
|
+
}
|
|
4925
|
+
function getAncestors(id) {
|
|
4926
|
+
return getPath(id).slice(0, -1);
|
|
4927
|
+
}
|
|
4928
|
+
function getDescendants(id) {
|
|
4929
|
+
const descendants = [];
|
|
4930
|
+
const queue = [...children.get(id) ?? []];
|
|
4931
|
+
let index = 0;
|
|
4932
|
+
while (index < queue.length) {
|
|
4933
|
+
const currentId = queue[index++];
|
|
4934
|
+
descendants.push(currentId);
|
|
4935
|
+
queue.push(...children.get(currentId) ?? []);
|
|
4936
|
+
}
|
|
4937
|
+
return descendants;
|
|
4938
|
+
}
|
|
4939
|
+
function isLeaf(id) {
|
|
4940
|
+
const childList = children.get(id);
|
|
4941
|
+
return /* @__PURE__ */ isUndefined(childList) || childList.length === 0;
|
|
4942
|
+
}
|
|
4943
|
+
function getDepth(id) {
|
|
4944
|
+
return getAncestors(id).length;
|
|
4945
|
+
}
|
|
4946
|
+
/**
|
|
4947
|
+
* Check if `ancestorId` is an ancestor of `descendantId`.
|
|
4948
|
+
* Returns false if either ID doesn't exist in the tree.
|
|
4949
|
+
*/
|
|
4950
|
+
function isAncestorOf(ancestorId, descendantId) {
|
|
4951
|
+
if (!group.has(ancestorId) || !group.has(descendantId)) return false;
|
|
4952
|
+
if (ancestorId === descendantId) return false;
|
|
4953
|
+
let currentId = parents.get(descendantId);
|
|
4954
|
+
while (!/* @__PURE__ */ isUndefined(currentId)) {
|
|
4955
|
+
if (currentId === ancestorId) return true;
|
|
4956
|
+
currentId = parents.get(currentId);
|
|
4957
|
+
}
|
|
4958
|
+
return false;
|
|
4959
|
+
}
|
|
4960
|
+
/**
|
|
4961
|
+
* Check if `id` has `ancestorId` as an ancestor.
|
|
4962
|
+
* Semantic alias for isAncestorOf(ancestorId, id).
|
|
4963
|
+
*/
|
|
4964
|
+
function hasAncestor(id, ancestorId) {
|
|
4965
|
+
return isAncestorOf(ancestorId, id);
|
|
4966
|
+
}
|
|
4967
|
+
/**
|
|
4968
|
+
* Get siblings of a node (including self).
|
|
4969
|
+
* For root nodes, returns all root IDs.
|
|
4970
|
+
*/
|
|
4971
|
+
function siblings(id) {
|
|
4972
|
+
if (!group.has(id)) return [];
|
|
4973
|
+
const parentId = parents.get(id);
|
|
4974
|
+
if (/* @__PURE__ */ isUndefined(parentId)) return group.values().filter((item) => /* @__PURE__ */ isUndefined(parents.get(item.id))).map((item) => item.id);
|
|
4975
|
+
return children.get(parentId) ?? [];
|
|
4976
|
+
}
|
|
4977
|
+
/**
|
|
4978
|
+
* Get 1-indexed position among siblings (for aria-posinset).
|
|
4979
|
+
* Returns 0 if node not found.
|
|
4980
|
+
*/
|
|
4981
|
+
function position(id) {
|
|
4982
|
+
const index = siblings(id).indexOf(id);
|
|
4983
|
+
return index === -1 ? 0 : index + 1;
|
|
4984
|
+
}
|
|
4985
|
+
function updateAncestors(id) {
|
|
4986
|
+
const ancestorIds = getAncestors(id).toReversed();
|
|
4987
|
+
for (const aid of ancestorIds) {
|
|
4988
|
+
const childIds = children.get(aid) ?? [];
|
|
4989
|
+
if (childIds.length === 0) continue;
|
|
4990
|
+
const allSelected = childIds.every((cid) => group.selected(cid));
|
|
4991
|
+
const someSelected = childIds.some((cid) => group.selected(cid) || group.mixed(cid));
|
|
4992
|
+
if (allSelected) {
|
|
4993
|
+
group.unmix(aid);
|
|
4994
|
+
group.select(aid);
|
|
4995
|
+
} else if (someSelected) {
|
|
4996
|
+
group.unselect(aid);
|
|
4997
|
+
group.mix(aid);
|
|
4998
|
+
} else {
|
|
4999
|
+
group.unmix(aid);
|
|
5000
|
+
group.unselect(aid);
|
|
5001
|
+
}
|
|
5002
|
+
}
|
|
5003
|
+
}
|
|
5004
|
+
function getLeafDescendants(id) {
|
|
5005
|
+
return getDescendants(id).filter((did) => isLeaf(did));
|
|
5006
|
+
}
|
|
5007
|
+
function select(ids) {
|
|
5008
|
+
for (const id of toArray(ids)) {
|
|
5009
|
+
if (!group.has(id)) continue;
|
|
5010
|
+
if (selectionMode === "independent") group.select(id);
|
|
5011
|
+
else if (selectionMode === "leaf") if (isLeaf(id)) group.select(id);
|
|
5012
|
+
else for (const lid of getLeafDescendants(id)) group.select(lid);
|
|
5013
|
+
else {
|
|
5014
|
+
group.unmix(id);
|
|
5015
|
+
group.select(id);
|
|
5016
|
+
for (const did of getDescendants(id)) {
|
|
5017
|
+
group.unmix(did);
|
|
5018
|
+
group.select(did);
|
|
5019
|
+
}
|
|
5020
|
+
updateAncestors(id);
|
|
5021
|
+
}
|
|
5022
|
+
}
|
|
5023
|
+
}
|
|
5024
|
+
function unselect(ids) {
|
|
5025
|
+
for (const id of toArray(ids)) {
|
|
5026
|
+
if (!group.has(id)) continue;
|
|
5027
|
+
if (selectionMode === "independent") group.unselect(id);
|
|
5028
|
+
else if (selectionMode === "leaf") if (isLeaf(id)) group.unselect(id);
|
|
5029
|
+
else for (const lid of getLeafDescendants(id)) group.unselect(lid);
|
|
5030
|
+
else {
|
|
5031
|
+
group.unmix(id);
|
|
5032
|
+
group.unselect(id);
|
|
5033
|
+
for (const did of getDescendants(id)) {
|
|
5034
|
+
group.unmix(did);
|
|
5035
|
+
group.unselect(did);
|
|
5036
|
+
}
|
|
5037
|
+
updateAncestors(id);
|
|
5038
|
+
}
|
|
5039
|
+
}
|
|
5040
|
+
}
|
|
5041
|
+
function toggle(ids) {
|
|
5042
|
+
for (const id of toArray(ids)) if (selectionMode === "independent") group.toggle(id);
|
|
5043
|
+
else if (selectionMode === "leaf") if (isLeaf(id)) group.toggle(id);
|
|
5044
|
+
else {
|
|
5045
|
+
const leafIds = getLeafDescendants(id);
|
|
5046
|
+
if (leafIds.every((lid) => group.selected(lid))) for (const lid of leafIds) group.unselect(lid);
|
|
5047
|
+
else for (const lid of leafIds) group.select(lid);
|
|
5048
|
+
}
|
|
5049
|
+
else if (group.selected(id) || group.mixed(id)) unselect(id);
|
|
5050
|
+
else select(id);
|
|
5051
|
+
}
|
|
5052
|
+
/**
|
|
5053
|
+
* Converts the tree to a flat array with parentId references.
|
|
5054
|
+
* Useful for serialization or sending to APIs/AI systems.
|
|
5055
|
+
*/
|
|
5056
|
+
function toFlat() {
|
|
5057
|
+
return group.values().map((item) => ({
|
|
5058
|
+
id: item.id,
|
|
5059
|
+
parentId: parents.get(item.id),
|
|
5060
|
+
value: item.value
|
|
5061
|
+
}));
|
|
5062
|
+
}
|
|
5063
|
+
function register(registration = {}) {
|
|
5064
|
+
const id = registration.id ?? /* @__PURE__ */ useId$1();
|
|
5065
|
+
const parentId = registration.parentId;
|
|
5066
|
+
const nested = registration.children;
|
|
5067
|
+
if (!/* @__PURE__ */ isUndefined(parentId) && !group.has(parentId)) logger$1.warn(`Parent with id "${parentId}" does not exist. Registering "${id}" without parent.`);
|
|
5068
|
+
if (!/* @__PURE__ */ isUndefined(parentId) && group.has(parentId)) {
|
|
5069
|
+
parents.set(id, parentId);
|
|
5070
|
+
const list = children.get(parentId);
|
|
5071
|
+
if (list) list.push(id);
|
|
5072
|
+
else children.set(parentId, [id]);
|
|
5073
|
+
if (openAll) openedIds.add(parentId);
|
|
5074
|
+
} else parents.set(id, void 0);
|
|
5075
|
+
const { children: _, ...rest } = registration;
|
|
5076
|
+
const item = {
|
|
5077
|
+
...rest,
|
|
5078
|
+
id,
|
|
5079
|
+
parentId: parents.get(id),
|
|
5080
|
+
isOpen: toRef(() => opened(id)),
|
|
5081
|
+
isLeaf: toRef(() => isLeaf(id)),
|
|
5082
|
+
depth: toRef(() => getDepth(id)),
|
|
5083
|
+
open: () => open(id),
|
|
5084
|
+
close: () => close(id),
|
|
5085
|
+
flip: () => flip(id),
|
|
5086
|
+
reveal: () => reveal(id),
|
|
5087
|
+
getPath: () => getPath(id),
|
|
5088
|
+
getAncestors: () => getAncestors(id),
|
|
5089
|
+
getDescendants: () => getDescendants(id),
|
|
5090
|
+
isAncestorOf: (descendantId) => isAncestorOf(id, descendantId),
|
|
5091
|
+
hasAncestor: (ancestorId) => hasAncestor(id, ancestorId),
|
|
5092
|
+
siblings: () => siblings(id),
|
|
5093
|
+
position: () => position(id)
|
|
5094
|
+
};
|
|
5095
|
+
const ticket = group.register(item);
|
|
5096
|
+
if (nested?.length) for (const child of nested) register({
|
|
5097
|
+
...child,
|
|
5098
|
+
parentId: id
|
|
5099
|
+
});
|
|
5100
|
+
return ticket;
|
|
5101
|
+
}
|
|
5102
|
+
function unregister(id, cascade = false) {
|
|
5103
|
+
if (!group.has(id)) return;
|
|
5104
|
+
const parentId = parents.get(id);
|
|
5105
|
+
if (!/* @__PURE__ */ isUndefined(parentId)) {
|
|
5106
|
+
const siblings$1 = children.get(parentId);
|
|
5107
|
+
if (siblings$1) {
|
|
5108
|
+
const filtered = siblings$1.filter((sid) => sid !== id);
|
|
5109
|
+
if (filtered.length === 0) children.delete(parentId);
|
|
5110
|
+
else children.set(parentId, filtered);
|
|
5111
|
+
}
|
|
5112
|
+
}
|
|
5113
|
+
const list = children.get(id);
|
|
5114
|
+
if (list?.length) if (cascade) for (const did of getDescendants(id)) {
|
|
5115
|
+
parents.delete(did);
|
|
5116
|
+
children.delete(did);
|
|
5117
|
+
openedIds.delete(did);
|
|
5118
|
+
group.unregister(did);
|
|
5119
|
+
}
|
|
5120
|
+
else {
|
|
5121
|
+
for (const did of getDescendants(id)) openedIds.delete(did);
|
|
5122
|
+
for (const cid of list) parents.set(cid, void 0);
|
|
5123
|
+
}
|
|
5124
|
+
parents.delete(id);
|
|
5125
|
+
children.delete(id);
|
|
5126
|
+
openedIds.delete(id);
|
|
5127
|
+
group.unregister(id);
|
|
5128
|
+
}
|
|
5129
|
+
function offboard(ids, cascade = false) {
|
|
5130
|
+
for (const id of ids) unregister(id, cascade);
|
|
5131
|
+
}
|
|
5132
|
+
function onboard(registrations) {
|
|
5133
|
+
return registrations.map((registration) => register(registration));
|
|
5134
|
+
}
|
|
5135
|
+
function clear() {
|
|
5136
|
+
children.clear();
|
|
5137
|
+
parents.clear();
|
|
5138
|
+
openedIds.clear();
|
|
5139
|
+
group.reset();
|
|
5140
|
+
}
|
|
5141
|
+
function reset() {
|
|
5142
|
+
clear();
|
|
5143
|
+
}
|
|
5144
|
+
const context = {
|
|
5145
|
+
...group,
|
|
5146
|
+
children,
|
|
5147
|
+
parents,
|
|
5148
|
+
openedIds,
|
|
5149
|
+
openedItems,
|
|
5150
|
+
roots,
|
|
5151
|
+
leaves,
|
|
5152
|
+
getPath,
|
|
5153
|
+
getAncestors,
|
|
5154
|
+
getDescendants,
|
|
5155
|
+
isLeaf,
|
|
5156
|
+
getDepth,
|
|
5157
|
+
isAncestorOf,
|
|
5158
|
+
hasAncestor,
|
|
5159
|
+
siblings,
|
|
5160
|
+
position,
|
|
5161
|
+
open,
|
|
5162
|
+
close,
|
|
5163
|
+
flip,
|
|
5164
|
+
opened,
|
|
5165
|
+
unfold,
|
|
5166
|
+
reveal,
|
|
5167
|
+
expand,
|
|
5168
|
+
expandAll,
|
|
5169
|
+
collapseAll,
|
|
5170
|
+
toFlat,
|
|
5171
|
+
openStrategy: resolvedOpenStrategy,
|
|
5172
|
+
select,
|
|
5173
|
+
unselect,
|
|
5174
|
+
toggle,
|
|
5175
|
+
register,
|
|
5176
|
+
unregister,
|
|
5177
|
+
offboard,
|
|
5178
|
+
onboard,
|
|
5179
|
+
clear,
|
|
5180
|
+
reset,
|
|
5181
|
+
get size() {
|
|
5182
|
+
return group.size;
|
|
5183
|
+
}
|
|
5184
|
+
};
|
|
5185
|
+
return context;
|
|
5186
|
+
}
|
|
5187
|
+
/**
|
|
5188
|
+
* Creates a new nested context with provide/inject pattern.
|
|
5189
|
+
*
|
|
5190
|
+
* @param options The options for the nested context.
|
|
5191
|
+
* @returns A trinity tuple [useNested, provideNested, defaultNested]
|
|
5192
|
+
*
|
|
5193
|
+
* @see https://0.vuetifyjs.com/composables/selection/use-nested
|
|
5194
|
+
*
|
|
5195
|
+
* @example
|
|
5196
|
+
* ```ts
|
|
5197
|
+
* import { createNestedContext } from '@vuetify/v0'
|
|
5198
|
+
*
|
|
5199
|
+
* export const [useTree, provideTree, tree] = createNestedContext()
|
|
5200
|
+
*
|
|
5201
|
+
* // In parent: provideTree()
|
|
5202
|
+
* // In child: const tree = useTree()
|
|
5203
|
+
* ```
|
|
5204
|
+
*/
|
|
5205
|
+
function createNestedContext(_options = {}) {
|
|
5206
|
+
const { namespace = "v0:nested", ...options } = _options;
|
|
5207
|
+
const [useNestedContext, _provideNestedContext] = createContext(namespace);
|
|
5208
|
+
const context = createNested(options);
|
|
5209
|
+
function provideNestedContext(_context = context, app) {
|
|
5210
|
+
return _provideNestedContext(_context, app);
|
|
5211
|
+
}
|
|
5212
|
+
return createTrinity(useNestedContext, provideNestedContext, context);
|
|
5213
|
+
}
|
|
5214
|
+
/**
|
|
5215
|
+
* Returns the current nested instance from context.
|
|
5216
|
+
*
|
|
5217
|
+
* @param namespace The namespace for the nested context. Defaults to `'v0:nested'`.
|
|
5218
|
+
* @returns The current nested instance.
|
|
5219
|
+
*
|
|
5220
|
+
* @see https://0.vuetifyjs.com/composables/selection/use-nested
|
|
5221
|
+
*/
|
|
5222
|
+
function useNested(namespace = "v0:nested") {
|
|
5223
|
+
return useContext(namespace);
|
|
5224
|
+
}
|
|
5225
|
+
|
|
5088
5226
|
//#endregion
|
|
5089
5227
|
//#region src/composables/useResizeObserver/index.ts
|
|
5090
5228
|
/**
|
|
@@ -5146,12 +5284,13 @@ function useMutationObserver(target, callback, options = {}) {
|
|
|
5146
5284
|
*/
|
|
5147
5285
|
function useResizeObserver(target, callback, options = {}) {
|
|
5148
5286
|
const { isHydrated } = useHydration();
|
|
5287
|
+
const targetRef = toRef(target);
|
|
5149
5288
|
const observer = shallowRef();
|
|
5150
5289
|
const isPaused = shallowRef(false);
|
|
5151
5290
|
const isActive = toRef(() => !!observer.value);
|
|
5152
5291
|
function setup() {
|
|
5153
5292
|
if (/* @__PURE__ */ isNull(observer.value)) return;
|
|
5154
|
-
if (!isHydrated.value || !SUPPORTS_OBSERVER || !
|
|
5293
|
+
if (!isHydrated.value || !SUPPORTS_OBSERVER || !targetRef.value || isPaused.value) return;
|
|
5155
5294
|
observer.value = new ResizeObserver((entries) => {
|
|
5156
5295
|
callback(entries.map((entry) => ({
|
|
5157
5296
|
contentRect: {
|
|
@@ -5164,9 +5303,9 @@ function useResizeObserver(target, callback, options = {}) {
|
|
|
5164
5303
|
})));
|
|
5165
5304
|
if (options.once) stop();
|
|
5166
5305
|
});
|
|
5167
|
-
observer.value.observe(
|
|
5306
|
+
observer.value.observe(targetRef.value, { box: options.box || "content-box" });
|
|
5168
5307
|
if (options.immediate) {
|
|
5169
|
-
const rect =
|
|
5308
|
+
const rect = targetRef.value.getBoundingClientRect();
|
|
5170
5309
|
callback([{
|
|
5171
5310
|
contentRect: {
|
|
5172
5311
|
width: rect.width,
|
|
@@ -5174,22 +5313,22 @@ function useResizeObserver(target, callback, options = {}) {
|
|
|
5174
5313
|
top: rect.top,
|
|
5175
5314
|
left: rect.left
|
|
5176
5315
|
},
|
|
5177
|
-
target:
|
|
5316
|
+
target: targetRef.value
|
|
5178
5317
|
}]);
|
|
5179
5318
|
}
|
|
5180
5319
|
}
|
|
5181
|
-
watch(() =>
|
|
5182
|
-
if (oldEl) cleanup();
|
|
5320
|
+
watch(() => targetRef.value, (el, oldEl) => {
|
|
5321
|
+
if (oldEl || observer.value) cleanup();
|
|
5183
5322
|
if (isHydrated.value && el) setup();
|
|
5184
5323
|
}, { immediate: true });
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
}
|
|
5192
|
-
}
|
|
5324
|
+
let stopHydrationWatch;
|
|
5325
|
+
if (!isHydrated.value) stopHydrationWatch = watch(() => isHydrated.value, (hydrated) => {
|
|
5326
|
+
if (hydrated && targetRef.value && !observer.value) {
|
|
5327
|
+
setup();
|
|
5328
|
+
stopHydrationWatch?.();
|
|
5329
|
+
stopHydrationWatch = void 0;
|
|
5330
|
+
}
|
|
5331
|
+
});
|
|
5193
5332
|
function cleanup() {
|
|
5194
5333
|
if (observer.value) {
|
|
5195
5334
|
observer.value.disconnect();
|
|
@@ -5205,6 +5344,8 @@ function useResizeObserver(target, callback, options = {}) {
|
|
|
5205
5344
|
setup();
|
|
5206
5345
|
}
|
|
5207
5346
|
function stop() {
|
|
5347
|
+
stopHydrationWatch?.();
|
|
5348
|
+
stopHydrationWatch = void 0;
|
|
5208
5349
|
cleanup();
|
|
5209
5350
|
observer.value = null;
|
|
5210
5351
|
}
|
|
@@ -5941,7 +6082,7 @@ function createQueue(_options = {}) {
|
|
|
5941
6082
|
}
|
|
5942
6083
|
}
|
|
5943
6084
|
function register(registration = {}) {
|
|
5944
|
-
const id = registration.id ?? /* @__PURE__ */
|
|
6085
|
+
const id = registration.id ?? /* @__PURE__ */ useId$1();
|
|
5945
6086
|
const timeout = Object.prototype.hasOwnProperty.call(registration, "timeout") ? registration.timeout : _timeout;
|
|
5946
6087
|
const ticket = {
|
|
5947
6088
|
...registration,
|
|
@@ -6198,8 +6339,9 @@ function createStep(_options = {}) {
|
|
|
6198
6339
|
* Creates a new step context.
|
|
6199
6340
|
*
|
|
6200
6341
|
* @param options The options for the step context.
|
|
6201
|
-
* @template Z The
|
|
6202
|
-
* @template E The
|
|
6342
|
+
* @template Z The input ticket type.
|
|
6343
|
+
* @template E The output ticket type.
|
|
6344
|
+
* @template R The context type.
|
|
6203
6345
|
* @returns A new step context.
|
|
6204
6346
|
*
|
|
6205
6347
|
* @see https://0.vuetifyjs.com/composables/selection/use-step
|
|
@@ -6232,6 +6374,9 @@ function createStepContext(_options = {}) {
|
|
|
6232
6374
|
* Returns the current step instance.
|
|
6233
6375
|
*
|
|
6234
6376
|
* @param namespace The namespace for the step context. Defaults to `'v0:step'`.
|
|
6377
|
+
* @template Z The input ticket type.
|
|
6378
|
+
* @template E The output ticket type.
|
|
6379
|
+
* @template R The context type.
|
|
6235
6380
|
* @returns The current step instance.
|
|
6236
6381
|
*
|
|
6237
6382
|
* @see https://0.vuetifyjs.com/composables/selection/use-step
|
|
@@ -7653,4 +7798,4 @@ function useClickOutside(target, handler, options = {}) {
|
|
|
7653
7798
|
}
|
|
7654
7799
|
|
|
7655
7800
|
//#endregion
|
|
7656
|
-
export {
|
|
7801
|
+
export { createForm as $, createLoggerPlugin as $t, PermissionAdapter as A, createBreakpoints as At, createNestedContext as B, useProxyModel as Bt, createQueue as C, Vuetify0LocaleAdapter as Ct, createPermissionsContext as D, createSingle as Dt, createPermissions as E, useTokens as Et, createOverflowContext as F, createHydration as Ft, useMediaQuery as G, useProxyRegistry as Gt, multipleOpenStrategy as H, createGroupContext as Ht, useOverflow as I, createHydrationContext as It, usePrefersReducedMotion as J, useSelection as Jt, usePrefersContrast as K, createSelection as Kt, useElementSize as L, createHydrationPlugin as Lt, createPaginationContext as M, createBreakpointsPlugin as Mt, usePagination as N, useBreakpoints as Nt, createPermissionsPlugin as O, createSingleContext as Ot, createOverflow as P, createFallbackHydration as Pt, useHotkey as Q, createLoggerContext as Qt, useResizeObserver as R, useHydration as Rt, useStep as S, useLocale as St, useQueue as T, createTokensContext as Tt, singleOpenStrategy as U, useGroup as Ut, useNested as V, createGroup as Vt, useMutationObserver as W, toArray as Wt, useElementIntersection as X, createRegistryContext as Xt, useLazy as Y, createRegistry as Yt, useIntersectionObserver as Z, createLogger as Zt, createStoragePlugin as _, useDate as _t, useVirtual as a, createTrinity as an, useFilterContext as at, createStep as b, createLocaleFallback as bt, createTimelineContext as c, useContext as cn, createFeaturesPlugin as ct, createThemeContext as d, LaunchDarklyFeatureAdapter as dt, useLogger as en, createFormContext as et, createThemePlugin as f, FlagsmithFeatureAdapter as ft, createStorageContext as g, createDatePlugin as gt, createStorage as h, createDateContext as ht, useWindowEventListener as i, createPlugin as in, useFilter as it, createPagination as j, createBreakpointsContext as jt, usePermissions as k, useSingle as kt, useTimeline as l, useFeatures as lt, Vuetify0ThemeAdapter as m, createDate as mt, useDocumentEventListener as n, PinoLoggerAdapter as nn, createFilter as nt, useToggleScope as o, createContext as on, createFeatures as ot, useTheme as p, FeaturesAdapter as pt, usePrefersDark as q, createSelectionContext as qt, useEventListener as r, ConsolaLoggerAdapter as rn, createFilterContext as rt, createTimeline as s, provideContext as sn, createFeaturesContext as st, useClickOutside as t, Vuetify0LoggerAdapter as tn, useForm as tt, createTheme as u, PostHogFeatureAdapter as ut, useStorage as v, createLocale as vt, createQueueContext as w, createTokens as wt, createStepContext as x, createLocalePlugin as xt, MemoryAdapter as y, createLocaleContext as yt, createNested as z, toReactive as zt };
|