@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/.eslintignore +6 -0
- package/.eslintrc.js +4 -0
- package/.turbo/turbo-build.log +21 -0
- package/CHANGELOG.md +7 -0
- package/dist/esm/index.js +577 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/index.d.mts +71 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.js +616 -0
- package/dist/index.js.map +1 -0
- package/jest.config.js +9 -0
- package/package.json +44 -0
- package/src/Badge.stories.tsx +83 -0
- package/src/Badge.tsx +55 -0
- package/src/BadgeTypes.ts +30 -0
- package/src/__tests__/features.test.tsx +94 -0
- package/src/__tests__/types.test.tsx +28 -0
- package/src/constants.ts +64 -0
- package/src/index.ts +6 -0
- package/src/styles.ts +36 -0
- package/tsconfig.json +9 -0
- package/tsup.config.ts +12 -0
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
|
+
});
|
package/src/constants.ts
ADDED
|
@@ -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
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
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
|
+
}));
|