@oslokommune/punkt-elements 16.16.1 → 16.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/dist/{accordion-nNH87Y60.js → accordion-CU2tJ5vn.js} +23 -9
- package/dist/{accordion-BB1JrONI.cjs → accordion-DDZkjXFb.cjs} +20 -7
- package/dist/{checkbox-nTbihMxW.cjs → checkbox-BerAYcfK.cjs} +1 -1
- package/dist/{checkbox-Bjp43NxA.js → checkbox-CF5mSBR5.js} +1 -1
- package/dist/{combobox-C4Q6kQEs.cjs → combobox-DYttdLJ4.cjs} +1 -1
- package/dist/{combobox-CL9BLuxt.js → combobox-DjvRMKOD.js} +3 -3
- package/dist/components/header-menu/header-menu.d.ts +41 -0
- package/dist/components/header-menu/header-menu.test.d.ts +0 -0
- package/dist/components/header-menu/index.d.ts +5 -0
- package/dist/components/header-menu/types.d.ts +6 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/searchinput/index.d.ts +4 -0
- package/dist/components/searchinput/searchinput.d.ts +27 -0
- package/dist/components/searchinput/searchinput.test.d.ts +0 -0
- package/dist/{datepicker-DYd3JCs_.cjs → datepicker-D3QQbd_H.cjs} +1 -1
- package/dist/{datepicker-BUK1Qanw.js → datepicker-M_jcY3wp.js} +2 -2
- package/dist/docs/components/header-full.d.ts +13 -0
- package/dist/docs/components/header-menu.d.ts +8 -0
- package/dist/docs/components/searchinput.d.ts +14 -0
- package/dist/{fileupload-DjUAvBcP.cjs → fileupload-BD_0oMrW.cjs} +1 -1
- package/dist/{fileupload-DbmqRkz3.js → fileupload-F9UMO7eS.js} +3 -3
- package/dist/focus-modality-controller-BSZAQk8y.cjs +1 -0
- package/dist/focus-modality-controller-pzSZkDkH.js +29 -0
- package/dist/{header-Dps8o-ZY.cjs → header-DZranHLm.cjs} +2 -2
- package/dist/{header-T5O6sfCN.js → header-j0SSHF4C.js} +4 -3
- package/dist/header-menu-CPI1_5oZ.cjs +126 -0
- package/dist/header-menu-zhGYdnvz.js +319 -0
- package/dist/header-menu.d.ts +1 -0
- package/dist/{helptext-C5rG4VkA.js → helptext-BdqoW19r.js} +1 -1
- package/dist/{helptext-DQgStO4D.cjs → helptext-KWXjKljV.cjs} +1 -1
- package/dist/{input-element-CjebcQd1.js → input-element-B1ciW1N2.js} +1 -1
- package/dist/{input-element-FGcr5hGd.cjs → input-element-D0egtEnr.cjs} +1 -1
- package/dist/{input-wrapper-B_XFi211.cjs → input-wrapper-DOIWggEv.cjs} +1 -1
- package/dist/{input-wrapper-DBpMVSxt.js → input-wrapper-DVU68NcJ.js} +5 -29
- package/dist/{modal-B6591sWa.cjs → modal-C_LxgxzC.cjs} +1 -1
- package/dist/{modal-DyIC3uhs.js → modal-Ca7dETTw.js} +1 -1
- package/dist/pkt-accordion.cjs +1 -1
- package/dist/pkt-accordion.js +1 -1
- package/dist/pkt-checkbox.cjs +1 -1
- package/dist/pkt-checkbox.js +1 -1
- package/dist/pkt-combobox.cjs +1 -1
- package/dist/pkt-combobox.js +1 -1
- package/dist/pkt-consent.cjs +1 -1
- package/dist/pkt-consent.js +1 -1
- package/dist/pkt-datepicker.cjs +1 -1
- package/dist/pkt-datepicker.js +1 -1
- package/dist/pkt-fileupload.cjs +1 -1
- package/dist/pkt-fileupload.js +1 -1
- package/dist/pkt-header-menu.cjs +1 -0
- package/dist/pkt-header-menu.js +2 -0
- package/dist/pkt-header.cjs +1 -1
- package/dist/pkt-header.js +1 -1
- package/dist/pkt-helptext.cjs +1 -1
- package/dist/pkt-helptext.js +1 -1
- package/dist/pkt-index.cjs +1 -1
- package/dist/pkt-index.js +24 -22
- package/dist/pkt-input-wrapper.cjs +1 -1
- package/dist/pkt-input-wrapper.js +1 -1
- package/dist/pkt-link.cjs +1 -1
- package/dist/pkt-link.js +1 -1
- package/dist/pkt-linkcard.cjs +1 -1
- package/dist/pkt-linkcard.js +1 -1
- package/dist/pkt-loader.cjs +1 -1
- package/dist/pkt-loader.js +1 -1
- package/dist/pkt-messagebox.cjs +1 -1
- package/dist/pkt-messagebox.js +1 -1
- package/dist/pkt-modal.cjs +1 -1
- package/dist/pkt-modal.js +1 -1
- package/dist/pkt-progressbar.cjs +1 -1
- package/dist/pkt-progressbar.js +1 -1
- package/dist/pkt-radiobutton.cjs +1 -1
- package/dist/pkt-radiobutton.js +1 -1
- package/dist/pkt-searchinput.cjs +1 -0
- package/dist/pkt-searchinput.js +2 -0
- package/dist/pkt-select.cjs +1 -1
- package/dist/pkt-select.js +1 -1
- package/dist/pkt-tabs.cjs +1 -1
- package/dist/pkt-tabs.js +1 -1
- package/dist/pkt-textarea.cjs +1 -1
- package/dist/pkt-textarea.js +1 -1
- package/dist/pkt-textinput.cjs +1 -1
- package/dist/pkt-textinput.js +1 -1
- package/dist/pkt-timepicker.cjs +1 -1
- package/dist/pkt-timepicker.js +1 -1
- package/dist/{radiobutton-DvXr7tDk.cjs → radiobutton-B1Xg6XzP.cjs} +1 -1
- package/dist/{radiobutton-B-8-wWFf.js → radiobutton-BAn1V_mQ.js} +1 -1
- package/dist/searchinput-BVIaoetB.cjs +60 -0
- package/dist/searchinput-CIseS5tL.js +147 -0
- package/dist/searchinput.d.ts +1 -0
- package/dist/{select-D9B8Ighz.js → select-6XCVj1lP.js} +3 -3
- package/dist/{select-B75wzvyz.cjs → select-DO0xGhQQ.cjs} +1 -1
- package/dist/shared-types/header-menu.d.ts +108 -0
- package/dist/shared-types/index.d.ts +3 -0
- package/dist/shared-types/searchinput.d.ts +41 -0
- package/dist/shared-types/skin.d.ts +1 -1
- package/dist/shared-utils/header-menu/example-data.d.ts +11 -0
- package/dist/shared-utils/header-menu/fetch-header-footer-data.d.ts +12 -0
- package/dist/shared-utils/header-menu/icon-map.d.ts +34 -0
- package/dist/shared-utils/header-menu/index.d.ts +11 -0
- package/dist/shared-utils/header-menu/select-megamenu.d.ts +16 -0
- package/dist/tests/component-registry.d.ts +2 -0
- package/dist/{textarea-CjqprL6Y.cjs → textarea-CV6z3LDf.cjs} +1 -1
- package/dist/{textarea-CIWXMaAD.js → textarea-DBSNSvrX.js} +2 -2
- package/dist/{textinput-CxzAxM8E.js → textinput-BZZnFDk3.js} +2 -2
- package/dist/{textinput-B0VWmVIF.cjs → textinput-Dsc-8-BB.cjs} +1 -1
- package/dist/{timepicker-Cv9juQeB.cjs → timepicker-C2Ua6vHY.cjs} +1 -1
- package/dist/{timepicker-DXrpg5C7.js → timepicker-DDQ7CfOy.js} +2 -2
- package/package.json +2 -2
- package/src/components/accordion/accordionitem.ts +22 -5
- package/src/components/header/header-service.ts +1 -0
- package/src/components/header-menu/header-menu.test.ts +314 -0
- package/src/components/header-menu/header-menu.ts +401 -0
- package/src/components/header-menu/index.ts +6 -0
- package/src/components/header-menu/types.ts +31 -0
- package/src/components/index.ts +10 -0
- package/src/components/searchinput/index.ts +10 -0
- package/src/components/searchinput/searchinput.test.ts +312 -0
- package/src/components/searchinput/searchinput.ts +213 -0
- /package/dist/{consent-zh2npq2K.cjs → consent-B5dIDyLD.cjs} +0 -0
- /package/dist/{consent-f_IGyHss.js → consent-DSHrt9eS.js} +0 -0
- /package/dist/{dialog-polyfill.esm-BmVHGRTX.js → dialog-polyfill.esm-B7W3teD0.js} +0 -0
- /package/dist/{dialog-polyfill.esm-CXDsb3l-.cjs → dialog-polyfill.esm-BnAQvMQO.cjs} +0 -0
- /package/dist/{input-wrapper-CYCCx8MP.cjs → input-wrapper-CQGoyLdZ.cjs} +0 -0
- /package/dist/{input-wrapper-kw2y6Jp_.js → input-wrapper-DwSsP39J.js} +0 -0
- /package/dist/{link-B8zYc5WK.cjs → link-DMKjKawh.cjs} +0 -0
- /package/dist/{link-CjJcwcxR.js → link-F51Ho7CV.js} +0 -0
- /package/dist/{linkcard-C4x-NJMi.cjs → linkcard-CBmJbSoV.cjs} +0 -0
- /package/dist/{linkcard-Ddh5R_L-.js → linkcard-E07qJZMP.js} +0 -0
- /package/dist/{loader-CGQXAuyM.cjs → loader-q_eO6zaE.cjs} +0 -0
- /package/dist/{loader-DeizpX45.js → loader-teN65oWo.js} +0 -0
- /package/dist/{messagebox-DqoPqo4K.js → messagebox-Ct9lfe0Z.js} +0 -0
- /package/dist/{messagebox-Ccu29rDv.cjs → messagebox-D1QeQqb8.cjs} +0 -0
- /package/dist/{pkt-options-controller-DbLrdRwH.js → pkt-options-controller-CCB15L_G.js} +0 -0
- /package/dist/{pkt-options-controller-BPBb_O2K.cjs → pkt-options-controller-CeAQ-D-i.cjs} +0 -0
- /package/dist/{progressbar-CrwpnIkv.cjs → progressbar-Ca7pRjmt.cjs} +0 -0
- /package/dist/{progressbar-uC-0W6o4.js → progressbar-o-M17HPA.js} +0 -0
- /package/dist/{tabs-RnDtIFv3.cjs → tabs-CN_RIMWg.cjs} +0 -0
- /package/dist/{tabs-4eWA7CsK.js → tabs-ClI1XQDt.js} +0 -0
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
import { PktElement } from '@/base-elements/element'
|
|
2
|
+
import { html, nothing, type PropertyValues, type TemplateResult } from 'lit'
|
|
3
|
+
import { customElement, property, state } from 'lit/decorators.js'
|
|
4
|
+
import { classMap } from 'lit/directives/class-map.js'
|
|
5
|
+
import { booleanishConverter, type Booleanish } from 'shared-types'
|
|
6
|
+
import {
|
|
7
|
+
DEFAULT_HEADER_FOOTER_URL,
|
|
8
|
+
deriveSocialIcon,
|
|
9
|
+
fetchHeaderFooterData,
|
|
10
|
+
mapOdsIcon,
|
|
11
|
+
selectLocaleData,
|
|
12
|
+
} from 'shared-utils/header-menu'
|
|
13
|
+
import type {
|
|
14
|
+
IHeaderFooterLocaleData,
|
|
15
|
+
IHeaderMenuButton,
|
|
16
|
+
IHeaderMenuLink,
|
|
17
|
+
IHeaderMenuSection,
|
|
18
|
+
IHeaderMenuServices,
|
|
19
|
+
IPktHeaderMenu,
|
|
20
|
+
THeaderFooterApi,
|
|
21
|
+
THeaderMenuLocale,
|
|
22
|
+
} from './types'
|
|
23
|
+
|
|
24
|
+
import '@/components/accordion'
|
|
25
|
+
import '@/components/icon'
|
|
26
|
+
|
|
27
|
+
type LoadState = 'idle' | 'loading' | 'ready' | 'error'
|
|
28
|
+
|
|
29
|
+
export class PktHeaderMenu extends PktElement<IPktHeaderMenu> implements IPktHeaderMenu {
|
|
30
|
+
@property({ type: String, attribute: 'data-url' })
|
|
31
|
+
dataUrl: string = DEFAULT_HEADER_FOOTER_URL
|
|
32
|
+
|
|
33
|
+
@property({ type: Object, attribute: false })
|
|
34
|
+
data?: THeaderFooterApi
|
|
35
|
+
|
|
36
|
+
@property({ type: String })
|
|
37
|
+
locale: THeaderMenuLocale = 'nb-NO'
|
|
38
|
+
|
|
39
|
+
@property({ type: Boolean, reflect: true, converter: booleanishConverter })
|
|
40
|
+
open: Booleanish = false
|
|
41
|
+
|
|
42
|
+
@property({ type: String, attribute: 'aria-labelledby', reflect: true })
|
|
43
|
+
ariaLabelledBy: string = ''
|
|
44
|
+
|
|
45
|
+
@property({ type: Number, attribute: 'mobile-breakpoint' })
|
|
46
|
+
mobileBreakpoint: number = 768
|
|
47
|
+
|
|
48
|
+
@state() private loadState: LoadState = 'idle'
|
|
49
|
+
@state() private fetchedData?: THeaderFooterApi
|
|
50
|
+
@state() private isMobile = false
|
|
51
|
+
|
|
52
|
+
private abortController?: AbortController
|
|
53
|
+
private mediaQuery?: MediaQueryList
|
|
54
|
+
|
|
55
|
+
override connectedCallback(): void {
|
|
56
|
+
super.connectedCallback()
|
|
57
|
+
this.classList.add('pkt-header-menu')
|
|
58
|
+
this.updateOpenClass()
|
|
59
|
+
this.setupMediaQuery()
|
|
60
|
+
if (!this.data) {
|
|
61
|
+
void this.loadData()
|
|
62
|
+
} else {
|
|
63
|
+
this.loadState = 'ready'
|
|
64
|
+
this.dispatchEvent(
|
|
65
|
+
new CustomEvent('data-loaded', {
|
|
66
|
+
detail: { data: this.data },
|
|
67
|
+
bubbles: true,
|
|
68
|
+
composed: true,
|
|
69
|
+
}),
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private updateOpenClass() {
|
|
75
|
+
this.classList.toggle('pkt-header-menu--open', Boolean(this.open))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
override disconnectedCallback(): void {
|
|
79
|
+
super.disconnectedCallback()
|
|
80
|
+
this.abortController?.abort()
|
|
81
|
+
this.teardownMediaQuery()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
override updated(changedProperties: PropertyValues): void {
|
|
85
|
+
super.updated(changedProperties)
|
|
86
|
+
|
|
87
|
+
if (changedProperties.has('open')) {
|
|
88
|
+
this.updateOpenClass()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (
|
|
92
|
+
changedProperties.has('mobileBreakpoint') &&
|
|
93
|
+
changedProperties.get('mobileBreakpoint') !== undefined
|
|
94
|
+
) {
|
|
95
|
+
this.setupMediaQuery()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Re-fetch only when dataUrl genuinely changes after first load.
|
|
99
|
+
// The initial fetch is kicked off from connectedCallback, so we
|
|
100
|
+
// skip the noop "field default" change that fires on first update.
|
|
101
|
+
if (
|
|
102
|
+
changedProperties.has('dataUrl') &&
|
|
103
|
+
changedProperties.get('dataUrl') !== undefined &&
|
|
104
|
+
!this.data
|
|
105
|
+
) {
|
|
106
|
+
void this.loadData()
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (changedProperties.has('data') && changedProperties.get('data') !== undefined && this.data) {
|
|
110
|
+
this.loadState = 'ready'
|
|
111
|
+
this.dispatchEvent(
|
|
112
|
+
new CustomEvent('data-loaded', {
|
|
113
|
+
detail: { data: this.data },
|
|
114
|
+
bubbles: true,
|
|
115
|
+
composed: true,
|
|
116
|
+
}),
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private setupMediaQuery() {
|
|
122
|
+
this.teardownMediaQuery()
|
|
123
|
+
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return
|
|
124
|
+
this.mediaQuery = window.matchMedia(`(max-width: ${this.mobileBreakpoint - 1}px)`)
|
|
125
|
+
this.isMobile = this.mediaQuery.matches
|
|
126
|
+
this.mediaQuery.addEventListener('change', this.handleMediaChange)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private teardownMediaQuery() {
|
|
130
|
+
this.mediaQuery?.removeEventListener('change', this.handleMediaChange)
|
|
131
|
+
this.mediaQuery = undefined
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private handleMediaChange = (event: MediaQueryListEvent) => {
|
|
135
|
+
this.isMobile = event.matches
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private async loadData() {
|
|
139
|
+
this.abortController?.abort()
|
|
140
|
+
this.abortController = new AbortController()
|
|
141
|
+
this.loadState = 'loading'
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
const data = await fetchHeaderFooterData<string>(this.dataUrl, this.abortController.signal)
|
|
145
|
+
this.fetchedData = data
|
|
146
|
+
this.loadState = 'ready'
|
|
147
|
+
this.dispatchEvent(
|
|
148
|
+
new CustomEvent('data-loaded', {
|
|
149
|
+
detail: { data },
|
|
150
|
+
bubbles: true,
|
|
151
|
+
composed: true,
|
|
152
|
+
}),
|
|
153
|
+
)
|
|
154
|
+
} catch (error) {
|
|
155
|
+
if ((error as Error).name === 'AbortError') return
|
|
156
|
+
this.loadState = 'error'
|
|
157
|
+
this.dispatchEvent(
|
|
158
|
+
new CustomEvent('data-error', {
|
|
159
|
+
detail: { error },
|
|
160
|
+
bubbles: true,
|
|
161
|
+
composed: true,
|
|
162
|
+
}),
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private get effectiveData(): THeaderFooterApi | undefined {
|
|
168
|
+
return this.data ?? this.fetchedData
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private get localeData(): IHeaderFooterLocaleData | undefined {
|
|
172
|
+
return selectLocaleData(this.effectiveData, this.locale)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
render() {
|
|
176
|
+
if (this.loadState === 'loading') {
|
|
177
|
+
return html`
|
|
178
|
+
<nav aria-busy="true">
|
|
179
|
+
<p class="pkt-header-menu__loading">Laster meny…</p>
|
|
180
|
+
</nav>
|
|
181
|
+
`
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (this.loadState === 'error' || !this.localeData) {
|
|
185
|
+
return html`
|
|
186
|
+
<nav aria-hidden=${!this.open}>
|
|
187
|
+
<p class="pkt-header-menu__error">Kunne ikke laste meny.</p>
|
|
188
|
+
</nav>
|
|
189
|
+
`
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const { megamenu, i18n } = this.localeData
|
|
193
|
+
const navAriaLabel = i18n?.navAriaLabel || 'Hovedmeny'
|
|
194
|
+
|
|
195
|
+
if (this.isMobile) {
|
|
196
|
+
return html`
|
|
197
|
+
<nav aria-label=${navAriaLabel}>
|
|
198
|
+
${this.renderMobileAccordion(megamenu.services, megamenu.sections)}
|
|
199
|
+
${this.renderButtons(megamenu.buttons, true)}
|
|
200
|
+
${this.renderFooter(megamenu.links, megamenu.some)}
|
|
201
|
+
</nav>
|
|
202
|
+
`
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return html`
|
|
206
|
+
<nav aria-label=${navAriaLabel}>
|
|
207
|
+
${this.renderServices(megamenu.services)} ${this.renderButtons(megamenu.buttons, false)}
|
|
208
|
+
${this.renderSections(megamenu.sections)}
|
|
209
|
+
${this.renderFooter(megamenu.links, megamenu.some)}
|
|
210
|
+
</nav>
|
|
211
|
+
`
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private renderMobileAccordion(
|
|
215
|
+
services: IHeaderMenuServices,
|
|
216
|
+
sections: IHeaderMenuSection[],
|
|
217
|
+
): TemplateResult {
|
|
218
|
+
return html`
|
|
219
|
+
<div class="pkt-header-menu__sections">
|
|
220
|
+
<pkt-accordion
|
|
221
|
+
class="pkt-header-menu__sections-inner"
|
|
222
|
+
skin="plus-minus"
|
|
223
|
+
name="header-menu-accordion"
|
|
224
|
+
>
|
|
225
|
+
<pkt-accordion-item
|
|
226
|
+
class="pkt-header-menu__section"
|
|
227
|
+
skin="plus-minus"
|
|
228
|
+
id="pkt-header-menu-services"
|
|
229
|
+
title=${services.title}
|
|
230
|
+
>
|
|
231
|
+
${this.renderServicesList(services)}
|
|
232
|
+
</pkt-accordion-item>
|
|
233
|
+
${sections.map(
|
|
234
|
+
(section, index) => html`
|
|
235
|
+
<pkt-accordion-item
|
|
236
|
+
class="pkt-header-menu__section"
|
|
237
|
+
skin="plus-minus"
|
|
238
|
+
id=${`pkt-header-menu-section-${index}`}
|
|
239
|
+
title=${section.title}
|
|
240
|
+
>
|
|
241
|
+
${this.renderSectionList(section.links)}
|
|
242
|
+
</pkt-accordion-item>
|
|
243
|
+
`,
|
|
244
|
+
)}
|
|
245
|
+
</pkt-accordion>
|
|
246
|
+
</div>
|
|
247
|
+
`
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
private renderServicesList(services: IHeaderMenuServices): TemplateResult {
|
|
251
|
+
return html`
|
|
252
|
+
<ul class="pkt-header-menu__services-list">
|
|
253
|
+
${services.links.map(
|
|
254
|
+
(link) => html`
|
|
255
|
+
<li class="pkt-header-menu__service">
|
|
256
|
+
<a class="pkt-header-menu__service-link" href=${link.url}>
|
|
257
|
+
<pkt-icon
|
|
258
|
+
class="pkt-header-menu__service-icon"
|
|
259
|
+
name=${mapOdsIcon(link.icon)}
|
|
260
|
+
aria-hidden="true"
|
|
261
|
+
></pkt-icon>
|
|
262
|
+
<span class="pkt-header-menu__service-text">${link.text}</span>
|
|
263
|
+
</a>
|
|
264
|
+
</li>
|
|
265
|
+
`,
|
|
266
|
+
)}
|
|
267
|
+
</ul>
|
|
268
|
+
`
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
private renderServices(services: IHeaderMenuServices): TemplateResult {
|
|
272
|
+
return html`
|
|
273
|
+
<div class="pkt-header-menu__services">
|
|
274
|
+
<h2 class="pkt-header-menu__services-title">${services.title}</h2>
|
|
275
|
+
${this.renderServicesList(services)}
|
|
276
|
+
</div>
|
|
277
|
+
`
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
private renderButtons(
|
|
281
|
+
buttons: IHeaderMenuButton[] | undefined,
|
|
282
|
+
isMobilePlacement: boolean,
|
|
283
|
+
): TemplateResult | typeof nothing {
|
|
284
|
+
if (!buttons || buttons.length === 0) return nothing
|
|
285
|
+
|
|
286
|
+
const classes = classMap({
|
|
287
|
+
'pkt-header-menu__buttons': true,
|
|
288
|
+
'pkt-header-menu__buttons--mobile': isMobilePlacement,
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
return html`
|
|
292
|
+
<div class=${classes}>
|
|
293
|
+
${buttons.map(
|
|
294
|
+
(button) => html`
|
|
295
|
+
<a
|
|
296
|
+
class="pkt-btn pkt-btn--secondary pkt-btn--icon-right pkt-btn--small"
|
|
297
|
+
href=${button.url}
|
|
298
|
+
>
|
|
299
|
+
<pkt-icon
|
|
300
|
+
class="pkt-btn__icon"
|
|
301
|
+
name=${button.iconName ? mapOdsIcon(button.iconName) : 'user'}
|
|
302
|
+
aria-hidden="true"
|
|
303
|
+
></pkt-icon>
|
|
304
|
+
<span class="pkt-btn__text">${button.text}</span>
|
|
305
|
+
</a>
|
|
306
|
+
`,
|
|
307
|
+
)}
|
|
308
|
+
</div>
|
|
309
|
+
`
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
private renderSections(sections: IHeaderMenuSection[]): TemplateResult | typeof nothing {
|
|
313
|
+
if (!sections || sections.length === 0) return nothing
|
|
314
|
+
|
|
315
|
+
return html`
|
|
316
|
+
<div class="pkt-header-menu__sections">
|
|
317
|
+
<div class="pkt-header-menu__sections-inner">
|
|
318
|
+
${sections.map(
|
|
319
|
+
(section) => html`
|
|
320
|
+
<div class="pkt-header-menu__section">
|
|
321
|
+
<h2 class="pkt-header-menu__section-title">${section.title}</h2>
|
|
322
|
+
${this.renderSectionList(section.links)}
|
|
323
|
+
</div>
|
|
324
|
+
`,
|
|
325
|
+
)}
|
|
326
|
+
</div>
|
|
327
|
+
</div>
|
|
328
|
+
`
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
private renderSectionList(links: IHeaderMenuLink[]): TemplateResult {
|
|
332
|
+
return html`
|
|
333
|
+
<ul class="pkt-header-menu__section-list">
|
|
334
|
+
${links.map(
|
|
335
|
+
(link) => html`
|
|
336
|
+
<li>
|
|
337
|
+
<a class="pkt-header-menu__section-link" href=${link.url}>${link.text}</a>
|
|
338
|
+
</li>
|
|
339
|
+
`,
|
|
340
|
+
)}
|
|
341
|
+
</ul>
|
|
342
|
+
`
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
private renderFooter(
|
|
346
|
+
links: IHeaderMenuLink[],
|
|
347
|
+
some: IHeaderMenuLink[],
|
|
348
|
+
): TemplateResult | typeof nothing {
|
|
349
|
+
if ((!links || links.length === 0) && (!some || some.length === 0)) return nothing
|
|
350
|
+
|
|
351
|
+
return html`
|
|
352
|
+
<div class="pkt-header-menu__footer">
|
|
353
|
+
${links && links.length > 0
|
|
354
|
+
? html`
|
|
355
|
+
<ul class="pkt-header-menu__footer-list">
|
|
356
|
+
${links.map(
|
|
357
|
+
(link) => html`
|
|
358
|
+
<li>
|
|
359
|
+
<a class="pkt-header-menu__footer-link" href=${link.url}>${link.text}</a>
|
|
360
|
+
</li>
|
|
361
|
+
`,
|
|
362
|
+
)}
|
|
363
|
+
</ul>
|
|
364
|
+
`
|
|
365
|
+
: nothing}
|
|
366
|
+
${some && some.length > 0
|
|
367
|
+
? html`
|
|
368
|
+
<ul class="pkt-header-menu__footer-list pkt-header-menu__footer-list--social">
|
|
369
|
+
${some.map((entry) => this.renderSocialLink(entry))}
|
|
370
|
+
</ul>
|
|
371
|
+
`
|
|
372
|
+
: nothing}
|
|
373
|
+
</div>
|
|
374
|
+
`
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
private renderSocialLink(entry: IHeaderMenuLink): TemplateResult {
|
|
378
|
+
const iconName = deriveSocialIcon(entry.url, entry.text)
|
|
379
|
+
return html`
|
|
380
|
+
<li>
|
|
381
|
+
<a class="pkt-header-menu__social-link" href=${entry.url} aria-label=${entry.text}>
|
|
382
|
+
${iconName
|
|
383
|
+
? html`<pkt-icon name=${iconName} aria-hidden="true"></pkt-icon>`
|
|
384
|
+
: html`<span>${entry.text}</span>`}
|
|
385
|
+
</a>
|
|
386
|
+
</li>
|
|
387
|
+
`
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
declare global {
|
|
392
|
+
interface HTMLElementTagNameMap {
|
|
393
|
+
'pkt-header-menu': PktHeaderMenu
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
try {
|
|
398
|
+
customElement('pkt-header-menu')(PktHeaderMenu)
|
|
399
|
+
} catch (e) {
|
|
400
|
+
console.warn('Forsøker å definere <pkt-header-menu>, men den er allerede definert')
|
|
401
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
IHeaderMenuLink,
|
|
3
|
+
IHeaderMenuIconLink,
|
|
4
|
+
IHeaderMenuButton,
|
|
5
|
+
IHeaderMenuServices,
|
|
6
|
+
IHeaderMenuSection,
|
|
7
|
+
IMegaMenu,
|
|
8
|
+
IHeaderFooter,
|
|
9
|
+
IHeaderFooterLocaleData,
|
|
10
|
+
IPktHeaderMenu as ISharedPktHeaderMenu,
|
|
11
|
+
THeaderFooterApi,
|
|
12
|
+
THeaderMenuLocale,
|
|
13
|
+
} from 'shared-types/header-menu'
|
|
14
|
+
import type { Booleanish } from 'shared-types'
|
|
15
|
+
|
|
16
|
+
export type {
|
|
17
|
+
IHeaderMenuLink,
|
|
18
|
+
IHeaderMenuIconLink,
|
|
19
|
+
IHeaderMenuButton,
|
|
20
|
+
IHeaderMenuServices,
|
|
21
|
+
IHeaderMenuSection,
|
|
22
|
+
IMegaMenu,
|
|
23
|
+
IHeaderFooter,
|
|
24
|
+
IHeaderFooterLocaleData,
|
|
25
|
+
THeaderFooterApi,
|
|
26
|
+
THeaderMenuLocale,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface IPktHeaderMenu extends Omit<ISharedPktHeaderMenu, 'open'> {
|
|
30
|
+
open?: Booleanish
|
|
31
|
+
}
|
package/src/components/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ export { PktFileUpload } from '@/components/fileupload'
|
|
|
13
13
|
export { PktDateTags } from '@/components/datepicker/date-tags.js'
|
|
14
14
|
export { PktDatepicker } from '@/components/datepicker/datepicker.js'
|
|
15
15
|
export { PktHeader, PktHeaderService, PktHeaderUserMenu } from '@/components/header'
|
|
16
|
+
export { PktHeaderMenu } from '@/components/header-menu'
|
|
16
17
|
export { PktHelptext } from '@/components/helptext'
|
|
17
18
|
export { PktHeading } from '@/components/heading'
|
|
18
19
|
export { PktIcon } from '@/components/icon'
|
|
@@ -31,6 +32,7 @@ export { PktTabs, PktTabItem } from '@/components/tabs'
|
|
|
31
32
|
export { PktTextarea } from '@/components/textarea'
|
|
32
33
|
export { PktTextinput } from '@/components/textinput'
|
|
33
34
|
export { PktSelect } from '@/components/select'
|
|
35
|
+
export { PktSearchInput } from '@/components/searchinput'
|
|
34
36
|
export { PktTimepicker } from '@/components/timepicker'
|
|
35
37
|
|
|
36
38
|
// Export component types
|
|
@@ -59,6 +61,8 @@ export type {
|
|
|
59
61
|
IPktHeader,
|
|
60
62
|
} from '@/components/header'
|
|
61
63
|
|
|
64
|
+
export type { IPktHeaderMenu } from '@/components/header-menu'
|
|
65
|
+
|
|
62
66
|
export type {
|
|
63
67
|
IPktProgressbar,
|
|
64
68
|
TProgressbarRole,
|
|
@@ -106,3 +110,9 @@ export type {
|
|
|
106
110
|
} from '@/components/fileupload'
|
|
107
111
|
|
|
108
112
|
export type { IPktTimepicker } from '@/components/timepicker'
|
|
113
|
+
export type {
|
|
114
|
+
IPktSearchInput,
|
|
115
|
+
IPktSearchInputSuggestion,
|
|
116
|
+
TPktSearchInputAppearance,
|
|
117
|
+
TPktSearchInputMethod,
|
|
118
|
+
} from '@/components/searchinput'
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { PktSearchInput } from './searchinput'
|
|
2
|
+
|
|
3
|
+
export { PktSearchInput } from './searchinput'
|
|
4
|
+
export type {
|
|
5
|
+
IPktSearchInput,
|
|
6
|
+
IPktSearchInputSuggestion,
|
|
7
|
+
TPktSearchInputAppearance,
|
|
8
|
+
TPktSearchInputMethod,
|
|
9
|
+
} from 'shared-types/searchinput'
|
|
10
|
+
export default PktSearchInput
|