@app-studio/web 0.9.31 → 0.9.32
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/docs/components/Accordion.mdx +158 -0
- package/docs/components/Alert.mdx +123 -0
- package/docs/components/AspectRatio.mdx +55 -0
- package/docs/components/Avatar.mdx +85 -0
- package/docs/components/Background.mdx +522 -0
- package/docs/components/Badge.mdx +220 -0
- package/docs/components/Button.mdx +272 -0
- package/docs/components/Calendar.mdx +274 -0
- package/docs/components/Card.mdx +341 -0
- package/docs/components/Carousel.mdx +411 -0
- package/docs/components/Center.mdx +474 -0
- package/docs/components/Chart.mdx +232 -0
- package/docs/components/ChatInput.mdx +373 -0
- package/docs/components/Checkbox.mdx +66 -0
- package/docs/components/ColorInput.mdx +209 -0
- package/docs/components/ComboBox.mdx +364 -0
- package/docs/components/Command.mdx +252 -0
- package/docs/components/ContextMenu.mdx +219 -0
- package/docs/components/CountryPicker.mdx +123 -0
- package/docs/components/DatePicker.mdx +77 -0
- package/docs/components/DragAndDrop.mdx +539 -0
- package/docs/components/DropdownMenu.mdx +205 -0
- package/docs/components/File.mdx +8 -0
- package/docs/components/Flow.mdx +257 -0
- package/docs/components/Form.mdx +681 -0
- package/docs/components/Formik.mdx +621 -0
- package/docs/components/Gradient.mdx +271 -0
- package/docs/components/Horizontal.mdx +40 -0
- package/docs/components/HoverCard.mdx +140 -0
- package/docs/components/Icon.mdx +438 -0
- package/docs/components/Label.mdx +438 -0
- package/docs/components/Link.mdx +83 -0
- package/docs/components/Loader.mdx +527 -0
- package/docs/components/Menubar.mdx +124 -0
- package/docs/components/Message.mdx +571 -0
- package/docs/components/Modal.mdx +533 -0
- package/docs/components/NavigationMenu.mdx +165 -0
- package/docs/components/Pagination.mdx +150 -0
- package/docs/components/Password.mdx +121 -0
- package/docs/components/Resizable.mdx +148 -0
- package/docs/components/Select.mdx +126 -0
- package/docs/components/Separator.mdx +121 -0
- package/docs/components/Sidebar.mdx +147 -0
- package/docs/components/Slider.mdx +232 -0
- package/docs/components/Switch.mdx +62 -0
- package/docs/components/Table.mdx +409 -0
- package/docs/components/Tabs.mdx +215 -0
- package/docs/components/TagInput.mdx +528 -0
- package/docs/components/Text.mdx +163 -0
- package/docs/components/TextArea.mdx +136 -0
- package/docs/components/TextField.mdx +225 -0
- package/docs/components/Title.mdx +535 -0
- package/docs/components/Toast.mdx +165 -0
- package/docs/components/Toggle.mdx +141 -0
- package/docs/components/ToggleGroup.mdx +165 -0
- package/docs/components/Tooltip.mdx +191 -0
- package/docs/components/Tree.mdx +340 -0
- package/docs/components/Uploader.mdx +426 -0
- package/docs/components/Vertical.mdx +566 -0
- package/package.json +1 -1
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
# TagInput
|
|
2
|
+
|
|
3
|
+
A form input component for managing a list of tags. Users can add tags by typing and pressing Enter or comma, and remove them by clicking the X button or using backspace.
|
|
4
|
+
|
|
5
|
+
### **Import**
|
|
6
|
+
```tsx
|
|
7
|
+
import { TagInput } from '@app-studio/web';
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
### **Default**
|
|
11
|
+
```tsx
|
|
12
|
+
import React, { useState } from 'react';
|
|
13
|
+
import { Vertical, Text } from 'app-studio';
|
|
14
|
+
import { TagInput } from '../TagInput';
|
|
15
|
+
|
|
16
|
+
export const DefaultTagInput = () => {
|
|
17
|
+
const [tags, setTags] = useState<string[]>([]);
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Vertical gap={20}>
|
|
21
|
+
<TagInput
|
|
22
|
+
label="Tags"
|
|
23
|
+
placeholder="Type tags and press Enter..."
|
|
24
|
+
tags={tags}
|
|
25
|
+
onTagsChange={setTags}
|
|
26
|
+
helperText="Add relevant tags for your content"
|
|
27
|
+
/>
|
|
28
|
+
<Text fontSize={14} color="color.gray.600">
|
|
29
|
+
Current tags: {Array.isArray(tags) ? tags.join(', ') : 'None'}
|
|
30
|
+
</Text>
|
|
31
|
+
</Vertical>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### **separators**
|
|
37
|
+
Characters that trigger tag creation. Supports 'enter', 'comma', 'space', and 'tab'.
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import React, { useState } from 'react';
|
|
41
|
+
import { Vertical } from 'app-studio';
|
|
42
|
+
import { TagInput } from '../TagInput';
|
|
43
|
+
|
|
44
|
+
export const CustomSeparatorsTagInput = () => {
|
|
45
|
+
const [tags, setTags] = useState<string[]>(['react', 'typescript']);
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<Vertical gap={20}>
|
|
49
|
+
<TagInput
|
|
50
|
+
name="customTags"
|
|
51
|
+
label="Skills"
|
|
52
|
+
placeholder="Use Enter, comma, or space to add skills..."
|
|
53
|
+
tags={tags}
|
|
54
|
+
onTagsChange={setTags}
|
|
55
|
+
separators={['enter', 'comma', 'space']}
|
|
56
|
+
variant="outline"
|
|
57
|
+
shape="rounded"
|
|
58
|
+
size="lg"
|
|
59
|
+
/>
|
|
60
|
+
</Vertical>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### **maxTags**
|
|
66
|
+
Maximum number of tags allowed.
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
import React, { useState } from 'react';
|
|
70
|
+
import { Vertical } from 'app-studio';
|
|
71
|
+
import { TagInput } from '../TagInput';
|
|
72
|
+
|
|
73
|
+
export const LimitedTagInput = () => {
|
|
74
|
+
const [tags, setTags] = useState<string[]>(['javascript', 'web']);
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<Vertical gap={20}>
|
|
78
|
+
<TagInput
|
|
79
|
+
name="limitedTags"
|
|
80
|
+
label="Technologies"
|
|
81
|
+
placeholder="Add up to 5 technologies..."
|
|
82
|
+
tags={tags}
|
|
83
|
+
onTagsChange={setTags}
|
|
84
|
+
maxTags={5}
|
|
85
|
+
variant="outline"
|
|
86
|
+
helperText={`${tags.length}/5 tags used`}
|
|
87
|
+
/>
|
|
88
|
+
</Vertical>
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### **minTagLength & maxTagLength**
|
|
94
|
+
Validation constraints for tag length.
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
import React, { useState } from 'react';
|
|
98
|
+
import { Vertical } from 'app-studio';
|
|
99
|
+
import { TagInput } from '../TagInput';
|
|
100
|
+
|
|
101
|
+
export const ValidatedTagInput = () => {
|
|
102
|
+
const [tags, setTags] = useState<string[]>([]);
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<Vertical gap={20}>
|
|
106
|
+
<TagInput
|
|
107
|
+
name="validatedTags"
|
|
108
|
+
label="Categories"
|
|
109
|
+
placeholder="Add categories..."
|
|
110
|
+
tags={tags}
|
|
111
|
+
onTagsChange={setTags}
|
|
112
|
+
minTagLength={3}
|
|
113
|
+
maxTagLength={20}
|
|
114
|
+
allowDuplicates={false}
|
|
115
|
+
variant="outline"
|
|
116
|
+
shape="pillShaped"
|
|
117
|
+
helperText="Tags must be 3-20 characters long"
|
|
118
|
+
/>
|
|
119
|
+
</Vertical>
|
|
120
|
+
);
|
|
121
|
+
};
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### **allowDuplicates**
|
|
125
|
+
Whether to allow duplicate tags.
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
import React, { useState } from 'react';
|
|
129
|
+
import { Vertical } from 'app-studio';
|
|
130
|
+
import { TagInput } from '../TagInput';
|
|
131
|
+
|
|
132
|
+
export const NoDuplicatesTagInput = () => {
|
|
133
|
+
const [tags, setTags] = useState<string[]>(['unique']);
|
|
134
|
+
|
|
135
|
+
return (
|
|
136
|
+
<TagInput
|
|
137
|
+
label="Unique Tags Only"
|
|
138
|
+
placeholder="Try adding 'unique' again..."
|
|
139
|
+
tags={tags}
|
|
140
|
+
onTagsChange={setTags}
|
|
141
|
+
allowDuplicates={false}
|
|
142
|
+
helperText="Duplicate tags will be rejected"
|
|
143
|
+
/>
|
|
144
|
+
);
|
|
145
|
+
};
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### **defaultTags**
|
|
149
|
+
Default tags for uncontrolled component usage.
|
|
150
|
+
|
|
151
|
+
```tsx
|
|
152
|
+
import React from 'react';
|
|
153
|
+
import { TagInput } from '../TagInput';
|
|
154
|
+
|
|
155
|
+
export const UncontrolledTagInput = () => {
|
|
156
|
+
return (
|
|
157
|
+
<TagInput
|
|
158
|
+
name="uncontrolledTags"
|
|
159
|
+
label="Default Tags"
|
|
160
|
+
placeholder="Add more tags..."
|
|
161
|
+
defaultTags={['default', 'example']}
|
|
162
|
+
onTagsChange={(tags) => console.log('Tags changed:', tags)}
|
|
163
|
+
helperText="This component manages its own state"
|
|
164
|
+
/>
|
|
165
|
+
);
|
|
166
|
+
};
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### **isDisabled & isReadOnly**
|
|
170
|
+
Disabled and read-only states.
|
|
171
|
+
|
|
172
|
+
```tsx
|
|
173
|
+
import React from 'react';
|
|
174
|
+
import { Vertical } from 'app-studio';
|
|
175
|
+
import { TagInput } from '../TagInput';
|
|
176
|
+
|
|
177
|
+
export const DisabledTagInput = () => {
|
|
178
|
+
return (
|
|
179
|
+
<Vertical gap={20}>
|
|
180
|
+
<TagInput
|
|
181
|
+
name="disabledTags"
|
|
182
|
+
label="Disabled Tags"
|
|
183
|
+
tags={['disabled', 'example']}
|
|
184
|
+
isDisabled={true}
|
|
185
|
+
helperText="This input is disabled"
|
|
186
|
+
/>
|
|
187
|
+
<TagInput
|
|
188
|
+
name="readonlyTags"
|
|
189
|
+
label="Read-Only Tags"
|
|
190
|
+
tags={['readonly', 'example']}
|
|
191
|
+
isReadOnly={true}
|
|
192
|
+
isRemovable={false}
|
|
193
|
+
helperText="This input is read-only"
|
|
194
|
+
/>
|
|
195
|
+
</Vertical>
|
|
196
|
+
);
|
|
197
|
+
};
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### **variant**
|
|
201
|
+
Visual variant of the component: 'outline', 'default', or 'none'.
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
import React, { useState } from 'react';
|
|
205
|
+
import { Vertical } from 'app-studio';
|
|
206
|
+
import { TagInput } from '../TagInput';
|
|
207
|
+
|
|
208
|
+
export const VariantTagInput = () => {
|
|
209
|
+
const [tags, setTags] = useState<string[]>(['example']);
|
|
210
|
+
|
|
211
|
+
return (
|
|
212
|
+
<Vertical gap={20}>
|
|
213
|
+
<TagInput
|
|
214
|
+
label="Default Variant"
|
|
215
|
+
tags={tags}
|
|
216
|
+
onTagsChange={setTags}
|
|
217
|
+
variant="default"
|
|
218
|
+
/>
|
|
219
|
+
<TagInput
|
|
220
|
+
label="Outline Variant"
|
|
221
|
+
tags={tags}
|
|
222
|
+
onTagsChange={setTags}
|
|
223
|
+
variant="outline"
|
|
224
|
+
/>
|
|
225
|
+
<TagInput
|
|
226
|
+
label="None Variant"
|
|
227
|
+
tags={tags}
|
|
228
|
+
onTagsChange={setTags}
|
|
229
|
+
variant="none"
|
|
230
|
+
/>
|
|
231
|
+
</Vertical>
|
|
232
|
+
);
|
|
233
|
+
};
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### **size**
|
|
237
|
+
Size of the component: 'xs', 'sm', 'md', 'lg', or 'xl'.
|
|
238
|
+
|
|
239
|
+
```tsx
|
|
240
|
+
import React, { useState } from 'react';
|
|
241
|
+
import { Vertical } from 'app-studio';
|
|
242
|
+
import { TagInput } from '../TagInput';
|
|
243
|
+
|
|
244
|
+
export const SizeTagInput = () => {
|
|
245
|
+
const [tags, setTags] = useState<string[]>(['tag']);
|
|
246
|
+
|
|
247
|
+
return (
|
|
248
|
+
<Vertical gap={15}>
|
|
249
|
+
{['xs', 'sm', 'md', 'lg', 'xl'].map((size) => (
|
|
250
|
+
<TagInput
|
|
251
|
+
key={size}
|
|
252
|
+
label={`Size: ${size}`}
|
|
253
|
+
tags={tags}
|
|
254
|
+
onTagsChange={setTags}
|
|
255
|
+
size={size as any}
|
|
256
|
+
variant="outline"
|
|
257
|
+
/>
|
|
258
|
+
))}
|
|
259
|
+
</Vertical>
|
|
260
|
+
);
|
|
261
|
+
};
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### **shape**
|
|
265
|
+
Shape/border radius: 'default', 'sharp', 'rounded', or 'pillShaped'.
|
|
266
|
+
|
|
267
|
+
```tsx
|
|
268
|
+
import React, { useState } from 'react';
|
|
269
|
+
import { Vertical } from 'app-studio';
|
|
270
|
+
import { TagInput } from '../TagInput';
|
|
271
|
+
|
|
272
|
+
export const ShapeTagInput = () => {
|
|
273
|
+
const [tags, setTags] = useState<string[]>(['shaped']);
|
|
274
|
+
|
|
275
|
+
return (
|
|
276
|
+
<Vertical gap={15}>
|
|
277
|
+
{['default', 'sharp', 'rounded', 'pillShaped'].map((shape) => (
|
|
278
|
+
<TagInput
|
|
279
|
+
key={shape}
|
|
280
|
+
label={`Shape: ${shape}`}
|
|
281
|
+
tags={tags}
|
|
282
|
+
onTagsChange={setTags}
|
|
283
|
+
shape={shape as any}
|
|
284
|
+
variant="outline"
|
|
285
|
+
/>
|
|
286
|
+
))}
|
|
287
|
+
</Vertical>
|
|
288
|
+
);
|
|
289
|
+
};
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### **left & right**
|
|
293
|
+
React nodes to render on the left and right sides of the input.
|
|
294
|
+
|
|
295
|
+
```tsx
|
|
296
|
+
import React, { useState } from 'react';
|
|
297
|
+
import { Vertical } from 'app-studio';
|
|
298
|
+
import { TagInput } from '../TagInput';
|
|
299
|
+
import { SearchIcon, TagIcon } from '../../../Icon';
|
|
300
|
+
|
|
301
|
+
export const IconTagInput = () => {
|
|
302
|
+
const [tags, setTags] = useState<string[]>(['search']);
|
|
303
|
+
|
|
304
|
+
return (
|
|
305
|
+
<Vertical gap={20}>
|
|
306
|
+
<TagInput
|
|
307
|
+
label="With Left Icon"
|
|
308
|
+
placeholder="Search tags..."
|
|
309
|
+
tags={tags}
|
|
310
|
+
onTagsChange={setTags}
|
|
311
|
+
left={<SearchIcon size={16} />}
|
|
312
|
+
variant="outline"
|
|
313
|
+
/>
|
|
314
|
+
<TagInput
|
|
315
|
+
label="With Right Icon"
|
|
316
|
+
placeholder="Add tags..."
|
|
317
|
+
tags={tags}
|
|
318
|
+
onTagsChange={setTags}
|
|
319
|
+
right={<TagIcon size={16} />}
|
|
320
|
+
variant="outline"
|
|
321
|
+
/>
|
|
322
|
+
</Vertical>
|
|
323
|
+
);
|
|
324
|
+
};
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### **views**
|
|
328
|
+
Custom styling for different parts of the component.
|
|
329
|
+
|
|
330
|
+
```tsx
|
|
331
|
+
import React, { useState } from 'react';
|
|
332
|
+
import { Vertical } from 'app-studio';
|
|
333
|
+
import { TagInput } from '../TagInput';
|
|
334
|
+
|
|
335
|
+
export const StyledTagInput = () => {
|
|
336
|
+
const [tags, setTags] = useState<string[]>(['design', 'ui']);
|
|
337
|
+
|
|
338
|
+
return (
|
|
339
|
+
<TagInput
|
|
340
|
+
name="styledTags"
|
|
341
|
+
label="Custom Styled"
|
|
342
|
+
placeholder="Add design-related tags..."
|
|
343
|
+
tags={tags}
|
|
344
|
+
onTagsChange={setTags}
|
|
345
|
+
variant="none"
|
|
346
|
+
shape="rounded"
|
|
347
|
+
shadow={{ boxShadow: 'rgba(0, 0, 0, 0.1) 0px 4px 12px' }}
|
|
348
|
+
views={{
|
|
349
|
+
inputContainer: {
|
|
350
|
+
borderColor: 'theme.primary',
|
|
351
|
+
borderWidth: '2px',
|
|
352
|
+
backgroundColor: 'color.blue.50',
|
|
353
|
+
},
|
|
354
|
+
tag: {
|
|
355
|
+
backgroundColor: 'theme.primary',
|
|
356
|
+
borderColor: 'theme.primary',
|
|
357
|
+
},
|
|
358
|
+
tagText: {
|
|
359
|
+
color: 'color.white',
|
|
360
|
+
},
|
|
361
|
+
tagRemove: {
|
|
362
|
+
_hover: {
|
|
363
|
+
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
label: {
|
|
367
|
+
color: 'theme.primary',
|
|
368
|
+
fontWeight: 'bold',
|
|
369
|
+
},
|
|
370
|
+
}}
|
|
371
|
+
/>
|
|
372
|
+
);
|
|
373
|
+
};
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### **onTagAdd & onTagRemove**
|
|
377
|
+
Callbacks for individual tag operations.
|
|
378
|
+
|
|
379
|
+
```tsx
|
|
380
|
+
import React, { useState } from 'react';
|
|
381
|
+
import { Vertical, Text } from 'app-studio';
|
|
382
|
+
import { TagInput } from '../TagInput';
|
|
383
|
+
|
|
384
|
+
export const CallbackTagInput = () => {
|
|
385
|
+
const [tags, setTags] = useState<string[]>(['initial']);
|
|
386
|
+
const [lastAction, setLastAction] = useState<string>('');
|
|
387
|
+
|
|
388
|
+
return (
|
|
389
|
+
<Vertical gap={20}>
|
|
390
|
+
<TagInput
|
|
391
|
+
label="Tag Operations"
|
|
392
|
+
placeholder="Add or remove tags..."
|
|
393
|
+
tags={tags}
|
|
394
|
+
onTagsChange={setTags}
|
|
395
|
+
onTagAdd={(tag) => setLastAction(`Added: ${tag}`)}
|
|
396
|
+
onTagRemove={(tag, index) => setLastAction(`Removed: ${tag} at index ${index}`)}
|
|
397
|
+
variant="outline"
|
|
398
|
+
/>
|
|
399
|
+
<Text fontSize={14} color="color.gray.600">
|
|
400
|
+
Last action: {lastAction || 'None'}
|
|
401
|
+
</Text>
|
|
402
|
+
</Vertical>
|
|
403
|
+
);
|
|
404
|
+
};
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### **isRemovable**
|
|
408
|
+
Whether tags can be removed by clicking the X button.
|
|
409
|
+
|
|
410
|
+
```tsx
|
|
411
|
+
import React, { useState } from 'react';
|
|
412
|
+
import { Vertical } from 'app-studio';
|
|
413
|
+
import { TagInput } from '../TagInput';
|
|
414
|
+
|
|
415
|
+
export const NonRemovableTagInput = () => {
|
|
416
|
+
const [tags, setTags] = useState<string[]>(['permanent', 'fixed']);
|
|
417
|
+
|
|
418
|
+
return (
|
|
419
|
+
<Vertical gap={20}>
|
|
420
|
+
<TagInput
|
|
421
|
+
label="Removable Tags (Default)"
|
|
422
|
+
tags={tags}
|
|
423
|
+
onTagsChange={setTags}
|
|
424
|
+
isRemovable={true}
|
|
425
|
+
helperText="Click X to remove tags"
|
|
426
|
+
/>
|
|
427
|
+
<TagInput
|
|
428
|
+
label="Non-Removable Tags"
|
|
429
|
+
tags={['permanent', 'fixed']}
|
|
430
|
+
isRemovable={false}
|
|
431
|
+
helperText="Tags cannot be removed"
|
|
432
|
+
/>
|
|
433
|
+
</Vertical>
|
|
434
|
+
);
|
|
435
|
+
};
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### **Form Integration**
|
|
439
|
+
TagInput works seamlessly with forms and form libraries.
|
|
440
|
+
|
|
441
|
+
```tsx
|
|
442
|
+
import React, { useState } from 'react';
|
|
443
|
+
import { Vertical, Button } from 'app-studio';
|
|
444
|
+
import { TagInput } from '../TagInput';
|
|
445
|
+
|
|
446
|
+
export const FormTagInput = () => {
|
|
447
|
+
const [formData, setFormData] = useState({
|
|
448
|
+
skills: ['react', 'typescript'],
|
|
449
|
+
interests: []
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
const handleSubmit = (e: React.FormEvent) => {
|
|
453
|
+
e.preventDefault();
|
|
454
|
+
console.log('Form submitted:', formData);
|
|
455
|
+
alert(`Skills: ${formData.skills.join(', ')}\nInterests: ${formData.interests.join(', ')}`);
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
return (
|
|
459
|
+
<form onSubmit={handleSubmit}>
|
|
460
|
+
<Vertical gap={20}>
|
|
461
|
+
<TagInput
|
|
462
|
+
name="skills"
|
|
463
|
+
label="Technical Skills"
|
|
464
|
+
placeholder="Add your skills..."
|
|
465
|
+
tags={formData.skills}
|
|
466
|
+
onTagsChange={(tags) => setFormData(prev => ({ ...prev, skills: tags }))}
|
|
467
|
+
maxTags={10}
|
|
468
|
+
variant="outline"
|
|
469
|
+
helperText="Add up to 10 technical skills"
|
|
470
|
+
/>
|
|
471
|
+
<TagInput
|
|
472
|
+
name="interests"
|
|
473
|
+
label="Interests"
|
|
474
|
+
placeholder="Add your interests..."
|
|
475
|
+
tags={formData.interests}
|
|
476
|
+
onTagsChange={(tags) => setFormData(prev => ({ ...prev, interests: tags }))}
|
|
477
|
+
separators={['enter', 'comma', 'space']}
|
|
478
|
+
variant="outline"
|
|
479
|
+
/>
|
|
480
|
+
<Button type="submit" variant="filled">
|
|
481
|
+
Submit Form
|
|
482
|
+
</Button>
|
|
483
|
+
</Vertical>
|
|
484
|
+
</form>
|
|
485
|
+
);
|
|
486
|
+
};
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### **Error Handling**
|
|
490
|
+
Display validation errors and helper messages.
|
|
491
|
+
|
|
492
|
+
```tsx
|
|
493
|
+
import React, { useState } from 'react';
|
|
494
|
+
import { Vertical } from 'app-studio';
|
|
495
|
+
import { TagInput } from '../TagInput';
|
|
496
|
+
|
|
497
|
+
export const ErrorTagInput = () => {
|
|
498
|
+
const [tags, setTags] = useState<string[]>([]);
|
|
499
|
+
const [error, setError] = useState<string>('');
|
|
500
|
+
|
|
501
|
+
const handleTagsChange = (newTags: string[]) => {
|
|
502
|
+
setTags(newTags);
|
|
503
|
+
|
|
504
|
+
// Validation logic
|
|
505
|
+
if (newTags.length === 0) {
|
|
506
|
+
setError('At least one tag is required');
|
|
507
|
+
} else if (newTags.length > 5) {
|
|
508
|
+
setError('Maximum 5 tags allowed');
|
|
509
|
+
} else {
|
|
510
|
+
setError('');
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
return (
|
|
515
|
+
<Vertical gap={20}>
|
|
516
|
+
<TagInput
|
|
517
|
+
label="Required Tags"
|
|
518
|
+
placeholder="Add at least one tag..."
|
|
519
|
+
tags={tags}
|
|
520
|
+
onTagsChange={handleTagsChange}
|
|
521
|
+
error={error}
|
|
522
|
+
variant="outline"
|
|
523
|
+
helperText={error || "Add 1-5 tags"}
|
|
524
|
+
/>
|
|
525
|
+
</Vertical>
|
|
526
|
+
);
|
|
527
|
+
};
|
|
528
|
+
```
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
### **Import**
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
import { Text } from "@app-studio/web";
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
### **Default**
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
<Text>Some text here</Text>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### **Sizes**
|
|
14
|
+
|
|
15
|
+
“**_size_**” changes the text-size. It has a type "Sizes" with default value “md”.
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { Vertical } from "../Layout/Vertical/Vertical";
|
|
19
|
+
|
|
20
|
+
<Vertical gap={5} alignItems="center">
|
|
21
|
+
{["xs", "sm", "md", "lg", "xl", "xl", "xl", "xl", "xl", "6xl"].map(
|
|
22
|
+
(size, index) => (
|
|
23
|
+
<Text key={index} size={size}>
|
|
24
|
+
{size}
|
|
25
|
+
</Text>
|
|
26
|
+
)
|
|
27
|
+
)}
|
|
28
|
+
</Vertical>;
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### **Headings**
|
|
32
|
+
|
|
33
|
+
“**_heading_**” renders a specific heading html tag. “h1” indicates the most important heading and “h6” the least important heading.
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { Vertical } from "../Layout/Vertical/Vertical";
|
|
37
|
+
<Vertical gap={2}>
|
|
38
|
+
<Text heading="h1">Heading 1</Text>
|
|
39
|
+
<Text heading="h2">Heading 2</Text>
|
|
40
|
+
<Text heading="h3">Heading 3</Text>
|
|
41
|
+
<Text heading="h4">Heading 4</Text>
|
|
42
|
+
<Text heading="h5">Heading 5</Text>
|
|
43
|
+
<Text heading="h6">Heading 6</Text>
|
|
44
|
+
</Vertical>;
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### **Strike**
|
|
48
|
+
|
|
49
|
+
“**_isStriked_**” marks up a text to indicate that it is no longer valid.
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
<Text color="theme.secondary" isStriked>
|
|
53
|
+
Some text here
|
|
54
|
+
</Text>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### **Subscript**
|
|
58
|
+
|
|
59
|
+
“**_isSub_**” makes text appears slightly below the baseline of the surrounding text.
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
<Text>
|
|
63
|
+
H<Text isSub>2</Text>0
|
|
64
|
+
</Text>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### **Superscript**
|
|
68
|
+
|
|
69
|
+
“isSup” makes text appears slightly above the surrounding text.
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
<Text>
|
|
73
|
+
H<Text isSup>2</Text>0
|
|
74
|
+
</Text>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### **Weights**
|
|
78
|
+
|
|
79
|
+
“**_weight_**” changes the font weight of the text. It have a default value of “medium”.
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import { Vertical } from "../Layout/Vertical/Vertical";
|
|
83
|
+
|
|
84
|
+
<Vertical gap={5} alignItems="center">
|
|
85
|
+
{[
|
|
86
|
+
"hairline",
|
|
87
|
+
"thin",
|
|
88
|
+
"light",
|
|
89
|
+
"normal",
|
|
90
|
+
"medium",
|
|
91
|
+
"semiBold",
|
|
92
|
+
"bold",
|
|
93
|
+
"extraBold",
|
|
94
|
+
"black",
|
|
95
|
+
].map((weight, index) => (
|
|
96
|
+
<Text key={index} weight={weight}>
|
|
97
|
+
{weight}
|
|
98
|
+
</Text>
|
|
99
|
+
))}
|
|
100
|
+
</Vertical>;
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### **Truncate**
|
|
104
|
+
|
|
105
|
+
“**__**” removes a part of the text and add an ellipsis to the end.
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
import { Center } from "app-studio";
|
|
109
|
+
|
|
110
|
+
<Center>
|
|
111
|
+
<Text maxLines={3} width="200px" >
|
|
112
|
+
Pellentesque habitant morbi tristique senectus et netus et malesuada fames
|
|
113
|
+
ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget,
|
|
114
|
+
tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean
|
|
115
|
+
ultricies mi vitae est.
|
|
116
|
+
</Text>
|
|
117
|
+
</Center>;
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### **Italic**
|
|
121
|
+
|
|
122
|
+
“**_isItalic_**” styles the text in italic.
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
<Text isItalic>Some text here</Text>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### **Underline**
|
|
129
|
+
|
|
130
|
+
“**_isUnderlined_**” underlines the text.
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
<Text isUnderlined>Some text here</Text>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## **Types**
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
export type Sizes =
|
|
140
|
+
| "xs"
|
|
141
|
+
| "sm"
|
|
142
|
+
| "md"
|
|
143
|
+
| "lg"
|
|
144
|
+
| "xl"
|
|
145
|
+
| "xl"
|
|
146
|
+
| "xl"
|
|
147
|
+
| "xl"
|
|
148
|
+
| "xl"
|
|
149
|
+
| "6xl";
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
type TextWeights =
|
|
154
|
+
| "hairline"
|
|
155
|
+
| "thin"
|
|
156
|
+
| "light"
|
|
157
|
+
| "normal"
|
|
158
|
+
| "medium"
|
|
159
|
+
| "semibold"
|
|
160
|
+
| "bold"
|
|
161
|
+
| "extrabold"
|
|
162
|
+
| "black";
|
|
163
|
+
```
|