@oslokommune/punkt-elements
Version:
Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo
221 lines (202 loc) • 6.78 kB
text/typescript
import { PktElement } from '@/base-elements/element'
import { html, nothing } from 'lit'
import { customElement, property } from 'lit/decorators.js'
import { classMap } from 'lit/directives/class-map.js'
import {
User,
Representing,
UserMenuItem,
TInternalMenuItem,
convertUserMenuItem,
Booleanish,
booleanishConverter,
} from './types'
import '@/components/icon'
import '@/components/link'
export interface IPktHeaderUserMenu {
user: User
formattedLastLoggedIn?: string
representing?: Representing
userMenu?: UserMenuItem[]
canChangeRepresentation?: Booleanish
logoutOnClick?: Booleanish
}
export class PktHeaderUserMenu
extends PktElement<IPktHeaderUserMenu>
implements IPktHeaderUserMenu
{
({ type: Object }) user!: User
({ type: String, attribute: 'formatted-last-logged-in' }) formattedLastLoggedIn?: string
({ type: Object }) representing?: Representing
({ type: Array, attribute: 'user-menu' }) userMenu?: UserMenuItem[]
({
type: Boolean,
attribute: 'can-change-representation',
converter: booleanishConverter,
})
canChangeRepresentation: Booleanish = false
({ type: Boolean, attribute: 'logout-on-click', converter: booleanishConverter })
logoutOnClick: Booleanish = false
private handleChangeRepresentation() {
this.dispatchEvent(
new CustomEvent('change-representation', {
bubbles: true,
composed: true,
}),
)
}
private handleLogout() {
this.dispatchEvent(
new CustomEvent('log-out', {
bubbles: true,
composed: true,
}),
)
}
private handleMenuItemClick(item: TInternalMenuItem) {
if ('onClick' in item && typeof item.onClick === 'function') {
item.onClick()
}
}
private renderLinkOrButton(item: TInternalMenuItem, className?: string) {
const isLink = 'href' in item
const classes = classMap({
'pkt-user-menu__link': true,
'pkt-link-button': !isLink,
'pkt-link': !isLink,
'pkt-link--icon-left': !isLink,
[className || '']: !!className,
})
if (isLink) {
return html`
<pkt-link
icon-name=${item.iconName || nothing}
href=${item.href}
aria-hidden="true"
class="pkt-user-menu__link ${className || ''}"
>
${item.title}
</pkt-link>
`
}
return html`
<button class=${classes} type="button" @click=${() => this.handleMenuItemClick(item)}>
${item.iconName
? html`<pkt-icon
name=${item.iconName}
class="pkt-link__icon"
aria-hidden="true"
></pkt-icon>`
: nothing}
${item.title}
</button>
`
}
private renderLinkSection(links: TInternalMenuItem[]) {
return html`
<ul class="pkt-user-menu__sublist">
${links.map(
(item) => html`
<li class="pkt-user-menu__subitem">${this.renderLinkOrButton(item)}</li>
`,
)}
</ul>
`
}
render() {
const internalMenuItems = this.userMenu?.map(convertUserMenuItem)
return html`
<nav class="pkt-user-menu" aria-label="Meny for innlogget bruker">
<ul class="pkt-user-menu__list">
<!-- User section -->
${this.user
? html`
<li class="pkt-user-menu__item">
<div class="pkt-user-menu__label">Pålogget som</div>
<div class="pkt-user-menu__name" translate="no">${this.user.name}</div>
${this.formattedLastLoggedIn
? html`
<div class="pkt-user-menu__last-logged-in">
Sist pålogget: <time>${this.formattedLastLoggedIn}</time>
</div>
`
: nothing}
</li>
`
: nothing}
<!-- User menu items -->
${internalMenuItems && internalMenuItems.length > 0
? html`
<li class="pkt-user-menu__item">${this.renderLinkSection(internalMenuItems)}</li>
`
: nothing}
<!-- Representing section -->
${this.representing
? html`
<li class="pkt-user-menu__item">
<div class="pkt-user-menu__label">Representerer</div>
<div class="pkt-user-menu__name" translate="no">${this.representing.name}</div>
${this.representing.orgNumber
? html`<div class="pkt-user-menu__org-number">
Org.nr. ${this.representing.orgNumber}
</div>`
: nothing}
${this.canChangeRepresentation
? html`
<ul class="pkt-user-menu__sublist mt-size-16">
<li class="pkt-user-menu__subitem">
${this.renderLinkOrButton({
title: 'Endre organisasjon',
iconName: 'cogwheel',
onClick: () => this.handleChangeRepresentation(),
})}
</li>
</ul>
`
: nothing}
</li>
`
: nothing}
<!-- Change representation without representing object -->
${!this.representing && this.canChangeRepresentation
? html`
<li class="pkt-user-menu__item">
<ul class="pkt-user-menu__sublist">
<li class="pkt-user-menu__subitem">
${this.renderLinkOrButton({
title: 'Endre organisasjon',
iconName: 'cogwheel',
onClick: () => this.handleChangeRepresentation(),
})}
</li>
</ul>
</li>
`
: nothing}
<!-- Logout -->
${this.logoutOnClick
? html`
<li class="pkt-user-menu__item">
${this.renderLinkOrButton({
title: 'Logg ut',
iconName: 'exit',
onClick: () => this.handleLogout(),
})}
</li>
`
: nothing}
</ul>
</nav>
`
}
}
declare global {
interface HTMLElementTagNameMap {
'pkt-header-user-menu': PktHeaderUserMenu
}
}
try {
customElement('pkt-header-user-menu')(PktHeaderUserMenu)
} catch (e) {
console.warn('Forsøker å definere <pkt-header-user-menu>, men den er allerede definert')
}