vueless 0.0.569 → 0.0.571

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 (81) hide show
  1. package/package.json +1 -1
  2. package/types.ts +24 -3
  3. package/ui.button/types.ts +2 -2
  4. package/ui.container-accordion/UAccordion.vue +2 -2
  5. package/ui.container-accordion/types.ts +1 -0
  6. package/ui.container-modal/UModal.vue +15 -8
  7. package/ui.container-page/UPage.vue +10 -6
  8. package/ui.form-checkbox/types.ts +7 -0
  9. package/ui.form-checkbox-group/UCheckboxGroup.vue +1 -1
  10. package/ui.form-checkbox-multi-state/UCheckboxMultiState.vue +4 -1
  11. package/ui.form-color-picker/UColorPicker.vue +67 -147
  12. package/ui.form-color-picker/storybook/Docs.mdx +2 -2
  13. package/ui.form-color-picker/storybook/{stories.js → stories.ts} +13 -5
  14. package/ui.form-color-picker/types.ts +64 -0
  15. package/ui.form-color-picker/useAttrs.ts +15 -0
  16. package/ui.form-input/UInput.vue +162 -321
  17. package/ui.form-input/{config.js → config.ts} +3 -0
  18. package/ui.form-input/storybook/Docs.mdx +2 -2
  19. package/ui.form-input/storybook/{stories.js → stories.ts} +14 -6
  20. package/ui.form-input/types.ts +103 -0
  21. package/ui.form-input/useAttrs.ts +31 -0
  22. package/ui.form-input-file/UInputFile.vue +188 -245
  23. package/ui.form-input-file/storybook/Docs.mdx +2 -2
  24. package/ui.form-input-file/storybook/{stories.js → stories.ts} +13 -5
  25. package/ui.form-input-file/types.ts +72 -0
  26. package/ui.form-input-file/useAttrs.ts +21 -0
  27. package/ui.form-input-file/{utilFileForm.js → utilFileForm.ts} +1 -1
  28. package/ui.form-input-money/UInputMoney.vue +76 -223
  29. package/ui.form-input-money/storybook/Docs.mdx +2 -2
  30. package/ui.form-input-money/storybook/{stories.js → stories.ts} +14 -6
  31. package/ui.form-input-money/types.ts +118 -0
  32. package/ui.form-input-money/useAttrs.ts +15 -0
  33. package/ui.form-input-money/{useFormatCurrency.js → useFormatCurrency.ts} +28 -17
  34. package/ui.form-input-money/utilFormat.ts +83 -0
  35. package/ui.form-input-number/UInputNumber.vue +69 -156
  36. package/ui.form-input-number/storybook/Docs.mdx +2 -2
  37. package/ui.form-input-number/storybook/{stories.js → stories.ts} +17 -9
  38. package/ui.form-input-number/types.ts +65 -0
  39. package/ui.form-input-number/useAttrs.ts +15 -0
  40. package/ui.form-input-rating/UInputRating.vue +70 -158
  41. package/ui.form-input-rating/storybook/Docs.mdx +2 -2
  42. package/ui.form-input-rating/storybook/{stories.js → stories.ts} +14 -6
  43. package/ui.form-input-rating/types.ts +67 -0
  44. package/ui.form-input-rating/useAttrs.ts +14 -0
  45. package/ui.form-input-search/UInputSearch.vue +97 -224
  46. package/ui.form-input-search/storybook/Docs.mdx +2 -2
  47. package/ui.form-input-search/storybook/{stories.js → stories.ts} +13 -5
  48. package/ui.form-input-search/types.ts +93 -0
  49. package/ui.form-input-search/useAttrs.ts +15 -0
  50. package/ui.form-radio/URadio.vue +1 -1
  51. package/ui.form-radio-group/URadioGroup.vue +1 -1
  52. package/ui.navigation-pagination/UPagination.vue +15 -15
  53. package/ui.navigation-pagination/types.ts +3 -0
  54. package/ui.navigation-progress/UProgress.vue +16 -2
  55. package/ui.navigation-progress/types.ts +2 -0
  56. package/ui.text-files/UFiles.vue +20 -16
  57. package/ui.text-files/types.ts +1 -1
  58. package/ui.text-notify/UNotify.vue +38 -48
  59. package/ui.text-notify/types.ts +24 -0
  60. package/web-types.json +227 -138
  61. package/ui.form-color-picker/useAttrs.js +0 -9
  62. package/ui.form-input/useAttrs.js +0 -15
  63. package/ui.form-input-file/useAttrs.js +0 -15
  64. package/ui.form-input-money/useAttrs.js +0 -9
  65. package/ui.form-input-money/utilFormat.js +0 -75
  66. package/ui.form-input-number/useAttrs.js +0 -9
  67. package/ui.form-input-rating/useAttrs.js +0 -8
  68. package/ui.form-input-search/useAttrs.js +0 -9
  69. /package/ui.form-color-picker/{config.js → config.ts} +0 -0
  70. /package/ui.form-color-picker/{constants.js → constants.ts} +0 -0
  71. /package/ui.form-input/{constants.js → constants.ts} +0 -0
  72. /package/ui.form-input-file/{config.js → config.ts} +0 -0
  73. /package/ui.form-input-file/{constants.js → constants.ts} +0 -0
  74. /package/ui.form-input-money/{config.js → config.ts} +0 -0
  75. /package/ui.form-input-money/{constants.js → constants.ts} +0 -0
  76. /package/ui.form-input-number/{config.js → config.ts} +0 -0
  77. /package/ui.form-input-number/{constants.js → constants.ts} +0 -0
  78. /package/ui.form-input-rating/{config.js → config.ts} +0 -0
  79. /package/ui.form-input-rating/{constants.js → constants.ts} +0 -0
  80. /package/ui.form-input-search/{config.js → config.ts} +0 -0
  81. /package/ui.form-input-search/{constants.js → constants.ts} +0 -0
