@oslokommune/punkt-elements 17.1.3 → 18.1.0

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 (280) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/{accordion-BeLvLPrB.js → accordion-CcUosZjL.js} +27 -27
  3. package/dist/{accordion-B3GBlvUC.cjs → accordion-k0pWTG1X.cjs} +5 -5
  4. package/dist/alert-BD8YVKia.cjs +35 -0
  5. package/dist/{alert-DKK_Tb9J.js → alert-Bmaly2Yo.js} +57 -52
  6. package/dist/{async-directive-BPf6K-V2.js → async-directive-COqx0IYj.js} +5 -5
  7. package/dist/{async-directive-Da7TJpnq.cjs → async-directive-DN2eg9gA.cjs} +1 -1
  8. package/dist/{backlink-D1y26pj3.js → backlink-C_ZO-ZbR.js} +9 -9
  9. package/dist/{backlink-CMmrKTe4.cjs → backlink-Ch64Pivx.cjs} +3 -3
  10. package/dist/base-elements/element.d.ts +13 -1
  11. package/dist/base-elements/input-element.d.ts +4 -2
  12. package/dist/{breadcrumbs-CcTQ3Grm.js → breadcrumbs-CF_gAbUk.js} +16 -16
  13. package/dist/{breadcrumbs-B6JGhJgC.cjs → breadcrumbs-CzzbardP.cjs} +7 -7
  14. package/dist/{button-2-OSPJkj.js → button-C1CQSASU.js} +28 -28
  15. package/dist/{button-CE97NQIk.cjs → button-CF3dNKeI.cjs} +7 -7
  16. package/dist/{calendar-kn4SrtJy.cjs → calendar-BxF81kB9.cjs} +28 -27
  17. package/dist/{calendar-pOW3R5Pw.js → calendar-DRmxORMc.js} +82 -68
  18. package/dist/{card-CETDFkxR.cjs → card-Cg1daj05.cjs} +26 -26
  19. package/dist/{card-zQ0eKRMV.js → card-W_Jb0Tlo.js} +44 -44
  20. package/dist/{checkbox-CQNr_sEg.cjs → checkbox-BHQv8lHq.cjs} +11 -11
  21. package/dist/{checkbox-CH7NpINF.js → checkbox-BQw2dMSX.js} +23 -23
  22. package/dist/{class-map-BeimMvPv.cjs → class-map-C33ixq7O.cjs} +1 -1
  23. package/dist/{class-map-CnWCnBSX.js → class-map-wh4Yi3oj.js} +3 -3
  24. package/dist/{combobox-Bvg0UO9w.cjs → combobox-BpZow9OU.cjs} +19 -18
  25. package/dist/{combobox-CRdYYlxu.js → combobox-C9wwnUfM.js} +55 -54
  26. package/dist/components/accordion/accordion.d.ts +2 -6
  27. package/dist/components/accordion/accordionitem.d.ts +2 -8
  28. package/dist/components/alert/alert.d.ts +2 -2
  29. package/dist/components/backlink/backlink.d.ts +4 -5
  30. package/dist/components/backlink/backlink.test.d.ts +1 -1
  31. package/dist/components/breadcrumbs/breadcrumbs.d.ts +6 -7
  32. package/dist/components/breadcrumbs/index.d.ts +1 -1
  33. package/dist/components/calendar/calendar.d.ts +21 -6
  34. package/dist/components/checkbox/checkbox.d.ts +4 -2
  35. package/dist/components/combobox/combobox-base.d.ts +2 -1
  36. package/dist/components/consent/strings.d.ts +1 -85
  37. package/dist/components/datepicker/datepicker-base.d.ts +0 -3
  38. package/dist/components/datepicker/datepicker-multiple.d.ts +0 -2
  39. package/dist/components/datepicker/datepicker-range.d.ts +0 -2
  40. package/dist/components/datepicker/datepicker-single.d.ts +0 -2
  41. package/dist/components/datepicker/datepicker-utils.d.ts +2 -1
  42. package/dist/components/fileupload/fileupload-base.d.ts +7 -4
  43. package/dist/components/fileupload/fileupload-types.d.ts +5 -43
  44. package/dist/components/header/header-service.d.ts +3 -1
  45. package/dist/components/header/header.d.ts +2 -1
  46. package/dist/components/helptext/helptext.d.ts +2 -1
  47. package/dist/components/index.d.ts +3 -1
  48. package/dist/components/input-wrapper/input-wrapper.d.ts +4 -2
  49. package/dist/components/radiobutton/radiobutton.d.ts +4 -2
  50. package/dist/components/searchinput/searchinput.d.ts +2 -1
  51. package/dist/{consent-CyY3RyoC.cjs → consent-CPtr7cBw.cjs} +5 -5
  52. package/dist/{consent-DZEkhgJ1.js → consent-D8MrqGKk.js} +10 -10
  53. package/dist/controllers/strings-controller.d.ts +27 -0
  54. package/dist/{datepicker-ButIas85.js → datepicker-D4YnAtWG.js} +104 -104
  55. package/dist/{datepicker-VTqSDQk5.cjs → datepicker-DaoumZT9.cjs} +38 -37
  56. package/dist/define-component-spec-BYOSeplU.js +6 -0
  57. package/dist/define-component-spec-DBNd2FJY.cjs +1 -0
  58. package/dist/{directive-helpers-CI8YZqku.js → directive-helpers-BWSAVe00.js} +1 -1
  59. package/dist/{directive-helpers-BlAV5EQD.cjs → directive-helpers-C6J4AkFk.cjs} +1 -1
  60. package/dist/docs/components/alert.d.ts +2 -3
  61. package/dist/docs/components/fileupload.d.ts +1 -0
  62. package/dist/element-DiFhBcIl.cjs +2 -0
  63. package/dist/{element-ChsFgr_B.js → element-WEzISABa.js} +241 -100
  64. package/dist/{element-with-slot-BvG9ctC-.js → element-with-slot-BKYUx4gb.js} +4 -4
  65. package/dist/{element-with-slot-Bj7nm7fO.cjs → element-with-slot-CBK4zrdN.cjs} +1 -1
  66. package/dist/{fileupload-D5IQ9HDe.js → fileupload-DEHSETw0.js} +340 -652
  67. package/dist/fileupload-DWu6FIMv.cjs +402 -0
  68. package/dist/{footer-DrR64HiK.js → footer-BJLEw6Ab.js} +91 -91
  69. package/dist/{footer-DbYQUYNR.cjs → footer-D_yYWkQ6.cjs} +32 -32
  70. package/dist/format-B8meU8Tm.cjs +1 -0
  71. package/dist/format-BTeSVkED.js +18 -0
  72. package/dist/{header-ClgIac6n.cjs → header-B7_4Cwaq.cjs} +84 -84
  73. package/dist/{header-KvJ1mGwA.js → header-DLVq7-dM.js} +267 -264
  74. package/dist/{header-menu-hVPXsb8g.js → header-menu-BsrrTjpT.js} +75 -75
  75. package/dist/{header-menu-BAsUNKSx.cjs → header-menu-m7nOOC1g.cjs} +24 -24
  76. package/dist/{heading-g-_IUB5T.js → heading-DSArgrDK.js} +16 -16
  77. package/dist/{heading-CFmiSuCQ.cjs → heading-_RPw2UW9.cjs} +1 -1
  78. package/dist/helptext-QMVsW5g6.cjs +27 -0
  79. package/dist/{helptext-DZng1D5i.js → helptext-dtVVufNH.js} +18 -19
  80. package/dist/{icon-D-LA22xD.js → icon-DEtOSWRK.js} +17 -17
  81. package/dist/{icon-9iwd2F2l.cjs → icon-DIavy2cB.cjs} +1 -1
  82. package/dist/{if-defined-CGzIlZ9-.js → if-defined-BmnvvxtR.js} +1 -1
  83. package/dist/if-defined-Dc3xFDaM.cjs +1 -0
  84. package/dist/input-element-DQY1Rpbp.cjs +1 -0
  85. package/dist/{input-element-DBMNBplu.js → input-element-IBypGOaV.js} +121 -120
  86. package/dist/input-wrapper-CQgAL1Br.js +308 -0
  87. package/dist/input-wrapper-mJZLVXy_.cjs +58 -0
  88. package/dist/link-DwLeY37f.js +131 -0
  89. package/dist/link-yk4IXDWm.cjs +7 -0
  90. package/dist/linkcard-BinKnxQF.cjs +13 -0
  91. package/dist/{linkcard-zqbg7Oqm.js → linkcard-D5DXpmXI.js} +16 -16
  92. package/dist/{listbox-Dc4rGdPi.cjs → listbox-C5zTRNAO.cjs} +15 -15
  93. package/dist/{listbox-va_E8afs.js → listbox-C8ooO8qZ.js} +100 -99
  94. package/dist/{loader-D_RDICnw.js → loader-C3HyayzL.js} +14 -14
  95. package/dist/{loader-CMUkVJmE.cjs → loader-DHF7M5Vn.cjs} +5 -5
  96. package/dist/{messagebox-Cv8LaSxv.cjs → messagebox-DqYf6VmQ.cjs} +5 -5
  97. package/dist/{messagebox-Cw-OWDya.js → messagebox-u8i3R5QA.js} +15 -15
  98. package/dist/{modal-BtInv031.cjs → modal-CnJ9y2TQ.cjs} +8 -8
  99. package/dist/{modal-D0t_X2dX.js → modal-V-jEe0aY.js} +20 -20
  100. package/dist/pkt-accordion.cjs +1 -1
  101. package/dist/pkt-accordion.js +1 -1
  102. package/dist/pkt-alert.cjs +1 -1
  103. package/dist/pkt-alert.js +1 -1
  104. package/dist/pkt-backlink.cjs +1 -1
  105. package/dist/pkt-backlink.js +1 -1
  106. package/dist/pkt-breadcrumbs.cjs +1 -1
  107. package/dist/pkt-breadcrumbs.js +1 -1
  108. package/dist/pkt-button.cjs +1 -1
  109. package/dist/pkt-button.js +1 -1
  110. package/dist/pkt-calendar.cjs +1 -1
  111. package/dist/pkt-calendar.js +1 -1
  112. package/dist/pkt-card.cjs +1 -1
  113. package/dist/pkt-card.js +1 -1
  114. package/dist/pkt-checkbox.cjs +1 -1
  115. package/dist/pkt-checkbox.js +1 -1
  116. package/dist/pkt-combobox.cjs +1 -1
  117. package/dist/pkt-combobox.js +1 -1
  118. package/dist/pkt-consent.cjs +1 -1
  119. package/dist/pkt-consent.js +1 -1
  120. package/dist/pkt-datepicker.cjs +1 -1
  121. package/dist/pkt-datepicker.js +1 -1
  122. package/dist/pkt-fileupload.cjs +1 -1
  123. package/dist/pkt-fileupload.js +1 -1
  124. package/dist/pkt-footer.cjs +1 -1
  125. package/dist/pkt-footer.js +1 -1
  126. package/dist/pkt-header-menu.cjs +1 -1
  127. package/dist/pkt-header-menu.js +1 -1
  128. package/dist/pkt-header.cjs +1 -1
  129. package/dist/pkt-header.js +1 -1
  130. package/dist/pkt-heading.cjs +1 -1
  131. package/dist/pkt-heading.js +1 -1
  132. package/dist/pkt-helptext.cjs +1 -1
  133. package/dist/pkt-helptext.js +1 -1
  134. package/dist/pkt-icon.cjs +1 -1
  135. package/dist/pkt-icon.js +1 -1
  136. package/dist/pkt-index.cjs +1 -1
  137. package/dist/pkt-index.js +35 -34
  138. package/dist/pkt-input-wrapper.cjs +1 -1
  139. package/dist/pkt-input-wrapper.js +1 -1
  140. package/dist/pkt-link.cjs +1 -1
  141. package/dist/pkt-link.js +1 -1
  142. package/dist/pkt-linkcard.cjs +1 -1
  143. package/dist/pkt-linkcard.js +1 -1
  144. package/dist/pkt-listbox.cjs +1 -1
  145. package/dist/pkt-listbox.js +1 -1
  146. package/dist/pkt-loader.cjs +1 -1
  147. package/dist/pkt-loader.js +1 -1
  148. package/dist/pkt-messagebox.cjs +1 -1
  149. package/dist/pkt-messagebox.js +1 -1
  150. package/dist/pkt-modal.cjs +1 -1
  151. package/dist/pkt-modal.js +1 -1
  152. package/dist/{pkt-options-controller-C5EBX2T0.cjs → pkt-options-controller-BhMNCWcc.cjs} +1 -1
  153. package/dist/{pkt-options-controller-B77vH3PE.js → pkt-options-controller-CuQ6SClv.js} +1 -1
  154. package/dist/pkt-progressbar.cjs +1 -1
  155. package/dist/pkt-progressbar.js +1 -1
  156. package/dist/pkt-radiobutton.cjs +1 -1
  157. package/dist/pkt-radiobutton.js +1 -1
  158. package/dist/pkt-searchinput.cjs +1 -1
  159. package/dist/pkt-searchinput.js +1 -1
  160. package/dist/pkt-select.cjs +1 -1
  161. package/dist/pkt-select.js +1 -1
  162. package/dist/pkt-tabs.cjs +1 -1
  163. package/dist/pkt-tabs.js +1 -1
  164. package/dist/pkt-tag.cjs +1 -1
  165. package/dist/pkt-tag.js +1 -1
  166. package/dist/pkt-textarea.cjs +1 -1
  167. package/dist/pkt-textarea.js +1 -1
  168. package/dist/pkt-textinput.cjs +1 -1
  169. package/dist/pkt-textinput.js +1 -1
  170. package/dist/pkt-timepicker.cjs +1 -1
  171. package/dist/pkt-timepicker.js +1 -1
  172. package/dist/{progressbar-CbcfLerF.js → progressbar-DS4i8IWq.js} +21 -21
  173. package/dist/{progressbar-D5MmnQId.cjs → progressbar-DY5hxImR.cjs} +5 -5
  174. package/dist/{radiobutton-BUnf3EPi.js → radiobutton-BhvZztMZ.js} +24 -24
  175. package/dist/{radiobutton-DpsO1F-8.cjs → radiobutton-BswqwRnA.cjs} +8 -8
  176. package/dist/{ref-CQoEIIp0.cjs → ref-DZmN5Qgj.cjs} +1 -1
  177. package/dist/{ref-CWD6PjVd.js → ref-OU8ryfP6.js} +2 -2
  178. package/dist/{repeat-sY6B7fAT.cjs → repeat-DIa_g6WL.cjs} +1 -1
  179. package/dist/{repeat-C02g7d5S.js → repeat-Dx2H127b.js} +4 -4
  180. package/dist/{searchinput-DwnjsvJ1.js → searchinput-CJo1PpM7.js} +43 -43
  181. package/dist/searchinput-Cl46nW0r.cjs +60 -0
  182. package/dist/{select-DMre80qs.js → select-CBrjauXT.js} +21 -20
  183. package/dist/{select-BOJi6H6T.cjs → select-Dman8Skr.cjs} +4 -3
  184. package/dist/shared-strings/consent.d.ts +71 -0
  185. package/dist/shared-strings/format.d.ts +21 -0
  186. package/dist/shared-strings/index.d.ts +14 -0
  187. package/dist/shared-strings/nb.d.ts +121 -0
  188. package/dist/shared-strings/resolve.d.ts +12 -0
  189. package/dist/shared-strings/store.d.ts +27 -0
  190. package/dist/shared-strings/types.d.ts +40 -0
  191. package/dist/shared-types/accordion.d.ts +58 -0
  192. package/dist/shared-types/alert.d.ts +20 -0
  193. package/dist/shared-types/aria.d.ts +2 -1
  194. package/dist/shared-types/backlink.d.ts +23 -0
  195. package/dist/shared-types/breadcrumbs.d.ts +33 -0
  196. package/dist/shared-types/fileupload.d.ts +55 -28
  197. package/dist/shared-types/footer.d.ts +10 -0
  198. package/dist/shared-types/form-field.d.ts +45 -0
  199. package/dist/shared-types/header-footer.d.ts +2 -0
  200. package/dist/shared-types/index.d.ts +15 -6
  201. package/dist/shared-types/render-link.d.ts +22 -0
  202. package/dist/shared-types/skin.d.ts +2 -9
  203. package/dist/shared-utils/combobox/index.d.ts +1 -0
  204. package/dist/shared-utils/combobox/input-utils.d.ts +2 -1
  205. package/dist/shared-utils/combobox/messages.d.ts +7 -0
  206. package/dist/shared-utils/combobox/option-utils.d.ts +2 -1
  207. package/dist/shared-utils/combobox/selection-manager.d.ts +3 -2
  208. package/dist/{tabs-Cf9ai0FD.cjs → tabs-C1m5rSrR.cjs} +7 -7
  209. package/dist/{tabs-TvxgbrCF.js → tabs-Xu3mIedh.js} +32 -32
  210. package/dist/{tag-Ds6n1LIs.js → tag-Azkjhkeu.js} +33 -32
  211. package/dist/tag-BS6dDPxY.cjs +27 -0
  212. package/dist/tests/strings-override.test.d.ts +0 -0
  213. package/dist/{textarea-vfzIcXhX.js → textarea-D4qXcVGD.js} +30 -29
  214. package/dist/{textarea-BydiLM9Z.cjs → textarea-DftUkR6w.cjs} +3 -2
  215. package/dist/{textinput-DGdicNSx.cjs → textinput-Ar-1Sbqy.cjs} +13 -12
  216. package/dist/{textinput-CMP2jPP_.js → textinput-iCgwwNPU.js} +28 -27
  217. package/dist/{timepicker-ClwgYywH.js → timepicker-W6HVWtmA.js} +67 -64
  218. package/dist/timepicker-dpAF7h49.cjs +196 -0
  219. package/package.json +3 -3
  220. package/src/components/accordion/accordion.ts +2 -10
  221. package/src/components/accordion/accordionitem.ts +2 -9
  222. package/src/components/alert/alert.ts +19 -10
  223. package/src/components/backlink/backlink.test.ts +3 -3
  224. package/src/components/backlink/backlink.ts +5 -7
  225. package/src/components/breadcrumbs/breadcrumbs.ts +9 -10
  226. package/src/components/breadcrumbs/index.ts +1 -1
  227. package/src/components/calendar/calendar.ts +56 -26
  228. package/src/components/checkbox/checkbox.test.ts +0 -2
  229. package/src/components/checkbox/checkbox.ts +8 -4
  230. package/src/components/combobox/combobox-base.ts +2 -1
  231. package/src/components/combobox/combobox-value.ts +10 -9
  232. package/src/components/combobox/combobox.selection.test.ts +5 -1
  233. package/src/components/combobox/combobox.ts +4 -1
  234. package/src/components/consent/strings.ts +1 -125
  235. package/src/components/datepicker/date-tags.ts +4 -1
  236. package/src/components/datepicker/datepicker-base.ts +2 -6
  237. package/src/components/datepicker/datepicker-multiple.ts +0 -3
  238. package/src/components/datepicker/datepicker-range.ts +4 -7
  239. package/src/components/datepicker/datepicker-single.ts +0 -3
  240. package/src/components/datepicker/datepicker-utils.test.ts +5 -5
  241. package/src/components/datepicker/datepicker-utils.ts +6 -11
  242. package/src/components/datepicker/datepicker.ts +8 -1
  243. package/src/components/fileupload/fileupload-base.ts +29 -19
  244. package/src/components/fileupload/fileupload-renderers.ts +2 -1
  245. package/src/components/fileupload/fileupload-types.ts +5 -42
  246. package/src/components/fileupload/fileupload.test.ts +16 -0
  247. package/src/components/fileupload/fileupload.ts +19 -15
  248. package/src/components/header/header-global.ts +3 -3
  249. package/src/components/header/header-service.ts +13 -8
  250. package/src/components/header/header.ts +2 -1
  251. package/src/components/helptext/helptext.test.ts +1 -1
  252. package/src/components/helptext/helptext.ts +3 -3
  253. package/src/components/index.ts +10 -1
  254. package/src/components/input-wrapper/input-wrapper.ts +18 -10
  255. package/src/components/link/link.ts +8 -3
  256. package/src/components/listbox/listbox.ts +3 -3
  257. package/src/components/radiobutton/radiobutton.ts +8 -4
  258. package/src/components/searchinput/searchinput.ts +5 -3
  259. package/src/components/select/select.ts +1 -0
  260. package/src/components/tag/tag.ts +2 -1
  261. package/src/components/textarea/textarea.ts +1 -0
  262. package/src/components/textinput/textinput.ts +1 -0
  263. package/src/components/timepicker/timepicker.ts +23 -21
  264. package/dist/alert-Cs4Rmq_J.cjs +0 -33
  265. package/dist/element-BA8v6S7z.cjs +0 -2
  266. package/dist/fileupload-BeWiTAoW.cjs +0 -401
  267. package/dist/helptext-CTtKJcML.cjs +0 -27
  268. package/dist/if-defined-B89_ZeCj.cjs +0 -1
  269. package/dist/input-element-DYmQw-fH.cjs +0 -1
  270. package/dist/input-wrapper-BmxNvznr.js +0 -128
  271. package/dist/input-wrapper-D-fPaTbY.js +0 -176
  272. package/dist/input-wrapper-D5PR0rJn.cjs +0 -1
  273. package/dist/input-wrapper-Q-B-aBeb.cjs +0 -54
  274. package/dist/link-D-Eqm5KH.js +0 -98
  275. package/dist/link-DK7gvmnj.cjs +0 -7
  276. package/dist/linkcard-B29cmZqh.cjs +0 -13
  277. package/dist/searchinput-Bh975rjX.cjs +0 -60
  278. package/dist/tag-CzojNU7z.cjs +0 -27
  279. package/dist/timepicker-DYrnLHqN.cjs +0 -195
  280. package/dist/translations/no.json.d.ts +0 -94
