@nuxt/ui 4.8.2 → 4.9.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.
Files changed (82) hide show
  1. package/dist/module.d.mts +7 -0
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +2 -2
  4. package/dist/runtime/components/Avatar.vue +1 -1
  5. package/dist/runtime/components/Banner.vue +0 -1
  6. package/dist/runtime/components/BlogPost.vue +8 -10
  7. package/dist/runtime/components/Calendar.d.vue.ts +40 -4
  8. package/dist/runtime/components/Calendar.vue +179 -61
  9. package/dist/runtime/components/Calendar.vue.d.ts +40 -4
  10. package/dist/runtime/components/ChatMessages.d.vue.ts +7 -3
  11. package/dist/runtime/components/ChatMessages.vue +4 -1
  12. package/dist/runtime/components/ChatMessages.vue.d.ts +7 -3
  13. package/dist/runtime/components/ChatPrompt.vue +8 -2
  14. package/dist/runtime/components/ChatPromptSubmit.d.vue.ts +2 -2
  15. package/dist/runtime/components/ChatPromptSubmit.vue +2 -2
  16. package/dist/runtime/components/ChatPromptSubmit.vue.d.ts +2 -2
  17. package/dist/runtime/components/CommandPalette.d.vue.ts +2 -2
  18. package/dist/runtime/components/CommandPalette.vue +10 -4
  19. package/dist/runtime/components/CommandPalette.vue.d.ts +2 -2
  20. package/dist/runtime/components/DashboardSearch.d.vue.ts +7 -1
  21. package/dist/runtime/components/DashboardSearch.vue +9 -2
  22. package/dist/runtime/components/DashboardSearch.vue.d.ts +7 -1
  23. package/dist/runtime/components/DashboardSearchButton.d.vue.ts +2 -2
  24. package/dist/runtime/components/DashboardSearchButton.vue +2 -2
  25. package/dist/runtime/components/DashboardSearchButton.vue.d.ts +2 -2
  26. package/dist/runtime/components/FileUpload.d.vue.ts +5 -2
  27. package/dist/runtime/components/FileUpload.vue +8 -6
  28. package/dist/runtime/components/FileUpload.vue.d.ts +5 -2
  29. package/dist/runtime/components/Link.d.vue.ts +1 -0
  30. package/dist/runtime/components/Link.vue +1 -1
  31. package/dist/runtime/components/Link.vue.d.ts +1 -0
  32. package/dist/runtime/components/Modal.d.vue.ts +6 -0
  33. package/dist/runtime/components/Modal.vue +3 -1
  34. package/dist/runtime/components/Modal.vue.d.ts +6 -0
  35. package/dist/runtime/components/PinInput.d.vue.ts +14 -2
  36. package/dist/runtime/components/PinInput.vue +36 -11
  37. package/dist/runtime/components/PinInput.vue.d.ts +14 -2
  38. package/dist/runtime/components/Popover.d.vue.ts +2 -0
  39. package/dist/runtime/components/Popover.vue +2 -2
  40. package/dist/runtime/components/Popover.vue.d.ts +2 -0
  41. package/dist/runtime/components/ScrollArea.d.vue.ts +8 -0
  42. package/dist/runtime/components/ScrollArea.vue +10 -0
  43. package/dist/runtime/components/ScrollArea.vue.d.ts +8 -0
  44. package/dist/runtime/components/Select.vue +8 -1
  45. package/dist/runtime/components/SelectMenu.vue +11 -4
  46. package/dist/runtime/components/Sidebar.d.vue.ts +5 -0
  47. package/dist/runtime/components/Sidebar.vue +3 -1
  48. package/dist/runtime/components/Sidebar.vue.d.ts +5 -0
  49. package/dist/runtime/components/Slideover.d.vue.ts +6 -0
  50. package/dist/runtime/components/Slideover.vue +3 -1
  51. package/dist/runtime/components/Slideover.vue.d.ts +6 -0
  52. package/dist/runtime/components/content/ContentSearch.d.vue.ts +7 -1
  53. package/dist/runtime/components/content/ContentSearch.vue +9 -2
  54. package/dist/runtime/components/content/ContentSearch.vue.d.ts +7 -1
  55. package/dist/runtime/components/content/ContentSearchButton.d.vue.ts +2 -2
  56. package/dist/runtime/components/content/ContentSearchButton.vue +2 -2
  57. package/dist/runtime/components/content/ContentSearchButton.vue.d.ts +2 -2
  58. package/dist/runtime/components/prose/Kbd.d.vue.ts +2 -1
  59. package/dist/runtime/components/prose/Kbd.vue.d.ts +2 -1
  60. package/dist/runtime/components/prose/Pre.vue +0 -1
  61. package/dist/runtime/composables/index.d.ts +1 -0
  62. package/dist/runtime/composables/index.js +1 -0
  63. package/dist/runtime/composables/useComponentProps.d.ts +3 -3
  64. package/dist/runtime/composables/useTour.d.ts +80 -0
  65. package/dist/runtime/composables/useTour.js +102 -0
  66. package/dist/runtime/index.css +1 -1
  67. package/dist/runtime/keyframes.css +1 -1
  68. package/dist/runtime/locale/index.d.ts +1 -0
  69. package/dist/runtime/locale/index.js +1 -0
  70. package/dist/runtime/locale/lv.d.ts +3 -0
  71. package/dist/runtime/locale/lv.js +152 -0
  72. package/dist/runtime/plugins/colors.js +5 -4
  73. package/dist/runtime/types/tv.d.ts +15 -3
  74. package/dist/runtime/utils/tv.d.ts +41 -1
  75. package/dist/runtime/utils/tv.js +91 -2
  76. package/dist/runtime/vue/stubs/base.d.ts +1 -1
  77. package/dist/runtime/vue/stubs/base.js +1 -1
  78. package/dist/shared/{ui.C-lVg1QQ.mjs → ui.BfHSFiIO.mjs} +375 -232
  79. package/dist/unplugin.d.mts +8 -0
  80. package/dist/unplugin.mjs +2 -2
  81. package/dist/vite.mjs +1 -1
  82. package/package.json +57 -40
