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
@@ -4,6 +4,8 @@
4
4
 
5
5
  Xertica UI provides a `ChartContainer` wrapper and related components built on top of **Recharts** for theme-aware, token-driven chart rendering. The chart system uses a `ChartConfig` object to define series labels and colors via CSS variables, ensuring full dark-mode support without hard-coded hex values.
6
6
 
7
+ The library ships **11 dashboard-ready chart wrappers** that handle loading, empty, and error states automatically, so feature layers only need to pass `data`, `isLoading`, `error`, and `onRetry`.
8
+
7
9
  ---
8
10
 
9
11
  ## Exports
@@ -23,7 +25,13 @@ Xertica UI provides a `ChartContainer` wrapper and related components built on t
23
25
  | `InteractiveTimeSeriesChart` | Area time-series chart with metric tabs and period select |
24
26
  | `ComboMetricChart` | Composed bar, line, and area chart for mixed metrics |
25
27
  | `DonutBreakdownChart` | Donut/pie breakdown chart with interactive segment focus |
28
+ | `SparklineChart` | Compact inline area/line chart for KPI cards |
29
+ | `RadarMetricChart` | Multi-dimensional radar/spider chart |
30
+ | `PieMetricChart` | Proportional pie chart with optional donut, labels, and exploded slice |
31
+ | `RadialBarMetricChart` | Circular progress rings (radial bar chart) |
32
+ | `GaugeChart` | Semicircle gauge with needle, thresholds, and color zones |
26
33
  | `ChartConfig` | TypeScript type for chart configuration |
34
+ | `GaugeChartThreshold` | TypeScript type for gauge color zone thresholds |
27
35
 
28
36
  ---
29
37
 
@@ -42,6 +50,8 @@ npm install recharts
42
50
  3. Reference colors in chart elements using `fill="var(--color-yourKey)"`.
43
51
  4. The container automatically injects CSS variables for light and dark themes.
44
52
 
53
+ Dashboard-ready wrappers (`DashboardBarChart`, `RadarMetricChart`, etc.) build the config internally — you only need to pass `data` and `series`/`nameKey`/`valueKey`.
54
+
45
55
  ---
46
56
 
47
57
  ## ChartConfig Type
