Skip to content

Commit 679cb5b

Browse files
committed
docs: TextInput design for playgrounds; use in useDebounce demo
1 parent 6b66c31 commit 679cb5b

File tree

9 files changed

+139
-14
lines changed

9 files changed

+139
-14
lines changed

docs/core/api/useDebounce.md

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ Delays updating the parameters by [debouncing](https://css-tricks.com/debouncing
1313

1414
Useful to avoid spamming network requests when parameters might change quickly (like a typeahead field).
1515

16+
:::tip React 18+
17+
18+
When loading new data, the [AsyncBoundary](./AsyncBoundary.md) will continue rendering the previous data until it is ready.
19+
`isPending` will be true while loading.
20+
21+
:::
22+
1623
## Usage
1724

1825
<HooksPlayground row>
@@ -95,12 +102,15 @@ export default function SearchIssues() {
95102
const [debouncedQuery, isPending] = useDebounce(query, 200);
96103
return (
97104
<div>
98-
<label>
99-
Query:{' '}
100-
<input type="text" value={query} onChange={handleChange} />
101-
{isPending ? '...' : ''}
102-
</label>
103-
<AsyncBoundary fallback={<div>searching...</div>}>
105+
<TextInput
106+
placeholder="Search react issues"
107+
label="Search"
108+
value={query}
109+
onChange={handleChange}
110+
autoFocus
111+
loading={isPending}
112+
/>
113+
<AsyncBoundary>
104114
<IssueList query={debouncedQuery} owner="facebook" repo="react" />
105115
</AsyncBoundary>
106116
</div>

website/src/components/Playground/DesignSystem/CancelButton.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,17 @@ export function CancelButton({ onClick }: { onClick?: () => void }) {
1313
style={{ cursor: onClick ? 'pointer' : 'default' }}
1414
onClick={onClick}
1515
>
16-
{onClick ? (
16+
{onClick ?
1717
<img
1818
src="/img/cancel.png"
1919
width="16"
2020
height="16"
2121
style={{ marginBottom: '-3px' }}
2222
/>
23-
) : (
24-
<div style={{ width: '16px', height: '16px', marginBottom: '-3px' }}>
23+
: <div style={{ width: '16px', height: '16px', marginBottom: '-3px' }}>
2524
&nbsp;
2625
</div>
27-
)}
26+
}
2827
</span>
2928
</div>
3029
);

website/src/components/Playground/DesignSystem/CurrentTime.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import React from 'react';
21
import { useEffect, useState } from 'react';
32

43
export function CurrentTime() {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import React, { type InputHTMLAttributes } from 'react';
2+
3+
export function TextInput({
4+
loading = false,
5+
label,
6+
...props
7+
}: InputHTMLAttributes<HTMLInputElement> & {
8+
label?: React.ReactNode;
9+
loading?: boolean;
10+
}) {
11+
return (
12+
<div className="rt-TextFieldRoot">
13+
<div className="rt-TextFieldSlot">
14+
<svg
15+
width="16"
16+
height="16"
17+
viewBox="0 0 15 15"
18+
fill="none"
19+
xmlns="http://www.w3.org/2000/svg"
20+
>
21+
<path
22+
d="M10 6.5C10 8.433 8.433 10 6.5 10C4.567 10 3 8.433 3 6.5C3 4.567 4.567 3 6.5 3C8.433 3 10 4.567 10 6.5ZM9.30884 10.0159C8.53901 10.6318 7.56251 11 6.5 11C4.01472 11 2 8.98528 2 6.5C2 4.01472 4.01472 2 6.5 2C8.98528 2 11 4.01472 11 6.5C11 7.56251 10.6318 8.53901 10.0159 9.30884L12.8536 12.1464C13.0488 12.3417 13.0488 12.6583 12.8536 12.8536C12.6583 13.0488 12.3417 13.0488 12.1464 12.8536L9.30884 10.0159Z"
23+
fill="currentColor"
24+
fillRule="evenodd"
25+
clipRule="evenodd"
26+
></path>
27+
</svg>
28+
</div>
29+
<input spellCheck="false" className="rt-TextFieldInput" {...props} />
30+
{label ?
31+
<label className="rt-TextFieldLabel">{label}</label>
32+
: null}
33+
{loading ?
34+
<div className="rt-TextFieldSpinner">
35+
<div className="rt-Spinner"></div>
36+
</div>
37+
: null}
38+
</div>
39+
);
40+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/* Root container for the text field */
2+
.rt-TextFieldRoot {
3+
display: flex;
4+
align-items: center;
5+
width: 100%;
6+
padding: 0.5em;
7+
background-color: white;
8+
border: 1px solid #ccc;
9+
border-radius: 4px;
10+
position: relative;
11+
}
12+
13+
/* The slot element (left side) */
14+
.rt-TextFieldSlot {
15+
display: flex;
16+
align-items: center;
17+
color: #666;
18+
}
19+
20+
/* The input element inside the text field */
21+
.rt-TextFieldInput {
22+
flex: 1;
23+
border: none;
24+
outline: none;
25+
font-size: 1em;
26+
color: #333;
27+
background: transparent;
28+
}
29+
30+
/* Spinner container (right side) */
31+
.rt-TextFieldSpinner {
32+
display: flex;
33+
align-items: center;
34+
color: #666;
35+
}
36+
37+
/* Spinner styles */
38+
.rt-Spinner {
39+
width: 16px;
40+
height: 16px;
41+
border: 2px solid #ccc;
42+
border-top-color: #007AFF;
43+
border-radius: 50%;
44+
animation: rt-spin 1s linear infinite;
45+
}
46+
47+
/* Spinner animation */
48+
@keyframes rt-spin {
49+
to {
50+
transform: rotate(360deg);
51+
}
52+
}
53+
54+
/* Placeholder or label styling */
55+
.rt-TextFieldLabel {
56+
position: absolute;
57+
top: -0.75em;
58+
left: 0.75em;
59+
background-color: white;
60+
padding: 0 0.25em;
61+
font-size: 0.75em;
62+
color: #666;
63+
pointer-events: none;
64+
}
65+
66+
/* Focus state for the text field */
67+
.rt-TextFieldInput:focus + .rt-TextFieldLabel,
68+
.rt-TextFieldInput:not(:placeholder-shown) + .rt-TextFieldLabel {
69+
color: #007AFF;
70+
}
71+
72+
.rt-TextFieldRoot:focus-within {
73+
border-color: #007AFF;
74+
}

website/src/components/Playground/DesignSystem/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ export { CancelButton } from './CancelButton';
22
export { CurrentTime } from './CurrentTime';
33
export { Avatar } from './Avatar';
44
export { Formatted } from './Formatted';
5+
import './design-system.css';
6+
export { TextInput } from './TextInput';

website/src/components/Playground/FixturePreview.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Fixture, Interceptor } from '@data-client/test';
22
import BrowserOnly from '@docusaurus/BrowserOnly';
33
import CodeBlock from '@theme/CodeBlock';
4-
import React, { memo, type ReactElement } from 'react';
4+
import { memo, type ReactElement } from 'react';
55

66
import styles from './styles.module.css';
77

website/src/components/Playground/Preview.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ function Preview<T>({
7171
getInitialInterceptorData={getInitialInterceptorData}
7272
>
7373
<div
74-
className={clsx(styles.playgroundPreview, {
74+
className={clsx('playground-preview', styles.playgroundPreview, {
7575
[styles.hidden]: hiddenResult,
7676
})}
7777
>

website/src/components/Playground/monaco-init.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,8 @@ if (
265265
declare function CancelButton(props: { onClick?: () => void }):JSX.Element;
266266
declare function Avatar(props: { src: string }):JSX.Element;
267267
declare function Formatted({ downColor, formatter, formatterFn, timeout, transition, transitionLength, upColor, value, stylePrefix, }: NumberProps):JSX.Element
268-
declare function ResetableErrorBoundary(props: { children: JSX.ReactChild }):JSX.Element;
268+
declare function ResetableErrorBoundary(props: { children: React.ReactNode }):JSX.Element;
269+
declare function TextInput(props:React.InputHTMLAttributes<HTMLInputElement> & { label?: React.ReactNode; loading?: boolean }):JSX.Element;
269270
declare function randomFloatInRange(min: number, max: number, decimals?: number): number;
270271
declare interface NumberProps {
271272
/**

0 commit comments

Comments
 (0)