xertica-ui 2.1.2 → 2.1.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.
Files changed (181) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +1 -1
  3. package/bin/cli.ts +1 -1
  4. package/bin/generate-tokens.ts +13 -7
  5. package/components/assistant/xertica-assistant/index.ts +2 -0
  6. package/components/assistant/xertica-assistant/parts/AssistantCollapsedView.tsx +97 -0
  7. package/components/assistant/xertica-assistant/parts/AssistantConversationList.tsx +104 -0
  8. package/components/assistant/xertica-assistant/parts/AssistantDocumentEditor.tsx +81 -0
  9. package/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.tsx +86 -0
  10. package/components/assistant/xertica-assistant/parts/AssistantHeader.tsx +77 -0
  11. package/components/assistant/xertica-assistant/parts/AssistantMessageBubble.tsx +573 -0
  12. package/components/assistant/xertica-assistant/parts/AssistantTabBar.tsx +65 -0
  13. package/components/assistant/xertica-assistant/parts/AssistantTypingIndicator.tsx +41 -0
  14. package/components/assistant/xertica-assistant/parts/AssistantWelcomeScreen.tsx +98 -0
  15. package/components/assistant/xertica-assistant/parts/index.ts +16 -0
  16. package/components/assistant/xertica-assistant/types.ts +139 -0
  17. package/components/assistant/xertica-assistant/use-assistant.ts +559 -0
  18. package/components/assistant/xertica-assistant/xertica-assistant.stories.tsx +200 -0
  19. package/components/assistant/xertica-assistant/xertica-assistant.tsx +198 -1460
  20. package/components/brand/theme-toggle/ThemeToggle.tsx +8 -27
  21. package/components/hooks/index.ts +3 -0
  22. package/components/hooks/use-layout-shortcuts.ts +46 -0
  23. package/components/layout/sidebar/index.ts +2 -0
  24. package/components/layout/sidebar/sidebar.stories.tsx +160 -8
  25. package/components/layout/sidebar/sidebar.tsx +606 -497
  26. package/components/layout/sidebar/use-sidebar.ts +104 -0
  27. package/components/media/audio-player/AudioPlayer.tsx +131 -206
  28. package/components/media/audio-player/use-audio-player.ts +298 -0
  29. package/components/pages/home-page/HomePage.tsx +1 -1
  30. package/components/pages/template-content/TemplateContent.tsx +5 -5
  31. package/components/pages/template-page/TemplatePage.tsx +5 -5
  32. package/components/shared/CustomTooltipContent.tsx +52 -0
  33. package/components/shared/layout-constants.ts +1 -1
  34. package/components/ui/chart/chart.stories.tsx +966 -7
  35. package/components/ui/chart/chart.tsx +918 -45
  36. package/components/ui/file-upload/file-upload.stories.tsx +100 -0
  37. package/components/ui/file-upload/file-upload.tsx +14 -74
  38. package/components/ui/file-upload/index.ts +1 -0
  39. package/components/ui/file-upload/use-file-upload.ts +181 -0
  40. package/components/ui/pagination/index.ts +2 -0
  41. package/components/ui/pagination/pagination.stories.tsx +94 -0
  42. package/components/ui/pagination/use-pagination.ts +194 -0
  43. package/components/ui/rich-text-editor/index.ts +2 -0
  44. package/components/ui/rich-text-editor/rich-text-editor.stories.tsx +129 -1
  45. package/components/ui/rich-text-editor/rich-text-editor.tsx +86 -305
  46. package/components/ui/rich-text-editor/use-rich-text-editor.ts +439 -0
  47. package/components/ui/stepper/index.ts +3 -1
  48. package/components/ui/stepper/stepper.stories.tsx +116 -0
  49. package/components/ui/stepper/stepper.tsx +4 -4
  50. package/components/ui/stepper/use-stepper.ts +137 -0
  51. package/components/ui/tree-view/index.ts +4 -1
  52. package/components/ui/tree-view/tree-view.stories.tsx +110 -4
  53. package/components/ui/tree-view/tree-view.tsx +17 -125
  54. package/components/ui/tree-view/use-tree-view.ts +229 -0
  55. package/contexts/AssistenteContext.tsx +17 -54
  56. package/contexts/BrandColorsContext.tsx +6 -17
  57. package/contexts/LayoutContext.tsx +5 -31
  58. package/dist/AssistantChart-BAudAfne.cjs +3591 -0
  59. package/dist/AssistantChart-BP8upjMk.js +3565 -0
  60. package/dist/AudioPlayer-1ypwE2Wh.cjs +936 -0
  61. package/dist/AudioPlayer-DuKXrCfy.js +937 -0
  62. package/dist/CustomTooltipContent-DHjkY0ww.js +40 -0
  63. package/dist/CustomTooltipContent-c_K-DWRr.cjs +56 -0
  64. package/dist/LanguageContext-BwhwC3G2.js +657 -0
  65. package/dist/LanguageContext-DvUt5jBg.cjs +656 -0
  66. package/dist/LayoutContext-BDmcZfMH.cjs +84 -0
  67. package/dist/LayoutContext-dbQvdC4O.js +85 -0
  68. package/dist/ThemeContext-RTy1m2Uq.js +82 -0
  69. package/dist/ThemeContext-bSzuOit2.cjs +81 -0
  70. package/dist/VerifyEmailPage-C_ihbcth.js +2828 -0
  71. package/dist/VerifyEmailPage-Dt7zgA4w.cjs +2827 -0
  72. package/dist/XerticaProvider-CW9hpCdF.cjs +39 -0
  73. package/dist/XerticaProvider-siSt9uG2.js +40 -0
  74. package/dist/XerticaXLogo-D8jf0SNv.cjs +214 -0
  75. package/dist/XerticaXLogo-fAJMy3H4.js +215 -0
  76. package/dist/assistant.cjs.js +2 -1
  77. package/dist/assistant.es.js +3 -2
  78. package/dist/brand.cjs.js +2 -2
  79. package/dist/brand.es.js +2 -2
  80. package/dist/cli.js +14 -8
  81. package/dist/components/assistant/xertica-assistant/index.d.ts +2 -0
  82. package/dist/components/assistant/xertica-assistant/parts/AssistantCollapsedView.d.ts +13 -0
  83. package/dist/components/assistant/xertica-assistant/parts/AssistantConversationList.d.ts +16 -0
  84. package/dist/components/assistant/xertica-assistant/parts/AssistantDocumentEditor.d.ts +17 -0
  85. package/dist/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.d.ts +19 -0
  86. package/dist/components/assistant/xertica-assistant/parts/AssistantHeader.d.ts +11 -0
  87. package/dist/components/assistant/xertica-assistant/parts/AssistantMessageBubble.d.ts +29 -0
  88. package/dist/components/assistant/xertica-assistant/parts/AssistantTabBar.d.ts +13 -0
  89. package/dist/components/assistant/xertica-assistant/parts/AssistantTypingIndicator.d.ts +4 -0
  90. package/dist/components/assistant/xertica-assistant/parts/AssistantWelcomeScreen.d.ts +17 -0
  91. package/dist/components/assistant/xertica-assistant/parts/index.d.ts +16 -0
  92. package/dist/components/assistant/xertica-assistant/types.d.ts +106 -0
  93. package/dist/components/assistant/xertica-assistant/use-assistant.d.ts +125 -0
  94. package/dist/components/assistant/xertica-assistant/xertica-assistant.d.ts +8 -97
  95. package/dist/components/hooks/index.d.ts +3 -0
  96. package/dist/components/hooks/use-layout-shortcuts.d.ts +22 -0
  97. package/dist/components/layout/sidebar/index.d.ts +2 -0
  98. package/dist/components/layout/sidebar/sidebar.d.ts +80 -0
  99. package/dist/components/layout/sidebar/use-sidebar.d.ts +22 -0
  100. package/dist/components/media/audio-player/AudioPlayer.d.ts +4 -1
  101. package/dist/components/media/audio-player/use-audio-player.d.ts +72 -0
  102. package/dist/components/shared/CustomTooltipContent.d.ts +20 -0
  103. package/dist/components/shared/layout-constants.d.ts +1 -1
  104. package/dist/components/ui/alert/alert.d.ts +1 -1
  105. package/dist/components/ui/badge/badge.d.ts +1 -1
  106. package/dist/components/ui/button/button.d.ts +2 -2
  107. package/dist/components/ui/chart/chart.d.ts +162 -5
  108. package/dist/components/ui/file-upload/file-upload.d.ts +2 -0
  109. package/dist/components/ui/file-upload/index.d.ts +1 -0
  110. package/dist/components/ui/file-upload/use-file-upload.d.ts +49 -0
  111. package/dist/components/ui/pagination/index.d.ts +2 -0
  112. package/dist/components/ui/pagination/use-pagination.d.ts +78 -0
  113. package/dist/components/ui/rich-text-editor/index.d.ts +2 -0
  114. package/dist/components/ui/rich-text-editor/use-rich-text-editor.d.ts +107 -0
  115. package/dist/components/ui/stepper/index.d.ts +3 -1
  116. package/dist/components/ui/stepper/stepper.d.ts +2 -2
  117. package/dist/components/ui/stepper/use-stepper.d.ts +60 -0
  118. package/dist/components/ui/tree-view/index.d.ts +4 -1
  119. package/dist/components/ui/tree-view/tree-view.d.ts +4 -6
  120. package/dist/components/ui/tree-view/use-tree-view.d.ts +60 -0
  121. package/dist/contexts/AssistenteContext.d.ts +10 -49
  122. package/dist/hooks.cjs.js +30 -10
  123. package/dist/hooks.es.js +25 -4
  124. package/dist/index.cjs.js +20 -9
  125. package/dist/index.es.js +38 -27
  126. package/dist/layout.cjs.js +82 -1
  127. package/dist/layout.es.js +83 -2
  128. package/dist/media.cjs.js +1 -1
  129. package/dist/media.es.js +1 -1
  130. package/dist/pages.cjs.js +1 -1
  131. package/dist/pages.es.js +1 -1
  132. package/dist/rich-text-editor-BmsjY03B.js +2949 -0
  133. package/dist/rich-text-editor-GS2kpTAK.cjs +2966 -0
  134. package/dist/sidebar-CVUGHOS_.cjs +756 -0
  135. package/dist/sidebar-CmvwjnVb.js +757 -0
  136. package/dist/ui.cjs.js +12 -2
  137. package/dist/ui.es.js +24 -14
  138. package/dist/use-audio-player-Bkh23vQ3.js +177 -0
  139. package/dist/use-audio-player-Dn1NR9xN.cjs +176 -0
  140. package/dist/utils/color-utils.d.ts +51 -0
  141. package/dist/xertica-assistant-BMqdyRVi.js +2082 -0
  142. package/dist/xertica-assistant-Bj3vBCq_.cjs +2081 -0
  143. package/dist/xertica-ui.css +1 -1
  144. package/docs/ai-usage.md +28 -10
  145. package/docs/architecture-improvements.md +463 -0
  146. package/docs/architecture.md +77 -1
  147. package/docs/components/assistant-chart.md +1 -1
  148. package/docs/components/assistant.md +159 -0
  149. package/docs/components/audio-player.md +46 -0
  150. package/docs/components/branding.md +251 -0
  151. package/docs/components/chart.md +354 -39
  152. package/docs/components/code-block.md +108 -0
  153. package/docs/components/file-upload.md +119 -2
  154. package/docs/components/formatted-document.md +113 -0
  155. package/docs/components/hooks.md +430 -0
  156. package/docs/components/image-with-fallback.md +106 -0
  157. package/docs/components/map-layers.md +140 -0
  158. package/docs/components/modern-chat-input.md +163 -0
  159. package/docs/components/pages.md +351 -0
  160. package/docs/components/pagination.md +187 -0
  161. package/docs/components/rich-text-editor.md +164 -0
  162. package/docs/components/sidebar.md +153 -4
  163. package/docs/components/stepper.md +157 -12
  164. package/docs/components/tree-view.md +164 -6
  165. package/docs/doc-audit.md +223 -0
  166. package/docs/getting-started.md +155 -1
  167. package/docs/guidelines.md +14 -8
  168. package/docs/layout.md +2 -2
  169. package/docs/llms.md +29 -9
  170. package/docs/patterns/detail-page.md +276 -0
  171. package/docs/patterns/settings.md +346 -0
  172. package/docs/patterns/wizard.md +217 -0
  173. package/guidelines/Guidelines.md +5 -3
  174. package/llms.txt +1 -1
  175. package/package.json +10 -10
  176. package/styles/xertica/tokens.css +41 -12
  177. package/templates/CLAUDE.md +16 -6
  178. package/templates/guidelines/Guidelines.md +16 -4
  179. package/templates/package.json +3 -3
  180. package/templates/src/styles/xertica/tokens.css +39 -10
  181. package/utils/color-utils.ts +72 -0
