From eca4447dcfe765bee8171eea056da5626b06b337 Mon Sep 17 00:00:00 2001 From: Ajay Ghanwat Date: Mon, 24 Aug 2026 22:50:41 +0530 Subject: [PATCH] fix(ui): stabilize catalog mega menu interaction --- bun.lock | 2 +- docs/ui-visual-contract-0.8.json | 2 +- packages/ui/components/MegaMenu.wrn | 56 ++++++++++++++++------------- packages/ui/package.json | 2 +- packages/ui/test/ui.test.ts | 4 ++- 5 files changed, 38 insertions(+), 28 deletions(-) diff --git a/bun.lock b/bun.lock index 4a90caf1..4448c828 100644 --- a/bun.lock +++ b/bun.lock @@ -688,7 +688,7 @@ }, "packages/ui": { "name": "@wrnexus/ui", - "version": "0.8.35", + "version": "0.8.36", "dependencies": { "@wrnexus/core": "workspace:*", }, diff --git a/docs/ui-visual-contract-0.8.json b/docs/ui-visual-contract-0.8.json index fdd29a7e..b2b6c879 100644 --- a/docs/ui-visual-contract-0.8.json +++ b/docs/ui-visual-contract-0.8.json @@ -55,7 +55,7 @@ "packages/ui/components/Map.wrn": "3e6d5de5a21dd050c5c65950d6fb2f89af4024e1856a48f055b65b88fcd7b890", "packages/ui/components/MarketingSectionHeader.wrn": "39b79499b77dc1c7d34e4e5ecb45a9ddc6182f78c2a2586671c4fa07f44679ad", "packages/ui/components/Marquee.wrn": "81cd80732be34c8d7e4bf28b00347e1a9273166afdf66589d9f5d5774b69403b", - "packages/ui/components/MegaMenu.wrn": "61869ce38dffdd0bb6ccef8da95143a528eccfcfa29718ca6afc2bfccb2fe642", + "packages/ui/components/MegaMenu.wrn": "c0bcd0613dba0237b211c4d0f2beb26616e4e1468715ad60965a31922860fcce", "packages/ui/components/MetricCard.wrn": "513a6e99be3d9db46d96af9942b51331a0a048b184603e77e814506f0a52bdc5", "packages/ui/components/MetricGrid.wrn": "1fcebf51dcbe8520fe16bda904c1ef206c25c3900438d53877492c64ea21a1a5", "packages/ui/components/Modal.wrn": "7fa4b877772736f29f690e24d8742922b310397ef3083f0b78acb67a9f0d14b2", diff --git a/packages/ui/components/MegaMenu.wrn b/packages/ui/components/MegaMenu.wrn index abac5e2d..39d6c213 100644 --- a/packages/ui/components/MegaMenu.wrn +++ b/packages/ui/components/MegaMenu.wrn @@ -47,7 +47,6 @@ component MegaMenu { state visible = defaultOpen state closeTimer = null - state openTimer = null state selectedCategory = activeCategory functions { @@ -59,6 +58,23 @@ component MegaMenu { return column && Array.isArray(column.items) ? column.items : [] } + shared function itemIcon(item) { + if (item && item.icon) { + return item.icon + } + return variant === "catalog" ? "icon-[lucide--component]" : "" + } + + shared function itemDescription(item, column) { + if (item && item.description) { + return item.description + } + if (variant === "catalog" && item && item.label) { + return "Open " + item.label + (column && column.heading ? " in " + column.heading : "") + } + return "" + } + shared function railList() { return Array.isArray(rail) ? rail : [] } @@ -93,14 +109,12 @@ component MegaMenu { } client function showPanel(sourceEvent) { - cancelScheduledOpen() cancelScheduledHide() visible = true output.open({ sourceEvent: sourceEvent }) } client function hidePanel(reason) { - cancelScheduledOpen() cancelScheduledHide() visible = false output.close({ reason: reason }) @@ -113,22 +127,6 @@ component MegaMenu { } } - client function cancelScheduledOpen() { - if (openTimer) { - window.clearTimeout(openTimer) - openTimer = null - } - } - - client function scheduleOpen(sourceEvent) { - cancelScheduledOpen() - cancelScheduledHide() - openTimer = window.setTimeout(function () { - openTimer = null - showPanel(sourceEvent) - }, 140) - } - client function scheduleHide() { cancelScheduledHide() closeTimer = window.setTimeout(function () { @@ -155,13 +153,22 @@ component MegaMenu { client function hoverPanel(sourceEvent) { if (openOnHover) { - scheduleOpen(sourceEvent) + showPanel(sourceEvent) } } - client function chooseCategory(item, index) { + client function chooseCategory(item, index, sourceEvent) { + const root = sourceEvent.currentTarget.closest(".wrn-mega") + const rail = sourceEvent.currentTarget.closest(".wrn-mega__rail") + const scrollTop = rail ? rail.scrollTop : 0 selectedCategory = categoryValue(item) output.category({ item: item, value: selectedCategory, index: index }) + window.requestAnimationFrame(function () { + const nextRail = root ? root.querySelector(".wrn-mega__rail") : null + if (nextRail) { + nextRail.scrollTop = scrollTop + } + }) } client function handleKeydown(sourceEvent) { @@ -215,6 +222,7 @@ component MegaMenu { class="wrn-mega__panel" data-wrn-anchored="true" data-show="visible" + style='{visible ? "" : "display:none"}' data-wrn-roving="both" @mouseenter='cancelScheduledHide()' > @@ -223,7 +231,7 @@ component MegaMenu {