@fluentui/react-charts 9.3.12 → 9.3.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +25 -2
  2. package/dist/index.d.ts +859 -0
  3. package/lib/VegaDeclarativeChart.js +1 -0
  4. package/lib/VegaDeclarativeChart.js.map +1 -0
  5. package/lib/components/LineChart/LineChart.js +47 -7
  6. package/lib/components/LineChart/LineChart.js.map +1 -1
  7. package/lib/components/ScatterChart/ScatterChart.js +12 -12
  8. package/lib/components/ScatterChart/ScatterChart.js.map +1 -1
  9. package/lib/components/VegaDeclarativeChart/VegaDeclarativeChart.js +405 -0
  10. package/lib/components/VegaDeclarativeChart/VegaDeclarativeChart.js.map +1 -0
  11. package/lib/components/VegaDeclarativeChart/VegaDeclarativeChartHooks.js +20 -0
  12. package/lib/components/VegaDeclarativeChart/VegaDeclarativeChartHooks.js.map +1 -0
  13. package/lib/components/VegaDeclarativeChart/VegaLiteColorAdapter.js +415 -0
  14. package/lib/components/VegaDeclarativeChart/VegaLiteColorAdapter.js.map +1 -0
  15. package/lib/components/VegaDeclarativeChart/VegaLiteExpressionEvaluator.js +537 -0
  16. package/lib/components/VegaDeclarativeChart/VegaLiteExpressionEvaluator.js.map +1 -0
  17. package/lib/components/VegaDeclarativeChart/VegaLiteSchemaAdapter.js +3279 -0
  18. package/lib/components/VegaDeclarativeChart/VegaLiteSchemaAdapter.js.map +1 -0
  19. package/lib/components/VegaDeclarativeChart/VegaLiteTypes.js +28 -0
  20. package/lib/components/VegaDeclarativeChart/VegaLiteTypes.js.map +1 -0
  21. package/lib/components/VegaDeclarativeChart/index.js +1 -0
  22. package/lib/components/VegaDeclarativeChart/index.js.map +1 -0
  23. package/lib/components/VerticalStackedBarChart/VerticalStackedBarChart.js +5 -2
  24. package/lib/components/VerticalStackedBarChart/VerticalStackedBarChart.js.map +1 -1
  25. package/lib/index.js +1 -0
  26. package/lib/index.js.map +1 -1
  27. package/lib/utilities/utilities.js +41 -0
  28. package/lib/utilities/utilities.js.map +1 -1
  29. package/lib-commonjs/VegaDeclarativeChart.js +6 -0
  30. package/lib-commonjs/VegaDeclarativeChart.js.map +1 -0
  31. package/lib-commonjs/components/LineChart/LineChart.js +46 -6
  32. package/lib-commonjs/components/LineChart/LineChart.js.map +1 -1
  33. package/lib-commonjs/components/ScatterChart/ScatterChart.js +11 -11
  34. package/lib-commonjs/components/ScatterChart/ScatterChart.js.map +1 -1
  35. package/lib-commonjs/components/VegaDeclarativeChart/VegaDeclarativeChart.js +274 -0
  36. package/lib-commonjs/components/VegaDeclarativeChart/VegaDeclarativeChart.js.map +1 -0
  37. package/lib-commonjs/components/VegaDeclarativeChart/VegaDeclarativeChartHooks.js +35 -0
  38. package/lib-commonjs/components/VegaDeclarativeChart/VegaDeclarativeChartHooks.js.map +1 -0
  39. package/lib-commonjs/components/VegaDeclarativeChart/VegaLiteColorAdapter.js +412 -0
  40. package/lib-commonjs/components/VegaDeclarativeChart/VegaLiteColorAdapter.js.map +1 -0
  41. package/lib-commonjs/components/VegaDeclarativeChart/VegaLiteExpressionEvaluator.js +533 -0
  42. package/lib-commonjs/components/VegaDeclarativeChart/VegaLiteExpressionEvaluator.js.map +1 -0
  43. package/lib-commonjs/components/VegaDeclarativeChart/VegaLiteSchemaAdapter.js +3214 -0
  44. package/lib-commonjs/components/VegaDeclarativeChart/VegaLiteSchemaAdapter.js.map +1 -0
  45. package/lib-commonjs/components/VegaDeclarativeChart/VegaLiteTypes.js +31 -0
  46. package/lib-commonjs/components/VegaDeclarativeChart/VegaLiteTypes.js.map +1 -0
  47. package/lib-commonjs/components/VegaDeclarativeChart/index.js +6 -0
  48. package/lib-commonjs/components/VegaDeclarativeChart/index.js.map +1 -0
  49. package/lib-commonjs/components/VerticalStackedBarChart/VerticalStackedBarChart.js +4 -1
  50. package/lib-commonjs/components/VerticalStackedBarChart/VerticalStackedBarChart.js.map +1 -1
  51. package/lib-commonjs/index.js +1 -0
  52. package/lib-commonjs/index.js.map +1 -1
  53. package/lib-commonjs/utilities/utilities.js +33 -0
  54. package/lib-commonjs/utilities/utilities.js.map +1 -1
  55. package/package.json +3 -3
