@kalink-ui/seedly 0.8.0 → 0.9.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.
Files changed (33) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +18 -16
  3. package/src/components/box/box.css.ts +4 -13
  4. package/src/components/box/box.tsx +2 -2
  5. package/src/components/box/index.ts +1 -1
  6. package/src/components/card/card.css.ts +42 -0
  7. package/src/components/card/card.tsx +73 -0
  8. package/src/components/card/index.ts +1 -0
  9. package/src/components/center/center.css.ts +1 -1
  10. package/src/components/cluster/cluster.css.ts +1 -1
  11. package/src/components/cluster/cluster.tsx +2 -2
  12. package/src/components/cluster/index.ts +1 -1
  13. package/src/components/cover/cover.css.ts +1 -1
  14. package/src/components/grid/grid.css.ts +1 -1
  15. package/src/components/heading/heading.css.ts +49 -2
  16. package/src/components/heading/heading.tsx +80 -61
  17. package/src/components/heading/index.ts +2 -1
  18. package/src/components/index.ts +4 -3
  19. package/src/components/seed/index.ts +1 -1
  20. package/src/components/seed/seed.tsx +38 -1
  21. package/src/components/text/text.css.ts +146 -7
  22. package/src/components/text/text.tsx +19 -27
  23. package/src/styles/system-contract.css.ts +0 -2
  24. package/src/styles/typography.css.ts +10 -5
  25. package/src/utils/arg-types/arg-types-from-recipe.ts +36 -0
  26. package/src/utils/arg-types/arg-types-from-sprinkles.ts +43 -0
  27. package/src/utils/arg-types/common/composable.ts +13 -0
  28. package/src/utils/arg-types/common/index.ts +4 -0
  29. package/src/utils/arg-types/common/polymorphic.ts +14 -0
  30. package/src/utils/arg-types/common/referable.ts +10 -0
  31. package/src/utils/arg-types/common/stylable.ts +14 -0
  32. package/src/utils/arg-types/common-args.ts +26 -0
  33. package/src/utils/arg-types/index.ts +3 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @kalink-ui/seedly
2
2
 
3
+ ## 0.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 7fe5a15: Fix issues with TypeScript config and setup Github Actions
8
+
9
+ ## 0.8.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 6670251: Do not ignore arg-types files from npm package
14
+
3
15
  ## 0.8.0
4
16
 
5
17
  ### Minor Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kalink-ui/seedly",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "A set of components for building UIs with React and TypeScript",
5
5
  "sideEffects": false,
6
6
  "license": "MIT",
@@ -17,14 +17,14 @@
17
17
  },
18
18
  "devDependencies": {
19
19
  "@chromatic-com/storybook": "^3.2.5",
20
- "@storybook/addon-docs": "^8.6.4",
21
- "@storybook/addon-essentials": "^8.6.4",
22
- "@storybook/addon-interactions": "^8.6.4",
23
- "@storybook/addon-onboarding": "^8.6.4",
24
- "@storybook/blocks": "^8.6.4",
25
- "@storybook/react": "^8.6.4",
26
- "@storybook/react-vite": "^8.6.4",
27
- "@storybook/test": "^8.6.4",
20
+ "@storybook/addon-docs": "^8.6.9",
21
+ "@storybook/addon-essentials": "^8.6.9",
22
+ "@storybook/addon-interactions": "^8.6.9",
23
+ "@storybook/addon-onboarding": "^8.6.9",
24
+ "@storybook/blocks": "^8.6.9",
25
+ "@storybook/react": "^8.6.9",
26
+ "@storybook/react-vite": "^8.6.9",
27
+ "@storybook/test": "^8.6.9",
28
28
  "@turbo/gen": "^2.4.4",
29
29
  "@types/node": "^22.13.9",
30
30
  "@types/react": "19.0.10",
@@ -40,15 +40,15 @@
40
40
  "react": "^19.0.0",
41
41
  "react-docgen-typescript": "^2.2.2",
42
42
  "react-dom": "^19.0.0",
43
- "storybook": "^8.6.4",
43
+ "storybook": "^8.6.9",
44
44
  "type-fest": "^4.37.0",
45
45
  "typescript": "5.8.2",
46
46
  "vite": "^6.2.1",
47
47
  "vite-tsconfig-paths": "^5.1.4",
48
48
  "vitest": "^3.0.8",
49
- "@kalink-ui/dibbly": "0.2.0",
50
- "@kalink-ui/eslint-config": "0.7.0",
51
- "@kalink-ui/typescript-config": "0.4.0"
49
+ "@kalink-ui/dibbly": "0.3.0",
50
+ "@kalink-ui/typescript-config": "0.4.0",
51
+ "@kalink-ui/eslint-config": "0.8.0"
52
52
  },
