@reliability-design/web 1.4.6 → 1.4.8

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.
Files changed (148) hide show
  1. package/CHANGELOG.md +246 -49
  2. package/dist/components/rel-accordion/README.md +133 -132
  3. package/dist/components/rel-alert/README.md +145 -141
  4. package/dist/components/rel-autocomplete/README.md +172 -61
  5. package/dist/components/rel-avatar/README.md +118 -130
  6. package/dist/components/rel-badge/README.md +97 -93
  7. package/dist/components/rel-breadcrumb/README.md +96 -102
  8. package/dist/components/rel-button/README.md +190 -130
  9. package/dist/components/rel-calendar/README.md +109 -109
  10. package/dist/components/rel-card/README.md +75 -94
  11. package/dist/components/rel-cardmedia/README.md +100 -127
  12. package/dist/components/rel-carousel/README.md +186 -166
  13. package/dist/components/rel-checkbox/README.md +96 -75
  14. package/dist/components/rel-chip/README.md +138 -121
  15. package/dist/components/rel-container/README.md +107 -99
  16. package/dist/components/rel-date-picker/README.md +200 -289
  17. package/dist/components/rel-divider/README.md +88 -100
  18. package/dist/components/rel-drawer/README.md +187 -200
  19. package/dist/components/rel-kbd/README.md +141 -151
  20. package/dist/components/rel-layout/README.md +34 -0
  21. package/dist/components/rel-menu/README.md +180 -151
  22. package/dist/components/rel-menubar/README.md +218 -329
  23. package/dist/components/rel-otp/README.md +171 -440
  24. package/dist/components/rel-pagination/README.md +100 -424
  25. package/dist/components/rel-popover/README.md +203 -568
  26. package/dist/components/rel-progress/README.md +88 -110
  27. package/dist/components/rel-radio/README.md +131 -138
  28. package/dist/components/rel-range-picker/README.md +165 -0
  29. package/dist/components/rel-resizable/README.md +199 -140
  30. package/dist/components/rel-segmented-button/README.md +156 -141
  31. package/dist/components/rel-select/README.md +156 -93
  32. package/dist/components/rel-sheet/README.md +168 -224
  33. package/dist/components/rel-skeleton/README.md +104 -0
  34. package/dist/components/rel-slider/README.md +131 -135
  35. package/dist/components/rel-snackbar/README.md +168 -134
  36. package/dist/components/rel-stepper/README.md +162 -160
  37. package/dist/components/rel-switch/README.md +117 -102
  38. package/dist/components/rel-tab/README.md +173 -163
  39. package/dist/components/rel-textfield/README.md +176 -69
  40. package/dist/components/rel-time-picker/README.md +122 -157
  41. package/dist/components/rel-toast/README.md +165 -148
  42. package/dist/components/rel-tooltip/README.md +119 -111
  43. package/dist/components/rel-upload/README.md +220 -0
  44. package/dist/index.d.mts +1726 -447
  45. package/dist/index.d.ts +1726 -447
  46. package/dist/index.js +13715 -10870
  47. package/dist/index.js.map +1 -1
  48. package/dist/index.mjs +14018 -11163
  49. package/dist/index.mjs.map +1 -1
  50. package/dist/styles/focus-ring.ts +84 -0
  51. package/dist/styles/vars.css +892 -866
  52. package/dist/{vars-XNMTSRVN.css → vars-DXX6QOAG.css} +892 -866
  53. package/package.json +3 -2
  54. package/dist/components/rel-accordion/rel-accordion.ts +0 -336
  55. package/dist/components/rel-alert/rel-alert.ts +0 -305
  56. package/dist/components/rel-autocomplete/rel-autocomplete.ts +0 -720
  57. package/dist/components/rel-avatar/rel-avatar.ts +0 -142
  58. package/dist/components/rel-badge/rel-badge.ts +0 -175
  59. package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +0 -106
  60. package/dist/components/rel-button/rel-button.ts +0 -560
  61. package/dist/components/rel-calendar/index.ts +0 -1
  62. package/dist/components/rel-calendar/rel-calendar.ts +0 -565
  63. package/dist/components/rel-card/rel-card.ts +0 -88
  64. package/dist/components/rel-cardmedia/rel-cardmedia.ts +0 -88
  65. package/dist/components/rel-carousel/index.ts +0 -1
  66. package/dist/components/rel-carousel/rel-carousel.ts +0 -723
  67. package/dist/components/rel-chart/README.md +0 -286
  68. package/dist/components/rel-chart/index.ts +0 -1
  69. package/dist/components/rel-chart/rel-chart.ts +0 -754
  70. package/dist/components/rel-checkbox/rel-checkbox.ts +0 -382
  71. package/dist/components/rel-chip/rel-chip.ts +0 -483
  72. package/dist/components/rel-container/rel-container.ts +0 -95
  73. package/dist/components/rel-date-picker/date-format.test.ts +0 -43
  74. package/dist/components/rel-date-picker/date-format.ts +0 -47
  75. package/dist/components/rel-date-picker/date-parse.test.ts +0 -116
  76. package/dist/components/rel-date-picker/date-parse.ts +0 -178
  77. package/dist/components/rel-date-picker/index.ts +0 -1
  78. package/dist/components/rel-date-picker/rel-date-picker.ts +0 -1676
  79. package/dist/components/rel-divider/rel-divider.ts +0 -54
  80. package/dist/components/rel-drawer/index.ts +0 -1
  81. package/dist/components/rel-drawer/rel-drawer-footer.ts +0 -27
  82. package/dist/components/rel-drawer/rel-drawer.ts +0 -607
  83. package/dist/components/rel-kbd/rel-kbd.ts +0 -188
  84. package/dist/components/rel-layout/rel-layout.ts +0 -49
  85. package/dist/components/rel-menu/rel-menu.ts +0 -541
  86. package/dist/components/rel-menubar/index.ts +0 -2
  87. package/dist/components/rel-menubar/rel-menubar-menu.css +0 -3
  88. package/dist/components/rel-menubar/rel-menubar-menu.ts +0 -17
  89. package/dist/components/rel-menubar/rel-menubar.ts +0 -777
  90. package/dist/components/rel-nav-menu/README.md +0 -289
  91. package/dist/components/rel-nav-menu/index.ts +0 -3
  92. package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +0 -243
  93. package/dist/components/rel-nav-menu/rel-nav-menu-panel.ts +0 -72
  94. package/dist/components/rel-nav-menu/rel-nav-menu.ts +0 -270
  95. package/dist/components/rel-navbar/README.md +0 -126
  96. package/dist/components/rel-navbar/rel-navbar.ts +0 -105
  97. package/dist/components/rel-otp/index.ts +0 -1
  98. package/dist/components/rel-otp/rel-otp.ts +0 -527
  99. package/dist/components/rel-pagination/index.ts +0 -1
  100. package/dist/components/rel-pagination/rel-pagination.ts +0 -522
  101. package/dist/components/rel-popover/index.ts +0 -2
  102. package/dist/components/rel-popover/rel-popover-content.ts +0 -81
  103. package/dist/components/rel-popover/rel-popover.ts +0 -475
  104. package/dist/components/rel-progress/rel-progress.ts +0 -234
  105. package/dist/components/rel-radio/rel-radio.ts +0 -481
  106. package/dist/components/rel-range-picker/rel-range-picker.ts +0 -1688
  107. package/dist/components/rel-resizable/index.ts +0 -3
  108. package/dist/components/rel-resizable/rel-resizable-group.ts +0 -405
  109. package/dist/components/rel-resizable/rel-resizable-handle.ts +0 -150
  110. package/dist/components/rel-resizable/rel-resizable-panel.ts +0 -58
  111. package/dist/components/rel-segmented-button/rel-segmented-button.ts +0 -217
  112. package/dist/components/rel-select/rel-select.ts +0 -1416
  113. package/dist/components/rel-sheet/rel-sheet.ts +0 -610
  114. package/dist/components/rel-sidebar/README.md +0 -209
  115. package/dist/components/rel-sidebar/rel-sidebar.ts +0 -1191
  116. package/dist/components/rel-skeleton/rel-skeleton.ts +0 -143
  117. package/dist/components/rel-slider/rel-slider.ts +0 -673
  118. package/dist/components/rel-snackbar/rel-snackbar.ts +0 -329
  119. package/dist/components/rel-stepper/rel-stepper.ts +0 -567
  120. package/dist/components/rel-switch/rel-switch.ts +0 -199
  121. package/dist/components/rel-tab/rel-tab.ts +0 -264
  122. package/dist/components/rel-table/README.md +0 -178
  123. package/dist/components/rel-table/rel-table-body.ts +0 -22
  124. package/dist/components/rel-table/rel-table-caption.ts +0 -30
  125. package/dist/components/rel-table/rel-table-cell.ts +0 -43
  126. package/dist/components/rel-table/rel-table-footer.ts +0 -24
  127. package/dist/components/rel-table/rel-table-head.ts +0 -47
  128. package/dist/components/rel-table/rel-table-header.ts +0 -22
  129. package/dist/components/rel-table/rel-table-row.ts +0 -37
  130. package/dist/components/rel-table/rel-table.ts +0 -62
  131. package/dist/components/rel-textfield/rel-textfield.ts +0 -1054
  132. package/dist/components/rel-time-picker/rel-time-picker.ts +0 -1482
  133. package/dist/components/rel-time-picker/time-parse.test.ts +0 -67
  134. package/dist/components/rel-time-picker/time-parse.ts +0 -85
  135. package/dist/components/rel-toast/rel-toast.ts +0 -206
  136. package/dist/components/rel-tooltip/rel-tooltip.ts +0 -193
  137. package/dist/components/rel-topbar/rel-topbar-actions.ts +0 -27
  138. package/dist/components/rel-topbar/rel-topbar-brand.ts +0 -54
  139. package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +0 -69
  140. package/dist/components/rel-topbar/rel-topbar-dropdown.ts +0 -31
  141. package/dist/components/rel-topbar/rel-topbar-item.ts +0 -324
  142. package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +0 -27
  143. package/dist/components/rel-topbar/rel-topbar-profile.ts +0 -243
  144. package/dist/components/rel-topbar/rel-topbar-utilities.ts +0 -27
  145. package/dist/components/rel-topbar/rel-topbar.ts +0 -446
  146. package/dist/components/rel-upload/UPLOAD-DESIGN-CHANGES.md +0 -134
  147. package/dist/components/rel-upload/rel-upload-actions.ts +0 -163
  148. package/dist/components/rel-upload/rel-upload.ts +0 -968
