diff --git a/.changeset/tiny-mobile-clicks.md b/.changeset/tiny-mobile-clicks.md new file mode 100644 index 0000000000..a7cd80d601 --- /dev/null +++ b/.changeset/tiny-mobile-clicks.md @@ -0,0 +1,5 @@ +--- +"@runfusion/fusion": patch +--- + +Fix mobile Quick Entry action buttons so taps rely on native browser click synthesis instead of a manual touchend click. diff --git a/packages/dashboard/app/components/QuickEntryBox.css b/packages/dashboard/app/components/QuickEntryBox.css index 4491016bc1..bf947e022d 100644 --- a/packages/dashboard/app/components/QuickEntryBox.css +++ b/packages/dashboard/app/components/QuickEntryBox.css @@ -428,11 +428,11 @@ } } -/* === Quick Entry Mobile Touch + Overflow Fixes (FN-1140, FN-6153) === */ +/* === Quick Entry Mobile Touch + Overflow Fixes (FN-1140, FN-6153, FN-6160) === */ @media (max-width: 768px) { .quick-entry-actions, .quick-entry-actions * { - touch-action: none; + touch-action: manipulation; } .quick-entry-actions .btn { diff --git a/packages/dashboard/app/components/QuickEntryBox.tsx b/packages/dashboard/app/components/QuickEntryBox.tsx index 31cf93455a..4a639b7bca 100644 --- a/packages/dashboard/app/components/QuickEntryBox.tsx +++ b/packages/dashboard/app/components/QuickEntryBox.tsx @@ -1492,16 +1492,7 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels, } }} onTouchEnd={() => { - const button = touchButtonRef.current; touchButtonRef.current = null; - if (button && !button.disabled) { - button.click(); - window.setTimeout(() => { - window.setTimeout(() => { - textareaRef.current?.focus({ preventScroll: true }); - }, 0); - }, 0); - } }} onTouchCancel={() => { touchButtonRef.current = null; diff --git a/packages/dashboard/app/components/__tests__/QuickEntryBox.test.tsx b/packages/dashboard/app/components/__tests__/QuickEntryBox.test.tsx index f7c62bc87b..936e19a791 100644 --- a/packages/dashboard/app/components/__tests__/QuickEntryBox.test.tsx +++ b/packages/dashboard/app/components/__tests__/QuickEntryBox.test.tsx @@ -505,6 +505,7 @@ describe("QuickEntryBox", () => { expect(preventDefaultSpy).toHaveBeenCalled(); await act(async () => { fireEvent(button, new Event("touchend", { bubbles: true, cancelable: true })); + fireEvent.click(button); vi.runOnlyPendingTimers(); vi.runOnlyPendingTimers(); }); @@ -530,6 +531,7 @@ describe("QuickEntryBox", () => { expect(preventDefaultSpy).toHaveBeenCalled(); await act(async () => { fireEvent(svg!, new Event("touchend", { bubbles: true, cancelable: true })); + fireEvent.click(priorityButton); vi.runOnlyPendingTimers(); vi.runOnlyPendingTimers(); }); @@ -569,6 +571,7 @@ describe("QuickEntryBox", () => { expect(preventDefaultSpy).toHaveBeenCalled(); await act(async () => { fireEvent(svg!, new Event("touchend", { bubbles: true, cancelable: true })); + fireEvent.click(githubToggle); vi.runOnlyPendingTimers(); vi.runOnlyPendingTimers(); }); @@ -653,10 +656,19 @@ describe("QuickEntryBox", () => { expect(document.activeElement).toBe(textarea); await act(async () => { fireEvent(button, new Event("touchend", { bubbles: true, cancelable: true })); + fireEvent.click(button); vi.runOnlyPendingTimers(); vi.runOnlyPendingTimers(); }); expect(document.activeElement).toBe(textarea); + + const outsideElement = document.createElement("div"); + document.body.appendChild(outsideElement); + try { + fireEvent.mouseDown(outsideElement); + } finally { + document.body.removeChild(outsideElement); + } }); it("does not fire disabled button actions via touch", async () => { @@ -3218,7 +3230,7 @@ describe("QuickEntryBox", () => { const touchRule = quickEntryMobileActionsTouchRule(); expect(touchRule).toMatch(/\.quick-entry-actions,\s*\.quick-entry-actions \*/); - expect(touchRule).toMatch(/touch-action:\s*none;/); + expect(touchRule).toMatch(/touch-action:\s*manipulation;/); }); it("keeps inline deps/models controls in touch-target button classes on mobile", () => {