@oslokommune/punkt-elements 12.17.2 → 12.18.1

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 (128) hide show
  1. package/dist/alert-BbVWu2lm.cjs +27 -0
  2. package/dist/alert-Dh6A96vo.js +159 -0
  3. package/dist/{index-D2jSRMrn.js → calendar-BUqcNvfI.js} +41 -29
  4. package/dist/calendar-QSulz7im.cjs +108 -0
  5. package/dist/card-B0GPdG5M.cjs +23 -0
  6. package/dist/card-kWt0BA2a.js +170 -0
  7. package/dist/{class-map-a5HUzP83.cjs → class-map-Boa7BqCc.cjs} +2 -2
  8. package/dist/{class-map-CBvUV2N3.js → class-map-hz16xq5a.js} +9 -10
  9. package/dist/datepicker-BHepKxof.cjs +154 -0
  10. package/dist/datepicker-iNCYioZ9.js +659 -0
  11. package/dist/helptext--4FLdAWi.js +194 -0
  12. package/dist/helptext-iZEgxz2U.cjs +23 -0
  13. package/dist/icon-CdMQ6zBT.cjs +250 -0
  14. package/dist/{index-CFDwiDTU.js → icon-wUXeHiBk.js} +7371 -7559
  15. package/dist/if-defined-DEDlGbAc.cjs +5 -0
  16. package/dist/if-defined-ZFE4ti2t.js +10 -0
  17. package/dist/index.d.ts +96 -51
  18. package/dist/input-element-D1Vls6A5.js +184 -0
  19. package/dist/input-element-DPKoFVwJ.cjs +1 -0
  20. package/dist/{input-wrapper-6vTrKtsW.js → input-wrapper-BTQk3W8T.js} +10 -10
  21. package/dist/input-wrapper-D-PNRJB_.cjs +46 -0
  22. package/dist/link-BpqavGSD.cjs +8 -0
  23. package/dist/link-Bx9nVgZi.js +108 -0
  24. package/dist/{linkcard-BlWQ8jOv.js → linkcard-CUrbzjLK.js} +16 -17
  25. package/dist/linkcard-DSu3A4Yx.cjs +13 -0
  26. package/dist/messagebox-C1aWoQbu.cjs +12 -0
  27. package/dist/messagebox-LpiVQIoM.js +107 -0
  28. package/dist/{modal-DYTVJjYh.cjs → modal-Avai5eVz.cjs} +2 -2
  29. package/dist/{modal-3OZTPqee.js → modal-Co1YFmHi.js} +8 -8
  30. package/dist/pkt-alert.cjs +1 -27
  31. package/dist/pkt-alert.js +4 -157
  32. package/dist/pkt-calendar.cjs +1 -1
  33. package/dist/pkt-calendar.js +4 -7
  34. package/dist/pkt-card.cjs +1 -23
  35. package/dist/pkt-card.js +4 -168
  36. package/dist/pkt-datepicker.cjs +1 -154
  37. package/dist/pkt-datepicker.js +4 -657
  38. package/dist/pkt-helptext.cjs +1 -1
  39. package/dist/pkt-helptext.js +1 -1
  40. package/dist/pkt-icon.cjs +1 -1
  41. package/dist/pkt-icon.js +4 -4
  42. package/dist/pkt-index.cjs +29 -1
  43. package/dist/pkt-index.js +127 -30
  44. package/dist/pkt-input-wrapper.cjs +1 -1
  45. package/dist/pkt-input-wrapper.js +1 -1
  46. package/dist/pkt-link.cjs +1 -8
  47. package/dist/pkt-link.js +4 -107
  48. package/dist/pkt-linkcard.cjs +1 -1
  49. package/dist/pkt-linkcard.js +1 -1
  50. package/dist/pkt-messagebox.cjs +1 -12
  51. package/dist/pkt-messagebox.js +4 -105
  52. package/dist/pkt-modal.cjs +1 -1
  53. package/dist/pkt-modal.js +1 -1
  54. package/dist/pkt-progressbar.cjs +1 -0
  55. package/dist/pkt-progressbar.js +6 -0
  56. package/dist/pkt-slot-controller-Ckk_yV0j.cjs +1 -0
  57. package/dist/pkt-slot-controller-RJvOnbF4.js +61 -0
  58. package/dist/pkt-tag.cjs +1 -17
  59. package/dist/pkt-tag.js +4 -148
  60. package/dist/pkt-textarea.cjs +1 -1
  61. package/dist/pkt-textarea.js +1 -1
  62. package/dist/pkt-textinput.cjs +1 -1
  63. package/dist/pkt-textinput.js +1 -1
  64. package/dist/progressbar-BS_oawSB.js +150 -0
  65. package/dist/progressbar-CuXkbAhJ.cjs +32 -0
  66. package/dist/ref-DCOsLZQg.cjs +13 -0
  67. package/dist/ref-DuFGTLVX.js +142 -0
  68. package/dist/state-BfyXV7EL.js +12 -0
  69. package/dist/state-SKYD8kRO.cjs +5 -0
  70. package/dist/stringutils-CkVRq4jP.cjs +1 -0
  71. package/dist/stringutils-DJjRa8dG.js +7 -0
  72. package/dist/tag-CGy2mSLE.cjs +17 -0
  73. package/dist/tag-DGFgUF3l.js +150 -0
  74. package/dist/{textarea-BTpJjEhO.js → textarea-BAGWR1Hi.js} +29 -29
  75. package/dist/textarea-BiUrhAlk.cjs +48 -0
  76. package/dist/{textinput-BIhQEr8z.cjs → textinput-CHOR5PPp.cjs} +2 -2
  77. package/dist/{textinput-CVo5wG14.js → textinput-pJ3N8m6g.js} +23 -23
  78. package/package.json +2 -2
  79. package/src/components/alert/alert.ts +115 -0
  80. package/src/components/alert/index.ts +4 -113
  81. package/src/components/calendar/calendar.ts +711 -0
  82. package/src/components/calendar/index.ts +3 -711
  83. package/src/components/card/card.ts +78 -0
  84. package/src/components/card/index.ts +4 -77
  85. package/src/components/datepicker/datepicker.ts +619 -0
  86. package/src/components/datepicker/index.ts +3 -618
  87. package/src/components/helptext/helptext.ts +2 -2
  88. package/src/components/icon/icon.ts +99 -0
  89. package/src/components/icon/index.ts +3 -98
  90. package/src/components/index.ts +29 -15
  91. package/src/components/input-wrapper/input-wrapper.ts +2 -2
  92. package/src/components/link/index.ts +3 -56
  93. package/src/components/link/link.ts +57 -0
  94. package/src/components/linkcard/index.ts +1 -1
  95. package/src/components/linkcard/linkcard.ts +5 -6
  96. package/src/components/messagebox/index.ts +4 -69
  97. package/src/components/messagebox/messagebox.ts +69 -0
  98. package/src/components/modal/index.ts +0 -1
  99. package/src/components/modal/modal.ts +5 -7
  100. package/src/components/progressbar/index.ts +12 -0
  101. package/src/components/progressbar/progressbar.ts +144 -0
  102. package/src/components/tag/index.ts +4 -109
  103. package/src/components/tag/tag.ts +118 -0
  104. package/src/components/textarea/textarea.ts +5 -4
  105. package/src/components/textinput/textinput.ts +3 -3
  106. package/dist/converters-DNCwIFwr.js +0 -17
  107. package/dist/converters-DhM11VlY.cjs +0 -1
  108. package/dist/custom-element-B-TlBwRu.cjs +0 -9
  109. package/dist/custom-element-CWfU4dcr.js +0 -38
  110. package/dist/element.d.ts +0 -8
  111. package/dist/helptext-DBolvFI4.js +0 -72
  112. package/dist/helptext-_fMLOOCL.cjs +0 -23
  113. package/dist/index-CR7t1zY9.cjs +0 -238
  114. package/dist/index-CmTjXoAb.cjs +0 -9
  115. package/dist/index-RwtTBIhT.js +0 -88
  116. package/dist/index-tvpcg-ad.cjs +0 -108
  117. package/dist/input-wrapper-DX41tnbj.cjs +0 -46
  118. package/dist/linkcard-Det6CJ5D.cjs +0 -13
  119. package/dist/pkt-component-template.cjs +0 -29
  120. package/dist/pkt-component-template.js +0 -99
  121. package/dist/pkt-element.cjs +0 -1
  122. package/dist/pkt-element.js +0 -5
  123. package/dist/ref-C2yPtMJA.cjs +0 -13
  124. package/dist/ref-CaiKp3S2.js +0 -202
  125. package/dist/textarea-B45ZZYpx.cjs +0 -48
  126. package/src/components/component-template/index.ts +0 -129
  127. package/src/components/element/index.ts +0 -353
  128. /package/dist/{component-template.d.ts → progressbar.d.ts} +0 -0