@@ -0,0 +1,405 @@
1
+ 'use client';
2
+ import * as React from 'react';
3
+ import { transformVegaLiteToLineChartProps, transformVegaLiteToVerticalBarChartProps, transformVegaLiteToVerticalStackedBarChartProps, transformVegaLiteToGroupedVerticalBarChartProps, transformVegaLiteToHorizontalBarChartProps, transformVegaLiteToAreaChartProps, transformVegaLiteToScatterChartProps, transformVegaLiteToDonutChartProps, transformVegaLiteToHeatMapChartProps, transformVegaLiteToHistogramProps, transformVegaLiteToPolarChartProps, getChartType, getMarkType, getVegaLiteLegendsProps } from './VegaLiteSchemaAdapter';
4
+ import { Legends } from '../Legends/index';
5
+ import { withResponsiveContainer } from '../ResponsiveContainer/withResponsiveContainer';
6
+ import { LineChart } from '../LineChart/index';
7
+ import { VerticalBarChart } from '../VerticalBarChart/index';
8
+ import { VerticalStackedBarChart } from '../VerticalStackedBarChart/index';
9
+ import { GroupedVerticalBarChart } from '../GroupedVerticalBarChart/index';
10
+ import { HorizontalBarChartWithAxis } from '../HorizontalBarChartWithAxis/index';
11
+ import { AreaChart } from '../AreaChart/index';
12
+ import { ScatterChart } from '../ScatterChart/index';
13
+ import { DonutChart } from '../DonutChart/index';
14
+ import { HeatMapChart } from '../HeatMapChart/index';
15
+ import { PolarChart } from '../PolarChart/index';
16
+ import { useIsDarkTheme, useColorMapping } from './VegaDeclarativeChartHooks';
17
+ /**
18
+ * Maximum allowed nesting depth for incoming JSON specs.
19
+ * Matches the Plotly adapter's MAX_DEPTH to prevent stack overflow / memory exhaustion.
20
+ */ const MAX_DEPTH = 15;
21
+ /**
22
+ * Validates that a JSON value does not exceed the maximum nesting depth.
23
+ * Throws if the depth limit is exceeded (same behavior as Plotly's sanitizeJson).
24
+ */ function validateJsonDepth(value, depth = 0) {
25
+ if (depth > MAX_DEPTH) {
26
+ throw new Error('VegaDeclarativeChart: Maximum JSON depth exceeded');
27
+ }
28
+ if (value !== null && typeof value === 'object') {
29
+ for (const key of Object.keys(value)){
30
+ validateJsonDepth(value[key], depth + 1);
31
+ }
32
+ }
33
+ }
34
+ /**
35
+ * Check if spec is a horizontal concatenation
36
+ */ function isHConcatSpec(spec) {
37
+ return !!spec.hconcat && Array.isArray(spec.hconcat) && spec.hconcat.length > 0;
38
+ }
39
+ /**
40
+ * Check if spec is a vertical concatenation
41
+ */ function isVConcatSpec(spec) {
42
+ return !!spec.vconcat && Array.isArray(spec.vconcat) && spec.vconcat.length > 0;
43
+ }
44
+ /**
45
+ * Get grid properties for concat specs
46
+ */ function getVegaConcatGridProperties(spec) {
47
+ if (isHConcatSpec(spec)) {
48
+ return {
49
+ templateRows: 'auto',
50
+ templateColumns: `repeat(${spec.hconcat.length}, 1fr)`,
51
+ isHorizontal: true,
52
+ specs: spec.hconcat
53
+ };
54
+ }
55
+ if (isVConcatSpec(spec)) {
56
+ return {
57
+ templateRows: `repeat(${spec.vconcat.length}, auto)`,
58
+ templateColumns: '1fr',
59
+ isHorizontal: false,
60
+ specs: spec.vconcat
61
+ };
62
+ }
63
+ return {
64
+ templateRows: '1fr',
65
+ templateColumns: '1fr',
66
+ isHorizontal: false,
67
+ specs: [
68
+ spec
69
+ ]
70
+ };
71
+ }
72
+ const ResponsiveLineChart = withResponsiveContainer(LineChart);
73
+ const ResponsiveVerticalBarChart = withResponsiveContainer(VerticalBarChart);
74
+ const ResponsiveVerticalStackedBarChart = withResponsiveContainer(VerticalStackedBarChart);
75
+ const ResponsiveGroupedVerticalBarChart = withResponsiveContainer(GroupedVerticalBarChart);
76
+ const ResponsiveHorizontalBarChartWithAxis = withResponsiveContainer(HorizontalBarChartWithAxis);
77
+ const ResponsiveAreaChart = withResponsiveContainer(AreaChart);
78
+ const ResponsiveScatterChart = withResponsiveContainer(ScatterChart);
79
+ const ResponsiveDonutChart = withResponsiveContainer(DonutChart);
80
+ const ResponsiveHeatMapChart = withResponsiveContainer(HeatMapChart);
81
+ const ResponsivePolarChart = withResponsiveContainer(PolarChart);
82
+ const vegaChartMap = {
83
+ line: {
84
+ transformer: transformVegaLiteToLineChartProps,
85
+ renderer: ResponsiveLineChart
86
+ },
87
+ bar: {
88
+ transformer: transformVegaLiteToVerticalBarChartProps,
89
+ renderer: ResponsiveVerticalBarChart
90
+ },
91
+ 'stacked-bar': {
92
+ transformer: transformVegaLiteToVerticalStackedBarChartProps,
93
+ renderer: ResponsiveVerticalStackedBarChart
94
+ },
95
+ 'grouped-bar': {
96
+ transformer: transformVegaLiteToGroupedVerticalBarChartProps,
97
+ renderer: ResponsiveGroupedVerticalBarChart
98
+ },
99
+ 'horizontal-bar': {
100
+ transformer: transformVegaLiteToHorizontalBarChartProps,
101
+ renderer: ResponsiveHorizontalBarChartWithAxis
102
+ },
103
+ area: {
104
+ transformer: transformVegaLiteToAreaChartProps,
105
+ renderer: ResponsiveAreaChart
106
+ },
107
+ scatter: {
108
+ transformer: transformVegaLiteToScatterChartProps,
109
+ renderer: ResponsiveScatterChart
110
+ },
111
+ donut: {
112
+ transformer: transformVegaLiteToDonutChartProps,
113
+ renderer: ResponsiveDonutChart
114
+ },
115
+ heatmap: {
116
+ transformer: transformVegaLiteToHeatMapChartProps,
117
+ renderer: ResponsiveHeatMapChart
118
+ },
119
+ histogram: {
120
+ transformer: transformVegaLiteToHistogramProps,
121
+ renderer: ResponsiveVerticalBarChart
122
+ },
123
+ polar: {
124
+ transformer: transformVegaLiteToPolarChartProps,
125
+ renderer: ResponsivePolarChart
126
+ }
127
+ };
128
+ /**
129
+ * Renders a single Vega-Lite chart spec
130
+ */ function renderSingleChart(spec, colorMap, isDarkTheme, interactiveCommonProps) {
131
+ const chartType = getChartType(spec);
132
+ const chartConfig = vegaChartMap[chartType.type];
133
+ if (!chartConfig) {
134
+ throw new Error(`VegaDeclarativeChart: Unsupported chart type '${chartType.type}'`);
135
+ }
136
+ const { transformer, renderer: ChartRenderer } = chartConfig;
137
+ const chartProps = transformer(spec, colorMap, isDarkTheme);
138
+ // For hconcat/vconcat sub-charts, hide per-chart legends (shared legend rendered separately)
139
+ if (spec._hideLegend) {
140
+ chartProps.hideLegend = true;
141
+ }
142
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
143
+ return /*#__PURE__*/ React.createElement(ChartRenderer, {
144
+ ...chartProps,
145
+ ...interactiveCommonProps
146
+ });
147
+ }
148
+ /**
149
+ * VegaDeclarativeChart - Render Vega-Lite specifications with Fluent UI styling
150
+ *
151
+ * Supported chart types:
152
+ * - Line charts: mark: 'line' or 'point'
153
+ * - Area charts: mark: 'area'
154
+ * - Scatter charts: mark: 'point', 'circle', or 'square'
155
+ * - Vertical bar charts: mark: 'bar' with nominal/ordinal x-axis
156
+ * - Stacked bar charts: mark: 'bar' with color encoding
157
+ * - Grouped bar charts: mark: 'bar' with color encoding (via configuration)
158
+ * - Horizontal bar charts: mark: 'bar' with nominal/ordinal y-axis
159
+ * - Donut/Pie charts: mark: 'arc' with theta encoding
160
+ * - Heatmaps: mark: 'rect' with x, y, and color (quantitative) encodings
161
+ * - Combo charts: Layered specs with bar + line marks render as VerticalStackedBarChart with line overlays
162
+ *
163
+ * Multi-plot Support:
164
+ * - Horizontal concatenation (hconcat): Multiple charts side-by-side
165
+ * - Vertical concatenation (vconcat): Multiple charts stacked vertically
166
+ * - Shared data and encoding are merged from parent spec to each subplot
167
+ *
168
+ * Limitations:
169
+ * - Most layered specifications (multiple chart types) are not fully supported
170
+ * - Bar + Line combinations ARE supported and will render properly
171
+ * - For other composite charts, only the first layer will be rendered
172
+ * - Faceting and repeat operators are not yet supported
173
+ * - Funnel charts are not a native Vega-Lite mark type. The conversion_funnel.json example
174
+ * uses a horizontal bar chart (y: nominal, x: quantitative) which is the standard way to
175
+ * represent funnel data in Vega-Lite. For specialized funnel visualizations with tapering
176
+ * shapes, consider using Plotly's native funnel chart type instead.
177
+ *
178
+ * Note: Sankey, Gantt, and Gauge charts are not standard Vega-Lite marks.
179
+ * These specialized visualizations would require custom extensions or alternative approaches.
180
+ *
181
+ * @example Line Chart
182
+ * ```tsx
183
+ * import { VegaDeclarativeChart } from '@fluentui/react-charts';
184
+ *
185
+ * const spec = {
186
+ * mark: 'line',
187
+ * data: { values: [{ x: 1, y: 10 }, { x: 2, y: 20 }] },
188
+ * encoding: {
189
+ * x: { field: 'x', type: 'quantitative' },
190
+ * y: { field: 'y', type: 'quantitative' }
191
+ * }
192
+ * };
193
+ *
194
+ * <VegaDeclarativeChart chartSchema={{ vegaLiteSpec: spec }} />
195
+ * ```
196
+ *
197
+ * @example Area Chart
198
+ * ```tsx
199
+ * const areaSpec = {
200
+ * mark: 'area',
201
+ * data: { values: [{ date: '2023-01', value: 100 }, { date: '2023-02', value: 150 }] },
202
+ * encoding: {
203
+ * x: { field: 'date', type: 'temporal' },
204
+ * y: { field: 'value', type: 'quantitative' }
205
+ * }
206
+ * };
207
+ *
208
+ * <VegaDeclarativeChart chartSchema={{ vegaLiteSpec: areaSpec }} />
209
+ * ```
210
+ *
211
+ * @example Scatter Chart
212
+ * ```tsx
213
+ * const scatterSpec = {
214
+ * mark: 'point',
215
+ * data: { values: [{ x: 10, y: 20, size: 100 }, { x: 15, y: 30, size: 200 }] },
216
+ * encoding: {
217
+ * x: { field: 'x', type: 'quantitative' },
218
+ * y: { field: 'y', type: 'quantitative' },
219
+ * size: { field: 'size', type: 'quantitative' }
220
+ * }
221
+ * };
222
+ *
223
+ * <VegaDeclarativeChart chartSchema={{ vegaLiteSpec: scatterSpec }} />
224
+ * ```
225
+ *
226
+ * @example Vertical Bar Chart
227
+ * ```tsx
228
+ * const barSpec = {
229
+ * mark: 'bar',
230
+ * data: { values: [{ cat: 'A', val: 28 }, { cat: 'B', val: 55 }] },
231
+ * encoding: {
232
+ * x: { field: 'cat', type: 'nominal' },
233
+ * y: { field: 'val', type: 'quantitative' }
234
+ * }
235
+ * };
236
+ *
237
+ * <VegaDeclarativeChart chartSchema={{ vegaLiteSpec: barSpec }} />
238
+ * ```
239
+ *
240
+ * @example Stacked Bar Chart
241
+ * ```tsx
242
+ * const stackedSpec = {
243
+ * mark: 'bar',
244
+ * data: { values: [
245
+ * { cat: 'A', group: 'G1', val: 28 },
246
+ * { cat: 'A', group: 'G2', val: 15 }
247
+ * ]},
248
+ * encoding: {
249
+ * x: { field: 'cat', type: 'nominal' },
250
+ * y: { field: 'val', type: 'quantitative' },
251
+ * color: { field: 'group', type: 'nominal' }
252
+ * }
253
+ * };
254
+ *
255
+ * <VegaDeclarativeChart chartSchema={{ vegaLiteSpec: stackedSpec }} />
256
+ * ```
257
+ *
258
+ * @example Donut Chart
259
+ * ```tsx
260
+ * const donutSpec = {
261
+ * mark: 'arc',
262
+ * data: { values: [{ category: 'A', value: 30 }, { category: 'B', value: 70 }] },
263
+ * encoding: {
264
+ * theta: { field: 'value', type: 'quantitative' },
265
+ * color: { field: 'category', type: 'nominal' }
266
+ * }
267
+ * };
268
+ *
269
+ * <VegaDeclarativeChart chartSchema={{ vegaLiteSpec: donutSpec }} />
270
+ * ```
271
+ *
272
+ * @example Heatmap
273
+ * ```tsx
274
+ * const heatmapSpec = {
275
+ * mark: 'rect',
276
+ * data: { values: [
277
+ * { x: 'A', y: 'Mon', value: 28 },
278
+ * { x: 'B', y: 'Mon', value: 55 },
279
+ * { x: 'A', y: 'Tue', value: 43 }
280
+ * ]},
281
+ * encoding: {
282
+ * x: { field: 'x', type: 'nominal' },
283
+ * y: { field: 'y', type: 'nominal' },
284
+ * color: { field: 'value', type: 'quantitative' }
285
+ * }
286
+ * };
287
+ *
288
+ * <VegaDeclarativeChart chartSchema={{ vegaLiteSpec: heatmapSpec }} />
289
+ * ```
290
+ */ export const VegaDeclarativeChart = /*#__PURE__*/ React.forwardRef((props, forwardedRef)=>{
291
+ const { vegaLiteSpec, selectedLegends = [] } = props.chartSchema;
292
+ if (!vegaLiteSpec) {
293
+ throw new Error('VegaDeclarativeChart: vegaLiteSpec is required in chartSchema');
294
+ }
295
+ // Guard against excessively deep JSON specs that could cause stack overflow / memory exhaustion
296
+ validateJsonDepth(vegaLiteSpec);
297
+ const colorMap = useColorMapping();
298
+ const isDarkTheme = useIsDarkTheme();
299
+ const chartRef = React.useRef(null);
300
+ const [activeLegends, setActiveLegends] = React.useState(selectedLegends);
301
+ const onActiveLegendsChange = (keys)=>{
302
+ setActiveLegends(keys);
303
+ if (props.onSchemaChange) {
304
+ props.onSchemaChange({
305
+ vegaLiteSpec,
306
+ selectedLegends: keys
307
+ });
308
+ }
309
+ };
310
+ React.useEffect(()=>{
311
+ var _props_chartSchema_selectedLegends;
312
+ setActiveLegends((_props_chartSchema_selectedLegends = props.chartSchema.selectedLegends) !== null && _props_chartSchema_selectedLegends !== void 0 ? _props_chartSchema_selectedLegends : []);
313
+ }, [
314
+ props.chartSchema.selectedLegends
315
+ ]);
316
+ const multiSelectLegendProps = {
317
+ canSelectMultipleLegends: true,
318
+ onChange: onActiveLegendsChange,
319
+ selectedLegends: activeLegends
320
+ };
321
+ const interactiveCommonProps = {
322
+ componentRef: chartRef,
323
+ legendProps: multiSelectLegendProps
324
+ };
325
+ try {
326
+ // Check if this is a concat spec (multiple charts side-by-side or stacked)
327
+ if (isHConcatSpec(vegaLiteSpec) || isVConcatSpec(vegaLiteSpec)) {
328
+ const gridProps = getVegaConcatGridProperties(vegaLiteSpec);
329
+ // Build shared legend from the first sub-chart's color encoding
330
+ const firstSubSpec = {
331
+ ...gridProps.specs[0],
332
+ data: gridProps.specs[0].data || vegaLiteSpec.data,
333
+ encoding: {
334
+ ...vegaLiteSpec.encoding || {},
335
+ ...gridProps.specs[0].encoding || {}
336
+ }
337
+ };
338
+ const sharedLegendProps = getVegaLiteLegendsProps(firstSubSpec, colorMap, isDarkTheme);
339
+ return /*#__PURE__*/ React.createElement("div", {
340
+ ref: forwardedRef,
341
+ className: props.className,
342
+ style: props.style
343
+ }, /*#__PURE__*/ React.createElement("div", {
344
+ style: {
345
+ display: 'grid',
346
+ gridTemplateRows: gridProps.templateRows,
347
+ gridTemplateColumns: gridProps.templateColumns,
348
+ gap: '16px'
349
+ }
350
+ }, gridProps.specs.map((subSpec, index)=>{
351
+ // Compute default height for sub-charts
352
+ const defaultSubHeight = typeof vegaLiteSpec.height === 'number' ? vegaLiteSpec.height : typeof subSpec.height === 'number' ? subSpec.height : 300;
353
+ const mergedSpec = {
354
+ ...subSpec,
355
+ data: subSpec.data || vegaLiteSpec.data,
356
+ encoding: {
357
+ ...vegaLiteSpec.encoding || {},
358
+ ...subSpec.encoding || {}
359
+ },
360
+ height: typeof subSpec.height === 'number' ? subSpec.height : defaultSubHeight,
361
+ // Hide legends on ALL sub-charts — shared legend is rendered below
362
+ _hideLegend: true
363
+ };
364
+ const cellRow = gridProps.isHorizontal ? 1 : index + 1;
365
+ const cellColumn = gridProps.isHorizontal ? index + 1 : 1;
366
+ return /*#__PURE__*/ React.createElement("div", {
367
+ key: `chart_${index}`,
368
+ style: {
369
+ gridRowStart: cellRow,
370
+ gridRowEnd: cellRow + 1,
371
+ gridColumnStart: cellColumn,
372
+ gridColumnEnd: cellColumn + 1,
373
+ minWidth: 0
374
+ }
375
+ }, renderSingleChart(mergedSpec, colorMap, isDarkTheme, interactiveCommonProps));
376
+ })), sharedLegendProps.legends.length > 0 && /*#__PURE__*/ React.createElement(Legends, {
377
+ ...sharedLegendProps,
378
+ ...multiSelectLegendProps
379
+ }));
380
+ }
381
+ // Check if this is a layered spec (composite chart)
382
+ if (vegaLiteSpec.layer && vegaLiteSpec.layer.length > 1) {
383
+ // Check if it's a supported bar+line combo
384
+ const marks = vegaLiteSpec.layer.map((layer)=>getMarkType(layer.mark));
385
+ const hasBar = marks.includes('bar');
386
+ const hasLine = marks.includes('line') || marks.includes('point');
387
+ const isBarLineCombo = hasBar && hasLine;
388
+ // Only warn for unsupported layered specs
389
+ if (!isBarLineCombo) {
390
+ // Layered specifications with multiple chart types are not fully supported.
391
+ // Only the first layer will be rendered.
392
+ }
393
+ }
394
+ // Render single chart
395
+ const chartComponent = renderSingleChart(vegaLiteSpec, colorMap, isDarkTheme, interactiveCommonProps);
396
+ return /*#__PURE__*/ React.createElement("div", {
397
+ ref: forwardedRef,
398
+ className: props.className,
399
+ style: props.style
400
+ }, chartComponent);
401
+ } catch (error) {
402
+ throw new Error(`Failed to transform Vega-Lite spec: ${error}`);
403
+ }
404
+ });
405
+ VegaDeclarativeChart.displayName = 'VegaDeclarativeChart';
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/VegaDeclarativeChart/VegaDeclarativeChart.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n transformVegaLiteToLineChartProps,\n transformVegaLiteToVerticalBarChartProps,\n transformVegaLiteToVerticalStackedBarChartProps,\n transformVegaLiteToGroupedVerticalBarChartProps,\n transformVegaLiteToHorizontalBarChartProps,\n transformVegaLiteToAreaChartProps,\n transformVegaLiteToScatterChartProps,\n transformVegaLiteToDonutChartProps,\n transformVegaLiteToHeatMapChartProps,\n transformVegaLiteToHistogramProps,\n transformVegaLiteToPolarChartProps,\n getChartType,\n getMarkType,\n getVegaLiteLegendsProps,\n} from './VegaLiteSchemaAdapter';\nimport type { VegaLiteUnitSpec, VegaLiteSpec } from './VegaLiteTypes';\nimport { Legends } from '../Legends/index';\nimport { withResponsiveContainer } from '../ResponsiveContainer/withResponsiveContainer';\nimport { LineChart } from '../LineChart/index';\nimport { VerticalBarChart } from '../VerticalBarChart/index';\nimport { VerticalStackedBarChart } from '../VerticalStackedBarChart/index';\nimport { GroupedVerticalBarChart } from '../GroupedVerticalBarChart/index';\nimport { HorizontalBarChartWithAxis } from '../HorizontalBarChartWithAxis/index';\nimport { AreaChart } from '../AreaChart/index';\nimport { ScatterChart } from '../ScatterChart/index';\nimport { DonutChart } from '../DonutChart/index';\nimport { HeatMapChart } from '../HeatMapChart/index';\nimport { PolarChart } from '../PolarChart/index';\nimport { useIsDarkTheme, useColorMapping } from './VegaDeclarativeChartHooks';\nimport type { Chart } from '../../types/index';\n\n// Re-export the typed VegaLiteSpec for public API\nexport type { VegaLiteSpec } from './VegaLiteTypes';\n\n/**\n * Maximum allowed nesting depth for incoming JSON specs.\n * Matches the Plotly adapter's MAX_DEPTH to prevent stack overflow / memory exhaustion.\n */\nconst MAX_DEPTH = 15;\n\n/**\n * Validates that a JSON value does not exceed the maximum nesting depth.\n * Throws if the depth limit is exceeded (same behavior as Plotly's sanitizeJson).\n */\nfunction validateJsonDepth(value: unknown, depth: number = 0): void {\n if (depth > MAX_DEPTH) {\n throw new Error('VegaDeclarativeChart: Maximum JSON depth exceeded');\n }\n if (value !== null && typeof value === 'object') {\n for (const key of Object.keys(value as Record<string, unknown>)) {\n validateJsonDepth((value as Record<string, unknown>)[key], depth + 1);\n }\n }\n}\n\n/**\n * Schema for VegaDeclarativeChart component\n */\nexport interface VegaSchema {\n /**\n * Vega-Lite specification\n *\n * @see https://vega.github.io/vega-lite/docs/spec.html\n */\n vegaLiteSpec: VegaLiteSpec;\n\n /**\n * Selected legends for filtering\n */\n selectedLegends?: string[];\n}\n\n/**\n * Props for VegaDeclarativeChart component\n */\nexport interface VegaDeclarativeChartProps {\n /**\n * Vega-Lite chart schema\n */\n chartSchema: VegaSchema;\n\n /**\n * Callback when schema changes (e.g., legend selection)\n */\n onSchemaChange?: (newSchema: VegaSchema) => void;\n\n /**\n * Additional CSS class name\n */\n className?: string;\n\n /**\n * Additional inline styles\n */\n style?: React.CSSProperties;\n}\n\n/**\n * Check if spec is a horizontal concatenation\n */\nfunction isHConcatSpec(spec: VegaLiteSpec): boolean {\n return !!spec.hconcat && Array.isArray(spec.hconcat) && spec.hconcat.length > 0;\n}\n\n/**\n * Check if spec is a vertical concatenation\n */\nfunction isVConcatSpec(spec: VegaLiteSpec): boolean {\n return !!spec.vconcat && Array.isArray(spec.vconcat) && spec.vconcat.length > 0;\n}\n\n/**\n * Get grid properties for concat specs\n */\nfunction getVegaConcatGridProperties(spec: VegaLiteSpec): {\n templateRows: string;\n templateColumns: string;\n isHorizontal: boolean;\n specs: VegaLiteSpec[];\n} {\n if (isHConcatSpec(spec)) {\n return {\n templateRows: 'auto',\n templateColumns: `repeat(${spec.hconcat!.length}, 1fr)`,\n isHorizontal: true,\n specs: spec.hconcat!,\n };\n }\n\n if (isVConcatSpec(spec)) {\n return {\n templateRows: `repeat(${spec.vconcat!.length}, auto)`,\n templateColumns: '1fr',\n isHorizontal: false,\n specs: spec.vconcat!,\n };\n }\n\n return {\n templateRows: '1fr',\n templateColumns: '1fr',\n isHorizontal: false,\n specs: [spec],\n };\n}\n\nconst ResponsiveLineChart = withResponsiveContainer(LineChart);\nconst ResponsiveVerticalBarChart = withResponsiveContainer(VerticalBarChart);\nconst ResponsiveVerticalStackedBarChart = withResponsiveContainer(VerticalStackedBarChart);\nconst ResponsiveGroupedVerticalBarChart = withResponsiveContainer(GroupedVerticalBarChart);\nconst ResponsiveHorizontalBarChartWithAxis = withResponsiveContainer(HorizontalBarChartWithAxis);\nconst ResponsiveAreaChart = withResponsiveContainer(AreaChart);\nconst ResponsiveScatterChart = withResponsiveContainer(ScatterChart);\nconst ResponsiveDonutChart = withResponsiveContainer(DonutChart);\nconst ResponsiveHeatMapChart = withResponsiveContainer(HeatMapChart);\nconst ResponsivePolarChart = withResponsiveContainer(PolarChart);\n\n/**\n * Chart type mapping with transformers and renderers\n * Follows the factory functor pattern from PlotlyDeclarativeChart\n */\ntype VegaChartTypeMap = {\n line: { transformer: typeof transformVegaLiteToLineChartProps; renderer: typeof ResponsiveLineChart };\n bar: { transformer: typeof transformVegaLiteToVerticalBarChartProps; renderer: typeof ResponsiveVerticalBarChart };\n 'stacked-bar': {\n transformer: typeof transformVegaLiteToVerticalStackedBarChartProps;\n renderer: typeof ResponsiveVerticalStackedBarChart;\n };\n 'grouped-bar': {\n transformer: typeof transformVegaLiteToGroupedVerticalBarChartProps;\n renderer: typeof ResponsiveGroupedVerticalBarChart;\n };\n 'horizontal-bar': {\n transformer: typeof transformVegaLiteToHorizontalBarChartProps;\n renderer: typeof ResponsiveHorizontalBarChartWithAxis;\n };\n area: { transformer: typeof transformVegaLiteToAreaChartProps; renderer: typeof ResponsiveAreaChart };\n scatter: { transformer: typeof transformVegaLiteToScatterChartProps; renderer: typeof ResponsiveScatterChart };\n donut: { transformer: typeof transformVegaLiteToDonutChartProps; renderer: typeof ResponsiveDonutChart };\n heatmap: { transformer: typeof transformVegaLiteToHeatMapChartProps; renderer: typeof ResponsiveHeatMapChart };\n histogram: { transformer: typeof transformVegaLiteToHistogramProps; renderer: typeof ResponsiveVerticalBarChart };\n polar: { transformer: typeof transformVegaLiteToPolarChartProps; renderer: typeof ResponsivePolarChart };\n};\n\nconst vegaChartMap: VegaChartTypeMap = {\n line: { transformer: transformVegaLiteToLineChartProps, renderer: ResponsiveLineChart },\n bar: { transformer: transformVegaLiteToVerticalBarChartProps, renderer: ResponsiveVerticalBarChart },\n 'stacked-bar': {\n transformer: transformVegaLiteToVerticalStackedBarChartProps,\n renderer: ResponsiveVerticalStackedBarChart,\n },\n 'grouped-bar': {\n transformer: transformVegaLiteToGroupedVerticalBarChartProps,\n renderer: ResponsiveGroupedVerticalBarChart,\n },\n 'horizontal-bar': {\n transformer: transformVegaLiteToHorizontalBarChartProps,\n renderer: ResponsiveHorizontalBarChartWithAxis,\n },\n area: { transformer: transformVegaLiteToAreaChartProps, renderer: ResponsiveAreaChart },\n scatter: { transformer: transformVegaLiteToScatterChartProps, renderer: ResponsiveScatterChart },\n donut: { transformer: transformVegaLiteToDonutChartProps, renderer: ResponsiveDonutChart },\n heatmap: { transformer: transformVegaLiteToHeatMapChartProps, renderer: ResponsiveHeatMapChart },\n histogram: { transformer: transformVegaLiteToHistogramProps, renderer: ResponsiveVerticalBarChart },\n polar: { transformer: transformVegaLiteToPolarChartProps, renderer: ResponsivePolarChart },\n};\n\ninterface MultiSelectLegendProps {\n canSelectMultipleLegends: boolean;\n onChange: (keys: string[]) => void;\n selectedLegends: string[];\n}\n\n/**\n * Renders a single Vega-Lite chart spec\n */\nfunction renderSingleChart(\n spec: VegaLiteSpec,\n colorMap: React.RefObject<Map<string, string>>,\n isDarkTheme: boolean,\n interactiveCommonProps: { componentRef: React.RefObject<Chart | null>; legendProps: MultiSelectLegendProps },\n): React.ReactElement {\n const chartType = getChartType(spec);\n const chartConfig = vegaChartMap[chartType.type];\n\n if (!chartConfig) {\n throw new Error(`VegaDeclarativeChart: Unsupported chart type '${chartType.type}'`);\n }\n\n const { transformer, renderer: ChartRenderer } = chartConfig;\n const chartProps = transformer(spec, colorMap, isDarkTheme) as Record<string, unknown>;\n\n // For hconcat/vconcat sub-charts, hide per-chart legends (shared legend rendered separately)\n if ((spec as Record<string, unknown>)._hideLegend) {\n chartProps.hideLegend = true;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return <ChartRenderer {...(chartProps as any)} {...interactiveCommonProps} />;\n}\n\n/**\n * VegaDeclarativeChart - Render Vega-Lite specifications with Fluent UI styling\n *\n * Supported chart types:\n * - Line charts: mark: 'line' or 'point'\n * - Area charts: mark: 'area'\n * - Scatter charts: mark: 'point', 'circle', or 'square'\n * - Vertical bar charts: mark: 'bar' with nominal/ordinal x-axis\n * - Stacked bar charts: mark: 'bar' with color encoding\n * - Grouped bar charts: mark: 'bar' with color encoding (via configuration)\n * - Horizontal bar charts: mark: 'bar' with nominal/ordinal y-axis\n * - Donut/Pie charts: mark: 'arc' with theta encoding\n * - Heatmaps: mark: 'rect' with x, y, and color (quantitative) encodings\n * - Combo charts: Layered specs with bar + line marks render as VerticalStackedBarChart with line overlays\n *\n * Multi-plot Support:\n * - Horizontal concatenation (hconcat): Multiple charts side-by-side\n * - Vertical concatenation (vconcat): Multiple charts stacked vertically\n * - Shared data and encoding are merged from parent spec to each subplot\n *\n * Limitations:\n * - Most layered specifications (multiple chart types) are not fully supported\n * - Bar + Line combinations ARE supported and will render properly\n * - For other composite charts, only the first layer will be rendered\n * - Faceting and repeat operators are not yet supported\n * - Funnel charts are not a native Vega-Lite mark type. The conversion_funnel.json example\n * uses a horizontal bar chart (y: nominal, x: quantitative) which is the standard way to\n * represent funnel data in Vega-Lite. For specialized funnel visualizations with tapering\n * shapes, consider using Plotly's native funnel chart type instead.\n *\n * Note: Sankey, Gantt, and Gauge charts are not standard Vega-Lite marks.\n * These specialized visualizations would require custom extensions or alternative approaches.\n *\n * @example Line Chart\n * ```tsx\n * import { VegaDeclarativeChart } from '@fluentui/react-charts';\n *\n * const spec = {\n * mark: 'line',\n * data: { values: [{ x: 1, y: 10 }, { x: 2, y: 20 }] },\n * encoding: {\n * x: { field: 'x', type: 'quantitative' },\n * y: { field: 'y', type: 'quantitative' }\n * }\n * };\n *\n * <VegaDeclarativeChart chartSchema={{ vegaLiteSpec: spec }} />\n * ```\n *\n * @example Area Chart\n * ```tsx\n * const areaSpec = {\n * mark: 'area',\n * data: { values: [{ date: '2023-01', value: 100 }, { date: '2023-02', value: 150 }] },\n * encoding: {\n * x: { field: 'date', type: 'temporal' },\n * y: { field: 'value', type: 'quantitative' }\n * }\n * };\n *\n * <VegaDeclarativeChart chartSchema={{ vegaLiteSpec: areaSpec }} />\n * ```\n *\n * @example Scatter Chart\n * ```tsx\n * const scatterSpec = {\n * mark: 'point',\n * data: { values: [{ x: 10, y: 20, size: 100 }, { x: 15, y: 30, size: 200 }] },\n * encoding: {\n * x: { field: 'x', type: 'quantitative' },\n * y: { field: 'y', type: 'quantitative' },\n * size: { field: 'size', type: 'quantitative' }\n * }\n * };\n *\n * <VegaDeclarativeChart chartSchema={{ vegaLiteSpec: scatterSpec }} />\n * ```\n *\n * @example Vertical Bar Chart\n * ```tsx\n * const barSpec = {\n * mark: 'bar',\n * data: { values: [{ cat: 'A', val: 28 }, { cat: 'B', val: 55 }] },\n * encoding: {\n * x: { field: 'cat', type: 'nominal' },\n * y: { field: 'val', type: 'quantitative' }\n * }\n * };\n *\n * <VegaDeclarativeChart chartSchema={{ vegaLiteSpec: barSpec }} />\n * ```\n *\n * @example Stacked Bar Chart\n * ```tsx\n * const stackedSpec = {\n * mark: 'bar',\n * data: { values: [\n * { cat: 'A', group: 'G1', val: 28 },\n * { cat: 'A', group: 'G2', val: 15 }\n * ]},\n * encoding: {\n * x: { field: 'cat', type: 'nominal' },\n * y: { field: 'val', type: 'quantitative' },\n * color: { field: 'group', type: 'nominal' }\n * }\n * };\n *\n * <VegaDeclarativeChart chartSchema={{ vegaLiteSpec: stackedSpec }} />\n * ```\n *\n * @example Donut Chart\n * ```tsx\n * const donutSpec = {\n * mark: 'arc',\n * data: { values: [{ category: 'A', value: 30 }, { category: 'B', value: 70 }] },\n * encoding: {\n * theta: { field: 'value', type: 'quantitative' },\n * color: { field: 'category', type: 'nominal' }\n * }\n * };\n *\n * <VegaDeclarativeChart chartSchema={{ vegaLiteSpec: donutSpec }} />\n * ```\n *\n * @example Heatmap\n * ```tsx\n * const heatmapSpec = {\n * mark: 'rect',\n * data: { values: [\n * { x: 'A', y: 'Mon', value: 28 },\n * { x: 'B', y: 'Mon', value: 55 },\n * { x: 'A', y: 'Tue', value: 43 }\n * ]},\n * encoding: {\n * x: { field: 'x', type: 'nominal' },\n * y: { field: 'y', type: 'nominal' },\n * color: { field: 'value', type: 'quantitative' }\n * }\n * };\n *\n * <VegaDeclarativeChart chartSchema={{ vegaLiteSpec: heatmapSpec }} />\n * ```\n */\nexport const VegaDeclarativeChart = React.forwardRef<HTMLDivElement, VegaDeclarativeChartProps>(\n (props, forwardedRef) => {\n const { vegaLiteSpec, selectedLegends = [] } = props.chartSchema;\n\n if (!vegaLiteSpec) {\n throw new Error('VegaDeclarativeChart: vegaLiteSpec is required in chartSchema');\n }\n\n // Guard against excessively deep JSON specs that could cause stack overflow / memory exhaustion\n validateJsonDepth(vegaLiteSpec);\n\n const colorMap = useColorMapping();\n const isDarkTheme = useIsDarkTheme();\n const chartRef = React.useRef<Chart>(null);\n\n const [activeLegends, setActiveLegends] = React.useState<string[]>(selectedLegends);\n\n const onActiveLegendsChange = (keys: string[]) => {\n setActiveLegends(keys);\n if (props.onSchemaChange) {\n props.onSchemaChange({ vegaLiteSpec, selectedLegends: keys });\n }\n };\n\n React.useEffect(() => {\n setActiveLegends(props.chartSchema.selectedLegends ?? []);\n }, [props.chartSchema.selectedLegends]);\n\n const multiSelectLegendProps = {\n canSelectMultipleLegends: true,\n onChange: onActiveLegendsChange,\n selectedLegends: activeLegends,\n };\n\n const interactiveCommonProps = {\n componentRef: chartRef,\n legendProps: multiSelectLegendProps,\n };\n\n try {\n // Check if this is a concat spec (multiple charts side-by-side or stacked)\n if (isHConcatSpec(vegaLiteSpec) || isVConcatSpec(vegaLiteSpec)) {\n const gridProps = getVegaConcatGridProperties(vegaLiteSpec);\n\n // Build shared legend from the first sub-chart's color encoding\n const firstSubSpec = {\n ...gridProps.specs[0],\n data: gridProps.specs[0].data || vegaLiteSpec.data,\n encoding: {\n ...(vegaLiteSpec.encoding || {}),\n ...(gridProps.specs[0].encoding || {}),\n },\n };\n const sharedLegendProps = getVegaLiteLegendsProps(firstSubSpec, colorMap, isDarkTheme);\n\n return (\n <div ref={forwardedRef} className={props.className} style={props.style}>\n <div\n style={{\n display: 'grid',\n gridTemplateRows: gridProps.templateRows,\n gridTemplateColumns: gridProps.templateColumns,\n gap: '16px',\n }}\n >\n {gridProps.specs.map((subSpec: VegaLiteSpec, index: number) => {\n // Compute default height for sub-charts\n const defaultSubHeight =\n typeof vegaLiteSpec.height === 'number'\n ? vegaLiteSpec.height\n : typeof subSpec.height === 'number'\n ? subSpec.height\n : 300;\n\n const mergedSpec = {\n ...subSpec,\n data: subSpec.data || vegaLiteSpec.data,\n encoding: {\n ...(vegaLiteSpec.encoding || {}),\n ...(subSpec.encoding || {}),\n },\n height: typeof subSpec.height === 'number' ? subSpec.height : defaultSubHeight,\n // Hide legends on ALL sub-charts — shared legend is rendered below\n _hideLegend: true,\n };\n\n const cellRow = gridProps.isHorizontal ? 1 : index + 1;\n const cellColumn = gridProps.isHorizontal ? index + 1 : 1;\n\n return (\n <div\n key={`chart_${index}`}\n style={{\n gridRowStart: cellRow,\n gridRowEnd: cellRow + 1,\n gridColumnStart: cellColumn,\n gridColumnEnd: cellColumn + 1,\n minWidth: 0,\n }}\n >\n {renderSingleChart(mergedSpec, colorMap, isDarkTheme, interactiveCommonProps)}\n </div>\n );\n })}\n </div>\n {sharedLegendProps.legends.length > 0 && <Legends {...sharedLegendProps} {...multiSelectLegendProps} />}\n </div>\n );\n }\n\n // Check if this is a layered spec (composite chart)\n if (vegaLiteSpec.layer && vegaLiteSpec.layer.length > 1) {\n // Check if it's a supported bar+line combo\n const marks = vegaLiteSpec.layer.map((layer: VegaLiteUnitSpec) => getMarkType(layer.mark));\n const hasBar = marks.includes('bar');\n const hasLine = marks.includes('line') || marks.includes('point');\n const isBarLineCombo = hasBar && hasLine;\n\n // Only warn for unsupported layered specs\n if (!isBarLineCombo) {\n // Layered specifications with multiple chart types are not fully supported.\n // Only the first layer will be rendered.\n }\n }\n\n // Render single chart\n const chartComponent = renderSingleChart(vegaLiteSpec, colorMap, isDarkTheme, interactiveCommonProps);\n\n return (\n <div ref={forwardedRef} className={props.className} style={props.style}>\n {chartComponent}\n </div>\n );\n } catch (error) {\n throw new Error(`Failed to transform Vega-Lite spec: ${error}`);\n }\n },\n);\n\nVegaDeclarativeChart.displayName = 'VegaDeclarativeChart';\n"],"names":["React","transformVegaLiteToLineChartProps","transformVegaLiteToVerticalBarChartProps","transformVegaLiteToVerticalStackedBarChartProps","transformVegaLiteToGroupedVerticalBarChartProps","transformVegaLiteToHorizontalBarChartProps","transformVegaLiteToAreaChartProps","transformVegaLiteToScatterChartProps","transformVegaLiteToDonutChartProps","transformVegaLiteToHeatMapChartProps","transformVegaLiteToHistogramProps","transformVegaLiteToPolarChartProps","getChartType","getMarkType","getVegaLiteLegendsProps","Legends","withResponsiveContainer","LineChart","VerticalBarChart","VerticalStackedBarChart","GroupedVerticalBarChart","HorizontalBarChartWithAxis","AreaChart","ScatterChart","DonutChart","HeatMapChart","PolarChart","useIsDarkTheme","useColorMapping","MAX_DEPTH","validateJsonDepth","value","depth","Error","key","Object","keys","isHConcatSpec","spec","hconcat","Array","isArray","length","isVConcatSpec","vconcat","getVegaConcatGridProperties","templateRows","templateColumns","isHorizontal","specs","ResponsiveLineChart","ResponsiveVerticalBarChart","ResponsiveVerticalStackedBarChart","ResponsiveGroupedVerticalBarChart","ResponsiveHorizontalBarChartWithAxis","ResponsiveAreaChart","ResponsiveScatterChart","ResponsiveDonutChart","ResponsiveHeatMapChart","ResponsivePolarChart","vegaChartMap","line","transformer","renderer","bar","area","scatter","donut","heatmap","histogram","polar","renderSingleChart","colorMap","isDarkTheme","interactiveCommonProps","chartType","chartConfig","type","ChartRenderer","chartProps","_hideLegend","hideLegend","VegaDeclarativeChart","forwardRef","props","forwardedRef","vegaLiteSpec","selectedLegends","chartSchema","chartRef","useRef","activeLegends","setActiveLegends","useState","onActiveLegendsChange","onSchemaChange","useEffect","multiSelectLegendProps","canSelectMultipleLegends","onChange","componentRef","legendProps","gridProps","firstSubSpec","data","encoding","sharedLegendProps","div","ref","className","style","display","gridTemplateRows","gridTemplateColumns","gap","map","subSpec","index","defaultSubHeight","height","mergedSpec","cellRow","cellColumn","gridRowStart","gridRowEnd","gridColumnStart","gridColumnEnd","minWidth","legends","layer","marks","mark","hasBar","includes","hasLine","isBarLineCombo","chartComponent","error","displayName"],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ 'use client';
2
+ import * as React from 'react';
3
+ import { ThemeContext_unstable as V9ThemeContext } from '@fluentui/react-shared-contexts';
4
+ import { webLightTheme } from '@fluentui/tokens';
5
+ import { hsl as d3Hsl } from 'd3-color';
6
+ /**
7
+ * Hook to determine if dark theme is active based on background/foreground luminance
8
+ */ export function useIsDarkTheme() {
9
+ const parentV9Theme = React.useContext(V9ThemeContext);
10
+ const v9Theme = parentV9Theme ? parentV9Theme : webLightTheme;
11
+ const backgroundColor = d3Hsl(v9Theme.colorNeutralBackground1);
12
+ const foregroundColor = d3Hsl(v9Theme.colorNeutralForeground1);
13
+ const isDarkTheme = backgroundColor.l < foregroundColor.l;
14
+ return isDarkTheme;
15
+ }
16
+ /**
17
+ * Hook for color mapping across charts - maintains persistent color assignments
18
+ */ export function useColorMapping() {
19
+ return React.useRef(new Map());
20
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/VegaDeclarativeChart/VegaDeclarativeChartHooks.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { ThemeContext_unstable as V9ThemeContext } from '@fluentui/react-shared-contexts';\nimport { Theme, webLightTheme } from '@fluentui/tokens';\nimport { hsl as d3Hsl } from 'd3-color';\n\n/**\n * Hook to determine if dark theme is active based on background/foreground luminance\n */\nexport function useIsDarkTheme(): boolean {\n const parentV9Theme = React.useContext(V9ThemeContext) as Theme;\n const v9Theme: Theme = parentV9Theme ? parentV9Theme : webLightTheme;\n\n const backgroundColor = d3Hsl(v9Theme.colorNeutralBackground1);\n const foregroundColor = d3Hsl(v9Theme.colorNeutralForeground1);\n\n const isDarkTheme = backgroundColor.l < foregroundColor.l;\n\n return isDarkTheme;\n}\n\n/**\n * Hook for color mapping across charts - maintains persistent color assignments\n */\nexport function useColorMapping(): React.RefObject<Map<string, string>> {\n return React.useRef<Map<string, string>>(new Map());\n}\n"],"names":["React","ThemeContext_unstable","V9ThemeContext","webLightTheme","hsl","d3Hsl","useIsDarkTheme","parentV9Theme","useContext","v9Theme","backgroundColor","colorNeutralBackground1","foregroundColor","colorNeutralForeground1","isDarkTheme","l","useColorMapping","useRef","Map"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,yBAAyBC,cAAc,QAAQ,kCAAkC;AAC1F,SAAgBC,aAAa,QAAQ,mBAAmB;AACxD,SAASC,OAAOC,KAAK,QAAQ,WAAW;AAExC;;CAEC,GACD,OAAO,SAASC;IACd,MAAMC,gBAAgBP,MAAMQ,UAAU,CAACN;IACvC,MAAMO,UAAiBF,gBAAgBA,gBAAgBJ;IAEvD,MAAMO,kBAAkBL,MAAMI,QAAQE,uBAAuB;IAC7D,MAAMC,kBAAkBP,MAAMI,QAAQI,uBAAuB;IAE7D,MAAMC,cAAcJ,gBAAgBK,CAAC,GAAGH,gBAAgBG,CAAC;IAEzD,OAAOD;AACT;AAEA;;CAEC,GACD,OAAO,SAASE;IACd,OAAOhB,MAAMiB,MAAM,CAAsB,IAAIC;AAC/C"}