rei-kit 0.12.1 → 0.14.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/dist/index.js CHANGED
@@ -1,158 +1,11 @@
1
+ import { a as addDays, c as lastNDays, d as toDateKey, f as todayKey, i as needsIosInstall, l as leadingBlanks, n as isApplePortable, o as eachDayOfYear, r as isInstalled, s as fromDateKey, t as SettingsGroup_default, u as startOfWeek } from "./SettingsGroup-DtEB_Hrd.js";
1
2
  import { n as registerErrorMapper, r as toAppError, t as AppError } from "./app-error-DF9cijE0.js";
2
- import { Fragment, Teleport, Transition, TransitionGroup, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createStaticVNode, createTextVNode, createVNode, defineComponent, mergeModels, mergeProps, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onErrorCaptured, onMounted, onScopeDispose, onUnmounted, openBlock, readonly, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, useId, useModel, vModelCheckbox, vModelDynamic, vModelRadio, vModelSelect, vModelText, watch, watchEffect, withCtx, withDirectives } from "vue";
3
- import { ArrowDown, ArrowRight, ArrowUp, CheckCircle2, ChevronDown, ChevronRight, Info, TriangleAlert, X, XCircle } from "lucide-vue-next";
3
+ import { a as readStoredTheme, i as isThemePreference, n as useVisualViewport, o as setThemeStorageKey, r as applyTheme, s as useTheme, t as BaseSheet_default } from "./BaseSheet-CLIhXDwe.js";
4
+ import { n as _plugin_vue_export_helper_default, r as BaseButton_default, t as SettingsRow_default } from "./SettingsRow-MnVleeTR.js";
5
+ import { Fragment, Teleport, TransitionGroup, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createStaticVNode, createTextVNode, createVNode, defineComponent, mergeModels, mergeProps, normalizeClass, normalizeStyle, onBeforeUnmount, onErrorCaptured, onMounted, onScopeDispose, onUnmounted, openBlock, readonly, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, useId, useModel, vModelCheckbox, vModelDynamic, vModelRadio, vModelSelect, vModelText, watch, watchEffect, withCtx, withDirectives } from "vue";
6
+ import { ArrowDown, ArrowRight, ArrowUp, CheckCircle2, ChevronDown, Info, TriangleAlert, X, XCircle } from "lucide-vue-next";
4
7
  import { RouterLink } from "vue-router";
5
8
  import { createI18n } from "vue-i18n";
