vueless 1.4.7 → 1.4.8

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 (83) hide show
  1. package/icons/internal/apps.svg +1 -1
  2. package/icons/internal/calendar_month-fill.svg +1 -1
  3. package/icons/internal/error.svg +1 -1
  4. package/icons/internal/info.svg +1 -1
  5. package/icons/internal/progress_activity.svg +1 -1
  6. package/icons/internal/search.svg +1 -1
  7. package/icons/internal/visibility-fill.svg +1 -1
  8. package/icons/internal/warning.svg +1 -1
  9. package/icons/storybook/account_circle.svg +1 -1
  10. package/icons/storybook/cloud_sync.svg +1 -0
  11. package/icons/storybook/contact_mail.svg +1 -1
  12. package/icons/storybook/delivery_truck_speed.svg +1 -1
  13. package/icons/storybook/directions_bike.svg +1 -1
  14. package/icons/storybook/error.svg +1 -1
  15. package/icons/storybook/folder.svg +1 -0
  16. package/icons/storybook/handyman.svg +1 -1
  17. package/icons/storybook/help.svg +1 -1
  18. package/icons/storybook/inbox.svg +1 -1
  19. package/icons/storybook/inbox_customize.svg +1 -1
  20. package/icons/storybook/info.svg +1 -1
  21. package/icons/storybook/key.svg +1 -1
  22. package/icons/storybook/local_shipping.svg +1 -0
  23. package/icons/storybook/lock.svg +1 -1
  24. package/icons/storybook/lock_open.svg +1 -1
  25. package/icons/storybook/notifications.svg +1 -0
  26. package/icons/storybook/palette.svg +1 -1
  27. package/icons/storybook/person.svg +1 -1
  28. package/icons/storybook/person_search.svg +1 -1
  29. package/icons/storybook/progress_activity.svg +1 -1
  30. package/icons/storybook/rocket_launch.svg +1 -1
  31. package/icons/storybook/sentiment_satisfied.svg +1 -1
  32. package/icons/storybook/timer.svg +1 -1
  33. package/icons/storybook/travel_explore.svg +1 -1
  34. package/package.json +33 -32
  35. package/plugin-vite.js +18 -7
  36. package/ui.container-accordion/storybook/stories.ts +1 -1
  37. package/ui.container-accordion-item/storybook/stories.ts +1 -1
  38. package/ui.container-accordion-item/tests/UAccordionItem.test.ts +4 -2
  39. package/ui.container-card/storybook/stories.ts +40 -39
  40. package/ui.container-col/config.ts +4 -2
  41. package/ui.container-col/tests/UCol.test.ts +24 -16
  42. package/ui.container-drawer/tests/UDrawer.test.ts +11 -29
  43. package/ui.container-modal/storybook/stories.ts +2 -2
  44. package/ui.container-modal/tests/UModal.test.ts +10 -22
  45. package/ui.container-modal-confirm/storybook/stories.ts +17 -2
  46. package/ui.container-page/storybook/stories.ts +6 -1
  47. package/ui.container-row/config.ts +4 -2
  48. package/ui.container-row/tests/URow.test.ts +24 -16
  49. package/ui.data-table/UTableRow.vue +2 -2
  50. package/ui.data-table/storybook/stories.ts +1 -1
  51. package/ui.form-calendar/tests/UCalendar.test.ts +14 -13
  52. package/ui.form-calendar/tests/UCalendarDayView.test.ts +15 -16
  53. package/ui.form-checkbox/UCheckbox.vue +0 -5
  54. package/ui.form-checkbox/storybook/stories.ts +50 -18
  55. package/ui.form-checkbox/tests/UCheckbox.test.ts +0 -17
  56. package/ui.form-checkbox-group/storybook/stories.ts +61 -0
  57. package/ui.form-date-picker/storybook/stories.ts +87 -37
  58. package/ui.form-date-picker-range/storybook/stories.ts +91 -38
  59. package/ui.form-input/storybook/stories.ts +71 -37
  60. package/ui.form-input-file/storybook/stories.ts +38 -5
  61. package/ui.form-input-number/storybook/stories.ts +60 -28
  62. package/ui.form-input-password/storybook/stories.ts +88 -50
  63. package/ui.form-input-rating/UInputRating.vue +8 -3
  64. package/ui.form-input-search/storybook/stories.ts +34 -4
  65. package/ui.form-label/ULabel.vue +0 -6
  66. package/ui.form-label/storybook/stories.ts +40 -24
  67. package/ui.form-label/tests/ULabel.test.ts +0 -12
  68. package/ui.form-listbox/tests/UListbox.test.ts +39 -3
  69. package/ui.form-radio/URadio.vue +0 -5
  70. package/ui.form-radio/storybook/stories.ts +60 -25
  71. package/ui.form-radio/tests/URadio.test.ts +0 -17
  72. package/ui.form-radio-group/storybook/stories.ts +61 -0
  73. package/ui.form-select/config.ts +4 -1
  74. package/ui.form-select/storybook/stories.ts +109 -46
  75. package/ui.form-switch/storybook/stories.ts +35 -11
  76. package/ui.form-textarea/storybook/stories.ts +55 -20
  77. package/ui.loader/tests/ULoader.test.ts +3 -3
  78. package/ui.navigation-progress/tests/UProgress.test.ts +2 -3
  79. package/ui.text-block/tests/UText.test.ts +3 -3
  80. package/ui.text-files/storybook/stories.ts +30 -13
  81. package/ui.text-header/tests/UHeader.test.ts +3 -3
  82. package/ui.text-notify/tests/UNotify.test.ts +14 -18
  83. package/utils/node/helper.js +8 -9
@@ -15,6 +15,8 @@ import UIcon from "../../ui.image-icon/UIcon.vue";
15
15
 
16
16
  import type { Meta, StoryFn } from "@storybook/vue3-vite";
17
17
  import type { Props } from "../types";
18
+ import { ref } from "vue";
19
+ import UCol from "../../ui.container-col/UCol.vue";
18
20
 
19
21
  interface URadioArgs extends Props {
20
22
  slotTemplate?: string;
@@ -107,30 +109,63 @@ Sizes.args = { name: "Sizes", enum: "size", label: "{enumValue}", modelValue: 1
107
109
  export const Colors = EnumTemplate.bind({});
108
110
  Colors.args = { name: "Colors", enum: "color", label: "{enumValue}", modelValue: 1 };
109
111
 
110
- export const LabelSlot = DefaultTemplate.bind({});
111
- LabelSlot.args = {
112
- name: "LabelSlot",
113
- value: "courier",
114
- color: "primary",
115
- slotTemplate: `
116
- <template #label>
117
- <URow gap="2xs" align="center">
118
- <UText>I agree to the <ULink label="Privacy Policy" /></UText>
119
- <UIcon name="contract" size="xs" />
120
- </URow>
121
- </template>
122
- `,
123
- };
112
+ export const Slots: StoryFn<URadioArgs> = (args) => ({
113
+ components: { URadio, UCol, UText, URow, ULink, UIcon },
114
+ setup: () => ({
115
+ args,
116
+ labelModel: ref(""),
117
+ descriptionModel: ref(""),
118
+ errorModel: ref(""),
119
+ }),
120
+ template: `
121
+ <UCol gap="3xl">
122
+ <URadio
123
+ v-bind="args"
124
+ v-model="labelModel"
125
+ name="LabelSlot"
126
+ value="courier"
127
+ >
128
+ <template #label>
129
+ <URow align="center" gap="2xs">
130
+ <UText>Courier delivery</UText>
131
+ <UIcon name="local_shipping" size="xs" color="neutral" />
132
+ </URow>
133
+ </template>
134
+ </URadio>
124
135
 
125
- export const BottomSlot = DefaultTemplate.bind({});
126
- BottomSlot.args = {
127
- name: "terms",
128
- label: "I agree to the Terms and Conditions",
129
- value: "terms",
130
- color: "primary",
131
- slotTemplate: `
132
- <template #bottom>
133
- <UBadge label="Required to proceed" color="warning" variant="outlined" size="sm" class="mt-2" />
134
- </template>
136
+ <URadio
137
+ v-bind="args"
138
+ v-model="descriptionModel"
139
+ name="DescriptionSlot"
140
+ value="pro"
141
+ >
142
+ <template #description>
143
+ <UText size="sm" variant="lifted">
144
+ Includes all core features,
145
+ <ULink label="compare plans" underlined size="sm" />
146
+ for upgrades.
147
+ </UText>
148
+ </template>
149
+ </URadio>
150
+
151
+ <URadio
152
+ v-bind="args"
153
+ v-model="errorModel"
154
+ name="ErrorSlot"
155
+ label="Select"
156
+ value="1"
157
+ :error="true"
158
+ >
159
+ <template #error>
160
+ <UText size="sm" color="error">
161
+ <ul>
162
+ <li>You must select one of the available options</li>
163
+ <li>This field is required to proceed</li>
164
+ <li>Choose an option above to clear this error</li>
165
+ </ul>
166
+ </UText>
167
+ </template>
168
+ </URadio>
169
+ </UCol>
135
170
  `,
136
- };
171
+ });
@@ -241,22 +241,5 @@ describe("URadio.vue", () => {
241
241
 
242
242
  expect(errorElement.text()).toBe(customError);
243
243
  });
244
-
245
- it("Bottom – renders custom content from bottom slot", () => {
246
- const customBottomContent = "Custom Bottom Content";
247
-
248
- const component = mount(URadio, {
249
- props: {
250
- label: "Test Label",
251
- },
252
- slots: {
253
- bottom: customBottomContent,
254
- },
255
- });
256
-
257
- const labelComponent = component.getComponent(ULabel);
258
-
259
- expect(labelComponent.text()).toContain(customBottomContent);
260
- });
261
244
  });
262
245
  });
@@ -13,9 +13,12 @@ import UCol from "../../ui.container-col/UCol.vue";
13
13
  import URow from "../../ui.container-row/URow.vue";
14
14
  import UBadge from "../../ui.text-badge/UBadge.vue";
15
15
  import UText from "../../ui.text-block/UText.vue";
16
+ import ULink from "../../ui.button-link/ULink.vue";
17
+ import UIcon from "../../ui.image-icon/UIcon.vue";
16
18
 
17
19
  import type { Meta, StoryFn } from "@storybook/vue3-vite";
18
20
  import type { Props } from "../types";
21
+ import { ref } from "vue";
19
22
 
20
23
  interface URadioGroupArgs extends Props {
21
24
  slotTemplate?: string;
@@ -170,3 +173,61 @@ CustomKeys.parameters = {
170
173
  },
171
174
  },
172
175
  };
176
+
177
+ export const Slots: StoryFn<URadioGroupArgs> = (args) => ({
178
+ components: { URadioGroup, UCol, UText, URow, ULink, UIcon },
179
+ setup: () => ({
180
+ args,
181
+ modelValueLabel: ref(null),
182
+ modelValueDescription: ref(null),
183
+ modelValueError: ref(null),
184
+ }),
185
+ template: `
186
+ <UCol gap="3xl">
187
+ <URadioGroup
188
+ v-bind="args"
189
+ v-model="modelValueLabel"
190
+ name="LabelSlot"
191
+ >
192
+ <template #label>
193
+ <URow align="center" gap="2xs">
194
+ <UText>Choose a delivery option</UText>
195
+ <UIcon name="local_shipping" size="xs" color="neutral" />
196
+ </URow>
197
+ </template>
198
+ </URadioGroup>
199
+
200
+ <URadioGroup
201
+ v-bind="args"
202
+ v-model="modelValueDescription"
203
+ name="SlotsDescription"
204
+ label="Delivery"
205
+ >
206
+ <template #description>
207
+ <UText size="sm" variant="lifted">
208
+ Shipping times are estimates, see the
209
+ <ULink label="full policy" underlined size="sm" />.
210
+ </UText>
211
+ </template>
212
+ </URadioGroup>
213
+
214
+ <URadioGroup
215
+ v-bind="args"
216
+ v-model="modelValueError"
217
+ name="SlotsError"
218
+ label="Delivery"
219
+ :error="true"
220
+ >
221
+ <template #error>
222
+ <UText size="sm" color="error">
223
+ <ul>
224
+ <li>Please choose one option from the group</li>
225
+ <li>At least one selection is required</li>
226
+ <li>Review the labels and pick a valid answer</li>
227
+ </ul>
228
+ </UText>
229
+ </template>
230
+ </URadioGroup>
231
+ </UCol>
232
+ `,
233
+ });
@@ -117,7 +117,10 @@ export default /*tw*/ {
117
117
  ],
118
118
  },
119
119
  toggleWrapper: "{>toggle} mr-3",
120
- toggleIcon: "{UIcon} {>selectIcon} -mr-1 transition duration-300 group-[*]/active:rotate-180",
120
+ toggleIcon: {
121
+ base: "{UIcon} {>selectIcon} -mr-1 transition duration-300",
122
+ compoundVariants: [{ opened: true, class: "rotate-180" }],
123
+ },
121
124
  leftIcon: "{UIcon} {>selectIcon}",
122
125
  rightIcon: "{UIcon} {>selectIcon}",
123
126
  leftSlot: "{>toggle} pl-2.5",
@@ -148,6 +148,13 @@ NotClearable.args = { clearable: false };
148
148
 
149
149
  export const Searchable = DefaultTemplate.bind({});
150
150
  Searchable.args = { searchable: true };
151
+ Searchable.parameters = {
152
+ docs: {
153
+ story: {
154
+ height: "350px",
155
+ },
156
+ },
157
+ };
151
158
 
152
159
  export const SearchModelValue = DefaultTemplate.bind({});
153
160
  SearchModelValue.args = { search: "New York", searchable: true };
@@ -163,10 +170,10 @@ export const NoCloseOnSelect = DefaultTemplate.bind({});
163
170
  NoCloseOnSelect.args = { modelValue: 3, closeOnSelect: false };
164
171
 
165
172
  export const Readonly = DefaultTemplate.bind({});
166
- Readonly.args = { readonly: true, modelValue: "1", clearable: false };
173
+ Readonly.args = { readonly: true, modelValue: 1, clearable: false };
167
174
 
168
175
  export const Disabled = DefaultTemplate.bind({});
169
- Disabled.args = { disabled: true, modelValue: "2", clearable: false };
176
+ Disabled.args = { disabled: true, modelValue: 2, clearable: false };
170
177
 
171
178
  export const LabelAlign = EnumTemplate.bind({});
172
179
  LabelAlign.args = {
@@ -184,6 +191,13 @@ LargeItemList.args = {
184
191
  return { value: index + 1, label: `value ${index + 1}`, badge: "badge" };
185
192
  }),
186
193
  };
194
+ LargeItemList.parameters = {
195
+ docs: {
196
+ story: {
197
+ height: "400px",
198
+ },
199
+ },
200
+ };
187
201
 
188
202
  export const Multiple = DefaultTemplate.bind({});
189
203
  Multiple.args = { multiple: true, modelValue: [] };
@@ -334,54 +348,103 @@ export const IconProps: StoryFn<USelectArgs> = (args) => ({
334
348
  });
335
349
 
336
350
  export const Slots: StoryFn<USelectArgs> = (args) => ({
337
- components: { USelect, URow, UIcon, UText },
338
- setup: () => ({ args, leftSlotModel: ref("paypal"), rightSlotModel: ref("bank") }),
351
+ components: { USelect, URow, UCol, UIcon, UText, ULink },
352
+ setup: () => ({
353
+ args,
354
+ leftSlotModel: ref("paypal"),
355
+ rightSlotModel: ref("bank"),
356
+ descriptionSlotModel: ref(null),
357
+ errorSlotModel: ref(null),
358
+ }),
339
359
  template: `
340
- <URow>
341
- <USelect
342
- v-model="leftSlotModel"
343
- label="Select Payment Method"
344
- :options="[
345
- { label: 'Visa', value: 'visa', icon: 'credit_card', details: '•••• 4242' },
346
- { label: 'PayPal', value: 'paypal', icon: 'payments', details: 'user@example.com' },
347
- { label: 'Bank Transfer', value: 'bank', icon: 'account_balance', details: 'Acct **** 1234' },
348
- { label: 'Apple Pay', value: 'apple', icon: 'phone_iphone', details: 'iPhone 15' },
349
- ]"
350
- >
351
- <template #left="{ options }">
352
- <UIcon
353
- v-if="leftSlotModel"
354
- :name="options?.icon"
355
- color="primary"
356
- size="sm"
357
- />
358
- </template>
359
- </USelect>
360
+ <UCol gap="3xl">
361
+ <URow block>
362
+ <USelect
363
+ v-model="leftSlotModel"
364
+ label="Select Payment Method"
365
+ :options="[
366
+ { label: 'Visa', value: 'visa', icon: 'credit_card', details: '•••• 4242' },
367
+ { label: 'PayPal', value: 'paypal', icon: 'payments', details: 'user@example.com' },
368
+ { label: 'Bank Transfer', value: 'bank', icon: 'account_balance', details: 'Acct **** 1234' },
369
+ { label: 'Apple Pay', value: 'apple', icon: 'phone_iphone', details: 'iPhone 15' },
370
+ ]"
371
+ >
372
+ <template #left="{ options }">
373
+ <UIcon
374
+ v-if="leftSlotModel"
375
+ :name="options?.icon"
376
+ color="primary"
377
+ size="sm"
378
+ />
379
+ </template>
380
+ </USelect>
381
+
382
+ <USelect
383
+ v-model="rightSlotModel"
384
+ label="Select Payment Method"
385
+ :options="[
386
+ { label: 'Visa', value: 'visa', icon: 'credit_card', details: '•••• 4242' },
387
+ { label: 'PayPal', value: 'paypal', icon: 'payments', details: 'user@example.com' },
388
+ { label: 'Bank Transfer', value: 'bank', icon: 'account_balance', details: 'Acct **** 1234' },
389
+ { label: 'Apple Pay', value: 'apple', icon: 'phone_iphone', details: 'iPhone 15' },
390
+ ]"
391
+ >
392
+ <template #right="{ options }">
393
+ <UText
394
+ v-if="rightSlotModel"
395
+ size="sm"
396
+ variant="lifted"
397
+ class="text-nowrap"
398
+ >
399
+ {{ options?.details }}
400
+ </UText>
401
+ </template>
402
+ </USelect>
403
+ </URow>
360
404
 
361
- <USelect
362
- v-model="rightSlotModel"
363
- label="Select Payment Method"
364
- :options="[
365
- { label: 'Visa', value: 'visa', icon: 'credit_card', details: '•••• 4242' },
366
- { label: 'PayPal', value: 'paypal', icon: 'payments', details: 'user@example.com' },
367
- { label: 'Bank Transfer', value: 'bank', icon: 'account_balance', details: 'Acct **** 1234' },
368
- { label: 'Apple Pay', value: 'apple', icon: 'phone_iphone', details: 'iPhone 15' },
369
- ]"
370
- >
371
- <template #right="{ options }">
372
- <UText
373
- v-if="rightSlotModel"
374
- size="sm"
375
- variant="lifted"
376
- class="text-nowrap"
377
- >
378
- {{ options?.details }}
379
- </UText>
380
- </template>
381
- </USelect>
382
- </URow>
405
+ <URow block>
406
+ <USelect
407
+ v-bind="args"
408
+ v-model="descriptionSlotModel"
409
+ label="City"
410
+ :options="args.options"
411
+ >
412
+ <template #description>
413
+ <UText size="sm" variant="lifted">
414
+ Only cities we ship to, see
415
+ <ULink label="shipping zones" underlined size="sm" />.
416
+ </UText>
417
+ </template>
418
+ </USelect>
419
+
420
+ <USelect
421
+ v-bind="args"
422
+ v-model="errorSlotModel"
423
+ label="City"
424
+ :options="args.options"
425
+ :error="true"
426
+ >
427
+ <template #error>
428
+ <UText size="sm" color="error">
429
+ <ul>
430
+ <li>Please select an option from the list</li>
431
+ <li>The current value is not available anymore</li>
432
+ <li>Pick a valid choice to continue</li>
433
+ </ul>
434
+ </UText>
435
+ </template>
436
+ </USelect>
437
+ </URow>
438
+ </UCol>
383
439
  `,
384
440
  });
441
+ Slots.parameters = {
442
+ docs: {
443
+ story: {
444
+ height: "400px",
445
+ },
446
+ },
447
+ };
385
448
 
386
449
  export const ToggleSlots: StoryFn<USelectArgs> = (args) => ({
387
450
  components: { USelect, URow, UIcon },
@@ -15,6 +15,7 @@ import ULink from "../../ui.button-link/ULink.vue";
15
15
 
16
16
  import type { Meta, StoryFn } from "@storybook/vue3-vite";
17
17
  import type { Props } from "../types";
18
+ import { ref } from "vue";
18
19
 
19
20
  interface USwitchArgs extends Props {
20
21
  slotTemplate?: string;
@@ -89,15 +90,38 @@ ToggleIcon.args = { toggleIcon: true };
89
90
  export const Disabled = DefaultTemplate.bind({});
90
91
  Disabled.args = { disabled: true };
91
92
 
92
- export const LabelSlot = DefaultTemplate.bind({});
93
- LabelSlot.args = {
94
- label: "Enable Notifications",
95
- slotTemplate: `
96
- <template #label="{ label }">
97
- <URow gap="2xs" align="center">
98
- <UText>I agree to the <ULink label="Privacy Policy" /></UText>
99
- <UIcon name="contract" size="xs" />
100
- </URow>
101
- </template>
93
+ export const Slots: StoryFn<USwitchArgs> = (args) => ({
94
+ components: { USwitch, UCol, UText, URow, ULink, UIcon },
95
+ setup: () => ({ args, labelSlotValue: ref(false), descriptionSlotValue: ref(false) }),
96
+ template: `
97
+ <UCol gap="3xl">
98
+ <USwitch
99
+ v-bind="args"
100
+ v-model="labelSlotValue"
101
+ label="Enable Notifications"
102
+ >
103
+ <template #label="{ label }">
104
+ <URow gap="2xs" align="center">
105
+ <UText :label="label" />
106
+ <UIcon name="notifications" size="xs" />
107
+ </URow>
108
+ </template>
109
+ </USwitch>
110
+
111
+ <USwitch
112
+ v-model="descriptionSlotValue"
113
+ label="Auto-save drafts"
114
+ >
115
+ <template #description>
116
+ <URow align="center" gap="2xs" class="text-neutral">
117
+ <UIcon name="cloud_sync" size="xs" class="mt-0.5" color="primary" />
118
+ <UText size="sm" variant="lifted">
119
+ Drafts sync across devices,
120
+ <ULink label="learn more" underlined size="sm" />.
121
+ </UText>
122
+ </URow>
123
+ </template>
124
+ </USwitch>
125
+ </UCol>
102
126
  `,
103
- };
127
+ });
@@ -12,9 +12,11 @@ import UCol from "../../ui.container-col/UCol.vue";
12
12
  import URow from "../../ui.container-row/URow.vue";