@@ -0,0 +1,346 @@
1
+ # Pattern: Settings Page
2
+
3
+ A structured settings page with categorized sections, form fields, and save/cancel actions. Suitable for user preferences, application configuration, and account management.
4
+
5
+ ---
6
+
7
+ ## When to Use
8
+
9
+ Use the Settings pattern when:
10
+ - Users need to configure personal preferences (theme, language, notifications)
11
+ - Administrators need to manage application-level configuration
12
+ - Account management (profile, password, API keys) is required
13
+ - Settings are grouped into logical categories (General, Security, Notifications, etc.)
14
+
15
+ ---
16
+
17
+ ## Components Used
18
+
19
+ - [`PageHeader`](../components/page-header.md) — page title and breadcrumb
20
+ - [`Card`](../components/card.md) — settings section container
21
+ - [`Tabs`](../components/tabs.md) — category navigation (sidebar or top tabs)
22
+ - [`Form`](../components/form.md) + form elements — settings fields
23
+ - [`Switch`](../components/switch.md) — boolean toggles
24
+ - [`Select`](../components/select.md) — option dropdowns
25
+ - [`Input`](../components/input.md) — text settings
26
+ - [`Button`](../components/button.md) — Save and Cancel actions
27
+ - [`Separator`](../components/separator.md) — section dividers
28
+ - [`Sonner`](../components/sonner.md) — success/error toast after save
29
+
30
+ ---
31
+
32
+ ## Basic Structure
33
+
34
+ ```tsx
35
+ import {
36
+ Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,
37
+ Tabs, TabsContent, TabsList, TabsTrigger,
38
+ Button, Input, Label, Switch, Select, SelectContent, SelectItem,
39
+ SelectTrigger, SelectValue, Separator,
40
+ } from 'xertica-ui/ui';
41
+ import { PageHeader, PageHeaderHeading, PageHeaderDescription } from 'xertica-ui/ui';
42
+ import { toast } from 'sonner';
43
+
44
+ export function SettingsPage() {
45
+ return (
46
+ <div className="flex flex-col h-full overflow-hidden">
47
+ <PageHeader>
48
+ <div>
49
+ <PageHeaderHeading>Configurações</PageHeaderHeading>
50
+ <PageHeaderDescription>
51
+ Gerencie suas preferências e configurações da conta.
52
+ </PageHeaderDescription>
53
+ </div>
54
+ </PageHeader>
55
+
56
+ <div className="flex-1 overflow-y-auto p-6">
57
+ <Tabs defaultValue="general" className="space-y-6">
58
+ <TabsList>
59
+ <TabsTrigger value="general">Geral</TabsTrigger>
60
+ <TabsTrigger value="security">Segurança</TabsTrigger>
61
+ <TabsTrigger value="notifications">Notificações</TabsTrigger>
62
+ <TabsTrigger value="api">API Keys</TabsTrigger>
63
+ </TabsList>
64
+
65
+ <TabsContent value="general">
66
+ <GeneralSettings />
67
+ </TabsContent>
68
+
69
+ <TabsContent value="security">
70
+ <SecuritySettings />
71
+ </TabsContent>
72
+
73
+ <TabsContent value="notifications">
74
+ <NotificationSettings />
75
+ </TabsContent>
76
+
77
+ <TabsContent value="api">
78
+ <ApiKeySettings />
79
+ </TabsContent>
80
+ </Tabs>
81
+ </div>
82
+ </div>
83
+ );
84
+ }
85
+ ```
86
+
87
+ ---
88
+
89
+ ## General Settings Section
90
+
91
+ ```tsx
92
+ function GeneralSettings() {
93
+ const [name, setName] = useState('João Silva');
94
+ const [language, setLanguage] = useState('pt-BR');
95
+ const [theme, setTheme] = useState('system');
96
+
97
+ const handleSave = () => {
98
+ // persist settings
99
+ toast.success('Configurações salvas com sucesso.');
100
+ };
101
+
102
+ return (
103
+ <div className="space-y-6 max-w-2xl">
104
+ {/* Profile */}
105
+ <Card>
106
+ <CardHeader>
107
+ <CardTitle>Perfil</CardTitle>
108
+ <CardDescription>Informações básicas da sua conta.</CardDescription>
109
+ </CardHeader>
110
+ <CardContent className="space-y-4">
111
+ <div className="space-y-2">
112
+ <Label htmlFor="name">Nome completo</Label>
113
+ <Input
114
+ id="name"
115
+ value={name}
116
+ onChange={e => setName(e.target.value)}
117
+ />
118
+ </div>
119
+ </CardContent>
120
+ </Card>
121
+
122
+ {/* Preferences */}
123
+ <Card>
124
+ <CardHeader>
125
+ <CardTitle>Preferências</CardTitle>
126
+ <CardDescription>Idioma e aparência da interface.</CardDescription>
127
+ </CardHeader>
128
+ <CardContent className="space-y-4">
129
+ <div className="space-y-2">
130
+ <Label>Idioma</Label>
131
+ <Select value={language} onValueChange={setLanguage}>
132
+ <SelectTrigger>
133
+ <SelectValue />
134
+ </SelectTrigger>
135
+ <SelectContent>
136
+ <SelectItem value="pt-BR">Português (Brasil)</SelectItem>
137
+ <SelectItem value="en">English</SelectItem>
138
+ <SelectItem value="es">Español</SelectItem>
139
+ </SelectContent>
140
+ </Select>
141
+ </div>
142
+
143
+ <div className="space-y-2">
144
+ <Label>Tema</Label>
145
+ <Select value={theme} onValueChange={setTheme}>
146
+ <SelectTrigger>
147
+ <SelectValue />
148
+ </SelectTrigger>
149
+ <SelectContent>
150
+ <SelectItem value="light">Claro</SelectItem>
151
+ <SelectItem value="dark">Escuro</SelectItem>
152
+ <SelectItem value="system">Sistema</SelectItem>
153
+ </SelectContent>
154
+ </Select>
155
+ </div>
156
+ </CardContent>
157
+ <CardFooter className="flex justify-end gap-2">
158
+ <Button variant="outline">Cancelar</Button>
159
+ <Button onClick={handleSave}>Salvar alterações</Button>
160
+ </CardFooter>
161
+ </Card>
162
+ </div>
163
+ );
164
+ }
165
+ ```
166
+
167
+ ---
168
+
169
+ ## Notification Settings Section
170
+
171
+ ```tsx
172
+ function NotificationSettings() {
173
+ const [notifications, setNotifications] = useState({
174
+ email: true,
175
+ push: false,
176
+ weeklyReport: true,
177
+ securityAlerts: true,
178
+ });
179
+
180
+ const toggle = (key: keyof typeof notifications) => {
181
+ setNotifications(prev => ({ ...prev, [key]: !prev[key] }));
182
+ };
183
+
184
+ const items = [
185
+ { key: 'email', label: 'Notificações por e-mail', description: 'Receba atualizações no seu e-mail' },
186
+ { key: 'push', label: 'Notificações push', description: 'Notificações no navegador' },
187
+ { key: 'weeklyReport', label: 'Relatório semanal', description: 'Resumo de atividades toda segunda-feira' },
188
+ { key: 'securityAlerts', label: 'Alertas de segurança', description: 'Notificações sobre acessos suspeitos' },
189
+ ];
190
+
191
+ return (
192
+ <Card className="max-w-2xl">
193
+ <CardHeader>
194
+ <CardTitle>Notificações</CardTitle>
195
+ <CardDescription>Escolha quais notificações deseja receber.</CardDescription>
196
+ </CardHeader>
197
+ <CardContent className="space-y-0">
198
+ {items.map(({ key, label, description }, index) => (
199
+ <div key={key}>
200
+ <div className="flex items-center justify-between py-4">
201
+ <div className="space-y-0.5">
202
+ <Label className="text-base">{label}</Label>
203
+ <p className="text-sm text-muted-foreground">{description}</p>
204
+ </div>
205
+ <Switch
206
+ checked={notifications[key as keyof typeof notifications]}
207
+ onCheckedChange={() => toggle(key as keyof typeof notifications)}
208
+ />
209
+ </div>
210
+ {index < items.length - 1 && <Separator />}
211
+ </div>
212
+ ))}
213
+ </CardContent>
214
+ <CardFooter className="flex justify-end">
215
+ <Button onClick={() => toast.success('Preferências de notificação salvas.')}>
216
+ Salvar
217
+ </Button>
218
+ </CardFooter>
219
+ </Card>
220
+ );
221
+ }
222
+ ```
223
+
224
+ ---
225
+
226
+ ## Security Settings Section
227
+
228
+ ```tsx
229
+ function SecuritySettings() {
230
+ const [currentPassword, setCurrentPassword] = useState('');
231
+ const [newPassword, setNewPassword] = useState('');
232
+ const [confirmPassword, setConfirmPassword] = useState('');
233
+
234
+ const handleChangePassword = () => {
235
+ if (newPassword !== confirmPassword) {
236
+ toast.error('As senhas não coincidem.');
237
+ return;
238
+ }
239
+ // call API
240
+ toast.success('Senha alterada com sucesso.');
241
+ setCurrentPassword('');
242
+ setNewPassword('');
243
+ setConfirmPassword('');
244
+ };
245
+
246
+ return (
247
+ <Card className="max-w-2xl">
248
+ <CardHeader>
249
+ <CardTitle>Alterar Senha</CardTitle>
250
+ <CardDescription>Use uma senha forte com pelo menos 8 caracteres.</CardDescription>
251
+ </CardHeader>
252
+ <CardContent className="space-y-4">
253
+ <div className="space-y-2">
254
+ <Label htmlFor="current-password">Senha atual</Label>
255
+ <Input
256
+ id="current-password"
257
+ type="password"
258
+ value={currentPassword}
259
+ onChange={e => setCurrentPassword(e.target.value)}
260
+ />
261
+ </div>
262
+ <div className="space-y-2">
263
+ <Label htmlFor="new-password">Nova senha</Label>
264
+ <Input
265
+ id="new-password"
266
+ type="password"
267
+ value={newPassword}
268
+ onChange={e => setNewPassword(e.target.value)}
269
+ />
270
+ </div>
271
+ <div className="space-y-2">
272
+ <Label htmlFor="confirm-password">Confirmar nova senha</Label>
273
+ <Input
274
+ id="confirm-password"
275
+ type="password"
276
+ value={confirmPassword}
277
+ onChange={e => setConfirmPassword(e.target.value)}
278
+ />
279
+ </div>
280
+ </CardContent>
281
+ <CardFooter className="flex justify-end">
282
+ <Button onClick={handleChangePassword}>Alterar senha</Button>
283
+ </CardFooter>
284
+ </Card>
285
+ );
286
+ }
287
+ ```
288
+
289
+ ---
290
+
291
+ ## API Key Settings Section
292
+
293
+ ```tsx
294
+ import { useApiKey } from 'xertica-ui/hooks';
295
+
296
+ function ApiKeySettings() {
297
+ const { geminiApiKey, setGeminiApiKey } = useApiKey();
298
+ const [localKey, setLocalKey] = useState(geminiApiKey);
299
+
300
+ const handleSave = () => {
301
+ setGeminiApiKey(localKey);
302
+ toast.success('API key salva com sucesso.');
303
+ };
304
+
305
+ return (
306
+ <Card className="max-w-2xl">
307
+ <CardHeader>
308
+ <CardTitle>Chaves de API</CardTitle>
309
+ <CardDescription>
310
+ Configure as chaves de API para os serviços integrados.
311
+ </CardDescription>
312
+ </CardHeader>
313
+ <CardContent className="space-y-4">
314
+ <div className="space-y-2">
315
+ <Label htmlFor="gemini-key">Google Gemini API Key</Label>
316
+ <Input
317
+ id="gemini-key"
318
+ type="password"
319
+ value={localKey}
320
+ onChange={e => setLocalKey(e.target.value)}
321
+ placeholder="AIza..."
322
+ />
323
+ <p className="text-xs text-muted-foreground">
324
+ Necessária para o assistente de IA em modo real.
325
+ </p>
326
+ </div>
327
+ </CardContent>
328
+ <CardFooter className="flex justify-end">
329
+ <Button onClick={handleSave}>Salvar chave</Button>
330
+ </CardFooter>
331
+ </Card>
332
+ );
333
+ }
334
+ ```
335
+
336
+ ---
337
+
338
+ ## AI Rules
339
+
340
+ > [!IMPORTANT]
341
+ > - **One `Card` per settings group**: Group related settings into a single `Card` with a `CardHeader` (title + description), `CardContent` (fields), and `CardFooter` (Save/Cancel buttons).
342
+ > - **Use `Switch` for boolean settings**: Never use `Checkbox` for on/off toggles in settings. `Switch` is the correct component for this context.
343
+ > - **Always show a toast after save**: Use `toast.success()` from `sonner` to confirm that settings were saved. Use `toast.error()` for validation failures.
344
+ > - **`Tabs` for categories**: When there are more than 2 settings categories, use `Tabs` to organize them. Do not use a custom sidebar navigation.
345
+ > - **Password fields use `type="password"`**: Never render password inputs as plain text. Always use `<Input type="password">`.
346
+ > - **API keys via `useApiKey`**: Use the `useApiKey()` hook from `xertica-ui/hooks` to read and write API keys. Do not store them in component state or `localStorage` directly.
@@ -0,0 +1,217 @@
1
+ # Pattern: Wizard (Multi-Step Form)
2
+
3
+ A multi-step form pattern using the `Stepper` component to guide users through a sequential process with validation at each step.
4
+
5
+ ---
6
+
7
+ ## When to Use
8
+
9
+ Use the Wizard pattern when:
10
+ - A form has more than 4–5 fields and benefits from being broken into logical sections
11
+ - Each step has its own validation before proceeding
12
+ - The user needs to review a summary before final submission
13
+ - The process has a clear linear sequence (e.g., onboarding, checkout, configuration)
14
+
15
+ ---
16
+
17
+ ## Components Used
18
+
19
+ - [`Stepper`](../components/stepper.md) — step indicator and navigation
20
+ - [`Card`](../components/card.md) — content container for each step
21
+ - [`Button`](../components/button.md) — Next, Back, and Submit actions
22
+ - [`Form`](../components/form.md) + [`Input`](../components/input.md) — form fields with validation
23
+ - [`PageHeader`](../components/page-header.md) — page title and breadcrumb
24
+
25
+ ---
26
+
27
+ ## Basic Structure
28
+
29
+ ```tsx
30
+ import { useState } from 'react';
31
+ import { Stepper } from 'xertica-ui/ui';
32
+ import { Button } from 'xertica-ui/ui';
33
+ import { Card, CardContent, CardFooter, CardHeader, CardTitle } from 'xertica-ui/ui';
34
+
35
+ const STEPS = [
36
+ { id: 'info', label: 'Informações Básicas' },
37
+ { id: 'address', label: 'Endereço' },
38
+ { id: 'review', label: 'Revisão' },
39
+ ];
40
+
41
+ export function WizardExample() {
42
+ const [currentStep, setCurrentStep] = useState(0);
43
+ const [formData, setFormData] = useState({
44
+ name: '', email: '',
45
+ street: '', city: '',
46
+ });
47
+
48
+ const isLastStep = currentStep === STEPS.length - 1;
49
+
50
+ const handleNext = () => {
51
+ if (!isLastStep) setCurrentStep(s => s + 1);
52
+ else handleSubmit();
53
+ };
54
+
55
+ const handleBack = () => {
56
+ if (currentStep > 0) setCurrentStep(s => s - 1);
57
+ };
58
+
59
+ const handleSubmit = () => {
60
+ console.log('Submitted:', formData);
61
+ };
62
+
63
+ return (
64
+ <div className="max-w-2xl mx-auto p-6 space-y-6">
65
+ <Stepper
66
+ steps={STEPS}
67
+ currentStep={currentStep}
68
+ onStepClick={setCurrentStep}
69
+ />
70
+
71
+ <Card>
72
+ <CardHeader>
73
+ <CardTitle>{STEPS[currentStep].label}</CardTitle>
74
+ </CardHeader>
75
+
76
+ <CardContent>
77
+ {currentStep === 0 && <StepBasicInfo data={formData} onChange={setFormData} />}
78
+ {currentStep === 1 && <StepAddress data={formData} onChange={setFormData} />}
79
+ {currentStep === 2 && <StepReview data={formData} />}
80
+ </CardContent>
81
+
82
+ <CardFooter className="flex justify-between">
83
+ <Button
84
+ variant="outline"
85
+ onClick={handleBack}
86
+ disabled={currentStep === 0}
87
+ >
88
+ Voltar
89
+ </Button>
90
+ <Button onClick={handleNext}>
91
+ {isLastStep ? 'Confirmar' : 'Próximo'}
92
+ </Button>
93
+ </CardFooter>
94
+ </Card>
95
+ </div>
96
+ );
97
+ }
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Step Components
103
+
104
+ Each step is a focused form section:
105
+
106
+ ```tsx
107
+ function StepBasicInfo({ data, onChange }) {
108
+ return (
109
+ <div className="space-y-4">
110
+ <div className="space-y-2">
111
+ <Label htmlFor="name">Nome completo</Label>
112
+ <Input
113
+ id="name"
114
+ value={data.name}
115
+ onChange={e => onChange(prev => ({ ...prev, name: e.target.value }))}
116
+ placeholder="João Silva"
117
+ />
118
+ </div>
119
+ <div className="space-y-2">
120
+ <Label htmlFor="email">E-mail</Label>
121
+ <Input
122
+ id="email"
123
+ type="email"
124
+ value={data.email}
125
+ onChange={e => onChange(prev => ({ ...prev, email: e.target.value }))}
126
+ placeholder="joao@empresa.com"
127
+ />
128
+ </div>
129
+ </div>
130
+ );
131
+ }
132
+
133
+ function StepReview({ data }) {
134
+ return (
135
+ <div className="space-y-3">
136
+ <div className="flex justify-between py-2 border-b border-border">
137
+ <span className="text-muted-foreground">Nome</span>
138
+ <span className="font-medium">{data.name}</span>
139
+ </div>
140
+ <div className="flex justify-between py-2 border-b border-border">
141
+ <span className="text-muted-foreground">E-mail</span>
142
+ <span className="font-medium">{data.email}</span>
143
+ </div>
144
+ <div className="flex justify-between py-2 border-b border-border">
145
+ <span className="text-muted-foreground">Endereço</span>
146
+ <span className="font-medium">{data.street}, {data.city}</span>
147
+ </div>
148
+ </div>
149
+ );
150
+ }
151
+ ```
152
+
153
+ ---
154
+
155
+ ## With React Hook Form Validation
156
+
157
+ For production forms, integrate `react-hook-form` with per-step validation:
158
+
159
+ ```tsx
160
+ import { useForm } from 'react-hook-form';
161
+ import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from 'xertica-ui/ui';
162
+
163
+ function StepBasicInfoValidated({ onValid }) {
164
+ const form = useForm({
165
+ defaultValues: { name: '', email: '' },
166
+ });
167
+
168
+ return (
169
+ <Form {...form}>
170
+ <form onSubmit={form.handleSubmit(onValid)} className="space-y-4">
171
+ <FormField
172
+ control={form.control}
173
+ name="name"
174
+ rules={{ required: 'Nome é obrigatório' }}
175
+ render={({ field }) => (
176
+ <FormItem>
177
+ <FormLabel>Nome</FormLabel>
178
+ <FormControl>
179
+ <Input {...field} placeholder="João Silva" />
180
+ </FormControl>
181
+ <FormMessage />
182
+ </FormItem>
183
+ )}
184
+ />
185
+ <Button type="submit">Próximo</Button>
186
+ </form>
187
+ </Form>
188
+ );
189
+ }
190
+ ```
191
+
192
+ ---
193
+
194
+ ## Progress Persistence
195
+
196
+ For long wizards, persist progress in `localStorage` or a URL query parameter:
197
+
198
+ ```tsx
199
+ // Save step to URL
200
+ const [searchParams, setSearchParams] = useSearchParams();
201
+ const currentStep = parseInt(searchParams.get('step') || '0');
202
+
203
+ const handleNext = () => {
204
+ setSearchParams({ step: String(currentStep + 1) });
205
+ };
206
+ ```
207
+
208
+ ---
209
+
210
+ ## AI Rules
211
+
212
+ > [!IMPORTANT]
213
+ > - **Use `Stepper` for the indicator**: Never build a custom step indicator with raw `div` elements. The `Stepper` component handles accessibility, active state, and completed state automatically.
214
+ > - **One `Card` per step**: Each step's content should be inside a single `Card`. Do not render multiple cards or use `Tabs` as a substitute for `Stepper`.
215
+ > - **Validate before advancing**: Always validate the current step's fields before calling `setCurrentStep(s => s + 1)`. Use `react-hook-form`'s `trigger()` method for partial validation.
216
+ > - **Review step is read-only**: The final review step should display a summary of all collected data. It must not contain editable fields.
217
+ > - **Back button is never disabled on step > 0**: Users must always be able to go back. Only disable the Back button on the first step.
@@ -95,17 +95,19 @@ The root `from 'xertica-ui'` exports everything and remains supported for backwa
95
95
 
96
96
  ## 5. Design Tokens — Rules for Component Authors
97
97
 
98
- All components must use semantic CSS tokens exclusively. Never hardcode colors, radii, or shadows:
98
+ All **library components** (`components/ui/`, `components/layout/`, etc.) must use semantic CSS tokens exclusively. Never hardcode colors, radii, or shadows in library source:
99
99
 
100
100
  ```tsx
