@rcarls/rc-pagination 0.0.0-next-20261102181447
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +85 -0
- package/README.md +44 -0
- package/dist/base.css +2 -0
- package/dist/custom-elements.json +486 -0
- package/dist/range.js +25 -0
- package/dist/range.js.map +1 -0
- package/dist/rc-pagination-define.js +12 -0
- package/dist/rc-pagination-define.js.map +1 -0
- package/dist/rc-pagination-mkpZ0mCK.js +196 -0
- package/dist/rc-pagination-mkpZ0mCK.js.map +1 -0
- package/dist/rc-pagination.js +10 -0
- package/dist/rc-pagination.js.map +1 -0
- package/dist/types/packages/rc-pagination/src/define.d.ts +1 -0
- package/dist/types/packages/rc-pagination/src/index.d.ts +3 -0
- package/dist/types/packages/rc-pagination/src/paginationBaseStyles.d.ts +10 -0
- package/dist/types/packages/rc-pagination/src/range.d.ts +24 -0
- package/dist/types/packages/rc-pagination/src/rc-pagination.d.ts +121 -0
- package/package.json +72 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# @rcarls/rc-pagination
|
|
2
|
+
|
|
3
|
+
## 0.0.0-next-20261102181447
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 34fa00a: Adds `rc-pagination`, a pagination enhancer for a native `<nav>` holding page links or
|
|
8
|
+
buttons tagged with `data-rc-page`. It keeps `aria-current="page"` on the current page, names
|
|
9
|
+
the landmark and numbered controls, disables steps past either end, and fires a cancelable
|
|
10
|
+
`rc-pagination-change` that can hand link navigation to a client-side router. The DOM-free
|
|
11
|
+
`paginationRange()` helper, also at `@rcarls/rc-pagination/range`, builds the page list on a
|
|
12
|
+
server. The aggregate, the React wrappers, and all four themes cover it.
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- 4db22ea: Adds `rc-data-table`, a sortable-header enhancer for a native `<table>` that follows the
|
|
17
|
+
WAI-ARIA sortable table example. Authored `<button>` or link controls in
|
|
18
|
+
`<th data-rc-sort-key>` headers request a sort; the element reflects it as `aria-sort` on the
|
|
19
|
+
active header, draws a distinct indicator for each sort state, and fires a cancelable
|
|
20
|
+
`rc-data-table-sort` for the consumer to re-render the rows. It never sorts data itself. The
|
|
21
|
+
host becomes a focusable group named by the caption while the table overflows. The aggregate,
|
|
22
|
+
the React wrappers, and all four themes cover it.
|
|
23
|
+
|
|
24
|
+
`rc-pagination` now places its live region on the document body instead of inside the
|
|
25
|
+
element, so it never joins the consumer's markup.
|
|
26
|
+
|
|
27
|
+
- b9fd59d: `LiveAnnouncer` mounts its region before each announcement in the open dialog or
|
|
28
|
+
popover around its host, else the document's current body, and creates it on
|
|
29
|
+
first use. An announcement after Turbo replaces `document.body` around a
|
|
30
|
+
permanent element, or after a DOM morph removes the region, now reaches
|
|
31
|
+
assistive technology instead of a detached node. `rc-pagination` and
|
|
32
|
+
`rc-data-table` with `announce` also announce from inside an open modal dialog,
|
|
33
|
+
where the body was inert. `announcerRootFor()` is exported for custom roots.
|
|
34
|
+
|
|
35
|
+
Breaking changes:
|
|
36
|
+
|
|
37
|
+
- `LiveAnnouncer` takes the host element and an optional `{ root }` resolver
|
|
38
|
+
instead of a mount node. Replace `new LiveAnnouncer($root)` with
|
|
39
|
+
`new LiveAnnouncer($host, { root: () => $root })`, or drop `root` to use the
|
|
40
|
+
dialog-aware default.
|
|
41
|
+
|
|
42
|
+
- 760742b: Preserve authored disabled states when pagination controls leave an edge. Numbered targets beyond
|
|
43
|
+
the page total now request the last page, and stale links do not navigate to an out-of-range URL.
|
|
44
|
+
- Updated dependencies [e3dfa59]
|
|
45
|
+
- Updated dependencies [50d5610]
|
|
46
|
+
- Updated dependencies [9ee769c]
|
|
47
|
+
- Updated dependencies [1179f24]
|
|
48
|
+
- Updated dependencies [595fe37]
|
|
49
|
+
- Updated dependencies [38cd00c]
|
|
50
|
+
- Updated dependencies [5c006de]
|
|
51
|
+
- Updated dependencies [a6553ff]
|
|
52
|
+
- Updated dependencies [2205478]
|
|
53
|
+
- Updated dependencies [4341311]
|
|
54
|
+
- Updated dependencies [899bb5e]
|
|
55
|
+
- Updated dependencies [25fcfe0]
|
|
56
|
+
- Updated dependencies [51f6403]
|
|
57
|
+
- Updated dependencies [9caca6b]
|
|
58
|
+
- Updated dependencies [2a499c0]
|
|
59
|
+
- Updated dependencies [b9fd59d]
|
|
60
|
+
- Updated dependencies [b764a3c]
|
|
61
|
+
- Updated dependencies [6c3a2d1]
|
|
62
|
+
- Updated dependencies [54d9ead]
|
|
63
|
+
- Updated dependencies [3c0b1f6]
|
|
64
|
+
- Updated dependencies [9723b63]
|
|
65
|
+
- Updated dependencies [b9175e9]
|
|
66
|
+
- Updated dependencies [c8b762b]
|
|
67
|
+
- Updated dependencies [55e1e7f]
|
|
68
|
+
- Updated dependencies [f1ca82d]
|
|
69
|
+
- Updated dependencies [b87f27b]
|
|
70
|
+
- Updated dependencies [32ebead]
|
|
71
|
+
- Updated dependencies [bfefedd]
|
|
72
|
+
- Updated dependencies [c130173]
|
|
73
|
+
- Updated dependencies [6fef402]
|
|
74
|
+
- Updated dependencies [11680b6]
|
|
75
|
+
- Updated dependencies [223d36c]
|
|
76
|
+
- Updated dependencies [7b91a44]
|
|
77
|
+
- Updated dependencies [aa04ead]
|
|
78
|
+
- Updated dependencies [ac65b5b]
|
|
79
|
+
- Updated dependencies [429a0c1]
|
|
80
|
+
- Updated dependencies [ccdf1cf]
|
|
81
|
+
- Updated dependencies [afcfef8]
|
|
82
|
+
- Updated dependencies [3f21c58]
|
|
83
|
+
- Updated dependencies [e00df90]
|
|
84
|
+
- Updated dependencies [11ef1ad]
|
|
85
|
+
- @rcarls/rc-common@0.0.0-next-20261102181447
|
package/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# `@rcarls/rc-pagination`
|
|
2
|
+
|
|
3
|
+
Pagination enhancer for a native `<nav>` holding page links or buttons, with a server-safe
|
|
4
|
+
page range helper.
|
|
5
|
+
|
|
6
|
+
Docs: [https://richardcarls.github.io/rc-webcomponents/components/rc-pagination](https://richardcarls.github.io/rc-webcomponents/components/rc-pagination).
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
yarn add @rcarls/rc-pagination lit
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import '@rcarls/rc-pagination/define';
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```html
|
|
21
|
+
<rc-pagination total="3" page="2">
|
|
22
|
+
<nav>
|
|
23
|
+
<ul>
|
|
24
|
+
<li><a href="?page=1" data-rc-page="previous" rel="prev">Previous</a></li>
|
|
25
|
+
<li><a href="?page=1" data-rc-page="1">1</a></li>
|
|
26
|
+
<li><a href="?page=2" data-rc-page="2" aria-current="page">2</a></li>
|
|
27
|
+
<li><a href="?page=3" data-rc-page="3">3</a></li>
|
|
28
|
+
<li><a href="?page=3" data-rc-page="next" rel="next">Next</a></li>
|
|
29
|
+
</ul>
|
|
30
|
+
</nav>
|
|
31
|
+
</rc-pagination>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The element keeps `aria-current="page"` current, names the landmark and numbered controls,
|
|
35
|
+
disables steps past either end, and fires a cancelable `rc-pagination-change` on activation.
|
|
36
|
+
|
|
37
|
+
Build the list with `paginationRange()` from `@rcarls/rc-pagination/range`, which has no DOM
|
|
38
|
+
dependency and runs on a server:
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
import { paginationRange } from '@rcarls/rc-pagination/range';
|
|
42
|
+
|
|
43
|
+
paginationRange({ page: 6, total: 12 }); // [1, 'ellipsis', 5, 6, 7, 'ellipsis', 12]
|
|
44
|
+
```
|
package/dist/base.css
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/* rc-pagination light-DOM base styles. Link with data-rc-light-dom-base="rc-pagination" to skip the runtime copy. */
|
|
2
|
+
@layer rc-base{rc-pagination{display:block}rc-pagination>nav>:is(ul,ol){align-items:center;gap:var(--rc-pagination-gap,.25em);flex-wrap:wrap;margin:0;padding:0;list-style:none;display:flex}rc-pagination [data-rc-page]{min-inline-size:var(--rc-pagination-item-min-inline-size,auto);justify-content:center;align-items:center;display:inline-flex}rc-pagination a[data-rc-page][aria-disabled=true]{cursor:default}}
|
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0.0",
|
|
3
|
+
"readme": "",
|
|
4
|
+
"modules": [
|
|
5
|
+
{
|
|
6
|
+
"kind": "javascript-module",
|
|
7
|
+
"path": "src/define.ts",
|
|
8
|
+
"declarations": [],
|
|
9
|
+
"exports": [
|
|
10
|
+
{
|
|
11
|
+
"kind": "custom-element-definition",
|
|
12
|
+
"name": "rc-pagination",
|
|
13
|
+
"declaration": {
|
|
14
|
+
"name": "RCPagination",
|
|
15
|
+
"module": "/src/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"kind": "js",
|
|
20
|
+
"name": "*",
|
|
21
|
+
"declaration": {
|
|
22
|
+
"name": "*",
|
|
23
|
+
"module": "src/index.js"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"kind": "javascript-module",
|
|
30
|
+
"path": "src/index.ts",
|
|
31
|
+
"declarations": [],
|
|
32
|
+
"exports": [
|
|
33
|
+
{
|
|
34
|
+
"kind": "js",
|
|
35
|
+
"name": "*",
|
|
36
|
+
"declaration": {
|
|
37
|
+
"name": "*",
|
|
38
|
+
"module": "src/rc-pagination.js"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"kind": "js",
|
|
43
|
+
"name": "*",
|
|
44
|
+
"declaration": {
|
|
45
|
+
"name": "*",
|
|
46
|
+
"module": "src/paginationBaseStyles.js"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"kind": "js",
|
|
51
|
+
"name": "*",
|
|
52
|
+
"declaration": {
|
|
53
|
+
"name": "*",
|
|
54
|
+
"module": "src/range.js"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"kind": "javascript-module",
|
|
61
|
+
"path": "src/paginationBaseStyles.ts",
|
|
62
|
+
"declarations": [
|
|
63
|
+
{
|
|
64
|
+
"kind": "variable",
|
|
65
|
+
"name": "PAGINATION_BASE_CSS",
|
|
66
|
+
"default": "cssText` @layer rc-base { rc-pagination { display: block; } rc-pagination > nav > :is(ul, ol) { display: flex; flex-wrap: wrap; align-items: center; gap: var(--rc-pagination-gap, 0.25em); margin: 0; padding: 0; list-style: none; } rc-pagination [data-rc-page] { display: inline-flex; align-items: center; justify-content: center; min-inline-size: var(--rc-pagination-item-min-inline-size, auto); } rc-pagination a[data-rc-page][aria-disabled='true'] { cursor: default; } } `",
|
|
67
|
+
"description": "Light-DOM base styles for the pagination list.\n\nThe consumer's `<nav>`, list, and controls stay in light DOM. These rules lay\nthe list out as a wrapping inline row and give each control a minimum size;\nthemes supply the shape, color, and state layers."
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"kind": "variable",
|
|
71
|
+
"name": "ensurePaginationBaseStyles",
|
|
72
|
+
"type": {
|
|
73
|
+
"text": "(root: Document | ShadowRoot) => void"
|
|
74
|
+
},
|
|
75
|
+
"description": "Installs the pagination list styles once per containing root."
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
"exports": [
|
|
79
|
+
{
|
|
80
|
+
"kind": "js",
|
|
81
|
+
"name": "PAGINATION_BASE_CSS",
|
|
82
|
+
"declaration": {
|
|
83
|
+
"name": "PAGINATION_BASE_CSS",
|
|
84
|
+
"module": "src/paginationBaseStyles.ts"
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"kind": "js",
|
|
89
|
+
"name": "ensurePaginationBaseStyles",
|
|
90
|
+
"declaration": {
|
|
91
|
+
"name": "ensurePaginationBaseStyles",
|
|
92
|
+
"module": "src/paginationBaseStyles.ts"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"kind": "javascript-module",
|
|
99
|
+
"path": "src/range.ts",
|
|
100
|
+
"declarations": [
|
|
101
|
+
{
|
|
102
|
+
"kind": "function",
|
|
103
|
+
"name": "paginationRange",
|
|
104
|
+
"return": {
|
|
105
|
+
"type": {
|
|
106
|
+
"text": "PaginationItem[]"
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"parameters": [
|
|
110
|
+
{
|
|
111
|
+
"name": "{\n page,\n total,\n siblings = 1,\n boundaries = 1,\n}",
|
|
112
|
+
"type": {
|
|
113
|
+
"text": "PaginationRangeOptions"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
],
|
|
117
|
+
"description": "The page numbers to render for a pagination list, with `'ellipsis'` where a\nrun of pages is hidden. A gap of a single page shows that page instead, so\nan ellipsis always stands for at least two pages.\n\nPure and DOM-free: import it from `@rcarls/rc-pagination/range` to build the\nmarkup on a server without loading the element."
|
|
118
|
+
}
|
|
119
|
+
],
|
|
120
|
+
"exports": [
|
|
121
|
+
{
|
|
122
|
+
"kind": "js",
|
|
123
|
+
"name": "paginationRange",
|
|
124
|
+
"declaration": {
|
|
125
|
+
"name": "paginationRange",
|
|
126
|
+
"module": "src/range.ts"
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"kind": "javascript-module",
|
|
133
|
+
"path": "src/rc-pagination.ts",
|
|
134
|
+
"declarations": [
|
|
135
|
+
{
|
|
136
|
+
"kind": "variable",
|
|
137
|
+
"name": "DEFAULT_PAGINATION_MESSAGES",
|
|
138
|
+
"type": {
|
|
139
|
+
"text": "Readonly<RCPaginationMessages>"
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"kind": "class",
|
|
144
|
+
"description": "Pagination enhancer for a native `<nav>` holding a list of page links or\nbuttons.\n\nThere is no WAI-ARIA pattern for pagination; the markup follows the GOV.UK\nand USWDS models. The consumer renders the list, usually from\n`paginationRange()`, and tags each control with `data-rc-page`: a page\nnumber, or `previous`, `next`, `first`, or `last`. The markup works before the\nelement upgrades. The element then keeps `aria-current=\"page\"` on the\ncurrent page, names the landmark and unlabeled controls, disables steps past\neither end, and reports each user request as `rc-pagination-change`.\n\nLinks navigate as usual unless a listener cancels `rc-pagination-change`,\nwhich also cancels the click, for client-side routing. Buttons only report.\nA numbered target above `total` reports the last page; its stale link does\nnot navigate to an out-of-range URL.\nIn uncontrolled use the element moves to the requested page itself; set\n`page` to control it.\n\nBuilt-in text follows the element's own `lang`, else `<html lang>`: per\nelement through `messages`, or for every instance through\n`registerMessages()` from `@rcarls/rc-common` under `rc-pagination`.",
|
|
145
|
+
"name": "RCPagination",
|
|
146
|
+
"cssProperties": [
|
|
147
|
+
{
|
|
148
|
+
"description": "Space between items.",
|
|
149
|
+
"name": "--rc-pagination-gap",
|
|
150
|
+
"default": "0.25em"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"description": "Minimum inline size of each item. Defers to the content size when unset.",
|
|
154
|
+
"name": "--rc-pagination-item-min-inline-size"
|
|
155
|
+
}
|
|
156
|
+
],
|
|
157
|
+
"members": [
|
|
158
|
+
{
|
|
159
|
+
"kind": "field",
|
|
160
|
+
"name": "total",
|
|
161
|
+
"type": {
|
|
162
|
+
"text": "number"
|
|
163
|
+
},
|
|
164
|
+
"default": "1",
|
|
165
|
+
"description": "Number of pages."
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"kind": "field",
|
|
169
|
+
"name": "announce",
|
|
170
|
+
"type": {
|
|
171
|
+
"text": "boolean"
|
|
172
|
+
},
|
|
173
|
+
"default": "false",
|
|
174
|
+
"description": "Announces each user change through a polite live region."
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"kind": "field",
|
|
178
|
+
"name": "messages",
|
|
179
|
+
"type": {
|
|
180
|
+
"text": "Partial<RCPaginationMessages> | undefined"
|
|
181
|
+
},
|
|
182
|
+
"description": "Built-in text overrides; unset keys fall back to registered text, then English."
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"kind": "field",
|
|
186
|
+
"name": "_page",
|
|
187
|
+
"type": {
|
|
188
|
+
"text": "number | undefined"
|
|
189
|
+
},
|
|
190
|
+
"privacy": "private"
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"kind": "field",
|
|
194
|
+
"name": "_defaultPage",
|
|
195
|
+
"type": {
|
|
196
|
+
"text": "number"
|
|
197
|
+
},
|
|
198
|
+
"privacy": "private",
|
|
199
|
+
"default": "1"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"kind": "field",
|
|
203
|
+
"name": "_uncontrolledPage",
|
|
204
|
+
"type": {
|
|
205
|
+
"text": "number | undefined"
|
|
206
|
+
},
|
|
207
|
+
"privacy": "private"
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"kind": "field",
|
|
211
|
+
"name": "_pageInitialized",
|
|
212
|
+
"type": {
|
|
213
|
+
"text": "boolean"
|
|
214
|
+
},
|
|
215
|
+
"privacy": "private",
|
|
216
|
+
"default": "false"
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
"kind": "field",
|
|
220
|
+
"name": "_messages",
|
|
221
|
+
"privacy": "private",
|
|
222
|
+
"readonly": true,
|
|
223
|
+
"default": "new MessagesController( this, 'rc-pagination', DEFAULT_PAGINATION_MESSAGES, { overrides: () => this.messages }, )"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"kind": "field",
|
|
227
|
+
"name": "_observer",
|
|
228
|
+
"type": {
|
|
229
|
+
"text": "MutationObserver | undefined"
|
|
230
|
+
},
|
|
231
|
+
"privacy": "private"
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
"kind": "field",
|
|
235
|
+
"name": "_announcer",
|
|
236
|
+
"type": {
|
|
237
|
+
"text": "LiveAnnouncer | undefined"
|
|
238
|
+
},
|
|
239
|
+
"privacy": "private"
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"kind": "field",
|
|
243
|
+
"name": "_writtenLabel",
|
|
244
|
+
"type": {
|
|
245
|
+
"text": "string | null"
|
|
246
|
+
},
|
|
247
|
+
"privacy": "private",
|
|
248
|
+
"default": "null"
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
"kind": "field",
|
|
252
|
+
"name": "_writtenNames",
|
|
253
|
+
"privacy": "private",
|
|
254
|
+
"readonly": true,
|
|
255
|
+
"default": "new WeakMap<Element, string | null>()"
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"kind": "field",
|
|
259
|
+
"name": "_$managedCurrent",
|
|
260
|
+
"privacy": "private",
|
|
261
|
+
"readonly": true,
|
|
262
|
+
"default": "new Set<Element>()"
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
"kind": "field",
|
|
266
|
+
"name": "_$managedDisabled",
|
|
267
|
+
"privacy": "private",
|
|
268
|
+
"readonly": true,
|
|
269
|
+
"default": "new Set<Element>()"
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
"kind": "field",
|
|
273
|
+
"name": "_disabledBeforeEdge",
|
|
274
|
+
"privacy": "private",
|
|
275
|
+
"readonly": true,
|
|
276
|
+
"default": "new Map<Element, string | null>()"
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"kind": "field",
|
|
280
|
+
"name": "page",
|
|
281
|
+
"type": {
|
|
282
|
+
"text": "number"
|
|
283
|
+
},
|
|
284
|
+
"description": "Current page, 1-based and clamped to `[1, total]`. Host writes are silent."
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
"kind": "field",
|
|
288
|
+
"name": "defaultPage",
|
|
289
|
+
"type": {
|
|
290
|
+
"text": "number"
|
|
291
|
+
},
|
|
292
|
+
"description": "Initial page for uncontrolled use."
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
"kind": "method",
|
|
296
|
+
"name": "createRenderRoot",
|
|
297
|
+
"privacy": "protected",
|
|
298
|
+
"return": {
|
|
299
|
+
"type": {
|
|
300
|
+
"text": "HTMLElement"
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
"description": "Renders nothing: the consumer's `<nav>` stays the element's only content."
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
"kind": "method",
|
|
307
|
+
"name": "firstUpdated",
|
|
308
|
+
"privacy": "protected",
|
|
309
|
+
"return": {
|
|
310
|
+
"type": {
|
|
311
|
+
"text": "void"
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
"kind": "method",
|
|
317
|
+
"name": "updated",
|
|
318
|
+
"privacy": "protected",
|
|
319
|
+
"return": {
|
|
320
|
+
"type": {
|
|
321
|
+
"text": "void"
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
"kind": "method",
|
|
327
|
+
"name": "_clamp",
|
|
328
|
+
"privacy": "private",
|
|
329
|
+
"return": {
|
|
330
|
+
"type": {
|
|
331
|
+
"text": "number"
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
"parameters": [
|
|
335
|
+
{
|
|
336
|
+
"name": "page",
|
|
337
|
+
"type": {
|
|
338
|
+
"text": "number"
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
]
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
"kind": "method",
|
|
345
|
+
"name": "_target",
|
|
346
|
+
"privacy": "private",
|
|
347
|
+
"return": {
|
|
348
|
+
"type": {
|
|
349
|
+
"text": "PageTarget | undefined"
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
"parameters": [
|
|
353
|
+
{
|
|
354
|
+
"name": "$item",
|
|
355
|
+
"type": {
|
|
356
|
+
"text": "Element"
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
]
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
"kind": "method",
|
|
363
|
+
"name": "_resolve",
|
|
364
|
+
"privacy": "private",
|
|
365
|
+
"return": {
|
|
366
|
+
"type": {
|
|
367
|
+
"text": "number"
|
|
368
|
+
}
|
|
369
|
+
},
|
|
370
|
+
"parameters": [
|
|
371
|
+
{
|
|
372
|
+
"name": "target",
|
|
373
|
+
"type": {
|
|
374
|
+
"text": "PageTarget"
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
]
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
"kind": "method",
|
|
381
|
+
"name": "_sync",
|
|
382
|
+
"privacy": "private",
|
|
383
|
+
"return": {
|
|
384
|
+
"type": {
|
|
385
|
+
"text": "void"
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
"kind": "method",
|
|
391
|
+
"name": "_syncName",
|
|
392
|
+
"privacy": "private",
|
|
393
|
+
"return": {
|
|
394
|
+
"type": {
|
|
395
|
+
"text": "void"
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
"parameters": [
|
|
399
|
+
{
|
|
400
|
+
"name": "$item",
|
|
401
|
+
"type": {
|
|
402
|
+
"text": "Element"
|
|
403
|
+
}
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
"name": "name",
|
|
407
|
+
"type": {
|
|
408
|
+
"text": "string"
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
"name": "numbered",
|
|
413
|
+
"type": {
|
|
414
|
+
"text": "boolean"
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
],
|
|
418
|
+
"description": "Gives a control its default name unless the author named it. Numbered\ncontrols always get one (\"Page 3\" contains the visible \"3\"); steps only\nwhen they have no visible text, such as an icon-only button."
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
"kind": "field",
|
|
422
|
+
"name": "_onClick",
|
|
423
|
+
"privacy": "private"
|
|
424
|
+
}
|
|
425
|
+
],
|
|
426
|
+
"events": [
|
|
427
|
+
{
|
|
428
|
+
"description": "Fired when the user activates a page control. Cancelable; canceling it also cancels the click, so a link does not navigate.",
|
|
429
|
+
"name": "rc-pagination-change"
|
|
430
|
+
}
|
|
431
|
+
],
|
|
432
|
+
"attributes": [
|
|
433
|
+
{
|
|
434
|
+
"description": "Controlled current page, 1-based. Host writes are silent.",
|
|
435
|
+
"name": "page"
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
"description": "Initial page for uncontrolled use. Defaults to 1.",
|
|
439
|
+
"name": "default-page"
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
"description": "Number of pages.",
|
|
443
|
+
"name": "total"
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
"description": "Announces the new page through a polite live region after each user change.",
|
|
447
|
+
"name": "announce"
|
|
448
|
+
}
|
|
449
|
+
],
|
|
450
|
+
"superclass": {
|
|
451
|
+
"name": "ReactiveElement",
|
|
452
|
+
"package": "lit"
|
|
453
|
+
},
|
|
454
|
+
"tagName": "rc-pagination",
|
|
455
|
+
"customElement": true
|
|
456
|
+
}
|
|
457
|
+
],
|
|
458
|
+
"exports": [
|
|
459
|
+
{
|
|
460
|
+
"kind": "js",
|
|
461
|
+
"name": "DEFAULT_PAGINATION_MESSAGES",
|
|
462
|
+
"declaration": {
|
|
463
|
+
"name": "DEFAULT_PAGINATION_MESSAGES",
|
|
464
|
+
"module": "src/rc-pagination.ts"
|
|
465
|
+
}
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
"kind": "js",
|
|
469
|
+
"name": "RCPagination",
|
|
470
|
+
"declaration": {
|
|
471
|
+
"name": "RCPagination",
|
|
472
|
+
"module": "src/rc-pagination.ts"
|
|
473
|
+
}
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
"kind": "js",
|
|
477
|
+
"name": "default",
|
|
478
|
+
"declaration": {
|
|
479
|
+
"name": "RCPagination",
|
|
480
|
+
"module": "src/rc-pagination.ts"
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
]
|
|
484
|
+
}
|
|
485
|
+
]
|
|
486
|
+
}
|
package/dist/range.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
function p({
|
|
2
|
+
page: u,
|
|
3
|
+
total: l,
|
|
4
|
+
siblings: i = 1,
|
|
5
|
+
boundaries: r = 1
|
|
6
|
+
}) {
|
|
7
|
+
const n = Math.max(0, Math.floor(l));
|
|
8
|
+
if (n === 0)
|
|
9
|
+
return [];
|
|
10
|
+
const h = Math.min(Math.max(1, Math.floor(u)), n), c = /* @__PURE__ */ new Set(), s = (a, o) => {
|
|
11
|
+
for (let t = Math.max(1, a); t <= Math.min(n, o); t += 1)
|
|
12
|
+
c.add(t);
|
|
13
|
+
};
|
|
14
|
+
s(1, r), s(n - r + 1, n), s(h - i, h + i);
|
|
15
|
+
const f = [...c].sort((a, o) => a - o), e = [];
|
|
16
|
+
for (const [a, o] of f.entries()) {
|
|
17
|
+
const t = f[a - 1];
|
|
18
|
+
t !== void 0 && o - t === 2 ? e.push(t + 1) : t !== void 0 && o - t > 2 && e.push("ellipsis"), e.push(o);
|
|
19
|
+
}
|
|
20
|
+
return e;
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
p as paginationRange
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=range.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"range.js","sources":["../src/range.ts"],"sourcesContent":["/** One slot in a pagination list: a page number or a gap of hidden pages. */\nexport type PaginationItem = number | 'ellipsis';\n\nexport interface PaginationRangeOptions {\n /** The current page, 1-based. Clamped to `[1, total]`. */\n page: number;\n /** The number of pages. */\n total: number;\n /** Pages shown on each side of the current page. Defaults to 1. */\n siblings?: number;\n /** Pages always shown at each end. Defaults to 1. */\n boundaries?: number;\n}\n\n/**\n * The page numbers to render for a pagination list, with `'ellipsis'` where a\n * run of pages is hidden. A gap of a single page shows that page instead, so\n * an ellipsis always stands for at least two pages.\n *\n * Pure and DOM-free: import it from `@rcarls/rc-pagination/range` to build the\n * markup on a server without loading the element.\n *\n * @example\n * paginationRange({ page: 6, total: 12 }); // [1, 'ellipsis', 5, 6, 7, 'ellipsis', 12]\n */\nexport function paginationRange({\n page,\n total,\n siblings = 1,\n boundaries = 1,\n}: PaginationRangeOptions): PaginationItem[] {\n const last = Math.max(0, Math.floor(total));\n\n if (last === 0) {\n return [];\n }\n\n const current = Math.min(Math.max(1, Math.floor(page)), last);\n const shown = new Set<number>();\n\n const add = (from: number, to: number) => {\n for (let value = Math.max(1, from); value <= Math.min(last, to); value += 1) {\n shown.add(value);\n }\n };\n\n add(1, boundaries);\n add(last - boundaries + 1, last);\n add(current - siblings, current + siblings);\n\n const pages = [...shown].sort((a, b) => a - b);\n const items: PaginationItem[] = [];\n\n for (const [index, value] of pages.entries()) {\n const previous = pages[index - 1];\n\n if (previous !== undefined && value - previous === 2) {\n items.push(previous + 1);\n } else if (previous !== undefined && value - previous > 2) {\n items.push('ellipsis');\n }\n\n items.push(value);\n }\n\n return items;\n}\n"],"names":["paginationRange","page","total","siblings","boundaries","last","current","shown","add","from","to","value","pages","b","items","index","previous"],"mappings":"AAyBO,SAASA,EAAgB;AAAA,EAC9B,MAAAC;AAAA,EACA,OAAAC;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,YAAAC,IAAa;AACf,GAA6C;AAC3C,QAAMC,IAAO,KAAK,IAAI,GAAG,KAAK,MAAMH,CAAK,CAAC;AAE1C,MAAIG,MAAS;AACX,WAAO,CAAA;AAGT,QAAMC,IAAU,KAAK,IAAI,KAAK,IAAI,GAAG,KAAK,MAAML,CAAI,CAAC,GAAGI,CAAI,GACtDE,wBAAY,IAAA,GAEZC,IAAM,CAACC,GAAcC,MAAe;AACxC,aAASC,IAAQ,KAAK,IAAI,GAAGF,CAAI,GAAGE,KAAS,KAAK,IAAIN,GAAMK,CAAE,GAAGC,KAAS;AACxE,MAAAJ,EAAM,IAAII,CAAK;AAAA,EAEnB;AAEA,EAAAH,EAAI,GAAGJ,CAAU,GACjBI,EAAIH,IAAOD,IAAa,GAAGC,CAAI,GAC/BG,EAAIF,IAAUH,GAAUG,IAAUH,CAAQ;AAE1C,QAAMS,IAAQ,CAAC,GAAGL,CAAK,EAAE,KAAK,CAAC,GAAGM,MAAM,IAAIA,CAAC,GACvCC,IAA0B,CAAA;AAEhC,aAAW,CAACC,GAAOJ,CAAK,KAAKC,EAAM,WAAW;AAC5C,UAAMI,IAAWJ,EAAMG,IAAQ,CAAC;AAEhC,IAAIC,MAAa,UAAaL,IAAQK,MAAa,IACjDF,EAAM,KAAKE,IAAW,CAAC,IACdA,MAAa,UAAaL,IAAQK,IAAW,KACtDF,EAAM,KAAK,UAAU,GAGvBA,EAAM,KAAKH,CAAK;AAAA,EAClB;AAEA,SAAOG;AACT;"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { R as a } from "./rc-pagination-mkpZ0mCK.js";
|
|
2
|
+
import { D as o, P as i, e as s } from "./rc-pagination-mkpZ0mCK.js";
|
|
3
|
+
import { paginationRange as m } from "./range.js";
|
|
4
|
+
customElements.get("rc-pagination") || customElements.define("rc-pagination", a);
|
|
5
|
+
export {
|
|
6
|
+
o as DEFAULT_PAGINATION_MESSAGES,
|
|
7
|
+
i as PAGINATION_BASE_CSS,
|
|
8
|
+
a as RCPagination,
|
|
9
|
+
s as ensurePaginationBaseStyles,
|
|
10
|
+
m as paginationRange
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=rc-pagination-define.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-pagination-define.js","sources":["../src/define.ts"],"sourcesContent":["import { RCPagination } from './index.js';\n\nif (!customElements.get('rc-pagination')) {\n customElements.define('rc-pagination', RCPagination);\n}\n\nexport * from './index.js';\n"],"names":["RCPagination"],"mappings":";;;AAEK,eAAe,IAAI,eAAe,KACrC,eAAe,OAAO,iBAAiBA,CAAY;"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { ReactiveElement as v } from "lit";
|
|
2
|
+
import { property as d } from "lit/decorators.js";
|
|
3
|
+
import { defineLightDomBaseStyles as y, cssText as P, MessagesController as E, LiveAnnouncer as w, syncDefaultAttribute as f, numberFormat as A } from "@rcarls/rc-common";
|
|
4
|
+
const $ = P`@layer rc-base{rc-pagination{display:block}rc-pagination>nav>:is(ul,ol){align-items:center;gap:var(--rc-pagination-gap,.25em);flex-wrap:wrap;margin:0;padding:0;list-style:none;display:flex}rc-pagination [data-rc-page]{min-inline-size:var(--rc-pagination-item-min-inline-size,auto);justify-content:center;align-items:center;display:inline-flex}rc-pagination a[data-rc-page][aria-disabled=true]{cursor:default}}`, C = y("rc-pagination", $);
|
|
5
|
+
var N = Object.defineProperty, S = Object.getOwnPropertyDescriptor, h = (o, e, t, r) => {
|
|
6
|
+
for (var i = r > 1 ? void 0 : r ? S(e, t) : e, l = o.length - 1, n; l >= 0; l--)
|
|
7
|
+
(n = o[l]) && (i = (r ? n(e, t, i) : n(i)) || i);
|
|
8
|
+
return r && i && N(e, t, i), i;
|
|
9
|
+
};
|
|
10
|
+
const _ = ":scope > nav", b = "[data-rc-page]", p = (o, e) => A(e, { useGrouping: !1 }).format(o), D = Object.freeze({
|
|
11
|
+
label: "Pagination",
|
|
12
|
+
page: (o, e, t) => `Page ${p(o, t)}`,
|
|
13
|
+
previous: "Previous page",
|
|
14
|
+
next: "Next page",
|
|
15
|
+
first: "First page",
|
|
16
|
+
last: "Last page",
|
|
17
|
+
status: (o, e, t) => `Page ${p(o, t)} of ${p(e, t)}`
|
|
18
|
+
});
|
|
19
|
+
class g extends v {
|
|
20
|
+
constructor() {
|
|
21
|
+
super(...arguments), this.total = 1, this.announce = !1, this._defaultPage = 1, this._pageInitialized = !1, this._messages = new E(
|
|
22
|
+
this,
|
|
23
|
+
"rc-pagination",
|
|
24
|
+
D,
|
|
25
|
+
{ overrides: () => this.messages }
|
|
26
|
+
), this._writtenLabel = null, this._writtenNames = /* @__PURE__ */ new WeakMap(), this._$managedCurrent = /* @__PURE__ */ new Set(), this._$managedDisabled = /* @__PURE__ */ new Set(), this._disabledBeforeEdge = /* @__PURE__ */ new Map(), this._onClick = (e) => {
|
|
27
|
+
const t = e.target?.closest?.(b), r = this.querySelector(_);
|
|
28
|
+
if (!t || !r?.contains(t))
|
|
29
|
+
return;
|
|
30
|
+
const i = this._target(t);
|
|
31
|
+
if (i === void 0)
|
|
32
|
+
return;
|
|
33
|
+
if (this._$managedDisabled.has(t)) {
|
|
34
|
+
e.preventDefault();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const l = this.page, n = this._resolve(i);
|
|
38
|
+
if (typeof i == "number" && i !== n && e.preventDefault(), n === l)
|
|
39
|
+
return;
|
|
40
|
+
const c = new CustomEvent("rc-pagination-change", {
|
|
41
|
+
bubbles: !0,
|
|
42
|
+
composed: !0,
|
|
43
|
+
cancelable: !0,
|
|
44
|
+
detail: { page: n, previousPage: l }
|
|
45
|
+
});
|
|
46
|
+
if (!this.dispatchEvent(c)) {
|
|
47
|
+
e.preventDefault();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
this._page === void 0 && (this._uncontrolledPage = n, this.requestUpdate("page", l)), this.announce && (this._announcer ??= new w(this), this._announcer.announce(
|
|
51
|
+
this._messages.value.status(n, this._clamp(this.total), this._messages.locale)
|
|
52
|
+
));
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
get page() {
|
|
56
|
+
return this._clamp(this._page ?? this._uncontrolledPage ?? this._defaultPage);
|
|
57
|
+
}
|
|
58
|
+
set page(e) {
|
|
59
|
+
const t = this.page;
|
|
60
|
+
this._page = e, this._pageInitialized = !0, this.requestUpdate("page", t);
|
|
61
|
+
}
|
|
62
|
+
get defaultPage() {
|
|
63
|
+
return this._defaultPage;
|
|
64
|
+
}
|
|
65
|
+
set defaultPage(e) {
|
|
66
|
+
const t = this._defaultPage;
|
|
67
|
+
this._defaultPage = e, !this._pageInitialized && this._page === void 0 && this._uncontrolledPage === void 0 && this.requestUpdate("page", this.page), this.requestUpdate("defaultPage", t);
|
|
68
|
+
}
|
|
69
|
+
/** Renders nothing: the consumer's `<nav>` stays the element's only content. */
|
|
70
|
+
createRenderRoot() {
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
connectedCallback() {
|
|
74
|
+
super.connectedCallback(), C(this.getRootNode()), this._observer ??= new MutationObserver(() => this._sync()), this._observer.observe(this, {
|
|
75
|
+
childList: !0,
|
|
76
|
+
subtree: !0,
|
|
77
|
+
attributes: !0,
|
|
78
|
+
attributeFilter: ["data-rc-page", "aria-label", "aria-labelledby"]
|
|
79
|
+
}), this.addEventListener("click", this._onClick);
|
|
80
|
+
}
|
|
81
|
+
disconnectedCallback() {
|
|
82
|
+
super.disconnectedCallback(), this._observer?.disconnect(), this.removeEventListener("click", this._onClick), this._announcer?.dispose(), this._announcer = void 0;
|
|
83
|
+
}
|
|
84
|
+
firstUpdated() {
|
|
85
|
+
}
|
|
86
|
+
updated() {
|
|
87
|
+
this._sync();
|
|
88
|
+
}
|
|
89
|
+
_clamp(e) {
|
|
90
|
+
const t = Math.max(1, Math.floor(this.total) || 1), r = Number.isFinite(e) ? Math.floor(e) : 1;
|
|
91
|
+
return Math.min(Math.max(1, r), t);
|
|
92
|
+
}
|
|
93
|
+
_target(e) {
|
|
94
|
+
const t = e.getAttribute("data-rc-page")?.trim() ?? "";
|
|
95
|
+
if (t === "previous" || t === "next" || t === "first" || t === "last")
|
|
96
|
+
return t;
|
|
97
|
+
const r = Number(t);
|
|
98
|
+
return Number.isInteger(r) && r > 0 ? r : void 0;
|
|
99
|
+
}
|
|
100
|
+
_resolve(e) {
|
|
101
|
+
switch (e) {
|
|
102
|
+
case "previous":
|
|
103
|
+
return this._clamp(this.page - 1);
|
|
104
|
+
case "next":
|
|
105
|
+
return this._clamp(this.page + 1);
|
|
106
|
+
case "first":
|
|
107
|
+
return 1;
|
|
108
|
+
case "last":
|
|
109
|
+
return this._clamp(this.total);
|
|
110
|
+
default:
|
|
111
|
+
return this._clamp(e);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
_sync() {
|
|
115
|
+
const e = this.querySelector(_);
|
|
116
|
+
if (!e)
|
|
117
|
+
return;
|
|
118
|
+
const t = this._messages.value, r = this._messages.locale;
|
|
119
|
+
e.hasAttribute("aria-labelledby") ? this._writtenLabel = null : this._writtenLabel = f(
|
|
120
|
+
e,
|
|
121
|
+
"aria-label",
|
|
122
|
+
t.label,
|
|
123
|
+
this._writtenLabel
|
|
124
|
+
);
|
|
125
|
+
const i = this.page, l = this._clamp(this.total), n = /* @__PURE__ */ new Set(), c = /* @__PURE__ */ new Set();
|
|
126
|
+
for (const a of e.querySelectorAll(b)) {
|
|
127
|
+
const s = this._target(a);
|
|
128
|
+
s !== void 0 && (typeof s == "number" ? (s === i && n.add(a), this._syncName(a, t.page(s, l, r), !0)) : (((s === "previous" || s === "first") && i <= 1 || (s === "next" || s === "last") && i >= l) && c.add(a), this._syncName(a, t[s], !1)));
|
|
129
|
+
}
|
|
130
|
+
for (const a of this._$managedCurrent)
|
|
131
|
+
n.has(a) || a.removeAttribute("aria-current");
|
|
132
|
+
for (const a of n)
|
|
133
|
+
a.setAttribute("aria-current", "page");
|
|
134
|
+
this._$managedCurrent.clear(), n.forEach((a) => this._$managedCurrent.add(a));
|
|
135
|
+
for (const a of this._$managedDisabled)
|
|
136
|
+
if (!c.has(a)) {
|
|
137
|
+
const s = m(a);
|
|
138
|
+
if (this._disabledBeforeEdge.has(a) && s) {
|
|
139
|
+
const u = this._disabledBeforeEdge.get(a) ?? null;
|
|
140
|
+
a.getAttribute(s) === (s === "disabled" ? "" : "true") && (u === null ? a.removeAttribute(s) : a.setAttribute(s, u)), this._disabledBeforeEdge.delete(a);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
for (const a of c) {
|
|
144
|
+
const s = m(a);
|
|
145
|
+
if (s && (!this._$managedDisabled.has(a) || this._disabledBeforeEdge.has(a) && !a.hasAttribute(s))) {
|
|
146
|
+
const u = a.getAttribute(s);
|
|
147
|
+
u !== (s === "disabled" ? "" : "true") && (this._$managedDisabled.has(a) || this._disabledBeforeEdge.set(a, u), a.setAttribute(s, s === "disabled" ? "" : "true"));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
this._$managedDisabled.clear(), c.forEach((a) => this._$managedDisabled.add(a));
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Gives a control its default name unless the author named it. Numbered
|
|
154
|
+
* controls always get one ("Page 3" contains the visible "3"); steps only
|
|
155
|
+
* when they have no visible text, such as an icon-only button.
|
|
156
|
+
*/
|
|
157
|
+
_syncName(e, t, r) {
|
|
158
|
+
if (!r && e.textContent?.trim())
|
|
159
|
+
return;
|
|
160
|
+
const i = f(
|
|
161
|
+
e,
|
|
162
|
+
"aria-label",
|
|
163
|
+
t,
|
|
164
|
+
this._writtenNames.get(e) ?? null
|
|
165
|
+
);
|
|
166
|
+
this._writtenNames.set(e, i);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
h([
|
|
170
|
+
d({ type: Number })
|
|
171
|
+
], g.prototype, "total", 2);
|
|
172
|
+
h([
|
|
173
|
+
d({ type: Boolean })
|
|
174
|
+
], g.prototype, "announce", 2);
|
|
175
|
+
h([
|
|
176
|
+
d({ attribute: !1 })
|
|
177
|
+
], g.prototype, "messages", 2);
|
|
178
|
+
h([
|
|
179
|
+
d({ type: Number })
|
|
180
|
+
], g.prototype, "page", 1);
|
|
181
|
+
h([
|
|
182
|
+
d({ type: Number, attribute: "default-page" })
|
|
183
|
+
], g.prototype, "defaultPage", 1);
|
|
184
|
+
function m(o) {
|
|
185
|
+
if (o instanceof HTMLButtonElement)
|
|
186
|
+
return "disabled";
|
|
187
|
+
if (o instanceof HTMLAnchorElement)
|
|
188
|
+
return "aria-disabled";
|
|
189
|
+
}
|
|
190
|
+
export {
|
|
191
|
+
D,
|
|
192
|
+
$ as P,
|
|
193
|
+
g as R,
|
|
194
|
+
C as e
|
|
195
|
+
};
|
|
196
|
+
//# sourceMappingURL=rc-pagination-mkpZ0mCK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-pagination-mkpZ0mCK.js","sources":["../src/paginationBaseStyles.ts","../src/rc-pagination.ts"],"sourcesContent":["import { cssText, defineLightDomBaseStyles } from '@rcarls/rc-common';\n\n/**\n * Light-DOM base styles for the pagination list.\n *\n * The consumer's `<nav>`, list, and controls stay in light DOM. These rules lay\n * the list out as a wrapping inline row and give each control a minimum size;\n * themes supply the shape, color, and state layers.\n */\nexport const PAGINATION_BASE_CSS = cssText`\n@layer rc-base {\n rc-pagination {\n display: block;\n }\n\n rc-pagination > nav > :is(ul, ol) {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--rc-pagination-gap, 0.25em);\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n rc-pagination [data-rc-page] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-inline-size: var(--rc-pagination-item-min-inline-size, auto);\n }\n\n rc-pagination a[data-rc-page][aria-disabled='true'] {\n cursor: default;\n }\n}\n`;\n\n/** Installs the pagination list styles once per containing root. */\nexport const ensurePaginationBaseStyles: (root: Document | ShadowRoot) => void =\n defineLightDomBaseStyles('rc-pagination', PAGINATION_BASE_CSS);\n","import { ReactiveElement } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport {\n LiveAnnouncer,\n MessagesController,\n numberFormat,\n syncDefaultAttribute,\n} from '@rcarls/rc-common';\nimport { ensurePaginationBaseStyles } from './paginationBaseStyles.js';\n\nconst NAV_SELECTOR = ':scope > nav';\nconst ITEM_SELECTOR = '[data-rc-page]';\n\n/** A `data-rc-page` value: a page number, or a step relative to the current page. */\ntype PageTarget = number | 'previous' | 'next' | 'first' | 'last';\n\n/** Built-in text of `rc-pagination`. */\nexport interface RCPaginationMessages {\n /** Accessible name for the `<nav>` landmark when the author gives it none. */\n label: string;\n /** Accessible name of a numbered page link or button. */\n page: (page: number, total: number, locale?: string) => string;\n /** Name of a previous control that has no text of its own. */\n previous: string;\n /** Name of a next control that has no text of its own. */\n next: string;\n /** Name of a first-page control that has no text of its own. */\n first: string;\n /** Name of a last-page control that has no text of its own. */\n last: string;\n /** Announcement after a page change, when `announce` is set. */\n status: (page: number, total: number, locale?: string) => string;\n}\n\nconst formatPage = (value: number, locale?: string) =>\n numberFormat(locale, { useGrouping: false }).format(value);\n\nexport const DEFAULT_PAGINATION_MESSAGES: Readonly<RCPaginationMessages> = Object.freeze({\n label: 'Pagination',\n page: (page: number, _total: number, locale?: string) => `Page ${formatPage(page, locale)}`,\n previous: 'Previous page',\n next: 'Next page',\n first: 'First page',\n last: 'Last page',\n status: (page: number, total: number, locale?: string) =>\n `Page ${formatPage(page, locale)} of ${formatPage(total, locale)}`,\n});\n\ndeclare module '@rcarls/rc-common' {\n interface RcMessageCatalog {\n 'rc-pagination': RCPaginationMessages;\n }\n}\n\n/** Detail of `rc-pagination-change`. */\nexport interface RCPaginationChangeEvent {\n /** The page the user asked for. */\n page: number;\n /** The page that was current when the user asked. */\n previousPage: number;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-pagination': RCPagination;\n }\n\n interface HTMLElementEventMap {\n 'rc-pagination-change': CustomEvent<RCPaginationChangeEvent>;\n }\n}\n\n/**\n * Pagination enhancer for a native `<nav>` holding a list of page links or\n * buttons.\n *\n * There is no WAI-ARIA pattern for pagination; the markup follows the GOV.UK\n * and USWDS models. The consumer renders the list, usually from\n * `paginationRange()`, and tags each control with `data-rc-page`: a page\n * number, or `previous`, `next`, `first`, or `last`. The markup works before the\n * element upgrades. The element then keeps `aria-current=\"page\"` on the\n * current page, names the landmark and unlabeled controls, disables steps past\n * either end, and reports each user request as `rc-pagination-change`.\n *\n * Links navigate as usual unless a listener cancels `rc-pagination-change`,\n * which also cancels the click, for client-side routing. Buttons only report.\n * A numbered target above `total` reports the last page; its stale link does\n * not navigate to an out-of-range URL.\n * In uncontrolled use the element moves to the requested page itself; set\n * `page` to control it.\n *\n * Built-in text follows the element's own `lang`, else `<html lang>`: per\n * element through `messages`, or for every instance through\n * `registerMessages()` from `@rcarls/rc-common` under `rc-pagination`.\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-pagination rc-pagination docs}\n * @see {@link https://design-system.service.gov.uk/components/pagination/ GOV.UK pagination}\n *\n * @fires rc-pagination-change - Fired when the user activates a page control. Cancelable;\n * canceling it also cancels the click, so a link does not navigate.\n *\n * @attr page - Controlled current page, 1-based. Host writes are silent.\n * @attr default-page - Initial page for uncontrolled use. Defaults to 1.\n * @attr total - Number of pages.\n * @attr announce - Announces the new page through a polite live region after each user change.\n *\n * @cssprop [--rc-pagination-gap=0.25em] - Space between items.\n * @cssprop [--rc-pagination-item-min-inline-size] - Minimum inline size of each item. Defers to\n * the content size when unset.\n */\nexport class RCPagination extends ReactiveElement {\n /** Number of pages. */\n @property({ type: Number })\n total = 1;\n\n /** Announces each user change through a polite live region. */\n @property({ type: Boolean })\n announce = false;\n\n /** Built-in text overrides; unset keys fall back to registered text, then English. */\n @property({ attribute: false })\n messages: Partial<RCPaginationMessages> | undefined;\n\n private _page: number | undefined;\n private _defaultPage = 1;\n private _uncontrolledPage: number | undefined;\n private _pageInitialized = false;\n\n private readonly _messages = new MessagesController(\n this,\n 'rc-pagination',\n DEFAULT_PAGINATION_MESSAGES,\n { overrides: () => this.messages },\n );\n\n // Created on connect or first use, so constructing the element without a\n // DOM (a server render) cannot throw.\n private _observer: MutationObserver | undefined;\n private _announcer: LiveAnnouncer | undefined;\n private _writtenLabel: string | null = null;\n private readonly _writtenNames = new WeakMap<Element, string | null>();\n private readonly _$managedCurrent = new Set<Element>();\n private readonly _$managedDisabled = new Set<Element>();\n private readonly _disabledBeforeEdge = new Map<Element, string | null>();\n\n /** Current page, 1-based and clamped to `[1, total]`. Host writes are silent. */\n @property({ type: Number })\n get page(): number {\n return this._clamp(this._page ?? this._uncontrolledPage ?? this._defaultPage);\n }\n\n set page(value: number | undefined) {\n const oldValue = this.page;\n\n this._page = value;\n this._pageInitialized = true;\n this.requestUpdate('page', oldValue);\n }\n\n /** Initial page for uncontrolled use. */\n @property({ type: Number, attribute: 'default-page' })\n get defaultPage(): number {\n return this._defaultPage;\n }\n\n set defaultPage(value: number) {\n const oldValue = this._defaultPage;\n\n this._defaultPage = value;\n\n if (\n !this._pageInitialized &&\n this._page === undefined &&\n this._uncontrolledPage === undefined\n ) {\n this.requestUpdate('page', this.page);\n }\n\n this.requestUpdate('defaultPage', oldValue);\n }\n\n /** Renders nothing: the consumer's `<nav>` stays the element's only content. */\n protected override createRenderRoot(): HTMLElement {\n return this;\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n ensurePaginationBaseStyles(this.getRootNode() as Document | ShadowRoot);\n this._observer ??= new MutationObserver(() => this._sync());\n\n this._observer.observe(this, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['data-rc-page', 'aria-label', 'aria-labelledby'],\n });\n\n this.addEventListener('click', this._onClick);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._observer?.disconnect();\n this.removeEventListener('click', this._onClick);\n this._announcer?.dispose();\n this._announcer = undefined;\n }\n\n protected override firstUpdated(): void {\n if (import.meta.env.DEV && !this.querySelector(NAV_SELECTOR)) {\n console.warn(\n '[rc-pagination] No direct child <nav> found. Place a native <nav> with a list of ' +\n '<a data-rc-page=\"2\"> or <button data-rc-page=\"2\"> controls inside <rc-pagination>.',\n this,\n );\n }\n }\n\n protected override updated(): void {\n this._sync();\n }\n\n private _clamp(page: number): number {\n const last = Math.max(1, Math.floor(this.total) || 1);\n const value = Number.isFinite(page) ? Math.floor(page) : 1;\n\n return Math.min(Math.max(1, value), last);\n }\n\n private _target($item: Element): PageTarget | undefined {\n const raw = $item.getAttribute('data-rc-page')?.trim() ?? '';\n\n if (raw === 'previous' || raw === 'next' || raw === 'first' || raw === 'last') {\n return raw;\n }\n\n const value = Number(raw);\n\n return Number.isInteger(value) && value > 0 ? value : undefined;\n }\n\n private _resolve(target: PageTarget): number {\n switch (target) {\n case 'previous':\n return this._clamp(this.page - 1);\n case 'next':\n return this._clamp(this.page + 1);\n case 'first':\n return 1;\n case 'last':\n return this._clamp(this.total);\n default:\n return this._clamp(target);\n }\n }\n\n private _sync(): void {\n const $nav = this.querySelector<HTMLElement>(NAV_SELECTOR);\n\n if (!$nav) {\n return;\n }\n\n const messages = this._messages.value;\n const locale = this._messages.locale;\n\n if ($nav.hasAttribute('aria-labelledby')) {\n this._writtenLabel = null;\n } else {\n this._writtenLabel = syncDefaultAttribute(\n $nav,\n 'aria-label',\n messages.label,\n this._writtenLabel,\n );\n }\n\n const page = this.page;\n const total = this._clamp(this.total);\n const $current = new Set<Element>();\n const $disabled = new Set<Element>();\n\n for (const $item of $nav.querySelectorAll(ITEM_SELECTOR)) {\n const target = this._target($item);\n\n if (target === undefined) {\n continue;\n }\n\n if (typeof target === 'number') {\n if (target === page) {\n $current.add($item);\n }\n\n this._syncName($item, messages.page(target, total, locale), true);\n } else {\n const atEdge =\n ((target === 'previous' || target === 'first') && page <= 1) ||\n ((target === 'next' || target === 'last') && page >= total);\n\n if (atEdge) {\n $disabled.add($item);\n }\n\n this._syncName($item, messages[target], false);\n }\n }\n\n for (const $item of this._$managedCurrent) {\n if (!$current.has($item)) {\n $item.removeAttribute('aria-current');\n }\n }\n\n for (const $item of $current) {\n $item.setAttribute('aria-current', 'page');\n }\n\n this._$managedCurrent.clear();\n $current.forEach(($item) => this._$managedCurrent.add($item));\n\n for (const $item of this._$managedDisabled) {\n if (!$disabled.has($item)) {\n const attribute = disabledAttribute($item);\n\n if (this._disabledBeforeEdge.has($item) && attribute) {\n const original = this._disabledBeforeEdge.get($item) ?? null;\n\n if ($item.getAttribute(attribute) === (attribute === 'disabled' ? '' : 'true')) {\n if (original === null) {\n $item.removeAttribute(attribute);\n } else {\n $item.setAttribute(attribute, original);\n }\n }\n\n this._disabledBeforeEdge.delete($item);\n }\n }\n }\n\n for (const $item of $disabled) {\n const attribute = disabledAttribute($item);\n\n if (\n attribute &&\n (!this._$managedDisabled.has($item) ||\n (this._disabledBeforeEdge.has($item) && !$item.hasAttribute(attribute)))\n ) {\n const original = $item.getAttribute(attribute);\n\n if (original !== (attribute === 'disabled' ? '' : 'true')) {\n if (!this._$managedDisabled.has($item)) {\n this._disabledBeforeEdge.set($item, original);\n }\n\n $item.setAttribute(attribute, attribute === 'disabled' ? '' : 'true');\n }\n }\n }\n\n this._$managedDisabled.clear();\n $disabled.forEach(($item) => this._$managedDisabled.add($item));\n }\n\n /**\n * Gives a control its default name unless the author named it. Numbered\n * controls always get one (\"Page 3\" contains the visible \"3\"); steps only\n * when they have no visible text, such as an icon-only button.\n */\n private _syncName($item: Element, name: string, numbered: boolean): void {\n if (!numbered && $item.textContent?.trim()) {\n return;\n }\n\n const written = syncDefaultAttribute(\n $item,\n 'aria-label',\n name,\n this._writtenNames.get($item) ?? null,\n );\n\n this._writtenNames.set($item, written);\n }\n\n private _onClick = (event: MouseEvent): void => {\n const $item = (event.target as Element | null)?.closest?.(ITEM_SELECTOR);\n const $nav = this.querySelector(NAV_SELECTOR);\n\n if (!$item || !$nav?.contains($item)) {\n return;\n }\n\n const target = this._target($item);\n\n if (target === undefined) {\n return;\n }\n\n if (this._$managedDisabled.has($item)) {\n event.preventDefault();\n\n return;\n }\n\n const previousPage = this.page;\n const page = this._resolve(target);\n\n // A stale numbered link may still point beyond `total`; report the\n // clamped page without following that invalid URL.\n if (typeof target === 'number' && target !== page) {\n event.preventDefault();\n }\n\n if (page === previousPage) {\n return;\n }\n\n const change = new CustomEvent<RCPaginationChangeEvent>('rc-pagination-change', {\n bubbles: true,\n composed: true,\n cancelable: true,\n detail: { page, previousPage },\n });\n\n if (!this.dispatchEvent(change)) {\n event.preventDefault();\n\n return;\n }\n\n if (this._page === undefined) {\n this._uncontrolledPage = page;\n this.requestUpdate('page', previousPage);\n }\n\n if (this.announce) {\n // The live region lives outside the host so it never joins the\n // consumer's list markup, which a framework may own. It mounts in the\n // open dialog around the host, else the current body.\n this._announcer ??= new LiveAnnouncer(this);\n\n this._announcer.announce(\n this._messages.value.status(page, this._clamp(this.total), this._messages.locale),\n );\n }\n };\n}\n\n/** The native or ARIA disabled attribute owned by a pagination control. */\nfunction disabledAttribute($item: Element): 'disabled' | 'aria-disabled' | undefined {\n if ($item instanceof HTMLButtonElement) {\n return 'disabled';\n }\n\n if ($item instanceof HTMLAnchorElement) {\n return 'aria-disabled';\n }\n\n return undefined;\n}\n\nexport default RCPagination;\n"],"names":["PAGINATION_BASE_CSS","cssText","ensurePaginationBaseStyles","defineLightDomBaseStyles","NAV_SELECTOR","ITEM_SELECTOR","formatPage","value","locale","numberFormat","DEFAULT_PAGINATION_MESSAGES","page","_total","total","RCPagination","ReactiveElement","MessagesController","event","$item","$nav","target","previousPage","change","LiveAnnouncer","oldValue","last","raw","messages","syncDefaultAttribute","$current","$disabled","attribute","disabledAttribute","original","name","numbered","written","__decorateClass","property"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { D as n, P as o, R as s, e as A } from "./rc-pagination-mkpZ0mCK.js";
|
|
2
|
+
import { paginationRange as i } from "./range.js";
|
|
3
|
+
export {
|
|
4
|
+
n as DEFAULT_PAGINATION_MESSAGES,
|
|
5
|
+
o as PAGINATION_BASE_CSS,
|
|
6
|
+
s as RCPagination,
|
|
7
|
+
A as ensurePaginationBaseStyles,
|
|
8
|
+
i as paginationRange
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=rc-pagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-pagination.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './index.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Light-DOM base styles for the pagination list.
|
|
3
|
+
*
|
|
4
|
+
* The consumer's `<nav>`, list, and controls stay in light DOM. These rules lay
|
|
5
|
+
* the list out as a wrapping inline row and give each control a minimum size;
|
|
6
|
+
* themes supply the shape, color, and state layers.
|
|
7
|
+
*/
|
|
8
|
+
export declare const PAGINATION_BASE_CSS: string;
|
|
9
|
+
/** Installs the pagination list styles once per containing root. */
|
|
10
|
+
export declare const ensurePaginationBaseStyles: (root: Document | ShadowRoot) => void;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** One slot in a pagination list: a page number or a gap of hidden pages. */
|
|
2
|
+
export type PaginationItem = number | 'ellipsis';
|
|
3
|
+
export interface PaginationRangeOptions {
|
|
4
|
+
/** The current page, 1-based. Clamped to `[1, total]`. */
|
|
5
|
+
page: number;
|
|
6
|
+
/** The number of pages. */
|
|
7
|
+
total: number;
|
|
8
|
+
/** Pages shown on each side of the current page. Defaults to 1. */
|
|
9
|
+
siblings?: number;
|
|
10
|
+
/** Pages always shown at each end. Defaults to 1. */
|
|
11
|
+
boundaries?: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The page numbers to render for a pagination list, with `'ellipsis'` where a
|
|
15
|
+
* run of pages is hidden. A gap of a single page shows that page instead, so
|
|
16
|
+
* an ellipsis always stands for at least two pages.
|
|
17
|
+
*
|
|
18
|
+
* Pure and DOM-free: import it from `@rcarls/rc-pagination/range` to build the
|
|
19
|
+
* markup on a server without loading the element.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* paginationRange({ page: 6, total: 12 }); // [1, 'ellipsis', 5, 6, 7, 'ellipsis', 12]
|
|
23
|
+
*/
|
|
24
|
+
export declare function paginationRange({ page, total, siblings, boundaries, }: PaginationRangeOptions): PaginationItem[];
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { ReactiveElement } from 'lit';
|
|
2
|
+
/** Built-in text of `rc-pagination`. */
|
|
3
|
+
export interface RCPaginationMessages {
|
|
4
|
+
/** Accessible name for the `<nav>` landmark when the author gives it none. */
|
|
5
|
+
label: string;
|
|
6
|
+
/** Accessible name of a numbered page link or button. */
|
|
7
|
+
page: (page: number, total: number, locale?: string) => string;
|
|
8
|
+
/** Name of a previous control that has no text of its own. */
|
|
9
|
+
previous: string;
|
|
10
|
+
/** Name of a next control that has no text of its own. */
|
|
11
|
+
next: string;
|
|
12
|
+
/** Name of a first-page control that has no text of its own. */
|
|
13
|
+
first: string;
|
|
14
|
+
/** Name of a last-page control that has no text of its own. */
|
|
15
|
+
last: string;
|
|
16
|
+
/** Announcement after a page change, when `announce` is set. */
|
|
17
|
+
status: (page: number, total: number, locale?: string) => string;
|
|
18
|
+
}
|
|
19
|
+
export declare const DEFAULT_PAGINATION_MESSAGES: Readonly<RCPaginationMessages>;
|
|
20
|
+
declare module '@rcarls/rc-common' {
|
|
21
|
+
interface RcMessageCatalog {
|
|
22
|
+
'rc-pagination': RCPaginationMessages;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** Detail of `rc-pagination-change`. */
|
|
26
|
+
export interface RCPaginationChangeEvent {
|
|
27
|
+
/** The page the user asked for. */
|
|
28
|
+
page: number;
|
|
29
|
+
/** The page that was current when the user asked. */
|
|
30
|
+
previousPage: number;
|
|
31
|
+
}
|
|
32
|
+
declare global {
|
|
33
|
+
interface HTMLElementTagNameMap {
|
|
34
|
+
'rc-pagination': RCPagination;
|
|
35
|
+
}
|
|
36
|
+
interface HTMLElementEventMap {
|
|
37
|
+
'rc-pagination-change': CustomEvent<RCPaginationChangeEvent>;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Pagination enhancer for a native `<nav>` holding a list of page links or
|
|
42
|
+
* buttons.
|
|
43
|
+
*
|
|
44
|
+
* There is no WAI-ARIA pattern for pagination; the markup follows the GOV.UK
|
|
45
|
+
* and USWDS models. The consumer renders the list, usually from
|
|
46
|
+
* `paginationRange()`, and tags each control with `data-rc-page`: a page
|
|
47
|
+
* number, or `previous`, `next`, `first`, or `last`. The markup works before the
|
|
48
|
+
* element upgrades. The element then keeps `aria-current="page"` on the
|
|
49
|
+
* current page, names the landmark and unlabeled controls, disables steps past
|
|
50
|
+
* either end, and reports each user request as `rc-pagination-change`.
|
|
51
|
+
*
|
|
52
|
+
* Links navigate as usual unless a listener cancels `rc-pagination-change`,
|
|
53
|
+
* which also cancels the click, for client-side routing. Buttons only report.
|
|
54
|
+
* A numbered target above `total` reports the last page; its stale link does
|
|
55
|
+
* not navigate to an out-of-range URL.
|
|
56
|
+
* In uncontrolled use the element moves to the requested page itself; set
|
|
57
|
+
* `page` to control it.
|
|
58
|
+
*
|
|
59
|
+
* Built-in text follows the element's own `lang`, else `<html lang>`: per
|
|
60
|
+
* element through `messages`, or for every instance through
|
|
61
|
+
* `registerMessages()` from `@rcarls/rc-common` under `rc-pagination`.
|
|
62
|
+
*
|
|
63
|
+
* @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-pagination rc-pagination docs}
|
|
64
|
+
* @see {@link https://design-system.service.gov.uk/components/pagination/ GOV.UK pagination}
|
|
65
|
+
*
|
|
66
|
+
* @fires rc-pagination-change - Fired when the user activates a page control. Cancelable;
|
|
67
|
+
* canceling it also cancels the click, so a link does not navigate.
|
|
68
|
+
*
|
|
69
|
+
* @attr page - Controlled current page, 1-based. Host writes are silent.
|
|
70
|
+
* @attr default-page - Initial page for uncontrolled use. Defaults to 1.
|
|
71
|
+
* @attr total - Number of pages.
|
|
72
|
+
* @attr announce - Announces the new page through a polite live region after each user change.
|
|
73
|
+
*
|
|
74
|
+
* @cssprop [--rc-pagination-gap=0.25em] - Space between items.
|
|
75
|
+
* @cssprop [--rc-pagination-item-min-inline-size] - Minimum inline size of each item. Defers to
|
|
76
|
+
* the content size when unset.
|
|
77
|
+
*/
|
|
78
|
+
export declare class RCPagination extends ReactiveElement {
|
|
79
|
+
/** Number of pages. */
|
|
80
|
+
total: number;
|
|
81
|
+
/** Announces each user change through a polite live region. */
|
|
82
|
+
announce: boolean;
|
|
83
|
+
/** Built-in text overrides; unset keys fall back to registered text, then English. */
|
|
84
|
+
messages: Partial<RCPaginationMessages> | undefined;
|
|
85
|
+
private _page;
|
|
86
|
+
private _defaultPage;
|
|
87
|
+
private _uncontrolledPage;
|
|
88
|
+
private _pageInitialized;
|
|
89
|
+
private readonly _messages;
|
|
90
|
+
private _observer;
|
|
91
|
+
private _announcer;
|
|
92
|
+
private _writtenLabel;
|
|
93
|
+
private readonly _writtenNames;
|
|
94
|
+
private readonly _$managedCurrent;
|
|
95
|
+
private readonly _$managedDisabled;
|
|
96
|
+
private readonly _disabledBeforeEdge;
|
|
97
|
+
/** Current page, 1-based and clamped to `[1, total]`. Host writes are silent. */
|
|
98
|
+
get page(): number;
|
|
99
|
+
set page(value: number | undefined);
|
|
100
|
+
/** Initial page for uncontrolled use. */
|
|
101
|
+
get defaultPage(): number;
|
|
102
|
+
set defaultPage(value: number);
|
|
103
|
+
/** Renders nothing: the consumer's `<nav>` stays the element's only content. */
|
|
104
|
+
protected createRenderRoot(): HTMLElement;
|
|
105
|
+
connectedCallback(): void;
|
|
106
|
+
disconnectedCallback(): void;
|
|
107
|
+
protected firstUpdated(): void;
|
|
108
|
+
protected updated(): void;
|
|
109
|
+
private _clamp;
|
|
110
|
+
private _target;
|
|
111
|
+
private _resolve;
|
|
112
|
+
private _sync;
|
|
113
|
+
/**
|
|
114
|
+
* Gives a control its default name unless the author named it. Numbered
|
|
115
|
+
* controls always get one ("Page 3" contains the visible "3"); steps only
|
|
116
|
+
* when they have no visible text, such as an icon-only button.
|
|
117
|
+
*/
|
|
118
|
+
private _syncName;
|
|
119
|
+
private _onClick;
|
|
120
|
+
}
|
|
121
|
+
export default RCPagination;
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rcarls/rc-pagination",
|
|
3
|
+
"publishConfig": {
|
|
4
|
+
"access": "public"
|
|
5
|
+
},
|
|
6
|
+
"version": "0.0.0-next-20261102181447",
|
|
7
|
+
"description": "Pagination enhancer for a native <nav> holding page links or buttons, with a server-safe page range helper.",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/richardcarls/rc-webcomponents.git",
|
|
11
|
+
"directory": "packages/rc-pagination"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://richardcarls.github.io/rc-webcomponents/components/rc-pagination",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"module": "./dist/rc-pagination.js",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"import": {
|
|
23
|
+
"types": "./dist/types/packages/rc-pagination/src/index.d.ts",
|
|
24
|
+
"default": "./dist/rc-pagination.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"./define": {
|
|
28
|
+
"import": {
|
|
29
|
+
"types": "./dist/types/packages/rc-pagination/src/define.d.ts",
|
|
30
|
+
"default": "./dist/rc-pagination-define.js"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"./range": {
|
|
34
|
+
"import": {
|
|
35
|
+
"types": "./dist/types/packages/rc-pagination/src/range.d.ts",
|
|
36
|
+
"default": "./dist/range.js"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"./base.css": "./dist/base.css"
|
|
40
|
+
},
|
|
41
|
+
"types": "./dist/types/packages/rc-pagination/src/index.d.ts",
|
|
42
|
+
"sideEffects": [
|
|
43
|
+
"./dist/rc-pagination-define.js",
|
|
44
|
+
"./dist/base.css"
|
|
45
|
+
],
|
|
46
|
+
"customElements": "dist/custom-elements.json",
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsc && vite build && node ../../scripts/emit-light-dom-base-css.mjs && cem analyze",
|
|
49
|
+
"cem:analyze": "cem analyze",
|
|
50
|
+
"test:browser": "vitest --run",
|
|
51
|
+
"test:browser:chrome": "vitest --run --project=chromium",
|
|
52
|
+
"test:browser:firefox": "vitest --run --project=firefox"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@rcarls/rc-common": "0.0.0-next-20261102181447"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@custom-elements-manifest/analyzer": "0.11.0",
|
|
59
|
+
"@vitest/browser-playwright": "4.1.5",
|
|
60
|
+
"lit": "^3.0.0",
|
|
61
|
+
"playwright": "^1.56.0",
|
|
62
|
+
"rollup": "^4.60.2",
|
|
63
|
+
"typescript": "~5.9.3",
|
|
64
|
+
"vite": "^7.1.7",
|
|
65
|
+
"vite-plugin-dts": "^4.5.4",
|
|
66
|
+
"vitest": "^4.0.6",
|
|
67
|
+
"vitest-browser-lit": "^1.0.1"
|
|
68
|
+
},
|
|
69
|
+
"peerDependencies": {
|
|
70
|
+
"lit": "^3.0.0"
|
|
71
|
+
}
|
|
72
|
+
}
|