Skip to content

Commit d829e79

Browse files
authored
feat(SegmentedControl): Add disabled option to control (#7454)
1 parent d831749 commit d829e79

File tree

3 files changed

+51
-1
lines changed

3 files changed

+51
-1
lines changed

packages/core/src/components/segmented-control/segmentedControl.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ export interface SegmentedControlProps
4242
extends Props,
4343
ControlledValueProps<string>,
4444
React.RefAttributes<HTMLDivElement> {
45+
/**
46+
* Whether this control should be disabled.
47+
*/
48+
disabled?: boolean;
49+
4550
/**
4651
* Whether the control should take up the full width of its container.
4752
*
@@ -111,6 +116,7 @@ export const SegmentedControl: React.FC<SegmentedControlProps> = React.forwardRe
111116
const {
112117
className,
113118
defaultValue,
119+
disabled,
114120
fill,
115121
inline,
116122
intent = Intent.NONE,
@@ -199,6 +205,7 @@ export const SegmentedControl: React.FC<SegmentedControlProps> = React.forwardRe
199205
return (
200206
<SegmentedControlOption
201207
{...option}
208+
disabled={option.disabled || disabled}
202209
intent={intent}
203210
isSelected={isSelected}
204211
key={option.value}

packages/core/test/segmented-control/segmentedControlTests.tsx

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { assert } from "chai";
17+
import { render, screen } from "@testing-library/react";
18+
import userEvent from "@testing-library/user-event";
19+
import { assert, expect } from "chai";
1820
import { mount } from "enzyme";
1921
import * as React from "react";
22+
import sinon from "sinon";
2023

2124
import { IconNames } from "@blueprintjs/icons";
2225

@@ -108,4 +111,41 @@ describe("<SegmentedControl>", () => {
108111
radioGroup.simulate("keydown", { key: "ArrowLeft" });
109112
assert.equal(document.activeElement, optionButtons[0], "move left and skip disabled");
110113
});
114+
115+
it("should select the correct option when clicked", () => {
116+
const onValueChange = sinon.spy();
117+
render(<SegmentedControl onValueChange={onValueChange} options={OPTIONS} />);
118+
const listButton = screen.getByRole("radio", { name: /list/i });
119+
120+
userEvent.click(listButton);
121+
122+
expect(onValueChange.called).to.be.true;
123+
expect(onValueChange.args[0][0]).to.equal("list");
124+
expect(listButton.getAttribute("aria-checked")).to.equal("true");
125+
});
126+
127+
it("should not allow disabled options to be selected", () => {
128+
const onValueChange = sinon.spy();
129+
render(<SegmentedControl onValueChange={onValueChange} options={OPTIONS} />);
130+
const gridButton = screen.getByRole("radio", { name: /grid/i });
131+
132+
userEvent.click(gridButton);
133+
134+
expect(onValueChange.called).to.be.false;
135+
expect(gridButton.getAttribute("aria-checked")).to.equal("false");
136+
});
137+
138+
it("should not allow any options to be selected when disabled", () => {
139+
const onValueChange = sinon.spy();
140+
render(<SegmentedControl onValueChange={onValueChange} options={OPTIONS} disabled={true} />);
141+
const listButton = screen.getByRole("radio", { name: /list/i });
142+
const gridButton = screen.getByRole("radio", { name: /grid/i });
143+
144+
userEvent.click(listButton);
145+
userEvent.click(gridButton);
146+
147+
expect(onValueChange.called).to.be.false;
148+
expect(listButton.getAttribute("aria-checked")).to.equal("false");
149+
expect(gridButton.getAttribute("aria-checked")).to.equal("false");
150+
});
111151
});

packages/docs-app/src/examples/core-examples/segmentedControlExample.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { IconNames } from "@blueprintjs/icons";
3131
import { SizeSelect } from "./common/sizeSelect";
3232

3333
export const SegmentedControlExample: React.FC<ExampleProps> = props => {
34+
const [disabled, setDisabled] = React.useState(false);
3435
const [fill, setFill] = React.useState(false);
3536
const [inline, setInline] = React.useState(false);
3637
const [intent, setIntent] = React.useState<SegmentedControlIntent>("none");
@@ -48,6 +49,7 @@ export const SegmentedControlExample: React.FC<ExampleProps> = props => {
4849
<Switch checked={inline} label="Inline" onChange={handleBooleanChange(setInline)} />
4950
<Switch checked={fill} label="Fill" onChange={handleBooleanChange(setFill)} />
5051
<Switch checked={withIcons} label="Icons" onChange={handleBooleanChange(setWithIcons)} />
52+
<Switch checked={disabled} label="Disabled" onChange={handleBooleanChange(setDisabled)} />
5153
<Divider />
5254
<FormGroup label="Intent">
5355
<SegmentedControl
@@ -69,6 +71,7 @@ export const SegmentedControlExample: React.FC<ExampleProps> = props => {
6971
<Example options={options} {...props}>
7072
<SegmentedControl
7173
defaultValue="list"
74+
disabled={disabled}
7275
fill={fill}
7376
inline={inline}
7477
intent={intent}

0 commit comments

Comments
 (0)