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
@@ -12,6 +12,13 @@ Full-featured AI chat assistant with support for:
12
12
  - Three layout modes: `collapsed`, `expanded`, `fullPage`
13
13
  - Demo mode (mock AI responses without API key)
14
14
 
15
+ The component ships in **two usage patterns**:
16
+
17
+ | Pattern | When to use |
18
+ |---|---|
19
+ | `<XerticaAssistant />` | Drop-in assistant panel — zero configuration needed |
20
+ | `useAssistant()` | Headless hook — bring your own UI while reusing all state and business logic |
21
+
15
22
  ---
16
23
 
17
24
  ## Props
@@ -227,6 +234,155 @@ Each assistant capability can be individually toggled via boolean props. All fla
227
234
 
228
235
  ---
229
236
 
237
+ ## Headless Hook — `useAssistant()`
238
+
239
+ Use the headless hook when you need full control over the assistant's UI — custom layout, custom styling, or embedding the assistant logic inside a larger component.
240
+
241
+ ### Import
242
+
243
+ ```tsx
244
+ import { useAssistant } from 'xertica-ui/assistant';
245
+ ```
246
+
247
+ ### Hook Props
248
+
249
+ The hook accepts the same props as `XerticaAssistantProps` (minus purely visual props like `width`, `height`, `className`, `mobileFloating`, `onNavigateSettings`, `onNavigateFullPage`, `userName`, and feature flags).
250
+
251
+ | Prop | Type | Default | Description |
252
+ |---|---|---|---|
253
+ | `mode` | `AssistantMode` | `'expanded'` | Layout mode |
254
+ | `isExpanded` | `boolean` | `true` | Controlled expansion state |
255
+ | `onToggle` | `() => void` | — | Toggle callback |
256
+ | `defaultTab` | `AssistantTab` | `'chat'` | Initially selected tab |
257
+ | `demoMode` | `boolean` | `true` | Enable demo mode |
258
+ | `customResponses` | `MockResponse[]` | `[]` | Custom mock responses |
259
+ | `initialMessages` | `Message[]` | `[]` | Pre-loaded messages |
260
+ | `savedConversations` | `Conversation[]` | `[]` | Previously saved conversations |
261
+ | `suggestions` | `Suggestion[]` | — | Suggested prompts |
262
+ | `onSendMessage` | `(message: string) => void` | — | Send message callback |
263
+ | `isProcessing` | `boolean` | `false` | Shows typing indicator |
264
+ | `responseGenerator` | `(message: string) => Promise<string \| Partial<Message>>` | — | Custom response generator |
265
+ | `richSuggestions` | `Suggestion[]` | `[]` | Extended suggestions |
266
+ | `onRichAction` | `(actionId: string, actionText: string) => void` | — | Rich suggestion callback |
267
+ | `onEvaluation` | `(messageId: string, type: 'like' \| 'dislike', reason?: string) => void` | — | Evaluation callback |
268
+
269
+ ### Hook Return Value
270
+
271
+ | Property | Type | Description |
272
+ |---|---|---|
273
+ | `isFullPage` | `boolean` | Whether mode is `'fullPage'` |
274
+ | `isExpanded` | `boolean` | Current expansion state |
275
+ | `isMobile` | `boolean` | Whether viewport is mobile |
276
+ | `abaSelecionada` | `AssistantTab` | Currently selected tab |
277
+ | `setAbaSelecionada` | `(tab: AssistantTab) => void` | Change selected tab |
278
+ | `mensagens` | `Message[]` | Current conversation messages |
279
+ | `setMensagens` | `Dispatch<SetStateAction<Message[]>>` | Update messages |
280
+ | `mensagem` | `string` | Current input value |
281
+ | `setMensagem` | `(value: string) => void` | Update input value |
282
+ | `conversas` | `Conversation[]` | All saved conversations |
283
+ | `conversaAtual` | `string \| null` | ID of the active conversation |
284
+ | `conversasFiltradas` | `Conversation[]` | Conversations filtered by active tab |
285
+ | `copiedId` | `string \| null` | ID of the message currently showing "copied" state |
286
+ | `generatingPodcastId` | `string \| null` | ID of the message generating a podcast |
287
+ | `executingCommand` | `string \| null` | ID of the search command being executed |
288
+ | `savedSearches` | `string[]` | IDs of saved search messages |
289
+ | `editingDocument` | `{ content: string; title: string } \| null` | Document being edited |
290
+ | `setEditingDocument` | `(doc \| null) => void` | Open/close document editor |
291
+ | `showMoreSuggestions` | `boolean` | Whether extended suggestions are visible |
292
+ | `setShowMoreSuggestions` | `(show: boolean) => void` | Toggle extended suggestions |
293
+ | `evaluationState` | `EvaluationState` | State of the feedback dialog |
294
+ | `setEvaluationState` | `Dispatch<...>` | Update evaluation state |
295
+ | `sugestoes` | `Suggestion[]` | Resolved suggestions (prop or defaults) |
296
+ | `messagesEndRef` | `RefObject<HTMLDivElement>` | Attach to the scroll anchor at the bottom of the message list |
297
+ | `fileInputRef` | `RefObject<HTMLInputElement>` | Attach to the hidden file input |
298
+ | `audioInputRef` | `RefObject<HTMLInputElement>` | Attach to the hidden audio input |
299
+ | `handleToggle` | `() => void` | Toggle expansion |
300
+ | `handleExpandWithTab` | `(tab: AssistantTab) => void` | Expand and switch to a specific tab |
301
+ | `handleEnviarMensagem` | `(arg?: string \| ActionType) => Promise<void>` | Send a message |
302
+ | `handleToggleFavorite` | `(messageId: string) => void` | Toggle message favorite |
303
+ | `handleCopyMessage` | `(content: string, messageId: string) => Promise<void>` | Copy message to clipboard |
304
+ | `handleGeneratePodcast` | `(messageId: string, content: string) => Promise<void>` | Generate podcast from message |
305
+ | `handleDownloadDocument` | `(content: string, fileName: string) => void` | Download document as `.md` |
306
+ | `handleDownloadPodcast` | `(audioUrl: string, fileName: string) => void` | Download podcast as `.mp3` |
307
+ | `handleEditDocument` | `(content: string, title: string) => void` | Open document editor |
308
+ | `handleNovaConversa` | `() => void` | Start a new conversation |
309
+ | `handleSelecionarConversa` | `(conversaId: string) => void` | Load a saved conversation |
310
+ | `handleToggleFavoritaConversa` | `(conversaId: string) => void` | Toggle conversation favorite |
311
+ | `handleOpenSearchResult` | `(result: SearchResult) => void` | Open a search result |
312
+ | `handleExecuteSearchCommand` | `(commandId, searchTerm, results, messageId) => Promise<void>` | Execute a search command |
313
+ | `handleRichSuggestionClick` | `(suggestion: Suggestion) => void` | Handle rich suggestion click |
314
+ | `handleEvaluationClick` | `(messageId: string, type: 'like' \| 'dislike') => void` | Handle message evaluation |
315
+ | `openFeedbackDialog` | `(messageId: string, category: string \| null) => void` | Open dislike feedback dialog |
316
+ | `handleSubmitDislike` | `() => void` | Submit dislike feedback |
317
+
318
+ ### Headless Hook Example
319
+
320
+ ```tsx
321
+ import { useAssistant } from 'xertica-ui/assistant';
322
+
323
+ function MyMinimalAssistant() {
324
+ const {
325
+ mensagens,
326
+ mensagem,
327
+ setMensagem,
328
+ handleEnviarMensagem,
329
+ isExpanded,
330
+ handleToggle,
331
+ messagesEndRef,
332
+ } = useAssistant({ demoMode: true });
333
+
334
+ return (
335
+ <div className="flex flex-col h-full border rounded-lg overflow-hidden">
336
+ {/* Header */}
337
+ <div className="flex items-center justify-between p-3 border-b">
338
+ <span className="font-semibold">AI Assistant</span>
339
+ <button onClick={handleToggle}>
340
+ {isExpanded ? 'Collapse' : 'Expand'}
341
+ </button>
342
+ </div>
343
+
344
+ {/* Messages */}
345
+ <div className="flex-1 overflow-y-auto p-4 space-y-3">
346
+ {mensagens.map(msg => (
347
+ <div
348
+ key={msg.id}
349
+ className={msg.type === 'user' ? 'text-right' : 'text-left'}
350
+ >
351
+ <span className={`inline-block px-3 py-2 rounded-lg text-sm ${
352
+ msg.type === 'user'
353
+ ? 'bg-primary text-primary-foreground'
354
+ : 'bg-muted'
355
+ }`}>
356
+ {msg.content}
357
+ </span>
358
+ </div>
359
+ ))}
360
+ <div ref={messagesEndRef} />
361
+ </div>
362
+
363
+ {/* Input */}
364
+ <div className="flex gap-2 p-3 border-t">
365
+ <input
366
+ value={mensagem}
367
+ onChange={e => setMensagem(e.target.value)}
368
+ onKeyDown={e => e.key === 'Enter' && handleEnviarMensagem()}
369
+ placeholder="Type a message..."
370
+ className="flex-1 border rounded px-3 py-2 text-sm"
371
+ />
372
+ <button
373
+ onClick={() => handleEnviarMensagem()}
374
+ className="px-4 py-2 bg-primary text-primary-foreground rounded text-sm"
375
+ >
376
+ Send
377
+ </button>
378
+ </div>
379
+ </div>
380
+ );
381
+ }
382
+ ```
383
+
384
+ ---
385
+
230
386
  ## AI Rules
