@kalink-ui/seedly 0.33.2 → 0.34.4

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 CHANGED
@@ -1,5 +1,51 @@
1
1
  # @kalink-ui/seedly
2
2
 
3
+ ## 0.34.4
4
+
5
+ ### Patch Changes
6
+
7
+ - 3b84777: Re-export the SheetBody, SheetFooter, and SheetOverlay components from the sheet entrypoint.
8
+
9
+ ## 0.34.3
10
+
11
+ ### Patch Changes
12
+
13
+ - a9c74d3: Rebump packages to align dev with trusted publishing rollout.
14
+ - Updated dependencies [a9c74d3]
15
+ - @kalink-ui/dibbly@0.6.3
16
+
17
+ ## 0.34.2
18
+
19
+ ### Patch Changes
20
+
21
+ - 7098356: Align package repository URLs with provenance origin for trusted publishing.
22
+ - Updated dependencies [7098356]
23
+ - @kalink-ui/dibbly@0.6.2
24
+
25
+ ## 0.34.1
26
+
27
+ ### Patch Changes
28
+
29
+ - 3642627: Trigger publish with trusted publishing and Playwright setup updates.
30
+ - Updated dependencies [3642627]
31
+ - @kalink-ui/dibbly@0.6.1
32
+
33
+ ## 0.34.0
34
+
35
+ ### Minor Changes
36
+
37
+ - 1efa841: Harden test suites (Vitest v4, Playwright, Storybook) and improve accessibility.
38
+
39
+ Breaking changes (still released as `minor` because we are in `0.x`):
40
+ - `@kalink-ui/seedly`: `ButtonIcon` now requires a `label` prop for accessibility.
41
+ - Migration: replace `aria-label="..."` with `label="..."` on `ButtonIcon`.
42
+ - Icon children are treated as decorative (`aria-hidden`) and the label is announced via visually-hidden text.
43
+
44
+ ### Patch Changes
45
+
46
+ - Updated dependencies [1efa841]
47
+ - @kalink-ui/dibbly@0.6.0
48
+
3
49
  ## 0.33.2
4
50
 
5
51
  ### Patch Changes
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@kalink-ui/seedly",
3
- "version": "0.33.2",
3
+ "version": "0.34.4",
4
4
  "description": "A set of components for building UIs with React and TypeScript",
5
- "sideEffects": false,
5
+ "sideEffects": [
6
+ "**/*.css.ts"
7
+ ],
6
8
  "license": "MIT",
7
9
  "author": "Louis Gollut",
8
10
  "repository": {
9
11
  "type": "git",
10
- "url": "git+https://github.com/Kalink/kalink-ui.git"
12
+ "url": "https://github.com/kalink-studio/kalink-ui"
11
13
  },
12
14
  "exports": {
13
15
  ".": "./src/index.ts",
@@ -16,35 +18,42 @@
16
18
  "./styles/layers": "./src/styles/layers.css.ts"
17
19
  },
