diff --git a/example/src/Examples/ListAccordionExample.tsx b/example/src/Examples/ListAccordionExample.tsx index 58c3841de5..ac2ab35771 100644 --- a/example/src/Examples/ListAccordionExample.tsx +++ b/example/src/Examples/ListAccordionExample.tsx @@ -56,6 +56,17 @@ const ListAccordionExample = () => { /> + + + } + title="Expandable list item" + expandDirection="upwards" + > + + + + ); }; diff --git a/example/src/Examples/ListAccordionGroupExample.tsx b/example/src/Examples/ListAccordionGroupExample.tsx index 51861858bb..8aa81bd001 100644 --- a/example/src/Examples/ListAccordionGroupExample.tsx +++ b/example/src/Examples/ListAccordionGroupExample.tsx @@ -71,6 +71,25 @@ const ListAccordionGroupExample = () => { + + + } + title="Expandable list item" + id="1" + > + + + + } + title="Expandable list item 2" + id="2" + > + + + + ); }; diff --git a/src/components/List/ListAccordion.tsx b/src/components/List/ListAccordion.tsx index 75505c7367..2691035188 100644 --- a/src/components/List/ListAccordion.tsx +++ b/src/components/List/ListAccordion.tsx @@ -18,7 +18,7 @@ import { ListAccordionGroupContext } from './ListAccordionGroup'; import type { ListChildProps, Style } from './utils'; import { getAccordionColors, getLeftStyles } from './utils'; import { useInternalTheme } from '../../core/theming'; -import type { ThemeProp } from '../../types'; +import type { InternalTheme, ThemeProp } from '../../types'; import MaterialCommunityIcon from '../MaterialCommunityIcon'; import TouchableRipple, { Props as TouchableRippleProps, @@ -136,6 +136,10 @@ export type Props = { * This can be used to enlarge the touchable area beyond the visible component. */ hitSlop?: TouchableRippleProps['hitSlop']; + /** + * Sets expansion direction for the accordion. + */ + expandDirection?: 'downwards' | 'upwards'; }; /** @@ -175,6 +179,39 @@ export type Props = { * export default MyComponent; * ``` */ +function getExpandedContent({ + isExpanded, + children, + left, + theme, +}: { + isExpanded: boolean; + children: React.ReactNode; + left?: Props['left']; + theme: InternalTheme; +}) { + return isExpanded + ? React.Children.map(children, (child) => { + if ( + !left || + !React.isValidElement(child) || + child.props.left || + child.props.right + ) { + return child; + } + + return React.cloneElement(child, { + style: [ + theme.isV3 ? styles.childV3 : styles.child, + child.props.style, + ], + theme, + }); + }) + : null; +} + const ListAccordion = ({ left, right, @@ -202,6 +239,7 @@ const ListAccordion = ({ titleMaxFontSizeMultiplier, descriptionMaxFontSizeMultiplier, hitSlop, + expandDirection = 'downwards', }: Props) => { const theme = useInternalTheme(themeOverrides); const [expanded, setExpanded] = React.useState( @@ -252,8 +290,17 @@ const ListAccordion = ({ groupContext && id !== undefined ? () => groupContext.onAccordionPress(id) : handlePressAction; + + const expandedContent = getExpandedContent({ + isExpanded, + children, + left, + theme, + }); + return ( + {expandDirection === 'upwards' ? expandedContent : null} - {isExpanded - ? React.Children.map(children, (child) => { - if ( - left && - React.isValidElement(child) && - !child.props.left && - !child.props.right - ) { - return React.cloneElement(child, { - style: [ - theme.isV3 ? styles.childV3 : styles.child, - child.props.style, - ], - theme, - }); - } - - return child; - }) - : null} + {expandDirection === 'downwards' ? expandedContent : null} ); }; diff --git a/src/components/List/ListAccordionGroup.tsx b/src/components/List/ListAccordionGroup.tsx index 15e148ae6e..c56a9e5dba 100644 --- a/src/components/List/ListAccordionGroup.tsx +++ b/src/components/List/ListAccordionGroup.tsx @@ -13,11 +13,16 @@ export type Props = { * React elements containing list accordions */ children: React.ReactNode; + /** + * Sets expansion direction for all accordions in the group. + */ + expandDirection?: 'downwards' | 'upwards'; }; export type ListAccordionGroupContextType = { expandedId: string | number | undefined; onAccordionPress: (expandedId: string | number) => void; + expandDirection?: 'downwards' | 'upwards'; } | null; export const ListAccordionGroupContext = @@ -60,6 +65,7 @@ const ListAccordionGroup = ({ expandedId: expandedIdProp, onAccordionPress, children, + expandDirection = 'downwards', }: Props) => { const [expandedId, setExpandedId] = React.useState< string | number | undefined @@ -76,6 +82,7 @@ const ListAccordionGroup = ({ value={{ expandedId: expandedIdProp || expandedId, // component can be controlled or uncontrolled onAccordionPress: onAccordionPress || onAccordionPressDefault, + expandDirection, }} > {children}