Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui5-multi-combobox/ui5-combobox): introduce open property #11044

Merged
merged 3 commits into from
Mar 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions packages/main/cypress/specs/ComboBox.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,59 @@ describe("Security", () => {
.should("have.text", "Albania<button onClick='alert(1)'>alert</button>");
});
});

describe("Event firing", () => {
it("tests if open and close events are fired correctly", () => {
cy.mount(
<ComboBox>
<ComboBoxItem text="Algeria"></ComboBoxItem>
<ComboBoxItem text="Bulgaria"></ComboBoxItem>
<ComboBoxItem text="England"></ComboBoxItem>
</ComboBox>
);

cy.get("ui5-combobox")
.as("combo");

cy.get("@combo").then($combo => {
$combo[0].addEventListener("focusin", () => {
$combo[0].setAttribute("open", "true");
});
});

cy.get("@combo").then($combo => {
$combo[0].addEventListener("ui5-open", cy.stub().as("comboOpened"));
});

cy.get("@combo").then($combo => {
$combo[0].addEventListener("ui5-close", cy.stub().as("comboClosed"));
});

cy.get("@combo")
.shadow()
.find("input")
.focus();

cy.get("@combo")
.shadow()
.find("ui5-icon")
.as("icon");

cy.get("@icon")
.click();

cy.get("@icon")
.click();

cy.get("@combo")
.shadow()
.find("ui5-responsive-popover")
.should("have.attr", "open");

cy.get("@comboClosed")
.should("have.been.calledOnce");

cy.get("@comboOpened")
.should("have.been.calledTwice");
});
});
68 changes: 68 additions & 0 deletions packages/main/cypress/specs/MultiComboBox.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,71 @@ describe("Value State", () => {
.should("not.exist");
});
});

describe("Event firing", () => {
it("tests if open and close events are fired correctly", () => {
cy.mount(
<MultiComboBox>
<MultiComboBoxItem text="Algeria"></MultiComboBoxItem>
<MultiComboBoxItem text="Bulgaria"></MultiComboBoxItem>
<MultiComboBoxItem text="England"></MultiComboBoxItem>
</MultiComboBox>
);

cy.get("ui5-multi-combobox")
.as("multiComboBox");

cy.get("@multiComboBox")
.then($mcb => {
$mcb[0].addEventListener("focusin", () => {
$mcb[0].setAttribute("open", "true");
});
});

cy.get("@multiComboBox")
.then($mcb => {
$mcb[0].addEventListener("ui5-open", cy.stub().as("mcbOpened"));
});

cy.get("@multiComboBox")
.then($mcb => {
$mcb[0].addEventListener("ui5-close", cy.stub().as("mcbClosed"));
});

cy.get("@multiComboBox")
.shadow()
.find("input")
.as("input");

cy.get("@input")
.click();

cy.get("@multiComboBox")
.shadow()
.find("ui5-responsive-popover")
.as("respPopover");

cy.get("@respPopover")
.should("have.attr", "open");

cy.get("@mcbOpened")
.should("have.been.calledOnce");

cy.get("@multiComboBox")
.shadow()
.find("ui5-icon")
.as("icon");

cy.get("@icon")
.click();

cy.get("@icon")
.click();

cy.get("@mcbClosed")
.should("have.been.calledOnce");

cy.get("@mcbOpened")
.should("have.been.calledTwice");
});
});
26 changes: 23 additions & 3 deletions packages/main/src/ComboBox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,22 @@ type ComboBoxSelectionChangeEventDetail = {
bubbles: true,
})

/**
* Fired when the dropdown is opened.
* @since 2.9.0
* @public
*/
@event("open", {
bubbles: true,
})

/**
* Fired when the dropdown is closed.
* @since 2.9.0
* @public
*/
@event("close")

/**
* Fired when typing in input or clear icon is pressed.
*
Expand All @@ -194,6 +210,8 @@ class ComboBox extends UI5Element implements IFormInputElement {
eventDetails!: {
"change": void,
"input": void,
"open": void,
"close": void,
"selection-change": ComboBoxSelectionChangeEventDetail,
}
/**
Expand Down Expand Up @@ -363,10 +381,10 @@ class ComboBox extends UI5Element implements IFormInputElement {

/**
* Indicates whether the items picker is open.
* @private
* @since 2.0.0
* @public
* @since 2.9.0
*/
@property({ type: Boolean, noAttribute: true })
@property({ type: Boolean })
open = false;

/**
Expand Down Expand Up @@ -526,6 +544,7 @@ class ComboBox extends UI5Element implements IFormInputElement {
_afterOpenPopover() {
this._iconPressed = true;
this.inner.focus();
this.fireDecoratorEvent("open");
}

_afterClosePopover() {
Expand All @@ -545,6 +564,7 @@ class ComboBox extends UI5Element implements IFormInputElement {
}

this.open = false;
this.fireDecoratorEvent("close");
}

_toggleRespPopover() {
Expand Down
49 changes: 25 additions & 24 deletions packages/main/src/MultiComboBox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -401,10 +401,11 @@ class MultiComboBox extends UI5Element implements IFormInputElement {

/**
* Indicates whether the items picker is open.
* @private
* @public
* @since 2.9.0
*/
@property({ type: Boolean, noAttribute: true })
_open = false;
@property({ type: Boolean })
open = false;

@property()
_valueBeforeOpen = this.value;
Expand Down Expand Up @@ -614,19 +615,19 @@ class MultiComboBox extends UI5Element implements IFormInputElement {
if (!changePrevented) {
matchingItem.selected = !initiallySelected;
this._getResponsivePopover().preventFocusRestore = false;
this._open = false;
this.open = false;
this.value = "";
}
}