101
- // ✅ Correct
101
+ // ✅ Correct — library component
102
102
  className="bg-primary text-primary-foreground rounded-[var(--radius)]"
103
103
 
104
- // ❌ Wrong
104
+ // ❌ Wrong — library component
105
105
  className="bg-blue-600 text-white rounded-lg"
106
106
  style={{ backgroundColor: '#3b82f6' }}
107
107
  ```
108
108
 
109
+ > **Note for Storybook stories and consumer applications:** The strict "semantic tokens only" rule applies to **library component internals** and to **semantic/status contexts** (error states, warning banners, success indicators, status badges) in all code. For layout, spacing, and general non-semantic UI in stories or consumer apps, standard Tailwind color utilities (`bg-blue-500`, `text-gray-700`) are acceptable when no semantic token maps to the intent. Raw hex values and `rgb()`/`hsl()` literals are **never** acceptable in any context.
110
+
109
111
  ### Token reference
110
112
 
111
113
  ```
package/llms.txt CHANGED
@@ -51,7 +51,7 @@ import 'xertica-ui/style.css';
51
51
  - [Calendar](docs/components/calendar.md): Date picker. Almost always wrapped in `Popover`.
52
52
  - [Card](docs/components/card.md): Primary content container. Never recreate with raw `<div>`.