18
20
  "devDependencies": {
19
- "@chromatic-com/storybook": "^4.1.1",
20
- "@storybook/addon-docs": "^9.1.10",
21
- "@storybook/addon-onboarding": "^9.1.10",
22
- "@storybook/react-vite": "^9.1.10",
23
- "@turbo/gen": "^2.5.8",
21
+ "@chromatic-com/storybook": "^4.1.3",
22
+ "@liip/storybook-addon-resizr": "^0.1.5",
23
+ "@storybook/addon-a11y": "^10.1.10",
24
+ "@storybook/addon-docs": "^10.1.10",
25
+ "@storybook/addon-onboarding": "^10.1.10",
26
+ "@storybook/addon-vitest": "^10.1.10",
27
+ "@storybook/react-vite": "^10.1.10",
28
+ "@turbo/gen": "^2.7.1",
24
29
  "@types/node": "^24.6.2",
25
- "@types/react": "^19.2.0",
26
- "@types/react-dom": "^19.2.0",
27
- "@vanilla-extract/css": "^1.17.4",
30
+ "@types/react": "^19.2.7",
31
+ "@types/react-dom": "^19.2.3",
32
+ "@vanilla-extract/css": "^1.18.0",
28
33
  "@vanilla-extract/css-utils": "^0.1.6",
29
34
  "@vanilla-extract/dynamic": "^2.1.5",
30
35
  "@vanilla-extract/recipes": "^0.5.7",
31
36
  "@vanilla-extract/sprinkles": "^1.6.5",
32
- "@vanilla-extract/vite-plugin": "^5.1.1",
33
- "@vitejs/plugin-react": "^5.0.4",
34
- "eslint": "^9.37.0",
35
- "eslint-plugin-storybook": "9.1.10",
36
- "lucide-react": "^0.544.0",
37
- "react": "^19.2.0",
37
+ "@vanilla-extract/vite-plugin": "^5.1.4",
38
+ "@vitejs/plugin-react": "^5.1.2",
39
+ "@vitest/browser": "^4.0.16",
40
+ "@vitest/browser-playwright": "^4.0.16",
41
+ "@vitest/coverage-v8": "^4.0.16",
42
+ "eslint": "^9.39.2",
43
+ "eslint-plugin-storybook": "10.1.10",
44
+ "lucide-react": "^0.562.0",
45
+ "playwright": "^1.57.0",
46
+ "react": "^19.2.3",
38
47
  "react-docgen-typescript": "^2.4.0",
39
- "react-dom": "^19.2.0",
40
- "storybook": "^9.1.10",
41
- "type-fest": "^5.0.1",
48
+ "react-dom": "^19.2.3",
49
+ "storybook": "^10.1.10",
50
+ "type-fest": "^5.3.1",
42
51
  "typescript": "^5.9.3",
43
- "vite": "^7.1.9",
44
- "vite-tsconfig-paths": "^5.1.4",
45
- "vitest": "^3.2.4",
46
- "@kalink-ui/typescript-config": "0.4.0",
47
- "@kalink-ui/eslint-config": "0.10.2"
52
+ "vite": "^7.3.0",
53
+ "vite-tsconfig-paths": "^6.0.3",
54
+ "vitest": "^4.0.16",
55
+ "@kalink-ui/eslint-config": "0.11.3",
56
+ "@kalink-ui/typescript-config": "0.4.2"
48
57
  },
49
58
  "peerDependencies": {
50
59
  "@vanilla-extract/css": "^1.17.4",
@@ -63,10 +72,10 @@
63
72
  "@radix-ui/react-popover": "^1.1.15",
64
73
  "@radix-ui/react-scroll-area": "^1.2.10",
65
74
  "@radix-ui/react-select": "^2.2.6",
66
- "@radix-ui/react-slot": "^1.2.3",
75
+ "@radix-ui/react-slot": "^1.2.4",
67
76
  "clsx": "^2.1.1",
68
77
  "cmdk": "^1.1.1",
69
- "@kalink-ui/dibbly": "^0.5.3"
78
+ "@kalink-ui/dibbly": "^0.6.3"
70
79
  },