package/dist/module.d.mts CHANGED
@@ -40,6 +40,13 @@ interface ModuleOptions {
40
40
  * @see https://ui.nuxt.com/docs/getting-started/installation/nuxt#themetransitions
41
41
  */
42
42
  transitions?: boolean;
43
+ /**
44
+ * Remove all default theme classes from components, keeping only their
45
+ * structure and the classes you supply via `class`, `ui` or `app.config.ui`.
46
+ * @defaultValue `false`
47
+ * @see https://ui.nuxt.com/docs/getting-started/installation/nuxt#themeunstyled
48
+ */
49
+ unstyled?: boolean;
43
50
  /**
44
51
  * The default variants to use for components
45
52
  * @see https://ui.nuxt.com/docs/getting-started/installation/nuxt#themedefaultvariants
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuxt/ui",
3
- "version": "4.8.2",
3
+ "version": "4.9.0",
4
4
  "docs": "https://ui.nuxt.com/docs/getting-started/installation/nuxt",
5
5
  "configKey": "ui",
6
6
  "compatibility": {
package/dist/module.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { defu } from 'defu';
2
2
  import { defineNuxtModule, createResolver, addPlugin, hasNuxtModule, addComponentsDir, addImportsDir, addImports } from '@nuxt/kit';
3
- import { d as defaultOptions, r as resolveColors, g as getDefaultConfig, p as publicComposables, a as addTemplates } from './shared/ui.C-lVg1QQ.mjs';
3
+ import { d as defaultOptions, r as resolveColors, g as getDefaultConfig, p as publicComposables, a as addTemplates } from './shared/ui.BfHSFiIO.mjs';
4
4
  import '../dist/runtime/utils/index.js';
5
5
  import 'node:url';
6
6
  import 'scule';
@@ -11,7 +11,7 @@ import 'pathe';
11
11
  import 'tinyglobby';
12
12
 
13
13
  const name = "@nuxt/ui";
14
- const version = "4.8.2";
14
+ const version = "4.9.0";
15
15
 
16
16
  const module$1 = defineNuxtModule({
17
17
  meta: {
@@ -43,7 +43,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.avatar || {}
43
43
  }));
44
44
  const rootClass = computed(() => ui.value.root({ class: [props.ui?.root, props.class] }));
45
45
  const sizePx = computed(() => {
46
- const sizeClass = rootClass.value.split(" ").find((c) => /^size-\d+$/.test(c));
46
+ const sizeClass = (rootClass.value || "").split(" ").find((c) => /^size-\d+$/.test(c));
47
47
  if (sizeClass) {
48
48
  const num = Number.parseFloat(sizeClass.split("-")[1] ?? "");
49
49
  if (!Number.isNaN(num)) return num * 4;
@@ -100,7 +100,6 @@ function onClose() {
100
100
  :aria-label="props.title"
101
101
  v-bind="{ to: props.to, target: props.target, ...$attrs }"
102
102
  :class="prefix('focus:outline-none')"
103
- tabindex="-1"
104
103
  raw
105
104
  >
106
105
  <span :class="prefix('absolute inset-0')" aria-hidden="true" />
@@ -74,6 +74,14 @@ const ariaLabel = computed(() => {
74
74
 
75
75
  <template>
76
76
  <Primitive :as="props.as" :data-orientation="props.orientation" data-slot="root" :class="ui.root({ class: [props.ui?.root, props.class] })" @click="props.onClick">
77
+ <ULink
78
+ v-if="props.to"
79
+ :aria-label="ariaLabel"
80
+ v-bind="{ to: props.to, target: props.target, ...$attrs }"
81
+ :class="prefix('focus:outline-none absolute inset-0')"
82
+ raw
83
+ />
84
+
77
85
  <div v-if="props.image || !!slots.header" data-slot="header" :class="ui.header({ class: props.ui?.header })">
78
86
  <slot name="header" :ui="ui">
79
87
  <component
@@ -86,16 +94,6 @@ const ariaLabel = computed(() => {
86
94
  </div>
87
95
 
88
96
  <div data-slot="body" :class="ui.body({ class: props.ui?.body })">
89
- <ULink
90
- v-if="props.to"
91
- :aria-label="ariaLabel"
92
- v-bind="{ to: props.to, target: props.target, ...$attrs }"
93
- :class="prefix('focus:outline-none peer')"
94
- raw
95
- >
96
- <span :class="prefix('absolute inset-0')" aria-hidden="true" />
97
- </ULink>
98
-
99
97
  <slot name="body">
100
98
  <div v-if="date || !!slots.date || (props.badge || !!slots.badge)" data-slot="meta" :class="ui.meta({ class: props.ui?.meta })">
101
99
  <slot name="badge">
@@ -1,4 +1,4 @@
1
- import type { CalendarRootProps, CalendarRootEmits, RangeCalendarRootProps, RangeCalendarRootEmits, DateRange, CalendarCellTriggerProps } from 'reka-ui';
1
+ import type { CalendarRootProps, CalendarRootEmits, RangeCalendarRootProps, RangeCalendarRootEmits, MonthPickerRootProps, YearPickerRootProps, DateRange, CalendarCellTriggerProps } from 'reka-ui';
2
2
  import type { VNode } from 'vue';
3
3
  import type { DateValue } from '@internationalized/date';
4
4
  import type { AppConfig } from '@nuxt/schema';
@@ -6,16 +6,28 @@ import theme from '#build/ui/calendar';
6
6
  import type { ButtonProps, IconProps, LinkPropsKeys } from '../types';
7
7
  import type { ComponentConfig } from '../types/tv';
8
8
  type Calendar = ComponentConfig<typeof theme, AppConfig, 'calendar'>;
9
+ export type CalendarType = 'date' | 'month' | 'year';
10
+ export type CalendarView = 'day' | 'month' | 'year';
9
11
  type CalendarDefaultValue<R extends boolean = false, M extends boolean = false> = R extends true ? DateRange : M extends true ? DateValue[] : DateValue;
10
12
  type CalendarModelValue<R extends boolean = false, M extends boolean = false> = R extends true ? (DateRange | null) : M extends true ? (DateValue[] | undefined) : (DateValue | undefined);
11
13
  type _CalendarRootProps = Omit<CalendarRootProps, 'as' | 'asChild' | 'modelValue' | 'defaultValue' | 'dir' | 'calendarLabel' | 'multiple'>;
12
14
  type _RangeCalendarRootProps = Omit<RangeCalendarRootProps, 'as' | 'asChild' | 'modelValue' | 'defaultValue' | 'dir' | 'calendarLabel' | 'multiple'>;
13
- export interface CalendarProps<R extends boolean = false, M extends boolean = false> extends _RangeCalendarRootProps, _CalendarRootProps {
15
+ type _MonthPickerRootProps = Pick<MonthPickerRootProps, 'isMonthDisabled' | 'isMonthUnavailable'>;
16
+ type _YearPickerRootProps = Pick<YearPickerRootProps, 'isYearDisabled' | 'isYearUnavailable'>;
17
+ export interface CalendarProps<R extends boolean = false, M extends boolean = false> extends _RangeCalendarRootProps, _CalendarRootProps, _MonthPickerRootProps, _YearPickerRootProps {
14
18
  /**
15
19
  * The element or component this component should render as.
16
20
  * @defaultValue 'div'
17
21
  */
18
22
  as?: any;
23
+ /**
24
+ * The type of picker.
25
+ * - `date` renders a day calendar whose heading can switch to a month then year view.
26
+ * - `month` renders a standalone month picker.
27
+ * - `year` renders a standalone year picker.
28
+ * @defaultValue 'date'
29
+ */
30
+ type?: CalendarType;
19
31
  /**
20
32
  * The icon to use for the next year control.
21
33
  * @defaultValue appConfig.ui.icons.chevronDoubleRight
@@ -60,6 +72,13 @@ export interface CalendarProps<R extends boolean = false, M extends boolean = fa
60
72
  * `{ color: 'neutral', variant: 'ghost' }`{lang="ts-type"}
61
73
  */
62
74
  prevMonth?: Omit<ButtonProps, LinkPropsKeys>;
75
+ /**
76
+ * Whether to make the heading a button that switches between the day, month and year views.
77
+ * Has no effect when `type` is `year`. Can be an object to override the button props.
78
+ * `{ color: 'neutral', variant: 'ghost', block: true }`{lang="ts-type"}
79
+ * @defaultValue true
80
+ */
81
+ viewControl?: boolean | Omit<ButtonProps, LinkPropsKeys>;
63
82
  /**
64
83
  * @defaultValue 'primary'
65
84
  */
@@ -88,22 +107,39 @@ export interface CalendarProps<R extends boolean = false, M extends boolean = fa
88
107
  }
