@seed-design/react 2.4.1 → 2.5.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.
@@ -29,7 +29,19 @@ export declare const SidePanelTitle: React.ForwardRefExoticComponent<SidePanelTi
29
29
  export interface SidePanelDescriptionProps extends Drawer.DescriptionProps {
30
30
  }
31
31
  export declare const SidePanelDescription: React.ForwardRefExoticComponent<SidePanelDescriptionProps & React.RefAttributes<HTMLParagraphElement>>;
32
- export interface SidePanelBodyProps extends PrimitiveProps, Pick<StyleProps, "paddingX" | "height" | "maxHeight" | "minHeight" | "justifyContent" | "alignItems">, React.HTMLAttributes<HTMLDivElement> {
32
+ export interface SidePanelBodyProps extends PrimitiveProps, Pick<StyleProps, "paddingX" | "justifyContent" | "alignItems">, React.HTMLAttributes<HTMLDivElement> {
33
+ /**
34
+ * @deprecated SEED React 3.0.0에서 제거됩니다. Side Panel 본문은 항상 헤더와 푸터를 제외한 남은 높이를 채우므로 이 prop은 효과가 없습니다. 콘텐츠의 높이를 지정하려면 본문 안에 `Box`를 두고 `height`를 지정하세요.
35
+ */
36
+ height?: StyleProps["height"];
37
+ /**
38
+ * @deprecated SEED React 3.0.0에서 제거됩니다. Side Panel 본문은 항상 헤더와 푸터를 제외한 남은 높이를 채우므로, 남은 높이보다 큰 값을 주면 푸터가 패널 밖으로 밀려납니다. 콘텐츠의 최소 높이를 지정하려면 본문 안에 `Box`를 두고 `minHeight`를 지정하세요.
39
+ */
40
+ minHeight?: StyleProps["minHeight"];
41
+ /**
42
+ * @deprecated SEED React 3.0.0에서 제거됩니다. Side Panel 본문은 항상 헤더와 푸터를 제외한 남은 높이를 채우므로, 남은 높이보다 작은 값을 주면 푸터가 패널 중간에 뜹니다. 콘텐츠의 최대 높이를 지정하려면 본문 안에 `Box`를 두고 `maxHeight`를 지정하세요.
43
+ */
44
+ maxHeight?: StyleProps["maxHeight"];
33
45
  }
34
46
  export declare const SidePanelBody: React.ForwardRefExoticComponent<SidePanelBodyProps & React.RefAttributes<HTMLDivElement>>;
35
47
  export interface SidePanelFooterProps extends PrimitiveProps, React.HTMLAttributes<HTMLDivElement> {
@@ -1 +1 @@
1
- {"version":3,"file":"SidePanel.d.ts","sourceRoot":"","sources":["../../../src/components/SidePanel/SidePanel.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAC5F,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAI9E,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EAAiC,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAQpF,MAAM,WAAW,kBACf,SAAQ,qBAAqB,EAC3B,IAAI,CACF,MAAM,CAAC,SAAS,EACd,UAAU,GACV,MAAM,GACN,aAAa,GACb,cAAc,GACd,OAAO,GACP,aAAa,GACb,eAAe,GACf,wBAAwB,GACxB,WAAW,GACX,eAAe,GACf,gBAAgB,CACnB;IACH,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC9B;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,2CAgBtD;AAID,MAAM,WAAW,qBAAsB,SAAQ,MAAM,CAAC,YAAY;CAAG;AAErE,eAAO,MAAM,gBAAgB,+FAAiB,CAAC;AAI/C,MAAM,WAAW,wBAAyB,SAAQ,MAAM,CAAC,eAAe;CAAG;AAE3E,eAAO,MAAM,mBAAmB,iGAG/B,CAAC;AAIF,MAAM,WAAW,sBAAuB,SAAQ,MAAM,CAAC,aAAa;CAAG;AAEvE,eAAO,MAAM,iBAAiB,+FAG7B,CAAC;AAIF,MAAM,WAAW,qBACf,SAAQ,MAAM,CAAC,YAAY,EACzB,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,UAAU,CAAC;CAAG;AAE7C,eAAO,MAAM,gBAAgB,8FAG5B,CAAC;AAIF,MAAM,WAAW,oBAAqB,SAAQ,MAAM,CAAC,WAAW;CAAG;AAEnE,eAAO,MAAM,eAAe,6FAc3B,CAAC;AAMF,MAAM,WAAW,mBAAoB,SAAQ,MAAM,CAAC,UAAU;CAAG;AAEjE,eAAO,MAAM,cAAc,gGAG1B,CAAC;AAMF,MAAM,WAAW,yBAA0B,SAAQ,MAAM,CAAC,gBAAgB;CAAG;AAE7E,eAAO,MAAM,oBAAoB,wGAGhC,CAAC;AAMF,MAAM,WAAW,kBACf,SAAQ,cAAc,EACpB,IAAI,CACF,UAAU,EACV,UAAU,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,GAAG,gBAAgB,GAAG,YAAY,CACpF,EACD,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;CAAG;AAE3C,eAAO,MAAM,aAAa,2FAqCzB,CAAC;AAMF,MAAM,WAAW,oBACf,SAAQ,cAAc,EACpB,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;CAAG;AAE3C,eAAO,MAAM,eAAe,6FAG3B,CAAC;AAIF,MAAM,WAAW,yBAA0B,SAAQ,MAAM,CAAC,gBAAgB;CAAG;AAE7E,eAAO,MAAM,oBAAoB,qGAchC,CAAC"}
1
+ {"version":3,"file":"SidePanel.d.ts","sourceRoot":"","sources":["../../../src/components/SidePanel/SidePanel.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAC5F,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAI9E,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EAAiC,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAQpF,MAAM,WAAW,kBACf,SAAQ,qBAAqB,EAC3B,IAAI,CACF,MAAM,CAAC,SAAS,EACd,UAAU,GACV,MAAM,GACN,aAAa,GACb,cAAc,GACd,OAAO,GACP,aAAa,GACb,eAAe,GACf,wBAAwB,GACxB,WAAW,GACX,eAAe,GACf,gBAAgB,CACnB;IACH,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC9B;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,2CAgBtD;AAID,MAAM,WAAW,qBAAsB,SAAQ,MAAM,CAAC,YAAY;CAAG;AAErE,eAAO,MAAM,gBAAgB,+FAAiB,CAAC;AAI/C,MAAM,WAAW,wBAAyB,SAAQ,MAAM,CAAC,eAAe;CAAG;AAE3E,eAAO,MAAM,mBAAmB,iGAG/B,CAAC;AAIF,MAAM,WAAW,sBAAuB,SAAQ,MAAM,CAAC,aAAa;CAAG;AAEvE,eAAO,MAAM,iBAAiB,+FAG7B,CAAC;AAIF,MAAM,WAAW,qBACf,SAAQ,MAAM,CAAC,YAAY,EACzB,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,UAAU,CAAC;CAAG;AAE7C,eAAO,MAAM,gBAAgB,8FAG5B,CAAC;AAIF,MAAM,WAAW,oBAAqB,SAAQ,MAAM,CAAC,WAAW;CAAG;AAEnE,eAAO,MAAM,eAAe,6FAc3B,CAAC;AAMF,MAAM,WAAW,mBAAoB,SAAQ,MAAM,CAAC,UAAU;CAAG;AAEjE,eAAO,MAAM,cAAc,gGAG1B,CAAC;AAMF,MAAM,WAAW,yBAA0B,SAAQ,MAAM,CAAC,gBAAgB;CAAG;AAE7E,eAAO,MAAM,oBAAoB,wGAGhC,CAAC;AAMF,MAAM,WAAW,kBACf,SAAQ,cAAc,EACpB,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,gBAAgB,GAAG,YAAY,CAAC,EAC9D,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACtC;;OAEG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;IAE9B;;OAEG;IACH,SAAS,CAAC,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC;IAEpC;;OAEG;IACH,SAAS,CAAC,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC;CACrC;AAED,eAAO,MAAM,aAAa,2FAqCzB,CAAC;AAMF,MAAM,WAAW,oBACf,SAAQ,cAAc,EACpB,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;CAAG;AAE3C,eAAO,MAAM,eAAe,6FAG3B,CAAC;AAIF,MAAM,WAAW,yBAA0B,SAAQ,MAAM,CAAC,gBAAgB;CAAG;AAE7E,eAAO,MAAM,oBAAoB,qGAchC,CAAC"}
@@ -1,11 +1,31 @@
1
1
  "use client";
2
2
  require("../../_virtual/_rolldown/runtime.cjs");
3
+ const require_responsive = require("../../types/responsive.cjs");
3
4
  const require_styled = require("../../utils/styled.cjs");
4
5
  const require_createRecipeContext = require("../../utils/createRecipeContext.cjs");
6
+ let _seed_design_css_vars = require("@seed-design/css/vars");
5
7
  let _seed_design_react_primitive = require("@seed-design/react-primitive");
8
+ let react = require("react");
9
+ let react_jsx_runtime = require("react/jsx-runtime");
6
10
  let _seed_design_css_recipes_skeleton = require("@seed-design/css/recipes/skeleton");
7
11
  //#region src/components/Skeleton/Skeleton.tsx
8
12
  var { withContext } = require_createRecipeContext.createRecipeContext(_seed_design_css_recipes_skeleton.skeleton);
9
- var Skeleton = withContext(require_styled.withStyleProps(_seed_design_react_primitive.Primitive.div));
13
+ function handleHeight(height) {
14
+ if (!height?.startsWith("lineHeight.")) return height;
15
+ const value = _seed_design_css_vars.vars.$lineHeight[height.slice(11)];
16
+ return typeof value === "string" ? value : height;
17
+ }
18
+ var Skeleton = withContext((0, react.forwardRef)(function Skeleton({ height, ...props }, ref) {
19
+ const { style, restProps } = require_styled.useStyleProps({
20
+ ...props,
21
+ height: require_responsive.isResponsiveObject(height) ? Object.fromEntries(Object.entries(height).map(([key, value]) => [key, handleHeight(value)])) : handleHeight(height)
22
+ });
23
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_seed_design_react_primitive.Primitive.div, {
24
+ ref,
25
+ style,
26
+ ...restProps
27
+ });
28
+ }));
29
+ Skeleton.displayName = "Skeleton";
10
30
  //#endregion
11
31
  exports.Skeleton = Skeleton;
@@ -1,8 +1,11 @@
1
1
  import { PrimitiveProps } from '@seed-design/react-primitive';
2
2
  import { SkeletonVariantProps } from '@seed-design/css/recipes/skeleton';
3
+ import { LineHeight } from '@seed-design/css/vars';
4
+ import { ResponsiveValue, UnwrapResponsive } from '../../types/responsive';
3
5
  import { StyleProps } from '../../utils/styled';
4
6
  import type * as React from "react";
5
- export interface SkeletonProps extends SkeletonVariantProps, PrimitiveProps, Pick<StyleProps, "height" | "width">, Omit<React.HTMLAttributes<HTMLDivElement>, "color"> {
7
+ export interface SkeletonProps extends SkeletonVariantProps, PrimitiveProps, Pick<StyleProps, "width">, Omit<React.HTMLAttributes<HTMLDivElement>, "color"> {
8
+ height?: ResponsiveValue<UnwrapResponsive<StyleProps["height"]> | `lineHeight.${LineHeight}`>;
6
9
  }
7
10
  export declare const Skeleton: React.ForwardRefExoticComponent<SkeletonProps & React.RefAttributes<HTMLDivElement>>;
8
11
  //# sourceMappingURL=Skeleton.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Skeleton.d.ts","sourceRoot":"","sources":["../../../src/components/Skeleton/Skeleton.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACxF,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAEpC,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIrE,MAAM,WAAW,aACf,SAAQ,oBAAoB,EAC1B,cAAc,EACd,IAAI,CAAC,UAAU,EAAE,QAAQ,GAAG,OAAO,CAAC,EACpC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;CAAG;AAE1D,eAAO,MAAM,QAAQ,sFAA4E,CAAC"}
1
+ {"version":3,"file":"Skeleton.d.ts","sourceRoot":"","sources":["../../../src/components/Skeleton/Skeleton.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACxF,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAEpC,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIpE,MAAM,WAAW,aACf,SAAQ,oBAAoB,EAC1B,cAAc,EACd,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,EACzB,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IACrD,MAAM,CAAC,EAAE,eAAe,CAAC,gBAAgB,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,GAAG,cAAc,UAAU,EAAE,CAAC,CAAC;CAC/F;AAUD,eAAO,MAAM,QAAQ,sFAapB,CAAC"}
@@ -1,10 +1,30 @@
1
1
  "use client";
2
- import { withStyleProps } from "../../utils/styled.js";
2
+ import { isResponsiveObject } from "../../types/responsive.js";
3
+ import { useStyleProps } from "../../utils/styled.js";
3
4
  import { createRecipeContext } from "../../utils/createRecipeContext.js";
5
+ import { vars } from "@seed-design/css/vars";
4
6
  import { Primitive } from "@seed-design/react-primitive";
7
+ import { forwardRef } from "react";
8
+ import { jsx } from "react/jsx-runtime";
5
9
  import { skeleton } from "@seed-design/css/recipes/skeleton";
6
10
  //#region src/components/Skeleton/Skeleton.tsx
7
11
  var { withContext } = createRecipeContext(skeleton);
8
- var Skeleton = withContext(withStyleProps(Primitive.div));
12
+ function handleHeight(height) {
13
+ if (!height?.startsWith("lineHeight.")) return height;
14
+ const value = vars.$lineHeight[height.slice(11)];
15
+ return typeof value === "string" ? value : height;
16
+ }
17
+ var Skeleton = withContext(forwardRef(function Skeleton({ height, ...props }, ref) {
18
+ const { style, restProps } = useStyleProps({
19
+ ...props,
20
+ height: isResponsiveObject(height) ? Object.fromEntries(Object.entries(height).map(([key, value]) => [key, handleHeight(value)])) : handleHeight(height)
21
+ });
22
+ return /* @__PURE__ */ jsx(Primitive.div, {
23
+ ref,
24
+ style,
25
+ ...restProps
26
+ });
27
+ }));
28
+ Skeleton.displayName = "Skeleton";
9
29
  //#endregion
10
30
  export { Skeleton };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Skeleton.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Skeleton.test.d.ts","sourceRoot":"","sources":["../../../src/components/Skeleton/Skeleton.test.tsx"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seed-design/react",
3
- "version": "2.4.1",
3
+ "version": "2.5.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/daangn/seed-design.git",
@@ -83,7 +83,7 @@
83
83
  "unicode-segmenter": "^0.17.3"
84
84
  },
85
85
  "peerDependencies": {
86
- "@seed-design/css": "^2.6.0",
86
+ "@seed-design/css": "^2.8.0",
87
87
  "react": ">=18.0.0",
88
88
  "react-dom": ">=18.0.0"
89
89
  },
@@ -6,9 +6,9 @@
6
6
 
7
7
  ## 파일 작성 컨벤션
8
8
 
9
- - 컴포넌트별 디렉토리는 `PascalCase`를 사용하고, 기본 파일은 `{ComponentName}.tsx`, `{ComponentName}.namespace.ts`, `index.ts` 조합을 따른다.
10
- - 실제 구현은 `{ComponentName}.tsx`에 두고, namespace 단축 이름은 `{ComponentName}.namespace.ts`, 공개 re-export는 `index.ts`에 둔다.
11
- - helper slot이 내부 구현에만 필요하면 별도 파일 분리보다 같은 구현 파일 안에 두고 export surface에서 숨기는 쪽을 우선 검토한다.
9
+ - 컴포넌트별 디렉토리는 `PascalCase`를 사용한다. 단일 컴포넌트는 `{ComponentName}.tsx`와 `index.ts`를 기본으로 둔다.
10
+ - compound component에서 public namespace 단축 이름이 필요할 때만 `{ComponentName}.namespace.ts`를 추가한다.
11
+ - 실제 구현은 `{ComponentName}.tsx` 또는 역할별 구현 파일에 두고, 공개 re-export `index.ts`와 필요한 namespace 파일에서 관리한다.
12
12
 
13
13
  ## 코드 작성 컨벤션
14
14
 
@@ -137,11 +137,23 @@ SidePanelDescription.displayName = "SidePanelDescription";
137
137
 
138
138
  export interface SidePanelBodyProps
139
139
  extends PrimitiveProps,
140
- Pick<
141
- StyleProps,
142
- "paddingX" | "height" | "maxHeight" | "minHeight" | "justifyContent" | "alignItems"
143
- >,
144
- React.HTMLAttributes<HTMLDivElement> {}
140
+ Pick<StyleProps, "paddingX" | "justifyContent" | "alignItems">,
141
+ React.HTMLAttributes<HTMLDivElement> {
142
+ /**
143
+ * @deprecated SEED React 3.0.0에서 제거됩니다. Side Panel 본문은 항상 헤더와 푸터를 제외한 남은 높이를 채우므로 이 prop은 효과가 없습니다. 콘텐츠의 높이를 지정하려면 본문 안에 `Box`를 두고 `height`를 지정하세요.
144
+ */
145
+ height?: StyleProps["height"];
146
+
147
+ /**
148
+ * @deprecated SEED React 3.0.0에서 제거됩니다. Side Panel 본문은 항상 헤더와 푸터를 제외한 남은 높이를 채우므로, 남은 높이보다 큰 값을 주면 푸터가 패널 밖으로 밀려납니다. 콘텐츠의 최소 높이를 지정하려면 본문 안에 `Box`를 두고 `minHeight`를 지정하세요.
149
+ */
150
+ minHeight?: StyleProps["minHeight"];
151
+
152
+ /**
153
+ * @deprecated SEED React 3.0.0에서 제거됩니다. Side Panel 본문은 항상 헤더와 푸터를 제외한 남은 높이를 채우므로, 남은 높이보다 작은 값을 주면 푸터가 패널 중간에 뜹니다. 콘텐츠의 최대 높이를 지정하려면 본문 안에 `Box`를 두고 `maxHeight`를 지정하세요.
154
+ */
155
+ maxHeight?: StyleProps["maxHeight"];
156
+ }
145
157
 
146
158
  export const SidePanelBody = React.forwardRef<HTMLDivElement, SidePanelBodyProps>(
147
159
  (props, forwardedRef) => {
@@ -0,0 +1,68 @@
1
+ import { vars } from "@seed-design/css/vars";
2
+ import { render } from "@testing-library/react";
3
+ import { describe, expect, it } from "bun:test";
4
+ import { createRef } from "react";
5
+ import { Skeleton } from "./Skeleton";
6
+
7
+ describe("Skeleton", () => {
8
+ it.each(["t4", "t4Static"] as const)("resolves lineHeight.%s", (token) => {
9
+ const { getByTestId } = render(
10
+ <Skeleton data-testid="skeleton" height={`lineHeight.${token}`} />,
11
+ );
12
+
13
+ expect(getByTestId("skeleton").style.getPropertyValue("--seed-box-height-base")).toBe(
14
+ vars.$lineHeight[token],
15
+ );
16
+ });
17
+
18
+ it("supports line-height and dimension tokens in responsive heights", () => {
19
+ const { getByTestId } = render(
20
+ <Skeleton
21
+ data-testid="skeleton"
22
+ height={{ base: "lineHeight.t4", sm: undefined, md: "lineHeight.t5", lg: "x8" }}
23
+ />,
24
+ );
25
+ const { style } = getByTestId("skeleton");
26
+
27
+ expect(style.getPropertyValue("--seed-box-height-base")).toBe(vars.$lineHeight.t4);
28
+ expect(style.getPropertyValue("--seed-box-height-sm")).toBe("");
29
+ expect(style.getPropertyValue("--seed-box-height-md")).toBe(vars.$lineHeight.t5);
30
+ expect(style.getPropertyValue("--seed-box-height-lg")).toBe(vars.$dimension.x8);
31
+ });
32
+
33
+ it.each([
34
+ [undefined, ""],
35
+ ["x4", vars.$dimension.x4],
36
+ ["24px", "24px"],
37
+ ["var(--custom-height)", "var(--custom-height)"],
38
+ ["lineHeight.invalid", "lineHeight.invalid"],
39
+ ["lineHeight.constructor", "lineHeight.constructor"],
40
+ ])("preserves existing height %s", (height, expected) => {
41
+ const { getByTestId } = render(<Skeleton data-testid="skeleton" height={height} />);
42
+
43
+ expect(getByTestId("skeleton").style.getPropertyValue("--seed-box-height-base")).toBe(expected);
44
+ });
45
+
46
+ it("preserves styles, className and ref with asChild", () => {
47
+ const ref = createRef<HTMLDivElement>();
48
+ const { getByTestId } = render(
49
+ <Skeleton
50
+ ref={ref}
51
+ asChild
52
+ height="lineHeight.t4"
53
+ width="x8"
54
+ className="custom"
55
+ style={{ height: "32px" }}
56
+ >
57
+ <div data-testid="skeleton" />
58
+ </Skeleton>,
59
+ );
60
+ const element = getByTestId("skeleton");
61
+
62
+ expect(ref.current).toBe(element);
63
+ expect(element).toHaveClass("custom");
64
+ expect(element.style.height).toBe("32px");
65
+ expect(element.style.getPropertyValue("--seed-box-width-base")).toBe(vars.$dimension.x8);
66
+ expect(element).not.toHaveAttribute("height");
67
+ });
68
+ });
@@ -1,15 +1,47 @@
1
1
  import { Primitive, type PrimitiveProps } from "@seed-design/react-primitive";
2
2
  import { skeleton, type SkeletonVariantProps } from "@seed-design/css/recipes/skeleton";
3
+ import { vars, type LineHeight } from "@seed-design/css/vars";
3
4
  import type * as React from "react";
5
+ import { forwardRef } from "react";
6
+ import {
7
+ isResponsiveObject,
8
+ type ResponsiveValue,
9
+ type UnwrapResponsive,
10
+ } from "../../types/responsive";
4
11
  import { createRecipeContext } from "../../utils/createRecipeContext";
5
- import { withStyleProps, type StyleProps } from "../../utils/styled";
12
+ import { useStyleProps, type StyleProps } from "../../utils/styled";
6
13
 
7
14
  const { withContext } = createRecipeContext(skeleton);
8
15
 
9
16
  export interface SkeletonProps
10
17
  extends SkeletonVariantProps,
11
18
  PrimitiveProps,
12
- Pick<StyleProps, "height" | "width">,
13
- Omit<React.HTMLAttributes<HTMLDivElement>, "color"> {}
19
+ Pick<StyleProps, "width">,
20
+ Omit<React.HTMLAttributes<HTMLDivElement>, "color"> {
21
+ height?: ResponsiveValue<UnwrapResponsive<StyleProps["height"]> | `lineHeight.${LineHeight}`>;
22
+ }
14
23
 
15
- export const Skeleton = withContext<HTMLDivElement, SkeletonProps>(withStyleProps(Primitive.div));
24
+ function handleHeight(height: string | undefined) {
25
+ if (!height?.startsWith("lineHeight.")) return height;
26
+
27
+ const value = vars.$lineHeight[height.slice("lineHeight.".length) as LineHeight];
28
+
29
+ return typeof value === "string" ? value : height;
30
+ }
31
+
32
+ export const Skeleton = withContext<HTMLDivElement, SkeletonProps>(
33
+ forwardRef<HTMLDivElement, SkeletonProps>(function Skeleton({ height, ...props }, ref) {
34
+ const { style, restProps } = useStyleProps({
35
+ ...props,
36
+ height: isResponsiveObject(height)
37
+ ? Object.fromEntries(
38
+ Object.entries(height).map(([key, value]) => [key, handleHeight(value)]),
39
+ )
40
+ : handleHeight(height),
41
+ });
42
+
43
+ return <Primitive.div ref={ref} style={style} {...restProps} />;
44
+ }),
45
+ );
46
+
47
+ Skeleton.displayName = "Skeleton";