Skip to content

Commit

Permalink
chore: Adds missing toasts component (#90)
Browse files Browse the repository at this point in the history
## Short description
This PR migrates the missing toast provider implemented in the base
repository

## List of changes proposed in this pull request
- Toast provider and variants

## How to test
Chack the Example app page for the usage
  • Loading branch information
CrisTofani authored Oct 3, 2023
1 parent 2e5ca7e commit b887a4c
Show file tree
Hide file tree
Showing 18 changed files with 913 additions and 20 deletions.
4 changes: 2 additions & 2 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ EXTERNAL SOURCES:
:podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
hermes-engine:
:podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec"
:tag: hermes-2023-03-20-RNv0.72.0-49794cfc7c81fb8f69fd60c3bbf85a7480cc5a77
:tag: hermes-2023-03-07-RNv0.71.4-31fdcf738940875c9bacf251e149006cf515d763
RCT-Folly:
:podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec"
RCTRequired:
Expand Down Expand Up @@ -780,4 +780,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: 3682f715bd91b22067ed6990af779570157f6eb0

COCOAPODS: 1.12.1
COCOAPODS: 1.12.0
41 changes: 23 additions & 18 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
IOThemeContext,
IOThemeDark,
IOThemeLight,
IOThemes
IOThemes,
ToastProvider
} from "@pagopa/io-app-design-system";
import { useColorScheme } from "react-native";
import { GestureHandlerRootView } from "react-native-gesture-handler";
Expand Down Expand Up @@ -38,22 +39,26 @@ export default function App() {
const colorScheme = useColorScheme();

return (
<IOThemeContext.Provider
value={colorScheme === "dark" ? IOThemes.dark : IOThemes.light}
>
<IODSExperimentalContextProvider>
<NavigationContainer
theme={
colorScheme === "dark"
? IONavigationDarkTheme
: IONavigationLightTheme
}
>
<GestureHandlerRootView style={IOStyles.flex}>
<AppNavigator />
</GestureHandlerRootView>
</NavigationContainer>
</IODSExperimentalContextProvider>
</IOThemeContext.Provider>
<GestureHandlerRootView style={{ flex: 1 }}>
<IOThemeContext.Provider
value={colorScheme === "dark" ? IOThemes.dark : IOThemes.light}
>
<IODSExperimentalContextProvider>
<ToastProvider>
<NavigationContainer
theme={
colorScheme === "dark"
? IONavigationDarkTheme
: IONavigationLightTheme
}
>
<GestureHandlerRootView style={IOStyles.flex}>
<AppNavigator />
</GestureHandlerRootView>
</NavigationContainer>
</ToastProvider>
</IODSExperimentalContextProvider>
</IOThemeContext.Provider>
</GestureHandlerRootView>
);
}
9 changes: 9 additions & 0 deletions example/src/navigation/navigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { FooterWithButton } from "../pages/FooterWithButton";
import Modules from "../pages/Modules";
import { HeaderSecondLevelScreen } from "../pages/HeaderSecondLevel";
import { StaticHeaderSecondLevelScreen } from "../pages/StaticHeaderSecondLevel";
import { Toasts } from "../pages/Toasts";
import { AppParamsList } from "./params";
import APP_ROUTES from "./routes";

Expand Down Expand Up @@ -206,6 +207,14 @@ const AppNavigator = () => (
}}
/>

<Stack.Screen
name={APP_ROUTES.COMPONENTS.TOASTS.route}
component={Toasts}
options={{
headerTitle: APP_ROUTES.COMPONENTS.TOASTS.title
}}
/>

