Skip to content

Commit

Permalink
feat: Misc Odyssey updates (#2326)
Browse files Browse the repository at this point in the history
DES-6538 feat(odyssey-react-mui): expose Stack and Grid from MUI
feat(odyssey-react-mui): expose Autocomplete getOptionLabel prop
fix(odyssey-storybook): fix deprectated storyName  warning
feat(odyssey-storybook): wrap stack and grid
fix(odyssey-storybook): fix palette dark color and intro darker
fix(odyssey-storybook): map darker to the correct number
feat(odyssey-react-mui): add linkTarget for Callout
feat(odyssey-react-mui): use ODS link and add story
feat(odyssey-react-mui): add correct prop description
feat(odyssey-react-mui): add linkTarget for Banner
feat(odyssey-react-mui): use defs from LinkProps
chore(odyssey-react-mui): remove disabled tooltip button story
chore(odyssey-react-mui): remove grid for now
chore(odyssey-react-mui): add Stack stories
fix(odyssey-react-mui): fix banner type error
feat(odyssey-react-mui): add linkRel prop Banner and Callout
  • Loading branch information
bryancunningham-okta authored Oct 1, 2024
1 parent 3bd3bac commit 84fcef3
Show file tree
Hide file tree
Showing 14 changed files with 369 additions and 49 deletions.
13 changes: 13 additions & 0 deletions packages/odyssey-react-mui/src/Autocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,17 @@ export type AutocompleteProps<
undefined,
IsCustomValueAllowed
>["defaultValue"];
/**
* Used to determine the string value for a given option. It's used to fill the input (and the list box options if renderOption is not provided). If used in free solo mode, it must accept both the type of the options and a string.
*
* `function(option: Value) => string`
*/
getOptionLabel?: UseAutocompleteProps<
OptionType,
HasMultipleChoices,
undefined,
IsCustomValueAllowed
>["getOptionLabel"];
/**
* Enables multiple choice selection
*/
Expand Down Expand Up @@ -249,6 +260,7 @@ const Autocomplete = <
defaultValue,
errorMessage,
errorMessageList,
getOptionLabel,
hasMultipleChoices,
id: idOverride,
inputValue,
Expand Down Expand Up @@ -571,6 +583,7 @@ const Autocomplete = <
disabled={isDisabled}
freeSolo={isCustomValueAllowed}
filterSelectedOptions={true}
getOptionLabel={getOptionLabel}
id={idOverride}
fullWidth={isFullWidth}
loading={isLoading}
Expand Down
43 changes: 29 additions & 14 deletions packages/odyssey-react-mui/src/Banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { useTranslation } from "react-i18next";
import { Alert, AlertColor, AlertTitle, AlertProps } from "@mui/material";

import type { HtmlProps } from "./HtmlProps";
import { Link } from "./Link";
import { Link, LinkProps } from "./Link";
import { ScreenReaderText } from "./ScreenReaderText";

export const bannerRoleValues = ["status", "alert"] as const;
Expand All @@ -27,16 +27,6 @@ export const bannerSeverityValues: AlertColor[] = [
];

export type BannerProps = {
/**
* If linkUrl is not undefined, this is the text of the link.
* If left blank, it defaults to "Learn more".
* Note that linkText does nothing if linkUrl is not defined
*/
linkText?: string;
/**
* If defined, the alert will include a link to the URL
*/
linkUrl?: string;
/**
* The function that's fired when the user clicks the close button. If undefined,
* the close button will not be shown.
Expand All @@ -56,11 +46,30 @@ export type BannerProps = {
* The text content of the alert
*/
text: string;
} & Pick<HtmlProps, "testId" | "translate">;
} & Pick<HtmlProps, "testId" | "translate"> &
(
| {
linkRel?: LinkProps["rel"];
linkTarget?: LinkProps["target"];
linkText: string;
/**
* If defined, the Banner will include a link to the URL
*/
linkUrl: LinkProps["href"];
}
| {
linkRel?: never;
linkTarget?: never;
linkText?: never;
linkUrl?: never;
}
);