@@ -1,424 +1,100 @@
1
- # rel-pagination
2
-
3
- A flexible pagination component with smart ellipsis rendering, keyboard navigation, and support for both controlled and uncontrolled modes.
4
-
5
- ## What It Is
6
-
7
- The pagination component provides navigation through multiple pages of content. It intelligently renders page numbers with ellipsis to handle large page counts, supports Previous/Next controls, and can render either as buttons or links.
8
-
9
- ## Basic Usage
10
-
11
- ```html
12
- <!-- Uncontrolled mode (manages its own state) -->
13
- <rel-pagination totalPages="10" defaultPage="1"></rel-pagination>
14
-
15
- <!-- Controlled mode (external state management) -->
16
- <rel-pagination totalPages="10" page="5"></rel-pagination>
17
- ```
18
-
19
- ## API Reference
20
-
21
- ### Attributes / Properties
22
-
23
- | Attribute | Type | Default | Description |
24
- |-----------|------|---------|-------------|
25
- | `page` | number | undefined | Current page (1-based). When set, enables controlled mode |
26
- | `defaultPage` | number | 1 | Initial page for uncontrolled mode |
27
- | `totalPages` | number | required | Total number of pages |
28
- | `siblingCount` | number | 1 | Number of pages to show around current page |
29
- | `boundaryCount` | number | 1 | Number of pages to show at start/end |
30
- | `disabled` | boolean | false | Disables all interactions |
31
- | `density` | "comfortable" \| "compact" | "comfortable" | Spacing density |
32
- | `variant` | "default" \| "icons" | "default" | Controls visual style |
33
- | `hrefTemplate` | string | "" | Template for href links (e.g., "/page/{page}") |
34
- | `ariaLabel` | string | "Pagination" | ARIA label for the nav element |
35
-
36
- ### Events
37
-
38
- **rel-change**
39
-
40
- Emitted when user selects a new page.
41
-
42
- ```typescript
43
- detail: { page: number }
44
- ```
45
-
46
- **Example:**
47
- ```javascript
48
- const pagination = document.querySelector('rel-pagination');
49
- pagination.addEventListener('rel-change', (e) => {
50
- console.log('New page:', e.detail.page);
51
- });
52
- ```
53
-
54
- ## Controlled vs Uncontrolled
55
-
56
- ### Uncontrolled Mode
57
-
58
- Component manages its own internal state. Use `defaultPage` to set initial page.
59
-
60
- ```html
61
- <rel-pagination totalPages="10" defaultPage="2"></rel-pagination>
62
- ```
63
-
64
- ```javascript
65
- pagination.addEventListener('rel-change', (e) => {
66
- // Component has already updated its internal page
67
- console.log('Changed to page:', e.detail.page);
68
- });
69
- ```
70
-
71
- ### Controlled Mode
72
-
73
- External code manages the page state. Set the `page` attribute.
74
-
75
- ```html
76
- <rel-pagination id="controlled-pagination" totalPages="10" page="5"></rel-pagination>
77
- ```
78
-
79
- ```javascript
80
- let currentPage = 5;
81
- const pagination = document.getElementById('controlled-pagination');
82
-
83
- pagination.addEventListener('rel-change', (e) => {
84
- // Update your external state
85
- currentPage = e.detail.page;
86
- // Update the component
87
- pagination.page = currentPage;
88
-
89
- // Fetch new data, etc.
90
- fetchData(currentPage);
91
- });
92
- ```
93
-
94
- ## Ellipsis Logic
95
-
96
- The component intelligently renders page numbers with ellipsis based on `siblingCount` and `boundaryCount`:
97
-
98
- ### Examples
99
-
100
- **totalPages=10, page=5, siblingCount=1, boundaryCount=1:**
101
- ```
102
- 1 … 4 5 6 … 10
103
- ```
104
-
105
- **totalPages=10, page=2, siblingCount=1, boundaryCount=1:**
106
- ```
107
- 1 2 3 … 10
108
- ```
109
-
110
- **totalPages=10, page=9, siblingCount=1, boundaryCount=1:**
111
- ```
112
- 1 … 8 9 10
113
- ```
114
-
115
- **totalPages=5, page=3 (no ellipsis needed):**
116
- ```
117
- 1 2 3 4 5
118
- ```
119
-
120
- ### How It Works
121
-
122
- 1. **Boundary Pages**: Always shows `boundaryCount` pages at start and end
123
- 2. **Sibling Pages**: Shows `siblingCount` pages on each side of current page
124
- 3. **Ellipsis**: Inserted when there's a gap between visible page ranges
125
-
126
- ## Variants
127
-
128
- ### Default Variant
129
-
130
- Shows text labels for Previous/Next buttons.
131
-
132
- ```html
133
- <rel-pagination totalPages="10" variant="default"></rel-pagination>
134
- <!-- Renders: [Previous] [1] [2] ... [10] [Next] -->
135
- ```
136
-
137
- ### Icons Variant
138
-
139
- Shows chevron icons instead of text labels.
140
-
141
- ```html
142
- <rel-pagination totalPages="10" variant="icons"></rel-pagination>
143
- <!-- Renders: [<] [1] [2] ... [10] [>] -->
144
- ```
145
-
146
- ## Density
147
-
148
- ### Comfortable (Default)
149
-
150
- Standard spacing with larger touch targets.
151
-
152
- ```html
153
- <rel-pagination totalPages="10" density="comfortable"></rel-pagination>
154
- ```
155
-
156
- - Height: 40px
157
- - Font size: sm
158
- - Padding: sm
159
-
160
- ### Compact
161
-
162
- Tighter spacing for dense layouts.
163
-
164
- ```html
165
- <rel-pagination totalPages="10" density="compact"></rel-pagination>
166
- ```
167
-
168
- - Height: 32px
169
- - Font size: xs
170
- - Padding: xs
171
-
172
- ## Link Mode
173
-
174
- Instead of buttons, render page items as links by providing an `hrefTemplate`.
175
-
176
- ```html
177
- <rel-pagination
178
- totalPages="10"
179
- page="3"
180
- hrefTemplate="/docs?page={page}">
181
- </rel-pagination>
182
- ```
183
-
184
- The `{page}` placeholder is replaced with the page number:
185
- - Page 1 → `/docs?page=1`
186
- - Page 5 → `/docs?page=5`
187
-
188
- **Note**: Click events still emit `rel-change` events and prevent default navigation, allowing you to handle routing in JavaScript.
189
-
190
- ## Keyboard Navigation
191
-
192
- Full keyboard accessibility:
193
-
194
- | Key | Action |
195
- |-----|--------|
196
- | `Tab` / `Shift+Tab` | Navigate through page buttons and controls |
197
- | `Enter` | Activate focused button/link |
198
- | `Space` | Activate focused button/link |
199
-
200
- ## Accessibility
201
-
202
- The component follows ARIA best practices:
203
-
204
- ### Semantic HTML
205
- - Wrapped in `<nav>` with `role="navigation"`
206
- - Configurable `aria-label` (default: "Pagination")
207
-
208
- ### Page Buttons
209
- - Current page has `aria-current="page"`
210
- - Each button has descriptive `aria-label`:
211
- - "Go to page 1"
212
- - "Go to page 2"
213
- - etc.
214
-
215
- ### Controls
216
- - Previous button: `aria-label="Go to previous page"`
217
- - Next button: `aria-label="Go to next page"`
218
- - Disabled state reflected with `disabled` attribute or `aria-disabled`
219
-
220
- ### Focus Management
221
- - Visible focus indicators using focus-visible
222
- - Proper tab order through page numbers
223
-
224
- ## Styling Tokens
225
-
226
- The component uses design tokens from the Reliability Design System:
227
-
228
- ### Colors
229
- - `--rel-bg-surface` - Button/link background
230
- - `--rel-text-label` - Text color and active page background
231
- - `--rel-border-default` - Border color
232
- - `--rel-text-default` - Hover border color
233
- - `--rel-bg-neutral-elevated-1` - Hover background
234
- - `--rel-text-placeholder` - Ellipsis color
235
- - `--rel-bg-info` - Focus outline
236
-
237
- ### Typography
238
- - `--rel-fonts-font-family` - Font family (Poppins)
239
- - `--rel-fonts-weight-body-medium` - Default text weight
240
- - `--rel-fonts-weight-body-semibold` - Active page weight
241
- - `--rel-body-sm-regular-font-size` - Comfortable mode font size
242
- - `--rel-body-xs-regular-font-size` - Compact mode font size
243
-
244
- ### Spacing
245
- - `--rel-spacing-3xs` (2px) - Compact gap
246
- - `--rel-spacing-2xs` (4px) - Comfortable gap
247
- - `--rel-spacing-xs` (8px) - Compact padding
248
- - `--rel-spacing-sm` (12px) - Comfortable padding
249
-
250
- ### Borders
251
- - `--rel-stroke-sm` (1px) - Border width
252
- - `--rel-border-radius-sm` (8px) - Border radius
253
-
254
- ## Complete Examples
255
-
256
- ### Simple Pagination
257
-
258
- ```html
259
- <rel-pagination totalPages="10" defaultPage="1"></rel-pagination>
260
- ```
261
-
262
- ### With Event Handling
263
-
264
- ```html
265
- <rel-pagination id="my-pagination" totalPages="50" defaultPage="1"></rel-pagination>
266
-
267
- <script>
268
- const pagination = document.getElementById('my-pagination');
269
-
270
- pagination.addEventListener('rel-change', (e) => {
271
- console.log('Loading page:', e.detail.page);
272
- fetchPageData(e.detail.page);
273
- });
274
-
275
- function fetchPageData(page) {
276
- // Your data fetching logic
277
- }
278
- </script>
279
- ```
280
-
281
- ### Controlled with More Siblings
282
-
283
- ```html
284
- <rel-pagination
285
- id="controlled"
286
- totalPages="100"
287
- page="50"
288
- siblingCount="2"
289
- boundaryCount="2">
290
- </rel-pagination>
291
-
292
- <script>
293
- let currentPage = 50;
294
- const pagination = document.getElementById('controlled');
295
-
296
- pagination.addEventListener('rel-change', (e) => {
297
- currentPage = e.detail.page;
298
- pagination.page = currentPage;
299
- updateContent(currentPage);
300
- });
301
- </script>
302
- ```
303
-
304
- ### Compact with Icons
305
-
306
- ```html
307
- <rel-pagination
308
- totalPages="25"
309
- defaultPage="1"
310
- density="compact"
311
- variant="icons"
312
- siblingCount="1"
313
- boundaryCount="1">
314
- </rel-pagination>
315
- ```
316
-
317
- ### Link Mode for SEO
318
-
319
- ```html
320
- <rel-pagination
321
- totalPages="20"
322
- page="5"
323
- hrefTemplate="/products?page={page}"
324
- siblingCount="1">
325
- </rel-pagination>
326
-
327
- <script>
328
- const pagination = document.querySelector('rel-pagination');
329
-
330
- pagination.addEventListener('rel-change', (e) => {
331
- // Handle client-side navigation
332
- navigateToPage(e.detail.page);
333
- });
334
-
335
- function navigateToPage(page) {
336
- // Your routing logic (e.g., History API)
337
- history.pushState({}, '', `/products?page=${page}`);
338
- loadPageData(page);
339
- }
340
- </script>
341
- ```
342
-
343
- ## Edge Cases
344
-
345
- ### Few Pages (No Ellipsis)
346
-
347
- When total pages is small, all pages are shown:
348
-
349
- ```html
350
- <rel-pagination totalPages="5" page="3"></rel-pagination>
351
- <!-- Renders: [Previous] [1] [2] [3] [4] [5] [Next] -->
352
- ```
353
-
354
- ### First Page
355
-
356
- Previous button is disabled:
357
-
358
- ```html
359
- <rel-pagination totalPages="10" page="1"></rel-pagination>
360
- <!-- [Previous - disabled] [1] [2] [3] ... [10] [Next] -->
361
- ```
362
-
363
- ### Last Page
364
-
365
- Next button is disabled:
366
-
367
- ```html
368
- <rel-pagination totalPages="10" page="10"></rel-pagination>
369
- <!-- [Previous] [1] ... [8] [9] [10] [Next - disabled] -->
370
- ```
371
-
372
- ### Disabled State
373
-
374
- All interactions disabled:
375
-
376
- ```html
377
- <rel-pagination totalPages="10" page="5" disabled></rel-pagination>
378
- ```
379
-
380
- ### Very Large Page Counts
381
-
382
- Page buttons auto-widen to fit their number (min-width 40px). Far first/last
383
- buttons with numbers ≥ 10,000 are abbreviated so the control stays compact:
384
- `10000` → `10k`, `368178` → `368k`, `1234567` → `1.2M`. The exact page number
385
- is preserved in the button's `aria-label` and `title` (hover tooltip). The
386
- current page and its immediate neighbors always render exact — abbreviating
387
- them would make adjacent pages indistinguishable.
388
-
389
- ```html
390
- <rel-pagination totalPages="368178" page="7"></rel-pagination>
391
- <!-- [<] [1] ... [6] [7] [8] ... [368k] [>] -->
392
- ```
393
-
394
- ## Browser Support
395
-
396
- Compatible with all modern browsers supporting:
397
- - Web Components (Custom Elements v1)
398
- - Shadow DOM
399
- - ES2020+ features
400
-
401
- ## Framework Integration
402
-
403
- Works seamlessly with:
404
- - Vanilla JavaScript
405
- - Angular
406
- - React (via wrapper)
407
- - Vue
408
- - Any framework supporting Web Components
409
-
410
- ## Best Practices
411
-
412
- 1. **Use controlled mode** for complex state management (Redux, Vuex, etc.)
413
- 2. **Use uncontrolled mode** for simple cases where component can manage its own state
414
- 3. **Adjust siblingCount** based on available space (mobile: 0-1, desktop: 1-2)
415
- 4. **Use compact density** on mobile or in sidebars
416
- 5. **Use link mode** when SEO matters (server-rendered pagination)
417
- 6. **Always handle rel-change events** to update your data/UI
418
-
419
- ## Performance Notes
420
-
421
- - Ellipsis calculation is optimized and runs only when page/total changes
422
- - No unnecessary re-renders in controlled mode
423
- - Minimal DOM elements (only visible pages + controls)
424
- - Efficient event handling with no memory leaks
1
+ # rel-pagination
2
+
3
+ Page navigation implementing the Figma "Pagination" component in its three **Type** layouts: `extended` (prev/next ghost buttons around numbered page chips, with a windowed ellipsis for long ranges), `compact` (prev/next around a "Page X of Y" readout) and `count-text` (a "1–10 of 50" item range with the nav on the right). Use it under tables, lists and search results that load one page at a time. It never fetches data or reads the URL: listen for `rel-change` and load the requested page yourself.
4
+
5
+ ## Usage
6
+
7
+ ```html
8
+ <!-- Extended (default): numbered pages, uncontrolled -->
9
+ <rel-pagination totalPages="12" defaultPage="3"></rel-pagination>
10
+
11
+ <!-- Extended with the "Viewing page X of Y" caption -->
12
+ <rel-pagination totalPages="20" showLabel></rel-pagination>
13
+
14
+ <!-- Compact: prev / "Page X of Y" / next -->
15
+ <rel-pagination type="compact" totalPages="8"></rel-pagination>
16
+
17
+ <!-- Count-text: item range computed from totalItems and perPage -->
18
+ <rel-pagination type="count-text" totalItems="137" perPage="25"></rel-pagination>
19
+
20
+ <!-- Controlled: the parent owns the page -->
21
+ <rel-pagination id="results" page="1" totalPages="40" ariaLabel="Search results pagination"></rel-pagination>
22
+ <script>
23
+ const pager = document.getElementById('results');
24
+ pager.addEventListener('rel-change', (e) => {
25
+ loadResults(e.detail.page).then(() => {
26
+ pager.page = e.detail.page; // commit once the data is in
27
+ });
28
+ });
29
+ </script>
30
+
31
+ <!-- Disabled while loading -->
32
+ <rel-pagination totalPages="12" disabled></rel-pagination>
33
+ ```
34
+
35
+ <!-- readme-gen:start -->
36
+
37
+ <!-- Generated from rel-pagination.ts — do not edit; run readme-generate.mjs -->
38
+
39
+ ## API
40
+
41
+ ### Attributes / Properties
42
+
43
+ | Property | Attribute | Type | Default | Description |
44
+ | --- | --- | --- | --- | --- |
45
+ | `type` | `type` | `"extended" \| "compact" \| "count-text"` | `"extended"` | Figma "Type": `extended` = prev/next + numbered page buttons (auto-collapses to compact under 480px container width), `compact` = prev/next + "Page X of Y", `count-text` = "start–end of total" item range + prev/next around the current page number. Reflected. |
46
+ | `page` | `page` | `number` | `undefined` | Controlled current page (1-based). When set, the element only emits `rel-change` and waits for the parent to update `page`; leave unset for uncontrolled behaviour. |
47
+ | `defaultPage` | `defaultpage` | `number` | `1` | Starting page for uncontrolled use (ignored when `page` is set). Attribute `defaultPage`, also read once as `default-page` on connect. |
48
+ | `totalPages` | `totalpages` | `number` | `0` | Total number of pages. `0` (the default) lets `totalItems` / `perPage` compute the page count instead. Attribute `totalPages`, also read once as `total-pages` on connect. |
49
+ | `totalItems` | `totalitems` | `number` | `0` | Total item count; with `perPage` it computes the page count when `totalPages` is `0` and is the "of N" figure in the count-text readout. Attribute `totalItems`, also read once as `total-items` on connect. |
50
+ | `perPage` | `perpage` | `number` | `10` | Items per page, used to compute the page count from `totalItems` and the "start–end" range in the count-text readout. Attribute `perPage`, also read once as `per-page` on connect. |
51
+ | `showLabel` | `showlabel` | `boolean` | `false` | DELIBERATE DIVERGENCE — do not flip this default to `true`. Figma's `Type=Extended` has no boolean for the caption: the "Viewing page 1 of 10" text is a fixed child of both Extended variants and is load-bearing for their 78px height (40 + spacing-md + 22). Here it stays opt-in. Ruled by the user: our behaviour stands and the DESIGN FILE follows our docs. Defaulting it on would silently add 38px to every existing extended pagination. |
52
+ | `disabled` | `disabled` | `boolean` | `false` | Dims the whole control to 40% opacity, shows a `not-allowed` cursor and ignores every page change. Reflected. |
53
+ | `hrefTemplate` | `hreftemplate` | `string` | `""` | Reserved for link-mode pagination. Currently accepted but not rendered: every page control is a `<button>`, so navigate in your `rel-change` handler instead. |
54
+ | `ariaLabel` | `arialabel` | `string` | `"Pagination"` | Accessible name of the `role="navigation"` landmark (attribute `ariaLabel`). Set it when a page contains more than one pagination control. |
55
+
56
+ ## Events
57
+
58
+ | Event | Detail | Bubbles / composed | Description |
59
+ | --- | --- | --- | --- |
60
+ | `rel-change` | `{ page: newPage }` | bubbles / composed | Fired when the user picks another page (prev/next or a page number). Detail: `{ page: number }` (1-based). In controlled mode the parent must then set `page`. |
61
+
62
+ ## Slots
63
+
64
+ | Slot | Description |
65
+ | --- | --- |
66
+ | — | This element has no slots. |
67
+
68
+ ## CSS Parts
69
+
70
+ | Part | Description |
71
+ | --- | --- |
72
+ | `base` | The `role="navigation"` root of the extended layout (page buttons plus the optional "Viewing page" label). |
73
+ | `label` | The `role="navigation"` root row of the count-text layout (item-range text plus prev/next nav). |
74
+
75
+ <!-- readme-gen:end -->
76
+
77
+ ## Accessibility
78
+
79
+ - The control is a `role="navigation"` landmark named by `ariaLabel` (default "Pagination"); give each pager on a page a distinct name.
80
+ - Prev/next are native buttons labelled "Previous page" / "Next page"; they are disabled (not hidden) on the first / last page.
81
+ - Each page chip is a native button labelled "Page N" with `aria-current="page"` on the current one. Abbreviated first/last chips (e.g. "368k") keep the exact number in their `title`.
82
+ - Every page change is announced to screen readers as "Page N of M" via the shared live region.
83
+ - If a prev/next button becomes disabled while it has focus (you reached the first/last page), focus moves to the other nav button instead of being lost.
84
+
85
+ | Key | Action |
86
+ | --- | --- |
87
+ | `Tab` / `Shift+Tab` | Move between the prev button, page chips and next button |
88
+ | `Enter` / `Space` | Activate the focused button (native behaviour) |
89
+
90
+ No arrow-key navigation is implemented; all controls are regular tab stops.
91
+
92
+ ## Notes / Edge Cases
93
+
94
+ - **Attribute names.** The Lit attributes are the lowercase property names (`totalPages`, `defaultPage`, `totalItems`, `perPage`, `showLabel`, `hrefTemplate`, `ariaLabel` — HTML attributes are case-insensitive). The kebab-case forms `total-pages`, `default-page`, `total-items`, `per-page` and `page` are additionally read **once** when the element connects, so they work in static markup but not for later updates; set the property in code.
95
+ - **Page count.** `totalPages` wins when greater than `0`; otherwise the count is `ceil(totalItems / perPage)`. With neither set the element renders no page chips and both nav buttons disabled.
96
+ - **Controlled vs uncontrolled.** With `page` unset the element tracks the current page itself starting at `defaultPage`. Once `page` is set it stays on that page until the parent changes it — clicking only emits `rel-change`.
97
+ - **Ellipsis window.** Up to 7 pages render in full. Beyond that: the first 5 + last near the start, first + last 5 near the end, otherwise first, current ±1 and last, with `…` between. Far first/last chips abbreviate large numbers (`10000` → `10k`, `2500000` → `2.5M`); chips inside the window are never abbreviated.
98
+ - **Responsive.** `extended` uses a container query on the host: between 480px and 768px only first, last and current ±1 stay visible; under 480px the whole control swaps to the compact layout (media-query fallback for browsers without container queries). The `label` part belongs to the `count-text` layout, not to the "Viewing page" caption.
99
+ - **`hrefTemplate`** is accepted but currently unused — chips are always buttons, not links. Perform navigation in the `rel-change` handler.
100
+ - **`rel-change` is not fired** for the current page, out-of-range pages, or while `disabled`.