diff --git a/src/components/NotificationAlert/NotificationAlert.stories.tsx b/src/components/NotificationAlert/NotificationAlert.stories.tsx new file mode 100644 index 00000000..011169c2 --- /dev/null +++ b/src/components/NotificationAlert/NotificationAlert.stories.tsx @@ -0,0 +1,141 @@ +// This file is part of MinIO Design System +// Copyright (c) 2024 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import React from "react"; +import { Meta, Story } from "@storybook/react"; + +import NotificationAlert from "./NotificationAlert"; +import { NotificationAlertPrp } from "./NotificationAlert.types"; + +import StoryThemeProvider from "../../utils/StoryThemeProvider"; +import { GlobalStyles } from "../index"; + +export default { + title: "MDS/Information/NotificationAlert", + component: NotificationAlert, + argTypes: {}, +} as Meta; + +const Template: Story = ({ ...props }) => { + return ( + + + +
+ +
+ +
+ +
+ {}} /> +
+ {}} /> +
+ {}} + action={Action} + /> +
+ {}} + action={Action} + /> +
+ {}} + action={Action} + shadow + /> +
+ {}} + action={Action} + shadow + /> +
+ {}} + action={Action} + emphasisMode={"minimal"} + shadow + /> +
+ {}} + action={Action} + emphasisMode={"minimal"} + shadow + /> +
+
+ ); +}; + +export const Neutral = Template.bind({}); +Neutral.args = { + variant: "neutral", + title: "This is the title for a message", + children: "This is the content for an informative message", +}; + +export const Success = Template.bind({}); +Success.args = { + variant: "success", + title: "This is the title for a message", + children: "This is the content for a success message", +}; + +export const Warning = Template.bind({}); +Warning.args = { + variant: "warning", + title: "This is the title for a message", + children: "This is the content for an warning message", +}; + +export const Danger = Template.bind({}); +Danger.args = { + variant: "danger", + title: "This is the title for a message", + children: "This is the content for an error message", +}; + +export const Information = Template.bind({}); +Information.args = { + variant: "information", + title: "This is the title for a message", + children: "This is the content for an error message", +}; diff --git a/src/components/NotificationAlert/NotificationAlert.tsx b/src/components/NotificationAlert/NotificationAlert.tsx new file mode 100644 index 00000000..2739f13d --- /dev/null +++ b/src/components/NotificationAlert/NotificationAlert.tsx @@ -0,0 +1,219 @@ +// This file is part of MinIO Design System +// Copyright (c) 2024 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import React, { FC, Fragment, useMemo } from "react"; +import get from "lodash/get"; +import { + NotificationAlertConstruct, + NotificationAlertPrp, +} from "./NotificationAlert.types"; +import XIcon from "../Icons/NewDesignIcons/XIcon"; +import styled from "styled-components"; +import CircleSlashIcon from "../Icons/NewDesignIcons/CircleSlashIcon"; +import InfoIcon from "../Icons/NewDesignIcons/InfoIcon"; +import CircleCheckIcon from "../Icons/NewDesignIcons/CircleCheckIcon"; +import CircleAlertIcon from "../Icons/NewDesignIcons/CircleAlertIcon"; +import CircleXIcon from "../Icons/NewDesignIcons/CircleXIcon"; +import { themeColors, themeShadows } from "../../global/themeColors"; +import { paddingSizeVariants } from "../../global/utils"; + +const NotificationContainer = styled.div.attrs(() => ({ + className: "notification-alert", +}))( + ({ theme, emphasisMode, shadow, variant, designMode }) => { + const backgroundColor = + emphasisMode === "subtle" + ? get( + theme, + `notificationAlert.${variant}.highContrastBG`, + themeColors["Color/Brand/Error/colorPrimaryBg"].lightMode, + ) + : get( + theme, + `notificationAlert.${variant}.minimalContrastBG`, + themeColors["Color/Neutral/Bg/colorBgElevated"].lightMode, + ); + const borderColor = + emphasisMode === "subtle" + ? get( + theme, + `notificationAlert.${variant}.highContrastBorder`, + themeColors["Color/Brand/Error/colorPrimaryBg"].lightMode, + ) + : get( + theme, + `notificationAlert.${variant}.minimalContrastBorder`, + themeColors["Color/Brand/Error/colorPrimaryBorder"].lightMode, + ); + + return { + display: "flex", + width: "100%", + maxWidth: 400, + backgroundColor: backgroundColor, + border: `1px solid ${borderColor}`, + borderRadius: 8, + gap: 8, + alignItems: designMode === "banner" ? "center" : "flex-start", + boxShadow: shadow ? themeShadows["boxShadow-03"] : "none", + padding: + designMode === "banner" + ? `${paddingSizeVariants.sizeXS}px ${paddingSizeVariants.size}px` + : paddingSizeVariants.size, + "& .mainInfoContainer": { + flexGrow: 1, + width: "100%", + }, + "& .actionCardMode": { + marginTop: 8, + }, + "& > svg": { + color: get( + theme, + `notificationAlert.${variant}.iconColor`, + themeColors["Color/Brand/Neutral/colorPrimaryBg"].lightMode, + ), + width: 16, + height: 16, + minWidth: 16, + minHeight: 16, + }, + "& .dismissAlert": { + color: get( + theme, + "notificationAlert.contentColor", + themeColors["Color/Neutral/Text/colorTextLabel"].lightMode, + ), + backgroundColor: "transparent", + border: 0, + padding: 0, + width: 16, + height: 16, + cursor: "pointer", + alignSelf: designMode === "card" ? "flex-start" : "center", + "& svg": { + width: 16, + height: 16, + }, + }, + "& .alertInitLine": { + display: "flex", + alignItems: "flex-start", + justifyContent: "flex-start", + + "& .content": { + fontSize: 14, + fontStyle: "normal", + fontWeight: 400, + lineHeight: "20px", + letterSpacing: "0.16px", + }, + + "& .notificationTitle": { + display: "flex", + alignItems: "center", + justifyContent: "space-between", + width: "100%", + "& .fillTitleContent": { + display: "flex", + flex: 1, + width: "100%", + gap: 8, + alignItems: designMode === "card" ? "flex-start" : "center", + }, + "& .cardTitle": { + fontSize: 14, + fontStyle: "normal", + fontWeight: 600, + letterSpacing: "0.16px", + lineHeight: 1, + color: get( + theme, + "notificationAlert.titleColor", + themeColors["Color/Neutral/Text/colorTextHeading"].lightMode, + ), + }, + }, + }, + }; + }, +); + +const NotificationAlert: FC = ({ + title, + children, + action, + onClose, + designMode = "banner", + emphasisMode = "subtle", + variant = "information", + shadow = false, +}) => { + const icon = useMemo(() => { + switch (variant) { + case "information": + return ; + case "success": + return ; + case "warning": + return ; + case "danger": + return ; + default: + return ; + } + }, [variant]); + + return ( + + {icon} +
+
+
+
+ {designMode === "banner" ? ( + +
{children}
+
{action}
+
+ ) : ( +
{title}
+ )} +
+
+
+ {designMode === "card" && ( +
+
{children}
+
{action}
+
+ )} +
+ {onClose && ( + + )} +
+ ); +}; + +export default NotificationAlert; diff --git a/src/components/NotificationAlert/NotificationAlert.types.ts b/src/components/NotificationAlert/NotificationAlert.types.ts new file mode 100644 index 00000000..0e10578d --- /dev/null +++ b/src/components/NotificationAlert/NotificationAlert.types.ts @@ -0,0 +1,43 @@ +// This file is part of MinIO Design System +// Copyright (c) 2024 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import { ReactNode } from "react"; + +export type AlertDesignMode = "banner" | "card"; +export type NotificationEmphasis = "subtle" | "minimal"; +export type NotificationVariant = + | "neutral" + | "information" + | "success" + | "warning" + | "danger"; + +export interface NotificationAlertBase { + title: string; + children: ReactNode; + action?: ReactNode; + onClose?: () => void; //If not set, we don't show the close button +} + +export interface NotificationAlertConstruct { + designMode?: AlertDesignMode; + emphasisMode?: NotificationEmphasis; + variant?: NotificationVariant; + shadow?: boolean; +} + +export type NotificationAlertPrp = NotificationAlertBase & + NotificationAlertConstruct; diff --git a/src/components/NotificationCount/NotificationCount.tsx b/src/components/NotificationCount/NotificationCount.tsx index 654c9385..30034491 100644 --- a/src/components/NotificationCount/NotificationCount.tsx +++ b/src/components/NotificationCount/NotificationCount.tsx @@ -1,5 +1,5 @@ // This file is part of MinIO Design System -// Copyright (c) 2023 MinIO, Inc. +// Copyright (c) 2024 MinIO, Inc. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -20,7 +20,6 @@ import { NotificationCountConstruct, NotificationCountProps, } from "./NotificationCount.types"; -import { lightColors } from "../../global/themes"; import get from "lodash/get"; import { overridePropsParse } from "../../global/utils"; import { themeColors } from "../../global/themeColors"; diff --git a/src/components/NotificationStack/NotificationStack.stories.tsx b/src/components/NotificationStack/NotificationStack.stories.tsx new file mode 100644 index 00000000..d00ba7b5 --- /dev/null +++ b/src/components/NotificationStack/NotificationStack.stories.tsx @@ -0,0 +1,67 @@ +// This file is part of MinIO Design System +// Copyright (c) 2024 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import React, { Fragment } from "react"; +import { Meta, Story } from "@storybook/react"; + +import { NotificationStackProps } from "./NotificationStack.types"; + +import StoryThemeProvider from "../../utils/StoryThemeProvider"; +import GlobalStyles from "../GlobalStyles/GlobalStyles"; +import { useNotifications } from "./hooks"; + +export default { + title: "MDS/Information/NotificationStack", + component: Fragment, + argTypes: {}, +} as Meta; + +const Template: Story = (args) => { + const { notifications, addNotification, removeNotification } = + useNotifications(); + + return ( + + + +
+ +

