@oslokommune/punkt-elements 13.4.2 → 13.5.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 (41) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/calendar-32W9p9uc.cjs +115 -0
  3. package/dist/{calendar-DevQhOup.js → calendar-CJSxvwAq.js} +353 -340
  4. package/dist/{card-Dtw26f7i.js → card-BDz4RWxK.js} +1 -1
  5. package/dist/{card-BUITGoqX.cjs → card-DBlFf1ry.cjs} +1 -1
  6. package/dist/{datepicker-CYOn3tRm.js → datepicker-BJKJBoy_.js} +102 -59
  7. package/dist/datepicker-CmTrG5GE.cjs +164 -0
  8. package/dist/{heading-D6jXE_Mz.js → heading-Bdh9absf.js} +22 -22
  9. package/dist/heading-CNycsyMj.cjs +1 -0
  10. package/dist/index.d.ts +6 -2
  11. package/dist/pkt-calendar.cjs +1 -1
  12. package/dist/pkt-calendar.js +1 -1
  13. package/dist/pkt-card.cjs +1 -1
  14. package/dist/pkt-card.js +1 -1
  15. package/dist/pkt-datepicker.cjs +1 -1
  16. package/dist/pkt-datepicker.js +1 -1
  17. package/dist/pkt-heading.cjs +1 -1
  18. package/dist/pkt-heading.js +1 -1
  19. package/dist/pkt-index.cjs +1 -1
  20. package/dist/pkt-index.js +5 -5
  21. package/package.json +3 -3
  22. package/src/components/calendar/calendar.accessibility.test.ts +111 -0
  23. package/src/components/calendar/calendar.constraints.test.ts +110 -0
  24. package/src/components/calendar/calendar.core.test.ts +367 -0
  25. package/src/components/calendar/calendar.interaction.test.ts +139 -0
  26. package/src/components/calendar/calendar.selection.test.ts +273 -0
  27. package/src/components/calendar/calendar.ts +74 -42
  28. package/src/components/card/card.test.ts +19 -5
  29. package/src/components/consent/consent.test.ts +436 -0
  30. package/src/components/datepicker/datepicker.accessibility.test.ts +193 -0
  31. package/src/components/datepicker/datepicker.core.test.ts +322 -0
  32. package/src/components/datepicker/datepicker.input.test.ts +268 -0
  33. package/src/components/datepicker/datepicker.selection.test.ts +286 -0
  34. package/src/components/datepicker/datepicker.ts +121 -19
  35. package/src/components/datepicker/datepicker.validation.test.ts +176 -0
  36. package/src/components/heading/heading.test.ts +458 -0
  37. package/src/components/heading/heading.ts +3 -0
  38. package/src/components/helptext/helptext.test.ts +474 -0
  39. package/dist/calendar-BZe2D4Sr.cjs +0 -108
  40. package/dist/datepicker-B9rhz_AF.cjs +0 -154
  41. package/dist/heading-BRE_iFtR.cjs +0 -1