<Stack.Screen
name={APP_ROUTES.SCREENS.SEARCH.route}
component={Search}
Expand Down
1 change: 1 addition & 0 deletions example/src/navigation/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export type AppParamsList = {
[DESIGN_SYSTEM_ROUTES.COMPONENTS.FOOTER_WITH_BUTTON.route]: undefined;
[DESIGN_SYSTEM_ROUTES.COMPONENTS.HEADER_SECOND_LEVEL.route]: undefined;
[DESIGN_SYSTEM_ROUTES.COMPONENTS.HEADER_SECOND_LEVEL_STATIC.route]: undefined;
[DESIGN_SYSTEM_ROUTES.COMPONENTS.TOASTS.route]: undefined;
[DESIGN_SYSTEM_ROUTES.SCREENS.FULL_SCREEN_MODAL.route]: undefined;
[DESIGN_SYSTEM_ROUTES.SCREENS.SEARCH.route]: undefined;
[DESIGN_SYSTEM_ROUTES.SANDBOX.SANDBOX_SCREEN.route]: undefined;
Expand Down
4 changes: 4 additions & 0 deletions example/src/navigation/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ const APP_ROUTES = {
route: "DESIGN_SYSTEM_HEADER_SECOND_LEVEL_STATIC",
title: "Header Second Level Static"
},
TOASTS: {
route: "DESIGN_SYSTEM_TOASTS",
title: "Toasts"
},
FOOTER_WITH_BUTTON: {
route: "DESIGN_SYSTEM_FOOTER_WITH_BUTTON",
title: "Footer with button"
Expand Down
40 changes: 40 additions & 0 deletions example/src/pages/Toasts.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from "react";
import { ButtonSolid, VSpacer, useIOToast } from "@pagopa/io-app-design-system";
import { Screen } from "../components/Screen";

export const Toasts = () => {
const { error, show, info, success, warning } = useIOToast();
return (
<Screen>
<ButtonSolid
onPress={() => error("Error Toast")}
accessibilityLabel=""
label="Toast Error"
/>
<VSpacer />
<ButtonSolid
accessibilityLabel=""
onPress={() => info("Info Toast")}
label="Toast Info"
/>
<VSpacer />
<ButtonSolid
accessibilityLabel=""
onPress={() => show("Toast show simple")}
label="Toast show"
/>
<VSpacer />
<ButtonSolid
accessibilityLabel=""
onPress={() => success("Success Toast")}
label="Toast success"
/>
<VSpacer />
<ButtonSolid
accessibilityLabel=""
onPress={() => warning("Warning Toast")}
label="Toast warning"
/>
</Screen>
);
};
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"@storybook/react-webpack5": "^7.4.0",
"@storybook/testing-library": "^0.2.0",
"@types/jest": "^28.1.2",
"@types/lodash": "^4.14.157",
"@types/react": "~17.0.38",
"@types/react-native": "0.70.0",
"babel-loader": "^9.1.3",
Expand Down Expand Up @@ -170,6 +171,7 @@
]
},
"dependencies": {
"lodash": "^4.17.21",
"@expo/vector-icons": "^13.0.0",
"@pagopa/ts-commons": "^12.0.0",
"@testing-library/jest-native": "^5.4.2",
Expand Down
1 change: 1 addition & 0 deletions src/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export * from "./spacer";
export * from "./switch";
export * from "./tag";
export * from "./tabs";
export * from "./toast";
export * from "./typography";
export * from "./textInput";
export * from "./layout";
76 changes: 76 additions & 0 deletions src/components/layout/Dismissable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React from "react";
import { Dimensions } from "react-native";
import { Gesture, GestureDetector } from "react-native-gesture-handler";
import Animated, {
Easing,
runOnJS,
useAnimatedStyle,
useSharedValue,
withSpring,
withTiming
} from "react-native-reanimated";
import { WithTestID } from "../../utils/types";

const windowWidth = Dimensions.get("window").width;

type Dismissable = WithTestID<{
onDismiss?: () => void;
dismissThreshold?: number;
children: React.ReactNode;
}>;

/**
* Component that allows for a dismissable gesture, both left and right.
* When the threshold is reached, the `onDismiss` callback is called.
* @param onDismiss Callback to be called when the threshold is reached.
* @param dismissThreshold Threshold to be reached to call the `onDismiss` callback.
* @param children Children to be rendered inside the component.
* @returns A dismissable component.
*/
const Dismissable = ({
onDismiss = () => undefined,
dismissThreshold = windowWidth / 3,
children,
testID
}: Dismissable) => {
const translateX = useSharedValue(0);

const animatedStyle = useAnimatedStyle(() => ({
transform: [
{
translateX: translateX.value
}
]
}));

const pan = Gesture.Pan()
.onUpdate(event => {
// eslint-disable-next-line functional/immutable-data
translateX.value = event.translationX;
})
.onEnd(event => {
if (Math.abs(event.translationX) > dismissThreshold) {
// eslint-disable-next-line functional/immutable-data
translateX.value = withTiming(
windowWidth * Math.sign(event.translationX),
{
duration: 300,
easing: Easing.inOut(Easing.exp)
},
runOnJS(onDismiss)
);
} else {
// eslint-disable-next-line functional/immutable-data
translateX.value = withSpring(0, { mass: 0.5 });
}
})
.withTestId(testID ?? "");

return (
<GestureDetector gesture={pan}>
<Animated.View style={animatedStyle}>{children}</Animated.View>
</GestureDetector>
);
};

export { Dismissable };
76 changes: 76 additions & 0 deletions src/components/toast/ToastNotification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React from "react";
import { StyleSheet, View } from "react-native";
import { Icon } from "../icons";
import { IOColors, IOAlertRadius } from "../../core";
import { ButtonText } from "../typography";
import { Toast, ToastVariant } from "./types";

type ColorVariant = {
background: IOColors;
stroke: IOColors;
};

const toastColorVariants: Record<ToastVariant, ColorVariant> = {
neutral: {
background: "turquoise-150",
stroke: "turquoise-850"
},
error: {
background: "error-100",
stroke: "error-850"
},
info: {
background: "info-100",
stroke: "info-850"
},
success: {
background: "success-100",
stroke: "success-850"
},
warning: {
background: "warning-100",
stroke: "warning-850"
}
};

type Props = Pick<Toast, "message" | "variant" | "icon">;

const ToastNotification = ({ message, variant = "neutral", icon }: Props) => {
const colors = toastColorVariants[variant];

return (
<View
style={[
styles.toast,
{
backgroundColor: IOColors[colors.background],
borderColor: IOColors[colors.stroke]
}
]}
accessible={true}
accessibilityRole={"alert"}
accessibilityLabel={message}
>
<ButtonText color={colors.stroke} style={styles.content}>
{message}
</ButtonText>
{icon && <Icon name={icon} size={24} color={colors.stroke} />}
</View>
);
};

const styles = StyleSheet.create({
toast: {
borderRadius: IOAlertRadius,
borderWidth: 1,
padding: 16,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between"
},
content: {
paddingVertical: 2
}
});

export { ToastNotification };
Loading

0 comments on commit b887a4c

Please sign in to comment.