vueless 1.2.8 → 1.2.10-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.
Files changed (78) hide show
  1. package/constants.d.ts +4 -0
  2. package/constants.js +4 -0
  3. package/icons/storybook/rocket_launch.svg +1 -0
  4. package/index.d.ts +3 -1
  5. package/index.ts +3 -1
  6. package/package.json +9 -5
  7. package/plugin-vite.js +6 -1
  8. package/types.ts +14 -2
  9. package/ui.button/config.ts +4 -4
  10. package/ui.button/tests/UButton.test.ts +3 -3
  11. package/ui.button-toggle/config.ts +2 -2
  12. package/ui.container-accordion/UAccordion.vue +0 -1
  13. package/ui.container-accordion/config.ts +1 -1
  14. package/ui.container-accordion/storybook/stories.ts +13 -1
  15. package/ui.container-accordion-item/UAccordionItem.vue +17 -4
  16. package/ui.container-accordion-item/config.ts +1 -1
  17. package/ui.container-accordion-item/storybook/stories.ts +26 -1
  18. package/ui.container-accordion-item/tests/UAccordionItem.test.ts +186 -0
  19. package/ui.container-card/config.ts +1 -1
  20. package/ui.data-table/config.ts +4 -4
  21. package/ui.dropdown-badge/UDropdownBadge.vue +68 -3
  22. package/ui.dropdown-badge/config.ts +5 -1
  23. package/ui.dropdown-badge/storybook/stories.ts +280 -4
  24. package/ui.dropdown-badge/tests/UDropdownBadge.test.ts +194 -0
  25. package/ui.dropdown-badge/types.ts +30 -0
  26. package/ui.dropdown-button/UDropdownButton.vue +69 -6
  27. package/ui.dropdown-button/config.ts +5 -1
  28. package/ui.dropdown-button/storybook/stories.ts +288 -3
  29. package/ui.dropdown-button/tests/UDropdownButton.test.ts +190 -0
  30. package/ui.dropdown-button/types.ts +30 -0
  31. package/ui.dropdown-link/UDropdownLink.vue +69 -6
  32. package/ui.dropdown-link/config.ts +5 -1
  33. package/ui.dropdown-link/storybook/stories.ts +281 -4
  34. package/ui.dropdown-link/tests/UDropdownLink.test.ts +194 -0
  35. package/ui.dropdown-link/types.ts +30 -0
  36. package/ui.form-calendar/config.ts +4 -2
  37. package/ui.form-checkbox/config.ts +1 -1
  38. package/ui.form-checkbox/tests/UCheckbox.test.ts +2 -2
  39. package/ui.form-checkbox-group/tests/UCheckboxGroup.test.ts +2 -2
  40. package/ui.form-date-picker-range/config.ts +1 -1
  41. package/ui.form-input/UInput.vue +4 -2
  42. package/ui.form-input/config.ts +1 -1
  43. package/ui.form-input/tests/UInput.test.ts +2 -2
  44. package/ui.form-input-counter/UInputCounter.vue +25 -1
  45. package/ui.form-input-counter/config.ts +7 -2
  46. package/ui.form-input-counter/tests/UInputCounter.test.ts +85 -1
  47. package/ui.form-input-counter/types.ts +25 -0
  48. package/ui.form-input-file/tests/UInputFile.test.ts +2 -2
  49. package/ui.form-input-number/UInputNumber.vue +15 -3
  50. package/ui.form-input-number/utilFormat.ts +17 -7
  51. package/ui.form-input-password/UInputPassword.vue +23 -1
  52. package/ui.form-label/ULabel.vue +10 -4
  53. package/ui.form-label/tests/ULabel.test.ts +29 -12
  54. package/ui.form-listbox/UListbox.vue +21 -9
  55. package/ui.form-listbox/config.ts +1 -1
  56. package/ui.form-listbox/storybook/stories.ts +188 -1
  57. package/ui.form-listbox/tests/UListbox.test.ts +36 -0
  58. package/ui.form-listbox/types.ts +5 -0
  59. package/ui.form-radio/config.ts +1 -1
  60. package/ui.form-radio/tests/URadio.test.ts +2 -2
  61. package/ui.form-radio-group/tests/URadioGroup.test.ts +2 -2
  62. package/ui.form-select/USelect.vue +20 -2
  63. package/ui.form-select/config.ts +2 -1
  64. package/ui.form-select/storybook/stories.ts +31 -4
  65. package/ui.form-select/tests/USelect.test.ts +143 -0
  66. package/ui.form-select/types.ts +10 -0
  67. package/ui.form-textarea/config.ts +1 -1
  68. package/ui.form-textarea/tests/UTextarea.test.ts +2 -2
  69. package/ui.text-alert/config.ts +1 -1
  70. package/ui.text-badge/config.ts +1 -1
  71. package/utils/helper.ts +4 -0
  72. package/utils/node/dynamicProps.d.ts +5 -2
  73. package/utils/node/dynamicProps.js +126 -53
  74. package/utils/node/helper.d.ts +10 -7
  75. package/utils/node/helper.js +59 -2
  76. package/utils/node/tailwindSafelist.js +9 -2
  77. package/utils/theme.ts +75 -31
  78. package/utils/ui.ts +32 -3
