Skip to content

Commit a2d64df

Browse files
LarryMattemeriouma
andcommitted
feat(DropdownList): ajout état readOnly (#1072)
DS-945 Ajout de l'état readOnly sur le composant DropdownList --------- Co-authored-by: Maxime Meriouma-Caron <[email protected]>
1 parent 9abcf35 commit a2d64df

File tree

7 files changed

+129
-9
lines changed

7 files changed

+129
-9
lines changed

packages/react/src/components/date-picker/date-picker.test.tsx.snap

+9
Original file line numberDiff line numberDiff line change
@@ -2614,6 +2614,7 @@ input + .c1 {
26142614
border: 1px solid #60666E;
26152615
border-radius: var(--border-radius);
26162616
box-sizing: border-box;
2617+
color: #1B1C1E;
26172618
display: -webkit-box;
26182619
display: -webkit-flex;
26192620
display: -ms-flexbox;
@@ -3079,6 +3080,7 @@ label + .c3 {
30793080
aria-invalid="false"
30803081
aria-label="Select a month"
30813082
aria-labelledby="uuid2_label uuid2_listbox_october_label"
3083+
aria-readonly="false"
30823084
aria-required="false"
30833085
class="c14"
30843086
data-testid="month-select"
@@ -3121,6 +3123,7 @@ label + .c3 {
31213123
aria-invalid="false"
31223124
aria-label="Select a year"
31233125
aria-labelledby="uuid3_label uuid3_listbox_2010_label"
3126+
aria-readonly="false"
31243127
aria-required="false"
31253128
class="c14"
31263129
data-testid="year-select"
@@ -3918,6 +3921,7 @@ input + .c1 {
39183921
border: 1px solid #60666E;
39193922
border-radius: var(--border-radius);
39203923
box-sizing: border-box;
3924+
color: #1B1C1E;
39213925
display: -webkit-box;
39223926
display: -webkit-flex;
39233927
display: -ms-flexbox;
@@ -4389,6 +4393,7 @@ label + .c3 {
43894393
aria-invalid="false"
43904394
aria-label="Select a month"
43914395
aria-labelledby="uuid2_label uuid2_listbox_october_label"
4396+
aria-readonly="false"
43924397
aria-required="false"
43934398
class="c14"
43944399
data-testid="month-select"
@@ -4431,6 +4436,7 @@ label + .c3 {
44314436
aria-invalid="false"
44324437
aria-label="Select a year"
44334438
aria-labelledby="uuid3_label uuid3_listbox_2010_label"
4439+
aria-readonly="false"
44344440
aria-required="false"
44354441
class="c14"
44364442
data-testid="year-select"
@@ -5208,6 +5214,7 @@ input + .c1 {
52085214
border: 1px solid #60666E;
52095215
border-radius: var(--border-radius);
52105216
box-sizing: border-box;
5217+
color: #1B1C1E;
52115218
display: -webkit-box;
52125219
display: -webkit-flex;
52135220
display: -ms-flexbox;
@@ -5669,6 +5676,7 @@ label + .c3 {
56695676
aria-invalid="false"
56705677
aria-label="Select a month"
56715678
aria-labelledby="uuid2_label uuid2_listbox_october_label"
5679+
aria-readonly="false"
56725680
aria-required="false"
56735681
class="c14"
56745682
data-testid="month-select"
@@ -5711,6 +5719,7 @@ label + .c3 {
57115719
aria-invalid="false"
57125720
aria-label="Select a year"
57135721
aria-labelledby="uuid3_label uuid3_listbox_2010_label"
5722+
aria-readonly="false"
57145723
aria-required="false"
57155724
class="c14"
57165725
data-testid="year-select"

packages/react/src/components/dropdown-list/dropdown-list.test.tsx

+54
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,60 @@ describe('Dropdown list', () => {
8787
});
8888
});
8989

90+
describe('readonly state', () => {
91+
test('renders correctly with readOnly enabled', () => {
92+
const wrapper = shallow(
93+
<DropdownList options={provinces} readOnly label="ReadOnly Dropdown" />,
94+
);
95+
96+
const textbox = getByTestId(wrapper, 'textbox');
97+
expect(textbox.prop('aria-readonly')).toBe('true');
98+
});
99+
100+
test('does not open listbox when clicked in readOnly mode', () => {
101+
const wrapper = shallow(
102+
<DropdownList options={provinces} readOnly label="ReadOnly Dropdown" />,
103+
);
104+
105+
getByTestId(wrapper, 'textbox').simulate('click');
106+
107+
expect(findByTestId(wrapper, 'listbox').length).toEqual(0);
108+
});
109+
110+
test('does not respond to keyboard events in readOnly mode', () => {
111+
const wrapper = shallow(
112+
<DropdownList options={provinces} readOnly label="ReadOnly Dropdown" />,
113+
);
114+
115+
getByTestId(wrapper, 'textbox').simulate('keydown', {
116+
key: 'ArrowDown',
117+
preventDefault: jest.fn(),
118+
});
119+
120+
expect(findByTestId(wrapper, 'listbox').length).toEqual(0);
121+
});
122+
123+
test('readonly mode prevents option selection', () => {
124+
const onChangeMock = jest.fn();
125+
126+
const wrapper = shallow(
127+
<DropdownList
128+
options={provinces}
129+
readOnly
130+
onChange={onChangeMock}
131+
label="ReadOnly Dropdown"
132+
/>,
133+
);
134+
135+
getByTestId(wrapper, 'textbox').simulate('click');
136+
137+
const option = findByTestId(wrapper, 'listitem-qc');
138+
expect(option.exists()).toBe(false);
139+
140+
expect(onChangeMock).not.toHaveBeenCalled();
141+
});
142+
});
143+
90144
describe('default value', () => {
91145
test('defaultValue assigns this value to the input', () => {
92146
const wrapper = shallow(<DropdownList options={provinces} defaultValue="qc" />);

packages/react/src/components/dropdown-list/dropdown-list.test.tsx.snap

+11
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ input + .c2 {
229229
aria-expanded="true"
230230
aria-invalid="false"
231231
aria-labelledby="uuid1_label uuid1_listbox_ab_label"
232+
aria-readonly="false"
232233
aria-required="false"
233234
class="c4"
234235
data-testid="textbox"
@@ -599,6 +600,7 @@ input + .c2 {
599600
border: 1px solid #60666E;
600601
border-radius: var(--border-radius);
601602
box-sizing: border-box;
603+
color: #1B1C1E;
602604
display: -webkit-box;
603605
display: -webkit-flex;
604606
display: -ms-flexbox;
@@ -685,6 +687,7 @@ input + .c2 {
685687
aria-expanded="true"
686688
aria-invalid="false"
687689
aria-labelledby="uuid1_label uuid1_listbox_ab_label"
690+
aria-readonly="false"
688691
aria-required="false"
689692
class="c5"
690693
data-testid="textbox"
@@ -1078,6 +1081,7 @@ input + .c2 {
10781081
border: 1px solid #CD2C23;
10791082
border-radius: var(--border-radius);
10801083
box-sizing: border-box;
1084+
color: #1B1C1E;
10811085
display: -webkit-box;
10821086
display: -webkit-flex;
10831087
display: -ms-flexbox;
@@ -1167,6 +1171,7 @@ input + .c2 {
11671171
aria-expanded="true"
11681172
aria-invalid="true"
11691173
aria-labelledby="uuid1_label uuid1_listbox_ab_label"
1174+
aria-readonly="false"
11701175
aria-required="false"
11711176
class="c6"
11721177
data-testid="textbox"
@@ -1503,6 +1508,7 @@ exports[`Dropdown list matches the snapshot (mobile) 1`] = `
15031508
border: 1px solid #60666E;
15041509
border-radius: var(--border-radius);
15051510
box-sizing: border-box;
1511+
color: #1B1C1E;
15061512
display: -webkit-box;
15071513
display: -webkit-flex;
15081514
display: -ms-flexbox;
@@ -1571,6 +1577,7 @@ exports[`Dropdown list matches the snapshot (mobile) 1`] = `
15711577
aria-invalid="false"
15721578
aria-label="Select an option"
15731579
aria-labelledby="uuid1_label uuid1_listbox_ab_label"
1580+
aria-readonly="false"
15741581
aria-required="false"
15751582
class="c2"
15761583
data-testid="textbox"
@@ -1907,6 +1914,7 @@ exports[`Dropdown list matches the snapshot (multiselect) 1`] = `
19071914
border: 1px solid #60666E;
19081915
border-radius: var(--border-radius);
19091916
box-sizing: border-box;
1917+
color: #1B1C1E;
19101918
display: -webkit-box;
19111919
display: -webkit-flex;
19121920
display: -ms-flexbox;
@@ -1978,6 +1986,7 @@ exports[`Dropdown list matches the snapshot (multiselect) 1`] = `
19781986
aria-invalid="false"
19791987
aria-label="Select an option"
19801988
aria-labelledby="uuid1_label"
1989+
aria-readonly="false"
19811990
aria-required="false"
19821991
class="c2"
19831992
data-testid="textbox"
@@ -2502,6 +2511,7 @@ input + .c2 {
25022511
border: 1px solid #60666E;
25032512
border-radius: var(--border-radius);
25042513
box-sizing: border-box;
2514+
color: #1B1C1E;
25052515
display: -webkit-box;
25062516
display: -webkit-flex;
25072517
display: -ms-flexbox;
@@ -2583,6 +2593,7 @@ input + .c2 {
25832593
aria-expanded="true"
25842594
aria-invalid="false"
25852595
aria-labelledby="uuid1_label uuid1_listbox_ab_label"
2596+
aria-readonly="false"
25862597
aria-required="false"
25872598
class="c5"
25882599
data-testid="textbox"

packages/react/src/components/dropdown-list/dropdown-list.tsx

+43-7
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ interface TextboxProps {
3333
$disabled?: boolean;
3434
$isMobile: boolean;
3535
$isMultiselect?: boolean;
36+
$readOnly?: boolean;
3637
theme: ResolvedTheme;
3738
$valid: boolean;
3839
value: string;
@@ -42,17 +43,47 @@ export interface DropdownListOption extends ListboxOption {
4243
label: string;
4344
}
4445

45-
function getBorderColor({ $disabled, theme, $valid }: TextboxProps): string {
46+
function getBackgroundColor({ $disabled, $readOnly, theme }: TextboxProps): string {
47+
if ($disabled) {
48+
return theme.component['dropdown-list-input-disabled-background-color'];
49+
}
50+
if ($readOnly) {
51+
return theme.component['dropdown-list-input-readonly-background-color'];
52+
}
53+
54+
return theme.component['dropdown-list-input-background-color'];
55+
}
56+
57+
function getBorderColor({
58+
$disabled,
59+
$readOnly,
60+
theme,
61+
$valid,
62+
}: TextboxProps): string {
4663
if ($disabled) {
4764
return theme.component['dropdown-list-input-disabled-border-color'];
4865
}
66+
if ($readOnly) {
67+
return theme.component['dropdown-list-input-readonly-border-color'];
68+
}
4969
if (!$valid) {
5070
return theme.component['dropdown-list-input-error-border-color'];
5171
}
5272

5373
return theme.component['dropdown-list-input-border-color'];
5474
}
5575

76+
function getTextColor({ $disabled, $readOnly, theme }: TextboxProps): string {
77+
if ($disabled) {
78+
return theme.component['dropdown-list-input-disabled-text-color'];
79+
}
80+
if ($readOnly) {
81+
return theme.component['dropdown-list-input-readonly-text-color'];
82+
}
83+
84+
return theme.component['dropdown-list-input-text-color'];
85+
}
86+
5687
const StyledFieldContainer = styled(FieldContainer)`
5788
position: relative;
5889
`;
@@ -65,11 +96,11 @@ const StyledListbox = styled(Listbox)`
6596

6697
const Textbox = styled.div<TextboxProps>`
6798
align-items: center;
68-
background-color: ${({ $disabled, theme }) => ($disabled ? theme.component['dropdown-list-input-disabled-background-color'] : theme.component['dropdown-list-input-background-color'])};
99+
background-color: ${getBackgroundColor};
69100
border: 1px solid ${getBorderColor};
70101
border-radius: var(--border-radius);
71102
box-sizing: border-box;
72-
color: ${({ $disabled, theme }) => $disabled && theme.component['dropdown-list-input-disabled-text-color']};
103+
color: ${getTextColor};
73104
display: flex;
74105
justify-content: space-between;
75106
min-height: ${({ $isMobile }) => ($isMobile ? 'var(--size-2halfx)' : 'var(--size-2x)')};
@@ -102,10 +133,10 @@ const ListBoxTag = styled(Tag)`
102133
}
103134
`;
104135

105-
const Arrow = styled(Icon)<{ $disabled?: boolean }>`
136+
const Arrow = styled(Icon)<{ $disabled?: boolean, $readOnly?: boolean }>`
106137
align-items: center;
107138
color: ${({ $disabled, theme }) => ($disabled ? theme.component['dropdown-list-arrow-disabled-color'] : theme.component['dropdown-list-arrow-color'])};
108-
display: flex;
139+
display: ${({ $readOnly }) => ($readOnly ? 'none' : 'flex')};
109140
flex: none;
110141
height: var(--size-1x);
111142
margin-left: auto;
@@ -150,6 +181,7 @@ export interface DropdownListProps<M extends boolean | undefined> {
150181
name?: string;
151182
options: DropdownListOption[];
152183
required?: boolean;
184+
readOnly?: boolean;
153185
tooltip?: TooltipProps;
154186
toggletip?: ToggletipProps;
155187
/**
@@ -200,6 +232,7 @@ export const DropdownList: VoidFunctionComponent<DropdownListProps<boolean | und
200232
onClose,
201233
options,
202234
name,
235+
readOnly,
203236
required,
204237
tooltip,
205238
toggletip,
@@ -282,7 +315,7 @@ export const DropdownList: VoidFunctionComponent<DropdownListProps<boolean | und
282315
}
283316

284317
function openListbox(): void {
285-
if (disabled) {
318+
if (disabled || readOnly) {
286319
return;
287320
}
288321

@@ -452,7 +485,7 @@ export const DropdownList: VoidFunctionComponent<DropdownListProps<boolean | und
452485
aria-hidden="true"
453486
data-testid={`listboxtag-${option.value}`}
454487
key={option.value}
455-
onRemove={handleTagRemove}
488+
onRemove={readOnly ? undefined : handleTagRemove}
456489
value={{ id: option.value, label: option.label }}
457490
/>
458491
));
@@ -502,6 +535,7 @@ export const DropdownList: VoidFunctionComponent<DropdownListProps<boolean | und
502535
aria-expanded={open}
503536
aria-invalid={!valid ? 'true' : 'false'}
504537
aria-labelledby={ariaLabelledBy}
538+
aria-readonly={readOnly ? 'true' : 'false'}
505539
aria-required={required ? 'true' : 'false'}
506540
data-testid="textbox"
507541
id={id}
@@ -512,6 +546,7 @@ export const DropdownList: VoidFunctionComponent<DropdownListProps<boolean | und
512546
onClick={handleTextboxClick}
513547
onKeyDown={handleTextboxKeyDown}
514548
ref={textboxRef}
549+
$readOnly={readOnly}
515550
role="combobox"
516551
tabIndex={0}
517552
$valid={valid}
@@ -534,6 +569,7 @@ export const DropdownList: VoidFunctionComponent<DropdownListProps<boolean | und
534569
aria-hidden="true"
535570
data-testid="arrow"
536571
$disabled={disabled}
572+
$readOnly={readOnly}
537573
name={open ? 'chevronUp' : 'chevronDown'}
538574
size={device === 'mobile' ? '24' : '16'}
539575
/>

packages/react/src/components/icon/icon.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import Phone from 'feather-icons/dist/icons/phone.svg';
3636
import PlusSign from 'feather-icons/dist/icons/plus.svg';
3737
import Transfer from 'feather-icons/dist/icons/refresh-cw.svg';
3838
import Search from 'feather-icons/dist/icons/search.svg';
39+
import Send from 'feather-icons/dist/icons/send.svg';
3940
import Settings from 'feather-icons/dist/icons/settings.svg';
4041
import Star from 'feather-icons/dist/icons/star.svg';
4142
import Trash from 'feather-icons/dist/icons/trash-2.svg';
@@ -121,6 +122,7 @@ const iconMapping = {
121122
plusSign: PlusSign,
122123
reorder: Reorder,
123124
search: Search,
125+
send: Send,
124126
settings: Settings,
125127
star: Star,
126128
table: Table,

0 commit comments

Comments
 (0)