@nuralyui/timepicker 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/controllers/formatting.controller.d.ts +93 -0
  2. package/controllers/formatting.controller.d.ts.map +1 -0
  3. package/controllers/formatting.controller.js +195 -0
  4. package/controllers/formatting.controller.js.map +1 -0
  5. package/controllers/index.d.ts +9 -0
  6. package/controllers/index.d.ts.map +1 -0
  7. package/controllers/index.js +9 -0
  8. package/controllers/index.js.map +1 -0
  9. package/controllers/selection.controller.d.ts +72 -0
  10. package/controllers/selection.controller.d.ts.map +1 -0
  11. package/controllers/selection.controller.js +175 -0
  12. package/controllers/selection.controller.js.map +1 -0
  13. package/controllers/validation.controller.d.ts +88 -0
  14. package/controllers/validation.controller.d.ts.map +1 -0
  15. package/controllers/validation.controller.js +200 -0
  16. package/controllers/validation.controller.js.map +1 -0
  17. package/index.d.ts +12 -0
  18. package/index.js +12 -0
  19. package/interfaces/timepicker.interface.d.ts +103 -0
  20. package/interfaces/timepicker.interface.d.ts.map +1 -0
  21. package/interfaces/timepicker.interface.js +7 -0
  22. package/interfaces/timepicker.interface.js.map +1 -0
  23. package/package.json +63 -0
  24. package/test/timepicker.test.d.ts +7 -0
  25. package/test/timepicker.test.d.ts.map +1 -0
  26. package/test/timepicker.test.js +218 -0
  27. package/test/timepicker.test.js.map +1 -0
  28. package/timepicker.component.backup.d.ts +165 -0
  29. package/timepicker.component.backup.js +890 -0
  30. package/timepicker.component.clean.d.ts +95 -0
  31. package/timepicker.component.clean.js +471 -0
  32. package/timepicker.component.d.ts +117 -0
  33. package/timepicker.component.js +747 -0
  34. package/timepicker.constants.d.ts +85 -0
  35. package/timepicker.constants.js +85 -0
  36. package/timepicker.style.d.ts +7 -0
  37. package/timepicker.style.js +646 -0
  38. package/timepicker.types.d.ts +161 -0
  39. package/timepicker.types.js +125 -0
  40. package/utils/time.utils.d.ts +87 -0
  41. package/utils/time.utils.d.ts.map +1 -0
  42. package/utils/time.utils.js +235 -0
  43. package/utils/time.utils.js.map +1 -0
