@refinitiv-ui/elements 5.8.0 → 5.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/lib/calendar/constants.d.ts +4 -0
  3. package/lib/calendar/constants.js +5 -0
  4. package/lib/calendar/index.d.ts +106 -17
  5. package/lib/calendar/index.js +486 -120
  6. package/lib/calendar/locales.js +2 -1
  7. package/lib/calendar/themes/halo/dark/index.js +1 -1
  8. package/lib/calendar/themes/halo/light/index.js +1 -1
  9. package/lib/calendar/themes/solar/charcoal/index.js +1 -1
  10. package/lib/calendar/themes/solar/pearl/index.js +1 -1
  11. package/lib/calendar/types.d.ts +11 -8
  12. package/lib/calendar/utils.js +2 -1
  13. package/lib/combo-box/custom-elements.json +23 -1
  14. package/lib/combo-box/custom-elements.md +8 -1
  15. package/lib/combo-box/helpers/renderer.d.ts +8 -0
  16. package/lib/combo-box/helpers/renderer.js +24 -0
  17. package/lib/combo-box/index.d.ts +36 -16
  18. package/lib/combo-box/index.js +60 -32
  19. package/lib/combo-box/themes/halo/dark/index.js +1 -2
  20. package/lib/combo-box/themes/halo/light/index.js +1 -2
  21. package/lib/combo-box/themes/solar/charcoal/index.js +1 -2
  22. package/lib/combo-box/themes/solar/pearl/index.js +1 -2
  23. package/lib/time-picker/custom-elements.json +2 -4
  24. package/lib/time-picker/custom-elements.md +3 -3
  25. package/lib/time-picker/index.d.ts +92 -62
  26. package/lib/time-picker/index.js +278 -158
  27. package/lib/tree-select/themes/halo/dark/index.js +1 -2
  28. package/lib/tree-select/themes/halo/light/index.js +1 -2
  29. package/lib/tree-select/themes/solar/charcoal/index.js +1 -2
  30. package/lib/tree-select/themes/solar/pearl/index.js +1 -2
  31. package/lib/version.js +1 -1
  32. package/package.json +291 -10
@@ -1,11 +1,18 @@
1
+ var TimePicker_1;
1
2
  import { __decorate } from "tslib";
2
3
  import { ControlElement, html, css } from '@refinitiv-ui/core';
4
+ import { ifDefined } from '@refinitiv-ui/core/lib/directives/if-defined.js';
5
+ import { guard } from '@refinitiv-ui/core/lib/directives/guard.js';
3
6
  import { customElement } from '@refinitiv-ui/core/lib/decorators/custom-element.js';
4
7
  import { property } from '@refinitiv-ui/core/lib/decorators/property.js';
8
+ import { state } from '@refinitiv-ui/core/lib/decorators/state.js';
5
9
  import { query } from '@refinitiv-ui/core/lib/decorators/query.js';
6
10
  import { VERSION } from '../version.js';
7
- import { isValidTime, toTimeSegment, TimeFormat, getFormat, format, isAM, isPM, MILLISECONDS_IN_SECOND, MILLISECONDS_IN_MINUTE, MILLISECONDS_IN_HOUR, addOffset, padNumber } from '@refinitiv-ui/utils/lib/date.js';
11
+ import { isValidTime, toTimeSegment, TimeFormat, getFormat, format, isAM, isPM, MILLISECONDS_IN_SECOND, MILLISECONDS_IN_MINUTE, MILLISECONDS_IN_HOUR, addOffset, padNumber, parse } from '@refinitiv-ui/utils/lib/date.js';
12
+ import { isIE } from '@refinitiv-ui/utils/lib/browser.js';
8
13
  import '../number-field/index.js';
14
+ import { translate } from '@refinitiv-ui/translate';
15
+ import '@refinitiv-ui/phrasebook/lib/locale/en/time-picker.js';
9
16
  var Segment;