53
53
  "peerDependencies": {
54
54
  "@vanilla-extract/css": "^1.17.1",
@@ -66,10 +66,12 @@
66
66
  "access": "public"
67
67
  },
68
68
  "scripts": {
69
- "lint": "eslint . --max-warnings 0",
69
+ "lint": "eslint --max-warnings 0",
70
+ "lint:fix": "pnpm lint --fix",
70
71
  "build-storybook": "storybook build",
71
72
  "dev": "storybook dev -p 6006 --no-open",
72
- "test": "vitest",
73
- "tsc": "tsc --noEmit"
73
+ "test": "vitest run",
74
+ "test:watch": "vitest",
75
+ "tsc": "tsc -b"
74
76
  }
75
77
  }
@@ -1,12 +1,8 @@
1
- import { createVar } from '@vanilla-extract/css';
2
1
  import { recipe, type RecipeVariants } from '@vanilla-extract/recipes';
3
2
 
4
3
  import { mapContractVars, sys } from '../../styles';
5
4
  import { components } from '../../styles/layers.css';
6
5
 
7
- export const colorForeground = createVar();
8
- export const colorBackground = createVar();
9
-
10
6
  export const boxRecipe = recipe({
11
7
  variants: {
12
8
  /**
@@ -16,13 +12,8 @@ export const boxRecipe = recipe({
16
12
  solid: {
17
13
  '@layer': {
18
14
  [components]: {
19
- color: colorForeground,
20
- backgroundColor: colorBackground,
21
- },
22
-
23
- vars: {
24
- [colorForeground]: sys.color.foreground,
25
- [colorBackground]: sys.color.background,
15
+ color: sys.color.foreground,
16
+ backgroundColor: sys.color.background,
26
17
  },
27
18
  },
28
19
  },
@@ -30,10 +21,10 @@ export const boxRecipe = recipe({
30
21
  outline: {
31
22
  '@layer': {
32
23
  [components]: {
33
- color: colorBackground,
24
+ color: sys.color.foreground,
34
25
  backgroundColor: 'transparent',
35
26
 
36
- borderColor: colorBackground,
27
+ borderColor: sys.color.foreground,
37
28
  borderStyle: 'solid',
38
29
  borderWidth: '1px',
39
30
  },
@@ -4,8 +4,8 @@ import { ElementType } from 'react';
4
4
 
5
5
  import { BoxVariants, boxRecipe } from './box.css';
6
6
 
7
- type BoxProps<TUse extends ElementType> = PolymorphicComponentProps<TUse> &
8
- BoxVariants;
7
+ export type BoxProps<TUse extends ElementType> =
8
+ PolymorphicComponentProps<TUse> & BoxVariants;
9
9
 
10
10
  /**
11
11
  * A evenly spaced container for grouping related elements. Can
@@ -1,2 +1,2 @@
1
- export { Box } from './box';
1
+ export { Box, type BoxProps } from './box';
2
2
  export { boxRecipe, type BoxVariants } from './box.css';
@@ -0,0 +1,42 @@
1
+ import { style } from '@vanilla-extract/css';
2
+ import { recipe } from '@vanilla-extract/recipes';
3
+
4
+ import { components } from '../../styles/layers.css';
5
+
6
+ export const card = style({});
7
+ export const cardHeader = style({});
8
+ export const cardBody = style({});
9
+ export const cardFooter = recipe({
10
+ base: {
11
+ '@layer': {
12
+ [components]: {
13
+ display: 'flex',
14
+ },
15
+ },
16
+ },
17
+ variants: {
18
+ align: {
19
+ start: {
20
+ '@layer': {
21
+ [components]: {
22
+ justifyContent: 'flex-start',
23
+ },
24
+ },
25
+ },
26
+ center: {
27
+ '@layer': {
28
+ [components]: {
29
+ justifyContent: 'center',
30
+ },
31
+ },
32
+ },
33
+ end: {
34
+ '@layer': {
35
+ [components]: {
36
+ justifyContent: 'flex-end',
37
+ },
38
+ },
39
+ },
40
+ },
41
+ },
42
+ });
@@ -0,0 +1,73 @@
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 CardProps<TUse extends ElementType = 'article'> = BoxProps<TUse> & {
14
+ verticalSpacing?: Spacing;
15
+ };
16
+
17
+ export function Card<TUse extends ElementType = 'article'>(
18
+ props: CardProps<TUse>,
19
+ ) {
20
+ const {
21
+ use = 'article',
22
+ variant = 'solid',
23
+ className,
24
+ spacing = 4,
25
+ verticalSpacing,
26
+ children,
27
+ ...rest
28
+ } = props;
29
+
30
+ return (
31
+ <Box
32
+ use={use as CardProps['use']}
33
+ variant={variant}
34
+ spacing={spacing}
35
+ className={clsx(card, className)}
36
+ {...rest}
37
+ >
38
+ <Stack spacing={verticalSpacing ?? spacing}>{children}</Stack>
39
+ </Box>
40
+ );
41
+ }
42
+
43
+ Card.Header = function CardHeader<TUse extends ElementType = 'header'>(
44
+ props: PolymorphicComponentProps<TUse>,
45
+ ) {
46
+ const { use: Comp = 'header', className, ...rest } = props;
47
+
48
+ return <Comp className={clsx(cardHeader, className)} {...rest} />;
49
+ };
50
+
51
+ Card.Body = function CardBody<TUse extends ElementType = 'div'>(
52
+ props: PolymorphicComponentProps<TUse>,
53
+ ) {
54
+ const { use: Comp = 'div', className, ...rest } = props;
55
+
56
+ return <Comp className={clsx(cardBody, className)} {...rest} />;
57
+ };
58
+
59
+ type CardFooterProps<TUse extends ElementType = 'footer'> = ClusterProps<TUse>;
60
+
61
+ Card.Footer = function CardFooter<TUse extends ElementType = 'footer'>(
62
+ props: CardFooterProps<TUse>,
63
+ ) {
64
+ const { use = 'footer', className, ...rest } = props;
65
+
66
+ return (
67
+ <Cluster
68
+ use={use as CardFooterProps['use']}
69
+ className={clsx(cardFooter, className)}
70
+ {...rest}
71
+ />
72
+ );
73
+ };
@@ -0,0 +1 @@
1
+ export { Card } from './card';
@@ -1,6 +1,6 @@
1
1
  import { recipe, type RecipeVariants } from '@vanilla-extract/recipes';
2
2
 
3
- import { mapContractVars , sys } from '../../styles';
3
+ import { mapContractVars, sys } from '../../styles';
4
4
  import { components } from '../../styles/layers.css';
5
5
 
6
6
  export const centerRecipe = recipe({
@@ -1,6 +1,6 @@
1
1
  import { recipe, type RecipeVariants } from '@vanilla-extract/recipes';
2
2
 
3
- import { mapContractVars , sys } from '../../styles';
3
+ import { mapContractVars, sys } from '../../styles';
4
4
  import { components } from '../../styles/layers.css';
5
5
 
6
6
  export const clusterRecipe = recipe({
@@ -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> = PolymorphicComponentProps<TUse> &
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 , mapContractVars } from '../../styles';
4
+ import { sys, mapContractVars } from '../../styles';
5
5
  import { components } from '../../styles/layers.css';
6
6
 
7
7
  const spaceVar = createVar();
@@ -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 , mapContractVars } from '../../styles';
4
+ import { sys, mapContractVars } from '../../styles';
5
5
  import { components } from '../../styles/layers.css';
6
6
 
7
7
  export const minSizeVar = createVar();
@@ -1,5 +1,52 @@
1
1
  import { recipe, type RecipeVariants } from '@vanilla-extract/recipes';
2
2
 
3
- export const headingRecipe = recipe({});
3
+ import { mapContractVars, sys } from '../../styles';
4
+ import { components } from '../../styles/layers.css';
4
5
 
5
- export type HeadingVariants = NonNullable<RecipeVariants<typeof headingRecipe>>;
6
+ export const headingRoot = recipe({
7
+ base: {
8
+ display: 'flex',
9
+ flexDirection: 'column',
10
+ },
11
+
12
+ variants: {
13
+ align: {
14
+ start: {
15
+ '@layer': {
16
+ [components]: {
17
+ alignItems: 'flex-start',
18
+ textAlign: 'start',
19
+ },
20
+ },
21
+ },
22
+ center: {
23
+ '@layer': {
24
+ [components]: {
25
+ alignItems: 'center',
26
+ textAlign: 'center',
27
+ },
28
+ },
29
+ },
30
+ end: {
31
+ '@layer': {
32
+ [components]: {
33
+ alignItems: 'flex-end',
34
+ textAlign: 'end',
35
+ },
36
+ },
37
+ },
38
+ },
39
+
40
+ spacing: mapContractVars(sys.spacing, (key) => ({
41
+ '@layer': {
42
+ [components]: {
43
+ gap: sys.spacing[key],
44
+ },
45
+ },
46
+ })),
47
+ },
48
+ });
49
+
50
+ export type HeadingRootVariants = NonNullable<
51
+ RecipeVariants<typeof headingRoot>
52
+ >;
@@ -1,83 +1,102 @@
1
- import { getProp, PolymorphicComponentProps } from '@kalink-ui/dibbly';
2
1
  import { clsx } from 'clsx';
2
+ import { ElementType, ReactElement } from 'react';
3
3
 
4
- import {
5
- typography,
6
- Spacing,
7
- TypographySize,
8
- TypographyVariant,
9
- } from '../../styles';
4
+ import { Spacing, TypographySize, TypographyVariant } from '../../styles';
10
5
  import { ConditionalWrapper } from '../conditional-wrapper';
11
- import { Stack } from '../stack';
6
+ import { Text, TextProps } from '../text';
12
7
 
13
- import { headingRecipe } from './heading.css';
8
+ import { headingRoot } from './heading.css';
14
9
 
15
- type HeadingTypes = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
10
+ export type HeadingTypes = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
16
11
 
17
- type HeadingProps<TUse extends HeadingTypes> =
18
- PolymorphicComponentProps<TUse> & {
19
- /**
20
- * The size of the typography used to render the text.
21
- */
22
- size?: TypographySize;
12
+ export type HeadingProps<TUse extends ElementType = 'h2'> = Omit<
13
+ TextProps<TUse>,
14
+ 'variant' | 'children'
15
+ > & {
16
+ /**
17
+ * The typography used to render the text.
18
+ */
19
+ variant: Extract<TypographyVariant, 'display' | 'headline' | 'title'>;
23
20
 
24
- /**
25
- * The typography used to render the text.
26
- */
27
- variant: Extract<TypographyVariant, 'display' | 'headline' | 'title'>;
21
+ /**
22
+ * If provided, the text will be rendered before the title.
23
+ */
24
+ pretitle?: ReactElement<TextProps<'p'>>;
28
25
 
29
- /**
30
- * The text to render.
31
- */
32
- children: string;
26
+ /**
27
+ * If provided, the text will be rendered after the title.
28
+ */
29
+ subtitle?: ReactElement<TextProps<'p'>>;
33
30
 
34
- /**
35
- * If provided, the text will be rendered before the title.
36
- */
37
- pretitle?: string;
31
+ /**
32
+ * The spacing between the title and the pretitle or subtitle.
33
+ */
34
+ spacing?: Spacing;
38
35
 
39
- /**
40
- * If provided, the text will be rendered after the title.
41
- */
42
- subtitle?: string;
36
+ /**
37
+ * The text to render.
38
+ */
39
+ children: string;
40
+ };
43
41
 
44
- /**
45
- * The spacing between the title and the pretitle or subtitle.
46
- */
47
- spacing?: Spacing;
48
- };
49
-
50
- export function Heading<TUse extends HeadingTypes>(props: HeadingProps<TUse>) {
51
- const {
52
- children,
53
- className,
54
- size = 'medium',
55
- use: Comp = 'h1',
56
- variant,
57
- pretitle,
58
- subtitle,
59
- spacing,
60
- ...rest
61
- } = props;
42
+ const headingMapping: Record<
43
+ HeadingTypes,
44
+ { variant: TypographyVariant; size: TypographySize }
45
+ > = {
46
+ h1: { variant: 'display', size: 'large' },
47
+ h2: { variant: 'display', size: 'medium' },
48
+ h3: { variant: 'display', size: 'small' },
49
+ h4: { variant: 'headline', size: 'large' },
50
+ h5: { variant: 'headline', size: 'medium' },
51
+ h6: { variant: 'headline', size: 'small' },
52
+ };
62
53
 
54
+ export function Heading<TUse extends HeadingTypes>({
55
+ children,
56
+ use = 'h2',
57
+ size,
58
+ variant,
59
+ align,
60
+ spacing,
61
+ pretitle,
62
+ subtitle,
63
+ ...rest
64
+ }: HeadingProps<TUse>) {
63
65
  return (
64
66
  <ConditionalWrapper
65
- use={Stack}
66
- spacing={spacing}
67
+ use={'hgroup'}
67
68
  condition={!!pretitle || !!subtitle}
69
+ className={clsx(headingRoot({ align, spacing }))}
68
70
  >
69
- {pretitle && <span>{pretitle}</span>}
70
- <Comp
71
- className={clsx(
72
- headingRecipe(),
73
- getProp(typography, `${variant}.${size}`),
74
- className,
75
- )}
71
+ {pretitle}
72
+
73
+ <Text
74
+ use={use}
75
+ align={align}
76
+ variant={variant ?? headingMapping[use].variant}
77
+ size={size ?? headingMapping[use].size}
76
78
  {...rest}
77
79
  >
78
80
  {children}
79
- </Comp>
80
- {subtitle && <span>{subtitle}</span>}
81
+ </Text>
82
+
83
+ {subtitle}
81
84
  </ConditionalWrapper>
82
85
  );
83
86
  }
87
+
88
+ Heading.Pretitle = function HeadingPretitle({
89
+ variant = 'title',
90
+ size = 'medium',
91
+ ...rest
92
+ }: TextProps<'p'>) {
93
+ return <Text use="p" variant={variant} size={size} {...rest} />;
94
+ };
95
+
96
+ Heading.Subtitle = function HeadingSubtitle({
97
+ variant = 'title',
98
+ size = 'medium',
99
+ ...rest
100
+ }: TextProps<'p'>) {
101
+ return <Text use="p" variant={variant} size={size} {...rest} />;
102
+ };
@@ -1 +1,2 @@
1
- export { Heading } from './heading';
1
+ export { Heading, type HeadingTypes, type HeadingProps } from './heading';
2
+ export { headingRoot, type HeadingRootVariants } from './heading.css';
@@ -1,13 +1,14 @@
1
1
  export { Box } from './box';
2
2
  export { Button } from './button';
3
+ export { Card } from './card';
3
4
  export { Center } from './center';
4
5
  export { Cluster } from './cluster';
5
- export { ConditionalWrapper } from "./conditional-wrapper";
6
+ export { ConditionalWrapper } from './conditional-wrapper';
6
7
  export { Cover } from './cover';
7
8
  export { Frame } from './frame';
8
9
  export { Grid } from './grid';
9
- export { Heading } from "./heading";
10
- export { plantSeed } from './seed';
10
+ export { Heading } from './heading';
11
+ export { plantSeed, withSeed } from './seed';
11
12
  export { Sidebar } from './sidebar';
12
13
  export { Stack } from './stack';
13
14
  export { Switcher } from './switcher';
@@ -1 +1 @@
1
- export { plantSeed } from './seed';
1
+ export { plantSeed, withSeed } from './seed';
@@ -1,6 +1,6 @@
1
1
  import { type PolymorphicComponentProps } from '@kalink-ui/dibbly';
2
2
  import { clsx } from 'clsx';
3
- import { type ElementType } from 'react';
3
+ import { ComponentType, type ElementType } from 'react';
4
4
 
5
5
  import {
6
6
  extractSprinklesProps,
@@ -48,3 +48,40 @@ export function plantSeed<SprinklesFn extends SprinklesFnBase>({
48
48
 
49
49
  return Seed;
50
50
  }
51
+
52
+ /**
53
+ * A higher-order component that injects sprinkles and default className.
54
+ */
55
+ export function withSeed<SprinklesFn extends SprinklesFnBase>({
56
+ sprinkles,
57
+ defaultClassName,
58
+ }: CreateSeedParams<SprinklesFn>) {
59
+ return function wrapWithSprinkles<TProps, TUse extends ElementType>(
60
+ WrappedComponent: ComponentType<PolymorphicComponentProps<TUse> & TProps>,
61
+ ) {
62
+ const ComponentWithSeed = (
63
+ props: SeedProps<TUse, SprinklesFn> & TProps,
64
+ ) => {
65
+ const { className, ...rest } = props;
66
+
67
+ const [sprinklesProps, componentProps] = extractSprinklesProps(
68
+ rest,
69
+ sprinkles,
70
+ );
71
+
72
+ return (
73
+ // @ts-expect-error - TODO: fix this
74
+ <WrappedComponent
75
+ className={clsx(
76
+ sprinkles(sprinklesProps),
77
+ defaultClassName,
78
+ className,
79
+ )}
80
+ {...componentProps}
81
+ />
82
+ );
83
+ };
84
+
85
+ return ComponentWithSeed;
86
+ };
87
+ }
@@ -1,25 +1,164 @@
1
- import { style } from '@vanilla-extract/css';
1
+ import { createVar, style } from '@vanilla-extract/css';
2
2
  import { recipe, type RecipeVariants } from '@vanilla-extract/recipes';
3
3
 
4
+ import { components } from '../../styles/layers.css';
5
+
6
+ const lineClampNumber = createVar();
7
+
8
+ const lineClamp = style({
9
+ '@layer': {
10
+ [components]: {
11
+ display: '-webkit-box',
12
+ WebkitLineClamp: lineClampNumber,
13
+ WebkitBoxOrient: 'vertical',
14
+ overflow: 'hidden',
15
+ },
16
+ },
17
+ });
18
+
4
19
  export const textRecipe = recipe({
5
20
  variants: {
21
+ /**
22
+ * Controls the wrapping of the text.
23
+ */
24
+ wrap: {
25
+ true: {
26
+ '@layer': {
27
+ [components]: {
28
+ textWrap: 'wrap',
29
+ },
30
+ },
31
+ },
32
+ false: {
33
+ '@layer': {
34
+ [components]: {
35
+ textWrap: 'nowrap',
36
+ },
37
+ },
38
+ },
39
+ balance: {
40
+ '@layer': {
41
+ [components]: {
42
+ textWrap: 'balance',
43
+ },
44
+ },
45
+ },
46
+ pretty: {
47
+ '@layer': {
48
+ [components]: {
49
+ textWrap: 'pretty',
50
+ },
51
+ },
52
+ },
53
+ },
54
+
6
55
  /**
7
56
  * If true, use an ellipsis when the text overflows the element.
8
57
  */
9
- ellipsis: {
58
+ truncate: {
10
59
  true: {
11
- display: 'inline-block',
12
- maxWidth: '100%',
13
- overflow: 'hidden',
60
+ '@layer': {
61
+ [components]: {
62
+ display: 'inline-block',
63
+ maxWidth: '100%',
64
+ overflow: 'hidden',
65
+
66
+ textOverflow: 'ellipsis',
67
+ },
68
+ },
69
+ },
70
+ },
71
+
72
+ /**
73
+ * If provided, the text will be truncated and displayed with a maximum of
74
+ * the provided number of lines.
75
+ */
76
+ lineClamp: {
77
+ 2: [
78
+ lineClamp,
79
+ {
80
+ '@layer': {
81
+ [components]: {
82
+ vars: {
83
+ [lineClampNumber]: '2',
84
+ },
85
+ },
86
+ },
87
+ },
88
+ ],
89
+ 3: [
90
+ lineClamp,
91
+ {
92
+ '@layer': {
93
+ [components]: {
94
+ vars: {
95
+ [lineClampNumber]: '3',
96
+ },
97
+ },
98
+ },
99
+ },
100
+ ],
101
+ 4: [
102
+ lineClamp,
103
+ {
104
+ '@layer': {
105
+ [components]: {
106
+ vars: {
107
+ [lineClampNumber]: '4',
108
+ },
109
+ },
110
+ },
111
+ },
112
+ ],
113
+ 5: [
114
+ lineClamp,
115
+ {
116
+ '@layer': {
117
+ [components]: {
118
+ vars: {
119
+ [lineClampNumber]: '5',
120
+ },
121
+ },
122
+ },
123
+ },
124
+ ],
125
+ },
14
126
 
15
- textOverflow: 'ellipsis',
127
+ /**
128
+ * Controls the alignment of the text.
129
+ */
130
+ align: {
131
+ start: {
132
+ '@layer': {
133
+ [components]: {
134
+ textAlign: 'start',
135
+ },
136
+ },
137
+ },
138
+ center: {
139
+ '@layer': {
140
+ [components]: {
141
+ textAlign: 'center',
142
+ },
143
+ },
144
+ },
145
+ end: {
146
+ '@layer': {
147
+ [components]: {
148
+ textAlign: 'end',
149
+ },
150
+ },
16
151
  },
17
152
  },
18
153
  },
19
154
  });
20
155
 
21
156
  export const textEllipsisWrapper = style({
22
- whiteSpace: 'nowrap',
157
+ '@layer': {
158
+ [components]: {
159
+ whiteSpace: 'nowrap',
160
+ },
161
+ },
23
162
  });
24
163
 
25
164
  export type TextVariants = NonNullable<RecipeVariants<typeof textRecipe>>;
@@ -1,8 +1,4 @@
1
- import {
2
- DistributiveOmit,
3
- PolymorphicComponentProps,
4
- getProp,
5
- } from '@kalink-ui/dibbly';
1
+ import { PolymorphicComponentProps, getProp } from '@kalink-ui/dibbly';
6
2
  import { clsx } from 'clsx';
7
3
  import { ElementType } from 'react';
8
4
 
@@ -10,48 +6,44 @@ import { TypographySize, TypographyVariant, typography } from '../../styles';
10
6
 
11
7
  import { TextVariants, textRecipe, textEllipsisWrapper } from './text.css';
12
8
 
13
- export type TextProps<TUse extends React.ElementType> = DistributiveOmit<
14
- PolymorphicComponentProps<TUse>,
15
- 'children'
16
- > &
17
- TextVariants & {
18
- /**
19
- * The size of the typography used to render the text.
20
- */
21
- size?: TypographySize;
9
+ export type TextProps<TUse extends React.ElementType> =
10
+ PolymorphicComponentProps<TUse> &
11
+ TextVariants & {
12
+ /**
13
+ * The size of the typography used to render the text.
14
+ */
15
+ size?: TypographySize;
22
16
 
23
- /**
24
- * The typography variant used to render the text.
25
- */
26
- variant?: Extract<TypographyVariant, 'body' | 'caption' | 'label'>;
27
-
28
- /**
29
- * The text to render.
30
- */
31
- children: string;
32
- };
17
+ /**
18
+ * The typography variant used to render the text.
19
+ */
20
+ variant?: TypographyVariant;
21
+ };
33
22
 
34
23
  export function Text<TUse extends ElementType>(props: TextProps<TUse>) {
35
24
  const {
36
25
  children,
37
26
  className,
38
- ellipsis,
27
+ truncate,
28
+ lineClamp,
39
29
  size = 'medium',
40
30
  use: Comp = 'span',
41
31
  variant = 'body',
32
+ wrap,
33
+ align,
42
34
  ...rest
43
35
  } = props;
44
36
 
45
37
  return (
46
38
  <Comp
47
39
  className={clsx(
48
- textRecipe({ ellipsis }),
49
40
  getProp(typography, `${variant}.${size}`),
41
+ textRecipe({ truncate, lineClamp, align, wrap }),
50
42
  className,
51
43
  )}
52
44
  {...rest}
53
45
  >
54
- {ellipsis ? (
46
+ {truncate ? (
55
47
  <span className={textEllipsisWrapper}>{children}</span>
56
48
  ) : (
57
49
  children
@@ -28,8 +28,6 @@ export const sys = createThemeContract({
28
28
  color: {
29
29
  background: null,
30
30
  foreground: null,
31
- muted: null,
32
- outline: null,
33
31
  },
34
32
 
35
33
  state: {
@@ -1,5 +1,6 @@
1
1
  import { styleVariants } from '@vanilla-extract/css';
2
2
 
3
+ import { base } from './layers.css';
3
4
  import { sys, TypographySize, TypographyVariant } from './system-contract.css';
4
5
 
5
6
  export const typography = Object.entries(sys.typography).reduce(
@@ -8,11 +9,15 @@ export const typography = Object.entries(sys.typography).reduce(
8
9
  ...acc,
9
10
  [key]: styleVariants(value, (variant) => {
10
11
  return {
11
- fontFamily: variant.font,
12
- fontWeight: variant.weight,
13
- lineHeight: variant.lineHeight,
14
- letterSpacing: variant.tracking,
15
- fontSize: variant.size,
12
+ '@layer': {
13
+ [base]: {
14
+ fontFamily: variant.font,
15
+ fontWeight: variant.weight,
16
+ lineHeight: variant.lineHeight,
17
+ letterSpacing: variant.tracking,
18
+ fontSize: variant.size,
19
+ },
20
+ },
16
21
  };
17
22
  }),
18
23
  };
@@ -0,0 +1,36 @@
1
+ import { type ComplexStyleRule } from '@vanilla-extract/css';
2
+ import { type RuntimeFn } from '@vanilla-extract/recipes';
3
+
4
+ type RecipeStyleRule = ComplexStyleRule | string;
5
+ type VariantDefinitions = Record<string, RecipeStyleRule>;
6
+ type VariantGroups = Record<string, VariantDefinitions>;
7
+
8
+ export function argTypesFromRecipe(
9
+ recipe: RuntimeFn<VariantGroups>,
10
+ excludes: string[] = [],
11
+ ) {
12
+ return Object.entries(recipe.classNames.variants).reduce(
13
+ (acc, [name, variant]) => {
14
+ if (excludes.includes(name)) {
15
+ return acc;
16
+ }
17
+
18
+ const options = Object.keys(variant);
19
+ let control = options.length > 5 ? 'select' : 'radio';
20
+
21
+ if (options.length === 1 && options[0] === 'true') {
22
+ options.push('false');
23
+ control = 'boolean';
24
+ }
25
+
26
+ return {
27
+ ...acc,
28
+ [name]: {
29
+ control,
30
+ options,
31
+ },
32
+ };
33
+ },
34
+ {},
35
+ );
36
+ }
@@ -0,0 +1,43 @@
1
+ import { isObject } from '@kalink-ui/dibbly';
2
+
3
+ type ArgTypesFromSprinklesProps = {
4
+ /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
5
+ props: Record<string, any>;
6
+ excludes?: string[];
7
+ category?: string;
8
+ } & {};
9
+
10
+ export function argTypesFromSprinkles({
11
+ props,
12
+ excludes = [],
13
+ category = 'Sprinkles props',
14
+ }: ArgTypesFromSprinklesProps) {
15
+ return Object.entries(props).reduce((acc, [name]) => {
16
+ if (Array.isArray(excludes) && excludes.includes(name)) {
17
+ return acc;
18
+ }
19
+
20
+ let options = props[name] || [];
21
+ let control = 'select';
22
+
23
+ if (options.length === 1 && options[0] === 'true') {
24
+ options.push('false');
25
+ control = 'boolean';
26
+ }
27
+
28
+ if (isObject(options)) {
29
+ options = Object.fromEntries(
30
+ Object.keys(options).map((key) => [key, key]),
31
+ );
32
+ }
33
+
34
+ return {
35
+ ...acc,
36
+ [name]: {
37
+ control,
38
+ options,
39
+ table: { category },
40
+ },
41
+ };
42
+ }, {});
43
+ }
@@ -0,0 +1,13 @@
1
+ export const composable = {
2
+ children: {
3
+ control: false,
4
+ description: 'Content of the component.',
5
+ defaultValue: '',
6
+ table: {
7
+ category: 'Intrinsic props',
8
+ type: {
9
+ summary: 'ReactNode',
10
+ },
11
+ },
12
+ },
13
+ };
@@ -0,0 +1,4 @@
1
+ export { composable } from './composable';
2
+ export { polymorphic } from './polymorphic';
3
+ export { referable } from './referable';
4
+ export { stylable } from './stylable';
@@ -0,0 +1,14 @@
1
+ export const polymorphic = {
2
+ use: {
3
+ control: false,
4
+ description:
5
+ 'The component used to render the root node of the component. Either a string to use an `JSX.IntrinsicElements` or a component reference to use a `React.ComponentType`',
6
+ defaultValue: '',
7
+ table: {
8
+ category: 'Intrinsic props',
9
+ type: {
10
+ summary: 'ElementType',
11
+ },
12
+ },
13
+ },
14
+ };
@@ -0,0 +1,10 @@
1
+ export const referable = {
2
+ ref: {
3
+ control: false,
4
+ description: 'Ref passed to the component root.',
5
+ defaultValue: '',
6
+ table: {
7
+ category: 'Intrinsic props',
8
+ },
9
+ },
10
+ };
@@ -0,0 +1,14 @@
1
+ export const stylable = {
2
+ className: {
3
+ control: false,
4
+ description:
5
+ 'A class name string passed to the component. Merged with the inner class names.',
6
+ defaultValue: '',
7
+ table: {
8
+ category: 'Intrinsic props',
9
+ type: {
10
+ summary: 'string',
11
+ },
12
+ },
13
+ },
14
+ };
@@ -0,0 +1,26 @@
1
+ /* eslint-disable import/namespace */
2
+ import * as CommonArgDefs from './common';
3
+
4
+ export enum CommonArgs {
5
+ COMPOSABLE = 'composable',
6
+ POLYMORPHIC = 'polymorphic',
7
+ STYLABLE = 'stylable',
8
+ REFERABLE = 'referable',
9
+ }
10
+
11
+ export function commonArgs(args: CommonArgs[]) {
12
+ const argTypes: Partial<Record<string, object>> = {};
13
+ const knownArgs = Object.values(CommonArgs);
14
+
15
+ for (const arg of args) {
16
+ if (!knownArgs.includes(arg)) {
17
+ continue;
18
+ }
19
+
20
+ for (const argDef in CommonArgDefs[arg]) {
21
+ argTypes[argDef] = (CommonArgDefs[arg] as Record<string, object>)[argDef];
22
+ }
23
+ }
24
+
25
+ return argTypes;
26
+ }
@@ -0,0 +1,3 @@
1
+ export { argTypesFromRecipe } from './arg-types-from-recipe';
2
+ export { argTypesFromSprinkles } from './arg-types-from-sprinkles';
3
+ export { commonArgs, CommonArgs } from './common-args';