@nova-design-system/nova-react 3.17.0 → 3.18.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 (50) hide show
  1. package/dist/cjs/{index-B0fvq6nd.js → index-_oq_uffl.js} +801 -590
  2. package/dist/cjs/index.js +1 -1
  3. package/dist/cjs/{nv-accordion-item.entry-DSXSMuOt.js → nv-accordion-item.entry-DBO7ztqb.js} +1 -1
  4. package/dist/cjs/{nv-accordion.entry-D2GTCEoF.js → nv-accordion.entry-Ma9HqnfE.js} +1 -1
  5. package/dist/cjs/{nv-alert.entry-CxrdJWzE.js → nv-alert.entry--bKp-lux.js} +1 -1
  6. package/dist/cjs/{nv-avatar.entry-Boe2Bp39.js → nv-avatar.entry-DN_-lrBo.js} +1 -1
  7. package/dist/cjs/{nv-badge_2.entry-Cvu8cWAm.js → nv-badge_2.entry-Dl4iJgMU.js} +1 -1
  8. package/dist/cjs/{nv-breadcrumb.entry-IBd49U13.js → nv-breadcrumb.entry-BBvgQ-p_.js} +1 -1
  9. package/dist/cjs/{nv-breadcrumbs.entry-CxDCe3pi.js → nv-breadcrumbs.entry-1SoAvjZG.js} +1 -1
  10. package/dist/cjs/{nv-button.entry-veszqyTF.js → nv-button.entry-B4k5GJIo.js} +1 -1
  11. package/dist/cjs/{nv-buttongroup.entry-BoqH0Kje.js → nv-buttongroup.entry-B5LQavYS.js} +1 -1
  12. package/dist/cjs/{nv-calendar.entry-D-Wl56-6.js → nv-calendar.entry-mOSPsfm-.js} +1 -1
  13. package/dist/cjs/{nv-col.entry-BhKZwFpL.js → nv-col.entry-Dzg7C_6U.js} +1 -1
  14. package/dist/cjs/{nv-datagrid.entry-DnMZbymp.js → nv-datagrid.entry-CfZeMjYO.js} +2 -2
  15. package/dist/cjs/{nv-datagridcolumn.entry-U38uoM6D.js → nv-datagridcolumn.entry-DEqq7_M9.js} +1 -1
  16. package/dist/cjs/{nv-dialog.entry-BF4VplVi.js → nv-dialog.entry-DSX9jRuv.js} +1 -1
  17. package/dist/cjs/{nv-dialogfooter_2.entry-TqO3Mryg.js → nv-dialogfooter_2.entry-t9MuuUDn.js} +1 -1
  18. package/dist/cjs/{nv-fieldcheckbox.entry-C_rJ7Jrf.js → nv-fieldcheckbox.entry-KDMtAaLt.js} +1 -1
  19. package/dist/cjs/{nv-fielddate.entry-DZdztKCP.js → nv-fielddate.entry-SjEKszkJ.js} +1 -1
  20. package/dist/cjs/{nv-fielddaterange.entry-CMxpi6X9.js → nv-fielddaterange.entry-B6pLWuF3.js} +1 -1
  21. package/dist/cjs/{nv-fielddropdown.entry-T-qNo0gM.js → nv-fielddropdown.entry-DIYVOvRw.js} +1 -1
  22. package/dist/cjs/{nv-fielddropdownitem.entry-BfIqaxW3.js → nv-fielddropdownitem.entry-CUMPmEzj.js} +1 -1
  23. package/dist/cjs/{nv-fieldmultiselect.entry-rtKSNZ5F.js → nv-fieldmultiselect.entry-BFt11EM5.js} +1 -1
  24. package/dist/cjs/{nv-fieldnumber.entry-BD-xCdb5.js → nv-fieldnumber.entry-V2AYjG7j.js} +1 -1
  25. package/dist/cjs/{nv-fieldpassword.entry-Dmt91T4y.js → nv-fieldpassword.entry-BoQAgzW2.js} +1 -1
  26. package/dist/cjs/{nv-fieldradio.entry-CAoRufTW.js → nv-fieldradio.entry-CKDZ6g8q.js} +1 -1
  27. package/dist/cjs/{nv-fieldselect.entry-2YLbIpBO.js → nv-fieldselect.entry-Daa3JB5t.js} +1 -1
  28. package/dist/cjs/{nv-fieldslider.entry-D6g_MrUd.js → nv-fieldslider.entry-BhT0C9hG.js} +1 -1
  29. package/dist/cjs/{nv-fieldtext.entry-D-SS4OPR.js → nv-fieldtext.entry-a1x9CfYv.js} +1 -1
  30. package/dist/cjs/{nv-fieldtextarea.entry-L0XDrdHL.js → nv-fieldtextarea.entry-nn5SqAJD.js} +1 -1
  31. package/dist/cjs/nv-fieldtime.entry-DQb9u4eg.js +1076 -0
  32. package/dist/cjs/{nv-icon.entry-B7mLhu0c.js → nv-icon.entry-17nX7627.js} +3 -3
  33. package/dist/cjs/{nv-iconbutton_2.entry-iinBJBb6.js → nv-iconbutton_2.entry-WTj2sSR7.js} +3 -3
  34. package/dist/cjs/{nv-menu.entry-BTW4XauN.js → nv-menu.entry-DnHSkRkc.js} +2 -2
  35. package/dist/cjs/{nv-menuitem.entry-CIT2_Fbe.js → nv-menuitem.entry-BMThBD-z.js} +2 -2
  36. package/dist/cjs/{nv-notification.entry-CVyzCsSh.js → nv-notification.entry-BgORwEc6.js} +2 -2
  37. package/dist/cjs/{nv-notificationcontainer.entry-CqoyGWAa.js → nv-notificationcontainer.entry-C3D52xHp.js} +2 -2
  38. package/dist/cjs/{nv-popover.entry-Bf5ihsdq.js → nv-popover.entry-Bc5Hs_ZA.js} +2 -2
  39. package/dist/cjs/{nv-row.entry-Chp5QzjD.js → nv-row.entry-rTFsRQhn.js} +2 -2
  40. package/dist/cjs/{nv-split.entry-DSB_HMU-.js → nv-split.entry-CEkdVB0d.js} +2 -2
  41. package/dist/cjs/{nv-stack.entry-D6L6830W.js → nv-stack.entry-DFWmiZRf.js} +2 -2
  42. package/dist/cjs/{nv-table.entry-B-UuWaI5.js → nv-table.entry-Drf8wXN5.js} +2 -2
  43. package/dist/cjs/{nv-toggle.entry-AG7sAORg.js → nv-toggle.entry-D3jHT0co.js} +3 -3
  44. package/dist/cjs/{nv-togglebutton.entry-Btlxm5gO.js → nv-togglebutton.entry-zN93TaA9.js} +2 -2
  45. package/dist/cjs/{nv-togglebuttongroup.entry-CM3nWiUU.js → nv-togglebuttongroup.entry-D4dUkodA.js} +2 -2
  46. package/dist/cjs/{nv-tooltip.entry-m4AYXhW3.js → nv-tooltip.entry-DqFRA9_B.js} +2 -2
  47. package/dist/components/NvDatatable.js +122 -19
  48. package/dist/types/components/NvDatatable.d.ts +35 -1
  49. package/package.json +1 -1
  50. package/dist/cjs/nv-fieldtime.entry-Hw5VOmpK.js +0 -1028
