@sproutsocial/racine 11.1.2-beta.0 → 11.3.0-beta.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/CHANGELOG.md +6 -0
- package/__flow__/Input/index.js +124 -66
- package/__flow__/Input/index.stories.js +33 -0
- package/__flow__/Input/index.test.js +224 -1
- package/__flow__/Input/styles.js +1 -1
- package/__flow__/themes/dark/theme.js +1 -0
- package/__flow__/themes/light/literal-colors.js +2 -0
- package/__flow__/themes/light/theme.js +1 -0
- package/__flow__/types/theme.colors.flow.js +27 -0
- package/commonjs/Input/index.js +68 -29
- package/commonjs/Input/styles.js +1 -1
- package/commonjs/themes/light/literal-colors.js +4 -2
- package/commonjs/types/theme.colors.flow.js +2 -0
- package/dist/themes/dark/dark.scss +4 -2
- package/dist/themes/light/light.scss +4 -2
- package/lib/Input/index.js +61 -28
- package/lib/Input/styles.js +1 -1
- package/lib/themes/light/literal-colors.js +4 -2
- package/lib/types/theme.colors.flow.js +2 -1
- package/package.json +1 -2
package/CHANGELOG.md
CHANGED
package/__flow__/Input/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import Container, { Accessory } from "./styles";
|
|
4
|
+
import Button from "../Button";
|
|
5
|
+
import Icon from "../Icon";
|
|
4
6
|
|
|
5
7
|
type TypeProps = {
|
|
6
8
|
/** ID of the form element, should match the "for" value of the associated label */
|
|
@@ -10,6 +12,8 @@ type TypeProps = {
|
|
|
10
12
|
ariaLabel?: string,
|
|
11
13
|
/** Attribute used to associate other elements that describe the Input, like an error */
|
|
12
14
|
ariaDescribedby?: string,
|
|
15
|
+
/** Label for Input.ClearButton. Required when using <Input type="search"/> or <Input.ClearButton/>. */
|
|
16
|
+
clearButtonLabel?: string,
|
|
13
17
|
/** Placeholder text for when value is undefined or empty */
|
|
14
18
|
placeholder?: string,
|
|
15
19
|
/** Current value of the input */
|
|
@@ -41,7 +45,14 @@ type TypeProps = {
|
|
|
41
45
|
/** Used to get a reference to the underlying element */
|
|
42
46
|
innerRef?: React.Ref<"input">,
|
|
43
47
|
onBlur?: (e: SyntheticFocusEvent<HTMLInputElement>) => void,
|
|
44
|
-
onChange?: (
|
|
48
|
+
onChange?: (
|
|
49
|
+
e:
|
|
50
|
+
| SyntheticInputEvent<HTMLInputElement>
|
|
51
|
+
| SyntheticEvent<HTMLButtonElement>,
|
|
52
|
+
value: string
|
|
53
|
+
) => void,
|
|
54
|
+
/** Called on Input.ClearButton trigger */
|
|
55
|
+
onClear?: (e: SyntheticEvent<HTMLButtonElement>) => void,
|
|
45
56
|
onFocus?: (e: SyntheticFocusEvent<HTMLInputElement>) => void,
|
|
46
57
|
onKeyDown?: (
|
|
47
58
|
e: SyntheticKeyboardEvent<HTMLInputElement>,
|
|
@@ -54,14 +65,34 @@ type TypeProps = {
|
|
|
54
65
|
onPaste?: (e: SyntheticInputEvent<HTMLInputElement>, value: string) => void,
|
|
55
66
|
size?: "large" | "small" | "default",
|
|
56
67
|
qa?: Object,
|
|
57
|
-
/**
|
|
58
|
-
Controls the styles of the input. Primary is our standard input styles and secondary is a borderless input.
|
|
68
|
+
/**
|
|
69
|
+
Controls the styles of the input. Primary is our standard input styles and secondary is a borderless input.
|
|
59
70
|
Note that this prop should only be used to alter styles and not functionality.
|
|
60
71
|
*/
|
|
61
72
|
appearance?: "primary" | "secondary",
|
|
62
73
|
};
|
|
63
74
|
|
|
64
|
-
|
|
75
|
+
// Using Context so that Input's Input.ClearButton-specific props can be passed to Input.ClearButton,
|
|
76
|
+
// regardless of whether it is manually included as elemAfter or automatically included for type="search" Inputs.
|
|
77
|
+
type TypeInputContext = $Shape<{
|
|
78
|
+
handleClear: (e: SyntheticEvent<HTMLButtonElement>) => void,
|
|
79
|
+
clearButtonLabel: string,
|
|
80
|
+
}>;
|
|
81
|
+
|
|
82
|
+
const InputContext = React.createContext<TypeInputContext>({});
|
|
83
|
+
|
|
84
|
+
const ClearButton = () => {
|
|
85
|
+
const { handleClear, clearButtonLabel } = React.useContext(InputContext);
|
|
86
|
+
return (
|
|
87
|
+
<Button onClick={handleClear}>
|
|
88
|
+
{/*Unlocalized fallback should not be used. Always include a localized
|
|
89
|
+
clearButtonLabel when using <Input.ClearButton/> or <Input type="search"/>.*/}
|
|
90
|
+
<Icon name="circlex" title={clearButtonLabel || "Clear"} />
|
|
91
|
+
</Button>
|
|
92
|
+
);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
class Input extends React.Component<TypeProps> {
|
|
65
96
|
static defaultProps = {
|
|
66
97
|
autoFocus: false,
|
|
67
98
|
disabled: false,
|
|
@@ -70,41 +101,33 @@ export default class Input extends React.Component<TypeProps> {
|
|
|
70
101
|
appearance: "primary",
|
|
71
102
|
};
|
|
72
103
|
|
|
73
|
-
|
|
74
|
-
if (this.props.onBlur) {
|
|
75
|
-
this.props.onBlur(e);
|
|
76
|
-
}
|
|
77
|
-
};
|
|
104
|
+
static ClearButton = ClearButton;
|
|
78
105
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
this.props.onChange(e, e.currentTarget.value);
|
|
82
|
-
}
|
|
83
|
-
};
|
|
106
|
+
handleBlur = (e: SyntheticFocusEvent<HTMLInputElement>) =>
|
|
107
|
+
this.props.onBlur?.(e);
|
|
84
108
|
|
|
85
|
-
|
|
86
|
-
if (this.props.
|
|
87
|
-
this.props.
|
|
109
|
+
handleClear = (e: SyntheticEvent<HTMLButtonElement>) => {
|
|
110
|
+
if (this.props.onClear) {
|
|
111
|
+
this.props.onClear(e);
|
|
112
|
+
} else if (this.props.onChange) {
|
|
113
|
+
this.props.onChange(e, "");
|
|
88
114
|
}
|
|
89
115
|
};
|
|
90
116
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
this.props.onKeyDown(e, e.currentTarget.value);
|
|
94
|
-
}
|
|
95
|
-
};
|
|
117
|
+
handleChange = (e: SyntheticInputEvent<HTMLInputElement>) =>
|
|
118
|
+
this.props.onChange?.(e, e.currentTarget.value);
|
|
96
119
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
this.props.onKeyUp(e, e.currentTarget.value);
|
|
100
|
-
}
|
|
101
|
-
};
|
|
120
|
+
handleFocus = (e: SyntheticFocusEvent<HTMLInputElement>) =>
|
|
121
|
+
this.props.onFocus?.(e);
|
|
102
122
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
123
|
+
handleKeyDown = (e: SyntheticKeyboardEvent<HTMLInputElement>) =>
|
|
124
|
+
this.props.onKeyDown?.(e, e.currentTarget.value);
|
|
125
|
+
|
|
126
|
+
handleKeyUp = (e: SyntheticKeyboardEvent<HTMLInputElement>) =>
|
|
127
|
+
this.props.onKeyUp?.(e, e.currentTarget.value);
|
|
128
|
+
|
|
129
|
+
handlePaste = (e: SyntheticInputEvent<HTMLInputElement>) =>
|
|
130
|
+
this.props.onPaste?.(e, e.currentTarget.value);
|
|
108
131
|
|
|
109
132
|
render() {
|
|
110
133
|
const {
|
|
@@ -125,9 +148,11 @@ export default class Input extends React.Component<TypeProps> {
|
|
|
125
148
|
maxLength,
|
|
126
149
|
ariaLabel,
|
|
127
150
|
ariaDescribedby,
|
|
151
|
+
clearButtonLabel,
|
|
128
152
|
innerRef,
|
|
129
153
|
onBlur,
|
|
130
154
|
onChange,
|
|
155
|
+
onClear,
|
|
131
156
|
onFocus,
|
|
132
157
|
onKeyDown,
|
|
133
158
|
onKeyUp,
|
|
@@ -138,15 +163,26 @@ export default class Input extends React.Component<TypeProps> {
|
|
|
138
163
|
...rest
|
|
139
164
|
} = this.props;
|
|
140
165
|
|
|
166
|
+
// Convert autoComplete from a boolean prop to a string value.
|
|
141
167
|
let autoCompleteValue = undefined;
|
|
142
168
|
if (autoComplete !== undefined) {
|
|
143
169
|
autoCompleteValue = autoComplete ? "on" : "off";
|
|
144
170
|
}
|
|
145
171
|
|
|
172
|
+
// Add default elemBefore and elemAfter elements if type is search.
|
|
173
|
+
const elementBefore =
|
|
174
|
+
type === "search" && !elemBefore ? (
|
|
175
|
+
<Icon name="search" ariaHidden />
|
|
176
|
+
) : (
|
|
177
|
+
elemBefore
|
|
178
|
+
);
|
|
179
|
+
const elementAfter =
|
|
180
|
+
type === "search" && !elemAfter ? <ClearButton /> : elemAfter;
|
|
181
|
+
|
|
146
182
|
return (
|
|
147
183
|
<Container
|
|
148
|
-
hasBeforeElement={!!
|
|
149
|
-
hasAfterElement={!!
|
|
184
|
+
hasBeforeElement={!!elementBefore}
|
|
185
|
+
hasAfterElement={!!elementAfter}
|
|
150
186
|
disabled={disabled}
|
|
151
187
|
invalid={!!isInvalid}
|
|
152
188
|
warning={hasWarning}
|
|
@@ -154,39 +190,61 @@ export default class Input extends React.Component<TypeProps> {
|
|
|
154
190
|
// $FlowIssue - upgrade v0.112.0
|
|
155
191
|
{...rest}
|
|
156
192
|
>
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
193
|
+
<InputContext.Provider
|
|
194
|
+
value={{
|
|
195
|
+
handleClear: this.handleClear,
|
|
196
|
+
clearButtonLabel,
|
|
197
|
+
}}
|
|
198
|
+
>
|
|
199
|
+
{elementBefore && <Accessory before>{elementBefore}</Accessory>}
|
|
200
|
+
|
|
201
|
+
<input
|
|
202
|
+
aria-invalid={!!isInvalid}
|
|
203
|
+
aria-label={ariaLabel}
|
|
204
|
+
aria-describedby={ariaDescribedby}
|
|
205
|
+
autoComplete={autoCompleteValue}
|
|
206
|
+
autoFocus={autoFocus}
|
|
207
|
+
disabled={disabled}
|
|
208
|
+
readOnly={readOnly}
|
|
209
|
+
id={id}
|
|
210
|
+
name={name}
|
|
211
|
+
placeholder={placeholder}
|
|
212
|
+
type={type}
|
|
213
|
+
required={required}
|
|
214
|
+
value={value}
|
|
215
|
+
maxLength={maxLength}
|
|
216
|
+
onBlur={this.handleBlur}
|
|
217
|
+
onChange={this.handleChange}
|
|
218
|
+
onFocus={this.handleFocus}
|
|
219
|
+
onKeyDown={this.handleKeyDown}
|
|
220
|
+
onKeyUp={this.handleKeyUp}
|
|
221
|
+
onPaste={this.handlePaste}
|
|
222
|
+
ref={innerRef}
|
|
223
|
+
data-qa-input={name || ""}
|
|
224
|
+
data-qa-input-isdisabled={disabled === true}
|
|
225
|
+
data-qa-input-isrequired={required === true}
|
|
226
|
+
{...qa}
|
|
227
|
+
{...inputProps}
|
|
228
|
+
/>
|
|
229
|
+
|
|
230
|
+
{elementAfter && (
|
|
231
|
+
<Accessory
|
|
232
|
+
after
|
|
233
|
+
// Used for positioning. This logic will detect if the element is a ClearButton,
|
|
234
|
+
// regardless of whether it was manually passed as elemAfter or automatically added to a search Input.
|
|
235
|
+
isClearButton={
|
|
236
|
+
elementAfter?.type?.prototype === Input.ClearButton.prototype
|
|
237
|
+
}
|
|
238
|
+
>
|
|
239
|
+
{elementAfter}
|
|
240
|
+
</Accessory>
|
|
241
|
+
)}
|
|
242
|
+
</InputContext.Provider>
|
|
189
243
|
</Container>
|
|
190
244
|
);
|
|
191
245
|
}
|
|
192
246
|
}
|
|
247
|
+
|
|
248
|
+
Input.ClearButton.displayName = "Input.ClearButton";
|
|
249
|
+
|
|
250
|
+
export default Input;
|
|
@@ -141,6 +141,39 @@ leftAndRightIcons.story = {
|
|
|
141
141
|
name: "Left and right icons",
|
|
142
142
|
};
|
|
143
143
|
|
|
144
|
+
export const searchInput = () => (
|
|
145
|
+
<Input
|
|
146
|
+
type="search"
|
|
147
|
+
placeholder={text("placeholder", "Please enter a value...")}
|
|
148
|
+
value={text("value", "val")}
|
|
149
|
+
onClear={() => window.alert("Cleared!")}
|
|
150
|
+
clearButtonLabel={text("clearButtonLabel", "Clear search")}
|
|
151
|
+
ariaLabel={text("ariaLabel", "Descriptive label goes here")}
|
|
152
|
+
/>
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
searchInput.story = {
|
|
156
|
+
name: "Search Input",
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export const nonSearchClearButtonInput = () => {
|
|
160
|
+
return (
|
|
161
|
+
<Input
|
|
162
|
+
type="text"
|
|
163
|
+
placeholder={text("placeholder", "Please enter a value...")}
|
|
164
|
+
value={text("value", "val")}
|
|
165
|
+
onClear={() => window.alert("Cleared!")}
|
|
166
|
+
ariaLabel={text("ariaLabel", "Descriptive label goes here")}
|
|
167
|
+
clearButtonLabel={text("clearButtonLabel", "Clear text")}
|
|
168
|
+
elemAfter={<Input.ClearButton />}
|
|
169
|
+
/>
|
|
170
|
+
);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
nonSearchClearButtonInput.story = {
|
|
174
|
+
name: "Input.ClearButton usage",
|
|
175
|
+
};
|
|
176
|
+
|
|
144
177
|
export const autofocus = () => (
|
|
145
178
|
<Input
|
|
146
179
|
autoFocus
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import "jest-styled-components";
|
|
3
|
-
import { render, fireEvent } from "../utils/react-testing-library";
|
|
3
|
+
import { render, fireEvent, userEvent } from "../utils/react-testing-library";
|
|
4
4
|
import Input from "./";
|
|
5
5
|
import Text from "../Text";
|
|
6
6
|
|
|
@@ -69,6 +69,229 @@ describe("Input", () => {
|
|
|
69
69
|
expect(getByText("After")).toBeTruthy();
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
+
describe("Input.ClearButton", () => {
|
|
73
|
+
describe("Input type=search", () => {
|
|
74
|
+
it("should render a clear button for search Inputs", () => {
|
|
75
|
+
const { getByTitle } = render(
|
|
76
|
+
<Input
|
|
77
|
+
id="name"
|
|
78
|
+
name="name"
|
|
79
|
+
value="mic"
|
|
80
|
+
type="search"
|
|
81
|
+
clearButtonLabel="Clear search"
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
84
|
+
expect(getByTitle("Clear search")).toBeTruthy();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should not override an elemAfter prop if passed", () => {
|
|
88
|
+
const { getByText, queryByTitle } = render(
|
|
89
|
+
<Input
|
|
90
|
+
id="name"
|
|
91
|
+
name="name"
|
|
92
|
+
value="mic"
|
|
93
|
+
type="search"
|
|
94
|
+
elemAfter={<Text>After</Text>}
|
|
95
|
+
/>
|
|
96
|
+
);
|
|
97
|
+
expect(getByText("After")).toBeTruthy();
|
|
98
|
+
expect(queryByTitle("Clear")).not.toBeInTheDocument();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("should use the fallback title if clearButtonLabel is not provided", () => {
|
|
102
|
+
const { getByTitle } = render(
|
|
103
|
+
<Input id="name" name="name" value="mic" type="search" />
|
|
104
|
+
);
|
|
105
|
+
expect(getByTitle("Clear")).toBeTruthy();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("should call onClear when clicked", () => {
|
|
109
|
+
const mockOnClear = jest.fn();
|
|
110
|
+
const { getByTitle } = render(
|
|
111
|
+
<Input
|
|
112
|
+
id="name"
|
|
113
|
+
name="name"
|
|
114
|
+
value="mic"
|
|
115
|
+
type="search"
|
|
116
|
+
onClear={mockOnClear}
|
|
117
|
+
clearButtonLabel="Clear search"
|
|
118
|
+
/>
|
|
119
|
+
);
|
|
120
|
+
fireEvent.click(getByTitle("Clear search"));
|
|
121
|
+
expect(mockOnClear).toHaveBeenCalled();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("should call onChange when clicked if there is no onClear prop", () => {
|
|
125
|
+
const mockOnChange = jest.fn();
|
|
126
|
+
const { getByTitle } = render(
|
|
127
|
+
<Input
|
|
128
|
+
id="name"
|
|
129
|
+
name="name"
|
|
130
|
+
value="mic"
|
|
131
|
+
type="search"
|
|
132
|
+
onChange={mockOnChange}
|
|
133
|
+
clearButtonLabel="Clear search"
|
|
134
|
+
/>
|
|
135
|
+
);
|
|
136
|
+
fireEvent.click(getByTitle("Clear search"));
|
|
137
|
+
expect(mockOnChange).toHaveBeenLastCalledWith(expect.anything(), "");
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("should allow keyboard access to and Space key triggering of the clear button", () => {
|
|
141
|
+
const mockOnClear = jest.fn();
|
|
142
|
+
const { getByRole } = render(
|
|
143
|
+
<Input
|
|
144
|
+
id="name"
|
|
145
|
+
name="name"
|
|
146
|
+
value="mic"
|
|
147
|
+
type="search"
|
|
148
|
+
onClear={mockOnClear}
|
|
149
|
+
clearButtonLabel="Clear search"
|
|
150
|
+
/>
|
|
151
|
+
);
|
|
152
|
+
const input = getByRole("searchbox");
|
|
153
|
+
const button = getByRole("button");
|
|
154
|
+
userEvent.tab();
|
|
155
|
+
expect(input).toHaveFocus();
|
|
156
|
+
userEvent.tab();
|
|
157
|
+
expect(button).toHaveFocus();
|
|
158
|
+
userEvent.keyboard("{space}");
|
|
159
|
+
expect(mockOnClear).toHaveBeenCalled();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("should allow keyboard access to and Enter key triggering of the clear button", () => {
|
|
163
|
+
const mockOnClear = jest.fn();
|
|
164
|
+
const { getByRole } = render(
|
|
165
|
+
<Input
|
|
166
|
+
id="name"
|
|
167
|
+
name="name"
|
|
168
|
+
value="mic"
|
|
169
|
+
type="search"
|
|
170
|
+
onClear={mockOnClear}
|
|
171
|
+
clearButtonLabel="Clear search"
|
|
172
|
+
/>
|
|
173
|
+
);
|
|
174
|
+
const input = getByRole("searchbox");
|
|
175
|
+
const button = getByRole("button");
|
|
176
|
+
userEvent.tab();
|
|
177
|
+
expect(input).toHaveFocus();
|
|
178
|
+
userEvent.tab();
|
|
179
|
+
expect(button).toHaveFocus();
|
|
180
|
+
userEvent.keyboard("{enter}");
|
|
181
|
+
expect(mockOnClear).toHaveBeenCalled();
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
describe("Manual Input.ClearButton usage", () => {
|
|
186
|
+
it("should render a clear button when passed with elemAfter", () => {
|
|
187
|
+
const { getByTitle } = render(
|
|
188
|
+
<Input
|
|
189
|
+
id="name"
|
|
190
|
+
name="name"
|
|
191
|
+
value="mic"
|
|
192
|
+
type="text"
|
|
193
|
+
elemAfter={<Input.ClearButton />}
|
|
194
|
+
clearButtonLabel="Clear search"
|
|
195
|
+
/>
|
|
196
|
+
);
|
|
197
|
+
expect(getByTitle("Clear search")).toBeTruthy();
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("should use the fallback title if clearButtonLabel is not provided", () => {
|
|
201
|
+
const { getByTitle } = render(
|
|
202
|
+
<Input
|
|
203
|
+
id="name"
|
|
204
|
+
name="name"
|
|
205
|
+
value="mic"
|
|
206
|
+
type="text"
|
|
207
|
+
elemAfter={<Input.ClearButton />}
|
|
208
|
+
/>
|
|
209
|
+
);
|
|
210
|
+
expect(getByTitle("Clear")).toBeTruthy();
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it("should call onClear when Input.ClearButton is clicked", () => {
|
|
214
|
+
const mockOnClear = jest.fn();
|
|
215
|
+
const { getByTitle } = render(
|
|
216
|
+
<Input
|
|
217
|
+
id="name"
|
|
218
|
+
name="name"
|
|
219
|
+
value="mic"
|
|
220
|
+
type="text"
|
|
221
|
+
elemAfter={<Input.ClearButton />}
|
|
222
|
+
onClear={mockOnClear}
|
|
223
|
+
clearButtonLabel="Clear search"
|
|
224
|
+
/>
|
|
225
|
+
);
|
|
226
|
+
fireEvent.click(getByTitle("Clear search"));
|
|
227
|
+
expect(mockOnClear).toHaveBeenCalled();
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it("should call onChange when clicked if there is no onClear prop", () => {
|
|
231
|
+
const mockOnChange = jest.fn();
|
|
232
|
+
const { getByTitle } = render(
|
|
233
|
+
<Input
|
|
234
|
+
id="name"
|
|
235
|
+
name="name"
|
|
236
|
+
value="mic"
|
|
237
|
+
type="text"
|
|
238
|
+
elemAfter={<Input.ClearButton />}
|
|
239
|
+
onChange={mockOnChange}
|
|
240
|
+
clearButtonLabel="Clear search"
|
|
241
|
+
/>
|
|
242
|
+
);
|
|
243
|
+
fireEvent.click(getByTitle("Clear search"));
|
|
244
|
+
expect(mockOnChange).toHaveBeenLastCalledWith(expect.anything(), "");
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it("should allow keyboard access to and Space key triggering of the clear button", () => {
|
|
248
|
+
const mockOnClear = jest.fn();
|
|
249
|
+
const { getByRole } = render(
|
|
250
|
+
<Input
|
|
251
|
+
id="name"
|
|
252
|
+
name="name"
|
|
253
|
+
value="mic"
|
|
254
|
+
type="text"
|
|
255
|
+
elemAfter={<Input.ClearButton />}
|
|
256
|
+
onClear={mockOnClear}
|
|
257
|
+
clearButtonLabel="Clear search"
|
|
258
|
+
/>
|
|
259
|
+
);
|
|
260
|
+
const input = getByRole("textbox");
|
|
261
|
+
const button = getByRole("button");
|
|
262
|
+
userEvent.tab();
|
|
263
|
+
expect(input).toHaveFocus();
|
|
264
|
+
userEvent.tab();
|
|
265
|
+
expect(button).toHaveFocus();
|
|
266
|
+
userEvent.keyboard("{space}");
|
|
267
|
+
expect(mockOnClear).toHaveBeenCalled();
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it("should allow keyboard access to and Enter key triggering of the clear button", () => {
|
|
271
|
+
const mockOnClear = jest.fn();
|
|
272
|
+
const { getByRole } = render(
|
|
273
|
+
<Input
|
|
274
|
+
id="name"
|
|
275
|
+
name="name"
|
|
276
|
+
value="mic"
|
|
277
|
+
type="text"
|
|
278
|
+
elemAfter={<Input.ClearButton />}
|
|
279
|
+
onClear={mockOnClear}
|
|
280
|
+
clearButtonLabel="Clear search"
|
|
281
|
+
/>
|
|
282
|
+
);
|
|
283
|
+
const input = getByRole("textbox");
|
|
284
|
+
const button = getByRole("button");
|
|
285
|
+
userEvent.tab();
|
|
286
|
+
expect(input).toHaveFocus();
|
|
287
|
+
userEvent.tab();
|
|
288
|
+
expect(button).toHaveFocus();
|
|
289
|
+
userEvent.keyboard("{enter}");
|
|
290
|
+
expect(mockOnClear).toHaveBeenCalled();
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
|
|
72
295
|
describe("autoComplete prop", () => {
|
|
73
296
|
it("should not have autoComplete attribute when passed prop is not passed", () => {
|
|
74
297
|
const { getByDataQaLabel } = render(<Input id="name" name="name" />);
|
package/__flow__/Input/styles.js
CHANGED
|
@@ -15,6 +15,7 @@ const literalColors = {
|
|
|
15
15
|
"800": COLORS.COLOR_NEUTRAL_800,
|
|
16
16
|
"900": COLORS.COLOR_NEUTRAL_900,
|
|
17
17
|
"1000": COLORS.COLOR_NEUTRAL_1000,
|
|
18
|
+
"1100": COLORS.COLOR_NEUTRAL_1100,
|
|
18
19
|
},
|
|
19
20
|
green: {
|
|
20
21
|
"0": COLORS.COLOR_GREEN_0,
|
|
@@ -42,6 +43,7 @@ const literalColors = {
|
|
|
42
43
|
"800": COLORS.COLOR_RED_800,
|
|
43
44
|
"900": COLORS.COLOR_RED_900,
|
|
44
45
|
"1000": COLORS.COLOR_RED_1000,
|
|
46
|
+
"1100": COLORS.COLOR_RED_1100,
|
|
45
47
|
},
|
|
46
48
|
blue: {
|
|
47
49
|
"0": COLORS.COLOR_BLUE_0,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// @flow strict-local
|
|
2
2
|
|
|
3
3
|
import literalColors from "../themes/light/literal-colors";
|
|
4
|
+
import { datavizPalette } from "../themes/light/dataviz-palette";
|
|
4
5
|
|
|
5
6
|
type TypeAppColors = {|
|
|
6
7
|
app: {
|
|
@@ -170,6 +171,7 @@ type TypeIconColors = {|
|
|
|
170
171
|
danger: string,
|
|
171
172
|
info: string,
|
|
172
173
|
opportunity: string,
|
|
174
|
+
applied: string,
|
|
173
175
|
positive_sentiment: string,
|
|
174
176
|
negative_sentiment: string,
|
|
175
177
|
neutral_sentiment: string,
|
|
@@ -204,6 +206,28 @@ type TypeListItemColors = {|
|
|
|
204
206
|
},
|
|
205
207
|
|};
|
|
206
208
|
|
|
209
|
+
type TypeOverlayColors = {|
|
|
210
|
+
overlay: {
|
|
211
|
+
background: {
|
|
212
|
+
base: string,
|
|
213
|
+
},
|
|
214
|
+
text: {
|
|
215
|
+
base: string,
|
|
216
|
+
},
|
|
217
|
+
icon: {
|
|
218
|
+
base: string,
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
|};
|
|
222
|
+
|
|
223
|
+
type TypeElevationColors = {|
|
|
224
|
+
elevation: {
|
|
225
|
+
base: string,
|
|
226
|
+
},
|
|
227
|
+
|};
|
|
228
|
+
|
|
229
|
+
type TypeDatavizColors = typeof datavizPalette;
|
|
230
|
+
|
|
207
231
|
type TypeNetworkColors = {|
|
|
208
232
|
network: {
|
|
209
233
|
twitter: string,
|
|
@@ -245,6 +269,9 @@ export type TypeColors = {
|
|
|
245
269
|
...TypeIconColors,
|
|
246
270
|
...TypeFormColors,
|
|
247
271
|
...TypeListItemColors,
|
|
272
|
+
...TypeOverlayColors,
|
|
273
|
+
...TypeElevationColors,
|
|
274
|
+
...TypeDatavizColors,
|
|
248
275
|
...TypeNetworkColors,
|
|
249
276
|
...TypeLiteralColors,
|
|
250
277
|
};
|
package/commonjs/Input/index.js
CHANGED
|
@@ -7,7 +7,13 @@ var React = _interopRequireWildcard(require("react"));
|
|
|
7
7
|
|
|
8
8
|
var _styles = _interopRequireWildcard(require("./styles"));
|
|
9
9
|
|
|
10
|
-
var
|
|
10
|
+
var _Button = _interopRequireDefault(require("../Button"));
|
|
11
|
+
|
|
12
|
+
var _Icon = _interopRequireDefault(require("../Icon"));
|
|
13
|
+
|
|
14
|
+
var _excluded = ["autoComplete", "autoFocus", "disabled", "readOnly", "isInvalid", "hasWarning", "id", "name", "placeholder", "type", "required", "value", "elemBefore", "elemAfter", "maxLength", "ariaLabel", "ariaDescribedby", "clearButtonLabel", "innerRef", "onBlur", "onChange", "onClear", "onFocus", "onKeyDown", "onKeyUp", "onPaste", "inputProps", "qa", "appearance"];
|
|
15
|
+
|
|
16
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
17
|
|
|
12
18
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
13
19
|
|
|
@@ -21,6 +27,21 @@ function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.crea
|
|
|
21
27
|
|
|
22
28
|
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
|
|
23
29
|
|
|
30
|
+
var InputContext = /*#__PURE__*/React.createContext({});
|
|
31
|
+
|
|
32
|
+
var ClearButton = function ClearButton() {
|
|
33
|
+
var _React$useContext = React.useContext(InputContext),
|
|
34
|
+
handleClear = _React$useContext.handleClear,
|
|
35
|
+
clearButtonLabel = _React$useContext.clearButtonLabel;
|
|
36
|
+
|
|
37
|
+
return /*#__PURE__*/React.createElement(_Button.default, {
|
|
38
|
+
onClick: handleClear
|
|
39
|
+
}, /*#__PURE__*/React.createElement(_Icon.default, {
|
|
40
|
+
name: "circlex",
|
|
41
|
+
title: clearButtonLabel || "Clear"
|
|
42
|
+
}));
|
|
43
|
+
};
|
|
44
|
+
|
|
24
45
|
var Input = /*#__PURE__*/function (_React$Component) {
|
|
25
46
|
_inheritsLoose(Input, _React$Component);
|
|
26
47
|
|
|
@@ -34,39 +55,35 @@ var Input = /*#__PURE__*/function (_React$Component) {
|
|
|
34
55
|
_this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
|
|
35
56
|
|
|
36
57
|
_this.handleBlur = function (e) {
|
|
37
|
-
|
|
38
|
-
|
|
58
|
+
return _this.props.onBlur == null ? void 0 : _this.props.onBlur(e);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
_this.handleClear = function (e) {
|
|
62
|
+
if (_this.props.onClear) {
|
|
63
|
+
_this.props.onClear(e);
|
|
64
|
+
} else if (_this.props.onChange) {
|
|
65
|
+
_this.props.onChange(e, "");
|
|
39
66
|
}
|
|
40
67
|
};
|
|
41
68
|
|
|
42
69
|
_this.handleChange = function (e) {
|
|
43
|
-
|
|
44
|
-
_this.props.onChange(e, e.currentTarget.value);
|
|
45
|
-
}
|
|
70
|
+
return _this.props.onChange == null ? void 0 : _this.props.onChange(e, e.currentTarget.value);
|
|
46
71
|
};
|
|
47
72
|
|
|
48
73
|
_this.handleFocus = function (e) {
|
|
49
|
-
|
|
50
|
-
_this.props.onFocus(e);
|
|
51
|
-
}
|
|
74
|
+
return _this.props.onFocus == null ? void 0 : _this.props.onFocus(e);
|
|
52
75
|
};
|
|
53
76
|
|
|
54
77
|
_this.handleKeyDown = function (e) {
|
|
55
|
-
|
|
56
|
-
_this.props.onKeyDown(e, e.currentTarget.value);
|
|
57
|
-
}
|
|
78
|
+
return _this.props.onKeyDown == null ? void 0 : _this.props.onKeyDown(e, e.currentTarget.value);
|
|
58
79
|
};
|
|
59
80
|
|
|
60
81
|
_this.handleKeyUp = function (e) {
|
|
61
|
-
|
|
62
|
-
_this.props.onKeyUp(e, e.currentTarget.value);
|
|
63
|
-
}
|
|
82
|
+
return _this.props.onKeyUp == null ? void 0 : _this.props.onKeyUp(e, e.currentTarget.value);
|
|
64
83
|
};
|
|
65
84
|
|
|
66
85
|
_this.handlePaste = function (e) {
|
|
67
|
-
|
|
68
|
-
_this.props.onPaste(e, e.currentTarget.value);
|
|
69
|
-
}
|
|
86
|
+
return _this.props.onPaste == null ? void 0 : _this.props.onPaste(e, e.currentTarget.value);
|
|
70
87
|
};
|
|
71
88
|
|
|
72
89
|
return _this;
|
|
@@ -75,6 +92,8 @@ var Input = /*#__PURE__*/function (_React$Component) {
|
|
|
75
92
|
var _proto = Input.prototype;
|
|
76
93
|
|
|
77
94
|
_proto.render = function render() {
|
|
95
|
+
var _elementAfter$type;
|
|
96
|
+
|
|
78
97
|
var _this$props = this.props,
|
|
79
98
|
autoComplete = _this$props.autoComplete,
|
|
80
99
|
autoFocus = _this$props.autoFocus,
|
|
@@ -93,9 +112,11 @@ var Input = /*#__PURE__*/function (_React$Component) {
|
|
|
93
112
|
maxLength = _this$props.maxLength,
|
|
94
113
|
ariaLabel = _this$props.ariaLabel,
|
|
95
114
|
ariaDescribedby = _this$props.ariaDescribedby,
|
|
115
|
+
clearButtonLabel = _this$props.clearButtonLabel,
|
|
96
116
|
innerRef = _this$props.innerRef,
|
|
97
117
|
onBlur = _this$props.onBlur,
|
|
98
118
|
onChange = _this$props.onChange,
|
|
119
|
+
onClear = _this$props.onClear,
|
|
99
120
|
onFocus = _this$props.onFocus,
|
|
100
121
|
onKeyDown = _this$props.onKeyDown,
|
|
101
122
|
onKeyUp = _this$props.onKeyUp,
|
|
@@ -105,25 +126,37 @@ var Input = /*#__PURE__*/function (_React$Component) {
|
|
|
105
126
|
_this$props$qa = _this$props.qa,
|
|
106
127
|
qa = _this$props$qa === void 0 ? {} : _this$props$qa,
|
|
107
128
|
appearance = _this$props.appearance,
|
|
108
|
-
rest = _objectWithoutPropertiesLoose(_this$props, _excluded);
|
|
129
|
+
rest = _objectWithoutPropertiesLoose(_this$props, _excluded); // Convert autoComplete from a boolean prop to a string value.
|
|
130
|
+
|
|
109
131
|
|
|
110
132
|
var autoCompleteValue = undefined;
|
|
111
133
|
|
|
112
134
|
if (autoComplete !== undefined) {
|
|
113
135
|
autoCompleteValue = autoComplete ? "on" : "off";
|
|
114
|
-
}
|
|
136
|
+
} // Add default elemBefore and elemAfter elements if type is search.
|
|
115
137
|
|
|
138
|
+
|
|
139
|
+
var elementBefore = type === "search" && !elemBefore ? /*#__PURE__*/React.createElement(_Icon.default, {
|
|
140
|
+
name: "search",
|
|
141
|
+
ariaHidden: true
|
|
142
|
+
}) : elemBefore;
|
|
143
|
+
var elementAfter = type === "search" && !elemAfter ? /*#__PURE__*/React.createElement(ClearButton, null) : elemAfter;
|
|
116
144
|
return /*#__PURE__*/React.createElement(_styles.default, _extends({
|
|
117
|
-
hasBeforeElement: !!
|
|
118
|
-
hasAfterElement: !!
|
|
145
|
+
hasBeforeElement: !!elementBefore,
|
|
146
|
+
hasAfterElement: !!elementAfter,
|
|
119
147
|
disabled: disabled,
|
|
120
148
|
invalid: !!isInvalid,
|
|
121
149
|
warning: hasWarning,
|
|
122
150
|
appearance: appearance // $FlowIssue - upgrade v0.112.0
|
|
123
151
|
|
|
124
|
-
}, rest),
|
|
152
|
+
}, rest), /*#__PURE__*/React.createElement(InputContext.Provider, {
|
|
153
|
+
value: {
|
|
154
|
+
handleClear: this.handleClear,
|
|
155
|
+
clearButtonLabel: clearButtonLabel
|
|
156
|
+
}
|
|
157
|
+
}, elementBefore && /*#__PURE__*/React.createElement(_styles.Accessory, {
|
|
125
158
|
before: true
|
|
126
|
-
},
|
|
159
|
+
}, elementBefore), /*#__PURE__*/React.createElement("input", _extends({
|
|
127
160
|
"aria-invalid": !!isInvalid,
|
|
128
161
|
"aria-label": ariaLabel,
|
|
129
162
|
"aria-describedby": ariaDescribedby,
|
|
@@ -148,19 +181,25 @@ var Input = /*#__PURE__*/function (_React$Component) {
|
|
|
148
181
|
"data-qa-input": name || "",
|
|
149
182
|
"data-qa-input-isdisabled": disabled === true,
|
|
150
183
|
"data-qa-input-isrequired": required === true
|
|
151
|
-
}, qa, inputProps)),
|
|
152
|
-
after: true
|
|
153
|
-
|
|
184
|
+
}, qa, inputProps)), elementAfter && /*#__PURE__*/React.createElement(_styles.Accessory, {
|
|
185
|
+
after: true // Used for positioning. This logic will detect if the element is a ClearButton,
|
|
186
|
+
// regardless of whether it was manually passed as elemAfter or automatically added to a search Input.
|
|
187
|
+
,
|
|
188
|
+
isClearButton: (elementAfter == null ? void 0 : (_elementAfter$type = elementAfter.type) == null ? void 0 : _elementAfter$type.prototype) === Input.ClearButton.prototype
|
|
189
|
+
}, elementAfter)));
|
|
154
190
|
};
|
|
155
191
|
|
|
156
192
|
return Input;
|
|
157
193
|
}(React.Component);
|
|
158
194
|
|
|
159
|
-
exports.default = Input;
|
|
160
195
|
Input.defaultProps = {
|
|
161
196
|
autoFocus: false,
|
|
162
197
|
disabled: false,
|
|
163
198
|
type: "text",
|
|
164
199
|
size: "default",
|
|
165
200
|
appearance: "primary"
|
|
166
|
-
};
|
|
201
|
+
};
|
|
202
|
+
Input.ClearButton = ClearButton;
|
|
203
|
+
Input.ClearButton.displayName = "Input.ClearButton";
|
|
204
|
+
var _default = Input;
|
|
205
|
+
exports.default = _default;
|
package/commonjs/Input/styles.js
CHANGED
|
@@ -86,7 +86,7 @@ var Accessory = _styledComponents.default.div.withConfig({
|
|
|
86
86
|
}, function (props) {
|
|
87
87
|
return props.before && (0, _styledComponents.css)(["left:", ";"], props.theme.space[350]);
|
|
88
88
|
}, function (props) {
|
|
89
|
-
return props.after && (0, _styledComponents.css)(["right:", ";"], props.theme.space[350]);
|
|
89
|
+
return props.after && (0, _styledComponents.css)(["right:", ";"], props.isClearButton ? 0 : props.theme.space[350]);
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
exports.Accessory = Accessory;
|
|
@@ -19,7 +19,8 @@ var literalColors = {
|
|
|
19
19
|
"700": _seedsColor.default.COLOR_NEUTRAL_700,
|
|
20
20
|
"800": _seedsColor.default.COLOR_NEUTRAL_800,
|
|
21
21
|
"900": _seedsColor.default.COLOR_NEUTRAL_900,
|
|
22
|
-
"1000": _seedsColor.default.COLOR_NEUTRAL_1000
|
|
22
|
+
"1000": _seedsColor.default.COLOR_NEUTRAL_1000,
|
|
23
|
+
"1100": _seedsColor.default.COLOR_NEUTRAL_1100
|
|
23
24
|
},
|
|
24
25
|
green: {
|
|
25
26
|
"0": _seedsColor.default.COLOR_GREEN_0,
|
|
@@ -46,7 +47,8 @@ var literalColors = {
|
|
|
46
47
|
"700": _seedsColor.default.COLOR_RED_700,
|
|
47
48
|
"800": _seedsColor.default.COLOR_RED_800,
|
|
48
49
|
"900": _seedsColor.default.COLOR_RED_900,
|
|
49
|
-
"1000": _seedsColor.default.COLOR_RED_1000
|
|
50
|
+
"1000": _seedsColor.default.COLOR_RED_1000,
|
|
51
|
+
"1100": _seedsColor.default.COLOR_RED_1100
|
|
50
52
|
},
|
|
51
53
|
blue: {
|
|
52
54
|
"0": _seedsColor.default.COLOR_BLUE_0,
|
|
@@ -262,7 +262,8 @@ $dark: (
|
|
|
262
262
|
700: #515e5f,
|
|
263
263
|
800: #364141,
|
|
264
264
|
900: #273333,
|
|
265
|
-
1000: #162020
|
|
265
|
+
1000: #162020,
|
|
266
|
+
1100: #040404
|
|
266
267
|
),
|
|
267
268
|
green: (
|
|
268
269
|
0: #ebf9eb,
|
|
@@ -289,7 +290,8 @@ $dark: (
|
|
|
289
290
|
700: #db3e3e,
|
|
290
291
|
800: #c63434,
|
|
291
292
|
900: #992222,
|
|
292
|
-
1000: #6d1313
|
|
293
|
+
1000: #6d1313,
|
|
294
|
+
1100: #2b1111
|
|
293
295
|
),
|
|
294
296
|
blue: (
|
|
295
297
|
0: #e9f8ff,
|
|
@@ -269,7 +269,8 @@ $light: (
|
|
|
269
269
|
700: #515e5f,
|
|
270
270
|
800: #364141,
|
|
271
271
|
900: #273333,
|
|
272
|
-
1000: #162020
|
|
272
|
+
1000: #162020,
|
|
273
|
+
1100: #040404
|
|
273
274
|
),
|
|
274
275
|
green: (
|
|
275
276
|
0: #ebf9eb,
|
|
@@ -296,7 +297,8 @@ $light: (
|
|
|
296
297
|
700: #db3e3e,
|
|
297
298
|
800: #c63434,
|
|
298
299
|
900: #992222,
|
|
299
|
-
1000: #6d1313
|
|
300
|
+
1000: #6d1313,
|
|
301
|
+
1100: #2b1111
|
|
300
302
|
),
|
|
301
303
|
blue: (
|
|
302
304
|
0: #e9f8ff,
|
package/lib/Input/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var _excluded = ["autoComplete", "autoFocus", "disabled", "readOnly", "isInvalid", "hasWarning", "id", "name", "placeholder", "type", "required", "value", "elemBefore", "elemAfter", "maxLength", "ariaLabel", "ariaDescribedby", "innerRef", "onBlur", "onChange", "onFocus", "onKeyDown", "onKeyUp", "onPaste", "inputProps", "qa", "appearance"];
|
|
1
|
+
var _excluded = ["autoComplete", "autoFocus", "disabled", "readOnly", "isInvalid", "hasWarning", "id", "name", "placeholder", "type", "required", "value", "elemBefore", "elemAfter", "maxLength", "ariaLabel", "ariaDescribedby", "clearButtonLabel", "innerRef", "onBlur", "onChange", "onClear", "onFocus", "onKeyDown", "onKeyUp", "onPaste", "inputProps", "qa", "appearance"];
|
|
2
2
|
|
|
3
3
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
4
4
|
|
|
@@ -10,6 +10,22 @@ function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || func
|
|
|
10
10
|
|
|
11
11
|
import * as React from "react";
|
|
12
12
|
import Container, { Accessory } from "./styles";
|
|
13
|
+
import Button from "../Button";
|
|
14
|
+
import Icon from "../Icon";
|
|
15
|
+
var InputContext = /*#__PURE__*/React.createContext({});
|
|
16
|
+
|
|
17
|
+
var ClearButton = function ClearButton() {
|
|
18
|
+
var _React$useContext = React.useContext(InputContext),
|
|
19
|
+
handleClear = _React$useContext.handleClear,
|
|
20
|
+
clearButtonLabel = _React$useContext.clearButtonLabel;
|
|
21
|
+
|
|
22
|
+
return /*#__PURE__*/React.createElement(Button, {
|
|
23
|
+
onClick: handleClear
|
|
24
|
+
}, /*#__PURE__*/React.createElement(Icon, {
|
|
25
|
+
name: "circlex",
|
|
26
|
+
title: clearButtonLabel || "Clear"
|
|
27
|
+
}));
|
|
28
|
+
};
|
|
13
29
|
|
|
14
30
|
var Input = /*#__PURE__*/function (_React$Component) {
|
|
15
31
|
_inheritsLoose(Input, _React$Component);
|
|
@@ -24,39 +40,35 @@ var Input = /*#__PURE__*/function (_React$Component) {
|
|
|
24
40
|
_this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
|
|
25
41
|
|
|
26
42
|
_this.handleBlur = function (e) {
|
|
27
|
-
|
|
28
|
-
|
|
43
|
+
return _this.props.onBlur == null ? void 0 : _this.props.onBlur(e);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
_this.handleClear = function (e) {
|
|
47
|
+
if (_this.props.onClear) {
|
|
48
|
+
_this.props.onClear(e);
|
|
49
|
+
} else if (_this.props.onChange) {
|
|
50
|
+
_this.props.onChange(e, "");
|
|
29
51
|
}
|
|
30
52
|
};
|
|
31
53
|
|
|
32
54
|
_this.handleChange = function (e) {
|
|
33
|
-
|
|
34
|
-
_this.props.onChange(e, e.currentTarget.value);
|
|
35
|
-
}
|
|
55
|
+
return _this.props.onChange == null ? void 0 : _this.props.onChange(e, e.currentTarget.value);
|
|
36
56
|
};
|
|
37
57
|
|
|
38
58
|
_this.handleFocus = function (e) {
|
|
39
|
-
|
|
40
|
-
_this.props.onFocus(e);
|
|
41
|
-
}
|
|
59
|
+
return _this.props.onFocus == null ? void 0 : _this.props.onFocus(e);
|
|
42
60
|
};
|
|
43
61
|
|
|
44
62
|
_this.handleKeyDown = function (e) {
|
|
45
|
-
|
|
46
|
-
_this.props.onKeyDown(e, e.currentTarget.value);
|
|
47
|
-
}
|
|
63
|
+
return _this.props.onKeyDown == null ? void 0 : _this.props.onKeyDown(e, e.currentTarget.value);
|
|
48
64
|
};
|
|
49
65
|
|
|
50
66
|
_this.handleKeyUp = function (e) {
|
|
51
|
-
|
|
52
|
-
_this.props.onKeyUp(e, e.currentTarget.value);
|
|
53
|
-
}
|
|
67
|
+
return _this.props.onKeyUp == null ? void 0 : _this.props.onKeyUp(e, e.currentTarget.value);
|
|
54
68
|
};
|
|
55
69
|
|
|
56
70
|
_this.handlePaste = function (e) {
|
|
57
|
-
|
|
58
|
-
_this.props.onPaste(e, e.currentTarget.value);
|
|
59
|
-
}
|
|
71
|
+
return _this.props.onPaste == null ? void 0 : _this.props.onPaste(e, e.currentTarget.value);
|
|
60
72
|
};
|
|
61
73
|
|
|
62
74
|
return _this;
|
|
@@ -65,6 +77,8 @@ var Input = /*#__PURE__*/function (_React$Component) {
|
|
|
65
77
|
var _proto = Input.prototype;
|
|
66
78
|
|
|
67
79
|
_proto.render = function render() {
|
|
80
|
+
var _elementAfter$type;
|
|
81
|
+
|
|
68
82
|
var _this$props = this.props,
|
|
69
83
|
autoComplete = _this$props.autoComplete,
|
|
70
84
|
autoFocus = _this$props.autoFocus,
|
|
@@ -83,9 +97,11 @@ var Input = /*#__PURE__*/function (_React$Component) {
|
|
|
83
97
|
maxLength = _this$props.maxLength,
|
|
84
98
|
ariaLabel = _this$props.ariaLabel,
|
|
85
99
|
ariaDescribedby = _this$props.ariaDescribedby,
|
|
100
|
+
clearButtonLabel = _this$props.clearButtonLabel,
|
|
86
101
|
innerRef = _this$props.innerRef,
|
|
87
102
|
onBlur = _this$props.onBlur,
|
|
88
103
|
onChange = _this$props.onChange,
|
|
104
|
+
onClear = _this$props.onClear,
|
|
89
105
|
onFocus = _this$props.onFocus,
|
|
90
106
|
onKeyDown = _this$props.onKeyDown,
|
|
91
107
|
onKeyUp = _this$props.onKeyUp,
|
|
@@ -95,25 +111,37 @@ var Input = /*#__PURE__*/function (_React$Component) {
|
|
|
95
111
|
_this$props$qa = _this$props.qa,
|
|
96
112
|
qa = _this$props$qa === void 0 ? {} : _this$props$qa,
|
|
97
113
|
appearance = _this$props.appearance,
|
|
98
|
-
rest = _objectWithoutPropertiesLoose(_this$props, _excluded);
|
|
114
|
+
rest = _objectWithoutPropertiesLoose(_this$props, _excluded); // Convert autoComplete from a boolean prop to a string value.
|
|
115
|
+
|
|
99
116
|
|
|
100
117
|
var autoCompleteValue = undefined;
|
|
101
118
|
|
|
102
119
|
if (autoComplete !== undefined) {
|
|
103
120
|
autoCompleteValue = autoComplete ? "on" : "off";
|
|
104
|
-
}
|
|
121
|
+
} // Add default elemBefore and elemAfter elements if type is search.
|
|
122
|
+
|
|
105
123
|
|
|
124
|
+
var elementBefore = type === "search" && !elemBefore ? /*#__PURE__*/React.createElement(Icon, {
|
|
125
|
+
name: "search",
|
|
126
|
+
ariaHidden: true
|
|
127
|
+
}) : elemBefore;
|
|
128
|
+
var elementAfter = type === "search" && !elemAfter ? /*#__PURE__*/React.createElement(ClearButton, null) : elemAfter;
|
|
106
129
|
return /*#__PURE__*/React.createElement(Container, _extends({
|
|
107
|
-
hasBeforeElement: !!
|
|
108
|
-
hasAfterElement: !!
|
|
130
|
+
hasBeforeElement: !!elementBefore,
|
|
131
|
+
hasAfterElement: !!elementAfter,
|
|
109
132
|
disabled: disabled,
|
|
110
133
|
invalid: !!isInvalid,
|
|
111
134
|
warning: hasWarning,
|
|
112
135
|
appearance: appearance // $FlowIssue - upgrade v0.112.0
|
|
113
136
|
|
|
114
|
-
}, rest),
|
|
137
|
+
}, rest), /*#__PURE__*/React.createElement(InputContext.Provider, {
|
|
138
|
+
value: {
|
|
139
|
+
handleClear: this.handleClear,
|
|
140
|
+
clearButtonLabel: clearButtonLabel
|
|
141
|
+
}
|
|
142
|
+
}, elementBefore && /*#__PURE__*/React.createElement(Accessory, {
|
|
115
143
|
before: true
|
|
116
|
-
},
|
|
144
|
+
}, elementBefore), /*#__PURE__*/React.createElement("input", _extends({
|
|
117
145
|
"aria-invalid": !!isInvalid,
|
|
118
146
|
"aria-label": ariaLabel,
|
|
119
147
|
"aria-describedby": ariaDescribedby,
|
|
@@ -138,9 +166,12 @@ var Input = /*#__PURE__*/function (_React$Component) {
|
|
|
138
166
|
"data-qa-input": name || "",
|
|
139
167
|
"data-qa-input-isdisabled": disabled === true,
|
|
140
168
|
"data-qa-input-isrequired": required === true
|
|
141
|
-
}, qa, inputProps)),
|
|
142
|
-
after: true
|
|
143
|
-
|
|
169
|
+
}, qa, inputProps)), elementAfter && /*#__PURE__*/React.createElement(Accessory, {
|
|
170
|
+
after: true // Used for positioning. This logic will detect if the element is a ClearButton,
|
|
171
|
+
// regardless of whether it was manually passed as elemAfter or automatically added to a search Input.
|
|
172
|
+
,
|
|
173
|
+
isClearButton: (elementAfter == null ? void 0 : (_elementAfter$type = elementAfter.type) == null ? void 0 : _elementAfter$type.prototype) === Input.ClearButton.prototype
|
|
174
|
+
}, elementAfter)));
|
|
144
175
|
};
|
|
145
176
|
|
|
146
177
|
return Input;
|
|
@@ -153,4 +184,6 @@ Input.defaultProps = {
|
|
|
153
184
|
size: "default",
|
|
154
185
|
appearance: "primary"
|
|
155
186
|
};
|
|
156
|
-
|
|
187
|
+
Input.ClearButton = ClearButton;
|
|
188
|
+
Input.ClearButton.displayName = "Input.ClearButton";
|
|
189
|
+
export default Input;
|
package/lib/Input/styles.js
CHANGED
|
@@ -73,7 +73,7 @@ export var Accessory = styled.div.withConfig({
|
|
|
73
73
|
}, function (props) {
|
|
74
74
|
return props.before && css(["left:", ";"], props.theme.space[350]);
|
|
75
75
|
}, function (props) {
|
|
76
|
-
return props.after && css(["right:", ";"], props.theme.space[350]);
|
|
76
|
+
return props.after && css(["right:", ";"], props.isClearButton ? 0 : props.theme.space[350]);
|
|
77
77
|
});
|
|
78
78
|
Container.displayName = "InputContainer";
|
|
79
79
|
Accessory.displayName = "InputAccessory";
|
|
@@ -11,7 +11,8 @@ var literalColors = {
|
|
|
11
11
|
"700": COLORS.COLOR_NEUTRAL_700,
|
|
12
12
|
"800": COLORS.COLOR_NEUTRAL_800,
|
|
13
13
|
"900": COLORS.COLOR_NEUTRAL_900,
|
|
14
|
-
"1000": COLORS.COLOR_NEUTRAL_1000
|
|
14
|
+
"1000": COLORS.COLOR_NEUTRAL_1000,
|
|
15
|
+
"1100": COLORS.COLOR_NEUTRAL_1100
|
|
15
16
|
},
|
|
16
17
|
green: {
|
|
17
18
|
"0": COLORS.COLOR_GREEN_0,
|
|
@@ -38,7 +39,8 @@ var literalColors = {
|
|
|
38
39
|
"700": COLORS.COLOR_RED_700,
|
|
39
40
|
"800": COLORS.COLOR_RED_800,
|
|
40
41
|
"900": COLORS.COLOR_RED_900,
|
|
41
|
-
"1000": COLORS.COLOR_RED_1000
|
|
42
|
+
"1000": COLORS.COLOR_RED_1000,
|
|
43
|
+
"1100": COLORS.COLOR_RED_1100
|
|
42
44
|
},
|
|
43
45
|
blue: {
|
|
44
46
|
"0": COLORS.COLOR_BLUE_0,
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
import literalColors from "../themes/light/literal-colors";
|
|
1
|
+
import literalColors from "../themes/light/literal-colors";
|
|
2
|
+
import { datavizPalette } from "../themes/light/dataviz-palette";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sproutsocial/racine",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.3.0-beta.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"__flow__",
|
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
"./includeIcons.js"
|
|
24
24
|
],
|
|
25
25
|
"scripts": {
|
|
26
|
-
"preinstall": "node ./bin/buildNpm.js",
|
|
27
26
|
"install-deps": "yarn install",
|
|
28
27
|
"prepublishOnly": "yarn run build",
|
|
29
28
|
"precommit": "lint-staged",
|