@oslokommune/punkt-elements 14.5.3 → 15.0.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.
- package/CHANGELOG.md +50 -0
- package/dist/{accordionitem-DB3tAjIZ.js → accordionitem-BbeS44TD.js} +1 -1
- package/dist/{accordionitem-DHYmPA-o.cjs → accordionitem-DUWhTUEI.cjs} +1 -1
- package/dist/{alert-GrKyqxuR.cjs → alert-B9flMht5.cjs} +1 -1
- package/dist/{alert-DqXar67l.js → alert-BpFxQviu.js} +3 -3
- package/dist/{backlink-QDcQd6vK.cjs → backlink-Bn16ZEIX.cjs} +1 -1
- package/dist/{backlink-CqUcmiPQ.js → backlink-DfMabyBp.js} +1 -1
- package/dist/{button-R4l10Nqd.cjs → button-BgCKV0zW.cjs} +1 -1
- package/dist/{button-f36menSU.js → button-CKgpX5QA.js} +2 -2
- package/dist/{calendar-DiNuZ8Ai.js → calendar-BMarIeVp.js} +333 -326
- package/dist/calendar-C6xgAJ7Z.cjs +90 -0
- package/dist/{card-C2hWaMev.cjs → card-DI3KodEc.cjs} +1 -1
- package/dist/{card-CnINxZma.js → card-h8ekgJRr.js} +3 -3
- package/dist/{checkbox-B-0FOdwi.cjs → checkbox-B2t7wfxe.cjs} +1 -1
- package/dist/{checkbox-CkAwPK_E.js → checkbox-BJ9pz3kV.js} +1 -1
- package/dist/{combobox-Dxa7XjLz.js → combobox-BjAvk8Y-.js} +6 -6
- package/dist/{combobox-yy6hIGmB.cjs → combobox-HNN7GTzh.cjs} +1 -1
- package/dist/{consent-FbFS1pmz.cjs → consent-C37tuFwZ.cjs} +1 -1
- package/dist/{consent-c9PhWxnP.js → consent-DAk2BJ7I.js} +2 -2
- package/dist/datepicker-2bneToiA.cjs +275 -0
- package/dist/datepicker-DvcH2QD9.js +1160 -0
- package/dist/{helptext-DebHGRsD.cjs → helptext-BG1P_9j0.cjs} +1 -1
- package/dist/{helptext-DuyRRfCn.js → helptext-Cm6FLBVf.js} +2 -2
- package/dist/icon-DBZvMard.js +103 -0
- package/dist/icon-n4-ve48P.cjs +9 -0
- package/dist/index.d.ts +10 -42
- package/dist/input-element-BBv4xjPb.cjs +1 -0
- package/dist/{input-element-DVZhYDJ_.js → input-element-CbjYtVou.js} +143 -147
- package/dist/{input-wrapper-3qfjLkrP.js → input-wrapper-Bwmva-69.js} +4 -4
- package/dist/{input-wrapper-rgXsRNkk.cjs → input-wrapper-CJqmwe3I.cjs} +1 -1
- package/dist/{link-CZvcdRek.js → link-BKnT-97D.js} +2 -2
- package/dist/{link-D85g20GS.cjs → link-DRPFqqEn.cjs} +1 -1
- package/dist/{linkcard-B-9K02q8.cjs → linkcard-02fxYQ2g.cjs} +1 -1
- package/dist/{linkcard-C3RTcMqc.js → linkcard-C2UENcqo.js} +2 -2
- package/dist/{loader-Dci0SrOz.js → loader-BW-AWQiE.js} +2 -2
- package/dist/{loader-1EXLdxfq.cjs → loader-Cj4kUNRE.cjs} +1 -1
- package/dist/{messagebox-dscnWgCd.cjs → messagebox-CK0sSRep.cjs} +1 -1
- package/dist/{messagebox-CnZlttZp.js → messagebox-DB8tEXrV.js} +2 -2
- package/dist/{modal-ncKVjcyZ.cjs → modal-BzVQSQy2.cjs} +1 -1
- package/dist/{modal-wSGthXAC.js → modal-ClYfWW2a.js} +2 -2
- package/dist/pkt-accordion.cjs +1 -1
- package/dist/pkt-accordion.js +2 -2
- package/dist/pkt-alert.cjs +1 -1
- package/dist/pkt-alert.js +1 -1
- package/dist/pkt-backlink.cjs +1 -1
- package/dist/pkt-backlink.js +1 -1
- package/dist/pkt-button.cjs +1 -1
- package/dist/pkt-button.js +1 -1
- package/dist/pkt-calendar.cjs +1 -1
- package/dist/pkt-calendar.js +1 -1
- package/dist/pkt-card.cjs +1 -1
- package/dist/pkt-card.js +1 -1
- package/dist/pkt-checkbox.cjs +1 -1
- package/dist/pkt-checkbox.js +1 -1
- package/dist/pkt-combobox.cjs +1 -1
- package/dist/pkt-combobox.js +1 -1
- package/dist/pkt-consent.cjs +1 -1
- package/dist/pkt-consent.js +1 -1
- package/dist/pkt-datepicker.cjs +1 -1
- package/dist/pkt-datepicker.js +2 -2
- package/dist/pkt-header.cjs +1 -1
- package/dist/pkt-header.js +5 -5
- package/dist/pkt-helptext.cjs +1 -1
- package/dist/pkt-helptext.js +1 -1
- package/dist/pkt-icon.cjs +1 -1
- package/dist/pkt-icon.js +1 -1
- package/dist/pkt-index.cjs +1 -1
- package/dist/pkt-index.js +25 -25
- package/dist/pkt-input-wrapper.cjs +1 -1
- package/dist/pkt-input-wrapper.js +1 -1
- package/dist/pkt-link.cjs +1 -1
- package/dist/pkt-link.js +1 -1
- package/dist/pkt-linkcard.cjs +1 -1
- package/dist/pkt-linkcard.js +1 -1
- package/dist/pkt-loader.cjs +1 -1
- package/dist/pkt-loader.js +1 -1
- package/dist/pkt-messagebox.cjs +1 -1
- package/dist/pkt-messagebox.js +1 -1
- package/dist/pkt-modal.cjs +1 -1
- package/dist/pkt-modal.js +1 -1
- package/dist/{pkt-options-controller-zn5cmMvL.js → pkt-options-controller-BcGywCmf.js} +1 -1
- package/dist/{pkt-options-controller-DjBCEHU4.cjs → pkt-options-controller-BnTmkl3g.cjs} +1 -1
- package/dist/pkt-progressbar.cjs +1 -1
- package/dist/pkt-progressbar.js +2 -2
- package/dist/pkt-radiobutton.cjs +1 -1
- package/dist/pkt-radiobutton.js +1 -1
- package/dist/pkt-select.cjs +1 -1
- package/dist/pkt-select.js +1 -1
- package/dist/pkt-slot-controller-D4nKlom5.cjs +1 -0
- package/dist/{pkt-slot-controller-BPGj-LC5.js → pkt-slot-controller-D7CrjM52.js} +27 -25
- package/dist/pkt-tabs.cjs +1 -1
- package/dist/pkt-tabs.js +2 -2
- package/dist/pkt-tag.cjs +1 -1
- package/dist/pkt-tag.js +1 -1
- package/dist/pkt-textarea.cjs +1 -1
- package/dist/pkt-textarea.js +1 -1
- package/dist/pkt-textinput.cjs +1 -1
- package/dist/pkt-textinput.js +1 -1
- package/dist/{progressbar-D5WBW1Dm.js → progressbar-CJa70NEo.js} +1 -1
- package/dist/{progressbar-ClY1WgnM.cjs → progressbar-ClZOyCz9.cjs} +1 -1
- package/dist/{radiobutton-oA20HijB.js → radiobutton-CvKKNFMd.js} +1 -1
- package/dist/{radiobutton-iHuLnuAn.cjs → radiobutton-DWoYQn8H.cjs} +1 -1
- package/dist/{select-jbIbD7hW.cjs → select-BQUp88lY.cjs} +1 -1
- package/dist/{select-Bug9sfr5.js → select-CFkxir_l.js} +4 -4
- package/dist/{tabitem-CypTmORF.js → tabitem-C8-tZyc_.js} +1 -1
- package/dist/{tabitem-CtltSqDK.cjs → tabitem-DaYfUaxw.cjs} +1 -1
- package/dist/{tag-DgoTYNVA.js → tag-DIJMJhyp.js} +2 -2
- package/dist/{tag-BfjOlIyS.cjs → tag-h0vD2Na0.cjs} +1 -1
- package/dist/{textarea-Da9E3RM7.js → textarea-CMuiBUee.js} +4 -4
- package/dist/{textarea-Dfa4_ZBy.cjs → textarea-DcCOfNlr.cjs} +1 -1
- package/dist/{textinput-DaMYc5gd.js → textinput-D30TCADP.js} +4 -4
- package/dist/{textinput-CLM9fRjm.cjs → textinput-DR3aaHTH.cjs} +1 -1
- package/package.json +4 -4
- package/src/components/calendar/calendar.core.test.ts +1 -1
- package/src/components/calendar/calendar.selection.test.ts +1 -1
- package/src/components/calendar/calendar.ts +32 -22
- package/src/components/datepicker/datepicker-popup.test.ts +1 -1
- package/src/components/datepicker/datepicker-popup.ts +73 -30
- package/src/components/datepicker/datepicker-range.ts +5 -1
- package/src/components/datepicker/datepicker-types.ts +4 -54
- package/src/components/datepicker/datepicker-utils.ts +38 -517
- package/src/components/datepicker/datepicker.core.test.ts +12 -10
- package/src/components/datepicker/datepicker.selection.test.ts +8 -6
- package/src/components/datepicker/datepicker.ts +26 -7
- package/src/components/icon/icon.test.ts +8 -8
- package/src/components/icon/icon.ts +56 -39
- package/dist/calendar-wuD6ZH0t.cjs +0 -90
- package/dist/datepicker-C7GWMtXH.js +0 -1444
- package/dist/datepicker-D_3vYgMt.cjs +0 -271
- package/dist/icon-BgG6oO4Q.js +0 -89
- package/dist/icon-Dl9ZPqe6.cjs +0 -9
- package/dist/input-element-RBQVA8i0.cjs +0 -1
- package/dist/pkt-slot-controller-BzddBp7z.cjs +0 -1
- package/src/components/calendar/helpers/calendar-grid.ts +0 -93
- package/src/components/calendar/helpers/date-validation.ts +0 -86
- package/src/components/calendar/helpers/index.ts +0 -49
- package/src/components/calendar/helpers/keyboard-navigation.ts +0 -54
- package/src/components/calendar/helpers/selection-manager.ts +0 -184
|
@@ -1,135 +1,50 @@
|
|
|
1
|
-
import {
|
|
2
|
-
fromISOToDate,
|
|
3
|
-
newDate,
|
|
4
|
-
isValidDateRange,
|
|
5
|
-
sortDateStrings,
|
|
6
|
-
filterSelectableDates,
|
|
7
|
-
} from 'shared-utils/date-utils'
|
|
8
|
-
import { isIOS } from 'shared-utils/device-utils'
|
|
1
|
+
import { fromISOToDate, newDate } from 'shared-utils/date-utils'
|
|
9
2
|
import { Ref } from 'lit/directives/ref.js'
|
|
10
3
|
import { PktCalendar } from '@/components/calendar/calendar'
|
|
4
|
+
import {
|
|
5
|
+
validateRangeOrder,
|
|
6
|
+
sortDates,
|
|
7
|
+
filterDates,
|
|
8
|
+
getDatepickerInputType,
|
|
9
|
+
getDatepickerInputClasses,
|
|
10
|
+
getDatepickerButtonClasses,
|
|
11
|
+
getRangeLabelClasses,
|
|
12
|
+
processDateSelection as sharedProcessDateSelection,
|
|
13
|
+
handleCalendarPosition as sharedHandleCalendarPosition,
|
|
14
|
+
handleDatepickerKeydown,
|
|
15
|
+
handleDatepickerButtonKeydown,
|
|
16
|
+
} from 'shared-utils/datepicker-utils'
|
|
11
17
|
|
|
12
18
|
/**
|
|
13
19
|
* Utility functions for PktDatepicker component
|
|
14
20
|
*
|
|
15
|
-
* This module provides helper functions organized by concern
|
|
16
|
-
* -
|
|
17
|
-
* -
|
|
18
|
-
* - formUtils: Form submission and validation
|
|
19
|
-
* - calendarUtils: Calendar interaction and positioning
|
|
20
|
-
* - eventUtils: Event listener creation
|
|
21
|
-
* - cssUtils: CSS class generation
|
|
22
|
-
* - dateProcessingUtils: Date value processing
|
|
23
|
-
* - keyboardUtils: Keyboard navigation handling
|
|
21
|
+
* This module provides helper functions organized by concern.
|
|
22
|
+
* Framework-agnostic functions are delegated to shared-utils/datepicker-utils.
|
|
23
|
+
* Lit-specific functions (using Ref, ElementInternals, PktCalendar) stay here.
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Value parsing and validation utilities
|
|
28
|
+
* Delegates to shared-utils/datepicker-utils
|
|
28
29
|
*/
|
|
29
30
|
export const valueUtils = {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
* @param values - Array of date strings (ISO format YYYY-MM-DD)
|
|
34
|
-
* @returns True if range is valid or incomplete, false if end date is before start date
|
|
35
|
-
*
|
|
36
|
-
* @example
|
|
37
|
-
* validateRangeOrder(['2024-01-01', '2024-01-31']) // Returns true
|
|
38
|
-
* validateRangeOrder(['2024-01-31', '2024-01-01']) // Returns false
|
|
39
|
-
* validateRangeOrder(['2024-01-01']) // Returns true (incomplete range)
|
|
40
|
-
*/
|
|
41
|
-
validateRangeOrder(values: string[]): boolean {
|
|
42
|
-
if (!values || values.length !== 2) return true // Not a complete range
|
|
43
|
-
return isValidDateRange(values[0], values[1])
|
|
44
|
-
},
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Sorts date strings chronologically
|
|
48
|
-
*
|
|
49
|
-
* @param dates - Array of date strings in ISO format (YYYY-MM-DD)
|
|
50
|
-
* @returns New array with dates sorted from earliest to latest
|
|
51
|
-
*
|
|
52
|
-
* @example
|
|
53
|
-
* sortDates(['2024-03-15', '2024-01-10', '2024-02-20'])
|
|
54
|
-
* // Returns ['2024-01-10', '2024-02-20', '2024-03-15']
|
|
55
|
-
*/
|
|
56
|
-
sortDates(dates: string[]): string[] {
|
|
57
|
-
return sortDateStrings(dates)
|
|
58
|
-
},
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Filters dates to only include selectable ones based on constraints
|
|
62
|
-
*
|
|
63
|
-
* Removes dates that:
|
|
64
|
-
* - Fall outside the min/max range
|
|
65
|
-
* - Are in the excludedDates array
|
|
66
|
-
* - Fall on excluded weekdays (0=Sunday, 6=Saturday)
|
|
67
|
-
*
|
|
68
|
-
* @param dates - Array of date strings to filter
|
|
69
|
-
* @param min - Minimum allowed date (ISO format)
|
|
70
|
-
* @param max - Maximum allowed date (ISO format)
|
|
71
|
-
* @param excludedDates - Array of specific dates to exclude
|
|
72
|
-
* @param excludedWeekdays - Array of weekday numbers to exclude ('0'-'6')
|
|
73
|
-
* @returns Filtered array containing only selectable dates
|
|
74
|
-
*
|
|
75
|
-
* @example
|
|
76
|
-
* filterSelectableDates(
|
|
77
|
-
* ['2024-01-01', '2024-01-06', '2024-01-15'],
|
|
78
|
-
* '2024-01-05',
|
|
79
|
-
* '2024-01-20',
|
|
80
|
-
* ['2024-01-15'],
|
|
81
|
-
* ['0', '6'] // Exclude weekends
|
|
82
|
-
* )
|
|
83
|
-
* // Returns ['2024-01-06'] (after min, not excluded, not a weekend)
|
|
84
|
-
*/
|
|
85
|
-
filterSelectableDates(
|
|
86
|
-
dates: string[],
|
|
87
|
-
min?: string | null,
|
|
88
|
-
max?: string | null,
|
|
89
|
-
excludedDates?: string[],
|
|
90
|
-
excludedWeekdays?: string[],
|
|
91
|
-
): string[] {
|
|
92
|
-
return filterSelectableDates(dates, min, max, excludedDates, excludedWeekdays)
|
|
93
|
-
},
|
|
31
|
+
validateRangeOrder,
|
|
32
|
+
sortDates,
|
|
33
|
+
filterSelectableDates: filterDates,
|
|
94
34
|
}
|
|
95
35
|
|
|
96
36
|
/**
|
|
97
37
|
* Input type detection utilities
|
|
38
|
+
* Delegates to shared-utils/datepicker-utils
|
|
98
39
|
*/
|
|
99
40
|
export const inputTypeUtils = {
|
|
100
|
-
|
|
101
|
-
* Determines the appropriate input type based on device
|
|
102
|
-
*
|
|
103
|
-
* Mobile Safari does not play well with type="date" and custom datepickers,
|
|
104
|
-
* so we use type="text" on iOS devices to avoid the native date picker
|
|
105
|
-
* interfering with our custom calendar component.
|
|
106
|
-
*
|
|
107
|
-
* @returns 'text' for iOS devices, 'date' for all other devices
|
|
108
|
-
*
|
|
109
|
-
* @example
|
|
110
|
-
* const inputType = getInputType()
|
|
111
|
-
* // Returns 'text' on iPhone/iPad, 'date' on desktop/Android
|
|
112
|
-
*/
|
|
113
|
-
getInputType(): string {
|
|
114
|
-
return isIOS() ? 'text' : 'date'
|
|
115
|
-
},
|
|
41
|
+
getInputType: getDatepickerInputType,
|
|
116
42
|
}
|
|
117
43
|
|
|
118
44
|
/**
|
|
119
|
-
* Form and validation utilities
|
|
45
|
+
* Form and validation utilities (Lit-specific — uses ElementInternals)
|
|
120
46
|
*/
|
|
121
47
|
export const formUtils = {
|
|
122
|
-
/**
|
|
123
|
-
* Submits the form that contains the given element
|
|
124
|
-
*
|
|
125
|
-
* Uses ElementInternals API to access the associated form and trigger submission.
|
|
126
|
-
* Requires the element to have attachInternals() called.
|
|
127
|
-
*
|
|
128
|
-
* @param element - The form-associated custom element
|
|
129
|
-
*
|
|
130
|
-
* @example
|
|
131
|
-
* submitForm(this) // From within a custom element
|
|
132
|
-
*/
|
|
133
48
|
submitForm(element: HTMLElement): void {
|
|
134
49
|
const form = (element as any).internals?.form as HTMLFormElement
|
|
135
50
|
if (form) {
|
|
@@ -137,21 +52,6 @@ export const formUtils = {
|
|
|
137
52
|
}
|
|
138
53
|
},
|
|
139
54
|
|
|
140
|
-
/**
|
|
141
|
-
* Submits form if available, otherwise executes fallback action
|
|
142
|
-
*
|
|
143
|
-
* Useful for Enter key handling where we want to submit the form,
|
|
144
|
-
* but provide a fallback behavior (like moving focus) if not in a form.
|
|
145
|
-
*
|
|
146
|
-
* @param internals - ElementInternals instance with optional form reference
|
|
147
|
-
* @param fallbackAction - Function to call if no form is available
|
|
148
|
-
*
|
|
149
|
-
* @example
|
|
150
|
-
* submitFormOrFallback(
|
|
151
|
-
* this.internals,
|
|
152
|
-
* () => this.inputRef.value?.blur()
|
|
153
|
-
* )
|
|
154
|
-
*/
|
|
155
55
|
submitFormOrFallback(internals: any, fallbackAction: () => void): void {
|
|
156
56
|
const form = internals?.form as HTMLFormElement
|
|
157
57
|
if (form) {
|
|
@@ -161,27 +61,6 @@ export const formUtils = {
|
|
|
161
61
|
}
|
|
162
62
|
},
|
|
163
63
|
|
|
164
|
-
/**
|
|
165
|
-
* Validates a date input and sets validity state
|
|
166
|
-
*
|
|
167
|
-
* Checks if the input value falls within the min/max range and
|
|
168
|
-
* sets appropriate validity flags using the ElementInternals API.
|
|
169
|
-
*
|
|
170
|
-
* @param input - The input element to validate
|
|
171
|
-
* @param internals - ElementInternals instance for setting validity
|
|
172
|
-
* @param min - Minimum allowed date (ISO format)
|
|
173
|
-
* @param max - Maximum allowed date (ISO format)
|
|
174
|
-
* @param strings - Optional localized error messages
|
|
175
|
-
*
|
|
176
|
-
* @example
|
|
177
|
-
* validateDateInput(
|
|
178
|
-
* inputElement,
|
|
179
|
-
* this.internals,
|
|
180
|
-
* '2024-01-01',
|
|
181
|
-
* '2024-12-31',
|
|
182
|
-
* { forms: { messages: { rangeUnderflow: 'Date too early' } } }
|
|
183
|
-
* )
|
|
184
|
-
*/
|
|
185
64
|
validateDateInput(
|
|
186
65
|
input: HTMLInputElement,
|
|
187
66
|
internals: any,
|
|
@@ -210,28 +89,10 @@ export const formUtils = {
|
|
|
210
89
|
|
|
211
90
|
/**
|
|
212
91
|
* Calendar interaction utilities
|
|
92
|
+
* handleCalendarPosition delegates to shared-utils (with Lit ref unwrapping).
|
|
93
|
+
* addToSelected stays Lit-specific (uses Ref<PktCalendar>).
|
|
213
94
|
*/
|
|
214
95
|
export const calendarUtils = {
|
|
215
|
-
/**
|
|
216
|
-
* Adds a date to selected dates if it's valid
|
|
217
|
-
*
|
|
218
|
-
* Used for multiple date selection - validates the input date against
|
|
219
|
-
* min/max constraints before adding it to the calendar's selected dates.
|
|
220
|
-
* Clears the input field after processing.
|
|
221
|
-
*
|
|
222
|
-
* @param event - Input or keyboard event containing the target input
|
|
223
|
-
* @param calendarRef - Lit ref to the calendar component
|
|
224
|
-
* @param min - Minimum allowed date (ISO format)
|
|
225
|
-
* @param max - Maximum allowed date (ISO format)
|
|
226
|
-
*
|
|
227
|
-
* @example
|
|
228
|
-
* addToSelected(
|
|
229
|
-
* blurEvent,
|
|
230
|
-
* this.calendarRef,
|
|
231
|
-
* '2024-01-01',
|
|
232
|
-
* '2024-12-31'
|
|
233
|
-
* )
|
|
234
|
-
*/
|
|
235
96
|
addToSelected(
|
|
236
97
|
event: Event | KeyboardEvent,
|
|
237
98
|
calendarRef: Ref<PktCalendar>,
|
|
@@ -257,87 +118,19 @@ export const calendarUtils = {
|
|
|
257
118
|
target.value = ''
|
|
258
119
|
},
|
|
259
120
|
|
|
260
|
-
/**
|
|
261
|
-
* Handles calendar positioning based on viewport and input position
|
|
262
|
-
*
|
|
263
|
-
* Intelligently positions the calendar popup either above or below the input
|
|
264
|
-
* depending on available viewport space. Accounts for optional counter elements.
|
|
265
|
-
*
|
|
266
|
-
* The positioning logic:
|
|
267
|
-
* 1. By default, positions calendar below the input (top: 100%)
|
|
268
|
-
* 2. If calendar would overflow viewport bottom AND there's space above, positions above
|
|
269
|
-
* 3. Accounts for counter height (30px) when hasCounter is true
|
|
270
|
-
*
|
|
271
|
-
* @param popupRef - Lit ref to the calendar popup element
|
|
272
|
-
* @param inputRef - Lit ref to the input element
|
|
273
|
-
* @param hasCounter - Whether the input has a character counter below it
|
|
274
|
-
*
|
|
275
|
-
* @example
|
|
276
|
-
* handleCalendarPosition(
|
|
277
|
-
* this.popupRef,
|
|
278
|
-
* this.inputRef,
|
|
279
|
-
* this.multiple && this.maxlength !== null
|
|
280
|
-
* )
|
|
281
|
-
*/
|
|
282
121
|
handleCalendarPosition(
|
|
283
122
|
popupRef: Ref<HTMLDivElement>,
|
|
284
123
|
inputRef: Ref<HTMLInputElement>,
|
|
285
124
|
hasCounter: boolean = false,
|
|
286
125
|
): void {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
const inputRect =
|
|
290
|
-
inputRef.value.parentElement?.getBoundingClientRect() ||
|
|
291
|
-
inputRef.value.getBoundingClientRect()
|
|
292
|
-
|
|
293
|
-
const inputHeight = hasCounter ? inputRect.height + 30 : inputRect.height
|
|
294
|
-
const popupHeight = popupRef.value.getBoundingClientRect().height
|
|
295
|
-
|
|
296
|
-
let top = hasCounter ? 'calc(100% - 30px)' : '100%'
|
|
297
|
-
|
|
298
|
-
if (
|
|
299
|
-
inputRect &&
|
|
300
|
-
inputRect.top + popupHeight > window.innerHeight &&
|
|
301
|
-
inputRect.top - popupHeight > 0
|
|
302
|
-
) {
|
|
303
|
-
top = `calc(100% - ${inputHeight}px - ${popupHeight}px)`
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
popupRef.value.style.top = top
|
|
126
|
+
sharedHandleCalendarPosition(popupRef.value ?? null, inputRef.value ?? null, hasCounter)
|
|
307
127
|
},
|
|
308
128
|
}
|
|
309
129
|
|
|
310
130
|
/**
|
|
311
|
-
* Event handling utilities
|
|
312
|
-
*
|
|
313
|
-
* Factory functions for creating event listeners with proper closure over component state.
|
|
131
|
+
* Event handling utilities (Lit-specific — uses Lit Ref types)
|
|
314
132
|
*/
|
|
315
133
|
export const eventUtils = {
|
|
316
|
-
/**
|
|
317
|
-
* Creates a document click listener for closing calendar on outside clicks
|
|
318
|
-
*
|
|
319
|
-
* Returns a function that closes the calendar when clicking outside the
|
|
320
|
-
* datepicker component (input, button, or calendar popup).
|
|
321
|
-
*
|
|
322
|
-
* @param inputRef - Lit ref to the primary input element
|
|
323
|
-
* @param inputRefTo - Lit ref to the secondary input (for range picker) or null
|
|
324
|
-
* @param btnRef - Lit ref to the calendar button
|
|
325
|
-
* @param getCalendarOpen - Function returning current calendar open state
|
|
326
|
-
* @param onBlur - Callback to execute on blur
|
|
327
|
-
* @param hideCalendar - Callback to hide the calendar
|
|
328
|
-
* @returns Event listener function to attach to document
|
|
329
|
-
*
|
|
330
|
-
* @example
|
|
331
|
-
* const listener = createDocumentClickListener(
|
|
332
|
-
* this.inputRef,
|
|
333
|
-
* null,
|
|
334
|
-
* this.btnRef,
|
|
335
|
-
* () => this.calendarOpen,
|
|
336
|
-
* () => this.handleBlur(),
|
|
337
|
-
* () => this.calendarOpen = false
|
|
338
|
-
* )
|
|
339
|
-
* document.addEventListener('click', listener)
|
|
340
|
-
*/
|
|
341
134
|
createDocumentClickListener(
|
|
342
135
|
inputRef: Ref<HTMLInputElement>,
|
|
343
136
|
inputRefTo: Ref<HTMLInputElement> | null,
|
|
@@ -362,22 +155,6 @@ export const eventUtils = {
|
|
|
362
155
|
}
|
|
363
156
|
},
|
|
364
157
|
|
|
365
|
-
/**
|
|
366
|
-
* Creates a document keydown listener for ESC key
|
|
367
|
-
*
|
|
368
|
-
* Returns a function that closes the calendar when Escape is pressed.
|
|
369
|
-
*
|
|
370
|
-
* @param getCalendarOpen - Function returning current calendar open state
|
|
371
|
-
* @param hideCalendar - Callback to hide the calendar
|
|
372
|
-
* @returns Event listener function to attach to document
|
|
373
|
-
*
|
|
374
|
-
* @example
|
|
375
|
-
* const listener = createDocumentKeydownListener(
|
|
376
|
-
* () => this.calendarOpen,
|
|
377
|
-
* () => this.calendarOpen = false
|
|
378
|
-
* )
|
|
379
|
-
* document.addEventListener('keydown', listener)
|
|
380
|
-
*/
|
|
381
158
|
createDocumentKeydownListener(
|
|
382
159
|
getCalendarOpen: () => boolean,
|
|
383
160
|
hideCalendar: () => void,
|
|
@@ -389,25 +166,6 @@ export const eventUtils = {
|
|
|
389
166
|
}
|
|
390
167
|
},
|
|
391
168
|
|
|
392
|
-
/**
|
|
393
|
-
* Handles focus out events for calendar popup
|
|
394
|
-
*
|
|
395
|
-
* Closes the calendar when focus leaves the datepicker component entirely.
|
|
396
|
-
* Used for keyboard navigation accessibility.
|
|
397
|
-
*
|
|
398
|
-
* @param event - The focusout event
|
|
399
|
-
* @param element - The container element to check focus against
|
|
400
|
-
* @param onBlur - Callback to execute on blur
|
|
401
|
-
* @param hideCalendar - Callback to hide the calendar
|
|
402
|
-
*
|
|
403
|
-
* @example
|
|
404
|
-
* handleFocusOut(
|
|
405
|
-
* event,
|
|
406
|
-
* this,
|
|
407
|
-
* () => this.handleBlur(),
|
|
408
|
-
* () => this.calendarOpen = false
|
|
409
|
-
* )
|
|
410
|
-
*/
|
|
411
169
|
handleFocusOut(
|
|
412
170
|
event: FocusEvent,
|
|
413
171
|
element: HTMLElement,
|
|
@@ -423,139 +181,22 @@ export const eventUtils = {
|
|
|
423
181
|
|
|
424
182
|
/**
|
|
425
183
|
* CSS class utilities
|
|
426
|
-
*
|
|
427
|
-
* Functions for generating CSS class objects for use with classMap directive.
|
|
184
|
+
* Delegates to shared-utils/datepicker-utils
|
|
428
185
|
*/
|
|
429
186
|
export const cssUtils = {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
* @param fullwidth - Whether input should take full width
|
|
434
|
-
* @param showRangeLabels - Whether range labels are visible
|
|
435
|
-
* @param multiple - Whether this is a multiple date picker
|
|
436
|
-
* @param range - Whether this is a range date picker
|
|
437
|
-
* @param readonly - Whether input is readonly
|
|
438
|
-
* @param inputType - The input type ('date' or 'text')
|
|
439
|
-
* @returns Object with class names as keys and boolean values
|
|
440
|
-
*
|
|
441
|
-
* @example
|
|
442
|
-
* const classes = getInputClasses(true, false, false, false, false, 'date')
|
|
443
|
-
* // Returns { 'pkt-input': true, 'pkt-input--fullwidth': true, ... }
|
|
444
|
-
*/
|
|
445
|
-
getInputClasses(
|
|
446
|
-
fullwidth: boolean,
|
|
447
|
-
showRangeLabels: boolean,
|
|
448
|
-
multiple: boolean,
|
|
449
|
-
range: boolean,
|
|
450
|
-
readonly?: boolean,
|
|
451
|
-
inputType?: string,
|
|
452
|
-
) {
|
|
453
|
-
return {
|
|
454
|
-
'pkt-input': true,
|
|
455
|
-
'pkt-datepicker__input': true,
|
|
456
|
-
'pkt-input--fullwidth': fullwidth,
|
|
457
|
-
'pkt-datepicker--hasrangelabels': showRangeLabels,
|
|
458
|
-
'pkt-datepicker--multiple': multiple,
|
|
459
|
-
'pkt-datepicker--range': range,
|
|
460
|
-
'ios-readonly-hack': readonly === false && inputType === 'text',
|
|
461
|
-
}
|
|
462
|
-
},
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
* Generates button classes for calendar button
|
|
466
|
-
*
|
|
467
|
-
* @returns Object with class names for the calendar toggle button
|
|
468
|
-
*
|
|
469
|
-
* @example
|
|
470
|
-
* const classes = getButtonClasses()
|
|
471
|
-
* // Returns { 'pkt-btn': true, 'pkt-btn--icon-only': true, ... }
|
|
472
|
-
*/
|
|
473
|
-
getButtonClasses() {
|
|
474
|
-
return {
|
|
475
|
-
'pkt-input-icon': true,
|
|
476
|
-
'pkt-btn': true,
|
|
477
|
-
'pkt-btn--icon-only': true,
|
|
478
|
-
'pkt-btn--tertiary': true,
|
|
479
|
-
'pkt-datepicker__calendar-button': true,
|
|
480
|
-
}
|
|
481
|
-
},
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* Generates range label classes
|
|
485
|
-
*
|
|
486
|
-
* @param showRangeLabels - Whether range labels should be visible
|
|
487
|
-
* @returns Object with class names for range label elements
|
|
488
|
-
*
|
|
489
|
-
* @example
|
|
490
|
-
* const classes = getRangeLabelClasses(true)
|
|
491
|
-
* // Returns { 'pkt-input-prefix': true, 'pkt-hide': false }
|
|
492
|
-
*/
|
|
493
|
-
getRangeLabelClasses(showRangeLabels: boolean) {
|
|
494
|
-
return {
|
|
495
|
-
'pkt-input-prefix': showRangeLabels,
|
|
496
|
-
'pkt-hide': !showRangeLabels,
|
|
497
|
-
}
|
|
498
|
-
},
|
|
187
|
+
getInputClasses: getDatepickerInputClasses,
|
|
188
|
+
getButtonClasses: getDatepickerButtonClasses,
|
|
189
|
+
getRangeLabelClasses,
|
|
499
190
|
}
|
|
500
191
|
|
|
501
192
|
/**
|
|
502
193
|
* Date value processing utilities
|
|
503
|
-
*
|
|
504
|
-
*
|
|
194
|
+
* processDateSelection delegates to shared-utils.
|
|
195
|
+
* updateInputValues and processRangeBlur stay Lit-specific (use Lit Ref).
|
|
505
196
|
*/
|
|
506
197
|
export const dateProcessingUtils = {
|
|
507
|
-
|
|
508
|
-
* Processes date selection from calendar events
|
|
509
|
-
*
|
|
510
|
-
* Converts the calendar's date selection into the appropriate string format
|
|
511
|
-
* for the input element's value.
|
|
512
|
-
*
|
|
513
|
-
* @param detail - Date selection detail from calendar event (string or array)
|
|
514
|
-
* @param multiple - Whether this is a multiple date picker
|
|
515
|
-
* @param range - Whether this is a range date picker
|
|
516
|
-
* @returns Formatted date string (single date or comma-separated dates)
|
|
517
|
-
*
|
|
518
|
-
* @example
|
|
519
|
-
* processDateSelection(['2024-01-15'], false, false) // Returns '2024-01-15'
|
|
520
|
-
* processDateSelection(['2024-01-15', '2024-01-20'], true, false) // Returns '2024-01-15,2024-01-20'
|
|
521
|
-
*/
|
|
522
|
-
processDateSelection(detail: any, multiple: boolean, range: boolean): string {
|
|
523
|
-
if (!multiple && !range) {
|
|
524
|
-
return detail[0] || ''
|
|
525
|
-
}
|
|
526
|
-
if (Array.isArray(detail)) {
|
|
527
|
-
return detail.join(',')
|
|
528
|
-
}
|
|
529
|
-
return detail
|
|
530
|
-
},
|
|
198
|
+
processDateSelection: sharedProcessDateSelection,
|
|
531
199
|
|
|
532
|
-
/**
|
|
533
|
-
* Updates input values after calendar selection
|
|
534
|
-
*
|
|
535
|
-
* Synchronizes input element values with the calendar's selected dates.
|
|
536
|
-
* Handles single, range, and multiple date scenarios differently.
|
|
537
|
-
*
|
|
538
|
-
* - Single: Updates single input with first date
|
|
539
|
-
* - Range: Updates two inputs with start and end dates
|
|
540
|
-
* - Multiple: Does nothing (dates shown as tags, not in input)
|
|
541
|
-
*
|
|
542
|
-
* @param inputRef - Lit ref to the primary input element
|
|
543
|
-
* @param inputRefTo - Lit ref to the secondary input (for range) or null
|
|
544
|
-
* @param values - Array of selected date strings
|
|
545
|
-
* @param range - Whether this is a range date picker
|
|
546
|
-
* @param multiple - Whether this is a multiple date picker
|
|
547
|
-
* @param manageValidity - Callback to validate the input
|
|
548
|
-
*
|
|
549
|
-
* @example
|
|
550
|
-
* updateInputValues(
|
|
551
|
-
* this.inputRef,
|
|
552
|
-
* this.inputRefTo,
|
|
553
|
-
* ['2024-01-15', '2024-01-20'],
|
|
554
|
-
* true, // range
|
|
555
|
-
* false,
|
|
556
|
-
* (input) => this.dispatchManageValidity(input)
|
|
557
|
-
* )
|
|
558
|
-
*/
|
|
559
200
|
updateInputValues(
|
|
560
201
|
inputRef: Ref<HTMLInputElement>,
|
|
561
202
|
inputRefTo: Ref<HTMLInputElement> | null,
|
|
@@ -577,30 +218,6 @@ export const dateProcessingUtils = {
|
|
|
577
218
|
}
|
|
578
219
|
},
|
|
579
220
|
|
|
580
|
-
/**
|
|
581
|
-
* Processes blur events for range inputs
|
|
582
|
-
*
|
|
583
|
-
* Handles the logic when a range input loses focus:
|
|
584
|
-
* - If input has value: validates it and updates the calendar to reflect the typed date
|
|
585
|
-
* - If input is empty but range has start date: clears the entire range
|
|
586
|
-
*
|
|
587
|
-
* This ensures the range picker calendar stays synchronized when users type dates directly.
|
|
588
|
-
*
|
|
589
|
-
* @param event - The blur event from the input
|
|
590
|
-
* @param values - Current array of selected dates [start, end]
|
|
591
|
-
* @param calendarRef - Lit ref to the calendar component
|
|
592
|
-
* @param clearInputValue - Callback to clear the date selection
|
|
593
|
-
* @param manageValidity - Callback to validate the input
|
|
594
|
-
*
|
|
595
|
-
* @example
|
|
596
|
-
* processRangeBlur(
|
|
597
|
-
* blurEvent,
|
|
598
|
-
* ['2024-01-15', '2024-01-20'],
|
|
599
|
-
* this.calendarRef,
|
|
600
|
-
* () => this.value = [],
|
|
601
|
-
* (input) => this.dispatchManageValidity(input)
|
|
602
|
-
* )
|
|
603
|
-
*/
|
|
604
221
|
processRangeBlur(
|
|
605
222
|
event: Event,
|
|
606
223
|
values: string[],
|
|
@@ -613,7 +230,6 @@ export const dateProcessingUtils = {
|
|
|
613
230
|
manageValidity(target)
|
|
614
231
|
const date = fromISOToDate(target.value)
|
|
615
232
|
if (date) {
|
|
616
|
-
// Always update the calendar when a valid date is typed
|
|
617
233
|
calendarRef?.value?.handleDateSelect(date)
|
|
618
234
|
}
|
|
619
235
|
} else if (values[0]) {
|
|
@@ -624,104 +240,9 @@ export const dateProcessingUtils = {
|
|
|
624
240
|
|
|
625
241
|
/**
|
|
626
242
|
* Keyboard navigation utilities
|
|
627
|
-
*
|
|
628
|
-
* Functions for handling keyboard interactions with proper accessibility support.
|
|
243
|
+
* Delegates to shared-utils/datepicker-utils
|
|
629
244
|
*/
|
|
630
245
|
export const keyboardUtils = {
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
*
|
|
634
|
-
* Provides consistent keyboard navigation across all datepicker types:
|
|
635
|
-
* - Space: Opens calendar
|
|
636
|
-
* - Enter: Submits form, focuses next input, or blurs (priority order)
|
|
637
|
-
* - Comma: Adds date to selection (multiple) or blurs input
|
|
638
|
-
*
|
|
639
|
-
* The handler prioritizes callbacks in the order provided, allowing
|
|
640
|
-
* different behaviors for single, multiple, and range pickers.
|
|
641
|
-
*
|
|
642
|
-
* @param event - The keyboard event
|
|
643
|
-
* @param toggleCalendar - Callback to toggle calendar visibility
|
|
644
|
-
* @param submitForm - Optional callback to submit the form (highest priority on Enter)
|
|
645
|
-
* @param focusNextInput - Optional callback to focus next input (medium priority on Enter)
|
|
646
|
-
* @param blurInput - Optional callback to blur current input (lowest priority on Enter/Comma)
|
|
647
|
-
* @param commaHandler - Optional callback for comma key (overrides default blur behavior)
|
|
648
|
-
*
|
|
649
|
-
* @example
|
|
650
|
-
* // Single datepicker: Enter submits form or blurs
|
|
651
|
-
* handleInputKeydown(
|
|
652
|
-
* event,
|
|
653
|
-
* (e) => this.toggleCalendar(e),
|
|
654
|
-
* () => formUtils.submitFormOrFallback(this.internals, () => this.inputRef.value?.blur()),
|
|
655
|
-
* undefined,
|
|
656
|
-
* () => this.inputRef.value?.blur()
|
|
657
|
-
* )
|
|
658
|
-
*
|
|
659
|
-
* @example
|
|
660
|
-
* // Range datepicker: Enter moves to next input
|
|
661
|
-
* handleInputKeydown(
|
|
662
|
-
* event,
|
|
663
|
-
* (e) => this.toggleCalendar(e),
|
|
664
|
-
* () => formUtils.submitFormOrFallback(this.internals, () => this.inputRefTo.value?.focus()),
|
|
665
|
-
* () => this.inputRefTo.value?.focus(),
|
|
666
|
-
* () => this.inputRef.value?.blur()
|
|
667
|
-
* )
|
|
668
|
-
*/
|
|
669
|
-
handleInputKeydown(
|
|
670
|
-
event: KeyboardEvent,
|
|
671
|
-
toggleCalendar: (e: Event) => void,
|
|
672
|
-
submitForm?: () => void,
|
|
673
|
-
focusNextInput?: () => void,
|
|
674
|
-
blurInput?: () => void,
|
|
675
|
-
commaHandler?: (e: KeyboardEvent) => void,
|
|
676
|
-
): void {
|
|
677
|
-
const { key } = event
|
|
678
|
-
|
|
679
|
-
if (key === ',') {
|
|
680
|
-
event.preventDefault()
|
|
681
|
-
if (commaHandler) {
|
|
682
|
-
commaHandler(event)
|
|
683
|
-
} else if (blurInput) {
|
|
684
|
-
blurInput()
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
if (key === 'Space' || key === ' ') {
|
|
689
|
-
event.preventDefault()
|
|
690
|
-
toggleCalendar(event)
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
if (key === 'Enter') {
|
|
694
|
-
event.preventDefault()
|
|
695
|
-
if (submitForm) {
|
|
696
|
-
submitForm()
|
|
697
|
-
} else if (focusNextInput) {
|
|
698
|
-
focusNextInput()
|
|
699
|
-
} else if (blurInput) {
|
|
700
|
-
blurInput()
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
},
|
|
704
|
-
|
|
705
|
-
/**
|
|
706
|
-
* Handles keyboard interactions for calendar button
|
|
707
|
-
*
|
|
708
|
-
* Ensures the calendar button is keyboard accessible by responding
|
|
709
|
-
* to Enter and Space keys (standard button activation keys).
|
|
710
|
-
*
|
|
711
|
-
* @param event - The keyboard event
|
|
712
|
-
* @param toggleCalendar - Callback to toggle calendar visibility
|
|
713
|
-
*
|
|
714
|
-
* @example
|
|
715
|
-
* handleButtonKeydown(
|
|
716
|
-
* event,
|
|
717
|
-
* (e) => this.dispatchToggleCalendar(e)
|
|
718
|
-
* )
|
|
719
|
-
*/
|
|
720
|
-
handleButtonKeydown(event: KeyboardEvent, toggleCalendar: (e: Event) => void): void {
|
|
721
|
-
const { key } = event
|
|
722
|
-
if (key === 'Enter' || key === ' ' || key === 'Space') {
|
|
723
|
-
event.preventDefault()
|
|
724
|
-
toggleCalendar(event)
|
|
725
|
-
}
|
|
726
|
-
},
|
|
246
|
+
handleInputKeydown: handleDatepickerKeydown,
|
|
247
|
+
handleButtonKeydown: handleDatepickerButtonKeydown,
|
|
727
248
|
}
|