@nuxt/ui 4.11.2 → 4.11.3

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 (31) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +2 -2
  3. package/dist/runtime/components/App.vue +2 -1
  4. package/dist/runtime/components/AuthForm.d.vue.ts +4 -0
  5. package/dist/runtime/components/AuthForm.vue.d.ts +4 -0
  6. package/dist/runtime/components/ChatPrompt.vue +1 -1
  7. package/dist/runtime/components/DashboardSearch.vue +3 -3
  8. package/dist/runtime/components/DashboardSidebar.vue +3 -3
  9. package/dist/runtime/components/EditorToolbar.vue +6 -5
  10. package/dist/runtime/components/Form.d.vue.ts +2 -0
  11. package/dist/runtime/components/Form.vue +56 -29
  12. package/dist/runtime/components/Form.vue.d.ts +2 -0
  13. package/dist/runtime/components/Header.vue +3 -3
  14. package/dist/runtime/components/PinInput.d.vue.ts +3 -3
  15. package/dist/runtime/components/PinInput.vue.d.ts +3 -3
  16. package/dist/runtime/components/Select.vue +7 -1
  17. package/dist/runtime/components/SelectMenu.vue +7 -1
  18. package/dist/runtime/components/content/ContentSearch.vue +3 -3
  19. package/dist/runtime/composables/useFilter.js +7 -1
  20. package/dist/runtime/composables/useFormField.d.ts +1 -1
  21. package/dist/runtime/composables/useFormField.js +8 -4
  22. package/dist/runtime/composables/useOverlay.d.ts +2 -2
  23. package/dist/runtime/composables/useOverlay.js +5 -5
  24. package/dist/runtime/index.css +1 -1
  25. package/dist/runtime/types/form.d.ts +3 -0
  26. package/dist/runtime/utils/form.js +3 -20
  27. package/dist/runtime/utils/index.js +22 -18
  28. package/dist/shared/{ui.oNygBd3N.mjs → ui.CNAeRcb0.mjs} +17 -12
  29. package/dist/unplugin.mjs +1 -1
  30. package/dist/vite.mjs +1 -1
  31. package/package.json +7 -6
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuxt/ui",
3
- "version": "4.11.2",
3
+ "version": "4.11.3",
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, c as getDefaultConfig, g as getClientBundleIcons, f as publicComposables, a as addTemplates } from './shared/ui.oNygBd3N.mjs';
3
+ import { d as defaultOptions, r as resolveColors, c as getDefaultConfig, g as getClientBundleIcons, f as publicComposables, a as addTemplates } from './shared/ui.CNAeRcb0.mjs';
4
4
  import '../dist/runtime/utils/index.js';
5
5
  import 'node:url';
6
6
  import 'scule';
@@ -14,7 +14,7 @@ import 'tinyglobby';
14
14
  import 'mlly';
15
15
 
16
16
  const name = "@nuxt/ui";
17
- const version = "4.11.2";
17
+ const version = "4.11.3";
18
18
 
19
19
  const module$1 = defineNuxtModule({
20
20
  meta: {
@@ -12,6 +12,7 @@ import { localeContextInjectionKey } from "../composables/useLocale";
12
12
  import { portalTargetInjectionKey } from "../composables/usePortal";
13
13
  import UToaster from "./Toaster.vue";
14
14
  import UOverlayProvider from "./OverlayProvider.vue";
15
+ import en from "../locale/en";
15
16
  const props = defineProps({
16
17
  tooltip: { type: Object, required: false },
17
18
  toaster: { type: [Object, null], required: false },
@@ -25,7 +26,7 @@ defineSlots();
25
26
  const configProviderProps = useForwardProps(reactivePick(props, "scrollBody"));
26
27
  const tooltipProps = toRef(() => props.tooltip);
27
28
  const toasterProps = toRef(() => props.toaster);
28
- const locale = toRef(() => props.locale);
29
+ const locale = toRef(() => props.dir ? { ...props.locale || en, dir: props.dir } : props.locale);
29
30
  provide(localeContextInjectionKey, locale);
30
31
  const portal = toRef(() => props.portal);
31
32
  provide(portalTargetInjectionKey, portal);
@@ -119,12 +119,14 @@ declare const __VLS_export: <T extends FormSchema, F extends AuthFormField>(__VL
119
119
  silent?: false | undefined;
120
120
  nested?: boolean;
121
121
  transform?: T_1 | undefined;
122
+ isCurrent?: (() => boolean) | undefined;
122
123
  }): Promise<FormData<T, T_1>>;
123
124
  <T_1 extends boolean>(opts: {
124
125
  name?: keyof InferInput<T> | (keyof InferInput<T>)[] | undefined;
125
126
  silent?: true | undefined;
126
127
  nested?: boolean;
127
128
  transform?: T_1 | undefined;
129
+ isCurrent?: (() => boolean) | undefined;
128
130
  }): Promise<false | FormData<T, T_1>>;
129
131
  };
130
132
  errors: {
@@ -153,12 +155,14 @@ declare const __VLS_export: <T extends FormSchema, F extends AuthFormField>(__VL
153
155
  silent?: false | undefined;
154
156
  nested?: boolean;
155
157
  transform?: T_1 | undefined;
158
+ isCurrent?: (() => boolean) | undefined;
156
159
  }): Promise<FormData<T, T_1>>;
157
160
  <T_1 extends boolean>(opts: {
158
161
  name?: keyof InferInput<T> | (keyof InferInput<T>)[] | undefined;
159
162
  silent?: true | undefined;
160
163
  nested?: boolean;
161
164
  transform?: T_1 | undefined;
165
+ isCurrent?: (() => boolean) | undefined;
162
166
  }): Promise<false | FormData<T, T_1>>;
163
167
  };
164
168
  errors: {
@@ -119,12 +119,14 @@ declare const __VLS_export: <T extends FormSchema, F extends AuthFormField>(__VL
119
119
  silent?: false | undefined;
120
120
  nested?: boolean;
121
121
  transform?: T_1 | undefined;
122
+ isCurrent?: (() => boolean) | undefined;
122
123
  }): Promise<FormData<T, T_1>>;
123
124
  <T_1 extends boolean>(opts: {
124
125
  name?: keyof InferInput<T> | (keyof InferInput<T>)[] | undefined;
125
126
  silent?: true | undefined;
126
127
  nested?: boolean;
127
128
  transform?: T_1 | undefined;
129
+ isCurrent?: (() => boolean) | undefined;
128
130
  }): Promise<false | FormData<T, T_1>>;
129
131
  };
130
132
  errors: {
@@ -153,12 +155,14 @@ declare const __VLS_export: <T extends FormSchema, F extends AuthFormField>(__VL
153
155
  silent?: false | undefined;
154
156
  nested?: boolean;
155
157
  transform?: T_1 | undefined;
158
+ isCurrent?: (() => boolean) | undefined;
156
159
  }): Promise<FormData<T, T_1>>;
157
160
  <T_1 extends boolean>(opts: {
158
161
  name?: keyof InferInput<T> | (keyof InferInput<T>)[] | undefined;
159
162
  silent?: true | undefined;
160
163
  nested?: boolean;
161
164
  transform?: T_1 | undefined;
165
+ isCurrent?: (() => boolean) | undefined;
162
166
  }): Promise<false | FormData<T, T_1>>;
163
167
  };
