Skip to content

Commit

Permalink
feat(avatar): Added ability to pass props to <img>
Browse files Browse the repository at this point in the history
Closes #908
  • Loading branch information
mlaursen committed Aug 7, 2020
1 parent 49319e6 commit 11848ee
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 6 deletions.
56 changes: 51 additions & 5 deletions packages/avatar/src/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { forwardRef, HTMLAttributes } from "react";
import React, { forwardRef, HTMLAttributes, ImgHTMLAttributes } from "react";
import cn from "classnames";
import { bem } from "@react-md/utils";
import { bem, PropsWithRef } from "@react-md/utils";

type ImgAttributes = ImgHTMLAttributes<HTMLImageElement>;

export interface AvatarProps extends HTMLAttributes<HTMLSpanElement> {
/**
Expand All @@ -21,6 +23,29 @@ export interface AvatarProps extends HTMLAttributes<HTMLSpanElement> {
*/
alt?: string;

/**
* An optional `referrerPolicy` to provide to the `<img>` element if the `src`
* or `imgProps` props are provided.
*
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-referrerpolicy
*
* @since 2.2.0
*/
referrerPolicy?: ImgAttributes["referrerPolicy"];

/**
* An optional object of image props and ref that can be used to create an
* image within the `Avatar`. This can be useful to add a custom `style`
* or`className` to the `<img>` element if that additional customization is
* needed.
*
* Note: The values in this object will override the `src`, `alt`, and
* `referrerPolicy` root level avatar props if they exist on this object.
*
* @since 2.2.0
*/
imgProps?: PropsWithRef<ImgAttributes, HTMLImageElement>;

/**
* An optional color to apply to the avatar. This will apply a className of
* `rmd-avatar--${color}`, so only the keys from the `$rmd-avatar-colors` Map
Expand All @@ -40,12 +65,29 @@ const block = bem("rmd-avatar");
* avatar more unique.
*/
const Avatar = forwardRef<HTMLSpanElement, AvatarProps>(function Avatar(
{ className, children, src, alt = "", color = "", ...props },
{
className,
children,
src,
alt = "",
color = "",
imgProps,
referrerPolicy,
...props
},
ref
) {
let img;
if (src) {
img = <img src={src} alt={alt} className={block("image")} />;
if (src || imgProps) {
img = (
<img
src={src}
alt={alt}
referrerPolicy={referrerPolicy}
{...imgProps}
className={cn(block("image"), imgProps?.className)}
/>
);
}

return (
Expand All @@ -70,6 +112,10 @@ if (process.env.NODE_ENV !== "production") {
color: PropTypes.string,
className: PropTypes.string,
children: PropTypes.node,
// Note: The MDN website has a lot more values, but this is what Typescript
// says is valid at the time of writing this
referrerPolicy: PropTypes.oneOf(["no-referrer", "origin", "unsafe-url"]),
imgProps: PropTypes.object,
};
} catch (e) {}
}
Expand Down
48 changes: 47 additions & 1 deletion packages/avatar/src/__tests__/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from "react";
import React, { createRef } from "react";
import { render } from "@testing-library/react";

import Avatar from "../Avatar";
Expand Down Expand Up @@ -89,4 +89,50 @@ describe("Avatar", () => {
rerender(<Avatar color="red" src="https://example.com" />);
expect(container).toMatchSnapshot();
});

it("should pass the referrerPolicy to the img element when the src prop was provided", () => {
const { getByAltText, rerender } = render(
<Avatar referrerPolicy="no-referrer">A</Avatar>
);

expect(() => getByAltText("")).toThrow();

rerender(<Avatar referrerPolicy="no-referrer" src="https://example.com" />);
const img = getByAltText("");
expect(img).toHaveAttribute("referrerpolicy", "no-referrer");
});

it("should render an img element if the imgProps are provided", () => {
const imgProps = { src: "https://example.com" };
const { getByAltText } = render(<Avatar imgProps={imgProps} />);

expect(getByAltText("")).not.toBeNull();
});

it('should correctly merge the imgProps with the "src", "alt", and "referrerPolicy" props', () => {
const props = {
src: "https://example.com",
alt: "",
referrerPolicy: "no-referrer" as const,
imgProps: {
alt: "An Image",
className: "custom",
referrerPolicy: "origin" as const,
},
};

const { getByAltText } = render(<Avatar {...props} />);
const img = getByAltText("An Image");

expect(img).toHaveAttribute("src", props.src);
expect(img.className).toContain("custom");
expect(img).toHaveAttribute("referrerpolicy", "origin");
});

it("should allow for a ref to be passed to the img element with the imgProps", () => {
const ref = createRef<HTMLImageElement>();
render(<Avatar src="https://example.com" imgProps={{ ref }} />);

expect(ref.current).toBeInstanceOf(HTMLImageElement);
});
});

0 comments on commit 11848ee

Please sign in to comment.