@nova-design-system/nova-react 3.18.0-beta.0 → 3.19.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 (54) hide show
  1. package/dist/cjs/generated/components.server.js +4 -2
  2. package/dist/cjs/{index-CQAMJPJk.js → index-C12eD0Qt.js} +886 -831
  3. package/dist/cjs/index.js +1 -1
  4. package/dist/cjs/{nv-accordion-item.entry-BQ4e6YBV.js → nv-accordion-item.entry-99OJUl7m.js} +1 -1
  5. package/dist/cjs/{nv-accordion.entry-BX5L-Gh7.js → nv-accordion.entry-D8jaknF9.js} +1 -1
  6. package/dist/cjs/{nv-alert.entry-GY7Xn7F6.js → nv-alert.entry-D_uvQxc9.js} +1 -1
  7. package/dist/cjs/{nv-avatar.entry-j-ctCQEi.js → nv-avatar.entry-B2zfDM3w.js} +1 -1
  8. package/dist/cjs/{nv-badge_2.entry-tuEGBPUn.js → nv-badge_2.entry-Fnq2K2Ul.js} +2 -2
  9. package/dist/cjs/{nv-breadcrumb.entry-DHZpC_e3.js → nv-breadcrumb.entry-CEN2iYUQ.js} +1 -1
  10. package/dist/cjs/{nv-breadcrumbs.entry-2tzS_xzO.js → nv-breadcrumbs.entry-Bq8qINNk.js} +1 -1
  11. package/dist/cjs/{nv-button.entry-BfV4ewn0.js → nv-button.entry-CmpagMPP.js} +1 -1
  12. package/dist/cjs/{nv-buttongroup.entry-BBTtBLTw.js → nv-buttongroup.entry-CbTXVSWL.js} +1 -1
  13. package/dist/cjs/{nv-calendar.entry-CTkbvFRZ.js → nv-calendar.entry-DNkXS4ll.js} +1 -1
  14. package/dist/cjs/{nv-col.entry-CsSk4Ltj.js → nv-col.entry-Dlrdqper.js} +1 -1
  15. package/dist/cjs/{nv-datagrid.entry-DlQRC5CG.js → nv-datagrid.entry-Z5GHfOvp.js} +1 -1
  16. package/dist/cjs/{nv-datagridcolumn.entry-BxSumv4Q.js → nv-datagridcolumn.entry-DvSFVguN.js} +1 -1
  17. package/dist/cjs/{nv-dialog.entry-BFeHCAhr.js → nv-dialog.entry-BV6QBtx2.js} +1 -1
  18. package/dist/cjs/{nv-dialogfooter_2.entry-CXOzxujX.js → nv-dialogfooter_2.entry-Ci1C_E-2.js} +1 -1
  19. package/dist/cjs/{nv-fieldcheckbox.entry-BMq7p1kc.js → nv-fieldcheckbox.entry-BD9ETFVV.js} +1 -1
  20. package/dist/cjs/{nv-fielddate.entry-DmMQq5bO.js → nv-fielddate.entry-C06n2Hri.js} +11 -7
  21. package/dist/cjs/{nv-fielddaterange.entry-BJm7_qAB.js → nv-fielddaterange.entry-DFlaA4gv.js} +12 -8
  22. package/dist/cjs/{nv-fielddropdown.entry-DOkzDn78.js → nv-fielddropdown.entry-ONwdJHOm.js} +194 -210
  23. package/dist/cjs/{nv-fielddropdownitem.entry-CVI8jUn4.js → nv-fielddropdownitem.entry-CDKQtEra.js} +8 -5
  24. package/dist/cjs/{nv-fieldmultiselect.entry-CWxL0xsk.js → nv-fieldmultiselect.entry-BHJC59Mw.js} +5 -1
  25. package/dist/cjs/{nv-fieldnumber.entry-bReRT-TF.js → nv-fieldnumber.entry-CmL1LPom.js} +4 -4
  26. package/dist/cjs/{nv-fieldpassword.entry-BprEVABM.js → nv-fieldpassword.entry-Bqbf_LJJ.js} +4 -4
  27. package/dist/cjs/{nv-fieldradio.entry-T_uuPP7m.js → nv-fieldradio.entry-RzSCysif.js} +4 -4
  28. package/dist/cjs/{nv-fieldselect.entry-DB9YREaD.js → nv-fieldselect.entry-COTE8Ntn.js} +6 -6
  29. package/dist/cjs/{nv-fieldslider.entry-Bkj5p8jp.js → nv-fieldslider.entry-BVfmpUhc.js} +4 -4
  30. package/dist/cjs/{nv-fieldtext.entry-BsUZW21W.js → nv-fieldtext.entry-DO0lmw9C.js} +4 -4
  31. package/dist/cjs/{nv-fieldtextarea.entry-DtC4sL4g.js → nv-fieldtextarea.entry-CzVq8gjw.js} +4 -4
  32. package/dist/cjs/nv-fieldtime.entry-CRNYbeMY.js +1077 -0
  33. package/dist/cjs/nv-icon.entry-FoRJzCHm.js +80 -0
  34. package/dist/cjs/{nv-iconbutton_2.entry-DI-3_IYV.js → nv-iconbutton_2.entry-0lnnCk0B.js} +3 -3
  35. package/dist/cjs/{nv-menu.entry-BbqP7TZx.js → nv-menu.entry-BjXa70qP.js} +3 -3
  36. package/dist/cjs/{nv-menuitem.entry-BxGppIvW.js → nv-menuitem.entry-CSPwpUWz.js} +2 -2
  37. package/dist/cjs/{nv-notification.entry-D1gy3PSV.js → nv-notification.entry-BYHTrzUz.js} +2 -2
  38. package/dist/cjs/{nv-notificationcontainer.entry-MJPLFXsR.js → nv-notificationcontainer.entry-BBjrL7gt.js} +2 -2
  39. package/dist/cjs/{nv-popover.entry-CL28RbQ0.js → nv-popover.entry-J_M8_rLL.js} +3 -3
  40. package/dist/cjs/{nv-row.entry-DkCe2B9f.js → nv-row.entry-CmOypCPp.js} +2 -2
  41. package/dist/cjs/{nv-split.entry-BMVNZDwj.js → nv-split.entry-BqBytQZn.js} +2 -2
  42. package/dist/cjs/{nv-stack.entry-iH3La5O3.js → nv-stack.entry-BKPf62wy.js} +2 -2
  43. package/dist/cjs/{nv-table.entry-DFHkpLLG.js → nv-table.entry-DSL_jd5Y.js} +2 -2
  44. package/dist/cjs/{nv-toggle.entry-BM2Xdtvg.js → nv-toggle.entry-DbQQdp5m.js} +3 -3
  45. package/dist/cjs/{nv-togglebutton.entry-DPu3j4uH.js → nv-togglebutton.entry-DNG6SFTU.js} +2 -2
  46. package/dist/cjs/{nv-togglebuttongroup.entry-BBUI9mSK.js → nv-togglebuttongroup.entry-Bl43CVZN.js} +2 -2
  47. package/dist/cjs/{nv-tooltip.entry-CEynYna7.js → nv-tooltip.entry-CV841nfI.js} +2 -2
  48. package/dist/generated/components.js +2 -0
  49. package/dist/generated/components.server.js +4 -2
  50. package/dist/types/generated/components.d.ts +3 -0
  51. package/dist/types/generated/components.server.d.ts +3 -0
  52. package/package.json +1 -1
  53. package/dist/cjs/nv-fieldtime.entry-BW8nABK-.js +0 -1028
  54. package/dist/cjs/nv-icon.entry-BFTi5BIN.js +0 -80
