@matthieumordrel/chart-studio 0.1.0
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/LICENSE +21 -0
- package/README.md +371 -0
- package/dist/core/chart-capabilities.d.ts +60 -0
- package/dist/core/chart-capabilities.d.ts.map +1 -0
- package/dist/core/chart-capabilities.js +55 -0
- package/dist/core/chart-capabilities.js.map +1 -0
- package/dist/core/colors.d.ts +25 -0
- package/dist/core/colors.d.ts.map +1 -0
- package/dist/core/colors.js +55 -0
- package/dist/core/colors.js.map +1 -0
- package/dist/core/config-utils.d.ts +43 -0
- package/dist/core/config-utils.d.ts.map +1 -0
- package/dist/core/config-utils.js +81 -0
- package/dist/core/config-utils.js.map +1 -0
- package/dist/core/date-utils.d.ts +29 -0
- package/dist/core/date-utils.d.ts.map +1 -0
- package/dist/core/date-utils.js +59 -0
- package/dist/core/date-utils.js.map +1 -0
- package/dist/core/define-chart-schema.d.ts +105 -0
- package/dist/core/define-chart-schema.d.ts.map +1 -0
- package/dist/core/define-chart-schema.js +45 -0
- package/dist/core/define-chart-schema.js.map +1 -0
- package/dist/core/formatting.d.ts +47 -0
- package/dist/core/formatting.d.ts.map +1 -0
- package/dist/core/formatting.js +397 -0
- package/dist/core/formatting.js.map +1 -0
- package/dist/core/index.d.ts +17 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +13 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/infer-columns.d.ts +6 -0
- package/dist/core/infer-columns.d.ts.map +1 -0
- package/dist/core/infer-columns.js +513 -0
- package/dist/core/infer-columns.js.map +1 -0
- package/dist/core/metric-utils.d.ts +43 -0
- package/dist/core/metric-utils.d.ts.map +1 -0
- package/dist/core/metric-utils.js +142 -0
- package/dist/core/metric-utils.js.map +1 -0
- package/dist/core/pipeline-data-points.d.ts +23 -0
- package/dist/core/pipeline-data-points.d.ts.map +1 -0
- package/dist/core/pipeline-data-points.js +236 -0
- package/dist/core/pipeline-data-points.js.map +1 -0
- package/dist/core/pipeline-helpers.d.ts +38 -0
- package/dist/core/pipeline-helpers.d.ts.map +1 -0
- package/dist/core/pipeline-helpers.js +98 -0
- package/dist/core/pipeline-helpers.js.map +1 -0
- package/dist/core/pipeline.d.ts +70 -0
- package/dist/core/pipeline.d.ts.map +1 -0
- package/dist/core/pipeline.js +157 -0
- package/dist/core/pipeline.js.map +1 -0
- package/dist/core/types.d.ts +1109 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +15 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/use-chart-options.d.ts +66 -0
- package/dist/core/use-chart-options.d.ts.map +1 -0
- package/dist/core/use-chart-options.js +5 -0
- package/dist/core/use-chart-options.js.map +1 -0
- package/dist/core/use-chart-resolvers.d.ts +14 -0
- package/dist/core/use-chart-resolvers.d.ts.map +1 -0
- package/dist/core/use-chart-resolvers.js +42 -0
- package/dist/core/use-chart-resolvers.js.map +1 -0
- package/dist/core/use-chart.d.ts +47 -0
- package/dist/core/use-chart.d.ts.map +1 -0
- package/dist/core/use-chart.js +266 -0
- package/dist/core/use-chart.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/ui/chart-axis-ticks.d.ts +35 -0
- package/dist/ui/chart-axis-ticks.d.ts.map +1 -0
- package/dist/ui/chart-axis-ticks.js +80 -0
- package/dist/ui/chart-axis-ticks.js.map +1 -0
- package/dist/ui/chart-canvas.d.ts +22 -0
- package/dist/ui/chart-canvas.d.ts.map +1 -0
- package/dist/ui/chart-canvas.js +338 -0
- package/dist/ui/chart-canvas.js.map +1 -0
- package/dist/ui/chart-context.d.ts +89 -0
- package/dist/ui/chart-context.d.ts.map +1 -0
- package/dist/ui/chart-context.js +129 -0
- package/dist/ui/chart-context.js.map +1 -0
- package/dist/ui/chart-date-range-badge.d.ts +14 -0
- package/dist/ui/chart-date-range-badge.d.ts.map +1 -0
- package/dist/ui/chart-date-range-badge.js +31 -0
- package/dist/ui/chart-date-range-badge.js.map +1 -0
- package/dist/ui/chart-date-range-panel.d.ts +25 -0
- package/dist/ui/chart-date-range-panel.d.ts.map +1 -0
- package/dist/ui/chart-date-range-panel.js +126 -0
- package/dist/ui/chart-date-range-panel.js.map +1 -0
- package/dist/ui/chart-date-range.d.ts +14 -0
- package/dist/ui/chart-date-range.d.ts.map +1 -0
- package/dist/ui/chart-date-range.js +38 -0
- package/dist/ui/chart-date-range.js.map +1 -0
- package/dist/ui/chart-debug.d.ts +10 -0
- package/dist/ui/chart-debug.d.ts.map +1 -0
- package/dist/ui/chart-debug.js +127 -0
- package/dist/ui/chart-debug.js.map +1 -0
- package/dist/ui/chart-dropdown.d.ts +35 -0
- package/dist/ui/chart-dropdown.d.ts.map +1 -0
- package/dist/ui/chart-dropdown.js +77 -0
- package/dist/ui/chart-dropdown.js.map +1 -0
- package/dist/ui/chart-filters-panel.d.ts +19 -0
- package/dist/ui/chart-filters-panel.d.ts.map +1 -0
- package/dist/ui/chart-filters-panel.js +47 -0
- package/dist/ui/chart-filters-panel.js.map +1 -0
- package/dist/ui/chart-filters.d.ts +12 -0
- package/dist/ui/chart-filters.d.ts.map +1 -0
- package/dist/ui/chart-filters.js +27 -0
- package/dist/ui/chart-filters.js.map +1 -0
- package/dist/ui/chart-group-by-selector.d.ts +8 -0
- package/dist/ui/chart-group-by-selector.d.ts.map +1 -0
- package/dist/ui/chart-group-by-selector.js +20 -0
- package/dist/ui/chart-group-by-selector.js.map +1 -0
- package/dist/ui/chart-metric-panel.d.ts +18 -0
- package/dist/ui/chart-metric-panel.d.ts.map +1 -0
- package/dist/ui/chart-metric-panel.js +119 -0
- package/dist/ui/chart-metric-panel.js.map +1 -0
- package/dist/ui/chart-metric-selector.d.ts +10 -0
- package/dist/ui/chart-metric-selector.d.ts.map +1 -0
- package/dist/ui/chart-metric-selector.js +28 -0
- package/dist/ui/chart-metric-selector.js.map +1 -0
- package/dist/ui/chart-select.d.ts +25 -0
- package/dist/ui/chart-select.d.ts.map +1 -0
- package/dist/ui/chart-select.js +36 -0
- package/dist/ui/chart-select.js.map +1 -0
- package/dist/ui/chart-source-switcher.d.ts +16 -0
- package/dist/ui/chart-source-switcher.d.ts.map +1 -0
- package/dist/ui/chart-source-switcher.js +32 -0
- package/dist/ui/chart-source-switcher.js.map +1 -0
- package/dist/ui/chart-time-bucket-selector.d.ts +9 -0
- package/dist/ui/chart-time-bucket-selector.d.ts.map +1 -0
- package/dist/ui/chart-time-bucket-selector.js +26 -0
- package/dist/ui/chart-time-bucket-selector.js.map +1 -0
- package/dist/ui/chart-toolbar-overflow.d.ts +29 -0
- package/dist/ui/chart-toolbar-overflow.d.ts.map +1 -0
- package/dist/ui/chart-toolbar-overflow.js +110 -0
- package/dist/ui/chart-toolbar-overflow.js.map +1 -0
- package/dist/ui/chart-toolbar.d.ts +45 -0
- package/dist/ui/chart-toolbar.d.ts.map +1 -0
- package/dist/ui/chart-toolbar.js +45 -0
- package/dist/ui/chart-toolbar.js.map +1 -0
- package/dist/ui/chart-type-selector.d.ts +8 -0
- package/dist/ui/chart-type-selector.d.ts.map +1 -0
- package/dist/ui/chart-type-selector.js +23 -0
- package/dist/ui/chart-type-selector.js.map +1 -0
- package/dist/ui/chart-x-axis-selector.d.ts +8 -0
- package/dist/ui/chart-x-axis-selector.d.ts.map +1 -0
- package/dist/ui/chart-x-axis-selector.js +15 -0
- package/dist/ui/chart-x-axis-selector.js.map +1 -0
- package/dist/ui/index.d.ts +25 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +24 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/theme.css +62 -0
- package/dist/ui/toolbar-types.d.ts +43 -0
- package/dist/ui/toolbar-types.d.ts.map +1 -0
- package/dist/ui/toolbar-types.js +51 -0
- package/dist/ui/toolbar-types.js.map +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1,1109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types for chart-studio.
|
|
3
|
+
*
|
|
4
|
+
* The type system is built around two concepts:
|
|
5
|
+
* 1. **Columns** describe the shape of your data (date, category, boolean, number)
|
|
6
|
+
* 2. **Chart state** tracks what the user has selected (chart type, groupBy, filters, etc.)
|
|
7
|
+
*
|
|
8
|
+
* Column types determine what operations are available:
|
|
9
|
+
* - `date` → X-axis candidate, time bucketing (day/week/month/quarter/year)
|
|
10
|
+
* - `category` → X-axis candidate, groupBy candidate, multi-select filter
|
|
11
|
+
* - `boolean` → groupBy candidate, toggle filter
|
|
12
|
+
* - `number` → metric/aggregation (count, sum, avg, min, max)
|
|
13
|
+
*/
|
|
14
|
+
type Nullish = null | undefined;
|
|
15
|
+
/** Primitive field values that chart-studio can infer directly from raw data. */
|
|
16
|
+
export type InferableColumnValue = string | number | boolean | Date | Nullish;
|
|
17
|
+
/** Top-level dataset keys whose values can be charted without a custom accessor. */
|
|
18
|
+
export type InferableFieldKey<T> = Extract<{
|
|
19
|
+
[TKey in keyof T]-?: Exclude<T[TKey], Nullish> extends InferableColumnValue ? TKey : never;
|
|
20
|
+
}[keyof T], string>;
|
|
21
|
+
/**
|
|
22
|
+
* Built-in format presets for `schema.columns.*.format`.
|
|
23
|
+
*
|
|
24
|
+
* Use these for the common cases before reaching for the object form:
|
|
25
|
+
* - `'number'` for a normal numeric display such as `12,340`
|
|
26
|
+
* - `'compact-number'` for short numeric display such as `12.3K`
|
|
27
|
+
* - `'currency'` for money such as `$12.3K` / `$12,340`
|
|
28
|
+
* - `'percent'` for ratios such as `27.8%`
|
|
29
|
+
* - `'date'` for date-only values such as `Mar 11, 2026`
|
|
30
|
+
* - `'datetime'` for date+time values such as `Mar 11, 2026, 3:30 PM`
|
|
31
|
+
*/
|
|
32
|
+
export type ColumnFormatPreset = 'number' | 'compact-number' | 'currency' | 'percent' | 'date' | 'datetime';
|
|
33
|
+
/**
|
|
34
|
+
* Fixed-size duration units that can be converted reliably without calendar
|
|
35
|
+
* ambiguity.
|
|
36
|
+
*
|
|
37
|
+
* These are used by `format: {kind: 'duration', unit: ...}` to tell the chart
|
|
38
|
+
* system what one raw numeric value represents.
|
|
39
|
+
*/
|
|
40
|
+
export type DurationInputUnit = 'seconds' | 'minutes' | 'hours' | 'days';
|
|
41
|
+
/**
|
|
42
|
+
* `Intl.NumberFormat` options for `format: {kind: 'number', ...}`.
|
|
43
|
+
*
|
|
44
|
+
* This is still a native `Intl` passthrough, but the most common properties are
|
|
45
|
+
* re-documented here so new users can understand them directly from editor
|
|
46
|
+
* hover text without opening MDN first.
|
|
47
|
+
*
|
|
48
|
+
* Typical example:
|
|
49
|
+
*
|
|
50
|
+
* ```ts
|
|
51
|
+
* format: {
|
|
52
|
+
* kind: 'number',
|
|
53
|
+
* options: {
|
|
54
|
+
* style: 'currency',
|
|
55
|
+
* currency: 'USD',
|
|
56
|
+
* notation: 'compact',
|
|
57
|
+
* maximumFractionDigits: 1,
|
|
58
|
+
* },
|
|
59
|
+
* }
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export type ChartNumberFormatOptions = Omit<Intl.NumberFormatOptions, 'style' | 'currency' | 'notation' | 'maximumFractionDigits'> & {
|
|
63
|
+
/**
|
|
64
|
+
* Which numeric family to render.
|
|
65
|
+
*
|
|
66
|
+
* Common values:
|
|
67
|
+
* - `'decimal'` -> `1,234`
|
|
68
|
+
* - `'currency'` -> `$1,234`
|
|
69
|
+
* - `'percent'` -> `27.8%`
|
|
70
|
+
*/
|
|
71
|
+
style?: Intl.NumberFormatOptions['style'];
|
|
72
|
+
/**
|
|
73
|
+
* Currency code used when `style: 'currency'`.
|
|
74
|
+
*
|
|
75
|
+
* Common examples:
|
|
76
|
+
* - `'USD'`
|
|
77
|
+
* - `'EUR'`
|
|
78
|
+
* - `'GBP'`
|
|
79
|
+
*/
|
|
80
|
+
currency?: string;
|
|
81
|
+
/**
|
|
82
|
+
* Whether large values should stay full length or use compact suffixes.
|
|
83
|
+
*
|
|
84
|
+
* Common values:
|
|
85
|
+
* - `'standard'` -> `1,200,000`
|
|
86
|
+
* - `'compact'` -> `1.2M`
|
|
87
|
+
*/
|
|
88
|
+
notation?: Intl.NumberFormatOptions['notation'];
|
|
89
|
+
/**
|
|
90
|
+
* Maximum number of digits shown after the decimal separator.
|
|
91
|
+
*
|
|
92
|
+
* Examples:
|
|
93
|
+
* - `0` -> `1M`
|
|
94
|
+
* - `1` -> `1.2M`
|
|
95
|
+
* - `2` -> `1.23M`
|
|
96
|
+
*/
|
|
97
|
+
maximumFractionDigits?: number;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* `Intl.DateTimeFormat` options for `format: {kind: 'date', ...}`.
|
|
101
|
+
*
|
|
102
|
+
* Like `ChartNumberFormatOptions`, this is still a native `Intl` passthrough
|
|
103
|
+
* with friendlier docs for the properties chart users reach for most often.
|
|
104
|
+
*
|
|
105
|
+
* Typical example:
|
|
106
|
+
*
|
|
107
|
+
* ```ts
|
|
108
|
+
* format: {
|
|
109
|
+
* kind: 'date',
|
|
110
|
+
* options: {
|
|
111
|
+
* month: 'short',
|
|
112
|
+
* year: 'numeric',
|
|
113
|
+
* },
|
|
114
|
+
* }
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export type ChartDateFormatOptions = Omit<Intl.DateTimeFormatOptions, 'dateStyle' | 'timeStyle' | 'year' | 'month' | 'day'> & {
|
|
118
|
+
/**
|
|
119
|
+
* Prebuilt date preset.
|
|
120
|
+
*
|
|
121
|
+
* Examples:
|
|
122
|
+
* - `'short'` -> `3/11/26`
|
|
123
|
+
* - `'medium'` -> `Mar 11, 2026`
|
|
124
|
+
* - `'long'` -> `March 11, 2026`
|
|
125
|
+
*/
|
|
126
|
+
dateStyle?: Intl.DateTimeFormatOptions['dateStyle'];
|
|
127
|
+
/**
|
|
128
|
+
* Prebuilt time preset.
|
|
129
|
+
*
|
|
130
|
+
* Examples:
|
|
131
|
+
* - `'short'` -> `3:30 PM`
|
|
132
|
+
* - `'medium'` -> `3:30:00 PM`
|
|
133
|
+
*/
|
|
134
|
+
timeStyle?: Intl.DateTimeFormatOptions['timeStyle'];
|
|
135
|
+
/** How the year should render, for example `'numeric'` or `'2-digit'`. */
|
|
136
|
+
year?: Intl.DateTimeFormatOptions['year'];
|
|
137
|
+
/** How the month should render, for example `'numeric'`, `'short'`, or `'long'`. */
|
|
138
|
+
month?: Intl.DateTimeFormatOptions['month'];
|
|
139
|
+
/** How the day should render, usually `'numeric'` or `'2-digit'`. */
|
|
140
|
+
day?: Intl.DateTimeFormatOptions['day'];
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Explicit number formatting object.
|
|
144
|
+
*
|
|
145
|
+
* Use this when the preset strings are close, but you want to control the
|
|
146
|
+
* locale or specific `Intl.NumberFormat` options yourself.
|
|
147
|
+
*/
|
|
148
|
+
export type NumberColumnFormat = {
|
|
149
|
+
/** Marks this object as the number-format form of `format`. */
|
|
150
|
+
kind: 'number';
|
|
151
|
+
/**
|
|
152
|
+
* Optional locale passed to `Intl.NumberFormat`.
|
|
153
|
+
*
|
|
154
|
+
* Examples:
|
|
155
|
+
* - `'en-US'`
|
|
156
|
+
* - `'fr-FR'`
|
|
157
|
+
* - `'de-DE'`
|
|
158
|
+
*/
|
|
159
|
+
locale?: string;
|
|
160
|
+
/**
|
|
161
|
+
* Native `Intl.NumberFormat` options.
|
|
162
|
+
*
|
|
163
|
+
* This is where you customize things like currency, compact notation, and the
|
|
164
|
+
* number of decimal places to show.
|
|
165
|
+
*/
|
|
166
|
+
options?: ChartNumberFormatOptions;
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Explicit date formatting object.
|
|
170
|
+
*
|
|
171
|
+
* Use this when the preset strings are close, but you want to control the
|
|
172
|
+
* locale or specific `Intl.DateTimeFormat` options yourself.
|
|
173
|
+
*/
|
|
174
|
+
export type DateColumnFormat = {
|
|
175
|
+
/** Marks this object as the date-format form of `format`. */
|
|
176
|
+
kind: 'date';
|
|
177
|
+
/**
|
|
178
|
+
* Optional locale passed to `Intl.DateTimeFormat`.
|
|
179
|
+
*
|
|
180
|
+
* Examples:
|
|
181
|
+
* - `'en-US'`
|
|
182
|
+
* - `'fr-FR'`
|
|
183
|
+
* - `'ja-JP'`
|
|
184
|
+
*/
|
|
185
|
+
locale?: string;
|
|
186
|
+
/**
|
|
187
|
+
* Native `Intl.DateTimeFormat` options.
|
|
188
|
+
*
|
|
189
|
+
* This is where you customize things like month/year-only displays, long
|
|
190
|
+
* versus short month names, or full date+time output.
|
|
191
|
+
*/
|
|
192
|
+
options?: ChartDateFormatOptions;
|
|
193
|
+
};
|
|
194
|
+
/**
|
|
195
|
+
* Explicit duration formatting object for numeric values that represent elapsed
|
|
196
|
+
* time.
|
|
197
|
+
*
|
|
198
|
+
* Use this when the charted value is a duration and you want chart-studio to
|
|
199
|
+
* render compact labels like `36s`, `1h36m`, or `1d5h`.
|
|
200
|
+
*
|
|
201
|
+
* Typical example:
|
|
202
|
+
*
|
|
203
|
+
* ```ts
|
|
204
|
+
* format: {
|
|
205
|
+
* kind: 'duration',
|
|
206
|
+
* unit: 'minutes',
|
|
207
|
+
* }
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
export type DurationColumnFormat = {
|
|
211
|
+
/** Marks this object as the duration-format form of `format`. */
|
|
212
|
+
kind: 'duration';
|
|
213
|
+
/**
|
|
214
|
+
* Unit represented by one raw numeric value.
|
|
215
|
+
*
|
|
216
|
+
* Examples:
|
|
217
|
+
* - `'seconds'` when `90` means ninety seconds
|
|
218
|
+
* - `'minutes'` when `45` means forty-five minutes
|
|
219
|
+
* - `'hours'` when `1.5` means one hour and thirty minutes
|
|
220
|
+
* - `'days'` when `2` means two days
|
|
221
|
+
*/
|
|
222
|
+
unit: DurationInputUnit;
|
|
223
|
+
};
|
|
224
|
+
/**
|
|
225
|
+
* Full declarative formatting surface accepted by `schema.columns.*.format`.
|
|
226
|
+
*
|
|
227
|
+
* Start with a preset string for the common case. Move to the object form when
|
|
228
|
+
* you need to customize locale, low-level `Intl` options, or duration units.
|
|
229
|
+
*/
|
|
230
|
+
export type ColumnFormat = ColumnFormatPreset | NumberColumnFormat | DateColumnFormat | DurationColumnFormat;
|
|
231
|
+
/** Column kinds understood by the chart pipeline. */
|
|
232
|
+
export type ChartColumnType = 'date' | 'category' | 'boolean' | 'number';
|
|
233
|
+
/** Confidence attached to runtime field inference. */
|
|
234
|
+
export type InferenceConfidence = 'low' | 'medium' | 'high';
|
|
235
|
+
/** Debug metadata describing how a column was inferred. */
|
|
236
|
+
export type ColumnInferenceMetadata = {
|
|
237
|
+
detectedType: ChartColumnType;
|
|
238
|
+
confidence: InferenceConfidence;
|
|
239
|
+
hinted: boolean;
|
|
240
|
+
};
|
|
241
|
+
/**
|
|
242
|
+
* Shared schema properties available on both raw-field overrides and derived
|
|
243
|
+
* columns.
|
|
244
|
+
*
|
|
245
|
+
* Most users will interact with these through `schema.columns.someField`.
|
|
246
|
+
*/
|
|
247
|
+
export interface BaseColumnHint<T, TValue> {
|
|
248
|
+
/**
|
|
249
|
+
* User-facing column label shown in selectors, tooltips, legends, and filter
|
|
250
|
+
* headers.
|
|
251
|
+
*
|
|
252
|
+
* Example: `revenuePerSeat` becomes `Revenue Per Seat` by default, but you can
|
|
253
|
+
* override it with `label: 'Revenue / Seat'`.
|
|
254
|
+
*/
|
|
255
|
+
label?: string;
|
|
256
|
+
/**
|
|
257
|
+
* How this column should be displayed in the chart UI.
|
|
258
|
+
*
|
|
259
|
+
* Use a preset like `'currency'` or `'percent'` for the common case. Use the
|
|
260
|
+
* object form when you need to control locale, specific `Intl` options, or
|
|
261
|
+
* duration units like `'minutes'`.
|
|
262
|
+
*
|
|
263
|
+
* This affects display surfaces such as:
|
|
264
|
+
* - axis tick labels
|
|
265
|
+
* - tooltip values
|
|
266
|
+
* - chart data labels
|
|
267
|
+
* - filter option labels when the values are typed
|
|
268
|
+
*/
|
|
269
|
+
format?: ColumnFormat;
|
|
270
|
+
/**
|
|
271
|
+
* Final escape hatch for fully custom display logic.
|
|
272
|
+
*
|
|
273
|
+
* Receives the resolved field value and, when the UI surface still maps to a
|
|
274
|
+
* single raw row, that source item as well. Prefer `format` first when a
|
|
275
|
+
* declarative option is enough, and use `formatter` only when the output
|
|
276
|
+
* really depends on custom business logic.
|
|
277
|
+
*/
|
|
278
|
+
formatter?: (value: TValue | null | undefined, item?: T) => string;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Schema override for a raw string field.
|
|
282
|
+
*
|
|
283
|
+
* Use this when a dataset field already exists and you want to relabel it,
|
|
284
|
+
* force its type, or change how it formats in the chart UI.
|
|
285
|
+
*/
|
|
286
|
+
export interface StringColumnHint<T> extends BaseColumnHint<T, string> {
|
|
287
|
+
/**
|
|
288
|
+
* How this string field should behave in the chart system.
|
|
289
|
+
*
|
|
290
|
+
* - `'category'` keeps it as a label-like field
|
|
291
|
+
* - `'date'` tells chart-studio to parse it as a date/time field
|
|
292
|
+
*/
|
|
293
|
+
type?: 'category' | 'date';
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Schema override for a raw numeric field.
|
|
297
|
+
*
|
|
298
|
+
* This is the most common place to use `format: 'currency'`,
|
|
299
|
+
* `format: 'percent'`, or a `kind: 'number'` object.
|
|
300
|
+
*/
|
|
301
|
+
export interface NumberColumnHint<T> extends BaseColumnHint<T, number> {
|
|
302
|
+
/**
|
|
303
|
+
* How this numeric field should behave in the chart system.
|
|
304
|
+
*
|
|
305
|
+
* - `'number'` keeps it as an aggregatable metric
|
|
306
|
+
* - `'date'` is useful for Unix timestamps or numeric date representations
|
|
307
|
+
*/
|
|
308
|
+
type?: 'number' | 'date';
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Schema override for a raw boolean field.
|
|
312
|
+
*
|
|
313
|
+
* These fields are useful for grouping and filtering, especially when paired
|
|
314
|
+
* with `trueLabel` / `falseLabel`.
|
|
315
|
+
*/
|
|
316
|
+
export interface BooleanColumnHint<T> extends BaseColumnHint<T, boolean> {
|
|
317
|
+
/** Boolean fields always resolve to the `'boolean'` column type. */
|
|
318
|
+
type?: 'boolean';
|
|
319
|
+
/** Label shown in the UI when the value is `true`, for example `'Open'`. */
|
|
320
|
+
trueLabel?: string;
|
|
321
|
+
/** Label shown in the UI when the value is `false`, for example `'Closed'`. */
|
|
322
|
+
falseLabel?: string;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Schema override for a raw date-like field.
|
|
326
|
+
*
|
|
327
|
+
* This is useful when your field is already a `Date`, ISO string, or timestamp
|
|
328
|
+
* and you want date-specific behavior with an optional custom display format.
|
|
329
|
+
*/
|
|
330
|
+
export interface DateValueColumnHint<T> extends BaseColumnHint<T, string | number | Date> {
|
|
331
|
+
/** Date-valued fields always resolve to the `'date'` column type. */
|
|
332
|
+
type?: 'date';
|
|
333
|
+
}
|
|
334
|
+
/** Override options for mixed primitive fields when runtime values need the final say. */
|
|
335
|
+
export interface MixedPrimitiveColumnHint<T, TValue> extends BaseColumnHint<T, TValue> {
|
|
336
|
+
/** Explicitly pin the runtime-inferred field to one chart column type. */
|
|
337
|
+
type?: ChartColumnType;
|
|
338
|
+
/** Human-facing label used when a mixed field is interpreted as boolean `true`. */
|
|
339
|
+
trueLabel?: string;
|
|
340
|
+
/** Human-facing label used when a mixed field is interpreted as boolean `false`. */
|
|
341
|
+
falseLabel?: string;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Type-safe schema entry for one raw dataset field.
|
|
345
|
+
*
|
|
346
|
+
* The available properties depend on the field's runtime type, so a boolean
|
|
347
|
+
* field gets boolean-specific options, a number field gets numeric options, and
|
|
348
|
+
* so on.
|
|
349
|
+
*/
|
|
350
|
+
export type ColumnHintFor<TValue, T> = [
|
|
351
|
+
Exclude<TValue, Nullish>
|
|
352
|
+
] extends [boolean] ? BooleanColumnHint<T> : [Exclude<TValue, Nullish>] extends [Date] ? DateValueColumnHint<T> : [Exclude<TValue, Nullish>] extends [number] ? NumberColumnHint<T> : [Exclude<TValue, Nullish>] extends [string] ? StringColumnHint<T> : MixedPrimitiveColumnHint<T, Exclude<TValue, Nullish>>;
|
|
353
|
+
/** Partial per-field overrides layered on top of automatic inference. */
|
|
354
|
+
export type ColumnHints<T> = Partial<{
|
|
355
|
+
[TKey in InferableFieldKey<T>]: ColumnHintFor<T[TKey], T> | false;
|
|
356
|
+
}>;
|
|
357
|
+
/**
|
|
358
|
+
* Override or exclude one inferred raw field inside `schema.columns`.
|
|
359
|
+
*
|
|
360
|
+
* This lightweight shape intentionally matches the inference override story so
|
|
361
|
+
* callers can keep the common case terse while the surrounding `schema` object
|
|
362
|
+
* becomes the single explicit chart contract.
|
|
363
|
+
*/
|
|
364
|
+
export type RawColumnSchemaFor<TValue, T> = ColumnHintFor<TValue, T>;
|
|
365
|
+
/**
|
|
366
|
+
* Raw-field schema entries keyed by existing top-level dataset fields.
|
|
367
|
+
*
|
|
368
|
+
* Set a field to `false` to exclude it from the chart API entirely.
|
|
369
|
+
*/
|
|
370
|
+
export type RawColumnSchemaMap<T> = Partial<{
|
|
371
|
+
[TKey in InferableFieldKey<T>]: RawColumnSchemaFor<T[TKey], T> | false;
|
|
372
|
+
}>;
|
|
373
|
+
/**
|
|
374
|
+
* Shared contract for every explicit derived column declared in `schema.columns`.
|
|
375
|
+
*
|
|
376
|
+
* Derived columns are how you add a brand new chart field that does not exist as
|
|
377
|
+
* a raw property on the input row.
|
|
378
|
+
*
|
|
379
|
+
* They are intentionally narrow:
|
|
380
|
+
* - they are additive-only and must use a new id
|
|
381
|
+
* - they compute from one row at a time via `accessor`
|
|
382
|
+
* - they reuse the same labeling and formatting surface as raw columns
|
|
383
|
+
* - they do not currently expose any extra metadata channel
|
|
384
|
+
*/
|
|
385
|
+
interface DerivedColumnSchemaBase<T, TValue, TType extends ChartColumnType> extends Omit<BaseColumnHint<T, TValue>, 'label'> {
|
|
386
|
+
/**
|
|
387
|
+
* Marks this schema entry as a derived column.
|
|
388
|
+
*
|
|
389
|
+
* Without `kind: 'derived'`, a `schema.columns` entry is interpreted as an
|
|
390
|
+
* override for an existing raw field.
|
|
391
|
+
*/
|
|
392
|
+
kind: 'derived';
|
|
393
|
+
/** User-facing label for this new derived column. */
|
|
394
|
+
label: string;
|
|
395
|
+
/**
|
|
396
|
+
* Declared column role.
|
|
397
|
+
*
|
|
398
|
+
* This controls how the derived column behaves:
|
|
399
|
+
* - `'date'` can be used on time-series X-axes
|
|
400
|
+
* - `'category'` can be used for X-axis, group-by, and filters
|
|
401
|
+
* - `'boolean'` can be used for group-by and filters
|
|
402
|
+
* - `'number'` can be aggregated as a metric
|
|
403
|
+
*/
|
|
404
|
+
type: TType;
|
|
405
|
+
}
|
|
406
|
+
/** Explicit derived date column definition. */
|
|
407
|
+
export interface DerivedDateColumnSchema<T> extends DerivedColumnSchemaBase<T, string | number | Date, 'date'> {
|
|
408
|
+
/** Compute one date-like value from a row for time-series usage. */
|
|
409
|
+
accessor: (item: T) => string | number | Date | null | undefined;
|
|
410
|
+
}
|
|
411
|
+
/** Explicit derived category column definition. */
|
|
412
|
+
export interface DerivedCategoryColumnSchema<T> extends DerivedColumnSchemaBase<T, string, 'category'> {
|
|
413
|
+
/** Compute one category label from a row. */
|
|
414
|
+
accessor: (item: T) => string | null | undefined;
|
|
415
|
+
}
|
|
416
|
+
/** Explicit derived boolean column definition. */
|
|
417
|
+
export interface DerivedBooleanColumnSchema<T> extends DerivedColumnSchemaBase<T, boolean, 'boolean'> {
|
|
418
|
+
/** Compute one boolean value from a row. */
|
|
419
|
+
accessor: (item: T) => boolean | null | undefined;
|
|
420
|
+
/** Human-facing label used when the derived value is `true`. */
|
|
421
|
+
trueLabel?: string;
|
|
422
|
+
/** Human-facing label used when the derived value is `false`. */
|
|
423
|
+
falseLabel?: string;
|
|
424
|
+
}
|
|
425
|
+
/** Explicit derived numeric column definition. */
|
|
426
|
+
export interface DerivedNumberColumnSchema<T> extends DerivedColumnSchemaBase<T, number, 'number'> {
|
|
427
|
+
/** Compute one numeric value from a row for aggregation. */
|
|
428
|
+
accessor: (item: T) => number | null | undefined;
|
|
429
|
+
}
|
|
430
|
+
/** Any explicit derived column accepted in `schema.columns`. */
|
|
431
|
+
export type DerivedColumnSchema<T> = DerivedDateColumnSchema<T> | DerivedCategoryColumnSchema<T> | DerivedBooleanColumnSchema<T> | DerivedNumberColumnSchema<T>;
|
|
432
|
+
/**
|
|
433
|
+
* Broad contextual typing surface used while authoring `schema.columns`.
|
|
434
|
+
*
|
|
435
|
+
* The validator stays stricter than this helper surface. This type exists so
|
|
436
|
+
* editors can still suggest known raw dataset keys while callers are also free
|
|
437
|
+
* to add arbitrary derived column ids inline.
|
|
438
|
+
*/
|
|
439
|
+
export type ChartColumnsAuthoringSurface<T> = RawColumnSchemaMap<T> & {
|
|
440
|
+
[TKey: string]: RawColumnSchemaFor<InferableColumnValue, T> | DerivedColumnSchema<T> | false;
|
|
441
|
+
};
|
|
442
|
+
type ExcludedHintKeys<THints> = Extract<{
|
|
443
|
+
[TKey in keyof THints]-?: THints[TKey] extends false ? TKey : never;
|
|
444
|
+
}[keyof THints], string>;
|
|
445
|
+
/** Column ID union after removing any fields explicitly disabled by hints. */
|
|
446
|
+
export type ResolvedColumnIdFromHints<T, THints extends ColumnHints<T> | undefined = undefined> = Exclude<InferableFieldKey<T>, THints extends ColumnHints<T> ? ExcludedHintKeys<THints> : never>;
|
|
447
|
+
type ExplicitHintedColumnType<THint> = Extract<THint extends {
|
|
448
|
+
type?: infer TType;
|
|
449
|
+
} ? TType : never, ChartColumnType>;
|
|
450
|
+
type PotentialColumnTypeFromValue<TValue> = [
|
|
451
|
+
Exclude<TValue, Nullish>
|
|
452
|
+
] extends [boolean] ? 'boolean' : [Exclude<TValue, Nullish>] extends [Date] ? 'date' : [Exclude<TValue, Nullish>] extends [number] ? 'date' | 'number' : [Exclude<TValue, Nullish>] extends [string] ? 'date' | 'category' : ChartColumnType;
|
|
453
|
+
type PotentialColumnTypeFromHints<T, THints extends ColumnHints<T> | undefined, TKey extends ResolvedColumnIdFromHints<T, THints>> = THints extends ColumnHints<T> ? [ExplicitHintedColumnType<THints[TKey]>] extends [never] ? PotentialColumnTypeFromValue<T[TKey]> : ExplicitHintedColumnType<THints[TKey]> : PotentialColumnTypeFromValue<T[TKey]>;
|
|
454
|
+
type ColumnIdsMatchingPotentialTypes<T, THints extends ColumnHints<T> | undefined, TAllowedType extends ChartColumnType> = Extract<{
|
|
455
|
+
[TKey in ResolvedColumnIdFromHints<T, THints>]: Extract<PotentialColumnTypeFromHints<T, THints, TKey>, TAllowedType> extends never ? never : TKey;
|
|
456
|
+
}[ResolvedColumnIdFromHints<T, THints>], string>;
|
|
457
|
+
/** Column IDs that can safely be treated as X-axis candidates from static information. */
|
|
458
|
+
export type ResolvedXAxisColumnIdFromHints<T, THints extends ColumnHints<T> | undefined = undefined> = ColumnIdsMatchingPotentialTypes<T, THints, 'date' | 'category' | 'boolean'>;
|
|
459
|
+
/** Column IDs that can safely be treated as groupBy candidates from static information. */
|
|
460
|
+
export type ResolvedGroupByColumnIdFromHints<T, THints extends ColumnHints<T> | undefined = undefined> = ColumnIdsMatchingPotentialTypes<T, THints, 'category' | 'boolean'>;
|
|
461
|
+
/** Column IDs that can safely be treated as filter candidates from static information. */
|
|
462
|
+
export type ResolvedFilterColumnIdFromHints<T, THints extends ColumnHints<T> | undefined = undefined> = ColumnIdsMatchingPotentialTypes<T, THints, 'category' | 'boolean'>;
|
|
463
|
+
/** Column IDs that can safely be treated as metric candidates from static information. */
|
|
464
|
+
export type ResolvedMetricColumnIdFromHints<T, THints extends ColumnHints<T> | undefined = undefined> = ColumnIdsMatchingPotentialTypes<T, THints, 'number'>;
|
|
465
|
+
/** Column IDs that can safely be treated as date candidates from static information. */
|
|
466
|
+
export type ResolvedDateColumnIdFromHints<T, THints extends ColumnHints<T> | undefined = undefined> = ColumnIdsMatchingPotentialTypes<T, THints, 'date'>;
|
|
467
|
+
/** Explicit config derived from the resolved role-aware IDs for one dataset. */
|
|
468
|
+
export type ChartConfigFromHints<T, THints extends ColumnHints<T> | undefined = undefined> = ChartConfig<ResolvedXAxisColumnIdFromHints<T, THints>, ResolvedGroupByColumnIdFromHints<T, THints>, ResolvedFilterColumnIdFromHints<T, THints>, ResolvedMetricColumnIdFromHints<T, THints>>;
|
|
469
|
+
type ConfigSection<TConfig, TKey extends string> = TKey extends keyof TConfig ? TConfig[TKey] : never;
|
|
470
|
+
type AllowedOptionFromControlConfig<TControlConfig> = TControlConfig extends {
|
|
471
|
+
allowed?: readonly (infer TAllowedOption)[];
|
|
472
|
+
} ? TAllowedOption : never;
|
|
473
|
+
type HiddenOptionFromControlConfig<TControlConfig> = TControlConfig extends {
|
|
474
|
+
hidden?: readonly (infer THiddenOption)[];
|
|
475
|
+
} ? THiddenOption : never;
|
|
476
|
+
type RestrictUnionOrFallback<TAllowed, TFallback> = [
|
|
477
|
+
Extract<TAllowed, TFallback>
|
|
478
|
+
] extends [never] ? TFallback : Extract<TAllowed, TFallback>;
|
|
479
|
+
type ExcludeHiddenOrFallback<TBase, THidden> = [
|
|
480
|
+
Extract<THidden, TBase>
|
|
481
|
+
] extends [TBase] ? TBase : Exclude<TBase, Extract<THidden, TBase>>;
|
|
482
|
+
type RestrictOptionsFromControlConfig<TBaseOption, TControlConfig> = ExcludeHiddenOrFallback<RestrictUnionOrFallback<AllowedOptionFromControlConfig<TControlConfig>, TBaseOption>, Extract<HiddenOptionFromControlConfig<TControlConfig>, TBaseOption>>;
|
|
483
|
+
type AllowedMetricFromConfig<TConfig> = TConfig extends {
|
|
484
|
+
metric?: {
|
|
485
|
+
allowed?: readonly (infer TAllowedMetric)[];
|
|
486
|
+
};
|
|
487
|
+
} ? TAllowedMetric : never;
|
|
488
|
+
type HiddenMetricFromConfig<TConfig> = TConfig extends {
|
|
489
|
+
metric?: {
|
|
490
|
+
hidden?: readonly (infer THiddenMetric)[];
|
|
491
|
+
};
|
|
492
|
+
} ? THiddenMetric : never;
|
|
493
|
+
type ExpandMetricAllowance<TMetricAllowance> = TMetricAllowance extends CountMetric ? CountMetric : TMetricAllowance extends {
|
|
494
|
+
kind: 'aggregate';
|
|
495
|
+
columnId: infer TColumnId extends string;
|
|
496
|
+
aggregate: infer TAggregate;
|
|
497
|
+
includeZeros?: infer TIncludeZeros;
|
|
498
|
+
} ? TAggregate extends readonly NumericAggregateFunction[] ? {
|
|
499
|
+
[TSelectedAggregate in TAggregate[number]]: {
|
|
500
|
+
kind: 'aggregate';
|
|
501
|
+
columnId: TColumnId;
|
|
502
|
+
aggregate: TSelectedAggregate;
|
|
503
|
+
includeZeros?: Extract<TIncludeZeros, boolean | undefined>;
|
|
504
|
+
};
|
|
505
|
+
}[TAggregate[number]] : TAggregate extends NumericAggregateFunction ? {
|
|
506
|
+
kind: 'aggregate';
|
|
507
|
+
columnId: TColumnId;
|
|
508
|
+
aggregate: TAggregate;
|
|
509
|
+
includeZeros?: Extract<TIncludeZeros, boolean | undefined>;
|
|
510
|
+
} : never : never;
|
|
511
|
+
type MetricColumnIdFromMetric<TMetric> = Extract<TMetric extends AggregateMetric<infer TColumnId> ? TColumnId : never, string>;
|
|
512
|
+
type StaticConfigError<TMessage extends string> = {
|
|
513
|
+
__configError__: TMessage;
|
|
514
|
+
};
|
|
515
|
+
type IsExactly<TLeft, TRight> = [
|
|
516
|
+
TLeft
|
|
517
|
+
] extends [TRight] ? [TRight] extends [TLeft] ? true : false : false;
|
|
518
|
+
type IsTuple<TArray extends readonly unknown[]> = number extends TArray['length'] ? false : true;
|
|
519
|
+
type NarrowConfigLiteral<TValue, TWide> = IsExactly<TValue, TWide> extends true ? never : TValue;
|
|
520
|
+
type RequiredKeys<TObject> = Extract<{
|
|
521
|
+
[TKey in keyof TObject]-?: undefined extends TObject[TKey] ? never : TKey;
|
|
522
|
+
}[keyof TObject], PropertyKey>;
|
|
523
|
+
export type ExactShape<TExpected, TActual> = TExpected extends unknown ? TActual extends readonly (infer TActualItem)[] ? TExpected extends readonly (infer TExpectedItem)[] ? readonly ExactShape<TExpectedItem, TActualItem>[] : never : TActual extends (...args: never[]) => unknown ? TActual extends TExpected ? TActual : never : TActual extends object ? TExpected extends object ? {
|
|
524
|
+
[TKey in keyof TActual]: TKey extends keyof TExpected ? ExactShape<TExpected[TKey], TActual[TKey]> : never;
|
|
525
|
+
} & {
|
|
526
|
+
[TKey in Exclude<RequiredKeys<TExpected>, keyof TActual>]-?: never;
|
|
527
|
+
} : never : TActual extends TExpected ? TActual : never : never;
|
|
528
|
+
export type SchemaColumnsValidationShape<T, TColumns extends Record<string, unknown> | undefined> = TColumns extends Record<string, unknown> ? {
|
|
529
|
+
[TKey in keyof TColumns]: TKey extends InferableFieldKey<T> ? RawColumnSchemaFor<T[TKey], T> | false : DerivedColumnSchema<T>;
|
|
530
|
+
} : never;
|
|
531
|
+
export type ValidateLiteralDefaultNotHidden<TSection, TWideOption, TSectionName extends string> = TSection extends {
|
|
532
|
+
default?: infer TDefault;
|
|
533
|
+
hidden?: infer THidden;
|
|
534
|
+
} ? THidden extends readonly unknown[] ? IsTuple<THidden> extends true ? [NarrowConfigLiteral<Exclude<TDefault, undefined>, TWideOption>] extends [never] ? unknown : [Extract<NarrowConfigLiteral<Exclude<TDefault, undefined>, TWideOption>, THidden[number]>] extends [never] ? unknown : StaticConfigError<`${TSectionName}.default cannot also appear in ${TSectionName}.hidden`> : unknown : unknown : unknown;
|
|
535
|
+
type ValidateChartConfigLiterals<T, THints extends ColumnHints<T> | undefined, TConfig extends ChartConfigFromHints<T, THints>> = ValidateLiteralDefaultNotHidden<ConfigSection<TConfig, 'xAxis'>, ResolvedXAxisColumnIdFromHints<T, THints>, 'xAxis'> & ValidateLiteralDefaultNotHidden<ConfigSection<TConfig, 'groupBy'>, ResolvedGroupByColumnIdFromHints<T, THints>, 'groupBy'> & ValidateLiteralDefaultNotHidden<ConfigSection<TConfig, 'metric'>, Metric<ResolvedMetricColumnIdFromHints<T, THints>>, 'metric'> & ValidateLiteralDefaultNotHidden<ConfigSection<TConfig, 'chartType'>, ChartType, 'chartType'> & ValidateLiteralDefaultNotHidden<ConfigSection<TConfig, 'timeBucket'>, TimeBucket, 'timeBucket'>;
|
|
536
|
+
export type ValidatedChartConfigFromHints<T, THints extends ColumnHints<T> | undefined, TConfig> = TConfig extends ChartConfigFromHints<T, THints> ? ExactShape<ChartConfigFromHints<T, THints>, TConfig> & TConfig & ValidateChartConfigLiterals<T, THints, TConfig> : TConfig;
|
|
537
|
+
/** Strict config object returned by `defineChartConfig(...)`. */
|
|
538
|
+
export type DefinedChartConfigFromHints<T, THints extends ColumnHints<T> | undefined = undefined, TConfig extends ChartConfigFromHints<T, THints> = ChartConfigFromHints<T, THints>> = ValidatedChartConfigFromHints<T, THints, TConfig> & ChartConfigDefinitionBrand;
|
|
539
|
+
type ValidateChartSchemaLiterals<T, TSchema extends ChartSchema<T, any>> = ValidateLiteralDefaultNotHidden<ConfigSection<TSchema, 'xAxis'>, ResolvedXAxisColumnIdFromSchema<T, TSchema>, 'xAxis'> & ValidateLiteralDefaultNotHidden<ConfigSection<TSchema, 'groupBy'>, ResolvedGroupByColumnIdFromSchema<T, TSchema>, 'groupBy'> & ValidateLiteralDefaultNotHidden<ConfigSection<TSchema, 'metric'>, Metric<ResolvedMetricColumnIdFromSchema<T, TSchema>>, 'metric'> & ValidateLiteralDefaultNotHidden<ConfigSection<TSchema, 'chartType'>, ChartType, 'chartType'> & ValidateLiteralDefaultNotHidden<ConfigSection<TSchema, 'timeBucket'>, TimeBucket, 'timeBucket'>;
|
|
540
|
+
type ChartSchemaValidationTarget<T, TSchema extends ChartSchema<T, any>> = {
|
|
541
|
+
columns?: SchemaColumnsValidationShape<T, ExtractSchemaColumns<TSchema>>;
|
|
542
|
+
xAxis?: XAxisConfig<ResolvedXAxisColumnIdFromSchema<T, TSchema>>;
|
|
543
|
+
groupBy?: GroupByConfig<ResolvedGroupByColumnIdFromSchema<T, TSchema>>;
|
|
544
|
+
filters?: FiltersConfig<ResolvedFilterColumnIdFromSchema<T, TSchema>>;
|
|
545
|
+
metric?: MetricConfig<ResolvedMetricColumnIdFromSchema<T, TSchema>>;
|
|
546
|
+
chartType?: ChartTypeConfig;
|
|
547
|
+
timeBucket?: TimeBucketConfig;
|
|
548
|
+
};
|
|
549
|
+
/** Strict schema object returned by `defineChartSchema(...)`. */
|
|
550
|
+
export type ValidatedChartSchema<T, TSchema> = TSchema extends ChartSchema<T, any> ? TSchema & ExactShape<ChartSchemaValidationTarget<T, TSchema>, TSchema> & ValidateChartSchemaLiterals<T, TSchema> : TSchema;
|
|
551
|
+
/** Strict schema object returned by `defineChartSchema(...)`. */
|
|
552
|
+
export type DefinedChartSchema<T, TSchema extends ChartSchema<T, any> = ChartSchema<T, any>> = TSchema & ChartSchemaDefinitionBrand;
|
|
553
|
+
export type ResolvedChartSchemaFromDefinition<TSchema> = TSchema extends DefinedChartSchema<any, infer TResolvedSchema> ? TResolvedSchema : undefined;
|
|
554
|
+
export type ResolvedChartConfigFromDefinition<TConfig> = TConfig extends DefinedChartConfigFromHints<any, any, infer TResolvedConfig> ? TResolvedConfig : undefined;
|
|
555
|
+
/** GroupBy IDs narrowed by explicit config when present. */
|
|
556
|
+
export type RestrictedGroupByColumnIdFromConfig<T, THints extends ColumnHints<T> | undefined = undefined, TConfig extends ChartConfigFromHints<T, THints> | undefined = undefined> = RestrictOptionsFromControlConfig<ResolvedGroupByColumnIdFromHints<T, THints>, ConfigSection<TConfig, 'groupBy'>>;
|
|
557
|
+
/** X-axis IDs narrowed by explicit config when present. */
|
|
558
|
+
export type RestrictedXAxisColumnIdFromConfig<T, THints extends ColumnHints<T> | undefined = undefined, TConfig extends ChartConfigFromHints<T, THints> | undefined = undefined> = RestrictOptionsFromControlConfig<ResolvedXAxisColumnIdFromHints<T, THints>, ConfigSection<TConfig, 'xAxis'>>;
|
|
559
|
+
/** Filter column IDs narrowed by explicit config when present. */
|
|
560
|
+
export type RestrictedFilterColumnIdFromConfig<T, THints extends ColumnHints<T> | undefined = undefined, TConfig extends ChartConfigFromHints<T, THints> | undefined = undefined> = RestrictOptionsFromControlConfig<ResolvedFilterColumnIdFromHints<T, THints>, ConfigSection<TConfig, 'filters'>>;
|
|
561
|
+
/** Metric union narrowed by explicit config when present. */
|
|
562
|
+
export type RestrictedMetricFromConfig<T, THints extends ColumnHints<T> | undefined = undefined, TConfig extends ChartConfigFromHints<T, THints> | undefined = undefined> = ExcludeHiddenOrFallback<RestrictUnionOrFallback<ExpandMetricAllowance<AllowedMetricFromConfig<TConfig>>, Metric<ResolvedMetricColumnIdFromHints<T, THints>>>, HiddenMetricFromConfig<TConfig>>;
|
|
563
|
+
/** Chart types narrowed by explicit config when present. */
|
|
564
|
+
export type RestrictedChartTypeFromConfig<TConfig> = RestrictOptionsFromControlConfig<ChartType, ConfigSection<TConfig, 'chartType'>>;
|
|
565
|
+
/** Time buckets narrowed by explicit config when present. */
|
|
566
|
+
export type RestrictedTimeBucketFromConfig<TConfig> = RestrictOptionsFromControlConfig<TimeBucket, ConfigSection<TConfig, 'timeBucket'>>;
|
|
567
|
+
/** GroupBy IDs narrowed by explicit schema restrictions when present. */
|
|
568
|
+
export type RestrictedGroupByColumnIdFromSchema<T, TSchema extends ChartSchema<T, any> | undefined = undefined> = RestrictOptionsFromControlConfig<ResolvedGroupByColumnIdFromSchema<T, TSchema>, ConfigSection<TSchema, 'groupBy'>>;
|
|
569
|
+
/** X-axis IDs narrowed by explicit schema restrictions when present. */
|
|
570
|
+
export type RestrictedXAxisColumnIdFromSchema<T, TSchema extends ChartSchema<T, any> | undefined = undefined> = RestrictOptionsFromControlConfig<ResolvedXAxisColumnIdFromSchema<T, TSchema>, ConfigSection<TSchema, 'xAxis'>>;
|
|
571
|
+
/** Filter column IDs narrowed by explicit schema restrictions when present. */
|
|
572
|
+
export type RestrictedFilterColumnIdFromSchema<T, TSchema extends ChartSchema<T, any> | undefined = undefined> = RestrictOptionsFromControlConfig<ResolvedFilterColumnIdFromSchema<T, TSchema>, ConfigSection<TSchema, 'filters'>>;
|
|
573
|
+
/** Metric union narrowed by explicit schema restrictions when present. */
|
|
574
|
+
export type RestrictedMetricFromSchema<T, TSchema extends ChartSchema<T, any> | undefined = undefined> = ExcludeHiddenOrFallback<RestrictUnionOrFallback<ExpandMetricAllowance<AllowedMetricFromConfig<TSchema>>, Metric<ResolvedMetricColumnIdFromSchema<T, TSchema>>>, HiddenMetricFromConfig<TSchema>>;
|
|
575
|
+
/** Chart types narrowed by explicit schema restrictions when present. */
|
|
576
|
+
export type RestrictedChartTypeFromSchema<TSchema> = RestrictOptionsFromControlConfig<ChartType, ConfigSection<TSchema, 'chartType'>>;
|
|
577
|
+
/** Time buckets narrowed by explicit schema restrictions when present. */
|
|
578
|
+
export type RestrictedTimeBucketFromSchema<TSchema> = RestrictOptionsFromControlConfig<TimeBucket, ConfigSection<TSchema, 'timeBucket'>>;
|
|
579
|
+
/** Base properties shared by all column types. */
|
|
580
|
+
type ColumnBase<T, TId extends string> = {
|
|
581
|
+
/** Unique identifier — typically the field key in the data object. */
|
|
582
|
+
id: TId;
|
|
583
|
+
/** Human-readable label for the UI. */
|
|
584
|
+
label: string;
|
|
585
|
+
/** Optional display formatter preset used by the UI layer. */
|
|
586
|
+
format?: ColumnFormat;
|
|
587
|
+
/**
|
|
588
|
+
* Optional per-value formatter used by the UI layer.
|
|
589
|
+
*
|
|
590
|
+
* The source `item` is passed when the rendered value still maps to one raw
|
|
591
|
+
* row, such as filter option labels. Aggregated chart values do not have a
|
|
592
|
+
* single backing row, so `item` is optional there by design.
|
|
593
|
+
*/
|
|
594
|
+
formatter?: (value: unknown, item?: T) => string;
|
|
595
|
+
/** Optional debug metadata describing how the column was inferred. */
|
|
596
|
+
inference?: ColumnInferenceMetadata;
|
|
597
|
+
};
|
|
598
|
+
/**
|
|
599
|
+
* A date column — eligible as a time-series X-axis.
|
|
600
|
+
*
|
|
601
|
+
* @property accessor - Extracts a date value from a data item
|
|
602
|
+
*/
|
|
603
|
+
export type DateColumn<T, TId extends string = string> = ColumnBase<T, TId> & {
|
|
604
|
+
type: 'date';
|
|
605
|
+
accessor: (item: T) => string | number | Date | null | undefined;
|
|
606
|
+
};
|
|
607
|
+
/**
|
|
608
|
+
* A category column — eligible for X-axis, groupBy, and filtering.
|
|
609
|
+
*
|
|
610
|
+
* @property accessor - Extracts a string category value from a data item
|
|
611
|
+
*/
|
|
612
|
+
export type CategoryColumn<T, TId extends string = string> = ColumnBase<T, TId> & {
|
|
613
|
+
type: 'category';
|
|
614
|
+
accessor: (item: T) => string | null | undefined;
|
|
615
|
+
};
|
|
616
|
+
/**
|
|
617
|
+
* A boolean column — eligible for groupBy (2 groups) and toggle filtering.
|
|
618
|
+
*
|
|
619
|
+
* @property accessor - Extracts a boolean value from a data item
|
|
620
|
+
* @property trueLabel - Label for the `true` group (e.g. "Open")
|
|
621
|
+
* @property falseLabel - Label for the `false` group (e.g. "Closed")
|
|
622
|
+
*/
|
|
623
|
+
export type BooleanColumn<T, TId extends string = string> = ColumnBase<T, TId> & {
|
|
624
|
+
type: 'boolean';
|
|
625
|
+
accessor: (item: T) => boolean | null | undefined;
|
|
626
|
+
trueLabel: string;
|
|
627
|
+
falseLabel: string;
|
|
628
|
+
};
|
|
629
|
+
/**
|
|
630
|
+
* A number column — eligible as a metric for aggregation.
|
|
631
|
+
*
|
|
632
|
+
* @property accessor - Extracts a numeric value from a data item
|
|
633
|
+
*/
|
|
634
|
+
export type NumberColumn<T, TId extends string = string> = ColumnBase<T, TId> & {
|
|
635
|
+
type: 'number';
|
|
636
|
+
accessor: (item: T) => number | null | undefined;
|
|
637
|
+
};
|
|
638
|
+
/** Union of all column types. */
|
|
639
|
+
export type ChartColumn<T, TId extends string = string> = DateColumn<T, TId> | CategoryColumn<T, TId> | BooleanColumn<T, TId> | NumberColumn<T, TId>;
|
|
640
|
+
/** Chart types available for time-series (date X-axis). */
|
|
641
|
+
export type TimeSeriesChartType = 'bar' | 'line' | 'area';
|
|
642
|
+
/** Chart types available for categorical (category/boolean X-axis). */
|
|
643
|
+
export type CategoricalChartType = 'bar' | 'pie' | 'donut';
|
|
644
|
+
/** All supported chart types. */
|
|
645
|
+
export type ChartType = TimeSeriesChartType | CategoricalChartType;
|
|
646
|
+
/** Time bucket sizes for date X-axis. */
|
|
647
|
+
export type TimeBucket = 'day' | 'week' | 'month' | 'quarter' | 'year';
|
|
648
|
+
/** Aggregation functions for the Y-axis metric. */
|
|
649
|
+
export type AggregateFunction = 'count' | 'sum' | 'avg' | 'min' | 'max';
|
|
650
|
+
/** Numeric aggregation functions that operate on number columns. */
|
|
651
|
+
export type NumericAggregateFunction = Exclude<AggregateFunction, 'count'>;
|
|
652
|
+
/** One or many numeric aggregates accepted by declarative metric restrictions. */
|
|
653
|
+
export type NumericAggregateSelection = NumericAggregateFunction | readonly NumericAggregateFunction[];
|
|
654
|
+
/**
|
|
655
|
+
* A metric definition — what the Y-axis measures.
|
|
656
|
+
*
|
|
657
|
+
* `count` represents item count.
|
|
658
|
+
* `aggregate` represents a numeric column aggregation.
|
|
659
|
+
*/
|
|
660
|
+
export type CountMetric = {
|
|
661
|
+
kind: 'count';
|
|
662
|
+
};
|
|
663
|
+
/**
|
|
664
|
+
* A numeric aggregation metric.
|
|
665
|
+
*
|
|
666
|
+
* @property columnId - The number column to aggregate
|
|
667
|
+
* @property aggregate - The numeric aggregation function to apply
|
|
668
|
+
* @property includeZeros - Whether zero values are included in aggregation
|
|
669
|
+
*/
|
|
670
|
+
export type AggregateMetric<TColumnId extends string = string> = {
|
|
671
|
+
kind: 'aggregate';
|
|
672
|
+
columnId: TColumnId;
|
|
673
|
+
aggregate: NumericAggregateFunction;
|
|
674
|
+
includeZeros?: boolean;
|
|
675
|
+
};
|
|
676
|
+
/** Metric union returned by the chart hook. */
|
|
677
|
+
export type Metric<TColumnId extends string = string> = CountMetric | AggregateMetric<TColumnId>;
|
|
678
|
+
/**
|
|
679
|
+
* Aggregate metric restriction accepted by `config.metric.allowed`.
|
|
680
|
+
*
|
|
681
|
+
* Unlike `AggregateMetric`, the `aggregate` field may be either one aggregate
|
|
682
|
+
* or an array shorthand that expands into several allowed metrics.
|
|
683
|
+
*/
|
|
684
|
+
export type AggregateMetricAllowance<TColumnId extends string = string> = {
|
|
685
|
+
kind: 'aggregate';
|
|
686
|
+
columnId: TColumnId;
|
|
687
|
+
aggregate: NumericAggregateSelection;
|
|
688
|
+
includeZeros?: boolean;
|
|
689
|
+
};
|
|
690
|
+
/** One declarative metric entry accepted by `config.metric.allowed`. */
|
|
691
|
+
export type MetricAllowance<TColumnId extends string = string> = CountMetric | AggregateMetricAllowance<TColumnId>;
|
|
692
|
+
/** Shared config shape for one selectable control. */
|
|
693
|
+
export type SelectableControlConfig<TOption extends string = string> = {
|
|
694
|
+
/** Optional whitelist of options that remain visible/selectable. */
|
|
695
|
+
allowed?: readonly TOption[];
|
|
696
|
+
/** Optional blacklist of options to hide after whitelisting. */
|
|
697
|
+
hidden?: readonly TOption[];
|
|
698
|
+
/** Preferred selection when the current value is missing or invalid. */
|
|
699
|
+
default?: TOption;
|
|
700
|
+
};
|
|
701
|
+
/** Declarative config for the X-axis control. */
|
|
702
|
+
export type XAxisConfig<TColumnId extends string = string> = SelectableControlConfig<TColumnId>;
|
|
703
|
+
/** Declarative config for the groupBy control. */
|
|
704
|
+
export type GroupByConfig<TColumnId extends string = string> = SelectableControlConfig<TColumnId>;
|
|
705
|
+
/**
|
|
706
|
+
* Declarative config for which columns may appear in the filters UI.
|
|
707
|
+
*
|
|
708
|
+
* Filter value restrictions are intentionally out of scope for now. This keeps
|
|
709
|
+
* `filters` aligned with the existing column-first headless model.
|
|
710
|
+
*/
|
|
711
|
+
export type FiltersConfig<TColumnId extends string = string> = Omit<SelectableControlConfig<TColumnId>, 'default'>;
|
|
712
|
+
/**
|
|
713
|
+
* Declarative config for the metric control.
|
|
714
|
+
*
|
|
715
|
+
* `allowed` keeps the shorthand array-expansion form while `hidden` and
|
|
716
|
+
* `default` operate on fully resolved metric objects.
|
|
717
|
+
*/
|
|
718
|
+
export type MetricConfig<TColumnId extends string = string> = {
|
|
719
|
+
allowed?: readonly MetricAllowance<TColumnId>[];
|
|
720
|
+
hidden?: readonly Metric<TColumnId>[];
|
|
721
|
+
default?: Metric<TColumnId>;
|
|
722
|
+
};
|
|
723
|
+
/** Declarative config for chart-type selection. */
|
|
724
|
+
export type ChartTypeConfig = SelectableControlConfig<ChartType>;
|
|
725
|
+
/** Declarative config for time-bucket selection. */
|
|
726
|
+
export type TimeBucketConfig = SelectableControlConfig<TimeBucket>;
|
|
727
|
+
/**
|
|
728
|
+
* Explicit chart config supported by `useChart()`.
|
|
729
|
+
*
|
|
730
|
+
* `columnHints` stays convenience-first and influences inference.
|
|
731
|
+
* `config` becomes authoritative when callers want to restrict the public chart contract.
|
|
732
|
+
*/
|
|
733
|
+
export type ChartConfig<TXAxisColumnId extends string = string, TGroupByColumnId extends string = string, TFilterColumnId extends string = string, TMetricColumnId extends string = string> = {
|
|
734
|
+
xAxis?: XAxisConfig<TXAxisColumnId>;
|
|
735
|
+
groupBy?: GroupByConfig<TGroupByColumnId>;
|
|
736
|
+
filters?: FiltersConfig<TFilterColumnId>;
|
|
737
|
+
metric?: MetricConfig<TMetricColumnId>;
|
|
738
|
+
chartType?: ChartTypeConfig;
|
|
739
|
+
timeBucket?: TimeBucketConfig;
|
|
740
|
+
};
|
|
741
|
+
type ChartConfigDefinitionBrand = {
|
|
742
|
+
readonly __chartConfigBrand: 'chart-config-definition';
|
|
743
|
+
};
|
|
744
|
+
type ExtractSchemaColumns<TSchema> = TSchema extends {
|
|
745
|
+
columns?: infer TColumns;
|
|
746
|
+
} ? Extract<TColumns, Record<string, unknown>> : undefined;
|
|
747
|
+
type RawSchemaColumnsFromColumns<T, TColumns extends Record<string, unknown> | undefined> = TColumns extends Record<string, unknown> ? {
|
|
748
|
+
[TKey in keyof TColumns as TKey extends InferableFieldKey<T> ? TKey : never]: TColumns[TKey];
|
|
749
|
+
} : undefined;
|
|
750
|
+
type RawSchemaColumns<T, TSchema> = RawSchemaColumnsFromColumns<T, ExtractSchemaColumns<TSchema>>;
|
|
751
|
+
type DerivedColumnIdsFromColumns<TColumns extends Record<string, unknown> | undefined> = Extract<TColumns extends Record<string, unknown> ? {
|
|
752
|
+
[TKey in keyof TColumns]-?: TColumns[TKey] extends DerivedColumnSchema<any> ? TKey : never;
|
|
753
|
+
}[keyof TColumns] : never, string>;
|
|
754
|
+
type DerivedColumnIdsByTypeFromColumns<TColumns extends Record<string, unknown> | undefined, TAllowedType extends ChartColumnType> = Extract<TColumns extends Record<string, unknown> ? {
|
|
755
|
+
[TKey in keyof TColumns]-?: TColumns[TKey] extends {
|
|
756
|
+
kind: 'derived';
|
|
757
|
+
type: infer TType;
|
|
758
|
+
} ? Extract<TType, TAllowedType> extends never ? never : TKey : never;
|
|
759
|
+
}[keyof TColumns] : never, string>;
|
|
760
|
+
/** Column ID union resolved from one explicit schema definition. */
|
|
761
|
+
export type ResolvedColumnIdFromSchema<T, TSchema extends {
|
|
762
|
+
columns?: Record<string, unknown>;
|
|
763
|
+
} | undefined = undefined> = ResolvedColumnIdFromHints<T, Extract<RawSchemaColumns<T, TSchema>, ColumnHints<T> | undefined>> | DerivedColumnIdsFromColumns<ExtractSchemaColumns<TSchema>>;
|
|
764
|
+
/** X-axis IDs resolved from one explicit schema definition. */
|
|
765
|
+
export type ResolvedXAxisColumnIdFromSchema<T, TSchema extends {
|
|
766
|
+
columns?: Record<string, unknown>;
|
|
767
|
+
} | undefined = undefined> = ResolvedXAxisColumnIdFromHints<T, Extract<RawSchemaColumns<T, TSchema>, ColumnHints<T> | undefined>> | DerivedColumnIdsByTypeFromColumns<ExtractSchemaColumns<TSchema>, 'date' | 'category' | 'boolean'>;
|
|
768
|
+
/** GroupBy IDs resolved from one explicit schema definition. */
|
|
769
|
+
export type ResolvedGroupByColumnIdFromSchema<T, TSchema extends {
|
|
770
|
+
columns?: Record<string, unknown>;
|
|
771
|
+
} | undefined = undefined> = ResolvedGroupByColumnIdFromHints<T, Extract<RawSchemaColumns<T, TSchema>, ColumnHints<T> | undefined>> | DerivedColumnIdsByTypeFromColumns<ExtractSchemaColumns<TSchema>, 'category' | 'boolean'>;
|
|
772
|
+
/** Filter IDs resolved from one explicit schema definition. */
|
|
773
|
+
export type ResolvedFilterColumnIdFromSchema<T, TSchema extends {
|
|
774
|
+
columns?: Record<string, unknown>;
|
|
775
|
+
} | undefined = undefined> = ResolvedFilterColumnIdFromHints<T, Extract<RawSchemaColumns<T, TSchema>, ColumnHints<T> | undefined>> | DerivedColumnIdsByTypeFromColumns<ExtractSchemaColumns<TSchema>, 'category' | 'boolean'>;
|
|
776
|
+
/** Metric column IDs resolved from one explicit schema definition. */
|
|
777
|
+
export type ResolvedMetricColumnIdFromSchema<T, TSchema extends {
|
|
778
|
+
columns?: Record<string, unknown>;
|
|
779
|
+
} | undefined = undefined> = ResolvedMetricColumnIdFromHints<T, Extract<RawSchemaColumns<T, TSchema>, ColumnHints<T> | undefined>> | DerivedColumnIdsByTypeFromColumns<ExtractSchemaColumns<TSchema>, 'number'>;
|
|
780
|
+
/** Date column IDs resolved from one explicit schema definition. */
|
|
781
|
+
export type ResolvedDateColumnIdFromSchema<T, TSchema extends {
|
|
782
|
+
columns?: Record<string, unknown>;
|
|
783
|
+
} | undefined = undefined> = ResolvedDateColumnIdFromHints<T, Extract<RawSchemaColumns<T, TSchema>, ColumnHints<T> | undefined>> | DerivedColumnIdsByTypeFromColumns<ExtractSchemaColumns<TSchema>, 'date'>;
|
|
784
|
+
/**
|
|
785
|
+
* Single authoritative explicit chart schema accepted by `useChart({schema})`.
|
|
786
|
+
*
|
|
787
|
+
* Think of this as the contract that sits on top of inference:
|
|
788
|
+
* - `columns` shapes what fields exist and how they behave
|
|
789
|
+
* - the top-level sections shape what the user is allowed to select in the UI
|
|
790
|
+
*/
|
|
791
|
+
export type ChartSchema<T, TColumns extends Record<string, unknown> | undefined = Record<string, unknown> | undefined> = {
|
|
792
|
+
/**
|
|
793
|
+
* Override raw inferred fields, exclude raw fields with `false`, or declare
|
|
794
|
+
* brand new derived columns.
|
|
795
|
+
*/
|
|
796
|
+
columns?: TColumns & Partial<Record<InferableFieldKey<T>, unknown>>;
|
|
797
|
+
/** Restrict which non-numeric columns can be selected on the X-axis. */
|
|
798
|
+
xAxis?: XAxisConfig<string>;
|
|
799
|
+
/** Restrict which categorical/boolean columns can split the chart into series. */
|
|
800
|
+
groupBy?: GroupByConfig<string>;
|
|
801
|
+
/** Restrict which categorical/boolean columns appear in the filters UI. */
|
|
802
|
+
filters?: FiltersConfig<string>;
|
|
803
|
+
/** Restrict which metrics and aggregations can be selected. */
|
|
804
|
+
metric?: MetricConfig<string>;
|
|
805
|
+
/** Restrict which chart types are available to the user. */
|
|
806
|
+
chartType?: ChartTypeConfig;
|
|
807
|
+
/** Restrict which time buckets are available for date X-axes. */
|
|
808
|
+
timeBucket?: TimeBucketConfig;
|
|
809
|
+
};
|
|
810
|
+
type ChartSchemaDefinitionBrand = {
|
|
811
|
+
readonly __chartSchemaBrand: 'chart-schema-definition';
|
|
812
|
+
};
|
|
813
|
+
/**
|
|
814
|
+
* Active filter state per column.
|
|
815
|
+
* - For category columns: Set of selected values (empty = no filter = show all)
|
|
816
|
+
* - For boolean columns: true/false/null (null = no filter)
|
|
817
|
+
*/
|
|
818
|
+
export type FilterState<TColumnId extends string = string> = Map<TColumnId, Set<string>>;
|
|
819
|
+
/** Sort direction. */
|
|
820
|
+
export type SortDirection = 'asc' | 'desc';
|
|
821
|
+
/**
|
|
822
|
+
* Sort configuration.
|
|
823
|
+
*
|
|
824
|
+
* @property key - The data key to sort by (e.g. "count", a group label)
|
|
825
|
+
* @property direction - Sort direction
|
|
826
|
+
*/
|
|
827
|
+
export type SortConfig = {
|
|
828
|
+
key: string;
|
|
829
|
+
direction: SortDirection;
|
|
830
|
+
};
|
|
831
|
+
/**
|
|
832
|
+
* Inference-first source definition accepted by multi-source charts.
|
|
833
|
+
*
|
|
834
|
+
* @property id - Unique identifier for this source
|
|
835
|
+
* @property label - Display label in the source switcher
|
|
836
|
+
* @property data - Array of raw data items
|
|
837
|
+
* @property schema - Optional explicit schema layered on top of inference
|
|
838
|
+
*/
|
|
839
|
+
export type ChartSourceOptions<TId extends string = string, T = unknown, TSchema extends ChartSchema<T, any> | undefined = undefined> = {
|
|
840
|
+
id: TId;
|
|
841
|
+
label: string;
|
|
842
|
+
data: readonly T[];
|
|
843
|
+
schema?: DefinedChartSchema<T, Exclude<TSchema, undefined>>;
|
|
844
|
+
};
|
|
845
|
+
/** Convenience alias for any multi-source input definition. */
|
|
846
|
+
export type AnyChartSourceOptions = {
|
|
847
|
+
id: string;
|
|
848
|
+
label: string;
|
|
849
|
+
data: readonly any[];
|
|
850
|
+
schema?: any;
|
|
851
|
+
};
|
|
852
|
+
/** Multi-source charts require at least one source so an active source always exists. */
|
|
853
|
+
export type NonEmptyChartSourceOptions = readonly [
|
|
854
|
+
AnyChartSourceOptions,
|
|
855
|
+
...AnyChartSourceOptions[]
|
|
856
|
+
];
|
|
857
|
+
/**
|
|
858
|
+
* Internal normalized source shape after inference has resolved columns.
|
|
859
|
+
*
|
|
860
|
+
* @property id - Unique identifier for this source
|
|
861
|
+
* @property label - Display label in the source switcher
|
|
862
|
+
* @property data - Array of raw data items
|
|
863
|
+
* @property columns - Column definitions for this source
|
|
864
|
+
*/
|
|
865
|
+
export type ResolvedChartSource<T, TColumnId extends string = string> = {
|
|
866
|
+
id: string;
|
|
867
|
+
label: string;
|
|
868
|
+
data: readonly T[];
|
|
869
|
+
columns: readonly ChartColumn<T, TColumnId>[];
|
|
870
|
+
schema?: ChartSchema<T, any>;
|
|
871
|
+
};
|
|
872
|
+
/**
|
|
873
|
+
* A single series to render in the chart.
|
|
874
|
+
*
|
|
875
|
+
* @property dataKey - Key in the transformed data row
|
|
876
|
+
* @property label - Display label for tooltips/legend
|
|
877
|
+
* @property color - CSS color value (shadcn chart variable)
|
|
878
|
+
*/
|
|
879
|
+
export type ChartSeries = {
|
|
880
|
+
dataKey: string;
|
|
881
|
+
label: string;
|
|
882
|
+
color: string;
|
|
883
|
+
};
|
|
884
|
+
/**
|
|
885
|
+
* A single data point in the transformed output.
|
|
886
|
+
* Keys are dynamic based on groupBy values.
|
|
887
|
+
*/
|
|
888
|
+
export type TransformedDataPoint = Record<string, string | number>;
|
|
889
|
+
/**
|
|
890
|
+
* Available filter options extracted from the data for a column.
|
|
891
|
+
*
|
|
892
|
+
* @property columnId - The column this filter belongs to
|
|
893
|
+
* @property label - Column label
|
|
894
|
+
* @property type - Column type (category or boolean)
|
|
895
|
+
* @property options - Available values with counts
|
|
896
|
+
*/
|
|
897
|
+
export type AvailableFilter<TColumnId extends string = string> = {
|
|
898
|
+
columnId: TColumnId;
|
|
899
|
+
label: string;
|
|
900
|
+
type: 'category' | 'boolean';
|
|
901
|
+
options: Array<{
|
|
902
|
+
value: string;
|
|
903
|
+
label: string;
|
|
904
|
+
count: number;
|
|
905
|
+
}>;
|
|
906
|
+
};
|
|
907
|
+
/**
|
|
908
|
+
* Date range for a date column computed from the (filtered) data.
|
|
909
|
+
*
|
|
910
|
+
* @property columnId - The date column this range belongs to
|
|
911
|
+
* @property label - Column display label
|
|
912
|
+
* @property min - Earliest date in the data (null if no valid dates)
|
|
913
|
+
* @property max - Latest date in the data (null if no valid dates)
|
|
914
|
+
*/
|
|
915
|
+
export type DateRange<TColumnId extends string = string> = {
|
|
916
|
+
columnId: TColumnId;
|
|
917
|
+
label: string;
|
|
918
|
+
min: Date | null;
|
|
919
|
+
max: Date | null;
|
|
920
|
+
};
|
|
921
|
+
/**
|
|
922
|
+
* User-selected date range filter applied to the reference date column.
|
|
923
|
+
* Both bounds are inclusive. Null = no bound on that side.
|
|
924
|
+
*
|
|
925
|
+
* @property from - Start date (inclusive), null = no lower bound
|
|
926
|
+
* @property to - End date (inclusive), null = no upper bound
|
|
927
|
+
*/
|
|
928
|
+
export type DateRangeFilter = {
|
|
929
|
+
from: Date | null;
|
|
930
|
+
to: Date | null;
|
|
931
|
+
};
|
|
932
|
+
/**
|
|
933
|
+
* Full chart state returned by the useChart hook.
|
|
934
|
+
* Contains both controlled state and derived computations.
|
|
935
|
+
*/
|
|
936
|
+
export type ChartInstance<T, TColumnId extends string = string, TChartType extends ChartType = ChartType, TXAxisId extends TColumnId = TColumnId, TGroupById extends TColumnId = TColumnId, TMetricColumnId extends TColumnId = TColumnId, TMetric extends Metric<any> = Metric<TMetricColumnId>, TFilterColumnId extends TColumnId = TColumnId, TDateColumnId extends TColumnId = TColumnId, TTimeBucket extends TimeBucket = TimeBucket> = {
|
|
937
|
+
/** Active source ID (only relevant for multi-source). */
|
|
938
|
+
activeSourceId: string;
|
|
939
|
+
/** Switch to a different data source. */
|
|
940
|
+
setActiveSource: (sourceId: string) => void;
|
|
941
|
+
/** Whether multiple sources are available. */
|
|
942
|
+
hasMultipleSources: boolean;
|
|
943
|
+
/** Labels for all available sources. */
|
|
944
|
+
sources: Array<{
|
|
945
|
+
id: string;
|
|
946
|
+
label: string;
|
|
947
|
+
}>;
|
|
948
|
+
/** Current chart type. */
|
|
949
|
+
chartType: TChartType;
|
|
950
|
+
/** Change the chart type. Runtime accepts only values in `availableChartTypes`. */
|
|
951
|
+
setChartType: (type: TChartType) => void;
|
|
952
|
+
/** Chart types currently available given the active axis, grouping, and config. */
|
|
953
|
+
availableChartTypes: TChartType[];
|
|
954
|
+
/** Current X-axis column ID. */
|
|
955
|
+
xAxisId: TXAxisId | null;
|
|
956
|
+
/**
|
|
957
|
+
* Change the X-axis column.
|
|
958
|
+
* Runtime accepts only IDs currently present in `availableXAxes`.
|
|
959
|
+
*/
|
|
960
|
+
setXAxis: (columnId: TXAxisId) => void;
|
|
961
|
+
/**
|
|
962
|
+
* Columns currently eligible for X-axis at runtime.
|
|
963
|
+
* Typing narrows only from explicit `columnHints.type`, not from runtime inference.
|
|
964
|
+
*/
|
|
965
|
+
availableXAxes: Array<{
|
|
966
|
+
id: TXAxisId;
|
|
967
|
+
label: string;
|
|
968
|
+
type: 'date' | 'category' | 'boolean';
|
|
969
|
+
}>;
|
|
970
|
+
/** Current groupBy column ID (null = no grouping). */
|
|
971
|
+
groupById: TGroupById | null;
|
|
972
|
+
/**
|
|
973
|
+
* Change the groupBy column.
|
|
974
|
+
* Runtime accepts only `null` or IDs currently present in `availableGroupBys`.
|
|
975
|
+
*/
|
|
976
|
+
setGroupBy: (columnId: TGroupById | null) => void;
|
|
977
|
+
/**
|
|
978
|
+
* Columns currently eligible for groupBy at runtime.
|
|
979
|
+
* Explicit `config.groupBy.allowed` further narrows this list and the setter type.
|
|
980
|
+
*/
|
|
981
|
+
availableGroupBys: Array<{
|
|
982
|
+
id: TGroupById;
|
|
983
|
+
label: string;
|
|
984
|
+
}>;
|
|
985
|
+
/** Current metric (what the Y-axis measures). */
|
|
986
|
+
metric: TMetric;
|
|
987
|
+
/**
|
|
988
|
+
* Change the metric.
|
|
989
|
+
* Runtime accepts only metrics currently present in `availableMetrics`.
|
|
990
|
+
*/
|
|
991
|
+
setMetric: (metric: TMetric) => void;
|
|
992
|
+
/**
|
|
993
|
+
* Metrics currently available at runtime.
|
|
994
|
+
* Explicit `config.metric.allowed` narrows both this list and the setter type.
|
|
995
|
+
*/
|
|
996
|
+
availableMetrics: TMetric[];
|
|
997
|
+
/** Current time bucket (only relevant when X-axis is date). */
|
|
998
|
+
timeBucket: TTimeBucket;
|
|
999
|
+
/** Change the time bucket. Runtime accepts only values in `availableTimeBuckets`. */
|
|
1000
|
+
setTimeBucket: (bucket: TTimeBucket) => void;
|
|
1001
|
+
/** Time buckets currently available for the active chart state and config. */
|
|
1002
|
+
availableTimeBuckets: TTimeBucket[];
|
|
1003
|
+
/** Whether time bucketing controls should be shown. */
|
|
1004
|
+
isTimeSeries: boolean;
|
|
1005
|
+
/** Active filter values per column. */
|
|
1006
|
+
filters: FilterState<TFilterColumnId>;
|
|
1007
|
+
/**
|
|
1008
|
+
* Toggle a specific filter value on/off for a column.
|
|
1009
|
+
* Runtime accepts only values currently exposed through `availableFilters`.
|
|
1010
|
+
*/
|
|
1011
|
+
toggleFilter: (columnId: TFilterColumnId, value: string) => void;
|
|
1012
|
+
/** Clear all filters for a column when that column is currently filterable. */
|
|
1013
|
+
clearFilter: (columnId: TFilterColumnId) => void;
|
|
1014
|
+
/** Clear all filters. */
|
|
1015
|
+
clearAllFilters: () => void;
|
|
1016
|
+
/** Filter options currently available from the runtime data. */
|
|
1017
|
+
availableFilters: AvailableFilter<TFilterColumnId>[];
|
|
1018
|
+
/** Current sort configuration (null = default order). */
|
|
1019
|
+
sorting: SortConfig | null;
|
|
1020
|
+
/** Change sorting. */
|
|
1021
|
+
setSorting: (sorting: SortConfig | null) => void;
|
|
1022
|
+
/** Date range for the active reference date column (computed from filtered data). */
|
|
1023
|
+
dateRange: DateRange<TDateColumnId> | null;
|
|
1024
|
+
/** Which date column provides the visible date range context. */
|
|
1025
|
+
referenceDateId: TDateColumnId | null;
|
|
1026
|
+
/**
|
|
1027
|
+
* Change the reference date column.
|
|
1028
|
+
* Runtime accepts only IDs currently present in `availableDateColumns`.
|
|
1029
|
+
*/
|
|
1030
|
+
setReferenceDateId: (columnId: TDateColumnId) => void;
|
|
1031
|
+
/** Date columns currently available as reference dates at runtime. */
|
|
1032
|
+
availableDateColumns: Array<{
|
|
1033
|
+
id: TDateColumnId;
|
|
1034
|
+
label: string;
|
|
1035
|
+
}>;
|
|
1036
|
+
/** Active date range filter (null = all time). */
|
|
1037
|
+
dateRangeFilter: DateRangeFilter | null;
|
|
1038
|
+
/** Set the date range filter. Pass null to clear (show all time). */
|
|
1039
|
+
setDateRangeFilter: (filter: DateRangeFilter | null) => void;
|
|
1040
|
+
/** Transformed data points ready for recharts. */
|
|
1041
|
+
transformedData: TransformedDataPoint[];
|
|
1042
|
+
/** Auto-generated series definitions for recharts. */
|
|
1043
|
+
series: ChartSeries[];
|
|
1044
|
+
/** Active columns for the current source. */
|
|
1045
|
+
columns: readonly ChartColumn<T, TColumnId>[];
|
|
1046
|
+
/** Raw data for the active source. */
|
|
1047
|
+
rawData: readonly T[];
|
|
1048
|
+
/** Total number of records in the active source (before filtering). */
|
|
1049
|
+
recordCount: number;
|
|
1050
|
+
};
|
|
1051
|
+
/** Single-source chart instance whose role-aware IDs are derived from `columnHints`. */
|
|
1052
|
+
export type ChartInstanceFromHints<T, THints extends ColumnHints<T> | undefined = undefined> = ChartInstance<T, ResolvedColumnIdFromHints<T, THints>, ChartType, ResolvedXAxisColumnIdFromHints<T, THints>, ResolvedGroupByColumnIdFromHints<T, THints>, ResolvedMetricColumnIdFromHints<T, THints>, Metric<ResolvedMetricColumnIdFromHints<T, THints>>, ResolvedFilterColumnIdFromHints<T, THints>, ResolvedDateColumnIdFromHints<T, THints>, TimeBucket>;
|
|
1053
|
+
/** Single-source chart instance narrowed by both explicit hints and explicit config. */
|
|
1054
|
+
export type ChartInstanceFromConfig<T, THints extends ColumnHints<T> | undefined = undefined, TConfig extends ChartConfigFromHints<T, THints> | undefined = undefined> = ChartInstance<T, ResolvedColumnIdFromHints<T, THints>, RestrictedChartTypeFromConfig<TConfig>, RestrictedXAxisColumnIdFromConfig<T, THints, TConfig>, RestrictedGroupByColumnIdFromConfig<T, THints, TConfig>, Extract<MetricColumnIdFromMetric<RestrictedMetricFromConfig<T, THints, TConfig>>, ResolvedMetricColumnIdFromHints<T, THints>>, RestrictedMetricFromConfig<T, THints, TConfig>, RestrictedFilterColumnIdFromConfig<T, THints, TConfig>, ResolvedDateColumnIdFromHints<T, THints>, RestrictedTimeBucketFromConfig<TConfig>>;
|
|
1055
|
+
/** Single-source chart instance narrowed by one explicit schema. */
|
|
1056
|
+
export type ChartInstanceFromSchema<T, TSchema extends ChartSchema<T, any> | undefined = undefined> = ChartInstance<T, ResolvedColumnIdFromSchema<T, TSchema>, RestrictedChartTypeFromSchema<TSchema>, RestrictedXAxisColumnIdFromSchema<T, TSchema>, RestrictedGroupByColumnIdFromSchema<T, TSchema>, Extract<MetricColumnIdFromMetric<RestrictedMetricFromSchema<T, TSchema>>, ResolvedMetricColumnIdFromSchema<T, TSchema>>, RestrictedMetricFromSchema<T, TSchema>, RestrictedFilterColumnIdFromSchema<T, TSchema>, ResolvedDateColumnIdFromSchema<T, TSchema>, RestrictedTimeBucketFromSchema<TSchema>>;
|
|
1057
|
+
type SourceIdFromSource<TSource extends AnyChartSourceOptions> = TSource['id'];
|
|
1058
|
+
type SourceRowFromSource<TSource extends AnyChartSourceOptions> = TSource extends ChartSourceOptions<string, infer TRow, any> ? TRow : never;
|
|
1059
|
+
type SourceColumnIdFromSource<TSource extends AnyChartSourceOptions> = TSource extends ChartSourceOptions<string, infer TRow, infer TSchema> ? ResolvedColumnIdFromSchema<TRow, Extract<TSchema, ChartSchema<TRow> | undefined>> : never;
|
|
1060
|
+
type SourceXAxisColumnIdFromSource<TSource extends AnyChartSourceOptions> = TSource extends ChartSourceOptions<string, infer TRow, infer TSchema> ? RestrictedXAxisColumnIdFromSchema<TRow, Extract<TSchema, ChartSchema<TRow> | undefined>> : never;
|
|
1061
|
+
type SourceGroupByColumnIdFromSource<TSource extends AnyChartSourceOptions> = TSource extends ChartSourceOptions<string, infer TRow, infer TSchema> ? RestrictedGroupByColumnIdFromSchema<TRow, Extract<TSchema, ChartSchema<TRow> | undefined>> : never;
|
|
1062
|
+
type SourceMetricColumnIdFromSource<TSource extends AnyChartSourceOptions> = TSource extends ChartSourceOptions<string, infer TRow, infer TSchema> ? Extract<MetricColumnIdFromMetric<RestrictedMetricFromSchema<TRow, Extract<TSchema, ChartSchema<TRow> | undefined>>>, ResolvedMetricColumnIdFromSchema<TRow, Extract<TSchema, ChartSchema<TRow> | undefined>>> : never;
|
|
1063
|
+
type SourceFilterColumnIdFromSource<TSource extends AnyChartSourceOptions> = TSource extends ChartSourceOptions<string, infer TRow, infer TSchema> ? RestrictedFilterColumnIdFromSchema<TRow, Extract<TSchema, ChartSchema<TRow> | undefined>> : never;
|
|
1064
|
+
type SourceDateColumnIdFromSource<TSource extends AnyChartSourceOptions> = TSource extends ChartSourceOptions<string, infer TRow, infer TSchema> ? ResolvedDateColumnIdFromSchema<TRow, Extract<TSchema, ChartSchema<TRow> | undefined>> : never;
|
|
1065
|
+
type SourceIdFromSources<TSources extends NonEmptyChartSourceOptions> = Extract<TSources[number]['id'], string>;
|
|
1066
|
+
type SourceColumnIdFromSources<TSources extends NonEmptyChartSourceOptions> = TSources[number] extends infer TSource ? TSource extends AnyChartSourceOptions ? SourceColumnIdFromSource<TSource> : never : never;
|
|
1067
|
+
type MultiSourceChartBranch<TSources extends NonEmptyChartSourceOptions, TSource extends AnyChartSourceOptions> = Omit<ChartInstance<SourceRowFromSource<TSource>, SourceColumnIdFromSources<TSources>>, 'activeSourceId' | 'setActiveSource' | 'sources' | 'xAxisId' | 'setXAxis' | 'availableXAxes' | 'groupById' | 'setGroupBy' | 'availableGroupBys' | 'metric' | 'setMetric' | 'availableMetrics' | 'filters' | 'toggleFilter' | 'clearFilter' | 'availableFilters' | 'dateRange' | 'referenceDateId' | 'setReferenceDateId' | 'availableDateColumns' | 'columns'> & {
|
|
1068
|
+
activeSourceId: SourceIdFromSource<TSource>;
|
|
1069
|
+
setActiveSource: (sourceId: SourceIdFromSources<TSources>) => void;
|
|
1070
|
+
sources: Array<{
|
|
1071
|
+
id: SourceIdFromSources<TSources>;
|
|
1072
|
+
label: string;
|
|
1073
|
+
}>;
|
|
1074
|
+
xAxisId: SourceXAxisColumnIdFromSource<TSource> | null;
|
|
1075
|
+
setXAxis: (columnId: SourceColumnIdFromSources<TSources>) => void;
|
|
1076
|
+
availableXAxes: Array<{
|
|
1077
|
+
id: SourceXAxisColumnIdFromSource<TSource>;
|
|
1078
|
+
label: string;
|
|
1079
|
+
type: 'date' | 'category' | 'boolean';
|
|
1080
|
+
}>;
|
|
1081
|
+
groupById: SourceGroupByColumnIdFromSource<TSource> | null;
|
|
1082
|
+
setGroupBy: (columnId: SourceColumnIdFromSources<TSources> | null) => void;
|
|
1083
|
+
availableGroupBys: Array<{
|
|
1084
|
+
id: SourceGroupByColumnIdFromSource<TSource>;
|
|
1085
|
+
label: string;
|
|
1086
|
+
}>;
|
|
1087
|
+
metric: Metric<SourceMetricColumnIdFromSource<TSource>>;
|
|
1088
|
+
setMetric: (metric: Metric<SourceColumnIdFromSources<TSources>>) => void;
|
|
1089
|
+
availableMetrics: Metric<SourceMetricColumnIdFromSource<TSource>>[];
|
|
1090
|
+
filters: FilterState<SourceFilterColumnIdFromSource<TSource>>;
|
|
1091
|
+
toggleFilter: (columnId: SourceColumnIdFromSources<TSources>, value: string) => void;
|
|
1092
|
+
clearFilter: (columnId: SourceColumnIdFromSources<TSources>) => void;
|
|
1093
|
+
availableFilters: AvailableFilter<SourceFilterColumnIdFromSource<TSource>>[];
|
|
1094
|
+
dateRange: DateRange<SourceDateColumnIdFromSource<TSource>> | null;
|
|
1095
|
+
referenceDateId: SourceDateColumnIdFromSource<TSource> | null;
|
|
1096
|
+
setReferenceDateId: (columnId: SourceColumnIdFromSources<TSources>) => void;
|
|
1097
|
+
availableDateColumns: Array<{
|
|
1098
|
+
id: SourceDateColumnIdFromSource<TSource>;
|
|
1099
|
+
label: string;
|
|
1100
|
+
}>;
|
|
1101
|
+
columns: readonly ChartColumn<SourceRowFromSource<TSource>, SourceColumnIdFromSource<TSource>>[];
|
|
1102
|
+
};
|
|
1103
|
+
/**
|
|
1104
|
+
* Direct multi-source hook return type.
|
|
1105
|
+
* Narrow on `activeSourceId` to recover the source-specific row and column IDs.
|
|
1106
|
+
*/
|
|
1107
|
+
export type MultiSourceChartInstance<TSources extends NonEmptyChartSourceOptions> = TSources[number] extends infer TSource ? TSource extends AnyChartSourceOptions ? MultiSourceChartBranch<TSources, TSource> : never : never;
|
|
1108
|
+
export {};
|
|
1109
|
+
//# sourceMappingURL=types.d.ts.map
|