const Banner = ({
linkUrl,
linkRel,
linkTarget,
linkText,
linkUrl,
onClose,
role,
severity,
Expand All @@ -83,7 +92,13 @@ const Banner = ({
</ScreenReaderText>
<AlertTitle translate={translate}>{text}</AlertTitle>
{linkUrl && (
<Link href={linkUrl} variant="monochrome" translate={translate}>
<Link
href={linkUrl}
rel={linkRel}
target={linkTarget}
translate={translate}
variant="monochrome"
>
{linkText}
</Link>
)}
Expand Down
29 changes: 18 additions & 11 deletions packages/odyssey-react-mui/src/Callout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
*/

import styled from "@emotion/styled";
import { Alert, AlertTitle, Box, Link as MuiLink } from "@mui/material";
import { Alert, AlertTitle, Box } from "@mui/material";
import { memo, ReactNode } from "react";
import { useTranslation } from "react-i18next";

import type { HtmlProps } from "./HtmlProps";
import { Link, LinkProps } from "./Link";
import {
DesignTokens,
useOdysseyDesignTokens,
Expand Down Expand Up @@ -92,18 +93,17 @@ export type CalloutProps = {
) &
(
| {
linkRel?: LinkProps["rel"];
linkTarget?: LinkProps["target"];
linkText: string;
/**
* If linkUrl is not undefined, this is the text of the link.
* If left blank, it defaults to "Learn more".
* Note that linkText does nothing if linkUrl is not defined
*/
linkUrl: string;
/**
* If defined, the Toast will include a link to the URL
* If defined, the Callout will include a link to the URL
*/
linkText: string;
linkUrl: LinkProps["href"];
}
| {
linkRel?: never;
linkTarget?: never;
linkUrl?: never;
linkText?: never;
}
Expand All @@ -120,6 +120,8 @@ const ContentContainer = styled("div", {

const Callout = ({
children,
linkRel,
linkTarget,
linkText,
linkUrl,
role,
Expand Down Expand Up @@ -153,9 +155,14 @@ const Callout = ({
{text && <Paragraph>{text}</Paragraph>}
{linkUrl && (
<Box>
<MuiLink href={linkUrl} variant="monochrome">
<Link
href={linkUrl}
rel={linkRel}
target={linkTarget}
variant="monochrome"
>
{linkText}
</MuiLink>
</Link>
</Box>
)}
</ContentContainer>
Expand Down
4 changes: 3 additions & 1 deletion packages/odyssey-react-mui/src/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ export type LinkProps = {
*/
onClick?: MuiLinkProps["onClick"];
/**
* The HTML `rel` attribute for the Link
* The rel attribute defines the relationship between a linked resource and the current document
*
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel
*/
rel?: string;
/**
Expand Down
56 changes: 56 additions & 0 deletions packages/odyssey-react-mui/src/Stack.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*!
* Copyright (c) 2023-present, Okta, Inc. and/or its affiliates. All rights reserved.
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
*
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and limitations under the License.
*/

import { memo } from "react";
import { Stack as MuiStack, StackProps as MuiStackProps } from "@mui/material";

export const stackSpacingValues = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] as const;
export const stackDirectionValues = [
"row",
"row-reverse",
"column",
"column-reverse",
] as const;

export type OdysseyStackProps = {
children?: MuiStackProps["children"];
/**
* The component used for the root node. Either a string to use a HTML element or a component.
*/
component?: MuiStackProps["component"];
/**
* Defines the flex-direction style property. It is applied for all screen sizes.
*/
direction?: (typeof stackDirectionValues)[number];
/**
* Defines the space between immediate children.
*/
spacing?: (typeof stackSpacingValues)[number];
sx?: MuiStackProps["sx"];
};

const Stack = ({
children,
direction = "column",
spacing = 2,
}: OdysseyStackProps) => {
return (
<MuiStack direction={direction} spacing={spacing}>
{children}
</MuiStack>
);
};

const MemoizedStack = memo(Stack);
MemoizedStack.displayName = "Stack";

export { MemoizedStack as Stack };
3 changes: 3 additions & 0 deletions packages/odyssey-react-mui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export {
Paper,
/** @deprecated Will be removed in a future Odyssey version in lieu of a wrapped version. */
ScopedCssBaseline,
/** @deprecated Will be removed in a future Odyssey version in lieu of a wrapped version. */
ThemeProvider,
} from "@mui/material";

Expand All @@ -49,6 +50,7 @@ export type {
MenuListProps,
PaperProps,
ScopedCssBaselineProps,
StackProps,
ThemeOptions,
} from "@mui/material";

Expand Down Expand Up @@ -100,6 +102,7 @@ export * from "./RadioGroup";
export * from "./ScreenReaderText";
export * from "./SearchField";
export * from "./Select";
export * from "./Stack";
export * from "./Status";
export * from "./Surface";
export * from "./Tabs";
Expand Down
8 changes: 2 additions & 6 deletions packages/odyssey-react-mui/src/labs/datePickerTheme.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,6 @@ const dateStyles: StateStyles = {
hoverSelected: ({ theme }) => ({
backgroundColor: theme.palette.primary.dark,
color: theme.palette.primary.contrastText,

"@media (pointer: fine)": {
backgroundColor: theme.palette.primary.main,
},
}),
outsideOfMonth: ({ theme }) => ({
backgroundColor: "transparent",
Expand Down Expand Up @@ -158,8 +154,8 @@ export const datePickerTheme: ThemeOptions = {
borderStyle: theme.mixins.borderStyle,
borderWidth: theme.mixins.borderWidth,
borderRadius: theme.mixins.borderRadius,
paddingBlock: theme.spacing(3),
paddingInline: theme.spacing(3),
paddingBlock: theme.spacing(6),
paddingInline: theme.spacing(6),
},
}),
},
Expand Down
3 changes: 2 additions & 1 deletion packages/odyssey-react-mui/src/theme/palette.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ export const palette = ({
lighter: odysseyTokens.HueBlue50,
light: odysseyTokens.HueBlue300,
main: odysseyTokens.HueBlue500,
dark: odysseyTokens.HueBlue900,
dark: odysseyTokens.HueBlue700,
darker: odysseyTokens.HueBlue800,
contrastText: odysseyTokens.TypographyColorInverse,
},
secondary: {
Expand Down
2 changes: 2 additions & 0 deletions packages/odyssey-react-mui/src/theme/palette.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@

declare module "@mui/material/styles" {
interface PaletteColor {
darker?: string;
lighter?: string;
}
interface SimplePaletteColorOptions {
darker?: string;
lighter?: string;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,38 @@ import { MuiThemeDecorator } from "../../../../.storybook/components";
import { userEvent, within } from "@storybook/testing-library";
import { expect, jest } from "@storybook/jest";
import { axeRun } from "../../../axe-util";
import type { PlaywrightProps } from "../storybookTypes";

const storybookMeta: Meta<typeof Banner> = {
type PlayType = {
args: BannerProps;
canvasElement: HTMLElement;
step: PlaywrightProps<BannerProps>["step"];
};

const storybookMeta: Meta<BannerProps> = {
title: "MUI Components/Banner",
component: Banner,
argTypes: {
linkRel: {
control: "text",
description:
"The rel attribute defines the relationship between a linked resource and the current document.",
table: {
type: {
summary: "string",
},
},
},
linkTarget: {
control: "text",
description:
"The target property of the `HTMLAnchorElement` interface is a string that indicates where to display the linked resource.",
table: {
type: {
summary: "string",
},
},
},
linkText: {
control: "text",
description:
Expand Down Expand Up @@ -138,7 +165,7 @@ export const Linked: StoryObj<BannerProps> = {
severity: "error",
text: "An unidentified flying object compromised Hangar 18.",
},
play: async ({ canvasElement, step }) => {
play: async ({ canvasElement, step }: PlayType) => {
await step("check for the link text", async () => {
const canvas = within(canvasElement);
const link = canvas.getByText("View report") as HTMLAnchorElement;
Expand All @@ -148,11 +175,22 @@ export const Linked: StoryObj<BannerProps> = {
},
};

export const LinkWithTarget: StoryObj<BannerProps> = {
args: {
linkTarget: "_blank",
linkText: "View report",
linkUrl: "#anchor",
role: "status",
severity: "error",
text: "An unidentified flying object compromised Hangar 18.",
},
};

export const Dismissible: StoryObj<BannerProps> = {
args: {
onClose: jest.fn(),
},
play: async ({ args, canvasElement, step }) => {
play: async ({ args, canvasElement, step }: PlayType) => {
await step("dismiss the banner on click", async () => {
const canvas = within(canvasElement);
const button = canvas.getByTitle("Close");
Expand Down
Loading

0 comments on commit 84fcef3

Please sign in to comment.