@vuetify/v0 0.0.2-beta.3 → 0.0.2

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.
@@ -1,4 +1,4 @@
1
- import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createPropsRestProxy, defineComponent, getCurrentInstance, getCurrentScope, guardReactiveProps, inject, isRef, mergeModels, mergeProps, normalizeProps, normalizeStyle, onMounted, onScopeDispose, onUnmounted, openBlock, provide, reactive, ref, renderSlot, resolveDynamicComponent, shallowReactive, shallowReadonly, shallowRef, toRaw, toRef, toValue, unref, useAttrs, useId, useModel, useTemplateRef, watch, withCtx } from "vue";
1
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createPropsRestProxy, defineComponent, getCurrentInstance, getCurrentScope, guardReactiveProps, inject, isRef, mergeModels, mergeProps, normalizeProps, normalizeStyle, onMounted, onScopeDispose, onUnmounted, openBlock, provide, reactive, readonly, ref, renderSlot, resolveDynamicComponent, shallowReactive, shallowReadonly, shallowRef, toRaw, toRef, toValue, unref, useAttrs, useId, useModel, useTemplateRef, watch, withCtx } from "vue";
2
2
 
3
3
  //#region src/constants/htmlElements.ts
4
4
  const selfClosingTags = [
@@ -22,6 +22,54 @@ const selfClosingTags = [
22
22
  */
23
23
  const SELF_CLOSING_TAGS = new Set(selfClosingTags);
24
24
  /**
25
+ * Common HTML element types for polymorphic components
26
+ */
27
+ const COMMON_ELEMENTS = {
28
+ DIV: "div",
29
+ SPAN: "span",
30
+ SECTION: "section",
31
+ ARTICLE: "article",
32
+ ASIDE: "aside",
33
+ HEADER: "header",
34
+ FOOTER: "footer",
35
+ MAIN: "main",
36
+ NAV: "nav",
37
+ P: "p",
38
+ H1: "h1",
39
+ H2: "h2",
40
+ H3: "h3",
41
+ H4: "h4",
42
+ H5: "h5",
43
+ H6: "h6",
44
+ BUTTON: "button",
45
+ A: "a",
46
+ INPUT: "input",
47
+ TEXTAREA: "textarea",
48
+ SELECT: "select",
49
+ LABEL: "label",
50
+ UL: "ul",
51
+ OL: "ol",
52
+ LI: "li",
53
+ DL: "dl",
54
+ DT: "dt",
55
+ DD: "dd",
56
+ IMG: "img",
57
+ VIDEO: "video",
58
+ AUDIO: "audio",
59
+ CANVAS: "canvas",
60
+ SVG: "svg",
61
+ TABLE: "table",
62
+ THEAD: "thead",
63
+ TBODY: "tbody",
64
+ TFOOT: "tfoot",
65
+ TR: "tr",
66
+ TH: "th",
67
+ TD: "td",
68
+ FORM: "form",
69
+ FIELDSET: "fieldset",
70
+ LEGEND: "legend"
71
+ };
72
+ /**
25
73
  * Check if an element is self-closing
26
74
  */
27
75
  function isSelfClosingTag(tag) {
@@ -234,7 +282,8 @@ const SUPPORTS_MATCH_MEDIA = IN_BROWSER && "matchMedia" in window && typeof wind
234
282
  const SUPPORTS_OBSERVER = IN_BROWSER && "ResizeObserver" in window;
235
283
  const SUPPORTS_INTERSECTION_OBSERVER = IN_BROWSER && "IntersectionObserver" in window;
236
284
  const SUPPORTS_MUTATION_OBSERVER = IN_BROWSER && "MutationObserver" in window;
237
- const __LOGGER_ENABLED__ = process.env.NODE_ENV !== "production" || process.env.VITE_LOGGER_ENABLED === "true";
285
+ const version = "0.0.2";
286
+ const __LOGGER_ENABLED__ = false;
238
287
 
239
288
  //#endregion
240
289
  //#region src/composables/useBreakpoints/index.ts
@@ -598,8 +647,8 @@ var Vuetify0LoggerAdapter = class {
598
647
  }
599
648
  timestamp() {
600
649
  if (!IN_BROWSER) return (/* @__PURE__ */ new Date()).toISOString();
601
- const now$1 = /* @__PURE__ */ new Date();
602
- return now$1.toTimeString().split(" ")[0];
650
+ const now = /* @__PURE__ */ new Date();
651
+ return now.toTimeString().split(" ")[0];
603
652
  }
604
653
  style(level) {
605
654
  if (!this.colors || !IN_BROWSER) return "";
@@ -724,9 +773,7 @@ function createFallbackLogger(namespace = "v0:logger") {
724
773
  function useLogger(namespace) {
725
774
  if (getCurrentInstance()) try {
726
775
  return useLoggerContext(namespace);
727
- } catch (error) {
728
- if (process.env.NODE_ENV !== "production" && IN_BROWSER && namespace) console.warn(error);
729
- }
776
+ } catch (error) {}
730
777
  return createFallbackLogger(namespace);
731
778
  }
732
779
  function createLoggerPlugin(options = {}) {
@@ -736,12 +783,31 @@ function createLoggerPlugin(options = {}) {
736
783
  provide: (app) => {
737
784
  provideLoggerContext(context, app);
738
785
  },
739
- setup: (_app) => {
740
- if (process.env.NODE_ENV !== "production" && IN_BROWSER) window.__v0Logger__ = context;
741
- }
786
+ setup: (_app) => {}
742
787
  });
743
788
  }
744
789
 
790
+ //#endregion
791
+ //#region src/factories/createTrinity/index.ts
792
+ /**
793
+ * A tuple containing Vue's provide/inject and a context object
794
+ * @param createContext The function that creates the context
795
+ * @param provideContext The function that provides context
796
+ * @param context The underlying context object singleton
797
+ * @template Z The type parameter for the context value
798
+ * @template E The vmodel type for the context state.
799
+ * @returns [createContext, provideContext, context]
800
+ *
801
+ * @see https://0.vuetifyjs.com/composables/foundation/create-trinity
802
+ */
803
+ function createTrinity(createContext$1, provideContext, context) {
804
+ return [
805
+ createContext$1,
806
+ (_context = context, app) => provideContext(_context, app),
807
+ context
808
+ ];
809
+ }
810
+
745
811
  //#endregion
746
812
  //#region src/composables/useRegistry/index.ts
747
813
  /**
@@ -781,6 +847,40 @@ function useRegistry(options) {
781
847
  function get(id) {
782
848
  return collection.get(id);
783
849
  }
850
+ function upsert(id, patch = {}) {
851
+ const existing = get(id);
852
+ if (!existing) return register({
853
+ ...patch,
854
+ id
855
+ });
856
+ const hasValue = Object.prototype.hasOwnProperty.call(patch, "value");
857
+ let value = existing.value;
858
+ let valueIsIndex = existing.valueIsIndex;
859
+ if (hasValue) {
860
+ if (patch.value === void 0) {
861
+ value = existing.index;
862
+ valueIsIndex = true;
863
+ } else {
864
+ value = patch.value;
865
+ valueIsIndex = false;
866
+ }
867
+ if (!Object.is(value, existing.value)) {
868
+ unassign(existing.value, id);
869
+ assign(value, id);
870
+ }
871
+ }
872
+ const updated = {
873
+ ...existing,
874
+ ...patch,
875
+ id,
876
+ index: existing.index,
877
+ value,
878
+ valueIsIndex
879
+ };
880
+ collection.set(id, updated);
881
+ invalidate();
882
+ return updated;
883
+ }
784
884
  function browse(value) {
785
885
  return catalog.get(value);
786
886
  }
@@ -836,8 +936,7 @@ function useRegistry(options) {
836
936
  invalidate();
837
937
  }
838
938
  function invalidate() {
839
- if (cache.size === 0) return;
840
- cache.clear();
939
+ if (cache.size > 0) cache.clear();
841
940
  }
842
941
  function reindex() {
843
942
  if (catalog.size > 0) catalog.clear();
@@ -861,12 +960,15 @@ function useRegistry(options) {
861
960
  logger.warn(`Item with id "${id}" already exists in the registry. Skipping registration.`);
862
961
  return get(id);
863
962
  }
963
+ const index = registration.index ?? size;
964
+ const value = registration.value === void 0 ? index : registration.value;
965
+ const valueIsIndex = registration.value === void 0;
864
966
  const item = {
865
967
  ...registration,
866
968
  id,
867
- index: registration.index ?? size,
868
- value: registration.value ?? size,
869
- valueIsIndex: registration.valueIsIndex ?? registration.value == null
969
+ index,
970
+ value,
971
+ valueIsIndex
870
972
  };
871
973
  collection.set(item.id, item);
872
974
  directory.set(item.index, item.id);
@@ -898,6 +1000,7 @@ function useRegistry(options) {
898
1000
  values,
899
1001
  lookup,
900
1002
  get,
1003
+ upsert,
901
1004
  register,
902
1005
  unregister,
903
1006
  reindex,
@@ -909,6 +1012,24 @@ function useRegistry(options) {
909
1012
  }
910
1013
  };
911
1014
  }
1015
+ /**
1016
+ * Creates a registry context with full injection/provision control.
1017
+ * Returns the complete trinity for advanced usage scenarios.
1018
+ *
1019
+ * @param namespace The namespace for the registry context.
1020
+ * @param options Optional configuration for reactivity behavior.
1021
+ * @template Z The type of tickets managed by the registry.
1022
+ * @template E The type of the registry context.
1023
+ * @returns A tuple containing the inject function, provide function, and the registry context.
1024
+ */
1025
+ function createRegistryContext(namespace, options) {
1026
+ const [useRegistryContext, _provideRegistryContext] = createContext(namespace);
1027
+ const context = useRegistry(options);
1028
+ function provideRegistryContext(_context = context, app) {
1029
+ return _provideRegistryContext(_context, app);
1030
+ }
1031
+ return createTrinity(useRegistryContext, provideRegistryContext, context);
1032
+ }
912
1033
 
913
1034
  //#endregion
914
1035
  //#region src/composables/useSelection/index.ts
@@ -991,32 +1112,12 @@ function useSelection(options) {
991
1112
 
992
1113
  //#endregion
993
1114
  //#region src/utilities/benchmark.ts
994
- function now() {
995
- if (typeof performance !== "undefined") return performance.now();
996
- return Date.now();
997
- }
998
1115
  async function run(name, fn, samples = 100) {
999
- if (!(process.env.NODE_ENV !== "production")) {
1000
- fn();
1001
- return {
1002
- name,
1003
- duration: 0,
1004
- ops: Infinity
1005
- };
1006
- }
1007
- const times = [];
1008
- for (let i = 0; i < 5; i++) fn();
1009
- for (let i = 0; i < samples; i++) {
1010
- const start = now();
1011
- fn();
1012
- times.push(now() - start);
1013
- }
1014
- const duration = times.reduce((a, b) => a + b, 0) / times.length;
1015
- const ops = Math.round(1e3 / duration);
1116
+ fn();
1016
1117
  return {
1017
1118
  name,
1018
- duration,
1019
- ops
1119
+ duration: 0,
1120
+ ops: Infinity
1020
1121
  };
1021
1122
  }
1022
1123
 
@@ -1627,27 +1728,6 @@ const Step = {
1627
1728
  Root: StepRoot_default
1628
1729
  };
1629
1730
 
1630
- //#endregion
1631
- //#region src/factories/createTrinity/index.ts
1632
- /**
1633
- * A tuple containing Vue's provide/inject and a context object
1634
- * @param createContext The function that creates the context
1635
- * @param provideContext The function that provides context
1636
- * @param context The underlying context object singleton
1637
- * @template Z The type parameter for the context value
1638
- * @template E The vmodel type for the context state.
1639
- * @returns [createContext, provideContext, context]
1640
- *
1641
- * @see https://0.vuetifyjs.com/composables/foundation/create-trinity
1642
- */
1643
- function createTrinity(createContext$1, provideContext, context) {
1644
- return [
1645
- createContext$1,
1646
- (_context = context, app) => provideContext(_context, app),
1647
- context
1648
- ];
1649
- }
1650
-
1651
1731
  //#endregion
1652
1732
  //#region src/composables/useTokens/index.ts
1653
1733
  /**
@@ -1658,6 +1738,7 @@ function createTrinity(createContext$1, provideContext, context) {
1658
1738
  * @template Z The structure of the registry token items.
1659
1739
  * @template E The available methods for the token's context.
1660
1740
  * @returns The token context object.
1741
+ * @see https://www.designtokens.org/tr/drafts/format/
1661
1742
  */
1662
1743
  function useTokens(tokens = {}) {
1663
1744
  const logger = useLogger();
@@ -1671,21 +1752,56 @@ function useTokens(tokens = {}) {
1671
1752
  return isObject(value) && "$value" in value;
1672
1753
  }
1673
1754
  function resolve(token) {
1674
- const cached = cache.get(token);
1755
+ const cacheKey = isString(token) ? token : JSON.stringify(token);
1756
+ const cached = cache.get(cacheKey);
1675
1757
  if (cached !== void 0) return cached;
1676
1758
  const reference = isTokenAlias(token) ? token.$value : token;
1677
- const cleaned = isAlias(reference) ? reference.slice(1, -1) : reference;
1678
- const found = registry.get(cleaned);
1759
+ const clean = isString(reference) && isAlias(reference) ? reference.slice(1, -1) : String(reference);
1760
+ let found = registry.get(clean);
1761
+ let segments = [];
1762
+ if (!found && clean.includes(".")) {
1763
+ const parts = clean.split(".");
1764
+ for (let i = parts.length - 1; i > 0; i--) {
1765
+ const prefix = parts.slice(0, i).join(".");
1766
+ const suffix = parts.slice(i);
1767
+ const candidate = registry.get(prefix);
1768
+ if (candidate?.value !== void 0) {
1769
+ found = candidate;
1770
+ segments = suffix;
1771
+ break;
1772
+ }
1773
+ }
1774
+ }
1679
1775
  if (found?.value === void 0) {
1680
- logger.warn(`Alias not found for "${reference}"`);
1681
- cache.set(token, void 0);
1776
+ logger.warn(`Alias not found for "${String(reference)}"`);
1777
+ cache.set(cacheKey, void 0);
1682
1778
  return void 0;
1683
1779
  }
1684
1780
  let result;
1685
- if (isTokenAlias(found.value)) result = resolve(found.value.$value);
1686
- else if (isAlias(found.value)) result = resolve(found.value);
1687
- else result = String(found.value);
1688
- cache.set(token, result);
1781
+ let current = found.value;
1782
+ if (segments.length > 0) {
1783
+ if (isTokenAlias(current)) current = current.$value;
1784
+ for (const segment of segments) {
1785
+ if (!isObject(current) || !(segment in current)) {
1786
+ current = void 0;
1787
+ break;
1788
+ }
1789
+ current = current[segment];
1790
+ if (isTokenAlias(current)) current = current.$value;
1791
+ }
1792
+ if (current === void 0) {
1793
+ logger.warn(`Path not found inside "${clean}": ${segments.join(".")}`);
1794
+ cache.set(cacheKey, void 0);
1795
+ return void 0;
1796
+ }
1797
+ result = current;
1798
+ } else if (isTokenAlias(current)) {
1799
+ const inner = current.$value;
1800
+ if (isString(inner) && isAlias(inner)) return resolve(inner);
1801
+ result = inner;
1802
+ } else if (isString(current) && isAlias(current)) return resolve(current);
1803
+ else result = current;
1804
+ cache.set(cacheKey, result);
1689
1805
  return result;
1690
1806
  }
1691
1807
  return {
@@ -1726,18 +1842,49 @@ function flatten(tokens, prefix = "") {
1726
1842
  }];
1727
1843
  while (stack.length > 0) {
1728
1844
  const { tokens: currentTokens, prefix: currentPrefix } = stack.pop();
1845
+ const meta = {};
1846
+ for (const k in currentTokens) if (k.startsWith("$")) meta[k] = currentTokens[k];
1847
+ if (Object.keys(meta).length > 0 && currentPrefix) flattened.push({
1848
+ id: currentPrefix,
1849
+ value: meta
1850
+ });
1729
1851
  for (const key in currentTokens) {
1852
+ if (key.startsWith("$")) continue;
1730
1853
  const value = currentTokens[key];
1731
1854
  const id = currentPrefix ? `${currentPrefix}.${key}` : key;
1732
- if (isPrimitive(value)) flattened.push({
1733
- id,
1734
- value: String(value)
1735
- });
1736
- else if (isObject(value) && "$value" in value) flattened.push({
1737
- id,
1738
- value
1739
- });
1740
- else if (isObject(value)) stack.push({
1855
+ if (!isObject(value)) {
1856
+ flattened.push({
1857
+ id,
1858
+ value
1859
+ });
1860
+ continue;
1861
+ }
1862
+ if ("$value" in value) {
1863
+ flattened.push({
1864
+ id,
1865
+ value
1866
+ });
1867
+ const inner = value.$value;
1868
+ if (isObject(inner)) for (const innerKey in inner) {
1869
+ if (innerKey.startsWith("$")) continue;
1870
+ const child = inner[innerKey];
1871
+ const childId = `${id}.${innerKey}`;
1872
+ if (!isObject(child)) flattened.push({
1873
+ id: childId,
1874
+ value: child
1875
+ });
1876
+ else if ("$value" in child) flattened.push({
1877
+ id: childId,
1878
+ value: child
1879
+ });
1880
+ else stack.push({
1881
+ tokens: child,
1882
+ prefix: childId
1883
+ });
1884
+ }
1885
+ continue;
1886
+ }
1887
+ stack.push({
1741
1888
  tokens: value,
1742
1889
  prefix: id
1743
1890
  });
@@ -1956,9 +2103,9 @@ var ThemeRoot_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defi
1956
2103
  }),
1957
2104
  emits: ["update:modelValue"],
1958
2105
  setup(__props) {
1959
- const model = useModel(__props, "modelValue");
2106
+ useModel(__props, "modelValue");
1960
2107
  const [provideThemeContext] = createTheme(__props.namespace);
1961
- const themeContext = provideThemeContext(model);
2108
+ const themeContext = provideThemeContext();
1962
2109
  for (const theme of __props.themes) themeContext.register(theme);
1963
2110
  return (_ctx, _cache) => {
1964
2111
  return renderSlot(_ctx.$slots, "default", normalizeProps(guardReactiveProps(unref(themeContext))));
@@ -2194,6 +2341,146 @@ function useForm(options) {
2194
2341
  };
2195
2342
  }
2196
2343
 
2344
+ //#endregion
2345
+ //#region src/composables/useIntersectionObserver/index.ts
2346
+ /**
2347
+ * Composable for observing element intersection with viewport or ancestor
2348
+ *
2349
+ * @param target - Element ref to observe
2350
+ * @param callback - Callback fired on intersection change
2351
+ * @param options - Observer options
2352
+ * @returns Observer controls and intersection state
2353
+ *
2354
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver
2355
+ */
2356
+ function useIntersectionObserver(target, callback, options = {}) {
2357
+ const { isHydrated } = useHydration();
2358
+ const observer = shallowRef();
2359
+ const isPaused = shallowRef(false);
2360
+ const isIntersecting = shallowRef(false);
2361
+ watch([isHydrated, target], ([hydrated, el]) => {
2362
+ cleanup();
2363
+ if (!hydrated || !SUPPORTS_INTERSECTION_OBSERVER || !el) return;
2364
+ observer.value = new IntersectionObserver((entries) => {
2365
+ const transformedEntries = entries.map((entry) => ({
2366
+ boundingClientRect: entry.boundingClientRect,
2367
+ intersectionRatio: entry.intersectionRatio,
2368
+ intersectionRect: entry.intersectionRect,
2369
+ isIntersecting: entry.isIntersecting,
2370
+ rootBounds: entry.rootBounds,
2371
+ target: entry.target,
2372
+ time: entry.time
2373
+ }));
2374
+ const latestEntry = transformedEntries.at(-1);
2375
+ if (latestEntry) isIntersecting.value = latestEntry.isIntersecting;
2376
+ callback(transformedEntries);
2377
+ }, {
2378
+ root: options.root || null,
2379
+ rootMargin: options.rootMargin || "0px",
2380
+ threshold: options.threshold || 0
2381
+ });
2382
+ observer.value.observe(el);
2383
+ if (options.immediate) {
2384
+ const rect = el.getBoundingClientRect();
2385
+ const syntheticEntry = {
2386
+ boundingClientRect: rect,
2387
+ intersectionRatio: 0,
2388
+ intersectionRect: new DOMRect(0, 0, 0, 0),
2389
+ isIntersecting: false,
2390
+ rootBounds: null,
2391
+ target: el,
2392
+ time: performance.now()
2393
+ };
2394
+ callback([syntheticEntry]);
2395
+ }
2396
+ });
2397
+ function setup() {
2398
+ if (!isHydrated.value || !SUPPORTS_INTERSECTION_OBSERVER || !target.value || isPaused.value) return;
2399
+ observer.value = new IntersectionObserver((entries) => {
2400
+ const transformedEntries = entries.map((entry) => ({
2401
+ boundingClientRect: entry.boundingClientRect,
2402
+ intersectionRatio: entry.intersectionRatio,
2403
+ intersectionRect: entry.intersectionRect,
2404
+ isIntersecting: entry.isIntersecting,
2405
+ rootBounds: entry.rootBounds,
2406
+ target: entry.target,
2407
+ time: entry.time
2408
+ }));
2409
+ const latestEntry = transformedEntries.at(-1);
2410
+ if (latestEntry) isIntersecting.value = latestEntry.isIntersecting;
2411
+ callback(transformedEntries);
2412
+ }, {
2413
+ root: options.root || null,
2414
+ rootMargin: options.rootMargin || "0px",
2415
+ threshold: options.threshold || 0
2416
+ });
2417
+ observer.value.observe(target.value);
2418
+ if (options.immediate) {
2419
+ const rect = target.value.getBoundingClientRect();
2420
+ const syntheticEntry = {
2421
+ boundingClientRect: rect,
2422
+ intersectionRatio: 0,
2423
+ intersectionRect: new DOMRect(0, 0, 0, 0),
2424
+ isIntersecting: false,
2425
+ rootBounds: null,
2426
+ target: target.value,
2427
+ time: performance.now()
2428
+ };
2429
+ callback([syntheticEntry]);
2430
+ }
2431
+ }
2432
+ function cleanup() {
2433
+ if (observer.value) {
2434
+ observer.value.disconnect();
2435
+ observer.value = void 0;
2436
+ }
2437
+ }
2438
+ function pause() {
2439
+ isPaused.value = true;
2440
+ observer.value?.disconnect();
2441
+ }
2442
+ function resume() {
2443
+ isPaused.value = false;
2444
+ setup();
2445
+ }
2446
+ function stop() {
2447
+ cleanup();
2448
+ }
2449
+ onUnmounted(stop);
2450
+ return {
2451
+ isIntersecting: readonly(isIntersecting),
2452
+ isPaused: readonly(isPaused),
2453
+ pause,
2454
+ resume,
2455
+ stop
2456
+ };
2457
+ }
2458
+ /**
2459
+ * Convenience composable for simple intersection detection
2460
+ *
2461
+ * @param target - Element ref to observe
2462
+ * @param options - Observer options
2463
+ * @returns Reactive intersection state
2464
+ */
2465
+ function useElementIntersection(target, options = {}) {
2466
+ const isIntersecting = shallowRef(false);
2467
+ const intersectionRatio = shallowRef(0);
2468
+ useIntersectionObserver(target, (entries) => {
2469
+ const entry = entries.at(-1);
2470
+ if (entry) {
2471
+ isIntersecting.value = entry.isIntersecting;
2472
+ intersectionRatio.value = entry.intersectionRatio;
2473
+ }
2474
+ }, {
2475
+ immediate: true,
2476
+ ...options
2477
+ });
2478
+ return {
2479
+ isIntersecting: readonly(isIntersecting),
2480
+ intersectionRatio: readonly(intersectionRatio)
2481
+ };
2482
+ }
2483
+
2197
2484
  //#endregion
2198
2485
  //#region src/composables/useKeydown/index.ts
2199
2486
  /**
@@ -2207,7 +2494,7 @@ function useForm(options) {
2207
2494
  function useKeydown(handlers) {
2208
2495
  const keyHandlers = Array.isArray(handlers) ? handlers : [handlers];
2209
2496
  function onKeydown(event) {
2210
- const handler = keyHandlers.find((h$1) => h$1.key === event.key);
2497
+ const handler = keyHandlers.find((h) => h.key === event.key);
2211
2498
  if (handler) {
2212
2499
  if (handler.preventDefault) event.preventDefault();
2213
2500
  if (handler.stopPropagation) event.stopPropagation();
@@ -2415,6 +2702,134 @@ function createLocalePlugin(options = {}) {
2415
2702
  });
2416
2703
  }
2417
2704
 
2705
+ //#endregion
2706
+ //#region src/composables/useMutationObserver/index.ts
2707
+ /**
2708
+ * Composable for observing DOM mutations
2709
+ *
2710
+ * @param target - Element ref to observe
2711
+ * @param callback - Callback fired on mutation
2712
+ * @param options - Observer options
2713
+ * @returns Observer controls
2714
+ *
2715
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
2716
+ */
2717
+ function useMutationObserver(target, callback, options = {}) {
2718
+ const { isHydrated } = useHydration();
2719
+ const observer = shallowRef();
2720
+ const isPaused = shallowRef(false);
2721
+ const observerOptions = {
2722
+ childList: options.childList ?? true,
2723
+ attributes: options.attributes ?? false,
2724
+ characterData: options.characterData ?? false,
2725
+ subtree: options.subtree ?? false,
2726
+ attributeOldValue: options.attributeOldValue ?? false,
2727
+ characterDataOldValue: options.characterDataOldValue ?? false,
2728
+ attributeFilter: options.attributeFilter
2729
+ };
2730
+ watch([isHydrated, target], ([hydrated, el]) => {
2731
+ cleanup();
2732
+ if (!hydrated || !SUPPORTS_MUTATION_OBSERVER || !el) return;
2733
+ observer.value = new MutationObserver((mutations) => {
2734
+ const transformedEntries = mutations.map((mutation) => ({
2735
+ type: mutation.type,
2736
+ target: mutation.target,
2737
+ addedNodes: mutation.addedNodes,
2738
+ removedNodes: mutation.removedNodes,
2739
+ previousSibling: mutation.previousSibling,
2740
+ nextSibling: mutation.nextSibling,
2741
+ attributeName: mutation.attributeName,
2742
+ attributeNamespace: mutation.attributeNamespace,
2743
+ oldValue: mutation.oldValue
2744
+ }));
2745
+ callback(transformedEntries);
2746
+ });
2747
+ observer.value.observe(el, observerOptions);
2748
+ if (options.immediate) {
2749
+ const emptyNodeList = {
2750
+ length: 0,
2751
+ item: () => null,
2752
+ forEach: () => {},
2753
+ *[Symbol.iterator]() {}
2754
+ };
2755
+ const syntheticEntry = {
2756
+ type: "childList",
2757
+ target: el,
2758
+ addedNodes: emptyNodeList,
2759
+ removedNodes: emptyNodeList,
2760
+ previousSibling: null,
2761
+ nextSibling: null,
2762
+ attributeName: null,
2763
+ attributeNamespace: null,
2764
+ oldValue: null
2765
+ };
2766
+ callback([syntheticEntry]);
2767
+ }
2768
+ }, { immediate: true });
2769
+ function setup() {
2770
+ if (!isHydrated.value || !SUPPORTS_MUTATION_OBSERVER || !target.value || isPaused.value) return;
2771
+ observer.value = new MutationObserver((mutations) => {
2772
+ const transformedEntries = mutations.map((mutation) => ({
2773
+ type: mutation.type,
2774
+ target: mutation.target,
2775
+ addedNodes: mutation.addedNodes,
2776
+ removedNodes: mutation.removedNodes,
2777
+ previousSibling: mutation.previousSibling,
2778
+ nextSibling: mutation.nextSibling,
2779
+ attributeName: mutation.attributeName,
2780
+ attributeNamespace: mutation.attributeNamespace,
2781
+ oldValue: mutation.oldValue
2782
+ }));
2783
+ callback(transformedEntries);
2784
+ });
2785
+ observer.value.observe(target.value, observerOptions);
2786
+ if (options.immediate) {
2787
+ const emptyNodeList = {
2788
+ length: 0,
2789
+ item: () => null,
2790
+ forEach: () => {},
2791
+ *[Symbol.iterator]() {}
2792
+ };
2793
+ const syntheticEntry = {
2794
+ type: "childList",
2795
+ target: target.value,
2796
+ addedNodes: emptyNodeList,
2797
+ removedNodes: emptyNodeList,
2798
+ previousSibling: null,
2799
+ nextSibling: null,
2800
+ attributeName: null,
2801
+ attributeNamespace: null,
2802
+ oldValue: null
2803
+ };
2804
+ callback([syntheticEntry]);
2805
+ }
2806
+ }
2807
+ function cleanup() {
2808
+ if (observer.value) {
2809
+ observer.value.disconnect();
2810
+ observer.value = void 0;
2811
+ }
2812
+ }
2813
+ function pause() {
2814
+ isPaused.value = true;
2815
+ observer.value?.disconnect();
2816
+ }
2817
+ function resume() {
2818
+ isPaused.value = false;
2819
+ setup();
2820
+ }
2821
+ function stop() {
2822
+ cleanup();
2823
+ }
2824
+ onUnmounted(stop);
2825
+ return {
2826
+ isPaused: readonly(isPaused),
2827
+ pause,
2828
+ resume,
2829
+ stop
2830
+ };
2831
+ }
2832
+
2418
2833
  //#endregion
2419
2834
  //#region src/composables/useProxyModel/index.ts
2420
2835
  /**
@@ -2477,6 +2892,126 @@ function useProxyModel(registry, initial, options, _transformIn, _transformOut)
2477
2892
  return model;
2478
2893
  }
2479
2894
 
2895
+ //#endregion
2896
+ //#region src/composables/useResizeObserver/index.ts
2897
+ /**
2898
+ * Composable for observing element resize events
2899
+ *
2900
+ * @param target - Element ref to observe
2901
+ * @param callback - Callback fired on resize
2902
+ * @param options - Observer options
2903
+ * @returns Observer controls
2904
+ *
2905
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver
2906
+ */
2907
+ function useResizeObserver(target, callback, options = {}) {
2908
+ const { isHydrated } = useHydration();
2909
+ const observer = shallowRef();
2910
+ const isPaused = shallowRef(false);
2911
+ watch([isHydrated, target], ([hydrated, el]) => {
2912
+ cleanup();
2913
+ if (!hydrated || !SUPPORTS_OBSERVER || !el) return;
2914
+ observer.value = new ResizeObserver((entries) => {
2915
+ const transformedEntries = entries.map((entry) => ({
2916
+ contentRect: {
2917
+ width: entry.contentRect.width,
2918
+ height: entry.contentRect.height,
2919
+ top: entry.contentRect.top,
2920
+ left: entry.contentRect.left
2921
+ },
2922
+ target: entry.target
2923
+ }));
2924
+ callback(transformedEntries);
2925
+ });
2926
+ observer.value.observe(el, { box: options.box || "content-box" });
2927
+ if (options.immediate) {
2928
+ const rect = el.getBoundingClientRect();
2929
+ callback([{
2930
+ contentRect: {
2931
+ width: rect.width,
2932
+ height: rect.height,
2933
+ top: rect.top,
2934
+ left: rect.left
2935
+ },
2936
+ target: el
2937
+ }]);
2938
+ }
2939
+ });
2940
+ function setup() {
2941
+ if (!isHydrated.value || !SUPPORTS_OBSERVER || !target.value || isPaused.value) return;
2942
+ observer.value = new ResizeObserver((entries) => {
2943
+ const transformedEntries = entries.map((entry) => ({
2944
+ contentRect: {
2945
+ width: entry.contentRect.width,
2946
+ height: entry.contentRect.height,
2947
+ top: entry.contentRect.top,
2948
+ left: entry.contentRect.left
2949
+ },
2950
+ target: entry.target
2951
+ }));
2952
+ callback(transformedEntries);
2953
+ });
2954
+ observer.value.observe(target.value, { box: options.box || "content-box" });
2955
+ if (options.immediate) {
2956
+ const rect = target.value.getBoundingClientRect();
2957
+ callback([{
2958
+ contentRect: {
2959
+ width: rect.width,
2960
+ height: rect.height,
2961
+ top: rect.top,
2962
+ left: rect.left
2963
+ },
2964
+ target: target.value
2965
+ }]);
2966
+ }
2967
+ }
2968
+ function cleanup() {
2969
+ if (observer.value) {
2970
+ observer.value.disconnect();
2971
+ observer.value = void 0;
2972
+ }
2973
+ }
2974
+ function pause() {
2975
+ isPaused.value = true;
2976
+ observer.value?.disconnect();
2977
+ }
2978
+ function resume() {
2979
+ isPaused.value = false;
2980
+ setup();
2981
+ }
2982
+ function stop() {
2983
+ cleanup();
2984
+ }
2985
+ onUnmounted(stop);
2986
+ return {
2987
+ isPaused: readonly(isPaused),
2988
+ pause,
2989
+ resume,
2990
+ stop
2991
+ };
2992
+ }
2993
+ /**
2994
+ * Convenience composable for tracking element dimensions
2995
+ *
2996
+ * @param target - Element ref to observe
2997
+ * @returns Reactive width and height
2998
+ */
2999
+ function useElementSize(target) {
3000
+ const width = shallowRef(0);
3001
+ const height = shallowRef(0);
3002
+ useResizeObserver(target, (entries) => {
3003
+ const entry = entries[0];
3004
+ if (entry) {
3005
+ width.value = entry.contentRect.width;
3006
+ height.value = entry.contentRect.height;
3007
+ }
3008
+ }, { immediate: true });
3009
+ return {
3010
+ width,
3011
+ height
3012
+ };
3013
+ }
3014
+
2480
3015
  //#endregion
2481
3016
  //#region src/composables/useStorage/adapters/memory.ts
2482
3017
  /**
@@ -2585,4 +3120,4 @@ function createStoragePlugin(options = {}) {
2585
3120
  }
2586
3121
 
2587
3122
  //#endregion
2588
- export { Atom_default as Atom, Breakpoints, ConsolaLoggerAdapter, Context, Group, Hydration_default as Hydration, HydrationRoot_default as HydrationRoot, PinoLoggerAdapter, Popover, Step, Theme, Vuetify0LoggerAdapter, createBreakpoints, createBreakpointsPlugin, createContext, createHydration, createHydrationPlugin, createLocale, createLocalePlugin, createLogger, createLoggerPlugin, createPlugin, createStorage, createStoragePlugin, createTheme, createThemePlugin, createTokensContext, createTrinity, genId, isArray, isBoolean, isFunction, isNullOrUndefined, isNumber, isObject, isPrimitive, isString, mergeDeep, provideBreakpointsContext, provideHydrationContext, providePopoverContext, provideStorageContext, run, toArray, toReactive, useBreakpoints, useBreakpointsContext, useContext, useDocumentEventListener, useEventListener, useFilter, useForm, useGroup, useHydration, useHydrationContext, useKeydown, useLayout, useLocale, useLogger, usePopoverContext, useProxyModel, useRegistry, useSelection, useSingle, useStep, useStorage, useStorageContext, useTheme, useTokens, useWindowEventListener };
3123
+ export { Atom_default as Atom, Breakpoints, COMMON_ELEMENTS, ConsolaLoggerAdapter, Context, Group, Hydration_default as Hydration, HydrationRoot_default as HydrationRoot, IN_BROWSER, PinoLoggerAdapter, Popover, SELF_CLOSING_TAGS, SUPPORTS_INTERSECTION_OBSERVER, SUPPORTS_MATCH_MEDIA, SUPPORTS_MUTATION_OBSERVER, SUPPORTS_OBSERVER, SUPPORTS_TOUCH, Step, Theme, Vuetify0LoggerAdapter, __LOGGER_ENABLED__, createBreakpoints, createBreakpointsPlugin, createContext, createHydration, createHydrationPlugin, createLocale, createLocalePlugin, createLogger, createLoggerPlugin, createPlugin, createRegistryContext, createStorage, createStoragePlugin, createTheme, createThemePlugin, createTokensContext, createTrinity, genId, isArray, isBoolean, isFunction, isNullOrUndefined, isNumber, isObject, isPrimitive, isSelfClosingTag, isString, mergeDeep, provideBreakpointsContext, provideHydrationContext, providePopoverContext, provideStorageContext, run, toArray, toReactive, useBreakpoints, useBreakpointsContext, useContext, useDocumentEventListener, useElementIntersection, useElementSize, useEventListener, useFilter, useForm, useGroup, useHydration, useHydrationContext, useIntersectionObserver, useKeydown, useLayout, useLocale, useLogger, useMutationObserver, usePopoverContext, useProxyModel, useRegistry, useResizeObserver, useSelection, useSingle, useStep, useStorage, useStorageContext, useTheme, useTokens, useWindowEventListener, version };