@sproutsocial/seeds-react-segmented-control 1.0.13 → 1.1.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.
- package/.turbo/turbo-build.log +11 -11
- package/CHANGELOG.md +22 -0
- package/dist/esm/index.js +68 -48
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +66 -46
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
- package/src/SegmentedControl.stories.tsx +6 -2
- package/src/SegmentedControl.tsx +41 -45
- package/src/SegmentedControlTypes.ts +4 -1
- package/src/__tests__/SegmentedControl.test.tsx +9 -36
- package/src/styles.ts +33 -5
package/.turbo/turbo-build.log
CHANGED
|
@@ -3,19 +3,19 @@ $ tsup --dts
|
|
|
3
3
|
[34mCLI[39m Building entry: src/index.ts
|
|
4
4
|
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
5
5
|
[34mCLI[39m tsup v8.5.0
|
|
6
|
-
[34mCLI[39m Using tsup config: /home/runner/
|
|
6
|
+
[34mCLI[39m Using tsup config: /home/runner/_work/seeds/seeds/seeds-react/seeds-react-segmented-control/tsup.config.ts
|
|
7
7
|
[34mCLI[39m Target: es2022
|
|
8
8
|
[34mCLI[39m Cleaning output folder
|
|
9
9
|
[34mCJS[39m Build start
|
|
10
10
|
[34mESM[39m Build start
|
|
11
|
-
[
|
|
12
|
-
[
|
|
13
|
-
[
|
|
14
|
-
[
|
|
15
|
-
[
|
|
16
|
-
[
|
|
11
|
+
[32mCJS[39m [1mdist/index.js [22m[32m7.20 KB[39m
|
|
12
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m10.49 KB[39m
|
|
13
|
+
[32mCJS[39m ⚡️ Build success in 15ms
|
|
14
|
+
[32mESM[39m [1mdist/esm/index.js [22m[32m5.04 KB[39m
|
|
15
|
+
[32mESM[39m [1mdist/esm/index.js.map [22m[32m10.41 KB[39m
|
|
16
|
+
[32mESM[39m ⚡️ Build success in 14ms
|
|
17
17
|
[34mDTS[39m Build start
|
|
18
|
-
[32mDTS[39m ⚡️ Build success in
|
|
19
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m1.
|
|
20
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[32m1.
|
|
21
|
-
Done in
|
|
18
|
+
[32mDTS[39m ⚡️ Build success in 4008ms
|
|
19
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m1.66 KB[39m
|
|
20
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m1.66 KB[39m
|
|
21
|
+
Done in 5.48s.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @sproutsocial/seeds-react-segmented-control
|
|
2
2
|
|
|
3
|
+
## 1.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 1f356b4: Correct SegmentedControll accessibility, switch to radix, introduce simpler onValueChange callback
|
|
8
|
+
|
|
9
|
+
## 1.0.15
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [17d4f12]
|
|
14
|
+
- @sproutsocial/seeds-react-theme@3.6.0
|
|
15
|
+
- @sproutsocial/seeds-react-box@1.1.14
|
|
16
|
+
- @sproutsocial/seeds-react-mixins@4.3.1
|
|
17
|
+
|
|
18
|
+
## 1.0.14
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- Updated dependencies [5bb63e1]
|
|
23
|
+
- @sproutsocial/seeds-react-mixins@4.3.0
|
|
24
|
+
|
|
3
25
|
## 1.0.13
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
package/dist/esm/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/SegmentedControl.tsx
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
import { useState
|
|
4
|
-
import
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import * as ToggleGroup from "@radix-ui/react-toggle-group";
|
|
5
5
|
|
|
6
6
|
// src/styles.ts
|
|
7
7
|
import styled, { css } from "styled-components";
|
|
@@ -11,18 +11,42 @@ import {
|
|
|
11
11
|
disabled
|
|
12
12
|
} from "@sproutsocial/seeds-react-mixins";
|
|
13
13
|
import Box from "@sproutsocial/seeds-react-box";
|
|
14
|
-
import
|
|
14
|
+
import Button from "@sproutsocial/seeds-react-button";
|
|
15
15
|
var SegmentedControlContainer = styled(Box)`
|
|
16
16
|
border: 1px solid
|
|
17
17
|
${(props) => props.theme.colors.button.secondary.border.base};
|
|
18
18
|
border-radius: ${(props) => props.theme.radii.outer};
|
|
19
19
|
padding: ${(props) => props.theme.space[100]};
|
|
20
|
+
display: flex;
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
${(props) => props.disabled && disabled}
|
|
23
|
+
`;
|
|
24
|
+
var ToggleButton = styled(Button)`
|
|
25
|
+
/* To match the height of buttons... 350 padding - 2px top and bottom padding of the parent - 1px border on top and bottom */
|
|
26
|
+
padding: calc(${(props) => props.theme.space[350]} - 6px);
|
|
27
|
+
flex: 1 1 auto;
|
|
28
|
+
display: flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
justify-content: center;
|
|
31
|
+
text-align: center;
|
|
32
|
+
border: 0;
|
|
33
|
+
|
|
34
|
+
& + & {
|
|
35
|
+
margin-left: ${(props) => props.theme.space[100]};
|
|
23
36
|
}
|
|
24
37
|
|
|
25
|
-
|
|
38
|
+
&:hover {
|
|
39
|
+
background-color: ${(props) => props.theme.colors.listItem.background.hover};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&[data-state="on"] {
|
|
43
|
+
color: ${(props) => props.theme.colors.text.inverse};
|
|
44
|
+
background-color: ${(props) => props.theme.colors.listItem.background.selected};
|
|
45
|
+
|
|
46
|
+
&:hover {
|
|
47
|
+
background-color: ${(props) => props.theme.colors.listItem.background.selected};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
26
50
|
`;
|
|
27
51
|
var SegmentedControlItemContainer = styled(Box)`
|
|
28
52
|
flex: 1 1 auto;
|
|
@@ -43,7 +67,7 @@ var SegmentedControlItemContainer = styled(Box)`
|
|
|
43
67
|
|
|
44
68
|
${(props) => props.disabled && disabled}
|
|
45
69
|
`;
|
|
46
|
-
var SegmentedControlLabel = styled(
|
|
70
|
+
var SegmentedControlLabel = styled(Button)`
|
|
47
71
|
flex: 1 1 auto;
|
|
48
72
|
display: flex;
|
|
49
73
|
align-items: center;
|
|
@@ -79,9 +103,8 @@ var SegmentedControlLabel = styled(Text)`
|
|
|
79
103
|
`;
|
|
80
104
|
|
|
81
105
|
// src/SegmentedControl.tsx
|
|
82
|
-
import { jsx
|
|
106
|
+
import { jsx } from "react/jsx-runtime";
|
|
83
107
|
var nameCounter = 0;
|
|
84
|
-
var idCounter = 0;
|
|
85
108
|
var SegmentedControlContext = React.createContext(null);
|
|
86
109
|
var SegmentedControlItem = ({
|
|
87
110
|
value,
|
|
@@ -89,36 +112,22 @@ var SegmentedControlItem = ({
|
|
|
89
112
|
disabled: disabled2,
|
|
90
113
|
...rest
|
|
91
114
|
}) => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
return null;
|
|
95
|
-
}
|
|
96
|
-
const { name, selectedValue, onChange } = context;
|
|
97
|
-
const [id] = useState(`${name}-${idCounter++}`);
|
|
98
|
-
const isChecked = value === selectedValue;
|
|
99
|
-
return /* @__PURE__ */ jsxs(
|
|
100
|
-
SegmentedControlItemContainer,
|
|
115
|
+
return /* @__PURE__ */ jsx(
|
|
116
|
+
ToggleGroup.Item,
|
|
101
117
|
{
|
|
102
|
-
|
|
103
|
-
"
|
|
104
|
-
"data-qa-segmentedcontrol-ischecked": isChecked === true,
|
|
118
|
+
value,
|
|
119
|
+
"aria-label": "Left aligned",
|
|
105
120
|
disabled: disabled2,
|
|
106
|
-
|
|
107
|
-
children:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
onChange,
|
|
117
|
-
disabled: disabled2
|
|
118
|
-
}
|
|
119
|
-
),
|
|
120
|
-
/* @__PURE__ */ jsx(SegmentedControlLabel, { as: "label", htmlFor: id, isActive: isChecked, children })
|
|
121
|
-
]
|
|
121
|
+
asChild: true,
|
|
122
|
+
children: /* @__PURE__ */ jsx(
|
|
123
|
+
ToggleButton,
|
|
124
|
+
{
|
|
125
|
+
"data-qa-segmentedcontrol-item": value,
|
|
126
|
+
disabled: disabled2,
|
|
127
|
+
...rest,
|
|
128
|
+
children
|
|
129
|
+
}
|
|
130
|
+
)
|
|
122
131
|
}
|
|
123
132
|
);
|
|
124
133
|
};
|
|
@@ -126,29 +135,40 @@ var SegmentedControl = ({
|
|
|
126
135
|
selectedValue,
|
|
127
136
|
label,
|
|
128
137
|
onChange,
|
|
138
|
+
onValueChange,
|
|
129
139
|
children,
|
|
140
|
+
disabled: disabled2,
|
|
130
141
|
...rest
|
|
131
142
|
}) => {
|
|
132
143
|
const [name] = useState(`Racine-segmented-control-${nameCounter++}`);
|
|
133
144
|
return /* @__PURE__ */ jsx(
|
|
134
|
-
|
|
145
|
+
ToggleGroup.Root,
|
|
135
146
|
{
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
147
|
+
className: "inline-flex space-x-px rounded bg-mauve6 shadow-[0_2px_10px] shadow-blackA4",
|
|
148
|
+
type: "single",
|
|
149
|
+
value: selectedValue,
|
|
150
|
+
"aria-label": label,
|
|
151
|
+
disabled: disabled2,
|
|
152
|
+
onValueChange: (e) => {
|
|
153
|
+
onValueChange?.(e);
|
|
154
|
+
const mockEvent = new Event("change", {
|
|
155
|
+
bubbles: true
|
|
156
|
+
});
|
|
157
|
+
Object.defineProperty(mockEvent, "target", { value: { value: e } });
|
|
158
|
+
Object.defineProperty(mockEvent, "currentTarget", {
|
|
159
|
+
value: { value: e }
|
|
160
|
+
});
|
|
161
|
+
onChange?.(mockEvent);
|
|
140
162
|
},
|
|
141
|
-
|
|
163
|
+
asChild: true,
|
|
164
|
+
children: /* @__PURE__ */ jsx(
|
|
142
165
|
SegmentedControlContainer,
|
|
143
166
|
{
|
|
144
|
-
forwardedAs: "fieldset",
|
|
145
167
|
"data-qa-segmentedcontrol": label,
|
|
146
168
|
"data-qa-segmentedcontrol-value": selectedValue,
|
|
169
|
+
disabled: disabled2,
|
|
147
170
|
...rest,
|
|
148
|
-
children
|
|
149
|
-
/* @__PURE__ */ jsx("legend", { children: label }),
|
|
150
|
-
/* @__PURE__ */ jsx(Box2, { display: "flex", children })
|
|
151
|
-
]
|
|
171
|
+
children
|
|
152
172
|
}
|
|
153
173
|
)
|
|
154
174
|
}
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/SegmentedControl.tsx","../../src/styles.ts","../../src/SegmentedControlTypes.ts","../../src/index.ts"],"sourcesContent":["import * as React from \"react\";\nimport { useState, useContext } from \"react\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport {\n SegmentedControlContainer,\n SegmentedControlItemContainer,\n SegmentedControlLabel,\n} from \"./styles\";\nimport type {\n TypeSegmentedControlProps,\n TypeSegmentedControlItemProps,\n} from \"./SegmentedControlTypes\";\n\nlet nameCounter = 0;\nlet idCounter = 0;\n\ninterface TypeSegmentedControlContext {\n name: string;\n selectedValue: string;\n onChange: (e: React.SyntheticEvent<HTMLInputElement>) => void;\n}\n\nconst SegmentedControlContext = React.createContext<\n TypeSegmentedControlContext | null | undefined\n>(null);\n\nconst SegmentedControlItem = ({\n value,\n children,\n disabled,\n ...rest\n}: TypeSegmentedControlItemProps) => {\n const context = useContext(SegmentedControlContext);\n\n if (!context) {\n return null;\n }\n\n const { name, selectedValue, onChange } = context;\n\n /* eslint-disable-next-line */\n const [id] = useState(`${name}-${idCounter++}`);\n const isChecked = value === selectedValue;\n\n return (\n <SegmentedControlItemContainer\n data-segmentedcontrol-isactive={isChecked}\n data-qa-segmentedcontrol-item={value}\n data-qa-segmentedcontrol-ischecked={isChecked === true}\n disabled={disabled}\n {...rest}\n >\n <input\n type=\"radio\"\n id={id}\n name={name}\n value={value}\n checked={isChecked}\n onChange={onChange}\n disabled={disabled}\n />\n <SegmentedControlLabel as=\"label\" htmlFor={id} isActive={isChecked}>\n {children}\n </SegmentedControlLabel>\n </SegmentedControlItemContainer>\n );\n};\n\nconst SegmentedControl = ({\n selectedValue,\n label,\n onChange,\n children,\n ...rest\n}: TypeSegmentedControlProps) => {\n const [name] = useState(`Racine-segmented-control-${nameCounter++}`);\n return (\n <SegmentedControlContext.Provider\n value={{\n name,\n selectedValue,\n onChange,\n }}\n >\n <SegmentedControlContainer\n forwardedAs=\"fieldset\"\n data-qa-segmentedcontrol={label}\n data-qa-segmentedcontrol-value={selectedValue}\n {...rest}\n >\n <legend>{label}</legend>\n\n <Box display=\"flex\">{children}</Box>\n </SegmentedControlContainer>\n </SegmentedControlContext.Provider>\n );\n};\n\nSegmentedControlItem.displayName = \"SegmentedControl.Item\";\nSegmentedControl.Item = SegmentedControlItem;\n\nexport default SegmentedControl;\n","import styled, { css } from \"styled-components\";\nimport {\n visuallyHidden,\n focusRing,\n disabled,\n} from \"@sproutsocial/seeds-react-mixins\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport Text from \"@sproutsocial/seeds-react-text\";\nimport type {\n TypeSegmentedControlProps,\n TypeSegmentedControlItemProps,\n} from \"./SegmentedControlTypes\";\n\nexport const SegmentedControlContainer = styled(Box)<\n Pick<TypeSegmentedControlProps, \"disabled\">\n>`\n border: 1px solid\n ${(props) => props.theme.colors.button.secondary.border.base};\n border-radius: ${(props) => props.theme.radii.outer};\n padding: ${(props) => props.theme.space[100]};\n\n legend {\n ${visuallyHidden}\n }\n\n ${(props) => props.disabled && disabled}\n`;\n\nexport const SegmentedControlItemContainer = styled(Box)<\n Pick<TypeSegmentedControlItemProps, \"disabled\">\n>`\n flex: 1 1 auto;\n display: flex;\n cursor: pointer;\n\n & + & {\n margin-left: ${(props) => props.theme.space[100]};\n }\n\n &:focus-within label {\n ${focusRing}\n }\n\n input {\n ${visuallyHidden}\n }\n\n ${(props) => props.disabled && disabled}\n`;\n\ninterface TypeSegmentedControlState {\n isActive: boolean;\n}\n\nexport const SegmentedControlLabel = styled(Text)<TypeSegmentedControlState>`\n flex: 1 1 auto;\n display: flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n color: ${(props) => props.theme.colors.text.body};\n cursor: pointer;\n font-size: ${(props) => props.theme.typography[200].fontSize};\n /**\n\t* Matches default line height of Icon. Also matches the overall height of\n\t* Input, Select, and Button.\n\t*/\n line-height: 16px;\n font-weight: ${(props) => props.theme.fontWeights.semibold};\n\n border-radius: ${(props) => props.theme.radii.inner};\n /* To match the height of buttons... 350 padding - 2px top and bottom padding of the parent - 1px border on top and bottom */\n padding: calc(${(props) => props.theme.space[350]} - 6px);\n transition: all ${(props) => props.theme.duration.fast};\n\n &:hover {\n background-color: ${(props) =>\n props.theme.colors.listItem.background.hover};\n }\n\n ${(props) =>\n props.isActive &&\n css`\n color: ${(props) => props.theme.colors.text.inverse};\n background-color: ${(props) =>\n props.theme.colors.listItem.background.selected};\n\n &:hover {\n background-color: ${(props) =>\n props.theme.colors.listItem.background.selected};\n }\n `}\n`;\n","import type { TypeContainerProps } from \"@sproutsocial/seeds-react-box\";\nimport * as React from \"react\";\n\nexport interface TypeSegmentedControlItemProps {\n /** The value of this item. Should be unique among sibling items. */\n value: string;\n children: React.ReactNode;\n /** Disables user action and applies a disabled style on the component */\n disabled?: boolean;\n}\n\nexport interface TypeSegmentedControlProps extends TypeContainerProps {\n /** The value of the currently selected item. Should match the value prop of one of the child items */\n selectedValue: string;\n\n /** The title of the segmented control, used for accessibility purposes */\n label: string;\n\n /** Called when the user selects a new item. You can access the value of the newly selected item using \"event.target.value\" */\n onChange: (e: React.SyntheticEvent<HTMLInputElement>) => void;\n\n /** Disables user action and applies a disabled style on the component */\n disabled?: boolean;\n children: React.ReactNode;\n}\n","import SegmentedControl from \"./SegmentedControl\";\n\nexport default SegmentedControl;\nexport { SegmentedControl };\nexport * from \"./SegmentedControlTypes\";\n"],"mappings":"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","names":["Box","props","disabled","Box"]}
|
|
1
|
+
{"version":3,"sources":["../../src/SegmentedControl.tsx","../../src/styles.ts","../../src/SegmentedControlTypes.ts","../../src/index.ts"],"sourcesContent":["import * as React from \"react\";\nimport { useState } from \"react\";\nimport * as ToggleGroup from \"@radix-ui/react-toggle-group\";\nimport { SegmentedControlContainer, ToggleButton } from \"./styles\";\nimport type {\n TypeSegmentedControlProps,\n TypeSegmentedControlItemProps,\n} from \"./SegmentedControlTypes\";\n\nlet nameCounter = 0;\nlet idCounter = 0;\n\ninterface TypeSegmentedControlContext {\n name: string;\n selectedValue: string;\n onChange: (e: React.SyntheticEvent<HTMLInputElement>) => void;\n}\n\nconst SegmentedControlContext = React.createContext<\n TypeSegmentedControlContext | null | undefined\n>(null);\n\nconst SegmentedControlItem = ({\n value,\n children,\n disabled,\n ...rest\n}: TypeSegmentedControlItemProps) => {\n return (\n <ToggleGroup.Item\n value={value}\n aria-label=\"Left aligned\"\n disabled={disabled}\n asChild\n >\n <ToggleButton\n // TODO: Discuss dropping these\n // We'd need to keep context, which seems unnecessary now\n // data-segmentedcontrol-isactive={isChecked}\n data-qa-segmentedcontrol-item={value}\n // data-qa-segmentedcontrol-ischecked={isChecked === true}\n disabled={disabled}\n {...rest}\n >\n {children}\n </ToggleButton>\n </ToggleGroup.Item>\n );\n};\n\nconst SegmentedControl = ({\n selectedValue,\n label,\n onChange,\n onValueChange,\n children,\n disabled,\n ...rest\n}: TypeSegmentedControlProps) => {\n const [name] = useState(`Racine-segmented-control-${nameCounter++}`);\n return (\n <ToggleGroup.Root\n className=\"inline-flex space-x-px rounded bg-mauve6 shadow-[0_2px_10px] shadow-blackA4\"\n type=\"single\"\n value={selectedValue}\n aria-label={label}\n disabled={disabled}\n onValueChange={(e) => {\n onValueChange?.(e);\n // Create a mock event to pass to onChange for backwards compatibility.\n // We want to move towards onValueChange, but onChange is used by consumers currently so we need to support both for now.\n const mockEvent = new Event(\"change\", {\n bubbles: true,\n }) as unknown as React.SyntheticEvent<HTMLInputElement>;\n Object.defineProperty(mockEvent, \"target\", { value: { value: e } });\n Object.defineProperty(mockEvent, \"currentTarget\", {\n value: { value: e },\n });\n onChange?.(mockEvent);\n }}\n asChild\n >\n <SegmentedControlContainer\n data-qa-segmentedcontrol={label}\n data-qa-segmentedcontrol-value={selectedValue}\n disabled={disabled}\n {...rest}\n >\n {children}\n </SegmentedControlContainer>\n </ToggleGroup.Root>\n );\n};\n\nSegmentedControlItem.displayName = \"SegmentedControl.Item\";\nSegmentedControl.Item = SegmentedControlItem;\n\nexport default SegmentedControl;\n","import styled, { css } from \"styled-components\";\nimport {\n visuallyHidden,\n focusRing,\n disabled,\n} from \"@sproutsocial/seeds-react-mixins\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport Button from \"@sproutsocial/seeds-react-button\";\nimport type {\n TypeSegmentedControlProps,\n TypeSegmentedControlItemProps,\n} from \"./SegmentedControlTypes\";\n\nexport const SegmentedControlContainer = styled(Box)<\n Pick<TypeSegmentedControlProps, \"disabled\">\n>`\n border: 1px solid\n ${(props) => props.theme.colors.button.secondary.border.base};\n border-radius: ${(props) => props.theme.radii.outer};\n padding: ${(props) => props.theme.space[100]};\n display: flex;\n\n ${(props) => props.disabled && disabled}\n`;\n\nexport const ToggleButton = styled(Button)`\n /* To match the height of buttons... 350 padding - 2px top and bottom padding of the parent - 1px border on top and bottom */\n padding: calc(${(props) => props.theme.space[350]} - 6px);\n flex: 1 1 auto;\n display: flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n border: 0;\n\n & + & {\n margin-left: ${(props) => props.theme.space[100]};\n }\n\n &:hover {\n background-color: ${(props) =>\n props.theme.colors.listItem.background.hover};\n }\n\n &[data-state=\"on\"] {\n color: ${(props) => props.theme.colors.text.inverse};\n background-color: ${(props) =>\n props.theme.colors.listItem.background.selected};\n\n &:hover {\n background-color: ${(props) =>\n props.theme.colors.listItem.background.selected};\n }\n }\n`;\n\nexport const SegmentedControlItemContainer = styled(Box)<\n Pick<TypeSegmentedControlItemProps, \"disabled\">\n>`\n flex: 1 1 auto;\n display: flex;\n cursor: pointer;\n\n & + & {\n margin-left: ${(props) => props.theme.space[100]};\n }\n\n &:focus-within label {\n ${focusRing}\n }\n\n input {\n ${visuallyHidden}\n }\n\n ${(props) => props.disabled && disabled}\n`;\n\ninterface TypeSegmentedControlState {\n isActive: boolean;\n}\n\nexport const SegmentedControlLabel = styled(Button)<TypeSegmentedControlState>`\n flex: 1 1 auto;\n display: flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n color: ${(props) => props.theme.colors.text.body};\n cursor: pointer;\n font-size: ${(props) => props.theme.typography[200].fontSize};\n /**\n\t* Matches default line height of Icon. Also matches the overall height of\n\t* Input, Select, and Button.\n\t*/\n line-height: 16px;\n font-weight: ${(props) => props.theme.fontWeights.semibold};\n\n border-radius: ${(props) => props.theme.radii.inner};\n /* To match the height of buttons... 350 padding - 2px top and bottom padding of the parent - 1px border on top and bottom */\n padding: calc(${(props) => props.theme.space[350]} - 6px);\n transition: all ${(props) => props.theme.duration.fast};\n\n &:hover {\n background-color: ${(props) =>\n props.theme.colors.listItem.background.hover};\n }\n\n ${(props) =>\n props.isActive &&\n css`\n color: ${(props) => props.theme.colors.text.inverse};\n background-color: ${(props) =>\n props.theme.colors.listItem.background.selected};\n\n &:hover {\n background-color: ${(props) =>\n props.theme.colors.listItem.background.selected};\n }\n `}\n`;\n","import type { TypeContainerProps } from \"@sproutsocial/seeds-react-box\";\nimport * as React from \"react\";\n\nexport interface TypeSegmentedControlItemProps {\n /** The value of this item. Should be unique among sibling items. */\n value: string;\n children: React.ReactNode;\n /** Disables user action and applies a disabled style on the component */\n disabled?: boolean;\n}\n\nexport interface TypeSegmentedControlProps extends TypeContainerProps {\n /** The value of the currently selected item. Should match the value prop of one of the child items */\n selectedValue: string;\n\n /** The title of the segmented control, used for accessibility purposes */\n label: string;\n\n /** Called when the user selects a new item. You can access the value of the newly selected item using \"event.target.value\" */\n onChange?: (e: React.SyntheticEvent<HTMLInputElement>) => void;\n\n /** Called when the user selects a new item. You can access the value of the newly selected item using \"event.target.value\" */\n onValueChange?: (value: string) => void;\n\n /** Disables user action and applies a disabled style on the component */\n disabled?: boolean;\n children: React.ReactNode;\n}\n","import SegmentedControl from \"./SegmentedControl\";\n\nexport default SegmentedControl;\nexport { SegmentedControl };\nexport * from \"./SegmentedControlTypes\";\n"],"mappings":";AAAA,YAAY,WAAW;AACvB,SAAS,gBAAgB;AACzB,YAAY,iBAAiB;;;ACF7B,OAAO,UAAU,WAAW;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,OAAO,SAAS;AAChB,OAAO,YAAY;AAMZ,IAAM,4BAA4B,OAAO,GAAG;AAAA;AAAA,MAI7C,CAAC,UAAU,MAAM,MAAM,OAAO,OAAO,UAAU,OAAO,IAAI;AAAA,mBAC7C,CAAC,UAAU,MAAM,MAAM,MAAM,KAAK;AAAA,aACxC,CAAC,UAAU,MAAM,MAAM,MAAM,GAAG,CAAC;AAAA;AAAA;AAAA,IAG1C,CAAC,UAAU,MAAM,YAAY,QAAQ;AAAA;AAGlC,IAAM,eAAe,OAAO,MAAM;AAAA;AAAA,kBAEvB,CAAC,UAAU,MAAM,MAAM,MAAM,GAAG,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAShC,CAAC,UAAU,MAAM,MAAM,MAAM,GAAG,CAAC;AAAA;AAAA;AAAA;AAAA,wBAI5B,CAAC,UACnB,MAAM,MAAM,OAAO,SAAS,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA,aAIrC,CAAC,UAAU,MAAM,MAAM,OAAO,KAAK,OAAO;AAAA,wBAC/B,CAAC,UACnB,MAAM,MAAM,OAAO,SAAS,WAAW,QAAQ;AAAA;AAAA;AAAA,0BAG3B,CAAC,UACnB,MAAM,MAAM,OAAO,SAAS,WAAW,QAAQ;AAAA;AAAA;AAAA;AAKhD,IAAM,gCAAgC,OAAO,GAAG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAQpC,CAAC,UAAU,MAAM,MAAM,MAAM,GAAG,CAAC;AAAA;AAAA;AAAA;AAAA,MAI9C,SAAS;AAAA;AAAA;AAAA;AAAA,MAIT,cAAc;AAAA;AAAA;AAAA,IAGhB,CAAC,UAAU,MAAM,YAAY,QAAQ;AAAA;AAOlC,IAAM,wBAAwB,OAAO,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAMvC,CAAC,UAAU,MAAM,MAAM,OAAO,KAAK,IAAI;AAAA;AAAA,eAEnC,CAAC,UAAU,MAAM,MAAM,WAAW,GAAG,EAAE,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAM7C,CAAC,UAAU,MAAM,MAAM,YAAY,QAAQ;AAAA;AAAA,mBAEzC,CAAC,UAAU,MAAM,MAAM,MAAM,KAAK;AAAA;AAAA,kBAEnC,CAAC,UAAU,MAAM,MAAM,MAAM,GAAG,CAAC;AAAA,oBAC/B,CAAC,UAAU,MAAM,MAAM,SAAS,IAAI;AAAA;AAAA;AAAA,wBAGhC,CAAC,UACnB,MAAM,MAAM,OAAO,SAAS,WAAW,KAAK;AAAA;AAAA;AAAA,IAG9C,CAAC,UACD,MAAM,YACN;AAAA,eACW,CAACA,WAAUA,OAAM,MAAM,OAAO,KAAK,OAAO;AAAA,0BAC/B,CAACA,WACnBA,OAAM,MAAM,OAAO,SAAS,WAAW,QAAQ;AAAA;AAAA;AAAA,4BAG3B,CAACA,WACnBA,OAAM,MAAM,OAAO,SAAS,WAAW,QAAQ;AAAA;AAAA,KAEpD;AAAA;;;ADpFC;AA1BN,IAAI,cAAc;AASlB,IAAM,0BAAgC,oBAEpC,IAAI;AAEN,IAAM,uBAAuB,CAAC;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,UAAAC;AAAA,EACA,GAAG;AACL,MAAqC;AACnC,SACE;AAAA,IAAa;AAAA,IAAZ;AAAA,MACC;AAAA,MACA,cAAW;AAAA,MACX,UAAUA;AAAA,MACV,SAAO;AAAA,MAEP;AAAA,QAAC;AAAA;AAAA,UAIC,iCAA+B;AAAA,UAE/B,UAAUA;AAAA,UACT,GAAG;AAAA,UAEH;AAAA;AAAA,MACH;AAAA;AAAA,EACF;AAEJ;AAEA,IAAM,mBAAmB,CAAC;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAAA;AAAA,EACA,GAAG;AACL,MAAiC;AAC/B,QAAM,CAAC,IAAI,IAAI,SAAS,4BAA4B,aAAa,EAAE;AACnE,SACE;AAAA,IAAa;AAAA,IAAZ;AAAA,MACC,WAAU;AAAA,MACV,MAAK;AAAA,MACL,OAAO;AAAA,MACP,cAAY;AAAA,MACZ,UAAUA;AAAA,MACV,eAAe,CAAC,MAAM;AACpB,wBAAgB,CAAC;AAGjB,cAAM,YAAY,IAAI,MAAM,UAAU;AAAA,UACpC,SAAS;AAAA,QACX,CAAC;AACD,eAAO,eAAe,WAAW,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC;AAClE,eAAO,eAAe,WAAW,iBAAiB;AAAA,UAChD,OAAO,EAAE,OAAO,EAAE;AAAA,QACpB,CAAC;AACD,mBAAW,SAAS;AAAA,MACtB;AAAA,MACA,SAAO;AAAA,MAEP;AAAA,QAAC;AAAA;AAAA,UACC,4BAA0B;AAAA,UAC1B,kCAAgC;AAAA,UAChC,UAAUA;AAAA,UACT,GAAG;AAAA,UAEH;AAAA;AAAA,MACH;AAAA;AAAA,EACF;AAEJ;AAEA,qBAAqB,cAAc;AACnC,iBAAiB,OAAO;AAExB,IAAO,2BAAQ;;;AEhGf,OAAuB;;;ACCvB,IAAO,gBAAQ;","names":["props","disabled"]}
|
package/dist/index.d.mts
CHANGED
|
@@ -15,16 +15,18 @@ interface TypeSegmentedControlProps extends TypeContainerProps {
|
|
|
15
15
|
/** The title of the segmented control, used for accessibility purposes */
|
|
16
16
|
label: string;
|
|
17
17
|
/** Called when the user selects a new item. You can access the value of the newly selected item using "event.target.value" */
|
|
18
|
-
onChange
|
|
18
|
+
onChange?: (e: React.SyntheticEvent<HTMLInputElement>) => void;
|
|
19
|
+
/** Called when the user selects a new item. You can access the value of the newly selected item using "event.target.value" */
|
|
20
|
+
onValueChange?: (value: string) => void;
|
|
19
21
|
/** Disables user action and applies a disabled style on the component */
|
|
20
22
|
disabled?: boolean;
|
|
21
23
|
children: React.ReactNode;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
declare const SegmentedControl: {
|
|
25
|
-
({ selectedValue, label, onChange, children, ...rest }: TypeSegmentedControlProps): react_jsx_runtime.JSX.Element;
|
|
27
|
+
({ selectedValue, label, onChange, onValueChange, children, disabled, ...rest }: TypeSegmentedControlProps): react_jsx_runtime.JSX.Element;
|
|
26
28
|
Item: {
|
|
27
|
-
({ value, children, disabled, ...rest }: TypeSegmentedControlItemProps): react_jsx_runtime.JSX.Element
|
|
29
|
+
({ value, children, disabled, ...rest }: TypeSegmentedControlItemProps): react_jsx_runtime.JSX.Element;
|
|
28
30
|
displayName: string;
|
|
29
31
|
};
|
|
30
32
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -15,16 +15,18 @@ interface TypeSegmentedControlProps extends TypeContainerProps {
|
|
|
15
15
|
/** The title of the segmented control, used for accessibility purposes */
|
|
16
16
|
label: string;
|
|
17
17
|
/** Called when the user selects a new item. You can access the value of the newly selected item using "event.target.value" */
|
|
18
|
-
onChange
|
|
18
|
+
onChange?: (e: React.SyntheticEvent<HTMLInputElement>) => void;
|
|
19
|
+
/** Called when the user selects a new item. You can access the value of the newly selected item using "event.target.value" */
|
|
20
|
+
onValueChange?: (value: string) => void;
|
|
19
21
|
/** Disables user action and applies a disabled style on the component */
|
|
20
22
|
disabled?: boolean;
|
|
21
23
|
children: React.ReactNode;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
declare const SegmentedControl: {
|
|
25
|
-
({ selectedValue, label, onChange, children, ...rest }: TypeSegmentedControlProps): react_jsx_runtime.JSX.Element;
|
|
27
|
+
({ selectedValue, label, onChange, onValueChange, children, disabled, ...rest }: TypeSegmentedControlProps): react_jsx_runtime.JSX.Element;
|
|
26
28
|
Item: {
|
|
27
|
-
({ value, children, disabled, ...rest }: TypeSegmentedControlItemProps): react_jsx_runtime.JSX.Element
|
|
29
|
+
({ value, children, disabled, ...rest }: TypeSegmentedControlItemProps): react_jsx_runtime.JSX.Element;
|
|
28
30
|
displayName: string;
|
|
29
31
|
};
|
|
30
32
|
};
|
package/dist/index.js
CHANGED
|
@@ -38,24 +38,48 @@ module.exports = __toCommonJS(index_exports);
|
|
|
38
38
|
// src/SegmentedControl.tsx
|
|
39
39
|
var React = __toESM(require("react"));
|
|
40
40
|
var import_react = require("react");
|
|
41
|
-
var
|
|
41
|
+
var ToggleGroup = __toESM(require("@radix-ui/react-toggle-group"));
|
|
42
42
|
|
|
43
43
|
// src/styles.ts
|
|
44
44
|
var import_styled_components = __toESM(require("styled-components"));
|
|
45
45
|
var import_seeds_react_mixins = require("@sproutsocial/seeds-react-mixins");
|
|
46
46
|
var import_seeds_react_box = __toESM(require("@sproutsocial/seeds-react-box"));
|
|
47
|
-
var
|
|
47
|
+
var import_seeds_react_button = __toESM(require("@sproutsocial/seeds-react-button"));
|
|
48
48
|
var SegmentedControlContainer = (0, import_styled_components.default)(import_seeds_react_box.default)`
|
|
49
49
|
border: 1px solid
|
|
50
50
|
${(props) => props.theme.colors.button.secondary.border.base};
|
|
51
51
|
border-radius: ${(props) => props.theme.radii.outer};
|
|
52
52
|
padding: ${(props) => props.theme.space[100]};
|
|
53
|
+
display: flex;
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
${(props) => props.disabled && import_seeds_react_mixins.disabled}
|
|
56
|
+
`;
|
|
57
|
+
var ToggleButton = (0, import_styled_components.default)(import_seeds_react_button.default)`
|
|
58
|
+
/* To match the height of buttons... 350 padding - 2px top and bottom padding of the parent - 1px border on top and bottom */
|
|
59
|
+
padding: calc(${(props) => props.theme.space[350]} - 6px);
|
|
60
|
+
flex: 1 1 auto;
|
|
61
|
+
display: flex;
|
|
62
|
+
align-items: center;
|
|
63
|
+
justify-content: center;
|
|
64
|
+
text-align: center;
|
|
65
|
+
border: 0;
|
|
66
|
+
|
|
67
|
+
& + & {
|
|
68
|
+
margin-left: ${(props) => props.theme.space[100]};
|
|
56
69
|
}
|
|
57
70
|
|
|
58
|
-
|
|
71
|
+
&:hover {
|
|
72
|
+
background-color: ${(props) => props.theme.colors.listItem.background.hover};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
&[data-state="on"] {
|
|
76
|
+
color: ${(props) => props.theme.colors.text.inverse};
|
|
77
|
+
background-color: ${(props) => props.theme.colors.listItem.background.selected};
|
|
78
|
+
|
|
79
|
+
&:hover {
|
|
80
|
+
background-color: ${(props) => props.theme.colors.listItem.background.selected};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
59
83
|
`;
|
|
60
84
|
var SegmentedControlItemContainer = (0, import_styled_components.default)(import_seeds_react_box.default)`
|
|
61
85
|
flex: 1 1 auto;
|
|
@@ -76,7 +100,7 @@ var SegmentedControlItemContainer = (0, import_styled_components.default)(import
|
|
|
76
100
|
|
|
77
101
|
${(props) => props.disabled && import_seeds_react_mixins.disabled}
|
|
78
102
|
`;
|
|
79
|
-
var SegmentedControlLabel = (0, import_styled_components.default)(
|
|
103
|
+
var SegmentedControlLabel = (0, import_styled_components.default)(import_seeds_react_button.default)`
|
|
80
104
|
flex: 1 1 auto;
|
|
81
105
|
display: flex;
|
|
82
106
|
align-items: center;
|
|
@@ -114,7 +138,6 @@ var SegmentedControlLabel = (0, import_styled_components.default)(import_seeds_r
|
|
|
114
138
|
// src/SegmentedControl.tsx
|
|
115
139
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
116
140
|
var nameCounter = 0;
|
|
117
|
-
var idCounter = 0;
|
|
118
141
|
var SegmentedControlContext = React.createContext(null);
|
|
119
142
|
var SegmentedControlItem = ({
|
|
120
143
|
value,
|
|
@@ -122,36 +145,22 @@ var SegmentedControlItem = ({
|
|
|
122
145
|
disabled: disabled2,
|
|
123
146
|
...rest
|
|
124
147
|
}) => {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return null;
|
|
128
|
-
}
|
|
129
|
-
const { name, selectedValue, onChange } = context;
|
|
130
|
-
const [id] = (0, import_react.useState)(`${name}-${idCounter++}`);
|
|
131
|
-
const isChecked = value === selectedValue;
|
|
132
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
133
|
-
SegmentedControlItemContainer,
|
|
148
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
149
|
+
ToggleGroup.Item,
|
|
134
150
|
{
|
|
135
|
-
|
|
136
|
-
"
|
|
137
|
-
"data-qa-segmentedcontrol-ischecked": isChecked === true,
|
|
151
|
+
value,
|
|
152
|
+
"aria-label": "Left aligned",
|
|
138
153
|
disabled: disabled2,
|
|
139
|
-
|
|
140
|
-
children:
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
onChange,
|
|
150
|
-
disabled: disabled2
|
|
151
|
-
}
|
|
152
|
-
),
|
|
153
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SegmentedControlLabel, { as: "label", htmlFor: id, isActive: isChecked, children })
|
|
154
|
-
]
|
|
154
|
+
asChild: true,
|
|
155
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
156
|
+
ToggleButton,
|
|
157
|
+
{
|
|
158
|
+
"data-qa-segmentedcontrol-item": value,
|
|
159
|
+
disabled: disabled2,
|
|
160
|
+
...rest,
|
|
161
|
+
children
|
|
162
|
+
}
|
|
163
|
+
)
|
|
155
164
|
}
|
|
156
165
|
);
|
|
157
166
|
};
|
|
@@ -159,29 +168,40 @@ var SegmentedControl = ({
|
|
|
159
168
|
selectedValue,
|
|
160
169
|
label,
|
|
161
170
|
onChange,
|
|
171
|
+
onValueChange,
|
|
162
172
|
children,
|
|
173
|
+
disabled: disabled2,
|
|
163
174
|
...rest
|
|
164
175
|
}) => {
|
|
165
176
|
const [name] = (0, import_react.useState)(`Racine-segmented-control-${nameCounter++}`);
|
|
166
177
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
167
|
-
|
|
178
|
+
ToggleGroup.Root,
|
|
168
179
|
{
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
180
|
+
className: "inline-flex space-x-px rounded bg-mauve6 shadow-[0_2px_10px] shadow-blackA4",
|
|
181
|
+
type: "single",
|
|
182
|
+
value: selectedValue,
|
|
183
|
+
"aria-label": label,
|
|
184
|
+
disabled: disabled2,
|
|
185
|
+
onValueChange: (e) => {
|
|
186
|
+
onValueChange?.(e);
|
|
187
|
+
const mockEvent = new Event("change", {
|
|
188
|
+
bubbles: true
|
|
189
|
+
});
|
|
190
|
+
Object.defineProperty(mockEvent, "target", { value: { value: e } });
|
|
191
|
+
Object.defineProperty(mockEvent, "currentTarget", {
|
|
192
|
+
value: { value: e }
|
|
193
|
+
});
|
|
194
|
+
onChange?.(mockEvent);
|
|
173
195
|
},
|
|
174
|
-
|
|
196
|
+
asChild: true,
|
|
197
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
175
198
|
SegmentedControlContainer,
|
|
176
199
|
{
|
|
177
|
-
forwardedAs: "fieldset",
|
|
178
200
|
"data-qa-segmentedcontrol": label,
|
|
179
201
|
"data-qa-segmentedcontrol-value": selectedValue,
|
|
202
|
+
disabled: disabled2,
|
|
180
203
|
...rest,
|
|
181
|
-
children
|
|
182
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("legend", { children: label }),
|
|
183
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_seeds_react_box2.default, { display: "flex", children })
|
|
184
|
-
]
|
|
204
|
+
children
|
|
185
205
|
}
|
|
186
206
|
)
|
|
187
207
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/SegmentedControl.tsx","../src/styles.ts","../src/SegmentedControlTypes.ts"],"sourcesContent":["import SegmentedControl from \"./SegmentedControl\";\n\nexport default SegmentedControl;\nexport { SegmentedControl };\nexport * from \"./SegmentedControlTypes\";\n","import * as React from \"react\";\nimport { useState, useContext } from \"react\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport {\n SegmentedControlContainer,\n SegmentedControlItemContainer,\n SegmentedControlLabel,\n} from \"./styles\";\nimport type {\n TypeSegmentedControlProps,\n TypeSegmentedControlItemProps,\n} from \"./SegmentedControlTypes\";\n\nlet nameCounter = 0;\nlet idCounter = 0;\n\ninterface TypeSegmentedControlContext {\n name: string;\n selectedValue: string;\n onChange: (e: React.SyntheticEvent<HTMLInputElement>) => void;\n}\n\nconst SegmentedControlContext = React.createContext<\n TypeSegmentedControlContext | null | undefined\n>(null);\n\nconst SegmentedControlItem = ({\n value,\n children,\n disabled,\n ...rest\n}: TypeSegmentedControlItemProps) => {\n const context = useContext(SegmentedControlContext);\n\n if (!context) {\n return null;\n }\n\n const { name, selectedValue, onChange } = context;\n\n /* eslint-disable-next-line */\n const [id] = useState(`${name}-${idCounter++}`);\n const isChecked = value === selectedValue;\n\n return (\n <SegmentedControlItemContainer\n data-segmentedcontrol-isactive={isChecked}\n data-qa-segmentedcontrol-item={value}\n data-qa-segmentedcontrol-ischecked={isChecked === true}\n disabled={disabled}\n {...rest}\n >\n <input\n type=\"radio\"\n id={id}\n name={name}\n value={value}\n checked={isChecked}\n onChange={onChange}\n disabled={disabled}\n />\n <SegmentedControlLabel as=\"label\" htmlFor={id} isActive={isChecked}>\n {children}\n </SegmentedControlLabel>\n </SegmentedControlItemContainer>\n );\n};\n\nconst SegmentedControl = ({\n selectedValue,\n label,\n onChange,\n children,\n ...rest\n}: TypeSegmentedControlProps) => {\n const [name] = useState(`Racine-segmented-control-${nameCounter++}`);\n return (\n <SegmentedControlContext.Provider\n value={{\n name,\n selectedValue,\n onChange,\n }}\n >\n <SegmentedControlContainer\n forwardedAs=\"fieldset\"\n data-qa-segmentedcontrol={label}\n data-qa-segmentedcontrol-value={selectedValue}\n {...rest}\n >\n <legend>{label}</legend>\n\n <Box display=\"flex\">{children}</Box>\n </SegmentedControlContainer>\n </SegmentedControlContext.Provider>\n );\n};\n\nSegmentedControlItem.displayName = \"SegmentedControl.Item\";\nSegmentedControl.Item = SegmentedControlItem;\n\nexport default SegmentedControl;\n","import styled, { css } from \"styled-components\";\nimport {\n visuallyHidden,\n focusRing,\n disabled,\n} from \"@sproutsocial/seeds-react-mixins\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport Text from \"@sproutsocial/seeds-react-text\";\nimport type {\n TypeSegmentedControlProps,\n TypeSegmentedControlItemProps,\n} from \"./SegmentedControlTypes\";\n\nexport const SegmentedControlContainer = styled(Box)<\n Pick<TypeSegmentedControlProps, \"disabled\">\n>`\n border: 1px solid\n ${(props) => props.theme.colors.button.secondary.border.base};\n border-radius: ${(props) => props.theme.radii.outer};\n padding: ${(props) => props.theme.space[100]};\n\n legend {\n ${visuallyHidden}\n }\n\n ${(props) => props.disabled && disabled}\n`;\n\nexport const SegmentedControlItemContainer = styled(Box)<\n Pick<TypeSegmentedControlItemProps, \"disabled\">\n>`\n flex: 1 1 auto;\n display: flex;\n cursor: pointer;\n\n & + & {\n margin-left: ${(props) => props.theme.space[100]};\n }\n\n &:focus-within label {\n ${focusRing}\n }\n\n input {\n ${visuallyHidden}\n }\n\n ${(props) => props.disabled && disabled}\n`;\n\ninterface TypeSegmentedControlState {\n isActive: boolean;\n}\n\nexport const SegmentedControlLabel = styled(Text)<TypeSegmentedControlState>`\n flex: 1 1 auto;\n display: flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n color: ${(props) => props.theme.colors.text.body};\n cursor: pointer;\n font-size: ${(props) => props.theme.typography[200].fontSize};\n /**\n\t* Matches default line height of Icon. Also matches the overall height of\n\t* Input, Select, and Button.\n\t*/\n line-height: 16px;\n font-weight: ${(props) => props.theme.fontWeights.semibold};\n\n border-radius: ${(props) => props.theme.radii.inner};\n /* To match the height of buttons... 350 padding - 2px top and bottom padding of the parent - 1px border on top and bottom */\n padding: calc(${(props) => props.theme.space[350]} - 6px);\n transition: all ${(props) => props.theme.duration.fast};\n\n &:hover {\n background-color: ${(props) =>\n props.theme.colors.listItem.background.hover};\n }\n\n ${(props) =>\n props.isActive &&\n css`\n color: ${(props) => props.theme.colors.text.inverse};\n background-color: ${(props) =>\n props.theme.colors.listItem.background.selected};\n\n &:hover {\n background-color: ${(props) =>\n props.theme.colors.listItem.background.selected};\n }\n `}\n`;\n","import type { TypeContainerProps } from \"@sproutsocial/seeds-react-box\";\nimport * as React from \"react\";\n\nexport interface TypeSegmentedControlItemProps {\n /** The value of this item. Should be unique among sibling items. */\n value: string;\n children: React.ReactNode;\n /** Disables user action and applies a disabled style on the component */\n disabled?: boolean;\n}\n\nexport interface TypeSegmentedControlProps extends TypeContainerProps {\n /** The value of the currently selected item. Should match the value prop of one of the child items */\n selectedValue: string;\n\n /** The title of the segmented control, used for accessibility purposes */\n label: string;\n\n /** Called when the user selects a new item. You can access the value of the newly selected item using \"event.target.value\" */\n onChange: (e: React.SyntheticEvent<HTMLInputElement>) => void;\n\n /** Disables user action and applies a disabled style on the component */\n disabled?: boolean;\n children: React.ReactNode;\n}\n"],"mappings":"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","names":["import_seeds_react_box","styled","Box","Text","props","disabled","Box","React"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/SegmentedControl.tsx","../src/styles.ts","../src/SegmentedControlTypes.ts"],"sourcesContent":["import SegmentedControl from \"./SegmentedControl\";\n\nexport default SegmentedControl;\nexport { SegmentedControl };\nexport * from \"./SegmentedControlTypes\";\n","import * as React from \"react\";\nimport { useState } from \"react\";\nimport * as ToggleGroup from \"@radix-ui/react-toggle-group\";\nimport { SegmentedControlContainer, ToggleButton } from \"./styles\";\nimport type {\n TypeSegmentedControlProps,\n TypeSegmentedControlItemProps,\n} from \"./SegmentedControlTypes\";\n\nlet nameCounter = 0;\nlet idCounter = 0;\n\ninterface TypeSegmentedControlContext {\n name: string;\n selectedValue: string;\n onChange: (e: React.SyntheticEvent<HTMLInputElement>) => void;\n}\n\nconst SegmentedControlContext = React.createContext<\n TypeSegmentedControlContext | null | undefined\n>(null);\n\nconst SegmentedControlItem = ({\n value,\n children,\n disabled,\n ...rest\n}: TypeSegmentedControlItemProps) => {\n return (\n <ToggleGroup.Item\n value={value}\n aria-label=\"Left aligned\"\n disabled={disabled}\n asChild\n >\n <ToggleButton\n // TODO: Discuss dropping these\n // We'd need to keep context, which seems unnecessary now\n // data-segmentedcontrol-isactive={isChecked}\n data-qa-segmentedcontrol-item={value}\n // data-qa-segmentedcontrol-ischecked={isChecked === true}\n disabled={disabled}\n {...rest}\n >\n {children}\n </ToggleButton>\n </ToggleGroup.Item>\n );\n};\n\nconst SegmentedControl = ({\n selectedValue,\n label,\n onChange,\n onValueChange,\n children,\n disabled,\n ...rest\n}: TypeSegmentedControlProps) => {\n const [name] = useState(`Racine-segmented-control-${nameCounter++}`);\n return (\n <ToggleGroup.Root\n className=\"inline-flex space-x-px rounded bg-mauve6 shadow-[0_2px_10px] shadow-blackA4\"\n type=\"single\"\n value={selectedValue}\n aria-label={label}\n disabled={disabled}\n onValueChange={(e) => {\n onValueChange?.(e);\n // Create a mock event to pass to onChange for backwards compatibility.\n // We want to move towards onValueChange, but onChange is used by consumers currently so we need to support both for now.\n const mockEvent = new Event(\"change\", {\n bubbles: true,\n }) as unknown as React.SyntheticEvent<HTMLInputElement>;\n Object.defineProperty(mockEvent, \"target\", { value: { value: e } });\n Object.defineProperty(mockEvent, \"currentTarget\", {\n value: { value: e },\n });\n onChange?.(mockEvent);\n }}\n asChild\n >\n <SegmentedControlContainer\n data-qa-segmentedcontrol={label}\n data-qa-segmentedcontrol-value={selectedValue}\n disabled={disabled}\n {...rest}\n >\n {children}\n </SegmentedControlContainer>\n </ToggleGroup.Root>\n );\n};\n\nSegmentedControlItem.displayName = \"SegmentedControl.Item\";\nSegmentedControl.Item = SegmentedControlItem;\n\nexport default SegmentedControl;\n","import styled, { css } from \"styled-components\";\nimport {\n visuallyHidden,\n focusRing,\n disabled,\n} from \"@sproutsocial/seeds-react-mixins\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport Button from \"@sproutsocial/seeds-react-button\";\nimport type {\n TypeSegmentedControlProps,\n TypeSegmentedControlItemProps,\n} from \"./SegmentedControlTypes\";\n\nexport const SegmentedControlContainer = styled(Box)<\n Pick<TypeSegmentedControlProps, \"disabled\">\n>`\n border: 1px solid\n ${(props) => props.theme.colors.button.secondary.border.base};\n border-radius: ${(props) => props.theme.radii.outer};\n padding: ${(props) => props.theme.space[100]};\n display: flex;\n\n ${(props) => props.disabled && disabled}\n`;\n\nexport const ToggleButton = styled(Button)`\n /* To match the height of buttons... 350 padding - 2px top and bottom padding of the parent - 1px border on top and bottom */\n padding: calc(${(props) => props.theme.space[350]} - 6px);\n flex: 1 1 auto;\n display: flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n border: 0;\n\n & + & {\n margin-left: ${(props) => props.theme.space[100]};\n }\n\n &:hover {\n background-color: ${(props) =>\n props.theme.colors.listItem.background.hover};\n }\n\n &[data-state=\"on\"] {\n color: ${(props) => props.theme.colors.text.inverse};\n background-color: ${(props) =>\n props.theme.colors.listItem.background.selected};\n\n &:hover {\n background-color: ${(props) =>\n props.theme.colors.listItem.background.selected};\n }\n }\n`;\n\nexport const SegmentedControlItemContainer = styled(Box)<\n Pick<TypeSegmentedControlItemProps, \"disabled\">\n>`\n flex: 1 1 auto;\n display: flex;\n cursor: pointer;\n\n & + & {\n margin-left: ${(props) => props.theme.space[100]};\n }\n\n &:focus-within label {\n ${focusRing}\n }\n\n input {\n ${visuallyHidden}\n }\n\n ${(props) => props.disabled && disabled}\n`;\n\ninterface TypeSegmentedControlState {\n isActive: boolean;\n}\n\nexport const SegmentedControlLabel = styled(Button)<TypeSegmentedControlState>`\n flex: 1 1 auto;\n display: flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n color: ${(props) => props.theme.colors.text.body};\n cursor: pointer;\n font-size: ${(props) => props.theme.typography[200].fontSize};\n /**\n\t* Matches default line height of Icon. Also matches the overall height of\n\t* Input, Select, and Button.\n\t*/\n line-height: 16px;\n font-weight: ${(props) => props.theme.fontWeights.semibold};\n\n border-radius: ${(props) => props.theme.radii.inner};\n /* To match the height of buttons... 350 padding - 2px top and bottom padding of the parent - 1px border on top and bottom */\n padding: calc(${(props) => props.theme.space[350]} - 6px);\n transition: all ${(props) => props.theme.duration.fast};\n\n &:hover {\n background-color: ${(props) =>\n props.theme.colors.listItem.background.hover};\n }\n\n ${(props) =>\n props.isActive &&\n css`\n color: ${(props) => props.theme.colors.text.inverse};\n background-color: ${(props) =>\n props.theme.colors.listItem.background.selected};\n\n &:hover {\n background-color: ${(props) =>\n props.theme.colors.listItem.background.selected};\n }\n `}\n`;\n","import type { TypeContainerProps } from \"@sproutsocial/seeds-react-box\";\nimport * as React from \"react\";\n\nexport interface TypeSegmentedControlItemProps {\n /** The value of this item. Should be unique among sibling items. */\n value: string;\n children: React.ReactNode;\n /** Disables user action and applies a disabled style on the component */\n disabled?: boolean;\n}\n\nexport interface TypeSegmentedControlProps extends TypeContainerProps {\n /** The value of the currently selected item. Should match the value prop of one of the child items */\n selectedValue: string;\n\n /** The title of the segmented control, used for accessibility purposes */\n label: string;\n\n /** Called when the user selects a new item. You can access the value of the newly selected item using \"event.target.value\" */\n onChange?: (e: React.SyntheticEvent<HTMLInputElement>) => void;\n\n /** Called when the user selects a new item. You can access the value of the newly selected item using \"event.target.value\" */\n onValueChange?: (value: string) => void;\n\n /** Disables user action and applies a disabled style on the component */\n disabled?: boolean;\n children: React.ReactNode;\n}\n"],"mappings":"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","names":["styled","Box","Button","props","disabled","React"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sproutsocial/seeds-react-segmented-control",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Seeds React SegmentedControl",
|
|
5
5
|
"author": "Sprout Social, Inc.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,11 +18,13 @@
|
|
|
18
18
|
"test:watch": "jest --watch --coverage=false"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@
|
|
21
|
+
"@radix-ui/react-toggle-group": "^1.0.0",
|
|
22
|
+
"@sproutsocial/seeds-react-theme": "^3.6.0",
|
|
22
23
|
"@sproutsocial/seeds-react-system-props": "^3.0.1",
|
|
23
|
-
"@sproutsocial/seeds-react-box": "^1.1.
|
|
24
|
+
"@sproutsocial/seeds-react-box": "^1.1.14",
|
|
25
|
+
"@sproutsocial/seeds-react-button": "^1.3.20",
|
|
24
26
|
"@sproutsocial/seeds-react-text": "^1.4.0",
|
|
25
|
-
"@sproutsocial/seeds-react-mixins": "^4.
|
|
27
|
+
"@sproutsocial/seeds-react-mixins": "^4.3.1"
|
|
26
28
|
},
|
|
27
29
|
"devDependencies": {
|
|
28
30
|
"@types/react": "^18.0.0",
|
|
@@ -15,11 +15,15 @@ type Story = StoryObj<typeof SegmentedControl>;
|
|
|
15
15
|
// @ts-ignore IDK what props should be
|
|
16
16
|
const StatefulSegmentedControl = (props) => {
|
|
17
17
|
const [value, setValue] = useState("1");
|
|
18
|
+
|
|
18
19
|
return (
|
|
19
20
|
<SegmentedControl
|
|
20
21
|
selectedValue={value}
|
|
21
22
|
label="Segmented control component"
|
|
22
|
-
onChange={(e) =>
|
|
23
|
+
onChange={(e) => {
|
|
24
|
+
console.log(e);
|
|
25
|
+
setValue((e.target as HTMLInputElement).value);
|
|
26
|
+
}}
|
|
23
27
|
{...props}
|
|
24
28
|
>
|
|
25
29
|
<SegmentedControl.Item value="1">Test 1</SegmentedControl.Item>
|
|
@@ -55,7 +59,7 @@ export const DisabledItem: Story = {
|
|
|
55
59
|
<SegmentedControl
|
|
56
60
|
selectedValue={value}
|
|
57
61
|
label="Segmented control component"
|
|
58
|
-
|
|
62
|
+
onValueChange={setValue}
|
|
59
63
|
flex="1"
|
|
60
64
|
>
|
|
61
65
|
<SegmentedControl.Item value="1">Test 1</SegmentedControl.Item>
|
package/src/SegmentedControl.tsx
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { useState
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
SegmentedControlContainer,
|
|
6
|
-
SegmentedControlItemContainer,
|
|
7
|
-
SegmentedControlLabel,
|
|
8
|
-
} from "./styles";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import * as ToggleGroup from "@radix-ui/react-toggle-group";
|
|
4
|
+
import { SegmentedControlContainer, ToggleButton } from "./styles";
|
|
9
5
|
import type {
|
|
10
6
|
TypeSegmentedControlProps,
|
|
11
7
|
TypeSegmentedControlItemProps,
|
|
@@ -30,39 +26,25 @@ const SegmentedControlItem = ({
|
|
|
30
26
|
disabled,
|
|
31
27
|
...rest
|
|
32
28
|
}: TypeSegmentedControlItemProps) => {
|
|
33
|
-
const context = useContext(SegmentedControlContext);
|
|
34
|
-
|
|
35
|
-
if (!context) {
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const { name, selectedValue, onChange } = context;
|
|
40
|
-
|
|
41
|
-
/* eslint-disable-next-line */
|
|
42
|
-
const [id] = useState(`${name}-${idCounter++}`);
|
|
43
|
-
const isChecked = value === selectedValue;
|
|
44
|
-
|
|
45
29
|
return (
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
data-qa-segmentedcontrol-ischecked={isChecked === true}
|
|
30
|
+
<ToggleGroup.Item
|
|
31
|
+
value={value}
|
|
32
|
+
aria-label="Left aligned"
|
|
50
33
|
disabled={disabled}
|
|
51
|
-
|
|
34
|
+
asChild
|
|
52
35
|
>
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
onChange={onChange}
|
|
36
|
+
<ToggleButton
|
|
37
|
+
// TODO: Discuss dropping these
|
|
38
|
+
// We'd need to keep context, which seems unnecessary now
|
|
39
|
+
// data-segmentedcontrol-isactive={isChecked}
|
|
40
|
+
data-qa-segmentedcontrol-item={value}
|
|
41
|
+
// data-qa-segmentedcontrol-ischecked={isChecked === true}
|
|
60
42
|
disabled={disabled}
|
|
61
|
-
|
|
62
|
-
|
|
43
|
+
{...rest}
|
|
44
|
+
>
|
|
63
45
|
{children}
|
|
64
|
-
</
|
|
65
|
-
</
|
|
46
|
+
</ToggleButton>
|
|
47
|
+
</ToggleGroup.Item>
|
|
66
48
|
);
|
|
67
49
|
};
|
|
68
50
|
|
|
@@ -70,29 +52,43 @@ const SegmentedControl = ({
|
|
|
70
52
|
selectedValue,
|
|
71
53
|
label,
|
|
72
54
|
onChange,
|
|
55
|
+
onValueChange,
|
|
73
56
|
children,
|
|
57
|
+
disabled,
|
|
74
58
|
...rest
|
|
75
59
|
}: TypeSegmentedControlProps) => {
|
|
76
60
|
const [name] = useState(`Racine-segmented-control-${nameCounter++}`);
|
|
77
61
|
return (
|
|
78
|
-
<
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
62
|
+
<ToggleGroup.Root
|
|
63
|
+
className="inline-flex space-x-px rounded bg-mauve6 shadow-[0_2px_10px] shadow-blackA4"
|
|
64
|
+
type="single"
|
|
65
|
+
value={selectedValue}
|
|
66
|
+
aria-label={label}
|
|
67
|
+
disabled={disabled}
|
|
68
|
+
onValueChange={(e) => {
|
|
69
|
+
onValueChange?.(e);
|
|
70
|
+
// Create a mock event to pass to onChange for backwards compatibility.
|
|
71
|
+
// We want to move towards onValueChange, but onChange is used by consumers currently so we need to support both for now.
|
|
72
|
+
const mockEvent = new Event("change", {
|
|
73
|
+
bubbles: true,
|
|
74
|
+
}) as unknown as React.SyntheticEvent<HTMLInputElement>;
|
|
75
|
+
Object.defineProperty(mockEvent, "target", { value: { value: e } });
|
|
76
|
+
Object.defineProperty(mockEvent, "currentTarget", {
|
|
77
|
+
value: { value: e },
|
|
78
|
+
});
|
|
79
|
+
onChange?.(mockEvent);
|
|
83
80
|
}}
|
|
81
|
+
asChild
|
|
84
82
|
>
|
|
85
83
|
<SegmentedControlContainer
|
|
86
|
-
forwardedAs="fieldset"
|
|
87
84
|
data-qa-segmentedcontrol={label}
|
|
88
85
|
data-qa-segmentedcontrol-value={selectedValue}
|
|
86
|
+
disabled={disabled}
|
|
89
87
|
{...rest}
|
|
90
88
|
>
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
<Box display="flex">{children}</Box>
|
|
89
|
+
{children}
|
|
94
90
|
</SegmentedControlContainer>
|
|
95
|
-
</
|
|
91
|
+
</ToggleGroup.Root>
|
|
96
92
|
);
|
|
97
93
|
};
|
|
98
94
|
|
|
@@ -17,7 +17,10 @@ export interface TypeSegmentedControlProps extends TypeContainerProps {
|
|
|
17
17
|
label: string;
|
|
18
18
|
|
|
19
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
|
|
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;
|
|
21
24
|
|
|
22
25
|
/** Disables user action and applies a disabled style on the component */
|
|
23
26
|
disabled?: boolean;
|
|
@@ -32,53 +32,26 @@ describe("SegmentedControl", () => {
|
|
|
32
32
|
const item2 = screen.getByText("Test 2");
|
|
33
33
|
const item3 = screen.getByText("Test 3");
|
|
34
34
|
|
|
35
|
-
expect(item1
|
|
36
|
-
"data-segmentedcontrol-isactive",
|
|
37
|
-
"true"
|
|
38
|
-
);
|
|
35
|
+
expect(item1).toHaveAttribute("data-state", "on");
|
|
39
36
|
|
|
40
|
-
expect(item2
|
|
41
|
-
"data-segmentedcontrol-isactive",
|
|
42
|
-
"false"
|
|
43
|
-
);
|
|
37
|
+
expect(item2).toHaveAttribute("data-state", "off");
|
|
44
38
|
|
|
45
|
-
expect(item3
|
|
46
|
-
"data-segmentedcontrol-isactive",
|
|
47
|
-
"false"
|
|
48
|
-
);
|
|
39
|
+
expect(item3).toHaveAttribute("data-state", "off");
|
|
49
40
|
|
|
50
41
|
fireEvent.click(item3);
|
|
51
42
|
|
|
52
|
-
expect(item1
|
|
53
|
-
"data-segmentedcontrol-isactive",
|
|
54
|
-
"false"
|
|
55
|
-
);
|
|
43
|
+
expect(item1).toHaveAttribute("data-state", "off");
|
|
56
44
|
|
|
57
|
-
expect(item2
|
|
58
|
-
"data-segmentedcontrol-isactive",
|
|
59
|
-
"false"
|
|
60
|
-
);
|
|
45
|
+
expect(item2).toHaveAttribute("data-state", "off");
|
|
61
46
|
|
|
62
|
-
expect(item3
|
|
63
|
-
"data-segmentedcontrol-isactive",
|
|
64
|
-
"true"
|
|
65
|
-
);
|
|
47
|
+
expect(item3).toHaveAttribute("data-state", "on");
|
|
66
48
|
|
|
67
49
|
fireEvent.click(item2);
|
|
68
50
|
|
|
69
|
-
expect(item1
|
|
70
|
-
"data-segmentedcontrol-isactive",
|
|
71
|
-
"false"
|
|
72
|
-
);
|
|
51
|
+
expect(item1).toHaveAttribute("data-state", "off");
|
|
73
52
|
|
|
74
|
-
expect(item2
|
|
75
|
-
"data-segmentedcontrol-isactive",
|
|
76
|
-
"true"
|
|
77
|
-
);
|
|
53
|
+
expect(item2).toHaveAttribute("data-state", "on");
|
|
78
54
|
|
|
79
|
-
expect(item3
|
|
80
|
-
"data-segmentedcontrol-isactive",
|
|
81
|
-
"false"
|
|
82
|
-
);
|
|
55
|
+
expect(item3).toHaveAttribute("data-state", "off");
|
|
83
56
|
});
|
|
84
57
|
});
|
package/src/styles.ts
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
disabled,
|
|
6
6
|
} from "@sproutsocial/seeds-react-mixins";
|
|
7
7
|
import Box from "@sproutsocial/seeds-react-box";
|
|
8
|
-
import
|
|
8
|
+
import Button from "@sproutsocial/seeds-react-button";
|
|
9
9
|
import type {
|
|
10
10
|
TypeSegmentedControlProps,
|
|
11
11
|
TypeSegmentedControlItemProps,
|
|
@@ -18,12 +18,40 @@ export const SegmentedControlContainer = styled(Box)<
|
|
|
18
18
|
${(props) => props.theme.colors.button.secondary.border.base};
|
|
19
19
|
border-radius: ${(props) => props.theme.radii.outer};
|
|
20
20
|
padding: ${(props) => props.theme.space[100]};
|
|
21
|
+
display: flex;
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
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]};
|
|
24
38
|
}
|
|
25
39
|
|
|
26
|
-
|
|
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
|
+
}
|
|
27
55
|
`;
|
|
28
56
|
|
|
29
57
|
export const SegmentedControlItemContainer = styled(Box)<
|
|
@@ -52,7 +80,7 @@ interface TypeSegmentedControlState {
|
|
|
52
80
|
isActive: boolean;
|
|
53
81
|
}
|
|
54
82
|
|
|
55
|
-
export const SegmentedControlLabel = styled(
|
|
83
|
+
export const SegmentedControlLabel = styled(Button)<TypeSegmentedControlState>`
|
|
56
84
|
flex: 1 1 auto;
|
|
57
85
|
display: flex;
|
|
58
86
|
align-items: center;
|