_toggleTokenizerPopover() {
this.tokenizerOpen = false;
this._open = !this.open;
this.open = !this.open;
}

togglePopoverByDropdownIcon() {
this._shouldFilterItems = false;
this._open = !this.open;
this.open = !this.open;
this.tokenizerOpen = false;
}

Expand All @@ -649,8 +650,8 @@ class MultiComboBox extends UI5Element implements IFormInputElement {
* @default false
* @public
*/
get open(): boolean {
return this._open;
get isOpen(): boolean {
return this.open;
}

get _showAllItemsButtonPressed(): boolean {
Expand Down Expand Up @@ -704,9 +705,9 @@ class MultiComboBox extends UI5Element implements IFormInputElement {

if (!isPhone()) {
if (filteredItems.length === 0) {
this._open = false;
this.open = false;
} else {
this._open = true;
this.open = true;
}
}

Expand Down Expand Up @@ -753,7 +754,7 @@ class MultiComboBox extends UI5Element implements IFormInputElement {

_onPopoverFocusOut() {
if (!isPhone()) {
this._tokenizer.expanded = this._open;
this._tokenizer.expanded = this.open;
}
}

Expand Down Expand Up @@ -962,7 +963,7 @@ class MultiComboBox extends UI5Element implements IFormInputElement {
this.value = this.valueBeforeAutoComplete;
}

if (!this.noValidation || (!this._open && this.noValidation)) {
if (!this.noValidation || (!this.open && this.noValidation)) {
this.value = this._lastValue;
}
}
Expand All @@ -988,7 +989,7 @@ class MultiComboBox extends UI5Element implements IFormInputElement {
}

_handleTab() {
this._open = false;
this.open = false;
}

_handleSelectAll() {
Expand Down Expand Up @@ -1144,7 +1145,7 @@ class MultiComboBox extends UI5Element implements IFormInputElement {
_onItemTab() {
this._getResponsivePopover().preventFocusRestore = true;
this._inputDom.focus();
this._open = false;
this.open = false;
this._tokenizer.expanded = false;
}

Expand Down Expand Up @@ -1175,7 +1176,7 @@ class MultiComboBox extends UI5Element implements IFormInputElement {
this._handleArrowDown();
}

if (!isArrowDown && !this._open && !this.readonly) {
if (!isArrowDown && !this.open && !this.readonly) {
this._navigateToPrevItem();
}
}
Expand Down Expand Up @@ -1315,7 +1316,7 @@ class MultiComboBox extends UI5Element implements IFormInputElement {
}

innerInput.setSelectionRange(matchingItem.text!.length, matchingItem.text!.length);
this._open = false;
this.open = false;
} else if (this._internals?.form) {
submitForm(this);
}
Expand Down Expand Up @@ -1399,7 +1400,7 @@ class MultiComboBox extends UI5Element implements IFormInputElement {
}

_afterOpen() {
const action = this._open ? "open" : "close";
const action = this.open ? "open" : "close";

if (!isPhone() && !this._isOpenedByKeyboard) {
this._innerInput.focus();
Expand Down Expand Up @@ -1472,7 +1473,7 @@ class MultiComboBox extends UI5Element implements IFormInputElement {
}

if (!e.detail.selectionComponentPressed && !isSpace(castedEvent) && !isSpaceCtrl(castedEvent)) {
this._open = false;
this.open = false;
this.value = "";

// if the item (not checkbox) is clicked, call the selection change
Expand Down Expand Up @@ -1506,7 +1507,7 @@ class MultiComboBox extends UI5Element implements IFormInputElement {

_click() {
if (isPhone() && !this.readonly && !this._showMorePressed && !this._deleting) {
this._open = true;
this.open = true;
}

this._showMorePressed = false;
Expand All @@ -1524,11 +1525,11 @@ class MultiComboBox extends UI5Element implements IFormInputElement {
}

_beforeClose() {
this._open = false;
this.open = false;
}

_afterClose() {
const action = this._open ? "open" : "close";
const action = this.open ? "open" : "close";

// close device's keyboard and prevent further typing
if (isPhone()) {
Expand All @@ -1544,7 +1545,7 @@ class MultiComboBox extends UI5Element implements IFormInputElement {
}

_beforeOpen() {
this._open = true;
this.open = true;
this._itemsBeforeOpen = this._getItems().map(item => {
return {
ref: item,
Expand Down Expand Up @@ -1694,7 +1695,7 @@ class MultiComboBox extends UI5Element implements IFormInputElement {
}

storeResponsivePopoverWidth() {
if (this._open && !this._listWidth) {
if (this.open && !this._listWidth) {
this._listWidth = this.list!.offsetWidth;
}
}
Expand Down Expand Up @@ -1978,7 +1979,7 @@ class MultiComboBox extends UI5Element implements IFormInputElement {
}

const isCurrentlyExpanded = this._tokenizer?.expanded;
const shouldBeExpanded = this.focused || this._open || isCurrentlyExpanded;
const shouldBeExpanded = this.focused || this.open || isCurrentlyExpanded;

return shouldBeExpanded;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/main/src/MultiComboBoxPopoverTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default function MultiComboBoxPopoverTemplate(this: MultiComboBox) {
onOpen={this._afterOpen}
onFocusOut={this._onPopoverFocusOut}
accessibleName={this._popupLabel}
open={this._open}
open={this.open}
opener={this}
>
{this._isPhone && <>
Expand Down
Loading