From e595ebd14610c1df947a338c3219e8f31a20d495 Mon Sep 17 00:00:00 2001 From: benlister-okta Date: Wed, 4 Dec 2024 22:25:26 -0800 Subject: [PATCH 1/3] feat: hackweek darkmode --- .../src/labs/AppSwitcher/AppSwitcher.tsx | 22 +- .../src/labs/AppSwitcher/OktaAura.tsx | 7 +- .../src/labs/SideNav/SideNav.tsx | 21 +- .../src/labs/SideNav/SideNavHeader.tsx | 44 +- .../src/labs/SideNav/SideNavItemContent.tsx | 92 ++- .../labs/SideNav/SideNavItemLinkContent.tsx | 11 +- .../src/labs/SideNav/SideNavLogo.tsx | 23 +- .../src/labs/TopNav/TopNav.tsx | 15 +- .../src/theme/components.tsx | 645 ++++++++++++------ .../src/ui-shell/UiShell/UiShellContent.tsx | 12 +- .../odyssey-react-mui/src/useContrastMode.tsx | 11 +- .../odyssey-storybook/.storybook/preview.ts | 6 +- 12 files changed, 641 insertions(+), 268 deletions(-) diff --git a/packages/odyssey-react-mui/src/labs/AppSwitcher/AppSwitcher.tsx b/packages/odyssey-react-mui/src/labs/AppSwitcher/AppSwitcher.tsx index e6bf144aba..6b037b2099 100644 --- a/packages/odyssey-react-mui/src/labs/AppSwitcher/AppSwitcher.tsx +++ b/packages/odyssey-react-mui/src/labs/AppSwitcher/AppSwitcher.tsx @@ -16,6 +16,7 @@ import { DesignTokens, useOdysseyDesignTokens, } from "../../OdysseyDesignTokensContext"; +import { ContrastMode, useContrastModeContext } from "../../useContrastMode"; import { OktaAura } from "./OktaAura"; import { AppSwitcherApp, @@ -31,12 +32,19 @@ export type AppSwitcherProps = { }; const AppSwitcherWrapperComponent = styled("nav", { - shouldForwardProp: (prop) => prop !== "odysseyDesignTokens", -})(({ odysseyDesignTokens }: { odysseyDesignTokens: DesignTokens }) => ({ + shouldForwardProp: (prop) => + prop !== "odysseyDesignTokens" && prop !== "contrastMode", +})<{ + odysseyDesignTokens: DesignTokens; + contrastMode: ContrastMode; +}>(({ odysseyDesignTokens, contrastMode }) => ({ position: "relative", display: "inline-block", height: "100%", - backgroundColor: odysseyDesignTokens.HueNeutralWhite, + backgroundColor: + contrastMode === "highContrast" + ? "#121212" + : odysseyDesignTokens.HueNeutralWhite, borderInlineEndStyle: "solid", borderInlineEndWidth: odysseyDesignTokens.BorderWidthMain, borderInlineEndColor: odysseyDesignTokens.BorderColorDisplay, @@ -65,13 +73,17 @@ const AppSwitcher = ({ selectedAppName, }: AppSwitcherProps) => { const odysseyDesignTokens = useOdysseyDesignTokens(); + const { contrastMode } = useContrastModeContext(); return ( - + - + {isLoading diff --git a/packages/odyssey-react-mui/src/labs/AppSwitcher/OktaAura.tsx b/packages/odyssey-react-mui/src/labs/AppSwitcher/OktaAura.tsx index dbe90c5444..300106bac4 100644 --- a/packages/odyssey-react-mui/src/labs/AppSwitcher/OktaAura.tsx +++ b/packages/odyssey-react-mui/src/labs/AppSwitcher/OktaAura.tsx @@ -16,6 +16,7 @@ import { DesignTokens, useOdysseyDesignTokens, } from "../../OdysseyDesignTokensContext"; +import { ContrastMode } from "../../useContrastMode"; const OktaAuraSvgComponent = styled("svg", { shouldForwardProp: (prop) => prop !== "odysseyDesignTokens", @@ -25,7 +26,7 @@ const OktaAuraSvgComponent = styled("svg", { margin: "auto", })); -const OktaAura = () => { +const OktaAura = ({ contrastMode }: { contrastMode: ContrastMode }) => { const odysseyDesignTokens = useOdysseyDesignTokens(); return ( { fillRule="evenodd" clipRule="evenodd" d="M17.6032 0.226701L16.9464 8.33185L16.9474 8.3328C16.6365 8.29478 16.3219 8.2734 16.0011 8.2734C15.6019 8.2734 15.2088 8.30381 14.8258 8.36227L14.4527 4.43184C14.4413 4.30922 14.5382 4.20181 14.6623 4.20371H15.3338L15.0102 0.227176C14.9992 0.105509 15.0957 0 15.2188 0H17.3946C17.5162 0 17.6127 0.104558 17.6032 0.226701ZM12.112 0.62925C12.0797 0.511384 11.9533 0.445798 11.8383 0.488096L9.79368 1.23283C9.67867 1.27466 9.62401 1.40631 9.67486 1.51752L11.3383 5.14331L10.7067 5.37143C10.5907 5.41326 10.5351 5.54681 10.5888 5.65897L12.2836 9.22487C12.8986 8.88649 13.5639 8.63127 14.2664 8.47063L12.112 0.62925ZM7.09038 2.88628L11.796 9.51669L11.7969 9.51764C11.2005 9.90545 10.6606 10.3736 10.1929 10.9064L7.37839 8.13367C7.28951 8.04717 7.29664 7.90269 7.39122 7.8238L7.90593 7.39321L5.1033 4.55493C5.01775 4.46843 5.02441 4.32585 5.11803 4.24696L6.78431 2.84731C6.87889 2.76841 7.01909 2.78695 7.09038 2.88628ZM3.14283 6.72451C3.04255 6.65512 2.9033 6.68649 2.84152 6.79152L1.75411 8.67642C1.6928 8.78288 1.73558 8.91833 1.84584 8.97061L5.45024 10.6792L5.11328 11.26C5.05102 11.3674 5.09474 11.5047 5.20786 11.556L8.79895 13.1981C9.05892 12.5303 9.40681 11.9077 9.8317 11.3455L3.14283 6.72451ZM0.487535 11.8479C0.508921 11.7271 0.627737 11.6501 0.746553 11.681L8.6117 13.7356C8.40781 14.4 8.29422 15.1029 8.27854 15.831L4.3405 15.515C4.21693 15.505 4.12901 15.391 4.15039 15.2693L4.26826 14.6087L0.297429 14.2365C0.175761 14.2247 0.088788 14.1115 0.110175 13.9908L0.487535 11.8479ZM0.190495 17.1594C0.068827 17.1713 -0.0181464 17.2844 0.00324043 17.4051L0.381551 19.5486C0.402938 19.6693 0.522704 19.7463 0.64057 19.7154L4.49971 18.7069L4.61473 19.3675C4.63611 19.4892 4.75778 19.5661 4.87707 19.5333L8.68346 18.4825C8.45914 17.8229 8.32084 17.1252 8.28376 16.399L0.19097 17.1604L0.190495 17.1594ZM1.44947 22.7918C1.38816 22.6853 1.42998 22.5499 1.54119 22.4971L8.88497 19.0148C9.16443 19.6736 9.53419 20.2847 9.97618 20.8346L6.75769 23.124C6.65741 23.1962 6.51578 23.1648 6.45447 23.0579L6.12036 22.4762L2.83914 24.7441C2.73791 24.8145 2.59961 24.7831 2.53782 24.6771L1.44947 22.7918ZM10.3474 21.2647L4.63516 27.052C4.54962 27.1385 4.55627 27.2811 4.6499 27.36L6.31712 28.7587C6.41075 28.8376 6.5519 28.8191 6.62319 28.7197L8.9306 25.4665L9.44436 25.8995C9.53894 25.9794 9.68199 25.9599 9.75233 25.8586L11.9927 22.6083C11.3849 22.2381 10.8321 21.7847 10.3488 21.2671L10.3474 21.2647ZM9.21908 30.5576C9.10407 30.5158 9.04942 30.3841 9.10027 30.2729L12.4894 22.8816C13.1129 23.2005 13.7854 23.4381 14.4931 23.5783L13.4993 27.3999C13.4679 27.5197 13.3406 27.5872 13.2246 27.5444L12.5939 27.3134L11.5374 31.1602C11.5051 31.2781 11.3787 31.3437 11.2637 31.3014L9.21908 30.5576ZM15.0539 23.6672L14.3971 31.7728C14.3876 31.8945 14.4836 32 14.6057 32H16.7815C16.9046 32 17.0006 31.8945 16.9901 31.7728L16.6665 27.7963H17.338C17.4616 27.7982 17.559 27.6908 17.5476 27.5682L17.1745 23.6377C16.7915 23.6962 16.3989 23.7261 15.9992 23.7261C15.6789 23.7261 15.3642 23.7052 15.0539 23.6672ZM22.9005 1.72521C22.9514 1.614 22.8967 1.48235 22.7817 1.44053L20.7371 0.696737C20.6221 0.654914 20.4957 0.720025 20.4634 0.837891L19.4068 4.68468L18.7762 4.4537C18.6602 4.41093 18.5324 4.47794 18.5015 4.5977L17.5077 8.4193C18.2154 8.5595 18.8874 8.79761 19.5114 9.11604L22.9005 1.72521ZM27.3656 4.94655L21.6534 10.7338L21.6525 10.7319C21.1691 10.2144 20.6169 9.76145 20.0085 9.39074L22.2489 6.14041C22.3193 6.03918 22.4623 6.01969 22.5569 6.09954L23.0707 6.53203L25.3781 3.27885C25.4493 3.17952 25.5905 3.16098 25.6841 3.23987L27.3514 4.63858C27.445 4.71747 27.4512 4.86005 27.3656 4.94655ZM30.4596 9.501C30.5708 9.44825 30.6126 9.3128 30.5513 9.20681L29.463 7.32192C29.4016 7.21546 29.2633 7.18457 29.1616 7.25443L25.8804 9.52239L25.5463 8.94067C25.485 8.83326 25.3438 8.80236 25.2431 8.8746L22.0246 11.164C22.4671 11.7138 22.8364 12.3245 23.1163 12.9837L30.4596 9.501ZM31.6183 12.451L31.9966 14.5944L31.9975 14.5954C32.0189 14.7161 31.9324 14.8292 31.8103 14.8411L23.7165 15.6015C23.6795 14.8753 23.5412 14.1776 23.3173 13.5179L27.1237 12.4671C27.2425 12.4339 27.3642 12.5108 27.386 12.633L27.5011 13.2936L31.3602 12.2851C31.4781 12.2537 31.5978 12.3307 31.6192 12.4519L31.6183 12.451ZM31.2528 20.3171C31.3716 20.3484 31.4904 20.2714 31.5118 20.1502L31.8892 18.0073C31.9106 17.8866 31.8241 17.7734 31.7019 17.7616L27.7311 17.3894L27.849 16.7288C27.8703 16.6071 27.7829 16.4931 27.6589 16.4831L23.7213 16.1671C23.7056 16.8952 23.5906 17.5981 23.3881 18.2625L31.2533 20.3161L31.2528 20.3171ZM29.1578 25.2066C29.0965 25.3121 28.9573 25.343 28.857 25.2736L28.8579 25.2726L22.1681 20.6521C22.593 20.0899 22.9409 19.4673 23.2009 18.7995L26.792 20.4421C26.9051 20.4939 26.9488 20.6312 26.8865 20.7381L26.5491 21.3189L30.154 23.0275C30.2642 23.0802 30.307 23.2157 30.2457 23.3217L29.1578 25.2066ZM20.2034 22.4814L24.909 29.1128C24.9803 29.2121 25.1205 29.2306 25.215 29.1517L26.8813 27.7521C26.9749 27.6732 26.9816 27.5306 26.8961 27.4441L24.0934 24.6063L24.6081 24.1757C24.7027 24.0968 24.7094 23.9524 24.621 23.8659L21.8069 21.0932C21.3393 21.6264 20.7998 22.0936 20.2034 22.4814ZM20.1625 31.5105C20.0475 31.5523 19.9206 31.4872 19.8888 31.3693L17.7344 23.5284C18.4368 23.3678 19.1027 23.1121 19.7177 22.7742L21.412 26.3401C21.4657 26.4522 21.4101 26.5858 21.2941 26.6276L20.6625 26.8557L22.3259 30.4815C22.3768 30.5927 22.3221 30.7244 22.2071 30.7662L20.1625 31.5105Z" - fill="black" + fill={contrastMode === "highContrast" ? "white" : "black"} /> ); }; + const MemoizedOktaAura = memo(OktaAura); +MemoizedOktaAura.displayName = "OktaAura"; export { MemoizedOktaAura as OktaAura }; diff --git a/packages/odyssey-react-mui/src/labs/SideNav/SideNav.tsx b/packages/odyssey-react-mui/src/labs/SideNav/SideNav.tsx index fe7f94e0a5..00961fd024 100644 --- a/packages/odyssey-react-mui/src/labs/SideNav/SideNav.tsx +++ b/packages/odyssey-react-mui/src/labs/SideNav/SideNav.tsx @@ -20,6 +20,7 @@ import { useEffect, KeyboardEventHandler, } from "react"; + import { Skeleton } from "@mui/material"; import { useTranslation } from "react-i18next"; @@ -28,6 +29,7 @@ import { DesignTokens, useOdysseyDesignTokens, } from "../../OdysseyDesignTokensContext"; +import { ContrastMode, useContrastModeContext } from "../../useContrastMode"; import { OdysseyThemeProvider } from "../../OdysseyThemeProvider"; import type { SideNavProps } from "./types"; import { SideNavHeader } from "./SideNavHeader"; @@ -101,19 +103,26 @@ const StyledOpacityTransitionContainer = styled("div", { const StyledSideNav = styled("nav", { shouldForwardProp: (prop) => - prop !== "odysseyDesignTokens" && prop !== "isSideNavCollapsed", + prop !== "odysseyDesignTokens" && + prop !== "isSideNavCollapsed" && + prop !== "contrastMode", })( ({ odysseyDesignTokens, isSideNavCollapsed, + contrastMode, }: { odysseyDesignTokens: DesignTokens; isSideNavCollapsed: boolean; + contrastMode: ContrastMode; }) => ({ position: "relative", display: "inline-block", height: "100%", - backgroundColor: odysseyDesignTokens.HueNeutralWhite, + backgroundColor: + contrastMode === "highContrast" + ? "#121212" + : odysseyDesignTokens.HueNeutralWhite, "&::after": { backgroundColor: odysseyDesignTokens.HueNeutral200, @@ -298,6 +307,8 @@ const SideNav = ({ const resizeObserverRef = useRef(null); const intersectionObserverRef = useRef(null); const odysseyDesignTokens: DesignTokens = useOdysseyDesignTokens(); + const { contrastMode } = useContrastModeContext(); + console.log("Current contrast mode1:", contrastMode); const { t } = useTranslation(); const [sideNavItemsList, updateSideNavItemsList] = useState(sideNavItems); @@ -484,6 +495,7 @@ const SideNav = ({ {...childProps} scrollRef={getRefIfThisIsFirstNodeWithIsSelected(childProps.id)} onItemSelected={setSelectedItem} + contrastMode={contrastMode} /> ), @@ -495,6 +507,7 @@ const SideNav = ({ sideNavItemsList, sideNavItemContentProviderValue, setSelectedItem, + contrastMode, ]); const sideNavExpandClickHandler = useCallback(() => { @@ -540,6 +553,7 @@ const SideNav = ({ id="side-nav-expandable" isSideNavCollapsed={isSideNavCollapsed} odysseyDesignTokens={odysseyDesignTokens} + contrastMode={contrastMode} > {isCollapsible && ( prop !== "odysseyDesignTokens", -})(({ odysseyDesignTokens }: { odysseyDesignTokens: DesignTokens }) => ({ + shouldForwardProp: (prop) => + prop !== "odysseyDesignTokens" && prop !== "contrastMode", +})<{ + odysseyDesignTokens: DesignTokens; + contrastMode: ContrastMode; +}>(({ odysseyDesignTokens, contrastMode }) => ({ position: "relative", display: "flex", flexDirection: "column", - backgroundColor: odysseyDesignTokens.HueNeutralWhite, + backgroundColor: + contrastMode === "highContrast" + ? "#121212" + : odysseyDesignTokens.HueNeutralWhite, zIndex: 1, })); @@ -49,8 +57,12 @@ const SideNavLogoContainer = styled("div", { })); const SideNavHeadingContainer = styled("div", { - shouldForwardProp: (prop) => prop !== "odysseyDesignTokens", -})(({ odysseyDesignTokens }: { odysseyDesignTokens: DesignTokens }) => ({ + shouldForwardProp: (prop) => + prop !== "odysseyDesignTokens" && prop !== "contrastMode", +})<{ + odysseyDesignTokens: DesignTokens; + contrastMode: ContrastMode; +}>(({ odysseyDesignTokens, contrastMode }) => ({ display: "flex", justifyContent: "space-between", alignItems: "center", @@ -60,6 +72,10 @@ const SideNavHeadingContainer = styled("div", { ["& .MuiTypography-root"]: { margin: 0, width: "100%", + color: + contrastMode === "highContrast" + ? odysseyDesignTokens.HueNeutralWhite + : odysseyDesignTokens.HueNeutral800, }, })); @@ -72,27 +88,37 @@ export type SideNavHeaderProps = { * If the side nav currently has no items, it will be loading. */ isLoading?: boolean; + /** + * The current contrast mode + */ + contrastMode: ContrastMode; } & Pick; const SideNavHeader = ({ appName, isLoading, logoProps, + contrastMode, }: SideNavHeaderProps) => { const odysseyDesignTokens = useOdysseyDesignTokens(); return ( - + {isLoading ? ( - // The skeleton takes the hardcoded dimensions of the Okta logo ) : ( - + )} - + {isLoading ? : appName} diff --git a/packages/odyssey-react-mui/src/labs/SideNav/SideNavItemContent.tsx b/packages/odyssey-react-mui/src/labs/SideNav/SideNavItemContent.tsx index f17db5e69b..6df3c8d7d0 100644 --- a/packages/odyssey-react-mui/src/labs/SideNav/SideNavItemContent.tsx +++ b/packages/odyssey-react-mui/src/labs/SideNav/SideNavItemContent.tsx @@ -24,6 +24,7 @@ import { type DesignTokens, useOdysseyDesignTokens, } from "../../OdysseyDesignTokensContext"; +import { ContrastMode } from "../../useContrastMode"; import { SideNavItemLinkContent } from "./SideNavItemLinkContent"; import type { SideNavItem } from "./types"; import { @@ -34,12 +35,15 @@ import { ExternalLinkIcon } from "../../icons.generated"; export const StyledSideNavListItem = styled("li", { shouldForwardProp: (prop) => - prop !== "odysseyDesignTokens" && prop !== "isSelected", + prop !== "odysseyDesignTokens" && + prop !== "isSelected" && + prop !== "contrastMode", })<{ odysseyDesignTokens: DesignTokens; isSelected?: boolean; disabled?: boolean; -}>(({ odysseyDesignTokens, isSelected }) => ({ + contrastMode: ContrastMode; +}>(({ odysseyDesignTokens, isSelected, contrastMode }) => ({ display: "flex", alignItems: "center", backgroundColor: "unset", @@ -47,8 +51,14 @@ export const StyledSideNavListItem = styled("li", { transition: `backgroundColor ${odysseyDesignTokens.TransitionDurationMain}, color ${odysseyDesignTokens.TransitionDurationMain}`, ...(isSelected && { - color: `${odysseyDesignTokens.TypographyColorAction} !important`, - backgroundColor: odysseyDesignTokens.HueBlue50, + color: + contrastMode === "highContrast" + ? "#ffffff" + : `${odysseyDesignTokens.TypographyColorAction}`, + backgroundColor: + contrastMode === "highContrast" + ? "#2d2d2d" + : odysseyDesignTokens.HueBlue50, }), })); @@ -70,16 +80,22 @@ export const getBaseNavItemContentStyles = ({ odysseyDesignTokens, isDisabled, isSelected, + contrastMode, }: { odysseyDesignTokens: DesignTokens; isDisabled?: boolean; isSelected?: boolean; + contrastMode: ContrastMode; }) => ({ display: "flex", alignItems: "center", width: "100%", textDecoration: "none", - color: `${odysseyDesignTokens.TypographyColorHeading} !important`, + color: + contrastMode === "highContrast" + ? "#ffffff !important" + : `${odysseyDesignTokens.TypographyColorHeading} !important`, + minHeight: "unset", paddingBlock: odysseyDesignTokens.Spacing3, paddingInlineEnd: odysseyDesignTokens.Spacing4, @@ -91,7 +107,10 @@ export const getBaseNavItemContentStyles = ({ "&:hover, [data-sortable-container='true']:has(button:hover, button:focus, button:focus-visible) &": { textDecoration: "none", - backgroundColor: odysseyDesignTokens.HueNeutral50, + backgroundColor: + contrastMode === "highContrast" + ? "#2d2d2d" + : odysseyDesignTokens.HueNeutral50, ...(isSelected && { backgroundColor: odysseyDesignTokens.HueBlue50, @@ -104,7 +123,10 @@ export const getBaseNavItemContentStyles = ({ }, ...(isSelected && { - color: `${odysseyDesignTokens.TypographyColorAction}`, + color: + contrastMode === "highContrast" + ? "#ffffff" + : odysseyDesignTokens.TypographyColorAction, fontWeight: odysseyDesignTokens.TypographyWeightBodyBold, }), @@ -148,18 +170,28 @@ const NavItemContentContainer = styled("div", { odysseyDesignTokens: DesignTokens; isSelected?: boolean; isDisabled?: boolean; -}>(({ contextValue, odysseyDesignTokens, isDisabled, isSelected }) => ({ - ...getBaseNavItemContentStyles({ + contrastMode: ContrastMode; +}>( + ({ + contextValue, odysseyDesignTokens, isDisabled, isSelected, - }), + contrastMode, + }) => ({ + ...getBaseNavItemContentStyles({ + odysseyDesignTokens, + isDisabled, + isSelected, + contrastMode, + }), - ...getNavItemContentStyles({ - odysseyDesignTokens, - contextValue, + ...getNavItemContentStyles({ + odysseyDesignTokens, + contextValue, + }), }), -})); +); const StyledNavItemLink = styled(NavItemLink, { shouldForwardProp: (prop) => @@ -172,23 +204,34 @@ const StyledNavItemLink = styled(NavItemLink, { odysseyDesignTokens: DesignTokens; isSelected?: boolean; isDisabled?: boolean; -}>(({ contextValue, odysseyDesignTokens, isDisabled, isSelected }) => ({ - ...getBaseNavItemContentStyles({ + contrastMode: ContrastMode; +}>( + ({ + contextValue, odysseyDesignTokens, isDisabled, isSelected, - }), + contrastMode, + }) => ({ + ...getBaseNavItemContentStyles({ + odysseyDesignTokens, + isDisabled, + isSelected, + contrastMode, + }), - ...getNavItemContentStyles({ - odysseyDesignTokens, - contextValue, + ...getNavItemContentStyles({ + odysseyDesignTokens, + contextValue, + }), }), -})); +); const SideNavItemContent = ({ count, id, label, + contrastMode, href, target, startIcon, @@ -220,6 +263,7 @@ const SideNavItemContent = ({ */ scrollRef?: React.RefObject; onItemSelected?(selectedItemId: string): void; + contrastMode: ContrastMode; }) => { const sidenavItemContentContext = useSideNavItemContent(); const contextValue = useMemo( @@ -227,7 +271,7 @@ const SideNavItemContent = ({ [sidenavItemContentContext], ); const odysseyDesignTokens = useOdysseyDesignTokens(); - + console.log("Current contrast mode:", contrastMode); const localScrollRef = useRef(null); useImperativeHandle( scrollRef, @@ -264,6 +308,7 @@ const SideNavItemContent = ({ return ( - prop !== "odysseyDesignTokens" && prop !== "isIconVisible", + prop !== "odysseyDesignTokens" && + prop !== "isIconVisible" && + prop !== "contrastMode", })<{ odysseyDesignTokens: DesignTokens; isIconVisible: boolean; -}>(({ odysseyDesignTokens, isIconVisible }) => ({ + contrastMode: ContrastMode; +}>(({ odysseyDesignTokens, isIconVisible, contrastMode }) => ({ width: "100%", display: "flex", flexWrap: "wrap", alignItems: "center", fontSize: odysseyDesignTokens.TypographySizeBody, marginInlineStart: isIconVisible ? odysseyDesignTokens.Spacing3 : 0, + color: contrastMode === "highContrast" ? "#ffffff !important" : "inherit", })); const SideNavItemLinkContent = ({ @@ -48,6 +53,7 @@ const SideNavItemLinkContent = ({ "count" | "label" | "startIcon" | "endIcon" | "severity" | "statusLabel" >): ReactNode => { const odysseyDesignTokens = useOdysseyDesignTokens(); + const { contrastMode } = useContrastModeContext(); const sideNavItemContentStyles = useMemo( () => ({ @@ -65,6 +71,7 @@ const SideNavItemLinkContent = ({ {label} {!count && severity && ( diff --git a/packages/odyssey-react-mui/src/labs/SideNav/SideNavLogo.tsx b/packages/odyssey-react-mui/src/labs/SideNav/SideNavLogo.tsx index f6983025df..d5827e820e 100644 --- a/packages/odyssey-react-mui/src/labs/SideNav/SideNavLogo.tsx +++ b/packages/odyssey-react-mui/src/labs/SideNav/SideNavLogo.tsx @@ -11,15 +11,30 @@ */ import { memo, useMemo } from "react"; +import styled from "@emotion/styled"; +import { ContrastMode } from "../../useContrastMode"; import { OktaLogo } from "./OktaLogo"; import { SideNavLogoProps } from "./types"; +// Create a styled wrapper for the logo +const LogoWrapper = styled.div<{ contrastMode: ContrastMode }>( + ({ contrastMode }) => ({ + "& svg, & img": { + filter: + contrastMode === "highContrast" + ? "brightness(0) invert(1)" // makes logo white in Dark Mode + : "none", + }, + }), +); + const SideNavLogo = ({ imageAltText, href, logoComponent, imageUrl, -}: SideNavLogoProps) => { + contrastMode, +}: SideNavLogoProps & { contrastMode: ContrastMode }) => { const logo = useMemo(() => { if (logoComponent) { return logoComponent; @@ -32,7 +47,11 @@ const SideNavLogo = ({ return ; }, [imageAltText, logoComponent, imageUrl]); - return href ? {logo} : logo; + const wrappedLogo = ( + {logo} + ); + + return href ? {wrappedLogo} : wrappedLogo; }; const MemoizedSideNavLogo = memo(SideNavLogo); diff --git a/packages/odyssey-react-mui/src/labs/TopNav/TopNav.tsx b/packages/odyssey-react-mui/src/labs/TopNav/TopNav.tsx index dd8de2bb69..ca6ec88b1a 100644 --- a/packages/odyssey-react-mui/src/labs/TopNav/TopNav.tsx +++ b/packages/odyssey-react-mui/src/labs/TopNav/TopNav.tsx @@ -18,6 +18,7 @@ import { DesignTokens, useOdysseyDesignTokens, } from "../../OdysseyDesignTokensContext"; +import { ContrastMode, useContrastModeContext } from "../../useContrastMode"; export const TOP_NAV_HEIGHT = `${64 / 14}rem`; @@ -31,13 +32,19 @@ const StyledRightSideContainer = styled("div")(() => ({ const StyledTopNavContainer = styled("div", { shouldForwardProp: (prop) => - prop !== "odysseyDesignTokens" && prop !== "isScrolled", + prop !== "odysseyDesignTokens" && + prop !== "isScrolled" && + prop !== "contrastMode", })<{ odysseyDesignTokens: DesignTokens; isScrolled?: boolean; -}>(({ odysseyDesignTokens, isScrolled }) => ({ + contrastMode: ContrastMode; +}>(({ odysseyDesignTokens, isScrolled, contrastMode }) => ({ alignItems: "center", - backgroundColor: odysseyDesignTokens.HueNeutral50, + backgroundColor: + contrastMode === "highContrast" + ? "#252525" // Dark mode background + : odysseyDesignTokens.HueNeutral50, // Light mode background boxShadow: isScrolled ? odysseyDesignTokens.DepthMedium : undefined, clipPath: "inset(0 0 -100vh 0)", display: "flex", @@ -73,11 +80,13 @@ const TopNav = ({ rightSideComponent, }: TopNavProps) => { const odysseyDesignTokens = useOdysseyDesignTokens(); + const { contrastMode } = useContrastModeContext(); return ( {leftSideComponent ??
} diff --git a/packages/odyssey-react-mui/src/theme/components.tsx b/packages/odyssey-react-mui/src/theme/components.tsx index 58bd7c8660..72ee3aee39 100644 --- a/packages/odyssey-react-mui/src/theme/components.tsx +++ b/packages/odyssey-react-mui/src/theme/components.tsx @@ -74,7 +74,12 @@ export const components = ({ MuiAccordion: { styleOverrides: { root: () => ({ - backgroundColor: odysseyTokens.HueNeutralWhite, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral900, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutralWhite, + }), border: 0, borderBottomColor: odysseyTokens.BorderColorDisplay, borderBottomStyle: "solid", @@ -83,7 +88,12 @@ export const components = ({ boxShadow: "none", "&.Mui-disabled": { - backgroundColor: odysseyTokens.HueNeutralWhite, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral900, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutralWhite, + }), color: odysseyTokens.TypographyColorDisabled, cursor: "default", @@ -119,11 +129,21 @@ export const components = ({ paddingInline: odysseyTokens.Spacing3, "&:hover": { - backgroundColor: odysseyTokens.HueNeutral50, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral800, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral50, + }), }, "&:focus-visible": { - backgroundColor: odysseyTokens.HueNeutral50, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral800, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral50, + }), outlineColor: odysseyTokens.PalettePrimaryMain, outlineWidth: 2, outlineStyle: "solid", @@ -428,7 +448,13 @@ export const components = ({ listbox: { borderWidth: odysseyTokens.BorderWidthMain, borderStyle: odysseyTokens.BorderStyleMain, - borderColor: odysseyTokens.HueNeutral200, + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral600, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral200, + }), paddingBlock: odysseyTokens.Spacing2, paddingInline: odysseyTokens.Spacing2, borderRadius: odysseyTokens.BorderRadiusMain, @@ -440,11 +466,21 @@ export const components = ({ borderRadius: odysseyTokens.BorderRadiusTight, [`&:hover`]: { - backgroundColor: odysseyTokens.HueNeutral100, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral700, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral100, + }), }, [`&.${autocompleteClasses.focused}`]: { - backgroundColor: odysseyTokens.HueNeutral100, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral700, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral100, + }), }, [`&[aria-selected="true"]`]: { @@ -472,7 +508,13 @@ export const components = ({ paddingInline: odysseyTokens.Spacing4, borderWidth: odysseyTokens.BorderWidthMain, borderStyle: odysseyTokens.BorderStyleMain, - borderColor: odysseyTokens.HueNeutral200, + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral600, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral200, + }), borderRadius: odysseyTokens.BorderRadiusMain, }, popupIndicator: { @@ -498,7 +540,12 @@ export const components = ({ }), inputRoot: ({ ownerState }) => ({ ...(ownerState.readOnly === true && { - backgroundColor: odysseyTokens.HueNeutral50, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral800, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral50, + }), [`&:not(:hover)`]: { borderColor: "transparent", @@ -549,7 +596,12 @@ export const components = ({ transitionTimingFunction: "linear", "&:hover": { - backgroundColor: odysseyTokens.HueNeutral100, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral700, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral100, + }), color: odysseyTokens.TypographyColorBody, }, @@ -663,12 +715,29 @@ export const components = ({ ...(ownerState.variant === "secondary" && { backgroundColor: "transparent", - borderColor: odysseyTokens.HueNeutral300, + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral500, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral300, + }), color: odysseyTokens.TypographyColorBody, "&:hover": { - backgroundColor: odysseyTokens.HueNeutral200, - borderColor: odysseyTokens.HueNeutral400, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral600, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral200, + }), + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral400, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral400, + }), }, "&:active, &[aria-expanded='true']": { @@ -678,7 +747,12 @@ export const components = ({ }, "&:disabled": { - backgroundColor: odysseyTokens.HueNeutral200, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral600, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral200, + }), borderColor: "transparent", color: odysseyTokens.TypographyColorDisabled, }, @@ -708,12 +782,29 @@ export const components = ({ ...(ownerState.variant === "dangerSecondary" && { backgroundColor: "transparent", - borderColor: odysseyTokens.HueNeutral300, + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral500, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral300, + }), color: odysseyTokens.PaletteDangerMain, "&:hover": { - backgroundColor: odysseyTokens.HueNeutral200, - borderColor: odysseyTokens.HueNeutral400, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral600, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral200, + }), + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral400, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral400, + }), color: odysseyTokens.PaletteDangerMain, }, @@ -735,7 +826,12 @@ export const components = ({ color: odysseyTokens.TypographyColorBody, "&:hover": { - backgroundColor: odysseyTokens.HueNeutral200, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral600, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral200, + }), }, "&:active, &[aria-expanded='true']": { @@ -755,7 +851,12 @@ export const components = ({ color: odysseyTokens.TypographyColorAction, "&:hover": { - backgroundColor: odysseyTokens.HueNeutral200, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral600, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral200, + }), }, "&:active, &[aria-expanded='true']": { @@ -835,7 +936,12 @@ export const components = ({ MuiCard: { styleOverrides: { root: () => ({ - backgroundColor: odysseyTokens.HueNeutralWhite, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral900, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutralWhite, + }), borderRadius: odysseyTokens.BorderRadiusOuter, boxShadow: odysseyTokens.DepthMedium, padding: odysseyTokens.Spacing5, @@ -982,12 +1088,34 @@ export const components = ({ outlineOffset: "1px", }, "&.Mui-disabled": { - backgroundColor: odysseyTokens.HueNeutral50, - borderColor: odysseyTokens.HueNeutral300, - - ".Mui-error:not(.Mui-valid) > &": { + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral800, + }), + ...(contrastMode === "lowContrast" && { backgroundColor: odysseyTokens.HueNeutral50, + }), + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral500, + }), + ...(contrastMode === "lowContrast" && { borderColor: odysseyTokens.HueNeutral300, + }), + + ".Mui-error:not(.Mui-valid) > &": { + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral800, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral50, + }), + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral500, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral300, + }), }, [`.${svgIconClasses.root}`]: { @@ -997,23 +1125,62 @@ export const components = ({ ...(isReadOnly && { // Override default styles - backgroundColor: odysseyTokens.HueNeutral100, + + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral700, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral100, + }), border: `1px solid ${odysseyTokens.HueNeutral300}`, cursor: "default", // Override checked/indeterminate styles "&.Mui-checked, &.MuiCheckbox-indeterminate": { - backgroundColor: odysseyTokens.HueNeutral100, - borderColor: odysseyTokens.HueNeutral300, - - [`.${formControlLabelClasses.root}:hover > &`]: { + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral700, + }), + ...(contrastMode === "lowContrast" && { backgroundColor: odysseyTokens.HueNeutral100, + }), + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral500, + }), + ...(contrastMode === "lowContrast" && { borderColor: odysseyTokens.HueNeutral300, + }), + + [`.${formControlLabelClasses.root}:hover > &`]: { + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral700, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral100, + }), + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral500, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral300, + }), }, }, [`.${formControlLabelClasses.root}:hover > &`]: { - backgroundColor: odysseyTokens.HueNeutral100, - borderColor: odysseyTokens.HueNeutral300, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral700, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral100, + }), + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral500, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral300, + }), }, // ReadOnly styles for SVG check icon [`.${svgIconClasses.root}`]: { @@ -1030,172 +1197,85 @@ export const components = ({ deleteIcon: , }, styleOverrides: { - root: ({ ownerState }) => { - return { - height: "auto", - paddingBlock: `calc(${odysseyTokens.Spacing2} - ${odysseyTokens.BorderWidthMain})`, - paddingInline: odysseyTokens.Spacing3, - fontSize: odysseyTokens.TypographySizeBody, - lineHeight: odysseyTokens.TypographyLineHeightUi, - borderRadius: odysseyTokens.BorderRadiusRound, + root: ({ ownerState }) => ({ + height: "auto", + paddingBlock: `calc(${odysseyTokens.Spacing2} - ${odysseyTokens.BorderWidthMain})`, + paddingInline: odysseyTokens.Spacing3, + fontSize: odysseyTokens.TypographySizeBody, + lineHeight: odysseyTokens.TypographyLineHeightUi, + borderRadius: odysseyTokens.BorderRadiusRound, + + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral700, + borderColor: odysseyTokens.HueNeutral600, + }), + ...(contrastMode === "lowContrast" && { backgroundColor: odysseyTokens.HueNeutral100, - borderWidth: odysseyTokens.BorderWidthMain, borderColor: odysseyTokens.HueNeutral200, - borderStyle: odysseyTokens.BorderStyleMain, - color: odysseyTokens.HueNeutral700, - - ...(ownerState.onDelete && { - paddingInlineEnd: odysseyTokens.Spacing2, - }), + }), - [`&.${chipClasses.disabled}`]: { - opacity: 1, - pointerEvents: "none", - borderColor: odysseyTokens.BorderColorDisabled, - color: odysseyTokens.TypographyColorDisabled, + borderWidth: odysseyTokens.BorderWidthMain, + borderStyle: odysseyTokens.BorderStyleMain, + color: odysseyTokens.HueNeutral700, - [`& .${chipClasses.deleteIcon}`]: { - color: odysseyTokens.HueNeutral300, - }, - [`& .${chipClasses.icon}`]: { - color: odysseyTokens.HueNeutral300, - }, - }, + ...(ownerState.onDelete && { + paddingInlineEnd: odysseyTokens.Spacing2, + }), - ...(ownerState.clickable && { - "&:hover": { - backgroundColor: odysseyTokens.HueNeutral200, - }, - [`&.${chipClasses.focusVisible}`]: { - backgroundColor: odysseyTokens.HueNeutral200, - outlineColor: odysseyTokens.FocusOutlineColorPrimary, - outlineOffset: odysseyTokens.FocusOutlineOffsetTight, - outlineStyle: odysseyTokens.FocusOutlineStyle, - outlineWidth: odysseyTokens.FocusOutlineWidthMain, - }, - "&:active": { - boxShadow: "none", - backgroundColor: odysseyTokens.HueNeutral300, - }, - }), + [`&.${chipClasses.disabled}`]: { + opacity: 1, + pointerEvents: "none", + borderColor: odysseyTokens.BorderColorDisabled, + color: odysseyTokens.TypographyColorDisabled, + [`& .${chipClasses.deleteIcon}`]: { + color: odysseyTokens.HueNeutral300, + }, [`& .${chipClasses.icon}`]: { - margin: 0, - marginInlineEnd: odysseyTokens.Spacing1, + color: odysseyTokens.HueNeutral300, }, + }, - ...(ownerState.variant === "lamp" && { - paddingBlock: 0, - paddingInline: 0, - borderRadius: 0, - border: 0, - backgroundColor: "transparent", - color: odysseyTokens.TypographyColorBody, - - "&::before": { - content: "''", - width: odysseyTokens.Spacing2, - height: odysseyTokens.Spacing2, - marginInlineEnd: odysseyTokens.Spacing2, - borderRadius: "100%", + ...(ownerState.clickable && { + "&:hover": { + ...(contrastMode === "highContrast" && { backgroundColor: odysseyTokens.HueNeutral600, - }, - - [`&.${chipClasses.colorError}`]: { - "&::before": { - border: 0, - backgroundColor: odysseyTokens.PaletteDangerMain, - }, - }, - - [`&.${chipClasses.colorSuccess}`]: { - "&::before": { - border: 0, - backgroundColor: odysseyTokens.PaletteSuccessMain, - }, - }, - - [`&.${chipClasses.colorWarning}`]: { - "&::before": { - border: 0, - backgroundColor: odysseyTokens.HueYellow200, - }, - }, - }), - - ...(ownerState.variant === "pill" && { - paddingBlock: odysseyTokens.Spacing1, - paddingInline: odysseyTokens.Spacing2, - borderRadius: odysseyTokens.BorderRadiusMain, - border: 0, - fontWeight: odysseyTokens.TypographyWeightHeadingBold, - lineHeight: odysseyTokens.TypographyLineHeightOverline, - fontSize: "0.71428571rem", - textTransform: "uppercase", - + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral200, + }), + }, + [`&.${chipClasses.focusVisible}`]: { ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral600, + }), + ...(contrastMode === "lowContrast" && { backgroundColor: odysseyTokens.HueNeutral200, - color: odysseyTokens.HueNeutral700, + }), + outlineColor: odysseyTokens.FocusOutlineColorPrimary, + outlineOffset: odysseyTokens.FocusOutlineOffsetTight, + outlineStyle: odysseyTokens.FocusOutlineStyle, + outlineWidth: odysseyTokens.FocusOutlineWidthMain, + }, + "&:active": { + boxShadow: "none", + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral500, }), ...(contrastMode === "lowContrast" && { - backgroundColor: odysseyTokens.HueNeutral50, - color: odysseyTokens.TypographyColorSubordinate, + backgroundColor: odysseyTokens.HueNeutral300, }), - - [`&.${chipClasses.colorError}`]: { - ...(contrastMode === "highContrast" && { - backgroundColor: odysseyTokens.HueRed100, - color: odysseyTokens.HueRed700, - }), - ...(contrastMode === "lowContrast" && { - backgroundColor: odysseyTokens.PaletteDangerLighter, - color: odysseyTokens.TypographyColorDanger, - }), - }, - - [`&.${chipClasses.colorInfo}`]: { - ...(contrastMode === "highContrast" && { - backgroundColor: odysseyTokens.HueBlue100, - color: odysseyTokens.HueBlue700, - }), - ...(contrastMode === "lowContrast" && { - backgroundColor: odysseyTokens.PalettePrimaryLighter, - color: odysseyTokens.PalettePrimaryText, - }), - }, - - [`&.${chipClasses.colorSuccess}`]: { - ...(contrastMode === "highContrast" && { - backgroundColor: odysseyTokens.HueGreen200, - color: odysseyTokens.HueGreen700, - }), - ...(contrastMode === "lowContrast" && { - backgroundColor: odysseyTokens.PaletteSuccessLighter, - color: odysseyTokens.TypographyColorSuccess, - }), - }, - - [`&.${chipClasses.colorWarning}`]: { - ...(contrastMode === "highContrast" && { - backgroundColor: odysseyTokens.HueYellow100, - color: odysseyTokens.HueYellow700, - }), - ...(contrastMode === "lowContrast" && { - backgroundColor: odysseyTokens.PaletteWarningLighter, - color: odysseyTokens.TypographyColorWarning, - }), - }, - }), - - [`.${inputBaseClasses.root}.${inputBaseClasses.disabled} &`]: { - backgroundColor: odysseyTokens.HueNeutral200, }, - }; - }, + }), + + [`& .${chipClasses.icon}`]: { + margin: 0, + marginInlineEnd: odysseyTokens.Spacing1, + }, + }), label: { padding: 0, - [`.${inputBaseClasses.root}.${inputBaseClasses.disabled} &`]: { color: odysseyTokens.TypographyColorDisabled, WebkitTextFillColor: odysseyTokens.TypographyColorDisabled, @@ -1209,11 +1289,9 @@ export const components = ({ cursor: "pointer", margin: "0", marginInlineStart: odysseyTokens.Spacing2, - "&:hover": { color: odysseyTokens.HueNeutral600, }, - [`.${inputBaseClasses.root}.${inputBaseClasses.disabled} &`]: { display: "none", }, @@ -1354,7 +1432,13 @@ export const components = ({ borderWidth: odysseyTokens.BorderWidthMain, borderRadius: odysseyTokens.BorderRadiusTight, borderColor: odysseyTokens.BorderColorDisplay, - backgroundColor: odysseyTokens.HueNeutral50, + + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral800, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral50, + }), padding: `calc(${odysseyTokens.Spacing1} / 2) ${odysseyTokens.Spacing1}`, fontSize: odysseyTokens.TypographySizeSubordinate, lineHeight: odysseyTokens.TypographyLineHeightHeading5, @@ -1450,7 +1534,13 @@ export const components = ({ marginInline: 0, borderWidth: odysseyTokens.BorderWidthMain, borderStyle: odysseyTokens.BorderStyleMain, - borderColor: odysseyTokens.HueNeutral200, + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral600, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral200, + }), }, ins: { @@ -1482,8 +1572,20 @@ export const components = ({ borderStyle: odysseyTokens.BorderStyleMain, borderWidth: odysseyTokens.BorderWidthMain, borderRadius: odysseyTokens.BorderRadiusMain, - borderColor: odysseyTokens.HueNeutral200, - backgroundColor: odysseyTokens.HueNeutral50, + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral600, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral200, + }), + + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral800, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral50, + }), padding: `calc(${odysseyTokens.Spacing1} / 2) ${odysseyTokens.Spacing1}`, fontFamily: "'Inconsolata', 'SFMono-Regular', 'Consolas', 'Liberation Mono', 'Menlo', 'Courier', monospace", @@ -1593,7 +1695,13 @@ export const components = ({ samp: { padding: "0 0.5ch", - backgroundColor: odysseyTokens.HueNeutral100, + + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral700, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral100, + }), boxShadow: `0 1px 0 ${odysseyTokens.HueNeutral50}`, fontSize: odysseyTokens.TypographySizeBody, @@ -1878,7 +1986,12 @@ export const components = ({ padding: odysseyTokens.Spacing1, borderRadius: odysseyTokens.BorderRadiusMain, "&:hover": { - backgroundColor: odysseyTokens.HueNeutral100, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral700, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral100, + }), }, "&:focus-visible": { boxShadow: `0 0 0 2px ${odysseyTokens.HueNeutralWhite}, 0 0 0 4px ${odysseyTokens.PalettePrimaryMain}`, @@ -1938,7 +2051,14 @@ export const components = ({ borderRadius: odysseyTokens.BorderRadiusMain, borderColor: odysseyTokens.HueNeutral500, boxShadow: `0 0 0 0 transparent`, - backgroundColor: odysseyTokens.HueNeutralWhite, + + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral900, + color: odysseyTokens.HueNeutralWhite, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutralWhite, + }), transition: theme.transitions.create( ["border-color", "background-color", "box-shadow"], { @@ -1947,7 +2067,12 @@ export const components = ({ ), ["&[data-ods-type='search']"]: { - borderColor: odysseyTokens.HueNeutral400, + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral400, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral400, + }), [`& .${inputBaseClasses.input}::placeholder`]: { color: odysseyTokens.TypographyColorSupport, @@ -1956,11 +2081,27 @@ export const components = ({ }, ["&[data-ods-variant='filled']"]: { - backgroundColor: odysseyTokens.HueNeutral50, - borderColor: odysseyTokens.HueNeutral50, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral800, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral50, + }), + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral800, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral50, + }), [`&:hover`]: { - borderColor: odysseyTokens.HueNeutral400, + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral400, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral400, + }), }, [`&.${inputBaseClasses.focused}`]: { @@ -1975,7 +2116,13 @@ export const components = ({ ...(ownerState.readOnly === true && { borderColor: "transparent", - backgroundColor: odysseyTokens.HueNeutral50, + + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral800, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral50, + }), }), [`&:hover`]: { @@ -2006,7 +2153,13 @@ export const components = ({ color: odysseyTokens.TypographyColorDisabled, borderColor: odysseyTokens.BorderColorDisabled, pointerEvents: "auto", - backgroundColor: odysseyTokens.HueNeutral50, + + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral800, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral50, + }), cursor: "not-allowed", }, }), @@ -2213,7 +2366,13 @@ export const components = ({ "&:hover": { textDecoration: "none", - backgroundColor: odysseyTokens.HueNeutral100, + + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral700, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral100, + }), // Reset on touch devices, it doesn't add specificity "@media (hover: none)": { @@ -2222,7 +2381,12 @@ export const components = ({ }, [`:focus-visible`]: { - backgroundColor: odysseyTokens.HueNeutral100, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral700, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral100, + }), }, [`&.${menuItemClasses.root}-destructive`]: { @@ -2348,7 +2512,13 @@ export const components = ({ marginBlockStart: odysseyTokens.Spacing1, borderWidth: odysseyTokens.BorderWidthMain, borderStyle: odysseyTokens.BorderStyleMain, - borderColor: odysseyTokens.HueNeutral200, + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral600, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral200, + }), }, }, }, @@ -2429,15 +2599,31 @@ export const components = ({ backgroundColor: odysseyTokens.PaletteDangerMain, }, "&.Mui-disabled": { - backgroundColor: odysseyTokens.HueNeutral50, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral800, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral50, + }), borderColor: odysseyTokens.BorderColorDisabled, "&.Mui-checked::before": { backgroundColor: odysseyTokens.BorderColorDisabled, }, }, ...(isReadOnly && { - backgroundColor: odysseyTokens.HueNeutral100, - borderColor: odysseyTokens.HueNeutral300, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral700, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral100, + }), + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral500, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral300, + }), cursor: "default", "&::before": { content: "''", @@ -2454,8 +2640,19 @@ export const components = ({ backgroundColor: odysseyTokens.HueNeutral700, }, [`.${formControlLabelClasses.root}:hover > &`]: { - backgroundColor: odysseyTokens.HueNeutral100, - borderColor: odysseyTokens.HueNeutral300, + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral700, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral100, + }), + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral500, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral300, + }), }, }), }; @@ -2492,10 +2689,26 @@ export const components = ({ root: ({ ownerState }) => ({ ...(ownerState?.inputProps?.readOnly && { "&.MuiInputBase-root": { - backgroundColor: odysseyTokens.HueNeutral50, - borderColor: odysseyTokens.HueNeutral200, - "&:hover": { + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral800, + }), + ...(contrastMode === "lowContrast" && { backgroundColor: odysseyTokens.HueNeutral50, + }), + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral600, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral200, + }), + "&:hover": { + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral800, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral50, + }), }, "&.Mui-focused": { borderColor: odysseyTokens.PalettePrimaryMain, @@ -2775,7 +2988,13 @@ export const components = ({ color: odysseyTokens.TypographyColorHeading, fontWeight: odysseyTokens.TypographyWeightBodyBold, textTransform: "uppercase", - backgroundColor: odysseyTokens.HueNeutral50, + + ...(contrastMode === "highContrast" && { + backgroundColor: odysseyTokens.HueNeutral800, + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.HueNeutral50, + }), borderBottom: 0, height: `${odysseyTokens.Spacing7} !important`, paddingBlock: `${odysseyTokens.Spacing3} !important`, @@ -2877,7 +3096,13 @@ export const components = ({ borderWidth: 1, borderRadius: 0, marginRight: 2, - borderColor: odysseyTokens.HueNeutral400, + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral400, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral400, + }), height: 18, }, @@ -3017,7 +3242,13 @@ export const components = ({ right: 0, top: 0, bottom: 0, - borderColor: odysseyTokens.HueNeutral200, + + ...(contrastMode === "highContrast" && { + borderColor: odysseyTokens.HueNeutral600, + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral200, + }), borderStyle: "dashed", borderWidth: 2, borderRadius: odysseyTokens.BorderRadiusOuter, diff --git a/packages/odyssey-react-mui/src/ui-shell/UiShell/UiShellContent.tsx b/packages/odyssey-react-mui/src/ui-shell/UiShell/UiShellContent.tsx index ac4a968dd3..67c1b7eb68 100644 --- a/packages/odyssey-react-mui/src/ui-shell/UiShell/UiShellContent.tsx +++ b/packages/odyssey-react-mui/src/ui-shell/UiShell/UiShellContent.tsx @@ -22,7 +22,7 @@ import { type DesignTokens, } from "../../OdysseyDesignTokensContext"; import { useScrollState } from "./useScrollState"; -import { ContrastMode } from "../../useContrastMode"; +import { ContrastMode, useContrastModeContext } from "../../useContrastMode"; const emptySideNavItems = [] satisfies SideNavProps["sideNavItems"]; @@ -40,7 +40,7 @@ const StyledAppContainer = styled("div", { paddingInline: odysseyDesignTokens.Spacing8, backgroundColor: appBackgroundContrastMode === "highContrast" - ? odysseyDesignTokens.HueNeutralWhite + ? "#252525" : odysseyDesignTokens.HueNeutral50, })); @@ -134,7 +134,7 @@ export type UiShellContentProps = { * If an error occurs, this will revert to only showing the app. */ const UiShellContent = ({ - appBackgroundContrastMode = "lowContrast", + appBackgroundContrastMode: propContrastMode = "lowContrast", appComponent, initialVisibleSections = ["TopNav", "SideNav", "AppSwitcher"], onError = console.error, @@ -145,6 +145,8 @@ const UiShellContent = ({ }: UiShellContentProps) => { const odysseyDesignTokens = useOdysseyDesignTokens(); const { isContentScrolled, scrollableContentRef } = useScrollState(); + const { contrastMode } = useContrastModeContext(); + const effectiveContrastMode = contrastMode || propContrastMode; return ( @@ -158,6 +160,8 @@ const UiShellContent = ({ initialVisibleSections?.includes("AppSwitcher") && !appSwitcherProps && ( + {" "} + appBackgroundContrastMode={effectiveContrastMode} ) @@ -223,7 +227,7 @@ const UiShellContent = ({ diff --git a/packages/odyssey-react-mui/src/useContrastMode.tsx b/packages/odyssey-react-mui/src/useContrastMode.tsx index dccfa30586..1152552c8d 100644 --- a/packages/odyssey-react-mui/src/useContrastMode.tsx +++ b/packages/odyssey-react-mui/src/useContrastMode.tsx @@ -18,7 +18,6 @@ import { useState, useCallback, } from "react"; -import * as Tokens from "@okta/odyssey-design-tokens"; export type ContrastMode = "lowContrast" | "highContrast"; export type ContrastModeContextType = { @@ -41,7 +40,7 @@ export const hexToRgb = (hexString: string) => { return `rgb(${red}, ${green}, ${blue})`; }; -export const hueNeutral50Rgb = hexToRgb(Tokens.HueNeutral50); +export const hueNeutral50Rgb = "#1d1d1d"; export const isTransparentColor = (color: string) => color === "rgba(0, 0, 0, 0)" || color === "transparent"; @@ -56,12 +55,10 @@ export const getElementComputedBackgroundColor = ( export const normalizeBackgroundColor = (bgColor: string): string => { if (/rgba\((\d+),\s*(\d+),\s*(\d+),\s*[\d.]+\)/.test(bgColor)) { const normalizedColor = normalizeRgbaToRgb(bgColor); - return normalizedColor === hueNeutral50Rgb - ? Tokens.HueNeutral50 - : normalizedColor; + return normalizedColor === hueNeutral50Rgb ? "#1d1d1d" : normalizedColor; } - return bgColor === hueNeutral50Rgb ? Tokens.HueNeutral50 : bgColor; + return bgColor === hueNeutral50Rgb ? "#1d1d1d" : bgColor; }; export const defaultParentBackgroundColor = "#ffffff"; @@ -110,7 +107,7 @@ export const useContrastMode = ({ if (!explicitContrastMode) { setContrastMode( - newBgColor === Tokens.HueNeutral50 ? "highContrast" : "lowContrast", + newBgColor === "rgb(29, 29, 29)" ? "highContrast" : "lowContrast", ); } }, [explicitContrastMode]); diff --git a/packages/odyssey-storybook/.storybook/preview.ts b/packages/odyssey-storybook/.storybook/preview.ts index 41003e310e..0e11810336 100644 --- a/packages/odyssey-storybook/.storybook/preview.ts +++ b/packages/odyssey-storybook/.storybook/preview.ts @@ -91,12 +91,12 @@ const preview: Preview = { backgrounds: { values: [ { - name: "White", + name: "Light mode", value: "#ffffff", }, { - name: "Gray", - value: "#f4f4f4", + name: "Dark Mode", + value: "#1d1d1d", }, ], }, From 97290e9d6c719ff57eb1417040c71cc69bc37292 Mon Sep 17 00:00:00 2001 From: benlister-okta Date: Thu, 5 Dec 2024 16:16:35 -0800 Subject: [PATCH 2/3] fix: updates --- packages/odyssey-react-mui/src/Typography.tsx | 2 + .../src/labs/AppSwitcher/AppSwitcher.tsx | 5 +- .../src/labs/AppSwitcher/AppSwitcherApp.tsx | 18 +- .../src/labs/SideNav/NavAccordion.tsx | 30 +- .../src/labs/SideNav/SideNav.tsx | 1 + .../src/labs/TopNav/UserProfile.tsx | 79 +++-- .../src/labs/TopNav/UserProfileMenuButton.tsx | 1 + .../src/theme/components.tsx | 297 +++++++++++------- .../src/ui-shell/UiShell/UiShellContent.tsx | 4 + .../odyssey-mui/DataTable/planetData.tsx | 2 +- .../UiShell/UiShell.stories.tsx | 294 +++++++++-------- 11 files changed, 433 insertions(+), 300 deletions(-) diff --git a/packages/odyssey-react-mui/src/Typography.tsx b/packages/odyssey-react-mui/src/Typography.tsx index 209dd6056c..bea93ec8a2 100644 --- a/packages/odyssey-react-mui/src/Typography.tsx +++ b/packages/odyssey-react-mui/src/Typography.tsx @@ -62,6 +62,8 @@ export const typographyColorValues = [ "secondary", "textSecondary", "error", + "white", + "#a0a0a0", ] as const; export type TypographyProps = { diff --git a/packages/odyssey-react-mui/src/labs/AppSwitcher/AppSwitcher.tsx b/packages/odyssey-react-mui/src/labs/AppSwitcher/AppSwitcher.tsx index 6b037b2099..96945dcfee 100644 --- a/packages/odyssey-react-mui/src/labs/AppSwitcher/AppSwitcher.tsx +++ b/packages/odyssey-react-mui/src/labs/AppSwitcher/AppSwitcher.tsx @@ -47,7 +47,10 @@ const AppSwitcherWrapperComponent = styled("nav", { : odysseyDesignTokens.HueNeutralWhite, borderInlineEndStyle: "solid", borderInlineEndWidth: odysseyDesignTokens.BorderWidthMain, - borderInlineEndColor: odysseyDesignTokens.BorderColorDisplay, + borderInlineEndColor: + contrastMode === "highContrast" + ? "#292930" + : odysseyDesignTokens.BorderColorDisplay, })); const AppSwitcherOktaAuraWrapperComponent = styled("div", { diff --git a/packages/odyssey-react-mui/src/labs/AppSwitcher/AppSwitcherApp.tsx b/packages/odyssey-react-mui/src/labs/AppSwitcher/AppSwitcherApp.tsx index a1794f62c5..9fcbb1bd69 100644 --- a/packages/odyssey-react-mui/src/labs/AppSwitcher/AppSwitcherApp.tsx +++ b/packages/odyssey-react-mui/src/labs/AppSwitcher/AppSwitcherApp.tsx @@ -17,6 +17,7 @@ import { DesignTokens, useOdysseyDesignTokens, } from "../../OdysseyDesignTokensContext"; +import { ContrastMode, useContrastModeContext } from "../../useContrastMode"; import { Tooltip } from "../../Tooltip"; import { MuiPropsContext, MuiPropsContextType } from "../../MuiPropsContext"; @@ -30,26 +31,32 @@ const AppSwitcherAppWrapperComponent = styled("li", { const AppSwitcherAppLinkComponent = styled("a", { shouldForwardProp: (prop) => - !["odysseyDesignTokens", "isSelected"].includes(prop), + !["odysseyDesignTokens", "isSelected", "contrastMode"].includes(prop), })( ({ odysseyDesignTokens, isSelected, + contrastMode, }: { odysseyDesignTokens: DesignTokens; isSelected: boolean; + contrastMode: ContrastMode; }) => ({ display: "inline-block", margin: "auto", padding: odysseyDesignTokens.Spacing1, backgroundColor: isSelected - ? odysseyDesignTokens.PalettePrimaryLighter + ? contrastMode === "highContrast" + ? "#292930" + : odysseyDesignTokens.PalettePrimaryLighter : "transparent", borderRadius: odysseyDesignTokens.BorderRadiusTight, transition: `background-color ${odysseyDesignTokens.TransitionDurationMain}`, - "&:hover, &:focus": { - backgroundColor: odysseyDesignTokens.HueNeutral50, + backgroundColor: + contrastMode === "highContrast" + ? "#252525" + : odysseyDesignTokens.HueNeutral50, }, }), ); @@ -93,6 +100,7 @@ export const AppSwitcherApp = ({ }: AppSwitcherAppProps) => { const odysseyDesignTokens = useOdysseyDesignTokens(); const isSelected = appName === selectedAppName; + const { contrastMode } = useContrastModeContext(); const renderAppIconLink = useCallback( (muiProps: MuiPropsContextType) => ( @@ -100,6 +108,7 @@ export const AppSwitcherApp = ({ {...muiProps} odysseyDesignTokens={odysseyDesignTokens} isSelected={isSelected} + contrastMode={contrastMode} href={linkUrl} aria-current={isSelected ? "page" : undefined} > @@ -116,6 +125,7 @@ export const AppSwitcherApp = ({ linkUrl, appIconDefaultUrl, appIconSelectedUrl, + contrastMode, ], ); diff --git a/packages/odyssey-react-mui/src/labs/SideNav/NavAccordion.tsx b/packages/odyssey-react-mui/src/labs/SideNav/NavAccordion.tsx index f2ccc34162..c09358289b 100644 --- a/packages/odyssey-react-mui/src/labs/SideNav/NavAccordion.tsx +++ b/packages/odyssey-react-mui/src/labs/SideNav/NavAccordion.tsx @@ -25,10 +25,12 @@ import { DesignTokens, useOdysseyDesignTokens, } from "../../OdysseyDesignTokensContext"; +import { ContrastMode } from "../../useContrastMode"; import { Support } from "../../Typography"; import { useUniqueId } from "../../useUniqueId"; export type NavAccordionProps = { + contrastMode: ContrastMode; /** * The label text for the AccordionSummary */ @@ -66,31 +68,39 @@ export type NavAccordionProps = { const AccordionLabelContainer = styled("span", { shouldForwardProp: (prop) => - prop !== "odysseyDesignTokens" && prop !== "isIconVisible", + prop !== "odysseyDesignTokens" && + prop !== "isIconVisible" && + prop !== "contrastMode", })<{ odysseyDesignTokens: DesignTokens; isIconVisible: boolean; -}>(({ odysseyDesignTokens, isIconVisible }) => ({ + contrastMode: ContrastMode; +}>(({ odysseyDesignTokens, isIconVisible, contrastMode }) => ({ width: "100%", marginInlineStart: isIconVisible ? odysseyDesignTokens.Spacing3 : 0, fontWeight: odysseyDesignTokens.TypographyWeightHeading, - color: odysseyDesignTokens.TypographyColorHeading, + color: + contrastMode === "highContrast" + ? "#ffffff" + : odysseyDesignTokens.TypographyColorHeading, })); const AccordionSummaryContainer = styled(MuiAccordionSummary, { shouldForwardProp: (prop) => prop !== "odysseyDesignTokens" && prop !== "isCompact" && - prop !== "isDisabled", + prop !== "isDisabled" && + prop !== "contrastMode", })<{ odysseyDesignTokens: DesignTokens; isCompact?: boolean; isDisabled?: boolean; -}>(({ odysseyDesignTokens, isCompact, isDisabled }) => ({ + contrastMode: ContrastMode; +}>(({ odysseyDesignTokens, isCompact, isDisabled, contrastMode }) => ({ borderRadius: odysseyDesignTokens.BorderRadiusMain, + paddingBlock: odysseyDesignTokens.Spacing3, paddingInline: odysseyDesignTokens.Spacing4, - "&:focus-visible": { backgroundColor: "unset", outline: "none", @@ -104,7 +114,10 @@ const AccordionSummaryContainer = styled(MuiAccordionSummary, { ...(!isDisabled && { "&:hover": { - backgroundColor: odysseyDesignTokens.HueNeutral50, + backgroundColor: + contrastMode === "highContrast" + ? "#252525" + : odysseyDesignTokens.HueNeutral50, }, }), })); @@ -119,6 +132,7 @@ const NavAccordion = ({ isExpanded, translate, startIcon, + contrastMode, }: PropsWithChildren) => { const id = useUniqueId(idOverride); const headerId = `${id}-header`; @@ -136,6 +150,7 @@ const NavAccordion = ({ } id={headerId} odysseyDesignTokens={odysseyDesignTokens} @@ -147,6 +162,7 @@ const NavAccordion = ({ {label} diff --git a/packages/odyssey-react-mui/src/labs/SideNav/SideNav.tsx b/packages/odyssey-react-mui/src/labs/SideNav/SideNav.tsx index 00961fd024..94efda8db0 100644 --- a/packages/odyssey-react-mui/src/labs/SideNav/SideNav.tsx +++ b/packages/odyssey-react-mui/src/labs/SideNav/SideNav.tsx @@ -631,6 +631,7 @@ const SideNav = ({ prop !== "odysseyDesignTokens", -})(({ odysseyDesignTokens }: { odysseyDesignTokens: DesignTokens }) => ({ + shouldForwardProp: (prop) => + prop !== "odysseyDesignTokens" && prop !== "contrastMode", +})<{ + odysseyDesignTokens: DesignTokens; + contrastMode: ContrastMode; +}>(({ odysseyDesignTokens, contrastMode }) => ({ display: "flex", alignItems: "center", paddingInlineEnd: odysseyDesignTokens.Spacing4, + color: contrastMode === "highContrast" ? "#ffffff" : "inherit", })); const UserProfileIconContainer = styled("div", { - shouldForwardProp: (prop) => prop !== "odysseyDesignTokens", -})(({ odysseyDesignTokens }: { odysseyDesignTokens: DesignTokens }) => ({ + shouldForwardProp: (prop) => + prop !== "odysseyDesignTokens" && prop !== "contrastMode", +})<{ + odysseyDesignTokens: DesignTokens; + contrastMode: ContrastMode; +}>(({ odysseyDesignTokens, contrastMode }) => ({ display: "flex", paddingInlineEnd: odysseyDesignTokens.Spacing2, + color: contrastMode === "highContrast" ? "#ffffff" : "inherit", })); -const UserProfileInfoContainer = styled("div")(() => ({ +const UserProfileInfoContainer = styled("div", { + shouldForwardProp: (prop) => + prop !== "odysseyDesignTokens" && prop !== "contrastMode", +})<{ + odysseyDesignTokens: DesignTokens; + contrastMode: ContrastMode; +}>(({ odysseyDesignTokens, contrastMode }) => ({ display: "flex", flexDirection: "column", textAlign: "left", + color: + contrastMode === "highContrast" + ? odysseyDesignTokens.HueNeutralWhite + : "inherit", })); +// Update props type export type UserProfileProps = { - /** - * Logged in user profile icon to be displayed in the top nav - */ + contrastMode: ContrastMode; // Add this profileIcon?: ReactElement; - /** - * Logged in user info to be displayed in the top nav - */ userName: string; - /** - * Org name of the logged in user - */ orgName: string; - /** - * The icon element to display after the username - */ userNameEndIcon?: ReactElement; }; @@ -65,18 +76,28 @@ const UserProfile = ({ userName, orgName, userNameEndIcon, + contrastMode, // Add this }: UserProfileProps) => { const odysseyDesignTokens = useOdysseyDesignTokens(); return ( - + {profileIcon && ( - + {profileIcon} )} - + {userNameEndIcon ? ( - {userName} + + {userName} + {userNameEndIcon} ) : ( - {userName} + + {userName} + )} - {orgName} + + {orgName} + ); diff --git a/packages/odyssey-react-mui/src/labs/TopNav/UserProfileMenuButton.tsx b/packages/odyssey-react-mui/src/labs/TopNav/UserProfileMenuButton.tsx index e808f61f02..d2aa4066d7 100644 --- a/packages/odyssey-react-mui/src/labs/TopNav/UserProfileMenuButton.tsx +++ b/packages/odyssey-react-mui/src/labs/TopNav/UserProfileMenuButton.tsx @@ -44,6 +44,7 @@ const UserProfileMenuButton = (props: UserProfileMenuButtonProps) => { profileIcon={profileIcon} userName={userName} orgName={orgName} + contrastMode={"highContrast"} userNameEndIcon={userNameEndIcon ?? } /> } diff --git a/packages/odyssey-react-mui/src/theme/components.tsx b/packages/odyssey-react-mui/src/theme/components.tsx index 72ee3aee39..318c90f29c 100644 --- a/packages/odyssey-react-mui/src/theme/components.tsx +++ b/packages/odyssey-react-mui/src/theme/components.tsx @@ -88,12 +88,12 @@ export const components = ({ boxShadow: "none", "&.Mui-disabled": { - ...(contrastMode === "highContrast" && { - backgroundColor: odysseyTokens.HueNeutral900, - }), - ...(contrastMode === "lowContrast" && { - backgroundColor: odysseyTokens.HueNeutralWhite, - }), + // ...(contrastMode === "highContrast" && { + // backgroundColor: odysseyTokens.HueNeutral900, + // }), + // ...(contrastMode === "lowContrast" && { + // backgroundColor: odysseyTokens.HueNeutralWhite, + // }), color: odysseyTokens.TypographyColorDisabled, cursor: "default", @@ -715,14 +715,14 @@ export const components = ({ ...(ownerState.variant === "secondary" && { backgroundColor: "transparent", - ...(contrastMode === "highContrast" && { borderColor: odysseyTokens.HueNeutral500, + color: odysseyTokens.HueNeutralWhite, }), ...(contrastMode === "lowContrast" && { borderColor: odysseyTokens.HueNeutral300, + color: odysseyTokens.TypographyColorBody, }), - color: odysseyTokens.TypographyColorBody, "&:hover": { ...(contrastMode === "highContrast" && { @@ -2902,6 +2902,7 @@ export const components = ({ marginBlock: odysseyTokens.Spacing0, marginInline: odysseyTokens.Spacing0, lineHeight: odysseyTokens.TypographyLineHeightUi, + backgroundColor: odysseyTokens.HueNeutral900, "&.narrow": { width: "100%", @@ -2939,6 +2940,17 @@ export const components = ({ position: "relative", overflowWrap: "break-word", + ...(contrastMode === "highContrast" && { + color: "#ffffff !important", // Force white text in dark mode + backgroundColor: "transparent !important", // Ensure it doesn't interfere with background + "& *": { + color: "#ffffff !important", // Ensure child elements inherit white text + }, + }), + ...(contrastMode === "lowContrast" && { + color: odysseyTokens.TypographyColorBody, // Default light mode color + }), + [`&.${tableCellClasses.root}`]: { borderTop: `none !important`, borderBottom: `none !important`, @@ -3138,141 +3150,204 @@ export const components = ({ }, MuiTableRow: { styleOverrides: { - root: () => ({ - borderTop: `${odysseyTokens.BorderWidthMain} ${odysseyTokens.BorderStyleMain} ${odysseyTokens.HueNeutral100}`, - transition: "none !important", - verticalAlign: "unset", + root: ({}) => { + return { + borderTop: `${odysseyTokens.BorderWidthMain} ${odysseyTokens.BorderStyleMain} ${ + contrastMode === "highContrast" + ? "#313231" + : odysseyTokens.HueNeutral100 + } !important`, + transition: "none !important", + verticalAlign: "unset", + + // Adding specificity by nesting classes or using attributes + "&.MuiTableRow-root": { + ...(contrastMode === "highContrast" && { + backgroundColor: "#1d1d1d !important", // High contrast background + color: "#ffffff !important", // High contrast text + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: "rgb(255, 255, 255) !important", // Default light mode background + }), + }, + "&:hover.MuiTableRow-root": { + ...(contrastMode === "highContrast" && { + backgroundColor: "#313231 !important", // High contrast hover + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: `${odysseyTokens.HueNeutral50} !important`, + }), + }, + ...(contrastMode === "highContrast" && { + backgroundColor: "#252525 !important", // Force dark mode background + color: "#ffffff !important", // Force white text color + }), + ...(contrastMode === "lowContrast" && + { + // Default light mode styles + }), - [`&:hover`]: { - backgroundColor: `${odysseyTokens.HueNeutral50} !important`, - }, + [`&:hover`]: { + ...(contrastMode === "highContrast" && { + backgroundColor: "#313231 !important", // Dark mode hover + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: `${odysseyTokens.HueNeutral50} !important`, + }), + }, - [`&:first-of-type`]: { - borderTopColor: odysseyTokens.HueNeutralWhite, - }, + [`&:first-of-type`]: { + ...(contrastMode === "highContrast" && { + borderTopColor: "#252525 !important", // Match dark mode background + }), + ...(contrastMode === "lowContrast" && { + borderTopColor: odysseyTokens.HueNeutralWhite, + }), + }, - [`&.${tableRowClasses.selected}`]: { - backgroundColor: `${odysseyTokens.PalettePrimaryLighter} !important`, + [`&.${tableRowClasses.selected}`]: { + ...(contrastMode === "highContrast" && { + backgroundColor: "#313231 !important", + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: `${odysseyTokens.PalettePrimaryLighter} !important`, + }), - "&:hover": { - backgroundColor: `${odysseyTokens.PalettePrimaryLighter} !important`, - }, + "&:hover": { + ...(contrastMode === "highContrast" && { + backgroundColor: "#313231 !important", + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: `${odysseyTokens.PalettePrimaryLighter} !important`, + }), + }, - [`&:hover + .${tableRowClasses.root}`]: { - borderTopColor: odysseyTokens.PalettePrimaryMain, + [`&:hover + .${tableRowClasses.root}`]: { + ...(contrastMode === "highContrast" && { + borderTopColor: "#252525 !important", + }), + ...(contrastMode === "lowContrast" && { + borderTopColor: odysseyTokens.PalettePrimaryMain, + }), + }, }, - }, - [`.${tableRowClasses.selected} + &`]: { - borderTopColor: odysseyTokens.PalettePrimaryLight, - }, - [`&.${tableRowClasses.head}`]: { - boxShadow: "none !important", - borderBottom: 0, - "&:hover, &:focus-within": { - backgroundColor: "transparent !important", + [`.${tableRowClasses.selected} + &`]: { + ...(contrastMode === "highContrast" && { + borderTopColor: "#252525 !important", + }), + ...(contrastMode === "lowContrast" && { + borderTopColor: odysseyTokens.PalettePrimaryLight, + }), }, - }, + [`&.${tableRowClasses.head}`]: { + border: "0 !important", // No border + ...(contrastMode === "highContrast" && { + backgroundColor: "#252525 !important", // High contrast header background + color: "#ffffff !important", // High contrast header text + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: "rgb(244, 244, 244) !important", // Light mode header background + color: "inherit !important", // Default light mode text + }), - [`.${tableBodyClasses.root} &`]: { - // Target is 48px height - paddingBlock: odysseyTokens.Spacing3, + [`&:hover`]: { + ...(contrastMode === "highContrast" && { + backgroundColor: "#313231 !important", // High contrast header hover + color: "#ffffff !important", // High contrast hover text + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: "rgb(244, 244, 244) !important !important", // Light mode header hover + color: "inherit !important", // Default light mode hover text + }), + }, + }, - [`& .${tableCellClasses.root}::after`]: { - top: `-${odysseyTokens.Spacing3} !important`, - bottom: `-${odysseyTokens.Spacing3} !important`, + // Adjust row padding for table body + [`.${tableBodyClasses.root} &`]: { + paddingBlock: odysseyTokens.Spacing3, + [`& .${tableCellClasses.root}::after`]: { + top: `-${odysseyTokens.Spacing3} !important`, + bottom: `-${odysseyTokens.Spacing3} !important`, + }, }, - }, - [`.${tableBodyClasses.root}.MuiTableBody-compact &`]: { - // Target is 36px height - paddingBlock: odysseyTokens.Spacing2, + [`.${tableBodyClasses.root}.MuiTableBody-compact &`]: { + paddingBlock: odysseyTokens.Spacing2, + [`& .${tableCellClasses.root}::after`]: { + top: `-${odysseyTokens.Spacing2} !important`, + bottom: `-${odysseyTokens.Spacing2} !important`, + }, + }, - [`& .${tableCellClasses.root}::after`]: { - top: `-${odysseyTokens.Spacing2} !important`, - bottom: `-${odysseyTokens.Spacing2} !important`, + [`.${tableBodyClasses.root}.MuiTableBody-spacious &`]: { + paddingBlock: odysseyTokens.Spacing4, + [`& .${tableCellClasses.root}::after`]: { + top: `-${odysseyTokens.Spacing4} !important`, + bottom: `-${odysseyTokens.Spacing4} !important`, + }, }, - }, - [`.${tableBodyClasses.root}.MuiTableBody-spacious &`]: { - // Target is 56px height - paddingBlock: odysseyTokens.Spacing4, + "&.isDragTarget": { + opacity: 1, + position: "relative", + ...(contrastMode === "highContrast" && { + backgroundColor: "#252525 !important", + }), + ...(contrastMode === "lowContrast" && { + backgroundColor: odysseyTokens.PalettePrimaryMain, + }), + borderRadius: odysseyTokens.BorderRadiusOuter, + + [`& td.${tableCellClasses.root}`]: { + border: "0 !important", + }, - [`& .${tableCellClasses.root}::after`]: { - top: `-${odysseyTokens.Spacing4} !important`, - bottom: `-${odysseyTokens.Spacing4} !important`, + "&::after": { + content: '""', + position: "absolute", + left: 0, + right: 0, + top: 0, + bottom: 0, + ...(contrastMode === "highContrast" && { + borderColor: "#313231 !important", + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.PalettePrimaryLight, + }), + borderStyle: "dashed", + borderWidth: 2, + borderRadius: odysseyTokens.BorderRadiusOuter, + }, }, - }, - "&.isDragTarget": { - opacity: 1, - position: "relative", - backgroundColor: odysseyTokens.PalettePrimaryMain, - borderRadius: odysseyTokens.BorderRadiusOuter, - - [`& td.${tableCellClasses.root}`]: { - borderTop: "0 !important", - borderRight: "0 !important", - borderBottom: "0 !important", - borderLeft: "0 !important", + "&.isDragging": { + borderRadius: odysseyTokens.BorderRadiusOuter, }, - "&::after": { + "&.isDragging::after": { content: '""', position: "absolute", left: 0, right: 0, top: 0, bottom: 0, - borderColor: odysseyTokens.PalettePrimaryLight, + ...(contrastMode === "highContrast" && { + borderColor: "#313231 !important", + }), + ...(contrastMode === "lowContrast" && { + borderColor: odysseyTokens.HueNeutral200, + }), borderStyle: "dashed", borderWidth: 2, borderRadius: odysseyTokens.BorderRadiusOuter, }, - }, - - "&.isDragging": { - borderRadius: odysseyTokens.BorderRadiusOuter, - }, - - "&.isDragging::after": { - content: '""', - position: "absolute", - left: 0, - right: 0, - top: 0, - bottom: 0, - - ...(contrastMode === "highContrast" && { - borderColor: odysseyTokens.HueNeutral600, - }), - ...(contrastMode === "lowContrast" && { - borderColor: odysseyTokens.HueNeutral200, - }), - borderStyle: "dashed", - borderWidth: 2, - borderRadius: odysseyTokens.BorderRadiusOuter, - }, - - "&.isDragging, &.isDragging.isDragTarget": { - position: "relative", - opacity: 1, - backgroundColor: "transparent", - }, - - "&.isDragging.isDragTarget::after": { - borderColor: odysseyTokens.PalettePrimaryLight, - left: 0, - right: 0, - }, - - [`&.isDragging + .${tableRowClasses.root}, &.isDragTarget + .${tableRowClasses.root}`]: - { - borderTopColor: "transparent", - }, - }), + }; + }, }, }, + MuiTableSortLabel: { styleOverrides: { root: { diff --git a/packages/odyssey-react-mui/src/ui-shell/UiShell/UiShellContent.tsx b/packages/odyssey-react-mui/src/ui-shell/UiShell/UiShellContent.tsx index 67c1b7eb68..d598dfc980 100644 --- a/packages/odyssey-react-mui/src/ui-shell/UiShell/UiShellContent.tsx +++ b/packages/odyssey-react-mui/src/ui-shell/UiShell/UiShellContent.tsx @@ -38,6 +38,10 @@ const StyledAppContainer = styled("div", { overflowY: "auto", paddingBlock: odysseyDesignTokens.Spacing5, paddingInline: odysseyDesignTokens.Spacing8, + color: + appBackgroundContrastMode === "highContrast" + ? "#ffffff" + : odysseyDesignTokens.HueNeutral900, backgroundColor: appBackgroundContrastMode === "highContrast" ? "#252525" diff --git a/packages/odyssey-storybook/src/components/odyssey-mui/DataTable/planetData.tsx b/packages/odyssey-storybook/src/components/odyssey-mui/DataTable/planetData.tsx index 7907b15ca9..18faa80f23 100644 --- a/packages/odyssey-storybook/src/components/odyssey-mui/DataTable/planetData.tsx +++ b/packages/odyssey-storybook/src/components/odyssey-mui/DataTable/planetData.tsx @@ -34,7 +34,7 @@ export const columns: DataTableColumn[] = [ }, { accessorKey: "distance", - header: "Distance from Sun (AU)", + header: "Distance to Sun", }, { accessorKey: "visit", diff --git a/packages/odyssey-storybook/src/components/odyssey-ui-shell/UiShell/UiShell.stories.tsx b/packages/odyssey-storybook/src/components/odyssey-ui-shell/UiShell/UiShell.stories.tsx index 7d088da3d8..b47a6e95ee 100644 --- a/packages/odyssey-storybook/src/components/odyssey-ui-shell/UiShell/UiShell.stories.tsx +++ b/packages/odyssey-storybook/src/components/odyssey-ui-shell/UiShell/UiShell.stories.tsx @@ -17,7 +17,7 @@ import { Button, OdysseyProvider, Paragraph, - SearchField, + // SearchField, Surface, } from "@okta/odyssey-react-mui"; import { PageTemplate, UserProfile } from "@okta/odyssey-react-mui/labs"; @@ -27,12 +27,99 @@ import { type UiShellNavComponentProps, type UiShellProps, } from "@okta/odyssey-react-mui/ui-shell"; +import { DataTable } from "@okta/odyssey-react-mui"; +import { + columns as planetColumns, + data as planetData, +} from "../../odyssey-mui/DataTable/planetData"; +import { + DataTableGetDataType, + DataTableOnReorderRowsType, +} from "@okta/odyssey-react-mui/labs"; +import { Planet } from "../../odyssey-mui/DataTable/planetData"; +import { Person } from "../../odyssey-mui/DataTable/personData"; import { AddCircleIcon, - HomeIcon, + // HomeIcon, UserIcon, } from "@okta/odyssey-react-mui/icons"; +const filterData = ({ + data, + ...args +}: { + data: (Planet | Person)[]; +} & DataTableGetDataType) => { + let filteredData = data; + const { search, filters, sort, page = 1, resultsPerPage = 20 } = args; + + if (search) { + filteredData = filteredData.filter((row) => + Object.values(row).some((value) => + value.toString().toLowerCase().includes(search.toLowerCase()), + ), + ); + } + + if (filters) { + filteredData = filteredData.filter((row) => { + return filters.every(({ id, value }) => { + if (value === null || value === undefined) { + return true; + } + if (Array.isArray(value)) { + return value.some((arrayValue) => + row[id as keyof (Planet | Person)] + ?.toString() + .toLowerCase() + .includes(arrayValue.toString().toLowerCase()), + ); + } + return row[id as keyof (Planet | Person)] + ?.toString() + .toLowerCase() + .includes(value.toString().toLowerCase()); + }); + }); + } + + if (sort && sort.length > 0) { + filteredData.sort((a, b) => { + for (const { id, desc } of sort) { + const aValue = a[id as keyof (Planet | Person)]; + const bValue = b[id as keyof (Planet | Person)]; + if (aValue < bValue) return desc ? 1 : -1; + if (aValue > bValue) return desc ? -1 : 1; + } + return 0; + }); + } + + const startRow = (page - 1) * resultsPerPage; + const endRow = startRow + resultsPerPage; + filteredData = filteredData.slice(startRow, endRow); + + return filteredData; +}; + +const reorderData = ({ + data, + ...args +}: { + data: T[]; +} & DataTableOnReorderRowsType) => { + const updatedData = data; + const { rowId, newRowIndex } = args; + const rowIndex = updatedData.findIndex((row) => row.id === rowId); + + if (rowIndex !== -1) { + const [removedRow] = updatedData.splice(rowIndex, 1); + updatedData.splice(newRowIndex, 0, removedRow); + } + + return updatedData; +}; + const storybookMeta: Meta = { title: "UI Shell Components/UI Shell", component: UiShell, @@ -162,7 +249,7 @@ const sharedSideNavProps: UiShellNavComponentProps["sideNavProps"] = { { id: "item1", label: "Dashboard", - startIcon: , + // startIcon: , isDisabled: true, nestedNavItems: [ { @@ -203,13 +290,16 @@ const sharedTopNavProps: UiShellNavComponentProps["topNavProps"] = { const sharedOptionalComponents: UiShellProps["optionalComponents"] = { topNavLeftSide: ( -
- -
+
{/* */}
), topNavRightSide: ( } + contrastMode={ + window.location.href.includes("backgrounds.value:!hex(1d1d1d)") + ? "highContrast" + : "lowContrast" + } orgName="ORG123" userName="test.user@test.com" /> @@ -303,155 +393,53 @@ export const WithoutAppContent: StoryObj = { }, }; -export const WithTallAppContent: StoryObj = { +export const HackweekTableExample: StoryObj = { args: { appComponent: ( -
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris lacinia - leo quis sodales scelerisque. Maecenas tempor eget nunc sit amet - ultrices. Maecenas et varius ante. Nulla eu quam sit amet orci fermentum - dictum sit amet scelerisque libero. Proin luctus semper elit, ut pretium - massa tristique a. Mauris hendrerit ex eu commodo egestas. Etiam a lacus - aliquet, convallis metus et, sollicitudin odio. Fusce vehicula purus sed - orci elementum, ut cursus diam sollicitudin. Pellentesque pulvinar nibh - turpis, eu finibus dolor egestas eget. Duis tellus mauris, pulvinar sit - amet ante a, aliquet laoreet sapien. Ut quis tempus massa. Fusce - fringilla mattis lacinia. Cras at pharetra quam, eu ultrices ipsum. - Etiam malesuada, ex consectetur fringilla faucibus, quam lorem luctus - diam, vitae lobortis urna lorem ac libero. Nulla a fermentum ligula, ut - pulvinar odio. Cras in dictum nibh. Ut et orci sodales, laoreet sem nec, - volutpat sapien. Phasellus dui turpis, euismod vitae euismod porta, - semper a tellus. Morbi bibendum eros quam, et suscipit ex blandit eu. - Etiam placerat, tellus viverra rutrum porttitor, elit arcu molestie - nibh, at porta arcu odio ut neque. Donec id odio ut neque malesuada - pulvinar a in tortor. Fusce eu urna lobortis, rhoncus odio nec, - scelerisque dolor. Donec tempor eros sed condimentum rutrum. Vivamus ac - odio ac erat bibendum ultricies. Cras nec libero sit amet leo luctus - gravida. Praesent placerat massa ex. Donec vehicula orci ac consequat - mollis. Sed vitae magna ligula. Nulla pulvinar lectus ex, sed varius - enim pulvinar vel. Morbi viverra vitae dui sit amet mattis. Phasellus - quis augue viverra, rhoncus tellus non, elementum massa. Donec posuere - luctus ultrices. Ut eu massa sem. Aliquam sed mattis nulla, ac fermentum - magna. Vestibulum ac ex ut massa molestie gravida. Cras est arcu, varius - nec fringilla semper, aliquet id nunc. Quisque facilisis, nulla nec - ornare vehicula, justo urna feugiat lorem, nec pretium odio nisl - facilisis diam. Sed a quam in risus semper convallis sed eget mauris. - Proin vitae purus augue. Ut et risus justo. Mauris porta, leo non - vestibulum cursus, ante nisi sagittis magna, et convallis enim arcu a - diam. Ut tincidunt urna ac massa consectetur euismod. Aenean sagittis - nisi mi, eu bibendum arcu auctor at. Sed et urna sit amet sapien euismod - vulputate molestie eu ipsum. Phasellus mattis semper neque, et porttitor - mi scelerisque eget. Donec non egestas ex, ac consequat nunc. Nunc sed - risus ac orci ullamcorper lacinia vel at risus. Nulla et odio eros. - Vivamus tempor ultricies mi sed luctus. Duis faucibus sollicitudin odio, - quis rhoncus orci volutpat nec. Vivamus id eros et est aliquam - porttitor. Maecenas maximus magna sed est condimentum hendrerit. Integer - fringilla posuere nisl, vitae molestie magna dictum id. Suspendisse - volutpat pharetra mauris, sed vehicula nulla suscipit a. Morbi sed augue - sodales, molestie purus et, egestas enim. Proin ut metus tempus, - ultricies neque vel, vulputate lectus. Lorem ipsum dolor sit amet, - consectetur adipiscing elit. Mauris lacinia leo quis sodales - scelerisque. Maecenas tempor eget nunc sit amet ultrices. Maecenas et - varius ante. Nulla eu quam sit amet orci fermentum dictum sit amet - scelerisque libero. Proin luctus semper elit, ut pretium massa tristique - a. Mauris hendrerit ex eu commodo egestas. Etiam a lacus aliquet, - convallis metus et, sollicitudin odio. Fusce vehicula purus sed orci - elementum, ut cursus diam sollicitudin. Pellentesque pulvinar nibh - turpis, eu finibus dolor egestas eget. Duis tellus mauris, pulvinar sit - amet ante a, aliquet laoreet sapien. Ut quis tempus massa. Fusce - fringilla mattis lacinia. Cras at pharetra quam, eu ultrices ipsum. - Etiam malesuada, ex consectetur fringilla faucibus, quam lorem luctus - diam, vitae lobortis urna lorem ac libero. Nulla a fermentum ligula, ut - pulvinar odio. Cras in dictum nibh. Ut et orci sodales, laoreet sem nec, - volutpat sapien. Phasellus dui turpis, euismod vitae euismod porta, - semper a tellus. Morbi bibendum eros quam, et suscipit ex blandit eu. - Etiam placerat, tellus viverra rutrum porttitor, elit arcu molestie - nibh, at porta arcu odio ut neque. Donec id odio ut neque malesuada - pulvinar a in tortor. Fusce eu urna lobortis, rhoncus odio nec, - scelerisque dolor. Donec tempor eros sed condimentum rutrum. Vivamus ac - odio ac erat bibendum ultricies. Cras nec libero sit amet leo luctus - gravida. Praesent placerat massa ex. Donec vehicula orci ac consequat - mollis. Sed vitae magna ligula. Nulla pulvinar lectus ex, sed varius - enim pulvinar vel. Morbi viverra vitae dui sit amet mattis. Phasellus - quis augue viverra, rhoncus tellus non, elementum massa. Donec posuere - luctus ultrices. Ut eu massa sem. Aliquam sed mattis nulla, ac fermentum - magna. Vestibulum ac ex ut massa molestie gravida. Cras est arcu, varius - nec fringilla semper, aliquet id nunc. Quisque facilisis, nulla nec - ornare vehicula, justo urna feugiat lorem, nec pretium odio nisl - facilisis diam. Sed a quam in risus semper convallis sed eget mauris. - Proin vitae purus augue. Ut et risus justo. Mauris porta, leo non - vestibulum cursus, ante nisi sagittis magna, et convallis enim arcu a - diam. Ut tincidunt urna ac massa consectetur euismod. Aenean sagittis - nisi mi, eu bibendum arcu auctor at. Sed et urna sit amet sapien euismod - vulputate molestie eu ipsum. Phasellus mattis semper neque, et porttitor - mi scelerisque eget. Donec non egestas ex, ac consequat nunc. Nunc sed - risus ac orci ullamcorper lacinia vel at risus. Nulla et odio eros. - Vivamus tempor ultricies mi sed luctus. Duis faucibus sollicitudin odio, - quis rhoncus orci volutpat nec. Vivamus id eros et est aliquam - porttitor. Maecenas maximus magna sed est condimentum hendrerit. Integer - fringilla posuere nisl, vitae molestie magna dictum id. Suspendisse - volutpat pharetra mauris, sed vehicula nulla suscipit a. Morbi sed augue - sodales, molestie purus et, egestas enim. Proin ut metus tempus, - ultricies neque vel, vulputate lectus. Lorem ipsum dolor sit amet, - consectetur adipiscing elit. Mauris lacinia leo quis sodales - scelerisque. Maecenas tempor eget nunc sit amet ultrices. Maecenas et - varius ante. Nulla eu quam sit amet orci fermentum dictum sit amet - scelerisque libero. Proin luctus semper elit, ut pretium massa tristique - a. Mauris hendrerit ex eu commodo egestas. Etiam a lacus aliquet, - convallis metus et, sollicitudin odio. Fusce vehicula purus sed orci - elementum, ut cursus diam sollicitudin. Pellentesque pulvinar nibh - turpis, eu finibus dolor egestas eget. Duis tellus mauris, pulvinar sit - amet ante a, aliquet laoreet sapien. Ut quis tempus massa. Fusce - fringilla mattis lacinia. Cras at pharetra quam, eu ultrices ipsum. - Etiam malesuada, ex consectetur fringilla faucibus, quam lorem luctus - diam, vitae lobortis urna lorem ac libero. Nulla a fermentum ligula, ut - pulvinar odio. Cras in dictum nibh. Ut et orci sodales, laoreet sem nec, - volutpat sapien. Phasellus dui turpis, euismod vitae euismod porta, - semper a tellus. Morbi bibendum eros quam, et suscipit ex blandit eu. - Etiam placerat, tellus viverra rutrum porttitor, elit arcu molestie - nibh, at porta arcu odio ut neque. Donec id odio ut neque malesuada - pulvinar a in tortor. Fusce eu urna lobortis, rhoncus odio nec, - scelerisque dolor. Donec tempor eros sed condimentum rutrum. Vivamus ac - odio ac erat bibendum ultricies. Cras nec libero sit amet leo luctus - gravida. Praesent placerat massa ex. Donec vehicula orci ac consequat - mollis. Sed vitae magna ligula. Nulla pulvinar lectus ex, sed varius - enim pulvinar vel. Morbi viverra vitae dui sit amet mattis. Phasellus - quis augue viverra, rhoncus tellus non, elementum massa. Donec posuere - luctus ultrices. Ut eu massa sem. Aliquam sed mattis nulla, ac fermentum - magna. Vestibulum ac ex ut massa molestie gravida. Cras est arcu, varius - nec fringilla semper, aliquet id nunc. Quisque facilisis, nulla nec - ornare vehicula, justo urna feugiat lorem, nec pretium odio nisl - facilisis diam. Sed a quam in risus semper convallis sed eget mauris. - Proin vitae purus augue. Ut et risus justo. Mauris porta, leo non - vestibulum cursus, ante nisi sagittis magna, et convallis enim arcu a - diam. Ut tincidunt urna ac massa consectetur euismod. Aenean sagittis - nisi mi, eu bibendum arcu auctor at. Sed et urna sit amet sapien euismod - vulputate molestie eu ipsum. Phasellus mattis semper neque, et porttitor - mi scelerisque eget. Donec non egestas ex, ac consequat nunc. Nunc sed - risus ac orci ullamcorper lacinia vel at risus. Nulla et odio eros. - Vivamus tempor ultricies mi sed luctus. Duis faucibus sollicitudin odio, - quis rhoncus orci volutpat nec. Vivamus id eros et est aliquam - porttitor. Maecenas maximus magna sed est condimentum hendrerit. Integer - fringilla posuere nisl, vitae molestie magna dictum id. Suspendisse - volutpat pharetra mauris, sed vehicula nulla suscipit a. Morbi sed augue - sodales, molestie purus et, egestas enim. Proin ut metus tempus, - ultricies neque vel, vulputate lectus. Lorem ipsum dolor sit amet, - consectetur adipiscing elit. Mauris lacinia leo quis sodales - scelerisque. Maecenas tempor eget nunc sit amet ultrices. Maecenas et - varius ante. Nulla eu quam sit amet orci fermentum dictum sit amet - scelerisque libero. Proin luctus semper elit, ut pretium massa tristique - a. Mauris hendrerit ex eu commodo egestas. Etiam a lacus aliquet, - convallis metus et, sollicitudin odio. Fusce vehicula purus sed orci - elementum, ut cursus diam sollicitudin. Pellentesque pulvinar nibh - turpis, eu finibus dolor egestas eget. Duis tellus mauris, pulvinar sit - amet ante a, aliquet laoreet sapien. Ut quis tempus massa. Fusce - fringilla mattis lacinia. Cras at pharetra quam, eu ultrices ipsum. - Etiam malesuada, ex consectetur fringilla faucibus, quam lorem luctus - diam, vitae lobortis urna lorem ac libero. Nulla a fermentum ligula, ut - pulvinar odio. Cras in dictum nibh. Ut et orci sodales, laoreet sem nec, - volutpat sapien. Phasellus dui turpis, euismod vitae euismod porta, - semper a tellus. Morbi bibendum eros quam, et suscipit ex blandit eu. - Et… +
+ {/* DataTable integration */} + + filterData({ + data: planetData, + page, + resultsPerPage, + search, + filters, + sort, + }) + } + onReorderRows={({ rowId, newRowIndex }) => + reorderData({ + data: planetData, + rowId, + newRowIndex, + }) + } + onChangeRowSelection={(rowSelection) => + console.log(`${Object.keys(rowSelection).length} selected rows`) + } + />
), optionalComponents: sharedOptionalComponents, From 4548847de2dfd6ad72db443e406b29f051a46a61 Mon Sep 17 00:00:00 2001 From: benlister-okta Date: Thu, 5 Dec 2024 17:11:40 -0800 Subject: [PATCH 3/3] fix: updates --- .../src/theme/components.tsx | 17 +++++-- .../odyssey-labs/TopNav/TopNav.stories.tsx | 1 + .../UiShell/UiShell.stories.tsx | 49 ++++++++++++++----- 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/packages/odyssey-react-mui/src/theme/components.tsx b/packages/odyssey-react-mui/src/theme/components.tsx index 318c90f29c..f2a13628e7 100644 --- a/packages/odyssey-react-mui/src/theme/components.tsx +++ b/packages/odyssey-react-mui/src/theme/components.tsx @@ -2363,11 +2363,14 @@ export const components = ({ [`& .${formControlLabelClasses.root}`]: { gap: "unset", }, - + ...(contrastMode === "highContrast" && { + color: "#fff", + }), "&:hover": { textDecoration: "none", ...(contrastMode === "highContrast" && { + color: "#fff", backgroundColor: odysseyTokens.HueNeutral700, }), ...(contrastMode === "lowContrast" && { @@ -2407,7 +2410,13 @@ export const components = ({ [`&.${menuItemClasses.selected}`]: { backgroundColor: "transparent", - color: odysseyTokens.TypographyColorAction, + ...(contrastMode === "highContrast" && { + color: odysseyTokens.HueBlue700, + background: odysseyTokens.HueBlue50, + }), + ...(contrastMode === "lowContrast" && { + color: odysseyTokens.TypographyColorAction, + }), "&:hover": { backgroundColor: odysseyTokens.PalettePrimaryLighter, @@ -2514,10 +2523,12 @@ export const components = ({ borderStyle: odysseyTokens.BorderStyleMain, ...(contrastMode === "highContrast" && { - borderColor: odysseyTokens.HueNeutral600, + borderColor: "#1d1d1d", + background: "#313231", }), ...(contrastMode === "lowContrast" && { borderColor: odysseyTokens.HueNeutral200, + background: "#ffffff", }), }, }, diff --git a/packages/odyssey-storybook/src/components/odyssey-labs/TopNav/TopNav.stories.tsx b/packages/odyssey-storybook/src/components/odyssey-labs/TopNav/TopNav.stories.tsx index 2268704718..2859ea0719 100644 --- a/packages/odyssey-storybook/src/components/odyssey-labs/TopNav/TopNav.stories.tsx +++ b/packages/odyssey-storybook/src/components/odyssey-labs/TopNav/TopNav.stories.tsx @@ -49,6 +49,7 @@ const storybookMeta: Meta = { profileIcon={} orgName="ORG123" userName="test.user@test.com" + contrastMode="lowContrast" /> ), diff --git a/packages/odyssey-storybook/src/components/odyssey-ui-shell/UiShell/UiShell.stories.tsx b/packages/odyssey-storybook/src/components/odyssey-ui-shell/UiShell/UiShell.stories.tsx index b47a6e95ee..927994f911 100644 --- a/packages/odyssey-storybook/src/components/odyssey-ui-shell/UiShell/UiShell.stories.tsx +++ b/packages/odyssey-storybook/src/components/odyssey-ui-shell/UiShell/UiShell.stories.tsx @@ -293,19 +293,44 @@ const sharedOptionalComponents: UiShellProps["optionalComponents"] = {
{/* */}
), topNavRightSide: ( - } - contrastMode={ - window.location.href.includes("backgrounds.value:!hex(1d1d1d)") - ? "highContrast" - : "lowContrast" - } - orgName="ORG123" - userName="test.user@test.com" - /> +
+
), }; - export const Default: StoryObj = { args: { subscribeToPropChanges: (subscriber) => { @@ -412,7 +437,7 @@ export const HackweekTableExample: StoryObj = { hasChangeableDensity={true} hasColumnResizing={true} hasColumnVisibility={false} - hasFilters={true} + hasFilters={false} hasPagination={false} hasRowSelection={true} hasSearch={true}