From 45a09d61af00165a4a8e78325cad13f501a22659 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Wed, 27 Sep 2023 13:32:02 -0500 Subject: [PATCH 01/54] updated slider to create a licket scale --- .../slider/examples/css/slider-rating.css | 35 +---- .../slider/examples/js/slider-rating.js | 142 +++++++----------- .../slider/examples/slider-rating.html | 42 +++--- 3 files changed, 85 insertions(+), 134 deletions(-) diff --git a/content/patterns/slider/examples/css/slider-rating.css b/content/patterns/slider/examples/css/slider-rating.css index a5474d5bd..ab13254ce 100644 --- a/content/patterns/slider/examples/css/slider-rating.css +++ b/content/patterns/slider/examples/css/slider-rating.css @@ -19,7 +19,7 @@ fill-opacity: 0; } -.rating-slider svg .star { +.rating-slider svg .circle { stroke-width: 2px; stroke: currentcolor; fill-opacity: 0; @@ -31,56 +31,37 @@ fill-opacity: 0; } -.rating-slider[aria-valuenow="5"] svg .star { +.rating-slider[aria-valuenow="1"] svg .circle-1 .circle { fill: currentcolor; fill-opacity: 1; } -.rating-slider[aria-valuenow="0.5"] svg .star-1 .fill-left { +.rating-slider[aria-valuenow="2"] svg .circle-2 .circle { fill: currentcolor; fill-opacity: 1; } -.rating-slider[aria-valuenow="1"] svg .star-1 .star { +.rating-slider[aria-valuenow="3"] svg .circle-3 .circle { fill: currentcolor; fill-opacity: 1; } -.rating-slider[aria-valuenow="1.5"] svg .star-1 .star, -.rating-slider[aria-valuenow="1.5"] svg .star-2 .fill-left { +.rating-slider[aria-valuenow="4"] svg .circle-4 .circle { fill: currentcolor; fill-opacity: 1; } -.rating-slider[aria-valuenow="2"] svg .star-2 .star { +.rating-slider[aria-valuenow="5"] svg .circle-5 .circle { fill: currentcolor; fill-opacity: 1; } -.rating-slider[aria-valuenow="2.5"] svg .star-2 .star, -.rating-slider[aria-valuenow="2.5"] svg .star-3 .fill-left { +.rating-slider[aria-valuenow="6"] svg .circle-6 .circle { fill: currentcolor; fill-opacity: 1; } -.rating-slider[aria-valuenow="3"] svg .star-3 .star { - fill: currentcolor; - fill-opacity: 1; -} - -.rating-slider[aria-valuenow="3.5"] svg .star-3 .star, -.rating-slider[aria-valuenow="3.5"] svg .star-4 .fill-left { - fill: currentcolor; - fill-opacity: 1; -} - -.rating-slider[aria-valuenow="4"] svg .star-4 .star { - fill: currentcolor; - fill-opacity: 1; -} - -.rating-slider[aria-valuenow="4.5"] svg .star-4 .star, -.rating-slider[aria-valuenow="4.5"] svg .star-5 .fill-left { +.rating-slider[aria-valuenow="7"] svg .circle-7 .circle { fill: currentcolor; fill-opacity: 1; } diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index 589616031..64e8f97fa 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -20,8 +20,11 @@ class RatingSlider { // var color = getComputedStyle(this.sliderNode).color; // this.svgNode.setAttribute('color', color); - this.starsWidth = 198; - this.starsX = 0; + this.railWidth = 200; + this.railOffset = 10; + + this.valueMin = this.getValueMin(); + this.valueMax = this.getValueMax(); this.svgPoint = this.svgNode.createSVGPoint(); @@ -44,10 +47,10 @@ class RatingSlider { // bind a pointerup event handler to stop tracking pointer movements document.addEventListener('pointerup', this.onPointerUp.bind(this)); - this.addTotalStarsToRatingLabel(); + this.addTotalCirclesToRatingLabel(); this.sliderNode.addEventListener( 'blur', - this.addTotalStarsToRatingLabel.bind(this) + this.addTotalCirclesToRatingLabel.bind(this) ); } @@ -70,46 +73,31 @@ class RatingSlider { return parseFloat(this.sliderNode.getAttribute('aria-valuemax')); } - isInRange(value) { - let valueMin = this.getValueMin(); - let valueMax = this.getValueMax(); - return value <= valueMax && value >= valueMin; - } - getValueText(value) { switch (value) { case 0: - return 'zero stars'; - - case 0.5: - return 'one half star'; - - case 1.0: - return 'one star'; + return 'no rating selected'; - case 1.5: - return 'one and a half stars'; + case 1: + return 'Strongly disagree'; - case 2.0: - return 'two stars'; + case 2: + return 'Disagree'; - case 2.5: - return 'two and a half stars'; + case 3: + return 'Somewhat disagree'; - case 3.0: - return 'three stars'; + case 4: + return 'Neither agree or disagree'; - case 3.5: - return 'three and a half stars'; + case 5: + return 'Somewhat agree'; - case 4.0: - return 'four stars'; + case 6: + return 'Agree'; - case 4.5: - return 'four and a half stars'; - - case 5.0: - return 'five stars'; + case 7: + return 'Strongly agree'; default: break; @@ -121,37 +109,28 @@ class RatingSlider { getValueTextWithMax(value) { switch (value) { case 0: - return 'zero of five stars'; - - case 0.5: - return 'one half of five stars'; - - case 1.0: - return 'one of five stars'; + return 'no rating on the seven point rating scale selected'; - case 1.5: - return 'one and a half of five stars'; + case 1: + return 'Strongly disagree, first of seven point rating scale'; - case 2.0: - return 'two of five stars'; + case 2: + return 'Disagree, second of seven point rating scale'; - case 2.5: - return 'two and a half of five stars'; + case 3: + return 'Somewhat disagree, seven point rating scale'; - case 3.0: - return 'three of five stars'; + case 4: + return 'Neither agree or disagree, seven point rating scale'; - case 3.5: - return 'three and a half of five stars'; + case 5: + return 'Somewhat agree, fifth of seven point rating scale'; - case 4.0: - return 'four of five stars'; + case 6: + return 'Agree, sixth of seven point rating scale'; - case 4.5: - return 'four and a half of five stars'; - - case 5.0: - return 'five of five stars'; + case 7: + return 'Strongly agree, seventh of seven point rating scale'; default: break; @@ -161,54 +140,45 @@ class RatingSlider { } moveSliderTo(value) { - let valueMax, valueMin; - - valueMin = this.getValueMin(); - valueMax = this.getValueMax(); - - value = Math.min(Math.max(value, valueMin), valueMax); - + value = Math.min(Math.max(value, 1), this.valueMax); this.sliderNode.setAttribute('aria-valuenow', value); - this.sliderNode.setAttribute('aria-valuetext', this.getValueText(value)); } onSliderKeydown(event) { var flag = false; var value = this.getValue(); - var valueMin = this.getValueMin(); - var valueMax = this.getValueMax(); switch (event.key) { case 'ArrowLeft': case 'ArrowDown': - this.moveSliderTo(value - 0.5); + this.moveSliderTo(value - 1); flag = true; break; case 'ArrowRight': case 'ArrowUp': - this.moveSliderTo(value + 0.5); + this.moveSliderTo(value + 1); flag = true; break; case 'PageDown': - this.moveSliderTo(value - 1); + this.moveSliderTo(value - 2); flag = true; break; case 'PageUp': - this.moveSliderTo(value + 1); + this.moveSliderTo(value + 2); flag = true; break; case 'Home': - this.moveSliderTo(valueMin); + this.moveSliderTo(1); flag = true; break; case 'End': - this.moveSliderTo(valueMax); + this.moveSliderTo(this.valueMax); flag = true; break; @@ -222,17 +192,18 @@ class RatingSlider { } } - addTotalStarsToRatingLabel() { + addTotalCirclesToRatingLabel() { let valuetext = this.getValueTextWithMax(this.getValue()); this.sliderNode.setAttribute('aria-valuetext', valuetext); } onRailClick(event) { - var x = this.getSVGPoint(event).x; - var min = this.getValueMin(); - var max = this.getValueMax(); - var diffX = x - this.starsX; - var value = Math.round((2 * (diffX * (max - min))) / this.starsWidth) / 2; + const x = this.getSVGPoint(event).x; + const diffX = x - this.railOffset; + const fract = + 0.5 + (diffX * (this.valueMax - this.valueMin)) / this.railWidth; + const value = Math.round(fract); + this.moveSliderTo(value); event.preventDefault(); @@ -254,11 +225,12 @@ class RatingSlider { onPointerMove(event) { if (this.isMoving) { - var x = this.getSVGPoint(event).x; - var min = this.getValueMin(); - var max = this.getValueMax(); - var diffX = x - this.starsX; - var value = Math.round((2 * (diffX * (max - min))) / this.starsWidth) / 2; + const x = this.getSVGPoint(event).x; + const diffX = x - this.railOffset; + const fract = + 0.5 + (diffX * (this.valueMax - this.valueMin)) / this.railWidth; + const value = Math.round(fract); + this.moveSliderTo(value); event.preventDefault(); diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index a23f5dfa7..a18b7212e 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -62,38 +62,36 @@

Example

Rating
-
+
From 452abe0ce361e9f9d2a36a860a2e08b8e1911c94 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Fri, 6 Oct 2023 16:54:32 -0500 Subject: [PATCH 02/54] update rating slider example --- .../slider/examples/css/slider-rating.css | 90 ++++++++++++++++--- .../slider/examples/js/slider-rating.js | 64 ++++++++----- .../slider/examples/slider-rating.html | 74 ++++++++++----- test/tests/slider_slider-rating.js | 69 +++++++------- 4 files changed, 202 insertions(+), 95 deletions(-) diff --git a/content/patterns/slider/examples/css/slider-rating.css b/content/patterns/slider/examples/css/slider-rating.css index ab13254ce..182d1e7b6 100644 --- a/content/patterns/slider/examples/css/slider-rating.css +++ b/content/patterns/slider/examples/css/slider-rating.css @@ -19,49 +19,63 @@ fill-opacity: 0; } -.rating-slider svg .circle { +.rating-slider svg .value { stroke-width: 2px; stroke: currentcolor; fill-opacity: 0; } -.rating-slider svg .fill-left, -.rating-slider svg .fill-right { - stroke-width: 0; - fill-opacity: 0; +.rating-slider[aria-valuenow="0"] svg .rating-0 .value { + fill: currentcolor; + fill-opacity: 1; +} + +.rating-slider[aria-valuenow="1"] svg .rating-1 .value { + fill: currentcolor; + fill-opacity: 1; } -.rating-slider[aria-valuenow="1"] svg .circle-1 .circle { +.rating-slider[aria-valuenow="2"] svg .rating-2 .value { fill: currentcolor; fill-opacity: 1; } -.rating-slider[aria-valuenow="2"] svg .circle-2 .circle { +.rating-slider[aria-valuenow="3"] svg .rating-3 .value { fill: currentcolor; fill-opacity: 1; } -.rating-slider[aria-valuenow="3"] svg .circle-3 .circle { +.rating-slider[aria-valuenow="4"] svg .rating-4 .value { fill: currentcolor; fill-opacity: 1; } -.rating-slider[aria-valuenow="4"] svg .circle-4 .circle { +.rating-slider[aria-valuenow="5"] svg .rating-5 .value { fill: currentcolor; fill-opacity: 1; } -.rating-slider[aria-valuenow="5"] svg .circle-5 .circle { +.rating-slider[aria-valuenow="6"] svg .rating-6 .value { fill: currentcolor; fill-opacity: 1; } -.rating-slider[aria-valuenow="6"] svg .circle-6 .circle { +.rating-slider[aria-valuenow="7"] svg .rating-7 .value { fill: currentcolor; fill-opacity: 1; } -.rating-slider[aria-valuenow="7"] svg .circle-7 .circle { +.rating-slider[aria-valuenow="8"] svg .rating-8 .value { + fill: currentcolor; + fill-opacity: 1; +} + +.rating-slider[aria-valuenow="9"] svg .rating-9 .value { + fill: currentcolor; + fill-opacity: 1; +} + +.rating-slider[aria-valuenow="10"] svg .rating-10 .value { fill: currentcolor; fill-opacity: 1; } @@ -72,7 +86,57 @@ outline: none; } -.rating-slider:focus svg .focus-ring { +.rating-slider svg .focus { + stroke-width: 0; + stroke: currentcolor; + fill-opacity: 0; +} + +.rating-slider[aria-valuenow="-1"]:focus svg .focus-ring { stroke-width: 2px; stroke: currentcolor; } + +.rating-slider[aria-valuenow="0"]:focus svg .rating-0 .focus { + stroke-width: 2px; +} + +.rating-slider[aria-valuenow="1"]:focus svg .rating-1 .focus { + stroke-width: 2px; +} + +.rating-slider[aria-valuenow="2"]:focus svg .rating-2 .focus { + stroke-width: 2px; +} + +.rating-slider[aria-valuenow="3"]:focus svg .rating-3 .focus { + stroke-width: 2px; +} + +.rating-slider[aria-valuenow="4"]:focus svg .rating-4 .focus { + stroke-width: 2px; +} + +.rating-slider[aria-valuenow="5"]:focus svg .rating-5 .focus { + stroke-width: 2px; +} + +.rating-slider[aria-valuenow="6"]:focus svg .rating-6 .focus { + stroke-width: 2px; +} + +.rating-slider[aria-valuenow="7"]:focus svg .rating-7 .focus { + stroke-width: 2px; +} + +.rating-slider[aria-valuenow="8"]:focus svg .rating-8 .focus { + stroke-width: 2px; +} + +.rating-slider[aria-valuenow="9"]:focus svg .rating-9 .focus { + stroke-width: 2px; +} + +.rating-slider[aria-valuenow="10"]:focus svg .rating-10 .focus { + stroke-width: 2px; +} diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index 64e8f97fa..d332e2c44 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -20,8 +20,8 @@ class RatingSlider { // var color = getComputedStyle(this.sliderNode).color; // this.svgNode.setAttribute('color', color); - this.railWidth = 200; - this.railOffset = 10; + this.railWidth = 360; + this.railOffset = 20; this.valueMin = this.getValueMin(); this.valueMax = this.getValueMax(); @@ -75,29 +75,41 @@ class RatingSlider { getValueText(value) { switch (value) { - case 0: + case -1: return 'no rating selected'; + case 0: + return 'Unacceptable service'; + case 1: - return 'Strongly disagree'; + return 'Extremely dissatisfied'; case 2: - return 'Disagree'; + return 'Strongly dissatisfied'; case 3: - return 'Somewhat disagree'; + return 'dissatisfied'; case 4: - return 'Neither agree or disagree'; + return 'Slightly dissatisfied'; case 5: - return 'Somewhat agree'; + return 'Neither satisfied or dissatisfied'; case 6: - return 'Agree'; + return 'Slightly satisfied'; case 7: - return 'Strongly agree'; + return 'Satisfied'; + + case 8: + return 'Strongly satisfied'; + + case 9: + return 'Extremely satisfied'; + + case 10: + return 'Completely satisfied'; default: break; @@ -108,29 +120,41 @@ class RatingSlider { getValueTextWithMax(value) { switch (value) { + case -1: + return 'no rating on the 11 point rating scale selected'; + case 0: - return 'no rating on the seven point rating scale selected'; + return 'Unacceptable service, first of eleven point rating scale'; case 1: - return 'Strongly disagree, first of seven point rating scale'; + return 'Extremely dissatisfied, second of eleven point rating scale'; case 2: - return 'Disagree, second of seven point rating scale'; + return 'Strongly dissatisfied, third of eleven point rating scale'; case 3: - return 'Somewhat disagree, seven point rating scale'; + return 'dissatisfied, fourth of eleven point rating scale'; case 4: - return 'Neither agree or disagree, seven point rating scale'; + return 'Slightly dissatisfied, fifth of eleven point rating scale'; case 5: - return 'Somewhat agree, fifth of seven point rating scale'; + return 'Neither satisfied or dissatisfied, sixth of eleven point rating scale'; case 6: - return 'Agree, sixth of seven point rating scale'; + return 'Slightly satisfied, seventh of eleven point rating scale'; case 7: - return 'Strongly agree, seventh of seven point rating scale'; + return 'Satisfied, eighth of eleven point rating scale'; + + case 8: + return 'Strongly satisfied, ninth of eleven point rating scale'; + + case 9: + return 'Extremely satisfied, tenth of eleven point rating scale'; + + case 10: + return 'Completely satisfied, eleventh of eleven point rating scale'; default: break; @@ -140,7 +164,7 @@ class RatingSlider { } moveSliderTo(value) { - value = Math.min(Math.max(value, 1), this.valueMax); + value = Math.min(Math.max(value, this.valueMin + 1), this.valueMax); this.sliderNode.setAttribute('aria-valuenow', value); this.sliderNode.setAttribute('aria-valuetext', this.getValueText(value)); } @@ -173,7 +197,7 @@ class RatingSlider { break; case 'Home': - this.moveSliderTo(1); + this.moveSliderTo(this.valueMin + 1); flag = true; break; diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index a18b7212e..facc80bba 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -60,39 +60,67 @@

Example

-
Rating
+
On a scale of 0-10, rate your satisfaction with the service you received?
-
+
-
diff --git a/test/tests/slider_slider-rating.js b/test/tests/slider_slider-rating.js index 4dd7360c1..c831d3a5f 100644 --- a/test/tests/slider_slider-rating.js +++ b/test/tests/slider_slider-rating.js @@ -10,12 +10,12 @@ const ex = { sliderSelector: '#ex1 [role="slider"]', ratingSelector: '#id-rating', svgSelector: '#ex1 svg', - ratingMax: '5', - ratingMin: '0', - ratingDefault: '0', - ratingDefaultValue: 'zero of five stars', - ratingInc: 0.5, - ratingPageInc: 1, + ratingMax: '10', + ratingMin: '-1', + ratingDefault: '-1', + ratingDefaultValue: 'no rating on the 11 point rating scale selected', + ratingInc: 1, + ratingPageInc: 2, }; const sendAllSlidersToEnd = async function (t) { @@ -33,50 +33,41 @@ const getRatingValueAndText = function (v, change) { let valuetext = 'Unexpected value: ' + value; switch (value) { + case -1: + return 'no rating selected'; + case 0: - valuetext = 'zero stars'; - break; + return 'Unacceptable service'; - case 0.5: - valuetext = 'one half star'; - break; + case 1: + return 'Extremely dissatisfied'; - case 1.0: - valuetext = 'one star'; - break; + case 2: + return 'Strongly dissatisfied'; - case 1.5: - valuetext = 'one and a half stars'; - break; + case 3: + return 'dissatisfied'; - case 2.0: - valuetext = 'two stars'; - break; + case 4: + return 'Slightly dissatisfied'; - case 2.5: - valuetext = 'two and a half stars'; - break; + case 5: + return 'Neither satisfied or dissatisfied'; - case 3.0: - valuetext = 'three stars'; - break; - - case 3.5: - valuetext = 'three and a half stars'; - break; + case 6: + return 'Slightly satisfied'; - case 4.0: - valuetext = 'four stars'; - break; + case 7: + return 'Satisfied'; - case 4.5: - valuetext = 'four and a half stars'; - break; + case 8: + return 'Strongly satisfied'; - case 5.0: - valuetext = 'five stars'; - break; + case 9: + return 'Extremely satisfied'; + case 10: + return 'Completely satisfied'; default: break; } From a93b182865ec2b66ccea56df84967e39a64bd832 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Sat, 7 Oct 2023 08:35:10 -0500 Subject: [PATCH 03/54] updated example documentation --- .../slider/examples/slider-rating.html | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index facc80bba..93f4b8654 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -40,13 +40,12 @@

Warning!

Following is an example of a rating input that demonstrates the Slider Pattern. - This rating widget employs a slider because the slider pattern supports step values of any size. - This particular input enables half-star steps. - A typical five-star rating widget that allows only five possible values could instead be implemented as a radio group. + This rating widget employs a slider because number of rating values. +

Similar examples include:

From fe20292fddcf0d58913f7024bde4dcfb2ef057e2 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Sun, 8 Oct 2023 17:14:28 -0500 Subject: [PATCH 06/54] fixed regression tests --- .../slider/examples/js/slider-rating.js | 4 +- test/tests/slider_slider-rating.js | 49 ++++++++++++------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index d332e2c44..d108a2f30 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -170,8 +170,8 @@ class RatingSlider { } onSliderKeydown(event) { - var flag = false; - var value = this.getValue(); + let flag = false; + let value = this.getValue(); switch (event.key) { case 'ArrowLeft': diff --git a/test/tests/slider_slider-rating.js b/test/tests/slider_slider-rating.js index c831d3a5f..9e387bf7f 100644 --- a/test/tests/slider_slider-rating.js +++ b/test/tests/slider_slider-rating.js @@ -28,46 +28,62 @@ const sendAllSlidersToEnd = async function (t) { const getRatingValueAndText = function (v, change) { let value = parseFloat(v) + parseFloat(change); - value = Math.min(Math.max(value, ex.ratingMin), ex.ratingMax); + + let min = parseFloat(change) <= 0 ? 0 : parseFloat(ex.ratingMin); + + value = Math.min(Math.max(value, min), ex.ratingMax); let valuetext = 'Unexpected value: ' + value; switch (value) { case -1: - return 'no rating selected'; + valuetext = 'no rating selected'; + break; case 0: - return 'Unacceptable service'; + valuetext = 'Unacceptable service'; + break; case 1: - return 'Extremely dissatisfied'; + valuetext = 'Extremely dissatisfied'; + break; case 2: - return 'Strongly dissatisfied'; + valuetext = 'Strongly dissatisfied'; + break; case 3: - return 'dissatisfied'; + valuetext = 'dissatisfied'; + break; case 4: - return 'Slightly dissatisfied'; + valuetext = 'Slightly dissatisfied'; + break; case 5: - return 'Neither satisfied or dissatisfied'; + valuetext = 'Neither satisfied or dissatisfied'; + break; case 6: - return 'Slightly satisfied'; + valuetext = 'Slightly satisfied'; + break; case 7: - return 'Satisfied'; + valuetext = 'Satisfied'; + break; case 8: - return 'Strongly satisfied'; + valuetext = 'Strongly satisfied'; + break; case 9: - return 'Extremely satisfied'; + valuetext = 'Extremely satisfied'; + break; case 10: - return 'Completely satisfied'; + valuetext = 'Completely satisfied'; + break; + default: break; } @@ -195,8 +211,7 @@ ariaTest( t.deepEqual( await getValueAndText(t, ex.ratingSelector), [value, text], - 'After sending 1 arrow right key to the rating slider, aria-valuenow should be " + value + " and aria-value-text should be: ' + - text + `After sending 1 arrow right key to the rating slider, aria-valuenow should be "${value}"" and aria-value-text should be: ${text}` ); // Send more than 5 keys to rating slider @@ -316,7 +331,7 @@ ariaTest( t.deepEqual( await getValueAndText(t, ex.ratingSelector), [value, text], - 'After sending key end to the heat slider, aria-valuenow should be "' + + 'After sending key end to the rating slider, aria-valuenow should be "' + value + '" and aria-value-text should be: ' + text @@ -471,7 +486,7 @@ ariaTest( t.deepEqual( await getValueAndText(t, ex.ratingSelector), [value, text], - 'After sending key home to the heat slider, aria-valuenow should be "' + + 'After sending key home to the rating slider, aria-valuenow should be "' + ex.ratingMin + '" and aria-value-text should be: ' + text From 85dae4682cbadbefcb7fc8c902f5590fb482d790 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Sun, 8 Oct 2023 17:23:43 -0500 Subject: [PATCH 07/54] updated rating documentation --- content/patterns/slider/examples/js/slider-rating.js | 4 ++-- content/patterns/slider/examples/slider-rating.html | 12 ++++++------ test/tests/slider_slider-rating.js | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index d108a2f30..afa1b2fce 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -79,7 +79,7 @@ class RatingSlider { return 'no rating selected'; case 0: - return 'Unacceptable service'; + return 'Unacceptable'; case 1: return 'Extremely dissatisfied'; @@ -124,7 +124,7 @@ class RatingSlider { return 'no rating on the 11 point rating scale selected'; case 0: - return 'Unacceptable service, first of eleven point rating scale'; + return 'Unacceptable, first of eleven point rating scale'; case 1: return 'Extremely dissatisfied, second of eleven point rating scale'; diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index 421206a11..69f213ace 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -148,7 +148,7 @@

Accessibility Features

  • To highlight the interactive nature of the satisfaction rating, a focus ring appears around the group of rating options when the thumb has focus and no rating value has been selected.
  • To ensure the borders of the circles and focus ring have sufficient contrast with the background when high contrast settings invert colors, the color of the borders are synchronized with the color of the text content. - For example, the color of the circle borders is set to match the foreground color of high contrast mode text by specifying the CSS currentcolor value for the stroke property of each inline SVG polygon element. + For example, the color of the circle borders is set to match the foreground color of high contrast mode text by specifying the CSS currentcolor value for the stroke property of each inline SVG circle and text elements. If specific colors were used to specify the stroke and fill properties, the color of these elements would remain the same in high contrast mode, which could lead to insufficient contrast between them and their background or even make them invisible if their color were to match the high contrast mode background.
    Note: The SVG element needs to have the CSS forced-color-adjust property set to the value auto for the currentcolor value to be updated in high contrast modes. Some browsers do not use auto for the default value.
  • @@ -185,23 +185,23 @@

    Keyboard Support

    Page Up Increases slider value multiple steps. - In this slider, by two rating step. + In this slider, by two rating steps. Page Down Decreases slider value multiple steps. - In this slider, by two rating step. + In this slider, by two rating steps. Home - Sets slider to its minimum value, unaccpetable. + Sets slider to its minimum value, unacceptable. End - Sets slider to its maximum value, completely satisified. + Sets slider to its maximum value, completely satisfied. @@ -262,7 +262,7 @@

    Role, Property, State, and Tabindex Attributes

    div - Specifies the minimum value of the slider.
    NOTE: -1 means no rating value has been selected. + Specifies the minimum value of the slider.
    NOTE: -1 identifies the slider as having no rating value selected. diff --git a/test/tests/slider_slider-rating.js b/test/tests/slider_slider-rating.js index 9e387bf7f..cc1148b98 100644 --- a/test/tests/slider_slider-rating.js +++ b/test/tests/slider_slider-rating.js @@ -41,7 +41,7 @@ const getRatingValueAndText = function (v, change) { break; case 0: - valuetext = 'Unacceptable service'; + valuetext = 'Unacceptable'; break; case 1: From ceaa0d815f46eecf2e32c4e49140d09dd65e6043 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Sun, 8 Oct 2023 17:26:44 -0500 Subject: [PATCH 08/54] fixed validation errors --- content/patterns/slider/examples/slider-rating.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index 69f213ace..885a5b274 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -40,8 +40,7 @@

    Warning!

    Following is an example of a rating input that demonstrates the Slider Pattern. - This rating widget employs a slider because number of rating values. - + This rating widget employs a slider because number of rating values, in general when there are more than seven choices consider using the slider pattern.

    Similar examples include:

      @@ -149,7 +148,7 @@

      Accessibility Features

    • To ensure the borders of the circles and focus ring have sufficient contrast with the background when high contrast settings invert colors, the color of the borders are synchronized with the color of the text content. For example, the color of the circle borders is set to match the foreground color of high contrast mode text by specifying the CSS currentcolor value for the stroke property of each inline SVG circle and text elements. - If specific colors were used to specify the stroke and fill properties, the color of these elements would remain the same in high contrast mode, which could lead to insufficient contrast between them and their background or even make them invisible if their color were to match the high contrast mode background.
      + If specific colors were used to specify the stroke and fill properties, the color of these elements would remain the same in high contrast mode, which could lead to insufficient contrast between them and their background or even make them invisible if their color were to match the high contrast mode background.
      Note: The SVG element needs to have the CSS forced-color-adjust property set to the value auto for the currentcolor value to be updated in high contrast modes. Some browsers do not use auto for the default value.
    From bf46ad4ce9fc03cd6e560ead91a337388d5ff8d3 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Sun, 8 Oct 2023 17:30:26 -0500 Subject: [PATCH 09/54] fixed validation errors --- content/patterns/slider/examples/slider-rating.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index 885a5b274..a28c8a7b4 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -148,7 +148,7 @@

    Accessibility Features

  • To ensure the borders of the circles and focus ring have sufficient contrast with the background when high contrast settings invert colors, the color of the borders are synchronized with the color of the text content. For example, the color of the circle borders is set to match the foreground color of high contrast mode text by specifying the CSS currentcolor value for the stroke property of each inline SVG circle and text elements. - If specific colors were used to specify the stroke and fill properties, the color of these elements would remain the same in high contrast mode, which could lead to insufficient contrast between them and their background or even make them invisible if their color were to match the high contrast mode background.
    + If specific colors were used to specify the stroke and fill properties, the color of these elements would remain the same in high contrast mode, which could lead to insufficient contrast between them and their background or even make them invisible if their color were to match the high contrast mode background.
    Note: The SVG element needs to have the CSS forced-color-adjust property set to the value auto for the currentcolor value to be updated in high contrast modes. Some browsers do not use auto for the default value.
  • @@ -261,7 +261,7 @@

    Role, Property, State, and Tabindex Attributes

    div - Specifies the minimum value of the slider.
    NOTE: -1 identifies the slider as having no rating value selected. + Specifies the minimum value of the slider.
    NOTE: -1 identifies the slider as having no rating value selected. From cf6754012dbcbb169a579d16413e539a5c9df121 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Sun, 8 Oct 2023 18:46:59 -0500 Subject: [PATCH 10/54] fixed validation errors --- content/patterns/slider/examples/js/slider-rating.js | 4 ++-- content/patterns/slider/examples/slider-rating.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index afa1b2fce..de36c781b 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -224,9 +224,9 @@ class RatingSlider { onRailClick(event) { const x = this.getSVGPoint(event).x; const diffX = x - this.railOffset; - const fract = + const rating = 0.5 + (diffX * (this.valueMax - this.valueMin)) / this.railWidth; - const value = Math.round(fract); + const value = Math.round(rating); this.moveSliderTo(value); diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index a28c8a7b4..5845aaad9 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -44,7 +44,7 @@

    Warning!

    Similar examples include:

      -
    • Rating Radio Group Example: Radio group that provides input for a eleve point rating scale.
    • +
    • Rating Radio Group Example: Radio group that provides input for a eleven point rating scale.
    • Color Viewer Slider Example: Basic horizontal sliders that illustrate setting numeric values for a color picker.
    • Vertical Temperature Slider Example: Demonstrates using aria-orientation to specify vertical orientation and aria-valuetext to communicate unit of measure for a temperature input.
    • Media Seek Slider Example: Horizontal slider that demonstrates using aria-valuetext to communicate current and maximum values of time in media to make the values easy to understand for assistive technology users by converting the total number of seconds to minutes and seconds.
    • @@ -129,7 +129,7 @@

      Example

      10 Completely - Satisified + Satisfied From 4efd6719c73fa0ad3b68222906681c759afd404e Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Sun, 8 Oct 2023 19:18:13 -0500 Subject: [PATCH 11/54] fixed validation error --- content/patterns/slider/examples/js/slider-rating.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index de36c781b..eda168f08 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -251,9 +251,9 @@ class RatingSlider { if (this.isMoving) { const x = this.getSVGPoint(event).x; const diffX = x - this.railOffset; - const fract = + const rating = 0.5 + (diffX * (this.valueMax - this.valueMin)) / this.railWidth; - const value = Math.round(fract); + const value = Math.round(rating); this.moveSliderTo(value); From e9ed9a1cec0fb250007595a6bcc19d0b673a7611 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Sun, 8 Oct 2023 20:12:10 -0500 Subject: [PATCH 12/54] fixed bugs with pointer events --- .../patterns/slider/examples/js/slider-rating.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index eda168f08..0a1f83587 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -20,8 +20,8 @@ class RatingSlider { // var color = getComputedStyle(this.sliderNode).color; // this.svgNode.setAttribute('color', color); - this.railWidth = 360; - this.railOffset = 20; + this.railWidth = 300; + this.railOffset = 30; this.valueMin = this.getValueMin(); this.valueMax = this.getValueMax(); @@ -224,9 +224,8 @@ class RatingSlider { onRailClick(event) { const x = this.getSVGPoint(event).x; const diffX = x - this.railOffset; - const rating = - 0.5 + (diffX * (this.valueMax - this.valueMin)) / this.railWidth; - const value = Math.round(rating); + const rating = (diffX * this.valueMax) / this.railWidth; + const value = Math.floor(rating); this.moveSliderTo(value); @@ -251,9 +250,8 @@ class RatingSlider { if (this.isMoving) { const x = this.getSVGPoint(event).x; const diffX = x - this.railOffset; - const rating = - 0.5 + (diffX * (this.valueMax - this.valueMin)) / this.railWidth; - const value = Math.round(rating); + const rating = (diffX * this.valueMax) / this.railWidth; + const value = Math.floor(rating); this.moveSliderTo(value); From 88d127750614d719c667d57933daab8a1edcd80b Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Tue, 10 Oct 2023 15:58:29 -0500 Subject: [PATCH 13/54] udpated slider based on meeting feedback --- .../slider/examples/css/slider-rating.css | 11 +-- .../slider/examples/js/slider-rating.js | 50 +++++------ .../slider/examples/slider-rating.html | 84 +++++++++---------- test/tests/slider_slider-rating.js | 34 ++++---- 4 files changed, 78 insertions(+), 101 deletions(-) diff --git a/content/patterns/slider/examples/css/slider-rating.css b/content/patterns/slider/examples/css/slider-rating.css index 0ffb12627..990c4d061 100644 --- a/content/patterns/slider/examples/css/slider-rating.css +++ b/content/patterns/slider/examples/css/slider-rating.css @@ -33,11 +33,6 @@ font-size: 90%; } -.rating-slider[aria-valuenow="0"] svg .rating-0 .value { - fill: currentcolor; - fill-opacity: 1; -} - .rating-slider[aria-valuenow="1"] svg .rating-1 .value { fill: currentcolor; fill-opacity: 1; @@ -100,15 +95,11 @@ fill-opacity: 0; } -.rating-slider[aria-valuenow="-1"]:focus svg .focus-ring { +.rating-slider[aria-valuenow="0"]:focus svg .focus-ring { stroke-width: 2px; stroke: currentcolor; } -.rating-slider[aria-valuenow="0"]:focus svg .rating-0 .focus { - stroke-width: 2px; -} - .rating-slider[aria-valuenow="1"]:focus svg .rating-1 .focus { stroke-width: 2px; } diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index 0a1f83587..61c6a1f7e 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -75,41 +75,38 @@ class RatingSlider { getValueText(value) { switch (value) { - case -1: - return 'no rating selected'; - case 0: - return 'Unacceptable'; + return 'no satisfaction rating selected'; case 1: - return 'Extremely dissatisfied'; + return 'one, extremely dissatisfied'; case 2: - return 'Strongly dissatisfied'; + return 'two'; case 3: - return 'dissatisfied'; + return 'three'; case 4: - return 'Slightly dissatisfied'; + return 'four'; case 5: - return 'Neither satisfied or dissatisfied'; + return 'five'; case 6: - return 'Slightly satisfied'; + return 'six'; case 7: - return 'Satisfied'; + return 'seven'; case 8: - return 'Strongly satisfied'; + return 'eight'; case 9: - return 'Extremely satisfied'; + return 'nine'; case 10: - return 'Completely satisfied'; + return 'ten, extremely satisfied'; default: break; @@ -120,41 +117,38 @@ class RatingSlider { getValueTextWithMax(value) { switch (value) { - case -1: - return 'no rating on the 11 point rating scale selected'; - case 0: - return 'Unacceptable, first of eleven point rating scale'; + return 'no rating on the 10 point satisfaction scale selected'; case 1: - return 'Extremely dissatisfied, second of eleven point rating scale'; + return 'one, extremely unsatisfied, first value on ten point satisfaction scale'; case 2: - return 'Strongly dissatisfied, third of eleven point rating scale'; + return 'two, second value on ten point satisfaction scale'; case 3: - return 'dissatisfied, fourth of eleven point rating scale'; + return 'three, third value on ten point satisfaction scale'; case 4: - return 'Slightly dissatisfied, fifth of eleven point rating scale'; + return 'four, fourth value on ten point satisfaction scale'; case 5: - return 'Neither satisfied or dissatisfied, sixth of eleven point rating scale'; + return 'five, fifth value on ten point satisfaction scale'; case 6: - return 'Slightly satisfied, seventh of eleven point rating scale'; + return 'six, sixth value on ten point satisfaction scale'; case 7: - return 'Satisfied, eighth of eleven point rating scale'; + return 'seven, seventh value on ten point satisfaction scale'; case 8: - return 'Strongly satisfied, ninth of eleven point rating scale'; + return 'eight, eighth value on ten point satisfaction scale'; case 9: - return 'Extremely satisfied, tenth of eleven point rating scale'; + return 'nine, ninth value on ten point satisfaction scale'; case 10: - return 'Completely satisfied, eleventh of eleven point rating scale'; + return 'ten, extremely satisfied, tenth value on ten point satisfaction scale'; default: break; diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index 5845aaad9..b15951f52 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -58,78 +58,74 @@

      Example

      -
      On a scale of 0-10, rate your satisfaction with the service you received?
      +
      Rate your satisfaction with the service you received?
      -
      diff --git a/test/tests/slider_slider-rating.js b/test/tests/slider_slider-rating.js index cc1148b98..2c0567555 100644 --- a/test/tests/slider_slider-rating.js +++ b/test/tests/slider_slider-rating.js @@ -11,9 +11,9 @@ const ex = { ratingSelector: '#id-rating', svgSelector: '#ex1 svg', ratingMax: '10', - ratingMin: '-1', - ratingDefault: '-1', - ratingDefaultValue: 'no rating on the 11 point rating scale selected', + ratingMin: '0', + ratingDefault: '0', + ratingDefaultValue: 'no rating on the 10 point satisfaction scale selected', ratingInc: 1, ratingPageInc: 2, }; @@ -29,59 +29,55 @@ const sendAllSlidersToEnd = async function (t) { const getRatingValueAndText = function (v, change) { let value = parseFloat(v) + parseFloat(change); - let min = parseFloat(change) <= 0 ? 0 : parseFloat(ex.ratingMin); + let min = parseFloat(change) <= 0 ? 1 : parseFloat(ex.ratingMin); value = Math.min(Math.max(value, min), ex.ratingMax); let valuetext = 'Unexpected value: ' + value; switch (value) { - case -1: - valuetext = 'no rating selected'; - break; - case 0: - valuetext = 'Unacceptable'; + valuetext = 'no satisfaction rating selected'; break; case 1: - valuetext = 'Extremely dissatisfied'; + valuetext = 'one, extremely dissatisfied'; break; case 2: - valuetext = 'Strongly dissatisfied'; + valuetext = 'two'; break; case 3: - valuetext = 'dissatisfied'; + valuetext = 'three'; break; case 4: - valuetext = 'Slightly dissatisfied'; + valuetext = 'four'; break; case 5: - valuetext = 'Neither satisfied or dissatisfied'; + valuetext = 'five'; break; case 6: - valuetext = 'Slightly satisfied'; + valuetext = 'six'; break; case 7: - valuetext = 'Satisfied'; + valuetext = 'seven'; break; case 8: - valuetext = 'Strongly satisfied'; + valuetext = 'eight'; break; case 9: - valuetext = 'Extremely satisfied'; + valuetext = 'nine'; break; case 10: - valuetext = 'Completely satisfied'; + valuetext = 'ten, extremely satisfied'; break; default: From bf97468b99bcb841105bc4eda941529f65df86f8 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Tue, 10 Oct 2023 16:25:06 -0500 Subject: [PATCH 14/54] updated documentation --- content/patterns/slider/examples/slider-rating.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index b15951f52..4446c39b3 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -44,7 +44,7 @@

      Warning!

      Similar examples include:

        -
      • Rating Radio Group Example: Radio group that provides input for a eleven point rating scale.
      • +
      • Rating Radio Group Example: Radio group that provides input for a ten point satisfaction rating scale.
      • Color Viewer Slider Example: Basic horizontal sliders that illustrate setting numeric values for a color picker.
      • Vertical Temperature Slider Example: Demonstrates using aria-orientation to specify vertical orientation and aria-valuetext to communicate unit of measure for a temperature input.
      • Media Seek Slider Example: Horizontal slider that demonstrates using aria-valuetext to communicate current and maximum values of time in media to make the values easy to understand for assistive technology users by converting the total number of seconds to minutes and seconds.
      • @@ -257,7 +257,7 @@

        Role, Property, State, and Tabindex Attributes

        div - Specifies the minimum value of the slider.
        NOTE: -1 identifies the slider as having no rating value selected. + Specifies the minimum value of the slider.
        NOTE: 0 identifies the slider as having no rating value selected. @@ -280,7 +280,7 @@

        Role, Property, State, and Tabindex Attributes

        • A string value that provides a user-friendly name for the current value of the slider -- the level of satisfaction.
        • -
        • When initialized, and when the slider loses focus, the string also includes the number of rating values e.g., seventh of eleven point rating scale.
        • +
        • When initialized, and when the slider loses focus, the string also includes the number of rating values e.g., seven, seventh value on ten point satisfaction scale.
        From 81989a505f21a21f262ddd46f0265b3e31413149 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Tue, 10 Oct 2023 16:39:54 -0500 Subject: [PATCH 15/54] updated documentation --- content/patterns/slider/examples/slider-rating.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index 4446c39b3..cc49f5668 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -252,7 +252,7 @@

        Role, Property, State, and Tabindex Attributes

        - aria-valuemin="-1" + aria-valuemin="0" div From c3ad48c9dcef2fcdd12efd92c947fcde62dc8bd2 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Wed, 11 Oct 2023 14:52:31 -0500 Subject: [PATCH 16/54] fixed focus outline on DIV element issue --- content/patterns/slider/examples/css/slider-rating.css | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/content/patterns/slider/examples/css/slider-rating.css b/content/patterns/slider/examples/css/slider-rating.css index 990c4d061..2d31883d2 100644 --- a/content/patterns/slider/examples/css/slider-rating.css +++ b/content/patterns/slider/examples/css/slider-rating.css @@ -85,8 +85,9 @@ /* focus styling */ -.rating-slider:focus { - outline: none; +.rating-slider:focus, +.rating-slider:focus-visible { + outline: none !important; } .rating-slider svg .focus { From 34b491d5dfb976c51ecb8a8ffde5466a798e74ac Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Thu, 19 Oct 2023 15:09:18 -0500 Subject: [PATCH 17/54] updated visual styling of rating slider, selected rating value and focus ring --- .../slider/examples/css/slider-rating.css | 91 +------------ .../slider/examples/js/slider-rating.js | 121 ++++++++++++++++-- .../slider/examples/slider-rating.html | 86 ++++++------- 3 files changed, 156 insertions(+), 142 deletions(-) diff --git a/content/patterns/slider/examples/css/slider-rating.css b/content/patterns/slider/examples/css/slider-rating.css index 2d31883d2..6f9063ea1 100644 --- a/content/patterns/slider/examples/css/slider-rating.css +++ b/content/patterns/slider/examples/css/slider-rating.css @@ -27,60 +27,21 @@ .rating-slider svg .label { font-size: 90%; + color: white; } .rating-slider svg .description { font-size: 90%; } -.rating-slider[aria-valuenow="1"] svg .rating-1 .value { +.rating-slider svg .current .value { fill: currentcolor; fill-opacity: 1; } -.rating-slider[aria-valuenow="2"] svg .rating-2 .value { - fill: currentcolor; - fill-opacity: 1; -} - -.rating-slider[aria-valuenow="3"] svg .rating-3 .value { - fill: currentcolor; - fill-opacity: 1; -} - -.rating-slider[aria-valuenow="4"] svg .rating-4 .value { - fill: currentcolor; - fill-opacity: 1; -} - -.rating-slider[aria-valuenow="5"] svg .rating-5 .value { - fill: currentcolor; - fill-opacity: 1; -} - -.rating-slider[aria-valuenow="6"] svg .rating-6 .value { - fill: currentcolor; - fill-opacity: 1; -} - -.rating-slider[aria-valuenow="7"] svg .rating-7 .value { - fill: currentcolor; - fill-opacity: 1; -} - -.rating-slider[aria-valuenow="8"] svg .rating-8 .value { - fill: currentcolor; - fill-opacity: 1; -} - -.rating-slider[aria-valuenow="9"] svg .rating-9 .value { - fill: currentcolor; - fill-opacity: 1; -} - -.rating-slider[aria-valuenow="10"] svg .rating-10 .value { - fill: currentcolor; - fill-opacity: 1; +.rating-slider svg .current .label { + fill: white; + font-weight: bold; } /* focus styling */ @@ -96,47 +57,7 @@ fill-opacity: 0; } -.rating-slider[aria-valuenow="0"]:focus svg .focus-ring { +.rating-slider:focus svg .focus-ring { stroke-width: 2px; stroke: currentcolor; } - -.rating-slider[aria-valuenow="1"]:focus svg .rating-1 .focus { - stroke-width: 2px; -} - -.rating-slider[aria-valuenow="2"]:focus svg .rating-2 .focus { - stroke-width: 2px; -} - -.rating-slider[aria-valuenow="3"]:focus svg .rating-3 .focus { - stroke-width: 2px; -} - -.rating-slider[aria-valuenow="4"]:focus svg .rating-4 .focus { - stroke-width: 2px; -} - -.rating-slider[aria-valuenow="5"]:focus svg .rating-5 .focus { - stroke-width: 2px; -} - -.rating-slider[aria-valuenow="6"]:focus svg .rating-6 .focus { - stroke-width: 2px; -} - -.rating-slider[aria-valuenow="7"]:focus svg .rating-7 .focus { - stroke-width: 2px; -} - -.rating-slider[aria-valuenow="8"]:focus svg .rating-8 .focus { - stroke-width: 2px; -} - -.rating-slider[aria-valuenow="9"]:focus svg .rating-9 .focus { - stroke-width: 2px; -} - -.rating-slider[aria-valuenow="10"]:focus svg .rating-10 .focus { - stroke-width: 2px; -} diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index 61c6a1f7e..6b157164e 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -8,6 +8,8 @@ * Desc: RatingSlider widget that implements ARIA Authoring Practices */ +const OFFSET_SIZE = 4; + class RatingSlider { constructor(domNode) { this.sliderNode = domNode; @@ -16,12 +18,37 @@ class RatingSlider { this.svgNode = domNode.querySelector('svg'); - // Inherit system text colors - // var color = getComputedStyle(this.sliderNode).color; - // this.svgNode.setAttribute('color', color); - - this.railWidth = 300; - this.railOffset = 30; + this.ratingRects = Array.from( + domNode.querySelectorAll('g.rating rect.value') + ); + this.infoRatingRects = []; + + this.ratingRects.forEach((r) => { + const info = { + x: parseInt(r.getAttribute('x')), + y: parseInt(r.getAttribute('y')), + width: parseInt(r.getAttribute('width')), + height: parseInt(r.getAttribute('height')), + rx: 0, + }; + this.infoRatingRects.push(info); + }); + + const infoFirstRect = this.infoRatingRects[0]; + const infoLastRect = this.infoRatingRects[this.infoRatingRects.length - 1]; + + this.railOffset = infoFirstRect.x; + this.railWidth = infoLastRect.x + infoLastRect.width - infoFirstRect.x; + + this.focusRect = domNode.querySelector('.focus-ring'); + + this.infoDefaultFocus = { + x: OFFSET_SIZE, + y: OFFSET_SIZE, + width: infoLastRect.x + infoLastRect.width + OFFSET_SIZE, + height: infoFirstRect.y + infoLastRect.height + OFFSET_SIZE, + rx: OFFSET_SIZE, + }; this.valueMin = this.getValueMin(); this.valueMax = this.getValueMax(); @@ -52,6 +79,8 @@ class RatingSlider { 'blur', this.addTotalCirclesToRatingLabel.bind(this) ); + + this.setFocusRing(0); } // Get point in global SVG space @@ -157,10 +186,86 @@ class RatingSlider { return 'Unexpected value: ' + value; } + resetRects() { + for (let i = 0; i < this.ratingRects.length; i += 1) { + const rect = this.ratingRects[i]; + const info = this.infoRatingRects[i]; + + rect.setAttribute('x', info.x); + rect.setAttribute('y', info.y); + rect.setAttribute('width', info.width); + rect.setAttribute('height', info.height); + rect.setAttribute('rx', info.rx); + + rect.parentNode.classList.remove('current'); + } + } + + setSelectedRating(value) { + let rect, info; + + const leftValue = value - 1; + const rightValue = value + 1; + + if (value > 0) { + rect = this.ratingRects[value - 1]; + info = this.infoRatingRects[value - 1]; + + rect.setAttribute('x', info.x - OFFSET_SIZE); + rect.setAttribute('y', info.y - OFFSET_SIZE); + rect.setAttribute('width', info.width + 2 * OFFSET_SIZE); + rect.setAttribute('height', info.height + 2 * OFFSET_SIZE); + rect.setAttribute('rx', OFFSET_SIZE); + + rect.parentNode.classList.add('current'); + } + + if (leftValue > 0) { + rect = this.ratingRects[leftValue - 1]; + info = this.infoRatingRects[leftValue - 1]; + + rect.setAttribute('width', info.width - OFFSET_SIZE); + } + + if (rightValue <= this.valueMax) { + rect = this.ratingRects[rightValue - 1]; + info = this.infoRatingRects[rightValue - 1]; + + rect.setAttribute('x', info.x + OFFSET_SIZE); + rect.setAttribute('width', info.width - OFFSET_SIZE); + } + } + + setFocusRing(value) { + const size = 2 * OFFSET_SIZE; + + if (value > 0 && value <= this.valueMax) { + const info = this.infoRatingRects[value - 1]; + + this.focusRect.setAttribute('x', info.x - size); + this.focusRect.setAttribute('y', info.y - size); + this.focusRect.setAttribute('width', info.width + 2 * size); + this.focusRect.setAttribute('height', info.height + 2 * size); + this.focusRect.setAttribute('rx', size); + } else { + // Set ring around entire control + + this.focusRect.setAttribute('x', this.infoDefaultFocus.x); + this.focusRect.setAttribute('y', this.infoDefaultFocus.y); + this.focusRect.setAttribute('width', this.infoDefaultFocus.width); + this.focusRect.setAttribute('height', this.infoDefaultFocus.height); + this.focusRect.setAttribute('rx', this.infoDefaultFocus.rx); + } + } + moveSliderTo(value) { value = Math.min(Math.max(value, this.valueMin + 1), this.valueMax); this.sliderNode.setAttribute('aria-valuenow', value); this.sliderNode.setAttribute('aria-valuetext', this.getValueText(value)); + + this.resetRects(); + this.setSelectedRating(value); + this.setFocusRing(value); } onSliderKeydown(event) { @@ -219,7 +324,7 @@ class RatingSlider { const x = this.getSVGPoint(event).x; const diffX = x - this.railOffset; const rating = (diffX * this.valueMax) / this.railWidth; - const value = Math.floor(rating); + const value = Math.ceil(rating); this.moveSliderTo(value); @@ -245,7 +350,7 @@ class RatingSlider { const x = this.getSVGPoint(event).x; const diffX = x - this.railOffset; const rating = (diffX * this.valueMax) / this.railWidth; - const value = Math.floor(rating); + const value = Math.ceil(rating); this.moveSliderTo(value); diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index cc49f5668..f9276daf1 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -71,61 +71,49 @@

        Example

        aria-labelledby="id-rating-label"> -
      @@ -140,10 +128,10 @@

      Accessibility Features

      To ensure assistive technology users correctly perceive the maximum slider value, this example uses the aria-valuetext property to communicate both the current and maximum values. However, since repeating the maximum value every time the slider value changes is potentially distracting, the maximum value is included in aria-valuetext only when the slider is initialized and when the thumb loses keyboard focus. -
    • To highlight the interactive nature of the satisfaction rating, a focus ring appears around the group of rating options when the thumb has focus and no rating value has been selected.
    • +
    • To highlight the interactive nature of the satisfaction rating, a focus ring appears around the group of rating options when the slider has focus and no rating value has been selected.
    • - To ensure the borders of the circles and focus ring have sufficient contrast with the background when high contrast settings invert colors, the color of the borders are synchronized with the color of the text content. - For example, the color of the circle borders is set to match the foreground color of high contrast mode text by specifying the CSS currentcolor value for the stroke property of each inline SVG circle and text elements. + To ensure the borders of the rating values and focus ring have sufficient contrast with the background when high contrast settings invert colors, the color of the borders are synchronized with the color of the text content. + For example, the color of the rating value borders is set to match the foreground color of high contrast mode text by specifying the CSS currentcolor value for the stroke property of each inline SVG rect and text elements. If specific colors were used to specify the stroke and fill properties, the color of these elements would remain the same in high contrast mode, which could lead to insufficient contrast between them and their background or even make them invisible if their color were to match the high contrast mode background.
      Note: The SVG element needs to have the CSS forced-color-adjust property set to the value auto for the currentcolor value to be updated in high contrast modes. Some browsers do not use auto for the default value.
    • From 579fe1c33f41a83a681f4f31fa6c0c4d9002c1fe Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Thu, 19 Oct 2023 15:36:25 -0500 Subject: [PATCH 18/54] updated offset --- content/patterns/slider/examples/js/slider-rating.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index 6b157164e..1853f1c75 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -8,7 +8,7 @@ * Desc: RatingSlider widget that implements ARIA Authoring Practices */ -const OFFSET_SIZE = 4; +const OFFSET_SIZE = 6; class RatingSlider { constructor(domNode) { @@ -43,8 +43,8 @@ class RatingSlider { this.focusRect = domNode.querySelector('.focus-ring'); this.infoDefaultFocus = { - x: OFFSET_SIZE, - y: OFFSET_SIZE, + x: 2, + y: 2, width: infoLastRect.x + infoLastRect.width + OFFSET_SIZE, height: infoFirstRect.y + infoLastRect.height + OFFSET_SIZE, rx: OFFSET_SIZE, From 8e457859d0f70f25c405d71c1d54c4e4af4ac9e4 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Tue, 31 Oct 2023 15:53:31 -0500 Subject: [PATCH 19/54] updated rating slider width --- .../slider/examples/slider-rating.html | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index f9276daf1..03623f6d5 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -74,46 +74,46 @@

      Example

      From 8fc0b22a7a831c7de662bb88af40ff77e59f64e7 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Tue, 31 Oct 2023 16:01:04 -0500 Subject: [PATCH 20/54] reduced with to rating bar --- .../slider/examples/slider-rating.html | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index 03623f6d5..15c60171d 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -74,46 +74,46 @@

      Example

      From 6cef06e4b08bfeb7872c3ceff1062fbd89138f02 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Wed, 8 Nov 2023 17:15:54 -0600 Subject: [PATCH 21/54] made rail responsive --- .../slider/examples/js/slider-rating.js | 166 +++++--- .../slider/examples/slider-rating.html | 4 +- examples/tabs/css/tabs-vertical.css | 74 ++++ examples/tabs/js/tabs-vertical.js | 136 ++++++ examples/tabs/tabs-vertical.html | 393 ++++++++++++++++++ 5 files changed, 717 insertions(+), 56 deletions(-) create mode 100644 examples/tabs/css/tabs-vertical.css create mode 100644 examples/tabs/js/tabs-vertical.js create mode 100644 examples/tabs/tabs-vertical.html diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index 1853f1c75..647064c19 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -8,7 +8,10 @@ * Desc: RatingSlider widget that implements ARIA Authoring Practices */ -const OFFSET_SIZE = 6; +const SELECTED_SIZE = 6; +const RAIL_LEFT = 13; +const RAIL_TOP = 35; +const RAIL_HEIGHT = 24; class RatingSlider { constructor(domNode) { @@ -17,38 +20,18 @@ class RatingSlider { this.isMoving = false; this.svgNode = domNode.querySelector('svg'); + this.focusRect = domNode.querySelector('.focus-ring'); this.ratingRects = Array.from( domNode.querySelectorAll('g.rating rect.value') ); - this.infoRatingRects = []; - - this.ratingRects.forEach((r) => { - const info = { - x: parseInt(r.getAttribute('x')), - y: parseInt(r.getAttribute('y')), - width: parseInt(r.getAttribute('width')), - height: parseInt(r.getAttribute('height')), - rx: 0, - }; - this.infoRatingRects.push(info); - }); - - const infoFirstRect = this.infoRatingRects[0]; - const infoLastRect = this.infoRatingRects[this.infoRatingRects.length - 1]; - this.railOffset = infoFirstRect.x; - this.railWidth = infoLastRect.x + infoLastRect.width - infoFirstRect.x; - - this.focusRect = domNode.querySelector('.focus-ring'); + this.ratingRectLabels = Array.from( + domNode.querySelectorAll('g.rating text.label') + ); - this.infoDefaultFocus = { - x: 2, - y: 2, - width: infoLastRect.x + infoLastRect.width + OFFSET_SIZE, - height: infoFirstRect.y + infoLastRect.height + OFFSET_SIZE, - rx: OFFSET_SIZE, - }; + [this.infoRatingRects, this.railWidth] = this.calcRatingRects(); + this.infoDefaultFocusRect = this.calcDefaultFocusRect(); this.valueMin = this.getValueMin(); this.valueMax = this.getValueMax(); @@ -74,12 +57,14 @@ class RatingSlider { // bind a pointerup event handler to stop tracking pointer movements document.addEventListener('pointerup', this.onPointerUp.bind(this)); - this.addTotalCirclesToRatingLabel(); + this.addTotalRectsToRatingLabel(); this.sliderNode.addEventListener( 'blur', - this.addTotalCirclesToRatingLabel.bind(this) + this.addTotalRectsToRatingLabel.bind(this) ); + window.addEventListener('resize', this.onResize.bind(this)); + this.setFocusRing(0); } @@ -186,22 +171,88 @@ class RatingSlider { return 'Unexpected value: ' + value; } + calcRatingRects() { + let infoRatingRects = []; + + const railWidth = Math.min( + Math.max(24, this.sliderNode.getBoundingClientRect().width), + 600 + ); + const rectWidth = (railWidth - RAIL_LEFT) / 10; + + let left = RAIL_LEFT; + + for (let i = 0; i < this.ratingRects.length; i += 1) { + const rect = this.ratingRects[i]; + const label = this.ratingRectLabels[i]; + + rect.setAttribute('x', left); + rect.setAttribute('y', RAIL_TOP); + rect.setAttribute('width', rectWidth); + rect.setAttribute('height', RAIL_HEIGHT); + rect.removeAttribute('rx'); + + const labelWidth = label.getBoundingClientRect().width; + const labelHeight = label.getBoundingClientRect().height; + + label.setAttribute('x', 2 + left + (rectWidth - labelWidth) / 2); + label.setAttribute( + 'y', + -2 + RAIL_TOP + RAIL_HEIGHT - (RAIL_HEIGHT - labelHeight + 4) / 2 + ); + + const info = { + x: left, + y: RAIL_TOP, + width: rectWidth, + height: RAIL_HEIGHT, + rx: 0, + }; + + infoRatingRects[i] = info; + + rect.parentNode.classList.remove('current'); + + left += rectWidth; + } + + // adjust extremely satisfied label position + const descNodes = this.sliderNode.querySelectorAll('g.rating .description'); + let descX = RAIL_LEFT; + descNodes[0].setAttribute('x', descX); + + descX = railWidth - descNodes[1].getBoundingClientRect().width + 5; + descNodes[1].setAttribute('x', descX); + + return [infoRatingRects, railWidth]; + } + + calcDefaultFocusRect() { + return { + x: 2, + y: 2, + width: this.railWidth + SELECTED_SIZE, + height: RAIL_TOP + RAIL_HEIGHT + SELECTED_SIZE, + rx: SELECTED_SIZE, + }; + } + resetRects() { for (let i = 0; i < this.ratingRects.length; i += 1) { const rect = this.ratingRects[i]; - const info = this.infoRatingRects[i]; + const infoRect = this.infoRatingRects[i]; - rect.setAttribute('x', info.x); - rect.setAttribute('y', info.y); - rect.setAttribute('width', info.width); - rect.setAttribute('height', info.height); - rect.setAttribute('rx', info.rx); + rect.setAttribute('x', infoRect.x); + rect.setAttribute('y', infoRect.y); + rect.setAttribute('width', infoRect.width); + rect.setAttribute('height', infoRect.height); + rect.removeAttribute('rx'); rect.parentNode.classList.remove('current'); } } - setSelectedRating(value) { + setSelectedRatingRect(value) { let rect, info; const leftValue = value - 1; @@ -211,11 +262,11 @@ class RatingSlider { rect = this.ratingRects[value - 1]; info = this.infoRatingRects[value - 1]; - rect.setAttribute('x', info.x - OFFSET_SIZE); - rect.setAttribute('y', info.y - OFFSET_SIZE); - rect.setAttribute('width', info.width + 2 * OFFSET_SIZE); - rect.setAttribute('height', info.height + 2 * OFFSET_SIZE); - rect.setAttribute('rx', OFFSET_SIZE); + rect.setAttribute('x', info.x - SELECTED_SIZE); + rect.setAttribute('y', info.y - SELECTED_SIZE); + rect.setAttribute('width', info.width + 2 * SELECTED_SIZE); + rect.setAttribute('height', info.height + 2 * SELECTED_SIZE); + rect.setAttribute('rx', SELECTED_SIZE); rect.parentNode.classList.add('current'); } @@ -224,20 +275,20 @@ class RatingSlider { rect = this.ratingRects[leftValue - 1]; info = this.infoRatingRects[leftValue - 1]; - rect.setAttribute('width', info.width - OFFSET_SIZE); + rect.setAttribute('width', info.width - SELECTED_SIZE); } if (rightValue <= this.valueMax) { rect = this.ratingRects[rightValue - 1]; info = this.infoRatingRects[rightValue - 1]; - rect.setAttribute('x', info.x + OFFSET_SIZE); - rect.setAttribute('width', info.width - OFFSET_SIZE); + rect.setAttribute('x', info.x + SELECTED_SIZE); + rect.setAttribute('width', info.width - SELECTED_SIZE); } } setFocusRing(value) { - const size = 2 * OFFSET_SIZE; + const size = 2 * SELECTED_SIZE; if (value > 0 && value <= this.valueMax) { const info = this.infoRatingRects[value - 1]; @@ -250,11 +301,11 @@ class RatingSlider { } else { // Set ring around entire control - this.focusRect.setAttribute('x', this.infoDefaultFocus.x); - this.focusRect.setAttribute('y', this.infoDefaultFocus.y); - this.focusRect.setAttribute('width', this.infoDefaultFocus.width); - this.focusRect.setAttribute('height', this.infoDefaultFocus.height); - this.focusRect.setAttribute('rx', this.infoDefaultFocus.rx); + this.focusRect.setAttribute('x', this.infoDefaultFocusRect.x); + this.focusRect.setAttribute('y', this.infoDefaultFocusRect.y); + this.focusRect.setAttribute('width', this.infoDefaultFocusRect.width); + this.focusRect.setAttribute('height', this.infoDefaultFocusRect.height); + this.focusRect.setAttribute('rx', SELECTED_SIZE); } } @@ -264,7 +315,7 @@ class RatingSlider { this.sliderNode.setAttribute('aria-valuetext', this.getValueText(value)); this.resetRects(); - this.setSelectedRating(value); + this.setSelectedRatingRect(value); this.setFocusRing(value); } @@ -315,14 +366,14 @@ class RatingSlider { } } - addTotalCirclesToRatingLabel() { + addTotalRectsToRatingLabel() { let valuetext = this.getValueTextWithMax(this.getValue()); this.sliderNode.setAttribute('aria-valuetext', valuetext); } onRailClick(event) { const x = this.getSVGPoint(event).x; - const diffX = x - this.railOffset; + const diffX = x - RAIL_LEFT; const rating = (diffX * this.valueMax) / this.railWidth; const value = Math.ceil(rating); @@ -348,7 +399,7 @@ class RatingSlider { onPointerMove(event) { if (this.isMoving) { const x = this.getSVGPoint(event).x; - const diffX = x - this.railOffset; + const diffX = x - RAIL_LEFT; const rating = (diffX * this.valueMax) / this.railWidth; const value = Math.ceil(rating); @@ -362,6 +413,13 @@ class RatingSlider { onPointerUp() { this.isMoving = false; } + + onResize() { + [this.infoRatingRects, this.railWidth] = this.calcRatingRects(); + this.infoDefaultFocusRect = this.calcDefaultFocusRect(); + this.setSelectedRatingRect(this.getValue()); + this.setFocusRing(this.getValue()); + } } // Initialize RatingSliders on the page diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index 15c60171d..9a1feed58 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -71,12 +71,12 @@

      Example

      aria-labelledby="id-rating-label"> - + + Example of Tabs with Vertical Orientation | WAI-ARIA Authoring Practices 1.2 + + + + + + + + + + + + + + + +
      +

      Example of Tabs with Vertical Orientation

      +

      + This example section demonstrates a tabs widget that implements the design pattern for tabs. + In this example, the tabs are oriented vertically and use automatic activation. + For additional guidance, see Deciding When to Make Selection Automatically Follow Focus. +

      +

      Similar examples include:

      + + +
      +
      +

      Example

      +
      + +
      +

      Danish Composers

      +
      +
      + + + + +
      + +
      +
      +

      Maria Theresia Ahlefeldt (16 January 1755 – 20 December 1810) was a Danish, (originally German), composer. She is known as the first female composer in Denmark. Maria Theresia composed music for several ballets, operas, and plays of the royal theatre. She was given good critic as a composer and described as a “virkelig Tonekunstnerinde” ('a True Artist of Music').

      +
      + + + +
      +
      +
      + +
      + +
      +

      Accessibility Features

      +
        +
      • + To make it easy for screen reader users to navigate from a tab to the beginning of content in the active tabpanel, the tabpanel element has tabindex="0" to include the panel in the page Tab sequence. + It is recommended that all tabpanel elements in a tab set are focusable if there are any panels in the set that contain content where the first element in the panel is not focusable. +
      • +
      • To ensure people who rely on browser or operating system high contrast settings can both distinguish the active (selected) tab from other tabs and perceive keyboard focus: +
          +
        • + The active tab has a 2 pixel border on its left and right sides and a 4 pixel border on top, while the names of inactive tabs have 1 pixel borders. + The active tab is also 4 pixels higher than the inactive tabs. +
        • +
        • + The focus ring is drawn with a CSS border on a child span element of the tab element. + This focus span is separated from the tab border by 2 pixels of space to ensure focus and selection are separately perceivable. + Note that when a tab element is focused, the outline of the tab element itself is set to 0 so that only one focus ring is displayed. +
        • +
        • + Because transparent borders are visible on some systems when high contrast settings are enabled, only the focused span element has a visible border. + When span elements are not indicating focus, they have a 0-width border and additional padding equal in width to the border that is used to indicate focus. +
        • +
        +
      • +
      +
      + +
      +

      Keyboard Support

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      KeyFunction
      Tab +
        +
      • When focus moves into the tab list, places focus on the active tab element .
      • +
      • When the tab list contains the focus, moves focus to the next element in the tab sequence, which is the tabpanel element.
      • +
      +
      Right Arrow +
        +
      • Moves focus to the next tab.
      • +
      • If focus is on the last tab, moves focus to the first tab.
      • +
      • Activates the newly focused tab.
      • +
      +
      Left Arrow +
        +
      • Moves focus to the previous tab.
      • +
      • If focus is on the first tab, moves focus to the last tab.
      • +
      • Activates the newly focused tab.
      • +
      +
      HomeMoves focus to the first tab and activates it.
      EndMoves focus to the last tab and activates it.
      +
      + +
      +

      Role, Property, State, and Tabindex Attributes

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      RoleAttributeElementUsage
      + tablist + + div + Indicates that the element serves as a container for a set of tabs.
      + aria-labelledby="ID_REFERENCE" + + div + Provides a label that describes the purpose of the set of tabs.
      + tab + + button + +
        +
      • Indicates the element serves as a tab control.
      • +
      • When focused, it is automatically activated, causing its associated tabpanel to be displayed.
      • +
      • Provides a label for its associated tabpanel.
      • +
      +
      + aria-selected="true" + + button + +
        +
      • Indicates the tab is selected and its associated tabpanel is displayed.
      • +
      • Set when a tab receives focus.
      • +
      +
      + aria-selected="false" + + button + +
        +
      • + Indicates the tab is not selected and its associated tabpanel is NOT + displayed. +
      • +
      • Set for all tab elements in the tab set except the tab that is selected.
      • +
      +
      + tabindex="-1" + + button + +
        +
      • Removes the element from the page Tab sequence.
      • +
      • Set when a tab is not selected so that only the selected tab is in the page Tab sequence.
      • +
      • Since an HTML button element is used for the tab, it is not necessary to set tabindex="0" on the selected (active) tab element.
      • +
      • This approach to managing focus is described in the section on roving tabindex.
      • +
      +
      + aria-controls="ID_REFERENCE" + + button + + Refers to the element with role=tabpanel associated with the tab. +
      + tabpanel + + div + +
        +
      • Indicates the element serves as a container for tab panel content.
      • +
      • + Is hidden unless its associated tab control is activated. +
      • +
      +
      + aria-labelledby="ID_REFERENCE" + + div + +
        +
      • Refers to the tab element that controls the panel.
      • +
      • Provides an accessible name for the tab panel.
      • +
      +
      + tabindex="0" + + div + +
        +
      • Puts the tabpanel in the page Tab sequence.
      • +
      • Facilitates navigation to panel content for assistive technology users.
      • +
      • Focusable tabpanel elements are recommended if any panels in a set contain content where the first element in the panel is not focusable.
      • +
      +
      +
      + +
      +

      Javascript and CSS Source Code

      + +
      + +
      +

      HTML Source Code

      + +
      + + +
      + +
      + + + + From 68305b14959396d30a70093769ca7e6817632e19 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Wed, 8 Nov 2023 19:05:19 -0600 Subject: [PATCH 22/54] fixed some resizing bugs --- content/patterns/slider/examples/js/slider-rating.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index 647064c19..454928690 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -175,7 +175,7 @@ class RatingSlider { let infoRatingRects = []; const railWidth = Math.min( - Math.max(24, this.sliderNode.getBoundingClientRect().width), + Math.max(260, this.sliderNode.getBoundingClientRect().width), 600 ); const rectWidth = (railWidth - RAIL_LEFT) / 10; @@ -221,7 +221,7 @@ class RatingSlider { let descX = RAIL_LEFT; descNodes[0].setAttribute('x', descX); - descX = railWidth - descNodes[1].getBoundingClientRect().width + 5; + descX = railWidth - descNodes[1].getBoundingClientRect().width + 2; descNodes[1].setAttribute('x', descX); return [infoRatingRects, railWidth]; @@ -278,7 +278,7 @@ class RatingSlider { rect.setAttribute('width', info.width - SELECTED_SIZE); } - if (rightValue <= this.valueMax) { + if (rightValue <= this.valueMax && value > 0) { rect = this.ratingRects[rightValue - 1]; info = this.infoRatingRects[rightValue - 1]; From 0093ef483be5a7e0ba6cd7e521339dbff4275307 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Wed, 8 Nov 2023 19:15:14 -0600 Subject: [PATCH 23/54] fixed some bugs in resizing --- content/patterns/slider/examples/js/slider-rating.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index 454928690..8db001b21 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -178,7 +178,7 @@ class RatingSlider { Math.max(260, this.sliderNode.getBoundingClientRect().width), 600 ); - const rectWidth = (railWidth - RAIL_LEFT) / 10; + const rectWidth = Math.round((railWidth - RAIL_LEFT) / 10); let left = RAIL_LEFT; @@ -198,7 +198,7 @@ class RatingSlider { label.setAttribute('x', 2 + left + (rectWidth - labelWidth) / 2); label.setAttribute( 'y', - -2 + RAIL_TOP + RAIL_HEIGHT - (RAIL_HEIGHT - labelHeight + 4) / 2 + -1 + RAIL_TOP + RAIL_HEIGHT - (RAIL_HEIGHT - labelHeight + 4) / 2 ); const info = { @@ -221,7 +221,9 @@ class RatingSlider { let descX = RAIL_LEFT; descNodes[0].setAttribute('x', descX); - descX = railWidth - descNodes[1].getBoundingClientRect().width + 2; + descX = Math.round( + railWidth - descNodes[1].getBoundingClientRect().width + 2 + ); descNodes[1].setAttribute('x', descX); return [infoRatingRects, railWidth]; From ca9fb0ddcba7772be06c88ae7726233ecfc97b6d Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Tue, 14 Nov 2023 11:44:26 -0600 Subject: [PATCH 24/54] added support for windows high contrast support --- .../slider/examples/css/slider-rating.css | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/content/patterns/slider/examples/css/slider-rating.css b/content/patterns/slider/examples/css/slider-rating.css index 6f9063ea1..81be219e2 100644 --- a/content/patterns/slider/examples/css/slider-rating.css +++ b/content/patterns/slider/examples/css/slider-rating.css @@ -5,7 +5,7 @@ } .rating-slider { - color: #005a9c; + color: blue; } .rating-slider svg { @@ -14,33 +14,34 @@ } .rating-slider svg .focus-ring { - fill: #eee; + fill: linktext; stroke-width: 0; fill-opacity: 0; } .rating-slider svg .value { stroke-width: 2px; - stroke: currentcolor; + stroke: linktext; fill-opacity: 0; } .rating-slider svg .label { font-size: 90%; - color: white; + fill: linktext; } .rating-slider svg .description { font-size: 90%; + fill: linktext; } .rating-slider svg .current .value { - fill: currentcolor; + fill: linktext; fill-opacity: 1; } .rating-slider svg .current .label { - fill: white; + fill: canvas; font-weight: bold; } @@ -53,11 +54,11 @@ .rating-slider svg .focus { stroke-width: 0; - stroke: currentcolor; + stroke: linktext; fill-opacity: 0; } .rating-slider:focus svg .focus-ring { stroke-width: 2px; - stroke: currentcolor; + stroke: linktext; } From 0b079c977c4a00a21444b51c5d861988b491f9a4 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Tue, 14 Nov 2023 11:54:12 -0600 Subject: [PATCH 25/54] updated documentation for rating slider --- content/patterns/slider/examples/slider-rating.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index 9a1feed58..c5656bbb1 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -131,7 +131,7 @@

      Accessibility Features

    • To highlight the interactive nature of the satisfaction rating, a focus ring appears around the group of rating options when the slider has focus and no rating value has been selected.
    • To ensure the borders of the rating values and focus ring have sufficient contrast with the background when high contrast settings invert colors, the color of the borders are synchronized with the color of the text content. - For example, the color of the rating value borders is set to match the foreground color of high contrast mode text by specifying the CSS currentcolor value for the stroke property of each inline SVG rect and text elements. + For example, the color of the rating value borders is set to match the foreground color of high contrast mode text by specifying the CSS canvas and linkText values for the stroke and fill properties of each inline SVG rect and text elements. If specific colors were used to specify the stroke and fill properties, the color of these elements would remain the same in high contrast mode, which could lead to insufficient contrast between them and their background or even make them invisible if their color were to match the high contrast mode background.
      Note: The SVG element needs to have the CSS forced-color-adjust property set to the value auto for the currentcolor value to be updated in high contrast modes. Some browsers do not use auto for the default value.
    • From 802d6e966e3da8c41502ebb920495b981ae3327e Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Tue, 14 Nov 2023 14:56:59 -0600 Subject: [PATCH 26/54] added media query for forced colors --- .../slider/examples/css/slider-rating.css | 54 +++++++++++++++---- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/content/patterns/slider/examples/css/slider-rating.css b/content/patterns/slider/examples/css/slider-rating.css index 81be219e2..d57332ffa 100644 --- a/content/patterns/slider/examples/css/slider-rating.css +++ b/content/patterns/slider/examples/css/slider-rating.css @@ -5,7 +5,7 @@ } .rating-slider { - color: blue; + color: #005a9c; } .rating-slider svg { @@ -14,34 +14,34 @@ } .rating-slider svg .focus-ring { - fill: linktext; + fill: currentcolor; stroke-width: 0; fill-opacity: 0; } .rating-slider svg .value { stroke-width: 2px; - stroke: linktext; + stroke: currentcolor; fill-opacity: 0; } .rating-slider svg .label { font-size: 90%; - fill: linktext; + fill: currentcolor; } .rating-slider svg .description { font-size: 90%; - fill: linktext; + fill: currentcolor; } .rating-slider svg .current .value { - fill: linktext; + fill: currentcolor; fill-opacity: 1; } .rating-slider svg .current .label { - fill: canvas; + fill: white; font-weight: bold; } @@ -54,11 +54,47 @@ .rating-slider svg .focus { stroke-width: 0; - stroke: linktext; + stroke: currentcolor; fill-opacity: 0; } .rating-slider:focus svg .focus-ring { stroke-width: 2px; - stroke: linktext; + stroke: currentcolor; +} + +@media (forced-colors: active) { + .rating-slider svg .focus-ring { + fill: linktext; + } + + .rating-slider svg .value { + stroke: linktext; + } + + .rating-slider svg .label { + fill: linktext; + } + + .rating-slider svg .description { + fill: linktext; + } + + .rating-slider svg .current .value { + fill: linktext; + } + + .rating-slider svg .current .label { + fill: canvas; + } + + /* focus styling */ + + .rating-slider svg .focus { + stroke: linktext; + } + + .rating-slider:focus svg .focus-ring { + stroke: linktext; + } } From a7f4dd31aa5d4b557c9fe8a05bd60c3e2d81f61f Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Tue, 14 Nov 2023 15:06:08 -0600 Subject: [PATCH 27/54] updated @media documentation --- content/patterns/slider/examples/slider-rating.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index c5656bbb1..5510674e5 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -130,8 +130,8 @@

      Accessibility Features

    • To highlight the interactive nature of the satisfaction rating, a focus ring appears around the group of rating options when the slider has focus and no rating value has been selected.
    • - To ensure the borders of the rating values and focus ring have sufficient contrast with the background when high contrast settings invert colors, the color of the borders are synchronized with the color of the text content. - For example, the color of the rating value borders is set to match the foreground color of high contrast mode text by specifying the CSS canvas and linkText values for the stroke and fill properties of each inline SVG rect and text elements. + To ensure the borders of the rating values and focus ring have sufficient contrast with the background when high contrast settings invert colors, the color of the borders are synchronized with the color of the text content using a CSS media query selector (e.g. @media (forced-colors: active)) . + For example, the color of the rating value borders is set to match link foreground color of high contrast mode text by specifying the CSS canvas and linkText values for the stroke and fill properties of each inline SVG rect and text elements. If specific colors were used to specify the stroke and fill properties, the color of these elements would remain the same in high contrast mode, which could lead to insufficient contrast between them and their background or even make them invisible if their color were to match the high contrast mode background.
      Note: The SVG element needs to have the CSS forced-color-adjust property set to the value auto for the currentcolor value to be updated in high contrast modes. Some browsers do not use auto for the default value.
    • From 1da4e84ce44ed863208b7de8a600d98808d364c4 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Tue, 14 Nov 2023 17:32:11 -0600 Subject: [PATCH 28/54] fixed positioning bug --- content/patterns/slider/examples/js/slider-rating.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index 8db001b21..3ae4a46f2 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -195,10 +195,16 @@ class RatingSlider { const labelWidth = label.getBoundingClientRect().width; const labelHeight = label.getBoundingClientRect().height; - label.setAttribute('x', 2 + left + (rectWidth - labelWidth) / 2); + label.setAttribute( + 'x', + 2 + left + Math.round((rectWidth - labelWidth) / 2) + ); label.setAttribute( 'y', - -1 + RAIL_TOP + RAIL_HEIGHT - (RAIL_HEIGHT - labelHeight + 4) / 2 + -1 + + RAIL_TOP + + RAIL_HEIGHT - + Math.round((RAIL_HEIGHT - labelHeight + 4) / 2) ); const info = { From 7911cacc5f55c2600f9e252e4ae26d8abd5381dc Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Tue, 14 Nov 2023 17:40:53 -0600 Subject: [PATCH 29/54] updated description text color --- content/patterns/slider/examples/css/slider-rating.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/patterns/slider/examples/css/slider-rating.css b/content/patterns/slider/examples/css/slider-rating.css index d57332ffa..5d32cc5b6 100644 --- a/content/patterns/slider/examples/css/slider-rating.css +++ b/content/patterns/slider/examples/css/slider-rating.css @@ -32,7 +32,7 @@ .rating-slider svg .description { font-size: 90%; - fill: currentcolor; + fill: canvasText; } .rating-slider svg .current .value { From 46cb2bbbd3201af6e6c52276763f02daeb14e0f1 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Wed, 15 Nov 2023 13:53:31 -0600 Subject: [PATCH 30/54] updated text element height calc --- content/patterns/slider/examples/js/slider-rating.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index 3ae4a46f2..1a0446f9e 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -192,8 +192,8 @@ class RatingSlider { rect.setAttribute('height', RAIL_HEIGHT); rect.removeAttribute('rx'); - const labelWidth = label.getBoundingClientRect().width; - const labelHeight = label.getBoundingClientRect().height; + const labelWidth = label.getBBox().width; + const labelHeight = label.getBBox().height; label.setAttribute( 'x', @@ -227,9 +227,7 @@ class RatingSlider { let descX = RAIL_LEFT; descNodes[0].setAttribute('x', descX); - descX = Math.round( - railWidth - descNodes[1].getBoundingClientRect().width + 2 - ); + descX = Math.round(railWidth - descNodes[1].getBBox().width + 2); descNodes[1].setAttribute('x', descX); return [infoRatingRects, railWidth]; From 240c65c7916b13739f1350937e82c3d0b3bcd595 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Wed, 15 Nov 2023 14:26:05 -0600 Subject: [PATCH 31/54] updated label height calc --- content/patterns/slider/examples/css/slider-rating.css | 2 ++ content/patterns/slider/examples/js/slider-rating.js | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/content/patterns/slider/examples/css/slider-rating.css b/content/patterns/slider/examples/css/slider-rating.css index 5d32cc5b6..cbc10e63f 100644 --- a/content/patterns/slider/examples/css/slider-rating.css +++ b/content/patterns/slider/examples/css/slider-rating.css @@ -27,11 +27,13 @@ .rating-slider svg .label { font-size: 90%; + font-family: sans-serif; fill: currentcolor; } .rating-slider svg .description { font-size: 90%; + font-family: sans-serif; fill: canvasText; } diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index 1a0446f9e..6cae4a4aa 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -192,8 +192,11 @@ class RatingSlider { rect.setAttribute('height', RAIL_HEIGHT); rect.removeAttribute('rx'); - const labelWidth = label.getBBox().width; - const labelHeight = label.getBBox().height; + const labelWidth = Math.round(label.getBBox().width); + const labelHeight = Math.round(label.getBBox().height); + + label.setAttribute('data-width', labelWidth); + label.setAttribute('data-height', labelHeight); label.setAttribute( 'x', From 7e65ec0c90e1d27f51b1608bd03d326281900a66 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Wed, 15 Nov 2023 14:42:38 -0600 Subject: [PATCH 32/54] removed debugging code --- content/patterns/slider/examples/js/slider-rating.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index 6cae4a4aa..3491de8b6 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -195,9 +195,6 @@ class RatingSlider { const labelWidth = Math.round(label.getBBox().width); const labelHeight = Math.round(label.getBBox().height); - label.setAttribute('data-width', labelWidth); - label.setAttribute('data-height', labelHeight); - label.setAttribute( 'x', 2 + left + Math.round((rectWidth - labelWidth) / 2) From 453b580ae30166a4600b2f5c483b7d281252cacf Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Wed, 15 Nov 2023 15:35:05 -0600 Subject: [PATCH 33/54] changed styling of selected value --- .../slider/examples/css/slider-rating.css | 1 - .../slider/examples/js/slider-rating.js | 28 +++++++++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/content/patterns/slider/examples/css/slider-rating.css b/content/patterns/slider/examples/css/slider-rating.css index cbc10e63f..c142cc2ad 100644 --- a/content/patterns/slider/examples/css/slider-rating.css +++ b/content/patterns/slider/examples/css/slider-rating.css @@ -33,7 +33,6 @@ .rating-slider svg .description { font-size: 90%; - font-family: sans-serif; fill: canvasText; } diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index 3491de8b6..f7874d2d0 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -192,6 +192,8 @@ class RatingSlider { rect.setAttribute('height', RAIL_HEIGHT); rect.removeAttribute('rx'); + label.setAttribute('style', 'font-size: 95%'); + const labelWidth = Math.round(label.getBBox().width); const labelHeight = Math.round(label.getBBox().height); @@ -259,7 +261,7 @@ class RatingSlider { } setSelectedRatingRect(value) { - let rect, info; + let label, rect, info; const leftValue = value - 1; const rightValue = value + 1; @@ -267,14 +269,34 @@ class RatingSlider { if (value > 0) { rect = this.ratingRects[value - 1]; info = this.infoRatingRects[value - 1]; + label = this.ratingRectLabels[value - 1]; + + rect.parentNode.classList.add('current'); + + const rectWidth = info.width + 2 * SELECTED_SIZE; rect.setAttribute('x', info.x - SELECTED_SIZE); rect.setAttribute('y', info.y - SELECTED_SIZE); - rect.setAttribute('width', info.width + 2 * SELECTED_SIZE); + rect.setAttribute('width', rectWidth); rect.setAttribute('height', info.height + 2 * SELECTED_SIZE); rect.setAttribute('rx', SELECTED_SIZE); - rect.parentNode.classList.add('current'); + label.setAttribute('style', 'font-size: 120%'); + + const labelWidth = Math.round(label.getBBox().width); + const labelHeight = Math.round(label.getBBox().height); + + label.setAttribute( + 'x', + 2 + info.x - SELECTED_SIZE + Math.round((rectWidth - labelWidth) / 2) + ); + label.setAttribute( + 'y', + -1 + + RAIL_TOP + + RAIL_HEIGHT - + Math.round((RAIL_HEIGHT - labelHeight + 4) / 2) + ); } if (leftValue > 0) { From 4fae83a4416a5a5c5e6a5139f805bcb96d0ef0d7 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Wed, 15 Nov 2023 16:38:19 -0600 Subject: [PATCH 34/54] fixed linting errors --- content/patterns/slider/examples/css/slider-rating.css | 2 +- cspell.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/content/patterns/slider/examples/css/slider-rating.css b/content/patterns/slider/examples/css/slider-rating.css index c142cc2ad..7b02d5a2f 100644 --- a/content/patterns/slider/examples/css/slider-rating.css +++ b/content/patterns/slider/examples/css/slider-rating.css @@ -33,7 +33,7 @@ .rating-slider svg .description { font-size: 90%; - fill: canvasText; + fill: canvastext; } .rating-slider svg .current .value { diff --git a/cspell.json b/cspell.json index dc73b071e..3c4210b15 100644 --- a/cspell.json +++ b/cspell.json @@ -122,6 +122,7 @@ "Leventhal", "Lewandowski", "Lilley", + "linktext", "listbox's", "Listboxes", "listitems", From 9c21e04721e9d3ec610272d37171e698e29278ac Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Wed, 15 Nov 2023 18:43:51 -0600 Subject: [PATCH 35/54] fixed linting errors --- cspell.json | 1 + 1 file changed, 1 insertion(+) diff --git a/cspell.json b/cspell.json index 3c4210b15..cc08dbcbb 100644 --- a/cspell.json +++ b/cspell.json @@ -26,6 +26,7 @@ "Brinza", "Bucketwheat", "camelcase", + "canvasText", "Capitan", "Carron", "checkmark", From 6729e7c05b7e5f431779569e7416e1ffe27d5749 Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Thu, 16 Nov 2023 09:11:32 -0600 Subject: [PATCH 36/54] refactored js code --- .../slider/examples/js/slider-rating.js | 151 +++++++++--------- cspell.json | 2 +- 2 files changed, 73 insertions(+), 80 deletions(-) diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index f7874d2d0..4b79f91da 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -183,33 +183,18 @@ class RatingSlider { let left = RAIL_LEFT; for (let i = 0; i < this.ratingRects.length; i += 1) { - const rect = this.ratingRects[i]; - const label = this.ratingRectLabels[i]; - - rect.setAttribute('x', left); - rect.setAttribute('y', RAIL_TOP); - rect.setAttribute('width', rectWidth); - rect.setAttribute('height', RAIL_HEIGHT); - rect.removeAttribute('rx'); - - label.setAttribute('style', 'font-size: 95%'); - - const labelWidth = Math.round(label.getBBox().width); - const labelHeight = Math.round(label.getBBox().height); - - label.setAttribute( - 'x', - 2 + left + Math.round((rectWidth - labelWidth) / 2) - ); - label.setAttribute( - 'y', - -1 + - RAIL_TOP + - RAIL_HEIGHT - - Math.round((RAIL_HEIGHT - labelHeight + 4) / 2) - ); - - const info = { + const rectNode = this.ratingRects[i]; + const labelNode = this.ratingRectLabels[i]; + + rectNode.setAttribute('x', left); + rectNode.setAttribute('y', RAIL_TOP); + rectNode.setAttribute('width', rectWidth); + rectNode.setAttribute('height', RAIL_HEIGHT); + rectNode.removeAttribute('rx'); + + this.setLabelPosition(labelNode, left, rectWidth); + + const infoRect = { x: left, y: RAIL_TOP, width: rectWidth, @@ -217,9 +202,9 @@ class RatingSlider { rx: 0, }; - infoRatingRects[i] = info; + infoRatingRects[i] = infoRect; - rect.parentNode.classList.remove('current'); + rectNode.parentNode.classList.remove('current'); left += rectWidth; } @@ -247,84 +232,92 @@ class RatingSlider { resetRects() { for (let i = 0; i < this.ratingRects.length; i += 1) { - const rect = this.ratingRects[i]; + const rectNode = this.ratingRects[i]; const infoRect = this.infoRatingRects[i]; + const labelNode = this.ratingRectLabels[i]; + + rectNode.setAttribute('x', infoRect.x); + rectNode.setAttribute('y', infoRect.y); + rectNode.setAttribute('width', infoRect.width); + rectNode.setAttribute('height', infoRect.height); + rectNode.removeAttribute('rx'); - rect.setAttribute('x', infoRect.x); - rect.setAttribute('y', infoRect.y); - rect.setAttribute('width', infoRect.width); - rect.setAttribute('height', infoRect.height); - rect.removeAttribute('rx'); + this.setLabelPosition(labelNode, infoRect.x, infoRect.width); - rect.parentNode.classList.remove('current'); + rectNode.parentNode.classList.remove('current'); } } setSelectedRatingRect(value) { - let label, rect, info; + let labelNode, rectNode, infoRect; const leftValue = value - 1; const rightValue = value + 1; if (value > 0) { - rect = this.ratingRects[value - 1]; - info = this.infoRatingRects[value - 1]; - label = this.ratingRectLabels[value - 1]; - - rect.parentNode.classList.add('current'); - - const rectWidth = info.width + 2 * SELECTED_SIZE; - - rect.setAttribute('x', info.x - SELECTED_SIZE); - rect.setAttribute('y', info.y - SELECTED_SIZE); - rect.setAttribute('width', rectWidth); - rect.setAttribute('height', info.height + 2 * SELECTED_SIZE); - rect.setAttribute('rx', SELECTED_SIZE); - - label.setAttribute('style', 'font-size: 120%'); - - const labelWidth = Math.round(label.getBBox().width); - const labelHeight = Math.round(label.getBBox().height); - - label.setAttribute( - 'x', - 2 + info.x - SELECTED_SIZE + Math.round((rectWidth - labelWidth) / 2) - ); - label.setAttribute( - 'y', - -1 + - RAIL_TOP + - RAIL_HEIGHT - - Math.round((RAIL_HEIGHT - labelHeight + 4) / 2) - ); + rectNode = this.ratingRects[value - 1]; + infoRect = this.infoRatingRects[value - 1]; + labelNode = this.ratingRectLabels[value - 1]; + + rectNode.parentNode.classList.add('current'); + + const rectWidth = infoRect.width + 2 * SELECTED_SIZE; + const x = infoRect.x - SELECTED_SIZE; + + rectNode.setAttribute('x', x); + rectNode.setAttribute('y', infoRect.y - SELECTED_SIZE); + rectNode.setAttribute('width', rectWidth); + rectNode.setAttribute('height', infoRect.height + 2 * SELECTED_SIZE); + rectNode.setAttribute('rx', SELECTED_SIZE); + + this.setLabelPosition(labelNode, x, rectWidth, '120%'); } if (leftValue > 0) { - rect = this.ratingRects[leftValue - 1]; - info = this.infoRatingRects[leftValue - 1]; + rectNode = this.ratingRects[leftValue - 1]; + infoRect = this.infoRatingRects[leftValue - 1]; - rect.setAttribute('width', info.width - SELECTED_SIZE); + rectNode.setAttribute('width', infoRect.width - SELECTED_SIZE); } if (rightValue <= this.valueMax && value > 0) { - rect = this.ratingRects[rightValue - 1]; - info = this.infoRatingRects[rightValue - 1]; + rectNode = this.ratingRects[rightValue - 1]; + infoRect = this.infoRatingRects[rightValue - 1]; - rect.setAttribute('x', info.x + SELECTED_SIZE); - rect.setAttribute('width', info.width - SELECTED_SIZE); + rectNode.setAttribute('x', infoRect.x + SELECTED_SIZE); + rectNode.setAttribute('width', infoRect.width - SELECTED_SIZE); } } + setLabelPosition(labelNode, x, rectWidth, fontSize = '95%') { + labelNode.setAttribute('style', `font-size: ${fontSize}`); + + const labelWidth = Math.round(labelNode.getBBox().width); + const labelHeight = Math.round(labelNode.getBBox().height); + + labelNode.setAttribute( + 'x', + 2 + x + Math.round((rectWidth - labelWidth) / 2) + ); + labelNode.setAttribute( + 'y', + -1 + + RAIL_TOP + + RAIL_HEIGHT - + Math.round((RAIL_HEIGHT - labelHeight + 4) / 2) + ); + } + setFocusRing(value) { const size = 2 * SELECTED_SIZE; if (value > 0 && value <= this.valueMax) { - const info = this.infoRatingRects[value - 1]; + const infoRect = this.infoRatingRects[value - 1]; - this.focusRect.setAttribute('x', info.x - size); - this.focusRect.setAttribute('y', info.y - size); - this.focusRect.setAttribute('width', info.width + 2 * size); - this.focusRect.setAttribute('height', info.height + 2 * size); + this.focusRect.setAttribute('x', infoRect.x - size); + this.focusRect.setAttribute('y', infoRect.y - size); + this.focusRect.setAttribute('width', infoRect.width + 2 * size); + this.focusRect.setAttribute('height', infoRect.height + 2 * size); this.focusRect.setAttribute('rx', size); } else { // Set ring around entire control diff --git a/cspell.json b/cspell.json index cc08dbcbb..5cc7a67b1 100644 --- a/cspell.json +++ b/cspell.json @@ -26,7 +26,7 @@ "Brinza", "Bucketwheat", "camelcase", - "canvasText", + "canvastext", "Capitan", "Carron", "checkmark", From 73838792414b8d072c57993a05019ae014a089cb Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Wed, 29 Nov 2023 11:34:06 -0600 Subject: [PATCH 37/54] fixed pointer bug --- .../slider/examples/css/slider-rating.css | 14 +- .../slider/examples/js/slider-rating.js | 163 ++++++++---------- .../slider/examples/slider-rating.html | 40 ++--- 3 files changed, 104 insertions(+), 113 deletions(-) diff --git a/content/patterns/slider/examples/css/slider-rating.css b/content/patterns/slider/examples/css/slider-rating.css index 7b02d5a2f..2d4326910 100644 --- a/content/patterns/slider/examples/css/slider-rating.css +++ b/content/patterns/slider/examples/css/slider-rating.css @@ -6,6 +6,12 @@ .rating-slider { color: #005a9c; + -webkit-touch-callout: none; + user-select: none; + user-select: none; + user-select: none; + user-select: none; + user-select: none; } .rating-slider svg { @@ -19,7 +25,7 @@ fill-opacity: 0; } -.rating-slider svg .value { +.rating-slider svg .target { stroke-width: 2px; stroke: currentcolor; fill-opacity: 0; @@ -36,7 +42,7 @@ fill: canvastext; } -.rating-slider svg .current .value { +.rating-slider svg .current .target { fill: currentcolor; fill-opacity: 1; } @@ -69,7 +75,7 @@ fill: linktext; } - .rating-slider svg .value { + .rating-slider svg .target { stroke: linktext; } @@ -81,7 +87,7 @@ fill: linktext; } - .rating-slider svg .current .value { + .rating-slider svg .current .target { fill: linktext; } diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index 4b79f91da..7c4612907 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -22,37 +22,34 @@ class RatingSlider { this.svgNode = domNode.querySelector('svg'); this.focusRect = domNode.querySelector('.focus-ring'); - this.ratingRects = Array.from( - domNode.querySelectorAll('g.rating rect.value') + this.targetRects = Array.from( + domNode.querySelectorAll('g.rating rect.target') ); - this.ratingRectLabels = Array.from( + this.labelTexts = Array.from( domNode.querySelectorAll('g.rating text.label') ); - [this.infoRatingRects, this.railWidth] = this.calcRatingRects(); + [this.infoTargetRects, this.railWidth] = this.calcRatingRects(); this.infoDefaultFocusRect = this.calcDefaultFocusRect(); this.valueMin = this.getValueMin(); this.valueMax = this.getValueMax(); - this.svgPoint = this.svgNode.createSVGPoint(); - - // define possible slider positions - this.sliderNode.addEventListener( 'keydown', this.onSliderKeydown.bind(this) ); - this.svgNode.addEventListener('click', this.onRailClick.bind(this)); - this.svgNode.addEventListener( - 'pointerdown', - this.onSliderPointerDown.bind(this) - ); + this.labelTexts.forEach((lt) => { + lt.addEventListener('click', this.onTargetClick.bind(this)); + }); - // bind a pointermove event handler to move pointer - this.svgNode.addEventListener('pointermove', this.onPointerMove.bind(this)); + this.targetRects.forEach((tr) => { + tr.addEventListener('click', this.onTargetClick.bind(this)); + tr.addEventListener('pointerdown', this.onSliderPointerDown.bind(this)); + tr.addEventListener('pointermove', this.onPointerMove.bind(this)); + }); // bind a pointerup event handler to stop tracking pointer movements document.addEventListener('pointerup', this.onPointerUp.bind(this)); @@ -68,13 +65,6 @@ class RatingSlider { this.setFocusRing(0); } - // Get point in global SVG space - getSVGPoint(event) { - this.svgPoint.x = event.clientX; - this.svgPoint.y = event.clientY; - return this.svgPoint.matrixTransform(this.svgNode.getScreenCTM().inverse()); - } - getValue() { return parseFloat(this.sliderNode.getAttribute('aria-valuenow')); } @@ -182,19 +172,19 @@ class RatingSlider { let left = RAIL_LEFT; - for (let i = 0; i < this.ratingRects.length; i += 1) { - const rectNode = this.ratingRects[i]; - const labelNode = this.ratingRectLabels[i]; + for (let i = 0; i < this.targetRects.length; i += 1) { + const targetNode = this.targetRects[i]; + const labelNode = this.labelTexts[i]; - rectNode.setAttribute('x', left); - rectNode.setAttribute('y', RAIL_TOP); - rectNode.setAttribute('width', rectWidth); - rectNode.setAttribute('height', RAIL_HEIGHT); - rectNode.removeAttribute('rx'); + targetNode.setAttribute('x', left); + targetNode.setAttribute('y', RAIL_TOP); + targetNode.setAttribute('width', rectWidth); + targetNode.setAttribute('height', RAIL_HEIGHT); + targetNode.removeAttribute('rx'); this.setLabelPosition(labelNode, left, rectWidth); - const infoRect = { + const infoTarget = { x: left, y: RAIL_TOP, width: rectWidth, @@ -202,9 +192,9 @@ class RatingSlider { rx: 0, }; - infoRatingRects[i] = infoRect; + infoRatingRects[i] = infoTarget; - rectNode.parentNode.classList.remove('current'); + targetNode.parentNode.classList.remove('current'); left += rectWidth; } @@ -231,61 +221,61 @@ class RatingSlider { } resetRects() { - for (let i = 0; i < this.ratingRects.length; i += 1) { - const rectNode = this.ratingRects[i]; - const infoRect = this.infoRatingRects[i]; - const labelNode = this.ratingRectLabels[i]; + for (let i = 0; i < this.targetRects.length; i += 1) { + const targetNode = this.targetRects[i]; + const infoTarget = this.infoTargetRects[i]; + const labelNode = this.labelTexts[i]; - rectNode.setAttribute('x', infoRect.x); - rectNode.setAttribute('y', infoRect.y); - rectNode.setAttribute('width', infoRect.width); - rectNode.setAttribute('height', infoRect.height); - rectNode.removeAttribute('rx'); + targetNode.setAttribute('x', infoTarget.x); + targetNode.setAttribute('y', infoTarget.y); + targetNode.setAttribute('width', infoTarget.width); + targetNode.setAttribute('height', infoTarget.height); + targetNode.removeAttribute('rx'); - this.setLabelPosition(labelNode, infoRect.x, infoRect.width); + this.setLabelPosition(labelNode, infoTarget.x, infoTarget.width); - rectNode.parentNode.classList.remove('current'); + targetNode.parentNode.classList.remove('current'); } } setSelectedRatingRect(value) { - let labelNode, rectNode, infoRect; + let labelNode, targetNode, infoTarget; const leftValue = value - 1; const rightValue = value + 1; if (value > 0) { - rectNode = this.ratingRects[value - 1]; - infoRect = this.infoRatingRects[value - 1]; - labelNode = this.ratingRectLabels[value - 1]; + targetNode = this.targetRects[value - 1]; + infoTarget = this.infoTargetRects[value - 1]; + labelNode = this.labelTexts[value - 1]; - rectNode.parentNode.classList.add('current'); + targetNode.parentNode.classList.add('current'); - const rectWidth = infoRect.width + 2 * SELECTED_SIZE; - const x = infoRect.x - SELECTED_SIZE; + const rectWidth = infoTarget.width + 2 * SELECTED_SIZE; + const x = infoTarget.x - SELECTED_SIZE; - rectNode.setAttribute('x', x); - rectNode.setAttribute('y', infoRect.y - SELECTED_SIZE); - rectNode.setAttribute('width', rectWidth); - rectNode.setAttribute('height', infoRect.height + 2 * SELECTED_SIZE); - rectNode.setAttribute('rx', SELECTED_SIZE); + targetNode.setAttribute('x', x); + targetNode.setAttribute('y', infoTarget.y - SELECTED_SIZE); + targetNode.setAttribute('width', rectWidth); + targetNode.setAttribute('height', infoTarget.height + 2 * SELECTED_SIZE); + targetNode.setAttribute('rx', SELECTED_SIZE); this.setLabelPosition(labelNode, x, rectWidth, '120%'); } if (leftValue > 0) { - rectNode = this.ratingRects[leftValue - 1]; - infoRect = this.infoRatingRects[leftValue - 1]; + targetNode = this.targetRects[leftValue - 1]; + infoTarget = this.infoTargetRects[leftValue - 1]; - rectNode.setAttribute('width', infoRect.width - SELECTED_SIZE); + targetNode.setAttribute('width', infoTarget.width - SELECTED_SIZE); } if (rightValue <= this.valueMax && value > 0) { - rectNode = this.ratingRects[rightValue - 1]; - infoRect = this.infoRatingRects[rightValue - 1]; + targetNode = this.targetRects[rightValue - 1]; + infoTarget = this.infoTargetRects[rightValue - 1]; - rectNode.setAttribute('x', infoRect.x + SELECTED_SIZE); - rectNode.setAttribute('width', infoRect.width - SELECTED_SIZE); + targetNode.setAttribute('x', infoTarget.x + SELECTED_SIZE); + targetNode.setAttribute('width', infoTarget.width - SELECTED_SIZE); } } @@ -312,12 +302,12 @@ class RatingSlider { const size = 2 * SELECTED_SIZE; if (value > 0 && value <= this.valueMax) { - const infoRect = this.infoRatingRects[value - 1]; + const infoTarget = this.infoTargetRects[value - 1]; - this.focusRect.setAttribute('x', infoRect.x - size); - this.focusRect.setAttribute('y', infoRect.y - size); - this.focusRect.setAttribute('width', infoRect.width + 2 * size); - this.focusRect.setAttribute('height', infoRect.height + 2 * size); + this.focusRect.setAttribute('x', infoTarget.x - size); + this.focusRect.setAttribute('y', infoTarget.y - size); + this.focusRect.setAttribute('width', infoTarget.width + 2 * size); + this.focusRect.setAttribute('height', infoTarget.height + 2 * size); this.focusRect.setAttribute('rx', size); } else { // Set ring around entire control @@ -392,13 +382,10 @@ class RatingSlider { this.sliderNode.setAttribute('aria-valuetext', valuetext); } - onRailClick(event) { - const x = this.getSVGPoint(event).x; - const diffX = x - RAIL_LEFT; - const rating = (diffX * this.valueMax) / this.railWidth; - const value = Math.ceil(rating); - - this.moveSliderTo(value); + onTargetClick(event) { + this.moveSliderTo( + event.currentTarget.parentNode.getAttribute('data-value') + ); event.preventDefault(); event.stopPropagation(); @@ -408,35 +395,33 @@ class RatingSlider { } onSliderPointerDown(event) { - this.isMoving = true; - + if (!this.isMoving) { + this.isMoving = true; + } event.preventDefault(); event.stopPropagation(); - - // Set focus to the clicked handle - this.sliderNode.focus(); } onPointerMove(event) { if (this.isMoving) { - const x = this.getSVGPoint(event).x; - const diffX = x - RAIL_LEFT; - const rating = (diffX * this.valueMax) / this.railWidth; - const value = Math.ceil(rating); - - this.moveSliderTo(value); - + this.moveSliderTo( + event.currentTarget.parentNode.getAttribute('data-value') + ); event.preventDefault(); event.stopPropagation(); } } onPointerUp() { - this.isMoving = false; + if (this.isMoving) { + this.isMoving = false; + // Set focus to the clicked handle + this.sliderNode.focus(); + } } onResize() { - [this.infoRatingRects, this.railWidth] = this.calcRatingRects(); + [this.infoTargetRects, this.railWidth] = this.calcRatingRects(); this.infoDefaultFocusRect = this.calcDefaultFocusRect(); this.setSelectedRatingRect(this.getValue()); this.setFocusRing(this.getValue()); diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index 5510674e5..90fd4a79e 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -73,45 +73,45 @@

      Example

      - - Example of Tabs with Vertical Orientation | WAI-ARIA Authoring Practices 1.2 - - - - - - - - - - - - - - - -
      -

      Example of Tabs with Vertical Orientation

      -

      - This example section demonstrates a tabs widget that implements the design pattern for tabs. - In this example, the tabs are oriented vertically and use automatic activation. - For additional guidance, see Deciding When to Make Selection Automatically Follow Focus. -

      -

      Similar examples include:

      - - -
      -
      -

      Example

      -
      - -
      -

      Danish Composers

      -
      -
      - - - - -
      - -
      -
      -

      Maria Theresia Ahlefeldt (16 January 1755 – 20 December 1810) was a Danish, (originally German), composer. She is known as the first female composer in Denmark. Maria Theresia composed music for several ballets, operas, and plays of the royal theatre. She was given good critic as a composer and described as a “virkelig Tonekunstnerinde” ('a True Artist of Music').

      -
      - - - -
      -
      -
      - -
      - -
      -

      Accessibility Features

      -
        -
      • - To make it easy for screen reader users to navigate from a tab to the beginning of content in the active tabpanel, the tabpanel element has tabindex="0" to include the panel in the page Tab sequence. - It is recommended that all tabpanel elements in a tab set are focusable if there are any panels in the set that contain content where the first element in the panel is not focusable. -
      • -
      • To ensure people who rely on browser or operating system high contrast settings can both distinguish the active (selected) tab from other tabs and perceive keyboard focus: -
          -
        • - The active tab has a 2 pixel border on its left and right sides and a 4 pixel border on top, while the names of inactive tabs have 1 pixel borders. - The active tab is also 4 pixels higher than the inactive tabs. -
        • -
        • - The focus ring is drawn with a CSS border on a child span element of the tab element. - This focus span is separated from the tab border by 2 pixels of space to ensure focus and selection are separately perceivable. - Note that when a tab element is focused, the outline of the tab element itself is set to 0 so that only one focus ring is displayed. -
        • -
        • - Because transparent borders are visible on some systems when high contrast settings are enabled, only the focused span element has a visible border. - When span elements are not indicating focus, they have a 0-width border and additional padding equal in width to the border that is used to indicate focus. -
        • -
        -
      • -
      -
      - -
      -

      Keyboard Support

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      KeyFunction
      Tab -
        -
      • When focus moves into the tab list, places focus on the active tab element .
      • -
      • When the tab list contains the focus, moves focus to the next element in the tab sequence, which is the tabpanel element.
      • -
      -
      Right Arrow -
        -
      • Moves focus to the next tab.
      • -
      • If focus is on the last tab, moves focus to the first tab.
      • -
      • Activates the newly focused tab.
      • -
      -
      Left Arrow -
        -
      • Moves focus to the previous tab.
      • -
      • If focus is on the first tab, moves focus to the last tab.
      • -
      • Activates the newly focused tab.
      • -
      -
      HomeMoves focus to the first tab and activates it.
      EndMoves focus to the last tab and activates it.
      -
      - -
      -

      Role, Property, State, and Tabindex Attributes

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      RoleAttributeElementUsage
      - tablist - - div - Indicates that the element serves as a container for a set of tabs.
      - aria-labelledby="ID_REFERENCE" - - div - Provides a label that describes the purpose of the set of tabs.
      - tab - - button - -
        -
      • Indicates the element serves as a tab control.
      • -
      • When focused, it is automatically activated, causing its associated tabpanel to be displayed.
      • -
      • Provides a label for its associated tabpanel.
      • -
      -
      - aria-selected="true" - - button - -
        -
      • Indicates the tab is selected and its associated tabpanel is displayed.
      • -
      • Set when a tab receives focus.
      • -
      -
      - aria-selected="false" - - button - -
        -
      • - Indicates the tab is not selected and its associated tabpanel is NOT - displayed. -
      • -
      • Set for all tab elements in the tab set except the tab that is selected.
      • -
      -
      - tabindex="-1" - - button - -
        -
      • Removes the element from the page Tab sequence.
      • -
      • Set when a tab is not selected so that only the selected tab is in the page Tab sequence.
      • -
      • Since an HTML button element is used for the tab, it is not necessary to set tabindex="0" on the selected (active) tab element.
      • -
      • This approach to managing focus is described in the section on roving tabindex.
      • -
      -
      - aria-controls="ID_REFERENCE" - - button - - Refers to the element with role=tabpanel associated with the tab. -
      - tabpanel - - div - -
        -
      • Indicates the element serves as a container for tab panel content.
      • -
      • - Is hidden unless its associated tab control is activated. -
      • -
      -
      - aria-labelledby="ID_REFERENCE" - - div - -
        -
      • Refers to the tab element that controls the panel.
      • -
      • Provides an accessible name for the tab panel.
      • -
      -
      - tabindex="0" - - div - -
        -
      • Puts the tabpanel in the page Tab sequence.
      • -
      • Facilitates navigation to panel content for assistive technology users.
      • -
      • Focusable tabpanel elements are recommended if any panels in a set contain content where the first element in the panel is not focusable.
      • -
      -
      -
      - -
      -

      Javascript and CSS Source Code

      - -
      - -
      -

      HTML Source Code

      - -
      - - -
      - -
      - - - - From 474dc01b80726c4d90cade5e0565c8eda256a3ea Mon Sep 17 00:00:00 2001 From: Jon Gunderson Date: Thu, 30 Nov 2023 18:04:16 -0600 Subject: [PATCH 40/54] improved JS readability --- .../slider/examples/js/slider-rating.js | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index 7c4612907..dd4220265 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -30,7 +30,7 @@ class RatingSlider { domNode.querySelectorAll('g.rating text.label') ); - [this.infoTargetRects, this.railWidth] = this.calcRatingRects(); + [this.targetInfo, this.railWidth] = this.calcRatingRects(); this.infoDefaultFocusRect = this.calcDefaultFocusRect(); this.valueMin = this.getValueMin(); @@ -184,7 +184,7 @@ class RatingSlider { this.setLabelPosition(labelNode, left, rectWidth); - const infoTarget = { + const targetInfo = { x: left, y: RAIL_TOP, width: rectWidth, @@ -192,7 +192,7 @@ class RatingSlider { rx: 0, }; - infoRatingRects[i] = infoTarget; + infoRatingRects[i] = targetInfo; targetNode.parentNode.classList.remove('current'); @@ -223,41 +223,41 @@ class RatingSlider { resetRects() { for (let i = 0; i < this.targetRects.length; i += 1) { const targetNode = this.targetRects[i]; - const infoTarget = this.infoTargetRects[i]; + const targetInfo = this.targetInfo[i]; const labelNode = this.labelTexts[i]; - targetNode.setAttribute('x', infoTarget.x); - targetNode.setAttribute('y', infoTarget.y); - targetNode.setAttribute('width', infoTarget.width); - targetNode.setAttribute('height', infoTarget.height); + targetNode.setAttribute('x', targetInfo.x); + targetNode.setAttribute('y', targetInfo.y); + targetNode.setAttribute('width', targetInfo.width); + targetNode.setAttribute('height', targetInfo.height); targetNode.removeAttribute('rx'); - this.setLabelPosition(labelNode, infoTarget.x, infoTarget.width); + this.setLabelPosition(labelNode, targetInfo.x, targetInfo.width); targetNode.parentNode.classList.remove('current'); } } setSelectedRatingRect(value) { - let labelNode, targetNode, infoTarget; + let labelNode, targetNode, targetInfo; const leftValue = value - 1; const rightValue = value + 1; if (value > 0) { targetNode = this.targetRects[value - 1]; - infoTarget = this.infoTargetRects[value - 1]; + targetInfo = this.targetInfo[value - 1]; labelNode = this.labelTexts[value - 1]; targetNode.parentNode.classList.add('current'); - const rectWidth = infoTarget.width + 2 * SELECTED_SIZE; - const x = infoTarget.x - SELECTED_SIZE; + const rectWidth = targetInfo.width + 2 * SELECTED_SIZE; + const x = targetInfo.x - SELECTED_SIZE; targetNode.setAttribute('x', x); - targetNode.setAttribute('y', infoTarget.y - SELECTED_SIZE); + targetNode.setAttribute('y', targetInfo.y - SELECTED_SIZE); targetNode.setAttribute('width', rectWidth); - targetNode.setAttribute('height', infoTarget.height + 2 * SELECTED_SIZE); + targetNode.setAttribute('height', targetInfo.height + 2 * SELECTED_SIZE); targetNode.setAttribute('rx', SELECTED_SIZE); this.setLabelPosition(labelNode, x, rectWidth, '120%'); @@ -265,17 +265,17 @@ class RatingSlider { if (leftValue > 0) { targetNode = this.targetRects[leftValue - 1]; - infoTarget = this.infoTargetRects[leftValue - 1]; + targetInfo = this.targetInfo[leftValue - 1]; - targetNode.setAttribute('width', infoTarget.width - SELECTED_SIZE); + targetNode.setAttribute('width', targetInfo.width - SELECTED_SIZE); } if (rightValue <= this.valueMax && value > 0) { targetNode = this.targetRects[rightValue - 1]; - infoTarget = this.infoTargetRects[rightValue - 1]; + targetInfo = this.targetInfo[rightValue - 1]; - targetNode.setAttribute('x', infoTarget.x + SELECTED_SIZE); - targetNode.setAttribute('width', infoTarget.width - SELECTED_SIZE); + targetNode.setAttribute('x', targetInfo.x + SELECTED_SIZE); + targetNode.setAttribute('width', targetInfo.width - SELECTED_SIZE); } } @@ -302,12 +302,12 @@ class RatingSlider { const size = 2 * SELECTED_SIZE; if (value > 0 && value <= this.valueMax) { - const infoTarget = this.infoTargetRects[value - 1]; + const targetInfo = this.targetInfo[value - 1]; - this.focusRect.setAttribute('x', infoTarget.x - size); - this.focusRect.setAttribute('y', infoTarget.y - size); - this.focusRect.setAttribute('width', infoTarget.width + 2 * size); - this.focusRect.setAttribute('height', infoTarget.height + 2 * size); + this.focusRect.setAttribute('x', targetInfo.x - size); + this.focusRect.setAttribute('y', targetInfo.y - size); + this.focusRect.setAttribute('width', targetInfo.width + 2 * size); + this.focusRect.setAttribute('height', targetInfo.height + 2 * size); this.focusRect.setAttribute('rx', size); } else { // Set ring around entire control @@ -421,7 +421,7 @@ class RatingSlider { } onResize() { - [this.infoTargetRects, this.railWidth] = this.calcRatingRects(); + [this.targetInfo, this.railWidth] = this.calcRatingRects(); this.infoDefaultFocusRect = this.calcDefaultFocusRect(); this.setSelectedRatingRect(this.getValue()); this.setFocusRing(this.getValue()); From 3d642b231b5ae6de7eee810588da7525e48eeb0f Mon Sep 17 00:00:00 2001 From: "Andrea N. Cardona" Date: Tue, 5 Dec 2023 12:31:16 -0700 Subject: [PATCH 41/54] Update content/patterns/slider/examples/slider-rating.html --- content/patterns/slider/examples/slider-rating.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index 90fd4a79e..dfff9418d 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -131,7 +131,7 @@

      Accessibility Features

    • To highlight the interactive nature of the satisfaction rating, a focus ring appears around the group of rating options when the slider has focus and no rating value has been selected.
    • To ensure the borders of the rating values and focus ring have sufficient contrast with the background when high contrast settings invert colors, the color of the borders are synchronized with the color of the text content using a CSS media query selector (e.g. @media (forced-colors: active)) . - For example, the color of the rating value borders is set to match link foreground color of high contrast mode text by specifying the CSS canvas and linkText values for the stroke and fill properties of each inline SVG rect and text elements. + For example, the color of the rating value borders is set to match the link foreground color of high contrast mode text by specifying the CSS canvas and linkText values for the stroke and fill properties of each inline SVG rect and text elements. If specific colors were used to specify the stroke and fill properties, the color of these elements would remain the same in high contrast mode, which could lead to insufficient contrast between them and their background or even make them invisible if their color were to match the high contrast mode background.
      Note: The SVG element needs to have the CSS forced-color-adjust property set to the value auto for the currentcolor value to be updated in high contrast modes. Some browsers do not use auto for the default value.
    • From e2afde9a84b21b40bcbb716ed81c8ae702e6a341 Mon Sep 17 00:00:00 2001 From: "Andrea N. Cardona" Date: Tue, 5 Dec 2023 12:31:23 -0700 Subject: [PATCH 42/54] Update content/patterns/slider/examples/slider-rating.html --- content/patterns/slider/examples/slider-rating.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index dfff9418d..88b102c92 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -58,7 +58,7 @@

      Example

      -
      Rate your satisfaction with the service you received?
      +
      Rate your satisfaction with the service you received
      Date: Sun, 10 Dec 2023 20:18:43 -0800 Subject: [PATCH 43/54] Correct link text for rating radio example --- content/patterns/slider/examples/slider-rating.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index 88b102c92..e0548cb34 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -44,7 +44,7 @@

      Warning!

      Similar examples include:

        -
      • Rating Radio Group Example: Radio group that provides input for a ten point satisfaction rating scale.
      • +
      • Rating Radio Group Example: Radio group that provides input for a five star rating scale.
      • Color Viewer Slider Example: Basic horizontal sliders that illustrate setting numeric values for a color picker.
      • Vertical Temperature Slider Example: Demonstrates using aria-orientation to specify vertical orientation and aria-valuetext to communicate unit of measure for a temperature input.
      • Media Seek Slider Example: Horizontal slider that demonstrates using aria-valuetext to communicate current and maximum values of time in media to make the values easy to understand for assistive technology users by converting the total number of seconds to minutes and seconds.
      • From 7bf1bd5b5e2911d5bbda5fd33dcea9bba6b7f5f2 Mon Sep 17 00:00:00 2001 From: Matt King Date: Sun, 10 Dec 2023 20:51:46 -0800 Subject: [PATCH 44/54] Revise 'about this example' section to explain use of slider compared to radio and other patterns. --- content/patterns/slider/examples/slider-rating.html | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index e0548cb34..193422e93 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -40,7 +40,14 @@

        Warning!

      Following is an example of a rating input that demonstrates the Slider Pattern. - This rating widget employs a slider because number of rating values, in general when there are more than seven choices consider using the slider pattern. + This rating widget employs a slider because of the relatively large number of values on its scale; it provides a ten-point scale. + For inputs with seven or fewer choices,another pattern that could be used is radio group as demonstrated by the + Rating Radio Group Example. + However, when there are more than seven choices, the radio group pattern is less friendly to keyboard and assistive technology users because it does not provide as many ways of easily navigating through choices as other input patterns, such as + slider, + spin button, + combobox, + and listbox.

      Similar examples include:

        From 74079af3bf7065a0f6a59b032ed9f175906682c0 Mon Sep 17 00:00:00 2001 From: Matt King Date: Sun, 10 Dec 2023 21:36:22 -0800 Subject: [PATCH 45/54] Editorial clarification of accessibility features --- content/patterns/slider/examples/slider-rating.html | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index 193422e93..d63ff898c 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -132,16 +132,19 @@

        Example

        Accessibility Features

        • - To ensure assistive technology users correctly perceive the maximum slider value, this example uses the aria-valuetext property to communicate both the current and maximum values. + To ensure assistive technology users correctly understand the meaning of the current value, this example uses the + aria-valuetext + property to communicate the current value, maximum value, and the meaning of the maximum value (Extremely Satisfied). However, since repeating the maximum value every time the slider value changes is potentially distracting, the maximum value is included in aria-valuetext only when the slider is initialized and when the thumb loses keyboard focus.
        • -
        • To highlight the interactive nature of the satisfaction rating, a focus ring appears around the group of rating options when the slider has focus and no rating value has been selected.
        • +
        • To highlight the interactive nature of the satisfaction rating, a focus ring appears around the group of rating options when the slider has focus and a rating value has not yet been set.
        • - To ensure the borders of the rating values and focus ring have sufficient contrast with the background when high contrast settings invert colors, the color of the borders are synchronized with the color of the text content using a CSS media query selector (e.g. @media (forced-colors: active)) . - For example, the color of the rating value borders is set to match the link foreground color of high contrast mode text by specifying the CSS canvas and linkText values for the stroke and fill properties of each inline SVG rect and text elements. + To ensure the borders of the rating values and focus ring have sufficient contrast with the background when high contrast settings invert colors, the color of the borders is synchronized with the color of the text content using a CSS media query selector (e.g. @media (forced-colors: active)) . + For example, the color of the rating value borders is set to match the link foreground color of high contrast mode text by specifying the CSS canvas and linkText values for the stroke and fill properties of each inline SVG rect and text element. If specific colors were used to specify the stroke and fill properties, the color of these elements would remain the same in high contrast mode, which could lead to insufficient contrast between them and their background or even make them invisible if their color were to match the high contrast mode background.
          Note: The SVG element needs to have the CSS forced-color-adjust property set to the value auto for the currentcolor value to be updated in high contrast modes. - Some browsers do not use auto for the default value.
        • + Some browsers do not use auto for the default value. +
        From 234c5725cd038323f9e406a44d87548fcbfd77c0 Mon Sep 17 00:00:00 2001 From: Matt King Date: Sun, 10 Dec 2023 21:39:30 -0800 Subject: [PATCH 46/54] Keyboard documenation: correct home and end descriptions --- content/patterns/slider/examples/slider-rating.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index d63ff898c..1e88ddd2a 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -190,11 +190,11 @@

        Keyboard Support

        Home - Sets slider to its minimum value, unacceptable. + Sets slider to its minimum value, extremely disatisfied. End - Sets slider to its maximum value, completely satisfied. + Sets slider to its maximum value, extremely satisfied. From ef3a76386d75f0e13b6e847b5300c86d86e87868 Mon Sep 17 00:00:00 2001 From: Matt King Date: Sun, 10 Dec 2023 21:58:21 -0800 Subject: [PATCH 47/54] Editorial revisions to states and properties documentation --- content/patterns/slider/examples/slider-rating.html | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index 1e88ddd2a..08f2a0d7f 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -74,7 +74,7 @@

        Example

        aria-valuemin="0" aria-valuenow="0" aria-valuemax="10" - aria-valuetext="no rating on the 10 point satisfaction scale selected" + aria-valuetext="Choose a rating from 1 to 10 where 10 is extremely satisfied" aria-labelledby="id-rating-label"> @@ -255,7 +255,7 @@

        Role, Property, State, and Tabindex Attributes

        div - Specifies the minimum value of the slider.
        NOTE: 0 identifies the slider as having no rating value selected. + Specifies the minimum value of the slider.
        NOTE: 0 indicates a rating value has not yet been set. @@ -277,15 +277,16 @@

        Role, Property, State, and Tabindex Attributes

          -
        • A string value that provides a user-friendly name for the current value of the slider -- the level of satisfaction.
        • -
        • When initialized, and when the slider loses focus, the string also includes the number of rating values e.g., seven, seventh value on ten point satisfaction scale.
        • +
        • A string that provides a user-friendly name for the current value.
        • +
        • When the value is 0, 1, or 10, provides the name of the value.
        • +
        • When initialized and when the slider loses focus, the string also includes the number of rating values and the meaning of the maximum value, e.g., seven out of 10 where 10 is extremely satisfied.
        - aria-labelledby="IDREF" + aria-labelledby="ID_REFERENCE" div From 620cbad4ad67b7a762d3c760e12026fcc1706a9b Mon Sep 17 00:00:00 2001 From: Matt King Date: Sun, 10 Dec 2023 21:59:26 -0800 Subject: [PATCH 48/54] correct spelling --- content/patterns/slider/examples/slider-rating.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index 08f2a0d7f..1afd426fd 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -190,7 +190,7 @@

        Keyboard Support

        Home - Sets slider to its minimum value, extremely disatisfied. + Sets slider to its minimum value, extremely dissatisfied. End From 83fd3e09a8a044d22c6ffd6941c36fd669e0a180 Mon Sep 17 00:00:00 2001 From: Matt King Date: Sun, 10 Dec 2023 22:12:36 -0800 Subject: [PATCH 49/54] Revise valuetext strings to be more understandable for screen reader users --- .../slider/examples/js/slider-rating.js | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index dd4220265..e27af4393 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -122,37 +122,37 @@ class RatingSlider { getValueTextWithMax(value) { switch (value) { case 0: - return 'no rating on the 10 point satisfaction scale selected'; + return 'Choose a rating from one to ten where 10 is extremely satisfied'; case 1: - return 'one, extremely unsatisfied, first value on ten point satisfaction scale'; + return 'one out of 10, extremely dissatisfied'; case 2: - return 'two, second value on ten point satisfaction scale'; + return 'two out of ten where ten is extremely satisfied'; case 3: - return 'three, third value on ten point satisfaction scale'; + return 'three out of ten where ten is extremely satisfied'; case 4: - return 'four, fourth value on ten point satisfaction scale'; + return 'four out of ten where ten is extremely satisfied'; case 5: - return 'five, fifth value on ten point satisfaction scale'; + return 'five out of ten where ten is extremely satisfied'; case 6: - return 'six, sixth value on ten point satisfaction scale'; + return 'six out of ten where ten is extremely satisfied'; case 7: - return 'seven, seventh value on ten point satisfaction scale'; + return 'seven out of ten where ten is extremely satisfied'; case 8: - return 'eight, eighth value on ten point satisfaction scale'; + return 'eight out of ten where ten is extremely satisfied'; case 9: - return 'nine, ninth value on ten point satisfaction scale'; + return 'nine out of ten where ten is extremely satisfied'; case 10: - return 'ten, extremely satisfied, tenth value on ten point satisfaction scale'; + return 'ten out of ten, extremely satisfied'; default: break; From 8553fb630aaadb51d68d25e569ec210a6fd833e2 Mon Sep 17 00:00:00 2001 From: Matt King Date: Sun, 10 Dec 2023 22:21:48 -0800 Subject: [PATCH 50/54] Correct link text for rating slider in slider pattern --- content/patterns/slider/slider-pattern.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/patterns/slider/slider-pattern.html b/content/patterns/slider/slider-pattern.html index 6045f7b5a..1c8035cb4 100644 --- a/content/patterns/slider/slider-pattern.html +++ b/content/patterns/slider/slider-pattern.html @@ -38,7 +38,7 @@

        Examples

        • Color Viewer Slider Example: Basic horizontal sliders that illustrate setting numeric values for a color picker.
        • Vertical Temperature Slider Example: Demonstrates using aria-orientation to specify vertical orientation and aria-valuetext to communicate unit of measure for a temperature input.
        • -
        • Rating Slider Example: Horizontal slider that demonstrates using aria-valuetext to communicate current and maximum value of a rating input for a five star rating scale.
        • +
        • Rating Slider Example: Horizontal slider that demonstrates using aria-valuetext to make it easy for assistive technology users to understand the meaning of the current value chosen on a ten-point satisfaction scale.
        • Media Seek Slider Example: Horizontal slider that demonstrates using aria-valuetext to communicate current and maximum values of time in media to make the values easy to understand for assistive technology users by converting the total number of seconds to minutes and seconds.
        From 38aff3581445402bc70d285c76b6dcb89a680368 Mon Sep 17 00:00:00 2001 From: Matt King Date: Sun, 10 Dec 2023 22:24:43 -0800 Subject: [PATCH 51/54] Correct link text for rating slider on rating radio example page --- content/patterns/radio/examples/radio-rating.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/patterns/radio/examples/radio-rating.html b/content/patterns/radio/examples/radio-rating.html index 8e4782107..582372b95 100644 --- a/content/patterns/radio/examples/radio-rating.html +++ b/content/patterns/radio/examples/radio-rating.html @@ -35,7 +35,7 @@

        About This Example

        Similar examples include:

        From 7425522607facbf79a3a2d5e04cbee0174faf343 Mon Sep 17 00:00:00 2001 From: Matt King Date: Sun, 10 Dec 2023 22:35:54 -0800 Subject: [PATCH 52/54] Correct lists of similar examples on other slider example pages --- content/patterns/slider/examples/slider-color-viewer.html | 3 +-- content/patterns/slider/examples/slider-seek.html | 3 +-- content/patterns/slider/examples/slider-temperature.html | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/content/patterns/slider/examples/slider-color-viewer.html b/content/patterns/slider/examples/slider-color-viewer.html index e2b6c4cb5..ec8b911e7 100644 --- a/content/patterns/slider/examples/slider-color-viewer.html +++ b/content/patterns/slider/examples/slider-color-viewer.html @@ -45,9 +45,8 @@

        Warning!

        Similar examples include:

          -
        • Rating Radio Group Example: Radio group that provides input for a five-star rating scale.
        • -
        • Color Viewer Slider Example: Basic horizontal sliders that illustrate setting numeric values for a color picker.
        • Vertical Temperature Slider Example: Demonstrates using aria-orientation to specify vertical orientation and aria-valuetext to communicate unit of measure for a temperature input.
        • +
        • Rating Slider Example: Horizontal slider that demonstrates using aria-valuetext to make it easy for assistive technology users to understand the meaning of the current value chosen on a ten-point satisfaction scale.
        • Media Seek Slider Example: Horizontal slider that demonstrates using aria-valuetext to communicate current and maximum values of time in media to make the values easy to understand for assistive technology users by converting the total number of seconds to minutes and seconds.
        • Horizontal Multi-Thumb Slider Example: Demonstrates using sliders with two thumbs to provide inputs for numeric ranges, such as for searching in a price range.
        diff --git a/content/patterns/slider/examples/slider-seek.html b/content/patterns/slider/examples/slider-seek.html index bb565b655..667e2922d 100644 --- a/content/patterns/slider/examples/slider-seek.html +++ b/content/patterns/slider/examples/slider-seek.html @@ -48,10 +48,9 @@

        Warning!

        Similar examples include:

          -
        • Rating Radio Group Example: Radio group that provides input for a five-star rating scale.
        • Color Viewer Slider Example: Basic horizontal sliders that illustrate setting numeric values for a color picker.
        • Vertical Temperature Slider Example: Demonstrates using aria-orientation to specify vertical orientation and aria-valuetext to communicate unit of measure for a temperature input.
        • -
        • Media Seek Slider Example: Horizontal slider that demonstrates using aria-valuetext to communicate current and maximum values of time in media to make the values easy to understand for assistive technology users by converting the total number of seconds to minutes and seconds.
        • +
        • Rating Slider Example: Horizontal slider that demonstrates using aria-valuetext to make it easy for assistive technology users to understand the meaning of the current value chosen on a ten-point satisfaction scale.
        • Horizontal Multi-Thumb Slider Example: Demonstrates using sliders with two thumbs to provide inputs for numeric ranges, such as for searching in a price range.
        diff --git a/content/patterns/slider/examples/slider-temperature.html b/content/patterns/slider/examples/slider-temperature.html index 48df5f802..b882b0e6b 100644 --- a/content/patterns/slider/examples/slider-temperature.html +++ b/content/patterns/slider/examples/slider-temperature.html @@ -44,9 +44,8 @@

        Warning!

        Similar examples include:

          -
        • Rating Radio Group Example: Radio group that provides input for a five-star rating scale.
        • Color Viewer Slider Example: Basic horizontal sliders that illustrate setting numeric values for a color picker.
        • -
        • Vertical Temperature Slider Example: Demonstrates using aria-orientation to specify vertical orientation and aria-valuetext to communicate unit of measure for a temperature input.
        • +
        • Rating Slider Example: Horizontal slider that demonstrates using aria-valuetext to make it easy for assistive technology users to understand the meaning of the current value chosen on a ten-point satisfaction scale.
        • Media Seek Slider Example: Horizontal slider that demonstrates using aria-valuetext to communicate current and maximum values of time in media to make the values easy to understand for assistive technology users by converting the total number of seconds to minutes and seconds.
        • Horizontal Multi-Thumb Slider Example: Demonstrates using sliders with two thumbs to provide inputs for numeric ranges, such as for searching in a price range.
        From 140510565f2485c55493ef34ad86efc42ca68c0e Mon Sep 17 00:00:00 2001 From: Matt King Date: Sun, 17 Dec 2023 13:56:26 -0800 Subject: [PATCH 53/54] Editorial revision to 'About this example' based on discussion in Dec 12 meeting --- content/patterns/slider/examples/slider-rating.html | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/content/patterns/slider/examples/slider-rating.html b/content/patterns/slider/examples/slider-rating.html index 1afd426fd..a775b361b 100644 --- a/content/patterns/slider/examples/slider-rating.html +++ b/content/patterns/slider/examples/slider-rating.html @@ -40,10 +40,11 @@

        Warning!

      Following is an example of a rating input that demonstrates the Slider Pattern. - This rating widget employs a slider because of the relatively large number of values on its scale; it provides a ten-point scale. - For inputs with seven or fewer choices,another pattern that could be used is radio group as demonstrated by the + This rating widget employs a slider because it enables users to choose from ten rating values, which is a relatively large number of choices for users to navigate. + For inputs with seven or fewer choices, another pattern that could be used is radio group as demonstrated by the Rating Radio Group Example. - However, when there are more than seven choices, the radio group pattern is less friendly to keyboard and assistive technology users because it does not provide as many ways of easily navigating through choices as other input patterns, such as + However, when there are more than seven choices, other patterns provide additional keyboard commands that significantly increase efficiency for users who rely on keyboard navigation to perceive options and make a selection. + These include slider, spin button, combobox, From 71170a3465362ee2b31763016e6967bd892430b8 Mon Sep 17 00:00:00 2001 From: Matt King Date: Sun, 17 Dec 2023 20:14:05 -0800 Subject: [PATCH 54/54] Update regression tests to support new valutext strings --- content/patterns/slider/examples/js/slider-rating.js | 2 +- test/tests/slider_slider-rating.js | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/content/patterns/slider/examples/js/slider-rating.js b/content/patterns/slider/examples/js/slider-rating.js index e27af4393..4eea74a72 100644 --- a/content/patterns/slider/examples/js/slider-rating.js +++ b/content/patterns/slider/examples/js/slider-rating.js @@ -80,7 +80,7 @@ class RatingSlider { getValueText(value) { switch (value) { case 0: - return 'no satisfaction rating selected'; + return 'Choose a rating from one to ten where 10 is extremely satisfied'; case 1: return 'one, extremely dissatisfied'; diff --git a/test/tests/slider_slider-rating.js b/test/tests/slider_slider-rating.js index 2c0567555..c802d3af3 100644 --- a/test/tests/slider_slider-rating.js +++ b/test/tests/slider_slider-rating.js @@ -13,7 +13,8 @@ const ex = { ratingMax: '10', ratingMin: '0', ratingDefault: '0', - ratingDefaultValue: 'no rating on the 10 point satisfaction scale selected', + ratingDefaultValue: + 'Choose a rating from one to ten where 10 is extremely satisfied', ratingInc: 1, ratingPageInc: 2, }; @@ -37,7 +38,8 @@ const getRatingValueAndText = function (v, change) { switch (value) { case 0: - valuetext = 'no satisfaction rating selected'; + valuetext = + 'Choose a rating from one to ten where 10 is extremely satisfied'; break; case 1: