@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.
@@ -3,19 +3,19 @@ $ tsup --dts
3
3
  CLI Building entry: src/index.ts
4
4
  CLI Using tsconfig: tsconfig.json
5
5
  CLI tsup v8.5.0
6
- CLI Using tsup config: /home/runner/work/seeds/seeds/seeds-react/seeds-react-segmented-control/tsup.config.ts
6
+ CLI Using tsup config: /home/runner/_work/seeds/seeds/seeds-react/seeds-react-segmented-control/tsup.config.ts
7
7
  CLI Target: es2022
8
8
  CLI Cleaning output folder
9
9
  CJS Build start
10
10
  ESM Build start
11
- ESM dist/esm/index.js 4.47 KB
12
- ESM dist/esm/index.js.map 8.81 KB
13
- ESM ⚡️ Build success in 218ms
14
- CJS dist/index.js 6.73 KB
15
- CJS dist/index.js.map 8.90 KB
16
- CJS ⚡️ Build success in 254ms
11
+ CJS dist/index.js 7.20 KB
12
+ CJS dist/index.js.map 10.49 KB
13
+ CJS ⚡️ Build success in 15ms
14
+ ESM dist/esm/index.js 5.04 KB
15
+ ESM dist/esm/index.js.map 10.41 KB
16
+ ESM ⚡️ Build success in 14ms
17
17
  DTS Build start
