diff --git a/__tests__/components/presentational/Layout/Layout.test.tsx b/__tests__/components/presentational/Layout/Layout.test.tsx index 06e1c5295..aa9a44fde 100644 --- a/__tests__/components/presentational/Layout/Layout.test.tsx +++ b/__tests__/components/presentational/Layout/Layout.test.tsx @@ -55,4 +55,45 @@ describe('Layout brand color tokens', () => { await renderLayout(); expect(globalCss()).not.toContain('--mdhui-color-primary-mark: #00B068'); }); + + it('uses primaryTextColor for text and keeps the brand on fills', async () => { + await renderLayout(); + expect(globalCss()).toContain('--mdhui-color-primary: #C2185B'); + expect(globalCss()).toContain('--mdhui-color-primary-text: #F48FB1'); + expect(globalCss()).toContain('--mdhui-color-primary-mark: #C2185B'); + }); + + it('uses primaryTextColor without a brand and leaves marks on the scheme default', async () => { + await renderLayout(); + expect(globalCss()).toContain('--mdhui-color-primary-text: #00693E'); + expect(globalCss()).not.toContain('--mdhui-color-primary: #00693E'); + expect(globalCss()).toContain('--mdhui-color-primary-mark: var(--mdh-blue-30)'); + }); + + it('falls back to the brand for text in dark when the text color has no dark value', async () => { + await renderLayout(); + expect(globalCss()).toContain('--mdhui-color-primary-text: #E91E63'); + expect(globalCss()).not.toContain('#C2185B'); + }); + + it('falls back to the brand for text in light when the text color has no light value', async () => { + await renderLayout(); + expect(globalCss()).toContain('--mdhui-color-primary-text: #E91E63'); + expect(globalCss()).not.toContain('#F48FB1'); + }); + + it('does not pin marks when text falls back to the brand', async () => { + await renderLayout(); + expect(globalCss()).toContain('--mdhui-color-primary-mark: var(--mdhui-color-primary-text)'); + expect(globalCss()).not.toContain('--mdhui-color-primary-mark: #'); + }); + + it('falls back to the brand for an invalid or null text color', async () => { + await renderLayout(); + expect(globalCss()).toContain('--mdhui-color-primary-text: #E91E63'); + cleanup(); + document.querySelectorAll('style').forEach(s => s.remove()); + await renderLayout(); + expect(globalCss()).toContain('--mdhui-color-primary-text: #E91E63'); + }); }); diff --git a/src/components/presentational/Layout/Layout.tsx b/src/components/presentational/Layout/Layout.tsx index 32266718b..a60304d49 100644 --- a/src/components/presentational/Layout/Layout.tsx +++ b/src/components/presentational/Layout/Layout.tsx @@ -2,13 +2,14 @@ import React, { createContext } from 'react'; import MyDataHelps, { StatusBarStyle } from '@careevolution/mydatahelps-js'; import { Global as EmotionGlobal, css } from '@emotion/react'; import "./Layout.css" -import { darkColorScheme, lightColorScheme, global, core } from '../../../helpers/globalCss'; +import { darkColorScheme, darkColorStyle, lightColorScheme, global, core } from '../../../helpers/globalCss'; import { ColorDefinition, resolveColor } from '../../../helpers/colors'; export interface LayoutProps { children?: React.ReactNode; bodyBackgroundColor?: ColorDefinition; primaryColor?: ColorDefinition; + primaryTextColor?: ColorDefinition; statusBarStyle?: StatusBarStyle; className?: string; noGlobalStyles?: boolean; @@ -62,10 +63,17 @@ export default function Layout(props: LayoutProps) { // scheme toggle would land the scheme tag after a separate brand tag and clobber it. const schemeStyles = context.colorScheme == "dark" ? darkColorScheme : lightColorScheme; const brand = props.primaryColor ? resolveColor(colorScheme, props.primaryColor) : undefined; - const brandStyles = brand ? css` + const textColor = props.primaryTextColor && typeof props.primaryTextColor === "object" + ? (colorScheme === "dark" ? props.primaryTextColor.darkMode : props.primaryTextColor.lightMode) + : props.primaryTextColor; + const brandText = resolveColor(colorScheme, textColor) ?? brand; + const schemeText = colorScheme === "dark" ? (darkColorStyle as Record)['--mdhui-color-primary-text'] : "var(--mdhui-color-primary)"; + const markColor = brand ?? schemeText; + const brandStyles = brand || brandText ? css` :root { - --mdhui-color-primary: ${brand}; - --mdhui-color-primary-text: ${brand}; + ${brand ? `--mdhui-color-primary: ${brand};` : ""} + ${brandText ? `--mdhui-color-primary-text: ${brandText};` : ""} + ${brandText !== brand ? `--mdhui-color-primary-mark: ${markColor};` : ""} }` : undefined; return ( diff --git a/src/components/view/BlankView/BlankView.tsx b/src/components/view/BlankView/BlankView.tsx index 41aaf321f..c67406961 100644 --- a/src/components/view/BlankView/BlankView.tsx +++ b/src/components/view/BlankView/BlankView.tsx @@ -10,6 +10,7 @@ export interface BlankViewProps { showBackButton?: boolean colorScheme?: "auto" | "light" | "dark" primaryColor?: ColorDefinition + primaryTextColor?: ColorDefinition bodyBackgroundColor?: ColorDefinition titleColor?: ColorDefinition; subtitleColor?: ColorDefinition; @@ -19,7 +20,7 @@ export interface BlankViewProps { export default function (props: BlankViewProps) { return ( - + {(props.showBackButton || props.showCloseButton) && + return
{badges == null && } {badges != null && <> diff --git a/src/components/view/NewPointsView/NewPointsView.tsx b/src/components/view/NewPointsView/NewPointsView.tsx index 01dc1ffe9..383ac58f2 100644 --- a/src/components/view/NewPointsView/NewPointsView.tsx +++ b/src/components/view/NewPointsView/NewPointsView.tsx @@ -20,6 +20,7 @@ export interface NewPointsViewProps { pointsToNextReward?: number; colorScheme?: 'auto' | 'light' | 'dark'; primaryColor?: ColorDefinition; + primaryTextColor?: ColorDefinition; doneButtonText?: string; } @@ -37,7 +38,7 @@ export default function NewPointsView(props: NewPointsViewProps) { }, totalBonusPoints); return ( - +