-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* initial files * Initial scripting * Add styling * Adding tests * styling tweak * Adding completed code to pattern * typo * another typo * Updating for amnually opening all toggles * update pattern with latest code * Updating ACs * Update CSS button icon, linting updates * Update dependency form mark-up --------- Co-authored-by: Mick Perkins <[email protected]>
- Loading branch information
1 parent
35d61c9
commit c39cea4
Showing
9 changed files
with
471 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import { h } from 'preact'; | ||
import { init as initViewAll } from '../../../src/js/modules/view-all'; | ||
import ViewAll from '../../../src/templates/pages/example/view-all'; | ||
import { render } from 'preact-render-to-string'; | ||
|
||
describe('View all > mark up', () => { | ||
beforeAll(() => { | ||
document.body.innerHTML = render(<ViewAll />); | ||
initViewAll(); | ||
}); | ||
|
||
it('Should use a button element for the expandable section trigger', () => { | ||
const toggleButton = document.querySelector('.js-expandable-section__btn-1'); | ||
expect(toggleButton.tagName).toEqual('BUTTON'); | ||
}); | ||
|
||
it('Should use a button element for the view all trigger', () => { | ||
const toggleButton = document.querySelector('.js-expandable-section__btn-all'); | ||
expect(toggleButton.tagName).toEqual('BUTTON'); | ||
}); | ||
|
||
it('Buttons should be focusable', () => { | ||
const toggleButton = document.querySelector('.js-expandable-section__btn-1'); | ||
toggleButton.focus(); | ||
expect(document.activeElement).toEqual(toggleButton); | ||
}); | ||
|
||
it('View all button should be focusable', () => { | ||
const toggleButton = document.querySelector('.js-expandable-section__btn-all'); | ||
toggleButton.focus(); | ||
expect(document.activeElement).toEqual(toggleButton); | ||
}); | ||
|
||
it('Buttons should be appropriately labelled', () => { | ||
const toggleButton = document.querySelector('.js-expandable-section__btn-1'); | ||
expect(toggleButton.textContent).toEqual('Section title'); | ||
}); | ||
|
||
it('View all button should be appropriately labelled', () => { | ||
const toggleButtonDetail = document.querySelector('.js-expandable-section__btn-all .visually-hidden'); | ||
expect(toggleButtonDetail.textContent).toEqual('sections about Lorem Ipsum'); | ||
}); | ||
|
||
}); | ||
|
||
describe('View all > functionality', () => { | ||
let instance; | ||
beforeEach(() => { | ||
document.body.innerHTML = render(<ViewAll />); | ||
[ instance ] = initViewAll(); | ||
}); | ||
|
||
it('Should update the visible text on the button when toggled', () => { | ||
const [ btn ] = instance.getState().btns; | ||
expect(btn.textContent).toMatch(/(View all)/i); | ||
btn.click(); | ||
expect(btn.textContent).toMatch(/(Hide all)/i); | ||
}); | ||
|
||
it('View all button should toggle all inner expandable sections when used', () => { | ||
const [ btn ] = instance.getState().btns; | ||
const toggles = instance.getState().toggles; | ||
|
||
const allClosed = toggles.reduce((acc, tog) => { | ||
return acc && !tog.getState().isOpen; | ||
}, true); | ||
expect(allClosed).toBeTruthy(); | ||
|
||
btn.click(); | ||
|
||
const allOpen = toggles.reduce((acc, tog) => { | ||
return acc && tog.getState().isOpen; | ||
}, true); | ||
expect(allOpen).toBeTruthy(); | ||
}); | ||
|
||
it('View all button should update when all toggles are manually opened', () => { | ||
const [ btn ] = instance.getState().btns; | ||
const toggles = instance.getState().toggles; | ||
|
||
toggles.forEach((toggle) => { | ||
toggle.getState().toggles[0].click(); | ||
}); | ||
expect(btn.textContent).toMatch(/(Hide all)/i); | ||
expect(btn.classList.contains('is--open')).toBeTruthy(); | ||
expect(btn.getAttribute('aria-expanded')).toEqual("true"); | ||
}); | ||
|
||
}); | ||
|
||
|
||
describe('Expandable search > axe > ARIA', () => { | ||
let instance; | ||
beforeEach(() => { | ||
document.body.innerHTML = render(<ViewAll />); | ||
[ instance ] = initViewAll(); | ||
}); | ||
|
||
it('ARIA controls attribute should correctly associate button with search container element', () => { | ||
const [ toggle ] = instance.getState().toggles; | ||
const [ innerToggleBtn ] = toggle.getState().toggles; | ||
expect(innerToggleBtn.getAttribute('aria-controls')).toEqual(toggle.node.getAttribute('id')); | ||
}); | ||
|
||
it('ARIA expanded attribute should correctly describe shown/hidden state of individual toggles', () => { | ||
const [ toggle ] = instance.getState().toggles; | ||
const [ innerToggleBtn ] = toggle.getState().toggles; | ||
expect(innerToggleBtn.getAttribute('aria-expanded')).toEqual("false"); | ||
toggle.toggle(); | ||
expect(innerToggleBtn.getAttribute('aria-expanded')).toEqual("true"); | ||
}); | ||
|
||
it('ARIA expanded attribute should correctly describe shown/hidden state of view all toggle', () => { | ||
const [ btn ] = instance.getState().btns; | ||
expect(btn.getAttribute('aria-expanded')).toEqual("false"); | ||
btn.click(); | ||
expect(btn.getAttribute('aria-expanded')).toEqual("true"); | ||
}); | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import toggle from '@stormid/toggle'; | ||
const SELECTORS = { | ||
NODE: '.js-expand-all', | ||
TOGGLES: '.js-expandable-section-all', | ||
BTN: '.js-expandable-section__btn-all' | ||
}; | ||
const CLASSES = { | ||
OPEN: 'is--open' | ||
}; | ||
|
||
const checkAllToggles = toggles => toggles.reduce((acc, tog) => acc && tog.getState().isOpen, true); | ||
|
||
const updateVewButton = (btns, allOpen) => { | ||
btns.forEach(btn => { | ||
btn.setAttribute('aria-expanded', allOpen); | ||
btn.classList.toggle(CLASSES.OPEN); | ||
}); | ||
}; | ||
|
||
export const init = () => { | ||
|
||
const nodes = Array.from(document.querySelectorAll(SELECTORS.NODE)); | ||
const initialised = []; | ||
|
||
nodes.forEach(node => { | ||
if (!node.querySelector(SELECTORS.TOGGLES)) return; | ||
const state = { | ||
allOpen: false, | ||
toggles: toggle(Array.from(node.querySelectorAll(SELECTORS.TOGGLES)), { | ||
focus: false, | ||
local: true, | ||
callback: () => { | ||
const newOpenState = checkAllToggles(state.toggles); | ||
if (newOpenState !== state.allOpen) { | ||
updateVewButton(state.btns, newOpenState); | ||
state.allOpen = newOpenState; | ||
} | ||
} }), | ||
btns: Array.from(node.querySelectorAll(SELECTORS.BTN)) | ||
}; | ||
|
||
if (state.toggles.length) { | ||
state.btns.forEach(btn => { | ||
btn.addEventListener('click', () => { | ||
state.allOpen = !state.allOpen; | ||
updateVewButton(state.btns, state.allOpen); | ||
state.toggles.forEach(tog => { | ||
if (tog.getState().isOpen !== state.allOpen) tog.toggle(); | ||
}); | ||
}); | ||
}); | ||
}; | ||
|
||
initialised.push({ | ||
node, | ||
getState: () => state | ||
}); | ||
}); | ||
|
||
return initialised; | ||
}; | ||
|
||
init(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,22 @@ | ||
import { h } from 'preact'; | ||
|
||
const DependencyTable = ({ dependencies }) => <table class="table push-bottom--double"> | ||
<thead> | ||
<tr> | ||
<th class="th th--tight">Package</th> | ||
<th class="th th--tight">Installation</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{ | ||
dependencies.map(dependency => <tr> | ||
<td class="td td--tight"><a href={`https://www.npmjs.com/package/${dependency.package}`} rel="noopener nofollow">{dependency.package}</a></td> | ||
<td class="td td--tight"><pre class="pre pre--inline"><code class="code">{dependency.installation}</code></pre></td> | ||
</tr>) | ||
} | ||
</tbody> | ||
</table>; | ||
const DependencyTable = ({ dependencies }) => <div class="table__container--base"> | ||
<table class="table push-bottom--double"> | ||
<thead> | ||
<tr> | ||
<th class="th th--tight">Package</th> | ||
<th class="th th--tight">Installation</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{ | ||
dependencies.map(dependency => <tr> | ||
<td class="td td--tight"><a href={`https://www.npmjs.com/package/${dependency.package}`} rel="noopener nofollow">{dependency.package}</a></td> | ||
<td class="td td--tight"><pre class="pre pre--inline"><code class="code">{dependency.installation}</code></pre></td> | ||
</tr>) | ||
} | ||
</tbody> | ||
</table> | ||
</div>; | ||
|
||
export default DependencyTable; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { h, Fragment } from 'preact'; | ||
|
||
const Code = () => <Fragment> | ||
<div class="expand-all js-expand-all"> | ||
<button type="button" class="expandable-section__btn-all js-expandable-section__btn-all" aria-expanded="false"> | ||
<span class="expandable-section__btn-all-view">View all <span class="visually-hidden">sections about Lorem Ipsum</span></span> | ||
<span class="expandable-section__btn-all-hide">Hide all <span class="visually-hidden">sections about Lorem Ipsum</span></span> | ||
</button> | ||
<div class="expandable-section"> | ||
<h2 class="expandable-section__heading"> | ||
<button type="button" class="expandable-section__btn js-expandable-section__btn-1" aria-expanded="false" aria-controls="section-1"> | ||
Section title | ||
</button> | ||
</h2> | ||
<div id="section-1" class="expandable-section__bd js-expandable-section-all" data-toggle="js-expandable-section__btn-1"> | ||
<p>Aenean id posuere nunc. Donec diam nisl, rhoncus vel faucibus sed, porttitor sit amet ipsum. Donec at venenatis augue. Phasellus consequat lectus non augue vestibulum, at varius diam sagittis. Morbi nec purus augue. Etiam rutrum ullamcorper arcu vitae sollicitudin. Aliquam bibendum suscipit risus, at lacinia tortor efficitur ac.</p> | ||
<p>Praesent vitae mi nec mauris vehicula ultricies nec ut felis. Nam vel nisi id nunc efficitur fermentum. Vestibulum mollis enim nec ultrices mattis. Curabitur placerat sed nisl lobortis iaculis. Fusce porttitor massa augue, sit amet faucibus enim finibus nec. Maecenas hendrerit metus in justo commodo viverra.</p> | ||
</div> | ||
</div> | ||
<div class="expandable-section"> | ||
<h2 class="expandable-section__heading"> | ||
<button type="button" class="expandable-section__btn js-expandable-section__btn-2" aria-expanded="false" aria-controls="section-2"> | ||
Section title | ||
</button> | ||
</h2> | ||
<div id="section-2" class="expandable-section__bd js-expandable-section-all" data-toggle="js-expandable-section__btn-2"> | ||
<p>Aenean id posuere nunc. Donec diam nisl, rhoncus vel faucibus sed, porttitor sit amet ipsum. Donec at venenatis augue. Phasellus consequat lectus non augue vestibulum, at varius diam sagittis. Morbi nec purus augue. Etiam rutrum ullamcorper arcu vitae sollicitudin. Aliquam bibendum suscipit risus, at lacinia tortor efficitur ac.</p> | ||
<p>Praesent vitae mi nec mauris vehicula ultricies nec ut felis. Nam vel nisi id nunc efficitur fermentum. Vestibulum mollis enim nec ultrices mattis. Curabitur placerat sed nisl lobortis iaculis. Fusce porttitor massa augue, sit amet faucibus enim finibus nec. Maecenas hendrerit metus in justo commodo viverra.</p> | ||
</div> | ||
</div> | ||
<div class="expandable-section"> | ||
<h2 class="expandable-section__heading"> | ||
<button type="button" class="expandable-section__btn js-expandable-section__btn-3" aria-expanded="false" aria-controls="section-3"> | ||
Section title | ||
</button> | ||
</h2> | ||
<div id="section-3" class="expandable-section__bd js-expandable-section-all" data-toggle="js-expandable-section__btn-3"> | ||
<p>Aenean id posuere nunc. Donec diam nisl, rhoncus vel faucibus sed, porttitor sit amet ipsum. Donec at venenatis augue. Phasellus consequat lectus non augue vestibulum, at varius diam sagittis. Morbi nec purus augue. Etiam rutrum ullamcorper arcu vitae sollicitudin. Aliquam bibendum suscipit risus, at lacinia tortor efficitur ac.</p> | ||
<p>Praesent vitae mi nec mauris vehicula ultricies nec ut felis. Nam vel nisi id nunc efficitur fermentum. Vestibulum mollis enim nec ultrices mattis. Curabitur placerat sed nisl lobortis iaculis. Fusce porttitor massa augue, sit amet faucibus enim finibus nec. Maecenas hendrerit metus in justo commodo viverra.</p> | ||
</div> | ||
</div> | ||
<div class="expandable-section"> | ||
<h2 class="expandable-section__heading"> | ||
<button type="button" class="expandable-section__btn js-expandable-section__btn-4" aria-expanded="false" aria-controls="section-4"> | ||
Section title | ||
</button> | ||
</h2> | ||
<div id="section-4" class="expandable-section__bd js-expandable-section-all" data-toggle="js-expandable-section__btn-4"> | ||
<p>Aenean id posuere nunc. Donec diam nisl, rhoncus vel faucibus sed, porttitor sit amet ipsum. Donec at venenatis augue. Phasellus consequat lectus non augue vestibulum, at varius diam sagittis. Morbi nec purus augue. Etiam rutrum ullamcorper arcu vitae sollicitudin. Aliquam bibendum suscipit risus, at lacinia tortor efficitur ac.</p> | ||
<p>Praesent vitae mi nec mauris vehicula ultricies nec ut felis. Nam vel nisi id nunc efficitur fermentum. Vestibulum mollis enim nec ultrices mattis. Curabitur placerat sed nisl lobortis iaculis. Fusce porttitor massa augue, sit amet faucibus enim finibus nec. Maecenas hendrerit metus in justo commodo viverra.</p> | ||
</div> | ||
</div> | ||
</div> | ||
</Fragment>; | ||
|
||
export default Code; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { h } from 'preact'; | ||
import ExampleLayout from '@layouts/example'; | ||
import Code from './code'; | ||
|
||
export const title = 'Expandable section example with view/hide all'; | ||
|
||
const ExpandableSectionViewAll = () => <ExampleLayout> | ||
<main class="wrap soft-top"> | ||
<h1 class="visuallyhidden">Expandable section example with view/hide all</h1> | ||
<Code /> | ||
</main> | ||
</ExampleLayout>; | ||
|
||
export default ExpandableSectionViewAll; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.