@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
@@ -1,712 +1,4 @@
1
- import { html, nothing, PropertyValues } from 'lit'
2
- import converters from '../../helpers/converters'
1
+ import { PktCalendar } from './calendar'
3
2
 
4
- import { customElement, property, state } from 'lit/decorators.js'
5
- import { classMap } from 'lit/directives/class-map.js'
6
- import { getWeek, eachDayOfInterval, getISODay, addDays, addHours } from 'date-fns'
7
- import { TZDate } from '@date-fns/tz'
8
- import { PktElement } from '../element'
9
- import { formatISODate, newDate, newDateYMD, formatReadableDate } from '@/utils/dateutils'
10
- import specs from 'componentSpecs/calendar.json'
11
- import '../icon'
12
-
13
- type DatesInRange = {
14
- [key: string]: boolean
15
- }
16
-
17
- @customElement('pkt-calendar')
18
- export class PktCalendar extends PktElement {
19
- /**
20
- * Element attributes
21
- */
22
- @property({ type: Boolean })
23
- multiple: boolean = specs.props.multiple.default
24
-
25
- @property({ type: Number })
26
- maxMultiple: number = specs.props.maxMultiple.default
27
-
28
- @property({ type: Boolean })
29
- range: boolean = specs.props.range.default
30
-
31
- @property({ type: Boolean })
32
- weeknumbers: boolean = specs.props.weeknumbers.default
33
-
34
- @property({ type: Boolean })
35
- withcontrols: boolean = specs.props.withcontrols.default
36
-
37
- @property({ converter: converters.csvToArray })
38
- selected: string | string[] = []
39
-
40
- @property({ type: String })
41
- earliest: string | null = specs.props.earliest.default
42
-
43
- @property({ type: String })
44
- latest: string | null = specs.props.latest.default
45
-
46
- @property({ converter: converters.stringsToDate })
47
- excludedates: Date[] = []
48
-
49
- @property({ converter: converters.csvToArray })
50
- excludeweekdays: string[] = []
51
-
52
- @property({ converter: converters.stringToDate })
53
- currentmonth: Date | null = null
54
-
55
- /**
56
- * Strings
57
- */
58
- @property({ type: Array }) dayStrings: string[] = this.strings.dates.daysShort
59
- @property({ type: Array }) dayStringsLong: string[] = this.strings.dates.days
60
- @property({ type: Array }) monthStrings: string[] = this.strings.dates.months
61
- @property({ type: String }) weekString: string = this.strings.dates.week
62
- @property({ type: String }) prevMonthString: string = this.strings.dates.prevMonth
63
- @property({ type: String }) nextMonthString: string = this.strings.dates.nextMonth
64
-
65
- /**
66
- * Private properties
67
- */
68
- @property({ type: Array }) private _selected: Date[] = []
69
- @property({ type: Number }) private year: number = 0
70
- @property({ type: Number }) private month: number = 0
71
- @property({ type: Number }) private week: number = 0
72
- @property({ type: Date }) private rangeHovered: Date | null = null
73
-
74
- @state() private inRange: DatesInRange = {}
75
- @state() private focusedDate: string | null = null
76
- @state() private selectableDates: {
77
- currentDateISO: string
78
- isDisabled: boolean
79
- tabindex: string
80
- }[] = []
81
- @state() private currentmonthtouched: boolean = false
82
- @state() private tabIndexSet: number = 0
83
- /**
84
- * Runs on mount, used to set up various values and whatever you need to run
85
- */
86
- connectedCallback() {
87
- super.connectedCallback()
88
- }
89
-
90
- disconnectedCallback(): void {
91
- this.removeEventListener('keydown', this.handleKeydown)
92
- super.disconnectedCallback()
93
- }
94
-
95
- attributeChangedCallback(name: string, _old: string | null, value: string | null): void {
96
- if (name === 'selected' && value) {
97
- this.convertSelected()
98
- }
99
- super.attributeChangedCallback(name, _old, value)
100
- }
101
-
102
- updated(changedProperties: PropertyValues): void {
103
- super.updated(changedProperties)
104
- if (changedProperties.has('selected')) {
105
- this.convertSelected()
106
- }
107
- }
108
-
109
- protected firstUpdated(_changedProperties: PropertyValues): void {
110
- this.addEventListener('keydown', this.handleKeydown)
111
- }
112
-
113
- convertSelected() {
114
- if (typeof this.selected === 'string') {
115
- this.selected = this.selected.split(',')
116
- }
117
- if (this.selected.length === 1 && this.selected[0] === '') {
118
- this.selected = []
119
- }
120
- this._selected = this.selected.map((d: string) => newDate(d))
121
- if (this.range && this.selected.length === 2) {
122
- const days = eachDayOfInterval({
123
- start: newDate(this.selected[0]),
124
- end: newDate(this.selected[1]),
125
- })
126
-
127
- this.inRange = {}
128
- if (Array.isArray(days) && days.length) {
129
- const inRange: DatesInRange = {}
130
- for (let i = 0; i < days.length; i++) {
131
- inRange[formatISODate(days[i])] = this.isInRange(days[i])
132
- }
133
- this.inRange = inRange
134
- }
135
- }
136
- this.setCurrentMonth()
137
- }
138
-
139
- setCurrentMonth() {
140
- if (this.currentmonth === null && !this.currentmonthtouched) {
141
- this.currentmonthtouched = true
142
- return
143
- }
144
- if (this.selected.length && this.selected[0] !== '') {
145
- this.currentmonth = newDate(this.selected[this.selected.length - 1])
146
- } else if (this.currentmonth === null) {
147
- this.currentmonth = newDate()
148
- }
149
- this.year = this.currentmonth.getFullYear()
150
- this.month = this.currentmonth.getMonth()
151
- }
152
-
153
- handleKeydown(e: KeyboardEvent) {
154
- switch (e.key) {
155
- case 'ArrowLeft':
156
- this.handleArrowKey(e, -1)
157
- break
158
- case 'ArrowRight':
159
- this.handleArrowKey(e, 1)
160
- break
161
- case 'ArrowUp':
162
- this.handleArrowKey(e, -7)
163
- break
164
- case 'ArrowDown':
165
- this.handleArrowKey(e, 7)
166
- break
167
- default:
168
- break
169
- }
170
- }
171
-
172
- handleArrowKey(e: KeyboardEvent, direction: number) {
173
- if ((e.target as HTMLElement)?.nodeName === 'INPUT') return
174
- if ((e.target as HTMLElement)?.nodeName === 'SELECT') return
175
- if ((e.target as HTMLElement)?.nodeName === 'BUTTON') return
176
- e.preventDefault()
177
- if (!this.focusedDate) {
178
- this.focusOnCurrentDate()
179
- }
180
- const date = this.focusedDate ? newDate(this.focusedDate) : newDateYMD(this.year, this.month, 1)
181
- let nextDate = addDays(date, direction)
182
- if (nextDate) {
183
- let el = this.querySelector(`div[data-date="${formatISODate(nextDate)}"]`)
184
- if (el instanceof HTMLDivElement) {
185
- if (el.dataset.disabled) {
186
- nextDate = addDays(nextDate, direction)
187
- let nextElement = this.querySelector(`div[data-date="${formatISODate(nextDate)}"]`)
188
- while (
189
- nextElement &&
190
- nextElement instanceof HTMLDivElement &&
191
- nextElement.dataset.disabled
192
- ) {
193
- nextDate = addDays(nextDate, direction)
194
- nextElement = this.querySelector(`div[data-date="${formatISODate(nextDate)}"]`)
195
- }
196
- el = nextElement
197
- }
198
- if (el instanceof HTMLDivElement && !el.dataset.disabled) {
199
- this.focusedDate = formatISODate(nextDate)
200
- el.focus()
201
- }
202
- }
203
- }
204
- }
205
- /**
206
- * Component functionality and render
207
- */
208
- render() {
209
- return html`
210
- <div
211
- class="pkt-calendar ${this.weeknumbers ? 'pkt-cal-weeknumbers' : nothing}"
212
- @focusout=${this.closeEvent}
213
- @keydown=${(e: KeyboardEvent) => {
214
- if (e.key === 'Escape') {
215
- e.preventDefault()
216
- this.close()
217
- }
218
- }}
219
- >
220
- <nav class="pkt-cal-month-nav">
221
- <div>
222
- <button
223
- type="button"
224
- @click=${this.isPrevMonthAllowed() && this.prevMonth}
225
- @keydown=${(e: KeyboardEvent) => {
226
- if (e.key === 'Enter' || e.key === ' ') {
227
- e.preventDefault()
228
- this.isNextMonthAllowed() && this.prevMonth()
229
- }
230
- }}
231
- class="pkt-btn pkt-btn--tertiary pkt-btn--small pkt-btn--icon-only ${this.isPrevMonthAllowed()
232
- ? ''
233
- : 'pkt-hide'}"
234
- .data-disabled=${!this.isPrevMonthAllowed() ? 'disabled' : nothing}
235
- ?aria-disabled=${!this.isPrevMonthAllowed()}
236
- tabindex=${this.isPrevMonthAllowed() ? '0' : '-1'}
237
- >
238
- <pkt-icon class="pkt-btn__icon" name="chevron-thin-left"></pkt-icon>
239
- <span class="pkt-btn__text">${this.prevMonthString}</span>
240
- </button>
241
- </div>
242
- ${this.renderMonthNav()}
243
- <div>
244
- <button
245
- type="button"
246
- @click=${this.isNextMonthAllowed() && this.nextMonth}
247
- @keydown=${(e: KeyboardEvent) => {
248
- if (e.key === 'Enter' || e.key === ' ') {
249
- e.preventDefault()
250
- this.isNextMonthAllowed() && this.nextMonth()
251
- }
252
- }}
253
- class="pkt-btn pkt-btn--tertiary pkt-btn--small pkt-btn--icon-only ${this.isNextMonthAllowed()
254
- ? ''
255
- : 'pkt-hide'}"
256
- .data-disabled=${!this.isNextMonthAllowed() ? 'disabled' : nothing}
257
- ?aria-disabled=${!this.isNextMonthAllowed()}
258
- tabindex=${this.isNextMonthAllowed() ? '0' : '-1'}
259
- >
260
- <pkt-icon class="pkt-btn__icon" name="chevron-thin-right"></pkt-icon>
261
- <span class="pkt-btn__text">${this.nextMonthString}</span>
262
- </button>
263
- </div>
264
- </nav>
265
- <table
266
- class="pkt-cal-days pkt-txt-12-medium"
267
- role="grid"
268
- ?aria-multiselectable=${this.range || this.multiple}
269
- >
270
- <thead>
271
- ${this.renderDayNames()}
272
- </thead>
273
- <tbody>
274
- ${this.renderCalendarBody()}
275
- </tbody>
276
- </table>
277
- </div>
278
- `
279
- }
280
-
281
- private renderDayNames() {
282
- const days = []
283
- if (this.weeknumbers) {
284
- days.push(html`<th><div>${this.weekString}</div></th>`)
285
- }
286
- for (let i = 0; i < this.dayStrings.length; i++) {
287
- days.push(
288
- html`<th><div aria-label="${this.dayStringsLong[i]}">${this.dayStrings[i]}</div></th>`,
289
- )
290
- }
291
- return html`<tr class="pkt-cal-week-row">
292
- ${days}
293
- </tr>`
294
- }
295
-
296
- private renderMonthNav() {
297
- let monthView = []
298
- if (this.withcontrols) {
299
- monthView.push(
300
- html`<div class="pkt-cal-month-picker">
301
- <label for="${this.id}-monthnav" class="pkt-hide">${this.strings.dates.month}</label>
302
- <select
303
- aria-label="${this.strings.dates.month}"
304
- class="pkt-input pkt-input-compact"
305
- id="${this.id}-monthnav"
306
- @change=${(e: any) => {
307
- e.stopImmediatePropagation()
308
- this.changeMonth(this.year, e.target.value)
309
- }}
310
- >
311
- ${this.monthStrings.map(
312
- (month, index) =>
313
- html`<option value=${index} ?selected=${this.month === index}>${month}</option>`,
314
- )}
315
- </select>
316
- <label for="${this.id}-yearnav" class="pkt-hide">${this.strings.dates.year}</label>
317
- <input
318
- aria-label="${this.strings.dates.year}"
319
- class="pkt-input pkt-cal-input-year pkt-input-compact"
320
- id="${this.id}-yearnav"
321
- type="number"
322
- size="4"
323
- placeholder="0000"
324
- @change=${(e: any) => {
325
- e.stopImmediatePropagation()
326
- this.changeMonth(e.target.value, this.month)
327
- }}
328
- .value=${this.year}
329
- />
330
- </div> `,
331
- )
332
- } else {
333
- monthView.push(
334
- html`<div class="pkt-txt-16-medium" aria-live="polite">
335
- ${this.monthStrings[this.month]} ${this.year}
336
- </div>`,
337
- )
338
- }
339
- return monthView
340
- }
341
-
342
- private renderDayView(dayCounter: number, today: Date, j: number) {
343
- const currentDate = newDateYMD(this.year, this.month, dayCounter)
344
- const currentDateISO = formatISODate(currentDate)
345
- const isToday = currentDateISO === formatISODate(today)
346
- const isSelected = this.selected.includes(currentDateISO)
347
- const ariaLabel = formatReadableDate(currentDate)
348
- const isDisabled =
349
- this.isExcluded(j, currentDate) ||
350
- (!isSelected &&
351
- this.multiple &&
352
- this.maxMultiple > 0 &&
353
- this.selected.length >= this.maxMultiple)
354
- const tabindex = this.focusedDate
355
- ? this.focusedDate === currentDateISO && !isDisabled
356
- ? '0'
357
- : '-1'
358
- : !isDisabled && this.tabIndexSet === 0
359
- ? '0'
360
- : this.tabIndexSet === dayCounter
361
- ? '0'
362
- : '-1'
363
-
364
- if (tabindex === '0') {
365
- this.tabIndexSet = dayCounter
366
- }
367
-
368
- this.selectableDates.push({ currentDateISO, isDisabled, tabindex })
369
-
370
- const classes = {
371
- 'pkt-cal-today': isToday,
372
- 'pkt-cal-selected': isSelected,
373
- 'pkt-cal-in-range': this.inRange[currentDateISO],
374
- 'pkt-cal-excluded': this.isExcluded(j, currentDate),
375
- 'pkt-cal-in-range-first':
376
- this.range &&
377
- (this.selected.length === 2 || this.rangeHovered !== null) &&
378
- currentDateISO === this.selected[0],
379
- 'pkt-cal-in-range-last':
380
- this.range && this.selected.length === 2 && currentDateISO === this.selected[1],
381
- 'pkt-cal-range-hover':
382
- this.rangeHovered !== null && currentDateISO === formatISODate(this.rangeHovered),
383
- }
384
- return html`<td class=${classMap(classes)}>
385
- <div
386
- ?aria-selected=${isSelected}
387
- role="gridcell"
388
- class="pkt-btn pkt-btn--tertiary pkt-btn--small pkt-btn--label-only"
389
- @mouseover=${() =>
390
- this.range && !this.isExcluded(j, currentDate) && this.handleRangeHover(currentDate)}
391
- @focus=${() => {
392
- this.range && !this.isExcluded(j, currentDate) && this.handleRangeHover(currentDate)
393
- this.focusedDate = currentDateISO
394
- }}
395
- aria-label="${ariaLabel}"
396
- tabindex=${this.selectableDates.find((x) => x.currentDateISO === currentDateISO)?.tabindex}
397
- data-disabled=${isDisabled ? 'disabled' : nothing}
398
- data-date=${currentDateISO}
399
- @keydown=${(e: KeyboardEvent) => {
400
- if (e.key === 'Enter' || e.key === ' ') {
401
- e.preventDefault()
402
- this.handleDateSelect(currentDate)
403
- }
404
- }}
405
- @click=${(e: MouseEvent) => {
406
- if (!isDisabled) {
407
- e.preventDefault()
408
- this.handleDateSelect(currentDate)
409
- }
410
- }}
411
- >
412
- <span class="pkt-btn__text pkt-txt-14-light">${dayCounter}</span>
413
- </div>
414
- </td>`
415
- }
416
-
417
- private renderCalendarBody() {
418
- const today = newDate()
419
- const firstDayOfMonth = newDateYMD(this.year, this.month, 1)
420
- const lastDayOfMonth = newDateYMD(this.year, this.month + 1, 0)
421
- const startingDay = (firstDayOfMonth.getDay() + 6) % 7
422
- const numDays = lastDayOfMonth.getDate()
423
- const numRows = Math.ceil((numDays + startingDay) / 7)
424
- const lastDayOfPrevMonth = newDateYMD(this.year, this.month, 0)
425
- const numDaysPrevMonth = lastDayOfPrevMonth.getDate()
426
-
427
- let dayCounter = 1
428
- this.week = getWeek(newDateYMD(this.year, this.month, 1))
429
-
430
- const rows = []
431
-
432
- for (let i = 0; i < numRows; i++) {
433
- const cells = []
434
-
435
- this.weeknumbers && cells.push(html`<td class="pkt-cal-week">${this.week}</td>`)
436
- this.week++
437
-
438
- for (let j = 1; j < 8; j++) {
439
- if (i === 0 && j < startingDay + 1) {
440
- const dayFromPrevMonth = numDaysPrevMonth - (startingDay - j)
441
- cells.push(
442
- html`<td class="pkt-cal-other">
443
- <div
444
- class="pkt-btn pkt-btn--tertiary pkt-btn--small pkt-btn--label-only"
445
- data-disabled="disabled"
446
- >
447
- <span class="pkt-btn__text pkt-txt-14-light">${dayFromPrevMonth}</span>
448
- </div>
449
- </td>`,
450
- )
451
- } else if (dayCounter > numDays) {
452
- cells.push(
453
- html`<td class="pkt-cal-other">
454
- <div
455
- class="pkt-btn pkt-btn--tertiary pkt-btn--small pkt-btn--label-only"
456
- data-disabled="disabled"
457
- >
458
- <span class="pkt-btn__text pkt-txt-14-light">${dayCounter - numDays}</span>
459
- </div>
460
- </td>`,
461
- )
462
- dayCounter++
463
- } else {
464
- cells.push(this.renderDayView(dayCounter, today, j))
465
- dayCounter++
466
- }
467
- }
468
-
469
- rows.push(
470
- html`<tr class="pkt-cal-week-row" role="row">
471
- ${cells}
472
- </tr>`,
473
- )
474
- }
475
-
476
- return rows
477
- }
478
-
479
- private isExcluded(weekday: number, date: TZDate) {
480
- if (this.excludeweekdays.includes(weekday.toString())) return true
481
- if (this.earliest && addHours(date, 1) < newDate(this.earliest)) return true
482
- if (this.latest && addHours(date, -1) > newDate(this.latest)) return true
483
- return this.excludedates.some((x: TZDate | Date | string) => {
484
- if (typeof x === 'string') {
485
- return x === formatISODate(date)
486
- } else {
487
- return x.toDateString() === date.toDateString()
488
- }
489
- })
490
- }
491
-
492
- isPrevMonthAllowed() {
493
- const prevMonth = newDateYMD(this.year, this.month, 0)
494
- if (this.earliest && newDate(this.earliest) > prevMonth) return false
495
- return true
496
- }
497
-
498
- private prevMonth() {
499
- const newMonth = this.month === 0 ? 11 : this.month - 1
500
- const newYear = this.month === 0 ? this.year - 1 : this.year
501
- this.changeMonth(newYear, newMonth)
502
- }
503
-
504
- isNextMonthAllowed() {
505
- const nextMonth = newDateYMD(
506
- this.month === 11 ? this.year + 1 : this.year,
507
- this.month === 11 ? 0 : this.month + 1,
508
- 1,
509
- )
510
- if (this.latest && newDate(this.latest) < nextMonth) return false
511
- return true
512
- }
513
-
514
- private nextMonth() {
515
- const newMonth = this.month === 11 ? 0 : this.month + 1
516
- const newYear = this.month === 11 ? this.year + 1 : this.year
517
- this.changeMonth(newYear, newMonth)
518
- }
519
-
520
- private changeMonth(year: number, month: number) {
521
- this.year = typeof year === 'string' ? parseInt(year) : year
522
- this.month = typeof month === 'string' ? parseInt(month) : month
523
- this.tabIndexSet = 0
524
- this.focusedDate = null
525
- this.selectableDates = []
526
- }
527
-
528
- private isInRange(date: TZDate | Date) {
529
- if (this.range && this.selected.length === 2) {
530
- if (date > newDate(this.selected[0]) && date < newDate(this.selected[1])) return true
531
- } else if (this.range && this.selected.length === 1 && this.rangeHovered) {
532
- if (date > newDate(this.selected[0]) && date < this.rangeHovered) return true
533
- }
534
- return false
535
- }
536
-
537
- private isRangeAllowed(date: TZDate) {
538
- let allowed = true
539
- if (this._selected.length === 1) {
540
- const days = eachDayOfInterval({
541
- start: this._selected[0],
542
- end: date,
543
- })
544
-
545
- if (Array.isArray(days) && days.length) {
546
- for (let i = 0; i < days.length; i++) {
547
- this.excludedates.forEach((d: TZDate | Date) => {
548
- if (d > this._selected[0] && d < date) {
549
- allowed = false
550
- }
551
- })
552
- if (this.excludeweekdays.includes(getISODay(days[i]).toString())) {
553
- allowed = false
554
- }
555
- }
556
- }
557
- }
558
- return allowed
559
- }
560
-
561
- private emptySelected() {
562
- this.selected = []
563
- this._selected = []
564
- this.inRange = {}
565
- }
566
-
567
- public addToSelected(selectedDate: TZDate) {
568
- if (this.selected.includes(formatISODate(selectedDate))) return
569
- this.selected = [...this.selected, formatISODate(selectedDate)]
570
- this._selected = [...this._selected, selectedDate]
571
- if (this.range && this.selected.length === 2) {
572
- this.close()
573
- }
574
- }
575
-
576
- public removeFromSelected(selectedDate: TZDate) {
577
- if (this.selected.length === 1) {
578
- this.emptySelected()
579
- } else {
580
- const selectedDateIndex = this.selected.indexOf(formatISODate(selectedDate))
581
- const selectedCopy = [...this.selected]
582
- const _selectedCopy = [...this._selected]
583
- selectedCopy.splice(selectedDateIndex, 1)
584
- _selectedCopy.splice(selectedDateIndex, 1)
585
- this.selected = selectedCopy
586
- this._selected = _selectedCopy
587
- }
588
- }
589
-
590
- public toggleSelected(selectedDate: TZDate) {
591
- const selectedDateISO = formatISODate(selectedDate)
592
- this.selected.includes(selectedDateISO)
593
- ? this.removeFromSelected(selectedDate)
594
- : !(this.maxMultiple && this.selected.length >= this.maxMultiple)
595
- ? this.addToSelected(selectedDate)
596
- : null
597
- }
598
-
599
- private handleRangeSelect(selectedDate: TZDate) {
600
- const selectedDateISO = formatISODate(selectedDate)
601
- if (this.selected.includes(selectedDateISO)) {
602
- if (this.selected.indexOf(selectedDateISO) === 0) {
603
- this.emptySelected()
604
- } else {
605
- this.removeFromSelected(selectedDate)
606
- }
607
- } else {
608
- if (this.selected.length > 1) {
609
- this.emptySelected()
610
- this.addToSelected(selectedDate)
611
- } else {
612
- if (this.selected.length === 1 && !this.isRangeAllowed(selectedDate)) {
613
- this.emptySelected()
614
- }
615
- if (this.selected.length === 1 && this._selected[0] > selectedDate) {
616
- this.emptySelected()
617
- }
618
- this.addToSelected(selectedDate)
619
- }
620
- }
621
- return Promise.resolve()
622
- }
623
-
624
- private handleRangeHover(date: TZDate) {
625
- if (
626
- this.range &&
627
- this._selected.length === 1 &&
628
- this.isRangeAllowed(date) &&
629
- this._selected[0] < date
630
- ) {
631
- this.rangeHovered = date
632
-
633
- this.inRange = {}
634
- const days = eachDayOfInterval({
635
- start: this._selected[0],
636
- end: date,
637
- })
638
-
639
- if (Array.isArray(days) && days.length) {
640
- for (let i = 0; i < days.length; i++) {
641
- this.inRange[formatISODate(days[i])] = this.isInRange(days[i])
642
- }
643
- }
644
- } else {
645
- this.rangeHovered = null
646
- }
647
- }
648
-
649
- public handleDateSelect(selectedDate: TZDate | null) {
650
- if (!selectedDate) return
651
- if (this.range) {
652
- this.handleRangeSelect(selectedDate)
653
- } else if (this.multiple) {
654
- this.toggleSelected(selectedDate)
655
- } else {
656
- if (this.selected.includes(formatISODate(selectedDate))) {
657
- this.emptySelected()
658
- } else {
659
- this.emptySelected()
660
- this.addToSelected(selectedDate)
661
- }
662
- this.close()
663
- }
664
- this.dispatchEvent(
665
- new CustomEvent('date-selected', {
666
- detail: this.selected,
667
- bubbles: true,
668
- composed: true,
669
- }),
670
- )
671
- return Promise.resolve()
672
- }
673
-
674
- public focusOnCurrentDate() {
675
- const currentDateISO = formatISODate(newDate())
676
- const el = this.querySelector(`div[data-date="${currentDateISO}"]`)
677
- if (el instanceof HTMLDivElement) {
678
- this.focusedDate = currentDateISO
679
- el.focus()
680
- } else {
681
- const firstSelectable = this.selectableDates.find((x) => !x.isDisabled)
682
- if (firstSelectable) {
683
- const firstSelectableEl = this.querySelector(
684
- `div[data-date="${firstSelectable.currentDateISO}"]`,
685
- )
686
- if (firstSelectableEl instanceof HTMLDivElement) {
687
- this.focusedDate = firstSelectable.currentDateISO
688
- firstSelectableEl.focus()
689
- }
690
- }
691
- }
692
- }
693
-
694
- public closeEvent(e: FocusEvent) {
695
- if (
696
- !this.contains(e.relatedTarget as Node) &&
697
- !(e.target as Element).classList.contains('pkt-hide')
698
- ) {
699
- this.close()
700
- }
701
- }
702
-
703
- public close() {
704
- this.dispatchEvent(
705
- new CustomEvent('close', {
706
- detail: true,
707
- bubbles: true,
708
- composed: true,
709
- }),
710
- )
711
- }
712
- }
3
+ export { PktCalendar }
4
+ export default PktCalendar