Skip to content

Commit d7b1179

Browse files
authored
feat: make input-based components open dialog on mobile device (#1144)
- All input-based components, such as "Input", "Select", "DatePicker", "Combobox" and "MultiCombobox" now open Dialog on mobile devices and Popover on desktop (as before) - Introduce new component ResponsivePopover, that manages that behavior.
1 parent 389bdba commit d7b1179

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1030
-252
lines changed

packages/main/bundle.esm.js

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import Link from "./dist/Link.js";
3030
import Popover from "./dist/Popover.js";
3131
import Panel from "./dist/Panel.js";
3232
import RadioButton from "./dist/RadioButton.js";
33+
import ResponsivePopover from "./dist/ResponsivePopover.js";
3334
import Select from "./dist/Select.js";
3435
import Option from "./dist/Option.js";
3536
import Switch from "./dist/Switch.js";

packages/main/src/ComboBox.hbs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
aria-haspopup="listbox"
44
aria-expanded="{{open}}"
55
>
6-
76
<input id="ui5-combobox-input"
87
.value="{{_tempValue}}"
98
inner-input
@@ -14,6 +13,7 @@
1413
value-state="{{valueState}}"
1514
@input="{{_input}}"
1615
@change="{{_inputChange}}"
16+
@click={{_click}}
1717
@keydown="{{_keydown}}"
1818
@focusin="{{_focusin}}"
1919
@focusout="{{_focusout}}"

packages/main/src/ComboBox.js

+53-27
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
11
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";
4+
import { isPhone } from "@ui5/webcomponents-base/dist/Device.js";
45
import "@ui5/webcomponents-icons/dist/icons/slim-arrow-down.js";
6+
import { getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js";
57
import { isBackSpace, isDelete, isShow } from "@ui5/webcomponents-base/dist/events/PseudoEvents.js";
68
import * as Filters from "./ComboBoxFilters.js";
79

8-
// Styles
10+
import {
11+
INPUT_SUGGESTIONS_TITLE,
12+
} from "./generated/i18n/i18n-defaults.js";
13+
14+
// Templates
915
import ComboBoxTemplate from "./generated/templates/ComboBoxTemplate.lit.js";
1016
import ComboBoxPopoverTemplate from "./generated/templates/ComboBoxPopoverTemplate.lit.js";
17+
18+
// Styles
1119
import ComboBoxCss from "./generated/themes/ComboBox.css.js";
1220
import ComboBoxPopoverCss from "./generated/themes/ComboBoxPopover.css.js";
21+
import ResponsivePopoverCommonCss from "./generated/themes/ResponsivePopoverCommon.css.js";
22+
1323
import ComboBoxItem from "./ComboBoxItem.js";
1424
import Icon from "./Icon.js";
15-
import Popover from "./Popover.js";
25+
import ResponsivePopover from "./ResponsivePopover.js";
1626
import List from "./List.js";
1727
import BusyIndicator from "./BusyIndicator.js";
1828
import StandardListItem from "./StandardListItem.js";
@@ -249,6 +259,10 @@ class ComboBox extends UI5Element {
249259
return ComboBoxCss;
250260
}
251261

262+
static get staticAreaStyles() {
263+
return [ComboBoxPopoverCss, ResponsivePopoverCommonCss];
264+
}
265+
252266
static get template() {
253267
return ComboBoxTemplate;
254268
}
@@ -257,15 +271,12 @@ class ComboBox extends UI5Element {
257271
return ComboBoxPopoverTemplate;
258272
}
259273

260-
static get staticAreaStyles() {
261-
return ComboBoxPopoverCss;
262-
}
263-
264274
constructor(props) {
265275
super(props);
266276

267277
this._filteredItems = [];
268278
this._initialRendering = true;
279+
this.i18nBundle = getI18nBundle("@ui5/webcomponents");
269280
}
270281

271282
onBeforeRendering() {
@@ -288,7 +299,10 @@ class ComboBox extends UI5Element {
288299
}
289300

290301
onAfterRendering() {
291-
this._width = this.getBoundingClientRect().width;
302+
if (isPhone() && this._respPopover.opened) {
303+
// Set initial focus to the native input
304+
this.inner.focus();
305+
}
292306
}
293307

294308
_focusin(event) {
@@ -311,13 +325,18 @@ class ComboBox extends UI5Element {
311325

312326
_afterClosePopover() {
313327
this._iconPressed = false;
328+
329+
// close device's keyboard and prevent further typing
330+
if (isPhone()) {
331+
this.blur();
332+
}
314333
}
315334

316-
_togglePopover() {
317-
if (this.popover.opened) {
318-
this.popover.close();
335+
_toggleRespPopover() {
336+
if (this._respPopover.opened) {
337+
this._respPopover.close();
319338
} else {
320-
this.popover.openBy(this);
339+
this._respPopover.open(this);
321340
}
322341
}
323342

@@ -330,7 +349,7 @@ class ComboBox extends UI5Element {
330349
this.inner.focus();
331350
this._resetFilter();
332351

333-
this._togglePopover();
352+
this._toggleRespPopover();
334353
}
335354

336355
_input(event) {
@@ -344,7 +363,7 @@ class ComboBox extends UI5Element {
344363
this.filterValue = value;
345364
this.fireEvent("input");
346365

347-
this.popover.openBy(this);
366+
this._respPopover.open(this);
348367
}
349368

350369
_startsWithMatchingItems(str) {
@@ -357,10 +376,20 @@ class ComboBox extends UI5Element {
357376
if (isShow(event) && !this.readonly && !this.disabled) {
358377
event.preventDefault();
359378
this._resetFilter();
360-
this._togglePopover();
379+
this._toggleRespPopover();
380+
}
381+
}
382+
383+
_click(event) {
384+
if (isPhone() && !this.readonly) {
385+
this._respPopover.open(this);
361386
}
362387
}
363388

389+
_closeRespPopover() {
390+
this._respPopover.close();
391+
}
392+
364393
_filterItems(str) {
365394
return (Filters[this.filter] || Filters.StartsWithPerTerm)(str, this.items);
366395
}
@@ -402,6 +431,7 @@ class ComboBox extends UI5Element {
402431
const listItem = event.detail.item;
403432

404433
this._tempValue = listItem.mappedItem.text;
434+
this.filterValue = this._tempValue;
405435

406436
this._filteredItems.map(item => {
407437
item.selected = (item === listItem.mappedItem);
@@ -410,15 +440,7 @@ class ComboBox extends UI5Element {
410440
});
411441

412442
this._inputChange();
413-
this.popover.close();
414-
}
415-
416-
get styles() {
417-
return {
418-
popover: {
419-
"min-width": `${this._width}px`,
420-
},
421-
};
443+
this._respPopover.close();
422444
}
423445

424446
get _filteredItems() {
@@ -427,12 +449,16 @@ class ComboBox extends UI5Element {
427449
});
428450
}
429451

452+
get _headerTitleText() {
453+
return this.i18nBundle.getText(INPUT_SUGGESTIONS_TITLE);
454+
}
455+
430456
get inner() {
431-
return this.shadowRoot.querySelector("[inner-input]");
457+
return isPhone() ? this._respPopover.querySelector(".ui5-input-inner-phone") : this.shadowRoot.querySelector("[inner-input]");
432458
}
433459

434-
get popover() {
435-
return this.getStaticAreaItemDomRef().querySelector("ui5-popover");
460+
get _respPopover() {
461+
return this.getStaticAreaItemDomRef().querySelector("ui5-responsive-popover");
436462
}
437463

438464
get editable() {
@@ -443,7 +469,7 @@ class ComboBox extends UI5Element {
443469
await Promise.all([
444470
ComboBoxItem.define(),
445471
Icon.define(),
446-
Popover.define(),
472+
ResponsivePopover.define(),
447473
List.define(),
448474
BusyIndicator.define(),
449475
StandardListItem.define(),

packages/main/src/ComboBoxPopover.hbs

+44-11
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,48 @@
1-
<ui5-popover
2-
style={{styles.popover}}
3-
horizontal-align="Left"
4-
?no-arrow={{editable}}
5-
no-padding="true"
6-
placement-type="Bottom"
7-
_disable-initial-focus="true"
1+
<ui5-responsive-popover
2+
no-arrow
3+
_disable-initial-focus
84
@ui5-afterOpen={{_afterOpenPopover}}
95
@ui5-afterClose={{_afterClosePopover}}
106
>
11-
12-
<ui5-busyindicator
7+
<ui5-busyindicator
138
?active={{loading}}
149
size="Medium"
1510
class="ui5-combobox-busy"
1611
>
1712
</ui5-busyindicator>
1813

19-
<ui5-list
14+
<div slot="header" class="ui5-responsive-popover-header">
15+
<div class="row">
16+
<span>{{_headerTitleText}}</span>
17+
<ui5-button
18+
icon="decline"
19+
design="Transparent"
20+
@click="{{_closeRespPopover}}"
21+
>
22+
</ui5-button>
23+
</div>
24+
<div class="row">
25+
<div
26+
slot="header"
27+
class="input-root-phone"
28+
value-state="{{valueState}}"
29+
>
30+
<input
31+
class="ui5-input-inner-phone"
32+
.value="{{_tempValue}}"
33+
inner-input
34+
placeholder="{{placeholder}}"
35+
value-state="{{valueState}}"
36+
@input="{{_input}}"
37+
@change="{{_inputChange}}"
38+
@keydown="{{_keydown}}"
39+
aria-autocomplete="both"
40+
/>
41+
</div>
42+
</div>
43+
</div>
44+
45+
<ui5-list
2046
separators="None"
2147
@ui5-itemClick={{_selectItem}}
2248
mode="SingleSelect"
@@ -31,4 +57,11 @@
3157
</ui5-li>
3258
{{/each}}
3359
</ui5-list>
34-
</ui5-popover>
60+
61+
<div slot="footer" class="ui5-responsive-popover-footer">
62+
<ui5-button
63+
design="Transparent"
64+
@click="{{_closeRespPopover}}"
65+
>OK</ui5-button>
66+
</div>
67+
</ui5-responsive-popover>

packages/main/src/DatePicker.hbs

+1
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,6 @@
3232
></ui5-icon>
3333
{{/unless}}
3434
</ui5-input>
35+
3536
<slot name="formSupport"></slot>
3637
</div>

0 commit comments

Comments
 (0)