@nuxt/ui 2.18.7 → 2.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/dist/module.d.mts +1 -1
  2. package/dist/module.d.ts +1 -1
  3. package/dist/module.json +1 -1
  4. package/dist/module.mjs +3 -3
  5. package/dist/runtime/components/data/Table.vue +82 -27
  6. package/dist/runtime/components/data/Table.vue.d.ts +45 -37
  7. package/dist/runtime/components/elements/AvatarGroup.js +2 -2
  8. package/dist/runtime/components/elements/ButtonGroup.d.ts +1 -1
  9. package/dist/runtime/components/elements/Carousel.vue +1 -1
  10. package/dist/runtime/components/elements/Dropdown.vue +6 -2
  11. package/dist/runtime/components/elements/MeterGroup.d.ts +2 -2
  12. package/dist/runtime/components/elements/Progress.vue +1 -1
  13. package/dist/runtime/components/forms/Checkbox.vue.d.ts +1 -1
  14. package/dist/runtime/components/forms/Form.vue +104 -43
  15. package/dist/runtime/components/forms/Form.vue.d.ts +5 -3
  16. package/dist/runtime/components/forms/Input.vue +5 -2
  17. package/dist/runtime/components/forms/Input.vue.d.ts +3 -0
  18. package/dist/runtime/components/forms/InputMenu.vue +19 -8
  19. package/dist/runtime/components/forms/InputMenu.vue.d.ts +19 -0
  20. package/dist/runtime/components/forms/Radio.vue.d.ts +1 -1
  21. package/dist/runtime/components/forms/RadioGroup.vue +3 -4
  22. package/dist/runtime/components/forms/RadioGroup.vue.d.ts +1 -1
  23. package/dist/runtime/components/forms/SelectMenu.vue +22 -11
  24. package/dist/runtime/components/forms/SelectMenu.vue.d.ts +30 -2
  25. package/dist/runtime/components/forms/Textarea.vue +7 -4
  26. package/dist/runtime/components/forms/Textarea.vue.d.ts +3 -0
  27. package/dist/runtime/components/layout/Divider.vue +1 -1
  28. package/dist/runtime/components/layout/Divider.vue.d.ts +5 -2
  29. package/dist/runtime/components/navigation/CommandPalette.vue +1 -1
  30. package/dist/runtime/components/navigation/CommandPalette.vue.d.ts +1 -1
  31. package/dist/runtime/components/navigation/CommandPaletteGroup.vue.d.ts +1 -1
  32. package/dist/runtime/components/navigation/Pagination.vue +4 -4
  33. package/dist/runtime/components/navigation/Pagination.vue.d.ts +1 -1
  34. package/dist/runtime/components/navigation/Tabs.vue +1 -1
  35. package/dist/runtime/components/navigation/VerticalNavigation.vue.d.ts +6 -2
  36. package/dist/runtime/components/overlays/Modal.vue +1 -1
  37. package/dist/runtime/components/overlays/Notifications.vue +1 -1
  38. package/dist/runtime/components/overlays/Popover.vue +6 -2
  39. package/dist/runtime/composables/defineShortcuts.js +1 -1
  40. package/dist/runtime/composables/useButtonGroup.d.ts +1 -1
  41. package/dist/runtime/composables/useUI.js +1 -1
  42. package/dist/runtime/plugins/modals.js +1 -1
  43. package/dist/runtime/plugins/slideovers.js +1 -1
  44. package/dist/runtime/types/accordion.d.ts +1 -1
  45. package/dist/runtime/types/alert.d.ts +4 -4
  46. package/dist/runtime/types/avatar.d.ts +3 -3
  47. package/dist/runtime/types/badge.d.ts +3 -3
  48. package/dist/runtime/types/button.d.ts +3 -5
  49. package/dist/runtime/types/chip.d.ts +2 -2
  50. package/dist/runtime/types/command-palette.d.ts +2 -2
  51. package/dist/runtime/types/component.d.ts +3 -3
  52. package/dist/runtime/types/divider.d.ts +3 -3
  53. package/dist/runtime/types/dropdown.d.ts +1 -1
  54. package/dist/runtime/types/form-group.d.ts +2 -2
  55. package/dist/runtime/types/form.d.ts +7 -2
  56. package/dist/runtime/types/index.d.ts +1 -0
  57. package/dist/runtime/types/index.js +1 -0
  58. package/dist/runtime/types/input.d.ts +3 -3
  59. package/dist/runtime/types/kbd.d.ts +2 -2
  60. package/dist/runtime/types/meter.d.ts +2 -2
  61. package/dist/runtime/types/modal.d.ts +2 -2
  62. package/dist/runtime/types/notification.d.ts +1 -1
  63. package/dist/runtime/types/progress.d.ts +2 -2
  64. package/dist/runtime/types/range.d.ts +3 -3
  65. package/dist/runtime/types/select.d.ts +3 -3
  66. package/dist/runtime/types/table.d.ts +18 -0
  67. package/dist/runtime/types/textarea.d.ts +3 -3
  68. package/dist/runtime/types/toggle.d.ts +3 -3
  69. package/dist/runtime/types/utils.d.ts +2 -2
  70. package/dist/runtime/ui.config/data/table.d.ts +1 -0
  71. package/dist/runtime/ui.config/data/table.js +1 -0
  72. package/dist/runtime/ui.config/elements/avatar.js +15 -15
  73. package/dist/runtime/ui.config/elements/button.js +25 -25
  74. package/dist/runtime/ui.config/elements/buttonGroup.js +1 -1
  75. package/dist/runtime/ui.config/elements/chip.js +5 -5
  76. package/dist/runtime/ui.config/elements/meter.js +20 -20
  77. package/dist/runtime/ui.config/elements/meterGroup.js +1 -1
  78. package/dist/runtime/ui.config/elements/progress.js +18 -18
  79. package/dist/runtime/ui.config/forms/formGroup.js +5 -6
  80. package/dist/runtime/ui.config/forms/input.js +40 -40
  81. package/dist/runtime/ui.config/forms/inputMenu.d.ts +6 -0
  82. package/dist/runtime/ui.config/forms/inputMenu.js +7 -1
  83. package/dist/runtime/ui.config/forms/range.js +20 -20
  84. package/dist/runtime/ui.config/forms/selectMenu.d.ts +9 -0
  85. package/dist/runtime/ui.config/forms/selectMenu.js +10 -1
  86. package/dist/runtime/ui.config/forms/toggle.js +20 -20
  87. package/dist/runtime/ui.config/layout/divider.d.ts +1 -0
  88. package/dist/runtime/ui.config/layout/divider.js +12 -11
  89. package/dist/runtime/ui.config/navigation/horizontalNavigation.js +1 -1
  90. package/dist/runtime/ui.config/navigation/verticalNavigation.js +1 -1
  91. package/dist/runtime/ui.config/popper.js +0 -1
  92. package/dist/runtime/utils/colors.js +7 -7
  93. package/dist/runtime/utils/index.js +4 -4
  94. package/dist/runtime/utils/lodash.js +1 -1
  95. package/package.json +21 -19