@@ -0,0 +1,747 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { LitElement, html, nothing } from 'lit';
8
+ import { customElement, property, state } from 'lit/decorators.js';
9
+ import { classMap } from 'lit/directives/class-map.js';
10
+ // Import UI components
11
+ import '../input/input.component.js';
12
+ import '../button/button.component.js';
13
+ // Import base mixin and types
14
+ import { NuralyUIBaseMixin } from '../../shared/base-mixin.js';
15
+ import { SharedDropdownController } from '../../shared/controllers/dropdown.controller.js';
16
+ import { TimeFormat, TimePickerState, TimePickerPlacement, TimePeriod, TimeStep, EMPTY_TIME_VALUE, TIME_PICKER_EVENTS, } from './timepicker.types.js';
17
+ // Import controllers
18
+ import { TimePickerSelectionController } from './controllers/selection.controller.js';
19
+ import { TimePickerValidationController } from './controllers/validation.controller.js';
20
+ import { TimePickerFormattingController } from './controllers/formatting.controller.js';
21
+ // Import utilities
22
+ import { TimeUtils } from './utils/time.utils.js';
23
+ // Import styles
24
+ import { styles as timePickerStyles } from './timepicker.style.js';
25
+ /**
26
+ * A comprehensive time picker component that supports both 12-hour and 24-hour formats,
27
+ * with optional seconds display and extensive customization options.
28
+ *
29
+ * @example
30
+ * ```html
31
+ * <nr-timepicker
32
+ * value="14:30:00"
33
+ * format="24h"
34
+ * show-seconds
35
+ * placeholder="Select time">
36
+ * </nr-timepicker>
37
+ * ```
38
+ */
39
+ let NrTimePickerElement = class NrTimePickerElement extends NuralyUIBaseMixin(LitElement) {
40
+ constructor() {
41
+ super();
42
+ // Properties
43
+ this.value = '';
44
+ this.name = '';
45
+ this.placeholder = 'Select time';
46
+ this.format = TimeFormat.TwentyFourHour;
47
+ this.showSeconds = false;
48
+ this.disabled = false;
49
+ this.readonly = false;
50
+ this.required = false;
51
+ this.helperText = '';
52
+ this.label = '';
53
+ this.size = 'medium';
54
+ this.variant = 'outlined';
55
+ this.placement = TimePickerPlacement.Bottom;
56
+ /** Scroll behavior for dropdown navigation - 'instant' for immediate, 'smooth' for animated, 'auto' for browser default */
57
+ this.scrollBehavior = 'instant';
58
+ // State
59
+ this.inputValue = '';
60
+ this.state = TimePickerState.Default;
61
+ this.validationMessage = '';
62
+ // Controllers
63
+ this.dropdownController = new SharedDropdownController(this);
64
+ this.selectionController = new TimePickerSelectionController(this);
65
+ this.validationController = new TimePickerValidationController(this);
66
+ this.formattingController = new TimePickerFormattingController(this);
67
+ }
68
+ connectedCallback() {
69
+ super.connectedCallback();
70
+ this.updateConstraints();
71
+ if (this.value) {
72
+ this.setTimeFromValue(this.value);
73
+ }
74
+ // Add global click listener to close dropdown when clicking outside
75
+ this.addEventListener('click', this.handleComponentClick.bind(this));
76
+ document.addEventListener('click', this.handleDocumentClick.bind(this));
77
+ }
78
+ disconnectedCallback() {
79
+ super.disconnectedCallback();
80
+ // Clean up global event listeners
81
+ document.removeEventListener('click', this.handleDocumentClick.bind(this));
82
+ }
83
+ updated(changedProperties) {
84
+ super.updated(changedProperties);
85
+ if (changedProperties.has('value') && this.value !== this.inputValue) {
86
+ this.setTimeFromValue(this.value);
87
+ // Scroll to the selected time when value changes from outside
88
+ if (this.dropdownController.isOpen) {
89
+ setTimeout(() => {
90
+ this.scrollToSelectedTime();
91
+ }, 50);
92
+ }
93
+ }
94
+ if (this.shouldUpdateConstraints(changedProperties)) {
95
+ this.updateConstraints();
96
+ }
97
+ // Set up dropdown elements
98
+ this.setupDropdownElements();
99
+ }
100
+ setupDropdownElements() {
101
+ var _a, _b;
102
+ const dropdown = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('.time-picker__dropdown');
103
+ const trigger = (_b = this.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('.time-picker__input-wrapper');
104
+ if (dropdown && trigger) {
105
+ this.dropdownController.setElements(dropdown, trigger);
106
+ }
107
+ }
108
+ render() {
109
+ const wrapperClasses = {
110
+ 'time-picker': true,
111
+ 'time-picker--open': this.dropdownController.isOpen,
112
+ 'time-picker--disabled': this.disabled,
113
+ 'time-picker--readonly': this.readonly,
114
+ 'time-picker--error': this.state === TimePickerState.Error,
115
+ };
116
+ return html `
117
+ <div class="${classMap(wrapperClasses)}" data-theme="${this.currentTheme}" part="wrapper">
118
+ ${this.renderLabel()}
119
+ ${this.renderInput()}
120
+ ${this.renderDropdown()}
121
+ ${this.renderHelperText()}
122
+ </div>
123
+ `;
124
+ }
125
+ // Public API methods
126
+ open() {
127
+ this.dropdownController.open();
128
+ // Scroll to selected time when opening programmatically
129
+ setTimeout(() => {
130
+ this.scrollToSelectedTime();
131
+ }, 50);
132
+ }
133
+ close() { this.dropdownController.close(); }
134
+ clear() {
135
+ this.value = '';
136
+ this.inputValue = '';
137
+ this.selectionController.clearSelection();
138
+ }
139
+ setToNow() {
140
+ const now = TimeUtils.getCurrentTime();
141
+ this.selectionController.selectTime(now);
142
+ this.updateInputValue();
143
+ // Scroll to the newly selected time if dropdown is open
144
+ if (this.dropdownController.isOpen) {
145
+ setTimeout(() => {
146
+ this.scrollToSelectedTime();
147
+ }, 10);
148
+ }
149
+ }
150
+ validate() {
151
+ const selectedTime = this.selectionController.getSelectedTime();
152
+ if (!selectedTime)
153
+ return true;
154
+ return this.validationController.validateConstraints(selectedTime);
155
+ }
156
+ validateTime(time) {
157
+ return this.validationController.validateConstraints(time);
158
+ }
159
+ // Helper methods for checking if individual time components are valid
160
+ isHourValid(hour, selectedTime) {
161
+ const testTime = Object.assign(Object.assign({}, selectedTime), { hours: hour });
162
+ return this.validateTime(testTime);
163
+ }
164
+ isMinuteValid(minute, selectedTime) {
165
+ const testTime = Object.assign(Object.assign({}, selectedTime), { minutes: minute });
166
+ return this.validateTime(testTime);
167
+ }
168
+ isSecondValid(second, selectedTime) {
169
+ const testTime = Object.assign(Object.assign({}, selectedTime), { seconds: second });
170
+ return this.validateTime(testTime);
171
+ }
172
+ // Private methods
173
+ renderLabel() {
174
+ if (!this.label)
175
+ return nothing;
176
+ return html `
177
+ <label class="time-picker__label" part="label" for="time-input">
178
+ ${this.label}
179
+ ${this.required ? html `<span class="time-picker__required">*</span>` : nothing}
180
+ </label>
181
+ `;
182
+ }
183
+ renderInput() {
184
+ const formatPlaceholder = this.getFormatPlaceholder();
185
+ return html `
186
+ <div class="time-picker__input-wrapper" part="input-wrapper">
187
+ <nr-input
188
+ id="time-input"
189
+ part="input"
190
+ type="calendar"
191
+ .value="${this.inputValue}"
192
+ placeholder="${this.placeholder || formatPlaceholder}"
193
+ ?disabled="${this.disabled}"
194
+ ?readonly="${false}"
195
+ ?required="${this.required}"
196
+ .state="${this.state === TimePickerState.Error ? "error" /* INPUT_STATE.Error */ : "default" /* INPUT_STATE.Default */}"
197
+ @click="${this.handleInputClick}"
198
+ @nr-input="${this.handleInputChange}"
199
+ @nr-blur="${this.handleInputBlur}"
200
+ >
201
+ </nr-input>
202
+ </div>
203
+ `;
204
+ }
205
+ renderDropdown() {
206
+ if (!this.dropdownController.isOpen)
207
+ return nothing;
208
+ return html `
209
+ <div
210
+ class="time-picker__dropdown time-picker__dropdown--open"
211
+ part="dropdown"
212
+ @click="${this.handleDropdownClick}"
213
+ >
214
+ ${this.renderColumnPicker()}
215
+ ${this.renderActions()}
216
+ </div>
217
+ `;
218
+ }
219
+ renderColumnPicker() {
220
+ const selectedTime = this.selectionController.getSelectedTime();
221
+ const config = this.getConfig();
222
+ return html `
223
+ <div class="time-picker__columns" part="columns">
224
+ ${this.renderHourColumn(selectedTime, config)}
225
+ ${this.renderMinuteColumn(selectedTime)}
226
+ ${this.showSeconds ? this.renderSecondColumn(selectedTime) : nothing}
227
+ </div>
228
+ `;
229
+ }
230
+ renderHourColumn(selectedTime, config) {
231
+ const hours = config.format === TimeFormat.TwelveHour
232
+ ? Array.from({ length: 12 }, (_, i) => i === 0 ? 12 : i)
233
+ : Array.from({ length: 24 }, (_, i) => i);
234
+ const displayHour = selectedTime && config.format === TimeFormat.TwelveHour
235
+ ? this.formattingController.formatHours(selectedTime.hours)
236
+ : selectedTime === null || selectedTime === void 0 ? void 0 : selectedTime.hours;
237
+ return html `
238
+ <div class="time-picker__column" part="hour-column">
239
+ <div class="time-picker__column-list">
240
+ ${hours.map(hour => {
241
+ // Convert display hour to actual hour for validation
242
+ let actualHour = hour;
243
+ if (config.format === TimeFormat.TwelveHour && selectedTime) {
244
+ const currentPeriod = this.formattingController.getPeriod(selectedTime.hours);
245
+ if (hour === 12) {
246
+ actualHour = currentPeriod === TimePeriod.AM ? 0 : 12;
247
+ }
248
+ else {
249
+ actualHour = currentPeriod === TimePeriod.AM ? hour : hour + 12;
250
+ }
251
+ }
252
+ // Use EMPTY_TIME_VALUE for validation when no time is selected
253
+ const timeForValidation = selectedTime || EMPTY_TIME_VALUE;
254
+ const isValid = this.isHourValid(actualHour, timeForValidation);
255
+ const isSelected = selectedTime ? hour === displayHour : false;
256
+ return html `
257
+ <div
258
+ class="time-picker__column-item ${isSelected ? 'time-picker__column-item--selected' : ''} ${!isValid ? 'time-picker__column-item--disabled' : ''}"
259
+ @click="${isValid ? () => this.handleHourSelect(hour, config.format) : null}"
260
+ >
261
+ ${hour.toString().padStart(2, '0')}
262
+ </div>
263
+ `;
264
+ })}
265
+ </div>
266
+ </div>
267
+ `;
268
+ }
269
+ renderMinuteColumn(selectedTime) {
270
+ const minutes = Array.from({ length: 60 }, (_, i) => i);
271
+ return html `
272
+ <div class="time-picker__column" part="minute-column">
273
+ <div class="time-picker__column-list">
274
+ ${minutes.map(minute => {
275
+ // Use EMPTY_TIME_VALUE for validation when no time is selected
276
+ const timeForValidation = selectedTime || EMPTY_TIME_VALUE;
277
+ const isValid = this.isMinuteValid(minute, timeForValidation);
278
+ const isSelected = selectedTime ? minute === selectedTime.minutes : false;
279
+ return html `
280
+ <div
281
+ class="time-picker__column-item ${isSelected ? 'time-picker__column-item--selected' : ''} ${!isValid ? 'time-picker__column-item--disabled' : ''}"
282
+ @click="${isValid ? () => this.handleMinuteSelect(minute) : null}"
283
+ >
284
+ ${minute.toString().padStart(2, '0')}
285
+ </div>
286
+ `;
287
+ })}
288
+ </div>
289
+ </div>
290
+ `;
291
+ }
292
+ renderSecondColumn(selectedTime) {
293
+ const seconds = Array.from({ length: 60 }, (_, i) => i);
294
+ return html `
295
+ <div class="time-picker__column" part="second-column">
296
+ <div class="time-picker__column-list">
297
+ ${seconds.map(second => {
298
+ // Use EMPTY_TIME_VALUE for validation when no time is selected
299
+ const timeForValidation = selectedTime || EMPTY_TIME_VALUE;
300
+ const isValid = this.isSecondValid(second, timeForValidation);
301
+ const isSelected = selectedTime ? second === selectedTime.seconds : false;
302
+ return html `
303
+ <div
304
+ class="time-picker__column-item ${isSelected ? 'time-picker__column-item--selected' : ''} ${!isValid ? 'time-picker__column-item--disabled' : ''}"
305
+ @click="${isValid ? () => this.handleSecondSelect(second) : null}"
306
+ >
307
+ ${second.toString().padStart(2, '0')}
308
+ </div>
309
+ `;
310
+ })}
311
+ </div>
312
+ </div>
313
+ `;
314
+ }
315
+ renderActions() {
316
+ return html `
317
+ <div class="time-picker__actions">
318
+ <nr-button
319
+ type="ghost"
320
+ size="small"
321
+ @click="${() => this.setToNow()}"
322
+ >
323
+ Now
324
+ </nr-button>
325
+ <nr-button
326
+ type="primary"
327
+ size="small"
328
+ @click="${this.handleOkClick}"
329
+ >
330
+ OK
331
+ </nr-button>
332
+ </div>
333
+ `;
334
+ }
335
+ renderHelperText() {
336
+ const text = this.validationMessage || this.helperText;
337
+ if (!text)
338
+ return nothing;
339
+ const isError = this.state === TimePickerState.Error || !!this.validationMessage;
340
+ return html `
341
+ <div class="time-picker__helper-text ${isError ? 'time-picker__helper-text--error' : ''}" part="helper-text">
342
+ ${text}
343
+ </div>
344
+ `;
345
+ }
346
+ scrollToSelectedTime() {
347
+ try {
348
+ const selectedTime = this.selectionController.getSelectedTime();
349
+ if (!selectedTime)
350
+ return;
351
+ // Scroll each column to the selected value
352
+ this.scrollToSelectedHour(selectedTime);
353
+ this.scrollToSelectedMinute(selectedTime);
354
+ if (this.showSeconds) {
355
+ this.scrollToSelectedSecond(selectedTime);
356
+ }
357
+ }
358
+ catch (error) {
359
+ console.warn('Failed to scroll to selected time:', error);
360
+ }
361
+ }
362
+ scrollToSelectedHour(selectedTime) {
363
+ var _a;
364
+ const config = this.getConfig();
365
+ const hourColumn = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('.time-picker__column:first-child .time-picker__column-list');
366
+ if (!hourColumn)
367
+ return;
368
+ let displayHour;
369
+ if (config.format === TimeFormat.TwelveHour) {
370
+ // Convert 24-hour to 12-hour format
371
+ if (selectedTime.hours === 0 || selectedTime.hours === 12) {
372
+ displayHour = 12;
373
+ }
374
+ else {
375
+ displayHour = selectedTime.hours > 12 ? selectedTime.hours - 12 : selectedTime.hours;
376
+ }
377
+ }
378
+ else {
379
+ displayHour = selectedTime.hours;
380
+ }
381
+ // Find the selected hour element
382
+ const selectedHourElement = hourColumn.querySelector(`.time-picker__column-item:nth-child(${this.getHourIndex(displayHour, config.format) + 1})`);
383
+ if (selectedHourElement) {
384
+ selectedHourElement.scrollIntoView({
385
+ behavior: this.scrollBehavior,
386
+ block: 'center',
387
+ inline: 'nearest'
388
+ });
389
+ }
390
+ }
391
+ scrollToSelectedMinute(selectedTime) {
392
+ var _a;
393
+ const minuteColumn = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('.time-picker__column:nth-child(2) .time-picker__column-list');
394
+ if (!minuteColumn)
395
+ return;
396
+ // Find the selected minute element (minute + 1 because nth-child is 1-indexed)
397
+ const selectedMinuteElement = minuteColumn.querySelector(`.time-picker__column-item:nth-child(${selectedTime.minutes + 1})`);
398
+ if (selectedMinuteElement) {
399
+ selectedMinuteElement.scrollIntoView({
400
+ behavior: this.scrollBehavior,
401
+ block: 'center',
402
+ inline: 'nearest'
403
+ });
404
+ }
405
+ }
406
+ scrollToSelectedSecond(selectedTime) {
407
+ var _a;
408
+ const secondColumn = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('.time-picker__column:nth-child(3) .time-picker__column-list');
409
+ if (!secondColumn)
410
+ return;
411
+ // Find the selected second element (second + 1 because nth-child is 1-indexed)
412
+ const selectedSecondElement = secondColumn.querySelector(`.time-picker__column-item:nth-child(${selectedTime.seconds + 1})`);
413
+ if (selectedSecondElement) {
414
+ selectedSecondElement.scrollIntoView({
415
+ behavior: this.scrollBehavior,
416
+ block: 'center',
417
+ inline: 'nearest'
418
+ });
419
+ }
420
+ }
421
+ getHourIndex(displayHour, format) {
422
+ if (format === TimeFormat.TwelveHour) {
423
+ // For 12-hour format: 12, 1, 2, ..., 11
424
+ return displayHour === 12 ? 0 : displayHour;
425
+ }
426
+ else {
427
+ // For 24-hour format: 0, 1, 2, ..., 23
428
+ return displayHour;
429
+ }
430
+ }
431
+ // Event handlers
432
+ handleComponentClick(e) {
433
+ // Stop propagation to prevent document click handler from firing
434
+ e.stopPropagation();
435
+ }
436
+ handleDocumentClick(e) {
437
+ var _a;
438
+ // Close dropdown when clicking outside the component
439
+ if (this.dropdownController.isOpen) {
440
+ const target = e.target;
441
+ const isClickInsideComponent = this.contains(target) ||
442
+ ((_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.contains(target));
443
+ if (!isClickInsideComponent) {
444
+ this.dropdownController.close();
445
+ this.dispatchEvent(new CustomEvent(TIME_PICKER_EVENTS.BLUR, {
446
+ bubbles: true,
447
+ composed: true,
448
+ }));
449
+ }
450
+ }
451
+ }
452
+ handleDropdownClick(e) {
453
+ // Prevent dropdown from closing when clicking inside
454
+ e.stopPropagation();
455
+ }
456
+ handleOkClick() {
457
+ // Close the dropdown and emit final change event
458
+ this.dropdownController.close();
459
+ const selectedTime = this.selectionController.getSelectedTime();
460
+ if (selectedTime) {
461
+ this.dispatchEvent(new CustomEvent(TIME_PICKER_EVENTS.TIME_CHANGE, {
462
+ bubbles: true,
463
+ composed: true,
464
+ detail: { value: this.value, time: selectedTime }
465
+ }));
466
+ }
467
+ this.dispatchEvent(new CustomEvent(TIME_PICKER_EVENTS.BLUR, {
468
+ bubbles: true,
469
+ composed: true,
470
+ }));
471
+ }
472
+ handleInputBlur() {
473
+ // Only close dropdown if clicking outside the component
474
+ setTimeout(() => {
475
+ var _a;
476
+ const activeElement = document.activeElement;
477
+ const isWithinComponent = this.contains(activeElement) ||
478
+ ((_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.contains(activeElement));
479
+ if (!isWithinComponent) {
480
+ this.dispatchEvent(new CustomEvent(TIME_PICKER_EVENTS.BLUR, {
481
+ bubbles: true,
482
+ composed: true,
483
+ }));
484
+ }
485
+ }, 150);
486
+ }
487
+ handleInputClick(e) {
488
+ e.preventDefault();
489
+ e.stopPropagation();
490
+ if (!this.disabled) {
491
+ // Only open if closed - don't close when clicking input
492
+ if (!this.dropdownController.isOpen) {
493
+ this.dropdownController.open();
494
+ // Scroll to selected items when dropdown opens
495
+ setTimeout(() => {
496
+ this.scrollToSelectedTime();
497
+ }, 50);
498
+ this.dispatchEvent(new CustomEvent(TIME_PICKER_EVENTS.FOCUS, {
499
+ bubbles: true,
500
+ composed: true,
501
+ }));
502
+ }
503
+ }
504
+ }
505
+ handleInputChange(e) {
506
+ var _a;
507
+ if (this.disabled)
508
+ return;
509
+ const inputValue = ((_a = e.detail) === null || _a === void 0 ? void 0 : _a.value) || '';
510
+ this.inputValue = inputValue;
511
+ // Parse the input value and update the time selection
512
+ const parsedTime = this.formattingController.parseInputValue(inputValue);
513
+ if (parsedTime) {
514
+ // Validate the parsed time
515
+ if (this.validateTime(parsedTime)) {
516
+ this.selectionController.selectTime(parsedTime);
517
+ this.value = this.formattingController.formatForInput(parsedTime);
518
+ this.state = TimePickerState.Default;
519
+ // Scroll to the newly selected time if dropdown is open
520
+ if (this.dropdownController.isOpen) {
521
+ setTimeout(() => {
522
+ this.scrollToSelectedTime();
523
+ }, 10);
524
+ }
525
+ // Emit change event
526
+ this.dispatchEvent(new CustomEvent(TIME_PICKER_EVENTS.TIME_CHANGE, {
527
+ bubbles: true,
528
+ composed: true,
529
+ detail: { value: this.value, time: parsedTime }
530
+ }));
531
+ }
532
+ else {
533
+ // Invalid time - show error state but don't clear the input
534
+ this.state = TimePickerState.Error;
535
+ }
536
+ }
537
+ else if (inputValue === '') {
538
+ // Empty input - clear the selection
539
+ this.selectionController.clearSelection();
540
+ this.value = '';
541
+ this.state = TimePickerState.Default;
542
+ this.dispatchEvent(new CustomEvent(TIME_PICKER_EVENTS.TIME_CHANGE, {
543
+ bubbles: true,
544
+ composed: true,
545
+ detail: { value: '', time: null }
546
+ }));
547
+ }
548
+ else {
549
+ // Invalid format - show error state
550
+ this.state = TimePickerState.Error;
551
+ }
552
+ // Request update to re-render with new state
553
+ this.requestUpdate();
554
+ }
555
+ handleHourSelect(hour, format) {
556
+ const selectedTime = this.selectionController.getSelectedTime() || TimeUtils.getCurrentTime();
557
+ let adjustedHour = hour;
558
+ if (format === TimeFormat.TwelveHour) {
559
+ const currentPeriod = this.formattingController.getPeriod(selectedTime.hours);
560
+ if (hour === 12) {
561
+ adjustedHour = currentPeriod === TimePeriod.AM ? 0 : 12;
562
+ }
563
+ else {
564
+ adjustedHour = currentPeriod === TimePeriod.AM ? hour : hour + 12;
565
+ }
566
+ }
567
+ const updatedTime = Object.assign(Object.assign({}, selectedTime), { hours: adjustedHour });
568
+ if (this.validateTime(updatedTime)) {
569
+ this.selectionController.selectTime(updatedTime);
570
+ this.updateInputValue();
571
+ // No scrolling when clicking on individual items
572
+ }
573
+ }
574
+ handleMinuteSelect(minute) {
575
+ const selectedTime = this.selectionController.getSelectedTime() || TimeUtils.getCurrentTime();
576
+ const updatedTime = Object.assign(Object.assign({}, selectedTime), { minutes: minute });
577
+ if (this.validateTime(updatedTime)) {
578
+ this.selectionController.selectTime(updatedTime);
579
+ this.updateInputValue();
580
+ // No scrolling when clicking on individual items
581
+ }
582
+ }
583
+ handleSecondSelect(second) {
584
+ const selectedTime = this.selectionController.getSelectedTime() || TimeUtils.getCurrentTime();
585
+ const updatedTime = Object.assign(Object.assign({}, selectedTime), { seconds: second });
586
+ if (this.validateTime(updatedTime)) {
587
+ this.selectionController.selectTime(updatedTime);
588
+ this.updateInputValue();
589
+ // No scrolling when clicking on individual items
590
+ }
591
+ }
592
+ // Utility methods
593
+ shouldUpdateConstraints(changedProperties) {
594
+ return (changedProperties.has('minTime') ||
595
+ changedProperties.has('maxTime') ||
596
+ changedProperties.has('disabledTimes') ||
597
+ changedProperties.has('enabledTimes'));
598
+ }
599
+ updateConstraints() {
600
+ const constraints = {
601
+ minTime: this.minTime,
602
+ maxTime: this.maxTime,
603
+ disabledTimes: this.disabledTimes || [],
604
+ enabledTimes: this.enabledTimes,
605
+ };
606
+ this.validationController.setConstraints(constraints);
607
+ }
608
+ setTimeFromValue(value) {
609
+ if (this.selectionController.setTimeFromString(value)) {
610
+ this.inputValue = value;
611
+ this.requestUpdate();
612
+ // Scroll to the time when setting from value (if dropdown is open)
613
+ if (this.dropdownController.isOpen) {
614
+ setTimeout(() => {
615
+ this.scrollToSelectedTime();
616
+ }, 50);
617
+ }
618
+ }
619
+ }
620
+ updateInputValue() {
621
+ const selectedTime = this.selectionController.getSelectedTime();
622
+ if (selectedTime) {
623
+ const formattedValue = this.formattingController.formatForDisplay(selectedTime);
624
+ this.inputValue = formattedValue;
625
+ this.value = formattedValue;
626
+ this.dispatchEvent(new CustomEvent(TIME_PICKER_EVENTS.TIME_CHANGE, {
627
+ detail: { value: formattedValue, time: selectedTime },
628
+ bubbles: true,
629
+ composed: true,
630
+ }));
631
+ }
632
+ }
633
+ getConfig() {
634
+ return {
635
+ format: this.format,
636
+ showSeconds: this.showSeconds,
637
+ step: {
638
+ hours: TimeStep.One,
639
+ minutes: TimeStep.One,
640
+ seconds: TimeStep.One,
641
+ },
642
+ use12HourClock: this.format === TimeFormat.TwelveHour,
643
+ minuteInterval: 1,
644
+ secondInterval: 1,
645
+ };
646
+ }
647
+ // TimePickerHost interface implementation
648
+ getCurrentTime() {
649
+ return this.selectionController.getSelectedTime() || EMPTY_TIME_VALUE;
650
+ }
651
+ setTime(time) {
652
+ this.selectionController.selectTime(time);
653
+ this.updateInputValue();
654
+ // Scroll to the newly selected time if dropdown is open
655
+ if (this.dropdownController.isOpen) {
656
+ setTimeout(() => {
657
+ this.scrollToSelectedTime();
658
+ }, 10);
659
+ }
660
+ }
661
+ formatTime(time) {
662
+ return this.formattingController.formatForDisplay(time);
663
+ }
664
+ /**
665
+ * Get appropriate placeholder text based on format
666
+ */
667
+ getFormatPlaceholder() {
668
+ if (this.format === TimeFormat.TwelveHour) {
669
+ return this.showSeconds ? 'HH:MM:SS AM/PM' : 'HH:MM AM/PM';
670
+ }
671
+ else {
672
+ return this.showSeconds ? 'HH:MM:SS' : 'HH:MM';
673
+ }
674
+ }
675
+ parseTime(timeString) {
676
+ return this.formattingController.parseInputValue(timeString);
677
+ }
678
+ };
679
+ NrTimePickerElement.styles = [timePickerStyles];
680
+ __decorate([
681
+ property({ type: String })
682
+ ], NrTimePickerElement.prototype, "value", void 0);
683
+ __decorate([
684
+ property({ type: String })
685
+ ], NrTimePickerElement.prototype, "name", void 0);
686
+ __decorate([
687
+ property({ type: String })
688
+ ], NrTimePickerElement.prototype, "placeholder", void 0);
689
+ __decorate([
690
+ property({ type: String })
691
+ ], NrTimePickerElement.prototype, "format", void 0);
692
+ __decorate([
693
+ property({ type: Boolean, attribute: 'show-seconds' })
694
+ ], NrTimePickerElement.prototype, "showSeconds", void 0);
695
+ __decorate([
696
+ property({ type: Boolean })
697
+ ], NrTimePickerElement.prototype, "disabled", void 0);
698
+ __decorate([
699
+ property({ type: Boolean })
700
+ ], NrTimePickerElement.prototype, "readonly", void 0);
701
+ __decorate([
702
+ property({ type: Boolean })
703
+ ], NrTimePickerElement.prototype, "required", void 0);
704
+ __decorate([
705
+ property({ type: String, attribute: 'min-time' })
706
+ ], NrTimePickerElement.prototype, "minTime", void 0);
707
+ __decorate([
708
+ property({ type: String, attribute: 'max-time' })
709
+ ], NrTimePickerElement.prototype, "maxTime", void 0);
710
+ __decorate([
711
+ property({ type: Array, attribute: 'disabled-times' })
712
+ ], NrTimePickerElement.prototype, "disabledTimes", void 0);
713
+ __decorate([
714
+ property({ type: Array, attribute: 'enabled-times' })
715
+ ], NrTimePickerElement.prototype, "enabledTimes", void 0);
716
+ __decorate([
717
+ property({ type: String, attribute: 'helper-text' })
718
+ ], NrTimePickerElement.prototype, "helperText", void 0);
719
+ __decorate([
720
+ property({ type: String })
721
+ ], NrTimePickerElement.prototype, "label", void 0);
722
+ __decorate([
723
+ property({ type: String })
724
+ ], NrTimePickerElement.prototype, "size", void 0);
725
+ __decorate([
726
+ property({ type: String })
727
+ ], NrTimePickerElement.prototype, "variant", void 0);
728
+ __decorate([
729
+ property({ type: String })
730
+ ], NrTimePickerElement.prototype, "placement", void 0);
731
+ __decorate([
732
+ property({ type: String, attribute: 'scroll-behavior' })
733
+ ], NrTimePickerElement.prototype, "scrollBehavior", void 0);
734
+ __decorate([
735
+ state()
736
+ ], NrTimePickerElement.prototype, "inputValue", void 0);
737
+ __decorate([
738
+ state()
739
+ ], NrTimePickerElement.prototype, "state", void 0);
740
+ __decorate([
741
+ state()
742
+ ], NrTimePickerElement.prototype, "validationMessage", void 0);
743
+ NrTimePickerElement = __decorate([
744
+ customElement('nr-timepicker')
745
+ ], NrTimePickerElement);
746
+ export { NrTimePickerElement };
747
+ //# sourceMappingURL=timepicker.component.js.map