@@ -1,132 +1,35 @@
1
- <template>
2
- <ULabel
3
- ref="labelComponentRef"
4
- :for="elementId"
5
- :label="label"
6
- :description="description"
7
- :disabled="disabled"
8
- :error="error"
9
- :size="size"
10
- :align="labelAlign"
11
- centred
12
- v-bind="inputLabelAttrs"
13
- >
14
- <label :for="elementId" v-bind="wrapperAttrs">
15
- <span v-if="hasSlotContent($slots['left'])" ref="leftSlotWrapperRef">
16
- <!-- @slot Use it to add something before the text. -->
17
- <slot name="left" />
18
- </span>
19
-
20
- <span
21
- v-if="hasSlotContent($slots['left-icon']) || leftIcon"
22
- ref="leftSlotWrapperRef"
23
- v-bind="leftIconWrapperAttrs"
24
- >
25
- <!--
26
- @slot Use it to add icon before the text.
27
- @binding {string} icon-name
28
- @binding {string} icon-size
29
- -->
30
- <slot name="left-icon" :icon-name="leftIcon" :icon-size="iconSize">
31
- <UIcon
32
- v-if="leftIcon"
33
- :name="leftIcon"
34
- :size="iconSize"
35
- internal
36
- v-bind="leftIconAttrs"
37
- />
38
- </slot>
39
- </span>
40
-
41
- <input
42
- :id="elementId"
43
- ref="inputRef"
44
- v-model="inputValue"
45
- :placeholder="placeholder"
46
- :type="inputType"
47
- :readonly="readonly"
48
- :disabled="disabled"
49
- :maxlength="maxLength"
50
- :inputmode="inputmode"
51
- v-bind="inputAttrs"
52
- :data-test="dataTest"
53
- @focus="onFocus"
54
- @blur="onBlur"
55
- @input="onInput"
56
- @change="onChange"
57
- @mousedown="onMousedown"
58
- @click="onClick"
59
- @paste="onPaste"
60
- @copy="onCopy"
61
- />
62
-
63
- <label v-if="isTypePassword" v-bind="rightIconWrapperAttrs" :for="elementId">
64
- <UIcon
65
- v-if="isTypePassword"
66
- :name="
67
- isShownPassword
68
- ? config.defaults.passwordVisibleIcon
69
- : config.defaults.passwordHiddenIcon
70
- "
71
- color="gray"
72
- interactive
73
- internal
74
- v-bind="passwordIconAttrs"
75
- :data-test="`${dataTest}-password-icon`"
76
- @click="onClickShowPassword"
77
- />
78
- </label>
79
-
80
- <span v-if="hasSlotContent($slots['right-icon']) || rightIcon" v-bind="rightIconWrapperAttrs">
81
- <!--
82
- @slot Use it to add icon after the text.
83
- @binding {string} icon-name
84
- @binding {string} icon-size
85
- -->
86
- <slot name="right-icon" :icon-name="rightIcon" :icon-size="iconSize">
87
- <UIcon
88
- v-if="rightIcon"
89
- :name="rightIcon"
90
- :size="iconSize"
91
- internal
92
- v-bind="rightIconAttrs"
93
- />
94
- </slot>
95
- </span>
96
-
97
- <!-- @slot Use it to add something after the text. -->
98
- <slot name="right" />
99
- </label>
100
- </ULabel>
101
- </template>
102
-
103
- <script>
104
- import { getDefault } from "../utils/ui.ts";
105
-
106
- const VALIDATION_RULES_REG_EX = {
107
- integer: /\d*/g,
108
- number: /\d*\.?\d*/g,
109
- string: /[a-zA-Z]+/g,
110
- stringAndNumber: /[a-zA-Z0-9]+/g,
111
- symbol: /\D/g,
112
- };
113
- </script>
114
-
115
- <script setup>
1
+ <script setup lang="ts">
116
2
  import { ref, computed, onMounted, useSlots, useId } from "vue";
