Element functions are now split into multiple file and started the ground work for onPress support

This commit is contained in:
Clément Le Bihan
2023-04-10 21:43:34 +02:00
parent 87fecb7522
commit 0ce17054fc
5 changed files with 227 additions and 189 deletions

View File

@@ -0,0 +1,15 @@
import React from "react";
import { ElementProps } from "./ElementList";
import { RawElement } from "./RawElement";
import { Pressable } from "native-base";
export const Element = (props: ElementProps) => {
if (props.type === "text" && props.data?.onPress) {
return (
<Pressable onPress={props.data.onPress}>
<RawElement {...props} />
</Pressable>
);
}
return <RawElement {...props} />;
};

View File

@@ -2,6 +2,8 @@ import React from "react";
import { StyleProp, ViewStyle } from "react-native";
import IconButton from "../IconButton";
import { Ionicons } from "@expo/vector-icons";
import { RawElement } from "./RawElement";
import { Element } from "./Element";
import {
Box,
@@ -14,91 +16,18 @@ import {
Divider,
Switch,
Popover,
Pressable,
useBreakpointValue,
Select,
} from "native-base";
type ElementType = "custom" | "default" | "text" | "toggle" | "dropdown";
type DropdownOption = {
label: string;
value: string;
};
type ElementTextProps = {
text: string;
};
type ElementToggleProps = {
onToggle: (value: boolean) => void;
value: boolean;
defaultValue?: boolean;
};
type ElementDropdownProps = {
options: DropdownOption[];
onSelect: (value: string) => void;
value: string;
defaultValue?: string;
};
const getElementTextNode = ({ text }: ElementTextProps, disabled: boolean) => {
return (
<Text
style={{
opacity: disabled ? 0.4 : 0.6,
}}
>
{text}
</Text>
);
};
const getElementToggleNode = (
{ onToggle, value, defaultValue }: ElementToggleProps,
disabled: boolean
) => {
return (
<Switch
onToggle={onToggle}
isChecked={value ?? false}
defaultIsChecked={defaultValue}
disabled={disabled}
/>
);
};
const getElementDropdownNode = (
{ options, onSelect, value, defaultValue }: ElementDropdownProps,
disabled: boolean
) => {
return (
<Select
selectedValue={value}
onValueChange={onSelect}
defaultValue={defaultValue}
variant="filled"
isDisabled={disabled}
>
{options.map((option) => (
<Select.Item
key={option.label}
label={option.label}
value={option.value}
/>
))}
</Select>
);
};
type ElementProps = {
export type ElementProps = {
title: string;
icon?: React.ReactNode;
type?: ElementType | "custom";
helperText?: string;
description?: string;
disabled?: boolean;
onPress?: () => void;
data?:
| ElementTextProps
| ElementToggleProps
@@ -106,117 +35,6 @@ type ElementProps = {
| React.ReactNode;
};
const Element = ({
title,
icon,
type,
helperText,
description,
disabled,
onPress,
node,
data,
}: ElementProps) => {
const screenSize = useBreakpointValue({ base: "small", md: "big" });
const isSmallScreen = screenSize === "small";
return (
<Row
style={{
width: "100%",
height: 45,
padding: 15,
justifyContent: "space-between",
alignItems: "center",
}}
>
<Box
style={{
flexGrow: 1,
opacity: disabled ? 0.6 : 1,
}}
>
{icon}
<Column>
<Text isTruncated maxW={"95%"}>
{title}
</Text>
{description && (
<Text
isTruncated
maxW={"90%"}
style={{
opacity: 0.6,
fontSize: 12,
}}
>
{description}
</Text>
)}
</Column>
</Box>
<Box>
<Row
style={{
alignItems: "center",
}}
>
{helperText && (
<Popover
trigger={(triggerProps) => (
<Button
{...triggerProps}
color="gray.500"
leftIcon={
<Icon
as={Ionicons}
size={"md"}
name="help-circle-outline"
/>
}
variant="ghost"
/>
)}
>
<Popover.Content
accessibilityLabel={`Additionnal information for ${title}`}
style={{
maxWidth: isSmallScreen ? "90vw" : "20vw",
}}
>
<Popover.Arrow />
<Popover.Body>{helperText}</Popover.Body>
</Popover.Content>
</Popover>
)}
{(() => {
switch (type) {
case "text":
return getElementTextNode(
data as ElementTextProps,
disabled ?? false
);
case "toggle":
return getElementToggleNode(
data as ElementToggleProps,
disabled ?? false
);
case "dropdown":
return getElementDropdownNode(
data as ElementDropdownProps,
disabled ?? false
);
case "custom":
return data as React.ReactNode;
default:
return <Text>Unknown type</Text>;
}
})()}
</Row>
</Box>
</Row>
);
};
type ElementListProps = {
elements: ElementProps[];
style?: StyleProp<ViewStyle>;

View File

@@ -0,0 +1,79 @@
import {
Select,
Switch,
Text,
} from "native-base";
export type ElementType = "custom" | "default" | "text" | "toggle" | "dropdown";
export type DropdownOption = {
label: string;
value: string;
};
export type ElementTextProps = {
text: string;
onPress?: () => void;
};
export type ElementToggleProps = {
onToggle: (value: boolean) => void;
value: boolean;
defaultValue?: boolean;
};
export type ElementDropdownProps = {
options: DropdownOption[];
onSelect: (value: string) => void;
value: string;
defaultValue?: string;
};
export const getElementTextNode = ({ text }: ElementTextProps, disabled: boolean) => {
return (
<Text
style={{
opacity: disabled ? 0.4 : 0.6,
}}
>
{text}
</Text>
);
};
export const getElementToggleNode = (
{ onToggle, value, defaultValue }: ElementToggleProps,
disabled: boolean
) => {
return (
<Switch
onToggle={onToggle}
isChecked={value ?? false}
defaultIsChecked={defaultValue}
disabled={disabled}
/>
);
};
export const getElementDropdownNode = (
{ options, onSelect, value, defaultValue }: ElementDropdownProps,
disabled: boolean
) => {
return (
<Select
selectedValue={value}
onValueChange={onSelect}
defaultValue={defaultValue}
variant="filled"
isDisabled={disabled}
>
{options.map((option) => (
<Select.Item
key={option.label}
label={option.label}
value={option.value}
/>
))}
</Select>
);
};

View File

@@ -0,0 +1,126 @@
import React from "react";
import {
Box,
Button,
Column,
Divider,
Icon,
Popover,
Row,
Text,
useBreakpointValue,
} from "native-base";
import { Ionicons } from "@expo/vector-icons";
import { ElementProps } from "./ElementList";
import {
getElementDropdownNode,
getElementTextNode,
getElementToggleNode,
ElementDropdownProps,
ElementTextProps,
ElementToggleProps,
} from "./ElementTypes";
export const RawElement = (
{ title, icon, type, helperText, description, disabled, data }: ElementProps,
isHovered: boolean
) => {
const screenSize = useBreakpointValue({ base: "small", md: "big" });
const isSmallScreen = screenSize === "small";
return (
<Row
style={{
width: "100%",
height: 45,
padding: 15,
justifyContent: "space-between",
alignItems: "center",
}}
>
<Box
style={{
flexGrow: 1,
opacity: disabled ? 0.6 : 1,
}}
>
{icon}
<Column>
<Text isTruncated maxW={"95%"}>
{title}
</Text>
{description && (
<Text
isTruncated
maxW={"90%"}
style={{
opacity: 0.6,
fontSize: 12,
}}
>
{description}
</Text>
)}
</Column>
</Box>
<Box>
<Row
style={{
alignItems: "center",
}}
>
{helperText && (
<Popover
trigger={(triggerProps) => (
<Button
{...triggerProps}
color="gray.500"
leftIcon={
<Icon
as={Ionicons}
size={"md"}
name="help-circle-outline"
/>
}
variant="ghost"
/>
)}
>
<Popover.Content
accessibilityLabel={`Additionnal information for ${title}`}
style={{
maxWidth: isSmallScreen ? "90vw" : "20vw",
}}
>
<Popover.Arrow />
<Popover.Body>{helperText}</Popover.Body>
</Popover.Content>
</Popover>
)}
{(() => {
switch (type) {
case "text":
return getElementTextNode(
data as ElementTextProps,
disabled ?? false
);
case "toggle":
return getElementToggleNode(
data as ElementToggleProps,
disabled ?? false
);
case "dropdown":
return getElementDropdownNode(
data as ElementDropdownProps,
disabled ?? false
);
case "custom":
return data as React.ReactNode;
default:
return <Text>Unknown type</Text>;
}
})()}
</Row>
</Box>
</Row>
);
};

View File

@@ -90,11 +90,11 @@ const ProfileSettings = ({ navigation }: { navigation: any }) => {
{
type: "text",
title: "Email",
onPress: () => {
console.log("Go to email settings");
},
data: {
text: user.email || "Aucun email associé",
onPress: () => {
console.log("Go to email settings");
},
},
},
{