@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.
Files changed (139) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/{accordion-nNH87Y60.js → accordion-CU2tJ5vn.js} +23 -9
  3. package/dist/{accordion-BB1JrONI.cjs → accordion-DDZkjXFb.cjs} +20 -7
  4. package/dist/{checkbox-nTbihMxW.cjs → checkbox-BerAYcfK.cjs} +1 -1
  5. package/dist/{checkbox-Bjp43NxA.js → checkbox-CF5mSBR5.js} +1 -1
  6. package/dist/{combobox-C4Q6kQEs.cjs → combobox-DYttdLJ4.cjs} +1 -1
  7. package/dist/{combobox-CL9BLuxt.js → combobox-DjvRMKOD.js} +3 -3
  8. package/dist/components/header-menu/header-menu.d.ts +41 -0
  9. package/dist/components/header-menu/header-menu.test.d.ts +0 -0
  10. package/dist/components/header-menu/index.d.ts +5 -0
  11. package/dist/components/header-menu/types.d.ts +6 -0
  12. package/dist/components/index.d.ts +4 -0
  13. package/dist/components/searchinput/index.d.ts +4 -0
  14. package/dist/components/searchinput/searchinput.d.ts +27 -0
  15. package/dist/components/searchinput/searchinput.test.d.ts +0 -0
  16. package/dist/{datepicker-DYd3JCs_.cjs → datepicker-D3QQbd_H.cjs} +1 -1
  17. package/dist/{datepicker-BUK1Qanw.js → datepicker-M_jcY3wp.js} +2 -2
  18. package/dist/docs/components/header-full.d.ts +13 -0
  19. package/dist/docs/components/header-menu.d.ts +8 -0
  20. package/dist/docs/components/searchinput.d.ts +14 -0
  21. package/dist/{fileupload-DjUAvBcP.cjs → fileupload-BD_0oMrW.cjs} +1 -1
  22. package/dist/{fileupload-DbmqRkz3.js → fileupload-F9UMO7eS.js} +3 -3
  23. package/dist/focus-modality-controller-BSZAQk8y.cjs +1 -0
  24. package/dist/focus-modality-controller-pzSZkDkH.js +29 -0
  25. package/dist/{header-Dps8o-ZY.cjs → header-DZranHLm.cjs} +2 -2
  26. package/dist/{header-T5O6sfCN.js → header-j0SSHF4C.js} +4 -3
  27. package/dist/header-menu-CPI1_5oZ.cjs +126 -0
  28. package/dist/header-menu-zhGYdnvz.js +319 -0
  29. package/dist/header-menu.d.ts +1 -0
  30. package/dist/{helptext-C5rG4VkA.js → helptext-BdqoW19r.js} +1 -1
  31. package/dist/{helptext-DQgStO4D.cjs → helptext-KWXjKljV.cjs} +1 -1
  32. package/dist/{input-element-CjebcQd1.js → input-element-B1ciW1N2.js} +1 -1
  33. package/dist/{input-element-FGcr5hGd.cjs → input-element-D0egtEnr.cjs} +1 -1
  34. package/dist/{input-wrapper-B_XFi211.cjs → input-wrapper-DOIWggEv.cjs} +1 -1
  35. package/dist/{input-wrapper-DBpMVSxt.js → input-wrapper-DVU68NcJ.js} +5 -29
  36. package/dist/{modal-B6591sWa.cjs → modal-C_LxgxzC.cjs} +1 -1
  37. package/dist/{modal-DyIC3uhs.js → modal-Ca7dETTw.js} +1 -1
  38. package/dist/pkt-accordion.cjs +1 -1
  39. package/dist/pkt-accordion.js +1 -1
  40. package/dist/pkt-checkbox.cjs +1 -1
  41. package/dist/pkt-checkbox.js +1 -1
  42. package/dist/pkt-combobox.cjs +1 -1
  43. package/dist/pkt-combobox.js +1 -1
  44. package/dist/pkt-consent.cjs +1 -1
  45. package/dist/pkt-consent.js +1 -1
  46. package/dist/pkt-datepicker.cjs +1 -1
  47. package/dist/pkt-datepicker.js +1 -1
  48. package/dist/pkt-fileupload.cjs +1 -1
  49. package/dist/pkt-fileupload.js +1 -1
  50. package/dist/pkt-header-menu.cjs +1 -0
  51. package/dist/pkt-header-menu.js +2 -0
  52. package/dist/pkt-header.cjs +1 -1
  53. package/dist/pkt-header.js +1 -1
  54. package/dist/pkt-helptext.cjs +1 -1
  55. package/dist/pkt-helptext.js +1 -1
  56. package/dist/pkt-index.cjs +1 -1
  57. package/dist/pkt-index.js +24 -22
  58. package/dist/pkt-input-wrapper.cjs +1 -1
  59. package/dist/pkt-input-wrapper.js +1 -1
  60. package/dist/pkt-link.cjs +1 -1
  61. package/dist/pkt-link.js +1 -1
  62. package/dist/pkt-linkcard.cjs +1 -1
  63. package/dist/pkt-linkcard.js +1 -1
  64. package/dist/pkt-loader.cjs +1 -1
  65. package/dist/pkt-loader.js +1 -1
  66. package/dist/pkt-messagebox.cjs +1 -1
  67. package/dist/pkt-messagebox.js +1 -1
  68. package/dist/pkt-modal.cjs +1 -1
  69. package/dist/pkt-modal.js +1 -1
  70. package/dist/pkt-progressbar.cjs +1 -1
  71. package/dist/pkt-progressbar.js +1 -1
  72. package/dist/pkt-radiobutton.cjs +1 -1
  73. package/dist/pkt-radiobutton.js +1 -1
  74. package/dist/pkt-searchinput.cjs +1 -0
  75. package/dist/pkt-searchinput.js +2 -0
  76. package/dist/pkt-select.cjs +1 -1
  77. package/dist/pkt-select.js +1 -1
  78. package/dist/pkt-tabs.cjs +1 -1
  79. package/dist/pkt-tabs.js +1 -1
  80. package/dist/pkt-textarea.cjs +1 -1
  81. package/dist/pkt-textarea.js +1 -1
  82. package/dist/pkt-textinput.cjs +1 -1
  83. package/dist/pkt-textinput.js +1 -1
  84. package/dist/pkt-timepicker.cjs +1 -1
  85. package/dist/pkt-timepicker.js +1 -1
  86. package/dist/{radiobutton-DvXr7tDk.cjs → radiobutton-B1Xg6XzP.cjs} +1 -1
  87. package/dist/{radiobutton-B-8-wWFf.js → radiobutton-BAn1V_mQ.js} +1 -1
  88. package/dist/searchinput-BVIaoetB.cjs +60 -0
  89. package/dist/searchinput-CIseS5tL.js +147 -0
  90. package/dist/searchinput.d.ts +1 -0
  91. package/dist/{select-D9B8Ighz.js → select-6XCVj1lP.js} +3 -3
  92. package/dist/{select-B75wzvyz.cjs → select-DO0xGhQQ.cjs} +1 -1
  93. package/dist/shared-types/header-menu.d.ts +108 -0
  94. package/dist/shared-types/index.d.ts +3 -0
  95. package/dist/shared-types/searchinput.d.ts +41 -0
  96. package/dist/shared-types/skin.d.ts +1 -1
  97. package/dist/shared-utils/header-menu/example-data.d.ts +11 -0
  98. package/dist/shared-utils/header-menu/fetch-header-footer-data.d.ts +12 -0
  99. package/dist/shared-utils/header-menu/icon-map.d.ts +34 -0
  100. package/dist/shared-utils/header-menu/index.d.ts +11 -0
  101. package/dist/shared-utils/header-menu/select-megamenu.d.ts +16 -0
  102. package/dist/tests/component-registry.d.ts +2 -0
  103. package/dist/{textarea-CjqprL6Y.cjs → textarea-CV6z3LDf.cjs} +1 -1
  104. package/dist/{textarea-CIWXMaAD.js → textarea-DBSNSvrX.js} +2 -2
  105. package/dist/{textinput-CxzAxM8E.js → textinput-BZZnFDk3.js} +2 -2
  106. package/dist/{textinput-B0VWmVIF.cjs → textinput-Dsc-8-BB.cjs} +1 -1
  107. package/dist/{timepicker-Cv9juQeB.cjs → timepicker-C2Ua6vHY.cjs} +1 -1
  108. package/dist/{timepicker-DXrpg5C7.js → timepicker-DDQ7CfOy.js} +2 -2
  109. package/package.json +2 -2
  110. package/src/components/accordion/accordionitem.ts +22 -5
  111. package/src/components/header/header-service.ts +1 -0
  112. package/src/components/header-menu/header-menu.test.ts +314 -0
  113. package/src/components/header-menu/header-menu.ts +401 -0
  114. package/src/components/header-menu/index.ts +6 -0
  115. package/src/components/header-menu/types.ts +31 -0
  116. package/src/components/index.ts +10 -0
  117. package/src/components/searchinput/index.ts +10 -0
  118. package/src/components/searchinput/searchinput.test.ts +312 -0
  119. package/src/components/searchinput/searchinput.ts +213 -0
  120. /package/dist/{consent-zh2npq2K.cjs → consent-B5dIDyLD.cjs} +0 -0
  121. /package/dist/{consent-f_IGyHss.js → consent-DSHrt9eS.js} +0 -0
  122. /package/dist/{dialog-polyfill.esm-BmVHGRTX.js → dialog-polyfill.esm-B7W3teD0.js} +0 -0
  123. /package/dist/{dialog-polyfill.esm-CXDsb3l-.cjs → dialog-polyfill.esm-BnAQvMQO.cjs} +0 -0
  124. /package/dist/{input-wrapper-CYCCx8MP.cjs → input-wrapper-CQGoyLdZ.cjs} +0 -0
  125. /package/dist/{input-wrapper-kw2y6Jp_.js → input-wrapper-DwSsP39J.js} +0 -0
  126. /package/dist/{link-B8zYc5WK.cjs → link-DMKjKawh.cjs} +0 -0
  127. /package/dist/{link-CjJcwcxR.js → link-F51Ho7CV.js} +0 -0
  128. /package/dist/{linkcard-C4x-NJMi.cjs → linkcard-CBmJbSoV.cjs} +0 -0
  129. /package/dist/{linkcard-Ddh5R_L-.js → linkcard-E07qJZMP.js} +0 -0
  130. /package/dist/{loader-CGQXAuyM.cjs → loader-q_eO6zaE.cjs} +0 -0
  131. /package/dist/{loader-DeizpX45.js → loader-teN65oWo.js} +0 -0
  132. /package/dist/{messagebox-DqoPqo4K.js → messagebox-Ct9lfe0Z.js} +0 -0
  133. /package/dist/{messagebox-Ccu29rDv.cjs → messagebox-D1QeQqb8.cjs} +0 -0
  134. /package/dist/{pkt-options-controller-DbLrdRwH.js → pkt-options-controller-CCB15L_G.js} +0 -0
  135. /package/dist/{pkt-options-controller-BPBb_O2K.cjs → pkt-options-controller-CeAQ-D-i.cjs} +0 -0
  136. /package/dist/{progressbar-CrwpnIkv.cjs → progressbar-Ca7pRjmt.cjs} +0 -0
  137. /package/dist/{progressbar-uC-0W6o4.js → progressbar-o-M17HPA.js} +0 -0
  138. /package/dist/{tabs-RnDtIFv3.cjs → tabs-CN_RIMWg.cjs} +0 -0
  139. /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,6 @@
1
+ import { PktHeaderMenu } from './header-menu'
2
+ import type { IPktHeaderMenu } from './types'
3
+
4
+ export { PktHeaderMenu }
5
+ export type { IPktHeaderMenu }
6
+ export default PktHeaderMenu
@@ -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
+ }
@@ -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