Skip to content

Commit

Permalink
fix: [#173702628] Reworks accordion component and improves accessibil…
Browse files Browse the repository at this point in the history
…ity (#2033)

* [#173702628] Reworks accordion component and improves accessibility

* Fix lint errors

* Fix for Voiceover support

* [#173702628] add parenthesis

* text update

Co-authored-by: Matteo Boschi <[email protected]>
  • Loading branch information
CrisTofani and Undermaken authored Jul 13, 2020
1 parent f741a5d commit 632b035
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 71 deletions.
2 changes: 2 additions & 0 deletions locales/en/index.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
---
global:
accessibility:
expanded: Expanded paragraph
collapsed: Collapsed paragraph
activityIndicator:
label: Loading
hint: Wait for the content load
Expand Down
2 changes: 2 additions & 0 deletions locales/it/index.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
---
global:
accessibility:
expanded: Paragrafo espanso
collapsed: Paragrafo chiuso
activityIndicator:
label: Caricamento in corso
hint: Attendi il caricamento del contenuto
Expand Down
87 changes: 16 additions & 71 deletions ts/components/FAQComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,86 +1,31 @@
import { fromNullable } from "fp-ts/lib/Option";
import { Accordion, Text, View } from "native-base";
import * as React from "react";
import { StyleSheet } from "react-native";
import customVariables from "../theme/variables";
import {
FAQsCategoriesType,
FAQType,
getFAQsFromCategories
} from "../utils/faq";
import ItemSeparatorComponent from "./ItemSeparatorComponent";
import IconFont from "./ui/IconFont";
import Markdown from "./ui/Markdown";
import Accordion from "./ui/Accordion";

type Props = Readonly<{
faqCategories: ReadonlyArray<FAQsCategoriesType>;
onLinkClicked?: (url: string) => void;
}>;

const styles = StyleSheet.create({
header: {
flexDirection: "row",
justifyContent: "space-between",
paddingVertical: customVariables.spacerHeight
},
pad: {
paddingVertical: customVariables.spacerHeight
},
headerIcon: {
paddingHorizontal: 10,
alignSelf: "center"
},
noBorder: {
borderWidth: 0
},
flex: {
flex: 1
}
});

export default function FAQComponent(props: Props) {
const renderHeader = (item: FAQType, expanded: boolean) => {
return (
<React.Fragment>
<View style={styles.header}>
<Text bold={true} style={styles.flex}>
{item.title}
</Text>
<IconFont
name={"io-right"}
color={customVariables.brandPrimary}
size={24}
style={[
styles.headerIcon,
{
transform: [{ rotateZ: expanded ? "-90deg" : "90deg" }]
}
]}
const FAQComponent: React.FunctionComponent<Props> = (props: Props) => {
return (
<>
{getFAQsFromCategories(props.faqCategories).map(
(faqType: FAQType, i: number) => (
<Accordion
key={i}
title={faqType.title}
content={faqType.content}
onLinkClicked={props.onLinkClicked}
/>
</View>
{!expanded && <ItemSeparatorComponent noPadded={true} />}
</React.Fragment>
);
};

const renderContent = (item: FAQType) => (
<View style={styles.pad}>
<Markdown
onLinkClicked={(url: string) => {
fromNullable(props.onLinkClicked).map(s => s(url));
}}
>
{item.content}
</Markdown>
</View>
)
)}
</>
);
};

return (
<Accordion
dataArray={[...getFAQsFromCategories(props.faqCategories)]}
renderHeader={renderHeader}
renderContent={renderContent}
style={styles.noBorder}
/>
);
}
export default FAQComponent;
96 changes: 96 additions & 0 deletions ts/components/ui/Accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { fromNullable } from "fp-ts/lib/Option";
import { Text, View } from "native-base";
import * as React from "react";
import { StyleSheet } from "react-native";
import I18n from "../../i18n";
import customVariables from "../../theme/variables";
import ItemSeparatorComponent from "../ItemSeparatorComponent";
import TouchableDefaultOpacity from "../TouchableDefaultOpacity";
import IconFont from "./IconFont";
import Markdown from "./Markdown";

type Props = {
title: string;
content: string;
onLinkClicked?: (url: string) => void;
};

const styles = StyleSheet.create({
header: {
flexDirection: "row",
justifyContent: "space-between",
paddingVertical: customVariables.spacerHeight
},
pad: {
paddingVertical: customVariables.spacerHeight
},
headerIcon: {
paddingHorizontal: 10,
alignSelf: "center"
},
noBorder: {
borderWidth: 0
},
flex: {
flex: 1
}
});

const Accordion: React.FunctionComponent<Props> = (props: Props) => {
const [expanded, setExpanded] = React.useState(false);

const renderHeader = (title: string) => {
return (
<TouchableDefaultOpacity
accessible={true}
accessibilityRole={"button"}
accessibilityLabel={
props.title +
(expanded
? I18n.t("global.accessibility.expanded")
: I18n.t("global.accessibility.collapsed"))
}
onPress={() => setExpanded(!expanded)}
>
<View style={styles.header}>
<Text bold={true} style={styles.flex}>
{title}
</Text>
<IconFont
name={"io-right"}
color={customVariables.brandPrimary}
size={24}
style={[
styles.headerIcon,
{
transform: [{ rotateZ: expanded ? "-90deg" : "90deg" }]
}
]}
/>
</View>
{!expanded && <ItemSeparatorComponent noPadded={true} />}
</TouchableDefaultOpacity>
);
};

const renderContent = (content: string) => (
<View style={styles.pad} accessible={expanded}>
<Markdown
onLinkClicked={(url: string) => {
fromNullable(props.onLinkClicked).map(s => s(url));
}}
>
{content}
</Markdown>
</View>
);

return (
<>
{renderHeader(props.title)}
{expanded && renderContent(props.content)}
</>
);
};

export default Accordion;

0 comments on commit 632b035

Please sign in to comment.