@salesmind-ai/design-system 0.3.1 → 0.3.2

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