Skip to content

Commit

Permalink
fix(ui5-color-picker): provide meaningful labels for the inner input …
Browse files Browse the repository at this point in the history
…components (#5217)

Issue description:
The screen reader should announce meaningful messages
in relation to the inner input controls of the "ui5-color-picker".
Solution:
The "accessibleName" property is enabled for the "ui5-slider"
and "ui5-range-slider" components.
The missing label references for the "ui5-color-picker" inner input
components are added as per specification.

Related to: #5015
Related to: #5023
  • Loading branch information
unazko authored May 25, 2022
1 parent 9bd9d24 commit a7de0cd
Show file tree
Hide file tree
Showing 13 changed files with 128 additions and 10 deletions.
7 changes: 7 additions & 0 deletions packages/main/src/ColorPicker.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
min="0"
max="1530"
value="{{_hue}}"
accessible-name="{{hueSliderLabel}}"
@ui5-input="{{_handleHueInput}}"
></ui5-slider>
<ui5-slider
Expand All @@ -29,6 +30,7 @@
max="1"
step="0.01"
value="{{_alpha}}"
accessible-name="{{alphaSliderLabel}}"
@ui5-input="{{_handleAlphaInput}}"
></ui5-slider>
</div>
Expand All @@ -47,6 +49,7 @@
class="ui5-color-picker-hex-input"
value="{{hex}}"
@keydown="{{_onkeydown}}"
accessible-name="{{hexInputLabel}}"
@ui5-change="{{_handleHEXChange}}"
value-state="{{hexInputErrorState}}"
></ui5-input>
Expand All @@ -62,6 +65,7 @@
id="red"
class="ui5-color-picker-rgb-input"
disabled="{{inputsDisabled}}"
accessible-name="{{redInputLabel}}"
value="{{_color.r}}"
></ui5-input>
<ui5-label>R</ui5-label>
Expand All @@ -71,6 +75,7 @@
id="green"
class="ui5-color-picker-rgb-input"
disabled="{{inputsDisabled}}"
accessible-name="{{greenInputLabel}}"
value="{{_color.g}}"
></ui5-input>
<ui5-label>G</ui5-label>
Expand All @@ -80,6 +85,7 @@
id="blue"
class="ui5-color-picker-rgb-input"
disabled="{{inputsDisabled}}"
accessible-name="{{blueInputLabel}}"
value="{{_color.b}}"
></ui5-input>
<ui5-label>B</ui5-label>
Expand All @@ -90,6 +96,7 @@
disabled="{{inputsDisabled}}"
class="ui5-color-picker-rgb-input"
value="{{_alpha}}"
accessible-name="{{alphaInputLabel}}"
@ui5-input="{{_handleAlphaInput}}"
@ui5-change="{{_handleAlphaChange}}"
></ui5-input>
Expand Down
43 changes: 43 additions & 0 deletions packages/main/src/ColorPicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { renderFinished } from "@ui5/webcomponents-base/dist/Render.js";
import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
import Integer from "@ui5/webcomponents-base/dist/types/Integer.js";
import Float from "@ui5/webcomponents-base/dist/types/Float.js";
import { getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js";
import {
getRGBColor,
HSLToRGB,
Expand All @@ -17,6 +18,16 @@ import Input from "./Input.js";
import Slider from "./Slider.js";
import Label from "./Label.js";

import {
COLORPICKER_ALPHA_SLIDER,
COLORPICKER_HUE_SLIDER,
COLORPICKER_HEX,
COLORPICKER_RED,
COLORPICKER_GREEN,
COLORPICKER_BLUE,
COLORPICKER_ALPHA,
} from "./generated/i18n/i18n-defaults.js";

// Styles
import ColorPickerCss from "./generated/themes/ColorPicker.css.js";

Expand Down Expand Up @@ -179,6 +190,10 @@ class ColorPicker extends UI5Element {
];
}

static async onDefine() {
ColorPicker.i18nBundle = await getI18nBundle("@ui5/webcomponents");
}

constructor() {
super();

Expand Down Expand Up @@ -533,6 +548,34 @@ class ColorPicker extends UI5Element {
this._setMainColor(this._hue);
}

get hueSliderLabel() {
return ColorPicker.i18nBundle.getText(COLORPICKER_HUE_SLIDER);
}

get alphaSliderLabel() {
return ColorPicker.i18nBundle.getText(COLORPICKER_ALPHA_SLIDER);
}

get hexInputLabel() {
return ColorPicker.i18nBundle.getText(COLORPICKER_HEX);
}

get redInputLabel() {
return ColorPicker.i18nBundle.getText(COLORPICKER_RED);
}

get greenInputLabel() {
return ColorPicker.i18nBundle.getText(COLORPICKER_GREEN);
}

get blueInputLabel() {
return ColorPicker.i18nBundle.getText(COLORPICKER_BLUE);
}

get alphaInputLabel() {
return ColorPicker.i18nBundle.getText(COLORPICKER_ALPHA);
}

get inputsDisabled() {
return this._wrongHEX ? true : undefined;
}
Expand Down
6 changes: 3 additions & 3 deletions packages/main/src/RangeSlider.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
aria-valuemin="{{min}}"
aria-valuemax="{{max}}"
aria-valuetext="From {{startValue}} to {{endValue}}"
aria-labelledby="{{_id}}-sliderDesc"
aria-labelledby="{{_ariaLabelledByProgressBarRefs}}"
aria-disabled="{{_ariaDisabled}}"
></div>
</div>
Expand All @@ -34,7 +34,7 @@
aria-valuemin="{{min}}"
aria-valuemax="{{max}}"
aria-valuenow="{{startValue}}"
aria-labelledby="{{_id}}-startHandleDesc"
aria-labelledby="{{_ariaLabelledByStartHandleRefs}}"
aria-disabled="{{_ariaDisabled}}"
>
<ui5-icon name="source-code" slider-icon></ui5-icon>
Expand All @@ -56,7 +56,7 @@
aria-valuemin="{{min}}"
aria-valuemax="{{max}}"
aria-valuenow="{{endValue}}"
aria-labelledby="{{_id}}-endHandleDesc"
aria-labelledby="{{_ariaLabelledByEndHandleRefs}}"
aria-disabled="{{_ariaDisabled}}"
>
<ui5-icon name="source-code" slider-icon></ui5-icon>
Expand Down
12 changes: 12 additions & 0 deletions packages/main/src/RangeSlider.js
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,18 @@ class RangeSlider extends SliderBase {
return this.shadowRoot.querySelector(".ui5-slider-progress");
}

get _ariaLabelledByStartHandleRefs() {
return [`${this._id}-accName`, `${this._id}-startHandleDesc`].join(" ").trim();
}

get _ariaLabelledByEndHandleRefs() {
return [`${this._id}-accName`, `${this._id}-endHandleDesc`].join(" ").trim();
}

get _ariaLabelledByProgressBarRefs() {
return [`${this._id}-accName`, `${this._id}-sliderDesc`].join(" ").trim();
}

get styles() {
return {
progress: {
Expand Down
2 changes: 1 addition & 1 deletion packages/main/src/Slider.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
aria-valuemin="{{min}}"
aria-valuemax="{{max}}"
aria-valuenow="{{value}}"
aria-labelledby="{{_id}}-sliderDesc"
aria-labelledby="{{_ariaLabelledByHandleRefs}}"
aria-disabled="{{_ariaDisabled}}"
data-sap-focus-ref
part="handle"
Expand Down
1 change: 1 addition & 0 deletions packages/main/src/SliderBase.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
{{> handles}}
</div>

<span id="{{_id}}-accName" class="ui5-hidden-text">{{accessibleName}}</span>
<span id="{{_id}}-sliderDesc" class="ui5-hidden-text">{{_ariaLabelledByText}}</span>
</div>

Expand Down
16 changes: 16 additions & 0 deletions packages/main/src/SliderBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,18 @@ const metadata = {
type: Boolean,
},

/**
* Defines the accessible aria name of the component.
*
* @type {string}
* @defaultvalue: ""
* @public
* @since 1.4.0
*/
accessibleName: {
type: String,
},

/**
* @private
*/
Expand Down Expand Up @@ -794,6 +806,10 @@ class SliderBase extends UI5Element {
get tabIndex() {
return this.disabled ? "-1" : "0";
}

get _ariaLabelledByHandleRefs() {
return [`${this._id}-accName`, `${this._id}-sliderDesc`].join(" ").trim();
}
}

export default SliderBase;
21 changes: 21 additions & 0 deletions packages/main/src/i18n/messagebundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,27 @@ COLOR_PALETTE_DIALOG_TITLE=Change Color
#XTIT: Color Palette dialog title of the Color Picker
COLOR_PALETTE_MORE_COLORS_TEXT=More Colors...

#XACT: Aria information for the ColorPicker Alpha slider
COLORPICKER_ALPHA_SLIDER=Alpha control

#XACT: Aria information for the ColorPicker Hue slider
COLORPICKER_HUE_SLIDER=Hue control

#XTOL: Six symbol hexadecimal group representing CSS color hex string
COLORPICKER_HEX=Hexadecimal

#XTOL: Red color for the ColorPicker control
COLORPICKER_RED=Red

#XTOL: Green color for the ColorPicker control
COLORPICKER_GREEN=Green

#XTOL: Blue color for the ColorPicker control
COLORPICKER_BLUE=Blue

#XTOL: Alpha chanel transparency value for RGBA color mode
COLORPICKER_ALPHA=Alpha

#XACT: DatePicker 'Open Picker' icon title
DATEPICKER_OPEN_ICON_TITLE=Open Picker

Expand Down
2 changes: 1 addition & 1 deletion packages/main/test/pages/RangeSlider.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<body class="rangeslider1auto">
<section class="group">
<h2>Basic Range Slider</h2>
<ui5-range-slider id="basic-range-slider" end-value="20"></ui5-range-slider>
<ui5-range-slider id="basic-range-slider" accessible-name="Basic Range Slider" end-value="20"></ui5-range-slider>

<h2>Range Slider with custom min and max properties and tooltip</h2>
<ui5-range-slider id="basic-range-slider-with-tooltip" min="50" max="200" show-tooltip></ui5-range-slider>
Expand Down
2 changes: 1 addition & 1 deletion packages/main/test/pages/Slider.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<body class="slider1auto">
<section class="group">
<h2>Basic Slider</h2>
<ui5-slider id="basic-slider" min="0" max="10"></ui5-slider>
<ui5-slider id="basic-slider" accessible-name="Basic Slider" min="0" max="10"></ui5-slider>

<h2>Basic Slider with tooltip</h2>
<ui5-slider id="basic-slider-with-tooltip" min="0" max="20" show-tooltip></ui5-slider>
Expand Down
18 changes: 18 additions & 0 deletions packages/main/test/specs/ColorPicker.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,22 @@ describe("Color Picker general interaction", () => {
assert.strictEqual(await colorPicker.getAttribute("_hue"), hueValue, "Hue value remained unchanged");
});

it("Inner input components accessibility references", async () => {
const colorPicker = await browser.$("#cp1");
const hueSlider = await colorPicker.shadow$(".ui5-color-picker-hue-slider");
const alphaSlider = await colorPicker.shadow$(".ui5-color-picker-alpha-slider");
const hexInput = await colorPicker.shadow$(".ui5-color-picker-hex-input");
const redInput = await colorPicker.shadow$("#red");
const greenInput = await colorPicker.shadow$("#green");
const blueInput = await colorPicker.shadow$("#blue");
const alphaInput = await colorPicker.shadow$("#alpha");

assert.strictEqual(await hueSlider.getAttribute("accessible-name"), "Hue control", "Hue slider accessible-name attribute properly set");
assert.strictEqual(await alphaSlider.getAttribute("accessible-name"), "Alpha control", "Alpha slider accessible-name attribute properly set");
assert.strictEqual(await hexInput.getAttribute("accessible-name"), "Hexadecimal", "Hex input accessible-name attribute properly set");
assert.strictEqual(await redInput.getAttribute("accessible-name"), "Red", "Red input accessible-name attribute properly set");
assert.strictEqual(await greenInput.getAttribute("accessible-name"), "Green", "Green input accessible-name attribute properly set");
assert.strictEqual(await blueInput.getAttribute("accessible-name"), "Blue", "Blue input accessible-name attribute properly set");
assert.strictEqual(await alphaInput.getAttribute("accessible-name"), "Alpha", "Alpha input accessible-name attribute properly set");
});
});
6 changes: 3 additions & 3 deletions packages/main/test/specs/RangeSlider.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ describe("Accessibility", async () => {
const rangeSliderId = await rangeSlider.getProperty("_id");

assert.strictEqual(await rangeSliderProgressBar.getAttribute("aria-labelledby"),
`${rangeSliderId}-sliderDesc`, "aria-labelledby is set correctly");
`${rangeSliderId}-accName ${rangeSliderId}-sliderDesc`, "aria-labelledby is set correctly");
assert.strictEqual(await rangeSliderProgressBar.getAttribute("aria-valuemin"),
`${await rangeSlider.getProperty("min")}`, "aria-valuemin is set correctly");
assert.strictEqual(await rangeSliderProgressBar.getAttribute("aria-valuemax"),
Expand All @@ -331,7 +331,7 @@ describe("Accessibility", async () => {
const rangeSliderId = await rangeSlider.getProperty("_id");

assert.strictEqual(await startHandle.getAttribute("aria-labelledby"),
`${rangeSliderId}-startHandleDesc`, "aria-labelledby is set correctly");
`${rangeSliderId}-accName ${rangeSliderId}-startHandleDesc`, "aria-labelledby is set correctly");
assert.strictEqual(await startHandle.getAttribute("aria-valuemin"),
`${await rangeSlider.getProperty("min")}`, "aria-valuemin is set correctly");
assert.strictEqual(await startHandle.getAttribute("aria-valuemax"),
Expand All @@ -346,7 +346,7 @@ describe("Accessibility", async () => {
const rangeSliderId = await rangeSlider.getProperty("_id");

assert.strictEqual(await endHandle.getAttribute("aria-labelledby"),
`${rangeSliderId}-endHandleDesc`, "aria-labelledby is set correctly");
`${rangeSliderId}-accName ${rangeSliderId}-endHandleDesc`, "aria-labelledby is set correctly");
assert.strictEqual(await endHandle.getAttribute("aria-valuemin"),
`${await rangeSlider.getProperty("min")}`, "aria-valuemin is set correctly");
assert.strictEqual(await endHandle.getAttribute("aria-valuemax"),
Expand Down
2 changes: 1 addition & 1 deletion packages/main/test/specs/Slider.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ describe("Accessibility", async () => {
const sliderId = await slider.getProperty("_id");

assert.strictEqual(await sliderHandle.getAttribute("aria-labelledby"),
`${sliderId}-sliderDesc`, "aria-labelledby is set correctly");
`${sliderId}-accName ${sliderId}-sliderDesc`, "aria-labelledby is set correctly");
assert.strictEqual(await sliderHandle.getAttribute("aria-valuemin"),
`${await slider.getProperty("min")}`, "aria-valuemin is set correctly");
assert.strictEqual(await sliderHandle.getAttribute("aria-valuemax"),
Expand Down

0 comments on commit a7de0cd

Please sign in to comment.