@sproutsocial/racine 11.3.0-beta.1 → 11.3.0-beta.4
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/CHANGELOG.md +30 -0
- package/__flow__/Badge/constants.js +48 -0
- package/__flow__/Badge/index.js +60 -33
- package/__flow__/Badge/index.stories.js +35 -42
- package/__flow__/Badge/index.test.js +34 -32
- package/__flow__/Badge/styles.js +22 -42
- package/__flow__/Input/index.js +40 -14
- package/__flow__/Input/index.stories.js +33 -1
- package/__flow__/Input/index.test.js +28 -0
- package/__flow__/Link/index.js +2 -1
- package/__flow__/themes/extendedThemes/README.md +6 -0
- package/commonjs/Badge/constants.js +43 -0
- package/commonjs/Badge/index.js +41 -39
- package/commonjs/Badge/styles.js +15 -31
- package/commonjs/Input/index.js +47 -13
- package/lib/Badge/constants.js +38 -0
- package/lib/Badge/index.js +38 -39
- package/lib/Badge/styles.js +12 -27
- package/lib/Input/index.js +47 -13
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 11.2.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 206bd32: copy updates to the TypeProps comments that power Seeds prop tables
|
|
8
|
+
|
|
9
|
+
## 11.2.3
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 514d738: Patch badge component flow issue
|
|
14
|
+
|
|
15
|
+
## 11.2.2
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 9cc377e: Created extended theme directory
|
|
20
|
+
|
|
21
|
+
## 11.2.1
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- 6968733: adds deprecation messaging to typeProps to be displayed on seeds page
|
|
26
|
+
|
|
27
|
+
## 11.2.0
|
|
28
|
+
|
|
29
|
+
### Minor Changes
|
|
30
|
+
|
|
31
|
+
- a71a431: backwards compatible style and api changes to the badge component
|
|
32
|
+
|
|
3
33
|
## 11.1.2
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
//@flow
|
|
2
|
+
|
|
3
|
+
const defaultPurple = {
|
|
4
|
+
color: "colors.text.body",
|
|
5
|
+
background: "colors.container.background.decorative.purple",
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const suggestion = {
|
|
9
|
+
color: "colors.text.body",
|
|
10
|
+
background: "colors.container.background.decorative.blue",
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const passive = {
|
|
14
|
+
color: "colors.text.body",
|
|
15
|
+
background: "colors.container.background.decorative.neutral",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const primary = {
|
|
19
|
+
color: "colors.text.body",
|
|
20
|
+
background: "colors.container.background.decorative.blue",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const secondary = {
|
|
24
|
+
color: "colors.text.body",
|
|
25
|
+
background: "colors.container.background.decorative.yellow",
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const common = {
|
|
29
|
+
color: "colors.text.inverse",
|
|
30
|
+
background: "colors.aqua.600",
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const approval = {
|
|
34
|
+
color: "colors.text.body",
|
|
35
|
+
background: "colors.container.background.decorative.orange",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
//Deprecated former "types"
|
|
39
|
+
|
|
40
|
+
export const legacyBadgeColors = {
|
|
41
|
+
primary,
|
|
42
|
+
secondary,
|
|
43
|
+
passive,
|
|
44
|
+
common,
|
|
45
|
+
approval,
|
|
46
|
+
default: defaultPurple,
|
|
47
|
+
suggestion,
|
|
48
|
+
};
|
package/__flow__/Badge/index.js
CHANGED
|
@@ -1,43 +1,70 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
import * as React from "react";
|
|
3
|
+
import Icon from "../Icon";
|
|
3
4
|
import Container from "./styles";
|
|
5
|
+
import Box from "../Box";
|
|
4
6
|
|
|
5
7
|
type TypeProps = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
| "
|
|
13
|
-
| "
|
|
14
|
-
| "
|
|
15
|
-
|
|
8
|
+
children?: React.Node,
|
|
9
|
+
/** DEPRECATED: Use children instead of text */
|
|
10
|
+
text?: React.Node,
|
|
11
|
+
/** Size default is deprecated in favor of small and large */
|
|
12
|
+
size?: "small" | "large" | "default",
|
|
13
|
+
badgeColor?:
|
|
14
|
+
| "green"
|
|
15
|
+
| "blue"
|
|
16
|
+
| "purple"
|
|
17
|
+
| "yellow"
|
|
18
|
+
| "orange"
|
|
19
|
+
| "red"
|
|
20
|
+
| "neutral",
|
|
21
|
+
iconName?: string,
|
|
22
|
+
/** DEPRECATED: Possibly only used for testing. Refrain from using at all if possible. (optional) */
|
|
16
23
|
tip?: React.Node,
|
|
24
|
+
/** DEPRECATED: The legacy method of choosing a theme. Use badgeColor instead. (optional) */
|
|
25
|
+
type?: string,
|
|
17
26
|
};
|
|
18
27
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
data-tip={tip}
|
|
33
|
-
data-qa-badge={text || ""}
|
|
34
|
-
data-qa-badge-type={type}
|
|
35
|
-
data-qa-badge-tip={tip || ""}
|
|
36
|
-
// $FlowIssue - upgrade v0.112.0
|
|
37
|
-
{...rest}
|
|
38
|
-
>
|
|
39
|
-
{text}
|
|
40
|
-
</Container>
|
|
28
|
+
const Badge = ({
|
|
29
|
+
children,
|
|
30
|
+
text,
|
|
31
|
+
iconName,
|
|
32
|
+
type,
|
|
33
|
+
tip,
|
|
34
|
+
size = "small",
|
|
35
|
+
badgeColor = "blue",
|
|
36
|
+
...rest
|
|
37
|
+
}: TypeProps) => {
|
|
38
|
+
if (children && text) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
"can't use both `children` and `text` props. Text is deprecated, consider using children."
|
|
41
41
|
);
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<Container
|
|
46
|
+
{...rest}
|
|
47
|
+
// size previously included default, which currently maps to small. Once consumers have updated this can be simplified.
|
|
48
|
+
size={size === "default" ? "large" : size}
|
|
49
|
+
badgeColor={badgeColor}
|
|
50
|
+
data-tip={tip}
|
|
51
|
+
data-qa-badge={text || ""}
|
|
52
|
+
data-qa-badge-type={type}
|
|
53
|
+
data-qa-badge-tip={tip || ""}
|
|
54
|
+
type={type && type}
|
|
55
|
+
>
|
|
56
|
+
<Box display="flex" alignItems="center" JustifyContent="center">
|
|
57
|
+
{iconName ? (
|
|
58
|
+
<Icon
|
|
59
|
+
mr={200}
|
|
60
|
+
name={iconName}
|
|
61
|
+
size={size === "small" ? "mini" : "default"}
|
|
62
|
+
/>
|
|
63
|
+
) : null}
|
|
64
|
+
{children || text}
|
|
65
|
+
</Box>
|
|
66
|
+
</Container>
|
|
67
|
+
);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export default Badge;
|
|
@@ -1,53 +1,46 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { text } from "@storybook/addon-knobs";
|
|
3
2
|
import Badge from "./index";
|
|
3
|
+
import Box from "../Box";
|
|
4
|
+
import Numeral from "../Numeral";
|
|
5
|
+
import Text from "../Text";
|
|
6
|
+
import Stack from "../Stack";
|
|
4
7
|
|
|
5
8
|
export default {
|
|
6
9
|
title: "Badge",
|
|
7
10
|
};
|
|
8
11
|
|
|
9
12
|
export const permutations = () => (
|
|
10
|
-
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
size=
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
/>
|
|
42
|
-
|
|
43
|
-
<Badge text={text("text", "Test")} type="default" />
|
|
44
|
-
<Badge text={text("text", "Test")} />
|
|
45
|
-
<Badge text={text("text", "Test")} type="secondary" />
|
|
46
|
-
<Badge text={text("text", "Test")} type="passive" />
|
|
47
|
-
<Badge text={text("text", "Test")} type="common" />
|
|
48
|
-
<Badge text={text("text", "Test")} type="approval" />
|
|
49
|
-
<Badge text={text("text", "Test")} type="suggestion" />
|
|
50
|
-
</>
|
|
13
|
+
<Stack space={450}>
|
|
14
|
+
<Box display="flex" alignItems="center">
|
|
15
|
+
<Badge badgeColor="green">Badge</Badge>
|
|
16
|
+
<Badge>Badge</Badge>
|
|
17
|
+
<Badge badgeColor="purple">Badge</Badge>
|
|
18
|
+
<Badge badgeColor="yellow">Badge</Badge>
|
|
19
|
+
<Badge badgeColor="orange">Badge</Badge>
|
|
20
|
+
<Badge badgeColor="red">Badge</Badge>
|
|
21
|
+
<Badge badgeColor="neutral" iconName="atom">
|
|
22
|
+
Badge
|
|
23
|
+
</Badge>
|
|
24
|
+
<Badge
|
|
25
|
+
size="small"
|
|
26
|
+
type="default"
|
|
27
|
+
bg="chartreuse"
|
|
28
|
+
color="crimson"
|
|
29
|
+
p={500}
|
|
30
|
+
>
|
|
31
|
+
Radical overrides!
|
|
32
|
+
</Badge>
|
|
33
|
+
</Box>
|
|
34
|
+
<Box display="flex" alignItems="center">
|
|
35
|
+
<Badge size="large" type="secondary" iconName="sparkles">
|
|
36
|
+
Supports legacy types
|
|
37
|
+
</Badge>
|
|
38
|
+
<Badge size="large">
|
|
39
|
+
<Numeral fontWeight="bold" number={1569241} />
|
|
40
|
+
<Text ml={200}>and children!</Text>
|
|
41
|
+
</Badge>
|
|
42
|
+
</Box>
|
|
43
|
+
</Stack>
|
|
51
44
|
);
|
|
52
45
|
|
|
53
46
|
permutations.story = {
|
|
@@ -3,48 +3,50 @@ import Badge from "./";
|
|
|
3
3
|
import { render } from "../utils/react-testing-library";
|
|
4
4
|
import "jest-styled-components";
|
|
5
5
|
|
|
6
|
-
describe("
|
|
7
|
-
it("should render with default props", () => {
|
|
8
|
-
const { getByText
|
|
6
|
+
describe("Badge...", () => {
|
|
7
|
+
it("...should render with default props", () => {
|
|
8
|
+
const { getByText } = render(<Badge>Test</Badge>);
|
|
9
9
|
expect(getByText("Test")).toBeTruthy();
|
|
10
|
-
expect(
|
|
10
|
+
expect(getByText("Test").closest("span")).toHaveStyleRule(
|
|
11
|
+
"padding",
|
|
12
|
+
"0px 4px"
|
|
13
|
+
);
|
|
14
|
+
expect(getByText("Test").closest("span")).toHaveStyleRule(
|
|
15
|
+
"background",
|
|
16
|
+
"#dcf2ff"
|
|
17
|
+
);
|
|
11
18
|
});
|
|
12
19
|
|
|
13
|
-
it("should render with correct size styling", () => {
|
|
14
|
-
const { getByText } = render(<Badge
|
|
15
|
-
expect(getByText("Test")).toHaveStyleRule("padding", "
|
|
20
|
+
it("...should render with correct size styling", () => {
|
|
21
|
+
const { getByText } = render(<Badge size="large">Test</Badge>);
|
|
22
|
+
expect(getByText("Test").closest("span")).toHaveStyleRule("padding", "8px");
|
|
16
23
|
});
|
|
17
24
|
|
|
18
|
-
it("should render with
|
|
19
|
-
const { getByText
|
|
20
|
-
<Badge text="Test" type="secondary" />
|
|
21
|
-
);
|
|
25
|
+
it("...should render with legacy type", () => {
|
|
26
|
+
const { getByText } = render(<Badge type="secondary">Test</Badge>);
|
|
22
27
|
expect(getByText("Test")).toBeTruthy();
|
|
23
|
-
expect(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
expect(getByText("Test").closest("span")).toHaveStyleRule(
|
|
29
|
+
"color",
|
|
30
|
+
"#364141"
|
|
31
|
+
);
|
|
32
|
+
expect(getByText("Test").closest("span")).toHaveStyleRule(
|
|
33
|
+
"background",
|
|
34
|
+
"#fdefcd"
|
|
29
35
|
);
|
|
30
|
-
expect(getByText("Test")).toBeTruthy();
|
|
31
|
-
expect(getByDataQaLabel({ "badge-type": "passive" })).toBeTruthy();
|
|
32
36
|
});
|
|
33
37
|
|
|
34
|
-
it("should render with
|
|
35
|
-
const { getByText
|
|
36
|
-
<Badge text="Test" type="common" />
|
|
37
|
-
);
|
|
38
|
+
it("...should render with a badge color", () => {
|
|
39
|
+
const { getByText } = render(<Badge badgeColor="purple">Test</Badge>);
|
|
38
40
|
expect(getByText("Test")).toBeTruthy();
|
|
39
|
-
expect(
|
|
41
|
+
expect(getByText("Test").closest("span")).toHaveStyleRule(
|
|
42
|
+
"background",
|
|
43
|
+
"#eaeaf9"
|
|
44
|
+
);
|
|
40
45
|
});
|
|
41
46
|
|
|
42
|
-
it("should render with
|
|
43
|
-
const {
|
|
44
|
-
|
|
45
|
-
);
|
|
46
|
-
expect(getByText("Test")).toBeTruthy();
|
|
47
|
-
expect(getByDataQaLabel({ "badge-type": "approval" })).toBeTruthy();
|
|
47
|
+
it("...should render with an icon", () => {
|
|
48
|
+
const { container } = render(<Badge iconName="sparkles">Test</Badge>);
|
|
49
|
+
expect(container.querySelector("svg")).toBeTruthy();
|
|
48
50
|
});
|
|
49
51
|
it("should render with suggestion type", () => {
|
|
50
52
|
const { getByText, getByDataQaLabel } = render(
|
|
@@ -54,9 +56,9 @@ describe("Racine Badge", () => {
|
|
|
54
56
|
expect(getByDataQaLabel({ "badge-type": "suggestion" })).toBeTruthy();
|
|
55
57
|
});
|
|
56
58
|
|
|
57
|
-
it("should render with tooltip class", () => {
|
|
59
|
+
it("...should render with tooltip class", () => {
|
|
58
60
|
const { getByText, getByDataQaLabel } = render(
|
|
59
|
-
<Badge
|
|
61
|
+
<Badge tip="test tip">Test</Badge>
|
|
60
62
|
);
|
|
61
63
|
expect(getByText("Test")).toBeTruthy();
|
|
62
64
|
expect(getByDataQaLabel({ "badge-tip": "test tip" })).toBeTruthy();
|
package/__flow__/Badge/styles.js
CHANGED
|
@@ -1,51 +1,31 @@
|
|
|
1
1
|
//@flow
|
|
2
|
-
import styled, {
|
|
2
|
+
import styled, { type StyledComponent } from "styled-components";
|
|
3
3
|
import { COMMON } from "../utils/system-props";
|
|
4
|
-
import { themeGet } from "@styled-system/theme-get";
|
|
5
|
-
|
|
6
4
|
import type { TypeTheme } from "../types/theme.flow";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
primary: "colors.neutral.0",
|
|
10
|
-
secondary: "colors.neutral.800",
|
|
11
|
-
passive: "colors.neutral.800",
|
|
12
|
-
common: "colors.neutral.0",
|
|
13
|
-
approval: "colors.neutral.800",
|
|
14
|
-
default: "colors.neutral.0",
|
|
15
|
-
suggestion: "colors.neutral.900",
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const backgroundColors = {
|
|
19
|
-
primary: "colors.blue.700",
|
|
20
|
-
secondary: "colors.yellow.500",
|
|
21
|
-
passive: "colors.neutral.200",
|
|
22
|
-
common: "colors.aqua.600",
|
|
23
|
-
approval: "colors.orange.300",
|
|
24
|
-
default: "colors.purple.700",
|
|
25
|
-
suggestion: "colors.blue.300",
|
|
26
|
-
};
|
|
5
|
+
import { themeGet } from "@styled-system/theme-get";
|
|
6
|
+
import { legacyBadgeColors } from "./constants";
|
|
27
7
|
|
|
28
8
|
// eslint-disable-next-line prettier/prettier
|
|
29
|
-
const Container: StyledComponent<{type:
|
|
9
|
+
const Container: StyledComponent<{type: ?string, badgeColor: string, size: string, ...}, TypeTheme, *> = styled.span`
|
|
10
|
+
font-family: ${(p) => p.theme.fontFamily};
|
|
11
|
+
${(p) =>
|
|
12
|
+
p.size === "small" ? p.theme.typography[100] : p.theme.typography[200]};
|
|
13
|
+
border-radius: 9999px;
|
|
14
|
+
line-height: 16px;
|
|
30
15
|
display: inline-block;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
?
|
|
38
|
-
:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
${
|
|
44
|
-
color: ${themeGet(colors[props.type])(props)};
|
|
45
|
-
background: ${themeGet(backgroundColors[props.type])(props)};
|
|
46
|
-
`}
|
|
47
|
-
|
|
48
|
-
${COMMON}
|
|
16
|
+
color: ${(p) =>
|
|
17
|
+
p.type
|
|
18
|
+
? themeGet(legacyBadgeColors[p.type].color)
|
|
19
|
+
: p.theme.colors.text.body};
|
|
20
|
+
background: ${(p) =>
|
|
21
|
+
p.type
|
|
22
|
+
? themeGet(legacyBadgeColors[p.type].background)
|
|
23
|
+
: p.theme.colors.container.background.decorative[p.badgeColor]};
|
|
24
|
+
padding: ${(p) =>
|
|
25
|
+
p.size === "small"
|
|
26
|
+
? `${p.theme.space[0]} ${p.theme.space[200]}`
|
|
27
|
+
: `${p.theme.space[300]}`};
|
|
28
|
+
${COMMON};
|
|
49
29
|
`;
|
|
50
30
|
|
|
51
31
|
export default Container;
|
package/__flow__/Input/index.js
CHANGED
|
@@ -72,21 +72,48 @@ type TypeProps = {
|
|
|
72
72
|
type TypeInputContext = $Shape<{
|
|
73
73
|
handleClear: (e: SyntheticEvent<HTMLButtonElement>) => void,
|
|
74
74
|
clearButtonLabel: string,
|
|
75
|
+
hasValue: boolean,
|
|
75
76
|
}>;
|
|
76
77
|
|
|
77
78
|
const InputContext = React.createContext<TypeInputContext>({});
|
|
78
79
|
|
|
79
80
|
const ClearButton = () => {
|
|
80
|
-
const { handleClear, clearButtonLabel } =
|
|
81
|
+
const { handleClear, clearButtonLabel, hasValue, size } =
|
|
82
|
+
React.useContext(InputContext);
|
|
83
|
+
|
|
84
|
+
// Hide the button when there is no text to clear.
|
|
85
|
+
if (!hasValue) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Cut down the padding for size small Inputs so that the focus ring won't go outside the bounds of the Input.
|
|
90
|
+
// This adjustment is handled automatically for default and large Inputs via Button's size. There is no "small" Button.
|
|
91
|
+
const py = size === "small" ? 100 : undefined;
|
|
92
|
+
const px = size === "small" ? 200 : undefined;
|
|
93
|
+
const buttonSize = size === "small" ? "default" : size;
|
|
94
|
+
|
|
95
|
+
// Warn if clearButtonLabel is not included, so that the unlocalized fallback will not be mistaken for a proper label.
|
|
96
|
+
if (!clearButtonLabel) {
|
|
97
|
+
console.warn(
|
|
98
|
+
"Warning: clearButtonLabel prop is required when using Input.ClearButton. Please pass a localized label to Input."
|
|
99
|
+
);
|
|
100
|
+
}
|
|
81
101
|
return (
|
|
82
|
-
<Button onClick={handleClear}>
|
|
83
|
-
{/*Unlocalized fallback should not be used. Always include a localized
|
|
84
|
-
clearButtonLabel when using <Input.ClearButton/> or <Input type="search"/>.*/}
|
|
102
|
+
<Button onClick={handleClear} size={buttonSize} py={py} px={px}>
|
|
85
103
|
<Icon name="circlex" title={clearButtonLabel || "Clear"} />
|
|
86
104
|
</Button>
|
|
87
105
|
);
|
|
88
106
|
};
|
|
89
107
|
|
|
108
|
+
// Used for positioning elementAfter. This logic will detect if the element is a ClearButton,
|
|
109
|
+
// regardless of whether it was manually passed as elemAfter or automatically added to a search Input.
|
|
110
|
+
const isClearButton = (elem: any) => {
|
|
111
|
+
if (elem?.type) {
|
|
112
|
+
return elem.type.displayName === "Input.ClearButton";
|
|
113
|
+
}
|
|
114
|
+
return false;
|
|
115
|
+
};
|
|
116
|
+
|
|
90
117
|
class Input extends React.Component<TypeProps> {
|
|
91
118
|
static defaultProps = {
|
|
92
119
|
autoFocus: false,
|
|
@@ -101,8 +128,10 @@ class Input extends React.Component<TypeProps> {
|
|
|
101
128
|
handleBlur = (e: SyntheticFocusEvent<HTMLInputElement>) =>
|
|
102
129
|
this.props.onBlur?.(e);
|
|
103
130
|
|
|
104
|
-
handleClear = (e: SyntheticEvent<HTMLButtonElement>) =>
|
|
131
|
+
handleClear = (e: SyntheticEvent<HTMLButtonElement>) => {
|
|
105
132
|
this.props.onClear?.(e);
|
|
133
|
+
this.props.innerRef?.current?.focus();
|
|
134
|
+
};
|
|
106
135
|
|
|
107
136
|
handleChange = (e: SyntheticInputEvent<HTMLInputElement>) =>
|
|
108
137
|
this.props.onChange?.(e, e.currentTarget.value);
|
|
@@ -150,6 +179,7 @@ class Input extends React.Component<TypeProps> {
|
|
|
150
179
|
inputProps = {},
|
|
151
180
|
qa = {},
|
|
152
181
|
appearance,
|
|
182
|
+
size,
|
|
153
183
|
...rest
|
|
154
184
|
} = this.props;
|
|
155
185
|
|
|
@@ -162,7 +192,7 @@ class Input extends React.Component<TypeProps> {
|
|
|
162
192
|
// Add default elemBefore and elemAfter elements if type is search.
|
|
163
193
|
const elementBefore =
|
|
164
194
|
type === "search" && !elemBefore ? (
|
|
165
|
-
<Icon name="search" ariaHidden />
|
|
195
|
+
<Icon name="search" ariaHidden color="icon.base" />
|
|
166
196
|
) : (
|
|
167
197
|
elemBefore
|
|
168
198
|
);
|
|
@@ -178,13 +208,16 @@ class Input extends React.Component<TypeProps> {
|
|
|
178
208
|
invalid={!!isInvalid}
|
|
179
209
|
warning={hasWarning}
|
|
180
210
|
appearance={appearance}
|
|
211
|
+
size={size}
|
|
181
212
|
// $FlowIssue - upgrade v0.112.0
|
|
182
213
|
{...rest}
|
|
183
214
|
>
|
|
184
215
|
<InputContext.Provider
|
|
185
216
|
value={{
|
|
186
217
|
handleClear: this.handleClear,
|
|
218
|
+
hasValue: !!value,
|
|
187
219
|
clearButtonLabel,
|
|
220
|
+
size,
|
|
188
221
|
}}
|
|
189
222
|
>
|
|
190
223
|
{elementBefore && <Accessory before>{elementBefore}</Accessory>}
|
|
@@ -219,14 +252,7 @@ class Input extends React.Component<TypeProps> {
|
|
|
219
252
|
/>
|
|
220
253
|
|
|
221
254
|
{elementAfter && (
|
|
222
|
-
<Accessory
|
|
223
|
-
after
|
|
224
|
-
// Used for positioning. This logic will detect if the element is a ClearButton,
|
|
225
|
-
// regardless of whether it was manually passed as elemAfter or automatically added to a search Input.
|
|
226
|
-
isClearButton={
|
|
227
|
-
elementAfter?.type?.prototype === Input.ClearButton.prototype
|
|
228
|
-
}
|
|
229
|
-
>
|
|
255
|
+
<Accessory after isClearButton={isClearButton(elementAfter)}>
|
|
230
256
|
{elementAfter}
|
|
231
257
|
</Accessory>
|
|
232
258
|
)}
|
|
@@ -156,6 +156,38 @@ searchInput.story = {
|
|
|
156
156
|
name: "Search Input",
|
|
157
157
|
};
|
|
158
158
|
|
|
159
|
+
export const smallSearchInput = () => (
|
|
160
|
+
<Input
|
|
161
|
+
type="search"
|
|
162
|
+
size="small"
|
|
163
|
+
placeholder={text("placeholder", "Please enter a value...")}
|
|
164
|
+
value={text("value", "val")}
|
|
165
|
+
onClear={() => window.alert("Cleared!")}
|
|
166
|
+
clearButtonLabel={text("clearButtonLabel", "Clear search")}
|
|
167
|
+
ariaLabel={text("ariaLabel", "Descriptive label goes here")}
|
|
168
|
+
/>
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
smallSearchInput.story = {
|
|
172
|
+
name: "Small Search Input",
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
export const largeSearchInput = () => (
|
|
176
|
+
<Input
|
|
177
|
+
type="search"
|
|
178
|
+
size="large"
|
|
179
|
+
placeholder={text("placeholder", "Please enter a value...")}
|
|
180
|
+
value={text("value", "val")}
|
|
181
|
+
onClear={() => window.alert("Cleared!")}
|
|
182
|
+
clearButtonLabel={text("clearButtonLabel", "Clear search")}
|
|
183
|
+
ariaLabel={text("ariaLabel", "Descriptive label goes here")}
|
|
184
|
+
/>
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
largeSearchInput.story = {
|
|
188
|
+
name: "Large Search Input",
|
|
189
|
+
};
|
|
190
|
+
|
|
159
191
|
export const nonSearchClearButtonInput = () => {
|
|
160
192
|
return (
|
|
161
193
|
<Input
|
|
@@ -171,7 +203,7 @@ export const nonSearchClearButtonInput = () => {
|
|
|
171
203
|
};
|
|
172
204
|
|
|
173
205
|
nonSearchClearButtonInput.story = {
|
|
174
|
-
name: "Input.ClearButton usage",
|
|
206
|
+
name: "Manual Input.ClearButton usage",
|
|
175
207
|
};
|
|
176
208
|
|
|
177
209
|
export const autofocus = () => (
|
|
@@ -85,6 +85,20 @@ describe("Input", () => {
|
|
|
85
85
|
expect(getByRole("button")).toBeTruthy();
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
+
it("should not render a clear button for search Inputs if there is no text", () => {
|
|
89
|
+
const { queryByRole } = render(
|
|
90
|
+
<Input
|
|
91
|
+
id="name"
|
|
92
|
+
name="name"
|
|
93
|
+
value=""
|
|
94
|
+
type="search"
|
|
95
|
+
onClear={jest.fn()}
|
|
96
|
+
clearButtonLabel="Clear search"
|
|
97
|
+
/>
|
|
98
|
+
);
|
|
99
|
+
expect(queryByRole("button")).toBeFalsy();
|
|
100
|
+
});
|
|
101
|
+
|
|
88
102
|
it("should not override an elemAfter prop if passed", () => {
|
|
89
103
|
const { getByText, queryByTitle } = render(
|
|
90
104
|
<Input
|
|
@@ -189,6 +203,20 @@ describe("Input", () => {
|
|
|
189
203
|
expect(getByRole("button")).toBeTruthy();
|
|
190
204
|
});
|
|
191
205
|
|
|
206
|
+
it("should not render a clear button if there is no text", () => {
|
|
207
|
+
const { queryByRole } = render(
|
|
208
|
+
<Input
|
|
209
|
+
id="name"
|
|
210
|
+
name="name"
|
|
211
|
+
value=""
|
|
212
|
+
type="text"
|
|
213
|
+
elemAfter={<Input.ClearButton />}
|
|
214
|
+
clearButtonLabel="Clear search"
|
|
215
|
+
/>
|
|
216
|
+
);
|
|
217
|
+
expect(queryByRole("button")).toBeFalsy();
|
|
218
|
+
});
|
|
219
|
+
|
|
192
220
|
it("should use the fallback title if clearButtonLabel is not provided", () => {
|
|
193
221
|
const { getByTitle } = render(
|
|
194
222
|
<Input
|
package/__flow__/Link/index.js
CHANGED
|
@@ -8,10 +8,11 @@ type TypeProps = {
|
|
|
8
8
|
/** Optional prop to make the URL open in a new tab */
|
|
9
9
|
external?: boolean,
|
|
10
10
|
children: React.Node,
|
|
11
|
+
/** Setting this prop will cause the component to be rendered as a link */
|
|
11
12
|
href?: string,
|
|
12
13
|
/** Disables user action and applies a disabled style to the component */
|
|
13
14
|
disabled?: boolean,
|
|
14
|
-
/**
|
|
15
|
+
/** Can be used in addition to an href but still renders as a link. Omitting href will render as button */
|
|
15
16
|
onClick?: (e: SyntheticEvent<HTMLButtonElement>) => void,
|
|
16
17
|
as?: $PropertyType<TypeStyledComponentsCommonProps, "as">,
|
|
17
18
|
underline?: boolean,
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
## Extended Theme Directory
|
|
2
|
+
|
|
3
|
+
This directory serves as a shared environment for all extended themes. Each unique theme should have its own folder and theme.js file.
|
|
4
|
+
`src/themes/extendedThemes/customTheme/theme.js`
|
|
5
|
+
|
|
6
|
+
Check out our documentation for [How to extend the theme](https://seeds.sproutsocial.com/components/theme#extending-the-theme) on Seeds.
|