diff --git a/packages/main/cypress/specs/Tokenizer.cy.tsx b/packages/main/cypress/specs/Tokenizer.cy.tsx
index 0dd97b5ce12a..c4d7138539a0 100755
--- a/packages/main/cypress/specs/Tokenizer.cy.tsx
+++ b/packages/main/cypress/specs/Tokenizer.cy.tsx
@@ -1824,6 +1824,108 @@ 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);
+ });
+
+ it("should cut only selected tokens when there are both selected and focused tokens", () => {
+ cy.mount(
+
+
+
+
+
+ );
+
+ // Focus the third token via keyboard without selecting it
+ cy.realPress("Tab");
+ cy.realPress("ArrowRight");
+ cy.realPress("ArrowRight");
+ cy.get("[ui5-token]").eq(2).should("have.prop", "focused", true);
+ cy.get("[ui5-token]").eq(2).should("have.prop", "selected", false);
+ // First two remain selected
+ cy.get("[ui5-token]").eq(0).should("have.prop", "selected", true);
+ cy.get("[ui5-token]").eq(1).should("have.prop", "selected", 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 cut the selected tokens, not the focused one
+ cy.get("@clipboardWrite").should("have.been.calledOnceWith", "Selected1\r\nSelected2");
+ cy.get("[ui5-token]").should("have.length", 1);
+ cy.get("[ui5-token]").eq(0).should("have.prop", "text", "NotSelected");
+ });
+
+ it("should cut focused token when no tokens are selected", () => {
+ cy.mount(
+
+
+
+
+ );
+
+ 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", "x"]);
+
+ cy.get("@clipboardWrite").should("have.been.calledOnceWith", "Focused");
+ cy.get("[ui5-token]").should("have.length", 1);
+ cy.get("[ui5-token]").eq(0).should("have.prop", "text", "Other");
+ });
});
describe("Tokenizer - getFocusDomRef Method", () => {
diff --git a/packages/main/src/Tokenizer.ts b/packages/main/src/Tokenizer.ts
index 0cdd39e560a1..aeb66ad8311f 100644
--- a/packages/main/src/Tokenizer.ts
+++ b/packages/main/src/Tokenizer.ts
@@ -721,17 +721,21 @@ class Tokenizer extends UI5Element implements IFormInputElement {
const isCut = e.key.toLowerCase() === "x" || isDeleteShift(e);
const selectedTokens = this._tokens.filter(token => token.selected);
- const focusedToken = selectedTokens.find(token => token.focused);
+ const focusedToken = this._tokens.find(token => token.focused);
+ let tokensToCopy = selectedTokens;
+ if (!tokensToCopy.length && focusedToken) {
+ tokensToCopy = [focusedToken];
+ }
- if (isCut) {
- const cutResult = this._fillClipboard(ClipboardDataOperation.cut, selectedTokens);
+ if (isCut && !this.readonly && tokensToCopy.length) {
+ const cutResult = this._fillClipboard(ClipboardDataOperation.cut, tokensToCopy);
- focusedToken && this.deleteToken(focusedToken);
+ this.deleteToken(tokensToCopy[0]);
return cutResult;
}
- return this._fillClipboard(ClipboardDataOperation.copy, selectedTokens);
+ return this._fillClipboard(ClipboardDataOperation.copy, tokensToCopy);
}
if (isCtrl && e.key.toLowerCase() === "i" && this._tokens.length > 0) {
@@ -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) {