@@ -47,7 +47,10 @@ export class PktDateTags extends PktElement {
47
47
  @close=${() => {
48
48
  this.dispatchEvent(new CustomEvent('date-tag-removed', { detail: date }))
49
49
  }}
50
- .ariaLabel=${`${this.strings?.calendar.deleteDate} ${fromISOtoLocal(date, this.dateformat)}`}
50
+ .ariaLabel=${`${this.pktStrings.get('datepicker').deleteDate} ${fromISOtoLocal(
51
+ date,
52
+ this.dateformat,
53
+ )}`}
51
54
  >
52
55
  <time datetime=${date}>${fromISOtoLocal(date, this.dateformat)}</time>
53
56
  </pkt-tag>`,
@@ -4,7 +4,7 @@ import { Ref, createRef } from 'lit/directives/ref.js'
4
4
  import { classMap } from 'lit/directives/class-map.js'
5
5
  import { PktElement } from '@/base-elements/element'
6
6
  import { cssUtils } from './datepicker-utils'
7
- import { IDatepickerStrings } from './datepicker-types'
7
+
8
8
  import type { TPktInputSize } from 'shared-types/size'
9
9
  import '@/components/icon'
10
10
 
@@ -15,7 +15,6 @@ import '@/components/icon'
15
15
  * used by all three datepicker input types (single, multiple, range).
16
16
  *
17
17
  * Subclasses must implement:
18
- * - `strings` property with component-specific defaults
19
18
  * - `render()` method with component-specific template
20
19
  */
21
20
  export abstract class PktDatepickerBase extends PktElement {
@@ -50,9 +49,6 @@ export abstract class PktDatepickerBase extends PktElement {
50
49
  @property({ type: Object })
51
50
  internals?: ElementInternals
52
51
 
53
- // Abstract property - must be implemented by subclasses
54
- abstract strings: IDatepickerStrings
55
-
56
52
  // Shared refs
57
53
  inputRef: Ref<HTMLInputElement> = createRef()
58
54
  btnRef: Ref<HTMLButtonElement> = createRef()
@@ -140,7 +136,7 @@ export abstract class PktDatepickerBase extends PktElement {
140
136
  ${this.btnRef}
141
137
  >
142
138
  <pkt-icon name="calendar"></pkt-icon>
143
- <span class="pkt-btn__text">${this.strings.calendar?.buttonAltText || 'Åpne kalender'}</span>
139
+ <span class="pkt-btn__text">${this.pktStrings.get('datepicker').openPicker}</span>
144
140
  </button>
145
141
  `
146
142
  }
