@kalink-ui/seedly 0.8.1 → 0.10.0
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/CHANGELOG.md +20 -0
- package/package.json +26 -18
- package/src/components/box/box.css.ts +6 -15
- package/src/components/box/box.tsx +2 -2
- package/src/components/box/index.ts +1 -1
- package/src/components/button/button.css.ts +45 -48
- package/src/components/button/button.tsx +11 -8
- package/src/components/button/index.ts +1 -1
- package/src/components/button-icon/button-icon.css.ts +90 -0
- package/src/components/button-icon/button-icon.tsx +23 -0
- package/src/components/button-icon/index.ts +1 -0
- package/src/components/card/card.css.ts +42 -0
- package/src/components/card/card.tsx +76 -0
- package/src/components/card/index.ts +1 -0
- package/src/components/center/center.css.ts +1 -1
- package/src/components/center/center.tsx +2 -2
- package/src/components/center/index.ts +1 -1
- package/src/components/cluster/cluster.css.ts +18 -1
- package/src/components/cluster/cluster.tsx +2 -2
- package/src/components/cluster/index.ts +1 -1
- package/src/components/cover/cover.css.ts +1 -1
- package/src/components/divider/divider.css.ts +11 -0
- package/src/components/divider/divider.tsx +11 -0
- package/src/components/divider/index.ts +1 -0
- package/src/components/form-field/form-field-context.ts +18 -0
- package/src/components/form-field/form-field-control.tsx +34 -0
- package/src/components/form-field/form-field-description.tsx +16 -0
- package/src/components/form-field/form-field-error.tsx +22 -0
- package/src/components/form-field/form-field-item-context.ts +6 -0
- package/src/components/form-field/form-field-item.tsx +28 -0
- package/src/components/form-field/form-field-label.tsx +27 -0
- package/src/components/form-field/form-field-message.tsx +33 -0
- package/src/components/form-field/form-field.css.ts +97 -0
- package/src/components/form-field/form-field.tsx +56 -0
- package/src/components/form-field/index.ts +9 -0
- package/src/components/frame/frame.css.ts +8 -8
- package/src/components/frame/frame.tsx +2 -6
- package/src/components/frame/index.ts +1 -1
- package/src/components/grid/grid.css.ts +1 -1
- package/src/components/heading/heading.css.ts +49 -2
- package/src/components/heading/heading.tsx +123 -69
- package/src/components/heading/index.ts +2 -1
- package/src/components/index.ts +27 -14
- package/src/components/input/index.ts +2 -0
- package/src/components/input/input-wrapper.tsx +58 -0
- package/src/components/input/input.css.ts +250 -0
- package/src/components/input/input.tsx +56 -0
- package/src/components/label/index.ts +1 -0
- package/src/components/label/label.css.ts +37 -0
- package/src/components/label/label.tsx +23 -0
- package/src/components/loader/index.ts +1 -0
- package/src/components/loader/loader.css.ts +109 -0
- package/src/components/loader/moon-loader.tsx +43 -0
- package/src/components/loader-overlay/index.ts +1 -0
- package/src/components/loader-overlay/loader-overlay.css.ts +35 -0
- package/src/components/loader-overlay/loader-overlay.tsx +28 -0
- package/src/components/menu/index.ts +2 -0
- package/src/components/menu/menu-item.css.ts +79 -0
- package/src/components/menu/menu-separator.css.ts +53 -0
- package/src/components/popover/index.ts +3 -0
- package/src/components/popover/popover-content.css.ts +107 -0
- package/src/components/popover/popover-content.tsx +78 -0
- package/src/components/popover/popover.tsx +6 -0
- package/src/components/scroll-area/index.ts +1 -0
- package/src/components/scroll-area/scroll-area.css.ts +72 -0
- package/src/components/scroll-area/scroll-area.tsx +39 -0
- package/src/components/scroll-area/scroll-bar.tsx +37 -0
- package/src/components/seed/index.ts +1 -1
- package/src/components/seed/seed.tsx +39 -2
- package/src/components/select/index.ts +5 -0
- package/src/components/select/select-content.css.ts +22 -0
- package/src/components/select/select-content.tsx +51 -0
- package/src/components/select/select-item.css.ts +24 -0
- package/src/components/select/select-item.tsx +24 -0
- package/src/components/select/select-root.tsx +14 -0
- package/src/components/select/select-trigger.css.ts +75 -0
- package/src/components/select/select-trigger.tsx +47 -0
- package/src/components/select/select.tsx +85 -0
- package/src/components/sheet/index.ts +5 -0
- package/src/components/sheet/sheet-content.css.ts +143 -0
- package/src/components/sheet/sheet-content.tsx +43 -0
- package/src/components/sheet/sheet-description.tsx +21 -0
- package/src/components/sheet/sheet-footer.tsx +15 -0
- package/src/components/sheet/sheet-header.css.ts +35 -0
- package/src/components/sheet/sheet-header.tsx +32 -0
- package/src/components/sheet/sheet-overlay.css.ts +43 -0
- package/src/components/sheet/sheet-overlay.tsx +14 -0
- package/src/components/sheet/sheet-title.tsx +31 -0
- package/src/components/sheet/sheet.tsx +8 -0
- package/src/components/stack/index.ts +1 -1
- package/src/components/stack/stack.tsx +2 -2
- package/src/components/text/index.ts +6 -0
- package/src/components/text/text.css.ts +173 -7
- package/src/components/text/text.tsx +19 -27
- package/src/components/text-field/index.ts +1 -0
- package/src/components/text-field/text-field.css.ts +3 -0
- package/src/components/text-field/text-field.tsx +64 -0
- package/src/components/textarea/index.ts +1 -0
- package/src/components/textarea/textarea-input.tsx +20 -0
- package/src/components/textarea/textarea.css.ts +10 -0
- package/src/components/textarea/textarea.tsx +69 -0
- package/src/styles/define-responsive-properties.ts +242 -0
- package/src/styles/extract-sprinkles-props.ts +29 -35
- package/src/styles/index.ts +9 -0
- package/src/styles/reset.css.ts +1 -0
- package/src/styles/system-contract.css.ts +0 -2
- package/src/styles/typography.css.ts +10 -5
- package/src/styles/visually-hidden.css.ts +21 -0
- package/build-storybook.log +0 -67
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { PolymorphicComponentProps } from '@kalink-ui/dibbly';
|
|
2
|
+
import { clsx } from 'clsx';
|
|
3
|
+
import { ElementType } from 'react';
|
|
4
|
+
|
|
5
|
+
import { Box, Cluster, Stack } from '@kalink-ui/seedly';
|
|
6
|
+
import { Spacing } from '@kalink-ui/seedly/styles';
|
|
7
|
+
|
|
8
|
+
import { BoxProps } from '../box';
|
|
9
|
+
import { ClusterProps } from '../cluster';
|
|
10
|
+
|
|
11
|
+
import { card, cardBody, cardFooter, cardHeader } from './card.css';
|
|
12
|
+
|
|
13
|
+
export type CardRootElement = 'article' | 'div';
|
|
14
|
+
|
|
15
|
+
export type CardProps<TUse extends CardRootElement = 'article'> =
|
|
16
|
+
BoxProps<TUse> & {
|
|
17
|
+
verticalSpacing?: Spacing;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function Card<TUse extends CardRootElement = 'article'>(
|
|
21
|
+
props: CardProps<TUse>,
|
|
22
|
+
) {
|
|
23
|
+
const {
|
|
24
|
+
use = 'article',
|
|
25
|
+
variant = 'solid',
|
|
26
|
+
className,
|
|
27
|
+
spacing = 4,
|
|
28
|
+
verticalSpacing,
|
|
29
|
+
children,
|
|
30
|
+
...rest
|
|
31
|
+
} = props;
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<Box
|
|
35
|
+
use={use as CardProps['use']}
|
|
36
|
+
variant={variant}
|
|
37
|
+
spacing={spacing}
|
|
38
|
+
className={clsx(card, className)}
|
|
39
|
+
{...rest}
|
|
40
|
+
>
|
|
41
|
+
<Stack spacing={verticalSpacing ?? spacing}>{children}</Stack>
|
|
42
|
+
</Box>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
Card.Header = function CardHeader<TUse extends ElementType = 'header'>(
|
|
47
|
+
props: PolymorphicComponentProps<TUse>,
|
|
48
|
+
) {
|
|
49
|
+
const { use: Comp = 'header', className, ...rest } = props;
|
|
50
|
+
|
|
51
|
+
return <Comp className={clsx(cardHeader, className)} {...rest} />;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
Card.Body = function CardBody<TUse extends ElementType = 'div'>(
|
|
55
|
+
props: PolymorphicComponentProps<TUse>,
|
|
56
|
+
) {
|
|
57
|
+
const { use: Comp = 'div', className, ...rest } = props;
|
|
58
|
+
|
|
59
|
+
return <Comp className={clsx(cardBody, className)} {...rest} />;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
type CardFooterProps<TUse extends ElementType = 'footer'> = ClusterProps<TUse>;
|
|
63
|
+
|
|
64
|
+
Card.Footer = function CardFooter<TUse extends ElementType = 'footer'>(
|
|
65
|
+
props: CardFooterProps<TUse>,
|
|
66
|
+
) {
|
|
67
|
+
const { use = 'footer', className, ...rest } = props;
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<Cluster
|
|
71
|
+
use={use as CardFooterProps['use']}
|
|
72
|
+
className={clsx(cardFooter, className)}
|
|
73
|
+
{...rest}
|
|
74
|
+
/>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Card, type CardProps, type CardRootElement } from './card';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { recipe, type RecipeVariants } from '@vanilla-extract/recipes';
|
|
2
2
|
|
|
3
|
-
import { mapContractVars
|
|
3
|
+
import { mapContractVars, sys } from '../../styles';
|
|
4
4
|
import { components } from '../../styles/layers.css';
|
|
5
5
|
|
|
6
6
|
export const centerRecipe = recipe({
|
|
@@ -4,8 +4,8 @@ import { ElementType } from 'react';
|
|
|
4
4
|
|
|
5
5
|
import { centerRecipe, CenterVariants } from './center.css';
|
|
6
6
|
|
|
7
|
-
type CenterProps<TUse extends ElementType> =
|
|
8
|
-
CenterVariants;
|
|
7
|
+
export type CenterProps<TUse extends ElementType> =
|
|
8
|
+
PolymorphicComponentProps<TUse> & CenterVariants;
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* A custom element for centering a block-level element horizontally,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Center } from './center';
|
|
1
|
+
export { Center, type CenterProps } from './center';
|
|
2
2
|
export { centerRecipe, type CenterVariants } from './center.css';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { recipe, type RecipeVariants } from '@vanilla-extract/recipes';
|
|
2
2
|
|
|
3
|
-
import { mapContractVars
|
|
3
|
+
import { mapContractVars, sys } from '../../styles';
|
|
4
4
|
import { components } from '../../styles/layers.css';
|
|
5
5
|
|
|
6
6
|
export const clusterRecipe = recipe({
|
|
@@ -115,6 +115,23 @@ export const clusterRecipe = recipe({
|
|
|
115
115
|
},
|
|
116
116
|
},
|
|
117
117
|
},
|
|
118
|
+
|
|
119
|
+
direction: {
|
|
120
|
+
row: {
|
|
121
|
+
'@layer': {
|
|
122
|
+
[components]: {
|
|
123
|
+
flexDirection: 'row',
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
rowReverse: {
|
|
128
|
+
'@layer': {
|
|
129
|
+
[components]: {
|
|
130
|
+
flexDirection: 'row-reverse',
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
},
|
|
118
135
|
},
|
|
119
136
|
});
|
|
120
137
|
|
|
@@ -4,8 +4,8 @@ import { ElementType } from 'react';
|
|
|
4
4
|
|
|
5
5
|
import { clusterRecipe, ClusterVariants } from './cluster.css';
|
|
6
6
|
|
|
7
|
-
type ClusterProps<TUse extends ElementType> =
|
|
8
|
-
ClusterVariants;
|
|
7
|
+
export type ClusterProps<TUse extends ElementType> =
|
|
8
|
+
PolymorphicComponentProps<TUse> & ClusterVariants;
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* A custom element for grouping items, with control over the margin between them
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Cluster } from './cluster';
|
|
1
|
+
export { Cluster, type ClusterProps } from './cluster';
|
|
2
2
|
export { clusterRecipe, type ClusterVariants } from './cluster.css';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createVar, globalStyle } from '@vanilla-extract/css';
|
|
2
2
|
import { recipe, type RecipeVariants } from '@vanilla-extract/recipes';
|
|
3
3
|
|
|
4
|
-
import { sys
|
|
4
|
+
import { sys, mapContractVars } from '../../styles';
|
|
5
5
|
import { components } from '../../styles/layers.css';
|
|
6
6
|
|
|
7
7
|
const spaceVar = createVar();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Divider, type DividerProps } from './divider';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { createRequiredContext } from '@kalink-ui/dibbly';
|
|
4
|
+
|
|
5
|
+
interface FormFieldContext {
|
|
6
|
+
name: string;
|
|
7
|
+
registerMessageId: (id: string) => void;
|
|
8
|
+
unRegisterMessageId: (id: string) => void;
|
|
9
|
+
messageIds: string[];
|
|
10
|
+
errors?: string | null;
|
|
11
|
+
hideErrorMessage: boolean;
|
|
12
|
+
label: string;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
hideLabel: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const [useFormFieldContext, FormFieldContextProvider] =
|
|
18
|
+
createRequiredContext<FormFieldContext>();
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
cloneElement,
|
|
5
|
+
HTMLAttributes,
|
|
6
|
+
isValidElement,
|
|
7
|
+
ReactElement,
|
|
8
|
+
} from 'react';
|
|
9
|
+
|
|
10
|
+
import { useFormFieldContext } from './form-field-context';
|
|
11
|
+
import { useFormFieldItemContext } from './form-field-item-context';
|
|
12
|
+
|
|
13
|
+
export interface FormFieldControlProps extends HTMLAttributes<HTMLElement> {
|
|
14
|
+
children: ReactElement;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function FormFieldControl({
|
|
18
|
+
children,
|
|
19
|
+
...props
|
|
20
|
+
}: FormFieldControlProps) {
|
|
21
|
+
const { messageIds, errors } = useFormFieldContext();
|
|
22
|
+
const { id } = useFormFieldItemContext();
|
|
23
|
+
|
|
24
|
+
if (!isValidElement(children)) {
|
|
25
|
+
throw new Error('FormFieldControl must have a valid child');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return cloneElement(children, {
|
|
29
|
+
id,
|
|
30
|
+
'aria-describedby': messageIds.join(' ') || undefined,
|
|
31
|
+
'aria-invalid': !!errors || undefined,
|
|
32
|
+
...props,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useFormFieldItemContext } from './form-field-item-context';
|
|
4
|
+
import { FormFieldMessage, FormFieldMessageProps } from './form-field-message';
|
|
5
|
+
|
|
6
|
+
export type FormFieldDescriptionProps = Omit<FormFieldMessageProps, 'id'>;
|
|
7
|
+
|
|
8
|
+
export function FormFieldDescription(props: FormFieldDescriptionProps) {
|
|
9
|
+
const { id } = useFormFieldItemContext();
|
|
10
|
+
|
|
11
|
+
if (!props.children) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return <FormFieldMessage id={`${id}-description`} {...props} />;
|
|
16
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useFormFieldContext } from './form-field-context';
|
|
4
|
+
import { useFormFieldItemContext } from './form-field-item-context';
|
|
5
|
+
import { FormFieldMessage, FormFieldMessageProps } from './form-field-message';
|
|
6
|
+
|
|
7
|
+
export type FormFieldErrorProps = Omit<FormFieldMessageProps, 'id'>;
|
|
8
|
+
|
|
9
|
+
export function FormFieldError(props: FormFieldErrorProps) {
|
|
10
|
+
const { errors, hideErrorMessage } = useFormFieldContext();
|
|
11
|
+
const { id } = useFormFieldItemContext();
|
|
12
|
+
|
|
13
|
+
if (!errors || hideErrorMessage) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<FormFieldMessage id={`${id}-error`} error {...props}>
|
|
19
|
+
{errors}
|
|
20
|
+
</FormFieldMessage>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { PolymorphicComponentProps } from '@kalink-ui/dibbly';
|
|
4
|
+
import { ElementType, useId } from 'react';
|
|
5
|
+
|
|
6
|
+
import { useFormFieldContext } from './form-field-context';
|
|
7
|
+
import { FormFieldItemContextProvider } from './form-field-item-context';
|
|
8
|
+
import { formFieldStyle } from './form-field.css';
|
|
9
|
+
|
|
10
|
+
export type FormFieldItemProps<TUse extends ElementType = 'div'> =
|
|
11
|
+
PolymorphicComponentProps<TUse>;
|
|
12
|
+
|
|
13
|
+
export function FormFieldItem<TUse extends ElementType = 'div'>(
|
|
14
|
+
props: FormFieldItemProps<TUse>,
|
|
15
|
+
) {
|
|
16
|
+
const id = useId();
|
|
17
|
+
const { errors, disabled } = useFormFieldContext();
|
|
18
|
+
|
|
19
|
+
const { use: Comp = 'div', className, children, ...rest } = props;
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<FormFieldItemContextProvider value={{ id }}>
|
|
23
|
+
<Comp className={formFieldStyle({ error: !!errors, disabled })} {...rest}>
|
|
24
|
+
{children}
|
|
25
|
+
</Comp>
|
|
26
|
+
</FormFieldItemContextProvider>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { clsx } from 'clsx';
|
|
2
|
+
|
|
3
|
+
import { visuallyHidden } from '../../styles';
|
|
4
|
+
import { Label, LabelProps } from '../label';
|
|
5
|
+
|
|
6
|
+
import { useFormFieldContext } from './form-field-context';
|
|
7
|
+
import { useFormFieldItemContext } from './form-field-item-context';
|
|
8
|
+
|
|
9
|
+
export function FormFieldLabel({
|
|
10
|
+
className,
|
|
11
|
+
children,
|
|
12
|
+
required,
|
|
13
|
+
...props
|
|
14
|
+
}: LabelProps) {
|
|
15
|
+
const { errors, hideLabel } = useFormFieldContext();
|
|
16
|
+
const { id } = useFormFieldItemContext();
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<Label
|
|
20
|
+
className={clsx(visuallyHidden({ hidden: hideLabel }), className)}
|
|
21
|
+
htmlFor={id}
|
|
22
|
+
error={!!errors}
|
|
23
|
+
required={required}
|
|
24
|
+
{...props}
|
|
25
|
+
>{`${children}${required ? ' *' : ''}`}</Label>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { HTMLAttributes, useEffect } from 'react';
|
|
4
|
+
|
|
5
|
+
import { useFormFieldContext } from './form-field-context';
|
|
6
|
+
import { formFieldMessageStyle } from './form-field.css';
|
|
7
|
+
|
|
8
|
+
export type FormFieldMessageProps = HTMLAttributes<HTMLDivElement> & {
|
|
9
|
+
id: string;
|
|
10
|
+
error?: boolean;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function FormFieldMessage({
|
|
14
|
+
className,
|
|
15
|
+
children,
|
|
16
|
+
id,
|
|
17
|
+
error,
|
|
18
|
+
...props
|
|
19
|
+
}: FormFieldMessageProps) {
|
|
20
|
+
const { registerMessageId, unRegisterMessageId } = useFormFieldContext();
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
registerMessageId(id);
|
|
24
|
+
|
|
25
|
+
return () => unRegisterMessageId(id);
|
|
26
|
+
}, [id, registerMessageId, unRegisterMessageId]);
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<div id={id} className={formFieldMessageStyle} {...props}>
|
|
30
|
+
{children}
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { createGlobalTheme, style } from '@vanilla-extract/css';
|
|
2
|
+
import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
|
|
3
|
+
|
|
4
|
+
import { sys, typography } from '../../styles';
|
|
5
|
+
import { components } from '../../styles/layers.css';
|
|
6
|
+
|
|
7
|
+
export const formFieldVars = createGlobalTheme(':root', {
|
|
8
|
+
'@layer': components,
|
|
9
|
+
|
|
10
|
+
spacing: {
|
|
11
|
+
vertical: sys.spacing[2],
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
color: {
|
|
15
|
+
foreground: sys.color.foreground,
|
|
16
|
+
background: sys.color.background,
|
|
17
|
+
outline: sys.color.foreground,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export const formFieldStyle = recipe({
|
|
22
|
+
base: {
|
|
23
|
+
'@layer': {
|
|
24
|
+
[components]: {
|
|
25
|
+
display: 'flex',
|
|
26
|
+
flexDirection: 'column',
|
|
27
|
+
gap: formFieldVars.spacing.vertical,
|
|
28
|
+
|
|
29
|
+
width: '100%',
|
|
30
|
+
maxWidth: '100%',
|
|
31
|
+
|
|
32
|
+
color: formFieldVars.color.foreground,
|
|
33
|
+
|
|
34
|
+
selectors: {
|
|
35
|
+
'&:disabled, &:has(:disabled)': {
|
|
36
|
+
cursor: 'not-allowed',
|
|
37
|
+
|
|
38
|
+
vars: {
|
|
39
|
+
[formFieldVars.color.foreground]:
|
|
40
|
+
`color(from ${sys.color.foreground} srgb r g b / 0.38)`,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
'&[aria-invalid], &:has([aria-invalid])': {
|
|
45
|
+
vars: {
|
|
46
|
+
[formFieldVars.color.foreground]: 'red',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
variants: {
|
|
55
|
+
error: {
|
|
56
|
+
true: {
|
|
57
|
+
'@layer': {
|
|
58
|
+
[components]: {
|
|
59
|
+
vars: {
|
|
60
|
+
[formFieldVars.color.foreground]: 'red',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
disabled: {
|
|
68
|
+
true: {
|
|
69
|
+
'@layer': {
|
|
70
|
+
[components]: {
|
|
71
|
+
cursor: 'not-allowed',
|
|
72
|
+
|
|
73
|
+
vars: {
|
|
74
|
+
[formFieldVars.color.foreground]:
|
|
75
|
+
`color(from ${sys.color.foreground} srgb r g b / ${sys.state.muted.light})`,
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
export const formFieldMessageStyle = style([
|
|
85
|
+
typography.body.small,
|
|
86
|
+
{
|
|
87
|
+
'@layer': {
|
|
88
|
+
[components]: {
|
|
89
|
+
display: 'block',
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
]);
|
|
94
|
+
|
|
95
|
+
export type FormFieldVariants = NonNullable<
|
|
96
|
+
RecipeVariants<typeof formFieldStyle>
|
|
97
|
+
>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState, useCallback, ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
import { FormFieldContextProvider } from './form-field-context';
|
|
6
|
+
|
|
7
|
+
export interface FormFieldProps {
|
|
8
|
+
name: string;
|
|
9
|
+
label: string;
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
errors?: string | null;
|
|
12
|
+
hideErrorMessage: boolean;
|
|
13
|
+
hideLabel: boolean;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function FormField({
|
|
18
|
+
name,
|
|
19
|
+
label,
|
|
20
|
+
children,
|
|
21
|
+
errors,
|
|
22
|
+
hideErrorMessage = false,
|
|
23
|
+
hideLabel = false,
|
|
24
|
+
disabled,
|
|
25
|
+
}: FormFieldProps) {
|
|
26
|
+
const [messageIds, setMessageIds] = useState<string[]>([]);
|
|
27
|
+
|
|
28
|
+
const registerMessageId = useCallback(
|
|
29
|
+
(id: string) => setMessageIds((ids) => [...new Set([...ids, id])]),
|
|
30
|
+
[setMessageIds],
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const unRegisterMessageId = useCallback(
|
|
34
|
+
(id: string) =>
|
|
35
|
+
setMessageIds((ids) => ids.filter((current) => current !== id)),
|
|
36
|
+
[setMessageIds],
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<FormFieldContextProvider
|
|
41
|
+
value={{
|
|
42
|
+
name,
|
|
43
|
+
registerMessageId,
|
|
44
|
+
unRegisterMessageId,
|
|
45
|
+
messageIds,
|
|
46
|
+
errors,
|
|
47
|
+
hideErrorMessage,
|
|
48
|
+
label,
|
|
49
|
+
disabled,
|
|
50
|
+
hideLabel,
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
{children}
|
|
54
|
+
</FormFieldContextProvider>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { useFormFieldContext } from './form-field-context';
|
|
2
|
+
export { useFormFieldItemContext } from './form-field-item-context';
|
|
3
|
+
export { formFieldStyle } from './form-field.css';
|
|
4
|
+
export { FormFieldControl } from './form-field-control';
|
|
5
|
+
export { FormFieldDescription } from './form-field-description';
|
|
6
|
+
export { FormFieldError } from './form-field-error';
|
|
7
|
+
export { FormField } from './form-field';
|
|
8
|
+
export { FormFieldItem } from './form-field-item';
|
|
9
|
+
export { FormFieldLabel } from './form-field-label';
|
|
@@ -3,7 +3,7 @@ import { recipe, type RecipeVariants } from '@vanilla-extract/recipes';
|
|
|
3
3
|
|
|
4
4
|
import { components } from '../../styles/layers.css';
|
|
5
5
|
|
|
6
|
-
const
|
|
6
|
+
export const frameRatioVar = createVar();
|
|
7
7
|
|
|
8
8
|
const baseFrame = style({
|
|
9
9
|
'@layer': {
|
|
@@ -14,7 +14,7 @@ const baseFrame = style({
|
|
|
14
14
|
|
|
15
15
|
overflow: 'hidden',
|
|
16
16
|
|
|
17
|
-
aspectRatio:
|
|
17
|
+
aspectRatio: frameRatioVar,
|
|
18
18
|
},
|
|
19
19
|
},
|
|
20
20
|
});
|
|
@@ -31,7 +31,7 @@ export const frameRecipe = recipe({
|
|
|
31
31
|
'@layer': {
|
|
32
32
|
[components]: {
|
|
33
33
|
vars: {
|
|
34
|
-
[
|
|
34
|
+
[frameRatioVar]: '1 / 1',
|
|
35
35
|
},
|
|
36
36
|
},
|
|
37
37
|
},
|
|
@@ -40,7 +40,7 @@ export const frameRecipe = recipe({
|
|
|
40
40
|
'@layer': {
|
|
41
41
|
[components]: {
|
|
42
42
|
vars: {
|
|
43
|
-
[
|
|
43
|
+
[frameRatioVar]: '3 / 2',
|
|
44
44
|
},
|
|
45
45
|
},
|
|
46
46
|
},
|
|
@@ -49,7 +49,7 @@ export const frameRecipe = recipe({
|
|
|
49
49
|
'@layer': {
|
|
50
50
|
[components]: {
|
|
51
51
|
vars: {
|
|
52
|
-
[
|
|
52
|
+
[frameRatioVar]: '2 / 3',
|
|
53
53
|
},
|
|
54
54
|
},
|
|
55
55
|
},
|
|
@@ -58,7 +58,7 @@ export const frameRecipe = recipe({
|
|
|
58
58
|
'@layer': {
|
|
59
59
|
[components]: {
|
|
60
60
|
vars: {
|
|
61
|
-
[
|
|
61
|
+
[frameRatioVar]: '4 / 3',
|
|
62
62
|
},
|
|
63
63
|
},
|
|
64
64
|
},
|
|
@@ -67,7 +67,7 @@ export const frameRecipe = recipe({
|
|
|
67
67
|
'@layer': {
|
|
68
68
|
[components]: {
|
|
69
69
|
vars: {
|
|
70
|
-
[
|
|
70
|
+
[frameRatioVar]: '16 / 9',
|
|
71
71
|
},
|
|
72
72
|
},
|
|
73
73
|
},
|
|
@@ -76,7 +76,7 @@ export const frameRecipe = recipe({
|
|
|
76
76
|
'@layer': {
|
|
77
77
|
[components]: {
|
|
78
78
|
vars: {
|
|
79
|
-
[
|
|
79
|
+
[frameRatioVar]: '9 / 16',
|
|
80
80
|
},
|
|
81
81
|
},
|
|
82
82
|
},
|
|
@@ -12,12 +12,8 @@ type FrameProps<TUse extends ElementType> = PolymorphicComponentProps<TUse> &
|
|
|
12
12
|
*
|
|
13
13
|
* https://every-layout.dev/layouts/frame
|
|
14
14
|
*/
|
|
15
|
-
export function Frame<TUse extends ElementType>({
|
|
16
|
-
ratio,
|
|
17
|
-
className,
|
|
18
|
-
...props
|
|
19
|
-
}: FrameProps<TUse>) {
|
|
20
|
-
const { use: Comp = 'div', ...rest } = props;
|
|
15
|
+
export function Frame<TUse extends ElementType>(props: FrameProps<TUse>) {
|
|
16
|
+
const { use: Comp = 'div', className, ratio, ...rest } = props;
|
|
21
17
|
|
|
22
18
|
return <Comp className={clsx(frameRecipe({ ratio }), className)} {...rest} />;
|
|
23
19
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { Frame } from './frame';
|
|
2
|
-
export { frameRecipe, type FrameVariants } from './frame.css';
|
|
2
|
+
export { frameRecipe, frameRatioVar, type FrameVariants } from './frame.css';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createVar } from '@vanilla-extract/css';
|
|
2
2
|
import { recipe, type RecipeVariants } from '@vanilla-extract/recipes';
|
|
3
3
|
|
|
4
|
-
import { sys
|
|
4
|
+
import { sys, mapContractVars } from '../../styles';
|
|
5
5
|
import { components } from '../../styles/layers.css';
|
|
6
6
|
|
|
7
7
|
export const minSizeVar = createVar();
|