Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT] Add BackgroundContext for gray background component theme changes #2362

Closed
wants to merge 9 commits into from

Conversation

benlister-okta
Copy link
Contributor

@benlister-okta benlister-okta commented Sep 18, 2024

DES-6423

Summary

This is a variation of my other PR that leverages OdysseyProvider and leverages the theme to add the BackgroundProvider logic globally

  • Adds BackgroundContext react context which can be used to display optimized contrast versions of certain components/component states
  • Currently configured for isDisabled secondary Button, Status, and Tag
  • Uses styled-components for the lowContrast/highContrast style differneces.

Example usage:

<BackgroundProvider value="lowContrast"> <Button isDisabled label="Secondary" onClick={() => {}} variant="secondary" /> </BackgroundProvider>

Testing & Screenshots

  • I have confirmed this change with my designer and the Odyssey Design Team.
    CleanShot 2024-09-18 at 10 05 46@2x

Comment on lines 15 to 17
export type BackgroundType = "white" | "gray";

const BackgroundContext = createContext<BackgroundType>("white");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't use words like "white" and "gray". If we have Dark mode, they won't make sense.

That's why I was suggesting "high contrast" and "low contrast". Maybe we can figure out better words.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great callout. I've updated it to LowContrast (gray) / and highContrast (white) which I think will be more scalable if/when we add dark mode since it will still be relevant for styles.

Comment on lines 28 to 29
import { useBackground } from "./BackgroundContext"; // Custom hook to consume the background context
import { useButton } from "./ButtonContext"; // Custom hook to consume the button context
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import { useBackground } from "./BackgroundContext"; // Custom hook to consume the background context
import { useButton } from "./ButtonContext"; // Custom hook to consume the button context
import { useBackground } from "./BackgroundContext";
import { useButton } from "./ButtonContext";

Comment on lines 156 to 158
const StyledButton = styled(MuiButton, {
shouldForwardProp: (prop) => !nonForwardedProps.includes(prop as string),
})<{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this function and why are we doing as string? I mean, I understand why relatively, but I wonder if there's a better way of doing this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, that's a bit wonky. I updated it to be more type-safe approach:
shouldForwardProp: (prop: string) => !nonForwardedProps.includes(prop),

const background = useBackground();
const odysseyDesignTokens = useOdysseyDesignTokens();
// Determine if the button is in a gray background and is a secondary variant
const isGrayBackground = background === "gray" && variantProp === "secondary";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanna get away from gray. isLowContrastBackground or something more generic that we could use.

Comment on lines 156 to 158
const StyledButton = styled(MuiButton, {
shouldForwardProp: (prop) => !nonForwardedProps.includes(prop as string),
})<{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great solution to components.tsx. I wonder if we should start doing this in the future. Have a pass to localize all component styles like this.

Comment on lines 238 to 244
const canvas = within(canvasElement);
await checkButtonStyles(
canvas,
"Secondary",
"rgb(243, 244, 246)",
"rgb(143, 149, 158)",
);
Copy link
Contributor

@KevinGhadyani-Okta KevinGhadyani-Okta Sep 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use design tokens here. I don't know what these RGB values mean otherwise or even how we got to them.

Comment on lines 82 to 93
const checkStatusStyles = async (
canvas: ReturnType<typeof within>,
statusLabel: string,
expectedBackgroundColor: string,
expectedColor: string,
) => {
const status = canvas.getByText(statusLabel);
await expect(status).toHaveStyle(
`background-color: ${expectedBackgroundColor}`,
);
await expect(status).toHaveStyle(`color: ${expectedColor}`);
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use Test Selectors here so we start putting that code in use?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I updated the tests to include an ID e.g. testId: "button-medium", (I believe that's what we're after, right?)

Comment on lines 83 to 94
const checkStatusStyles = async (
canvas: ReturnType<typeof within>,
testId: string,
expectedBackgroundColor: string,
expectedColor: string,
) => {
const status = canvas.getByTestId(testId);
await expect(status).toHaveStyle(
`background-color: ${expectedBackgroundColor}`,
);
await expect(status).toHaveStyle(`color: ${expectedColor}`);
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't rely on test IDs because we're wanting to use accessibility selectors and want other people to use them as well.

We should be able to select by the "status" role. In fact, if we could, we should add that to odysseyQuerySelector. It will help consumers of Odyssey.

Comment on lines 134 to 139
) => {
const tag = canvas.getByTestId(testId);
await expect(tag).toHaveStyle(`background-color: ${expectedBackgroundColor}`);
await expect(tag).toHaveStyle(`color: ${expectedColor}`);
};

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, we shouldn't select by test ID, we should use accessibility selectors.

Test IDs are deprecated because they're there for existing Selenium tests.

Comment on lines 236 to 243
const tag = canvasElement.querySelector(`[data-se="${args.testId}"]`);
if (tag) {
await userEvent.click(tag);
expect(args.onClick).toHaveBeenCalledTimes(1);
await axeRun("Clickable Tag");
} else {
throw new Error(`Element with data-se="${args.testId}" not found`);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use testing library to select these elements.

If we use getByRole("tab", { name: "" }) instead of querySelector, it will throw an error if it can't find the element; therefore, you won't need the if (tag) {} check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants