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. type PropsType = {
  9. theme: CustomThemeType,
  10. title: string,
  11. subtitle?: string,
  12. left?: () => React.Node,
  13. opened?: boolean,
  14. unmountWhenCollapsed?: boolean,
  15. children?: React.Node,
  16. };
  17. type StateType = {
  18. expanded: boolean,
  19. };
  20. const AnimatedListIcon = Animatable.createAnimatableComponent(List.Icon);
  21. class AnimatedAccordion extends React.Component<PropsType, StateType> {
  22. static defaultProps = {
  23. subtitle: '',
  24. left: null,
  25. opened: null,
  26. unmountWhenCollapsed: false,
  27. children: null,
  28. };
  29. chevronRef: {current: null | AnimatedListIcon};
  30. chevronIcon: string;
  31. animStart: string;
  32. animEnd: string;
  33. constructor(props: PropsType) {
  34. super(props);
  35. this.state = {
  36. expanded: props.opened != null ? props.opened : false,
  37. };
  38. this.chevronRef = React.createRef();
  39. this.setupChevron();
  40. }
  41. shouldComponentUpdate(nextProps: PropsType): boolean {
  42. const {state, props} = this;
  43. if (nextProps.opened != null && nextProps.opened !== props.opened)
  44. state.expanded = nextProps.opened;
  45. return true;
  46. }
  47. setupChevron() {
  48. const {expanded} = this.state;
  49. if (expanded) {
  50. this.chevronIcon = 'chevron-up';
  51. this.animStart = '180deg';
  52. this.animEnd = '0deg';
  53. } else {
  54. this.chevronIcon = 'chevron-down';
  55. this.animStart = '0deg';
  56. this.animEnd = '180deg';
  57. }
  58. }
  59. toggleAccordion = () => {
  60. const {expanded} = this.state;
  61. if (this.chevronRef.current != null) {
  62. this.chevronRef.current.transitionTo({
  63. rotate: expanded ? this.animStart : this.animEnd,
  64. });
  65. this.setState((prevState: StateType): {expanded: boolean} => ({
  66. expanded: !prevState.expanded,
  67. }));
  68. }
  69. };
  70. render(): React.Node {
  71. const {props, state} = this;
  72. const {colors} = props.theme;
  73. return (
  74. <View>
  75. <List.Item
  76. title={props.title}
  77. subtitle={props.subtitle}
  78. titleStyle={state.expanded ? {color: colors.primary} : null}
  79. onPress={this.toggleAccordion}
  80. right={({size}: {size: number}): React.Node => (
  81. <AnimatedListIcon
  82. ref={this.chevronRef}
  83. size={size}
  84. icon={this.chevronIcon}
  85. color={state.expanded ? colors.primary : null}
  86. useNativeDriver
  87. style={{rotate: '0deg'}}
  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);