53
53
  - [Carousel](docs/components/carousel.md): Horizontal content slider. Built on embla-carousel.
54
- - [Chart](docs/components/chart.md): Token-aware charts built on Recharts. Use `ChartContainer`; dashboard-ready wrappers include `ChartCard`, `DashboardBarChart`, `DashboardLineChart`, `HorizontalBarChart`, `InteractiveTimeSeriesChart`, `ComboMetricChart`, and `DonutBreakdownChart`.
54
+ - [Chart](docs/components/chart.md): Token-aware charts built on Recharts. Use `ChartContainer`; 11 dashboard-ready wrappers: `ChartCard`, `DashboardBarChart`, `DashboardLineChart`, `HorizontalBarChart`, `InteractiveTimeSeriesChart`, `ComboMetricChart`, `DonutBreakdownChart`, `SparklineChart`, `RadarMetricChart`, `PieMetricChart`, `RadialBarMetricChart`, and `GaugeChart` (pure SVG semicircle gauge with thresholds).
55
55
  - [Checkbox](docs/components/checkbox.md): Boolean toggle or multi-select option.
56
56
  - [Collapsible](docs/components/collapsible.md): Single expandable section — no sibling management.
57
57
  - [Command](docs/components/command.md): Command palette (⌘K). Searchable action list.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xertica-ui",
