@kalink-ui/seedly 0.1.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/package.json +78 -0
- package/src/components/.DS_Store +0 -0
- package/src/components/box/box.css.ts +47 -0
- package/src/components/box/box.stories.tsx +29 -0
- package/src/components/box/box.tsx +55 -0
- package/src/components/box/index.ts +2 -0
- package/src/components/button/button.css.ts +33 -0
- package/src/components/button/button.stories.tsx +31 -0
- package/src/components/button/button.tsx +33 -0
- package/src/components/button/index.ts +2 -0
- package/src/components/center/.DS_Store +0 -0
- package/src/components/center/center.css.ts +35 -0
- package/src/components/center/center.stories.tsx +31 -0
- package/src/components/center/center.tsx +46 -0
- package/src/components/center/index.ts +2 -0
- package/src/components/cluster/.DS_Store +0 -0
- package/src/components/cluster/cluster.css.ts +60 -0
- package/src/components/cluster/cluster.stories.tsx +37 -0
- package/src/components/cluster/cluster.tsx +46 -0
- package/src/components/cluster/index.ts +2 -0
- package/src/components/cover/.DS_Store +0 -0
- package/src/components/cover/cover.css.ts +60 -0
- package/src/components/cover/cover.stories.tsx +45 -0
- package/src/components/cover/cover.tsx +55 -0
- package/src/components/cover/index.ts +2 -0
- package/src/components/frame/.DS_Store +0 -0
- package/src/components/frame/frame.css.ts +61 -0
- package/src/components/frame/frame.stories.tsx +39 -0
- package/src/components/frame/frame.tsx +28 -0
- package/src/components/frame/index.ts +2 -0
- package/src/components/grid/.DS_Store +0 -0
- package/src/components/grid/grid.css.ts +26 -0
- package/src/components/grid/grid.stories.tsx +50 -0
- package/src/components/grid/grid.tsx +48 -0
- package/src/components/grid/index.ts +2 -0
- package/src/components/layout.mdx +206 -0
- package/src/components/sidebar/.DS_Store +0 -0
- package/src/components/sidebar/index.ts +2 -0
- package/src/components/sidebar/sidebar.css.ts +68 -0
- package/src/components/sidebar/sidebar.stories.tsx +60 -0
- package/src/components/sidebar/sidebar.tsx +77 -0
- package/src/components/stack/.DS_Store +0 -0
- package/src/components/stack/index.ts +2 -0
- package/src/components/stack/stack.css.ts +36 -0
- package/src/components/stack/stack.stories.tsx +72 -0
- package/src/components/stack/stack.tsx +44 -0
- package/src/components/switcher/.DS_Store +0 -0
- package/src/components/switcher/index.ts +2 -0
- package/src/components/switcher/switcher.css.ts +93 -0
- package/src/components/switcher/switcher.stories.tsx +66 -0
- package/src/components/switcher/switcher.tsx +53 -0
- package/src/styles/index.ts +2 -0
- package/src/styles/seed/.DS_Store +0 -0
- package/src/styles/seed/index.ts +1 -0
- package/src/styles/seed/seed.stories.tsx +52 -0
- package/src/styles/seed/seed.tsx +53 -0
- package/src/styles/styles.mdx +98 -0
- package/src/styles/system-contract.css.ts +144 -0
- package/src/types/index.ts +5 -0
- package/src/types/utils.types.ts +15 -0
- package/src/utils/__tests__/extract-sprinkles-props.test.ts +101 -0
- package/src/utils/__tests__/is-object.test.ts +24 -0
- package/src/utils/__tests__/map-contract-vars.test.ts +34 -0
- package/src/utils/arg-types/.DS_Store +0 -0
- package/src/utils/arg-types/arg-types-from-recipe.ts +37 -0
- package/src/utils/arg-types/arg-types-from-sprinkles.ts +43 -0
- package/src/utils/arg-types/common/composable.ts +13 -0
- package/src/utils/arg-types/common/index.ts +4 -0
- package/src/utils/arg-types/common/polymorphic.ts +14 -0
- package/src/utils/arg-types/common/referable.ts +10 -0
- package/src/utils/arg-types/common/stylable.ts +14 -0
- package/src/utils/arg-types/common-args.ts +26 -0
- package/src/utils/arg-types/index.ts +3 -0
- package/src/utils/extract-sprinkles-props.ts +46 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/is-object.ts +3 -0
- package/src/utils/map-contract-vars.ts +10 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { argTypesFromRecipe, CommonArgs, commonArgs } from '@/utils/arg-types';
|
|
2
|
+
|
|
3
|
+
import { Sidebar } from './sidebar';
|
|
4
|
+
import { sidebarRecipe } from './sidebar.css';
|
|
5
|
+
|
|
6
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
title: 'Layout/Sidebar',
|
|
10
|
+
component: Sidebar,
|
|
11
|
+
tags: ['autodocs'],
|
|
12
|
+
args: {
|
|
13
|
+
children: (
|
|
14
|
+
<>
|
|
15
|
+
<div>Sidebar</div>
|
|
16
|
+
<div>Main content</div>
|
|
17
|
+
</>
|
|
18
|
+
),
|
|
19
|
+
},
|
|
20
|
+
argTypes: {
|
|
21
|
+
...argTypesFromRecipe(sidebarRecipe),
|
|
22
|
+
|
|
23
|
+
...commonArgs([
|
|
24
|
+
CommonArgs.COMPOSABLE,
|
|
25
|
+
CommonArgs.POLYMORPHIC,
|
|
26
|
+
CommonArgs.STYLABLE,
|
|
27
|
+
CommonArgs.REFERABLE,
|
|
28
|
+
]),
|
|
29
|
+
|
|
30
|
+
sideWidth: {
|
|
31
|
+
table: {
|
|
32
|
+
category: 'Recipe props',
|
|
33
|
+
},
|
|
34
|
+
control: { type: 'range', min: 1, max: 100, step: 1 },
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
contentMinWidth: {
|
|
38
|
+
table: {
|
|
39
|
+
category: 'Recipe props',
|
|
40
|
+
},
|
|
41
|
+
control: { type: 'range', min: 1, max: 100, step: 1 },
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
render: ({ sideWidth, contentMinWidth, ...args }) => (
|
|
46
|
+
<Sidebar
|
|
47
|
+
{...{
|
|
48
|
+
...(sideWidth && { sideWidth: `${sideWidth}%` }),
|
|
49
|
+
...(contentMinWidth && { contentMinWidth: `${contentMinWidth}%` }),
|
|
50
|
+
}}
|
|
51
|
+
{...args}
|
|
52
|
+
/>
|
|
53
|
+
),
|
|
54
|
+
} satisfies Meta<typeof Sidebar>;
|
|
55
|
+
|
|
56
|
+
export default meta;
|
|
57
|
+
|
|
58
|
+
type Story = StoryObj<typeof Sidebar>;
|
|
59
|
+
|
|
60
|
+
export const Default: Story = {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
|
4
|
+
import { clsx } from 'clsx';
|
|
5
|
+
import { ElementType } from 'react';
|
|
6
|
+
|
|
7
|
+
import { PolymorphicComponentProps } from '@/types/utils.types';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
contentMinWidthVar,
|
|
11
|
+
sidebarRecipe,
|
|
12
|
+
SidebarVariants,
|
|
13
|
+
sideWidthVar,
|
|
14
|
+
} from './sidebar.css';
|
|
15
|
+
|
|
16
|
+
type SidebarProps<TUse extends ElementType> =
|
|
17
|
+
PolymorphicComponentProps<TUse> & {
|
|
18
|
+
/**
|
|
19
|
+
* The size of the side element
|
|
20
|
+
*/
|
|
21
|
+
sideWidth?: string;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The narrowest the content (main) element can be before wrapping.
|
|
25
|
+
* Should be a percentage.
|
|
26
|
+
*/
|
|
27
|
+
contentMinWidth?: string;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The side of the sidebar
|
|
31
|
+
*/
|
|
32
|
+
side?: SidebarVariants['side'];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The spacing between the sidebar and main content elements
|
|
36
|
+
*/
|
|
37
|
+
spacing?: SidebarVariants['spacing'];
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Whether the sidebar should stretch to fill the available space
|
|
41
|
+
*/
|
|
42
|
+
noStretch?: SidebarVariants['noStretch'];
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* A custom element for placing two elements side-by-side. If space permits,
|
|
47
|
+
* the sided element has a set width, and the companion takes up the rest
|
|
48
|
+
* of the available horizontal space. If not, the elements are collapsed into
|
|
49
|
+
* a single column, each taking up 100% of the horizontal space.
|
|
50
|
+
*
|
|
51
|
+
* https://every-layout.dev/layouts/sidebar/
|
|
52
|
+
*/
|
|
53
|
+
export const Sidebar = <TUse extends ElementType>({
|
|
54
|
+
side = 'left',
|
|
55
|
+
sideWidth,
|
|
56
|
+
contentMinWidth,
|
|
57
|
+
spacing,
|
|
58
|
+
noStretch,
|
|
59
|
+
className,
|
|
60
|
+
...props
|
|
61
|
+
}: SidebarProps<TUse>) => {
|
|
62
|
+
const { use: Comp = 'div', ...rest } = props;
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<Comp
|
|
66
|
+
className={clsx(
|
|
67
|
+
sidebarRecipe({ side, sideWidth: !!sideWidth, spacing, noStretch }),
|
|
68
|
+
className,
|
|
69
|
+
)}
|
|
70
|
+
style={assignInlineVars({
|
|
71
|
+
...(sideWidth && { [sideWidthVar]: sideWidth }),
|
|
72
|
+
...(contentMinWidth && { [contentMinWidthVar]: contentMinWidth }),
|
|
73
|
+
})}
|
|
74
|
+
{...rest}
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
Binary file
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createVar, globalStyle } from '@vanilla-extract/css';
|
|
2
|
+
import { recipe, type RecipeVariants } from '@vanilla-extract/recipes';
|
|
3
|
+
|
|
4
|
+
import { sys } from '@/styles/system-contract.css';
|
|
5
|
+
import { mapContractVars } from '@/utils/map-contract-vars';
|
|
6
|
+
|
|
7
|
+
const spacing = createVar();
|
|
8
|
+
|
|
9
|
+
export const stackRecipe = recipe({
|
|
10
|
+
base: {
|
|
11
|
+
display: 'flex',
|
|
12
|
+
flexDirection: 'column',
|
|
13
|
+
justifyContent: 'flex-start',
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
variants: {
|
|
17
|
+
recursive: {
|
|
18
|
+
true: {},
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
spacing: mapContractVars(sys.spacing, (key) => ({
|
|
22
|
+
vars: {
|
|
23
|
+
[spacing]: sys.spacing[key],
|
|
24
|
+
},
|
|
25
|
+
})),
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
globalStyle(
|
|
30
|
+
`${stackRecipe.classNames.base} > * + *, ${stackRecipe.classNames.variants.recursive.true} * + *`,
|
|
31
|
+
{
|
|
32
|
+
marginBlockStart: spacing,
|
|
33
|
+
},
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
export type StackVariants = NonNullable<RecipeVariants<typeof stackRecipe>>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { argTypesFromRecipe, CommonArgs, commonArgs } from '@/utils/arg-types';
|
|
2
|
+
|
|
3
|
+
import { Stack } from './stack';
|
|
4
|
+
import { stackRecipe } from './stack.css';
|
|
5
|
+
|
|
6
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
title: 'Layout/Stack',
|
|
10
|
+
component: Stack,
|
|
11
|
+
tags: ['autodocs'],
|
|
12
|
+
parameters: {
|
|
13
|
+
layout: 'fullscreen',
|
|
14
|
+
},
|
|
15
|
+
args: {
|
|
16
|
+
children: (
|
|
17
|
+
<>
|
|
18
|
+
<div>Stack element one</div>
|
|
19
|
+
<div>Stack element two</div>
|
|
20
|
+
<div>Stack element three</div>
|
|
21
|
+
</>
|
|
22
|
+
),
|
|
23
|
+
},
|
|
24
|
+
argTypes: {
|
|
25
|
+
...argTypesFromRecipe(stackRecipe),
|
|
26
|
+
|
|
27
|
+
...commonArgs([
|
|
28
|
+
CommonArgs.COMPOSABLE,
|
|
29
|
+
CommonArgs.POLYMORPHIC,
|
|
30
|
+
CommonArgs.STYLABLE,
|
|
31
|
+
CommonArgs.REFERABLE,
|
|
32
|
+
]),
|
|
33
|
+
},
|
|
34
|
+
} satisfies Meta<typeof Stack>;
|
|
35
|
+
|
|
36
|
+
export default meta;
|
|
37
|
+
|
|
38
|
+
type Story = StoryObj<typeof Stack>;
|
|
39
|
+
|
|
40
|
+
export const Default: Story = {};
|
|
41
|
+
|
|
42
|
+
export const Nested: Story = {
|
|
43
|
+
args: {
|
|
44
|
+
recursive: true,
|
|
45
|
+
spacing: 4,
|
|
46
|
+
children: (
|
|
47
|
+
<>
|
|
48
|
+
<div>Stack element one</div>
|
|
49
|
+
<div>
|
|
50
|
+
<div>Stack element two</div>
|
|
51
|
+
<div>Stack element three</div>
|
|
52
|
+
</div>
|
|
53
|
+
<div>Stack element four</div>
|
|
54
|
+
</>
|
|
55
|
+
),
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const AsList: Story = {
|
|
60
|
+
args: {
|
|
61
|
+
spacing: 4,
|
|
62
|
+
use: 'ol',
|
|
63
|
+
children: (
|
|
64
|
+
<>
|
|
65
|
+
<li>Stack element one</li>
|
|
66
|
+
<li>Stack element two</li>
|
|
67
|
+
<li>Stack element three</li>
|
|
68
|
+
<li>Stack element four</li>
|
|
69
|
+
</>
|
|
70
|
+
),
|
|
71
|
+
},
|
|
72
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { clsx } from 'clsx';
|
|
2
|
+
import { ElementType } from 'react';
|
|
3
|
+
|
|
4
|
+
import { PolymorphicComponentProps } from '@/types/utils.types';
|
|
5
|
+
|
|
6
|
+
import { stackRecipe, StackVariants } from './stack.css';
|
|
7
|
+
|
|
8
|
+
type StackProps<TUse extends ElementType> = PolymorphicComponentProps<TUse> & {
|
|
9
|
+
/**
|
|
10
|
+
* Whether the stack spacing should be applied recursively
|
|
11
|
+
*/
|
|
12
|
+
recursive?: StackVariants['recursive'];
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The spacing between items
|
|
16
|
+
*/
|
|
17
|
+
spacing?: StackVariants['spacing'];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A custom element for injecting white space (margin) between flow
|
|
22
|
+
* (block) elements along a vertical axis.
|
|
23
|
+
*
|
|
24
|
+
* `splitAfter` is not available in this implementation since it only
|
|
25
|
+
* works in a web component context where the css selector is
|
|
26
|
+
* dynamically generated.
|
|
27
|
+
*
|
|
28
|
+
* https://every-layout.dev/layouts/stack
|
|
29
|
+
*/
|
|
30
|
+
export const Stack = <TUse extends ElementType = 'div'>({
|
|
31
|
+
recursive,
|
|
32
|
+
spacing,
|
|
33
|
+
className,
|
|
34
|
+
...props
|
|
35
|
+
}: StackProps<TUse>) => {
|
|
36
|
+
const { use: Comp = 'div', ...rest } = props;
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<Comp
|
|
40
|
+
className={clsx(stackRecipe({ recursive, spacing }), className)}
|
|
41
|
+
{...rest}
|
|
42
|
+
/>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
Binary file
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { createVar, globalStyle } from '@vanilla-extract/css';
|
|
2
|
+
import { recipe, type RecipeVariants } from '@vanilla-extract/recipes';
|
|
3
|
+
|
|
4
|
+
import { sys } from '@/styles/system-contract.css';
|
|
5
|
+
import { mapContractVars } from '@/utils/map-contract-vars';
|
|
6
|
+
|
|
7
|
+
export const thresholdVar = createVar();
|
|
8
|
+
export const limitVar = createVar();
|
|
9
|
+
|
|
10
|
+
export const switcherRecipe = recipe({
|
|
11
|
+
base: {
|
|
12
|
+
display: 'flex',
|
|
13
|
+
flexWrap: 'wrap',
|
|
14
|
+
|
|
15
|
+
vars: {
|
|
16
|
+
[thresholdVar]: sys.layout.measure,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
variants: {
|
|
21
|
+
/**
|
|
22
|
+
* The space (margin) between the child elements
|
|
23
|
+
*/
|
|
24
|
+
spacing: mapContractVars(sys.spacing, (key) => ({
|
|
25
|
+
gap: sys.spacing[key],
|
|
26
|
+
})),
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The maximum number of elements allowed to appear in the horizontal configuration
|
|
30
|
+
*/
|
|
31
|
+
limit: {
|
|
32
|
+
2: {},
|
|
33
|
+
3: {},
|
|
34
|
+
4: {},
|
|
35
|
+
5: {},
|
|
36
|
+
6: {},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
globalStyle(`${switcherRecipe.classNames.base} > *`, {
|
|
42
|
+
flexBasis: `calc((${thresholdVar} - 100%) * 999)`,
|
|
43
|
+
flexGrow: 1,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
globalStyle(
|
|
47
|
+
`${switcherRecipe.classNames.variants.limit[2]} > :nth-last-child(n+3), ${
|
|
48
|
+
switcherRecipe.classNames.variants.limit[2]
|
|
49
|
+
} > :nth-last-child(n+3) ~ *`,
|
|
50
|
+
{
|
|
51
|
+
flexBasis: '100%',
|
|
52
|
+
},
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
globalStyle(
|
|
56
|
+
`${switcherRecipe.classNames.variants.limit[3]} > :nth-last-child(n+4), ${
|
|
57
|
+
switcherRecipe.classNames.variants.limit[3]
|
|
58
|
+
} > :nth-last-child(n+4) ~ *`,
|
|
59
|
+
{
|
|
60
|
+
flexBasis: '100%',
|
|
61
|
+
},
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
globalStyle(
|
|
65
|
+
`${switcherRecipe.classNames.variants.limit[4]} > :nth-last-child(n+5), ${
|
|
66
|
+
switcherRecipe.classNames.variants.limit[4]
|
|
67
|
+
} > :nth-last-child(n+5) ~ *`,
|
|
68
|
+
{
|
|
69
|
+
flexBasis: '100%',
|
|
70
|
+
},
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
globalStyle(
|
|
74
|
+
`${switcherRecipe.classNames.variants.limit[5]} > :nth-last-child(n+6), ${
|
|
75
|
+
switcherRecipe.classNames.variants.limit[5]
|
|
76
|
+
} > :nth-last-child(n+6) ~ *`,
|
|
77
|
+
{
|
|
78
|
+
flexBasis: '100%',
|
|
79
|
+
},
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
globalStyle(
|
|
83
|
+
`${switcherRecipe.classNames.variants.limit[6]} > :nth-last-child(n+7), ${
|
|
84
|
+
switcherRecipe.classNames.variants.limit[6]
|
|
85
|
+
} > :nth-last-child(n+7) ~ *`,
|
|
86
|
+
{
|
|
87
|
+
flexBasis: '100%',
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
export type SwitcherVariants = NonNullable<
|
|
92
|
+
RecipeVariants<typeof switcherRecipe>
|
|
93
|
+
>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import { argTypesFromRecipe, CommonArgs, commonArgs } from '@/utils/arg-types';
|
|
4
|
+
|
|
5
|
+
import { Switcher } from './switcher';
|
|
6
|
+
import { switcherRecipe } from './switcher.css';
|
|
7
|
+
|
|
8
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
9
|
+
|
|
10
|
+
type StoryArgs = ComponentPropsWithoutRef<typeof Switcher> & {
|
|
11
|
+
childCount: number;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const meta = {
|
|
15
|
+
title: 'Layout/Switcher',
|
|
16
|
+
component: Switcher,
|
|
17
|
+
tags: ['autodocs'],
|
|
18
|
+
argTypes: {
|
|
19
|
+
...argTypesFromRecipe(switcherRecipe),
|
|
20
|
+
|
|
21
|
+
...commonArgs([
|
|
22
|
+
CommonArgs.COMPOSABLE,
|
|
23
|
+
CommonArgs.POLYMORPHIC,
|
|
24
|
+
CommonArgs.STYLABLE,
|
|
25
|
+
CommonArgs.REFERABLE,
|
|
26
|
+
]),
|
|
27
|
+
|
|
28
|
+
threshold: {
|
|
29
|
+
table: {
|
|
30
|
+
category: 'Recipe props',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
limit: {
|
|
35
|
+
table: {
|
|
36
|
+
category: 'Recipe props',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
childCount: {
|
|
41
|
+
control: { type: 'range', min: 1, max: 10, step: 1 },
|
|
42
|
+
table: {
|
|
43
|
+
category: 'Story args',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
args: {
|
|
49
|
+
childCount: 4,
|
|
50
|
+
},
|
|
51
|
+
render: ({ childCount, ...args }) => {
|
|
52
|
+
return (
|
|
53
|
+
<Switcher {...args}>
|
|
54
|
+
{new Array(childCount).fill('').map((_, index) => (
|
|
55
|
+
<div key={index}>{`Block ${index + 1}`}</div>
|
|
56
|
+
))}
|
|
57
|
+
</Switcher>
|
|
58
|
+
);
|
|
59
|
+
},
|
|
60
|
+
} satisfies Meta<StoryArgs>;
|
|
61
|
+
|
|
62
|
+
export default meta;
|
|
63
|
+
|
|
64
|
+
type Story = StoryObj<StoryArgs>;
|
|
65
|
+
|
|
66
|
+
export const Default: Story = {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
|
4
|
+
import { clsx } from 'clsx';
|
|
5
|
+
import { ElementType } from 'react';
|
|
6
|
+
|
|
7
|
+
import { PolymorphicComponentProps } from '@/types/utils.types';
|
|
8
|
+
|
|
9
|
+
import { switcherRecipe, SwitcherVariants, thresholdVar } from './switcher.css';
|
|
10
|
+
|
|
11
|
+
type SwitcherProps<TUse extends ElementType> =
|
|
12
|
+
PolymorphicComponentProps<TUse> & {
|
|
13
|
+
/**
|
|
14
|
+
* The gap between items
|
|
15
|
+
*/
|
|
16
|
+
spacing?: SwitcherVariants['spacing'];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The threshold at which to switch between horizontal and vertical layouts
|
|
20
|
+
*/
|
|
21
|
+
threshold?: string;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The maximum number of elements allowed to appear in the horizontal configuration
|
|
25
|
+
*/
|
|
26
|
+
limit?: SwitcherVariants['limit'];
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Switch directly between horizontal and vertical layouts
|
|
31
|
+
* at a given (container width-based) breakpoint or 'threshold'
|
|
32
|
+
*
|
|
33
|
+
* https://every-layout.dev/layouts/switcher
|
|
34
|
+
*/
|
|
35
|
+
export const Switcher = <TUse extends ElementType>({
|
|
36
|
+
spacing,
|
|
37
|
+
threshold,
|
|
38
|
+
limit,
|
|
39
|
+
className,
|
|
40
|
+
...props
|
|
41
|
+
}: SwitcherProps<TUse>) => {
|
|
42
|
+
const { use: Comp = 'div' } = props;
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<Comp
|
|
46
|
+
className={clsx(switcherRecipe({ spacing, limit }), className)}
|
|
47
|
+
style={assignInlineVars({
|
|
48
|
+
...(threshold && { [thresholdVar]: threshold }),
|
|
49
|
+
})}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { plantSeed } from './seed';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { sprinkles, sprinklesProps } from '@/storybook/theme/sprinkles.css';
|
|
2
|
+
import {
|
|
3
|
+
CommonArgs,
|
|
4
|
+
commonArgs,
|
|
5
|
+
argTypesFromSprinkles,
|
|
6
|
+
} from '@/utils/arg-types';
|
|
7
|
+
|
|
8
|
+
import { plantSeed } from './seed';
|
|
9
|
+
|
|
10
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
11
|
+
|
|
12
|
+
const Sprout = plantSeed({ sprinkles });
|
|
13
|
+
|
|
14
|
+
const meta = {
|
|
15
|
+
title: 'Styles/Sprout',
|
|
16
|
+
component: Sprout,
|
|
17
|
+
tags: ['autodocs'],
|
|
18
|
+
args: {
|
|
19
|
+
children: 'Box content',
|
|
20
|
+
},
|
|
21
|
+
argTypes: {
|
|
22
|
+
...argTypesFromSprinkles({ props: sprinklesProps }),
|
|
23
|
+
|
|
24
|
+
...commonArgs([
|
|
25
|
+
CommonArgs.COMPOSABLE,
|
|
26
|
+
CommonArgs.POLYMORPHIC,
|
|
27
|
+
CommonArgs.STYLABLE,
|
|
28
|
+
CommonArgs.REFERABLE,
|
|
29
|
+
]),
|
|
30
|
+
},
|
|
31
|
+
} satisfies Meta<typeof Sprout>;
|
|
32
|
+
|
|
33
|
+
export default meta;
|
|
34
|
+
|
|
35
|
+
type Story = StoryObj<typeof Sprout>;
|
|
36
|
+
|
|
37
|
+
export const Default: Story = {};
|
|
38
|
+
|
|
39
|
+
export const WithSprinklesProps: Story = {
|
|
40
|
+
args: {
|
|
41
|
+
padding: 'medium',
|
|
42
|
+
backgroundColor: 'blue',
|
|
43
|
+
color: 'white',
|
|
44
|
+
textAlign: 'center',
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const UseElement: Story = {
|
|
49
|
+
args: {
|
|
50
|
+
use: 'h1',
|
|
51
|
+
},
|
|
52
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { clsx } from 'clsx';
|
|
2
|
+
|
|
3
|
+
import type { PolymorphicComponentProps } from '@/types/utils.types';
|
|
4
|
+
import {
|
|
5
|
+
extractSprinklesProps,
|
|
6
|
+
type GetSprinkles,
|
|
7
|
+
type SprinklesFnBase,
|
|
8
|
+
} from '@/utils/extract-sprinkles-props';
|
|
9
|
+
|
|
10
|
+
import type { ElementType } from 'react';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* When you use `SeedProps` in other components and want to define a default
|
|
14
|
+
* value for that prop in your component (e.g. `const { use = 'span' } = props;`)
|
|
15
|
+
* you will need to cast the `use` prop as `YourComponentProps<TUse>['use]` otherwise
|
|
16
|
+
* it will be considered as `TUse | span` and you will get a type error.
|
|
17
|
+
*
|
|
18
|
+
* You can see an example of this in `frontend/components/text/text.tsx`.
|
|
19
|
+
*/
|
|
20
|
+
export type SeedProps<
|
|
21
|
+
TUse extends ElementType,
|
|
22
|
+
TSprinklesFn extends SprinklesFnBase,
|
|
23
|
+
> = PolymorphicComponentProps<TUse> & GetSprinkles<TSprinklesFn>;
|
|
24
|
+
|
|
25
|
+
export interface CreateSeedParams<SprinklesFn> {
|
|
26
|
+
sprinkles: SprinklesFn;
|
|
27
|
+
defaultClassName?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function plantSeed<SprinklesFn extends SprinklesFnBase>({
|
|
31
|
+
sprinkles,
|
|
32
|
+
defaultClassName,
|
|
33
|
+
}: CreateSeedParams<SprinklesFn>) {
|
|
34
|
+
const Seed = <TUse extends ElementType = 'div'>(
|
|
35
|
+
props: SeedProps<TUse, SprinklesFn>,
|
|
36
|
+
) => {
|
|
37
|
+
const { use: Comp = 'div', className, ...rest } = props;
|
|
38
|
+
|
|
39
|
+
const [sprinklesProps, componentProps] = extractSprinklesProps(
|
|
40
|
+
rest,
|
|
41
|
+
sprinkles,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<Comp
|
|
46
|
+
className={clsx(sprinkles(sprinklesProps), defaultClassName, className)}
|
|
47
|
+
{...componentProps}
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return Seed;
|
|
53
|
+
}
|