@ceed/ads 1.23.3 β 1.23.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/dist/components/data-display/Badge.md +71 -39
- package/dist/components/data-display/InfoSign.md +74 -98
- package/dist/components/data-display/Typography.md +310 -61
- package/dist/components/feedback/CircularProgress.md +257 -0
- package/dist/components/feedback/Skeleton.md +280 -0
- package/dist/components/feedback/llms.txt +2 -0
- package/dist/components/inputs/ButtonGroup.md +115 -106
- package/dist/components/inputs/Calendar.md +98 -459
- package/dist/components/inputs/CurrencyInput.md +181 -8
- package/dist/components/inputs/DatePicker.md +108 -436
- package/dist/components/inputs/DateRangePicker.md +130 -496
- package/dist/components/inputs/FilterMenu.md +169 -19
- package/dist/components/inputs/FilterableCheckboxGroup.md +119 -24
- package/dist/components/inputs/FormControl.md +368 -0
- package/dist/components/inputs/IconButton.md +137 -88
- package/dist/components/inputs/MonthPicker.md +95 -427
- package/dist/components/inputs/MonthRangePicker.md +89 -471
- package/dist/components/inputs/PercentageInput.md +183 -19
- package/dist/components/inputs/RadioButton.md +163 -35
- package/dist/components/inputs/RadioList.md +241 -0
- package/dist/components/inputs/RadioTileGroup.md +146 -62
- package/dist/components/inputs/Select.md +219 -328
- package/dist/components/inputs/Slider.md +334 -0
- package/dist/components/inputs/Switch.md +136 -376
- package/dist/components/inputs/Textarea.md +209 -11
- package/dist/components/inputs/Uploader/Uploader.md +145 -66
- package/dist/components/inputs/llms.txt +3 -0
- package/dist/components/navigation/Breadcrumbs.md +80 -322
- package/dist/components/navigation/Dropdown.md +92 -221
- package/dist/components/navigation/IconMenuButton.md +40 -502
- package/dist/components/navigation/InsetDrawer.md +68 -738
- package/dist/components/navigation/Link.md +39 -298
- package/dist/components/navigation/Menu.md +92 -285
- package/dist/components/navigation/MenuButton.md +55 -448
- package/dist/components/navigation/Pagination.md +47 -338
- package/dist/components/navigation/ProfileMenu.md +45 -268
- package/dist/components/navigation/Stepper.md +160 -28
- package/dist/components/navigation/Tabs.md +57 -316
- package/dist/components/surfaces/Sheet.md +150 -333
- package/dist/guides/ThemeProvider.md +116 -0
- package/dist/guides/llms.txt +9 -0
- package/dist/llms.txt +8 -0
- package/package.json +1 -1
|
@@ -2,11 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
## Introduction
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The Textarea component provides a multi-line text input field for collecting longer-form user input such as comments, descriptions, and notes. It is built on top of Joy UI's Textarea and automatically adjusts its height between `minRows` (default 2) and `maxRows` (default 4) as the user types.
|
|
6
|
+
|
|
7
|
+
Textarea integrates with the form system by wrapping itself in a FormControl, supporting built-in `label`, `helperText`, and `error` props. It also supports decorators, multiple visual variants, sizes, and color themes to fit a wide range of admin UI use cases.
|
|
8
|
+
|
|
9
|
+
> **Use built-in form props**
|
|
6
10
|
>
|
|
7
11
|
> This component natively supports form elements such as `label` and `helperText` props.
|
|
8
12
|
> When building forms, use these built-in props instead of manually composing labels and helper text with Typography.
|
|
9
13
|
|
|
14
|
+
## Playground
|
|
15
|
+
|
|
16
|
+
Interact with the Textarea component using the controls below.
|
|
17
|
+
|
|
10
18
|
```tsx
|
|
11
19
|
<Textarea name="Textarea" />
|
|
12
20
|
```
|
|
@@ -25,7 +33,26 @@
|
|
|
25
33
|
| error | β | β |
|
|
26
34
|
| onChange | β | β |
|
|
27
35
|
|
|
28
|
-
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import { Textarea } from '@ceed/ads';
|
|
40
|
+
|
|
41
|
+
function MyComponent() {
|
|
42
|
+
return (
|
|
43
|
+
<Textarea
|
|
44
|
+
name="description"
|
|
45
|
+
label="Description"
|
|
46
|
+
placeholder="Enter a description..."
|
|
47
|
+
helperText="Provide a brief summary."
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Variants
|
|
54
|
+
|
|
55
|
+
Textarea supports four visual variants: `solid`, `soft`, `outlined`, and `plain`. The default variant is `outlined`.
|
|
29
56
|
|
|
30
57
|
```tsx
|
|
31
58
|
<>
|
|
@@ -36,7 +63,16 @@
|
|
|
36
63
|
</>
|
|
37
64
|
```
|
|
38
65
|
|
|
39
|
-
|
|
66
|
+
```tsx
|
|
67
|
+
<Textarea variant="solid" placeholder="Solid" />
|
|
68
|
+
<Textarea variant="soft" placeholder="Soft" />
|
|
69
|
+
<Textarea variant="outlined" placeholder="Outlined" />
|
|
70
|
+
<Textarea variant="plain" placeholder="Plain" />
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Sizes
|
|
74
|
+
|
|
75
|
+
Textarea comes in three sizes: `sm`, `md`, and `lg`. The default size is `md`.
|
|
40
76
|
|
|
41
77
|
```tsx
|
|
42
78
|
<>
|
|
@@ -46,7 +82,15 @@
|
|
|
46
82
|
</>
|
|
47
83
|
```
|
|
48
84
|
|
|
49
|
-
|
|
85
|
+
```tsx
|
|
86
|
+
<Textarea size="sm" placeholder="Small" />
|
|
87
|
+
<Textarea size="md" placeholder="Medium" />
|
|
88
|
+
<Textarea size="lg" placeholder="Large" />
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Colors
|
|
92
|
+
|
|
93
|
+
Textarea supports semantic colors via the `color` prop: `primary`, `neutral`, `danger`, and `warning`.
|
|
50
94
|
|
|
51
95
|
```tsx
|
|
52
96
|
<>
|
|
@@ -57,13 +101,167 @@
|
|
|
57
101
|
</>
|
|
58
102
|
```
|
|
59
103
|
|
|
60
|
-
|
|
104
|
+
```tsx
|
|
105
|
+
<Textarea color="primary" placeholder="Primary" />
|
|
106
|
+
<Textarea color="neutral" placeholder="Neutral" />
|
|
107
|
+
<Textarea color="danger" placeholder="Danger" />
|
|
108
|
+
<Textarea color="warning" placeholder="Warning" />
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Required with Label and Helper Text
|
|
112
|
+
|
|
113
|
+
Use the `required`, `label`, and `helperText` props together to build complete form fields. The `required` prop adds an asterisk indicator to the label.
|
|
61
114
|
|
|
62
115
|
```tsx
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
116
|
+
<Textarea
|
|
117
|
+
name="Textarea"
|
|
118
|
+
placeholder="Type in here..."
|
|
119
|
+
helperText="I'm helper text"
|
|
120
|
+
label="Label"
|
|
121
|
+
required
|
|
122
|
+
/>
|
|
69
123
|
```
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
<Textarea
|
|
127
|
+
label="Label"
|
|
128
|
+
helperText="I'm helper text"
|
|
129
|
+
placeholder="Type in here..."
|
|
130
|
+
required
|
|
131
|
+
/>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Common Use Cases
|
|
135
|
+
|
|
136
|
+
### Feedback Form
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
import { Textarea, Button, Stack } from '@ceed/ads';
|
|
140
|
+
|
|
141
|
+
function FeedbackForm() {
|
|
142
|
+
const [value, setValue] = React.useState('');
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
<Stack spacing={2}>
|
|
146
|
+
<Textarea
|
|
147
|
+
name="feedback"
|
|
148
|
+
label="Feedback"
|
|
149
|
+
placeholder="Tell us what you think..."
|
|
150
|
+
helperText="Your feedback helps us improve the service."
|
|
151
|
+
minRows={3}
|
|
152
|
+
maxRows={6}
|
|
153
|
+
value={value}
|
|
154
|
+
onChange={(e) => setValue(e.target.value)}
|
|
155
|
+
required
|
|
156
|
+
/>
|
|
157
|
+
<Button disabled={!value.trim()}>Submit</Button>
|
|
158
|
+
</Stack>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Error State with Validation
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
import { Textarea } from '@ceed/ads';
|
|
167
|
+
|
|
168
|
+
function ValidatedTextarea() {
|
|
169
|
+
const [value, setValue] = React.useState('');
|
|
170
|
+
const isError = value.length > 0 && value.length < 10;
|
|
171
|
+
|
|
172
|
+
return (
|
|
173
|
+
<Textarea
|
|
174
|
+
name="notes"
|
|
175
|
+
label="Notes"
|
|
176
|
+
placeholder="Write at least 10 characters..."
|
|
177
|
+
helperText={isError ? 'Must be at least 10 characters.' : 'Optional notes for this record.'}
|
|
178
|
+
error={isError}
|
|
179
|
+
value={value}
|
|
180
|
+
onChange={(e) => setValue(e.target.value)}
|
|
181
|
+
/>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Disabled Read-Only Display
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
import { Textarea } from '@ceed/ads';
|
|
190
|
+
|
|
191
|
+
function ReadOnlyNotes() {
|
|
192
|
+
return (
|
|
193
|
+
<Textarea
|
|
194
|
+
name="archived-notes"
|
|
195
|
+
label="Archived Notes"
|
|
196
|
+
value="This record has been archived and cannot be edited."
|
|
197
|
+
disabled
|
|
198
|
+
/>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Best Practices
|
|
204
|
+
|
|
205
|
+
1. **Use built-in form props instead of manual composition.**
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
// β
Recommended
|
|
209
|
+
<Textarea label="Description" helperText="Keep it brief." />
|
|
210
|
+
|
|
211
|
+
// β Avoid
|
|
212
|
+
<FormControl>
|
|
213
|
+
<Typography level="title-sm" component="label">Description</Typography>
|
|
214
|
+
<Textarea />
|
|
215
|
+
<Typography level="body-xs" color="neutral">Keep it brief.</Typography>
|
|
216
|
+
</FormControl>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
2. **Set appropriate `minRows` and `maxRows` for the expected content length.**
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
// β
Short comment field
|
|
223
|
+
<Textarea minRows={2} maxRows={4} placeholder="Add a comment..." />
|
|
224
|
+
|
|
225
|
+
// β
Long description field
|
|
226
|
+
<Textarea minRows={4} maxRows={10} placeholder="Write a detailed description..." />
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
3. **Always provide a `name` prop for form submission.**
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
// β
Named textarea for form data
|
|
233
|
+
<Textarea name="description" label="Description" />
|
|
234
|
+
|
|
235
|
+
// β Missing name β value won't be included in form data
|
|
236
|
+
<Textarea label="Description" />
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
4. **Use `error` and `helperText` together for validation feedback.**
|
|
240
|
+
|
|
241
|
+
```tsx
|
|
242
|
+
// β
Clear error feedback
|
|
243
|
+
<Textarea
|
|
244
|
+
error={hasError}
|
|
245
|
+
helperText={hasError ? 'This field is required.' : 'Optional description.'}
|
|
246
|
+
/>
|
|
247
|
+
|
|
248
|
+
// β Error state without explanation
|
|
249
|
+
<Textarea error />
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
5. **Use a descriptive `placeholder` to guide user input.**
|
|
253
|
+
|
|
254
|
+
```tsx
|
|
255
|
+
// β
Descriptive placeholder
|
|
256
|
+
<Textarea placeholder="Describe the issue in detail..." />
|
|
257
|
+
|
|
258
|
+
// β Vague placeholder
|
|
259
|
+
<Textarea placeholder="Type here" />
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Accessibility
|
|
263
|
+
|
|
264
|
+
- The component automatically associates the `label` with the textarea element through FormControl, ensuring screen readers announce the label when the field receives focus.
|
|
265
|
+
- When `required` is set, the field is marked with `aria-required` and a visual asterisk indicator is added to the label.
|
|
266
|
+
- When `error` is set, the `helperText` is associated with the textarea via `aria-describedby`, allowing screen readers to announce the error message.
|
|
267
|
+
- Use a clear and descriptive `label` for every Textarea in a form. Avoid relying solely on `placeholder` text, as it disappears once the user starts typing and is not reliably announced by all screen readers.
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Uploader
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
Uploader is a file upload component that provides a drag-and-drop zone along with a file browser for selecting files. It handles file type validation, individual and total file size limits, minimum and maximum file count constraints, and displays uploaded file previews with delete capabilities. The component automatically generates helper text based on its configuration and surfaces clear error messages when validation rules are violated.
|
|
6
|
+
|
|
7
|
+
Uploader is designed for forms where users need to attach documents, images, or other files. It supports both controlled error states via the `error` prop and internal validation that triggers automatically when files are added. A [Figma design guide](https://www.figma.com/design/NoAOnaPiP2H2lzvRhkBnGZ/CDS-v1.1?node-id=2600-3701\&t=WLh4JrGHlzDGMeV4-0) is available for reference.
|
|
4
8
|
|
|
5
9
|
```tsx
|
|
6
10
|
<Uploader
|
|
@@ -23,10 +27,28 @@ Uploader μ»΄ν¬λνΈλ νμΌ μ
λ‘λλ₯Ό μν μ»΄ν¬λνΈμ
λλ€. [κ΄
|
|
|
23
27
|
| onChange | β | β |
|
|
24
28
|
| onDelete | β | β |
|
|
25
29
|
|
|
26
|
-
##
|
|
30
|
+
## Usage
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
```tsx
|
|
33
|
+
import { Uploader } from '@ceed/ads';
|
|
34
|
+
|
|
35
|
+
function MyForm() {
|
|
36
|
+
return (
|
|
37
|
+
<Uploader
|
|
38
|
+
accept=".png,.jpg,.pdf"
|
|
39
|
+
maxFileTotalSize={10 * 1024 * 1024}
|
|
40
|
+
maxCount={5}
|
|
41
|
+
label="Attachments"
|
|
42
|
+
onChange={(files) => console.log('Files added:', files)}
|
|
43
|
+
onDelete={(fileId) => console.log('File removed:', fileId)}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Default
|
|
50
|
+
|
|
51
|
+
The most basic Uploader requires `accept` and `maxFileTotalSize` props. Helper text is automatically generated from these values.
|
|
30
52
|
|
|
31
53
|
```tsx
|
|
32
54
|
<Uploader
|
|
@@ -35,7 +57,9 @@ Uploader μ»΄ν¬λνΈλ νμΌ μ
λ‘λλ₯Ό μν μ»΄ν¬λνΈμ
λλ€. [κ΄
|
|
|
35
57
|
/>
|
|
36
58
|
```
|
|
37
59
|
|
|
38
|
-
|
|
60
|
+
## With Label
|
|
61
|
+
|
|
62
|
+
Adding a `label` prop displays a title above the dropzone.
|
|
39
63
|
|
|
40
64
|
```tsx
|
|
41
65
|
<Uploader
|
|
@@ -45,9 +69,9 @@ Uploader μ»΄ν¬λνΈλ νμΌ μ
λ‘λλ₯Ό μν μ»΄ν¬λνΈμ
λλ€. [κ΄
|
|
|
45
69
|
/>
|
|
46
70
|
```
|
|
47
71
|
|
|
48
|
-
##
|
|
72
|
+
## Sizes
|
|
49
73
|
|
|
50
|
-
|
|
74
|
+
Two sizes are available: `sm` and `md`. Use the smaller size for compact form layouts.
|
|
51
75
|
|
|
52
76
|
```tsx
|
|
53
77
|
<Stack gap={4}>
|
|
@@ -62,11 +86,20 @@ Sizeλ `sm`, `md` λ μ¬μ΄μ¦λ₯Ό μ§μν©λλ€.
|
|
|
62
86
|
</Stack>
|
|
63
87
|
```
|
|
64
88
|
|
|
65
|
-
##
|
|
89
|
+
## File Type Restriction (Accepts)
|
|
90
|
+
|
|
91
|
+
The `accept` prop controls which file types are allowed. You can specify individual extensions (`.png,.jpg`) or use wildcards (`image/*`, `video/*`, `audio/*`) that map to predefined extension sets.
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
<Uploader
|
|
95
|
+
accept="image/png, image/jpeg, .pdf,.word,.txt,.doc,.docx"
|
|
96
|
+
maxFileTotalSize={31457280}
|
|
97
|
+
/>
|
|
98
|
+
```
|
|
66
99
|
|
|
67
|
-
|
|
100
|
+
## Min Count Validation
|
|
68
101
|
|
|
69
|
-
`minCount`
|
|
102
|
+
The `minCount` prop sets a minimum number of required files. Validation triggers on form submission.
|
|
70
103
|
|
|
71
104
|
```tsx
|
|
72
105
|
<>
|
|
@@ -82,10 +115,9 @@ Sizeλ `sm`, `md` λ μ¬μ΄μ¦λ₯Ό μ§μν©λλ€.
|
|
|
82
115
|
</>
|
|
83
116
|
```
|
|
84
117
|
|
|
85
|
-
|
|
118
|
+
## With Uploaded Files
|
|
86
119
|
|
|
87
|
-
`maxCount`
|
|
88
|
-
μλμ μν©μμ λ κ° μ΄μμ νμΌμ μ
λ‘λ ν΄λ³΄μΈμ.
|
|
120
|
+
Display pre-existing uploaded files and enforce `maxCount` limits. Try uploading additional files to trigger the limit error.
|
|
89
121
|
|
|
90
122
|
```tsx
|
|
91
123
|
<Uploader
|
|
@@ -105,30 +137,9 @@ Sizeλ `sm`, `md` λ μ¬μ΄μ¦λ₯Ό μ§μν©λλ€.
|
|
|
105
137
|
/>
|
|
106
138
|
```
|
|
107
139
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
`accept` μμ±μ μ΄μ©ν΄ νΉμ νμΌ νμλ§ μ
λ‘λν μ μλλ‘ μ νν μ μμ΅λλ€.\
|
|
111
|
-
νμΌ νμ₯μ μ νμ μν `accept`κ°μ νμμ μΌλ‘ λ°κ³ μμΌλ©°, νμ₯μλ₯Ό νΉμ ν΄μ μ¬μ©νκ±°λ(`.png,.jpeg,.txt`) `image/*`, `video/*`, `audio/*`μ κ°μ κ°μ μ¬μ©ν μ μμ΅λλ€.
|
|
112
|
-
|
|
113
|
-
μΌλΆ λλ°μ΄μ€μμ MIME typeμ μ¬μ©ν΄μ λ°μ νμΌμ μ ννλ κ²μ΄ μλμ λ€λ₯Έ λμμ μΌμΌν¬ μ μκΈ° λλ¬Έμ `image/*`, `video/*`, `audio/*`λ₯Ό μ¬μ©νλ©΄ λ΄λΆμ μΌλ‘ νΉμ νμ₯μ μ§ν©κ³Ό λ§΅νλ©λλ€.
|
|
140
|
+
## Total File Size Limit
|
|
114
141
|
|
|
115
|
-
`
|
|
116
|
-
`video/*` = `.mp4,.avi,.mkv,.mov,.wmv,.flv,.webm,.mpeg,.3gp,.m4v`\
|
|
117
|
-
`audio/*` = `.mp3,.wav,.flac,.aac,.ogg,.m4a,.wma,.aiff,.alac,.midi,.mp4`
|
|
118
|
-
|
|
119
|
-
```tsx
|
|
120
|
-
<Uploader
|
|
121
|
-
accept="image/png, image/jpeg, .pdf,.word,.txt,.doc,.docx"
|
|
122
|
-
maxFileTotalSize={31457280}
|
|
123
|
-
/>
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
### File Size
|
|
127
|
-
|
|
128
|
-
#### Total File Size
|
|
129
|
-
|
|
130
|
-
`maxFileTotalSize`κ°μΌλ‘ μ
λ‘λ κ°λ₯ν νμΌμ μ΄ ν¬κΈ°λ₯Ό μ νν μ μμ΅λλ€. `maxFileTotalSize`λ νμ μμ± κ°μ
λλ€.\
|
|
131
|
-
μλμ μν©μμ 1MB μ΄μμΌλ‘ νμΌμ μ
λ‘λ ν΄λ³΄μΈμ.
|
|
142
|
+
The `maxFileTotalSize` prop limits the combined size of all uploaded files.
|
|
132
143
|
|
|
133
144
|
```tsx
|
|
134
145
|
<Uploader
|
|
@@ -139,10 +150,9 @@ Sizeλ `sm`, `md` λ μ¬μ΄μ¦λ₯Ό μ§μν©λλ€.
|
|
|
139
150
|
/>
|
|
140
151
|
```
|
|
141
152
|
|
|
142
|
-
|
|
153
|
+
## Individual File Size Limit
|
|
143
154
|
|
|
144
|
-
`maxFileSize
|
|
145
|
-
μλμ μν©μμ Total 1MB μ΄μμ νμΌλ μ
λ‘λ ν΄λ³΄κ³ , 1MBκ° λλ λ¨μΌ νμΌλ μ
λ‘λ ν΄λ³΄μΈμ.
|
|
155
|
+
The `maxFileSize` prop limits the size of each individual file, independent of the total size limit.
|
|
146
156
|
|
|
147
157
|
```tsx
|
|
148
158
|
<Uploader
|
|
@@ -156,9 +166,7 @@ Sizeλ `sm`, `md` λ μ¬μ΄μ¦λ₯Ό μ§μν©λλ€.
|
|
|
156
166
|
|
|
157
167
|
## Error State
|
|
158
168
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
`error` propμ ν΅ν΄ μΈλΆμμ μλ¬ μνλ₯Ό μ μ΄ν μ μμ΅λλ€. μλ¬ μνμΌ λ Uploaderμ λλ‘μ‘΄ ν
λλ¦¬κ° λΉ¨κ°μμΌλ‘ λ³κ²½λ©λλ€.
|
|
169
|
+
Use the `error` prop to externally control the error state, and `helperText` to display a custom error message.
|
|
162
170
|
|
|
163
171
|
```tsx
|
|
164
172
|
<Uploader
|
|
@@ -170,9 +178,9 @@ Sizeλ `sm`, `md` λ μ¬μ΄μ¦λ₯Ό μ§μν©λλ€.
|
|
|
170
178
|
/>
|
|
171
179
|
```
|
|
172
180
|
|
|
173
|
-
|
|
181
|
+
## Validation Errors
|
|
174
182
|
|
|
175
|
-
|
|
183
|
+
Demonstrates automatic validation error messages for various rule violations (file type, size, count).
|
|
176
184
|
|
|
177
185
|
```tsx
|
|
178
186
|
<Stack gap={4}>
|
|
@@ -187,12 +195,9 @@ Sizeλ `sm`, `md` λ μ¬μ΄μ¦λ₯Ό μ§μν©λλ€.
|
|
|
187
195
|
</Stack>
|
|
188
196
|
```
|
|
189
197
|
|
|
190
|
-
## Helper Text
|
|
198
|
+
## Helper Text Variations
|
|
191
199
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
`helperText` propμ μ¬μ©νλ©΄ κΈ°λ³Έ μλ΄ λ©μμ§ λμ μ¬μ©μ μ μ λ©μμ§λ₯Ό νμν μ μμ΅λλ€.\
|
|
195
|
-
`helperText`κ° μ 곡λλ©΄ λͺ¨λ κΈ°λ³Έ μλ΄ λ©μμ§μ μλ¬ λ©μμ§λ³΄λ€ μ°μ μ μΌλ‘ νμλ©λλ€.
|
|
200
|
+
Comparison of auto-generated helper text, custom helper text, and error-state helper text.
|
|
196
201
|
|
|
197
202
|
```tsx
|
|
198
203
|
<Stack gap={4}>
|
|
@@ -211,28 +216,102 @@ Sizeλ `sm`, `md` λ μ¬μ΄μ¦λ₯Ό μ§μν©λλ€.
|
|
|
211
216
|
</Stack>
|
|
212
217
|
```
|
|
213
218
|
|
|
214
|
-
##
|
|
219
|
+
## Disabled State
|
|
220
|
+
|
|
221
|
+
The Uploader can be disabled to prevent file selection and drag-and-drop interactions.
|
|
222
|
+
|
|
223
|
+
```tsx
|
|
224
|
+
<Uploader
|
|
225
|
+
accept=".png"
|
|
226
|
+
maxFileTotalSize={31457280}
|
|
227
|
+
label="Click to Upload or drag file"
|
|
228
|
+
disabled
|
|
229
|
+
/>
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Common Use Cases
|
|
233
|
+
|
|
234
|
+
### Profile Photo Upload
|
|
235
|
+
|
|
236
|
+
```tsx
|
|
237
|
+
import { Uploader } from '@ceed/ads';
|
|
238
|
+
|
|
239
|
+
function ProfilePhotoUpload() {
|
|
240
|
+
return (
|
|
241
|
+
<Uploader
|
|
242
|
+
label="Profile Photo"
|
|
243
|
+
accept="image/*"
|
|
244
|
+
maxFileTotalSize={5 * 1024 * 1024}
|
|
245
|
+
maxCount={1}
|
|
246
|
+
maxFileSize={5 * 1024 * 1024}
|
|
247
|
+
helperText="Upload a profile photo (JPG, PNG, max 5MB)"
|
|
248
|
+
/>
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Document Attachment in a Form
|
|
254
|
+
|
|
255
|
+
```tsx
|
|
256
|
+
import { Uploader, Stack, Button } from '@ceed/ads';
|
|
257
|
+
|
|
258
|
+
function DocumentForm() {
|
|
259
|
+
return (
|
|
260
|
+
<form onSubmit={(e) => { e.preventDefault(); }}>
|
|
261
|
+
<Stack gap={3}>
|
|
262
|
+
<Uploader
|
|
263
|
+
label="Supporting Documents"
|
|
264
|
+
accept=".pdf,.doc,.docx"
|
|
265
|
+
maxFileTotalSize={30 * 1024 * 1024}
|
|
266
|
+
maxCount={10}
|
|
267
|
+
minCount={1}
|
|
268
|
+
maxFileSize={10 * 1024 * 1024}
|
|
269
|
+
/>
|
|
270
|
+
<Button type="submit">Submit</Button>
|
|
271
|
+
</Stack>
|
|
272
|
+
</form>
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Multi-Image Gallery Upload
|
|
278
|
+
|
|
279
|
+
```tsx
|
|
280
|
+
import { Uploader } from '@ceed/ads';
|
|
281
|
+
|
|
282
|
+
function GalleryUpload({ existingImages }) {
|
|
283
|
+
return (
|
|
284
|
+
<Uploader
|
|
285
|
+
label="Gallery Images"
|
|
286
|
+
accept="image/*"
|
|
287
|
+
maxFileTotalSize={50 * 1024 * 1024}
|
|
288
|
+
maxCount={20}
|
|
289
|
+
maxFileSize={10 * 1024 * 1024}
|
|
290
|
+
uploaded={existingImages}
|
|
291
|
+
onChange={(files) => console.log('New files:', files)}
|
|
292
|
+
onDelete={(id) => console.log('Removed:', id)}
|
|
293
|
+
/>
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
```
|
|
215
297
|
|
|
216
|
-
|
|
298
|
+
## Best Practices
|
|
217
299
|
|
|
218
|
-
|
|
300
|
+
- **Always set `maxFileTotalSize`.** This is a required prop that protects against excessively large uploads and informs users of the limit via auto-generated helper text.
|
|
219
301
|
|
|
220
|
-
|
|
302
|
+
- **Be specific with `accept`.** Use explicit extensions (`.png,.jpg,.pdf`) rather than wildcards when possible, as wildcard-to-extension mapping may vary across devices.
|
|
303
|
+
- β `accept=".png,.jpg,.pdf"` -- clear and predictable
|
|
304
|
+
- β `accept="*"` -- allows any file type with no validation
|
|
221
305
|
|
|
222
|
-
-
|
|
223
|
-
- **νμΌ ν¬κΈ° μ΄κ³Ό**: "One or more files exceeded the maximum file size. Each file size must be \[ν¬κΈ°] or less."
|
|
224
|
-
- **μ΄ νμΌ ν¬κΈ° μ΄κ³Ό**: "The total file size exceeds the maximum limit."
|
|
225
|
-
- **νμΌ κ°μ μ΄κ³Ό**: "Exceeded the maximum number of files."
|
|
226
|
-
- **μ΅μ νμΌ κ°μ λ―Έλ¬**: "Please choose \[κ°μ] files to upload." (form validation μ)
|
|
306
|
+
- **Provide meaningful labels.** Use the `label` prop to clearly indicate what type of files the user should upload and in what context.
|
|
227
307
|
|
|
228
|
-
|
|
308
|
+
- **Set `maxFileSize` for individual limits.** Even if `maxFileTotalSize` is set, large individual files can cause upload failures. Use `maxFileSize` to catch oversized files early.
|
|
229
309
|
|
|
230
|
-
`
|
|
310
|
+
- **Use `minCount` with form validation.** The minimum count check triggers on form submission, not on file selection. Make sure the Uploader is inside a `<form>` element for this validation to work.
|
|
231
311
|
|
|
232
|
-
|
|
233
|
-
- `image/*`, `video/*`, `audio/*` β "Any image file", "Any video file", "Any audio file"
|
|
234
|
-
- νΉμ νμ₯μ β λλ¬Έμ νμ₯μλͺ
λμ΄
|
|
235
|
-
2. **μ΅λ νμΌ ν¬κΈ°**: `maxFileTotalSize` prop κΈ°λ°
|
|
236
|
-
3. **νμΌ κ°μ μ ν**: `maxCount` prop κΈ°λ° (μλ κ²½μ°)
|
|
312
|
+
## Accessibility
|
|
237
313
|
|
|
238
|
-
|
|
314
|
+
- The dropzone is keyboard-accessible and can be activated via **Enter** or **Space** to open the file browser.
|
|
315
|
+
- Error messages and helper text are associated with the dropzone via ARIA attributes, ensuring screen readers announce validation feedback.
|
|
316
|
+
- Uploaded file items include accessible delete buttons with descriptive labels.
|
|
317
|
+
- The `label` prop renders as a visible label associated with the upload control for screen reader identification.
|
|
@@ -12,14 +12,17 @@
|
|
|
12
12
|
- [DateRangePicker](./DateRangePicker.md)
|
|
13
13
|
- [FilterableCheckboxGroup](./FilterableCheckboxGroup.md)
|
|
14
14
|
- [FilterMenu](./FilterMenu.md)
|
|
15
|
+
- [FormControl](./FormControl.md)
|
|
15
16
|
- [IconButton](./IconButton.md)
|
|
16
17
|
- [Input](./Input.md)
|
|
17
18
|
- [MonthPicker](./MonthPicker.md)
|
|
18
19
|
- [MonthRangePicker](./MonthRangePicker.md)
|
|
19
20
|
- [PercentageInput](./PercentageInput.md)
|
|
20
21
|
- [Radio](./RadioButton.md)
|
|
22
|
+
- [RadioList](./RadioList.md)
|
|
21
23
|
- [RadioTileGroup](./RadioTileGroup.md)
|
|
22
24
|
- [Select](./Select.md)
|
|
25
|
+
- [Slider](./Slider.md)
|
|
23
26
|
- [Switch](./Switch.md)
|
|
24
27
|
- [Textarea](./Textarea.md)
|
|
25
28
|
|