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.
- package/CHANGELOG.md +46 -0
- package/README.md +1 -1
- package/bin/cli.ts +1 -1
- package/bin/generate-tokens.ts +13 -7
- package/components/assistant/xertica-assistant/index.ts +2 -0
- package/components/assistant/xertica-assistant/parts/AssistantCollapsedView.tsx +97 -0
- package/components/assistant/xertica-assistant/parts/AssistantConversationList.tsx +104 -0
- package/components/assistant/xertica-assistant/parts/AssistantDocumentEditor.tsx +81 -0
- package/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.tsx +86 -0
- package/components/assistant/xertica-assistant/parts/AssistantHeader.tsx +77 -0
- package/components/assistant/xertica-assistant/parts/AssistantMessageBubble.tsx +573 -0
- package/components/assistant/xertica-assistant/parts/AssistantTabBar.tsx +65 -0
- package/components/assistant/xertica-assistant/parts/AssistantTypingIndicator.tsx +41 -0
- package/components/assistant/xertica-assistant/parts/AssistantWelcomeScreen.tsx +98 -0
- package/components/assistant/xertica-assistant/parts/index.ts +16 -0
- package/components/assistant/xertica-assistant/types.ts +139 -0
- package/components/assistant/xertica-assistant/use-assistant.ts +559 -0
- package/components/assistant/xertica-assistant/xertica-assistant.stories.tsx +200 -0
- package/components/assistant/xertica-assistant/xertica-assistant.tsx +198 -1460
- package/components/brand/theme-toggle/ThemeToggle.tsx +8 -27
- package/components/hooks/index.ts +3 -0
- package/components/hooks/use-layout-shortcuts.ts +46 -0
- package/components/layout/sidebar/index.ts +2 -0
- package/components/layout/sidebar/sidebar.stories.tsx +160 -8
- package/components/layout/sidebar/sidebar.tsx +606 -497
- package/components/layout/sidebar/use-sidebar.ts +104 -0
- package/components/media/audio-player/AudioPlayer.tsx +131 -206
- package/components/media/audio-player/use-audio-player.ts +298 -0
- package/components/pages/home-page/HomePage.tsx +1 -1
- package/components/pages/template-content/TemplateContent.tsx +5 -5
- package/components/pages/template-page/TemplatePage.tsx +5 -5
- package/components/shared/CustomTooltipContent.tsx +52 -0
- package/components/shared/layout-constants.ts +1 -1
- package/components/ui/chart/chart.stories.tsx +966 -7
- package/components/ui/chart/chart.tsx +918 -45
- package/components/ui/file-upload/file-upload.stories.tsx +100 -0
- package/components/ui/file-upload/file-upload.tsx +14 -74
- package/components/ui/file-upload/index.ts +1 -0
- package/components/ui/file-upload/use-file-upload.ts +181 -0
- package/components/ui/pagination/index.ts +2 -0
- package/components/ui/pagination/pagination.stories.tsx +94 -0
- package/components/ui/pagination/use-pagination.ts +194 -0
- package/components/ui/rich-text-editor/index.ts +2 -0
- package/components/ui/rich-text-editor/rich-text-editor.stories.tsx +129 -1
- package/components/ui/rich-text-editor/rich-text-editor.tsx +86 -305
- package/components/ui/rich-text-editor/use-rich-text-editor.ts +439 -0
- package/components/ui/stepper/index.ts +3 -1
- package/components/ui/stepper/stepper.stories.tsx +116 -0
- package/components/ui/stepper/stepper.tsx +4 -4
- package/components/ui/stepper/use-stepper.ts +137 -0
- package/components/ui/tree-view/index.ts +4 -1
- package/components/ui/tree-view/tree-view.stories.tsx +110 -4
- package/components/ui/tree-view/tree-view.tsx +17 -125
- package/components/ui/tree-view/use-tree-view.ts +229 -0
- package/contexts/AssistenteContext.tsx +17 -54
- package/contexts/BrandColorsContext.tsx +6 -17
- package/contexts/LayoutContext.tsx +5 -31
- package/dist/AssistantChart-BAudAfne.cjs +3591 -0
- package/dist/AssistantChart-BP8upjMk.js +3565 -0
- package/dist/AudioPlayer-1ypwE2Wh.cjs +936 -0
- package/dist/AudioPlayer-DuKXrCfy.js +937 -0
- package/dist/CustomTooltipContent-DHjkY0ww.js +40 -0
- package/dist/CustomTooltipContent-c_K-DWRr.cjs +56 -0
- package/dist/LanguageContext-BwhwC3G2.js +657 -0
- package/dist/LanguageContext-DvUt5jBg.cjs +656 -0
- package/dist/LayoutContext-BDmcZfMH.cjs +84 -0
- package/dist/LayoutContext-dbQvdC4O.js +85 -0
- package/dist/ThemeContext-RTy1m2Uq.js +82 -0
- package/dist/ThemeContext-bSzuOit2.cjs +81 -0
- package/dist/VerifyEmailPage-C_ihbcth.js +2828 -0
- package/dist/VerifyEmailPage-Dt7zgA4w.cjs +2827 -0
- package/dist/XerticaProvider-CW9hpCdF.cjs +39 -0
- package/dist/XerticaProvider-siSt9uG2.js +40 -0
- package/dist/XerticaXLogo-D8jf0SNv.cjs +214 -0
- package/dist/XerticaXLogo-fAJMy3H4.js +215 -0
- package/dist/assistant.cjs.js +2 -1
- package/dist/assistant.es.js +3 -2
- package/dist/brand.cjs.js +2 -2
- package/dist/brand.es.js +2 -2
- package/dist/cli.js +14 -8
- package/dist/components/assistant/xertica-assistant/index.d.ts +2 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantCollapsedView.d.ts +13 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantConversationList.d.ts +16 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantDocumentEditor.d.ts +17 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.d.ts +19 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantHeader.d.ts +11 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantMessageBubble.d.ts +29 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantTabBar.d.ts +13 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantTypingIndicator.d.ts +4 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantWelcomeScreen.d.ts +17 -0
- package/dist/components/assistant/xertica-assistant/parts/index.d.ts +16 -0
- package/dist/components/assistant/xertica-assistant/types.d.ts +106 -0
- package/dist/components/assistant/xertica-assistant/use-assistant.d.ts +125 -0
- package/dist/components/assistant/xertica-assistant/xertica-assistant.d.ts +8 -97
- package/dist/components/hooks/index.d.ts +3 -0
- package/dist/components/hooks/use-layout-shortcuts.d.ts +22 -0
- package/dist/components/layout/sidebar/index.d.ts +2 -0
- package/dist/components/layout/sidebar/sidebar.d.ts +80 -0
- package/dist/components/layout/sidebar/use-sidebar.d.ts +22 -0
- package/dist/components/media/audio-player/AudioPlayer.d.ts +4 -1
- package/dist/components/media/audio-player/use-audio-player.d.ts +72 -0
- package/dist/components/shared/CustomTooltipContent.d.ts +20 -0
- package/dist/components/shared/layout-constants.d.ts +1 -1
- package/dist/components/ui/alert/alert.d.ts +1 -1
- package/dist/components/ui/badge/badge.d.ts +1 -1
- package/dist/components/ui/button/button.d.ts +2 -2
- package/dist/components/ui/chart/chart.d.ts +162 -5
- package/dist/components/ui/file-upload/file-upload.d.ts +2 -0
- package/dist/components/ui/file-upload/index.d.ts +1 -0
- package/dist/components/ui/file-upload/use-file-upload.d.ts +49 -0
- package/dist/components/ui/pagination/index.d.ts +2 -0
- package/dist/components/ui/pagination/use-pagination.d.ts +78 -0
- package/dist/components/ui/rich-text-editor/index.d.ts +2 -0
- package/dist/components/ui/rich-text-editor/use-rich-text-editor.d.ts +107 -0
- package/dist/components/ui/stepper/index.d.ts +3 -1
- package/dist/components/ui/stepper/stepper.d.ts +2 -2
- package/dist/components/ui/stepper/use-stepper.d.ts +60 -0
- package/dist/components/ui/tree-view/index.d.ts +4 -1
- package/dist/components/ui/tree-view/tree-view.d.ts +4 -6
- package/dist/components/ui/tree-view/use-tree-view.d.ts +60 -0
- package/dist/contexts/AssistenteContext.d.ts +10 -49
- package/dist/hooks.cjs.js +30 -10
- package/dist/hooks.es.js +25 -4
- package/dist/index.cjs.js +20 -9
- package/dist/index.es.js +38 -27
- package/dist/layout.cjs.js +82 -1
- package/dist/layout.es.js +83 -2
- package/dist/media.cjs.js +1 -1
- package/dist/media.es.js +1 -1
- package/dist/pages.cjs.js +1 -1
- package/dist/pages.es.js +1 -1
- package/dist/rich-text-editor-BmsjY03B.js +2949 -0
- package/dist/rich-text-editor-GS2kpTAK.cjs +2966 -0
- package/dist/sidebar-CVUGHOS_.cjs +756 -0
- package/dist/sidebar-CmvwjnVb.js +757 -0
- package/dist/ui.cjs.js +12 -2
- package/dist/ui.es.js +24 -14
- package/dist/use-audio-player-Bkh23vQ3.js +177 -0
- package/dist/use-audio-player-Dn1NR9xN.cjs +176 -0
- package/dist/utils/color-utils.d.ts +51 -0
- package/dist/xertica-assistant-BMqdyRVi.js +2082 -0
- package/dist/xertica-assistant-Bj3vBCq_.cjs +2081 -0
- package/dist/xertica-ui.css +1 -1
- package/docs/ai-usage.md +28 -10
- package/docs/architecture-improvements.md +463 -0
- package/docs/architecture.md +77 -1
- package/docs/components/assistant-chart.md +1 -1
- package/docs/components/assistant.md +159 -0
- package/docs/components/audio-player.md +46 -0
- package/docs/components/branding.md +251 -0
- package/docs/components/chart.md +354 -39
- package/docs/components/code-block.md +108 -0
- package/docs/components/file-upload.md +119 -2
- package/docs/components/formatted-document.md +113 -0
- package/docs/components/hooks.md +430 -0
- package/docs/components/image-with-fallback.md +106 -0
- package/docs/components/map-layers.md +140 -0
- package/docs/components/modern-chat-input.md +163 -0
- package/docs/components/pages.md +351 -0
- package/docs/components/pagination.md +187 -0
- package/docs/components/rich-text-editor.md +164 -0
- package/docs/components/sidebar.md +153 -4
- package/docs/components/stepper.md +157 -12
- package/docs/components/tree-view.md +164 -6
- package/docs/doc-audit.md +223 -0
- package/docs/getting-started.md +155 -1
- package/docs/guidelines.md +14 -8
- package/docs/layout.md +2 -2
- package/docs/llms.md +29 -9
- package/docs/patterns/detail-page.md +276 -0
- package/docs/patterns/settings.md +346 -0
- package/docs/patterns/wizard.md +217 -0
- package/guidelines/Guidelines.md +5 -3
- package/llms.txt +1 -1
- package/package.json +10 -10
- package/styles/xertica/tokens.css +41 -12
- package/templates/CLAUDE.md +16 -6
- package/templates/guidelines/Guidelines.md +16 -4
- package/templates/package.json +3 -3
- package/templates/src/styles/xertica/tokens.css +39 -10
- package/utils/color-utils.ts +72 -0
package/docs/components/chart.md
CHANGED
|
@@ -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
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
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
|
-
|
|
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 `
|
|
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
|
|
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"`.
|