10
17
  (function (Segment) {
11
18
  Segment["HOURS"] = "hours";
@@ -33,9 +40,13 @@ const Placeholder = {
33
40
  * @attr {boolean} disabled - Set disabled state
34
41
  * @prop {boolean} [disabled=false] - Set disabled state
35
42
  */
36
- let TimePicker = class TimePicker extends ControlElement {
43
+ let TimePicker = TimePicker_1 = class TimePicker extends ControlElement {
37
44
  constructor() {
38
45
  super(...arguments);
46
+ this.defaultRole = 'group';
47
+ /**
48
+ * If time-picker is in mobile mode
49
+ */
39
50
  this.isMobile = false;
40
51
  /**
41
52
  * Internal hours value, used only in value getters and setters
@@ -63,53 +74,14 @@ let TimePicker = class TimePicker extends ControlElement {
63
74
  * Seconds are automatically shown when `hh:mm:ss` time format is provided as a value.
64
75
  */
65
76
  this.showSeconds = false;
77
+ this._selectedSegment = null;
66
78
  /**
67
- * Handles the blur event of any inputs
68
- *
69
- * @param event Event Object
70
- * @returns {void}
71
- */
72
- this.onBlur = (event) => {
73
- if (this.readonly) {
74
- return;
75
- }
76
- const target = event.target;
77
- const value = target.value;
78
- let segment;
79
- if (target === this.hoursInput) {
80
- segment = Segment.HOURS;
81
- }
82
- else if (target === this.minutesInput) {
83
- segment = Segment.MINUTES;
84
- }
85
- else if (target === this.secondsInput) {
86
- segment = Segment.SECONDS;
87
- }
88
- /* istanbul ignore next */
89
- if (!segment) {
90
- return;
91
- }
92
- if (value) {
93
- this.updateTimeSegmentTo(segment, Number(value));
94
- }
95
- this.updateSegmentValue(segment);
96
- };
97
- /**
98
- * Handles the focus event of any inputs
99
- *
100
- * @param event Event Object
101
- * @returns {void}
79
+ * Connected to role. If false, the values are not announced in the screen reader
102
80
  */
103
- this.onFocus = (event) => {
104
- if (this.readonly) {
105
- return;
106
- }
107
- event.target.value = '';
108
- };
81
+ this.announceValues = true;
109
82
  /**
110
83
  * Handles any keydown events
111
84
  * Used for control keys
112
- *
113
85
  * @param event Event Object
114
86
  * @returns {void}
115
87
  */
@@ -135,7 +107,7 @@ let TimePicker = class TimePicker extends ControlElement {
135
107
  if ((hours !== null && isNaN(hours)) || oldHours === hours) {
136
108
  return;
137
109
  }
138
- this._hours = this.validUnit(hours, MIN_UNIT, MAX_HOURS, oldHours);
110
+ this._hours = TimePicker_1.validUnit(hours, MIN_UNIT, MAX_HOURS, oldHours);
139
111
  if (this._hours !== oldHours) {
140
112
  this.requestUpdate('hours', oldHours);
141
113
  }
@@ -150,7 +122,6 @@ let TimePicker = class TimePicker extends ControlElement {
150
122
  /**
151
123
  * Minutes time segment
152
124
  * @param minutes minutes value
153
- * @default null
154
125
  * @returns {void}
155
126
  */
156
127
  set minutes(minutes) {
@@ -158,14 +129,14 @@ let TimePicker = class TimePicker extends ControlElement {
158
129
  if ((minutes !== null && isNaN(minutes)) || oldMinutes === minutes) {
159
130
  return;
160
131
  }
161
- this._minutes = this.validUnit(minutes, MIN_UNIT, MAX_MINUTES, oldMinutes);
132
+ this._minutes = TimePicker_1.validUnit(minutes, MIN_UNIT, MAX_MINUTES, oldMinutes);
162
133
  if (this._minutes !== oldMinutes) {
163
134
  this.requestUpdate('minutes', oldMinutes);
164
135
  }
165
136
  }
166
137
  /**
167
138
  * Get minutes value
168
- * @returns hours
139
+ * @returns minutes
169
140
  */
170
141
  get minutes() {
171
142
  return this._minutes;
@@ -173,7 +144,6 @@ let TimePicker = class TimePicker extends ControlElement {
173
144
  /**
174
145
  * Seconds time segment
175
146
  * @param seconds seconds value
176
- * @default null
177
147
  * @returns {void}
178
148
  */
179
149
  set seconds(seconds) {
@@ -181,7 +151,7 @@ let TimePicker = class TimePicker extends ControlElement {
181
151
  if ((seconds !== null && isNaN(seconds)) || oldSeconds === seconds) {
182
152
  return;
183
153
  }
184
- this._seconds = this.validUnit(seconds, MIN_UNIT, MAX_SECONDS, oldSeconds);
154
+ this._seconds = TimePicker_1.validUnit(seconds, MIN_UNIT, MAX_SECONDS, oldSeconds);
185
155
  if (this._seconds !== oldSeconds) {
186
156
  this.requestUpdate('seconds', oldSeconds);
187
157
  }
@@ -195,7 +165,6 @@ let TimePicker = class TimePicker extends ControlElement {
195
165
  }
196
166
  /**
197
167
  * Value of the element
198
- * @default -
199
168
  * @param value Element value
200
169
  */
201
170
  set value(value) {
@@ -228,6 +197,19 @@ let TimePicker = class TimePicker extends ControlElement {
228
197
  }
229
198
  return this.currentTimeString;
230
199
  }
200
+ /**
201
+ * State to select text in the segment
202
+ * Used to asynchronously select text after render cycle is complete
203
+ * @param segment Selected segment or null
204
+ */
205
+ set selectedSegment(segment) {
206
+ const oldSelectedSegment = this._selectedSegment;
207
+ this._selectedSegment = segment;
208
+ this.requestUpdate('selectedSegment', oldSelectedSegment);
209
+ }
210
+ get selectedSegment() {
211
+ return this._selectedSegment;
212
+ }
231
213
  /**
232
214
  * Return the current time string, based on the current hours, minutes and seconds.
233
215
  * Used internally to set the value string after updates.
@@ -247,61 +229,105 @@ let TimePicker = class TimePicker extends ControlElement {
247
229
  return this.showSeconds || this.valueWithSeconds;
248
230
  }
249
231
  /**
250
- * Formats the hours value
232
+ * Get hours taking into account AM/PM placeholder
251
233
  */
252
- get formattedHours() {
234
+ get periodHours() {
253
235
  const _hours = this.hours;
254
236
  let hours = _hours;
255
237
  if (_hours !== null) {
256
238
  hours = this.amPm && _hours > HOURS_OF_NOON
257
239
  ? _hours - HOURS_OF_NOON : this.amPm && !_hours ? HOURS_OF_NOON : _hours;
258
240
  }
259
- return this.formattedUnit(hours);
241
+ return hours;
242
+ }
243
+ /**
244
+ * Formats the hours value
245
+ */
246
+ get formattedHours() {
247
+ return TimePicker_1.formattedUnit(this.periodHours);
260
248
  }
261
249
  /**
262
250
  * Formats the minutes value
263
251
  */
264
252
  get formattedMinutes() {
265
- return this.formattedUnit(this.minutes);
253
+ return TimePicker_1.formattedUnit(this.minutes);
266
254
  }
267
255
  /**
268
256
  * Formats the seconds value
269
- * @returns Formatted number
270
257
  */
271
258
  get formattedSeconds() {
272
- return this.formattedUnit(this.seconds);
259
+ return TimePicker_1.formattedUnit(this.seconds);
260
+ }
261
+ /**
262
+ * Observes attribute change for `attributeChangedCallback`
263
+ */
264
+ static get observedAttributes() {
265
+ const observed = super.observedAttributes;
266
+ return ['role'].concat(observed);
267
+ }
268
+ /**
269
+ * Synchronizes attribute value
270
+ * @param name attribute name
271
+ * @param oldValue old attribute value
272
+ * @param newValue new attribute value
273
+ * @returns {void}
274
+ */
275
+ attributeChangedCallback(name, oldValue, newValue) {
276
+ super.attributeChangedCallback(name, oldValue, newValue);
277
+ if (name === 'role') {
278
+ this.announceValues = !(!newValue || newValue === 'none' || newValue === 'presentation');
279
+ }
273
280
  }
274
281
  /**
275
282
  * On first updated life-cycle
276
- *
277
283
  * @param changedProperties changed properties
278
284
  * @returns {void}
279
285
  */
280
286
  firstUpdated(changedProperties) {
281
287
  super.firstUpdated(changedProperties);
282
- // add events
283
- this.renderRoot.addEventListener('blur', this.onBlur, true);
284
- this.renderRoot.addEventListener('focus', this.onFocus, true);
285
288
  this.renderRoot.addEventListener('keydown', this.onKeydown, true);
286
289
  }
287
290
  /**
288
291
  * On updated life-cycle
289
- *
290
292
  * @param changedProperties changed properties
291
293
  * @returns {void}
292
294
  */
293
295
  updated(changedProperties) {
294
296
  super.updated(changedProperties);
295
297
  /* istanbul ignore next */
296
- if (this.hasTimeChanged(changedProperties) && this.isMobile) {
298
+ if (TimePicker_1.hasTimeChanged(changedProperties) && this.isMobile) {
297
299
  this.updateMobileTimePickerValue();
298
300
  }
301
+ if (this.selectedSegment && changedProperties.has('selectedSegment')) {
302
+ void this.selectSegment();
303
+ }
304
+ }
305
+ /**
306
+ * Select text in input when update element is complete
307
+ * @returns returns a promise void
308
+ */
309
+ async selectSegment() {
310
+ var _a;
311
+ await this.updateComplete;
312
+ switch (this.selectedSegment) {
313
+ case Segment.HOURS:
314
+ this.hoursInput.select();
315
+ break;
316
+ case Segment.MINUTES:
317
+ this.minutesInput.select();
318
+ break;
319
+ case Segment.SECONDS:
320
+ (_a = this.secondsInput) === null || _a === void 0 ? void 0 : _a.select();
321
+ break;
322
+ // no default
323
+ }
324
+ // Silently clear selected segment to ensure it can be reselected
325
+ this._selectedSegment = null;
299
326
  }
300
327
  /**
301
328
  * Overwrite validation method for value
302
- *
303
329
  * @param value value
304
- * @returns {boolean} result
330
+ * @returns True if value is valid
305
331
  */
306
332
  isValidValue(value) {
307
333
  return value === '' || isValidTime(value);
@@ -346,21 +372,20 @@ let TimePicker = class TimePicker extends ControlElement {
346
372
  * @param changedProperties changed properties
347
373
  * @returns True if changed
348
374
  */
349
- hasTimeChanged(changedProperties) {
375
+ static hasTimeChanged(changedProperties) {
350
376
  return changedProperties.has('hours')
351
377
  || changedProperties.has('minutes')
352
378
  || changedProperties.has('seconds');
353
379
  }
354
380
  /**
355
381
  * Validates a given unit against a min and max value, returning a fallback if invalid.
356
- *
357
382
  * @param unit Unit to validate
358
383
  * @param min Minimum allowed
359
384
  * @param max Maximum allowed
360
385
  * @param fallback Fallback value to use, if unit is invalid
361
386
  * @returns unit or fallback or 0 value
362
387
  */
363
- validUnit(unit, min, max, fallback) {
388
+ static validUnit(unit, min, max, fallback) {
364
389
  if (unit === null) {
365
390
  return null;
366
391
  }
@@ -371,7 +396,6 @@ let TimePicker = class TimePicker extends ControlElement {
371
396
  }
372
397
  /**
373
398
  * Handles value change from native time picker on mobile devices
374
- *
375
399
  * @param event Event Object
376
400
  * @returns {void}
377
401
  */
@@ -381,7 +405,6 @@ let TimePicker = class TimePicker extends ControlElement {
381
405
  }
382
406
  /**
383
407
  * Helper, used to update the mobile time picker value
384
- *
385
408
  * @returns {void}
386
409
  */
387
410
  /* istanbul ignore next */
@@ -390,9 +413,57 @@ let TimePicker = class TimePicker extends ControlElement {
390
413
  this.mtpInput.value = this.value;
391
414
  }
392
415
  }
416
+ /**
417
+ * Handles action when input focused change
418
+ * @param event Focus change event
419
+ * @returns {void}
420
+ */
421
+ onInputFocusedChanged(event) {
422
+ const target = event.target;
423
+ const focused = event.detail.value;
424
+ let segment;
425
+ if (target === this.hoursInput) {
426
+ segment = Segment.HOURS;
427
+ }
428
+ else if (target === this.minutesInput) {
429
+ segment = Segment.MINUTES;
430
+ }
431
+ else if (target === this.secondsInput) {
432
+ segment = Segment.SECONDS;
433
+ }
434
+ this.selectedSegment = focused && segment ? segment : null;
435
+ /* istanbul ignore next */
436
+ if (!segment || this.readonly) {
437
+ return;
438
+ }
439
+ const value = target.value;
440
+ if (value) {
441
+ this.updateTimeSegmentTo(segment, Number(value));
442
+ }
443
+ this.updateSegmentValue(segment);
444
+ }
445
+ /**
446
+ * Handles action when input value changes
447
+ * @param event Value change event
448
+ * @returns {void}
449
+ */
450
+ onInputValueChanged(event) {
451
+ // Make sure that the value can be reset to null
452
+ if (!event.detail.value) {
453
+ const target = event.target;
454
+ if (target === this.hoursInput) {
455
+ this.setSegmentAndNotify(Segment.HOURS, null);
456
+ }
457
+ else if (target === this.minutesInput) {
458
+ this.setSegmentAndNotify(Segment.MINUTES, null);
459
+ }
460
+ else if (target === this.secondsInput) {
461
+ this.setSegmentAndNotify(Segment.SECONDS, null);
462
+ }
463
+ }
464
+ }
393
465
  /**
394
466
  * Updates a time segment to the provided value
395
- *
396
467
  * @param segment Segment id
397
468
  * @param value Unit to change to
398
469
  * @returns {void}
@@ -405,7 +476,6 @@ let TimePicker = class TimePicker extends ControlElement {
405
476
  }
406
477
  /**
407
478
  * Updates the value of a time segment (element)
408
- *
409
479
  * @param segment Segment's name
410
480
  * @returns {void}
411
481
  */
@@ -426,12 +496,11 @@ let TimePicker = class TimePicker extends ControlElement {
426
496
  /**
427
497
  * Handle valid control keys and execute their corresponding commands
428
498
  * Will stop when readonly is set
429
- *
430
- * @param event Event Object
499
+ * @param event Keyboard event
431
500
  * @returns {void}
432
501
  */
433
502
  manageControlKeys(event) {
434
- if (this.readonly || this.disabled) {
503
+ if (this.readonly || this.disabled || event.defaultPrevented) {
435
504
  return;
436
505
  }
437
506
  switch (event.key) {
@@ -448,9 +517,6 @@ let TimePicker = class TimePicker extends ControlElement {
448
517
  case ' ':
449
518
  this.handleEnterKey(event);
450
519
  break;
451
- case 'Backspace':
452
- this.handleBackspaceKey(event);
453
- return;
454
520
  default:
455
521
  return;
456
522
  }
@@ -458,17 +524,18 @@ let TimePicker = class TimePicker extends ControlElement {
458
524
  }
459
525
  /**
460
526
  * Handles ENTER key press
461
- *
462
- * @param event Event Object
527
+ * @param event Keyboard event
463
528
  * @returns {void}
464
529
  */
465
530
  handleEnterKey(event) {
466
- event.target.blur();
531
+ if (event.target === this.toggleEl) {
532
+ this.toggle();
533
+ event.preventDefault();
534
+ }
467
535
  }
468
536
  /**
469
537
  * Handles UP key press
470
- *
471
- * @param event Event Object
538
+ * @param event Keyboard event
472
539
  * @returns {void}
473
540
  */
474
541
  handleUpKey(event) {
@@ -476,35 +543,15 @@ let TimePicker = class TimePicker extends ControlElement {
476
543
  }
477
544
  /**
478
545
  * Handle DOWN key press
479
- *
480
- * @param event Event Object
546
+ * @param event Keyboard event
481
547
  * @returns {void}
482
548
  */
483
549
  handleDownKey(event) {
484
550
  this.toggleOrModify(-1, event.target);
485
551
  }
486
- /**
487
- * Handle Backspace key press
488
- *
489
- * @param event Event Object
490
- * @returns {void}
491
- */
492
- handleBackspaceKey(event) {
493
- const target = event.target;
494
- if (target === this.hoursInput) {
495
- this.setSegmentAndNotify(Segment.HOURS, null);
496
- }
497
- else if (target === this.minutesInput) {
498
- this.setSegmentAndNotify(Segment.MINUTES, null);
499
- }
500
- else if (target === this.secondsInput) {
501
- this.setSegmentAndNotify(Segment.SECONDS, null);
502
- }
503
- }
504
552
  /**
505
553
  * Toggles the amPm flag or updates the time segment value.
506
554
  * Essentially a handler for user inputs on the control.
507
- *
508
555
  * @param amount to change value by
509
556
  * @param target Segment id
510
557
  * @returns {void}
@@ -526,7 +573,6 @@ let TimePicker = class TimePicker extends ControlElement {
526
573
  /**
527
574
  * Changes a time segment value by a specified amount.
528
575
  * Also updates parent values when rolling through cycles.
529
- *
530
576
  * @param amount Amount to change by
531
577
  * @param segment Segment id
532
578
  * @returns {void}
@@ -547,6 +593,7 @@ let TimePicker = class TimePicker extends ControlElement {
547
593
  }
548
594
  const value = addOffset(this.currentTimeString, offset);
549
595
  this.setValueAndNotify(value);
596
+ this.selectedSegment = segment;
550
597
  }
551
598
  /**
552
599
  * Gets the hours segment of the provided value
@@ -568,7 +615,6 @@ let TimePicker = class TimePicker extends ControlElement {
568
615
  }
569
616
  /**
570
617
  * Updates the value of the hours element
571
- *
572
618
  * @returns {void}
573
619
  */
574
620
  updateHoursSegmentValue() {
@@ -578,7 +624,6 @@ let TimePicker = class TimePicker extends ControlElement {
578
624
  }
579
625
  /**
580
626
  * Updated the value of the minutes element
581
- *
582
627
  * @returns {void}
583
628
  */
584
629
  updateMinutesSegmentValue() {
@@ -588,7 +633,6 @@ let TimePicker = class TimePicker extends ControlElement {
588
633
  }
589
634
  /**
590
635
  * Updates the value of the seconds element
591
- *
592
636
  * @returns {void}
593
637
  */
594
638
  updateSecondsSegmentValue() {
@@ -598,32 +642,28 @@ let TimePicker = class TimePicker extends ControlElement {
598
642
  }
599
643
  /**
600
644
  * Formats a given number and prefixes a 0 on numbers lower than 10
601
- *
602
645
  * @param n Number to format
603
646
  * @returns Formatted number
604
647
  */
605
- formattedUnit(n) {
648
+ static formattedUnit(n) {
606
649
  return n === null ? '' : padNumber(n, 2);
607
650
  }
608
651
  /**
609
652
  * Returns `true` or `false` depending on whether the hours are before, or, after noon
610
- *
611
- * @returns Result
653
+ * @returns True if time is AM
612
654
  */
613
655
  isAM() {
614
656
  return isAM(this.currentTimeString);
615
657
  }
616
658
  /**
617
659
  * Returns opposite of isAM
618
- *
619
- * @returns Result
660
+ * @returns True if time is PM
620
661
  */
621
662
  isPM() {
622
663
  return isPM(this.currentTimeString);
623
664
  }
624
665
  /**
625
666
  * Toggles the AM/PM state
626
- *
627
667
  * @returns {void}
628
668
  */
629
669
  toggle() {
@@ -658,49 +698,137 @@ let TimePicker = class TimePicker extends ControlElement {
658
698
  }
659
699
  `;
660
700
  }
701
+ /**
702
+ * Template for Hours Segment
703
+ * @returns template hours segment
704
+ */
705
+ get hoursTemplate() {
706
+ const hours = this.formattedHours;
707
+ return html `<ef-number-field
708
+ id="hours"
709
+ part="input"
710
+ aria-label="${ifDefined(!isIE ? this.t('SELECT_HOURS', { value: this.periodHours }) : undefined)}"
711
+ no-spinner
712
+ transparent
713
+ min="${this.amPm ? 1 : MIN_UNIT}"
714
+ max="${this.amPm ? HOURS_OF_NOON : MAX_HOURS}"
715
+ .value="${hours}"
716
+ placeholder="${ifDefined(hours ? undefined : Placeholder.HOURS)}"
717
+ ?disabled="${this.disabled}"
718
+ ?readonly="${this.readonly}"
719
+ @value-changed="${this.onInputValueChanged}"
720
+ @focused-changed=${this.onInputFocusedChanged}></ef-number-field>`;
721
+ }
722
+ /**
723
+ * Template for Minutes Segment
724
+ * @returns template minutes segment
725
+ */
726
+ get minutesTemplate() {
727
+ const minutes = this.formattedMinutes;
728
+ return html `<ef-number-field
729
+ id="minutes"
730
+ aria-label="${ifDefined(!isIE ? this.t('SELECT_MINUTES', { value: this.minutes }) : undefined)}"
731
+ part="input"
732
+ no-spinner
733
+ min="${MIN_UNIT}"
734
+ max="${MAX_MINUTES}"
735
+ .value="${minutes}"
736
+ placeholder="${ifDefined(minutes ? undefined : Placeholder.MINUTES)}"
737
+ ?readonly="${this.readonly}"
738
+ ?disabled="${this.disabled}"
739
+ transparent
740
+ @value-changed="${this.onInputValueChanged}"
741
+ @focused-changed=${this.onInputFocusedChanged}></ef-number-field>`;
742
+ }
661
743
  /**
662
744
  * Template for Seconds Segment
663
- *
664
- * @returns Seconds segment
745
+ * @returns template seconds segment
665
746
  */
666
- getSecondsHtml() {
667
- return this.isShowSeconds ? html `
668
- <span part="divider"></span>
747
+ get secondsTemplate() {
748
+ const seconds = this.formattedSeconds;
749
+ return html `
669
750
  <ef-number-field
670
751
  id="seconds"
671
752
  part="input"
753
+ aria-label="${ifDefined(!isIE ? this.t('SELECT_SECONDS', { value: this.seconds }) : undefined)}"
672
754
  no-spinner
673
755
  min="${MIN_UNIT}"
674
756
  max="${MAX_SECONDS}"
675
- .value="${this.formattedSeconds}"
676
- placeholder="${this.formattedSeconds || Placeholder.SECONDS}"
757
+ .value="${seconds}"
758
+ placeholder="${ifDefined(seconds ? undefined : Placeholder.SECONDS)}"
677
759
  ?readonly="${this.readonly}"
678
760
  ?disabled="${this.disabled}"
679
- transparent></ef-number-field>
680
- ` : null;
761
+ transparent
762
+ @value-changed="${this.onInputValueChanged}"
763
+ @focused-changed=${this.onInputFocusedChanged}></ef-number-field>`;
681
764
  }
682
765
  /**
683
766
  * Template for AmPm Segment
684
- *
685
767
  * @returns Am/Pm segment
686
768
  */
687
- getAmPmHtml() {
769
+ get getAmPmHtml() {
688
770
  const hasHours = this.hours !== null;
689
771
  return this.amPm ? html `
690
- <div id="toggle" part="toggle" @tap=${this.toggle} tabindex="0">
691
- <div part="toggle-item" ?active=${hasHours && this.isAM()}>AM</div>
692
- <div part="toggle-item" ?active=${hasHours && this.isPM()}>PM</div>
772
+ <div role="listbox"
773
+ aria-label="${this.t('TOGGLE_TIME_PERIOD')}"
774
+ aria-activedescendant="${ifDefined(hasHours ? this.isAM() ? 'toggle-am' : 'toggle-pm' : undefined)}"
775
+ id="toggle"
776
+ part="toggle"
777
+ @tap=${this.toggle}
778
+ tabindex="0">
779
+ <div
780
+ aria-label="${this.t('BEFORE_MIDDAY')}"
781
+ role="option"
782
+ id="toggle-am"
783
+ part="toggle-item"
784
+ ?active=${hasHours && this.isAM()}>AM</div>
785
+ <div
786
+ aria-label="${this.t('AFTER_MIDDAY')}"
787
+ role="option"
788
+ id="toggle-pm"
789
+ part="toggle-item"
790
+ ?active=${hasHours && this.isPM()}>PM</div>
693
791
  </div>
694
792
  ` : null;
695
793
  }
696
794
  /**
697
795
  * Native input's template for mobile
698
- *
699
796
  * @returns input
700
797
  */
701
- getNativeInputForMobile() {
798
+ get nativeInputForMobile() {
702
799
  return this.isMobile ? html `<input id="mtp" type="time" @change=${this.onMobileTimeChange}>` : null;
703
800
  }
801
+ /**
802
+ * A template used to notify currently selected value for screen readers
803
+ * @returns template result
804
+ */
805
+ get selectionTemplate() {
806
+ if (isIE || !this.announceValues) {
807
+ return;
808
+ }
809
+ const value = this.value;
810
+ const showSeconds = this.isShowSeconds;
811
+ const amPm = this.amPm;
812
+ return html `<div
813
+ part="aria-selection"
814
+ aria-live="polite"
815
+ aria-label="${this.t('SELECTED', {
816
+ value: value ? parse(value) : null,
817
+ showSeconds,
818
+ amPm
819
+ })}"></div>`;
820
+ }
821
+ /**
822
+ * Get time input template
823
+ * @returns template result
824
+ */
825
+ get inputTemplate() {
826
+ return html `
827
+ ${this.hoursTemplate}
828
+ ${TimePicker_1.dividerTemplate}
829
+ ${this.minutesTemplate}
830
+ ${this.isShowSeconds ? html `${TimePicker_1.dividerTemplate}${this.secondsTemplate}` : undefined}`;
831
+ }
704
832
  /**
705
833
  * A `TemplateResult` that will be used
706
834
  * to render the updated internal template.
@@ -708,35 +836,18 @@ let TimePicker = class TimePicker extends ControlElement {
708
836
  */
709
837
  render() {
710
838
  return html `
711
- <ef-number-field
712
- id="hours"
713
- part="input"
714
- no-spinner
715
- transparent
716
- min="${this.amPm ? 1 : MIN_UNIT}"
717
- max="${this.amPm ? HOURS_OF_NOON : MAX_HOURS}"
718
- .value="${this.formattedHours}"
719
- placeholder="${this.formattedHours || Placeholder.HOURS}"
720
- ?disabled="${this.disabled}"
721
- ?readonly="${this.readonly}"></ef-number-field>
722
- <span part="divider"></span>
723
- <ef-number-field
724
- id="minutes"
725
- part="input"
726
- no-spinner
727
- min="${MIN_UNIT}"
728
- max="${MAX_MINUTES}"
729
- .value="${this.formattedMinutes}"
730
- placeholder="${this.formattedMinutes || Placeholder.MINUTES}"
731
- ?readonly="${this.readonly}"
732
- ?disabled="${this.disabled}"
733
- transparent></ef-number-field>
734
- ${this.getSecondsHtml()}
735
- ${this.getAmPmHtml()}
736
- ${this.getNativeInputForMobile()}
839
+ ${this.inputTemplate}
840
+ ${guard([this.value, this.lang, this.amPm], () => this.getAmPmHtml)}
841
+ ${guard([this.isMobile], () => this.nativeInputForMobile)}
842
+ ${guard([this.value, this.lang, this.showSeconds, this.amPm, this.announceValues], () => this.selectionTemplate)}
737
843
  `;
738
844
  }
739
845
  };
846
+ /**
847
+ * Template for divider segment
848
+ * @returns Divider segment
849
+ */
850
+ TimePicker.dividerTemplate = html `<span part="divider"></span>`;
740
851
  __decorate([
741
852
  property({ type: Number })
742
853
  ], TimePicker.prototype, "hours", null);
@@ -770,7 +881,16 @@ __decorate([
770
881
  __decorate([
771
882
  query('#toggle')
772
883
  ], TimePicker.prototype, "toggleEl", void 0);
773
- TimePicker = __decorate([
884
+ __decorate([
885
+ translate({ mode: 'directive', scope: 'ef-time-picker' })
886
+ ], TimePicker.prototype, "t", void 0);
887
+ __decorate([
888
+ state()
889
+ ], TimePicker.prototype, "selectedSegment", null);
890
+ __decorate([
891
+ state()
892
+ ], TimePicker.prototype, "announceValues", void 0);
893
+ TimePicker = TimePicker_1 = __decorate([
774
894
  customElement('ef-time-picker', {
775
895
  alias: 'coral-time-picker'
776
896
  })