├── .DS_Store
├── .github
└── workflows
│ ├── npm-publish-github-packages.yml
│ └── webpack.yml
├── .gitignore
├── .idea
├── .gitignore
├── misc.xml
├── modules.xml
├── react-native-accordion-list.iml
└── vcs.xml
├── .prettierrc
├── LICENSE
├── README.md
├── examples
├── android.gif
├── demo.gif
├── ios.gif
└── singleSelect.gif
├── lib
├── .DS_Store
├── animations
│ ├── toggleAnimation.d.ts
│ ├── toggleAnimation.js
│ └── toggleAnimation.js.map
├── components
│ ├── .DS_Store
│ ├── AccordionItem
│ │ ├── index.d.ts
│ │ ├── index.js
│ │ ├── index.js.map
│ │ ├── styles.d.ts
│ │ ├── styles.js
│ │ └── styles.js.map
│ └── AccordionList
│ │ ├── index.d.ts
│ │ ├── index.js
│ │ └── index.js.map
├── index.d.ts
├── index.js
├── index.js.map
└── models
│ ├── AccordionItem.d.ts
│ ├── AccordionItem.js
│ ├── AccordionItem.js.map
│ ├── AccordionList.d.ts
│ ├── AccordionList.js
│ ├── AccordionList.js.map
│ ├── AccordionPressable.d.ts
│ ├── AccordionPressable.js
│ └── AccordionPressable.js.map
├── package-lock.json
├── package.json
├── src
├── .DS_Store
├── README.md
├── animations
│ └── toggleAnimation.tsx
├── components
│ ├── .DS_Store
│ ├── AccordionItem
│ │ ├── index.tsx
│ │ └── styles.tsx
│ └── AccordionList
│ │ └── index.tsx
├── index.tsx
└── models
│ ├── AccordionItem.tsx
│ ├── AccordionList.tsx
│ └── AccordionPressable.tsx
├── tsconfig.json
└── tslint.json
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louaySleman/react-native-accordion-list-view/a35573fc0beb36e31851c0513cbe0a05700df022/.DS_Store
--------------------------------------------------------------------------------
/.github/workflows/npm-publish-github-packages.yml:
--------------------------------------------------------------------------------
1 | # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages
3 |
4 | name: Node.js Package
5 |
6 | on:
7 | release:
8 | types: [created]
9 |
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v3
15 | - uses: actions/setup-node@v3
16 | with:
17 | node-version: 16
18 | - run: npm ci
19 | - run: npm test
20 |
21 | publish-gpr:
22 | needs: build
23 | runs-on: ubuntu-latest
24 | permissions:
25 | contents: read
26 | packages: write
27 | steps:
28 | - uses: actions/checkout@v3
29 | - uses: actions/setup-node@v3
30 | with:
31 | node-version: 16
32 | registry-url: https://npm.pkg.github.com/
33 | - run: npm ci
34 | - run: npm publish
35 | env:
36 | NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
37 |
--------------------------------------------------------------------------------
/.github/workflows/webpack.yml:
--------------------------------------------------------------------------------
1 | name: NodeJS with Webpack
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | strategy:
14 | matrix:
15 | node-version: [12.x, 14.x, 16.x]
16 |
17 | steps:
18 | - uses: actions/checkout@v3
19 |
20 | - name: Use Node.js ${{ matrix.node-version }}
21 | uses: actions/setup-node@v3
22 | with:
23 | node-version: ${{ matrix.node-version }}
24 |
25 | - name: Build
26 | run: |
27 | npm install
28 | npx webpack
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/react-native-accordion-list.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 120,
3 | "trailingComma": "all",
4 | "singleQuote": true
5 | }
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 louaySleman
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## react-native-accordion-list-view
2 | A high performance, beautiful and fully customizable Accordion list for React Native.
3 | Implemented using [react-native-vector-icons](https://github.com/oblador/react-native-vector-icons).
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ## Getting started
18 | ```js
19 | npm install react-native-accordion-list-view --save
20 | ```
21 | or
22 | ```js
23 | yarn add react-native-accordion-list-view
24 | ```
25 | Now we need to install [react-native-vector-icons](https://github.com/oblador/react-native-vector-icons).
26 |
27 | ```js
28 | npm install react-native-vector-icons --save
29 | ```
30 | or
31 | ```js
32 | yarn add react-native-vector-icons
33 | ```
34 |
35 | ## Platforms Supported
36 |
37 | - [x] iOS
38 | - [x] Android
39 |
40 | ## Important Note
41 | This plugin work with Layout Animation and In order to get this to work on Android you need to set the following flags via UIManager:
42 | ```javascript
43 | if (Platform.OS === 'android') {
44 | if (UIManager.setLayoutAnimationEnabledExperimental) {
45 | UIManager.setLayoutAnimationEnabledExperimental(true);
46 | }
47 | }
48 | ```
49 |
50 | ### Demo
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | ## Versioning
60 | This project follows semantic versioning. We do not hesitate to release breaking changes but they will be in a major version.
61 |
62 | ### Breaking History:
63 | - [2.0.3](https://www.npmjs.com/package/react-native-accordion-list-view/v/2.0.3) - New Features
64 | We've enhanced the Accordion list by adding support for the index parameter in the customTitle, customBody, and customIcon functions. This enables greater customization possibilities, allowing you to dynamically adjust the rendering of elements based on the index of each accordion item. Explore these new parameters to tailor your accordion items more precisely to your application's requirements.
65 | - [2.0.2](https://www.npmjs.com/package/react-native-accordion-list-view/v/2.0.2) - New Features
66 |
67 | **defaultOpenIndices**: You can now specify an array of indices in the `defaultOpenIndices` prop for the accordion list. These indices indicate which sections should be expanded by default, allowing you to control the initial state of the accordion.
68 |
69 | **pressableProps**: We've added a new prop called `pressableProps` to both the accordion list and accordion item components. This allows you to customize the styles and ripple effects for the pressable component, giving you more control over the user interaction experience.
70 | - [2.0.1](https://www.npmjs.com/package/react-native-accordion-list-view/v/2.0.1) - Allow single/multiple expanding, allow `AccordionItem` to be opened by default using `isOpen` property, add `onPress` for `AccordionItem`.
71 | - [2.0.0](https://www.npmjs.com/package/react-native-accordion-list-view/v/2.0.0) - Change library code to typescript and Replacing `TouchableOpacity` with `Pressable`.
72 | - [1.0.4](https://www.npmjs.com/package/react-native-accordion-list-view/v/1.0.4) - Support RTL and update `README`.
73 | - [1.0.3](https://www.npmjs.com/package/react-native-accordion-list-view/v/1.0.3) - Accordion list `FlatList` props bug fixes.
74 | - [1.0.2](https://www.npmjs.com/package/react-native-accordion-list-view/v/1.0.2) - Accordion Item Bug fixes.
75 | - [1.0.1](https://www.npmjs.com/package/react-native-accordion-list-view/v/1.0.1) - Update `README`.
76 | - [1.0.0](https://www.npmjs.com/package/react-native-accordion-list-view/v/1.0.0) - First release.
77 |
78 | ### Accordion list
79 |
80 | | Props | Params | isRequire | Default | Description |
81 | |--------------------|-------------------------------------------------------------------|-----------|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
82 | | data | Array | Yes | | For simplicity, data is a plain array. If you want to use something else, like an immutable list |
83 | | customTitle | (item, index) => JSX.Element | Yes | | Function that returns a React element to display as Accordion title |
84 | | customBody | (item, index) => JSX.Element | Yes | | Function that returns a React element to display as Accordion body |
85 | | customIcon | (index) => JSX.Element | No | keyboard-arrow-left | Function that returns a React element to display as Accordion icon |
86 | | containerItemStyle | ViewStyle | No | {} | Styling for Accordion item container view |
87 | | style | ViewStyle | No | {} | Styling for container view |
88 | | animationDuration | Number | No | 300 | Accordion animation duration |
89 | | isRTL | Boolean | No | false | Support RTL |
90 | | expandMultiple | Boolean | No | false | Allow more than one section to be expanded |
91 | | defaultOpenIndices | number[] | No | [] | An array of indices indicating which sections should be expanded by default. If `expandMultiple` is set to `false`, it can only contain a single index. |
92 | | pressableProps | [AccordionPressableProps](https://reactnative.dev/docs/pressable) | No | {} | Additional props for configuring the Pressable component. |
93 |
94 |
95 | ### More props
96 |
97 | This is a wrapper around `Flatlist`, all their props works well and the inherited props too (from `ScrollView` and `VirtualizedList`).
98 |
99 | ### Example
100 |
101 | #### Without Custom Styles
102 | ```javascript
103 | import React, { useEffect } from 'react';
104 | import {View, SafeAreaView, StyleSheet, Text, Platform, UIManager} from 'react-native';
105 | import {AccordionList} from 'react-native-accordion-list-view';
106 |
107 | const App = () => {
108 | const data = [
109 | {
110 | id: 0,
111 | title: 'Lorem Ipsum is simply dummy',
112 | body: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
113 | },
114 | {
115 | id: 1,
116 | title: 'Lorem Ipsum is simply dummy',
117 | body: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
118 | },
119 | ];
120 | useEffect(() => {
121 | if (Platform.OS === 'android') {
122 | if (UIManager.setLayoutAnimationEnabledExperimental) {
123 | UIManager.setLayoutAnimationEnabledExperimental(true);
124 | }
125 | }
126 | }, []);
127 | return (
128 |
129 |
130 | {item.title}}
133 | customBody={item => {item.body}}
134 | animationDuration={400}
135 | expandMultiple={true}
136 | />
137 |
138 |
139 | );
140 | };
141 |
142 | export default App;
143 | const styles = StyleSheet.create({
144 | container: {
145 | paddingVertical: '2%',
146 | paddingHorizontal: '3%',
147 | height: '100%',
148 | backgroundColor: '#e7e7e7',
149 | },
150 | });
151 |
152 | ```
153 |
154 | #### With Custom Styles
155 | ```javascript
156 | import React, { useEffect } from 'react';
157 | import {View, SafeAreaView, StyleSheet, Text, Platform, UIManager} from 'react-native';
158 | import {AccordionList} from 'react-native-accordion-list-view';
159 |
160 | const App = () => {
161 | const data = [
162 | {
163 | id: 0,
164 | title: 'Lorem Ipsum is simply dummy',
165 | body: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
166 | },
167 | {
168 | id: 1,
169 | title: 'Lorem Ipsum is simply dummy',
170 | body: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
171 | },
172 | {
173 | id: 2,
174 | title: 'Lorem Ipsum is simply dummy',
175 | body: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
176 | },
177 | {
178 | id: 3,
179 | title: 'Lorem Ipsum is simply dummy',
180 | body: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
181 | },
182 | ];
183 | useEffect(() => {
184 | if (Platform.OS === 'android') {
185 | if (UIManager.setLayoutAnimationEnabledExperimental) {
186 | UIManager.setLayoutAnimationEnabledExperimental(true);
187 | }
188 | }
189 | }, []);
190 | return (
191 |
192 |
193 | {item.title}}
196 | customBody={(item, index) => {item.body}}
197 | animationDuration={400}
198 | defaultOpenIndices={[0, 2]}
199 | expandMultiple={true}
200 | containerItemStyle={{padding: 0}}
201 | pressableProps={{
202 | style: ({pressed}) => [
203 | {
204 | padding: '2%',
205 | backgroundColor:
206 | pressed && Platform.OS == 'ios'
207 | ? 'rgb(210, 230, 255)'
208 | : 'transparent',
209 | },
210 | ],
211 | android_ripple: {
212 | color: 'rgb(210, 230, 255)',
213 | },
214 | }}
215 | />
216 |
217 |
218 | );
219 | };
220 |
221 | export default App;
222 | const styles = StyleSheet.create({
223 | container: {
224 | paddingVertical: '2%',
225 | paddingHorizontal: '3%',
226 | height: '100%',
227 | backgroundColor: '#e7e7e7',
228 | },
229 | });
230 |
231 | ```
232 |
233 | ### Accordion Item
234 | This component allows you to use `Accordion Item` component in any place if you have your own wrapper or if you have a problem with using `FlatList` in your screen.
235 |
236 | | Props | Params | isRequire | Default | Description |
237 | |-------------------|------------------|-----------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------|
238 | | customTitle | () => JSX.Element | Yes | | Function that returns a React element to display as Accordion title |
239 | | customBody | () => JSX.Element | Yes | | Function that returns a React element to display as Accordion body |
240 | | customIcon | () => JSX.Element | No | keyboard-arrow-left | Function that returns a React element to display as Accordion icon |
241 | | containerStyle | ViewStyle | No | {} | Styling for Accordion item container view |
242 | | animationDuration | Number | No | 300 | Accordion animation duration |
243 | | isRTL | Boolean | No | false | Support RTL |
244 | | isOpen | Boolean | No | false | An optional param to make accordion item already open |
245 | | onPress | (isOpen: boolean) => void | No | - | An optional callback function called when a click happen to the accordion item and return the current state (if it's open or not) |
246 | | pressableProps | [AccordionPressableProps](https://reactnative.dev/docs/pressable) | No | {} | Additional props for configuring the Pressable component. |
247 |
248 | ### Example
249 |
250 | ```javascript
251 | import React, {useEffect} from 'react';
252 | import {View, SafeAreaView, StyleSheet, Text, ScrollView, Platform, UIManager} from 'react-native';
253 | import {AccordionItem} from 'react-native-accordion-list-view';
254 |
255 | const App = () => {
256 | const data = [
257 | {
258 | id: 0,
259 | title: 'Lorem Ipsum is simply dummy',
260 | body: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
261 | },
262 | {
263 | id: 1,
264 | title: 'Lorem Ipsum is simply dummy',
265 | body: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
266 | },
267 | ];
268 | useEffect(() => {
269 | if (Platform.OS === 'android') {
270 | if (UIManager.setLayoutAnimationEnabledExperimental) {
271 | UIManager.setLayoutAnimationEnabledExperimental(true);
272 | }
273 | }
274 | }, []);
275 | return (
276 |
277 |
278 | {data.map(item => (
279 | {item.title}}
282 | customBody={() => {item.body}}
283 | animationDuration={400}
284 | isOpen={false}
285 | onPress={(isOpen) => console.log(isOpen)}
286 | />
287 | ))}
288 |
289 |
290 | );
291 | };
292 |
293 | export default App;
294 | const styles = StyleSheet.create({
295 | container: {
296 | paddingVertical: '2%',
297 | paddingHorizontal: '3%',
298 | height: '100%',
299 | backgroundColor: '#e7e7e7',
300 | },
301 | });
302 |
303 | ```
304 | ### Common Issues and Errors
305 |
306 | Error: You have multiple items opened by default, but expandMultiple is disabled, If you encounter the following error message in your console:
307 |
308 | ```javascript
309 | console.error('Error: You have multiple items opened by default, but expandMultiple is disabled.');
310 | ```
311 | This error occurs when you have set expandMultiple to false and provided an array with multiple indices in the defaultOpenIndices prop. Remember that when expandMultiple is set to false, you can only specify a single index in the defaultOpenIndices array.
312 |
313 | To resolve this issue, make sure that defaultOpenIndices contains only one index when expandMultiple is false.
314 |
315 | ### License
316 | MIT
317 |
--------------------------------------------------------------------------------
/examples/android.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louaySleman/react-native-accordion-list-view/a35573fc0beb36e31851c0513cbe0a05700df022/examples/android.gif
--------------------------------------------------------------------------------
/examples/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louaySleman/react-native-accordion-list-view/a35573fc0beb36e31851c0513cbe0a05700df022/examples/demo.gif
--------------------------------------------------------------------------------
/examples/ios.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louaySleman/react-native-accordion-list-view/a35573fc0beb36e31851c0513cbe0a05700df022/examples/ios.gif
--------------------------------------------------------------------------------
/examples/singleSelect.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louaySleman/react-native-accordion-list-view/a35573fc0beb36e31851c0513cbe0a05700df022/examples/singleSelect.gif
--------------------------------------------------------------------------------
/lib/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louaySleman/react-native-accordion-list-view/a35573fc0beb36e31851c0513cbe0a05700df022/lib/.DS_Store
--------------------------------------------------------------------------------
/lib/animations/toggleAnimation.d.ts:
--------------------------------------------------------------------------------
1 | import { LayoutAnimationConfig } from 'react-native';
2 | /**
3 | * Generates a layout animation configuration for toggling the visibility of an element.
4 | *
5 | * @param {number} animationDuration - The duration of the animation in milliseconds.
6 | * @returns {LayoutAnimationConfig} - The layout animation configuration object.
7 | */
8 | export declare const toggleAnimation: (animationDuration?: number) => LayoutAnimationConfig;
9 |
--------------------------------------------------------------------------------
/lib/animations/toggleAnimation.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.toggleAnimation = void 0;
4 | const react_native_1 = require("react-native");
5 | /**
6 | * Generates a layout animation configuration for toggling the visibility of an element.
7 | *
8 | * @param {number} animationDuration - The duration of the animation in milliseconds.
9 | * @returns {LayoutAnimationConfig} - The layout animation configuration object.
10 | */
11 | const toggleAnimation = (animationDuration = 300) => {
12 | return {
13 | duration: animationDuration,
14 | update: {
15 | duration: animationDuration,
16 | property: react_native_1.LayoutAnimation.Properties.scaleXY,
17 | type: react_native_1.LayoutAnimation.Types.easeInEaseOut,
18 | },
19 | delete: {
20 | duration: animationDuration,
21 | property: react_native_1.LayoutAnimation.Properties.opacity,
22 | type: react_native_1.LayoutAnimation.Types.easeInEaseOut,
23 | },
24 | };
25 | };
26 | exports.toggleAnimation = toggleAnimation;
27 | //# sourceMappingURL=toggleAnimation.js.map
--------------------------------------------------------------------------------
/lib/animations/toggleAnimation.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"toggleAnimation.js","sourceRoot":"","sources":["../../src/animations/toggleAnimation.tsx"],"names":[],"mappings":";;;AAAA,+CAAsE;AAEtE;;;;;GAKG;AACI,MAAM,eAAe,GAAG,CAAC,iBAAiB,GAAG,GAAG,EAAyB,EAAE;IAChF,OAAO;QACL,QAAQ,EAAE,iBAAiB;QAC3B,MAAM,EAAE;YACN,QAAQ,EAAE,iBAAiB;YAC3B,QAAQ,EAAE,8BAAe,CAAC,UAAU,CAAC,OAAO;YAC5C,IAAI,EAAE,8BAAe,CAAC,KAAK,CAAC,aAAa;SAC1C;QACD,MAAM,EAAE;YACN,QAAQ,EAAE,iBAAiB;YAC3B,QAAQ,EAAE,8BAAe,CAAC,UAAU,CAAC,OAAO;YAC5C,IAAI,EAAE,8BAAe,CAAC,KAAK,CAAC,aAAa;SAC1C;KACF,CAAC;AACJ,CAAC,CAAC;AAdW,QAAA,eAAe,mBAc1B"}
--------------------------------------------------------------------------------
/lib/components/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louaySleman/react-native-accordion-list-view/a35573fc0beb36e31851c0513cbe0a05700df022/lib/components/.DS_Store
--------------------------------------------------------------------------------
/lib/components/AccordionItem/index.d.ts:
--------------------------------------------------------------------------------
1 | import { AccordionItemProps } from '../../models/AccordionItem';
2 | /**
3 | * An individual item within an accordion list that can be expanded or collapsed.
4 | * @param {AccordionItemProps} props - Props for configuring the AccordionItem.
5 | * @returns {JSX.Element} - The AccordionItem component.
6 | */
7 | declare const AccordionItem: ({ customBody, customTitle, customIcon, containerStyle, animationDuration, isRTL, isOpen, onPress, pressableProps, }: AccordionItemProps) => JSX.Element;
8 | export default AccordionItem;
9 |
--------------------------------------------------------------------------------
/lib/components/AccordionItem/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 | if (k2 === undefined) k2 = k;
4 | var desc = Object.getOwnPropertyDescriptor(m, k);
5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6 | desc = { enumerable: true, get: function() { return m[k]; } };
7 | }
8 | Object.defineProperty(o, k2, desc);
9 | }) : (function(o, m, k, k2) {
10 | if (k2 === undefined) k2 = k;
11 | o[k2] = m[k];
12 | }));
13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14 | Object.defineProperty(o, "default", { enumerable: true, value: v });
15 | }) : function(o, v) {
16 | o["default"] = v;
17 | });
18 | var __importStar = (this && this.__importStar) || function (mod) {
19 | if (mod && mod.__esModule) return mod;
20 | var result = {};
21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22 | __setModuleDefault(result, mod);
23 | return result;
24 | };
25 | var __importDefault = (this && this.__importDefault) || function (mod) {
26 | return (mod && mod.__esModule) ? mod : { "default": mod };
27 | };
28 | Object.defineProperty(exports, "__esModule", { value: true });
29 | const react_1 = __importStar(require("react"));
30 | const react_native_1 = require("react-native");
31 | const MaterialIcons_1 = __importDefault(require("react-native-vector-icons/MaterialIcons"));
32 | const toggleAnimation_1 = require("../../animations/toggleAnimation");
33 | const styles_1 = require("./styles");
34 | /**
35 | * An individual item within an accordion list that can be expanded or collapsed.
36 | * @param {AccordionItemProps} props - Props for configuring the AccordionItem.
37 | * @returns {JSX.Element} - The AccordionItem component.
38 | */
39 | const AccordionItem = ({ customBody, customTitle, customIcon = undefined, containerStyle = {}, animationDuration = 300, isRTL = false, isOpen = false, onPress = undefined, pressableProps = {}, }) => {
40 | /**
41 | * Indicates whether the content of the accordion item is currently displayed.
42 | * @type {boolean}
43 | */
44 | const [showContent, setShowContent] = (0, react_1.useState)(isOpen);
45 | /**
46 | * A controller for managing the animation of the accordion item.
47 | * @type {Animated.Value}
48 | */
49 | const animationController = (0, react_1.useRef)(new react_native_1.Animated.Value(isOpen ? 1 : 0)).current;
50 | /**
51 | * Toggles the visibility of the accordion item's content when the `isOpen` prop changes.
52 | * This effect is triggered when the `isOpen` prop changes.
53 | */
54 | (0, react_1.useEffect)(() => {
55 | if (isOpen !== showContent) {
56 | toggleListItem();
57 | }
58 | }, [isOpen]);
59 | /**
60 | * Toggles the visibility of the accordion item's content.
61 | */
62 | const toggleListItem = () => {
63 | const config = {
64 | duration: animationDuration,
65 | toValue: showContent ? 0 : 1,
66 | useNativeDriver: true,
67 | };
68 | react_native_1.Animated.timing(animationController, config).start();
69 | react_native_1.LayoutAnimation.configureNext((0, toggleAnimation_1.toggleAnimation)(animationDuration));
70 | if (onPress)
71 | onPress(!showContent);
72 | setShowContent(!showContent);
73 | };
74 | /**
75 | * An animated transformation for rotating the arrow icon based on the animation state.
76 | * @type {Animated.AnimatedInterpolation}
77 | */
78 | const arrowTransform = animationController.interpolate({
79 | inputRange: [0, 1],
80 | outputRange: ['0deg', isRTL ? '-90deg' : '90deg'],
81 | });
82 | return (react_1.default.createElement(react_native_1.View, { style: [styles_1.styles.container, containerStyle] },
83 | react_1.default.createElement(react_native_1.Pressable, { ...pressableProps, onPress: () => toggleListItem() },
84 | react_1.default.createElement(react_native_1.View, { style: styles_1.styles.titleContainer },
85 | (!isRTL || react_native_1.I18nManager.isRTL) && customTitle(),
86 | react_1.default.createElement(react_native_1.Animated.View, { style: { transform: [{ rotateZ: arrowTransform }] } }, !customIcon ? (react_1.default.createElement(MaterialIcons_1.default, { name: isRTL ? 'keyboard-arrow-left' : 'keyboard-arrow-right', size: 30 })) : (customIcon())),
87 | isRTL && !react_native_1.I18nManager.isRTL && customTitle())),
88 | showContent && customBody()));
89 | };
90 | exports.default = AccordionItem;
91 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/lib/components/AccordionItem/index.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/AccordionItem/index.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAA2D;AAC3D,+CAAuF;AACvF,4FAAoE;AACpE,sEAAmE;AAEnE,qCAAkC;AAElC;;;;GAIG;AACH,MAAM,aAAa,GAAG,CAAC,EACrB,UAAU,EACV,WAAW,EACX,UAAU,GAAG,SAAS,EACtB,cAAc,GAAG,EAAE,EACnB,iBAAiB,GAAG,GAAG,EACvB,KAAK,GAAG,KAAK,EACb,MAAM,GAAG,KAAK,EACd,OAAO,GAAG,SAAS,EACnB,cAAc,GAAG,EAAE,GACA,EAAe,EAAE;IACpC;;;OAGG;IACH,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,IAAA,gBAAQ,EAAU,MAAM,CAAC,CAAC;IAChE;;;OAGG;IACH,MAAM,mBAAmB,GAAG,IAAA,cAAM,EAAC,IAAI,uBAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAE/E;;;OAGG;IACH,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,IAAI,MAAM,KAAK,WAAW,EAAE;YAC1B,cAAc,EAAE,CAAC;SAClB;IACH,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb;;OAEG;IACH,MAAM,cAAc,GAAG,GAAG,EAAE;QAC1B,MAAM,MAAM,GAAG;YACb,QAAQ,EAAE,iBAAiB;YAC3B,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5B,eAAe,EAAE,IAAI;SACtB,CAAC;QACF,uBAAQ,CAAC,MAAM,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC;QACrD,8BAAe,CAAC,aAAa,CAAC,IAAA,iCAAe,EAAC,iBAAiB,CAAC,CAAC,CAAC;QAClE,IAAI,OAAO;YAAE,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC;QACnC,cAAc,CAAC,CAAC,WAAW,CAAC,CAAC;IAC/B,CAAC,CAAC;IAEF;;;OAGG;IACH,MAAM,cAAc,GAAG,mBAAmB,CAAC,WAAW,CAAC;QACrD,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QAClB,WAAW,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;KAClD,CAAC,CAAC;IAEH,OAAO,CACL,8BAAC,mBAAI,IAAC,KAAK,EAAE,CAAC,eAAM,CAAC,SAAS,EAAE,cAAc,CAAC;QAC7C,8BAAC,wBAAS,OAAK,cAAc,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,EAAE;YAC5D,8BAAC,mBAAI,IAAC,KAAK,EAAE,eAAM,CAAC,cAAc;gBAC/B,CAAC,CAAC,KAAK,IAAI,0BAAW,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE;gBAC/C,8BAAC,uBAAQ,CAAC,IAAI,IAAC,KAAK,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,EAAE,IAC/D,CAAC,UAAU,CAAC,CAAC,CAAC,CACb,8BAAC,uBAAa,IAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,sBAAsB,EAAE,IAAI,EAAE,EAAE,GAAI,CAC1F,CAAC,CAAC,CAAC,CACF,UAAU,EAAE,CACb,CACa;gBACf,KAAK,IAAI,CAAC,0BAAW,CAAC,KAAK,IAAI,WAAW,EAAE,CACxC,CACG;QACX,WAAW,IAAI,UAAU,EAAE,CACvB,CACR,CAAC;AACJ,CAAC,CAAC;AACF,kBAAe,aAAa,CAAC"}
--------------------------------------------------------------------------------
/lib/components/AccordionItem/styles.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Styles for the AccordionItem component.
3 | * @constant {object}
4 | */
5 | export declare const styles: {
6 | /**
7 | * Styles for the container that wraps the entire AccordionItem.
8 | * @type {object}
9 | */
10 | container: {
11 | width: string;
12 | padding: string;
13 | borderRadius: number;
14 | backgroundColor: string;
15 | marginBottom: string;
16 | overflow: "hidden";
17 | };
18 | /**
19 | * Styles for the title text within the AccordionItem.
20 | * @type {object}
21 | */
22 | title: {
23 | fontSize: number;
24 | color: string;
25 | fontWeight: "bold";
26 | };
27 | /**
28 | * Styles for the body content within the AccordionItem.
29 | * @type {object}
30 | */
31 | body: {
32 | paddingHorizontal: string;
33 | paddingVertical: string;
34 | };
35 | /**
36 | * Styles for the container of the title and optional icon.
37 | * @type {object}
38 | */
39 | titleContainer: {
40 | flexDirection: "row";
41 | alignItems: "center";
42 | justifyContent: "space-between";
43 | };
44 | };
45 |
--------------------------------------------------------------------------------
/lib/components/AccordionItem/styles.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.styles = void 0;
4 | const react_native_1 = require("react-native");
5 | /**
6 | * Styles for the AccordionItem component.
7 | * @constant {object}
8 | */
9 | exports.styles = react_native_1.StyleSheet.create({
10 | /**
11 | * Styles for the container that wraps the entire AccordionItem.
12 | * @type {object}
13 | */
14 | container: {
15 | width: '100%',
16 | padding: '2%',
17 | borderRadius: 12,
18 | backgroundColor: 'white',
19 | marginBottom: '2%',
20 | overflow: 'hidden',
21 | },
22 | /**
23 | * Styles for the title text within the AccordionItem.
24 | * @type {object}
25 | */
26 | title: {
27 | fontSize: 16,
28 | color: '#2d2d2d',
29 | fontWeight: 'bold',
30 | },
31 | /**
32 | * Styles for the body content within the AccordionItem.
33 | * @type {object}
34 | */
35 | body: {
36 | paddingHorizontal: '2%',
37 | paddingVertical: '3%',
38 | },
39 | /**
40 | * Styles for the container of the title and optional icon.
41 | * @type {object}
42 | */
43 | titleContainer: {
44 | flexDirection: 'row',
45 | alignItems: 'center',
46 | justifyContent: 'space-between',
47 | },
48 | });
49 | //# sourceMappingURL=styles.js.map
--------------------------------------------------------------------------------
/lib/components/AccordionItem/styles.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../../src/components/AccordionItem/styles.tsx"],"names":[],"mappings":";;;AACA,+CAA0C;AAE1C;;;GAGG;AACU,QAAA,MAAM,GAAG,yBAAU,CAAC,MAAM,CAAC;IACtC;;;OAGG;IACH,SAAS,EAAE;QACT,KAAK,EAAE,MAAM;QACb,OAAO,EAAE,IAAI;QACb,YAAY,EAAE,EAAE;QAChB,eAAe,EAAE,OAAO;QACxB,YAAY,EAAE,IAAI;QAClB,QAAQ,EAAE,QAAQ;KACnB;IACD;;;OAGG;IACH,KAAK,EAAE;QACL,QAAQ,EAAE,EAAE;QACZ,KAAK,EAAE,SAAS;QAChB,UAAU,EAAE,MAAM;KACnB;IACD;;;OAGG;IACH,IAAI,EAAE;QACJ,iBAAiB,EAAE,IAAI;QACvB,eAAe,EAAE,IAAI;KACtB;IACD;;;OAGG;IACH,cAAc,EAAE;QACd,aAAa,EAAE,KAAK;QACpB,UAAU,EAAE,QAAQ;QACpB,cAAc,EAAE,eAAe;KAChC;CACF,CAAC,CAAC"}
--------------------------------------------------------------------------------
/lib/components/AccordionList/index.d.ts:
--------------------------------------------------------------------------------
1 | import { AccordionListProps } from '../../models/AccordionList';
2 | /**
3 | * A component for rendering an accordion list with expandable items.
4 | *
5 | * @param {AccordionListProps} props - Props for configuring the AccordionList.
6 | * @param {any[]} props.data - The data to render in the accordion list.
7 | * @param {(item: any) => JSX.Element} props.customTitle - Function that returns a React element for the custom title of each item.
8 | * @param {(item: any) => JSX.Element} props.customBody - Function that returns a React element for the custom body of each item.
9 | * @param {() => JSX.Element | undefined} [props.customIcon] - Function that returns a React element for a custom icon, or undefined to use default icons.
10 | * @param {object} [props.containerItemStyle] - Additional styles for the container of each accordion item.
11 | * @param {number} [props.animationDuration] - The duration of the animation when expanding/collapsing items.
12 | * @param {boolean} [props.isRTL] - Whether to use right-to-left layout.
13 | * @param {boolean} [props.expandMultiple] - Whether to allow multiple items to be expanded at the same time.
14 | * @param {number[]} [props.defaultOpenIndices] - An array of indices specifying which items should be open by default.
15 | * @param {object} [props.pressableProps] - Additional props for the Pressable component.
16 | * @returns {JSX.Element} - The AccordionList component.
17 | */
18 | declare const AccordionList: ({ data, customTitle, customBody, customIcon, containerItemStyle, animationDuration, isRTL, expandMultiple, defaultOpenIndices, pressableProps, ...props }: AccordionListProps) => JSX.Element;
19 | export default AccordionList;
20 |
--------------------------------------------------------------------------------
/lib/components/AccordionList/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 | if (k2 === undefined) k2 = k;
4 | var desc = Object.getOwnPropertyDescriptor(m, k);
5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6 | desc = { enumerable: true, get: function() { return m[k]; } };
7 | }
8 | Object.defineProperty(o, k2, desc);
9 | }) : (function(o, m, k, k2) {
10 | if (k2 === undefined) k2 = k;
11 | o[k2] = m[k];
12 | }));
13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14 | Object.defineProperty(o, "default", { enumerable: true, value: v });
15 | }) : function(o, v) {
16 | o["default"] = v;
17 | });
18 | var __importStar = (this && this.__importStar) || function (mod) {
19 | if (mod && mod.__esModule) return mod;
20 | var result = {};
21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22 | __setModuleDefault(result, mod);
23 | return result;
24 | };
25 | var __importDefault = (this && this.__importDefault) || function (mod) {
26 | return (mod && mod.__esModule) ? mod : { "default": mod };
27 | };
28 | Object.defineProperty(exports, "__esModule", { value: true });
29 | const react_1 = __importStar(require("react"));
30 | const react_native_1 = require("react-native");
31 | const AccordionItem_1 = __importDefault(require("../AccordionItem"));
32 | /**
33 | * A component for rendering an accordion list with expandable items.
34 | *
35 | * @param {AccordionListProps} props - Props for configuring the AccordionList.
36 | * @param {any[]} props.data - The data to render in the accordion list.
37 | * @param {(item: any) => JSX.Element} props.customTitle - Function that returns a React element for the custom title of each item.
38 | * @param {(item: any) => JSX.Element} props.customBody - Function that returns a React element for the custom body of each item.
39 | * @param {() => JSX.Element | undefined} [props.customIcon] - Function that returns a React element for a custom icon, or undefined to use default icons.
40 | * @param {object} [props.containerItemStyle] - Additional styles for the container of each accordion item.
41 | * @param {number} [props.animationDuration] - The duration of the animation when expanding/collapsing items.
42 | * @param {boolean} [props.isRTL] - Whether to use right-to-left layout.
43 | * @param {boolean} [props.expandMultiple] - Whether to allow multiple items to be expanded at the same time.
44 | * @param {number[]} [props.defaultOpenIndices] - An array of indices specifying which items should be open by default.
45 | * @param {object} [props.pressableProps] - Additional props for the Pressable component.
46 | * @returns {JSX.Element} - The AccordionList component.
47 | */
48 | const AccordionList = ({ data, customTitle, customBody, customIcon = undefined, containerItemStyle = {}, animationDuration = 300, isRTL = false, expandMultiple = false, defaultOpenIndices = [], pressableProps = {}, ...props }) => {
49 | /**
50 | * State variable to track the currently open item in the accordion.
51 | * @type {any}
52 | */
53 | const [currentlyOpen, setCurrentlyOpen] = (0, react_1.useState)(null);
54 | /**
55 | * State variable to store an array of default open indices in the accordion.
56 | * @type {number[]}
57 | */
58 | const [defaultOpen, setDefaultOpen] = (0, react_1.useState)(defaultOpenIndices);
59 | /**
60 | * Checks if an accordion item is open based on its index.
61 | *
62 | * @param {any} item - The data item of the accordion.
63 | * @param {number} index - The index of the accordion item.
64 | * @returns {boolean} - True if the item is open; otherwise, false.
65 | */
66 | const checkIfOpen = (0, react_1.useCallback)((item, index) => {
67 | return JSON.stringify(currentlyOpen) === JSON.stringify(item) || (defaultOpen?.includes(index) ?? false);
68 | }, [currentlyOpen, defaultOpen]);
69 | /**
70 | * useEffect to initialize the default open indices and show an error if necessary.
71 | */
72 | (0, react_1.useEffect)(() => {
73 | setDefaultOpen(defaultOpenIndices || []);
74 | if (defaultOpenIndices?.length > 1 && !expandMultiple) {
75 | console.error('Error: You have multiple items opened by default, but expandMultiple is disabled.');
76 | }
77 | }, [defaultOpenIndices, expandMultiple]);
78 | /**
79 | * Renders an individual item within the accordion.
80 | *
81 | * @param {{ item: any; index: number }} - The item and its index.
82 | * @returns {JSX.Element} - The rendered AccordionItem component.
83 | */
84 | const renderItem = ({ item, index }) => (react_1.default.createElement(AccordionItem_1.default, { containerStyle: containerItemStyle, customTitle: () => customTitle(item, index), customBody: () => customBody(item, index), animationDuration: animationDuration, isRTL: isRTL, isOpen: checkIfOpen(item, index), onPress: (status) => {
85 | if (status && !expandMultiple) {
86 | setDefaultOpen([]);
87 | setCurrentlyOpen(item);
88 | }
89 | }, pressableProps: pressableProps, customIcon: customIcon ? () => customIcon(index) : undefined }));
90 | return react_1.default.createElement(react_native_1.FlatList, { data: data, renderItem: renderItem, keyExtractor: (item, index) => index.toString(), ...props });
91 | };
92 | exports.default = AccordionList;
93 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/lib/components/AccordionList/index.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/AccordionList/index.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAgE;AAChE,+CAAwC;AACxC,qEAA6C;AAG7C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,aAAa,GAAG,CAAC,EACrB,IAAI,EACJ,WAAW,EACX,UAAU,EACV,UAAU,GAAG,SAAS,EACtB,kBAAkB,GAAG,EAAE,EACvB,iBAAiB,GAAG,GAAG,EACvB,KAAK,GAAG,KAAK,EACb,cAAc,GAAG,KAAK,EACtB,kBAAkB,GAAG,EAAE,EACvB,cAAc,GAAG,EAAE,EACnB,GAAG,KAAK,EACW,EAAe,EAAE;IACpC;;;OAGG;IACH,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,IAAA,gBAAQ,EAAM,IAAI,CAAC,CAAC;IAC9D;;;OAGG;IACH,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,IAAA,gBAAQ,EAAW,kBAAkB,CAAC,CAAC;IAE7E;;;;;;OAMG;IACH,MAAM,WAAW,GAAG,IAAA,mBAAW,EAC7B,CAAC,IAAS,EAAE,KAAa,EAAW,EAAE;QACpC,OAAO,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC;IAC3G,CAAC,EACD,CAAC,aAAa,EAAE,WAAW,CAAC,CAC7B,CAAC;IAEF;;OAEG;IACH,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,cAAc,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAC;QACzC,IAAI,kBAAkB,EAAE,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE;YACrD,OAAO,CAAC,KAAK,CAAC,mFAAmF,CAAC,CAAC;SACpG;IACH,CAAC,EAAE,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAC,CAAC;IAEzC;;;;;OAKG;IACH,MAAM,UAAU,GAAG,CAAC,EAAE,IAAI,EAAE,KAAK,EAAgC,EAAe,EAAE,CAAC,CACjF,8BAAC,uBAAa,IACZ,cAAc,EAAE,kBAAkB,EAClC,WAAW,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,EAC3C,UAAU,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,EACzC,iBAAiB,EAAE,iBAAiB,EACpC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,EAChC,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE;YAClB,IAAI,MAAM,IAAI,CAAC,cAAc,EAAE;gBAC7B,cAAc,CAAC,EAAE,CAAC,CAAC;gBACnB,gBAAgB,CAAC,IAAI,CAAC,CAAC;aACxB;QACH,CAAC,EACD,cAAc,EAAE,cAAc,EAC9B,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,GAC5D,CACH,CAAC;IACF,OAAO,8BAAC,uBAAQ,IAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAM,KAAK,GAAI,CAAC;AACtH,CAAC,CAAC;AAEF,kBAAe,aAAa,CAAC"}
--------------------------------------------------------------------------------
/lib/index.d.ts:
--------------------------------------------------------------------------------
1 | import AccordionItem from './components/AccordionItem';
2 | import AccordionList from './components/AccordionList';
3 | /**
4 | * Exported components from the Accordion module.
5 | *
6 | * @module Accordion
7 | * @exports AccordionItem - An individual accordion item component.
8 | * @exports AccordionList - A component for rendering a list of expandable accordion items.
9 | */
10 | export { AccordionItem, AccordionList };
11 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
4 | };
5 | Object.defineProperty(exports, "__esModule", { value: true });
6 | exports.AccordionList = exports.AccordionItem = void 0;
7 | const AccordionItem_1 = __importDefault(require("./components/AccordionItem"));
8 | exports.AccordionItem = AccordionItem_1.default;
9 | const AccordionList_1 = __importDefault(require("./components/AccordionList"));
10 | exports.AccordionList = AccordionList_1.default;
11 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/lib/index.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":";;;;;;AAAA,+EAAuD;AAU9C,wBAVF,uBAAa,CAUE;AATtB,+EAAuD;AAS/B,wBATjB,uBAAa,CASiB"}
--------------------------------------------------------------------------------
/lib/models/AccordionItem.d.ts:
--------------------------------------------------------------------------------
1 | import { ViewStyle } from 'react-native';
2 | import { AccordionPressableProps } from './AccordionPressable';
3 | /**
4 | * Props for the AccordionItem component.
5 | * @interface AccordionItemProps
6 | */
7 | export interface AccordionItemProps {
8 | /**
9 | * Function that returns a React element to display as Accordion title.
10 | * @function
11 | * @returns {JSX.Element} - The React element for the title.
12 | */
13 | customTitle: () => JSX.Element;
14 | /**
15 | * Function that returns a React element to display as Accordion body.
16 | * @function
17 | * @returns {JSX.Element} - The React element for the body.
18 | */
19 | customBody: () => JSX.Element;
20 | /**
21 | * An optional function that returns a React element to display as Accordion icon.
22 | * Default icon is keyboard-arrow-left.
23 | * @function
24 | * @returns {JSX.Element} - The React element for the icon.
25 | */
26 | customIcon?: () => JSX.Element;
27 | /**
28 | * An optional parameter to add custom container style.
29 | * @type {ViewStyle}
30 | */
31 | containerStyle?: ViewStyle;
32 | /**
33 | * An optional parameter to control Accordion animation duration.
34 | * Default value is 300.
35 | * @type {number}
36 | */
37 | animationDuration?: number;
38 | /**
39 | * An optional parameter to support RTL layout.
40 | * Default value is false.
41 | * @type {boolean}
42 | */
43 | isRTL?: boolean;
44 | /**
45 | * An optional parameter to make the accordion item already open.
46 | * Default value is false.
47 | * @type {boolean}
48 | */
49 | isOpen?: boolean;
50 | /**
51 | * An optional parameter to call a function when a click happens to the accordion item.
52 | * Default value is undefined.
53 | * @param {boolean} isOpen - The current state of the accordion item.
54 | */
55 | onPress?: (isOpen: boolean) => void;
56 | /**
57 | * Additional props for configuring the Pressable component.
58 | * @type {AccordionPressableProps}
59 | */
60 | pressableProps?: AccordionPressableProps;
61 | }
62 |
--------------------------------------------------------------------------------
/lib/models/AccordionItem.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | //# sourceMappingURL=AccordionItem.js.map
--------------------------------------------------------------------------------
/lib/models/AccordionItem.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"AccordionItem.js","sourceRoot":"","sources":["../../src/models/AccordionItem.tsx"],"names":[],"mappings":""}
--------------------------------------------------------------------------------
/lib/models/AccordionList.d.ts:
--------------------------------------------------------------------------------
1 | import { FlatListProps, ViewStyle } from 'react-native';
2 | import { AccordionPressableProps } from './AccordionPressable';
3 | /**
4 | * Props for the AccordionList component.
5 | * Extends FlatListProps from react-native.
6 | * @interface AccordionListProps
7 | * @extends FlatListProps
8 | */
9 | export interface AccordionListProps extends Omit, 'data' | 'renderItem'> {
10 | /**
11 | * An array of data to be displayed in the AccordionList.
12 | * @type {any[]}
13 | */
14 | data: any[];
15 | /**
16 | * Function that returns a React element to display as Accordion title.
17 | * @function
18 | * @param {any} item - The data item for the Accordion.
19 | * @param {number} [index] - The index of the item in the data array.
20 | * @returns {JSX.Element} - The React element for the title.
21 | */
22 | customTitle: (item: any, index: number) => JSX.Element;
23 | /**
24 | * Function that returns a React element to display as Accordion body.
25 | * @function
26 | * @param {any} item - The data item for the Accordion.
27 | * @param {number} [index] - The index of the item in the data array.
28 | * @returns {JSX.Element} - The React element for the body.
29 | */
30 | customBody: (item: any, index: number) => JSX.Element;
31 | /**
32 | * An optional function that returns a React element to display as Accordion icon.
33 | * Default icon is keyboard-arrow-left.
34 | * @function
35 | * @param {number} [index] - The index of the item in the data array.
36 | * @returns {JSX.Element} - The React element for the icon.
37 | */
38 | customIcon?: (index: number) => JSX.Element;
39 | /**
40 | * An optional parameter to add custom container item style.
41 | * @type {ViewStyle}
42 | */
43 | containerItemStyle?: ViewStyle;
44 | /**
45 | * An optional parameter to control Accordion animation duration.
46 | * Default value is 300.
47 | * @type {number}
48 | */
49 | animationDuration?: number;
50 | /**
51 | * An optional parameter to support RTL layout.
52 | * Default value is false.
53 | * @type {boolean}
54 | */
55 | isRTL?: boolean;
56 | /**
57 | * Allow more than one section to be expanded.
58 | * Default value is false.
59 | * @type {boolean}
60 | */
61 | expandMultiple?: boolean;
62 | /**
63 | * An array of indices indicating which sections should be expanded by default.
64 | * @type {number[]}
65 | */
66 | defaultOpenIndices?: number[];
67 | /**
68 | * Additional props for configuring the Pressable component.
69 | * @type {AccordionPressableProps}
70 | */
71 | pressableProps?: AccordionPressableProps;
72 | }
73 |
--------------------------------------------------------------------------------
/lib/models/AccordionList.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | //# sourceMappingURL=AccordionList.js.map
--------------------------------------------------------------------------------
/lib/models/AccordionList.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"AccordionList.js","sourceRoot":"","sources":["../../src/models/AccordionList.tsx"],"names":[],"mappings":""}
--------------------------------------------------------------------------------
/lib/models/AccordionPressable.d.ts:
--------------------------------------------------------------------------------
1 | import { GestureResponderEvent, Insets, MouseEvent, NativeSyntheticEvent, PressableAndroidRippleConfig, PressableStateCallbackType, StyleProp, TargetedEvent, ViewStyle } from 'react-native';
2 | /**
3 | * Props for configuring the behavior and styling of the Pressable component within the AccordionItem component.
4 | * @interface AccordionPressableProps
5 | */
6 | export interface AccordionPressableProps {
7 | /**
8 | * Called when the hover is activated to provide visual feedback.
9 | * @param {MouseEvent} event - The mouse event when hover is activated.
10 | */
11 | onHoverIn?: ((event: MouseEvent) => void) | null | undefined;
12 | /**
13 | * Called when the hover is deactivated to undo visual feedback.
14 | * @param {MouseEvent} event - The mouse event when hover is deactivated.
15 | */
16 | onHoverOut?: ((event: MouseEvent) => void) | null | undefined;
17 | /**
18 | * Called when a touch is engaged before `onPress`.
19 | * @param {GestureResponderEvent} event - The gesture responder event when touch is engaged.
20 | */
21 | onPressIn?: ((event: GestureResponderEvent) => void) | null | undefined;
22 | /**
23 | * Called when a touch is released before `onPress`.
24 | * @param {GestureResponderEvent} event - The gesture responder event when touch is released.
25 | */
26 | onPressOut?: ((event: GestureResponderEvent) => void) | null | undefined;
27 | /**
28 | * Called when a long-tap gesture is detected.
29 | * @param {GestureResponderEvent} event - The gesture responder event when long-tap is detected.
30 | */
31 | onLongPress?: ((event: GestureResponderEvent) => void) | null | undefined;
32 | /**
33 | * Called after the element loses focus.
34 | * @platform macos windows
35 | * @param {NativeSyntheticEvent} event - The native synthetic event.
36 | */
37 | onBlur?: ((event: NativeSyntheticEvent) => void) | null | undefined;
38 | /**
39 | * Called after the element is focused.
40 | * @platform macos windows
41 | * @param {NativeSyntheticEvent} event - The native synthetic event.
42 | */
43 | onFocus?: ((event: NativeSyntheticEvent) => void) | null | undefined;
44 | /**
45 | * Whether a press gesture can be interrupted by a parent gesture such as a scroll event. Defaults to true.
46 | * @type {boolean}
47 | */
48 | cancelable?: boolean | null | undefined;
49 | /**
50 | * Duration to wait after hover in before calling `onHoverIn`.
51 | * @platform macos windows
52 | * @type {number}
53 | */
54 | delayHoverIn?: number | null | undefined;
55 | /**
56 | * Duration to wait after hover out before calling `onHoverOut`.
57 | * @platform macos windows
58 | * @type {number}
59 | */
60 | delayHoverOut?: number | null | undefined;
61 | /**
62 | * Duration (in milliseconds) from `onPressIn` before `onLongPress` is called.
63 | * @type {number}
64 | */
65 | delayLongPress?: number | null | undefined;
66 | /**
67 | * Whether the press behavior is disabled.
68 | * @type {boolean}
69 | */
70 | disabled?: boolean | null | undefined;
71 | /**
72 | * Additional distance outside of this view in which a press is detected.
73 | * @type {Insets | number}
74 | */
75 | hitSlop?: Insets | number | null | undefined;
76 | /**
77 | * Additional distance outside of this view in which a touch is considered a press before `onPressOut` is triggered.
78 | * @type {Insets | number}
79 | */
80 | pressRetentionOffset?: Insets | number | null | undefined;
81 | /**
82 | * If true, doesn't play system sound on touch.
83 | * @type {boolean}
84 | */
85 | android_disableSound?: boolean | null | undefined;
86 | /**
87 | * Enables the Android ripple effect and configures its color.
88 | * @type {PressableAndroidRippleConfig}
89 | */
90 | android_ripple?: PressableAndroidRippleConfig | null | undefined;
91 | /**
92 | * Used only for documentation or testing (e.g. snapshot testing).
93 | * @type {boolean}
94 | */
95 | testOnly_pressed?: boolean | null | undefined;
96 | /**
97 | * Duration (in milliseconds) to wait after press down before calling onPressIn.
98 | * @type {number}
99 | */
100 | unstable_pressDelay?: number;
101 | /**
102 | * Either view styles or a function that receives a boolean reflecting whether
103 | * the component is currently pressed and returns view styles.
104 | * @type {StyleProp | ((state: PressableStateCallbackType) => StyleProp)}
105 | */
106 | style?: StyleProp | ((state: PressableStateCallbackType) => StyleProp) | undefined;
107 | }
108 |
--------------------------------------------------------------------------------
/lib/models/AccordionPressable.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | //# sourceMappingURL=AccordionPressable.js.map
--------------------------------------------------------------------------------
/lib/models/AccordionPressable.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"AccordionPressable.js","sourceRoot":"","sources":["../../src/models/AccordionPressable.tsx"],"names":[],"mappings":""}
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-accordion-list-view",
3 | "version": "2.0.3",
4 | "description": "Animated accordion collapsable List for react native.",
5 | "main": "lib/index.js",
6 | "types": "lib/index.d.ts",
7 | "scripts": {
8 | "build": "tsc",
9 | "test": "echo \"Error: no test specified\" && exit 1",
10 | "format": "prettier --write \"src/**/*.tsx\"",
11 | "lint": "tslint -p tsconfig.json"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/louaySleman/react-native-accordion-list-view.git"
16 | },
17 | "keywords": [
18 | "react",
19 | "react-native",
20 | "Accordion",
21 | "Collapse",
22 | "show",
23 | "hide",
24 | "click to show/hide",
25 | "android",
26 | "ios",
27 | "react-native-component",
28 | "react native",
29 | "mobile",
30 | "expand",
31 | "expandable-listview",
32 | "react-native-expandable-listview",
33 | "customizable",
34 | "react-native-accordion-list-view",
35 | "react-native-accordion-listview",
36 | "react-native-accordion",
37 | "animated",
38 | "RTL accordion",
39 | "RTL"
40 | ],
41 | "dependencies": {
42 | "react-native-vector-icons": "*"
43 | },
44 | "devDependencies": {
45 | "@types/react": "^18.0.21",
46 | "@types/react-native": "^0.70.6",
47 | "@types/react-native-vector-icons": "^6.4.12",
48 | "prettier": "^2.8.1",
49 | "react": "18.1.0",
50 | "react-native": "0.70.6",
51 | "tslint": "^6.1.3",
52 | "tslint-config-prettier": "^1.18.0",
53 | "typescript": "^4.9.4"
54 | },
55 | "author": "Louay Sleman",
56 | "license": "MIT",
57 | "bugs": {
58 | "url": "https://github.com/louaySleman/react-native-accordion-list-view/issues"
59 | },
60 | "homepage": "https://github.com/louaySleman/react-native-accordion-list-view"
61 | }
62 |
--------------------------------------------------------------------------------
/src/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louaySleman/react-native-accordion-list-view/a35573fc0beb36e31851c0513cbe0a05700df022/src/.DS_Store
--------------------------------------------------------------------------------
/src/README.md:
--------------------------------------------------------------------------------
1 | ## react-native-accordion-list-view
2 | A high performance, beautiful and fully customizable Accordion list for React Native.
3 | Implemented using [react-native-vector-icons](https://github.com/oblador/react-native-vector-icons).
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ## Getting started
18 | ```js
19 | npm install react-native-accordion-list-view --save
20 | ```
21 | or
22 | ```js
23 | yarn add react-native-accordion-list-view
24 | ```
25 | Now we need to install [react-native-vector-icons](https://github.com/oblador/react-native-vector-icons).
26 |
27 | ```js
28 | npm install react-native-vector-icons --save
29 | ```
30 | or
31 | ```js
32 | yarn add react-native-vector-icons
33 | ```
34 |
35 | ## Platforms Supported
36 |
37 | - [x] iOS
38 | - [x] Android
39 |
40 | ## Important Note
41 | This plugin work with Layout Animation and In order to get this to work on Android you need to set the following flags via UIManager:
42 | ```javascript
43 | if (Platform.OS === 'android') {
44 | if (UIManager.setLayoutAnimationEnabledExperimental) {
45 | UIManager.setLayoutAnimationEnabledExperimental(true);
46 | }
47 | }
48 | ```
49 |
50 | ### Demo
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | ## Versioning
60 | This project follows semantic versioning. We do not hesitate to release breaking changes but they will be in a major version.
61 |
62 | ### Breaking History:
63 |
64 | - [2.0.2](https://www.npmjs.com/package/react-native-accordion-list-view/v/2.0.2) - New Features
65 |
66 | **defaultOpenIndices**: You can now specify an array of indices in the `defaultOpenIndices` prop for the accordion list. These indices indicate which sections should be expanded by default, allowing you to control the initial state of the accordion.
67 |
68 | **pressableProps**: We've added a new prop called `pressableProps` to both the accordion list and accordion item components. This allows you to customize the styles and ripple effects for the pressable component, giving you more control over the user interaction experience.
69 | - [2.0.1](https://www.npmjs.com/package/react-native-accordion-list-view/v/2.0.1) - Allow single/multiple expanding, allow `AccordionItem` to be opened by default using `isOpen` property, add `onPress` for `AccordionItem`.
70 | - [2.0.0](https://www.npmjs.com/package/react-native-accordion-list-view/v/2.0.0) - Change library code to typescript and Replacing `TouchableOpacity` with `Pressable`.
71 | - [1.0.4](https://www.npmjs.com/package/react-native-accordion-list-view/v/1.0.4) - Support RTL and update `README`.
72 | - [1.0.3](https://www.npmjs.com/package/react-native-accordion-list-view/v/1.0.3) - Accordion list `FlatList` props bug fixes.
73 | - [1.0.2](https://www.npmjs.com/package/react-native-accordion-list-view/v/1.0.2) - Accordion Item Bug fixes.
74 | - [1.0.1](https://www.npmjs.com/package/react-native-accordion-list-view/v/1.0.1) - Update `README`.
75 | - [1.0.0](https://www.npmjs.com/package/react-native-accordion-list-view/v/1.0.0) - First release.
76 |
77 | ### Accordion list
78 |
79 | | Props | Params | isRequire | Default | Description |
80 | |--------------------|-------------------------------------------------------------------|-----------|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
81 | | data | Array | Yes | | For simplicity, data is a plain array. If you want to use something else, like an immutable list |
82 | | customTitle | (item) => JSX.Element | Yes | | Function that returns a React element to display as Accordion title |
83 | | customBody | (item) => JSX.Element | Yes | | Function that returns a React element to display as Accordion body |
84 | | customIcon | () => JSX.Element | No | keyboard-arrow-left | Function that returns a React element to display as Accordion icon |
85 | | containerItemStyle | ViewStyle | No | {} | Styling for Accordion item container view |
86 | | style | ViewStyle | No | {} | Styling for container view |
87 | | animationDuration | Number | No | 300 | Accordion animation duration |
88 | | isRTL | Boolean | No | false | Support RTL |
89 | | expandMultiple | Boolean | No | false | Allow more than one section to be expanded |
90 | | defaultOpenIndices | number[] | No | [] | An array of indices indicating which sections should be expanded by default. If `expandMultiple` is set to `false`, it can only contain a single index. |
91 | | pressableProps | [AccordionPressableProps](https://reactnative.dev/docs/pressable) | No | {} | Additional props for configuring the Pressable component. |
92 |
93 |
94 | ### More props
95 |
96 | This is a wrapper around `Flatlist`, all their props works well and the inherited props too (from `ScrollView` and `VirtualizedList`).
97 |
98 | ### Example
99 |
100 | #### Without Custom Styles
101 | ```javascript
102 | import React, { useEffect } from 'react';
103 | import {View, SafeAreaView, StyleSheet, Text, Platform, UIManager} from 'react-native';
104 | import {AccordionList} from 'react-native-accordion-list-view';
105 |
106 | const App = () => {
107 | const data = [
108 | {
109 | id: 0,
110 | title: 'Lorem Ipsum is simply dummy',
111 | body: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
112 | },
113 | {
114 | id: 1,
115 | title: 'Lorem Ipsum is simply dummy',
116 | body: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
117 | },
118 | ];
119 | useEffect(() => {
120 | if (Platform.OS === 'android') {
121 | if (UIManager.setLayoutAnimationEnabledExperimental) {
122 | UIManager.setLayoutAnimationEnabledExperimental(true);
123 | }
124 | }
125 | }, []);
126 | return (
127 |
128 |
129 | {item.title}}
132 | customBody={item => {item.body}}
133 | animationDuration={400}
134 | expandMultiple={true}
135 | />
136 |
137 |
138 | );
139 | };
140 |
141 | export default App;
142 | const styles = StyleSheet.create({
143 | container: {
144 | paddingVertical: '2%',
145 | paddingHorizontal: '3%',
146 | height: '100%',
147 | backgroundColor: '#e7e7e7',
148 | },
149 | });
150 |
151 | ```
152 |
153 | #### With Custom Styles
154 | ```javascript
155 | import React, { useEffect } from 'react';
156 | import {View, SafeAreaView, StyleSheet, Text, Platform, UIManager} from 'react-native';
157 | import {AccordionList} from 'react-native-accordion-list-view';
158 |
159 | const App = () => {
160 | const data = [
161 | {
162 | id: 0,
163 | title: 'Lorem Ipsum is simply dummy',
164 | body: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
165 | },
166 | {
167 | id: 1,
168 | title: 'Lorem Ipsum is simply dummy',
169 | body: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
170 | },
171 | {
172 | id: 2,
173 | title: 'Lorem Ipsum is simply dummy',
174 | body: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
175 | },
176 | {
177 | id: 3,
178 | title: 'Lorem Ipsum is simply dummy',
179 | body: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
180 | },
181 | ];
182 | useEffect(() => {
183 | if (Platform.OS === 'android') {
184 | if (UIManager.setLayoutAnimationEnabledExperimental) {
185 | UIManager.setLayoutAnimationEnabledExperimental(true);
186 | }
187 | }
188 | }, []);
189 | return (
190 |
191 |
192 | {item.title}}
195 | customBody={item => {item.body}}
196 | animationDuration={400}
197 | defaultOpenIndices={[0, 2]}
198 | expandMultiple={true}
199 | containerItemStyle={{padding: 0}}
200 | pressableProps={{
201 | style: ({pressed}) => [
202 | {
203 | padding: '2%',
204 | backgroundColor:
205 | pressed && Platform.OS == 'ios'
206 | ? 'rgb(210, 230, 255)'
207 | : 'transparent',
208 | },
209 | ],
210 | android_ripple: {
211 | color: 'rgb(210, 230, 255)',
212 | },
213 | }}
214 | />
215 |
216 |
217 | );
218 | };
219 |
220 | export default App;
221 | const styles = StyleSheet.create({
222 | container: {
223 | paddingVertical: '2%',
224 | paddingHorizontal: '3%',
225 | height: '100%',
226 | backgroundColor: '#e7e7e7',
227 | },
228 | });
229 |
230 | ```
231 |
232 | ### Accordion Item
233 | This component allows you to use `Accordion Item` component in any place if you have your own wrapper or if you have a problem with using `FlatList` in your screen.
234 |
235 | | Props | Params | isRequire | Default | Description |
236 | |-------------------|------------------|-----------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------|
237 | | customTitle | () => JSX.Element | Yes | | Function that returns a React element to display as Accordion title |
238 | | customBody | () => JSX.Element | Yes | | Function that returns a React element to display as Accordion body |
239 | | customIcon | () => JSX.Element | No | keyboard-arrow-left | Function that returns a React element to display as Accordion icon |
240 | | containerStyle | ViewStyle | No | {} | Styling for Accordion item container view |
241 | | animationDuration | Number | No | 300 | Accordion animation duration |
242 | | isRTL | Boolean | No | false | Support RTL |
243 | | isOpen | Boolean | No | false | An optional param to make accordion item already open |
244 | | onPress | (isOpen: boolean) => void | No | - | An optional callback function called when a click happen to the accordion item and return the current state (if it's open or not) |
245 | | pressableProps | [AccordionPressableProps](https://reactnative.dev/docs/pressable) | No | {} | Additional props for configuring the Pressable component. |
246 |
247 | ### Example
248 |
249 | ```javascript
250 | import React, {useEffect} from 'react';
251 | import {View, SafeAreaView, StyleSheet, Text, ScrollView, Platform, UIManager} from 'react-native';
252 | import {AccordionItem} from 'react-native-accordion-list-view';
253 |
254 | const App = () => {
255 | const data = [
256 | {
257 | id: 0,
258 | title: 'Lorem Ipsum is simply dummy',
259 | body: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
260 | },
261 | {
262 | id: 1,
263 | title: 'Lorem Ipsum is simply dummy',
264 | body: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
265 | },
266 | ];
267 | useEffect(() => {
268 | if (Platform.OS === 'android') {
269 | if (UIManager.setLayoutAnimationEnabledExperimental) {
270 | UIManager.setLayoutAnimationEnabledExperimental(true);
271 | }
272 | }
273 | }, []);
274 | return (
275 |
276 |
277 | {data.map(item => (
278 | {item.title}}
281 | customBody={() => {item.body}}
282 | animationDuration={400}
283 | isOpen={false}
284 | onPress={(isOpen) => console.log(isOpen)}
285 | />
286 | ))}
287 |
288 |
289 | );
290 | };
291 |
292 | export default App;
293 | const styles = StyleSheet.create({
294 | container: {
295 | paddingVertical: '2%',
296 | paddingHorizontal: '3%',
297 | height: '100%',
298 | backgroundColor: '#e7e7e7',
299 | },
300 | });
301 |
302 | ```
303 | ### Common Issues and Errors
304 |
305 | Error: You have multiple items opened by default, but expandMultiple is disabled, If you encounter the following error message in your console:
306 |
307 | ```javascript
308 | console.error('Error: You have multiple items opened by default, but expandMultiple is disabled.');
309 | ```
310 | This error occurs when you have set expandMultiple to false and provided an array with multiple indices in the defaultOpenIndices prop. Remember that when expandMultiple is set to false, you can only specify a single index in the defaultOpenIndices array.
311 |
312 | To resolve this issue, make sure that defaultOpenIndices contains only one index when expandMultiple is false.
313 |
314 | ### License
315 | MIT
316 |
--------------------------------------------------------------------------------
/src/animations/toggleAnimation.tsx:
--------------------------------------------------------------------------------
1 | import { LayoutAnimation, LayoutAnimationConfig } from 'react-native';
2 |
3 | /**
4 | * Generates a layout animation configuration for toggling the visibility of an element.
5 | *
6 | * @param {number} animationDuration - The duration of the animation in milliseconds.
7 | * @returns {LayoutAnimationConfig} - The layout animation configuration object.
8 | */
9 | export const toggleAnimation = (animationDuration = 300): LayoutAnimationConfig => {
10 | return {
11 | duration: animationDuration,
12 | update: {
13 | duration: animationDuration,
14 | property: LayoutAnimation.Properties.scaleXY,
15 | type: LayoutAnimation.Types.easeInEaseOut,
16 | },
17 | delete: {
18 | duration: animationDuration,
19 | property: LayoutAnimation.Properties.opacity,
20 | type: LayoutAnimation.Types.easeInEaseOut,
21 | },
22 | };
23 | };
24 |
--------------------------------------------------------------------------------
/src/components/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louaySleman/react-native-accordion-list-view/a35573fc0beb36e31851c0513cbe0a05700df022/src/components/.DS_Store
--------------------------------------------------------------------------------
/src/components/AccordionItem/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef, useState } from 'react';
2 | import { View, Animated, LayoutAnimation, I18nManager, Pressable } from 'react-native';
3 | import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
4 | import { toggleAnimation } from '../../animations/toggleAnimation';
5 | import { AccordionItemProps } from '../../models/AccordionItem';
6 | import { styles } from './styles';
7 |
8 | /**
9 | * An individual item within an accordion list that can be expanded or collapsed.
10 | * @param {AccordionItemProps} props - Props for configuring the AccordionItem.
11 | * @returns {JSX.Element} - The AccordionItem component.
12 | */
13 | const AccordionItem = ({
14 | customBody,
15 | customTitle,
16 | customIcon = undefined,
17 | containerStyle = {},
18 | animationDuration = 300,
19 | isRTL = false,
20 | isOpen = false,
21 | onPress = undefined,
22 | pressableProps = {},
23 | }: AccordionItemProps): JSX.Element => {
24 | /**
25 | * Indicates whether the content of the accordion item is currently displayed.
26 | * @type {boolean}
27 | */
28 | const [showContent, setShowContent] = useState(isOpen);
29 | /**
30 | * A controller for managing the animation of the accordion item.
31 | * @type {Animated.Value}
32 | */
33 | const animationController = useRef(new Animated.Value(isOpen ? 1 : 0)).current;
34 |
35 | /**
36 | * Toggles the visibility of the accordion item's content when the `isOpen` prop changes.
37 | * This effect is triggered when the `isOpen` prop changes.
38 | */
39 | useEffect(() => {
40 | if (isOpen !== showContent) {
41 | toggleListItem();
42 | }
43 | }, [isOpen]);
44 |
45 | /**
46 | * Toggles the visibility of the accordion item's content.
47 | */
48 | const toggleListItem = () => {
49 | const config = {
50 | duration: animationDuration,
51 | toValue: showContent ? 0 : 1,
52 | useNativeDriver: true,
53 | };
54 | Animated.timing(animationController, config).start();
55 | LayoutAnimation.configureNext(toggleAnimation(animationDuration));
56 | if (onPress) onPress(!showContent);
57 | setShowContent(!showContent);
58 | };
59 |
60 | /**
61 | * An animated transformation for rotating the arrow icon based on the animation state.
62 | * @type {Animated.AnimatedInterpolation}
63 | */
64 | const arrowTransform = animationController.interpolate({
65 | inputRange: [0, 1],
66 | outputRange: ['0deg', isRTL ? '-90deg' : '90deg'],
67 | });
68 |
69 | return (
70 |
71 | toggleListItem()}>
72 |
73 | {(!isRTL || I18nManager.isRTL) && customTitle()}
74 |
75 | {!customIcon ? (
76 |
77 | ) : (
78 | customIcon()
79 | )}
80 |
81 | {isRTL && !I18nManager.isRTL && customTitle()}
82 |
83 |
84 | {showContent && customBody()}
85 |
86 | );
87 | };
88 | export default AccordionItem;
89 |
--------------------------------------------------------------------------------
/src/components/AccordionItem/styles.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { StyleSheet } from 'react-native';
3 |
4 | /**
5 | * Styles for the AccordionItem component.
6 | * @constant {object}
7 | */
8 | export const styles = StyleSheet.create({
9 | /**
10 | * Styles for the container that wraps the entire AccordionItem.
11 | * @type {object}
12 | */
13 | container: {
14 | width: '100%',
15 | padding: '2%',
16 | borderRadius: 12,
17 | backgroundColor: 'white',
18 | marginBottom: '2%',
19 | overflow: 'hidden',
20 | },
21 | /**
22 | * Styles for the title text within the AccordionItem.
23 | * @type {object}
24 | */
25 | title: {
26 | fontSize: 16,
27 | color: '#2d2d2d',
28 | fontWeight: 'bold',
29 | },
30 | /**
31 | * Styles for the body content within the AccordionItem.
32 | * @type {object}
33 | */
34 | body: {
35 | paddingHorizontal: '2%',
36 | paddingVertical: '3%',
37 | },
38 | /**
39 | * Styles for the container of the title and optional icon.
40 | * @type {object}
41 | */
42 | titleContainer: {
43 | flexDirection: 'row',
44 | alignItems: 'center',
45 | justifyContent: 'space-between',
46 | },
47 | });
48 |
--------------------------------------------------------------------------------
/src/components/AccordionList/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useCallback, useEffect, useState } from 'react';
2 | import { FlatList } from 'react-native';
3 | import AccordionItem from '../AccordionItem';
4 | import { AccordionListProps } from '../../models/AccordionList';
5 |
6 | /**
7 | * A component for rendering an accordion list with expandable items.
8 | *
9 | * @param {AccordionListProps} props - Props for configuring the AccordionList.
10 | * @param {any[]} props.data - The data to render in the accordion list.
11 | * @param {(item: any) => JSX.Element} props.customTitle - Function that returns a React element for the custom title of each item.
12 | * @param {(item: any) => JSX.Element} props.customBody - Function that returns a React element for the custom body of each item.
13 | * @param {() => JSX.Element | undefined} [props.customIcon] - Function that returns a React element for a custom icon, or undefined to use default icons.
14 | * @param {object} [props.containerItemStyle] - Additional styles for the container of each accordion item.
15 | * @param {number} [props.animationDuration] - The duration of the animation when expanding/collapsing items.
16 | * @param {boolean} [props.isRTL] - Whether to use right-to-left layout.
17 | * @param {boolean} [props.expandMultiple] - Whether to allow multiple items to be expanded at the same time.
18 | * @param {number[]} [props.defaultOpenIndices] - An array of indices specifying which items should be open by default.
19 | * @param {object} [props.pressableProps] - Additional props for the Pressable component.
20 | * @returns {JSX.Element} - The AccordionList component.
21 | */
22 | const AccordionList = ({
23 | data,
24 | customTitle,
25 | customBody,
26 | customIcon = undefined,
27 | containerItemStyle = {},
28 | animationDuration = 300,
29 | isRTL = false,
30 | expandMultiple = false,
31 | defaultOpenIndices = [],
32 | pressableProps = {},
33 | ...props
34 | }: AccordionListProps): JSX.Element => {
35 | /**
36 | * State variable to track the currently open item in the accordion.
37 | * @type {any}
38 | */
39 | const [currentlyOpen, setCurrentlyOpen] = useState(null);
40 | /**
41 | * State variable to store an array of default open indices in the accordion.
42 | * @type {number[]}
43 | */
44 | const [defaultOpen, setDefaultOpen] = useState(defaultOpenIndices);
45 |
46 | /**
47 | * Checks if an accordion item is open based on its index.
48 | *
49 | * @param {any} item - The data item of the accordion.
50 | * @param {number} index - The index of the accordion item.
51 | * @returns {boolean} - True if the item is open; otherwise, false.
52 | */
53 | const checkIfOpen = useCallback(
54 | (item: any, index: number): boolean => {
55 | return JSON.stringify(currentlyOpen) === JSON.stringify(item) || (defaultOpen?.includes(index) ?? false);
56 | },
57 | [currentlyOpen, defaultOpen],
58 | );
59 |
60 | /**
61 | * useEffect to initialize the default open indices and show an error if necessary.
62 | */
63 | useEffect(() => {
64 | setDefaultOpen(defaultOpenIndices || []);
65 | if (defaultOpenIndices?.length > 1 && !expandMultiple) {
66 | console.error('Error: You have multiple items opened by default, but expandMultiple is disabled.');
67 | }
68 | }, [defaultOpenIndices, expandMultiple]);
69 |
70 | /**
71 | * Renders an individual item within the accordion.
72 | *
73 | * @param {{ item: any; index: number }} - The item and its index.
74 | * @returns {JSX.Element} - The rendered AccordionItem component.
75 | */
76 | const renderItem = ({ item, index }: { item: any; index: number }): JSX.Element => (
77 | customTitle(item, index)}
80 | customBody={() => customBody(item, index)}
81 | animationDuration={animationDuration}
82 | isRTL={isRTL}
83 | isOpen={checkIfOpen(item, index)}
84 | onPress={(status) => {
85 | if (status && !expandMultiple) {
86 | setDefaultOpen([]);
87 | setCurrentlyOpen(item);
88 | }
89 | }}
90 | pressableProps={pressableProps}
91 | customIcon={customIcon ? () => customIcon(index) : undefined}
92 | />
93 | );
94 | return index.toString()} {...props} />;
95 | };
96 |
97 | export default AccordionList;
98 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import AccordionItem from './components/AccordionItem';
2 | import AccordionList from './components/AccordionList';
3 |
4 | /**
5 | * Exported components from the Accordion module.
6 | *
7 | * @module Accordion
8 | * @exports AccordionItem - An individual accordion item component.
9 | * @exports AccordionList - A component for rendering a list of expandable accordion items.
10 | */
11 | export { AccordionItem, AccordionList };
12 |
--------------------------------------------------------------------------------
/src/models/AccordionItem.tsx:
--------------------------------------------------------------------------------
1 | import { ViewStyle } from 'react-native';
2 | import * as React from 'react';
3 | import { AccordionPressableProps } from './AccordionPressable';
4 |
5 | /**
6 | * Props for the AccordionItem component.
7 | * @interface AccordionItemProps
8 | */
9 | export interface AccordionItemProps {
10 | /**
11 | * Function that returns a React element to display as Accordion title.
12 | * @function
13 | * @returns {JSX.Element} - The React element for the title.
14 | */
15 | customTitle: () => JSX.Element;
16 |
17 | /**
18 | * Function that returns a React element to display as Accordion body.
19 | * @function
20 | * @returns {JSX.Element} - The React element for the body.
21 | */
22 | customBody: () => JSX.Element;
23 |
24 | /**
25 | * An optional function that returns a React element to display as Accordion icon.
26 | * Default icon is keyboard-arrow-left.
27 | * @function
28 | * @returns {JSX.Element} - The React element for the icon.
29 | */
30 | customIcon?: () => JSX.Element;
31 |
32 | /**
33 | * An optional parameter to add custom container style.
34 | * @type {ViewStyle}
35 | */
36 | containerStyle?: ViewStyle;
37 |
38 | /**
39 | * An optional parameter to control Accordion animation duration.
40 | * Default value is 300.
41 | * @type {number}
42 | */
43 | animationDuration?: number;
44 |
45 | /**
46 | * An optional parameter to support RTL layout.
47 | * Default value is false.
48 | * @type {boolean}
49 | */
50 | isRTL?: boolean;
51 |
52 | /**
53 | * An optional parameter to make the accordion item already open.
54 | * Default value is false.
55 | * @type {boolean}
56 | */
57 | isOpen?: boolean;
58 |
59 | /**
60 | * An optional parameter to call a function when a click happens to the accordion item.
61 | * Default value is undefined.
62 | * @param {boolean} isOpen - The current state of the accordion item.
63 | */
64 | onPress?: (isOpen: boolean) => void;
65 |
66 | /**
67 | * Additional props for configuring the Pressable component.
68 | * @type {AccordionPressableProps}
69 | */
70 | pressableProps?: AccordionPressableProps;
71 | }
72 |
--------------------------------------------------------------------------------
/src/models/AccordionList.tsx:
--------------------------------------------------------------------------------
1 | import { FlatListProps, ViewStyle } from 'react-native';
2 | import { AccordionPressableProps } from './AccordionPressable';
3 |
4 | /**
5 | * Props for the AccordionList component.
6 | * Extends FlatListProps from react-native.
7 | * @interface AccordionListProps
8 | * @extends FlatListProps
9 | */
10 | export interface AccordionListProps extends Omit, 'data' | 'renderItem'> {
11 | /**
12 | * An array of data to be displayed in the AccordionList.
13 | * @type {any[]}
14 | */
15 | data: any[];
16 |
17 | /**
18 | * Function that returns a React element to display as Accordion title.
19 | * @function
20 | * @param {any} item - The data item for the Accordion.
21 | * @param {number} [index] - The index of the item in the data array.
22 | * @returns {JSX.Element} - The React element for the title.
23 | */
24 | customTitle: (item: any, index: number) => JSX.Element;
25 |
26 | /**
27 | * Function that returns a React element to display as Accordion body.
28 | * @function
29 | * @param {any} item - The data item for the Accordion.
30 | * @param {number} [index] - The index of the item in the data array.
31 | * @returns {JSX.Element} - The React element for the body.
32 | */
33 | customBody: (item: any, index: number) => JSX.Element;
34 |
35 | /**
36 | * An optional function that returns a React element to display as Accordion icon.
37 | * Default icon is keyboard-arrow-left.
38 | * @function
39 | * @param {number} [index] - The index of the item in the data array.
40 | * @returns {JSX.Element} - The React element for the icon.
41 | */
42 | customIcon?: (index: number) => JSX.Element;
43 |
44 | /**
45 | * An optional parameter to add custom container item style.
46 | * @type {ViewStyle}
47 | */
48 | containerItemStyle?: ViewStyle;
49 |
50 | /**
51 | * An optional parameter to control Accordion animation duration.
52 | * Default value is 300.
53 | * @type {number}
54 | */
55 | animationDuration?: number;
56 |
57 | /**
58 | * An optional parameter to support RTL layout.
59 | * Default value is false.
60 | * @type {boolean}
61 | */
62 | isRTL?: boolean;
63 |
64 | /**
65 | * Allow more than one section to be expanded.
66 | * Default value is false.
67 | * @type {boolean}
68 | */
69 | expandMultiple?: boolean;
70 |
71 | /**
72 | * An array of indices indicating which sections should be expanded by default.
73 | * @type {number[]}
74 | */
75 | defaultOpenIndices?: number[];
76 |
77 | /**
78 | * Additional props for configuring the Pressable component.
79 | * @type {AccordionPressableProps}
80 | */
81 | pressableProps?: AccordionPressableProps;
82 | }
83 |
--------------------------------------------------------------------------------
/src/models/AccordionPressable.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | GestureResponderEvent,
3 | Insets,
4 | MouseEvent,
5 | NativeSyntheticEvent,
6 | PressableAndroidRippleConfig,
7 | PressableStateCallbackType,
8 | StyleProp,
9 | TargetedEvent,
10 | ViewStyle,
11 | } from 'react-native';
12 | import * as React from 'react';
13 |
14 | /**
15 | * Props for configuring the behavior and styling of the Pressable component within the AccordionItem component.
16 | * @interface AccordionPressableProps
17 | */
18 | export interface AccordionPressableProps {
19 | /**
20 | * Called when the hover is activated to provide visual feedback.
21 | * @param {MouseEvent} event - The mouse event when hover is activated.
22 | */
23 | onHoverIn?: ((event: MouseEvent) => void) | null | undefined;
24 |
25 | /**
26 | * Called when the hover is deactivated to undo visual feedback.
27 | * @param {MouseEvent} event - The mouse event when hover is deactivated.
28 | */
29 | onHoverOut?: ((event: MouseEvent) => void) | null | undefined;
30 |
31 | /**
32 | * Called when a touch is engaged before `onPress`.
33 | * @param {GestureResponderEvent} event - The gesture responder event when touch is engaged.
34 | */
35 | onPressIn?: ((event: GestureResponderEvent) => void) | null | undefined;
36 |
37 | /**
38 | * Called when a touch is released before `onPress`.
39 | * @param {GestureResponderEvent} event - The gesture responder event when touch is released.
40 | */
41 | onPressOut?: ((event: GestureResponderEvent) => void) | null | undefined;
42 |
43 | /**
44 | * Called when a long-tap gesture is detected.
45 | * @param {GestureResponderEvent} event - The gesture responder event when long-tap is detected.
46 | */
47 | onLongPress?: ((event: GestureResponderEvent) => void) | null | undefined;
48 |
49 | /**
50 | * Called after the element loses focus.
51 | * @platform macos windows
52 | * @param {NativeSyntheticEvent} event - The native synthetic event.
53 | */
54 | onBlur?: ((event: NativeSyntheticEvent) => void) | null | undefined;
55 |
56 | /**
57 | * Called after the element is focused.
58 | * @platform macos windows
59 | * @param {NativeSyntheticEvent} event - The native synthetic event.
60 | */
61 | onFocus?: ((event: NativeSyntheticEvent) => void) | null | undefined;
62 |
63 | /**
64 | * Whether a press gesture can be interrupted by a parent gesture such as a scroll event. Defaults to true.
65 | * @type {boolean}
66 | */
67 | cancelable?: boolean | null | undefined;
68 |
69 | /**
70 | * Duration to wait after hover in before calling `onHoverIn`.
71 | * @platform macos windows
72 | * @type {number}
73 | */
74 | delayHoverIn?: number | null | undefined;
75 |
76 | /**
77 | * Duration to wait after hover out before calling `onHoverOut`.
78 | * @platform macos windows
79 | * @type {number}
80 | */
81 | delayHoverOut?: number | null | undefined;
82 |
83 | /**
84 | * Duration (in milliseconds) from `onPressIn` before `onLongPress` is called.
85 | * @type {number}
86 | */
87 | delayLongPress?: number | null | undefined;
88 |
89 | /**
90 | * Whether the press behavior is disabled.
91 | * @type {boolean}
92 | */
93 | disabled?: boolean | null | undefined;
94 |
95 | /**
96 | * Additional distance outside of this view in which a press is detected.
97 | * @type {Insets | number}
98 | */
99 | hitSlop?: Insets | number | null | undefined;
100 |
101 | /**
102 | * Additional distance outside of this view in which a touch is considered a press before `onPressOut` is triggered.
103 | * @type {Insets | number}
104 | */
105 | pressRetentionOffset?: Insets | number | null | undefined;
106 |
107 | /**
108 | * If true, doesn't play system sound on touch.
109 | * @type {boolean}
110 | */
111 | android_disableSound?: boolean | null | undefined;
112 |
113 | /**
114 | * Enables the Android ripple effect and configures its color.
115 | * @type {PressableAndroidRippleConfig}
116 | */
117 | android_ripple?: PressableAndroidRippleConfig | null | undefined;
118 |
119 | /**
120 | * Used only for documentation or testing (e.g. snapshot testing).
121 | * @type {boolean}
122 | */
123 | testOnly_pressed?: boolean | null | undefined;
124 |
125 | /**
126 | * Duration (in milliseconds) to wait after press down before calling onPressIn.
127 | * @type {number}
128 | */
129 | unstable_pressDelay?: number;
130 |
131 | /**
132 | * Either view styles or a function that receives a boolean reflecting whether
133 | * the component is currently pressed and returns view styles.
134 | * @type {StyleProp | ((state: PressableStateCallbackType) => StyleProp)}
135 | */
136 | style?: StyleProp | ((state: PressableStateCallbackType) => StyleProp) | undefined;
137 | }
138 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": true,
4 | "allowSyntheticDefaultImports": true,
5 | "esModuleInterop": true,
6 | "isolatedModules": true,
7 | "module": "commonjs",
8 | "declaration": true,
9 | "outDir": "./lib",
10 | "jsx": "react",
11 | "lib": [
12 | "es6"
13 | ],
14 | "moduleResolution": "node",
15 | "strict": true,
16 | "sourceMap": true,
17 | "skipLibCheck": true,
18 | "target": "esnext"
19 | },
20 | "include": ["src"],
21 | "exclude": ["node_modules", "**/__tests__/*"]
22 | }
23 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["tslint:recommended", "tslint-config-prettier"]
3 | }
4 |
--------------------------------------------------------------------------------