Skip to content

Commit

Permalink
fix: proper handling of user-specified aspect-ratio (#11)
Browse files Browse the repository at this point in the history
- Introduce `<ImageWrapper />` to wrap `<Image />` when a custom aspect
ratio is specified by the user (via the `style` prop). This prevents
conflicts with our internally calculated aspect ratio, resolving
previous sizing issues.
- bump package version: `1.0.3`
  • Loading branch information
tex-murphy authored Aug 14, 2024
1 parent 81d77de commit 86a490a
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 6 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const ImageDetails = () => <Image alt="..." src="<Visionary URL>" />;
| `disableImageLayer` <br/> boolean | Disables rendering of the image layer. |
| `height` <br/>number, string | If set, will override internally computed image height. By default, Visionary renders optimally sized images, using the aspect-ratio and max-width placeholder data. |
| `hideImageLayer` <br/> boolean | Hides the image layer, revealing the blur layer underneath. |
| `lazy` <br/> boolean | Should image lazily load. <br/> Default: `true` |
| `lazy` <br/> boolean | Should image load lazily. <br/> Default: `true` |
| `onClick` <br/> function | Callback function to invoke when the image is clicked. function. |
| `onError` <br/> function | Error callback function. |
| `onLoad` <br/> function | Image loaded callback function. |
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "visionary-image",
"description": "React image component with built-in Blurhash placeholders for better UX and Core Web Vitals.",
"version": "1.0.2",
"version": "1.0.3",
"homepage": "https://visionary.cloud",
"type": "module",
"main": "./dist/visionary-image.umd.js",
Expand Down
13 changes: 11 additions & 2 deletions src/components/Image/Image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import type {
} from "react";
import { useInView } from "react-hook-inview";

import { ImageWrapper } from "./ImageWrapper";

import { BG_ALPHA, BLURHASH_PUNCH, CANVAS_SIZE } from "../../lib/constants";
import { useIsomorphicLayoutEffect } from "../../lib/hook";
import { logDebug } from "../../lib/logger";
Expand Down Expand Up @@ -139,12 +141,12 @@ export const Image = ({
} as CSSProperties;
const containerStyles: CSSProperties = {
...customAspectRatioCssVariable,
...userStyles,
aspectRatio: imageState.aspectRatio,
backgroundColor: imageState?.backgroundColor ?? undefined,
maxWidth: imageState.maxWidth,
position: "relative",
width: "100%",
...userStyles,
};
// User wants to hardcode height/width
if (userWidth) {
Expand All @@ -157,11 +159,12 @@ export const Image = ({
onClick,
};
const imageStyles = getImageStyles(hideImageLayer);
return (
const imageComponent = (
<div
className={containerClasses}
ref={containerRef}
style={containerStyles}
// style={{ aspectRatio }}
{...getDebugIdProp(imageState.url, debug)}
{...getTestIdProp(TEST_IDS.CONTAINER)}
{...containerProps}
Expand All @@ -188,4 +191,10 @@ export const Image = ({
)}
</div>
);

// Apply user-specified aspect ratio via <ImageWrapper>
if (userStyles?.aspectRatio) {
return <ImageWrapper aspectRatio={userStyles.aspectRatio}>{imageComponent}</ImageWrapper>;
}
return imageComponent;
};
20 changes: 20 additions & 0 deletions src/components/Image/ImageWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { CSSProperties, ReactNode } from "react";

interface ImageWrapperProps {
aspectRatio: CSSProperties["aspectRatio"];
children: ReactNode;
}

const imageWrapperStyles: CSSProperties = {
overflow: "hidden",
};

/**
* Wrapper component that applies a user-specified aspect ratio.
* - Wraps the usual `<Image />` component when the user specifies `aspect-ratio` via the `style` prop.
* - Position the inner image and blur by using `top`/`left` or `transform: translateX/translateY` on the `<Image />` component.
* - Storybook example: https://visionary-ux.github.io/visionary-image/?path=/story/visionary-image--custom-aspect-ratio
*/
export const ImageWrapper = ({ aspectRatio, children }: ImageWrapperProps) => (
<div style={{ aspectRatio, ...imageWrapperStyles }}>{children}</div>
);
10 changes: 10 additions & 0 deletions src/stories/Image.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ export const PreventSelection: Story = {
},
};

export const CustomAspectRatio: Story = {
args: {
...sharedProps,
style: {
aspectRatio: "3 / 1",
transform: "translateY(-30%)",
},
},
};

export const CustomSizeToken: Story = {
args: {
...sharedProps,
Expand Down

0 comments on commit 86a490a

Please sign in to comment.