89
108
  export interface CalendarEmits<R extends boolean = false, M extends boolean = false> extends Omit<CalendarRootEmits & RangeCalendarRootEmits, 'update:modelValue'> {
90
109
  'update:modelValue': [value: CalendarModelValue<R, M>];
110
+ 'update:placeholder': [date: DateValue];
111
+ 'update:startValue': [date: DateValue | undefined];
112
+ 'update:validModelValue': [date: DateRange];
91
113
  }
92
114
  export interface CalendarSlots {
93
115
  'heading'?: (props: {
94
116
  value: string;
117
+ view: CalendarView;
118
+ date: DateValue;
119
+ setView: (view: CalendarView) => void;
120
+ setPlaceholder: (date: DateValue) => void;
95
121
  }) => VNode[];
96
122
  'day'?: (props: Pick<CalendarCellTriggerProps, 'day'>) => VNode[];
97
123
  'week-day'?: (props: {
98
124
  day: string;
99
125
  }) => VNode[];
126
+ 'month-cell'?: (props: {
127
+ month: DateValue;
128
+ selected: boolean;
129
+ disabled: boolean;
130
+ }) => VNode[];
131
+ 'year-cell'?: (props: {
132
+ year: DateValue;
133
+ selected: boolean;
134
+ disabled: boolean;
135
+ }) => VNode[];
100
136
  }
101
137
  declare const _default: typeof __VLS_export;
102
138
  export default _default;
103
139
  declare const __VLS_export: <R extends boolean, M extends boolean>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