NOTIFICATIONS

+ {notifications.map((notificationElement) => ( +
+ {notificationElement.message} + +
+ ))} +
+
+ ); +}; + +export const Default = Template.bind({}); +Default.args = {}; diff --git a/src/components/NotificationStack/NotificationStack.types.ts b/src/components/NotificationStack/NotificationStack.types.ts new file mode 100644 index 00000000..04d94b98 --- /dev/null +++ b/src/components/NotificationStack/NotificationStack.types.ts @@ -0,0 +1,23 @@ +// This file is part of MinIO Design System +// Copyright (c) 2024 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import React from "react"; + +export interface NotificationStackProps { + id: number; + message: React.ReactNode; + duration: number; +} diff --git a/src/components/NotificationStack/hooks.ts b/src/components/NotificationStack/hooks.ts new file mode 100644 index 00000000..7d101309 --- /dev/null +++ b/src/components/NotificationStack/hooks.ts @@ -0,0 +1,49 @@ +// This file is part of MinIO Design System +// Copyright (c) 2024 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import { useState, useCallback } from "react"; +import { NotificationStackProps } from "./NotificationStack.types"; + +export const useNotifications = () => { + const [notifications, setNotifications] = useState( + [], + ); + + const addNotification = useCallback( + (message: React.ReactNode, duration: number) => { + const id = Date.now(); + const newNotification = { id, message, duration }; + setNotifications((prevState) => [...prevState, newNotification]); + + setTimeout(() => { + setNotifications((prev) => prev.filter((notif) => notif.id !== id)); + }, duration); // Se wait for this notification to complete it's appearance. + }, + [], + ); + + const removeNotification = useCallback((id: number) => { + setNotifications((prev) => + prev.filter((notification) => notification.id !== id), + ); + }, []); + + return { + notifications, + addNotification, + removeNotification, + }; +}; diff --git a/src/components/index.ts b/src/components/index.ts index 5867c936..3cc07ccc 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -88,6 +88,7 @@ export { default as BoxedIcon } from "./BoxedIcon/BoxedIcon"; export { default as Pill } from "./Pill/Pill"; export { default as SearchBox } from "./SearchBox/SearchBox"; export { default as Badge } from "./Badge/Badge"; +export { default as NotificationAlert } from "./NotificationAlert/NotificationAlert"; /*Icons*/ export * from "./Icons/NewDesignIcons"; @@ -153,3 +154,4 @@ export * from "./BoxedIcon/BoxedIcon.types"; export * from "./Pill/Pill.types"; export * from "./SearchBox/SearchBox.types"; export * from "./Badge/Badge.types"; +export * from "./NotificationAlert/NotificationAlert.types"; diff --git a/src/global/global.types.ts b/src/global/global.types.ts index cea05eee..79c05c2e 100644 --- a/src/global/global.types.ts +++ b/src/global/global.types.ts @@ -475,6 +475,25 @@ export interface BadgeThemeProps { disabled: BadgeElementThemeProps; } +export interface NotificationAlertThemeProps { + highContrastBG: string; + highContrastBorder: string; + minimalContrastBG: string; + minimalContrastBorder: string; + iconColor: string; + titleColor: string; + contentColor: string; + actionColor: string; +} + +export interface NotificationAlertProps { + neutral: NotificationAlertThemeProps; + information: NotificationAlertThemeProps; + success: NotificationAlertThemeProps; + warning: NotificationAlertThemeProps; + danger: NotificationAlertThemeProps; +} + export interface ThemeDefinitionProps { bgColor: string; fontColor: string; @@ -538,6 +557,7 @@ export interface ThemeDefinitionProps { boxedIcon?: BoxedIconThemeProps; pill?: PillThemeProps; badge?: BadgeThemeProps; + notificationAlert: NotificationAlertProps; } export interface SelectOption { diff --git a/src/global/themes.ts b/src/global/themes.ts index eb404d7c..e62342c9 100644 --- a/src/global/themes.ts +++ b/src/global/themes.ts @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import { ThemeDefinitionProps } from "./global.types"; +import { NotificationAlertProps, ThemeDefinitionProps } from "./global.types"; import { themeColors, themeShadows } from "./themeColors"; import { getThemeColors, paddingSizeVariants, radioVariants } from "./utils"; @@ -1183,6 +1183,84 @@ export const lightTheme: ThemeDefinitionProps = { boldLabel: themeColors["Color/Neutral/Text/colorTextDisabled"].lightMode, }, }, + notificationAlert: { + danger: { + highContrastBG: themeColors["Color/Brand/Error/colorPrimaryBg"].lightMode, + highContrastBorder: + themeColors["Color/Brand/Error/colorPrimaryBg"].lightMode, + minimalContrastBG: + themeColors["Color/Neutral/Bg/colorBgElevated"].lightMode, + minimalContrastBorder: + themeColors["Color/Brand/Error/colorPrimaryBorder"].lightMode, + actionColor: + themeColors["Color/Brand/Primary/colorPrimaryText"].lightMode, + iconColor: themeColors["Color/Brand/Error/colorPrimaryText"].lightMode, + contentColor: themeColors["Color/Neutral/Text/colorTextLabel"].lightMode, + titleColor: themeColors["Color/Neutral/Text/colorTextHeading"].lightMode, + }, + success: { + highContrastBG: + themeColors["Color/Brand/Success/colorPrimaryBg"].lightMode, + highContrastBorder: + themeColors["Color/Brand/Success/colorPrimaryBg"].lightMode, + minimalContrastBG: + themeColors["Color/Neutral/Bg/colorBgElevated"].lightMode, + minimalContrastBorder: + themeColors["Color/Brand/Success/colorPrimaryBorder"].lightMode, + actionColor: + themeColors["Color/Brand/Primary/colorPrimaryText"].lightMode, + iconColor: + themeColors["Color/Brand/Success/colorPrimaryBorder"].lightMode, + contentColor: themeColors["Color/Neutral/Text/colorTextLabel"].lightMode, + titleColor: themeColors["Color/Neutral/Text/colorTextHeading"].lightMode, + }, + warning: { + highContrastBG: + themeColors["Color/Brand/Warning/colorPrimaryBg"].lightMode, + highContrastBorder: + themeColors["Color/Brand/Warning/colorPrimaryBg"].lightMode, + minimalContrastBG: + themeColors["Color/Neutral/Bg/colorBgElevated"].lightMode, + minimalContrastBorder: + themeColors["Color/Brand/Warning/colorPrimaryBorder"].lightMode, + actionColor: + themeColors["Color/Brand/Primary/colorPrimaryText"].lightMode, + iconColor: + themeColors["Color/Brand/Warning/colorPrimaryBorder"].lightMode, + contentColor: themeColors["Color/Neutral/Text/colorTextLabel"].lightMode, + titleColor: themeColors["Color/Neutral/Text/colorTextHeading"].lightMode, + }, + information: { + highContrastBG: themeColors["Color/Brand/Info/colorPrimaryBg"].lightMode, + highContrastBorder: + themeColors["Color/Brand/Info/colorPrimaryBg"].lightMode, + minimalContrastBG: + themeColors["Color/Neutral/Bg/colorBgElevated"].lightMode, + minimalContrastBorder: + themeColors["Color/Brand/Primary/colorPrimaryText"].lightMode, + actionColor: + themeColors["Color/Brand/Primary/colorPrimaryText"].lightMode, + iconColor: themeColors["Color/Brand/Primary/colorPrimaryText"].lightMode, + contentColor: themeColors["Color/Neutral/Text/colorTextLabel"].lightMode, + titleColor: themeColors["Color/Neutral/Text/colorTextHeading"].lightMode, + }, + neutral: { + highContrastBG: + themeColors["Color/Brand/Neutral/colorPrimaryBg"].lightMode, + highContrastBorder: + themeColors["Color/Brand/Neutral/colorPrimaryBg"].lightMode, + minimalContrastBG: + themeColors["Color/Neutral/Bg/colorBgElevated"].lightMode, + minimalContrastBorder: + themeColors["Color/Brand/Neutral/colorPrimaryBorder"].lightMode, + actionColor: + themeColors["Color/Brand/Primary/colorPrimaryText"].lightMode, + iconColor: + themeColors["Color/Brand/Neutral/colorPrimaryBorder"].lightMode, + contentColor: themeColors["Color/Neutral/Text/colorTextLabel"].lightMode, + titleColor: themeColors["Color/Neutral/Text/colorTextHeading"].lightMode, + }, + }, }; export const darkTheme: ThemeDefinitionProps = { @@ -2066,4 +2144,74 @@ export const darkTheme: ThemeDefinitionProps = { boldLabel: themeColors["Color/Neutral/Text/colorTextDisabled"].darkMode, }, }, + notificationAlert: { + danger: { + highContrastBG: themeColors["Color/Brand/Error/colorPrimaryBg"].darkMode, + highContrastBorder: + themeColors["Color/Brand/Error/colorPrimaryBg"].darkMode, + minimalContrastBG: + themeColors["Color/Neutral/Bg/colorBgElevated"].darkMode, + minimalContrastBorder: + themeColors["Color/Brand/Error/colorPrimaryBorder"].darkMode, + actionColor: themeColors["Color/Brand/Primary/colorPrimaryText"].darkMode, + iconColor: themeColors["Color/Brand/Error/colorPrimaryText"].darkMode, + contentColor: themeColors["Color/Neutral/Text/colorTextLabel"].darkMode, + titleColor: themeColors["Color/Neutral/Text/colorTextHeading"].darkMode, + }, + success: { + highContrastBG: + themeColors["Color/Brand/Success/colorPrimaryBg"].darkMode, + highContrastBorder: + themeColors["Color/Brand/Success/colorPrimaryBg"].darkMode, + minimalContrastBG: + themeColors["Color/Neutral/Bg/colorBgElevated"].darkMode, + minimalContrastBorder: + themeColors["Color/Brand/Success/colorPrimaryBorder"].darkMode, + actionColor: themeColors["Color/Brand/Primary/colorPrimaryText"].darkMode, + iconColor: themeColors["Color/Brand/Success/colorPrimaryBorder"].darkMode, + contentColor: themeColors["Color/Neutral/Text/colorTextLabel"].darkMode, + titleColor: themeColors["Color/Neutral/Text/colorTextHeading"].darkMode, + }, + warning: { + highContrastBG: + themeColors["Color/Brand/Warning/colorPrimaryBg"].darkMode, + highContrastBorder: + themeColors["Color/Brand/Warning/colorPrimaryBg"].darkMode, + minimalContrastBG: + themeColors["Color/Neutral/Bg/colorBgElevated"].darkMode, + minimalContrastBorder: + themeColors["Color/Brand/Warning/colorPrimaryBorder"].darkMode, + actionColor: themeColors["Color/Brand/Primary/colorPrimaryText"].darkMode, + iconColor: themeColors["Color/Brand/Warning/colorPrimaryBorder"].darkMode, + contentColor: themeColors["Color/Neutral/Text/colorTextLabel"].darkMode, + titleColor: themeColors["Color/Neutral/Text/colorTextHeading"].darkMode, + }, + information: { + highContrastBG: themeColors["Color/Brand/Info/colorPrimaryBg"].darkMode, + highContrastBorder: + themeColors["Color/Brand/Info/colorPrimaryBg"].darkMode, + minimalContrastBG: + themeColors["Color/Neutral/Bg/colorBgElevated"].darkMode, + minimalContrastBorder: + themeColors["Color/Brand/Primary/colorPrimaryText"].darkMode, + actionColor: themeColors["Color/Brand/Primary/colorPrimaryText"].darkMode, + iconColor: themeColors["Color/Brand/Primary/colorPrimaryText"].darkMode, + contentColor: themeColors["Color/Neutral/Text/colorTextLabel"].darkMode, + titleColor: themeColors["Color/Neutral/Text/colorTextHeading"].darkMode, + }, + neutral: { + highContrastBG: + themeColors["Color/Brand/Neutral/colorPrimaryBg"].darkMode, + highContrastBorder: + themeColors["Color/Brand/Neutral/colorPrimaryBg"].darkMode, + minimalContrastBG: + themeColors["Color/Neutral/Bg/colorBgElevated"].darkMode, + minimalContrastBorder: + themeColors["Color/Brand/Neutral/colorPrimaryBorder"].darkMode, + actionColor: themeColors["Color/Brand/Primary/colorPrimaryText"].darkMode, + iconColor: themeColors["Color/Brand/Neutral/colorPrimaryBorder"].darkMode, + contentColor: themeColors["Color/Neutral/Text/colorTextLabel"].darkMode, + titleColor: themeColors["Color/Neutral/Text/colorTextHeading"].darkMode, + }, + }, };