@nuxt/ui 4.0.0-alpha.2 → 4.0.0-beta.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.
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "slots": {
3
- "base": "rounded-md",
3
+ "base": "rounded-md w-full",
4
4
  "overlay": "fixed inset-0 bg-default/75 backdrop-blur-sm will-change-opacity",
5
5
  "content": "fixed inset-0 flex items-center justify-center cursor-zoom-out focus:outline-none p-4 sm:p-8"
6
6
  },
package/README.md CHANGED
@@ -31,6 +31,7 @@ Kickstart your project with one of our ready-to-use Nuxt UI templates or follow
31
31
  - [Dashboard](https://github.com/nuxt-ui-templates/dashboard) — A dashboard template with multi-column layout.
32
32
  - [Chat](https://github.com/nuxt-ui-templates/chat) — An AI chatbot template with GitHub authentication and persistent chat history powered by Vercel AI SDK.
33
33
  - [Portfolio](https://github.com/nuxt-ui-templates/portfolio) — A sleek portfolio template to showcase your work, skills and blog powered by Nuxt Content.
34
+ - [Changelog](https://github.com/nuxt-ui-templates/changelog) — A changelog template to display your repository releases notes from GitHub powered by Nuxt MDC.
34
35
 
35
36
  ## Installation
36
37
 
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuxt/ui",
3
- "version": "4.0.0-alpha.2",
3
+ "version": "4.0.0-beta.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, installModule } from '@nuxt/kit';
3
- import { d as defaultOptions, r as resolveColors, a as getDefaultUiConfig, b as addTemplates } from './shared/ui.Bs5uUhtm.mjs';
3
+ import { d as defaultOptions, r as resolveColors, a as getDefaultUiConfig, b as addTemplates } from './shared/ui.DGJZ-1aX.mjs';
4
4
  import '../dist/runtime/utils/index.js';
5
5
  import 'node:url';
6
6
  import 'scule';
@@ -8,7 +8,7 @@ import 'knitwork';
8
8
  import 'tailwindcss/colors';
9
9
 
10
10
  const name = "@nuxt/ui";
11
- const version = "4.0.0-alpha.2";
11
+ const version = "4.0.0-beta.0";
12
12
 
13
13
  const module = defineNuxtModule({
14
14
  meta: {
@@ -30,7 +30,7 @@ const module = defineNuxtModule({
30
30
  nuxt.options.appConfig.ui = defu(nuxt.options.appConfig.ui || {}, getDefaultUiConfig(options.theme.colors));
31
31
  nuxt.options.app.rootAttrs = nuxt.options.app.rootAttrs || {};
32
32
  nuxt.options.app.rootAttrs.class = [nuxt.options.app.rootAttrs.class, "isolate"].filter(Boolean).join(" ");
33
- nuxt.hook("vite:extendConfig", async (config) => {
33
+ nuxt.hook("vite:extend", async ({ config }) => {
34
34
  const plugin = await import('@tailwindcss/vite').then((r) => r.default);
35
35
  config.plugins ||= [];
36
36
  config.plugins.push(plugin());
@@ -180,13 +180,13 @@ onMounted(() => {
180
180
  :compact="compact"
181
181
  >
182
182
  <template #content>
183
- <div :class="ui.indicator({ class: props.ui?.indicator })">
184
- <slot name="indicator">
183
+ <slot name="indicator">
184
+ <div :class="ui.indicator({ class: props.ui?.indicator })">
185
185
  <span />
186
186
  <span />
187
187
  <span />
188
- </slot>
189
- </div>
188
+ </div>
189
+ </slot>
190
190
  </template>
191
191
  </UChatMessage>
192
192
 
@@ -58,7 +58,7 @@ export interface CheckboxGroupProps<T extends CheckboxGroupItem[] = CheckboxGrou
58
58
  class?: any;
59
59
  ui?: CheckboxGroup['slots'] & CheckboxProps['ui'];
60
60
  }
61
- export type CheckboxGroupEmits = CheckboxGroupRootEmits & {
61
+ export type CheckboxGroupEmits<T extends CheckboxGroupItem[] = CheckboxGroupItem[]> = CheckboxGroupRootEmits<T[number]> & {
62
62
  change: [event: Event];
63
63
  };
64
64
  type SlotProps<T extends CheckboxGroupItem> = (props: {
@@ -74,12 +74,12 @@ export interface CheckboxGroupSlots<T extends CheckboxGroupItem[] = CheckboxGrou
74
74
  declare const _default: <T extends CheckboxGroupItem[], VK extends GetItemKeys<T> = "value">(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
75
75
  props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{
76
76
  readonly onChange?: ((event: Event) => any) | undefined;
77
- readonly "onUpdate:modelValue"?: ((value: import("reka-ui").AcceptableValue[]) => any) | undefined;
77
+ readonly "onUpdate:modelValue"?: ((value: T[number][]) => any) | undefined;
78
78
  } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, never>, "onChange" | "onUpdate:modelValue"> & CheckboxGroupProps<T, VK> & {}> & import("vue").PublicProps;
79
79
  expose(exposed: import("vue").ShallowUnwrapRef<{}>): void;
80
80
  attrs: any;
81
81
  slots: CheckboxGroupSlots<T>;
82
- emit: ((evt: "change", event: Event) => void) & ((evt: "update:modelValue", value: import("reka-ui").AcceptableValue[]) => void);
82
+ emit: ((evt: "change", event: Event) => void) & ((evt: "update:modelValue", value: T[number][]) => void);
83
83
  }>) => import("vue").VNode & {
84
84
  __ctx?: Awaited<typeof __VLS_setup>;
85
85
  };
@@ -58,7 +58,7 @@ export interface CheckboxGroupProps<T extends CheckboxGroupItem[] = CheckboxGrou
58
58
  class?: any;
59
59
  ui?: CheckboxGroup['slots'] & CheckboxProps['ui'];
60
60
  }
61
- export type CheckboxGroupEmits = CheckboxGroupRootEmits & {
61
+ export type CheckboxGroupEmits<T extends CheckboxGroupItem[] = CheckboxGroupItem[]> = CheckboxGroupRootEmits<T[number]> & {
62
62
  change: [event: Event];
63
63
  };
64
64
  type SlotProps<T extends CheckboxGroupItem> = (props: {
@@ -74,12 +74,12 @@ export interface CheckboxGroupSlots<T extends CheckboxGroupItem[] = CheckboxGrou
74
74
  declare const _default: <T extends CheckboxGroupItem[], VK extends GetItemKeys<T> = "value">(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
75
75
  props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{
76
76
  readonly onChange?: ((event: Event) => any) | undefined;
77
- readonly "onUpdate:modelValue"?: ((value: import("reka-ui").AcceptableValue[]) => any) | undefined;
77
+ readonly "onUpdate:modelValue"?: ((value: T[number][]) => any) | undefined;
78
78
  } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, never>, "onChange" | "onUpdate:modelValue"> & CheckboxGroupProps<T, VK> & {}> & import("vue").PublicProps;
79
79
  expose(exposed: import("vue").ShallowUnwrapRef<{}>): void;
80
80
  attrs: any;
81
81
  slots: CheckboxGroupSlots<T>;
82
- emit: ((evt: "change", event: Event) => void) & ((evt: "update:modelValue", value: import("reka-ui").AcceptableValue[]) => void);
82
+ emit: ((evt: "change", event: Event) => void) & ((evt: "update:modelValue", value: T[number][]) => void);
83
83
  }>) => import("vue").VNode & {
84
84
  __ctx?: Awaited<typeof __VLS_setup>;
85
85
  };
@@ -12,9 +12,9 @@ export interface DashboardGroupSlots {
12
12
  }
13
13
  declare const _default: __VLS_WithSlots<import("vue").DefineComponent<DashboardGroupProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<DashboardGroupProps> & Readonly<{}>, {
14
14
  storage: "cookie" | "local";
15
- unit: "%" | "rem" | "px";
16
15
  storageKey: string;
17
16
  persistent: boolean;
17
+ unit: "%" | "rem" | "px";
18
18
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, DashboardGroupSlots>;
19
19
  export default _default;
20
20
  type __VLS_WithSlots<T, S> = T & {
@@ -12,9 +12,9 @@ export interface DashboardGroupSlots {
12
12
  }
13
13
  declare const _default: __VLS_WithSlots<import("vue").DefineComponent<DashboardGroupProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<DashboardGroupProps> & Readonly<{}>, {
14
14
  storage: "cookie" | "local";
15
- unit: "%" | "rem" | "px";
16
15
  storageKey: string;
17
16
  persistent: boolean;
17
+ unit: "%" | "rem" | "px";
18
18
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, DashboardGroupSlots>;
19
19
  export default _default;
20
20
  type __VLS_WithSlots<T, S> = T & {
@@ -112,35 +112,20 @@ async function getErrors() {
112
112
  }
113
113
  async function _validate(opts = { silent: false, nested: false, transform: false }) {
114
114
  const names = opts.name && !Array.isArray(opts.name) ? [opts.name] : opts.name;
115
- async function validateNestedForms({ validate, name }) {
116
- try {
117
- return { name, output: await validate({ ...opts, silent: false }) };
118
- } catch (error) {
119
- if (!(error instanceof FormValidationException)) {
120
- throw error;
121
- }
122
- return { name, error };
123
- }
115
+ let nestedResults = [];
116
+ let nestedErrors = [];
117
+ if (!names && opts.nested) {
118
+ const validations = Array.from(nestedForms.value.values()).map(
119
+ (form) => validateNestedForm(form, opts)
120
+ );
121
+ const results = await Promise.all(validations);
122
+ nestedErrors = results.filter((r) => r.error).flatMap((r) => r.error.errors.map((e) => addFormPath(e, r.name)));
123
+ nestedResults = results.filter((r) => r.output !== void 0);
124
124
  }
125
- const nestedValidatePromises = !names && opts.nested ? Array.from(nestedForms.value.values()).map(validateNestedForms) : [];
126
- const nestedResults = await Promise.all(nestedValidatePromises);
127
- const nestedErrors = nestedResults.flatMap((result) => {
128
- if (!result.error) return [];
129
- return result.error.errors.map((e) => ({ ...e, name: result.name ? [result.name, e.name].join(".") : e.name }));
130
- });
131
- const nestedOutputs = nestedResults.filter((c) => c.output !== void 0);
132
- const allErrors = [await getErrors(), nestedErrors].flat();
125
+ const currentErrors = await getErrors();
126
+ const allErrors = [...currentErrors, ...nestedErrors];
133
127
  if (names) {
134
- const namesSet = new Set(names);
135
- const patterns = names.map((name) => inputs.value?.[name]?.pattern).filter(Boolean);
136
- const isErrorForPath = (error) => {
137
- if (!error.name) return false;
138
- if (namesSet.has(error.name)) return true;
139
- return patterns.some((pattern) => pattern.test(error.name));
140
- };
141
- const otherErrors = errors.value.filter((error) => !isErrorForPath(error));
142
- const pathErrors = allErrors.filter(isErrorForPath);
143
- errors.value = otherErrors.concat(pathErrors);
128
+ errors.value = filterErrorsByNames(allErrors, names);
144
129
  } else {
145
130
  errors.value = allErrors;
146
131
  }
@@ -149,9 +134,12 @@ async function _validate(opts = { silent: false, nested: false, transform: false
149
134
  throw new FormValidationException(formId, errors.value);
150
135
  }
151
136
  if (opts.transform) {
152
- nestedOutputs.forEach((o) => {
153
- if (o.name) setAtPath(transformedState.value, o.name, o.output);
154
- else Object.assign(transformedState.value, o.output);
137
+ nestedResults.forEach((result) => {
138
+ if (result.name) {
139
+ setAtPath(transformedState.value, result.name, result.output);
140
+ } else {
141
+ Object.assign(transformedState.value, result.output);
142
+ }
155
143
  });
156
144
  return transformedState.value ?? state.value;
157
145
  }
@@ -184,68 +172,105 @@ provide(formOptionsInjectionKey, computed(() => ({
184
172
  disabled: disabled.value,
185
173
  validateOnInputDelay: props.validateOnInputDelay
186
174
  })));
175
+ async function validateNestedForm(form, opts) {
176
+ try {
177
+ const result = await form.validate({ ...opts, silent: false });
178
+ return { name: form.name, output: result };
179
+ } catch (error) {
180
+ if (!(error instanceof FormValidationException)) throw error;
181
+ return { name: form.name, error };
182
+ }
183
+ }
184
+ function addFormPath(error, formPath) {
185
+ if (!formPath || !error.name) return error;
186
+ return { ...error, name: formPath + "." + error.name };
187
+ }
188
+ function stripFormPath(error, formPath) {
189
+ const prefix = formPath + ".";
190
+ const name = error?.name?.startsWith(prefix) ? error.name.substring(prefix.length) : error.name;
191
+ return { ...error, name };
192
+ }
193
+ function filterFormErrors(errors2, formPath) {
194
+ if (!formPath) return errors2;
195
+ return errors2.filter((e) => e?.name?.startsWith(formPath + ".")).map((e) => stripFormPath(e, formPath));
196
+ }
197
+ function getFormErrors(form) {
198
+ return form.api.getErrors().map(
199
+ (e) => form.name ? { ...e, name: form.name + "." + e.name } : e
200
+ );
201
+ }
202
+ function matchesTarget(target, path) {
203
+ if (!target || !path) return true;
204
+ if (target instanceof RegExp) return target.test(path);
205
+ return path === target || typeof target === "string" && target.startsWith(path + ".");
206
+ }
207
+ function getNestedTarget(target, formPath) {
208
+ if (!target || target instanceof RegExp) return target;
209
+ if (formPath === target) return void 0;
210
+ if (typeof target === "string" && target.startsWith(formPath + ".")) {
211
+ return target.substring(formPath.length + 1);
212
+ }
213
+ return target;
214
+ }
215
+ function filterErrorsByNames(allErrors, names) {
216
+ const nameSet = new Set(names);
217
+ const patterns = names.map((name) => inputs.value?.[name]?.pattern).filter(Boolean);
218
+ const matchesNames = (error) => {
219
+ if (!error.name) return false;
220
+ if (nameSet.has(error.name)) return true;
221
+ return patterns.some((pattern) => pattern.test(error.name));
222
+ };
223
+ const keepErrors = errors.value.filter((error) => !matchesNames(error));
224
+ const newErrors = allErrors.filter(matchesNames);
225
+ return [...keepErrors, ...newErrors];
226
+ }
227
+ function filterErrorsByTarget(currentErrors, target) {
228
+ return currentErrors.filter(
229
+ (err) => target instanceof RegExp ? !(err.name && target.test(err.name)) : !err.name || err.name !== target
230
+ );
231
+ }
232
+ function isLocalError(error) {
233
+ return !error.name || !!inputs.value[error.name];
234
+ }
187
235
  const api = {
188
236
  validate: _validate,
189
237
  errors,
190
238
  setErrors(errs, name) {
191
- let formErrors = resolveErrorIds(errs).filter((e) => e.id);
192
- if (name) {
193
- formErrors = errors.value.filter(
194
- (err) => name instanceof RegExp ? !(err.name && name.test(err.name)) : err.name !== name
195
- ).concat(formErrors);
196
- }
239
+ const localErrors = resolveErrorIds(errs.filter(isLocalError));
240
+ const nestedErrors = [];
197
241
  for (const form of nestedForms.value.values()) {
198
- const errors2 = errs.flatMap((e) => {
199
- if (!form.name) return [e];
200
- if (e?.name?.startsWith(form.name + `.`)) {
201
- return [{
202
- ...e,
203
- name: e?.name.split(form.name + `.`)[1]
204
- }];
205
- }
206
- return [];
207
- });
208
- const nameMatch = name instanceof RegExp ? form.name && name.test(form.name.toString()) : form.name !== name;
209
- if (nameMatch || !form.name) {
210
- form.api.setErrors(errors2, name);
211
- formErrors = formErrors.concat(form.api.getErrors().map((e) => ({ ...e, name: form.name ? [form.name, e.name].join(".") : e.name })));
242
+ if (matchesTarget(name, form.name)) {
243
+ const formErrors = filterFormErrors(errs, form.name);
244
+ form.api.setErrors(formErrors, getNestedTarget(name, form.name || ""));
245
+ nestedErrors.push(...getFormErrors(form));
212
246
  }
213
247
  }
214
- errors.value = formErrors;
248
+ if (name) {
249
+ const keepErrors = filterErrorsByTarget(errors.value, name);
250
+ errors.value = [...keepErrors, ...localErrors, ...nestedErrors];
251
+ } else {
252
+ errors.value = [...localErrors, ...nestedErrors];
253
+ }
215
254
  },
216
255
  async submit() {
217
256
  await onSubmitWrapper(new Event("submit"));
218
257
  },
219
258
  getErrors(name) {
220
- if (name) {
221
- return errors.value.filter((err) => name instanceof RegExp ? err.name && name.test(err.name) : err.name === name);
222
- }
223
- return errors.value;
259
+ if (!name) return errors.value;
260
+ return errors.value.filter(
261
+ (err) => name instanceof RegExp ? err.name && name.test(err.name) : err.name === name
262
+ );
224
263
  },
225
264
  clear(name) {
226
- let formErrors = [];
227
- if (name) {
228
- formErrors = errors.value.filter(
229
- (err) => {
230
- return err.name && !!inputs.value[err.name] && (name instanceof RegExp ? !(err.name && name.test(err.name)) : err.name !== name);
231
- }
232
- );
233
- }
265
+ const localErrors = name ? errors.value.filter(
266
+ (err) => isLocalError(err) && (name instanceof RegExp ? !(err.name && name.test(err.name)) : err.name !== name)
267
+ ) : [];
268
+ const nestedErrors = [];
234
269
  for (const form of nestedForms.value.values()) {
235
- if (!form.name) form.api.clear(name);
236
- else if (form.name === name || name instanceof RegExp && name.test(form.name)) form.api.clear();
237
- else if (typeof name === "string" && name?.startsWith(form.name + `.`)) {
238
- const nestedName = name?.split(`${form.name}.`)[1];
239
- form.api.clear(nestedName);
240
- }
241
- formErrors = formErrors.concat(
242
- form.api.getErrors().map((e) => ({
243
- ...e,
244
- name: form.name ? [form.name, e.name].join(".") : e.name
245
- }))
246
- );
270
+ if (matchesTarget(name, form.name)) form.api.clear();
271
+ nestedErrors.push(...getFormErrors(form));
247
272
  }
248
- errors.value = formErrors;
273
+ errors.value = [...localErrors, ...nestedErrors];
249
274
  },
250
275
  disabled,
251
276
  loading,
@@ -3,10 +3,10 @@ import theme from "#build/ui/form-field";
3
3
  </script>
4
4
 
5
5
  <script setup>
6
- import { computed, ref, inject, provide, useId } from "vue";
6
+ import { computed, ref, inject, provide, useId, watch } from "vue";
7
7
  import { Primitive, Label } from "reka-ui";
8
8
  import { useAppConfig } from "#imports";
9
- import { formFieldInjectionKey, inputIdInjectionKey, formErrorsInjectionKey } from "../composables/useFormField";
9
+ import { formFieldInjectionKey, inputIdInjectionKey, formErrorsInjectionKey, formInputsInjectionKey } from "../composables/useFormField";
10
10
  import { tv } from "../utils/tv";
11
11
  const props = defineProps({
12
12
  as: { type: null, required: false },
@@ -31,9 +31,15 @@ const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.formField ||
31
31
  required: props.required
32
32
  }));
33
33
  const formErrors = inject(formErrorsInjectionKey, null);
34
- const error = computed(() => props.error || formErrors?.value?.find((error2) => error2.name && (error2.name === props.name || props.errorPattern && error2.name.match(props.errorPattern)))?.message);
34
+ const error = computed(() => props.error || formErrors?.value?.find((error2) => error2.name === props.name || props.errorPattern && error2.name?.match(props.errorPattern))?.message);
35
35
  const id = ref(useId());
36
36
  const ariaId = id.value;
37
+ const formInputs = inject(formInputsInjectionKey, void 0);
38
+ watch(id, () => {
39
+ if (formInputs && props.name) {
40
+ formInputs.value[props.name] = { id: id.value, pattern: props.errorPattern };
41
+ }
42
+ }, { immediate: true });
37
43
  provide(inputIdInjectionKey, id);
38
44
  provide(formFieldInjectionKey, computed(() => ({
39
45
  error: error.value,
@@ -259,7 +259,7 @@ defineExpose({
259
259
  @focus="onFocus"
260
260
  @remove-tag="onRemoveTag"
261
261
  >
262
- <TagsInputItem v-for="(item, index) in tags" :key="index" :value="item" :class="ui.tagsItem({ class: [props.ui?.tagsItem, isInputItem(item) && item.ui?.tagsItem] })">
262
+ <TagsInputItem v-for="(item, index) in tags" :key="index" :value="isInputItem(item) ? item : String(item)" :class="ui.tagsItem({ class: [props.ui?.tagsItem, isInputItem(item) && item.ui?.tagsItem] })">
263
263
  <TagsInputItemText :class="ui.tagsItemText({ class: [props.ui?.tagsItemText, isInputItem(item) && item.ui?.tagsItemText] })">
264
264
  <slot name="tags-item-text" :item="item" :index="index">
265
265
  {{ displayValue(item) }}
@@ -112,8 +112,6 @@ defineExpose({
112
112
  :name="name"
113
113
  :disabled="disabled"
114
114
  @update:model-value="onUpdate"
115
- @blur="onBlur"
116
- @focus="onFocus"
117
115
  >
118
116
  <TagsInputItem
119
117
  v-for="(item, index) in tags"
@@ -141,6 +139,8 @@ defineExpose({
141
139
  :placeholder="placeholder"
142
140
  :max-length="maxLength"
143
141
  :class="ui.input({ class: props.ui?.input })"
142
+ @blur="onBlur"
143
+ @focus="onFocus"
144
144
  />
145
145
 
146
146
  <slot />
@@ -62,7 +62,7 @@ defineExpose({
62
62
  v-for="(item, index) of items"
63
63
  :key="index"
64
64
  :ref="(el) => triggersRef[index] = el"
65
- :value="item.value || String(index)"
65
+ :value="item.value ?? String(index)"
66
66
  :disabled="item.disabled"
67
67
  :class="ui.trigger({ class: [props.ui?.trigger, item.ui?.trigger] })"
68
68
  >
@@ -91,7 +91,7 @@ defineExpose({
91
91
  </TabsList>
92
92
 
93
93
  <template v-if="!!content">
94
- <TabsContent v-for="(item, index) of items" :key="index" :value="item.value || String(index)" :class="ui.content({ class: [props.ui?.content, item.ui?.content, item.class] })">
94
+ <TabsContent v-for="(item, index) of items" :key="index" :value="item.value ?? String(index)" :class="ui.content({ class: [props.ui?.content, item.ui?.content, item.class] })">
95
95
  <slot :name="item.slot || 'content'" :item="item" :index="index">
96
96
  {{ item.content }}
97
97
  </slot>
@@ -2,7 +2,7 @@ import type { TreeRootProps, TreeRootEmits } from 'reka-ui';
2
2
  import type { AppConfig } from '@nuxt/schema';
3
3
  import theme from '#build/ui/tree';
4
4
  import type { IconProps } from '../types';
5
- import type { DynamicSlots, GetItemKeys, GetModelValue, GetModelValueEmits, NestedItem } from '../types/utils';
5
+ import type { DynamicSlots, GetItemKeys } from '../types/utils';
6
6
  import type { ComponentConfig } from '../types/tv';
7
7
  type Tree = ComponentConfig<typeof theme, AppConfig, 'tree'>;
8
8
  export type TreeItem = {
@@ -17,7 +17,6 @@ export type TreeItem = {
17
17
  trailingIcon?: IconProps['name'];
18
18
  defaultExpanded?: boolean;
19
19
  disabled?: boolean;
20
- value?: string;
21
20
  slot?: string;
22
21
  children?: TreeItem[];
23
22
  onToggle?(e: Event): void;
@@ -26,7 +25,7 @@ export type TreeItem = {
26
25
  ui?: Pick<Tree['slots'], 'item' | 'itemWithChildren' | 'link' | 'linkLeadingIcon' | 'linkLabel' | 'linkTrailing' | 'linkTrailingIcon' | 'listWithChildren'>;
27
26
  [key: string]: any;
28
27
  };
29
- export interface TreeProps<T extends TreeItem[] = TreeItem[], VK extends GetItemKeys<T> = 'value', M extends boolean = false> extends Pick<TreeRootProps<T>, 'expanded' | 'defaultExpanded' | 'selectionBehavior' | 'propagateSelect' | 'disabled' | 'bubbleSelect'> {
28
+ export interface TreeProps<T extends TreeItem[] = TreeItem[], M extends boolean = false> extends Pick<TreeRootProps<T>, 'expanded' | 'defaultExpanded' | 'selectionBehavior' | 'propagateSelect' | 'disabled' | 'bubbleSelect'> {
30
29
  /**
31
30
  * The element or component this component should render as.
32
31
  * @defaultValue 'ul'
@@ -40,11 +39,8 @@ export interface TreeProps<T extends TreeItem[] = TreeItem[], VK extends GetItem
40
39
  * @defaultValue 'md'
41
40
  */
42
41
  size?: Tree['variants']['size'];
43
- /**
44
- * The key used to get the value from the item.
45
- * @defaultValue 'value'
46
- */
47
- valueKey?: VK;
42
+ /** This function is passed the index of each item and should return a unique key for that item */
43
+ getKey?: (val: T[number]) => string;
48
44
  /**
49
45
  * The key used to get the label from the item.
50
46
  * @defaultValue 'label'
@@ -70,15 +66,15 @@ export interface TreeProps<T extends TreeItem[] = TreeItem[], VK extends GetItem
70
66
  collapsedIcon?: IconProps['name'];
71
67
  items?: T;
72
68
  /** The controlled value of the Tree. Can be bind as `v-model`. */
73
- modelValue?: GetModelValue<T, VK, M>;
69
+ modelValue?: M extends true ? T[number][] : T[number];
74
70
  /** The value of the Tree when initially rendered. Use when you do not need to control the state of the Tree. */
75
- defaultValue?: GetModelValue<T, VK, M>;
71
+ defaultValue?: M extends true ? T[number][] : T[number];
76
72
  /** Whether multiple options can be selected or not. */
77
73
  multiple?: M & boolean;
78
74
  class?: any;
79
75
  ui?: Tree['slots'];
80
76
  }
81
- export type TreeEmits<A extends TreeItem[], VK extends GetItemKeys<A> | undefined, M extends boolean> = Omit<TreeRootEmits, 'update:modelValue'> & GetModelValueEmits<A, VK, M>;
77
+ export type TreeEmits<T extends TreeItem[] = TreeItem[], M extends boolean = false> = TreeRootEmits<T[number], M>;
82
78
  type SlotProps<T extends TreeItem> = (props: {
83
79
  item: T;
84
80
  index: number;
@@ -86,27 +82,27 @@ type SlotProps<T extends TreeItem> = (props: {
86
82
  expanded: boolean;
87
83
  selected: boolean;
88
84
  }) => any;
89
- export type TreeSlots<A extends TreeItem[] = TreeItem[], T extends NestedItem<A> = NestedItem<A>> = {
90
- 'item-wrapper': SlotProps<T>;
91
- 'item': SlotProps<T>;
92
- 'item-leading': SlotProps<T>;
93
- 'item-label': SlotProps<T>;
94
- 'item-trailing': SlotProps<T>;
95
- } & DynamicSlots<T, undefined, {
85
+ export type TreeSlots<T extends TreeItem[] = TreeItem[]> = {
86
+ 'item-wrapper': SlotProps<T[number]>;
87
+ 'item': SlotProps<T[number]>;
88
+ 'item-leading': SlotProps<T[number]>;
89
+ 'item-label': SlotProps<T[number]>;
90
+ 'item-trailing': SlotProps<T[number]>;
91
+ } & DynamicSlots<T[number], undefined, {
96
92
  index: number;
97
93
  level: number;
98
94
  expanded: boolean;
99
95
  selected: boolean;
100
96
  }>;
101
- declare const _default: <T extends TreeItem[], VK extends GetItemKeys<T> = "value", M extends boolean = false>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
97
+ declare const _default: <T extends TreeItem[], M extends boolean = false>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
102
98
  props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{
103
- readonly "onUpdate:modelValue"?: ((value: GetModelValue<T, VK, M>) => any) | undefined;
99
+ readonly "onUpdate:modelValue"?: ((val: M extends true ? T[number][] : T[number]) => any) | undefined;
104
100
  readonly "onUpdate:expanded"?: ((val: string[]) => any) | undefined;
105
- } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, never>, "onUpdate:modelValue" | "onUpdate:expanded"> & TreeProps<T, VK, M> & {}> & import("vue").PublicProps;
101
+ } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, never>, "onUpdate:modelValue" | "onUpdate:expanded"> & TreeProps<T, M> & {}> & import("vue").PublicProps;
106
102
  expose(exposed: import("vue").ShallowUnwrapRef<{}>): void;
107
103
  attrs: any;
108
- slots: TreeSlots<T, NestedItem<T>>;
109
- emit: ((evt: "update:modelValue", value: GetModelValue<T, VK, M>) => void) & ((evt: "update:expanded", val: string[]) => void);
104
+ slots: TreeSlots<T>;
105
+ emit: ((evt: "update:modelValue", val: M extends true ? T[number][] : T[number]) => void) & ((evt: "update:expanded", val: string[]) => void);
110
106
  }>) => import("vue").VNode & {
111
107
  __ctx?: Awaited<typeof __VLS_setup>;
112
108
  };
@@ -15,7 +15,7 @@ const props = defineProps({
15
15
  as: { type: null, required: false },
16
16
  color: { type: null, required: false },
17
17
  size: { type: null, required: false },
18
- valueKey: { type: null, required: false, default: "value" },
18
+ getKey: { type: Function, required: false },
19
19
  labelKey: { type: null, required: false, default: "label" },
20
20
  trailingIcon: { type: [String, Object], required: false },
21
21
  expandedIcon: { type: [String, Object], required: false },
@@ -33,10 +33,10 @@ const props = defineProps({
33
33
  disabled: { type: Boolean, required: false },
34
34
  bubbleSelect: { type: Boolean, required: false }
35
35
  });
36
- const emits = defineEmits(["update:expanded", "update:modelValue"]);
36
+ const emits = defineEmits(["update:modelValue", "update:expanded"]);
37
37
  const slots = defineSlots();
38
38
  const appConfig = useAppConfig();
39
- const rootProps = useForwardPropsEmits(reactivePick(props, "as", "modelValue", "defaultValue", "items", "multiple", "expanded", "disabled", "propagateSelect", "bubbleSelect"), emits);
39
+ const rootProps = useForwardPropsEmits(reactivePick(props, "as", "items", "multiple", "expanded", "disabled", "propagateSelect", "bubbleSelect"), emits);
40
40
  const [DefineTreeTemplate, ReuseTreeTemplate] = createReusableTemplate();
41
41
  const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.tree || {} })({
42
42
  color: props.color,
@@ -45,11 +45,11 @@ const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.tree || {} })
45
45
  function getItemLabel(item) {
46
46
  return get(item, props.labelKey);
47
47
  }
48
- function getItemValue(item) {
49
- return get(item, props.valueKey) ?? get(item, props.labelKey);
48
+ function getItemKey(item) {
49
+ return props.getKey ? props.getKey(item) || getItemLabel(item) : getItemLabel(item);
50
50
  }
51
51
  function getDefaultOpenedItems(item) {
52
- const currentItem = item.defaultExpanded ? getItemValue(item) : null;
52
+ const currentItem = item.defaultExpanded ? getItemKey(item) : null;
53
53
  const childItems = item.children?.flatMap((child) => getDefaultOpenedItems(child)) ?? [];
54
54
  return [currentItem, ...childItems].filter(Boolean);
55
55
  }
@@ -72,7 +72,8 @@ const defaultExpanded = computed(
72
72
  >
73
73
  <slot
74
74
  :name="item.slot ? `${item.slot}-wrapper` : 'item-wrapper'"
75
- v-bind="{ item, index, level, expanded: isExpanded, selected: isSelected }"
75
+ v-bind="{ index, level, expanded: isExpanded, selected: isSelected }"
76
+ :item="item"
76
77
  >
77
78
  <button
78
79
  type="button"
@@ -80,8 +81,16 @@ const defaultExpanded = computed(
80
81
  :data-expanded="isExpanded"
81
82
  :class="ui.link({ class: [props.ui?.link, item.ui?.link, item.class], selected: isSelected, disabled: item.disabled || disabled })"
82
83
  >
83
- <slot :name="item.slot || 'item'" v-bind="{ index, level, expanded: isExpanded, selected: isSelected }" :item="item">
84
- <slot :name="item.slot ? `${item.slot}-leading` : 'item-leading'" v-bind="{ index, level, expanded: isExpanded, selected: isSelected }" :item="item">
84
+ <slot
85
+ :name="item.slot || 'item'"
86
+ v-bind="{ index, level, expanded: isExpanded, selected: isSelected }"
87
+ :item="item"
88
+ >
89
+ <slot
90
+ :name="item.slot ? `${item.slot}-leading` : 'item-leading'"
91
+ v-bind="{ index, level, expanded: isExpanded, selected: isSelected }"
92
+ :item="item"
93
+ >
85
94
  <UIcon
86
95
  v-if="item.icon"
87
96
  :name="item.icon"
@@ -100,7 +109,8 @@ const defaultExpanded = computed(
100
109
  >
101
110
  <slot
102
111
  :name="item.slot ? `${item.slot}-label` : 'item-label'"
103
- v-bind="{ item, index, level, expanded: isExpanded, selected: isSelected }"
112
+ v-bind="{ index, level, expanded: isExpanded, selected: isSelected }"
113
+ :item="item"
104
114
  >
105
115
  {{ getItemLabel(item) }}
106
116
  </slot>
@@ -112,7 +122,8 @@ const defaultExpanded = computed(
112
122
  >
113
123
  <slot
114
124
  :name="item.slot ? `${item.slot}-trailing` : 'item-trailing'"
115
- v-bind="{ item, index, level, expanded: isExpanded, selected: isSelected }"
125
+ v-bind="{ index, level, expanded: isExpanded, selected: isSelected }"
126
+ :item="item"
116
127
  >
117
128
  <UIcon
118
129
  v-if="item.trailingIcon"
@@ -142,8 +153,10 @@ const defaultExpanded = computed(
142
153
 
143
154
  <TreeRoot
144
155
  v-bind="{ ...rootProps, ...$attrs }"
156
+ :model-value="modelValue"
157
+ :default-value="defaultValue"
145
158
  :class="ui.root({ class: [props.ui?.root, props.class] })"
146
- :get-key="getItemValue"
159
+ :get-key="getItemKey"
147
160
  :default-expanded="defaultExpanded"
148
161
  :selection-behavior="selectionBehavior"
149
162
  >
@@ -2,7 +2,7 @@ import type { TreeRootProps, TreeRootEmits } from 'reka-ui';
2
2
  import type { AppConfig } from '@nuxt/schema';
3
3
  import theme from '#build/ui/tree';
4
4
  import type { IconProps } from '../types';
5
- import type { DynamicSlots, GetItemKeys, GetModelValue, GetModelValueEmits, NestedItem } from '../types/utils';
5
+ import type { DynamicSlots, GetItemKeys } from '../types/utils';
6
6
  import type { ComponentConfig } from '../types/tv';
7
7
  type Tree = ComponentConfig<typeof theme, AppConfig, 'tree'>;
8
8
  export type TreeItem = {
@@ -17,7 +17,6 @@ export type TreeItem = {
17
17
  trailingIcon?: IconProps['name'];
18
18
  defaultExpanded?: boolean;
19
19
  disabled?: boolean;
20
- value?: string;
21
20
  slot?: string;
22
21
  children?: TreeItem[];
23
22
  onToggle?(e: Event): void;
@@ -26,7 +25,7 @@ export type TreeItem = {
26
25
  ui?: Pick<Tree['slots'], 'item' | 'itemWithChildren' | 'link' | 'linkLeadingIcon' | 'linkLabel' | 'linkTrailing' | 'linkTrailingIcon' | 'listWithChildren'>;
27
26
  [key: string]: any;
28
27
  };
29
- export interface TreeProps<T extends TreeItem[] = TreeItem[], VK extends GetItemKeys<T> = 'value', M extends boolean = false> extends Pick<TreeRootProps<T>, 'expanded' | 'defaultExpanded' | 'selectionBehavior' | 'propagateSelect' | 'disabled' | 'bubbleSelect'> {
28
+ export interface TreeProps<T extends TreeItem[] = TreeItem[], M extends boolean = false> extends Pick<TreeRootProps<T>, 'expanded' | 'defaultExpanded' | 'selectionBehavior' | 'propagateSelect' | 'disabled' | 'bubbleSelect'> {
30
29
  /**
31
30
  * The element or component this component should render as.
32
31
  * @defaultValue 'ul'
@@ -40,11 +39,8 @@ export interface TreeProps<T extends TreeItem[] = TreeItem[], VK extends GetItem
40
39
  * @defaultValue 'md'
41
40
  */
42
41
  size?: Tree['variants']['size'];
43
- /**
44
- * The key used to get the value from the item.
45
- * @defaultValue 'value'
46
- */
47
- valueKey?: VK;
42
+ /** This function is passed the index of each item and should return a unique key for that item */
43
+ getKey?: (val: T[number]) => string;
48
44
  /**
49
45
  * The key used to get the label from the item.
50
46
  * @defaultValue 'label'
@@ -70,15 +66,15 @@ export interface TreeProps<T extends TreeItem[] = TreeItem[], VK extends GetItem
70
66
  collapsedIcon?: IconProps['name'];
71
67
  items?: T;
72
68
  /** The controlled value of the Tree. Can be bind as `v-model`. */
73
- modelValue?: GetModelValue<T, VK, M>;
69
+ modelValue?: M extends true ? T[number][] : T[number];
74
70
  /** The value of the Tree when initially rendered. Use when you do not need to control the state of the Tree. */
75
- defaultValue?: GetModelValue<T, VK, M>;
71
+ defaultValue?: M extends true ? T[number][] : T[number];
76
72
  /** Whether multiple options can be selected or not. */
77
73
  multiple?: M & boolean;
78
74
  class?: any;
79
75
  ui?: Tree['slots'];
80
76
  }
81
- export type TreeEmits<A extends TreeItem[], VK extends GetItemKeys<A> | undefined, M extends boolean> = Omit<TreeRootEmits, 'update:modelValue'> & GetModelValueEmits<A, VK, M>;
77
+ export type TreeEmits<T extends TreeItem[] = TreeItem[], M extends boolean = false> = TreeRootEmits<T[number], M>;
82
78
  type SlotProps<T extends TreeItem> = (props: {
83
79
  item: T;
84
80
  index: number;
@@ -86,27 +82,27 @@ type SlotProps<T extends TreeItem> = (props: {
86
82
  expanded: boolean;
87
83
  selected: boolean;
88
84
  }) => any;
89
- export type TreeSlots<A extends TreeItem[] = TreeItem[], T extends NestedItem<A> = NestedItem<A>> = {
90
- 'item-wrapper': SlotProps<T>;
91
- 'item': SlotProps<T>;
92
- 'item-leading': SlotProps<T>;
93
- 'item-label': SlotProps<T>;
94
- 'item-trailing': SlotProps<T>;
95
- } & DynamicSlots<T, undefined, {
85
+ export type TreeSlots<T extends TreeItem[] = TreeItem[]> = {
86
+ 'item-wrapper': SlotProps<T[number]>;
87
+ 'item': SlotProps<T[number]>;
88
+ 'item-leading': SlotProps<T[number]>;
89
+ 'item-label': SlotProps<T[number]>;
90
+ 'item-trailing': SlotProps<T[number]>;
91
+ } & DynamicSlots<T[number], undefined, {
96
92
  index: number;
97
93
  level: number;
98
94
  expanded: boolean;
99
95
  selected: boolean;
100
96
  }>;
101
- declare const _default: <T extends TreeItem[], VK extends GetItemKeys<T> = "value", M extends boolean = false>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
97
+ declare const _default: <T extends TreeItem[], M extends boolean = false>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
102
98
  props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{
103
- readonly "onUpdate:modelValue"?: ((value: GetModelValue<T, VK, M>) => any) | undefined;
99
+ readonly "onUpdate:modelValue"?: ((val: M extends true ? T[number][] : T[number]) => any) | undefined;
104
100
  readonly "onUpdate:expanded"?: ((val: string[]) => any) | undefined;
105
- } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, never>, "onUpdate:modelValue" | "onUpdate:expanded"> & TreeProps<T, VK, M> & {}> & import("vue").PublicProps;
101
+ } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, never>, "onUpdate:modelValue" | "onUpdate:expanded"> & TreeProps<T, M> & {}> & import("vue").PublicProps;
106
102
  expose(exposed: import("vue").ShallowUnwrapRef<{}>): void;
107
103
  attrs: any;
108
- slots: TreeSlots<T, NestedItem<T>>;
109
- emit: ((evt: "update:modelValue", value: GetModelValue<T, VK, M>) => void) & ((evt: "update:expanded", val: string[]) => void);
104
+ slots: TreeSlots<T>;
105
+ emit: ((evt: "update:modelValue", val: M extends true ? T[number][] : T[number]) => void) & ((evt: "update:expanded", val: string[]) => void);
110
106
  }>) => import("vue").VNode & {
111
107
  __ctx?: Awaited<typeof __VLS_setup>;
112
108
  };
@@ -12,7 +12,6 @@ export function useFormField(props, opts) {
12
12
  const formOptions = inject(formOptionsInjectionKey, void 0);
13
13
  const formBus = inject(formBusInjectionKey, void 0);
14
14
  const formField = inject(formFieldInjectionKey, void 0);
15
- const formInputs = inject(formInputsInjectionKey, void 0);
16
15
  const inputId = inject(inputIdInjectionKey, void 0);
17
16
  provide(formFieldInjectionKey, void 0);
18
17
  if (formField && inputId) {
@@ -21,9 +20,6 @@ export function useFormField(props, opts) {
21
20
  } else if (props?.id) {
22
21
  inputId.value = props?.id;
23
22
  }
24
- if (formInputs && formField.value.name && inputId.value) {
25
- formInputs.value[formField.value.name] = { id: inputId.value, pattern: formField.value.errorPattern };
26
- }
27
23
  }
28
24
  function emitFormEvent(type, name, eager) {
29
25
  if (formBus && formField && name) {
@@ -27,7 +27,7 @@ export default defineLocale({
27
27
  prev: "Anterior"
28
28
  },
29
29
  chatPrompt: {
30
- placeholder: "Escreva sua mensagem aqui..."
30
+ placeholder: "Escreva a sua mensagem aqui..."
31
31
  },
32
32
  chatPromptSubmit: {
33
33
  label: "Enviar"
@@ -114,7 +114,7 @@ export default defineLocale({
114
114
  create: 'Criar "{label}"',
115
115
  noData: "Sem dados",
116
116
  noMatch: "Nenhum dado correspondente",
117
- search: "Buscar..."
117
+ search: "Pesquisar..."
118
118
  },
119
119
  slideover: {
120
120
  close: "Fechar"
@@ -1,7 +1,5 @@
1
1
  import type { StandardSchemaV1 } from '@standard-schema/spec';
2
2
  import type { ComputedRef, DeepReadonly, Ref } from 'vue';
3
- import type { Schema as JoiSchema } from 'joi';
4
- import type { ObjectSchema as YupObjectSchema } from 'yup';
5
3
  import type { GetObjectField } from './utils';
6
4
  import type { Struct as SuperstructSchema } from 'superstruct';
7
5
  export interface Form<S extends FormSchema> {
@@ -23,9 +21,9 @@ export interface Form<S extends FormSchema> {
23
21
  touchedFields: ReadonlySet<DeepReadonly<keyof FormData<S, false>>>;
24
22
  blurredFields: ReadonlySet<DeepReadonly<keyof FormData<S, false>>>;
25
23
  }
26
- export type FormSchema<I extends object = object, O extends object = I> = YupObjectSchema<I> | JoiSchema<I> | SuperstructSchema<any, any> | StandardSchemaV1<I, O>;
27
- export type InferInput<Schema> = Schema extends StandardSchemaV1 ? StandardSchemaV1.InferInput<Schema> : Schema extends YupObjectSchema<infer I> ? I : Schema extends JoiSchema<infer I> ? I : Schema extends SuperstructSchema<infer I, any> ? I : Schema extends StandardSchemaV1 ? StandardSchemaV1.InferInput<Schema> : never;
28
- export type InferOutput<Schema> = Schema extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<Schema> : Schema extends YupObjectSchema<infer O> ? O : Schema extends JoiSchema<infer O> ? O : Schema extends SuperstructSchema<infer O, any> ? O : never;
24
+ export type FormSchema<I extends object = object, O extends object = I> = SuperstructSchema<any, any> | StandardSchemaV1<I, O>;
25
+ export type InferInput<Schema> = Schema extends StandardSchemaV1 ? StandardSchemaV1.InferInput<Schema> : Schema extends SuperstructSchema<infer I, any> ? I : Schema extends StandardSchemaV1 ? StandardSchemaV1.InferInput<Schema> : never;
26
+ export type InferOutput<Schema> = Schema extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<Schema> : Schema extends SuperstructSchema<infer O, any> ? O : never;
29
27
  export type FormData<S extends FormSchema, T extends boolean = true> = T extends true ? InferOutput<S> : InferInput<S>;
30
28
  export type FormInputEvents = 'input' | 'blur' | 'change' | 'focus';
31
29
  export interface FormError<P extends string = string> {
@@ -4,11 +4,18 @@ import type { ClassValue, TVVariants, TVCompoundVariants, TVDefaultVariants } fr
4
4
  */
5
5
  export type TVConfig<T extends Record<string, any>> = {
6
6
  [P in keyof T]?: {
7
- [K in keyof T[P] as K extends 'base' | 'slots' | 'variants' | 'compoundVariants' | 'defaultVariants' ? K : never]?: K extends 'base' ? ClassValue : K extends 'slots' ? {
7
+ [K in keyof T[P] as K extends 'base' | 'slots' | 'variants' | 'defaultVariants' ? K : never]?: K extends 'base' ? ClassValue : K extends 'slots' ? {
8
8
  [S in keyof T[P]['slots']]?: ClassValue;
9
- } : K extends 'variants' ? TVVariants<T[P]['slots'], ClassValue, T[P]['variants']> : K extends 'compoundVariants' ? TVCompoundVariants<T[P]['variants'], T[P]['slots'], ClassValue, object, undefined> : K extends 'defaultVariants' ? TVDefaultVariants<T[P]['variants'], T[P]['slots'], object, undefined> : never;
9
+ } : K extends 'variants' ? TVVariants<T[P]['slots'], ClassValue, WidenVariantsValues<T[P]['variants']>> : K extends 'defaultVariants' ? TVDefaultVariants<WidenVariantsValues<T[P]['variants']>, T[P]['slots'], object, undefined> : never;
10
+ };
11
+ } & {
12
+ [P in keyof T]?: {
13
+ compoundVariants?: TVCompoundVariants<WidenVariantsValues<T[P]['variants']>, T[P]['slots'], ClassValue, object, undefined>;
10
14
  };
11
15
  };
16
+ type WidenVariantsValues<V extends Record<string, any> | undefined> = V extends Record<string, any> ? V & {
17
+ [K in keyof V]: V[K] extends Record<string, any> ? V[K] & Record<string & {}, any> : V[K];
18
+ } : V;
12
19
  /**
13
20
  * Utility type to flatten intersection types for better IDE hover information.
14
21
  * @template T The type to flatten.
@@ -1,13 +1,7 @@
1
1
  import type { StandardSchemaV1 } from '@standard-schema/spec';
2
- import type { ValidationError as JoiError, Schema as JoiSchema } from 'joi';
3
- import type { ObjectSchema as YupObjectSchema, ValidationError as YupError } from 'yup';
4
2
  import type { Struct } from 'superstruct';
5
3
  import type { FormSchema, ValidateReturnSchema } from '../types/form';
6
- export declare function isYupSchema(schema: any): schema is YupObjectSchema<any>;
7
- export declare function isYupError(error: any): error is YupError;
8
4
  export declare function isSuperStructSchema(schema: any): schema is Struct<any, any>;
9
- export declare function isJoiSchema(schema: any): schema is JoiSchema;
10
- export declare function isJoiError(error: any): error is JoiError;
11
5
  export declare function isStandardSchema(schema: any): schema is StandardSchemaV1;
12
6
  export declare function validateStandardSchema(state: any, schema: StandardSchemaV1): Promise<ValidateReturnSchema<typeof state>>;
13
7
  export declare function validateSchema<T extends object>(state: T, schema: FormSchema<T>): Promise<ValidateReturnSchema<typeof state>>;
@@ -1,18 +1,6 @@
1
- export function isYupSchema(schema) {
2
- return schema.validate && schema.__isYupSchema__;
3
- }
4
- export function isYupError(error) {
5
- return error.inner !== void 0;
6
- }
7
1
  export function isSuperStructSchema(schema) {
8
2
  return "schema" in schema && typeof schema.coercer === "function" && typeof schema.validator === "function" && typeof schema.refiner === "function";
9
3
  }
10
- export function isJoiSchema(schema) {
11
- return schema.validateAsync !== void 0 && schema.id !== void 0;
12
- }
13
- export function isJoiError(error) {
14
- return error.isJoi === true;
15
- }
16
4
  export function isStandardSchema(schema) {
17
5
  return "~standard" in schema;
18
6
  }
@@ -32,28 +20,6 @@ export async function validateStandardSchema(state, schema) {
32
20
  result: result.value
33
21
  };
34
22
  }
35
- async function validateYupSchema(state, schema) {
36
- try {
37
- const result = await schema.validate(state, { abortEarly: false });
38
- return {
39
- errors: null,
40
- result
41
- };
42
- } catch (error) {
43
- if (isYupError(error)) {
44
- const errors = error.inner.map((issue) => ({
45
- name: issue.path ?? "",
46
- message: issue.message
47
- }));
48
- return {
49
- errors,
50
- result: null
51
- };
52
- } else {
53
- throw error;
54
- }
55
- }
56
- }
57
23
  async function validateSuperstructSchema(state, schema) {
58
24
  const [err, result] = schema.validate(state);
59
25
  if (err) {
@@ -71,35 +37,9 @@ async function validateSuperstructSchema(state, schema) {
71
37
  result
72
38
  };
73
39
  }
74
- async function validateJoiSchema(state, schema) {
75
- try {
76
- const result = await schema.validateAsync(state, { abortEarly: false });
77
- return {
78
- errors: null,
79
- result
80
- };
81
- } catch (error) {
82
- if (isJoiError(error)) {
83
- const errors = error.details.map((issue) => ({
84
- name: issue.path.join("."),
85
- message: issue.message
86
- }));
87
- return {
88
- errors,
89
- result: null
90
- };
91
- } else {
92
- throw error;
93
- }
94
- }
95
- }
96
40
  export function validateSchema(state, schema) {
97
41
  if (isStandardSchema(schema)) {
98
42
  return validateStandardSchema(state, schema);
99
- } else if (isJoiSchema(schema)) {
100
- return validateJoiSchema(state, schema);
101
- } else if (isYupSchema(schema)) {
102
- return validateYupSchema(state, schema);
103
43
  } else if (isSuperStructSchema(schema)) {
104
44
  return validateSuperstructSchema(state, schema);
105
45
  } else {
@@ -6082,7 +6082,7 @@ const icon = {
6082
6082
 
6083
6083
  const img = {
6084
6084
  slots: {
6085
- base: "rounded-md",
6085
+ base: "rounded-md w-full",
6086
6086
  overlay: "fixed inset-0 bg-default/75 backdrop-blur-sm will-change-opacity",
6087
6087
  content: "fixed inset-0 flex items-center justify-center cursor-zoom-out focus:outline-none p-4 sm:p-8"
6088
6088
  },
package/dist/unplugin.mjs CHANGED
@@ -3,7 +3,7 @@ import { join, normalize } from 'pathe';
3
3
  import { createUnplugin } from 'unplugin';
4
4
  import { defu } from 'defu';
5
5
  import tailwind from '@tailwindcss/vite';
6
- import { g as getTemplates, d as defaultOptions, r as resolveColors, a as getDefaultUiConfig } from './shared/ui.Bs5uUhtm.mjs';
6
+ import { g as getTemplates, d as defaultOptions, r as resolveColors, a as getDefaultUiConfig } from './shared/ui.DGJZ-1aX.mjs';
7
7
  import MagicString from 'magic-string';
8
8
  import { genSafeVariableName } from 'knitwork';
9
9
  import { resolvePathSync } from 'mlly';
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.Bs5uUhtm.mjs';
7
+ import './shared/ui.DGJZ-1aX.mjs';
8
8
  import '../dist/runtime/utils/index.js';
9
9
  import 'scule';
10
10
  import 'knitwork';
package/package.json CHANGED
@@ -1,8 +1,8 @@
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.0.0-alpha.2",
5
- "packageManager": "pnpm@10.16.1",
4
+ "version": "4.0.0-beta.0",
5
+ "packageManager": "pnpm@10.17.0",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/nuxt/ui.git"
@@ -108,10 +108,10 @@
108
108
  "typecheck": "vue-tsc --noEmit && nuxt typecheck playgrounds/nuxt && nuxt typecheck docs && cd playgrounds/vue && vue-tsc --noEmit",
109
109
  "test": "vitest",
110
110
  "test:vue": "vitest -c vitest.vue.config.ts",
111
- "release": "release-it --preRelease=alpha"
111
+ "release": "release-it --preRelease=beta"
112
112
  },
113
113
  "dependencies": {
114
- "@ai-sdk/vue": "^2.0.44",
114
+ "@ai-sdk/vue": "^2.0.48",
115
115
  "@iconify/vue": "^5.0.0",
116
116
  "@internationalized/date": "^3.9.0",
117
117
  "@internationalized/number": "^3.6.5",
@@ -124,7 +124,7 @@
124
124
  "@tailwindcss/postcss": "^4.1.13",
125
125
  "@tailwindcss/vite": "^4.1.13",
126
126
  "@tanstack/vue-table": "^8.21.3",
127
- "@unhead/vue": "^2.0.14",
127
+ "@unhead/vue": "^2.0.17",
128
128
  "@vueuse/core": "^13.9.0",
129
129
  "@vueuse/integrations": "^13.9.0",
130
130
  "colortranslator": "^5.0.0",
@@ -153,34 +153,34 @@
153
153
  "tinyglobby": "^0.2.15",
154
154
  "unplugin": "^2.3.10",
155
155
  "unplugin-auto-import": "^20.1.0",
156
- "unplugin-vue-components": "^29.0.0",
156
+ "unplugin-vue-components": "^29.1.0",
157
157
  "vaul-vue": "0.4.1",
158
158
  "vue-component-type-helpers": "^3.0.7"
159
159
  },
160
160
  "devDependencies": {
161
- "@nuxt/content": "^3.7.0",
161
+ "@nuxt/content": "^3.7.1",
162
162
  "@nuxt/eslint-config": "^1.9.0",
163
163
  "@nuxt/module-builder": "^1.0.2",
164
164
  "@nuxt/test-utils": "^3.19.2",
165
165
  "@release-it/conventional-changelog": "^10.0.1",
166
166
  "@vue/test-utils": "^2.4.6",
167
167
  "embla-carousel": "^8.6.0",
168
- "eslint": "^9.35.0",
168
+ "eslint": "^9.36.0",
169
169
  "happy-dom": "^18.0.1",
170
170
  "nuxt": "^4.0.3",
171
- "release-it": "^19.0.4",
171
+ "release-it": "^19.0.5",
172
172
  "vitest": "^3.2.4",
173
173
  "vitest-environment-nuxt": "^1.0.1",
174
174
  "vue-tsc": "^3.0.7"
175
175
  },
176
176
  "peerDependencies": {
177
177
  "@inertiajs/vue3": "^2.0.7",
178
- "joi": "^17.13.0",
178
+ "joi": "^18.0.0",
179
179
  "superstruct": "^2.0.0",
180
180
  "typescript": "^5.6.3",
181
181
  "valibot": "^1.0.0",
182
182
  "vue-router": "^4.5.0",
183
- "yup": "^1.6.0",
183
+ "yup": "^1.7.0",
184
184
  "zod": "^3.24.0 || ^4.0.0"
185
185
  },
186
186
  "peerDependenciesMeta": {