6
- //#region src/utils/date.ts
7
- /**
8
- * Local calendar-day helpers.
9
- *
10
- * Every function is pure and works on `YYYY-MM-DD` keys, the same shape as the
11
- * `date` columns in Postgres. Nothing here calls `toISOString`: that converts to
12
- * UTC, so in a UTC+9 timezone every entry made between midnight and 09:00 would
13
- * be written to the previous day.
14
- */
15
- /**
16
- * Formats a `Date` as a local `YYYY-MM-DD` key.
17
- *
18
- * @param date - Any `Date`; only its local year, month and day are read.
19
- * @returns The calendar day in the runtime's own timezone.
20
- *
21
- * @example
22
- * ```ts
23
- * // 2026-08-23 01:30 in Tokyo
24
- * toDateKey(new Date()) // '2026-08-23'
25
- * new Date().toISOString() // '2026-08-22T16:30…' ← the bug
26
- * ```
27
- */
28
- function toDateKey(date) {
29
- return `${String(date.getFullYear()).padStart(4, "0")}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
30
- }
31
- /** Today's key in the user's own timezone. */
32
- function todayKey() {
33
- return toDateKey(/* @__PURE__ */ new Date());
34
- }
35
- /**
36
- * Parses a `YYYY-MM-DD` key into a `Date` at local midnight.
37
- *
38
- * @param key - A key produced by {@link toDateKey}.
39
- * @returns Local midnight of that calendar day.
40
- * @throws If the key is not three numeric parts.
41
- *
42
- * @example
43
- * ```ts
44
- * fromDateKey('2026-08-23') // local midnight, correct
45
- * new Date('2026-08-23') // UTC midnight — shifts a day in some zones
46
- * ```
47
- */
48
- function fromDateKey(key) {
49
- const [year, month, day] = key.split("-").map(Number);
50
- if (year === void 0 || month === void 0 || day === void 0) throw new Error(`Invalid date key: ${key}`);
51
- return new Date(year, month - 1, day);
52
- }
53
- /**
54
- * Shifts a date key by whole calendar days.
55
- *
56
- * Uses `setDate`, which is calendar-aware: it rolls over month and year ends,
57
- * and stays correct across daylight-saving transitions. Adding
58
- * `days * 86_400_000` milliseconds would not — a DST day is 23 or 25 hours long.
59
- *
60
- * @param key - Starting `YYYY-MM-DD` key.
61
- * @param days - Days to add; negative goes back.
62
- * @returns The resulting key.
63
- *
64
- * @example
65
- * ```ts
66
- * addDays('2026-01-31', 1) // '2026-02-01'
67
- * addDays('2026-01-01', -1) // '2025-12-31'
68
- * addDays('2028-02-28', 1) // '2028-02-29' — leap year
69
- * ```
70
- */
71
- function addDays(key, days) {
72
- const date = fromDateKey(key);
73
- date.setDate(date.getDate() + days);
74
- return toDateKey(date);
75
- }
76
- /**
77
- * The last `count` days ending today, oldest first.
78
- *
79
- * `today` is a parameter so the function stays pure and testable; call sites
80
- * normally omit it.
81
- *
82
- * @param count - How many days to return, including `today`.
83
- * @param today - End of the range. Defaults to the real today.
84
- * @returns Keys in ascending order.
85
- *
86
- * @example
87
- * ```ts
88
- * lastNDays(3, '2026-08-23') // ['2026-08-21', '2026-08-22', '2026-08-23']
89
- * ```
90
- */
91
- function lastNDays(count, today = todayKey()) {
92
- const keys = [];
93
- for (let offset = count - 1; offset >= 0; offset -= 1) keys.push(addDays(today, -offset));
94
- return keys;
95
- }
96
- /**
97
- * The first day of the week containing `key`.
98
- *
99
- * The user's preference is a parameter, not a module-level setting: changing it
100
- * in Profile has to re-render the week grid and the year heatmap immediately,
101
- * and a global would make that a hidden dependency.
102
- *
103
- * @param key - Any day in the week.
104
- * @param weekStartsOn - 0 for Sunday, 1 for Monday.
105
- * @returns Key of that week's first day.
106
- *
107
- * @example
108
- * ```ts
109
- * // 2026-08-23 is a Sunday
110
- * startOfWeek('2026-08-23', 1) // '2026-08-17' — previous Monday
111
- * startOfWeek('2026-08-23', 0) // '2026-08-23' — already Sunday
112
- * ```
113
- */
114
- function startOfWeek(key, weekStartsOn) {
115
- return addDays(key, -((fromDateKey(key).getDay() - weekStartsOn + 7) % 7));
116
- }
117
- /**
118
- * Every day of a calendar year, in order.
119
- *
120
- * Leap years fall out of the loop for free: it walks day by day until the year
121
- * rolls over, so February 29 is included when it exists.
122
- *
123
- * @param year - Four-digit year.
124
- * @returns 365 or 366 keys, oldest first.
125
- */
126
- function eachDayOfYear(year) {
127
- const keys = [];
128
- const date = new Date(year, 0, 1);
129
- while (date.getFullYear() === year) {
130
- keys.push(toDateKey(date));
131
- date.setDate(date.getDate() + 1);
132
- }
133
- return keys;
134
- }
135
- /**
136
- * Empty cells before a block's first day in a seven-row column grid.
137
- *
138
- * The grid fills column by column, so the first column is only partly used
139
- * unless the block starts exactly on the week's first day. An off-by-one here
140
- * shifts the whole block by a row, so this is unit tested.
141
- *
142
- * @param firstDayKey - First day of the block, e.g. `'2026-02-01'`.
143
- * @param weekStartsOn - 0 for Sunday, 1 for Monday.
144
- * @returns 0-6 blank cells.
145
- *
146
- * @example
147
- * ```ts
148
- * leadingBlanks('2026-01-01', 1) // 3 — a Thursday, Mon-Wed are blank
149
- * leadingBlanks('2024-01-01', 1) // 0 — a Monday
150
- * ```
151
- */
152
- function leadingBlanks(firstDayKey, weekStartsOn) {
153
- return (fromDateKey(firstDayKey).getDay() - weekStartsOn + 7) % 7;
154
- }
155
- //#endregion
156
9
  //#region src/utils/format.ts
157
10
  /**
158
11
  * The locale `Intl` formatting uses.
@@ -300,129 +153,6 @@ function tapFeedback(duration = 10) {
300
153
  navigator.vibrate?.(duration);
301
154
  }
302
155
  //#endregion
303
- //#region src/utils/platform.ts
304
- /**
305
- * Whether the app is running from the Home Screen rather than a browser tab.
306
- *
307
- * Two checks because iOS predates the standard one: `display-mode: standalone`
308
- * is the modern signal, `navigator.standalone` is Safari's own.
309
- */
310
- function isInstalled() {
311
- if (typeof window === "undefined") return false;
312
- return window.matchMedia("(display-mode: standalone)").matches || navigator.standalone === true;
313
- }
314
- /** iPhone and iPad, including iPadOS reporting itself as a Mac. */
315
- function isApplePortable() {
316
- if (typeof window === "undefined") return false;
317
- return /iPad|iPhone|iPod/.test(navigator.userAgent) || navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1;
318
- }
319
- /**
320
- * Whether this device can only receive notifications once the app is installed.
321
- *
322
- * Safari on iOS grants notification permission to an installed web app and to
323
- * nothing else — in a normal tab the request does not even prompt. Telling the
324
- * user to allow notifications there is asking for something the browser will
325
- * not offer, so the UI has to say "add to Home Screen" instead.
326
- *
327
- * @example
328
- * ```ts
329
- * if (needsIosInstall()) // show the Home Screen instruction, not the button
330
- * ```
331
- */
332
- function needsIosInstall() {
333
- return isApplePortable() && !isInstalled();
334
- }
335
- //#endregion
336
- //#region src/composables/use-theme.ts
337
- /**
338
- * Namespaced by the app, not by this package.
339
- *
340
- * Two rei-kit apps served from the same origin would otherwise share one theme
341
- * setting — and during development on localhost, they will be.
342
- */
343
- var storageKey = "rei-theme";
344
- function isThemePreference(value) {
345
- return value === "system" || value === "light" || value === "dark";
346
- }
347
- /** Reads the stored preference, falling back to `system`. */
348
- function readStoredTheme() {
349
- try {
350
- const stored = localStorage.getItem(storageKey);
351
- return isThemePreference(stored) ? stored : "system";
352
- } catch {
353
- return "system";
354
- }
355
- }
356
- function storeTheme(preference) {
357
- try {
358
- localStorage.setItem(storageKey, preference);
359
- } catch {}
360
- }
361
- /**
362
- * Does the environment prefer a dark scheme?
363
- *
364
- * `matchMedia` is checked for on its own rather than inferred from `document`.
365
- * Having one does not imply having the other: jsdom supplies a document and no
366
- * `matchMedia`, so a consumer's component test that so much as mounts something
367
- * calling `useTheme` threw — and some embedded webviews are the same. Where
368
- * there is nothing to ask, the answer is no rather than an exception.
369
- */
370
- function prefersDarkScheme() {
371
- return typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(prefers-color-scheme: dark)").matches : false;
372
- }
373
- /**
374
- * Adds or removes `.dark` on `<html>`, resolving `system` against the OS.
375
- *
376
- * A no-op without a document. There is no OS preference to read on a server and
377
- * no `<html>` to write to, so a prerender leaves the class off and the app
378
- * decides the theme before hydration — see the note in the README.
379
- */
380
- function applyTheme(preference) {
381
- if (typeof document === "undefined") return;
382
- const isDark = preference === "dark" || preference === "system" && prefersDarkScheme();
383
- document.documentElement.classList.toggle("dark", isDark);
384
- }
385
- /**
386
- * The shared preference, created on first use rather than at import.
387
- *
388
- * Lazy on purpose: reading storage at import time would lock in the default key
389
- * before an app had a chance to set its own, leaving the controller reading one
390
- * key and writing another.
391
- */
392
- var preference = null;
393
- function controller() {
394
- if (preference) return preference;
395
- preference = ref(readStoredTheme());
396
- watch(preference, (next) => {
397
- storeTheme(next);
398
- applyTheme(next);
399
- }, { immediate: true });
400
- if (typeof window !== "undefined" && typeof window.matchMedia === "function") window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => {
401
- if (preference?.value === "system") applyTheme("system");
402
- });
403
- return preference;
404
- }
405
- /**
406
- * Sets where the preference is stored.
407
- *
408
- * Safe in either order: called before the first `useTheme()` it simply changes
409
- * the key, and called after it re-reads under the new one, so the controller
410
- * never reads from one key while writing to another.
411
- *
412
- * @example
413
- * ```ts
414
- * setThemeStorageKey('hibi-theme') // once, at startup
415
- * ```
416
- */
417
- function setThemeStorageKey(key) {
418
- storageKey = key;
419
- if (preference) preference.value = readStoredTheme();
420
- }
421
- /** @returns The shared preference ref; assigning to it stores and applies it. */
422
- function useTheme() {
423
- return controller();
424
- }
425
- //#endregion
426
156
  //#region src/composables/use-today.ts
427
157
  /**
428
158
  * Today's date key, kept current while the app stays open.
@@ -686,47 +416,6 @@ function useMediaQuery(query) {
686
416
  return matches;
687
417
  }
688
418
  //#endregion
689
- //#region src/composables/use-visual-viewport.ts
690
- /**
691
- * Tracks the visual viewport.
692
- *
693
- * Chrome and Android browsers honour `interactive-widget=resizes-content`, so
694
- * the layout viewport already shrinks for the keyboard there. Safari on iOS
695
- * does not implement it: it shrinks only the *visual* viewport, leaving a sheet
696
- * sized in `dvh` sitting partly underneath the keyboard.
697
- *
698
- * `null` means the API is unavailable, which callers should read as "trust the
699
- * layout viewport" rather than as zero. A server has no viewport at all, so it
700
- * gets that same `null` — this runs during `setup`, and a component using it
701
- * has to survive being rendered there.
702
- *
703
- * @example
704
- * ```ts
705
- * const viewport = useVisualViewport()
706
- * // :style="viewport ? { height: `${viewport.height}px` } : undefined"
707
- * ```
708
- */
709
- function useVisualViewport() {
710
- const rect = ref(null);
711
- const viewport = typeof window === "undefined" ? void 0 : window.visualViewport;
712
- if (!viewport) return readonly(rect);
713
- function read() {
714
- if (!viewport) return;
715
- rect.value = {
716
- height: viewport.height,
717
- offsetTop: viewport.offsetTop
718
- };
719
- }
720
- read();
721
- viewport.addEventListener("resize", read);
722
- viewport.addEventListener("scroll", read);
723
- onScopeDispose(() => {
724
- viewport.removeEventListener("resize", read);
725
- viewport.removeEventListener("scroll", read);
726
- });
727
- return readonly(rect);
728
- }
729
- //#endregion
730
419
  //#region src/composables/use-toast.ts
731
420
  /**
732
421
  * Four seconds: long enough to read a short sentence twice, short enough that
@@ -838,9 +527,9 @@ function useToast() {
838
527
  }
839
528
  //#endregion
840
529
  //#region src/components/BaseAlert.vue?vue&type=script&setup=true&lang.ts
841
- var _hoisted_1$22 = ["role", "aria-live"];
842
- var _hoisted_2$16 = { class: "min-w-0 flex-1" };
843
- var _hoisted_3$11 = {
530
+ var _hoisted_1$18 = ["role", "aria-live"];
531
+ var _hoisted_2$13 = { class: "min-w-0 flex-1" };
532
+ var _hoisted_3$8 = {
844
533
  key: 0,
845
534
  class: "text-ink font-semibold"
846
535
  };
@@ -881,9 +570,9 @@ var BaseAlert_default = /* @__PURE__ */ defineComponent({
881
570
  class: normalizeClass(["mt-px grid size-6 shrink-0 place-items-center rounded-full text-xs font-semibold", mark.value]),
882
571
  "aria-hidden": "true"
883
572
  }, [renderSlot(_ctx.$slots, "mark")], 2)) : createCommentVNode("", true),
884
- createElementVNode("div", _hoisted_2$16, [_ctx.$slots.title ? (openBlock(), createElementBlock("p", _hoisted_3$11, [renderSlot(_ctx.$slots, "title")])) : createCommentVNode("", true), createElementVNode("div", { class: normalizeClass(_ctx.$slots.title ? "mt-1" : "") }, [renderSlot(_ctx.$slots, "default")], 2)]),
573
+ createElementVNode("div", _hoisted_2$13, [_ctx.$slots.title ? (openBlock(), createElementBlock("p", _hoisted_3$8, [renderSlot(_ctx.$slots, "title")])) : createCommentVNode("", true), createElementVNode("div", { class: normalizeClass(_ctx.$slots.title ? "mt-1" : "") }, [renderSlot(_ctx.$slots, "default")], 2)]),
885
574
  renderSlot(_ctx.$slots, "action")
886
- ], 10, _hoisted_1$22);
575
+ ], 10, _hoisted_1$18);
887
576
  };
888
577
  }
889
578
  });
@@ -907,153 +596,8 @@ var BaseBadge_default = /* @__PURE__ */ defineComponent({
907
596
  }
908
597
  });
909
598
  //#endregion
910
- //#region src/components/BaseButton.vue?vue&type=script&setup=true&lang.ts
911
- var _hoisted_1$21 = {
912
- key: 0,
913
- class: "size-4 animate-spin rounded-full border-2 border-current border-t-transparent",
914
- "aria-hidden": "true"
915
- };
916
- //#endregion
917
- //#region src/components/BaseButton.vue
918
- var BaseButton_default = /* @__PURE__ */ defineComponent({
919
- __name: "BaseButton",
920
- props: {
921
- as: { default: "button" },
922
- variant: { default: "primary" },
923
- size: { default: "md" },
924
- loading: {
925
- type: Boolean,
926
- default: false
927
- },
928
- disabled: {
929
- type: Boolean,
930
- default: false
931
- },
932
- type: { default: "button" },
933
- icon: {
934
- type: Boolean,
935
- default: false
936
- },
937
- block: {
938
- type: Boolean,
939
- default: false
940
- },
941
- to: { default: () => void 0 },
942
- href: { default: () => void 0 },
943
- pill: {
944
- type: Boolean,
945
- default: false
946
- },
947
- pressed: {
948
- type: Boolean,
949
- default: () => void 0
950
- }
951
- },
952
- setup(__props) {
953
- const VARIANT_CLASS = {
954
- primary: "bg-primary text-white hover:bg-primary/90",
955
- secondary: "border-hair bg-surface text-ink border hover:bg-muted",
956
- ghost: "bg-transparent text-ink hover:bg-muted",
957
- destructive: "bg-transparent text-ink-soft hover:text-negative",
958
- row: "w-full justify-start text-left bg-transparent text-ink hover:bg-muted",
959
- quiet: "bg-transparent text-ink-soft hover:bg-muted hover:text-ink",
960
- danger: "bg-negative text-white hover:bg-negative/90",
961
- positive: "bg-positive text-white hover:bg-positive/90",
962
- warning: "bg-warning text-white hover:bg-warning/90",
963
- accent: "bg-accent text-white hover:bg-accent/90",
964
- link: "bg-transparent underline underline-offset-2 hover:opacity-80",
965
- unstyled: ""
966
- };
967
- const SIZE_CLASS = {
968
- xs: "h-8 px-3 text-xs",
969
- sm: "h-9 px-3 text-sm",
970
- md: "h-11 px-4 text-base",
971
- lg: "h-14 px-6 text-lg"
972
- };
973
- const ICON_SIZE_CLASS = {
974
- xs: "size-8 text-xs",
975
- sm: "size-9 text-sm",
976
- md: "size-11 text-base",
977
- lg: "size-14 text-lg"
978
- };
979
- const ROW_SIZE_CLASS = {
980
- xs: "px-2 py-1.5 text-xs",
981
- sm: "px-3 py-2 text-sm",
982
- md: "px-3 py-2.5 text-base",
983
- lg: "px-4 py-3 text-lg"
984
- };
985
- const LINK_SIZE_CLASS = {
986
- xs: "text-xs",
987
- sm: "text-sm",
988
- md: "text-base",
989
- lg: "text-lg"
990
- };
991
- const sizing = computed(() => {
992
- if (__props.variant === "unstyled") return "";
993
- if (__props.variant === "link") return LINK_SIZE_CLASS[__props.size];
994
- if (__props.variant === "row") return ROW_SIZE_CLASS[__props.size];
995
- return __props.icon ? ICON_SIZE_CLASS[__props.size] : SIZE_CLASS[__props.size];
996
- });
997
- const PRESSED_CLASS = {
998
- ghost: "bg-primary text-white hover:bg-primary/90",
999
- quiet: "bg-primary text-white hover:bg-primary/90",
1000
- secondary: "bg-primary border-primary text-white hover:bg-primary/90",
1001
- row: "w-full justify-start text-left bg-muted text-ink hover:bg-muted"
1002
- };
1003
- const surface = computed(() => {
1004
- if (__props.pressed === true) return PRESSED_CLASS[__props.variant] ?? VARIANT_CLASS[__props.variant];
1005
- if (__props.variant === "destructive") return `${VARIANT_CLASS.destructive} hover:bg-negative/10`;
1006
- return VARIANT_CLASS[__props.variant];
1007
- });
1008
- const shell = computed(() => {
1009
- if (__props.variant === "unstyled") return "";
1010
- const feel = "transition-[transform,color,background-color,border-color] duration-100 select-none";
1011
- if (__props.variant === "row") return `inline-flex items-center gap-2 font-medium ${feel}`;
1012
- return `inline-flex items-center justify-center gap-2 font-medium ${feel} active:scale-95`;
1013
- });
1014
- const radius = computed(() => {
1015
- if (__props.variant === "unstyled") return "";
1016
- if (__props.variant === "link") return "rounded-xs";
1017
- return __props.pill ? "rounded-full" : "rounded-card";
1018
- });
1019
- /** Anything that is not a `<button>` cannot be `disabled`; it has to be told. */
1020
- const inactive = computed(() => __props.disabled || __props.loading);
1021
- const linkProps = computed(() => {
1022
- if (__props.as === "router-link") return { to: __props.to };
1023
- if (__props.as === "a") return inactive.value ? {} : { href: __props.href };
1024
- return {};
1025
- });
1026
- return (_ctx, _cache) => {
1027
- return openBlock(), createBlock(resolveDynamicComponent(__props.as), mergeProps(linkProps.value, {
1028
- type: __props.as === "button" ? __props.type : void 0,
1029
- disabled: __props.as === "button" ? inactive.value : void 0,
1030
- "aria-disabled": __props.as !== "button" && inactive.value ? "true" : void 0,
1031
- "aria-busy": __props.loading,
1032
- "aria-pressed": __props.pressed === void 0 ? void 0 : String(__props.pressed),
1033
- class: ["focus-visible:outline-primary focus-visible:outline-2 focus-visible:outline-offset-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50", [
1034
- shell.value,
1035
- surface.value,
1036
- sizing.value,
1037
- radius.value,
1038
- __props.block ? "w-full" : ""
1039
- ]]
1040
- }), {
1041
- default: withCtx(() => [__props.loading ? (openBlock(), createElementBlock("span", _hoisted_1$21)) : createCommentVNode("", true), renderSlot(_ctx.$slots, "default")]),
1042
- _: 3
1043
- }, 16, [
1044
- "type",
1045
- "disabled",
1046
- "aria-disabled",
1047
- "aria-busy",
1048
- "aria-pressed",
1049
- "class"
1050
- ]);
1051
- };
1052
- }
1053
- });
1054
- //#endregion
1055
599
  //#region src/components/FormField.vue?vue&type=script&setup=true&lang.ts
1056
- var _hoisted_1$20 = ["for"];
600
+ var _hoisted_1$17 = ["for"];
1057
601
  //#endregion
1058
602
  //#region src/components/FormField.vue
1059
603
  var FormField_default = /* @__PURE__ */ defineComponent({
@@ -1081,7 +625,7 @@ var FormField_default = /* @__PURE__ */ defineComponent({
1081
625
  createElementVNode("label", {
1082
626
  for: unref(id),
1083
627
  class: normalizeClass(["font-medium", [__props.labelHidden ? "sr-only" : "", __props.size === "sm" ? "text-ink-soft text-xs" : "text-ink text-sm"]])
1084
- }, toDisplayString(__props.label), 11, _hoisted_1$20),
628
+ }, toDisplayString(__props.label), 11, _hoisted_1$17),
1085
629
  renderSlot(_ctx.$slots, "default", {
1086
630
  id: unref(id),
1087
631
  describedBy: describedBy.value,
@@ -1103,7 +647,7 @@ var FormField_default = /* @__PURE__ */ defineComponent({
1103
647
  });
1104
648
  //#endregion
1105
649
  //#region src/components/BaseInput.vue?vue&type=script&setup=true&lang.ts
1106
- var _hoisted_1$19 = [
650
+ var _hoisted_1$16 = [
1107
651
  "id",
1108
652
  "type",
1109
653
  "aria-invalid",
@@ -1151,7 +695,7 @@ var BaseInput_default = /* @__PURE__ */ defineComponent({
1151
695
  __props.variant === "unstyled" ? "" : "border-hair bg-surface text-ink rounded-card focus-visible:outline-primary border px-3 focus-visible:outline-2 focus-visible:outline-offset-1",
1152
696
  __props.variant === "unstyled" ? "text-base" : CONTROL_CLASS,
1153
697
  __props.variant !== "unstyled" && invalid ? "border-negative" : ""
1154
- ] }), null, 16, _hoisted_1$19), [[vModelDynamic, model.value]])]),
698
+ ] }), null, 16, _hoisted_1$16), [[vModelDynamic, model.value]])]),
1155
699
  _: 1
1156
700
  }, 8, [
1157
701
  "label",
@@ -1164,130 +708,6 @@ var BaseInput_default = /* @__PURE__ */ defineComponent({
1164
708
  }
1165
709
  });
1166
710
  //#endregion
1167
- //#region src/components/BaseSheet.vue?vue&type=script&setup=true&lang.ts
1168
- var _hoisted_1$18 = { class: "shell-frame md:rounded-shell relative flex max-h-full flex-col justify-end overflow-hidden" };
1169
- var _hoisted_2$15 = ["aria-label"];
1170
- var _hoisted_3$10 = { class: "flex shrink-0 items-start gap-3 px-6 pt-4 pb-5" };
1171
- var _hoisted_4$7 = { class: "min-w-0 flex-1" };
1172
- var _hoisted_5$4 = { class: "text-ink text-xl leading-tight font-semibold" };
1173
- var _hoisted_6$2 = {
1174
- key: 0,
1175
- class: "text-ink-soft mt-1 text-sm leading-snug"
1176
- };
1177
- var _hoisted_7$2 = { class: "min-h-0 flex-1 overflow-y-auto px-6 pb-[calc(2rem+env(safe-area-inset-bottom,0px))]" };
1178
- var BaseSheet_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
1179
- __name: "BaseSheet",
1180
- props: /*@__PURE__*/ mergeModels({
1181
- title: {},
1182
- subtitle: { default: "" },
1183
- closeLabel: { default: "Close" }
1184
- }, {
1185
- "modelValue": {
1186
- type: Boolean,
1187
- required: true
1188
- },
1189
- "modelModifiers": {}
1190
- }),
1191
- emits: ["update:modelValue"],
1192
- setup(__props) {
1193
- const open = useModel(__props, "modelValue");
1194
- const viewport = useVisualViewport();
1195
- /**
1196
- * Pins the sheet to the area the keyboard has left visible.
1197
- *
1198
- * Only needed where the layout viewport does not shrink on its own — iOS. On
1199
- * Android the numbers already agree, so this is a no-op there rather than a
1200
- * second, competing adjustment.
1201
- */
1202
- const viewportStyle = computed(() => viewport.value ? {
1203
- height: `${viewport.value.height}px`,
1204
- top: `${viewport.value.offsetTop}px`
1205
- } : void 0);
1206
- const panel = ref(null);
1207
- let lastFocused = null;
1208
- function close() {
1209
- open.value = false;
1210
- }
1211
- function onKeydown(event) {
1212
- if (event.key === "Escape") close();
1213
- }
1214
- watch(open, async (isOpen) => {
1215
- if (isOpen) {
1216
- setBackgroundInert(true);
1217
- lastFocused = document.activeElement instanceof HTMLElement ? document.activeElement : null;
1218
- window.addEventListener("keydown", onKeydown);
1219
- await nextTick();
1220
- panel.value?.focus();
1221
- } else {
1222
- window.removeEventListener("keydown", onKeydown);
1223
- lastFocused?.focus();
1224
- lastFocused = null;
1225
- setBackgroundInert(false);
1226
- }
1227
- });
1228
- /**
1229
- * `inert` takes the whole app out of tab order and pointer events while the
1230
- * sheet is open — a real focus trap without keydown bookkeeping.
1231
- *
1232
- * The sheet itself is teleported to `#sheet-root`, a sibling of `#app`, so it
1233
- * stays interactive.
1234
- */
1235
- function setBackgroundInert(isInert) {
1236
- document.getElementById("app")?.toggleAttribute("inert", isInert);
1237
- }
1238
- onUnmounted(() => {
1239
- window.removeEventListener("keydown", onKeydown);
1240
- setBackgroundInert(false);
1241
- });
1242
- return (_ctx, _cache) => {
1243
- return openBlock(), createBlock(Teleport, { to: "#sheet-root" }, [createVNode(Transition, { name: "sheet" }, {
1244
- default: withCtx(() => [open.value ? (openBlock(), createElementBlock("div", {
1245
- key: 0,
1246
- class: "fixed inset-x-0 top-0 bottom-0 z-50 flex items-center justify-center",
1247
- style: normalizeStyle(viewportStyle.value)
1248
- }, [createElementVNode("div", _hoisted_1$18, [createElementVNode("div", {
1249
- class: "bg-ink/45 absolute inset-0 backdrop-blur-[2px]",
1250
- onClick: close
1251
- }), createElementVNode("section", {
1252
- ref_key: "panel",
1253
- ref: panel,
1254
- role: "dialog",
1255
- "aria-modal": "true",
1256
- "aria-label": __props.title,
1257
- tabindex: "-1",
1258
- class: "sheet-panel bg-surface relative flex max-h-[94%] min-h-[56dvh] flex-col rounded-t-[28px] shadow-2xl outline-none"
1259
- }, [
1260
- _cache[0] || (_cache[0] = createElementVNode("div", {
1261
- class: "flex shrink-0 justify-center pt-3",
1262
- "aria-hidden": "true"
1263
- }, [createElementVNode("span", { class: "bg-hair h-1.5 w-10 rounded-full" })], -1)),
1264
- createElementVNode("header", _hoisted_3$10, [createElementVNode("div", _hoisted_4$7, [createElementVNode("h2", _hoisted_5$4, toDisplayString(__props.title), 1), __props.subtitle ? (openBlock(), createElementBlock("p", _hoisted_6$2, toDisplayString(__props.subtitle), 1)) : createCommentVNode("", true)]), createVNode(BaseButton_default, {
1265
- variant: "unstyled",
1266
- class: "text-ink-soft hover:bg-muted hover:text-ink -mt-1 flex size-10 shrink-0 items-center justify-center rounded-full transition-colors active:scale-90",
1267
- "aria-label": __props.closeLabel,
1268
- onClick: close
1269
- }, {
1270
- default: withCtx(() => [createVNode(unref(X), { class: "size-5" })]),
1271
- _: 1
1272
- }, 8, ["aria-label"])]),
1273
- createElementVNode("div", _hoisted_7$2, [renderSlot(_ctx.$slots, "default", {}, void 0, true)])
1274
- ], 8, _hoisted_2$15)])], 4)) : createCommentVNode("", true)]),
1275
- _: 3
1276
- })]);
1277
- };
1278
- }
1279
- });
1280
- //#endregion
1281
- //#region \0plugin-vue:export-helper
1282
- var _plugin_vue_export_helper_default = (sfc, props) => {
1283
- const target = sfc.__vccOpts || sfc;
1284
- for (const [key, val] of props) target[key] = val;
1285
- return target;
1286
- };
1287
- //#endregion
1288
- //#region src/components/BaseSheet.vue
1289
- var BaseSheet_default = /*#__PURE__*/ _plugin_vue_export_helper_default(BaseSheet_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-51709579"]]);
1290
- //#endregion
1291
711
  //#region src/components/BaseCard.vue
1292
712
  var BaseCard_default = /* @__PURE__ */ defineComponent({
1293
713
  __name: "BaseCard",
@@ -1354,9 +774,9 @@ var BaseCard_default = /* @__PURE__ */ defineComponent({
1354
774
  });
1355
775
  //#endregion
1356
776
  //#region src/components/BaseCheckbox.vue?vue&type=script&setup=true&lang.ts
1357
- var _hoisted_1$17 = { class: "flex flex-col gap-1.5" };
1358
- var _hoisted_2$14 = ["for"];
1359
- var _hoisted_3$9 = [
777
+ var _hoisted_1$15 = { class: "flex flex-col gap-1.5" };
778
+ var _hoisted_2$12 = ["for"];
779
+ var _hoisted_3$7 = [
1360
780
  "id",
1361
781
  "disabled",
1362
782
  "aria-invalid",
@@ -1393,7 +813,7 @@ var BaseCheckbox_default = /* @__PURE__ */ defineComponent({
1393
813
  if (__props.hint) return hintId;
1394
814
  });
1395
815
  return (_ctx, _cache) => {
1396
- return openBlock(), createElementBlock("div", _hoisted_1$17, [createElementVNode("label", {
816
+ return openBlock(), createElementBlock("div", _hoisted_1$15, [createElementVNode("label", {
1397
817
  for: unref(id),
1398
818
  class: normalizeClass(["flex items-center", [__props.size === "sm" ? "gap-2" : "gap-3", __props.disabled ? "opacity-50" : "cursor-pointer"]])
1399
819
  }, [withDirectives(createElementVNode("input", {
@@ -1404,7 +824,7 @@ var BaseCheckbox_default = /* @__PURE__ */ defineComponent({
1404
824
  "aria-invalid": Boolean(__props.error),
1405
825
  "aria-describedby": describedBy.value,
1406
826
  class: "accent-primary focus-visible:outline-primary size-4 shrink-0 focus-visible:outline-2 focus-visible:outline-offset-2"
1407
- }, null, 8, _hoisted_3$9), [[vModelCheckbox, model.value]]), createElementVNode("span", { class: normalizeClass(["text-sm", __props.size === "sm" ? "text-ink-soft" : "text-ink"]) }, toDisplayString(__props.label), 3)], 10, _hoisted_2$14), __props.error ? (openBlock(), createElementBlock("p", {
827
+ }, null, 8, _hoisted_3$7), [[vModelCheckbox, model.value]]), createElementVNode("span", { class: normalizeClass(["text-sm", __props.size === "sm" ? "text-ink-soft" : "text-ink"]) }, toDisplayString(__props.label), 3)], 10, _hoisted_2$12), __props.error ? (openBlock(), createElementBlock("p", {
1408
828
  key: 0,
1409
829
  id: errorId,
1410
830
  class: "text-negative text-xs"
@@ -1418,13 +838,13 @@ var BaseCheckbox_default = /* @__PURE__ */ defineComponent({
1418
838
  });
1419
839
  //#endregion
1420
840
  //#region src/components/BaseRadioGroup.vue?vue&type=script&setup=true&lang.ts
1421
- var _hoisted_1$16 = ["aria-describedby"];
1422
- var _hoisted_2$13 = [
841
+ var _hoisted_1$14 = ["aria-describedby"];
842
+ var _hoisted_2$11 = [
1423
843
  "name",
1424
844
  "value",
1425
845
  "disabled"
1426
846
  ];
1427
- var _hoisted_3$8 = { class: "text-ink text-sm" };
847
+ var _hoisted_3$6 = { class: "text-ink text-sm" };
1428
848
  //#endregion
1429
849
  //#region src/components/BaseRadioGroup.vue
1430
850
  var BaseRadioGroup_default = /* @__PURE__ */ defineComponent({
@@ -1469,7 +889,7 @@ var BaseRadioGroup_default = /* @__PURE__ */ defineComponent({
1469
889
  value: option.value,
1470
890
  disabled: option.disabled,
1471
891
  class: "accent-primary focus-visible:outline-primary size-4 shrink-0 focus-visible:outline-2 focus-visible:outline-offset-2"
1472
- }, null, 8, _hoisted_2$13), [[vModelRadio, model.value]]), createElementVNode("span", _hoisted_3$8, toDisplayString(option.label), 1)], 2);
892
+ }, null, 8, _hoisted_2$11), [[vModelRadio, model.value]]), createElementVNode("span", _hoisted_3$6, toDisplayString(option.label), 1)], 2);
1473
893
  }), 128)),
1474
894
  __props.error ? (openBlock(), createElementBlock("p", {
1475
895
  key: 0,
@@ -1480,24 +900,24 @@ var BaseRadioGroup_default = /* @__PURE__ */ defineComponent({
1480
900
  id: hintId,
1481
901
  class: "text-ink-soft text-xs"
1482
902
  }, toDisplayString(__props.hint), 1)) : createCommentVNode("", true)
1483
- ], 8, _hoisted_1$16);
903
+ ], 8, _hoisted_1$14);
1484
904
  };
1485
905
  }
1486
906
  });
