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.
- package/package.json +1 -1
- package/types.ts +14 -0
- package/ui.container-accordion/UAccordion.vue +2 -2
- package/ui.container-accordion/types.ts +1 -0
- package/ui.container-modal/UModal.vue +15 -8
- package/ui.container-page/UPage.vue +10 -6
- package/ui.form-calendar/UCalendar.vue +14 -25
- package/ui.form-calendar/config.ts +3 -0
- package/ui.form-calendar/constants.ts +0 -2
- package/ui.form-calendar/useAttrs.ts +1 -1
- package/ui.form-calendar/utilCalendar.ts +16 -9
- package/ui.form-calendar/utilFormatting.ts +63 -11
- package/ui.form-checkbox/types.ts +7 -0
- package/ui.form-checkbox-group/UCheckboxGroup.vue +1 -1
- package/ui.form-checkbox-multi-state/UCheckboxMultiState.vue +4 -1
- package/ui.form-color-picker/UColorPicker.vue +67 -147
- package/ui.form-color-picker/storybook/Docs.mdx +2 -2
- package/ui.form-color-picker/storybook/{stories.js → stories.ts} +13 -5
- package/ui.form-color-picker/types.ts +64 -0
- package/ui.form-color-picker/useAttrs.ts +15 -0
- package/ui.form-date-picker/UDatePicker.vue +109 -43
- package/ui.form-date-picker/config.ts +5 -5
- package/ui.form-date-picker-range/useAttrs.ts +1 -1
- package/ui.form-date-picker-range/useLocale.ts +1 -1
- package/ui.form-input/UInput.vue +162 -301
- package/ui.form-input/{config.js → config.ts} +3 -0
- package/ui.form-input/storybook/Docs.mdx +2 -2
- package/ui.form-input/storybook/{stories.js → stories.ts} +14 -6
- package/ui.form-input/types.ts +103 -0
- package/ui.form-input/useAttrs.ts +31 -0
- package/ui.form-input-file/UInputFile.vue +188 -245
- package/ui.form-input-file/storybook/Docs.mdx +2 -2
- package/ui.form-input-file/storybook/{stories.js → stories.ts} +13 -5
- package/ui.form-input-file/types.ts +72 -0
- package/ui.form-input-file/useAttrs.ts +21 -0
- package/ui.form-input-file/{utilFileForm.js → utilFileForm.ts} +1 -1
- package/ui.form-input-money/UInputMoney.vue +76 -223
- package/ui.form-input-money/storybook/Docs.mdx +2 -2
- package/ui.form-input-money/storybook/{stories.js → stories.ts} +14 -6
- package/ui.form-input-money/types.ts +118 -0
- package/ui.form-input-money/useAttrs.ts +15 -0
- package/ui.form-input-money/{useFormatCurrency.js → useFormatCurrency.ts} +28 -17
- package/ui.form-input-money/utilFormat.ts +83 -0
- package/ui.form-input-number/UInputNumber.vue +69 -156
- package/ui.form-input-number/storybook/Docs.mdx +2 -2
- package/ui.form-input-number/storybook/{stories.js → stories.ts} +17 -9
- package/ui.form-input-number/types.ts +65 -0
- package/ui.form-input-number/useAttrs.ts +15 -0
- package/ui.form-input-rating/UInputRating.vue +70 -158
- package/ui.form-input-rating/storybook/Docs.mdx +2 -2
- package/ui.form-input-rating/storybook/{stories.js → stories.ts} +14 -6
- package/ui.form-input-rating/types.ts +67 -0
- package/ui.form-input-rating/useAttrs.ts +14 -0
- package/ui.form-input-search/UInputSearch.vue +97 -224
- package/ui.form-input-search/storybook/Docs.mdx +2 -2
- package/ui.form-input-search/storybook/{stories.js → stories.ts} +13 -5
- package/ui.form-input-search/types.ts +93 -0
- package/ui.form-input-search/useAttrs.ts +15 -0
- package/ui.form-radio/URadio.vue +1 -1
- package/ui.form-radio-group/URadioGroup.vue +1 -1
- package/ui.navigation-pagination/UPagination.vue +15 -15
- package/ui.navigation-pagination/types.ts +3 -0
- package/ui.navigation-progress/UProgress.vue +16 -2
- package/ui.navigation-progress/types.ts +2 -0
- package/ui.text-files/UFiles.vue +20 -16
- package/ui.text-files/types.ts +1 -1
- package/ui.text-notify/UNotify.vue +38 -48
- package/ui.text-notify/types.ts +24 -0
- package/web-types.json +229 -132
- package/ui.form-color-picker/useAttrs.js +0 -9
- package/ui.form-input/useAttrs.js +0 -15
- package/ui.form-input-file/useAttrs.js +0 -15
- package/ui.form-input-money/useAttrs.js +0 -9
- package/ui.form-input-money/utilFormat.js +0 -75
- package/ui.form-input-number/useAttrs.js +0 -9
- package/ui.form-input-rating/useAttrs.js +0 -8
- package/ui.form-input-search/useAttrs.js +0 -9
- /package/ui.form-color-picker/{config.js → config.ts} +0 -0
- /package/ui.form-color-picker/{constants.js → constants.ts} +0 -0
- /package/ui.form-input/{constants.js → constants.ts} +0 -0
- /package/ui.form-input-file/{config.js → config.ts} +0 -0
- /package/ui.form-input-file/{constants.js → constants.ts} +0 -0
- /package/ui.form-input-money/{config.js → config.ts} +0 -0
- /package/ui.form-input-money/{constants.js → constants.ts} +0 -0
- /package/ui.form-input-number/{config.js → config.ts} +0 -0
- /package/ui.form-input-number/{constants.js → constants.ts} +0 -0
- /package/ui.form-input-rating/{config.js → config.ts} +0 -0
- /package/ui.form-input-rating/{constants.js → constants.ts} +0 -0
- /package/ui.form-input-search/{config.js → config.ts} +0 -0
- /package/ui.form-input-search/{constants.js → constants.ts} +0 -0
package/ui.form-input/UInput.vue
CHANGED
|
@@ -1,130 +1,35 @@
|
|
|
1
|
-
<
|
|
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.
|
|
123
|
-
import { UInput } from "./constants.
|
|
124
|
-
import useAttrs from "./useAttrs.
|
|
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
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
|
335
|
-
const
|
|
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
|
|
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, {
|
|
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
|
-
|
|
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
|
-
|
|
463
|
-
|
|
464
|
-
|
|
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
|
-
|
|
467
|
-
|
|
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.
|
|
5
|
-
import defaultConfig from "../config.
|
|
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]
|
|
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,
|
|
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 };
|