@salesmind-ai/design-system 0.2.0 → 0.3.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.
Files changed (123) hide show
  1. package/dist/AppearancePanel-UT57J69V.d.cts +51 -0
  2. package/dist/AppearancePanel-UT57J69V.d.ts +51 -0
  3. package/dist/AppearanceProvider-C36a8-eb.d.cts +45 -0
  4. package/dist/AppearanceProvider-C36a8-eb.d.ts +45 -0
  5. package/dist/Breadcrumb-RX-B_gDV.d.cts +44 -0
  6. package/dist/Breadcrumb-RX-B_gDV.d.ts +44 -0
  7. package/dist/ExportMenu-A2TLFiVv.d.cts +311 -0
  8. package/dist/ExportMenu-C8qck5AT.d.ts +311 -0
  9. package/dist/SectionShell-BfBw5q0Y.d.cts +18 -0
  10. package/dist/SectionShell-BfBw5q0Y.d.ts +18 -0
  11. package/dist/Select-BdZmK0Lt.d.cts +66 -0
  12. package/dist/Select-BdZmK0Lt.d.ts +66 -0
  13. package/dist/admin/index.cjs +2941 -0
  14. package/dist/admin/index.cjs.map +1 -0
  15. package/dist/admin/index.css +4145 -0
  16. package/dist/admin/index.css.map +1 -0
  17. package/dist/admin/index.d.cts +491 -0
  18. package/dist/admin/index.d.ts +491 -0
  19. package/dist/admin/index.js +2918 -0
  20. package/dist/admin/index.js.map +1 -0
  21. package/dist/{audit-CiyPkxk1.d.cts → audit-BS2fn7M4.d.ts} +2 -51
  22. package/dist/{audit-CiyPkxk1.d.ts → audit-DwCmg32J.d.cts} +2 -51
  23. package/dist/blog/index.cjs +1074 -0
  24. package/dist/blog/index.cjs.map +1 -0
  25. package/dist/blog/index.css +1422 -0
  26. package/dist/blog/index.css.map +1 -0
  27. package/dist/blog/index.d.cts +233 -0
  28. package/dist/blog/index.d.ts +233 -0
  29. package/dist/blog/index.js +1056 -0
  30. package/dist/blog/index.js.map +1 -0
  31. package/dist/chart-types-BGVVO-zl.d.cts +208 -0
  32. package/dist/chart-types-BGVVO-zl.d.ts +208 -0
  33. package/dist/charts/index.cjs +2698 -0
  34. package/dist/charts/index.cjs.map +1 -0
  35. package/dist/charts/index.css +1167 -0
  36. package/dist/charts/index.css.map +1 -0
  37. package/dist/charts/index.d.cts +453 -0
  38. package/dist/charts/index.d.ts +453 -0
  39. package/dist/charts/index.js +2682 -0
  40. package/dist/charts/index.js.map +1 -0
  41. package/dist/core/index.cjs +526 -395
  42. package/dist/core/index.cjs.map +1 -1
  43. package/dist/core/index.css +297 -2
  44. package/dist/core/index.css.map +1 -1
  45. package/dist/core/index.d.cts +7 -982
  46. package/dist/core/index.d.ts +7 -982
  47. package/dist/core/index.js +476 -351
  48. package/dist/core/index.js.map +1 -1
  49. package/dist/i18n/index.cjs +585 -0
  50. package/dist/i18n/index.cjs.map +1 -0
  51. package/dist/i18n/index.d.cts +855 -0
  52. package/dist/i18n/index.d.ts +855 -0
  53. package/dist/i18n/index.js +547 -0
  54. package/dist/i18n/index.js.map +1 -0
  55. package/dist/index.css +16 -6
  56. package/dist/index.css.map +1 -1
  57. package/dist/index.d.cts +22 -1290
  58. package/dist/index.d.ts +22 -1290
  59. package/dist/marketing/index.cjs +2144 -3023
  60. package/dist/marketing/index.cjs.map +1 -1
  61. package/dist/marketing/index.css +3729 -4824
  62. package/dist/marketing/index.css.map +1 -1
  63. package/dist/marketing/index.d.cts +1351 -4
  64. package/dist/marketing/index.d.ts +1351 -4
  65. package/dist/marketing/index.js +2190 -3054
  66. package/dist/marketing/index.js.map +1 -1
  67. package/dist/motion/index.cjs +1230 -0
  68. package/dist/motion/index.cjs.map +1 -0
  69. package/dist/motion/index.css +699 -0
  70. package/dist/motion/index.css.map +1 -0
  71. package/dist/motion/index.d.cts +68 -0
  72. package/dist/motion/index.d.ts +68 -0
  73. package/dist/motion/index.js +1218 -0
  74. package/dist/motion/index.js.map +1 -0
  75. package/dist/nav/index.cjs +1533 -0
  76. package/dist/nav/index.cjs.map +1 -0
  77. package/dist/nav/index.css +1984 -0
  78. package/dist/nav/index.css.map +1 -0
  79. package/dist/nav/index.d.cts +279 -0
  80. package/dist/nav/index.d.ts +279 -0
  81. package/dist/nav/index.js +1501 -0
  82. package/dist/nav/index.js.map +1 -0
  83. package/dist/report/index.cjs +26 -1649
  84. package/dist/report/index.cjs.map +1 -1
  85. package/dist/report/index.css +6 -968
  86. package/dist/report/index.css.map +1 -1
  87. package/dist/report/index.d.cts +4 -2
  88. package/dist/report/index.d.ts +4 -2
  89. package/dist/report/index.js +27 -1640
  90. package/dist/report/index.js.map +1 -1
  91. package/dist/sections/index.cjs +385 -0
  92. package/dist/sections/index.cjs.map +1 -0
  93. package/dist/sections/index.css +818 -0
  94. package/dist/sections/index.css.map +1 -0
  95. package/dist/sections/index.d.cts +69 -0
  96. package/dist/sections/index.d.ts +69 -0
  97. package/dist/sections/index.js +374 -0
  98. package/dist/sections/index.js.map +1 -0
  99. package/dist/social-proof/index.cjs +1254 -0
  100. package/dist/social-proof/index.cjs.map +1 -0
  101. package/dist/social-proof/index.css +1416 -0
  102. package/dist/social-proof/index.css.map +1 -0
  103. package/dist/social-proof/index.d.cts +258 -0
  104. package/dist/social-proof/index.d.ts +258 -0
  105. package/dist/social-proof/index.js +1237 -0
  106. package/dist/social-proof/index.js.map +1 -0
  107. package/dist/theme/index.cjs +573 -0
  108. package/dist/theme/index.cjs.map +1 -0
  109. package/dist/theme/index.css +464 -0
  110. package/dist/theme/index.css.map +1 -0
  111. package/dist/theme/index.d.cts +48 -0
  112. package/dist/theme/index.d.ts +48 -0
  113. package/dist/theme/index.js +558 -0
  114. package/dist/theme/index.js.map +1 -0
  115. package/dist/types-DAlgDGzw.d.cts +52 -0
  116. package/dist/types-DAlgDGzw.d.ts +52 -0
  117. package/dist/web/index.d.cts +3 -2
  118. package/dist/web/index.d.ts +3 -2
  119. package/package.json +68 -9
  120. package/dist/ExportMenu-hEe5MhLq.d.cts +0 -1027
  121. package/dist/ExportMenu-hEe5MhLq.d.ts +0 -1027
  122. package/dist/index-B64suAAc.d.cts +0 -1498
  123. package/dist/index-B64suAAc.d.ts +0 -1498