13
13
  import tooltip from "../../v.tooltip/vTooltip";
14
14
  import UText from "../../ui.text-block/UText.vue";
15
+ import ULink from "../../ui.button-link/ULink.vue";
15
16
 
16
17
  import type { Meta, StoryFn } from "@storybook/vue3-vite";
17
18
  import type { Props } from "../types";
19
+ import { ref } from "vue";
18
20
 
19
21
  interface UTextareaArgs extends Props {
20
22
  slotTemplate?: string;
@@ -138,27 +140,60 @@ NoAutocomplete.parameters = {
138
140
  };
139
141
 
140
142
  export const Slots: StoryFn<UTextareaArgs> = (args) => ({
141
- components: { UTextarea, URow, UIcon, UText },
143
+ components: { UTextarea, URow, UCol, UIcon, UText, ULink },
142
144
  directives: { tooltip },
143
- setup: () => ({ args }),
145
+ setup: () => ({
146
+ args,
147
+ descriptionSlotValue: ref(""),
148
+ errorSlotValue: ref(""),
149
+ }),
144
150
  template: `
145
- <URow>
146
- <UTextarea v-bind="args" v-model="args.modelValue" :max-length="300">
147
- <template #left>
148
- <UText :label="args.modelValue?.length + '/300'" variant="lifted" />
149
- </template>
150
- </UTextarea>
151
-
152
- <UTextarea v-bind="args">
153
- <template #right>
154
- <UIcon
155
- name="send"
156
- color="success"
157
- v-tooltip="'Send message'"
158
- interactive
159
- />
160
- </template>
161
- </UTextarea>
162
- </URow>
151
+ <UCol gap="3xl">
152
+ <URow block>
153
+ <UTextarea v-bind="args" v-model="args.modelValue" :max-length="300">
154
+ <template #left>
155
+ <UText :label="args.modelValue?.length + '/300'" variant="lifted" />
156
+ </template>
157
+ </UTextarea>
158
+
159
+ <UTextarea v-bind="args">
160
+ <template #right>
161
+ <UIcon
162
+ name="send"
163
+ color="success"
164
+ v-tooltip="'Send message'"
165
+ interactive
166
+ />
167
+ </template>
168
+ </UTextarea>
169
+ </URow>
170
+
171
+ <URow block>
172
+ <UTextarea v-model="descriptionSlotValue" label="Feedback">
173
+ <template #description>
174
+ <UText size="sm" variant="lifted">
175
+ Markdown is not supported, see
176
+ <ULink label="content guidelines" underlined size="sm" />.
177
+ </UText>
178
+ </template>
179
+ </UTextarea>
180
+
181
+ <UTextarea
182
+ v-model="errorSlotValue"
183
+ label="Message"
184
+ :error="true"
185
+ >
186
+ <template #error>
187
+ <UText size="sm" color="error">
188
+ <ul>
189
+ <li>Message is too short (minimum 10 characters)</li>
190
+ <li>Remove disallowed characters from your text</li>
191
+ <li>Try again after fixing the issues above</li>
192
+ </ul>
193
+ </UText>
194
+ </template>
195
+ </UTextarea>
196
+ </URow>
197
+ </UCol>
163
198
  `,
164
199
  });
@@ -57,10 +57,10 @@ describe("ULoader.vue", () => {
57
57
  // Check if the ellipses have the correct color class
58
58
  const ellipses = component.findAll("[vl-key='ellipse']");
59
59
 
60
+ const expectedClass = color === "inherit" ? "bg-current" : `bg-${color}`;
61
+
60
62
  ellipses.forEach((ellipse) => {
61
- color === "inherit"
62
- ? expect(ellipse.classes()).toContain("bg-current")
63
- : expect(ellipse.classes()).toContain(`bg-${color}`);
63
+ expect(ellipse.classes()).toContain(expectedClass);
64
64
  });
65
65
  });
66
66
  });
