@nuxt/ui 4.10.0 → 4.11.1

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 (117) hide show
  1. package/.nuxt/ui.static.css +11 -11
  2. package/README.md +1 -0
  3. package/cli/commands/make/locale.mjs +40 -11
  4. package/cli/templates.mjs +2 -2
  5. package/dist/module.d.mts +1 -1
  6. package/dist/module.json +2 -2
  7. package/dist/module.mjs +5 -2
  8. package/dist/runtime/components/AuthForm.d.vue.ts +7 -7
  9. package/dist/runtime/components/AuthForm.vue.d.ts +7 -7
  10. package/dist/runtime/components/Button.vue +11 -2
  11. package/dist/runtime/components/Carousel.d.vue.ts +6 -6
  12. package/dist/runtime/components/Carousel.vue.d.ts +6 -6
  13. package/dist/runtime/components/ChatMessages.d.vue.ts +2 -2
  14. package/dist/runtime/components/ChatMessages.vue.d.ts +2 -2
  15. package/dist/runtime/components/ChatPromptSubmit.d.vue.ts +2 -2
  16. package/dist/runtime/components/ChatPromptSubmit.vue.d.ts +2 -2
  17. package/dist/runtime/components/Checkbox.d.vue.ts +1 -1
  18. package/dist/runtime/components/Checkbox.vue +12 -6
  19. package/dist/runtime/components/Checkbox.vue.d.ts +1 -1
  20. package/dist/runtime/components/CheckboxGroup.d.vue.ts +6 -0
  21. package/dist/runtime/components/CheckboxGroup.vue +10 -4
  22. package/dist/runtime/components/CheckboxGroup.vue.d.ts +6 -0
  23. package/dist/runtime/components/Editor.vue +4 -1
  24. package/dist/runtime/components/Error.d.vue.ts +1 -1
  25. package/dist/runtime/components/Error.vue.d.ts +1 -1
  26. package/dist/runtime/components/FileUpload.vue +17 -10
  27. package/dist/runtime/components/Form.vue +1 -1
  28. package/dist/runtime/components/Input.vue +12 -7
  29. package/dist/runtime/components/InputDate.vue +12 -8
  30. package/dist/runtime/components/InputMenu.vue +25 -11
  31. package/dist/runtime/components/InputNumber.vue +22 -14
  32. package/dist/runtime/components/InputRating.vue +10 -7
  33. package/dist/runtime/components/InputTags.vue +12 -7
  34. package/dist/runtime/components/InputTime.vue +12 -7
  35. package/dist/runtime/components/Link.vue +61 -7
  36. package/dist/runtime/components/Listbox.vue +10 -6
  37. package/dist/runtime/components/Modal.vue +12 -5
  38. package/dist/runtime/components/NavigationMenu.vue +10 -10
  39. package/dist/runtime/components/PinInput.vue +13 -8
  40. package/dist/runtime/components/Popover.vue +0 -1
  41. package/dist/runtime/components/PricingTable.d.vue.ts +1 -1
  42. package/dist/runtime/components/PricingTable.vue.d.ts +1 -1
  43. package/dist/runtime/components/Progress.d.vue.ts +2 -1
  44. package/dist/runtime/components/Progress.vue +5 -6
  45. package/dist/runtime/components/Progress.vue.d.ts +2 -1
  46. package/dist/runtime/components/ProgressGroup.d.vue.ts +91 -0
  47. package/dist/runtime/components/ProgressGroup.vue +99 -0
  48. package/dist/runtime/components/ProgressGroup.vue.d.ts +91 -0
  49. package/dist/runtime/components/RadioGroup.d.vue.ts +7 -1
  50. package/dist/runtime/components/RadioGroup.vue +14 -5
  51. package/dist/runtime/components/RadioGroup.vue.d.ts +7 -1
  52. package/dist/runtime/components/Select.d.vue.ts +2 -0
  53. package/dist/runtime/components/Select.vue +23 -8
  54. package/dist/runtime/components/Select.vue.d.ts +2 -0
  55. package/dist/runtime/components/SelectMenu.d.vue.ts +3 -0
  56. package/dist/runtime/components/SelectMenu.vue +35 -14
  57. package/dist/runtime/components/SelectMenu.vue.d.ts +3 -0
  58. package/dist/runtime/components/Slider.vue +15 -8
  59. package/dist/runtime/components/Splitter.d.vue.ts +266 -0
  60. package/dist/runtime/components/Splitter.vue +99 -0
  61. package/dist/runtime/components/Splitter.vue.d.ts +266 -0
  62. package/dist/runtime/components/Switch.vue +8 -4
  63. package/dist/runtime/components/Table.vue +5 -5
  64. package/dist/runtime/components/Textarea.vue +17 -7
  65. package/dist/runtime/components/Theme.d.vue.ts +1 -1
  66. package/dist/runtime/components/Theme.vue +4 -3
  67. package/dist/runtime/components/Theme.vue.d.ts +1 -1
  68. package/dist/runtime/components/Tree.vue +1 -1
  69. package/dist/runtime/components/color-mode/ColorModeSelect.vue +1 -0
  70. package/dist/runtime/components/content/ContentNavigation.vue +8 -1
  71. package/dist/runtime/components/content/ContentToc.vue +4 -1
  72. package/dist/runtime/components/locale/LocaleSelect.vue +1 -0
  73. package/dist/runtime/components/prose/CodeTree.vue +31 -18
  74. package/dist/runtime/composables/useComponentProps.d.ts +1 -1
  75. package/dist/runtime/composables/useComponentProps.js +6 -0
  76. package/dist/runtime/composables/useFormField.d.ts +10 -4
  77. package/dist/runtime/composables/useFormField.js +10 -3
  78. package/dist/runtime/keyframes.css +1 -1
  79. package/dist/runtime/locale/da.js +1 -1
  80. package/dist/runtime/locale/de_at.js +7 -0
  81. package/dist/runtime/locale/de_ch.js +1 -1
  82. package/dist/runtime/locale/eu.js +1 -1
  83. package/dist/runtime/locale/fi.js +1 -1
  84. package/dist/runtime/locale/he.js +1 -1
  85. package/dist/runtime/locale/hi.js +1 -1
  86. package/dist/runtime/locale/index.d.ts +2 -1
  87. package/dist/runtime/locale/index.js +2 -1
  88. package/dist/runtime/locale/is.js +1 -1
  89. package/dist/runtime/locale/lb.js +1 -1
  90. package/dist/runtime/locale/tg.d.ts +3 -0
  91. package/dist/runtime/locale/{tj.js → tg.js} +1 -1
  92. package/dist/runtime/locale/ur.js +1 -1
  93. package/dist/runtime/types/form.d.ts +1 -1
  94. package/dist/runtime/types/html.d.ts +3 -1
  95. package/dist/runtime/types/index.d.ts +2 -0
  96. package/dist/runtime/types/index.js +2 -0
  97. package/dist/runtime/types/theme.d.ts +2 -0
  98. package/dist/runtime/types/tv.d.ts +6 -2
  99. package/dist/runtime/utils/form.d.ts +1 -1
  100. package/dist/runtime/utils/form.js +3 -1
  101. package/dist/runtime/utils/link-keys.d.ts +1 -0
  102. package/dist/runtime/utils/link-keys.js +40 -0
  103. package/dist/runtime/utils/link.d.ts +2 -1
  104. package/dist/runtime/utils/link.js +2 -40
  105. package/dist/runtime/utils/prefetch.d.ts +5 -0
  106. package/dist/runtime/utils/prefetch.js +45 -0
  107. package/dist/runtime/utils/search.js +11 -18
  108. package/dist/runtime/utils/tv.d.ts +1 -1
  109. package/dist/runtime/utils/tv.js +103 -25
  110. package/dist/runtime/vue/components/Icon.vue +5 -2
  111. package/dist/runtime/vue/components/color-mode/ColorModeSelect.vue +1 -0
  112. package/dist/shared/{ui.XkBrgXFP.mjs → ui.DCJ9twx8.mjs} +597 -220
  113. package/dist/unplugin.d.mts +1 -1
  114. package/dist/unplugin.mjs +22 -6
  115. package/dist/vite.mjs +4 -4
  116. package/package.json +54 -53
  117. /package/dist/runtime/locale/{tj.d.ts → de_at.d.ts} +0 -0
