import { PktElementWithSlot } from '@/base-elements/element-with-slot' import { classMap } from 'lit/directives/class-map.js' import { customElement, property, state } from 'lit/decorators.js' import { html, nothing } from 'lit' import { slotContent } from '@/directives/slot-content' import { TPktSize } from '@/types/size' import '@/components/icon' const defaultAnimationPath = 'https://punkt-cdn.oslo.kommune.no/latest/animations/' // Allow global override of animation assets path if (typeof window !== 'undefined') { window.pktAnimationPath = window.pktAnimationPath || defaultAnimationPath } export type TPktLoaderVariant = 'blue' | 'rainbow' | 'shapes' export interface IPktLoader { /** * The `delay` prop controls how much time the loading should be given before the loader is displayed. * This is handy for situations where the load time might be so short that loader is not necessary. * Delay time is in milliseconds. */ delay?: number /** * The `inline` prop decides whether the loader should be displayed inline or not. */ inline?: boolean /** * The boolean 'isLoading' decides whether the loader or the children will be displayed. * If set to false, the children will be displayed. */ isLoading?: boolean /** * The message to display when the loader is loading. */ message?: string | null /** * The size of the loader. Default is "medium". */ size?: TPktSize /** * The variant of the loader. Default is "shapes" which is the OSLO wave loader. * Other variants are "blue" and "rainbow" which are spinner variants. */ variant?: TPktLoaderVariant /** * Override path to loading animations. */ loadingAnimationPath?: string } export class PktLoader extends PktElementWithSlot implements IPktLoader { @property({ type: Number }) delay: number = 0 @property({ type: Boolean }) inline: boolean = false @property({ type: Boolean }) isLoading: boolean = true @property({ type: String }) message: string | null = null @property({ type: String }) size: TPktSize = 'medium' @property({ type: String }) variant: TPktLoaderVariant = 'shapes' @property({ type: String }) loadingAnimationPath: string | undefined = typeof window !== 'undefined' ? window.pktAnimationPath : defaultAnimationPath @state() private _shouldDisplayLoader: boolean = false connectedCallback() { super.connectedCallback() this._shouldDisplayLoader = this.delay === 0 if (this.delay > 0) { this.setupLoader() } } updated(changedProperties: Map) { if (changedProperties.has('delay')) { this.setupLoader() } } render() { const classes = classMap({ 'pkt-loader': true, [`pkt-loader--${this.inline ? 'inline' : 'box'}`]: true, [`pkt-loader--${this.size}`]: true, }) const slotClasses = classMap({ 'pkt-contents': true, 'pkt-hide': this.isLoading, }) return html`
${this.isLoading && this._shouldDisplayLoader ? html`
${this.message && html`

${this.message}

`}
` : nothing}
${slotContent(this)}
` } private getVariant(variant: TPktLoaderVariant): string { switch (variant) { case 'blue': return 'spinner-blue' case 'rainbow': return 'spinner' default: return 'loader' } } private setupLoader() { if (this.delay > 0) { this._shouldDisplayLoader = false setTimeout(() => { this._shouldDisplayLoader = true this.requestUpdate() }, this.delay) } } } export default PktLoader try { customElement('pkt-loader')(PktLoader) } catch (e) { console.warn('Forsøker å definere , men den er allerede definert') }