@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.
- package/dist/module.d.mts +1 -1
- package/dist/module.d.ts +1 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +3 -3
- package/dist/runtime/components/data/Table.vue +82 -27
- package/dist/runtime/components/data/Table.vue.d.ts +45 -37
- package/dist/runtime/components/elements/AvatarGroup.js +2 -2
- package/dist/runtime/components/elements/ButtonGroup.d.ts +1 -1
- package/dist/runtime/components/elements/Carousel.vue +1 -1
- package/dist/runtime/components/elements/Dropdown.vue +6 -2
- package/dist/runtime/components/elements/MeterGroup.d.ts +2 -2
- package/dist/runtime/components/elements/Progress.vue +1 -1
- package/dist/runtime/components/forms/Checkbox.vue.d.ts +1 -1
- package/dist/runtime/components/forms/Form.vue +104 -43
- package/dist/runtime/components/forms/Form.vue.d.ts +5 -3
- package/dist/runtime/components/forms/Input.vue +5 -2
- package/dist/runtime/components/forms/Input.vue.d.ts +3 -0
- package/dist/runtime/components/forms/InputMenu.vue +19 -8
- package/dist/runtime/components/forms/InputMenu.vue.d.ts +19 -0
- package/dist/runtime/components/forms/Radio.vue.d.ts +1 -1
- package/dist/runtime/components/forms/RadioGroup.vue +3 -4
- package/dist/runtime/components/forms/RadioGroup.vue.d.ts +1 -1
- package/dist/runtime/components/forms/SelectMenu.vue +22 -11
- package/dist/runtime/components/forms/SelectMenu.vue.d.ts +30 -2
- package/dist/runtime/components/forms/Textarea.vue +7 -4
- package/dist/runtime/components/forms/Textarea.vue.d.ts +3 -0
- package/dist/runtime/components/layout/Divider.vue +1 -1
- package/dist/runtime/components/layout/Divider.vue.d.ts +5 -2
- package/dist/runtime/components/navigation/CommandPalette.vue +1 -1
- package/dist/runtime/components/navigation/CommandPalette.vue.d.ts +1 -1
- package/dist/runtime/components/navigation/CommandPaletteGroup.vue.d.ts +1 -1
- package/dist/runtime/components/navigation/Pagination.vue +4 -4
- package/dist/runtime/components/navigation/Pagination.vue.d.ts +1 -1
- package/dist/runtime/components/navigation/Tabs.vue +1 -1
- package/dist/runtime/components/navigation/VerticalNavigation.vue.d.ts +6 -2
- package/dist/runtime/components/overlays/Modal.vue +1 -1
- package/dist/runtime/components/overlays/Notifications.vue +1 -1
- package/dist/runtime/components/overlays/Popover.vue +6 -2
- package/dist/runtime/composables/defineShortcuts.js +1 -1
- package/dist/runtime/composables/useButtonGroup.d.ts +1 -1
- package/dist/runtime/composables/useUI.js +1 -1
- package/dist/runtime/plugins/modals.js +1 -1
- package/dist/runtime/plugins/slideovers.js +1 -1
- package/dist/runtime/types/accordion.d.ts +1 -1
- package/dist/runtime/types/alert.d.ts +4 -4
- package/dist/runtime/types/avatar.d.ts +3 -3
- package/dist/runtime/types/badge.d.ts +3 -3
- package/dist/runtime/types/button.d.ts +3 -5
- package/dist/runtime/types/chip.d.ts +2 -2
- package/dist/runtime/types/command-palette.d.ts +2 -2
- package/dist/runtime/types/component.d.ts +3 -3
- package/dist/runtime/types/divider.d.ts +3 -3
- package/dist/runtime/types/dropdown.d.ts +1 -1
- package/dist/runtime/types/form-group.d.ts +2 -2
- package/dist/runtime/types/form.d.ts +7 -2
- package/dist/runtime/types/index.d.ts +1 -0
- package/dist/runtime/types/index.js +1 -0
- package/dist/runtime/types/input.d.ts +3 -3
- package/dist/runtime/types/kbd.d.ts +2 -2
- package/dist/runtime/types/meter.d.ts +2 -2
- package/dist/runtime/types/modal.d.ts +2 -2
- package/dist/runtime/types/notification.d.ts +1 -1
- package/dist/runtime/types/progress.d.ts +2 -2
- package/dist/runtime/types/range.d.ts +3 -3
- package/dist/runtime/types/select.d.ts +3 -3
- package/dist/runtime/types/table.d.ts +18 -0
- package/dist/runtime/types/textarea.d.ts +3 -3
- package/dist/runtime/types/toggle.d.ts +3 -3
- package/dist/runtime/types/utils.d.ts +2 -2
- package/dist/runtime/ui.config/data/table.d.ts +1 -0
- package/dist/runtime/ui.config/data/table.js +1 -0
- package/dist/runtime/ui.config/elements/avatar.js +15 -15
- package/dist/runtime/ui.config/elements/button.js +25 -25
- package/dist/runtime/ui.config/elements/buttonGroup.js +1 -1
- package/dist/runtime/ui.config/elements/chip.js +5 -5
- package/dist/runtime/ui.config/elements/meter.js +20 -20
- package/dist/runtime/ui.config/elements/meterGroup.js +1 -1
- package/dist/runtime/ui.config/elements/progress.js +18 -18
- package/dist/runtime/ui.config/forms/formGroup.js +5 -6
- package/dist/runtime/ui.config/forms/input.js +40 -40
- package/dist/runtime/ui.config/forms/inputMenu.d.ts +6 -0
- package/dist/runtime/ui.config/forms/inputMenu.js +7 -1
- package/dist/runtime/ui.config/forms/range.js +20 -20
- package/dist/runtime/ui.config/forms/selectMenu.d.ts +9 -0
- package/dist/runtime/ui.config/forms/selectMenu.js +10 -1
- package/dist/runtime/ui.config/forms/toggle.js +20 -20
- package/dist/runtime/ui.config/layout/divider.d.ts +1 -0
- package/dist/runtime/ui.config/layout/divider.js +12 -11
- package/dist/runtime/ui.config/navigation/horizontalNavigation.js +1 -1
- package/dist/runtime/ui.config/navigation/verticalNavigation.js +1 -1
- package/dist/runtime/ui.config/popper.js +0 -1
- package/dist/runtime/utils/colors.js +7 -7
- package/dist/runtime/utils/index.js +4 -4
- package/dist/runtime/utils/lodash.js +1 -1
- 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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
163
|
-
return
|
|
190
|
+
await schema.validateAsync(state, { abortEarly: false });
|
|
191
|
+
return {
|
|
192
|
+
errors: null,
|
|
193
|
+
result: state
|
|
194
|
+
};
|
|
164
195
|
} catch (error) {
|
|
165
|
-
if (
|
|
166
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
189
|
-
|
|
222
|
+
return {
|
|
223
|
+
result: result.data,
|
|
224
|
+
errors: null
|
|
225
|
+
};
|
|
190
226
|
}
|
|
191
|
-
function
|
|
192
|
-
|
|
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
|
|
244
|
+
async function validateYupSchema(state, schema) {
|
|
195
245
|
try {
|
|
196
|
-
|
|
197
|
-
return
|
|
246
|
+
const result = schema.validateSync(state, { abortEarly: false });
|
|
247
|
+
return {
|
|
248
|
+
errors: null,
|
|
249
|
+
result
|
|
250
|
+
};
|
|
198
251
|
} catch (error) {
|
|
199
|
-
if (
|
|
200
|
-
|
|
201
|
-
path:
|
|
202
|
-
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
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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:
|
|
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:
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
300
|
+
return option ? accessor(option, props.optionAttribute) : null;
|
|
301
301
|
} else {
|
|
302
|
-
return ["string", "number"].includes(typeof props.modelValue) ? props.modelValue : props.modelValue
|
|
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(
|
|
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(
|
|
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;
|
|
@@ -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
|
}
|
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
|
377
|
+
return accessor(selected.value, props.optionAttribute) ?? null;
|
|
378
378
|
} else {
|
|
379
|
-
return ["string", "number"].includes(typeof props.modelValue) ? props.modelValue : props.modelValue
|
|
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(
|
|
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(
|
|
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
|
|
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;
|