@@ -177,7 +177,10 @@ const editor = useEditor({
177
177
  editor2.view.dispatch(editor2.state.tr);
178
178
  }
179
179
  },
180
- onUpdate: ({ editor: editor2 }) => {
180
+ onUpdate: ({ editor: editor2, transaction, appendedTransactions }) => {
181
+ if (!transaction.docChanged && !appendedTransactions.some((tr) => tr.docChanged)) {
182
+ return;
183
+ }
181
184
  let value;
182
185
  try {
183
186
  if (contentType.value === "html") {
@@ -47,9 +47,9 @@ export interface ErrorSlots {
47
47
  declare const _default: typeof __VLS_export;
48
48
  export default _default;
49
49
  declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<ErrorProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ErrorProps> & Readonly<{}>, {
50
+ redirect: string;
50
51
  clear: boolean | ButtonProps;
51
52
  as: any;
52
- redirect: string;
53
53
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, ErrorSlots>;
54
54
  type __VLS_WithSlots<T, S> = T & {
55
55
  new (): {
@@ -47,9 +47,9 @@ export interface ErrorSlots {
47
47
  declare const _default: typeof __VLS_export;
48
48
  export default _default;
49
49
  declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<ErrorProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ErrorProps> & Readonly<{}>, {
50
+ redirect: string;
50
51
  clear: boolean | ButtonProps;
51
52
  as: any;
52
- redirect: string;
53
53
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, ErrorSlots>;
54
54
  type __VLS_WithSlots<T, S> = T & {
55
55
  new (): {
@@ -59,7 +59,11 @@ const { isDragging, open, inputRef, dropzoneRef } = useFileUpload({
59
59
  dropzone: props.dropzone,
60
60
  onUpdate
61
61
  });
62
- const { emitFormInput, emitFormChange, id, name, color, highlight, disabled, ariaAttrs } = useFormField(_props);
62
+ const { emitFormInput, emitFormChange, id, name, size: formFieldSize, color: formFieldColor, highlight: formFieldHighlight, disabled: formFieldDisabled, ariaAttrs } = useFormField(_props);
63
+ const color = computed(() => formFieldColor.value ?? props.color);
64
+ const highlight = computed(() => formFieldHighlight.value ?? props.highlight);
65
+ const size = computed(() => formFieldSize.value ?? props.size);
66
+ const disabled = computed(() => formFieldDisabled.value ?? props.disabled);
63
67
  const variant = computed(() => props.multiple ? "area" : props.variant);
64
68
  const layout = computed(() => props.variant === "button" && !props.multiple ? "grid" : props.layout);
65
69
  const position = computed(() => {
@@ -74,14 +78,14 @@ const position = computed(() => {
74
78
  const ui = computed(() => tv({ extend: theme, ...appConfig.ui?.fileUpload || {} })({
75
79
  dropzone: props.dropzone,
76
80
  interactive: props.interactive,
77
- color: color.value ?? props.color,
78
- size: props.size,
81
+ color: color.value,
82
+ size: size.value,
79
83
  variant: variant.value,
80
84
  layout: layout.value,
81
85
  position: position.value,
82
86
  multiple: props.multiple,
83
- highlight: highlight.value ?? props.highlight,
84
- disabled: props.disabled
87
+ highlight: highlight.value,
88
+ disabled: disabled.value
85
89
  }));
86
90
  function createObjectUrl(file) {
87
91
  if (!props.fileImage) return void 0;
@@ -94,11 +98,14 @@ function formatFileSize(bytes) {
94
98
  const k = 1024;
95
99
  const sizes = ["B", "KB", "MB", "GB"];
96
100
  const i = Math.floor(Math.log(bytes) / Math.log(k));
97
- const size = bytes / Math.pow(k, i);
98
- const formattedSize = i === 0 ? size.toString() : size.toFixed(0);
101
+ const value = bytes / Math.pow(k, i);
102
+ const formattedSize = i === 0 ? value.toString() : value.toFixed(0);
99
103
  return `${formattedSize}${sizes[i]}`;
100
104
  }
101
105
  function onUpdate(files, reset2 = false) {
106
+ if (disabled.value) {
107
+ return;
108
+ }
102
109
  if (props.multiple) {
103
110
  if (reset2) {
104
111
  modelValue.value = files;
@@ -154,7 +161,7 @@ defineExpose({
154
161
  :as="{ img: 'img' }"
155
162
  :src="createObjectUrl(file)"
156
163
  :icon="props.fileIcon || appConfig.ui.icons.file"
157
- :size="props.size"
164
+ :size="size"
158
165
  data-slot="fileLeadingAvatar"
159
166
  :class="ui.fileLeadingAvatar({ class: props.ui?.fileLeadingAvatar })"
160
167
  />
@@ -184,7 +191,7 @@ defineExpose({
184
191
  size: 'xs'
185
192
  } : {
186
193
  variant: 'link',
187
- size: props.size
194
+ size
188
195
  },
189
196
  ...typeof props.fileDelete === 'object' ? props.fileDelete : void 0
190
197
  }"
@@ -227,7 +234,7 @@ defineExpose({
227
234
  <slot name="leading" :ui="ui">
228
235
  <template v-if="props.icon !== false">
229
236
  <UIcon v-if="variant === 'button'" :name="props.icon ?? appConfig.ui.icons.upload" data-slot="icon" :class="ui.icon({ class: props.ui?.icon })" />
230
- <UAvatar v-else :icon="props.icon ?? appConfig.ui.icons.upload" :size="props.size" data-slot="avatar" :class="ui.avatar({ class: props.ui?.avatar })" />
237
+ <UAvatar v-else :icon="props.icon ?? appConfig.ui.icons.upload" :size="size" data-slot="avatar" :class="ui.avatar({ class: props.ui?.avatar })" />
231
238
  </template>
232
239
  </slot>
233
240
 
@@ -294,7 +294,7 @@ defineExpose(api);
294
294
  :id="formId"
295
295
  ref="formRef"
296
296
  :name="parentBus ? void 0 : props.name"
297
- method="post"
297
+ :method="parentBus ? void 0 : 'post'"
298
298
  :class="ui({ class: [props.ui?.base, props.class] })"
299
299
  @submit.prevent="onSubmitWrapper"
300
300
  >
@@ -3,7 +3,7 @@ import theme from "#build/ui/input";
3
3
  </script>
4
4
 
5
5
  <script setup>
6
- import { useTemplateRef, computed, onMounted } from "vue";
6
+ import { useTemplateRef, computed, onMounted, onScopeDispose } from "vue";
7
7
  import { Primitive } from "reka-ui";
8
8
  import { useVModel } from "@vueuse/core";
9
9
  import { useAppConfig } from "#imports";
@@ -51,17 +51,20 @@ const slots = defineSlots();
51
51
  const props = useComponentProps("input", _props);
52
52
  const modelValue = useVModel(props, "modelValue", emits, { defaultValue: props.defaultValue });
53
53
  const appConfig = useAppConfig();
54
- const { emitFormBlur, emitFormInput, emitFormChange, size: formFieldSize, color, id, name, highlight, disabled, emitFormFocus, ariaAttrs } = useFormField(_props, { deferInputValidation: true });
54
+ const { emitFormBlur, emitFormInput, emitFormChange, size: formFieldSize, color: formFieldColor, id, name, highlight: formFieldHighlight, disabled: formFieldDisabled, emitFormFocus, ariaAttrs } = useFormField(_props, { deferInputValidation: true });
55
55
  const { orientation, size: fieldGroupSize } = useFieldGroup(_props);
56
56
  const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(props);
57
- const inputSize = computed(() => fieldGroupSize.value || formFieldSize.value);
57
+ const color = computed(() => formFieldColor.value ?? props.color);
58
+ const highlight = computed(() => formFieldHighlight.value ?? props.highlight);
59
+ const size = computed(() => fieldGroupSize.value ?? formFieldSize.value ?? props.size);
60
+ const disabled = computed(() => formFieldDisabled.value ?? props.disabled);
58
61
  const ui = computed(() => tv({ extend: theme, ...appConfig.ui?.input || {} })({
59
62
  type: props.type,
60
- color: color.value ?? props.color,
63
+ color: color.value,
61
64
  variant: props.variant,
62
- size: inputSize?.value ?? props.size,
65
+ size: size.value,
63
66
  loading: props.loading,
64
- highlight: highlight.value ?? props.highlight,
67
+ highlight: highlight.value,
65
68
  fixed: props.fixed,
66
69
  leading: isLeading.value || !!props.avatar || !!slots.leading,
67
70
  trailing: isTrailing.value || !!slots.trailing,
@@ -109,11 +112,13 @@ function autoFocus() {
109
112
  inputRef.value?.focus();
110
113
  }
111
114
  }
115
+ let autofocusTimeoutId;
112
116
  onMounted(() => {
113
- setTimeout(() => {
117
+ autofocusTimeoutId = setTimeout(() => {
114
118
  autoFocus();
115
119
  }, props.autofocusDelay);
116
120
  });
121
+ onScopeDispose(() => clearTimeout(autofocusTimeoutId));
117
122
  defineExpose({
118
123
  inputRef
119
124
  });
@@ -3,8 +3,7 @@ import theme from "#build/ui/input-date";
3
3
  </script>
4
4
 
5
5
  <script setup>
6
- import { computed, onMounted, ref } from "vue";
7
- import {} from "reka-ui";
6
+ import { computed, onMounted, onScopeDispose, ref } from "vue";
8
7
  import { useForwardProps } from "../composables/useForwardProps";
9
8
  import { DateField as SingleDateField, DateRangeField as RangeDateField } from "reka-ui/namespaced";
10
9
  import { reactiveOmit, createReusableTemplate } from "@vueuse/core";
@@ -62,16 +61,19 @@ const slots = defineSlots();
62
61
  const props = useComponentProps("inputDate", _props);
63
62
  const appConfig = useAppConfig();
64
63
  const rootProps = useForwardProps(reactiveOmit(props, "id", "name", "range", "modelValue", "defaultValue", "color", "variant", "size", "highlight", "fixed", "disabled", "autofocus", "autofocusDelay", "icon", "avatar", "leading", "leadingIcon", "trailing", "trailingIcon", "loading", "loadingIcon", "separatorIcon", "class", "ui"), emits);
65
- const { emitFormBlur, emitFormFocus, emitFormChange, emitFormInput, size: formFieldSize, color, id, name, highlight, disabled, ariaAttrs } = useFormField(_props);
64
+ const { emitFormBlur, emitFormFocus, emitFormChange, emitFormInput, size: formFieldSize, color: formFieldColor, id, name, highlight: formFieldHighlight, disabled: formFieldDisabled, ariaAttrs } = useFormField(_props);
66
65
  const { orientation, size: fieldGroupSize } = useFieldGroup(_props);
67
66
  const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(props);
68
67
  const [DefineSegmentsTemplate, ReuseSegmentsTemplate] = createReusableTemplate();
69
- const inputSize = computed(() => fieldGroupSize.value || formFieldSize.value);
68
+ const color = computed(() => formFieldColor.value ?? props.color);
69
+ const highlight = computed(() => formFieldHighlight.value ?? props.highlight);
70
+ const size = computed(() => fieldGroupSize.value ?? formFieldSize.value ?? props.size);
71
+ const disabled = computed(() => formFieldDisabled.value ?? props.disabled);
70
72
  const ui = computed(() => tv({ extend: theme, ...appConfig.ui?.inputDate || {} })({
71
- color: color.value ?? props.color,
73
+ color: color.value,
72
74
  variant: props.variant,
73
- size: inputSize.value ?? props.size,
74
- highlight: highlight.value ?? props.highlight,
75
+ size: size.value,
76
+ highlight: highlight.value,
75
77
  fixed: props.fixed,
76
78
  loading: props.loading,
77
79
  leading: isLeading.value || !!props.avatar || !!slots.leading,
@@ -101,11 +103,13 @@ function autoFocus() {
101
103
  inputsRef.value[0]?.$el?.focus();
102
104
  }
103
105
  }
106
+ let autofocusTimeoutId;
104
107
  onMounted(() => {
105
- setTimeout(() => {
108
+ autofocusTimeoutId = setTimeout(() => {
106
109
  autoFocus();
107
110
  }, props.autofocusDelay);
108
111
  });
112
+ onScopeDispose(() => clearTimeout(autofocusTimeoutId));
109
113
  const DateField = computed(() => props.range ? RangeDateField : SingleDateField);
110
114
  defineExpose({
111
115
  inputsRef
@@ -3,7 +3,7 @@ import theme from "#build/ui/input-menu";
3
3
  </script>
4
4
 
5
5
  <script setup>
6
- import { computed, ref, useAttrs, useTemplateRef, toRef, onMounted, toRaw, nextTick, watch } from "vue";
6
+ import { computed, ref, useAttrs, useTemplateRef, toRef, onMounted, onScopeDispose, toRaw, nextTick, watch } from "vue";
7
7
  import { TagsInputRoot, TagsInputItem, TagsInputItemText, TagsInputItemDelete, TagsInputInput } from "reka-ui";
8
8
  import { useForwardProps } from "../composables/useForwardProps";
9
9
  import { Combobox, Autocomplete } from "reka-ui/namespaced";
@@ -102,13 +102,24 @@ const clearProps = computed(() => typeof props.clear === "object" ? props.clear
102
102
  const virtualizerProps = toRef(() => {
103
103
  if (!props.virtualize) return false;
104
104
  return defu(typeof props.virtualize === "boolean" ? {} : props.virtualize, {
105
- estimateSize: getEstimateSize(filteredItems.value, inputSize.value || "md", props.descriptionKey, !!slots["item-description"])
105
+ estimateSize: getEstimateSize(filteredItems.value, size.value ?? "md", props.descriptionKey, !!slots["item-description"])
106
106
  });
107
107
  });
108
- const { emitFormBlur, emitFormFocus, emitFormChange, emitFormInput, size: formFieldSize, color, id, name, highlight, disabled, ariaAttrs } = useFormField(_props);
108
+ const { emitFormBlur, emitFormFocus, emitFormChange, emitFormInput, size: formFieldSize, color: formFieldColor, id, name, highlight: formFieldHighlight, disabled: formFieldDisabled, ariaAttrs } = useFormField(_props);
109
109
  const { orientation, size: fieldGroupSize } = useFieldGroup(_props);
110
- const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(toRef(() => defu(props, { trailingIcon: appConfig.ui.icons.chevronDown })));
111
- const inputSize = computed(() => fieldGroupSize.value || formFieldSize.value);
110
+ const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(computed(() => ({
111
+ icon: props.icon,
112
+ leading: props.leading,
113
+ leadingIcon: props.leadingIcon,
114
+ trailing: props.trailing,
115
+ trailingIcon: props.trailingIcon ?? appConfig.ui.icons.chevronDown,
116
+ loading: props.loading,
117
+ loadingIcon: props.loadingIcon
118
+ })));
119
+ const color = computed(() => formFieldColor.value ?? props.color);
120
+ const highlight = computed(() => formFieldHighlight.value ?? props.highlight);
121
+ const size = computed(() => fieldGroupSize.value ?? formFieldSize.value ?? props.size);
122
+ const disabled = computed(() => formFieldDisabled.value ?? props.disabled);
112
123
  const [DefineCreateItemTemplate, ReuseCreateItemTemplate] = createReusableTemplate();
113
124
  const [DefineItemTemplate, ReuseItemTemplate] = createReusableTemplate({
114
125
  props: {
@@ -123,11 +134,11 @@ const [DefineItemTemplate, ReuseItemTemplate] = createReusableTemplate({
123
134
  }
124
135
  });
125
136
  const ui = computed(() => tv({ extend: theme, ...appConfig.ui?.inputMenu || {} })({
126
- color: color.value ?? props.color,
137
+ color: color.value,
127
138
  variant: props.variant,
128
- size: inputSize?.value ?? props.size,
139
+ size: size.value,
129
140
  loading: props.loading,
130
- highlight: highlight.value ?? props.highlight,
141
+ highlight: highlight.value,
131
142
  fixed: props.fixed,
132
143
  leading: isLeading.value || !!props.avatar || !!slots.leading,
133
144
  trailing: isTrailing.value || !!slots.trailing,
@@ -174,6 +185,7 @@ function autoFocus() {
174
185
  inputRef.value?.$el?.focus();
175
186
  }
176
187
  }
188
+ let autofocusTimeoutId;
177
189
  onMounted(() => {
178
190
  nextTick(() => {
179
191
  if (isAutocomplete.value) {
@@ -182,10 +194,11 @@ onMounted(() => {
182
194
  searchTerm.value = "";
183
195
  }
184
196
  });
185
- setTimeout(() => {
197
+ autofocusTimeoutId = setTimeout(() => {
186
198
  autoFocus();
187
199
  }, props.autofocusDelay);
188
200
  });
201
+ onScopeDispose(() => clearTimeout(autofocusTimeoutId));
189
202
  watch(() => props.modelValue, (newValue) => {
190
203
  if (isAutocomplete.value) {
191
204
  searchTerm.value = String(newValue ?? "");
@@ -231,9 +244,10 @@ function onFocus(event) {
231
244
  emitFormFocus();
232
245
  }
233
246
  const isOpen = ref(false);
247
+ let timeoutId;
248
+ onScopeDispose(() => clearTimeout(timeoutId));
234
249
  function onUpdateOpen(value) {
235
250
  isOpen.value = value;
236
- let timeoutId;
237
251
  if (!value) {
238
252
  const event = new FocusEvent("blur");
239
253
  emits("blur", event);
@@ -453,7 +467,7 @@ defineExpose({
453
467
  <UButton
454
468
  as="span"
455
469
  :icon="props.clearIcon || appConfig.ui.icons.close"
456
- :size="inputSize"
470
+ :size="size"
457
471
  variant="link"
458
472
  color="neutral"
459
473
  tabindex="-1"
@@ -3,10 +3,10 @@ import theme from "#build/ui/input-number";
3
3
  </script>
4
4
 
5
5
  <script setup>
6
- import { onMounted, computed, useTemplateRef, toRef } from "vue";
6
+ import { onMounted, onScopeDispose, computed, useTemplateRef, toRef } from "vue";
7
7
  import { NumberFieldRoot, NumberFieldInput, NumberFieldDecrement, NumberFieldIncrement } from "reka-ui";
8
8
  import { useForwardProps } from "../composables/useForwardProps";
9
- import { reactivePick, useVModel } from "@vueuse/core";
9
+ import { reactivePick } from "@vueuse/core";
10
10
  import { useAppConfig } from "#imports";
11
11
  import { useComponentProps } from "../composables/useComponentProps";
12
12
  import { useFieldGroup } from "../composables/useFieldGroup";
@@ -55,18 +55,20 @@ const _props = defineProps({
55
55
  const emits = defineEmits(["update:modelValue", "blur", "change"]);
56
56
  defineSlots();
57
57
  const props = useComponentProps("inputNumber", _props);
58
- const modelValue = useVModel(props, "modelValue", emits, { defaultValue: props.defaultValue });
59
58
  const { t } = useLocale();
60
59
  const appConfig = useAppConfig();
61
- const rootProps = useForwardProps(reactivePick(props, "as", "stepSnapping", "formatOptions", "disableWheelChange", "invertWheelChange", "required", "readonly", "focusOnChange", "locale"), emits);
62
- const { emitFormBlur, emitFormFocus, emitFormChange, emitFormInput, id, color, size: formFieldSize, name, highlight, disabled, ariaAttrs } = useFormField(_props);
60
+ const rootProps = useForwardProps(reactivePick(props, "as", "stepSnapping", "formatOptions", "disableWheelChange", "invertWheelChange", "required", "readonly", "focusOnChange", "locale"));
61
+ const { emitFormBlur, emitFormFocus, emitFormChange, emitFormInput, id, color: formFieldColor, size: formFieldSize, name, highlight: formFieldHighlight, disabled: formFieldDisabled, ariaAttrs } = useFormField(_props);
63
62
  const { orientation, size: fieldGroupSize } = useFieldGroup(_props);
64
- const inputSize = computed(() => fieldGroupSize.value || formFieldSize.value);
63
+ const color = computed(() => formFieldColor.value ?? props.color);
64
+ const highlight = computed(() => formFieldHighlight.value ?? props.highlight);
65
+ const size = computed(() => fieldGroupSize.value ?? formFieldSize.value ?? props.size);
66
+ const disabled = computed(() => formFieldDisabled.value ?? props.disabled);
65
67
  const ui = computed(() => tv({ extend: theme, ...appConfig.ui?.inputNumber || {} })({
66
- color: color.value ?? props.color,
68
+ color: color.value,
67
69
  variant: props.variant,
68
- size: inputSize.value ?? props.size,
69
- highlight: highlight.value ?? props.highlight,
70
+ size: size.value,
71
+ highlight: highlight.value,
70
72
  fixed: props.fixed,
71
73
  orientation: props.orientation,
72
74
  fieldGroup: orientation.value,
@@ -78,8 +80,12 @@ const decrementIcon = computed(() => props.decrementIcon || (props.orientation =
78
80
  const inputRef = useTemplateRef("inputRef");
79
81
  function onUpdate(value) {
80
82
  if (props.modelModifiers?.optional) {
81
- modelValue.value = value = value ?? void 0;
83
+ value = value ?? void 0;
82
84
  }
85
+ if (value === props.modelValue || value == null && props.modelValue == null) {
86
+ return;
87
+ }
88
+ emits("update:modelValue", value);
83
89
  const event = new Event("change", { target: { value } });
84
90
  emits("change", event);
85
91
  emitFormChange();
@@ -94,11 +100,13 @@ function autoFocus() {
94
100
  inputRef.value?.$el?.focus();
95
101
  }
96
102
  }
103
+ let autofocusTimeoutId;
97
104
  onMounted(() => {
98
- setTimeout(() => {
105
+ autofocusTimeoutId = setTimeout(() => {
99
106
  autoFocus();
100
107
  }, props.autofocusDelay);
101
108
  });
109
+ onScopeDispose(() => clearTimeout(autofocusTimeoutId));
102
110
  defineExpose({
103
111
  inputRef: toRef(() => inputRef.value?.$el)
104
112
  });
@@ -109,7 +117,7 @@ defineExpose({
109
117
  v-bind="rootProps"
110
118
  :id="id"
111
119
  :default-value="props.defaultValue"
112
- :model-value="modelValue"
120
+ :model-value="props.modelValue"
113
121
  :min="props.min"
114
122
  :max="props.max"
115
123
  :step="props.step"
@@ -136,7 +144,7 @@ defineExpose({
136
144
  <UButton
137
145
  :icon="incrementIcon"
138
146
  :color="color"
139
- :size="inputSize"
147
+ :size="size"
140
148
  variant="link"
141
149
  :aria-label="t('inputNumber.increment')"
142
150
  v-bind="typeof props.increment === 'object' ? props.increment : void 0"
@@ -151,7 +159,7 @@ defineExpose({
151
159
  <UButton
152
160
  :icon="decrementIcon"
153
161
  :color="color"
154
- :size="inputSize"
162
+ :size="size"
155
163
  variant="link"
156
164
  :aria-label="t('inputNumber.decrement')"
157
165
  v-bind="typeof props.decrement === 'object' ? props.decrement : void 0"
@@ -39,14 +39,17 @@ defineSlots();
39
39
  const props = useComponentProps("inputRating", _props);
40
40
  const appConfig = useAppConfig();
41
41
  const rootProps = useForwardProps(reactivePick(props, "as", "length", "step", "hoverable", "clearable", "required", "modelValue", "defaultValue"), emits);
42
- const { id, emitFormChange, emitFormInput, size, color, name, disabled: formDisabled, ariaAttrs } = useFormField(_props);
43
- const disabled = computed(() => formDisabled.value || props.readonly);
42
+ const { id, emitFormChange, emitFormInput, size: formFieldSize, color: formFieldColor, name, disabled: formFieldDisabled, ariaAttrs } = useFormField(_props);
43
+ const color = computed(() => formFieldColor.value ?? props.color);
44
+ const size = computed(() => formFieldSize.value ?? props.size);
45
+ const disabled = computed(() => formFieldDisabled.value ?? props.disabled);
46
+ const rootDisabled = computed(() => disabled.value || props.readonly);
44
47
  const ui = computed(() => tv({ extend: theme, ...appConfig.ui?.inputRating || {} })({
45
- size: size.value ?? props.size,
46
- color: color.value ?? props.color,
48
+ size: size.value,
49
+ color: color.value,
47
50
  orientation: props.orientation,
48
- readonly: props.readonly && !formDisabled.value,
49
- disabled: formDisabled.value
51
+ readonly: props.readonly && !disabled.value,
52
+ disabled: disabled.value
50
53
  }));
51
54
  const starIcon = computed(() => props.icon ?? appConfig.ui.icons.star);
52
55
  function onUpdate(value) {
@@ -64,7 +67,7 @@ function onUpdate(value) {
64
67
  data-slot="root"
65
68
  v-bind="{ ...rootProps, ...$attrs, ...ariaAttrs }"
66
69
  :name="name"
67
- :disabled="disabled"
70
+ :disabled="rootDisabled"
68
71
  :aria-readonly="props.readonly || void 0"
69
72
  :orientation="props.orientation"
70
73
  :class="ui.root({ class: [props.ui?.root, props.class] })"
@@ -3,7 +3,7 @@ import theme from "#build/ui/input-tags";
3
3
  </script>
4
4
 
5
5
  <script setup>
6
- import { computed, useTemplateRef, onMounted, toRaw, toRef } from "vue";
6
+ import { computed, useTemplateRef, onMounted, onScopeDispose, toRaw, toRef } from "vue";
7
7
  import { TagsInputRoot, TagsInputItem, TagsInputItemText, TagsInputItemDelete, TagsInputInput } from "reka-ui";
8
8
  import { useForwardProps } from "../composables/useForwardProps";
9
9
  import { reactivePick } from "@vueuse/core";
@@ -58,16 +58,19 @@ const slots = defineSlots();
58
58
  const props = useComponentProps("inputTags", _props);
59
59
  const appConfig = useAppConfig();
60
60
  const rootProps = useForwardProps(reactivePick(props, "as", "addOnPaste", "addOnTab", "addOnBlur", "duplicate", "delimiter", "max", "convertValue", "displayValue", "required"), emits);
61
- const { emitFormBlur, emitFormFocus, emitFormChange, emitFormInput, size: formFieldSize, color, id, name, highlight, disabled, ariaAttrs } = useFormField(_props);
61
+ const { emitFormBlur, emitFormFocus, emitFormChange, emitFormInput, size: formFieldSize, color: formFieldColor, id, name, highlight: formFieldHighlight, disabled: formFieldDisabled, ariaAttrs } = useFormField(_props);
62
62
  const { orientation, size: fieldGroupSize } = useFieldGroup(_props);
63
63
  const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(props);
64
- const inputSize = computed(() => fieldGroupSize.value || formFieldSize.value);
64
+ const color = computed(() => formFieldColor.value ?? props.color);
65
+ const highlight = computed(() => formFieldHighlight.value ?? props.highlight);
66
+ const size = computed(() => fieldGroupSize.value ?? formFieldSize.value ?? props.size);
67
+ const disabled = computed(() => formFieldDisabled.value ?? props.disabled);
65
68
  const ui = computed(() => tv({ extend: theme, ...appConfig.ui?.inputTags || {} })({
66
- color: color.value ?? props.color,
69
+ color: color.value,
67
70
  variant: props.variant,
68
- size: inputSize?.value ?? props.size,
71
+ size: size.value,
69
72
  loading: props.loading,
70
- highlight: highlight.value ?? props.highlight,
73
+ highlight: highlight.value,
71
74
  fixed: props.fixed,
72
75
  leading: isLeading.value || !!props.avatar || !!slots.leading,
73
76
  trailing: isTrailing.value || !!slots.trailing,
@@ -79,11 +82,13 @@ function autoFocus() {
79
82
  inputRef.value?.$el?.focus();
80
83
  }
81
84
  }
85
+ let autofocusTimeoutId;
82
86
  onMounted(() => {
83
- setTimeout(() => {
87
+ autofocusTimeoutId = setTimeout(() => {
84
88
  autoFocus();
85
89
  }, props.autofocusDelay);
86
90
  });
91
+ onScopeDispose(() => clearTimeout(autofocusTimeoutId));
87
92
  function onUpdate(value) {
88
93
  if (toRaw(props.modelValue) === value) {
89
94
  return;
@@ -3,7 +3,7 @@ import theme from "#build/ui/input-time";
3
3
  </script>
4
4
 
5
5
  <script setup>
6
- import { computed, onMounted, ref } from "vue";
6
+ import { computed, onMounted, onScopeDispose, ref } from "vue";
7
7
  import { TimeRangeFieldRoot, TimeRangeFieldInput } from "reka-ui";
8
8
  import { useForwardProps } from "../composables/useForwardProps";
9
9
  import { TimeField as SingleTimeField } from "reka-ui/namespaced";
@@ -62,16 +62,19 @@ const slots = defineSlots();
62
62
  const props = useComponentProps("inputTime", _props);
63
63
  const appConfig = useAppConfig();
64
64
  const rootProps = useForwardProps(reactiveOmit(props, "id", "name", "range", "modelValue", "defaultValue", "color", "variant", "size", "highlight", "fixed", "disabled", "autofocus", "autofocusDelay", "icon", "avatar", "leading", "leadingIcon", "trailing", "trailingIcon", "loading", "loadingIcon", "separatorIcon", "class", "ui"), emits);
65
- const { emitFormBlur, emitFormFocus, emitFormChange, emitFormInput, id, color, size: formFieldSize, name, highlight, disabled, ariaAttrs } = useFormField(_props);
65
+ const { emitFormBlur, emitFormFocus, emitFormChange, emitFormInput, id, color: formFieldColor, size: formFieldSize, name, highlight: formFieldHighlight, disabled: formFieldDisabled, ariaAttrs } = useFormField(_props);
66
66
  const { orientation, size: fieldGroupSize } = useFieldGroup(_props);
67
67
  const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(props);
68
- const inputSize = computed(() => fieldGroupSize.value || formFieldSize.value);
68
+ const color = computed(() => formFieldColor.value ?? props.color);
69
+ const highlight = computed(() => formFieldHighlight.value ?? props.highlight);
70
+ const size = computed(() => fieldGroupSize.value ?? formFieldSize.value ?? props.size);
71
+ const disabled = computed(() => formFieldDisabled.value ?? props.disabled);
69
72
  const ui = computed(() => tv({ extend: theme, ...appConfig.ui?.inputTime || {} })({
70
- color: color.value ?? props.color,
73
+ color: color.value,
71
74
  variant: props.variant,
72
- size: inputSize.value ?? props.size,
75
+ size: size.value,
73
76
  loading: props.loading,
74
- highlight: highlight.value ?? props.highlight,
77
+ highlight: highlight.value,
75
78
  fixed: props.fixed,
76
79
  leading: isLeading.value || !!props.avatar || !!slots.leading,
77
80
  trailing: isTrailing.value || !!slots.trailing,
@@ -103,11 +106,13 @@ function autoFocus() {
103
106
  inputsRef.value[0]?.$el?.focus();
104
107
  }
105
108
  }
109
+ let autofocusTimeoutId;
106
110
  onMounted(() => {
107
- setTimeout(() => {
111
+ autofocusTimeoutId = setTimeout(() => {
108
112
  autoFocus();
109
113
  }, props.autofocusDelay);
110
114
  });
115
+ onScopeDispose(() => clearTimeout(autofocusTimeoutId));
111
116
  defineExpose({
112
117
  inputsRef
113
118
  });
@@ -3,16 +3,17 @@ import theme from "#build/ui/link";
3
3
  </script>
4
4
 
5
5
  <script setup>
6
- import { computed } from "vue";
6
+ import { computed, getCurrentInstance, mergeProps, onMounted, onBeforeUnmount } from "vue";
7
7
  import { isEqual } from "ohash/utils";
8
8
  import { useForwardProps, Slot } from "reka-ui";
9
9
  import { defu } from "defu";
10
10
  import { hasProtocol } from "ufo";
11
11
  import { reactiveOmit } from "@vueuse/core";
12
- import { useRoute, useAppConfig, useNuxtApp } from "#imports";
12
+ import { useRoute, useAppConfig, useNuxtApp, onNuxtReady } from "#imports";
13
13
  import { mergeClasses } from "../utils";
14
14
  import { tv } from "../utils/tv";
15
15
  import { isPartiallyEqual } from "../utils/link";
16
+ import { requestIdleCallback, cancelIdleCallback, observeIntersection } from "../utils/prefetch";
16
17
  import ULinkBase from "./LinkBase.vue";
17
18
  defineOptions({ inheritAttrs: false });
18
19
  const props = defineProps({
@@ -126,13 +127,63 @@ function isLinkActive({ route: linkRoute, isActive, isExactActive } = {}) {
126
127
  }
127
128
  return false;
128
129
  }
129
- function resolveLinkClass({ route: route2, isActive, isExactActive } = {}) {
130
+ function resolveLinkClass({ route: route2, isActive, isExactActive, prefetched } = {}) {
130
131
  const active = isLinkActive({ route: route2, isActive, isExactActive });
132
+ const prefetchedClass = prefetched ? props.prefetchedClass : void 0;
131
133
  if (props.raw) {
132
- return [props.class, active ? props.activeClass : props.inactiveClass];
134
+ return [props.class, active ? props.activeClass : props.inactiveClass, prefetchedClass];
133
135
  }
134
- return ui.value({ class: props.class, active, disabled: props.disabled });
136
+ return ui.value({ class: prefetchedClass ? [props.class, prefetchedClass] : props.class, active, disabled: props.disabled });
135
137
  }
138
+ const instance = getCurrentInstance();
139
+ let prefetchApi;
140
+ function onPrefetch() {
141
+ prefetchApi?.prefetch?.(nuxtApp);
142
+ }
143
+ function getPrefetchListeners({ prefetch, shouldPrefetch }, attrs) {
144
+ if (!prefetch || !shouldPrefetch) {
145
+ return void 0;
146
+ }
147
+ prefetchApi = { prefetch, shouldPrefetch };
148
+ if (!shouldPrefetch("interaction")) {
149
+ return void 0;
150
+ }
151
+ return mergeProps(
152
+ { onPointerenter: attrs.onPointerenter, onFocus: attrs.onFocus },
153
+ { onPointerenter: onPrefetch, onFocus: onPrefetch }
154
+ );
155
+ }
156
+ let idleId;
157
+ let unobserve = null;
158
+ let unmounted = false;
159
+ onMounted(() => {
160
+ if (!prefetchApi?.shouldPrefetch?.("visibility")) {
161
+ return;
162
+ }
163
+ const root = instance?.proxy?.$el;
164
+ const el = root instanceof Element ? root : root?.nextElementSibling;
165
+ if (!el) {
166
+ return;
167
+ }
168
+ onNuxtReady(() => {
169
+ if (unmounted) {
170
+ return;
171
+ }
172
+ idleId = requestIdleCallback(() => {
173
+ unobserve = observeIntersection(el, () => {
174
+ unobserve?.();
175
+ unobserve = null;
176
+ onPrefetch();
177
+ });
178
+ });
179
+ });
180
+ });
181
+ onBeforeUnmount(() => {
182
+ unmounted = true;
183
+ cancelIdleCallback(idleId);
184
+ unobserve?.();
185
+ unobserve = null;
186
+ });
136
187
  </script>
137
188
 
138
189
  <template>
@@ -142,6 +193,8 @@ function resolveLinkClass({ route: route2, isActive, isExactActive } = {}) {
142
193
  v-bind="{
143
194
  ...$attrs,
144
195
  ...exact && isExactActive ? { 'aria-current': props.ariaCurrentValue } : {},
196
+ ...rest.prefetched && prefetchedClass ? { class: prefetchedClass } : {},
197
+ ...getPrefetchListeners(rest, $attrs),
145
198
  as,
146
199
  type,
147
200
  disabled,
@@ -166,9 +219,10 @@ function resolveLinkClass({ route: route2, isActive, isExactActive } = {}) {
166
219
  navigate,
167
220
  rel,
168
221
  target: rest.target,
169
- isExternal: rest.isExternal
222
+ isExternal: rest.isExternal,
223
+ ...getPrefetchListeners(rest, $attrs)
170
224
  }"
171
- :class="resolveLinkClass({ route: linkRoute, isActive, isExactActive })"
225
+ :class="resolveLinkClass({ route: linkRoute, isActive, isExactActive, prefetched: rest.prefetched })"
172
226
  >
173
227
  <slot :active="isLinkActive({ route: linkRoute, isActive, isExactActive })" />
174
228
  </ULinkBase>