sprintify-ui 0.6.32 → 0.6.34
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/dist/sprintify-ui.es.js +13449 -13183
- package/dist/style.css +1 -1
- package/dist/tailwindcss/button.js +261 -0
- package/dist/tailwindcss/index.js +16 -301
- package/dist/tailwindcss/input.js +24 -0
- package/dist/tailwindcss/overlay.js +13 -0
- package/dist/tailwindcss/theme.js +46 -0
- package/dist/types/src/components/BaseActionItemButton.vue.d.ts +2 -2
- package/dist/types/src/components/BaseAddressForm.vue.d.ts +10 -0
- package/dist/types/src/components/BaseAutocomplete.vue.d.ts +10 -10
- package/dist/types/src/components/BaseAutocompleteDrawer.vue.d.ts +3 -3
- package/dist/types/src/components/BaseAutocompleteFetch.vue.d.ts +6 -6
- package/dist/types/src/components/BaseAvatarGroup.vue.d.ts +1 -1
- package/dist/types/src/components/BaseBelongsTo.vue.d.ts +6 -6
- package/dist/types/src/components/BaseBelongsToFetch.vue.d.ts +6 -6
- package/dist/types/src/components/BaseButton.vue.d.ts +12 -12
- package/dist/types/src/components/BaseButtonGroup.vue.d.ts +24 -24
- package/dist/types/src/components/BaseCalendar.vue.d.ts +1 -1
- package/dist/types/src/components/BaseColor.vue.d.ts +19 -0
- package/dist/types/src/components/BaseDataIterator.vue.d.ts +1 -1
- package/dist/types/src/components/BaseDataIteratorSectionColumns.vue.d.ts +4 -4
- package/dist/types/src/components/BaseDataTable.vue.d.ts +1 -1
- package/dist/types/src/components/BaseDropdownAutocomplete.vue.d.ts +1 -1
- package/dist/types/src/components/BaseField.vue.d.ts +13 -3
- package/dist/types/src/components/BaseInput.vue.d.ts +53 -4
- package/dist/types/src/components/BaseInputError.vue.d.ts +14 -1
- package/dist/types/src/components/BaseInputLabel.vue.d.ts +15 -5
- package/dist/types/src/components/BaseLayoutSidebarConfigurable.vue.d.ts +1 -1
- package/dist/types/src/components/BaseLayoutStackedConfigurable.vue.d.ts +1 -1
- package/dist/types/src/components/BaseLoadingCover.vue.d.ts +1 -1
- package/dist/types/src/components/BaseMediaGallery.vue.d.ts +1 -1
- package/dist/types/src/components/BaseMediaListItem.vue.d.ts +1 -1
- package/dist/types/src/components/BaseMediaPictures.vue.d.ts +1 -1
- package/dist/types/src/components/BaseMediaPicturesItem.vue.d.ts +1 -1
- package/dist/types/src/components/BaseMenu.vue.d.ts +1 -1
- package/dist/types/src/components/BaseMenuItem.vue.d.ts +1 -1
- package/dist/types/src/components/BaseNavbar.vue.d.ts +1 -1
- package/dist/types/src/components/BaseNavbarItemContent.vue.d.ts +1 -1
- package/dist/types/src/components/BaseNavbarSideItemContent.vue.d.ts +1 -1
- package/dist/types/src/components/BasePassword.vue.d.ts +13 -0
- package/dist/types/src/components/BaseSelect.vue.d.ts +27 -0
- package/dist/types/src/components/BaseSideNavigation.vue.d.ts +3 -3
- package/dist/types/src/components/BaseSwitch.vue.d.ts +1 -1
- package/dist/types/src/components/BaseTable.vue.d.ts +1 -1
- package/dist/types/src/components/BaseTabs.vue.d.ts +3 -3
- package/dist/types/src/components/BaseTagAutocomplete.vue.d.ts +3 -3
- package/dist/types/src/components/BaseTextarea.vue.d.ts +18 -0
- package/dist/types/src/components/BaseTextareaAutoresize.vue.d.ts +9 -0
- package/dist/types/src/composables/field.d.ts +3 -0
- package/dist/types/src/composables/inputSize.d.ts +6 -0
- package/dist/types/src/utils/sizes.d.ts +19 -0
- package/package.json +1 -1
- package/src/assets/form.css +1 -1
- package/src/components/BaseAddressForm.stories.js +7 -2
- package/src/components/BaseAddressForm.vue +64 -37
- package/src/components/BaseAutocomplete.stories.js +1 -1
- package/src/components/BaseAutocomplete.vue +86 -96
- package/src/components/BaseAutocompleteDrawer.vue +3 -2
- package/src/components/BaseAutocompleteFetch.stories.js +1 -1
- package/src/components/BaseAutocompleteFetch.vue +3 -2
- package/src/components/BaseBelongsTo.stories.js +1 -1
- package/src/components/BaseBelongsTo.vue +3 -2
- package/src/components/BaseBelongsToFetch.vue +3 -2
- package/src/components/BaseButton.stories.js +21 -0
- package/src/components/BaseButton.vue +42 -6
- package/src/components/BaseButtonGroup.stories.js +31 -1
- package/src/components/BaseButtonGroup.vue +46 -33
- package/src/components/BaseColor.stories.js +22 -0
- package/src/components/BaseColor.vue +28 -25
- package/src/components/BaseDataTable.vue +5 -5
- package/src/components/BaseDataTableRowAction.vue +6 -6
- package/src/components/BaseDatePicker.vue +6 -3
- package/src/components/BaseDraggable.vue +5 -1
- package/src/components/BaseDropdown.stories.js +2 -3
- package/src/components/BaseDropdownAutocomplete.vue +2 -2
- package/src/components/BaseField.vue +19 -8
- package/src/components/BaseInput.stories.js +36 -2
- package/src/components/BaseInput.vue +199 -74
- package/src/components/BaseInputError.vue +32 -2
- package/src/components/BaseInputLabel.vue +36 -9
- package/src/components/BasePassword.stories.js +25 -0
- package/src/components/BasePassword.vue +35 -55
- package/src/components/BaseSelect.stories.js +34 -0
- package/src/components/BaseSelect.vue +57 -8
- package/src/components/BaseTagAutocomplete.vue +3 -2
- package/src/components/BaseTextarea.stories.js +25 -0
- package/src/components/BaseTextarea.vue +34 -3
- package/src/components/BaseTextareaAutoresize.stories.js +27 -2
- package/src/components/BaseTextareaAutoresize.vue +27 -8
- package/src/components/BaseTimelineItem.stories.js +1 -3
- package/src/composables/field.ts +20 -0
- package/src/composables/inputSize.ts +29 -0
- package/src/utils/sizes.ts +21 -0
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
3
|
-
class="
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
{{ prefix }}
|
|
2
|
+
<div :class="classes">
|
|
3
|
+
<div :class="decorationWrapClasses">
|
|
4
|
+
<component
|
|
5
|
+
:is="hasLeftListener ? 'button' : 'div'"
|
|
6
|
+
v-if="iconLeft"
|
|
7
|
+
:type="hasLeftListener ? 'button' : undefined"
|
|
8
|
+
:class="[decorationClasses, hasLeftListener ? 'hover:bg-slate-100' : '']"
|
|
9
|
+
@click="onIconLeftClickInternal"
|
|
10
|
+
>
|
|
11
|
+
<BaseIcon
|
|
12
|
+
:icon="iconLeft"
|
|
13
|
+
:class="iconClasses"
|
|
14
|
+
/>
|
|
15
|
+
</component>
|
|
16
|
+
<div
|
|
17
|
+
v-if="prefix"
|
|
18
|
+
:class="decorationClasses"
|
|
19
|
+
@click="focusAction"
|
|
20
|
+
>
|
|
21
|
+
{{ prefix }}
|
|
22
|
+
</div>
|
|
24
23
|
</div>
|
|
24
|
+
|
|
25
25
|
<input
|
|
26
26
|
v-if="maskOptions"
|
|
27
27
|
ref="input"
|
|
@@ -30,12 +30,10 @@
|
|
|
30
30
|
:value="modelValue"
|
|
31
31
|
:type="type"
|
|
32
32
|
:autocomplete="autocomplete ? 'on' : 'off'"
|
|
33
|
-
:class="
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}"
|
|
38
|
-
@input="update"
|
|
33
|
+
:class="baseClasses"
|
|
34
|
+
@input="onInput"
|
|
35
|
+
@click="onClick"
|
|
36
|
+
@keydown="onKeydown"
|
|
39
37
|
>
|
|
40
38
|
<input
|
|
41
39
|
v-else
|
|
@@ -44,31 +42,31 @@
|
|
|
44
42
|
:value="modelValue"
|
|
45
43
|
:type="type"
|
|
46
44
|
:autocomplete="autocomplete ? 'on' : 'off'"
|
|
47
|
-
:class="
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}"
|
|
52
|
-
@input="update"
|
|
53
|
-
>
|
|
54
|
-
<div
|
|
55
|
-
v-if="suffix"
|
|
56
|
-
class="flex shrink-0 items-center justify-center border-l px-4 transition-colors"
|
|
57
|
-
:class="[
|
|
58
|
-
iconRight ? '' : 'rounded-r',
|
|
59
|
-
borderColor,
|
|
60
|
-
backgroundColor,
|
|
61
|
-
textColor,
|
|
62
|
-
]"
|
|
63
|
-
>
|
|
64
|
-
{{ suffix }}
|
|
65
|
-
</div>
|
|
66
|
-
<div
|
|
67
|
-
v-if="iconRight"
|
|
68
|
-
class="flex shrink-0 items-center justify-center rounded-r border-l px-3 transition-colors"
|
|
69
|
-
:class="[borderColor, backgroundColor, textColor]"
|
|
45
|
+
:class="baseClasses"
|
|
46
|
+
@input="onInput"
|
|
47
|
+
@click="onClick"
|
|
48
|
+
@keydown="onKeydown"
|
|
70
49
|
>
|
|
71
|
-
|
|
50
|
+
<div :class="decorationWrapClasses">
|
|
51
|
+
<div
|
|
52
|
+
v-if="suffix"
|
|
53
|
+
:class="decorationClasses"
|
|
54
|
+
@click="focusAction"
|
|
55
|
+
>
|
|
56
|
+
{{ suffix }}
|
|
57
|
+
</div>
|
|
58
|
+
<component
|
|
59
|
+
:is="hasRightListener ? 'button' : 'div'"
|
|
60
|
+
v-if="iconRight"
|
|
61
|
+
:type="hasRightListener ? 'button' : undefined"
|
|
62
|
+
:class="[decorationClasses, hasRightListener ? 'hover:bg-slate-100' : '']"
|
|
63
|
+
@click="onIconRightClickInternal"
|
|
64
|
+
>
|
|
65
|
+
<BaseIcon
|
|
66
|
+
:icon="iconRight"
|
|
67
|
+
:class="iconClasses"
|
|
68
|
+
/>
|
|
69
|
+
</component>
|
|
72
70
|
</div>
|
|
73
71
|
</div>
|
|
74
72
|
</template>
|
|
@@ -79,12 +77,22 @@ import { PropType } from 'vue';
|
|
|
79
77
|
import { Icon as BaseIcon } from '@iconify/vue';
|
|
80
78
|
import { useField } from '@/composables/field';
|
|
81
79
|
import { vMaska } from 'maska';
|
|
80
|
+
import { Size, sizes } from '@/utils/sizes';
|
|
81
|
+
import { twMerge } from 'tailwind-merge';
|
|
82
|
+
|
|
83
|
+
defineOptions({
|
|
84
|
+
inheritAttrs: false,
|
|
85
|
+
})
|
|
82
86
|
|
|
83
87
|
const props = defineProps({
|
|
84
88
|
modelValue: {
|
|
85
89
|
default: '',
|
|
86
90
|
type: [String, Number, null] as PropType<string | number | null>,
|
|
87
91
|
},
|
|
92
|
+
class: {
|
|
93
|
+
default: '',
|
|
94
|
+
type: [String, Array] as PropType<string | string[]>,
|
|
95
|
+
},
|
|
88
96
|
type: {
|
|
89
97
|
type: String,
|
|
90
98
|
default: 'text',
|
|
@@ -140,6 +148,10 @@ const props = defineProps({
|
|
|
140
148
|
default: false,
|
|
141
149
|
type: Boolean,
|
|
142
150
|
},
|
|
151
|
+
size: {
|
|
152
|
+
default: undefined,
|
|
153
|
+
type: String as PropType<Size>,
|
|
154
|
+
},
|
|
143
155
|
min: {
|
|
144
156
|
default: undefined,
|
|
145
157
|
type: [null, Number] as PropType<undefined | null | number>,
|
|
@@ -154,9 +166,38 @@ const props = defineProps({
|
|
|
154
166
|
return null;
|
|
155
167
|
},
|
|
156
168
|
},
|
|
169
|
+
visibleFocus: {
|
|
170
|
+
default: true,
|
|
171
|
+
type: Boolean,
|
|
172
|
+
},
|
|
173
|
+
onIconLeftClick: {
|
|
174
|
+
default: undefined,
|
|
175
|
+
type: Function as PropType<() => void>,
|
|
176
|
+
},
|
|
177
|
+
onIconRightClick: {
|
|
178
|
+
default: undefined,
|
|
179
|
+
type: Function as PropType<() => void>,
|
|
180
|
+
},
|
|
157
181
|
});
|
|
158
182
|
|
|
159
183
|
const input = ref<HTMLInputElement | null>(null);
|
|
184
|
+
const focus = ref(false);
|
|
185
|
+
|
|
186
|
+
const hasLeftDecoration = computed(() => {
|
|
187
|
+
return props.iconLeft || props.prefix;
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
const hasRightDecoration = computed(() => {
|
|
191
|
+
return props.iconRight || props.suffix;
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
const hasLeftListener = computed(() => {
|
|
195
|
+
return props.onIconLeftClick !== undefined;
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const hasRightListener = computed(() => {
|
|
199
|
+
return props.onIconRightClick !== undefined;
|
|
200
|
+
});
|
|
160
201
|
|
|
161
202
|
const maskOptions = computed(() => {
|
|
162
203
|
if (props.mask) {
|
|
@@ -167,14 +208,6 @@ const maskOptions = computed(() => {
|
|
|
167
208
|
return undefined;
|
|
168
209
|
});
|
|
169
210
|
|
|
170
|
-
const emptyLeft = computed(() => {
|
|
171
|
-
return !props.iconLeft && !props.prefix;
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
const emptyRight = computed(() => {
|
|
175
|
-
return !props.iconRight && !props.suffix;
|
|
176
|
-
});
|
|
177
|
-
|
|
178
211
|
const bindings = computed<any>(() => {
|
|
179
212
|
return {
|
|
180
213
|
name: nameInternal.value,
|
|
@@ -184,7 +217,6 @@ const bindings = computed<any>(() => {
|
|
|
184
217
|
disabled: props.disabled,
|
|
185
218
|
placeholder: props.placeholder,
|
|
186
219
|
required: requiredInternal.value,
|
|
187
|
-
|
|
188
220
|
onKeydown(event: KeyboardEvent) {
|
|
189
221
|
if (event.code == 'Enter' && props.preventSubmit) {
|
|
190
222
|
event.preventDefault();
|
|
@@ -192,9 +224,11 @@ const bindings = computed<any>(() => {
|
|
|
192
224
|
},
|
|
193
225
|
onFocus: (e: Event) => {
|
|
194
226
|
emit('focus', e);
|
|
227
|
+
focus.value = true;
|
|
195
228
|
},
|
|
196
229
|
onBlur: (e: Event) => {
|
|
197
230
|
emit('blur', e);
|
|
231
|
+
focus.value = false;
|
|
198
232
|
},
|
|
199
233
|
};
|
|
200
234
|
});
|
|
@@ -219,17 +253,18 @@ const maskInternal = computed(() => {
|
|
|
219
253
|
return props.mask;
|
|
220
254
|
});
|
|
221
255
|
|
|
222
|
-
const emit = defineEmits(['update:modelValue', 'focus', 'blur']);
|
|
256
|
+
const emit = defineEmits(['update:modelValue', 'focus', 'blur', 'click', 'keydown']);
|
|
223
257
|
|
|
224
|
-
const { nameInternal, requiredInternal, hasErrorInternal, emitUpdate } =
|
|
258
|
+
const { nameInternal, requiredInternal, hasErrorInternal, emitUpdate, sizeInternal } =
|
|
225
259
|
useField({
|
|
226
260
|
name: computed(() => props.name),
|
|
227
261
|
required: computed(() => props.required),
|
|
228
262
|
hasError: computed(() => props.hasError),
|
|
263
|
+
size: computed(() => props.size),
|
|
229
264
|
emit: emit,
|
|
230
265
|
});
|
|
231
266
|
|
|
232
|
-
function
|
|
267
|
+
function onInput(event: any | null) {
|
|
233
268
|
if (event === null) {
|
|
234
269
|
emitUpdate(null);
|
|
235
270
|
}
|
|
@@ -237,28 +272,118 @@ function update(event: any | null) {
|
|
|
237
272
|
return emitUpdate(get(event, 'target.value', ''));
|
|
238
273
|
}
|
|
239
274
|
|
|
240
|
-
|
|
241
|
-
|
|
275
|
+
function onClick(event: MouseEvent) {
|
|
276
|
+
emit('click', event);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function onKeydown(event: KeyboardEvent) {
|
|
280
|
+
emit('keydown', event);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const classes = computed(() => {
|
|
284
|
+
const base = `inline-flex bg-white input-rounded border transition-colors duration-200`;
|
|
285
|
+
const border = hasErrorInternal.value ? 'border-red-500' : 'border-slate-300';
|
|
286
|
+
const disabled = props.disabled ? 'cursor-not-allowed text-slate-300' : '';
|
|
287
|
+
const sizeConfig = sizes[sizeInternal.value];
|
|
288
|
+
let focusClass = '';
|
|
289
|
+
if (props.visibleFocus) {
|
|
290
|
+
if (hasErrorInternal.value) {
|
|
291
|
+
focusClass = 'focus-within:input-focus-error';
|
|
292
|
+
} else {
|
|
293
|
+
focusClass = 'focus-within:input-focus';
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return twMerge([
|
|
298
|
+
base,
|
|
299
|
+
border,
|
|
300
|
+
disabled,
|
|
301
|
+
sizeConfig.height,
|
|
302
|
+
sizeConfig.fontSize,
|
|
303
|
+
focusClass,
|
|
304
|
+
props.class,
|
|
305
|
+
]);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
const baseClasses = computed(() => {
|
|
309
|
+
const base = `border-none outline-none bg-transparent grow min-w-0 focus:border-none focus:outline-none focus:ring-0`;
|
|
310
|
+
const sizeConfig = sizes[sizeInternal.value];
|
|
311
|
+
const disabled = props.disabled ? 'cursor-not-allowed text-slate-300' : '';
|
|
312
|
+
|
|
313
|
+
const paddingX = {
|
|
314
|
+
xs: [hasLeftDecoration.value ? 'pl-0.5' : 'pl-2', hasRightDecoration.value ? 'pr-0' : 'pr-2'],
|
|
315
|
+
sm: [hasLeftDecoration.value ? 'pl-0.5' : 'pl-2.5', hasRightDecoration.value ? 'pr-0' : 'pr-2.5'],
|
|
316
|
+
md: [hasLeftDecoration.value ? 'pl-1' : 'pl-3', hasRightDecoration.value ? 'pr-1' : 'pr-3'],
|
|
317
|
+
}[sizeInternal.value];
|
|
318
|
+
|
|
319
|
+
return [
|
|
320
|
+
base,
|
|
321
|
+
disabled,
|
|
322
|
+
paddingX,
|
|
323
|
+
sizeConfig.fontSize,
|
|
324
|
+
];
|
|
242
325
|
});
|
|
243
326
|
|
|
244
|
-
const
|
|
245
|
-
|
|
327
|
+
const decorationWrapClasses = computed(() => {
|
|
328
|
+
const base = `flex justify-center empty:hidden`;
|
|
329
|
+
const spacing = {
|
|
330
|
+
xs: 'first:pl-0.5 last:pr-0.5 py-0.5',
|
|
331
|
+
sm: 'first:pl-1 last:pr-1 py-1',
|
|
332
|
+
md: 'first:pl-1 last:pr-1 py-1',
|
|
333
|
+
}[sizeInternal.value];
|
|
334
|
+
|
|
335
|
+
return [
|
|
336
|
+
base,
|
|
337
|
+
spacing,
|
|
338
|
+
];
|
|
246
339
|
});
|
|
247
340
|
|
|
248
|
-
const
|
|
249
|
-
|
|
341
|
+
const decorationClasses = computed(() => {
|
|
342
|
+
const base = `flex items-center justify-center rounded-md`;
|
|
343
|
+
const textColor = hasErrorInternal.value ? 'text-red-800' : 'text-slate-500';
|
|
344
|
+
const padding = {
|
|
345
|
+
xs: 'p-1',
|
|
346
|
+
sm: 'p-1.5',
|
|
347
|
+
md: 'p-2',
|
|
348
|
+
}[sizeInternal.value];
|
|
349
|
+
|
|
350
|
+
return `${base} ${textColor} ${padding}`;
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
const iconClasses = computed(() => {
|
|
354
|
+
const sizeConfig = sizes[sizeInternal.value];
|
|
355
|
+
|
|
356
|
+
return [
|
|
357
|
+
sizeConfig.iconSize,
|
|
358
|
+
];
|
|
250
359
|
});
|
|
251
360
|
|
|
252
|
-
function
|
|
361
|
+
function focusAction() {
|
|
253
362
|
input.value?.focus();
|
|
254
363
|
}
|
|
255
364
|
|
|
256
|
-
function
|
|
365
|
+
function blurAction() {
|
|
257
366
|
input.value?.blur();
|
|
258
367
|
}
|
|
259
368
|
|
|
369
|
+
function onIconLeftClickInternal() {
|
|
370
|
+
if (props.onIconLeftClick) {
|
|
371
|
+
props.onIconLeftClick();
|
|
372
|
+
} else {
|
|
373
|
+
focusAction();
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function onIconRightClickInternal() {
|
|
378
|
+
if (props.onIconRightClick) {
|
|
379
|
+
props.onIconRightClick();
|
|
380
|
+
} else {
|
|
381
|
+
blurAction();
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
260
385
|
defineExpose({
|
|
261
|
-
focus,
|
|
262
|
-
blur,
|
|
386
|
+
focus: focusAction,
|
|
387
|
+
blur: blurAction,
|
|
263
388
|
});
|
|
264
389
|
</script>
|
|
@@ -1,7 +1,37 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<p class="
|
|
2
|
+
<p :class="classes">
|
|
3
3
|
<slot />
|
|
4
4
|
</p>
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
|
-
<script lang="ts" setup
|
|
7
|
+
<script lang="ts" setup>
|
|
8
|
+
import { useInputSize } from '@/composables/inputSize';
|
|
9
|
+
import { Size } from '@/utils/sizes';
|
|
10
|
+
import { PropType } from 'vue';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const props = defineProps({
|
|
14
|
+
size: {
|
|
15
|
+
default: undefined,
|
|
16
|
+
type: String as PropType<Size>,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const { size } = useInputSize(computed(() => props.size));
|
|
21
|
+
|
|
22
|
+
const classes = computed(() => {
|
|
23
|
+
const base = 'block font-medium leading-tight text-red-600';
|
|
24
|
+
|
|
25
|
+
const responsive = {
|
|
26
|
+
'xs': 'text-xs mb-0.5',
|
|
27
|
+
'sm': 'text-xs mb-1',
|
|
28
|
+
'md': 'text-sm mb-1',
|
|
29
|
+
}[size.value];
|
|
30
|
+
|
|
31
|
+
return [
|
|
32
|
+
base,
|
|
33
|
+
responsive,
|
|
34
|
+
]
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
</script>
|
|
@@ -2,25 +2,27 @@
|
|
|
2
2
|
<label :class="classes">
|
|
3
3
|
<div
|
|
4
4
|
ref="labelRef"
|
|
5
|
-
class="relative inline-flex"
|
|
5
|
+
class="relative inline-flex items-center flex-wrap"
|
|
6
6
|
:class="[help ? 'cursor-help' : 'cursor-default']"
|
|
7
7
|
>
|
|
8
8
|
<div> {{ label }}</div>
|
|
9
9
|
|
|
10
|
+
<div
|
|
11
|
+
v-if="required"
|
|
12
|
+
class="ml-0.5 text-red-600"
|
|
13
|
+
> *</div>
|
|
14
|
+
|
|
10
15
|
<BaseTooltip
|
|
11
16
|
v-if="help"
|
|
12
17
|
:text="help"
|
|
13
18
|
>
|
|
14
19
|
<BaseIcon
|
|
15
|
-
class="block relative text-slate-900
|
|
20
|
+
class="block relative text-slate-900 ml-1 mr-1 h-[13px] w-[13px]"
|
|
16
21
|
icon="mdi:information-outline"
|
|
17
22
|
/>
|
|
18
23
|
</BaseTooltip>
|
|
19
24
|
|
|
20
|
-
|
|
21
|
-
v-if="required"
|
|
22
|
-
class="ml-0.5 text-red-600"
|
|
23
|
-
> *</div>
|
|
25
|
+
|
|
24
26
|
</div>
|
|
25
27
|
</label>
|
|
26
28
|
</template>
|
|
@@ -29,8 +31,15 @@
|
|
|
29
31
|
import { PropType } from 'vue';
|
|
30
32
|
import { Icon as BaseIcon } from '@iconify/vue';
|
|
31
33
|
import BaseTooltip from './BaseTooltip.vue';
|
|
34
|
+
import { Size } from '@/utils/sizes';
|
|
35
|
+
import { useInputSize } from '@/composables/inputSize';
|
|
36
|
+
import { ClassNameValue, twMerge } from 'tailwind-merge';
|
|
32
37
|
|
|
33
|
-
|
|
38
|
+
defineOptions({
|
|
39
|
+
inheritAttrs: false,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const props = defineProps({
|
|
34
43
|
required: {
|
|
35
44
|
default: false,
|
|
36
45
|
type: Boolean,
|
|
@@ -39,16 +48,34 @@ defineProps({
|
|
|
39
48
|
required: true,
|
|
40
49
|
type: String,
|
|
41
50
|
},
|
|
42
|
-
|
|
51
|
+
class: {
|
|
43
52
|
default: 'mb-1 block text-sm',
|
|
44
|
-
type: String,
|
|
53
|
+
type: [String, Array] as PropType<ClassNameValue>,
|
|
45
54
|
},
|
|
46
55
|
help: {
|
|
47
56
|
default: null,
|
|
48
57
|
type: [String, null] as PropType<string | null>,
|
|
49
58
|
},
|
|
59
|
+
size: {
|
|
60
|
+
default: undefined,
|
|
61
|
+
type: String as PropType<Size>,
|
|
62
|
+
},
|
|
50
63
|
});
|
|
51
64
|
|
|
52
65
|
const labelRef = ref();
|
|
53
66
|
|
|
67
|
+
const { size } = useInputSize(computed(() => props.size));
|
|
68
|
+
|
|
69
|
+
const classes = computed(() => {
|
|
70
|
+
const base = 'mb-1 block text-sm';
|
|
71
|
+
|
|
72
|
+
const responsive = {
|
|
73
|
+
'xs': 'text-xs mb-[0.2rem]',
|
|
74
|
+
'sm': 'text-sm mb-1',
|
|
75
|
+
'md': 'text-sm mb-1',
|
|
76
|
+
}[size.value];
|
|
77
|
+
|
|
78
|
+
return twMerge(base, responsive, props.class);
|
|
79
|
+
});
|
|
80
|
+
|
|
54
81
|
</script>
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import BasePassword from './BasePassword.vue';
|
|
2
2
|
import { createFieldStory } from '@/../.storybook/utils';
|
|
3
3
|
|
|
4
|
+
const sizes = ['xs', 'sm', 'md'];
|
|
5
|
+
|
|
4
6
|
export default {
|
|
5
7
|
title: 'Form/BasePassword',
|
|
6
8
|
component: BasePassword,
|
|
7
9
|
args: {},
|
|
10
|
+
argTypes: {
|
|
11
|
+
size: {
|
|
12
|
+
control: { type: 'select' },
|
|
13
|
+
options: sizes,
|
|
14
|
+
},
|
|
15
|
+
},
|
|
8
16
|
};
|
|
9
17
|
|
|
10
18
|
const Template = (args) => ({
|
|
@@ -55,4 +63,21 @@ const FocusTemplate = (args) => ({
|
|
|
55
63
|
`,
|
|
56
64
|
});
|
|
57
65
|
|
|
66
|
+
const TemplateSizes = (args) => ({
|
|
67
|
+
components: { BasePassword },
|
|
68
|
+
setup() {
|
|
69
|
+
const value = ref(null);
|
|
70
|
+
const sizes = ['xs', 'sm', 'md'];
|
|
71
|
+
return { args, value, sizes };
|
|
72
|
+
},
|
|
73
|
+
template: `
|
|
74
|
+
<div v-for="size in sizes" :key="size" class="mb-4">
|
|
75
|
+
<p class="text-xs text-slate-600 leading-tight mb-1">{{ size }}</p>
|
|
76
|
+
<BasePassword v-model="value" v-bind="args" :size="size" class="w-full"></BasePassword>
|
|
77
|
+
</div>
|
|
78
|
+
`,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
export const Sizes = TemplateSizes.bind({});
|
|
82
|
+
|
|
58
83
|
export const Focus = FocusTemplate.bind({});
|
|
@@ -1,50 +1,25 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
:placeholder="placeholder"
|
|
16
|
-
:required="requiredInternal"
|
|
17
|
-
class="grow rounded-l rounded-r-none border-none focus:ring-2 focus:ring-primary-500 disabled:cursor-not-allowed"
|
|
18
|
-
@input="onInput"
|
|
19
|
-
>
|
|
20
|
-
<div class="flex shrink-0 pl-3">
|
|
21
|
-
<button
|
|
22
|
-
tabindex="-1"
|
|
23
|
-
type="button"
|
|
24
|
-
class="pr-3 text-slate-500 disabled:cursor-not-allowed disabled:text-slate-300"
|
|
25
|
-
:disabled="disabled"
|
|
26
|
-
@click="showPassword = !showPassword"
|
|
27
|
-
>
|
|
28
|
-
<BaseIcon
|
|
29
|
-
v-if="!showPassword"
|
|
30
|
-
icon="heroicons:eye-slash-20-solid"
|
|
31
|
-
class="h-5 w-5"
|
|
32
|
-
/>
|
|
33
|
-
<BaseIcon
|
|
34
|
-
v-else
|
|
35
|
-
icon="heroicons:eye-20-solid"
|
|
36
|
-
class="h-5 w-5"
|
|
37
|
-
/>
|
|
38
|
-
</button>
|
|
39
|
-
</div>
|
|
40
|
-
</div>
|
|
2
|
+
<BaseInput
|
|
3
|
+
ref="input"
|
|
4
|
+
:model-value="modelValue"
|
|
5
|
+
:type="showPassword ? 'text' : 'password'"
|
|
6
|
+
:disabled="disabled"
|
|
7
|
+
:placeholder="placeholder"
|
|
8
|
+
:size="size"
|
|
9
|
+
:icon-right="showPassword ? 'heroicons:eye-20-solid' : 'heroicons:eye-slash-20-solid'"
|
|
10
|
+
@icon-right-click="onIconRightClick"
|
|
11
|
+
@update:model-value="onUpdateModelValue"
|
|
12
|
+
@focus="onFocus"
|
|
13
|
+
@blur="onBlur"
|
|
14
|
+
/>
|
|
41
15
|
</template>
|
|
42
16
|
|
|
43
17
|
<script lang="ts" setup>
|
|
44
|
-
import { trim } from 'lodash';
|
|
45
|
-
import { Icon as BaseIcon } from '@iconify/vue';
|
|
46
18
|
import { PropType } from 'vue';
|
|
47
|
-
import {
|
|
19
|
+
import { Size } from '@/utils/sizes';
|
|
20
|
+
import BaseInput from './BaseInput.vue';
|
|
21
|
+
|
|
22
|
+
const emit = defineEmits(['update:modelValue', 'blur', 'focus']);
|
|
48
23
|
|
|
49
24
|
const props = defineProps({
|
|
50
25
|
modelValue: {
|
|
@@ -55,6 +30,10 @@ const props = defineProps({
|
|
|
55
30
|
default: false,
|
|
56
31
|
type: Boolean,
|
|
57
32
|
},
|
|
33
|
+
size: {
|
|
34
|
+
default: undefined,
|
|
35
|
+
type: String as PropType<Size>,
|
|
36
|
+
},
|
|
58
37
|
name: {
|
|
59
38
|
default: undefined,
|
|
60
39
|
type: String,
|
|
@@ -75,21 +54,10 @@ const props = defineProps({
|
|
|
75
54
|
|
|
76
55
|
const input = ref<HTMLInputElement | null>(null);
|
|
77
56
|
|
|
78
|
-
const emit = defineEmits(['update:modelValue']);
|
|
79
|
-
|
|
80
|
-
const { nameInternal, requiredInternal, hasErrorInternal, emitUpdate } =
|
|
81
|
-
useField({
|
|
82
|
-
name: computed(() => props.name),
|
|
83
|
-
required: computed(() => props.required),
|
|
84
|
-
hasError: computed(() => props.hasError),
|
|
85
|
-
emit: emit,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
57
|
const showPassword = ref(false);
|
|
89
58
|
|
|
90
|
-
function
|
|
91
|
-
|
|
92
|
-
emitUpdate(trim(value));
|
|
59
|
+
function onIconRightClick() {
|
|
60
|
+
showPassword.value = !showPassword.value;
|
|
93
61
|
}
|
|
94
62
|
|
|
95
63
|
function focus() {
|
|
@@ -100,6 +68,18 @@ function blur() {
|
|
|
100
68
|
input.value?.blur();
|
|
101
69
|
}
|
|
102
70
|
|
|
71
|
+
function onUpdateModelValue(value: string) {
|
|
72
|
+
emit('update:modelValue', value);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function onBlur() {
|
|
76
|
+
emit('blur');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function onFocus() {
|
|
80
|
+
emit('focus');
|
|
81
|
+
}
|
|
82
|
+
|
|
103
83
|
defineExpose({
|
|
104
84
|
focus,
|
|
105
85
|
blur,
|