spoko-design-system 1.1.0 → 1.1.2
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/.claude/settings.local.json +2 -1
- package/.github/workflows/code-quality.yml +3 -3
- package/.github/workflows/sonarcloud.yml +1 -1
- package/.prettierrc +1 -0
- package/CHANGELOG.md +12 -0
- package/package.json +8 -2
- package/src/MyComponent.astro +1 -1
- package/src/components/Badge.vue +2 -2
- package/src/components/Badges.vue +17 -7
- package/src/components/Breadcrumbs.vue +47 -39
- package/src/components/Button.vue +31 -30
- package/src/components/ButtonCopy.astro +12 -17
- package/src/components/ButtonCopy.vue +26 -25
- package/src/components/Card.astro +4 -6
- package/src/components/Carousel.astro +4 -4
- package/src/components/Category/CategoriesCarousel.astro +75 -75
- package/src/components/Category/CategoryDetails.astro +75 -79
- package/src/components/Category/CategoryLink.vue +8 -12
- package/src/components/Category/CategorySidebarToggler.vue +2 -7
- package/src/components/Category/CategoryTile.astro +3 -3
- package/src/components/Category/CategoryViewToggler.astro +18 -18
- package/src/components/Category/SubCategoryLink.vue +13 -13
- package/src/components/Faq.astro +16 -17
- package/src/components/FaqItem.astro +27 -27
- package/src/components/FeaturesList.vue +19 -29
- package/src/components/FuckRussia.vue +40 -27
- package/src/components/HandDrive.astro +11 -15
- package/src/components/Header/Header.astro +165 -166
- package/src/components/Header/SkipToContent.astro +1 -1
- package/src/components/Headline.vue +44 -27
- package/src/components/Image.astro +5 -7
- package/src/components/Input.vue +143 -153
- package/src/components/Jumbotron/index.astro +143 -156
- package/src/components/Jumbotron/types.ts +28 -29
- package/src/components/Jumbotron/variants/Default.astro +44 -40
- package/src/components/Jumbotron/variants/Hero.astro +45 -53
- package/src/components/Jumbotron/variants/Post.astro +68 -64
- package/src/components/Jumbotron/variants/PostSplit.astro +89 -81
- package/src/components/Jumbotron.astro +12 -12
- package/src/components/LanguageSuggestion.astro +66 -69
- package/src/components/LeftSidebar.astro +10 -10
- package/src/components/MainColors.vue +2 -2
- package/src/components/MainInput.vue +6 -3
- package/src/components/Modal.astro +2 -2
- package/src/components/PartNumber.vue +2 -3
- package/src/components/Post/PostCategories.astro +2 -4
- package/src/components/Post/PostCategories.vue +2 -2
- package/src/components/PostHeader.astro +4 -6
- package/src/components/PrCode.vue +20 -19
- package/src/components/Product/ProductButton.vue +2 -5
- package/src/components/Product/ProductCarousel.astro +38 -27
- package/src/components/Product/ProductColors.vue +46 -42
- package/src/components/Product/ProductDetailName.vue +22 -22
- package/src/components/Product/ProductDetails.vue +115 -99
- package/src/components/Product/ProductDoc.vue +27 -25
- package/src/components/Product/ProductEngineType.vue +13 -10
- package/src/components/Product/ProductImage.astro +18 -19
- package/src/components/Product/ProductLink.vue +55 -58
- package/src/components/Product/ProductLinkInfo.astro +15 -18
- package/src/components/Product/ProductModel.vue +25 -24
- package/src/components/Product/ProductModels.vue +29 -33
- package/src/components/Product/ProductName.vue +15 -15
- package/src/components/Product/ProductNumber.astro +23 -31
- package/src/components/Product/ProductPositions.vue +32 -34
- package/src/components/ProductCarousel.astro +5 -5
- package/src/components/ProductCodes.vue +12 -14
- package/src/components/ProductDetailName.vue +18 -20
- package/src/components/ProductDetailsList.vue +48 -27
- package/src/components/Quote.vue +8 -6
- package/src/components/ReloadPrompt.astro +39 -47
- package/src/components/SlimBanner.vue +44 -19
- package/src/components/Table.vue +4 -6
- package/src/components/Translations.vue +17 -8
- package/src/components/flags/FlagPL.vue +4 -3
- package/src/components/flags/FlagUA.vue +2 -2
- package/src/components/layout/CallToAction.astro +17 -12
- package/src/components/layout/Container.astro +3 -1
- package/src/components/layout/Header.astro +12 -21
- package/src/config.ts +43 -43
- package/src/design.config.ts +63 -63
- package/src/env.d.ts +4 -4
- package/src/layouts/Layout.astro +10 -19
- package/src/layouts/MainLayout.astro +13 -19
- package/src/layouts/partials/FooterCommon.astro +2 -2
- package/src/layouts/partials/HeadCommon.astro +9 -9
- package/src/layouts/partials/HeadSEO.astro +12 -5
- package/src/pages/components/icons.astro +130 -121
- package/src/pages/core/shadows.astro +18 -11
- package/src/pages/index.astro +178 -75
- package/src/pwa.ts +4 -4
- package/src/styles/base/base.css +14 -19
- package/src/styles/base/grid.css +54 -58
- package/src/styles/base/typography.css +40 -40
- package/src/styles/content.css +25 -23
- package/src/styles/main.css +5 -6
- package/src/types/Product.ts +31 -31
- package/src/types/astro.d.ts +1 -1
- package/src/types/index.ts +234 -237
- package/src/utils/api/getCategories.ts +9 -9
- package/src/utils/category/getMainCategoryList.ts +22 -22
- package/src/utils/category/getSortedCategories.ts +7 -11
- package/src/utils/product/getPriceFormatted.ts +14 -11
- package/src/utils/product/getProductChecklist.ts +10 -11
- package/src/utils/product/useFormatProductNumber.ts +18 -9
- package/src/utils/seo/getShorterDescription.ts +6 -4
- package/src/utils/text/formatDate.ts +2 -3
- package/src/utils/text/formatLocaleNumber.ts +2 -2
- package/src/utils/text/formatPad.ts +2 -2
- package/src/utils/text/getNumberFormatted.ts +10 -10
- package/src/utils/text/getTranslatedLink.ts +3 -3
- package/src/utils/text.ts +11 -8
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type { PropType } from 'vue'
|
|
2
|
+
import type { PropType } from 'vue';
|
|
3
3
|
|
|
4
4
|
const props = defineProps({
|
|
5
5
|
as: {
|
|
@@ -8,61 +8,78 @@ const props = defineProps({
|
|
|
8
8
|
required: true,
|
|
9
9
|
},
|
|
10
10
|
textSize: {
|
|
11
|
-
type: String as PropType<
|
|
11
|
+
type: String as PropType<
|
|
12
|
+
| 'xs'
|
|
13
|
+
| 'sm'
|
|
14
|
+
| 'base'
|
|
15
|
+
| 'lg'
|
|
16
|
+
| 'xl'
|
|
17
|
+
| '2xl'
|
|
18
|
+
| '3xl'
|
|
19
|
+
| '4xl'
|
|
20
|
+
| '5xl'
|
|
21
|
+
| '6xl'
|
|
22
|
+
| '7xl'
|
|
23
|
+
| '8xl'
|
|
24
|
+
| '9xl'
|
|
25
|
+
>,
|
|
12
26
|
required: false,
|
|
13
|
-
default: null
|
|
27
|
+
default: null,
|
|
14
28
|
},
|
|
15
29
|
fontFamily: {
|
|
16
30
|
type: String as PropType<'head' | 'text' | 'novamono' | 'mono'>,
|
|
17
31
|
required: false,
|
|
18
|
-
default: 'head'
|
|
32
|
+
default: 'head',
|
|
19
33
|
},
|
|
20
34
|
fontWeight: {
|
|
21
35
|
type: String as PropType<'light' | 'regular' | 'bold' | 'light-bold' | 'light-thin'>,
|
|
22
36
|
required: false,
|
|
23
|
-
default: 'regular'
|
|
37
|
+
default: 'regular',
|
|
24
38
|
},
|
|
25
39
|
underline: {
|
|
26
40
|
type: [Boolean, String] as PropType<boolean | 'center'>,
|
|
27
41
|
required: false,
|
|
28
|
-
default: false
|
|
29
|
-
}
|
|
30
|
-
})
|
|
42
|
+
default: false,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
31
45
|
|
|
32
46
|
// Generate the typography class based on font family and weight
|
|
33
47
|
const getTypographyClass = (): string => {
|
|
34
|
-
const family = props.fontFamily
|
|
35
|
-
const weight = props.fontWeight
|
|
36
|
-
|
|
48
|
+
const family = props.fontFamily;
|
|
49
|
+
const weight = props.fontWeight;
|
|
50
|
+
|
|
37
51
|
// Handle special cases for mono fonts
|
|
38
52
|
if (family === 'novamono' || family === 'mono') {
|
|
39
|
-
return `font-${family}
|
|
53
|
+
return `font-${family}`;
|
|
40
54
|
}
|
|
41
|
-
|
|
55
|
+
|
|
42
56
|
// For head family, generate specific classes
|
|
43
57
|
if (family === 'head') {
|
|
44
|
-
if (weight === 'light') return 'headline-light'
|
|
45
|
-
if (weight === 'bold') return 'headline-bold'
|
|
46
|
-
if (weight === 'light-bold') return 'headline-light-bold'
|
|
47
|
-
if (weight === 'light-thin') return 'headline-light-thin'
|
|
48
|
-
return 'headline' // for regular weight
|
|
58
|
+
if (weight === 'light') return 'headline-light';
|
|
59
|
+
if (weight === 'bold') return 'headline-bold';
|
|
60
|
+
if (weight === 'light-bold') return 'headline-light-bold';
|
|
61
|
+
if (weight === 'light-thin') return 'headline-light-thin';
|
|
62
|
+
return 'headline'; // for regular weight
|
|
49
63
|
}
|
|
50
|
-
|
|
64
|
+
|
|
51
65
|
// For text family, generate appropriate class
|
|
52
66
|
if (family === 'text') {
|
|
53
|
-
return `font-text${weight}
|
|
67
|
+
return `font-text${weight}`;
|
|
54
68
|
}
|
|
55
|
-
|
|
69
|
+
|
|
56
70
|
// Default fallback
|
|
57
|
-
return 'headline'
|
|
58
|
-
}
|
|
71
|
+
return 'headline';
|
|
72
|
+
};
|
|
59
73
|
|
|
60
|
-
const typographyClass = getTypographyClass()
|
|
74
|
+
const typographyClass = getTypographyClass();
|
|
61
75
|
</script>
|
|
62
76
|
|
|
63
77
|
<template>
|
|
64
|
-
<component
|
|
65
|
-
:
|
|
78
|
+
<component
|
|
79
|
+
:is="props.as"
|
|
80
|
+
class="mb-2.5 leading-none"
|
|
81
|
+
:class="`${typographyClass} ${props.textSize ? `text-${props.textSize}` : 'text-xl'} ${props.underline === true ? 'headline--underline' : ''} ${props.underline === 'center' ? 'headline--underline-center block text-center' : 'flex sm:block md:flex items-center'}`"
|
|
82
|
+
>
|
|
66
83
|
<slot />
|
|
67
84
|
</component>
|
|
68
85
|
</template>
|
|
@@ -105,4 +122,4 @@ const typographyClass = getTypographyClass()
|
|
|
105
122
|
left: calc(50% - min(47.5%, 127.5px));
|
|
106
123
|
}
|
|
107
124
|
}
|
|
108
|
-
</style>
|
|
125
|
+
</style>
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { Image } from
|
|
2
|
+
import { Image } from 'astro:assets';
|
|
3
3
|
|
|
4
4
|
const { imageObject } = Astro.props;
|
|
5
5
|
let inputProps = {};
|
|
6
6
|
|
|
7
7
|
if (imageObject.index && imageObject.index === 1) {
|
|
8
|
-
inputProps[
|
|
9
|
-
inputProps[
|
|
8
|
+
inputProps['data-pagefind-meta'] = 'image[src], image_alt[alt]';
|
|
9
|
+
inputProps['loading'] = 'eager';
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
if (imageObject.srcset && imageObject.srcset.length) {
|
|
13
|
-
inputProps[
|
|
13
|
+
inputProps['widths'] = imageObject.srcset;
|
|
14
14
|
}
|
|
15
15
|
---
|
|
16
16
|
|
|
@@ -23,8 +23,6 @@ if (imageObject.srcset && imageObject.srcset.length) {
|
|
|
23
23
|
format="avif"
|
|
24
24
|
data-pagefind-index-attrs="alt"
|
|
25
25
|
onerror="this.style.display='none';"
|
|
26
|
-
class={`h-full w-full select-none pointer-none ${
|
|
27
|
-
imageObject.class || "object-cover"
|
|
28
|
-
}`}
|
|
26
|
+
class={`h-full w-full select-none pointer-none ${imageObject.class || 'object-cover'}`}
|
|
29
27
|
{...inputProps}
|
|
30
28
|
/>
|
package/src/components/Input.vue
CHANGED
|
@@ -1,153 +1,143 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed, useAttrs } from 'vue';
|
|
3
|
-
|
|
4
|
-
interface InputProps {
|
|
5
|
-
id?: string;
|
|
6
|
-
name?: string;
|
|
7
|
-
label: string;
|
|
8
|
-
variant?: 'filled' | 'standard';
|
|
9
|
-
type?: string;
|
|
10
|
-
modelValue?: string | number;
|
|
11
|
-
required?: boolean;
|
|
12
|
-
rows?: number;
|
|
13
|
-
placeholder?: string;
|
|
14
|
-
error?: string | boolean;
|
|
15
|
-
success?: string | boolean;
|
|
16
|
-
size?: 'sm' | 'md' | 'lg';
|
|
17
|
-
class?: string;
|
|
18
|
-
[key: string]: any;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const props = withDefaults(defineProps<InputProps>(), {
|
|
22
|
-
id: () => `input-${Math.random().toString(36).substring(2, 9)}`,
|
|
23
|
-
name: undefined,
|
|
24
|
-
variant: 'standard',
|
|
25
|
-
type: 'text',
|
|
26
|
-
modelValue: '',
|
|
27
|
-
required: false,
|
|
28
|
-
rows: 3,
|
|
29
|
-
placeholder: ' ', // space for "floating label"
|
|
30
|
-
error: false,
|
|
31
|
-
success: false,
|
|
32
|
-
size: 'md',
|
|
33
|
-
class: ''
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
const emit = defineEmits(['update:modelValue', 'input', 'focus', 'blur']);
|
|
37
|
-
|
|
38
|
-
// Handle external attrs
|
|
39
|
-
const attrs = useAttrs();
|
|
40
|
-
|
|
41
|
-
// Compute wrapper class - uses existing shortcut
|
|
42
|
-
const wrapperClass = computed(() => `input-wrapper-${props.variant}`);
|
|
43
|
-
|
|
44
|
-
// Compute input classes - uses shortcuts
|
|
45
|
-
const inputClass = computed(() => {
|
|
46
|
-
const classes = ['input-base', 'input-placeholder', `input-${props.variant}`];
|
|
47
|
-
|
|
48
|
-
// Add size class
|
|
49
|
-
if (props.size) classes.push(`input-${props.size}`);
|
|
50
|
-
|
|
51
|
-
// Add textarea class if needed
|
|
52
|
-
if (props.type === 'textarea') classes.push('input-textarea');
|
|
53
|
-
|
|
54
|
-
// Add status classes
|
|
55
|
-
if (props.error) classes.push('input-error');
|
|
56
|
-
else if (props.success) classes.push('input-success');
|
|
57
|
-
|
|
58
|
-
// Add custom classes
|
|
59
|
-
if (props.class) classes.push(props.class);
|
|
60
|
-
|
|
61
|
-
return classes.join(' ');
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
// Compute label classes - using optimized shortcuts
|
|
65
|
-
const labelClass = computed(() => {
|
|
66
|
-
const classes = [
|
|
67
|
-
// Base label style
|
|
68
|
-
'input-label-base',
|
|
69
|
-
|
|
70
|
-
// Position styling
|
|
71
|
-
`input-label-${props.variant}`,
|
|
72
|
-
|
|
73
|
-
// State styling - contains all transformations for the specific variant
|
|
74
|
-
`input-label-${props.variant}-state
|
|
75
|
-
];
|
|
76
|
-
|
|
77
|
-
// Add size class
|
|
78
|
-
if (props.size) classes.push(`input-label-${props.size}`);
|
|
79
|
-
|
|
80
|
-
// Add status classes
|
|
81
|
-
if (props.error) classes.push('input-label-error');
|
|
82
|
-
else if (props.success) classes.push('input-label-success');
|
|
83
|
-
|
|
84
|
-
return classes.join(' ');
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// Event handlers
|
|
88
|
-
const handleInput = (event: Event) => {
|
|
89
|
-
const target = event.target as HTMLInputElement | HTMLTextAreaElement;
|
|
90
|
-
emit('update:modelValue', target.value);
|
|
91
|
-
emit('input', event);
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const handleFocus = (event: FocusEvent) => emit('focus', event);
|
|
95
|
-
const handleBlur = (event: FocusEvent) => emit('blur', event);
|
|
96
|
-
</script>
|
|
97
|
-
|
|
98
|
-
<template>
|
|
99
|
-
<div :class="wrapperClass">
|
|
100
|
-
<textarea
|
|
101
|
-
v-if="type === 'textarea'"
|
|
102
|
-
:id="id"
|
|
103
|
-
:name="name || id"
|
|
104
|
-
:rows="rows"
|
|
105
|
-
:required="required"
|
|
106
|
-
:class="inputClass + ' peer'"
|
|
107
|
-
:placeholder="placeholder"
|
|
108
|
-
:value="modelValue"
|
|
109
|
-
@input="handleInput"
|
|
110
|
-
@focus="handleFocus"
|
|
111
|
-
@blur="handleBlur"
|
|
112
|
-
v-bind="attrs"
|
|
113
|
-
></textarea>
|
|
114
|
-
|
|
115
|
-
<input
|
|
116
|
-
v-else
|
|
117
|
-
:type="type"
|
|
118
|
-
:id="id"
|
|
119
|
-
:name="name || id"
|
|
120
|
-
:required="required"
|
|
121
|
-
:class="inputClass + ' peer'"
|
|
122
|
-
:placeholder="placeholder"
|
|
123
|
-
:value="modelValue"
|
|
124
|
-
@input="handleInput"
|
|
125
|
-
@focus="handleFocus"
|
|
126
|
-
@blur="handleBlur"
|
|
127
|
-
v-bind="attrs"
|
|
128
|
-
/>
|
|
129
|
-
|
|
130
|
-
<label
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
</
|
|
138
|
-
|
|
139
|
-
<div
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
</div>
|
|
145
|
-
|
|
146
|
-
<div
|
|
147
|
-
v-if="success && typeof success === 'string'"
|
|
148
|
-
class="input-success-message"
|
|
149
|
-
>
|
|
150
|
-
{{ success }}
|
|
151
|
-
</div>
|
|
152
|
-
</div>
|
|
153
|
-
</template>
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, useAttrs } from 'vue';
|
|
3
|
+
|
|
4
|
+
interface InputProps {
|
|
5
|
+
id?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
label: string;
|
|
8
|
+
variant?: 'filled' | 'standard';
|
|
9
|
+
type?: string;
|
|
10
|
+
modelValue?: string | number;
|
|
11
|
+
required?: boolean;
|
|
12
|
+
rows?: number;
|
|
13
|
+
placeholder?: string;
|
|
14
|
+
error?: string | boolean;
|
|
15
|
+
success?: string | boolean;
|
|
16
|
+
size?: 'sm' | 'md' | 'lg';
|
|
17
|
+
class?: string;
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const props = withDefaults(defineProps<InputProps>(), {
|
|
22
|
+
id: () => `input-${Math.random().toString(36).substring(2, 9)}`,
|
|
23
|
+
name: undefined,
|
|
24
|
+
variant: 'standard',
|
|
25
|
+
type: 'text',
|
|
26
|
+
modelValue: '',
|
|
27
|
+
required: false,
|
|
28
|
+
rows: 3,
|
|
29
|
+
placeholder: ' ', // space for "floating label"
|
|
30
|
+
error: false,
|
|
31
|
+
success: false,
|
|
32
|
+
size: 'md',
|
|
33
|
+
class: '',
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const emit = defineEmits(['update:modelValue', 'input', 'focus', 'blur']);
|
|
37
|
+
|
|
38
|
+
// Handle external attrs
|
|
39
|
+
const attrs = useAttrs();
|
|
40
|
+
|
|
41
|
+
// Compute wrapper class - uses existing shortcut
|
|
42
|
+
const wrapperClass = computed(() => `input-wrapper-${props.variant}`);
|
|
43
|
+
|
|
44
|
+
// Compute input classes - uses shortcuts
|
|
45
|
+
const inputClass = computed(() => {
|
|
46
|
+
const classes = ['input-base', 'input-placeholder', `input-${props.variant}`];
|
|
47
|
+
|
|
48
|
+
// Add size class
|
|
49
|
+
if (props.size) classes.push(`input-${props.size}`);
|
|
50
|
+
|
|
51
|
+
// Add textarea class if needed
|
|
52
|
+
if (props.type === 'textarea') classes.push('input-textarea');
|
|
53
|
+
|
|
54
|
+
// Add status classes
|
|
55
|
+
if (props.error) classes.push('input-error');
|
|
56
|
+
else if (props.success) classes.push('input-success');
|
|
57
|
+
|
|
58
|
+
// Add custom classes
|
|
59
|
+
if (props.class) classes.push(props.class);
|
|
60
|
+
|
|
61
|
+
return classes.join(' ');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Compute label classes - using optimized shortcuts
|
|
65
|
+
const labelClass = computed(() => {
|
|
66
|
+
const classes = [
|
|
67
|
+
// Base label style
|
|
68
|
+
'input-label-base',
|
|
69
|
+
|
|
70
|
+
// Position styling
|
|
71
|
+
`input-label-${props.variant}`,
|
|
72
|
+
|
|
73
|
+
// State styling - contains all transformations for the specific variant
|
|
74
|
+
`input-label-${props.variant}-state`,
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
// Add size class
|
|
78
|
+
if (props.size) classes.push(`input-label-${props.size}`);
|
|
79
|
+
|
|
80
|
+
// Add status classes
|
|
81
|
+
if (props.error) classes.push('input-label-error');
|
|
82
|
+
else if (props.success) classes.push('input-label-success');
|
|
83
|
+
|
|
84
|
+
return classes.join(' ');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Event handlers
|
|
88
|
+
const handleInput = (event: Event) => {
|
|
89
|
+
const target = event.target as HTMLInputElement | HTMLTextAreaElement;
|
|
90
|
+
emit('update:modelValue', target.value);
|
|
91
|
+
emit('input', event);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const handleFocus = (event: FocusEvent) => emit('focus', event);
|
|
95
|
+
const handleBlur = (event: FocusEvent) => emit('blur', event);
|
|
96
|
+
</script>
|
|
97
|
+
|
|
98
|
+
<template>
|
|
99
|
+
<div :class="wrapperClass">
|
|
100
|
+
<textarea
|
|
101
|
+
v-if="type === 'textarea'"
|
|
102
|
+
:id="id"
|
|
103
|
+
:name="name || id"
|
|
104
|
+
:rows="rows"
|
|
105
|
+
:required="required"
|
|
106
|
+
:class="inputClass + ' peer'"
|
|
107
|
+
:placeholder="placeholder"
|
|
108
|
+
:value="modelValue"
|
|
109
|
+
@input="handleInput"
|
|
110
|
+
@focus="handleFocus"
|
|
111
|
+
@blur="handleBlur"
|
|
112
|
+
v-bind="attrs"
|
|
113
|
+
></textarea>
|
|
114
|
+
|
|
115
|
+
<input
|
|
116
|
+
v-else
|
|
117
|
+
:type="type"
|
|
118
|
+
:id="id"
|
|
119
|
+
:name="name || id"
|
|
120
|
+
:required="required"
|
|
121
|
+
:class="inputClass + ' peer'"
|
|
122
|
+
:placeholder="placeholder"
|
|
123
|
+
:value="modelValue"
|
|
124
|
+
@input="handleInput"
|
|
125
|
+
@focus="handleFocus"
|
|
126
|
+
@blur="handleBlur"
|
|
127
|
+
v-bind="attrs"
|
|
128
|
+
/>
|
|
129
|
+
|
|
130
|
+
<label :for="id" :class="labelClass" style="transform-origin: top left">
|
|
131
|
+
{{ label }}
|
|
132
|
+
<span v-if="required" class="text-red-500 ml-1">*</span>
|
|
133
|
+
</label>
|
|
134
|
+
|
|
135
|
+
<div v-if="error && typeof error === 'string'" class="input-error-message">
|
|
136
|
+
{{ error }}
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
<div v-if="success && typeof success === 'string'" class="input-success-message">
|
|
140
|
+
{{ success }}
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
</template>
|