react-virtual-renderer 1.0.3
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/README.md +170 -0
- package/dist/App.d.ts +3 -0
- package/dist/App.d.ts.map +1 -0
- package/dist/App.js +7 -0
- package/dist/App.js.map +1 -0
- package/dist/accessibility/a11y.d.ts +111 -0
- package/dist/accessibility/a11y.d.ts.map +1 -0
- package/dist/accessibility/a11y.js +254 -0
- package/dist/accessibility/a11y.js.map +1 -0
- package/dist/components/VirtualGrid.d.ts +8 -0
- package/dist/components/VirtualGrid.d.ts.map +1 -0
- package/dist/components/VirtualGrid.js +187 -0
- package/dist/components/VirtualGrid.js.map +1 -0
- package/dist/components/VirtualList.d.ts +8 -0
- package/dist/components/VirtualList.d.ts.map +1 -0
- package/dist/components/VirtualList.js +102 -0
- package/dist/components/VirtualList.js.map +1 -0
- package/dist/core/MeasurementSystem.d.ts +52 -0
- package/dist/core/MeasurementSystem.d.ts.map +1 -0
- package/dist/core/MeasurementSystem.js +138 -0
- package/dist/core/MeasurementSystem.js.map +1 -0
- package/dist/core/VirtualizationEngine.d.ts +65 -0
- package/dist/core/VirtualizationEngine.d.ts.map +1 -0
- package/dist/core/VirtualizationEngine.js +203 -0
- package/dist/core/VirtualizationEngine.js.map +1 -0
- package/dist/examples/AdvancedExamples.d.ts +24 -0
- package/dist/examples/AdvancedExamples.d.ts.map +1 -0
- package/dist/examples/AdvancedExamples.js +216 -0
- package/dist/examples/AdvancedExamples.js.map +1 -0
- package/dist/examples/Example.d.ts +26 -0
- package/dist/examples/Example.d.ts.map +1 -0
- package/dist/examples/Example.js +186 -0
- package/dist/examples/Example.js.map +1 -0
- package/dist/hooks/useInfiniteScroll.d.ts +17 -0
- package/dist/hooks/useInfiniteScroll.d.ts.map +1 -0
- package/dist/hooks/useInfiniteScroll.js +41 -0
- package/dist/hooks/useInfiniteScroll.js.map +1 -0
- package/dist/hooks/useLazyLoad.d.ts +16 -0
- package/dist/hooks/useLazyLoad.d.ts.map +1 -0
- package/dist/hooks/useLazyLoad.js +34 -0
- package/dist/hooks/useLazyLoad.js.map +1 -0
- package/dist/hooks/useScrollRestoration.d.ts +10 -0
- package/dist/hooks/useScrollRestoration.d.ts.map +1 -0
- package/dist/hooks/useScrollRestoration.js +63 -0
- package/dist/hooks/useScrollRestoration.js.map +1 -0
- package/dist/hooks/useVirtualList.d.ts +33 -0
- package/dist/hooks/useVirtualList.d.ts.map +1 -0
- package/dist/hooks/useVirtualList.js +226 -0
- package/dist/hooks/useVirtualList.js.map +1 -0
- package/dist/hooks/useVirtualizedSearch.d.ts +40 -0
- package/dist/hooks/useVirtualizedSearch.d.ts.map +1 -0
- package/dist/hooks/useVirtualizedSearch.js +168 -0
- package/dist/hooks/useVirtualizedSearch.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +11 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +6 -0
- package/dist/main.js.map +1 -0
- package/dist/performance/metrics.d.ts +110 -0
- package/dist/performance/metrics.d.ts.map +1 -0
- package/dist/performance/metrics.js +310 -0
- package/dist/performance/metrics.js.map +1 -0
- package/dist/plugin.d.ts +182 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +409 -0
- package/dist/plugin.js.map +1 -0
- package/dist/types.d.ts +84 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/helpers.d.ts +66 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +166 -0
- package/dist/utils/helpers.js.map +1 -0
- package/package.json +111 -0
package/README.md
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# React Virtual Renderer
|
|
2
|
+
|
|
3
|
+
High-performance React virtualization library for **large lists, grids, tables, infinite scrolling, dynamic heights, and masonry layouts**.
|
|
4
|
+
|
|
5
|
+
A modern alternative to react-window and react-virtualized with built-in accessibility, dynamic sizing, and TypeScript support.
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Why React Virtual Renderer?
|
|
15
|
+
|
|
16
|
+
Rendering thousands of DOM nodes can severely impact performance.
|
|
17
|
+
|
|
18
|
+
React Virtual Renderer only renders visible items, allowing your application to handle:
|
|
19
|
+
|
|
20
|
+
- 10,000+ rows
|
|
21
|
+
- Infinite scrolling
|
|
22
|
+
- Dynamic item heights
|
|
23
|
+
- Large tables
|
|
24
|
+
- Chat applications
|
|
25
|
+
- Product catalogs
|
|
26
|
+
- Masonry layouts
|
|
27
|
+
|
|
28
|
+
while maintaining smooth scrolling and low memory usage.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Features
|
|
33
|
+
|
|
34
|
+
### Performance
|
|
35
|
+
|
|
36
|
+
- Virtualized Lists
|
|
37
|
+
- Virtualized Grids
|
|
38
|
+
- Infinite Scrolling
|
|
39
|
+
- Dynamic Heights
|
|
40
|
+
- Variable Item Sizes
|
|
41
|
+
- Overscan Optimization
|
|
42
|
+
- Scroll Position Restoration
|
|
43
|
+
|
|
44
|
+
### Developer Experience
|
|
45
|
+
|
|
46
|
+
- TypeScript First
|
|
47
|
+
- Tree Shakeable
|
|
48
|
+
- Lightweight Bundle
|
|
49
|
+
- Zero Dependencies
|
|
50
|
+
- React 18 & React 19 Support
|
|
51
|
+
|
|
52
|
+
### Accessibility
|
|
53
|
+
|
|
54
|
+
- WCAG 2.1 AA Friendly
|
|
55
|
+
- Keyboard Navigation
|
|
56
|
+
- ARIA Support
|
|
57
|
+
- Screen Reader Compatible
|
|
58
|
+
|
|
59
|
+
### Layouts
|
|
60
|
+
|
|
61
|
+
- List
|
|
62
|
+
- Grid
|
|
63
|
+
- Masonry
|
|
64
|
+
- Feed Layout
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Installation
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npm install react-virtual-renderer
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
or
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
yarn add react-virtual-renderer
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Quick Start
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
import { VirtualList } from "react-virtual-renderer";
|
|
86
|
+
|
|
87
|
+
const items = Array.from({ length: 10000 }, (_, index) => ({
|
|
88
|
+
id: index,
|
|
89
|
+
name: `Item ${index}`,
|
|
90
|
+
}));
|
|
91
|
+
|
|
92
|
+
export default function App() {
|
|
93
|
+
return (
|
|
94
|
+
<VirtualList
|
|
95
|
+
items={items}
|
|
96
|
+
height={600}
|
|
97
|
+
renderItem={({ item }) => <div style={{ padding: 12 }}>{item.name}</div>}
|
|
98
|
+
/>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Common Use Cases
|
|
106
|
+
|
|
107
|
+
- Chat Applications
|
|
108
|
+
- Messaging Systems
|
|
109
|
+
- Activity Feeds
|
|
110
|
+
- Social Networks
|
|
111
|
+
- Infinite Scroll Lists
|
|
112
|
+
- Data Tables
|
|
113
|
+
- Admin Dashboards
|
|
114
|
+
- Product Catalogs
|
|
115
|
+
- E-commerce Grids
|
|
116
|
+
- Analytics Dashboards
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Comparison
|
|
121
|
+
|
|
122
|
+
| Feature | React Virtual Renderer | react-window | react-virtualized |
|
|
123
|
+
| --------------- | ---------------------- | ------------ | ----------------- |
|
|
124
|
+
| Dynamic Heights | ✅ | ⚠️ | ⚠️ |
|
|
125
|
+
| Infinite Scroll | ✅ | ❌ | ⚠️ |
|
|
126
|
+
| Masonry Layout | ✅ | ❌ | ⚠️ |
|
|
127
|
+
| Accessibility | ✅ | ❌ | ⚠️ |
|
|
128
|
+
| TypeScript | ✅ | ⚠️ | ⚠️ |
|
|
129
|
+
| Lightweight | ✅ | ✅ | ❌ |
|
|
130
|
+
| React 19 Ready | ✅ | ⚠️ | ⚠️ |
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Roadmap
|
|
135
|
+
|
|
136
|
+
### v1.x
|
|
137
|
+
|
|
138
|
+
- Virtual Lists
|
|
139
|
+
- Virtual Grids
|
|
140
|
+
- Infinite Scroll
|
|
141
|
+
- Dynamic Heights
|
|
142
|
+
- Accessibility
|
|
143
|
+
|
|
144
|
+
### v2.x
|
|
145
|
+
|
|
146
|
+
- Masonry Layouts
|
|
147
|
+
- Waterfall Layouts
|
|
148
|
+
- Advanced Grid System
|
|
149
|
+
|
|
150
|
+
### v3.x
|
|
151
|
+
|
|
152
|
+
- Visual Debugger
|
|
153
|
+
- Performance Inspector
|
|
154
|
+
- Analytics Dashboard
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Documentation
|
|
159
|
+
|
|
160
|
+
- Getting Started
|
|
161
|
+
- API Reference
|
|
162
|
+
- Accessibility Guide
|
|
163
|
+
- Performance Guide
|
|
164
|
+
- Examples
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## License
|
|
169
|
+
|
|
170
|
+
MIT
|
package/dist/App.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../src/App.tsx"],"names":[],"mappings":"AAEA,iBAAS,GAAG,4CAOX;AAED,eAAe,GAAG,CAAA"}
|
package/dist/App.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import VirtualizeDemo from "./examples/Example";
|
|
3
|
+
function App() {
|
|
4
|
+
return (_jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: 20, padding: 20 }, children: _jsx(VirtualizeDemo, {}) }));
|
|
5
|
+
}
|
|
6
|
+
export default App;
|
|
7
|
+
//# sourceMappingURL=App.js.map
|
package/dist/App.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"App.js","sourceRoot":"","sources":["../src/App.tsx"],"names":[],"mappings":";AAAA,OAAO,cAAc,MAAM,oBAAoB,CAAA;AAE/C,SAAS,GAAG;IAEV,OAAO,CACL,cAAK,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,YAC5E,KAAC,cAAc,KAAG,GACd,CACP,CAAA;AACH,CAAC;AAED,eAAe,GAAG,CAAA"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accessibility module for WCAG 2.1 AA compliance
|
|
3
|
+
* Provides keyboard navigation, screen reader support, and ARIA labels
|
|
4
|
+
*/
|
|
5
|
+
export interface A11yConfig {
|
|
6
|
+
enableKeyboardNav?: boolean;
|
|
7
|
+
enableScreenReaderAnnouncements?: boolean;
|
|
8
|
+
ariaLabel?: string;
|
|
9
|
+
ariaDescribedBy?: string;
|
|
10
|
+
role?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Generate unique IDs for accessibility attributes
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateA11yIds(prefix: string): {
|
|
16
|
+
container: string;
|
|
17
|
+
announcer: string;
|
|
18
|
+
option: (index: number) => string;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Hook for keyboard navigation in virtualized lists
|
|
22
|
+
*/
|
|
23
|
+
export declare function useA11yKeyboardNav({ itemCount, onSelectItem, onSelectIndex, }: {
|
|
24
|
+
itemCount: number;
|
|
25
|
+
onSelectItem?: (index: number) => void;
|
|
26
|
+
onSelectIndex?: (index: number) => void;
|
|
27
|
+
}): {
|
|
28
|
+
selectedIndex: number;
|
|
29
|
+
focusedIndex: number;
|
|
30
|
+
handleKeyDown: (e: React.KeyboardEvent) => void;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Screen reader announcements
|
|
34
|
+
*/
|
|
35
|
+
export declare function announceToScreenReader(message: string, priority?: 'polite' | 'assertive'): void;
|
|
36
|
+
/**
|
|
37
|
+
* Generate ARIA attributes for list items
|
|
38
|
+
*/
|
|
39
|
+
export declare function getItemA11yProps(index: number, total: number, isSelected?: boolean): {
|
|
40
|
+
'aria-posinset': number;
|
|
41
|
+
'aria-setsize': number;
|
|
42
|
+
'aria-selected': boolean;
|
|
43
|
+
role: string;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Generate ARIA attributes for container
|
|
47
|
+
*/
|
|
48
|
+
export declare function getContainerA11yProps(label: string, describedBy?: string): {
|
|
49
|
+
role: string;
|
|
50
|
+
'aria-label': string;
|
|
51
|
+
'aria-describedby': string | undefined;
|
|
52
|
+
'aria-multiselectable': boolean;
|
|
53
|
+
};
|
|
54
|
+
import React from 'react';
|
|
55
|
+
/**
|
|
56
|
+
* Screen reader friendly virtual list announcement
|
|
57
|
+
* Announces when list is scrolled or filtered
|
|
58
|
+
*/
|
|
59
|
+
export declare function useA11yAnnouncements({ itemCount, filteredCount, searchQuery, isLoading, }: {
|
|
60
|
+
itemCount: number;
|
|
61
|
+
filteredCount?: number;
|
|
62
|
+
searchQuery?: string;
|
|
63
|
+
isLoading?: boolean;
|
|
64
|
+
}): void;
|
|
65
|
+
/**
|
|
66
|
+
* Ensure keyboard-accessible interactions
|
|
67
|
+
*/
|
|
68
|
+
export declare const a11yEventHandlers: {
|
|
69
|
+
/**
|
|
70
|
+
* Handle click or Enter/Space key
|
|
71
|
+
*/
|
|
72
|
+
onClickOrKey: (callback: () => void) => {
|
|
73
|
+
onClick: () => void;
|
|
74
|
+
onKeyDown: (e: React.KeyboardEvent) => void;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Make any element keyboard accessible
|
|
78
|
+
*/
|
|
79
|
+
makeKeyboardAccessible: (element: HTMLElement, callback: () => void) => void;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Focus management utilities
|
|
83
|
+
*/
|
|
84
|
+
export declare const focusManagement: {
|
|
85
|
+
/**
|
|
86
|
+
* Set focus with announcement
|
|
87
|
+
*/
|
|
88
|
+
focusWithAnnouncement: (element: HTMLElement, message?: string) => void;
|
|
89
|
+
/**
|
|
90
|
+
* Trap focus within container (for modals, etc.)
|
|
91
|
+
*/
|
|
92
|
+
trapFocus: (container: HTMLElement) => () => void;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* ARIA live region for dynamic content
|
|
96
|
+
*/
|
|
97
|
+
export declare class AriaLiveRegion {
|
|
98
|
+
private region;
|
|
99
|
+
constructor(priority?: 'polite' | 'assertive');
|
|
100
|
+
announce(message: string): void;
|
|
101
|
+
clear(): void;
|
|
102
|
+
remove(): void;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Accessibility audit helper
|
|
106
|
+
*/
|
|
107
|
+
export declare function auditAccessibility(container: HTMLElement): {
|
|
108
|
+
warnings: string[];
|
|
109
|
+
errors: string[];
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=a11y.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a11y.d.ts","sourceRoot":"","sources":["../../src/accessibility/a11y.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,UAAU;IACvB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,+BAA+B,CAAC,EAAE,OAAO,CAAC;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM;;;oBAItB,MAAM;EAE7B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,EAC/B,SAAS,EACT,YAAY,EACZ,aAAa,GAChB,EAAE;IACC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C;;;uBAKW,mBAAmB;EA+C9B;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAClC,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,QAAQ,GAAG,WAAsB,QAoB9C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC5B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,UAAU,CAAC,EAAE,OAAO;;;;;EAQvB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM;;;;;EAOxE;AAED,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,SAAS,EACT,aAAa,EACb,WAAW,EACX,SAAS,GACZ,EAAE;IACC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB,QAqBA;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB;IAC1B;;OAEG;6BACsB,MAAM,IAAI;uBAAJ,IAAI;uBAEhB,mBAAmB;;IAQtC;;OAEG;sCAEU,WAAW,YACV,MAAM,IAAI;CAY3B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe;IACxB;;OAEG;qCAC8B,WAAW,YAAY,MAAM;IAO9D;;OAEG;2BACoB,WAAW;CA4BrC,CAAC;AAEF;;GAEG;AACH,qBAAa,cAAc;IACvB,OAAO,CAAC,MAAM,CAAc;gBAEhB,QAAQ,GAAE,QAAQ,GAAG,WAAsB;IAYvD,QAAQ,CAAC,OAAO,EAAE,MAAM;IAIxB,KAAK;IAIL,MAAM;CAGT;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,WAAW,GAAG;IACxD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;CACpB,CAgCA"}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accessibility module for WCAG 2.1 AA compliance
|
|
3
|
+
* Provides keyboard navigation, screen reader support, and ARIA labels
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Generate unique IDs for accessibility attributes
|
|
7
|
+
*/
|
|
8
|
+
export function generateA11yIds(prefix) {
|
|
9
|
+
return {
|
|
10
|
+
container: `${prefix}-container`,
|
|
11
|
+
announcer: `${prefix}-announcer`,
|
|
12
|
+
option: (index) => `${prefix}-option-${index}`,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Hook for keyboard navigation in virtualized lists
|
|
17
|
+
*/
|
|
18
|
+
export function useA11yKeyboardNav({ itemCount, onSelectItem, onSelectIndex, }) {
|
|
19
|
+
const [selectedIndex, setSelectedIndex] = React.useState(0);
|
|
20
|
+
const [focusedIndex, setFocusedIndex] = React.useState(0);
|
|
21
|
+
const handleKeyDown = React.useCallback((e) => {
|
|
22
|
+
let newIndex = focusedIndex;
|
|
23
|
+
switch (e.key) {
|
|
24
|
+
case 'ArrowDown':
|
|
25
|
+
e.preventDefault();
|
|
26
|
+
newIndex = Math.min(focusedIndex + 1, itemCount - 1);
|
|
27
|
+
break;
|
|
28
|
+
case 'ArrowUp':
|
|
29
|
+
e.preventDefault();
|
|
30
|
+
newIndex = Math.max(focusedIndex - 1, 0);
|
|
31
|
+
break;
|
|
32
|
+
case 'Home':
|
|
33
|
+
e.preventDefault();
|
|
34
|
+
newIndex = 0;
|
|
35
|
+
break;
|
|
36
|
+
case 'End':
|
|
37
|
+
e.preventDefault();
|
|
38
|
+
newIndex = itemCount - 1;
|
|
39
|
+
break;
|
|
40
|
+
case 'Enter':
|
|
41
|
+
case ' ':
|
|
42
|
+
e.preventDefault();
|
|
43
|
+
setSelectedIndex(focusedIndex);
|
|
44
|
+
onSelectItem?.(focusedIndex);
|
|
45
|
+
onSelectIndex?.(focusedIndex);
|
|
46
|
+
return;
|
|
47
|
+
default:
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
setFocusedIndex(newIndex);
|
|
51
|
+
onSelectIndex?.(newIndex);
|
|
52
|
+
}, [focusedIndex, itemCount, onSelectItem, onSelectIndex]);
|
|
53
|
+
return {
|
|
54
|
+
selectedIndex,
|
|
55
|
+
focusedIndex,
|
|
56
|
+
handleKeyDown,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Screen reader announcements
|
|
61
|
+
*/
|
|
62
|
+
export function announceToScreenReader(message, priority = 'polite') {
|
|
63
|
+
// Create or reuse announcer div
|
|
64
|
+
let announcer = document.getElementById('virtualize-announcer');
|
|
65
|
+
if (!announcer) {
|
|
66
|
+
announcer = document.createElement('div');
|
|
67
|
+
announcer.id = 'virtualize-announcer';
|
|
68
|
+
announcer.setAttribute('aria-live', priority);
|
|
69
|
+
announcer.setAttribute('aria-atomic', 'true');
|
|
70
|
+
announcer.style.position = 'absolute';
|
|
71
|
+
announcer.style.left = '-10000px';
|
|
72
|
+
announcer.style.width = '1px';
|
|
73
|
+
announcer.style.height = '1px';
|
|
74
|
+
announcer.style.overflow = 'hidden';
|
|
75
|
+
document.body.appendChild(announcer);
|
|
76
|
+
}
|
|
77
|
+
announcer.setAttribute('aria-live', priority);
|
|
78
|
+
announcer.textContent = message;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Generate ARIA attributes for list items
|
|
82
|
+
*/
|
|
83
|
+
export function getItemA11yProps(index, total, isSelected) {
|
|
84
|
+
return {
|
|
85
|
+
'aria-posinset': index + 1,
|
|
86
|
+
'aria-setsize': total,
|
|
87
|
+
'aria-selected': isSelected ?? false,
|
|
88
|
+
role: 'option',
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Generate ARIA attributes for container
|
|
93
|
+
*/
|
|
94
|
+
export function getContainerA11yProps(label, describedBy) {
|
|
95
|
+
return {
|
|
96
|
+
role: 'listbox',
|
|
97
|
+
'aria-label': label,
|
|
98
|
+
'aria-describedby': describedBy,
|
|
99
|
+
'aria-multiselectable': false,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
import React from 'react';
|
|
103
|
+
/**
|
|
104
|
+
* Screen reader friendly virtual list announcement
|
|
105
|
+
* Announces when list is scrolled or filtered
|
|
106
|
+
*/
|
|
107
|
+
export function useA11yAnnouncements({ itemCount, filteredCount, searchQuery, isLoading, }) {
|
|
108
|
+
React.useEffect(() => {
|
|
109
|
+
if (isLoading) {
|
|
110
|
+
announceToScreenReader('Loading items...', 'polite');
|
|
111
|
+
}
|
|
112
|
+
}, [isLoading]);
|
|
113
|
+
React.useEffect(() => {
|
|
114
|
+
if (searchQuery) {
|
|
115
|
+
const message = filteredCount === 0
|
|
116
|
+
? `No results found for "${searchQuery}"`
|
|
117
|
+
: `Found ${filteredCount} results for "${searchQuery}"`;
|
|
118
|
+
announceToScreenReader(message, 'polite');
|
|
119
|
+
}
|
|
120
|
+
}, [searchQuery, filteredCount]);
|
|
121
|
+
React.useEffect(() => {
|
|
122
|
+
announceToScreenReader(`List has ${itemCount} items`, 'polite');
|
|
123
|
+
}, [itemCount]);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Ensure keyboard-accessible interactions
|
|
127
|
+
*/
|
|
128
|
+
export const a11yEventHandlers = {
|
|
129
|
+
/**
|
|
130
|
+
* Handle click or Enter/Space key
|
|
131
|
+
*/
|
|
132
|
+
onClickOrKey: (callback) => ({
|
|
133
|
+
onClick: callback,
|
|
134
|
+
onKeyDown: (e) => {
|
|
135
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
136
|
+
e.preventDefault();
|
|
137
|
+
callback();
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
}),
|
|
141
|
+
/**
|
|
142
|
+
* Make any element keyboard accessible
|
|
143
|
+
*/
|
|
144
|
+
makeKeyboardAccessible: (element, callback) => {
|
|
145
|
+
element.setAttribute('role', 'button');
|
|
146
|
+
element.setAttribute('tabindex', '0');
|
|
147
|
+
element.addEventListener('keydown', (e) => {
|
|
148
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
149
|
+
e.preventDefault();
|
|
150
|
+
callback();
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Focus management utilities
|
|
157
|
+
*/
|
|
158
|
+
export const focusManagement = {
|
|
159
|
+
/**
|
|
160
|
+
* Set focus with announcement
|
|
161
|
+
*/
|
|
162
|
+
focusWithAnnouncement: (element, message) => {
|
|
163
|
+
element.focus();
|
|
164
|
+
if (message) {
|
|
165
|
+
announceToScreenReader(message, 'assertive');
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
/**
|
|
169
|
+
* Trap focus within container (for modals, etc.)
|
|
170
|
+
*/
|
|
171
|
+
trapFocus: (container) => {
|
|
172
|
+
const focusableElements = container.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
|
|
173
|
+
const firstElement = focusableElements[0];
|
|
174
|
+
const lastElement = focusableElements[focusableElements.length - 1];
|
|
175
|
+
const handleKeyDown = (e) => {
|
|
176
|
+
if (e.key !== 'Tab')
|
|
177
|
+
return;
|
|
178
|
+
if (e.shiftKey) {
|
|
179
|
+
if (document.activeElement === firstElement) {
|
|
180
|
+
e.preventDefault();
|
|
181
|
+
lastElement.focus();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
if (document.activeElement === lastElement) {
|
|
186
|
+
e.preventDefault();
|
|
187
|
+
firstElement.focus();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
container.addEventListener('keydown', handleKeyDown);
|
|
192
|
+
return () => container.removeEventListener('keydown', handleKeyDown);
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
/**
|
|
196
|
+
* ARIA live region for dynamic content
|
|
197
|
+
*/
|
|
198
|
+
export class AriaLiveRegion {
|
|
199
|
+
constructor(priority = 'polite') {
|
|
200
|
+
Object.defineProperty(this, "region", {
|
|
201
|
+
enumerable: true,
|
|
202
|
+
configurable: true,
|
|
203
|
+
writable: true,
|
|
204
|
+
value: void 0
|
|
205
|
+
});
|
|
206
|
+
this.region = document.createElement('div');
|
|
207
|
+
this.region.setAttribute('aria-live', priority);
|
|
208
|
+
this.region.setAttribute('aria-atomic', 'true');
|
|
209
|
+
this.region.style.position = 'absolute';
|
|
210
|
+
this.region.style.left = '-10000px';
|
|
211
|
+
this.region.style.width = '1px';
|
|
212
|
+
this.region.style.height = '1px';
|
|
213
|
+
this.region.style.overflow = 'hidden';
|
|
214
|
+
document.body.appendChild(this.region);
|
|
215
|
+
}
|
|
216
|
+
announce(message) {
|
|
217
|
+
this.region.textContent = message;
|
|
218
|
+
}
|
|
219
|
+
clear() {
|
|
220
|
+
this.region.textContent = '';
|
|
221
|
+
}
|
|
222
|
+
remove() {
|
|
223
|
+
this.region.remove();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Accessibility audit helper
|
|
228
|
+
*/
|
|
229
|
+
export function auditAccessibility(container) {
|
|
230
|
+
const warnings = [];
|
|
231
|
+
const errors = [];
|
|
232
|
+
// Check for proper ARIA labels
|
|
233
|
+
if (!container.hasAttribute('aria-label') && !container.hasAttribute('aria-describedby')) {
|
|
234
|
+
warnings.push('Container should have aria-label or aria-describedby');
|
|
235
|
+
}
|
|
236
|
+
// Check for keyboard navigation support
|
|
237
|
+
const focusableElements = container.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
|
|
238
|
+
if (focusableElements.length === 0 && container.querySelectorAll('[role="button"]').length === 0) {
|
|
239
|
+
warnings.push('No keyboard-accessible interactive elements found');
|
|
240
|
+
}
|
|
241
|
+
// Check color contrast (basic check)
|
|
242
|
+
const allElements = container.querySelectorAll('*');
|
|
243
|
+
allElements.forEach((el) => {
|
|
244
|
+
const style = window.getComputedStyle(el);
|
|
245
|
+
const bgColor = style.backgroundColor;
|
|
246
|
+
const textColor = style.color;
|
|
247
|
+
// This is a simplified check - real implementation would calculate actual contrast ratio
|
|
248
|
+
if (bgColor === textColor) {
|
|
249
|
+
errors.push(`Element has same foreground and background color: ${el.tagName}`);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
return { warnings, errors };
|
|
253
|
+
}
|
|
254
|
+
//# sourceMappingURL=a11y.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a11y.js","sourceRoot":"","sources":["../../src/accessibility/a11y.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { VirtualGridProps } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* VirtualGrid Component
|
|
5
|
+
* Efficient rendering for grid and masonry layouts
|
|
6
|
+
*/
|
|
7
|
+
export declare const VirtualGrid: React.ForwardRefExoticComponent<VirtualGridProps<any> & React.RefAttributes<HTMLDivElement>>;
|
|
8
|
+
//# sourceMappingURL=VirtualGrid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VirtualGrid.d.ts","sourceRoot":"","sources":["../../src/components/VirtualGrid.tsx"],"names":[],"mappings":"AAAA,OAAO,KAMN,MAAM,OAAO,CAAC;AAEf,OAAO,EAAE,gBAAgB,EAAmB,MAAM,UAAU,CAAC;AAW7D;;;GAGG;AACH,eAAO,MAAM,WAAW,8FAkTvB,CAAC"}
|