@@ -133,9 +133,8 @@ describe("UProgress.vue", () => {
133
133
  const progressElement = component.find("progress");
134
134
  const stepperElement = component.findComponent(UStepperProgress);
135
135
 
136
- isProgress
137
- ? expect(progressElement.exists()).toBe(isProgress)
138
- : expect(stepperElement.exists()).toBe(!isProgress);
136
+ expect(progressElement.exists()).toBe(isProgress);
137
+ expect(stepperElement.exists()).toBe(!isProgress);
139
138
  });
140
139
  });
141
140
 
@@ -66,9 +66,9 @@ describe("UText.vue", () => {
66
66
  },
67
67
  });
68
68
 
69
- color === "text"
70
- ? expect(component.attributes("class")).toContain("text-default")
71
- : expect(component.attributes("class")).toContain(color);
69
+ const expectedInClass = color === "text" ? "text-default" : color;
70
+
71
+ expect(component.attributes("class")).toContain(expectedInClass);
72
72
  });
73
73
  });
74
74
 
@@ -8,7 +8,10 @@ import {
8
8
 
9
9
  import UFiles from "../../ui.text-files/UFiles.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";
13
+ import UText from "../../ui.text-block/UText.vue";
14
+ import ULink from "../../ui.button-link/ULink.vue";
12
15
 
13
16
  import type { Meta, StoryFn } from "@storybook/vue3-vite";
14
17
  import type { Props } from "../types";
@@ -80,25 +83,39 @@ export const Sizes = EnumTemplate.bind({});
80
83
  Sizes.args = { enum: "size" };
81
84
 
82
85
  export const Slots: StoryFn<UFilesArgs> = (args) => ({
83
- components: { UFiles, URow, UIcon },
86
+ components: { UFiles, URow, UCol, UIcon, UText, ULink },
84
87
  setup() {
85
88
  return { args };
86
89
  },
87
90
  template: `
88
- <URow>
89
- <UFiles v-bind="args">
90
- <template #before-file="{ index }">
91
- <UIcon v-if="index === 0" name="info" color="warning" size="xs" />
92
- <UIcon v-if="index === 1" name="check_circle" color="success" size="xs" />
93
- </template>
94
- </UFiles>
91
+ <UCol gap="3xl">
92
+ <URow block>
93
+ <UFiles v-bind="args">
94
+ <template #before-file="{ index }">
95
+ <UIcon v-if="index === 0" name="info" color="warning" size="xs" />
96
+ <UIcon v-if="index === 1" name="check_circle" color="success" size="xs" />
97
+ </template>
98
+ </UFiles>
95
99
 
96
- <UFiles v-bind="args">
97
- <template #after-file="{ index }">
98
- <UIcon v-if="index === 0" name="info" color="warning" size="xs" />
99
- <UIcon v-if="index === 1" name="check_circle" color="success" size="xs" />
100
+ <UFiles v-bind="args">
101
+ <template #after-file="{ index }">
102
+ <UIcon v-if="index === 0" name="info" color="warning" size="xs" />
103
+ <UIcon v-if="index === 1" name="check_circle" color="success" size="xs" />
104
+ </template>
105
+ </UFiles>
106
+ </URow>
107
+
108
+ <UFiles v-bind="args" label="Documents">
109
+ <template #description>
110
+ <URow align="center" gap="2xs" class="text-neutral">
111
+ <UIcon name="folder" size="xs" class="mt-0.5" color="primary" />
112
+ <UText size="sm" variant="lifted">
113
+ Files are read-only here,
114
+ <ULink label="manage in storage" underlined size="sm" />.
115
+ </UText>
116
+ </URow>
100
117
  </template>
101
118
  </UFiles>
102
- </URow>
119
+ </UCol>
103
120
  `,
104
121
  });