Skip to content

Commit 385bb0b

Browse files
authored
feat(ui5-combobox): implement valueStateMessage slot (#2099)
Related to: #1086
1 parent 4bcd797 commit 385bb0b

File tree

3 files changed

+169
-5
lines changed

3 files changed

+169
-5
lines changed

packages/main/src/ComboBox.js

+108-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
22
import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
33
import ValueState from "@ui5/webcomponents-base/dist/types/ValueState.js";
44
import { isPhone } from "@ui5/webcomponents-base/dist/Device.js";
5+
import Integer from "@ui5/webcomponents-base/dist/types/Integer.js";
56
import getEffectiveAriaLabelText from "@ui5/webcomponents-base/dist/util/getEffectiveAriaLabelText.js";
67
import "@ui5/webcomponents-icons/dist/icons/slim-arrow-down.js";
78
import "@ui5/webcomponents-icons/dist/icons/decline.js";
@@ -20,6 +21,7 @@ import {
2021
VALUE_STATE_SUCCESS,
2122
VALUE_STATE_ERROR,
2223
VALUE_STATE_WARNING,
24+
VALUE_STATE_INFORMATION,
2325
INPUT_SUGGESTIONS_TITLE,
2426
ICON_ACCESSIBLE_NAME,
2527
} from "./generated/i18n/i18n-defaults.js";
@@ -32,9 +34,11 @@ import ComboBoxPopoverTemplate from "./generated/templates/ComboBoxPopoverTempla
3234
import ComboBoxCss from "./generated/themes/ComboBox.css.js";
3335
import ComboBoxPopoverCss from "./generated/themes/ComboBoxPopover.css.js";
3436
import ResponsivePopoverCommonCss from "./generated/themes/ResponsivePopoverCommon.css.js";
37+
import ValueStateMessageCss from "./generated/themes/ValueStateMessage.css.js";
3538

3639
import ComboBoxItem from "./ComboBoxItem.js";
3740
import Icon from "./Icon.js";
41+
import Popover from "./Popover.js";
3842
import ResponsivePopover from "./ResponsivePopover.js";
3943
import List from "./List.js";
4044
import BusyIndicator from "./BusyIndicator.js";
@@ -218,6 +222,12 @@ const metadata = {
218222
_filteredItems: {
219223
type: Object,
220224
},
225+
226+
_listWidth: {
227+
type: Integer,
228+
defaultValue: 0,
229+
noAttribute: true,
230+
},
221231
},
222232
managedSlots: true,
223233
slots: /** @lends sap.ui.webcomponents.main.ComboBox.prototype */ {
@@ -240,6 +250,23 @@ const metadata = {
240250
type: HTMLElement,
241251
listenFor: { include: ["*"] },
242252
},
253+
254+
/**
255+
* Defines the value state message that will be displayed as pop up under the <code>ui5-combobox</code>.
256+
* <br><br>
257+
*
258+
* <b>Note:</b> If not specified, a default text (in the respective language) will be displayed.
259+
* <br>
260+
* <b>Note:</b> The <code>valueStateMessage</code> would be displayed,
261+
* when the <code>ui5-select</code> is in <code>Information</code>, <code>Warning</code> or <code>Error</code> value state.
262+
* @type {HTMLElement[]}
263+
* @since 1.0.0-rc.9
264+
* @slot
265+
* @public
266+
*/
267+
valueStateMessage: {
268+
type: HTMLElement,
269+
},
243270
},
244271
events: /** @lends sap.ui.webcomponents.main.ComboBox.prototype */ {
245272
/**
@@ -314,7 +341,7 @@ class ComboBox extends UI5Element {
314341
}
315342

316343
static get staticAreaStyles() {
317-
return [ResponsivePopoverCommonCss, ComboBoxPopoverCss];
344+
return [ResponsivePopoverCommonCss, ValueStateMessageCss, ComboBoxPopoverCss];
318345
}
319346

320347
static get template() {
@@ -379,6 +406,9 @@ class ComboBox extends UI5Element {
379406
}
380407

381408
this._itemFocused = false;
409+
410+
this.toggleValueStatePopover(this.shouldOpenValueStateMessagePopover);
411+
this.storeResponsivePopoverWidth();
382412
}
383413

384414
shouldClosePopover() {
@@ -425,6 +455,35 @@ class ComboBox extends UI5Element {
425455
}
426456
}
427457

458+
storeResponsivePopoverWidth() {
459+
if (this.open && !this._listWidth) {
460+
this._listWidth = this.responsivePopover.offsetWidth;
461+
}
462+
}
463+
464+
toggleValueStatePopover(open) {
465+
if (open) {
466+
this.openValueStatePopover();
467+
} else {
468+
this.closeValueStatePopover();
469+
}
470+
}
471+
472+
async openValueStatePopover() {
473+
this.popover = await this._getPopover();
474+
this.popover && this.popover.openBy(this);
475+
}
476+
477+
async closeValueStatePopover() {
478+
this.popover = await this._getPopover();
479+
this.popover && this.popover.close();
480+
}
481+
482+
async _getPopover() {
483+
const staticAreaItem = await this.getStaticAreaItemDomRef();
484+
return staticAreaItem.querySelector(".ui5-valuestatemessage-popover");
485+
}
486+
428487
_resetFilter() {
429488
this._filteredItems = this._filterItems("");
430489
this._selectMatchingItem();
@@ -627,10 +686,18 @@ class ComboBox extends UI5Element {
627686
return this.valueState !== ValueState.None;
628687
}
629688

689+
get hasValueStateText() {
690+
return this.hasValueState && this.valueState !== ValueState.Success;
691+
}
692+
630693
get valueStateText() {
631694
return this.valueStateTextMappings[this.valueState];
632695
}
633696

697+
get valueStateMessageText() {
698+
return this.getSlottedNodes("valueStateMessage").map(el => el.cloneNode(true));
699+
}
700+
634701
get valueStateTextId() {
635702
return this.hasValueState ? `${this._id}-valueStateDesc` : undefined;
636703
}
@@ -640,13 +707,27 @@ class ComboBox extends UI5Element {
640707
"Success": this.i18nBundle.getText(VALUE_STATE_SUCCESS),
641708
"Error": this.i18nBundle.getText(VALUE_STATE_ERROR),
642709
"Warning": this.i18nBundle.getText(VALUE_STATE_WARNING),
710+
"Information": this.i18nBundle.getText(VALUE_STATE_INFORMATION),
643711
};
644712
}
645713

714+
get shouldOpenValueStateMessagePopover() {
715+
return this.focused && this.hasValueStateText && !this._iconPressed
716+
&& !this.open && !this._isPhone;
717+
}
718+
719+
get shouldDisplayDefaultValueStateMessage() {
720+
return !this.valueStateMessage.length && this.hasValueStateText;
721+
}
722+
646723
get open() {
647724
return this.responsivePopover ? this.responsivePopover.opened : false;
648725
}
649726

727+
get _isPhone() {
728+
return isPhone();
729+
}
730+
650731
get itemTabIndex() {
651732
return undefined;
652733
}
@@ -655,10 +736,36 @@ class ComboBox extends UI5Element {
655736
return getEffectiveAriaLabelText(this);
656737
}
657738

739+
get styles() {
740+
return {
741+
popoverHeader: {
742+
"width": `${this.offsetWidth}px`,
743+
},
744+
suggestionPopoverHeader: {
745+
"display": this._listWidth === 0 ? "none" : "inline-block",
746+
"width": `${this._listWidth}px`,
747+
"padding": "0.5625rem 1rem",
748+
},
749+
};
750+
}
751+
752+
get classes() {
753+
return {
754+
popoverValueState: {
755+
"ui5-valuestatemessage-root": true,
756+
"ui5-valuestatemessage--success": this.valueState === ValueState.Success,
757+
"ui5-valuestatemessage--error": this.valueState === ValueState.Error,
758+
"ui5-valuestatemessage--warning": this.valueState === ValueState.Warning,
759+
"ui5-valuestatemessage--information": this.valueState === ValueState.Information,
760+
},
761+
};
762+
}
763+
658764
static async onDefine() {
659765
await Promise.all([
660766
ComboBoxItem.define(),
661767
Icon.define(),
768+
Popover.define(),
662769
ResponsivePopover.define(),
663770
List.define(),
664771
BusyIndicator.define(),

packages/main/src/ComboBoxPopover.hbs

+42-2
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@
2525
>
2626
</ui5-button>
2727
</div>
28+
2829
<div class="row">
2930
<div
30-
slot="header"
3131
class="input-root-phone"
3232
value-state="{{valueState}}"
3333
>
@@ -44,8 +44,22 @@
4444
/>
4545
</div>
4646
</div>
47+
48+
{{#if hasValueStateText}}
49+
<div class="row {{classes.popoverValueState}}">
50+
{{> valueStateMessage}}
51+
</div>
52+
{{/if}}
4753
</div>
4854

55+
{{#unless _isPhone}}
56+
{{#if hasValueStateText}}
57+
<div class="ui5-responsive-popover-header {{classes.popoverValueState}}" style="{{styles.suggestionPopoverHeader}}">
58+
{{> valueStateMessage}}
59+
</div>
60+
{{/if}}
61+
{{/unless}}
62+
4963
<ui5-list
5064
separators="None"
5165
@ui5-item-click={{_selectItem}}
@@ -72,4 +86,30 @@
7286
@click="{{_closeRespPopover}}"
7387
>OK</ui5-button>
7488
</div>
75-
</ui5-responsive-popover>
89+
</ui5-responsive-popover>
90+
91+
{{#if shouldOpenValueStateMessagePopover}}
92+
<ui5-popover
93+
skip-registry-update
94+
_disable-initial-focus
95+
prevent-focus-restore
96+
no-padding
97+
no-arrow
98+
class="ui5-valuestatemessage-popover"
99+
placement-type="Bottom"
100+
>
101+
<div slot="header" class="{{classes.popoverValueState}}" style="{{styles.popoverHeader}}">
102+
{{> valueStateMessage}}
103+
</div>
104+
</ui5-popover>
105+
{{/if}}
106+
107+
{{#*inline "valueStateMessage"}}
108+
{{#if shouldDisplayDefaultValueStateMessage}}
109+
{{valueStateText}}
110+
{{else}}
111+
{{#each valueStateMessageText}}
112+
{{this}}
113+
{{/each}}
114+
{{/if}}
115+
{{/inline}}

packages/main/test/pages/ComboBox.html

+19-2
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,25 @@
7373
<ui5-combobox id="" style="width: 360px;" placeholder="Hello World"></ui5-combobox>
7474
<ui5-combobox id="" style="width: 360px;" readonly value="readonly"></ui5-combobox>
7575
<ui5-combobox id="" style="width: 360px;" required value="required"></ui5-combobox>
76-
<ui5-combobox id="" style="width: 360px;" value-state="Error"></ui5-combobox>
77-
<ui5-combobox id="" style="width: 360px;" value-state="Warning"></ui5-combobox>
76+
<ui5-combobox id="" style="width: 360px;" value-state="Error">
77+
<ui5-cb-item text="Algeria"></ui5-cb-item>
78+
<ui5-cb-item text="Argentina"></ui5-cb-item>
79+
<ui5-cb-item text="Australia"></ui5-cb-item>
80+
<ui5-cb-item text="Austria"></ui5-cb-item>
81+
<ui5-cb-item text="Bahrain"></ui5-cb-item>
82+
<ui5-cb-item text="Belgium"></ui5-cb-item>
83+
<div slot="valueStateMessage">Information message. This is a <a href="#">Link</a>. Extra long text used as an information message. Extra long text used as an information message - 2. Extra long text used as an information message - 3.</div>
84+
<div slot="valueStateMessage">Information message 2. This is a <a href="#">Link</a>. Extra long text used as an information message. Extra long text used as an information message - 2. Extra long text used as an information message - 3.</div>
85+
</ui5-combobox>
86+
<ui5-combobox id="" style="width: 360px;" value-state="Warning">
87+
<ui5-cb-item text="Algeria"></ui5-cb-item>
88+
<ui5-cb-item text="Argentina"></ui5-cb-item>
89+
<ui5-cb-item text="Australia"></ui5-cb-item>
90+
<ui5-cb-item text="Austria"></ui5-cb-item>
91+
<ui5-cb-item text="Bahrain"></ui5-cb-item>
92+
<ui5-cb-item text="Belgium"></ui5-cb-item>
93+
</ui5-combobox>
94+
<ui5-combobox id="" style="width: 360px;" value-state="Information"></ui5-combobox>
7895
<ui5-combobox id="" style="width: 360px;" value-state="Success"></ui5-combobox>
7996
</div>
8097

0 commit comments

Comments
 (0)