@@ -0,0 +1,286 @@
1
+ import '@testing-library/jest-dom'
2
+ import { fireEvent } from '@testing-library/dom'
3
+
4
+ import './datepicker'
5
+ import '../calendar/calendar'
6
+ import { PktDatepicker } from './datepicker'
7
+
8
+ const waitForCustomElements = async () => {
9
+ await customElements.whenDefined('pkt-datepicker')
10
+ await customElements.whenDefined('pkt-calendar')
11
+ }
12
+
13
+ // Helper function to create datepicker markup
14
+ const createDatepicker = async (datepickerProps = '') => {
15
+ const container = document.createElement('div')
16
+ container.innerHTML = `
17
+ <pkt-datepicker ${datepickerProps}></pkt-datepicker>
18
+ `
19
+ document.body.appendChild(container)
20
+ await waitForCustomElements()
21
+ return container
22
+ }
23
+
24
+ // Cleanup after each test
25
+ afterEach(() => {
26
+ document.body.innerHTML = ''
27
+ })
28
+
29
+ describe('PktDatepicker', () => {
30
+ describe('Multiple date selection', () => {
31
+ test('displays multiple selected dates as tags', async () => {
32
+ const multipleDates = '2024-06-15,2024-06-20,2024-06-25'
33
+ const container = await createDatepicker(`value="${multipleDates}" multiple`)
34
+
35
+ const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
36
+ await datepicker.updateComplete
37
+
38
+ const tags = datepicker.querySelectorAll('pkt-tag')
39
+ expect(tags.length).toBe(3)
40
+ })
41
+
42
+ test('allows adding dates through calendar in multiple mode', async () => {
43
+ const container = await createDatepicker('multiple')
44
+
45
+ const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
46
+ await datepicker.updateComplete
47
+
48
+ // Open calendar
49
+ const calendarButton = datepicker.querySelector('button[type="button"]')
50
+ fireEvent.click(calendarButton!)
51
+ await datepicker.updateComplete
52
+
53
+ // Select a date
54
+ const availableDate = datepicker.querySelector('[data-date]:not([data-disabled="disabled"])')
55
+ if (availableDate) {
56
+ fireEvent.click(availableDate)
57
+ await datepicker.updateComplete
58
+
59
+ // Should add tag
60
+ const tags = datepicker.querySelectorAll('pkt-tag')
61
+ expect(tags.length).toBe(1)
62
+ }
63
+ })
64
+
65
+ test('removes dates when clicking tag close button', async () => {
66
+ const multipleDates = '2024-06-15,2024-06-20'
67
+ const container = await createDatepicker(`value="${multipleDates}" multiple`)
68
+
69
+ const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
70
+ await datepicker.updateComplete
71
+
72
+ const closeButtons = datepicker.querySelectorAll('pkt-tag .pkt-tag__close-btn')
73
+ expect(closeButtons.length).toBe(2)
74
+
75
+ // Click first close button
76
+ fireEvent.click(closeButtons[0])
77
+ await datepicker.updateComplete
78
+
79
+ const remainingTags = datepicker.querySelectorAll('pkt-tag')
80
+ expect(remainingTags.length).toBe(1)
81
+ })
82
+
83
+ test('respects maxlength in multiple mode', async () => {
84
+ const container = await createDatepicker('multiple maxlength="2"')
85
+
86
+ const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
87
+ await datepicker.updateComplete
88
+
89
+ // Open calendar and try to select more than maxlength dates
90
+ const calendarButton = datepicker.querySelector('button[type="button"]')
91
+ fireEvent.click(calendarButton!)
92
+ await datepicker.updateComplete
93
+
94
+ const availableDates = datepicker.querySelectorAll(
95
+ '.pkt-calendar__date:not(.pkt-calendar__date--disabled)',
96
+ )
97
+
98
+ // Select 3 dates
99
+ fireEvent.click(availableDates[0])
100
+ await datepicker.updateComplete
101
+ fireEvent.click(availableDates[1])
102
+ await datepicker.updateComplete
103
+ fireEvent.click(availableDates[2])
104
+ await datepicker.updateComplete
105
+
106
+ // Should only have maxlength tags
107
+ const tags = datepicker.querySelectorAll('pkt-tag')
108
+ expect(tags.length).toBeLessThanOrEqual(2)
109
+ })
110
+
111
+ test('sorts multiple dates chronologically', async () => {
112
+ const unsortedDates = '2024-06-25,2024-06-15,2024-06-20'
113
+ const container = await createDatepicker(`value="${unsortedDates}" multiple`)
114
+
115
+ const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
116
+ await datepicker.updateComplete
117
+
118
+ const tags = datepicker.querySelectorAll('pkt-tag')
119
+ const tagTexts = Array.from(tags).map((tag) => tag.textContent?.trim())
120
+
121
+ // Should be sorted chronologically
122
+ expect(tagTexts[0]).toContain('15')
123
+ expect(tagTexts[1]).toContain('20')
124
+ expect(tagTexts[2]).toContain('25')
125
+ })
126
+ })
127
+
128
+ describe('Range selection', () => {
129
+ test('displays range labels when showRangeLabels is true', async () => {
130
+ const rangeValue = '2024-06-15,2024-06-20'
131
+ const container = await createDatepicker(`value="${rangeValue}" range showRangeLabels`)
132
+
133
+ const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
134
+ await datepicker.updateComplete
135
+
136
+ expect(datepicker.showRangeLabels).toBe(true)
137
+
138
+ const rangeLabels = datepicker.querySelectorAll('.pkt-input-prefix')
139
+ expect(rangeLabels.length).toBeGreaterThan(0)
140
+ })
141
+
142
+ test('populates both input fields when initialized with range value', async () => {
143
+ const rangeValue = '2024-06-15,2024-06-20'
144
+ const container = await createDatepicker(`value="${rangeValue}" range`)
145
+
146
+ const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
147
+ await datepicker.updateComplete
148
+
149
+ const inputs = datepicker.querySelectorAll('input')
150
+ expect(inputs.length).toBe(2)
151
+
152
+ // Check that both input fields are populated
153
+ expect(inputs[0].value).toBe('2024-06-15')
154
+ expect(inputs[1].value).toBe('2024-06-20')
155
+
156
+ // Check internal state
157
+ expect(datepicker._value).toEqual(['2024-06-15', '2024-06-20'])
158
+ expect(datepicker.value).toBe('2024-06-15,2024-06-20')
159
+ })
160
+
161
+ test('dispatches value-change event with array for range and multiple datepickers', async () => {
162
+ // Test range datepicker
163
+ const rangeContainer = await createDatepicker('range')
164
+ const rangeDatepicker = rangeContainer.querySelector('pkt-datepicker') as PktDatepicker
165
+ await rangeDatepicker.updateComplete
166
+
167
+ let valueChangeEvent: CustomEvent | null = null
168
+ rangeDatepicker.addEventListener('value-change', (e: Event) => {
169
+ valueChangeEvent = e as CustomEvent
170
+ })
171
+
172
+ // Set a range value programmatically
173
+ rangeDatepicker.value = '2024-06-15,2024-06-20'
174
+ await rangeDatepicker.updateComplete
175
+
176
+ expect(valueChangeEvent).toBeTruthy()
177
+ expect(valueChangeEvent!.detail).toEqual(['2024-06-15', '2024-06-20'])
178
+
179
+ // Test multiple datepicker
180
+ const multipleContainer = await createDatepicker('multiple')
181
+ const multipleDatepicker = multipleContainer.querySelector('pkt-datepicker') as PktDatepicker
182
+ await multipleDatepicker.updateComplete
183
+
184
+ valueChangeEvent = null
185
+ multipleDatepicker.addEventListener('value-change', (e: Event) => {
186
+ valueChangeEvent = e as CustomEvent
187
+ })
188
+
189
+ // Set multiple values programmatically
190
+ multipleDatepicker.value = '2024-06-15,2024-06-20,2024-06-25'
191
+ await multipleDatepicker.updateComplete
192
+
193
+ expect(valueChangeEvent).toBeTruthy()
194
+ expect(valueChangeEvent!.detail).toEqual(['2024-06-15', '2024-06-20', '2024-06-25'])
195
+
196
+ // Test single datepicker
197
+ const singleContainer = await createDatepicker('')
198
+ const singleDatepicker = singleContainer.querySelector('pkt-datepicker') as PktDatepicker
199
+ await singleDatepicker.updateComplete
200
+
201
+ valueChangeEvent = null
202
+ singleDatepicker.addEventListener('value-change', (e: Event) => {
203
+ valueChangeEvent = e as CustomEvent
204
+ })
205
+
206
+ // Set single value programmatically
207
+ singleDatepicker.value = '2024-06-15'
208
+ await singleDatepicker.updateComplete
209
+
210
+ expect(valueChangeEvent).toBeTruthy()
211
+ expect(valueChangeEvent!.detail).toBe('2024-06-15')
212
+ })
213
+
214
+ test('handles range selection through calendar', async () => {
215
+ const container = await createDatepicker('range')
216
+
217
+ const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
218
+ await datepicker.updateComplete
219
+
220
+ // Open calendar
221
+ const calendarButton = datepicker.querySelector('button[type="button"]')
222
+ fireEvent.click(calendarButton!)
223
+ await datepicker.updateComplete
224
+
225
+ const availableDates = datepicker.querySelectorAll(
226
+ '[data-date]:not([data-disabled="disabled"])',
227
+ )
228
+
229
+ // Select start date
230
+ if (availableDates.length > 5) {
231
+ fireEvent.click(availableDates[5])
232
+ await datepicker.updateComplete
233
+
234
+ // Select end date
235
+ if (availableDates.length > 10) {
236
+ fireEvent.click(availableDates[10])
237
+ await datepicker.updateComplete
238
+
239
+ // Should have range value
240
+ expect(datepicker.value).toContain(',')
241
+ const values = (datepicker.value as string).split(',')
242
+ expect(values.length).toBe(2)
243
+ }
244
+ }
245
+ })
246
+
247
+ test('validates range order', async () => {
248
+ const invalidRange = '2024-06-20,2024-06-15' // End before start
249
+ const container = await createDatepicker(`value="${invalidRange}" range`)
250
+
251
+ const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
252
+ await datepicker.updateComplete
253
+
254
+ // Should handle invalid range gracefully
255
+ expect(datepicker).toBeInTheDocument()
256
+ })
257
+
258
+ test('shows range preview on hover', async () => {
259
+ const container = await createDatepicker('range')
260
+
261
+ const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
262
+ await datepicker.updateComplete
263
+
264
+ // Open calendar
265
+ const calendarButton = datepicker.querySelector('button[type="button"]')
266
+ fireEvent.click(calendarButton!)
267
+ await datepicker.updateComplete
268
+
269
+ const availableDates = datepicker.querySelectorAll(
270
+ '.pkt-calendar__date:not(.pkt-calendar__date--disabled)',
271
+ )
272
+
273
+ // Select start date
274
+ fireEvent.click(availableDates[5])
275
+ await datepicker.updateComplete
276
+
277
+ // Hover over potential end date
278
+ fireEvent.mouseOver(availableDates[10])
279
+ await datepicker.updateComplete
280
+
281
+ // Should show hover preview
282
+ const hoverRanges = datepicker.querySelectorAll('.pkt-calendar__date--in-range-hover')
283
+ expect(hoverRanges.length).toBeGreaterThan(0)
284
+ })
285
+ })
286
+ })
@@ -1,7 +1,13 @@
1
1
  import { classMap } from 'lit/directives/class-map.js'
