From 08936e75ae5e99024b109776099a8ec5b37356fd Mon Sep 17 00:00:00 2001 From: Damiano Plebani Date: Thu, 24 Oct 2024 15:41:06 +0200 Subject: [PATCH 1/7] Add dark mode support to `Badge` --- example/src/pages/Badges.tsx | 115 ++++++++++++++--------------- src/components/badge/Badge.tsx | 128 ++++++++++++++++++++++++++++----- src/components/stack/Stack.tsx | 4 +- 3 files changed, 164 insertions(+), 83 deletions(-) diff --git a/example/src/pages/Badges.tsx b/example/src/pages/Badges.tsx index 663c6a44..9ff77f0c 100644 --- a/example/src/pages/Badges.tsx +++ b/example/src/pages/Badges.tsx @@ -1,13 +1,18 @@ import { Badge, H2, + H4, + hexToRgba, HSpacer, + HStack, + IOBadgeRadius, IOColors, IOStyles, IOTagRadius, IOVisualCostants, Tag, - VSpacer + VSpacer, + VStack } from "@pagopa/io-app-design-system"; import React from "react"; import { View } from "react-native"; @@ -37,65 +42,51 @@ export const Badges = () => ( const renderBadge = () => ( <> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +

Default

+ + + + + + + + + + + +
+ +

Outline

+ + + + + + + + + + + + +
+ +

Contrast

+ + + +
+
); @@ -130,9 +121,9 @@ const renderTag = () => ( diff --git a/src/components/badge/Badge.tsx b/src/components/badge/Badge.tsx index 12f412e2..933185cc 100644 --- a/src/components/badge/Badge.tsx +++ b/src/components/badge/Badge.tsx @@ -1,12 +1,14 @@ import React from "react"; -import { Platform, StyleSheet, View } from "react-native"; +import { ColorValue, Platform, StyleSheet, View } from "react-native"; import { + hexToRgba, IOBadgeHSpacing, IOBadgeRadius, IOBadgeVSpacing, IOColors, useIOExperimentalDesign, - useIOTheme + useIOTheme, + useIOThemeContext } from "../../core"; import { WithTestID } from "../../utils/types"; import { IOText } from "../typography"; @@ -28,7 +30,7 @@ export type Badge = WithTestID<{ }>; type SolidVariantProps = { - background: IOColors; + background: ColorValue; foreground: IOColors; }; @@ -60,54 +62,103 @@ const styles = StyleSheet.create({ export const Badge = ({ text, outline = false, variant, testID }: Badge) => { const { isExperimental } = useIOExperimentalDesign(); const theme = useIOTheme(); + const { themeType } = useIOThemeContext(); - const mapVariants: Record< + const bgOpacityDarkMode = 0.4; + + const mapVariantsLightMode: Record< NonNullable, SolidVariantProps > = { default: { foreground: "grey-700", - background: "grey-50" + background: IOColors["grey-50"] }, info: { foreground: "info-850", - background: "info-100" + background: IOColors["info-100"] }, warning: { foreground: "warning-850", - background: "warning-100" + background: IOColors["warning-100"] }, success: { foreground: "success-850", - background: "success-100" + background: IOColors["success-100"] }, error: { foreground: "error-850", - background: "error-100" + background: IOColors["error-100"] }, purple: { foreground: "hanPurple-500", - background: "hanPurple-100" + background: IOColors["hanPurple-100"] }, lightBlue: { foreground: "blueIO-850", - background: "blueIO-50" + background: IOColors["blueIO-50"] }, blue: { foreground: "white", - background: theme["interactiveElem-default"] + background: IOColors[theme["interactiveElem-default"]] }, turquoise: { foreground: "turquoise-850", - background: "turquoise-50" + background: IOColors["turquoise-50"] + }, + contrast: { + foreground: "grey-700", + background: IOColors.white + } + }; + + const mapVariantsDarkMode: Record< + NonNullable, + SolidVariantProps + > = { + default: { + foreground: "grey-50", + background: hexToRgba(IOColors["grey-700"], bgOpacityDarkMode) + }, + info: { + foreground: "info-400", + background: hexToRgba(IOColors["info-850"], bgOpacityDarkMode) + }, + warning: { + foreground: "warning-400", + background: hexToRgba(IOColors["warning-850"], bgOpacityDarkMode) + }, + success: { + foreground: "success-400", + background: hexToRgba(IOColors["success-850"], bgOpacityDarkMode) + }, + error: { + foreground: "error-400", + background: hexToRgba(IOColors["error-850"], bgOpacityDarkMode) + }, + purple: { + foreground: "hanPurple-250", + background: hexToRgba(IOColors["hanPurple-500"], bgOpacityDarkMode) + }, + lightBlue: { + foreground: "blueIO-200", + background: hexToRgba(IOColors["blueIO-600"], bgOpacityDarkMode) + }, + blue: { + foreground: "white", + background: IOColors[theme["interactiveElem-default"]] + }, + turquoise: { + foreground: "turquoise-150", + background: hexToRgba(IOColors["turquoise-850"], bgOpacityDarkMode) }, contrast: { foreground: "grey-700", - background: "white" + background: IOColors.white } }; - const mapOutlineVariants: Record< + const mapOutlineVariantsLightMode: Record< NonNullable, OutlinedVariantProps > = { @@ -143,9 +194,48 @@ export const Badge = ({ text, outline = false, variant, testID }: Badge) => { } }; - const { background, foreground } = ( - outline ? mapOutlineVariants : mapVariants - )[variant]; + const mapOutlineVariantsDarkMode: Record< + NonNullable, + OutlinedVariantProps + > = { + default: { + foreground: "grey-100" + }, + info: { + foreground: "info-400" + }, + warning: { + foreground: "warning-400" + }, + success: { + foreground: "success-400" + }, + error: { + foreground: "error-100" + }, + purple: { + foreground: "hanPurple-250" + }, + lightBlue: { + foreground: "blueIO-150" + }, + blue: { + foreground: theme["interactiveElem-default"] + }, + turquoise: { + foreground: "turquoise-150" + }, + contrast: { + foreground: "grey-100" + } + }; + + // prettier-ignore + const variantMap = themeType === "light" + ? (outline ? mapOutlineVariantsLightMode : mapVariantsLightMode) + : (outline ? mapOutlineVariantsDarkMode : mapVariantsDarkMode); + + const { background, foreground } = variantMap[variant]; return ( { borderColor: IOColors[foreground] } : { - backgroundColor: background ? IOColors[background] : undefined + backgroundColor: background ?? undefined } ]} > diff --git a/src/components/stack/Stack.tsx b/src/components/stack/Stack.tsx index b0f59d39..81bf6774 100644 --- a/src/components/stack/Stack.tsx +++ b/src/components/stack/Stack.tsx @@ -22,7 +22,7 @@ export const HStack = ({ space, children, style }: Stack) => ( style={{ display: "flex", flexDirection: "row", - columnGap: space, + gap: space, ...style }} > @@ -40,7 +40,7 @@ export const VStack = ({ space, children, style }: Stack) => ( style={{ display: "flex", flexDirection: "column", - rowGap: space, + gap: space, ...style }} > From 1dec3c7adf010cddee02f9451e3acbfe9929d867 Mon Sep 17 00:00:00 2001 From: Damiano Plebani Date: Thu, 24 Oct 2024 18:40:20 +0200 Subject: [PATCH 2/7] Add basic dark mode support to `Tag` --- example/src/pages/Badges.tsx | 41 ++++++++----------- src/components/tag/Tag.tsx | 78 ++++++++++++++++++++++-------------- src/core/IOColors.ts | 9 +++++ 3 files changed, 75 insertions(+), 53 deletions(-) diff --git a/example/src/pages/Badges.tsx b/example/src/pages/Badges.tsx index 9ff77f0c..fb2d34d5 100644 --- a/example/src/pages/Badges.tsx +++ b/example/src/pages/Badges.tsx @@ -93,30 +93,23 @@ const renderBadge = () => ( const renderTag = () => ( - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + = { + primary: "interactiveElem-default", + warning: "warningIcon", + error: "errorIcon", + success: "successIcon", + info: "infoIcon", + grey: "icon-default", + lightGrey: "icon-decorative" +}; + +type IconColorVariant = keyof typeof IconColorsMap; + type VariantProps = { - iconColor: IOColors; - iconName: IOIcons; + color: IconColorVariant; + name: IOIcons; }; type TextProps = @@ -44,11 +57,12 @@ export type Tag = TextProps & | "success" | "attachment" | "noIcon"; - customIconProps?: never; + iconName?: IOIcons; + icon?: never; } | { - variant: "customIcon"; - customIconProps: VariantProps; + variant: "custom"; + icon: VariantProps; } >; @@ -66,7 +80,6 @@ const styles = StyleSheet.create({ textAlignVertical: "center" } }), - backgroundColor: IOColors.white, borderWidth: 1, borderColor: IOColors["grey-100"], borderRadius: IOTagRadius, @@ -84,45 +97,46 @@ const styles = StyleSheet.create({ const getVariantProps = ( variant: NonNullable, - customIconProps?: VariantProps + customIcon?: VariantProps ): VariantProps | undefined => { + if (variant === "custom" && customIcon) { + return customIcon; + } switch (variant) { - case "customIcon": - return customIconProps; case "qrCode": return { - iconColor: "blueIO-500", - iconName: "qrCode" + color: "primary", + name: "qrCode" }; case "attachment": return { - iconColor: "grey-700", - iconName: "attachment" + color: "grey", + name: "attachment" }; case "legalMessage": return { - iconColor: "blueIO-500", - iconName: "legalValue" + color: "primary", + name: "legalValue" }; case "info": return { - iconColor: "info-700", - iconName: "info" + color: "info", + name: "infoFilled" }; case "warning": return { - iconColor: "warning-700", - iconName: "warningFilled" + color: "warning", + name: "warningFilled" }; case "error": return { - iconColor: "error-600", - iconName: "errorFilled" + color: "error", + name: "errorFilled" }; case "success": return { - iconColor: "success-700", - iconName: "success" + color: "success", + name: "success" }; case "noIcon": return undefined; @@ -138,26 +152,32 @@ export const Tag = ({ text, variant, testID, - customIconProps, + icon, iconAccessibilityLabel }: Tag) => { const theme = useIOTheme(); const { isExperimental } = useIOExperimentalDesign(); - const variantProps = getVariantProps(variant, customIconProps); + const variantProps = getVariantProps(variant, icon); return ( - + {pipe( variantProps, O.fromNullable, O.fold( () => null, - ({ iconColor, iconName }) => ( + ({ color, name }) => ( Date: Fri, 25 Oct 2024 11:14:29 +0200 Subject: [PATCH 3/7] Add `forceLightMode` to `Tag` --- example/src/pages/Badges.tsx | 29 ++++++++++++++++++++++++----- src/components/tag/Tag.tsx | 23 ++++++++++++++--------- src/core/IOColors.ts | 1 + 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/example/src/pages/Badges.tsx b/example/src/pages/Badges.tsx index fb2d34d5..cab16c4b 100644 --- a/example/src/pages/Badges.tsx +++ b/example/src/pages/Badges.tsx @@ -3,11 +3,9 @@ import { H2, H4, hexToRgba, - HSpacer, HStack, IOBadgeRadius, IOColors, - IOStyles, IOTagRadius, IOVisualCostants, Tag, @@ -94,7 +92,7 @@ const renderTag = () => ( - + @@ -107,14 +105,35 @@ const renderTag = () => ( + + + + + + + + + + + + { const theme = useIOTheme(); const { isExperimental } = useIOExperimentalDesign(); const variantProps = getVariantProps(variant, icon); + const borderColor = forceLightMode + ? IOColors[IOThemeLight["cardBorder-default"]] + : IOColors[theme["cardBorder-default"]]; + + const backgroundColor = forceLightMode + ? IOColors[IOThemeLight["appBackground-primary"]] + : IOColors[theme["appBackground-primary"]]; + return ( {pipe( variantProps, diff --git a/src/core/IOColors.ts b/src/core/IOColors.ts index 5ab9866e..32404c7f 100644 --- a/src/core/IOColors.ts +++ b/src/core/IOColors.ts @@ -362,6 +362,7 @@ export const IOThemeDark: IOTheme = { // Design System related "cardBorder-default": "grey-850", "icon-default": "grey-450", + "icon-decorative": "grey-650", // Layout "divider-header": "grey-850", "divider-default": "grey-850", From bd2663c72694a58530eb759ceb764340918298ca Mon Sep 17 00:00:00 2001 From: Damiano Plebani Date: Fri, 25 Oct 2024 11:59:42 +0200 Subject: [PATCH 4/7] Adjust chromatic values of dark mode version of `Badge` --- src/components/badge/Badge.tsx | 22 +++++++++++----------- src/core/IOColors.ts | 1 + 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/components/badge/Badge.tsx b/src/components/badge/Badge.tsx index 933185cc..babd6578 100644 --- a/src/components/badge/Badge.tsx +++ b/src/components/badge/Badge.tsx @@ -64,7 +64,7 @@ export const Badge = ({ text, outline = false, variant, testID }: Badge) => { const theme = useIOTheme(); const { themeType } = useIOThemeContext(); - const bgOpacityDarkMode = 0.4; + const bgOpacityDarkMode = 0.2; const mapVariantsLightMode: Record< NonNullable, @@ -118,27 +118,27 @@ export const Badge = ({ text, outline = false, variant, testID }: Badge) => { > = { default: { foreground: "grey-50", - background: hexToRgba(IOColors["grey-700"], bgOpacityDarkMode) + background: hexToRgba(IOColors["grey-50"], bgOpacityDarkMode) }, info: { foreground: "info-400", - background: hexToRgba(IOColors["info-850"], bgOpacityDarkMode) + background: hexToRgba(IOColors["info-400"], bgOpacityDarkMode) }, warning: { foreground: "warning-400", - background: hexToRgba(IOColors["warning-850"], bgOpacityDarkMode) + background: hexToRgba(IOColors["warning-400"], bgOpacityDarkMode) }, success: { foreground: "success-400", - background: hexToRgba(IOColors["success-850"], bgOpacityDarkMode) + background: hexToRgba(IOColors["success-400"], bgOpacityDarkMode) }, error: { foreground: "error-400", - background: hexToRgba(IOColors["error-850"], bgOpacityDarkMode) + background: hexToRgba(IOColors["error-400"], bgOpacityDarkMode) }, purple: { foreground: "hanPurple-250", - background: hexToRgba(IOColors["hanPurple-500"], bgOpacityDarkMode) + background: hexToRgba(IOColors["hanPurple-250"], bgOpacityDarkMode) }, lightBlue: { foreground: "blueIO-200", @@ -149,8 +149,8 @@ export const Badge = ({ text, outline = false, variant, testID }: Badge) => { background: IOColors[theme["interactiveElem-default"]] }, turquoise: { - foreground: "turquoise-150", - background: hexToRgba(IOColors["turquoise-850"], bgOpacityDarkMode) + foreground: "turquoise-300", + background: hexToRgba(IOColors["turquoise-300"], bgOpacityDarkMode) }, contrast: { foreground: "grey-700", @@ -211,7 +211,7 @@ export const Badge = ({ text, outline = false, variant, testID }: Badge) => { foreground: "success-400" }, error: { - foreground: "error-100" + foreground: "error-400" }, purple: { foreground: "hanPurple-250" @@ -223,7 +223,7 @@ export const Badge = ({ text, outline = false, variant, testID }: Badge) => { foreground: theme["interactiveElem-default"] }, turquoise: { - foreground: "turquoise-150" + foreground: "turquoise-300" }, contrast: { foreground: "grey-100" diff --git a/src/core/IOColors.ts b/src/core/IOColors.ts index 32404c7f..c678abc9 100644 --- a/src/core/IOColors.ts +++ b/src/core/IOColors.ts @@ -53,6 +53,7 @@ export const IOColors = asIOColors({ "turquoise-850": "#003B3D", "turquoise-500": "#00C5CA", "turquoise-450": "#19CBCF" /* Dark mode */, + "turquoise-300": "#61DCDF", "turquoise-150": "#AAEEEF", "turquoise-100": "#C2F3F4", "turquoise-50": "#DBF9FA", From 4f2e8e24571fdcedb43edb42619821027d649c3d Mon Sep 17 00:00:00 2001 From: Damiano Plebani Date: Fri, 25 Oct 2024 12:01:29 +0200 Subject: [PATCH 5/7] Fix wrong icon color in the forced light mode version of `Tag` --- src/components/tag/Tag.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/tag/Tag.tsx b/src/components/tag/Tag.tsx index 22a91baa..926de206 100644 --- a/src/components/tag/Tag.tsx +++ b/src/components/tag/Tag.tsx @@ -182,7 +182,11 @@ export const Tag = ({ Date: Fri, 25 Oct 2024 14:37:56 +0200 Subject: [PATCH 6/7] Update `jest` snapshot --- .../numberpad/__test__/__snapshots__/NumberPad.test.tsx.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/numberpad/__test__/__snapshots__/NumberPad.test.tsx.snap b/src/components/numberpad/__test__/__snapshots__/NumberPad.test.tsx.snap index dddc2457..aa73081c 100644 --- a/src/components/numberpad/__test__/__snapshots__/NumberPad.test.tsx.snap +++ b/src/components/numberpad/__test__/__snapshots__/NumberPad.test.tsx.snap @@ -13,7 +13,7 @@ exports[`NumberPad Should match the snapshot 1`] = ` { "display": "flex", "flexDirection": "column", - "rowGap": 16, + "gap": 16, } } > From 1184272dfb0e3a9ed92786e9077801e4ca163458 Mon Sep 17 00:00:00 2001 From: Damiano Plebani Date: Fri, 25 Oct 2024 16:17:59 +0200 Subject: [PATCH 7/7] Fix wrong text color of dark mode version of `Tag` --- src/components/tag/Tag.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/tag/Tag.tsx b/src/components/tag/Tag.tsx index 926de206..9ecc9eaf 100644 --- a/src/components/tag/Tag.tsx +++ b/src/components/tag/Tag.tsx @@ -202,7 +202,11 @@ export const Tag = ({ weight={isExperimental ? "Regular" : "Semibold"} size={12} lineHeight={16} - color={theme["textBody-tertiary"]} + color={ + forceLightMode + ? IOThemeLight["textBody-tertiary"] + : theme["textBody-tertiary"] + } numberOfLines={1} ellipsizeMode="tail" style={{