231
387
 
232
388
  - Use `demoMode={true}` for development without API key
@@ -236,3 +392,6 @@ Each assistant capability can be individually toggled via boolean props. All fla
236
392
  - Feature flags are independent and can be combined freely; all default to `true`
237
393
  - When `showHistory` or `showFavorites` is `false`, both the collapsed icon and expanded tab are removed
238
394
  - When both `showHistory` and `showFavorites` are `false`, the entire tab navigation bar is hidden (including the Chat tab) — there is no point showing a single tab with no alternatives
395
+ - ALWAYS use `useAssistant()` when building a custom assistant UI — never re-implement message state or response generation manually
396
+ - The `messagesEndRef` from the hook MUST be attached to a div at the bottom of the message list for auto-scroll to work
397
+ - `handleEnviarMensagem()` handles both demo mode responses and `responseGenerator` — do not call `responseGenerator` directly
@@ -72,9 +72,55 @@ The `bar` variant automatically detects the state of the **Sidebar** and **AI As
72
72
 
73
73
  ---
74
74
 
75
+ ## Headless Hook: `useAudioPlayer`
76
+
77
+ For advanced use cases where you need a fully custom player UI, use the `useAudioPlayer` headless hook directly:
78
+
79
+ ```tsx
80
+ import { useAudioPlayer } from 'xertica-ui/hooks';
81
+
82
+ function MyCustomPlayer({ src }: { src: string }) {
83
+ const {
84
+ audioRef,
85
+ containerRef,
86
+ isPlaying,
87
+ togglePlay,
88
+ currentTime,
89
+ duration,
90
+ formatTime,
91
+ onPlay,
92
+ onPause,
93
+ onEnded,
94
+ onTimeUpdate,
95
+ onLoadedMetadata,
96
+ } = useAudioPlayer({ src, variant: 'card' });
97
+
98
+ return (
99
+ <div ref={containerRef}>
100
+ <audio
101
+ ref={audioRef}
102
+ src={src}
103
+ onPlay={onPlay}
104
+ onPause={onPause}
105
+ onEnded={onEnded}
106
+ onTimeUpdate={onTimeUpdate}
107
+ onLoadedMetadata={onLoadedMetadata}
108
+ />
109
+ <button onClick={togglePlay}>{isPlaying ? 'Pause' : 'Play'}</button>
110
+ <span>{formatTime(currentTime)} / {formatTime(duration)}</span>
111
+ </div>
112
+ );
113
+ }
114
+ ```
115
+
116
+ See [`hooks.md`](./hooks.md#useaudioplayer) for the complete `useAudioPlayer` API reference.
117
+
118
+ ---
119
+
75
120
  ## AI Best Practices
76
121
 
77
122
  > [!IMPORTANT]
78
123
  > - **Branding Variants**: Use `colorVariant="primary"` for high-relevance or branded content (like Podcasts). Use the default style for utility audios.
79
124
  > - **Manual Floating**: In Card mode, users can click the "Maximize" icon to manually force floating mode.
80
125
  > - **Accessibility**: All buttons have appropriate ARIA labels. Always provide a descriptive `title` for each audio track.
126
+ > - **Custom UI**: Use `useAudioPlayer` from `xertica-ui/hooks` only when you need a fully custom player interface. For standard playback, always use `<AudioPlayer>` directly.
@@ -0,0 +1,251 @@
1
+ # Branding — Xertica UI
2
+
3
+ The branding system in Xertica UI provides tools for applying, customizing, and switching the visual identity of an application — including color themes, logos, language, and dark/light mode.
4
+
5
+ ---
6
+
7
+ ## Brand Components Overview
8
+
9
+ | Component | Import | Purpose |
10
+ |---|---|---|
11
+ | `XerticaProvider` | `xertica-ui/brand` | Root provider for all brand, theme, and layout contexts |
12
+ | `ThemeToggle` | `xertica-ui/brand` | Self-contained dark/light mode switcher |
13
+ | `LanguageSelector` | `xertica-ui/brand` | Standalone language dropdown (pt-BR / en / es) |
14
+ | `XerticaLogo` | `xertica-ui/brand` | Full horizontal Xertica logotype SVG |
15
+ | `XerticaXLogo` | `xertica-ui/brand` | Compact X-mark logo variant |
16
+ | `XerticaOrbe` | `xertica-ui/brand` | Animated orb brand mark |
17
+
18
+ ---
19
+
20
+ ## Color Theme System
21
+
22
+ ### How It Works
23
+
24
+ Xertica UI uses CSS custom properties (design tokens) for all colors. The theme is applied by injecting token values at `:root` and `.dark`. Tailwind v4 maps these tokens via `@theme inline`.
25
+
26
+ ```
27
+ tokens.css → :root { --primary: ...; --background: ...; }
28
+ → .dark { --primary: ...; --background: ...; }
29
+ → @theme inline { --color-primary: var(--primary); }
30
+ → Tailwind utilities: bg-primary, text-foreground, etc.
31
+ ```
32
+
33
+ ### Available Theme Presets
34
+
35
+ The CLI (`npx xertica-ui@latest init` or `npx xertica-ui@latest update-theme`) offers multiple color presets. Each preset defines a complete set of tokens for both light and dark modes.
36
+
37
+ ### Customizing Colors Programmatically
38
+
39
+ Use `useBrandColors` to read and modify brand colors at runtime:
40
+
41
+ ```tsx
42
+ import { useBrandColors } from 'xertica-ui/hooks';
43
+
44
+ function BrandCustomizer() {
45
+ const { colors, setBrandColor } = useBrandColors();
46
+
47
+ return (
48
+ <div className="space-y-2">
49
+ <label>Primary Color</label>
50
+ <input
51
+ type="color"
52
+ value={colors.primary}
53
+ onChange={e => setBrandColor('primary', e.target.value)}
54
+ />
55
+ </div>
56
+ );
57
+ }
58
+ ```
59
+
60
+ Changes are applied immediately as CSS variables on `:root`.
61
+
62
+ ---
63
+
64
+ ## Dark / Light Mode
65
+
66
+ ### `ThemeToggle`
67
+
68
+ A self-contained button that toggles between light and dark mode. Does not require any context provider — it reads and writes `document.documentElement.classList` directly.
69
+
70
+ ```tsx
71
+ import { ThemeToggle } from 'xertica-ui/brand';
72
+
73
+ // Place in Header actions or Sidebar footer
74
+ <ThemeToggle size="sm" />
75
+ ```
76
+
77
+ **Props:**
78
+
79
+ | Prop | Type | Default | Description |
80
+ |---|---|---|---|
81
+ | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Button size |
82
+ | `className` | `string` | — | Additional CSS classes |
83
+
84
+ ### `useTheme` Hook
85
+
86
+ For programmatic theme control:
87
+
88
+ ```tsx
89
+ import { useTheme } from 'xertica-ui/hooks';
90
+
91
+ function ThemeController() {
92
+ const { theme, setTheme, toggleTheme } = useTheme();
93
+ return (
94
+ <button onClick={toggleTheme}>
95
+ Mode: {theme}
96
+ </button>
97
+ );
98
+ }
99
+ ```
100
+
101
+ > **Note**: `useTheme` requires `<XerticaProvider>` in the tree. `ThemeToggle` works without any provider.
102
+
103
+ ---
104
+
105
+ ## Language Selector
106
+
107
+ ### `LanguageSelector`
108
+
109
+ A standalone dropdown for switching the UI language preference.
110
+
111
+ ```tsx
112
+ import { LanguageSelector } from 'xertica-ui/brand';
113
+
114
+ // Typically placed in PageHeader or Sidebar footer
115
+ <LanguageSelector />
116
+ ```
117
+
118
+ The selected language is persisted in `localStorage` under `xertica_language`. Access the current value via `useLanguage()`:
119
+
120
+ ```tsx
121
+ import { useLanguage } from 'xertica-ui/hooks';
122
+
123
+ function MyComponent() {
124
+ const { language } = useLanguage(); // 'pt-BR' | 'en' | 'es'
125
+ }
126
+ ```
127
+
128
+ ---
129
+
130
+ ## Logo Components
131
+
132
+ ### `XerticaLogo`
133
+
134
+ Full horizontal logotype. Use in the Sidebar header or login page.
135
+
136
+ ```tsx
137
+ import { XerticaLogo } from 'xertica-ui/brand';
138
+
139
+ <XerticaLogo className="h-8" />
140
+ ```
141
+
142
+ ### `XerticaXLogo`
143
+
144
+ Compact X-mark variant. Use when space is limited (collapsed sidebar, favicon-like contexts).
145
+
146
+ ```tsx
147
+ import { XerticaXLogo } from 'xertica-ui/brand';
148
+
149
+ <XerticaXLogo className="w-8 h-8" />
150
+ ```
151
+
152
+ ### `XerticaOrbe`
153
+
154
+ Animated orb brand mark. Use as a decorative element or loading indicator.
155
+
156
+ ```tsx
157
+ import { XerticaOrbe } from 'xertica-ui/brand';
158
+
159
+ <XerticaOrbe size={64} />
160
+ ```
161
+
162
+ ---
163
+
164
+ ## `XerticaProvider`
165
+
166
+ The root provider that initializes all brand, theme, layout, and service contexts. Must wrap the entire application once.
167
+
168
+ ```tsx
169
+ import { XerticaProvider } from 'xertica-ui/brand';
170
+ import 'xertica-ui/style.css';
171
+
172
+ ReactDOM.createRoot(document.getElementById('root')!).render(
173
+ <React.StrictMode>
174
+ <XerticaProvider>
175
+ <App />
176
+ </XerticaProvider>
177
+ </React.StrictMode>
178
+ );
179
+ ```
180
+
181
+ `XerticaProvider` initializes:
182
+ - `ThemeProvider` — dark/light mode
183
+ - `LanguageProvider` — language preference
184
+ - `BrandColorsProvider` — brand color tokens
185
+ - `LayoutProvider` — sidebar and assistant state
186
+ - `AssistenteProvider` — AI assistant context
187
+ - `ApiKeyProvider` — API key management
188
+ - `GoogleMapsLoaderProvider` — lazy Maps API loading
189
+ - `TooltipProvider` — Radix tooltip context
190
+ - `Toaster` — Sonner toast notifications
191
+
192
+ **Props:**
193
+
194
+ | Prop | Type | Default | Description |
195
+ |---|---|---|---|
196
+ | `children` | `ReactNode` | _(required)_ | Application content |
197
+ | `googleMapsApiKey` | `string` | — | Google Maps API key (activates Maps loader) |
198
+ | `initialApiKey` | `string` | — | Pre-set Xertica API key |
199
+ | `initialGeminiApiKey` | `string` | — | Pre-set Gemini API key |
200
+
201
+ ---
202
+
203
+ ## CSS Token Structure
204
+
205
+ The complete token set is defined in `tokens.css` (generated by the CLI). Key token groups:
206
+
207
+ ```css
208
+ :root {
209
+ /* Colors */
210
+ --background: 0 0% 100%;
211
+ --foreground: 222.2 84% 4.9%;
212
+ --primary: 221.2 83.2% 53.3%;
213
+ --primary-foreground: 210 40% 98%;
214
+ --secondary: 210 40% 96.1%;
215
+ --muted: 210 40% 96.1%;
216
+ --muted-foreground: 215.4 16.3% 46.9%;
217
+ --accent: 210 40% 96.1%;
218
+ --destructive: 0 84.2% 60.2%;
219
+ --border: 214.3 31.8% 91.4%;
220
+ --input: 214.3 31.8% 91.4%;
221
+ --ring: 221.2 83.2% 53.3%;
222
+ --card: 0 0% 100%;
223
+ --card-foreground: 222.2 84% 4.9%;
224
+
225
+ /* Chart colors */
226
+ --chart-1: 221.2 83.2% 53.3%;
227
+ --chart-2: 142.1 76.2% 36.3%;
228
+ --chart-3: 47.9 95.8% 53.1%;
229
+ --chart-4: 280.1 65.3% 60%;
230
+ --chart-5: 24.6 95% 53.1%;
231
+
232
+ /* Sidebar */
233
+ --sidebar: 222.2 84% 4.9%;
234
+ --sidebar-foreground: 210 40% 98%;
235
+
236
+ /* Shape */
237
+ --radius: 0.5rem;
238
+ --radius-button: 0.375rem;
239
+ }
240
+ ```
241
+
242
+ ---
243
+
244
+ ## AI Rules
245
+
246
+ > [!IMPORTANT]
247
+ > - **`XerticaProvider` is required once**: Place it at the root of your application. Never nest multiple `XerticaProvider` instances.
248
+ > - **Never use raw hex/rgb colors**: All colors must use semantic tokens (`bg-primary`, `text-destructive`, `border-border`). Raw values like `#3b82f6` or `rgb(59, 130, 246)` are forbidden.
249
+ > - **`ThemeToggle` is self-contained**: It does not need `useTheme` or any context. Use it directly in any component without provider requirements.
250
+ > - **Logo sizing via `className`**: Size logo components using Tailwind height/width classes (`h-8`, `w-8`). Do not use `width`/`height` HTML attributes.
251
+ > - **Language is preference only**: `LanguageSelector` stores a preference. The library UI renders in Portuguese regardless. Implement your own i18n logic using the `language` value from `useLanguage()`.