@hortonstudio/main 1.9.8 → 1.9.10

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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## **Overview**
4
4
 
5
- The accessibility system provides 7 modular functions to enhance website accessibility and functionality. Each function operates independently and can be customized through data attributes.
5
+ The accessibility system provides 8 modular functions to enhance website accessibility and functionality. Each function operates independently and can be customized through data attributes.
6
6
 
7
7
  **Note:** This module auto-initializes and loads all functions on page load.
8
8
 
@@ -61,6 +61,13 @@ Universal dropdown system for FAQ, summary/read-more, and general toggle compone
61
61
 
62
62
  ---
63
63
 
64
+ ### **8. Pagination**
65
+ Complete pagination system for paginated lists with controls, counters, dot navigation, and infinite looping. Supports responsive layouts and accessibility features.
66
+
67
+ **Use case:** Multi-item paginated lists (product grids, blog lists, search results) and carousels (with `show-1` config).
68
+
69
+ ---
70
+
64
71
  ## **Documentation**
65
72
 
66
73
  Each function has detailed documentation in its respective folder:
@@ -72,6 +79,7 @@ Each function has detailed documentation in its respective folder:
72
79
  - `functions/text-synchronization/README.md`
73
80
  - `functions/toc/README.md`
74
81
  - `functions/dropdown/README.md`
82
+ - `functions/pagination/README.md`
75
83
 
76
84
  ---
77
85
 
@@ -12,7 +12,8 @@ export async function init() {
12
12
  "click-forwarding": () => import("./functions/click-forwarding/click-forwarding.js"),
13
13
  "text-synchronization": () => import("./functions/text-synchronization/text-synchronization.js"),
14
14
  "toc": () => import("./functions/toc/toc.js"),
15
- "dropdown": () => import("./functions/dropdown/dropdown.js")
15
+ "dropdown": () => import("./functions/dropdown/dropdown.js"),
16
+ "pagination": () => import("./functions/pagination/pagination.js")
16
17
  };
17
18
 
