Skip to content

Commit c94e217

Browse files
committed
feat: variants to floating input
1 parent 89e2b1b commit c94e217

File tree

12 files changed

+362
-347
lines changed

12 files changed

+362
-347
lines changed

.changeset/tricky-turtles-sort.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte-5-ui-lib': patch
3+
---
4+
5+
feat: add variants to floating input

src/lib/forms/floating-label-input/FloatingLabelInput.svelte

Lines changed: 70 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,122 +1,103 @@
11
<script lang="ts">
2-
import type { Snippet } from 'svelte';
32
import { twMerge } from 'tailwind-merge';
43
import { idGenerator } from '../../uiHelpers.svelte';
5-
import type { HTMLInputAttributes } from 'svelte/elements';
6-
7-
interface Props extends HTMLInputAttributes {
8-
children: Snippet;
9-
id?: string | undefined | null;
10-
aria_describedby?: string | undefined | null;
11-
style?: 'filled' | 'outlined' | 'standard';
12-
inputSize?: 'small' | 'default';
13-
color?: 'base' | 'green' | 'red';
14-
divClass?: string | undefined | null;
15-
inputClass?: string | undefined | null;
16-
labelClass?: string | undefined | null;
17-
}
4+
import { type FloatingLabelInputProps as Props, floatingLabelInput } from '.';
5+
186
let {
197
children,
208
id = idGenerator(),
219
aria_describedby,
2210
style = 'standard',
23-
inputSize = 'default',
24-
color = 'base',
11+
size = 'default',
12+
color = 'gray',
2513
divClass,
2614
inputClass,
2715
labelClass,
2816
...attributes
2917
}: Props = $props();
3018
31-
const divClasses = {
32-
filled: 'relative',
33-
outlined: 'relative',
34-
standard: 'relative z-0'
35-
};
19+
const { base, input, label } = $derived(floatingLabelInput({ style, size, color }));
20+
21+
// const divClasses = {
22+
// filled: 'relative',
23+
// outlined: 'relative',
24+
// standard: 'relative z-0'
25+
// };
3626
37-
const inputSizes = {
38-
filled: {
39-
small: 'px-2.5 pb-1.5 pt-4',
40-
default: 'px-2.5 pb-2.5 pt-5'
41-
},
42-
outlined: {
43-
small: 'px-2.5 pb-1.5 pt-3',
44-
default: 'px-2.5 pb-2.5 pt-4'
45-
},
46-
standard: {
47-
small: 'py-2 px-0',
48-
default: 'py-2.5 px-0'
49-
}
50-
};
27+
// const inputSizes = {
28+
// filled: {
29+
// small: 'px-2.5 pb-1.5 pt-4',
30+
// default: 'px-2.5 pb-2.5 pt-5'
31+
// },
32+
// outlined: {
33+
// small: 'px-2.5 pb-1.5 pt-3',
34+
// default: 'px-2.5 pb-2.5 pt-4'
35+
// },
36+
// standard: {
37+
// small: 'py-2 px-0',
38+
// default: 'py-2.5 px-0'
39+
// }
40+
// };
5141
52-
const labelSizes = {
53-
filled: {
54-
small: 'top-3',
55-
default: 'top-4'
56-
},
57-
outlined: {
58-
small: 'top-1',
59-
default: 'top-2'
60-
},
61-
standard: {
62-
small: 'top-3',
63-
default: 'top-3'
64-
}
65-
};
42+
// const labelSizes = {
43+
// filled: {
44+
// small: 'top-3',
45+
// default: 'top-4'
46+
// },
47+
// outlined: {
48+
// small: 'top-1',
49+
// default: 'top-2'
50+
// },
51+
// standard: {
52+
// small: 'top-3',
53+
// default: 'top-3'
54+
// }
55+
// };
6656
67-
const inputClasses = {
68-
filled:
69-
'block rounded-t-lg w-full text-sm text-gray-900 bg-gray-50 dark:bg-gray-700 border-0 border-b-2 appearance-none dark:text-white focus:outline-none focus:ring-0 peer',
70-
outlined:
71-
'block w-full text-sm text-gray-900 bg-transparent rounded-lg border appearance-none dark:text-white focus:outline-none focus:ring-0 peer',
72-
standard:
73-
'block w-full text-sm text-gray-900 bg-transparent border-0 border-b-2 appearance-none dark:text-white focus:outline-none focus:ring-0 peer'
74-
};
57+
// const inputClasses = {
58+
// filled:
59+
// 'block rounded-t-lg w-full text-sm text-gray-900 bg-gray-50 dark:bg-gray-700 border-0 border-b-2 appearance-none dark:text-white focus:outline-none focus:ring-0 peer',
60+
// outlined:
61+
// 'block w-full text-sm text-gray-900 bg-transparent rounded-lg border appearance-none dark:text-white focus:outline-none focus:ring-0 peer',
62+
// standard:
63+
// 'block w-full text-sm text-gray-900 bg-transparent border-0 border-b-2 appearance-none dark:text-white focus:outline-none focus:ring-0 peer'
64+
// };
7565
76-
const labelClasses = {
77-
filled:
78-
'absolute text-sm duration-300 transform -translate-y-4 scale-75 top-4 z-10 origin-left rtl:origin-right start-2.5 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-4',
79-
outlined:
80-
'absolute text-sm duration-300 transform -translate-y-4 scale-75 top-2 z-10 origin-left rtl:origin-right bg-white dark:bg-gray-900 px-2 peer-focus:px-2 peer-placeholder-shown:scale-100 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:top-1/2 peer-focus:top-2 peer-focus:scale-75 peer-focus:-translate-y-4 start-1',
81-
standard:
82-
'absolute text-sm duration-300 transform -translate-y-6 scale-75 top-3 -z-10 origin-left rtl:origin-right peer-focus:start-0 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-6'
83-
};
66+
// const labelClasses = {
67+
// filled:
68+
// 'absolute text-sm duration-300 transform -translate-y-4 scale-75 top-4 z-10 origin-left rtl:origin-right start-2.5 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-4',
69+
// outlined:
70+
// 'absolute text-sm duration-300 transform -translate-y-4 scale-75 top-2 z-10 origin-left rtl:origin-right bg-white dark:bg-gray-900 px-2 peer-focus:px-2 peer-placeholder-shown:scale-100 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:top-1/2 peer-focus:top-2 peer-focus:scale-75 peer-focus:-translate-y-4 start-1',
71+
// standard:
72+
// 'absolute text-sm duration-300 transform -translate-y-6 scale-75 top-3 -z-10 origin-left rtl:origin-right peer-focus:start-0 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-6'
73+
// };
8474
85-
const inputColorClasses = {
86-
base: 'border-gray-300 dark:border-gray-600 dark:focus:border-primary-500 focus:border-primary-600',
87-
green:
88-
'border-green-600 dark:border-green-500 dark:focus:border-green-500 focus:border-green-600',
89-
red: 'border-red-600 dark:border-red-500 dark:focus:border-red-500 focus:border-red-600'
90-
};
75+
// const inputColorClasses = {
76+
// base: 'border-gray-300 dark:border-gray-600 dark:focus:border-primary-500 focus:border-primary-600',
77+
// green:
78+
// 'border-green-600 dark:border-green-500 dark:focus:border-green-500 focus:border-green-600',
79+
// red: 'border-red-600 dark:border-red-500 dark:focus:border-red-500 focus:border-red-600'
80+
// };
9181
92-
const labelColorClasses = {
93-
base: 'text-gray-500 dark:text-gray-400 peer-focus:text-primary-600 peer-focus:dark:text-primary-500',
94-
green: 'text-green-600 dark:text-green-500',
95-
red: 'text-red-600 dark:text-red-500'
96-
};
82+
// const labelColorClasses = {
83+
// base: 'text-gray-500 dark:text-gray-400 peer-focus:text-primary-600 peer-focus:dark:text-primary-500',
84+
// green: 'text-green-600 dark:text-green-500',
85+
// red: 'text-red-600 dark:text-red-500'
86+
// };
9787
</script>
9888