@@ -8,14 +8,22 @@ import {
8
8
 
9
9
  import UDropdownLink from "../../ui.dropdown-link/UDropdownLink.vue";
10
10
  import URow from "../../ui.container-row/URow.vue";
11
+ import UCol from "../../ui.container-col/UCol.vue";
11
12
  import UIcon from "../../ui.image-icon/UIcon.vue";
12
13
  import UBadge from "../../ui.text-badge/UBadge.vue";
13
14
  import ULink from "../../ui.button-link/ULink.vue";
14
15
  import UAvatar from "../../ui.image-avatar/UAvatar.vue";
16
+ import UText from "../../ui.text-block/UText.vue";
17
+ import ULoader from "../../ui.loader/ULoader.vue";
15
18
 
16
19
  import type { Meta, StoryFn } from "@storybook/vue3-vite";
17
20
  import type { Props } from "../types";
18
21
 
22
+ import johnDoe from "../../ui.form-select/storybook/assets/images/john-doe.png";
23
+ import emilyDavis from "../../ui.form-select/storybook/assets/images/emily-davis.png";
24
+ import alexJohnson from "../../ui.form-select/storybook/assets/images/alex-johnson.png";
25
+ import patMorgan from "../../ui.form-select/storybook/assets/images/pat-morgan.png";
26
+
19
27
  interface DefaultUDropdownLinkArgs extends Props {
20
28
  slotTemplate?: string;
21
29
  }
@@ -51,7 +59,7 @@ export default {
51
59
  } as Meta;
52
60
 
53
61
  const DefaultTemplate: StoryFn<DefaultUDropdownLinkArgs> = (args: DefaultUDropdownLinkArgs) => ({
54
- components: { UDropdownLink, UIcon, ULink, UBadge, UAvatar },
62
+ components: { UDropdownLink, UIcon, ULink, UBadge, UAvatar, ULoader, URow, UText },
55
63
  setup: () => ({ args, slots: getSlotNames(UDropdownLink.__name) }),
56
64
  template: `
57
65
  <UDropdownLink v-bind="args">
@@ -87,6 +95,35 @@ const EnumTemplate: StoryFn<EnumUDropdownLinkArgs> = (
87
95
  `,
88
96
  });
89
97
 
98
+ const GroupValuesTemplate: StoryFn<DefaultUDropdownLinkArgs> = (
99
+ args: DefaultUDropdownLinkArgs,
100
+ ) => ({
101
+ components: { UDropdownLink },
102
+ setup() {
103
+ return {
104
+ args,
105
+ };
106
+ },
107
+ template: `
108
+ <UDropdownLink
109
+ v-bind="args"
110
+ v-model="args.modelValue"
111
+ label="Single"
112
+ :config="{ listbox: 'min-w-[200px]' }"
113
+ class="max-w-96 mr-20"
114
+ />
115
+
116
+ <UDropdownLink
117
+ v-bind="args"
118
+ v-model="args.modelValueMultiple"
119
+ label="Multiple"
120
+ multiple
121
+ :config="{ listbox: 'min-w-[200px]' }"
122
+ class="mt-5 max-w-96"
123
+ />
124
+ `,
125
+ });
126
+
90
127
  export const Default = DefaultTemplate.bind({});
91
128
  Default.args = {};
92
129
  Default.parameters = {
@@ -97,6 +134,9 @@ Default.parameters = {
97
134
  },
98
135
  };
99
136
 
137
+ export const Disabled = DefaultTemplate.bind({});
138
+ Disabled.args = { disabled: true };
139
+
100
140
  export const Searchable = DefaultTemplate.bind({});
101
141
  Searchable.args = { searchable: true };
102
142
  Searchable.parameters = {
@@ -107,6 +147,19 @@ Searchable.parameters = {
107
147
  },
108
148
  };
109
149
 
150
+ export const SearchModelValue = DefaultTemplate.bind({});
151
+ SearchModelValue.args = { searchable: true, search: "Settings" };
152
+ SearchModelValue.parameters = {
153
+ docs: {
154
+ story: {
155
+ height: "250px",
156
+ },
157
+ },
158
+ };
159
+
160
+ export const NoCloseOnSelect = SelectableTemplate.bind({});
161
+ NoCloseOnSelect.args = { modelValue: "logout", closeOnSelect: false };
162
+
110
163
  export const OptionSelection = SelectableTemplate.bind({});
111
164
  OptionSelection.args = { modelValue: "profile" };
112
165
 
@@ -132,6 +185,60 @@ ListboxYPosition.parameters = {
132
185
  storyClasses: "h-[350px] flex items-center px-6 pt-8 pb-12",
133
186
  };
134
187
 
188
+ export const GroupValue = GroupValuesTemplate.bind({});
189
+ GroupValue.args = {
190
+ modelValue: "",
191
+ groupValueKey: "libs",
192
+ groupLabelKey: "language",
193
+ labelKey: "name",
194
+ valueKey: "name",
195
+ options: [
196
+ {
197
+ language: "Javascript",
198
+ libs: [{ name: "Vue.js" }, { name: "Adonis" }],
199
+ },
200
+ {
201
+ language: "Ruby",
202
+ libs: [
203
+ { name: "Frameworks", isSubGroup: true, level: 2 },
204
+ { name: "Rails", level: 3 },
205
+ { name: "Sinatra", level: 3 },
206
+ ],
207
+ },
208
+ {
209
+ language: "Other",
210
+ libs: [{ name: "Laravel" }, { name: "Phoenix" }],
211
+ },
212
+ ],
213
+ };
214
+ GroupValue.parameters = {
215
+ docs: {
216
+ story: {
217
+ height: "400px",
218
+ },
219
+ },
220
+ };
221
+
222
+ export const OptionsLimit = DefaultTemplate.bind({});
223
+ OptionsLimit.args = { optionsLimit: 2 };
224
+ OptionsLimit.parameters = {
225
+ docs: {
226
+ description: {
227
+ story: "`optionsLimit` prop controls the number of options displayed in the dropdown.",
228
+ },
229
+ },
230
+ };
231
+
232
+ export const VisibleOptions = DefaultTemplate.bind({});
233
+ VisibleOptions.args = { visibleOptions: 2 };
234
+ VisibleOptions.parameters = {
235
+ docs: {
236
+ description: {
237
+ story: "`visibleOptions` prop controls the number of options you can see without a scroll.",
238
+ },
239
+ },
240
+ };
241
+
135
242
  export const Color = EnumTemplate.bind({});
136
243
  Color.args = { enum: "color", label: "{enumValue}" };
137
244
 
@@ -149,9 +256,6 @@ export const UnderlineVariants: StoryFn<EnumUDropdownLinkArgs> = (args: EnumUDro
149
256
  `,
150
257
  });
151
258
 
152
- export const Disabled = DefaultTemplate.bind({});
153
- Disabled.args = { disabled: true };
154
-
155
259
  export const WithoutToggleIcon = Default.bind({});
156
260
  WithoutToggleIcon.args = { toggleIcon: false };
157
261
 
@@ -202,3 +306,176 @@ ToggleSlot.args = {
202
306
  </template>
203
307
  `,
204
308
  };
309
+
310
+ export const EmptySlot = DefaultTemplate.bind({});
311
+ EmptySlot.args = {
312
+ options: [],
313
+ slotTemplate: `
314
+ <template #empty>
315
+ <URow align="center">
316
+ <ULoader loading size="sm" />
317
+ <UText label="Loading, this may take a while..." />
318
+ </URow>
319
+ </template>
320
+ `,
321
+ };
322
+
323
+ export const OptionSlots: StoryFn<DefaultUDropdownLinkArgs> = (args) => ({
324
+ components: { UDropdownLink, URow, UCol, UAvatar, UIcon, UBadge, UText },
325
+ setup: () => ({ args, johnDoe, emilyDavis, alexJohnson, patMorgan }),
326
+ template: `
327
+ <URow>
328
+ <UDropdownLink
329
+ v-model="args.beforeOptionModel"
330
+ label="Before option slot"
331
+ :options="[
332
+ {
333
+ label: 'John Doe',
334
+ id: '1',
335
+ role: 'Developer',
336
+ avatar: johnDoe,
337
+ status: 'online',
338
+ statusColor: 'success',
339
+ },
340
+ {
341
+ label: 'Jane Smith',
342
+ id: '2',
343
+ role: 'Designer',
344
+ avatar: emilyDavis,
345
+ status: 'away',
346
+ statusColor: 'warning',
347
+ },
348
+ {
349
+ label: 'Mike Johnson',
350
+ id: '3',
351
+ role: 'Product Manager',
352
+ avatar: alexJohnson,
353
+ status: 'offline',
354
+ statusColor: 'grayscale',
355
+ },
356
+ {
357
+ label: 'Sarah Wilson',
358
+ id: '4',
359
+ role: 'QA Engineer',
360
+ avatar: patMorgan,
361
+ status: 'online',
362
+ statusColor: 'success',
363
+ },
364
+ ]"
365
+ >
366
+ <template #before-option="{ option }">
367
+ <UAvatar :src="option.avatar" size="sm" />
368
+ </template>
369
+ </UDropdownLink>
370
+
371
+ <UDropdownLink
372
+ v-model="args.optionModel"
373
+ label="Option slot"
374
+ :options="[
375
+ {
376
+ label: 'John Doe',
377
+ id: '1',
378
+ role: 'Developer',
379
+ avatar: johnDoe,
380
+ status: 'online',
381
+ statusColor: 'success',
382
+ },
383
+ {
384
+ label: 'Jane Smith',
385
+ id: '2',
386
+ role: 'Designer',
387
+ avatar: emilyDavis,
388
+ status: 'away',
389
+ statusColor: 'warning',
390
+ },
391
+ {
392
+ label: 'Mike Johnson',
393
+ id: '3',
394
+ role: 'Product Manager',
395
+ avatar: alexJohnson,
396
+ status: 'offline',
397
+ statusColor: 'grayscale',
398
+ },
399
+ {
400
+ label: 'Sarah Wilson',
401
+ id: '4',
402
+ role: 'QA Engineer',
403
+ avatar: patMorgan,
404
+ status: 'online',
405
+ statusColor: 'success',
406
+ },
407
+ ]"
408
+ >
409
+ <template #option="{ option }">
410
+ <URow align="center" gap="xs">
411
+ <UCol gap="none">
412
+ <UText size="sm">{{ option.label }}</UText>
413
+ <UText variant="lifted" size="xs">{{ option.role }}</UText>
414
+ </UCol>
415
+ <UBadge
416
+ :label="option.status"
417
+ :color="option.statusColor"
418
+ size="sm"
419
+ variant="subtle"
420
+ />
421
+ </URow>
422
+ </template>
423
+ </UDropdownLink>
424
+
425
+ <UDropdownLink
426
+ v-model="args.afterOptionModel"
427
+ label="After option slot"
428
+ :options="[
429
+ {
430
+ label: 'John Doe',
431
+ id: '1',
432
+ role: 'Developer',
433
+ avatar: johnDoe,
434
+ status: 'online',
435
+ statusColor: 'success',
436
+ },
437
+ {
438
+ label: 'Jane Smith',
439
+ id: '2',
440
+ role: 'Designer',
441
+ avatar: emilyDavis,
442
+ status: 'away',
443
+ statusColor: 'warning',
444
+ },
445
+ {
446
+ label: 'Mike Johnson',
447
+ id: '3',
448
+ role: 'Product Manager',
449
+ avatar: alexJohnson,
450
+ status: 'offline',
451
+ statusColor: 'grayscale',
452
+ },
453
+ {
454
+ label: 'Sarah Wilson',
455
+ id: '4',
456
+ role: 'QA Engineer',
457
+ avatar: patMorgan,
458
+ status: 'online',
459
+ statusColor: 'success',
460
+ },
461
+ ]"
462
+ >
463
+ <template #after-option="{ option }">
464
+ <UBadge
465
+ :label="option.status"
466
+ :color="option.statusColor"
467
+ size="sm"
468
+ variant="subtle"
469
+ />
470
+ </template>
471
+ </UDropdownLink>
472
+ </URow>
473
+ `,
474
+ });
475
+ OptionSlots.parameters = {
476
+ docs: {
477
+ story: {
478
+ height: "300px",
479
+ },
480
+ },
481
+ };
@@ -268,6 +268,101 @@ describe("UDropdownLink.vue", () => {
268
268
 
269
269
  expect(component.findComponent(ULink).attributes("data-test")).toBe(dataTest);
270
270
  });
271
+
272
+ // OptionsLimit prop
273
+ it("passes optionsLimit prop to UListbox component", async () => {
274
+ const optionsLimit = 2;
275
+
276
+ const component = mount(UDropdownLink, {
277
+ props: {
278
+ optionsLimit,
279
+ options: defaultOptions,
280
+ },
281
+ });
282
+
283
+ await component.findComponent(ULink).trigger("click");
284
+
285
+ expect(component.findComponent(UListbox).props("optionsLimit")).toBe(optionsLimit);
286
+ });
287
+
288
+ // VisibleOptions prop
289
+ it("passes visibleOptions prop to UListbox component", async () => {
290
+ const visibleOptions = 5;
291
+
292
+ const component = mount(UDropdownLink, {
293
+ props: {
294
+ visibleOptions,
295
+ options: defaultOptions,
296
+ },
297
+ });
298
+
299
+ await component.findComponent(ULink).trigger("click");
300
+
301
+ expect(component.findComponent(UListbox).props("visibleOptions")).toBe(visibleOptions);
302
+ });
303
+
304
+ // GroupLabelKey prop
305
+ it("passes groupLabelKey prop to UListbox component", async () => {
306
+ const groupLabelKey = "category";
307
+ const groupedOptions = [
308
+ { groupLabel: "Group 1", category: "group1" },
309
+ { label: "Option 1", id: "option1", category: "group1" },
310
+ { groupLabel: "Group 2", category: "group2" },
311
+ { label: "Option 2", id: "option2", category: "group2" },
312
+ ];
313
+
314
+ const component = mount(UDropdownLink, {
315
+ props: {
316
+ groupLabelKey,
317
+ options: groupedOptions,
318
+ },
319
+ });
320
+
321
+ await component.findComponent(ULink).trigger("click");
322
+
323
+ expect(component.findComponent(UListbox).props("groupLabelKey")).toBe(groupLabelKey);
324
+ });
325
+
326
+ it("Search v-model – passes search to UListbox and filters", async () => {
327
+ const component = mount(UDropdownLink, {
328
+ props: {
329
+ searchable: true,
330
+ options: defaultOptions,
331
+ search: "Option 3",
332
+ },
333
+ });
334
+
335
+ await component.findComponent(ULink).trigger("click");
336
+
337
+ const listbox = component.getComponent(UListbox);
338
+ const options = listbox.findAll("[vl-child-key='option']");
339
+
340
+ expect(options).toHaveLength(1);
341
+ expect(options[0].text()).toBe("Option 3");
342
+ });
343
+
344
+ // CloseOnSelect prop
345
+ it("keeps dropdown open when closeOnSelect is false", async () => {
346
+ const component = mount(UDropdownLink, {
347
+ props: {
348
+ options: defaultOptions,
349
+ closeOnSelect: false,
350
+ },
351
+ });
352
+
353
+ // Open the dropdown
354
+ await component.findComponent(ULink).trigger("click");
355
+ expect(component.findComponent(UListbox).exists()).toBe(true);
356
+
357
+ // Find the listbox component
358
+ const listbox = component.findComponent(UListbox);
359
+
360
+ // Simulate selecting an option by emitting update:modelValue from the listbox
361
+ listbox.vm.$emit("update:modelValue", 2);
362
+
363
+ // Dropdown should remain open
364
+ expect(component.findComponent(UListbox).exists()).toBe(true);
365
+ });
271
366
  });
