Skip to content

Commit 40ed423

Browse files
mperrottipksjcecolebemis
authored
Text input loading state (#1920)
* adds loading indicator to text inputs * removes style debugging div * updates stories and docs * updates tests * fixes silly test mistakes * revert default textinput story * adds changeset * Update src/TextInput.tsx Co-authored-by: Pavithra Kodmad <[email protected]> * updates component API * addresses PR feedback * fixes linting error * indicate a busy status to assistive technology * updates snaps * renames 'isLoading' prop to 'loading' * Update docs/content/TextInput.mdx Co-authored-by: Cole Bemis <[email protected]> * Update docs/content/TextInput.mdx Co-authored-by: Cole Bemis <[email protected]> * Update docs/content/TextInput.mdx Co-authored-by: Cole Bemis <[email protected]> * Update docs/content/TextInput.mdx Co-authored-by: Cole Bemis <[email protected]> * Update docs/content/TextInput.mdx Co-authored-by: Cole Bemis <[email protected]> * updates snapshots * nests examples under an 'Examples' heading * export TextInput non-pass-through props * fix undefined type usage * fixes story types Co-authored-by: Pavithra Kodmad <[email protected]> Co-authored-by: Cole Bemis <[email protected]>
1 parent da44635 commit 40ed423

13 files changed

+12982
-50
lines changed

.changeset/smooth-lemons-brake.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@primer/react': minor
3+
---
4+
5+
Adds a loadings state to our text input components

docs/content/TextInput.mdx

Lines changed: 88 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ TextInput is a form component to add default styling to the native text input.
99

1010
**Note:** Don't forget to set `aria-label` to make the TextInput accessible to screen reader users.
1111

12-
## Default example
12+
## Examples
13+
14+
### Basic
1315

1416
```jsx live
1517
<TextInput aria-label="Zipcode" name="zipcode" placeholder="Zipcode" autoComplete="postal-code" />
1618
```
1719

18-
## Text Input with icons
20+
### With icons
1921

2022
```jsx live
2123
<>
@@ -37,7 +39,7 @@ TextInput is a form component to add default styling to the native text input.
3739
</>
3840
```
3941

40-
## Text Input with text visuals
42+
### With text visuals
4143

4244
```jsx live
4345
<>
@@ -47,7 +49,66 @@ TextInput is a form component to add default styling to the native text input.
4749
</>
4850
```
4951

50-
## Text Input with error and warning states
52+
### With visuals and loading indicators
53+
54+
```javascript live noinline
55+
const WithIconAndLoadingIndicator = () => {
56+
const [loading, setLoading] = React.useState(true)
57+
58+
const toggleLoadingState = () => {
59+
setLoading(!loading)
60+
}
61+
62+
return (
63+
<>
64+
<Box mb={6}>
65+
<button type="button" onClick={toggleLoadingState}>
66+
Toggle loading state {loading ? 'off' : 'on'}
67+
</button>
68+
</Box>
69+
70+
<Text fontSize={3} mb={1} display="block">
71+
No visual
72+
</Text>
73+
<Box mb={3}>
74+
<TextInput loading={loading} />
75+
</Box>
76+
77+
<Text fontSize={3} mb={1} display="block">
78+
Leading visual
79+
</Text>
80+
<Box mb={3}>
81+
<TextInput leadingVisual={SearchIcon} loading={loading} />
82+
</Box>
83+
84+
<Text fontSize={3} mb={1} display="block">
85+
Trailing visual
86+
</Text>
87+
<Box mb={3}>
88+
<TextInput trailingVisual={SearchIcon} loading={loading} />
89+
</Box>
90+
91+
<Text fontSize={3} mb={1} display="block">
92+
Both visuals
93+
</Text>
94+
<Box mb={3}>
95+
<TextInput leadingVisual={SearchIcon} trailingVisual={SearchIcon} loading={loading} />
96+
</Box>
97+
98+
<Text fontSize={3} mb={2} display="block">
99+
Both visuals, position overriden
100+
</Text>
101+
<Box mb={3}>
102+
<TextInput loaderPosition="trailing" leadingVisual={SearchIcon} trailingVisual={SearchIcon} loading={loading} />
103+
</Box>
104+
</>
105+
)
106+
}
107+
108+
render(<WithIconAndLoadingIndicator />)
109+
```
110+
111+
### With error and warning states
51112

52113
```jsx live
53114
<>
@@ -69,19 +130,19 @@ TextInput is a form component to add default styling to the native text input.
69130
</>
70131
```
71132

72-
## Block text input
133+
### Block text input
73134

74135
```jsx live
75136
<TextInput block aria-label="Zipcode" name="zipcode" placeholder="560076" autoComplete="postal-code" />
76137
```
77138

78-
## Contrast text input
139+
### Contrast text input
79140

80141
```jsx live
81142
<TextInput contrast aria-label="Zipcode" name="zipcode" placeholder="Find user" autoComplete="postal-code" />
82143
```
83144

84-
## Monospace text input
145+
### Monospace text input
85146

86147
```jsx live
87148
<TextInput
@@ -103,31 +164,40 @@ TextInput is a form component to add default styling to the native text input.
103164
name="block"
104165
type="boolean"
105166
defaultValue="false"
106-
description={
107-
<>
108-
Creates a full width input element
109-
</>
110-
}
167+
description="Creates a full-width input element"
111168
/>
112169
<PropsTableRow
113170
name="contrast"
114171
type="boolean"
115172
defaultValue="false"
116173
description="Changes background color to a higher contrast color"
117174
/>
118-
<PropsTableRow
119-
name="monospace"
120-
type="boolean"
121-
defaultValue="false"
122-
description="Shows input in monospace font"
123-
/>
124175
<PropsTableRow name='size' type="'small' | 'medium' | 'large'" description="Creates a smaller or larger input than the default." />
125176

177+
<PropsTableRow name="loading" type="boolean" description="Whether to show a loading indicator in the input" />
178+
<PropsTableRow
179+
name="loaderPosition"
180+
type="'auto' | 'leading' | 'trailing'"
181+
description={
182+
<>
183+
<div>Which position to render the loading indicator</div>
184+
<ul>
185+
<li>
186+
'auto' (default): at the end of the input, unless a `leadingVisual` is passed. Then, it will render at the
187+
beginning
188+
</li>
189+
<li>'leading': at the beginning of the input</li>
190+
<li>'trailing': at the end of the input</li>
191+
</ul>
192+
</>
193+
}
194+
/>
126195
<PropsTableRow
127196
name="leadingVisual"
128197
type={<>string | React.ComponentType</>}
129198
description="Visual positioned on the left edge inside the input"
130199
/>
200+
<PropsTableRow name="monospace" type="boolean" defaultValue="false" description="Shows input in monospace font" />
131201
<PropsTableRow
132202
name="trailingVisual"
133203
type={<>string | React.ComponentType</>}
@@ -138,7 +208,6 @@ TextInput is a form component to add default styling to the native text input.
138208
type="'error' | 'success' | 'warning'"
139209
description="Style the input to match the status"
140210
/>
141-
142211
<PropsTableRow
143212
name="variant"
144213
type="'small' | 'medium' | 'large'"

docs/content/TextInputWithTokens.mdx

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,159 @@ const LeadingVisualExample = () => {
237237
render(LeadingVisualExample)
238238
```
239239

240+
## With visuals and loading indicators
241+
242+
```javascript live noinline
243+
const WithIconAndLoadingIndicator = () => {
244+
const [dates, setDates] = React.useState([
245+
{text: '01 Jan', id: 0},
246+
{text: '01 Feb', id: 1},
247+
{text: '01 Mar', id: 2}
248+
])
249+
const onDateRemove = tokenId => {
250+
setDates(dates.filter(token => token.id !== tokenId))
251+
}
252+
253+
const [loading, setLoading] = React.useState(true)
254+
const toggleLoadingState = () => {
255+
setLoading(!loading)
256+
}
257+
258+
return (
259+
<>
260+
<Box mb={5} display="flex" justifyContent="flex-end">
261+
<button type="button" onClick={toggleLoadingState}>
262+
Toggle loading state {loading ? 'off' : 'on'}
263+
</button>
264+
</Box>
265+
266+
<h3>No visual</h3>
267+
<Box mb={2}>
268+
<TextInputWithTokens tokens={dates} onTokenRemove={onDateRemove} value="auto" loading={loading} />
269+
</Box>
270+
<Box mb={2}>
271+
<TextInputWithTokens
272+
tokens={dates}
273+
onTokenRemove={onDateRemove}
274+
value="leading"
275+
loading={loading}
276+
loaderPosition="leading"
277+
/>
278+
</Box>
279+
<Box mb={5}>
280+
<TextInputWithTokens
281+
tokens={dates}
282+
onTokenRemove={onDateRemove}
283+
value="trailing"
284+
loading={loading}
285+
loaderPosition="trailing"
286+
/>
287+
</Box>
288+
289+
<h3>Leading visual</h3>
290+
<Box mb={2}>
291+
<TextInputWithTokens
292+
tokens={dates}
293+
onTokenRemove={onDateRemove}
294+
leadingVisual={CalendarIcon}
295+
loading={loading}
296+
value="auto"
297+
/>
298+
</Box>
299+
<Box mb={2}>
300+
<TextInputWithTokens
301+
tokens={dates}
302+
onTokenRemove={onDateRemove}
303+
leadingVisual={CalendarIcon}
304+
loading={loading}
305+
loaderPosition="leading"
306+
value="leading"
307+
/>
308+
</Box>
309+
<Box mb={5}>
310+
<TextInputWithTokens
311+
tokens={dates}
312+
onTokenRemove={onDateRemove}
313+
leadingVisual={CalendarIcon}
314+
loading={loading}
315+
loaderPosition="trailing"
316+
value="trailing"
317+
/>
318+
</Box>
319+
320+
<h3>Trailing visual</h3>
321+
<Box mb={2}>
322+
<TextInputWithTokens
323+
tokens={dates}
324+
onTokenRemove={onDateRemove}
325+
trailingVisual={CalendarIcon}
326+
loading={loading}
327+
value="auto"
328+
/>
329+
</Box>
330+
<Box mb={2}>
331+
<TextInputWithTokens
332+
tokens={dates}
333+
onTokenRemove={onDateRemove}
334+
trailingVisual={CalendarIcon}
335+
loading={loading}
336+
loaderPosition="leading"
337+
value="leading"
338+
/>
339+
</Box>
340+
<Box mb={5}>
341+
<TextInputWithTokens
342+
tokens={dates}
343+
onTokenRemove={onDateRemove}
344+
trailingVisual={CalendarIcon}
345+
loading={loading}
346+
loaderPosition="trailing"
347+
value="trailing"
348+
/>
349+
</Box>
350+
351+
<h3>Both visuals</h3>
352+
<Box mb={2}>
353+
<TextInputWithTokens
354+
tokens={dates}
355+
onTokenRemove={onDateRemove}
356+
size="small"
357+
leadingVisual={CalendarIcon}
358+
trailingVisual={CalendarIcon}
359+
loading={loading}
360+
value="auto"
361+
/>
362+
</Box>
363+
<Box mb={2}>
364+
<TextInputWithTokens
365+
tokens={dates}
366+
onTokenRemove={onDateRemove}
367+
leadingVisual={CalendarIcon}
368+
trailingVisual={CalendarIcon}
369+
loading={loading}
370+
loaderPosition="leading"
371+
value="leading"
372+
/>
373+
</Box>
374+
<Box mb={2}>
375+
<TextInputWithTokens
376+
tokens={dates}
377+
onTokenRemove={onDateRemove}
378+
size="large"
379+
leadingVisual={CalendarIcon}
380+
trailingVisual={CalendarIcon}
381+
loading={loading}
382+
loaderPosition="trailing"
383+
value="trailing"
384+
/>
385+
</Box>
386+
</>
387+
)
388+
}
389+
390+
render(<WithIconAndLoadingIndicator />)
391+
```
392+
240393
## Props
241394

242395
<PropsTable>

0 commit comments

Comments
 (0)