@@ -59,9 +69,24 @@ type ChartConfig = {
59
69
 
60
70
  ---
61
71
 
72
+ ## Color Tokens
73
+
74
+ Chart colors use `--chart-1` through `--chart-8` CSS tokens. These are theme-aware and automatically switch between light and dark mode.
75
+
76
+ ```tsx
77
+ // In ChartConfig
78
+ { revenue: { label: 'Revenue', color: 'var(--chart-1)' } }
79
+
80
+ // In dashboard-ready wrappers — pass as array or per-key map
81
+ colors={['var(--chart-1)', 'var(--chart-2)']}
82
+ colors={{ revenue: 'var(--chart-1)', expenses: 'var(--chart-5)' }}
83
+ ```
84
+
85
+ ---
86
+
62
87
  ## Examples
63
88
 
64
- ### Bar Chart
89
+ ### Bar Chart (low-level)
65
90
 
66
91
  ```tsx
67
92
  import {
@@ -72,13 +97,7 @@ import {
72
97
  ChartLegendContent,
73
98
  type ChartConfig,
74
99
  } from 'xertica-ui/ui';
75
- import {
76
- BarChart,
77
- Bar,
78
- XAxis,
79
- YAxis,
80
- CartesianGrid,
81
- } from 'recharts';
100
+ import { BarChart, Bar, XAxis, YAxis, CartesianGrid } from 'recharts';
82
101
  import { Card, CardHeader, CardTitle, CardContent } from 'xertica-ui/ui';
83
102
 
84
103
  const chartConfig: ChartConfig = {
@@ -112,7 +131,7 @@ const data = [
112
131
  </Card>
113
132
  ```
114
133
 
115
- ### Line Chart
134
+ ### Line Chart (low-level)
116
135
 
117
136
  ```tsx
118
137
  const chartConfig: ChartConfig = {
@@ -168,7 +187,6 @@ const data = [
168
187
  data={data}
169
188
  indexKey="date"
170
189
  config={config}
171
- colors={['var(--chart-1)', 'var(--chart-4)']}
172
190
  series={[
173
191
  { key: 'revenue', label: 'Revenue' },
174
192
  { key: 'pipeline', label: 'Pipeline' },
@@ -180,22 +198,8 @@ const data = [
180
198
  <DonutBreakdownChart data={segments} config={segmentConfig} />
181
199
  </ChartCard>
182
200
 
183
- <ChartCard title="Pipeline Trend">
184
- <DashboardLineChart data={trendData} config={config} />
185
- </ChartCard>
186
-
187
201
  <DashboardBarChart data={data} indexKey="date" config={config} stacked />
188
202
 
189
- <DashboardLineChart
190
- data={data}
191
- indexKey="date"
192
- config={config}
193
- colors={{
194
- revenue: 'var(--chart-1)',
195
- pipeline: 'var(--chart-4)',
196
- }}
197
- />
198
-
199
203
  <HorizontalBarChart
200
204
  data={[
201
205
  { segment: 'Enterprise', revenue: 7600 },
@@ -217,25 +221,318 @@ const data = [
217
221
  { key: 'conversion', type: 'line' },
218
222
  ]}
219
223
  />
224
+ ```
220
225
 
221
- <DonutBreakdownChart
222
- data={[
223
- { name: 'enterprise', value: 52 },
224
- { name: 'midmarket', value: 31 },
225
- ]}
226
- config={{
227
- enterprise: { label: 'Enterprise', color: 'var(--chart-1)' },
228
- midmarket: { label: 'Mid-market', color: 'var(--chart-4)' },
229
- }}
230
- colors={['var(--chart-1)', 'var(--chart-4)']}
231
- centerValue="83"
232
- centerLabel="Accounts"
226
+ ---
227
+
228
+ ### Radar Chart
229
+
230
+ Multi-dimensional comparison across categorical axes. Use a single series for a simple spider chart, or multiple series for side-by-side comparison.
231
+
232
+ ```tsx
233
+ import { RadarMetricChart, ChartCard } from 'xertica-ui/ui';
234
+
235
+ const data = [
236
+ { skill: 'Speed', frontend: 80, backend: 60 },
237
+ { skill: 'Quality', frontend: 90, backend: 85 },
238
+ { skill: 'Coverage', frontend: 70, backend: 95 },
239
+ { skill: 'Security', frontend: 65, backend: 88 },
240
+ { skill: 'Perf', frontend: 75, backend: 72 },
241
+ ];
242
+
243
+ // Single series — filled polygon
244
+ <ChartCard title="Frontend Skills">
245
+ <RadarMetricChart
246
+ data={data}
247
+ labelKey="skill"
248
+ series={[{ key: 'frontend', label: 'Frontend' }]}
249
+ filled
250
+ fillOpacity={0.3}
251
+ />
252
+ </ChartCard>
253
+
254
+ // Multi-series comparison
255
+ <ChartCard title="Team Comparison">
256
+ <RadarMetricChart
257
+ data={data}
258
+ labelKey="skill"
259
+ series={[
260
+ { key: 'frontend', label: 'Frontend' },
261
+ { key: 'backend', label: 'Backend' },
262
+ ]}
263
+ filled={false}
264
+ showDots
265
+ showLegend
266
+ />
267
+ </ChartCard>
268
+ ```
269
+
270
+ **Props:**
271
+
272
+ | Prop | Type | Default | Description |
273
+ |---|---|---|---|
274
+ | `data` | `DashboardChartDatum[]` | — | Data array; each item is one axis point |
275
+ | `labelKey` | `string` | — | Key used as the axis label |
276
+ | `series` | `DashboardChartSeries[]` | — | Series to render (one `<Radar>` per entry) |
277
+ | `colors` | `DashboardChartColors` | auto | Override colors per key or as ordered array |
278
+ | `filled` | `boolean` | `true` | Fill the radar polygon |
279
+ | `fillOpacity` | `number` | `0.25` | Fill opacity when `filled` is true |
280
+ | `showDots` | `boolean` | `false` | Show dots on each axis point |
281
+ | `showGrid` | `boolean` | `true` | Show polar grid lines |
282
+ | `showLegend` | `boolean` | auto | Show legend (auto-shown when multiple series) |
283
+ | `valueFormatter` | `(v: number) => string` | — | Format axis tick and tooltip values |
284
+ | + state props | — | — | `isLoading`, `error`, `onRetry`, etc. |
285
+
286
+ ---
287
+
288
+ ### Pie Chart
289
+
290
+ Proportional slices. Supports donut mode (`innerRadius > 0`), percentage labels, and an exploded (offset) slice for emphasis.
291
+
292
+ ```tsx
293
+ import { PieMetricChart, ChartCard } from 'xertica-ui/ui';
294
+
295
+ const data = [
296
+ { segment: 'Enterprise', value: 52 },
297
+ { segment: 'Mid-market', value: 31 },
298
+ { segment: 'SMB', value: 17 },
299
+ ];
300
+
301
+ // Simple pie
302
+ <ChartCard title="Revenue Mix">
303
+ <PieMetricChart
304
+ data={data}
305
+ nameKey="segment"
306
+ valueKey="value"
307
+ showLabels
308
+ />
309
+ </ChartCard>
310
+
311
+ // Donut variant
312
+ <ChartCard title="Revenue Mix (Donut)">
313
+ <PieMetricChart
314
+ data={data}
315
+ nameKey="segment"
316
+ valueKey="value"
317
+ innerRadius="55%"
318
+ outerRadius="80%"
319
+ />
320
+ </ChartCard>
321
+
322
+ // Exploded slice (highlight index 0)
323
+ <ChartCard title="Top Segment">
324
+ <PieMetricChart
325
+ data={data}
326
+ nameKey="segment"
327
+ valueKey="value"
328
+ explodeIndex={0}
329
+ explodeOffset={14}
330
+ />
331
+ </ChartCard>
332
+ ```
333
+
334
+ **Props:**
335
+
336
+ | Prop | Type | Default | Description |
337
+ |---|---|---|---|
338
+ | `data` | `DashboardChartDatum[]` | — | Data array; each item is one slice |
339
+ | `nameKey` | `string` | — | Key used as the slice name/label |
340
+ | `valueKey` | `string` | — | Key used as the slice value |
341
+ | `colors` | `DashboardChartColors` | auto | Override colors as ordered array or per-name map |
342
+ | `outerRadius` | `number \| string` | `"80%"` | Outer radius of the pie |
343
+ | `innerRadius` | `number \| string` | `0` | Inner radius — set > 0 for donut |
344
+ | `showLabels` | `boolean` | `false` | Show percentage labels on slices |
345
+ | `showLegend` | `boolean` | `true` | Show the legend |
346
+ | `explodeIndex` | `number` | — | Index of the slice to offset outward |
347
+ | `explodeOffset` | `number` | `12` | Offset distance in px for the exploded slice |
348
+ | `valueFormatter` | `(v: number) => string` | — | Format tooltip values |
349
+ | + state props | — | — | `isLoading`, `error`, `onRetry`, etc. |
350
+
351
+ ---
352
+
353
+ ### Radial Bar Chart
354
+
355
+ Circular progress rings. Each data item renders as a concentric arc. Useful for showing multiple metrics as percentage completion.
356
+
357
+ ```tsx
358
+ import { RadialBarMetricChart, ChartCard } from 'xertica-ui/ui';
359
+
360
+ const data = [
361
+ { name: 'CPU', value: 72 },
362
+ { name: 'Memory', value: 58 },
363
+ { name: 'Storage', value: 41 },
364
+ { name: 'Network', value: 89 },
365
+ ];
366
+
367
+ // Full-circle rings (default)
368
+ <ChartCard title="Resource Usage">
369
+ <RadialBarMetricChart
370
+ data={data}
371
+ dataKey="value"
372
+ nameKey="name"
373
+ valueFormatter={(v) => `${v}%`}
374
+ />
375
+ </ChartCard>
376
+
377
+ // Semi-circle layout
378
+ <ChartCard title="Resource Usage (Semi)">
379
+ <RadialBarMetricChart
380
+ data={data}
381
+ dataKey="value"
382
+ nameKey="name"
383
+ startAngle={180}
384
+ endAngle={0}
385
+ innerRadius="20%"
386
+ outerRadius="90%"
387
+ />
388
+ </ChartCard>
389
+ ```
390
+
391
+ **Props:**
392
+
393
+ | Prop | Type | Default | Description |
394
+ |---|---|---|---|
395
+ | `data` | `DashboardChartDatum[]` | — | Data array; each item is one ring |
396
+ | `dataKey` | `string` | `"value"` | Key used as the bar value |
397
+ | `nameKey` | `string` | `"name"` | Key used as the bar label |
398
+ | `colors` | `DashboardChartColors` | auto | Override colors as ordered array or per-name map |
399
+ | `innerRadius` | `number \| string` | `"30%"` | Inner radius of the radial bar |
400
+ | `outerRadius` | `number \| string` | `"100%"` | Outer radius of the radial bar |
401
+ | `startAngle` | `number` | `90` | Start angle in degrees (90 = top) |
402
+ | `endAngle` | `number` | `-270` | End angle in degrees (-270 = full circle) |
403
+ | `showBackground` | `boolean` | `true` | Show background track behind each bar |
404
+ | `showLegend` | `boolean` | `true` | Show the legend below the chart |
405
+ | `valueFormatter` | `(v: number) => string` | — | Format tooltip and legend values |
406
+ | + state props | — | — | `isLoading`, `error`, `onRetry`, etc. |
407
+
408
+ ---
409
+
410
+ ### Gauge Chart
411
+
412
+ Semicircle gauge with a needle indicator and optional color zones (thresholds). Implemented as pure SVG — no Recharts dependency.
413
+
414
+ ```tsx
415
+ import { GaugeChart, ChartCard, type GaugeChartThreshold } from 'xertica-ui/ui';
416
+
417
+ // Simple percentage gauge
418
+ <ChartCard title="CPU Usage">
419
+ <div className="flex justify-center py-4">
420
+ <GaugeChart value={72} label="CPU" />
421
+ </div>
422
+ </ChartCard>
423
+
424
+ // With color thresholds
425
+ const thresholds: GaugeChartThreshold[] = [
426
+ { value: 40, color: 'var(--chart-2)', label: 'Healthy' },
427
+ { value: 70, color: 'var(--chart-3)', label: 'Warning' },
428
+ { value: 100, color: 'var(--chart-5)', label: 'Critical' },
429
+ ];
430
+
431
+ <ChartCard title="Memory Usage">
432
+ <div className="flex justify-center py-4">
433
+ <GaugeChart
434
+ value={85}
435
+ label="Memory"
436
+ thresholds={thresholds}
437
+ />
438
+ </div>
439
+ </ChartCard>
440
+
441
+ // Custom range and formatter
442
+ <GaugeChart
443
+ value={1250}
444
+ min={0}
445
+ max={2000}
446
+ label="Requests/s"
447
+ valueFormatter={(value) => `${value.toLocaleString()} rps`}
448
+ showNeedle={false}
233
449
  />
234
450
  ```
235
451
 
452
+ **Props:**
453
+
454
+ | Prop | Type | Default | Description |
455
+ |---|---|---|---|
456
+ | `value` | `number` | — | Current value (must be within `[min, max]`) |
457
+ | `min` | `number` | `0` | Minimum value |
458
+ | `max` | `number` | `100` | Maximum value |
459
+ | `thresholds` | `GaugeChartThreshold[]` | — | Color zones evaluated in order; first zone where `value >= current %` wins |
460
+ | `label` | `React.ReactNode` | — | Label shown below the center value |
461
+ | `valueFormatter` | `(value: number, percent: number) => string` | — | Format the center value text (default: shows `%`) |
462
+ | `showNeedle` | `boolean` | `true` | Show the needle indicator |
463
+ | `className` | `string` | — | Additional CSS classes |
464
+
465
+ **`GaugeChartThreshold` type:**
466
+
467
+ ```typescript
468
+ interface GaugeChartThreshold {
469
+ value: number; // Upper bound of this zone (0–100)
470
+ color: string; // Color for this zone (use CSS var tokens)
471
+ label?: string; // Optional label shown in the legend
472
+ }
473
+ ```
474
+
475
+ **Infrastructure dashboard example:**
476
+
477
+ ```tsx
478
+ const metrics = [
479
+ { label: 'CPU', value: 72 },
480
+ { label: 'Memory', value: 85 },
481
+ { label: 'Storage', value: 41 },
482
+ ];
483
+
484
+ const thresholds: GaugeChartThreshold[] = [
485
+ { value: 60, color: 'var(--chart-2)', label: 'OK' },
486
+ { value: 80, color: 'var(--chart-3)', label: 'Warning' },
487
+ { value: 100, color: 'var(--chart-5)', label: 'Critical' },
488
+ ];
489
+
490
+ <div className="grid grid-cols-3 gap-4">
491
+ {metrics.map((m) => (
492
+ <ChartCard key={m.label} title={m.label}>
493
+ <div className="flex justify-center py-2">
494
+ <GaugeChart
495
+ value={m.value}
496
+ label={m.label}
497
+ thresholds={thresholds}
498
+ />
499
+ </div>
500
+ </ChartCard>
501
+ ))}
502
+ </div>
503
+ ```
504
+
505
+ ---
506
+
507
+ ### Sparkline Chart
508
+
509
+ Compact inline chart for KPI cards and metric summaries. Renders as a minimal area or line chart with no axes or labels.
510
+
511
+ ```tsx
512
+ import { SparklineChart } from 'xertica-ui/ui';
513
+
514
+ // Filled area sparkline (default)
515
+ <SparklineChart
516
+ data={[{ v: 10 }, { v: 25 }, { v: 18 }, { v: 40 }, { v: 35 }]}
517
+ dataKey="v"
518
+ color="var(--chart-1)"
519
+ filled
520
+ />
521
+
522
+ // Line-only sparkline
523
+ <SparklineChart
524
+ data={weeklyData}
525
+ dataKey="sessions"
526
+ color="var(--chart-2)"
527
+ filled={false}
528
+ />
529
+ ```
530
+
531
+ ---
532
+
236
533
  ### Empty and Connection States
237
534
 
238
- Dashboard-ready chart wrappers handle loading, empty data, and connection errors without forcing each feature to duplicate presentation logic. In an FSD architecture, keep fetching and error mapping in the feature/model layer, then pass the state into the UI component.
535
+ All dashboard-ready chart wrappers handle loading, empty data, and connection errors without forcing each feature to duplicate presentation logic. In an FSD architecture, keep fetching and error mapping in the feature/model layer, then pass the state into the UI component.
239
536
 
240
537
  ```tsx
241
538
  <DashboardLineChart
@@ -249,9 +546,23 @@ Dashboard-ready chart wrappers handle loading, empty data, and connection errors
249
546
  errorTitle="Connection error"
250
547
  errorDescription="Unable to load analytics data."
251
548
  />
549
+
550
+ // State props work on all dashboard-ready wrappers:
551
+ <RadarMetricChart
552
+ data={skillData}
553
+ labelKey="skill"
554
+ series={[{ key: 'score', label: 'Score' }]}
555
+ isLoading={isLoading}
556
+ error={error}
557
+ onRetry={refetch}
558
+ />
252
559
  ```
253
560
 
254
- State props are available on `DashboardBarChart`, `DashboardLineChart`, `HorizontalBarChart`, `InteractiveTimeSeriesChart`, `ComboMetricChart`, and `DonutBreakdownChart`.
561
+ State props (`isLoading`, `error`, `onRetry`, `retryLabel`, `emptyTitle`, `emptyDescription`, `errorTitle`, `errorDescription`, `loadingLabel`, `stateClassName`) are available on: `DashboardBarChart`, `DashboardLineChart`, `HorizontalBarChart`, `InteractiveTimeSeriesChart`, `ComboMetricChart`, `DonutBreakdownChart`, `RadarMetricChart`, `PieMetricChart`, and `RadialBarMetricChart`.
562
+
563
+ > `GaugeChart` does not extend `ChartStateProps` — it is a pure display component with no async state.
564
+
565
+ ---
255
566
 
256
567
  ### Stacked Bar Chart
257
568
 
@@ -317,10 +628,14 @@ Bar-based dashboard charts support `barSize="sm" | "md" | "lg" | "xl"` or a nume
317
628
  - `ChartContainer` already wraps `ResponsiveContainer width="100%" height="100%"` — do not add another one.
318
629
  - Set height on `ChartContainer` via `className="h-[300px]"` — this sizes the container, not the Recharts elements.
319
630
  - Import all base Recharts components (`BarChart`, `Bar`, `Line`, etc.) directly from `recharts` — they are not re-exported by `xertica-ui`.
320
- - For dashboard-ready charts, prefer `ChartCard` plus `DashboardBarChart`, `DashboardLineChart`, `HorizontalBarChart`, `InteractiveTimeSeriesChart`, `ComboMetricChart`, or `DonutBreakdownChart` before hand-assembling Recharts primitives.
631
+ - For dashboard-ready charts, prefer `ChartCard` plus a dashboard-ready wrapper before hand-assembling Recharts primitives.
321
632
  - In FSD apps, keep data fetching in the feature/model layer and pass `data`, `isLoading`, `error`, and `onRetry` into chart wrappers.
322
633
  - Use `barSize` to control bar thickness. Do not use a chart wrapper prop to control graph width; layout width belongs to the parent grid/container.
323
634
  - When using `stacked`, order your `series` array so the visually topmost series is last — it will automatically receive the rounded top corners.
635
+ - `RadarMetricChart`, `PieMetricChart`, and `RadialBarMetricChart` build their `ChartConfig` internally from the `series`/`nameKey` data — you do not need to pass a `config` prop.
636
+ - `GaugeChart` is a pure SVG component — it does not use `ChartContainer` or Recharts. Wrap it in a `div` with `flex justify-center` to control its width.
637
+ - For `GaugeChart` thresholds, use `--chart-*` CSS tokens for colors so they remain theme-aware. Never use raw hex values.
638
+ - `RadialBarMetricChart` renders its legend as HTML below the chart (not inside the SVG) — this is intentional to avoid Recharts polar chart legend positioning issues.
324
639
 
325
640
  ---
326
641
 
@@ -0,0 +1,108 @@
1
+ # CodeBlock
2
+
3
+ A syntax-highlighted code display component with a one-click copy button. Designed for use inside AI chat messages and documentation panels.
4
+
5
+ ---
6
+
7
+ ## Import
8
+
9
+ ```tsx
10
+ import { CodeBlock } from 'xertica-ui/assistant';
11
+ ```
12
+
13
+ ---
14
+
15
+ ## Basic Usage
16
+
17
+ ```tsx
18
+ <CodeBlock
19
+ language="typescript"
20
+ code={`function greet(name: string): string {
21
+ return \`Hello, \${name}!\`;
22
+ }`}
23
+ />
24
+ ```
25
+
26
+ ---
27
+
28
+ ## Props
29
+
30
+ | Prop | Type | Default | Description |
31
+ |---|---|---|---|
32
+ | `code` | `string` | _(required)_ | The source code string to display |
33
+ | `language` | `string` | `'text'` | Language identifier for syntax highlighting (e.g. `'typescript'`, `'python'`, `'bash'`) |
34
+ | `className` | `string` | — | Additional CSS classes for the outer container |
35
+
36
+ ---
37
+
38
+ ## Features
39
+
40
+ ### Syntax Highlighting
41
+
42
+ Uses `react-syntax-highlighter` (Prism engine) with a custom theme built on Xertica UI design tokens:
43
+
44
+ - **Keywords / operators**: `var(--chart-1)` (primary accent)
45
+ - **Strings**: `var(--chart-2)` (green-toned)
46
+ - **Numbers / booleans**: `var(--chart-5)` (amber-toned)
47
+ - **Properties / attributes**: `var(--chart-4)` (blue-toned)
48
+ - **Comments**: `var(--muted-foreground)` (subdued)
49
+ - **Background**: transparent (inherits from parent card)
50
+
51
+ The theme automatically adapts to light and dark mode via CSS custom properties.
52
+
53
+ ### Copy Button
54
+
55
+ A copy-to-clipboard button appears in the top-right corner of the code block. After clicking:
56
+ - The icon changes from `Copy` to `Check` for 2 seconds
57
+ - The code string is written to the clipboard via the Clipboard API
58
+
59
+ ### Supported Languages
60
+
61
+ Any language supported by Prism.js is valid. Common examples:
62
+
63
+ ```
64
+ typescript javascript tsx jsx
65
+ python bash sql json
66
+ css html yaml markdown
67
+ ```
68
+
69
+ ---
70
+
71
+ ## Usage in AI Context
72
+
73
+ `CodeBlock` is used internally by `XerticaAssistant` to render code snippets returned by the AI. When the assistant response contains a fenced code block (` ```language `), it is automatically rendered as a `CodeBlock`.
74
+
75
+ To render code blocks in a standalone context:
76
+
77
+ ```tsx
78
+ import { CodeBlock } from 'xertica-ui/assistant';
79
+
80
+ function AiResponse({ content }: { content: string }) {
81
+ // Parse code blocks from markdown and render them
82
+ return (
83
+ <CodeBlock
84
+ language="python"
85
+ code="print('Hello from AI')"
86
+ />
87
+ );
88
+ }
89
+ ```
90
+
91
+ ---
92
+
93
+ ## Design Notes
94
+
95
+ - The component uses `font-mono` (CSS variable `--font-mono`) for the code font
96
+ - Font size is fixed at `0.875rem` (14px) for readability in narrow panels
97
+ - Line height is `1.6` for comfortable reading
98
+ - Tab size is 2 spaces
99
+ - Horizontal overflow scrolls within the block (no line wrapping)
100
+
101
+ ---
102
+
103
+ ## AI Rules
104
+
105
+ > [!IMPORTANT]
106
+ > - **Always provide `language`**: Without it, syntax highlighting falls back to plain text. Use the correct language identifier (e.g. `'typescript'` not `'ts'`, `'javascript'` not `'js'`).
107
+ > - **Do not wrap in `<pre>` or `<code>`**: `CodeBlock` renders its own `<pre>` via `react-syntax-highlighter`. Wrapping it will break the layout.
108
+ > - **Optimized for narrow panels**: This component is designed for the AI Assistant sidebar (~400px). For full-page code display, consider adding `className="w-full"`.