@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,45 @@
|
|
|
1
|
+
import { argTypesFromRecipe, CommonArgs, commonArgs } from '@/utils/arg-types';
|
|
2
|
+
|
|
3
|
+
import { Cover } from './cover';
|
|
4
|
+
import { coverRecipe } from './cover.css';
|
|
5
|
+
|
|
6
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
title: 'Layout/Cover',
|
|
10
|
+
component: Cover,
|
|
11
|
+
tags: ['autodocs'],
|
|
12
|
+
argTypes: {
|
|
13
|
+
...argTypesFromRecipe(coverRecipe),
|
|
14
|
+
|
|
15
|
+
...commonArgs([
|
|
16
|
+
CommonArgs.COMPOSABLE,
|
|
17
|
+
CommonArgs.POLYMORPHIC,
|
|
18
|
+
CommonArgs.STYLABLE,
|
|
19
|
+
CommonArgs.REFERABLE,
|
|
20
|
+
]),
|
|
21
|
+
|
|
22
|
+
minSize: {
|
|
23
|
+
table: {
|
|
24
|
+
category: 'Recipe props',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
args: {
|
|
29
|
+
minSize: '30vh',
|
|
30
|
+
|
|
31
|
+
children: (
|
|
32
|
+
<>
|
|
33
|
+
<div>Cover element one</div>
|
|
34
|
+
<div data-cover-center>Cover element two</div>
|
|
35
|
+
<div>Cover element three</div>
|
|
36
|
+
</>
|
|
37
|
+
),
|
|
38
|
+
},
|
|
39
|
+
} satisfies Meta<typeof Cover>;
|
|
40
|
+
|
|
41
|
+
export default meta;
|
|
42
|
+
|
|
43
|
+
type Story = StoryObj<typeof Cover>;
|
|
44
|
+
|
|
45
|
+
export const Default: Story = {};
|
|
@@ -0,0 +1,55 @@
|
|
|
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 { coverRecipe, CoverVariants, minSizeVar } from './cover.css';
|
|
10
|
+
|
|
11
|
+
type CoverProps<TUse extends ElementType> = PolymorphicComponentProps<TUse> & {
|
|
12
|
+
/**
|
|
13
|
+
* The spacing between items
|
|
14
|
+
*/
|
|
15
|
+
spacing?: CoverVariants['spacing'];
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* True if the cover should have no padding
|
|
19
|
+
*/
|
|
20
|
+
noPad?: CoverVariants['noPad'];
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The minimum height of the cover
|
|
24
|
+
*/
|
|
25
|
+
minSize?: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* A custom element for covering a block-level element horizontally,
|
|
30
|
+
* with a max-width value representing the typographic measure.
|
|
31
|
+
*
|
|
32
|
+
* The element that should be towards the vertical center of the space
|
|
33
|
+
* is identified with a simple `data-cover-center` attribute.
|
|
34
|
+
*
|
|
35
|
+
* https://every-layout.dev/layouts/cover
|
|
36
|
+
*/
|
|
37
|
+
export const Cover = <TUse extends ElementType>({
|
|
38
|
+
spacing,
|
|
39
|
+
noPad,
|
|
40
|
+
minSize,
|
|
41
|
+
className,
|
|
42
|
+
...props
|
|
43
|
+
}: CoverProps<TUse>) => {
|
|
44
|
+
const { use: Comp = 'div', ...rest } = props;
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<Comp
|
|
48
|
+
className={clsx(coverRecipe({ spacing, noPad }), className)}
|
|
49
|
+
style={assignInlineVars({
|
|
50
|
+
...(minSize && { [minSizeVar]: minSize }),
|
|
51
|
+
})}
|
|
52
|
+
{...rest}
|
|
53
|
+
/>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
Binary file
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { createVar, globalStyle, style } from '@vanilla-extract/css';
|
|
2
|
+
import { recipe, type RecipeVariants } from '@vanilla-extract/recipes';
|
|
3
|
+
|
|
4
|
+
const ratioVar = createVar();
|
|
5
|
+
|
|
6
|
+
const baseFrame = style({
|
|
7
|
+
display: 'flex',
|
|
8
|
+
justifyContent: 'center',
|
|
9
|
+
alignItems: 'center',
|
|
10
|
+
|
|
11
|
+
overflow: 'hidden',
|
|
12
|
+
|
|
13
|
+
aspectRatio: ratioVar,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export const frameRecipe = recipe({
|
|
17
|
+
base: baseFrame,
|
|
18
|
+
|
|
19
|
+
variants: {
|
|
20
|
+
ratio: {
|
|
21
|
+
'1:1': {
|
|
22
|
+
vars: {
|
|
23
|
+
[ratioVar]: '1 / 1',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
'3:2': {
|
|
27
|
+
vars: {
|
|
28
|
+
[ratioVar]: '3 / 2',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
'2:3': {
|
|
32
|
+
vars: {
|
|
33
|
+
[ratioVar]: '2 / 3',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
'4:3': {
|
|
37
|
+
vars: {
|
|
38
|
+
[ratioVar]: '4 / 3',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
'16:9': {
|
|
42
|
+
vars: {
|
|
43
|
+
[ratioVar]: '16 / 9',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
'9:16': {
|
|
47
|
+
vars: {
|
|
48
|
+
[ratioVar]: '9 / 16',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
globalStyle(`${baseFrame} > img, ${baseFrame} > video`, {
|
|
56
|
+
inlineSize: '100%',
|
|
57
|
+
blockSize: '100%',
|
|
58
|
+
objectFit: 'cover',
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
export type FrameVariants = NonNullable<RecipeVariants<typeof frameRecipe>>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { argTypesFromRecipe, CommonArgs, commonArgs } from '@/utils/arg-types';
|
|
2
|
+
|
|
3
|
+
import { Frame } from './frame';
|
|
4
|
+
import { frameRecipe } from './frame.css';
|
|
5
|
+
|
|
6
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
title: 'Layout/Frame',
|
|
10
|
+
component: Frame,
|
|
11
|
+
tags: ['autodocs'],
|
|
12
|
+
argTypes: {
|
|
13
|
+
...argTypesFromRecipe(frameRecipe),
|
|
14
|
+
|
|
15
|
+
...commonArgs([
|
|
16
|
+
CommonArgs.COMPOSABLE,
|
|
17
|
+
CommonArgs.POLYMORPHIC,
|
|
18
|
+
CommonArgs.STYLABLE,
|
|
19
|
+
CommonArgs.REFERABLE,
|
|
20
|
+
]),
|
|
21
|
+
|
|
22
|
+
ratio: {
|
|
23
|
+
table: {
|
|
24
|
+
category: 'Recipe props',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
args: {
|
|
29
|
+
ratio: '16:9',
|
|
30
|
+
|
|
31
|
+
children: <div>Frame element</div>,
|
|
32
|
+
},
|
|
33
|
+
} satisfies Meta<typeof Frame>;
|
|
34
|
+
|
|
35
|
+
export default meta;
|
|
36
|
+
|
|
37
|
+
type Story = StoryObj<typeof Frame>;
|
|
38
|
+
|
|
39
|
+
export const Default: Story = {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { clsx } from 'clsx';
|
|
2
|
+
import { ElementType } from 'react';
|
|
3
|
+
|
|
4
|
+
import { PolymorphicComponentProps } from '@/types/utils.types';
|
|
5
|
+
|
|
6
|
+
import { frameRecipe, FrameVariants } from './frame.css';
|
|
7
|
+
|
|
8
|
+
type FrameProps<TUse extends ElementType> = PolymorphicComponentProps<TUse> & {
|
|
9
|
+
/**
|
|
10
|
+
* The ratio of the frame
|
|
11
|
+
*/
|
|
12
|
+
ratio?: FrameVariants['ratio'];
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A custom element for augmenting image ratios
|
|
17
|
+
*
|
|
18
|
+
* https://every-layout.dev/layouts/frame
|
|
19
|
+
*/
|
|
20
|
+
export const Frame = <TUse extends ElementType>({
|
|
21
|
+
ratio,
|
|
22
|
+
className,
|
|
23
|
+
...props
|
|
24
|
+
}: FrameProps<TUse>) => {
|
|
25
|
+
const { use: Comp = 'div', ...rest } = props;
|
|
26
|
+
|
|
27
|
+
return <Comp className={clsx(frameRecipe({ ratio }), className)} {...rest} />;
|
|
28
|
+
};
|
|
Binary file
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createVar } 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 minSizeVar = createVar();
|
|
8
|
+
|
|
9
|
+
export const gridRecipe = recipe({
|
|
10
|
+
base: {
|
|
11
|
+
display: 'grid',
|
|
12
|
+
gridTemplateColumns: `repeat(auto-fill, minmax(min(${minSizeVar}, 100%), 1fr))`,
|
|
13
|
+
|
|
14
|
+
vars: {
|
|
15
|
+
[minSizeVar]: '250px',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
variants: {
|
|
20
|
+
spacing: mapContractVars(sys.spacing, (key) => ({
|
|
21
|
+
gridGap: sys.spacing[key],
|
|
22
|
+
})),
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export type GridVariants = NonNullable<RecipeVariants<typeof gridRecipe>>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { argTypesFromRecipe, CommonArgs, commonArgs } from '@/utils/arg-types';
|
|
2
|
+
|
|
3
|
+
import { Grid } from './grid';
|
|
4
|
+
import { gridRecipe } from './grid.css';
|
|
5
|
+
|
|
6
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
title: 'Layout/Grid',
|
|
10
|
+
component: Grid,
|
|
11
|
+
tags: ['autodocs'],
|
|
12
|
+
argTypes: {
|
|
13
|
+
...argTypesFromRecipe(gridRecipe),
|
|
14
|
+
|
|
15
|
+
...commonArgs([
|
|
16
|
+
CommonArgs.COMPOSABLE,
|
|
17
|
+
CommonArgs.POLYMORPHIC,
|
|
18
|
+
CommonArgs.STYLABLE,
|
|
19
|
+
CommonArgs.REFERABLE,
|
|
20
|
+
]),
|
|
21
|
+
|
|
22
|
+
minSize: {
|
|
23
|
+
table: {
|
|
24
|
+
category: 'Recipe props',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
args: {
|
|
29
|
+
minSize: '250px',
|
|
30
|
+
|
|
31
|
+
children: (
|
|
32
|
+
<>
|
|
33
|
+
<div>Grid cell one</div>
|
|
34
|
+
<div>Grid cell two</div>
|
|
35
|
+
<div>Grid cell three</div>
|
|
36
|
+
<div>Grid cell four</div>
|
|
37
|
+
<div>Grid cell five</div>
|
|
38
|
+
<div>Grid cell six</div>
|
|
39
|
+
<div>Grid cell seven</div>
|
|
40
|
+
<div>Grid cell eight</div>
|
|
41
|
+
</>
|
|
42
|
+
),
|
|
43
|
+
},
|
|
44
|
+
} satisfies Meta<typeof Grid>;
|
|
45
|
+
|
|
46
|
+
export default meta;
|
|
47
|
+
|
|
48
|
+
type Story = StoryObj<typeof Grid>;
|
|
49
|
+
|
|
50
|
+
export const Default: Story = {};
|
|
@@ -0,0 +1,48 @@
|
|
|
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 { gridRecipe, GridVariants, minSizeVar } from './grid.css';
|
|
10
|
+
|
|
11
|
+
type GridProps<TUse extends ElementType> = PolymorphicComponentProps<TUse> & {
|
|
12
|
+
/**
|
|
13
|
+
* The minimum size of a grid cell
|
|
14
|
+
*/
|
|
15
|
+
minSize?: string;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The spacing between the grid cell
|
|
19
|
+
*/
|
|
20
|
+
spacing?: GridVariants['spacing'];
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The Grid layout provides a flexible, responsive grid system that
|
|
25
|
+
* arranges elements in a structured, multi-column format, automatically
|
|
26
|
+
* adjusting the number of columns based on the available space and
|
|
27
|
+
* predefined constraints.
|
|
28
|
+
*
|
|
29
|
+
* https://every-layout.dev/layouts/grid/
|
|
30
|
+
*/
|
|
31
|
+
export const Grid = <TUse extends ElementType>({
|
|
32
|
+
spacing,
|
|
33
|
+
minSize,
|
|
34
|
+
className,
|
|
35
|
+
...props
|
|
36
|
+
}: GridProps<TUse>) => {
|
|
37
|
+
const { use: Comp = 'div', ...rest } = props;
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<Comp
|
|
41
|
+
className={clsx(gridRecipe({ spacing }), className)}
|
|
42
|
+
style={assignInlineVars({
|
|
43
|
+
...(minSize && { [minSizeVar]: minSize }),
|
|
44
|
+
})}
|
|
45
|
+
{...rest}
|
|
46
|
+
/>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { Meta } from '@storybook/addon-docs';
|
|
2
|
+
|
|
3
|
+
<Meta title="Layout/Layout Components" />
|
|
4
|
+
|
|
5
|
+
# Layout Components
|
|
6
|
+
|
|
7
|
+
This section provides implementations of various layout components inspired by [Every Layout](https://every-layout.dev/). These components are designed to create responsive, adaptable, and minimal CSS layouts, solving common design problems with composable and flexible solutions.
|
|
8
|
+
|
|
9
|
+
## The Box
|
|
10
|
+
|
|
11
|
+
The Box layout provides a simple way to add padding and a border to its content, useful for creating visually distinct sections. It's a fundamental building block for creating consistent spacing and visual separation in your designs.
|
|
12
|
+
|
|
13
|
+
Use cases:
|
|
14
|
+
|
|
15
|
+
- Creating card-like components
|
|
16
|
+
- Highlighting important content
|
|
17
|
+
- Separating sections in a form
|
|
18
|
+
|
|
19
|
+
[Box documentation page](?path=/docs/layout-box--docs)
|
|
20
|
+
|
|
21
|
+
```jsx
|
|
22
|
+
import { Box } from '@kalink-studio/ui/layout';
|
|
23
|
+
|
|
24
|
+
<Box padding="md" variant="plain">
|
|
25
|
+
<p>This is a box.</p>
|
|
26
|
+
</Box>;
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## The Stack
|
|
30
|
+
|
|
31
|
+
The Stack layout arranges its children vertically with a consistent gap between them. It's perfect for creating a vertical flow of elements, eliminating the need for manual margin management between elements.
|
|
32
|
+
|
|
33
|
+
Use cases:
|
|
34
|
+
|
|
35
|
+
- Organizing form fields
|
|
36
|
+
- Creating a vertical list of articles or comments
|
|
37
|
+
- Structuring content in a sidebar
|
|
38
|
+
|
|
39
|
+
[Stack documentation page](?path=/docs/layout-stack--docs)
|
|
40
|
+
|
|
41
|
+
```jsx
|
|
42
|
+
import { Stack } from '@kalink-studio/ui/layout';
|
|
43
|
+
|
|
44
|
+
<Stack spacing="md" recursive>
|
|
45
|
+
<div>Item 1</div>
|
|
46
|
+
<div>Item 2</div>
|
|
47
|
+
<div>
|
|
48
|
+
<div>Nested item 2.1</div>
|
|
49
|
+
<div>Nested item 2.2</div>
|
|
50
|
+
</div>
|
|
51
|
+
<div>Item 3</div>
|
|
52
|
+
</Stack>;
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## The Center
|
|
56
|
+
|
|
57
|
+
The Center layout is designed to center its content both horizontally and optionally vertically. It's particularly useful for creating visually balanced layouts and focusing attention on specific content.
|
|
58
|
+
|
|
59
|
+
Use cases:
|
|
60
|
+
|
|
61
|
+
- Creating hero sections
|
|
62
|
+
- Creating a centered column of content
|
|
63
|
+
- Designing error pages or "empty state" screens
|
|
64
|
+
|
|
65
|
+
[Center documentation page](?path=/docs/layout-center--docs)
|
|
66
|
+
|
|
67
|
+
```jsx
|
|
68
|
+
import { Center } from '@kalink-studio/ui/layout';
|
|
69
|
+
|
|
70
|
+
<Center gutters="md" intrinsic>
|
|
71
|
+
<p>This content is centered.</p>
|
|
72
|
+
</Center>;
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## The Cluster
|
|
76
|
+
|
|
77
|
+
The Cluster layout arranges elements in a flexible row that wraps to accommodate available space. It's ideal for layouts that need to manage many small items while maintaining consistent spacing and alignment.
|
|
78
|
+
|
|
79
|
+
Use cases:
|
|
80
|
+
|
|
81
|
+
- Displaying tags or categories
|
|
82
|
+
- Creating a flexible navigation menu
|
|
83
|
+
- Showing a group of action buttons
|
|
84
|
+
|
|
85
|
+
[Cluster documentation page](?path=/docs/layout-cluster--docs)
|
|
86
|
+
|
|
87
|
+
```jsx
|
|
88
|
+
import { Cluster } from '@kalink-studio/ui/layout';
|
|
89
|
+
|
|
90
|
+
<Cluster spacing="md" justify="center">
|
|
91
|
+
<div>Item 1</div>
|
|
92
|
+
<div>Item 2</div>
|
|
93
|
+
<div>Item 3</div>
|
|
94
|
+
<div>Item 4</div>
|
|
95
|
+
</Cluster>;
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## The Sidebar
|
|
99
|
+
|
|
100
|
+
The Sidebar layout divides content into a main section and a sidebar, which can be positioned on either side and resized according to the layout requirements. It's crucial for creating responsive layouts that adapt to different screen sizes.
|
|
101
|
+
|
|
102
|
+
Use cases:
|
|
103
|
+
|
|
104
|
+
- Creating a layout with a navigation sidebar
|
|
105
|
+
- Displaying additional information alongside main content
|
|
106
|
+
- Building dashboard layouts
|
|
107
|
+
|
|
108
|
+
[Sidebar documentation page](?path=/docs/layout-sidebar--docs)
|
|
109
|
+
|
|
110
|
+
```jsx
|
|
111
|
+
import { Sidebar } from '@kalink-studio/ui/layout';
|
|
112
|
+
|
|
113
|
+
<Sidebar sideWidth="250px" contentMinWidth="300px" spacing="md" side="left">
|
|
114
|
+
<div>Sidebar content</div>
|
|
115
|
+
<div>Main content</div>
|
|
116
|
+
</Sidebar>;
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## The Switcher
|
|
120
|
+
|
|
121
|
+
The Switcher layout allows elements to switch between a horizontal and vertical arrangement based on the available space. It's ideal for responsive design scenarios where content needs to adapt to different screen sizes seamlessly.
|
|
122
|
+
|
|
123
|
+
Use cases:
|
|
124
|
+
|
|
125
|
+
- Creating responsive navigation menus
|
|
126
|
+
- Designing flexible card layouts
|
|
127
|
+
- Building adaptable form layouts
|
|
128
|
+
|
|
129
|
+
[Switcher documentation page](?path=/docs/layout-switcher--docs)
|
|
130
|
+
|
|
131
|
+
```jsx
|
|
132
|
+
import { Switcher } from '@kalink-studio/ui/layout';
|
|
133
|
+
|
|
134
|
+
<Switcher threshold="300px" spacing="md">
|
|
135
|
+
<div>Item 1</div>
|
|
136
|
+
<div>Item 2</div>
|
|
137
|
+
<div>Item 3</div>
|
|
138
|
+
</Switcher>;
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## The Cover
|
|
142
|
+
|
|
143
|
+
The Cover layout helps create a vertically centered layout with a header, main content, and footer, ensuring that the main content stays centered. It's particularly useful for creating full-page layouts or sections that need to utilize the full viewport height.
|
|
144
|
+
|
|
145
|
+
Use cases:
|
|
146
|
+
|
|
147
|
+
- Designing landing pages
|
|
148
|
+
- Creating login or signup screens
|
|
149
|
+
- Building "coming soon" pages
|
|
150
|
+
|
|
151
|
+
[Cover documentation page](?path=/docs/layout-cover--docs)
|
|
152
|
+
|
|
153
|
+
```jsx
|
|
154
|
+
import { Cover } from '@kalink-studio/ui/layout';
|
|
155
|
+
|
|
156
|
+
<Cover minSize="60vh" spacing="md" noPad>
|
|
157
|
+
<header>Header</header>
|
|
158
|
+
<main>Main content</main>
|
|
159
|
+
<footer>Footer</footer>
|
|
160
|
+
</Cover>;
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## The Grid
|
|
164
|
+
|
|
165
|
+
The Grid layout provides a responsive grid system that adapts the number of columns based on available space, with defined gaps between columns and rows. It's perfect for creating complex, responsive layouts without the need for media queries.
|
|
166
|
+
|
|
167
|
+
Use cases:
|
|
168
|
+
|
|
169
|
+
- Displaying a gallery of images
|
|
170
|
+
- Creating a responsive product listing
|
|
171
|
+
- Organizing dashboard widgets
|
|
172
|
+
|
|
173
|
+
[Grid documentation page](?path=/docs/layout-grid--docs)
|
|
174
|
+
|
|
175
|
+
```jsx
|
|
176
|
+
import { Grid } from '@kalink-studio/ui/layout';
|
|
177
|
+
|
|
178
|
+
<Grid minSize="200px" spacing="md">
|
|
179
|
+
<div>Item 1</div>
|
|
180
|
+
<div>Item 2</div>
|
|
181
|
+
<div>Item 3</div>
|
|
182
|
+
<div>Item 4</div>
|
|
183
|
+
</Grid>;
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## The Frame
|
|
187
|
+
|
|
188
|
+
The Frame layout is used to maintain aspect ratios of embedded content, such as videos or iframes, ensuring that content scales appropriately while preserving its aspect ratio. It's crucial for responsive design and preventing layout shifts.
|
|
189
|
+
|
|
190
|
+
Use cases:
|
|
191
|
+
|
|
192
|
+
- Embedding responsive videos
|
|
193
|
+
- Displaying images with consistent aspect ratios
|
|
194
|
+
- Creating responsive data visualizations
|
|
195
|
+
|
|
196
|
+
[Frame documentation page](?path=/docs/layout-frame--docs)
|
|
197
|
+
|
|
198
|
+
```jsx
|
|
199
|
+
import { Frame } from '@kalink-studio/ui/layout';
|
|
200
|
+
|
|
201
|
+
<Frame ratio="16:9">
|
|
202
|
+
<img src="...">
|
|
203
|
+
</Frame>;
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Each of these components is designed to solve specific layout challenges while promoting responsive and adaptable designs. By combining these layout primitives, you can create complex, flexible layouts that work across various screen sizes and devices, all while minimizing the amount of custom CSS required.
|
|
Binary file
|
|
@@ -0,0 +1,68 @@
|
|
|
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 sideWidthVar = createVar();
|
|
8
|
+
export const contentMinWidthVar = createVar();
|
|
9
|
+
|
|
10
|
+
export const sidebarRecipe = recipe({
|
|
11
|
+
base: {
|
|
12
|
+
display: 'flex',
|
|
13
|
+
flexWrap: 'wrap',
|
|
14
|
+
|
|
15
|
+
vars: {
|
|
16
|
+
[contentMinWidthVar]: '50%',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
variants: {
|
|
21
|
+
spacing: mapContractVars(sys.spacing, (key) => ({
|
|
22
|
+
gap: sys.spacing[key],
|
|
23
|
+
})),
|
|
24
|
+
|
|
25
|
+
noStretch: {
|
|
26
|
+
true: {
|
|
27
|
+
alignItems: 'flex-start',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The width of the sidebar (empty means not set; defaults to the content width)
|
|
33
|
+
*/
|
|
34
|
+
sideWidth: {
|
|
35
|
+
true: {},
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Whether the sided element is the :last-child
|
|
40
|
+
*/
|
|
41
|
+
side: {
|
|
42
|
+
right: {},
|
|
43
|
+
left: {},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
globalStyle(`${sidebarRecipe.classNames.base} > *`, {
|
|
49
|
+
flexGrow: 1,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
globalStyle(`${sidebarRecipe.classNames.variants.sideWidth.true} > *`, {
|
|
53
|
+
flexBasis: sideWidthVar,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
globalStyle(`${sidebarRecipe.classNames.variants.side.left} > :last-child`, {
|
|
57
|
+
flexBasis: 0,
|
|
58
|
+
flexGrow: 999,
|
|
59
|
+
minInlineSize: contentMinWidthVar,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
globalStyle(`${sidebarRecipe.classNames.variants.side.right} > :first-child`, {
|
|
63
|
+
flexBasis: 0,
|
|
64
|
+
flexGrow: 999,
|
|
65
|
+
minInlineSize: contentMinWidthVar,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export type SidebarVariants = NonNullable<RecipeVariants<typeof sidebarRecipe>>;
|