Skip to content

Commit

Permalink
Tried fixing typing
Browse files Browse the repository at this point in the history
  • Loading branch information
vicky-comeau committed Jun 19, 2024
1 parent 49bb9d1 commit 5262602
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 12 deletions.
17 changes: 10 additions & 7 deletions packages/components/src/Avatar/src/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ import styles from "./Avatar.module.css";
export const GlobalAvatarCssSelector = "hop-Avatar";
export type AvatarSize = "xs" | "sm" | "md" | "lg" | "xl" | "2xl";

export interface AvatarProps extends StyledSystemProps, BaseComponentProps {
type ImageOmittedProps = "name" | "size" | "slot" | "content" | "color" | "height" | "width";
type AvatarOmittedProps = "content" | "color" | "height" | "width";
type AvatarImageBaseProps = Omit<React.HTMLProps<HTMLImageElement>, ImageOmittedProps>;

interface AvatarBaseProps extends StyledSystemProps, BaseComponentProps {
/**
* The src of the image to display if the image fails to load. If set to null, the initials will be displayed instead.
* * @default "BrokenImageRichIcon"
Expand All @@ -40,15 +44,13 @@ export interface AvatarProps extends StyledSystemProps, BaseComponentProps {
*/
src?: string;
}
export type AvatarProps = AvatarBaseProps & AvatarImageBaseProps;

interface AvatarInitialsProps extends Omit<AvatarProps, "src"> {
size: AvatarSize;
}

type AvatarOmittedProps = "content" | "color" | "height" | "width";
type ImageOmittedProps = "name" | "size" | "slot";

interface AvatarImageProps extends Omit<AvatarProps, AvatarOmittedProps>, Omit<React.HTMLProps<HTMLImageElement>, ImageOmittedProps> {
interface AvatarImageProps extends Omit<AvatarBaseProps, AvatarOmittedProps>, AvatarImageBaseProps {
size: AvatarSize;
src: string;
children: React.ReactNode;
Expand Down Expand Up @@ -162,6 +164,7 @@ function AvatarImage(props: AvatarImageProps) {
<div
data-disabled={isDisabled || undefined}
slot={slot || undefined}
role="img"
aria-label={ariaLabel ?? name}
className={classNames}
>
Expand All @@ -176,7 +179,7 @@ function AvatarImage(props: AvatarImageProps) {
);
}

function Avatar(props: AvatarProps, ref: ForwardedRef<HTMLDivElement>) {
function Avatar(props: AvatarProps, ref: ForwardedRef<HTMLElement>) {
[props, ref] = useContextProps(props, ref, AvatarContext);
const { stylingProps, ...ownProps } = useStyledSystem(props);
const {
Expand Down Expand Up @@ -242,7 +245,7 @@ function Avatar(props: AvatarProps, ref: ForwardedRef<HTMLDivElement>) {
*
* [View Documentation](TODO)
*/
const _Avatar = forwardRef<HTMLDivElement, AvatarProps>(Avatar);
const _Avatar = forwardRef<HTMLElement, AvatarProps>(Avatar);
_Avatar.displayName = "Avatar";

export { _Avatar as Avatar };
2 changes: 1 addition & 1 deletion packages/components/src/Avatar/src/AvatarContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ import type { ContextValue } from "react-aria-components";

import type { AvatarProps } from "./Avatar.tsx";

export const AvatarContext = createContext<ContextValue<AvatarProps, HTMLDivElement>>({});
export const AvatarContext = createContext<ContextValue<AvatarProps, HTMLElement>>({});

AvatarContext.displayName = "AvatarContext";
5 changes: 3 additions & 2 deletions packages/components/src/Avatar/src/RichIconAvatarImage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { RichIconContext, type RichIconProps } from "@hopper-ui/icons";
import { useStyledSystem, type StyledSystemProps } from "@hopper-ui/styled-system";
import clsx from "clsx";
import { type CSSProperties, forwardRef, type ForwardedRef } from "react";
import { type CSSProperties, forwardRef, type ForwardedRef, type HTMLAttributes } from "react";
import { useContextProps } from "react-aria-components";

import { type SizeAdapter, SlotProvider, cssModule, type BaseComponentProps } from "../../utils/index.ts";
Expand All @@ -13,7 +13,7 @@ import styles from "./RichIconAvatarImage.module.css";

export const GlobalRichIconAvatarImageCssSelector = "hop-RichIconAvatarImage";

export interface RichIconAvatarImageProps extends StyledSystemProps, BaseComponentProps {
export interface RichIconAvatarImageProps extends StyledSystemProps, BaseComponentProps, Omit<HTMLAttributes<HTMLDivElement>, "slot" | "content" | "color"> {
/**
* Whether or not the avatar image is disabled.
*/
Expand Down Expand Up @@ -70,6 +70,7 @@ function RichIconAvatarImage(props: RichIconAvatarImageProps, ref: ForwardedRef<
className={classNames}
style={mergedStyles}
slot={slot ?? undefined}
role="img"
data-disabled={isDisabled || undefined}
>
<SlotProvider
Expand Down
4 changes: 4 additions & 0 deletions packages/components/src/Avatar/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
export * from "./Avatar.tsx";
export * from "./AnonymousAvatar.tsx";
export * from "./DeletedAvatar.tsx";
export * from "./RichIconAvatarImage.tsx";
export * from "./AvatarContext.ts";
export * from "./RichIconAvatarImageContext.ts";
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe("Avatar", () => {
it("should render on the server", () => {
const renderOnServer = () =>
renderToString(
<Avatar>Text</Avatar>
<Avatar name="John Doe" />
);

expect(renderOnServer).not.toThrow();
Expand Down
77 changes: 76 additions & 1 deletion packages/components/src/Avatar/tests/jest/Avatar.test.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,85 @@
import { render, screen } from "@hopper-ui/test-utils";
import { createRef } from "react";

import { Avatar } from "../../src/Avatar.tsx";
import { AvatarContext } from "../../src/AvatarContext.ts";

describe("Avatar", () => {
it("should render a span with default class", () => {
it("should render with default class", () => {
render(<Avatar name="John Doe" />);

const element = screen.getByRole("img", { hidden: true });

expect(element).toHaveClass("hop-RichIcon");
});

it("should support custom class", () => {
render(<Avatar name="John Doe" className="test" />);

const element = screen.getByRole("img", { hidden: true });

expect(element).toHaveClass("hop-RichIcon");
expect(element).toHaveClass("test");
});

it("should support custom style", () => {
render(<Avatar name="John Doe" marginTop="stack-sm" style={{ marginBottom: "13px" }} />);

const element = screen.getByRole("img", { hidden: true });

expect(element).toHaveStyle({ marginTop: "var(--hop-space-stack-sm)", marginBottom: "13px" });
});

it("should support DOM props", () => {
render(<Avatar name="John Doe" data-foo="bar" />);

const element = screen.getByRole("img", { hidden: true });

expect(element).toHaveAttribute("data-foo", "bar");
});

it("should support slots", () => {
render(
<AvatarContext.Provider value={{ slots: { test: { "aria-label": "test", "name": "test" } } }}>
<Avatar name="John Doe" slot="test" />
</AvatarContext.Provider>
);

const element = screen.getByRole("img", { hidden: true });
expect(element).not.toHaveAttribute("slot", "test"); // svg doesn't have slot attribute
expect(element).toHaveAttribute("aria-label", "test");
});

it("should support refs", () => {
const ref = createRef<HTMLDivElement>();
render(<Avatar name="John Doe" ref={ref} />);

const element = screen.getByRole("img", { hidden: true });

expect(ref.current).toBe(element);
expect(ref.current instanceof HTMLDivElement).toBeTruthy();
expect(ref.current?.tagName.toUpperCase()).toBe("div");
});

it("should apply default displayName", () => {
expect(Avatar.displayName).toBe("Avatar");
});

it("should apply aria-label and aria-hidden attributes", () => {
render(<Avatar name="John Doe" aria-label="Test Icon" />);

const icon = screen.getByRole("img");

expect(icon).toHaveAttribute("aria-label", "Test Icon");
expect(icon).not.toHaveAttribute("aria-hidden");
});

it("should apply aria-hidden attributes when no aria-label is provided", () => {
render(<Avatar name="John Doe" />);

const icon = screen.getByRole("img", { hidden: true });

expect(icon).not.toHaveAttribute("aria-label");
expect(icon).toHaveAttribute("aria-hidden", "true");
});
});
1 change: 1 addition & 0 deletions packages/components/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./Avatar/index.ts";
export * from "./badge/index.ts";
export * from "./buttons/index.ts";
export * from "./checkbox/index.ts";
Expand Down

0 comments on commit 5262602

Please sign in to comment.