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.
- package/package.json +1 -1
- package/types.ts +24 -3
- package/ui.button/types.ts +2 -2
- 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-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-input/UInput.vue +162 -321
- 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 +227 -138
- 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,132 +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
|
-
@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.
|
|
125
|
-
import { UInput } from "./constants.
|
|
126
|
-
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";
|
|
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
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
|
347
|
-
const
|
|
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
|
|
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, {
|
|
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
|
-
|
|
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
|
-
|
|
483
|
-
|
|
484
|
-
|
|
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
|
-
|
|
487
|
-
|
|
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.
|
|
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 };
|