@@ -0,0 +1,1077 @@
1
+ 'use strict';
2
+
3
+ var index = require('./index-C12eD0Qt.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
+ this.open = false;
389
+ }
390
+ }
391
+ //#endregion LISTENERS
392
+ /****************************************************************************/
393
+ //#region WATCHERS
394
+ handleValueChange(newValue) {
395
+ // Parse the new value and ensure it's in the correct format
396
+ if (newValue) {
397
+ const components = parseValueByFormat(newValue, this.format);
398
+ const formattedValue = reconstructTimeByFormat(components, this.format);
399
+ // Only emit if the formatted value is different from what we received
400
+ // This prevents infinite loops while ensuring format consistency
401
+ if (formattedValue !== newValue) {
402
+ this.value = formattedValue;
403
+ return; // The watcher will be called again with the formatted value
404
+ }
405
+ }
406
+ // Emit the value in the correct format
407
+ this.valueChanged.emit(newValue);
408
+ }
409
+ handleOpenChange(newOpen) {
410
+ // React to external changes, e.g., highlight current time on open
411
+ if (newOpen) {
412
+ // Re-highlight columns based on current value
413
+ const hourSelector = `.time-column.time-column-${constants69bafca2.TimeType.Hours} div`;
414
+ this.updateColumnHighlight(hourSelector, this.hours);
415
+ const minutesSelector = `.time-column.time-column-${constants69bafca2.TimeType.Minutes} div`;
416
+ this.updateColumnHighlight(minutesSelector, this.minutes);
417
+ const secondsSelector = `.time-column.time-column-${constants69bafca2.TimeType.Seconds} div`;
418
+ this.updateColumnHighlight(secondsSelector, this.seconds);
419
+ }
420
+ }
421
+ handleFormatChange(newFormat, oldFormat) {
422
+ if (newFormat === oldFormat) {
423
+ return; // No change, nothing to do
424
+ }
425
+ // Re-parse the current value with the new format
426
+ const currentValue = this.value || this.reconstructTime();
427
+ // Parse the current value using the old format to get the time components
428
+ const components = parseValueByFormat(currentValue, oldFormat || 'HH:mm:ss');
429
+ // Update the component state with the parsed components
430
+ this.hours = components.hours;
431
+ this.minutes = components.minutes;
432
+ this.seconds = components.seconds;
433
+ // Reconstruct the time value in the new format
434
+ const newValue = reconstructTimeByFormat(components, newFormat);
435
+ // Update the value, which will trigger the value watcher and emit the event
436
+ this.value = newValue;
437
+ // Force a re-render to update the visible input fields
438
+ index.forceUpdate(this.el);
439
+ }
440
+ //#endregion WATCHERS
441
+ /****************************************************************************/
442
+ //#region METHODS
443
+ handleInputChange(e, type) {
444
+ const inputElement = e.target;
445
+ const inputValue = inputElement.value.replace(/[^0-9]/g, ''); // Only keep numeric input
446
+ // Check if this field is visible for the current format
447
+ const visibleTypes = getVisibleTimeTypes(this.format);
448
+ if (!visibleTypes.includes(type)) {
449
+ return; // Don't process input for non-visible fields
450
+ }
451
+ // Update the time value based on the type
452
+ switch (type) {
453
+ case constants69bafca2.TimeType.Hours:
454
+ this.handleHoursChange(inputValue, type);
455
+ break;
456
+ case constants69bafca2.TimeType.Minutes:
457
+ this.handleMinutesChange(inputValue, type);
458
+ break;
459
+ case constants69bafca2.TimeType.Seconds:
460
+ this.handleSecondsChange(inputValue, type);
461
+ break;
462
+ }
463
+ // Reconstruct time from inputs in the correct format
464
+ const reconstructedValue = this.reconstructTime();
465
+ // Update the value, which will trigger the watcher and emit the event
466
+ this.value = reconstructedValue;
467
+ }
468
+ handleHoursChange(inputValue, type) {
469
+ var _a, _b;
470
+ const isHHFormat = this.format.startsWith('HH');
471
+ const maxHours = isHHFormat ? 24 : 12;
472
+ // Handle empty input
473
+ if (inputValue.length === 0) {
474
+ this.hours = '00';
475
+ return;
476
+ }
477
+ if (inputValue.length === 1) {
478
+ this.inputZeroAdded[type] = true;
479
+ const newInputValue = inputValue.padStart(2, '0');
480
+ this.hours = newInputValue;
481
+ }
482
+ else if (this.inputZeroAdded[type]) {
483
+ this.inputZeroAdded[type] = false;
484
+ const newInputValue = inputValue.slice(1, 3).padStart(2, '0');
485
+ const parsedNewInputValue = parseInt(newInputValue, 10) || 0;
486
+ // Only apply format validation (not min/max constraints)
487
+ if (parsedNewInputValue >= maxHours) {
488
+ this.hours = '00';
489
+ }
490
+ else {
491
+ this.hours = newInputValue;
492
+ }
493
+ }
494
+ else if (inputValue.length > 2) {
495
+ if (inputValue.startsWith('00')) {
496
+ this.inputZeroAdded[type] = true;
497
+ const newInputValue = inputValue.slice(1, 3).padStart(2, '0');
498
+ this.hours = newInputValue;
499
+ }
500
+ else {
501
+ const newInputValue = inputValue.slice(1, 3).padStart(2, '0');
502
+ const parsedNewInputValue = parseInt(newInputValue, 10) || 0;
503
+ // Only apply format validation (not min/max constraints)
504
+ if (parsedNewInputValue >= maxHours) {
505
+ this.hours = '00';
506
+ }
507
+ else {
508
+ this.hours = parsedNewInputValue.toString();
509
+ }
510
+ }
511
+ }
512
+ else {
513
+ const parsedNewInputValue = parseInt(inputValue, 10) || 0;
514
+ // Only apply format validation (not min/max constraints)
515
+ if (parsedNewInputValue >= maxHours) {
516
+ this.hours = '00';
517
+ }
518
+ else {
519
+ // For direct input, remove unnecessary leading zeros (e.g., '01' becomes '1')
520
+ this.hours = parsedNewInputValue.toString();
521
+ }
522
+ }
523
+ // Auto-navigation to next field when input is complete
524
+ if (this.hours.length >= 1 && !this.inputZeroAdded[type]) {
525
+ const visibleTypes = getVisibleTimeTypes(this.format);
526
+ const currentTypeIndex = visibleTypes.indexOf(constants69bafca2.TimeType.Hours);
527
+ const nextTypeIndex = currentTypeIndex + 1;
528
+ if (nextTypeIndex < visibleTypes.length) {
529
+ const nextType = visibleTypes[nextTypeIndex];
530
+ (_a = this.inputElements[nextType]) === null || _a === void 0 ? void 0 : _a.focus();
531
+ (_b = this.inputElements[nextType]) === null || _b === void 0 ? void 0 : _b.select();
532
+ }
533
+ }
534
+ }
535
+ handleMinutesChange(inputValue, type) {
536
+ var _a, _b;
537
+ const maxMinutes = 60;
538
+ // Handle empty input
539
+ if (inputValue.length === 0) {
540
+ this.minutes = '00';
541
+ return;
542
+ }
543
+ if (inputValue.length === 1) {
544
+ this.inputZeroAdded[type] = true;
545
+ const newInputValue = inputValue.padStart(2, '0');
546
+ this.minutes = newInputValue;
547
+ }
548
+ else if (this.inputZeroAdded[type]) {
549
+ this.inputZeroAdded[type] = false;
550
+ const newInputValue = inputValue.slice(1, 3).padStart(2, '0');
551
+ const parsedNewInputValue = parseInt(newInputValue, 10) || 0;
552
+ // Only apply format validation (not min/max constraints)
553
+ if (parsedNewInputValue >= maxMinutes) {
554
+ this.minutes = '00';
555
+ }
556
+ else {
557
+ this.minutes = newInputValue;
558
+ }
559
+ }
560
+ else if (inputValue.length > 2) {
561
+ if (inputValue.startsWith('00')) {
562
+ this.inputZeroAdded[type] = true;
563
+ const newInputValue = inputValue.slice(1, 3).padStart(2, '0');
564
+ this.minutes = newInputValue;
565
+ }
566
+ else {
567
+ const newInputValue = inputValue.slice(1, 3).padStart(2, '0');
568
+ const parsedNewInputValue = parseInt(newInputValue, 10) || 0;
569
+ // Only apply format validation (not min/max constraints)
570
+ if (parsedNewInputValue >= maxMinutes) {
571
+ this.minutes = '00';
572
+ }
573
+ else {
574
+ this.minutes = parsedNewInputValue.toString();
575
+ }
576
+ }
577
+ }
578
+ else {
579
+ const parsedNewInputValue = parseInt(inputValue, 10) || 0;
580
+ // Only apply format validation (not min/max constraints)
581
+ if (parsedNewInputValue >= maxMinutes) {
582
+ this.minutes = '00';
583
+ }
584
+ else {
585
+ // For direct input, remove unnecessary leading zeros (e.g., '01' becomes '1')
586
+ this.minutes = parsedNewInputValue.toString();
587
+ }
588
+ }
589
+ // Auto-navigation to next field when input is complete
590
+ if (this.minutes.length >= 1 && !this.inputZeroAdded[type]) {
591
+ const visibleTypes = getVisibleTimeTypes(this.format);
592
+ const currentTypeIndex = visibleTypes.indexOf(constants69bafca2.TimeType.Minutes);
593
+ const nextTypeIndex = currentTypeIndex + 1;
594
+ if (nextTypeIndex < visibleTypes.length) {
595
+ const nextType = visibleTypes[nextTypeIndex];
596
+ (_a = this.inputElements[nextType]) === null || _a === void 0 ? void 0 : _a.focus();
597
+ (_b = this.inputElements[nextType]) === null || _b === void 0 ? void 0 : _b.select();
598
+ }
599
+ }
600
+ }
601
+ handleSecondsChange(inputValue, type) {
602
+ const maxSeconds = 60;
603
+ // Handle empty input
604
+ if (inputValue.length === 0) {
605
+ this.seconds = '00';
606
+ return;
607
+ }
608
+ if (inputValue.length === 1) {
609
+ this.inputZeroAdded[type] = true;
610
+ const newInputValue = inputValue.padStart(2, '0');
611
+ this.seconds = newInputValue;
612
+ }
613
+ else if (this.inputZeroAdded[type]) {
614
+ this.inputZeroAdded[type] = false;
615
+ const newInputValue = inputValue.slice(1, 3).padStart(2, '0');
616
+ const parsedNewInputValue = parseInt(newInputValue, 10) || 0;
617
+ // Only apply format validation (not min/max constraints)
618
+ if (parsedNewInputValue >= maxSeconds) {
619
+ this.seconds = '00';
620
+ }
621
+ else {
622
+ this.seconds = newInputValue;
623
+ }
624
+ }
625
+ else if (inputValue.length > 2) {
626
+ const newInputValue = inputValue.slice(1, 3).padStart(2, '0');
627
+ const parsedNewInputValue = parseInt(newInputValue, 10) || 0;
628
+ // Only apply format validation (not min/max constraints)
629
+ if (parsedNewInputValue >= maxSeconds) {
630
+ this.seconds = '00';
631
+ }
632
+ else {
633
+ this.seconds = parsedNewInputValue.toString();
634
+ }
635
+ }
636
+ else {
637
+ const parsedNewInputValue = parseInt(inputValue, 10) || 0;
638
+ // Only apply format validation (not min/max constraints)
639
+ if (parsedNewInputValue >= maxSeconds) {
640
+ this.seconds = '00';
641
+ }
642
+ else {
643
+ // For direct input, remove unnecessary leading zeros (e.g., '01' becomes '1')
644
+ this.seconds = parsedNewInputValue.toString();
645
+ }
646
+ }
647
+ // No auto-navigation for seconds field as it's typically the last field
648
+ }
649
+ // Parse a time string according to the current format
650
+ parseTime(timeString) {
651
+ if (!timeString) {
652
+ return;
653
+ }
654
+ // Use format-aware parsing without constraint application
655
+ const components = parseValueByFormat(timeString, this.format);
656
+ // Set the parsed values without applying min/max constraints
657
+ this.hours = components.hours;
658
+ this.minutes = components.minutes;
659
+ this.seconds = components.seconds;
660
+ }
661
+ reconstructTime() {
662
+ const components = {
663
+ hours: this.hours,
664
+ minutes: this.minutes,
665
+ seconds: this.seconds,
666
+ };
667
+ // Ensure the reconstructed time is in the correct format
668
+ const reconstructedTime = reconstructTimeByFormat(components, this.format);
669
+ // Validate that the reconstructed time matches the expected format
670
+ if (!isValidFormatValue(reconstructedTime, this.format)) {
671
+ // If invalid, return the default value for this format
672
+ const config = FORMAT_CONFIGS[this.format];
673
+ return config ? config.defaultValue : reconstructedTime;
674
+ }
675
+ return reconstructedTime;
676
+ }
677
+ handleFocus(type) {
678
+ var _a, _b, _c, _d;
679
+ if (this.readonly || this.disabled) {
680
+ return;
681
+ }
682
+ // Check if this field is visible for the current format
683
+ const visibleTypes = getVisibleTimeTypes(this.format);
684
+ if (!visibleTypes.includes(type)) {
685
+ return; // Don't handle focus for non-visible fields
686
+ }
687
+ if (!this.open) {
688
+ this.open = true; // Force the popover to open
689
+ }
690
+ // Refocus on the input if it loses focus and is empty
691
+ if (((_a = this.inputElements[type]) === null || _a === void 0 ? void 0 : _a.value.length) === 0 ||
692
+ ((_b = this.inputElements[type]) === null || _b === void 0 ? void 0 : _b.value) === '00') {
693
+ (_c = this.inputElements[type]) === null || _c === void 0 ? void 0 : _c.focus();
694
+ (_d = this.inputElements[type]) === null || _d === void 0 ? void 0 : _d.select();
695
+ }
696
+ this.typeFocused = type;
697
+ }
698
+ HandleDropdownIconClick() {
699
+ var _a, _b;
700
+ if (this.disabled || this.readonly) {
701
+ return; // Do not toggle if disabled or read-only
702
+ }
703
+ const visibleTypes = getVisibleTimeTypes(this.format);
704
+ const firstVisibleType = visibleTypes[0];
705
+ if (this.open) {
706
+ this.open = false; // Close the popover if it is open
707
+ }
708
+ else if (!this.open &&
709
+ firstVisibleType &&
710
+ this.inputElements[firstVisibleType]) {
711
+ (_a = this.inputElements[firstVisibleType]) === null || _a === void 0 ? void 0 : _a.focus(); // Focus will open the popover
712
+ (_b = this.inputElements[firstVisibleType]) === null || _b === void 0 ? void 0 : _b.select();
713
+ }
714
+ else {
715
+ console.warn('nv-fieldtime -> No visible input elements found to focus');
716
+ }
717
+ }
718
+ updateHighlightedItem(items, index) {
719
+ items.forEach((item, i) => {
720
+ if (i === index) {
721
+ item.classList.add('highlighted');
722
+ item.setAttribute('tabindex', '0');
723
+ item.focus(); // Forcer le focus ici
724
+ item.scrollIntoView({ block: 'nearest' });
725
+ }
726
+ else {
727
+ item.classList.remove('highlighted');
728
+ item.setAttribute('tabindex', '-1');
729
+ }
730
+ });
731
+ }
732
+ handleTimeOptionClick(event, type) {
733
+ const option = parseInt(event.target.textContent || '0', 10);
734
+ // Update the time component directly without constraint validation
735
+ // Dropdown options are already filtered by constraints during generation
736
+ if (type === constants69bafca2.TimeType.Hours) {
737
+ this.hours = option.toString().padStart(2, '0');
738
+ }
739
+ else if (type === constants69bafca2.TimeType.Minutes) {
740
+ this.minutes = option.toString().padStart(2, '0');
741
+ }
742
+ else if (type === constants69bafca2.TimeType.Seconds) {
743
+ this.seconds = option.toString().padStart(2, '0');
744
+ }
745
+ // Reconstruct time in the correct format and update value
746
+ const reconstructedTime = this.reconstructTime();
747
+ this.value = reconstructedTime;
748
+ }
749
+ handleInputBlur() {
750
+ // Use a delay to check if the focus is still within the popover
751
+ setTimeout(() => {
752
+ if (!this.el.contains(document.activeElement)) {
753
+ if (this.open) {
754
+ this.open = false; // Close the popover if the focus is outside the component
755
+ }
756
+ }
757
+ }, 150);
758
+ }
759
+ handleClickOutside(event) {
760
+ const target = event.target;
761
+ // Check if the click is inside the component or any of the input elements
762
+ if (this.el.contains(target) ||
763
+ Object.values(this.inputElements).some(input => input.contains(target))) {
764
+ return;
765
+ }
766
+ if (this.open) {
767
+ this.open = false; // Close the popover if the click is outside
768
+ }
769
+ }
770
+ handleScroll(e, type) {
771
+ const target = e.target;
772
+ const scrollTop = target.scrollTop;
773
+ const containerHeight = target.clientHeight;
774
+ const scrollHeight = target.scrollHeight;
775
+ // Define the height of each item, this could be dynamic if the height varies
776
+ const itemHeight = 40; // Consider making this configurable or dynamic
777
+ const options = this.generateTimeOptions(type); // Generates the list of time options
778
+ const singleSetHeight = options.length * itemHeight;
779
+ // Check if the scroll is near the bottom or top and reset to the first set
780
+ if (scrollTop + containerHeight >= scrollHeight - itemHeight ||
781
+ scrollTop <= 0) {
782
+ target.scrollTop = singleSetHeight; // Reset to the first set from the bottom
783
+ }
784
+ }
785
+ generateTimeOptions(type) {
786
+ // Convert the step in seconds
787
+ const stepInSeconds = this.step / 1000;
788
+ // Handle edge case for zero step
789
+ if (stepInSeconds === 0) {
790
+ return ['00']; // Just return the default value
791
+ }
792
+ // Generate the time options based on the type
793
+ switch (type) {
794
+ case constants69bafca2.TimeType.Hours:
795
+ return this.generateHourOptions(stepInSeconds);
796
+ case constants69bafca2.TimeType.Minutes:
797
+ return this.generateMinuteOptions(stepInSeconds);
798
+ case constants69bafca2.TimeType.Seconds:
799
+ return this.generateSecondOptions(stepInSeconds);
800
+ default:
801
+ return [];
802
+ }
803
+ }
804
+ generateHourOptions(stepInSeconds) {
805
+ const hourStep = Math.max(1, Math.floor(stepInSeconds / 3600)); // Prevent step < 1
806
+ const is12HourFormat = this.format.startsWith('hh');
807
+ // Set proper hour ranges based on format
808
+ const defaultMaxHour = is12HourFormat ? 12 : 23;
809
+ const defaultMinHour = is12HourFormat ? 1 : 0;
810
+ const maxHour = this.parseHour(this.max, this.format);
811
+ const minHour = this.parseHour(this.min, this.format);
812
+ const maxHourValue = maxHour ? parseInt(maxHour, 10) : defaultMaxHour;
813
+ const minHourValue = minHour ? parseInt(minHour, 10) : defaultMinHour;
814
+ const values = [];
815
+ for (let i = minHourValue; i <= maxHourValue; i += hourStep) {
816
+ const hourStr = i.toString().padStart(2, '0');
817
+ values.push(hourStr);
818
+ }
819
+ return values;
820
+ }
821
+ /**
822
+ * Parse hour value from min/max constraint strings for dropdown generation only.
823
+ * This method is used exclusively for filtering dropdown options and should not
824
+ * affect input values or validation.
825
+ * @param {string} value - The time string to parse (e.g., "14:30" or "02:30")
826
+ * @param {string} format - The time format string (e.g., "HH:mm" or "hh:mm")
827
+ * @returns {string} The parsed hour string or null if invalid
828
+ */
829
+ parseHour(value, format) {
830
+ if (!value)
831
+ return null;
832
+ const [hourStr] = value.split(':');
833
+ const hour = parseInt(hourStr, 10);
834
+ if (isNaN(hour))
835
+ return null;
836
+ if (format.startsWith('hh'))
837
+ return hour > 0 && hour <= 12 ? hourStr.padStart(2, '0') : null;
838
+ return hour >= 0 && hour <= 24 ? hourStr.padStart(2, '0') : null;
839
+ }
840
+ generateMinuteOptions(stepInSeconds) {
841
+ var _a, _b;
842
+ const minuteStep = Math.max(1, Math.floor((stepInSeconds % 3600) / 60)); // Ensure step >= 1
843
+ const minMinute = (_a = this.parseMinute(this.min)) !== null && _a !== void 0 ? _a : 0;
844
+ const maxMinute = (_b = this.parseMinute(this.max)) !== null && _b !== void 0 ? _b : 59;
845
+ if (minMinute === 0 && maxMinute === 0)
846
+ return ['00']; // Handle edge case for zero minutes
847
+ const values = [];
848
+ for (let i = minMinute; i <= maxMinute; i += minuteStep) {
849
+ const minuteStr = i.toString().padStart(2, '0');
850
+ values.push(minuteStr);
851
+ }
852
+ return values;
853
+ }
854
+ /**
855
+ * Parse minute value from min/max constraint strings for dropdown generation only.
856
+ * This method is used exclusively for filtering dropdown options and should not
857
+ * affect input values or validation.
858
+ * @param {string} value - The time string to parse (e.g., "14:30" or "02:30")
859
+ * @returns {number} The parsed minute number or null if invalid
860
+ */
861
+ parseMinute(value) {
862
+ if (!value)
863
+ return null;
864
+ const parts = value.split(':');
865
+ if (parts.length < 2)
866
+ return null; // Expect at least "hh:mm"
867
+ const minute = parseInt(parts[1], 10);
868
+ return isNaN(minute) || minute < 0 || minute >= 60 ? null : minute;
869
+ }
870
+ generateSecondOptions(stepInSeconds) {
871
+ var _a, _b;
872
+ const secondStep = Math.max(1, stepInSeconds % 60); // Ensure step >= 1
873
+ const minSecond = (_a = this.parseSecond(this.min)) !== null && _a !== void 0 ? _a : 0;
874
+ const maxSecond = (_b = this.parseSecond(this.max)) !== null && _b !== void 0 ? _b : 59;
875
+ if (minSecond === 0 && maxSecond === 0)
876
+ return ['00']; // Handle edge case for zero seconds
877
+ const values = [];
878
+ for (let i = minSecond; i <= maxSecond; i += secondStep) {
879
+ const secondStr = i.toString().padStart(2, '0');
880
+ values.push(secondStr);
881
+ }
882
+ return values;
883
+ }
884
+ /**
885
+ * Parse second value from min/max constraint strings for dropdown generation only.
886
+ * This method is used exclusively for filtering dropdown options and should not
887
+ * affect input values or validation.
888
+ * @param {string} value - The time string to parse (e.g., "14:30:45" or "02:30:45")
889
+ * @returns {number} The parsed second number or null if invalid
890
+ */
891
+ parseSecond(value) {
892
+ if (!value)
893
+ return null;
894
+ const parts = value.split(':');
895
+ if (parts.length < 3)
896
+ return null; // Expect "hh:mm:ss" or "HH:mm:ss"
897
+ const second = parseInt(parts[2], 10);
898
+ return isNaN(second) || second < 0 || second >= 60 ? null : second;
899
+ }
900
+ generateInfiniteTimeOptions(type) {
901
+ const options = this.generateTimeOptions(type);
902
+ const totalOptions = options.length;
903
+ // Dynamically calculate repetitions based on a target number of items (e.g., 300 items)
904
+ const repetitions = Math.ceil(300 / totalOptions);
905
+ return Array(repetitions).fill(options).flat();
906
+ }
907
+ updateColumnHighlight(selector, value) {
908
+ const items = Array.from(this.el.querySelectorAll(selector));
909
+ const index = items.findIndex(x => x.textContent === value);
910
+ this.updateHighlightedItem(items, index);
911
+ }
912
+ handleHostClick(event) {
913
+ var _a, _b;
914
+ if (this.disabled || this.readonly) {
915
+ return;
916
+ }
917
+ const targetElement = event.target;
918
+ // Check if the click target or its ancestors are inside an nv-iconbutton element
919
+ if (targetElement.closest('nv-iconbutton')) {
920
+ return; // Handle icon button click separately
921
+ }
922
+ if (!this.open) {
923
+ if (this.inputElements) {
924
+ // Focus on the first visible field based on format
925
+ const visibleTypes = getVisibleTimeTypes(this.format);
926
+ const firstVisibleType = visibleTypes[0];
927
+ if (firstVisibleType && this.inputElements[firstVisibleType]) {
928
+ (_a = this.inputElements[firstVisibleType]) === null || _a === void 0 ? void 0 : _a.focus();
929
+ (_b = this.inputElements[firstVisibleType]) === null || _b === void 0 ? void 0 : _b.select();
930
+ }
931
+ }
932
+ event.preventDefault();
933
+ }
934
+ }
935
+ //#endregion METHODS
936
+ /****************************************************************************/
937
+ //#region LIFECYCLE
938
+ componentWillLoad() {
939
+ document.addEventListener('click', this.handleClickOutside.bind(this));
940
+ // Initialize component state based on format and value
941
+ if (this.value) {
942
+ // Parse the provided value using format-aware parsing without constraint application
943
+ this.parseTime(this.value);
944
+ }
945
+ else {
946
+ // Initialize with format-appropriate default values without any constraint application
947
+ // Use format-specific defaults: '01' for 12-hour formats, '00' for 24-hour formats
948
+ const defaultComponents = parseValueByFormat('', this.format);
949
+ // Set default values directly without any min/max constraint validation
950
+ this.hours = defaultComponents.hours;
951
+ this.minutes = defaultComponents.minutes;
952
+ this.seconds = defaultComponents.seconds;
953
+ // Set the initial value in the correct format without constraint validation
954
+ // This ensures the component has a proper initial state for the value watcher
955
+ const initialValue = reconstructTimeByFormat(defaultComponents, this.format);
956
+ this.value = initialValue;
957
+ }
958
+ }
959
+ connectedCallback() {
960
+ document.addEventListener('click', this.handleClickOutside.bind(this));
961
+ }
962
+ disconnectedCallback() {
963
+ document.removeEventListener('click', this.handleClickOutside.bind(this));
964
+ }
965
+ componentDidLoad() {
966
+ // Initialize dropdown highlighting based on current component state
967
+ // This ensures proper visual feedback without applying any constraints
968
+ // Update highlighted items for hours based on current state
969
+ const hourSelector = `.time-column.time-column-hours div`;
970
+ this.updateColumnHighlight(hourSelector, this.hours);
971
+ // Update highlighted items for minutes based on current state
972
+ const minuteSelector = `.time-column.time-column-minutes div`;
973
+ this.updateColumnHighlight(minuteSelector, this.minutes);
974
+ // Update highlighted items for seconds based on current state
975
+ const secondSelector = `.time-column.time-column-seconds div`;
976
+ this.updateColumnHighlight(secondSelector, this.seconds);
977
+ }
978
+ //#endregion LIFECYCLE
979
+ /****************************************************************************/
980
+ //#region RENDER
981
+ /**
982
+ * Renders input fields based on the current format
983
+ * Only shows fields that are relevant to the selected format
984
+ * @returns {HTMLElement[]} Array of HTML elements for time input fields
985
+ */
986
+ renderTimeInputFields() {
987
+ const visibleTypes = getVisibleTimeTypes(this.format);
988
+ const elements = [];
989
+ visibleTypes.forEach((type, index$1) => {
990
+ // Add separator colon before minutes and seconds (but not before the first field)
991
+ if (index$1 > 0) {
992
+ elements.push(index.h("span", null, ":"));
993
+ }
994
+ // Add the input field for this time type
995
+ elements.push(this.renderTimeInputField(type));
996
+ });
997
+ return elements;
998
+ }
999
+ /**
1000
+ * Renders a single time input field for the specified type
1001
+ * @param {TimeType} type - The time type to render input for
1002
+ * @returns {HTMLInputElement} HTML input element for the specified time type
1003
+ */
1004
+ renderTimeInputField(type) {
1005
+ const getValue = () => {
1006
+ switch (type) {
1007
+ case constants69bafca2.TimeType.Hours:
1008
+ return this.hours;
1009
+ case constants69bafca2.TimeType.Minutes:
1010
+ return this.minutes;
1011
+ case constants69bafca2.TimeType.Seconds:
1012
+ return this.seconds;
1013
+ default:
1014
+ return '00';
1015
+ }
1016
+ };
1017
+ const getPlaceholder = () => {
1018
+ switch (type) {
1019
+ case constants69bafca2.TimeType.Hours:
1020
+ return this.format.includes('hh') ? 'hh' : 'HH';
1021
+ case constants69bafca2.TimeType.Minutes:
1022
+ return 'mm';
1023
+ case constants69bafca2.TimeType.Seconds:
1024
+ return 'ss';
1025
+ default:
1026
+ return '';
1027
+ }
1028
+ };
1029
+ const getId = () => {
1030
+ switch (type) {
1031
+ case constants69bafca2.TimeType.Hours:
1032
+ return this.inputId;
1033
+ case constants69bafca2.TimeType.Minutes:
1034
+ return `${this.inputId}-minutes`;
1035
+ case constants69bafca2.TimeType.Seconds:
1036
+ return `${this.inputId}-seconds`;
1037
+ default:
1038
+ return this.inputId;
1039
+ }
1040
+ };
1041
+ // Remove min/max constraints from input elements to allow native stepper behavior
1042
+ // Constraints are only applied to dropdown options, not input steppers
1043
+ 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() }));
1044
+ }
1045
+ /**
1046
+ * Renders dropdown columns based on the current format
1047
+ * Only shows columns that are relevant to the selected format
1048
+ * @returns {HTMLElement[]} Array of HTML elements for time dropdown columns
1049
+ */
1050
+ renderTimeDropdownColumns() {
1051
+ const visibleTypes = getVisibleTimeTypes(this.format);
1052
+ return visibleTypes.map(type => this.RenderTimeOptionsColumn(type));
1053
+ }
1054
+ RenderTimeOptionsColumn(type) {
1055
+ 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: {
1056
+ 'time-option': true,
1057
+ 'selected': (type === constants69bafca2.TimeType.Hours && option === this.hours) ||
1058
+ (type === constants69bafca2.TimeType.Minutes && option === this.minutes) ||
1059
+ (type === constants69bafca2.TimeType.Seconds && option === this.seconds),
1060
+ }, key: `${option}-${index$1}`, onClick: e => this.handleTimeOptionClick(e, type) }, option)))));
1061
+ }
1062
+ render() {
1063
+ return (index.h(index.Host, { key: 'f66fe2a29f23a0bc967821a0c9bca4347b622286', onclick: (e) => this.handleHostClick(e), "aria-expanded": this.open ? 'true' : 'false' }, (this.label || this.el.querySelector('[slot="label"]')) && (index.h("label", { key: 'f01ce1b034b1b547cbdde5814db9357ee1913e04', htmlFor: this.inputId }, index.h("slot", { key: 'd81dcb20883b93280db6e76e0299f679f1f9ed84', name: "label" }, this.label))), index.h("nv-popover", { key: '8c9e83002edcfba89ca4ca282fc82db714ed2f43', ref: el => (this.popoverElement = el), triggerMode: "controlled", placement: "bottom-start", open: this.open }, index.h("div", { key: '3a5b26e4be67f277ead2a9fe2f04e5d12a4bd596', class: "input-wrapper", slot: "trigger" }, index.h("slot", { key: '2ea5f8269c6f0892c53a002a298ca3ceed8f8a00', name: "before-input" }), index.h("div", { key: 'ab97bbbf183118d7b510f82c800b4a3fa1fefda3', class: "input-container" }, index.h("slot", { key: 'a80d2f68b24d4226c18bf0df18ebf13ac6e0873e', name: "leading-input" }), this.renderTimeInputFields(), index.h("nv-iconbutton", { key: '1f7aacf1ab073c0c6ef10b50e948a7ecbca4dd75', 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: '8f414a3b3daae6f0625b3c62b920621bf8698db3', name: "alert-circle", class: "validation", size: "sm" })), this.success && (index.h("nv-icon", { key: '13b5671664466b6bb50f2561b5cffb96517a1068', name: "circle-check", class: "validation", size: "sm" }))), index.h("slot", { key: 'b5d6085a9864ef84d4113062a0b1cb8a807ab241', name: "after-input" })), index.h("div", { key: '2950c5fac3a0f219e5db2e3a7e9f605d86e50aa2', class: "time-dropdown", slot: "content" }, index.h("div", { key: 'c5b7ff3818a05e1f6d7ca76657f57b85bb595345', class: "time-columns" }, this.renderTimeDropdownColumns()))), (this.description ||
1064
+ this.el.querySelector('[slot="description"]')) && (index.h("div", { key: 'c8cb90fad74721a9b5eb0ab50980f3fd7c587e62', class: "description" }, index.h("slot", { key: '641d1a6a9dbf580267664831d5b371a601afb039', name: "description" }, this.description))), (this.errorDescription ||
1065
+ this.el.querySelector('[slot="error-description"]')) && (index.h("div", { key: '5721b81d7a16b626bfa7c3af20897f33b7c37080', hidden: !this.error, class: "error-description" }, index.h("slot", { key: '84cef1043666ab6dd86f70d4ba0054d7f33ca589', name: "error-description" }, this.errorDescription)))));
1066
+ }
1067
+ static get formAssociated() { return true; }
1068
+ get el() { return index.getElement(this); }
1069
+ static get watchers() { return {
1070
+ "value": ["handleValueChange"],
1071
+ "open": ["handleOpenChange"],
1072
+ "format": ["handleFormatChange"]
1073
+ }; }
1074
+ };
1075
+ NvFieldtime.style = NvFieldtimeStyle0;
1076
+
1077
+ exports.nv_fieldtime = NvFieldtime;