@latte-macchiat-io/latte-vanilla-components 0.0.553 → 0.0.555

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@latte-macchiat-io/latte-vanilla-components",
3
- "version": "0.0.553",
3
+ "version": "0.0.555",
4
4
  "description": "Beautiful components for amazing projects, with a touch of Vanilla 🥤",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -162,7 +162,5 @@ export const boxContent = recipe({
162
162
  },
163
163
  });
164
164
 
165
- // export type BoxVariants = NonNullable<CleanRecipeVariants<RecipeVariants<typeof box>>>;
166
- // export type BoxContentVariants = NonNullable<CleanRecipeVariants<RecipeVariants<typeof boxContent>>>;
167
165
  export type BoxVariants = RecipeVariants<typeof box>;
168
166
  export type BoxContentVariants = RecipeVariants<typeof boxContent>;
@@ -0,0 +1,2 @@
1
+ export { Checkbox, type CheckboxProps } from './';
2
+ export { type CheckboxVariants } from './styles.css';
@@ -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,3 +1,2 @@
1
1
  export { Input, type InputProps } from './';
2
- export { type InputVariants } from './styles.css';
3
2
  export { type InputType as InputFieldType } from './types';
@@ -1,4 +1,4 @@
1
- import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
1
+ import { recipe } from '@vanilla-extract/recipes';
2
2
 
3
3
  import { generateResponsiveMedia } from '../../../../styles/utils/generateResponsiveMedia';
4
4
  import { themeContract } from '../../../../theme/contract.css';
@@ -35,4 +35,3 @@ export const inputRecipe = recipe(
35
35
  'input'
36
36
  );
37
37
 
38
- export type InputVariants = RecipeVariants<typeof inputRecipe>;
@@ -1,2 +1 @@
1
1
  export { Label, type LabelProps } from './index';
2
- export { type LabelVariants } from './styles.css';
@@ -1,12 +1,12 @@
1
- import { labelRecipe, type LabelVariants } from './styles.css';
1
+ import { labelRecipe } from './styles.css';
2
2
  import { cn } from '../../../../utils/styleOverride';
3
3
 
4
- export type LabelProps = React.LabelHTMLAttributes<HTMLLabelElement> &
5
- LabelVariants & {
6
- name: string;
7
- label: string;
8
- required: boolean;
9
- };
4
+ export type LabelProps = {
5
+ name: string;
6
+ label: string;
7
+ required: boolean;
8
+ className?: string;
9
+ };
10
10
 
11
11
  export const Label = ({ label, name, required, className }: LabelProps) => (
12
12
  <label htmlFor={name} className={cn(labelRecipe(), className)}>
@@ -1,4 +1,4 @@
1
- import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
1
+ import { recipe } from '@vanilla-extract/recipes';
2
2
 
3
3
  export const labelRecipe = recipe(
4
4
  {
@@ -9,5 +9,3 @@ export const labelRecipe = recipe(
9
9
  },
10
10
  'text-field-label'
11
11
  );
12
-
13
- export type LabelVariants = RecipeVariants<typeof labelRecipe>;
@@ -1,2 +1 @@
1
1
  export { Textarea, type TextareaProps } from './';
2
- export { type TextareaVariants } from './styles.css';
@@ -1,4 +1,4 @@
1
- import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
1
+ import { recipe } from '@vanilla-extract/recipes';
2
2
 
3
3
  import { generateResponsiveMedia } from '../../../../styles/utils/generateResponsiveMedia';
4
4
  import { themeContract } from '../../../../theme/contract.css';
@@ -37,4 +37,3 @@ export const textareaRecipe = recipe(
37
37
  'text-area'
38
38
  );
39
39
 
40
- export type TextareaVariants = RecipeVariants<typeof textareaRecipe>;
@@ -1,5 +1,4 @@
1
1
  export { TextField, type TextFieldProps } from './';
2
- export { type TextFieldVariants } from './styles.css';
3
2
 
4
3
  export * from './Input/export';
5
4
  export * from './Label/export';
@@ -1,5 +1,5 @@
1
1
  import { style } from '@vanilla-extract/css';
2
- import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
2
+ import { recipe } from '@vanilla-extract/recipes';
3
3
  import { themeContract } from '../../../theme/contract.css';
4
4
 
5
5
  const textFieldBase = style({
@@ -29,4 +29,3 @@ export const textFieldRecipe = recipe(
29
29
  );
30
30
 
31
31
  export { messageContainer, errorMessage };
32
- export type TextFieldVariants = RecipeVariants<typeof textFieldRecipe>;
@@ -4,3 +4,4 @@ export * from './Row/export';
4
4
 
5
5
  export * from './TextField/export';
6
6
  export * from './Select/export';
7
+ export * from './Checkbox/export';
@@ -1287,6 +1287,7 @@ export const themeContract = createGlobalThemeContract({
1287
1287
  '2xl': 'latte-textField-input-paddingLeft-2xl',
1288
1288
  },
1289
1289
  },
1290
+
1290
1291
  },
1291
1292
 
1292
1293
  consentCookie: {
@@ -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
- };
@@ -1,12 +0,0 @@
1
- /**
2
- * Utility type that normalizes Vanilla Extract's RecipeVariants by removing
3
- * optional keys and filtering out `undefined` from both the variant object
4
- * and its individual properties.
5
- *
6
- * Ensures that variants become strictly typed, fully defined, and safe to use
7
- * in Storybook controls and component props.
8
- */
9
-
10
- export type CleanRecipeVariants<T> = NonNullable<{
11
- [K in keyof T]-?: Exclude<T[K], undefined>;
12
- }>;