2
2
  import { ifDefined } from 'lit/directives/if-defined.js'
3
3
  import { customElement, property, state } from 'lit/decorators.js'
4
- import { formatISODate, fromISOToDate, fromISOtoLocal, newDate } from '@/utils/dateutils'
4
+ import {
5
+ formatISODate,
6
+ fromISOToDate,
7
+ fromISOtoLocal,
8
+ newDate,
9
+ parseISODateString,
10
+ } from '@/utils/dateutils'
5
11
  import { html, nothing, PropertyValues } from 'lit'
6
12
  import { PktCalendar } from '@/components/calendar/calendar'
7
13
  import { PktInputElement } from '@/base-elements/input-element'
@@ -21,15 +27,22 @@ export class PktDatepicker extends PktInputElement {
21
27
  /**
22
28
  * Element attributes and properties
23
29
  */
30
+ private _valueProperty: string = ''
31
+
24
32
  @property({ type: String, reflect: true })
25
- value: string | string[] = ''
33
+ get value(): string {
34
+ return this._valueProperty
35
+ }
36
+
37
+ set value(newValue: string | string[]) {
38
+ const oldValue = this._valueProperty
39
+ this._valueProperty = Array.isArray(newValue) ? newValue.join(',') : newValue || ''
40
+ this.valueChanged(this._valueProperty, oldValue)
41
+ this.requestUpdate('value', oldValue)
42
+ }
26
43
 
27
44
  @property({ type: Array })
28
- _value: string[] = this.value
29
- ? !Array.isArray(this.value)
30
- ? this.value.split(',')
31
- : this.value
32
- : []
45
+ _value: string[] = []
33
46
 
34
47
  @property({ type: String, reflect: true })
35
48
  label: string = 'Datovelger'
@@ -112,8 +125,17 @@ export class PktDatepicker extends PktInputElement {
112
125
  }
113
126
  })
