@oslokommune/punkt-elements 19.15.0 → 19.17.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 (182) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/{accordion-BlsqYbJf.js → accordion-B0zAUNUV.js} +5 -5
  3. package/dist/{accordion-DukAa2ED.cjs → accordion-Cx-Gh3hc.cjs} +1 -1
  4. package/dist/{alert-CuXM6TnC.cjs → alert-BRZDpVMt.cjs} +1 -1
  5. package/dist/{alert-Xt26J9yX.js → alert-JnRrtTOW.js} +5 -5
  6. package/dist/{async-directive-yh8hG41Q.js → async-directive-C4LocQwR.js} +2 -2
  7. package/dist/{backlink-ogvv493Y.js → backlink-D8Rv46lA.js} +3 -3
  8. package/dist/{breadcrumbs-53QVnTFP.js → breadcrumbs-ybOBe_op.js} +2 -2
  9. package/dist/{button-BFG-7bDB.cjs → button-Ca_V13cQ.cjs} +1 -1
  10. package/dist/{button-DhCqyX4D.js → button-ChdHZYBF.js} +5 -5
  11. package/dist/{calendar-D9w8M99G.js → calendar-BQCjUQvP.js} +51 -70
  12. package/dist/calendar-CFTrX0C5.cjs +85 -0
  13. package/dist/{card-Diivw_vm.cjs → card-COseC8ZL.cjs} +1 -1
  14. package/dist/{card-DCc3wfUb.js → card-DSTEL8Kv.js} +6 -6
  15. package/dist/{checkbox-BDwOYcNM.js → checkbox-CKYNnLDh.js} +5 -9
  16. package/dist/{checkbox-BwI9QNSh.cjs → checkbox-DkFswqr-.cjs} +2 -2
  17. package/dist/{checkbox-group-C8mo9dkO.js → checkbox-group-1ghi5uHp.js} +3 -3
  18. package/dist/{checkbox-group-adbFTj8y.cjs → checkbox-group-lcxR3cYR.cjs} +1 -1
  19. package/dist/{class-map-Bf-QzUpN.js → class-map-BkEYw5uE.js} +1 -1
  20. package/dist/combobox-CaWnlvTX.cjs +139 -0
  21. package/dist/{combobox-B8IeuEF0.js → combobox-iXYiaWbN.js} +63 -96
  22. package/dist/components/index.d.ts +1 -0
  23. package/dist/components/input-wrapper/index.d.ts +1 -0
  24. package/dist/components/input-wrapper/input-wrapper.d.ts +13 -6
  25. package/dist/{consent-DBYZaCTp.cjs → consent-CxcKuGi9.cjs} +1 -1
  26. package/dist/{consent-BUS6GEUu.js → consent-D2nfauO8.js} +3 -3
  27. package/dist/converters-CW6SN0TT.cjs +1 -0
  28. package/dist/{converters-CkjLSYpa.js → converters-CYgQrWVm.js} +138 -141
  29. package/dist/{datepicker-CjUY_mLR.js → datepicker-DTcow1ih.js} +15 -25
  30. package/dist/{datepicker-CZYpIyJd.cjs → datepicker-Da8SfyVG.cjs} +3 -3
  31. package/dist/{dialog-polyfill.esm-B-g35ove.cjs → dialog-polyfill.esm-CW51hN2p.cjs} +1 -1
  32. package/dist/{dialog-polyfill.esm-DHSvqor8.js → dialog-polyfill.esm-D39dWbRt.js} +2 -2
  33. package/dist/{directive-helpers-CwxFepWh.js → directive-helpers-BAinC437.js} +1 -1
  34. package/dist/{element-DBugHPKM.js → element-ckeMVgMz.js} +1 -1
  35. package/dist/{element-with-slot-CVmm0_IE.js → element-with-slot-C0bH0T0H.js} +27 -38
  36. package/dist/element-with-slot-DkyaNnm0.cjs +1 -0
  37. package/dist/{fileupload-BKk03Dq-.js → fileupload-BNAQ9tNR.js} +16 -23
  38. package/dist/{fileupload-CnjtgTlF.cjs → fileupload-Cb1c7ul0.cjs} +3 -3
  39. package/dist/{footer-C6ajmlq2.cjs → footer-Box90zhr.cjs} +1 -1
  40. package/dist/{footer-L2vhQTAS.js → footer-D2RpIbsD.js} +4 -4
  41. package/dist/{header-BCrefip0.cjs → header-CvER8wo6.cjs} +2 -2
  42. package/dist/{header-20rqKJFb.js → header-Cwr995oK.js} +13 -13
  43. package/dist/{header-menu-F3tZZ5vO.js → header-menu-CsL4DZE2.js} +5 -5
  44. package/dist/{header-menu-Cz7G7Q2R.cjs → header-menu-D-wOwG1V.cjs} +1 -1
  45. package/dist/{heading-BluavR6A.cjs → heading-D4Kkb6-N.cjs} +1 -1
  46. package/dist/{heading-y72aIgB8.js → heading-DhTyaJms.js} +2 -2
  47. package/dist/{helptext-Dujce_W9.js → helptext-DN0jjgVu.js} +4 -4
  48. package/dist/{helptext-Bdv80rcs.cjs → helptext-p0nwJsyf.cjs} +1 -1
  49. package/dist/{icon-Bao96Zb8.js → icon-CLMJYuTL.js} +1 -1
  50. package/dist/{if-defined-O59_I-e-.js → if-defined-D18nY_K_.js} +1 -1
  51. package/dist/{input-element-mTphzs9b.js → input-element-0yYtRu0p.js} +3 -3
  52. package/dist/{input-element-BjnKPikY.cjs → input-element-BOi7rBbw.cjs} +1 -1
  53. package/dist/input-wrapper-4PTk8aX3.cjs +62 -0
  54. package/dist/{input-wrapper-Bb6CZxmg.js → input-wrapper-BSjQc4Vx.js} +30 -199
  55. package/dist/{link-sO401Ieh.js → link-39EvU2ng.js} +5 -5
  56. package/dist/{link-CRLAhYi0.cjs → link-Dj6SbcaD.cjs} +1 -1
  57. package/dist/{linkcard-DnZgMzqL.cjs → linkcard-BoQIfci8.cjs} +1 -1
  58. package/dist/{linkcard-DdmGxzAP.js → linkcard-K9vvKg1u.js} +4 -4
  59. package/dist/{listbox-CvduK_YU.cjs → listbox-BbdUu-IV.cjs} +3 -3
  60. package/dist/{listbox-BDesthOp.js → listbox-DFd-1faX.js} +15 -16
  61. package/dist/{loader-Zo_VSsNw.cjs → loader-BRYL5kTN.cjs} +1 -1
  62. package/dist/{loader-Di5kHEQ4.js → loader-MoI2VRFr.js} +4 -4
  63. package/dist/{messagebox-CR59jv8N.cjs → messagebox-CiOQUt0C.cjs} +1 -1
  64. package/dist/{messagebox-CzaFlrYz.js → messagebox-Dr-k3pnZ.js} +4 -4
  65. package/dist/{modal-wEEmCcUx.cjs → modal-DGiq84MG.cjs} +1 -1
  66. package/dist/{modal-0D0paY70.js → modal-DbzEnZNF.js} +8 -8
  67. package/dist/option-group-element-CH0sgVIl.cjs +23 -0
  68. package/dist/{option-group-element-D5PgGNdt.js → option-group-element-DC364Rw_.js} +3 -3
  69. package/dist/pkt-accordion.cjs +1 -1
  70. package/dist/pkt-accordion.js +1 -2
  71. package/dist/pkt-alert.cjs +1 -1
  72. package/dist/pkt-alert.js +1 -2
  73. package/dist/pkt-backlink.js +1 -2
  74. package/dist/pkt-breadcrumbs.js +1 -2
  75. package/dist/pkt-button.cjs +1 -1
  76. package/dist/pkt-button.js +1 -2
  77. package/dist/pkt-calendar.cjs +1 -1
  78. package/dist/pkt-calendar.js +1 -2
  79. package/dist/pkt-card.cjs +1 -1
  80. package/dist/pkt-card.js +1 -2
  81. package/dist/pkt-checkbox-group.cjs +1 -1
  82. package/dist/pkt-checkbox-group.js +1 -2
  83. package/dist/pkt-checkbox.cjs +1 -1
  84. package/dist/pkt-checkbox.js +1 -2
  85. package/dist/pkt-combobox.cjs +1 -1
  86. package/dist/pkt-combobox.js +1 -2
  87. package/dist/pkt-consent.cjs +1 -1
  88. package/dist/pkt-consent.js +1 -2
  89. package/dist/pkt-datepicker.cjs +1 -1
  90. package/dist/pkt-datepicker.js +1 -1
  91. package/dist/pkt-fileupload.cjs +1 -1
  92. package/dist/pkt-fileupload.js +1 -2
  93. package/dist/pkt-footer.cjs +1 -1
  94. package/dist/pkt-footer.js +1 -2
  95. package/dist/pkt-header-menu.cjs +1 -1
  96. package/dist/pkt-header-menu.js +1 -2
  97. package/dist/pkt-header.cjs +1 -1
  98. package/dist/pkt-header.js +1 -2
  99. package/dist/pkt-heading.cjs +1 -1
  100. package/dist/pkt-heading.js +1 -2
  101. package/dist/pkt-helptext.cjs +1 -1
  102. package/dist/pkt-helptext.js +1 -2
  103. package/dist/pkt-icon.js +1 -2
  104. package/dist/pkt-index.cjs +1 -1
  105. package/dist/pkt-index.js +37 -37
  106. package/dist/pkt-input-wrapper.cjs +1 -1
  107. package/dist/pkt-input-wrapper.js +1 -2
  108. package/dist/pkt-link.cjs +1 -1
  109. package/dist/pkt-link.js +1 -2
  110. package/dist/pkt-linkcard.cjs +1 -1
  111. package/dist/pkt-linkcard.js +1 -2
  112. package/dist/pkt-listbox.cjs +1 -1
  113. package/dist/pkt-listbox.js +1 -2
  114. package/dist/pkt-loader.cjs +1 -1
  115. package/dist/pkt-loader.js +1 -2
  116. package/dist/pkt-messagebox.cjs +1 -1
  117. package/dist/pkt-messagebox.js +1 -2
  118. package/dist/pkt-modal.cjs +1 -1
  119. package/dist/pkt-modal.js +1 -2
  120. package/dist/{pkt-options-controller-CHosj1Oo.js → pkt-options-controller-BikFfGcZ.js} +1 -1
  121. package/dist/{pkt-options-controller-139UsV4h.cjs → pkt-options-controller-D1sKTkbR.cjs} +1 -1
  122. package/dist/pkt-progressbar.js +1 -2
  123. package/dist/pkt-radio-group.cjs +1 -1
  124. package/dist/pkt-radio-group.js +1 -2
  125. package/dist/pkt-radiobutton.cjs +1 -1
  126. package/dist/pkt-radiobutton.js +1 -2
  127. package/dist/pkt-searchinput.js +1 -2
  128. package/dist/pkt-select.cjs +1 -1
  129. package/dist/pkt-select.js +1 -2
  130. package/dist/pkt-tabs.cjs +1 -1
  131. package/dist/pkt-tabs.js +1 -2
  132. package/dist/pkt-tag.cjs +1 -1
  133. package/dist/pkt-tag.js +1 -2
  134. package/dist/pkt-textarea.cjs +1 -1
  135. package/dist/pkt-textarea.js +1 -2
  136. package/dist/pkt-textinput.cjs +1 -1
  137. package/dist/pkt-textinput.js +1 -2
  138. package/dist/pkt-timepicker.cjs +1 -1
  139. package/dist/pkt-timepicker.js +1 -2
  140. package/dist/{progressbar-DZHiq7B0.js → progressbar-t0zgEke0.js} +5 -5
  141. package/dist/{radio-group-CtZhXMF8.js → radio-group-DJikniZi.js} +3 -3
  142. package/dist/{radio-group-MxNLGu-0.cjs → radio-group-XCYKqoLD.cjs} +1 -1
  143. package/dist/{radiobutton-DwDErNo5.cjs → radiobutton-DgkML7sd.cjs} +1 -1
  144. package/dist/{radiobutton-BK-V6Itu.js → radiobutton-PYQKVnNQ.js} +4 -4
  145. package/dist/{ref-y_5qv9vU.js → ref-D4OwQYdf.js} +2 -2
  146. package/dist/{repeat-CV9S4zya.js → repeat-BGbBqnfz.js} +2 -2
  147. package/dist/{scroll-lock-BALd8hF9.js → scroll-lock-CR-g54ai.js} +1 -1
  148. package/dist/{scroll-lock-B46ur0FF.cjs → scroll-lock-x0VxhKWZ.cjs} +1 -1
  149. package/dist/{searchinput-Bkcr3Fby.js → searchinput-BzYifHBf.js} +4 -4
  150. package/dist/{select-Bs-Z5Thd.js → select-CorofYxz.js} +21 -21
  151. package/dist/{select-Czz1y2nI.cjs → select-D8TC1msV.cjs} +14 -14
  152. package/dist/shared-types/calendar.d.ts +0 -1
  153. package/dist/shared-types/icon.d.ts +2 -0
  154. package/dist/shared-types/index.d.ts +3 -1
  155. package/dist/shared-types/input-wrapper.d.ts +59 -0
  156. package/dist/shared-utils/calendar/calendar-grid.d.ts +0 -4
  157. package/dist/shared-utils/calendar/index.d.ts +1 -1
  158. package/dist/{tabs-R1Jzzj3-.cjs → tabs-B63J6MXb.cjs} +2 -2
  159. package/dist/{tabs-DBW3P90Z.js → tabs-DDakCTkY.js} +7 -15
  160. package/dist/{tag-BMtnaJ1A.cjs → tag-6IPe9bwQ.cjs} +1 -1
  161. package/dist/{tag-uVXp7uP-.js → tag-BPvGZcKf.js} +5 -5
  162. package/dist/{textarea-COHaMHpP.js → textarea-BZCUHjEj.js} +19 -19
  163. package/dist/{textarea-C-sdNBRk.cjs → textarea-BiCZBjOe.cjs} +10 -10
  164. package/dist/{textinput-BqBgsBZF.cjs → textinput-BZPGcxZV.cjs} +12 -12
  165. package/dist/{textinput-0DZeMqBr.js → textinput-D_oEaI41.js} +19 -19
  166. package/dist/{timepicker-C_k-K1jA.cjs → timepicker-C0d92R8u.cjs} +12 -12
  167. package/dist/{timepicker-CvdI7jDN.js → timepicker-JBOeZg-7.js} +24 -32
  168. package/package.json +2 -2
  169. package/src/components/calendar/calendar.constraints.test.ts +15 -0
  170. package/src/components/calendar/calendar.core.test.ts +15 -0
  171. package/src/components/calendar/calendar.ts +7 -15
  172. package/src/components/index.ts +1 -0
  173. package/src/components/input-wrapper/index.ts +1 -0
  174. package/src/components/input-wrapper/input-wrapper.test.ts +1 -0
  175. package/src/components/input-wrapper/input-wrapper.ts +38 -19
  176. package/src/components/input-wrapper/wrapper-parity.test.ts +4 -2
  177. package/dist/calendar-C5QwPrbk.cjs +0 -91
  178. package/dist/combobox-jsPpImVF.cjs +0 -139
  179. package/dist/converters-BJ9Fe0kW.cjs +0 -1
  180. package/dist/element-with-slot-CcJPCLgn.cjs +0 -1
  181. package/dist/input-wrapper-BwzajfFX.cjs +0 -63
  182. package/dist/option-group-element-CzehfgVZ.cjs +0 -23