@@ -5,7 +5,6 @@ import { ifDefined } from 'lit/directives/if-defined.js'
5
5
  import { ref } from 'lit/directives/ref.js'
6
6
  import { PktDatepickerBase } from './datepicker-base'
7
7
  import { keyboardUtils, formUtils } from './datepicker-utils'
8
- import { IDatepickerStrings, defaultSingleStrings } from './datepicker-types'
9
8
  import { isIOS } from 'shared-utils/device-utils'
10
9
  import '@/components/icon'
11
10
 
@@ -16,8 +15,6 @@ export class PktDatepickerMultiple extends PktDatepickerBase {
16
15
  @property({ type: Number })
17
16
  maxlength?: number
18
17
 
19
- @property({ type: Object })
20
- strings: IDatepickerStrings = defaultSingleStrings
21
18
 
22
19
  get isInputDisabled(): boolean {
23
20
  return (
@@ -5,7 +5,6 @@ import { ifDefined } from 'lit/directives/if-defined.js'
5
5
  import { Ref, createRef, ref } from 'lit/directives/ref.js'
6
6
  import { PktDatepickerBase } from './datepicker-base'
7
7
  import { keyboardUtils, formUtils, cssUtils } from './datepicker-utils'
8
- import { IDatepickerStrings, defaultRangeStrings } from './datepicker-types'
9
8
  import { isIOS } from 'shared-utils/device-utils'
10
9
  import '@/components/icon'
11
10
 
@@ -19,8 +18,6 @@ export class PktDatepickerRange extends PktDatepickerBase {
19
18
  @property({ type: Boolean })
20
19
  showRangeLabels: boolean = false
21
20
 
22
- @property({ type: Object })
23
- strings: IDatepickerStrings = defaultRangeStrings
24
21
 
25
22
  inputRefTo: Ref<HTMLInputElement> = createRef()
26
23
 
@@ -34,13 +31,13 @@ export class PktDatepickerRange extends PktDatepickerBase {
34
31
  return html`
35
32
  <div class="pkt-input__container">
36
33
  ${this.showRangeLabels
37
- ? html` <div class="pkt-input-prefix">${this.strings.generic?.from}</div> `
34
+ ? html` <div class="pkt-input-prefix">${this.pktStrings.get('generic').from}</div> `
38
35
  : nothing}
39
36
  <input
40
37
  class=${classMap(this.inputClasses)}
41
38
  .type=${this.inputType}
42
39
  id="${this.id}-input"
43
- aria-label="${this.label} ${this.strings.generic?.from ?? 'Fra'}"
40
+ aria-label="${this.label} ${this.pktStrings.get('generic').from}"
44
41
  .value=${this.value[0] ?? ''}
45
42
  min=${ifDefined(this.min)}
46
43
  max=${ifDefined(this.max)}
@@ -97,14 +94,14 @@ export class PktDatepickerRange extends PktDatepickerBase {
97
94
  ${ref(this.inputRef)}
98
95
  />
99
96
  <div class="${classMap(rangeLabelClasses)}" id="${this.id}-to-label">
100
- ${this.strings.generic?.to}
97
+ ${this.pktStrings.get('generic').to}
101
98
  </div>
102
99
  ${!this.showRangeLabels ? html` <div class="pkt-input-separator">–</div> ` : nothing}
103
100
  <input
104
101
  class=${classMap(this.inputClasses)}
105
102
  .type=${this.inputType}
106
103
  id="${this.id}-to"
107
- aria-label="${this.label} ${this.strings.generic?.to ?? 'Til'}"
104
+ aria-label="${this.label} ${this.pktStrings.get('generic').to}"
108
105
  .value=${this.value[1] ?? ''}
109
106
  min=${ifDefined(this.min)}
110
107
  max=${ifDefined(this.max)}
@@ -5,15 +5,12 @@ import { ifDefined } from 'lit/directives/if-defined.js'
5
5
  import { ref } from 'lit/directives/ref.js'
6
6
  import { PktDatepickerBase } from './datepicker-base'
7
7
  import { keyboardUtils, formUtils } from './datepicker-utils'
8
- import { IDatepickerStrings, defaultSingleStrings } from './datepicker-types'
9
8
  import { isIOS } from 'shared-utils/device-utils'
10
9
 
11
10
  export class PktDatepickerSingle extends PktDatepickerBase {
12
11
  @property({ type: String })
13
12
  value: string = ''
14
13
 
15
- @property({ type: Object })
16
- strings: IDatepickerStrings = defaultSingleStrings
17
14
 
18
15
  private dispatchManageValidity(input: HTMLInputElement) {
19
16
  this.dispatchEvent(
@@ -144,9 +144,9 @@ describe('datepicker-utils', () => {
144
144
  it('should set rangeUnderflow validity when value is below minimum', () => {
145
145
  const input = { value: '2024-01-01' } as HTMLInputElement
146
146
  const internals = { setValidity: vi.fn() }
147
- const strings = { forms: { messages: { rangeUnderflow: 'Too early' } } }
147
+ const messages = { dateUnderflow: 'Too early' }
148
148
 
149
- formUtils.validateDateInput(input, internals, '2024-01-10', null, strings)
149
+ formUtils.validateDateInput(input, internals, '2024-01-10', null, messages)
150
150
  expect(internals.setValidity).toHaveBeenCalledWith(
151
151
  { rangeUnderflow: true },
152
152
  'Too early',
@@ -157,9 +157,9 @@ describe('datepicker-utils', () => {
157
157
  it('should set rangeOverflow validity when value is above maximum', () => {
158
158
  const input = { value: '2024-01-31' } as HTMLInputElement
159
159
  const internals = { setValidity: vi.fn() }
160
- const strings = { forms: { messages: { rangeOverflow: 'Too late' } } }
160
+ const messages = { dateOverflow: 'Too late' }
161
161
 
162
- formUtils.validateDateInput(input, internals, null, '2024-01-20', strings)
162
+ formUtils.validateDateInput(input, internals, null, '2024-01-20', messages)
163
163
  expect(internals.setValidity).toHaveBeenCalledWith(
164
164
  { rangeOverflow: true },
165
165
  'Too late',
@@ -174,7 +174,7 @@ describe('datepicker-utils', () => {
174
174
  formUtils.validateDateInput(input, internals, '2024-01-10', null)
175
175
  expect(internals.setValidity).toHaveBeenCalledWith(
176
176
  { rangeUnderflow: true },
177
- 'Value is below minimum',
177
+ 'For tidlig dato',
178
178
  input,
179
179
  )
180
180
  })
@@ -1,6 +1,7 @@
1
1
  import { fromISOToDate, newDate } from 'shared-utils/date-utils'
2
2
  import { Ref } from 'lit/directives/ref.js'
3
3
  import { PktCalendar } from '@/components/calendar/calendar'
4
+ import { nb, type TPktStrings } from 'shared-strings'
4
5
  import {
5
6
  validateRangeOrder,
6
7
  sortDates,
@@ -66,23 +67,17 @@ export const formUtils = {
66
67
  internals: any,
67
68
  min?: string | null,
68
69
  max?: string | null,
69
- strings?: any,
70
+ messages?: Partial<TPktStrings['validation']>,
70
71
  ): void {
71
72
  const value = input.value
72
73
  if (!value) return
73
74
 
75
+ const validation = { ...nb.validation, ...messages }
76
+
74
77
  if (min && min > value) {
75
- internals.setValidity(
76
- { rangeUnderflow: true },
77
- strings?.forms?.messages?.rangeUnderflow || 'Value is below minimum',
78
- input,
79
- )
78
+ internals.setValidity({ rangeUnderflow: true }, validation.dateUnderflow, input)
80
79
  } else if (max && max < value) {
81
- internals.setValidity(
82
- { rangeOverflow: true },
83
- strings?.forms?.messages?.rangeOverflow || 'Value is above maximum',
84
- input,
85
- )
80
+ internals.setValidity({ rangeOverflow: true }, validation.dateOverflow, input)
86
81
  }
87
82
  },
88
83
  }
@@ -391,7 +391,13 @@ export class PktDatepicker extends PktInputElement<Props> {
391
391
  }}
392
392
  @manage-validity=${(e: CustomEvent) => this.manageValidity(e.detail)}
393
393
  @validate-date-input=${(e: CustomEvent) => {
394
- formUtils.validateDateInput(e.detail, this.internals, this.min, this.max, this.strings)
394
+ formUtils.validateDateInput(
395
+ e.detail,
396
+ this.internals,
397
+ this.min,
398
+ this.max,
399
+ this.pktStrings.get('validation'),
400
+ )
395
401
  }}
396
402
  @handle-date-select=${(e: CustomEvent) => {
397
403
  const date = fromISOToDate(e.detail)
@@ -497,6 +503,7 @@ export class PktDatepicker extends PktInputElement<Props> {
497
503
 
498
504
  return html`
499
505
  <pkt-input-wrapper
506
+ .strings=${this.strings}
500
507
  label="${this.label}"
501
508
  forId="${this.id}-input"
502
509
  ?counter=${this.multiple && !!this.maxlength}
@@ -1,7 +1,6 @@
1
1
  import { PropertyValues } from 'lit'
2
2
  import { property, state } from 'lit/decorators.js'
3
3
 
4
- import { defaultFileUploadStrings } from 'shared-types'
5
4
  import {
6
5
  countFileTransferStates,
7
6
  formatFileSize,
@@ -14,7 +13,6 @@ import {
14
13
 
15
14
  import { PktElement } from '@/base-elements/element'
16
15
  import converters from '../../helpers/converters'
17
- import specs from 'componentSpecs/fileupload.json'
18
16
 
19
17
  import type {
20
18
  FileItem,
@@ -29,6 +27,7 @@ import type {
29
27
  TUploadStrategy,
30
28
  } from './fileupload-types'
31
29
  import { uuidish } from 'shared-utils/utils'
30
+ import { formatString, plural } from 'shared-strings'
32
31
 
33
32
  export abstract class PktFileUploadBase
34
33
  extends PktElement<IPktFileUpload>
@@ -45,8 +44,9 @@ export abstract class PktFileUploadBase
45
44
  /** Expandable help text (dropdown) shown by `pkt-input-wrapper`. */
46
45
  @property({ type: String, attribute: 'helptext-dropdown' }) helptextDropdown: string = ''
47
46
  /** Button label for expandable help text. */
47
+ /** @deprecated Bruk `strings={{ forms: { readMore: '…' } }}` eller `setPktStrings()`. */
48
48
  @property({ type: String, attribute: 'helptext-dropdown-button' })
49
- helptextDropdownButton: string = specs.props.helptextDropdownButton.default
49
+ helptextDropdownButton?: string
50
50
  /** Mark input as required in form strategy. */
51
51
  @property({ type: Boolean, reflect: true }) required = false
52
52
  /** Allow selecting/dropping multiple files. */
@@ -92,13 +92,15 @@ export abstract class PktFileUploadBase
92
92
  /** Show "Valgfritt" tag in the input wrapper. */
93
93
  @property({ type: Boolean, attribute: 'optional-tag' }) optionalTag = false
94
94
  /** Label text for the optional tag. */
95
+ /** @deprecated Bruk `strings={{ forms: { optional: '…' } }}` eller `setPktStrings()`. */
95
96
  @property({ type: String, attribute: 'optional-text' })
96
- optionalText: string = specs.props.optionalText.default
97
+ optionalText?: string
97
98
  /** Show "Må fylles ut" tag in the input wrapper. */
98
99
  @property({ type: Boolean, attribute: 'required-tag' }) requiredTag = false
99
100
  /** Label text for the required tag. */
101
+ /** @deprecated Bruk `strings={{ forms: { required: '…' } }}` eller `setPktStrings()`. */
100
102
  @property({ type: String, attribute: 'required-text' })
101
- requiredText: string = specs.props.requiredText.default
103
+ requiredText?: string
102
104
  /** Extra tag next to the label. */
103
105
  @property({ type: String, attribute: 'tag-text' }) tagText: string | null = null
104
106
  /** Trailing characters to keep when middle-truncating long filenames. Set to `0` to disable. */
@@ -119,7 +121,9 @@ export abstract class PktFileUploadBase
119
121
  private thumbnailFileById = new Map<string, File>()
120
122
  private connectedForm: HTMLFormElement | null = null
121
123
  private addedAnnouncementTimer: ReturnType<typeof setTimeout> | null = null
122
- private readonly requiredSelectionMessage = defaultFileUploadStrings.requiredMissing
124
+ private get requiredSelectionMessage() {
125
+ return this.pktStrings.get('fileupload').requiredMissing
126
+ }
123
127
 
124
128
  protected get isControlled() {
125
129
  return this.value !== undefined
@@ -297,10 +301,13 @@ export abstract class PktFileUploadBase
297
301
  },
298
302
  }))
299
303
 
304
+ const fileuploadStrings = this.pktStrings.get('fileupload')
300
305
  this.setAddedAnnouncement(
301
306
  newItems.length === 1
302
- ? defaultFileUploadStrings.srFileAdded(newItems[0].attributes.targetFilename)
303
- : defaultFileUploadStrings.srFilesAdded(newItems.length),
307
+ ? formatString(fileuploadStrings.srFileAdded, {
308
+ filename: newItems[0].attributes.targetFilename,
309
+ })
310
+ : formatString(fileuploadStrings.srFilesAdded, { count: newItems.length }),
304
311
  )
305
312
 
306
313
  const currentFiles = this.getCurrentFiles()
@@ -448,7 +455,8 @@ export abstract class PktFileUploadBase
448
455
  this.dispatchEvent(validationEvent)
449
456
 
450
457
  if (eventDetail.errorMessage) return eventDetail.errorMessage
451
- if (validationEvent.defaultPrevented) return defaultFileUploadStrings.genericValidationRejection
458
+ if (validationEvent.defaultPrevented)
459
+ return this.pktStrings.get('fileupload').genericValidationRejection
452
460
  return null
453
461
  }
454
462
 
@@ -523,11 +531,12 @@ export abstract class PktFileUploadBase
523
531
  this.transfers,
524
532
  )
525
533
  if (totalCount === 0 || uploadedCount === 0) return ''
526
- return defaultFileUploadStrings.srFilesUploadedOfTotal(
527
- uploadedCount,
528
- totalCount,
529
- defaultFileUploadStrings.fileLabel(totalCount),
530
- )
534
+ const fileuploadStrings = this.pktStrings.get('fileupload')
535
+ return formatString(fileuploadStrings.srFilesUploadedOfTotal, {
536
+ uploaded: uploadedCount,
537
+ total: totalCount,
538
+ label: plural(totalCount, fileuploadStrings.fileLabelOne, fileuploadStrings.fileLabelOther),
539
+ })
531
540
  }
532
541
 
533
542
  /** Assertive summary for transfer errors (parity with React `FileUpload`). */
@@ -537,11 +546,12 @@ export abstract class PktFileUploadBase
537
546
  this.transfers,
538
547
  )
539
548
  if (totalCount === 0 || failedCount === 0) return ''
540
- return defaultFileUploadStrings.srFilesFailedOfTotal(
541
- failedCount,
542
- totalCount,
543
- defaultFileUploadStrings.fileLabel(totalCount),
544
- )
549
+ const fileuploadStrings = this.pktStrings.get('fileupload')
550
+ return formatString(fileuploadStrings.srFilesFailedOfTotal, {
551
+ failed: failedCount,
552
+ total: totalCount,
553
+ label: plural(totalCount, fileuploadStrings.fileLabelOne, fileuploadStrings.fileLabelOther),
554
+ })
545
555
  }
