import { PktElementWithSlot } from '@/base-elements/element-with-slot' import { slotContent } from '@/directives/slot-content' import { html, nothing, PropertyValues } from 'lit' import { customElement, property } from 'lit/decorators.js' import { ifDefined } from 'lit/directives/if-defined.js' import { User, Representing, UserMenuItem, THeaderMenu, TLogOutButtonPlacement, THeaderPosition, THeaderScrollBehavior, TSlotMenuVariant, THeaderType, THeaderFooterApi, THeaderMenuLocale, IPktHeader, Booleanish, booleanishConverter, } from './types' import './header-service' import './header-global' /** * PktHeader - Main header component for Oslo kommune services * * This component provides a complete header solution with: * - Logo and service name * - User menu with login/logout functionality * - Search functionality * - Responsive mobile menu * - Fixed positioning with scroll-to-hide * * The `type` prop switches between the `service` header (a customizable * header for a single service, the default) and the `global` * (kommune-wide) header driven by the shared header/footer payload. */ export class PktHeader extends PktElementWithSlot implements IPktHeader { @property({ type: String }) type: THeaderType = 'service' @property({ type: String, attribute: 'service-name' }) serviceName?: string @property({ type: String, attribute: 'service-link' }) serviceLink?: string @property({ type: String, attribute: 'logo-link' }) logoLink?: string @property({ type: String, attribute: 'logo-path' }) logoPath?: string @property({ type: String, attribute: 'search-placeholder' }) searchPlaceholder = 'Søk' @property({ type: String, attribute: 'search-value' }) searchValue = '' @property({ type: Number, attribute: 'mobile-breakpoint' }) mobileBreakpoint: number = 768 @property({ type: Number, attribute: 'tablet-breakpoint' }) tabletBreakpoint: number = 1280 @property({ type: String, attribute: 'opened-menu' }) openedMenu: THeaderMenu = 'none' @property({ type: String, attribute: 'log-out-button-placement' }) logOutButtonPlacement: TLogOutButtonPlacement = 'none' @property({ type: String }) position: THeaderPosition = 'fixed' @property({ type: String, attribute: 'scroll-behavior' }) scrollBehavior: THeaderScrollBehavior = 'hide' @property({ type: String, attribute: 'slot-menu-variant' }) slotMenuVariant: TSlotMenuVariant = 'icon-only' @property({ type: String, attribute: 'slot-menu-text' }) slotMenuText = 'Meny' @property({ type: Boolean, attribute: 'hide-logo', converter: booleanishConverter }) hideLogo: Booleanish = false @property({ type: Boolean, converter: booleanishConverter }) compact: Booleanish = false @property({ type: Boolean, attribute: 'show-search', converter: booleanishConverter }) showSearch?: Booleanish @property({ type: Boolean, attribute: 'can-change-representation', converter: booleanishConverter, }) canChangeRepresentation: Booleanish = false @property({ type: Boolean, attribute: 'has-log-out', converter: booleanishConverter }) hasLogOut: Booleanish = false @property({ type: Object }) user?: User @property({ type: Array, attribute: 'user-menu' }) userMenu?: UserMenuItem[] @property({ type: Object }) representing?: Representing // Global header props (type="global") @property({ type: String, attribute: 'data-url' }) dataUrl?: string @property({ type: Object, attribute: false }) data?: THeaderFooterApi @property({ type: String }) locale?: THeaderMenuLocale @property({ type: Boolean, attribute: 'show-contact', converter: booleanishConverter }) showContact: Booleanish = true // Deprecated props - emit warnings @property({ type: Array, attribute: 'user-menu-footer' }) userMenuFooter?: UserMenuItem[] @property({ type: Array, attribute: 'user-options' }) userOptions?: UserMenuItem[] firstUpdated(changedProperties: PropertyValues) { super.firstUpdated(changedProperties) this.emitDeprecationWarnings() } private emitDeprecationWarnings() { if (this.userMenuFooter !== undefined) { console.warn('[PktHeader] userMenuFooter is deprecated. Use userMenu instead.') } if (this.userOptions !== undefined) { console.warn('[PktHeader] userOptions is deprecated. Use userMenu instead.') } } /** * Convert deprecated props to new props */ private get effectiveUserMenu(): UserMenuItem[] | undefined { const menu = this.userMenu || [] const footer = this.userMenuFooter || [] const options = this.userOptions || [] if (footer.length || options.length) { return [...menu, ...options, ...footer] } return this.userMenu } private renderGlobal() { return html` ` } render() { if (this.type === 'global') { return this.renderGlobal() } return html` ${this.hasSlotContent() ? html`
${slotContent(this)}
` : nothing}
` } } declare global { interface HTMLElementTagNameMap { 'pkt-header': PktHeader } } try { customElement('pkt-header')(PktHeader) } catch (e) { console.warn('Forsøker å definere , men den er allerede definert') }