1487
907
  //#endregion
1488
908
  //#region src/components/BaseSelect.vue?vue&type=script&setup=true&lang.ts
1489
- var _hoisted_1$15 = { class: "relative" };
1490
- var _hoisted_2$12 = [
909
+ var _hoisted_1$13 = { class: "relative" };
910
+ var _hoisted_2$10 = [
1491
911
  "id",
1492
912
  "aria-invalid",
1493
913
  "aria-describedby"
1494
914
  ];
1495
- var _hoisted_3$7 = {
915
+ var _hoisted_3$5 = {
1496
916
  key: 0,
1497
917
  value: void 0,
1498
918
  disabled: ""
1499
919
  };
1500
- var _hoisted_4$6 = ["value", "disabled"];
920
+ var _hoisted_4$5 = ["value", "disabled"];
1501
921
  //#endregion
1502
922
  //#region src/components/BaseSelect.vue
1503
923
  var BaseSelect_default = /* @__PURE__ */ defineComponent({
@@ -1533,7 +953,7 @@ var BaseSelect_default = /* @__PURE__ */ defineComponent({
1533
953
  "label-hidden": __props.labelHidden,
1534
954
  size: __props.size
1535
955
  }, {
1536
- default: withCtx(({ id, describedBy, invalid }) => [createElementVNode("div", _hoisted_1$15, [withDirectives(createElementVNode("select", {
956
+ default: withCtx(({ id, describedBy, invalid }) => [createElementVNode("div", _hoisted_1$13, [withDirectives(createElementVNode("select", {
1537
957
  id,
1538
958
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => model.value = $event),
1539
959
  "aria-invalid": invalid,
@@ -1543,13 +963,13 @@ var BaseSelect_default = /* @__PURE__ */ defineComponent({
1543
963
  __props.variant === "unstyled" ? "" : SIZE_CLASS[__props.size],
1544
964
  __props.variant !== "unstyled" && invalid ? "border-negative" : ""
1545
965
  ]])
1546
- }, [__props.placeholder ? (openBlock(), createElementBlock("option", _hoisted_3$7, toDisplayString(__props.placeholder), 1)) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList(__props.options, (option) => {
966
+ }, [__props.placeholder ? (openBlock(), createElementBlock("option", _hoisted_3$5, toDisplayString(__props.placeholder), 1)) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList(__props.options, (option) => {
1547
967
  return openBlock(), createElementBlock("option", {
1548
968
  key: option.value,
1549
969
  value: option.value,
1550
970
  disabled: option.disabled
1551
- }, toDisplayString(option.label), 9, _hoisted_4$6);
1552
- }), 128))], 10, _hoisted_2$12), [[vModelSelect, model.value]]), createVNode(unref(ChevronDown), {
971
+ }, toDisplayString(option.label), 9, _hoisted_4$5);
972
+ }), 128))], 10, _hoisted_2$10), [[vModelSelect, model.value]]), createVNode(unref(ChevronDown), {
1553
973
  class: "text-ink-soft pointer-events-none absolute top-1/2 right-3 size-4 -translate-y-1/2",
1554
974
  "aria-hidden": "true"
1555
975
  })])]),
@@ -1566,7 +986,7 @@ var BaseSelect_default = /* @__PURE__ */ defineComponent({
1566
986
  });
1567
987
  //#endregion
1568
988
  //#region src/components/BaseTextarea.vue?vue&type=script&setup=true&lang.ts
1569
- var _hoisted_1$14 = [
989
+ var _hoisted_1$12 = [
1570
990
  "id",
1571
991
  "rows",
1572
992
  "aria-invalid",
@@ -1613,7 +1033,7 @@ var BaseTextarea_default = /* @__PURE__ */ defineComponent({
1613
1033
  __props.variant === "unstyled" ? "" : "border-hair bg-surface text-ink rounded-card focus-visible:outline-primary resize-y border px-3 py-2 leading-relaxed focus-visible:outline-2 focus-visible:outline-offset-1",
1614
1034
  "text-base",
1615
1035
  __props.variant !== "unstyled" && invalid ? "border-negative" : ""
1616
- ] }), null, 16, _hoisted_1$14), [[vModelText, model.value]])]),
1036
+ ] }), null, 16, _hoisted_1$12), [[vModelText, model.value]])]),
1617
1037
  _: 1
1618
1038
  }, 8, [
1619
1039
  "label",
@@ -1627,17 +1047,17 @@ var BaseTextarea_default = /* @__PURE__ */ defineComponent({
1627
1047
  });
1628
1048
  //#endregion
1629
1049
  //#region src/components/EmptyState.vue?vue&type=script&setup=true&lang.ts
1630
- var _hoisted_1$13 = { class: "flex flex-col items-center gap-3 px-6 py-10 text-center" };
1631
- var _hoisted_2$11 = {
1050
+ var _hoisted_1$11 = { class: "flex flex-col items-center gap-3 px-6 py-10 text-center" };
1051
+ var _hoisted_2$9 = {
1632
1052
  key: 0,
1633
1053
  class: "bg-muted text-primary rounded-card flex size-12 items-center justify-center"
1634
1054
  };
1635
- var _hoisted_3$6 = { class: "text-ink text-base font-semibold" };
1636
- var _hoisted_4$5 = {
1055
+ var _hoisted_3$4 = { class: "text-ink text-base font-semibold" };
1056
+ var _hoisted_4$4 = {
1637
1057
  key: 1,
1638
1058
  class: "text-ink-soft max-w-[36ch] text-sm"
1639
1059
  };
1640
- var _hoisted_5$3 = {
1060
+ var _hoisted_5$2 = {
1641
1061
  key: 2,
1642
1062
  class: "mt-2 flex w-full flex-col gap-2"
1643
1063
  };
@@ -1651,11 +1071,11 @@ var EmptyState_default = /* @__PURE__ */ defineComponent({
1651
1071
  },
1652
1072
  setup(__props) {
1653
1073
  return (_ctx, _cache) => {
1654
- return openBlock(), createElementBlock("div", _hoisted_1$13, [
1655
- _ctx.$slots.icon ? (openBlock(), createElementBlock("div", _hoisted_2$11, [renderSlot(_ctx.$slots, "icon")])) : createCommentVNode("", true),
1656
- createElementVNode("h3", _hoisted_3$6, toDisplayString(__props.title), 1),
1657
- __props.description ? (openBlock(), createElementBlock("p", _hoisted_4$5, toDisplayString(__props.description), 1)) : createCommentVNode("", true),
1658
- _ctx.$slots.action ? (openBlock(), createElementBlock("div", _hoisted_5$3, [renderSlot(_ctx.$slots, "action")])) : createCommentVNode("", true)
1074
+ return openBlock(), createElementBlock("div", _hoisted_1$11, [
1075
+ _ctx.$slots.icon ? (openBlock(), createElementBlock("div", _hoisted_2$9, [renderSlot(_ctx.$slots, "icon")])) : createCommentVNode("", true),
1076
+ createElementVNode("h3", _hoisted_3$4, toDisplayString(__props.title), 1),
1077
+ __props.description ? (openBlock(), createElementBlock("p", _hoisted_4$4, toDisplayString(__props.description), 1)) : createCommentVNode("", true),
1078
+ _ctx.$slots.action ? (openBlock(), createElementBlock("div", _hoisted_5$2, [renderSlot(_ctx.$slots, "action")])) : createCommentVNode("", true)
1659
1079
  ]);
1660
1080
  };
1661
1081
  }
@@ -1722,11 +1142,11 @@ var PageContainer_default = /* @__PURE__ */ defineComponent({
1722
1142
  });
1723
1143
  //#endregion
1724
1144
  //#region src/components/PageHeader.vue?vue&type=script&setup=true&lang.ts
1725
- var _hoisted_1$12 = { class: "grid h-12 shrink-0 grid-cols-[2.5rem_1fr_2.5rem] items-center" };
1726
- var _hoisted_2$10 = { class: "justify-self-start" };
1727
- var _hoisted_3$5 = { class: "text-ink flex min-w-0 justify-center text-base font-semibold tabular-nums" };
1728
- var _hoisted_4$4 = { class: "truncate" };
1729
- var _hoisted_5$2 = { class: "justify-self-end" };
1145
+ var _hoisted_1$10 = { class: "grid h-12 shrink-0 grid-cols-[2.5rem_1fr_2.5rem] items-center" };
1146
+ var _hoisted_2$8 = { class: "justify-self-start" };
1147
+ var _hoisted_3$3 = { class: "text-ink flex min-w-0 justify-center text-base font-semibold tabular-nums" };
1148
+ var _hoisted_4$3 = { class: "truncate" };
1149
+ var _hoisted_5$1 = { class: "justify-self-end" };
1730
1150
  //#endregion
1731
1151
  //#region src/components/PageHeader.vue
1732
1152
  var PageHeader_default = /* @__PURE__ */ defineComponent({
@@ -1734,17 +1154,17 @@ var PageHeader_default = /* @__PURE__ */ defineComponent({
1734
1154
  props: { title: {} },
1735
1155
  setup(__props) {
1736
1156
  return (_ctx, _cache) => {
1737
- return openBlock(), createElementBlock("header", _hoisted_1$12, [
1738
- createElementVNode("div", _hoisted_2$10, [renderSlot(_ctx.$slots, "left")]),
1739
- createElementVNode("h1", _hoisted_3$5, [renderSlot(_ctx.$slots, "title", {}, () => [createElementVNode("span", _hoisted_4$4, toDisplayString(__props.title), 1)])]),
1740
- createElementVNode("div", _hoisted_5$2, [renderSlot(_ctx.$slots, "right")])
1157
+ return openBlock(), createElementBlock("header", _hoisted_1$10, [
1158
+ createElementVNode("div", _hoisted_2$8, [renderSlot(_ctx.$slots, "left")]),
1159
+ createElementVNode("h1", _hoisted_3$3, [renderSlot(_ctx.$slots, "title", {}, () => [createElementVNode("span", _hoisted_4$3, toDisplayString(__props.title), 1)])]),
1160
+ createElementVNode("div", _hoisted_5$1, [renderSlot(_ctx.$slots, "right")])
1741
1161
  ]);
1742
1162
  };
1743
1163
  }
1744
1164
  });
1745
1165
  //#endregion
1746
1166
  //#region src/components/ProgressBar.vue?vue&type=script&setup=true&lang.ts
1747
- var _hoisted_1$11 = ["aria-valuenow", "aria-label"];
1167
+ var _hoisted_1$9 = ["aria-valuenow", "aria-label"];
1748
1168
  //#endregion
1749
1169
  //#region src/components/ProgressBar.vue
1750
1170
  var ProgressBar_default = /* @__PURE__ */ defineComponent({
@@ -1776,25 +1196,25 @@ var ProgressBar_default = /* @__PURE__ */ defineComponent({
1776
1196
  }, [createElementVNode("div", {
1777
1197
  class: "bg-primary h-full rounded-full transition-[width] duration-700 ease-out",
1778
1198
  style: normalizeStyle({ width: `${portion.value}%` })
1779
- }, null, 4)], 10, _hoisted_1$11);
1199
+ }, null, 4)], 10, _hoisted_1$9);
1780
1200
  };
1781
1201
  }
1782
1202
  });
1783
1203
  //#endregion
1784
1204
  //#region src/components/PriceCard.vue?vue&type=script&setup=true&lang.ts
1785
- var _hoisted_1$10 = {
1205
+ var _hoisted_1$8 = {
1786
1206
  key: 0,
1787
1207
  class: "bg-primary rounded-cell absolute -top-3 left-7 px-3 py-1 text-[0.7rem] font-semibold text-white"
1788
1208
  };
1789
- var _hoisted_2$9 = { class: "flex items-start justify-between gap-4" };
1790
- var _hoisted_3$4 = { class: "text-ink mt-5 text-lg font-semibold" };
1791
- var _hoisted_4$3 = {
1209
+ var _hoisted_2$7 = { class: "flex items-start justify-between gap-4" };
1210
+ var _hoisted_3$2 = { class: "text-ink mt-5 text-lg font-semibold" };
1211
+ var _hoisted_4$2 = {
1792
1212
  key: 1,
1793
1213
  class: "text-ink-soft mt-1.5 text-sm leading-relaxed"
1794
1214
  };
1795
- var _hoisted_5$1 = { class: "mt-6 flex items-baseline gap-1.5" };
1796
- var _hoisted_6$1 = { class: "text-ink text-3xl font-semibold tracking-tight tabular-nums" };
1797
- var _hoisted_7$1 = {
1215
+ var _hoisted_5 = { class: "mt-6 flex items-baseline gap-1.5" };
1216
+ var _hoisted_6 = { class: "text-ink text-3xl font-semibold tracking-tight tabular-nums" };
1217
+ var _hoisted_7 = {
1798
1218
  key: 0,
1799
1219
  class: "text-ink-soft text-sm"
1800
1220
  };
@@ -1857,17 +1277,17 @@ var PriceCard_default = /* @__PURE__ */ defineComponent({
1857
1277
  const palette = computed(() => TONE[__props.tone]);
1858
1278
  return (_ctx, _cache) => {
1859
1279
  return openBlock(), createElementBlock("article", { class: normalizeClass(["bg-surface rounded-card relative flex h-full flex-col border p-7 shadow-[var(--shadow-card)] transition-[border-color,box-shadow,transform] duration-[420ms] hover:border-[color-mix(in_oklab,var(--color-primary)_60%,transparent)] hover:shadow-[var(--shadow-lift)] sm:p-8", [palette.value.ring, __props.recommended ? "shadow-[var(--shadow-lift)]" : "hover:-translate-y-0.5"]]) }, [
1860
- __props.badge && __props.recommended ? (openBlock(), createElementBlock("span", _hoisted_1$10, toDisplayString(__props.badge), 1)) : createCommentVNode("", true),
1861
- createElementVNode("div", _hoisted_2$9, [_ctx.$slots.icon ? (openBlock(), createElementBlock("span", {
1280
+ __props.badge && __props.recommended ? (openBlock(), createElementBlock("span", _hoisted_1$8, toDisplayString(__props.badge), 1)) : createCommentVNode("", true),
1281
+ createElementVNode("div", _hoisted_2$7, [_ctx.$slots.icon ? (openBlock(), createElementBlock("span", {
1862
1282
  key: 0,
1863
1283
  class: normalizeClass(["rounded-card grid size-11 place-items-center text-xl", palette.value.icon])
1864
1284
  }, [renderSlot(_ctx.$slots, "icon")], 2)) : createCommentVNode("", true), __props.chip ? (openBlock(), createElementBlock("span", {
1865
1285
  key: 1,
1866
1286
  class: normalizeClass(["rounded-cell ml-auto px-2.5 py-1 text-[0.7rem] font-medium", palette.value.soft])
1867
1287
  }, toDisplayString(__props.chip), 3)) : createCommentVNode("", true)]),
1868
- createElementVNode("h3", _hoisted_3$4, toDisplayString(__props.name), 1),
1869
- __props.lead ? (openBlock(), createElementBlock("p", _hoisted_4$3, toDisplayString(__props.lead), 1)) : createCommentVNode("", true),
1870
- createElementVNode("p", _hoisted_5$1, [createElementVNode("span", _hoisted_6$1, toDisplayString(__props.price), 1), __props.period ? (openBlock(), createElementBlock("span", _hoisted_7$1, toDisplayString(__props.period), 1)) : createCommentVNode("", true)]),
1288
+ createElementVNode("h3", _hoisted_3$2, toDisplayString(__props.name), 1),
1289
+ __props.lead ? (openBlock(), createElementBlock("p", _hoisted_4$2, toDisplayString(__props.lead), 1)) : createCommentVNode("", true),
1290
+ createElementVNode("p", _hoisted_5, [createElementVNode("span", _hoisted_6, toDisplayString(__props.price), 1), __props.period ? (openBlock(), createElementBlock("span", _hoisted_7, toDisplayString(__props.period), 1)) : createCommentVNode("", true)]),
1871
1291
  __props.note ? (openBlock(), createElementBlock("p", _hoisted_8, toDisplayString(__props.note), 1)) : createCommentVNode("", true),
1872
1292
  createElementVNode("ul", _hoisted_9, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.features, (feature) => {
1873
1293
  return openBlock(), createElementBlock("li", {
@@ -1882,8 +1302,8 @@ var PriceCard_default = /* @__PURE__ */ defineComponent({
1882
1302
  });
1883
1303
  //#endregion
1884
1304
  //#region src/components/ToneDot.vue?vue&type=script&setup=true&lang.ts
1885
- var _hoisted_1$9 = { class: "inline-flex items-center gap-1.5" };
1886
- var _hoisted_2$8 = {
1305
+ var _hoisted_1$7 = { class: "inline-flex items-center gap-1.5" };
1306
+ var _hoisted_2$6 = {
1887
1307
  key: 0,
1888
1308
  class: "text-ink-soft text-xs font-medium"
1889
1309
  };
@@ -1904,13 +1324,13 @@ var ToneDot_default = /* @__PURE__ */ defineComponent({
1904
1324
  * priorities — without this component knowing about any of them.
1905
1325
  */
1906
1326
  return (_ctx, _cache) => {
1907
- return openBlock(), createElementBlock("span", _hoisted_1$9, [createElementVNode("span", { class: normalizeClass(["size-2 rounded-full", __props.fill]) }, null, 2), __props.label ? (openBlock(), createElementBlock("span", _hoisted_2$8, toDisplayString(__props.label), 1)) : createCommentVNode("", true)]);
1327
+ return openBlock(), createElementBlock("span", _hoisted_1$7, [createElementVNode("span", { class: normalizeClass(["size-2 rounded-full", __props.fill]) }, null, 2), __props.label ? (openBlock(), createElementBlock("span", _hoisted_2$6, toDisplayString(__props.label), 1)) : createCommentVNode("", true)]);
1908
1328
  };
1909
1329
  }
1910
1330
  });
1911
1331
  //#endregion
1912
1332
  //#region src/components/SectionHeading.vue?vue&type=script&setup=true&lang.ts
1913
- var _hoisted_1$8 = {
1333
+ var _hoisted_1$6 = {
1914
1334
  key: 0,
1915
1335
  class: "text-ink-soft text-xs tabular-nums"
1916
1336
  };
@@ -1928,15 +1348,15 @@ var SectionHeading_default = /* @__PURE__ */ defineComponent({
1928
1348
  return openBlock(), createElementBlock("h2", { class: normalizeClass(["flex items-center gap-2 self-start rounded-full border px-3 py-1", __props.tone.card]) }, [
1929
1349
  createVNode(ToneDot_default, { fill: __props.tone.fill }, null, 8, ["fill"]),
1930
1350
  createElementVNode("span", { class: normalizeClass(["text-xs font-semibold tracking-wide uppercase", __props.tone.text]) }, toDisplayString(__props.label), 3),
1931
- __props.count > 0 ? (openBlock(), createElementBlock("span", _hoisted_1$8, toDisplayString(__props.count), 1)) : createCommentVNode("", true)
1351
+ __props.count > 0 ? (openBlock(), createElementBlock("span", _hoisted_1$6, toDisplayString(__props.count), 1)) : createCommentVNode("", true)
1932
1352
  ], 2);
1933
1353
  };
1934
1354
  }
1935
1355
  });
1936
1356
  //#endregion
1937
1357
  //#region src/components/SegmentedControl.vue?vue&type=script&setup=true&lang.ts
1938
- var _hoisted_1$7 = { class: "bg-muted rounded-card flex w-full gap-1 p-1" };
1939
- var _hoisted_2$7 = ["value", "name"];
1358
+ var _hoisted_1$5 = { class: "bg-muted rounded-card flex w-full gap-1 p-1" };
1359
+ var _hoisted_2$5 = ["value", "name"];
1940
1360
  //#endregion
1941
1361
  //#region src/components/SegmentedControl.vue
1942
1362
  var SegmentedControl_default = /* @__PURE__ */ defineComponent({
@@ -1950,7 +1370,7 @@ var SegmentedControl_default = /* @__PURE__ */ defineComponent({
1950
1370
  const model = useModel(__props, "modelValue");
1951
1371
  const name = useId();
1952
1372
  return (_ctx, _cache) => {
1953
- return openBlock(), createElementBlock("div", _hoisted_1$7, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.options, (option) => {
1373
+ return openBlock(), createElementBlock("div", _hoisted_1$5, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.options, (option) => {
1954
1374
  return openBlock(), createElementBlock("label", {
1955
1375
  key: String(option.value),
1956
1376
  class: "flex-1 cursor-pointer"
@@ -1960,88 +1380,12 @@ var SegmentedControl_default = /* @__PURE__ */ defineComponent({
1960
1380
  value: option.value,
1961
1381
  name: unref(name),
1962
1382
  class: "sr-only"
1963
- }, null, 8, _hoisted_2$7), [[vModelRadio, model.value]]), createElementVNode("span", { class: normalizeClass(["flex h-10 items-center justify-center rounded-xl px-2 text-sm font-medium transition-colors select-none", model.value === option.value ? "bg-surface text-ink shadow-sm" : "text-ink-soft"]) }, toDisplayString(option.label), 3)]);
1383
+ }, null, 8, _hoisted_2$5), [[vModelRadio, model.value]]), createElementVNode("span", { class: normalizeClass(["flex h-10 items-center justify-center rounded-xl px-2 text-sm font-medium transition-colors select-none", model.value === option.value ? "bg-surface text-ink shadow-sm" : "text-ink-soft"]) }, toDisplayString(option.label), 3)]);
1964
1384
  }), 128))]);
1965
1385
  };
1966
1386
  }
1967
1387
  });
1968
1388
  //#endregion
1969
- //#region src/components/SettingsGroup.vue?vue&type=script&setup=true&lang.ts
1970
- var _hoisted_1$6 = { class: "flex flex-col gap-2" };
1971
- var _hoisted_2$6 = { class: "text-ink-soft px-1 text-xs font-semibold tracking-wide uppercase" };
1972
- var _hoisted_3$3 = { class: "border-hair bg-surface rounded-card divide-hair divide-y overflow-hidden border" };
1973
- //#endregion
1974
- //#region src/components/SettingsGroup.vue
1975
- var SettingsGroup_default = /* @__PURE__ */ defineComponent({
1976
- __name: "SettingsGroup",
1977
- props: { title: {} },
1978
- setup(__props) {
1979
- return (_ctx, _cache) => {
1980
- return openBlock(), createElementBlock("section", _hoisted_1$6, [createElementVNode("h2", _hoisted_2$6, toDisplayString(__props.title), 1), createElementVNode("div", _hoisted_3$3, [renderSlot(_ctx.$slots, "default")])]);
1981
- };
1982
- }
1983
- });
1984
- //#endregion
1985
- //#region src/components/SettingsRow.vue?vue&type=script&setup=true&lang.ts
1986
- var _hoisted_1$5 = { class: "flex items-center gap-3" };
1987
- var _hoisted_2$5 = {
1988
- key: 0,
1989
- class: "bg-muted text-ink-soft flex size-9 shrink-0 items-center justify-center rounded-xl",
1990
- "aria-hidden": "true"
1991
- };
1992
- var _hoisted_3$2 = { class: "min-w-0 flex-1" };
1993
- var _hoisted_4$2 = { class: "text-ink text-sm font-medium" };
1994
- var _hoisted_5 = {
1995
- key: 0,
1996
- class: "text-ink-soft mt-0.5 text-xs leading-snug"
1997
- };
1998
- var _hoisted_6 = {
1999
- key: 1,
2000
- class: "shrink-0"
2001
- };
2002
- var _hoisted_7 = { key: 0 };
2003
- //#endregion
2004
- //#region src/components/SettingsRow.vue
2005
- var SettingsRow_default = /* @__PURE__ */ defineComponent({
2006
- __name: "SettingsRow",
2007
- props: {
2008
- label: {},
2009
- description: { default: "" },
2010
- icon: { default: () => void 0 },
2011
- interactive: {
2012
- type: Boolean,
2013
- default: false
2014
- },
2015
- stacked: {
2016
- type: Boolean,
2017
- default: false
2018
- }
2019
- },
2020
- emits: ["click"],
2021
- setup(__props, { emit: __emit }) {
2022
- const emit = __emit;
2023
- return (_ctx, _cache) => {
2024
- return openBlock(), createBlock(resolveDynamicComponent(__props.interactive ? "button" : "div"), {
2025
- type: __props.interactive ? "button" : void 0,
2026
- class: normalizeClass(["flex w-full items-center gap-3 px-4 py-3 text-left", [__props.interactive ? "hover:bg-muted/60 transition-colors active:scale-[0.99]" : "", __props.stacked ? "flex-col items-stretch gap-3" : ""]]),
2027
- onClick: _cache[0] || (_cache[0] = ($event) => __props.interactive && emit("click"))
2028
- }, {
2029
- default: withCtx(() => [createElementVNode("div", _hoisted_1$5, [
2030
- __props.icon ? (openBlock(), createElementBlock("span", _hoisted_2$5, [(openBlock(), createBlock(resolveDynamicComponent(__props.icon), { class: "size-[18px]" }))])) : createCommentVNode("", true),
2031
- createElementVNode("div", _hoisted_3$2, [createElementVNode("p", _hoisted_4$2, toDisplayString(__props.label), 1), __props.description ? (openBlock(), createElementBlock("p", _hoisted_5, toDisplayString(__props.description), 1)) : createCommentVNode("", true)]),
2032
- !__props.stacked ? (openBlock(), createElementBlock("div", _hoisted_6, [renderSlot(_ctx.$slots, "default")])) : createCommentVNode("", true),
2033
- __props.interactive ? (openBlock(), createBlock(unref(ChevronRight), {
2034
- key: 2,
2035
- class: "text-ink-soft size-4 shrink-0",
2036
- "aria-hidden": "true"
2037
- })) : createCommentVNode("", true)
2038
- ]), __props.stacked ? (openBlock(), createElementBlock("div", _hoisted_7, [renderSlot(_ctx.$slots, "default")])) : createCommentVNode("", true)]),
2039
- _: 3
2040
- }, 8, ["type", "class"]);
2041
- };
2042
- }
2043
- });
2044
- //#endregion
2045
1389
  //#region src/components/SkeletonList.vue?vue&type=script&setup=true&lang.ts
2046
1390
  var _hoisted_1$4 = {
2047
1391
  role: "status",
@@ -2437,7 +1781,7 @@ function createI18nRuntime(options) {
2437
1781
  *
2438
1782
  * The fallback keeps `vitest` and `vite dev` honest, where no define runs.
2439
1783
  */
2440
- var VERSION = "0.12.1";
1784
+ var VERSION = "0.14.0";
2441
1785
  //#endregion
2442
1786
  export { AppError, BaseAlert_default as BaseAlert, BaseBadge_default as BaseBadge, BaseButton_default as BaseButton, BaseCard_default as BaseCard, BaseCheckbox_default as BaseCheckbox, BaseInput_default as BaseInput, BaseRadioGroup_default as BaseRadioGroup, BaseSelect_default as BaseSelect, BaseSheet_default as BaseSheet, BaseTextarea_default as BaseTextarea, EmptyState_default as EmptyState, ErrorBoundary_default as ErrorBoundary, FormField_default as FormField, GoogleButton_default as GoogleButton, LocaleLinks_default as LocaleLinks, PageContainer_default as PageContainer, PageHeader_default as PageHeader, PriceCard_default as PriceCard, ProgressBar_default as ProgressBar, SectionHeading_default as SectionHeading, SegmentedControl_default as SegmentedControl, SettingsGroup_default as SettingsGroup, SettingsRow_default as SettingsRow, SkeletonList_default as SkeletonList, StatCard_default as StatCard, TabBar_default as TabBar, ToastHost_default as ToastHost, ToneDot_default as ToneDot, VERSION, addDays, applyTheme, createI18nRuntime, downloadJson, eachDayOfYear, formatDate, fromDateKey, isApplePortable, isInstalled, isThemePreference, lastNDays, leadingBlanks, needsIosInstall, readStoredTheme, registerErrorMapper, relativeDayLabel, safeRedirect, setFormatLocale, setThemeStorageKey, startOfWeek, tapFeedback, toAppError, toDateKey, todayKey, useDebouncedCallback, useDragScroll, useMediaQuery, useOnline, useTheme, useToast, useToday, useVisualViewport };
2443
1787