@@ -56,16 +56,11 @@ export default defineComponent({
56
56
  async function getErrors() {
57
57
  let errs = await props.validate(props.state);
58
58
  if (props.schema) {
59
- if (isZodSchema(props.schema)) {
60
- errs = errs.concat(await getZodErrors(props.state, props.schema));
61
- } else if (isYupSchema(props.schema)) {
62
- errs = errs.concat(await getYupErrors(props.state, props.schema));
63
- } else if (isJoiSchema(props.schema)) {
64
- errs = errs.concat(await getJoiErrors(props.state, props.schema));
65
- } else if (isValibotSchema(props.schema)) {
66
- errs = errs.concat(await getValibotError(props.state, props.schema));
59
+ const { errors: errors2, result } = await parseSchema(props.state, props.schema);
60
+ if (errors2) {
61
+ errs = errs.concat(errors2);
67
62
  } else {
68
- throw new Error("Form validation failed: Unsupported form schema");
63
+ Object.assign(props.state, result);
69
64
  }
70
65
  }
71
66
  return errs;
@@ -157,64 +152,130 @@ function isYupSchema(schema) {
157
152
  function isYupError(error) {
158
153
  return error.inner !== void 0;
159
154
  }
160
- async function getYupErrors(state, schema) {
155
+ function isSuperStructSchema(schema) {
156
+ return "schema" in schema && typeof schema.coercer === "function" && typeof schema.validator === "function" && typeof schema.refiner === "function";
157
+ }
158
+ function isJoiSchema(schema) {
159
+ return schema.validateAsync !== void 0 && schema.id !== void 0;
160
+ }
161
+ function isJoiError(error) {
162
+ return error.isJoi === true;
163
+ }
164
+ function isValibotSchema(schema) {
165
+ return "_parse" in schema || "_run" in schema || typeof schema === "function" && "schema" in schema;
166
+ }
167
+ function isZodSchema(schema) {
168
+ return schema.parse !== void 0;
169
+ }
170
+ async function validateValibotSchema(state, schema) {
171
+ const result = await ("_parse" in schema ? schema._parse(state) : "_run" in schema ? schema._run({ typed: false, value: state }, {}) : schema(state));
172
+ if (!result.issues || result.issues.length === 0) {
173
+ const output = "output" in result ? result.output : "value" in result ? result.value : null;
174
+ return {
175
+ errors: null,
176
+ result: output
177
+ };
178
+ }
179
+ const errors = result.issues.map((issue) => ({
180
+ path: issue.path?.map((item) => item.key).join(".") || "",
181
+ message: issue.message
182
+ }));
183
+ return {
184
+ errors,
185
+ result: null
186
+ };
187
+ }
188
+ async function validateJoiSchema(state, schema) {
161
189
  try {
162
- await schema.validate(state, { abortEarly: false });
163
- return [];
190
+ await schema.validateAsync(state, { abortEarly: false });
191
+ return {
192
+ errors: null,
193
+ result: state
194
+ };
164
195
  } catch (error) {
165
- if (isYupError(error)) {
166
- return error.inner.map((issue) => ({
167
- path: issue.path ?? "",
196
+ if (isJoiError(error)) {
197
+ const errors = error.details.map((issue) => ({
198
+ path: issue.path.join("."),
168
199
  message: issue.message
169
200
  }));
201
+ return {
202
+ errors,
203
+ result: null
204
+ };
170
205
  } else {
171
206
  throw error;
172
207
  }
173
208
  }
174
209
  }
175
- function isZodSchema(schema) {
176
- return schema.parse !== void 0;
177
- }
178
- async function getZodErrors(state, schema) {
210
+ async function validateZodSchema(state, schema) {
179
211
  const result = await schema.safeParseAsync(state);
180
212
  if (result.success === false) {
181
- return result.error.issues.map((issue) => ({
213
+ const errors = result.error.issues.map((issue) => ({
182
214
  path: issue.path.join("."),
183
215
  message: issue.message
184
216
  }));
217
+ return {
218
+ errors,
219
+ result: null
220
+ };
185
221
  }
186
- return [];
187
- }
188
- function isJoiSchema(schema) {
189
- return schema.validateAsync !== void 0 && schema.id !== void 0;
222
+ return {
223
+ result: result.data,
224
+ errors: null
225
+ };
190
226
  }
191
- function isJoiError(error) {
192
- return error.isJoi === true;
227
+ async function validateSuperstructSchema(state, schema) {
228
+ const [err, result] = schema.validate(state);
229
+ if (err) {
230
+ const errors = err.failures().map((error) => ({
231
+ message: error.message,
232
+ path: error.path.join(".")
233
+ }));
234
+ return {
235
+ errors,
236
+ result: null
237
+ };
238
+ }
239
+ return {
240
+ errors: null,
241
+ result
242
+ };
193
243
  }
194
- async function getJoiErrors(state, schema) {
244
+ async function validateYupSchema(state, schema) {
195
245
  try {
196
- await schema.validateAsync(state, { abortEarly: false });
197
- return [];
246
+ const result = schema.validateSync(state, { abortEarly: false });
247
+ return {
248
+ errors: null,
249
+ result
250
+ };
198
251
  } catch (error) {
199
- if (isJoiError(error)) {
200
- return error.details.map((detail) => ({
201
- path: detail.path.join("."),
202
- message: detail.message
252
+ if (isYupError(error)) {
253
+ const errors = error.inner.map((issue) => ({
254
+ path: issue.path ?? "",
255
+ message: issue.message
203
256
  }));
257
+ return {
258
+ errors,
259
+ result: null
260
+ };
204
261
  } else {
205
262
  throw error;
206
263
  }
207
264
  }
208
265
  }
209
- function isValibotSchema(schema) {
210
- return "_parse" in schema || "_run" in schema || typeof schema === "function" && "schema" in schema;
211
- }
212
- async function getValibotError(state, schema) {
213
- const result = await ("_parse" in schema ? schema._parse(state) : "_run" in schema ? schema._run({ typed: false, value: state }, {}) : schema(state));
214
- return result.issues?.map((issue) => ({
215
- // We know that the key for a form schema is always a string or a number
216
- path: issue.path?.map((item) => item.key).join(".") || "",
217
- message: issue.message
218
- })) || [];
266
+ function parseSchema(state, schema) {
267
+ if (isZodSchema(schema)) {
268
+ return validateZodSchema(state, schema);
269
+ } else if (isJoiSchema(schema)) {
270
+ return validateJoiSchema(state, schema);
271
+ } else if (isValibotSchema(schema)) {
272
+ return validateValibotSchema(state, schema);
273
+ } else if (isYupSchema(schema)) {
274
+ return validateYupSchema(state, schema);
275
+ } else if (isSuperStructSchema(schema)) {
276
+ return validateSuperstructSchema(state, schema);
277
+ } else {
278
+ throw new Error("Form validation failed: Unsupported form schema");
279
+ }
219
280
  }
220
281
  </script>
@@ -5,10 +5,12 @@ import type { ObjectSchema as YupObjectSchema } from 'yup';
5
5
  import type { BaseSchema as ValibotSchema30, BaseSchemaAsync as ValibotSchemaAsync30 } from 'valibot30';
6
6
  import type { GenericSchema as ValibotSchema31, GenericSchemaAsync as ValibotSchemaAsync31, SafeParser as ValibotSafeParser31, SafeParserAsync as ValibotSafeParserAsync31 } from 'valibot31';
7
7
  import type { GenericSchema as ValibotSchema, GenericSchemaAsync as ValibotSchemaAsync, SafeParser as ValibotSafeParser, SafeParserAsync as ValibotSafeParserAsync } from 'valibot';
8
+ import type { Struct } from 'superstruct';
8
9
  import type { FormError, FormEventType } from '../../types/form.js';
10
+ type Schema = PropType<ZodSchema> | PropType<YupObjectSchema<any>> | PropType<JoiSchema> | PropType<ValibotSchema30 | ValibotSchemaAsync30> | PropType<ValibotSchema31 | ValibotSchemaAsync31> | PropType<ValibotSafeParser31<any, any> | ValibotSafeParserAsync31<any, any>> | PropType<ValibotSchema | ValibotSchemaAsync> | PropType<ValibotSafeParser<any, any> | ValibotSafeParserAsync<any, any>> | PropType<Struct<any, any>>;
9
11
  declare const _default: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
10
12
  schema: {
11
- type: PropType<ZodSchema> | PropType<YupObjectSchema<any>> | PropType<JoiSchema> | PropType<ValibotSchema30 | ValibotSchemaAsync30> | PropType<ValibotSchema31 | ValibotSchemaAsync31> | PropType<ValibotSafeParser31<any, any> | ValibotSafeParserAsync31<any, any>> | PropType<ValibotSchema | ValibotSchemaAsync> | PropType<ValibotSafeParser<any, any> | ValibotSafeParserAsync<any, any>>;
13
+ type: Schema;
12
14
  default: any;
13
15
  };
14
16
  state: {
@@ -34,7 +36,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
34
36
  }[]>>;
35
37
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("error" | "submit")[], "error" | "submit", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
36
38
  schema: {
37
- type: PropType<ZodSchema> | PropType<YupObjectSchema<any>> | PropType<JoiSchema> | PropType<ValibotSchema30 | ValibotSchemaAsync30> | PropType<ValibotSchema31 | ValibotSchemaAsync31> | PropType<ValibotSafeParser31<any, any> | ValibotSafeParserAsync31<any, any>> | PropType<ValibotSchema | ValibotSchemaAsync> | PropType<ValibotSafeParser<any, any> | ValibotSafeParserAsync<any, any>>;
39
+ type: Schema;
38
40
  default: any;
39
41
  };
40
42
  state: {
@@ -53,7 +55,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
53
55
  onSubmit?: (...args: any[]) => any;
54
56
  onError?: (...args: any[]) => any;
55
57
  }>, {
56
- schema: ZodSchema<any, import("zod").ZodTypeDef, any> | YupObjectSchema<any, import("yup").AnyObject, any, ""> | import("joi").AnySchema<any> | ValibotSchema30<any, any> | ValibotSchemaAsync30<any, any> | ValibotSchema31<unknown, unknown, import("valibot31").BaseIssue<unknown>> | ValibotSchemaAsync31<unknown, unknown, import("valibot31").BaseIssue<unknown>> | ValibotSafeParser31<any, any> | ValibotSafeParserAsync31<any, any> | ValibotSchema<unknown, unknown, import("valibot").BaseIssue<unknown>> | ValibotSchemaAsync<unknown, unknown, import("valibot").BaseIssue<unknown>>;
58
+ schema: ZodSchema<any, import("zod").ZodTypeDef, any> | YupObjectSchema<any, import("yup").AnyObject, any, ""> | import("joi").AnySchema<any> | ValibotSchema30<any, any> | ValibotSchemaAsync30<any, any> | ValibotSchema31<unknown, unknown, import("valibot31").BaseIssue<unknown>> | ValibotSchemaAsync31<unknown, unknown, import("valibot31").BaseIssue<unknown>> | ValibotSafeParser31<any, any> | ValibotSafeParserAsync31<any, any> | ValibotSchema<unknown, unknown, import("valibot").BaseIssue<unknown>> | ValibotSchemaAsync<unknown, unknown, import("valibot").BaseIssue<unknown>> | Struct<any, any>;
57
59
  validate: ((state: any) => Promise<FormError[]>) | ((state: any) => FormError[]);
58
60
  validateOn: FormEventType[];
59
61
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -33,8 +33,8 @@
33
33
  <script>
34
34
  import { ref, computed, toRef, onMounted, defineComponent } from "vue";
35
35
  import { twMerge, twJoin } from "tailwind-merge";
36
- import UIcon from "../elements/Icon.vue";
37
36
  import { defu } from "defu";
37
+ import UIcon from "../elements/Icon.vue";
38
38
  import { useUI } from "../../composables/useUI";
39
39
  import { useFormGroup } from "../../composables/useFormGroup";
40
40
  import { mergeConfig, looseToNumber } from "../../utils";
@@ -163,7 +163,7 @@ export default defineComponent({
163
163
  const { size: sizeButtonGroup, rounded } = useInjectButtonGroup({ ui, props });
164
164
  const { emitFormBlur, emitFormInput, size: sizeFormGroup, color, inputId, name } = useFormGroup(props, config);
165
165
  const size = computed(() => sizeButtonGroup.value ?? sizeFormGroup.value);
166
- const modelModifiers = ref(defu({}, props.modelModifiers, { trim: false, lazy: false, number: false }));
166
+ const modelModifiers = ref(defu({}, props.modelModifiers, { trim: false, lazy: false, number: false, nullify: false }));
167
167
  const input2 = ref(null);
168
168
  const autoFocus = () => {
169
169
  if (props.autofocus) {
@@ -177,6 +177,9 @@ export default defineComponent({
177
177
  if (modelModifiers.value.number || props.type === "number") {
178
178
  value = looseToNumber(value);
179
179
  }
180
+ if (modelModifiers.value.nullify) {
181
+ value ||= null;
182
+ }
180
183
  emit("update:modelValue", value);
181
184
  emitFormInput();
182
185
  };
@@ -212,6 +212,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
212
212
  trim?: boolean;
213
213
  lazy?: boolean;
214
214
  number?: boolean;
215
+ nullify?: boolean;
215
216
  }>;
216
217
  default: () => {};
217
218
  };
@@ -446,6 +447,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
446
447
  trim?: boolean;
447
448
  lazy?: boolean;
448
449
  number?: boolean;
450
+ nullify?: boolean;
449
451
  }>;
450
452
  default: () => {};
451
453
  };
@@ -593,6 +595,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
593
595
  trim?: boolean;
594
596
  lazy?: boolean;
595
597
  number?: boolean;
598
+ nullify?: boolean;
596
599
  };
597
600
  }, {}, {
598
601
  UIcon: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
@@ -63,7 +63,7 @@
63
63
  />
64
64
  <span v-else-if="option.chip" :class="uiMenu.option.chip.base" :style="{ background: `#${option.chip}` }" />
65
65
 
66
- <span class="truncate">{{ ['string', 'number'].includes(typeof option) ? option : option[optionAttribute] }}</span>
66
+ <span class="truncate">{{ ['string', 'number'].includes(typeof option) ? option : accessor(option, optionAttribute) }}</span>
67
67
  </slot>
68
68
  </div>
69
69
 
@@ -75,12 +75,12 @@
75
75
 
76
76
  <p v-if="query && !filteredOptions.length" :class="uiMenu.option.empty">
77
77
  <slot name="option-empty" :query="query">
78
- No results for "{{ query }}".
78
+ {{ uiMenu.default.optionEmpty.label.replace('{query}', query) }}
79
79
  </slot>
80
80
  </p>
81
81
  <p v-else-if="!filteredOptions.length" :class="uiMenu.empty">
82
82
  <slot name="empty" :query="query">
83
- No options.
83
+ {{ uiMenu.default.empty.label }}
84
84
  </slot>
85
85
  </p>
86
86
  </HComboboxOptions>
@@ -91,7 +91,7 @@
91
91
  </template>
92
92
 
93
93
  <script>
94
- import { ref, computed, toRef, watch, defineComponent } from "vue";
94
+ import { ref, computed, toRef, watch, defineComponent, toRaw } from "vue";
95
95
  import {
96
96
  Combobox as HCombobox,
97
97
  ComboboxButton as HComboboxButton,
@@ -297,9 +297,9 @@ export default defineComponent({
297
297
  }
298
298
  if (props.valueAttribute) {
299
299
  const option = options.value.find((option2) => option2[props.valueAttribute] === props.modelValue);
300
- return option ? option[props.optionAttribute] : null;
300
+ return option ? accessor(option, props.optionAttribute) : null;
301
301
  } else {
302
- return ["string", "number"].includes(typeof props.modelValue) ? props.modelValue : props.modelValue[props.optionAttribute];
302
+ return ["string", "number"].includes(typeof props.modelValue) ? props.modelValue : accessor(props.modelValue, props.optionAttribute);
303
303
  }
304
304
  });
305
305
  const inputClass = computed(() => {
@@ -372,17 +372,21 @@ export default defineComponent({
372
372
  }, [], {
373
373
  lazy: props.searchLazy
374
374
  });
375
+ function escapeRegExp(string) {
376
+ return string.replace(/[.*+?^${}()|[\]\\]/g, (match) => `\\${match}`);
377
+ }
375
378
  const filteredOptions = computed(() => {
376
379
  if (!query.value || debouncedSearch) {
377
380
  return options.value;
378
381
  }
382
+ const escapedQuery = escapeRegExp(query.value);
379
383
  return options.value.filter((option) => {
380
384
  return (props.searchAttributes?.length ? props.searchAttributes : [props.optionAttribute]).some((searchAttribute) => {
381
385
  if (["string", "number"].includes(typeof option)) {
382
- return String(option).search(new RegExp(query.value, "i")) !== -1;
386
+ return String(option).search(new RegExp(escapedQuery, "i")) !== -1;
383
387
  }
384
388
  const child = get(option, searchAttribute);
385
- return child !== null && child !== void 0 && String(child).search(new RegExp(query.value, "i")) !== -1;
389
+ return child !== null && child !== void 0 && String(child).search(new RegExp(escapedQuery, "i")) !== -1;
386
390
  });
387
391
  });
388
392
  });
@@ -396,10 +400,16 @@ export default defineComponent({
396
400
  });
397
401
  function onUpdate(value) {
398
402
  query.value = "";
403
+ if (toRaw(props.modelValue) === toRaw(value)) {
404
+ return;
405
+ }
399
406
  emit("update:modelValue", value);
400
407
  emit("change", value);
401
408
  emitFormChange();
402
409
  }
410
+ function accessor(obj, key) {
411
+ return get(obj, key);
412
+ }
403
413
  function onQueryChange(event) {
404
414
  query.value = event.target.value;
405
415
  }
@@ -431,6 +441,7 @@ export default defineComponent({
431
441
  filteredOptions,
432
442
  // eslint-disable-next-line vue/no-dupe-keys
433
443
  query,
444
+ accessor,
434
445
  onUpdate,
435
446
  onQueryChange
436
447
  };
@@ -162,6 +162,12 @@ declare const configMenu: {
162
162
  default: {
163
163
  selectedIcon: string;
164
164
  trailingIcon: string;
165
+ empty: {
166
+ label: string;
167
+ };
168
+ optionEmpty: {
169
+ label: string;
170
+ };
165
171
  };
166
172
  arrow: {
167
173
  ring: string;
@@ -478,6 +484,12 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
478
484
  default: {
479
485
  selectedIcon: string;
480
486
  trailingIcon: string;
487
+ empty: {
488
+ label: string;
489
+ };
490
+ optionEmpty: {
491
+ label: string;
492
+ };
481
493
  };
482
494
  arrow: {
483
495
  ring: string;
@@ -508,6 +520,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
508
520
  trailingWrapperIconClass: import("vue").ComputedRef<string>;
509
521
  filteredOptions: import("vue").ComputedRef<any[]>;
510
522
  query: import("vue").WritableComputedRef<string, string>;
523
+ accessor: <T extends Record<string, any>>(obj: T, key: string) => any;
511
524
  onUpdate: (value: any) => void;
512
525
  onQueryChange: (event: any) => void;
513
526
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("change" | "close" | "update:modelValue" | "open" | "update:query")[], "change" | "close" | "update:modelValue" | "open" | "update:query", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
@@ -860,6 +873,12 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
860
873
  default?: DeepPartial<{
861
874
  selectedIcon: string;
862
875
  trailingIcon: string;
876
+ empty: {
877
+ label: string;
878
+ };
879
+ optionEmpty: {
880
+ label: string;
881
+ };
863
882
  }, any>;
864
883
  arrow?: DeepPartial<{
865
884
  ring: string;
@@ -1,6 +1,6 @@
1
1
  import type { PropType } from 'vue';
2
2
  import type { DeepPartial, Strategy } from '../../types/index.js';
3
- import colors from '#ui-colors';
3
+ import type colors from '#ui-colors';
4
4
  declare const config: {
5
5
  wrapper: string;
6
6
  container: string;
@@ -17,11 +17,11 @@
17
17
  :ui="uiRadio"
18
18
  @change="onUpdate(option.value)"
19
19
  >
20
- <template #label>
20
+ <template v-if="$slots.label" #label>
21
21
  <slot name="label" v-bind="{ option, selected: option.selected }" />
22
22
  </template>
23
23
 
24
- <template #help>
24
+ <template v-if="$slots.help" #help>
25
25
  <slot name="help" v-bind="{ option, selected: option.selected }" />
26
26
  </template>
27
27
  </URadio>
@@ -30,11 +30,11 @@
30
30
  </template>
31
31
 
32
32
  <script>
33
- import URadio from "./Radio.vue";
34
33
  import { computed, defineComponent, provide, toRef } from "vue";
35
34
  import { useUI } from "../../composables/useUI";
36
35
  import { useFormGroup } from "../../composables/useFormGroup";
37
36
  import { mergeConfig, get } from "../../utils";
37
+ import URadio from "./Radio.vue";
38
38
  import appConfig from "#build/app.config";
39
39
  import { radioGroup, radio } from "#ui/ui.config";
40
40
  const config = mergeConfig(appConfig.ui.strategy, appConfig.ui.radioGroup, radioGroup);
@@ -137,7 +137,6 @@ export default defineComponent({
137
137
  uiRadio,
138
138
  attrs,
139
139
  normalizedOptions,
140
- // eslint-disable-next-line vue/no-dupe-keys
141
140
  onUpdate
142
141
  };
143
142
  }
@@ -1,6 +1,6 @@
1
1
  import type { PropType } from 'vue';
2
2
  import type { DeepPartial, Strategy } from '../../types/index.js';
3
- import colors from '#ui-colors';
3
+ import type colors from '#ui-colors';
4
4
  declare const config: {
5
5
  wrapper: string;
6
6
  fieldset: string;
@@ -86,7 +86,7 @@
86
86
  />
87
87
  <span v-else-if="option.chip" :class="uiMenu.option.chip.base" :style="{ background: `#${option.chip}` }" />
88
88
 
89
- <span class="truncate">{{ ['string', 'number'].includes(typeof option) ? option : option[optionAttribute] }}</span>
89
+ <span class="truncate">{{ ['string', 'number'].includes(typeof option) ? option : accessor(option, optionAttribute) }}</span>
90
90
  </slot>
91
91
  </div>
92
92
 
@@ -100,19 +100,19 @@
100
100
  <li :class="[uiMenu.option.base, uiMenu.option.rounded, uiMenu.option.padding, uiMenu.option.size, uiMenu.option.color, active ? uiMenu.option.active : uiMenu.option.inactive]">
101
101
  <div :class="uiMenu.option.container">
102
102
  <slot name="option-create" :option="createOption" :active="active" :selected="optionSelected">
103
- <span :class="uiMenu.option.create">Create "{{ createOption[optionAttribute] }}"</span>
103
+ <span :class="uiMenu.option.create">Create "{{ typeof createOption === 'string' ? createOption : accessor(createOption, optionAttribute) }}"</span>
104
104
  </slot>
105
105
  </div>
106
106
  </li>
107
107
  </component>
108
108
  <p v-else-if="searchable && query && !filteredOptions?.length" :class="uiMenu.option.empty">
109
109
  <slot name="option-empty" :query="query">
110
- No results for "{{ query }}".
110
+ {{ uiMenu.default.optionEmpty.label.replace('{query}', query) }}
111
111
  </slot>
112
112
  </p>
113
113
  <p v-else-if="!filteredOptions?.length" :class="uiMenu.empty">
114
114
  <slot name="empty" :query="query">
115
- No options.
115
+ {{ uiMenu.default.empty.label }}
116
116
  </slot>
117
117
  </p>
118
118
  </component>
@@ -123,7 +123,7 @@
123
123
  </template>
124
124
 
125
125
  <script>
126
- import { ref, computed, toRef, watch, defineComponent } from "vue";
126
+ import { ref, computed, toRef, watch, defineComponent, toRaw } from "vue";
127
127
  import {
128
128
  Combobox as HCombobox,
129
129
  ComboboxButton as HComboboxButton,
@@ -241,7 +241,7 @@ export default defineComponent({
241
241
  },
242
242
  searchablePlaceholder: {
243
243
  type: String,
244
- default: "Search..."
244
+ default: () => configMenu.default.searchablePlaceholder.label
245
245
  },
246
246
  searchableLazy: {
247
247
  type: Boolean,
@@ -374,9 +374,9 @@ export default defineComponent({
374
374
  }
375
375
  } else if (props.modelValue !== void 0 && props.modelValue !== null) {
376
376
  if (props.valueAttribute) {
377
- return selected.value?.[props.optionAttribute] ?? null;
377
+ return accessor(selected.value, props.optionAttribute) ?? null;
378
378
  } else {
379
- return ["string", "number"].includes(typeof props.modelValue) ? props.modelValue : props.modelValue[props.optionAttribute];
379
+ return ["string", "number"].includes(typeof props.modelValue) ? props.modelValue : accessor(props.modelValue, props.optionAttribute);
380
380
  }
381
381
  }
382
382
  return null;
@@ -452,17 +452,24 @@ export default defineComponent({
452
452
  }, [], {
453
453
  lazy: props.searchableLazy
454
454
  });
455
+ function escapeRegExp(string) {
456
+ return string.replace(/[.*+?^${}()|[\]\\]/g, (match) => `\\${match}`);
457
+ }
458
+ function accessor(obj, key) {
459
+ return get(obj, key);
460
+ }
455
461
  const filteredOptions = computed(() => {
456
462
  if (!query.value || debouncedSearch) {
457
463
  return options.value;
458
464
  }
465
+ const escapedQuery = escapeRegExp(query.value);
459
466
  return options.value.filter((option) => {
460
467
  return (props.searchAttributes?.length ? props.searchAttributes : [props.optionAttribute]).some((searchAttribute) => {
461
468
  if (["string", "number"].includes(typeof option)) {
462
- return String(option).search(new RegExp(query.value, "i")) !== -1;
469
+ return String(option).search(new RegExp(escapedQuery, "i")) !== -1;
463
470
  }
464
471
  const child = get(option, searchAttribute);
465
- return child !== null && child !== void 0 && String(child).search(new RegExp(query.value, "i")) !== -1;
472
+ return child !== null && child !== void 0 && String(child).search(new RegExp(escapedQuery, "i")) !== -1;
466
473
  });
467
474
  });
468
475
  });
@@ -474,7 +481,7 @@ export default defineComponent({
474
481
  return null;
475
482
  }
476
483
  if (props.showCreateOptionWhen === "always") {
477
- const existingOption = filteredOptions.value.find((option) => ["string", "number"].includes(typeof option) ? option === query.value : option[props.optionAttribute] === query.value);
484
+ const existingOption = filteredOptions.value.find((option) => ["string", "number"].includes(typeof option) ? option === query.value : accessor(option, props.optionAttribute) === query.value);
478
485
  if (existingOption) {
479
486
  return null;
480
487
  }
@@ -501,6 +508,9 @@ export default defineComponent({
501
508
  }
502
509
  });
503
510
  function onUpdate(value) {
511
+ if (toRaw(props.modelValue) === value) {
512
+ return;
513
+ }
504
514
  emit("update:modelValue", value);
505
515
  emit("change", value);
506
516
  emitFormChange();
@@ -524,6 +534,7 @@ export default defineComponent({
524
534
  container,
525
535
  selected,
526
536
  label,
537
+ accessor,
527
538
  isLeading,
528
539
  isTrailing,
529
540
  // eslint-disable-next-line vue/no-dupe-keys
@@ -158,6 +158,15 @@ declare const configMenu: {
158
158
  selectedIcon: string;
159
159
  clearSearchOnClose: boolean;
160
160
  showCreateOptionWhen: string;
161
+ searchablePlaceholder: {
162
+ label: string;
163
+ };
164
+ empty: {
165
+ label: string;
166
+ };
167
+ optionEmpty: {
168
+ label: string;
169
+ };
161
170
  };
162
171
  arrow: {
163
172
  ring: string;
@@ -257,7 +266,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
257
266
  };
258
267
  searchablePlaceholder: {
259
268
  type: StringConstructor;
260
- default: string;
269
+ default: () => string;
261
270
  };
262
271
  searchableLazy: {
263
272
  type: BooleanConstructor;
@@ -497,6 +506,15 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
497
506
  selectedIcon: string;
498
507
  clearSearchOnClose: boolean;
499
508
  showCreateOptionWhen: string;
509
+ searchablePlaceholder: {
510
+ label: string;
511
+ };
512
+ empty: {
513
+ label: string;
514
+ };
515
+ optionEmpty: {
516
+ label: string;
517
+ };
500
518
  };
501
519
  arrow: {
502
520
  ring: string;
@@ -528,6 +546,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
528
546
  container: import("vue").Ref<import("@vueuse/core").MaybeElement, import("@vueuse/core").MaybeElement>;
529
547
  selected: import("vue").ComputedRef<any>;
530
548
  label: import("vue").ComputedRef<any>;
549
+ accessor: <T extends Record<string, any>>(obj: T, key: string) => any;
531
550
  isLeading: import("vue").ComputedRef<string | true>;
532
551
  isTrailing: import("vue").ComputedRef<string | true>;
533
552
  selectClass: import("vue").ComputedRef<string>;
@@ -622,7 +641,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
622
641
  };
623
642
  searchablePlaceholder: {
624
643
  type: StringConstructor;
625
- default: string;
644
+ default: () => string;
626
645
  };
627
646
  searchableLazy: {
628
647
  type: BooleanConstructor;
@@ -903,6 +922,15 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
903
922
  selectedIcon: string;
904
923
  clearSearchOnClose: boolean;
905
924
  showCreateOptionWhen: string;
925
+ searchablePlaceholder: {
926
+ label: string;
927
+ };
928
+ empty: {
929
+ label: string;
930
+ };
931
+ optionEmpty: {
932
+ label: string;
933
+ };
906
934
  }, any>;
907
935
  arrow?: DeepPartial<{
908
936
  ring: string;