spoko-design-system 0.5.6 → 0.5.8
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/.astro/data-store.json +1 -1
- package/package.json +11 -11
- package/src/components/Input.vue +171 -0
- package/src/pages/components/input.mdx +38 -1
- package/uno-config/index.ts +54 -1
- package/uno-config/theme/shortcuts/index.ts +2 -0
- package/uno-config/theme/shortcuts/inputs.ts +44 -0
- package/src/components/Input.astro +0 -86
package/.astro/data-store.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
[["Map",1,2],"meta::meta",["Map",3,4,5,6],"astro-version","5.3.
|
|
1
|
+
[["Map",1,2],"meta::meta",["Map",3,4,5,6],"astro-version","5.3.1","astro-config-digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{},\"site\":\"https://sds.spoko.space/\",\"compressHTML\":true,\"base\":\"/\",\"trailingSlash\":\"ignore\",\"output\":\"static\",\"scopedStyleStrategy\":\"attribute\",\"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astro\",\"serverEntry\":\"entry.mjs\",\"redirects\":true,\"inlineStylesheets\":\"auto\",\"concurrency\":1},\"server\":{\"open\":false,\"host\":false,\"port\":1234,\"streaming\":true},\"redirects\":{},\"image\":{\"endpoint\":{\"route\":\"/_image\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\"config\":{}},\"domains\":[\"placehold.co\",\"api.polo.blue\",\"polo.blue\",\"media.istockphoto.com\",\"freepik.com\",\"img.freepik.com\",\"polo6r.pl\"],\"remotePatterns\":[]},\"devToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":\"shiki\",\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"theme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPlugins\":[],\"rehypePlugins\":[],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":true},\"security\":{\"checkOrigin\":true},\"env\":{\"schema\":{},\"validateSecrets\":false},\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false,\"responsiveImages\":false,\"serializeConfig\":false},\"legacy\":{\"collections\":false}}"]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spoko-design-system",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"main": "./index.ts",
|
|
6
6
|
"module": "./index.ts",
|
|
@@ -74,20 +74,20 @@
|
|
|
74
74
|
"@iconify/vue": "^4.3.0",
|
|
75
75
|
"@playform/compress": "^0.1.7",
|
|
76
76
|
"@playform/inline": "^0.1.1",
|
|
77
|
-
"@unocss/astro": "
|
|
78
|
-
"@unocss/preset-attributify": "
|
|
79
|
-
"@unocss/preset-typography": "
|
|
80
|
-
"@unocss/preset-uno": "
|
|
81
|
-
"@unocss/preset-web-fonts": "
|
|
82
|
-
"@unocss/preset-wind": "
|
|
83
|
-
"@unocss/reset": "
|
|
77
|
+
"@unocss/astro": "66.1.0-beta.2",
|
|
78
|
+
"@unocss/preset-attributify": "66.1.0-beta.2",
|
|
79
|
+
"@unocss/preset-typography": "66.1.0-beta.2",
|
|
80
|
+
"@unocss/preset-uno": "66.1.0-beta.2",
|
|
81
|
+
"@unocss/preset-web-fonts": "66.1.0-beta.2",
|
|
82
|
+
"@unocss/preset-wind": "66.1.0-beta.2",
|
|
83
|
+
"@unocss/reset": "66.1.0-beta.2",
|
|
84
84
|
"@vite-pwa/astro": "^0.5.0",
|
|
85
85
|
"@vueuse/core": "^12.7.0",
|
|
86
86
|
"astro-i18next": "1.0.0-beta.21",
|
|
87
87
|
"astro-icon": "^1.1.5",
|
|
88
88
|
"astro-meta-tags": "^0.3.1",
|
|
89
89
|
"astro-navbar": "^2.3.9",
|
|
90
|
-
"astro-pagefind": "^1.8.
|
|
90
|
+
"astro-pagefind": "^1.8.1",
|
|
91
91
|
"astro-remote": "^0.3.3",
|
|
92
92
|
"dotenv": "^16.4.7",
|
|
93
93
|
"i18next": "^24.2.2",
|
|
@@ -96,13 +96,13 @@
|
|
|
96
96
|
"i18next-http-backend": "^3.0.2",
|
|
97
97
|
"i18next-vue": "^5.2.0",
|
|
98
98
|
"swiper": "^11.2.4",
|
|
99
|
-
"unocss": "
|
|
99
|
+
"unocss": "66.1.0-beta.2",
|
|
100
100
|
"vue": "^3.5.13"
|
|
101
101
|
},
|
|
102
102
|
"devDependencies": {
|
|
103
103
|
"@types/gtag.js": "^0.0.20",
|
|
104
104
|
"@types/node": "^22.13.5",
|
|
105
|
-
"@unocss/transformer-variant-group": "
|
|
105
|
+
"@unocss/transformer-variant-group": "66.1.0-beta.2",
|
|
106
106
|
"@vitejs/plugin-vue": "^5.2.1",
|
|
107
107
|
"@vue/compiler-sfc": "^3.5.13",
|
|
108
108
|
"astro": "^5.3.1",
|
|
@@ -0,0 +1,171 @@
|
|
|
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; // HTMLInputElement['type'] | 'textarea'
|
|
10
|
+
modelValue?: string | number; // For v-model compatibility
|
|
11
|
+
required?: boolean;
|
|
12
|
+
rows?: number; // rows for textarea
|
|
13
|
+
placeholder?: string;
|
|
14
|
+
error?: string | boolean;
|
|
15
|
+
success?: string | boolean;
|
|
16
|
+
size?: 'sm' | 'md' | 'lg'; // Size prop
|
|
17
|
+
class?: string; // additional classes
|
|
18
|
+
[key: string]: any; // To allow additional props
|
|
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 is important 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
|
|
42
|
+
const wrapperClass = computed(() => `input-wrapper-${props.variant}`);
|
|
43
|
+
|
|
44
|
+
// Compute input classes going back to direct arbitrary selectors
|
|
45
|
+
const inputClass = computed(() => {
|
|
46
|
+
// Base classes
|
|
47
|
+
const classes = ['input-base', `input-${props.variant}`];
|
|
48
|
+
|
|
49
|
+
// Focus and placeholder behavior - using direct arbitrary selectors
|
|
50
|
+
classes.push('[&:focus~label]:text-blue-light');
|
|
51
|
+
classes.push('[&:focus~label]:dark:text-blue-lightest');
|
|
52
|
+
classes.push('[&:focus~label]:scale-75');
|
|
53
|
+
classes.push('[&:placeholder-shown~label]:scale-100');
|
|
54
|
+
classes.push('[&:placeholder-shown~label]:translate-y-0');
|
|
55
|
+
classes.push('[&:not(:placeholder-shown)~label]:scale-75');
|
|
56
|
+
|
|
57
|
+
// Variant-specific behaviors
|
|
58
|
+
if (props.variant === 'standard') {
|
|
59
|
+
classes.push('[&:focus~label]:-translate-y-6');
|
|
60
|
+
classes.push('[&:focus~label]:start-0');
|
|
61
|
+
classes.push('[&:not(:placeholder-shown)~label]:-translate-y-6');
|
|
62
|
+
} else if (props.variant === 'filled') {
|
|
63
|
+
classes.push('[&:focus~label]:-translate-y-4');
|
|
64
|
+
classes.push('[&:not(:placeholder-shown)~label]:-translate-y-4');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Additional classes
|
|
68
|
+
if (props.size) classes.push(`input-${props.size}`);
|
|
69
|
+
if (props.type === 'textarea') classes.push('input-textarea');
|
|
70
|
+
if (props.error) classes.push('input-error');
|
|
71
|
+
else if (props.success) classes.push('input-success');
|
|
72
|
+
if (props.class) classes.push(props.class);
|
|
73
|
+
|
|
74
|
+
return classes.join(' ');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Compute label classes - important: add -translate-y for initial state explicitly
|
|
78
|
+
const labelClass = computed(() => {
|
|
79
|
+
// Base classes
|
|
80
|
+
const classes = ['input-label-base', `input-label-${props.variant}`];
|
|
81
|
+
|
|
82
|
+
// Explicitly add transform for initial state to ensure consistency
|
|
83
|
+
if (props.variant === 'standard') {
|
|
84
|
+
// Start in position and let focus/content move it
|
|
85
|
+
classes.push('translate-y-0');
|
|
86
|
+
} else if (props.variant === 'filled') {
|
|
87
|
+
// Start in position and let focus/content move it
|
|
88
|
+
classes.push('translate-y-0');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Additional classes
|
|
92
|
+
if (props.size) classes.push(`input-label-${props.size}`);
|
|
93
|
+
if (props.error) classes.push('input-label-error');
|
|
94
|
+
else if (props.success) classes.push('input-label-success');
|
|
95
|
+
|
|
96
|
+
return classes.join(' ');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Emit modelValue on input change
|
|
100
|
+
const handleInput = (event: Event) => {
|
|
101
|
+
const target = event.target as HTMLInputElement | HTMLTextAreaElement;
|
|
102
|
+
emit('update:modelValue', target.value);
|
|
103
|
+
emit('input', event);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// Forward focus and blur events
|
|
107
|
+
const handleFocus = (event: FocusEvent) => emit('focus', event);
|
|
108
|
+
const handleBlur = (event: FocusEvent) => emit('blur', event);
|
|
109
|
+
</script>
|
|
110
|
+
|
|
111
|
+
<template>
|
|
112
|
+
<div :class="wrapperClass">
|
|
113
|
+
<!-- Textarea field -->
|
|
114
|
+
<textarea
|
|
115
|
+
v-if="type === 'textarea'"
|
|
116
|
+
:id="id"
|
|
117
|
+
:name="name || id"
|
|
118
|
+
:rows="rows"
|
|
119
|
+
:required="required"
|
|
120
|
+
:class="inputClass"
|
|
121
|
+
:placeholder="placeholder"
|
|
122
|
+
:value="modelValue"
|
|
123
|
+
@input="handleInput"
|
|
124
|
+
@focus="handleFocus"
|
|
125
|
+
@blur="handleBlur"
|
|
126
|
+
v-bind="attrs"
|
|
127
|
+
></textarea>
|
|
128
|
+
|
|
129
|
+
<!-- Input field -->
|
|
130
|
+
<input
|
|
131
|
+
v-else
|
|
132
|
+
:type="type"
|
|
133
|
+
:id="id"
|
|
134
|
+
:name="name || id"
|
|
135
|
+
:required="required"
|
|
136
|
+
:class="inputClass"
|
|
137
|
+
:placeholder="placeholder"
|
|
138
|
+
:value="modelValue"
|
|
139
|
+
@input="handleInput"
|
|
140
|
+
@focus="handleFocus"
|
|
141
|
+
@blur="handleBlur"
|
|
142
|
+
v-bind="attrs"
|
|
143
|
+
/>
|
|
144
|
+
|
|
145
|
+
<!-- Label with guaranteed correct transform origin -->
|
|
146
|
+
<label
|
|
147
|
+
:for="id"
|
|
148
|
+
:class="labelClass"
|
|
149
|
+
style="transform-origin: top left;"
|
|
150
|
+
>
|
|
151
|
+
{{ label }}
|
|
152
|
+
<span v-if="required" class="text-red-500 ml-1">*</span>
|
|
153
|
+
</label>
|
|
154
|
+
|
|
155
|
+
<!-- Error message -->
|
|
156
|
+
<div
|
|
157
|
+
v-if="error && typeof error === 'string'"
|
|
158
|
+
class="input-error-message"
|
|
159
|
+
>
|
|
160
|
+
{{ error }}
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<!-- Success message -->
|
|
164
|
+
<div
|
|
165
|
+
v-if="success && typeof success === 'string'"
|
|
166
|
+
class="input-success-message"
|
|
167
|
+
>
|
|
168
|
+
{{ success }}
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
</template>
|
|
@@ -3,7 +3,7 @@ title: Input
|
|
|
3
3
|
layout: ../../layouts/MainLayout.astro
|
|
4
4
|
---
|
|
5
5
|
import MainInput from '../../components/MainInput.vue'
|
|
6
|
-
import Input from '../../components/Input.
|
|
6
|
+
import Input from '../../components/Input.vue';
|
|
7
7
|
|
|
8
8
|
# Basic Input text
|
|
9
9
|
|
|
@@ -45,4 +45,41 @@ import Input from '../../components/Input.astro';
|
|
|
45
45
|
label="Floating standard"
|
|
46
46
|
variant="standard"
|
|
47
47
|
/>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# Floating Textarea
|
|
52
|
+
<div class="component-preview">
|
|
53
|
+
<div class="bg-white grid items-end w-full gap-6 md:grid-cols-3 px-4 py-6">
|
|
54
|
+
<Input
|
|
55
|
+
id="name-filled"
|
|
56
|
+
label="Floating filled"
|
|
57
|
+
variant="filled"
|
|
58
|
+
type="textarea"
|
|
59
|
+
/>
|
|
60
|
+
<Input
|
|
61
|
+
id="email-standard"
|
|
62
|
+
label="Floating standard"
|
|
63
|
+
variant="standard"
|
|
64
|
+
type="textarea"
|
|
65
|
+
/>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
// Filled variant
|
|
71
|
+
<Input
|
|
72
|
+
id="name-filled"
|
|
73
|
+
label="Floating filled"
|
|
74
|
+
variant="filled"
|
|
75
|
+
type="textarea"
|
|
76
|
+
/>
|
|
77
|
+
|
|
78
|
+
// Standard variant
|
|
79
|
+
<Input
|
|
80
|
+
id="email-standard"
|
|
81
|
+
label="Floating standard"
|
|
82
|
+
variant="standard"
|
|
83
|
+
type="textarea"
|
|
84
|
+
/>
|
|
48
85
|
```
|
package/uno-config/index.ts
CHANGED
|
@@ -33,8 +33,61 @@ export function createSdsConfig(customConfig: CustomConfig = {}) {
|
|
|
33
33
|
...theme,
|
|
34
34
|
...(customConfig.theme || {})
|
|
35
35
|
},
|
|
36
|
+
// safelist section with transform origin classes
|
|
36
37
|
safelist: [
|
|
37
|
-
|
|
38
|
+
// Existing safelist items
|
|
39
|
+
'md:grid-cols-product',
|
|
40
|
+
|
|
41
|
+
// Base classes
|
|
42
|
+
'input-base',
|
|
43
|
+
'input-label-base',
|
|
44
|
+
|
|
45
|
+
// Variants
|
|
46
|
+
'input-standard',
|
|
47
|
+
'input-filled',
|
|
48
|
+
'input-label-standard',
|
|
49
|
+
'input-label-filled',
|
|
50
|
+
'input-wrapper-standard',
|
|
51
|
+
'input-wrapper-filled',
|
|
52
|
+
|
|
53
|
+
// Sizes
|
|
54
|
+
'input-sm',
|
|
55
|
+
'input-md',
|
|
56
|
+
'input-lg',
|
|
57
|
+
'input-label-sm',
|
|
58
|
+
'input-label-md',
|
|
59
|
+
'input-label-lg',
|
|
60
|
+
|
|
61
|
+
// Special types
|
|
62
|
+
'input-textarea',
|
|
63
|
+
|
|
64
|
+
// Status classes
|
|
65
|
+
'input-error',
|
|
66
|
+
'input-label-error',
|
|
67
|
+
'input-error-message',
|
|
68
|
+
'input-success',
|
|
69
|
+
'input-label-success',
|
|
70
|
+
'input-success-message',
|
|
71
|
+
|
|
72
|
+
// Essential transform classes
|
|
73
|
+
'origin-top-left',
|
|
74
|
+
'transform-gpu',
|
|
75
|
+
'translate-y-0',
|
|
76
|
+
'-translate-y-4',
|
|
77
|
+
'-translate-y-6',
|
|
78
|
+
|
|
79
|
+
// Critical arbitrary selectors (all needed ones)
|
|
80
|
+
'[&:focus~label]:text-blue-light',
|
|
81
|
+
'[&:focus~label]:dark:text-blue-lightest',
|
|
82
|
+
'[&:focus~label]:scale-75',
|
|
83
|
+
'[&:focus~label]:-translate-y-6',
|
|
84
|
+
'[&:focus~label]:-translate-y-4',
|
|
85
|
+
'[&:focus~label]:start-0',
|
|
86
|
+
'[&:placeholder-shown~label]:scale-100',
|
|
87
|
+
'[&:placeholder-shown~label]:translate-y-0',
|
|
88
|
+
'[&:not(:placeholder-shown)~label]:scale-75',
|
|
89
|
+
'[&:not(:placeholder-shown)~label]:-translate-y-6',
|
|
90
|
+
'[&:not(:placeholder-shown)~label]:-translate-y-4',
|
|
38
91
|
],
|
|
39
92
|
presets: [
|
|
40
93
|
presetUno(),
|
|
@@ -5,6 +5,7 @@ import { layoutShortcuts } from './layout';
|
|
|
5
5
|
import { componentShortcuts } from './components';
|
|
6
6
|
import { productShortcuts } from './product';
|
|
7
7
|
import { jumbotronShortcuts } from './jumbotron';
|
|
8
|
+
import { inputShortcuts } from './inputs';
|
|
8
9
|
|
|
9
10
|
const convertToShortcuts = (shortcuts: string[][]): UserShortcuts => {
|
|
10
11
|
return Object.fromEntries(shortcuts.map(([name, value]) => [name, value]));
|
|
@@ -16,4 +17,5 @@ export const shortcuts: UserShortcuts = {
|
|
|
16
17
|
...convertToShortcuts(componentShortcuts),
|
|
17
18
|
...convertToShortcuts(productShortcuts),
|
|
18
19
|
...convertToShortcuts(jumbotronShortcuts),
|
|
20
|
+
...convertToShortcuts(inputShortcuts),
|
|
19
21
|
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// shortcuts/inputs.ts
|
|
2
|
+
|
|
3
|
+
export const inputShortcuts = [
|
|
4
|
+
// Base input styles
|
|
5
|
+
['input-base', 'block w-full text-4.5 text-blue-medium border-0 border-b-1 border-neutral-light appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-lightest focus:outline-none focus:ring-0 focus:border-blue-medium'],
|
|
6
|
+
|
|
7
|
+
// Base label styles with optimized transform settings
|
|
8
|
+
['input-label-base', 'absolute text-sm text-slate-light dark:text-neutral-default origin-top-left transform-gpu transition-all duration-300 ease-in-out'],
|
|
9
|
+
|
|
10
|
+
// We're going back to direct arbitrary selectors in the input component
|
|
11
|
+
// since the grouped selectors seem to be causing issues with the focus behavior
|
|
12
|
+
|
|
13
|
+
// Variant styles for labels - position only, no transforms
|
|
14
|
+
['input-label-standard', 'top-3 -z-10'],
|
|
15
|
+
['input-label-filled', 'top-4 z-10 start-2.5'],
|
|
16
|
+
|
|
17
|
+
// Container styles
|
|
18
|
+
['input-wrapper-standard', 'relative z-0'],
|
|
19
|
+
['input-wrapper-filled', 'relative'],
|
|
20
|
+
|
|
21
|
+
// Input variant styles
|
|
22
|
+
['input-standard', 'py-2.5 px-0 bg-transparent'],
|
|
23
|
+
['input-filled', 'rounded-t-lg px-2.5 pb-2.5 pt-5 bg-gray-50 dark:bg-gray-700'],
|
|
24
|
+
|
|
25
|
+
// Special input types
|
|
26
|
+
['input-textarea', 'resize-none'],
|
|
27
|
+
|
|
28
|
+
// Size variants
|
|
29
|
+
['input-sm', 'text-sm'],
|
|
30
|
+
['input-md', 'text-base'],
|
|
31
|
+
['input-lg', 'text-lg py-3'],
|
|
32
|
+
['input-label-sm', 'text-xs'],
|
|
33
|
+
['input-label-md', 'text-sm'],
|
|
34
|
+
['input-label-lg', 'text-base'],
|
|
35
|
+
|
|
36
|
+
// Status styles - grouped logically
|
|
37
|
+
['input-error', 'border-red-500 focus:border-red-500 dark:border-red-400 dark:focus:border-red-400'],
|
|
38
|
+
['input-label-error', 'text-red-500 dark:text-red-400'],
|
|
39
|
+
['input-error-message', 'mt-1 text-xs text-red-500 dark:text-red-400'],
|
|
40
|
+
|
|
41
|
+
['input-success', 'border-green-500 focus:border-green-500 dark:border-green-400 dark:focus:border-green-400'],
|
|
42
|
+
['input-label-success', 'text-green-500 dark:text-green-400'],
|
|
43
|
+
['input-success-message', 'mt-1 text-xs text-green-500 dark:text-green-400'],
|
|
44
|
+
];
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
// Input.astro
|
|
3
|
-
interface Props {
|
|
4
|
-
id: string;
|
|
5
|
-
name?: string;
|
|
6
|
-
label: string;
|
|
7
|
-
variant?: 'filled' | 'standard';
|
|
8
|
-
type?: HTMLInputElement['type'] | 'textarea'; // support textarea
|
|
9
|
-
value?: string;
|
|
10
|
-
required?: boolean;
|
|
11
|
-
rows?: number; // rows for textarea
|
|
12
|
-
placeholder?: string;
|
|
13
|
-
class?: string; // additional classes
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const {
|
|
17
|
-
id,
|
|
18
|
-
name,
|
|
19
|
-
label,
|
|
20
|
-
variant = 'standard',
|
|
21
|
-
type = 'text',
|
|
22
|
-
value = '',
|
|
23
|
-
required = false,
|
|
24
|
-
rows = 3,
|
|
25
|
-
placeholder = " ", //space for "floating label")
|
|
26
|
-
class: additionalClasses = "",
|
|
27
|
-
...restProps
|
|
28
|
-
} = Astro.props;
|
|
29
|
-
|
|
30
|
-
// Common classes for both variants
|
|
31
|
-
const baseInputClasses = "block w-full text-4.5 text-blue-medium border-0 border-b-1 border-neutral-light appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-lightest focus:outline-none focus:ring-0 focus:border-blue-medium peer";
|
|
32
|
-
|
|
33
|
-
const baseLabelClasses = "absolute text-sm text-slate-medium dark:text-neutral-default transform scale-75 origin-[0] peer-focus:text-blue-medium peer-focus:dark:text-blue-lightest peer-placeholder-shown:scale-100 peer-focus:scale-75 rtl:peer-focus:translate-x-1/4 rtl:peer-focus:left-auto transition-all duration-300 ease-in-out";
|
|
34
|
-
|
|
35
|
-
// Variant specific classes
|
|
36
|
-
const variantClasses = {
|
|
37
|
-
filled: {
|
|
38
|
-
wrapper: "relative",
|
|
39
|
-
input: `${baseInputClasses} rounded-t-lg px-2.5 pb-2.5 pt-5 bg-gray-50 dark:bg-gray-700 ${additionalClasses}`,
|
|
40
|
-
label: `${baseLabelClasses} -translate-y-4 top-4 z-10 start-2.5 peer-placeholder-shown:translate-y-0 peer-focus:-translate-y-4`
|
|
41
|
-
},
|
|
42
|
-
standard: {
|
|
43
|
-
wrapper: "relative z-0",
|
|
44
|
-
input: `${baseInputClasses} py-2.5 px-0 bg-transparent ${additionalClasses}`,
|
|
45
|
-
label: `${baseLabelClasses} -translate-y-6 top-3 -z-10 peer-focus:start-0 peer-placeholder-shown:translate-y-0 peer-focus:-translate-y-6`
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const classes = variantClasses[variant];
|
|
50
|
-
|
|
51
|
-
// Dla textarea modyfikujemy nieco style
|
|
52
|
-
const textareaClasses = type === 'textarea'
|
|
53
|
-
? classes.input.replace('border-b-1', 'border-1') + ' resize-none'
|
|
54
|
-
: classes.input;
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
<div class={classes.wrapper}>
|
|
58
|
-
{type === 'textarea' ? (
|
|
59
|
-
<textarea
|
|
60
|
-
name={name}
|
|
61
|
-
id={id}
|
|
62
|
-
rows={rows}
|
|
63
|
-
required={required}
|
|
64
|
-
class={textareaClasses}
|
|
65
|
-
placeholder={placeholder}
|
|
66
|
-
{...restProps}
|
|
67
|
-
>{value}</textarea>
|
|
68
|
-
) : (
|
|
69
|
-
<input
|
|
70
|
-
type={type}
|
|
71
|
-
name={name}
|
|
72
|
-
id={id}
|
|
73
|
-
value={value}
|
|
74
|
-
required={required}
|
|
75
|
-
class={classes.input}
|
|
76
|
-
placeholder={placeholder}
|
|
77
|
-
{...restProps}
|
|
78
|
-
/>
|
|
79
|
-
)}
|
|
80
|
-
<label
|
|
81
|
-
for={id}
|
|
82
|
-
class={classes.label}
|
|
83
|
-
>
|
|
84
|
-
{label}
|
|
85
|
-
</label>
|
|
86
|
-
</div>
|