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
|
@@ -78,6 +78,23 @@ Disabled.args = {
|
|
|
78
78
|
disabled: true,
|
|
79
79
|
};
|
|
80
80
|
|
|
81
|
+
const TemplateSizes = (args) => ({
|
|
82
|
+
components: { BaseSelect },
|
|
83
|
+
setup() {
|
|
84
|
+
const value = ref(null);
|
|
85
|
+
const sizes = ['xs', 'sm', 'md'];
|
|
86
|
+
return { args, value, sizes, options };
|
|
87
|
+
},
|
|
88
|
+
template: `
|
|
89
|
+
<div v-for="size in sizes" :key="size" class="mb-4">
|
|
90
|
+
<p class="text-xs text-slate-600 leading-tight mb-1">btn {{ size }}</p>
|
|
91
|
+
<BaseSelect v-model="value" v-bind="args" :options="options" label-key="label" value-key="value" :size="size" class="w-full"></BaseSelect>
|
|
92
|
+
</div>
|
|
93
|
+
`,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
export const Sizes = TemplateSizes.bind({});
|
|
97
|
+
|
|
81
98
|
export const OptionsAsProps = (args) => ({
|
|
82
99
|
components: { BaseSelect, ShowValue },
|
|
83
100
|
setup() {
|
|
@@ -106,6 +123,23 @@ OptionsAsProps.args = {
|
|
|
106
123
|
valueKey: 'label',
|
|
107
124
|
};
|
|
108
125
|
|
|
126
|
+
const CustomClassesT = (args) => ({
|
|
127
|
+
components: { BaseSelect },
|
|
128
|
+
setup() {
|
|
129
|
+
const value = ref(null);
|
|
130
|
+
return { args, value };
|
|
131
|
+
},
|
|
132
|
+
template: `
|
|
133
|
+
<BaseSelect
|
|
134
|
+
v-model="value"
|
|
135
|
+
v-bind="args"
|
|
136
|
+
class="w-full bg-green-100 text-green-700 border-green-700 focus-within:border-red-500 focus-within:ring-red-800 placeholder:text-green-400 shadow-xl"
|
|
137
|
+
></BaseSelect>
|
|
138
|
+
`,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
export const CustomClasses = CustomClassesT.bind({});
|
|
142
|
+
|
|
109
143
|
export const Field = createFieldStory({
|
|
110
144
|
component: BaseSelect,
|
|
111
145
|
componentName: 'BaseSelect',
|
|
@@ -5,11 +5,7 @@
|
|
|
5
5
|
:name="nameInternal"
|
|
6
6
|
:disabled="disabled"
|
|
7
7
|
:required="requiredInternal"
|
|
8
|
-
class="
|
|
9
|
-
:class="[
|
|
10
|
-
!modelValue && requiredInternal ? 'text-slate-400' : '',
|
|
11
|
-
hasErrorInternal ? 'border-red-600' : 'border-slate-300',
|
|
12
|
-
]"
|
|
8
|
+
:class="classes"
|
|
13
9
|
@change="onChange($event)"
|
|
14
10
|
>
|
|
15
11
|
<template v-if="requiredInternal">
|
|
@@ -43,17 +39,22 @@
|
|
|
43
39
|
|
|
44
40
|
<script lang="ts" setup>
|
|
45
41
|
import { PropType } from 'vue';
|
|
46
|
-
import { get, isArray
|
|
47
|
-
import { useMutationObserver } from '@vueuse/core';
|
|
42
|
+
import { get, isArray } from 'lodash';
|
|
48
43
|
import { useField } from '@/composables/field';
|
|
49
44
|
import { NormalizedOption, OptionValue, Option } from '@/types';
|
|
50
45
|
import { t } from '@/i18n';
|
|
46
|
+
import { twMerge } from 'tailwind-merge';
|
|
47
|
+
import { Size, sizes } from '@/utils/sizes';
|
|
51
48
|
|
|
52
49
|
type SelectOption = string | number | null;
|
|
53
50
|
|
|
54
51
|
const EMPTY_VALUE_INTERNAL = '';
|
|
55
52
|
const EMPTY_VALUE_EXTERNAL = null;
|
|
56
53
|
|
|
54
|
+
defineOptions({
|
|
55
|
+
inheritAttrs: false,
|
|
56
|
+
});
|
|
57
|
+
|
|
57
58
|
const props = defineProps({
|
|
58
59
|
modelValue: {
|
|
59
60
|
default: undefined,
|
|
@@ -63,6 +64,14 @@ const props = defineProps({
|
|
|
63
64
|
default: undefined,
|
|
64
65
|
type: String,
|
|
65
66
|
},
|
|
67
|
+
class: {
|
|
68
|
+
default: '',
|
|
69
|
+
type: [String, Array] as PropType<string | string[]>,
|
|
70
|
+
},
|
|
71
|
+
size: {
|
|
72
|
+
default: undefined,
|
|
73
|
+
type: String as PropType<Size>,
|
|
74
|
+
},
|
|
66
75
|
placeholder: {
|
|
67
76
|
default: '',
|
|
68
77
|
type: String,
|
|
@@ -91,16 +100,21 @@ const props = defineProps({
|
|
|
91
100
|
default: undefined,
|
|
92
101
|
type: String,
|
|
93
102
|
},
|
|
103
|
+
visibleFocus: {
|
|
104
|
+
default: true,
|
|
105
|
+
type: Boolean,
|
|
106
|
+
},
|
|
94
107
|
});
|
|
95
108
|
|
|
96
109
|
const select = ref<HTMLSelectElement | null>(null);
|
|
97
110
|
|
|
98
111
|
const emit = defineEmits(['update:modelValue']);
|
|
99
112
|
|
|
100
|
-
const { nameInternal, requiredInternal, hasErrorInternal, emitUpdate } =
|
|
113
|
+
const { nameInternal, requiredInternal, hasErrorInternal, emitUpdate, sizeInternal } =
|
|
101
114
|
useField({
|
|
102
115
|
name: computed(() => props.name),
|
|
103
116
|
required: computed(() => props.required),
|
|
117
|
+
size: computed(() => props.size),
|
|
104
118
|
hasError: computed(() => props.hasError),
|
|
105
119
|
emit: emit,
|
|
106
120
|
});
|
|
@@ -182,4 +196,39 @@ const normalizedOptions = computed<NormalizedOption[] | undefined>(() => {
|
|
|
182
196
|
} as NormalizedOption;
|
|
183
197
|
});
|
|
184
198
|
});
|
|
199
|
+
|
|
200
|
+
const classes = computed(() => {
|
|
201
|
+
const base = 'input-rounded border transition-colors duration-200 py-0';
|
|
202
|
+
|
|
203
|
+
let focusClass = '';
|
|
204
|
+
if (props.visibleFocus) {
|
|
205
|
+
if (hasErrorInternal.value) {
|
|
206
|
+
focusClass = 'focus-within:input-focus-error';
|
|
207
|
+
} else {
|
|
208
|
+
focusClass = 'focus-within:input-focus';
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const disabled = 'disabled:cursor-not-allowed disabled:text-slate-300 disabled:opacity-100';
|
|
213
|
+
const error = hasErrorInternal.value ? 'border-red-600' : 'border-slate-300';
|
|
214
|
+
const textColor = !props.modelValue && requiredInternal ? 'text-slate-400' : '';
|
|
215
|
+
const sizeConfig = sizes[sizeInternal.value];
|
|
216
|
+
const padding = {
|
|
217
|
+
xs: 'pl-2 pr-7',
|
|
218
|
+
sm: 'pl-2.5 pr-8',
|
|
219
|
+
md: 'pl-3 pr-10',
|
|
220
|
+
}[sizeInternal.value];
|
|
221
|
+
|
|
222
|
+
return twMerge([
|
|
223
|
+
base,
|
|
224
|
+
focusClass,
|
|
225
|
+
disabled,
|
|
226
|
+
error,
|
|
227
|
+
textColor,
|
|
228
|
+
sizeConfig.height,
|
|
229
|
+
sizeConfig.fontSize,
|
|
230
|
+
padding,
|
|
231
|
+
props.class,
|
|
232
|
+
]);
|
|
233
|
+
});
|
|
185
234
|
</script>
|
|
@@ -116,6 +116,7 @@ import { useNotificationsStore } from '@/stores/notifications';
|
|
|
116
116
|
import BaseAutocompleteDrawer from './BaseAutocompleteDrawer.vue';
|
|
117
117
|
import { twMerge } from 'tailwind-merge';
|
|
118
118
|
import { t } from '@/i18n';
|
|
119
|
+
import { Size } from '@/utils/sizes';
|
|
119
120
|
|
|
120
121
|
const notifications = useNotificationsStore();
|
|
121
122
|
|
|
@@ -177,8 +178,8 @@ const props = defineProps({
|
|
|
177
178
|
type: Boolean,
|
|
178
179
|
},
|
|
179
180
|
size: {
|
|
180
|
-
default: '
|
|
181
|
-
type: String as PropType<
|
|
181
|
+
default: 'md',
|
|
182
|
+
type: String as PropType<Size>,
|
|
182
183
|
},
|
|
183
184
|
dropdownShow: {
|
|
184
185
|
default: 'focus',
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { createFieldStory } from '../../.storybook/utils';
|
|
2
2
|
import BaseTextarea from './BaseTextarea.vue';
|
|
3
3
|
|
|
4
|
+
const sizes = ['xs', 'sm', 'md'];
|
|
5
|
+
|
|
4
6
|
export default {
|
|
5
7
|
title: 'Form/BaseTextarea',
|
|
6
8
|
component: BaseTextarea,
|
|
7
9
|
args: {
|
|
8
10
|
placeholder: 'Describe your complete life in 4 sentences...',
|
|
9
11
|
},
|
|
12
|
+
argTypes: {
|
|
13
|
+
size: {
|
|
14
|
+
control: { type: 'select' },
|
|
15
|
+
options: sizes,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
10
18
|
};
|
|
11
19
|
|
|
12
20
|
const Template = (args) => ({
|
|
@@ -42,6 +50,23 @@ export const Field = createFieldStory({
|
|
|
42
50
|
label: 'Biography',
|
|
43
51
|
});
|
|
44
52
|
|
|
53
|
+
const TemplateSizes = (args) => ({
|
|
54
|
+
components: { BaseTextarea },
|
|
55
|
+
setup() {
|
|
56
|
+
const value = ref(null);
|
|
57
|
+
const sizes = ['xs', 'sm', 'md'];
|
|
58
|
+
return { args, value, sizes };
|
|
59
|
+
},
|
|
60
|
+
template: `
|
|
61
|
+
<div v-for="size in sizes" :key="size" class="mb-4">
|
|
62
|
+
<p class="text-xs text-slate-600 leading-tight mb-1">{{ size }}</p>
|
|
63
|
+
<BaseTextarea v-model="value" v-bind="args" :size="size" class="w-full"></BaseTextarea>
|
|
64
|
+
</div>
|
|
65
|
+
`,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export const Sizes = TemplateSizes.bind({});
|
|
69
|
+
|
|
45
70
|
const FocusTemplate = (args) => ({
|
|
46
71
|
components: { BaseTextarea },
|
|
47
72
|
setup() {
|
|
@@ -8,17 +8,23 @@
|
|
|
8
8
|
:disabled="disabled"
|
|
9
9
|
:required="requiredInternal"
|
|
10
10
|
:rows="rows"
|
|
11
|
-
:
|
|
12
|
-
class="
|
|
11
|
+
:autocomplete="autocomplete ? 'on' : 'off'"
|
|
12
|
+
:class="classes"
|
|
13
13
|
@input="emitUpdate(transformInputValue($event))"
|
|
14
14
|
/>
|
|
15
15
|
</template>
|
|
16
16
|
|
|
17
17
|
<script lang="ts" setup>
|
|
18
18
|
import { useField } from '@/composables/field';
|
|
19
|
+
import { Size, sizes } from '@/utils/sizes';
|
|
19
20
|
import { get, isString } from 'lodash';
|
|
21
|
+
import { twMerge } from 'tailwind-merge';
|
|
20
22
|
import { PropType } from 'vue';
|
|
21
23
|
|
|
24
|
+
defineOptions({
|
|
25
|
+
inheritAttrs: false,
|
|
26
|
+
});
|
|
27
|
+
|
|
22
28
|
const props = defineProps({
|
|
23
29
|
modelValue: {
|
|
24
30
|
default: undefined,
|
|
@@ -28,6 +34,14 @@ const props = defineProps({
|
|
|
28
34
|
type: String,
|
|
29
35
|
default: 'text',
|
|
30
36
|
},
|
|
37
|
+
size: {
|
|
38
|
+
default: undefined,
|
|
39
|
+
type: String as PropType<Size>,
|
|
40
|
+
},
|
|
41
|
+
class: {
|
|
42
|
+
default: '',
|
|
43
|
+
type: [String, Array] as PropType<string | string[]>,
|
|
44
|
+
},
|
|
31
45
|
autocomplete: {
|
|
32
46
|
default: true,
|
|
33
47
|
type: Boolean,
|
|
@@ -64,10 +78,11 @@ const props = defineProps({
|
|
|
64
78
|
|
|
65
79
|
const emit = defineEmits(['update:modelValue']);
|
|
66
80
|
|
|
67
|
-
const { nameInternal, requiredInternal, hasErrorInternal, emitUpdate } =
|
|
81
|
+
const { nameInternal, requiredInternal, hasErrorInternal, emitUpdate, sizeInternal } =
|
|
68
82
|
useField({
|
|
69
83
|
name: computed(() => props.name),
|
|
70
84
|
required: computed(() => props.required),
|
|
85
|
+
size: computed(() => props.size),
|
|
71
86
|
hasError: computed(() => props.hasError),
|
|
72
87
|
emit: emit,
|
|
73
88
|
});
|
|
@@ -96,6 +111,22 @@ function blur() {
|
|
|
96
111
|
textareaRef.value?.blur();
|
|
97
112
|
}
|
|
98
113
|
|
|
114
|
+
const classes = computed(() => {
|
|
115
|
+
const base = 'mb-0 block input-rounded transition-colors duration-200';
|
|
116
|
+
const disabled = 'disabled:cursor-not-allowed disabled:text-slate-300';
|
|
117
|
+
const focus = 'focus:input-focus';
|
|
118
|
+
const error = hasErrorInternal.value ? 'border-red-500 focus:input-focus-error' : 'border-slate-300';
|
|
119
|
+
const sizeConfig = sizes[sizeInternal.value];
|
|
120
|
+
|
|
121
|
+
const padding = {
|
|
122
|
+
xs: 'p-2',
|
|
123
|
+
sm: 'p-2.5',
|
|
124
|
+
md: 'p-3',
|
|
125
|
+
}[sizeInternal.value];
|
|
126
|
+
|
|
127
|
+
return twMerge(base, disabled, error, focus, sizeConfig.fontSize, padding, props.class);
|
|
128
|
+
});
|
|
129
|
+
|
|
99
130
|
defineExpose({
|
|
100
131
|
focus,
|
|
101
132
|
blur,
|
|
@@ -2,6 +2,8 @@ import BaseTextareaAutoresize from './BaseTextareaAutoresize.vue';
|
|
|
2
2
|
import ShowValue from '@/../.storybook/components/ShowValue.vue';
|
|
3
3
|
import { createFieldStory } from '../../.storybook/utils';
|
|
4
4
|
|
|
5
|
+
const sizes = ['xs', 'sm', 'md'];
|
|
6
|
+
|
|
5
7
|
export default {
|
|
6
8
|
title: 'Form/BaseTextareaAutoresize',
|
|
7
9
|
component: BaseTextareaAutoresize,
|
|
@@ -9,6 +11,12 @@ export default {
|
|
|
9
11
|
name: 'name',
|
|
10
12
|
placeholder: 'Describe your complete life in 4 sentences...',
|
|
11
13
|
},
|
|
14
|
+
argTypes: {
|
|
15
|
+
size: {
|
|
16
|
+
control: { type: 'select' },
|
|
17
|
+
options: sizes,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
12
20
|
};
|
|
13
21
|
|
|
14
22
|
const Template = (args) => ({
|
|
@@ -68,8 +76,8 @@ const TemplateTWTextarea = (args) => ({
|
|
|
68
76
|
<BaseTextareaAutoresize
|
|
69
77
|
v-model="value"
|
|
70
78
|
v-bind="args"
|
|
71
|
-
class="w-full
|
|
72
|
-
tw-textarea="p-5 bg-slate-100 text-slate-700 focus:ring-
|
|
79
|
+
class="w-full"
|
|
80
|
+
tw-textarea="shadow-xl rounded-none p-5 duration-500 transition-all bg-slate-100 text-slate-900 ring-2 ring-purple-700 border-none ring-opacity-60 focus:ring-pink-500 focus:ring-4 focus:bg-pink-100"
|
|
73
81
|
@submit="onSubmit"
|
|
74
82
|
></BaseTextareaAutoresize>
|
|
75
83
|
</form>
|
|
@@ -86,6 +94,23 @@ export const Field = createFieldStory({
|
|
|
86
94
|
label: 'Biography',
|
|
87
95
|
});
|
|
88
96
|
|
|
97
|
+
const TemplateSizes = (args) => ({
|
|
98
|
+
components: { BaseTextareaAutoresize },
|
|
99
|
+
setup() {
|
|
100
|
+
const value = ref(null);
|
|
101
|
+
const sizes = ['xs', 'sm', 'md'];
|
|
102
|
+
return { args, value, sizes };
|
|
103
|
+
},
|
|
104
|
+
template: `
|
|
105
|
+
<div v-for="size in sizes" :key="size" class="mb-4">
|
|
106
|
+
<p class="text-xs text-slate-600 leading-tight mb-1">{{ size }}</p>
|
|
107
|
+
<BaseTextareaAutoresize v-model="value" v-bind="args" :size="size" class="w-full"></BaseTextareaAutoresize>
|
|
108
|
+
</div>
|
|
109
|
+
`,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
export const Sizes = TemplateSizes.bind({});
|
|
113
|
+
|
|
89
114
|
const FocusTemplate = (args) => ({
|
|
90
115
|
components: { BaseTextareaAutoresize },
|
|
91
116
|
setup() {
|
|
@@ -36,12 +36,10 @@
|
|
|
36
36
|
|
|
37
37
|
<script lang="ts" setup>
|
|
38
38
|
import { useField } from '@/composables/field';
|
|
39
|
+
import { sizes, Size } from '@/utils/sizes';
|
|
39
40
|
import { twMerge } from 'tailwind-merge';
|
|
40
41
|
import { PropType } from 'vue';
|
|
41
42
|
|
|
42
|
-
const BASE_TEXTAREA_CLASSES =
|
|
43
|
-
'py-2 px-3 font-normal text-base disabled:cursor-not-allowed disabled:text-slate-300 font-sans rounded leading-normal tracking-normal border placeholder:text-slate-400 placeholder:font-light';
|
|
44
|
-
|
|
45
43
|
const BASE_GRID_AREA = '1 / 1 / 2 / 2';
|
|
46
44
|
|
|
47
45
|
/* Note the weird space! Needed to prevent jumpy behavior */
|
|
@@ -64,6 +62,10 @@ const props = defineProps({
|
|
|
64
62
|
default: false,
|
|
65
63
|
type: Boolean,
|
|
66
64
|
},
|
|
65
|
+
size: {
|
|
66
|
+
default: undefined,
|
|
67
|
+
type: String as PropType<Size>,
|
|
68
|
+
},
|
|
67
69
|
maxHeight: {
|
|
68
70
|
default: 100,
|
|
69
71
|
type: Number,
|
|
@@ -98,10 +100,11 @@ const emit = defineEmits(['update:modelValue', 'submit', 'focus', 'input']);
|
|
|
98
100
|
|
|
99
101
|
const textareaRef = ref<null | HTMLTextAreaElement>(null);
|
|
100
102
|
|
|
101
|
-
const { nameInternal, requiredInternal, hasErrorInternal } =
|
|
103
|
+
const { nameInternal, requiredInternal, hasErrorInternal, sizeInternal } =
|
|
102
104
|
useField({
|
|
103
105
|
name: computed(() => props.name),
|
|
104
106
|
required: computed(() => props.required),
|
|
107
|
+
size: computed(() => props.size),
|
|
105
108
|
hasError: computed(() => props.hasError),
|
|
106
109
|
emit: emit,
|
|
107
110
|
});
|
|
@@ -142,11 +145,27 @@ function onFocus(event: FocusEvent) {
|
|
|
142
145
|
}
|
|
143
146
|
|
|
144
147
|
const textareaClasses = computed(() => {
|
|
148
|
+
const base = 'py-2 px-3 input-rounded leading-normal tracking-normal border transition-colors duration-200';
|
|
149
|
+
const disabled = 'disabled:cursor-not-allowed disabled:text-slate-300';
|
|
150
|
+
const focus = 'focus:input-focus';
|
|
151
|
+
const error = hasErrorInternal.value ? 'border-red-500 focus:input-focus-error' : 'border-slate-300';
|
|
152
|
+
const placeholder = 'placeholder:text-slate-400 placeholder:font-light';
|
|
153
|
+
const sizeConfig = sizes[sizeInternal.value];
|
|
154
|
+
|
|
155
|
+
const padding = {
|
|
156
|
+
xs: 'px-2',
|
|
157
|
+
sm: 'px-2.5',
|
|
158
|
+
md: 'px-3',
|
|
159
|
+
}[sizeInternal.value];
|
|
160
|
+
|
|
145
161
|
return twMerge(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
162
|
+
base,
|
|
163
|
+
disabled,
|
|
164
|
+
error,
|
|
165
|
+
placeholder,
|
|
166
|
+
focus,
|
|
167
|
+
sizeConfig.fontSize,
|
|
168
|
+
padding,
|
|
150
169
|
props.twTextarea
|
|
151
170
|
);
|
|
152
171
|
});
|
|
@@ -68,9 +68,7 @@ WithDescription.args = {
|
|
|
68
68
|
item: {
|
|
69
69
|
title: 'Advanced to phone screening by Bethany Blake',
|
|
70
70
|
icon: 'heroicons:shield-check-20-solid',
|
|
71
|
-
description:
|
|
72
|
-
'Lorem nostrud quis aute elit ea Lorem magna eiusmod ipsum. Eu ipsum eiusmod ad minim adipisicing irure. Fugiat ut adipisicing consequat dolor.',
|
|
73
|
-
color: 'primary',
|
|
71
|
+
description: 'Lorem nostrud quis aute elit ea Lorem magna eiusmod ipsum. Eu ipsum eiusmod ad minim adipisicing irure. Fugiat ut adipisicing consequat dolor.',
|
|
74
72
|
date: '15 Jan',
|
|
75
73
|
},
|
|
76
74
|
};
|
package/src/composables/field.ts
CHANGED
|
@@ -1,21 +1,26 @@
|
|
|
1
|
+
import { Size } from '@/utils/sizes';
|
|
1
2
|
import { uniqueId } from 'lodash';
|
|
2
3
|
import { Ref } from 'vue';
|
|
4
|
+
import { useInputSize } from './inputSize';
|
|
3
5
|
|
|
4
6
|
interface Config {
|
|
5
7
|
name: Ref<string | null | undefined>;
|
|
6
8
|
required: Ref<boolean>;
|
|
7
9
|
hasError: Ref<boolean | undefined>;
|
|
8
10
|
emit: any;
|
|
11
|
+
size?: Ref<Size | undefined>;
|
|
9
12
|
errorType?: string;
|
|
10
13
|
labelClass?: string;
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
export function useField(config: Config) {
|
|
17
|
+
|
|
14
18
|
const uuid = uniqueId();
|
|
15
19
|
const name = config.name;
|
|
16
20
|
const required = config.required;
|
|
17
21
|
const hasError = config.hasError;
|
|
18
22
|
const emit = config.emit;
|
|
23
|
+
const size = config.size;
|
|
19
24
|
const errorType = config.errorType ?? null;
|
|
20
25
|
const labelClass = config.labelClass ?? null;
|
|
21
26
|
|
|
@@ -23,6 +28,7 @@ export function useField(config: Config) {
|
|
|
23
28
|
|
|
24
29
|
const fieldRequired = inject('field:required', ref(false)) as Ref<boolean>;
|
|
25
30
|
const fieldName = inject('field:name', ref('')) as Ref<string>;
|
|
31
|
+
const fieldSize = inject('field:size', ref('md')) as Ref<Size>;
|
|
26
32
|
|
|
27
33
|
const fieldOnUpdate = inject('field:onUpdate', () => {
|
|
28
34
|
return;
|
|
@@ -88,6 +94,19 @@ export function useField(config: Config) {
|
|
|
88
94
|
return fieldName.value;
|
|
89
95
|
});
|
|
90
96
|
|
|
97
|
+
const sizeInternal = computed((): Size => {
|
|
98
|
+
|
|
99
|
+
let s = size?.value ?? null;
|
|
100
|
+
|
|
101
|
+
if (!s) {
|
|
102
|
+
s = fieldSize.value;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const inputSize = useInputSize(s);
|
|
106
|
+
|
|
107
|
+
return inputSize.size.value;
|
|
108
|
+
});
|
|
109
|
+
|
|
91
110
|
const errorMessageInternal = computed((): string | null | undefined => {
|
|
92
111
|
return getErrorMessageByName(nameInternal.value);
|
|
93
112
|
});
|
|
@@ -110,6 +129,7 @@ export function useField(config: Config) {
|
|
|
110
129
|
nameInternal,
|
|
111
130
|
hasErrorInternal,
|
|
112
131
|
errorMessageInternal,
|
|
132
|
+
sizeInternal,
|
|
113
133
|
emitUpdate,
|
|
114
134
|
enableForm: () => enableForm(uuid),
|
|
115
135
|
disableForm: () => disableForm(uuid),
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useBreakpoints } from "./breakpoints";
|
|
2
|
+
import { Size } from "@/utils/sizes";
|
|
3
|
+
import { MaybeRef } from "vue";
|
|
4
|
+
|
|
5
|
+
function useInputSize(size: MaybeRef<Size | '' | undefined | null>) {
|
|
6
|
+
|
|
7
|
+
const bp = useBreakpoints();
|
|
8
|
+
|
|
9
|
+
const sizeInternal = computed(() => {
|
|
10
|
+
|
|
11
|
+
if (bp.smaller('sm').value) {
|
|
12
|
+
return 'md';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let s = unref(size);
|
|
16
|
+
|
|
17
|
+
if (!s) {
|
|
18
|
+
s = 'md';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return s;
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
size: sizeInternal,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export { useInputSize };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const sizes = {
|
|
2
|
+
xs: {
|
|
3
|
+
fontSize: 'text-xs',
|
|
4
|
+
height: 'h-control-xs',
|
|
5
|
+
iconSize: 'h-[0.9rem] w-[0.9rem]'
|
|
6
|
+
},
|
|
7
|
+
sm: {
|
|
8
|
+
fontSize: 'text-sm',
|
|
9
|
+
height: 'h-control-sm',
|
|
10
|
+
iconSize: 'h-[1.125rem] w-[1.125rem]'
|
|
11
|
+
},
|
|
12
|
+
md: {
|
|
13
|
+
fontSize: 'text-base',
|
|
14
|
+
height: 'h-control-md',
|
|
15
|
+
iconSize: 'h-5 w-5'
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
type Size = keyof typeof sizes;
|
|
20
|
+
|
|
21
|
+
export { sizes, Size }
|