@sproutsocial/seeds-react-segmented-control 1.1.24 → 1.1.26
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.
- package/dist/esm/index.js +146 -51
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +30 -8
- package/dist/index.d.ts +30 -8
- package/dist/index.js +147 -52
- package/dist/index.js.map +1 -1
- package/dist/segmented-control.css +80 -0
- package/package.json +20 -9
- package/.eslintignore +0 -6
- package/.eslintrc.js +0 -4
- package/.turbo/turbo-build.log +0 -21
- package/CHANGELOG.md +0 -339
- package/jest.config.js +0 -9
- package/src/SegmentedControl.stories.tsx +0 -76
- package/src/SegmentedControl.tsx +0 -97
- package/src/SegmentedControlTypes.ts +0 -28
- package/src/__tests__/SegmentedControl.test.tsx +0 -57
- package/src/__tests__/SegmentedControl.typetest.tsx +0 -24
- package/src/index.ts +0 -5
- package/src/styled.d.ts +0 -7
- package/src/styles.ts +0 -121
- package/tsconfig.json +0 -9
- package/tsup.config.ts +0 -12
package/src/SegmentedControl.tsx
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
import * as ToggleGroup from "@radix-ui/react-toggle-group";
|
|
4
|
-
import { SegmentedControlContainer, ToggleButton } from "./styles";
|
|
5
|
-
import type {
|
|
6
|
-
TypeSegmentedControlProps,
|
|
7
|
-
TypeSegmentedControlItemProps,
|
|
8
|
-
} from "./SegmentedControlTypes";
|
|
9
|
-
|
|
10
|
-
let nameCounter = 0;
|
|
11
|
-
let idCounter = 0;
|
|
12
|
-
|
|
13
|
-
interface TypeSegmentedControlContext {
|
|
14
|
-
name: string;
|
|
15
|
-
selectedValue: string;
|
|
16
|
-
onChange: (e: React.SyntheticEvent<HTMLInputElement>) => void;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const SegmentedControlContext = React.createContext<
|
|
20
|
-
TypeSegmentedControlContext | null | undefined
|
|
21
|
-
>(null);
|
|
22
|
-
|
|
23
|
-
const SegmentedControlItem = ({
|
|
24
|
-
value,
|
|
25
|
-
children,
|
|
26
|
-
disabled,
|
|
27
|
-
...rest
|
|
28
|
-
}: TypeSegmentedControlItemProps) => {
|
|
29
|
-
return (
|
|
30
|
-
<ToggleGroup.Item value={value} disabled={disabled} asChild>
|
|
31
|
-
<ToggleButton
|
|
32
|
-
// TODO: Discuss dropping these
|
|
33
|
-
// We'd need to keep context, which seems unnecessary now
|
|
34
|
-
// data-segmentedcontrol-isactive={isChecked}
|
|
35
|
-
data-qa-segmentedcontrol-item={value}
|
|
36
|
-
// data-qa-segmentedcontrol-ischecked={isChecked === true}
|
|
37
|
-
disabled={disabled}
|
|
38
|
-
{...rest}
|
|
39
|
-
>
|
|
40
|
-
{children}
|
|
41
|
-
</ToggleButton>
|
|
42
|
-
</ToggleGroup.Item>
|
|
43
|
-
);
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const SegmentedControl = ({
|
|
47
|
-
selectedValue,
|
|
48
|
-
label,
|
|
49
|
-
onChange,
|
|
50
|
-
onValueChange,
|
|
51
|
-
children,
|
|
52
|
-
disabled,
|
|
53
|
-
...rest
|
|
54
|
-
}: TypeSegmentedControlProps) => {
|
|
55
|
-
const [name] = useState(`Racine-segmented-control-${nameCounter++}`);
|
|
56
|
-
return (
|
|
57
|
-
<ToggleGroup.Root
|
|
58
|
-
className="inline-flex space-x-px rounded bg-mauve6 shadow-[0_2px_10px] shadow-blackA4"
|
|
59
|
-
type="single"
|
|
60
|
-
value={selectedValue}
|
|
61
|
-
aria-label={label}
|
|
62
|
-
disabled={disabled}
|
|
63
|
-
onValueChange={(e) => {
|
|
64
|
-
// Radix allows deselecting a value by clicking on it when it's already selected,
|
|
65
|
-
// but we don't want to allow that behavior in our SegmentedControl.
|
|
66
|
-
if (!e) return;
|
|
67
|
-
|
|
68
|
-
onValueChange?.(e);
|
|
69
|
-
// Create a mock event to pass to onChange for backwards compatibility.
|
|
70
|
-
// We want to move towards onValueChange, but onChange is used by consumers currently so we need to support both for now.
|
|
71
|
-
const mockEvent = new Event("change", {
|
|
72
|
-
bubbles: true,
|
|
73
|
-
}) as unknown as React.SyntheticEvent<HTMLInputElement>;
|
|
74
|
-
Object.defineProperty(mockEvent, "target", { value: { value: e } });
|
|
75
|
-
Object.defineProperty(mockEvent, "currentTarget", {
|
|
76
|
-
value: { value: e },
|
|
77
|
-
});
|
|
78
|
-
onChange?.(mockEvent);
|
|
79
|
-
}}
|
|
80
|
-
asChild
|
|
81
|
-
>
|
|
82
|
-
<SegmentedControlContainer
|
|
83
|
-
data-qa-segmentedcontrol={label}
|
|
84
|
-
data-qa-segmentedcontrol-value={selectedValue}
|
|
85
|
-
disabled={disabled}
|
|
86
|
-
{...rest}
|
|
87
|
-
>
|
|
88
|
-
{children}
|
|
89
|
-
</SegmentedControlContainer>
|
|
90
|
-
</ToggleGroup.Root>
|
|
91
|
-
);
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
SegmentedControlItem.displayName = "SegmentedControl.Item";
|
|
95
|
-
SegmentedControl.Item = SegmentedControlItem;
|
|
96
|
-
|
|
97
|
-
export default SegmentedControl;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { TypeContainerProps } from "@sproutsocial/seeds-react-box";
|
|
2
|
-
import * as React from "react";
|
|
3
|
-
|
|
4
|
-
export interface TypeSegmentedControlItemProps {
|
|
5
|
-
/** The value of this item. Should be unique among sibling items. */
|
|
6
|
-
value: string;
|
|
7
|
-
children: React.ReactNode;
|
|
8
|
-
/** Disables user action and applies a disabled style on the component */
|
|
9
|
-
disabled?: boolean;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface TypeSegmentedControlProps extends TypeContainerProps {
|
|
13
|
-
/** The value of the currently selected item. Should match the value prop of one of the child items */
|
|
14
|
-
selectedValue: string;
|
|
15
|
-
|
|
16
|
-
/** The title of the segmented control, used for accessibility purposes */
|
|
17
|
-
label: string;
|
|
18
|
-
|
|
19
|
-
/** Called when the user selects a new item. You can access the value of the newly selected item using "event.target.value" */
|
|
20
|
-
onChange?: (e: React.SyntheticEvent<HTMLInputElement>) => void;
|
|
21
|
-
|
|
22
|
-
/** Called when the user selects a new item. You can access the value of the newly selected item using "event.target.value" */
|
|
23
|
-
onValueChange?: (value: string) => void;
|
|
24
|
-
|
|
25
|
-
/** Disables user action and applies a disabled style on the component */
|
|
26
|
-
disabled?: boolean;
|
|
27
|
-
children: React.ReactNode;
|
|
28
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
2
|
-
import {
|
|
3
|
-
render,
|
|
4
|
-
fireEvent,
|
|
5
|
-
screen,
|
|
6
|
-
} from "@sproutsocial/seeds-react-testing-library";
|
|
7
|
-
import SegmentedControl from "../SegmentedControl";
|
|
8
|
-
|
|
9
|
-
// @ts-ignore IDK what props should be
|
|
10
|
-
const StatefulSegmentedControl = (props) => {
|
|
11
|
-
const [value, setValue] = useState("1");
|
|
12
|
-
|
|
13
|
-
return (
|
|
14
|
-
<SegmentedControl
|
|
15
|
-
selectedValue={value}
|
|
16
|
-
label="Segmented control component"
|
|
17
|
-
onChange={(e) => setValue((e.target as HTMLInputElement).value)}
|
|
18
|
-
{...props}
|
|
19
|
-
>
|
|
20
|
-
<SegmentedControl.Item value="1">Test 1</SegmentedControl.Item>
|
|
21
|
-
<SegmentedControl.Item value="2">Test 2</SegmentedControl.Item>
|
|
22
|
-
<SegmentedControl.Item value="3">Test 3</SegmentedControl.Item>
|
|
23
|
-
</SegmentedControl>
|
|
24
|
-
);
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
describe("SegmentedControl", () => {
|
|
28
|
-
it("should select the correct item when clicked", async () => {
|
|
29
|
-
render(<StatefulSegmentedControl />);
|
|
30
|
-
|
|
31
|
-
const item1 = screen.getByText("Test 1");
|
|
32
|
-
const item2 = screen.getByText("Test 2");
|
|
33
|
-
const item3 = screen.getByText("Test 3");
|
|
34
|
-
|
|
35
|
-
expect(item1).toHaveAttribute("data-state", "on");
|
|
36
|
-
|
|
37
|
-
expect(item2).toHaveAttribute("data-state", "off");
|
|
38
|
-
|
|
39
|
-
expect(item3).toHaveAttribute("data-state", "off");
|
|
40
|
-
|
|
41
|
-
fireEvent.click(item3);
|
|
42
|
-
|
|
43
|
-
expect(item1).toHaveAttribute("data-state", "off");
|
|
44
|
-
|
|
45
|
-
expect(item2).toHaveAttribute("data-state", "off");
|
|
46
|
-
|
|
47
|
-
expect(item3).toHaveAttribute("data-state", "on");
|
|
48
|
-
|
|
49
|
-
fireEvent.click(item2);
|
|
50
|
-
|
|
51
|
-
expect(item1).toHaveAttribute("data-state", "off");
|
|
52
|
-
|
|
53
|
-
expect(item2).toHaveAttribute("data-state", "on");
|
|
54
|
-
|
|
55
|
-
expect(item3).toHaveAttribute("data-state", "off");
|
|
56
|
-
});
|
|
57
|
-
});
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import SegmentedControl from "../SegmentedControl";
|
|
3
|
-
|
|
4
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
5
|
-
function SegmentedControlTypes() {
|
|
6
|
-
const mockChange = jest.fn();
|
|
7
|
-
return (
|
|
8
|
-
<>
|
|
9
|
-
<SegmentedControl
|
|
10
|
-
selectedValue="orange"
|
|
11
|
-
label="Fruits"
|
|
12
|
-
onChange={mockChange}
|
|
13
|
-
height="34px"
|
|
14
|
-
ml="300"
|
|
15
|
-
>
|
|
16
|
-
<SegmentedControl.Item value="apple">Apple</SegmentedControl.Item>
|
|
17
|
-
<SegmentedControl.Item value="orange">Orange</SegmentedControl.Item>
|
|
18
|
-
<SegmentedControl.Item value="banana">Banana</SegmentedControl.Item>
|
|
19
|
-
</SegmentedControl>
|
|
20
|
-
{/* @ts-expect-error - test that invalid and missing props are rejected */}
|
|
21
|
-
<SegmentedControl />
|
|
22
|
-
</>
|
|
23
|
-
);
|
|
24
|
-
}
|
package/src/index.ts
DELETED
package/src/styled.d.ts
DELETED
package/src/styles.ts
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import styled, { css } from "styled-components";
|
|
2
|
-
import {
|
|
3
|
-
visuallyHidden,
|
|
4
|
-
focusRing,
|
|
5
|
-
disabled,
|
|
6
|
-
} from "@sproutsocial/seeds-react-mixins";
|
|
7
|
-
import Box from "@sproutsocial/seeds-react-box";
|
|
8
|
-
import Button from "@sproutsocial/seeds-react-button";
|
|
9
|
-
import type {
|
|
10
|
-
TypeSegmentedControlProps,
|
|
11
|
-
TypeSegmentedControlItemProps,
|
|
12
|
-
} from "./SegmentedControlTypes";
|
|
13
|
-
|
|
14
|
-
export const SegmentedControlContainer = styled(Box)<
|
|
15
|
-
Pick<TypeSegmentedControlProps, "disabled">
|
|
16
|
-
>`
|
|
17
|
-
border: 1px solid
|
|
18
|
-
${(props) => props.theme.colors.button.secondary.border.base};
|
|
19
|
-
border-radius: ${(props) => props.theme.radii.outer};
|
|
20
|
-
padding: ${(props) => props.theme.space[100]};
|
|
21
|
-
display: flex;
|
|
22
|
-
|
|
23
|
-
${(props) => props.disabled && disabled}
|
|
24
|
-
`;
|
|
25
|
-
|
|
26
|
-
export const ToggleButton = styled(Button)`
|
|
27
|
-
/* To match the height of buttons... 350 padding - 2px top and bottom padding of the parent - 1px border on top and bottom */
|
|
28
|
-
padding: calc(${(props) => props.theme.space[350]} - 6px);
|
|
29
|
-
flex: 1 1 auto;
|
|
30
|
-
display: flex;
|
|
31
|
-
align-items: center;
|
|
32
|
-
justify-content: center;
|
|
33
|
-
text-align: center;
|
|
34
|
-
border: 0;
|
|
35
|
-
|
|
36
|
-
& + & {
|
|
37
|
-
margin-left: ${(props) => props.theme.space[100]};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
&:hover {
|
|
41
|
-
background-color: ${(props) =>
|
|
42
|
-
props.theme.colors.listItem.background.hover};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
&[data-state="on"] {
|
|
46
|
-
color: ${(props) => props.theme.colors.text.inverse};
|
|
47
|
-
background-color: ${(props) =>
|
|
48
|
-
props.theme.colors.listItem.background.selected};
|
|
49
|
-
|
|
50
|
-
&:hover {
|
|
51
|
-
background-color: ${(props) =>
|
|
52
|
-
props.theme.colors.listItem.background.selected};
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
`;
|
|
56
|
-
|
|
57
|
-
export const SegmentedControlItemContainer = styled(Box)<
|
|
58
|
-
Pick<TypeSegmentedControlItemProps, "disabled">
|
|
59
|
-
>`
|
|
60
|
-
flex: 1 1 auto;
|
|
61
|
-
display: flex;
|
|
62
|
-
cursor: pointer;
|
|
63
|
-
|
|
64
|
-
& + & {
|
|
65
|
-
margin-left: ${(props) => props.theme.space[100]};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
&:focus-within label {
|
|
69
|
-
${focusRing}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
input {
|
|
73
|
-
${visuallyHidden}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
${(props) => props.disabled && disabled}
|
|
77
|
-
`;
|
|
78
|
-
|
|
79
|
-
interface TypeSegmentedControlState {
|
|
80
|
-
isActive: boolean;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export const SegmentedControlLabel = styled(Button)<TypeSegmentedControlState>`
|
|
84
|
-
flex: 1 1 auto;
|
|
85
|
-
display: flex;
|
|
86
|
-
align-items: center;
|
|
87
|
-
justify-content: center;
|
|
88
|
-
text-align: center;
|
|
89
|
-
color: ${(props) => props.theme.colors.text.body};
|
|
90
|
-
cursor: pointer;
|
|
91
|
-
font-size: ${(props) => props.theme.typography[200].fontSize};
|
|
92
|
-
/**
|
|
93
|
-
* Matches default line height of Icon. Also matches the overall height of
|
|
94
|
-
* Input, Select, and Button.
|
|
95
|
-
*/
|
|
96
|
-
line-height: 16px;
|
|
97
|
-
font-weight: ${(props) => props.theme.fontWeights.semibold};
|
|
98
|
-
|
|
99
|
-
border-radius: ${(props) => props.theme.radii.inner};
|
|
100
|
-
/* To match the height of buttons... 350 padding - 2px top and bottom padding of the parent - 1px border on top and bottom */
|
|
101
|
-
padding: calc(${(props) => props.theme.space[350]} - 6px);
|
|
102
|
-
transition: all ${(props) => props.theme.duration.fast};
|
|
103
|
-
|
|
104
|
-
&:hover {
|
|
105
|
-
background-color: ${(props) =>
|
|
106
|
-
props.theme.colors.listItem.background.hover};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
${(props) =>
|
|
110
|
-
props.isActive &&
|
|
111
|
-
css`
|
|
112
|
-
color: ${(props) => props.theme.colors.text.inverse};
|
|
113
|
-
background-color: ${(props) =>
|
|
114
|
-
props.theme.colors.listItem.background.selected};
|
|
115
|
-
|
|
116
|
-
&:hover {
|
|
117
|
-
background-color: ${(props) =>
|
|
118
|
-
props.theme.colors.listItem.background.selected};
|
|
119
|
-
}
|
|
120
|
-
`}
|
|
121
|
-
`;
|
package/tsconfig.json
DELETED
package/tsup.config.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "tsup";
|
|
2
|
-
|
|
3
|
-
export default defineConfig((options) => ({
|
|
4
|
-
entry: ["src/index.ts"],
|
|
5
|
-
format: ["cjs", "esm"],
|
|
6
|
-
clean: true,
|
|
7
|
-
legacyOutput: true,
|
|
8
|
-
dts: options.dts,
|
|
9
|
-
external: ["react"],
|
|
10
|
-
sourcemap: true,
|
|
11
|
-
metafile: options.metafile,
|
|
12
|
-
}));
|