@sproutsocial/seeds-react-segmented-control 1.1.24 → 1.1.25

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