Last active
January 26, 2024 22:46
-
-
Save andyjessop/8568b6a85e24deea15f98fabddc0e8c4 to your computer and use it in GitHub Desktop.
Link custom element to handle route changes in thepassle/app-tools router
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { RouterLink } from './RouterLink'; | |
// After router is setup... | |
RouterLink.setRouter(() => router); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { css, html, LitElement } from 'lit'; | |
import { customElement, property, state } from 'lit/decorators.js'; | |
import { RouteEvent, Router } from './Router'; | |
@customElement('router-link') | |
export class RouterLink extends LitElement { | |
static router: Router | null = null; | |
@property({ type: String }) to = ''; | |
static styles = [ | |
css` | |
a { | |
cursor: pointer; | |
} | |
`, | |
]; | |
static setRouter(fn: () => Router) { | |
RouterLink.router = fn(); | |
} | |
@state() private isActive = false; | |
constructor() { | |
super(); | |
if (!RouterLink.router) { | |
console.error( | |
'Router is not set for RouterLink. Please use RouterLink.setRouter().', | |
); | |
} | |
this.boundHandleRouteChange = this.handleRouteChange.bind(this); | |
} | |
connectedCallback() { | |
super.connectedCallback(); | |
if (!RouterLink.router) { | |
return; | |
} | |
RouterLink.router.addEventListener( | |
'route-changed', | |
this.boundHandleRouteChange, | |
); | |
this.updateActiveState(RouterLink.router.context.url.pathname); | |
} | |
disconnectedCallback() { | |
super.disconnectedCallback(); | |
RouterLink.router?.removeEventListener( | |
'route-changed', | |
this.boundHandleRouteChange, | |
); | |
} | |
handleRouteChange(event: Event) { | |
this.updateActiveState((event as RouteEvent).context.url.pathname); | |
} | |
updateActiveState = (currentPath: string) => { | |
this.isActive = currentPath === this.to; | |
}; | |
render() { | |
const part = this.isActive ? 'link active' : 'link'; | |
return html`<a href="${this.to}" part=${part} @click="${this.handleClick}" | |
><slot></slot | |
></a>`; | |
} | |
handleClick(event: Event) { | |
event.preventDefault(); | |
if (RouterLink.router?.navigate && this.to) { | |
RouterLink.router?.navigate(this.to); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { css, html, LitElement } from 'lit'; | |
import { customElement, property } from 'lit/decorators.js'; | |
import { Item } from './types'; | |
@customElement('my-links') | |
export class Links extends LitElement { | |
@property({ type: Array }) | |
items: Item[] = []; | |
static styles = [ | |
css` | |
cx-link::part(link):hover { | |
background-color: var(--color-gray-100); | |
} | |
cx-link::part(link active) { | |
background-color: var(--color-primary-500); | |
color: white; | |
} | |
cx-link::part(link active):hover { | |
background-color: var(--color-primary-500); | |
cursor: default; | |
} | |
`, | |
]; | |
render() { | |
return html` | |
<ul> | |
${this.items.map( | |
(item) => html` | |
<li> | |
<cx-link to="${item.path}">${item.title}</cx-link> | |
</li> | |
`, | |
)} | |
</ul> | |
`; | |
} | |
} |
Amazing, thank you!
I've updated the gist and tested locally, and it looks good 👍
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Not that you asked for a review, but these lines actually introduce a memory leak and can cause the page the navigation handlers to fire many times:
https://gist.github.com/andyjessop/8568b6a85e24deea15f98fabddc0e8c4#file-routerlink-ts-L54-L57
https://gist.github.com/andyjessop/8568b6a85e24deea15f98fabddc0e8c4#file-routerlink-ts-L43-L46
The
.bind()
creates a new function everytime, so it will never have a stable reference to dedupe new listeners, or be able to remove listeners.The "easy" fix is something like this: