@oslokommune/punkt-elements 13.6.12 → 13.7.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 (147) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/{accordionitem-B_h5XGCo.js → accordionitem-C_URrDjP.js} +4 -4
  3. package/dist/{accordionitem-BOmnm80g.cjs → accordionitem-DCZrHVNR.cjs} +1 -1
  4. package/dist/{alert-ZP5-fqlt.cjs → alert-Ci7WvRXi.cjs} +1 -1
  5. package/dist/{alert-CTTm6ugp.js → alert-Dh1YhaBq.js} +13 -26
  6. package/dist/{backlink-BT7DO6rV.cjs → backlink-BzEvli8m.cjs} +1 -1
  7. package/dist/{backlink-Bq8O2bt8.js → backlink-CI_jMGzZ.js} +3 -3
  8. package/dist/{button-x6Xw-5w0.js → button-CCFAUJa0.js} +5 -5
  9. package/dist/{button-BfqxLnMT.cjs → button-CXJQ_Wgl.cjs} +1 -1
  10. package/dist/calendar-BaMrdMDZ.cjs +115 -0
  11. package/dist/{calendar-CodWwTHM.js → calendar-DtJh7UYD.js} +532 -480
  12. package/dist/{card-B9RPShvV.cjs → card-Cf-UcGAP.cjs} +1 -1
  13. package/dist/{card-en2KhOPO.js → card-M1X36b6i.js} +8 -26
  14. package/dist/{checkbox-CH8xeK-0.cjs → checkbox-CTxc8wQe.cjs} +1 -1
  15. package/dist/{checkbox-DSAcMC-D.js → checkbox-_5LbXU7N.js} +4 -4
  16. package/dist/class-map-C_erArZz.cjs +5 -0
  17. package/dist/{class-map-Dw6Wrxwi.js → class-map-wy7PUk0P.js} +3 -3
  18. package/dist/{combobox-BFOjlFIj.cjs → combobox-BJ1gA0f0.cjs} +1 -1
  19. package/dist/{combobox-DaiEdUKx.js → combobox-Ct0NNY1p.js} +12 -16
  20. package/dist/{consent-CXp0bLvg.js → consent-B2hIQh4b.js} +3 -3
  21. package/dist/{consent-DFrsiYGQ.cjs → consent-BeOjxQdR.cjs} +1 -1
  22. package/dist/datepicker-B8mifBAm.js +1374 -0
  23. package/dist/datepicker-DVqmQAOe.cjs +289 -0
  24. package/dist/directive-helpers-4oOjKnGY.cjs +5 -0
  25. package/dist/directive-helpers-BzAtj9by.js +38 -0
  26. package/dist/{element-D62wHiNU.cjs → element-CJ_QKaki.cjs} +6 -6
  27. package/dist/{element-DJZPsA_J.js → element-CRDRygXu.js} +47 -132
  28. package/dist/{heading-H_FWjo2k.cjs → heading--JKFppLS.cjs} +1 -1
  29. package/dist/{heading-DQ0R34j4.js → heading-Cs5yGnJg.js} +1 -1
  30. package/dist/{helptext-D1fkGmfT.cjs → helptext-CVQP3pis.cjs} +1 -1
  31. package/dist/{helptext-8ykxyegi.js → helptext-DuvVSH7d.js} +6 -6
  32. package/dist/icon-1dy7UZcu.js +89 -0
  33. package/dist/icon-BGuizDwk.cjs +9 -0
  34. package/dist/{if-defined-D3lgJqT7.js → if-defined-BWZGb3bh.js} +1 -1
  35. package/dist/{if-defined-CkVc_RJD.cjs → if-defined-Bc9-_I01.cjs} +1 -1
  36. package/dist/index.d.ts +98 -6
  37. package/dist/input-element-BcFmygSF.js +707 -0
  38. package/dist/input-element-j9znzLWz.cjs +1 -0
  39. package/dist/{input-wrapper-DVjNwf8-.cjs → input-wrapper-BsQ7oFMd.cjs} +1 -1
  40. package/dist/input-wrapper-CDgenrYA.js +6 -0
  41. package/dist/{input-wrapper-CQzXG44g.js → input-wrapper-CKJU0QWG.js} +8 -8
  42. package/dist/{link-CyiVlb-7.cjs → link-Da3pZ_CW.cjs} +1 -1
  43. package/dist/{link-DSSJYrtn.js → link-DzZCw8j2.js} +9 -16
  44. package/dist/{linkcard-fH9uydjS.cjs → linkcard-BM23gzhS.cjs} +1 -1
  45. package/dist/{linkcard-g8JtooPU.js → linkcard-RIK5xqbd.js} +4 -4
  46. package/dist/{listbox-L-iOSF7M.cjs → listbox-CsGiqzD0.cjs} +1 -1
  47. package/dist/{listbox-n4wjlLqD.js → listbox-DlJevu8O.js} +5 -5
  48. package/dist/{loader-Bzf1sPSg.js → loader-BVvBzaPI.js} +5 -5
  49. package/dist/{loader-C-3l7kb9.cjs → loader-Bo8RCbCJ.cjs} +1 -1
  50. package/dist/{messagebox---xPIAwR.cjs → messagebox-C76IcXTl.cjs} +1 -1
  51. package/dist/{messagebox-okJLeSpj.js → messagebox-DwdMXoAe.js} +6 -16
  52. package/dist/{modal-pohCsr_x.js → modal-BGXk3f9u.js} +6 -16
  53. package/dist/{modal-IjDRQfX1.cjs → modal-Cdz9JcCX.cjs} +1 -1
  54. package/dist/pkt-accordion.cjs +1 -1
  55. package/dist/pkt-accordion.js +2 -2
  56. package/dist/pkt-alert.cjs +1 -1
  57. package/dist/pkt-alert.js +1 -1
  58. package/dist/pkt-backlink.cjs +1 -1
  59. package/dist/pkt-backlink.js +1 -1
  60. package/dist/pkt-button.cjs +1 -1
  61. package/dist/pkt-button.js +1 -1
  62. package/dist/pkt-calendar.cjs +1 -1
  63. package/dist/pkt-calendar.js +1 -1
  64. package/dist/pkt-card.cjs +1 -1
  65. package/dist/pkt-card.js +1 -1
  66. package/dist/pkt-checkbox.cjs +1 -1
  67. package/dist/pkt-checkbox.js +1 -1
  68. package/dist/pkt-combobox.cjs +1 -1
  69. package/dist/pkt-combobox.js +1 -1
  70. package/dist/pkt-consent.cjs +1 -1
  71. package/dist/pkt-consent.js +1 -1
  72. package/dist/pkt-datepicker.cjs +1 -1
  73. package/dist/pkt-datepicker.js +8 -4
  74. package/dist/pkt-heading.cjs +1 -1
  75. package/dist/pkt-heading.js +1 -1
  76. package/dist/pkt-helptext.cjs +1 -1
  77. package/dist/pkt-helptext.js +1 -1
  78. package/dist/pkt-icon.cjs +1 -1
  79. package/dist/pkt-icon.js +1 -1
  80. package/dist/pkt-index.cjs +1 -1
  81. package/dist/pkt-index.js +29 -29
  82. package/dist/pkt-input-wrapper.cjs +1 -1
  83. package/dist/pkt-input-wrapper.js +1 -1
  84. package/dist/pkt-link.cjs +1 -1
  85. package/dist/pkt-link.js +1 -1
  86. package/dist/pkt-linkcard.cjs +1 -1
  87. package/dist/pkt-linkcard.js +1 -1
  88. package/dist/pkt-listbox.cjs +1 -1
  89. package/dist/pkt-listbox.js +1 -1
  90. package/dist/pkt-loader.cjs +1 -1
  91. package/dist/pkt-loader.js +1 -1
  92. package/dist/pkt-messagebox.cjs +1 -1
  93. package/dist/pkt-messagebox.js +1 -1
  94. package/dist/pkt-modal.cjs +1 -1
  95. package/dist/pkt-modal.js +1 -1
  96. package/dist/pkt-progressbar.cjs +1 -1
  97. package/dist/pkt-progressbar.js +2 -2
  98. package/dist/pkt-radiobutton.cjs +1 -1
  99. package/dist/pkt-radiobutton.js +1 -1
  100. package/dist/pkt-select.cjs +1 -1
  101. package/dist/pkt-select.js +1 -1
  102. package/dist/pkt-tag.cjs +1 -1
  103. package/dist/pkt-tag.js +1 -1
  104. package/dist/pkt-textarea.cjs +1 -1
  105. package/dist/pkt-textarea.js +1 -1
  106. package/dist/pkt-textinput.cjs +1 -1
  107. package/dist/pkt-textinput.js +1 -1
  108. package/dist/{progressbar-DjsupQ7Y.js → progressbar-BbVei20_.js} +7 -7
  109. package/dist/{progressbar-DJzEC7cx.cjs → progressbar-CazcIzVT.cjs} +2 -2
  110. package/dist/{radiobutton-DEboKECm.cjs → radiobutton-D1fihs8R.cjs} +1 -1
  111. package/dist/{radiobutton-Bz_qApF3.js → radiobutton-DODROIBF.js} +5 -5
  112. package/dist/{ref-BfgcOXko.cjs → ref-BFa5Utho.cjs} +1 -1
  113. package/dist/{ref-BCGCor-j.js → ref-Xa5dbh--.js} +2 -2
  114. package/dist/repeat-BZb41H64.cjs +5 -0
  115. package/dist/{repeat-B6qPUgAq.js → repeat-CJ79egkN.js} +8 -8
  116. package/dist/{select-DKkoxmgj.js → select-BG2MBQbh.js} +6 -6
  117. package/dist/{select-DynzsPo0.cjs → select-D-m1PhpA.cjs} +1 -1
  118. package/dist/{state-CPQXJ4Ct.js → state-DS_kr2Fy.js} +1 -1
  119. package/dist/{state-BkE_Rxl7.cjs → state-DSjcvzDN.cjs} +1 -1
  120. package/dist/{tag-NZ5oeGfw.js → tag-CqMgt01I.js} +7 -20
  121. package/dist/{tag-BKq07hGI.cjs → tag-EFUKrc8q.cjs} +2 -2
  122. package/dist/{textarea-COG1CH_s.js → textarea-DCKKhs1B.js} +9 -9
  123. package/dist/{textarea-BS1tgktz.cjs → textarea-aUG3S7C2.cjs} +1 -1
  124. package/dist/{textinput-CTOtfcTR.js → textinput-B5Ai5R8L.js} +8 -8
  125. package/dist/{textinput-CCK8ti2y.cjs → textinput-mUERucRy.cjs} +1 -1
  126. package/package.json +15 -7
  127. package/src/components/combobox/combobox.ts +1 -1
  128. package/src/components/datepicker/datepicker-multiple.ts +202 -0
  129. package/src/components/datepicker/datepicker-range.ts +281 -0
  130. package/src/components/datepicker/datepicker-single.ts +198 -0
  131. package/src/components/datepicker/datepicker-utils.ts +9 -1
  132. package/src/components/datepicker/datepicker.ts +141 -213
  133. package/src/components/datepicker/index.ts +5 -1
  134. package/src/components/icon/icon.ts +16 -7
  135. package/src/components/select/select.ts +1 -1
  136. package/dist/calendar-DH-fCGyW.cjs +0 -115
  137. package/dist/class-map-CG3vIaNm.cjs +0 -5
  138. package/dist/datepicker-C244h82t.cjs +0 -190
  139. package/dist/datepicker-DwOkktaP.js +0 -859
  140. package/dist/directive-helpers-_qHew-gi.cjs +0 -5
  141. package/dist/directive-helpers-cAOIHg9K.js +0 -45
  142. package/dist/icon-B1-mkmwB.js +0 -88
  143. package/dist/icon-__Hjt2XZ.cjs +0 -9
  144. package/dist/input-element-DQOVrqUZ.js +0 -703
  145. package/dist/input-element-Y8sdrq9C.cjs +0 -1
  146. package/dist/input-wrapper-8iKEzDRZ.js +0 -40
  147. package/dist/repeat-DzibMwhi.cjs +0 -5
@@ -0,0 +1,202 @@
1
+ import { html } from 'lit'
2
+ import { customElement, property } from 'lit/decorators.js'
3
+ import { classMap } from 'lit/directives/class-map.js'
4
+ import { ifDefined } from 'lit/directives/if-defined.js'
5
+ import { Ref, createRef, ref } from 'lit/directives/ref.js'
6
+ import { PktElement } from '@/base-elements/element'
7
+ import { keyboardUtils, formUtils, deviceDetection, cssUtils } from './datepicker-utils'
8
+ import '@/components/icon'
9
+
10
+ @customElement('pkt-datepicker-multiple')
11
+ export class PktDatepickerMultiple extends PktElement {
12
+ @property({ type: Array })
13
+ value: string[] = []
14
+
15
+ @property({ type: String })
16
+ inputType: string = 'date'
17
+
18
+ @property({ type: String })
19
+ id: string = ''
20
+
21
+ @property({ type: String })
22
+ min?: string
23
+
24
+ @property({ type: String })
25
+ max?: string
26
+
27
+ @property({ type: String })
28
+ placeholder?: string
29
+
30
+ @property({ type: Boolean })
31
+ readonly: boolean = false
32
+
33
+ @property({ type: Boolean })
34
+ disabled: boolean = false
35
+
36
+ @property({ type: Number })
37
+ maxlength?: number
38
+
39
+ @property({ type: Object })
40
+ inputClasses: Record<string, boolean> = {}
41
+
42
+ @property({ type: Object })
43
+ internals?: any
44
+
45
+ @property({ type: Object })
46
+ strings: any = { calendar: { buttonAltText: 'Åpne kalender' } }
47
+
48
+ inputRef: Ref<HTMLInputElement> = createRef()
49
+ btnRef: Ref<HTMLButtonElement> = createRef()
50
+
51
+ get inputElement(): HTMLInputElement | undefined {
52
+ return this.inputRef.value
53
+ }
54
+
55
+ get buttonElement(): HTMLButtonElement | undefined {
56
+ return this.btnRef.value
57
+ }
58
+
59
+ get isInputReadonly(): boolean {
60
+ return this.readonly || this.inputType === 'text'
61
+ }
62
+
63
+ get isInputDisabled(): boolean {
64
+ return (
65
+ this.disabled ||
66
+ (this.maxlength !== undefined &&
67
+ this.maxlength !== null &&
68
+ this.value.length >= this.maxlength)
69
+ )
70
+ }
71
+
72
+ private dispatchToggleCalendar(e: Event) {
73
+ if (this.readonly) return
74
+
75
+ this.dispatchEvent(
76
+ new CustomEvent('toggle-calendar', {
77
+ detail: e,
78
+ bubbles: true,
79
+ composed: true,
80
+ }),
81
+ )
82
+ }
83
+
84
+ private dispatchInput(e: Event) {
85
+ this.dispatchEvent(
86
+ new CustomEvent('input-change', {
87
+ detail: e,
88
+ bubbles: true,
89
+ composed: true,
90
+ }),
91
+ )
92
+ }
93
+
94
+ private dispatchFocus() {
95
+ this.dispatchEvent(
96
+ new CustomEvent('input-focus', {
97
+ bubbles: true,
98
+ composed: true,
99
+ }),
100
+ )
101
+ }
102
+
103
+ private dispatchBlur(e: FocusEvent) {
104
+ this.dispatchEvent(
105
+ new CustomEvent('input-blur', {
106
+ detail: e,
107
+ bubbles: true,
108
+ composed: true,
109
+ }),
110
+ )
111
+ }
112
+
113
+ private dispatchChange(e: Event) {
114
+ this.dispatchEvent(
115
+ new CustomEvent('input-changed', {
116
+ detail: e,
117
+ bubbles: true,
118
+ composed: true,
119
+ }),
120
+ )
121
+ }
122
+
123
+ private dispatchAddToSelected(e: Event | KeyboardEvent) {
124
+ this.dispatchEvent(
125
+ new CustomEvent('add-to-selected', {
126
+ detail: e,
127
+ bubbles: true,
128
+ composed: true,
129
+ }),
130
+ )
131
+ }
132
+
133
+ createRenderRoot() {
134
+ return this
135
+ }
136
+
137
+ render() {
138
+ return html`
139
+ <div class="pkt-input__container">
140
+ <input
141
+ class=${classMap(this.inputClasses)}
142
+ .type=${this.inputType}
143
+ id="${this.id}-input"
144
+ min=${ifDefined(this.min)}
145
+ max=${ifDefined(this.max)}
146
+ placeholder=${ifDefined(this.placeholder)}
147
+ ?readonly=${this.isInputReadonly}
148
+ ?disabled=${this.isInputDisabled}
149
+ @click=${(e: MouseEvent) => {
150
+ e.preventDefault()
151
+ this.dispatchToggleCalendar(e)
152
+ }}
153
+ @touchend=${(e: TouchEvent) => {
154
+ e.preventDefault()
155
+ this.dispatchToggleCalendar(e)
156
+ }}
157
+ @blur=${(e: FocusEvent) => {
158
+ this.dispatchBlur(e)
159
+ this.dispatchAddToSelected(e)
160
+ }}
161
+ @input=${(e: Event) => {
162
+ this.dispatchInput(e)
163
+ e.stopImmediatePropagation()
164
+ }}
165
+ @focus=${() => {
166
+ this.dispatchFocus()
167
+ if (deviceDetection.isIOS()) {
168
+ this.dispatchToggleCalendar(new Event('focus'))
169
+ }
170
+ }}
171
+ @keydown=${(e: KeyboardEvent) =>
172
+ keyboardUtils.handleInputKeydown(
173
+ e,
174
+ (event) => this.dispatchToggleCalendar(event),
175
+ () =>
176
+ formUtils.submitFormOrFallback(this.internals, () => this.inputRef.value?.blur()),
177
+ undefined,
178
+ undefined,
179
+ (event) => this.dispatchAddToSelected(event),
180
+ )}
181
+ @change=${(e: Event) => {
182
+ this.dispatchChange(e)
183
+ e.stopImmediatePropagation()
184
+ }}
185
+ ${ref(this.inputRef)}
186
+ />
187
+ <button
188
+ class="${classMap(cssUtils.getButtonClasses())}"
189
+ type="button"
190
+ @click=${(e: Event) => this.dispatchToggleCalendar(e)}
191
+ @keydown=${(e: KeyboardEvent) =>
192
+ keyboardUtils.handleButtonKeydown(e, (event) => this.dispatchToggleCalendar(event))}
193
+ ?disabled=${this.disabled}
194
+ ${ref(this.btnRef)}
195
+ >
196
+ <pkt-icon name="calendar"></pkt-icon>
197
+ <span class="pkt-btn__text">${this.strings.calendar.buttonAltText}</span>
198
+ </button>
199
+ </div>
200
+ `
201
+ }
202
+ }
@@ -0,0 +1,281 @@
1
+ import { html, nothing } from 'lit'
2
+ import { customElement, property } from 'lit/decorators.js'
3
+ import { classMap } from 'lit/directives/class-map.js'
4
+ import { ifDefined } from 'lit/directives/if-defined.js'
5
+ import { Ref, createRef, ref } from 'lit/directives/ref.js'
6
+ import { PktElement } from '@/base-elements/element'
7
+ import { keyboardUtils, formUtils, deviceDetection, cssUtils } from './datepicker-utils'
8
+ import '@/components/icon'
9
+
10
+ @customElement('pkt-datepicker-range')
11
+ export class PktDatepickerRange extends PktElement {
12
+ @property({ type: Array })
13
+ value: string[] = []
14
+
15
+ @property({ type: String })
16
+ inputType: string = 'date'
17
+
18
+ @property({ type: String })
19
+ id: string = ''
20
+
21
+ @property({ type: String })
22
+ min?: string
23
+
24
+ @property({ type: String })
25
+ max?: string
26
+
27
+ @property({ type: String })
28
+ placeholder?: string
29
+
30
+ @property({ type: Boolean })
31
+ readonly: boolean = false
32
+
33
+ @property({ type: Boolean })
34
+ disabled: boolean = false
35
+
36
+ @property({ type: Boolean })
37
+ showRangeLabels: boolean = false
38
+
39
+ @property({ type: Object })
40
+ inputClasses: Record<string, boolean> = {}
41
+
42
+ @property({ type: Object })
43
+ internals?: any
44
+
45
+ @property({ type: Object })
46
+ strings: any = { generic: { from: 'Fra', to: 'Til' } }
47
+
48
+ inputRef: Ref<HTMLInputElement> = createRef()
49
+ inputRefTo: Ref<HTMLInputElement> = createRef()
50
+ btnRef: Ref<HTMLButtonElement> = createRef()
51
+
52
+ get inputElement(): HTMLInputElement | undefined {
53
+ return this.inputRef.value
54
+ }
55
+
56
+ get inputElementTo(): HTMLInputElement | undefined {
57
+ return this.inputRefTo.value
58
+ }
59
+
60
+ get buttonElement(): HTMLButtonElement | undefined {
61
+ return this.btnRef.value
62
+ }
63
+
64
+ get isInputReadonly(): boolean {
65
+ return this.readonly || this.inputType === 'text'
66
+ }
67
+
68
+ private dispatchToggleCalendar(e: Event) {
69
+ if (this.readonly) return
70
+
71
+ this.dispatchEvent(
72
+ new CustomEvent('toggle-calendar', {
73
+ detail: e,
74
+ bubbles: true,
75
+ composed: true,
76
+ }),
77
+ )
78
+ }
79
+
80
+ private dispatchInput(e: Event) {
81
+ this.dispatchEvent(
82
+ new CustomEvent('input-change', {
83
+ detail: e,
84
+ bubbles: true,
85
+ composed: true,
86
+ }),
87
+ )
88
+ }
89
+
90
+ private dispatchFocus() {
91
+ this.dispatchEvent(
92
+ new CustomEvent('input-focus', {
93
+ bubbles: true,
94
+ composed: true,
95
+ }),
96
+ )
97
+ }
98
+
99
+ private dispatchBlur(e: FocusEvent) {
100
+ this.dispatchEvent(
101
+ new CustomEvent('input-blur', {
102
+ detail: e,
103
+ bubbles: true,
104
+ composed: true,
105
+ }),
106
+ )
107
+ }
108
+
109
+ private dispatchChange(e: Event) {
110
+ this.dispatchEvent(
111
+ new CustomEvent('input-changed', {
112
+ detail: e,
113
+ bubbles: true,
114
+ composed: true,
115
+ }),
116
+ )
117
+ }
118
+
119
+ private dispatchManageValidity(input: HTMLInputElement) {
120
+ this.dispatchEvent(
121
+ new CustomEvent('manage-validity', {
122
+ detail: input,
123
+ bubbles: true,
124
+ composed: true,
125
+ }),
126
+ )
127
+ }
128
+
129
+ createRenderRoot() {
130
+ return this
131
+ }
132
+
133
+ render() {
134
+ const rangeLabelClasses = cssUtils.getRangeLabelClasses(this.showRangeLabels)
135
+
136
+ return html`
137
+ <div class="pkt-input__container">
138
+ ${this.showRangeLabels
139
+ ? html` <div class="pkt-input-prefix">${this.strings.generic.from}</div> `
140
+ : nothing}
141
+ <input
142
+ class=${classMap(this.inputClasses)}
143
+ .type=${this.inputType}
144
+ id="${this.id}-input"
145
+ .value=${this.value[0] ?? ''}
146
+ min=${ifDefined(this.min)}
147
+ max=${ifDefined(this.max)}
148
+ placeholder=${ifDefined(this.placeholder)}
149
+ ?readonly=${this.isInputReadonly}
150
+ ?disabled=${this.disabled}
151
+ @click=${(e: MouseEvent) => {
152
+ e.preventDefault()
153
+ this.dispatchToggleCalendar(e)
154
+ }}
155
+ @touchend=${(e: TouchEvent) => {
156
+ e.preventDefault()
157
+ this.dispatchToggleCalendar(e)
158
+ }}
159
+ @keydown=${(e: KeyboardEvent) =>
160
+ keyboardUtils.handleInputKeydown(
161
+ e,
162
+ (event) => this.dispatchToggleCalendar(event),
163
+ () =>
164
+ formUtils.submitFormOrFallback(this.internals, () =>
165
+ this.inputRefTo.value?.focus(),
166
+ ),
167
+ () => this.inputRefTo.value?.focus(),
168
+ () => this.inputRef.value?.blur(),
169
+ )}
170
+ @input=${(e: Event) => {
171
+ this.dispatchInput(e)
172
+ e.stopImmediatePropagation()
173
+ }}
174
+ @focus=${() => {
175
+ this.dispatchFocus()
176
+ if (deviceDetection.isIOS()) {
177
+ this.dispatchToggleCalendar(new Event('focus'))
178
+ }
179
+ }}
180
+ @blur=${(e: Event) => {
181
+ this.dispatchEvent(
182
+ new CustomEvent('range-blur', {
183
+ detail: {
184
+ event: e,
185
+ values: this.value,
186
+ inputType: 'from',
187
+ },
188
+ bubbles: true,
189
+ composed: true,
190
+ }),
191
+ )
192
+ }}
193
+ @change=${(e: Event) => {
194
+ e.stopImmediatePropagation()
195
+ }}
196
+ ${ref(this.inputRef)}
197
+ />
198
+ <div class="${classMap(rangeLabelClasses)}" id="${this.id}-to-label">
199
+ ${this.strings.generic.to}
200
+ </div>
201
+ ${!this.showRangeLabels ? html` <div class="pkt-input-separator">–</div> ` : nothing}
202
+ <input
203
+ class=${classMap(this.inputClasses)}
204
+ .type=${this.inputType}
205
+ id="${this.id}-to"
206
+ aria-labelledby="${this.id}-to-label"
207
+ .value=${this.value[1] ?? ''}
208
+ min=${ifDefined(this.min)}
209
+ max=${ifDefined(this.max)}
210
+ placeholder=${ifDefined(this.placeholder)}
211
+ ?readonly=${this.isInputReadonly}
212
+ ?disabled=${this.disabled}
213
+ @click=${(e: MouseEvent) => {
214
+ e.preventDefault()
215
+ this.dispatchToggleCalendar(e)
216
+ }}
217
+ @touchend=${(e: TouchEvent) => {
218
+ e.preventDefault()
219
+ this.dispatchToggleCalendar(e)
220
+ }}
221
+ @keydown=${(e: KeyboardEvent) =>
222
+ keyboardUtils.handleInputKeydown(
223
+ e,
224
+ (event) => this.dispatchToggleCalendar(event),
225
+ () =>
226
+ formUtils.submitFormOrFallback(this.internals, () => this.inputRefTo.value?.blur()),
227
+ undefined,
228
+ () => this.inputRefTo.value?.blur(),
229
+ )}
230
+ @input=${(e: Event) => {
231
+ this.dispatchInput(e)
232
+ e.stopImmediatePropagation()
233
+ }}
234
+ @focus=${() => {
235
+ this.dispatchFocus()
236
+ if (deviceDetection.isIOS()) {
237
+ this.dispatchToggleCalendar(new Event('focus'))
238
+ }
239
+ }}
240
+ @blur=${(e: FocusEvent) => {
241
+ this.dispatchBlur(e)
242
+ if ((e.target as HTMLInputElement).value) {
243
+ this.dispatchManageValidity(e.target as HTMLInputElement)
244
+ this.dispatchEvent(
245
+ new CustomEvent('validate-date-input', {
246
+ detail: e.target as HTMLInputElement,
247
+ bubbles: true,
248
+ composed: true,
249
+ }),
250
+ )
251
+ this.dispatchEvent(
252
+ new CustomEvent('handle-date-select', {
253
+ detail: (e.target as HTMLInputElement).value,
254
+ bubbles: true,
255
+ composed: true,
256
+ }),
257
+ )
258
+ }
259
+ }}
260
+ @change=${(e: Event) => {
261
+ this.dispatchChange(e)
262
+ e.stopImmediatePropagation()
263
+ }}
264
+ ${ref(this.inputRefTo)}
265
+ />
266
+ <button
267
+ class="${classMap(cssUtils.getButtonClasses())}"
268
+ type="button"
269
+ @click=${(e: Event) => this.dispatchToggleCalendar(e)}
270
+ @keydown=${(e: KeyboardEvent) =>
271
+ keyboardUtils.handleButtonKeydown(e, (event) => this.dispatchToggleCalendar(event))}
272
+ ?disabled=${this.disabled}
273
+ ${ref(this.btnRef)}
274
+ >
275
+ <pkt-icon name="calendar"></pkt-icon>
276
+ <span class="pkt-btn__text">${this.strings.calendar.buttonAltText}</span>
277
+ </button>
278
+ </div>
279
+ `
280
+ }
281
+ }
@@ -0,0 +1,198 @@
1
+ import { html } from 'lit'
2
+ import { customElement, property } from 'lit/decorators.js'
3
+ import { classMap } from 'lit/directives/class-map.js'
4
+ import { ifDefined } from 'lit/directives/if-defined.js'
5
+ import { Ref, createRef, ref } from 'lit/directives/ref.js'
6
+ import { PktElement } from '@/base-elements/element'
7
+ import { keyboardUtils, formUtils, deviceDetection, cssUtils } from './datepicker-utils'
8
+ import '@/components/icon'
9
+
10
+ @customElement('pkt-datepicker-single')
11
+ export class PktDatepickerSingle extends PktElement {
12
+ @property({ type: String })
13
+ value: string = ''
14
+
15
+ @property({ type: String })
16
+ inputType: string = 'date'
17
+
18
+ @property({ type: String })
19
+ id: string = ''
20
+
21
+ @property({ type: String })
22
+ min?: string
23
+
24
+ @property({ type: String })
25
+ max?: string
26
+
27
+ @property({ type: String })
28
+ placeholder?: string
29
+
30
+ @property({ type: Boolean })
31
+ readonly: boolean = false
32
+
33
+ @property({ type: Boolean })
34
+ disabled: boolean = false
35
+
36
+ @property({ type: Object })
37
+ inputClasses: Record<string, boolean> = {}
38
+
39
+ @property({ type: Object })
40
+ internals?: any
41
+
42
+ @property({ type: Object })
43
+ strings: any = { calendar: { buttonAltText: 'Åpne kalender' } }
44
+
45
+ inputRef: Ref<HTMLInputElement> = createRef()
46
+ btnRef: Ref<HTMLButtonElement> = createRef()
47
+
48
+ get inputElement(): HTMLInputElement | undefined {
49
+ return this.inputRef.value
50
+ }
51
+
52
+ get buttonElement(): HTMLButtonElement | undefined {
53
+ return this.btnRef.value
54
+ }
55
+
56
+ get isInputReadonly(): boolean {
57
+ return this.readonly || this.inputType === 'text'
58
+ }
59
+
60
+ private dispatchToggleCalendar(e: Event) {
61
+ if (this.readonly) return
62
+
63
+ this.dispatchEvent(
64
+ new CustomEvent('toggle-calendar', {
65
+ detail: e,
66
+ bubbles: true,
67
+ composed: true,
68
+ }),
69
+ )
70
+ }
71
+
72
+ private dispatchInput(e: Event) {
73
+ this.dispatchEvent(
74
+ new CustomEvent('input-change', {
75
+ detail: e,
76
+ bubbles: true,
77
+ composed: true,
78
+ }),
79
+ )
80
+ }
81
+
82
+ private dispatchFocus() {
83
+ this.dispatchEvent(
84
+ new CustomEvent('input-focus', {
85
+ bubbles: true,
86
+ composed: true,
87
+ }),
88
+ )
89
+ }
90
+
91
+ private dispatchBlur(e: FocusEvent) {
92
+ this.dispatchEvent(
93
+ new CustomEvent('input-blur', {
94
+ detail: e,
95
+ bubbles: true,
96
+ composed: true,
97
+ }),
98
+ )
99
+ }
100
+
101
+ private dispatchChange(e: Event) {
102
+ this.dispatchEvent(
103
+ new CustomEvent('input-changed', {
104
+ detail: e,
105
+ bubbles: true,
106
+ composed: true,
107
+ }),
108
+ )
109
+ }
110
+
111
+ private dispatchManageValidity(input: HTMLInputElement) {
112
+ this.dispatchEvent(
113
+ new CustomEvent('manage-validity', {
114
+ detail: input,
115
+ bubbles: true,
116
+ composed: true,
117
+ }),
118
+ )
119
+ }
120
+
121
+ createRenderRoot() {
122
+ return this
123
+ }
124
+
125
+ render() {
126
+ return html`
127
+ <div class="pkt-input__container">
128
+ <input
129
+ class="${classMap(this.inputClasses)}"
130
+ .type=${this.inputType}
131
+ id="${this.id}-input"
132
+ .value=${this.value}
133
+ min=${ifDefined(this.min)}
134
+ max=${ifDefined(this.max)}
135
+ placeholder=${ifDefined(this.placeholder)}
136
+ ?readonly=${this.isInputReadonly}
137
+ aria-describedby="${this.id}-helptext"
138
+ @click=${(e: MouseEvent) => {
139
+ e.preventDefault()
140
+ this.dispatchToggleCalendar(e)
141
+ }}
142
+ @touchend=${(e: TouchEvent) => {
143
+ e.preventDefault()
144
+ this.dispatchToggleCalendar(e)
145
+ }}
146
+ ?disabled=${this.disabled}
147
+ @keydown=${(e: KeyboardEvent) =>
148
+ keyboardUtils.handleInputKeydown(
149
+ e,
150
+ (event) => this.dispatchToggleCalendar(event),
151
+ () =>
152
+ formUtils.submitFormOrFallback(this.internals, () => this.inputRef.value?.blur()),
153
+ undefined,
154
+ () => this.inputRef.value?.blur(),
155
+ )}
156
+ @input=${(e: Event) => {
157
+ this.dispatchInput(e)
158
+ e.stopImmediatePropagation()
159
+ }}
160
+ @focus=${() => {
161
+ this.dispatchFocus()
162
+ if (deviceDetection.isIOS()) {
163
+ this.dispatchToggleCalendar(new Event('focus'))
164
+ }
165
+ }}
166
+ @blur=${(e: FocusEvent) => {
167
+ this.dispatchBlur(e)
168
+ this.dispatchManageValidity(e.target as HTMLInputElement)
169
+ this.dispatchEvent(
170
+ new CustomEvent('value-change', {
171
+ detail: (e.target as HTMLInputElement).value,
172
+ bubbles: true,
173
+ composed: true,
174
+ }),
175
+ )
176
+ }}
177
+ @change=${(e: Event) => {
178
+ this.dispatchChange(e)
179
+ e.stopImmediatePropagation()
180
+ }}
181
+ ${ref(this.inputRef)}
182
+ />
183
+ <button
184
+ class="${classMap(cssUtils.getButtonClasses())}"
185
+ type="button"
186
+ @click=${(e: Event) => this.dispatchToggleCalendar(e)}
187
+ @keydown=${(e: KeyboardEvent) =>
188
+ keyboardUtils.handleButtonKeydown(e, (event) => this.dispatchToggleCalendar(event))}
189
+ ?disabled=${this.disabled}
190
+ ${ref(this.btnRef)}
191
+ >
192
+ <pkt-icon name="calendar"></pkt-icon>
193
+ <span class="pkt-btn__text">${this.strings.calendar.buttonAltText}</span>
194
+ </button>
195
+ </div>
196
+ `
197
+ }
198
+ }
@@ -322,7 +322,14 @@ export const cssUtils = {
322
322
  /**
323
323
  * Generates input classes for datepicker
324
324
  */
325
- getInputClasses(fullwidth: boolean, showRangeLabels: boolean, multiple: boolean, range: boolean) {
325
+ getInputClasses(
326
+ fullwidth: boolean,
327
+ showRangeLabels: boolean,
328
+ multiple: boolean,
329
+ range: boolean,
330
+ readonly?: boolean,
331
+ inputType?: string
332
+ ) {
326
333
  return {
327
334
  'pkt-input': true,
328
335
  'pkt-datepicker__input': true,
@@ -330,6 +337,7 @@ export const cssUtils = {
330
337
  'pkt-datepicker--hasrangelabels': showRangeLabels,
331
338
  'pkt-datepicker--multiple': multiple,
332
339
  'pkt-datepicker--range': range,
340
+ 'ios-readonly-hack': readonly === false && inputType === 'text',
333
341
  }
334
342
  },
335
343