Skip to content

Commit 96319ae

Browse files
authored
fix(input-time-picker): implement dialog behavior to improve a11y (#6837)
**Related Issue:** #6835 ## Summary Updates `input-time-picker` to use the dialog role for its time-picker popover along with descriptive text.
1 parent 7d26fc4 commit 96319ae

File tree

4 files changed

+60
-41
lines changed

4 files changed

+60
-41
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"chooseTime": "Choose time"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"chooseTime": "Choose time"
3+
}

src/components/input-time-picker/input-time-picker.e2e.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import {
99
hidden,
1010
labelable,
1111
reflects,
12-
renders
12+
renders,
13+
t9n
1314
} from "../../tests/commonTests";
1415
import { skipAnimations } from "../../tests/utils";
1516
import { html } from "../../../support/formatting";
@@ -27,6 +28,8 @@ describe("calcite-input-time-picker", () => {
2728
</calcite-label>
2829
`));
2930

31+
it.skip("supports t9n", () => t9n("calcite-input-time-picker"));
32+
3033
it("has defaults", async () =>
3134
defaults("calcite-input-time-picker", [
3235
{ propertyName: "scale", defaultValue: "m" },

src/components/input-time-picker/input-time-picker.tsx

+50-40
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,17 @@ import {
4040
import { formatTimeString, isValidTime, localizeTimeString } from "../../utils/time";
4141
import { Scale } from "../interfaces";
4242
import { TimePickerMessages } from "../time-picker/assets/time-picker/t9n";
43+
import { connectMessages, disconnectMessages, setUpMessages, T9nComponent } from "../../utils/t9n";
44+
import { InputTimePickerMessages } from "./assets/input-time-picker/t9n";
4345
import { CSS } from "./resources";
44-
import { toAriaBoolean } from "../../utils/dom";
4546

4647
@Component({
4748
tag: "calcite-input-time-picker",
4849
styleUrl: "input-time-picker.scss",
4950
shadow: {
5051
delegatesFocus: true
51-
}
52+
},
53+
assetsDirs: ["assets"]
5254
})
5355
export class InputTimePicker
5456
implements
@@ -57,7 +59,8 @@ export class InputTimePicker
5759
InteractiveComponent,
5860
FloatingUIComponent,
5961
LocalizedComponent,
60-
LoadableComponent
62+
LoadableComponent,
63+
T9nComponent
6164
{
6265
//--------------------------------------------------------------------------
6366
//
@@ -118,7 +121,21 @@ export class InputTimePicker
118121
/**
119122
* Use this property to override individual strings used by the component.
120123
*/
121-
@Prop() messagesOverrides: Partial<TimePickerMessages>;
124+
// eslint-disable-next-line @stencil-community/strict-mutable -- updated by t9n module
125+
@Prop({ mutable: true }) messageOverrides: Partial<InputTimePickerMessages & TimePickerMessages>;
126+
127+
/**
128+
* Made into a prop for testing purposes only
129+
*
130+
* @internal
131+
*/
132+
// eslint-disable-next-line @stencil-community/strict-mutable -- updated by t9n module
133+
@Prop({ mutable: true }) messages: InputTimePickerMessages;
134+
135+
@Watch("messageOverrides")
136+
onMessagesChange(): void {
137+
/* wired up by t9n util */
138+
}
122139

123140
/** Specifies the name of the component on form submission. */
124141
@Prop() name: string;
@@ -200,6 +217,8 @@ export class InputTimePicker
200217
//
201218
//--------------------------------------------------------------------------
202219

220+
@State() defaultMessages: InputTimePickerMessages;
221+
203222
@State() effectiveLocale = "";
204223

205224
@Watch("effectiveLocale")
@@ -480,10 +499,12 @@ export class InputTimePicker
480499

481500
connectLabel(this);
482501
connectForm(this);
502+
connectMessages(this);
483503
}
484504

485-
componentWillLoad(): void {
505+
async componentWillLoad(): Promise<void> {
486506
setUpLoadableComponent(this);
507+
await setUpMessages(this);
487508
}
488509

489510
componentDidLoad() {
@@ -495,6 +516,7 @@ export class InputTimePicker
495516
disconnectLabel(this);
496517
disconnectForm(this);
497518
disconnectLocalized(this);
519+
disconnectMessages(this);
498520
}
499521

500522
componentDidRender(): void {
@@ -508,57 +530,45 @@ export class InputTimePicker
508530
// --------------------------------------------------------------------------
509531

510532
render(): VNode {
511-
const { dialogId } = this;
533+
const { disabled, messages, readOnly, dialogId } = this;
512534
return (
513535
<Host onBlur={this.deactivate} onKeyDown={this.keyDownHandler}>
514-
<div
515-
aria-controls={dialogId}
516-
aria-haspopup="dialog"
517-
aria-label={this.name}
518-
aria-owns={dialogId}
519-
id={this.referenceElementId}
520-
role="combobox"
521-
>
522-
<div class="input-wrapper" onClick={this.onInputWrapperClick}>
523-
<calcite-input
524-
aria-autocomplete="none"
525-
aria-controls={this.dialogId}
526-
aria-expanded={toAriaBoolean(this.open)}
527-
aria-haspopup="dialog"
528-
disabled={this.disabled}
529-
icon="clock"
530-
label={getLabelText(this)}
531-
onCalciteInputInput={this.calciteInputInputHandler}
532-
onCalciteInternalInputBlur={this.calciteInternalInputBlurHandler}
533-
onCalciteInternalInputFocus={this.calciteInternalInputFocusHandler}
534-
onFocus={this.inputFocus}
535-
readOnly={this.readOnly}
536-
role="combobox"
537-
scale={this.scale}
538-
step={this.step}
539-
// eslint-disable-next-line react/jsx-sort-props
540-
ref={this.setCalciteInputEl}
541-
/>
542-
{this.renderToggleIcon(this.open)}
543-
</div>
536+
<div class="input-wrapper" onClick={this.onInputWrapperClick}>
537+
<calcite-input
538+
aria-autocomplete="none"
539+
aria-haspopup="dialog"
540+
disabled={disabled}
541+
icon="clock"
542+
id={this.referenceElementId}
543+
label={getLabelText(this)}
544+
onCalciteInputInput={this.calciteInputInputHandler}
545+
onCalciteInternalInputBlur={this.calciteInternalInputBlurHandler}
546+
onCalciteInternalInputFocus={this.calciteInternalInputFocusHandler}
547+
onFocus={this.inputFocus}
548+
readOnly={readOnly}
549+
role="combobox"
550+
scale={this.scale}
551+
step={this.step}
552+
// eslint-disable-next-line react/jsx-sort-props
553+
ref={this.setCalciteInputEl}
554+
/>
555+
{this.renderToggleIcon(this.open)}
544556
</div>
545557
<calcite-popover
546-
aria-live="polite"
547558
focusTrapDisabled={true}
548559
id={dialogId}
549-
label="Time Picker"
560+
label={messages.chooseTime}
550561
open={this.open}
551562
overlayPositioning={this.overlayPositioning}
552563
placement={this.placement}
553564
referenceElement={this.referenceElementId}
554-
role="dialog"
555565
triggerDisabled={true}
556566
// eslint-disable-next-line react/jsx-sort-props
557567
ref={this.setCalcitePopoverEl}
558568
>
559569
<calcite-time-picker
560570
lang={this.effectiveLocale}
561-
messageOverrides={this.messagesOverrides}
571+
messageOverrides={this.messageOverrides}
562572
numberingSystem={this.numberingSystem}
563573
onCalciteInternalTimePickerChange={this.timePickerChangeHandler}
564574
scale={this.scale}

0 commit comments

Comments
 (0)