18
19
  const loadFunction = async (functionName) => {
@@ -0,0 +1,428 @@
1
+ # **Pagination System Documentation**
2
+
3
+ ## **Overview**
4
+
5
+ Complete pagination system for paginated lists with controls, counters, dot navigation, and infinite looping. Features responsive layouts, ARIA live announcements, and full keyboard accessibility.
6
+
7
+ **Note:** This function auto-initializes on page load as part of the accessibility system.
8
+
9
+ ---
10
+
11
+ ## **Features**
12
+
13
+ - **Infinite Loop Pagination**: Seamless page transitions with cloned pages
14
+ - **Responsive Layouts**: Different items per page for desktop/mobile
15
+ - **Page Controls**: Next/Previous buttons with infinite looping
16
+ - **Page Counter**: Live-updating "X / Y" page indicator
17
+ - **Dot Navigation**: Visual page indicators with click/keyboard support
18
+ - **Auto-height Management**: Smooth height transitions between pages
19
+ - **Focus Management**: Uses `inert` attribute for inactive pages
20
+ - **ARIA Live Announcements**: Screen reader announcements for page changes
21
+ - **Mobile Auto-scroll**: Scrolls controls into view on mobile after navigation
22
+ - **Infinite Mode**: Disable all pagination for continuous scrolling
23
+
24
+ ---
25
+
26
+ ## **Required Structure**
27
+
28
+ ### **Wrapper** *(required)*
29
+
30
+ **Attribute:** `data-hs-pagination="wrapper"`
31
+
32
+ **What it does:** Main container for entire pagination instance.
33
+
34
+ ---
35
+
36
+ ### **List** *(required)*
37
+
38
+ **Attribute:** `data-hs-pagination="list"`
39
+
40
+ **What it does:** Container for all items to be paginated. System will split these into pages.
41
+
42
+ **Important:** Must be a direct child of a wrapper element (typically a div).
43
+
44
+ ---
45
+
46
+ ### **Next Button** *(required)*
47
+
48
+ **Attribute:** `data-hs-pagination="next"`
49
+
50
+ **What it does:** Navigate to next page. Loops to first page after last page.
51
+
52
+ **Accessibility:** Automatically receives `aria-label="Go to next page"`
53
+
54
+ ---
55
+
56
+ ### **Previous Button** *(required)*
57
+
58
+ **Attribute:** `data-hs-pagination="previous"`
59
+
60
+ **What it does:** Navigate to previous page. Loops to last page from first page.
61
+
62
+ **Accessibility:** Automatically receives `aria-label="Go to previous page"`
63
+
64
+ ---
65
+
66
+ ### **Controls Container** *(required for configuration)*
67
+
68
+ **Attribute:** `data-hs-pagination="controls"`
69
+
70
+ **What it does:** Container for pagination controls AND configuration via `data-hs-config`.
71
+
72
+ **Configuration Syntax:**
73
+ ```
74
+ data-hs-config="[option], [option], ..."
75
+ ```
76
+
77
+ **Configuration Options:**
78
+
79
+ **Show Items (Desktop):**
80
+ ```html
81
+ data-hs-config="show-6"
82
+ ```
83
+ Shows 6 items per page on desktop (default: 6)
84
+
85
+ **Show Items (Mobile):**
86
+ ```html
87
+ data-hs-config="show-3-mobile"
88
+ ```
89
+ Shows 3 items per page on mobile (default: desktop value)
90
+
91
+ **Infinite Mode:**
92
+ ```html
93
+ data-hs-config="infinite"
94
+ ```
95
+ Disables pagination completely (hides controls and dots, shows all items)
96
+
97
+ **Combined Example:**
98
+ ```html
99
+ <div data-hs-pagination="controls" data-hs-config="show-4, show-2-mobile">
100
+ <!-- Buttons, counter, etc. -->
101
+ </div>
102
+ ```
103
+
104
+ ---
105
+
106
+ ### **Counter** *(optional)*
107
+
108
+ **Attribute:** `data-hs-pagination="counter"`
109
+
110
+ **What it does:** Displays current page and total pages (e.g., "2 / 5").
111
+
112
+ **Accessibility:** Automatically receives:
113
+ - `aria-live="polite"` - Announces changes
114
+ - `aria-label="Current page"`
115
+
116
+ ---
117
+
118
+ ### **Dots Container** *(optional)*
119
+
120
+ **Attribute:** `data-hs-pagination="dots"`
121
+
122
+ **What it does:** Container for pagination dots. Requires template dot as first child.
123
+
124
+ **Template Requirements:**
125
+ - At least one child element (used as template)
126
+ - Use `.is-active` class to designate active template
127
+ - If only one template, same used for active/inactive states
128
+
129
+ **Accessibility:** System automatically adds:
130
+ - Individual dots via separate pagination dots system
131
+ - `role="button"`, `tabindex="0"`, `aria-label` on each dot
132
+ - `aria-current="page"` on active dot
133
+
134
+ ---
135
+
136
+ ## **Usage Example**
137
+
138
+ ### **Basic Pagination**
139
+
140
+ ```html
141
+ <div data-hs-pagination="wrapper">
142
+ <!-- Wrapper for list -->
143
+ <div>
144
+ <div data-hs-pagination="list">
145
+ <div>Item 1</div>
146
+ <div>Item 2</div>
147
+ <div>Item 3</div>
148
+ <div>Item 4</div>
149
+ <div>Item 5</div>
150
+ <div>Item 6</div>
151
+ <div>Item 7</div>
152
+ <div>Item 8</div>
153
+ </div>
154
+ </div>
155
+
156
+ <!-- Controls -->
157
+ <div data-hs-pagination="controls" data-hs-config="show-4, show-2-mobile">
158
+ <button data-hs-pagination="previous">Previous</button>
159
+ <div data-hs-pagination="counter">1 / 2</div>
160
+ <button data-hs-pagination="next">Next</button>
161
+ </div>
162
+
163
+ <!-- Dots -->
164
+ <div data-hs-pagination="dots">
165
+ <div class="dot is-active"></div> <!-- Active template -->
166
+ <div class="dot"></div> <!-- Inactive template -->
167
+ </div>
168
+ </div>
169
+ ```
170
+
171
+ ---
172
+
173
+ ### **Infinite Mode (No Pagination)**
174
+
175
+ ```html
176
+ <div data-hs-pagination="wrapper">
177
+ <div>
178
+ <div data-hs-pagination="list">
179
+ <!-- All items displayed, no pagination -->
180
+ <div>Item 1</div>
181
+ <div>Item 2</div>
182
+ <div>Item 3</div>
183
+ </div>
184
+ </div>
185
+
186
+ <div data-hs-pagination="controls" data-hs-config="infinite">
187
+ <!-- Controls hidden automatically -->
188
+ <button data-hs-pagination="previous">Previous</button>
189
+ <button data-hs-pagination="next">Next</button>
190
+ </div>
191
+ </div>
192
+ ```
193
+
194
+ ---
195
+
196
+ ## **Responsive Breakpoints**
197
+
198
+ Uses CSS custom property `--data-hs-break` to detect layout:
199
+
200
+ ```css
201
+ .pagination-list {
202
+ --data-hs-break: "desktop";
203
+ }
204
+
205
+ @media (max-width: 768px) {
206
+ .pagination-list {
207
+ --data-hs-break: "mobile";
208
+ }
209
+ }
210
+ ```
211
+
212
+ **When breakpoint changes:**
213
+ - Re-calculates items per page
214
+ - Re-generates pagination
215
+ - Maintains current page when possible
216
+ - Updates dots accordingly
217
+
218
+ ---
219
+
220
+ ## **Key Attributes Summary**
221
+
222
+ | Attribute | Purpose | Required | Element Type |
223
+ | ----- | ----- | ----- | ----- |
224
+ | `data-hs-pagination="wrapper"` | Main container | **Required** | Wrapper div |
225
+ | `data-hs-pagination="list"` | Items to paginate | **Required** | List container |
226
+ | `data-hs-pagination="next"` | Next button | **Required** | `<button>` |
227
+ | `data-hs-pagination="previous"` | Previous button | **Required** | `<button>` |
228
+ | `data-hs-pagination="controls"` | Controls + config | Required for config | Wrapper div |
229
+ | `data-hs-pagination="counter"` | Page counter | Optional | Any element |
230
+ | `data-hs-pagination="dots"` | Dots container | Optional | Wrapper div |
231
+
232
+ ---
233
+
234
+ ## **Accessibility Features**
235
+
236
+ ### **ARIA Live Regions**
237
+ - Dynamically created live region for announcements
238
+ - Announces page changes: "Page 2 of 5"
239
+ - Uses `aria-live="assertive"` and `aria-atomic="true"`
240
+ - Visually hidden with sr-only styling
241
+
242
+ ### **Button Accessibility**
243
+ - Next/Previous buttons: `aria-label` with clear descriptions
244
+ - Counter: `aria-live="polite"` for automatic announcements
245
+
246
+ ### **Focus Management**
247
+ - Active page: No `inert` attribute (focusable)
248
+ - Inactive pages: `inert` attribute prevents tab navigation
249
+ - Focus stays on controls during navigation
250
+
251
+ ### **Dot Navigation**
252
+ - Handled by separate pagination dots system
253
+ - Full keyboard support (Enter/Space)
254
+ - ARIA attributes for current page
255
+
256
+ ---
257
+
258
+ ## **How It Works**
259
+
260
+ ### **Initialization:**
261
+ 1. Finds all `[data-hs-pagination="wrapper"]` containers
262
+ 2. Reads configuration from `data-hs-config`
263
+ 3. Calculates total pages based on items and config
264
+ 4. Splits items into page lists
265
+ 5. Clones pages for infinite loop (adds before/after)
266
+ 6. Positions wrapper at page 1 (middle clone)
267
+ 7. Initializes dots via pagination dots system
268
+
269
+ ### **Navigation:**
270
+ 1. User clicks next/previous or dot
271
+ 2. Updates current page index
272
+ 3. Animates wrapper with CSS transform
273
+ 4. On loop boundary, instantly resets to real page
274
+ 5. Updates counter, announces change, manages focus
275
+ 6. Auto-scrolls on mobile to keep controls visible
276
+
277
+ ### **Responsive:**
278
+ 1. ResizeObserver monitors wrapper size
279
+ 2. Detects breakpoint via CSS custom property
280
+ 3. Re-initializes pagination if breakpoint changes
281
+ 4. Maintains current page position when possible
282
+
283
+ ### **Infinite Mode:**
284
+ 1. Hides all pagination controls and dots
285
+ 2. Shows all items without splitting
286
+ 3. No page transitions or animations
287
+
288
+ ---
289
+
290
+ ## **Pagination Behavior**
291
+
292
+ ### **Single Page:**
293
+ - Controls and dots hidden automatically
294
+ - All items visible
295
+ - No navigation needed
296
+
297
+ ### **Multiple Pages:**
298
+ - Infinite loop (last → first, first → last)
299
+ - Clones pages at boundaries for seamless transitions
300
+ - Instant position reset after loop animation
301
+ - Smooth CSS transitions between pages
302
+
303
+ ### **Mobile Scroll:**
304
+ After page change on mobile:
305
+ - Auto-scrolls to keep controls visible
306
+ - 5rem clearance from bottom of viewport
307
+ - Smooth scroll behavior
308
+
309
+ ---
310
+
311
+ ## **Dot Navigation Integration**
312
+
313
+ The pagination system integrates with the separate pagination dots system:
314
+
315
+ **How Integration Works:**
316
+ 1. Pagination sets attributes on dots container:
317
+ - `data-hs-pagination=""` (empty, triggers dots system)
318
+ - `data-hs-pagination-total` (total pages)
319
+ - `data-hs-pagination-current` (current page)
320
+ 2. Dots system handles rendering and click events
321
+ 3. Pagination listens for `hs-pagination-change` custom event
322
+ 4. Updates are bidirectional via `hsPaginationUpdate()` API
323
+
324
+ **See:** `/autoInit/accessibility/functions/pagination/README.md` for full dots documentation
325
+
326
+ ---
327
+
328
+ ## **Configuration Examples**
329
+
330
+ ### **Desktop: 6 items, Mobile: 3 items**
331
+ ```html
332
+ <div data-hs-config="show-6, show-3-mobile">
333
+ ```
334
+
335
+ ### **Desktop: 4 items, Mobile: 2 items**
336
+ ```html
337
+ <div data-hs-config="show-4, show-2-mobile">
338
+ ```
339
+
340
+ ### **Same on all devices (8 items)**
341
+ ```html
342
+ <div data-hs-config="show-8">
343
+ ```
344
+
345
+ ### **Disable pagination (infinite mode)**
346
+ ```html
347
+ <div data-hs-config="infinite">
348
+ ```
349
+
350
+ ---
351
+
352
+ ## **Edge Cases**
353
+
354
+ ### **No Items:**
355
+ - Early exit, no initialization
356
+ - Console warning displayed
357
+
358
+ ### **Single Page:**
359
+ - Controls hidden with `display: none` and `aria-hidden="true"`
360
+ - Dots hidden similarly
361
+ - All items displayed on single page
362
+
363
+ ### **Infinite Mode:**
364
+ - Controls completely hidden
365
+ - Dots completely hidden
366
+ - List displayed as-is
367
+ - No pagination logic runs
368
+
369
+ ### **Layout Changes:**
370
+ - ResizeObserver detects breakpoint changes
371
+ - Re-initializes pagination with new item count
372
+ - Tries to maintain current page position
373
+
374
+ ---
375
+
376
+ ## **Performance**
377
+
378
+ - Uses CSS custom properties for breakpoint detection
379
+ - ResizeObserver for efficient layout monitoring
380
+ - `inert` attribute prevents unnecessary focus handling
381
+ - Cleanup on destroy for Barba.js compatibility
382
+ - Efficient DOM cloning and manipulation
383
+ - CSS transitions (not JavaScript animations) for page changes
384
+
385
+ ---
386
+
387
+ ## **Common Issues**
388
+
389
+ **Pagination not working:**
390
+ 1. Ensure wrapper, list, next, and previous elements exist
391
+ 2. Check `data-hs-config` has valid configuration
392
+ 3. Verify list has children elements
393
+ 4. Check console for warnings
394
+
395
+ **Items not splitting into pages:**
396
+ 1. Ensure `data-hs-config` specifies `show-X`
397
+ 2. Check that total items > items per page
398
+ 3. Verify CSS custom property `--data-hs-break` is set
399
+
400
+ **Dots not appearing:**
401
+ 1. Ensure dots container has template children
402
+ 2. Check that there are multiple pages (>1)
403
+ 3. Verify pagination accessibility system is loaded
404
+ 4. Check that `data-hs-pagination="dots"` attribute is correct
405
+
406
+ **Layout not responsive:**
407
+ 1. Add `--data-hs-break` CSS custom property to list
408
+ 2. Ensure media query updates the property
409
+ 3. Check ResizeObserver is not being blocked
410
+
411
+ **Controls always hidden:**
412
+ 1. Check `data-hs-config` doesn't include "infinite"
413
+ 2. Ensure total items > items per page
414
+ 3. Verify controls container exists
415
+
416
+ ---
417
+
418
+ ## **Notes**
419
+
420
+ - Each wrapper is an independent instance
421
+ - Pages are cloned for infinite looping
422
+ - Dots handled by separate pagination dots system
423
+ - Works with any element type for items
424
+ - Requires GSAP-less approach (uses CSS transitions)
425
+ - Barba.js compatible with proper cleanup
426
+ - Auto-initializes as part of accessibility system
427
+ - Supports any number of items
428
+ - Mobile-first responsive behavior