Skip to content

Commit f950675

Browse files
Merge pull request #1487 from clpetersonucf/react/accessibility-indicator-polish-part-two
Catalog accessibility indicator updates
2 parents 5daaa65 + e85dc6e commit f950675

File tree

5 files changed

+296
-143
lines changed

5 files changed

+296
-143
lines changed

src/components/accessibility-indicator.jsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,20 @@ const AccessibilityIndicator = ({widget = {}}) => {
1515
}
1616
}
1717

18+
let descriptionRender = ''
19+
if (widget.accessibility.keyboard.toLowerCase() != 'unavailable' || widget.accessibility.screen_reader.toLowerCase() != 'unavailable') {
20+
descriptionRender = widget.accessibility.description
21+
}
22+
else {
23+
descriptionRender = 'No accessibility information is provided for this widget.'
24+
}
25+
1826
return (
1927
<div className='feature-list accessibility-options'>
2028
<div className='list-holder'>
2129
<span className='feature-heading'>Accessibility:</span>
2230
<ul>
23-
<li>
31+
<li className={`accessibility-indicator ${widget.accessibility?.keyboard.toLowerCase() != 'unavailable' ? 'show' : ''}`}>
2432
<div className='icon-spacer'>
2533
<KeyboardIcon color='#5a5a5a'/>
2634
</div>
@@ -30,16 +38,19 @@ const AccessibilityIndicator = ({widget = {}}) => {
3038
</span>
3139
</span>
3240
</li>
33-
<li>
41+
<li className={`accessibility-indicator ${widget.accessibility?.screen_reader.toLowerCase() != 'unavailable' ? 'show' : ''}`}>
3442
<div className='icon-spacer'>
3543
<ScreenReaderIcon color='#5a5a5a'/>
3644
</div>
37-
<span>Screen reader is&nbsp;
45+
<span>Screen readers are&nbsp;
3846
<span id='screen-reader-access-level' className={`highlighted ${widget.accessibility?.screen_reader.toLowerCase()}`}>
3947
{`${accessLevelToText(widget.accessibility?.screen_reader)} supported`}
4048
</span>
4149
</span>
4250
</li>
51+
<li className={`accessibility-description ${descriptionRender.length > 0 ? 'show' : ''}`}>
52+
{descriptionRender}
53+
</li>
4354
</ul>
4455
</div>
4556
</div>

src/components/catalog.jsx

Lines changed: 101 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,27 @@ const Catalog = ({widgets = [], isLoading = true}) => {
1010
const [state, setState] = useState({
1111
searchText: '',
1212
showingFilters: false,
13+
showingAccessibility: false,
1314
activeFilters: [],
14-
showMobileFilters: false
15+
showMobileFilters: false,
16+
showMobileAccessibilityFilters: false
1517
})
1618
const totalWidgets = widgets.length
1719

1820
// collect all unique features and supported data
1921
const filters = useMemo(() => {
20-
const filters = new Set()
22+
const features = new Set()
23+
const accessibility = new Set()
2124
widgets.forEach(w => {
22-
w.meta_data.features.forEach(f => {filters.add(f)})
23-
w.meta_data.supported_data.forEach(f => {filters.add(f)})
24-
if(w.meta_data.hasOwnProperty('accessibility_keyboard')) filters.add('Keyboard Accessible')
25-
if(w.meta_data.hasOwnProperty('accessibility_reader')) filters.add('Screen Reader Accessible')
25+
w.meta_data.features.forEach(f => {features.add(f)})
26+
w.meta_data.supported_data.forEach(f => {features.add(f)})
27+
if(w.meta_data.hasOwnProperty('accessibility_keyboard')) accessibility.add('Keyboard Accessible')
28+
if(w.meta_data.hasOwnProperty('accessibility_reader')) accessibility.add('Screen Reader Accessible')
2629
})
27-
return Array.from(filters)
30+
return {
31+
features: Array.from(features),
32+
accessibility: Array.from(accessibility)
33+
}
2834
},
2935
[widgets]
3036
)
@@ -72,6 +78,15 @@ const Catalog = ({widgets = [], isLoading = true}) => {
7278
setState({...state, activeFilters: newFilters, showMobileFilters: false})
7379
}
7480

81+
const accessibilityLinkClickHandler = () => {
82+
if (state.showingAccessibility){
83+
setState({...state, showingAccessibility: !state.showingAccessibility, activeFilters: []})
84+
}
85+
else {
86+
setState({...state, showingAccessibility: !state.showingAccessibility})
87+
}
88+
}
89+
7590
const filterLinkClickHandler = () => {
7691
if(state.showingFilters){
7792
setState({...state, showingFilters: !state.showingFilters, activeFilters: []})
@@ -92,7 +107,7 @@ const Catalog = ({widgets = [], isLoading = true}) => {
92107

93108
let mobileFilterRender = null
94109
if (state.showMobileFilters) {
95-
const mobileFilterOptionsRender = filters.map(filter => (
110+
const mobileFilterOptionsRender = filters.features.map(filter => (
96111
<label key={filter}>
97112
<input type='checkbox'
98113
className='filter-button'
@@ -112,14 +127,51 @@ const Catalog = ({widgets = [], isLoading = true}) => {
112127
{ mobileFilterOptionsRender }
113128
</div>
114129
)
130+
} else if (state.showMobileAccessibilityFilters) {
131+
const mobileFilterOptionsRender = filters.accessibility.map(filter => (
132+
<label key={filter}>
133+
<input type='checkbox'
134+
className='filter-button'
135+
checked={state.activeFilters.includes(filter)}
136+
readOnly={true}
137+
onClick={ () => toggleFilter(filter) }
138+
/>
139+
{filter}
140+
</label>
141+
))
142+
143+
mobileFilterRender = (
144+
<div
145+
id='filter-dropdown'
146+
className='mobile-only accessibility'
147+
aria-hidden={!isMobileDevice()}>
148+
{ mobileFilterOptionsRender }
149+
</div>
150+
)
115151
}
116152

117-
const filterOptionsRender = filters.map((filter, index) => {
153+
const filterOptionsRender = filters.features.map((filter, index) => {
118154
const isEnabled = state.activeFilters.includes(filter)
119155
const filterOptionClickHandler = () => toggleFilter(filter)
120156
return <button key={index}
121157
className={'feature-button' + (isEnabled ? ' selected' : '')}
158+
aria-label={`Filter by ${filter}. ${isEnabled ? 'Selected.' : ''}`}
122159
aria-hidden={!state.showingFilters}
160+
disabled={!state.showingFilters}
161+
onClick={ filterOptionClickHandler }>
162+
{filter}
163+
</button>
164+
}
165+
)
166+
167+
const accessibilityOptionsRender = filters.accessibility.map((filter, index) => {
168+
const isEnabled = state.activeFilters.includes(filter)
169+
const filterOptionClickHandler = () => toggleFilter(filter)
170+
return <button key={index}
171+
className={'feature-button' + (isEnabled ? ' selected' : '')}
172+
aria-label={`Filter by ${filter}. ${isEnabled ? 'Selected.' : ''}`}
173+
aria-hidden={!state.showingAccessibility}
174+
disabled={!state.showingAccessibility}
123175
onClick={ filterOptionClickHandler }>
124176
{ filter == 'Keyboard Accessible' ? <KeyboardIcon color='#000' /> : '' }
125177
{ filter == 'Screen Reader Accessible' ? <ScreenReaderIcon color='#000' /> : '' }
@@ -203,40 +255,59 @@ const Catalog = ({widgets = [], isLoading = true}) => {
203255

204256
<div className='top'>
205257
<h1>Widget Catalog</h1>
206-
<button
207-
className='filter-toggle cancel_button desktop-only'
208-
onClick={ filterLinkClickHandler }>
209-
{state.showingFilters ? 'Clear Filters' : 'Filter by feature'}
210-
</button>
211-
<div className={'search' + (state.searchText === '' ? '' : ' not-empty')}>
212-
<input value={state.searchText} onChange={(e) => {setState({...state, searchText: e.target.value})}} type='text'/>
213-
<div className='search-icon'>
214-
<svg viewBox='0 0 250.313 250.313'>
215-
<path d='m244.19 214.6l-54.379-54.378c-0.289-0.289-0.628-0.491-0.93-0.76 10.7-16.231 16.945-35.66 16.945-56.554 0-56.837-46.075-102.91-102.91-102.91s-102.91 46.075-102.91 102.91c0 56.835 46.074 102.91 102.91 102.91 20.895 0 40.323-6.245 56.554-16.945 0.269 0.301 0.47 0.64 0.759 0.929l54.38 54.38c8.169 8.168 21.413 8.168 29.583 0 8.168-8.169 8.168-21.413 0-29.582zm-141.28-44.458c-37.134 0-67.236-30.102-67.236-67.235 0-37.134 30.103-67.236 67.236-67.236 37.132 0 67.235 30.103 67.235 67.236s-30.103 67.235-67.235 67.235z'
216-
clipRule='evenodd'
217-
fillRule='evenodd'/>
218-
</svg>
258+
<aside>
259+
<span className='label'>Filter by:</span>
260+
<button
261+
className={`filter-toggle desktop-only ${state.showingFilters ? 'close-mode' : ''}`}
262+
aria-label={state.showingFilters ? 'Feature filters drawer open' : 'Filter catalog by features'}
263+
onClick={ filterLinkClickHandler }>
264+
Feature</button>
265+
<button
266+
className={`filter-toggle desktop-only ${state.showingAccessibility ? 'close-mode' : ''}`}
267+
aria-label={state.showingAccessibility ? 'Accessibility filters drawer open' : 'Filter catalog by accessibility'}
268+
onClick={ accessibilityLinkClickHandler }>
269+
Accessibility</button>
270+
<div className={'search' + (state.searchText === '' ? '' : ' not-empty')}>
271+
<input value={state.searchText} onChange={(e) => {setState({...state, searchText: e.target.value})}} type='text'/>
272+
<div className='search-icon'>
273+
<svg viewBox='0 0 250.313 250.313'>
274+
<path d='m244.19 214.6l-54.379-54.378c-0.289-0.289-0.628-0.491-0.93-0.76 10.7-16.231 16.945-35.66 16.945-56.554 0-56.837-46.075-102.91-102.91-102.91s-102.91 46.075-102.91 102.91c0 56.835 46.074 102.91 102.91 102.91 20.895 0 40.323-6.245 56.554-16.945 0.269 0.301 0.47 0.64 0.759 0.929l54.38 54.38c8.169 8.168 21.413 8.168 29.583 0 8.168-8.169 8.168-21.413 0-29.582zm-141.28-44.458c-37.134 0-67.236-30.102-67.236-67.235 0-37.134 30.103-67.236 67.236-67.236 37.132 0 67.235 30.103 67.235 67.236s-30.103 67.235-67.235 67.235z'
275+
clipRule='evenodd'
276+
fillRule='evenodd'/>
277+
</svg>
278+
</div>
279+
{ searchCloseRender }
219280
</div>
220-
{ searchCloseRender }
221-
</div>
281+
</aside>
282+
222283
</div>
223284

224-
<div aria-hidden={!isMobileDevice()} id='active-filters' className='mobile-only'>
225-
<button id='add-filter'
226-
onClick={ () => { setState({...state, showMobileFilters: !state.showMobileFilters}) } }>
285+
<div aria-hidden={!isMobileDevice()} className='mobile-filter-select mobile-only'>
286+
<button className='add-filter'
287+
onClick={ () => { setState({...state, showMobileFilters: !state.showMobileFilters, showMobileAccessibilityFilters: false}) } }>
227288
{state.activeFilters.length ? 'Filters' : 'Filter by Feature'}
228289
</button>
229-
<div>
290+
<button className='add-filter'
291+
onClick={ () => { setState({...state, showMobileAccessibilityFilters: !state.showMobileAccessibilityFilters, showMobileFilters: false}) } }>
292+
{state.activeFilters.length ? 'Accessibility' : 'Filter by Accessibility'}
293+
</button>
294+
<div className='active-filters'>
230295
{ state.activeFilters.join(', ') }
231296
</div>
232297
</div>
233298
{ mobileFilterRender }
234299
<div id='filters-container'
235-
className={`ready ${state.showingFilters ? 'open' : 'closed'}`}>
236-
<div className='filter-labels-container'>
300+
className={`ready ${state.showingFilters ? 'open' : 'closed'}`} aria-hidden={!state.showingFilters}>
301+
<div className='filter-labels-container' disabled={!state.showingFilters}>
237302
{ filterOptionsRender }
238303
</div>
239304
</div>
305+
<div id='filters-container'
306+
className={`ready ${state.showingAccessibility ? 'open' : 'closed'}`} aria-hidden={!state.showingAccessibility}>
307+
<div className='filter-labels-container accessibility' disabled={!state.showingAccessibility}>
308+
{ accessibilityOptionsRender }
309+
</div>
310+
</div>
240311

241312
{ featuredWidgetsRender }
242313

0 commit comments

Comments
 (0)