117
3
 
4
+ import { getDefault } from "../utils/ui.ts";
118
5
  import { hasSlotContent } from "../utils/helper.ts";
119
6
  import { useMutationObserver } from "../composables/useMutationObserver.ts";
120
7
 
121
8
  import UIcon from "../ui.image-icon/UIcon.vue";
122
9
  import ULabel from "../ui.form-label/ULabel.vue";
123
10
 
124
- import defaultConfig from "./config.js";
125
- import { UInput } from "./constants.js";
126
- import useAttrs from "./useAttrs.js";
11
+ import defaultConfig from "./config.ts";
12
+ import { UInput } from "./constants.ts";
13
+ import useAttrs from "./useAttrs.ts";
14
+
15
+ import type { UInputProps, IconSize } from "./types.ts";
127
16
 
128
17
  defineOptions({ inheritAttrs: false });
129
18
 
19
+ const props = withDefaults(defineProps<UInputProps>(), {
20
+ labelAlign: getDefault<UInputProps>(defaultConfig, UInput).labelAlign,
21
+ size: getDefault<UInputProps>(defaultConfig, UInput).size,
22
+ validationRule: getDefault<UInputProps>(defaultConfig, UInput).validationRule,
23
+ type: getDefault<UInputProps>(defaultConfig, UInput).type,
24
+ inputmode: getDefault<UInputProps>(defaultConfig, UInput).inputmode,
25
+ readonly: getDefault<UInputProps>(defaultConfig, UInput).readonly,
26
+ disabled: getDefault<UInputProps>(defaultConfig, UInput).disabled,
27
+ noAutocomplete: getDefault<UInputProps>(defaultConfig, UInput).noAutocomplete,
28
+ modelValue: "",
29
+ dataTest: "",
30
+ config: () => ({}),
31
+ });
32
+
130
33
  const emit = defineEmits([
131
34
  /**
132
35
  * Triggers when the input value is changes.
@@ -160,16 +63,6 @@ const emit = defineEmits([
160
63
  */
161
64
  "blur",
162
65
 
163
- /**
164
- * Triggers when content pasted to the input.
165
- */
166
- "paste",
167
-
168
- /**
169
- * Triggers when content copied from the input.
170
- */
171
- "copy",
172
-
173
66
  /**
174
67
  * Triggers when the input value is changes.
175
68
  * @property {string} modelValue
@@ -178,173 +71,20 @@ const emit = defineEmits([
178
71
  "input",
179
72
  ]);
180
73
 
181
- const props = defineProps({
182
- /**
183
- * Input value.
184
- */
185
- modelValue: {
186
- type: [String, Number],
187
- default: "",
188
- },
189
-
190
- /**
191
- * Input label.
192
- */
193
- label: {
194
- type: String,
195
- default: "",
196
- },
197
-
198
- /**
199
- * Label placement.
200
- * @values top, topInside, topWithDesc, left, right
201
- */
202
- labelAlign: {
203
- type: String,
204
- default: getDefault(defaultConfig, UInput).labelAlign,
205
- },
206
-
207
- /**
208
- * Input placeholder.
209
- */
210
- placeholder: {
211
- type: String,
212
- default: "",
213
- },
214
-
215
- /**
216
- * Input description.
217
- */
218
- description: {
219
- type: String,
220
- default: "",
221
- },
222
-
223
- /**
224
- * Error message.
225
- */
226
- error: {
227
- type: String,
228
- default: "",
229
- },
230
-
231
- /**
232
- * Input size.
233
- * @values sm, md, lg
234
- */
235
- size: {
236
- type: String,
237
- default: getDefault(defaultConfig, UInput).size,
238
- },
239
-
240
- /**
241
- * Left icon name.
242
- */
243
- leftIcon: {
244
- type: String,
245
- default: "",
246
- },
247
-
248
- /**
249
- * Right icon name.
250
- */
251
- rightIcon: {
252
- type: String,
253
- default: "",
254
- },
255
-
256
- /**
257
- * Maximum character length.
258
- */
259
- maxLength: {
260
- type: [String, Number],
261
- default: "",
262
- },
263
-
264
- /**
265
- * Prevents some characters from input.
266
- * You can use predefined values or own RegExp.
267
- * @values symbol, string, stringAndNumber, number, integer
268
- */
269
- validationRule: {
270
- type: [String, RegExp],
271
- default: getDefault(defaultConfig, UInput).validationRule,
272
- validator: (value) => Object.keys(VALIDATION_RULES_REG_EX).includes(value) || value === "",
273
- },
274
-
275
- /**
276
- * Input type.
277
- * @values text, number, tel, email, url, search, password
278
- */
279
- type: {
280
- type: String,
281
- default: getDefault(defaultConfig, UInput).type,
282
- },
283
-
284
- /**
285
- * Set specific keyboard for mobile devices.
286
- * @values text, decimal, numeric, tel, email, url, search, none
287
- */
288
- inputmode: {
289
- type: String,
290
- default: getDefault(defaultConfig, UInput).inputmode,
291
- },
292
-
293
- /**
294
- * Make input read-only.
295
- */
296
- readonly: {
297
- type: Boolean,
298
- default: getDefault(defaultConfig, UInput).readonly,
299
- },
300
-
301
- /**
302
- * Disable the input.
303
- */
304
- disabled: {
305
- type: Boolean,
306
- default: getDefault(defaultConfig, UInput).disabled,
307
- },
308
-
309
- /**
310
- * Disable browsers autocomplete.
311
- */
312
- noAutocomplete: {
313
- type: Boolean,
314
- default: getDefault(defaultConfig, UInput).noAutocomplete,
315
- },
316
-
317
- /**
318
- * Unique element id.
319
- */
320
- id: {
321
- type: String,
322
- default: "",
323
- },
324
-
325
- /**
326
- * Component config object.
327
- */
328
- config: {
329
- type: Object,
330
- default: () => ({}),
331
- },
332
-
333
- /**
334
- * Data-test attribute for automated testing.
335
- */
336
- dataTest: {
337
- type: String,
338
- default: "",
339
- },
340
- });
74
+ const VALIDATION_RULES_REG_EX = {
75
+ integer: /\d*/g,
76
+ number: /\d*\.?\d*/g,
77
+ string: /[a-zA-Z]+/g,
78
+ stringAndNumber: /[a-zA-Z0-9]+/g,
79
+ symbol: /\D/g,
80
+ };
341
81
 
