@htlkg/components 0.0.1
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/dist/composables/index.js +388 -0
- package/dist/composables/index.js.map +1 -0
- package/package.json +41 -0
- package/src/composables/index.ts +6 -0
- package/src/composables/useForm.test.ts +229 -0
- package/src/composables/useForm.ts +130 -0
- package/src/composables/useFormValidation.test.ts +189 -0
- package/src/composables/useFormValidation.ts +83 -0
- package/src/composables/useModal.property.test.ts +164 -0
- package/src/composables/useModal.ts +43 -0
- package/src/composables/useNotifications.test.ts +166 -0
- package/src/composables/useNotifications.ts +81 -0
- package/src/composables/useTable.property.test.ts +198 -0
- package/src/composables/useTable.ts +134 -0
- package/src/composables/useTabs.property.test.ts +247 -0
- package/src/composables/useTabs.ts +101 -0
- package/src/data/Chart.demo.vue +340 -0
- package/src/data/Chart.md +525 -0
- package/src/data/Chart.vue +133 -0
- package/src/data/DataList.md +80 -0
- package/src/data/DataList.test.ts +69 -0
- package/src/data/DataList.vue +46 -0
- package/src/data/SearchableSelect.md +107 -0
- package/src/data/SearchableSelect.vue +124 -0
- package/src/data/Table.demo.vue +296 -0
- package/src/data/Table.md +588 -0
- package/src/data/Table.property.test.ts +548 -0
- package/src/data/Table.test.ts +562 -0
- package/src/data/Table.unit.test.ts +544 -0
- package/src/data/Table.vue +321 -0
- package/src/data/index.ts +5 -0
- package/src/domain/BrandCard.md +81 -0
- package/src/domain/BrandCard.vue +63 -0
- package/src/domain/BrandSelector.md +84 -0
- package/src/domain/BrandSelector.vue +65 -0
- package/src/domain/ProductBadge.md +60 -0
- package/src/domain/ProductBadge.vue +47 -0
- package/src/domain/UserAvatar.md +84 -0
- package/src/domain/UserAvatar.vue +60 -0
- package/src/domain/domain-components.property.test.ts +449 -0
- package/src/domain/index.ts +4 -0
- package/src/forms/DateRange.demo.vue +273 -0
- package/src/forms/DateRange.md +337 -0
- package/src/forms/DateRange.vue +110 -0
- package/src/forms/JsonSchemaForm.demo.vue +549 -0
- package/src/forms/JsonSchemaForm.md +112 -0
- package/src/forms/JsonSchemaForm.property.test.ts +817 -0
- package/src/forms/JsonSchemaForm.test.ts +601 -0
- package/src/forms/JsonSchemaForm.unit.test.ts +801 -0
- package/src/forms/JsonSchemaForm.vue +615 -0
- package/src/forms/index.ts +3 -0
- package/src/index.ts +17 -0
- package/src/navigation/Breadcrumbs.demo.vue +142 -0
- package/src/navigation/Breadcrumbs.md +102 -0
- package/src/navigation/Breadcrumbs.test.ts +69 -0
- package/src/navigation/Breadcrumbs.vue +58 -0
- package/src/navigation/Stepper.demo.vue +337 -0
- package/src/navigation/Stepper.md +174 -0
- package/src/navigation/Stepper.vue +146 -0
- package/src/navigation/Tabs.demo.vue +293 -0
- package/src/navigation/Tabs.md +163 -0
- package/src/navigation/Tabs.test.ts +176 -0
- package/src/navigation/Tabs.vue +104 -0
- package/src/navigation/index.ts +5 -0
- package/src/overlays/Alert.demo.vue +377 -0
- package/src/overlays/Alert.md +248 -0
- package/src/overlays/Alert.test.ts +166 -0
- package/src/overlays/Alert.vue +70 -0
- package/src/overlays/Drawer.md +140 -0
- package/src/overlays/Drawer.test.ts +92 -0
- package/src/overlays/Drawer.vue +76 -0
- package/src/overlays/Modal.demo.vue +149 -0
- package/src/overlays/Modal.md +385 -0
- package/src/overlays/Modal.test.ts +128 -0
- package/src/overlays/Modal.vue +86 -0
- package/src/overlays/Notification.md +150 -0
- package/src/overlays/Notification.test.ts +96 -0
- package/src/overlays/Notification.vue +58 -0
- package/src/overlays/index.ts +4 -0
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
# Chart Component
|
|
2
|
+
|
|
3
|
+
A powerful charting component for data visualization supporting multiple chart types (line, area, bar, scatter). Built on top of `uiChart` from `@hotelinking/ui` which uses ApexCharts internally.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Multiple chart types**: Line, area, bar, and scatter charts
|
|
8
|
+
- **Interactive**: Hover tooltips, data point selection, zoom capabilities
|
|
9
|
+
- **Time range selector**: Built-in time range buttons (24h, 7d, 1m, 3m, all)
|
|
10
|
+
- **Date range support**: Custom date range selection
|
|
11
|
+
- **Loading state**: Skeleton loader while data is fetching
|
|
12
|
+
- **Empty state**: Displays message when no data is available
|
|
13
|
+
- **Responsive**: Adapts to container size
|
|
14
|
+
- **Horizontal/Vertical**: Support for horizontal bar charts
|
|
15
|
+
- **Stacked charts**: Stack multiple series
|
|
16
|
+
- **Annotations**: Add reference lines and labels
|
|
17
|
+
- **NPS support**: Special mode for Net Promoter Score charts
|
|
18
|
+
- **Customizable**: Full control over ApexCharts options
|
|
19
|
+
- **Maximize**: Full-screen chart view
|
|
20
|
+
- **Exposed methods**: Programmatic control via `refresh()`, `getChartId()`
|
|
21
|
+
|
|
22
|
+
## Import
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { Chart } from '@htlkg/components';
|
|
26
|
+
import type { ChartSeries, ChartOptions, ChartDateRange, ChartAnnotation } from '@htlkg/components';
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Props
|
|
30
|
+
|
|
31
|
+
| Prop | Type | Default | Description |
|
|
32
|
+
|------|------|---------|-------------|
|
|
33
|
+
| `id` | `string` | **required** | Unique identifier for the chart |
|
|
34
|
+
| `title` | `string` | **required** | Chart title displayed at the top |
|
|
35
|
+
| `series` | `ChartSeries[]` | **required** | Data series to display |
|
|
36
|
+
| `type` | `'area' \| 'line' \| 'bar' \| 'scatter'` | `'line'` | Chart type |
|
|
37
|
+
| `options` | `ChartOptions` | `undefined` | ApexCharts configuration options |
|
|
38
|
+
| `loading` | `boolean` | `false` | Shows skeleton loader when true |
|
|
39
|
+
| `empty` | `boolean` | `false` | Shows empty state when true |
|
|
40
|
+
| `range` | `'24h' \| '7d' \| '1m' \| '3m' \| 'all'` | `undefined` | Selected time range |
|
|
41
|
+
| `horizontal` | `boolean` | `false` | Horizontal orientation for bar charts |
|
|
42
|
+
| `stacked` | `boolean` | `false` | Stack multiple series |
|
|
43
|
+
| `height` | `number` | `undefined` | Custom chart height in pixels |
|
|
44
|
+
| `labels` | `string[]` | `undefined` | X-axis labels |
|
|
45
|
+
| `dates` | `ChartDateRange` | `undefined` | Date range for the chart |
|
|
46
|
+
| `isNps` | `boolean` | `false` | Enable NPS (Net Promoter Score) mode |
|
|
47
|
+
| `npsLiterals` | `NpsLiterals` | `undefined` | Labels for NPS chart sections |
|
|
48
|
+
| `annotations` | `ChartAnnotation` | `undefined` | Reference lines and labels |
|
|
49
|
+
|
|
50
|
+
### Type Definitions
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
interface ChartSeries {
|
|
54
|
+
name: string;
|
|
55
|
+
type?: 'area' | 'line' | 'bar' | 'scatter';
|
|
56
|
+
data: number[];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface ChartOptions {
|
|
60
|
+
xaxis?: {
|
|
61
|
+
tickAmount?: number;
|
|
62
|
+
decimalsInFloat?: number;
|
|
63
|
+
hideOverlappingLabels?: boolean;
|
|
64
|
+
type?: string;
|
|
65
|
+
max?: number;
|
|
66
|
+
categories?: string[];
|
|
67
|
+
};
|
|
68
|
+
tooltip?: {
|
|
69
|
+
intersect?: boolean;
|
|
70
|
+
};
|
|
71
|
+
[key: string]: any; // Supports all ApexCharts options
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
interface ChartDateRange {
|
|
75
|
+
from: Date | string;
|
|
76
|
+
to: Date | string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
interface ChartAnnotation {
|
|
80
|
+
text: string;
|
|
81
|
+
high: number;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface NpsLiterals {
|
|
85
|
+
unhappy: string;
|
|
86
|
+
neutral: string;
|
|
87
|
+
happy: string;
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Events
|
|
92
|
+
|
|
93
|
+
| Event | Payload | Description |
|
|
94
|
+
|-------|---------|-------------|
|
|
95
|
+
| `range-selected` | `{ range: ChartDateRange; chartId: string }` | Emitted when time range is selected |
|
|
96
|
+
| `chart-updated` | - | Emitted when chart data is updated |
|
|
97
|
+
| `data-point-selection` | `any` | Emitted when user clicks on a data point |
|
|
98
|
+
| `maximize` | `string` (chartId) | Emitted when maximize button is clicked |
|
|
99
|
+
|
|
100
|
+
## Exposed Methods
|
|
101
|
+
|
|
102
|
+
| Method | Parameters | Returns | Description |
|
|
103
|
+
|--------|------------|---------|-------------|
|
|
104
|
+
| `refresh()` | - | `void` | Triggers chart refresh |
|
|
105
|
+
| `getChartId()` | - | `string` | Returns the chart ID |
|
|
106
|
+
|
|
107
|
+
## Usage Examples
|
|
108
|
+
|
|
109
|
+
### Basic Line Chart
|
|
110
|
+
|
|
111
|
+
```vue
|
|
112
|
+
<template>
|
|
113
|
+
<Chart
|
|
114
|
+
id="sales-chart"
|
|
115
|
+
title="Monthly Sales"
|
|
116
|
+
type="line"
|
|
117
|
+
:series="salesData"
|
|
118
|
+
:options="chartOptions"
|
|
119
|
+
:loading="loading"
|
|
120
|
+
/>
|
|
121
|
+
</template>
|
|
122
|
+
|
|
123
|
+
<script setup lang="ts">
|
|
124
|
+
import { ref } from 'vue';
|
|
125
|
+
import { Chart } from '@htlkg/components';
|
|
126
|
+
import type { ChartSeries, ChartOptions } from '@htlkg/components';
|
|
127
|
+
|
|
128
|
+
const loading = ref(false);
|
|
129
|
+
|
|
130
|
+
const salesData: ChartSeries[] = [
|
|
131
|
+
{
|
|
132
|
+
name: 'Revenue',
|
|
133
|
+
data: [30, 40, 45, 50, 49, 60, 70, 91, 125, 140, 165, 180]
|
|
134
|
+
}
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
const chartOptions: ChartOptions = {
|
|
138
|
+
xaxis: {
|
|
139
|
+
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
|
140
|
+
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
|
141
|
+
},
|
|
142
|
+
tooltip: {
|
|
143
|
+
intersect: false
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
</script>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Area Chart with Multiple Series
|
|
150
|
+
|
|
151
|
+
```vue
|
|
152
|
+
<template>
|
|
153
|
+
<Chart
|
|
154
|
+
id="traffic-chart"
|
|
155
|
+
title="Website Traffic"
|
|
156
|
+
type="area"
|
|
157
|
+
:series="trafficData"
|
|
158
|
+
:options="chartOptions"
|
|
159
|
+
:loading="loading"
|
|
160
|
+
@data-point-selection="handlePointClick"
|
|
161
|
+
/>
|
|
162
|
+
</template>
|
|
163
|
+
|
|
164
|
+
<script setup lang="ts">
|
|
165
|
+
import { ref } from 'vue';
|
|
166
|
+
import { Chart } from '@htlkg/components';
|
|
167
|
+
import type { ChartSeries } from '@htlkg/components';
|
|
168
|
+
|
|
169
|
+
const loading = ref(false);
|
|
170
|
+
|
|
171
|
+
const trafficData: ChartSeries[] = [
|
|
172
|
+
{
|
|
173
|
+
name: 'Visitors',
|
|
174
|
+
data: [30, 40, 45, 50, 49, 60, 70, 91, 125]
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
name: 'Page Views',
|
|
178
|
+
data: [50, 60, 70, 80, 75, 90, 100, 130, 180]
|
|
179
|
+
}
|
|
180
|
+
];
|
|
181
|
+
|
|
182
|
+
const chartOptions = {
|
|
183
|
+
xaxis: {
|
|
184
|
+
categories: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun', 'Mon', 'Tue']
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
function handlePointClick(data: any) {
|
|
189
|
+
console.log('Clicked data point:', data);
|
|
190
|
+
}
|
|
191
|
+
</script>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Horizontal Bar Chart
|
|
195
|
+
|
|
196
|
+
```vue
|
|
197
|
+
<template>
|
|
198
|
+
<Chart
|
|
199
|
+
id="locations-chart"
|
|
200
|
+
title="Top Locations"
|
|
201
|
+
type="bar"
|
|
202
|
+
:series="locationsData"
|
|
203
|
+
:options="chartOptions"
|
|
204
|
+
:loading="loading"
|
|
205
|
+
horizontal
|
|
206
|
+
/>
|
|
207
|
+
</template>
|
|
208
|
+
|
|
209
|
+
<script setup lang="ts">
|
|
210
|
+
import { ref } from 'vue';
|
|
211
|
+
import { Chart } from '@htlkg/components';
|
|
212
|
+
|
|
213
|
+
const loading = ref(false);
|
|
214
|
+
|
|
215
|
+
const locationsData = [
|
|
216
|
+
{
|
|
217
|
+
name: 'Sessions',
|
|
218
|
+
data: [400, 300, 250, 200, 150]
|
|
219
|
+
}
|
|
220
|
+
];
|
|
221
|
+
|
|
222
|
+
const chartOptions = {
|
|
223
|
+
xaxis: {
|
|
224
|
+
categories: ['New York', 'London', 'Tokyo', 'Paris', 'Berlin']
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
</script>
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Stacked Bar Chart
|
|
231
|
+
|
|
232
|
+
```vue
|
|
233
|
+
<template>
|
|
234
|
+
<Chart
|
|
235
|
+
id="revenue-chart"
|
|
236
|
+
title="Revenue by Product"
|
|
237
|
+
type="bar"
|
|
238
|
+
:series="revenueData"
|
|
239
|
+
:options="chartOptions"
|
|
240
|
+
:loading="loading"
|
|
241
|
+
stacked
|
|
242
|
+
/>
|
|
243
|
+
</template>
|
|
244
|
+
|
|
245
|
+
<script setup lang="ts">
|
|
246
|
+
import { ref } from 'vue';
|
|
247
|
+
import { Chart } from '@htlkg/components';
|
|
248
|
+
|
|
249
|
+
const loading = ref(false);
|
|
250
|
+
|
|
251
|
+
const revenueData = [
|
|
252
|
+
{
|
|
253
|
+
name: 'Product A',
|
|
254
|
+
data: [44, 55, 41, 67, 22, 43]
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
name: 'Product B',
|
|
258
|
+
data: [13, 23, 20, 8, 13, 27]
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
name: 'Product C',
|
|
262
|
+
data: [11, 17, 15, 15, 21, 14]
|
|
263
|
+
}
|
|
264
|
+
];
|
|
265
|
+
|
|
266
|
+
const chartOptions = {
|
|
267
|
+
xaxis: {
|
|
268
|
+
categories: ['Q1', 'Q2', 'Q3', 'Q4', 'Q5', 'Q6']
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
</script>
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Chart with Time Range Selector
|
|
275
|
+
|
|
276
|
+
```vue
|
|
277
|
+
<template>
|
|
278
|
+
<Chart
|
|
279
|
+
id="analytics-chart"
|
|
280
|
+
title="Analytics Overview"
|
|
281
|
+
type="area"
|
|
282
|
+
:series="analyticsData"
|
|
283
|
+
:options="chartOptions"
|
|
284
|
+
:loading="loading"
|
|
285
|
+
:range="selectedRange"
|
|
286
|
+
@range-selected="handleRangeChange"
|
|
287
|
+
/>
|
|
288
|
+
</template>
|
|
289
|
+
|
|
290
|
+
<script setup lang="ts">
|
|
291
|
+
import { ref } from 'vue';
|
|
292
|
+
import { Chart } from '@htlkg/components';
|
|
293
|
+
import type { ChartDateRange } from '@htlkg/components';
|
|
294
|
+
|
|
295
|
+
const loading = ref(false);
|
|
296
|
+
const selectedRange = ref<'24h' | '7d' | '1m' | '3m' | 'all'>('7d');
|
|
297
|
+
|
|
298
|
+
const analyticsData = [
|
|
299
|
+
{
|
|
300
|
+
name: 'Users',
|
|
301
|
+
data: [30, 40, 45, 50, 49, 60, 70]
|
|
302
|
+
}
|
|
303
|
+
];
|
|
304
|
+
|
|
305
|
+
const chartOptions = {
|
|
306
|
+
xaxis: {
|
|
307
|
+
categories: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
function handleRangeChange(data: { range: ChartDateRange; chartId: string }) {
|
|
312
|
+
console.log('Range changed:', data.range);
|
|
313
|
+
// Fetch new data for the selected range
|
|
314
|
+
loading.value = true;
|
|
315
|
+
// await fetchData(data.range.from, data.range.to);
|
|
316
|
+
loading.value = false;
|
|
317
|
+
}
|
|
318
|
+
</script>
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Chart with Annotations
|
|
322
|
+
|
|
323
|
+
```vue
|
|
324
|
+
<template>
|
|
325
|
+
<Chart
|
|
326
|
+
id="performance-chart"
|
|
327
|
+
title="Performance Metrics"
|
|
328
|
+
type="line"
|
|
329
|
+
:series="performanceData"
|
|
330
|
+
:options="chartOptions"
|
|
331
|
+
:annotations="annotation"
|
|
332
|
+
:loading="loading"
|
|
333
|
+
/>
|
|
334
|
+
</template>
|
|
335
|
+
|
|
336
|
+
<script setup lang="ts">
|
|
337
|
+
import { ref } from 'vue';
|
|
338
|
+
import { Chart } from '@htlkg/components';
|
|
339
|
+
import type { ChartAnnotation } from '@htlkg/components';
|
|
340
|
+
|
|
341
|
+
const loading = ref(false);
|
|
342
|
+
|
|
343
|
+
const performanceData = [
|
|
344
|
+
{
|
|
345
|
+
name: 'Response Time',
|
|
346
|
+
data: [120, 150, 170, 140, 160, 180, 200, 190]
|
|
347
|
+
}
|
|
348
|
+
];
|
|
349
|
+
|
|
350
|
+
const chartOptions = {
|
|
351
|
+
xaxis: {
|
|
352
|
+
categories: ['00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00']
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
const annotation: ChartAnnotation = {
|
|
357
|
+
text: 'Target: 150ms',
|
|
358
|
+
high: 150
|
|
359
|
+
};
|
|
360
|
+
</script>
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Empty State
|
|
364
|
+
|
|
365
|
+
```vue
|
|
366
|
+
<template>
|
|
367
|
+
<Chart
|
|
368
|
+
id="empty-chart"
|
|
369
|
+
title="No Data Available"
|
|
370
|
+
type="line"
|
|
371
|
+
:series="[]"
|
|
372
|
+
:loading="false"
|
|
373
|
+
:empty="true"
|
|
374
|
+
/>
|
|
375
|
+
</template>
|
|
376
|
+
|
|
377
|
+
<script setup lang="ts">
|
|
378
|
+
import { Chart } from '@htlkg/components';
|
|
379
|
+
</script>
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### Loading State
|
|
383
|
+
|
|
384
|
+
```vue
|
|
385
|
+
<template>
|
|
386
|
+
<Chart
|
|
387
|
+
id="loading-chart"
|
|
388
|
+
title="Loading Data..."
|
|
389
|
+
type="area"
|
|
390
|
+
:series="chartData"
|
|
391
|
+
:loading="isLoading"
|
|
392
|
+
/>
|
|
393
|
+
</template>
|
|
394
|
+
|
|
395
|
+
<script setup lang="ts">
|
|
396
|
+
import { ref, onMounted } from 'vue';
|
|
397
|
+
import { Chart } from '@htlkg/components';
|
|
398
|
+
|
|
399
|
+
const isLoading = ref(true);
|
|
400
|
+
const chartData = ref([]);
|
|
401
|
+
|
|
402
|
+
onMounted(async () => {
|
|
403
|
+
// Simulate data loading
|
|
404
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
405
|
+
chartData.value = [
|
|
406
|
+
{
|
|
407
|
+
name: 'Data',
|
|
408
|
+
data: [10, 20, 30, 40, 50]
|
|
409
|
+
}
|
|
410
|
+
];
|
|
411
|
+
isLoading.value = false;
|
|
412
|
+
});
|
|
413
|
+
</script>
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### Programmatic Control
|
|
417
|
+
|
|
418
|
+
```vue
|
|
419
|
+
<template>
|
|
420
|
+
<div>
|
|
421
|
+
<button @click="refreshChart">Refresh Chart</button>
|
|
422
|
+
<Chart
|
|
423
|
+
ref="chartRef"
|
|
424
|
+
id="controlled-chart"
|
|
425
|
+
title="Controlled Chart"
|
|
426
|
+
type="line"
|
|
427
|
+
:series="chartData"
|
|
428
|
+
:loading="loading"
|
|
429
|
+
/>
|
|
430
|
+
</div>
|
|
431
|
+
</template>
|
|
432
|
+
|
|
433
|
+
<script setup lang="ts">
|
|
434
|
+
import { ref } from 'vue';
|
|
435
|
+
import { Chart } from '@htlkg/components';
|
|
436
|
+
|
|
437
|
+
const chartRef = ref<InstanceType<typeof Chart>>();
|
|
438
|
+
const loading = ref(false);
|
|
439
|
+
const chartData = ref([
|
|
440
|
+
{
|
|
441
|
+
name: 'Series 1',
|
|
442
|
+
data: [10, 20, 30, 40, 50]
|
|
443
|
+
}
|
|
444
|
+
]);
|
|
445
|
+
|
|
446
|
+
function refreshChart() {
|
|
447
|
+
loading.value = true;
|
|
448
|
+
// Fetch new data
|
|
449
|
+
setTimeout(() => {
|
|
450
|
+
chartData.value = [
|
|
451
|
+
{
|
|
452
|
+
name: 'Series 1',
|
|
453
|
+
data: [15, 25, 35, 45, 55]
|
|
454
|
+
}
|
|
455
|
+
];
|
|
456
|
+
chartRef.value?.refresh();
|
|
457
|
+
loading.value = false;
|
|
458
|
+
}, 1000);
|
|
459
|
+
}
|
|
460
|
+
</script>
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
## TypeScript Support
|
|
464
|
+
|
|
465
|
+
The component is fully typed with TypeScript:
|
|
466
|
+
|
|
467
|
+
```typescript
|
|
468
|
+
import { Chart } from '@htlkg/components';
|
|
469
|
+
import type { ChartSeries, ChartOptions, ChartDateRange } from '@htlkg/components';
|
|
470
|
+
|
|
471
|
+
// Type-safe series
|
|
472
|
+
const series: ChartSeries[] = [
|
|
473
|
+
{
|
|
474
|
+
name: 'Revenue',
|
|
475
|
+
type: 'area',
|
|
476
|
+
data: [100, 200, 300]
|
|
477
|
+
}
|
|
478
|
+
];
|
|
479
|
+
|
|
480
|
+
// Type-safe options
|
|
481
|
+
const options: ChartOptions = {
|
|
482
|
+
xaxis: {
|
|
483
|
+
categories: ['Jan', 'Feb', 'Mar'],
|
|
484
|
+
tickAmount: 3
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
// Type-safe ref
|
|
489
|
+
const chartRef = ref<InstanceType<typeof Chart>>();
|
|
490
|
+
chartRef.value?.refresh();
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
## Best Practices
|
|
494
|
+
|
|
495
|
+
1. **Provide meaningful titles**: Clear chart titles help users understand the data
|
|
496
|
+
2. **Use appropriate chart types**: Line for trends, bar for comparisons, area for cumulative data
|
|
497
|
+
3. **Limit data points**: Too many points can make charts hard to read
|
|
498
|
+
4. **Use consistent colors**: Maintain color consistency across related charts
|
|
499
|
+
5. **Add tooltips**: Enable tooltips for detailed information on hover
|
|
500
|
+
6. **Handle empty states**: Always provide feedback when no data is available
|
|
501
|
+
7. **Show loading states**: Use loading prop while fetching data
|
|
502
|
+
8. **Responsive design**: Charts should adapt to container size
|
|
503
|
+
9. **Accessibility**: Provide alternative text descriptions for screen readers
|
|
504
|
+
10. **Performance**: For large datasets, consider data aggregation or pagination
|
|
505
|
+
|
|
506
|
+
## Accessibility
|
|
507
|
+
|
|
508
|
+
- Chart title is properly labeled
|
|
509
|
+
- Interactive elements are keyboard accessible
|
|
510
|
+
- Color is not the only means of conveying information
|
|
511
|
+
- Consider providing data tables as alternatives for screen readers
|
|
512
|
+
|
|
513
|
+
## Demo
|
|
514
|
+
|
|
515
|
+
See the component in action at `/demo/components/chart`
|
|
516
|
+
|
|
517
|
+
## Related Components
|
|
518
|
+
|
|
519
|
+
- [DateRange](../forms/DateRange.md) - Often used to filter chart data
|
|
520
|
+
- [Table](./Table.md) - Complementary data visualization
|
|
521
|
+
- [DataList](./DataList.md) - Alternative list-based data display
|
|
522
|
+
|
|
523
|
+
## ApexCharts Documentation
|
|
524
|
+
|
|
525
|
+
For advanced customization, refer to the [ApexCharts documentation](https://apexcharts.com/docs/).
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<uiChart
|
|
3
|
+
:id="id"
|
|
4
|
+
:title="title"
|
|
5
|
+
:type="type"
|
|
6
|
+
:series="series"
|
|
7
|
+
:options="options"
|
|
8
|
+
:loading="loading"
|
|
9
|
+
:empty="empty"
|
|
10
|
+
:range="range"
|
|
11
|
+
:horizontal="horizontal"
|
|
12
|
+
:stacked="stacked"
|
|
13
|
+
:height="height"
|
|
14
|
+
:labels="labels"
|
|
15
|
+
:dates="dates"
|
|
16
|
+
:isNps="isNps"
|
|
17
|
+
:npsLiterals="npsLiterals"
|
|
18
|
+
:annotations="annotations"
|
|
19
|
+
@selectedRange="handleRangeSelected"
|
|
20
|
+
@chartUpdated="handleChartUpdated"
|
|
21
|
+
@dataPointSelection="handleDataPointSelection"
|
|
22
|
+
@maximizeChart="handleMaximizeChart"
|
|
23
|
+
/>
|
|
24
|
+
</template>
|
|
25
|
+
|
|
26
|
+
<script setup lang="ts">
|
|
27
|
+
import { ref, watch } from 'vue';
|
|
28
|
+
import { uiChart } from '@hotelinking/ui';
|
|
29
|
+
|
|
30
|
+
export interface ChartSeries {
|
|
31
|
+
name: string;
|
|
32
|
+
type?: 'area' | 'line' | 'bar' | 'scatter';
|
|
33
|
+
data: number[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ChartOptions {
|
|
37
|
+
xaxis?: {
|
|
38
|
+
tickAmount?: number;
|
|
39
|
+
decimalsInFloat?: number;
|
|
40
|
+
hideOverlappingLabels?: boolean;
|
|
41
|
+
type?: string;
|
|
42
|
+
max?: number;
|
|
43
|
+
categories?: string[];
|
|
44
|
+
};
|
|
45
|
+
tooltip?: {
|
|
46
|
+
intersect?: boolean;
|
|
47
|
+
};
|
|
48
|
+
[key: string]: any;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface ChartAnnotation {
|
|
52
|
+
text: string;
|
|
53
|
+
high: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface ChartDateRange {
|
|
57
|
+
from: Date | string;
|
|
58
|
+
to: Date | string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface NpsLiterals {
|
|
62
|
+
unhappy: string;
|
|
63
|
+
neutral: string;
|
|
64
|
+
happy: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
interface Props {
|
|
68
|
+
id: string;
|
|
69
|
+
title: string;
|
|
70
|
+
series: ChartSeries[];
|
|
71
|
+
type?: 'area' | 'line' | 'bar' | 'scatter';
|
|
72
|
+
options?: ChartOptions;
|
|
73
|
+
loading?: boolean;
|
|
74
|
+
empty?: boolean;
|
|
75
|
+
range?: '24h' | '7d' | '1m' | '3m' | 'all';
|
|
76
|
+
horizontal?: boolean;
|
|
77
|
+
stacked?: boolean;
|
|
78
|
+
height?: number;
|
|
79
|
+
labels?: string[];
|
|
80
|
+
dates?: ChartDateRange;
|
|
81
|
+
isNps?: boolean;
|
|
82
|
+
npsLiterals?: NpsLiterals;
|
|
83
|
+
annotations?: ChartAnnotation;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
87
|
+
type: 'line',
|
|
88
|
+
loading: false,
|
|
89
|
+
empty: false,
|
|
90
|
+
horizontal: false,
|
|
91
|
+
stacked: false,
|
|
92
|
+
isNps: false
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const emit = defineEmits<{
|
|
96
|
+
'range-selected': [data: { range: ChartDateRange; chartId: string }];
|
|
97
|
+
'chart-updated': [];
|
|
98
|
+
'data-point-selection': [data: any];
|
|
99
|
+
'maximize': [chartId: string];
|
|
100
|
+
}>();
|
|
101
|
+
|
|
102
|
+
// Handle events from uiChart
|
|
103
|
+
function handleRangeSelected(data: { range: ChartDateRange; chartId: string }) {
|
|
104
|
+
emit('range-selected', data);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function handleChartUpdated() {
|
|
108
|
+
emit('chart-updated');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function handleDataPointSelection(data: any) {
|
|
112
|
+
emit('data-point-selection', data);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function handleMaximizeChart(chartId: string) {
|
|
116
|
+
emit('maximize', chartId);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Exposed methods
|
|
120
|
+
function refresh() {
|
|
121
|
+
// Trigger chart refresh by emitting chart-updated
|
|
122
|
+
emit('chart-updated');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function getChartId() {
|
|
126
|
+
return props.id;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
defineExpose({
|
|
130
|
+
refresh,
|
|
131
|
+
getChartId
|
|
132
|
+
});
|
|
133
|
+
</script>
|