fix(ui): stabilize catalog mega menu interaction
This commit is contained in:
@@ -688,7 +688,7 @@
|
|||||||
},
|
},
|
||||||
"packages/ui": {
|
"packages/ui": {
|
||||||
"name": "@wrnexus/ui",
|
"name": "@wrnexus/ui",
|
||||||
"version": "0.8.35",
|
"version": "0.8.36",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/core": "workspace:*",
|
"@wrnexus/core": "workspace:*",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
"packages/ui/components/Map.wrn": "3e6d5de5a21dd050c5c65950d6fb2f89af4024e1856a48f055b65b88fcd7b890",
|
"packages/ui/components/Map.wrn": "3e6d5de5a21dd050c5c65950d6fb2f89af4024e1856a48f055b65b88fcd7b890",
|
||||||
"packages/ui/components/MarketingSectionHeader.wrn": "39b79499b77dc1c7d34e4e5ecb45a9ddc6182f78c2a2586671c4fa07f44679ad",
|
"packages/ui/components/MarketingSectionHeader.wrn": "39b79499b77dc1c7d34e4e5ecb45a9ddc6182f78c2a2586671c4fa07f44679ad",
|
||||||
"packages/ui/components/Marquee.wrn": "81cd80732be34c8d7e4bf28b00347e1a9273166afdf66589d9f5d5774b69403b",
|
"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/MetricCard.wrn": "513a6e99be3d9db46d96af9942b51331a0a048b184603e77e814506f0a52bdc5",
|
||||||
"packages/ui/components/MetricGrid.wrn": "1fcebf51dcbe8520fe16bda904c1ef206c25c3900438d53877492c64ea21a1a5",
|
"packages/ui/components/MetricGrid.wrn": "1fcebf51dcbe8520fe16bda904c1ef206c25c3900438d53877492c64ea21a1a5",
|
||||||
"packages/ui/components/Modal.wrn": "7fa4b877772736f29f690e24d8742922b310397ef3083f0b78acb67a9f0d14b2",
|
"packages/ui/components/Modal.wrn": "7fa4b877772736f29f690e24d8742922b310397ef3083f0b78acb67a9f0d14b2",
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ component MegaMenu {
|
|||||||
|
|
||||||
state visible = defaultOpen
|
state visible = defaultOpen
|
||||||
state closeTimer = null
|
state closeTimer = null
|
||||||
state openTimer = null
|
|
||||||
state selectedCategory = activeCategory
|
state selectedCategory = activeCategory
|
||||||
|
|
||||||
functions {
|
functions {
|
||||||
@@ -59,6 +58,23 @@ component MegaMenu {
|
|||||||
return column && Array.isArray(column.items) ? column.items : []
|
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() {
|
shared function railList() {
|
||||||
return Array.isArray(rail) ? rail : []
|
return Array.isArray(rail) ? rail : []
|
||||||
}
|
}
|
||||||
@@ -93,14 +109,12 @@ component MegaMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
client function showPanel(sourceEvent) {
|
client function showPanel(sourceEvent) {
|
||||||
cancelScheduledOpen()
|
|
||||||
cancelScheduledHide()
|
cancelScheduledHide()
|
||||||
visible = true
|
visible = true
|
||||||
output.open({ sourceEvent: sourceEvent })
|
output.open({ sourceEvent: sourceEvent })
|
||||||
}
|
}
|
||||||
|
|
||||||
client function hidePanel(reason) {
|
client function hidePanel(reason) {
|
||||||
cancelScheduledOpen()
|
|
||||||
cancelScheduledHide()
|
cancelScheduledHide()
|
||||||
visible = false
|
visible = false
|
||||||
output.close({ reason: reason })
|
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() {
|
client function scheduleHide() {
|
||||||
cancelScheduledHide()
|
cancelScheduledHide()
|
||||||
closeTimer = window.setTimeout(function () {
|
closeTimer = window.setTimeout(function () {
|
||||||
@@ -155,13 +153,22 @@ component MegaMenu {
|
|||||||
|
|
||||||
client function hoverPanel(sourceEvent) {
|
client function hoverPanel(sourceEvent) {
|
||||||
if (openOnHover) {
|
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)
|
selectedCategory = categoryValue(item)
|
||||||
output.category({ item: item, value: selectedCategory, index: index })
|
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) {
|
client function handleKeydown(sourceEvent) {
|
||||||
@@ -215,6 +222,7 @@ component MegaMenu {
|
|||||||
class="wrn-mega__panel"
|
class="wrn-mega__panel"
|
||||||
data-wrn-anchored="true"
|
data-wrn-anchored="true"
|
||||||
data-show="visible"
|
data-show="visible"
|
||||||
|
style='{visible ? "" : "display:none"}'
|
||||||
data-wrn-roving="both"
|
data-wrn-roving="both"
|
||||||
@mouseenter='cancelScheduledHide()'
|
@mouseenter='cancelScheduledHide()'
|
||||||
>
|
>
|
||||||
@@ -223,7 +231,7 @@ component MegaMenu {
|
|||||||
<aside class="wrn-mega__rail">
|
<aside class="wrn-mega__rail">
|
||||||
{#each railList() as item, index}
|
{#each railList() as item, index}
|
||||||
{#if variant === "catalog"}
|
{#if variant === "catalog"}
|
||||||
<button type="button" class="wrn-mega__rail-link" data-active='{activeCategoryIndex() === index ? "true" : "false"}' aria-pressed='{activeCategoryIndex() === index ? "true" : "false"}' @click='chooseCategory(item, index)'>
|
<button type="button" class="wrn-mega__rail-link" data-active='{activeCategoryIndex() === index ? "true" : "false"}' aria-pressed='{activeCategoryIndex() === index ? "true" : "false"}' @click='chooseCategory(item, index, event)'>
|
||||||
{#if item.icon}<span class='wrn-mega__rail-icon {item.icon}' aria-hidden="true"></span>{/if}
|
{#if item.icon}<span class='wrn-mega__rail-icon {item.icon}' aria-hidden="true"></span>{/if}
|
||||||
<span><strong>{item.label}</strong>{#if item.description}<small>{item.description}</small>{/if}</span>
|
<span><strong>{item.label}</strong>{#if item.description}<small>{item.description}</small>{/if}</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -251,11 +259,11 @@ component MegaMenu {
|
|||||||
<li>
|
<li>
|
||||||
<a class="wrn-mega__link" href='{item.href || "#"}' data-wrn-roving-item="true" aria-disabled='{item.disabled ? "true" : "false"}' @click='choose(item)'>
|
<a class="wrn-mega__link" href='{item.href || "#"}' data-wrn-roving-item="true" aria-disabled='{item.disabled ? "true" : "false"}' @click='choose(item)'>
|
||||||
{#if item.image}<img class="wrn-mega__link-image" src='{item.image}' alt="" loading="lazy" />{/if}
|
{#if item.image}<img class="wrn-mega__link-image" src='{item.image}' alt="" loading="lazy" />{/if}
|
||||||
<span class='wrn-mega__link-icon {item.icon}' data-show="item.icon" aria-hidden="true"></span>
|
<span class='wrn-mega__link-icon {itemIcon(item)}' data-show="itemIcon(item)" aria-hidden="true"></span>
|
||||||
<span class="wrn-mega__link-body">
|
<span class="wrn-mega__link-body">
|
||||||
{#if item.eyebrow}<span class="wrn-mega__link-eyebrow">{item.eyebrow}</span>{/if}
|
{#if item.eyebrow}<span class="wrn-mega__link-eyebrow">{item.eyebrow}</span>{/if}
|
||||||
<span class="wrn-mega__link-label">{item.label}{#if item.badge}<span class="wrn-mega__badge">{item.badge}</span>{/if}</span>
|
<span class="wrn-mega__link-label">{item.label}{#if item.badge}<span class="wrn-mega__badge">{item.badge}</span>{/if}</span>
|
||||||
<span class="wrn-mega__link-description" data-show="item.description">{item.description}</span>
|
<span class="wrn-mega__link-description" data-show="itemDescription(item, column)">{itemDescription(item, column)}</span>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/ui",
|
"name": "@wrnexus/ui",
|
||||||
"version": "0.8.35",
|
"version": "0.8.36",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -3155,8 +3155,10 @@ test("mega menu keeps hover activation and click activation from cancelling each
|
|||||||
expect(source).toContain("openOnHover: boolean = true");
|
expect(source).toContain("openOnHover: boolean = true");
|
||||||
expect(source).toContain("@click='activatePanel(event)'");
|
expect(source).toContain("@click='activatePanel(event)'");
|
||||||
expect(source).toContain("@mouseenter='hoverPanel(event)'");
|
expect(source).toContain("@mouseenter='hoverPanel(event)'");
|
||||||
expect(source).toContain("}, 140)");
|
expect(source).toContain("showPanel(sourceEvent)");
|
||||||
|
expect(source).not.toContain("function scheduleOpen");
|
||||||
expect(source).toContain('.wrn-mega__panel[data-show="false"] { display: none; }');
|
expect(source).toContain('.wrn-mega__panel[data-show="false"] { display: none; }');
|
||||||
|
expect(source).toContain("style='{visible ? \"\" : \"display:none\"}'");
|
||||||
expect(source).not.toContain("@focus='showPanel(event)'");
|
expect(source).not.toContain("@focus='showPanel(event)'");
|
||||||
expect(source).toContain("max-height: calc(100dvh - 5.5rem)");
|
expect(source).toContain("max-height: calc(100dvh - 5.5rem)");
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user