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