From 11848ee80b5aca0416ea3e0f4812746dd47d90b7 Mon Sep 17 00:00:00 2001 From: Mikkel Laursen Date: Thu, 6 Aug 2020 19:22:52 -0600 Subject: [PATCH] feat(avatar): Added ability to pass props to `` Closes #908 --- packages/avatar/src/Avatar.tsx | 56 +++++++++++++++++++++--- packages/avatar/src/__tests__/Avatar.tsx | 48 +++++++++++++++++++- 2 files changed, 98 insertions(+), 6 deletions(-) diff --git a/packages/avatar/src/Avatar.tsx b/packages/avatar/src/Avatar.tsx index 717093bf99..df71284df8 100644 --- a/packages/avatar/src/Avatar.tsx +++ b/packages/avatar/src/Avatar.tsx @@ -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; export interface AvatarProps extends HTMLAttributes { /** @@ -21,6 +23,29 @@ export interface AvatarProps extends HTMLAttributes { */ alt?: string; + /** + * An optional `referrerPolicy` to provide to the `` 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 `` 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; + /** * 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 @@ -40,12 +65,29 @@ const block = bem("rmd-avatar"); * avatar more unique. */ const Avatar = forwardRef(function Avatar( - { className, children, src, alt = "", color = "", ...props }, + { + className, + children, + src, + alt = "", + color = "", + imgProps, + referrerPolicy, + ...props + }, ref ) { let img; - if (src) { - img = {alt}; + if (src || imgProps) { + img = ( + {alt} + ); } return ( @@ -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) {} } diff --git a/packages/avatar/src/__tests__/Avatar.tsx b/packages/avatar/src/__tests__/Avatar.tsx index f0c432dc80..3d5263ef5c 100644 --- a/packages/avatar/src/__tests__/Avatar.tsx +++ b/packages/avatar/src/__tests__/Avatar.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { createRef } from "react"; import { render } from "@testing-library/react"; import Avatar from "../Avatar"; @@ -89,4 +89,50 @@ describe("Avatar", () => { rerender(); expect(container).toMatchSnapshot(); }); + + it("should pass the referrerPolicy to the img element when the src prop was provided", () => { + const { getByAltText, rerender } = render( + A + ); + + expect(() => getByAltText("")).toThrow(); + + rerender(); + 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(); + + 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(); + 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(); + render(); + + expect(ref.current).toBeInstanceOf(HTMLImageElement); + }); });