104
140
  props: import("vue").PublicProps & __VLS_PrettifyLocal<CalendarProps<R, M> & {
105
141
  "onUpdate:modelValue"?: ((value: CalendarModelValue<R, M>) => any) | undefined;
106
- "onUpdate:placeholder"?: ((...args: DateValue[]) => any) | undefined;
142
+ "onUpdate:placeholder"?: ((date: DateValue) => any) | undefined;
107
143
  "onUpdate:validModelValue"?: ((date: DateRange) => any) | undefined;
108
144
  "onUpdate:startValue"?: ((date: DateValue | undefined) => any) | undefined;
109
145
  }> & (typeof globalThis extends {
@@ -112,7 +148,7 @@ declare const __VLS_export: <R extends boolean, M extends boolean>(__VLS_props:
112
148
  expose: (exposed: {}) => void;
113
149
  attrs: any;
114
150
  slots: CalendarSlots;
115
- emit: ((evt: "update:modelValue", value: CalendarModelValue<R, M>) => void) & ((evt: "update:placeholder", ...args: [date: DateValue] & [date: DateValue]) => void) & ((evt: "update:validModelValue", date: DateRange) => void) & ((evt: "update:startValue", date: DateValue | undefined) => void);
151
+ emit: ((evt: "update:modelValue", value: CalendarModelValue<R, M>) => void) & ((evt: "update:placeholder", date: DateValue) => void) & ((evt: "update:validModelValue", date: DateRange) => void) & ((evt: "update:startValue", date: DateValue | undefined) => void);
116
152
  }>) => import("vue").VNode & {
117
153
  __ctx?: Awaited<typeof __VLS_setup>;
118
154
  };
@@ -1,13 +1,13 @@
1
1
  <script>
2
2
  import { getWeekNumber } from "reka-ui/date";
3
+ import { getLocalTimeZone, today } from "@internationalized/date";
3
4
  import theme from "#build/ui/calendar";
4
5
  </script>
5
6
 
6
7
  <script setup>
7
- import { computed } from "vue";
8
- import {} from "reka-ui";
8
+ import { computed, ref, shallowRef, watch } from "vue";
9
9
  import { useForwardProps } from "../composables/useForwardProps";
10
- import { Calendar as SingleCalendar, RangeCalendar } from "reka-ui/namespaced";
10
+ import { Calendar as SingleCalendar, RangeCalendar, MonthPicker, MonthRangePicker, YearPicker, YearRangePicker } from "reka-ui/namespaced";
11
11
  import { reactiveOmit } from "@vueuse/core";
12
12
  import { useAppConfig } from "#imports";
13
13
  import { useComponentProps } from "../composables/useComponentProps";
@@ -16,6 +16,7 @@ import { tv } from "../utils/tv";
16
16
  import UButton from "./Button.vue";
17
17
  const _props = defineProps({
18
18
  as: { type: null, required: false },
19
+ type: { type: String, required: false, default: "date" },
19
20
  nextYearIcon: { type: null, required: false },
20
21
  nextYear: { type: Object, required: false },
21
22
  nextMonthIcon: { type: null, required: false },
@@ -24,6 +25,7 @@ const _props = defineProps({
24
25
  prevYear: { type: Object, required: false },
25
26
  prevMonthIcon: { type: null, required: false },
26
27
  prevMonth: { type: Object, required: false },
28
+ viewControl: { type: [Boolean, Object], required: false, default: true },
27
29
  color: { type: null, required: false },
28
30
  variant: { type: null, required: false },
29
31
  size: { type: null, required: false },
@@ -58,71 +60,181 @@ const _props = defineProps({
58
60
  nextPage: { type: Function, required: false },
59
61
  prevPage: { type: Function, required: false },
60
62
  disableDaysOutsideCurrentView: { type: Boolean, required: false },
61
- fixedDate: { type: String, required: false }
63
+ fixedDate: { type: String, required: false },
64
+ isMonthDisabled: { type: Function, required: false },
65
+ isMonthUnavailable: { type: Function, required: false },
66
+ isYearDisabled: { type: Function, required: false },
67
+ isYearUnavailable: { type: Function, required: false }
62
68
  });
63
- const emits = defineEmits(["update:modelValue", "update:placeholder", "update:validModelValue", "update:startValue"]);
69
+ const emits = defineEmits(["update:modelValue", "update:placeholder", "update:startValue", "update:validModelValue"]);
64
70
  defineSlots();
65
71
  const props = useComponentProps("calendar", _props);
66
72
  const { dir, t, locale } = useLocale();
67
73
  const appConfig = useAppConfig();
68
- const rootProps = useForwardProps(reactiveOmit(props, "range", "modelValue", "defaultValue", "color", "variant", "size", "monthControls", "yearControls", "class", "ui"), emits);
74
+ const VIEWS = ["day", "month", "year"];
75
+ const minView = computed(() => props.type === "year" ? "year" : props.type === "month" ? "month" : "day");
76
+ const maxView = "year";
77
+ const view = ref(minView.value);
78
+ watch(() => props.type, () => {
79
+ view.value = minView.value;
80
+ });
81
+ const switchable = computed(() => minView.value !== maxView);
82
+ const isMinView = computed(() => view.value === minView.value);
83
+ function clampView(value) {
84
+ const min = VIEWS.indexOf(minView.value);
85
+ const max = VIEWS.indexOf(maxView);
86
+ return VIEWS[Math.min(Math.max(VIEWS.indexOf(value), min), max)];
87
+ }
88
+ function setView(value) {
89
+ view.value = clampView(value);
90
+ }
91
+ function cycleView() {
92
+ const max = VIEWS.indexOf(maxView);
93
+ const next = VIEWS.indexOf(view.value) >= max ? minView.value : VIEWS[VIEWS.indexOf(view.value) + 1];
94
+ view.value = next;
95
+ }
96
+ function resolveDateValue(value) {
97
+ if (Array.isArray(value)) {
98
+ return value[0];
99
+ }
100
+ if (!value) {
101
+ return void 0;
102
+ }
103
+ if ("start" in value || "end" in value) {
104
+ const range = value;
105
+ return range.start ?? range.end ?? void 0;
106
+ }
107
+ return value;
108
+ }
109
+ const placeholder = shallowRef(
110
+ props.placeholder ?? resolveDateValue(props.modelValue) ?? resolveDateValue(props.defaultValue) ?? today(getLocalTimeZone())
111
+ );
112
+ watch(() => props.placeholder, (value) => {
113
+ if (value) {
114
+ placeholder.value = value;
115
+ }
116
+ });
117
+ function setPlaceholder(date) {
118
+ placeholder.value = date;
119
+ emits("update:placeholder", date);
120
+ }
121
+ function onSelect(value) {
122
+ if (isMinView.value) {
123
+ emits("update:modelValue", value);
124
+ return;
125
+ }
126
+ const resolved = resolveDateValue(value);
127
+ if (resolved) {
128
+ setPlaceholder(resolved);
129
+ }
130
+ setView(VIEWS[VIEWS.indexOf(view.value) - 1]);
131
+ }
132
+ function paginateYear(date, sign) {
133
+ return sign === -1 ? date.subtract({ years: 1 }) : date.add({ years: 1 });
134
+ }
135
+ const Picker = computed(() => {
136
+ const range = props.range && isMinView.value;
137
+ if (view.value === "year") {
138
+ return range ? YearRangePicker : YearPicker;
139
+ }
140
+ if (view.value === "month") {
141
+ return range ? MonthRangePicker : MonthPicker;
142
+ }
143
+ return props.range ? RangeCalendar : SingleCalendar;
144
+ });
145
+ const omittedProps = ["type", "placeholder", "range", "modelValue", "defaultValue", "color", "variant", "size", "monthControls", "yearControls", "viewControl", "class", "ui"];
146
+ const dayOnlyProps = ["pagedNavigation", "weekStartsOn", "weekdayFormat", "fixedWeeks", "numberOfMonths", "isDateDisabled", "isDateUnavailable", "isDateHighlightable", "disableDaysOutsideCurrentView", "maximumDays"];
147
+ const monthOnlyProps = ["isMonthDisabled", "isMonthUnavailable"];
148
+ const yearOnlyProps = ["isYearDisabled", "isYearUnavailable"];
149
+ const rangeOnlyProps = ["allowNonContiguousRanges", "fixedDate"];
150
+ const rootProps = useForwardProps(reactiveOmit(
151
+ props,
152
+ (_, key) => omittedProps.includes(key) || view.value !== "day" && dayOnlyProps.includes(key) || view.value !== "month" && monthOnlyProps.includes(key) || view.value !== "year" && yearOnlyProps.includes(key) || !isMinView.value && rangeOnlyProps.includes(key)
153
+ ));
154
+ function cellProps(cellDate, monthValue) {
155
+ if (view.value === "month") {
156
+ return { month: cellDate };
157
+ }
158
+ if (view.value === "year") {
159
+ return { year: cellDate };
160
+ }
161
+ return { day: cellDate, month: monthValue };
162
+ }
69
163
  const nextYearIcon = computed(() => props.nextYearIcon || (dir.value === "rtl" ? appConfig.ui.icons.chevronDoubleLeft : appConfig.ui.icons.chevronDoubleRight));
70
164
  const nextMonthIcon = computed(() => props.nextMonthIcon || (dir.value === "rtl" ? appConfig.ui.icons.chevronLeft : appConfig.ui.icons.chevronRight));
71
165
  const prevYearIcon = computed(() => props.prevYearIcon || (dir.value === "rtl" ? appConfig.ui.icons.chevronDoubleRight : appConfig.ui.icons.chevronDoubleLeft));
72
166
  const prevMonthIcon = computed(() => props.prevMonthIcon || (dir.value === "rtl" ? appConfig.ui.icons.chevronRight : appConfig.ui.icons.chevronLeft));
167
+ const prevLabel = computed(() => view.value === "day" ? t("calendar.prevMonth") : t("calendar.prevYear"));
168
+ const nextLabel = computed(() => view.value === "day" ? t("calendar.nextMonth") : t("calendar.nextYear"));
73
169
  const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.calendar || {} })({
74
170
  color: props.color,
75
171
  size: props.size,
76
172
  variant: props.variant,
77
- weekNumbers: props.weekNumbers
173
+ weekNumbers: props.weekNumbers,
174
+ view: view.value
78
175
  }));
79
- function paginateYear(date, sign) {
80
- if (sign === -1) {
81
- return date.subtract({ years: 1 });
82
- }
83
- return date.add({ years: 1 });
84
- }
85
- const Calendar = computed(() => props.range ? RangeCalendar : SingleCalendar);
86
176
  </script>
87
177
 
88
178
  <template>
89
- <Calendar.Root
90
- v-slot="{ weekDays, grid }"
179
+ <Picker.Root
180
+ v-slot="{ weekDays, grid, date }"
91
181
  v-bind="rootProps"
92
- :model-value="props.modelValue"
93
- :default-value="props.defaultValue"
182
+ :model-value="isMinView ? props.modelValue : void 0"
183
+ :default-value="isMinView ? props.defaultValue : void 0"
184
+ :placeholder="placeholder"
94
185
  data-slot="root"
95
186
  :class="ui.root({ class: [props.ui?.root, props.class] })"
187
+ @update:placeholder="setPlaceholder"
188
+ @update:model-value="onSelect"
189
+ @update:start-value="(value) => emits('update:startValue', value)"
190
+ @update:valid-model-value="(value) => emits('update:validModelValue', value)"
96
191
  >
97
- <Calendar.Header data-slot="header" :class="ui.header({ class: props.ui?.header })">
98
- <Calendar.Prev v-if="props.yearControls" :prev-page="(date) => paginateYear(date, -1)" :aria-label="t('calendar.prevYear')" as-child>
192
+ <Picker.Header data-slot="header" :class="ui.header({ class: props.ui?.header })">
193
+ <Picker.Prev v-if="view === 'day' && props.yearControls" :prev-page="(date) => paginateYear(date, -1)" :aria-label="t('calendar.prevYear')" as-child>
99
194
  <UButton :icon="prevYearIcon" :size="props.size" color="neutral" variant="ghost" v-bind="props.prevYear" />
100
- </Calendar.Prev>
101
- <Calendar.Prev v-if="props.monthControls" :aria-label="t('calendar.prevMonth')" as-child>
195
+ </Picker.Prev>
196
+ <Picker.Prev v-if="view !== 'day' || props.monthControls" :aria-label="prevLabel" as-child>
102
197
  <UButton :icon="prevMonthIcon" :size="props.size" color="neutral" variant="ghost" v-bind="props.prevMonth" />
103
- </Calendar.Prev>
104
- <Calendar.Heading v-slot="{ headingValue }" data-slot="heading" :class="ui.heading({ class: props.ui?.heading })">
105
- <slot name="heading" :value="headingValue">
106
- {{ headingValue }}
198
+ </Picker.Prev>
199
+ <Picker.Heading v-slot="{ headingValue }" data-slot="heading" :class="ui.heading({ class: props.ui?.heading })">
200
+ <slot
201
+ name="heading"
202
+ :value="headingValue"
203
+ :view="view"
204
+ :date="date"
205
+ :set-view="setView"
206
+ :set-placeholder="setPlaceholder"
207
+ >
208
+ <UButton
209
+ v-if="switchable && props.viewControl"
210
+ :label="headingValue"
211
+ :size="props.size"
212
+ color="neutral"
213
+ variant="ghost"
214
+ block
215
+ v-bind="typeof props.viewControl === 'object' ? props.viewControl : {}"
216
+ @click="cycleView"
217
+ />
218
+ <span v-else data-slot="headingLabel" :class="ui.headingLabel({ class: props.ui?.headingLabel })">{{ headingValue }}</span>
107
219
  </slot>
108
- </Calendar.Heading>
109
- <Calendar.Next v-if="props.monthControls" :aria-label="t('calendar.nextMonth')" as-child>
220
+ </Picker.Heading>
221
+ <Picker.Next v-if="view !== 'day' || props.monthControls" :aria-label="nextLabel" as-child>
110
222
  <UButton :icon="nextMonthIcon" :size="props.size" color="neutral" variant="ghost" v-bind="props.nextMonth" />
111
- </Calendar.Next>
112
- <Calendar.Next v-if="props.yearControls" :next-page="(date) => paginateYear(date, 1)" :aria-label="t('calendar.nextYear')" as-child>
223
+ </Picker.Next>
224
+ <Picker.Next v-if="view === 'day' && props.yearControls" :next-page="(date) => paginateYear(date, 1)" :aria-label="t('calendar.nextYear')" as-child>
113
225
  <UButton :icon="nextYearIcon" :size="props.size" color="neutral" variant="ghost" v-bind="props.nextYear" />
114
- </Calendar.Next>
115
- </Calendar.Header>
226
+ </Picker.Next>
227
+ </Picker.Header>
116
228
  <div data-slot="body" :class="ui.body({ class: props.ui?.body })">
117
- <Calendar.Grid
118
- v-for="month in grid"
229
+ <Picker.Grid
230
+ v-for="month in Array.isArray(grid) ? grid : [grid]"
119
231
  :key="month.value.toString()"
120
232
  data-slot="grid"
121
233
  :class="ui.grid({ class: props.ui?.grid })"
122
234
  >
123
- <Calendar.GridHead>
124
- <Calendar.GridRow data-slot="gridWeekDaysRow" :class="ui.gridWeekDaysRow({ class: props.ui?.gridWeekDaysRow })">
125
- <Calendar.HeadCell
235
+ <Picker.GridHead v-if="'GridHead' in Picker">
236
+ <Picker.GridRow data-slot="gridWeekDaysRow" :class="ui.gridWeekDaysRow({ class: props.ui?.gridWeekDaysRow })">
237
+ <Picker.HeadCell
126
238
  v-for="day in weekDays"
127
239
  :key="day"
128
240
  data-slot="headCell"
@@ -131,45 +243,51 @@ const Calendar = computed(() => props.range ? RangeCalendar : SingleCalendar);
131
243
  <slot name="week-day" :day="day">
132
244
  {{ day }}
133
245
  </slot>
134
- </Calendar.HeadCell>
135
- </Calendar.GridRow>
136
- </Calendar.GridHead>
137
- <Calendar.GridBody data-slot="gridBody" :class="ui.gridBody({ class: props.ui?.gridBody })">
138
- <Calendar.GridRow
139
- v-for="(weekDates, index) in month.rows"
140
- :key="`weekDate-${index}`"
246
+ </Picker.HeadCell>
247
+ </Picker.GridRow>
248
+ </Picker.GridHead>
249
+ <Picker.GridBody data-slot="gridBody" :class="ui.gridBody({ class: props.ui?.gridBody })">
250
+ <Picker.GridRow
251
+ v-for="(row, index) in month.rows"
252
+ :key="`row-${index}`"
141
253
  data-slot="gridRow"
142
254
  :class="ui.gridRow({ class: props.ui?.gridRow })"
143
255
  >
144
256
  <td
145
- v-if="props.weekNumbers && weekDates[0]"
257
+ v-if="view === 'day' && props.weekNumbers && row[0]"
146
258
  role="gridcell"
147
259
  data-slot="cellWeek"
148
260
  :class="ui.cellWeek({ class: props.ui?.cellWeek })"
149
261
  >
150
- {{ getWeekNumber(weekDates[0], props.locale ?? locale.code) }}
262
+ {{ getWeekNumber(row[0], props.locale ?? locale.code) }}
151
263
  </td>
152
- <Calendar.Cell
153
- v-for="weekDate in weekDates"
154
- :key="weekDate.toString()"
155
- :date="weekDate"
264
+ <Picker.Cell
265
+ v-for="cellDate in row"
266
+ :key="cellDate.toString()"
267
+ :date="cellDate"
156
268
  data-slot="cell"
157
269
  :class="ui.cell({ class: props.ui?.cell })"
158
270
  >
159
- <Calendar.CellTrigger
160
- :day="weekDate"
161
- :month="month.value"
271
+ <Picker.CellTrigger
272
+ v-slot="cell"
273
+ v-bind="cellProps(cellDate, month.value)"
162
274
  data-slot="cellTrigger"
163
275
  :class="ui.cellTrigger({ class: props.ui?.cellTrigger })"
164
276
  >
165
- <slot name="day" :day="weekDate">
166
- {{ weekDate.day }}
277
+ <slot v-if="view === 'day'" name="day" :day="cellDate">
278
+ {{ cellDate.day }}
279
+ </slot>
280
+ <slot v-else-if="view === 'month'" name="month-cell" :month="cellDate" :selected="cell.selected" :disabled="cell.disabled">
281
+ {{ cell.monthValue }}
282
+ </slot>
283
+ <slot v-else name="year-cell" :year="cellDate" :selected="cell.selected" :disabled="cell.disabled">
284
+ {{ cell.yearValue }}
167
285
  </slot>
168
- </Calendar.CellTrigger>
169
- </Calendar.Cell>
170
- </Calendar.GridRow>
171
- </Calendar.GridBody>
172
- </Calendar.Grid>
286
+ </Picker.CellTrigger>
287
+ </Picker.Cell>
288
+ </Picker.GridRow>
289
+ </Picker.GridBody>
290
+ </Picker.Grid>
173
291
  </div>
174
- </Calendar.Root>
292
+ </Picker.Root>
175
293
  </template>
@@ -1,4 +1,4 @@
1
- import type { CalendarRootProps, CalendarRootEmits, RangeCalendarRootProps, RangeCalendarRootEmits, DateRange, CalendarCellTriggerProps } from 'reka-ui';
1
+ import type { CalendarRootProps, CalendarRootEmits, RangeCalendarRootProps, RangeCalendarRootEmits, MonthPickerRootProps, YearPickerRootProps, DateRange, CalendarCellTriggerProps } from 'reka-ui';
2
2
  import type { VNode } from 'vue';
3
3
  import type { DateValue } from '@internationalized/date';
4
4
  import type { AppConfig } from '@nuxt/schema';
@@ -6,16 +6,28 @@ import theme from '#build/ui/calendar';
6
6
  import type { ButtonProps, IconProps, LinkPropsKeys } from '../types';
7
7
  import type { ComponentConfig } from '../types/tv';
8
8
  type Calendar = ComponentConfig<typeof theme, AppConfig, 'calendar'>;
9
+ export type CalendarType = 'date' | 'month' | 'year';
10
+ export type CalendarView = 'day' | 'month' | 'year';
9
11
  type CalendarDefaultValue<R extends boolean = false, M extends boolean = false> = R extends true ? DateRange : M extends true ? DateValue[] : DateValue;
10
12
  type CalendarModelValue<R extends boolean = false, M extends boolean = false> = R extends true ? (DateRange | null) : M extends true ? (DateValue[] | undefined) : (DateValue | undefined);
11
13
  type _CalendarRootProps = Omit<CalendarRootProps, 'as' | 'asChild' | 'modelValue' | 'defaultValue' | 'dir' | 'calendarLabel' | 'multiple'>;
12
14
  type _RangeCalendarRootProps = Omit<RangeCalendarRootProps, 'as' | 'asChild' | 'modelValue' | 'defaultValue' | 'dir' | 'calendarLabel' | 'multiple'>;
13
- export interface CalendarProps<R extends boolean = false, M extends boolean = false> extends _RangeCalendarRootProps, _CalendarRootProps {
15
+ type _MonthPickerRootProps = Pick<MonthPickerRootProps, 'isMonthDisabled' | 'isMonthUnavailable'>;
16
+ type _YearPickerRootProps = Pick<YearPickerRootProps, 'isYearDisabled' | 'isYearUnavailable'>;
17
+ export interface CalendarProps<R extends boolean = false, M extends boolean = false> extends _RangeCalendarRootProps, _CalendarRootProps, _MonthPickerRootProps, _YearPickerRootProps {
14
18
  /**
15
19
  * The element or component this component should render as.
16
20
  * @defaultValue 'div'
17
21
  */
18
22
  as?: any;
23
+ /**
24
+ * The type of picker.
25
+ * - `date` renders a day calendar whose heading can switch to a month then year view.
26
+ * - `month` renders a standalone month picker.
27
+ * - `year` renders a standalone year picker.
28
+ * @defaultValue 'date'
29
+ */
30
+ type?: CalendarType;
19
31
  /**
20
32
  * The icon to use for the next year control.
21
33
  * @defaultValue appConfig.ui.icons.chevronDoubleRight
@@ -60,6 +72,13 @@ export interface CalendarProps<R extends boolean = false, M extends boolean = fa
60
72
  * `{ color: 'neutral', variant: 'ghost' }`{lang="ts-type"}
61
73
  */
62
74
  prevMonth?: Omit<ButtonProps, LinkPropsKeys>;
75
+ /**
76
+ * Whether to make the heading a button that switches between the day, month and year views.
77
+ * Has no effect when `type` is `year`. Can be an object to override the button props.
78
+ * `{ color: 'neutral', variant: 'ghost', block: true }`{lang="ts-type"}
79
+ * @defaultValue true
80
+ */
81
+ viewControl?: boolean | Omit<ButtonProps, LinkPropsKeys>;
63
82
  /**
64
83
  * @defaultValue 'primary'
65
84
  */
@@ -88,22 +107,39 @@ export interface CalendarProps<R extends boolean = false, M extends boolean = fa
88
107
  }
89
108
  export interface CalendarEmits<R extends boolean = false, M extends boolean = false> extends Omit<CalendarRootEmits & RangeCalendarRootEmits, 'update:modelValue'> {
90
109
  'update:modelValue': [value: CalendarModelValue<R, M>];
110
+ 'update:placeholder': [date: DateValue];
111
+ 'update:startValue': [date: DateValue | undefined];
112
+ 'update:validModelValue': [date: DateRange];
91
113
  }
92
114
  export interface CalendarSlots {
93
115
  'heading'?: (props: {
94
116
  value: string;
117
+ view: CalendarView;
118
+ date: DateValue;
119
+ setView: (view: CalendarView) => void;
120
+ setPlaceholder: (date: DateValue) => void;
95
121
  }) => VNode[];
96
122
  'day'?: (props: Pick<CalendarCellTriggerProps, 'day'>) => VNode[];
97
123
  'week-day'?: (props: {
98
124
  day: string;
99
125
  }) => VNode[];
126
+ 'month-cell'?: (props: {
127
+ month: DateValue;
128
+ selected: boolean;
129
+ disabled: boolean;
130
+ }) => VNode[];
131
+ 'year-cell'?: (props: {
132
+ year: DateValue;
133
+ selected: boolean;
134
+ disabled: boolean;
135
+ }) => VNode[];
100
136
  }
101
137
  declare const _default: typeof __VLS_export;
102
138
  export default _default;
103
139
  declare const __VLS_export: <R extends boolean, M extends boolean>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
104
140
  props: import("vue").PublicProps & __VLS_PrettifyLocal<CalendarProps<R, M> & {
105
141
  "onUpdate:modelValue"?: ((value: CalendarModelValue<R, M>) => any) | undefined;
106
- "onUpdate:placeholder"?: ((...args: DateValue[]) => any) | undefined;
142
+ "onUpdate:placeholder"?: ((date: DateValue) => any) | undefined;
107
143
  "onUpdate:validModelValue"?: ((date: DateRange) => any) | undefined;
108
144
  "onUpdate:startValue"?: ((date: DateValue | undefined) => any) | undefined;
109
145
  }> & (typeof globalThis extends {
@@ -112,7 +148,7 @@ declare const __VLS_export: <R extends boolean, M extends boolean>(__VLS_props:
112
148
  expose: (exposed: {}) => void;
113
149
  attrs: any;
114
150
  slots: CalendarSlots;
115
- emit: ((evt: "update:modelValue", value: CalendarModelValue<R, M>) => void) & ((evt: "update:placeholder", ...args: [date: DateValue] & [date: DateValue]) => void) & ((evt: "update:validModelValue", date: DateRange) => void) & ((evt: "update:startValue", date: DateValue | undefined) => void);
151
+ emit: ((evt: "update:modelValue", value: CalendarModelValue<R, M>) => void) & ((evt: "update:placeholder", date: DateValue) => void) & ((evt: "update:validModelValue", date: DateRange) => void) & ((evt: "update:startValue", date: DateValue | undefined) => void);
116
152
  }>) => import("vue").VNode & {
117
153
  __ctx?: Awaited<typeof __VLS_setup>;
118
154
  };
@@ -1,4 +1,4 @@
1
- import type { VNode } from 'vue';
1
+ import type { ComponentPublicInstance, VNode } from 'vue';
2
2
  import type { AppConfig } from '@nuxt/schema';
3
3
  import type { UIDataTypes, UIMessage, UITools, ChatStatus } from 'ai';
4
4
  import theme from '#build/ui/chat-messages';
@@ -57,7 +57,9 @@ export interface ChatMessagesProps<T extends UIMessage[] = UIMessage[]> {
57
57
  ui?: ChatMessages['slots'];
58
58
  }
59
59
  export type ChatMessagesSlots<T extends UIMessage[] = UIMessage[]> = {
60
- default?(props?: {}): VNode[];
60
+ default?(props: {
61
+ registerMessageRef: (id: string, element: ComponentPublicInstance | null) => void;
62
+ }): VNode[];
61
63
  indicator?(props: {
62
64
  ui: ChatMessages['ui'];
63
65
  }): VNode[];
@@ -76,7 +78,9 @@ declare const __VLS_export: <T extends UIMessage[] = UIMessage[]>(__VLS_props: N
76
78
  props: import("vue").PublicProps & __VLS_PrettifyLocal<ChatMessagesProps<T>> & (typeof globalThis extends {
77
79
  __VLS_PROPS_FALLBACK: infer P;
78
80
  } ? P : {});
79
- expose: (exposed: {}) => void;
81
+ expose: (exposed: import("vue").ShallowUnwrapRef<{
82
+ registerMessageRef: (id: string, element: ComponentPublicInstance | null) => void;
83
+ }>) => void;
80
84
  attrs: any;
81
85
  slots: ChatMessagesSlots<T>;
82
86
  emit: {};