164
168
  errors: {
@@ -83,7 +83,7 @@ defineExpose({
83
83
  </script>
84
84
 
85
85
  <template>
86
- <Primitive :as="props.as" :data-slot="$attrs['data-slot'] ?? 'root'" :class="ui.root({ class: [props.ui?.root, props.class] })" @submit.prevent="submit">
86
+ <Primitive :as="props.as" :method="props.as === 'form' ? 'post' : void 0" :data-slot="$attrs['data-slot'] ?? 'root'" :class="ui.root({ class: [props.ui?.root, props.class] })" @submit.prevent="submit">
87
87
  <div v-if="!!slots.header" data-slot="header" :class="ui.header({ class: props.ui?.header })">
88
88
  <slot name="header" />
89
89
  </div>
@@ -60,7 +60,7 @@ const searchTerm = defineModel("searchTerm", { type: String, ...{ default: "" }
60
60
  useRuntimeHook("dashboard:search:toggle", () => {
61
61
  open.value = !open.value;
62
62
  });
63
- const { t } = useLocale();
63
+ const { t, locale } = useLocale();
64
64
  const colorMode = useColorMode();
65
65
  const appConfig = useAppConfig();
66
66
  const commandPaletteProps = useForwardProps(reactivePick(props, "size", "icon", "trailingIcon", "selectedIcon", "childrenIcon", "placeholder", "autofocus", "loading", "loadingIcon", "close", "closeIcon", "back", "backIcon", "disabled", "highlightOnHover", "labelKey", "descriptionKey", "preserveGroupOrder", "virtualize", "searchDelay"));
@@ -136,8 +136,8 @@ defineExpose({
136
136
  <template>
137
137
  <UModal
138
138
  v-model:open="open"
139
- :title="props.title || t('dashboardSearch.title')"
140
- :description="props.description || t('dashboardSearch.description')"
139
+ :title="props.title || locale.messages.dashboardSearch?.title || t('dashboardSearchButton.label')"
140
+ :description="props.description || locale.messages.dashboardSearch?.description"
141
141
  v-bind="modalProps"
142
142
  data-slot="modal"
143
143
  :class="ui.modal({ class: [props.ui?.modal, props.class] })"
@@ -40,7 +40,7 @@ const props = useComponentProps("dashboardSidebar", _props);
40
40
  const open = defineModel("open", { type: Boolean, ...{ default: false } });
41
41
  const collapsed = defineModel("collapsed", { type: Boolean, ...{ default: false } });
42
42
  const route = useRoute();
43
- const { t } = useLocale();
43
+ const { t, locale } = useLocale();
44
44
  const appConfig = useAppConfig();
45
45
  const dashboardContext = useDashboard({
46
46
  storageKey: "dashboard",
@@ -134,8 +134,8 @@ function toggleOpen() {
134
134
 
135
135
  <Menu
136
136
  v-model:open="open"
137
- :title="t('dashboardSidebar.title')"
138
- :description="t('dashboardSidebar.description')"
137
+ :title="locale.messages.dashboardSidebar?.title || t('dashboardSidebarToggle.open')"
138
+ :description="locale.messages.dashboardSidebar?.description"
139
139
  v-bind="menuProps"
140
140
  :ui="{
141
141
  overlay: ui.overlay({ class: props.ui?.overlay }),
@@ -138,11 +138,12 @@ function getButtonProps(item) {
138
138
  }
139
139
  }
140
140
  return defu(baseProps, {
141
- color: props.color,
142
- activeColor: props.activeColor,
143
- activeVariant: props.activeVariant,
144
- variant: props.variant,
145
- size: props.size
141
+ "aria-label": baseProps.label ? void 0 : item.tooltip?.text,
142
+ "color": props.color,
143
+ "activeColor": props.activeColor,
144
+ "activeVariant": props.activeVariant,
145
+ "variant": props.variant,
146
+ "size": props.size
146
147
  });
147
148
  }
148
149
  function getDropdownProps(item) {
@@ -79,12 +79,14 @@ declare const __VLS_export: <S extends FormSchema, T extends boolean = true, N e
79
79
  silent?: false | undefined;
80
80
  nested?: boolean;
81
81
  transform?: T_1 | undefined;
82
+ isCurrent?: () => boolean;
82
83
  }): Promise<FormData<S, T_1>>;
83
84
  <T_1 extends boolean>(opts: {
84
85
  name?: keyof InferInput<S> | (keyof InferInput<S>)[] | undefined;
85
86
  silent?: true | undefined;
86
87
  nested?: boolean;
87
88
  transform?: T_1 | undefined;
89
+ isCurrent?: () => boolean;
88
90
  }): Promise<FormData<S, T_1> | false>;
89
91
  };
90
92
  errors: import("vue").Ref<{
@@ -3,7 +3,7 @@ import theme from "#build/ui/form";
3
3
  </script>
4
4
 
5
5
  <script setup>
6
- import { provide, inject, nextTick, ref, onUnmounted, onMounted, computed, useId, readonly, reactive, useTemplateRef } from "vue";
6
+ import { provide, inject, nextTick, ref, onUnmounted, onMounted, computed, useId, readonly, reactive, useTemplateRef, unref, toRaw } from "vue";
7
7
  import { useEventBus } from "@vueuse/core";
8
8
  import { useAppConfig } from "#imports";
9
9
  import { formOptionsInjectionKey, formInputsInjectionKey, formBusInjectionKey, formLoadingInjectionKey, formErrorsInjectionKey, formStateInjectionKey } from "../composables/useFormField";
@@ -54,7 +54,7 @@ const nestedForms = ref(/* @__PURE__ */ new Map());
54
54
  onMounted(async () => {
55
55
  if (parentBus) {
56
56
  await nextTick();
57
- parentBus.emit({ type: "attach", validate: _validate, formId, name: props.name, api });
57
+ parentBus.emit({ type: "attach", validate: _validate, clearDirty, formId, name: props.name, api });
58
58
  }
59
59
  });
60
60
  onUnmounted(() => {
@@ -66,25 +66,37 @@ onUnmounted(() => {
66
66
  onMounted(async () => {
67
67
  bus.on(async (event) => {
68
68
  if (event.type === "attach") {
69
- nestedForms.value.set(event.formId, { validate: event.validate, name: event.name, api: event.api });
70
- } else if (event.type === "detach") {
71
- nestedForms.value.delete(event.formId);
72
- } else if (props.validateOn?.includes(event.type) && !loading.value) {
73
- if (event.type !== "input") {
74
- await _validate({ name: event.name, silent: true, nested: false });
75
- } else if (event.eager || blurredFields.has(event.name)) {
76
- await _validate({ name: event.name, silent: true, nested: false });
77
- }
69
+ nestedForms.value.set(event.formId, { validate: event.validate, clearDirty: event.clearDirty, name: event.name, api: event.api });
70
+ return;
78
71
  }
79
- if (event.type === "blur") {
80
- blurredFields.add(event.name);
72
+ if (event.type === "detach") {
73
+ nestedForms.value.delete(event.formId);
74
+ return;
81
75
  }
82
- if (event.type === "change" || event.type === "input" || event.type === "blur" || event.type === "focus") {
76
+ if (event.track !== false) {
77
+ if (event.type === "blur") {
78
+ blurredFields.add(event.name);
79
+ }
80
+ if (event.type === "change" || event.type === "input") {
81
+ dirtyFields.add(event.name);
82
+ dirtyEpochs.set(event.name, epoch);
83
+ }
84
+ if (event.type === "input") {
85
+ inputEpochs.set(event.name, epoch);
86
+ }
83
87
  touchedFields.add(event.name);
84
88
  }
85
- if (event.type === "change" || event.type === "input") {
86
- dirtyFields.add(event.name);
87
- }
89
+ if (event.validate === false || !props.validateOn?.includes(event.type) || loading.value) return;
90
+ if (event.type === "input" && (inputEpochs.get(event.name) !== epoch || !(event.eager || blurredFields.has(event.name)))) return;
91
+ const run = (validationRuns.get(event.name) ?? 0) + 1;
92
+ validationRuns.set(event.name, run);
93
+ const startEpoch = epoch;
94
+ await _validate({
95
+ name: event.name,
96
+ silent: true,
97
+ nested: false,
98
+ isCurrent: () => validationRuns.get(event.name) === run && epoch === startEpoch
99
+ });
88
100
  });
89
101
  });
90
102
  const errors = ref([]);
@@ -94,6 +106,18 @@ provide(formInputsInjectionKey, inputs);
94
106
  const dirtyFields = reactive(/* @__PURE__ */ new Set());
95
107
  const touchedFields = reactive(/* @__PURE__ */ new Set());
96
108
  const blurredFields = reactive(/* @__PURE__ */ new Set());
109
+ let epoch = 0;
110
+ const inputEpochs = /* @__PURE__ */ new Map();
111
+ const validationRuns = /* @__PURE__ */ new Map();
112
+ const dirtyEpochs = /* @__PURE__ */ new Map();
113
+ function clearDirty() {
114
+ for (const field of dirtyFields) {
115
+ if (dirtyEpochs.get(field) !== epoch) dirtyFields.delete(field);
116
+ }
117
+ for (const form of nestedForms.value.values()) {
118
+ form.clearDirty();
119
+ }
120
+ }
97
121
  function resolveErrorIds(errs) {
98
122
  return errs.map((err) => ({
99
123
  ...err,
@@ -115,6 +139,7 @@ async function getErrors() {
115
139
  }
116
140
  async function _validate(opts = { silent: false, nested: false, transform: false }) {
117
141
  const names = opts.name && !Array.isArray(opts.name) ? [opts.name] : opts.name;
142
+ if (!names) epoch++;
118
143
  let nestedResults = [];
119
144
  let nestedErrors = [];
120
145
  if (!names && opts.nested) {
@@ -126,25 +151,30 @@ async function _validate(opts = { silent: false, nested: false, transform: false
126
151
  nestedResults = results.filter((r) => r.output !== void 0);
127
152
  }
128
153
  const currentErrors = await getErrors();
154
+ if (opts.isCurrent?.() === false) return false;
129
155
  const allErrors = [...currentErrors, ...nestedErrors];
156
+ let failedErrors = allErrors;
130
157
  if (names) {
131
- errors.value = filterErrorsByNames(allErrors, names);
158
+ const matchesNames = nameMatcher(names);
159
+ failedErrors = allErrors.filter(matchesNames);
160
+ errors.value = [...errors.value.filter((error) => !matchesNames(error)), ...failedErrors];
132
161
  } else {
133
162
  errors.value = allErrors;
134
163
  }
135
- if (errors.value?.length) {
164
+ if (failedErrors.length) {
136
165
  if (opts.silent) return false;
137
- throw new FormValidationException(formId, errors.value);
166
+ throw new FormValidationException(formId, failedErrors);
138
167
  }
139
168
  if (opts.transform) {
169
+ let output = transformedState.value;
140
170
  nestedResults.forEach((result) => {
141
171
  if (result.name) {
142
172
  setAtPath(transformedState.value, result.name, result.output);
143
173
  } else {
144
- Object.assign(transformedState.value, result.output);
174
+ output = Object.assign(output ?? { ...toRaw(state.value) }, result.output);
145
175
  }
146
176
  });
147
- return transformedState.value ?? state.value;
177
+ return output ?? state.value;
148
178
  }
149
179
  return state.value;
150
180
  }
@@ -156,7 +186,7 @@ async function onSubmitWrapper(payload) {
156
186
  try {
157
187
  event.data = await _validate({ nested: true, transform: props.transform });
158
188
  await props.onSubmit?.(event);
159
- dirtyFields.clear();
189
+ clearDirty();
160
190
  } catch (error) {
161
191
  if (!(error instanceof FormValidationException)) {
162
192
  throw error;
@@ -215,17 +245,14 @@ function getNestedTarget(target, formPath) {
215
245
  }
216
246
  return target;
217
247
  }
218
- function filterErrorsByNames(allErrors, names) {
248
+ function nameMatcher(names) {
219
249
  const nameSet = new Set(names);
220
250
  const patterns = names.map((name) => inputs.value?.[name]?.pattern).filter(Boolean);
221
- const matchesNames = (error) => {
251
+ return (error) => {
222
252
  if (!error.name) return false;
223
253
  if (nameSet.has(error.name)) return true;
224
254
  return patterns.some((pattern) => pattern.test(error.name));
225
255
  };
226
- const keepErrors = errors.value.filter((error) => !matchesNames(error));
227
- const newErrors = allErrors.filter(matchesNames);
228
- return [...keepErrors, ...newErrors];
229
256
  }
230
257
  function filterErrorsByTarget(currentErrors, target) {
231
258
  return currentErrors.filter(
@@ -280,7 +307,7 @@ const api = {
280
307
  },
281
308
  disabled,
282
309
  loading,
283
- dirty: computed(() => !!dirtyFields.size),
310
+ dirty: computed(() => !!dirtyFields.size || Array.from(nestedForms.value.values()).some((form) => unref(form.api.dirty))),
284
311
  dirtyFields: readonly(dirtyFields),
285
312
  blurredFields: readonly(blurredFields),
286
313
  touchedFields: readonly(touchedFields)
@@ -79,12 +79,14 @@ declare const __VLS_export: <S extends FormSchema, T extends boolean = true, N e
79
79
  silent?: false | undefined;
80
80
  nested?: boolean;
81
81
  transform?: T_1 | undefined;
82
+ isCurrent?: () => boolean;
82
83
  }): Promise<FormData<S, T_1>>;
83
84
  <T_1 extends boolean>(opts: {
84
85
  name?: keyof InferInput<S> | (keyof InferInput<S>)[] | undefined;
85
86
  silent?: true | undefined;
86
87
  nested?: boolean;
87
88
  transform?: T_1 | undefined;
89
+ isCurrent?: () => boolean;
88
90
  }): Promise<FormData<S, T_1> | false>;
89
91
  };
90
92
  errors: import("vue").Ref<{
@@ -35,7 +35,7 @@ const slots = defineSlots();
35
35
  const props = useComponentProps("header", _props);
36
36
  const open = defineModel("open", { type: Boolean, ...{ default: false } });
37
37
  const route = useRoute();
38
- const { t } = useLocale();
38
+ const { t, locale } = useLocale();
39
39
  const appConfig = useAppConfig();
40
40
  const [DefineLeftTemplate, ReuseLeftTemplate] = createReusableTemplate();
41
41
  const [DefineRightTemplate, ReuseRightTemplate] = createReusableTemplate();
@@ -117,8 +117,8 @@ function toggleOpen() {
117
117
 
118
118
  <Menu
119
119
  v-model:open="open"
120
- :title="t('header.title')"
121
- :description="t('header.description')"
120
+ :title="locale.messages.header?.title || t('header.open')"
121
+ :description="locale.messages.header?.description"
122
122
  v-bind="menuProps"
123
123
  :ui="{
124
124
  overlay: ui.overlay({ class: props.ui?.overlay }),
@@ -60,8 +60,8 @@ declare const __VLS_export: <T extends PinInputType>(__VLS_props: NonNullable<Aw
60
60
  onBlur?: ((event: Event) => any) | undefined;
61
61
  onChange?: ((event: Event) => any) | undefined;
62
62
  onFocus?: ((event: Event) => any) | undefined;
63
- "onUpdate:modelValue"?: ((value: [T] extends ["number"] ? number[] : string[]) => any) | undefined;
64
- onComplete?: ((value: [T] extends ["number"] ? number[] : string[]) => any) | undefined;
63
+ "onUpdate:modelValue"?: ((value: [T] extends ["number"] ? (number | undefined)[] : string[]) => any) | undefined;
64
+ onComplete?: ((value: [T] extends ["number"] ? (number | undefined)[] : string[]) => any) | undefined;
65
65
  }> & (typeof globalThis extends {
66
66
  __VLS_PROPS_FALLBACK: infer P;
67
67
  } ? P : {});
@@ -70,7 +70,7 @@ declare const __VLS_export: <T extends PinInputType>(__VLS_props: NonNullable<Aw
70
70
  }>) => void;
71
71
  attrs: any;
72
72
  slots: PinInputSlots;
73
- emit: ((evt: "blur", event: Event) => void) & ((evt: "change", event: Event) => void) & ((evt: "focus", event: Event) => void) & ((evt: "update:modelValue", value: [T] extends ["number"] ? number[] : string[]) => void) & ((evt: "complete", value: [T] extends ["number"] ? number[] : string[]) => void);
73
+ emit: ((evt: "blur", event: Event) => void) & ((evt: "change", event: Event) => void) & ((evt: "focus", event: Event) => void) & ((evt: "update:modelValue", value: [T] extends ["number"] ? (number | undefined)[] : string[]) => void) & ((evt: "complete", value: [T] extends ["number"] ? (number | undefined)[] : string[]) => void);
74
74
  }>) => import("vue").VNode & {
75
75
  __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
76
76
  };
@@ -60,8 +60,8 @@ declare const __VLS_export: <T extends PinInputType>(__VLS_props: NonNullable<Aw
60
60
  onBlur?: ((event: Event) => any) | undefined;
61
61
  onChange?: ((event: Event) => any) | undefined;
62
62
  onFocus?: ((event: Event) => any) | undefined;
63
- "onUpdate:modelValue"?: ((value: [T] extends ["number"] ? number[] : string[]) => any) | undefined;
64
- onComplete?: ((value: [T] extends ["number"] ? number[] : string[]) => any) | undefined;
63
+ "onUpdate:modelValue"?: ((value: [T] extends ["number"] ? (number | undefined)[] : string[]) => any) | undefined;
64
+ onComplete?: ((value: [T] extends ["number"] ? (number | undefined)[] : string[]) => any) | undefined;
65
65
  }> & (typeof globalThis extends {
66
66
  __VLS_PROPS_FALLBACK: infer P;
67
67
  } ? P : {});
@@ -70,7 +70,7 @@ declare const __VLS_export: <T extends PinInputType>(__VLS_props: NonNullable<Aw
70
70
  }>) => void;
71
71
  attrs: any;
72
72
  slots: PinInputSlots;
73
- emit: ((evt: "blur", event: Event) => void) & ((evt: "change", event: Event) => void) & ((evt: "focus", event: Event) => void) & ((evt: "update:modelValue", value: [T] extends ["number"] ? number[] : string[]) => void) & ((evt: "complete", value: [T] extends ["number"] ? number[] : string[]) => void);
73
+ emit: ((evt: "blur", event: Event) => void) & ((evt: "change", event: Event) => void) & ((evt: "focus", event: Event) => void) & ((evt: "update:modelValue", value: [T] extends ["number"] ? (number | undefined)[] : string[]) => void) & ((evt: "complete", value: [T] extends ["number"] ? (number | undefined)[] : string[]) => void);
74
74
  }>) => import("vue").VNode & {
75
75
  __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
76
76
  };
@@ -167,6 +167,12 @@ function onTriggerClick(open) {
167
167
  triggerRef.value?.$el?.dispatchEvent(new PointerEvent("pointerdown", { bubbles: true, button: 0 }));
168
168
  }
169
169
  }
170
+ function onCloseAutoFocus(event) {
171
+ const activeElement = document.activeElement;
172
+ if (activeElement && activeElement !== document.body && !event.target.contains(activeElement)) {
173
+ event.preventDefault();
174
+ }
175
+ }
170
176
  const viewportRef = useTemplateRef("viewportRef");
171
177
  defineExpose({
172
178
  triggerRef: toRef(() => triggerRef.value?.$el),
@@ -224,7 +230,7 @@ defineExpose({
224
230
 
225
231
  <SelectPortal v-bind="portalProps">
226
232
  <FieldGroupReset>
227
- <SelectContent data-slot="content" :class="ui.content({ class: props.ui?.content })" v-bind="contentProps">
233
+ <SelectContent data-slot="content" :class="ui.content({ class: props.ui?.content })" v-bind="contentProps" @close-auto-focus="onCloseAutoFocus">
228
234
  <slot name="content-top" />
229
235
 
230
236
  <component :is="isItemAligned ? SelectViewport : 'div'" ref="viewportRef" role="presentation" data-slot="viewport" :class="ui.viewport({ class: props.ui?.viewport })">
@@ -280,6 +280,12 @@ function onMountAutoFocus(event) {
280
280
  event.preventDefault();
281
281
  }
282
282
  }
283
+ function onUnmountAutoFocus(event) {
284
+ const activeElement = document.activeElement;
285
+ if (activeElement && activeElement !== document.body && !event.target.contains(activeElement)) {
286
+ event.preventDefault();
287
+ }
288
+ }
283
289
  const viewportRef = useTemplateRef("viewportRef");
284
290
  const comboboxRootRef = useTemplateRef("comboboxRootRef");
285
291
  watch(() => props.items, async () => {
@@ -432,7 +438,7 @@ defineExpose({
432
438
  <ComboboxPortal v-bind="portalProps">
433
439
  <FieldGroupReset>
434
440
  <ComboboxContent data-slot="content" :class="ui.content({ class: props.ui?.content })" v-bind="contentProps">
435
- <FocusScope trapped data-slot="focusScope" :class="ui.focusScope({ class: props.ui?.focusScope })" @mount-auto-focus="onMountAutoFocus">
441
+ <FocusScope loop data-slot="focusScope" :class="ui.focusScope({ class: props.ui?.focusScope })" @mount-auto-focus="onMountAutoFocus" @unmount-auto-focus="onUnmountAutoFocus">
436
442
  <slot name="content-top" />
437
443
 
438
444
  <ComboboxInput v-if="!!props.searchInput" v-model="searchTerm" :display-value="() => searchTerm" as-child>
@@ -62,7 +62,7 @@ const _props = defineProps({
62
62
  const slots = defineSlots();
63
63
  const props = useComponentProps("contentSearch", _props);
64
64
  const searchTerm = defineModel("searchTerm", { type: String, ...{ default: "" } });
65
- const { t } = useLocale();
65
+ const { t, locale } = useLocale();
66
66
  const { open, mapNavigationItems, mapLinks, mapSearchResults, postFilter } = useContentSearch();
67
67
  const colorMode = useColorMode();
68
68
  const appConfig = useAppConfig();
@@ -214,8 +214,8 @@ defineExpose({
214
214
  <template>
215
215
  <UModal
216
216
  v-model:open="open"
217
- :title="props.title || t('contentSearch.title')"
218
- :description="props.description || t('contentSearch.description')"
217
+ :title="props.title || locale.messages.contentSearch?.title || t('contentSearchButton.label')"
218
+ :description="props.description || locale.messages.contentSearch?.description"
219
219
  v-bind="modalProps"
220
220
  data-slot="modal"
221
221
  :class="ui.modal({ class: [props.ui?.modal, props.class] })"
@@ -52,7 +52,13 @@ export function useFilter() {
52
52
  result.push({ item, score: s });
53
53
  }
54
54
  }
55
- result.sort((a, b) => a.score - b.score);
55
+ let start = 0;
56
+ for (let i = 0; i <= result.length; i++) {
57
+ if (i === result.length || result[i].score === -1) {
58
+ result.splice(start, i - start, ...result.slice(start, i).sort((a, b) => a.score - b.score));
59
+ start = i + 1;
60
+ }
61
+ }
56
62
  return result.map(({ item }) => item);
57
63
  }).filter((group) => group.some((item) => !options.isStructural?.(item)));
58
64
  }
@@ -59,7 +59,7 @@ export declare function useFormField<T>(props?: Props<T>, opts?: {
59
59
  highlight: ComputedRef<true | undefined>;
60
60
  disabled: ComputedRef<true | undefined>;
61
61
  emitFormBlur: () => void;
62
- emitFormInput: import("@vueuse/shared").UseDebounceFnReturn<() => void>;
62
+ emitFormInput: () => import("@vueuse/shared").Promisify<void>;
63
63
  emitFormChange: () => void;
64
64
  emitFormFocus: () => void;
65
65
  ariaAttrs: ComputedRef<Record<string, any> | undefined>;
@@ -21,9 +21,9 @@ export function useFormField(props, opts) {
21
21
  inputId.value = props?.id;
22
22
  }
23
23
  }
24
- function emitFormEvent(type, name, eager) {
24
+ function emitFormEvent(type, name, flags) {
25
25
  if (formBus && formField && name) {
26
- formBus.emit({ type, name, eager });
26
+ formBus.emit({ type, name, ...flags });
27
27
  }
28
28
  }
29
29
  function emitFormBlur() {
@@ -41,13 +41,17 @@ export function useFormField(props, opts) {
41
41
  disposed = true;
42
42
  });
43
43
  }
44
- const emitFormInput = useDebounceFn(
44
+ const validateInput = useDebounceFn(
45
45
  () => {
46
46
  if (disposed) return;
47
- emitFormEvent("input", formField?.value.name, !opts?.deferInputValidation || formField?.value.eagerValidation);
47
+ emitFormEvent("input", formField?.value.name, { eager: !opts?.deferInputValidation || formField?.value.eagerValidation, track: false });
48
48
  },
49
49
  formField?.value.validateOnInputDelay ?? formOptions?.value.validateOnInputDelay ?? 0
50
50
  );
51
+ function emitFormInput() {
52
+ emitFormEvent("input", formField?.value.name, { validate: false });
53
+ return validateInput();
54
+ }
51
55
  return {
52
56
  id: computed(() => props?.id ?? inputId?.value),
53
57
  name: computed(() => props?.name ?? formField?.value.name),
@@ -41,7 +41,7 @@ interface ManagedOverlayOptionsPrivate<T extends Component> {
41
41
  isMounted: boolean;
42
42
  isOpen: boolean;
43
43
  originalProps?: ComponentProps<T>;
44
- resolvePromise?: (value: any) => void;
44
+ resolvers: ((value: any) => void)[];
45
45
  }
46
46
  export type Overlay = OverlayOptions<Component> & ManagedOverlayOptionsPrivate<Component>;
47
47
  type OverlayInstance<T extends Component> = Omit<ManagedOverlayOptionsPrivate<T>, 'component'> & {
@@ -50,7 +50,7 @@ type OverlayInstance<T extends Component> = Omit<ManagedOverlayOptionsPrivate<T>
50
50
  close: (value?: any) => void;
51
51
  patch: (props: Partial<ComponentProps<T>>) => void;
52
52
  };
53
- type OpenedOverlay<T extends Component> = Omit<OverlayInstance<T>, 'open' | 'close' | 'patch' | 'modelValue' | 'resolvePromise'> & {
53
+ type OpenedOverlay<T extends Component> = Omit<OverlayInstance<T>, 'open' | 'close' | 'patch' | 'modelValue' | 'resolvers'> & {
54
54
  result: Promise<CloseEventArgType<ComponentEmit<T>>>;
55
55
  } & Promise<CloseEventArgType<ComponentEmit<T>>>;
56
56
  declare function _useOverlay(): {
@@ -11,7 +11,8 @@ function _useOverlay() {
11
11
  isMounted: !!defaultOpen,
12
12
  destroyOnClose: !!destroyOnClose,
13
13
  originalProps: props || {},
14
- props: { ...props }
14
+ props: { ...props },
15
+ resolvers: []
15
16
  });
16
17
  overlays.push(options);
17
18
  return {
@@ -30,7 +31,7 @@ function _useOverlay() {
30
31
  }
31
32
  overlay.isOpen = true;
32
33
  overlay.isMounted = true;
33
- const result = new Promise((resolve) => overlay.resolvePromise = resolve);
34
+ const result = new Promise((resolve) => overlay.resolvers.push(resolve));
34
35
  return Object.assign(result, {
35
36
  id,
36
37
  isMounted: overlay.isMounted,
@@ -41,9 +42,8 @@ function _useOverlay() {
41
42
  const close = (id, value) => {
42
43
  const overlay = getOverlay(id);
43
44
  overlay.isOpen = false;
44
- if (overlay.resolvePromise) {
45
- overlay.resolvePromise(value);
46
- overlay.resolvePromise = void 0;
45
+ for (const resolve of overlay.resolvers.splice(0)) {
46
+ resolve(value);
47
47
  }
48
48
  };
49
49
  const closeAll = () => {
@@ -1 +1 @@
1
- @import "#build/ui.css";@import "./keyframes.css";@source "./components";@variant light (&:where(.light, .light *));@variant dark (&:where(.dark, .dark *));@layer base{a:focus-visible{outline-offset:0}}@layer theme{:host,:root{--ui-header-height:4rem;--ui-radius:0.25rem;--ui-container:80rem}.light,:host,:root{--ui-text-dimmed:var(--ui-color-neutral-400);--ui-text-muted:var(--ui-color-neutral-500);--ui-text-toned:var(--ui-color-neutral-600);--ui-text:var(--ui-color-neutral-700);--ui-text-highlighted:var(--ui-color-neutral-900);--ui-text-inverted:#fff;--ui-bg:#fff;--ui-bg-muted:var(--ui-color-neutral-50);--ui-bg-elevated:var(--ui-color-neutral-100);--ui-bg-accented:var(--ui-color-neutral-200);--ui-bg-inverted:var(--ui-color-neutral-900);--ui-border:var(--ui-color-neutral-200);--ui-border-muted:var(--ui-color-neutral-200);--ui-border-accented:var(--ui-color-neutral-300);--ui-border-inverted:var(--ui-color-neutral-900)}.dark{--ui-text-dimmed:var(--ui-color-neutral-500);--ui-text-muted:var(--ui-color-neutral-400);--ui-text-toned:var(--ui-color-neutral-300);--ui-text:var(--ui-color-neutral-200);--ui-text-highlighted:#fff;--ui-text-inverted:var(--ui-color-neutral-900);--ui-bg:var(--ui-color-neutral-900);--ui-bg-muted:var(--ui-color-neutral-800);--ui-bg-elevated:var(--ui-color-neutral-800);--ui-bg-accented:var(--ui-color-neutral-700);--ui-bg-inverted:#fff;--ui-border:var(--ui-color-neutral-800);--ui-border-muted:var(--ui-color-neutral-700);--ui-border-accented:var(--ui-color-neutral-700);--ui-border-inverted:#fff}}
1
+ @import "#build/ui.css";@import "./keyframes.css";@source "./components";@custom-variant light (&:where(.light, .light *));@custom-variant dark (&:where(.dark, .dark *));@layer base{a:focus-visible{outline-offset:0}}@layer theme{:host,:root{--ui-header-height:4rem;--ui-radius:0.25rem;--ui-container:80rem}.light,:host,:root{--ui-text-dimmed:var(--ui-color-neutral-400);--ui-text-muted:var(--ui-color-neutral-500);--ui-text-toned:var(--ui-color-neutral-600);--ui-text:var(--ui-color-neutral-700);--ui-text-highlighted:var(--ui-color-neutral-900);--ui-text-inverted:#fff;--ui-bg:#fff;--ui-bg-muted:var(--ui-color-neutral-50);--ui-bg-elevated:var(--ui-color-neutral-100);--ui-bg-accented:var(--ui-color-neutral-200);--ui-bg-inverted:var(--ui-color-neutral-900);--ui-border:var(--ui-color-neutral-200);--ui-border-muted:var(--ui-color-neutral-200);--ui-border-accented:var(--ui-color-neutral-300);--ui-border-inverted:var(--ui-color-neutral-900)}.dark{--ui-text-dimmed:var(--ui-color-neutral-500);--ui-text-muted:var(--ui-color-neutral-400);--ui-text-toned:var(--ui-color-neutral-300);--ui-text:var(--ui-color-neutral-200);--ui-text-highlighted:#fff;--ui-text-inverted:var(--ui-color-neutral-900);--ui-bg:var(--ui-color-neutral-900);--ui-bg-muted:var(--ui-color-neutral-800);--ui-bg-elevated:var(--ui-color-neutral-800);--ui-bg-accented:var(--ui-color-neutral-700);--ui-bg-inverted:#fff;--ui-border:var(--ui-color-neutral-800);--ui-border-muted:var(--ui-color-neutral-700);--ui-border-accented:var(--ui-color-neutral-700);--ui-border-inverted:#fff}}
@@ -46,6 +46,7 @@ export type FormChildAttachEvent<S extends FormSchema> = {
46
46
  type: 'attach';
47
47
  formId: string | number;
48
48
  validate: Form<any>['validate'];
49
+ clearDirty: () => void;
49
50
  name?: string;
50
51
  api: Form<S>;
51
52
  };
@@ -57,6 +58,8 @@ export type FormInputEvent<T extends object> = {
57
58
  type: FormEventType;
58
59
  name: keyof T;
59
60
  eager?: boolean;
61
+ track?: boolean;
62
+ validate?: boolean;
60
63
  };
61
64
  export type FormEvent<T extends object> = FormInputEvent<T> | FormChildAttachEvent<any> | FormChildDetachEvent;
62
65
  export interface FormInjectedOptions {
@@ -1,4 +1,5 @@
1
1
  import { toRaw } from "vue";
2
+ import { get, set } from "./index.js";
2
3
  export function isSuperStructSchema(schema) {
3
4
  return "schema" in schema && typeof schema.coercer === "function" && typeof schema.validator === "function" && typeof schema.refiner === "function";
4
5
  }
@@ -50,29 +51,11 @@ export function validateSchema(state, _schema) {
50
51
  }
51
52
  export function getAtPath(data, path) {
52
53
  if (!path) return data;
53
- const value = path.split(".").reduce(
54
- (value2, key) => value2?.[key],
55
- data
56
- );
57
- return value;
54
+ return get(data, path);
58
55
  }
59
56
  export function setAtPath(data, path, value) {
60
57
  if (!path) return Object.assign(data, value);
61
58
  if (!data) return data;
62
- const keys = path.split(".");
63
- let current = data;
64
- for (let i = 0; i < keys.length - 1; i++) {
65
- const key = keys[i];
66
- if (current[key] === void 0 || current[key] === null) {
67
- if (i + 1 < keys.length && !Number.isNaN(Number(keys[i + 1]))) {
68
- current[key] = [];
69
- } else {
70
- current[key] = {};
71
- }
72
- }
73
- current = current[key];
74
- }
75
- const lastKey = keys[keys.length - 1];
76
- current[lastKey] = value;
59
+ set(data, path, value);
77
60
  return data;
78
61
  }
@@ -15,14 +15,9 @@ export function omit(data, keys) {
15
15
  return result;
16
16
  }
17
17
  export function get(object, path, defaultValue) {
18
- if (typeof path === "string") {
19
- path = path.split(".").map((key) => {
20
- const numKey = Number(key);
21
- return Number.isNaN(numKey) ? key : numKey;
22
- });
23
- }
18
+ const keys = typeof path === "string" ? path.split(".") : path;
24
19
  let result = object;
25
- for (const key of path) {
20
+ for (const key of keys) {
26
21
  if (result === void 0 || result === null) {
27
22
  return defaultValue;
28
23
  }
@@ -31,17 +26,26 @@ export function get(object, path, defaultValue) {
31
26
  return result !== void 0 ? result : defaultValue;
32
27
  }
33
28
  export function set(object, path, value) {
34
- if (typeof path === "string") {
35
- path = path.split(".").map((key) => {
36
- const numKey = Number(key);
37
- return Number.isNaN(numKey) ? key : numKey;
38
- });
39
- }
40
- path.reduce((acc, key, i) => {
41
- if (acc[key] === void 0) acc[key] = {};
42
- if (i === path.length - 1) acc[key] = value;
43
- return acc[key];
44
- }, object);
29
+ const keys = [];
30
+ for (const segment of typeof path === "string" ? path.split(".") : path) {
31
+ const key = String(segment);
32
+ if (key === "__proto__" || key === "constructor" || key === "prototype") {
33
+ return;
34
+ }
35
+ keys.push(key);
36
+ }
37
+ let current = object;
38
+ for (let i = 0; i < keys.length; i++) {
39
+ const key = keys[i];
40
+ if (i === keys.length - 1) {
41
+ current[key] = value;
42
+ return;
43
+ }
44
+ if (current[key] === null || typeof current[key] !== "object" && typeof current[key] !== "function") {
45
+ current[key] = /^(?:0|[1-9]\d*)$/.test(keys[i + 1]) ? [] : {};
46
+ }
47
+ current = current[key];
48
+ }
45
49
  }
46
50
  export function looseToNumber(val) {
47
51
  const n = Number.parseFloat(val);
@@ -180,7 +180,7 @@ function applyDefaultVariants(result, defaultVariants) {
180
180
  function createComponentPattern(prefix) {
181
181
  const escapedPrefix = prefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
182
182
  const kebabPrefix = kebabCase(prefix).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
183
- return new RegExp(`<(?:Lazy)?${escapedPrefix}([A-Z][a-zA-Z]+)|<(?:lazy-)?${kebabPrefix}-([a-z][a-z0-9-]*)|\\b(?:Lazy)?${escapedPrefix}([A-Z][a-zA-Z]+)\\b`, "g");
183
+ return new RegExp(`<(?:Lazy)?${escapedPrefix}([A-Z][a-zA-Z]+)|(?:<|#\\[|^[ \\t]*|:[ \\t]+)(?:lazy-)?${kebabPrefix}-([a-z][a-z0-9-]*)|\\b(?:Lazy)?${escapedPrefix}([A-Z][a-zA-Z]+)\\b`, "gm");
184
184
  }
185
185
  function getMatchedComponent(match) {
186
186
  if (match[2]) {
@@ -2012,7 +2012,7 @@ const checkboxGroup = (options) => ({
2012
2012
  variant: "table",
2013
2013
  highlight: false,
2014
2014
  class: {
2015
- item: `${hover}border-accented`
2015
+ item: `${hover}border-accented ${hover}z-[1]`
2016
2016
  }
2017
2017
  },
2018
2018
  { size: "xs", variant: "table", class: { item: "p-2.5" } },
@@ -2040,14 +2040,14 @@ const checkboxGroup = (options) => ({
2040
2040
  color,
2041
2041
  variant: "table",
2042
2042
  class: {
2043
- item: `has-data-[state=checked]:bg-${color}/10 has-data-[state=checked]:border-${color}/50 has-data-[state=checked]:z-[1]`
2043
+ item: `has-data-[state=checked]:bg-${color}/10 has-data-[state=checked]:border-${color}/50 has-data-[state=checked]:z-[2]`
2044
2044
  }
2045
2045
  })),
2046
2046
  {
2047
2047
  color: "neutral",
2048
2048
  variant: "table",
2049
2049
  class: {
2050
- item: "has-data-[state=checked]:bg-elevated has-data-[state=checked]:border-inverted/50 has-data-[state=checked]:z-[1]"
2050
+ item: "has-data-[state=checked]:bg-elevated has-data-[state=checked]:border-inverted/50 has-data-[state=checked]:z-[2]"
2051
2051
  }
2052
2052
  },
2053
2053
  {
@@ -3932,7 +3932,7 @@ const inputTags = (options) => {
3932
3932
  slots: {
3933
3933
  root: (prev) => [prev, "flex-wrap"],
3934
3934
  base: () => ["rounded-md", options.theme.transitions && "transition-colors"],
3935
- item: 'px-1.5 py-0.5 rounded-sm font-medium inline-flex items-center gap-0.5 ring ring-inset ring-accented bg-elevated text-default data-disabled:cursor-not-allowed data-disabled:opacity-75 wrap-anywhere data-[state="active"]:bg-accented',
3935
+ item: "px-1.5 py-0.5 rounded-sm font-medium inline-flex items-center gap-0.5 ring ring-inset ring-accented bg-elevated text-default data-disabled:cursor-not-allowed data-disabled:opacity-75 wrap-anywhere data-[state=active]:bg-accented",
3936
3936
  itemText: "",
3937
3937
  itemDelete: ["inline-flex items-center rounded-xs text-dimmed hover:text-default hover:bg-accented/75 disabled:pointer-events-none", options.theme.transitions && "transition-colors"],
3938
3938
  itemDeleteIcon: "shrink-0",
@@ -4285,7 +4285,7 @@ const marquee = {
4285
4285
  },
4286
4286
  overlay: {
4287
4287
  true: {
4288
- root: 'before:absolute before:pointer-events-none before:content-[""] before:z-2 before:from-default before:to-transparent after:absolute after:pointer-events-none after:content-[""] after:z-2 after:from-default after:to-transparent'
4288
+ root: "before:absolute before:pointer-events-none before:content-[''] before:z-2 before:from-default before:to-transparent after:absolute after:pointer-events-none after:content-[''] after:z-2 after:from-default after:to-transparent"
4289
4289
  }
4290
4290
  }
4291
4291
  },
@@ -5929,7 +5929,7 @@ const radioGroup = (options) => ({
5929
5929
  variant: ["card", "table"],
5930
5930
  highlight: false,
5931
5931
  class: {
5932
- item: `${hover}border-accented`
5932
+ item: `${hover}border-accented ${hover}z-[1]`
5933
5933
  }
5934
5934
  },
5935
5935
  { size: "xs", indicator: "hidden", class: { icon: "size-3" } },
@@ -5999,14 +5999,14 @@ const radioGroup = (options) => ({
5999
5999
  color,
6000
6000
  variant: "table",
6001
6001
  class: {
6002
- item: `has-data-[state=checked]:bg-${color}/10 has-data-[state=checked]:border-${color}/50 has-data-[state=checked]:z-[1]`
6002
+ item: `has-data-[state=checked]:bg-${color}/10 has-data-[state=checked]:border-${color}/50 has-data-[state=checked]:z-[2]`
6003
6003
  }
6004
6004
  })),
6005
6005
  {
6006
6006
  color: "neutral",
6007
6007
  variant: "table",
6008
6008
  class: {
6009
- item: "has-data-[state=checked]:bg-elevated has-data-[state=checked]:border-inverted/50 has-data-[state=checked]:z-[1]"
6009
+ item: "has-data-[state=checked]:bg-elevated has-data-[state=checked]:border-inverted/50 has-data-[state=checked]:z-[2]"
6010
6010
  }
6011
6011
  },
6012
6012
  {
@@ -6091,7 +6091,7 @@ const select = (options) => {
6091
6091
  value: "truncate pointer-events-none",
6092
6092
  placeholder: "truncate text-dimmed",
6093
6093
  arrow: "fill-bg stroke-default",
6094
- content: "max-h-[min(15rem,var(--reka-select-content-available-height,15rem))] w-(--reka-select-trigger-width) bg-default shadow-lg rounded-md ring ring-default overflow-hidden origin-(--reka-select-content-transform-origin) pointer-events-auto flex flex-col",
6094
+ content: "max-h-[min(15rem,var(--reka-select-content-available-height,15rem))] w-(--reka-select-trigger-width) bg-default shadow-lg rounded-md ring ring-default overflow-hidden origin-(--reka-select-content-transform-origin) pointer-events-auto data-[state=closed]:pointer-events-none! flex flex-col",
6095
6095
  viewport: "relative divide-y divide-default scroll-py-1 overflow-y-auto flex-1",
6096
6096
  group: "p-1 isolate",
6097
6097
  empty: "text-center text-muted",
@@ -7033,7 +7033,7 @@ const table$1 = (options) => ({
7033
7033
  caption: "sr-only",
7034
7034
  thead: "relative",
7035
7035
  tbody: "isolate [&>tr]:data-[selectable=true]:hover:bg-elevated/50 [&>tr]:data-[selectable=true]:outline-primary/25 [&>tr]:data-[selectable=true]:focus-visible:outline-3 [&>tr]:data-[selectable=true]:-outline-offset-3 divide-y divide-default",
7036
- tfoot: "relative",
7036
+ tfoot: "relative [&>[data-slot=separator]]:z-2",
7037
7037
  tr: "data-[selected=true]:bg-elevated/50",
7038
7038
  th: "px-4 py-3.5 text-sm text-highlighted text-start font-semibold [&:has([role=checkbox])]:pe-0",
7039
7039
  td: "p-4 text-sm text-muted whitespace-nowrap [&:has([role=checkbox])]:pe-0",
@@ -7904,7 +7904,7 @@ const theme = {
7904
7904
  };
7905
7905
 
7906
7906
  const a = (options) => ({
7907
- base: ["text-primary border-b border-transparent hover:border-primary font-medium rounded-xs outline-primary/25 focus-visible:outline-3 focus-visible:has-[>code]:outline-0 [&>code]:border-dashed [&>code]:outline-primary/25 focus-visible:[&>code]:outline-3 hover:[&>code]:border-primary hover:[&>code]:text-primary focus-visible:[&>code]:border-primary focus-visible:[&>code]:text-primary", options.theme.transitions && "transition-colors [&>code]:transition-colors"]
7907
+ base: ["text-primary border-b border-transparent hover:border-primary font-medium focus-visible:rounded-xs outline-primary/25 focus-visible:outline-3 focus-visible:has-[>code]:outline-0 [&>code]:border-dashed [&>code]:outline-primary/25 focus-visible:[&>code]:outline-3 hover:[&>code]:border-primary hover:[&>code]:text-primary focus-visible:[&>code]:border-primary focus-visible:[&>code]:text-primary", options.theme.transitions && "transition-colors [&>code]:transition-colors"]
7908
7908
  });
7909
7909
 
7910
7910
  const accordion = {
@@ -8752,6 +8752,7 @@ const themeContent = {
8752
8752
  contentToc: contentToc
8753
8753
  };
8754
8754
 
8755
+ const prefixedClasses = ["absolute", "dark:block", "dark:hidden", "dark:inline-block", "focus:outline-none", "hidden", "inset-0", "lg:block", "lg:flex", "lg:hidden", "peer", "sm:block"];
8755
8756
  function getTemplates(options, uiConfig, nuxt, resolve, vue) {
8756
8757
  const templates = [];
8757
8758
  let hasProse = false;
@@ -8828,6 +8829,10 @@ function getTemplates(options, uiConfig, nuxt, resolve, vue) {
8828
8829
  }
8829
8830
  }
8830
8831
  }
8832
+ const prefix = options.theme?.prefix;
8833
+ if (prefix) {
8834
+ sources.push(`@source inline(${JSON.stringify(prefixedClasses.map((cls) => `${prefix}:${cls}`).join(" "))});`);
8835
+ }
8831
8836
  const componentDir = resolve ? resolve("./runtime/components") : void 0;
8832
8837
  if (options.experimental?.componentDetection && nuxt && componentDir && layers.length) {
8833
8838
  const detectedComponents = await detectUsedComponents(
package/dist/unplugin.mjs CHANGED
@@ -3,7 +3,7 @@ import { join, normalize, relative } from 'pathe';
3
3
  import { createUnplugin } from 'unplugin';
4
4
  import { defu } from 'defu';
5
5
  import tailwind from '@tailwindcss/vite';
6
- import { e as getTemplates, h as resolveExtraScanDirs, b as detectUsedComponents, f as publicComposables, g as getClientBundleIcons, p as parseIconName, d as defaultOptions, r as resolveColors, c as getDefaultConfig } from './shared/ui.oNygBd3N.mjs';
6
+ import { e as getTemplates, h as resolveExtraScanDirs, b as detectUsedComponents, f as publicComposables, g as getClientBundleIcons, p as parseIconName, d as defaultOptions, r as resolveColors, c as getDefaultConfig } from './shared/ui.CNAeRcb0.mjs';
7
7
  import fs from 'node:fs';
8
8
  import path from 'node:path';
9
9
  import { consola } from 'consola';
package/dist/vite.mjs CHANGED
@@ -4,7 +4,7 @@ import 'pathe';
4
4
  import 'unplugin';
5
5
  import 'defu';
6
6
  import '@tailwindcss/vite';
7
- import './shared/ui.oNygBd3N.mjs';
7
+ import './shared/ui.CNAeRcb0.mjs';
8
8
  import '../dist/runtime/utils/index.js';
9
9
  import 'scule';
10
10
  import 'knitwork';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nuxt/ui",
3
3
  "description": "A UI Library for Modern Web Apps, powered by Vue & Tailwind CSS.",
4
- "version": "4.11.2",
4
+ "version": "4.11.3",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/nuxt/ui.git"
@@ -104,7 +104,7 @@
104
104
  ],
105
105
  "dependencies": {
106
106
  "@floating-ui/dom": "^1.8.0",
107
- "@iconify/vue": "^5.0.2",
107
+ "@iconify/vue": "^5.0.3",
108
108
  "@internationalized/date": "^3.12.4",
109
109
  "@internationalized/number": "^3.6.8",
110
110
  "@nuxt/fonts": "^0.14.0",
@@ -151,12 +151,12 @@
151
151
  "fuse.js": "^7.5.0",
152
152
  "hookable": "^6.1.2",
153
153
  "knitwork": "^1.3.0",
154
- "magic-string": "^1.4.1",
154
+ "magic-string": "^1.4.2",
155
155
  "mlly": "^1.8.2",
156
156
  "motion-v": "^2.4.4",
157
157
  "ohash": "^2.0.12",
158
158
  "pathe": "^2.0.3",
159
- "reka-ui": "2.10.4",
159
+ "reka-ui": "2.10.5",
160
160
  "scule": "^1.3.0",
161
161
  "tailwind-merge": "^3.7.0",
162
162
  "tailwind-variants": "^3.2.2",
@@ -178,7 +178,7 @@
178
178
  "@tanstack/table-core": "^8.21.3",
179
179
  "@vitejs/plugin-vue": "^6.0.9",
180
180
  "@vue/test-utils": "^2.5.1",
181
- "ai": "^7.0.107",
181
+ "ai": "^7.0.116",
182
182
  "embla-carousel": "^8.6.0",
183
183
  "eslint": "^10.11.0",
184
184
  "eslint-plugin-better-tailwindcss": "^4.7.0",
@@ -291,11 +291,12 @@
291
291
  "docs:build": "nuxt build docs",
292
292
  "lint": "eslint .",
293
293
  "lint:fix": "eslint . --fix",
294
- "typecheck": "vue-tsc --noEmit && nuxt typecheck playgrounds/nuxt && nuxt typecheck docs && cd playgrounds/vue && vue-tsc --noEmit",
294
+ "typecheck": "vue-tsc --noEmit && nuxt typecheck playgrounds/nuxt && nuxt typecheck docs",
295
295
  "test": "vitest",
296
296
  "test:vue": "vitest --project vue",
297
297
  "test:nuxt": "vitest --project nuxt",
298
298
  "bench": "vitest bench --project vue",
299
+ "size": "node test/bundle/size.mjs",
299
300
  "release": "release-it"
300
301
  }
301
302
  }