Skip to content

Commit 442e893

Browse files
authored
feat(ui5-tokenizer): deselect tokens on ESC (#13482)
deselect all selected tokens on ESC key press
1 parent 37e9fef commit 442e893

4 files changed

Lines changed: 194 additions & 0 deletions

File tree

packages/main/cypress/specs/MultiComboBox.cy.tsx

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3430,6 +3430,54 @@ describe("Keyboard Handling", () => {
34303430
.should("have.value", "I");
34313431
});
34323432

3433+
it("should deselect all tokens on [Escape] key when focus is on tokenizer", () => {
3434+
cy.mount(
3435+
<MultiComboBox>
3436+
<MultiComboBoxItem selected={true} text="Andora"></MultiComboBoxItem>
3437+
<MultiComboBoxItem selected={true} text="Bulgaria"></MultiComboBoxItem>
3438+
<MultiComboBoxItem selected={true} text="Canada"></MultiComboBoxItem>
3439+
</MultiComboBox>
3440+
);
3441+
3442+
cy.get("[ui5-multi-combobox]")
3443+
.shadow()
3444+
.find("[ui5-tokenizer]")
3445+
.find("[ui5-token]")
3446+
.should("have.length", 3);
3447+
3448+
cy.get("[ui5-multi-combobox]")
3449+
.realClick();
3450+
3451+
cy.realPress("Backspace");
3452+
3453+
cy.get("[ui5-multi-combobox]")
3454+
.shadow()
3455+
.find("[ui5-tokenizer]")
3456+
.find("[ui5-token]")
3457+
.last()
3458+
.should("be.focused");
3459+
3460+
cy.realPress(["Shift", "Home"]);
3461+
3462+
cy.get("[ui5-multi-combobox]")
3463+
.shadow()
3464+
.find("[ui5-tokenizer]")
3465+
.find("[ui5-token]")
3466+
.each($token => {
3467+
cy.wrap($token).should("have.attr", "selected");
3468+
});
3469+
3470+
cy.realPress("Escape");
3471+
3472+
cy.get("[ui5-multi-combobox]")
3473+
.shadow()
3474+
.find("[ui5-tokenizer]")
3475+
.find("[ui5-token]")
3476+
.each($token => {
3477+
cy.wrap($token).should("not.have.attr", "selected");
3478+
});
3479+
});
3480+
34333481
it("Selects an item when enter is pressed and value matches a text of an item in the list", () => {
34343482
cy.mount(
34353483
<>

packages/main/cypress/specs/MultiInput.cy.tsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,6 +1502,39 @@ describe("Keyboard handling", () => {
15021502
cy.get("@changeSpy")
15031503
.should("have.been.calledOnce");
15041504
});
1505+
1506+
it("should deselect all tokens on [Escape] key", () => {
1507+
cy.mount(
1508+
<MultiInput>
1509+
<Token slot="tokens" text="Andora"></Token>
1510+
<Token slot="tokens" text="Bulgaria"></Token>
1511+
<Token slot="tokens" text="Canada"></Token>
1512+
</MultiInput>
1513+
);
1514+
1515+
cy.get("[ui5-multi-input]")
1516+
.shadow()
1517+
.find("input")
1518+
.realClick();
1519+
1520+
cy.realPress("Home");
1521+
1522+
cy.get("[ui5-token]")
1523+
.eq(0)
1524+
.should("be.focused");
1525+
1526+
cy.realPress(["Shift", "End"]);
1527+
1528+
cy.get("[ui5-token]").each($token => {
1529+
cy.wrap($token).should("have.attr", "selected");
1530+
});
1531+
1532+
cy.realPress("Escape");
1533+
1534+
cy.get("[ui5-token]").each($token => {
1535+
cy.wrap($token).should("not.have.attr", "selected");
1536+
});
1537+
});
15051538
});
15061539

15071540
describe("MultiInput Composition", () => {

packages/main/cypress/specs/Tokenizer.cy.tsx

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1590,6 +1590,104 @@ describe("Keyboard Handling", () => {
15901590
.eq(1)
15911591
.should("have.attr", "selected");
15921592
});
1593+
1594+
it("should deselect all tokens on [Escape] key", () => {
1595+
cy.get("[ui5-token]")
1596+
.eq(0)
1597+
.as("firstToken");
1598+
1599+
cy.get("[ui5-token]")
1600+
.eq(1)
1601+
.as("secondToken");
1602+
1603+
cy.get("[ui5-token]")
1604+
.eq(2)
1605+
.as("thirdToken");
1606+
1607+
cy.get("@firstToken")
1608+
.realClick();
1609+
1610+
cy.realPress(["Shift", "End"]);
1611+
1612+
cy.get("@firstToken")
1613+
.should("have.attr", "selected");
1614+
1615+
cy.get("@secondToken")
1616+
.should("have.attr", "selected");
1617+
1618+
cy.get("@thirdToken")
1619+
.should("have.attr", "selected");
1620+
1621+
cy.realPress("Escape");
1622+
1623+
cy.get("@firstToken")
1624+
.should("not.have.attr", "selected");
1625+
1626+
cy.get("@secondToken")
1627+
.should("not.have.attr", "selected");
1628+
1629+
cy.get("@thirdToken")
1630+
.should("not.have.attr", "selected");
1631+
});
1632+
1633+
it("should fire selection-change event on [Escape] when tokens are selected", () => {
1634+
cy.mount(
1635+
<Tokenizer onSelectionChange={cy.stub().as("selectionChange")}>
1636+
<Token text="Andora"></Token>
1637+
<Token text="Bulgaria"></Token>
1638+
<Token text="Canada"></Token>
1639+
</Tokenizer>
1640+
);
1641+
1642+
cy.get("[ui5-token]")
1643+
.eq(0)
1644+
.realClick();
1645+
1646+
cy.get("@selectionChange")
1647+
.should("have.been.called");
1648+
1649+
cy.get("@selectionChange")
1650+
.invoke("resetHistory");
1651+
1652+
cy.realPress("Escape");
1653+
1654+
cy.get("@selectionChange")
1655+
.should("have.been.calledOnce");
1656+
1657+
cy.get("@selectionChange")
1658+
.its("firstCall.args.0.detail.tokens")
1659+
.should("have.length", 0);
1660+
});
1661+
1662+
it("should not fire selection-change on [Escape] when no tokens are selected", () => {
1663+
cy.mount(
1664+
<Tokenizer onSelectionChange={cy.stub().as("selectionChange")}>
1665+
<Token text="Andora"></Token>
1666+
<Token text="Bulgaria"></Token>
1667+
</Tokenizer>
1668+
);
1669+
1670+
cy.get("[ui5-token]")
1671+
.eq(0)
1672+
.realClick();
1673+
1674+
cy.get("@selectionChange")
1675+
.invoke("resetHistory");
1676+
1677+
cy.realPress("Space");
1678+
1679+
cy.get("[ui5-token]")
1680+
.eq(0)
1681+
.should("not.have.attr", "selected");
1682+
1683+
cy.get("@selectionChange")
1684+
.invoke("resetHistory");
1685+
1686+
cy.realPress("Escape");
1687+
1688+
cy.get("@selectionChange")
1689+
.should("not.have.been.called");
1690+
});
15931691
});
15941692

15951693
describe("Clipboard Operations", () => {

packages/main/src/Tokenizer.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,10 @@ class Tokenizer extends UI5Element implements IFormInputElement {
716716
_onkeydown(e: KeyboardEvent) {
717717
const isCtrl = !!(e.metaKey || e.ctrlKey);
718718

719+
if (isEscape(e)) {
720+
return this._deselectAllTokens();
721+
}
722+
719723
if ((isCtrl && ["c", "x"].includes(e.key.toLowerCase())) || isDeleteShift(e) || isInsertCtrl(e)) {
720724
e.preventDefault();
721725

@@ -1070,6 +1074,17 @@ class Tokenizer extends UI5Element implements IFormInputElement {
10701074
}
10711075
}
10721076

1077+
_deselectAllTokens() {
1078+
const hadSelection = this._selectedTokens.length > 0;
1079+
this._tokens.forEach(token => { token.selected = false; });
1080+
1081+
if (hadSelection) {
1082+
this.fireDecoratorEvent("selection-change", {
1083+
tokens: [],
1084+
});
1085+
}
1086+
}
1087+
10731088
get hasTokens() {
10741089
return this._tokens.length > 0;
10751090
}

0 commit comments

Comments
 (0)