18
- DTS ⚡️ Build success in 30853ms
19
- DTS dist/index.d.ts 1.47 KB
20
- DTS dist/index.d.mts 1.47 KB
21
- Done in 38.59s.
18
+ DTS ⚡️ Build success in 4008ms
19
+ DTS dist/index.d.ts 1.66 KB
20
+ DTS dist/index.d.mts 1.66 KB
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, useContext } from "react";
4
- import Box2 from "@sproutsocial/seeds-react-box";
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 Text from "@sproutsocial/seeds-react-text";
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
- legend {
22
- ${visuallyHidden}
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
- ${(props) => props.disabled && disabled}
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(Text)`
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, jsxs } from "react/jsx-runtime";
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
- const context = useContext(SegmentedControlContext);
93
- if (!context) {
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
- "data-segmentedcontrol-isactive": isChecked,
103
- "data-qa-segmentedcontrol-item": value,
104
- "data-qa-segmentedcontrol-ischecked": isChecked === true,
118
+ value,
119
+ "aria-label": "Left aligned",
105
120
  disabled: disabled2,
106
- ...rest,
107
- children: [
108
- /* @__PURE__ */ jsx(
109
- "input",
110
- {
111
- type: "radio",
112
- id,
113
- name,
114
- value,
115
- checked: isChecked,
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
- SegmentedControlContext.Provider,
145
+ ToggleGroup.Root,
135
146
  {
136
- value: {
137
- name,
138
- selectedValue,
139
- onChange
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
- children: /* @__PURE__ */ jsxs(
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
  }
@@ -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":"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","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: (e: React.SyntheticEvent<HTMLInputElement>) => void;
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 | null;
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: (e: React.SyntheticEvent<HTMLInputElement>) => void;
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 | null;
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 import_seeds_react_box2 = __toESM(require("@sproutsocial/seeds-react-box"));
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 import_seeds_react_text = __toESM(require("@sproutsocial/seeds-react-text"));
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
- legend {
55
- ${import_seeds_react_mixins.visuallyHidden}
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
- ${(props) => props.disabled && import_seeds_react_mixins.disabled}
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)(import_seeds_react_text.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
- const context = (0, import_react.useContext)(SegmentedControlContext);
126
- if (!context) {
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
- "data-segmentedcontrol-isactive": isChecked,
136
- "data-qa-segmentedcontrol-item": value,
137
- "data-qa-segmentedcontrol-ischecked": isChecked === true,
151
+ value,
152
+ "aria-label": "Left aligned",
138
153
  disabled: disabled2,
139
- ...rest,
140
- children: [
141
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
142
- "input",
143
- {
144
- type: "radio",
145
- id,
146
- name,
147
- value,
148
- checked: isChecked,
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
- SegmentedControlContext.Provider,
178
+ ToggleGroup.Root,
168
179
  {
169
- value: {
170
- name,
171
- selectedValue,
172
- onChange
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
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,YAAuB;AACvB,mBAAqC;AACrC,IAAAA,0BAAgB;;;ACFhB,+BAA4B;AAC5B,gCAIO;AACP,6BAAgB;AAChB,8BAAiB;AAMV,IAAM,gCAA4B,yBAAAC,SAAO,uBAAAC,OAAG;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,MAGxC,wCAAc;AAAA;AAAA;AAAA,IAGhB,CAAC,UAAU,MAAM,YAAY,kCAAQ;AAAA;AAGlC,IAAM,oCAAgC,yBAAAD,SAAO,uBAAAC,OAAG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAQpC,CAAC,UAAU,MAAM,MAAM,MAAM,GAAG,CAAC;AAAA;AAAA;AAAA;AAAA,MAI9C,mCAAS;AAAA;AAAA;AAAA;AAAA,MAIT,wCAAc;AAAA;AAAA;AAAA,IAGhB,CAAC,UAAU,MAAM,YAAY,kCAAQ;AAAA;AAOlC,IAAM,4BAAwB,yBAAAD,SAAO,wBAAAE,OAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAMrC,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,CAACC,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;;;AD9CD;AAhCJ,IAAI,cAAc;AAClB,IAAI,YAAY;AAQhB,IAAM,0BAAgC,oBAEpC,IAAI;AAEN,IAAM,uBAAuB,CAAC;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,UAAAC;AAAA,EACA,GAAG;AACL,MAAqC;AACnC,QAAM,cAAU,yBAAW,uBAAuB;AAElD,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AAEA,QAAM,EAAE,MAAM,eAAe,SAAS,IAAI;AAG1C,QAAM,CAAC,EAAE,QAAI,uBAAS,GAAG,IAAI,IAAI,WAAW,EAAE;AAC9C,QAAM,YAAY,UAAU;AAE5B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,kCAAgC;AAAA,MAChC,iCAA+B;AAAA,MAC/B,sCAAoC,cAAc;AAAA,MAClD,UAAUA;AAAA,MACT,GAAG;AAAA,MAEJ;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL;AAAA,YACA;AAAA,YACA;AAAA,YACA,SAAS;AAAA,YACT;AAAA,YACA,UAAUA;AAAA;AAAA,QACZ;AAAA,QACA,4CAAC,yBAAsB,IAAG,SAAQ,SAAS,IAAI,UAAU,WACtD,UACH;AAAA;AAAA;AAAA,EACF;AAEJ;AAEA,IAAM,mBAAmB,CAAC;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAiC;AAC/B,QAAM,CAAC,IAAI,QAAI,uBAAS,4BAA4B,aAAa,EAAE;AACnE,SACE;AAAA,IAAC,wBAAwB;AAAA,IAAxB;AAAA,MACC,OAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,aAAY;AAAA,UACZ,4BAA0B;AAAA,UAC1B,kCAAgC;AAAA,UAC/B,GAAG;AAAA,UAEJ;AAAA,wDAAC,YAAQ,iBAAM;AAAA,YAEf,4CAAC,wBAAAC,SAAA,EAAI,SAAQ,QAAQ,UAAS;AAAA;AAAA;AAAA,MAChC;AAAA;AAAA,EACF;AAEJ;AAEA,qBAAqB,cAAc;AACnC,iBAAiB,OAAO;AAExB,IAAO,2BAAQ;;;AEpGf,IAAAC,SAAuB;;;AHCvB,IAAO,gBAAQ;","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.13",
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
- "@sproutsocial/seeds-react-theme": "^3.5.1",
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.13",
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.2.5"
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) => setValue((e.target as HTMLInputElement).value)}
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
- onChange={(e) => setValue((e.target as HTMLInputElement).value)}
62
+ onValueChange={setValue}
59
63
  flex="1"
60
64
  >
61
65
  <SegmentedControl.Item value="1">Test 1</SegmentedControl.Item>
@@ -1,11 +1,7 @@
1
1
  import * as React from "react";
2
- import { useState, useContext } from "react";
3
- import Box from "@sproutsocial/seeds-react-box";
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
- <SegmentedControlItemContainer
47
- data-segmentedcontrol-isactive={isChecked}
48
- data-qa-segmentedcontrol-item={value}
49
- data-qa-segmentedcontrol-ischecked={isChecked === true}
30
+ <ToggleGroup.Item
31
+ value={value}
32
+ aria-label="Left aligned"
50
33
  disabled={disabled}
51
- {...rest}
34
+ asChild
52
35
  >
53
- <input
54
- type="radio"
55
- id={id}
56
- name={name}
57
- value={value}
58
- checked={isChecked}
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
- <SegmentedControlLabel as="label" htmlFor={id} isActive={isChecked}>
43
+ {...rest}
44
+ >
63
45
  {children}
64
- </SegmentedControlLabel>
65
- </SegmentedControlItemContainer>
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
- <SegmentedControlContext.Provider
79
- value={{
80
- name,
81
- selectedValue,
82
- onChange,
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
- <legend>{label}</legend>
92
-
93
- <Box display="flex">{children}</Box>
89
+ {children}
94
90
  </SegmentedControlContainer>
95
- </SegmentedControlContext.Provider>
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: (e: React.SyntheticEvent<HTMLInputElement>) => void;
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?.parentNode).toHaveAttribute(
36
- "data-segmentedcontrol-isactive",
37
- "true"
38
- );
35
+ expect(item1).toHaveAttribute("data-state", "on");
39
36
 
40
- expect(item2?.parentNode).toHaveAttribute(
41
- "data-segmentedcontrol-isactive",
42
- "false"
43
- );
37
+ expect(item2).toHaveAttribute("data-state", "off");
44
38
 
45
- expect(item3?.parentNode).toHaveAttribute(
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?.parentNode).toHaveAttribute(
53
- "data-segmentedcontrol-isactive",
54
- "false"
55
- );
43
+ expect(item1).toHaveAttribute("data-state", "off");
56
44
 
57
- expect(item2?.parentNode).toHaveAttribute(
58
- "data-segmentedcontrol-isactive",
59
- "false"
60
- );
45
+ expect(item2).toHaveAttribute("data-state", "off");
61
46
 
62
- expect(item3?.parentNode).toHaveAttribute(
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?.parentNode).toHaveAttribute(
70
- "data-segmentedcontrol-isactive",
71
- "false"
72
- );
51
+ expect(item1).toHaveAttribute("data-state", "off");
73
52
 
74
- expect(item2?.parentNode).toHaveAttribute(
75
- "data-segmentedcontrol-isactive",
76
- "true"
77
- );
53
+ expect(item2).toHaveAttribute("data-state", "on");
78
54
 
79
- expect(item3?.parentNode).toHaveAttribute(
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 Text from "@sproutsocial/seeds-react-text";
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
- legend {
23
- ${visuallyHidden}
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
- ${(props) => props.disabled && disabled}
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(Text)<TypeSegmentedControlState>`
83
+ export const SegmentedControlLabel = styled(Button)<TypeSegmentedControlState>`
56
84
  flex: 1 1 auto;
57
85
  display: flex;
58
86
  align-items: center;