Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/toast-icon-position.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"reshaped": minor
---

Toast: Added `iconPosition` prop to control the icon placement relative to the content (start/end, top/center)
11 changes: 11 additions & 0 deletions packages/reshaped/src/components/Toast/Toast.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,14 @@
width: 360px;
}
}

.icon {
&--position-start-top,
&--position-end-top {
align-self: flex-start;
}

&--position-end-center {
align-self: center;
}
}
12 changes: 10 additions & 2 deletions packages/reshaped/src/components/Toast/Toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@ const Toast: React.FC<T.Props & { collapsed: boolean }> = (props) => {
title,
actionsSlot,
startSlot,
iconPosition = "start-center",
collapsed,
className,
attributes,
} = props;
const isIconAtEnd = iconPosition.startsWith("end-");

let backgroundColor: ViewProps["backgroundColor"] =
color === "inverted" || color === "neutral" ? "elevation-overlay" : color;
if (color === "neutral") backgroundColor = collapsed ? "neutral" : "elevation-overlay";
Expand All @@ -51,6 +54,10 @@ const Toast: React.FC<T.Props & { collapsed: boolean }> = (props) => {
</React.Fragment>
);

const iconNode = icon && (
<Icon size={5} svg={icon} className={s[`icon--position-${iconPosition}`]} />
);

const toastNode = (
<View
backgroundColor={backgroundColor}
Expand All @@ -64,8 +71,8 @@ const Toast: React.FC<T.Props & { collapsed: boolean }> = (props) => {
className={[s.toast, className]}
attributes={attributes}
>
{icon && <Icon size={5} svg={icon} className={s.icon} />}
{startSlot && !icon && <View.Item>{startSlot}</View.Item>}
{!isIconAtEnd && iconNode}
{startSlot && (!icon || isIconAtEnd) && <View.Item>{startSlot}</View.Item>}

<View.Item grow>
<View direction={isLarge ? "column" : "row"} align={isLarge ? "start" : "center"} gap={3}>
Expand Down Expand Up @@ -103,6 +110,7 @@ const Toast: React.FC<T.Props & { collapsed: boolean }> = (props) => {
)}
</View>
</View.Item>
{isIconAtEnd && iconNode}
</View>
);

Expand Down
4 changes: 4 additions & 0 deletions packages/reshaped/src/components/Toast/Toast.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ export type Props = {
size?: "small" | "medium" | "large";
/** Icon at the inline start position of the toast */
icon?: IconProps["svg"];
/** Position of the icon relative to the content
* @default "start-center"
*/
iconPosition?: "start-center" | "start-top" | "end-center" | "end-top";
/** Node for inserting content at the inline start position of the toast */
startSlot?: React.ReactNode;
/** Title value for the toast */
Expand Down
69 changes: 69 additions & 0 deletions packages/reshaped/src/components/Toast/tests/Toast.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,75 @@ const Slots = () => {
};
export const slots = { name: "slots", render: () => <Slots /> };

const IconPosition = () => {
const toast = useToast();
const props = {
icon: IconZap,
title: "Hey!",
text: "Very long event completed notification message that spans multiple lines",
size: "medium" as const,
};

return (
<Example>
<Example.Item title="iconPosition: start-center (default)">
<Button
onClick={() => {
toast.show({ ...props });
}}
>
Show toast
</Button>
</Example.Item>
<Example.Item title="iconPosition: start-top">
<Button
onClick={() => {
toast.show({ ...props, iconPosition: "start-top" });
}}
>
Show toast
</Button>
</Example.Item>
<Example.Item title="iconPosition: end-center">
<Button
onClick={() => {
toast.show({ ...props, iconPosition: "end-center" });
}}
>
Show toast
</Button>
</Example.Item>
<Example.Item title="iconPosition: end-top">
<Button
onClick={() => {
toast.show({ ...props, iconPosition: "end-top" });
}}
>
Show toast
</Button>
</Example.Item>
<Example.Item title="iconPosition: end-center with startSlot">
<Button
onClick={() => {
toast.show({
...props,
iconPosition: "end-center",
startSlot: "Slot",
});
}}
>
Show toast
</Button>
</Example.Item>
</Example>
);
};

export const iconPosition = {
name: "iconPosition",
render: () => <IconPosition />,
};

export const base: StoryObj = {
name: "base",
render: () => {
Expand Down
Loading