-
Notifications
You must be signed in to change notification settings - Fork 942
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5472 from uswds/cm-range-slider-sr-unit
USWDS - Range: Enhance SR callouts
- Loading branch information
Showing
8 changed files
with
265 additions
and
3 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,65 @@ | ||
const selectOrMatches = require("../../uswds-core/src/js/utils/select-or-matches"); | ||
const behavior = require("../../uswds-core/src/js/utils/behavior"); | ||
|
||
const { prefix: PREFIX } = require("../../uswds-core/src/js/config"); | ||
|
||
const RANGE_CLASSNAME = `${PREFIX}-range`; | ||
const RANGE = `.${RANGE_CLASSNAME}`; | ||
|
||
/** | ||
* Update range callout for screen readers using the optional data attributes. | ||
* | ||
* Get optional data attributes, construct and appends aria-valuetext attribute. | ||
* | ||
* @example | ||
* | ||
* <input id="usa-range" class="usa-range" type="range" min="0" max="100" step="10" value="20" data-text-unit="degrees"> | ||
* | ||
* Callout returns "20 degrees of 100." | ||
* | ||
* <input id="usa-range" class="usa-range" type="range" min="0" max="100" step="10" value="20" data-text-preposition="de"> | ||
* | ||
* Callout returns "20 de 100." | ||
* | ||
* @param {HTMLInputElement} targetRange - The range slider input element | ||
*/ | ||
const updateCallout = (targetRange) => { | ||
const rangeSlider = targetRange; | ||
const defaultPrep = "of"; | ||
const optionalPrep = rangeSlider.dataset.textPreposition; | ||
const prep = optionalPrep || defaultPrep; | ||
const unit = rangeSlider.dataset.textUnit; | ||
const val = rangeSlider.value; | ||
// Note: 100 is the max attribute's native default value on range inputs | ||
// Reference: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/range#validation | ||
const max = rangeSlider.getAttribute("max") || 100; | ||
|
||
let callout; | ||
|
||
if (unit) { | ||
callout = `${val} ${unit} ${prep} ${max}`; | ||
} else { | ||
callout = `${val} ${prep} ${max}`; | ||
} | ||
|
||
rangeSlider.setAttribute("aria-valuetext", callout); | ||
}; | ||
|
||
const rangeEvents = { | ||
change: { | ||
[RANGE]() { | ||
updateCallout(this); | ||
}, | ||
}, | ||
}; | ||
|
||
const range = behavior(rangeEvents, { | ||
init(root) { | ||
selectOrMatches(RANGE, root).forEach((rangeSlider) => { | ||
updateCallout(rangeSlider); | ||
}); | ||
}, | ||
updateCallout, | ||
}); | ||
|
||
module.exports = range; |
12 changes: 12 additions & 0 deletions
12
packages/usa-range/src/test/sr-callout-with-preposition.spec.html
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,12 @@ | ||
<form class="usa-form"> | ||
<input | ||
id="usa-range" | ||
class="usa-range" | ||
type="range" | ||
min="0" | ||
max="100" | ||
step="10" | ||
value="20" | ||
data-text-preposition="de" | ||
> | ||
</form> |
71 changes: 71 additions & 0 deletions
71
packages/usa-range/src/test/sr-callout-with-preposition.spec.js
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,71 @@ | ||
const fs = require("fs"); | ||
const path = require("path"); | ||
const assert = require("assert"); | ||
const range = require("../index"); | ||
|
||
const TEMPLATE = fs.readFileSync( | ||
path.join(__dirname, "./sr-callout-with-preposition.spec.html") | ||
); | ||
|
||
const EVENTS = {}; | ||
|
||
/** | ||
* send an change event | ||
* @param {HTMLElement} el the element to sent the event to | ||
*/ | ||
EVENTS.change = (el) => { | ||
el.dispatchEvent(new KeyboardEvent("change", { bubbles: true })); | ||
}; | ||
|
||
const rangeSliderSelector = () => document.querySelector(".usa-range"); | ||
|
||
const tests = [ | ||
{ name: "document.body", selector: () => document.body }, | ||
{ name: "range slider", selector: rangeSliderSelector }, | ||
]; | ||
|
||
tests.forEach(({ name, selector: containerSelector }) => { | ||
describe(`Range slider with updated preposition initialized at ${name}`, () => { | ||
describe("range slider component", () => { | ||
const { body } = document; | ||
|
||
let slider; | ||
let valueText; | ||
|
||
beforeEach(() => { | ||
body.innerHTML = TEMPLATE; | ||
range.on(containerSelector()); | ||
|
||
slider = rangeSliderSelector(); | ||
valueText = slider.getAttribute("aria-valuetext"); | ||
}); | ||
|
||
afterEach(() => { | ||
body.textContent = ""; | ||
}); | ||
|
||
it("adds aria-valuetext attribute with updated preposition", () => { | ||
assert.ok(valueText, "aria-valuetext attribute is added"); | ||
assert.strictEqual( | ||
valueText, | ||
"20 de 100", | ||
"initial value is incorrect" | ||
); | ||
}); | ||
|
||
it("updates aria-valuetext with updated preposition to match new slider value on change", () => { | ||
slider.value = "30"; | ||
EVENTS.change(slider); | ||
|
||
assert.strictEqual(slider.value, "30"); | ||
|
||
valueText = slider.getAttribute("aria-valuetext"); | ||
assert.strictEqual( | ||
valueText, | ||
"30 de 100", | ||
"Screen reader value does not match range value" | ||
); | ||
}); | ||
}); | ||
}); | ||
}); |
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,12 @@ | ||
<form class="usa-form"> | ||
<input | ||
id="usa-range" | ||
class="usa-range" | ||
type="range" | ||
min="0" | ||
max="100" | ||
step="10" | ||
value="20" | ||
data-text-unit="percent" | ||
> | ||
</form> |
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,71 @@ | ||
const fs = require("fs"); | ||
const path = require("path"); | ||
const assert = require("assert"); | ||
const range = require("../index"); | ||
|
||
const TEMPLATE = fs.readFileSync( | ||
path.join(__dirname, "./sr-callout.spec.html") | ||
); | ||
|
||
const EVENTS = {}; | ||
|
||
/** | ||
* send an change event | ||
* @param {HTMLElement} el the element to sent the event to | ||
*/ | ||
EVENTS.change = (el) => { | ||
el.dispatchEvent(new KeyboardEvent("change", { bubbles: true })); | ||
}; | ||
|
||
const rangeSliderSelector = () => document.querySelector(".usa-range"); | ||
|
||
const tests = [ | ||
{ name: "document.body", selector: () => document.body }, | ||
{ name: "range slider", selector: rangeSliderSelector }, | ||
]; | ||
|
||
tests.forEach(({ name, selector: containerSelector }) => { | ||
describe(`Range slider with aria-valuetext initialized at ${name}`, () => { | ||
describe("range slider component", () => { | ||
const { body } = document; | ||
|
||
let slider; | ||
let valueText; | ||
|
||
beforeEach(() => { | ||
body.innerHTML = TEMPLATE; | ||
range.on(containerSelector()); | ||
|
||
slider = rangeSliderSelector(); | ||
valueText = slider.getAttribute("aria-valuetext"); | ||
}); | ||
|
||
afterEach(() => { | ||
body.textContent = ""; | ||
}); | ||
|
||
it("adds aria-valuetext attribute", () => { | ||
assert.ok(valueText, "aria-valuetext attribute is added"); | ||
assert.strictEqual( | ||
valueText, | ||
"20 percent of 100", | ||
"initial value is incorrect" | ||
); | ||
}); | ||
|
||
it("updates aria-valuetext to match new slider value on change", () => { | ||
slider.value = "30"; | ||
EVENTS.change(slider); | ||
|
||
assert.strictEqual(slider.value, "30"); | ||
|
||
valueText = slider.getAttribute("aria-valuetext"); | ||
assert.strictEqual( | ||
valueText, | ||
"30 percent of 100", | ||
"Screen reader value does not match range value" | ||
); | ||
}); | ||
}); | ||
}); | ||
}); |
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