@@ -0,0 +1,1076 @@
1
+ 'use strict';
2
+
3
+ var index = require('./index-_oq_uffl.js');
4
+ var constants69bafca2 = require('./constants-69bafca2-DpB_ghPF.js');
5
+ var v4A79185f4 = require('./v4-a79185f4-2n0dOd_Y.js');
6
+ require('react');
7
+ require('react-dom');
8
+
9
+ /**
10
+ * Format configurations for all supported time formats
11
+ */
12
+ const FORMAT_CONFIGS = {
13
+ 'HH': {
14
+ pattern: /^([0-1]?[0-9]|2[0-3])$/,
15
+ parts: [constants69bafca2.TimeType.Hours],
16
+ defaultValue: '00',
17
+ maxLength: 2,
18
+ },
19
+ 'HH:mm': {
20
+ pattern: /^([0-1]?[0-9]|2[0-3]):([0-5]?[0-9])$/,
21
+ parts: [constants69bafca2.TimeType.Hours, constants69bafca2.TimeType.Minutes],
22
+ defaultValue: '00:00',
23
+ maxLength: 5,
24
+ },
25
+ 'HH:mm:ss': {
26
+ pattern: /^([0-1]?[0-9]|2[0-3]):([0-5]?[0-9]):([0-5]?[0-9])$/,
27
+ parts: [constants69bafca2.TimeType.Hours, constants69bafca2.TimeType.Minutes, constants69bafca2.TimeType.Seconds],
28
+ defaultValue: '00:00:00',
29
+ maxLength: 8,
30
+ },
31
+ 'hh': {
32
+ pattern: /^(0?[1-9]|1[0-2])$/,
33
+ parts: [constants69bafca2.TimeType.Hours],
34
+ defaultValue: '01',
35
+ maxLength: 2,
36
+ },
37
+ 'hh:mm': {
38
+ pattern: /^(0?[1-9]|1[0-2]):([0-5]?[0-9])$/,
39
+ parts: [constants69bafca2.TimeType.Hours, constants69bafca2.TimeType.Minutes],
40
+ defaultValue: '01:00',
41
+ maxLength: 5,
42
+ },
43
+ 'hh:mm:ss': {
44
+ pattern: /^(0?[1-9]|1[0-2]):([0-5]?[0-9]):([0-5]?[0-9])$/,
45
+ parts: [constants69bafca2.TimeType.Hours, constants69bafca2.TimeType.Minutes, constants69bafca2.TimeType.Seconds],
46
+ defaultValue: '01:00:00',
47
+ maxLength: 8,
48
+ },
49
+ };
50
+ /**
51
+ * Returns the visible time types for a given format
52
+ * @param {string} format - The time format string
53
+ * @returns {TimeType[]} Array of TimeType values that should be visible
54
+ */
55
+ function getVisibleTimeTypes(format) {
56
+ const config = FORMAT_CONFIGS[format];
57
+ if (!config) {
58
+ // Fallback for unknown formats
59
+ return [constants69bafca2.TimeType.Hours, constants69bafca2.TimeType.Minutes, constants69bafca2.TimeType.Seconds];
60
+ }
61
+ return config.parts;
62
+ }
63
+ /**
64
+ * Validates if a given value string matches the expected format pattern
65
+ * @param {string} value - The time value string to validate
66
+ * @param {string} format - The expected time format
67
+ * @returns {boolean} True if the value matches the format, false otherwise
68
+ */
69
+ function isValidFormatValue(value, format) {
70
+ if (!value || !format) {
71
+ return false;
72
+ }
73
+ const config = FORMAT_CONFIGS[format];
74
+ if (!config) {
75
+ return false;
76
+ }
77
+ return config.pattern.test(value);
78
+ }
79
+ /**
80
+ * Parses a time value string according to the specified format
81
+ * Handles both full and partial time strings with backward compatibility
82
+ * @param {string} value - The time value string to parse
83
+ * @param {string} format - The target time format
84
+ * @returns {TimeComponents} TimeComponents object with parsed hours, minutes, and seconds
85
+ */
86
+ function parseValueByFormat(value, format) {
87
+ const config = FORMAT_CONFIGS[format];
88
+ const defaultComponents = {
89
+ hours: format.startsWith('hh') ? '01' : '00',
90
+ minutes: '00',
91
+ seconds: '00',
92
+ };
93
+ if (!value || !config) {
94
+ return defaultComponents;
95
+ }
96
+ // Clean the input value - remove non-numeric characters except colons
97
+ const cleanValue = value.replace(/[^0-9:]/g, '');
98
+ // Try to match the exact format first
99
+ const exactMatch = cleanValue.match(config.pattern);
100
+ if (exactMatch) {
101
+ return extractComponentsFromMatch(exactMatch, format);
102
+ }
103
+ // Handle backward compatibility - parse full format values when format is shorter
104
+ const fullFormatPattern = /^([0-1]?[0-9]|2[0-3]):([0-5]?[0-9]):([0-5]?[0-9])$/;
105
+ const fullMatch = cleanValue.match(fullFormatPattern);
106
+ if (fullMatch) {
107
+ const fullComponents = extractComponentsFromMatch(fullMatch, 'HH:mm:ss');
108
+ return extractRelevantComponents(fullComponents, format);
109
+ }
110
+ // Handle partial format values - try to parse what we can
111
+ const parts = cleanValue.split(':');
112
+ const result = Object.assign({}, defaultComponents);
113
+ if (parts.length >= 1 && parts[0]) {
114
+ const hours = parseInt(parts[0], 10);
115
+ if (!isNaN(hours)) {
116
+ if (format.startsWith('hh')) {
117
+ // 12-hour format validation
118
+ if (hours >= 1 && hours <= 12) {
119
+ result.hours = hours.toString().padStart(2, '0');
120
+ }
121
+ else {
122
+ // Invalid hour for 12-hour format, keep default
123
+ result.hours = defaultComponents.hours;
124
+ }
125
+ }
126
+ else {
127
+ // 24-hour format validation
128
+ if (hours >= 0 && hours <= 23) {
129
+ result.hours = hours.toString().padStart(2, '0');
130
+ }
131
+ else {
132
+ // Invalid hour for 24-hour format, keep default
133
+ result.hours = defaultComponents.hours;
134
+ }
135
+ }
136
+ }
137
+ }
138
+ if (parts.length >= 2 &&
139
+ parts[1] &&
140
+ config.parts.includes(constants69bafca2.TimeType.Minutes)) {
141
+ const minutes = parseInt(parts[1], 10);
142
+ if (!isNaN(minutes) && minutes >= 0 && minutes <= 59) {
143
+ result.minutes = minutes.toString().padStart(2, '0');
144
+ }
145
+ }
146
+ if (parts.length >= 3 &&
147
+ parts[2] &&
148
+ config.parts.includes(constants69bafca2.TimeType.Seconds)) {
149
+ const seconds = parseInt(parts[2], 10);
150
+ if (!isNaN(seconds) && seconds >= 0 && seconds <= 59) {
151
+ result.seconds = seconds.toString().padStart(2, '0');
152
+ }
153
+ }
154
+ return result;
155
+ }
156
+ /**
157
+ * Extracts time components from a regex match result
158
+ * @param {RegExpMatchArray} match - The regex match result
159
+ * @param {string} format - The format that was matched
160
+ * @returns {TimeComponents} TimeComponents object
161
+ */
162
+ function extractComponentsFromMatch(match, format) {
163
+ const result = {
164
+ hours: format.startsWith('hh') ? '01' : '00',
165
+ minutes: '00',
166
+ seconds: '00',
167
+ };
168
+ if (match[1]) {
169
+ result.hours = parseInt(match[1], 10).toString().padStart(2, '0');
170
+ }
171
+ if (match[2]) {
172
+ result.minutes = parseInt(match[2], 10).toString().padStart(2, '0');
173
+ }
174
+ if (match[3]) {
175
+ result.seconds = parseInt(match[3], 10).toString().padStart(2, '0');
176
+ }
177
+ return result;
178
+ }
179
+ /**
180
+ * Extracts only the relevant components based on the target format
181
+ * @param {TimeComponents} components - Full time components
182
+ * @param {string} format - Target format to extract components for
183
+ * @returns {TimeComponents} TimeComponents with only relevant parts
184
+ */
185
+ function extractRelevantComponents(components, format) {
186
+ const config = FORMAT_CONFIGS[format];
187
+ const result = {
188
+ hours: format.startsWith('hh') ? '01' : '00',
189
+ minutes: '00',
190
+ seconds: '00',
191
+ };
192
+ if (config.parts.includes(constants69bafca2.TimeType.Hours)) {
193
+ // Validate hours for the target format
194
+ const hours = parseInt(components.hours, 10);
195
+ if (format.startsWith('hh')) {
196
+ // 12-hour format validation
197
+ if (hours >= 1 && hours <= 12) {
198
+ result.hours = components.hours;
199
+ }
200
+ // If invalid, keep the default '01'
201
+ }
202
+ else {
203
+ // 24-hour format validation
204
+ if (hours >= 0 && hours <= 23) {
205
+ result.hours = components.hours;
206
+ }
207
+ // If invalid, keep the default '00'
208
+ }
209
+ }
210
+ if (config.parts.includes(constants69bafca2.TimeType.Minutes)) {
211
+ result.minutes = components.minutes;
212
+ }
213
+ if (config.parts.includes(constants69bafca2.TimeType.Seconds)) {
214
+ result.seconds = components.seconds;
215
+ }
216
+ return result;
217
+ }
218
+ /**
219
+ * Reconstructs a time string from components according to the specified format
220
+ * @param {TimeComponents} components - Time components to reconstruct
221
+ * @param {string} format - Target format for reconstruction
222
+ * @returns {string} Formatted time string
223
+ */
224
+ function reconstructTimeByFormat(components, format) {
225
+ const config = FORMAT_CONFIGS[format];
226
+ if (!config) {
227
+ return `${components.hours}:${components.minutes}:${components.seconds}`;
228
+ }
229
+ switch (format) {
230
+ case 'HH':
231
+ case 'hh':
232
+ return components.hours;
233
+ case 'HH:mm':
234
+ case 'hh:mm':
235
+ return `${components.hours}:${components.minutes}`;
236
+ case 'HH:mm:ss':
237
+ case 'hh:mm:ss':
238
+ return `${components.hours}:${components.minutes}:${components.seconds}`;
239
+ default:
240
+ return `${components.hours}:${components.minutes}:${components.seconds}`;
241
+ }
242
+ }
243
+
244
+ const nvFieldtimeCss = "nv-fieldslider .slider-container .track-container:has(.thumb:hover) .track-range{background:var(--components-slider-track-filled-hover)}nv-fieldslider .slider-container .track-container:has(.thumb:hover) .thumb{border-color:var(--components-slider-track-filled-hover)}nv-fieldslider .slider-container .track-container:has(.thumb:focus) .track-range{background:var(--components-slider-track-filled-focus)}nv-fieldslider .slider-container .track-container:has(.thumb:focus) .thumb{border-color:var(--components-slider-track-filled-focus)}nv-fieldslider[error] .slider-container .track-container .track .track-range{background:var(--components-slider-track-filled-error)}nv-fieldslider[error] .slider-container .track-container .track .thumb{border-color:var(--components-slider-track-filled-error)}nv-fieldslider[error] .slider-container .track-container .track .thumb:hover{border-color:var(--components-slider-track-filled-error);outline:calc(var(--focus-outline-stroke) * 1) solid var(--components-slider-track-filled-error);outline-offset:calc(var(--focus-outline-offset) * 1);background-color:var(--components-slider-handler-background-error)}nv-fieldslider[error] .slider-container .track-container .track .thumb:focus{border-color:var(--components-slider-track-filled-error);outline:calc(var(--focus-outline-stroke) * 1) solid var(--components-slider-track-filled-error);outline-offset:calc(var(--focus-outline-offset) * 1);background-color:var(--components-slider-track-filled-error)}nv-fieldslider[error] .slider-container .track-container:has(.thumb:hover) .track-range{background:var(--components-slider-track-filled-error)}nv-fieldslider[error] .slider-container .track-container:has(.thumb:hover) .thumb{border-color:var(--components-slider-track-filled-error)}nv-fieldtime{--nv-field-border-default:var(--components-form-field-border-default);--nv-field-border-hover:var(--components-form-field-border-hover);--nv-field-border-focus:var(--components-form-field-border-focus);--nv-field-border-disabled:var(--components-form-field-border-default);--nv-field-border-readonly:var(--components-form-field-border-default);--nv-field-focus-box-shadow:var(--color-focus-brand);--nv-field-background:var(--components-form-field-background-default);display:flex;flex-direction:column;align-items:flex-start;gap:var(--form-gap-y);box-sizing:border-box;max-width:480px}nv-fieldtime[readonly]:not([readonly=false]){--nv-field-border-default:var(--components-form-field-border-readonly);--nv-field-border-hover:var(--nv-field-border-default);--nv-field-border-focus:var(--components-form-field-border-focus);--nv-field-border-disabled:var(--nv-field-border-default);--nv-field-border-readonly:var(--nv-field-border-default);--nv-field-background:var(--components-form-field-background-readonly)}nv-fieldtime[error]:not([error=false]){--nv-field-border-default:var(--components-form-field-border-error);--nv-field-border-hover:var(--nv-field-border-default);--nv-field-border-focus:var(--nv-field-border-default);--nv-field-border-disabled:var(--nv-field-border-default);--nv-field-border-readonly:var(--nv-field-border-default);--nv-field-focus-box-shadow:var(--color-focus-destructive-in-field)}nv-fieldtime[success]:not([success=false]){--nv-field-border-default:var(--components-form-field-border-success);--nv-field-border-hover:var(--nv-field-border-default);--nv-field-border-focus:var(--nv-field-border-default);--nv-field-border-disabled:var(--nv-field-border-default);--nv-field-border-readonly:var(--nv-field-border-default);--nv-field-focus-box-shadow:var(--color-focus-success)}nv-fieldtime[required]:not([required=false]) label::after{content:\"*\";color:var(--components-form-text-required);font-weight:var(--font-weight-high-emphasis)}nv-fieldtime label{display:flex;align-items:center;gap:var(--form-label-gap);align-self:stretch;color:var(--components-form-text-label-default);font-family:var(--font-family-default), var(--font-family-fallback), sans-serif;font-size:var(--form-label-font-size);font-style:normal;font-weight:var(--font-weight-medium-emphasis);line-height:var(--form-label-line-height)}nv-fieldtime nv-popover{width:100%;display:block;z-index:9999}nv-fieldtime nv-popover [data-scope=popover]{padding:var(--list-dropdown-padding);background-color:var(--components-list-dropdown-background);border:1px solid var(--components-list-dropdown-border);width:100%}nv-fieldtime .input-wrapper{display:flex;flex-wrap:wrap;gap:var(--form-gap-x);align-items:stretch;align-self:stretch;width:100%}nv-fieldtime .input-container{display:flex;flex-grow:1;justify-content:center;align-items:center;align-self:stretch;border-radius:var(--form-field-radius);border-width:1px;border-style:solid;border-color:var(--nv-field-border-default);opacity:var(--components-form-opacity-default, 1);background:var(--nv-field-background);transition:all 150ms ease-out;display:flex;justify-content:flex-start;align-items:center;position:relative;width:100%;min-height:40px;gap:0;padding-left:var(--form-field-padding-x)}nv-fieldtime .input-container:hover{border-color:var(--nv-field-border-hover)}nv-fieldtime .input-container:focus-within,nv-fieldtime .input-container:focus-within:hover,nv-fieldtime .input-container:focus,nv-fieldtime .input-container:focus:hover{border-color:var(--nv-field-border-focus);box-shadow:0px 0px 0px var(--focus-field-stroke) var(--nv-field-focus-box-shadow)}nv-fieldtime .input-container:has(input:read-only){opacity:0.5;background-color:var(--components-form-field-background-readonly);border-color:var(--nv-field-border-readonly)}nv-fieldtime .input-container:has(input:disabled){opacity:0.5;background-color:var(--components-form-field-background-disabled);border-color:var(--nv-field-border-disabled)}nv-fieldtime .input-container input.time-input{display:flex;align-items:center;flex:1 0 0;overflow:hidden;background-color:transparent;color:var(--components-form-field-content-text);padding:var(--form-field-padding-y) var(--form-field-padding-x);font-size:var(--form-field-font-size);font-style:normal;font-weight:var(--font-weight-medium-emphasis);line-height:var(--form-field-line-height);width:100%;width:100%;min-width:24px;flex:0 0 24px;text-align:center;padding:0;margin:0}nv-fieldtime .input-container input.time-input:focus{outline:none}nv-fieldtime .input-container input.time-input::placeholder{overflow:hidden;color:var(--components-form-field-content-placeholder);text-overflow:ellipsis;font-family:var(--font-family-default), var(--font-family-fallback), sans-serif;font-size:var(--form-field-font-size);font-style:normal;font-weight:var(--font-weight-low-emphasis);line-height:var(--form-field-line-height)}nv-fieldtime .input-container input.time-input[type=password]::-ms-clear,nv-fieldtime .input-container input.time-input[type=password]::-ms-reveal{display:none;width:0;height:0}nv-fieldtime .input-container input.time-input::-webkit-inner-spin-button,nv-fieldtime .input-container input.time-input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}nv-fieldtime .input-container span{width:100%;text-align:center;min-width:24px;flex:0 0 24px;padding:0 4px;color:var(--components-form-field-content-text)}nv-fieldtime .input-container>nv-iconbutton{border:0px;border-radius:0px;margin-left:auto}nv-fieldtime .input-container>nv-iconbutton:focus-visible{border-radius:var(--button-md-border-radius);outline-offset:-3px}nv-fieldtime .input-container>nv-iconbutton:last-of-type{border-top-right-radius:var(--form-field-radius);border-bottom-right-radius:var(--form-field-radius)}nv-fieldtime .input-container nv-icon.validation{color:var(--nv-field-border-default);position:absolute;right:50px;top:50%;transform:translateY(-50%)}nv-fieldtime .input-container:focus,nv-fieldtime .input-container:focus-within{border-color:var(--color-focus-brand);box-shadow:0px 0px 0px var(--focus-field-stroke) var(--color-focus-brand)}nv-fieldtime .description{display:flex;align-items:center;align-self:stretch;gap:var(--spacing-1);color:var(--components-form-text-description-default);font-family:var(--font-family-default), var(--font-family-fallback), sans-serif;font-size:var(--form-description-font-size);font-style:normal;line-height:var(--form-description-line-height)}nv-fieldtime .error-description{display:flex;align-items:center;align-self:stretch;gap:var(--spacing-1);color:var(--components-form-text-description-default);font-family:var(--font-family-default), var(--font-family-fallback), sans-serif;font-size:var(--form-description-font-size);font-style:normal;line-height:var(--form-description-line-height);color:var(--components-form-text-description-error)}nv-fieldtime hr{border:none;border-top:1px solid var(--dropdown-divider-color, #ccc);margin:0.5rem 0}nv-fieldtime .time-dropdown{width:100%}nv-fieldtime .time-dropdown .time-columns{display:flex;justify-content:flex-start;align-items:center}nv-fieldtime .time-dropdown .time-columns .time-column{flex:1;text-align:center;max-height:200px;overflow-y:auto;scroll-behavior:smooth;scrollbar-gutter:stable both-edges;scrollbar-gutter:auto}nv-fieldtime .time-dropdown .time-columns .time-column::-webkit-scrollbar{width:6px;height:6px}nv-fieldtime .time-dropdown .time-columns .time-column::-webkit-scrollbar-track{background-color:var(--color-level-10-background);border-radius:9999px}nv-fieldtime .time-dropdown .time-columns .time-column::-webkit-scrollbar-thumb{background-color:var(--color-gray-200);border-radius:9999px}nv-fieldtime .time-dropdown .time-columns .time-column:last-child{border-right:none}nv-fieldtime .time-dropdown .time-columns .time-column .time-option{padding:var(--calendar-padding);text-align:center;cursor:pointer;transition:background-color 0.2s;border-radius:var(--list-dropdown-item-radius);color:var(--components-calendar-cell-text);font-size:var(--font-size-sm);display:flex;justify-content:center;align-items:center}nv-fieldtime .time-dropdown .time-columns .time-column .time-option:hover{background-color:var(--components-calendar-cell-background-hover);color:var(--components-calendar-cell-text-hover)}nv-fieldtime .time-dropdown .time-columns .time-column .time-option:focus,nv-fieldtime .time-dropdown .time-columns .time-column .time-option:focus-within{background-color:var(--components-calendar-cell-background-hover);color:var(--components-calendar-cell-text-hover)}nv-fieldtime .time-dropdown .time-columns .time-column .time-option.selected{background-color:var(--components-calendar-cell-background-selected);color:var(--components-calendar-cell-text-selected)}nv-fieldtime .time-dropdown .time-columns .time-column .time-option.highlighted{background-color:var(--components-calendar-cell-background-hover);color:var(--components-menu-contextual-item-content-hover)}";
245
+ const NvFieldtimeStyle0 = nvFieldtimeCss;
246
+
247
+ const NvFieldtime = class {
248
+ constructor(hostRef) {
249
+ index.registerInstance(this, hostRef);
250
+ this.valueChanged = index.createEvent(this, "valueChanged");
251
+ // Input elements for hours, minutes, and seconds
252
+ this.inputElements = {};
253
+ this.inputZeroAdded = {};
254
+ this.typeFocused = constants69bafca2.TimeType.Hours;
255
+ /****************************************************************************/
256
+ //#region STATES
257
+ this.hours = '00';
258
+ this.minutes = '00';
259
+ this.seconds = '00';
260
+ /**
261
+ * Sets the ID for the input element and the for attribute of the associated
262
+ * label. If no ID is provided, a random one will be automatically generated
263
+ * to ensure unique identification, facilitating proper label association and
264
+ * accessibility.
265
+ */
266
+ this.inputId = v4A79185f4.v4();
267
+ /**
268
+ * Display the input field's content without allowing users to change it.
269
+ * Users can still click on it, select, and copy the text, but they won't be
270
+ * able to type or delete anything.
271
+ */
272
+ this.readonly = false;
273
+ /**
274
+ * The disabled prop lets you turn off the input field so that users can't
275
+ * interact with it. When disabled, the field is grayed out and won't respond to
276
+ * clicks or touches.
277
+ */
278
+ this.disabled = false;
279
+ /**
280
+ * Marks the input field as required, ensuring that the user must fill it out
281
+ * before submitting the form.
282
+ */
283
+ this.required = false;
284
+ /**
285
+ * Changes the input field’s appearance to indicate successful input or
286
+ * validation.
287
+ */
288
+ this.success = false;
289
+ /**
290
+ * Alters the input field's appearance to indicate an error, helping users
291
+ * identify fields that need correction.
292
+ * @validator error
293
+ */
294
+ this.error = false;
295
+ /**
296
+ * Specifies the time format to be used.
297
+ * Available formats:
298
+ * - HH: 24-hour format (00-23)
299
+ * - HH:mm: 24-hour format with minutes (00:00-23:59)
300
+ * - HH:mm:ss: 24-hour format with minutes and seconds (00:00:00-23:59:59)
301
+ * - hh: 12-hour format (01-12)
302
+ * - hh:mm: 12-hour format with minutes (01:00-12:59)
303
+ * - hh:mm:ss: 12-hour format with minutes and seconds (01:00:00-12:59:59)
304
+ *
305
+ * The component automatically shows only the relevant input fields based on the selected format.
306
+ * When the format changes dynamically, the component re-parses the current value and updates
307
+ * the visible fields accordingly.
308
+ */
309
+ this.format = 'HH:mm:ss';
310
+ /**
311
+ * State of the time picker popover.
312
+ */
313
+ this.open = false;
314
+ /**
315
+ * The step interval in milliseconds for time increments/decrements.
316
+ * This affects how the time changes when using arrow keys or spinners.
317
+ */
318
+ this.step = 60000; // In secondes
319
+ /**
320
+ * Applies focus to the input field as soon as the component is mounted. This
321
+ * is equivalent to setting the native autofocus attribute on an <input>
322
+ * element.
323
+ */
324
+ this.autofocus = false;
325
+ }
326
+ //#endregion EVENTS
327
+ /****************************************************************************/
328
+ //#region LISTENERS
329
+ handleOpenChanged(event) {
330
+ // Stop propagation to prevent the event from affecting parent components like dialogs
331
+ event.stopPropagation();
332
+ // Update `open` based on the popover state
333
+ this.open = event.detail;
334
+ }
335
+ handleKeyDown(event) {
336
+ var _a, _b;
337
+ if (!this.open) {
338
+ if (event.key === 'ArrowDown') {
339
+ this.open = true;
340
+ event.preventDefault();
341
+ return;
342
+ }
343
+ return;
344
+ }
345
+ // Verify if the popover element is defined
346
+ if (!this.popoverElement) {
347
+ console.warn('nv-fieldtime -> Popover element is not defined');
348
+ return;
349
+ }
350
+ const stringSelector = `.time-column.time-column-${this.typeFocused} div`;
351
+ const items = Array.from(this.el.querySelectorAll(stringSelector));
352
+ // Verify if there are items to navigate
353
+ if (items.length === 0) {
354
+ console.warn('nv-fieldtime -> No dropdown items found to navigate');
355
+ return;
356
+ }
357
+ let currentIndex = items.findIndex(item => item.classList.contains('highlighted'));
358
+ if (event.key === 'ArrowDown') {
359
+ event.preventDefault();
360
+ currentIndex = (currentIndex + 1) % items.length;
361
+ this.updateHighlightedItem(items, currentIndex);
362
+ }
363
+ else if (event.key === 'ArrowUp') {
364
+ event.preventDefault();
365
+ currentIndex = (currentIndex - 1 + items.length) % items.length;
366
+ this.updateHighlightedItem(items, currentIndex);
367
+ }
368
+ else if (event.key === 'Enter' && currentIndex >= 0) {
369
+ event.preventDefault();
370
+ items[currentIndex].click();
371
+ // Navigate to the next visible field
372
+ const visibleTypes = getVisibleTimeTypes(this.format);
373
+ const currentTypeIndex = visibleTypes.indexOf(this.typeFocused);
374
+ const nextTypeIndex = currentTypeIndex + 1;
375
+ if (nextTypeIndex < visibleTypes.length) {
376
+ const nextType = visibleTypes[nextTypeIndex];
377
+ (_a = this.inputElements[nextType]) === null || _a === void 0 ? void 0 : _a.focus();
378
+ (_b = this.inputElements[nextType]) === null || _b === void 0 ? void 0 : _b.select();
379
+ }
380
+ }
381
+ else if (event.key === 'Escape') {
382
+ event.preventDefault();
383
+ const visibleTypes = getVisibleTimeTypes(this.format);
384
+ const firstVisibleType = visibleTypes[0];
385
+ if (firstVisibleType && this.inputElements[firstVisibleType]) {
386
+ this.inputElements[firstVisibleType].blur();
387
+ }
388
+ }
389
+ }
390
+ //#endregion LISTENERS
391
+ /****************************************************************************/
392
+ //#region WATCHERS
393
+ handleValueChange(newValue) {
394
+ // Parse the new value and ensure it's in the correct format
395
+ if (newValue) {
396
+ const components = parseValueByFormat(newValue, this.format);
397
+ const formattedValue = reconstructTimeByFormat(components, this.format);
398
+ // Only emit if the formatted value is different from what we received
399
+ // This prevents infinite loops while ensuring format consistency
400
+ if (formattedValue !== newValue) {
401
+ this.value = formattedValue;
402
+ return; // The watcher will be called again with the formatted value
403
+ }
404
+ }
405
+ // Emit the value in the correct format
406
+ this.valueChanged.emit(newValue);
407
+ }
408
+ handleOpenChange(newOpen) {
409
+ // React to external changes, e.g., highlight current time on open
410
+ if (newOpen) {
411
+ // Re-highlight columns based on current value
412
+ const hourSelector = `.time-column.time-column-${constants69bafca2.TimeType.Hours} div`;
413
+ this.updateColumnHighlight(hourSelector, this.hours);
414
+ const minutesSelector = `.time-column.time-column-${constants69bafca2.TimeType.Minutes} div`;
415
+ this.updateColumnHighlight(minutesSelector, this.minutes);
416
+ const secondsSelector = `.time-column.time-column-${constants69bafca2.TimeType.Seconds} div`;
417
+ this.updateColumnHighlight(secondsSelector, this.seconds);
418
+ }
419
+ }
420
+ handleFormatChange(newFormat, oldFormat) {
421
+ if (newFormat === oldFormat) {
422
+ return; // No change, nothing to do
423
+ }
424
+ // Re-parse the current value with the new format
425
+ const currentValue = this.value || this.reconstructTime();
426
+ // Parse the current value using the old format to get the time components
427
+ const components = parseValueByFormat(currentValue, oldFormat || 'HH:mm:ss');
428
+ // Update the component state with the parsed components
429
+ this.hours = components.hours;
430
+ this.minutes = components.minutes;
431
+ this.seconds = components.seconds;
432
+ // Reconstruct the time value in the new format
433
+ const newValue = reconstructTimeByFormat(components, newFormat);
434
+ // Update the value, which will trigger the value watcher and emit the event
435
+ this.value = newValue;
436
+ // Force a re-render to update the visible input fields
437
+ index.forceUpdate(this.el);
438
+ }
439
+ //#endregion WATCHERS
440
+ /****************************************************************************/
441
+ //#region METHODS
442
+ handleInputChange(e, type) {
443
+ const inputElement = e.target;
444
+ const inputValue = inputElement.value.replace(/[^0-9]/g, ''); // Only keep numeric input
445
+ // Check if this field is visible for the current format
446
+ const visibleTypes = getVisibleTimeTypes(this.format);
447
+ if (!visibleTypes.includes(type)) {
448
+ return; // Don't process input for non-visible fields
449
+ }
450
+ // Update the time value based on the type
451
+ switch (type) {
452
+ case constants69bafca2.TimeType.Hours:
453
+ this.handleHoursChange(inputValue, type);
454
+ break;
455
+ case constants69bafca2.TimeType.Minutes:
456
+ this.handleMinutesChange(inputValue, type);
457
+ break;
458
+ case constants69bafca2.TimeType.Seconds:
459
+ this.handleSecondsChange(inputValue, type);
460
+ break;
461
+ }
462
+ // Reconstruct time from inputs in the correct format
463
+ const reconstructedValue = this.reconstructTime();
464
+ // Update the value, which will trigger the watcher and emit the event
465
+ this.value = reconstructedValue;
466
+ }
467
+ handleHoursChange(inputValue, type) {
468
+ var _a, _b;
469
+ const isHHFormat = this.format.startsWith('HH');
470
+ const maxHours = isHHFormat ? 24 : 12;
471
+ // Handle empty input
472
+ if (inputValue.length === 0) {
473
+ this.hours = '00';
474
+ return;
475
+ }
476
+ if (inputValue.length === 1) {
477
+ this.inputZeroAdded[type] = true;
478
+ const newInputValue = inputValue.padStart(2, '0');
479
+ this.hours = newInputValue;
480
+ }
481
+ else if (this.inputZeroAdded[type]) {
482
+ this.inputZeroAdded[type] = false;
483
+ const newInputValue = inputValue.slice(1, 3).padStart(2, '0');
484
+ const parsedNewInputValue = parseInt(newInputValue, 10) || 0;
485
+ // Only apply format validation (not min/max constraints)
486
+ if (parsedNewInputValue >= maxHours) {
487
+ this.hours = '00';
488
+ }
489
+ else {
490
+ this.hours = newInputValue;
491
+ }
492
+ }
493
+ else if (inputValue.length > 2) {
494
+ if (inputValue.startsWith('00')) {
495
+ this.inputZeroAdded[type] = true;
496
+ const newInputValue = inputValue.slice(1, 3).padStart(2, '0');
497
+ this.hours = newInputValue;
498
+ }
499
+ else {
500
+ const newInputValue = inputValue.slice(1, 3).padStart(2, '0');
501
+ const parsedNewInputValue = parseInt(newInputValue, 10) || 0;
502
+ // Only apply format validation (not min/max constraints)
503
+ if (parsedNewInputValue >= maxHours) {
504
+ this.hours = '00';
505
+ }
506
+ else {
507
+ this.hours = parsedNewInputValue.toString();
508
+ }
509
+ }
510
+ }
511
+ else {
512
+ const parsedNewInputValue = parseInt(inputValue, 10) || 0;
513
+ // Only apply format validation (not min/max constraints)
514
+ if (parsedNewInputValue >= maxHours) {
515
+ this.hours = '00';
516
+ }
517
+ else {
518
+ // For direct input, remove unnecessary leading zeros (e.g., '01' becomes '1')
519
+ this.hours = parsedNewInputValue.toString();
520
+ }
521
+ }
522
+ // Auto-navigation to next field when input is complete
523
+ if (this.hours.length >= 1 && !this.inputZeroAdded[type]) {
524
+ const visibleTypes = getVisibleTimeTypes(this.format);
525
+ const currentTypeIndex = visibleTypes.indexOf(constants69bafca2.TimeType.Hours);
526
+ const nextTypeIndex = currentTypeIndex + 1;
527
+ if (nextTypeIndex < visibleTypes.length) {
528
+ const nextType = visibleTypes[nextTypeIndex];
529
+ (_a = this.inputElements[nextType]) === null || _a === void 0 ? void 0 : _a.focus();
530
+ (_b = this.inputElements[nextType]) === null || _b === void 0 ? void 0 : _b.select();
531
+ }
532
+ }
533
+ }
534
+ handleMinutesChange(inputValue, type) {
535
+ var _a, _b;
536
+ const maxMinutes = 60;
537
+ // Handle empty input
538
+ if (inputValue.length === 0) {
539
+ this.minutes = '00';
540
+ return;
541
+ }
542
+ if (inputValue.length === 1) {
543
+ this.inputZeroAdded[type] = true;
544
+ const newInputValue = inputValue.padStart(2, '0');
545
+ this.minutes = newInputValue;
546
+ }
547
+ else if (this.inputZeroAdded[type]) {
548
+ this.inputZeroAdded[type] = false;
549
+ const newInputValue = inputValue.slice(1, 3).padStart(2, '0');
550
+ const parsedNewInputValue = parseInt(newInputValue, 10) || 0;
551
+ // Only apply format validation (not min/max constraints)
552
+ if (parsedNewInputValue >= maxMinutes) {
553
+ this.minutes = '00';
554
+ }
555
+ else {
556
+ this.minutes = newInputValue;
557
+ }
558
+ }
559
+ else if (inputValue.length > 2) {
560
+ if (inputValue.startsWith('00')) {
561
+ this.inputZeroAdded[type] = true;
562
+ const newInputValue = inputValue.slice(1, 3).padStart(2, '0');
563
+ this.minutes = newInputValue;
564
+ }
565
+ else {
566
+ const newInputValue = inputValue.slice(1, 3).padStart(2, '0');
567
+ const parsedNewInputValue = parseInt(newInputValue, 10) || 0;
568
+ // Only apply format validation (not min/max constraints)
569
+ if (parsedNewInputValue >= maxMinutes) {
570
+ this.minutes = '00';
571
+ }
572
+ else {
573
+ this.minutes = parsedNewInputValue.toString();
574
+ }
575
+ }
576
+ }
577
+ else {
578
+ const parsedNewInputValue = parseInt(inputValue, 10) || 0;
579
+ // Only apply format validation (not min/max constraints)
580
+ if (parsedNewInputValue >= maxMinutes) {
581
+ this.minutes = '00';
582
+ }
583
+ else {
584
+ // For direct input, remove unnecessary leading zeros (e.g., '01' becomes '1')
585
+ this.minutes = parsedNewInputValue.toString();
586
+ }
587
+ }
588
+ // Auto-navigation to next field when input is complete
589
+ if (this.minutes.length >= 1 && !this.inputZeroAdded[type]) {
590
+ const visibleTypes = getVisibleTimeTypes(this.format);
591
+ const currentTypeIndex = visibleTypes.indexOf(constants69bafca2.TimeType.Minutes);
592
+ const nextTypeIndex = currentTypeIndex + 1;
593
+ if (nextTypeIndex < visibleTypes.length) {
594
+ const nextType = visibleTypes[nextTypeIndex];
595
+ (_a = this.inputElements[nextType]) === null || _a === void 0 ? void 0 : _a.focus();
596
+ (_b = this.inputElements[nextType]) === null || _b === void 0 ? void 0 : _b.select();
597
+ }
598
+ }
599
+ }
600
+ handleSecondsChange(inputValue, type) {
601
+ const maxSeconds = 60;
602
+ // Handle empty input
603
+ if (inputValue.length === 0) {
604
+ this.seconds = '00';
605
+ return;
606
+ }
607
+ if (inputValue.length === 1) {
608
+ this.inputZeroAdded[type] = true;
609
+ const newInputValue = inputValue.padStart(2, '0');
610
+ this.seconds = newInputValue;
611
+ }
612
+ else if (this.inputZeroAdded[type]) {
613
+ this.inputZeroAdded[type] = false;
614
+ const newInputValue = inputValue.slice(1, 3).padStart(2, '0');
615
+ const parsedNewInputValue = parseInt(newInputValue, 10) || 0;
616
+ // Only apply format validation (not min/max constraints)
617
+ if (parsedNewInputValue >= maxSeconds) {
618
+ this.seconds = '00';
619
+ }
620
+ else {
621
+ this.seconds = newInputValue;
622
+ }
623
+ }
624
+ else if (inputValue.length > 2) {
625
+ const newInputValue = inputValue.slice(1, 3).padStart(2, '0');
626
+ const parsedNewInputValue = parseInt(newInputValue, 10) || 0;
627
+ // Only apply format validation (not min/max constraints)
628
+ if (parsedNewInputValue >= maxSeconds) {
629
+ this.seconds = '00';
630
+ }
631
+ else {
632
+ this.seconds = parsedNewInputValue.toString();
633
+ }
634
+ }
635
+ else {
636
+ const parsedNewInputValue = parseInt(inputValue, 10) || 0;
637
+ // Only apply format validation (not min/max constraints)
638
+ if (parsedNewInputValue >= maxSeconds) {
639
+ this.seconds = '00';
640
+ }
641
+ else {
642
+ // For direct input, remove unnecessary leading zeros (e.g., '01' becomes '1')
643
+ this.seconds = parsedNewInputValue.toString();
644
+ }
645
+ }
646
+ // No auto-navigation for seconds field as it's typically the last field
647
+ }
648
+ // Parse a time string according to the current format
649
+ parseTime(timeString) {
650
+ if (!timeString) {
651
+ return;
652
+ }
653
+ // Use format-aware parsing without constraint application
654
+ const components = parseValueByFormat(timeString, this.format);
655
+ // Set the parsed values without applying min/max constraints
656
+ this.hours = components.hours;
657
+ this.minutes = components.minutes;
658
+ this.seconds = components.seconds;
659
+ }
660
+ reconstructTime() {
661
+ const components = {
662
+ hours: this.hours,
663
+ minutes: this.minutes,
664
+ seconds: this.seconds,
665
+ };
666
+ // Ensure the reconstructed time is in the correct format
667
+ const reconstructedTime = reconstructTimeByFormat(components, this.format);
668
+ // Validate that the reconstructed time matches the expected format
669
+ if (!isValidFormatValue(reconstructedTime, this.format)) {
670
+ // If invalid, return the default value for this format
671
+ const config = FORMAT_CONFIGS[this.format];
672
+ return config ? config.defaultValue : reconstructedTime;
673
+ }
674
+ return reconstructedTime;
675
+ }
676
+ handleFocus(type) {
677
+ var _a, _b, _c, _d;
678
+ if (this.readonly || this.disabled) {
679
+ return;
680
+ }
681
+ // Check if this field is visible for the current format
682
+ const visibleTypes = getVisibleTimeTypes(this.format);
683
+ if (!visibleTypes.includes(type)) {
684
+ return; // Don't handle focus for non-visible fields
685
+ }
686
+ if (!this.open) {
687
+ this.open = true; // Force the popover to open
688
+ }
689
+ // Refocus on the input if it loses focus and is empty
690
+ if (((_a = this.inputElements[type]) === null || _a === void 0 ? void 0 : _a.value.length) === 0 ||
691
+ ((_b = this.inputElements[type]) === null || _b === void 0 ? void 0 : _b.value) === '00') {
692
+ (_c = this.inputElements[type]) === null || _c === void 0 ? void 0 : _c.focus();
693
+ (_d = this.inputElements[type]) === null || _d === void 0 ? void 0 : _d.select();
694
+ }
695
+ this.typeFocused = type;
696
+ }
697
+ HandleDropdownIconClick() {
698
+ var _a, _b;
699
+ if (this.disabled || this.readonly) {
700
+ return; // Do not toggle if disabled or read-only
701
+ }
702
+ const visibleTypes = getVisibleTimeTypes(this.format);
703
+ const firstVisibleType = visibleTypes[0];
704
+ if (this.open) {
705
+ this.open = false; // Close the popover if it is open
706
+ }
707
+ else if (!this.open &&
708
+ firstVisibleType &&
709
+ this.inputElements[firstVisibleType]) {
710
+ (_a = this.inputElements[firstVisibleType]) === null || _a === void 0 ? void 0 : _a.focus(); // Focus will open the popover
711
+ (_b = this.inputElements[firstVisibleType]) === null || _b === void 0 ? void 0 : _b.select();
712
+ }
713
+ else {
714
+ console.warn('nv-fieldtime -> No visible input elements found to focus');
715
+ }
716
+ }
717
+ updateHighlightedItem(items, index) {
718
+ items.forEach((item, i) => {
719
+ if (i === index) {
720
+ item.classList.add('highlighted');
721
+ item.setAttribute('tabindex', '0');
722
+ item.focus(); // Forcer le focus ici
723
+ item.scrollIntoView({ block: 'nearest' });
724
+ }
725
+ else {
726
+ item.classList.remove('highlighted');
727
+ item.setAttribute('tabindex', '-1');
728
+ }
729
+ });
730
+ }
731
+ handleTimeOptionClick(event, type) {
732
+ const option = parseInt(event.target.textContent || '0', 10);
733
+ // Update the time component directly without constraint validation
734
+ // Dropdown options are already filtered by constraints during generation
735
+ if (type === constants69bafca2.TimeType.Hours) {
736
+ this.hours = option.toString().padStart(2, '0');
737
+ }
738
+ else if (type === constants69bafca2.TimeType.Minutes) {
739
+ this.minutes = option.toString().padStart(2, '0');
740
+ }
741
+ else if (type === constants69bafca2.TimeType.Seconds) {
742
+ this.seconds = option.toString().padStart(2, '0');
743
+ }
744
+ // Reconstruct time in the correct format and update value
745
+ const reconstructedTime = this.reconstructTime();
746
+ this.value = reconstructedTime;
747
+ }
748
+ handleInputBlur() {
749
+ // Use a delay to check if the focus is still within the popover
750
+ setTimeout(() => {
751
+ if (!this.el.contains(document.activeElement)) {
752
+ if (this.open) {
753
+ this.open = false; // Close the popover if the focus is outside the component
754
+ }
755
+ }
756
+ }, 150);
757
+ }
758
+ handleClickOutside(event) {
759
+ const target = event.target;
760
+ // Check if the click is inside the component or any of the input elements
761
+ if (this.el.contains(target) ||
762
+ Object.values(this.inputElements).some(input => input.contains(target))) {
763
+ return;
764
+ }
765
+ if (this.open) {
766
+ this.open = false; // Close the popover if the click is outside
767
+ }
768
+ }
769
+ handleScroll(e, type) {
770
+ const target = e.target;
771
+ const scrollTop = target.scrollTop;
772
+ const containerHeight = target.clientHeight;
773
+ const scrollHeight = target.scrollHeight;
774
+ // Define the height of each item, this could be dynamic if the height varies
775
+ const itemHeight = 40; // Consider making this configurable or dynamic
776
+ const options = this.generateTimeOptions(type); // Generates the list of time options
777
+ const singleSetHeight = options.length * itemHeight;
778
+ // Check if the scroll is near the bottom or top and reset to the first set
779
+ if (scrollTop + containerHeight >= scrollHeight - itemHeight ||
780
+ scrollTop <= 0) {
781
+ target.scrollTop = singleSetHeight; // Reset to the first set from the bottom
782
+ }
783
+ }
784
+ generateTimeOptions(type) {
785
+ // Convert the step in seconds
786
+ const stepInSeconds = this.step / 1000;
787
+ // Handle edge case for zero step
788
+ if (stepInSeconds === 0) {
789
+ return ['00']; // Just return the default value
790
+ }
791
+ // Generate the time options based on the type
792
+ switch (type) {
793
+ case constants69bafca2.TimeType.Hours:
794
+ return this.generateHourOptions(stepInSeconds);
795
+ case constants69bafca2.TimeType.Minutes:
796
+ return this.generateMinuteOptions(stepInSeconds);
797
+ case constants69bafca2.TimeType.Seconds:
798
+ return this.generateSecondOptions(stepInSeconds);
799
+ default:
800
+ return [];
801
+ }
802
+ }
803
+ generateHourOptions(stepInSeconds) {
804
+ const hourStep = Math.max(1, Math.floor(stepInSeconds / 3600)); // Prevent step < 1
805
+ const is12HourFormat = this.format.startsWith('hh');
806
+ // Set proper hour ranges based on format
807
+ const defaultMaxHour = is12HourFormat ? 12 : 23;
808
+ const defaultMinHour = is12HourFormat ? 1 : 0;
809
+ const maxHour = this.parseHour(this.max, this.format);
810
+ const minHour = this.parseHour(this.min, this.format);
811
+ const maxHourValue = maxHour ? parseInt(maxHour, 10) : defaultMaxHour;
812
+ const minHourValue = minHour ? parseInt(minHour, 10) : defaultMinHour;
813
+ const values = [];
814
+ for (let i = minHourValue; i <= maxHourValue; i += hourStep) {
815
+ const hourStr = i.toString().padStart(2, '0');
816
+ values.push(hourStr);
817
+ }
818
+ return values;
819
+ }
820
+ /**
821
+ * Parse hour value from min/max constraint strings for dropdown generation only.
822
+ * This method is used exclusively for filtering dropdown options and should not
823
+ * affect input values or validation.
824
+ * @param {string} value - The time string to parse (e.g., "14:30" or "02:30")
825
+ * @param {string} format - The time format string (e.g., "HH:mm" or "hh:mm")
826
+ * @returns {string} The parsed hour string or null if invalid
827
+ */
828
+ parseHour(value, format) {
829
+ if (!value)
830
+ return null;
831
+ const [hourStr] = value.split(':');
832
+ const hour = parseInt(hourStr, 10);
833
+ if (isNaN(hour))
834
+ return null;
835
+ if (format.startsWith('hh'))
836
+ return hour > 0 && hour <= 12 ? hourStr.padStart(2, '0') : null;
837
+ return hour >= 0 && hour <= 24 ? hourStr.padStart(2, '0') : null;
838
+ }
839
+ generateMinuteOptions(stepInSeconds) {
840
+ var _a, _b;
841
+ const minuteStep = Math.max(1, Math.floor((stepInSeconds % 3600) / 60)); // Ensure step >= 1
842
+ const minMinute = (_a = this.parseMinute(this.min)) !== null && _a !== void 0 ? _a : 0;
843
+ const maxMinute = (_b = this.parseMinute(this.max)) !== null && _b !== void 0 ? _b : 59;
844
+ if (minMinute === 0 && maxMinute === 0)
845
+ return ['00']; // Handle edge case for zero minutes
846
+ const values = [];
847
+ for (let i = minMinute; i <= maxMinute; i += minuteStep) {
848
+ const minuteStr = i.toString().padStart(2, '0');
849
+ values.push(minuteStr);
850
+ }
851
+ return values;
852
+ }
853
+ /**
854
+ * Parse minute value from min/max constraint strings for dropdown generation only.
855
+ * This method is used exclusively for filtering dropdown options and should not
856
+ * affect input values or validation.
857
+ * @param {string} value - The time string to parse (e.g., "14:30" or "02:30")
858
+ * @returns {number} The parsed minute number or null if invalid
859
+ */
860
+ parseMinute(value) {
861
+ if (!value)
862
+ return null;
863
+ const parts = value.split(':');
864
+ if (parts.length < 2)
865
+ return null; // Expect at least "hh:mm"
866
+ const minute = parseInt(parts[1], 10);
867
+ return isNaN(minute) || minute < 0 || minute >= 60 ? null : minute;
868
+ }
869
+ generateSecondOptions(stepInSeconds) {
870
+ var _a, _b;
871
+ const secondStep = Math.max(1, stepInSeconds % 60); // Ensure step >= 1
872
+ const minSecond = (_a = this.parseSecond(this.min)) !== null && _a !== void 0 ? _a : 0;
873
+ const maxSecond = (_b = this.parseSecond(this.max)) !== null && _b !== void 0 ? _b : 59;
874
+ if (minSecond === 0 && maxSecond === 0)
875
+ return ['00']; // Handle edge case for zero seconds
876
+ const values = [];
877
+ for (let i = minSecond; i <= maxSecond; i += secondStep) {
878
+ const secondStr = i.toString().padStart(2, '0');
879
+ values.push(secondStr);
880
+ }
881
+ return values;
882
+ }
883
+ /**
884
+ * Parse second value from min/max constraint strings for dropdown generation only.
885
+ * This method is used exclusively for filtering dropdown options and should not
886
+ * affect input values or validation.
887
+ * @param {string} value - The time string to parse (e.g., "14:30:45" or "02:30:45")
888
+ * @returns {number} The parsed second number or null if invalid
889
+ */
890
+ parseSecond(value) {
891
+ if (!value)
892
+ return null;
893
+ const parts = value.split(':');
894
+ if (parts.length < 3)
895
+ return null; // Expect "hh:mm:ss" or "HH:mm:ss"
896
+ const second = parseInt(parts[2], 10);
897
+ return isNaN(second) || second < 0 || second >= 60 ? null : second;
898
+ }
899
+ generateInfiniteTimeOptions(type) {
900
+ const options = this.generateTimeOptions(type);
901
+ const totalOptions = options.length;
902
+ // Dynamically calculate repetitions based on a target number of items (e.g., 300 items)
903
+ const repetitions = Math.ceil(300 / totalOptions);
904
+ return Array(repetitions).fill(options).flat();
905
+ }
906
+ updateColumnHighlight(selector, value) {
907
+ const items = Array.from(this.el.querySelectorAll(selector));
908
+ const index = items.findIndex(x => x.textContent === value);
909
+ this.updateHighlightedItem(items, index);
910
+ }
911
+ handleHostClick(event) {
912
+ var _a, _b;
913
+ if (this.disabled || this.readonly) {
914
+ return;
915
+ }
916
+ const targetElement = event.target;
917
+ // Check if the click target or its ancestors are inside an nv-iconbutton element
918
+ if (targetElement.closest('nv-iconbutton')) {
919
+ return; // Handle icon button click separately
920
+ }
921
+ if (!this.open) {
922
+ if (this.inputElements) {
923
+ // Focus on the first visible field based on format
924
+ const visibleTypes = getVisibleTimeTypes(this.format);
925
+ const firstVisibleType = visibleTypes[0];
926
+ if (firstVisibleType && this.inputElements[firstVisibleType]) {
927
+ (_a = this.inputElements[firstVisibleType]) === null || _a === void 0 ? void 0 : _a.focus();
928
+ (_b = this.inputElements[firstVisibleType]) === null || _b === void 0 ? void 0 : _b.select();
929
+ }
930
+ }
931
+ event.preventDefault();
932
+ }
933
+ }
934
+ //#endregion METHODS
935
+ /****************************************************************************/
936
+ //#region LIFECYCLE
937
+ componentWillLoad() {
938
+ document.addEventListener('click', this.handleClickOutside.bind(this));
939
+ // Initialize component state based on format and value
940
+ if (this.value) {
941
+ // Parse the provided value using format-aware parsing without constraint application
942
+ this.parseTime(this.value);
943
+ }
944
+ else {
945
+ // Initialize with format-appropriate default values without any constraint application
946
+ // Use format-specific defaults: '01' for 12-hour formats, '00' for 24-hour formats
947
+ const defaultComponents = parseValueByFormat('', this.format);
948
+ // Set default values directly without any min/max constraint validation
949
+ this.hours = defaultComponents.hours;
950
+ this.minutes = defaultComponents.minutes;
951
+ this.seconds = defaultComponents.seconds;
952
+ // Set the initial value in the correct format without constraint validation
953
+ // This ensures the component has a proper initial state for the value watcher
954
+ const initialValue = reconstructTimeByFormat(defaultComponents, this.format);
955
+ this.value = initialValue;
956
+ }
957
+ }
958
+ connectedCallback() {
959
+ document.addEventListener('click', this.handleClickOutside.bind(this));
960
+ }
961
+ disconnectedCallback() {
962
+ document.removeEventListener('click', this.handleClickOutside.bind(this));
963
+ }
964
+ componentDidLoad() {
965
+ // Initialize dropdown highlighting based on current component state
966
+ // This ensures proper visual feedback without applying any constraints
967
+ // Update highlighted items for hours based on current state
968
+ const hourSelector = `.time-column.time-column-hours div`;
969
+ this.updateColumnHighlight(hourSelector, this.hours);
970
+ // Update highlighted items for minutes based on current state
971
+ const minuteSelector = `.time-column.time-column-minutes div`;
972
+ this.updateColumnHighlight(minuteSelector, this.minutes);
973
+ // Update highlighted items for seconds based on current state
974
+ const secondSelector = `.time-column.time-column-seconds div`;
975
+ this.updateColumnHighlight(secondSelector, this.seconds);
976
+ }
977
+ //#endregion LIFECYCLE
978
+ /****************************************************************************/
979
+ //#region RENDER
980
+ /**
981
+ * Renders input fields based on the current format
982
+ * Only shows fields that are relevant to the selected format
983
+ * @returns {HTMLElement[]} Array of HTML elements for time input fields
984
+ */
985
+ renderTimeInputFields() {
986
+ const visibleTypes = getVisibleTimeTypes(this.format);
987
+ const elements = [];
988
+ visibleTypes.forEach((type, index$1) => {
989
+ // Add separator colon before minutes and seconds (but not before the first field)
990
+ if (index$1 > 0) {
991
+ elements.push(index.h("span", null, ":"));
992
+ }
993
+ // Add the input field for this time type
994
+ elements.push(this.renderTimeInputField(type));
995
+ });
996
+ return elements;
997
+ }
998
+ /**
999
+ * Renders a single time input field for the specified type
1000
+ * @param {TimeType} type - The time type to render input for
1001
+ * @returns {HTMLInputElement} HTML input element for the specified time type
1002
+ */
1003
+ renderTimeInputField(type) {
1004
+ const getValue = () => {
1005
+ switch (type) {
1006
+ case constants69bafca2.TimeType.Hours:
1007
+ return this.hours;
1008
+ case constants69bafca2.TimeType.Minutes:
1009
+ return this.minutes;
1010
+ case constants69bafca2.TimeType.Seconds:
1011
+ return this.seconds;
1012
+ default:
1013
+ return '00';
1014
+ }
1015
+ };
1016
+ const getPlaceholder = () => {
1017
+ switch (type) {
1018
+ case constants69bafca2.TimeType.Hours:
1019
+ return this.format.includes('hh') ? 'hh' : 'HH';
1020
+ case constants69bafca2.TimeType.Minutes:
1021
+ return 'mm';
1022
+ case constants69bafca2.TimeType.Seconds:
1023
+ return 'ss';
1024
+ default:
1025
+ return '';
1026
+ }
1027
+ };
1028
+ const getId = () => {
1029
+ switch (type) {
1030
+ case constants69bafca2.TimeType.Hours:
1031
+ return this.inputId;
1032
+ case constants69bafca2.TimeType.Minutes:
1033
+ return `${this.inputId}-minutes`;
1034
+ case constants69bafca2.TimeType.Seconds:
1035
+ return `${this.inputId}-seconds`;
1036
+ default:
1037
+ return this.inputId;
1038
+ }
1039
+ };
1040
+ // Remove min/max constraints from input elements to allow native stepper behavior
1041
+ // Constraints are only applied to dropdown options, not input steppers
1042
+ return (index.h("input", { ref: el => (this.inputElements[type] = el), type: "number", autofocus: this.autofocus && type === getVisibleTimeTypes(this.format)[0], class: "time-input", pattern: "[0-9]*", maxlength: "3", value: getValue(), onInput: e => this.handleInputChange(e, type), placeholder: getPlaceholder(), inputMode: "numeric", onFocus: () => this.handleFocus(type), name: this.name ? `${type}-${this.name}` : type, id: getId(), readonly: this.readonly, disabled: this.disabled, required: this.required, onKeyDown: e => this.handleKeyDown(e), onBlur: () => this.handleInputBlur() }));
1043
+ }
1044
+ /**
1045
+ * Renders dropdown columns based on the current format
1046
+ * Only shows columns that are relevant to the selected format
1047
+ * @returns {HTMLElement[]} Array of HTML elements for time dropdown columns
1048
+ */
1049
+ renderTimeDropdownColumns() {
1050
+ const visibleTypes = getVisibleTimeTypes(this.format);
1051
+ return visibleTypes.map(type => this.RenderTimeOptionsColumn(type));
1052
+ }
1053
+ RenderTimeOptionsColumn(type) {
1054
+ return (index.h("div", { class: `time-column time-column-${type}`, onScroll: e => this.handleScroll(e, type) }, this.generateInfiniteTimeOptions(type).map((option, index$1) => (index.h("div", { class: {
1055
+ 'time-option': true,
1056
+ 'selected': (type === constants69bafca2.TimeType.Hours && option === this.hours) ||
1057
+ (type === constants69bafca2.TimeType.Minutes && option === this.minutes) ||
1058
+ (type === constants69bafca2.TimeType.Seconds && option === this.seconds),
1059
+ }, key: `${option}-${index$1}`, onClick: e => this.handleTimeOptionClick(e, type) }, option)))));
1060
+ }
1061
+ render() {
1062
+ return (index.h(index.Host, { key: '315b0a732c1ef8bee7aaa0141ce533ec265e35ab', onclick: (e) => this.handleHostClick(e), "aria-expanded": this.open ? 'true' : 'false' }, (this.label || this.el.querySelector('[slot="label"]')) && (index.h("label", { key: '100b75accd50c277e3ddd13c007e55dad8c6f8b7', htmlFor: this.inputId }, index.h("slot", { key: 'cec67688f98fc7976299a2f55ba8ba859e4ecacc', name: "label" }, this.label))), index.h("nv-popover", { key: 'feaaefb107251368db809babb02b8f8c7cb7baf0', ref: el => (this.popoverElement = el), triggerMode: "controlled", placement: "bottom-start", open: this.open }, index.h("div", { key: 'c539917597eebdd92bb2e832d1fd9d6afceb5c04', class: "input-wrapper", slot: "trigger" }, index.h("slot", { key: '5a869349e9fd7a422d596f5bd05402d5559a6f2b', name: "before-input" }), index.h("div", { key: '27dac6987b28d08bb54b9ffc70ddade28f527a9c', class: "input-container" }, index.h("slot", { key: '9df638bb3d58df138a360966925b04092f1d4b9a', name: "leading-input" }), this.renderTimeInputFields(), index.h("nv-iconbutton", { key: '8d6796d9fc57ef2a934bfe79621ff76def8e9507', name: 'clock', size: "md", emphasis: "lower", "aria-label": this.open ? 'Hide time picker' : 'Show time picker', onClick: () => this.HandleDropdownIconClick() }), this.error && (index.h("nv-icon", { key: '15b593ce4e850d18a5f5f93120ae84e84054cffe', name: "alert-circle", class: "validation", size: "sm" })), this.success && (index.h("nv-icon", { key: '85e4a38c3ef64552fc7a47448471d4276ee5cc46', name: "circle-check", class: "validation", size: "sm" }))), index.h("slot", { key: '45cc1c26bc40425df62382a371ab658dd18aefa8', name: "after-input" })), index.h("div", { key: '23432dd354491420e42400d9eeb22bc23e36623e', class: "time-dropdown", slot: "content" }, index.h("div", { key: 'efb53556077c85ee94a8fe345a03d67a3e36cdc1', class: "time-columns" }, this.renderTimeDropdownColumns()))), (this.description ||
1063
+ this.el.querySelector('[slot="description"]')) && (index.h("div", { key: '735447b328a8264739d3185ce6c65d48a01ec801', class: "description" }, index.h("slot", { key: '86387e48804b2ac1842c64b4cf4f5ca9f34a6719', name: "description" }, this.description))), (this.errorDescription ||
1064
+ this.el.querySelector('[slot="error-description"]')) && (index.h("div", { key: 'b6cc406c6a872b5ebb83a35a84852e143781e12f', hidden: !this.error, class: "error-description" }, index.h("slot", { key: 'c9dc284e202b081a61346796d21e73c8647c7daa', name: "error-description" }, this.errorDescription)))));
1065
+ }
1066
+ static get formAssociated() { return true; }
1067
+ get el() { return index.getElement(this); }
1068
+ static get watchers() { return {
1069
+ "value": ["handleValueChange"],
1070
+ "open": ["handleOpenChange"],
1071
+ "format": ["handleFormatChange"]
1072
+ }; }
1073
+ };
1074
+ NvFieldtime.style = NvFieldtimeStyle0;
1075
+
1076
+ exports.nv_fieldtime = NvFieldtime;