546
556
 
547
557
  private syncFormSubmitListener() {
@@ -10,6 +10,7 @@ import type {
10
10
  TQueueOperationContext,
11
11
  TTransferProgress,
12
12
  } from './fileupload-types'
13
+ import { formatString, nb } from 'shared-strings'
13
14
 
14
15
  type TRenderQueueItemProps = {
15
16
  file: FileItem
@@ -449,7 +450,7 @@ const renderThumbnailIdleMain = ({
449
450
  <button
450
451
  type="button"
451
452
  class="pkt-fileupload__queue-display__item__thumbnail__image-wrapper pkt-btn pkt-btn--medium pkt-btn--secondary pkt-btn--label-only"
452
- aria-label=${`Forhåndsvis bilde ${filename}`}
453
+ aria-label=${formatString(nb.fileupload.previewImage, { filename })}
453
454
  ?disabled=${!isInteractive}
454
455
  @click=${() => {
455
456
  if (!isInteractive || !onOpenPreview) return
@@ -5,6 +5,7 @@ import type {
5
5
  IFileTransfer,
6
6
  IFileValidateDetail,
7
7
  IFilesChangedDetail,
8
+ IPktFileUploadBase,
8
9
  ITransferCancelledDetail,
9
10
  TFilesChangedReason,
10
11
  TFileUploadItemRenderer,
@@ -50,49 +51,11 @@ export type TQueueItemOperation = {
50
51
  renderHidden?: (context: TQueueOperationContext) => TemplateResult | null
51
52
  }
52
53
 
53
- export interface IPktFileUpload {
54
- id?: string
54
+ export interface IPktFileUpload extends Omit<IPktFileUploadBase, 'extraOperations' | 'name'> {
55
55
  name?: string
56
- label?: string
57
- helptext?: string
58
- /** Expandable help text (dropdown) in input-wrapper. */
59
- helptextDropdown?: string
60
- /** Button label for expandable help text. */
61
- helptextDropdownButton?: string
62
- required?: boolean
63
- multiple?: boolean
64
- disabled?: boolean
65
- fullwidth?: boolean
66
- uploadStrategy?: TUploadStrategy
67
- itemRenderer?: TFileUploadItemRenderer
56
+ /** Custom element id — required for `uploadStrategy="custom"`. */
57
+ id?: string
58
+ /** HTML `accept` attribute on the native file input. */
68
59
  accept?: string
69
- allowedFormats?: string[]
70
- formatErrorMessage?: string
71
- maxFileSize?: string | number
72
- sizeErrorMessage?: string
73
- onFileValidation?: TFileValidator
74
- /** External error state (combined with internal validation errors). */
75
- hasError?: boolean
76
- /** External error message shown under the component. */
77
- errorMessage?: string
78
- /** Show "Valgfritt" tag in input-wrapper. */
79
- optionalTag?: boolean
80
- /** Label text for the optional tag. */
81
- optionalText?: string
82
- /** Show "Må fylles ut" tag in input-wrapper. */
83
- requiredTag?: boolean
84
- /** Label text for the required tag. */
85
- requiredText?: string
86
- /** Extra tag next to the label. */
87
- tagText?: string | null
88
- /** Trailing characters to keep when truncating long filenames. */
89
- truncateTail?: number
90
- /** Transfer states keyed by `fileId` (custom strategy progress/error/cancel rendering). */
91
- transfers?: TFileTransfer[]
92
- addCommentsEnabled?: boolean
93
- renameFilesEnabled?: boolean
94
60
  extraOperations?: TQueueItemOperation[]
95
- enableImagePreview?: boolean
96
- value?: FileItem[]
97
- defaultValue?: FileItem[]
98
61
  }
@@ -368,6 +368,22 @@ describe('PktFileUpload', () => {
368
368
  expect(withAcceptText).toContain('Format: PNG, application/pdf')
369
369
  })
370
370
 
371
+ test('uses drop zone text from the strings property', async () => {
372
+ const { fileupload } = await createFileUploadTest({ multiple: true })
373
+ fileupload.strings = {
374
+ fileupload: {
375
+ dropZoneDragMultiple: 'Dra dokumentene hit eller',
376
+ dropZoneOpenFileDialogMultiple: 'bla i filene',
377
+ },
378
+ }
379
+ await fileupload.updateComplete
380
+
381
+ const title = fileupload.querySelector('.pkt-fileupload__drop-zone__placeholder__title')
382
+ expect(title?.textContent).toContain('Dra dokumentene hit eller')
383
+ expect(title?.textContent).toContain('bla i filene')
384
+ expect(title?.textContent).not.toContain('velg filer')
385
+ })
386
+
371
387
  test('sets required only on native file input in form strategy', async () => {
372
388
  const { fileupload: formUpload } = await createFileUploadTest({
373
389
  required: true,
@@ -3,7 +3,6 @@ import { classMap } from 'lit/directives/class-map.js'
3
3
  import { ifDefined } from 'lit/directives/if-defined.js'
4
4
  import { customElement, state } from 'lit/decorators.js'
5
5
 
6
- import { defaultFileUploadStrings } from 'shared-types'
7
6
  import { navigateCyclic, trapTabInside, type IFileAndTransfer } from 'shared-utils/fileupload'
8
7
 
9
8
  import '@/components/alert'
@@ -70,6 +69,7 @@ export class PktFileUpload extends PktFileUploadBase implements IPktFileUpload {
70
69
 
71
70
  return html`
72
71
  <pkt-input-wrapper
72
+ .strings=${this.strings}
73
73
  .forId=${`${this.id}-input`}
74
74
  .label=${this.label}
75
75
  .helptext=${this.helptext}
@@ -95,6 +95,7 @@ export class PktFileUpload extends PktFileUploadBase implements IPktFileUpload {
95
95
  private renderContent() {
96
96
  const filesAndTransfers = this.getSortedFilesAndTransfers()
97
97
  const previewableImages = this.getPreviewableImages(filesAndTransfers)
98
+ const fileuploadStrings = this.pktStrings.get('fileupload')
98
99
  const supportedFormatsText = this.getSupportedFormatsText()
99
100
  const helptextId = !this.label && this.helptext ? `${this.id}-helptext` : undefined
100
101
  const errorId = this.hasEffectiveError ? `${this.id}-error` : undefined
@@ -103,25 +104,25 @@ export class PktFileUpload extends PktFileUploadBase implements IPktFileUpload {
103
104
  const dropZoneCopy = isThumbnailView
104
105
  ? this.multiple
105
106
  ? {
106
- dragInactive: defaultFileUploadStrings.dropZoneDragMultipleThumbnail,
107
- dragActive: defaultFileUploadStrings.dropZoneDragActiveMultipleThumbnail,
108
- openFileDialog: defaultFileUploadStrings.dropZoneOpenFileDialogMultipleThumbnail,
107
+ dragInactive: fileuploadStrings.dropZoneDragMultipleThumbnail,
108
+ dragActive: fileuploadStrings.dropZoneDragActiveMultipleThumbnail,
109
+ openFileDialog: fileuploadStrings.dropZoneOpenFileDialogMultipleThumbnail,
109
110
  }
110
111
  : {
111
- dragInactive: defaultFileUploadStrings.dropZoneDragSingleThumbnail,
112
- dragActive: defaultFileUploadStrings.dropZoneDragActiveSingleThumbnail,
113
- openFileDialog: defaultFileUploadStrings.dropZoneOpenFileDialogSingleThumbnail,
112
+ dragInactive: fileuploadStrings.dropZoneDragSingleThumbnail,
113
+ dragActive: fileuploadStrings.dropZoneDragActiveSingleThumbnail,
114
+ openFileDialog: fileuploadStrings.dropZoneOpenFileDialogSingleThumbnail,
114
115
  }
115
116
  : this.multiple
116
117
  ? {
117
- dragInactive: defaultFileUploadStrings.dropZoneDragMultiple,
118
- dragActive: defaultFileUploadStrings.dropZoneDragActiveMultiple,
119
- openFileDialog: defaultFileUploadStrings.dropZoneOpenFileDialogMultiple,
118
+ dragInactive: fileuploadStrings.dropZoneDragMultiple,
119
+ dragActive: fileuploadStrings.dropZoneDragActiveMultiple,
120
+ openFileDialog: fileuploadStrings.dropZoneOpenFileDialogMultiple,
120
121
  }
121
122
  : {
122
- dragInactive: defaultFileUploadStrings.dropZoneDragSingle,
123
- dragActive: defaultFileUploadStrings.dropZoneDragActiveSingle,
124
- openFileDialog: defaultFileUploadStrings.dropZoneOpenFileDialogSingle,
123
+ dragInactive: fileuploadStrings.dropZoneDragSingle,
124
+ dragActive: fileuploadStrings.dropZoneDragActiveSingle,
125
+ openFileDialog: fileuploadStrings.dropZoneOpenFileDialogSingle,
125
126
  }
126
127
 
127
128
  return html`
@@ -194,7 +195,7 @@ export class PktFileUpload extends PktFileUploadBase implements IPktFileUpload {
194
195
  </p>
195
196
  ${supportedFormatsText
196
197
  ? html`<p class="pkt-fileupload__drop-zone__placeholder__formats">
197
- ${defaultFileUploadStrings.supportedFormatsPrefix} ${supportedFormatsText}
198
+ ${fileuploadStrings.supportedFormatsPrefix} ${supportedFormatsText}
198
199
  </p>`
199
200
  : null}
200
201
  </div>
@@ -351,13 +352,16 @@ export class PktFileUpload extends PktFileUploadBase implements IPktFileUpload {
351
352
 
352
353
  private renderPreviewModal(previewableImages: IFileAndTransfer[]) {
353
354
  if (!this.enableImagePreview || previewableImages.length === 0) return null
355
+ const fileuploadStrings = this.pktStrings.get('fileupload')
354
356
  const currentImage = previewableImages[this.previewCurrentIndex]
355
357
  if (!currentImage) return null
356
358
  const hasMultipleImages = previewableImages.length > 1
357
359
  const imageUrl = this.getThumbnailUrl(currentImage)
358
360
  const hasImage = !!imageUrl && !this.failedImageFileIds[currentImage.fileId]?.preview
359
361
  const filename =
360
- currentImage.attributes?.targetFilename || currentImage.file?.name || 'Forhåndsvisning'
362
+ currentImage.attributes?.targetFilename ||
363
+ currentImage.file?.name ||
364
+ fileuploadStrings.previewFallbackName
361
365
 
362
366
  return html`
363
367
  <pkt-modal
@@ -428,7 +428,7 @@ export class PktHeaderGlobal extends PktElement<IPktHeaderGlobal> implements IPk
428
428
  }
429
429
 
430
430
  private renderMenuToggle(localeData?: IHeaderFooterLocaleData) {
431
- const menuText = localeData?.i18n?.menu || 'Meny'
431
+ const menuText = localeData?.i18n?.menu || this.pktStrings.get('header').menu
432
432
  const isOpen = this.openMenu === 'menu'
433
433
  return html`
434
434
  <pkt-button
@@ -466,7 +466,7 @@ export class PktHeaderGlobal extends PktElement<IPktHeaderGlobal> implements IPk
466
466
  aria-controls=${SEARCH_PANEL_ID}
467
467
  @click=${() => this.toggleMenu('search')}
468
468
  >
469
- ${localeData.i18n?.search || 'Søk'}
469
+ ${localeData.i18n?.search || this.pktStrings.get('header').search}
470
470
  </pkt-button>
471
471
  `
472
472
  }
@@ -489,7 +489,7 @@ export class PktHeaderGlobal extends PktElement<IPktHeaderGlobal> implements IPk
489
489
  id=${search.input.id || 'pkt-header-global-search'}
490
490
  name=${ifDefined(search.input.name)}
491
491
  placeholder=${ifDefined(placeholder)}
492
- aria-label=${ifDefined(localeData.i18n?.search || 'Søk')}
492
+ aria-label=${ifDefined(localeData.i18n?.search || this.pktStrings.get('header').search)}
493
493
  action=${search.endpoint}
494
494
  method="get"
495
495
  @pkt-search=${(e: CustomEvent<{ value: string }>) => this.handleSearch(e.detail.value)}
@@ -40,7 +40,8 @@ export class PktHeaderService extends PktElementWithSlot<IPktHeader> implements
40
40
  @property({ type: String, attribute: 'logo-link' }) logoLink: string = DEFAULT_HEADER_LOGO_LINK
41
41
  @property({ type: String, attribute: 'logo-path' }) logoPath: string | undefined =
42
42
  typeof window !== 'undefined' ? window.pktLogoPath : defaultLogoPath
43
- @property({ type: String, attribute: 'search-placeholder' }) searchPlaceholder = 'Søk'
43
+ /** @deprecated Bruk `strings={{ header: { search: '' } }}` eller `setPktStrings()`. */
44
+ @property({ type: String, attribute: 'search-placeholder' }) searchPlaceholder?: string
44
45
  @property({ type: String, attribute: 'search-value' }) searchValue = ''
45
46
  @property({ type: Number, attribute: 'mobile-breakpoint' }) mobileBreakpoint: number = 768
46
47
  @property({ type: Number, attribute: 'tablet-breakpoint' }) tabletBreakpoint: number = 1280
@@ -333,6 +334,10 @@ export class PktHeaderService extends PktElementWithSlot<IPktHeader> implements
333
334
  )
334
335
  }
335
336
 
337
+ private get headerStrings() {
338
+ return this.pktStrings.get('header')
339
+ }
340
+
336
341
  private renderLogo() {
337
342
  if (this.hideLogo) return nothing
338
343
 
@@ -422,7 +427,7 @@ export class PktHeaderService extends PktElementWithSlot<IPktHeader> implements
422
427
  @click=${() => this.handleMenuToggle('slot')}
423
428
  aria-expanded=${this.openMenu === 'slot'}
424
429
  aria-controls="mobile-slot-menu"
425
- aria-label="Åpne meny"
430
+ aria-label=${this.headerStrings.openMenu}
426
431
  >
427
432
  ${this.slotMenuText}
428
433
  </pkt-button>
@@ -472,9 +477,9 @@ export class PktHeaderService extends PktElementWithSlot<IPktHeader> implements
472
477
  state=${this.openMenu === 'search' ? 'active' : 'normal'}
473
478
  aria-expanded=${this.openMenu === 'search'}
474
479
  aria-controls="mobile-search-menu"
475
- aria-label="Åpne søkefelt"
480
+ aria-label=${this.headerStrings.openSearch}
476
481
  >
477
- Søk
482
+ ${this.headerStrings.search}
478
483
  </pkt-button>
479
484
  <div class=${searchMenuClasses} ${ref(this.searchMenuRef)}>
480
485
  ${this.openMenu === 'search'
@@ -483,9 +488,9 @@ export class PktHeaderService extends PktElementWithSlot<IPktHeader> implements
483
488
  id="mobile-search-menu"
484
489
  class="pkt-header-service__search-input"
485
490
  type="search"
486
- label="Søk"
491
+ label=${this.headerStrings.search}
487
492
  useWrapper="false"
488
- placeholder=${this.searchPlaceholder}
493
+ placeholder=${this.searchPlaceholder ?? this.headerStrings.search}
489
494
  value=${this.searchValue}
490
495
  autofocus
491
496
  fullwidth
@@ -508,9 +513,9 @@ export class PktHeaderService extends PktElementWithSlot<IPktHeader> implements
508
513
  id="header-service-search"
509
514
  class="pkt-header-service__search-input"
510
515
  type="search"
511
- label="Søk"
516
+ label=${this.headerStrings.search}
512
517
  useWrapper="false"
513
- placeholder=${this.searchPlaceholder}
518
+ placeholder=${this.searchPlaceholder ?? this.headerStrings.search}
514
519
  value=${this.searchValue}
515
520
  @input=${this.handleSearchInputChange}
516
521
  @keydown=${this.handleSearchKeyDown}
@@ -44,7 +44,8 @@ export class PktHeader extends PktElementWithSlot<IPktHeader> implements IPktHea
44
44
  @property({ type: String, attribute: 'service-link' }) serviceLink?: string
45
45
  @property({ type: String, attribute: 'logo-link' }) logoLink?: string
46
46
  @property({ type: String, attribute: 'logo-path' }) logoPath?: string
47
- @property({ type: String, attribute: 'search-placeholder' }) searchPlaceholder = 'Søk'
47
+ /** @deprecated Bruk `strings={{ header: { search: '' } }}` eller `setPktStrings()`. */
48
+ @property({ type: String, attribute: 'search-placeholder' }) searchPlaceholder?: string
48
49
  @property({ type: String, attribute: 'search-value' }) searchValue = ''
49
50
  @property({ type: Number, attribute: 'mobile-breakpoint' }) mobileBreakpoint: number = 768
50
51
  @property({ type: Number, attribute: 'tablet-breakpoint' }) tabletBreakpoint: number = 1280