@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.
- package/dist/cjs/generated/components.server.js +4 -2
- package/dist/cjs/{index-CQAMJPJk.js → index-C12eD0Qt.js} +886 -831
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/{nv-accordion-item.entry-BQ4e6YBV.js → nv-accordion-item.entry-99OJUl7m.js} +1 -1
- package/dist/cjs/{nv-accordion.entry-BX5L-Gh7.js → nv-accordion.entry-D8jaknF9.js} +1 -1
- package/dist/cjs/{nv-alert.entry-GY7Xn7F6.js → nv-alert.entry-D_uvQxc9.js} +1 -1
- package/dist/cjs/{nv-avatar.entry-j-ctCQEi.js → nv-avatar.entry-B2zfDM3w.js} +1 -1
- package/dist/cjs/{nv-badge_2.entry-tuEGBPUn.js → nv-badge_2.entry-Fnq2K2Ul.js} +2 -2
- package/dist/cjs/{nv-breadcrumb.entry-DHZpC_e3.js → nv-breadcrumb.entry-CEN2iYUQ.js} +1 -1
- package/dist/cjs/{nv-breadcrumbs.entry-2tzS_xzO.js → nv-breadcrumbs.entry-Bq8qINNk.js} +1 -1
- package/dist/cjs/{nv-button.entry-BfV4ewn0.js → nv-button.entry-CmpagMPP.js} +1 -1
- package/dist/cjs/{nv-buttongroup.entry-BBTtBLTw.js → nv-buttongroup.entry-CbTXVSWL.js} +1 -1
- package/dist/cjs/{nv-calendar.entry-CTkbvFRZ.js → nv-calendar.entry-DNkXS4ll.js} +1 -1
- package/dist/cjs/{nv-col.entry-CsSk4Ltj.js → nv-col.entry-Dlrdqper.js} +1 -1
- package/dist/cjs/{nv-datagrid.entry-DlQRC5CG.js → nv-datagrid.entry-Z5GHfOvp.js} +1 -1
- package/dist/cjs/{nv-datagridcolumn.entry-BxSumv4Q.js → nv-datagridcolumn.entry-DvSFVguN.js} +1 -1
- package/dist/cjs/{nv-dialog.entry-BFeHCAhr.js → nv-dialog.entry-BV6QBtx2.js} +1 -1
- package/dist/cjs/{nv-dialogfooter_2.entry-CXOzxujX.js → nv-dialogfooter_2.entry-Ci1C_E-2.js} +1 -1
- package/dist/cjs/{nv-fieldcheckbox.entry-BMq7p1kc.js → nv-fieldcheckbox.entry-BD9ETFVV.js} +1 -1
- package/dist/cjs/{nv-fielddate.entry-DmMQq5bO.js → nv-fielddate.entry-C06n2Hri.js} +11 -7
- package/dist/cjs/{nv-fielddaterange.entry-BJm7_qAB.js → nv-fielddaterange.entry-DFlaA4gv.js} +12 -8
- package/dist/cjs/{nv-fielddropdown.entry-DOkzDn78.js → nv-fielddropdown.entry-ONwdJHOm.js} +194 -210
- package/dist/cjs/{nv-fielddropdownitem.entry-CVI8jUn4.js → nv-fielddropdownitem.entry-CDKQtEra.js} +8 -5
- package/dist/cjs/{nv-fieldmultiselect.entry-CWxL0xsk.js → nv-fieldmultiselect.entry-BHJC59Mw.js} +5 -1
- package/dist/cjs/{nv-fieldnumber.entry-bReRT-TF.js → nv-fieldnumber.entry-CmL1LPom.js} +4 -4
- package/dist/cjs/{nv-fieldpassword.entry-BprEVABM.js → nv-fieldpassword.entry-Bqbf_LJJ.js} +4 -4
- package/dist/cjs/{nv-fieldradio.entry-T_uuPP7m.js → nv-fieldradio.entry-RzSCysif.js} +4 -4
- package/dist/cjs/{nv-fieldselect.entry-DB9YREaD.js → nv-fieldselect.entry-COTE8Ntn.js} +6 -6
- package/dist/cjs/{nv-fieldslider.entry-Bkj5p8jp.js → nv-fieldslider.entry-BVfmpUhc.js} +4 -4
- package/dist/cjs/{nv-fieldtext.entry-BsUZW21W.js → nv-fieldtext.entry-DO0lmw9C.js} +4 -4
- package/dist/cjs/{nv-fieldtextarea.entry-DtC4sL4g.js → nv-fieldtextarea.entry-CzVq8gjw.js} +4 -4
- package/dist/cjs/nv-fieldtime.entry-CRNYbeMY.js +1077 -0
- package/dist/cjs/nv-icon.entry-FoRJzCHm.js +80 -0
- package/dist/cjs/{nv-iconbutton_2.entry-DI-3_IYV.js → nv-iconbutton_2.entry-0lnnCk0B.js} +3 -3
- package/dist/cjs/{nv-menu.entry-BbqP7TZx.js → nv-menu.entry-BjXa70qP.js} +3 -3
- package/dist/cjs/{nv-menuitem.entry-BxGppIvW.js → nv-menuitem.entry-CSPwpUWz.js} +2 -2
- package/dist/cjs/{nv-notification.entry-D1gy3PSV.js → nv-notification.entry-BYHTrzUz.js} +2 -2
- package/dist/cjs/{nv-notificationcontainer.entry-MJPLFXsR.js → nv-notificationcontainer.entry-BBjrL7gt.js} +2 -2
- package/dist/cjs/{nv-popover.entry-CL28RbQ0.js → nv-popover.entry-J_M8_rLL.js} +3 -3
- package/dist/cjs/{nv-row.entry-DkCe2B9f.js → nv-row.entry-CmOypCPp.js} +2 -2
- package/dist/cjs/{nv-split.entry-BMVNZDwj.js → nv-split.entry-BqBytQZn.js} +2 -2
- package/dist/cjs/{nv-stack.entry-iH3La5O3.js → nv-stack.entry-BKPf62wy.js} +2 -2
- package/dist/cjs/{nv-table.entry-DFHkpLLG.js → nv-table.entry-DSL_jd5Y.js} +2 -2
- package/dist/cjs/{nv-toggle.entry-BM2Xdtvg.js → nv-toggle.entry-DbQQdp5m.js} +3 -3
- package/dist/cjs/{nv-togglebutton.entry-DPu3j4uH.js → nv-togglebutton.entry-DNG6SFTU.js} +2 -2
- package/dist/cjs/{nv-togglebuttongroup.entry-BBUI9mSK.js → nv-togglebuttongroup.entry-Bl43CVZN.js} +2 -2
- package/dist/cjs/{nv-tooltip.entry-CEynYna7.js → nv-tooltip.entry-CV841nfI.js} +2 -2
- package/dist/generated/components.js +2 -0
- package/dist/generated/components.server.js +4 -2
- package/dist/types/generated/components.d.ts +3 -0
- package/dist/types/generated/components.server.d.ts +3 -0
- package/package.json +1 -1
- package/dist/cjs/nv-fieldtime.entry-BW8nABK-.js +0 -1028
- 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;
|