3
- "version": "2.1.2",
3
+ "version": "2.1.4",
4
4
  "description": "Xertica UI — Enterprise-grade React design system with Tailwind CSS v4, Radix UI, and AI-first documentation.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs.js",
@@ -154,12 +154,12 @@
154
154
  "react-router-dom": "^7.1.3"
155
155
  },
156
156
  "devDependencies": {
157
- "@chromatic-com/storybook": "^5.1.2",
158
- "@storybook/addon-a11y": "10.3.5",
159
- "@storybook/addon-docs": "10.3.5",
160
- "@storybook/addon-onboarding": "10.3.5",
161
- "@storybook/addon-vitest": "^10.3.5",
162
- "@storybook/react-vite": "10.3.5",
157
+ "@chromatic-com/storybook": "^5.2.1",
158
+ "@storybook/addon-a11y": "10.4.0",
159
+ "@storybook/addon-docs": "10.4.0",
160
+ "@storybook/addon-onboarding": "10.4.0",
161
+ "@storybook/addon-vitest": "^10.4.0",
162
+ "@storybook/react-vite": "10.4.0",
163
163
  "@tailwindcss/postcss": "^4.0.0",
164
164
  "@testing-library/jest-dom": "^6.9.1",
165
165
  "@testing-library/react": "^16.3.2",
@@ -182,7 +182,7 @@
182
182
  "eslint": "^9.18.0",
183
183
  "eslint-plugin-react-hooks": "^5.1.0",
184
184
  "eslint-plugin-react-refresh": "^0.4.16",
185
- "eslint-plugin-storybook": "^10.3.5",
185
+ "eslint-plugin-storybook": "^10.4.0",
186
186
  "globals": "^15.14.0",
187
187
  "jsdom": "^29.0.2",
188
188
  "playwright": "^1.59.1",
@@ -191,7 +191,7 @@
191
191
  "react-dom": "^18.3.1",
192
192
  "react-router-dom": "^7.1.3",
193
193
  "set-cookie-parser": "^3.1.0",
194
- "storybook": "^10.3.6",
194
+ "storybook": "^10.4.0",
195
195
  "tailwindcss": "^4.0.0",
196
196
  "ts-morph": "^28.0.0",
197
197
  "ts-node": "^10.9.2",
@@ -200,4 +200,4 @@
200
200
  "vite": "^6.0.5",
201
201
  "vitest": "^4.1.5"
202
202
  }
203
- }
203
+ }