@@ -0,0 +1,2682 @@
1
+ import clsx11 from 'clsx';
2
+ import { LineChart as LineChart$1, CartesianGrid, XAxis, YAxis, Tooltip as Tooltip$1, Legend, Line, BarChart as BarChart$1, Bar, Cell, PieChart as PieChart$1, Pie, RadarChart, PolarGrid, PolarAngleAxis, PolarRadiusAxis, Radar, ResponsiveContainer, AreaChart, Area } from 'recharts';
3
+ import React2, { createContext, useMemo, useState, useContext } from 'react';
4
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
+ import { Tooltip } from '@base-ui/react/tooltip';
6
+
7
+ // src/components/ChartContainer/ChartContainer.tsx
8
+
9
+ // src/report-engine/constants.ts
10
+ var EXECUTIVE_MODE = {
11
+ mode: "executive",
12
+ features: {
13
+ showMethodology: false,
14
+ showConfidenceScores: false,
15
+ showRawData: false,
16
+ showStatisticalTests: false,
17
+ chartDetailLevel: "summary",
18
+ maxInsightsShown: 5,
19
+ allowDrilldown: false
20
+ }
21
+ };
22
+ var CONFIDENCE_THRESHOLDS = [
23
+ { level: "high", min: 90, max: 100, label: "High Confidence", color: "var(--status-success)" },
24
+ {
25
+ level: "moderate",
26
+ min: 70,
27
+ max: 89,
28
+ label: "Moderate Confidence",
29
+ color: "var(--status-info)"
30
+ },
31
+ { level: "low", min: 50, max: 69, label: "Low Confidence", color: "var(--status-warning)" },
32
+ {
33
+ level: "insufficient",
34
+ min: 0,
35
+ max: 49,
36
+ label: "Insufficient Data",
37
+ color: "var(--status-error)"
38
+ }
39
+ ];
40
+ var MINIMUM_SAMPLE_SIZES = {
41
+ overall: 30};
42
+ var ANALYTICAL_STATE_CONFIG = {
43
+ VALID: {
44
+ label: "Valid",
45
+ icon: "check",
46
+ color: "var(--status-success)",
47
+ action: null
48
+ },
49
+ INSUFFICIENT_SAMPLE: {
50
+ label: "Insufficient Sample",
51
+ icon: "alert-triangle",
52
+ color: "var(--status-warning)",
53
+ action: "Add more data"
54
+ },
55
+ LOW_CONFIDENCE: {
56
+ label: "Low Confidence",
57
+ icon: "alert-circle",
58
+ color: "var(--status-warning)",
59
+ action: "Interpret with caution"
60
+ },
61
+ PARTIAL_TIME_WINDOW: {
62
+ label: "Partial Data",
63
+ icon: "clock",
64
+ color: "var(--status-info)",
65
+ action: "Expand date range"
66
+ },
67
+ DATA_SKEW_DETECTED: {
68
+ label: "Data Skew",
69
+ icon: "bar-chart-2",
70
+ color: "var(--status-warning)",
71
+ action: "Review methodology"
72
+ },
73
+ CONFLICTING_SIGNALS: {
74
+ label: "Conflicting Signals",
75
+ icon: "git-merge",
76
+ color: "var(--status-error)",
77
+ action: "Manual review needed"
78
+ },
79
+ INFERRED_NOT_OBSERVED: {
80
+ label: "AI Generated",
81
+ icon: "cpu",
82
+ color: "var(--status-info)",
83
+ action: "Verify with data"
84
+ },
85
+ STALE_DATA: {
86
+ label: "Stale Data",
87
+ icon: "clock",
88
+ color: "var(--status-warning)",
89
+ action: "Refresh data"
90
+ },
91
+ FIELD_MISSING: {
92
+ label: "Missing Field",
93
+ icon: "file-x",
94
+ color: "var(--status-error)",
95
+ action: "Upload complete data"
96
+ },
97
+ CALCULATION_ERROR: {
98
+ label: "Calculation Error",
99
+ icon: "x-circle",
100
+ color: "var(--status-error)",
101
+ action: "Contact support"
102
+ }
103
+ };
104
+
105
+ // src/report-engine/confidence.ts
106
+ function calculateConfidence(params) {
107
+ const { sampleSize, requiredSize, completeness, recency, variance} = params;
108
+ const sampleScore = Math.min(40, sampleSize / requiredSize * 40);
109
+ const completenessScore = completeness * 20;
110
+ const recencyScore = recency * 20;
111
+ const variancePenalty = variance * 10;
112
+ const aiPenalty = 0;
113
+ const rawScore = sampleScore + completenessScore + recencyScore - variancePenalty - aiPenalty;
114
+ return Math.max(0, Math.min(100, Math.round(rawScore)));
115
+ }
116
+ function getConfidenceThreshold(score) {
117
+ return CONFIDENCE_THRESHOLDS.find((t) => score >= t.min && score <= t.max) ?? CONFIDENCE_THRESHOLDS[CONFIDENCE_THRESHOLDS.length - 1];
118
+ }
119
+ var ReportModeContext = createContext(null);
120
+ function useReportMode() {
121
+ const context = useContext(ReportModeContext);
122
+ if (!context) {
123
+ return EXECUTIVE_MODE;
124
+ }
125
+ return context;
126
+ }
127
+ function useChartData({
128
+ data,
129
+ requiredFields,
130
+ minSampleSize = MINIMUM_SAMPLE_SIZES.overall
131
+ }) {
132
+ return useMemo(() => {
133
+ const missingFields = [];
134
+ if (data.length > 0) {
135
+ const firstRecord = data[0];
136
+ for (const field of requiredFields) {
137
+ if (!(field in firstRecord)) {
138
+ missingFields.push(field);
139
+ }
140
+ }
141
+ }
142
+ let completeness = 1;
143
+ if (data.length > 0 && requiredFields.length > 0) {
144
+ let filled = 0;
145
+ let total = 0;
146
+ for (const record of data) {
147
+ for (const field of requiredFields) {
148
+ total++;
149
+ const value = record[field];
150
+ if (value !== null && value !== void 0 && value !== "") {
151
+ filled++;
152
+ }
153
+ }
154
+ }
155
+ completeness = total > 0 ? filled / total : 0;
156
+ }
157
+ let state = "VALID";
158
+ let message;
159
+ if (missingFields.length > 0) {
160
+ state = "FIELD_MISSING";
161
+ message = `Missing fields: ${missingFields.join(", ")}`;
162
+ } else if (data.length === 0) {
163
+ state = "INSUFFICIENT_SAMPLE";
164
+ message = "No data available";
165
+ } else if (data.length < minSampleSize) {
166
+ state = "INSUFFICIENT_SAMPLE";
167
+ message = `Sample size ${data.length} is below minimum ${minSampleSize}`;
168
+ } else if (completeness < 0.7) {
169
+ state = "LOW_CONFIDENCE";
170
+ message = `Data completeness is ${Math.round(completeness * 100)}%`;
171
+ }
172
+ const confidence = calculateConfidence({
173
+ sampleSize: data.length,
174
+ requiredSize: minSampleSize,
175
+ completeness,
176
+ recency: 1,
177
+ // Assume fresh data if not specified
178
+ variance: 0});
179
+ const isRenderable = state === "VALID" || state === "LOW_CONFIDENCE";
180
+ return {
181
+ data,
182
+ state,
183
+ confidence,
184
+ isRenderable,
185
+ message
186
+ };
187
+ }, [data, requiredFields, minSampleSize]);
188
+ }
189
+
190
+ // src/report-engine/chart-types.ts
191
+ var CHART_REGISTRY = {
192
+ // ══════════════════════════════════════════════════════════════════════════
193
+ // TREND CHARTS (MVP)
194
+ // ══════════════════════════════════════════════════════════════════════════
195
+ line: {
196
+ id: "line",
197
+ name: "Line Chart",
198
+ description: "Shows trends over time with connected data points",
199
+ intent: "trend",
200
+ phase: "mvp",
201
+ contract: {
202
+ requiredDimensions: 1,
203
+ requiredMeasures: 1,
204
+ minDataPoints: 3,
205
+ idealDataPoints: 7,
206
+ allowNegativeValues: true,
207
+ requireNonZeroTotal: false,
208
+ warningThresholds: { sparseData: 3 },
209
+ fallback: { type: "show_kpi", message: "Insufficient data for trend visualization" }
210
+ },
211
+ switchableTo: ["smooth_line", "area", "stacked_area"],
212
+ supportsStacking: false,
213
+ supportsMultipleSeries: true,
214
+ requiresTimeAxis: true
215
+ },
216
+ smooth_line: {
217
+ id: "smooth_line",
218
+ name: "Smooth Line Chart",
219
+ description: "Curved line chart for smoother trend visualization",
220
+ intent: "trend",
221
+ phase: "mvp",
222
+ contract: {
223
+ requiredDimensions: 1,
224
+ requiredMeasures: 1,
225
+ minDataPoints: 3,
226
+ idealDataPoints: 7,
227
+ allowNegativeValues: true,
228
+ requireNonZeroTotal: false,
229
+ warningThresholds: { sparseData: 3 },
230
+ fallback: { type: "show_kpi", message: "Insufficient data for trend visualization" }
231
+ },
232
+ switchableTo: ["line", "area", "stacked_area"],
233
+ supportsStacking: false,
234
+ supportsMultipleSeries: true,
235
+ requiresTimeAxis: true
236
+ },
237
+ area: {
238
+ id: "area",
239
+ name: "Area Chart",
240
+ description: "Filled area under line, emphasizes volume over time",
241
+ intent: "trend",
242
+ phase: "mvp",
243
+ contract: {
244
+ requiredDimensions: 1,
245
+ requiredMeasures: 1,
246
+ minDataPoints: 3,
247
+ idealDataPoints: 7,
248
+ allowNegativeValues: false,
249
+ requireNonZeroTotal: false,
250
+ warningThresholds: { sparseData: 3 },
251
+ fallback: { type: "show_kpi", message: "Insufficient data for area visualization" }
252
+ },
253
+ switchableTo: ["line", "smooth_line", "stacked_area", "area_100pct"],
254
+ supportsStacking: true,
255
+ supportsMultipleSeries: true,
256
+ requiresTimeAxis: true
257
+ },
258
+ stacked_area: {
259
+ id: "stacked_area",
260
+ name: "Stacked Area Chart",
261
+ description: "Multiple series stacked to show cumulative trends",
262
+ intent: "trend",
263
+ phase: "mvp",
264
+ contract: {
265
+ requiredDimensions: 1,
266
+ requiredMeasures: 2,
267
+ minDataPoints: 3,
268
+ idealDataPoints: 7,
269
+ allowNegativeValues: false,
270
+ requireNonZeroTotal: true,
271
+ warningThresholds: { sparseData: 3 },
272
+ fallback: { type: "warn", message: "Stacked area requires non-negative values" }
273
+ },
274
+ switchableTo: ["line", "area", "area_100pct"],
275
+ supportsStacking: true,
276
+ supportsMultipleSeries: true,
277
+ requiresTimeAxis: true
278
+ },
279
+ area_100pct: {
280
+ id: "area_100pct",
281
+ name: "100% Stacked Area",
282
+ description: "Shows proportional contribution over time",
283
+ intent: "trend",
284
+ phase: "mvp",
285
+ contract: {
286
+ requiredDimensions: 1,
287
+ requiredMeasures: 2,
288
+ minDataPoints: 3,
289
+ idealDataPoints: 7,
290
+ allowNegativeValues: false,
291
+ requireNonZeroTotal: true,
292
+ warningThresholds: { sparseData: 3 },
293
+ fallback: { type: "warn", message: "100% stacked requires positive totals" }
294
+ },
295
+ switchableTo: ["stacked_area", "area"],
296
+ supportsStacking: true,
297
+ supportsMultipleSeries: true,
298
+ requiresTimeAxis: true
299
+ },
300
+ // ══════════════════════════════════════════════════════════════════════════
301
+ // COMPARISON CHARTS (MVP)
302
+ // ══════════════════════════════════════════════════════════════════════════
303
+ bar: {
304
+ id: "bar",
305
+ name: "Horizontal Bar Chart",
306
+ description: "Horizontal bars for comparing categories",
307
+ intent: "comparison",
308
+ phase: "mvp",
309
+ contract: {
310
+ requiredDimensions: 1,
311
+ requiredMeasures: 1,
312
+ minDataPoints: 2,
313
+ idealDataPoints: 5,
314
+ maxDataPoints: 15,
315
+ allowNegativeValues: true,
316
+ requireNonZeroTotal: false,
317
+ warningThresholds: { tooManyCategories: 12 },
318
+ fallback: { type: "aggregate", strategy: "top_n" }
319
+ },
320
+ switchableTo: ["column", "stacked_bar", "stacked_column"],
321
+ supportsStacking: true,
322
+ supportsMultipleSeries: true,
323
+ requiresTimeAxis: false
324
+ },
325
+ column: {
326
+ id: "column",
327
+ name: "Vertical Column Chart",
328
+ description: "Vertical bars for comparing categories",
329
+ intent: "comparison",
330
+ phase: "mvp",
331
+ contract: {
332
+ requiredDimensions: 1,
333
+ requiredMeasures: 1,
334
+ minDataPoints: 2,
335
+ idealDataPoints: 5,
336
+ maxDataPoints: 12,
337
+ allowNegativeValues: true,
338
+ requireNonZeroTotal: false,
339
+ warningThresholds: { tooManyCategories: 10 },
340
+ fallback: { type: "aggregate", strategy: "top_n" }
341
+ },
342
+ switchableTo: ["bar", "stacked_column", "stacked_bar"],
343
+ supportsStacking: true,
344
+ supportsMultipleSeries: true,
345
+ requiresTimeAxis: false
346
+ },
347
+ stacked_bar: {
348
+ id: "stacked_bar",
349
+ name: "Stacked Horizontal Bar",
350
+ description: "Horizontal stacked bars showing composition per category",
351
+ intent: "comparison",
352
+ phase: "mvp",
353
+ contract: {
354
+ requiredDimensions: 1,
355
+ requiredMeasures: 2,
356
+ minDataPoints: 2,
357
+ idealDataPoints: 5,
358
+ maxDataPoints: 10,
359
+ allowNegativeValues: false,
360
+ requireNonZeroTotal: true,
361
+ warningThresholds: { tooManyCategories: 8, imbalancedRatio: 0.9 },
362
+ fallback: { type: "aggregate", strategy: "other_bucket" }
363
+ },
364
+ switchableTo: ["bar", "stacked_column", "column_100pct"],
365
+ supportsStacking: true,
366
+ supportsMultipleSeries: true,
367
+ requiresTimeAxis: false
368
+ },
369
+ stacked_column: {
370
+ id: "stacked_column",
371
+ name: "Stacked Vertical Column",
372
+ description: "Vertical stacked columns showing composition per category",
373
+ intent: "comparison",
374
+ phase: "mvp",
375
+ contract: {
376
+ requiredDimensions: 1,
377
+ requiredMeasures: 2,
378
+ minDataPoints: 2,
379
+ idealDataPoints: 5,
380
+ maxDataPoints: 10,
381
+ allowNegativeValues: false,
382
+ requireNonZeroTotal: true,
383
+ warningThresholds: { tooManyCategories: 8, imbalancedRatio: 0.9 },
384
+ fallback: { type: "aggregate", strategy: "other_bucket" }
385
+ },
386
+ switchableTo: ["column", "stacked_bar", "column_100pct"],
387
+ supportsStacking: true,
388
+ supportsMultipleSeries: true,
389
+ requiresTimeAxis: false
390
+ },
391
+ column_100pct: {
392
+ id: "column_100pct",
393
+ name: "100% Stacked Column",
394
+ description: "Shows proportional composition per category",
395
+ intent: "comparison",
396
+ phase: "mvp",
397
+ contract: {
398
+ requiredDimensions: 1,
399
+ requiredMeasures: 2,
400
+ minDataPoints: 2,
401
+ idealDataPoints: 5,
402
+ maxDataPoints: 10,
403
+ allowNegativeValues: false,
404
+ requireNonZeroTotal: true,
405
+ warningThresholds: { tooManyCategories: 8 },
406
+ fallback: { type: "warn", message: "100% stacked requires positive totals" }
407
+ },
408
+ switchableTo: ["stacked_column", "stacked_bar"],
409
+ supportsStacking: true,
410
+ supportsMultipleSeries: true,
411
+ requiresTimeAxis: false
412
+ },
413
+ combo: {
414
+ id: "combo",
415
+ name: "Combo Chart",
416
+ description: "Combines bars with line overlay (Phase 2)",
417
+ intent: "comparison",
418
+ phase: "phase2",
419
+ contract: {
420
+ requiredDimensions: 1,
421
+ requiredMeasures: 2,
422
+ minDataPoints: 3,
423
+ idealDataPoints: 6,
424
+ allowNegativeValues: true,
425
+ requireNonZeroTotal: false,
426
+ warningThresholds: { tooManyCategories: 10 },
427
+ fallback: { type: "warn", message: "Combo chart requires dual measures" }
428
+ },
429
+ switchableTo: ["column", "line"],
430
+ supportsStacking: false,
431
+ supportsMultipleSeries: true,
432
+ requiresTimeAxis: false
433
+ },
434
+ // ══════════════════════════════════════════════════════════════════════════
435
+ // COMPOSITION CHARTS (MVP)
436
+ // ══════════════════════════════════════════════════════════════════════════
437
+ pie: {
438
+ id: "pie",
439
+ name: "Pie Chart",
440
+ description: "Shows proportional composition of a whole",
441
+ intent: "composition",
442
+ phase: "mvp",
443
+ contract: {
444
+ requiredDimensions: 1,
445
+ requiredMeasures: 1,
446
+ minDataPoints: 2,
447
+ idealDataPoints: 4,
448
+ maxDataPoints: 6,
449
+ allowNegativeValues: false,
450
+ requireNonZeroTotal: true,
451
+ warningThresholds: { tooManyCategories: 6, imbalancedRatio: 0.95 },
452
+ fallback: { type: "aggregate", strategy: "other_bucket" }
453
+ },
454
+ switchableTo: ["donut", "column_100pct"],
455
+ supportsStacking: false,
456
+ supportsMultipleSeries: false,
457
+ requiresTimeAxis: false,
458
+ maxSlices: 6
459
+ },
460
+ donut: {
461
+ id: "donut",
462
+ name: "Donut Chart",
463
+ description: "Pie chart with center cutout, can display total",
464
+ intent: "composition",
465
+ phase: "mvp",
466
+ contract: {
467
+ requiredDimensions: 1,
468
+ requiredMeasures: 1,
469
+ minDataPoints: 2,
470
+ idealDataPoints: 4,
471
+ maxDataPoints: 6,
472
+ allowNegativeValues: false,
473
+ requireNonZeroTotal: true,
474
+ warningThresholds: { tooManyCategories: 6, imbalancedRatio: 0.95 },
475
+ fallback: { type: "aggregate", strategy: "other_bucket" }
476
+ },
477
+ switchableTo: ["pie", "column_100pct"],
478
+ supportsStacking: false,
479
+ supportsMultipleSeries: false,
480
+ requiresTimeAxis: false,
481
+ maxSlices: 6
482
+ },
483
+ treemap: {
484
+ id: "treemap",
485
+ name: "Treemap",
486
+ description: "Nested rectangles showing hierarchical composition (Phase 2)",
487
+ intent: "composition",
488
+ phase: "phase2",
489
+ contract: {
490
+ requiredDimensions: 1,
491
+ requiredMeasures: 1,
492
+ minDataPoints: 3,
493
+ idealDataPoints: 10,
494
+ maxDataPoints: 50,
495
+ allowNegativeValues: false,
496
+ requireNonZeroTotal: true,
497
+ warningThresholds: { tooManyCategories: 30 },
498
+ fallback: { type: "aggregate", strategy: "top_n" }
499
+ },
500
+ switchableTo: ["pie", "donut"],
501
+ supportsStacking: false,
502
+ supportsMultipleSeries: false,
503
+ requiresTimeAxis: false
504
+ },
505
+ // ══════════════════════════════════════════════════════════════════════════
506
+ // DISTRIBUTION CHARTS (MVP)
507
+ // ══════════════════════════════════════════════════════════════════════════
508
+ histogram: {
509
+ id: "histogram",
510
+ name: "Histogram",
511
+ description: "Shows distribution of values across bins",
512
+ intent: "distribution",
513
+ phase: "mvp",
514
+ contract: {
515
+ requiredDimensions: 0,
516
+ requiredMeasures: 1,
517
+ minDataPoints: 10,
518
+ idealDataPoints: 50,
519
+ allowNegativeValues: true,
520
+ requireNonZeroTotal: false,
521
+ warningThresholds: { sparseData: 10 },
522
+ fallback: { type: "show_kpi", message: "Insufficient data for distribution" }
523
+ },
524
+ switchableTo: ["radar"],
525
+ supportsStacking: false,
526
+ supportsMultipleSeries: false,
527
+ requiresTimeAxis: false
528
+ },
529
+ radar: {
530
+ id: "radar",
531
+ name: "Radar Chart",
532
+ description: "Multi-dimensional comparison in radial layout (Phase 2)",
533
+ intent: "distribution",
534
+ phase: "phase2",
535
+ contract: {
536
+ requiredDimensions: 1,
537
+ requiredMeasures: 3,
538
+ minDataPoints: 3,
539
+ idealDataPoints: 6,
540
+ maxDataPoints: 8,
541
+ allowNegativeValues: false,
542
+ requireNonZeroTotal: false,
543
+ warningThresholds: { tooManyCategories: 8 },
544
+ fallback: { type: "warn", message: "Radar works best with 3-8 dimensions" }
545
+ },
546
+ switchableTo: ["histogram"],
547
+ supportsStacking: false,
548
+ supportsMultipleSeries: true,
549
+ requiresTimeAxis: false
550
+ },
551
+ // ══════════════════════════════════════════════════════════════════════════
552
+ // RELATIONSHIP CHARTS
553
+ // ══════════════════════════════════════════════════════════════════════════
554
+ heatmap: {
555
+ id: "heatmap",
556
+ name: "Heatmap",
557
+ description: "Color-coded matrix showing intensity",
558
+ intent: "relationship",
559
+ phase: "mvp",
560
+ contract: {
561
+ requiredDimensions: 2,
562
+ requiredMeasures: 1,
563
+ minDataPoints: 9,
564
+ idealDataPoints: 25,
565
+ allowNegativeValues: true,
566
+ requireNonZeroTotal: false,
567
+ warningThresholds: { sparseData: 9 },
568
+ fallback: { type: "warn", message: "Heatmap requires grid data" }
569
+ },
570
+ switchableTo: ["scatter"],
571
+ supportsStacking: false,
572
+ supportsMultipleSeries: false,
573
+ requiresTimeAxis: false
574
+ },
575
+ scatter: {
576
+ id: "scatter",
577
+ name: "Scatter Plot",
578
+ description: "Shows correlation between two variables (Phase 2)",
579
+ intent: "relationship",
580
+ phase: "phase2",
581
+ contract: {
582
+ requiredDimensions: 0,
583
+ requiredMeasures: 2,
584
+ minDataPoints: 20,
585
+ idealDataPoints: 100,
586
+ allowNegativeValues: true,
587
+ requireNonZeroTotal: false,
588
+ warningThresholds: { sparseData: 20 },
589
+ fallback: { type: "show_kpi", message: "Scatter requires 20+ points" }
590
+ },
591
+ switchableTo: ["bubble", "heatmap"],
592
+ supportsStacking: false,
593
+ supportsMultipleSeries: true,
594
+ requiresTimeAxis: false
595
+ },
596
+ bubble: {
597
+ id: "bubble",
598
+ name: "Bubble Chart",
599
+ description: "Scatter with sized points for third dimension (Phase 2)",
600
+ intent: "relationship",
601
+ phase: "phase2",
602
+ contract: {
603
+ requiredDimensions: 0,
604
+ requiredMeasures: 3,
605
+ minDataPoints: 10,
606
+ idealDataPoints: 50,
607
+ allowNegativeValues: true,
608
+ requireNonZeroTotal: false,
609
+ warningThresholds: { sparseData: 10 },
610
+ fallback: { type: "show_kpi", message: "Bubble requires 3 measures" }
611
+ },
612
+ switchableTo: ["scatter"],
613
+ supportsStacking: false,
614
+ supportsMultipleSeries: true,
615
+ requiresTimeAxis: false
616
+ },
617
+ // ══════════════════════════════════════════════════════════════════════════
618
+ // GEOGRAPHIC CHARTS (Phase 2)
619
+ // ══════════════════════════════════════════════════════════════════════════
620
+ geo: {
621
+ id: "geo",
622
+ name: "Geographic Map",
623
+ description: "Map with regional data markers (Phase 2)",
624
+ intent: "geo",
625
+ phase: "phase2",
626
+ contract: {
627
+ requiredDimensions: 1,
628
+ // geo dimension (country/region)
629
+ requiredMeasures: 1,
630
+ minDataPoints: 1,
631
+ idealDataPoints: 10,
632
+ allowNegativeValues: true,
633
+ requireNonZeroTotal: false,
634
+ warningThresholds: {},
635
+ fallback: { type: "hide" }
636
+ },
637
+ switchableTo: ["choropleth"],
638
+ supportsStacking: false,
639
+ supportsMultipleSeries: false,
640
+ requiresTimeAxis: false
641
+ },
642
+ choropleth: {
643
+ id: "choropleth",
644
+ name: "Choropleth Map",
645
+ description: "Color-shaded regions by value (Phase 2)",
646
+ intent: "geo",
647
+ phase: "phase2",
648
+ contract: {
649
+ requiredDimensions: 1,
650
+ requiredMeasures: 1,
651
+ minDataPoints: 3,
652
+ idealDataPoints: 20,
653
+ allowNegativeValues: false,
654
+ requireNonZeroTotal: false,
655
+ warningThresholds: {},
656
+ fallback: { type: "hide" }
657
+ },
658
+ switchableTo: ["geo"],
659
+ supportsStacking: false,
660
+ supportsMultipleSeries: false,
661
+ requiresTimeAxis: false
662
+ },
663
+ // ══════════════════════════════════════════════════════════════════════════
664
+ // SPECIAL CHARTS
665
+ // ══════════════════════════════════════════════════════════════════════════
666
+ funnel: {
667
+ id: "funnel",
668
+ name: "Funnel Chart",
669
+ description: "Shows conversion through sequential stages",
670
+ intent: "comparison",
671
+ phase: "mvp",
672
+ contract: {
673
+ requiredDimensions: 1,
674
+ requiredMeasures: 1,
675
+ minDataPoints: 3,
676
+ idealDataPoints: 5,
677
+ maxDataPoints: 7,
678
+ allowNegativeValues: false,
679
+ requireNonZeroTotal: true,
680
+ warningThresholds: { tooManyCategories: 7 },
681
+ fallback: { type: "warn", message: "Funnel requires sequential stages" }
682
+ },
683
+ switchableTo: ["bar"],
684
+ supportsStacking: false,
685
+ supportsMultipleSeries: false,
686
+ requiresTimeAxis: false
687
+ },
688
+ waterfall: {
689
+ id: "waterfall",
690
+ name: "Waterfall Chart",
691
+ description: "Shows cumulative effect of sequential changes (Phase 2)",
692
+ intent: "comparison",
693
+ phase: "phase2",
694
+ contract: {
695
+ requiredDimensions: 1,
696
+ requiredMeasures: 1,
697
+ minDataPoints: 3,
698
+ idealDataPoints: 6,
699
+ maxDataPoints: 12,
700
+ allowNegativeValues: true,
701
+ requireNonZeroTotal: false,
702
+ warningThresholds: { tooManyCategories: 10 },
703
+ fallback: { type: "warn", message: "Waterfall requires sequential data" }
704
+ },
705
+ switchableTo: ["bar", "column"],
706
+ supportsStacking: false,
707
+ supportsMultipleSeries: false,
708
+ requiresTimeAxis: false
709
+ },
710
+ timeline: {
711
+ id: "timeline",
712
+ name: "Timeline",
713
+ description: "Shows events along time axis (Phase 2)",
714
+ intent: "trend",
715
+ phase: "phase2",
716
+ contract: {
717
+ requiredDimensions: 1,
718
+ requiredMeasures: 0,
719
+ minDataPoints: 2,
720
+ idealDataPoints: 10,
721
+ allowNegativeValues: false,
722
+ requireNonZeroTotal: false,
723
+ warningThresholds: {},
724
+ fallback: { type: "hide" }
725
+ },
726
+ switchableTo: ["line"],
727
+ supportsStacking: false,
728
+ supportsMultipleSeries: false,
729
+ requiresTimeAxis: true
730
+ }
731
+ };
732
+ function getAllowedSwitchTargets(currentType) {
733
+ const metadata = CHART_REGISTRY[currentType];
734
+ if (!metadata) return [];
735
+ return metadata.switchableTo.filter((type) => {
736
+ const targetMeta = CHART_REGISTRY[type];
737
+ return targetMeta && targetMeta.phase === "mvp";
738
+ });
739
+ }
740
+ function validateChartData(chartType, data, dimensions, measures) {
741
+ const metadata = CHART_REGISTRY[chartType];
742
+ if (!metadata) {
743
+ return {
744
+ isValid: false,
745
+ warnings: [],
746
+ errors: [`Unknown chart type: ${chartType}`]
747
+ };
748
+ }
749
+ const contract = metadata.contract;
750
+ const warnings = [];
751
+ const errors = [];
752
+ if (data.length < contract.minDataPoints) {
753
+ errors.push(`Requires at least ${contract.minDataPoints} data points, got ${data.length}`);
754
+ }
755
+ if (contract.maxDataPoints && data.length > contract.maxDataPoints) {
756
+ warnings.push(`Chart works best with \u2264${contract.maxDataPoints} items. Consider aggregating.`);
757
+ }
758
+ if (dimensions.length < contract.requiredDimensions) {
759
+ errors.push(`Requires ${contract.requiredDimensions} dimension(s), got ${dimensions.length}`);
760
+ }
761
+ if (measures.length < contract.requiredMeasures) {
762
+ errors.push(`Requires ${contract.requiredMeasures} measure(s), got ${measures.length}`);
763
+ }
764
+ if (!contract.allowNegativeValues && data.length > 0) {
765
+ const hasNegative = data.some((row) => {
766
+ if (typeof row !== "object" || row === null) return false;
767
+ return measures.some((m) => {
768
+ const val = row[m];
769
+ return typeof val === "number" && val < 0;
770
+ });
771
+ });
772
+ if (hasNegative) {
773
+ errors.push("This chart type does not support negative values");
774
+ }
775
+ }
776
+ if (contract.warningThresholds.tooManyCategories && data.length > contract.warningThresholds.tooManyCategories) {
777
+ warnings.push(`Too many categories (${data.length}). Consider grouping smaller values.`);
778
+ }
779
+ return {
780
+ isValid: errors.length === 0,
781
+ warnings,
782
+ errors,
783
+ fallbackAction: errors.length > 0 ? contract.fallback : void 0
784
+ };
785
+ }
786
+ function getDefaultChartForIntent(intent) {
787
+ const defaults = {
788
+ trend: "line",
789
+ comparison: "column",
790
+ composition: "donut",
791
+ distribution: "histogram",
792
+ relationship: "heatmap",
793
+ geo: "geo"
794
+ };
795
+ return defaults[intent];
796
+ }
797
+ var DataStateIndicator = React2.forwardRef(
798
+ ({ state, details, variant = "compact", onAction, className, ...props }, ref) => {
799
+ const config = ANALYTICAL_STATE_CONFIG[state];
800
+ if (state === "VALID" && variant === "compact") {
801
+ return null;
802
+ }
803
+ const renderIcon = () => {
804
+ switch (config.icon) {
805
+ case "check":
806
+ return /* @__PURE__ */ jsx(
807
+ "svg",
808
+ {
809
+ width: "16",
810
+ height: "16",
811
+ viewBox: "0 0 24 24",
812
+ fill: "none",
813
+ stroke: "currentColor",
814
+ strokeWidth: "2",
815
+ children: /* @__PURE__ */ jsx("polyline", { points: "20,6 9,17 4,12" })
816
+ }
817
+ );
818
+ case "alert-triangle":
819
+ return /* @__PURE__ */ jsxs(
820
+ "svg",
821
+ {
822
+ width: "16",
823
+ height: "16",
824
+ viewBox: "0 0 24 24",
825
+ fill: "none",
826
+ stroke: "currentColor",
827
+ strokeWidth: "2",
828
+ children: [
829
+ /* @__PURE__ */ jsx("path", { d: "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" }),
830
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
831
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
832
+ ]
833
+ }
834
+ );
835
+ case "alert-circle":
836
+ return /* @__PURE__ */ jsxs(
837
+ "svg",
838
+ {
839
+ width: "16",
840
+ height: "16",
841
+ viewBox: "0 0 24 24",
842
+ fill: "none",
843
+ stroke: "currentColor",
844
+ strokeWidth: "2",
845
+ children: [
846
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
847
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
848
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
849
+ ]
850
+ }
851
+ );
852
+ case "x-circle":
853
+ return /* @__PURE__ */ jsxs(
854
+ "svg",
855
+ {
856
+ width: "16",
857
+ height: "16",
858
+ viewBox: "0 0 24 24",
859
+ fill: "none",
860
+ stroke: "currentColor",
861
+ strokeWidth: "2",
862
+ children: [
863
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
864
+ /* @__PURE__ */ jsx("line", { x1: "15", y1: "9", x2: "9", y2: "15" }),
865
+ /* @__PURE__ */ jsx("line", { x1: "9", y1: "9", x2: "15", y2: "15" })
866
+ ]
867
+ }
868
+ );
869
+ case "cpu":
870
+ return /* @__PURE__ */ jsxs(
871
+ "svg",
872
+ {
873
+ width: "16",
874
+ height: "16",
875
+ viewBox: "0 0 24 24",
876
+ fill: "none",
877
+ stroke: "currentColor",
878
+ strokeWidth: "2",
879
+ children: [
880
+ /* @__PURE__ */ jsx("rect", { x: "4", y: "4", width: "16", height: "16", rx: "2", ry: "2" }),
881
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "6", height: "6" }),
882
+ /* @__PURE__ */ jsx("line", { x1: "9", y1: "1", x2: "9", y2: "4" }),
883
+ /* @__PURE__ */ jsx("line", { x1: "15", y1: "1", x2: "15", y2: "4" }),
884
+ /* @__PURE__ */ jsx("line", { x1: "9", y1: "20", x2: "9", y2: "23" }),
885
+ /* @__PURE__ */ jsx("line", { x1: "15", y1: "20", x2: "15", y2: "23" }),
886
+ /* @__PURE__ */ jsx("line", { x1: "20", y1: "9", x2: "23", y2: "9" }),
887
+ /* @__PURE__ */ jsx("line", { x1: "20", y1: "14", x2: "23", y2: "14" }),
888
+ /* @__PURE__ */ jsx("line", { x1: "1", y1: "9", x2: "4", y2: "9" }),
889
+ /* @__PURE__ */ jsx("line", { x1: "1", y1: "14", x2: "4", y2: "14" })
890
+ ]
891
+ }
892
+ );
893
+ default:
894
+ return /* @__PURE__ */ jsxs(
895
+ "svg",
896
+ {
897
+ width: "16",
898
+ height: "16",
899
+ viewBox: "0 0 24 24",
900
+ fill: "none",
901
+ stroke: "currentColor",
902
+ strokeWidth: "2",
903
+ children: [
904
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
905
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
906
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "8", x2: "12.01", y2: "8" })
907
+ ]
908
+ }
909
+ );
910
+ }
911
+ };
912
+ return /* @__PURE__ */ jsxs(
913
+ "div",
914
+ {
915
+ ref,
916
+ className: clsx11(
917
+ "ds-data-state-indicator",
918
+ `ds-data-state-indicator--${variant}`,
919
+ `ds-data-state-indicator--${state.toLowerCase().replace(/_/g, "-")}`,
920
+ className
921
+ ),
922
+ role: "status",
923
+ "aria-live": "polite",
924
+ ...props,
925
+ children: [
926
+ /* @__PURE__ */ jsx("span", { className: "ds-data-state-indicator__icon", style: { color: config.color }, children: renderIcon() }),
927
+ /* @__PURE__ */ jsxs("div", { className: "ds-data-state-indicator__content", children: [
928
+ /* @__PURE__ */ jsx("span", { className: "ds-data-state-indicator__label", children: config.label }),
929
+ variant === "full" && details && /* @__PURE__ */ jsxs("span", { className: "ds-data-state-indicator__details", children: [
930
+ details.message,
931
+ details.sampleSize !== void 0 && details.requiredSize !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
932
+ " ",
933
+ "(n=",
934
+ details.sampleSize,
935
+ "/",
936
+ details.requiredSize,
937
+ ")"
938
+ ] }),
939
+ details.confidence !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
940
+ " \u2022 ",
941
+ details.confidence,
942
+ "% confidence"
943
+ ] }),
944
+ details.missingFields && details.missingFields.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
945
+ " \u2022 Missing: ",
946
+ details.missingFields.join(", ")
947
+ ] })
948
+ ] })
949
+ ] }),
950
+ config.action && onAction && /* @__PURE__ */ jsx("button", { type: "button", className: "ds-data-state-indicator__action", onClick: onAction, children: config.action })
951
+ ]
952
+ }
953
+ );
954
+ }
955
+ );
956
+ DataStateIndicator.displayName = "DataStateIndicator";
957
+ var DataCoverageBadge = React2.forwardRef(
958
+ ({ sampleSize, requiredSize, dateRange, showDateRange = true, size = "md", className, ...props }, ref) => {
959
+ const isSufficient = !requiredSize || sampleSize >= requiredSize;
960
+ const percentage = requiredSize ? Math.min(100, Math.round(sampleSize / requiredSize * 100)) : 100;
961
+ return /* @__PURE__ */ jsxs(
962
+ "div",
963
+ {
964
+ ref,
965
+ className: clsx11(
966
+ "ds-data-coverage-badge",
967
+ `ds-data-coverage-badge--${size}`,
968
+ !isSufficient && "ds-data-coverage-badge--insufficient",
969
+ className
970
+ ),
971
+ ...props,
972
+ children: [
973
+ /* @__PURE__ */ jsxs("div", { className: "ds-data-coverage-badge__sample", children: [
974
+ /* @__PURE__ */ jsx("span", { className: "ds-data-coverage-badge__icon", children: /* @__PURE__ */ jsxs(
975
+ "svg",
976
+ {
977
+ width: "14",
978
+ height: "14",
979
+ viewBox: "0 0 24 24",
980
+ fill: "none",
981
+ stroke: "currentColor",
982
+ strokeWidth: "2",
983
+ children: [
984
+ /* @__PURE__ */ jsx("path", { d: "M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" }),
985
+ /* @__PURE__ */ jsx("circle", { cx: "9", cy: "7", r: "4" }),
986
+ /* @__PURE__ */ jsx("path", { d: "M23 21v-2a4 4 0 0 0-3-3.87" }),
987
+ /* @__PURE__ */ jsx("path", { d: "M16 3.13a4 4 0 0 1 0 7.75" })
988
+ ]
989
+ }
990
+ ) }),
991
+ /* @__PURE__ */ jsxs("span", { className: "ds-data-coverage-badge__count", children: [
992
+ "n=",
993
+ sampleSize.toLocaleString()
994
+ ] }),
995
+ requiredSize && /* @__PURE__ */ jsxs("span", { className: "ds-data-coverage-badge__required", children: [
996
+ "(",
997
+ percentage,
998
+ "% of min ",
999
+ requiredSize,
1000
+ ")"
1001
+ ] })
1002
+ ] }),
1003
+ showDateRange && dateRange && /* @__PURE__ */ jsxs("div", { className: "ds-data-coverage-badge__date", children: [
1004
+ /* @__PURE__ */ jsx("span", { className: "ds-data-coverage-badge__icon", children: /* @__PURE__ */ jsxs(
1005
+ "svg",
1006
+ {
1007
+ width: "14",
1008
+ height: "14",
1009
+ viewBox: "0 0 24 24",
1010
+ fill: "none",
1011
+ stroke: "currentColor",
1012
+ strokeWidth: "2",
1013
+ children: [
1014
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }),
1015
+ /* @__PURE__ */ jsx("line", { x1: "16", y1: "2", x2: "16", y2: "6" }),
1016
+ /* @__PURE__ */ jsx("line", { x1: "8", y1: "2", x2: "8", y2: "6" }),
1017
+ /* @__PURE__ */ jsx("line", { x1: "3", y1: "10", x2: "21", y2: "10" })
1018
+ ]
1019
+ }
1020
+ ) }),
1021
+ /* @__PURE__ */ jsxs("span", { children: [
1022
+ dateRange.start,
1023
+ " \u2013 ",
1024
+ dateRange.end
1025
+ ] })
1026
+ ] })
1027
+ ]
1028
+ }
1029
+ );
1030
+ }
1031
+ );
1032
+ DataCoverageBadge.displayName = "DataCoverageBadge";
1033
+ function ChartContainer({
1034
+ title,
1035
+ subtitle,
1036
+ height = 300,
1037
+ data = [],
1038
+ requiredFields = [],
1039
+ minSampleSize = 30,
1040
+ showCoverage = true,
1041
+ dateRange,
1042
+ loading,
1043
+ emptyMessage = "No data available",
1044
+ children,
1045
+ className,
1046
+ ...props
1047
+ }) {
1048
+ const { features } = useReportMode();
1049
+ const { state, isRenderable, message } = useChartData({
1050
+ data,
1051
+ requiredFields,
1052
+ minSampleSize
1053
+ });
1054
+ const renderContent = () => {
1055
+ if (loading) {
1056
+ return /* @__PURE__ */ jsxs("div", { className: "ds-chart-container__loading", children: [
1057
+ /* @__PURE__ */ jsx("div", { className: "ds-chart-container__spinner" }),
1058
+ /* @__PURE__ */ jsx("span", { children: "Loading chart..." })
1059
+ ] });
1060
+ }
1061
+ if (!isRenderable && state !== "VALID") {
1062
+ return /* @__PURE__ */ jsxs("div", { className: "ds-chart-container__empty", children: [
1063
+ /* @__PURE__ */ jsx(
1064
+ DataStateIndicator,
1065
+ {
1066
+ state,
1067
+ variant: "full",
1068
+ details: { message, sampleSize: data.length, requiredSize: minSampleSize }
1069
+ }
1070
+ ),
1071
+ state === "INSUFFICIENT_SAMPLE" && data.length === 0 && /* @__PURE__ */ jsx("p", { className: "ds-chart-container__empty-message", children: emptyMessage })
1072
+ ] });
1073
+ }
1074
+ return /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height, children });
1075
+ };
1076
+ return /* @__PURE__ */ jsxs(
1077
+ "div",
1078
+ {
1079
+ className: clsx11(
1080
+ "ds-chart-container",
1081
+ loading && "ds-chart-container--loading",
1082
+ !isRenderable && "ds-chart-container--invalid",
1083
+ className
1084
+ ),
1085
+ ...props,
1086
+ children: [
1087
+ (title || subtitle || showCoverage && features.showMethodology) && /* @__PURE__ */ jsxs("header", { className: "ds-chart-container__header", children: [
1088
+ /* @__PURE__ */ jsxs("div", { className: "ds-chart-container__header-content", children: [
1089
+ title && /* @__PURE__ */ jsx("h4", { className: "ds-chart-container__title", children: title }),
1090
+ subtitle && /* @__PURE__ */ jsx("p", { className: "ds-chart-container__subtitle", children: subtitle })
1091
+ ] }),
1092
+ showCoverage && features.showMethodology && data.length > 0 && /* @__PURE__ */ jsx(
1093
+ DataCoverageBadge,
1094
+ {
1095
+ sampleSize: data.length,
1096
+ requiredSize: minSampleSize,
1097
+ dateRange,
1098
+ size: "sm"
1099
+ }
1100
+ )
1101
+ ] }),
1102
+ /* @__PURE__ */ jsx(
1103
+ "div",
1104
+ {
1105
+ className: "ds-chart-container__chart",
1106
+ style: { height: typeof height === "number" ? height : void 0 },
1107
+ children: renderContent()
1108
+ }
1109
+ ),
1110
+ isRenderable && state !== "VALID" && /* @__PURE__ */ jsx("footer", { className: "ds-chart-container__footer", children: /* @__PURE__ */ jsx(DataStateIndicator, { state, variant: "compact" }) })
1111
+ ]
1112
+ }
1113
+ );
1114
+ }
1115
+ ChartContainer.displayName = "ChartContainer";
1116
+ var DEFAULT_COLORS = [
1117
+ "var(--brand-pink)",
1118
+ "var(--brand-yellow)",
1119
+ "var(--status-info)",
1120
+ "var(--status-success)",
1121
+ "var(--status-warning)"
1122
+ ];
1123
+ function LineChart({
1124
+ data,
1125
+ xKey,
1126
+ lines,
1127
+ title,
1128
+ subtitle,
1129
+ height = 300,
1130
+ grid = true,
1131
+ legend: showLegend = true,
1132
+ curve = "monotone",
1133
+ minSampleSize = 7,
1134
+ dateRange,
1135
+ className
1136
+ }) {
1137
+ const requiredFields = [xKey, ...lines.map((l) => l.key)];
1138
+ const chartData = React2.useMemo(() => data.map((item) => ({ ...item })), [data]);
1139
+ return /* @__PURE__ */ jsx(
1140
+ ChartContainer,
1141
+ {
1142
+ title,
1143
+ subtitle,
1144
+ height,
1145
+ data,
1146
+ requiredFields,
1147
+ minSampleSize,
1148
+ dateRange,
1149
+ className,
1150
+ children: /* @__PURE__ */ jsxs(LineChart$1, { data: chartData, margin: { top: 5, right: 20, left: 0, bottom: 5 }, children: [
1151
+ grid && /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", vertical: false }),
1152
+ /* @__PURE__ */ jsx(
1153
+ XAxis,
1154
+ {
1155
+ dataKey: xKey,
1156
+ tick: { fontSize: 12 },
1157
+ tickLine: false,
1158
+ axisLine: { strokeWidth: 1 }
1159
+ }
1160
+ ),
1161
+ /* @__PURE__ */ jsx(YAxis, { tick: { fontSize: 12 }, tickLine: false, axisLine: false, width: 40 }),
1162
+ /* @__PURE__ */ jsx(Tooltip$1, {}),
1163
+ showLegend && /* @__PURE__ */ jsx(Legend, {}),
1164
+ lines.map((line, index) => /* @__PURE__ */ jsx(
1165
+ Line,
1166
+ {
1167
+ type: curve,
1168
+ dataKey: line.key,
1169
+ name: line.name || line.key,
1170
+ stroke: line.color || DEFAULT_COLORS[index % DEFAULT_COLORS.length],
1171
+ strokeWidth: 2,
1172
+ strokeDasharray: line.dashed ? "5 5" : void 0,
1173
+ dot: line.dot !== false,
1174
+ activeDot: { r: 6 }
1175
+ },
1176
+ line.key
1177
+ ))
1178
+ ] })
1179
+ }
1180
+ );
1181
+ }
1182
+ LineChart.displayName = "LineChart";
1183
+ var DEFAULT_COLORS2 = [
1184
+ "var(--brand-pink)",
1185
+ "var(--brand-yellow)",
1186
+ "var(--status-info)",
1187
+ "var(--status-success)",
1188
+ "var(--status-warning)"
1189
+ ];
1190
+ function BarChart({
1191
+ data,
1192
+ xKey,
1193
+ bars,
1194
+ title,
1195
+ subtitle,
1196
+ height = 300,
1197
+ layout = "horizontal",
1198
+ grid = true,
1199
+ legend: showLegend = true,
1200
+ radius = 4,
1201
+ showLabels = false,
1202
+ minSampleSize = 5,
1203
+ categoryColors,
1204
+ className
1205
+ }) {
1206
+ const requiredFields = [xKey, ...bars.map((b) => b.key)];
1207
+ const isVertical = layout === "vertical";
1208
+ const chartData = useMemo(() => data.map((item) => ({ ...item })), [data]);
1209
+ return /* @__PURE__ */ jsx(
1210
+ ChartContainer,
1211
+ {
1212
+ title,
1213
+ subtitle,
1214
+ height,
1215
+ data: chartData,
1216
+ requiredFields,
1217
+ minSampleSize,
1218
+ className,
1219
+ children: /* @__PURE__ */ jsxs(
1220
+ BarChart$1,
1221
+ {
1222
+ data: chartData,
1223
+ layout: isVertical ? "vertical" : "horizontal",
1224
+ margin: { top: 5, right: 20, left: isVertical ? 80 : 0, bottom: 5 },
1225
+ children: [
1226
+ grid && /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", horizontal: !isVertical, vertical: isVertical }),
1227
+ isVertical ? /* @__PURE__ */ jsxs(Fragment, { children: [
1228
+ /* @__PURE__ */ jsx(XAxis, { type: "number", tick: { fontSize: 12 }, tickLine: false, axisLine: false }),
1229
+ /* @__PURE__ */ jsx(
1230
+ YAxis,
1231
+ {
1232
+ type: "category",
1233
+ dataKey: xKey,
1234
+ tick: { fontSize: 12 },
1235
+ tickLine: false,
1236
+ axisLine: false,
1237
+ width: 80
1238
+ }
1239
+ )
1240
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1241
+ /* @__PURE__ */ jsx(
1242
+ XAxis,
1243
+ {
1244
+ dataKey: xKey,
1245
+ tick: { fontSize: 12 },
1246
+ tickLine: false,
1247
+ axisLine: { strokeWidth: 1 }
1248
+ }
1249
+ ),
1250
+ /* @__PURE__ */ jsx(YAxis, { tick: { fontSize: 12 }, tickLine: false, axisLine: false, width: 40 })
1251
+ ] }),
1252
+ /* @__PURE__ */ jsx(Tooltip$1, {}),
1253
+ showLegend && bars.length > 1 && /* @__PURE__ */ jsx(Legend, {}),
1254
+ bars.map((bar, barIndex) => /* @__PURE__ */ jsx(
1255
+ Bar,
1256
+ {
1257
+ dataKey: bar.key,
1258
+ name: bar.name || bar.key,
1259
+ fill: bar.color || DEFAULT_COLORS2[barIndex % DEFAULT_COLORS2.length],
1260
+ stackId: bar.stackId,
1261
+ radius: [radius, radius, 0, 0],
1262
+ label: showLabels ? { position: "top", fontSize: 10 } : false,
1263
+ children: categoryColors && chartData.map((_, index) => /* @__PURE__ */ jsx(Cell, { fill: categoryColors[index % categoryColors.length] }, `cell-${index}`))
1264
+ },
1265
+ bar.key
1266
+ ))
1267
+ ]
1268
+ }
1269
+ )
1270
+ }
1271
+ );
1272
+ }
1273
+ BarChart.displayName = "BarChart";
1274
+ var DEFAULT_COLORS3 = [
1275
+ "var(--brand-pink)",
1276
+ "var(--brand-yellow)",
1277
+ "var(--status-info)",
1278
+ "var(--status-success)",
1279
+ "var(--status-warning)",
1280
+ "var(--status-error)",
1281
+ "#8884d8",
1282
+ "#82ca9d"
1283
+ ];
1284
+ function PieChart({
1285
+ data,
1286
+ title,
1287
+ subtitle,
1288
+ height = 300,
1289
+ innerRadius = 0,
1290
+ outerRadius = 80,
1291
+ showLabels = true,
1292
+ labelType = "percent",
1293
+ legend: showLegend = true,
1294
+ minSampleSize = 30,
1295
+ className
1296
+ }) {
1297
+ const safeData = useMemo(() => data.map((item) => ({ ...item })), [data]);
1298
+ const renderLabel = (props) => {
1299
+ const { name, value, percent } = props;
1300
+ switch (labelType) {
1301
+ case "percent":
1302
+ return `${((percent ?? 0) * 100).toFixed(0)}%`;
1303
+ case "value":
1304
+ return (value ?? 0).toLocaleString();
1305
+ case "name":
1306
+ return name ?? "";
1307
+ default:
1308
+ return "";
1309
+ }
1310
+ };
1311
+ return /* @__PURE__ */ jsx(
1312
+ ChartContainer,
1313
+ {
1314
+ title,
1315
+ subtitle,
1316
+ height,
1317
+ data: safeData,
1318
+ requiredFields: ["name", "value"],
1319
+ minSampleSize,
1320
+ className,
1321
+ children: /* @__PURE__ */ jsxs(PieChart$1, { children: [
1322
+ /* @__PURE__ */ jsx(
1323
+ Pie,
1324
+ {
1325
+ data: safeData,
1326
+ cx: "50%",
1327
+ cy: "50%",
1328
+ innerRadius,
1329
+ outerRadius,
1330
+ paddingAngle: 2,
1331
+ dataKey: "value",
1332
+ label: showLabels ? renderLabel : void 0,
1333
+ labelLine: showLabels,
1334
+ children: safeData.map((entry, index) => /* @__PURE__ */ jsx(
1335
+ Cell,
1336
+ {
1337
+ fill: entry.color || DEFAULT_COLORS3[index % DEFAULT_COLORS3.length]
1338
+ },
1339
+ `cell-${index}`
1340
+ ))
1341
+ }
1342
+ ),
1343
+ /* @__PURE__ */ jsx(Tooltip$1, {}),
1344
+ showLegend && /* @__PURE__ */ jsx(Legend, {})
1345
+ ] })
1346
+ }
1347
+ );
1348
+ }
1349
+ PieChart.displayName = "PieChart";
1350
+ var DEFAULT_COLORS4 = [
1351
+ "var(--brand-pink)",
1352
+ "var(--brand-yellow)",
1353
+ "var(--status-info)",
1354
+ "var(--status-success)",
1355
+ "var(--status-warning)"
1356
+ ];
1357
+ function FunnelChart({
1358
+ stages,
1359
+ title,
1360
+ subtitle,
1361
+ showConversionRates = true,
1362
+ showDropOff = true,
1363
+ showValues = true,
1364
+ height = 300,
1365
+ className
1366
+ }) {
1367
+ const { features } = useReportMode();
1368
+ const isValid = stages.length >= 3;
1369
+ const maxValue = stages.length > 0 ? Math.max(...stages.map((s) => s.value)) : 0;
1370
+ const stagesWithMetrics = useMemo(() => {
1371
+ return stages.map((stage, index) => {
1372
+ const prevStage = index > 0 ? stages[index - 1] : null;
1373
+ const conversionRate = prevStage ? stage.value / prevStage.value * 100 : 100;
1374
+ const dropOff = prevStage ? (prevStage.value - stage.value) / prevStage.value * 100 : 0;
1375
+ const widthPercent = maxValue > 0 ? stage.value / maxValue * 100 : 0;
1376
+ return {
1377
+ ...stage,
1378
+ conversionRate,
1379
+ dropOff,
1380
+ widthPercent,
1381
+ color: stage.color || DEFAULT_COLORS4[index % DEFAULT_COLORS4.length]
1382
+ };
1383
+ });
1384
+ }, [stages, maxValue]);
1385
+ if (!isValid) {
1386
+ return /* @__PURE__ */ jsxs("div", { className: clsx11("ds-funnel-chart", "ds-funnel-chart--invalid", className), children: [
1387
+ title && /* @__PURE__ */ jsx("h4", { className: "ds-funnel-chart__title", children: title }),
1388
+ /* @__PURE__ */ jsx("div", { className: "ds-funnel-chart__empty", children: /* @__PURE__ */ jsx(
1389
+ DataStateIndicator,
1390
+ {
1391
+ state: "INSUFFICIENT_SAMPLE",
1392
+ variant: "full",
1393
+ details: {
1394
+ message: "Funnel requires at least 3 stages",
1395
+ sampleSize: stages.length,
1396
+ requiredSize: 3
1397
+ }
1398
+ }
1399
+ ) })
1400
+ ] });
1401
+ }
1402
+ const totalConversion = stages.length > 1 ? (stages[stages.length - 1].value / stages[0].value * 100).toFixed(1) : "100";
1403
+ return /* @__PURE__ */ jsxs("div", { className: clsx11("ds-funnel-chart", className), style: { minHeight: height }, children: [
1404
+ (title || subtitle) && /* @__PURE__ */ jsxs("header", { className: "ds-funnel-chart__header", children: [
1405
+ /* @__PURE__ */ jsxs("div", { children: [
1406
+ title && /* @__PURE__ */ jsx("h4", { className: "ds-funnel-chart__title", children: title }),
1407
+ subtitle && /* @__PURE__ */ jsx("p", { className: "ds-funnel-chart__subtitle", children: subtitle })
1408
+ ] }),
1409
+ features.showMethodology && /* @__PURE__ */ jsx(DataCoverageBadge, { sampleSize: stages[0].value, size: "sm" })
1410
+ ] }),
1411
+ /* @__PURE__ */ jsx("div", { className: "ds-funnel-chart__stages", children: stagesWithMetrics.map((stage, index) => /* @__PURE__ */ jsxs("div", { className: "ds-funnel-chart__stage", children: [
1412
+ /* @__PURE__ */ jsx("div", { className: "ds-funnel-chart__bar-container", children: /* @__PURE__ */ jsx(
1413
+ "div",
1414
+ {
1415
+ className: "ds-funnel-chart__bar",
1416
+ style: {
1417
+ width: `${stage.widthPercent}%`,
1418
+ backgroundColor: stage.color
1419
+ },
1420
+ children: showValues && /* @__PURE__ */ jsx("span", { className: "ds-funnel-chart__value", children: stage.value.toLocaleString() })
1421
+ }
1422
+ ) }),
1423
+ /* @__PURE__ */ jsxs("div", { className: "ds-funnel-chart__label", children: [
1424
+ /* @__PURE__ */ jsx("span", { className: "ds-funnel-chart__stage-name", children: stage.name }),
1425
+ showConversionRates && index > 0 && /* @__PURE__ */ jsxs("span", { className: "ds-funnel-chart__conversion", children: [
1426
+ stage.conversionRate.toFixed(1),
1427
+ "% converted"
1428
+ ] })
1429
+ ] }),
1430
+ showDropOff && index > 0 && stage.dropOff > 0 && /* @__PURE__ */ jsxs("div", { className: "ds-funnel-chart__dropoff", children: [
1431
+ /* @__PURE__ */ jsx("span", { className: "ds-funnel-chart__dropoff-arrow", children: "\u2193" }),
1432
+ /* @__PURE__ */ jsxs("span", { className: "ds-funnel-chart__dropoff-value", children: [
1433
+ "-",
1434
+ stage.dropOff.toFixed(1),
1435
+ "%"
1436
+ ] })
1437
+ ] })
1438
+ ] }, stage.name)) }),
1439
+ /* @__PURE__ */ jsx("footer", { className: "ds-funnel-chart__footer", children: /* @__PURE__ */ jsxs("span", { className: "ds-funnel-chart__total", children: [
1440
+ "Overall Conversion: ",
1441
+ /* @__PURE__ */ jsxs("strong", { children: [
1442
+ totalConversion,
1443
+ "%"
1444
+ ] })
1445
+ ] }) })
1446
+ ] });
1447
+ }
1448
+ FunnelChart.displayName = "FunnelChart";
1449
+ Tooltip.Provider;
1450
+ Tooltip.Root;
1451
+ Tooltip.Trigger;
1452
+ var TooltipContent = React2.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(Tooltip.Portal, { children: /* @__PURE__ */ jsx(Tooltip.Positioner, { sideOffset: 5, children: /* @__PURE__ */ jsxs(Tooltip.Popup, { ref, className: clsx11("ds-tooltip__content", className), ...props, children: [
1453
+ children,
1454
+ /* @__PURE__ */ jsx(Tooltip.Arrow, { className: "ds-tooltip__arrow" })
1455
+ ] }) }) }));
1456
+ TooltipContent.displayName = "TooltipContent";
1457
+ var Tooltip4 = ({ content, children, delay = 200 }) => {
1458
+ return /* @__PURE__ */ jsx(Tooltip.Provider, { delay, children: /* @__PURE__ */ jsxs(Tooltip.Root, { children: [
1459
+ /* @__PURE__ */ jsx(Tooltip.Trigger, { render: children }),
1460
+ /* @__PURE__ */ jsx(TooltipContent, { children: content })
1461
+ ] }) });
1462
+ };
1463
+ function HeatmapChart({
1464
+ data,
1465
+ title,
1466
+ subtitle,
1467
+ xLabel,
1468
+ yLabel,
1469
+ colorScale = ["var(--glass-elevated)", "var(--brand-pink)"],
1470
+ showValues = true,
1471
+ valueFormatter = (v) => v.toFixed(0),
1472
+ minCells = 25,
1473
+ className
1474
+ }) {
1475
+ const { features } = useReportMode();
1476
+ const { xValues, yValues, cellMap, minValue, maxValue } = useMemo(() => {
1477
+ const xSet = /* @__PURE__ */ new Set();
1478
+ const ySet = /* @__PURE__ */ new Set();
1479
+ const map = /* @__PURE__ */ new Map();
1480
+ let min = Infinity;
1481
+ let max = -Infinity;
1482
+ for (const cell of data) {
1483
+ xSet.add(cell.x);
1484
+ ySet.add(cell.y);
1485
+ map.set(`${cell.x}-${cell.y}`, cell.value);
1486
+ min = Math.min(min, cell.value);
1487
+ max = Math.max(max, cell.value);
1488
+ }
1489
+ return {
1490
+ xValues: Array.from(xSet),
1491
+ yValues: Array.from(ySet),
1492
+ cellMap: map,
1493
+ minValue: min === Infinity ? 0 : min,
1494
+ maxValue: max === -Infinity ? 0 : max
1495
+ };
1496
+ }, [data]);
1497
+ const isValid = data.length >= minCells;
1498
+ const getCellColor = (value) => {
1499
+ if (maxValue === minValue) return colorScale[0];
1500
+ const ratio = (value - minValue) / (maxValue - minValue);
1501
+ return `color-mix(in srgb, ${colorScale[1]} ${ratio * 100}%, ${colorScale[0]})`;
1502
+ };
1503
+ const getTextColor = (value) => {
1504
+ const ratio = (value - minValue) / (maxValue - minValue);
1505
+ return ratio > 0.5 ? "white" : "var(--text-primary)";
1506
+ };
1507
+ if (!isValid) {
1508
+ return /* @__PURE__ */ jsxs("div", { className: clsx11("ds-heatmap-chart", "ds-heatmap-chart--invalid", className), children: [
1509
+ title && /* @__PURE__ */ jsx("h4", { className: "ds-heatmap-chart__title", children: title }),
1510
+ /* @__PURE__ */ jsxs("div", { className: "ds-heatmap-chart__empty", children: [
1511
+ /* @__PURE__ */ jsx("p", { children: "Insufficient data for heatmap visualization" }),
1512
+ /* @__PURE__ */ jsxs("p", { className: "ds-heatmap-chart__empty-detail", children: [
1513
+ data.length,
1514
+ " cells provided, ",
1515
+ minCells,
1516
+ " required"
1517
+ ] })
1518
+ ] })
1519
+ ] });
1520
+ }
1521
+ return /* @__PURE__ */ jsxs("div", { className: clsx11("ds-heatmap-chart", className), children: [
1522
+ (title || subtitle) && /* @__PURE__ */ jsxs("header", { className: "ds-heatmap-chart__header", children: [
1523
+ /* @__PURE__ */ jsxs("div", { children: [
1524
+ title && /* @__PURE__ */ jsx("h4", { className: "ds-heatmap-chart__title", children: title }),
1525
+ subtitle && /* @__PURE__ */ jsx("p", { className: "ds-heatmap-chart__subtitle", children: subtitle })
1526
+ ] }),
1527
+ features.showMethodology && /* @__PURE__ */ jsx(DataCoverageBadge, { sampleSize: data.length, requiredSize: minCells, size: "sm" })
1528
+ ] }),
1529
+ /* @__PURE__ */ jsxs("div", { className: "ds-heatmap-chart__container", children: [
1530
+ yLabel && /* @__PURE__ */ jsx("div", { className: "ds-heatmap-chart__y-label", children: /* @__PURE__ */ jsx("span", { children: yLabel }) }),
1531
+ /* @__PURE__ */ jsxs("div", { className: "ds-heatmap-chart__grid-wrapper", children: [
1532
+ /* @__PURE__ */ jsx(
1533
+ "div",
1534
+ {
1535
+ className: "ds-heatmap-chart__grid",
1536
+ style: {
1537
+ gridTemplateColumns: `repeat(${xValues.length}, 1fr)`,
1538
+ gridTemplateRows: `repeat(${yValues.length}, 1fr)`
1539
+ },
1540
+ children: yValues.map(
1541
+ (y) => xValues.map((x) => {
1542
+ const value = cellMap.get(`${x}-${y}`) ?? 0;
1543
+ const cellContent = /* @__PURE__ */ jsx(
1544
+ "div",
1545
+ {
1546
+ className: "ds-heatmap-chart__cell",
1547
+ style: {
1548
+ backgroundColor: getCellColor(value),
1549
+ color: getTextColor(value)
1550
+ },
1551
+ children: showValues && /* @__PURE__ */ jsx("span", { className: "ds-heatmap-chart__cell-value", children: valueFormatter(value) })
1552
+ },
1553
+ `${x}-${y}`
1554
+ );
1555
+ return /* @__PURE__ */ jsx(Tooltip4, { content: `${x}, ${y}: ${valueFormatter(value)}`, children: cellContent }, `${x}-${y}`);
1556
+ })
1557
+ )
1558
+ }
1559
+ ),
1560
+ /* @__PURE__ */ jsx(
1561
+ "div",
1562
+ {
1563
+ className: "ds-heatmap-chart__x-labels",
1564
+ style: { gridTemplateColumns: `repeat(${xValues.length}, 1fr)` },
1565
+ children: xValues.map((x) => /* @__PURE__ */ jsx("span", { className: "ds-heatmap-chart__x-label", children: x }, x))
1566
+ }
1567
+ )
1568
+ ] }),
1569
+ /* @__PURE__ */ jsx(
1570
+ "div",
1571
+ {
1572
+ className: "ds-heatmap-chart__y-labels",
1573
+ style: { gridTemplateRows: `repeat(${yValues.length}, 1fr)` },
1574
+ children: yValues.map((y) => /* @__PURE__ */ jsx("span", { className: "ds-heatmap-chart__y-label-item", children: y }, y))
1575
+ }
1576
+ )
1577
+ ] }),
1578
+ xLabel && /* @__PURE__ */ jsx("div", { className: "ds-heatmap-chart__x-axis-label", children: /* @__PURE__ */ jsx("span", { children: xLabel }) }),
1579
+ /* @__PURE__ */ jsxs("div", { className: "ds-heatmap-chart__legend", children: [
1580
+ /* @__PURE__ */ jsx("span", { className: "ds-heatmap-chart__legend-label", children: "Low" }),
1581
+ /* @__PURE__ */ jsx(
1582
+ "div",
1583
+ {
1584
+ className: "ds-heatmap-chart__legend-bar",
1585
+ style: {
1586
+ background: `linear-gradient(to right, ${colorScale[0]}, ${colorScale[1]})`
1587
+ }
1588
+ }
1589
+ ),
1590
+ /* @__PURE__ */ jsx("span", { className: "ds-heatmap-chart__legend-label", children: "High" })
1591
+ ] })
1592
+ ] });
1593
+ }
1594
+ HeatmapChart.displayName = "HeatmapChart";
1595
+ function ChartSwitchControl({
1596
+ currentType,
1597
+ allowedTypes,
1598
+ onTypeChange,
1599
+ size = "sm",
1600
+ className
1601
+ }) {
1602
+ if (allowedTypes.length <= 1) {
1603
+ return null;
1604
+ }
1605
+ return /* @__PURE__ */ jsx("div", { className: clsx11("ds-chart-switch", `ds-chart-switch--${size}`, className), children: allowedTypes.map((type) => {
1606
+ const meta = CHART_REGISTRY[type];
1607
+ if (!meta) return null;
1608
+ const isActive = type === currentType;
1609
+ const Icon = getChartIcon(type);
1610
+ return /* @__PURE__ */ jsxs(
1611
+ "button",
1612
+ {
1613
+ type: "button",
1614
+ className: clsx11(
1615
+ "ds-chart-switch__option",
1616
+ isActive && "ds-chart-switch__option--active"
1617
+ ),
1618
+ onClick: () => onTypeChange(type),
1619
+ title: meta.name,
1620
+ "aria-pressed": isActive,
1621
+ children: [
1622
+ /* @__PURE__ */ jsx(Icon, {}),
1623
+ /* @__PURE__ */ jsx("span", { className: "ds-chart-switch__label", children: getShortLabel(type) })
1624
+ ]
1625
+ },
1626
+ type
1627
+ );
1628
+ }) });
1629
+ }
1630
+ ChartSwitchControl.displayName = "ChartSwitchControl";
1631
+ function getChartIcon(type) {
1632
+ const icons = {
1633
+ line: LineIcon,
1634
+ smooth_line: SmoothLineIcon,
1635
+ area: AreaIcon,
1636
+ stacked_area: StackedAreaIcon,
1637
+ area_100pct: StackedAreaIcon,
1638
+ bar: BarIcon,
1639
+ column: ColumnIcon,
1640
+ stacked_bar: StackedBarIcon,
1641
+ stacked_column: StackedColumnIcon,
1642
+ column_100pct: StackedColumnIcon,
1643
+ pie: PieIcon,
1644
+ donut: DonutIcon,
1645
+ histogram: HistogramIcon,
1646
+ funnel: FunnelIcon,
1647
+ heatmap: HeatmapIcon
1648
+ };
1649
+ return icons[type] || DefaultChartIcon;
1650
+ }
1651
+ function getShortLabel(type) {
1652
+ const labels = {
1653
+ line: "Line",
1654
+ smooth_line: "Smooth",
1655
+ area: "Area",
1656
+ stacked_area: "Stacked",
1657
+ area_100pct: "100%",
1658
+ bar: "Bar",
1659
+ column: "Column",
1660
+ stacked_bar: "Stacked",
1661
+ stacked_column: "Stacked",
1662
+ column_100pct: "100%",
1663
+ pie: "Pie",
1664
+ donut: "Donut",
1665
+ histogram: "Histogram",
1666
+ funnel: "Funnel",
1667
+ heatmap: "Heatmap"
1668
+ };
1669
+ return labels[type] || type;
1670
+ }
1671
+ function LineIcon() {
1672
+ return /* @__PURE__ */ jsx(
1673
+ "svg",
1674
+ {
1675
+ width: "16",
1676
+ height: "16",
1677
+ viewBox: "0 0 24 24",
1678
+ fill: "none",
1679
+ stroke: "currentColor",
1680
+ strokeWidth: "2",
1681
+ children: /* @__PURE__ */ jsx("polyline", { points: "22 12 18 8 13 13 9 9 2 16" })
1682
+ }
1683
+ );
1684
+ }
1685
+ function SmoothLineIcon() {
1686
+ return /* @__PURE__ */ jsx(
1687
+ "svg",
1688
+ {
1689
+ width: "16",
1690
+ height: "16",
1691
+ viewBox: "0 0 24 24",
1692
+ fill: "none",
1693
+ stroke: "currentColor",
1694
+ strokeWidth: "2",
1695
+ children: /* @__PURE__ */ jsx("path", { d: "M2 16 C6 16, 8 8, 12 12 S18 6, 22 10" })
1696
+ }
1697
+ );
1698
+ }
1699
+ function AreaIcon() {
1700
+ return /* @__PURE__ */ jsxs(
1701
+ "svg",
1702
+ {
1703
+ width: "16",
1704
+ height: "16",
1705
+ viewBox: "0 0 24 24",
1706
+ fill: "none",
1707
+ stroke: "currentColor",
1708
+ strokeWidth: "2",
1709
+ children: [
1710
+ /* @__PURE__ */ jsx("path", { d: "M2 20 L2 16 L8 10 L14 14 L22 6 L22 20 Z", fill: "currentColor", fillOpacity: "0.2" }),
1711
+ /* @__PURE__ */ jsx("polyline", { points: "2 16 8 10 14 14 22 6" })
1712
+ ]
1713
+ }
1714
+ );
1715
+ }
1716
+ function StackedAreaIcon() {
1717
+ return /* @__PURE__ */ jsxs(
1718
+ "svg",
1719
+ {
1720
+ width: "16",
1721
+ height: "16",
1722
+ viewBox: "0 0 24 24",
1723
+ fill: "none",
1724
+ stroke: "currentColor",
1725
+ strokeWidth: "2",
1726
+ children: [
1727
+ /* @__PURE__ */ jsx("path", { d: "M2 20 L2 14 L8 10 L14 12 L22 8 L22 20 Z", fill: "currentColor", fillOpacity: "0.3" }),
1728
+ /* @__PURE__ */ jsx("path", { d: "M2 20 L2 16 L8 14 L14 15 L22 12 L22 20 Z", fill: "currentColor", fillOpacity: "0.2" })
1729
+ ]
1730
+ }
1731
+ );
1732
+ }
1733
+ function BarIcon() {
1734
+ return /* @__PURE__ */ jsxs(
1735
+ "svg",
1736
+ {
1737
+ width: "16",
1738
+ height: "16",
1739
+ viewBox: "0 0 24 24",
1740
+ fill: "none",
1741
+ stroke: "currentColor",
1742
+ strokeWidth: "2",
1743
+ children: [
1744
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "4", width: "14", height: "4", rx: "1", fill: "currentColor", fillOpacity: "0.2" }),
1745
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "10", width: "18", height: "4", rx: "1", fill: "currentColor", fillOpacity: "0.2" }),
1746
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "16", width: "10", height: "4", rx: "1", fill: "currentColor", fillOpacity: "0.2" })
1747
+ ]
1748
+ }
1749
+ );
1750
+ }
1751
+ function ColumnIcon() {
1752
+ return /* @__PURE__ */ jsxs(
1753
+ "svg",
1754
+ {
1755
+ width: "16",
1756
+ height: "16",
1757
+ viewBox: "0 0 24 24",
1758
+ fill: "none",
1759
+ stroke: "currentColor",
1760
+ strokeWidth: "2",
1761
+ children: [
1762
+ /* @__PURE__ */ jsx("rect", { x: "4", y: "8", width: "4", height: "14", rx: "1", fill: "currentColor", fillOpacity: "0.2" }),
1763
+ /* @__PURE__ */ jsx("rect", { x: "10", y: "4", width: "4", height: "18", rx: "1", fill: "currentColor", fillOpacity: "0.2" }),
1764
+ /* @__PURE__ */ jsx("rect", { x: "16", y: "12", width: "4", height: "10", rx: "1", fill: "currentColor", fillOpacity: "0.2" })
1765
+ ]
1766
+ }
1767
+ );
1768
+ }
1769
+ function StackedBarIcon() {
1770
+ return /* @__PURE__ */ jsxs(
1771
+ "svg",
1772
+ {
1773
+ width: "16",
1774
+ height: "16",
1775
+ viewBox: "0 0 24 24",
1776
+ fill: "none",
1777
+ stroke: "currentColor",
1778
+ strokeWidth: "2",
1779
+ children: [
1780
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "4", width: "8", height: "4", rx: "1", fill: "currentColor", fillOpacity: "0.3" }),
1781
+ /* @__PURE__ */ jsx("rect", { x: "10", y: "4", width: "6", height: "4", rx: "1", fill: "currentColor", fillOpacity: "0.15" }),
1782
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "10", width: "12", height: "4", rx: "1", fill: "currentColor", fillOpacity: "0.3" }),
1783
+ /* @__PURE__ */ jsx("rect", { x: "14", y: "10", width: "6", height: "4", rx: "1", fill: "currentColor", fillOpacity: "0.15" }),
1784
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "16", width: "6", height: "4", rx: "1", fill: "currentColor", fillOpacity: "0.3" }),
1785
+ /* @__PURE__ */ jsx("rect", { x: "8", y: "16", width: "4", height: "4", rx: "1", fill: "currentColor", fillOpacity: "0.15" })
1786
+ ]
1787
+ }
1788
+ );
1789
+ }
1790
+ function StackedColumnIcon() {
1791
+ return /* @__PURE__ */ jsxs(
1792
+ "svg",
1793
+ {
1794
+ width: "16",
1795
+ height: "16",
1796
+ viewBox: "0 0 24 24",
1797
+ fill: "none",
1798
+ stroke: "currentColor",
1799
+ strokeWidth: "2",
1800
+ children: [
1801
+ /* @__PURE__ */ jsx("rect", { x: "4", y: "14", width: "4", height: "8", rx: "1", fill: "currentColor", fillOpacity: "0.3" }),
1802
+ /* @__PURE__ */ jsx("rect", { x: "4", y: "8", width: "4", height: "6", rx: "1", fill: "currentColor", fillOpacity: "0.15" }),
1803
+ /* @__PURE__ */ jsx("rect", { x: "10", y: "10", width: "4", height: "12", rx: "1", fill: "currentColor", fillOpacity: "0.3" }),
1804
+ /* @__PURE__ */ jsx("rect", { x: "10", y: "4", width: "4", height: "6", rx: "1", fill: "currentColor", fillOpacity: "0.15" }),
1805
+ /* @__PURE__ */ jsx("rect", { x: "16", y: "16", width: "4", height: "6", rx: "1", fill: "currentColor", fillOpacity: "0.3" }),
1806
+ /* @__PURE__ */ jsx("rect", { x: "16", y: "12", width: "4", height: "4", rx: "1", fill: "currentColor", fillOpacity: "0.15" })
1807
+ ]
1808
+ }
1809
+ );
1810
+ }
1811
+ function PieIcon() {
1812
+ return /* @__PURE__ */ jsxs(
1813
+ "svg",
1814
+ {
1815
+ width: "16",
1816
+ height: "16",
1817
+ viewBox: "0 0 24 24",
1818
+ fill: "none",
1819
+ stroke: "currentColor",
1820
+ strokeWidth: "2",
1821
+ children: [
1822
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", fill: "currentColor", fillOpacity: "0.2" }),
1823
+ /* @__PURE__ */ jsx("path", { d: "M12 2 A10 10 0 0 1 22 12 L12 12 Z", fill: "currentColor", fillOpacity: "0.3" })
1824
+ ]
1825
+ }
1826
+ );
1827
+ }
1828
+ function DonutIcon() {
1829
+ return /* @__PURE__ */ jsxs(
1830
+ "svg",
1831
+ {
1832
+ width: "16",
1833
+ height: "16",
1834
+ viewBox: "0 0 24 24",
1835
+ fill: "none",
1836
+ stroke: "currentColor",
1837
+ strokeWidth: "2",
1838
+ children: [
1839
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", fill: "currentColor", fillOpacity: "0.2" }),
1840
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "5", fill: "var(--glass-elevated)", stroke: "none" }),
1841
+ /* @__PURE__ */ jsx(
1842
+ "path",
1843
+ {
1844
+ d: "M12 2 A10 10 0 0 1 22 12 L17 12 A5 5 0 0 0 12 7 Z",
1845
+ fill: "currentColor",
1846
+ fillOpacity: "0.3"
1847
+ }
1848
+ )
1849
+ ]
1850
+ }
1851
+ );
1852
+ }
1853
+ function HistogramIcon() {
1854
+ return /* @__PURE__ */ jsxs(
1855
+ "svg",
1856
+ {
1857
+ width: "16",
1858
+ height: "16",
1859
+ viewBox: "0 0 24 24",
1860
+ fill: "none",
1861
+ stroke: "currentColor",
1862
+ strokeWidth: "2",
1863
+ children: [
1864
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "14", width: "4", height: "8", rx: "0", fill: "currentColor", fillOpacity: "0.2" }),
1865
+ /* @__PURE__ */ jsx("rect", { x: "6", y: "10", width: "4", height: "12", rx: "0", fill: "currentColor", fillOpacity: "0.2" }),
1866
+ /* @__PURE__ */ jsx("rect", { x: "10", y: "4", width: "4", height: "18", rx: "0", fill: "currentColor", fillOpacity: "0.2" }),
1867
+ /* @__PURE__ */ jsx("rect", { x: "14", y: "8", width: "4", height: "14", rx: "0", fill: "currentColor", fillOpacity: "0.2" }),
1868
+ /* @__PURE__ */ jsx("rect", { x: "18", y: "12", width: "4", height: "10", rx: "0", fill: "currentColor", fillOpacity: "0.2" })
1869
+ ]
1870
+ }
1871
+ );
1872
+ }
1873
+ function FunnelIcon() {
1874
+ return /* @__PURE__ */ jsxs(
1875
+ "svg",
1876
+ {
1877
+ width: "16",
1878
+ height: "16",
1879
+ viewBox: "0 0 24 24",
1880
+ fill: "none",
1881
+ stroke: "currentColor",
1882
+ strokeWidth: "2",
1883
+ children: [
1884
+ /* @__PURE__ */ jsx("path", { d: "M2 4 H22 L18 10 H6 Z", fill: "currentColor", fillOpacity: "0.3" }),
1885
+ /* @__PURE__ */ jsx("path", { d: "M6 10 H18 L15 16 H9 Z", fill: "currentColor", fillOpacity: "0.25" }),
1886
+ /* @__PURE__ */ jsx("path", { d: "M9 16 H15 L13 22 H11 Z", fill: "currentColor", fillOpacity: "0.2" })
1887
+ ]
1888
+ }
1889
+ );
1890
+ }
1891
+ function HeatmapIcon() {
1892
+ return /* @__PURE__ */ jsxs(
1893
+ "svg",
1894
+ {
1895
+ width: "16",
1896
+ height: "16",
1897
+ viewBox: "0 0 24 24",
1898
+ fill: "none",
1899
+ stroke: "currentColor",
1900
+ strokeWidth: "1",
1901
+ children: [
1902
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "2", width: "6", height: "6", fill: "currentColor", fillOpacity: "0.1" }),
1903
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "2", width: "6", height: "6", fill: "currentColor", fillOpacity: "0.3" }),
1904
+ /* @__PURE__ */ jsx("rect", { x: "16", y: "2", width: "6", height: "6", fill: "currentColor", fillOpacity: "0.2" }),
1905
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "9", width: "6", height: "6", fill: "currentColor", fillOpacity: "0.4" }),
1906
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "6", height: "6", fill: "currentColor", fillOpacity: "0.6" }),
1907
+ /* @__PURE__ */ jsx("rect", { x: "16", y: "9", width: "6", height: "6", fill: "currentColor", fillOpacity: "0.3" }),
1908
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "16", width: "6", height: "6", fill: "currentColor", fillOpacity: "0.2" }),
1909
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "16", width: "6", height: "6", fill: "currentColor", fillOpacity: "0.5" }),
1910
+ /* @__PURE__ */ jsx("rect", { x: "16", y: "16", width: "6", height: "6", fill: "currentColor", fillOpacity: "0.4" })
1911
+ ]
1912
+ }
1913
+ );
1914
+ }
1915
+ function DefaultChartIcon() {
1916
+ return /* @__PURE__ */ jsxs(
1917
+ "svg",
1918
+ {
1919
+ width: "16",
1920
+ height: "16",
1921
+ viewBox: "0 0 24 24",
1922
+ fill: "none",
1923
+ stroke: "currentColor",
1924
+ strokeWidth: "2",
1925
+ children: [
1926
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
1927
+ /* @__PURE__ */ jsx("path", { d: "M3 15 L9 9 L13 13 L21 5" })
1928
+ ]
1929
+ }
1930
+ );
1931
+ }
1932
+ var CHART_COLORS = [
1933
+ "var(--brand-pink)",
1934
+ "var(--brand-yellow)",
1935
+ "var(--status-info)",
1936
+ "var(--status-success)",
1937
+ "var(--status-warning)",
1938
+ "var(--status-error)"
1939
+ ];
1940
+ function getColor(index, customColor) {
1941
+ return customColor || CHART_COLORS[index % CHART_COLORS.length];
1942
+ }
1943
+ function Chart({
1944
+ intent,
1945
+ data,
1946
+ dimensions,
1947
+ measures,
1948
+ defaultType,
1949
+ allowedTypes,
1950
+ chartType: controlledType,
1951
+ onChartTypeChange,
1952
+ allowSwitching = false,
1953
+ title,
1954
+ subtitle,
1955
+ height = 300,
1956
+ legend: showLegend = true,
1957
+ grid = true,
1958
+ className
1959
+ }) {
1960
+ const { features } = useReportMode();
1961
+ const resolvedDefault = defaultType || getDefaultChartForIntent(intent);
1962
+ const [internalType, setInternalType] = useState(resolvedDefault);
1963
+ const activeType = controlledType ?? internalType;
1964
+ const resolvedAllowedTypes = useMemo(() => {
1965
+ if (allowedTypes) return allowedTypes;
1966
+ return getAllowedSwitchTargets(activeType);
1967
+ }, [allowedTypes, activeType]);
1968
+ const validation = useMemo(() => {
1969
+ return validateChartData(
1970
+ activeType,
1971
+ data,
1972
+ dimensions.map((d) => d.key),
1973
+ measures.map((m) => m.key)
1974
+ );
1975
+ }, [activeType, data, dimensions, measures]);
1976
+ const handleTypeChange = (newType) => {
1977
+ if (onChartTypeChange) {
1978
+ onChartTypeChange(newType);
1979
+ } else {
1980
+ setInternalType(newType);
1981
+ }
1982
+ };
1983
+ const chartMeta = CHART_REGISTRY[activeType];
1984
+ const renderChart = () => {
1985
+ if (!validation.isValid) {
1986
+ return /* @__PURE__ */ jsx("div", { className: "ds-chart__invalid", children: /* @__PURE__ */ jsx(
1987
+ DataStateIndicator,
1988
+ {
1989
+ state: "INSUFFICIENT_SAMPLE",
1990
+ variant: "full",
1991
+ details: {
1992
+ message: validation.errors[0],
1993
+ sampleSize: data.length,
1994
+ requiredSize: chartMeta?.contract.minDataPoints || 0
1995
+ }
1996
+ }
1997
+ ) });
1998
+ }
1999
+ const xKey = dimensions[0]?.key || "x";
2000
+ switch (activeType) {
2001
+ case "line":
2002
+ case "smooth_line":
2003
+ return renderLineChart(xKey, activeType === "smooth_line");
2004
+ case "area":
2005
+ case "stacked_area":
2006
+ case "area_100pct":
2007
+ return renderAreaChart(xKey, activeType);
2008
+ case "bar":
2009
+ case "stacked_bar":
2010
+ return renderBarChart(xKey, activeType, "horizontal");
2011
+ case "column":
2012
+ case "stacked_column":
2013
+ case "column_100pct":
2014
+ return renderBarChart(xKey, activeType, "vertical");
2015
+ case "pie":
2016
+ case "donut":
2017
+ return renderPieChart(xKey, activeType === "donut");
2018
+ case "histogram":
2019
+ return renderHistogram();
2020
+ default:
2021
+ return /* @__PURE__ */ jsxs("div", { className: "ds-chart__unsupported", children: [
2022
+ 'Chart type "',
2023
+ activeType,
2024
+ '" is not yet implemented'
2025
+ ] });
2026
+ }
2027
+ };
2028
+ const renderLineChart = (xKey, smooth) => /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height, children: /* @__PURE__ */ jsxs(LineChart$1, { data, margin: { top: 5, right: 20, left: 0, bottom: 5 }, children: [
2029
+ grid && /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", vertical: false }),
2030
+ /* @__PURE__ */ jsx(
2031
+ XAxis,
2032
+ {
2033
+ dataKey: xKey,
2034
+ tick: { fontSize: 12 },
2035
+ tickLine: false,
2036
+ axisLine: { strokeWidth: 1 }
2037
+ }
2038
+ ),
2039
+ /* @__PURE__ */ jsx(YAxis, { tick: { fontSize: 12 }, tickLine: false, axisLine: false, width: 40 }),
2040
+ /* @__PURE__ */ jsx(
2041
+ Tooltip$1,
2042
+ {
2043
+ contentStyle: {
2044
+ background: "var(--glass-elevated)",
2045
+ border: "1px solid var(--glass-border)"
2046
+ }
2047
+ }
2048
+ ),
2049
+ showLegend && measures.length > 1 && /* @__PURE__ */ jsx(Legend, {}),
2050
+ measures.map((measure, idx) => /* @__PURE__ */ jsx(
2051
+ Line,
2052
+ {
2053
+ type: smooth ? "monotone" : "linear",
2054
+ dataKey: measure.key,
2055
+ name: measure.label || measure.key,
2056
+ stroke: getColor(idx, measure.color),
2057
+ strokeWidth: 2,
2058
+ dot: true,
2059
+ activeDot: { r: 6 }
2060
+ },
2061
+ measure.key
2062
+ ))
2063
+ ] }) });
2064
+ const renderAreaChart = (xKey, type) => {
2065
+ const isStacked = type === "stacked_area" || type === "area_100pct";
2066
+ const is100Pct = type === "area_100pct";
2067
+ const chartData = is100Pct ? normalizeData(data, measures) : data;
2068
+ return /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height, children: /* @__PURE__ */ jsxs(AreaChart, { data: chartData, margin: { top: 5, right: 20, left: 0, bottom: 5 }, children: [
2069
+ grid && /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", vertical: false }),
2070
+ /* @__PURE__ */ jsx(
2071
+ XAxis,
2072
+ {
2073
+ dataKey: xKey,
2074
+ tick: { fontSize: 12 },
2075
+ tickLine: false,
2076
+ axisLine: { strokeWidth: 1 }
2077
+ }
2078
+ ),
2079
+ /* @__PURE__ */ jsx(
2080
+ YAxis,
2081
+ {
2082
+ tick: { fontSize: 12 },
2083
+ tickLine: false,
2084
+ axisLine: false,
2085
+ width: 40,
2086
+ domain: is100Pct ? [0, 100] : void 0,
2087
+ tickFormatter: is100Pct ? (v) => `${v}%` : void 0
2088
+ }
2089
+ ),
2090
+ /* @__PURE__ */ jsx(
2091
+ Tooltip$1,
2092
+ {
2093
+ contentStyle: {
2094
+ background: "var(--glass-elevated)",
2095
+ border: "1px solid var(--glass-border)"
2096
+ }
2097
+ }
2098
+ ),
2099
+ showLegend && /* @__PURE__ */ jsx(Legend, {}),
2100
+ measures.map((measure, idx) => /* @__PURE__ */ jsx(
2101
+ Area,
2102
+ {
2103
+ type: "monotone",
2104
+ dataKey: measure.key,
2105
+ name: measure.label || measure.key,
2106
+ stroke: getColor(idx, measure.color),
2107
+ fill: getColor(idx, measure.color),
2108
+ fillOpacity: 0.3,
2109
+ stackId: isStacked ? "stack" : void 0
2110
+ },
2111
+ measure.key
2112
+ ))
2113
+ ] }) });
2114
+ };
2115
+ const renderBarChart = (xKey, type, layout) => {
2116
+ const isStacked = type.includes("stacked") || type.includes("100pct");
2117
+ const is100Pct = type.includes("100pct");
2118
+ const isHorizontal = layout === "horizontal";
2119
+ const chartData = is100Pct ? normalizeData(data, measures) : data;
2120
+ return /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height, children: /* @__PURE__ */ jsxs(
2121
+ BarChart$1,
2122
+ {
2123
+ data: chartData,
2124
+ layout: isHorizontal ? "vertical" : "horizontal",
2125
+ margin: { top: 5, right: 20, left: isHorizontal ? 80 : 0, bottom: 5 },
2126
+ children: [
2127
+ grid && /* @__PURE__ */ jsx(
2128
+ CartesianGrid,
2129
+ {
2130
+ strokeDasharray: "3 3",
2131
+ horizontal: !isHorizontal,
2132
+ vertical: isHorizontal
2133
+ }
2134
+ ),
2135
+ isHorizontal ? /* @__PURE__ */ jsxs(Fragment, { children: [
2136
+ /* @__PURE__ */ jsx(
2137
+ XAxis,
2138
+ {
2139
+ type: "number",
2140
+ tick: { fontSize: 12 },
2141
+ tickLine: false,
2142
+ axisLine: false,
2143
+ domain: is100Pct ? [0, 100] : void 0,
2144
+ tickFormatter: is100Pct ? (v) => `${v}%` : void 0
2145
+ }
2146
+ ),
2147
+ /* @__PURE__ */ jsx(
2148
+ YAxis,
2149
+ {
2150
+ type: "category",
2151
+ dataKey: xKey,
2152
+ tick: { fontSize: 12 },
2153
+ tickLine: false,
2154
+ axisLine: false,
2155
+ width: 80
2156
+ }
2157
+ )
2158
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2159
+ /* @__PURE__ */ jsx(
2160
+ XAxis,
2161
+ {
2162
+ dataKey: xKey,
2163
+ tick: { fontSize: 12 },
2164
+ tickLine: false,
2165
+ axisLine: { strokeWidth: 1 }
2166
+ }
2167
+ ),
2168
+ /* @__PURE__ */ jsx(
2169
+ YAxis,
2170
+ {
2171
+ tick: { fontSize: 12 },
2172
+ tickLine: false,
2173
+ axisLine: false,
2174
+ width: 40,
2175
+ domain: is100Pct ? [0, 100] : void 0,
2176
+ tickFormatter: is100Pct ? (v) => `${v}%` : void 0
2177
+ }
2178
+ )
2179
+ ] }),
2180
+ /* @__PURE__ */ jsx(
2181
+ Tooltip$1,
2182
+ {
2183
+ contentStyle: {
2184
+ background: "var(--glass-elevated)",
2185
+ border: "1px solid var(--glass-border)"
2186
+ }
2187
+ }
2188
+ ),
2189
+ showLegend && measures.length > 1 && /* @__PURE__ */ jsx(Legend, {}),
2190
+ measures.map((measure, idx) => /* @__PURE__ */ jsx(
2191
+ Bar,
2192
+ {
2193
+ dataKey: measure.key,
2194
+ name: measure.label || measure.key,
2195
+ fill: getColor(idx, measure.color),
2196
+ stackId: isStacked ? "stack" : void 0,
2197
+ radius: isStacked ? void 0 : [4, 4, 0, 0]
2198
+ },
2199
+ measure.key
2200
+ ))
2201
+ ]
2202
+ }
2203
+ ) });
2204
+ };
2205
+ const renderPieChart = (nameKey, isDonut) => {
2206
+ const valueKey = measures[0]?.key || "value";
2207
+ return /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height, children: /* @__PURE__ */ jsxs(PieChart$1, { children: [
2208
+ /* @__PURE__ */ jsx(
2209
+ Pie,
2210
+ {
2211
+ data,
2212
+ dataKey: valueKey,
2213
+ nameKey,
2214
+ cx: "50%",
2215
+ cy: "50%",
2216
+ innerRadius: isDonut ? "50%" : 0,
2217
+ outerRadius: "80%",
2218
+ label: ({ name, percent }) => `${name}: ${((percent ?? 0) * 100).toFixed(0)}%`,
2219
+ labelLine: false,
2220
+ children: data.map((_, idx) => /* @__PURE__ */ jsx(Cell, { fill: getColor(idx) }, `cell-${idx}`))
2221
+ }
2222
+ ),
2223
+ /* @__PURE__ */ jsx(
2224
+ Tooltip$1,
2225
+ {
2226
+ contentStyle: {
2227
+ background: "var(--glass-elevated)",
2228
+ border: "1px solid var(--glass-border)"
2229
+ }
2230
+ }
2231
+ ),
2232
+ showLegend && /* @__PURE__ */ jsx(Legend, {})
2233
+ ] }) });
2234
+ };
2235
+ const renderHistogram = () => {
2236
+ const valueKey = measures[0]?.key || "value";
2237
+ const binKey = dimensions[0]?.key || "bin";
2238
+ return /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height, children: /* @__PURE__ */ jsxs(BarChart$1, { data, margin: { top: 5, right: 20, left: 0, bottom: 5 }, children: [
2239
+ grid && /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", vertical: false }),
2240
+ /* @__PURE__ */ jsx(
2241
+ XAxis,
2242
+ {
2243
+ dataKey: binKey,
2244
+ tick: { fontSize: 12 },
2245
+ tickLine: false,
2246
+ axisLine: { strokeWidth: 1 }
2247
+ }
2248
+ ),
2249
+ /* @__PURE__ */ jsx(YAxis, { tick: { fontSize: 12 }, tickLine: false, axisLine: false, width: 40 }),
2250
+ /* @__PURE__ */ jsx(
2251
+ Tooltip$1,
2252
+ {
2253
+ contentStyle: {
2254
+ background: "var(--glass-elevated)",
2255
+ border: "1px solid var(--glass-border)"
2256
+ }
2257
+ }
2258
+ ),
2259
+ /* @__PURE__ */ jsx(Bar, { dataKey: valueKey, fill: getColor(0), radius: [4, 4, 0, 0] })
2260
+ ] }) });
2261
+ };
2262
+ const normalizeData = (sourceData, sourceMeasures) => {
2263
+ return sourceData.map((row) => {
2264
+ const total = sourceMeasures.reduce((sum, m) => {
2265
+ const val = row[m.key];
2266
+ return sum + (typeof val === "number" ? val : 0);
2267
+ }, 0);
2268
+ if (total === 0) return row;
2269
+ const normalized = { ...row };
2270
+ sourceMeasures.forEach((m) => {
2271
+ const val = row[m.key];
2272
+ if (typeof val === "number") {
2273
+ normalized[m.key] = val / total * 100;
2274
+ }
2275
+ });
2276
+ return normalized;
2277
+ });
2278
+ };
2279
+ return /* @__PURE__ */ jsxs("div", { className: clsx11("ds-chart", className), children: [
2280
+ (title || subtitle || allowSwitching) && /* @__PURE__ */ jsxs("header", { className: "ds-chart__header", children: [
2281
+ /* @__PURE__ */ jsxs("div", { className: "ds-chart__header-text", children: [
2282
+ title && /* @__PURE__ */ jsx("h4", { className: "ds-chart__title", children: title }),
2283
+ subtitle && /* @__PURE__ */ jsx("p", { className: "ds-chart__subtitle", children: subtitle })
2284
+ ] }),
2285
+ /* @__PURE__ */ jsxs("div", { className: "ds-chart__header-actions", children: [
2286
+ features.showMethodology && data.length > 0 && /* @__PURE__ */ jsx(
2287
+ DataCoverageBadge,
2288
+ {
2289
+ sampleSize: data.length,
2290
+ requiredSize: chartMeta?.contract.minDataPoints || 0,
2291
+ size: "sm"
2292
+ }
2293
+ ),
2294
+ allowSwitching && resolvedAllowedTypes.length > 0 && /* @__PURE__ */ jsx(
2295
+ ChartSwitchControl,
2296
+ {
2297
+ currentType: activeType,
2298
+ allowedTypes: [activeType, ...resolvedAllowedTypes],
2299
+ onTypeChange: handleTypeChange
2300
+ }
2301
+ )
2302
+ ] })
2303
+ ] }),
2304
+ validation.warnings.length > 0 && /* @__PURE__ */ jsx("div", { className: "ds-chart__warnings", children: validation.warnings.map((warning, idx) => /* @__PURE__ */ jsx("div", { className: "ds-chart__warning", children: warning }, idx)) }),
2305
+ /* @__PURE__ */ jsx("div", { className: "ds-chart__body", style: { height }, children: renderChart() })
2306
+ ] });
2307
+ }
2308
+ Chart.displayName = "Chart";
2309
+ var ConfidenceIndicator = React2.forwardRef(
2310
+ ({ score, showScore = true, showLabel = true, size = "md", className, ...props }, ref) => {
2311
+ const threshold = getConfidenceThreshold(score);
2312
+ const normalizedScore = Math.max(0, Math.min(100, score));
2313
+ return /* @__PURE__ */ jsxs(
2314
+ "div",
2315
+ {
2316
+ ref,
2317
+ className: clsx11(
2318
+ "ds-confidence-indicator",
2319
+ `ds-confidence-indicator--${size}`,
2320
+ `ds-confidence-indicator--${threshold.level}`,
2321
+ className
2322
+ ),
2323
+ role: "meter",
2324
+ "aria-valuenow": normalizedScore,
2325
+ "aria-valuemin": 0,
2326
+ "aria-valuemax": 100,
2327
+ "aria-label": `Confidence: ${threshold.label} (${normalizedScore}%)`,
2328
+ ...props,
2329
+ children: [
2330
+ /* @__PURE__ */ jsx("div", { className: "ds-confidence-indicator__bar", children: /* @__PURE__ */ jsx("div", { className: "ds-confidence-indicator__fill", style: { width: `${normalizedScore}%` } }) }),
2331
+ /* @__PURE__ */ jsxs("div", { className: "ds-confidence-indicator__text", children: [
2332
+ showScore && /* @__PURE__ */ jsxs("span", { className: "ds-confidence-indicator__score", children: [
2333
+ normalizedScore,
2334
+ "%"
2335
+ ] }),
2336
+ showLabel && /* @__PURE__ */ jsx("span", { className: "ds-confidence-indicator__label", children: threshold.label })
2337
+ ] })
2338
+ ]
2339
+ }
2340
+ );
2341
+ }
2342
+ );
2343
+ ConfidenceIndicator.displayName = "ConfidenceIndicator";
2344
+ var DIMENSION_LABELS = {
2345
+ EI: { left: "Extraversion", right: "Introversion", full: "E/I" },
2346
+ SN: { left: "Sensing", right: "Intuition", full: "S/N" },
2347
+ TF: { left: "Thinking", right: "Feeling", full: "T/F" },
2348
+ JP: { left: "Judging", right: "Perceiving", full: "J/P" }
2349
+ };
2350
+ function MBTIRadar({
2351
+ dimensions,
2352
+ sampleSize,
2353
+ comparison,
2354
+ title,
2355
+ subtitle,
2356
+ size = 300,
2357
+ showLabels = true,
2358
+ showValues = true,
2359
+ minSampleSize = 20,
2360
+ confidence,
2361
+ className
2362
+ }) {
2363
+ const { features } = useReportMode();
2364
+ const isValid = sampleSize >= minSampleSize;
2365
+ const radarData = useMemo(() => {
2366
+ return Object.keys(dimensions).map((key) => ({
2367
+ dimension: DIMENSION_LABELS[key].full,
2368
+ fullName: `${DIMENSION_LABELS[key].left} vs ${DIMENSION_LABELS[key].right}`,
2369
+ value: dimensions[key],
2370
+ comparison: comparison?.[key],
2371
+ leftLabel: DIMENSION_LABELS[key].left,
2372
+ rightLabel: DIMENSION_LABELS[key].right
2373
+ }));
2374
+ }, [dimensions, comparison]);
2375
+ const derivedType = useMemo(() => {
2376
+ const e = dimensions.EI < 50 ? "E" : "I";
2377
+ const s = dimensions.SN < 50 ? "S" : "N";
2378
+ const t = dimensions.TF < 50 ? "T" : "F";
2379
+ const j = dimensions.JP < 50 ? "J" : "P";
2380
+ return `${e}${s}${t}${j}`;
2381
+ }, [dimensions]);
2382
+ if (!isValid) {
2383
+ return /* @__PURE__ */ jsxs("div", { className: clsx11("ds-mbti-radar", "ds-mbti-radar--invalid", className), children: [
2384
+ title && /* @__PURE__ */ jsx("h4", { className: "ds-mbti-radar__title", children: title }),
2385
+ /* @__PURE__ */ jsx("div", { className: "ds-mbti-radar__empty", children: /* @__PURE__ */ jsx(
2386
+ DataStateIndicator,
2387
+ {
2388
+ state: "INSUFFICIENT_SAMPLE",
2389
+ variant: "full",
2390
+ details: {
2391
+ message: "MBTI analysis requires sufficient sample size",
2392
+ sampleSize,
2393
+ requiredSize: minSampleSize
2394
+ }
2395
+ }
2396
+ ) })
2397
+ ] });
2398
+ }
2399
+ const CustomTooltip = ({
2400
+ active,
2401
+ payload
2402
+ }) => {
2403
+ if (!active || !payload?.length) return null;
2404
+ const data = payload[0].payload;
2405
+ return /* @__PURE__ */ jsxs("div", { className: "ds-mbti-radar__tooltip", children: [
2406
+ /* @__PURE__ */ jsx("p", { className: "ds-mbti-radar__tooltip-title", children: data.fullName }),
2407
+ /* @__PURE__ */ jsxs("p", { className: "ds-mbti-radar__tooltip-value", children: [
2408
+ data.leftLabel,
2409
+ ": ",
2410
+ 100 - data.value,
2411
+ "%"
2412
+ ] }),
2413
+ /* @__PURE__ */ jsxs("p", { className: "ds-mbti-radar__tooltip-value", children: [
2414
+ data.rightLabel,
2415
+ ": ",
2416
+ data.value,
2417
+ "%"
2418
+ ] }),
2419
+ data.comparison !== void 0 && /* @__PURE__ */ jsxs("p", { className: "ds-mbti-radar__tooltip-comparison", children: [
2420
+ "Benchmark: ",
2421
+ data.comparison,
2422
+ "%"
2423
+ ] })
2424
+ ] });
2425
+ };
2426
+ return /* @__PURE__ */ jsxs("div", { className: clsx11("ds-mbti-radar", className), children: [
2427
+ (title || subtitle) && /* @__PURE__ */ jsxs("header", { className: "ds-mbti-radar__header", children: [
2428
+ /* @__PURE__ */ jsxs("div", { className: "ds-mbti-radar__header-text", children: [
2429
+ title && /* @__PURE__ */ jsx("h4", { className: "ds-mbti-radar__title", children: title }),
2430
+ subtitle && /* @__PURE__ */ jsx("p", { className: "ds-mbti-radar__subtitle", children: subtitle })
2431
+ ] }),
2432
+ /* @__PURE__ */ jsxs("div", { className: "ds-mbti-radar__header-badges", children: [
2433
+ features.showConfidenceScores && confidence !== void 0 && /* @__PURE__ */ jsx(ConfidenceIndicator, { score: confidence, size: "sm" }),
2434
+ features.showMethodology && /* @__PURE__ */ jsx(DataCoverageBadge, { sampleSize, requiredSize: minSampleSize, size: "sm" })
2435
+ ] })
2436
+ ] }),
2437
+ /* @__PURE__ */ jsxs("div", { className: "ds-mbti-radar__type-badge", children: [
2438
+ /* @__PURE__ */ jsx("span", { className: "ds-mbti-radar__type-label", children: "Derived Type" }),
2439
+ /* @__PURE__ */ jsx("span", { className: "ds-mbti-radar__type-value", children: derivedType })
2440
+ ] }),
2441
+ /* @__PURE__ */ jsx("div", { className: "ds-mbti-radar__chart", style: { width: size, height: size }, children: /* @__PURE__ */ jsxs(RadarChart, { cx: "50%", cy: "50%", outerRadius: "70%", width: size, height: size, data: radarData, children: [
2442
+ /* @__PURE__ */ jsx(PolarGrid, { stroke: "var(--glass-border)" }),
2443
+ /* @__PURE__ */ jsx(
2444
+ PolarAngleAxis,
2445
+ {
2446
+ dataKey: "dimension",
2447
+ tick: { fill: "var(--text-secondary)", fontSize: 12 }
2448
+ }
2449
+ ),
2450
+ /* @__PURE__ */ jsx(
2451
+ PolarRadiusAxis,
2452
+ {
2453
+ angle: 45,
2454
+ domain: [0, 100],
2455
+ tick: { fill: "var(--text-tertiary)", fontSize: 10 },
2456
+ tickCount: 5
2457
+ }
2458
+ ),
2459
+ /* @__PURE__ */ jsx(
2460
+ Radar,
2461
+ {
2462
+ name: "Profile",
2463
+ dataKey: "value",
2464
+ stroke: "var(--brand-pink)",
2465
+ fill: "var(--brand-pink)",
2466
+ fillOpacity: 0.3,
2467
+ strokeWidth: 2
2468
+ }
2469
+ ),
2470
+ comparison && /* @__PURE__ */ jsx(
2471
+ Radar,
2472
+ {
2473
+ name: "Benchmark",
2474
+ dataKey: "comparison",
2475
+ stroke: "var(--brand-yellow)",
2476
+ fill: "var(--brand-yellow)",
2477
+ fillOpacity: 0.1,
2478
+ strokeWidth: 2,
2479
+ strokeDasharray: "5 5"
2480
+ }
2481
+ ),
2482
+ showValues && /* @__PURE__ */ jsx(Tooltip$1, { content: /* @__PURE__ */ jsx(CustomTooltip, {}) }),
2483
+ comparison && /* @__PURE__ */ jsx(Legend, {})
2484
+ ] }) }),
2485
+ showLabels && /* @__PURE__ */ jsx("div", { className: "ds-mbti-radar__dimensions", children: radarData.map((d) => /* @__PURE__ */ jsxs("div", { className: "ds-mbti-radar__dimension", children: [
2486
+ /* @__PURE__ */ jsx("span", { className: "ds-mbti-radar__dimension-left", children: d.leftLabel }),
2487
+ /* @__PURE__ */ jsxs("div", { className: "ds-mbti-radar__dimension-bar", children: [
2488
+ /* @__PURE__ */ jsx("div", { className: "ds-mbti-radar__dimension-fill", style: { width: `${d.value}%` } }),
2489
+ /* @__PURE__ */ jsx("div", { className: "ds-mbti-radar__dimension-marker", style: { left: `${d.value}%` } })
2490
+ ] }),
2491
+ /* @__PURE__ */ jsx("span", { className: "ds-mbti-radar__dimension-right", children: d.rightLabel })
2492
+ ] }, d.dimension)) })
2493
+ ] });
2494
+ }
2495
+ MBTIRadar.displayName = "MBTIRadar";
2496
+ var MBTI_GRID = [
2497
+ ["ISTJ", "ISFJ", "INFJ", "INTJ"],
2498
+ ["ISTP", "ISFP", "INFP", "INTP"],
2499
+ ["ESTP", "ESFP", "ENFP", "ENTP"],
2500
+ ["ESTJ", "ESFJ", "ENFJ", "ENTJ"]
2501
+ ];
2502
+ var TYPE_DESCRIPTIONS = {
2503
+ ISTJ: "The Inspector - Practical, reliable, systematic",
2504
+ ISFJ: "The Protector - Caring, supportive, traditional",
2505
+ INFJ: "The Advocate - Insightful, principled, compassionate",
2506
+ INTJ: "The Architect - Strategic, independent, determined",
2507
+ ISTP: "The Virtuoso - Observant, practical, analytical",
2508
+ ISFP: "The Adventurer - Artistic, sensitive, exploratory",
2509
+ INFP: "The Mediator - Idealistic, empathetic, creative",
2510
+ INTP: "The Logician - Inventive, logical, objective",
2511
+ ESTP: "The Entrepreneur - Energetic, pragmatic, observant",
2512
+ ESFP: "The Entertainer - Spontaneous, energetic, friendly",
2513
+ ENFP: "The Campaigner - Enthusiastic, creative, sociable",
2514
+ ENTP: "The Debater - Clever, curious, innovative",
2515
+ ESTJ: "The Executive - Organized, logical, assertive",
2516
+ ESFJ: "The Consul - Caring, sociable, traditional",
2517
+ ENFJ: "The Protagonist - Charismatic, empathetic, organized",
2518
+ ENTJ: "The Commander - Strategic, efficient, energetic"
2519
+ };
2520
+ var COLUMN_LABELS = ["ST", "SF", "NF", "NT"];
2521
+ var ROW_LABELS = ["I-J", "I-P", "E-P", "E-J"];
2522
+ function MBTITypeGrid({
2523
+ data,
2524
+ sampleSize: propSampleSize,
2525
+ title,
2526
+ subtitle,
2527
+ showPercentages = true,
2528
+ showCounts = true,
2529
+ highlightThreshold,
2530
+ minSampleSize = 50,
2531
+ confidence,
2532
+ onTypeClick,
2533
+ selectedType,
2534
+ className
2535
+ }) {
2536
+ const { features } = useReportMode();
2537
+ const typeMap = useMemo(() => {
2538
+ const map = /* @__PURE__ */ new Map();
2539
+ for (const item of data) {
2540
+ map.set(item.type, item);
2541
+ }
2542
+ return map;
2543
+ }, [data]);
2544
+ const totalSampleSize = propSampleSize ?? data.reduce((sum, d) => sum + d.count, 0);
2545
+ const isValid = totalSampleSize >= minSampleSize;
2546
+ const maxCount = useMemo(() => Math.max(...data.map((d) => d.count), 1), [data]);
2547
+ const getPercentage = (count) => {
2548
+ return totalSampleSize > 0 ? (count / totalSampleSize * 100).toFixed(1) : "0.0";
2549
+ };
2550
+ const getIntensity = (count) => {
2551
+ if (maxCount === 0) return 0;
2552
+ return count / maxCount * 100;
2553
+ };
2554
+ const isHighlighted = (type) => {
2555
+ if (!highlightThreshold) return false;
2556
+ const item = typeMap.get(type);
2557
+ if (!item) return false;
2558
+ const percentage = item.count / totalSampleSize * 100;
2559
+ return percentage >= highlightThreshold;
2560
+ };
2561
+ if (!isValid) {
2562
+ return /* @__PURE__ */ jsxs("div", { className: clsx11("ds-mbti-type-grid", "ds-mbti-type-grid--invalid", className), children: [
2563
+ title && /* @__PURE__ */ jsx("h4", { className: "ds-mbti-type-grid__title", children: title }),
2564
+ /* @__PURE__ */ jsx("div", { className: "ds-mbti-type-grid__empty", children: /* @__PURE__ */ jsx(
2565
+ DataStateIndicator,
2566
+ {
2567
+ state: "INSUFFICIENT_SAMPLE",
2568
+ variant: "full",
2569
+ details: {
2570
+ message: "MBTI distribution analysis requires sufficient sample size",
2571
+ sampleSize: totalSampleSize,
2572
+ requiredSize: minSampleSize
2573
+ }
2574
+ }
2575
+ ) })
2576
+ ] });
2577
+ }
2578
+ return /* @__PURE__ */ jsxs("div", { className: clsx11("ds-mbti-type-grid", className), children: [
2579
+ (title || subtitle) && /* @__PURE__ */ jsxs("header", { className: "ds-mbti-type-grid__header", children: [
2580
+ /* @__PURE__ */ jsxs("div", { className: "ds-mbti-type-grid__header-text", children: [
2581
+ title && /* @__PURE__ */ jsx("h4", { className: "ds-mbti-type-grid__title", children: title }),
2582
+ subtitle && /* @__PURE__ */ jsx("p", { className: "ds-mbti-type-grid__subtitle", children: subtitle })
2583
+ ] }),
2584
+ /* @__PURE__ */ jsxs("div", { className: "ds-mbti-type-grid__header-badges", children: [
2585
+ features.showConfidenceScores && confidence !== void 0 && /* @__PURE__ */ jsx(ConfidenceIndicator, { score: confidence, size: "sm" }),
2586
+ features.showMethodology && /* @__PURE__ */ jsx(
2587
+ DataCoverageBadge,
2588
+ {
2589
+ sampleSize: totalSampleSize,
2590
+ requiredSize: minSampleSize,
2591
+ size: "sm"
2592
+ }
2593
+ )
2594
+ ] })
2595
+ ] }),
2596
+ /* @__PURE__ */ jsxs("div", { className: "ds-mbti-type-grid__container", children: [
2597
+ /* @__PURE__ */ jsxs("div", { className: "ds-mbti-type-grid__column-headers", children: [
2598
+ /* @__PURE__ */ jsx("div", { className: "ds-mbti-type-grid__corner" }),
2599
+ COLUMN_LABELS.map((label) => /* @__PURE__ */ jsx("div", { className: "ds-mbti-type-grid__column-header", children: label }, label))
2600
+ ] }),
2601
+ MBTI_GRID.map((row, rowIndex) => /* @__PURE__ */ jsxs("div", { className: "ds-mbti-type-grid__row", children: [
2602
+ /* @__PURE__ */ jsx("div", { className: "ds-mbti-type-grid__row-header", children: ROW_LABELS[rowIndex] }),
2603
+ row.map((type) => {
2604
+ const typeData = typeMap.get(type);
2605
+ const count = typeData?.count ?? 0;
2606
+ const percentage = getPercentage(count);
2607
+ const intensity = getIntensity(count);
2608
+ const highlighted = isHighlighted(type);
2609
+ const selected = selectedType === type;
2610
+ return /* @__PURE__ */ jsx(
2611
+ Tooltip4,
2612
+ {
2613
+ content: /* @__PURE__ */ jsxs("div", { className: "ds-mbti-type-grid__tooltip-content", children: [
2614
+ /* @__PURE__ */ jsx("strong", { children: type }),
2615
+ /* @__PURE__ */ jsx("p", { children: TYPE_DESCRIPTIONS[type] }),
2616
+ /* @__PURE__ */ jsxs("p", { children: [
2617
+ "Count: ",
2618
+ count.toLocaleString()
2619
+ ] }),
2620
+ /* @__PURE__ */ jsxs("p", { children: [
2621
+ "Percentage: ",
2622
+ percentage,
2623
+ "%"
2624
+ ] }),
2625
+ typeData?.responseRate !== void 0 && /* @__PURE__ */ jsxs("p", { children: [
2626
+ "Response Rate: ",
2627
+ typeData.responseRate.toFixed(1),
2628
+ "%"
2629
+ ] })
2630
+ ] }),
2631
+ children: /* @__PURE__ */ jsxs(
2632
+ "button",
2633
+ {
2634
+ type: "button",
2635
+ className: clsx11(
2636
+ "ds-mbti-type-grid__cell",
2637
+ highlighted && "ds-mbti-type-grid__cell--highlighted",
2638
+ selected && "ds-mbti-type-grid__cell--selected",
2639
+ onTypeClick && "ds-mbti-type-grid__cell--clickable"
2640
+ ),
2641
+ onClick: () => onTypeClick?.(type),
2642
+ disabled: !onTypeClick,
2643
+ style: {
2644
+ "--cell-intensity": `${intensity}%`
2645
+ },
2646
+ children: [
2647
+ /* @__PURE__ */ jsx("span", { className: "ds-mbti-type-grid__cell-type", children: type }),
2648
+ showCounts && /* @__PURE__ */ jsx("span", { className: "ds-mbti-type-grid__cell-count", children: count.toLocaleString() }),
2649
+ showPercentages && /* @__PURE__ */ jsxs("span", { className: "ds-mbti-type-grid__cell-percentage", children: [
2650
+ percentage,
2651
+ "%"
2652
+ ] })
2653
+ ]
2654
+ }
2655
+ )
2656
+ },
2657
+ type
2658
+ );
2659
+ })
2660
+ ] }, rowIndex))
2661
+ ] }),
2662
+ /* @__PURE__ */ jsxs("div", { className: "ds-mbti-type-grid__legend", children: [
2663
+ /* @__PURE__ */ jsxs("div", { className: "ds-mbti-type-grid__legend-item", children: [
2664
+ /* @__PURE__ */ jsx("span", { className: "ds-mbti-type-grid__legend-bar ds-mbti-type-grid__legend-bar--gradient" }),
2665
+ /* @__PURE__ */ jsx("span", { className: "ds-mbti-type-grid__legend-label", children: "Distribution density" })
2666
+ ] }),
2667
+ highlightThreshold && /* @__PURE__ */ jsxs("div", { className: "ds-mbti-type-grid__legend-item", children: [
2668
+ /* @__PURE__ */ jsx("span", { className: "ds-mbti-type-grid__legend-bar ds-mbti-type-grid__legend-bar--highlight" }),
2669
+ /* @__PURE__ */ jsxs("span", { className: "ds-mbti-type-grid__legend-label", children: [
2670
+ ">=",
2671
+ highlightThreshold,
2672
+ "% of sample"
2673
+ ] })
2674
+ ] })
2675
+ ] })
2676
+ ] });
2677
+ }
2678
+ MBTITypeGrid.displayName = "MBTITypeGrid";
2679
+
2680
+ export { BarChart, Chart, ChartContainer, ChartSwitchControl, FunnelChart, HeatmapChart, LineChart, MBTIRadar, MBTITypeGrid, PieChart };
2681
+ //# sourceMappingURL=out.js.map
2682
+ //# sourceMappingURL=index.js.map