vueless 0.0.568 → 0.0.570

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