PluginProbe
Code Snippets / 4.0.0-beta.1
Code Snippets v4.0.0-beta.1
4.0.0-beta.2 3.10.2 3.10.1 3.10.0 3.10.0-beta.2 3.10.0-beta.1 4.0.0-beta.1 3.9.6 trunk 2.10.0 2.10.1 2.12.0 2.12.1 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.14.1 2.14.2 2.14.3 2.14.4 2.14.5 2.14.6 3.0.0 All 65 releases
code-snippets / js / components / common / ListTable / TablePagination.tsx

TablePagination.tsx in Code Snippets 4.0.0-beta.1, at js/components/common/ListTable/TablePagination.tsx

297 lines 7.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import React, { useState } from 'react'
2 import classnames from 'classnames'
3 import { __, _n, _x, sprintf } from '@wordpress/i18n'
4 import { buildUrl, updateQueryParams } from '../../../utils/urls'
5 import { Button } from '../Button'
6 import type { ListTablePaginationProps } from './ListTable'
7 import type { ReactNode } from 'react'
8
9 interface NavigationButtonProps {
10 icon: ReactNode
11 newPage: number
12 className?: string
13 disabled?: boolean
14 helperText?: string
15 renderAsLinks?: boolean
16 setCurrentPage: (page: number) => void
17 }
18
19 const NavigationButton: React.FC<NavigationButtonProps> = ({
20 icon,
21 newPage,
22 disabled,
23 className,
24 helperText,
25 renderAsLinks,
26 setCurrentPage
27 }) =>
28 renderAsLinks
29 ? <>
30 <a
31 className={`${className} button`}
32 href={buildUrl(window.location.href, { paged: 1 === newPage ? undefined : newPage })}
33 onClick={event => {
34 event.preventDefault()
35 setCurrentPage(newPage)
36 }}
37 >
38 <span className="screen-reader-text">{helperText}</span>
39 <span aria-hidden>{icon}</span>
40 </a>{'\n'}
41 </>
42 : <Button className={className} onClick={() => setCurrentPage(newPage)} disabled={disabled}>
43 <span className="screen-reader-text">{helperText}</span>
44 <span aria-hidden>{icon}</span>
45 </Button>
46
47 interface NavigationButtonsProps {
48 currentPage: number
49 disabled?: boolean
50 renderAsLinks?: boolean
51 setCurrentPage: (page: number) => void
52 }
53
54 const BackwardNavigationButtons: React.FC<NavigationButtonsProps> = ({ currentPage, ...buttonProps }) =>
55 1 === currentPage
56 ? <>
57 <span className="tablenav-pages-navspan button disabled" aria-hidden="true">&laquo;</span>{'\n'}
58 <span className="tablenav-pages-navspan button disabled" aria-hidden="true">&lsaquo;</span>{'\n'}
59 </>
60 : <>
61 <NavigationButton
62 icon={<>&laquo;</>}
63 newPage={1}
64 className="first-page"
65 /* translators: Hidden accessibility text. */
66 helperText={__('First page', 'code-snippets')}
67 {...buttonProps}
68 />{'\n'}
69 <NavigationButton
70 icon={<>&lsaquo;</>}
71 newPage={Math.max(1, currentPage - 1)}
72 className="prev-page"
73 /* translators: Hidden accessibility text. */
74 helperText={__('Previous page', 'code-snippets')}
75 {...buttonProps}
76 />{'\n'}
77 </>
78
79 interface ForwardNavigationButtonsProps extends NavigationButtonsProps {
80 totalPages: number
81 }
82
83 const ForwardNavigationButtons: React.FC<ForwardNavigationButtonsProps> = ({ currentPage, totalPages, ...buttonProps }) =>
84 totalPages === currentPage
85 ? <>
86 <span className="tablenav-pages-navspan button disabled" aria-hidden="true">&rsaquo;</span>{'\n'}
87 <span className="tablenav-pages-navspan button disabled" aria-hidden="true">&raquo;</span>
88 </>
89 : <>
90 <NavigationButton
91 icon={<>&rsaquo;</>}
92 newPage={Math.min(totalPages, currentPage + 1)}
93 className="next-page"
94 /* translators: Hidden accessibility text. */
95 helperText={__('Next page', 'code-snippets')}
96 {...buttonProps}
97 />{'\n'}
98 <NavigationButton
99 icon={<>&raquo;</>}
100 newPage={totalPages}
101 className="last-page"
102 /* translators: Hidden accessibility text. */
103 helperText={__('Last page', 'code-snippets')}
104 {...buttonProps}
105 />{'\n'}
106 </>
107
108 interface PagingInputProps {
109 which: 'top' | 'bottom'
110 totalPages: number
111 disabled?: boolean
112 inputValue: number
113 setInputValue: (value: number) => void
114 confirmInputValue: VoidFunction
115 }
116
117 const PagingInput: React.FC<PagingInputProps> = ({ which, totalPages, disabled, inputValue, setInputValue, confirmInputValue }) =>
118 <input
119 className="current-page"
120 id={`current-page-selector-${which}`}
121 aria-label={__('Current Page', 'code-snippets')}
122 type="text"
123 name="paged"
124 value={inputValue}
125 size={totalPages.toString().length}
126 disabled={disabled}
127 aria-describedby="table-paging"
128 onBlur={confirmInputValue}
129 onChange={event => {
130 const value = Number(event.target.value)
131
132 if (value) {
133 setInputValue(value)
134 }
135 }}
136 />
137
138 interface CurrentPageProps extends PagingInputProps {
139 currentPage: number
140 }
141
142 const CurrentPage: React.FC<CurrentPageProps> = ({ which, totalPages, currentPage, ...inputProps }) =>
143 'bottom' === which
144 ? <>
145 {/* translators: Hidden accessibility text. */}
146 <span className="screen-reader-text">{__('Current Page', 'code-snippets')}</span>
147 <span className="paging-input">
148 <span className="tablenav-paging-text">
149 {/* translators: 1: Current page. */
150 sprintf(_x('%s of ', 'paging', 'code-snippets'), currentPage)}
151 <span className="total-pages">{totalPages}</span>
152 </span>
153 </span>
154 </>
155 : <span className="paging-input">
156 <PagingInput which={which} totalPages={totalPages} {...inputProps} />
157 <span className="tablenav-paging-text">
158 {/* translators: 1: Current page. */
159 _x(' of ', 'paging', 'code-snippets')}
160 <span className="total-pages">{totalPages}</span>
161 </span>
162 </span>
163
164 interface PaginationControlsProps {
165 which: 'top' | 'bottom'
166 inputValue: number
167 totalPages: number
168 totalItems: number
169 currentPage: number
170 disabled?: boolean
171 useQueryVars?: boolean
172 setInputValue: (value: number) => void
173 setCurrentPage: (page: number) => void
174 }
175
176 type NavigationLinksProps = Omit<PaginationControlsProps, 'totalItems'>
177
178 const NavigationLinks: React.FC<NavigationLinksProps> = ({
179 which,
180 disabled,
181 totalPages,
182 inputValue,
183 currentPage,
184 useQueryVars,
185 setCurrentPage,
186 setInputValue
187 }) => (
188 <span className="pagination-links">
189 <BackwardNavigationButtons
190 disabled={disabled}
191 currentPage={currentPage}
192 renderAsLinks={useQueryVars}
193 setCurrentPage={setCurrentPage}
194 />
195 <CurrentPage
196 which={which}
197 disabled={disabled}
198 totalPages={totalPages}
199 currentPage={currentPage}
200 inputValue={inputValue}
201 setInputValue={setInputValue}
202 confirmInputValue={() => setCurrentPage(inputValue)}
203 />{'\n'}
204 <ForwardNavigationButtons
205 disabled={disabled}
206 totalPages={totalPages}
207 currentPage={currentPage}
208 renderAsLinks={useQueryVars}
209 setCurrentPage={setCurrentPage}
210 />
211 </span>
212 )
213
214 const PaginationControls: React.FC<PaginationControlsProps> = ({
215 which,
216 disabled,
217 totalPages,
218 totalItems,
219 inputValue,
220 currentPage,
221 useQueryVars,
222 setCurrentPage,
223 setInputValue
224 }) => {
225 const navLabel = 'top' === which
226 ? __('Pagination, before the table', 'code-snippets')
227 : __('Pagination, after the table', 'code-snippets')
228
229 return (
230 <nav aria-label={navLabel}>
231 <form
232 className={classnames('tablenav-pages', {
233 'one-page': totalPages && 1 === totalPages,
234 'no-pages': !totalPages
235 })}
236 onSubmit={event => {
237 event.preventDefault()
238 setCurrentPage(inputValue)
239 }}
240 >
241 <span className="displaying-num">
242 {
243 sprintf(
244 // translators: %s: Number of items.
245 _n('%s item', '%s items', totalItems),
246 totalItems
247 )
248 }
249 </span>{'\n'}
250 <NavigationLinks
251 {...{ which, disabled, totalPages, inputValue, currentPage, useQueryVars, setCurrentPage, setInputValue }}
252 />
253 </form>
254 </nav>
255 )
256 }
257
258 export interface TablePaginationProps extends Omit<ListTablePaginationProps, 'totalPages'>,
259 Required<Pick<ListTablePaginationProps, 'totalPages'>> {
260 which: 'top' | 'bottom'
261 totalItems: number
262 disabled?: boolean
263 currentPage: number
264 setCurrentPage: (page: number) => void
265 }
266
267 export const TablePagination: React.FC<TablePaginationProps> = ({
268 which,
269 disabled,
270 totalItems,
271 currentPage,
272 totalPages,
273 useQueryVars,
274 setCurrentPage
275 }) => {
276 const [inputValue, setInputValue] = useState(currentPage)
277
278 const setCurrentPageSafe = (page: number) => {
279 if (page) {
280 const validPage = Math.max(1, Math.min(page, totalPages))
281 setInputValue(validPage)
282 setCurrentPage(validPage)
283
284 if (useQueryVars) {
285 updateQueryParams({ paged: 1 === validPage ? undefined : validPage })
286 }
287 }
288 }
289
290 return (
291 <PaginationControls
292 {...{ which, inputValue, currentPage, totalItems, totalPages, disabled, setInputValue }}
293 setCurrentPage={setCurrentPageSafe}
294 />
295 )
296 }
297