Skip to content

Commit

Permalink
feat(ui5-select): introduce readonly state (#7950)
Browse files Browse the repository at this point in the history
Introduces readonly state to the Select web component and align the readonly styles for all input fields to the latest specs. Changes in Select API: new property readonly; VD: respective visual styling for readonly state, dropdown icon is not displayed; InteractionDesign: dropdown remains always closed, no changes in selection allowed; a11y: new aria attribute aria-readonly true|false accordingly.

Fixes: #7727
  • Loading branch information
ilhan007 authored Dec 18, 2023
1 parent 8eeb8b3 commit 02ea9a4
Show file tree
Hide file tree
Showing 12 changed files with 137 additions and 11 deletions.
13 changes: 8 additions & 5 deletions packages/main/src/Select.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
aria-describedby="{{valueStateTextId}}"
aria-disabled="{{isDisabled}}"
aria-required="{{required}}"
aria-readonly="{{readonly}}"
aria-expanded="{{_isPickerOpen}}"
aria-roledescription="{{_ariaRoleDescription}}"
@keydown="{{_onkeydown}}"
Expand All @@ -34,11 +35,13 @@
{{/if}}
</div>

<ui5-icon
name="slim-arrow-down"
input-icon
?pressed="{{_iconPressed}}"
></ui5-icon>
{{#unless readonly}}
<ui5-icon
name="slim-arrow-down"
input-icon
?pressed="{{_iconPressed}}"
></ui5-icon>
{{/unless}}

{{#if hasValueState}}
<span id="{{_id}}-valueStateDesc" class="ui5-hidden-text">{{valueStateText}}</span>
Expand Down
39 changes: 34 additions & 5 deletions packages/main/src/Select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,21 @@ class Select extends UI5Element implements IFormElement {
@property({ type: Boolean })
required!: boolean;

/**
* Defines whether the component is read-only.
* <br><br>
* <b>Note:</b> A read-only component is not editable,
* but still provides visual feedback upon user interaction.
*
* @type {boolean}
* @name sap.ui.webc.main.Select.prototype.readonly
* @defaultvalue false
* @since 1.21.0
* @public
*/
@property({ type: Boolean })
readonly!: boolean;

/**
* Defines the accessible ARIA name of the component.
*
Expand Down Expand Up @@ -589,7 +604,7 @@ class Select extends UI5Element implements IFormElement {
}

async _toggleRespPopover() {
if (this.disabled) {
if (this.disabled || this.readonly) {
return;
}

Expand Down Expand Up @@ -739,7 +754,7 @@ class Select extends UI5Element implements IFormElement {
}

_handleKeyboardNavigation(e: KeyboardEvent) {
if (isEnter(e)) {
if (isEnter(e) || this.readonly) {
return;
}

Expand Down Expand Up @@ -790,13 +805,22 @@ class Select extends UI5Element implements IFormElement {

_handleHomeKey(e: KeyboardEvent) {
e.preventDefault();

if (this.readonly) {
return;
}

this._changeSelectedItem(this._selectedIndex, 0);
}

_handleEndKey(e: KeyboardEvent) {
const lastIndex = this.selectOptions.length - 1;

e.preventDefault();

if (this.readonly) {
return;
}

const lastIndex = this.selectOptions.length - 1;
this._changeSelectedItem(this._selectedIndex, lastIndex);
}

Expand Down Expand Up @@ -870,11 +894,16 @@ class Select extends UI5Element implements IFormElement {
}

_handleArrowNavigation(e: KeyboardEvent) {
e.preventDefault();

if (this.readonly) {
return;
}

let nextIndex = -1;
const currentIndex = this._selectedIndex;
const isDownKey = isDown(e);

e.preventDefault();
if (isDownKey) {
nextIndex = this._getNextOptionIndex();
} else {
Expand Down
8 changes: 8 additions & 0 deletions packages/main/src/themes/Input.css
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@
right: var(--_ui5_input_focus_offset);
}

:host([focused][readonly]:not([opened])) .ui5-input-focusable-element::after {
top: var(--_ui5_input_readonly_focus_offset);
bottom: var(--_ui5_input_readonly_focus_offset);
left: var(--_ui5_input_readonly_focus_offset);
right: var(--_ui5_input_readonly_focus_offset);
border-radius: var(--_ui5_input_readonly_focus_border_radius);
}

.ui5-input-root::before {
content: "";
position: absolute;
Expand Down
2 changes: 2 additions & 0 deletions packages/main/src/themes/base/Input-parameters.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
--_ui5_input_background_color: var(--sapField_Background);
--_ui5_input_border_radius: var(--sapField_BorderCornerRadius);
--_ui5_input_focus_border_radius: 0;
--_ui5_input_readonly_focus_border_radius: 0;
--_ui5-input-border: 2px solid transparent; /* The value of this variable defaults to sap_horizon theme, because if it defaults to fiori, then a flickering of the border is present*/
--_ui5_input_placeholder_style: italic;
--_ui5_input_placeholder_color: var(--sapField_PlaceholderTextColor);
Expand Down Expand Up @@ -62,6 +63,7 @@
--_ui5-input-value-state-information-border-width: 1px;
--_ui5-input-background-image: none;
--_ui5_input_focus_offset: 1px;
--_ui5_input_readonly_focus_offset: 1px;
--ui5_input_focus_pseudo_element_content: '';
--_ui5_input_value_state_error_warning_placeholder_font_weight: normal;
--_ui5_input_focus_outline_color: var(--sapContent_FocusColor);
Expand Down
2 changes: 2 additions & 0 deletions packages/main/src/themes/sap_horizon/Input-parameters.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
--_ui5-input-border: none;
--_ui5_input_hover_border: none;
--_ui5_input_focus_border_radius: 0.25rem;
--_ui5_input_readonly_focus_border_radius: 0.125rem;
--_ui5_input_error_warning_border_style: none;
--_ui5_input_focused_value_state_error_background: var(--sapField_Hover_Background);
--_ui5_input_focused_value_state_warning_background: var(--sapField_Hover_Background);
Expand All @@ -13,6 +14,7 @@
--_ui5_input_focused_value_state_warning_focus_outline_color: var(--sapField_WarningColor);
--_ui5_input_focused_value_state_success_focus_outline_color: var(--sapField_SuccessColor);
--_ui5_input_focus_offset: 0;
--_ui5_input_readonly_focus_offset: 0.125rem;
--_ui5_input_information_icon_padding: .625rem .625rem .5rem .625rem;
--_ui5_input_information_focused_icon_padding: .625rem .625rem .5625rem .625rem;
--_ui5_input_error_warning_icon_padding: .625rem .625rem .5rem .625rem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
--_ui5-input-border: none;
--_ui5_input_hover_border: none;
--_ui5_input_focus_border_radius: 0.25rem;
--_ui5_input_readonly_focus_border_radius: 0.125rem;
--_ui5_input_error_warning_border_style: none;
--_ui5_input_focused_value_state_error_background: var(--sapField_Hover_Background);
--_ui5_input_focused_value_state_warning_background: var(--sapField_Hover_Background);
Expand All @@ -13,6 +14,7 @@
--_ui5_input_focused_value_state_warning_focus_outline_color: var(--sapField_WarningColor);
--_ui5_input_focused_value_state_success_focus_outline_color: var(--sapField_SuccessColor);
--_ui5_input_focus_offset: 0;
--_ui5_input_readonly_focus_offset: 0.125rem;
--_ui5_input_information_icon_padding: .625rem .625rem .5rem .625rem;
--_ui5_input_information_focused_icon_padding: .625rem .625rem .5625rem .625rem;
--_ui5_input_error_warning_icon_padding: .625rem .625rem .5rem .625rem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
--_ui5-input-border: none;
--_ui5_input_hover_border: none;
--_ui5_input_focus_border_radius: 0.25rem;
--_ui5_input_readonly_focus_border_radius: 0.125rem;
--_ui5_input_error_warning_border_style: none;
--_ui5_input_focused_value_state_error_background: var(--sapField_Hover_Background);
--_ui5_input_focused_value_state_warning_background: var(--sapField_Hover_Background);
Expand All @@ -14,6 +15,7 @@
--_ui5_input_focused_value_state_success_focus_outline_color: var(--sapField_SuccessColor);
--_ui5_input_icon_min_width: 2.125rem;
--_ui5_input_focus_offset: 0;
--_ui5_input_readonly_focus_offset: 0.125rem;
--_ui5_input_information_icon_padding: .625rem .625rem .5rem .625rem;
--_ui5_input_error_warning_icon_padding: .625rem .625rem .5rem .625rem;
--_ui5_input_custom_icon_padding: .625rem .625rem .5625rem .625rem;
Expand Down
2 changes: 2 additions & 0 deletions packages/main/src/themes/sap_horizon_exp/Input-parameters.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
--_ui5-input-border: none;
--_ui5_input_hover_border: none;
--_ui5_input_focus_border_radius: 0.25rem;
--_ui5_input_readonly_focus_border_radius: 0.125rem;
--_ui5_input_error_warning_border_style: none;
--_ui5_input_focused_value_state_error_background: var(--sapField_Hover_Background);
--_ui5_input_focused_value_state_warning_background: var(--sapField_Hover_Background);
Expand All @@ -13,6 +14,7 @@
--_ui5_input_focused_value_state_warning_focus_outline_color: var(--sapField_WarningColor);
--_ui5_input_focused_value_state_success_focus_outline_color: var(--sapField_SuccessColor);
--_ui5_input_focus_offset: 0;
--_ui5_input_readonly_focus_offset: 0.125rem;
--_ui5_input_information_icon_padding: .625rem .625rem .5rem .625rem;
--_ui5_input_error_warning_icon_padding: .625rem .625rem .5rem .625rem;
--_ui5_input_custom_icon_padding: .625rem .625rem .5625rem .625rem;
Expand Down
9 changes: 8 additions & 1 deletion packages/main/test/pages/Select.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
<ui5-button id="restore-items-btn">Restore Items</ui5-button>
<ui5-button id="myBtn2">click</ui5-button>


<h2>Content size</h2>
<ui5-label id="lblResult"></ui5-label>
<ui5-select id="mySelect">
Expand Down Expand Up @@ -69,6 +68,14 @@ <h2>Success Select</h2>
<h2>Disabled Select</h2>
<ui5-select id="mySelect4" disabled value-state="Success"></ui5-select>

<h2>Readonly Select</h2>
<ui5-select id="mySelectReadOnly" readonly>
<ui5-option>Cozy</ui5-option>
<ui5-option selected>Compact</ui5-option>
<ui5-option>Condensed</ui5-option>
</ui5-select>


<h2> Input with suggestions</h2>
<ui5-input id="myInput" show-suggestions placeholder="Search for a country ..."></ui5-input>

Expand Down
36 changes: 36 additions & 0 deletions packages/main/test/pages/SelectMenu.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
<ui5-select menu="selectOptions3" value-state="Information"></ui5-select>

<ui5-select menu="selectMultipleItems" value-state="Error"></ui5-select>

<ui5-select menu="selectReadOnly" readonly></ui5-select>
</section>

<section>
Expand Down Expand Up @@ -612,6 +614,40 @@
</ui5-select-menu-option>
</ui5-select-menu>

<ui5-select-menu id="selectReadOnly">

<ui5-select-menu-option display-text="Phone">
<div class="selectMenuOption">
Phone
<div>
<ui5-icon name="phone"></ui5-icon>
<ui5-icon name="employee"></ui5-icon>
</div>
</div>
</ui5-select-menu-option>

<ui5-select-menu-option display-text="Tablet">
<div class="selectMenuOption">
Tablet
<div>
<ui5-icon name="ipad-2"></ui5-icon>
<ui5-icon name="employee"></ui5-icon>
</div>
</div>
</ui5-select-menu-option>

<ui5-select-menu-option display-text="Desktop">
<div class="selectMenuOption">
Desktop
<div>
<ui5-icon name="laptop"></ui5-icon>
<ui5-icon name="employee"></ui5-icon>
</div>
</div>
</ui5-select-menu-option>

</ui5-select-menu>

<script>
let counter = 0;
let liveCounter = 0;
Expand Down
27 changes: 27 additions & 0 deletions packages/main/test/specs/Select.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,33 @@ describe("Select general interaction", () => {
assert.strictEqual(await inputResult.getProperty("value"), "3", "Change event should have fired twice");
});

it("remains closed and unchanged when read-only", async () => {
const select = await browser.$("#mySelectReadOnly");
const EXPECTED_SELECTION_TEXT = "Compact";
const selectOptionText = await select.shadow$(".ui5-select-label-root");

// act - try to open the dropdown
await select.click();

const staticAreaItemClassName = await browser.getStaticAreaItemClassName("#mySelectReadOnly");
const popover = await browser.$(`.${staticAreaItemClassName}`).shadow$("ui5-responsive-popover");

// assert
assert.notOk(await popover.getProperty("opened"), "Select remains closed.");

// act - try to change selection when dropdown is closed
await select.keys("ArrowUp");
// assert
let selectOptionTextHtml = await selectOptionText.getHTML(false);
assert.include(selectOptionTextHtml, EXPECTED_SELECTION_TEXT, "Selected option remains " + EXPECTED_SELECTION_TEXT);

// act - try to change selection when dropdown is closed
await select.keys("ArrowDown");
// assert
selectOptionTextHtml = await selectOptionText.getHTML(false);
assert.include(selectOptionTextHtml, EXPECTED_SELECTION_TEXT, "Selected option remains" + EXPECTED_SELECTION_TEXT);
});

it("announces the selected value once Select Popover is opened", async () => {
await browser.url(`test/pages/Select.html`);

Expand Down
6 changes: 6 additions & 0 deletions packages/playground/_stories/main/Select/Select.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const Template: UI5StoryArgs<Select, StoryArgsSlots> = (args) => {
name="${ifDefined(args.name)}"
?disabled="${ifDefined(args.disabled)}"
?required="${ifDefined(args.required)}"
?readonly="${ifDefined(args.readonly)}"
value-state="${ifDefined(args.valueState)}"
value-state-message="${ifDefined(args.valueStateMessage)}"
selected-option="${ifDefined(args.selectedOption)}"
Expand Down Expand Up @@ -102,6 +103,11 @@ export const ValueStateAndValueStateMessage: StoryFn = () =>
used as an information message. Extra long text used as an information
message - 2. Extra long text used as an information message - 3.
</div>
</ui5-select>
<ui5-select class="select" readonly>
<ui5-option icon="meal" selected="">Apple</ui5-option>
<ui5-option icon="meal">Avocado</ui5-option>
<ui5-option icon="meal">Mango</ui5-option>
</ui5-select>`;

ValueStateAndValueStateMessage.storyName = "Value State";
Expand Down

0 comments on commit 02ea9a4

Please sign in to comment.