@adlas/create-app 1.0.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/README.md +476 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +39 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/figma.d.ts +16 -0
- package/dist/commands/figma.d.ts.map +1 -0
- package/dist/commands/figma.js +172 -0
- package/dist/commands/figma.js.map +1 -0
- package/dist/commands/index.d.ts +5 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +5 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +1471 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/swagger.d.ts +16 -0
- package/dist/commands/swagger.d.ts.map +1 -0
- package/dist/commands/swagger.js +404 -0
- package/dist/commands/swagger.js.map +1 -0
- package/dist/commands/update.d.ts +15 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +93 -0
- package/dist/commands/update.js.map +1 -0
- package/package.json +63 -0
- package/templates/.vscode/extensions.json +9 -0
- package/templates/.vscode/launch.json +26 -0
- package/templates/.vscode/settings.json +67 -0
- package/templates/.vscode/tasks.json +21 -0
- package/templates/boilerplate/config/fonts.ts +10 -0
- package/templates/boilerplate/config/navigationUrls.ts +47 -0
- package/templates/boilerplate/config/site.ts +96 -0
- package/templates/boilerplate/libs/I18n.ts +15 -0
- package/templates/boilerplate/libs/I18nNavigation.ts +5 -0
- package/templates/boilerplate/libs/I18nRouting.ts +9 -0
- package/templates/boilerplate/libs/env.ts +21 -0
- package/templates/boilerplate/libs/react-query/ReactQueryProvider.tsx +21 -0
- package/templates/boilerplate/libs/react-query/index.ts +2 -0
- package/templates/boilerplate/libs/react-query/queryClient.ts +62 -0
- package/templates/boilerplate/libs/react-query/queryKeys.ts +5 -0
- package/templates/boilerplate/public/images/index.ts +1 -0
- package/templates/boilerplate/reset.d.ts +2 -0
- package/templates/boilerplate/styles/globals.css +308 -0
- package/templates/boilerplate/types/i18n.ts +10 -0
- package/templates/boilerplate/types/locale.ts +8 -0
- package/templates/boilerplate/utils/file/fileConfig.ts +123 -0
- package/templates/boilerplate/utils/file/fileValidation.ts +78 -0
- package/templates/boilerplate/utils/file/imageCompression.ts +182 -0
- package/templates/boilerplate/utils/file/index.ts +3 -0
- package/templates/boilerplate/utils/helpers.ts +55 -0
- package/templates/boilerplate/validations/auth.validation.ts +92 -0
- package/templates/boilerplate/validations/commonValidations.ts +258 -0
- package/templates/boilerplate/validations/zodErrorMap.ts +101 -0
- package/templates/configs/.env.example +8 -0
- package/templates/configs/.prettierignore +23 -0
- package/templates/configs/.prettierrc.cjs +26 -0
- package/templates/configs/.prettierrc.icons.cjs +11 -0
- package/templates/configs/Dockerfile +6 -0
- package/templates/configs/commitlint.config.ts +8 -0
- package/templates/configs/eslint.config.mjs +119 -0
- package/templates/configs/knip.config.ts +32 -0
- package/templates/configs/lefthook.yml +42 -0
- package/templates/configs/lint-staged.config.js +8 -0
- package/templates/configs/next.config.template.ts +77 -0
- package/templates/configs/next.config.ts +43 -0
- package/templates/configs/package.json +75 -0
- package/templates/configs/postcss.config.mjs +15 -0
- package/templates/configs/svgr.config.mjs +129 -0
- package/templates/configs/tsconfig.json +75 -0
- package/templates/docs/AI_QUICK_REFERENCE.md +379 -0
- package/templates/docs/ARCHITECTURE_PATTERNS.md +927 -0
- package/templates/docs/DOCUMENTATION_INDEX.md +411 -0
- package/templates/docs/FIGMA_TO_CODE_GUIDE.md +768 -0
- package/templates/docs/IMPLEMENTATION_GUIDE.md +892 -0
- package/templates/docs/PROJECT_OVERVIEW.md +302 -0
- package/templates/docs/REFACTOR_PROGRESS.md +1113 -0
- package/templates/docs/SHADCN_TO_HEROUI_MIGRATION.md +1375 -0
- package/templates/docs/UI_COMPONENTS_GUIDE.md +893 -0
|
@@ -0,0 +1,893 @@
|
|
|
1
|
+
# UI Components Guide
|
|
2
|
+
|
|
3
|
+
Complete reference for all available UI components in the Berndorf e-commerce project. All components are based on **HeroUI** and extended for project-specific needs.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
1. [Form Components](#form-components)
|
|
8
|
+
2. [Display Components](#display-components)
|
|
9
|
+
3. [Form System](#form-system)
|
|
10
|
+
4. [Element Components](#element-components)
|
|
11
|
+
5. [Component Usage Patterns](#component-usage-patterns)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Form Components
|
|
16
|
+
|
|
17
|
+
### Input
|
|
18
|
+
|
|
19
|
+
Text input field with label placement outside by default.
|
|
20
|
+
|
|
21
|
+
**Location:** `/src/components/ui/Input.tsx`
|
|
22
|
+
|
|
23
|
+
**Props:**
|
|
24
|
+
- `label` - Field label (string)
|
|
25
|
+
- `placeholder` - Placeholder text (string)
|
|
26
|
+
- `isInvalid` - Invalid state (boolean)
|
|
27
|
+
- `errorMessage` - Error message (string)
|
|
28
|
+
- `isDisabled` - Disabled state (boolean)
|
|
29
|
+
- `value` - Input value (string)
|
|
30
|
+
- `onChange` - Change handler (function)
|
|
31
|
+
|
|
32
|
+
**Variants:**
|
|
33
|
+
- `variant`: `bordered` (default)
|
|
34
|
+
- `size`: `sm`, `md`, `lg` (default)
|
|
35
|
+
- `labelPlacement`: `outside` (default), `inside`
|
|
36
|
+
- `radius`: `none` (default), `sm`, `md`, `lg`, `full`
|
|
37
|
+
|
|
38
|
+
**Example:**
|
|
39
|
+
```tsx
|
|
40
|
+
import { Input } from '@/components/ui/Input';
|
|
41
|
+
|
|
42
|
+
<Input
|
|
43
|
+
label="Email Address"
|
|
44
|
+
placeholder="Enter your email"
|
|
45
|
+
type="email"
|
|
46
|
+
isRequired
|
|
47
|
+
/>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
### PasswordInput
|
|
53
|
+
|
|
54
|
+
Password field with show/hide toggle.
|
|
55
|
+
|
|
56
|
+
**Location:** `/src/components/ui/PasswordInput.tsx`
|
|
57
|
+
|
|
58
|
+
**Props:** Same as Input, plus:
|
|
59
|
+
- Automatically includes visibility toggle icon
|
|
60
|
+
|
|
61
|
+
**Example:**
|
|
62
|
+
```tsx
|
|
63
|
+
import { PasswordInput } from '@/components/ui/PasswordInput';
|
|
64
|
+
|
|
65
|
+
<PasswordInput
|
|
66
|
+
label="Password"
|
|
67
|
+
placeholder="Enter your password"
|
|
68
|
+
isRequired
|
|
69
|
+
/>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
### Textarea
|
|
75
|
+
|
|
76
|
+
Multi-line text input.
|
|
77
|
+
|
|
78
|
+
**Location:** `/src/components/ui/Textarea.tsx`
|
|
79
|
+
|
|
80
|
+
**Props:**
|
|
81
|
+
- All Input props, plus:
|
|
82
|
+
- `rows` - Number of rows (number)
|
|
83
|
+
- `minRows` - Minimum rows (number)
|
|
84
|
+
- `maxRows` - Maximum rows (number)
|
|
85
|
+
|
|
86
|
+
**Example:**
|
|
87
|
+
```tsx
|
|
88
|
+
import { Textarea } from '@/components/ui/Textarea';
|
|
89
|
+
|
|
90
|
+
<Textarea
|
|
91
|
+
label="Message"
|
|
92
|
+
placeholder="Enter your message"
|
|
93
|
+
minRows={3}
|
|
94
|
+
maxRows={10}
|
|
95
|
+
/>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
### Select
|
|
101
|
+
|
|
102
|
+
Dropdown selection component.
|
|
103
|
+
|
|
104
|
+
**Location:** `/src/components/ui/Select.tsx`
|
|
105
|
+
|
|
106
|
+
**Props:**
|
|
107
|
+
- `label` - Field label (string)
|
|
108
|
+
- `placeholder` - Placeholder text (string)
|
|
109
|
+
- `items` - Array of options (SelectItem[])
|
|
110
|
+
- `selectedKey` - Selected value (string)
|
|
111
|
+
- `onSelectionChange` - Selection change handler (function)
|
|
112
|
+
|
|
113
|
+
**Example:**
|
|
114
|
+
```tsx
|
|
115
|
+
import { Select, SelectItem } from '@/components/ui/Select';
|
|
116
|
+
|
|
117
|
+
const options = [
|
|
118
|
+
{ key: 'option1', label: 'Option 1' },
|
|
119
|
+
{ key: 'option2', label: 'Option 2' },
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
<Select
|
|
123
|
+
label="Choose option"
|
|
124
|
+
placeholder="Select an option"
|
|
125
|
+
>
|
|
126
|
+
{options.map((option) => (
|
|
127
|
+
<SelectItem key={option.key}>{option.label}</SelectItem>
|
|
128
|
+
))}
|
|
129
|
+
</Select>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
### Autocomplete
|
|
135
|
+
|
|
136
|
+
Searchable dropdown with filtering.
|
|
137
|
+
|
|
138
|
+
**Location:** `/src/components/ui/Autocomplete.tsx`
|
|
139
|
+
|
|
140
|
+
**Props:**
|
|
141
|
+
- `label` - Field label (string)
|
|
142
|
+
- `placeholder` - Placeholder text (string)
|
|
143
|
+
- `items` - Array of options (AutocompleteItem[])
|
|
144
|
+
- `onSelectionChange` - Selection change handler (function)
|
|
145
|
+
|
|
146
|
+
**Example:**
|
|
147
|
+
```tsx
|
|
148
|
+
import { Autocomplete, AutocompleteItem } from '@/components/ui/Autocomplete';
|
|
149
|
+
|
|
150
|
+
const items = [
|
|
151
|
+
{ id: '1', label: 'Apple' },
|
|
152
|
+
{ id: '2', label: 'Banana' },
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
<Autocomplete
|
|
156
|
+
label="Search fruits"
|
|
157
|
+
placeholder="Type to search"
|
|
158
|
+
items={items}
|
|
159
|
+
>
|
|
160
|
+
{(item) => <AutocompleteItem key={item.id}>{item.label}</AutocompleteItem>}
|
|
161
|
+
</Autocomplete>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
### Checkbox
|
|
167
|
+
|
|
168
|
+
Single checkbox component.
|
|
169
|
+
|
|
170
|
+
**Location:** `/src/components/ui/Checkbox.tsx`
|
|
171
|
+
|
|
172
|
+
**Props:**
|
|
173
|
+
- `children` - Checkbox label (ReactNode)
|
|
174
|
+
- `isSelected` - Checked state (boolean)
|
|
175
|
+
- `onValueChange` - Change handler (function)
|
|
176
|
+
- `isDisabled` - Disabled state (boolean)
|
|
177
|
+
|
|
178
|
+
**Example:**
|
|
179
|
+
```tsx
|
|
180
|
+
import { Checkbox } from '@/components/ui/Checkbox';
|
|
181
|
+
|
|
182
|
+
<Checkbox isSelected={agreed} onValueChange={setAgreed}>
|
|
183
|
+
I agree to the terms and conditions
|
|
184
|
+
</Checkbox>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### RadioGroup
|
|
190
|
+
|
|
191
|
+
Radio button group.
|
|
192
|
+
|
|
193
|
+
**Location:** `/src/components/ui/RadioGroup.tsx`
|
|
194
|
+
|
|
195
|
+
**Props:**
|
|
196
|
+
- `label` - Group label (string)
|
|
197
|
+
- `value` - Selected value (string)
|
|
198
|
+
- `onValueChange` - Change handler (function)
|
|
199
|
+
- `children` - Radio buttons (RadioButton components)
|
|
200
|
+
|
|
201
|
+
**Example:**
|
|
202
|
+
```tsx
|
|
203
|
+
import { RadioGroup, Radio } from '@/components/ui/RadioGroup';
|
|
204
|
+
|
|
205
|
+
<RadioGroup
|
|
206
|
+
label="Select delivery method"
|
|
207
|
+
value={deliveryMethod}
|
|
208
|
+
onValueChange={setDeliveryMethod}
|
|
209
|
+
>
|
|
210
|
+
<Radio value="standard">Standard Delivery</Radio>
|
|
211
|
+
<Radio value="express">Express Delivery</Radio>
|
|
212
|
+
</RadioGroup>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
### NumberInput
|
|
218
|
+
|
|
219
|
+
Numeric input with increment/decrement buttons.
|
|
220
|
+
|
|
221
|
+
**Location:** `/src/components/ui/NumberInput.tsx`
|
|
222
|
+
|
|
223
|
+
**Props:**
|
|
224
|
+
- `label` - Field label (string)
|
|
225
|
+
- `value` - Numeric value (number)
|
|
226
|
+
- `onChange` - Change handler (function)
|
|
227
|
+
- `min` - Minimum value (number)
|
|
228
|
+
- `max` - Maximum value (number)
|
|
229
|
+
- `step` - Increment step (number)
|
|
230
|
+
|
|
231
|
+
**Example:**
|
|
232
|
+
```tsx
|
|
233
|
+
import { NumberInput } from '@/components/ui/NumberInput';
|
|
234
|
+
|
|
235
|
+
<NumberInput
|
|
236
|
+
label="Quantity"
|
|
237
|
+
value={quantity}
|
|
238
|
+
onChange={setQuantity}
|
|
239
|
+
min={1}
|
|
240
|
+
max={100}
|
|
241
|
+
step={1}
|
|
242
|
+
/>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
### FileInput
|
|
248
|
+
|
|
249
|
+
File upload input.
|
|
250
|
+
|
|
251
|
+
**Location:** `/src/components/ui/FileInput.tsx`
|
|
252
|
+
|
|
253
|
+
**Props:**
|
|
254
|
+
- `label` - Field label (string)
|
|
255
|
+
- `accept` - Accepted file types (string)
|
|
256
|
+
- `onChange` - Change handler (function)
|
|
257
|
+
- `multiple` - Allow multiple files (boolean)
|
|
258
|
+
|
|
259
|
+
**Example:**
|
|
260
|
+
```tsx
|
|
261
|
+
import { FileInput } from '@/components/ui/FileInput';
|
|
262
|
+
|
|
263
|
+
<FileInput
|
|
264
|
+
label="Upload document"
|
|
265
|
+
accept=".pdf,.doc,.docx"
|
|
266
|
+
onChange={handleFileChange}
|
|
267
|
+
/>
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
### DocumentUpload
|
|
273
|
+
|
|
274
|
+
Advanced document upload with validation.
|
|
275
|
+
|
|
276
|
+
**Location:** `/src/components/ui/DocumentUpload.tsx`
|
|
277
|
+
|
|
278
|
+
**Props:**
|
|
279
|
+
- `label` - Field label (string)
|
|
280
|
+
- `accept` - Accepted file types (string)
|
|
281
|
+
- `maxSize` - Maximum file size in bytes (number)
|
|
282
|
+
- `onUpload` - Upload handler (function)
|
|
283
|
+
|
|
284
|
+
**Example:**
|
|
285
|
+
```tsx
|
|
286
|
+
import { DocumentUpload } from '@/components/ui/DocumentUpload';
|
|
287
|
+
|
|
288
|
+
<DocumentUpload
|
|
289
|
+
label="Upload PDF"
|
|
290
|
+
accept=".pdf"
|
|
291
|
+
maxSize={5 * 1024 * 1024} // 5MB
|
|
292
|
+
onUpload={handleUpload}
|
|
293
|
+
/>
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
### DatePicker
|
|
299
|
+
|
|
300
|
+
Date selection component.
|
|
301
|
+
|
|
302
|
+
**Location:** `/src/components/ui/DatePicker.tsx`
|
|
303
|
+
|
|
304
|
+
**Props:**
|
|
305
|
+
- `label` - Field label (string)
|
|
306
|
+
- `value` - Date value (DateValue)
|
|
307
|
+
- `onChange` - Change handler (function)
|
|
308
|
+
- `minValue` - Minimum date (DateValue)
|
|
309
|
+
- `maxValue` - Maximum date (DateValue)
|
|
310
|
+
|
|
311
|
+
**Example:**
|
|
312
|
+
```tsx
|
|
313
|
+
import { DatePicker } from '@/components/ui/DatePicker';
|
|
314
|
+
import { parseDate } from '@internationalized/date';
|
|
315
|
+
|
|
316
|
+
<DatePicker
|
|
317
|
+
label="Select date"
|
|
318
|
+
value={date}
|
|
319
|
+
onChange={setDate}
|
|
320
|
+
minValue={parseDate('2024-01-01')}
|
|
321
|
+
/>
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## Display Components
|
|
327
|
+
|
|
328
|
+
### Button
|
|
329
|
+
|
|
330
|
+
Action button with multiple variants.
|
|
331
|
+
|
|
332
|
+
**Location:** `/src/components/ui/Button.tsx`
|
|
333
|
+
|
|
334
|
+
**Props:**
|
|
335
|
+
- `children` - Button content (ReactNode)
|
|
336
|
+
- `onPress` - Click handler (function)
|
|
337
|
+
- `isDisabled` - Disabled state (boolean)
|
|
338
|
+
- `isLoading` - Loading state (boolean)
|
|
339
|
+
- `variant` - Visual variant (string)
|
|
340
|
+
- `color` - Color theme (string)
|
|
341
|
+
- `size` - Button size (string)
|
|
342
|
+
|
|
343
|
+
**Variants:**
|
|
344
|
+
- `variant`: `solid` (default), `bordered`, `light`, `flat`, `faded`, `shadow`, `ghost`, `primary`
|
|
345
|
+
- `color`: `primary` (default), `secondary`, `success`, `warning`, `danger`, `default`, `foreground`
|
|
346
|
+
- `size`: `sm`, `md` (default), `lg`
|
|
347
|
+
- `radius`: `none` (default), `sm`, `md`, `lg`, `full`
|
|
348
|
+
|
|
349
|
+
**Example:**
|
|
350
|
+
```tsx
|
|
351
|
+
import { Button } from '@/components/ui/Button';
|
|
352
|
+
|
|
353
|
+
// Primary solid button
|
|
354
|
+
<Button variant="solid" color="primary">
|
|
355
|
+
Submit
|
|
356
|
+
</Button>
|
|
357
|
+
|
|
358
|
+
// Bordered button
|
|
359
|
+
<Button variant="bordered">
|
|
360
|
+
Cancel
|
|
361
|
+
</Button>
|
|
362
|
+
|
|
363
|
+
// Light button with danger color
|
|
364
|
+
<Button variant="light" color="danger">
|
|
365
|
+
Delete
|
|
366
|
+
</Button>
|
|
367
|
+
|
|
368
|
+
// Loading state
|
|
369
|
+
<Button isLoading>
|
|
370
|
+
Processing...
|
|
371
|
+
</Button>
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
### Chip
|
|
377
|
+
|
|
378
|
+
Small badge or tag component.
|
|
379
|
+
|
|
380
|
+
**Location:** `/src/components/ui/Chip.tsx`
|
|
381
|
+
|
|
382
|
+
**Props:**
|
|
383
|
+
- `children` - Chip content (ReactNode)
|
|
384
|
+
- `variant` - Visual variant (string)
|
|
385
|
+
- `color` - Color theme (string)
|
|
386
|
+
- `size` - Chip size (string)
|
|
387
|
+
|
|
388
|
+
**Variants:**
|
|
389
|
+
- `variant`: `solid`, `bordered`, `flat`, `shadow`
|
|
390
|
+
- `color`: `primary`, `secondary`, `success`, `warning`, `danger`, `default`
|
|
391
|
+
- `size`: `sm`, `md`, `lg`
|
|
392
|
+
|
|
393
|
+
**Example:**
|
|
394
|
+
```tsx
|
|
395
|
+
import { Chip } from '@/components/ui/Chip';
|
|
396
|
+
|
|
397
|
+
<Chip color="success" variant="flat">
|
|
398
|
+
New
|
|
399
|
+
</Chip>
|
|
400
|
+
|
|
401
|
+
<Chip color="primary">
|
|
402
|
+
Featured
|
|
403
|
+
</Chip>
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
### Modal
|
|
409
|
+
|
|
410
|
+
Dialog/popup component.
|
|
411
|
+
|
|
412
|
+
**Location:** `/src/components/ui/Modal.tsx`
|
|
413
|
+
|
|
414
|
+
**Props:**
|
|
415
|
+
- `isOpen` - Modal open state (boolean)
|
|
416
|
+
- `onClose` - Close handler (function)
|
|
417
|
+
- `title` - Modal title (string)
|
|
418
|
+
- `children` - Modal content (ReactNode)
|
|
419
|
+
- `size` - Modal size (string)
|
|
420
|
+
|
|
421
|
+
**Sizes:**
|
|
422
|
+
- `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `4xl`, `5xl`, `full`
|
|
423
|
+
|
|
424
|
+
**Example:**
|
|
425
|
+
```tsx
|
|
426
|
+
import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@/components/ui/Modal';
|
|
427
|
+
import { Button } from '@/components/ui/Button';
|
|
428
|
+
|
|
429
|
+
<Modal isOpen={isOpen} onClose={onClose} size="lg">
|
|
430
|
+
<ModalContent>
|
|
431
|
+
<ModalHeader>
|
|
432
|
+
<h2>Confirm Action</h2>
|
|
433
|
+
</ModalHeader>
|
|
434
|
+
<ModalBody>
|
|
435
|
+
<p>Are you sure you want to proceed?</p>
|
|
436
|
+
</ModalBody>
|
|
437
|
+
<ModalFooter>
|
|
438
|
+
<Button variant="light" onPress={onClose}>
|
|
439
|
+
Cancel
|
|
440
|
+
</Button>
|
|
441
|
+
<Button color="primary" onPress={handleConfirm}>
|
|
442
|
+
Confirm
|
|
443
|
+
</Button>
|
|
444
|
+
</ModalFooter>
|
|
445
|
+
</ModalContent>
|
|
446
|
+
</Modal>
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
### Tabs
|
|
452
|
+
|
|
453
|
+
Tab navigation component.
|
|
454
|
+
|
|
455
|
+
**Location:** `/src/components/ui/Tabs.tsx`
|
|
456
|
+
|
|
457
|
+
**Props:**
|
|
458
|
+
- `selectedKey` - Active tab key (string)
|
|
459
|
+
- `onSelectionChange` - Tab change handler (function)
|
|
460
|
+
- `children` - Tab items (TabItem components)
|
|
461
|
+
|
|
462
|
+
**Example:**
|
|
463
|
+
```tsx
|
|
464
|
+
import { Tabs, Tab } from '@/components/ui/Tabs';
|
|
465
|
+
|
|
466
|
+
<Tabs selectedKey={activeTab} onSelectionChange={setActiveTab}>
|
|
467
|
+
<Tab key="details" title="Details">
|
|
468
|
+
<div>Details content</div>
|
|
469
|
+
</Tab>
|
|
470
|
+
<Tab key="specs" title="Specifications">
|
|
471
|
+
<div>Specifications content</div>
|
|
472
|
+
</Tab>
|
|
473
|
+
</Tabs>
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
---
|
|
477
|
+
|
|
478
|
+
### Breadcrumbs
|
|
479
|
+
|
|
480
|
+
Breadcrumb navigation.
|
|
481
|
+
|
|
482
|
+
**Location:** `/src/components/ui/Breadcrumbs.tsx`
|
|
483
|
+
|
|
484
|
+
**Props:**
|
|
485
|
+
- `items` - Breadcrumb items (BreadcrumbItem[])
|
|
486
|
+
|
|
487
|
+
**Example:**
|
|
488
|
+
```tsx
|
|
489
|
+
import { Breadcrumbs, BreadcrumbItem } from '@/components/ui/Breadcrumbs';
|
|
490
|
+
|
|
491
|
+
<Breadcrumbs>
|
|
492
|
+
<BreadcrumbItem href="/">Home</BreadcrumbItem>
|
|
493
|
+
<BreadcrumbItem href="/products">Products</BreadcrumbItem>
|
|
494
|
+
<BreadcrumbItem>Current Page</BreadcrumbItem>
|
|
495
|
+
</Breadcrumbs>
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
### Carousel
|
|
501
|
+
|
|
502
|
+
Image/content carousel.
|
|
503
|
+
|
|
504
|
+
**Location:** `/src/components/ui/Carousel.tsx`
|
|
505
|
+
|
|
506
|
+
**Props:**
|
|
507
|
+
- `items` - Carousel items (array)
|
|
508
|
+
- `autoplay` - Auto-play slides (boolean)
|
|
509
|
+
- `interval` - Auto-play interval in ms (number)
|
|
510
|
+
|
|
511
|
+
**Example:**
|
|
512
|
+
```tsx
|
|
513
|
+
import { Carousel } from '@/components/ui/Carousel';
|
|
514
|
+
|
|
515
|
+
const slides = [
|
|
516
|
+
{ id: 1, image: '/slide1.jpg', title: 'Slide 1' },
|
|
517
|
+
{ id: 2, image: '/slide2.jpg', title: 'Slide 2' },
|
|
518
|
+
];
|
|
519
|
+
|
|
520
|
+
<Carousel items={slides} autoplay interval={5000} />
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
---
|
|
524
|
+
|
|
525
|
+
### Icon
|
|
526
|
+
|
|
527
|
+
Icon component.
|
|
528
|
+
|
|
529
|
+
**Location:** `/src/components/ui/Icon.tsx`
|
|
530
|
+
|
|
531
|
+
**Props:**
|
|
532
|
+
- `name` - Icon name (string)
|
|
533
|
+
- `size` - Icon size (number or string)
|
|
534
|
+
- `color` - Icon color (string)
|
|
535
|
+
|
|
536
|
+
**Example:**
|
|
537
|
+
```tsx
|
|
538
|
+
import { Icon } from '@/components/ui/Icon';
|
|
539
|
+
|
|
540
|
+
<Icon name="heart" size={24} color="primary" />
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
---
|
|
544
|
+
|
|
545
|
+
## Form System
|
|
546
|
+
|
|
547
|
+
### Form
|
|
548
|
+
|
|
549
|
+
Form wrapper with validation support.
|
|
550
|
+
|
|
551
|
+
**Location:** `/src/components/ui/form/Form.tsx`
|
|
552
|
+
|
|
553
|
+
**Props:**
|
|
554
|
+
- `form` - react-hook-form instance (UseFormReturn)
|
|
555
|
+
- `validationSchema` - Zod validation schema (ZodSchema)
|
|
556
|
+
- `children` - Form fields (ReactNode)
|
|
557
|
+
- `className` - Additional classes (string)
|
|
558
|
+
|
|
559
|
+
**Example:**
|
|
560
|
+
```tsx
|
|
561
|
+
import { Form } from '@/components/ui/form/Form';
|
|
562
|
+
import { useForm } from 'react-hook-form';
|
|
563
|
+
import { z } from 'zod';
|
|
564
|
+
|
|
565
|
+
const schema = z.object({
|
|
566
|
+
email: z.string().email(),
|
|
567
|
+
password: z.string().min(8),
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
type FormData = z.infer<typeof schema>;
|
|
571
|
+
|
|
572
|
+
function MyForm() {
|
|
573
|
+
const form = useForm<FormData>();
|
|
574
|
+
|
|
575
|
+
return (
|
|
576
|
+
<Form form={form} validationSchema={schema}>
|
|
577
|
+
{/* Form fields */}
|
|
578
|
+
</Form>
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
---
|
|
584
|
+
|
|
585
|
+
### FormItem
|
|
586
|
+
|
|
587
|
+
Individual form field wrapper with error handling.
|
|
588
|
+
|
|
589
|
+
**Location:** `/src/components/ui/form/Form.tsx`
|
|
590
|
+
|
|
591
|
+
**Props:**
|
|
592
|
+
- `name` - Field name (string, must match schema)
|
|
593
|
+
- `children` - Render function for input component (function)
|
|
594
|
+
- `rowsNumber` - Grid column span (1 or 2)
|
|
595
|
+
- `extraLabel` - Additional label above field (string)
|
|
596
|
+
|
|
597
|
+
**Example:**
|
|
598
|
+
```tsx
|
|
599
|
+
import { Form } from '@/components/ui/form/Form';
|
|
600
|
+
import { Input } from '@/components/ui/Input';
|
|
601
|
+
|
|
602
|
+
<Form.Item name="email">
|
|
603
|
+
{(props) => <Input {...props} label="Email Address" type="email" />}
|
|
604
|
+
</Form.Item>
|
|
605
|
+
|
|
606
|
+
<Form.Item name="description" rowsNumber={1}>
|
|
607
|
+
{(props) => <Textarea {...props} label="Description" />}
|
|
608
|
+
</Form.Item>
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
---
|
|
612
|
+
|
|
613
|
+
### FormGenerator
|
|
614
|
+
|
|
615
|
+
Dynamic form generation from schema.
|
|
616
|
+
|
|
617
|
+
**Location:** `/src/components/ui/form/FormGenerator.tsx`
|
|
618
|
+
|
|
619
|
+
**Props:**
|
|
620
|
+
- `schema` - Form schema definition (object)
|
|
621
|
+
- `onSubmit` - Form submit handler (function)
|
|
622
|
+
|
|
623
|
+
**Example:**
|
|
624
|
+
```tsx
|
|
625
|
+
import { FormGenerator } from '@/components/ui/form/FormGenerator';
|
|
626
|
+
|
|
627
|
+
const formSchema = {
|
|
628
|
+
fields: [
|
|
629
|
+
{ name: 'email', type: 'email', label: 'Email' },
|
|
630
|
+
{ name: 'password', type: 'password', label: 'Password' },
|
|
631
|
+
],
|
|
632
|
+
};
|
|
633
|
+
|
|
634
|
+
<FormGenerator schema={formSchema} onSubmit={handleSubmit} />
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
---
|
|
638
|
+
|
|
639
|
+
## Element Components
|
|
640
|
+
|
|
641
|
+
Higher-level composite components built from UI components.
|
|
642
|
+
|
|
643
|
+
### ProductCard
|
|
644
|
+
|
|
645
|
+
Product display card.
|
|
646
|
+
|
|
647
|
+
**Location:** `/src/components/elements/ProductCard.tsx`
|
|
648
|
+
|
|
649
|
+
**Usage:**
|
|
650
|
+
```tsx
|
|
651
|
+
import { ProductCard } from '@/components/elements/ProductCard';
|
|
652
|
+
|
|
653
|
+
<ProductCard
|
|
654
|
+
id={product.id}
|
|
655
|
+
name={product.name}
|
|
656
|
+
price={product.price}
|
|
657
|
+
image={product.image}
|
|
658
|
+
onAddToCart={handleAddToCart}
|
|
659
|
+
/>
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
---
|
|
663
|
+
|
|
664
|
+
### NewsCard
|
|
665
|
+
|
|
666
|
+
News article card.
|
|
667
|
+
|
|
668
|
+
**Location:** `/src/components/elements/NewsCard.tsx`
|
|
669
|
+
|
|
670
|
+
**Usage:**
|
|
671
|
+
```tsx
|
|
672
|
+
import { NewsCard } from '@/components/elements/NewsCard';
|
|
673
|
+
|
|
674
|
+
<NewsCard
|
|
675
|
+
title={news.title}
|
|
676
|
+
excerpt={news.excerpt}
|
|
677
|
+
image={news.image}
|
|
678
|
+
date={news.date}
|
|
679
|
+
href={`/news/${news.slug}`}
|
|
680
|
+
/>
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
---
|
|
684
|
+
|
|
685
|
+
### CollectionCard
|
|
686
|
+
|
|
687
|
+
Collection display card.
|
|
688
|
+
|
|
689
|
+
**Location:** `/src/components/elements/CollectionCard.tsx`
|
|
690
|
+
|
|
691
|
+
**Usage:**
|
|
692
|
+
```tsx
|
|
693
|
+
import { CollectionCard } from '@/components/elements/CollectionCard';
|
|
694
|
+
|
|
695
|
+
<CollectionCard
|
|
696
|
+
name={collection.name}
|
|
697
|
+
image={collection.image}
|
|
698
|
+
itemCount={collection.itemCount}
|
|
699
|
+
href={`/collections/${collection.slug}`}
|
|
700
|
+
/>
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
---
|
|
704
|
+
|
|
705
|
+
### Gallery
|
|
706
|
+
|
|
707
|
+
Image gallery component.
|
|
708
|
+
|
|
709
|
+
**Location:** `/src/components/elements/Gallery.tsx`
|
|
710
|
+
|
|
711
|
+
**Usage:**
|
|
712
|
+
```tsx
|
|
713
|
+
import { Gallery } from '@/components/elements/Gallery';
|
|
714
|
+
|
|
715
|
+
<Gallery
|
|
716
|
+
images={product.images}
|
|
717
|
+
title={product.name}
|
|
718
|
+
/>
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
---
|
|
722
|
+
|
|
723
|
+
### EmptyState
|
|
724
|
+
|
|
725
|
+
Empty state placeholder.
|
|
726
|
+
|
|
727
|
+
**Location:** `/src/components/elements/EmptyState.tsx`
|
|
728
|
+
|
|
729
|
+
**Usage:**
|
|
730
|
+
```tsx
|
|
731
|
+
import { EmptyState } from '@/components/elements/EmptyState';
|
|
732
|
+
|
|
733
|
+
<EmptyState
|
|
734
|
+
title="No items found"
|
|
735
|
+
description="Try adjusting your filters"
|
|
736
|
+
icon="search"
|
|
737
|
+
/>
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
---
|
|
741
|
+
|
|
742
|
+
### ContactCard
|
|
743
|
+
|
|
744
|
+
Contact information card.
|
|
745
|
+
|
|
746
|
+
**Location:** `/src/components/elements/ContactCard.tsx`
|
|
747
|
+
|
|
748
|
+
**Usage:**
|
|
749
|
+
```tsx
|
|
750
|
+
import { ContactCard } from '@/components/elements/ContactCard';
|
|
751
|
+
|
|
752
|
+
<ContactCard
|
|
753
|
+
name="Support"
|
|
754
|
+
email="support@example.com"
|
|
755
|
+
phone="+43 123 456 789"
|
|
756
|
+
/>
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
---
|
|
760
|
+
|
|
761
|
+
### StoreCard
|
|
762
|
+
|
|
763
|
+
Store location card.
|
|
764
|
+
|
|
765
|
+
**Location:** `/src/components/elements/StoreCard.tsx`
|
|
766
|
+
|
|
767
|
+
**Usage:**
|
|
768
|
+
```tsx
|
|
769
|
+
import { StoreCard } from '@/components/elements/StoreCard';
|
|
770
|
+
|
|
771
|
+
<StoreCard
|
|
772
|
+
name={store.name}
|
|
773
|
+
address={store.address}
|
|
774
|
+
phone={store.phone}
|
|
775
|
+
hours={store.hours}
|
|
776
|
+
/>
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
---
|
|
780
|
+
|
|
781
|
+
### HeaderBanner
|
|
782
|
+
|
|
783
|
+
Page header banner.
|
|
784
|
+
|
|
785
|
+
**Location:** `/src/components/elements/HeaderBanner.tsx`
|
|
786
|
+
|
|
787
|
+
**Usage:**
|
|
788
|
+
```tsx
|
|
789
|
+
import { HeaderBanner } from '@/components/elements/HeaderBanner';
|
|
790
|
+
|
|
791
|
+
<HeaderBanner
|
|
792
|
+
title="Our Products"
|
|
793
|
+
description="Explore our premium cutlery collection"
|
|
794
|
+
image="/banners/products.jpg"
|
|
795
|
+
/>
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
---
|
|
799
|
+
|
|
800
|
+
## Component Usage Patterns
|
|
801
|
+
|
|
802
|
+
### 1. Form Field with Validation
|
|
803
|
+
|
|
804
|
+
```tsx
|
|
805
|
+
<Form.Item name="email">
|
|
806
|
+
{(props) => (
|
|
807
|
+
<Input
|
|
808
|
+
{...props}
|
|
809
|
+
label="Email Address"
|
|
810
|
+
type="email"
|
|
811
|
+
placeholder="your@email.com"
|
|
812
|
+
isRequired
|
|
813
|
+
/>
|
|
814
|
+
)}
|
|
815
|
+
</Form.Item>
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
### 2. Conditional Button State
|
|
819
|
+
|
|
820
|
+
```tsx
|
|
821
|
+
<Button
|
|
822
|
+
variant="solid"
|
|
823
|
+
color="primary"
|
|
824
|
+
isLoading={isSubmitting}
|
|
825
|
+
isDisabled={!isValid}
|
|
826
|
+
onPress={handleSubmit}
|
|
827
|
+
>
|
|
828
|
+
{isSubmitting ? 'Submitting...' : 'Submit'}
|
|
829
|
+
</Button>
|
|
830
|
+
```
|
|
831
|
+
|
|
832
|
+
### 3. Modal with Form
|
|
833
|
+
|
|
834
|
+
```tsx
|
|
835
|
+
<Modal isOpen={isOpen} onClose={onClose}>
|
|
836
|
+
<ModalContent>
|
|
837
|
+
<ModalHeader>Add New Item</ModalHeader>
|
|
838
|
+
<ModalBody>
|
|
839
|
+
<Form form={form} validationSchema={schema}>
|
|
840
|
+
<Form.Item name="name">
|
|
841
|
+
{(props) => <Input {...props} label="Name" />}
|
|
842
|
+
</Form.Item>
|
|
843
|
+
</Form>
|
|
844
|
+
</ModalBody>
|
|
845
|
+
<ModalFooter>
|
|
846
|
+
<Button variant="light" onPress={onClose}>Cancel</Button>
|
|
847
|
+
<Button onPress={form.handleSubmit(onSubmit)}>Save</Button>
|
|
848
|
+
</ModalFooter>
|
|
849
|
+
</ModalContent>
|
|
850
|
+
</Modal>
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
### 4. Responsive Grid Layout
|
|
854
|
+
|
|
855
|
+
```tsx
|
|
856
|
+
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
|
|
857
|
+
{products.map((product) => (
|
|
858
|
+
<ProductCard key={product.id} {...product} />
|
|
859
|
+
))}
|
|
860
|
+
</div>
|
|
861
|
+
```
|
|
862
|
+
|
|
863
|
+
### 5. Loading State
|
|
864
|
+
|
|
865
|
+
```tsx
|
|
866
|
+
{isLoading ? (
|
|
867
|
+
<div className="flex justify-center items-center h-64">
|
|
868
|
+
<Spinner size="lg" />
|
|
869
|
+
</div>
|
|
870
|
+
) : (
|
|
871
|
+
<div>{/* Content */}</div>
|
|
872
|
+
)}
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
---
|
|
876
|
+
|
|
877
|
+
## Best Practices
|
|
878
|
+
|
|
879
|
+
1. **Always use existing components** - Never create custom UI components if HeroUI provides them
|
|
880
|
+
2. **Spread props correctly** - Use `{...props}` in FormItem children for proper validation
|
|
881
|
+
3. **Type your forms** - Always infer form types from Zod schemas: `type FormData = z.infer<typeof schema>`
|
|
882
|
+
4. **Use translations** - Never hardcode text, always use `useTranslations()`
|
|
883
|
+
5. **Handle loading states** - Always show loading indicators for async operations
|
|
884
|
+
6. **Validate user input** - Use Zod schemas for all form validation
|
|
885
|
+
7. **Maintain consistency** - Use the same variants and sizes across similar components
|
|
886
|
+
8. **Test responsiveness** - Ensure components work on all screen sizes
|
|
887
|
+
|
|
888
|
+
## Need More Information?
|
|
889
|
+
|
|
890
|
+
- **Quick Reference** → See `AI_QUICK_REFERENCE.md`
|
|
891
|
+
- **Architecture Patterns** → See `ARCHITECTURE_PATTERNS.md`
|
|
892
|
+
- **Implementation Guide** → See `IMPLEMENTATION_GUIDE.md`
|
|
893
|
+
- **Figma to Code** → See `FIGMA_TO_CODE_GUIDE.md`
|