From 0935731d958cd1955d4fefefba1a97da7cb8245b Mon Sep 17 00:00:00 2001 From: Cristiano Tofani Date: Wed, 15 Nov 2023 16:42:59 +0100 Subject: [PATCH 01/10] Adds Placeholder loading state --- example/src/pages/Selection.tsx | 8 +++++ src/components/listitems/ListItemRadio.tsx | 37 ++++++++++++++++++++-- src/components/radio/RadioGroup.tsx | 2 ++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/example/src/pages/Selection.tsx b/example/src/pages/Selection.tsx index 358ea3aa..c5e83c8c 100644 --- a/example/src/pages/Selection.tsx +++ b/example/src/pages/Selection.tsx @@ -169,6 +169,14 @@ const mockRadioItems = (): ReadonlyArray> => [ "Ti contatteranno solo i servizi che hanno qualcosa di importante da dirti.", id: "example-disabled", disabled: true + }, + { + value: "Let's try with a disabled item", + description: + "Ti contatteranno solo i servizi che hanno qualcosa di importante da dirti.", + id: "example-loading", + disabled: true, + loading: true } ]; diff --git a/src/components/listitems/ListItemRadio.tsx b/src/components/listitems/ListItemRadio.tsx index ae5b89bd..7ae7b2bf 100644 --- a/src/components/listitems/ListItemRadio.tsx +++ b/src/components/listitems/ListItemRadio.tsx @@ -1,6 +1,6 @@ import * as React from "react"; import { useCallback, useState } from "react"; -import { Pressable, View } from "react-native"; +import { Dimensions, Pressable, View } from "react-native"; import ReactNativeHapticFeedback from "react-native-haptic-feedback"; import Animated, { Extrapolate, @@ -11,6 +11,7 @@ import Animated, { useSharedValue, withSpring } from "react-native-reanimated"; +import Placeholder from "rn-placeholder"; import { IOColors, IOScaleValues, @@ -33,6 +34,7 @@ type Props = WithTestID<{ icon?: IOIcons; selected: boolean; onValueChange?: (newValue: boolean) => void; + loading?: boolean; }>; const DISABLED_OPACITY = 0.5; @@ -59,6 +61,7 @@ export const ListItemRadio = ({ selected, disabled, onValueChange, + loading = false, testID }: OwnProps) => { const [toggleValue, setToggleValue] = useState(selected ?? false); @@ -123,7 +126,37 @@ export const ListItemRadio = ({ } }; - return ( + const SkeletonComponent = () => ( + + + + + + + + + + + + + + + + + + ); + + return loading ? ( + + ) : ( = { description?: string; icon?: IOIcons; disabled?: boolean; + loading?: boolean; }; type Props = { @@ -33,6 +34,7 @@ export const RadioGroup = ({ items, selectedItem, onPress }: Props) => ( description={item.description} icon={item.icon} disabled={item.disabled} + loading={item.loading} onValueChange={() => onPress(item.id)} selected={selectedItem === item.id} /> From 80f214f70fa0c81477e4a5c255948aea905d916f Mon Sep 17 00:00:00 2001 From: Cristiano Tofani Date: Thu, 16 Nov 2023 09:12:46 +0100 Subject: [PATCH 02/10] Adds the possibility to use a `paymentLogo` instead of icon component --- example/src/pages/Selection.tsx | 9 +++++- src/components/listitems/ListItemRadio.tsx | 34 +++++++++++++++------- src/components/radio/RadioGroup.tsx | 7 ++--- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/example/src/pages/Selection.tsx b/example/src/pages/Selection.tsx index c5e83c8c..886e41fe 100644 --- a/example/src/pages/Selection.tsx +++ b/example/src/pages/Selection.tsx @@ -147,7 +147,14 @@ const renderListItemCheckbox = () => ( const mockRadioItems = (): ReadonlyArray> => [ { - icon: "coggle", + startImage: { icon: "coggle" }, + value: "Let's try with a basic title", + description: + "Ti contatteranno solo i servizi che hanno qualcosa di importante da dirti. Potrai sempre disattivare le comunicazioni che non ti interessano.", + id: "example-1" + }, + { + startImage: { paymentLogo: "myBank" }, value: "Let's try with a basic title", description: "Ti contatteranno solo i servizi che hanno qualcosa di importante da dirti. Potrai sempre disattivare le comunicazioni che non ti interessano.", diff --git a/src/components/listitems/ListItemRadio.tsx b/src/components/listitems/ListItemRadio.tsx index 7ae7b2bf..b1db36ca 100644 --- a/src/components/listitems/ListItemRadio.tsx +++ b/src/components/listitems/ListItemRadio.tsx @@ -1,6 +1,6 @@ import * as React from "react"; import { useCallback, useState } from "react"; -import { Dimensions, Pressable, View } from "react-native"; +import { Pressable, View } from "react-native"; import ReactNativeHapticFeedback from "react-native-haptic-feedback"; import Animated, { Extrapolate, @@ -27,14 +27,19 @@ import { IOIcons, Icon } from "../icons"; import { HSpacer, VSpacer } from "../spacer"; import { H6, LabelSmall } from "../typography"; import { AnimatedRadio } from "../radio/AnimatedRadio"; +import { IOLogoPaymentType, LogoPayment } from "../logos"; + +type ListItemRadioGraphicProps = + | { icon?: never; paymentLogo: IOLogoPaymentType } + | { icon: IOIcons; paymentLogo?: never }; type Props = WithTestID<{ value: string; description?: string; - icon?: IOIcons; selected: boolean; onValueChange?: (newValue: boolean) => void; loading?: boolean; + startImage?: ListItemRadioGraphicProps; }>; const DISABLED_OPACITY = 0.5; @@ -48,7 +53,7 @@ type OwnProps = Props & >; /** - * with the automatic state management that uses a {@link AnimatedCheckBox} + * `ListItemRadio` component with the automatic state management that uses a {@link AnimatedCheckBox} * The toggleValue change when a `onPress` event is received and dispatch the `onValueChange`. * * @param props @@ -57,7 +62,7 @@ type OwnProps = Props & export const ListItemRadio = ({ value, description, - icon, + startImage, selected, disabled, onValueChange, @@ -178,17 +183,26 @@ export const ListItemRadio = ({ - {icon && ( + {startImage && ( - + {/* icon or paymentLogo props are mutually exclusive */} + {startImage.icon && ( + + )} + {startImage.paymentLogo && ( + + )} )} diff --git a/src/components/radio/RadioGroup.tsx b/src/components/radio/RadioGroup.tsx index 66f192e5..c80f70e3 100644 --- a/src/components/radio/RadioGroup.tsx +++ b/src/components/radio/RadioGroup.tsx @@ -1,16 +1,15 @@ -import React from "react"; +import React, { ComponentProps } from "react"; import { View } from "react-native"; import { Divider } from "../divider"; -import { IOIcons } from "../icons"; import { ListItemRadio } from "../listitems/ListItemRadio"; export type RadioItem = { id: T; value: string; description?: string; - icon?: IOIcons; disabled?: boolean; loading?: boolean; + startImage?: ComponentProps["startImage"]; }; type Props = { @@ -32,7 +31,7 @@ export const RadioGroup = ({ items, selectedItem, onPress }: Props) => ( testID={`RadioItemTestID_${item.id}`} value={item.value} description={item.description} - icon={item.icon} + startImage={item.startImage} disabled={item.disabled} loading={item.loading} onValueChange={() => onPress(item.id)} From 2f06143970e27a5988811fe1c5cc759d08b2811a Mon Sep 17 00:00:00 2001 From: Cristiano Tofani Date: Thu, 16 Nov 2023 14:58:19 +0100 Subject: [PATCH 03/10] fix id radiogroup --- example/src/pages/Selection.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/src/pages/Selection.tsx b/example/src/pages/Selection.tsx index 886e41fe..aa464b57 100644 --- a/example/src/pages/Selection.tsx +++ b/example/src/pages/Selection.tsx @@ -151,14 +151,14 @@ const mockRadioItems = (): ReadonlyArray> => [ value: "Let's try with a basic title", description: "Ti contatteranno solo i servizi che hanno qualcosa di importante da dirti. Potrai sempre disattivare le comunicazioni che non ti interessano.", - id: "example-1" + id: "example-icon" }, { startImage: { paymentLogo: "myBank" }, value: "Let's try with a basic title", description: "Ti contatteranno solo i servizi che hanno qualcosa di importante da dirti. Potrai sempre disattivare le comunicazioni che non ti interessano.", - id: "example-1" + id: "example-paymentLogo" }, { value: "Let's try with a basic title", From 9d34c3fc5fee1bd4f51d40d95a80462c66b73869 Mon Sep 17 00:00:00 2001 From: Cristiano Tofani Date: Thu, 16 Nov 2023 15:00:30 +0100 Subject: [PATCH 04/10] adds disabled opacity on loading version --- src/components/listitems/ListItemRadio.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/listitems/ListItemRadio.tsx b/src/components/listitems/ListItemRadio.tsx index b1db36ca..95c6c803 100644 --- a/src/components/listitems/ListItemRadio.tsx +++ b/src/components/listitems/ListItemRadio.tsx @@ -131,6 +131,8 @@ export const ListItemRadio = ({ } }; + const disabledStyle = { opacity: disabled ? DISABLED_OPACITY : 1 }; + const SkeletonComponent = () => ( - + @@ -174,7 +176,7 @@ export const ListItemRadio = ({ style={[ IOSelectionListItemStyles.listItem, animatedBackgroundStyle, - { opacity: disabled ? DISABLED_OPACITY : 1 } + disabledStyle ]} // This is required to avoid opacity // inheritance on Android From 32cfb82d876be74fc376467b4591a1e0820c61d1 Mon Sep 17 00:00:00 2001 From: Cristiano Tofani Date: Thu, 16 Nov 2023 15:41:57 +0100 Subject: [PATCH 05/10] minor refinement on loading placeholder dimensions --- src/components/listitems/ListItemRadio.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/listitems/ListItemRadio.tsx b/src/components/listitems/ListItemRadio.tsx index 95c6c803..d98476f1 100644 --- a/src/components/listitems/ListItemRadio.tsx +++ b/src/components/listitems/ListItemRadio.tsx @@ -152,12 +152,12 @@ export const ListItemRadio = ({ - - - - - - + + + + + + ); From 2dfe8556210919d430e84bfc25f6a239f09bba64 Mon Sep 17 00:00:00 2001 From: Damiano Plebani Date: Thu, 16 Nov 2023 15:58:04 +0100 Subject: [PATCH 06/10] Improve visual appearance of the skeleton in the `ListItemRadio` component --- src/components/listitems/ListItemRadio.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/listitems/ListItemRadio.tsx b/src/components/listitems/ListItemRadio.tsx index d98476f1..b0f57858 100644 --- a/src/components/listitems/ListItemRadio.tsx +++ b/src/components/listitems/ListItemRadio.tsx @@ -144,7 +144,13 @@ export const ListItemRadio = ({ needsOffscreenAlphaCompositing={true} > - + @@ -152,7 +158,7 @@ export const ListItemRadio = ({ - + From d0e83ce55ee75edcf91eef20a9432baf995b951b Mon Sep 17 00:00:00 2001 From: Cristiano Tofani Date: Mon, 20 Nov 2023 16:35:41 +0100 Subject: [PATCH 07/10] increment loading feature --- example/src/pages/Selection.tsx | 27 ++++- src/components/listitems/ListItemRadio.tsx | 116 +++++++++++++++------ src/components/radio/RadioGroup.tsx | 4 +- 3 files changed, 110 insertions(+), 37 deletions(-) diff --git a/example/src/pages/Selection.tsx b/example/src/pages/Selection.tsx index aa464b57..ea1bd283 100644 --- a/example/src/pages/Selection.tsx +++ b/example/src/pages/Selection.tsx @@ -183,7 +183,32 @@ const mockRadioItems = (): ReadonlyArray> => [ "Ti contatteranno solo i servizi che hanno qualcosa di importante da dirti.", id: "example-loading", disabled: true, - loading: true + loadingProps: { + loading: true, + loadingSkeleton: "base" + } + }, + { + value: "Let's try with a disabled item", + description: + "Ti contatteranno solo i servizi che hanno qualcosa di importante da dirti.", + id: "example-loading_1", + disabled: true, + loadingProps: { + loading: true, + loadingSkeleton: "extended" + } + }, + { + value: "Let's try with a disabled item", + description: + "Ti contatteranno solo i servizi che hanno qualcosa di importante da dirti.", + id: "example-loading_2", + disabled: true, + loadingProps: { + loading: true, + loadingSkeleton: "extended_icon" + } } ]; diff --git a/src/components/listitems/ListItemRadio.tsx b/src/components/listitems/ListItemRadio.tsx index b0f57858..2f3d5ab5 100644 --- a/src/components/listitems/ListItemRadio.tsx +++ b/src/components/listitems/ListItemRadio.tsx @@ -33,13 +33,23 @@ type ListItemRadioGraphicProps = | { icon?: never; paymentLogo: IOLogoPaymentType } | { icon: IOIcons; paymentLogo?: never }; +type ListItemRadioLoadingProps = + | { + loading: true; + loadingSkeleton: "base" | "extended" | "extended_icon"; + } + | { + loading?: false; + loadingSkeleton?: never; + }; + type Props = WithTestID<{ value: string; description?: string; selected: boolean; onValueChange?: (newValue: boolean) => void; - loading?: boolean; startImage?: ListItemRadioGraphicProps; + loadingProps?: ListItemRadioLoadingProps; }>; const DISABLED_OPACITY = 0.5; @@ -66,13 +76,12 @@ export const ListItemRadio = ({ selected, disabled, onValueChange, - loading = false, + loadingProps, testID }: OwnProps) => { const [toggleValue, setToggleValue] = useState(selected ?? false); // Animations const isPressed: Animated.SharedValue = useSharedValue(0); - // Scaling transformation applied when the button is pressed const animationScaleValue = IOScaleValues?.basicButton?.pressedState; @@ -133,41 +142,80 @@ export const ListItemRadio = ({ const disabledStyle = { opacity: disabled ? DISABLED_OPACITY : 1 }; - const SkeletonComponent = () => ( - - - - - - - + const SkeletonComponent = () => + loadingProps && loadingProps.loading ? ( + + + + {loadingProps.loadingSkeleton === "extended_icon" && ( + + + + )} + + + + + + {loadingProps.loadingSkeleton !== "base" && ( + <> + + + + + + + + )} - - - - - - - - ); + ) : null; - return loading ? ( + return loadingProps && loadingProps.loading ? ( ) : ( = { value: string; description?: string; disabled?: boolean; - loading?: boolean; startImage?: ComponentProps["startImage"]; + loadingProps?: ComponentProps["loadingProps"]; }; type Props = { @@ -33,7 +33,7 @@ export const RadioGroup = ({ items, selectedItem, onPress }: Props) => ( description={item.description} startImage={item.startImage} disabled={item.disabled} - loading={item.loading} + loadingProps={item.loadingProps} onValueChange={() => onPress(item.id)} selected={selectedItem === item.id} /> From 6cb077f28554f0dd04edc43bac99acaf53fd3328 Mon Sep 17 00:00:00 2001 From: Cristiano Tofani Date: Mon, 20 Nov 2023 17:12:02 +0100 Subject: [PATCH 08/10] fixes --- example/src/pages/Selection.tsx | 12 ++++++------ src/components/listitems/ListItemRadio.tsx | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/example/src/pages/Selection.tsx b/example/src/pages/Selection.tsx index ea1bd283..d99a5646 100644 --- a/example/src/pages/Selection.tsx +++ b/example/src/pages/Selection.tsx @@ -184,8 +184,8 @@ const mockRadioItems = (): ReadonlyArray> => [ id: "example-loading", disabled: true, loadingProps: { - loading: true, - loadingSkeleton: "base" + state: true, + skeletonType: "base" } }, { @@ -195,8 +195,8 @@ const mockRadioItems = (): ReadonlyArray> => [ id: "example-loading_1", disabled: true, loadingProps: { - loading: true, - loadingSkeleton: "extended" + state: true, + skeletonType: "extended" } }, { @@ -206,8 +206,8 @@ const mockRadioItems = (): ReadonlyArray> => [ id: "example-loading_2", disabled: true, loadingProps: { - loading: true, - loadingSkeleton: "extended_icon" + state: true, + skeletonType: "extended_icon" } } ]; diff --git a/src/components/listitems/ListItemRadio.tsx b/src/components/listitems/ListItemRadio.tsx index 2f3d5ab5..b219c49c 100644 --- a/src/components/listitems/ListItemRadio.tsx +++ b/src/components/listitems/ListItemRadio.tsx @@ -35,12 +35,12 @@ type ListItemRadioGraphicProps = type ListItemRadioLoadingProps = | { - loading: true; - loadingSkeleton: "base" | "extended" | "extended_icon"; + state: true; + skeletonType: "base" | "extended" | "extended_icon"; } | { - loading?: false; - loadingSkeleton?: never; + state?: false; + skeletonType?: never; }; type Props = WithTestID<{ @@ -143,7 +143,7 @@ export const ListItemRadio = ({ const disabledStyle = { opacity: disabled ? DISABLED_OPACITY : 1 }; const SkeletonComponent = () => - loadingProps && loadingProps.loading ? ( + loadingProps && loadingProps.state ? ( - {loadingProps.loadingSkeleton === "extended_icon" && ( + {loadingProps.skeletonType === "extended_icon" && ( - {loadingProps.loadingSkeleton !== "base" && ( + {loadingProps.skeletonType !== "base" && ( <> ) : null; - return loadingProps && loadingProps.loading ? ( + return loadingProps && loadingProps.state ? ( ) : ( Date: Tue, 21 Nov 2023 10:20:43 +0100 Subject: [PATCH 09/10] Add more props to `loadingProps` to improve code readability --- example/src/pages/Selection.tsx | 22 +++- src/components/listitems/ListItemRadio.tsx | 121 ++++++++++----------- 2 files changed, 72 insertions(+), 71 deletions(-) diff --git a/example/src/pages/Selection.tsx b/example/src/pages/Selection.tsx index d99a5646..dbccadca 100644 --- a/example/src/pages/Selection.tsx +++ b/example/src/pages/Selection.tsx @@ -185,29 +185,41 @@ const mockRadioItems = (): ReadonlyArray> => [ disabled: true, loadingProps: { state: true, - skeletonType: "base" + skeletonIcon: false } }, { value: "Let's try with a disabled item", description: "Ti contatteranno solo i servizi che hanno qualcosa di importante da dirti.", - id: "example-loading_1", + id: "example-loading-withIcon", disabled: true, loadingProps: { state: true, - skeletonType: "extended" + skeletonIcon: true } }, { value: "Let's try with a disabled item", description: "Ti contatteranno solo i servizi che hanno qualcosa di importante da dirti.", - id: "example-loading_2", + id: "example-loading-withDescription", disabled: true, loadingProps: { state: true, - skeletonType: "extended_icon" + skeletonDescription: true + } + }, + { + value: "Let's try with a disabled item", + description: + "Ti contatteranno solo i servizi che hanno qualcosa di importante da dirti.", + id: "example-loading-withIcon-withDescription", + disabled: true, + loadingProps: { + state: true, + skeletonDescription: true, + skeletonIcon: true } } ]; diff --git a/src/components/listitems/ListItemRadio.tsx b/src/components/listitems/ListItemRadio.tsx index b219c49c..10b9646f 100644 --- a/src/components/listitems/ListItemRadio.tsx +++ b/src/components/listitems/ListItemRadio.tsx @@ -36,11 +36,13 @@ type ListItemRadioGraphicProps = type ListItemRadioLoadingProps = | { state: true; - skeletonType: "base" | "extended" | "extended_icon"; + skeletonDescription?: boolean; + skeletonIcon?: boolean; } | { state?: false; - skeletonType?: never; + skeletonDescription?: never; + skeletonIcon?: never; }; type Props = WithTestID<{ @@ -142,80 +144,67 @@ export const ListItemRadio = ({ const disabledStyle = { opacity: disabled ? DISABLED_OPACITY : 1 }; - const SkeletonComponent = () => - loadingProps && loadingProps.state ? ( - - - - {loadingProps.skeletonType === "extended_icon" && ( - - - - )} + const SkeletonDescriptionLines = () => ( + <> + + + + + + + + ); + + const SkeletonIcon = () => ( + + + + ); + + const SkeletonComponent = () => ( + + + + + {loadingProps?.skeletonIcon && } - - - - + + + + - {loadingProps.skeletonType !== "base" && ( - <> - - - - - - - - )} - ) : null; + {loadingProps?.skeletonDescription && } + + ); - return loadingProps && loadingProps.state ? ( + return loadingProps?.state ? ( ) : ( Date: Tue, 21 Nov 2023 10:23:45 +0100 Subject: [PATCH 10/10] Delete unnecessary style from `ListItemRadio` (Skeleton component) --- src/components/listitems/ListItemRadio.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/listitems/ListItemRadio.tsx b/src/components/listitems/ListItemRadio.tsx index 10b9646f..6d418fa8 100644 --- a/src/components/listitems/ListItemRadio.tsx +++ b/src/components/listitems/ListItemRadio.tsx @@ -171,12 +171,7 @@ export const ListItemRadio = ({ ); const SkeletonComponent = () => ( - +