342
82
  const slots = useSlots();
343
83
 
344
84
  const isShownPassword = ref(false);
345
- const inputRef = ref(null);
346
- const labelComponentRef = ref(null);
347
- const leftSlotWrapperRef = ref(null);
85
+ const inputRef = ref<HTMLInputElement | null>(null);
86
+ const leftSlotWrapperRef = ref<HTMLElement | null>(null);
87
+ const labelComponentRef = ref<{ labelElement: HTMLElement } | null>(null);
348
88
 
349
89
  const isTypePassword = computed(() => props.type === "password");
350
90
 
@@ -353,10 +93,8 @@ const inputValue = computed({
353
93
  set: (value) => emit("update:modelValue", value),
354
94
  });
355
95
 
356
- const inputPasswordClasses = computed(() => {
357
- return inputValue.value && !isShownPassword.value && isTypePassword.value
358
- ? "tracking-widest [font-family:text-security-disc,serif] [-webkit-text-security:disc]"
359
- : "";
96
+ const applyPasswordClasses = computed(() => {
97
+ return Boolean(inputValue.value && !isShownPassword.value && isTypePassword.value);
360
98
  });
361
99
 
362
100
  const elementId = props.id || useId();
@@ -371,7 +109,7 @@ const {
371
109
  leftIconAttrs,
372
110
  rightIconAttrs,
373
111
  rightIconWrapperAttrs,
374
- } = useAttrs(props, { isTypePassword, inputPasswordClasses });
112
+ } = useAttrs(props, { applyPasswordClasses });
375
113
 
376
114
  const iconSize = computed(() => {
377
115
  const sizes = {
@@ -380,23 +118,35 @@ const iconSize = computed(() => {
380
118
  lg: "md",
381
119
  };
382
120
 
383
- return sizes[props.size];
121
+ return sizes[props.size] as IconSize;
384
122
  });
385
123
 
386
124
  const inputType = computed(() => {
387
125
  return isShownPassword.value || props.noAutocomplete ? "text" : props.type;
388
126
  });
389
127
 
128
+ const passwordIcon = computed(() => {
129
+ return isShownPassword.value
130
+ ? config.value?.defaults?.passwordVisibleIcon || ""
131
+ : config.value?.defaults?.passwordHiddenIcon || "";
132
+ });
133
+
390
134
  onMounted(() => {
391
135
  toggleReadonlyToPreventAutocomplete(true);
392
136
  setLabelPosition();
393
137
  });
394
138
 
395
- function onInput(inputEvent) {
396
- let value = inputEvent.target.value;
139
+ function onInput(inputEvent: InputEvent) {
140
+ const target = inputEvent.target as HTMLInputElement | null;
141
+
142
+ if (!target) return;
143
+
144
+ let value = target.value;
397
145
 
398
146
  if (props.validationRule) {
399
- const input = document.querySelector(`#${elementId}`);
147
+ const input = document.querySelector(`#${elementId}`) as HTMLInputElement | null;
148
+
149
+ if (!input) return;
400
150
 
401
151
  value = VALIDATION_RULES_REG_EX[props.validationRule]
402
152
  ? transformValue(value, VALIDATION_RULES_REG_EX[props.validationRule])
@@ -408,42 +158,34 @@ function onInput(inputEvent) {
408
158
  emit("input", value);
409
159
  }
410
160
 
411
- function onChange(event) {
161
+ function onChange(event: CustomEvent) {
412
162
  emit("change", event);
413
163
  }
414
164
 
415
- function onClick(event) {
165
+ function onClick(event: MouseEvent) {
416
166
  toggleReadonlyToPreventAutocomplete(false);
417
167
 
418
168
  emit("click", event);
419
169
  }
420
170
 
421
- function onFocus(event) {
171
+ function onFocus(event: FocusEvent) {
422
172
  toggleReadonlyToPreventAutocomplete(false);
423
173
 
424
174
  emit("focus", event);
425
175
  }
426
176
 
427
- function onBlur(event) {
177
+ function onBlur(event: FocusEvent) {
428
178
  toggleReadonlyToPreventAutocomplete(true);
429
179
 
430
180
  emit("blur", event);
431
181
  }
432
182
 
433
- function onMousedown(event) {
183
+ function onMousedown(event: MouseEvent) {
434
184
  toggleReadonlyToPreventAutocomplete(false);
435
185
 
436
186
  emit("mousedown", event);
437
187
  }
438
188
 
439
- function onPaste(event) {
440
- emit("paste", event);
441
- }
442
-
443
- function onCopy(event) {
444
- emit("copy", event);
445
- }
446
-
447
189
  function onClickShowPassword() {
448
190
  isShownPassword.value = !isShownPassword.value;
449
191
  }
@@ -452,15 +194,15 @@ function onClickShowPassword() {
452
194
  * This trick prevents default browser autocomplete behavior.
453
195
  * @param toggleState { boolean }
454
196
  */
455
- function toggleReadonlyToPreventAutocomplete(toggleState) {
456
- if (props.noAutocomplete && !props.readonly) {
197
+ function toggleReadonlyToPreventAutocomplete(toggleState: boolean) {
198
+ if (props.noAutocomplete && !props.readonly && inputRef.value) {
457
199
  toggleState
458
200
  ? inputRef.value.setAttribute("readonly", "readonly")
459
201
  : inputRef.value.removeAttribute("readonly");
460
202
  }
461
203
  }
462
204
 
463
- function transformValue(value, exp) {
205
+ function transformValue(value: string | number, exp: string | RegExp) {
464
206
  const regExp = new RegExp(exp, "ig");
465
207
  const matches = String(value).match(regExp);
466
208
 
@@ -479,12 +221,13 @@ function setLabelPosition() {
479
221
  return;
480
222
  }
481
223
 
482
- const leftSlotOrIconWidth = leftSlotWrapperRef.value.getBoundingClientRect().width;
483
-
484
- const leftPaddingValue = parseFloat(getComputedStyle(inputRef.value).paddingLeft);
224
+ if (leftSlotWrapperRef.value && inputRef.value && labelComponentRef.value?.labelElement) {
225
+ const leftSlotOrIconWidth = leftSlotWrapperRef.value.getBoundingClientRect().width;
226
+ const leftPaddingValue = parseFloat(getComputedStyle(inputRef.value).paddingLeft);
485
227
 
486
- if (labelComponentRef.value.labelElement) {
487
- labelComponentRef.value.labelElement.style.left = `${leftSlotOrIconWidth + leftPaddingValue}px`;
228
+ if (labelComponentRef.value?.labelElement) {
229
+ labelComponentRef.value.labelElement.style.left = `${leftSlotOrIconWidth + leftPaddingValue}px`;
230
+ }
488
231
  }
489
232
  }
490
233
 
@@ -497,6 +240,104 @@ defineExpose({
497
240
  });
498
241
  </script>
499
242
 
243
+ <template>
244
+ <ULabel
245
+ ref="labelComponentRef"
246
+ :for="elementId"
247
+ :label="label"
248
+ :description="description"
249
+ :disabled="disabled"
250
+ :error="error"
251
+ :size="size"
252
+ :align="labelAlign"
253
+ centred
254
+ v-bind="inputLabelAttrs"
255
+ >
256
+ <label :for="elementId" v-bind="wrapperAttrs">
257
+ <span v-if="hasSlotContent($slots['left'])" ref="leftSlotWrapperRef">
258
+ <!-- @slot Use it to add something before the text. -->
259
+ <slot name="left" />
260
+ </span>
261
+
262
+ <span
263
+ v-if="hasSlotContent($slots['left-icon']) || leftIcon"
264
+ ref="leftSlotWrapperRef"
265
+ v-bind="leftIconWrapperAttrs"
266
+ >
267
+ <!--
268
+ @slot Use it to add icon before the text.
269
+ @binding {string} icon-name
270
+ @binding {string} icon-size
271
+ -->
272
+ <slot name="left-icon" :icon-name="leftIcon" :icon-size="iconSize">
273
+ <UIcon
274
+ v-if="leftIcon"
275
+ :name="leftIcon"
276
+ :size="iconSize"
277
+ internal
278
+ v-bind="leftIconAttrs"
279
+ />
280
+ </slot>
281
+ </span>
282
+
283
+ <input
284
+ :id="elementId"
285
+ ref="inputRef"
286
+ v-model="inputValue"
287
+ :placeholder="placeholder"
288
+ :type="inputType"
289
+ :readonly="readonly"
290
+ :disabled="disabled"
291
+ :maxlength="maxLength"
292
+ :inputmode="inputmode"
293
+ v-bind="inputAttrs"
294
+ :data-test="dataTest"
295
+ @focus="onFocus"
296
+ @blur="onBlur"
297
+ @input="onInput"
298
+ @change="onChange"
299
+ @mousedown="onMousedown"
300
+ @click="onClick"
301
+ @paste="onPaste"
302
+ @copy="onCopy"
303
+ />
304
+
305
+ <label v-if="isTypePassword" v-bind="rightIconWrapperAttrs" :for="elementId">
306
+ <UIcon
307
+ v-if="isTypePassword"
308
+ :name="passwordIcon"
309
+ color="gray"
310
+ interactive
311
+ internal
312
+ v-bind="passwordIconAttrs"
313
+ :data-test="`${dataTest}-password-icon`"
314
+ @click="onClickShowPassword"
315
+ />
316
+ </label>
317
+
318
+ <span v-if="hasSlotContent($slots['right-icon']) || rightIcon" v-bind="rightIconWrapperAttrs">
319
+ <!--
320
+ @slot Use it to add icon after the text.
321
+ @binding {string} icon-name
322
+ @binding {string} icon-size
323
+ -->
324
+ <slot name="right-icon" :icon-name="rightIcon" :icon-size="iconSize">
325
+ <UIcon
326
+ v-if="rightIcon"
327
+ :name="rightIcon"
328
+ :size="iconSize"
329
+ internal
330
+ v-bind="rightIconAttrs"
331
+ />
332
+ </slot>
333
+ </span>
334
+
335
+ <!-- @slot Use it to add something after the text. -->
336
+ <slot name="right" />
337
+ </label>
338
+ </ULabel>
339
+ </template>
340
+
500
341
  <style lang="postcss" scoped>
501
342
  @font-face {
502
343
  font-family: text-security-disc;
@@ -43,6 +43,9 @@ export default /*tw*/ {
43
43
  focus-within:border-red-500 focus-within:ring-red-700/15
44
44
  `,
45
45
  },
46
+ typePassword: {
47
+ true: "tracking-widest [font-family:text-security-disc,serif] [-webkit-text-security:disc]",
48
+ },
46
49
  },
47
50
  compoundVariants: [
48
51
  { labelAlign: "topInside", label: true, size: "sm", class: "pt-5" },
@@ -1,8 +1,8 @@
1
1
  import { Meta, Title, Subtitle, Description, Primary, Controls, Stories, Source } from "@storybook/blocks";
2
2
  import { getSource } from "../../utils/storybook.ts";
3
3
 
4
- import * as stories from "./stories.js";
5
- import defaultConfig from "../config.js?raw"
4
+ import * as stories from "./stories.ts";
5
+ import defaultConfig from "../config.ts?raw"
6
6
 
7
7
  <Meta of={stories} />
8
8
  <Title of={stories} />
@@ -10,6 +10,14 @@ import UIcon from "../../ui.image-icon/UIcon.vue";
10
10
  import UButton from "../../ui.button/UButton.vue";
11
11
  import UCol from "../../ui.container-col/UCol.vue";
12
12
 
13
+ import type { Meta, StoryFn } from "@storybook/vue3";
14
+ import type { UInputProps } from "../types.ts";
15
+
16
+ interface UInputArgs extends UInputProps {
17
+ slotTemplate?: string;
18
+ enum: "labelAlign" | "size" | "validationRule";
19
+ }
20
+
13
21
  export default {
14
22
  id: "3010",
15
23
  title: "Form Inputs & Controls / Input",
@@ -24,9 +32,9 @@ export default {
24
32
  parameters: {
25
33
  ...getDocsDescription(UInput.__name),
26
34
  },
27
- };
35
+ } as Meta;
28
36
 
29
- const DefaultTemplate = (args) => ({
37
+ const DefaultTemplate: StoryFn<UInputArgs> = (args: UInputArgs) => ({
30
38
  components: { UInput, UIcon, UButton },
31
39
  setup() {
32
40
  const slots = getSlotNames(UInput.__name);
@@ -35,17 +43,17 @@ const DefaultTemplate = (args) => ({
35
43
  },
36
44
  template: `
37
45
  <UInput v-bind="args" v-model="args.modelValue">
38
- ${args.slotTemplate || getSlotsFragment()}
46
+ ${args.slotTemplate || getSlotsFragment("")}
39
47
  </UInput>
40
48
  `,
41
49
  });
42
50
 
43
- const EnumVariantTemplate = (args, { argTypes }) => ({
51
+ const EnumVariantTemplate: StoryFn<UInputArgs> = (args: UInputArgs, { argTypes }) => ({
44
52
  components: { UInput, UCol },
45
53
  setup() {
46
54
  return {
47
55
  args,
48
- options: argTypes[args.enum].options,
56
+ options: argTypes?.[args.enum]?.options,
49
57
  };
50
58
  },
51
59
  template: `
@@ -77,7 +85,7 @@ export const Placeholder = DefaultTemplate.bind({});
77
85
  Placeholder.args = { placeholder: "some placeholder text" };
78
86
 
79
87
  export const Readonly = DefaultTemplate.bind({});
80
- Readonly.args = { readonly: true, value: "some value for read" };
88
+ Readonly.args = { readonly: true, modelValue: "some value for read" };
81
89
 
82
90
  export const NoAutocomplete = DefaultTemplate.bind({});
83
91
  NoAutocomplete.args = { noAutocomplete: true };