272
367
 
273
368
  // Slots tests
@@ -329,6 +424,105 @@ describe("UDropdownLink.vue", () => {
329
424
  expect(component.find(`.${slotClass}`).exists()).toBe(true);
330
425
  expect(component.find(`.${slotClass}`).text()).toBe(slotText);
331
426
  });
427
+
428
+ // Before-option slot
429
+ it("renders content from before-option slot", async () => {
430
+ const label = "Dropdown Link";
431
+ const slotText = "Before";
432
+ const slotClass = "before-option-content";
433
+
434
+ const component = mount(UDropdownLink, {
435
+ props: {
436
+ label,
437
+ options: defaultOptions,
438
+ },
439
+ slots: {
440
+ "before-option": `<span class='${slotClass}'>${slotText}</span>`,
441
+ },
442
+ });
443
+
444
+ await component.findComponent(ULink).trigger("click");
445
+
446
+ const listbox = component.findComponent(UListbox);
447
+ const beforeOptionSlot = listbox.find(`.${slotClass}`);
448
+
449
+ expect(beforeOptionSlot.exists()).toBe(true);
450
+ expect(beforeOptionSlot.text()).toBe(slotText);
451
+ });
452
+
453
+ // Option slot
454
+ it("renders custom content from option slot", async () => {
455
+ const label = "Dropdown Link";
456
+ const slotClass = "custom-option-content";
457
+
458
+ const component = mount(UDropdownLink, {
459
+ props: {
460
+ label,
461
+ options: defaultOptions,
462
+ },
463
+ slots: {
464
+ option: `<span class='${slotClass}'>Custom {{ params.option.label }}</span>`,
465
+ },
466
+ });
467
+
468
+ await component.findComponent(ULink).trigger("click");
469
+
470
+ const listbox = component.findComponent(UListbox);
471
+ const customOptionSlot = listbox.find(`.${slotClass}`);
472
+
473
+ expect(customOptionSlot.exists()).toBe(true);
474
+ expect(customOptionSlot.text()).toBe("Custom Option 1");
475
+ });
476
+
477
+ // After-option slot
478
+ it("renders content from after-option slot", async () => {
479
+ const label = "Dropdown Link";
480
+ const slotText = "After";
481
+ const slotClass = "after-option-content";
482
+
483
+ const component = mount(UDropdownLink, {
484
+ props: {
485
+ label,
486
+ options: defaultOptions,
487
+ },
488
+ slots: {
489
+ "after-option": `<span class='${slotClass}'>${slotText}</span>`,
490
+ },
491
+ });
492
+
493
+ await component.findComponent(ULink).trigger("click");
494
+
495
+ const listbox = component.findComponent(UListbox);
496
+ const afterOptionSlot = listbox.find(`.${slotClass}`);
497
+
498
+ expect(afterOptionSlot.exists()).toBe(true);
499
+ expect(afterOptionSlot.text()).toBe(slotText);
500
+ });
501
+
502
+ // Empty slot
503
+ it("renders custom content from empty slot", async () => {
504
+ const label = "Dropdown Link";
505
+ const slotContent = "No options available";
506
+ const slotClass = "custom-empty";
507
+
508
+ const component = mount(UDropdownLink, {
509
+ props: {
510
+ label,
511
+ options: [],
512
+ },
513
+ slots: {
514
+ empty: `<span class='${slotClass}'>${slotContent}</span>`,
515
+ },
516
+ });
517
+
518
+ await component.findComponent(ULink).trigger("click");
519
+
520
+ const listbox = component.findComponent(UListbox);
521
+ const emptySlot = listbox.find(`.${slotClass}`);
522
+
523
+ expect(emptySlot.exists()).toBe(true);
524
+ expect(emptySlot.text()).toBe(slotContent);
525
+ });
332
526
  });