99-
<div class={twMerge(divClasses[style], divClass)}>
89+
<div class={base({ class: divClass})}>
10090
<input
10191
{id}
92+
placeholder=" "
10293
{...attributes}
10394
aria-describedby={aria_describedby}
104-
class={twMerge(
105-
inputClasses[style],
106-
inputColorClasses[color],
107-
inputSizes[style][inputSize],
108-
inputClass
109-
)}
95+
class={input({ class: inputClass })}
11096
/>
11197

11298
<label
11399
for={id}
114-
class={twMerge(
115-
labelClasses[style],
116-
labelColorClasses[color],
117-
labelSizes[style][inputSize],
118-
labelClass
119-
)}
100+
class={label({ class: labelClass})}
120101
>
121102
{@render children()}
122103
</label>
Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
11
import FloatingLabelInput from './FloatingLabelInput.svelte';
2+
import type { Snippet } from 'svelte';
3+
import type { HTMLInputAttributes } from 'svelte/elements';
4+
import { floatingLabelInput } from './theme';
5+
import { type ColorName } from '$lib/types';
26

3-
export { FloatingLabelInput };
7+
interface FloatingLabelInputProps extends Omit<HTMLInputAttributes, 'size'> {
8+
children: Snippet;
9+
id?: string | undefined | null;
10+
aria_describedby?: string | undefined | null;
11+
style?: 'filled' | 'outlined' | 'standard';
12+
size?: 'small' | 'default';
13+
color?: ColorName;
14+
divClass?: string | undefined | null;
15+
inputClass?: string | undefined | null;
16+
labelClass?: string | undefined | null;
17+
}
18+
19+
export { FloatingLabelInput, floatingLabelInput, type FloatingLabelInputProps };
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
import { tv } from 'tailwind-variants';
2+
3+
export const floatingLabelInput = tv({
4+
slots: {
5+
base: 'relative',
6+
input: 'block w-full text-sm text-gray-900 bg-transparent appearance-none dark:text-white focus:outline-none focus:ring-0 peer',
7+
label: 'absolute text-sm duration-300 transform scale-75 z-10 origin-left rtl:origin-right peer-placeholder-shown:scale-100 peer-focus:scale-75',
8+
},
9+
variants: {
10+
style: {
11+
filled: {
12+
base: 'relative',
13+
input: 'rounded-t-lg border-0 border-b-2 bg-gray-50 dark:bg-gray-700',
14+
label: '-translate-y-4 start-2.5 peer-placeholder-shown:translate-y-0 peer-focus:-translate-y-4',
15+
},
16+
outlined: {
17+
base: 'relative',
18+
input: 'rounded-lg border',
19+
label: '-translate-y-4 bg-white dark:bg-gray-900 px-2 peer-focus:px-2 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:top-1/2 peer-focus:top-2 peer-focus:-translate-y-4 start-1',
20+
},
21+
standard: {
22+
base: 'relative z-0',
23+
input: 'border-0 border-b-2',
24+
label: '-translate-y-6 -z-10 peer-focus:start-0 peer-placeholder-shown:translate-y-0 peer-focus:-translate-y-6',
25+
},
26+
},
27+
size: {
28+
small: {},
29+
default: {},
30+
},
31+
color: {
32+
primary: {
33+
input: 'border-primary-600 dark:border-primary-500 dark:focus:border-primary-500 focus:border-primary-600',
34+
label: 'text-primary-600 dark:text-primary-500',
35+
},
36+
secondary: {
37+
input: 'border-secondary-600 dark:border-secondary-500 dark:focus:border-secondary-500 focus:border-secondary-600',
38+
label: 'text-secondary-600 dark:text-secondary-500',
39+
},
40+
gray: {
41+
input: 'border-gray-300 dark:border-gray-600 dark:focus:border-primary-500 focus:border-primary-600',
42+
label: 'text-gray-500 dark:text-gray-400 peer-focus:text-primary-600 peer-focus:dark:text-primary-500',
43+
},
44+
red: {
45+
input: 'border-red-600 dark:border-red-500 dark:focus:border-red-500 focus:border-red-600',
46+
label: 'text-red-600 dark:text-red-500',
47+
},
48+
orange: {
49+
input: 'border-orange-600 dark:border-orange-500 dark:focus:border-orange-500 focus:border-orange-600',
50+
label: 'text-orange-600 dark:text-orange-500',
51+
},
52+
amber: {
53+
input: 'border-amber-600 dark:border-amber-500 dark:focus:border-amber-500 focus:border-amber-600',
54+
label: 'text-amber-600 dark:text-amber-500',
55+
},
56+
yellow: {
57+
input: 'border-yellow-600 dark:border-yellow-500 dark:focus:border-yellow-500 focus:border-yellow-600',
58+
label: 'text-yellow-600 dark:text-yellow-500',
59+
},
60+
lime: {
61+
input: 'border-lime-600 dark:border-lime-500 dark:focus:border-lime-500 focus:border-lime-600',
62+
label: 'text-lime-600 dark:text-lime-500',
63+
},
64+
green: {
65+
input: 'border-green-600 dark:border-green-500 dark:focus:border-green-500 focus:border-green-600',
66+
label: 'text-green-600 dark:text-green-500',
67+
},
68+
emerald: {
69+
input: 'border-emerald-600 dark:border-emerald-500 dark:focus:border-emerald-500 focus:border-emerald-600',
70+
label: 'text-emerald-600 dark:text-emerald-500',
71+
},
72+
teal: {
73+
input: 'border-teal-600 dark:border-teal-500 dark:focus:border-teal-500 focus:border-teal-600',
74+
label: 'text-teal-600 dark:text-teal-500',
75+
},
76+
cyan: {
77+
input: 'border-cyan-600 dark:border-cyan-500 dark:focus:border-cyan-500 focus:border-cyan-600',
78+
label: 'text-cyan-600 dark:text-cyan-500',
79+
},
80+
sky: {
81+
input: 'border-sky-600 dark:border-sky-500 dark:focus:border-sky-500 focus:border-sky-600',
82+
label: 'text-sky-600 dark:text-sky-500',
83+
},
84+
blue: {
85+
input: 'border-blue-600 dark:border-blue-500 dark:focus:border-blue-500 focus:border-blue-600',
86+
label: 'text-blue-600 dark:text-blue-500',
87+
},
88+
indigo: {
89+
input: 'border-indigo-600 dark:border-indigo-500 dark:focus:border-indigo-500 focus:border-indigo-600',
90+
label: 'text-indigo-600 dark:text-indigo-500',
91+
},
92+
violet: {
93+
input: 'border-violet-600 dark:border-violet-500 dark:focus:border-violet-500 focus:border-violet-600',
94+
label: 'text-violet-600 dark:text-violet-500',
95+
},
96+
purple: {
97+
input: 'border-purple-600 dark:border-purple-500 dark:focus:border-purple-500 focus:border-purple-600',
98+
label: 'text-purple-600 dark:text-purple-500',
99+
},
100+
fuchsia: {
101+
input: 'border-fuchsia-600 dark:border-fuchsia-500 dark:focus:border-fuchsia-500 focus:border-fuchsia-600',
102+
label: 'text-fuchsia-600 dark:text-fuchsia-500',
103+
},
104+
pink: {
105+
input: 'border-pink-600 dark:border-pink-500 dark:focus:border-pink-500 focus:border-pink-600',
106+
label: 'text-pink-600 dark:text-pink-500',
107+
},
108+
rose: {
109+
input: 'border-rose-600 dark:border-rose-500 dark:focus:border-rose-500 focus:border-rose-600',
110+
label: 'text-rose-600 dark:text-rose-500',
111+
},
112+
},
113+
},
114+
compoundVariants: [
115+
{
116+
style: 'filled',
117+
size: 'small',
118+
class: {
119+
input: 'px-2.5 pb-1.5 pt-4',
120+
label: 'top-3',
121+
},
122+
},
123+
{
124+
style: 'filled',
125+
size: 'default',
126+
class: {
127+
input: 'px-2.5 pb-2.5 pt-5',
128+
label: 'top-4',
129+
},
130+
},
131+
{
132+
style: 'outlined',
133+
size: 'small',
134+
class: {
135+
input: 'px-2.5 pb-1.5 pt-3',
136+
label: 'top-1',
137+
},
138+
},
139+
{
140+
style: 'outlined',
141+
size: 'default',
142+
class: {
143+
input: 'px-2.5 pb-2.5 pt-4',
144+
label: 'top-2',
145+
},
146+
},
147+
{
148+
style: 'standard',
149+
size: 'small',
150+
class: {
151+
input: 'py-2 px-0',
152+
label: 'top-3',
153+
},
154+
},
155+
{
156+
style: 'standard',
157+
size: 'default',
158+
class: {
159+
input: 'py-2.5 px-0',
160+
label: 'top-3',
161+
},
162+
},
163+
{
164+
style: 'filled',
165+
color: 'primary',
166+
class: {
167+
input: 'dark:focus:border-primary-500 focus:border-primary-600',
168+
},
169+
},
170+
],
171+
defaultVariants: {
172+
style: 'standard',
173+
size: 'default',
174+
color: 'primary',
175+
},
176+
});

0 commit comments

Comments
 (0)