diff --git a/.changeset/allow-style-prop.md b/.changeset/allow-style-prop.md new file mode 100644 index 00000000..b1eefcf8 --- /dev/null +++ b/.changeset/allow-style-prop.md @@ -0,0 +1,6 @@ +--- +"@unpic/core": patch +"@unpic/react": patch +--- + +Fix type definition to allow `style` prop on Image component. This is a TypeScript-only change that corrects an incorrect type definition - the `style` prop was always supported at runtime but was incorrectly omitted from the type. No runtime behavior has changed. diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 93e094f3..06c0579b 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -142,7 +142,7 @@ type FullWidthLayout = { export type UnpicImageProps< TImageAttributes extends CoreImageAttributes, TStyle = TImageAttributes["style"], -> = Omit & +> = Omit & BaseOptions & (FixedLayout | ConstrainedLayout | FullWidthLayout); @@ -155,7 +155,7 @@ export type UnpicBaseImageProps< TOptions, TImageAttributes extends CoreImageAttributes, TStyle = TImageAttributes["style"], -> = Omit & +> = Omit & BaseTransformerOptions & (FixedLayout | ConstrainedLayout | FullWidthLayout); diff --git a/packages/core/test/core.test.tsx b/packages/core/test/core.test.tsx index 2462b085..7b36c290 100644 --- a/packages/core/test/core.test.tsx +++ b/packages/core/test/core.test.tsx @@ -50,4 +50,42 @@ describe("Core", () => { expect(props.width).toEqual(100); expect(props.height).toEqual(200); }); + + test("merges user styles with generated styles", () => { + const props = transformBaseImageProps({ + src: "images/my-image", + width: 800, + height: 600, + layout: "constrained", + objectFit: "cover", + style: { border: "1px solid red", opacity: "0.5" }, + transformer: (tUrl) => tUrl, + }); + expect(props.style).toBeDefined(); + // Generated styles should be present + expect(props.style?.["object-fit"]).toEqual("cover"); + expect(props.style?.["max-width"]).toEqual("800px"); + expect(props.style?.["width"]).toEqual("100%"); + // User styles should be present and override if needed + expect(props.style?.["border"]).toEqual("1px solid red"); + expect(props.style?.["opacity"]).toEqual("0.5"); + }); + + test("user styles override generated styles", () => { + const props = transformBaseImageProps({ + src: "images/my-image", + width: 800, + height: 600, + layout: "constrained", + objectFit: "contain", + style: { "object-fit": "fill", border: "2px solid blue" }, + transformer: (tUrl) => tUrl, + }); + expect(props.style).toBeDefined(); + // User's object-fit should override generated one + expect(props.style?.["object-fit"]).toEqual("fill"); + expect(props.style?.["border"]).toEqual("2px solid blue"); + // Other generated styles should still be present + expect(props.style?.["max-width"]).toEqual("800px"); + }); }); diff --git a/packages/react/test/react.test.tsx b/packages/react/test/react.test.tsx index 51740a60..843e89e9 100644 --- a/packages/react/test/react.test.tsx +++ b/packages/react/test/react.test.tsx @@ -46,4 +46,17 @@ describe("the React component", () => { expect(img.getAttribute("aria-label")).toBe("A cool image"); expectImagePropsToMatchTransformed(img, props); }); + + test(`renders an image with style prop`, () => { + const props = { + style: { border: "1px solid red", opacity: "0.5" }, + ...imgTestCases[0], + }; + + render(); + const img = screen.getByAltText(props.alt); + expect(img).toBeTruthy(); + expect(img.style.border).toBe("1px solid red"); + expect(img.style.opacity).toBe("0.5"); + }); });