@sproutsocial/seeds-react-badge 1.0.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/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@sproutsocial/seeds-react-badge",
3
+ "version": "1.0.0",
4
+ "description": "Seeds React Badge",
5
+ "author": "Sprout Social, Inc.",
6
+ "license": "MIT",
7
+ "main": "dist/index.js",
8
+ "module": "dist/esm/index.js",
9
+ "types": "dist/index.d.ts",
10
+ "scripts": {
11
+ "build": "tsup --dts",
12
+ "build:debug": "tsup --dts --metafile",
13
+ "dev": "tsup --watch --dts",
14
+ "clean": "rm -rf .turbo dist",
15
+ "clean:modules": "rm -rf node_modules",
16
+ "typecheck": "tsc --noEmit",
17
+ "test": "jest",
18
+ "test:watch": "jest --watch --coverage=false"
19
+ },
20
+ "dependencies": {
21
+ "@sproutsocial/seeds-react-box": "*",
22
+ "@sproutsocial/seeds-react-icon": "*",
23
+ "@styled-system/theme-get": "^5.1.2"
24
+ },
25
+ "devDependencies": {
26
+ "tsup": "^8.0.2",
27
+ "typescript": "^5.6.2",
28
+ "@types/react": "^18.0.0",
29
+ "@types/styled-components": "^5.1.26",
30
+ "@sproutsocial/eslint-config-seeds": "*",
31
+ "react": "^18.0.0",
32
+ "styled-components": "^5.2.3",
33
+ "@sproutsocial/seeds-tsconfig": "*",
34
+ "@sproutsocial/seeds-testing": "*",
35
+ "@sproutsocial/seeds-react-testing-library": "*",
36
+ "@types/styled-system": "^5.1.15"
37
+ },
38
+ "peerDependencies": {
39
+ "styled-components": "^5.2.3"
40
+ },
41
+ "engines": {
42
+ "node": ">=18"
43
+ }
44
+ }
@@ -0,0 +1,83 @@
1
+ import React from "react";
2
+ // import Numeral from "@src/Numeral";
3
+ // import Stack from "@src/Stack";
4
+ import { Text } from "@sproutsocial/seeds-react-text";
5
+ import { Badge, type TypeBadgeProps } from "./";
6
+ import { Box } from "@sproutsocial/seeds-react-box";
7
+
8
+ export default {
9
+ title: "Components/Badge",
10
+ component: Badge,
11
+ argTypes: {
12
+ badgeColor: {
13
+ options: [
14
+ "green",
15
+ "purple",
16
+ "yellow",
17
+ "orange",
18
+ "red",
19
+ "magenta",
20
+ "pink",
21
+ "aqua",
22
+ "teal",
23
+ "neutral",
24
+ ],
25
+ control: { type: "select" },
26
+ },
27
+ },
28
+ args: {
29
+ badgeColor: "green",
30
+ },
31
+ };
32
+
33
+ export const ConfigurableBadge = (args: TypeBadgeProps) => (
34
+ <Badge {...args}>I'm a badge</Badge>
35
+ );
36
+
37
+ ConfigurableBadge.story = {
38
+ name: "Configurable badge",
39
+ };
40
+
41
+ export const permutations = () => (
42
+ // <Stack space={450}>
43
+ <Box>
44
+ <Box display="flex" alignItems="center">
45
+ <Badge badgeColor="green">Badge</Badge>
46
+ <Badge>Badge</Badge>
47
+ <Badge badgeColor="purple">Badge</Badge>
48
+ <Badge badgeColor="yellow">Badge</Badge>
49
+ <Badge badgeColor="orange">Badge</Badge>
50
+ <Badge badgeColor="red">Badge</Badge>
51
+ <Badge badgeColor="magenta">Badge</Badge>
52
+ <Badge badgeColor="pink">Badge</Badge>
53
+ <Badge badgeColor="aqua">Badge</Badge>
54
+ <Badge badgeColor="teal">Badge</Badge>
55
+ <Badge badgeColor="neutral" iconName="atom-outline">
56
+ Badge
57
+ </Badge>
58
+ <Badge
59
+ size="small"
60
+ type="default"
61
+ bg="chartreuse"
62
+ color="crimson"
63
+ p={500}
64
+ >
65
+ Radical overrides!
66
+ </Badge>
67
+ </Box>
68
+ <Box display="flex" alignItems="center">
69
+ <Badge size="large" type="secondary" iconName="sparkle-outline">
70
+ Supports legacy types
71
+ </Badge>
72
+ <Badge size="large">
73
+ {/* <Numeral fontWeight="bold" number={1569241} /> */}
74
+ <Text ml={200}>and children!</Text>
75
+ </Badge>
76
+ </Box>
77
+ </Box>
78
+ // </Stack>
79
+ );
80
+
81
+ permutations.story = {
82
+ name: "Permutations",
83
+ };
package/src/Badge.tsx ADDED
@@ -0,0 +1,55 @@
1
+ import * as React from "react";
2
+ import Box from "@sproutsocial/seeds-react-box";
3
+ import Icon from "@sproutsocial/seeds-react-icon";
4
+ import Container from "./styles";
5
+ import type { TypeBadgeProps } from "./BadgeTypes";
6
+
7
+ const Badge = ({
8
+ children,
9
+ text,
10
+ iconName,
11
+ type,
12
+ tip,
13
+ size = "small",
14
+ badgeColor = "blue",
15
+ color,
16
+ ...rest
17
+ }: TypeBadgeProps) => {
18
+ if (children && text) {
19
+ throw new Error(
20
+ "can't use both `children` and `text` props. Text is deprecated, consider using children."
21
+ );
22
+ }
23
+
24
+ return (
25
+ <Container
26
+ // size previously included default, which currently maps to small. Once consumers have updated this can be simplified.
27
+ size={size === "default" ? "large" : size}
28
+ badgeColor={badgeColor}
29
+ data-tip={tip}
30
+ data-qa-badge={text || ""}
31
+ data-qa-badge-type={type}
32
+ data-qa-badge-tip={tip || ""}
33
+ type={type}
34
+ // TODO: fix this type since `color` should be valid here. TS can't resolve the correct type.
35
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
36
+ // @ts-ignore
37
+ color={color}
38
+ {...rest}
39
+ >
40
+ <Box display="flex" alignItems="center" justifyContent="center">
41
+ {iconName ? (
42
+ <Icon
43
+ mr={200}
44
+ name={iconName}
45
+ size={size === "small" ? "mini" : "small"}
46
+ aria-hidden
47
+ />
48
+ ) : null}
49
+ {children || text}
50
+ </Box>
51
+ </Container>
52
+ );
53
+ };
54
+
55
+ export default Badge;
@@ -0,0 +1,30 @@
1
+ import type { TypeIconName } from "@sproutsocial/seeds-react-icon";
2
+ import type {
3
+ TypeSystemCommonProps,
4
+ TypeStyledComponentsCommonProps,
5
+ } from "@sproutsocial/seeds-react-system-props";
6
+ import { badgeColors } from "./constants";
7
+
8
+ export type TypeBadgeColor = keyof typeof badgeColors;
9
+
10
+ export interface TypeBaseBadgeProps
11
+ extends Omit<
12
+ React.ComponentPropsWithoutRef<"span">,
13
+ keyof TypeSystemCommonProps
14
+ >,
15
+ TypeSystemCommonProps,
16
+ TypeStyledComponentsCommonProps {}
17
+
18
+ export interface TypeBadgeProps extends TypeBaseBadgeProps {
19
+ children?: React.ReactNode;
20
+ /** DEPRECATED: Use children instead of text */
21
+ text?: React.ReactNode;
22
+ /** Size default is deprecated in favor of small and large */
23
+ size?: "small" | "large" | "default";
24
+ badgeColor?: TypeBadgeColor;
25
+ iconName?: TypeIconName;
26
+ /** DEPRECATED: Possibly only used for testing. Refrain from using at all if possible. (optional) */
27
+ tip?: React.ReactNode;
28
+ /** DEPRECATED: The legacy method of choosing a theme. Use badgeColor instead. (optional) */
29
+ type?: string;
30
+ }
@@ -0,0 +1,94 @@
1
+ import React from "react";
2
+ import { render, screen } from "@sproutsocial/seeds-react-testing-library";
3
+ import Badge from "../Badge";
4
+
5
+ describe("Badge...", () => {
6
+ it("...should render with default props", () => {
7
+ render(<Badge>Test</Badge>);
8
+ expect(screen.getByText("Test")).toBeInTheDocument();
9
+ expect(screen.getByText("Test").closest("span")).toHaveStyleRule(
10
+ "padding",
11
+ "0px 4px"
12
+ );
13
+ expect(screen.getByText("Test").closest("span")).toHaveStyleRule(
14
+ "background",
15
+ "#deebfe"
16
+ );
17
+ });
18
+
19
+ it("...should render with correct size styling", () => {
20
+ render(<Badge size="large">Test</Badge>);
21
+ expect(screen.getByText("Test").closest("span")).toHaveStyleRule(
22
+ "padding",
23
+ "8px"
24
+ );
25
+ });
26
+
27
+ it("...should render with legacy type", () => {
28
+ render(<Badge type="secondary">Test</Badge>);
29
+ expect(screen.getByText("Test")).toBeInTheDocument();
30
+ expect(screen.getByText("Test").closest("span")).toHaveStyleRule(
31
+ "color",
32
+ "#364141"
33
+ );
34
+ expect(screen.getByText("Test").closest("span")).toHaveStyleRule(
35
+ "background",
36
+ "#fdefcd"
37
+ );
38
+ });
39
+
40
+ it("...should render with a badge color", () => {
41
+ render(<Badge badgeColor="purple">Test</Badge>);
42
+ expect(screen.getByText("Test")).toBeInTheDocument();
43
+ expect(screen.getByText("Test").closest("span")).toHaveStyleRule(
44
+ "background",
45
+ "#eaeaf9"
46
+ );
47
+ });
48
+
49
+ it("...should render with an icon", () => {
50
+ const { container } = render(
51
+ <Badge iconName="sparkle-outline">Test</Badge>
52
+ );
53
+ expect(container.querySelector("svg")).toBeTruthy();
54
+ });
55
+ it("...should fail with invalid iconName", () => {
56
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
57
+ // @ts-expect-error
58
+ render(<Badge iconName="someinvalidname123">Test</Badge>);
59
+ });
60
+ it("should render with suggestion type", () => {
61
+ render(<Badge text="Test" type="suggestion" />);
62
+ expect(screen.getByText("Test")).toBeInTheDocument();
63
+ expect(
64
+ screen.getByDataQaLabel({ "badge-type": "suggestion" })
65
+ ).toBeTruthy();
66
+ });
67
+
68
+ it("...should render with tooltip class", () => {
69
+ render(<Badge tip="test tip">Test</Badge>);
70
+ expect(screen.getByText("Test")).toBeInTheDocument();
71
+ expect(screen.getByDataQaLabel({ "badge-tip": "test tip" })).toBeTruthy();
72
+ });
73
+
74
+ it("...should allow overriding qa props", () => {
75
+ render(
76
+ <Badge
77
+ data-qa-badge="text-override"
78
+ data-qa-badge-type="type-override"
79
+ data-qa-badge-tip="tip-override"
80
+ type="suggestion"
81
+ tip="tip"
82
+ >
83
+ Text
84
+ </Badge>
85
+ );
86
+ expect(screen.getByDataQaLabel({ badge: "text-override" })).toBeTruthy();
87
+ expect(
88
+ screen.getByDataQaLabel({ "badge-type": "type-override" })
89
+ ).toBeTruthy();
90
+ expect(
91
+ screen.getByDataQaLabel({ "badge-tip": "tip-override" })
92
+ ).toBeTruthy();
93
+ });
94
+ });
@@ -0,0 +1,28 @@
1
+ import * as React from "react";
2
+ import { render } from "@sproutsocial/seeds-react-testing-library";
3
+ import Badge from "../Badge";
4
+
5
+ describe.skip("Badge/types", () => {
6
+ it("should render valid props", () => {
7
+ render(
8
+ <>
9
+ <Badge>Test</Badge>
10
+ <Badge size="large">Test</Badge>
11
+ <Badge type="secondary">Test</Badge>
12
+ <Badge badgeColor="purple">Test</Badge>
13
+ <Badge badgeColor="red">Test</Badge>
14
+ <Badge badgeColor="magenta">Test</Badge>
15
+ <Badge badgeColor="neutral">Test</Badge>
16
+ <Badge badgeColor="aqua">Test</Badge>
17
+ <Badge iconName="sparkle-outline">Test</Badge>;
18
+ <Badge text="Test" type="suggestion" />
19
+ <Badge tip="test tip">Test</Badge>
20
+ <Badge data-qa-badge="123456">Test</Badge>
21
+ {/* @ts-expect-error - test that invalid iconName is rejected */}
22
+ <Badge iconName="someinvalidname123">Test</Badge>
23
+ {/* @ts-expect-error - test that invalid badgeColor is rejected */}
24
+ <Badge badgeColor="notARealColor">Test</Badge>
25
+ </>
26
+ );
27
+ });
28
+ });
@@ -0,0 +1,64 @@
1
+ const defaultPurple = {
2
+ color: "colors.text.body",
3
+ background: "colors.container.background.decorative.purple",
4
+ };
5
+
6
+ const suggestion = {
7
+ color: "colors.text.body",
8
+ background: "colors.container.background.decorative.blue",
9
+ };
10
+
11
+ const passive = {
12
+ color: "colors.text.body",
13
+ background: "colors.container.background.decorative.neutral",
14
+ };
15
+
16
+ const primary = {
17
+ color: "colors.text.body",
18
+ background: "colors.container.background.decorative.blue",
19
+ };
20
+
21
+ const secondary = {
22
+ color: "colors.text.body",
23
+ background: "colors.container.background.decorative.yellow",
24
+ };
25
+
26
+ const common = {
27
+ color: "colors.text.inverse",
28
+ background: "colors.aqua.600",
29
+ };
30
+
31
+ const approval = {
32
+ color: "colors.text.body",
33
+ background: "colors.container.background.decorative.orange",
34
+ };
35
+
36
+ //Deprecated former "types"
37
+
38
+ /**
39
+ * @deprecated Use badgeColor instead
40
+ */
41
+
42
+ export const legacyBadgeColors = {
43
+ primary,
44
+ secondary,
45
+ passive,
46
+ common,
47
+ approval,
48
+ default: defaultPurple,
49
+ suggestion,
50
+ };
51
+
52
+ export const badgeColors = {
53
+ green: "green",
54
+ blue: "blue",
55
+ purple: "purple",
56
+ yellow: "yellow",
57
+ orange: "orange",
58
+ red: "red",
59
+ neutral: "neutral",
60
+ magenta: "magenta",
61
+ pink: "pink",
62
+ aqua: "aqua",
63
+ teal: "teal",
64
+ } as const;
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ import Badge from "./Badge";
2
+
3
+ export default Badge;
4
+ export { Badge };
5
+ export * from "./BadgeTypes";
6
+ export * from "./constants";
package/src/styles.ts ADDED
@@ -0,0 +1,36 @@
1
+ import styled from "styled-components";
2
+
3
+ import { COMMON } from "@sproutsocial/seeds-react-system-props";
4
+ import { legacyBadgeColors } from "./constants";
5
+ // @ts-ignore: no types exist for this thang
6
+ import { themeGet } from "@styled-system/theme-get";
7
+
8
+ type TypeTypeKey = keyof typeof legacyBadgeColors;
9
+
10
+ const Container = styled.span<{
11
+ type?: TypeTypeKey;
12
+ badgeColor: string;
13
+ size: string;
14
+ }>`
15
+ font-family: ${(p) => p.theme.fontFamily};
16
+ ${(p) =>
17
+ p.size === "small" ? p.theme.typography[100] : p.theme.typography[200]};
18
+ border-radius: 9999px;
19
+ line-height: 16px;
20
+ display: inline-block;
21
+ color: ${(p) =>
22
+ p.type
23
+ ? themeGet(legacyBadgeColors[p.type].color)
24
+ : p.theme.colors.text.body};
25
+ background: ${(p) =>
26
+ p.type
27
+ ? themeGet(legacyBadgeColors[p.type].background)
28
+ : p.theme.colors.container.background.decorative[p.badgeColor]};
29
+ padding: ${(p) =>
30
+ p.size === "small"
31
+ ? `${p.theme.space[0]} ${p.theme.space[200]}`
32
+ : `${p.theme.space[300]}`};
33
+ ${COMMON};
34
+ `;
35
+
36
+ export default Container;
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
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"]
9
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,12 @@
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
+ }));