333
527
 
334
528
  // Events tests
@@ -36,6 +36,26 @@ export interface Props {
36
36
  */
37
37
  valueKey?: string;
38
38
 
39
+ /**
40
+ * Set a name of the property containing the group label.
41
+ */
42
+ groupLabelKey?: string;
43
+
44
+ /**
45
+ * Set a name of the property containing the group values.
46
+ */
47
+ groupValueKey?: string;
48
+
49
+ /**
50
+ * Number of options displayed in the dropdown.
51
+ */
52
+ optionsLimit?: number;
53
+
54
+ /**
55
+ * Number of options you can see without a scroll.
56
+ */
57
+ visibleOptions?: number;
58
+
39
59
  /**
40
60
  * Link color.
41
61
  */
@@ -65,6 +85,16 @@ export interface Props {
65
85
  */
66
86
  searchable?: boolean;
67
87
 
88
+ /**
89
+ * Search input model value for the dropdown list.
90
+ */
91
+ search?: string;
92
+
93
+ /**
94
+ * Close dropdown on option select.
95
+ */
96
+ closeOnSelect?: boolean;
97
+
68
98
  /**
69
99
  * Allows multiple selection.
70
100
  */
@@ -1,5 +1,7 @@
1
1
  export default /*tw*/ {
2
- wrapper: "p-3 w-[19rem] border border-default rounded-medium bg-default shadow-sm overflow-hidden focus:outline-hidden",
2
+ wrapper: `
3
+ p-3 w-[19rem] bg-default shadow-sm overflow-hidden focus:outline-hidden
4
+ border border-solid border-default rounded-medium`,
3
5
  navigation: "mb-2 pb-2 border-b border-muted flex items-center justify-between",
4
6
  viewSwitchButton: {
5
7
  base: "{UButton}",
@@ -54,7 +56,7 @@ export default /*tw*/ {
54
56
  timepicker: "mt-2 pl-1 pt-3 text-medium flex items-stretch justify-between gap-2 border-t border-muted",
55
57
  timepickerLabel: "w-full self-center",
56
58
  timepickerInputWrapper: `
57
- flex items-center rounded-medium border border-default
59
+ flex items-center rounded-medium border border-solid border-default
58
60
  hover:focus-within:border-primary focus-within:border-primary
59
61
  focus-within:outline focus-within:outline-small focus-within:outline-primary
60
62
  `,
@@ -3,7 +3,7 @@ export default /*tw*/ {
3
3
  checkbox: {
4
4
  base: `
5
5
  bg-default cursor-pointer transition
6
- border border-default rounded-small outline-transparent
6
+ border border-solid border-default rounded-small outline-transparent
7
7
  appearance-none p-0 print:color-adjust-exact inline-block align-middle bg-origin-border select-none shrink-0
8
8
  hover:border-lifted
9
9
  active:border-{color} active:bg-{color}/15
@@ -261,7 +261,7 @@ describe("UCheckbox.vue", () => {
261
261
  });
262
262
 
263
263
  const labelComponent = component.getComponent(ULabel);
264
- const labelElement = labelComponent.find("label");
264
+ const labelElement = labelComponent.find("[vl-child-key='label']");
265
265
 
266
266
  expect(labelElement.text()).toBe(customLabelContent);
267
267
  });
@@ -279,7 +279,7 @@ describe("UCheckbox.vue", () => {
279
279
  });
280
280
 
281
281
  const labelComponent = component.getComponent(ULabel);
282
- const labelElement = labelComponent.find("label");
282
+ const labelElement = labelComponent.find("[vl-child-key='label']");
283
283
 
284
284
  expect(labelElement.text()).toBe(`Modified ${defaultLabel}`);
285
285
  });
@@ -201,7 +201,7 @@ describe("UCheckboxGroup.vue", () => {
201
201
  });
202
202
 
203
203
  const labelComponent = component.getComponent(ULabel);
204
- const labelElement = labelComponent.find("label");
204
+ const labelElement = labelComponent.find("[vl-child-key='label']");
205
205
 
206
206
  expect(labelElement.text()).toBe(customLabelContent);
207
207
  });
@@ -219,7 +219,7 @@ describe("UCheckboxGroup.vue", () => {
219
219
  });
220
220
 
221
221
  const labelComponent = component.getComponent(ULabel);
222
- const labelElement = labelComponent.find("label");
222
+ const labelElement = labelComponent.find("[vl-child-key='label']");
223
223
 
224
224
  expect(labelElement.text()).toBe(`Modified ${defaultLabel}`);
225
225
  });
@@ -31,7 +31,7 @@ export default /*tw*/ {
31
31
  menu: {
32
32
  base: `
33
33
  absolute z-40 mb-3 w-80 overflow-hidden rounded-medium
34
- border border-default bg-default p-2 shadow-sm focus:outline-hidden
34
+ border border-solid border-default bg-default p-2 shadow-sm focus:outline-hidden
35
35
  `,
36
36
  variants: {
37
37
  openDirectionX: {
@@ -25,7 +25,7 @@ const props = withDefaults(defineProps<Props>(), {
25
25
 
26
26
  const emit = defineEmits([
27
27
  /**
28
- * Triggers when the input value is changes.
28
+ * Triggers when the input value is changed.
29
29
  * @property {string} modelValue
30
30
  * @property {number} modelValue
31
31
  */
@@ -43,6 +43,7 @@ const emit = defineEmits([
43
43
 
44
44
  /**
45
45
  * Triggers when the input gains focus.
46
+ * @property {FocusEvent} event
46
47
  */
47
48
  "focus",
48
49
 
@@ -53,11 +54,12 @@ const emit = defineEmits([
53
54
 
54
55
  /**
55
56
  * Triggers when the input loses focus.
57
+ * @property {FocusEvent} event
56
58
  */
57
59
  "blur",
58
60
 
59
61
  /**
60
- * Triggers when the input value is changes.
62
+ * Triggers when the input value is changed.
61
63
  * @property {string} modelValue
62
64
  * @property {number} modelValue
63
65
  */