@latte-macchiat-io/latte-vanilla-components 0.0.553 → 0.0.554
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/package.json +1 -1
- package/src/components/Form/Checkbox/export.tsx +2 -0
- package/src/components/Form/Checkbox/index.tsx +56 -0
- package/src/components/Form/Checkbox/stories.tsx +80 -0
- package/src/components/Form/Checkbox/styles.css.ts +62 -0
- package/src/components/Form/export.tsx +1 -0
- package/src/theme/contract.css.ts +1 -0
- package/src/components/Form/Select/theme.ts +0 -40
package/package.json
CHANGED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
import { checkboxInput, checkboxLabel, checkboxRecipe, CheckboxVariants, errorMessage, messageContainer } from './styles.css';
|
|
4
|
+
|
|
5
|
+
import { cn } from '../../../utils/styleOverride';
|
|
6
|
+
|
|
7
|
+
export type CheckboxProps = React.InputHTMLAttributes<HTMLInputElement> &
|
|
8
|
+
CheckboxVariants & {
|
|
9
|
+
name: string;
|
|
10
|
+
label?: string;
|
|
11
|
+
errors?: string | string[];
|
|
12
|
+
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const Checkbox = ({ name, label, errors, labelPosition, required, checked, disabled, onChange, className }: CheckboxProps) => {
|
|
16
|
+
const hasErrors = useMemo(() => {
|
|
17
|
+
if (!errors) return false;
|
|
18
|
+
if (Array.isArray(errors)) return errors.length > 0;
|
|
19
|
+
return Boolean(errors);
|
|
20
|
+
}, [errors]);
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div className={cn(checkboxRecipe({ labelPosition }), className)}>
|
|
24
|
+
<input
|
|
25
|
+
id={name}
|
|
26
|
+
name={name}
|
|
27
|
+
type="checkbox"
|
|
28
|
+
required={required}
|
|
29
|
+
checked={checked}
|
|
30
|
+
disabled={disabled}
|
|
31
|
+
onChange={onChange}
|
|
32
|
+
className={checkboxInput}
|
|
33
|
+
/>
|
|
34
|
+
|
|
35
|
+
{label && (
|
|
36
|
+
<label htmlFor={name} className={checkboxLabel}>
|
|
37
|
+
{label} {required && '*'}
|
|
38
|
+
</label>
|
|
39
|
+
)}
|
|
40
|
+
|
|
41
|
+
{hasErrors && (
|
|
42
|
+
<div className={messageContainer}>
|
|
43
|
+
{Array.isArray(errors) ? (
|
|
44
|
+
errors.map((error, index) => (
|
|
45
|
+
<span key={index} className={errorMessage}>
|
|
46
|
+
{error}
|
|
47
|
+
</span>
|
|
48
|
+
))
|
|
49
|
+
) : (
|
|
50
|
+
<span className={errorMessage}>{errors}</span>
|
|
51
|
+
)}
|
|
52
|
+
</div>
|
|
53
|
+
)}
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
|
|
3
|
+
import { Checkbox } from '.';
|
|
4
|
+
|
|
5
|
+
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
|
|
6
|
+
const meta: Meta<typeof Checkbox> = {
|
|
7
|
+
title: '5. Forms / Checkbox',
|
|
8
|
+
component: Checkbox,
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: 'centered',
|
|
11
|
+
},
|
|
12
|
+
tags: ['autodocs'],
|
|
13
|
+
argTypes: {},
|
|
14
|
+
decorators: [
|
|
15
|
+
(Story) => (
|
|
16
|
+
<div style={{ minWidth: '320px', maxWidth: '500px', width: '100%' }}>
|
|
17
|
+
<Story />
|
|
18
|
+
</div>
|
|
19
|
+
),
|
|
20
|
+
],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default meta;
|
|
24
|
+
type Story = StoryObj<typeof meta>;
|
|
25
|
+
|
|
26
|
+
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
|
|
27
|
+
export const Default: Story = {
|
|
28
|
+
args: {
|
|
29
|
+
name: 'agree',
|
|
30
|
+
label: 'I agree to the terms and conditions',
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const Checked: Story = {
|
|
35
|
+
args: {
|
|
36
|
+
name: 'newsletter',
|
|
37
|
+
label: 'Subscribe to newsletter',
|
|
38
|
+
checked: true,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const Required: Story = {
|
|
43
|
+
args: {
|
|
44
|
+
name: 'required-checkbox',
|
|
45
|
+
label: 'Accept terms',
|
|
46
|
+
required: true,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const LabelLeft: Story = {
|
|
51
|
+
args: {
|
|
52
|
+
name: 'label-left',
|
|
53
|
+
label: 'Label on the left',
|
|
54
|
+
labelPosition: 'left',
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const Disabled: Story = {
|
|
59
|
+
args: {
|
|
60
|
+
name: 'disabled-checkbox',
|
|
61
|
+
label: 'This option is disabled',
|
|
62
|
+
disabled: true,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const WithError: Story = {
|
|
67
|
+
args: {
|
|
68
|
+
name: 'terms',
|
|
69
|
+
label: 'I accept the terms',
|
|
70
|
+
errors: 'You must accept the terms to continue',
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const WithMultipleErrors: Story = {
|
|
75
|
+
args: {
|
|
76
|
+
name: 'gdpr',
|
|
77
|
+
label: 'I accept the GDPR policy',
|
|
78
|
+
errors: ['This field is required', 'You must be 18 or older to accept'],
|
|
79
|
+
},
|
|
80
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { style } from '@vanilla-extract/css';
|
|
2
|
+
import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
|
|
3
|
+
|
|
4
|
+
import { themeContract } from '../../../theme/contract.css';
|
|
5
|
+
|
|
6
|
+
export const checkboxRecipe = recipe(
|
|
7
|
+
{
|
|
8
|
+
base: {
|
|
9
|
+
display: 'flex',
|
|
10
|
+
alignItems: 'center',
|
|
11
|
+
gap: themeContract.space.sm,
|
|
12
|
+
transition: 'all 0.2s ease-in-out',
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
variants: {
|
|
16
|
+
labelPosition: {
|
|
17
|
+
left: {
|
|
18
|
+
flexDirection: 'row-reverse',
|
|
19
|
+
justifyContent: 'flex-end',
|
|
20
|
+
},
|
|
21
|
+
right: {
|
|
22
|
+
flexDirection: 'row',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
defaultVariants: {
|
|
28
|
+
labelPosition: 'right',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
'checkbox'
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
export const checkboxInput = style({
|
|
35
|
+
appearance: 'none',
|
|
36
|
+
cursor: 'pointer',
|
|
37
|
+
flexShrink: 0,
|
|
38
|
+
width: '1.25rem',
|
|
39
|
+
height: '1.25rem',
|
|
40
|
+
border: themeContract.form.textField.border,
|
|
41
|
+
borderRadius: themeContract.form.textField.borderRadius,
|
|
42
|
+
backgroundColor: themeContract.form.textField.backgroundColor,
|
|
43
|
+
transition: 'all 0.2s ease-in-out',
|
|
44
|
+
|
|
45
|
+
selectors: {
|
|
46
|
+
'&:checked': {
|
|
47
|
+
backgroundColor: themeContract.colors.primary,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
export const checkboxLabel = style({
|
|
53
|
+
cursor: 'pointer',
|
|
54
|
+
fontFamily: themeContract.fonts.body,
|
|
55
|
+
color: themeContract.form.textField.color,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
export const messageContainer = style({});
|
|
59
|
+
|
|
60
|
+
export const errorMessage = style({});
|
|
61
|
+
|
|
62
|
+
export type CheckboxVariants = RecipeVariants<typeof checkboxRecipe>;
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
const themeActionsBase = {
|
|
2
|
-
actions: {
|
|
3
|
-
gap: {
|
|
4
|
-
mobile: '15px',
|
|
5
|
-
sm: '15px',
|
|
6
|
-
md: '30px',
|
|
7
|
-
lg: '30px',
|
|
8
|
-
xl: '50px',
|
|
9
|
-
'2xl': '50px',
|
|
10
|
-
},
|
|
11
|
-
paddingTop: {
|
|
12
|
-
mobile: '15px',
|
|
13
|
-
sm: '15px',
|
|
14
|
-
md: '30px',
|
|
15
|
-
lg: '30px',
|
|
16
|
-
xl: '50px',
|
|
17
|
-
'2xl': '50px',
|
|
18
|
-
},
|
|
19
|
-
paddingBottom: {
|
|
20
|
-
mobile: '15px',
|
|
21
|
-
sm: '15px',
|
|
22
|
-
md: '30px',
|
|
23
|
-
lg: '30px',
|
|
24
|
-
xl: '50px',
|
|
25
|
-
'2xl': '50px',
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export const themeActionsLight = {
|
|
31
|
-
actions: {
|
|
32
|
-
...themeActionsBase.actions,
|
|
33
|
-
},
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export const themeActionsDark = {
|
|
37
|
-
actions: {
|
|
38
|
-
...themeActionsBase.actions,
|
|
39
|
-
},
|
|
40
|
-
};
|