@@ -1,4 +1,4 @@
1
- const e=require("./element-C6WTyJFE.cjs"),t=require("./class-map-Bh6toDeV.cjs"),n=require("./format-B8meU8Tm.cjs"),r=require("./element-with-slot-CcJPCLgn.cjs");require("./icon-jPhyZD1z.cjs");const i=require("./if-defined-CiML3MTM.cjs"),a=require("./ref-CB7e9nMY.cjs"),o=require("./input-element-BjnKPikY.cjs"),s=require("./input-wrapper-BwzajfFX.cjs");var c=e=>/^\d{2}:\d{2}$/.test(e)&&parseInt(e.slice(0,2),10)<=23&&parseInt(e.slice(3),10)<=59,l=e=>{let[t,n]=e.split(`:`).map(Number);return t*60+n},u=e=>e?Math.max(1,Math.round(e/60)):1,d=(e,t)=>{let n=e?parseInt(String(e).split(`:`)[0],10):0,r=t?parseInt(String(t).split(`:`)[0],10):23;return Array.from({length:r-n+1},(e,t)=>t+n)},f=e=>{let t=u(e);return Array.from({length:Math.floor(60/t)},(e,n)=>n*t)},p=(e,t,n,r)=>{let i=e===``?n===1?0:23:parseInt(e,10),a=t===``?n===1?0:Math.floor(59/r)*r:parseInt(t,10);return a+=n*r,a>59?(a=0,i=(i+1)%24):a<0&&(a=Math.floor(59/r)*r,i=(i-1+24)%24),{hours:String(i).padStart(2,`0`),minutes:String(a).padStart(2,`0`)}},m=class extends o.t{constructor(...e){super(...e),this.hiddenInputRef=a.t(),this.hoursInputRef=a.t(),this.minutesInputRef=a.t(),this.buttonRef=a.t(),this.value=``,this.hidePicker=!1,this.stepArrows=!1,this._hours=``,this._minutes=``,this._isOpen=!1,this._hoursDigitCount=0,this._hoursFirstDigit=-1,this._minutesDigitCount=0,this._minutesFirstDigit=-1,this._hasFocus=!1,this._outsideClickHandler=e=>{this.contains(e.target)||this._closePopup()},this._handleComponentFocusIn=()=>{this._hasFocus||(this._hasFocus=!0,this.onFocus())},this._handleComponentFocusOut=e=>{this.contains(e.relatedTarget)||(this._hasFocus=!1,this.onBlur())},this._handleHoursKeydown=e=>{let t=e.target;switch(e.key){case`ArrowUp`:{e.preventDefault();let t=this._hours===``?0:parseInt(this._hours,10);this._hours=String((t+1)%24).padStart(2,`0`),this._syncValueFromDisplay(),this.onInput();break}case`ArrowDown`:{e.preventDefault();let t=this._hours===``?0:parseInt(this._hours,10);this._hours=String((t-1+24)%24).padStart(2,`0`),this._syncValueFromDisplay(),this.onInput();break}case`ArrowRight`:e.preventDefault(),this.minutesInputRef.value?.focus();break;case`Backspace`:case`Delete`:this._hoursDigitCount=0,this._hoursFirstDigit=-1;break;case`Tab`:break;case`Enter`:{e.preventDefault();let n=this.internals.form;n?n.requestSubmit():t.blur();break}default:if(/^\d$/.test(e.key)){e.preventDefault();let t=parseInt(e.key,10);if(this._hoursDigitCount===0)this._hoursFirstDigit=t,this._hours=String(t).padStart(2,`0`),this._hoursDigitCount=1,this.onInput(),t>=3&&(this._hoursFirstDigit=-1,this._hoursDigitCount=0,this._syncValueFromDisplay(),this.minutesInputRef.value?.focus());else{let e=this._hoursFirstDigit*10+t;this._hours=e<=23?String(e).padStart(2,`0`):String(t).padStart(2,`0`),this._hoursFirstDigit=-1,this._hoursDigitCount=0,this._syncValueFromDisplay(),this.onInput(),this.minutesInputRef.value?.focus()}}else e.preventDefault()}},this._handleHoursBlur=()=>{this._hours!==``&&(this._hours=String(parseInt(this._hours,10)).padStart(2,`0`)),this._hoursDigitCount=0,this._hoursFirstDigit=-1,this._syncValueFromDisplay()},this._handleMinutesKeydown=e=>{let t=e.target;switch(e.key){case`ArrowUp`:{e.preventDefault();let t=this._minutes===``?0:parseInt(this._minutes,10);this._minutes=String((t+this._minuteStep)%60).padStart(2,`0`),this._syncValueFromDisplay(),this.onInput();break}case`ArrowDown`:{e.preventDefault();let t=this._minutes===``?0:parseInt(this._minutes,10);this._minutes=String((t-this._minuteStep+60)%60).padStart(2,`0`),this._syncValueFromDisplay(),this.onInput();break}case`ArrowLeft`:e.preventDefault(),this.hoursInputRef.value?.focus();break;case`Backspace`:case`Delete`:this._minutesDigitCount=0,this._minutesFirstDigit=-1;break;case`Tab`:break;case`Enter`:{e.preventDefault();let n=this.internals.form;n?n.requestSubmit():t.blur();break}default:if(/^\d$/.test(e.key)){e.preventDefault();let t=parseInt(e.key,10);if(this._minutesDigitCount===0)this._minutesFirstDigit=t,this._minutes=String(t).padStart(2,`0`),this._minutesDigitCount=1,this.onInput(),t>=6&&(this._minutesFirstDigit=-1,this._minutesDigitCount=0,this._syncValueFromDisplay());else{let e=this._minutesFirstDigit*10+t;this._minutes=e<=59?String(e).padStart(2,`0`):String(t).padStart(2,`0`),this._minutesFirstDigit=-1,this._minutesDigitCount=0,this._syncValueFromDisplay(),this.onInput()}}else e.preventDefault()}},this._handleMinutesBlur=()=>{this._minutes!==``&&(this._minutes=String(parseInt(this._minutes,10)).padStart(2,`0`)),this._minutesDigitCount=0,this._minutesFirstDigit=-1,this._syncValueFromDisplay()},this._handlePopupKeydown=e=>{let t=document.activeElement,n=t.closest(`.pkt-timepicker-popup__col`);if(!n)return;let r=Array.from(n.querySelectorAll(`.pkt-timepicker-popup__option`)),i=r.indexOf(t),a=t.dataset.type??``;switch(e.key){case`ArrowDown`:e.preventDefault(),this._focusOptionAndSync(r[Math.min(i+1,r.length-1)],a);break;case`ArrowUp`:e.preventDefault(),this._focusOptionAndSync(r[Math.max(i-1,0)],a);break;case`Home`:e.preventDefault(),this._focusOptionAndSync(r[0],a);break;case`End`:e.preventDefault(),this._focusOptionAndSync(r[r.length-1],a);break;case`ArrowRight`:e.preventDefault(),a===`hour`&&(this._focusOptionAndSync(t,a),this.updateComplete.then(()=>{this._scrollToSelected(),this._focusSelectedOrFirst(`minute`)}));break;case`ArrowLeft`:e.preventDefault(),a===`minute`&&(this._focusOptionAndSync(t,a),this.updateComplete.then(()=>{this._scrollToSelected(),this._focusSelectedOrFirst(`hour`)}));break;case`Enter`:case` `:e.preventDefault(),t.click();break;case`Escape`:e.preventDefault(),this._closePopup(),this.buttonRef.value?.focus()}}}get inputRef(){return this.hiddenInputRef}manageValidity(e){let t=this.hoursInputRef.value;if(!t)return;let r=this.pktStrings.get(`validation`);if(this.required&&!this.value){this.internals.setValidity({valueMissing:!0},r.valueMissing,t),this._setAriaInvalid(!0);return}if(!this.value){this.internals.setValidity({}),this._setAriaInvalid(!1);return}let i=l(this.value),a=u(this.step);if(this.min&&i<l(String(this.min))){this.internals.setValidity({rangeUnderflow:!0},n.t(r.rangeUnderflowMin,{min:String(this.min)}),t),this._setAriaInvalid(!0);return}if(this.max&&i>l(String(this.max))){this.internals.setValidity({rangeOverflow:!0},n.t(r.rangeOverflowMax,{max:String(this.max)}),t),this._setAriaInvalid(!0);return}if(this.step&&i%a!==0){let e=a===60?r.timeStepMismatchHour:a===30?r.timeStepMismatchHalfHour:n.t(r.timeStepMismatch,{step:`${a}, ${a*2}, ${a*3}`});this.internals.setValidity({stepMismatch:!0},e,t),this._setAriaInvalid(!0);return}this.internals.setValidity({}),this._setAriaInvalid(!1)}_describedBy(){return s.r({id:`${this.id}-hours`,hasHelptext:!!this.helptext||this.hasSlotContent(`helptext`),ariaDescribedby:this.ariaDescribedby})}_setAriaInvalid(e){if(!this.touched&&e)return;let t=this.hoursInputRef.value,n=this.minutesInputRef.value;if(e)t?.setAttribute(`aria-invalid`,`true`),n?.setAttribute(`aria-invalid`,`true`);else{if(this.hasError)return;t?.removeAttribute(`aria-invalid`),n?.removeAttribute(`aria-invalid`)}}connectedCallback(){super.connectedCallback(),this.addEventListener(`focusin`,this._handleComponentFocusIn),this.addEventListener(`focusout`,this._handleComponentFocusOut),document.addEventListener(`click`,this._outsideClickHandler)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener(`focusin`,this._handleComponentFocusIn),this.removeEventListener(`focusout`,this._handleComponentFocusOut),document.removeEventListener(`click`,this._outsideClickHandler)}willUpdate(e){super.willUpdate(e),e.has(`value`)&&this._syncDisplayFromValue()}updated(e){super.updated(e),this.classList.add(`pkt-timepicker`),this.classList.toggle(`pkt-timepicker--stepper`,this.stepArrows),this.classList.toggle(`pkt-timepicker--fullwidth`,this.fullwidth),this.classList.toggle(`pkt-timepicker--medium`,this.inputSize===`medium`),this.classList.toggle(`pkt-timepicker--small`,this.inputSize===`small`),this.classList.toggle(`pkt-timepicker--xsmall`,this.inputSize===`xsmall`),e.has(`step`)&&this.step!==null&&!this._isValidStep(this.step)&&console.warn(`pkt-timepicker: step="${this.step}" er ikke en gyldig verdi. Step må være et multiplum av 60 (hele minutter) eller nøyaktig 3600 (hel time).`)}formResetCallback(){super.formResetCallback(),this._hours=``,this._minutes=``,this._isOpen=!1}_isValidStep(e){return e===3600||e<3600&&3600%e==0&&e%60==0}_syncDisplayFromValue(){let e=c(this.value)?this.value.split(`:`):null;e?(this._hours=e[0],this._minutes=e[1]):(this._hours=``,this._minutes=``)}_syncValueFromDisplay(){if(this._hours!==``&&this._minutes!==``){let e=`${this._hours}:${this._minutes}`;e!==this.value&&(this.value=e,this.onChange(e))}else this.value!==``&&(this.value=``,this.onChange(``))}get _minuteStep(){return u(this.step)}get _hourOptions(){return d(this.min,this.max)}get _minuteOptions(){return f(this.step)}_openPopup(){this._isOpen=!0,this.updateComplete.then(()=>{this._scrollToSelected(),this._focusSelectedOrFirst(`hour`)})}_closePopup(){this._isOpen=!1,this._syncValueFromDisplay()}_togglePopup(){this._isOpen?this._closePopup():this._openPopup()}_scrollToSelected(){let e=this.querySelector(`.pkt-timepicker-popup`);e&&e.querySelectorAll(`.pkt-timepicker-popup__col`).forEach(e=>{let t=e.querySelector(`.pkt-timepicker-popup__option--selected`);t&&t.scrollIntoView({block:`center`})})}_focusSelectedOrFirst(e){let t=this.querySelector(`.pkt-timepicker-popup`);if(!t)return;let n=t.querySelectorAll(`.pkt-timepicker-popup__col`),r=e===`hour`?n[0]:n[1];if(!r)return;let i=r.querySelector(`.pkt-timepicker-popup__option--selected`),a=r.querySelector(`.pkt-timepicker-popup__option`);(i||a)?.focus()}_handleOptionClick(e,t){let n=String(e).padStart(2,`0`);t===`hour`?(this._hours=n,this.updateComplete.then(()=>this._focusSelectedOrFirst(`minute`))):(this._minutes=n,this._closePopup(),this.buttonRef.value?.focus())}_focusOptionAndSync(e,t){if(!e)return;let n=parseInt(e.dataset.value??`0`,10);t===`hour`?this._hours=String(n).padStart(2,`0`):this._minutes=String(n).padStart(2,`0`),e.focus()}_stepTime(e){let t=p(this._hours,this._minutes,e,this._minuteStep);this._hours=t.hours,this._minutes=t.minutes,this._syncValueFromDisplay()}_renderOption(n,r){let i=String(n).padStart(2,`0`),a=n===(r===`hour`?this._hours===``?NaN:parseInt(this._hours,10):this._minutes===``?NaN:parseInt(this._minutes,10));return e._`
1
+ const e=require("./element-C6WTyJFE.cjs"),t=require("./class-map-Bh6toDeV.cjs"),n=require("./format-B8meU8Tm.cjs"),r=require("./element-with-slot-DkyaNnm0.cjs");require("./icon-jPhyZD1z.cjs");const i=require("./input-wrapper-4PTk8aX3.cjs"),a=require("./if-defined-CiML3MTM.cjs"),o=require("./ref-CB7e9nMY.cjs"),s=require("./input-element-BOi7rBbw.cjs");var c=e=>/^\d{2}:\d{2}$/.test(e)&&parseInt(e.slice(0,2),10)<=23&&parseInt(e.slice(3),10)<=59,l=e=>{let[t,n]=e.split(`:`).map(Number);return t*60+n},u=e=>e?Math.max(1,Math.round(e/60)):1,d=(e,t)=>{let n=e?parseInt(String(e).split(`:`)[0],10):0,r=t?parseInt(String(t).split(`:`)[0],10):23;return Array.from({length:r-n+1},(e,t)=>t+n)},f=e=>{let t=u(e);return Array.from({length:Math.floor(60/t)},(e,n)=>n*t)},p=(e,t,n,r)=>{let i=e===``?n===1?0:23:parseInt(e,10),a=t===``?n===1?0:Math.floor(59/r)*r:parseInt(t,10);return a+=n*r,a>59?(a=0,i=(i+1)%24):a<0&&(a=Math.floor(59/r)*r,i=(i-1+24)%24),{hours:String(i).padStart(2,`0`),minutes:String(a).padStart(2,`0`)}},m=class extends s.t{constructor(...e){super(...e),this.hiddenInputRef=o.t(),this.hoursInputRef=o.t(),this.minutesInputRef=o.t(),this.buttonRef=o.t(),this.value=``,this.hidePicker=!1,this.stepArrows=!1,this._hours=``,this._minutes=``,this._isOpen=!1,this._hoursDigitCount=0,this._hoursFirstDigit=-1,this._minutesDigitCount=0,this._minutesFirstDigit=-1,this._hasFocus=!1,this._outsideClickHandler=e=>{this.contains(e.target)||this._closePopup()},this._handleComponentFocusIn=()=>{this._hasFocus||(this._hasFocus=!0,this.onFocus())},this._handleComponentFocusOut=e=>{this.contains(e.relatedTarget)||(this._hasFocus=!1,this.onBlur())},this._handleHoursKeydown=e=>{let t=e.target;switch(e.key){case`ArrowUp`:{e.preventDefault();let t=this._hours===``?0:parseInt(this._hours,10);this._hours=String((t+1)%24).padStart(2,`0`),this._syncValueFromDisplay(),this.onInput();break}case`ArrowDown`:{e.preventDefault();let t=this._hours===``?0:parseInt(this._hours,10);this._hours=String((t-1+24)%24).padStart(2,`0`),this._syncValueFromDisplay(),this.onInput();break}case`ArrowRight`:e.preventDefault(),this.minutesInputRef.value?.focus();break;case`Backspace`:case`Delete`:this._hoursDigitCount=0,this._hoursFirstDigit=-1;break;case`Tab`:break;case`Enter`:{e.preventDefault();let n=this.internals.form;n?n.requestSubmit():t.blur();break}default:if(/^\d$/.test(e.key)){e.preventDefault();let t=parseInt(e.key,10);if(this._hoursDigitCount===0)this._hoursFirstDigit=t,this._hours=String(t).padStart(2,`0`),this._hoursDigitCount=1,this.onInput(),t>=3&&(this._hoursFirstDigit=-1,this._hoursDigitCount=0,this._syncValueFromDisplay(),this.minutesInputRef.value?.focus());else{let e=this._hoursFirstDigit*10+t;this._hours=e<=23?String(e).padStart(2,`0`):String(t).padStart(2,`0`),this._hoursFirstDigit=-1,this._hoursDigitCount=0,this._syncValueFromDisplay(),this.onInput(),this.minutesInputRef.value?.focus()}}else e.preventDefault()}},this._handleHoursBlur=()=>{this._hours!==``&&(this._hours=String(parseInt(this._hours,10)).padStart(2,`0`)),this._hoursDigitCount=0,this._hoursFirstDigit=-1,this._syncValueFromDisplay()},this._handleMinutesKeydown=e=>{let t=e.target;switch(e.key){case`ArrowUp`:{e.preventDefault();let t=this._minutes===``?0:parseInt(this._minutes,10);this._minutes=String((t+this._minuteStep)%60).padStart(2,`0`),this._syncValueFromDisplay(),this.onInput();break}case`ArrowDown`:{e.preventDefault();let t=this._minutes===``?0:parseInt(this._minutes,10);this._minutes=String((t-this._minuteStep+60)%60).padStart(2,`0`),this._syncValueFromDisplay(),this.onInput();break}case`ArrowLeft`:e.preventDefault(),this.hoursInputRef.value?.focus();break;case`Backspace`:case`Delete`:this._minutesDigitCount=0,this._minutesFirstDigit=-1;break;case`Tab`:break;case`Enter`:{e.preventDefault();let n=this.internals.form;n?n.requestSubmit():t.blur();break}default:if(/^\d$/.test(e.key)){e.preventDefault();let t=parseInt(e.key,10);if(this._minutesDigitCount===0)this._minutesFirstDigit=t,this._minutes=String(t).padStart(2,`0`),this._minutesDigitCount=1,this.onInput(),t>=6&&(this._minutesFirstDigit=-1,this._minutesDigitCount=0,this._syncValueFromDisplay());else{let e=this._minutesFirstDigit*10+t;this._minutes=e<=59?String(e).padStart(2,`0`):String(t).padStart(2,`0`),this._minutesFirstDigit=-1,this._minutesDigitCount=0,this._syncValueFromDisplay(),this.onInput()}}else e.preventDefault()}},this._handleMinutesBlur=()=>{this._minutes!==``&&(this._minutes=String(parseInt(this._minutes,10)).padStart(2,`0`)),this._minutesDigitCount=0,this._minutesFirstDigit=-1,this._syncValueFromDisplay()},this._handlePopupKeydown=e=>{let t=document.activeElement,n=t.closest(`.pkt-timepicker-popup__col`);if(!n)return;let r=Array.from(n.querySelectorAll(`.pkt-timepicker-popup__option`)),i=r.indexOf(t),a=t.dataset.type??``;switch(e.key){case`ArrowDown`:e.preventDefault(),this._focusOptionAndSync(r[Math.min(i+1,r.length-1)],a);break;case`ArrowUp`:e.preventDefault(),this._focusOptionAndSync(r[Math.max(i-1,0)],a);break;case`Home`:e.preventDefault(),this._focusOptionAndSync(r[0],a);break;case`End`:e.preventDefault(),this._focusOptionAndSync(r[r.length-1],a);break;case`ArrowRight`:e.preventDefault(),a===`hour`&&(this._focusOptionAndSync(t,a),this.updateComplete.then(()=>{this._scrollToSelected(),this._focusSelectedOrFirst(`minute`)}));break;case`ArrowLeft`:e.preventDefault(),a===`minute`&&(this._focusOptionAndSync(t,a),this.updateComplete.then(()=>{this._scrollToSelected(),this._focusSelectedOrFirst(`hour`)}));break;case`Enter`:case` `:e.preventDefault(),t.click();break;case`Escape`:e.preventDefault(),this._closePopup(),this.buttonRef.value?.focus()}}}get inputRef(){return this.hiddenInputRef}manageValidity(e){let t=this.hoursInputRef.value;if(!t)return;let r=this.pktStrings.get(`validation`);if(this.required&&!this.value){this.internals.setValidity({valueMissing:!0},r.valueMissing,t),this._setAriaInvalid(!0);return}if(!this.value){this.internals.setValidity({}),this._setAriaInvalid(!1);return}let i=l(this.value),a=u(this.step);if(this.min&&i<l(String(this.min)))this.internals.setValidity({rangeUnderflow:!0},n.t(r.rangeUnderflowMin,{min:String(this.min)}),t),this._setAriaInvalid(!0);else if(this.max&&i>l(String(this.max)))this.internals.setValidity({rangeOverflow:!0},n.t(r.rangeOverflowMax,{max:String(this.max)}),t),this._setAriaInvalid(!0);else if(this.step&&i%a!==0){let e=a===60?r.timeStepMismatchHour:a===30?r.timeStepMismatchHalfHour:n.t(r.timeStepMismatch,{step:`${a}, ${a*2}, ${a*3}`});this.internals.setValidity({stepMismatch:!0},e,t),this._setAriaInvalid(!0)}else this.internals.setValidity({}),this._setAriaInvalid(!1)}_describedBy(){return i.r({id:`${this.id}-hours`,hasHelptext:!!this.helptext||this.hasSlotContent(`helptext`),ariaDescribedby:this.ariaDescribedby})}_setAriaInvalid(e){if(!this.touched&&e)return;let t=this.hoursInputRef.value,n=this.minutesInputRef.value;if(e)t?.setAttribute(`aria-invalid`,`true`),n?.setAttribute(`aria-invalid`,`true`);else{if(this.hasError)return;t?.removeAttribute(`aria-invalid`),n?.removeAttribute(`aria-invalid`)}}connectedCallback(){super.connectedCallback(),this.addEventListener(`focusin`,this._handleComponentFocusIn),this.addEventListener(`focusout`,this._handleComponentFocusOut),document.addEventListener(`click`,this._outsideClickHandler)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener(`focusin`,this._handleComponentFocusIn),this.removeEventListener(`focusout`,this._handleComponentFocusOut),document.removeEventListener(`click`,this._outsideClickHandler)}willUpdate(e){super.willUpdate(e),e.has(`value`)&&this._syncDisplayFromValue()}updated(e){super.updated(e),this.classList.add(`pkt-timepicker`),this.classList.toggle(`pkt-timepicker--stepper`,this.stepArrows),this.classList.toggle(`pkt-timepicker--fullwidth`,this.fullwidth),this.classList.toggle(`pkt-timepicker--medium`,this.inputSize===`medium`),this.classList.toggle(`pkt-timepicker--small`,this.inputSize===`small`),this.classList.toggle(`pkt-timepicker--xsmall`,this.inputSize===`xsmall`),e.has(`step`)&&this.step!==null&&!this._isValidStep(this.step)&&console.warn(`pkt-timepicker: step="${this.step}" er ikke en gyldig verdi. Step må være et multiplum av 60 (hele minutter) eller nøyaktig 3600 (hel time).`)}formResetCallback(){super.formResetCallback(),this._hours=``,this._minutes=``,this._isOpen=!1}_isValidStep(e){return e===3600||e<3600&&3600%e==0&&e%60==0}_syncDisplayFromValue(){let e=c(this.value)?this.value.split(`:`):null;e?(this._hours=e[0],this._minutes=e[1]):(this._hours=``,this._minutes=``)}_syncValueFromDisplay(){if(this._hours!==``&&this._minutes!==``){let e=`${this._hours}:${this._minutes}`;e!==this.value&&(this.value=e,this.onChange(e))}else this.value!==``&&(this.value=``,this.onChange(``))}get _minuteStep(){return u(this.step)}get _hourOptions(){return d(this.min,this.max)}get _minuteOptions(){return f(this.step)}_openPopup(){this._isOpen=!0,this.updateComplete.then(()=>{this._scrollToSelected(),this._focusSelectedOrFirst(`hour`)})}_closePopup(){this._isOpen=!1,this._syncValueFromDisplay()}_togglePopup(){this._isOpen?this._closePopup():this._openPopup()}_scrollToSelected(){let e=this.querySelector(`.pkt-timepicker-popup`);e&&e.querySelectorAll(`.pkt-timepicker-popup__col`).forEach(e=>{let t=e.querySelector(`.pkt-timepicker-popup__option--selected`);t&&t.scrollIntoView({block:`center`})})}_focusSelectedOrFirst(e){let t=this.querySelector(`.pkt-timepicker-popup`);if(!t)return;let n=t.querySelectorAll(`.pkt-timepicker-popup__col`),r=e===`hour`?n[0]:n[1];if(!r)return;let i=r.querySelector(`.pkt-timepicker-popup__option--selected`),a=r.querySelector(`.pkt-timepicker-popup__option`);(i||a)?.focus()}_handleOptionClick(e,t){let n=String(e).padStart(2,`0`);t===`hour`?(this._hours=n,this.updateComplete.then(()=>this._focusSelectedOrFirst(`minute`))):(this._minutes=n,this._closePopup(),this.buttonRef.value?.focus())}_focusOptionAndSync(e,t){if(!e)return;let n=parseInt(e.dataset.value??`0`,10);t===`hour`?this._hours=String(n).padStart(2,`0`):this._minutes=String(n).padStart(2,`0`),e.focus()}_stepTime(e){let t=p(this._hours,this._minutes,e,this._minuteStep);this._hours=t.hours,this._minutes=t.minutes,this._syncValueFromDisplay()}_renderOption(n,r){let i=String(n).padStart(2,`0`),a=n===(r===`hour`?this._hours===``?NaN:parseInt(this._hours,10):this._minutes===``?NaN:parseInt(this._minutes,10));return e._`
2
2
  <button
3
3
  class=${t.t({"pkt-btn":!0,"pkt-btn--tertiary":!0,"pkt-btn--small":!0,"pkt-btn--label-only":!0,"pkt-timepicker-popup__option":!0,"pkt-timepicker-popup__option--selected":a})}
4
4
  type="button"
@@ -38,7 +38,7 @@ const e=require("./element-C6WTyJFE.cjs"),t=require("./class-map-Bh6toDeV.cjs"),
38
38
  ${this._minuteOptions.map(e=>this._renderOption(e,`minute`))}
39
39
  </div>
40
40
  </div>
41
- `}_renderContainer(){let t=this.pktStrings.get(`timepicker`).hours,n=this.pktStrings.get(`timepicker`).minutes,r=this.label?`${t}, ${this.label}`:t,o=this.label?`${n}, ${this.label}`:n;return e._`
41
+ `}_renderContainer(){let t=this.pktStrings.get(`timepicker`).hours,n=this.pktStrings.get(`timepicker`).minutes,r=this.label?`${t}, ${this.label}`:t,i=this.label?`${n}, ${this.label}`:n;return e._`
42
42
  <div
43
43
  class="pkt-input__container pkt-input__container--${this.inputSize}"
44
44
  @click=${e=>{e.target.closest(`button, input`)||this.hoursInputRef.value?.focus()}}
@@ -58,7 +58,7 @@ const e=require("./element-C6WTyJFE.cjs"),t=require("./class-map-Bh6toDeV.cjs"),
58
58
  </button>
59
59
  `:e.h}
60
60
  <input
61
- ${a.n(this.hoursInputRef)}
61
+ ${o.n(this.hoursInputRef)}
62
62
  type="text"
63
63
  inputmode="numeric"
64
64
  maxlength="2"
@@ -73,7 +73,7 @@ const e=require("./element-C6WTyJFE.cjs"),t=require("./class-map-Bh6toDeV.cjs"),
73
73
  role="spinbutton"
74
74
  aria-invalid=${this.hasError?`true`:e.h}
75
75
  aria-errormessage=${this.hasError?`${this.id}-hours-error`:e.h}
76
- aria-describedby=${i.t(this._describedBy())}
76
+ aria-describedby=${a.t(this._describedBy())}
77
77
  aria-valuemin="0"
78
78
  aria-valuemax="23"
79
79
  aria-valuenow=${this._hours===``?e.h:this._hours}
@@ -86,7 +86,7 @@ const e=require("./element-C6WTyJFE.cjs"),t=require("./class-map-Bh6toDeV.cjs"),
86
86
  />
87
87
  <span class="pkt-timepicker__separator">:</span>
88
88
  <input
89
- ${a.n(this.minutesInputRef)}
89
+ ${o.n(this.minutesInputRef)}
90
90
  type="text"
91
91
  inputmode="numeric"
92
92
  maxlength="2"
@@ -97,11 +97,11 @@ const e=require("./element-C6WTyJFE.cjs"),t=require("./class-map-Bh6toDeV.cjs"),
97
97
  data-max="59"
98
98
  .value=${this._minutes}
99
99
  placeholder="––"
100
- aria-label=${o}
100
+ aria-label=${i}
101
101
  role="spinbutton"
102
102
  aria-invalid=${this.hasError?`true`:e.h}
103
103
  aria-errormessage=${this.hasError?`${this.id}-hours-error`:e.h}
104
- aria-describedby=${i.t(this._describedBy())}
104
+ aria-describedby=${a.t(this._describedBy())}
105
105
  aria-valuemin="0"
106
106
  aria-valuemax="59"
107
107
  aria-valuenow=${this._minutes===``?e.h:this._minutes}
@@ -119,7 +119,7 @@ const e=require("./element-C6WTyJFE.cjs"),t=require("./class-map-Bh6toDeV.cjs"),
119
119
  ></pkt-icon>`:e.h}
120
120
  ${!this.hidePicker&&!this.stepArrows?e._`
121
121
  <button
122
- ${a.n(this.buttonRef)}
122
+ ${o.n(this.buttonRef)}
123
123
  class="pkt-input-icon pkt-btn pkt-btn--icon-only pkt-btn--tertiary pkt-btn--${this.inputSize} pkt-timepicker__button"
124
124
  type="button"
125
125
  aria-label=${this.pktStrings.get(`timepicker`).openPicker}
@@ -150,15 +150,15 @@ const e=require("./element-C6WTyJFE.cjs"),t=require("./class-map-Bh6toDeV.cjs"),
150
150
  </button>
151
151
  `:e.h}
152
152
  <input
153
- ${a.n(this.hiddenInputRef)}
153
+ ${o.n(this.hiddenInputRef)}
154
154
  type="time"
155
155
  hidden
156
156
  name=${this.name||this.id}
157
157
  id=${this.id+`-input`}
158
158
  .value=${this.value}
159
- min=${i.t(this.min??void 0)}
160
- max=${i.t(this.max??void 0)}
161
- step=${i.t(this.step??void 0)}
159
+ min=${a.t(this.min??void 0)}
160
+ max=${a.t(this.max??void 0)}
161
+ step=${a.t(this.step??void 0)}
162
162
  ?required=${this.required}
163
163
  ?disabled=${this.isDisabled}
164
164
  tabindex="-1"
@@ -1,12 +1,12 @@
1
- import { _ as e, d as t, h as n, l as r, n as i, u as a } from "./element-DBugHPKM.js";
2
- import { t as o } from "./class-map-Bf-QzUpN.js";
1
+ import { _ as e, d as t, h as n, l as r, n as i, u as a } from "./element-ckeMVgMz.js";
2
+ import { t as o } from "./class-map-BkEYw5uE.js";
3
3
  import { t as s } from "./format-BTeSVkED.js";
4
- import { n as c } from "./element-with-slot-CVmm0_IE.js";
5
- import "./icon-Bao96Zb8.js";
6
- import { t as l } from "./if-defined-O59_I-e-.js";
7
- import { n as u, t as d } from "./ref-y_5qv9vU.js";
8
- import { t as f } from "./input-element-mTphzs9b.js";
9
- import { r as p } from "./input-wrapper-Bb6CZxmg.js";
4
+ import { n as c } from "./element-with-slot-C0bH0T0H.js";
5
+ import "./icon-CLMJYuTL.js";
6
+ import { r as l } from "./input-wrapper-BSjQc4Vx.js";
7
+ import { t as u } from "./if-defined-D18nY_K_.js";
8
+ import { n as d, t as f } from "./ref-D4OwQYdf.js";
9
+ import { t as p } from "./input-element-0yYtRu0p.js";
10
10
  //#region ../../shared-utils/timepicker/time-utils.ts
11
11
  var m = (e) => /^\d{2}:\d{2}$/.test(e) && parseInt(e.slice(0, 2), 10) <= 23 && parseInt(e.slice(3), 10) <= 59, h = (e) => {
12
12
  let [t, n] = e.split(":").map(Number);
@@ -23,9 +23,9 @@ var m = (e) => /^\d{2}:\d{2}$/.test(e) && parseInt(e.slice(0, 2), 10) <= 23 && p
23
23
  hours: String(i).padStart(2, "0"),
24
24
  minutes: String(a).padStart(2, "0")
25
25
  };
26
- }, b = class extends f {
26
+ }, b = class extends p {
27
27
  constructor(...e) {
28
- super(...e), this.hiddenInputRef = d(), this.hoursInputRef = d(), this.minutesInputRef = d(), this.buttonRef = d(), this.value = "", this.hidePicker = !1, this.stepArrows = !1, this._hours = "", this._minutes = "", this._isOpen = !1, this._hoursDigitCount = 0, this._hoursFirstDigit = -1, this._minutesDigitCount = 0, this._minutesFirstDigit = -1, this._hasFocus = !1, this._outsideClickHandler = (e) => {
28
+ super(...e), this.hiddenInputRef = f(), this.hoursInputRef = f(), this.minutesInputRef = f(), this.buttonRef = f(), this.value = "", this.hidePicker = !1, this.stepArrows = !1, this._hours = "", this._minutes = "", this._isOpen = !1, this._hoursDigitCount = 0, this._hoursFirstDigit = -1, this._minutesDigitCount = 0, this._minutesFirstDigit = -1, this._hasFocus = !1, this._outsideClickHandler = (e) => {
29
29
  this.contains(e.target) || this._closePopup();
30
30
  }, this._handleComponentFocusIn = () => {
31
31
  this._hasFocus || (this._hasFocus = !0, this.onFocus());
@@ -164,23 +164,15 @@ var m = (e) => /^\d{2}:\d{2}$/.test(e) && parseInt(e.slice(0, 2), 10) <= 23 && p
164
164
  return;
165
165
  }
166
166
  let r = h(this.value), i = g(this.step);
167
- if (this.min && r < h(String(this.min))) {
168
- this.internals.setValidity({ rangeUnderflow: !0 }, s(n.rangeUnderflowMin, { min: String(this.min) }), t), this._setAriaInvalid(!0);
169
- return;
170
- }
171
- if (this.max && r > h(String(this.max))) {
172
- this.internals.setValidity({ rangeOverflow: !0 }, s(n.rangeOverflowMax, { max: String(this.max) }), t), this._setAriaInvalid(!0);
173
- return;
174
- }
175
- if (this.step && r % i !== 0) {
167
+ if (this.min && r < h(String(this.min))) this.internals.setValidity({ rangeUnderflow: !0 }, s(n.rangeUnderflowMin, { min: String(this.min) }), t), this._setAriaInvalid(!0);
168
+ else if (this.max && r > h(String(this.max))) this.internals.setValidity({ rangeOverflow: !0 }, s(n.rangeOverflowMax, { max: String(this.max) }), t), this._setAriaInvalid(!0);
169
+ else if (this.step && r % i !== 0) {
176
170
  let e = i === 60 ? n.timeStepMismatchHour : i === 30 ? n.timeStepMismatchHalfHour : s(n.timeStepMismatch, { step: `${i}, ${i * 2}, ${i * 3}` });
177
171
  this.internals.setValidity({ stepMismatch: !0 }, e, t), this._setAriaInvalid(!0);
178
- return;
179
- }
180
- this.internals.setValidity({}), this._setAriaInvalid(!1);
172
+ } else this.internals.setValidity({}), this._setAriaInvalid(!1);
181
173
  }
182
174
  _describedBy() {
183
- return p({
175
+ return l({
184
176
  id: `${this.id}-hours`,
185
177
  hasHelptext: !!this.helptext || this.hasSlotContent("helptext"),
186
178
  ariaDescribedby: this.ariaDescribedby
@@ -353,7 +345,7 @@ var m = (e) => /^\d{2}:\d{2}$/.test(e) && parseInt(e.slice(0, 2), 10) <= 23 && p
353
345
  </button>
354
346
  ` : n}
355
347
  <input
356
- ${u(this.hoursInputRef)}
348
+ ${d(this.hoursInputRef)}
357
349
  type="text"
358
350
  inputmode="numeric"
359
351
  maxlength="2"
@@ -368,7 +360,7 @@ var m = (e) => /^\d{2}:\d{2}$/.test(e) && parseInt(e.slice(0, 2), 10) <= 23 && p
368
360
  role="spinbutton"
369
361
  aria-invalid=${this.hasError ? "true" : n}
370
362
  aria-errormessage=${this.hasError ? `${this.id}-hours-error` : n}
371
- aria-describedby=${l(this._describedBy())}
363
+ aria-describedby=${u(this._describedBy())}
372
364
  aria-valuemin="0"
373
365
  aria-valuemax="23"
374
366
  aria-valuenow=${this._hours === "" ? n : this._hours}
@@ -383,7 +375,7 @@ var m = (e) => /^\d{2}:\d{2}$/.test(e) && parseInt(e.slice(0, 2), 10) <= 23 && p
383
375
  />
384
376
  <span class="pkt-timepicker__separator">:</span>
385
377
  <input
386
- ${u(this.minutesInputRef)}
378
+ ${d(this.minutesInputRef)}
387
379
  type="text"
388
380
  inputmode="numeric"
389
381
  maxlength="2"
@@ -398,7 +390,7 @@ var m = (e) => /^\d{2}:\d{2}$/.test(e) && parseInt(e.slice(0, 2), 10) <= 23 && p
398
390
  role="spinbutton"
399
391
  aria-invalid=${this.hasError ? "true" : n}
400
392
  aria-errormessage=${this.hasError ? `${this.id}-hours-error` : n}
401
- aria-describedby=${l(this._describedBy())}
393
+ aria-describedby=${u(this._describedBy())}
402
394
  aria-valuemin="0"
403
395
  aria-valuemax="59"
404
396
  aria-valuenow=${this._minutes === "" ? n : this._minutes}
@@ -418,7 +410,7 @@ var m = (e) => /^\d{2}:\d{2}$/.test(e) && parseInt(e.slice(0, 2), 10) <= 23 && p
418
410
  ></pkt-icon>` : n}
419
411
  ${!this.hidePicker && !this.stepArrows ? e`
420
412
  <button
421
- ${u(this.buttonRef)}
413
+ ${d(this.buttonRef)}
422
414
  class="pkt-input-icon pkt-btn pkt-btn--icon-only pkt-btn--tertiary pkt-btn--${this.inputSize} pkt-timepicker__button"
423
415
  type="button"
424
416
  aria-label=${this.pktStrings.get("timepicker").openPicker}
@@ -449,15 +441,15 @@ var m = (e) => /^\d{2}:\d{2}$/.test(e) && parseInt(e.slice(0, 2), 10) <= 23 && p
449
441
  </button>
450
442
  ` : n}
451
443
  <input
452
- ${u(this.hiddenInputRef)}
444
+ ${d(this.hiddenInputRef)}
453
445
  type="time"
454
446
  hidden
455
447
  name=${this.name || this.id}
456
448
  id=${this.id + "-input"}
457
449
  .value=${this.value}
458
- min=${l(this.min ?? void 0)}
459
- max=${l(this.max ?? void 0)}
460
- step=${l(this.step ?? void 0)}
450
+ min=${u(this.min ?? void 0)}
451
+ max=${u(this.max ?? void 0)}
452
+ step=${u(this.step ?? void 0)}
461
453
  ?required=${this.required}
462
454
  ?disabled=${this.isDisabled}
463
455
  tabindex="-1"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oslokommune/punkt-elements",
3
- "version": "19.15.0",
3
+ "version": "19.17.0",
4
4
  "description": "Komponentbiblioteket til Punkt, designsystem for Oslo kommune",
5
5
  "homepage": "https://punkt.oslo.kommune.no",
6
6
  "author": "Team Designsystem, Oslo kommune",
@@ -84,5 +84,5 @@
84
84
  "engines": {
85
85
  "node": "^22.19.0 || ^24.0.0 || ^26.0.0"
86
86
  },
87
- "gitHead": "3d719ef8a2e368d08d6111be152f9a6c1b64da1e"
87
+ "gitHead": "85027304cea63a12d61597a0b283cf33f0aaefdb"
88
88
  }
@@ -41,6 +41,21 @@ describe('PktCalendar', () => {
41
41
  expect(disabledDates.length).toBeGreaterThan(0)
42
42
  })
43
43
 
44
+ test('marks month navigation as disabled outside earliest and latest', async () => {
45
+ const container = await createCalendar(
46
+ 'earliest="2024-10-05" latest="2024-10-25" currentmonth="2024-10-01"',
47
+ )
48
+
49
+ const calendar = container.querySelector('pkt-calendar') as PktCalendar
50
+ await calendar.updateComplete
51
+
52
+ for (const selector of ['.pkt-calendar__prev-month', '.pkt-calendar__next-month']) {
53
+ const button = calendar.querySelector(selector)
54
+ expect(button).toHaveAttribute('aria-disabled', 'true')
55
+ expect(button).toHaveAttribute('data-disabled', 'disabled')
56
+ }
57
+ })
58
+
44
59
  test('handles latest date property correctly', async () => {
45
60
  const latestDate = '2024-12-15'
46
61
  const container = await createCalendar(`latest="${latestDate}"`)
@@ -52,6 +52,18 @@ describe('PktCalendar', () => {
52
52
  expect(monthNav).toBeInTheDocument()
53
53
  })
54
54
 
55
+ test('renders days outside the current month as empty cells', async () => {
56
+ const container = await createCalendar('currentmonth="2024-10-01"')
57
+
58
+ const calendar = container.querySelector('pkt-calendar') as PktCalendar
59
+ await calendar.updateComplete
60
+
61
+ const otherCells = calendar.querySelectorAll('.pkt-cal-other')
62
+ expect(otherCells).toHaveLength(4)
63
+ otherCells.forEach((cell) => expect(cell).toBeEmptyDOMElement())
64
+ expect(calendar.querySelectorAll('.pkt-calendar__date')).toHaveLength(31)
65
+ })
66
+
55
67
  test('renders month picker when withcontrols is true', async () => {
56
68
  const container = await createCalendar('withcontrols')
57
69
 
@@ -113,6 +125,7 @@ describe('PktCalendar', () => {
113
125
  expect(calendar.selected).toEqual([])
114
126
  expect(calendar.earliest).toBe(null)
115
127
  expect(calendar.latest).toBe(null)
128
+ expect(calendar.querySelector('[role="grid"]')).not.toHaveAttribute('aria-multiselectable')
116
129
  })
117
130
 
118
131
  test('handles multiple property correctly', async () => {
@@ -122,6 +135,7 @@ describe('PktCalendar', () => {
122
135
  await calendar.updateComplete
123
136
 
124
137
  expect(calendar.multiple).toBe(true)
138
+ expect(calendar.querySelector('[role="grid"]')).toHaveAttribute('aria-multiselectable', 'true')
125
139
  })
126
140
 
127
141
  test('handles range property correctly', async () => {
@@ -131,6 +145,7 @@ describe('PktCalendar', () => {
131
145
  await calendar.updateComplete
132
146
 
133
147
  expect(calendar.range).toBe(true)
148
+ expect(calendar.querySelector('[role="grid"]')).toHaveAttribute('aria-multiselectable', 'true')
134
149
  })
135
150
 
136
151
  test('handles weeknumbers property correctly', async () => {
@@ -25,7 +25,6 @@ import {
25
25
  DAYS_PER_WEEK,
26
26
  calculateCalendarDimensions,
27
27
  getCellType,
28
- getDayNumber,
29
28
  } from 'shared-utils/calendar/calendar-grid'
30
29
  import {
31
30
  convertSelectedToDates,
@@ -256,7 +255,7 @@ export class PktCalendar extends PktElement<IPktStringsProps<'dates' | 'calendar
256
255
  <table
257
256
  class="pkt-cal-days pkt-txt-12-medium pkt-calendar__body"
258
257
  role="grid"
259
- ?aria-multiselectable=${this.range || this.multiple}
258
+ aria-multiselectable=${this.range || this.multiple ? 'true' : nothing}
260
259
  >
261
260
  <thead>
262
261
  ${this.renderDayNames()}
@@ -290,8 +289,8 @@ export class PktCalendar extends PktElement<IPktStringsProps<'dates' | 'calendar
290
289
  }
291
290
  }}
292
291
  class="pkt-btn pkt-btn--tertiary pkt-btn--small pkt-btn--icon-only ${className} ${isAllowed ? '' : 'pkt-invisible'}"
293
- .data-disabled=${!isAllowed ? 'disabled' : nothing}
294
- ?aria-disabled=${!isAllowed}
292
+ data-disabled=${!isAllowed ? 'disabled' : nothing}
293
+ aria-disabled=${!isAllowed ? 'true' : nothing}
295
294
  tabindex=${isAllowed ? '0' : '-1'}
296
295
  >
297
296
  <pkt-icon class="pkt-btn__icon" name="${iconName}"></pkt-icon>
@@ -356,6 +355,7 @@ export class PktCalendar extends PktElement<IPktStringsProps<'dates' | 'calendar
356
355
  const target = e.target as HTMLInputElement
357
356
  this.changeMonth(parseInt(target.value), this.month)
358
357
  }}
358
+ value=${this.year}
359
359
  .value=${this.year}
360
360
  />
361
361
  </div>`
@@ -505,15 +505,8 @@ export class PktCalendar extends PktElement<IPktStringsProps<'dates' | 'calendar
505
505
  </td>`
506
506
  }
507
507
 
508
- private renderEmptyDayCell(day: number): TemplateResult {
509
- return html`<td class="pkt-cal-other">
510
- <div
511
- class="pkt-btn pkt-btn--tertiary pkt-btn--small pkt-btn--label-only"
512
- data-disabled="disabled"
513
- >
514
- <span class="pkt-btn__text pkt-txt-14-light">${day}</span>
515
- </div>
516
- </td>`
508
+ private renderEmptyDayCell(): TemplateResult {
509
+ return html`<td class="pkt-cal-other"></td>`
517
510
  }
518
511
 
519
512
  private renderWeekRow(cells: TemplateResult[]): TemplateResult {
@@ -551,8 +544,7 @@ export class PktCalendar extends PktElement<IPktStringsProps<'dates' | 'calendar
551
544
  cells.push(this.renderDayView(dayCounter, today))
552
545
  dayCounter++
553
546
  } else {
554
- const dayNumber = getDayNumber(cellType, j, dayCounter, dimensions)
555
- cells.push(this.renderEmptyDayCell(dayNumber))
547
+ cells.push(this.renderEmptyDayCell())
556
548
  if (cellType === 'next-month') {
557
549
  dayCounter++
558
550
  }
@@ -25,6 +25,7 @@ export { PktHelptext } from '@/components/helptext'
25
25
  export { PktHeading } from '@/components/heading'
26
26
  export { PktIcon } from '@/components/icon'
27
27
  export { PktInputWrapper } from '@/components/input-wrapper'
28
+ export type { IPktInputWrapper } from '@/components/input-wrapper'
28
29
  export { PktLink } from '@/components/link'
29
30
  export { PktLinkCard } from '@/components/linkcard'
30
31
  export { PktLoader } from '@/components/loader'
@@ -1,4 +1,5 @@
1
1
  import { PktInputWrapper } from './input-wrapper'
2
2
 
3
3
  export { PktInputWrapper }
4
+ export type { IPktInputWrapper } from './input-wrapper'
4
5
  export default PktInputWrapper
@@ -197,6 +197,7 @@ describe('PktInputWrapper', () => {
197
197
 
198
198
  const counter = wrapper.querySelector('.pkt-input__counter')
199
199
  expect(counter).toBeInTheDocument()
200
+ expect(counter?.textContent?.trim()).toBe('5/100')
200
201
  })
201
202
 
202
203
  test('updates counter current value', async () => {
@@ -8,15 +8,20 @@ import { unsafeHTML } from 'lit/directives/unsafe-html.js'
8
8
  import { customElement, property } from 'lit/decorators.js'
9
9
  import { ElementProps } from '@/types/typeUtils'
10
10
  import { uuidish } from 'shared-utils/utils'
11
- import { booleanishConverter, type Booleanish, type TLayout } from 'shared-types'
11
+ import {
12
+ booleanishConverter,
13
+ INPUT_WRAPPER_DEFAULTS,
14
+ type Booleanish,
15
+ type IPktInputWrapperBase,
16
+ type TLayout,
17
+ type TPktCounterPosition,
18
+ type TPktInputSize,
19
+ } from 'shared-types'
12
20
  import { FocusModalityController } from '@/controllers/focus-modality-controller'
13
- import specs from 'componentSpecs/input-wrapper.json'
14
21
  import '@/components/helptext'
15
22
  import '@/components/icon'
16
23
  import '@/components/alert'
17
24
 
18
- type TCounterPosition = 'top' | 'bottom'
19
- type TInputWrapperSize = 'small' | 'medium' | 'xsmall'
20
25
  type Props = ElementProps<
21
26
  PktInputWrapper,
22
27
  | 'forId'
@@ -44,7 +49,19 @@ type Props = ElementProps<
44
49
  > &
45
50
  IPktStringsProps<'forms' | 'validation'>
46
51
 
47
- export class PktInputWrapper extends PktElementWithSlot<Props> {
52
+ export interface IPktInputWrapper extends Omit<
53
+ IPktInputWrapperBase,
54
+ 'helptext' | 'helptextDropdown' | 'helptextDropdownButton' | 'role' | 'useWrapper'
55
+ > {
56
+ helptext?: string | null
57
+ helptextDropdown?: string | null
58
+ /** @deprecated Bruk `strings={{ forms: { readMore: '…' } }}` eller `setPktStrings()`. */
59
+ helptextDropdownButton?: string | null
60
+ role?: string | null
61
+ useWrapper?: Booleanish
62
+ }
63
+
64
+ export class PktInputWrapper extends PktElementWithSlot<Props> implements IPktInputWrapper {
48
65
  /**
49
66
  * Element attributes
50
67
  */
@@ -54,31 +71,33 @@ export class PktInputWrapper extends PktElementWithSlot<Props> {
54
71
  @property({ type: String }) helptextDropdown: string | null = null
55
72
  /** @deprecated Bruk `strings={{ forms: { readMore: '…' } }}` eller `setPktStrings()`. */
56
73
  @property({ type: String }) helptextDropdownButton: string | null = null
57
- @property({ type: Boolean }) counter: boolean = specs.props.counter.default
58
- @property({ type: Number }) counterCurrent: number = 0
74
+ @property({ type: Boolean }) counter: boolean = INPUT_WRAPPER_DEFAULTS.counter
75
+ @property({ type: Number }) counterCurrent: number = INPUT_WRAPPER_DEFAULTS.counterCurrent
59
76
  @property({ type: Number }) counterMaxLength: number = 0
60
77
 
78
+ /** @deprecated Ikke i bruk av Punkt-komponentene, og vises ikke for skjermlesere. */
61
79
  @property({ type: String }) counterError: string | null = null
62
- @property({ type: String, reflect: false }) counterPosition: TCounterPosition = 'bottom'
63
- @property({ type: Boolean }) optionalTag: boolean = specs.props.optionalTag.default
80
+ @property({ type: String, reflect: false }) counterPosition: TPktCounterPosition =
81
+ INPUT_WRAPPER_DEFAULTS.counterPosition
82
+ @property({ type: Boolean }) optionalTag: boolean = INPUT_WRAPPER_DEFAULTS.optionalTag
64
83
  /** @deprecated Bruk `strings={{ forms: { optional: '…' } }}` eller `setPktStrings()`. */
65
84
  @property({ type: String }) optionalText?: string
66
- @property({ type: Boolean }) requiredTag: boolean = specs.props.requiredTag.default
85
+ @property({ type: Boolean }) requiredTag: boolean = INPUT_WRAPPER_DEFAULTS.requiredTag
67
86
  /** @deprecated Bruk `strings={{ forms: { required: '…' } }}` eller `setPktStrings()`. */
68
87
  @property({ type: String }) requiredText?: string
69
88
  @property({ type: String }) tagText: string | null = null
70
- @property({ type: Boolean }) hasError: boolean = specs.props.hasError.default
89
+ @property({ type: Boolean }) hasError: boolean = INPUT_WRAPPER_DEFAULTS.hasError
71
90
  @property({ type: String }) errorMessage: string = ''
72
- @property({ type: Boolean }) disabled: boolean = specs.props.disabled.default
73
- @property({ type: Boolean }) inline: boolean = specs.props.inline.default
91
+ @property({ type: Boolean }) disabled: boolean = INPUT_WRAPPER_DEFAULTS.disabled
92
+ @property({ type: Boolean }) inline: boolean = INPUT_WRAPPER_DEFAULTS.inline
74
93
  @property({ type: String }) ariaDescribedby: string | undefined = undefined
75
- @property({ type: Boolean }) hasFieldset: boolean = specs.props.hasFieldset.default
76
- @property({ type: String }) layout: TLayout = specs.props.layout.default as TLayout
94
+ @property({ type: Boolean }) hasFieldset: boolean = INPUT_WRAPPER_DEFAULTS.hasFieldset
95
+ @property({ type: String }) layout: TLayout = INPUT_WRAPPER_DEFAULTS.layout
77
96
  @property({ type: String, reflect: true }) role: string | null = null
78
97
  @property({ type: Boolean, reflect: true, converter: booleanishConverter })
79
- useWrapper: Booleanish = specs.props.useWrapper.default
98
+ useWrapper: Booleanish = INPUT_WRAPPER_DEFAULTS.useWrapper
80
99
  @property({ type: String, attribute: 'input-wrapper-size' })
81
- size: TInputWrapperSize = 'medium'
100
+ size: TPktInputSize = INPUT_WRAPPER_DEFAULTS.size
82
101
 
83
102
  protected updated(changedProperties: PropertyValues): void {
84
103
  super.updated(changedProperties)
@@ -184,9 +203,9 @@ export class PktInputWrapper extends PktElementWithSlot<Props> {
184
203
  // Den synlige telleren er aria-hidden. Statusregionen under holdes tom
185
204
  // til grensa er brutt, så skjermlesere bare varsler når det faktisk er noe å si.
186
205
  const exceeded = isCounterExceeded(this.counterCurrent, this.counterMaxLength)
206
+ const count = `${this.counterCurrent || 0}${this.counterMaxLength ? `/${this.counterMaxLength}` : ''}`
187
207
  return html`<div class="pkt-input__counter" aria-hidden="true">
188
- ${this.counterError ? this.counterError : nothing} ${this.counterCurrent || 0}
189
- ${this.counterMaxLength ? `/${this.counterMaxLength}` : nothing}
208
+ ${this.counterError ? `${this.counterError} ` : nothing}${count}
190
209
  </div>
191
210
  <div class="pkt-sr-only" id=${counterStatusId(this.forId)} aria-live="polite">
192
211
  ${exceeded
@@ -1,7 +1,7 @@
1
1
  import { readFileSync } from 'node:fs'
2
2
  import { join } from 'node:path'
3
3
  import { describe, expect, test } from 'vitest'
4
- import wrapperSpec from 'componentSpecs/input-wrapper.json'
4
+ import wrapperSpec from 'componentSpecs/input-wrapper.spec'
5
5
 
6
6
  const ROOT = join(__dirname, '../../../../..')
7
7
 
@@ -129,7 +129,9 @@ const wrapperCall = (source: string, framework: 'elements' | 'react') => {
129
129
  const forwards = (block: string, prop: string) =>
130
130
  new RegExp(`[.?]?${prop}\\s*=`).test(block) || new RegExp(`\\b${prop}\\b`).test(block)
131
131
 
132
- const wrapperProps = Object.keys(wrapperSpec.props).filter((p) => !NOT_A_FORWARDED_PROP.has(p))
132
+ const wrapperProps = Object.keys(wrapperSpec.props ?? {}).filter(
133
+ (p) => !NOT_A_FORWARDED_PROP.has(p),
134
+ )
133
135
 
134
136
  describe('input-wrapper: paritet mellom rammeverk', () => {
135
137
  for (const [name, paths] of Object.entries(COMPONENTS)) {