Skip to content

Commit

Permalink
[Navigation]: Add animations when changing between active nav items (#…
Browse files Browse the repository at this point in the history
…854)

* Add animations

* Cleanup

* Add fallback for when anchor positioning isn't supported (i.e. firefox)

* Fix example

* Get working with web components

* Make plain html example work

* Move fallback into the same place
  • Loading branch information
fallaciousreasoning authored Oct 18, 2024
1 parent 982b01f commit 481d25d
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 26 deletions.
10 changes: 9 additions & 1 deletion examples/plain-html/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@
const segmentedControlToggle = segmentedControlExample.querySelector('leo-toggle');
const segmentedControl = segmentedControlExample.querySelector('leo-segmentedcontrol');

for (const navItem of document.querySelectorAll('leo-navigationitem')) {
navItem.addEventListener('click', e => {
const href = navItem.getAttribute('href')
if (!href) return
window.location = new URL(href, window.location)
})
}

function updateSelectedOption(e) {
for (const radio of radios)
radio.currentValue = e.value
Expand Down Expand Up @@ -282,7 +290,7 @@ <h1 style="font: var(--leo-font-heading-h4); color: var(--leo-color-text-primary

<leo-navigationitem icon="discover" href="#explore">Explore</leo-navigationitem>

<leo-navigationitem icon="discover" href="#explore">
<leo-navigationitem icon="discover" href="#settings">
Settings

<leo-navigationmenu slot="subnav">
Expand Down
52 changes: 49 additions & 3 deletions src/components/navigation/navigation.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
export let kind: 'vertical' | 'horizontal' = 'vertical'
</script>

<div
class="leo-navigation kind-{kind}"
>
<div class="leo-navigation kind-{kind}">
{#if $$slots.header}
<slot name="header" />
{/if}
Expand All @@ -16,11 +14,59 @@
{#if $$slots.actions}
<slot name="actions" />
{/if}

<div class="active-indicator" />
</div>

<style lang="scss">
:host, .leo-navigation {
--anchor-padding: var(--leo-spacing-m);
position: relative;
}
:global(leo-navigation::before), .active-indicator {
@supports (anchor-name: --active-indicator) {
position-anchor: --active-indicator;
transition:
top 0.12s ease-in-out,
bottom 0.12s ease-in-out,
left 0.12s ease-in;
content: '';
width: 4px;
border-top-right-radius: var(--leo-radius-xs);
border-bottom-right-radius: var(--leo-radius-xs);
background: var(--leo-color-text-interactive);
position: absolute;
left: anchor(left);
top: calc(anchor(top) + var(--anchor-padding));
bottom: calc(anchor(bottom) + var(--anchor-padding));
z-index: 1;
}
}
// Fallback active indicator for when the browser doesn't support anchor positioning
@supports (not (anchor-name: --active-indicator)) {
:global(leo-navigation [data-selected=true]::before), .leo-navigation [data-selected=true]::before {
content: '';
width: 4px;
height: calc(100% - var(--anchor-padding) * 2);
border-top-right-radius: var(--leo-radius-xs);
border-bottom-right-radius: var(--leo-radius-xs);
background: var(--leo-color-text-interactive);
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
z-index: 1;
}
}
.leo-navigation {
--nav-direction: row;
--leo-icon-size: var(--leo-icon-s);
display: flex;
flex-direction: var(--nav-direction);
height: 100%;
Expand Down
65 changes: 43 additions & 22 deletions src/components/navigation/navigationItem.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,27 @@
export let onClick: () => void = undefined
let el: HTMLElement
const checkIfCurrent = () => {
isCurrent =
window.location.pathname === href || window.location.hash === href
}
$: tag = href ? 'a' : ('button' as 'a' | 'button')
// Handle updating data-selected attribute in web-components land -
// unfortunately we need to do this because changing isCurrent internally
// won't notify the webcomponent something has changed.
$: {
// Note: We read isCurrent & el here so the Svelte tracking works properly
const selected = isCurrent
const host = (el?.getRootNode() as ShadowRoot)?.host as HTMLElement
if (host) {
host.dataset.selected = selected.toString()
}
}
onMount(() => {
;['pushState', 'replaceState'].forEach((name) => {
const original = history[name]
Expand All @@ -72,14 +86,18 @@
<svelte:window on:popstate={checkIfCurrent} on:hashchange={checkIfCurrent} />

<!-- Note that this doesn't currently work properly in WC land due to the nested dynamic elements -->
<svelte:element this={outsideList ? 'div' : 'li'} class="leo-navigation-item">
<svelte:element
this={outsideList ? 'div' : 'li'}
bind:this={el}
class="leo-navigation-item"
data-selected={isCurrent}
>
<svelte:element
this={tag}
href={href || undefined}
disabled={isLoading || isDisabled || undefined}
on:click={onClick}
{...$$restProps}
class:isCurrent
>
<slot name="icon">
{#if icon}
Expand All @@ -95,10 +113,32 @@
</svelte:element>

<style lang="scss">
:global(leo-navigationitem[data-selected='true']),
.leo-navigation-item[data-selected='true'] {
anchor-name: --active-indicator;
}
:host {
position: relative;
}
.leo-navigation-item {
--nav-item-color: var(--leo-color-text-secondary);
--leo-icon-color: var(--leo-color-icon-default);
--leo-icon-size: var(--leo-icon-s);
position: relative;
// When this item is selected, set it as the active indicator
&[data-selected='true'] {
--nav-item-color: var(--leo-color-text-interactive);
--leo-icon-color: var(--leo-color-icon-interactive);
}
// If a parent is selected, change the nav item color to unselected
[data-selected='true'] & {
--nav-item-color: var(--leo-color-text-secondary);
--leo-icon-color: var(--leo-color-icon-default);
}
list-style: none;
Expand All @@ -116,7 +156,6 @@
padding-right: var(--leo-spacing-m);
border-radius: 0;
outline: none;
position: relative;
text-decoration: none;
font: var(--leo-font-components-navbutton);
Expand All @@ -129,24 +168,6 @@
&:focus-visible {
box-shadow: var(--leo-effect-focus-state);
}
&.isCurrent {
--nav-item-color: var(--leo-color-text-interactive);
--leo-icon-color: var(--leo-color-icon-interactive);
&::before {
content: '';
width: 4px;
height: 76%;
border-top-right-radius: var(--leo-radius-xs);
border-bottom-right-radius: var(--leo-radius-xs);
background: var(--leo-color-text-interactive);
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
}
}
}
}
</style>

0 comments on commit 481d25d

Please sign in to comment.