Application Android et IOS pour l'amicale des élèves
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AnimatedAccordion.js 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // @flow
  2. import * as React from 'react';
  3. import {View} from 'react-native';
  4. import {List, withTheme} from 'react-native-paper';
  5. import Collapsible from 'react-native-collapsible';
  6. import * as Animatable from 'react-native-animatable';
  7. import type {CustomThemeType} from '../../managers/ThemeManager';
  8. import type {ListIconPropsType} from '../../constants/PaperStyles';
  9. type PropsType = {
  10. theme: CustomThemeType,
  11. title: string,
  12. subtitle?: string,
  13. left?: () => React.Node,
  14. opened?: boolean,
  15. unmountWhenCollapsed?: boolean,
  16. children?: React.Node,
  17. };
  18. type StateType = {
  19. expanded: boolean,
  20. };
  21. const AnimatedListIcon = Animatable.createAnimatableComponent(List.Icon);
  22. class AnimatedAccordion extends React.Component<PropsType, StateType> {
  23. static defaultProps = {
  24. subtitle: '',
  25. left: null,
  26. opened: null,
  27. unmountWhenCollapsed: false,
  28. children: null,
  29. };
  30. chevronRef: {current: null | AnimatedListIcon};
  31. chevronIcon: string;
  32. animStart: string;
  33. animEnd: string;
  34. constructor(props: PropsType) {
  35. super(props);
  36. this.state = {
  37. expanded: props.opened != null ? props.opened : false,
  38. };
  39. this.chevronRef = React.createRef();
  40. this.setupChevron();
  41. }
  42. shouldComponentUpdate(nextProps: PropsType): boolean {
  43. const {state, props} = this;
  44. if (nextProps.opened != null && nextProps.opened !== props.opened)
  45. state.expanded = nextProps.opened;
  46. return true;
  47. }
  48. setupChevron() {
  49. const {expanded} = this.state;
  50. if (expanded) {
  51. this.chevronIcon = 'chevron-up';
  52. this.animStart = '180deg';
  53. this.animEnd = '0deg';
  54. } else {
  55. this.chevronIcon = 'chevron-down';
  56. this.animStart = '0deg';
  57. this.animEnd = '180deg';
  58. }
  59. }
  60. toggleAccordion = () => {
  61. const {expanded} = this.state;
  62. if (this.chevronRef.current != null) {
  63. this.chevronRef.current.transitionTo({
  64. rotate: expanded ? this.animStart : this.animEnd,
  65. });
  66. this.setState((prevState: StateType): {expanded: boolean} => ({
  67. expanded: !prevState.expanded,
  68. }));
  69. }
  70. };
  71. render(): React.Node {
  72. const {props, state} = this;
  73. const {colors} = props.theme;
  74. return (
  75. <View>
  76. <List.Item
  77. title={props.title}
  78. subtitle={props.subtitle}
  79. titleStyle={state.expanded ? {color: colors.primary} : null}
  80. onPress={this.toggleAccordion}
  81. right={(iconProps: ListIconPropsType): React.Node => (
  82. <AnimatedListIcon
  83. ref={this.chevronRef}
  84. style={iconProps.style}
  85. icon={this.chevronIcon}
  86. color={state.expanded ? colors.primary : iconProps.color}
  87. useNativeDriver
  88. />
  89. )}
  90. left={props.left}
  91. />
  92. <Collapsible collapsed={!state.expanded}>
  93. {!props.unmountWhenCollapsed ||
  94. (props.unmountWhenCollapsed && state.expanded)
  95. ? props.children
  96. : null}
  97. </Collapsible>
  98. </View>
  99. );
  100. }
  101. }
  102. export default withTheme(AnimatedAccordion);