@salesmind-ai/design-system 0.3.1 → 0.3.3

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 +11 -1
@@ -1,2365 +1,5 @@
1
- import React2, { createContext, useMemo, useContext } from 'react';
2
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
- import clsx12 from 'clsx';
4
- import { Select as Select$1 } from '@base-ui/react/select';
5
- import { Menu } from '@base-ui/react/menu';
6
-
7
- // src/report-engine/constants.ts
8
- var EXECUTIVE_MODE = {
9
- mode: "executive",
10
- features: {
11
- showMethodology: false,
12
- showConfidenceScores: false,
13
- showRawData: false,
14
- showStatisticalTests: false,
15
- chartDetailLevel: "summary",
16
- maxInsightsShown: 5,
17
- allowDrilldown: false
18
- }
19
- };
20
- var ANALYST_MODE = {
21
- mode: "analyst",
22
- features: {
23
- showMethodology: true,
24
- showConfidenceScores: true,
25
- showRawData: true,
26
- showStatisticalTests: true,
27
- chartDetailLevel: "detailed",
28
- maxInsightsShown: 20,
29
- allowDrilldown: true
30
- }
31
- };
32
- var CONFIDENCE_THRESHOLDS = [
33
- { level: "high", min: 90, max: 100, label: "High Confidence", color: "var(--status-success)" },
34
- {
35
- level: "moderate",
36
- min: 70,
37
- max: 89,
38
- label: "Moderate Confidence",
39
- color: "var(--status-info)"
40
- },
41
- { level: "low", min: 50, max: 69, label: "Low Confidence", color: "var(--status-warning)" },
42
- {
43
- level: "insufficient",
44
- min: 0,
45
- max: 49,
46
- label: "Insufficient Data",
47
- color: "var(--status-error)"
48
- }
49
- ];
50
- var MINIMUM_SAMPLE_SIZES = {
51
- overall: 30,
52
- segment: 30,
53
- mbtiType: 50,
54
- correlation: 100,
55
- timeSeries: 7
56
- };
57
- var INSIGHT_TYPE_CONTRACTS = {
58
- "performance-delta": {
59
- type: "performance-delta",
60
- allowedCharts: ["BarChart", "LineChart", "KeyMetric"],
61
- requiredFields: ["metric_name", "current_value", "previous_value", "time_period"],
62
- minSampleSize: 30,
63
- headlinePattern: "{metric} {direction} by {delta}% {timeframe}",
64
- recommendationFormats: ["maintain-strategy", "investigate-decline", "scale-success"]
65
- },
66
- "behavioral-correlation": {
67
- type: "behavioral-correlation",
68
- allowedCharts: ["HeatmapChart", "BarChart"],
69
- requiredFields: ["variable_a", "variable_b", "correlation_coefficient"],
70
- minSampleSize: 100,
71
- headlinePattern: "{variable_a} correlates with {variable_b}",
72
- recommendationFormats: ["leverage-correlation", "investigate-causation"]
73
- },
74
- "funnel-leakage": {
75
- type: "funnel-leakage",
76
- allowedCharts: ["FunnelChart", "BarChart"],
77
- requiredFields: ["stages", "stage_counts", "drop_rates"],
78
- minSampleSize: 50,
79
- headlinePattern: "{drop_rate}% drop-off at {stage}",
80
- recommendationFormats: ["optimize-stage", "remove-friction"]
81
- },
82
- "audience-mismatch": {
83
- type: "audience-mismatch",
84
- allowedCharts: ["BarChart", "PieChart"],
85
- requiredFields: ["target_audience", "actual_audience", "overlap_percentage"],
86
- minSampleSize: 50,
87
- headlinePattern: "Target audience differs by {mismatch}%",
88
- recommendationFormats: ["refine-targeting", "expand-audience"]
89
- },
90
- "message-fatigue": {
91
- type: "message-fatigue",
92
- allowedCharts: ["LineChart", "BarChart"],
93
- requiredFields: ["message_sequence", "engagement_rates", "fatigue_point"],
94
- minSampleSize: 100,
95
- headlinePattern: "Engagement drops {drop}% after message {n}",
96
- recommendationFormats: ["reduce-frequency", "vary-content"]
97
- },
98
- "psychological-resonance": {
99
- type: "psychological-resonance",
100
- allowedCharts: ["MBTIRadar", "MBTITypeGrid", "BarChart"],
101
- requiredFields: ["mbti_types", "response_rates", "message_type"],
102
- minSampleSize: 50,
103
- headlinePattern: "{mbti_type} responds {rate}% better to {message_type}",
104
- recommendationFormats: ["personalize-messaging", "segment-by-type"]
105
- },
106
- "timing-pattern": {
107
- type: "timing-pattern",
108
- allowedCharts: ["HeatmapChart", "LineChart"],
109
- requiredFields: ["time_slots", "engagement_rates"],
110
- minSampleSize: 100,
111
- headlinePattern: "Best engagement on {day} at {time}",
112
- recommendationFormats: ["optimize-timing", "schedule-sends"]
113
- },
114
- "segment-outperformance": {
115
- type: "segment-outperformance",
116
- allowedCharts: ["BarChart", "KeyMetric"],
117
- requiredFields: ["segments", "performance_metrics", "baseline"],
118
- minSampleSize: 30,
119
- headlinePattern: "{segment} outperforms by {delta}%",
120
- recommendationFormats: ["double-down", "investigate-success"]
121
- },
122
- "anomaly-detection": {
123
- type: "anomaly-detection",
124
- allowedCharts: ["LineChart", "BarChart"],
125
- requiredFields: ["metric", "expected_value", "actual_value", "deviation"],
126
- minSampleSize: 30,
127
- headlinePattern: "Unusual {direction} in {metric}",
128
- recommendationFormats: ["investigate", "monitor"]
129
- },
130
- "competitive-benchmark": {
131
- type: "competitive-benchmark",
132
- allowedCharts: ["BarChart", "KeyMetric"],
133
- requiredFields: ["metric", "our_value", "benchmark_value"],
134
- minSampleSize: 30,
135
- headlinePattern: "{position} industry benchmark by {delta}%",
136
- recommendationFormats: ["maintain-lead", "close-gap"]
137
- }
138
- };
139
- var ANALYTICAL_STATE_CONFIG = {
140
- VALID: {
141
- label: "Valid",
142
- icon: "check",
143
- color: "var(--status-success)",
144
- action: null
145
- },
146
- INSUFFICIENT_SAMPLE: {
147
- label: "Insufficient Sample",
148
- icon: "alert-triangle",
149
- color: "var(--status-warning)",
150
- action: "Add more data"
151
- },
152
- LOW_CONFIDENCE: {
153
- label: "Low Confidence",
154
- icon: "alert-circle",
155
- color: "var(--status-warning)",
156
- action: "Interpret with caution"
157
- },
158
- PARTIAL_TIME_WINDOW: {
159
- label: "Partial Data",
160
- icon: "clock",
161
- color: "var(--status-info)",
162
- action: "Expand date range"
163
- },
164
- DATA_SKEW_DETECTED: {
165
- label: "Data Skew",
166
- icon: "bar-chart-2",
167
- color: "var(--status-warning)",
168
- action: "Review methodology"
169
- },
170
- CONFLICTING_SIGNALS: {
171
- label: "Conflicting Signals",
172
- icon: "git-merge",
173
- color: "var(--status-error)",
174
- action: "Manual review needed"
175
- },
176
- INFERRED_NOT_OBSERVED: {
177
- label: "AI Generated",
178
- icon: "cpu",
179
- color: "var(--status-info)",
180
- action: "Verify with data"
181
- },
182
- STALE_DATA: {
183
- label: "Stale Data",
184
- icon: "clock",
185
- color: "var(--status-warning)",
186
- action: "Refresh data"
187
- },
188
- FIELD_MISSING: {
189
- label: "Missing Field",
190
- icon: "file-x",
191
- color: "var(--status-error)",
192
- action: "Upload complete data"
193
- },
194
- CALCULATION_ERROR: {
195
- label: "Calculation Error",
196
- icon: "x-circle",
197
- color: "var(--status-error)",
198
- action: "Contact support"
199
- }
200
- };
201
-
202
- // src/report-engine/confidence.ts
203
- function calculateConfidence(params) {
204
- const { sampleSize, requiredSize, completeness, recency, variance, aiInference } = params;
205
- const sampleScore = Math.min(40, sampleSize / requiredSize * 40);
206
- const completenessScore = completeness * 20;
207
- const recencyScore = recency * 20;
208
- const variancePenalty = variance * 10;
209
- const aiPenalty = aiInference ? 10 : 0;
210
- const rawScore = sampleScore + completenessScore + recencyScore - variancePenalty - aiPenalty;
211
- return Math.max(0, Math.min(100, Math.round(rawScore)));
212
- }
213
- function getConfidenceLevel(score) {
214
- const threshold = CONFIDENCE_THRESHOLDS.find((t) => score >= t.min && score <= t.max);
215
- return threshold?.level ?? "insufficient";
216
- }
217
- function getConfidenceThreshold(score) {
218
- return CONFIDENCE_THRESHOLDS.find((t) => score >= t.min && score <= t.max) ?? CONFIDENCE_THRESHOLDS[CONFIDENCE_THRESHOLDS.length - 1];
219
- }
220
- function calculateRecency(dataDate, maxAgeDays = 30) {
221
- const now = /* @__PURE__ */ new Date();
222
- const ageInDays = (now.getTime() - dataDate.getTime()) / (1e3 * 60 * 60 * 24);
223
- if (ageInDays <= 0) return 1;
224
- if (ageInDays >= maxAgeDays) return 0;
225
- return 1 - ageInDays / maxAgeDays;
226
- }
227
- function calculateCompleteness(data, requiredFields) {
228
- if (data.length === 0 || requiredFields.length === 0) return 0;
229
- let totalFields = 0;
230
- let filledFields = 0;
231
- for (const record of data) {
232
- for (const field of requiredFields) {
233
- totalFields++;
234
- const value = record[field];
235
- if (value !== null && value !== void 0 && value !== "") {
236
- filledFields++;
237
- }
238
- }
239
- }
240
- return totalFields > 0 ? filledFields / totalFields : 0;
241
- }
242
- function calculateNormalizedVariance(values) {
243
- if (values.length < 2) return 0;
244
- const mean = values.reduce((a, b) => a + b, 0) / values.length;
245
- const squaredDiffs = values.map((v) => Math.pow(v - mean, 2));
246
- const variance = squaredDiffs.reduce((a, b) => a + b, 0) / values.length;
247
- const stdDev = Math.sqrt(variance);
248
- const cv = mean !== 0 ? stdDev / Math.abs(mean) : 0;
249
- return Math.min(1, cv);
250
- }
251
- var ReportModeContext = createContext(null);
252
- function ReportModeProvider({
253
- mode = "executive",
254
- children,
255
- onModeChange
256
- }) {
257
- const config = mode === "executive" ? EXECUTIVE_MODE : ANALYST_MODE;
258
- const value = useMemo(
259
- () => ({
260
- ...config,
261
- setMode: onModeChange
262
- }),
263
- [config, onModeChange]
264
- );
265
- return /* @__PURE__ */ jsx(ReportModeContext.Provider, { value, children });
266
- }
267
- function useReportMode() {
268
- const context = useContext(ReportModeContext);
269
- if (!context) {
270
- return EXECUTIVE_MODE;
271
- }
272
- return context;
273
- }
274
- function useDataState(params) {
275
- const {
276
- sampleSize,
277
- requiredSize = MINIMUM_SAMPLE_SIZES.overall,
278
- completeness = 1,
279
- recency = 1,
280
- variance = 0,
281
- aiInferred = false,
282
- missingFields = [],
283
- staleDays
284
- } = params;
285
- return useMemo(() => {
286
- const confidenceParams = {
287
- sampleSize,
288
- requiredSize,
289
- completeness,
290
- recency,
291
- variance,
292
- aiInference: aiInferred
293
- };
294
- const confidence = calculateConfidence(confidenceParams);
295
- const confidenceLevel = getConfidenceLevel(confidence);
296
- let state = "VALID";
297
- if (missingFields.length > 0) {
298
- state = "FIELD_MISSING";
299
- } else if (sampleSize < requiredSize) {
300
- state = "INSUFFICIENT_SAMPLE";
301
- } else if (staleDays && staleDays > 30) {
302
- state = "STALE_DATA";
303
- } else if (aiInferred) {
304
- state = "INFERRED_NOT_OBSERVED";
305
- } else if (confidence < 50) {
306
- state = "LOW_CONFIDENCE";
307
- } else if (variance > 0.7) {
308
- state = "DATA_SKEW_DETECTED";
309
- } else if (recency < 0.3) {
310
- state = "PARTIAL_TIME_WINDOW";
311
- }
312
- const details = {
313
- sampleSize,
314
- requiredSize,
315
- confidence,
316
- missingFields: missingFields.length > 0 ? missingFields : void 0,
317
- staleDays
318
- };
319
- return {
320
- state,
321
- confidence,
322
- confidenceLevel,
323
- details,
324
- isValid: state === "VALID"
325
- };
326
- }, [
327
- sampleSize,
328
- requiredSize,
329
- completeness,
330
- recency,
331
- variance,
332
- aiInferred,
333
- missingFields,
334
- staleDays
335
- ]);
336
- }
337
- function useChartData({
338
- data,
339
- requiredFields,
340
- minSampleSize = MINIMUM_SAMPLE_SIZES.overall
341
- }) {
342
- return useMemo(() => {
343
- const missingFields = [];
344
- if (data.length > 0) {
345
- const firstRecord = data[0];
346
- for (const field of requiredFields) {
347
- if (!(field in firstRecord)) {
348
- missingFields.push(field);
349
- }
350
- }
351
- }
352
- let completeness = 1;
353
- if (data.length > 0 && requiredFields.length > 0) {
354
- let filled = 0;
355
- let total = 0;
356
- for (const record of data) {
357
- for (const field of requiredFields) {
358
- total++;
359
- const value = record[field];
360
- if (value !== null && value !== void 0 && value !== "") {
361
- filled++;
362
- }
363
- }
364
- }
365
- completeness = total > 0 ? filled / total : 0;
366
- }
367
- let state = "VALID";
368
- let message;
369
- if (missingFields.length > 0) {
370
- state = "FIELD_MISSING";
371
- message = `Missing fields: ${missingFields.join(", ")}`;
372
- } else if (data.length === 0) {
373
- state = "INSUFFICIENT_SAMPLE";
374
- message = "No data available";
375
- } else if (data.length < minSampleSize) {
376
- state = "INSUFFICIENT_SAMPLE";
377
- message = `Sample size ${data.length} is below minimum ${minSampleSize}`;
378
- } else if (completeness < 0.7) {
379
- state = "LOW_CONFIDENCE";
380
- message = `Data completeness is ${Math.round(completeness * 100)}%`;
381
- }
382
- const confidence = calculateConfidence({
383
- sampleSize: data.length,
384
- requiredSize: minSampleSize,
385
- completeness,
386
- recency: 1,
387
- // Assume fresh data if not specified
388
- variance: 0,
389
- aiInference: false
390
- });
391
- const isRenderable = state === "VALID" || state === "LOW_CONFIDENCE";
392
- return {
393
- data,
394
- state,
395
- confidence,
396
- isRenderable,
397
- message
398
- };
399
- }, [data, requiredFields, minSampleSize]);
400
- }
401
-
402
- // src/report-engine/chart-types.ts
403
- var CHART_REGISTRY = {
404
- // ══════════════════════════════════════════════════════════════════════════
405
- // TREND CHARTS (MVP)
406
- // ══════════════════════════════════════════════════════════════════════════
407
- line: {
408
- id: "line",
409
- name: "Line Chart",
410
- description: "Shows trends over time with connected data points",
411
- intent: "trend",
412
- phase: "mvp",
413
- contract: {
414
- requiredDimensions: 1,
415
- requiredMeasures: 1,
416
- minDataPoints: 3,
417
- idealDataPoints: 7,
418
- allowNegativeValues: true,
419
- requireNonZeroTotal: false,
420
- warningThresholds: { sparseData: 3 },
421
- fallback: { type: "show_kpi", message: "Insufficient data for trend visualization" }
422
- },
423
- switchableTo: ["smooth_line", "area", "stacked_area"],
424
- supportsStacking: false,
425
- supportsMultipleSeries: true,
426
- requiresTimeAxis: true
427
- },
428
- smooth_line: {
429
- id: "smooth_line",
430
- name: "Smooth Line Chart",
431
- description: "Curved line chart for smoother trend visualization",
432
- intent: "trend",
433
- phase: "mvp",
434
- contract: {
435
- requiredDimensions: 1,
436
- requiredMeasures: 1,
437
- minDataPoints: 3,
438
- idealDataPoints: 7,
439
- allowNegativeValues: true,
440
- requireNonZeroTotal: false,
441
- warningThresholds: { sparseData: 3 },
442
- fallback: { type: "show_kpi", message: "Insufficient data for trend visualization" }
443
- },
444
- switchableTo: ["line", "area", "stacked_area"],
445
- supportsStacking: false,
446
- supportsMultipleSeries: true,
447
- requiresTimeAxis: true
448
- },
449
- area: {
450
- id: "area",
451
- name: "Area Chart",
452
- description: "Filled area under line, emphasizes volume over time",
453
- intent: "trend",
454
- phase: "mvp",
455
- contract: {
456
- requiredDimensions: 1,
457
- requiredMeasures: 1,
458
- minDataPoints: 3,
459
- idealDataPoints: 7,
460
- allowNegativeValues: false,
461
- requireNonZeroTotal: false,
462
- warningThresholds: { sparseData: 3 },
463
- fallback: { type: "show_kpi", message: "Insufficient data for area visualization" }
464
- },
465
- switchableTo: ["line", "smooth_line", "stacked_area", "area_100pct"],
466
- supportsStacking: true,
467
- supportsMultipleSeries: true,
468
- requiresTimeAxis: true
469
- },
470
- stacked_area: {
471
- id: "stacked_area",
472
- name: "Stacked Area Chart",
473
- description: "Multiple series stacked to show cumulative trends",
474
- intent: "trend",
475
- phase: "mvp",
476
- contract: {
477
- requiredDimensions: 1,
478
- requiredMeasures: 2,
479
- minDataPoints: 3,
480
- idealDataPoints: 7,
481
- allowNegativeValues: false,
482
- requireNonZeroTotal: true,
483
- warningThresholds: { sparseData: 3 },
484
- fallback: { type: "warn", message: "Stacked area requires non-negative values" }
485
- },
486
- switchableTo: ["line", "area", "area_100pct"],
487
- supportsStacking: true,
488
- supportsMultipleSeries: true,
489
- requiresTimeAxis: true
490
- },
491
- area_100pct: {
492
- id: "area_100pct",
493
- name: "100% Stacked Area",
494
- description: "Shows proportional contribution over time",
495
- intent: "trend",
496
- phase: "mvp",
497
- contract: {
498
- requiredDimensions: 1,
499
- requiredMeasures: 2,
500
- minDataPoints: 3,
501
- idealDataPoints: 7,
502
- allowNegativeValues: false,
503
- requireNonZeroTotal: true,
504
- warningThresholds: { sparseData: 3 },
505
- fallback: { type: "warn", message: "100% stacked requires positive totals" }
506
- },
507
- switchableTo: ["stacked_area", "area"],
508
- supportsStacking: true,
509
- supportsMultipleSeries: true,
510
- requiresTimeAxis: true
511
- },
512
- // ══════════════════════════════════════════════════════════════════════════
513
- // COMPARISON CHARTS (MVP)
514
- // ══════════════════════════════════════════════════════════════════════════
515
- bar: {
516
- id: "bar",
517
- name: "Horizontal Bar Chart",
518
- description: "Horizontal bars for comparing categories",
519
- intent: "comparison",
520
- phase: "mvp",
521
- contract: {
522
- requiredDimensions: 1,
523
- requiredMeasures: 1,
524
- minDataPoints: 2,
525
- idealDataPoints: 5,
526
- maxDataPoints: 15,
527
- allowNegativeValues: true,
528
- requireNonZeroTotal: false,
529
- warningThresholds: { tooManyCategories: 12 },
530
- fallback: { type: "aggregate", strategy: "top_n" }
531
- },
532
- switchableTo: ["column", "stacked_bar", "stacked_column"],
533
- supportsStacking: true,
534
- supportsMultipleSeries: true,
535
- requiresTimeAxis: false
536
- },
537
- column: {
538
- id: "column",
539
- name: "Vertical Column Chart",
540
- description: "Vertical bars for comparing categories",
541
- intent: "comparison",
542
- phase: "mvp",
543
- contract: {
544
- requiredDimensions: 1,
545
- requiredMeasures: 1,
546
- minDataPoints: 2,
547
- idealDataPoints: 5,
548
- maxDataPoints: 12,
549
- allowNegativeValues: true,
550
- requireNonZeroTotal: false,
551
- warningThresholds: { tooManyCategories: 10 },
552
- fallback: { type: "aggregate", strategy: "top_n" }
553
- },
554
- switchableTo: ["bar", "stacked_column", "stacked_bar"],
555
- supportsStacking: true,
556
- supportsMultipleSeries: true,
557
- requiresTimeAxis: false
558
- },
559
- stacked_bar: {
560
- id: "stacked_bar",
561
- name: "Stacked Horizontal Bar",
562
- description: "Horizontal stacked bars showing composition per category",
563
- intent: "comparison",
564
- phase: "mvp",
565
- contract: {
566
- requiredDimensions: 1,
567
- requiredMeasures: 2,
568
- minDataPoints: 2,
569
- idealDataPoints: 5,
570
- maxDataPoints: 10,
571
- allowNegativeValues: false,
572
- requireNonZeroTotal: true,
573
- warningThresholds: { tooManyCategories: 8, imbalancedRatio: 0.9 },
574
- fallback: { type: "aggregate", strategy: "other_bucket" }
575
- },
576
- switchableTo: ["bar", "stacked_column", "column_100pct"],
577
- supportsStacking: true,
578
- supportsMultipleSeries: true,
579
- requiresTimeAxis: false
580
- },
581
- stacked_column: {
582
- id: "stacked_column",
583
- name: "Stacked Vertical Column",
584
- description: "Vertical stacked columns showing composition per category",
585
- intent: "comparison",
586
- phase: "mvp",
587
- contract: {
588
- requiredDimensions: 1,
589
- requiredMeasures: 2,
590
- minDataPoints: 2,
591
- idealDataPoints: 5,
592
- maxDataPoints: 10,
593
- allowNegativeValues: false,
594
- requireNonZeroTotal: true,
595
- warningThresholds: { tooManyCategories: 8, imbalancedRatio: 0.9 },
596
- fallback: { type: "aggregate", strategy: "other_bucket" }
597
- },
598
- switchableTo: ["column", "stacked_bar", "column_100pct"],
599
- supportsStacking: true,
600
- supportsMultipleSeries: true,
601
- requiresTimeAxis: false
602
- },
603
- column_100pct: {
604
- id: "column_100pct",
605
- name: "100% Stacked Column",
606
- description: "Shows proportional composition per category",
607
- intent: "comparison",
608
- phase: "mvp",
609
- contract: {
610
- requiredDimensions: 1,
611
- requiredMeasures: 2,
612
- minDataPoints: 2,
613
- idealDataPoints: 5,
614
- maxDataPoints: 10,
615
- allowNegativeValues: false,
616
- requireNonZeroTotal: true,
617
- warningThresholds: { tooManyCategories: 8 },
618
- fallback: { type: "warn", message: "100% stacked requires positive totals" }
619
- },
620
- switchableTo: ["stacked_column", "stacked_bar"],
621
- supportsStacking: true,
622
- supportsMultipleSeries: true,
623
- requiresTimeAxis: false
624
- },
625
- combo: {
626
- id: "combo",
627
- name: "Combo Chart",
628
- description: "Combines bars with line overlay (Phase 2)",
629
- intent: "comparison",
630
- phase: "phase2",
631
- contract: {
632
- requiredDimensions: 1,
633
- requiredMeasures: 2,
634
- minDataPoints: 3,
635
- idealDataPoints: 6,
636
- allowNegativeValues: true,
637
- requireNonZeroTotal: false,
638
- warningThresholds: { tooManyCategories: 10 },
639
- fallback: { type: "warn", message: "Combo chart requires dual measures" }
640
- },
641
- switchableTo: ["column", "line"],
642
- supportsStacking: false,
643
- supportsMultipleSeries: true,
644
- requiresTimeAxis: false
645
- },
646
- // ══════════════════════════════════════════════════════════════════════════
647
- // COMPOSITION CHARTS (MVP)
648
- // ══════════════════════════════════════════════════════════════════════════
649
- pie: {
650
- id: "pie",
651
- name: "Pie Chart",
652
- description: "Shows proportional composition of a whole",
653
- intent: "composition",
654
- phase: "mvp",
655
- contract: {
656
- requiredDimensions: 1,
657
- requiredMeasures: 1,
658
- minDataPoints: 2,
659
- idealDataPoints: 4,
660
- maxDataPoints: 6,
661
- allowNegativeValues: false,
662
- requireNonZeroTotal: true,
663
- warningThresholds: { tooManyCategories: 6, imbalancedRatio: 0.95 },
664
- fallback: { type: "aggregate", strategy: "other_bucket" }
665
- },
666
- switchableTo: ["donut", "column_100pct"],
667
- supportsStacking: false,
668
- supportsMultipleSeries: false,
669
- requiresTimeAxis: false,
670
- maxSlices: 6
671
- },
672
- donut: {
673
- id: "donut",
674
- name: "Donut Chart",
675
- description: "Pie chart with center cutout, can display total",
676
- intent: "composition",
677
- phase: "mvp",
678
- contract: {
679
- requiredDimensions: 1,
680
- requiredMeasures: 1,
681
- minDataPoints: 2,
682
- idealDataPoints: 4,
683
- maxDataPoints: 6,
684
- allowNegativeValues: false,
685
- requireNonZeroTotal: true,
686
- warningThresholds: { tooManyCategories: 6, imbalancedRatio: 0.95 },
687
- fallback: { type: "aggregate", strategy: "other_bucket" }
688
- },
689
- switchableTo: ["pie", "column_100pct"],
690
- supportsStacking: false,
691
- supportsMultipleSeries: false,
692
- requiresTimeAxis: false,
693
- maxSlices: 6
694
- },
695
- treemap: {
696
- id: "treemap",
697
- name: "Treemap",
698
- description: "Nested rectangles showing hierarchical composition (Phase 2)",
699
- intent: "composition",
700
- phase: "phase2",
701
- contract: {
702
- requiredDimensions: 1,
703
- requiredMeasures: 1,
704
- minDataPoints: 3,
705
- idealDataPoints: 10,
706
- maxDataPoints: 50,
707
- allowNegativeValues: false,
708
- requireNonZeroTotal: true,
709
- warningThresholds: { tooManyCategories: 30 },
710
- fallback: { type: "aggregate", strategy: "top_n" }
711
- },
712
- switchableTo: ["pie", "donut"],
713
- supportsStacking: false,
714
- supportsMultipleSeries: false,
715
- requiresTimeAxis: false
716
- },
717
- // ══════════════════════════════════════════════════════════════════════════
718
- // DISTRIBUTION CHARTS (MVP)
719
- // ══════════════════════════════════════════════════════════════════════════
720
- histogram: {
721
- id: "histogram",
722
- name: "Histogram",
723
- description: "Shows distribution of values across bins",
724
- intent: "distribution",
725
- phase: "mvp",
726
- contract: {
727
- requiredDimensions: 0,
728
- requiredMeasures: 1,
729
- minDataPoints: 10,
730
- idealDataPoints: 50,
731
- allowNegativeValues: true,
732
- requireNonZeroTotal: false,
733
- warningThresholds: { sparseData: 10 },
734
- fallback: { type: "show_kpi", message: "Insufficient data for distribution" }
735
- },
736
- switchableTo: ["radar"],
737
- supportsStacking: false,
738
- supportsMultipleSeries: false,
739
- requiresTimeAxis: false
740
- },
741
- radar: {
742
- id: "radar",
743
- name: "Radar Chart",
744
- description: "Multi-dimensional comparison in radial layout (Phase 2)",
745
- intent: "distribution",
746
- phase: "phase2",
747
- contract: {
748
- requiredDimensions: 1,
749
- requiredMeasures: 3,
750
- minDataPoints: 3,
751
- idealDataPoints: 6,
752
- maxDataPoints: 8,
753
- allowNegativeValues: false,
754
- requireNonZeroTotal: false,
755
- warningThresholds: { tooManyCategories: 8 },
756
- fallback: { type: "warn", message: "Radar works best with 3-8 dimensions" }
757
- },
758
- switchableTo: ["histogram"],
759
- supportsStacking: false,
760
- supportsMultipleSeries: true,
761
- requiresTimeAxis: false
762
- },
763
- // ══════════════════════════════════════════════════════════════════════════
764
- // RELATIONSHIP CHARTS
765
- // ══════════════════════════════════════════════════════════════════════════
766
- heatmap: {
767
- id: "heatmap",
768
- name: "Heatmap",
769
- description: "Color-coded matrix showing intensity",
770
- intent: "relationship",
771
- phase: "mvp",
772
- contract: {
773
- requiredDimensions: 2,
774
- requiredMeasures: 1,
775
- minDataPoints: 9,
776
- idealDataPoints: 25,
777
- allowNegativeValues: true,
778
- requireNonZeroTotal: false,
779
- warningThresholds: { sparseData: 9 },
780
- fallback: { type: "warn", message: "Heatmap requires grid data" }
781
- },
782
- switchableTo: ["scatter"],
783
- supportsStacking: false,
784
- supportsMultipleSeries: false,
785
- requiresTimeAxis: false
786
- },
787
- scatter: {
788
- id: "scatter",
789
- name: "Scatter Plot",
790
- description: "Shows correlation between two variables (Phase 2)",
791
- intent: "relationship",
792
- phase: "phase2",
793
- contract: {
794
- requiredDimensions: 0,
795
- requiredMeasures: 2,
796
- minDataPoints: 20,
797
- idealDataPoints: 100,
798
- allowNegativeValues: true,
799
- requireNonZeroTotal: false,
800
- warningThresholds: { sparseData: 20 },
801
- fallback: { type: "show_kpi", message: "Scatter requires 20+ points" }
802
- },
803
- switchableTo: ["bubble", "heatmap"],
804
- supportsStacking: false,
805
- supportsMultipleSeries: true,
806
- requiresTimeAxis: false
807
- },
808
- bubble: {
809
- id: "bubble",
810
- name: "Bubble Chart",
811
- description: "Scatter with sized points for third dimension (Phase 2)",
812
- intent: "relationship",
813
- phase: "phase2",
814
- contract: {
815
- requiredDimensions: 0,
816
- requiredMeasures: 3,
817
- minDataPoints: 10,
818
- idealDataPoints: 50,
819
- allowNegativeValues: true,
820
- requireNonZeroTotal: false,
821
- warningThresholds: { sparseData: 10 },
822
- fallback: { type: "show_kpi", message: "Bubble requires 3 measures" }
823
- },
824
- switchableTo: ["scatter"],
825
- supportsStacking: false,
826
- supportsMultipleSeries: true,
827
- requiresTimeAxis: false
828
- },
829
- // ══════════════════════════════════════════════════════════════════════════
830
- // GEOGRAPHIC CHARTS (Phase 2)
831
- // ══════════════════════════════════════════════════════════════════════════
832
- geo: {
833
- id: "geo",
834
- name: "Geographic Map",
835
- description: "Map with regional data markers (Phase 2)",
836
- intent: "geo",
837
- phase: "phase2",
838
- contract: {
839
- requiredDimensions: 1,
840
- // geo dimension (country/region)
841
- requiredMeasures: 1,
842
- minDataPoints: 1,
843
- idealDataPoints: 10,
844
- allowNegativeValues: true,
845
- requireNonZeroTotal: false,
846
- warningThresholds: {},
847
- fallback: { type: "hide" }
848
- },
849
- switchableTo: ["choropleth"],
850
- supportsStacking: false,
851
- supportsMultipleSeries: false,
852
- requiresTimeAxis: false
853
- },
854
- choropleth: {
855
- id: "choropleth",
856
- name: "Choropleth Map",
857
- description: "Color-shaded regions by value (Phase 2)",
858
- intent: "geo",
859
- phase: "phase2",
860
- contract: {
861
- requiredDimensions: 1,
862
- requiredMeasures: 1,
863
- minDataPoints: 3,
864
- idealDataPoints: 20,
865
- allowNegativeValues: false,
866
- requireNonZeroTotal: false,
867
- warningThresholds: {},
868
- fallback: { type: "hide" }
869
- },
870
- switchableTo: ["geo"],
871
- supportsStacking: false,
872
- supportsMultipleSeries: false,
873
- requiresTimeAxis: false
874
- },
875
- // ══════════════════════════════════════════════════════════════════════════
876
- // SPECIAL CHARTS
877
- // ══════════════════════════════════════════════════════════════════════════
878
- funnel: {
879
- id: "funnel",
880
- name: "Funnel Chart",
881
- description: "Shows conversion through sequential stages",
882
- intent: "comparison",
883
- phase: "mvp",
884
- contract: {
885
- requiredDimensions: 1,
886
- requiredMeasures: 1,
887
- minDataPoints: 3,
888
- idealDataPoints: 5,
889
- maxDataPoints: 7,
890
- allowNegativeValues: false,
891
- requireNonZeroTotal: true,
892
- warningThresholds: { tooManyCategories: 7 },
893
- fallback: { type: "warn", message: "Funnel requires sequential stages" }
894
- },
895
- switchableTo: ["bar"],
896
- supportsStacking: false,
897
- supportsMultipleSeries: false,
898
- requiresTimeAxis: false
899
- },
900
- waterfall: {
901
- id: "waterfall",
902
- name: "Waterfall Chart",
903
- description: "Shows cumulative effect of sequential changes (Phase 2)",
904
- intent: "comparison",
905
- phase: "phase2",
906
- contract: {
907
- requiredDimensions: 1,
908
- requiredMeasures: 1,
909
- minDataPoints: 3,
910
- idealDataPoints: 6,
911
- maxDataPoints: 12,
912
- allowNegativeValues: true,
913
- requireNonZeroTotal: false,
914
- warningThresholds: { tooManyCategories: 10 },
915
- fallback: { type: "warn", message: "Waterfall requires sequential data" }
916
- },
917
- switchableTo: ["bar", "column"],
918
- supportsStacking: false,
919
- supportsMultipleSeries: false,
920
- requiresTimeAxis: false
921
- },
922
- timeline: {
923
- id: "timeline",
924
- name: "Timeline",
925
- description: "Shows events along time axis (Phase 2)",
926
- intent: "trend",
927
- phase: "phase2",
928
- contract: {
929
- requiredDimensions: 1,
930
- requiredMeasures: 0,
931
- minDataPoints: 2,
932
- idealDataPoints: 10,
933
- allowNegativeValues: false,
934
- requireNonZeroTotal: false,
935
- warningThresholds: {},
936
- fallback: { type: "hide" }
937
- },
938
- switchableTo: ["line"],
939
- supportsStacking: false,
940
- supportsMultipleSeries: false,
941
- requiresTimeAxis: true
942
- }
943
- };
944
- var INTENT_CHART_FAMILIES = {
945
- trend: ["line", "smooth_line", "area", "stacked_area", "area_100pct"],
946
- comparison: ["bar", "column", "stacked_bar", "stacked_column", "column_100pct", "funnel"],
947
- composition: ["pie", "donut"],
948
- distribution: ["histogram"],
949
- relationship: ["heatmap"],
950
- geo: []
951
- };
952
- function getAllowedSwitchTargets(currentType) {
953
- const metadata = CHART_REGISTRY[currentType];
954
- if (!metadata) return [];
955
- return metadata.switchableTo.filter((type) => {
956
- const targetMeta = CHART_REGISTRY[type];
957
- return targetMeta && targetMeta.phase === "mvp";
958
- });
959
- }
960
- function canSwitchChart(from, to) {
961
- const fromMeta = CHART_REGISTRY[from];
962
- const toMeta = CHART_REGISTRY[to];
963
- if (!fromMeta || !toMeta) return false;
964
- if (fromMeta.intent !== toMeta.intent) return false;
965
- return fromMeta.switchableTo.includes(to);
966
- }
967
- function validateChartData(chartType, data, dimensions, measures) {
968
- const metadata = CHART_REGISTRY[chartType];
969
- if (!metadata) {
970
- return {
971
- isValid: false,
972
- warnings: [],
973
- errors: [`Unknown chart type: ${chartType}`]
974
- };
975
- }
976
- const contract = metadata.contract;
977
- const warnings = [];
978
- const errors = [];
979
- if (data.length < contract.minDataPoints) {
980
- errors.push(`Requires at least ${contract.minDataPoints} data points, got ${data.length}`);
981
- }
982
- if (contract.maxDataPoints && data.length > contract.maxDataPoints) {
983
- warnings.push(`Chart works best with \u2264${contract.maxDataPoints} items. Consider aggregating.`);
984
- }
985
- if (dimensions.length < contract.requiredDimensions) {
986
- errors.push(`Requires ${contract.requiredDimensions} dimension(s), got ${dimensions.length}`);
987
- }
988
- if (measures.length < contract.requiredMeasures) {
989
- errors.push(`Requires ${contract.requiredMeasures} measure(s), got ${measures.length}`);
990
- }
991
- if (!contract.allowNegativeValues && data.length > 0) {
992
- const hasNegative = data.some((row) => {
993
- if (typeof row !== "object" || row === null) return false;
994
- return measures.some((m) => {
995
- const val = row[m];
996
- return typeof val === "number" && val < 0;
997
- });
998
- });
999
- if (hasNegative) {
1000
- errors.push("This chart type does not support negative values");
1001
- }
1002
- }
1003
- if (contract.warningThresholds.tooManyCategories && data.length > contract.warningThresholds.tooManyCategories) {
1004
- warnings.push(`Too many categories (${data.length}). Consider grouping smaller values.`);
1005
- }
1006
- return {
1007
- isValid: errors.length === 0,
1008
- warnings,
1009
- errors,
1010
- fallbackAction: errors.length > 0 ? contract.fallback : void 0
1011
- };
1012
- }
1013
- function getMVPChartsForIntent(intent) {
1014
- return Object.values(CHART_REGISTRY).filter(
1015
- (meta) => meta.intent === intent && meta.phase === "mvp"
1016
- );
1017
- }
1018
- function getDefaultChartForIntent(intent) {
1019
- const defaults = {
1020
- trend: "line",
1021
- comparison: "column",
1022
- composition: "donut",
1023
- distribution: "histogram",
1024
- relationship: "heatmap",
1025
- geo: "geo"
1026
- };
1027
- return defaults[intent];
1028
- }
1029
- function suggestChartType(params) {
1030
- const {
1031
- hasTimeAxis,
1032
- dimensionCount,
1033
- measureCount,
1034
- dataPointCount,
1035
- hasNegativeValues,
1036
- isSequential
1037
- } = params;
1038
- if (hasTimeAxis && measureCount >= 1) {
1039
- if (measureCount > 1 && !hasNegativeValues) return "stacked_area";
1040
- return "line";
1041
- }
1042
- if (isSequential && !hasNegativeValues && dataPointCount <= 7) {
1043
- return "funnel";
1044
- }
1045
- if (measureCount === 1 && dataPointCount <= 6 && !hasNegativeValues) {
1046
- return "donut";
1047
- }
1048
- if (dimensionCount === 2 && measureCount === 1) {
1049
- return "heatmap";
1050
- }
1051
- return "column";
1052
- }
1053
- function validateReportStructure(children) {
1054
- const issues = [];
1055
- const childArray = React2.Children.toArray(children);
1056
- let hasThesis = false;
1057
- let thesisIndex = -1;
1058
- const getComponentName2 = (child) => {
1059
- if (!React2.isValidElement(child)) return void 0;
1060
- const type = child.type;
1061
- return type.displayName || type.name;
1062
- };
1063
- const isChart2 = (name) => {
1064
- return name && (name.endsWith("Chart") || name === "MBTIRadar" || name === "MBTITypeGrid" || name === "KeyMetric");
1065
- };
1066
- childArray.forEach((child, index) => {
1067
- const name = getComponentName2(child);
1068
- if (name === "ExecutiveThesis") {
1069
- if (hasThesis) {
1070
- issues.push({
1071
- ruleId: "R1",
1072
- severity: "error",
1073
- message: "Only one ExecutiveThesis is allowed per report.",
1074
- component: "ExecutiveThesis"
1075
- });
1076
- }
1077
- hasThesis = true;
1078
- thesisIndex = index;
1079
- }
1080
- if (isChart2(name)) {
1081
- issues.push({
1082
- ruleId: "R3",
1083
- severity: "error",
1084
- message: `Orphan chart detected: <${name} />. Charts must be placed inside an InsightBlock or EvidenceGroup.`,
1085
- component: name
1086
- });
1087
- }
1088
- if (name === "InsightBlock" && React2.isValidElement(child)) {
1089
- validateInsightBlock(child, issues);
1090
- }
1091
- });
1092
- if (!hasThesis) {
1093
- issues.push({
1094
- ruleId: "R1",
1095
- severity: "error",
1096
- message: "Report must contain an ExecutiveThesis."
1097
- });
1098
- } else if (thesisIndex > 2) {
1099
- issues.push({
1100
- ruleId: "R1",
1101
- severity: "warning",
1102
- message: "ExecutiveThesis should be the first major component in the report."
1103
- });
1104
- }
1105
- return {
1106
- isValid: issues.filter((i) => i.severity === "error").length === 0,
1107
- issues
1108
- };
1109
- }
1110
- function validateInsightBlock(node, issues) {
1111
- const children = node.props.children;
1112
- const childArray = React2.Children.toArray(children);
1113
- let chartsInBlock = 0;
1114
- const countCharts = (nodes) => {
1115
- nodes.forEach((n) => {
1116
- const name = getComponentName(n);
1117
- if (isChart(name)) {
1118
- chartsInBlock++;
1119
- }
1120
- if (name === "EvidenceGroup" && React2.isValidElement(n)) {
1121
- countCharts(React2.Children.toArray(n.props.children));
1122
- }
1123
- });
1124
- };
1125
- countCharts(childArray);
1126
- if (chartsInBlock > 3) {
1127
- issues.push({
1128
- ruleId: "R6",
1129
- severity: "warning",
1130
- message: `InsightBlock contains ${chartsInBlock} charts. Recommended maximum is 3 to prevent data dumping.`,
1131
- component: "InsightBlock"
1132
- });
1133
- }
1134
- }
1135
- var getComponentName = (child) => {
1136
- if (!React2.isValidElement(child)) return void 0;
1137
- const type = child.type;
1138
- return type.displayName || type.name;
1139
- };
1140
- var isChart = (name) => {
1141
- return name && (name.endsWith("Chart") || name === "MBTIRadar" || name === "MBTITypeGrid" || name === "KeyMetric");
1142
- };
1143
- var ReportShell = React2.forwardRef(
1144
- ({
1145
- title,
1146
- subtitle,
1147
- mode = "executive",
1148
- brand,
1149
- onModeChange,
1150
- children,
1151
- actions,
1152
- className,
1153
- ...props
1154
- }, ref) => {
1155
- return /* @__PURE__ */ jsx(ReportModeProvider, { mode, onModeChange, children: /* @__PURE__ */ jsxs(
1156
- "div",
1157
- {
1158
- ref,
1159
- className: clsx12("ds-report-shell", className),
1160
- "data-mode": mode,
1161
- "data-brand": brand,
1162
- ...props,
1163
- children: [
1164
- (title || subtitle || actions) && /* @__PURE__ */ jsxs("header", { className: "ds-report-shell__header", children: [
1165
- /* @__PURE__ */ jsxs("div", { className: "ds-report-shell__header-content", children: [
1166
- title && /* @__PURE__ */ jsx("h1", { className: "ds-report-shell__title", children: title }),
1167
- subtitle && /* @__PURE__ */ jsx("p", { className: "ds-report-shell__subtitle", children: subtitle })
1168
- ] }),
1169
- actions && /* @__PURE__ */ jsx("div", { className: "ds-report-shell__actions", children: actions })
1170
- ] }),
1171
- /* @__PURE__ */ jsx("main", { className: "ds-report-shell__content", children })
1172
- ]
1173
- }
1174
- ) });
1175
- }
1176
- );
1177
- ReportShell.displayName = "ReportShell";
1178
- var ExecutiveThesis = React2.forwardRef(
1179
- ({ thesis, context, metric, aiGenerated, className, ...props }, ref) => {
1180
- const { features } = useReportMode();
1181
- return /* @__PURE__ */ jsxs(
1182
- "section",
1183
- {
1184
- ref,
1185
- className: clsx12("ds-executive-thesis", className),
1186
- "aria-labelledby": "executive-thesis-title",
1187
- ...props,
1188
- children: [
1189
- /* @__PURE__ */ jsxs("div", { className: "ds-executive-thesis__content", children: [
1190
- /* @__PURE__ */ jsxs("h2", { id: "executive-thesis-title", className: "ds-executive-thesis__title", children: [
1191
- "Key Finding",
1192
- aiGenerated && features.showConfidenceScores && /* @__PURE__ */ jsx("span", { className: "ds-executive-thesis__ai-badge", children: "AI Generated" })
1193
- ] }),
1194
- /* @__PURE__ */ jsx("p", { className: "ds-executive-thesis__thesis", children: thesis }),
1195
- context && /* @__PURE__ */ jsx("p", { className: "ds-executive-thesis__context", children: context })
1196
- ] }),
1197
- metric && /* @__PURE__ */ jsxs("div", { className: "ds-executive-thesis__metric", children: [
1198
- /* @__PURE__ */ jsx("span", { className: "ds-executive-thesis__metric-label", children: metric.label }),
1199
- /* @__PURE__ */ jsxs(
1200
- "span",
1201
- {
1202
- className: clsx12(
1203
- "ds-executive-thesis__metric-value",
1204
- metric.trend && `ds-executive-thesis__metric-value--${metric.trend}`
1205
- ),
1206
- children: [
1207
- metric.trend === "up" && "\u2191 ",
1208
- metric.trend === "down" && "\u2193 ",
1209
- metric.value
1210
- ]
1211
- }
1212
- )
1213
- ] })
1214
- ]
1215
- }
1216
- );
1217
- }
1218
- );
1219
- ExecutiveThesis.displayName = "ExecutiveThesis";
1220
- var InsightBlock = React2.forwardRef(
1221
- ({ type, headline, description, confidence, methodology, children, className, ...props }, ref) => {
1222
- const { features } = useReportMode();
1223
- const contract = INSIGHT_TYPE_CONTRACTS[type];
1224
- const getConfidenceClass = () => {
1225
- if (confidence === void 0) return "";
1226
- if (confidence >= 90) return "ds-insight-block--confidence-high";
1227
- if (confidence >= 70) return "ds-insight-block--confidence-moderate";
1228
- if (confidence >= 50) return "ds-insight-block--confidence-low";
1229
- return "ds-insight-block--confidence-insufficient";
1230
- };
1231
- return /* @__PURE__ */ jsxs(
1232
- "section",
1233
- {
1234
- ref,
1235
- className: clsx12("ds-insight-block", getConfidenceClass(), className),
1236
- "data-insight-type": type,
1237
- "aria-labelledby": `insight-${type}-title`,
1238
- ...props,
1239
- children: [
1240
- /* @__PURE__ */ jsxs("header", { className: "ds-insight-block__header", children: [
1241
- /* @__PURE__ */ jsxs("div", { className: "ds-insight-block__meta", children: [
1242
- /* @__PURE__ */ jsx("span", { className: "ds-insight-block__type", children: type.replace(/-/g, " ") }),
1243
- features.showConfidenceScores && confidence !== void 0 && /* @__PURE__ */ jsxs("span", { className: "ds-insight-block__confidence", children: [
1244
- confidence,
1245
- "% confidence"
1246
- ] })
1247
- ] }),
1248
- /* @__PURE__ */ jsx("h3", { id: `insight-${type}-title`, className: "ds-insight-block__headline", children: headline }),
1249
- description && /* @__PURE__ */ jsx("p", { className: "ds-insight-block__description", children: description })
1250
- ] }),
1251
- /* @__PURE__ */ jsx("div", { className: "ds-insight-block__evidence", children }),
1252
- features.showMethodology && methodology && /* @__PURE__ */ jsxs("footer", { className: "ds-insight-block__methodology", children: [
1253
- /* @__PURE__ */ jsx("h4", { className: "ds-insight-block__methodology-title", children: "Methodology" }),
1254
- /* @__PURE__ */ jsx("p", { className: "ds-insight-block__methodology-text", children: methodology }),
1255
- contract && /* @__PURE__ */ jsxs("p", { className: "ds-insight-block__methodology-contract", children: [
1256
- "Min sample: ",
1257
- contract.minSampleSize,
1258
- " | Allowed charts:",
1259
- " ",
1260
- contract.allowedCharts.join(", ")
1261
- ] })
1262
- ] })
1263
- ]
1264
- }
1265
- );
1266
- }
1267
- );
1268
- InsightBlock.displayName = "InsightBlock";
1269
- var EvidenceGroup = React2.forwardRef(
1270
- ({ title, layout = "row", columns = 2, children, className, ...props }, ref) => {
1271
- const childCount = React2.Children.count(children);
1272
- if (childCount > 3) {
1273
- console.warn(
1274
- `EvidenceGroup: Maximum 3 charts allowed per insight block (received ${childCount}). This violates composition rule R6.`
1275
- );
1276
- }
1277
- return /* @__PURE__ */ jsxs(
1278
- "div",
1279
- {
1280
- ref,
1281
- className: clsx12(
1282
- "ds-evidence-group",
1283
- `ds-evidence-group--${layout}`,
1284
- layout === "grid" && `ds-evidence-group--cols-${columns}`,
1285
- className
1286
- ),
1287
- role: "group",
1288
- "aria-label": title || "Evidence charts",
1289
- ...props,
1290
- children: [
1291
- title && /* @__PURE__ */ jsx("h4", { className: "ds-evidence-group__title", children: title }),
1292
- /* @__PURE__ */ jsx("div", { className: "ds-evidence-group__content", children })
1293
- ]
1294
- }
1295
- );
1296
- }
1297
- );
1298
- EvidenceGroup.displayName = "EvidenceGroup";
1299
- var ConfidenceIndicator = React2.forwardRef(
1300
- ({ score, showScore = true, showLabel = true, size = "md", className, ...props }, ref) => {
1301
- const threshold = getConfidenceThreshold(score);
1302
- const normalizedScore = Math.max(0, Math.min(100, score));
1303
- return /* @__PURE__ */ jsxs(
1304
- "div",
1305
- {
1306
- ref,
1307
- className: clsx12(
1308
- "ds-confidence-indicator",
1309
- `ds-confidence-indicator--${size}`,
1310
- `ds-confidence-indicator--${threshold.level}`,
1311
- className
1312
- ),
1313
- role: "meter",
1314
- "aria-valuenow": normalizedScore,
1315
- "aria-valuemin": 0,
1316
- "aria-valuemax": 100,
1317
- "aria-label": `Confidence: ${threshold.label} (${normalizedScore}%)`,
1318
- ...props,
1319
- children: [
1320
- /* @__PURE__ */ jsx("div", { className: "ds-confidence-indicator__bar", children: /* @__PURE__ */ jsx("div", { className: "ds-confidence-indicator__fill", style: { width: `${normalizedScore}%` } }) }),
1321
- /* @__PURE__ */ jsxs("div", { className: "ds-confidence-indicator__text", children: [
1322
- showScore && /* @__PURE__ */ jsxs("span", { className: "ds-confidence-indicator__score", children: [
1323
- normalizedScore,
1324
- "%"
1325
- ] }),
1326
- showLabel && /* @__PURE__ */ jsx("span", { className: "ds-confidence-indicator__label", children: threshold.label })
1327
- ] })
1328
- ]
1329
- }
1330
- );
1331
- }
1332
- );
1333
- ConfidenceIndicator.displayName = "ConfidenceIndicator";
1334
- var DataCoverageBadge = React2.forwardRef(
1335
- ({ sampleSize, requiredSize, dateRange, showDateRange = true, size = "md", className, ...props }, ref) => {
1336
- const isSufficient = !requiredSize || sampleSize >= requiredSize;
1337
- const percentage = requiredSize ? Math.min(100, Math.round(sampleSize / requiredSize * 100)) : 100;
1338
- return /* @__PURE__ */ jsxs(
1339
- "div",
1340
- {
1341
- ref,
1342
- className: clsx12(
1343
- "ds-data-coverage-badge",
1344
- `ds-data-coverage-badge--${size}`,
1345
- !isSufficient && "ds-data-coverage-badge--insufficient",
1346
- className
1347
- ),
1348
- ...props,
1349
- children: [
1350
- /* @__PURE__ */ jsxs("div", { className: "ds-data-coverage-badge__sample", children: [
1351
- /* @__PURE__ */ jsx("span", { className: "ds-data-coverage-badge__icon", children: /* @__PURE__ */ jsxs(
1352
- "svg",
1353
- {
1354
- width: "14",
1355
- height: "14",
1356
- viewBox: "0 0 24 24",
1357
- fill: "none",
1358
- stroke: "currentColor",
1359
- strokeWidth: "2",
1360
- children: [
1361
- /* @__PURE__ */ jsx("path", { d: "M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" }),
1362
- /* @__PURE__ */ jsx("circle", { cx: "9", cy: "7", r: "4" }),
1363
- /* @__PURE__ */ jsx("path", { d: "M23 21v-2a4 4 0 0 0-3-3.87" }),
1364
- /* @__PURE__ */ jsx("path", { d: "M16 3.13a4 4 0 0 1 0 7.75" })
1365
- ]
1366
- }
1367
- ) }),
1368
- /* @__PURE__ */ jsxs("span", { className: "ds-data-coverage-badge__count", children: [
1369
- "n=",
1370
- sampleSize.toLocaleString()
1371
- ] }),
1372
- requiredSize && /* @__PURE__ */ jsxs("span", { className: "ds-data-coverage-badge__required", children: [
1373
- "(",
1374
- percentage,
1375
- "% of min ",
1376
- requiredSize,
1377
- ")"
1378
- ] })
1379
- ] }),
1380
- showDateRange && dateRange && /* @__PURE__ */ jsxs("div", { className: "ds-data-coverage-badge__date", children: [
1381
- /* @__PURE__ */ jsx("span", { className: "ds-data-coverage-badge__icon", children: /* @__PURE__ */ jsxs(
1382
- "svg",
1383
- {
1384
- width: "14",
1385
- height: "14",
1386
- viewBox: "0 0 24 24",
1387
- fill: "none",
1388
- stroke: "currentColor",
1389
- strokeWidth: "2",
1390
- children: [
1391
- /* @__PURE__ */ jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }),
1392
- /* @__PURE__ */ jsx("line", { x1: "16", y1: "2", x2: "16", y2: "6" }),
1393
- /* @__PURE__ */ jsx("line", { x1: "8", y1: "2", x2: "8", y2: "6" }),
1394
- /* @__PURE__ */ jsx("line", { x1: "3", y1: "10", x2: "21", y2: "10" })
1395
- ]
1396
- }
1397
- ) }),
1398
- /* @__PURE__ */ jsxs("span", { children: [
1399
- dateRange.start,
1400
- " \u2013 ",
1401
- dateRange.end
1402
- ] })
1403
- ] })
1404
- ]
1405
- }
1406
- );
1407
- }
1408
- );
1409
- DataCoverageBadge.displayName = "DataCoverageBadge";
1410
- var DataStateIndicator = React2.forwardRef(
1411
- ({ state, details, variant = "compact", onAction, className, ...props }, ref) => {
1412
- const config = ANALYTICAL_STATE_CONFIG[state];
1413
- if (state === "VALID" && variant === "compact") {
1414
- return null;
1415
- }
1416
- const renderIcon = () => {
1417
- switch (config.icon) {
1418
- case "check":
1419
- return /* @__PURE__ */ jsx(
1420
- "svg",
1421
- {
1422
- width: "16",
1423
- height: "16",
1424
- viewBox: "0 0 24 24",
1425
- fill: "none",
1426
- stroke: "currentColor",
1427
- strokeWidth: "2",
1428
- children: /* @__PURE__ */ jsx("polyline", { points: "20,6 9,17 4,12" })
1429
- }
1430
- );
1431
- case "alert-triangle":
1432
- return /* @__PURE__ */ jsxs(
1433
- "svg",
1434
- {
1435
- width: "16",
1436
- height: "16",
1437
- viewBox: "0 0 24 24",
1438
- fill: "none",
1439
- stroke: "currentColor",
1440
- strokeWidth: "2",
1441
- children: [
1442
- /* @__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" }),
1443
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
1444
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
1445
- ]
1446
- }
1447
- );
1448
- case "alert-circle":
1449
- return /* @__PURE__ */ jsxs(
1450
- "svg",
1451
- {
1452
- width: "16",
1453
- height: "16",
1454
- viewBox: "0 0 24 24",
1455
- fill: "none",
1456
- stroke: "currentColor",
1457
- strokeWidth: "2",
1458
- children: [
1459
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
1460
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
1461
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
1462
- ]
1463
- }
1464
- );
1465
- case "x-circle":
1466
- return /* @__PURE__ */ jsxs(
1467
- "svg",
1468
- {
1469
- width: "16",
1470
- height: "16",
1471
- viewBox: "0 0 24 24",
1472
- fill: "none",
1473
- stroke: "currentColor",
1474
- strokeWidth: "2",
1475
- children: [
1476
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
1477
- /* @__PURE__ */ jsx("line", { x1: "15", y1: "9", x2: "9", y2: "15" }),
1478
- /* @__PURE__ */ jsx("line", { x1: "9", y1: "9", x2: "15", y2: "15" })
1479
- ]
1480
- }
1481
- );
1482
- case "cpu":
1483
- return /* @__PURE__ */ jsxs(
1484
- "svg",
1485
- {
1486
- width: "16",
1487
- height: "16",
1488
- viewBox: "0 0 24 24",
1489
- fill: "none",
1490
- stroke: "currentColor",
1491
- strokeWidth: "2",
1492
- children: [
1493
- /* @__PURE__ */ jsx("rect", { x: "4", y: "4", width: "16", height: "16", rx: "2", ry: "2" }),
1494
- /* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "6", height: "6" }),
1495
- /* @__PURE__ */ jsx("line", { x1: "9", y1: "1", x2: "9", y2: "4" }),
1496
- /* @__PURE__ */ jsx("line", { x1: "15", y1: "1", x2: "15", y2: "4" }),
1497
- /* @__PURE__ */ jsx("line", { x1: "9", y1: "20", x2: "9", y2: "23" }),
1498
- /* @__PURE__ */ jsx("line", { x1: "15", y1: "20", x2: "15", y2: "23" }),
1499
- /* @__PURE__ */ jsx("line", { x1: "20", y1: "9", x2: "23", y2: "9" }),
1500
- /* @__PURE__ */ jsx("line", { x1: "20", y1: "14", x2: "23", y2: "14" }),
1501
- /* @__PURE__ */ jsx("line", { x1: "1", y1: "9", x2: "4", y2: "9" }),
1502
- /* @__PURE__ */ jsx("line", { x1: "1", y1: "14", x2: "4", y2: "14" })
1503
- ]
1504
- }
1505
- );
1506
- default:
1507
- return /* @__PURE__ */ jsxs(
1508
- "svg",
1509
- {
1510
- width: "16",
1511
- height: "16",
1512
- viewBox: "0 0 24 24",
1513
- fill: "none",
1514
- stroke: "currentColor",
1515
- strokeWidth: "2",
1516
- children: [
1517
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
1518
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
1519
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "8", x2: "12.01", y2: "8" })
1520
- ]
1521
- }
1522
- );
1523
- }
1524
- };
1525
- return /* @__PURE__ */ jsxs(
1526
- "div",
1527
- {
1528
- ref,
1529
- className: clsx12(
1530
- "ds-data-state-indicator",
1531
- `ds-data-state-indicator--${variant}`,
1532
- `ds-data-state-indicator--${state.toLowerCase().replace(/_/g, "-")}`,
1533
- className
1534
- ),
1535
- role: "status",
1536
- "aria-live": "polite",
1537
- ...props,
1538
- children: [
1539
- /* @__PURE__ */ jsx("span", { className: "ds-data-state-indicator__icon", style: { color: config.color }, children: renderIcon() }),
1540
- /* @__PURE__ */ jsxs("div", { className: "ds-data-state-indicator__content", children: [
1541
- /* @__PURE__ */ jsx("span", { className: "ds-data-state-indicator__label", children: config.label }),
1542
- variant === "full" && details && /* @__PURE__ */ jsxs("span", { className: "ds-data-state-indicator__details", children: [
1543
- details.message,
1544
- details.sampleSize !== void 0 && details.requiredSize !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1545
- " ",
1546
- "(n=",
1547
- details.sampleSize,
1548
- "/",
1549
- details.requiredSize,
1550
- ")"
1551
- ] }),
1552
- details.confidence !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1553
- " \u2022 ",
1554
- details.confidence,
1555
- "% confidence"
1556
- ] }),
1557
- details.missingFields && details.missingFields.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1558
- " \u2022 Missing: ",
1559
- details.missingFields.join(", ")
1560
- ] })
1561
- ] })
1562
- ] }),
1563
- config.action && onAction && /* @__PURE__ */ jsx("button", { type: "button", className: "ds-data-state-indicator__action", onClick: onAction, children: config.action })
1564
- ]
1565
- }
1566
- );
1567
- }
1568
- );
1569
- DataStateIndicator.displayName = "DataStateIndicator";
1570
- var MethodologyNote = React2.forwardRef(
1571
- ({ children, sampleSize, sources, calculation, forceShow = false, className, labels, ...props }, ref) => {
1572
- const titleText = labels?.title ?? "Methodology";
1573
- const sampleSizeLabel = labels?.sampleSize ?? "Sample Size";
1574
- const dataSourcesLabel = labels?.dataSources ?? "Data Sources";
1575
- const calculationLabel = labels?.calculation ?? "Calculation";
1576
- const { features } = useReportMode();
1577
- const shouldShow = forceShow || features.showMethodology || sampleSize !== void 0 && sampleSize < 100;
1578
- if (!shouldShow) {
1579
- return null;
1580
- }
1581
- return /* @__PURE__ */ jsxs(
1582
- "aside",
1583
- {
1584
- ref,
1585
- className: clsx12("ds-methodology-note", className),
1586
- "aria-label": titleText,
1587
- ...props,
1588
- children: [
1589
- /* @__PURE__ */ jsxs("div", { className: "ds-methodology-note__header", children: [
1590
- /* @__PURE__ */ jsxs(
1591
- "svg",
1592
- {
1593
- className: "ds-methodology-note__icon",
1594
- width: "16",
1595
- height: "16",
1596
- viewBox: "0 0 24 24",
1597
- fill: "none",
1598
- stroke: "currentColor",
1599
- strokeWidth: "2",
1600
- children: [
1601
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
1602
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
1603
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "8", x2: "12.01", y2: "8" })
1604
- ]
1605
- }
1606
- ),
1607
- /* @__PURE__ */ jsx("span", { className: "ds-methodology-note__title", children: titleText })
1608
- ] }),
1609
- /* @__PURE__ */ jsx("div", { className: "ds-methodology-note__content", children }),
1610
- (sources || calculation || sampleSize !== void 0) && /* @__PURE__ */ jsxs("dl", { className: "ds-methodology-note__details", children: [
1611
- sampleSize !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1612
- /* @__PURE__ */ jsx("dt", { children: sampleSizeLabel }),
1613
- /* @__PURE__ */ jsxs("dd", { children: [
1614
- "n=",
1615
- sampleSize.toLocaleString()
1616
- ] })
1617
- ] }),
1618
- sources && sources.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1619
- /* @__PURE__ */ jsx("dt", { children: dataSourcesLabel }),
1620
- /* @__PURE__ */ jsx("dd", { children: sources.join(", ") })
1621
- ] }),
1622
- calculation && /* @__PURE__ */ jsxs(Fragment, { children: [
1623
- /* @__PURE__ */ jsx("dt", { children: calculationLabel }),
1624
- /* @__PURE__ */ jsx("dd", { children: calculation })
1625
- ] })
1626
- ] })
1627
- ]
1628
- }
1629
- );
1630
- }
1631
- );
1632
- MethodologyNote.displayName = "MethodologyNote";
1633
- var CaveatBlock = React2.forwardRef(
1634
- ({
1635
- title = "Important Caveat",
1636
- children,
1637
- severity = "warning",
1638
- confidence,
1639
- forceShow = false,
1640
- className,
1641
- ...props
1642
- }, ref) => {
1643
- const { features } = useReportMode();
1644
- const shouldShow = forceShow || features.showMethodology || confidence !== void 0 && confidence < 70;
1645
- if (!shouldShow) {
1646
- return null;
1647
- }
1648
- const renderIcon = () => {
1649
- if (severity === "critical") {
1650
- return /* @__PURE__ */ jsxs(
1651
- "svg",
1652
- {
1653
- width: "18",
1654
- height: "18",
1655
- viewBox: "0 0 24 24",
1656
- fill: "none",
1657
- stroke: "currentColor",
1658
- strokeWidth: "2",
1659
- children: [
1660
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
1661
- /* @__PURE__ */ jsx("line", { x1: "15", y1: "9", x2: "9", y2: "15" }),
1662
- /* @__PURE__ */ jsx("line", { x1: "9", y1: "9", x2: "15", y2: "15" })
1663
- ]
1664
- }
1665
- );
1666
- }
1667
- if (severity === "info") {
1668
- return /* @__PURE__ */ jsxs(
1669
- "svg",
1670
- {
1671
- width: "18",
1672
- height: "18",
1673
- viewBox: "0 0 24 24",
1674
- fill: "none",
1675
- stroke: "currentColor",
1676
- strokeWidth: "2",
1677
- children: [
1678
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
1679
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
1680
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "8", x2: "12.01", y2: "8" })
1681
- ]
1682
- }
1683
- );
1684
- }
1685
- return /* @__PURE__ */ jsxs(
1686
- "svg",
1687
- {
1688
- width: "18",
1689
- height: "18",
1690
- viewBox: "0 0 24 24",
1691
- fill: "none",
1692
- stroke: "currentColor",
1693
- strokeWidth: "2",
1694
- children: [
1695
- /* @__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" }),
1696
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
1697
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
1698
- ]
1699
- }
1700
- );
1701
- };
1702
- return /* @__PURE__ */ jsxs(
1703
- "aside",
1704
- {
1705
- ref,
1706
- className: clsx12("ds-caveat-block", `ds-caveat-block--${severity}`, className),
1707
- role: "note",
1708
- "aria-label": title,
1709
- ...props,
1710
- children: [
1711
- /* @__PURE__ */ jsxs("div", { className: "ds-caveat-block__header", children: [
1712
- /* @__PURE__ */ jsx("span", { className: "ds-caveat-block__icon", children: renderIcon() }),
1713
- /* @__PURE__ */ jsx("span", { className: "ds-caveat-block__title", children: title }),
1714
- confidence !== void 0 && /* @__PURE__ */ jsxs("span", { className: "ds-caveat-block__confidence", children: [
1715
- confidence,
1716
- "% confidence"
1717
- ] })
1718
- ] }),
1719
- /* @__PURE__ */ jsx("div", { className: "ds-caveat-block__content", children })
1720
- ]
1721
- }
1722
- );
1723
- }
1724
- );
1725
- CaveatBlock.displayName = "CaveatBlock";
1726
- var KeyMetric = React2.forwardRef(
1727
- ({
1728
- title,
1729
- value,
1730
- prefix,
1731
- suffix,
1732
- trend,
1733
- secondary,
1734
- sampleSize,
1735
- confidence,
1736
- onClick,
1737
- loading,
1738
- size = "md",
1739
- className,
1740
- ...props
1741
- }, ref) => {
1742
- const { features } = useReportMode();
1743
- const { isValid } = useDataState({
1744
- sampleSize: sampleSize ?? 100,
1745
- requiredSize: 30
1746
- });
1747
- const isClickable = onClick && !loading;
1748
- const formatValue = (val) => {
1749
- if (typeof val === "number") {
1750
- return val.toLocaleString();
1751
- }
1752
- return val;
1753
- };
1754
- const getTrendIcon = (direction) => {
1755
- switch (direction) {
1756
- case "up":
1757
- return "\u2191";
1758
- case "down":
1759
- return "\u2193";
1760
- default:
1761
- return "\u2192";
1762
- }
1763
- };
1764
- const Component = isClickable ? "button" : "div";
1765
- return /* @__PURE__ */ jsxs(
1766
- Component,
1767
- {
1768
- ref,
1769
- className: clsx12(
1770
- "ds-key-metric",
1771
- `ds-key-metric--${size}`,
1772
- loading && "ds-key-metric--loading",
1773
- isClickable && "ds-key-metric--clickable",
1774
- !isValid && "ds-key-metric--invalid",
1775
- className
1776
- ),
1777
- onClick: isClickable ? onClick : void 0,
1778
- type: isClickable ? "button" : void 0,
1779
- ...props,
1780
- children: [
1781
- /* @__PURE__ */ jsxs("div", { className: "ds-key-metric__header", children: [
1782
- /* @__PURE__ */ jsx("span", { className: "ds-key-metric__title", children: title }),
1783
- features.showConfidenceScores && confidence !== void 0 && /* @__PURE__ */ jsxs("span", { className: "ds-key-metric__confidence", children: [
1784
- confidence,
1785
- "%"
1786
- ] })
1787
- ] }),
1788
- /* @__PURE__ */ jsxs("div", { className: "ds-key-metric__value-row", children: [
1789
- /* @__PURE__ */ jsxs("span", { className: "ds-key-metric__value", children: [
1790
- prefix && /* @__PURE__ */ jsx("span", { className: "ds-key-metric__prefix", children: prefix }),
1791
- loading ? "\u2014" : formatValue(value),
1792
- suffix && /* @__PURE__ */ jsx("span", { className: "ds-key-metric__suffix", children: suffix })
1793
- ] }),
1794
- trend && /* @__PURE__ */ jsxs(
1795
- "span",
1796
- {
1797
- className: clsx12("ds-key-metric__trend", `ds-key-metric__trend--${trend.direction}`),
1798
- children: [
1799
- /* @__PURE__ */ jsx("span", { className: "ds-key-metric__trend-icon", children: getTrendIcon(trend.direction) }),
1800
- /* @__PURE__ */ jsxs("span", { className: "ds-key-metric__trend-value", children: [
1801
- Math.abs(trend.value),
1802
- "%"
1803
- ] }),
1804
- trend.label && /* @__PURE__ */ jsx("span", { className: "ds-key-metric__trend-label", children: trend.label })
1805
- ]
1806
- }
1807
- )
1808
- ] }),
1809
- secondary && /* @__PURE__ */ jsxs("div", { className: "ds-key-metric__secondary", children: [
1810
- /* @__PURE__ */ jsxs("span", { className: "ds-key-metric__secondary-label", children: [
1811
- secondary.label,
1812
- ":"
1813
- ] }),
1814
- /* @__PURE__ */ jsx("span", { className: "ds-key-metric__secondary-value", children: formatValue(secondary.value) })
1815
- ] }),
1816
- features.showMethodology && sampleSize !== void 0 && /* @__PURE__ */ jsxs("div", { className: "ds-key-metric__sample", children: [
1817
- "n=",
1818
- sampleSize.toLocaleString()
1819
- ] })
1820
- ]
1821
- }
1822
- );
1823
- }
1824
- );
1825
- KeyMetric.displayName = "KeyMetric";
1826
- var TrendIndicator = React2.forwardRef(
1827
- ({
1828
- value,
1829
- direction: directionOverride,
1830
- positiveIsGood = true,
1831
- showIcon = true,
1832
- showPercent = true,
1833
- size = "md",
1834
- className,
1835
- ...props
1836
- }, ref) => {
1837
- const direction = directionOverride ?? (value > 0 ? "up" : value < 0 ? "down" : "neutral");
1838
- const isGood = positiveIsGood ? direction === "up" : direction === "down";
1839
- const isBad = positiveIsGood ? direction === "down" : direction === "up";
1840
- const getIcon = () => {
1841
- switch (direction) {
1842
- case "up":
1843
- return /* @__PURE__ */ jsx(
1844
- "svg",
1845
- {
1846
- width: "12",
1847
- height: "12",
1848
- viewBox: "0 0 24 24",
1849
- fill: "none",
1850
- stroke: "currentColor",
1851
- strokeWidth: "3",
1852
- children: /* @__PURE__ */ jsx("polyline", { points: "18,15 12,9 6,15" })
1853
- }
1854
- );
1855
- case "down":
1856
- return /* @__PURE__ */ jsx(
1857
- "svg",
1858
- {
1859
- width: "12",
1860
- height: "12",
1861
- viewBox: "0 0 24 24",
1862
- fill: "none",
1863
- stroke: "currentColor",
1864
- strokeWidth: "3",
1865
- children: /* @__PURE__ */ jsx("polyline", { points: "6,9 12,15 18,9" })
1866
- }
1867
- );
1868
- default:
1869
- return /* @__PURE__ */ jsx(
1870
- "svg",
1871
- {
1872
- width: "12",
1873
- height: "12",
1874
- viewBox: "0 0 24 24",
1875
- fill: "none",
1876
- stroke: "currentColor",
1877
- strokeWidth: "3",
1878
- children: /* @__PURE__ */ jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
1879
- }
1880
- );
1881
- }
1882
- };
1883
- return /* @__PURE__ */ jsxs(
1884
- "span",
1885
- {
1886
- ref,
1887
- className: clsx12(
1888
- "ds-trend-indicator",
1889
- `ds-trend-indicator--${size}`,
1890
- `ds-trend-indicator--${direction}`,
1891
- isGood && "ds-trend-indicator--good",
1892
- isBad && "ds-trend-indicator--bad",
1893
- className
1894
- ),
1895
- "aria-label": `${direction === "up" ? "Increased" : direction === "down" ? "Decreased" : "No change"} by ${Math.abs(value)}%`,
1896
- ...props,
1897
- children: [
1898
- showIcon && /* @__PURE__ */ jsx("span", { className: "ds-trend-indicator__icon", children: getIcon() }),
1899
- /* @__PURE__ */ jsxs("span", { className: "ds-trend-indicator__value", children: [
1900
- value > 0 && "+",
1901
- value.toFixed(1),
1902
- showPercent && "%"
1903
- ] })
1904
- ]
1905
- }
1906
- );
1907
- }
1908
- );
1909
- TrendIndicator.displayName = "TrendIndicator";
1910
- function Select({
1911
- value,
1912
- defaultValue,
1913
- onValueChange,
1914
- disabled,
1915
- required,
1916
- name,
1917
- items,
1918
- children
1919
- }) {
1920
- return /* @__PURE__ */ jsx(
1921
- Select$1.Root,
1922
- {
1923
- value,
1924
- defaultValue,
1925
- onValueChange: onValueChange ? (val) => onValueChange(val) : void 0,
1926
- disabled,
1927
- required,
1928
- name,
1929
- items,
1930
- children
1931
- }
1932
- );
1933
- }
1934
- Select.displayName = "Select";
1935
- var SelectTrigger = React2.forwardRef(
1936
- ({ className, placeholder = "Select...", size = "md", ...props }, ref) => {
1937
- return /* @__PURE__ */ jsx("div", { className: "ds-select__trigger-wrapper", children: /* @__PURE__ */ jsxs(
1938
- Select$1.Trigger,
1939
- {
1940
- ref,
1941
- className: clsx12("ds-select__trigger", `ds-select__trigger--${size}`, className),
1942
- "aria-label": props["aria-label"] || (typeof placeholder === "string" ? placeholder : "Select"),
1943
- ...props,
1944
- children: [
1945
- /* @__PURE__ */ jsx(Select$1.Value, { className: "ds-select__value", placeholder }),
1946
- /* @__PURE__ */ jsx(Select$1.Icon, { className: "ds-select__icon", "aria-hidden": true, children: /* @__PURE__ */ jsx(ChevronDownIcon, {}) })
1947
- ]
1948
- }
1949
- ) });
1950
- }
1951
- );
1952
- SelectTrigger.displayName = "SelectTrigger";
1953
- var SelectContent = React2.forwardRef(
1954
- ({ className, side = "bottom", sideOffset = 4, align = "start", children, ...props }, ref) => {
1955
- return /* @__PURE__ */ jsx(Select$1.Portal, { children: /* @__PURE__ */ jsx(
1956
- Select$1.Positioner,
1957
- {
1958
- side,
1959
- sideOffset,
1960
- align,
1961
- alignItemWithTrigger: false,
1962
- children: /* @__PURE__ */ jsx(Select$1.Popup, { ref, className: clsx12("ds-select__content", className), ...props, children: /* @__PURE__ */ jsx(Select$1.List, { className: "ds-select__list", children }) })
1963
- }
1964
- ) });
1965
- }
1966
- );
1967
- SelectContent.displayName = "SelectContent";
1968
- var SelectItem = React2.forwardRef(
1969
- ({ className, value, children, disabled, ...props }, ref) => {
1970
- return /* @__PURE__ */ jsxs(
1971
- Select$1.Item,
1972
- {
1973
- ref,
1974
- value,
1975
- disabled,
1976
- className: clsx12("ds-select__item", className),
1977
- ...props,
1978
- children: [
1979
- /* @__PURE__ */ jsx(Select$1.ItemIndicator, { className: "ds-select__item-indicator", children: /* @__PURE__ */ jsx(CheckIcon, {}) }),
1980
- /* @__PURE__ */ jsx(Select$1.ItemText, { children })
1981
- ]
1982
- }
1983
- );
1984
- }
1985
- );
1986
- SelectItem.displayName = "SelectItem";
1987
- var SelectGroup = React2.forwardRef(
1988
- ({ className, label, children, ...props }, ref) => {
1989
- return /* @__PURE__ */ jsxs(Select$1.Group, { ref, className: clsx12("ds-select__group", className), ...props, children: [
1990
- label && /* @__PURE__ */ jsx(Select$1.GroupLabel, { className: "ds-select__group-label", children: label }),
1991
- children
1992
- ] });
1993
- }
1994
- );
1995
- SelectGroup.displayName = "SelectGroup";
1996
- var SelectSeparator = React2.forwardRef(({ className, ...props }, ref) => {
1997
- return /* @__PURE__ */ jsx("div", { ref, className: clsx12("ds-select__separator", className), ...props });
1998
- });
1999
- SelectSeparator.displayName = "SelectSeparator";
2000
- function ChevronDownIcon() {
2001
- return /* @__PURE__ */ jsx(
2002
- "svg",
2003
- {
2004
- xmlns: "http://www.w3.org/2000/svg",
2005
- width: "16",
2006
- height: "16",
2007
- viewBox: "0 0 24 24",
2008
- fill: "none",
2009
- stroke: "currentColor",
2010
- strokeWidth: "2",
2011
- strokeLinecap: "round",
2012
- strokeLinejoin: "round",
2013
- children: /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" })
2014
- }
2015
- );
2016
- }
2017
- function CheckIcon() {
2018
- return /* @__PURE__ */ jsx(
2019
- "svg",
2020
- {
2021
- xmlns: "http://www.w3.org/2000/svg",
2022
- width: "14",
2023
- height: "14",
2024
- viewBox: "0 0 24 24",
2025
- fill: "none",
2026
- stroke: "currentColor",
2027
- strokeWidth: "2",
2028
- strokeLinecap: "round",
2029
- strokeLinejoin: "round",
2030
- children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" })
2031
- }
2032
- );
2033
- }
2034
- var DropdownMenu = Menu.Root;
2035
- var DropdownMenuTrigger = React2.forwardRef(({ className, ...props }, ref) => {
2036
- return /* @__PURE__ */ jsx(
2037
- Menu.Trigger,
2038
- {
2039
- ref,
2040
- className: clsx12("ds-dropdown-menu__trigger", className),
2041
- ...props
2042
- }
2043
- );
2044
- });
2045
- DropdownMenuTrigger.displayName = "DropdownMenuTrigger";
2046
- var DropdownMenuContent = React2.forwardRef(
2047
- ({ className, side = "bottom", align = "start", sideOffset = 4, alignOffset = 0, ...props }, ref) => {
2048
- return /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(
2049
- Menu.Positioner,
2050
- {
2051
- side,
2052
- align,
2053
- sideOffset,
2054
- alignOffset,
2055
- children: /* @__PURE__ */ jsx(
2056
- Menu.Popup,
2057
- {
2058
- ref,
2059
- className: clsx12("ds-dropdown-menu__content", className),
2060
- ...props
2061
- }
2062
- )
2063
- }
2064
- ) });
2065
- }
2066
- );
2067
- DropdownMenuContent.displayName = "DropdownMenuContent";
2068
- var DropdownMenuItem = React2.forwardRef(
2069
- ({ className, ...props }, ref) => {
2070
- return /* @__PURE__ */ jsx(Menu.Item, { ref, className: clsx12("ds-dropdown-menu__item", className), ...props });
2071
- }
2072
- );
2073
- DropdownMenuItem.displayName = "DropdownMenuItem";
2074
- var DropdownMenuSeparator = React2.forwardRef(({ className, ...props }, ref) => {
2075
- return /* @__PURE__ */ jsx("div", { ref, className: clsx12("ds-dropdown-menu__separator", className), ...props });
2076
- });
2077
- DropdownMenuSeparator.displayName = "DropdownMenuSeparator";
2078
- var DropdownMenuLabel = React2.forwardRef(({ className, ...props }, ref) => {
2079
- return /* @__PURE__ */ jsx("div", { ref, className: clsx12("ds-dropdown-menu__label", className), ...props });
2080
- });
2081
- DropdownMenuLabel.displayName = "DropdownMenuLabel";
2082
- var DEFAULT_OPTIONS = [
2083
- { format: "pdf", label: "PDF Document", description: "Best for sharing reports" },
2084
- { format: "pptx", label: "PowerPoint", description: "Editable presentation" },
2085
- { format: "xlsx", label: "Excel Spreadsheet", description: "Data with charts" },
2086
- { format: "csv", label: "CSV Data", description: "Raw data only" },
2087
- { format: "png", label: "PNG Image", description: "Chart screenshot" },
2088
- { format: "json", label: "JSON", description: "Developer format" }
2089
- ];
2090
- var FORMAT_ICONS = {
2091
- pdf: /* @__PURE__ */ jsx(PdfIcon, {}),
2092
- csv: /* @__PURE__ */ jsx(CsvIcon, {}),
2093
- xlsx: /* @__PURE__ */ jsx(ExcelIcon, {}),
2094
- pptx: /* @__PURE__ */ jsx(PptIcon, {}),
2095
- png: /* @__PURE__ */ jsx(ImageIcon, {}),
2096
- json: /* @__PURE__ */ jsx(JsonIcon, {})
2097
- };
2098
- function ExportMenu({
2099
- options = DEFAULT_OPTIONS,
2100
- onExport,
2101
- isExporting = false,
2102
- label = "Export",
2103
- size = "md",
2104
- variant = "secondary",
2105
- className,
2106
- disabled
2107
- }) {
2108
- const documentOptions = options.filter((o) => ["pdf", "pptx"].includes(o.format));
2109
- const dataOptions = options.filter((o) => ["xlsx", "csv", "json"].includes(o.format));
2110
- const imageOptions = options.filter((o) => ["png"].includes(o.format));
2111
- return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
2112
- /* @__PURE__ */ jsx(
2113
- DropdownMenuTrigger,
2114
- {
2115
- className: clsx12(
2116
- "ds-export-menu__trigger",
2117
- "ds-button",
2118
- `ds-button--${variant}`,
2119
- `ds-button--${size}`,
2120
- className
2121
- ),
2122
- disabled: disabled || isExporting,
2123
- children: isExporting ? /* @__PURE__ */ jsxs(Fragment, { children: [
2124
- /* @__PURE__ */ jsx(LoadingIcon, {}),
2125
- "Exporting..."
2126
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2127
- /* @__PURE__ */ jsx(ExportIcon, {}),
2128
- label
2129
- ] })
2130
- }
2131
- ),
2132
- /* @__PURE__ */ jsxs(DropdownMenuContent, { side: "bottom", align: "end", sideOffset: 4, children: [
2133
- documentOptions.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
2134
- /* @__PURE__ */ jsx(DropdownMenuLabel, { children: "Documents" }),
2135
- documentOptions.map((option) => /* @__PURE__ */ jsxs(
2136
- DropdownMenuItem,
2137
- {
2138
- disabled: option.disabled,
2139
- onClick: () => onExport(option.format),
2140
- children: [
2141
- /* @__PURE__ */ jsx("span", { className: "ds-export-menu__item-icon", children: FORMAT_ICONS[option.format] }),
2142
- /* @__PURE__ */ jsxs("span", { className: "ds-export-menu__item-content", children: [
2143
- /* @__PURE__ */ jsx("span", { className: "ds-export-menu__item-label", children: option.label }),
2144
- option.description && /* @__PURE__ */ jsx("span", { className: "ds-export-menu__item-description", children: option.description })
2145
- ] })
2146
- ]
2147
- },
2148
- option.format
2149
- ))
2150
- ] }),
2151
- documentOptions.length > 0 && dataOptions.length > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2152
- dataOptions.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
2153
- /* @__PURE__ */ jsx(DropdownMenuLabel, { children: "Data" }),
2154
- dataOptions.map((option) => /* @__PURE__ */ jsxs(
2155
- DropdownMenuItem,
2156
- {
2157
- disabled: option.disabled,
2158
- onClick: () => onExport(option.format),
2159
- children: [
2160
- /* @__PURE__ */ jsx("span", { className: "ds-export-menu__item-icon", children: FORMAT_ICONS[option.format] }),
2161
- /* @__PURE__ */ jsxs("span", { className: "ds-export-menu__item-content", children: [
2162
- /* @__PURE__ */ jsx("span", { className: "ds-export-menu__item-label", children: option.label }),
2163
- option.description && /* @__PURE__ */ jsx("span", { className: "ds-export-menu__item-description", children: option.description })
2164
- ] })
2165
- ]
2166
- },
2167
- option.format
2168
- ))
2169
- ] }),
2170
- imageOptions.length > 0 && (dataOptions.length > 0 || documentOptions.length > 0) && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2171
- imageOptions.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
2172
- /* @__PURE__ */ jsx(DropdownMenuLabel, { children: "Image" }),
2173
- imageOptions.map((option) => /* @__PURE__ */ jsxs(
2174
- DropdownMenuItem,
2175
- {
2176
- disabled: option.disabled,
2177
- onClick: () => onExport(option.format),
2178
- children: [
2179
- /* @__PURE__ */ jsx("span", { className: "ds-export-menu__item-icon", children: FORMAT_ICONS[option.format] }),
2180
- /* @__PURE__ */ jsxs("span", { className: "ds-export-menu__item-content", children: [
2181
- /* @__PURE__ */ jsx("span", { className: "ds-export-menu__item-label", children: option.label }),
2182
- option.description && /* @__PURE__ */ jsx("span", { className: "ds-export-menu__item-description", children: option.description })
2183
- ] })
2184
- ]
2185
- },
2186
- option.format
2187
- ))
2188
- ] })
2189
- ] })
2190
- ] });
2191
- }
2192
- ExportMenu.displayName = "ExportMenu";
2193
- function ExportIcon() {
2194
- return /* @__PURE__ */ jsxs(
2195
- "svg",
2196
- {
2197
- xmlns: "http://www.w3.org/2000/svg",
2198
- width: "16",
2199
- height: "16",
2200
- viewBox: "0 0 24 24",
2201
- fill: "none",
2202
- stroke: "currentColor",
2203
- strokeWidth: "2",
2204
- strokeLinecap: "round",
2205
- strokeLinejoin: "round",
2206
- children: [
2207
- /* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
2208
- /* @__PURE__ */ jsx("polyline", { points: "17 8 12 3 7 8" }),
2209
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
2210
- ]
2211
- }
2212
- );
2213
- }
2214
- function LoadingIcon() {
2215
- return /* @__PURE__ */ jsx(
2216
- "svg",
2217
- {
2218
- className: "ds-export-menu__loading-icon",
2219
- xmlns: "http://www.w3.org/2000/svg",
2220
- width: "16",
2221
- height: "16",
2222
- viewBox: "0 0 24 24",
2223
- fill: "none",
2224
- stroke: "currentColor",
2225
- strokeWidth: "2",
2226
- strokeLinecap: "round",
2227
- strokeLinejoin: "round",
2228
- children: /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
2229
- }
2230
- );
2231
- }
2232
- function PdfIcon() {
2233
- return /* @__PURE__ */ jsxs(
2234
- "svg",
2235
- {
2236
- xmlns: "http://www.w3.org/2000/svg",
2237
- width: "16",
2238
- height: "16",
2239
- viewBox: "0 0 24 24",
2240
- fill: "none",
2241
- stroke: "currentColor",
2242
- strokeWidth: "2",
2243
- strokeLinecap: "round",
2244
- strokeLinejoin: "round",
2245
- children: [
2246
- /* @__PURE__ */ jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
2247
- /* @__PURE__ */ jsx("polyline", { points: "14 2 14 8 20 8" }),
2248
- /* @__PURE__ */ jsx("line", { x1: "16", y1: "13", x2: "8", y2: "13" }),
2249
- /* @__PURE__ */ jsx("line", { x1: "16", y1: "17", x2: "8", y2: "17" }),
2250
- /* @__PURE__ */ jsx("polyline", { points: "10 9 9 9 8 9" })
2251
- ]
2252
- }
2253
- );
2254
- }
2255
- function CsvIcon() {
2256
- return /* @__PURE__ */ jsxs(
2257
- "svg",
2258
- {
2259
- xmlns: "http://www.w3.org/2000/svg",
2260
- width: "16",
2261
- height: "16",
2262
- viewBox: "0 0 24 24",
2263
- fill: "none",
2264
- stroke: "currentColor",
2265
- strokeWidth: "2",
2266
- strokeLinecap: "round",
2267
- strokeLinejoin: "round",
2268
- children: [
2269
- /* @__PURE__ */ jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
2270
- /* @__PURE__ */ jsx("polyline", { points: "14 2 14 8 20 8" }),
2271
- /* @__PURE__ */ jsx("line", { x1: "8", y1: "13", x2: "16", y2: "13" }),
2272
- /* @__PURE__ */ jsx("line", { x1: "8", y1: "17", x2: "16", y2: "17" })
2273
- ]
2274
- }
2275
- );
2276
- }
2277
- function ExcelIcon() {
2278
- return /* @__PURE__ */ jsxs(
2279
- "svg",
2280
- {
2281
- xmlns: "http://www.w3.org/2000/svg",
2282
- width: "16",
2283
- height: "16",
2284
- viewBox: "0 0 24 24",
2285
- fill: "none",
2286
- stroke: "currentColor",
2287
- strokeWidth: "2",
2288
- strokeLinecap: "round",
2289
- strokeLinejoin: "round",
2290
- children: [
2291
- /* @__PURE__ */ jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
2292
- /* @__PURE__ */ jsx("path", { d: "M3 9h18" }),
2293
- /* @__PURE__ */ jsx("path", { d: "M3 15h18" }),
2294
- /* @__PURE__ */ jsx("path", { d: "M9 3v18" }),
2295
- /* @__PURE__ */ jsx("path", { d: "M15 3v18" })
2296
- ]
2297
- }
2298
- );
2299
- }
2300
- function PptIcon() {
2301
- return /* @__PURE__ */ jsxs(
2302
- "svg",
2303
- {
2304
- xmlns: "http://www.w3.org/2000/svg",
2305
- width: "16",
2306
- height: "16",
2307
- viewBox: "0 0 24 24",
2308
- fill: "none",
2309
- stroke: "currentColor",
2310
- strokeWidth: "2",
2311
- strokeLinecap: "round",
2312
- strokeLinejoin: "round",
2313
- children: [
2314
- /* @__PURE__ */ jsx("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2" }),
2315
- /* @__PURE__ */ jsx("line", { x1: "8", y1: "21", x2: "16", y2: "21" }),
2316
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "17", x2: "12", y2: "21" })
2317
- ]
2318
- }
2319
- );
2320
- }
2321
- function ImageIcon() {
2322
- return /* @__PURE__ */ jsxs(
2323
- "svg",
2324
- {
2325
- xmlns: "http://www.w3.org/2000/svg",
2326
- width: "16",
2327
- height: "16",
2328
- viewBox: "0 0 24 24",
2329
- fill: "none",
2330
- stroke: "currentColor",
2331
- strokeWidth: "2",
2332
- strokeLinecap: "round",
2333
- strokeLinejoin: "round",
2334
- children: [
2335
- /* @__PURE__ */ jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
2336
- /* @__PURE__ */ jsx("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
2337
- /* @__PURE__ */ jsx("path", { d: "m21 15-5-5L5 21" })
2338
- ]
2339
- }
2340
- );
2341
- }
2342
- function JsonIcon() {
2343
- return /* @__PURE__ */ jsxs(
2344
- "svg",
2345
- {
2346
- xmlns: "http://www.w3.org/2000/svg",
2347
- width: "16",
2348
- height: "16",
2349
- viewBox: "0 0 24 24",
2350
- fill: "none",
2351
- stroke: "currentColor",
2352
- strokeWidth: "2",
2353
- strokeLinecap: "round",
2354
- strokeLinejoin: "round",
2355
- children: [
2356
- /* @__PURE__ */ jsx("path", { d: "M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5a2 2 0 0 0 2 2h1" }),
2357
- /* @__PURE__ */ jsx("path", { d: "M16 21h1a2 2 0 0 0 2-2v-5a2 2 0 0 1 2-2 2 2 0 0 1-2-2V5a2 2 0 0 0-2-2h-1" })
2358
- ]
2359
- }
2360
- );
2361
- }
2362
-
2363
- export { ANALYST_MODE, ANALYTICAL_STATE_CONFIG, CHART_REGISTRY, CONFIDENCE_THRESHOLDS, CaveatBlock, ConfidenceIndicator, DataCoverageBadge, DataStateIndicator, EXECUTIVE_MODE, EvidenceGroup, ExecutiveThesis, ExportMenu, INSIGHT_TYPE_CONTRACTS, INTENT_CHART_FAMILIES, InsightBlock, KeyMetric, MINIMUM_SAMPLE_SIZES, MethodologyNote, ReportModeProvider, ReportShell, Select, SelectContent, SelectGroup, SelectItem, SelectSeparator, SelectTrigger, TrendIndicator, calculateCompleteness, calculateConfidence, calculateNormalizedVariance, calculateRecency, canSwitchChart, getAllowedSwitchTargets, getConfidenceLevel, getConfidenceThreshold, getDefaultChartForIntent, getMVPChartsForIntent, suggestChartType, useChartData, useDataState, useReportMode, validateChartData, validateReportStructure };
1
+ export { CaveatBlock, EvidenceGroup, ExecutiveThesis, ExportMenu, InsightBlock, KeyMetric, MethodologyNote, ReportShell, TrendIndicator } from '../chunk-6H4DSTXR.js';
2
+ export { ANALYST_MODE, ANALYTICAL_STATE_CONFIG, CHART_REGISTRY, CONFIDENCE_THRESHOLDS, ConfidenceIndicator, DataCoverageBadge, DataStateIndicator, EXECUTIVE_MODE, INSIGHT_TYPE_CONTRACTS, INTENT_CHART_FAMILIES, MINIMUM_SAMPLE_SIZES, ReportModeProvider, calculateCompleteness, calculateConfidence, calculateNormalizedVariance, calculateRecency, canSwitchChart, getAllowedSwitchTargets, getConfidenceLevel, getConfidenceThreshold, getDefaultChartForIntent, getMVPChartsForIntent, suggestChartType, useChartData, useDataState, useReportMode, validateChartData, validateReportStructure } from '../chunk-B6AVAX4F.js';
3
+ export { Select, SelectContent, SelectGroup, SelectItem, SelectSeparator, SelectTrigger } from '../chunk-FAFAP4L5.js';
2364
4
  //# sourceMappingURL=out.js.map
2365
5
  //# sourceMappingURL=index.js.map