From 408009bef32a8f9ab7329624fba3b428d6f672d4 Mon Sep 17 00:00:00 2001 From: Gianluca Spada Date: Wed, 18 Sep 2024 17:43:32 +0200 Subject: [PATCH 01/11] feat: [EUDIW-54] Add new pictograms for EUDIW app (#332) ## Short description This PR adds three new pictograms created for the EUDIW app. ## List of changes proposed in this pull request - Added `PictogramFingerprint` - Added `PictogramSmile` - Added `PictogramWalletDoc` ## How to test Use the new pictograms in the `Pictogram` component or run the storybook. --- scripts/pictograms_timestamp.txt | 2 +- src/components/pictograms/Pictogram.tsx | 13 ++++- .../pictograms/svg/PictogramFingerprint.tsx | 50 +++++++++++++++++++ .../pictograms/svg/PictogramSmile.tsx | 22 ++++++++ .../pictograms/svg/PictogramWalletDoc.tsx | 44 ++++++++++++++++ .../svg/originals/PictogramFingerprint.svg | 1 + .../svg/originals/PictogramSmile.svg | 1 + .../svg/originals/PictogramWalletDoc.svg | 1 + src/core/IOColors.ts | 4 +- 9 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 src/components/pictograms/svg/PictogramFingerprint.tsx create mode 100644 src/components/pictograms/svg/PictogramSmile.tsx create mode 100644 src/components/pictograms/svg/PictogramWalletDoc.tsx create mode 100644 src/components/pictograms/svg/originals/PictogramFingerprint.svg create mode 100644 src/components/pictograms/svg/originals/PictogramSmile.svg create mode 100644 src/components/pictograms/svg/originals/PictogramWalletDoc.svg diff --git a/scripts/pictograms_timestamp.txt b/scripts/pictograms_timestamp.txt index 0c29636d..519f491c 100644 --- a/scripts/pictograms_timestamp.txt +++ b/scripts/pictograms_timestamp.txt @@ -1 +1 @@ -2024-07-10T13:20:00.647Z \ No newline at end of file +2024-09-13T09:57:37.653Z \ No newline at end of file diff --git a/src/components/pictograms/Pictogram.tsx b/src/components/pictograms/Pictogram.tsx index a32a5ce2..9873ef95 100644 --- a/src/components/pictograms/Pictogram.tsx +++ b/src/components/pictograms/Pictogram.tsx @@ -95,6 +95,7 @@ import PictogramEmailDotCheck from "./svg/PictogramEmailDotCheck"; import PictogramEmailDotNotif from "./svg/PictogramEmailDotNotif"; import PictogramEnded from "./svg/PictogramEnded"; import PictogramEventClose from "./svg/PictogramEventClose"; +import PictogramFingerprint from "./svg/PictogramFingerprint"; import PictogramIdea from "./svg/PictogramIdea"; import PictogramLostConnection from "./svg/PictogramLostConnection"; import PictogramMessage from "./svg/PictogramMessage"; @@ -106,8 +107,10 @@ import PictogramQrCode from "./svg/PictogramQrCode"; import PictogramReactivate from "./svg/PictogramReactivate"; import PictogramSearchLens from "./svg/PictogramSearchLens"; import PictogramSettings from "./svg/PictogramSettings"; +import PictogramSmile from "./svg/PictogramSmile"; import PictogramStar from "./svg/PictogramStar"; import PictogramTiming from "./svg/PictogramTiming"; +import PictogramWalletDoc from "./svg/PictogramWalletDoc"; import { IOPictogramSizeScale, SVGPictogramProps } from "./types"; export const IOPictograms = { @@ -169,6 +172,9 @@ export const IOPictograms = { comunicationProblem: PictogramComunicationProblem, payments: PictogramPayments, workInProgress: PictogramWorkInProgress, + smile: PictogramSmile, + fingerprint: PictogramFingerprint, + walletDoc: PictogramWalletDoc, // Start Objects Pictogram ibanCard: PictogramObjIbanCard, followMessage: PictogramObjFollowMessage, @@ -196,6 +202,7 @@ type PictogramPalette = { hands: ColorValue; main: ColorValue; secondary: ColorValue; + tertiary: ColorValue; }; export const Pictogram = ({ @@ -223,7 +230,8 @@ export const Pictogram = ({ () => ({ hands: IOColors[themeObj["pictogram-hands"]], main: IOColors[themeObj["pictogram-tint-main"]], - secondary: IOColors[themeObj["pictogram-tint-secondary"]] + secondary: IOColors[themeObj["pictogram-tint-secondary"]], + tertiary: IOColors[themeObj["pictogram-tint-tertiary"]] }), [themeObj] ); @@ -365,7 +373,8 @@ export const PictogramBleed = ({ () => ({ hands: IOColors[themeObj["pictogram-hands"]], main: IOColors[themeObj["pictogram-tint-main"]], - secondary: IOColors[themeObj["pictogram-tint-secondary"]] + secondary: IOColors[themeObj["pictogram-tint-secondary"]], + tertiary: IOColors[themeObj["pictogram-tint-tertiary"]] }), [themeObj] ); diff --git a/src/components/pictograms/svg/PictogramFingerprint.tsx b/src/components/pictograms/svg/PictogramFingerprint.tsx new file mode 100644 index 00000000..9b71ea49 --- /dev/null +++ b/src/components/pictograms/svg/PictogramFingerprint.tsx @@ -0,0 +1,50 @@ +import React from "react"; +import { Svg, Path } from "react-native-svg"; +import { SVGPictogramProps } from "../types"; + +const PictogramFingerprint = ({ + size, + colorValues, + ...props +}: SVGPictogramProps) => ( + + + + + + + + + + + +); + +export default PictogramFingerprint; diff --git a/src/components/pictograms/svg/PictogramSmile.tsx b/src/components/pictograms/svg/PictogramSmile.tsx new file mode 100644 index 00000000..71de7c0d --- /dev/null +++ b/src/components/pictograms/svg/PictogramSmile.tsx @@ -0,0 +1,22 @@ +import React from "react"; +import { Svg, Path } from "react-native-svg"; +import { SVGPictogramProps } from "../types"; + +const PictogramSmile = ({ size, colorValues, ...props }: SVGPictogramProps) => ( + + + + +); + +export default PictogramSmile; diff --git a/src/components/pictograms/svg/PictogramWalletDoc.tsx b/src/components/pictograms/svg/PictogramWalletDoc.tsx new file mode 100644 index 00000000..0f4bdcf0 --- /dev/null +++ b/src/components/pictograms/svg/PictogramWalletDoc.tsx @@ -0,0 +1,44 @@ +import React from "react"; +import { Svg, Path } from "react-native-svg"; +import { SVGPictogramProps } from "../types"; + +const PictogramWalletDoc = ({ + size, + colorValues, + ...props +}: SVGPictogramProps) => ( + + + + + + + + + +); + +export default PictogramWalletDoc; diff --git a/src/components/pictograms/svg/originals/PictogramFingerprint.svg b/src/components/pictograms/svg/originals/PictogramFingerprint.svg new file mode 100644 index 00000000..f15d9581 --- /dev/null +++ b/src/components/pictograms/svg/originals/PictogramFingerprint.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/pictograms/svg/originals/PictogramSmile.svg b/src/components/pictograms/svg/originals/PictogramSmile.svg new file mode 100644 index 00000000..e42df606 --- /dev/null +++ b/src/components/pictograms/svg/originals/PictogramSmile.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/pictograms/svg/originals/PictogramWalletDoc.svg b/src/components/pictograms/svg/originals/PictogramWalletDoc.svg new file mode 100644 index 00000000..d9235baa --- /dev/null +++ b/src/components/pictograms/svg/originals/PictogramWalletDoc.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/core/IOColors.ts b/src/core/IOColors.ts index 1ee94cd1..a2f8e7f9 100644 --- a/src/core/IOColors.ts +++ b/src/core/IOColors.ts @@ -283,6 +283,7 @@ export type IOTheme = { "pictogram-hands": IOColors; "pictogram-tint-main": IOColors; "pictogram-tint-secondary": IOColors; + "pictogram-tint-tertiary": IOColors; }; export const IOThemeLight: IOTheme = { @@ -311,7 +312,8 @@ export const IOThemeLight: IOTheme = { // Pictograms "pictogram-hands": "blueIO-500", "pictogram-tint-main": "turquoise-150", - "pictogram-tint-secondary": "turquoise-500" + "pictogram-tint-secondary": "turquoise-500", + "pictogram-tint-tertiary": "blueIO-400" }; export const IOThemeLightLegacy: IOTheme = { From 492b8a67d452c93b47b6a3ca23a1dd3d191b267f Mon Sep 17 00:00:00 2001 From: Damiano Plebani Date: Thu, 19 Sep 2024 11:30:49 +0200 Subject: [PATCH 02/11] chore: release 1.46.2 --- CHANGELOG.md | 20 ++++++++++++++++++-- package.json | 2 +- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f041f469..78a7b2e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,18 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). -#### [v1.46.1](https://github.com/pagopa/io-app-design-system/compare/v2.0.0...v1.46.1) +#### [v1.46.2](https://github.com/pagopa/io-app-design-system/compare/v2.0.1...v1.46.2) +- feat: [EUDIW-54] Add new pictograms for EUDIW app [`#332`](https://github.com/pagopa/io-app-design-system/pull/332) + +#### [v2.0.1](https://github.com/pagopa/io-app-design-system/compare/v2.0.0...v2.0.1) + +> 18 September 2024 + +- feat: [PE-680] Change purple badge colors [`#333`](https://github.com/pagopa/io-app-design-system/pull/333) - feat(Icons): add iconCieLetter [`#331`](https://github.com/pagopa/io-app-design-system/pull/331) +- chore: release 1.46.1 [`de72bac`](https://github.com/pagopa/io-app-design-system/commit/de72bac13e4d20c30553609586898d87ad7dfa67) +- chore: release 2.0.1 [`6cdf523`](https://github.com/pagopa/io-app-design-system/commit/6cdf523a9f723b50d1fae1b63b1a3e821db5d226) ### [v2.0.0](https://github.com/pagopa/io-app-design-system/compare/v2.0.0-1...v2.0.0) @@ -33,13 +42,20 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - [IOAPPX-362] Change `Label…` default weight to Semibold + Fix autocomplete of `IOText` when using `font` prop [`#322`](https://github.com/pagopa/io-app-design-system/pull/322) - chore: release 2.0.0-1 [`15cfe9c`](https://github.com/pagopa/io-app-design-system/commit/15cfe9ccbfa743e9252e13e0687f482dbeb07a58) -#### [v2.0.0-0](https://github.com/pagopa/io-app-design-system/compare/v1.46.0...v2.0.0-0) +#### [v2.0.0-0](https://github.com/pagopa/io-app-design-system/compare/v1.46.1...v2.0.0-0) > 31 July 2024 - [IOAPPX-349] Add the new `IOText` component with support for advanced a11y features [`#312`](https://github.com/pagopa/io-app-design-system/pull/312) - chore: release 2.0.0-0 [`7227d4b`](https://github.com/pagopa/io-app-design-system/commit/7227d4bee6d1fe913973a5a35e3308555d0101bb) +#### [v1.46.1](https://github.com/pagopa/io-app-design-system/compare/v1.46.0...v1.46.1) + +> 11 September 2024 + +- feat(Icons): add iconCieLetter [`#331`](https://github.com/pagopa/io-app-design-system/pull/331) +- chore: release 1.46.1 [`de72bac`](https://github.com/pagopa/io-app-design-system/commit/de72bac13e4d20c30553609586898d87ad7dfa67) + #### [v1.46.0](https://github.com/pagopa/io-app-design-system/compare/v1.45.0...v1.46.0) > 3 September 2024 diff --git a/package.json b/package.json index 1bfbe71d..bae903e2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@pagopa/io-app-design-system", - "version": "1.46.1", + "version": "1.46.2", "description": "The library defining the core components of the design system of @pagopa/io-app", "main": "lib/commonjs/index", "module": "lib/module/index", From ef084b24f9a7231f1a1abe3e1f2e2a61a81b01dc Mon Sep 17 00:00:00 2001 From: Damiano Plebani Date: Wed, 9 Oct 2024 10:36:09 +0200 Subject: [PATCH 03/11] [IOAPPX-353] Add the new `FooterActions` (from `io-app`) and `FooterActionsInline` (#316) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Short description This PR adds the new `FooterActions` (migrated from `io-app`) and the new `FooterActionsInline`, which replaces the legacy `FooterWithButtons`. So if you want to add actions to the footer you have several options: - **If you need a single button**, just use `FooterActions` with the `SingleButton` type - **If you need two buttons**, depending on your needs: - use `FooterActions` as recommended in the official guidelines - for special reasons (e.g. you need to save space), use `FooterActionsInline` to render both buttons on the same line - **If you need three buttons**, just use `FooterActions` with the `ThreeButtons` type Both `FooterActions` and `FooterActionsInline` come with two hooks, `useFooterActionsMeasurements` and `useFooterActionsInlineMeasurements` respectively, to get the `safeBottomAreaHeight` value to apply to the `ScrollView`'s `paddingBottom` ## List of changes proposed in this pull request - Add the new `FooterActions` and `FooterActionsInline` and relative hooks - Add the new demo screens to the example app - Add the new `IOSpacing` object with the common spacing constants - Update the deprecation note to `FooterWithButtons` - Add the deprecation note to `BlockButtons` ### Preview https://github.com/user-attachments/assets/027914cf-3427-4bed-9a0e-9f208fd66c49 ## How to test 1. Launch the example app 2. Go to the `FooterActions…` screens --------- Co-authored-by: Cristiano Tofani --- example/src/navigation/navigator.tsx | 65 ++++- example/src/navigation/params.ts | 9 +- example/src/navigation/routes.ts | 28 +- ....tsx => FooterActionsEmptyStateScreen.tsx} | 45 ++- .../src/pages/FooterActionsInlineNotFixed.tsx | 55 ++++ .../src/pages/FooterActionsInlineScreen.tsx | 60 ++++ example/src/pages/FooterActionsNotFixed.tsx | 62 +++++ example/src/pages/FooterActionsScreen.tsx | 75 +++++ .../src/pages/FooterActionsStickyScreen.tsx | 167 +++++++++++ example/src/pages/FooterWithButton.tsx | 66 ----- src/components/layout/BlockButtons.tsx | 2 +- src/components/layout/FooterActions.tsx | 260 ++++++++++++++++++ src/components/layout/FooterActionsInline.tsx | 137 +++++++++ src/components/layout/FooterWithButtons.tsx | 4 +- src/components/layout/HeaderFirstLevel.tsx | 14 +- src/components/layout/HeaderSecondLevel.tsx | 14 +- src/components/layout/common.ts | 2 +- src/components/layout/hooks/index.ts | 2 + .../layout/hooks/useBottomMargins.ts | 30 ++ .../useFooterActionsInlineMeasurements.ts | 38 +++ .../hooks/useFooterActionsMeasurements.ts | 35 +++ src/components/layout/index.tsx | 3 + src/core/IOColors.ts | 3 + src/core/IOSpacing.ts | 14 + src/core/IOStyleVariables.ts | 6 - src/core/index.ts | 1 - 26 files changed, 1061 insertions(+), 136 deletions(-) rename example/src/pages/{FooterWithButtonEmptyState.tsx => FooterActionsEmptyStateScreen.tsx} (58%) create mode 100644 example/src/pages/FooterActionsInlineNotFixed.tsx create mode 100644 example/src/pages/FooterActionsInlineScreen.tsx create mode 100644 example/src/pages/FooterActionsNotFixed.tsx create mode 100644 example/src/pages/FooterActionsScreen.tsx create mode 100644 example/src/pages/FooterActionsStickyScreen.tsx delete mode 100644 example/src/pages/FooterWithButton.tsx create mode 100644 src/components/layout/FooterActions.tsx create mode 100644 src/components/layout/FooterActionsInline.tsx create mode 100644 src/components/layout/hooks/index.ts create mode 100644 src/components/layout/hooks/useBottomMargins.ts create mode 100644 src/components/layout/hooks/useFooterActionsInlineMeasurements.ts create mode 100644 src/components/layout/hooks/useFooterActionsMeasurements.ts delete mode 100644 src/core/IOStyleVariables.ts diff --git a/example/src/navigation/navigator.tsx b/example/src/navigation/navigator.tsx index 5e1763ea..045af8f1 100644 --- a/example/src/navigation/navigator.tsx +++ b/example/src/navigation/navigator.tsx @@ -20,12 +20,19 @@ import { DSAlert } from "../pages/Alert"; import { Badges } from "../pages/Badges"; import { Buttons } from "../pages/Buttons"; import { Colors } from "../pages/Colors"; -import { FooterWithButton } from "../pages/FooterWithButton"; -import { FooterWithButtonEmptyState } from "../pages/FooterWithButtonEmptyState"; +import { FooterActionsEmptyStateScreen } from "../pages/FooterActionsEmptyStateScreen"; +import { FooterActionsInlineNotFixed } from "../pages/FooterActionsInlineNotFixed"; +import { FooterActionsInlineScreen } from "../pages/FooterActionsInlineScreen"; +import { FooterActionsNotFixed } from "../pages/FooterActionsNotFixed"; +import { FooterActionsScreen } from "../pages/FooterActionsScreen"; +import { FooterActionsStickyScreen } from "../pages/FooterActionsStickyScreen"; import { ForceScrollDownViewPage } from "../pages/ForceScrollDownViewPage"; import { GradientScroll } from "../pages/GradientScroll"; import { HeaderFirstLevelScreen } from "../pages/HeaderFirstLevel"; import { HeaderSecondLevelScreen } from "../pages/HeaderSecondLevel"; +import { HeaderSecondLevelCustomBackground } from "../pages/HeaderSecondLevelCustomBackground"; +import { HeaderSecondLevelScreenDiscreteTransition } from "../pages/HeaderSecondLevelDiscreteTransition"; +import { HeaderSecondLevelScreenDiscreteTransitionCustomBg } from "../pages/HeaderSecondLevelScreenDiscreteTransitionCustomBg"; import { HeaderSecondLevelWithStepper } from "../pages/HeaderSecondLevelWithStepper"; import { Icons } from "../pages/Icons"; import { ImageScreen } from "../pages/Image"; @@ -39,6 +46,7 @@ import { NumberPadScreen } from "../pages/NumberPad"; import { OTPInputScreen } from "../pages/OTPInput"; import { Pictograms } from "../pages/Pictograms"; import { Sandbox } from "../pages/Sandbox"; +import { SearchCustom } from "../pages/SearchCustom"; import { SearchNative } from "../pages/SearchNative"; import { Selection } from "../pages/Selection"; import { StaticHeaderSecondLevelScreen } from "../pages/StaticHeaderSecondLevel"; @@ -47,10 +55,6 @@ import { TabNavigationScreen } from "../pages/TabNavigation"; import { TextInputs } from "../pages/TextInputs"; import { Toasts } from "../pages/Toasts"; import { Typography } from "../pages/Typography"; -import { SearchCustom } from "../pages/SearchCustom"; -import { HeaderSecondLevelCustomBackground } from "../pages/HeaderSecondLevelCustomBackground"; -import { HeaderSecondLevelScreenDiscreteTransition } from "../pages/HeaderSecondLevelDiscreteTransition"; -import { HeaderSecondLevelScreenDiscreteTransitionCustomBg } from "../pages/HeaderSecondLevelScreenDiscreteTransitionCustomBg"; import { AppParamsList } from "./params"; import APP_ROUTES from "./routes"; @@ -275,20 +279,57 @@ const AppNavigator = () => { /> + + + + + + + + diff --git a/example/src/navigation/params.ts b/example/src/navigation/params.ts index fa170c55..783be116 100644 --- a/example/src/navigation/params.ts +++ b/example/src/navigation/params.ts @@ -36,9 +36,14 @@ export type AppParamsList = { [DESIGN_SYSTEM_ROUTES.COMPONENTS.HEADER_SECOND_LEVEL_STATIC.route]: undefined; [DESIGN_SYSTEM_ROUTES.COMPONENTS.HEADER_SECOND_LEVEL_STEPPER .route]: undefined; - [DESIGN_SYSTEM_ROUTES.SCREENS.FOOTER_WITH_BUTTON.route]: undefined; + [DESIGN_SYSTEM_ROUTES.SCREENS.FOOTER_ACTIONS_INLINE.route]: undefined; + [DESIGN_SYSTEM_ROUTES.SCREENS.FOOTER_ACTIONS_INLINE_NOT_FIXED + .route]: undefined; + [DESIGN_SYSTEM_ROUTES.SCREENS.FOOTER_ACTIONS.route]: undefined; + [DESIGN_SYSTEM_ROUTES.SCREENS.FOOTER_ACTIONS_STICKY.route]: undefined; + [DESIGN_SYSTEM_ROUTES.SCREENS.FOOTER_ACTIONS_NOT_FIXED.route]: undefined; + [DESIGN_SYSTEM_ROUTES.SCREENS.FOOTER_ACTIONS_EMPTY_STATE.route]: undefined; [DESIGN_SYSTEM_ROUTES.SCREENS.GRADIENT_SCROLLVIEW.route]: undefined; - [DESIGN_SYSTEM_ROUTES.SCREENS.FOOTER_WITH_BUTTON_EMPTY.route]: undefined; [DESIGN_SYSTEM_ROUTES.COMPONENTS.TOASTS.route]: undefined; [DESIGN_SYSTEM_ROUTES.SCREENS.FULL_SCREEN_MODAL.route]: undefined; [DESIGN_SYSTEM_ROUTES.SCREENS.FULL_SCREEN_MODAL_2.route]: undefined; diff --git a/example/src/navigation/routes.ts b/example/src/navigation/routes.ts index 0c473b7d..670f13de 100644 --- a/example/src/navigation/routes.ts +++ b/example/src/navigation/routes.ts @@ -78,13 +78,29 @@ const APP_ROUTES = { title: "Full screen modal (second example)" }, SEARCH: { route: "DESIGN_SYSTEM_SEARCHBAR", title: "Search" }, - FOOTER_WITH_BUTTON_EMPTY: { - route: "DESIGN_SYSTEM_FOOTER_WITH_BUTTON_EMPTY", - title: "Footer with button (Empty state)" + FOOTER_ACTIONS: { + route: "DESIGN_SYSTEM_FOOTER_ACTIONS", + title: "Footer actions" }, - FOOTER_WITH_BUTTON: { - route: "DESIGN_SYSTEM_FOOTER_WITH_BUTTON", - title: "Footer with button" + FOOTER_ACTIONS_STICKY: { + route: "DESIGN_SYSTEM_FOOTER_ACTIONS_STICKY", + title: "Footer actions (sticky)" + }, + FOOTER_ACTIONS_NOT_FIXED: { + route: "DESIGN_SYSTEM_FOOTER_ACTIONS_NOT_FIXED", + title: "Footer actions (not fixed)" + }, + FOOTER_ACTIONS_EMPTY_STATE: { + route: "DESIGN_SYSTEM_FOOTER_ACTIONS_EMPTY_STATE", + title: "Footer actions (Empty state)" + }, + FOOTER_ACTIONS_INLINE: { + route: "DESIGN_SYSTEM_FOOTER_ACTIONS_INLINE", + title: "Footer actions (inline)" + }, + FOOTER_ACTIONS_INLINE_NOT_FIXED: { + route: "DESIGN_SYSTEM_FOOTER_ACTIONS_INLINE_NOT_FIXED", + title: "Footer actions (inline, not fixed)" }, GRADIENT_SCROLLVIEW: { route: "DESIGN_SYSTEM_GRADIENT_SCROLLVIEW", diff --git a/example/src/pages/FooterWithButtonEmptyState.tsx b/example/src/pages/FooterActionsEmptyStateScreen.tsx similarity index 58% rename from example/src/pages/FooterWithButtonEmptyState.tsx rename to example/src/pages/FooterActionsEmptyStateScreen.tsx index b76a72bb..aa56435d 100644 --- a/example/src/pages/FooterWithButtonEmptyState.tsx +++ b/example/src/pages/FooterActionsEmptyStateScreen.tsx @@ -1,21 +1,22 @@ import { Body, ContentWrapper, - FooterWithButtons, + FooterActions, H2, IOColors, - VSpacer + VSpacer, + useFooterActionsMeasurements } from "@pagopa/io-app-design-system"; import * as React from "react"; -import { useState } from "react"; import { Alert, Platform, ScrollView, View } from "react-native"; /** * This Screen is used to test components in isolation while developing. * @returns a screen with a flexed view where you can test components */ -export const FooterWithButtonEmptyState = () => { - const [footerHeight, setFooterHeight] = useState(0); +export const FooterActionsEmptyStateScreen = () => { + const { footerActionsMeasurements, handleFooterActionsMeasurements } = + useFooterActionsMeasurements(); return ( { {/* This extra View is mandatory when you have a fixed bottom component to get a consistent behavior across platforms */} - + { - Alert.alert("Button pressed"), - label: "Primary button" + Alert.alert("Button pressed") } }} - // secondary={{ - // type: "Outline", - // buttonProps: { - // color: "primary", - // accessibilityLabel: "secondary button", - // onPress: () => Alert.alert("Button pressed"), - // label: "Secondary button" - // } - // }} - type="SingleButton" /> ); diff --git a/example/src/pages/FooterActionsInlineNotFixed.tsx b/example/src/pages/FooterActionsInlineNotFixed.tsx new file mode 100644 index 00000000..b3f847c3 --- /dev/null +++ b/example/src/pages/FooterActionsInlineNotFixed.tsx @@ -0,0 +1,55 @@ +import { + FooterActionsInline, + IOColors, + VSpacer, + useIOTheme +} from "@pagopa/io-app-design-system"; +import React from "react"; +import { Alert, ScrollView, StyleSheet, Text, View } from "react-native"; + +const onButtonPress = () => { + Alert.alert("Alert", "Action triggered"); +}; + +export const FooterActionsInlineNotFixed = () => { + const theme = useIOTheme(); + + return ( + + {[...Array(9)].map((_el, i) => ( + + + + {`Block ${i}`} + + + + + ))} + + + ); +}; + +const styles = StyleSheet.create({ + block: { + alignItems: "center", + justifyContent: "center", + aspectRatio: 16 / 10 + } +}); diff --git a/example/src/pages/FooterActionsInlineScreen.tsx b/example/src/pages/FooterActionsInlineScreen.tsx new file mode 100644 index 00000000..77fdd220 --- /dev/null +++ b/example/src/pages/FooterActionsInlineScreen.tsx @@ -0,0 +1,60 @@ +import { + Body, + ButtonOutline, + ContentWrapper, + FooterActionsInline, + H1, + useFooterActionsInlineMeasurements +} from "@pagopa/io-app-design-system"; +import * as React from "react"; +import { Alert, ScrollView, View } from "react-native"; + +/** + * This Screen is used to test components in isolation while developing. + * @returns a screen with a flexed view where you can test components + */ +export const FooterActionsInlineScreen = () => { + const { + footerActionsInlineMeasurements, + handleFooterActionsInlineMeasurements + } = useFooterActionsInlineMeasurements(); + + return ( + + + +

Footer Actions (inline)

+ {[...Array(50)].map((_el, i) => ( + {`Repeated text ${i}`} + ))} + Alert.alert("Button pressed")} + label="Test Button" + /> + {[...Array(10)].map((_el, i) => ( + {`Repeated text ${i}`} + ))} +
+
+ Alert.alert("Button pressed") + }} + endAction={{ + color: "primary", + onPress: () => Alert.alert("Button pressed"), + label: "Solid button" + }} + /> +
+ ); +}; diff --git a/example/src/pages/FooterActionsNotFixed.tsx b/example/src/pages/FooterActionsNotFixed.tsx new file mode 100644 index 00000000..2ad3e0dd --- /dev/null +++ b/example/src/pages/FooterActionsNotFixed.tsx @@ -0,0 +1,62 @@ +import { + FooterActions, + IOColors, + VSpacer, + useIOTheme +} from "@pagopa/io-app-design-system"; +import React from "react"; +import { Alert, ScrollView, StyleSheet, Text, View } from "react-native"; + +const onButtonPress = () => { + Alert.alert("Alert", "Action triggered"); +}; + +export const FooterActionsNotFixed = () => { + const theme = useIOTheme(); + + return ( + + {[...Array(9)].map((_el, i) => ( + + + + {`Block ${i}`} + + + + + ))} + + + ); +}; + +const styles = StyleSheet.create({ + block: { + alignItems: "center", + justifyContent: "center", + aspectRatio: 16 / 10 + } +}); diff --git a/example/src/pages/FooterActionsScreen.tsx b/example/src/pages/FooterActionsScreen.tsx new file mode 100644 index 00000000..39489d00 --- /dev/null +++ b/example/src/pages/FooterActionsScreen.tsx @@ -0,0 +1,75 @@ +import { + FooterActions, + IOColors, + VSpacer, + useFooterActionsMeasurements, + useIOTheme +} from "@pagopa/io-app-design-system"; +import React from "react"; +import { Alert, ScrollView, StyleSheet, Text, View } from "react-native"; + +const onButtonPress = () => { + Alert.alert("Alert", "Action triggered"); +}; + +export const FooterActionsScreen = () => { + const theme = useIOTheme(); + + const { footerActionsMeasurements, handleFooterActionsMeasurements } = + useFooterActionsMeasurements(); + + return ( + + + {[...Array(9)].map((_el, i) => ( + + + + {`Block ${i}`} + + + + + ))} + + + + ); +}; + +const styles = StyleSheet.create({ + container: { + flexGrow: 1 + }, + block: { + alignItems: "center", + justifyContent: "center", + aspectRatio: 16 / 10 + } +}); diff --git a/example/src/pages/FooterActionsStickyScreen.tsx b/example/src/pages/FooterActionsStickyScreen.tsx new file mode 100644 index 00000000..42c2e88a --- /dev/null +++ b/example/src/pages/FooterActionsStickyScreen.tsx @@ -0,0 +1,167 @@ +import { + FooterActions, + FooterActionsMeasurements, + IOColors, + VSpacer, + useIOTheme +} from "@pagopa/io-app-design-system"; +import { useHeaderHeight } from "@react-navigation/elements"; +import React, { useMemo, useState } from "react"; +import { + Alert, + Dimensions, + LayoutChangeEvent, + LayoutRectangle, + StyleSheet, + Text, + View +} from "react-native"; +import Animated, { + Extrapolation, + interpolate, + useAnimatedScrollHandler, + useAnimatedStyle, + useSharedValue +} from "react-native-reanimated"; + +const onButtonPress = () => { + Alert.alert("Alert", "Action triggered"); +}; + +export const FooterActionsStickyScreen = () => { + const theme = useIOTheme(); + + const scrollY = useSharedValue(0); + + /* We can't just use `windowHeight` from `Dimensions` because + it doesn't count the fixed block used by `react-navigation` + for the header */ + const { height: windowHeight } = Dimensions.get("window"); + const headerHeight = useHeaderHeight(); + const activeScreenHeight = windowHeight - headerHeight; + + /* Disambiguation: + actionBlock: Block element fixed at the bottom of the screen + actionBlockPlaceholder: Block element to which the fixed action block + needs to be attached + */ + type ActionBlockHeight = LayoutRectangle["height"]; + + const [actionBlockHeight, setActionBlockHeight] = + useState(0); + const [actionBlockPlaceholderY, setActionBlockPlaceholderY] = + useState(0); + + const handleScroll = useAnimatedScrollHandler(({ contentOffset }) => { + // eslint-disable-next-line functional/immutable-data + scrollY.value = contentOffset.y; + }); + + /* Get `FooterActions` measurements from `onLayout` */ + const handleFooterActionsHeight = (values: FooterActionsMeasurements) => { + setActionBlockHeight(values.safeBottomAreaHeight); + }; + + const getActionBlockY = (event: LayoutChangeEvent) => { + setActionBlockPlaceholderY(event.nativeEvent.layout.y); + }; + + const actionBlockPlaceholderTopEdge = useMemo( + () => actionBlockPlaceholderY - activeScreenHeight + actionBlockHeight, + [actionBlockPlaceholderY, activeScreenHeight, actionBlockHeight] + ); + + const actionBlockAnimatedStyle = useAnimatedStyle(() => ({ + /* + We only start translating the action block + when it reaches the top of the placeholder + 0 = Translate is blocked + -1 = Translate is unblocked + */ + transform: [ + { + translateY: interpolate( + scrollY.value, + [0, actionBlockPlaceholderTopEdge - 1, actionBlockPlaceholderTopEdge], + [0, 0, -1], + { extrapolateLeft: Extrapolation.CLAMP } + ) + } + ] + })); + + const actionBackgroundBlockAnimatedStyle = useAnimatedStyle(() => ({ + /* Avoid solid background overlap with the + system scrollbar */ + backgroundColor: + actionBlockPlaceholderTopEdge < scrollY.value + ? "transparent" + : IOColors[theme["appBackground-primary"]] + })); + + return ( + + + {[...Array(9)].map((_el, i) => ( + + + + {`Block ${i}`} + + + + + ))} + {/* Action Block Placeholder: START */} + + {/* Action Block Placeholder: END */} + + {`Footer`} + + + + + ); +}; + +const styles = StyleSheet.create({ + container: { + flexGrow: 1 + }, + block: { + alignItems: "center", + justifyContent: "center", + aspectRatio: 16 / 10 + }, + footer: { + backgroundColor: IOColors["success-100"] + } +}); diff --git a/example/src/pages/FooterWithButton.tsx b/example/src/pages/FooterWithButton.tsx deleted file mode 100644 index 15416188..00000000 --- a/example/src/pages/FooterWithButton.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { - Body, - ButtonOutline, - ContentWrapper, - FooterWithButtons, - H1, - IOVisualCostants -} from "@pagopa/io-app-design-system"; -import * as React from "react"; -import { useState } from "react"; -import { Alert, ScrollView, View } from "react-native"; - -/** - * This Screen is used to test components in isolation while developing. - * @returns a screen with a flexed view where you can test components - */ -export const FooterWithButton = () => { - const [footerHeight, setFooterHeight] = useState(0); - - return ( - - - - -

Footer with button

- {[...Array(50)].map((_el, i) => ( - {`Repeated text ${i}`} - ))} - Alert.alert("Button pressed")} - label="Test Button" - /> - {[...Array(10)].map((_el, i) => ( - {`Repeated text ${i}`} - ))} -
-
-
- Alert.alert("Button pressed"), - label: "Primary button" - } - }} - // secondary={{ - // type: "Outline", - // buttonProps: { - // color: "primary", - // accessibilityLabel: "secondary button", - // onPress: () => Alert.alert("Button pressed"), - // label: "Secondary button" - // } - // }} - type="SingleButton" - /> -
- ); -}; diff --git a/src/components/layout/BlockButtons.tsx b/src/components/layout/BlockButtons.tsx index 31113a7e..58bbf493 100644 --- a/src/components/layout/BlockButtons.tsx +++ b/src/components/layout/BlockButtons.tsx @@ -77,7 +77,7 @@ export type BlockButtonsProps = Props; /** * Implements a component that show buttons on a line on 1, 2 or 3 buttons - * @deprecated This component is deprecated. + * @deprecated This component is deprecated. Use `FooterActionsInline` instead. */ export const BlockButtons = (props: Props) => { const renderRightButton = () => { diff --git a/src/components/layout/FooterActions.tsx b/src/components/layout/FooterActions.tsx new file mode 100644 index 00000000..31a2046b --- /dev/null +++ b/src/components/layout/FooterActions.tsx @@ -0,0 +1,260 @@ +import * as React from "react"; +import { ComponentProps, Fragment, PropsWithChildren, useState } from "react"; +import { + ColorValue, + LayoutChangeEvent, + LayoutRectangle, + StyleSheet, + Text, + View, + ViewStyle +} from "react-native"; +import Animated from "react-native-reanimated"; +import { + IOColors, + IOSpacer, + IOSpacing, + IOVisualCostants, + buttonSolidHeight, + hexToRgba, + useIOExperimentalDesign, + useIOTheme +} from "../../core"; +import { WithTestID } from "../../utils/types"; +import { ButtonLink, ButtonOutline, ButtonSolid } from "../buttons"; +import { VSpacer } from "../spacer"; +import { useBottomMargins } from "./hooks/useBottomMargins"; + +type FooterSingleButton = { + type: "SingleButton"; + primary: Omit, "fullWidth">; + secondary?: never; + tertiary?: never; +}; + +type FooterTwoButtons = { + type: "TwoButtons"; + primary: Omit, "fullWidth">; + secondary: Omit, "color">; + tertiary?: never; +}; + +type FooterThreeButtons = { + type: "ThreeButtons"; + primary: Omit, "fullWidth">; + secondary: Omit, "fullWidth" | "color">; + tertiary: Omit, "color">; +}; + +export type FooterActionsMeasurements = { + // Height of the "Actions" block + actionBlockHeight: number; + /* Height of the safe bottom area. It includes: + - Margin between screen content + and actions (contentEndMargin) + - Actions block height + - Eventual safe area margin (bottomMargin) + This is the total bottom padding that needs + to be applied to the ScrollView. + */ + safeBottomAreaHeight: number; +}; + +type FooterActions = FooterSingleButton | FooterTwoButtons | FooterThreeButtons; + +type FooterAnimatedStyles = { + /* Apply object returned by `useAnimatedStyle` to the main block */ + mainBlock?: Animated.AnimateStyle; + /* Apply object returned by `useAnimatedStyle` to the background */ + background?: Animated.AnimateStyle; +}; + +type FooterActionsProps = WithTestID< + PropsWithChildren<{ + actions?: FooterActions; + onMeasure?: (measurements: FooterActionsMeasurements) => void; + animatedStyles?: FooterAnimatedStyles; + /* Make the background transparent */ + transparent?: boolean; + /* Don't include safe area insets */ + excludeSafeAreaMargins?: boolean; + /* Fixed at the bottom of the screen */ + fixed?: boolean; + /* Show the following elements: + - Opaque red background to show the component boundaries + - Height of the component */ + debugMode?: boolean; + }> +>; + +/* Margin between ButtonSolid and ButtonOutline */ +const spaceBetweenActions: IOSpacer = 16; +/* Margin between ButtonSolid and ButtonLink */ +const spaceBetweenActionAndLink: IOSpacer = 16; + +const styles = StyleSheet.create({ + buttonContainer: { + paddingHorizontal: IOVisualCostants.appMarginDefault, + width: "100%", + flexShrink: 0 + }, + debugText: { + position: "absolute", + right: 8, + top: -16, + color: IOColors.black, + fontSize: 9, + opacity: 0.75 + }, + blockShadow: { + shadowColor: IOColors.black, + shadowOffset: { + width: 0, + height: -4 + }, + shadowOpacity: 0.1, + shadowRadius: 32 + } +}); + +export const FooterActions = ({ + actions, + excludeSafeAreaMargins = false, + animatedStyles, + fixed = true, + transparent = false, + onMeasure, + testID, + debugMode = false +}: FooterActionsProps) => { + const theme = useIOTheme(); + const { isExperimental } = useIOExperimentalDesign(); + + const { bottomMargin, extraBottomMargin } = useBottomMargins( + !!actions?.secondary, + excludeSafeAreaMargins + ); + + /* Total height of actions */ + const [actionBlockHeight, setActionBlockHeight] = + useState(0); + + /* Background color should be app main background + (both light and dark themes) */ + const HEADER_BG_COLOR: ColorValue = IOColors[theme["appBackground-primary"]]; + const TRANSPARENT_BG_COLOR: ColorValue = "transparent"; + const BUTTONSOLID_HEIGHT = isExperimental ? buttonSolidHeight : 40; + + /* Safe background block. Cover everything until it reaches + the half of the primary action button. It avoids + glitchy behavior underneath. */ + const safeBackgroundBlockHeight = + bottomMargin + actionBlockHeight - BUTTONSOLID_HEIGHT / 2; + + const getActionBlockMeasurements = (event: LayoutChangeEvent) => { + const { height } = event.nativeEvent.layout; + setActionBlockHeight(height); + /* Height of the safe bottom area, applied to the ScrollView: + Actions + Content end margin */ + const safeBottomAreaHeight = + bottomMargin + height + IOSpacing.screenEndMargin; + onMeasure?.({ actionBlockHeight: height, safeBottomAreaHeight }); + }; + + return ( + + {/* Safe background block. It's added because when you swipe up + quickly, the content below is visible for about 100ms. Without this + block, the content scrolls underneath. */} + + + + {debugMode && ( + {`Height: ${actionBlockHeight}`} + )} + + {renderActions(actions, extraBottomMargin)} + + + ); +}; + +const renderActions = ( + actions: FooterActions | undefined, + extraBottomMargin: number +) => { + if (!actions) { + return null; + } + const { + type, + primary: primaryAction, + secondary: secondaryAction, + tertiary: tertiaryAction + } = actions; + return ( + + {primaryAction && } + {type === "TwoButtons" && secondaryAction && ( + + + + + )} + {type === "ThreeButtons" && ( + <> + {secondaryAction && ( + <> + + + + )} + {tertiaryAction && ( + + + + + )} + + )} + + ); +}; diff --git a/src/components/layout/FooterActionsInline.tsx b/src/components/layout/FooterActionsInline.tsx new file mode 100644 index 00000000..8a530b7e --- /dev/null +++ b/src/components/layout/FooterActionsInline.tsx @@ -0,0 +1,137 @@ +import * as React from "react"; +import { ComponentProps, PropsWithChildren } from "react"; +import { ColorValue, LayoutChangeEvent, StyleSheet, View } from "react-native"; +import { + IOColors, + IOSpacer, + IOSpacing, + IOSpacingScale, + IOVisualCostants, + useIOTheme, + useIOThemeContext +} from "../../core"; +import { WithTestID } from "../../utils/types"; +import { ButtonOutline, ButtonSolid } from "../buttons"; +import { HSpacer } from "../spacer"; +import { useBottomMargins } from "./hooks/useBottomMargins"; + +export type FooterActionsInlineMeasurements = { + /* Height of the safe bottom area. It includes: + - Margin between screen content + and actions (contentEndMargin) + - Actions block height + - Eventual safe area margin (bottomMargin) + This is the total bottom padding that needs + to be applied to the ScrollView. + */ + safeBottomAreaHeight: number; +}; + +type FooterActionsInline = WithTestID< + PropsWithChildren<{ + startAction: Omit, "fullWidth">; + endAction: Omit, "fullWidth">; + onMeasure?: (measurements: FooterActionsInlineMeasurements) => void; + /* Don't include safe area insets */ + excludeSafeAreaMargins?: boolean; + /* Fixed at the bottom of the screen */ + fixed?: boolean; + }> +>; + +/* Margin between ButtonSolid and ButtonOutline */ +const spaceBetweenActions: IOSpacer = 16; + +const styles = StyleSheet.create({ + buttonContainer: { + paddingHorizontal: IOVisualCostants.appMarginDefault, + width: "100%", + flexShrink: 0 + }, + buttonWrapper: { + flex: 1 + }, + blockShadow: { + shadowColor: IOColors.black, + shadowOffset: { + width: 0, + height: -4 + }, + shadowOpacity: 0.1, + shadowRadius: 32, + elevation: 10 // Prop supported on Android only + } +}); + +export const FooterActionsInline = ({ + startAction, + endAction, + excludeSafeAreaMargins = false, + fixed = true, + onMeasure, + testID +}: FooterActionsInline) => { + const theme = useIOTheme(); + const { themeType } = useIOThemeContext(); + + const { bottomMargin } = useBottomMargins(false, excludeSafeAreaMargins); + + /* Top padding applied above the actions */ + const topSpacingValue: IOSpacingScale = 16; + const topSpacing = fixed ? topSpacingValue : 0; + + /* Background color should be app main background + (both light and dark themes) */ + const HEADER_BG_COLOR: ColorValue = IOColors[theme["appBackground-primary"]]; + + const getActionBlockMeasurements = (event: LayoutChangeEvent) => { + const { height } = event.nativeEvent.layout; + /* Height of the safe bottom area, applied to the ScrollView: + Actions + Screen end margin */ + const safeBottomAreaHeight = + bottomMargin + height + IOSpacing.screenEndMargin; + onMeasure?.({ safeBottomAreaHeight }); + }; + + return ( + + + + + + + + + + + + + + ); +}; diff --git a/src/components/layout/FooterWithButtons.tsx b/src/components/layout/FooterWithButtons.tsx index 86aa4d0a..bf890723 100644 --- a/src/components/layout/FooterWithButtons.tsx +++ b/src/components/layout/FooterWithButtons.tsx @@ -44,7 +44,9 @@ const verticalSpacing: IOSpacingScale = 16; /** * Implements a component that show buttons as sticky footer * It can include 1, 2 or 3 buttons. If they are 2, they can have the inlineHalf or the inlineOneThird style - * @deprecated This component is deprecated. Use `FooterActions` in the main `io-app` repo instead. + * @deprecated This component is deprecated. Use `FooterActions` or `FooterActionsInline` instead. + * `FooterActionsInline` is the official replacement for `FooterWithButtons`, but use it only + * if explicitly required. */ export const FooterWithButtons = ({ sticky = false, diff --git a/src/components/layout/HeaderFirstLevel.tsx b/src/components/layout/HeaderFirstLevel.tsx index 7e3e7e58..1fddc332 100644 --- a/src/components/layout/HeaderFirstLevel.tsx +++ b/src/components/layout/HeaderFirstLevel.tsx @@ -23,7 +23,7 @@ import { WithTestID } from "../../utils/types"; import { IconButton } from "../buttons"; import { HSpacer } from "../spacer"; import { H3 } from "../typography"; -import { ActionProp } from "./common"; +import { HeaderActionProps } from "./common"; type CommonProps = WithTestID<{ title: string; @@ -41,23 +41,23 @@ interface Base extends CommonProps { interface OneAction extends CommonProps { type: "singleAction"; - firstAction: ActionProp; + firstAction: HeaderActionProps; secondAction?: never; thirdAction?: never; } interface TwoActions extends CommonProps { type: "twoActions"; - firstAction: ActionProp; - secondAction: ActionProp; + firstAction: HeaderActionProps; + secondAction: HeaderActionProps; thirdAction?: never; } interface ThreeActions extends CommonProps { type: "threeActions"; - firstAction: ActionProp; - secondAction: ActionProp; - thirdAction: ActionProp; + firstAction: HeaderActionProps; + secondAction: HeaderActionProps; + thirdAction: HeaderActionProps; } export type HeaderFirstLevel = Base | OneAction | TwoActions | ThreeActions; diff --git a/src/components/layout/HeaderSecondLevel.tsx b/src/components/layout/HeaderSecondLevel.tsx index 93359dde..ae47e249 100644 --- a/src/components/layout/HeaderSecondLevel.tsx +++ b/src/components/layout/HeaderSecondLevel.tsx @@ -37,7 +37,7 @@ import { makeFontStyleObject } from "../../utils/fonts"; import { WithTestID } from "../../utils/types"; import IconButton from "../buttons/IconButton"; import { HSpacer } from "../spacer"; -import { ActionProp } from "./common"; +import { HeaderActionProps } from "./common"; type ScrollValues = { contentOffsetY: SharedValue; @@ -85,23 +85,23 @@ interface Base extends CommonProps { interface OneAction extends CommonProps { type: "singleAction"; - firstAction: ActionProp; + firstAction: HeaderActionProps; secondAction?: never; thirdAction?: never; } interface TwoActions extends CommonProps { type: "twoActions"; - firstAction: ActionProp; - secondAction: ActionProp; + firstAction: HeaderActionProps; + secondAction: HeaderActionProps; thirdAction?: never; } interface ThreeActions extends CommonProps { type: "threeActions"; - firstAction: ActionProp; - secondAction: ActionProp; - thirdAction: ActionProp; + firstAction: HeaderActionProps; + secondAction: HeaderActionProps; + thirdAction: HeaderActionProps; } export type HeaderSecondLevel = BackProps & diff --git a/src/components/layout/common.ts b/src/components/layout/common.ts index b1f81c85..81d886aa 100644 --- a/src/components/layout/common.ts +++ b/src/components/layout/common.ts @@ -1,7 +1,7 @@ import * as React from "react"; import { IconButton } from "../buttons"; -export type ActionProp = Pick< +export type HeaderActionProps = Pick< React.ComponentProps, "icon" | "onPress" | "accessibilityLabel" | "accessibilityHint" | "testID" >; diff --git a/src/components/layout/hooks/index.ts b/src/components/layout/hooks/index.ts new file mode 100644 index 00000000..4a88cdd3 --- /dev/null +++ b/src/components/layout/hooks/index.ts @@ -0,0 +1,2 @@ +export * from "./useFooterActionsMeasurements"; +export * from "./useFooterActionsInlineMeasurements"; diff --git a/src/components/layout/hooks/useBottomMargins.ts b/src/components/layout/hooks/useBottomMargins.ts new file mode 100644 index 00000000..da62e5e3 --- /dev/null +++ b/src/components/layout/hooks/useBottomMargins.ts @@ -0,0 +1,30 @@ +import { useSafeAreaInsets } from "react-native-safe-area-context"; +import { IOSpacingScale, IOVisualCostants } from "../../../core"; + +/* Extra bottom margin for iPhone bottom handle because + ButtonLink doesn't have a fixed height */ +const extraSafeAreaMargin: IOSpacingScale = 8; + +export const useBottomMargins = ( + withSecondaryAction: boolean = false, + excludeSafeAreaMargins: boolean = false +) => { + const insets = useSafeAreaInsets(); + const needSafeAreaMargin = insets.bottom !== 0; + + /* Check if the iPhone bottom handle is present. + If not, or if you don't need safe area insets, + add a default margin to prevent the button + from sticking to the bottom. */ + const bottomMargin = + !needSafeAreaMargin || excludeSafeAreaMargins + ? IOVisualCostants.appMarginDefault + : insets.bottom; + + /* When the secondary action is visible, add extra margin + to avoid little space from iPhone bottom handle */ + const extraBottomMargin = + withSecondaryAction && needSafeAreaMargin ? extraSafeAreaMargin : 0; + + return { bottomMargin, extraBottomMargin }; +}; diff --git a/src/components/layout/hooks/useFooterActionsInlineMeasurements.ts b/src/components/layout/hooks/useFooterActionsInlineMeasurements.ts new file mode 100644 index 00000000..eea74738 --- /dev/null +++ b/src/components/layout/hooks/useFooterActionsInlineMeasurements.ts @@ -0,0 +1,38 @@ +import { useState } from "react"; +import { FooterActionsInlineMeasurements } from "../FooterActionsInline"; + +type UseFooterActionsInlineMeasurementsProps = { + footerActionsInlineMeasurements: FooterActionsInlineMeasurements; + handleFooterActionsInlineMeasurements: ( + values: FooterActionsInlineMeasurements + ) => void; +}; +/** + * Custom hook to handle the `FooterActions` measurements + * @returns + * - `footerActionsInlineMeasurements` + * Object containing the `FooterActionsInline` measurements + * - `handleFooterActionsInlineMeasurements` + * Function to update the footer actions measurements + * (to be applied to `onMeasure` prop of `FooterActionsInline`) + */ +export const useFooterActionsInlineMeasurements = + (): UseFooterActionsInlineMeasurementsProps => { + const [ + footerActionsInlineMeasurements, + setFooterActionsInlineMeasurements + ] = useState({ + safeBottomAreaHeight: 0 + }); + + const handleFooterActionsInlineMeasurements = ( + values: FooterActionsInlineMeasurements + ) => { + setFooterActionsInlineMeasurements(values); + }; + + return { + footerActionsInlineMeasurements, + handleFooterActionsInlineMeasurements + }; + }; diff --git a/src/components/layout/hooks/useFooterActionsMeasurements.ts b/src/components/layout/hooks/useFooterActionsMeasurements.ts new file mode 100644 index 00000000..5f41c3c1 --- /dev/null +++ b/src/components/layout/hooks/useFooterActionsMeasurements.ts @@ -0,0 +1,35 @@ +import { useState } from "react"; +import { FooterActionsMeasurements } from "../FooterActions"; + +type UseFooterActionsMeasurementsProps = { + footerActionsMeasurements: FooterActionsMeasurements; + handleFooterActionsMeasurements: (values: FooterActionsMeasurements) => void; +}; +/** + * Custom hook to handle the `FooterActions` measurements + * @returns + * - `footerActionsMeasurements` + * Object containing the `FooterActions` measurements + * - `handleFooterActionsMeasurements` + * Function to update the footer actions measurements + * (to be applied to `onMeasure` prop of `FooterActions`) + */ +export const useFooterActionsMeasurements = + (): UseFooterActionsMeasurementsProps => { + const [footerActionsMeasurements, setFooterActionsMeasurements] = + useState({ + actionBlockHeight: 0, + safeBottomAreaHeight: 0 + }); + + const handleFooterActionsMeasurements = ( + values: FooterActionsMeasurements + ) => { + setFooterActionsMeasurements(values); + }; + + return { + footerActionsMeasurements, + handleFooterActionsMeasurements + }; + }; diff --git a/src/components/layout/index.tsx b/src/components/layout/index.tsx index 4b9de220..21392ebf 100644 --- a/src/components/layout/index.tsx +++ b/src/components/layout/index.tsx @@ -1,4 +1,6 @@ export * from "./BlockButtons"; +export * from "./FooterActions"; +export * from "./FooterActionsInline"; export * from "./FooterWithButtons"; export * from "./ForceScrollDownView"; export * from "./GradientBottomActions"; @@ -7,3 +9,4 @@ export * from "./HeaderFirstLevel"; export * from "./HeaderSecondLevel"; export * from "./ModalBSHeader"; export * from "./common"; +export * from "./hooks"; diff --git a/src/core/IOColors.ts b/src/core/IOColors.ts index a2f8e7f9..3f226c06 100644 --- a/src/core/IOColors.ts +++ b/src/core/IOColors.ts @@ -276,6 +276,7 @@ export type IOTheme = { "icon-decorative": IOColors; // Layout "divider-default": IOColors; + "divider-bottomBar": IOColors; // Status errorIcon: IOColors; errorText: IOColors; @@ -306,6 +307,7 @@ export const IOThemeLight: IOTheme = { "icon-decorative": "grey-300", // Layout "divider-default": "grey-200", + "divider-bottomBar": "grey-200", // Status errorIcon: "error-600", errorText: "error-600", @@ -342,6 +344,7 @@ export const IOThemeDark: IOTheme = { "icon-default": "grey-450", // Layout "divider-default": "grey-850", + "divider-bottomBar": "grey-850", // Status errorIcon: "error-400", errorText: "error-400", diff --git a/src/core/IOSpacing.ts b/src/core/IOSpacing.ts index a6aa1100..4ec14221 100644 --- a/src/core/IOSpacing.ts +++ b/src/core/IOSpacing.ts @@ -49,3 +49,17 @@ export const IOModuleIDPHSpacing: IOModuleIDPSpacing = 16; export const IOModuleIDPVSpacing: IOModuleIDPSpacing = 16; export const IOModuleIDPSavedVSpacing: IOModuleIDPSpacing = 24; export const IOListItemLogoMargin: IOModuleIDPSpacing = 8; + +/* +░░░ SPACING CONSTANTS ░░░ +*/ + +const spacingConstantKeys = ["screenEndMargin"] as const; + +export type IOSpacingConstants = { + [K in (typeof spacingConstantKeys)[number]]: IOSpacingScale; +}; + +export const IOSpacing = { + screenEndMargin: 32 +} as const satisfies IOSpacingConstants; diff --git a/src/core/IOStyleVariables.ts b/src/core/IOStyleVariables.ts deleted file mode 100644 index 88a20791..00000000 --- a/src/core/IOStyleVariables.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * A collection of default style variables used within IO App. - */ -export const IOStyleVariables = { - switchWidth: 51 -}; diff --git a/src/core/index.ts b/src/core/index.ts index de156d49..ecd42510 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -4,6 +4,5 @@ export * from "./IOTransitions"; export * from "./IOStyles"; export * from "./IOShapes"; export * from "./IOSpacing"; -export * from "./IOStyleVariables"; export * from "./IODSExperimentalContextProvider"; export * from "./IOThemeContextProvider"; From 5b3f8a650fa3c7573000eb35a332d0906d0551ed Mon Sep 17 00:00:00 2001 From: Damiano Plebani Date: Wed, 9 Oct 2024 10:50:29 +0200 Subject: [PATCH 04/11] chore: release 1.47.0 --- CHANGELOG.md | 14 ++++++++++++-- package.json | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78a7b2e0..21925d38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,11 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). -#### [v1.46.2](https://github.com/pagopa/io-app-design-system/compare/v2.0.1...v1.46.2) +#### [v1.47.0](https://github.com/pagopa/io-app-design-system/compare/v2.0.1...v1.47.0) +- [IOAPPX-353] Add the new `FooterActions` (from `io-app`) and `FooterActionsInline` [`#316`](https://github.com/pagopa/io-app-design-system/pull/316) - feat: [EUDIW-54] Add new pictograms for EUDIW app [`#332`](https://github.com/pagopa/io-app-design-system/pull/332) +- chore: release 1.46.2 [`492b8a6`](https://github.com/pagopa/io-app-design-system/commit/492b8a67d452c93b47b6a3ca23a1dd3d191b267f) #### [v2.0.1](https://github.com/pagopa/io-app-design-system/compare/v2.0.0...v2.0.1) @@ -42,13 +44,21 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - [IOAPPX-362] Change `Label…` default weight to Semibold + Fix autocomplete of `IOText` when using `font` prop [`#322`](https://github.com/pagopa/io-app-design-system/pull/322) - chore: release 2.0.0-1 [`15cfe9c`](https://github.com/pagopa/io-app-design-system/commit/15cfe9ccbfa743e9252e13e0687f482dbeb07a58) -#### [v2.0.0-0](https://github.com/pagopa/io-app-design-system/compare/v1.46.1...v2.0.0-0) +#### [v2.0.0-0](https://github.com/pagopa/io-app-design-system/compare/v1.46.2...v2.0.0-0) > 31 July 2024 - [IOAPPX-349] Add the new `IOText` component with support for advanced a11y features [`#312`](https://github.com/pagopa/io-app-design-system/pull/312) - chore: release 2.0.0-0 [`7227d4b`](https://github.com/pagopa/io-app-design-system/commit/7227d4bee6d1fe913973a5a35e3308555d0101bb) +#### [v1.46.2](https://github.com/pagopa/io-app-design-system/compare/v1.46.1...v1.46.2) + +> 19 September 2024 + +- feat: [EUDIW-54] Add new pictograms for EUDIW app [`#332`](https://github.com/pagopa/io-app-design-system/pull/332) +- feat: [PE-680] Change purple badge colors [`#333`](https://github.com/pagopa/io-app-design-system/pull/333) +- chore: release 1.46.2 [`492b8a6`](https://github.com/pagopa/io-app-design-system/commit/492b8a67d452c93b47b6a3ca23a1dd3d191b267f) + #### [v1.46.1](https://github.com/pagopa/io-app-design-system/compare/v1.46.0...v1.46.1) > 11 September 2024 diff --git a/package.json b/package.json index bae903e2..75626b41 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@pagopa/io-app-design-system", - "version": "1.46.2", + "version": "1.47.0", "description": "The library defining the core components of the design system of @pagopa/io-app", "main": "lib/commonjs/index", "module": "lib/module/index", From 4f33fae9cea941e012478c9e173b62273e50fb44 Mon Sep 17 00:00:00 2001 From: Damiano Plebani Date: Tue, 15 Oct 2024 15:54:11 +0200 Subject: [PATCH 05/11] [IOAPPX-398] Add dark mode compatibility to `HeaderSecondLevel` (#335) ## Short description This PR adds dark mode compatibility to the `HeaderSecondLevel` ## List of changes proposed in this pull request - Replace previous default colors with new ones based on the theme ### Preview https://github.com/user-attachments/assets/5558dd78-beaf-4186-b09c-06681e61a28c ## How to test Launch the example app and visit each screen related to the **Header Second Level** --- example/src/navigation/navigator.tsx | 4 ++-- example/src/pages/HeaderSecondLevel.tsx | 24 +++++++++++-------- .../HeaderSecondLevelDiscreteTransition.tsx | 6 ++++- .../src/pages/HeaderSecondLevelForModal.tsx | 6 ++++- .../pages/HeaderSecondLevelWithStepper.tsx | 6 ++++- example/src/pages/StaticHeaderSecondLevel.tsx | 8 +++++-- src/components/layout/HeaderSecondLevel.tsx | 18 ++++++++++---- src/core/IOColors.ts | 3 +++ 8 files changed, 53 insertions(+), 22 deletions(-) diff --git a/example/src/navigation/navigator.tsx b/example/src/navigation/navigator.tsx index 045af8f1..b80a2cec 100644 --- a/example/src/navigation/navigator.tsx +++ b/example/src/navigation/navigator.tsx @@ -49,7 +49,7 @@ import { Sandbox } from "../pages/Sandbox"; import { SearchCustom } from "../pages/SearchCustom"; import { SearchNative } from "../pages/SearchNative"; import { Selection } from "../pages/Selection"; -import { StaticHeaderSecondLevelScreen } from "../pages/StaticHeaderSecondLevel"; +import { HeaderSecondLevelScreenStatic } from "../pages/StaticHeaderSecondLevel"; import { StepperPage } from "../pages/Stepper"; import { TabNavigationScreen } from "../pages/TabNavigation"; import { TextInputs } from "../pages/TextInputs"; @@ -401,7 +401,7 @@ const AppNavigator = () => { { const insets = useSafeAreaInsets(); const navigation = useNavigation(); + const theme = useIOTheme(); const getTitleHeight = (event: LayoutChangeEvent) => { const { height } = event.nativeEvent.layout; @@ -122,7 +124,9 @@ export const HeaderSecondLevelScreen = () => { onLayout={getTitleHeight} // style={{ backgroundColor: IOColors["hanPurple-500"] }} > -

Questo è un titolo lungo, ma lungo lungo davvero, eh!

+

+ Questo è un titolo lungo, ma lungo lungo davvero, eh! +

{["info", "warning", "error"].map(variant => ( diff --git a/example/src/pages/HeaderSecondLevelDiscreteTransition.tsx b/example/src/pages/HeaderSecondLevelDiscreteTransition.tsx index bb5ee453..31d45100 100644 --- a/example/src/pages/HeaderSecondLevelDiscreteTransition.tsx +++ b/example/src/pages/HeaderSecondLevelDiscreteTransition.tsx @@ -3,6 +3,7 @@ import { H3, HeaderSecondLevel, IOVisualCostants, + useIOTheme, VSpacer } from "@pagopa/io-app-design-system"; import { useNavigation } from "@react-navigation/native"; @@ -15,6 +16,7 @@ import { useSafeAreaInsets } from "react-native-safe-area-context"; export const HeaderSecondLevelScreenDiscreteTransition = () => { const insets = useSafeAreaInsets(); const navigation = useNavigation(); + const theme = useIOTheme(); const animatedScrollViewRef = useAnimatedRef(); @@ -63,7 +65,9 @@ export const HeaderSecondLevelScreenDiscreteTransition = () => { }} scrollEventThrottle={8} > -

Questo è un titolo lungo, ma lungo lungo davvero, eh!

+

+ Questo è un titolo lungo, ma lungo lungo davvero, eh! +

{[...Array(50)].map((_el, i) => ( Repeated text diff --git a/example/src/pages/HeaderSecondLevelForModal.tsx b/example/src/pages/HeaderSecondLevelForModal.tsx index a60949a8..b21e8dd5 100644 --- a/example/src/pages/HeaderSecondLevelForModal.tsx +++ b/example/src/pages/HeaderSecondLevelForModal.tsx @@ -12,6 +12,7 @@ import { H3, HeaderSecondLevel, IOVisualCostants, + useIOTheme, VSpacer } from "@pagopa/io-app-design-system"; @@ -26,6 +27,7 @@ export const HeaderSecondLevelScreen = () => { const insets = useSafeAreaInsets(); const navigation = useNavigation(); + const theme = useIOTheme(); const getTitleHeight = (event: LayoutChangeEvent) => { const { height } = event.nativeEvent.layout; @@ -94,7 +96,9 @@ export const HeaderSecondLevelScreen = () => { onLayout={getTitleHeight} // style={{ backgroundColor: IOColors["hanPurple-500"] }} > -

Questo è un titolo lungo, ma lungo lungo davvero, eh!

+

+ Questo è un titolo lungo, ma lungo lungo davvero, eh! +

{[...Array(50)].map((_el, i) => ( diff --git a/example/src/pages/HeaderSecondLevelWithStepper.tsx b/example/src/pages/HeaderSecondLevelWithStepper.tsx index 5eab9661..4ab83b1c 100644 --- a/example/src/pages/HeaderSecondLevelWithStepper.tsx +++ b/example/src/pages/HeaderSecondLevelWithStepper.tsx @@ -13,6 +13,7 @@ import { HeaderSecondLevel, IOVisualCostants, Stepper, + useIOTheme, VSpacer } from "@pagopa/io-app-design-system"; @@ -27,6 +28,7 @@ export const HeaderSecondLevelWithStepper = () => { const insets = useSafeAreaInsets(); const navigation = useNavigation(); + const theme = useIOTheme(); const getTitleHeight = (event: LayoutChangeEvent) => { const { height } = event.nativeEvent.layout; @@ -74,7 +76,9 @@ export const HeaderSecondLevelWithStepper = () => { decelerationRate="normal" > -

Questo è un titolo lungo, ma lungo lungo davvero, eh!

+

+ Questo è un titolo lungo, ma lungo lungo davvero, eh! +

{[...Array(50)].map((_el, i) => ( diff --git a/example/src/pages/StaticHeaderSecondLevel.tsx b/example/src/pages/StaticHeaderSecondLevel.tsx index 44a31e35..fbeba790 100644 --- a/example/src/pages/StaticHeaderSecondLevel.tsx +++ b/example/src/pages/StaticHeaderSecondLevel.tsx @@ -12,13 +12,14 @@ import { H3, HeaderSecondLevel, IOVisualCostants, + useIOTheme, VSpacer } from "@pagopa/io-app-design-system"; // This is defined as about the half of a default ListItem… component const defaultTriggerOffsetValue: number = 32; -export const StaticHeaderSecondLevelScreen = () => { +export const HeaderSecondLevelScreenStatic = () => { const [triggerOffsetValue, setTriggerOffsetValue] = useState( defaultTriggerOffsetValue ); @@ -26,6 +27,7 @@ export const StaticHeaderSecondLevelScreen = () => { const insets = useSafeAreaInsets(); const navigation = useNavigation(); + const theme = useIOTheme(); const getTitleHeight = (event: LayoutChangeEvent) => { const { height } = event.nativeEvent.layout; @@ -77,7 +79,9 @@ export const StaticHeaderSecondLevelScreen = () => { decelerationRate="normal" > -

Questo è un titolo lungo, ma lungo lungo davvero, eh!

+

+ Questo è un titolo lungo, ma lungo lungo davvero, eh! +

{[...Array(50)].map((_el, i) => ( diff --git a/src/components/layout/HeaderSecondLevel.tsx b/src/components/layout/HeaderSecondLevel.tsx index ae47e249..e95acc0e 100644 --- a/src/components/layout/HeaderSecondLevel.tsx +++ b/src/components/layout/HeaderSecondLevel.tsx @@ -30,7 +30,8 @@ import { hexToRgba, iconBtnSizeSmall, useIOExperimentalDesign, - useIOTheme + useIOTheme, + useIOThemeContext } from "../../core"; import type { IOSpacer, IOSpacingScale } from "../../core/IOSpacing"; import { makeFontStyleObject } from "../../utils/fonts"; @@ -166,19 +167,24 @@ export const HeaderSecondLevel = ({ const { isExperimental } = useIOExperimentalDesign(); const theme = useIOTheme(); + const { themeType } = useIOThemeContext(); const insets = useSafeAreaInsets(); const isTitleAccessible = React.useMemo(() => !!title.trim(), [title]); const paddingTop = useSharedValue(ignoreSafeAreaMargin ? 0 : insets.top); + const iconButtonColorDefault: ComponentProps["color"] = + themeType === "dark" ? "contrast" : "neutral"; + const iconButtonColor: ComponentProps["color"] = - variant === "neutral" ? "neutral" : "contrast"; + variant === "contrast" ? "contrast" : iconButtonColorDefault; + const titleColor: ColorValue = variant === "neutral" ? IOColors[theme["textHeading-default"]] : IOColors.white; /* Visual attributes when there are transitions between states */ - const HEADER_DEFAULT_BG_COLOR: IOColors = "white"; + const HEADER_DEFAULT_BG_COLOR: IOColors = theme["appBackground-primary"]; const headerBgColorTransparentState = backgroundColor ? hexToRgba(backgroundColor, 0) @@ -189,10 +195,12 @@ export const HeaderSecondLevel = ({ const headerBgColorSolidState = backgroundColor ?? IOColors[HEADER_DEFAULT_BG_COLOR]; + const borderColorDefault = IOColors[theme["divider-default"]]; + const borderColorTransparentState = backgroundColor ? hexToRgba(backgroundColor, 0) - : hexToRgba(IOColors["grey-100"], 0); - const borderColorSolidState = backgroundColor ?? IOColors["grey-100"]; + : hexToRgba(borderColorDefault, 0); + const borderColorSolidState = backgroundColor ?? borderColorDefault; useLayoutEffect(() => { if (isTitleAccessible) { diff --git a/src/core/IOColors.ts b/src/core/IOColors.ts index 3f226c06..a39329a3 100644 --- a/src/core/IOColors.ts +++ b/src/core/IOColors.ts @@ -275,6 +275,7 @@ export type IOTheme = { "icon-default": IOColors; "icon-decorative": IOColors; // Layout + "divider-header": IOColors; "divider-default": IOColors; "divider-bottomBar": IOColors; // Status @@ -306,6 +307,7 @@ export const IOThemeLight: IOTheme = { "icon-default": "grey-650", "icon-decorative": "grey-300", // Layout + "divider-header": "grey-100", "divider-default": "grey-200", "divider-bottomBar": "grey-200", // Status @@ -343,6 +345,7 @@ export const IOThemeDark: IOTheme = { "cardBorder-default": "grey-850", "icon-default": "grey-450", // Layout + "divider-header": "grey-850", "divider-default": "grey-850", "divider-bottomBar": "grey-850", // Status From 49173c4f3c232303cab4e2e4799d21ef7032274c Mon Sep 17 00:00:00 2001 From: Damiano Plebani Date: Tue, 15 Oct 2024 16:01:39 +0200 Subject: [PATCH 06/11] chore: release 1.47.1 --- CHANGELOG.md | 13 +++++++++++-- package.json | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21925d38..b64342c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,13 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). -#### [v1.47.0](https://github.com/pagopa/io-app-design-system/compare/v2.0.1...v1.47.0) +#### [v1.47.1](https://github.com/pagopa/io-app-design-system/compare/v2.0.1...v1.47.1) +- [IOAPPX-398] Add dark mode compatibility to `HeaderSecondLevel` [`#335`](https://github.com/pagopa/io-app-design-system/pull/335) - [IOAPPX-353] Add the new `FooterActions` (from `io-app`) and `FooterActionsInline` [`#316`](https://github.com/pagopa/io-app-design-system/pull/316) - feat: [EUDIW-54] Add new pictograms for EUDIW app [`#332`](https://github.com/pagopa/io-app-design-system/pull/332) - chore: release 1.46.2 [`492b8a6`](https://github.com/pagopa/io-app-design-system/commit/492b8a67d452c93b47b6a3ca23a1dd3d191b267f) +- chore: release 1.47.0 [`5b3f8a6`](https://github.com/pagopa/io-app-design-system/commit/5b3f8a650fa3c7573000eb35a332d0906d0551ed) #### [v2.0.1](https://github.com/pagopa/io-app-design-system/compare/v2.0.0...v2.0.1) @@ -44,13 +46,20 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - [IOAPPX-362] Change `Label…` default weight to Semibold + Fix autocomplete of `IOText` when using `font` prop [`#322`](https://github.com/pagopa/io-app-design-system/pull/322) - chore: release 2.0.0-1 [`15cfe9c`](https://github.com/pagopa/io-app-design-system/commit/15cfe9ccbfa743e9252e13e0687f482dbeb07a58) -#### [v2.0.0-0](https://github.com/pagopa/io-app-design-system/compare/v1.46.2...v2.0.0-0) +#### [v2.0.0-0](https://github.com/pagopa/io-app-design-system/compare/v1.47.0...v2.0.0-0) > 31 July 2024 - [IOAPPX-349] Add the new `IOText` component with support for advanced a11y features [`#312`](https://github.com/pagopa/io-app-design-system/pull/312) - chore: release 2.0.0-0 [`7227d4b`](https://github.com/pagopa/io-app-design-system/commit/7227d4bee6d1fe913973a5a35e3308555d0101bb) +#### [v1.47.0](https://github.com/pagopa/io-app-design-system/compare/v1.46.2...v1.47.0) + +> 9 October 2024 + +- [IOAPPX-353] Add the new `FooterActions` (from `io-app`) and `FooterActionsInline` [`#316`](https://github.com/pagopa/io-app-design-system/pull/316) +- chore: release 1.47.0 [`5b3f8a6`](https://github.com/pagopa/io-app-design-system/commit/5b3f8a650fa3c7573000eb35a332d0906d0551ed) + #### [v1.46.2](https://github.com/pagopa/io-app-design-system/compare/v1.46.1...v1.46.2) > 19 September 2024 diff --git a/package.json b/package.json index 75626b41..d81646d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@pagopa/io-app-design-system", - "version": "1.47.0", + "version": "1.47.1", "description": "The library defining the core components of the design system of @pagopa/io-app", "main": "lib/commonjs/index", "module": "lib/module/index", From f3072ac5493c0a34a4c4caa1355f5a8c86a19d57 Mon Sep 17 00:00:00 2001 From: Damiano Plebani Date: Wed, 16 Oct 2024 11:26:54 +0200 Subject: [PATCH 07/11] [IOAPPX-400] Add `testID` to `ContentWrapper` (#336) ## Short description This PR adds `testID` prop to the `ContentWrapper` component. ## How to test N/A --- src/components/contentWrapper/ContentWrapper.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/contentWrapper/ContentWrapper.tsx b/src/components/contentWrapper/ContentWrapper.tsx index e9aaa92c..ea24e0cd 100644 --- a/src/components/contentWrapper/ContentWrapper.tsx +++ b/src/components/contentWrapper/ContentWrapper.tsx @@ -1,12 +1,13 @@ import React from "react"; import { View } from "react-native"; +import { WithTestID } from "src/utils/types"; import type { IOAppMargin } from "../../core"; import { IOVisualCostants } from "../../core/IOStyles"; -type IOContentWrapperProps = { +type IOContentWrapperProps = WithTestID<{ margin?: IOAppMargin; children: React.ReactNode; -}; +}>; /** `ContentWrapper` is the main wrapper of the application. It automatically sets side margins, @@ -15,9 +16,11 @@ depending on the size value */ export const ContentWrapper = ({ margin = IOVisualCostants.appMarginDefault, + testID, children }: IOContentWrapperProps) => ( Date: Wed, 16 Oct 2024 11:28:25 +0200 Subject: [PATCH 08/11] chore: release 1.47.2 --- CHANGELOG.md | 13 +++++++++++-- package.json | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b64342c4..7d4ae120 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,13 +4,15 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). -#### [v1.47.1](https://github.com/pagopa/io-app-design-system/compare/v2.0.1...v1.47.1) +#### [v1.47.2](https://github.com/pagopa/io-app-design-system/compare/v2.0.1...v1.47.2) +- [IOAPPX-400] Add `testID` to `ContentWrapper` [`#336`](https://github.com/pagopa/io-app-design-system/pull/336) - [IOAPPX-398] Add dark mode compatibility to `HeaderSecondLevel` [`#335`](https://github.com/pagopa/io-app-design-system/pull/335) - [IOAPPX-353] Add the new `FooterActions` (from `io-app`) and `FooterActionsInline` [`#316`](https://github.com/pagopa/io-app-design-system/pull/316) - feat: [EUDIW-54] Add new pictograms for EUDIW app [`#332`](https://github.com/pagopa/io-app-design-system/pull/332) - chore: release 1.46.2 [`492b8a6`](https://github.com/pagopa/io-app-design-system/commit/492b8a67d452c93b47b6a3ca23a1dd3d191b267f) - chore: release 1.47.0 [`5b3f8a6`](https://github.com/pagopa/io-app-design-system/commit/5b3f8a650fa3c7573000eb35a332d0906d0551ed) +- chore: release 1.47.1 [`49173c4`](https://github.com/pagopa/io-app-design-system/commit/49173c4f3c232303cab4e2e4799d21ef7032274c) #### [v2.0.1](https://github.com/pagopa/io-app-design-system/compare/v2.0.0...v2.0.1) @@ -46,13 +48,20 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - [IOAPPX-362] Change `Label…` default weight to Semibold + Fix autocomplete of `IOText` when using `font` prop [`#322`](https://github.com/pagopa/io-app-design-system/pull/322) - chore: release 2.0.0-1 [`15cfe9c`](https://github.com/pagopa/io-app-design-system/commit/15cfe9ccbfa743e9252e13e0687f482dbeb07a58) -#### [v2.0.0-0](https://github.com/pagopa/io-app-design-system/compare/v1.47.0...v2.0.0-0) +#### [v2.0.0-0](https://github.com/pagopa/io-app-design-system/compare/v1.47.1...v2.0.0-0) > 31 July 2024 - [IOAPPX-349] Add the new `IOText` component with support for advanced a11y features [`#312`](https://github.com/pagopa/io-app-design-system/pull/312) - chore: release 2.0.0-0 [`7227d4b`](https://github.com/pagopa/io-app-design-system/commit/7227d4bee6d1fe913973a5a35e3308555d0101bb) +#### [v1.47.1](https://github.com/pagopa/io-app-design-system/compare/v1.47.0...v1.47.1) + +> 15 October 2024 + +- [IOAPPX-398] Add dark mode compatibility to `HeaderSecondLevel` [`#335`](https://github.com/pagopa/io-app-design-system/pull/335) +- chore: release 1.47.1 [`49173c4`](https://github.com/pagopa/io-app-design-system/commit/49173c4f3c232303cab4e2e4799d21ef7032274c) + #### [v1.47.0](https://github.com/pagopa/io-app-design-system/compare/v1.46.2...v1.47.0) > 9 October 2024 diff --git a/package.json b/package.json index d81646d0..0c7bc46a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@pagopa/io-app-design-system", - "version": "1.47.1", + "version": "1.47.2", "description": "The library defining the core components of the design system of @pagopa/io-app", "main": "lib/commonjs/index", "module": "lib/module/index", From 309df9eef2fcb131357aa36910f42fda37de8f89 Mon Sep 17 00:00:00 2001 From: Damiano Plebani Date: Mon, 21 Oct 2024 11:21:16 +0200 Subject: [PATCH 09/11] [IOAPPX-402] Add full dark mode support to `ListItemTransaction` (#337) --- src/components/listitems/ListItemTransaction.tsx | 7 +++++-- src/core/IOColors.ts | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/listitems/ListItemTransaction.tsx b/src/components/listitems/ListItemTransaction.tsx index 91210af1..ee51c7e9 100644 --- a/src/components/listitems/ListItemTransaction.tsx +++ b/src/components/listitems/ListItemTransaction.tsx @@ -142,6 +142,9 @@ export const ListItemTransaction = ({ ? theme["interactiveElem-default"] : "blue"; + const amountColor: IOColors = theme["textBody-default"]; + const successColor: IOColors = theme.successText; + const ListItemTransactionContent = () => { const TransactionAmountOrBadgeComponent = () => { switch (transactionStatus) { @@ -149,7 +152,7 @@ export const ListItemTransaction = ({ return (
{transactionAmount || ""} @@ -159,7 +162,7 @@ export const ListItemTransaction = ({ return (
{transactionAmount || ""} diff --git a/src/core/IOColors.ts b/src/core/IOColors.ts index a39329a3..74984f75 100644 --- a/src/core/IOColors.ts +++ b/src/core/IOColors.ts @@ -281,6 +281,7 @@ export type IOTheme = { // Status errorIcon: IOColors; errorText: IOColors; + successText: IOColors; // Pictograms "pictogram-hands": IOColors; "pictogram-tint-main": IOColors; @@ -313,6 +314,7 @@ export const IOThemeLight: IOTheme = { // Status errorIcon: "error-600", errorText: "error-600", + successText: "success-700", // Pictograms "pictogram-hands": "blueIO-500", "pictogram-tint-main": "turquoise-150", @@ -351,6 +353,7 @@ export const IOThemeDark: IOTheme = { // Status errorIcon: "error-400", errorText: "error-400", + successText: "success-400", // Pictograms "pictogram-hands": "white", "pictogram-tint-main": "turquoise-150", From 382df275569da0f95b0d0f896a77361b493a072f Mon Sep 17 00:00:00 2001 From: Damiano Plebani Date: Mon, 21 Oct 2024 16:39:45 +0200 Subject: [PATCH 10/11] Make the `2.x` version the official, latest release. (#339) --- CHANGELOG.md | 13 +- example/src/pages/Advice.tsx | 19 +- example/src/pages/Alert.tsx | 5 +- example/src/pages/Buttons.tsx | 37 +- example/src/pages/Colors.tsx | 12 +- example/src/pages/Icons.tsx | 44 +- example/src/pages/Layout.tsx | 6 +- example/src/pages/ListItem.tsx | 75 +- example/src/pages/Logos.tsx | 67 +- example/src/pages/MainScreen.tsx | 14 +- example/src/pages/Modules.tsx | 61 +- example/src/pages/Pictograms.tsx | 274 ++++---- example/src/pages/Typography.tsx | 174 +++-- jestSetup.js | 7 +- package.json | 2 +- .../__snapshots__/advice.test.tsx.snap | 40 +- src/components/accordion/AccordionItem.tsx | 16 +- src/components/alert/Alert.tsx | 23 +- src/components/alert/AlertEdgeToEdge.tsx | 8 +- src/components/badge/Badge.tsx | 46 +- .../__snapshots__/badge.test.tsx.snap | 38 +- src/components/badge/__test__/badge.test.tsx | 4 +- .../__snapshots__/banner.test.tsx.snap | 52 +- src/components/buttons/ButtonLink.tsx | 47 +- src/components/buttons/ButtonOutline.tsx | 39 +- .../__snapshots__/button.test.tsx.snap | 105 ++- src/components/featureInfo/FeatureInfo.tsx | 26 +- src/components/layout/HeaderSecondLevel.tsx | 27 +- src/components/listitems/ListItemAction.tsx | 88 +-- src/components/listitems/ListItemAmount.tsx | 7 +- src/components/listitems/ListItemSwitch.tsx | 6 +- .../__snapshots__/listitem.test.tsx.snap | 430 +++--------- src/components/modules/ModuleIDP.tsx | 47 +- .../__snapshots__/NumberPad.test.tsx.snap | 180 +---- src/components/searchInput/SearchInput.tsx | 20 +- src/components/switch/SwitchLabel.tsx | 38 +- src/components/tabs/TabItem.tsx | 6 +- src/components/tag/Tag.tsx | 46 +- src/components/textInput/TextInputBase.tsx | 29 +- .../ToastNotification.test.tsx.snap | 288 +++----- src/components/typography/BaseTypography.tsx | 17 +- src/components/typography/Body.tsx | 81 ++- src/components/typography/BodyMonospace.tsx | 61 +- src/components/typography/ButtonText.tsx | 60 +- src/components/typography/Caption.tsx | 64 +- src/components/typography/Chip.tsx | 62 +- src/components/typography/Factory.tsx | 1 + src/components/typography/H1.tsx | 67 +- src/components/typography/H2.tsx | 67 +- src/components/typography/H3.tsx | 65 +- src/components/typography/H4.tsx | 67 +- src/components/typography/H5.tsx | 58 +- src/components/typography/H6.tsx | 71 +- src/components/typography/Hero.tsx | 63 +- src/components/typography/IOText.tsx | 157 +++++ src/components/typography/Label.tsx | 89 ++- src/components/typography/LabelHeader.tsx | 56 -- src/components/typography/LabelLink.tsx | 61 -- src/components/typography/LabelMini.tsx | 52 ++ src/components/typography/LabelSmall.tsx | 104 ++- src/components/typography/LabelSmallAlt.tsx | 76 +- .../__snapshots__/typography.test.tsx.snap | 649 +++--------------- .../typography/__test__/typography.test.tsx | 38 +- src/components/typography/index.tsx | 6 +- src/components/typography/markdown/MdH1.tsx | 54 +- src/components/typography/markdown/MdH2.tsx | 57 +- src/components/typography/markdown/MdH3.tsx | 53 +- src/components/typography/markdown/MdH4.tsx | 34 - src/components/typography/markdown/MdH5.tsx | 32 - src/components/typography/markdown/MdH6.tsx | 33 - src/core/IOColors.ts | 60 +- src/core/IOStyles.ts | 6 +- src/utils/accessibility.ts | 34 + src/utils/fonts.ts | 144 ++-- stories/featureInfo/FeatureInfo.stories.ts | 8 +- stories/foundation/typography/Link.stories.ts | 28 - 76 files changed, 1855 insertions(+), 3246 deletions(-) create mode 100644 src/components/typography/IOText.tsx delete mode 100644 src/components/typography/LabelHeader.tsx delete mode 100644 src/components/typography/LabelLink.tsx create mode 100644 src/components/typography/LabelMini.tsx delete mode 100644 src/components/typography/markdown/MdH4.tsx delete mode 100644 src/components/typography/markdown/MdH5.tsx delete mode 100644 src/components/typography/markdown/MdH6.tsx delete mode 100644 stories/foundation/typography/Link.stories.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d4ae120..34958a8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). -#### [v1.47.2](https://github.com/pagopa/io-app-design-system/compare/v2.0.1...v1.47.2) +#### [v2.0.2](https://github.com/pagopa/io-app-design-system/compare/v2.0.1...v2.0.2) - [IOAPPX-400] Add `testID` to `ContentWrapper` [`#336`](https://github.com/pagopa/io-app-design-system/pull/336) - [IOAPPX-398] Add dark mode compatibility to `HeaderSecondLevel` [`#335`](https://github.com/pagopa/io-app-design-system/pull/335) @@ -12,7 +12,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - feat: [EUDIW-54] Add new pictograms for EUDIW app [`#332`](https://github.com/pagopa/io-app-design-system/pull/332) - chore: release 1.46.2 [`492b8a6`](https://github.com/pagopa/io-app-design-system/commit/492b8a67d452c93b47b6a3ca23a1dd3d191b267f) - chore: release 1.47.0 [`5b3f8a6`](https://github.com/pagopa/io-app-design-system/commit/5b3f8a650fa3c7573000eb35a332d0906d0551ed) -- chore: release 1.47.1 [`49173c4`](https://github.com/pagopa/io-app-design-system/commit/49173c4f3c232303cab4e2e4799d21ef7032274c) +- chore: release 1.47.2 [`2ccec35`](https://github.com/pagopa/io-app-design-system/commit/2ccec35de737493b3092592fe63911c77e1abef3) #### [v2.0.1](https://github.com/pagopa/io-app-design-system/compare/v2.0.0...v2.0.1) @@ -48,13 +48,20 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - [IOAPPX-362] Change `Label…` default weight to Semibold + Fix autocomplete of `IOText` when using `font` prop [`#322`](https://github.com/pagopa/io-app-design-system/pull/322) - chore: release 2.0.0-1 [`15cfe9c`](https://github.com/pagopa/io-app-design-system/commit/15cfe9ccbfa743e9252e13e0687f482dbeb07a58) -#### [v2.0.0-0](https://github.com/pagopa/io-app-design-system/compare/v1.47.1...v2.0.0-0) +#### [v2.0.0-0](https://github.com/pagopa/io-app-design-system/compare/v1.47.2...v2.0.0-0) > 31 July 2024 - [IOAPPX-349] Add the new `IOText` component with support for advanced a11y features [`#312`](https://github.com/pagopa/io-app-design-system/pull/312) - chore: release 2.0.0-0 [`7227d4b`](https://github.com/pagopa/io-app-design-system/commit/7227d4bee6d1fe913973a5a35e3308555d0101bb) +#### [v1.47.2](https://github.com/pagopa/io-app-design-system/compare/v1.47.1...v1.47.2) + +> 16 October 2024 + +- [IOAPPX-400] Add `testID` to `ContentWrapper` [`#336`](https://github.com/pagopa/io-app-design-system/pull/336) +- chore: release 1.47.2 [`2ccec35`](https://github.com/pagopa/io-app-design-system/commit/2ccec35de737493b3092592fe63911c77e1abef3) + #### [v1.47.1](https://github.com/pagopa/io-app-design-system/compare/v1.47.0...v1.47.1) > 15 October 2024 diff --git a/example/src/pages/Advice.tsx b/example/src/pages/Advice.tsx index d9d3588d..9064af65 100644 --- a/example/src/pages/Advice.tsx +++ b/example/src/pages/Advice.tsx @@ -48,9 +48,7 @@ export const DSAdvice = () => ( const renderFeatureInfo = () => ( <> -

- FeatureInfo -

+

FeatureInfo

( @@ -93,8 +94,10 @@ const renderFeatureInfo = () => ( body={ "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor ut labore et dolore magna aliqua. sed do eiusmod tempor ut labore et dolore magna aliqua" } - actionLabel="Scopri di più" - actionOnPress={onLinkPress} + action={{ + label: "Scopri di più", + onPress: onLinkPress + }} /> @@ -103,8 +106,6 @@ const renderFeatureInfo = () => ( const renderBanner = () => ( <>

{

{ -

+

Content + Action

@@ -288,7 +287,7 @@ export const DSAlert = () => { {/* Full width */} -

+

Full width

diff --git a/example/src/pages/Buttons.tsx b/example/src/pages/Buttons.tsx index d308454d..553e4259 100644 --- a/example/src/pages/Buttons.tsx +++ b/example/src/pages/Buttons.tsx @@ -44,7 +44,6 @@ export const Buttons = () => { {/* The title should be dynamic, got from the route object */}

{ -

+

ButtonOutline

@@ -449,11 +444,7 @@ export const Buttons = () => { -

+

ButtonLink

@@ -594,11 +585,7 @@ export const Buttons = () => { -

+

IconButton

@@ -707,11 +694,7 @@ export const Buttons = () => { -

+

IconButtonSolid

@@ -775,11 +758,7 @@ export const Buttons = () => { -

+

IconButtonContained (Icebox)

@@ -861,11 +840,7 @@ export const Buttons = () => { -

+

Specific buttons

diff --git a/example/src/pages/Colors.tsx b/example/src/pages/Colors.tsx index a99a0a42..339073ab 100644 --- a/example/src/pages/Colors.tsx +++ b/example/src/pages/Colors.tsx @@ -11,6 +11,7 @@ import { IOThemeDark, IOThemeLight, IOVisualCostants, + LabelMini, LabelSmall, VSpacer, hexToRgba, @@ -263,11 +264,7 @@ export const Colors = () => ( )} {/* Gradients */} -

+

Gradients

@@ -309,14 +306,13 @@ const ColorBox = ({ {name && ( - {name} - + )} ); diff --git a/example/src/pages/Icons.tsx b/example/src/pages/Icons.tsx index ab76d12e..362c1d2e 100644 --- a/example/src/pages/Icons.tsx +++ b/example/src/pages/Icons.tsx @@ -100,11 +100,7 @@ export const Icons = () => { /> ))} -

+

Navigation

@@ -123,11 +119,7 @@ export const Icons = () => { /> ))} -

+

System

@@ -146,11 +138,7 @@ export const Icons = () => { /> ))} -

+

Biometric

@@ -169,11 +157,7 @@ export const Icons = () => { /> ))} -

+

Categories

@@ -192,13 +176,7 @@ export const Icons = () => { /> ))} -

- Product -

+

Product

{Object.entries(IOProductIcons).map(([iconItemName]) => ( { ))} -

- IconContained -

+

IconContained

@@ -227,9 +203,7 @@ export const Icons = () => { -

- Sizes -

+

Sizes

{/* If you want to render another icon in different sizes, just change the name below */} @@ -247,9 +221,7 @@ export const Icons = () => { /> ))} -

- Colors -

+

Colors

{IOIconColors.map(color => ( { }} > Content example - {value} - + diff --git a/example/src/pages/ListItem.tsx b/example/src/pages/ListItem.tsx index c97c2f09..f0b20461 100644 --- a/example/src/pages/ListItem.tsx +++ b/example/src/pages/ListItem.tsx @@ -16,8 +16,7 @@ import { ListItemTransactionLogo, ListItemTransactionStatusWithBadge, VSpacer, - useIOExperimentalDesign, - useIOTheme + useIOExperimentalDesign } from "@pagopa/io-app-design-system"; import * as React from "react"; import { Alert, View } from "react-native"; @@ -30,16 +29,10 @@ const onButtonPress = () => { export const ListItems = () => { const { isExperimental, setExperimental } = useIOExperimentalDesign(); - const theme = useIOTheme(); + return ( -

- ListItemNav -

+

ListItemNav

{ /> {renderListItemNav()} -

- ListItemInfoCopy -

+

ListItemInfoCopy

{renderListItemInfoCopy()} -

- ListItemInfo -

+

ListItemInfo

{renderListItemInfo()} -

- ListItemHeader -

+

ListItemHeader

{renderListItemHeader()} -

- ListItemAmount -

+

ListItemAmount

{renderListItemAmount()} -

- ListItemAction -

+

ListItemAction

{renderListItemAction()} -

- ListItemTransaction -

+

ListItemTransaction

{renderListItemTransaction()} -

- ListItemRadio -

+

ListItemRadio

{renderListItemRadio()} -

+

ListItemRadioWithAmount

{renderListItemRadioWithAmount()} diff --git a/example/src/pages/Logos.tsx b/example/src/pages/Logos.tsx index be97df26..a8181bf2 100644 --- a/example/src/pages/Logos.tsx +++ b/example/src/pages/Logos.tsx @@ -16,8 +16,7 @@ import { LogoPaymentCard, LogoPaymentExt, VSpacer, - hexToRgba, - useIOTheme + hexToRgba } from "@pagopa/io-app-design-system"; import * as React from "react"; import { ScrollView, StyleSheet, View } from "react-native"; @@ -44,54 +43,30 @@ const styles = StyleSheet.create({ } }); -export const Logos = () => { - const theme = useIOTheme(); - - return ( - -

- Avatar -

- {renderAvatar()} +export const Logos = () => ( + +

+ Avatar +

+ {renderAvatar()} - + -

- Payment Networks (Small) -

- {renderPaymentLogosSmall()} +

Payment Networks (Small)

+ {renderPaymentLogosSmall()} -

- Payment Networks (Big) -

- {renderPaymentLogosBig()} +

Payment Networks (Big)

+ {renderPaymentLogosBig()} -

- Payment Networks (Card) -

- {renderPaymentLogosCard()} -
- ); -}; +

Payment Networks (Card)

+ {renderPaymentLogosCard()} +
+); const cdnPath = "https://assets.cdn.io.italia.it/logos/organizations/"; diff --git a/example/src/pages/MainScreen.tsx b/example/src/pages/MainScreen.tsx index dbad4c2d..f455ec41 100644 --- a/example/src/pages/MainScreen.tsx +++ b/example/src/pages/MainScreen.tsx @@ -1,18 +1,18 @@ -import { SectionList, View } from "react-native"; -import * as React from "react"; import { - IOStyles, Divider, H1, + IOStyles, LabelSmall, - VSpacer, ListItemNav, - useIOExperimentalDesign, ListItemSwitch, + VSpacer, + useIOExperimentalDesign, useIOThemeContext } from "@pagopa/io-app-design-system"; -import APP_ROUTES from "../navigation/routes"; +import * as React from "react"; +import { SectionList, View } from "react-native"; import { AppParamsList } from "../navigation/params"; +import APP_ROUTES from "../navigation/routes"; import { IOStackNavigationRouteProps } from "../utils/types"; type Props = IOStackNavigationRouteProps; @@ -76,7 +76,7 @@ const MainScreen = (props: Props) => { section: { title: string; description?: string }; }) => ( -

{title}

+

{title}

{description && ( {description} diff --git a/example/src/pages/Modules.tsx b/example/src/pages/Modules.tsx index d3cfae17..66c338ed 100644 --- a/example/src/pages/Modules.tsx +++ b/example/src/pages/Modules.tsx @@ -8,8 +8,7 @@ import { ModuleNavigation, ModulePaymentNotice, ModuleSummary, - useIOExperimentalDesign, - useIOTheme + useIOExperimentalDesign } from "@pagopa/io-app-design-system"; import * as React from "react"; import { Alert, ImageSourcePropType, View } from "react-native"; @@ -370,7 +369,7 @@ const renderModuleSummary = () => ( const Modules = () => { const { isExperimental, setExperimental } = useIOExperimentalDesign(); - const theme = useIOTheme(); + return ( { value={isExperimental} onSwitchValueChange={setExperimental} /> -

- ModuleIDP -

+

ModuleIDP

{renderModuleIDP()} -

- ModulePaymentNotice -

+

ModulePaymentNotice

{renderModulePaymentNotice()} -

- ModuleSummary -

+

ModuleSummary

{renderModuleSummary()} -

- ModuleCheckout -

+

ModuleCheckout

{renderModuleCheckout()} -

- ModuleAttachment -

+

ModuleAttachment

{renderModuleAttachment()} -

- ModuleCredential -

+

ModuleCredential

{renderModuleCredential()} -

- ModuleNavigation -

+

ModuleNavigation

{renderModuleNavigation()}
); diff --git a/example/src/pages/Pictograms.tsx b/example/src/pages/Pictograms.tsx index 608ee096..dc47cbe0 100644 --- a/example/src/pages/Pictograms.tsx +++ b/example/src/pages/Pictograms.tsx @@ -10,8 +10,7 @@ import { Pictogram, PictogramBleed, SVGPictogramProps, - hexToRgba, - useIOTheme + hexToRgba } from "@pagopa/io-app-design-system"; import * as React from "react"; import { StyleSheet, View } from "react-native"; @@ -71,156 +70,143 @@ const sortedIOPictogramsBleed = sortPictogramSet(IOPictogramsBleed); const sortedIOPictogramsObject = sortPictogramSet(IOPictogramsObject); const sortedIOPictogramsLegacy = sortPictogramSet(IOPictogramsLegacy); -export const Pictograms = () => { - const theme = useIOTheme(); - return ( - -

- Pictograms -

- - {Object.entries(sortedIOPictograms).map(([pictogramItemName]) => ( - - } - /> - ))} - +export const Pictograms = () => ( + +

+ Pictograms +

+ + {Object.entries(sortedIOPictograms).map(([pictogramItemName]) => ( + + } + /> + ))} + -

- Bleed Pictograms -

- - {Object.entries(sortedIOPictogramsBleed).map(([pictogramItemName]) => ( - - } - /> - ))} - +

+ Bleed Pictograms +

+ + {Object.entries(sortedIOPictogramsBleed).map(([pictogramItemName]) => ( + + } + /> + ))} + -

- Objects Pictograms -

- - {Object.entries(sortedIOPictogramsObject).map(([pictogramItemName]) => ( - - } - /> - ))} - +

+ Objects Pictograms +

+ + {Object.entries(sortedIOPictogramsObject).map(([pictogramItemName]) => ( + + } + /> + ))} + -

+ Color mode agnostic +

+ + - Color mode agnostic -

- - - - - - - - - - - - - - - + + + + + -

+ - Legacy Pictograms -

- - {Object.entries(sortedIOPictogramsLegacy).map(([pictogramItemName]) => ( - - } - /> - ))} + + + - - ); -}; + + +

+ Legacy Pictograms +

+ + {Object.entries(sortedIOPictogramsLegacy).map(([pictogramItemName]) => ( + + } + /> + ))} + + +); diff --git a/example/src/pages/Typography.tsx b/example/src/pages/Typography.tsx index 8a30f585..14e5c6bb 100644 --- a/example/src/pages/Typography.tsx +++ b/example/src/pages/Typography.tsx @@ -15,15 +15,12 @@ import { Hero, IOColors, Label, - LabelLink, + LabelMini, LabelSmall, LabelSmallAlt, MdH1, MdH2, MdH3, - MdH4, - MdH5, - MdH6, VSpacer, VStack } from "@pagopa/io-app-design-system"; @@ -41,6 +38,8 @@ const styles = StyleSheet.create({ } }); +const linkOnPress = () => Alert.alert("onPress triggered"); + export const Typography = () => ( @@ -65,15 +64,18 @@ export const Typography = () => ( lorem aliquam, aliquam massa eget, commodo erat. Maecenas finibus dui massa, eget pharetra mauris posuere semper. + Body Semibold + Body Bold + + Body asLink + BodyMonoSpace + - Alert.alert("onPress LabelLink!")}> - LabelLink - @@ -85,9 +87,6 @@ export const Typography = () => ( - - - @@ -204,17 +203,115 @@ export const ChipRow = () => ( ); export const LabelSmallRow = () => ( - - Label small - - Label small - - Label small - - - Label small + <> + + Label small + + Label small + + Label small + + + Label small + + + + Label small asLink + - + + Label small SB + + + Label small SB + + + + Label small SB + + + + + Label small SB + + + + + Label small SB asLink + + + + Label small Regular + + + Label small Regular + + + + Label small Regular + + + + + Label small Regular + + + + + Label small Regular asLink + + + +); + +export const LabelMiniRow = () => ( + <> + + Label mini + + Label mini + + Label mini + + + Label mini + + + + Label mini SB + + + Label mini SB + + + + Label mini SB + + + + + Label mini SB + + + + + Label mini Regular + + + Label mini Regular + + + + Label mini Regular + + + + + Label mini Regular + + + + ); export const LabelSmallAltRow = () => ( @@ -223,7 +320,7 @@ export const LabelSmallAltRow = () => ( Label small alt - + Label small alt @@ -233,9 +330,21 @@ export const LabelRow = () => ( - + + + + + ); @@ -259,24 +368,3 @@ export const MdH3Row = () => ( {getLongerTitle("Markdown H3")} ); - -export const MdH4Row = () => ( - - {getTitle("Markdown H4")} - {getLongerTitle("Markdown H4")} - -); - -export const MdH5Row = () => ( - - {getTitle("Markdown H5")} - {getLongerTitle("Markdown H5")} - -); - -export const MdH6Row = () => ( - - {getTitle("Markdown H6")} - {getLongerTitle("Markdown H6")} - -); diff --git a/jestSetup.js b/jestSetup.js index d0f2607a..d28af3e0 100644 --- a/jestSetup.js +++ b/jestSetup.js @@ -43,4 +43,9 @@ global.fetch = nodeFetch; // eslint-disable-next-line @typescript-eslint/no-explicit-any,functional/immutable-data global.AbortController = AbortController; // eslint-disable-next-line functional/immutable-data, no-underscore-dangle -global.__reanimatedWorkletInit = jest.fn(); \ No newline at end of file +global.__reanimatedWorkletInit = jest.fn(); + +jest.mock("./src/utils/accessibility", () => ({ + useBoldTextEnabled: () => false, + getAccessibleAmountText: t => t +})); diff --git a/package.json b/package.json index 0c7bc46a..f075df1a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@pagopa/io-app-design-system", - "version": "1.47.2", + "version": "2.0.2", "description": "The library defining the core components of the design system of @pagopa/io-app", "main": "lib/commonjs/index", "module": "lib/module/index", diff --git a/src/components/Advice/__test__/__snapshots__/advice.test.tsx.snap b/src/components/Advice/__test__/__snapshots__/advice.test.tsx.snap index 678d98b6..6c9fb1d6 100644 --- a/src/components/Advice/__test__/__snapshots__/advice.test.tsx.snap +++ b/src/components/Advice/__test__/__snapshots__/advice.test.tsx.snap @@ -85,33 +85,21 @@ exports[`Test Advice Components - Experimental Enabled Advice Snapshot 1`] = ` /> Text @@ -203,33 +191,21 @@ exports[`Test Advice Components Advice Snapshot 1`] = ` /> Text diff --git a/src/components/accordion/AccordionItem.tsx b/src/components/accordion/AccordionItem.tsx index a37f9ee6..4d716e4b 100644 --- a/src/components/accordion/AccordionItem.tsx +++ b/src/components/accordion/AccordionItem.tsx @@ -2,7 +2,6 @@ import React, { useState } from "react"; import { LayoutChangeEvent, StyleSheet, - Text, TouchableWithoutFeedback, View } from "react-native"; @@ -19,9 +18,8 @@ import { } from "../../core"; import { IOSpringValues } from "../../core/IOAnimations"; import { IOColors, hexToRgba } from "../../core/IOColors"; -import { makeFontStyleObject } from "../../utils/fonts"; import { IOIconSizeScale, IOIcons, Icon } from "../icons/Icon"; -import { H6 } from "../typography"; +import { Body, H6 } from "../typography"; export type AccordionItem = { title: string; @@ -158,11 +156,7 @@ export const AccordionItem = ({ - {typeof body === "string" ? ( - {body} - ) : ( - body - )} + {typeof body === "string" ? {body} : body} {/* This gradient adds a smooth end to the content. If it is missing, the content will be cut sharply during the height transition. */} @@ -199,12 +193,6 @@ const styles = StyleSheet.create({ padding: accordionBodySpacing, paddingTop: 0 }, - accordionBodyText: { - fontSize: 14, - lineHeight: 21, - color: IOColors["grey-700"], - ...makeFontStyleObject("Regular", undefined, "TitilliumSansPro") - }, textContainer: { padding: accordionBodySpacing, flexDirection: "row", diff --git a/src/components/alert/Alert.tsx b/src/components/alert/Alert.tsx index 6f24aef8..7e6cd341 100644 --- a/src/components/alert/Alert.tsx +++ b/src/components/alert/Alert.tsx @@ -4,7 +4,6 @@ import { PixelRatio, Pressable, StyleSheet, - Text, View } from "react-native"; import Animated, { @@ -15,7 +14,7 @@ import Animated, { useSharedValue, withSpring } from "react-native-reanimated"; -import { IOVisualCostants, useIOExperimentalDesign } from "../../core"; +import { IOVisualCostants } from "../../core"; import { IOScaleValues, IOSpringValues } from "../../core/IOAnimations"; import { IOColors, @@ -24,10 +23,10 @@ import { } from "../../core/IOColors"; import { IOAlertRadius } from "../../core/IOShapes"; import { IOAlertSpacing } from "../../core/IOSpacing"; -import { makeFontStyleObject } from "../../utils/fonts"; import { WithTestID } from "../../utils/types"; import { IOIconSizeScale, IOIcons, Icon } from "../icons"; import { VSpacer } from "../spacer"; +import { ButtonText } from "../typography"; import { H4 } from "../typography/H4"; import { Label } from "../typography/Label"; @@ -48,14 +47,6 @@ const styles = StyleSheet.create({ }, spacingFullWidth: { padding: spacingFullWidth - }, - label: { - fontSize: 16, - ...makeFontStyleObject("Regular", false, "ReadexPro") - }, - labelLegacy: { - fontSize: 16, - ...makeFontStyleObject("Bold", false, "TitilliumSansPro") } }); @@ -129,7 +120,6 @@ export const Alert = React.forwardRef( viewRef ): JSX.Element => { const isPressed: Animated.SharedValue = useSharedValue(0); - const { isExperimental } = useIOExperimentalDesign(); // Scaling transformation applied when the button is pressed const animationScaleValue = IOScaleValues?.magnifiedButton?.pressedState; @@ -198,16 +188,13 @@ export const Alert = React.forwardRef( {action && ( <> - {action} - + )} diff --git a/src/components/alert/AlertEdgeToEdge.tsx b/src/components/alert/AlertEdgeToEdge.tsx index 67eea7d5..fb2472f4 100644 --- a/src/components/alert/AlertEdgeToEdge.tsx +++ b/src/components/alert/AlertEdgeToEdge.tsx @@ -170,8 +170,12 @@ export const AlertEdgeToEdge = ({ {action && ( diff --git a/src/components/badge/Badge.tsx b/src/components/badge/Badge.tsx index f7321814..12f412e2 100644 --- a/src/components/badge/Badge.tsx +++ b/src/components/badge/Badge.tsx @@ -1,16 +1,15 @@ import React from "react"; -import { Platform, StyleSheet, Text, View } from "react-native"; +import { Platform, StyleSheet, View } from "react-native"; import { IOBadgeHSpacing, IOBadgeRadius, IOBadgeVSpacing, IOColors, - IOVisualCostants, useIOExperimentalDesign, useIOTheme } from "../../core"; -import { makeFontStyleObject } from "../../utils/fonts"; import { WithTestID } from "../../utils/types"; +import { IOText } from "../typography"; export type Badge = WithTestID<{ outline?: boolean; @@ -52,20 +51,6 @@ const styles = StyleSheet.create({ borderRadius: IOBadgeRadius, paddingHorizontal: IOBadgeHSpacing, paddingVertical: IOBadgeVSpacing - }, - label: { - fontSize: 12, - lineHeight: 16, - alignSelf: "center", - textTransform: "uppercase", - flexShrink: 1 - }, - labelFont: { - ...makeFontStyleObject("Regular", false, "ReadexPro") - }, - // TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 - legacyLabelFont: { - ...makeFontStyleObject("Semibold", false, "TitilliumSansPro") } }); @@ -178,24 +163,23 @@ export const Badge = ({ text, outline = false, variant, testID }: Badge) => { } ]} > - {text} - + ); }; diff --git a/src/components/badge/__test__/__snapshots__/badge.test.tsx.snap b/src/components/badge/__test__/__snapshots__/badge.test.tsx.snap index 20244e80..1eab52ca 100644 --- a/src/components/badge/__test__/__snapshots__/badge.test.tsx.snap +++ b/src/components/badge/__test__/__snapshots__/badge.test.tsx.snap @@ -21,29 +21,26 @@ exports[`Test Badge Components - Experimental Enabled Badge Snapshot 1`] = ` } > { it("Badge Snapshot", () => { const badge = TestRenderer.create( - + ).toJSON(); expect(badge).toMatchSnapshot(); }); @@ -15,7 +15,7 @@ describe("Test Badge Components", () => { describe("Test Badge Components - Experimental Enabled", () => { it("Badge Snapshot", () => { const badge = TestRendererWithExperimentalEnabledContextProvider( - + ).toJSON(); expect(badge).toMatchSnapshot(); }); diff --git a/src/components/banner/__test__/__snapshots__/banner.test.tsx.snap b/src/components/banner/__test__/__snapshots__/banner.test.tsx.snap index 63446766..1b5aafde 100644 --- a/src/components/banner/__test__/__snapshots__/banner.test.tsx.snap +++ b/src/components/banner/__test__/__snapshots__/banner.test.tsx.snap @@ -73,33 +73,21 @@ exports[`Test Banner Components - Experimental Enabled Banner Snapshot 1`] = ` > Banner title @@ -197,18 +185,18 @@ exports[`Test Banner Components - Experimental Enabled Banner Snapshot 1`] = ` allowFontScaling={true} ellipsizeMode="tail" importantForAccessibility="no-hide-descendants" - maxFontSizeMultiplier={1.3} + maxFontSizeMultiplier={1.25} numberOfLines={1} style={ [ + {}, { + "color": "#0E0F13", "fontFamily": "Readex Pro", "fontSize": 16, "fontStyle": "normal", "fontWeight": "400", - }, - { - "color": "#0B3EE3", + "lineHeight": undefined, }, { "color": undefined, @@ -434,33 +422,21 @@ exports[`Test Banner Components Banner Snapshot 1`] = ` > Banner title @@ -558,18 +534,18 @@ exports[`Test Banner Components Banner Snapshot 1`] = ` allowFontScaling={false} ellipsizeMode="tail" importantForAccessibility="no-hide-descendants" - maxFontSizeMultiplier={1.3} + maxFontSizeMultiplier={1.25} numberOfLines={1} style={ [ + {}, { + "color": "#0E0F13", "fontFamily": "Titillium Sans Pro", "fontSize": 16, "fontStyle": "normal", "fontWeight": "700", - }, - { - "color": "#0073E6", + "lineHeight": undefined, }, { "color": undefined, diff --git a/src/components/buttons/ButtonLink.tsx b/src/components/buttons/ButtonLink.tsx index 737f79c4..2b1e97d8 100644 --- a/src/components/buttons/ButtonLink.tsx +++ b/src/components/buttons/ButtonLink.tsx @@ -1,10 +1,5 @@ import React, { useCallback, useMemo } from "react"; -import { - GestureResponderEvent, - Pressable, - StyleSheet, - View -} from "react-native"; +import { GestureResponderEvent, Pressable, View } from "react-native"; import Animated, { Extrapolate, interpolate, @@ -23,7 +18,6 @@ import { hexToRgba, useIOExperimentalDesign } from "../../core"; -import { makeFontStyleObject } from "../../utils/fonts"; import { WithTestID } from "../../utils/types"; import { AnimatedIcon, @@ -32,7 +26,7 @@ import { IconClassComponent } from "../icons"; import { HSpacer } from "../spacer/Spacer"; -import { buttonTextFontSize } from "../typography"; +import { IOText, buttonTextFontSize } from "../typography"; export type ColorButtonLink = "primary" | "contrast"; @@ -102,20 +96,6 @@ const mapLegacyColorStates: Record< }; const DISABLED_OPACITY = 0.5; -const IOButtonStylesLocal = StyleSheet.create({ - label: { - ...makeFontStyleObject("Regular", false, "ReadexPro"), - fontSize: buttonTextFontSize - } -}); - -// TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 -const IOButtonLegacyStylesLocal = StyleSheet.create({ - label: { - fontSize: 16, - ...makeFontStyleObject("Bold", false, "TitilliumSansPro") - } -}); export const ButtonLink = React.forwardRef( ( @@ -139,10 +119,8 @@ export const ButtonLink = React.forwardRef( () => (isExperimental ? mapColorStates : mapLegacyColorStates), [isExperimental] ); - const buttonStylesLocal = useMemo( - () => (isExperimental ? IOButtonStylesLocal : IOButtonLegacyStylesLocal), - [isExperimental] - ); + + const AnimatedIOText = Animated.createAnimatedComponent(IOText); // Scaling transformation applied when the button is pressed const animationScaleValue = IOScaleValues?.basicButton?.pressedState; @@ -255,24 +233,23 @@ export const ButtonLink = React.forwardRef( )} - {label} - + ); diff --git a/src/components/buttons/ButtonOutline.tsx b/src/components/buttons/ButtonOutline.tsx index 3f1c0f44..877b8a3a 100644 --- a/src/components/buttons/ButtonOutline.tsx +++ b/src/components/buttons/ButtonOutline.tsx @@ -24,7 +24,6 @@ import { hexToRgba, useIOExperimentalDesign } from "../../core/"; -import { makeFontStyleObject } from "../../utils/fonts"; import { WithTestID } from "../../utils/types"; import { AnimatedIcon, @@ -33,7 +32,7 @@ import { IconClassComponent } from "../icons"; import { HSpacer } from "../spacer/Spacer"; -import { buttonTextFontSize } from "../typography"; +import { IOText, buttonTextFontSize } from "../typography"; type ColorButtonOutline = "primary" | "contrast" | "danger"; export type ButtonOutline = WithTestID< @@ -193,11 +192,6 @@ const mapLegacyColorStates: Record< // TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 const IOButtonLegacyStylesLocal = StyleSheet.create({ - // eslint-disable-next-line react-native/no-unused-styles - label: { - ...makeFontStyleObject("Bold") - }, - // eslint-disable-next-line react-native/no-unused-styles buttonWithBorder: { borderWidth: 1 } @@ -209,12 +203,6 @@ const iconSize: IOIconSizeScale = 20; const DISABLED_OPACITY = 0.5; const IOButtonStylesLocal = StyleSheet.create({ - // eslint-disable-next-line react-native/no-unused-styles - label: { - ...makeFontStyleObject("Regular", false, "ReadexPro"), - fontSize: buttonTextFontSize - }, - // eslint-disable-next-line react-native/no-unused-styles buttonWithBorder: { borderWidth: 2 } @@ -239,6 +227,8 @@ export const ButtonOutline = React.forwardRef( const { isExperimental } = useIOExperimentalDesign(); const isPressed: Animated.SharedValue = useSharedValue(0); + const AnimatedIOText = Animated.createAnimatedComponent(IOText); + const colorMap = React.useMemo( () => (isExperimental ? mapColorStates : mapLegacyColorStates), [isExperimental] @@ -383,25 +373,24 @@ export const ButtonOutline = React.forwardRef( )} - {label} - + ); diff --git a/src/components/buttons/__test__/__snapshots__/button.test.tsx.snap b/src/components/buttons/__test__/__snapshots__/button.test.tsx.snap index 65e5ec60..d3fd6131 100644 --- a/src/components/buttons/__test__/__snapshots__/button.test.tsx.snap +++ b/src/components/buttons/__test__/__snapshots__/button.test.tsx.snap @@ -76,18 +76,18 @@ exports[`Test Buttons Components - Experimental Enabled ButtonLink Snapshot 1`] allowFontScaling={true} ellipsizeMode="tail" importantForAccessibility="no-hide-descendants" - maxFontSizeMultiplier={1.3} + maxFontSizeMultiplier={1.25} numberOfLines={1} style={ [ + {}, { + "color": "#0E0F13", "fontFamily": "Readex Pro", "fontSize": 16, "fontStyle": "normal", "fontWeight": "400", - }, - { - "color": "#0B3EE3", + "lineHeight": undefined, }, { "color": undefined, @@ -183,25 +183,27 @@ exports[`Test Buttons Components - Experimental Enabled ButtonOutline Snapshot 1 allowFontScaling={true} ellipsizeMode="tail" importantForAccessibility="no-hide-descendants" - maxFontSizeMultiplier={1.3} + maxFontSizeMultiplier={1.25} numberOfLines={1} style={ [ + {}, { + "color": "#0E0F13", "fontFamily": "Readex Pro", "fontSize": 16, "fontStyle": "normal", "fontWeight": "400", + "lineHeight": undefined, }, - { - "alignSelf": "center", - }, - { - "color": "#0B3EE3", - }, - { - "color": undefined, - }, + [ + { + "alignSelf": "center", + }, + { + "color": undefined, + }, + ], ] } > @@ -300,36 +302,26 @@ exports[`Test Buttons Components - Experimental Enabled ButtonSolid Snapshot 1`] accessibilityElementsHidden={true} accessible={false} allowFontScaling={true} - color="white" - defaultColor="white" - defaultWeight="Regular" ellipsizeMode="tail" - font="ReadexPro" - fontStyle={ - { - "fontSize": 16, - } - } importantForAccessibility="no-hide-descendants" maxFontSizeMultiplier={1.25} numberOfLines={1} style={ [ - { - "alignSelf": "center", - }, - { - "fontSize": 16, - }, + {}, { "color": "#FFFFFF", "fontFamily": "Readex Pro", + "fontSize": 16, "fontStyle": "normal", "fontWeight": "400", + "lineHeight": 20, + }, + { + "alignSelf": "center", }, ] } - weight="Regular" > label @@ -803,18 +795,18 @@ exports[`Test Buttons Components ButtonLink Snapshot 1`] = ` allowFontScaling={false} ellipsizeMode="tail" importantForAccessibility="no-hide-descendants" - maxFontSizeMultiplier={1.3} + maxFontSizeMultiplier={1.25} numberOfLines={1} style={ [ + {}, { + "color": "#0E0F13", "fontFamily": "Titillium Sans Pro", "fontSize": 16, "fontStyle": "normal", "fontWeight": "700", - }, - { - "color": "#0073E6", + "lineHeight": undefined, }, { "color": undefined, @@ -909,24 +901,27 @@ exports[`Test Buttons Components ButtonOutline Snapshot 1`] = ` allowFontScaling={false} ellipsizeMode="tail" importantForAccessibility="no-hide-descendants" - maxFontSizeMultiplier={1.3} + maxFontSizeMultiplier={1.25} numberOfLines={1} style={ [ + {}, { + "color": "#0E0F13", "fontFamily": "Titillium Sans Pro", + "fontSize": 16, "fontStyle": "normal", "fontWeight": "700", + "lineHeight": undefined, }, - { - "alignSelf": "center", - }, - { - "color": "#0073E6", - }, - { - "color": undefined, - }, + [ + { + "alignSelf": "center", + }, + { + "color": undefined, + }, + ], ] } > @@ -1024,36 +1019,26 @@ exports[`Test Buttons Components ButtonSolid Snapshot 1`] = ` accessibilityElementsHidden={true} accessible={false} allowFontScaling={false} - color="white" - defaultColor="white" - defaultWeight="Bold" ellipsizeMode="tail" - font="TitilliumSansPro" - fontStyle={ - { - "fontSize": 16, - } - } importantForAccessibility="no-hide-descendants" maxFontSizeMultiplier={1.25} numberOfLines={1} style={ [ - { - "alignSelf": "center", - }, - { - "fontSize": 16, - }, + {}, { "color": "#FFFFFF", "fontFamily": "Titillium Sans Pro", + "fontSize": 16, "fontStyle": "normal", "fontWeight": "700", + "lineHeight": 20, + }, + { + "alignSelf": "center", }, ] } - weight="Bold" > label diff --git a/src/components/featureInfo/FeatureInfo.tsx b/src/components/featureInfo/FeatureInfo.tsx index c84c8e33..0f8edece 100644 --- a/src/components/featureInfo/FeatureInfo.tsx +++ b/src/components/featureInfo/FeatureInfo.tsx @@ -8,7 +8,7 @@ import { IOPictogramSizeScale, IOPictograms, Icon, - LabelLink, + Label, Pictogram, VSpacer } from "../../components"; @@ -21,12 +21,13 @@ type PartialFeatureInfo = { type FeatureInfoActionProps = | { - actionLabel?: string; - actionOnPress: (event: GestureResponderEvent) => void; + action: { + label: string; + onPress: (event: GestureResponderEvent) => void; + }; } | { - actionLabel?: never; - actionOnPress?: never; + action?: never; }; type FeatureInfoGraphicProps = @@ -56,8 +57,7 @@ export const FeatureInfo = ({ iconName, pictogramName, body, - actionLabel, - actionOnPress + action }: FeatureInfoProps) => ( {iconName && ( @@ -69,21 +69,21 @@ export const FeatureInfo = ({ {renderNode(body)} - {actionLabel && actionOnPress && ( + {action && ( <> {/* Add "marginTop" equivalent if body text is present. This verbose code could be deleted once we got "gap" property support */} {body && } - - {actionLabel} - + {action.label} + )} diff --git a/src/components/layout/HeaderSecondLevel.tsx b/src/components/layout/HeaderSecondLevel.tsx index e95acc0e..a0db613c 100644 --- a/src/components/layout/HeaderSecondLevel.tsx +++ b/src/components/layout/HeaderSecondLevel.tsx @@ -34,10 +34,10 @@ import { useIOThemeContext } from "../../core"; import type { IOSpacer, IOSpacingScale } from "../../core/IOSpacing"; -import { makeFontStyleObject } from "../../utils/fonts"; import { WithTestID } from "../../utils/types"; import IconButton from "../buttons/IconButton"; import { HSpacer } from "../spacer"; +import { IOText } from "../typography"; import { HeaderActionProps } from "./common"; type ScrollValues = { @@ -124,16 +124,6 @@ const styles = StyleSheet.create({ flexGrow: 1, flexShrink: 1, marginHorizontal: titleHorizontalMargin - }, - headerTitle: { - fontSize: 14, - textAlign: "center" - }, - headerTitleFont: { - ...makeFontStyleObject("Regular", false, "ReadexPro") - }, - headerTitleLegacyFont: { - ...makeFontStyleObject("Semibold", false, "TitilliumSansPro") } }); @@ -172,6 +162,8 @@ export const HeaderSecondLevel = ({ const isTitleAccessible = React.useMemo(() => !!title.trim(), [title]); const paddingTop = useSharedValue(ignoreSafeAreaMargin ? 0 : insets.top); + const AnimatedIOText = Animated.createAnimatedComponent(IOText); + const iconButtonColorDefault: ComponentProps["color"] = themeType === "dark" ? "contrast" : "neutral"; @@ -307,20 +299,19 @@ export const HeaderSecondLevel = ({ accessibilityRole="header" style={styles.titleContainer} > - {title} - + {type === "threeActions" && ( diff --git a/src/components/listitems/ListItemAction.tsx b/src/components/listitems/ListItemAction.tsx index 8b1bd608..ee18cf5a 100644 --- a/src/components/listitems/ListItemAction.tsx +++ b/src/components/listitems/ListItemAction.tsx @@ -1,11 +1,5 @@ import React, { ComponentProps, useCallback, useMemo } from "react"; -import { - GestureResponderEvent, - Pressable, - StyleSheet, - Text, - View -} from "react-native"; +import { GestureResponderEvent, Pressable, View } from "react-native"; import Animated, { Extrapolate, interpolate, @@ -21,15 +15,12 @@ import { IOListItemVisualParams, IOScaleValues, IOSpringValues, - IOStyles, hexToRgba, - useIOExperimentalDesign, useIOTheme } from "../../core"; -import { makeFontStyleObject } from "../../utils/fonts"; import { WithTestID } from "../../utils/types"; -import { AnimatedIcon, IOIcons, Icon } from "../icons"; -import { buttonTextFontSize } from "../typography/ButtonText"; +import { AnimatedIcon, IOIcons } from "../icons"; +import { ButtonText } from "../typography/ButtonText"; export type ListItemAction = WithTestID<{ label: string; @@ -42,23 +33,6 @@ export type ListItemAction = WithTestID<{ "accessibilityLabel" | "accessibilityHint" >; -const styles = StyleSheet.create({ - label: { - fontSize: buttonTextFontSize, - lineHeight: 20, - ...makeFontStyleObject("Regular", false, "ReadexPro") - } -}); - -// TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 -const legacyStyles = StyleSheet.create({ - labelLegacy: { - fontSize: buttonTextFontSize, - lineHeight: 20, - ...makeFontStyleObject("Semibold", false, "TitilliumSansPro") - } -}); - export const ListItemAction = ({ variant, label, @@ -70,7 +44,6 @@ export const ListItemAction = ({ }: ListItemAction) => { const isPressed = useSharedValue(0); - const { isExperimental } = useIOExperimentalDesign(); const theme = useIOTheme(); const listItemAccessibilityLabel = useMemo( @@ -83,53 +56,14 @@ export const ListItemAction = ({ pressed: IOColors[theme["listItem-pressed"]] }; - const mapLegacyForegroundColor: Record< - NonNullable, - IOColors - > = { - primary: "blue", - danger: "error-600" - }; - const mapForegroundColor: Record< NonNullable, - string + IOColors > = { - primary: IOColors[theme["interactiveElem-default"]], - danger: IOColors[theme.errorText] + primary: theme["interactiveElem-default"], + danger: theme.errorText }; - // TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 - const legacyItemActionIcon = (icon: IOIcons) => ( - - ); - - const itemActionIcon = (icon: IOIcons) => ( - <> - - - ); - - const itemActionIconComponent = (icon: IOIcons) => - isExperimental ? itemActionIcon(icon) : legacyItemActionIcon(icon); - - const textStyle = [styles.label, { color: mapForegroundColor[variant] }]; - - const legacyTextStyle = [ - legacyStyles.labelLegacy, - { color: IOColors[mapLegacyForegroundColor[variant]] } - ]; - - const textStyleComponent = isExperimental ? textStyle : legacyTextStyle; - // Scaling transformation applied when the button is pressed const animationScaleValue = IOScaleValues?.basicButton?.pressedState; @@ -194,11 +128,15 @@ export const ListItemAction = ({ > {icon && ( - {itemActionIconComponent(icon)} + )} - - {label} + + {label} diff --git a/src/components/listitems/ListItemAmount.tsx b/src/components/listitems/ListItemAmount.tsx index e3e5ea9c..24f7c638 100644 --- a/src/components/listitems/ListItemAmount.tsx +++ b/src/components/listitems/ListItemAmount.tsx @@ -54,9 +54,7 @@ export const ListItemAmount = ({ importantForAccessibility={"no-hide-descendants"} accessibilityElementsHidden={false} > -
- {label} -
+
{label}
); @@ -80,9 +78,8 @@ export const ListItemAmount = ({ {itemInfoTextComponent}

- + {action.label} - + )} diff --git a/src/components/listitems/__test__/__snapshots__/listitem.test.tsx.snap b/src/components/listitems/__test__/__snapshots__/listitem.test.tsx.snap index 00bde58b..71c4dc37 100644 --- a/src/components/listitems/__test__/__snapshots__/listitem.test.tsx.snap +++ b/src/components/listitems/__test__/__snapshots__/listitem.test.tsx.snap @@ -72,23 +72,24 @@ exports[`Test List Item Components - Experimental Enabled ListItemAction Snapsh @@ -170,17 +171,16 @@ exports[`Test List Item Components - Experimental Enabled ListItemIDP Snapshot { "alignSelf": "center", "flexShrink": 1, - "fontSize": 12, - "lineHeight": 16, + "letterSpacing": 0.5, "textTransform": "uppercase", }, { "color": "#555C70", - }, - { "fontFamily": "Readex Pro", + "fontSize": 12, "fontStyle": "normal", "fontWeight": "400", + "lineHeight": 16, }, ] } @@ -238,66 +238,42 @@ exports[`Test List Item Components - Experimental Enabled ListItemInfo Snapshot > label testValue @@ -384,66 +360,42 @@ exports[`Test List Item Components - Experimental Enabled ListItemInfoCopy Snap > label testValue @@ -596,33 +548,21 @@ exports[`Test List Item Components - Experimental Enabled ListItemNav Snapshot > testValue @@ -837,33 +777,21 @@ exports[`Test List Item Components - Experimental Enabled ListItemNavAlert Snap > testValue @@ -1016,34 +944,22 @@ exports[`Test List Item Components - Experimental Enabled ListItemRadioWithAmou > label @@ -1128,33 +1044,21 @@ exports[`Test List Item Components - Experimental Enabled ListItemRadioWithAmou /> suggestReason @@ -1179,33 +1083,21 @@ exports[`Test List Item Components - Experimental Enabled ListItemRadioWithAmou /> € 1.000,00 @@ -1440,34 +1332,22 @@ exports[`Test List Item Components - Experimental Enabled ListItemRadioWithAmou > label @@ -1491,33 +1371,21 @@ exports[`Test List Item Components - Experimental Enabled ListItemRadioWithAmou /> € 1.000,00 @@ -1901,23 +1769,24 @@ exports[`Test List Item Components ListItemAction Snapshot 1`] = ` @@ -1999,17 +1868,16 @@ exports[`Test List Item Components ListItemIDP Snapshot 1`] = ` { "alignSelf": "center", "flexShrink": 1, - "fontSize": 12, - "lineHeight": 16, + "letterSpacing": 0.5, "textTransform": "uppercase", }, { "color": "#555C70", - }, - { "fontFamily": "Titillium Sans Pro", + "fontSize": 12, "fontStyle": "normal", "fontWeight": "600", + "lineHeight": 16, }, ] } @@ -2067,66 +1935,42 @@ exports[`Test List Item Components ListItemInfo Snapshot 1`] = ` > label testValue @@ -2213,66 +2057,42 @@ exports[`Test List Item Components ListItemInfoCopy Snapshot 1`] = ` > label testValue @@ -2425,33 +2245,21 @@ exports[`Test List Item Components ListItemNav Snapshot 1`] = ` > testValue @@ -2666,33 +2474,21 @@ exports[`Test List Item Components ListItemNavAlert Snapshot 1`] = ` > testValue @@ -2845,34 +2641,22 @@ exports[`Test List Item Components ListItemRadioWithAmount Snapshot 1`] = ` > label @@ -2957,33 +2741,21 @@ exports[`Test List Item Components ListItemRadioWithAmount Snapshot 1`] = ` /> suggestReason @@ -3008,33 +2780,21 @@ exports[`Test List Item Components ListItemRadioWithAmount Snapshot 1`] = ` /> € 1.000,00 @@ -3269,34 +3029,22 @@ exports[`Test List Item Components ListItemRadioWithAmount Snapshot 2`] = ` > label @@ -3320,33 +3068,21 @@ exports[`Test List Item Components ListItemRadioWithAmount Snapshot 2`] = ` /> € 1.000,00 diff --git a/src/components/modules/ModuleIDP.tsx b/src/components/modules/ModuleIDP.tsx index 0851b68e..a046fc41 100644 --- a/src/components/modules/ModuleIDP.tsx +++ b/src/components/modules/ModuleIDP.tsx @@ -1,20 +1,12 @@ import * as React from "react"; +import { Image, ImageSourcePropType, Platform, StyleSheet } from "react-native"; import { - Image, - ImageSourcePropType, - Platform, - StyleSheet, - Text -} from "react-native"; -import { - IOColors, IOListItemLogoMargin, - IOVisualCostants, useIOExperimentalDesign, useIOTheme } from "../../core"; import { toAndroidCacheTimestamp } from "../../utils/dates"; -import { makeFontStyleObject } from "../../utils/fonts"; +import { IOText } from "../typography"; import { PressableModuleBase, PressableModuleBaseProps @@ -28,19 +20,6 @@ interface ModuleIDP extends PressableModuleBaseProps { } const styles = StyleSheet.create({ - idpName: { - fontSize: 12, - lineHeight: 16, - alignSelf: "center", - textTransform: "uppercase", - flexShrink: 1 - }, - idpNameFont: { - ...makeFontStyleObject("Regular", false, "ReadexPro") - }, - idpLegacyNameFont: { - ...makeFontStyleObject("Semibold", false, "TitilliumSansPro") - }, idpLogo: { marginStart: IOListItemLogoMargin, width: 120, @@ -79,18 +58,22 @@ export const ModuleIDP = ({ testID={testID} withLooseSpacing={withLooseSpacing} > - {name} - + 1 @@ -182,33 +170,21 @@ exports[`NumberPad Should match the snapshot 1`] = ` > 2 @@ -273,33 +249,21 @@ exports[`NumberPad Should match the snapshot 1`] = ` > 3 @@ -380,33 +344,21 @@ exports[`NumberPad Should match the snapshot 1`] = ` > 4 @@ -471,33 +423,21 @@ exports[`NumberPad Should match the snapshot 1`] = ` > 5 @@ -562,33 +502,21 @@ exports[`NumberPad Should match the snapshot 1`] = ` > 6 @@ -669,33 +597,21 @@ exports[`NumberPad Should match the snapshot 1`] = ` > 7 @@ -760,33 +676,21 @@ exports[`NumberPad Should match the snapshot 1`] = ` > 8 @@ -851,33 +755,21 @@ exports[`NumberPad Should match the snapshot 1`] = ` > 9 @@ -1099,33 +991,21 @@ exports[`NumberPad Should match the snapshot 1`] = ` > 0 diff --git a/src/components/searchInput/SearchInput.tsx b/src/components/searchInput/SearchInput.tsx index b4e87fde..6759fc27 100644 --- a/src/components/searchInput/SearchInput.tsx +++ b/src/components/searchInput/SearchInput.tsx @@ -36,7 +36,7 @@ import { useIOExperimentalDesign, useIOTheme } from "../../core"; -import { makeFontStyleObject } from "../../utils/fonts"; +import { IOFontSize, makeFontStyleObject } from "../../utils/fonts"; import { ButtonLink } from "../buttons"; import { IOIconSizeScale, Icon } from "../icons"; @@ -51,7 +51,7 @@ const iconMargin: IOSpacingScale = 8; const iconColor: IOColors = "grey-700"; const iconSize: IOIconSizeScale = 16; const iconCloseSize: IOIconSizeScale = 24; -const inputFontSizePlaceholder: number = 14; +const inputFontSizePlaceholder: IOFontSize = 14; const cancelButtonMargin: IOSpacingScale = 16; const inputTransitionDuration: number = 250; const inputHeightIOS: number = 36; @@ -324,12 +324,20 @@ const styles = StyleSheet.create({ marginRight: iconMargin }, placeholder: { - fontSize: inputFontSizePlaceholder, - ...makeFontStyleObject("Regular", false, "ReadexPro") + ...makeFontStyleObject( + inputFontSizePlaceholder, + "ReadexPro", + undefined, + "Regular" + ) }, placeholderLegacy: { - fontSize: inputFontSizePlaceholder, - ...makeFontStyleObject("Regular", false, "TitilliumSansPro") + ...makeFontStyleObject( + inputFontSizePlaceholder, + "TitilliumSansPro", + undefined, + "Regular" + ) }, cancelButton: { position: "absolute", diff --git a/src/components/switch/SwitchLabel.tsx b/src/components/switch/SwitchLabel.tsx index c7767882..dc20db3b 100644 --- a/src/components/switch/SwitchLabel.tsx +++ b/src/components/switch/SwitchLabel.tsx @@ -1,10 +1,9 @@ import * as React from "react"; import { useState } from "react"; -import { Pressable, StyleSheet, Text, View } from "react-native"; -import { IOColors, useIOExperimentalDesign, useIOTheme } from "../../core"; +import { Pressable, View } from "react-native"; +import { useIOTheme } from "../../core"; import { IOStyles } from "../../core/IOStyles"; import { triggerHaptic } from "../../functions/haptic-feedback/hapticFeedback"; -import { makeFontStyleObject } from "../../utils/fonts"; import { HSpacer } from "../spacer/Spacer"; import { H6 } from "../typography/H6"; import { AnimatedSwitch } from "./AnimatedSwitch"; @@ -23,17 +22,6 @@ type OwnProps = Props & Pick, "disabled" | "checked"> & Pick, "onPress">; -// TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 -const styles = StyleSheet.create({ - legacyTextValue: { - fontSize: 16, - lineHeight: 24, - color: IOColors.bluegreyDark, - flexShrink: 1, - ...makeFontStyleObject("Semibold", undefined, "TitilliumSansPro") - } -}); - /** * A checkbox with the automatic state management that uses a {@link AnimatedCheckBox} * The toggleValue change when a `onPress` event is received and dispatch the `onValueChange`. @@ -47,24 +35,8 @@ export const SwitchLabel = ({ disabled, onValueChange }: OwnProps) => { - const [toggleValue, setToggleValue] = useState(checked ?? false); const theme = useIOTheme(); - - const { isExperimental } = useIOExperimentalDesign(); - const switchLabelText = ( -
- {label} -
- ); - - // TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 - const legacySwitchlabelText = ( - {label} - ); - - const switchLabelTextComponent = isExperimental - ? switchLabelText - : legacySwitchlabelText; + const [toggleValue, setToggleValue] = useState(checked ?? false); const toggleCheckbox = () => { triggerHaptic("impactLight"); @@ -99,7 +71,9 @@ export const SwitchLabel = ({
- {switchLabelTextComponent} +
+ {label} +
); diff --git a/src/components/tabs/TabItem.tsx b/src/components/tabs/TabItem.tsx index 46e00fb7..c87e6aef 100644 --- a/src/components/tabs/TabItem.tsx +++ b/src/components/tabs/TabItem.tsx @@ -20,7 +20,7 @@ import { useSpringPressProgressValue } from "../../utils/hooks/useSpringPressPro import { WithTestID } from "../../utils/types"; import { IOIcons, Icon } from "../icons"; import { HSpacer } from "../spacer"; -import { LabelHeader } from "../typography/LabelHeader"; +import { LabelSmall } from "../typography"; type ColorMode = "light" | "dark"; @@ -257,7 +257,9 @@ const TabItem = ({ )} - {label} + + {label} + ); diff --git a/src/components/tag/Tag.tsx b/src/components/tag/Tag.tsx index f8d0ff66..406756cb 100644 --- a/src/components/tag/Tag.tsx +++ b/src/components/tag/Tag.tsx @@ -1,16 +1,21 @@ import * as O from "fp-ts/lib/Option"; import { pipe } from "fp-ts/lib/function"; import React from "react"; -import { Platform, StyleSheet, Text, View } from "react-native"; -import { IOColors, IOTagRadius, useIOExperimentalDesign } from "../../core"; +import { Platform, StyleSheet, View } from "react-native"; +import { + IOColors, + IOTagRadius, + useIOExperimentalDesign, + useIOTheme +} from "../../core"; import { IOSpacingScale, IOTagHSpacing, IOTagVSpacing } from "../../core/IOSpacing"; -import { makeFontStyleObject } from "../../utils/fonts"; import { WithTestID } from "../../utils/types"; import { IOIconSizeScale, IOIcons, Icon } from "../icons"; +import { IOText } from "../typography"; type VariantProps = { iconColor: IOColors; @@ -74,21 +79,6 @@ const styles = StyleSheet.create({ }, spacer: { width: IOTagIconMargin - }, - label: { - fontSize: 12, - lineHeight: 16, - alignSelf: "center", - textTransform: "uppercase", - color: IOColors["grey-700"], - flexShrink: 1 - }, - labelFont: { - ...makeFontStyleObject("Regular", false, "ReadexPro") - }, - // TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 - legacyLabelFont: { - ...makeFontStyleObject("Semibold", false, "TitilliumSansPro") } }); @@ -151,6 +141,7 @@ export const Tag = ({ customIconProps, iconAccessibilityLabel }: Tag) => { + const theme = useIOTheme(); const { isExperimental } = useIOExperimentalDesign(); const variantProps = getVariantProps(variant, customIconProps); @@ -177,16 +168,23 @@ export const Tag = ({ )} {variantProps && text && } {text && ( - {text} - + )} ); diff --git a/src/components/textInput/TextInputBase.tsx b/src/components/textInput/TextInputBase.tsx index f9797213..379b357f 100644 --- a/src/components/textInput/TextInputBase.tsx +++ b/src/components/textInput/TextInputBase.tsx @@ -26,7 +26,7 @@ import { useIOExperimentalDesign, useIOTheme } from "../../core"; -import { makeFontStyleObject } from "../../utils/fonts"; +import { IOFontSize, makeFontStyleObject } from "../../utils/fonts"; import { RNTextInputProps, getInputPropsByType } from "../../utils/textInput"; import { InputType, WithTestID } from "../../utils/types"; import { IOIconSizeScale, IOIcons, Icon } from "../icons"; @@ -63,7 +63,7 @@ const inputPaddingVertical: IOSpacingScale = 8; const inputRadius: number = 8; const inputTransitionDuration: number = 250; const inputLabelScaleFactor: number = 0.75; /* 16pt becomes 12pt */ -const inputLabelFontSize: number = 16; +const inputLabelFontSize: IOFontSize = 16; const inputDisabledOpacity: number = 0.5; const inputRightElementMargin: IOSpacingScale = 8; const iconColor: IOColors = "grey-300"; @@ -100,7 +100,6 @@ const styles = StyleSheet.create({ Android where the text input scrolls, if the user apply some gestures on it with keyboard open */ paddingVertical: 0, - fontSize: 16, marginTop: inputMarginTop, height: "100%", /* Slightly move the input on the left on Android @@ -108,11 +107,21 @@ const styles = StyleSheet.create({ ...(Platform.OS === "android" && { marginLeft: -4 }) }, textInputStyleFont: { - ...makeFontStyleObject("Regular", false, "ReadexPro") + ...makeFontStyleObject( + inputLabelFontSize, + "ReadexPro", + undefined, + "Regular" + ) }, // TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 textInputStyleLegacyFont: { - ...makeFontStyleObject("Semibold", false, "TitilliumSansPro") + ...makeFontStyleObject( + inputLabelFontSize, + "TitilliumSansPro", + undefined, + "Semibold" + ) }, textInputLabelWrapper: { position: "absolute", @@ -123,9 +132,13 @@ const styles = StyleSheet.create({ justifyContent: "center" }, textInputLabel: { - ...makeFontStyleObject("Regular", false, "TitilliumSansPro"), - color: inputLabelColor, - fontSize: inputLabelFontSize + ...makeFontStyleObject( + inputLabelFontSize, + "TitilliumSansPro", + undefined, + "Regular" + ), + color: inputLabelColor } }); diff --git a/src/components/toast/__tests__/__snapshots__/ToastNotification.test.tsx.snap b/src/components/toast/__tests__/__snapshots__/ToastNotification.test.tsx.snap index ed063489..fbcaf70e 100644 --- a/src/components/toast/__tests__/__snapshots__/ToastNotification.test.tsx.snap +++ b/src/components/toast/__tests__/__snapshots__/ToastNotification.test.tsx.snap @@ -25,34 +25,24 @@ exports[`Test ToastNotification component - Experimental Enabled should match sn > Hello @@ -151,34 +141,24 @@ exports[`Test ToastNotification component - Experimental Enabled should match sn > Hello @@ -210,34 +190,24 @@ exports[`Test ToastNotification component - Experimental Enabled should match sn > Hello @@ -269,34 +239,24 @@ exports[`Test ToastNotification component - Experimental Enabled should match sn > Hello @@ -328,34 +288,24 @@ exports[`Test ToastNotification component - Experimental Enabled should match sn > Hello @@ -387,34 +337,24 @@ exports[`Test ToastNotification component - Experimental Enabled should match sn > Hello @@ -446,34 +386,24 @@ exports[`Test ToastNotification component should match snapshot for props ({ mes > Hello @@ -572,34 +502,24 @@ exports[`Test ToastNotification component should match snapshot for props ({ mes > Hello @@ -631,34 +551,24 @@ exports[`Test ToastNotification component should match snapshot for props ({ mes > Hello @@ -690,34 +600,24 @@ exports[`Test ToastNotification component should match snapshot for props ({ mes > Hello @@ -749,34 +649,24 @@ exports[`Test ToastNotification component should match snapshot for props ({ mes > Hello @@ -808,34 +698,24 @@ exports[`Test ToastNotification component should match snapshot for props ({ mes > Hello diff --git a/src/components/typography/BaseTypography.tsx b/src/components/typography/BaseTypography.tsx index 140fffda..af895646 100644 --- a/src/components/typography/BaseTypography.tsx +++ b/src/components/typography/BaseTypography.tsx @@ -1,8 +1,9 @@ import React, { useMemo } from "react"; -import { StyleProp, Text, TextStyle, View } from "react-native"; +import { Text, TextStyle, View } from "react-native"; import { IOColors } from "../../core/IOColors"; import { IOFontFamily, + IOFontSize, IOFontWeight, makeFontStyleObject } from "../../utils/fonts"; @@ -19,7 +20,7 @@ type BaseTypographyProps = { }; type OwnProps = BaseTypographyProps & { - fontStyle?: StyleProp; + fontStyle?: TextStyle; } & React.ComponentPropsWithRef; /** @@ -41,13 +42,21 @@ const calculateTextStyle = ( * used to calculate at runtime the platform-dependent styles. * This component shouldn't be used in the application but only to compose others `Typography elements`. * @param props + * @deprecated Use {@link IOText} instead * @constructor */ export const BaseTypography = React.forwardRef((props, ref) => { const fontStyle = useMemo( () => - calculateTextStyle(props.color, props.weight, props.isItalic, props.font), - [props.color, props.weight, props.isItalic, props.font] + calculateTextStyle( + props.color, + props.fontStyle?.fontSize as IOFontSize, + props.font, + props.fontStyle?.lineHeight, + props.weight, + props.isItalic ? "italic" : "normal" + ), + [props.color, props.fontStyle, props.font, props.weight, props.isItalic] ); const style = props.style diff --git a/src/components/typography/Body.tsx b/src/components/typography/Body.tsx index e88fdf84..05a23122 100644 --- a/src/components/typography/Body.tsx +++ b/src/components/typography/Body.tsx @@ -1,50 +1,55 @@ -import React from "react"; +import React, { ForwardedRef, forwardRef } from "react"; import { View } from "react-native"; +import { useIOTheme } from "../../core"; +import { IOFontWeight } from "../../utils/fonts"; import { - IOColors, - IOTheme, - IOVisualCostants, - useIOExperimentalDesign -} from "../../core"; -import { FontFamily, IOFontWeight } from "../../utils/fonts"; -import { useTypographyFactory } from "./Factory"; -import { ExternalTypographyProps, TypographyProps } from "./common"; + IOText, + IOTextProps, + TypographicStyleAsLinkProps, + TypographicStyleProps +} from "./IOText"; -type PartialAllowedColors = Extract< - IOColors, - "bluegreyDark" | "white" | "blue" | "bluegrey" | "bluegreyLight" ->; -type AllowedColors = PartialAllowedColors | IOTheme["textBody-default"]; -type AllowedWeight = IOFontWeight | "Regular" | "Semibold"; - -type BodyProps = ExternalTypographyProps< - TypographyProps ->; - -const fontName: FontFamily = "TitilliumSansPro"; +type BodyStyleProps = TypographicStyleProps & { + weight?: Extract; +} & TypographicStyleAsLinkProps; export const bodyFontSize = 16; export const bodyLineHeight = 24; -export const bodyDefaultColor: AllowedColors = "bluegrey"; -export const bodyDefaultWeight: AllowedWeight = "Regular"; /** * `Body` typographic style */ -export const Body = React.forwardRef((props, ref) => { - const { isExperimental } = useIOExperimentalDesign(); +export const Body = forwardRef( + ( + { weight: customWeight, color: customColor, asLink, ...props }, + ref?: ForwardedRef + ) => { + const theme = useIOTheme(); - return useTypographyFactory( - { + const defaultColor = asLink + ? theme["interactiveElem-default"] + : theme["textBody-tertiary"]; + + const BodyProps: IOTextProps = { ...props, - allowFontScaling: isExperimental, - maxFontSizeMultiplier: IOVisualCostants.maxFontSizeMultiplier, - dynamicTypeRamp: "body" /* iOS only */, - defaultWeight: bodyDefaultWeight, - defaultColor: bodyDefaultColor, - font: fontName, - fontStyle: { fontSize: bodyFontSize, lineHeight: bodyLineHeight } - }, - ref - ); -}); + dynamicTypeRamp: "body", // iOS only + font: "TitilliumSansPro", + weight: customWeight ?? "Regular", + size: bodyFontSize, + lineHeight: bodyLineHeight, + color: customColor ?? defaultColor, + ...(asLink + ? { + accessibilityRole: "link", + textStyle: { textDecorationLine: "underline" } + } + : {}) + }; + + return ( + + {props.children} + + ); + } +); diff --git a/src/components/typography/BodyMonospace.tsx b/src/components/typography/BodyMonospace.tsx index caffc0d7..78b1d122 100644 --- a/src/components/typography/BodyMonospace.tsx +++ b/src/components/typography/BodyMonospace.tsx @@ -1,46 +1,33 @@ -import React from "react"; +import React, { ForwardedRef, forwardRef } from "react"; import { View } from "react-native"; -import { - IOVisualCostants, - useIOExperimentalDesign, - type IOColors -} from "../../core"; -import { FontFamily, IOFontWeight } from "../../utils/fonts"; -import { useTypographyFactory } from "./Factory"; -import { ExternalTypographyProps, TypographyProps } from "./common"; - -type AllowedColors = Extract; -type AllowedWeight = Extract; - -type BodyMonospaceProps = ExternalTypographyProps< - TypographyProps ->; - -const fontName: FontFamily = "DMMono"; -const fontSize = 16; -const lineHeight = 24; -const monospaceDefaultWeight = "Medium"; -const monospaceDefaultcolor = "bluegrey"; +import { useIOTheme } from "../../core"; +import { bodyFontSize, bodyLineHeight } from "./Body"; +import { IOText, IOTextProps, TypographicStyleProps } from "./IOText"; /** * `BodyMonospace` typographic style */ -export const BodyMonospace = React.forwardRef( - (props, ref) => { - const { isExperimental } = useIOExperimentalDesign(); +export const BodyMonospace = forwardRef( + ({ color: customColor, ...props }, ref?: ForwardedRef) => { + const theme = useIOTheme(); + + const BodyProps: IOTextProps = { + ...props, + dynamicTypeRamp: "body", // iOS only + font: "DMMono", + weight: "Medium", + size: bodyFontSize, + lineHeight: bodyLineHeight, + color: customColor ?? theme["textBody-tertiary"], + textStyle: { + letterSpacing: 0.5 + } + }; - return useTypographyFactory( - { - ...props, - allowFontScaling: isExperimental, - maxFontSizeMultiplier: IOVisualCostants.maxFontSizeMultiplier, - dynamicTypeRamp: "body" /* iOS only */, - defaultWeight: monospaceDefaultWeight, - defaultColor: monospaceDefaultcolor, - font: fontName, - fontStyle: { fontSize, lineHeight } - }, - ref + return ( + + {props.children} + ); } ); diff --git a/src/components/typography/ButtonText.tsx b/src/components/typography/ButtonText.tsx index 4f00582b..b73f0a2c 100644 --- a/src/components/typography/ButtonText.tsx +++ b/src/components/typography/ButtonText.tsx @@ -1,51 +1,41 @@ -import React from "react"; +import React, { ForwardedRef, forwardRef } from "react"; import { View } from "react-native"; +import { useIOExperimentalDesign } from "../../core"; import { IOColors } from "../../core/IOColors"; -import { IOFontFamily, IOFontWeight } from "../../utils/fonts"; -import { IOVisualCostants, useIOExperimentalDesign } from "../../core"; -import { useTypographyFactory } from "./Factory"; -import { ExternalTypographyProps, TypographyProps } from "./common"; +import { IOFontFamily, IOFontSize, IOFontWeight } from "../../utils/fonts"; +import { IOText, IOTextProps, TypographicStyleProps } from "./IOText"; -export type ButtonTextAllowedColors = IOColors; -type AllowedWeight = Extract; - -type ButtonTextProps = ExternalTypographyProps< - TypographyProps ->; - -export const buttonTextFontSize = 16; +export const buttonTextFontSize: IOFontSize = 16; /* Needed to render `ButtonOutline` and`ButtonLink` because they use `AnimatedText` for color transition through Reanimated */ -const buttonTextDefaultColor: ButtonTextAllowedColors = "white"; -const buttonTextFontName: IOFontFamily = "ReadexPro"; -const buttonTextDefaultWeight: AllowedWeight = "Regular"; +const defaultColor: IOColors = "white"; +const fontName: IOFontFamily = "ReadexPro"; +const fontWeight: IOFontWeight = "Regular"; // TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 -const legacyTextFontName: IOFontFamily = "TitilliumSansPro"; -const legacyTextDefaultWeight: AllowedWeight = "Bold"; +const legacyFontName: IOFontFamily = "TitilliumSansPro"; +const legacyFontWeight: IOFontWeight = "Bold"; /** * `ButtonText` typographic style */ -export const ButtonText = React.forwardRef( - (props, ref) => { +export const ButtonText = forwardRef( + ({ color: customColor, ...props }, ref?: ForwardedRef) => { const { isExperimental } = useIOExperimentalDesign(); - return useTypographyFactory( - { - ...props, - allowFontScaling: isExperimental, - maxFontSizeMultiplier: IOVisualCostants.maxFontSizeMultiplier, - defaultWeight: isExperimental - ? buttonTextDefaultWeight - : legacyTextDefaultWeight, - defaultColor: buttonTextDefaultColor, - font: isExperimental ? buttonTextFontName : legacyTextFontName, - fontStyle: { - fontSize: buttonTextFontSize - } - }, - ref + const ButtonTextProps: IOTextProps = { + ...props, + font: isExperimental ? fontName : legacyFontName, + weight: isExperimental ? fontWeight : legacyFontWeight, + size: buttonTextFontSize, + lineHeight: 20, + color: customColor ?? defaultColor + }; + + return ( + + {props.children} + ); } ); diff --git a/src/components/typography/Caption.tsx b/src/components/typography/Caption.tsx index 6fcc7767..ea249078 100644 --- a/src/components/typography/Caption.tsx +++ b/src/components/typography/Caption.tsx @@ -1,45 +1,43 @@ -import React from "react"; +import React, { ForwardedRef, forwardRef } from "react"; import { View } from "react-native"; -import { IOTheme, IOVisualCostants, useIOExperimentalDesign } from "../../core"; -import { FontFamily, IOFontWeight } from "../../utils/fonts"; -import { useTypographyFactory } from "./Factory"; -import { ExternalTypographyProps, TypographyProps } from "./common"; +import { IOTheme, useIOExperimentalDesign, useIOTheme } from "../../core"; +import { IOFontFamily, IOFontSize, IOFontWeight } from "../../utils/fonts"; +import { IOText, IOTextProps, TypographicStyleProps } from "./IOText"; -type AllowedColors = IOTheme["textHeading-default"]; -type AllowedWeight = Extract; +const defaultColor: keyof IOTheme = "textBody-default"; -type CaptionProps = ExternalTypographyProps< - TypographyProps ->; - -export const captionFontSize = 12; -const font: FontFamily = "ReadexPro"; -const defaultColor: AllowedColors = "black"; -const defaultWeight: AllowedWeight = "Regular"; +export const captionFontSize: IOFontSize = 12; +const fontName: IOFontFamily = "ReadexPro"; +const fontWeight: IOFontWeight = "Regular"; // TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 -const legacyFont: FontFamily = "TitilliumSansPro"; +const legacyFontName: IOFontFamily = "TitilliumSansPro"; /** * `Caption` typographic style */ -export const Caption = React.forwardRef((props, ref) => { - const { isExperimental } = useIOExperimentalDesign(); +export const Caption = forwardRef( + ({ color: customColor, ...props }, ref?: ForwardedRef) => { + const theme = useIOTheme(); + const { isExperimental } = useIOExperimentalDesign(); - return useTypographyFactory( - { + const CaptionProps: IOTextProps = { ...props, - allowFontScaling: isExperimental, - maxFontSizeMultiplier: IOVisualCostants.maxFontSizeMultiplier, - dynamicTypeRamp: "caption1" /* iOS only */, - defaultWeight, - defaultColor, - font: isExperimental ? font : legacyFont, - fontStyle: { - fontSize: captionFontSize, - textTransform: "uppercase" + dynamicTypeRamp: "caption1", // iOS only + font: isExperimental ? fontName : legacyFontName, + size: captionFontSize, + weight: fontWeight, + color: customColor ?? theme[defaultColor], + textStyle: { + textTransform: "uppercase", + letterSpacing: 0.5 } - }, - ref - ); -}); + }; + + return ( + + {props.children} + + ); + } +); diff --git a/src/components/typography/Chip.tsx b/src/components/typography/Chip.tsx index e6f7180d..04357cd7 100644 --- a/src/components/typography/Chip.tsx +++ b/src/components/typography/Chip.tsx @@ -1,45 +1,33 @@ -import React from "react"; +import React, { ForwardedRef, forwardRef } from "react"; import { View } from "react-native"; -import { - IOColors, - IOVisualCostants, - useIOExperimentalDesign -} from "../../core"; -import { FontFamily, IOFontWeight } from "../../utils/fonts"; -import { useTypographyFactory } from "./Factory"; -import { ExternalTypographyProps, TypographyProps } from "./common"; - -type AllowedColors = IOColors; -type AllowedWeight = Extract; - -type ChipProps = ExternalTypographyProps< - TypographyProps ->; - -const chipFontSize = 12; -const font: FontFamily = "ReadexPro"; -const defaultColor: AllowedColors = "black"; -const defaultWeight: AllowedWeight = "Regular"; +import { useIOExperimentalDesign, useIOTheme } from "../../core"; +import { IOFontFamily } from "../../utils/fonts"; +import { IOText, IOTextProps, TypographicStyleProps } from "./IOText"; +const fontName: IOFontFamily = "ReadexPro"; // TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 -const legacyFont: FontFamily = "TitilliumSansPro"; +const legacyFontName: IOFontFamily = "TitilliumSansPro"; /** * `Chip` typographic style */ -export const Chip = React.forwardRef((props, ref) => { - const { isExperimental } = useIOExperimentalDesign(); +export const Chip = forwardRef( + ({ color: customColor, ...props }, ref?: ForwardedRef) => { + const theme = useIOTheme(); + const { isExperimental } = useIOExperimentalDesign(); - return useTypographyFactory( - { + const ChipProps: IOTextProps = { ...props, - allowFontScaling: isExperimental, - maxFontSizeMultiplier: IOVisualCostants.maxFontSizeMultiplier, - dynamicTypeRamp: "caption2" /* iOS only */, - defaultWeight, - defaultColor, - font: isExperimental ? font : legacyFont, - fontStyle: { fontSize: chipFontSize } - }, - ref - ); -}); + dynamicTypeRamp: "caption2", // iOS only + font: isExperimental ? fontName : legacyFontName, + weight: "Regular", + size: 12, + color: customColor ?? theme["textBody-default"] + }; + + return ( + + {props.children} + + ); + } +); diff --git a/src/components/typography/Factory.tsx b/src/components/typography/Factory.tsx index 51f37d10..72231e1d 100644 --- a/src/components/typography/Factory.tsx +++ b/src/components/typography/Factory.tsx @@ -71,6 +71,7 @@ function isDefaultFactoryProps( * The default values can be calculated specifying some fallback values using {@link DefaultArgumentProps} * or with a factory function to define some custom behaviour using {@link DefaultFactoryProps} * @param props + * @deprecated Use `IOText` instead. Or use the new typographic styles that use it. */ export function useTypographyFactory< WeightPropsType extends IOFontWeight, diff --git a/src/components/typography/H1.tsx b/src/components/typography/H1.tsx index ebb057ba..673b85c8 100644 --- a/src/components/typography/H1.tsx +++ b/src/components/typography/H1.tsx @@ -1,49 +1,44 @@ -import React from "react"; +import React, { ForwardedRef, forwardRef } from "react"; import { View } from "react-native"; -import { IOTheme, IOVisualCostants, useIOExperimentalDesign } from "../../core"; -import { FontFamily, IOFontWeight } from "../../utils/fonts"; -import { useTypographyFactory } from "./Factory"; -import { ExternalTypographyProps, TypographyProps } from "./common"; +import { IOTheme, useIOExperimentalDesign, useIOTheme } from "../../core"; +import { IOFontFamily, IOFontSize, IOFontWeight } from "../../utils/fonts"; +import { IOText, IOTextProps, TypographicStyleProps } from "./IOText"; -type AllowedColors = IOTheme["textHeading-default"]; -type AllowedWeight = Extract; +const defaultColor: keyof IOTheme = "textHeading-default"; -type H1Props = ExternalTypographyProps< - TypographyProps ->; - -export const h1FontSize = 28; +export const h1FontSize: IOFontSize = 28; export const h1LineHeight = 42; -const fontName: FontFamily = "ReadexPro"; -const defaultColor: AllowedColors = "black"; -const defaultWeight: AllowedWeight = "Regular"; +const fontName: IOFontFamily = "ReadexPro"; +const fontWeight: IOFontWeight = "Regular"; // TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 -const legacyFont: FontFamily = "TitilliumSansPro"; -const legacyDefaultWeight: AllowedWeight = "Semibold"; -const legacyH1FontSize = 31; +const legacyH1FontSize: IOFontSize = 31; const legacyH1LineHeight = 43; +const legacyFontName: IOFontFamily = "TitilliumSansPro"; +const legacyFontWeight: IOFontWeight = "Semibold"; /** * `H1` typographic style */ -export const H1 = React.forwardRef((props, ref) => { - const { isExperimental } = useIOExperimentalDesign(); +export const H1 = forwardRef( + ({ color: customColor, ...props }, ref?: ForwardedRef) => { + const theme = useIOTheme(); + const { isExperimental } = useIOExperimentalDesign(); - return useTypographyFactory( - { + const H1Props: IOTextProps = { ...props, - allowFontScaling: isExperimental, - maxFontSizeMultiplier: IOVisualCostants.maxFontSizeMultiplier, - dynamicTypeRamp: "largeTitle" /* iOS only */, - defaultWeight: isExperimental ? defaultWeight : legacyDefaultWeight, - defaultColor, - font: isExperimental ? fontName : legacyFont, - fontStyle: { - fontSize: isExperimental ? h1FontSize : legacyH1FontSize, - lineHeight: isExperimental ? h1LineHeight : legacyH1LineHeight - } - }, - ref - ); -}); + dynamicTypeRamp: "largeTitle", // iOS only + font: isExperimental ? fontName : legacyFontName, + weight: isExperimental ? fontWeight : legacyFontWeight, + size: isExperimental ? h1FontSize : legacyH1FontSize, + lineHeight: isExperimental ? h1LineHeight : legacyH1LineHeight, + color: customColor ?? theme[defaultColor] + }; + + return ( + + {props.children} + + ); + } +); diff --git a/src/components/typography/H2.tsx b/src/components/typography/H2.tsx index 3015626e..48ce1eaa 100644 --- a/src/components/typography/H2.tsx +++ b/src/components/typography/H2.tsx @@ -1,49 +1,44 @@ -import React from "react"; +import React, { ForwardedRef, forwardRef } from "react"; import { View } from "react-native"; -import { IOTheme, IOVisualCostants, useIOExperimentalDesign } from "../../core"; -import { FontFamily, IOFontWeight } from "../../utils/fonts"; -import { useTypographyFactory } from "./Factory"; -import { ExternalTypographyProps, TypographyProps } from "./common"; +import { IOTheme, useIOExperimentalDesign, useIOTheme } from "../../core"; +import { IOFontFamily, IOFontSize, IOFontWeight } from "../../utils/fonts"; +import { IOText, IOTextProps, TypographicStyleProps } from "./IOText"; -type AllowedColors = IOTheme["textHeading-default"]; -type AllowedWeight = Extract; +const defaultColor: keyof IOTheme = "textHeading-default"; -type H2Props = ExternalTypographyProps< - TypographyProps ->; - -export const h2FontSize = 26; +export const h2FontSize: IOFontSize = 26; export const h2LineHeight = 39; -const fontName: FontFamily = "ReadexPro"; -const defaultColor: AllowedColors = "black"; -const defaultWeight: AllowedWeight = "Regular"; +const fontName: IOFontFamily = "ReadexPro"; +const fontWeight: IOFontWeight = "Regular"; // TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 -const legacyFont: FontFamily = "TitilliumSansPro"; -const legacyDefaultWeight: AllowedWeight = "Semibold"; -const legacyH2FontSize = 28; +const legacyH2FontSize: IOFontSize = 28; const legacyH2LineHeight = 40; +const legacyFontName: IOFontFamily = "TitilliumSansPro"; +const legacyFontWeight: IOFontWeight = "Semibold"; /** * `H2` typographic style */ -export const H2 = React.forwardRef((props, ref) => { - const { isExperimental } = useIOExperimentalDesign(); +export const H2 = forwardRef( + ({ color: customColor, ...props }, ref?: ForwardedRef) => { + const theme = useIOTheme(); + const { isExperimental } = useIOExperimentalDesign(); - return useTypographyFactory( - { + const H2Props: IOTextProps = { ...props, - allowFontScaling: isExperimental, - maxFontSizeMultiplier: IOVisualCostants.maxFontSizeMultiplier, - dynamicTypeRamp: "title1" /* iOS only */, - defaultWeight: isExperimental ? defaultWeight : legacyDefaultWeight, - defaultColor, - font: isExperimental ? fontName : legacyFont, - fontStyle: { - fontSize: isExperimental ? h2FontSize : legacyH2FontSize, - lineHeight: isExperimental ? h2LineHeight : legacyH2LineHeight - } - }, - ref - ); -}); + dynamicTypeRamp: "title1", // iOS only + font: isExperimental ? fontName : legacyFontName, + size: isExperimental ? h2FontSize : legacyH2FontSize, + weight: isExperimental ? fontWeight : legacyFontWeight, + color: customColor ?? theme[defaultColor], + lineHeight: isExperimental ? h2LineHeight : legacyH2LineHeight + }; + + return ( + + {props.children} + + ); + } +); diff --git a/src/components/typography/H3.tsx b/src/components/typography/H3.tsx index 52dc6880..7005cf98 100644 --- a/src/components/typography/H3.tsx +++ b/src/components/typography/H3.tsx @@ -1,48 +1,43 @@ -import React from "react"; +import React, { ForwardedRef, forwardRef } from "react"; import { View } from "react-native"; -import { IOTheme, IOVisualCostants, useIOExperimentalDesign } from "../../core"; -import { FontFamily, IOFontWeight } from "../../utils/fonts"; -import { useTypographyFactory } from "./Factory"; -import { ExternalTypographyProps, TypographyProps } from "./common"; +import { IOTheme, useIOExperimentalDesign, useIOTheme } from "../../core"; +import { IOFontFamily, IOFontSize, IOFontWeight } from "../../utils/fonts"; +import { IOText, IOTextProps, TypographicStyleProps } from "./IOText"; -type AllowedColors = IOTheme["textHeading-default"]; -type AllowedWeight = Extract; - -type H3Props = ExternalTypographyProps< - TypographyProps ->; +const defaultColor: keyof IOTheme = "textHeading-default"; /* Common typographic styles */ -export const h3FontSize = 22; +export const h3FontSize: IOFontSize = 22; export const h3LineHeight = 33; -const fontName: FontFamily = "ReadexPro"; -const defaultColor: AllowedColors = "black"; -const defaultWeight: AllowedWeight = "Regular"; +const fontName: IOFontFamily = "ReadexPro"; +const fontWeight: IOFontWeight = "Regular"; // TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 -const legacyFontName: FontFamily = "TitilliumSansPro"; -const legacyDefaultColor: AllowedColors = "bluegreyDark"; -const legacyDefaultWeight: AllowedWeight = "Semibold"; +const legacyFontName: IOFontFamily = "TitilliumSansPro"; +const legacyFontWeight: IOFontWeight = "Semibold"; + /** * `H3` typographic style */ -export const H3 = React.forwardRef((props, ref) => { - const { isExperimental } = useIOExperimentalDesign(); +export const H3 = forwardRef( + ({ color: customColor, ...props }, ref?: ForwardedRef) => { + const theme = useIOTheme(); + const { isExperimental } = useIOExperimentalDesign(); - return useTypographyFactory( - { + const H3Props: IOTextProps = { ...props, - allowFontScaling: isExperimental, - maxFontSizeMultiplier: IOVisualCostants.maxFontSizeMultiplier, - dynamicTypeRamp: "title2" /* iOS only */, - defaultWeight: isExperimental ? defaultWeight : legacyDefaultWeight, - defaultColor: isExperimental ? defaultColor : legacyDefaultColor, + dynamicTypeRamp: "title2", // iOS only font: isExperimental ? fontName : legacyFontName, - fontStyle: { - fontSize: h3FontSize, - lineHeight: h3LineHeight - } - }, - ref - ); -}); + weight: isExperimental ? fontWeight : legacyFontWeight, + size: h3FontSize, + lineHeight: h3LineHeight, + color: customColor ?? theme[defaultColor] + }; + + return ( + + {props.children} + + ); + } +); diff --git a/src/components/typography/H4.tsx b/src/components/typography/H4.tsx index f29ab7f9..52bf1c12 100644 --- a/src/components/typography/H4.tsx +++ b/src/components/typography/H4.tsx @@ -1,47 +1,42 @@ -import React from "react"; +import React, { ForwardedRef, forwardRef } from "react"; import { View } from "react-native"; -import { IOTheme, IOVisualCostants, useIOExperimentalDesign } from "../../core"; -import { FontFamily, IOFontWeight } from "../../utils/fonts"; -import { useTypographyFactory } from "./Factory"; -import { ExternalTypographyProps, TypographyProps } from "./common"; +import { IOTheme, useIOExperimentalDesign, useIOTheme } from "../../core"; +import { IOFontFamily, IOFontSize, IOFontWeight } from "../../utils/fonts"; +import { IOText, IOTextProps, TypographicStyleProps } from "./IOText"; -type AllowedColors = IOTheme["textHeading-default"]; -type AllowedWeight = Extract; +const defaultColor: keyof IOTheme = "textHeading-default"; -type H4Props = ExternalTypographyProps< - TypographyProps ->; - -export const h4FontSize = 20; +export const h4FontSize: IOFontSize = 20; export const h4LineHeight = 24; -const font: FontFamily = "ReadexPro"; -const defaultColor: AllowedColors = "black"; -const defaultWeight: AllowedWeight = "Regular"; +const fontName: IOFontFamily = "ReadexPro"; +const fontWeight: IOFontWeight = "Regular"; // TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 -const legacyFontName: FontFamily = "TitilliumSansPro"; -const legacyDefaultColor: AllowedColors = "bluegreyDark"; -const legacyDefaultWeight: AllowedWeight = "Semibold"; +const legacyFontName: IOFontFamily = "TitilliumSansPro"; +const legacyFontWeight: IOFontWeight = "Semibold"; /** * `H4` typographic style */ -export const H4 = React.forwardRef((props, ref) => { - const { isExperimental } = useIOExperimentalDesign(); - return useTypographyFactory( - { +export const H4 = forwardRef( + ({ color: customColor, ...props }, ref?: ForwardedRef) => { + const theme = useIOTheme(); + const { isExperimental } = useIOExperimentalDesign(); + + const H4Props: IOTextProps = { ...props, - allowFontScaling: isExperimental, - maxFontSizeMultiplier: IOVisualCostants.maxFontSizeMultiplier, - dynamicTypeRamp: "title3" /* iOS only */, - defaultWeight: isExperimental ? defaultWeight : legacyDefaultWeight, - defaultColor: isExperimental ? defaultColor : legacyDefaultColor, - font: isExperimental ? font : legacyFontName, - fontStyle: { - fontSize: h4FontSize, - lineHeight: h4LineHeight - } - }, - ref - ); -}); + dynamicTypeRamp: "title3", // iOS only + font: isExperimental ? fontName : legacyFontName, + size: h4FontSize, + weight: isExperimental ? fontWeight : legacyFontWeight, + color: customColor ?? theme[defaultColor], + lineHeight: h4LineHeight + }; + + return ( + + {props.children} + + ); + } +); diff --git a/src/components/typography/H5.tsx b/src/components/typography/H5.tsx index 947f5102..1273a1ab 100644 --- a/src/components/typography/H5.tsx +++ b/src/components/typography/H5.tsx @@ -1,45 +1,39 @@ -import React from "react"; +import React, { ForwardedRef, forwardRef } from "react"; import { View } from "react-native"; -import { IOTheme, IOVisualCostants, useIOExperimentalDesign } from "../../core"; -import { FontFamily, IOFontWeight } from "../../utils/fonts"; -import { useTypographyFactory } from "./Factory"; -import { ExternalTypographyProps, TypographyProps } from "./common"; +import { IOTheme, useIOTheme } from "../../core"; +import { IOFontSize } from "../../utils/fonts"; +import { IOText, IOTextProps, TypographicStyleProps } from "./IOText"; -type AllowedColors = IOTheme["textHeading-default"]; -type AllowedWeight = Extract; +const defaultColor: keyof IOTheme = "textHeading-default"; -type H5Props = ExternalTypographyProps< - TypographyProps ->; - -export const h5FontSize = 14; +export const h5FontSize: IOFontSize = 14; export const h5LineHeight = 16; -const font: FontFamily = "TitilliumSansPro"; -const defaultColor: AllowedColors = "black"; -const defaultWeight: AllowedWeight = "Semibold"; /** * `H5` typographic style */ -export const H5 = React.forwardRef((props, ref) => { - const { isExperimental } = useIOExperimentalDesign(); +export const H5 = forwardRef( + ({ color: customColor, ...props }, ref?: ForwardedRef) => { + const theme = useIOTheme(); - return useTypographyFactory( - { + const H5Props: IOTextProps = { ...props, - allowFontScaling: isExperimental, - maxFontSizeMultiplier: IOVisualCostants.maxFontSizeMultiplier, - dynamicTypeRamp: "subheadline" /* iOS only */, - defaultWeight, - defaultColor, - font, - fontStyle: { - fontSize: h5FontSize, - lineHeight: h5LineHeight, + dynamicTypeRamp: "subheadline", // iOS only + font: "TitilliumSansPro", + weight: "Semibold", + size: h5FontSize, + lineHeight: h5LineHeight, + color: customColor ?? theme[defaultColor], + textStyle: { textTransform: "uppercase", letterSpacing: 0.5 } - }, - ref - ); -}); + }; + + return ( + + {props.children} + + ); + } +); diff --git a/src/components/typography/H6.tsx b/src/components/typography/H6.tsx index e4fb7b3d..dc4ab95a 100644 --- a/src/components/typography/H6.tsx +++ b/src/components/typography/H6.tsx @@ -1,55 +1,44 @@ -import React from "react"; +import React, { ForwardedRef, forwardRef } from "react"; import { View } from "react-native"; -import { - IOTheme, - IOThemeLight, - IOVisualCostants, - useIOExperimentalDesign -} from "../../core"; -import { FontFamily, IOFontWeight } from "../../utils/fonts"; -import { useTypographyFactory } from "./Factory"; -import { ExternalTypographyProps, TypographyProps } from "./common"; +import { IOTheme, useIOExperimentalDesign, useIOTheme } from "../../core"; +import { IOFontFamily, IOFontSize, IOFontWeight } from "../../utils/fonts"; +import { IOText, IOTextProps, TypographicStyleProps } from "./IOText"; -// when the weight is bold, only these color are allowed -type AllowedColors = IOTheme["textBody-default"] | "blueIO-850"; -type AllowedWeight = Extract; +const defaultColor: keyof IOTheme = "textHeading-default"; -type H6Props = ExternalTypographyProps< - TypographyProps ->; - -export const h6FontSize = 16; +export const h6FontSize: IOFontSize = 16; export const h6LineHeight = 24; -const h6DefaultColor: AllowedColors = IOThemeLight["textBody-default"]; -const h6DefaultWeight: AllowedWeight = "Regular"; -const fontName: FontFamily = "ReadexPro"; +const fontName: IOFontFamily = "ReadexPro"; +const fontWeight: IOFontWeight = "Regular"; // TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 -const legacyFontSize = 18; +const legacyFontSize: IOFontSize = 18; const legacyLineHeight = 25; -const legacyFontName: FontFamily = "TitilliumSansPro"; -const legacyDefaultWeight: AllowedWeight = "Semibold"; +const legacyFontName: IOFontFamily = "TitilliumSansPro"; +const legacyFontWeight: IOFontWeight = "Semibold"; /** * `H6` typographic style */ -export const H6 = React.forwardRef((props, ref) => { - const { isExperimental } = useIOExperimentalDesign(); +export const H6 = forwardRef( + ({ color: customColor, ...props }, ref?: ForwardedRef) => { + const theme = useIOTheme(); + const { isExperimental } = useIOExperimentalDesign(); - return useTypographyFactory( - { + const H6Props: IOTextProps = { ...props, - allowFontScaling: isExperimental, - maxFontSizeMultiplier: IOVisualCostants.maxFontSizeMultiplier, - dynamicTypeRamp: "headline" /* iOS only */, - defaultWeight: isExperimental ? h6DefaultWeight : legacyDefaultWeight, - defaultColor: h6DefaultColor, + dynamicTypeRamp: "headline", // iOS only font: isExperimental ? fontName : legacyFontName, - fontStyle: { - fontSize: isExperimental ? h6FontSize : legacyFontSize, - lineHeight: isExperimental ? h6LineHeight : legacyLineHeight - } - }, - ref - ); -}); + size: isExperimental ? h6FontSize : legacyFontSize, + lineHeight: isExperimental ? h6LineHeight : legacyLineHeight, + weight: isExperimental ? fontWeight : legacyFontWeight, + color: customColor ?? theme[defaultColor] + }; + + return ( + + {props.children} + + ); + } +); diff --git a/src/components/typography/Hero.tsx b/src/components/typography/Hero.tsx index b7334c28..3355f421 100644 --- a/src/components/typography/Hero.tsx +++ b/src/components/typography/Hero.tsx @@ -1,46 +1,43 @@ -import React from "react"; +import React, { ForwardedRef, forwardRef } from "react"; import { View } from "react-native"; -import { useIOExperimentalDesign, IOTheme } from "../../core"; -import { FontFamily, IOFontWeight } from "../../utils/fonts"; -import { useTypographyFactory } from "./Factory"; -import { ExternalTypographyProps, TypographyProps } from "./common"; +import { IOTheme, useIOExperimentalDesign, useIOTheme } from "../../core"; +import { IOFontFamily, IOFontSize, IOFontWeight } from "../../utils/fonts"; +import { IOText, IOTextProps, TypographicStyleProps } from "./IOText"; -type AllowedColors = IOTheme["textHeading-default"]; -type AllowedWeight = Extract; +const defaultColor: keyof IOTheme = "textHeading-default"; -type HeroProps = ExternalTypographyProps< - TypographyProps ->; - -export const heroFontSize = 32; +export const heroFontSize: IOFontSize = 32; export const heroLineHeight = 48; -const fontName: FontFamily = "ReadexPro"; -const defaultColor: AllowedColors = "black"; -const defaultWeight: AllowedWeight = "Regular"; +const fontName: IOFontFamily = "ReadexPro"; +const fontWeight: IOFontWeight = "Regular"; // TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 -const legacyFont: FontFamily = "TitilliumSansPro"; -const legacyWeight: AllowedWeight = "Semibold"; -const legacyHeroFontSize = 35; +const legacyHeroFontSize: IOFontSize = 35; const legacyHeroLineHeight = 49; +const legacyFontName: IOFontFamily = "TitilliumSansPro"; +const legacyFontWeight: IOFontWeight = "Semibold"; /** * `Hero` typographic style */ -export const Hero = React.forwardRef((props, ref) => { - const { isExperimental } = useIOExperimentalDesign(); +export const Hero = forwardRef( + ({ color: customColor, ...props }, ref?: ForwardedRef) => { + const theme = useIOTheme(); + const { isExperimental } = useIOExperimentalDesign(); - return useTypographyFactory( - { + const HeroProps: IOTextProps = { ...props, - defaultWeight: isExperimental ? defaultWeight : legacyWeight, - defaultColor, - font: isExperimental ? fontName : legacyFont, - fontStyle: { - fontSize: isExperimental ? heroFontSize : legacyHeroFontSize, - lineHeight: isExperimental ? heroLineHeight : legacyHeroLineHeight - } - }, - ref - ); -}); + font: isExperimental ? fontName : legacyFontName, + weight: isExperimental ? fontWeight : legacyFontWeight, + size: isExperimental ? heroFontSize : legacyHeroFontSize, + lineHeight: isExperimental ? heroLineHeight : legacyHeroLineHeight, + color: customColor ?? theme[defaultColor] + }; + + return ( + + {props.children} + + ); + } +); diff --git a/src/components/typography/IOText.tsx b/src/components/typography/IOText.tsx new file mode 100644 index 00000000..a8e01ce4 --- /dev/null +++ b/src/components/typography/IOText.tsx @@ -0,0 +1,157 @@ +import React, { ComponentProps, forwardRef, useMemo } from "react"; +import { + ColorValue, + GestureResponderEvent, + Text, + TextStyle, + View +} from "react-native"; +import { IOColors, useIOExperimentalDesign, useIOTheme } from "../../core"; +import { useBoldTextEnabled } from "../../utils/accessibility"; +import { + IOFontFamily, + IOFontSize, + IOFontWeight, + makeFontStyleObject +} from "../../utils/fonts"; + +/** + * We exclude all of the following props when we define a new + * typographic style in which all of these visual attributes + * are already defined. + */ +export type IOTextStyle = Omit< + TextStyle, + "fontFamily" | "fontSize" | "fontWeight" | "lineHeight" | "fontStyle" +>; + +export type TypographicStyleProps = Omit< + IOTextProps, + "style" | "font" | "size" | "weight" | "color" | "lineHeight" | "fontStyle" +> & { textStyle?: IOTextStyle; style?: IOTextStyle } & { + color?: IOTextBaseProps["color"]; +}; + +/** + * The specific properties needed to calculate the font style using {@link makeFontStyleObject} (these information + * cannot be included in the default StyleProp + */ +type IOTextBaseProps = { + size?: IOFontSize; + weight?: IOFontWeight; + color?: IOColors; + font?: IOFontFamily; + lineHeight?: TextStyle["lineHeight"]; + fontStyle?: TextStyle["fontStyle"]; + textStyle?: IOTextStyle; + style?: IOTextStyle; +}; + +type IOTextExcludedProps = Omit< + ComponentProps, + "allowFontScaling" | "maxFontSizeMultiplier" | "style" +>; + +export type IOTextProps = IOTextBaseProps & IOTextExcludedProps; + +/** + * Extend `TypographicStyleProps` with extra props for styles that + * can be used as links + */ +export type TypographicStyleAsLinkProps = + | { + color?: never; + asLink: true; + onPress: (event: GestureResponderEvent) => void; + } + | { color?: IOColors; asLink?: false }; + +/** + * Decorate the function {@link makeFontStyleObject} with the additional color calculation. + * @param color A value key from {@link IOColors}, transformed here in {@link ColorValue} + * @param args the args of the function {@link makeFontStyleObject} + */ +const calculateTextStyle = ( + color: IOColors, + ...args: Parameters +) => ({ + ...makeFontStyleObject(...args), + color: IOColors[color] +}); + +/** + * `IOText` is the core Typography component used to render a text. + * It accepts all the default text style `StyleProp` (excluding the ones already applied) in addition with {@link IOTextBaseProps} + * used to calculate at runtime the platform-dependent styles. + * @param props + * @constructor + */ +export const IOText = forwardRef( + ( + { + color, + size, + font, + lineHeight, + weight, + fontStyle, + textStyle, + style, + children, + ...props + }, + ref + ) => { + const theme = useIOTheme(); + const boldEnabled = useBoldTextEnabled(); + + const { isExperimental } = useIOExperimentalDesign(); + + const computedStyleObj = useMemo( + () => + calculateTextStyle( + color ?? theme["textBody-default"], + size, + font, + lineHeight, + weight, + fontStyle, + boldEnabled + ), + [color, theme, size, font, lineHeight, weight, fontStyle, boldEnabled] + ); + + /* In some cases, for example when we use color transitions with + `reanimated` we need to manage chromatic values as `ColorValue` + or `string` (not `IOColors`). So we keep a way to override + the the `color' attribute without giving the ability to + override all other all other typographic attributes + through the `style' prop. */ + const fontStyleObj = style?.color + ? [{ ...computedStyleObj, color: style?.color }] + : computedStyleObj; + + /* Some typographic styles like `H5` have certain `TextStyle` properties + like `textTransform` or `letterSpacing` that we want to apply to the text. + We use the `textStyle` prop to pass these properties to the `IOText` + component and preserve the ability to define the `style` prop as well. + The `style` prop is the last one to be applied, so we can properly + override the `color` attribute. + */ + const styleObj = style + ? [textStyle ?? {}, fontStyleObj ?? {}, style] + : [textStyle ?? {}, fontStyleObj ?? {}]; + + /* Accessible typography based on the `fontScale` parameter */ + const accessibleFontSizeProps: ComponentProps = { + allowFontScaling: isExperimental, + maxFontSizeMultiplier: 1.25 + }; + + return ( + + {children} + + ); + } +); diff --git a/src/components/typography/Label.tsx b/src/components/typography/Label.tsx index c9432505..21e081d0 100644 --- a/src/components/typography/Label.tsx +++ b/src/components/typography/Label.tsx @@ -1,58 +1,51 @@ -import React from "react"; +import React, { ForwardedRef, forwardRef } from "react"; import { View } from "react-native"; +import { useIOTheme } from "../../core"; +import { IOFontWeight } from "../../utils/fonts"; import { - IOColors, - IOColorsStatusForeground, - IOVisualCostants, - useIOExperimentalDesign -} from "../../core"; -import { FontFamily, IOFontWeight } from "../../utils/fonts"; -import { useTypographyFactory } from "./Factory"; -import { - ExternalTypographyProps, - FontSize, - TypographyProps, - fontSizeMapping, - lineHeightMapping -} from "./common"; - -type PartialAllowedColors = Extract; -type AllowedColors = PartialAllowedColors | IOColorsStatusForeground; -type AllowedWeight = Extract; -type LabelProps = ExternalTypographyProps< - TypographyProps -> & { fontSize?: FontSize }; + IOText, + IOTextProps, + TypographicStyleAsLinkProps, + TypographicStyleProps +} from "./IOText"; -const font: FontFamily = "TitilliumSansPro"; -const labelDefaultWeight = "Bold"; -const labelDefaultcolor = "black"; +type LabelProps = TypographicStyleProps & { + weight?: Extract; +} & TypographicStyleAsLinkProps; /** - * `Label` typographic style + * `LabelSmall` typographic style */ -export const Label = React.forwardRef( - ({ fontSize, ...props }, ref) => { - const { isExperimental } = useIOExperimentalDesign(); +export const Label = forwardRef( + ( + { weight: customWeight, color: customColor, asLink, ...props }, + ref?: ForwardedRef + ) => { + const theme = useIOTheme(); + + const defaultColor = asLink + ? theme["interactiveElem-default"] + : theme["textBody-tertiary"]; + + const LabelProps: IOTextProps = { + ...props, + font: "TitilliumSansPro", + weight: customWeight ?? "Semibold", + size: 16, + lineHeight: 24, + color: customColor ?? defaultColor, + ...(asLink + ? { + accessibilityRole: "link", + textStyle: { textDecorationLine: "underline" } + } + : {}) + }; - return useTypographyFactory( - { - ...props, - allowFontScaling: isExperimental, - maxFontSizeMultiplier: IOVisualCostants.maxFontSizeMultiplier, - dynamicTypeRamp: "footnote" /* iOS only */, - defaultWeight: labelDefaultWeight, - defaultColor: labelDefaultcolor, - font, - fontStyle: { - fontSize: fontSize - ? fontSizeMapping[fontSize] - : fontSizeMapping.regular, - lineHeight: fontSize - ? lineHeightMapping[fontSize] - : lineHeightMapping.regular - } - }, - ref + return ( + + {props.children} + ); } ); diff --git a/src/components/typography/LabelHeader.tsx b/src/components/typography/LabelHeader.tsx deleted file mode 100644 index e146bf1b..00000000 --- a/src/components/typography/LabelHeader.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { View } from "react-native"; -import React from "react"; -import { IOFontFamily, IOFontWeight } from "../../utils/fonts"; -import { IOTheme, IOThemeLight, useIOExperimentalDesign } from "../../core"; -import { useTypographyFactory } from "./Factory"; -import { ExternalTypographyProps, TypographyProps } from "./common"; - -type AllowedColors = - | IOTheme["textBody-default"] - | "grey-650" - | "grey-850" - | "white" - | "black"; -type AllowedWeight = Extract; - -type LabelHeaderProps = ExternalTypographyProps< - TypographyProps ->; - -export const labelHeaderFontSize = 14; -export const labelHeaderLineHeight = 18; -export const labelHeaderDefaultColor: AllowedColors = - IOThemeLight["textBody-default"]; -const labelHeaderFontName: IOFontFamily = "ReadexPro"; -const labelHeaderDefaultWeight: AllowedWeight = "Regular"; - -// TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 -const legacyLabelHeaderFontName: IOFontFamily = "TitilliumSansPro"; -const legacyLabelHeaderWeight: AllowedWeight = "Semibold"; -const legacyLabelHeaderLineHeight = 20; -/** - * `LabelHeader` typographic style - */ -export const LabelHeader = React.forwardRef( - (props, ref) => { - const { isExperimental } = useIOExperimentalDesign(); - // console.log("isExperimental", isExperimental); - return useTypographyFactory( - { - ...props, - defaultWeight: isExperimental - ? labelHeaderDefaultWeight - : legacyLabelHeaderWeight, - defaultColor: labelHeaderDefaultColor, - font: isExperimental ? labelHeaderFontName : legacyLabelHeaderFontName, - fontStyle: { - fontSize: labelHeaderFontSize, - lineHeight: isExperimental - ? labelHeaderLineHeight - : legacyLabelHeaderLineHeight - } - }, - ref - ); - } -); diff --git a/src/components/typography/LabelLink.tsx b/src/components/typography/LabelLink.tsx deleted file mode 100644 index 29e337b5..00000000 --- a/src/components/typography/LabelLink.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import React from "react"; -import { View } from "react-native"; -import { - IOVisualCostants, - useIOExperimentalDesign, - type IOColors -} from "../../core"; -import { IOFontFamily, IOFontWeight } from "../../utils/fonts"; -import { useTypographyFactory } from "./Factory"; -import { - ExternalTypographyProps, - FontSize, - TypographyProps, - fontSizeMapping, - lineHeightMapping -} from "./common"; - -type AllowedColors = IOColors; -type AllowedWeight = Extract; -type AllowedFontSize = { fontSize?: FontSize }; - -type LinkProps = ExternalTypographyProps< - TypographyProps -> & - AllowedFontSize; - -const font: IOFontFamily = "TitilliumSansPro"; - -export const linkLegacyDefaultColor: AllowedColors = "blue"; -export const linkDefaultColor: AllowedColors = "blueIO-500"; -export const linkDefaultWeight: AllowedWeight = "Semibold"; - -/** - * `Link` typographic style - */ -export const LabelLink = React.forwardRef((props, ref) => { - const { isExperimental } = useIOExperimentalDesign(); - - return useTypographyFactory( - { - accessibilityRole: props.onPress ? "link" : undefined, - ...props, - allowFontScaling: isExperimental, - maxFontSizeMultiplier: IOVisualCostants.maxFontSizeMultiplier, - dynamicTypeRamp: "footnote" /* iOS only */, - defaultWeight: linkDefaultWeight, - defaultColor: isExperimental ? linkDefaultColor : linkLegacyDefaultColor, - font, - fontStyle: { - fontSize: props.fontSize - ? fontSizeMapping[props.fontSize] - : fontSizeMapping.regular, - lineHeight: props.fontSize - ? lineHeightMapping[props.fontSize] - : lineHeightMapping.regular, - textDecorationLine: "underline" - } - }, - ref - ); -}); diff --git a/src/components/typography/LabelMini.tsx b/src/components/typography/LabelMini.tsx new file mode 100644 index 00000000..bd503e60 --- /dev/null +++ b/src/components/typography/LabelMini.tsx @@ -0,0 +1,52 @@ +import React, { ForwardedRef, forwardRef } from "react"; +import { View } from "react-native"; +import { useIOTheme } from "../../core"; +import { IOFontWeight } from "../../utils/fonts"; +import { + IOText, + IOTextProps, + TypographicStyleAsLinkProps, + TypographicStyleProps +} from "./IOText"; + +type LabelMiniProps = TypographicStyleProps & { + weight?: Extract; +} & TypographicStyleAsLinkProps; + +/** + * `LabelMini` typographic style + */ +export const LabelMini = forwardRef( + ( + { weight: customWeight, color: customColor, asLink, ...props }, + ref?: ForwardedRef + ) => { + const theme = useIOTheme(); + + const defaultColor = asLink + ? theme["interactiveElem-default"] + : theme["textBody-tertiary"]; + + const LabelMiniProps: IOTextProps = { + ...props, + dynamicTypeRamp: "footnote" /* iOS only */, + font: "TitilliumSansPro", + weight: customWeight ?? "Semibold", + size: 12, + lineHeight: 18, + color: customColor ?? defaultColor, + ...(asLink + ? { + accessibilityRole: "link", + textStyle: { textDecorationLine: "underline" } + } + : {}) + }; + + return ( + + {props.children} + + ); + } +); diff --git a/src/components/typography/LabelSmall.tsx b/src/components/typography/LabelSmall.tsx index 37022e28..1a6f1f57 100644 --- a/src/components/typography/LabelSmall.tsx +++ b/src/components/typography/LabelSmall.tsx @@ -1,74 +1,52 @@ -import React from "react"; +import React, { ForwardedRef, forwardRef } from "react"; import { View } from "react-native"; +import { useIOTheme } from "../../core"; +import { IOFontWeight } from "../../utils/fonts"; import { - IOColors, - IOTheme, - IOVisualCostants, - useIOExperimentalDesign -} from "../../core"; -import { FontFamily, IOFontWeight } from "../../utils/fonts"; -import { useTypographyFactory } from "./Factory"; -import { ExternalTypographyProps, TypographyProps } from "./common"; + IOText, + IOTextProps, + TypographicStyleAsLinkProps, + TypographicStyleProps +} from "./IOText"; -type PartialAllowedColors = Extract< - IOColors, - | "blue" - | "bluegrey" - | "red" - | "white" - | "bluegreyDark" - | "grey-700" - | "grey-200" ->; -type AllowedColors = PartialAllowedColors | IOTheme["textBody-tertiary"]; -type AllowedWeight = Extract; - -type FontSize = "regular" | "small"; -type AllowedFontSize = { fontSize?: FontSize }; - -type LabelSmallProps = ExternalTypographyProps< - TypographyProps -> & - AllowedFontSize; - -const font: FontFamily = "TitilliumSansPro"; -const fontSizeMapping: Record = { - regular: 14, - small: 12 -}; -const lineHeightMapping: Record = { - regular: 21, - small: 18 -}; -const labelDefaultWeight = "Bold"; -const labelDefaultcolor = "blue"; +type LabelSmallProps = TypographicStyleProps & { + weight?: Extract; +} & TypographicStyleAsLinkProps; /** * `LabelSmall` typographic style */ -export const LabelSmall = React.forwardRef( - (props, ref) => { - const { isExperimental } = useIOExperimentalDesign(); +export const LabelSmall = forwardRef( + ( + { weight: customWeight, color: customColor, asLink, ...props }, + ref?: ForwardedRef + ) => { + const theme = useIOTheme(); + + const defaultColor = asLink + ? theme["interactiveElem-default"] + : theme["textBody-tertiary"]; + + const LabelSmallProps: IOTextProps = { + ...props, + dynamicTypeRamp: "footnote" /* iOS only */, + font: "TitilliumSansPro", + weight: customWeight ?? "Semibold", + size: 14, + lineHeight: 21, + color: customColor ?? defaultColor, + ...(asLink + ? { + accessibilityRole: "link", + textStyle: { textDecorationLine: "underline" } + } + : {}) + }; - return useTypographyFactory( - { - ...props, - allowFontScaling: isExperimental, - maxFontSizeMultiplier: IOVisualCostants.maxFontSizeMultiplier, - dynamicTypeRamp: "footnote" /* iOS only */, - defaultWeight: labelDefaultWeight, - defaultColor: labelDefaultcolor, - font, - fontStyle: { - fontSize: props.fontSize - ? fontSizeMapping[props.fontSize] - : fontSizeMapping.regular, - lineHeight: props.fontSize - ? lineHeightMapping[props.fontSize] - : lineHeightMapping.regular - } - }, - ref + return ( + + {props.children} + ); } ); diff --git a/src/components/typography/LabelSmallAlt.tsx b/src/components/typography/LabelSmallAlt.tsx index b21a378e..b81420b5 100644 --- a/src/components/typography/LabelSmallAlt.tsx +++ b/src/components/typography/LabelSmallAlt.tsx @@ -1,61 +1,41 @@ -import React from "react"; +import React, { ForwardedRef, forwardRef } from "react"; import { View } from "react-native"; -import { IOVisualCostants, useIOExperimentalDesign } from "../../core"; -import type { IOColors, IOTheme } from "../../core/IOColors"; -import { FontFamily, IOFontWeight } from "../../utils/fonts"; -import { useTypographyFactory } from "./Factory"; -import { ExternalTypographyProps, TypographyProps } from "./common"; +import { useIOExperimentalDesign, useIOTheme } from "../../core"; +import { IOFontFamily, IOFontWeight } from "../../utils/fonts"; +import { IOText, IOTextProps, TypographicStyleProps } from "./IOText"; -type PartialAllowedColors = Extract< - IOColors, - | "blue" - | "bluegrey" - | "red" - | "white" - | "bluegreyDark" - | "grey-700" - | "grey-200" ->; -type AllowedColors = PartialAllowedColors | IOTheme["textBody-tertiary"]; -type AllowedWeight = Extract; - -type LabelSmallAltProps = ExternalTypographyProps< - TypographyProps ->; - -const labelFontSize = 14; -const labelLineHeight = 21; -const fontName: FontFamily = "ReadexPro"; -const defaultColor: AllowedColors = "black"; -const defaultWeight: AllowedWeight = "Regular"; +const fontSize = 14; +const lineHeight = 21; +const fontName: IOFontFamily = "ReadexPro"; +const fontWeight: IOFontWeight = "Regular"; // TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153 -const legacyLabelFontSize = 16; -const legacyFontName: FontFamily = "TitilliumSansPro"; -const legacyDefaultWeight: AllowedWeight = "Semibold"; +const legacyFontSize = 16; +const legacyFontName: IOFontFamily = "TitilliumSansPro"; +const legacyFontWeight: IOFontWeight = "Semibold"; /** * `LabelSmallAlt` typographic style. It's referenced as `LabelSmallReadex` in the design projects. */ -export const LabelSmallAlt = React.forwardRef( - (props, ref) => { +export const LabelSmallAlt = forwardRef( + ({ color: customColor, ...props }, ref?: ForwardedRef) => { + const theme = useIOTheme(); const { isExperimental } = useIOExperimentalDesign(); - return useTypographyFactory( - { - ...props, - allowFontScaling: isExperimental, - maxFontSizeMultiplier: IOVisualCostants.maxFontSizeMultiplier, - dynamicTypeRamp: "footnote" /* iOS only */, - defaultWeight: isExperimental ? defaultWeight : legacyDefaultWeight, - defaultColor, - font: isExperimental ? fontName : legacyFontName, - fontStyle: { - fontSize: isExperimental ? labelFontSize : legacyLabelFontSize, - lineHeight: labelLineHeight - } - }, - ref + const LabelSmallAltProps: IOTextProps = { + ...props, + dynamicTypeRamp: "footnote" /* iOS only */, + font: isExperimental ? fontName : legacyFontName, + weight: isExperimental ? fontWeight : legacyFontWeight, + size: isExperimental ? fontSize : legacyFontSize, + lineHeight, + color: customColor ?? theme["textBody-tertiary"] + }; + + return ( + + {props.children} + ); } ); diff --git a/src/components/typography/__test__/__snapshots__/typography.test.tsx.snap b/src/components/typography/__test__/__snapshots__/typography.test.tsx.snap index 7fe6f9cf..26e3ceec 100644 --- a/src/components/typography/__test__/__snapshots__/typography.test.tsx.snap +++ b/src/components/typography/__test__/__snapshots__/typography.test.tsx.snap @@ -3,33 +3,21 @@ exports[`Test Typography Components Body Snapshot 1`] = ` Text @@ -38,33 +26,23 @@ exports[`Test Typography Components Body Snapshot 1`] = ` exports[`Test Typography Components BodyMonospace Snapshot 1`] = ` Text @@ -73,30 +51,20 @@ exports[`Test Typography Components BodyMonospace Snapshot 1`] = ` exports[`Test Typography Components CTA Snapshot 1`] = ` Text @@ -105,33 +73,21 @@ exports[`Test Typography Components CTA Snapshot 1`] = ` exports[`Test Typography Components H1 Snapshot 1`] = ` Text @@ -140,33 +96,21 @@ exports[`Test Typography Components H1 Snapshot 1`] = ` exports[`Test Typography Components H1 Snapshot 2`] = ` Text @@ -175,33 +119,21 @@ exports[`Test Typography Components H1 Snapshot 2`] = ` exports[`Test Typography Components H2 Snapshot 1`] = ` Text @@ -210,33 +142,21 @@ exports[`Test Typography Components H2 Snapshot 1`] = ` exports[`Test Typography Components H3 Snapshot 1`] = ` Text @@ -245,33 +165,21 @@ exports[`Test Typography Components H3 Snapshot 1`] = ` exports[`Test Typography Components H3 Snapshot 2`] = ` Text @@ -280,33 +188,21 @@ exports[`Test Typography Components H3 Snapshot 2`] = ` exports[`Test Typography Components H3 Snapshot 3`] = ` Text @@ -315,33 +211,21 @@ exports[`Test Typography Components H3 Snapshot 3`] = ` exports[`Test Typography Components H3 Snapshot 4`] = ` Text @@ -350,33 +234,21 @@ exports[`Test Typography Components H3 Snapshot 4`] = ` exports[`Test Typography Components H3 Snapshot 5`] = ` Text @@ -385,33 +257,21 @@ exports[`Test Typography Components H3 Snapshot 5`] = ` exports[`Test Typography Components H4 Snapshot 1`] = ` Text @@ -420,208 +280,44 @@ exports[`Test Typography Components H4 Snapshot 1`] = ` exports[`Test Typography Components H4 Snapshot 2`] = ` - Text - -`; - -exports[`Test Typography Components H4 Snapshot 3`] = ` - - Text - -`; - -exports[`Test Typography Components H4 Snapshot 4`] = ` - Text `; -exports[`Test Typography Components H4 Snapshot 5`] = ` +exports[`Test Typography Components H4 Snapshot 3`] = ` - Text - -`; - -exports[`Test Typography Components H4 Snapshot 6`] = ` - - Text - -`; - -exports[`Test Typography Components H4 Snapshot 7`] = ` - Text @@ -630,37 +326,24 @@ exports[`Test Typography Components H4 Snapshot 7`] = ` exports[`Test Typography Components H5 Snapshot 1`] = ` Text @@ -669,37 +352,24 @@ exports[`Test Typography Components H5 Snapshot 1`] = ` exports[`Test Typography Components H5 Snapshot 2`] = ` Text @@ -708,37 +378,24 @@ exports[`Test Typography Components H5 Snapshot 2`] = ` exports[`Test Typography Components H5 Snapshot 3`] = ` Text @@ -747,37 +404,24 @@ exports[`Test Typography Components H5 Snapshot 3`] = ` exports[`Test Typography Components H5 Snapshot 4`] = ` Text @@ -786,33 +430,21 @@ exports[`Test Typography Components H5 Snapshot 4`] = ` exports[`Test Typography Components H6 Snapshot 1`] = ` Text @@ -821,33 +453,20 @@ exports[`Test Typography Components H6 Snapshot 1`] = ` exports[`Test Typography Components Label Snapshot 1`] = ` Text @@ -856,33 +475,20 @@ exports[`Test Typography Components Label Snapshot 1`] = ` exports[`Test Typography Components Label Snapshot 2`] = ` Text @@ -891,33 +497,21 @@ exports[`Test Typography Components Label Snapshot 2`] = ` exports[`Test Typography Components LabelSmall Snapshot 1`] = ` Text @@ -926,33 +520,21 @@ exports[`Test Typography Components LabelSmall Snapshot 1`] = ` exports[`Test Typography Components LabelSmall Snapshot 2`] = ` Text @@ -961,33 +543,21 @@ exports[`Test Typography Components LabelSmall Snapshot 2`] = ` exports[`Test Typography Components LabelSmall Snapshot 3`] = ` Text @@ -996,33 +566,21 @@ exports[`Test Typography Components LabelSmall Snapshot 3`] = ` exports[`Test Typography Components LabelSmall Snapshot 4`] = ` Text @@ -1031,33 +589,21 @@ exports[`Test Typography Components LabelSmall Snapshot 4`] = ` exports[`Test Typography Components LabelSmall Snapshot 5`] = ` Text @@ -1065,36 +611,25 @@ exports[`Test Typography Components LabelSmall Snapshot 5`] = ` exports[`Test Typography Components Link Snapshot 1`] = ` Text diff --git a/src/components/typography/__test__/typography.test.tsx b/src/components/typography/__test__/typography.test.tsx index 037b2add..a878a2a0 100644 --- a/src/components/typography/__test__/typography.test.tsx +++ b/src/components/typography/__test__/typography.test.tsx @@ -1,8 +1,10 @@ import React from "react"; import * as TestRenderer from "react-test-renderer"; +import { Alert } from "react-native"; import type { IOColors } from "../../../core/IOColors"; import { IOFontWeight } from "../../../utils/fonts"; import { Body } from "../Body"; +import { BodyMonospace } from "../BodyMonospace"; import { ButtonText } from "../ButtonText"; import { H1 } from "../H1"; import { H2 } from "../H2"; @@ -12,8 +14,6 @@ import { H5 } from "../H5"; import { H6 } from "../H6"; import { Label } from "../Label"; import { LabelSmall } from "../LabelSmall"; -import { LabelLink } from "../LabelLink"; -import { BodyMonospace } from "../BodyMonospace"; import { calculateWeightColor } from "../common"; describe("Test Typography Components", () => { @@ -54,34 +54,6 @@ describe("Test Typography Components", () => { expect(h4Dblue).toMatchSnapshot(); const h4white = TestRenderer.create(

Text

).toJSON(); expect(h4white).toMatchSnapshot(); - - // Regular weight - // with regular weight, default color is bluegreydark - const h4Regular = TestRenderer.create( -

Text

- ).toJSON(); - expect(h4Regular).toMatchSnapshot(); - - const h4Regularbluegrey = TestRenderer.create( -

- Text -

- ).toJSON(); - expect(h4Regularbluegrey).toMatchSnapshot(); - - const h4RegularbluegreyLight = TestRenderer.create( -

- Text -

- ).toJSON(); - expect(h4RegularbluegreyLight).toMatchSnapshot(); - - const h4Regularwhite = TestRenderer.create( -

- Text -

- ).toJSON(); - expect(h4Regularwhite).toMatchSnapshot(); }); it("H5 Snapshot", () => { // SemiBold weight, default @@ -151,7 +123,11 @@ describe("Test Typography Components", () => { }); }); it("Link Snapshot", () => { - const link = TestRenderer.create(Text).toJSON(); + const link = TestRenderer.create( + + ).toJSON(); expect(link).toMatchSnapshot(); }); it("BodyMonospace Snapshot", () => { diff --git a/src/components/typography/index.tsx b/src/components/typography/index.tsx index 9fc0bb78..1e797134 100644 --- a/src/components/typography/index.tsx +++ b/src/components/typography/index.tsx @@ -1,4 +1,5 @@ export * from "./BaseTypography"; +export * from "./IOText"; export * from "./Body"; export * from "./Caption"; export * from "./Chip"; @@ -14,12 +15,9 @@ export * from "./Hero"; export * from "./Label"; export * from "./LabelSmall"; export * from "./LabelSmallAlt"; -export * from "./LabelLink"; +export * from "./LabelMini"; export * from "./BodyMonospace"; export * from "./common"; export * from "./markdown/MdH1"; export * from "./markdown/MdH2"; export * from "./markdown/MdH3"; -export * from "./markdown/MdH4"; -export * from "./markdown/MdH5"; -export * from "./markdown/MdH6"; diff --git a/src/components/typography/markdown/MdH1.tsx b/src/components/typography/markdown/MdH1.tsx index 03a86626..70f41585 100644 --- a/src/components/typography/markdown/MdH1.tsx +++ b/src/components/typography/markdown/MdH1.tsx @@ -1,32 +1,30 @@ -import { IOColors, IOTheme } from "../../../core"; -import { FontFamily, IOFontWeight } from "../../../utils/fonts"; -import { ExternalTypographyProps, TypographyProps } from "../common"; -import { useTypographyFactory } from "../Factory"; - -type AllowedColors = Extract | IOColors; -type AllowedWeight = Extract; - -type MdH1Props = ExternalTypographyProps< - TypographyProps ->; - -const fontSize = 20; -const lineHeight = 24; -const font: FontFamily = "ReadexPro"; -const defaultColor: AllowedColors = "black"; -const defaultWeight: AllowedWeight = "Regular"; +import React, { ForwardedRef, forwardRef } from "react"; +import { View } from "react-native"; +import { useIOExperimentalDesign, useIOTheme } from "../../../core"; +import { IOText, IOTextProps, TypographicStyleProps } from "../IOText"; /** * `MdH1` typographic style */ -export const MdH1 = (props: MdH1Props) => - useTypographyFactory({ - ...props, - defaultWeight, - defaultColor, - font, - fontStyle: { - fontSize, - lineHeight - } - }); + +export const MdH1 = forwardRef( + ({ color: customColor, ...props }, ref?: ForwardedRef) => { + const theme = useIOTheme(); + const { isExperimental } = useIOExperimentalDesign(); + + const MdH1Props: IOTextProps = { + ...props, + font: isExperimental ? "ReadexPro" : "TitilliumSansPro", + weight: isExperimental ? "Regular" : "Semibold", + size: 20, + lineHeight: 24, + color: customColor ?? theme["textHeading-tertiary"] + }; + + return ( + + {props.children} + + ); + } +); diff --git a/src/components/typography/markdown/MdH2.tsx b/src/components/typography/markdown/MdH2.tsx index 950d0f88..26c2b838 100644 --- a/src/components/typography/markdown/MdH2.tsx +++ b/src/components/typography/markdown/MdH2.tsx @@ -1,34 +1,31 @@ -import { IOColors, IOTheme } from "../../../core"; -import { FontFamily, IOFontWeight } from "../../../utils/fonts"; -import { ExternalTypographyProps, TypographyProps } from "../common"; -import { useTypographyFactory } from "../Factory"; - -type AllowedColors = Extract | IOColors; -type AllowedWeight = Extract; - -type MdH2Props = ExternalTypographyProps< - TypographyProps ->; - -/* We set 18 instead of 16 to diffrentiate from the H3 typographic style. -It should be 16 with `SemiBold` font weight. */ -const fontSize = 18; -const lineHeight = 24; -const font: FontFamily = "ReadexPro"; -const defaultColor: AllowedColors = "black"; -const defaultWeight: AllowedWeight = "Regular"; +import React, { ForwardedRef, forwardRef } from "react"; +import { View } from "react-native"; +import { useIOExperimentalDesign, useIOTheme } from "../../../core"; +import { IOText, IOTextProps, TypographicStyleProps } from "../IOText"; /** * `MdH2` typographic style */ -export const MdH2 = (props: MdH2Props) => - useTypographyFactory({ - ...props, - defaultWeight, - defaultColor, - font, - fontStyle: { - fontSize, - lineHeight - } - }); +export const MdH2 = forwardRef( + ({ color: customColor, ...props }, ref?: ForwardedRef) => { + const theme = useIOTheme(); + const { isExperimental } = useIOExperimentalDesign(); + + const MdH2Props: IOTextProps = { + ...props, + font: isExperimental ? "ReadexPro" : "TitilliumSansPro", + weight: isExperimental ? "Regular" : "Semibold", + /* We set 18 instead of 16 to diffrentiate from the H3 typographic style. +It should be 16 with `SemiBold` font weight. */ + size: 18, + lineHeight: 24, + color: customColor ?? theme["textHeading-tertiary"] + }; + + return ( + + {props.children} + + ); + } +); diff --git a/src/components/typography/markdown/MdH3.tsx b/src/components/typography/markdown/MdH3.tsx index a72ea3e2..50d92039 100644 --- a/src/components/typography/markdown/MdH3.tsx +++ b/src/components/typography/markdown/MdH3.tsx @@ -1,32 +1,29 @@ -import { IOColors, IOTheme } from "../../../core"; -import { FontFamily, IOFontWeight } from "../../../utils/fonts"; -import { ExternalTypographyProps, TypographyProps } from "../common"; -import { useTypographyFactory } from "../Factory"; - -type AllowedColors = Extract | IOColors; -type AllowedWeight = Extract; - -type MdH3Props = ExternalTypographyProps< - TypographyProps ->; - -const fontSize = 16; -const lineHeight = 24; -const font: FontFamily = "ReadexPro"; -const defaultColor: AllowedColors = "black"; -const defaultWeight: AllowedWeight = "Regular"; +import React, { ForwardedRef, forwardRef } from "react"; +import { View } from "react-native"; +import { useIOExperimentalDesign, useIOTheme } from "../../../core"; +import { IOText, IOTextProps, TypographicStyleProps } from "../IOText"; /** * `MdH3` typographic style */ -export const MdH3 = (props: MdH3Props) => - useTypographyFactory({ - ...props, - defaultWeight, - defaultColor, - font, - fontStyle: { - fontSize, - lineHeight - } - }); +export const MdH3 = forwardRef( + ({ color: customColor, ...props }, ref?: ForwardedRef) => { + const theme = useIOTheme(); + const { isExperimental } = useIOExperimentalDesign(); + + const MdH3Props: IOTextProps = { + ...props, + font: isExperimental ? "ReadexPro" : "TitilliumSansPro", + weight: isExperimental ? "Regular" : "Semibold", + size: 16, + lineHeight: 24, + color: customColor ?? theme["textHeading-tertiary"] + }; + + return ( + + {props.children} + + ); + } +); diff --git a/src/components/typography/markdown/MdH4.tsx b/src/components/typography/markdown/MdH4.tsx deleted file mode 100644 index 0c2fa2d4..00000000 --- a/src/components/typography/markdown/MdH4.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { IOColors, IOTheme } from "../../../core"; -import { FontFamily, IOFontWeight } from "../../../utils/fonts"; -import { ExternalTypographyProps, TypographyProps } from "../common"; -import { useTypographyFactory } from "../Factory"; - -type AllowedColors = Extract | IOColors; -type AllowedWeight = Extract; - -type MdH4Props = ExternalTypographyProps< - TypographyProps ->; - -const fontSize = 14; -const lineHeight = 24; -const font: FontFamily = "TitilliumSansPro"; -const defaultColor: AllowedColors = "grey-700"; -const defaultWeight: AllowedWeight = "Semibold"; - -/** - * `MdH4` typographic style - */ -export const MdH4 = (props: MdH4Props) => - useTypographyFactory({ - ...props, - defaultWeight, - defaultColor, - font, - fontStyle: { - fontSize, - textTransform: "uppercase", - letterSpacing: 0.5, - lineHeight - } - }); diff --git a/src/components/typography/markdown/MdH5.tsx b/src/components/typography/markdown/MdH5.tsx deleted file mode 100644 index c127a621..00000000 --- a/src/components/typography/markdown/MdH5.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { IOColors, IOTheme } from "../../../core"; -import { FontFamily, IOFontWeight } from "../../../utils/fonts"; -import { ExternalTypographyProps, TypographyProps } from "../common"; -import { useTypographyFactory } from "../Factory"; - -type AllowedColors = Extract | IOColors; -type AllowedWeight = Extract; - -type MdH5Props = ExternalTypographyProps< - TypographyProps ->; - -const fontSize = 12; -const lineHeight = 16; -const font: FontFamily = "ReadexPro"; -const defaultColor: AllowedColors = "grey-850"; -const defaultWeight: AllowedWeight = "Regular"; - -/** - * `MdH5` typographic style - */ -export const MdH5 = (props: MdH5Props) => - useTypographyFactory({ - ...props, - defaultWeight, - defaultColor, - font, - fontStyle: { - fontSize, - lineHeight - } - }); diff --git a/src/components/typography/markdown/MdH6.tsx b/src/components/typography/markdown/MdH6.tsx deleted file mode 100644 index 30f23e29..00000000 --- a/src/components/typography/markdown/MdH6.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { IOColors, IOTheme } from "../../../core"; -import { FontFamily, IOFontWeight } from "../../../utils/fonts"; -import { ExternalTypographyProps, TypographyProps } from "../common"; -import { useTypographyFactory } from "../Factory"; - -type AllowedColors = Extract | IOColors; -type AllowedWeight = Extract; - -type MdH6Props = ExternalTypographyProps< - TypographyProps ->; - -const fontSize = 10; -const lineHeight = 14; -const font: FontFamily = "ReadexPro"; -const defaultColor: AllowedColors = "grey-700"; -const defaultWeight: AllowedWeight = "Regular"; - -/** - * `MdH5` typographic style - */ -export const MdH6 = (props: MdH6Props) => - useTypographyFactory({ - ...props, - defaultWeight, - defaultColor, - font, - fontStyle: { - fontSize, - lineHeight, - letterSpacing: 0.5 - } - }); diff --git a/src/core/IOColors.ts b/src/core/IOColors.ts index 74984f75..3fbb2949 100644 --- a/src/core/IOColors.ts +++ b/src/core/IOColors.ts @@ -256,37 +256,43 @@ export type IOColorsExtra = keyof typeof IOColorsExtra; ░░░ THEME COLORS ░░░ */ -export type IOTheme = { +const themeKeys = [ // General - "appBackground-primary": IOColors; - "appBackground-secondary": IOColors; - "appBackground-tertiary": IOColors; - "appBackground-accent": IOColors; - "interactiveElem-default": IOColors; - "interactiveElem-pressed": IOColors; - "listItem-pressed": IOColors; + "appBackground-primary", + "appBackground-secondary", + "appBackground-tertiary", + "appBackground-accent", + "interactiveElem-default", + "interactiveElem-pressed", + "listItem-pressed", // Typography - "textHeading-default": IOColors; - "textBody-default": IOColors; - "textBody-secondary": IOColors; - "textBody-tertiary": IOColors; + "textHeading-default", + "textHeading-secondary", + "textHeading-tertiary", + "textBody-default", + "textBody-secondary", + "textBody-tertiary", // Design System related - "cardBorder-default": IOColors; - "icon-default": IOColors; - "icon-decorative": IOColors; + "cardBorder-default", + "icon-default", + "icon-decorative", // Layout - "divider-header": IOColors; - "divider-default": IOColors; - "divider-bottomBar": IOColors; + "divider-header", + "divider-default", + "divider-bottomBar", // Status - errorIcon: IOColors; - errorText: IOColors; - successText: IOColors; + "errorIcon", + "errorText", + "successText", // Pictograms - "pictogram-hands": IOColors; - "pictogram-tint-main": IOColors; - "pictogram-tint-secondary": IOColors; - "pictogram-tint-tertiary": IOColors; + "pictogram-hands", + "pictogram-tint-main", + "pictogram-tint-secondary", + "pictogram-tint-tertiary" +] as const; + +export type IOTheme = { + [K in (typeof themeKeys)[number]]: IOColors; }; export const IOThemeLight: IOTheme = { @@ -300,6 +306,8 @@ export const IOThemeLight: IOTheme = { "listItem-pressed": "grey-50", // Typography "textHeading-default": "black", + "textHeading-secondary": "grey-850", + "textHeading-tertiary": "grey-700", "textBody-default": "black", "textBody-secondary": "grey-850", "textBody-tertiary": "grey-700", @@ -340,6 +348,8 @@ export const IOThemeDark: IOTheme = { "listItem-pressed": "grey-850", // Typography "textHeading-default": "grey-200", + "textHeading-secondary": "grey-300", + "textHeading-tertiary": "grey-450", "textBody-default": "white", "textBody-secondary": "grey-100", "textBody-tertiary": "grey-450", diff --git a/src/core/IOStyles.ts b/src/core/IOStyles.ts index 8a320544..47430b98 100644 --- a/src/core/IOStyles.ts +++ b/src/core/IOStyles.ts @@ -1,5 +1,4 @@ -import { Platform, StyleSheet, Text } from "react-native"; -import { ComponentProps } from "react"; +import { Platform, StyleSheet } from "react-native"; import { IOIconSizeScale } from "../components/icons"; import { IOColors } from "./IOColors"; import { IOModuleIDPRadius } from "./IOShapes"; @@ -19,8 +18,6 @@ interface IOVisualCostants { appMarginDefault: IOAppMargin; // Header headerHeight: number; - // Typography - maxFontSizeMultiplier: ComponentProps["maxFontSizeMultiplier"]; // Dimensions avatarSizeSmall: number; avatarSizeMedium: number; @@ -35,7 +32,6 @@ interface IOVisualCostants { export const IOVisualCostants: IOVisualCostants = { appMarginDefault: 24, headerHeight: 56, - maxFontSizeMultiplier: 1.25, avatarSizeSmall: 44, avatarSizeMedium: 66, avatarRadiusSizeSmall: 8, diff --git a/src/utils/accessibility.ts b/src/utils/accessibility.ts index 31da6295..0b7b224d 100644 --- a/src/utils/accessibility.ts +++ b/src/utils/accessibility.ts @@ -1,6 +1,8 @@ import { pipe } from "fp-ts/lib/function"; import * as O from "fp-ts/lib/Option"; import I18n from "i18n-js"; +import { useEffect, useState } from "react"; +import { AccessibilityInfo, Platform } from "react-native"; /** * This function is used to get the text that will be read by the screen reader @@ -15,3 +17,35 @@ export const getAccessibleAmountText = (amount?: string) => ), O.getOrElseW(() => undefined) ); + +/** + * Query whether a bold text is currently enabled. The result is true + * when bold text is enabled and false otherwise. + */ +export const useBoldTextEnabled = () => { + const [boldTextEnabled, setBoldTextEnabled] = useState(false); + + useEffect(() => { + if (Platform.OS !== "web") { + const boldTextChangedSubscription = AccessibilityInfo.addEventListener( + "boldTextChanged", + isBoldTextEnabled => { + setBoldTextEnabled(isBoldTextEnabled); + } + ); + + AccessibilityInfo.isBoldTextEnabled() + .then(isBoldTextEnabled => { + setBoldTextEnabled(isBoldTextEnabled); + }) + .catch(_ => false); + + return () => { + boldTextChangedSubscription.remove(); + }; + } + return; + }, []); + + return boldTextEnabled; +}; diff --git a/src/utils/fonts.ts b/src/utils/fonts.ts index b7bfb69c..2ff4be4f 100644 --- a/src/utils/fonts.ts +++ b/src/utils/fonts.ts @@ -4,7 +4,7 @@ * README file included in this repository. */ -import { Platform } from "react-native"; +import { Platform, TextStyle } from "react-native"; /** * Choose the font name based on the platform @@ -13,33 +13,48 @@ const fonts = { TitilliumSansPro: Platform.select({ android: "TitilliumSansPro", web: "TitilliumSansPro", - ios: "Titillium Sans Pro" + ios: "Titillium Sans Pro", + default: "TitilliumSansPro" }), ReadexPro: Platform.select({ android: "ReadexPro", web: "ReadexPro", - ios: "Readex Pro" + ios: "Readex Pro", + default: "ReadexPro" }), DMMono: Platform.select({ android: "DMMono", web: "DMMono", - ios: "DM Mono" + ios: "DM Mono", + default: "DMMono" }) }; export type IOFontFamily = keyof typeof fonts; +/* + * Font Sizes + */ +const fontSizes = [12, 14, 16, 20, 22, 26, 28, 32] as const; +const fontSizesLegacy = [18, 28, 31, 35] as const; +const allFontSizes = [...new Set([...fontSizes, ...fontSizesLegacy])]; +export type IOFontSize = (typeof allFontSizes)[number]; + +/* + * Font Weights + */ + const weights = ["Light", "Regular", "Medium", "Semibold", "Bold"] as const; export type IOFontWeight = (typeof weights)[number]; const weightValues = ["300", "400", "500", "600", "700"] as const; -export type FontWeightValue = (typeof weightValues)[number]; +export type IOFontWeightNumeric = (typeof weightValues)[number]; /** * Mapping between the nominal description of the weight (also the postfix used on Android) and the numeric value * used on iOS */ -export const fontWeights: Record = { +export const fontWeights: Record = { Light: "300", Regular: "400", Medium: "500", @@ -47,30 +62,28 @@ export const fontWeights: Record = { Bold: "700" }; -export type FontFamily = keyof typeof fonts; -export type FontWeight = keyof typeof fontWeights; - -/** - * Mapping between the nominal description of the weight (also the postfix used on Android) and the numeric value - * used on iOS - */ -export const fontWeightsMap: Record = { - Light: "300", - Regular: "400", - Medium: "500", - Semibold: "600", - Bold: "700" +type FontStyleObject = { + fontSize: IOFontSize; + /* We also accept `string` because Android needs a composed + fontFamily name, like `TitilliumSansPro-Regular` */ + fontFamily: string | IOFontFamily; + fontWeight?: IOFontWeightNumeric; + lineHeight?: TextStyle["lineHeight"]; + fontStyle?: TextStyle["fontStyle"]; + boldEnabled?: boolean; }; -export enum FontStyle { - "normal" = "normal", - "italic" = "italic" -} - -type FontStyleObject = { - fontFamily: string; - fontWeight?: FontWeightValue; - fontStyle?: FontStyle; +/* Function that, given a certain weight, returns the next +available `FontWeight` value. +For example, if I set it to `Regular`, the function +should return `Medium`, and so on. If I set it to the last `FontWeight` +value, the function will return the same value. +*/ +const getBolderFontWeight = (weight: IOFontWeight): IOFontWeight => { + const currentWeight = weights.indexOf(weight); + return currentWeight === weights.length - 1 + ? weight + : weights[currentWeight + 1]; }; /** @@ -80,42 +93,73 @@ type FontStyleObject = { * @param isItalic */ export const makeFontFamilyName = ( - font: FontFamily, - weight?: IOFontWeight, - isItalic: boolean = false -): string => + font: IOFontFamily, + weight: IOFontWeight = defaultWeight, + fontStyle: TextStyle["fontStyle"] = "normal" +): FontStyleObject["fontFamily"] => Platform.select({ web: fonts[font], - android: `${fonts[font]}-${weight || "Regular"}${isItalic ? "Italic" : ""}`, + android: `${fonts[font]}-${weight || "Regular"}${ + fontStyle === "italic" ? "Italic" : "" + }`, ios: fonts[font], - default: "undefined" + default: fonts[font] }); +/** + * Default `IOText` typography style + */ +const defaultFont: IOFontFamily = "TitilliumSansPro"; +const defaultWeight: IOFontWeight = "Regular"; +const defaultFontSize: IOFontSize = 16; + /** * Return a {@link FontStyleObject} with the fields filled based on the platform (iOS or Android). - * @param weight - * @param isItalic + * @param size * @param font + * @param weight + * @param fontStyle */ + export const makeFontStyleObject = ( - weight: IOFontWeight | undefined = undefined, - isItalic: boolean | undefined = false, - font: FontFamily | undefined = "TitilliumSansPro" -): FontStyleObject => - Platform.select({ + size: IOFontSize = defaultFontSize, + font: IOFontFamily = defaultFont, + lineHeight: TextStyle["lineHeight"], + weight: IOFontWeight = defaultWeight, + fontStyle: TextStyle["fontStyle"] = "normal", + boldEnabled: boolean = false +): FontStyleObject => { + /* If bold text is currently enabled, we select the next + available `IOFontWeight` value */ + const dynamicWeight = boldEnabled ? getBolderFontWeight(weight) : weight; + + return Platform.select({ web: { - fontFamily: makeFontFamilyName(font, weight, isItalic), - fontWeight: weight !== undefined ? fontWeightsMap[weight] : weight, - fontStyle: isItalic ? FontStyle.italic : FontStyle.normal + fontSize: size, + fontFamily: makeFontFamilyName(font, dynamicWeight, fontStyle), + fontWeight: fontWeights[dynamicWeight], + lineHeight, + fontStyle }, + // On Android other type attributes, like `fontWeight` or `fontStyle` + // are directly managed through the `fontFamily` name, so we dont' need to + // include them in the object. android: { - includeFontPadding: false, - fontFamily: makeFontFamilyName(font, weight, isItalic) + fontSize: size, + fontFamily: makeFontFamilyName(font, dynamicWeight, fontStyle), + lineHeight, + includeFontPadding: false }, ios: { - fontFamily: makeFontFamilyName(font, weight, isItalic), - fontWeight: weight !== undefined ? fontWeightsMap[weight] : weight, - fontStyle: isItalic ? FontStyle.italic : FontStyle.normal + fontSize: size, + fontFamily: makeFontFamilyName(font, dynamicWeight, fontStyle), + fontWeight: fontWeights[dynamicWeight], + lineHeight, + fontStyle }, - default: { fontFamily: "undefined" } + default: { + fontSize: size, + fontFamily: makeFontFamilyName(font, dynamicWeight, fontStyle) + } }); +}; diff --git a/stories/featureInfo/FeatureInfo.stories.ts b/stories/featureInfo/FeatureInfo.stories.ts index 70232416..4c94b05f 100644 --- a/stories/featureInfo/FeatureInfo.stories.ts +++ b/stories/featureInfo/FeatureInfo.stories.ts @@ -27,9 +27,11 @@ type Story = StoryObj; export const Primary: Story = { args: { body: "Dopo questo passaggio non sarà più possibile annullare il pagamento", - actionLabel: "Conferma", - actionOnPress: e => { - action("clicked")(e); + action: { + label: "Conferma", + onPress: e => { + action("clicked")(e); + } } } }; diff --git a/stories/foundation/typography/Link.stories.ts b/stories/foundation/typography/Link.stories.ts deleted file mode 100644 index daeab1ee..00000000 --- a/stories/foundation/typography/Link.stories.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Meta, StoryObj } from "@storybook/react"; - -import { Alert } from "react-native"; -import { LabelLink } from "../../../src/components"; - -// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export -const meta = { - title: "Foundation/Typography/Link", - component: LabelLink, - parameters: { - // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/react/configure/story-layout - layout: "centered", - actions: { argTypesRegex: "^on.*" } - }, - // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs - tags: ["autodocs"] -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -export const Primary: Story = { - args: { - accessibilityLabel: "Tap to trigger test alert", - onPress: () => Alert.alert("Alert", "Action triggered"), - children: "Hello World" - } -}; From 72467a9b189b27a994d2419df54a86c89f288bfc Mon Sep 17 00:00:00 2001 From: Damiano Plebani Date: Mon, 21 Oct 2024 17:00:06 +0200 Subject: [PATCH 11/11] chore: release 2.0.3 --- CHANGELOG.md | 9 ++++++++- package.json | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34958a8d..b49d87f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,15 +4,22 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [v2.0.3](https://github.com/pagopa/io-app-design-system/compare/v2.0.2...v2.0.3) + +- Make the `2.x` version the official, latest release. [`#339`](https://github.com/pagopa/io-app-design-system/pull/339) +- [IOAPPX-402] Add full dark mode support to `ListItemTransaction` [`#337`](https://github.com/pagopa/io-app-design-system/pull/337) + #### [v2.0.2](https://github.com/pagopa/io-app-design-system/compare/v2.0.1...v2.0.2) +> 17 October 2024 + - [IOAPPX-400] Add `testID` to `ContentWrapper` [`#336`](https://github.com/pagopa/io-app-design-system/pull/336) - [IOAPPX-398] Add dark mode compatibility to `HeaderSecondLevel` [`#335`](https://github.com/pagopa/io-app-design-system/pull/335) - [IOAPPX-353] Add the new `FooterActions` (from `io-app`) and `FooterActionsInline` [`#316`](https://github.com/pagopa/io-app-design-system/pull/316) - feat: [EUDIW-54] Add new pictograms for EUDIW app [`#332`](https://github.com/pagopa/io-app-design-system/pull/332) - chore: release 1.46.2 [`492b8a6`](https://github.com/pagopa/io-app-design-system/commit/492b8a67d452c93b47b6a3ca23a1dd3d191b267f) +- chore: release 2.0.2 [`f904e02`](https://github.com/pagopa/io-app-design-system/commit/f904e025a426d346e0e3848f5ae572487bfe5048) - chore: release 1.47.0 [`5b3f8a6`](https://github.com/pagopa/io-app-design-system/commit/5b3f8a650fa3c7573000eb35a332d0906d0551ed) -- chore: release 1.47.2 [`2ccec35`](https://github.com/pagopa/io-app-design-system/commit/2ccec35de737493b3092592fe63911c77e1abef3) #### [v2.0.1](https://github.com/pagopa/io-app-design-system/compare/v2.0.0...v2.0.1) diff --git a/package.json b/package.json index f075df1a..7b1f07fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@pagopa/io-app-design-system", - "version": "2.0.2", + "version": "2.0.3", "description": "The library defining the core components of the design system of @pagopa/io-app", "main": "lib/commonjs/index", "module": "lib/module/index",