114
127
 
115
- if (this.value.length && this._value.length === 0) {
116
- this._value = !Array.isArray(this.value) ? this.value.split(',') : this.value
128
+ document &&
129
+ document.body.addEventListener('keydown', (e: KeyboardEvent) => {
130
+ if (e.key === 'Escape' && this.calendarOpen) {
131
+ this.hideCalendar()
132
+ }
133
+ })
134
+
135
+ if (this.value) {
136
+ this._value = Array.isArray(this.value)
137
+ ? this.value.filter(Boolean)
138
+ : this.value.split(',').filter(Boolean)
117
139
  }
118
140
  this.min = this.min || specs.props.min.default
119
141
  this.max = this.max || specs.props.max.default
@@ -151,10 +173,55 @@ export class PktDatepicker extends PktInputElement {
151
173
  })
152
174
  }
153
175
 
176
+ onInput(): void {
177
+ // Trigger input event for form validation
178
+ this.dispatchEvent(new Event('input', { bubbles: true }))
179
+ }
180
+
181
+ valueChanged(newValue: string | null, oldValue: string | null): void {
182
+ if (newValue !== oldValue) {
183
+ let validatedValue: string[] = []
184
+
185
+ if (newValue) {
186
+ // Handle case where newValue might be a string or need conversion
187
+ if (typeof newValue === 'string') {
188
+ validatedValue = newValue.split(',').filter(Boolean)
189
+ } else {
190
+ // If not a string, convert to string first
191
+ validatedValue = String(newValue).split(',').filter(Boolean)
192
+ }
193
+ }
194
+
195
+ // Validate dates against min/max boundaries
196
+ if (this.min || this.max) {
197
+ const minDate = this.min ? new Date(this.min) : null
198
+ const maxDate = this.max ? new Date(this.max) : null
199
+
200
+ validatedValue = validatedValue.filter((dateStr) => {
201
+ const date = new Date(dateStr)
202
+ if (isNaN(date.getTime())) return false
203
+ if (minDate && date < minDate) return false
204
+ if (maxDate && date > maxDate) return false
205
+ return true
206
+ })
207
+ }
208
+
209
+ this._value = validatedValue
210
+
211
+ // Update the public value property to reflect validated value
212
+ const validatedValueString = validatedValue.join(',')
213
+ if (this._valueProperty !== validatedValueString) {
214
+ this._valueProperty = validatedValueString
215
+ }
216
+
217
+ // Call base class valueChanged to handle events properly
218
+ super.valueChanged(validatedValueString, oldValue)
219
+ }
220
+ }
221
+
154
222
  attributeChangedCallback(name: string, _old: string | null, value: string | null): void {
155
- if (name === 'value') {
156
- if (this.range && value?.split(',').length === 1) return
157
- if (this.value !== _old) this.valueChanged(value, _old)
223
+ if (name === 'value' && this.value !== _old) {
224
+ this.valueChanged(value, _old)
158
225
  }
159
226
 
160
227
  if (name === 'excludedates' && typeof this.excludedates === 'string') {
@@ -168,6 +235,12 @@ export class PktDatepicker extends PktInputElement {
168
235
  }
169
236
 
170
237
  updated(changedProperties: PropertyValues): void {
238
+ if (changedProperties.has('value')) {
239
+ const newValue = Array.isArray(this.value) ? this.value.join(',') : this.value
240
+ const oldValue = changedProperties.get('value')
241
+ const oldValueStr = Array.isArray(oldValue) ? oldValue.join(',') : oldValue
242
+ this.valueChanged(newValue, oldValueStr)
243
+ }
171
244
  if (changedProperties.has('multiple')) {
172
245
  // If multiple is now true, ensure _value is an array of non-empty strings
173
246
  if (this.multiple && !Array.isArray(this._value)) {
@@ -180,8 +253,8 @@ export class PktDatepicker extends PktInputElement {
180
253
  } else if (!this.multiple && Array.isArray(this._value)) {
181
254
  this._value = this._value.filter(Boolean)
182
255
  }
183
- // If multiple is now false, ensure _value is a single value
184
- if (!this.multiple && Array.isArray(this._value)) {
256
+ // If multiple is now false, ensure _value is a single value (but not for range datepickers)
257
+ if (!this.multiple && !this.range && Array.isArray(this._value)) {
185
258
  this._value = [this._value[0] ?? '']
186
259
  }
187
260
  }
@@ -212,6 +285,9 @@ export class PktDatepicker extends PktInputElement {
212
285
  .value=${this._value[0] ?? ''}
213
286
  min=${ifDefined(this.min)}
214
287
  max=${ifDefined(this.max)}
288
+ placeholder=${ifDefined(this.placeholder)}
289
+ ?readonly=${this.readonly}
290
+ aria-describedby="${this.id}-helptext"
215
291
  @click=${(e: MouseEvent) => {
216
292
  e.preventDefault()
217
293
  this.showCalendar()
@@ -276,6 +352,8 @@ export class PktDatepicker extends PktInputElement {
276
352
  .value=${this._value[0] ?? ''}
277
353
  min=${ifDefined(this.min)}
278
354
  max=${ifDefined(this.max)}
355
+ placeholder=${ifDefined(this.placeholder)}
356
+ ?readonly=${this.readonly}
279
357
  ?disabled=${this.disabled}
280
358
  @click=${(e: MouseEvent) => {
281
359
  e.preventDefault()
@@ -339,6 +417,8 @@ export class PktDatepicker extends PktInputElement {
339
417
  .value=${this._value[1] ?? ''}
340
418
  min=${ifDefined(this.min)}
341
419
  max=${ifDefined(this.max)}
420
+ placeholder=${ifDefined(this.placeholder)}
421
+ ?readonly=${this.readonly}
342
422
  ?disabled=${this.disabled}
343
423
  @click=${(e: MouseEvent) => {
344
424
  e.preventDefault()
@@ -409,7 +489,6 @@ export class PktDatepicker extends PktInputElement {
409
489
  }
410
490
 
411
491
  renderMultipleInput() {
412
- console.log('range', this.range, 'multiple', this.multiple)
413
492
  return html`
414
493
  <input
415
494
  class=${classMap(this.inputClasses)}
@@ -417,6 +496,8 @@ export class PktDatepicker extends PktInputElement {
417
496
  id="${this.id}-input"
418
497
  min=${ifDefined(this.min)}
419
498
  max=${ifDefined(this.max)}
499
+ placeholder=${ifDefined(this.placeholder)}
500
+ ?readonly=${this.readonly}
420
501
  ?disabled=${this.disabled || (this.maxlength && this._value.length >= this.maxlength)}
421
502
  @click=${(e: MouseEvent) => {
422
503
  e.preventDefault()
@@ -470,7 +551,7 @@ export class PktDatepicker extends PktInputElement {
470
551
  <div class="pkt-datepicker__tags" aria-live="polite">
471
552
  ${!!this._value[0]
472
553
  ? repeat(
473
- (this._value ?? []).filter(Boolean),
554
+ (this._value ?? []).filter(Boolean).sort(),
474
555
  (date) => date,
475
556
  (date) => html`
476
557
  <pkt-tag
@@ -513,16 +594,26 @@ export class PktDatepicker extends PktInputElement {
513
594
  ? this.excludedates
514
595
  : (this.excludedates as string).split(',')}
515
596
  .excludeweekdays=${this.excludeweekdays}
516
- .currentmonth=${this.currentmonth ? newDate(this.currentmonth) : null}
597
+ .currentmonth=${this.currentmonth ? parseISODateString(this.currentmonth) : null}
517
598
  @date-selected=${(e: CustomEvent) => {
518
- this.value = !this.multiple && !this.range ? e.detail[0] : e.detail
599
+ this.value =
600
+ !this.multiple && !this.range
601
+ ? e.detail[0]
602
+ : Array.isArray(e.detail)
603
+ ? e.detail.join(',')
604
+ : e.detail
519
605
  this._value = e.detail
520
606
  if (this.inputRef.value) {
521
607
  if (this.range && this.inputRefTo.value) {
522
608
  this.inputRef.value.value = this._value[0] ?? ''
523
609
  this.inputRefTo.value.value = this._value[1] ?? ''
610
+ // Update validity state after programmatic value change
611
+ this.manageValidity(this.inputRef.value)
612
+ this.manageValidity(this.inputRefTo.value)
524
613
  } else if (!this.multiple) {
525
614
  this.inputRef.value.value = this._value.length ? this._value[0] : ''
615
+ // Update validity state after programmatic value change
616
+ this.manageValidity(this.inputRef.value)
526
617
  }
527
618
  }
528
619
  }}
@@ -536,7 +627,6 @@ export class PktDatepicker extends PktInputElement {
536
627
  }
537
628
 
538
629
  render() {
539
- console.log('multiple', this.multiple, 'value', this.value, '_value', this._value)
540
630
  this.inputClasses = {
541
631
  'pkt-input': true,
542
632
  'pkt-datepicker__input': true,
@@ -551,6 +641,7 @@ export class PktDatepicker extends PktInputElement {
551
641
  'pkt-btn': true,
552
642
  'pkt-btn--icon-only': true,
553
643
  'pkt-btn--tertiary': true,
644
+ 'pkt-datepicker__calendar-button': true,
554
645
  }
555
646
 
556
647
  return html`
@@ -595,6 +686,12 @@ export class PktDatepicker extends PktInputElement {
595
686
  class="${classMap(this.buttonClasses)}"
596
687
  type="button"
597
688
  @click=${this.toggleCalendar}
689
+ @keydown=${(e: KeyboardEvent) => {
690
+ if (e.key === 'Enter' || e.key === ' ' || e.key === 'Space') {
691
+ e.preventDefault()
692
+ this.toggleCalendar(e)
693
+ }
694
+ }}
598
695
  ?disabled=${this.disabled}
599
696
  ${ref(this.btnRef)}
600
697
  >
@@ -677,4 +774,9 @@ export class PktDatepicker extends PktInputElement {
677
774
  e.preventDefault()
678
775
  this.calendarOpen ? this.hideCalendar() : this.showCalendar()
679
776
  }
777
+
778
+ public clearInputValue() {
779
+ this._value = []
780
+ this.value = ''
781
+ }
680
782
  }