From 561e0f4cd83669e67d01eded575c124799c0aead Mon Sep 17 00:00:00 2001 From: Fusion Agent Date: Tue, 18 Aug 2026 19:46:08 +0000 Subject: [PATCH] FN-015: remove legacy lane-columns CSS Remove the retired lane compatibility selector while preserving live Board scrolling and overscroll behavior. - Remove legacy .lane-columns styling from Lane.css. - Update mobile Board regression fixtures and solution documentation for current workflow-column paths. - Add a patch changeset documenting the internal cleanup. Files changed: .changeset/fn-015-removal.md | 7 ++++ ...-board-ios-horizontal-overscroll-containment.md | 32 +++++++++-------- .../__tests__/board-mobile-column-swipe.test.ts | 11 +++--- .../__tests__/board-mobile-overscroll-containment.test.ts | 28 ++++++++------- packages/dashboard/app/components/Lane.css | 41 +++------------------- 5 files changed, 51 insertions(+), 68 deletions(-) Fusion-Task-Id: FN-015 Fusion-Task-Lineage: 78128638-a319-4589-8cdd-a6497efe226f Co-authored-by: Fusion --- .changeset/fn-015-removal.md | 7 ++++ ...d-ios-horizontal-overscroll-containment.md | 32 ++++++++------- .../board-mobile-column-swipe.test.ts | 11 ++--- ...oard-mobile-overscroll-containment.test.ts | 28 +++++++------ packages/dashboard/app/components/Lane.css | 41 +++---------------- 5 files changed, 51 insertions(+), 68 deletions(-) create mode 100644 .changeset/fn-015-removal.md diff --git a/.changeset/fn-015-removal.md b/.changeset/fn-015-removal.md new file mode 100644 index 0000000000..ef5c5afd5d --- /dev/null +++ b/.changeset/fn-015-removal.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Remove retired Board compatibility styling without changing live scrolling behavior. +category: internal +dev: Removes the legacy `.lane-columns` CSS after verifying current selected-workflow and All-workflows Board paths and known/bundled plugin surfaces do not consume it; live desktop containment and phone proximity snapping remain covered by CSS-fixture regression tests. diff --git a/docs/solutions/ui-bugs/mobile-board-ios-horizontal-overscroll-containment.md b/docs/solutions/ui-bugs/mobile-board-ios-horizontal-overscroll-containment.md index ed24c8c4f3..6bf7906f17 100644 --- a/docs/solutions/ui-bugs/mobile-board-ios-horizontal-overscroll-containment.md +++ b/docs/solutions/ui-bugs/mobile-board-ios-horizontal-overscroll-containment.md @@ -22,7 +22,7 @@ tags: - css-regression-test - kanban applies_when: - - "A horizontally scrollable board or lane strip uses `overflow-x: auto` with mobile momentum scrolling" + - "A horizontally scrollable Board surface uses `overflow-x: auto` with mobile momentum scrolling" - "Edge dragging should keep native inner scrolling but must not chain or park content off screen" --- @@ -30,35 +30,39 @@ applies_when: ## Problem -The mobile kanban board intentionally scrolls horizontally between columns using `overflow-x: auto`, `-webkit-overflow-scrolling: touch`, and `scroll-snap-type: x proximity`. On iOS Safari/PWA, that same momentum scroller can rubber-band past its first or last column if the scroller does not contain horizontal overscroll. The visible result is that the columns slide away from the viewport edge, exposing empty space and sometimes chaining the drag to the document. +The mobile kanban Board intentionally scrolls horizontally between columns using `overflow-x: auto`, `-webkit-overflow-scrolling: touch`, and `scroll-snap-type: x proximity`. On iOS Safari/PWA, that same momentum scroller can rubber-band past its first or last column if the scroller does not contain horizontal overscroll. The visible result is that the columns slide away from the viewport edge, exposing empty space and sometimes chaining the drag to the document. ## Root cause -The board had page-level mobile overscroll protection on `html, body`, but the board itself is the horizontal scroll container. The base `.board` and the mobile `@media (max-width: 768px) .board` rules declared the intended scroll and snap properties without `overscroll-behavior-x`, so iOS edge overscroll was not contained at the board boundary. Workflow and multi-lane board variants in `Lane.css` had the same independent horizontal scrollers. +The board had page-level mobile overscroll protection on `html, body`, but the Board itself is the horizontal scroll container. The base `.board` and the live workflow-column `.board.board-workflow-columns` rules declare the intended scroll and snap properties with `overscroll-behavior-x: contain`, so iOS edge overscroll stops at the Board boundary. Both selected-workflow and All-workflows render paths use the workflow-column selector. ## Solution -Add axis-specific containment to each horizontal board strip: +Keep axis-specific containment on the current horizontal Board surfaces: ```css .board, -.board.board-workflow-columns, -.lane-columns { +.board.board-workflow-columns { overflow-x: auto; overscroll-behavior-x: contain; - scroll-snap-type: x proximity; +} + +@media (max-width: 768px), (max-height: 480px) { + .board.board-workflow-columns { + scroll-snap-type: x proximity; + } } ``` -Keep `contain` rather than `none`: the board can retain its native inner scroll feel while edge overscroll stops at the board/lane container instead of chaining outward. Do not replace this with `overflow: hidden`/`clip`, and do not switch snap back to `x mandatory`; both would regress intentional mobile column navigation. +Keep `contain` rather than `none`: the Board retains its native inner scroll feel while edge overscroll stops at the Board container instead of chaining outward. Desktop and tablet workflow columns explicitly use `scroll-snap-type: none`; phone and short-landscape workflow columns use proximity snapping. Do not replace this with `overflow: hidden`/`clip`, and do not switch snap to `x mandatory`; both would regress intentional mobile column navigation. ## Regression coverage -Use a CSS-fixture test that loads the combined dashboard CSS and asserts: +Use CSS-fixture tests that load the combined dashboard CSS and assert: -- the mobile `.board` rule still has `overflow-x: auto` and `scroll-snap-type: x proximity`; -- the mobile `.board` rule declares `overscroll-behavior-x: contain`; -- the base `.board`, `.board.board-workflow-columns`, and `.lane-columns` horizontal scrollers also declare containment; -- no checked board path uses `scroll-snap-type: x mandatory`. +- the base `.board` and `.board.board-workflow-columns` rules have `overflow-x: auto`, `overscroll-behavior-x: contain`, and `scroll-snap-type: none`; +- the phone and short-landscape `.board` and `.board.board-workflow-columns` rules retain `scroll-snap-type: x proximity`; +- neither Board workflow render path permits `scroll-snap-type: x mandatory`; +- the retired lane compatibility selector is absent from both the base and phone CSS slices. -For FN-6378 this lives in `packages/dashboard/app/__tests__/board-mobile-overscroll-containment.test.ts`. +For FN-6378 this lives in `packages/dashboard/app/__tests__/board-mobile-overscroll-containment.test.ts` and the companion column-swipe fixture. diff --git a/packages/dashboard/app/__tests__/board-mobile-column-swipe.test.ts b/packages/dashboard/app/__tests__/board-mobile-column-swipe.test.ts index babdc72479..fe4690bae8 100644 --- a/packages/dashboard/app/__tests__/board-mobile-column-swipe.test.ts +++ b/packages/dashboard/app/__tests__/board-mobile-column-swipe.test.ts @@ -88,12 +88,13 @@ describe("mobile board column swipe target containment (FN-6389)", () => { expect(columnBodyBlock).not.toContain("overflow-y: hidden"); }); - it("opts workflow and multi-lane board interiors into horizontal panning", () => { + it("opts live workflow Board columns into horizontal panning", () => { + expect(baseCss).not.toMatch(/\.lane-columns\b/); + expect(mobileCss).not.toMatch(/\.lane-columns\b/); + for (const selector of [ ".board.board-workflow-columns", ".board.board-workflow-columns > .column", - ".lane-columns", - ".lane-columns > .column", ]) { expectTouchPanXY(baseCss, selector); } @@ -120,10 +121,10 @@ describe("mobile board column swipe target containment (FN-6389)", () => { expect(widthContainmentBlock).toContain("max-inline-size: 100%;"); }); - it("preserves FN-6378 horizontal overscroll containment, with proximity snap on phones and none on desktop", () => { + it("preserves live Board containment, phone proximity snap, and desktop free-panning", () => { expectContainmentScroller(ruleBlock(baseCss, ".board"), "none"); expectContainmentScroller(ruleBlock(mobileCss, ".board"), "proximity"); expectContainmentScroller(ruleBlock(baseCss, ".board.board-workflow-columns"), "none"); - expectContainmentScroller(ruleBlock(baseCss, ".lane-columns"), "none"); + expectContainmentScroller(ruleBlock(mobileCss, ".board.board-workflow-columns"), "proximity"); }); }); diff --git a/packages/dashboard/app/__tests__/board-mobile-overscroll-containment.test.ts b/packages/dashboard/app/__tests__/board-mobile-overscroll-containment.test.ts index b39733df81..f964b4cda2 100644 --- a/packages/dashboard/app/__tests__/board-mobile-overscroll-containment.test.ts +++ b/packages/dashboard/app/__tests__/board-mobile-overscroll-containment.test.ts @@ -57,22 +57,24 @@ describe("board-mobile-overscroll-containment (FN-6378)", () => { expect(boardBlock).not.toContain("scroll-snap-type: x"); }); - it("workflow columns and multi-lane column strips contain horizontal overscroll and do not snap on desktop", () => { + it("live workflow Board columns contain horizontal overscroll and do not snap on desktop", () => { const workflowColumnsBlock = extractRuleBlock(baseCss, ".board.board-workflow-columns"); - const laneColumnsBlock = extractRuleBlock(baseCss, ".lane-columns"); - for (const block of [workflowColumnsBlock, laneColumnsBlock]) { - expect(block).toContain("overflow-x: auto"); - expect(block).toContain("overscroll-behavior-x: contain"); - expect(block).toContain("scroll-snap-type: none"); - expect(block).not.toContain("scroll-snap-type: x"); - } + expect(workflowColumnsBlock).toContain("overflow-x: auto"); + expect(workflowColumnsBlock).toContain("overscroll-behavior-x: contain"); + expect(workflowColumnsBlock).toContain("scroll-snap-type: none"); + expect(workflowColumnsBlock).not.toContain("scroll-snap-type: x"); }); - it("phone tier re-enables proximity snapping for workflow columns and lane strips", () => { - // Both live in Lane.css's mobile block; assert against the mobile slice of all app CSS. - expect(mobileCss).toContain("scroll-snap-type: x proximity"); - expect(mobileCss).not.toContain("scroll-snap-type: x mandatory"); - expect(mobileCss).toMatch(/\.board\.board-workflow-columns,\s*\n?\s*\.lane-columns\s*\{[^}]*scroll-snap-type: x proximity/); + it("does not ship the retired lane selector in base or phone CSS", () => { + expect(baseCss).not.toMatch(/\.lane-columns\b/); + expect(mobileCss).not.toMatch(/\.lane-columns\b/); + }); + + it("phone tier re-enables proximity snapping for the live workflow Board", () => { + const workflowColumnsBlock = extractRuleBlock(mobileCss, ".board.board-workflow-columns"); + + expect(workflowColumnsBlock).toContain("scroll-snap-type: x proximity"); + expect(workflowColumnsBlock).not.toContain("scroll-snap-type: x mandatory"); }); }); diff --git a/packages/dashboard/app/components/Lane.css b/packages/dashboard/app/components/Lane.css index 5c67f94a21..f91e6224b0 100644 --- a/packages/dashboard/app/components/Lane.css +++ b/packages/dashboard/app/components/Lane.css @@ -123,36 +123,6 @@ text-align: center; } -.lane-columns { - display: flex; - gap: var(--column-gap, 12px); - padding: 12px; - overflow-x: auto; - overflow-y: hidden; - overscroll-behavior-x: contain; - /* FNXC:BoardNavigation 2026-07-24-10:05: lane columns snap on phones only (see mobile block). */ - scroll-snap-type: none; - scrollbar-color: var(--border) transparent; - scrollbar-width: thin; - min-height: 0; - touch-action: pan-x pan-y; -} - -.lane-columns > .column { - flex: 0 0 clamp(280px, 28vw, 340px); - /* Repo convention (mobile-scroll-snap test): snap-align must be `center`. */ - scroll-snap-align: center; - touch-action: pan-x pan-y; -} - -.lane-columns::-webkit-scrollbar { - height: 6px; -} -.lane-columns::-webkit-scrollbar-thumb { - background: var(--border); - border-radius: var(--radius-sm, 6px); -} - /* Inline column feedback (capacity-exhausted promote, deterministic drag * rejection) — rendered in-column, not a toast (R17 / promote spec). */ .column-inline-feedback { @@ -195,14 +165,13 @@ } /* -FNXC:BoardNavigation 2026-07-24-10:05: -Phone tier keeps proximity snapping (paired with the JS column pager in useColumnScrollSnap) so a -swipe still rests on exactly one column center. Mirrors the mobile `.board` block in styles.css and -matches the mobile viewport query (max-width: 768px, max-height: 480px). +FNXC:BoardNavigation 2026-08-18-19:29: +The selected-workflow and All-workflows Board paths share this live workflow-column scroller. +Keep desktop free-panning and phone proximity snapping here; retired lane compatibility styling is +not part of the current Board or plugin surface. */ @media (max-width: 768px), (max-height: 480px) { - .board.board-workflow-columns, - .lane-columns { + .board.board-workflow-columns { scroll-snap-type: x proximity; } }