diff --git a/packages/main/cypress/specs/Tokenizer.cy.tsx b/packages/main/cypress/specs/Tokenizer.cy.tsx index 0dd97b5ce12a..e5bf68971bb0 100755 --- a/packages/main/cypress/specs/Tokenizer.cy.tsx +++ b/packages/main/cypress/specs/Tokenizer.cy.tsx @@ -1824,6 +1824,52 @@ describe("Clipboard Operations", () => { // Only the selected token should be copied cy.get("@clipboardWrite").should("have.been.calledOnceWith", "Selected"); }); + + it("should copy focused token text when no tokens are selected", () => { + cy.mount( + + + + + ); + + // Tab into the tokenizer to focus the first token without selecting it + cy.realPress("Tab"); + cy.get("[ui5-token]").eq(0).should("have.prop", "focused", true); + cy.get("[ui5-token]").eq(0).should("have.prop", "selected", false); + + cy.window().then((win) => { + cy.stub(win.navigator.clipboard, "writeText").as("clipboardWrite"); + Object.defineProperty(win, "isSecureContext", { value: true, writable: true }); + }); + + cy.realPress(["Control", "c"]); + + cy.get("@clipboardWrite").should("have.been.calledOnceWith", "Focused"); + }); + + it("should not cut token in readonly mode", () => { + cy.mount( + + + + + ); + + cy.realPress("Tab"); + cy.get("[ui5-token]").eq(0).should("have.prop", "focused", true); + + cy.window().then((win) => { + cy.stub(win.navigator.clipboard, "writeText").as("clipboardWrite"); + Object.defineProperty(win, "isSecureContext", { value: true, writable: true }); + }); + + cy.realPress(["Control", "x"]); + + // Should copy but not delete in readonly mode + cy.get("@clipboardWrite").should("have.been.calledOnceWith", "ReadonlyToken"); + cy.get("[ui5-token]").should("have.length", 2); + }); }); describe("Tokenizer - getFocusDomRef Method", () => { diff --git a/packages/main/src/Tokenizer.ts b/packages/main/src/Tokenizer.ts index 0cdd39e560a1..edc33e73be1f 100644 --- a/packages/main/src/Tokenizer.ts +++ b/packages/main/src/Tokenizer.ts @@ -720,10 +720,14 @@ class Tokenizer extends UI5Element implements IFormInputElement { e.preventDefault(); const isCut = e.key.toLowerCase() === "x" || isDeleteShift(e); - const selectedTokens = this._tokens.filter(token => token.selected); - const focusedToken = selectedTokens.find(token => token.focused); + let selectedTokens = this._tokens.filter(token => token.selected); + const focusedToken = this._tokens.find(token => token.focused); - if (isCut) { + if (!selectedTokens.length && focusedToken) { + selectedTokens = [focusedToken]; + } + + if (isCut && !this.readonly) { const cutResult = this._fillClipboard(ClipboardDataOperation.cut, selectedTokens); focusedToken && this.deleteToken(focusedToken); @@ -1079,7 +1083,7 @@ class Tokenizer extends UI5Element implements IFormInputElement { } _fillClipboard(shortcutName: ClipboardDataOperation, tokens: Array) { - const tokensTexts = tokens.filter(token => token.selected).map(token => token.text).join("\r\n"); + const tokensTexts = tokens.map(token => token.text).join("\r\n"); // Async clipboard API (works in secure contexts - HTTPS/localhost) if (navigator.clipboard?.writeText && window.isSecureContext) {