71
80
  "publishConfig": {
72
81
  "access": "public"
@@ -0,0 +1,31 @@
1
+ import {
2
+ Children,
3
+ cloneElement,
4
+ ReactElement,
5
+ ReactNode,
6
+ SVGAttributes,
7
+ } from 'react';
8
+
9
+ import { VisuallyHidden } from '../visually-hidden';
10
+
11
+ export interface AccessibleIconProps {
12
+ children?: ReactNode;
13
+ /**
14
+ * The accessible label for the icon. This label will be visually hidden but announced to screen
15
+ * reader users, similar to `alt` text for `img` tags.
16
+ */
17
+ label: string;
18
+ }
19
+
20
+ export function AccessibleIcon({ children, label }: AccessibleIconProps) {
21
+ const child = Children.only(children);
22
+ return (
23
+ <>
24
+ {cloneElement(child as ReactElement<SVGAttributes<SVGElement>>, {
25
+ 'aria-hidden': 'true',
26
+ focusable: 'false', // See: https://allyjs.io/tutorials/focusing-in-svg.html#making-svg-elements-focusable
27
+ })}
28
+ <VisuallyHidden>{label}</VisuallyHidden>
29
+ </>
30
+ );
31
+ }
@@ -0,0 +1 @@
1
+ export { AccessibleIcon, type AccessibleIconProps } from './accessible-icon';
@@ -1,6 +1,7 @@
1
1
  import { PolymorphicComponentProps } from '@kalink-ui/dibbly';
2
2
  import { clsx } from 'clsx';
3
3
 
4
+ import { AccessibleIcon } from '../accessible-icon';
4
5
  import { ButtonTypes } from '../button/button';
5
6
 
6
7
  import { ButtonIconVariants } from './button-icon.css';
@@ -15,17 +16,30 @@ type ButtonIconVariantResponsive = {
15
16
  };
16
17
 
17
18
  export type ButtonIconProps<TUse extends ButtonTypes> =
18
- PolymorphicComponentProps<TUse> & ButtonIconVariantResponsive;
19
+ PolymorphicComponentProps<TUse> &
20
+ ButtonIconVariantResponsive & {
21
+ label: string;
22
+ };
19
23
 
20
24
  export function ButtonIcon<TUse extends ButtonTypes>(
21
25
  props: ButtonIconProps<TUse>,
22
26
  ) {
23
- const { use: Comp = 'button', className, variant, size, ...rest } = props;
27
+ const {
28
+ use: Comp = 'button',
29
+ className,
30
+ variant,
31
+ size,
32
+ children,
33
+ label,
34
+ ...rest
35
+ } = props;
24
36
 
25
37
  return (
26
38
  <Comp
27
39
  className={clsx(buttonIconResponsive({ variant, size }), className)}
28
40
  {...(rest as Record<string, unknown>)}
29
- />
41
+ >
42
+ <AccessibleIcon label={label}>{children}</AccessibleIcon>
43
+ </Comp>
30
44
  );
31
45
  }
@@ -47,13 +47,13 @@ export const formFieldStyle = recipe({
47
47
 
48
48
  vars: {
49
49
  [formFieldVars.color.foreground]:
50
- `color(from ${sys.color.foreground} srgb r g b / 0.38)`,
50
+ `color-mix(in srgb, ${sys.color.foreground} calc(${sys.state.muted.light} * 75%), transparent)`,
51
51
  },
52
52
  },
53
53
 
54
54
  '&[aria-invalid], &:has([aria-invalid])': {
55
55
  vars: {
56
- [formFieldVars.color.foreground]: 'red',
56
+ [formFieldVars.color.foreground]: '#d80000',
57
57
  },
58
58
  },
59
59
  },
@@ -67,7 +67,7 @@ export const formFieldStyle = recipe({
67
67
  '@layer': {
68
68
  [components]: {
69
69
  vars: {
70
- [formFieldVars.color.foreground]: 'red',
70
+ [formFieldVars.color.foreground]: '#d80000',
71
71
  },
72
72
  },
73
73
  },
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { Corner, Root, Viewport } from '@radix-ui/react-scroll-area';
4
4
  import { assignInlineVars } from '@vanilla-extract/dynamic';
5
+ import { clsx } from 'clsx';
5
6
  import { ComponentPropsWithRef } from 'react';
6
7
 
7
8
  import {
@@ -13,6 +14,8 @@ import { ScrollBar } from './scroll-bar';
13
14
 
14
15
  export type ScrollAreaProps = ComponentPropsWithRef<typeof Root> & {
15
16
  maxHeight?: string;
17
+ /** Scrollbar orientation. Use 'both' for both vertical and horizontal scrollbars. */
18
+ orientation?: 'vertical' | 'horizontal' | 'both';
16
19
  };
17
20
 
18
21
  export function ScrollArea({
@@ -20,11 +23,13 @@ export function ScrollArea({
20
23
  className,
21
24
  children,
22
25
  maxHeight = 'initial',
26
+ orientation = 'vertical',
23
27
  ...props
24
28
  }: ScrollAreaProps) {
25
29
  return (
26
- <Root ref={ref} className={scrollArea} {...props}>
30
+ <Root ref={ref} className={clsx(scrollArea, className)} {...props}>
27
31
  <Viewport
32
+ tabIndex={0}
28
33
  className={scrollAreaViewport}
29
34
  style={assignInlineVars({
30
35
  [viewportMaxHeight]: maxHeight,
@@ -32,7 +37,12 @@ export function ScrollArea({
32
37
  >
33
38
  {children}
34
39
  </Viewport>
35
- <ScrollBar />
40
+ {(orientation === 'vertical' || orientation === 'both') && (
41
+ <ScrollBar orientation="vertical" />
42
+ )}
43
+ {(orientation === 'horizontal' || orientation === 'both') && (
44
+ <ScrollBar orientation="horizontal" />
45
+ )}
36
46
  <Corner />
37
47
  </Root>
38
48
  );
@@ -3,3 +3,6 @@ export { SheetHeader } from './sheet-header';
3
3
  export { SheetTitle } from './sheet-title';
4
4
  export { SheetDescription } from './sheet-description';
5
5
  export { SheetContent } from './sheet-content';
6
+ export { SheetBody } from './sheet-body';
7
+ export { SheetFooter } from './sheet-footer';
8
+ export { SheetOverlay } from './sheet-overlay';
@@ -0,0 +1,68 @@
1
+ import { globalStyle, style } from '@vanilla-extract/css';
2
+
3
+ import { sys, transition } from '../../styles';
4
+
5
+ export const sheetBodyRoot = style({
6
+ flexGrow: 1,
7
+ flexShrink: 1,
8
+ flexBasis: 'auto',
9
+
10
+ overflow: 'hidden',
11
+ });
12
+
13
+ export const sheetBodyViewport = style({
14
+ height: '100%',
15
+ });
16
+
17
+ export const sheetBodyScrollbar = style({
18
+ display: 'flex',
19
+ userSelect: 'none',
20
+ touchAction: 'none',
21
+ padding: 2,
22
+ background: 'transparent',
23
+ transition: transition('background', { duration: 'short.3' }),
24
+ borderRadius: sys.shape.corner.small,
25
+
26
+ selectors: {
27
+ '&:hover': {
28
+ background: `color-mix(in srgb, ${sys.color.foreground} 10%, transparent)`,
29
+ },
30
+
31
+ '&[data-orientation="vertical"]': {
32
+ width: sys.spacing[2],
33
+ },
34
+ },
35
+ });
36
+
37
+ export const sheetBodyThumb = style({
38
+ flex: 1,
39
+ background: `color-mix(in srgb, ${sys.color.foreground} 50%, transparent)`,
40
+ borderRadius: sys.shape.corner.small,
41
+ position: 'relative',
42
+ opacity: 0,
43
+ transition: transition('opacity', { duration: 'short.3' }),
44
+ pointerEvents: 'none',
45
+
46
+ selectors: {
47
+ '&:hover': {
48
+ background: `color-mix(in srgb, ${sys.color.foreground} 75%, transparent)`,
49
+ },
50
+
51
+ '&::before': {
52
+ content: '""',
53
+ position: 'absolute',
54
+ insetBlockStart: '50%',
55
+ insetInlineStart: '50%',
56
+ width: '100%',
57
+ height: '100%',
58
+ minWidth: sys.spacing[4],
59
+ minHeight: sys.spacing[4],
60
+ transform: 'translate(-50%, -50%)',
61
+ },
62
+ },
63
+ });
64
+
65
+ globalStyle(`${sheetBodyScrollbar}[data-state="visible"] ${sheetBodyThumb}`, {
66
+ opacity: 1,
67
+ pointerEvents: 'auto',
68
+ });
@@ -0,0 +1,16 @@
1
+ import { ElementType } from 'react';
2
+
3
+ import { Box, BoxProps } from '../box';
4
+ import { ScrollArea } from '../scroll-area';
5
+
6
+ export type SheetBodyProps<TUse extends ElementType> = BoxProps<TUse>;
7
+
8
+ export function SheetBody<TUse extends ElementType>(
9
+ props: SheetBodyProps<TUse>,
10
+ ) {
11
+ return (
12
+ <ScrollArea>
13
+ <Box {...props} />
14
+ </ScrollArea>
15
+ );
16
+ }
@@ -1,7 +1,7 @@
1
1
  import { createVar, keyframes } from '@vanilla-extract/css';
2
2
  import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
3
3
 
4
- import { sys } from '../../styles';
4
+ import { mapContractVars, sys } from '../../styles';
5
5
  import { components } from '../../styles/layers.css';
6
6
 
7
7
  const from = createVar();
@@ -32,6 +32,9 @@ export const sheetContent = recipe({
32
32
  base: {
33
33
  '@layer': {
34
34
  [components]: {
35
+ display: 'flex',
36
+ flexDirection: 'column',
37
+
35
38
  zIndex: 50,
36
39
  maxWidth: '100vw',
37
40
  maxHeight: '100vh',
@@ -167,6 +170,14 @@ export const sheetContent = recipe({
167
170
  },
168
171
  },
169
172
  },
173
+
174
+ spacing: mapContractVars(sys.spacing, (key) => ({
175
+ '@layer': {
176
+ [components]: {
177
+ gap: sys.spacing[key],
178
+ },
179
+ },
180
+ })),
170
181
  },
171
182
 
172
183
  defaultVariants: {
@@ -5,7 +5,6 @@ import { clsx } from 'clsx';
5
5
  import { ComponentPropsWithRef, ElementType } from 'react';
6
6
 
7
7
  import { Box, BoxProps } from '../box';
8
- import { ScrollArea } from '../scroll-area';
9
8
 
10
9
  import { SheetPortal } from './sheet';
11
10
  import { sheetContent, SheetContentVariants } from './sheet-content.css';
@@ -22,6 +21,7 @@ export function SheetContent<TUse extends ElementType>({
22
21
  side,
23
22
  size,
24
23
  ref,
24
+ spacing = 4,
25
25
  ...props
26
26
  }: SheetContentProps<TUse>) {
27
27
  return (
@@ -31,11 +31,11 @@ export function SheetContent<TUse extends ElementType>({
31
31
  <Box
32
32
  ref={ref}
33
33
  variant="solid"
34
- className={clsx(sheetContent({ side, size }), className)}
34
+ spacing={spacing}
35
+ className={clsx(sheetContent({ side, size, spacing }), className)}
36
+ {...props}
35
37
  >
36
- <ScrollArea>
37
- <Box {...props}>{children}</Box>
38
- </ScrollArea>
38
+ {children}
39
39
  </Box>
40
40
  </Content>
41
41
  </SheetPortal>
@@ -0,0 +1,7 @@
1
+ import { style } from '@vanilla-extract/css';
2
+
3
+ export const sheetFooter = style({
4
+ flexGrow: 0,
5
+ flexShrink: 0,
6
+ flexBasis: 'auto',
7
+ });
@@ -1,14 +1,19 @@
1
+ import { clsx } from 'clsx';
1
2
  import { ElementType } from 'react';
2
3
 
3
- import { Box, BoxProps } from '../box';
4
+ import { Cluster, ClusterProps } from '../cluster';
4
5
 
5
- export function SheetFooter<TUse extends ElementType>(props: BoxProps<TUse>) {
6
+ import { sheetFooter } from './sheet-footer.css';
7
+
8
+ export function SheetFooter<TUse extends ElementType>({
9
+ spacing = 4,
10
+ className,
11
+ ...props
12
+ }: ClusterProps<TUse>) {
6
13
  return (
7
- <Box
8
- display="flex"
9
- flexDirection={{ sm: 'column-reverse', md: 'row' }}
10
- justifyContent={{ sm: 'flex-start', md: 'flex-end' }}
11
- gap="sm"
14
+ <Cluster
15
+ spacing={spacing}
16
+ className={clsx(sheetFooter, className)}
12
17
  {...props}
13
18
  />
14
19
  );
@@ -13,6 +13,9 @@ export const sheetHeader = recipe({
13
13
  justifyContent: 'space-between',
14
14
  flexWrap: 'nowrap',
15
15
  gap: sys.spacing[4],
16
+ flexGrow: 0,
17
+ flexShrink: 0,
18
+ flexBasis: 'auto',
16
19
  },
17
20
  },
18
21
  },
@@ -0,0 +1,2 @@
1
+ export { VisuallyHidden, type VisuallyHiddenProps } from './visually-hidden';
2
+ export { visuallyHiddenStyle } from './visually-hidden.css';
@@ -0,0 +1,17 @@
1
+ import { style } from '@vanilla-extract/css';
2
+
3
+ export const visuallyHiddenStyle = style({
4
+ width: 1,
5
+ height: 1,
6
+ padding: 0,
7
+ margin: -1,
8
+ overflow: 'hidden',
9
+ clip: 'rect(0, 0, 0, 0)',
10
+
11
+ position: 'absolute',
12
+
13
+ whiteSpace: 'nowrap',
14
+ wordWrap: 'normal',
15
+
16
+ border: 0,
17
+ });
@@ -0,0 +1,10 @@
1
+ import { clsx } from 'clsx';
2
+ import { ComponentPropsWithoutRef } from 'react';
3
+
4
+ import { visuallyHiddenStyle } from './visually-hidden.css';
5
+
6
+ export type VisuallyHiddenProps = ComponentPropsWithoutRef<'span'>;
7
+
8
+ export function VisuallyHidden({ className, ...props }: VisuallyHiddenProps) {
9
+ return <span {...props} className={clsx(visuallyHiddenStyle, className)} />;
10
+ }
@@ -129,8 +129,7 @@ export function getInterpolationFor(
129
129
  }
130
130
 
131
131
  export interface FluidClampForOptions
132
- extends DynamicInterpolationOptions,
133
- FluidClampOptions {}
132
+ extends DynamicInterpolationOptions, FluidClampOptions {}
134
133
 
135
134
  /**
136
135
  * Convenience to produce a CSS clamp() for a single `value` by first computing