@@ -0,0 +1,619 @@
1
+ import { classMap } from 'lit/directives/class-map.js'
2
+ import { ifDefined } from 'lit/directives/if-defined.js'
3
+ import { customElement, property, state } from 'lit/decorators.js'
4
+ import { formatISODate, fromISOToDate, fromISOtoLocal, newDate } from '@/utils/dateutils'
5
+ import { html, nothing, PropertyValues } from 'lit'
6
+ import { PktCalendar } from '@/components/calendar/calendar'
7
+ import { PktInputElement } from '@/base-elements/input-element'
8
+ import { Ref, createRef, ref } from 'lit/directives/ref.js'
9
+ import { repeat } from 'lit/directives/repeat.js'
10
+ import converters from '@/helpers/converters'
11
+ import specs from 'componentSpecs/datepicker.json'
12
+ import '../calendar/calendar'
13
+ import '../input-wrapper'
14
+ import '../tag/tag'
15
+ import '../icon/icon'
16
+
17
+ const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
18
+ @customElement('pkt-datepicker')
19
+ export class PktDatepicker extends PktInputElement {
20
+ /**
21
+ * Element attributes and properties
22
+ */
23
+ @property({ type: String, reflect: true })
24
+ value: string | string[] = ''
25
+
26
+ @property({ type: Array })
27
+ _value: string[] = this.value
28
+ ? !Array.isArray(this.value)
29
+ ? this.value.split(',')
30
+ : this.value
31
+ : []
32
+
33
+ @property({ type: String, reflect: true })
34
+ label: string = 'Datovelger'
35
+
36
+ @property({ type: String })
37
+ dateformat: string = specs.props.dateformat.default
38
+
39
+ @property({ type: Boolean, reflect: true })
40
+ multiple: boolean = specs.props.multiple.default
41
+
42
+ @property({ type: Number, reflect: true })
43
+ maxlength: number | null = null
44
+
45
+ @property({ type: Boolean, reflect: true })
46
+ range: boolean = specs.props.range.default
47
+
48
+ @property({ type: Boolean })
49
+ showRangeLabels: boolean = false
50
+
51
+ @property({ type: String, reflect: true })
52
+ min: string | null = null
53
+
54
+ @property({ type: String, reflect: true })
55
+ max: string | null = null
56
+
57
+ @property({ type: Boolean })
58
+ weeknumbers: boolean = specs.props.weeknumbers.default
59
+
60
+ @property({ type: Boolean, reflect: true })
61
+ withcontrols: boolean = specs.props.withcontrols.default
62
+
63
+ @property({ converter: converters.csvToArray })
64
+ excludedates: string[] = []
65
+
66
+ @property({ converter: converters.csvToArray })
67
+ excludeweekdays: string[] = []
68
+
69
+ @property({ type: String })
70
+ currentmonth: string | null = null
71
+
72
+ @property({ type: Boolean, reflect: true })
73
+ calendarOpen: boolean = false
74
+
75
+ @property({ type: String })
76
+ timezone: string = 'Europe/Oslo'
77
+
78
+ @state() inputClasses = {}
79
+ @state() buttonClasses = {}
80
+
81
+ /**
82
+ * Housekeeping / lifecycle methods
83
+ */
84
+
85
+ async connectedCallback() {
86
+ super.connectedCallback()
87
+
88
+ this.isMobileSafari =
89
+ /iP(ad|od|hone)/i.test(window.navigator.userAgent) &&
90
+ !!navigator.userAgent.match(/Version\/[\d\.]+.*Safari/)
91
+ this.inputType = this.isMobileSafari ? 'text' : 'date'
92
+
93
+ document &&
94
+ document.body.addEventListener('click', (e: MouseEvent) => {
95
+ if (
96
+ this.inputRef?.value &&
97
+ this.btnRef?.value &&
98
+ !this.inputRef.value.contains(e.target as Node) &&
99
+ !(this.inputRefTo.value && this.inputRefTo.value.contains(e.target as Node)) &&
100
+ !this.btnRef.value.contains(e.target as Node) &&
101
+ !(e.target as Element).closest('.pkt-calendar-popup') &&
102
+ this.calendarOpen
103
+ ) {
104
+ this.onBlur()
105
+ this.hideCalendar()
106
+ }
107
+ })
108
+
109
+ if (this.value.length && this._value.length === 0) {
110
+ this._value = !Array.isArray(this.value) ? this.value.split(',') : this.value
111
+ }
112
+ this.min = this.min || specs.props.min.default
113
+ this.max = this.max || specs.props.max.default
114
+
115
+ if (typeof this.excludedates === 'string') {
116
+ this.excludedates = (this.excludedates as unknown as string).split(',')
117
+ }
118
+
119
+ if (typeof this.excludeweekdays === 'string') {
120
+ this.excludeweekdays = (this.excludeweekdays as unknown as string).split(',')
121
+ }
122
+
123
+ if ((this.multiple || this.range) && this.name && !this.name.endsWith('[]')) {
124
+ this.name = this.name + '[]'
125
+ }
126
+
127
+ if (this.calendarOpen) {
128
+ await sleep(20)
129
+ this.handleCalendarPosition()
130
+ }
131
+ }
132
+
133
+ disconnectedCallback(): void {
134
+ super.disconnectedCallback()
135
+ document &&
136
+ document.body.removeEventListener('click', (e: MouseEvent) => {
137
+ if (
138
+ this.inputRef?.value &&
139
+ this.btnRef?.value &&
140
+ !this.inputRef.value.contains(e.target as Node) &&
141
+ !this.btnRef.value.contains(e.target as Node)
142
+ ) {
143
+ this.hideCalendar()
144
+ }
145
+ })
146
+ }
147
+
148
+ attributeChangedCallback(name: string, _old: string | null, value: string | null): void {
149
+ if (name === 'value') {
150
+ if (this.range && value?.split(',').length === 1) return
151
+ if (this.value !== _old) this.valueChanged(value, _old)
152
+ }
153
+
154
+ if (name === 'excludedates' && typeof this.excludedates === 'string') {
155
+ this.excludedates = value?.split(',') ?? []
156
+ }
157
+
158
+ if (name === 'excludeweekdays' && typeof this.excludeweekdays === 'string') {
159
+ this.excludeweekdays = value?.split(',') ?? []
160
+ }
161
+ super.attributeChangedCallback(name, _old, value)
162
+ }
163
+
164
+ updated(changedProperties: PropertyValues): void {
165
+ if (changedProperties.has('value')) {
166
+ if (this.range && this.value.length === 1) return
167
+ this.valueChanged(this.value, changedProperties.get('value'))
168
+ }
169
+ super.updated(changedProperties)
170
+ }
171
+
172
+ /**
173
+ * Element references
174
+ */
175
+
176
+ // When using PktInputElement, we always need to define `inputRef`
177
+ inputRef: Ref<HTMLInputElement> = createRef()
178
+ inputRefTo: Ref<HTMLInputElement> = createRef()
179
+ btnRef: Ref<HTMLButtonElement> = createRef()
180
+ calRef: Ref<PktCalendar> = createRef()
181
+ popupRef: Ref<HTMLDivElement> = createRef()
182
+
183
+ /**
184
+ * Rendering
185
+ */
186
+ renderInput() {
187
+ return html`
188
+ <input
189
+ class="${classMap(this.inputClasses)}"
190
+ .type=${this.inputType}
191
+ id="${this.id}-input"
192
+ .value=${this._value[0] ?? ''}
193
+ min=${ifDefined(this.min)}
194
+ max=${ifDefined(this.max)}
195
+ @click=${(e: MouseEvent) => {
196
+ e.preventDefault()
197
+ this.showCalendar()
198
+ }}
199
+ ?disabled=${this.disabled}
200
+ @keydown=${(e: KeyboardEvent) => {
201
+ if (e.key === ',' || e.key === 'Enter') {
202
+ this.inputRef.value?.blur()
203
+ }
204
+ if (e.key === 'Space' || e.key === ' ') {
205
+ e.preventDefault()
206
+ this.toggleCalendar(e)
207
+ }
208
+ }}
209
+ @input=${(e: Event) => {
210
+ this.onInput()
211
+ e.stopImmediatePropagation()
212
+ }}
213
+ @focus=${() => {
214
+ this.onFocus()
215
+ if (this.isMobileSafari) {
216
+ this.showCalendar()
217
+ }
218
+ }}
219
+ @blur=${(e: FocusEvent) => {
220
+ if (!this.calRef.value?.contains(e.relatedTarget as Node)) {
221
+ this.onBlur()
222
+ }
223
+ this.manageValidity(e.target as HTMLInputElement)
224
+ this.value = (e.target as HTMLInputElement).value
225
+ }}
226
+ @change=${(e: Event) => {
227
+ e.stopImmediatePropagation()
228
+ }}
229
+ ${ref(this.inputRef)}
230
+ />
231
+ `
232
+ }
233
+
234
+ renderRangeInput() {
235
+ const rangeLabelClasses = {
236
+ 'pkt-input-prefix': this.showRangeLabels,
237
+ 'pkt-hide': !this.showRangeLabels,
238
+ }
239
+ return html`
240
+ ${this.showRangeLabels
241
+ ? html` <div class="pkt-input-prefix">${this.strings.generic.from}</div> `
242
+ : nothing}
243
+ <input
244
+ class=${classMap(this.inputClasses)}
245
+ .type=${this.inputType}
246
+ id="${this.id}-input"
247
+ .value=${this._value[0] ?? ''}
248
+ min=${ifDefined(this.min)}
249
+ max=${ifDefined(this.max)}
250
+ ?disabled=${this.disabled}
251
+ @click=${(e: MouseEvent) => {
252
+ e.preventDefault()
253
+ this.showCalendar()
254
+ }}
255
+ @keydown=${(e: KeyboardEvent) => {
256
+ if (e.key === ',' || e.key === 'Enter') {
257
+ this.inputRef.value?.blur()
258
+ }
259
+ if (e.key === 'Space' || e.key === ' ') {
260
+ e.preventDefault()
261
+ this.toggleCalendar(e)
262
+ }
263
+ }}
264
+ @input=${(e: Event) => {
265
+ this.onInput()
266
+ e.stopImmediatePropagation()
267
+ }}
268
+ @focus=${() => {
269
+ this.onFocus()
270
+ if (this.isMobileSafari) {
271
+ this.showCalendar()
272
+ }
273
+ }}
274
+ @blur=${(e: Event) => {
275
+ if ((e.target as HTMLInputElement).value) {
276
+ this.manageValidity(e.target as HTMLInputElement)
277
+ const date = fromISOToDate((e.target as HTMLInputElement).value)
278
+ if (date) {
279
+ if (this._value[0] !== (e.target as HTMLInputElement).value && this._value[1]) {
280
+ this.clearInputValue()
281
+ this.calRef?.value?.handleDateSelect(date)
282
+ }
283
+ }
284
+ } else if (this._value[0]) {
285
+ this.clearInputValue()
286
+ }
287
+ }}
288
+ @change=${(e: Event) => {
289
+ e.stopImmediatePropagation()
290
+ }}
291
+ ${ref(this.inputRef)}
292
+ />
293
+ <div class="${classMap(rangeLabelClasses)}" id="${this.id}-to-label">
294
+ ${this.strings.generic.to}
295
+ </div>
296
+ ${!this.showRangeLabels ? html` <div class="pkt-input-separator">–</div> ` : nothing}
297
+ <input
298
+ class=${classMap(this.inputClasses)}
299
+ .type=${this.inputType}
300
+ id="${this.id}-to"
301
+ aria-labelledby="${this.id}-to-label"
302
+ .value=${this._value[1] ?? ''}
303
+ min=${ifDefined(this.min)}
304
+ max=${ifDefined(this.max)}
305
+ ?disabled=${this.disabled}
306
+ @click=${(e: MouseEvent) => {
307
+ e.preventDefault()
308
+ this.showCalendar()
309
+ }}
310
+ @keydown=${(e: KeyboardEvent) => {
311
+ if (e.key === ',' || e.key === 'Enter') {
312
+ this.inputRefTo.value?.blur()
313
+ }
314
+ if (e.key === 'Space' || e.key === ' ') {
315
+ e.preventDefault()
316
+ this.toggleCalendar(e)
317
+ }
318
+ }}
319
+ @input=${(e: Event) => {
320
+ this.onInput()
321
+ e.stopImmediatePropagation()
322
+ }}
323
+ @focus=${() => {
324
+ this.onFocus()
325
+ if (this.isMobileSafari) {
326
+ this.showCalendar()
327
+ }
328
+ }}
329
+ @blur=${(e: FocusEvent) => {
330
+ if (!this.calRef.value?.contains(e.relatedTarget as Node)) {
331
+ this.onBlur()
332
+ }
333
+ if ((e.target as HTMLInputElement).value) {
334
+ this.manageValidity(e.target as HTMLInputElement)
335
+ const val = (e.target as HTMLInputElement).value
336
+ if (this.min && this.min > val) {
337
+ this.internals.setValidity(
338
+ { rangeUnderflow: true },
339
+ this.strings.forms.messages.rangeUnderflow,
340
+ e.target as HTMLInputElement,
341
+ )
342
+ } else if (this.max && this.max < val) {
343
+ this.internals.setValidity(
344
+ { rangeOverflow: true },
345
+ this.strings.forms.messages.rangeOverflow,
346
+ e.target as HTMLInputElement,
347
+ )
348
+ }
349
+ const date = fromISOToDate((e.target as HTMLInputElement).value)
350
+ if (date) {
351
+ if (this._value[1] !== formatISODate(date)) {
352
+ this.calRef?.value?.handleDateSelect(date)
353
+ }
354
+ }
355
+ }
356
+ }}
357
+ @change=${(e: Event) => {
358
+ e.stopImmediatePropagation()
359
+ }}
360
+ ${ref(this.inputRefTo)}
361
+ />
362
+ `
363
+ }
364
+
365
+ renderMultipleInput() {
366
+ return html`
367
+ <input
368
+ class=${classMap(this.inputClasses)}
369
+ .type=${this.inputType}
370
+ id="${this.id}-input"
371
+ min=${ifDefined(this.min)}
372
+ max=${ifDefined(this.max)}
373
+ ?disabled=${this.disabled || (this.maxlength && this._value.length >= this.maxlength)}
374
+ @click=${(e: MouseEvent) => {
375
+ e.preventDefault()
376
+ this.showCalendar()
377
+ }}
378
+ @blur=${(e: FocusEvent) => {
379
+ if (!this.calRef.value?.contains(e.relatedTarget as Node)) {
380
+ this.onBlur()
381
+ }
382
+ this.addToSelected(e)
383
+ }}
384
+ @input=${(e: Event) => {
385
+ this.onInput()
386
+ e.stopImmediatePropagation()
387
+ }}
388
+ @focus=${() => {
389
+ this.onFocus()
390
+ if (this.isMobileSafari) {
391
+ this.showCalendar()
392
+ }
393
+ }}
394
+ @keydown=${(e: KeyboardEvent) => {
395
+ if (e.key === ',' || e.key === 'Enter') {
396
+ e.preventDefault()
397
+ this.addToSelected(e)
398
+ }
399
+ if (e.key === 'Space' || e.key === ' ') {
400
+ e.preventDefault()
401
+ this.toggleCalendar(e)
402
+ }
403
+ }}
404
+ @change=${(e: Event) => {
405
+ e.stopImmediatePropagation()
406
+ }}
407
+ ${ref(this.inputRef)}
408
+ />
409
+ `
410
+ }
411
+
412
+ renderTags() {
413
+ return html`
414
+ <div class="pkt-datepicker__tags" aria-live="polite">
415
+ ${!!this._value[0]
416
+ ? repeat(
417
+ this._value ?? [],
418
+ (date) => date,
419
+ (date) => html`
420
+ <pkt-tag
421
+ .id="${this.id + date + '-tag'}"
422
+ closeTag
423
+ ariaLabel="${this.strings.calendar.deleteDate} ${fromISOtoLocal(
424
+ date,
425
+ this.dateformat,
426
+ )}"
427
+ @close=${() => this.calRef.value?.handleDateSelect(fromISOToDate(date))}
428
+ ><time datetime="${date}">${fromISOtoLocal(date, this.dateformat)}</time></pkt-tag
429
+ >
430
+ `,
431
+ )
432
+ : nothing}
433
+ </div>
434
+ `
435
+ }
436
+
437
+ renderCalendar() {
438
+ return html`<div
439
+ class="pkt-calendar-popup pkt-${this.calendarOpen ? 'show' : 'hide'}"
440
+ @focusout=${(e: FocusEvent) => {
441
+ if (this.calendarOpen) this.handleFocusOut(e)
442
+ }}
443
+ id="${this.id}-popup"
444
+ ${ref(this.popupRef)}
445
+ >
446
+ <pkt-calendar
447
+ id="${this.id}-calendar"
448
+ ?multiple=${this.multiple}
449
+ ?range=${this.range}
450
+ ?weeknumbers=${this.weeknumbers}
451
+ ?withcontrols=${this.withcontrols}
452
+ .maxMultiple=${this.maxlength}
453
+ .selected=${this._value}
454
+ .earliest=${this.min}
455
+ .latest=${this.max}
456
+ .excludedates=${Array.isArray(this.excludedates)
457
+ ? this.excludedates
458
+ : (this.excludedates as string).split(',')}
459
+ .excludeweekdays=${this.excludeweekdays}
460
+ .currentmonth=${this.currentmonth ? newDate(this.currentmonth) : null}
461
+ @date-selected=${(e: CustomEvent) => {
462
+ this.value = !this.multiple && !this.range ? e.detail[0] : e.detail
463
+ this._value = e.detail
464
+ if (this.inputRef.value) {
465
+ if (this.range && this.inputRefTo.value) {
466
+ this.inputRef.value.value = this._value[0] ?? ''
467
+ this.inputRefTo.value.value = this._value[1] ?? ''
468
+ } else if (!this.multiple) {
469
+ this.inputRef.value.value = this._value.length ? this._value[0] : ''
470
+ }
471
+ }
472
+ }}
473
+ @close=${() => {
474
+ this.onBlur()
475
+ this.hideCalendar()
476
+ }}
477
+ ${ref(this.calRef)}
478
+ ></pkt-calendar>
479
+ </div>`
480
+ }
481
+
482
+ render() {
483
+ this.inputClasses = {
484
+ 'pkt-input': true,
485
+ 'pkt-datepicker__input': true,
486
+ 'pkt-input--fullwidth': this.fullwidth,
487
+ 'pkt-datepicker--hasrangelabels': this.showRangeLabels,
488
+ 'pkt-datepicker--multiple': this.multiple,
489
+ 'pkt-datepicker--range': this.range,
490
+ }
491
+
492
+ this.buttonClasses = {
493
+ 'pkt-input-icon': true,
494
+ 'pkt-btn': true,
495
+ 'pkt-btn--icon-only': true,
496
+ 'pkt-btn--tertiary': true,
497
+ }
498
+
499
+ return html`
500
+ <pkt-input-wrapper
501
+ label="${this.label}"
502
+ forId="${this.id}-input"
503
+ ?counter=${this.multiple && !!this.maxlength}
504
+ .counterCurrent=${this.value ? this._value.length : 0}
505
+ .counterMaxLength=${this.maxlength}
506
+ ?disabled=${this.disabled}
507
+ ?hasError=${this.hasError}
508
+ ?required=${this.required}
509
+ ?optionalTag=${this.optionalTag}
510
+ ?requiredTag=${this.requiredTag}
511
+ ?useWrapper=${this.useWrapper}
512
+ .optionalText=${this.optionalText}
513
+ .requiredText=${this.requiredText}
514
+ .errorMessage=${this.errorMessage}
515
+ .helptext=${this.helptext}
516
+ .helptextDropdown=${this.helptextDropdown}
517
+ .helptextDropdownButton=${this.helptextDropdownButton}
518
+ .ariaDescribedBy=${this.ariaDescribedBy}
519
+ class="pkt-datepicker"
520
+ >
521
+ ${this.multiple ? this.renderTags() : nothing}
522
+ <div
523
+ class="pkt-datepicker__inputs ${this.range && this.showRangeLabels
524
+ ? 'pkt-input__range-inputs'
525
+ : ''}"
526
+ >
527
+ <div class="pkt-input__container">
528
+ ${this.range
529
+ ? this.renderRangeInput()
530
+ : this.multiple
531
+ ? this.renderMultipleInput()
532
+ : this.renderInput()}
533
+ <button
534
+ class="${classMap(this.buttonClasses)}"
535
+ type="button"
536
+ @click=${this.toggleCalendar}
537
+ ?disabled=${this.disabled}
538
+ ${ref(this.btnRef)}
539
+ >
540
+ <pkt-icon name="calendar"></pkt-icon>
541
+ <span class="pkt-btn__text">${this.strings.calendar.buttonAltText}</span>
542
+ </button>
543
+ </div>
544
+ </div>
545
+ </pkt-input-wrapper>
546
+ ${this.renderCalendar()}
547
+ `
548
+ }
549
+
550
+ /**
551
+ * Handlers
552
+ */
553
+
554
+ handleCalendarPosition() {
555
+ if (this.popupRef.value && this.inputRef.value) {
556
+ const counter = this.multiple && !!this.maxlength
557
+
558
+ const inputRect =
559
+ this.inputRef.value.parentElement?.getBoundingClientRect() ||
560
+ this.inputRef.value.getBoundingClientRect()
561
+
562
+ const inputHeight = counter ? inputRect.height + 30 : inputRect.height
563
+ const popupHeight = this.popupRef.value.getBoundingClientRect().height
564
+
565
+ let top = counter ? 'calc(100% - 30px)' : '100%'
566
+ if (
567
+ inputRect &&
568
+ inputRect.top + popupHeight > window.innerHeight &&
569
+ inputRect.top - popupHeight > 0
570
+ ) {
571
+ top = `calc(100% - ${inputHeight}px - ${popupHeight}px)`
572
+ }
573
+ this.popupRef.value.style.top = top
574
+ }
575
+ }
576
+
577
+ addToSelected = (e: Event | KeyboardEvent) => {
578
+ const target = e.target as HTMLInputElement
579
+ if (!target.value) return
580
+ const minAsDate = this.min ? newDate(this.min as string) : null
581
+ const maxAsDate = this.max ? newDate(this.max as string) : null
582
+ const date = newDate(target.value.split(',')[0])
583
+ if (
584
+ date &&
585
+ !isNaN(date.getTime()) &&
586
+ (!minAsDate || date >= minAsDate) &&
587
+ (!maxAsDate || date <= maxAsDate) &&
588
+ this.calRef.value
589
+ ) {
590
+ this.calRef.value.handleDateSelect(date)
591
+ }
592
+ target.value = ''
593
+ }
594
+
595
+ private handleFocusOut(e: FocusEvent) {
596
+ if (!this.contains(e.target as Node)) {
597
+ this.onBlur()
598
+ this.hideCalendar()
599
+ }
600
+ }
601
+
602
+ public async showCalendar() {
603
+ this.calendarOpen = true
604
+ await sleep(20)
605
+ this.handleCalendarPosition()
606
+ if (this.isMobileSafari) {
607
+ this.calRef.value?.focusOnCurrentDate()
608
+ }
609
+ }
610
+
611
+ public hideCalendar() {
612
+ this.calendarOpen = false
613
+ }
614
+
615
+ public async toggleCalendar(e: Event) {
616
+ e.preventDefault()
617
+ this.calendarOpen ? this.hideCalendar() : this.showCalendar()
618
+ }
619
+ }