UNPKG

9.05 kBTypeScriptView Raw
1import * as React from 'react';
2import {
3 StyleSheet,
4 StyleProp,
5 View,
6 ViewStyle,
7 I18nManager,
8} from 'react-native';
9import color from 'color';
10import IconButton from '../IconButton';
11import Text from '../Typography/Text';
12import { withTheme, useTheme } from '../../core/theming';
13import MaterialCommunityIcon from '../MaterialCommunityIcon';
14import Menu from '../Menu/Menu';
15import Button from '../Button';
16
17type Props = React.ComponentPropsWithRef<typeof View> &
18 PaginationControlsProps &
19 PaginationDropdownProps & {
20 /**
21 * Label text to display which indicates current pagination.
22 */
23 label?: React.ReactNode;
24 /**
25 * AccessibilityLabel for `label`.
26 */
27 accessibilityLabel?: string;
28 /**
29 * Label text for select page dropdown to display.
30 */
31 selectPageDropdownLabel?: React.ReactNode;
32 /**
33 * AccessibilityLabel for `selectPageDropdownLabel`.
34 */
35 selectPageDropdownAccessibilityLabel?: string;
36 style?: StyleProp<ViewStyle>;
37 /**
38 * @optional
39 */
40 theme: ReactNativePaper.Theme;
41 };
42
43type PaginationDropdownProps = {
44 /**
45 * The current number of rows per page.
46 */
47 numberOfItemsPerPage?: number;
48 /**
49 * Options for a number of rows per page to choose from.
50 */
51 numberOfItemsPerPageList?: Array<number>;
52 /**
53 * The function to set the number of rows per page.
54 */
55 onItemsPerPageChange?: (numberOfItemsPerPage: number) => void;
56};
57
58type PaginationControlsProps = {
59 /**
60 * The currently visible page (starting with 0).
61 */
62 page: number;
63 /**
64 * The total number of pages.
65 */
66 numberOfPages: number;
67 /**
68 * Function to execute on page change.
69 */
70 onPageChange: (page: number) => void;
71 /**
72 * Whether to show fast forward and fast rewind buttons in pagination. False by default.
73 */
74 showFastPaginationControls?: boolean;
75};
76
77const PaginationControls = ({
78 page,
79 numberOfPages,
80 onPageChange,
81 showFastPaginationControls,
82}: PaginationControlsProps) => {
83 const { colors } = useTheme();
84 return (
85 <>
86 {showFastPaginationControls ? (
87 <IconButton
88 icon={({ size, color }) => (
89 <MaterialCommunityIcon
90 name="page-first"
91 color={color}
92 size={size}
93 direction={I18nManager.isRTL ? 'rtl' : 'ltr'}
94 />
95 )}
96 color={colors.text}
97 disabled={page === 0}
98 onPress={() => onPageChange(0)}
99 accessibilityLabel="page-first"
100 />
101 ) : null}
102 <IconButton
103 icon={({ size, color }) => (
104 <MaterialCommunityIcon
105 name="chevron-left"
106 color={color}
107 size={size}
108 direction={I18nManager.isRTL ? 'rtl' : 'ltr'}
109 />
110 )}
111 color={colors.text}
112 disabled={page === 0}
113 onPress={() => onPageChange(page - 1)}
114 accessibilityLabel="chevron-left"
115 />
116 <IconButton
117 icon={({ size, color }) => (
118 <MaterialCommunityIcon
119 name="chevron-right"
120 color={color}
121 size={size}
122 direction={I18nManager.isRTL ? 'rtl' : 'ltr'}
123 />
124 )}
125 color={colors.text}
126 disabled={numberOfPages === 0 || page === numberOfPages - 1}
127 onPress={() => onPageChange(page + 1)}
128 accessibilityLabel="chevron-right"
129 />
130 {showFastPaginationControls ? (
131 <IconButton
132 icon={({ size, color }) => (
133 <MaterialCommunityIcon
134 name="page-last"
135 color={color}
136 size={size}
137 direction={I18nManager.isRTL ? 'rtl' : 'ltr'}
138 />
139 )}
140 color={colors.text}
141 disabled={numberOfPages === 0 || page === numberOfPages - 1}
142 onPress={() => onPageChange(numberOfPages - 1)}
143 accessibilityLabel="page-last"
144 />
145 ) : null}
146 </>
147 );
148};
149
150const PaginationDropdown = ({
151 numberOfItemsPerPageList,
152 numberOfItemsPerPage,
153 onItemsPerPageChange,
154}: PaginationDropdownProps) => {
155 const { colors } = useTheme();
156 const [showSelect, toggleSelect] = React.useState<boolean>(false);
157
158 return (
159 <Menu
160 visible={showSelect}
161 onDismiss={() => toggleSelect(!showSelect)}
162 anchor={
163 <Button
164 mode="outlined"
165 onPress={() => toggleSelect(true)}
166 style={styles.button}
167 icon="menu-down"
168 contentStyle={styles.contentStyle}
169 >
170 {`${numberOfItemsPerPage}`}
171 </Button>
172 }
173 >
174 {numberOfItemsPerPageList?.map((option) => (
175 <Menu.Item
176 key={option}
177 titleStyle={
178 option === numberOfItemsPerPage && {
179 color: colors.primary,
180 }
181 }
182 onPress={() => {
183 onItemsPerPageChange?.(option);
184 toggleSelect(false);
185 }}
186 title={option}
187 />
188 ))}
189 </Menu>
190 );
191};
192
193/**
194 * A component to show pagination for data table.
195 *
196 * <div class="screenshots">
197 * <figure>
198 * <img class="medium" src="screenshots/data-table-pagination.png" />
199 * </figure>
200 * </div>
201 *
202 *
203 * ## Usage
204 * ```js
205 * import * as React from 'react';
206 * import { DataTable } from 'react-native-paper';
207 *
208 * const numberOfItemsPerPageList = [2, 3, 4];
209 *
210 * const items = [
211 * {
212 * key: 1,
213 * name: 'Page 1',
214 * },
215 * {
216 * key: 2,
217 * name: 'Page 2',
218 * },
219 * {
220 * key: 3,
221 * name: 'Page 3',
222 * },
223 * ];
224 *
225 * const MyComponent = () => {
226 * const [page, setPage] = React.useState(0);
227 * const [numberOfItemsPerPage, onItemsPerPageChange] = React.useState(numberOfItemsPerPageList[0]);
228 * const from = page * numberOfItemsPerPage;
229 * const to = Math.min((page + 1) * numberOfItemsPerPage, items.length);
230 *
231 * React.useEffect(() => {
232 * setPage(0);
233 * }, [numberOfItemsPerPage]);
234 *
235 * return (
236 * <DataTable>
237 * <DataTable.Pagination
238 * page={page}
239 * numberOfPages={Math.ceil(items.length / numberOfItemsPerPage)}
240 * onPageChange={page => setPage(page)}
241 * label={`${from + 1}-${to} of ${items.length}`}
242 * showFastPaginationControls
243 * numberOfItemsPerPageList={numberOfItemsPerPageList}
244 * numberOfItemsPerPage={numberOfItemsPerPage}
245 * onItemsPerPageChange={onItemsPerPageChange}
246 * selectPageDropdownLabel={'Rows per page'}
247 * />
248 * </DataTable>
249 * );
250 * };
251 *
252 * export default MyComponent;
253 * ```
254 */
255const DataTablePagination = ({
256 label,
257 accessibilityLabel,
258 page,
259 numberOfPages,
260 onPageChange,
261 style,
262 theme,
263 showFastPaginationControls = false,
264 numberOfItemsPerPageList,
265 numberOfItemsPerPage,
266 onItemsPerPageChange,
267 selectPageDropdownLabel,
268 selectPageDropdownAccessibilityLabel,
269 ...rest
270}: Props) => {
271 const labelColor = color(theme.colors.text).alpha(0.6).rgb().string();
272
273 return (
274 <View
275 {...rest}
276 style={[styles.container, style]}
277 accessibilityLabel="pagination-container"
278 >
279 {numberOfItemsPerPageList &&
280 numberOfItemsPerPage &&
281 onItemsPerPageChange && (
282 <View
283 accessibilityLabel="Options Select"
284 style={styles.optionsContainer}
285 >
286 <Text
287 style={[styles.label, { color: labelColor }]}
288 numberOfLines={3}
289 accessibilityLabel={
290 selectPageDropdownAccessibilityLabel ||
291 'selectPageDropdownLabel'
292 }
293 >
294 {selectPageDropdownLabel}
295 </Text>
296 <PaginationDropdown
297 numberOfItemsPerPageList={numberOfItemsPerPageList}
298 numberOfItemsPerPage={numberOfItemsPerPage}
299 onItemsPerPageChange={onItemsPerPageChange}
300 />
301 </View>
302 )}
303 <Text
304 style={[styles.label, { color: labelColor }]}
305 numberOfLines={3}
306 accessibilityLabel={accessibilityLabel || 'label'}
307 >
308 {label}
309 </Text>
310 <View style={styles.iconsContainer}>
311 <PaginationControls
312 showFastPaginationControls={showFastPaginationControls}
313 onPageChange={onPageChange}
314 page={page}
315 numberOfPages={numberOfPages}
316 />
317 </View>
318 </View>
319 );
320};
321
322DataTablePagination.displayName = 'DataTable.Pagination';
323
324const styles = StyleSheet.create({
325 container: {
326 justifyContent: 'flex-end',
327 flexDirection: 'row',
328 alignItems: 'center',
329 paddingLeft: 16,
330 flexWrap: 'wrap',
331 },
332 optionsContainer: {
333 flexDirection: 'row',
334 alignItems: 'center',
335 marginVertical: 6,
336 },
337 label: {
338 fontSize: 12,
339 marginRight: 16,
340 },
341 button: {
342 textAlign: 'center',
343 marginRight: 16,
344 },
345 iconsContainer: {
346 flexDirection: 'row',
347 },
348 contentStyle: {
349 flexDirection: 'row-reverse',
350 },
351});
352
353export default withTheme(DataTablePagination);
354
355// @component-docs ignore-next-line
356export { DataTablePagination };