@wealthx/shadcn 1.5.38 → 1.5.40

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 (39) hide show
  1. package/.turbo/turbo-build.log +98 -95
  2. package/CHANGELOG.md +12 -0
  3. package/dist/{chunk-LSSIWLYU.mjs → chunk-6XNEHTII.mjs} +1 -1
  4. package/dist/{chunk-ULQ53FRJ.mjs → chunk-7NQKFPXE.mjs} +1 -1
  5. package/dist/{chunk-DSVKEVX6.mjs → chunk-CZOGJC76.mjs} +1 -1
  6. package/dist/{chunk-JPGL36WQ.mjs → chunk-FL7DEYUA.mjs} +6 -7
  7. package/dist/{chunk-2CHH5QOA.mjs → chunk-FQUT5XD6.mjs} +1 -1
  8. package/dist/chunk-MGIDYXOP.mjs +814 -0
  9. package/dist/{chunk-OG2VM34K.mjs → chunk-MHBQJVHE.mjs} +1 -1
  10. package/dist/{chunk-R7M657QL.mjs → chunk-STN5QIWN.mjs} +36 -1
  11. package/dist/components/ui/file-preview-dialog.js +6 -7
  12. package/dist/components/ui/file-preview-dialog.mjs +2 -2
  13. package/dist/components/ui/kanban-column.js +6 -7
  14. package/dist/components/ui/kanban-column.mjs +3 -3
  15. package/dist/components/ui/opportunity-card.js +6 -7
  16. package/dist/components/ui/opportunity-card.mjs +2 -2
  17. package/dist/components/ui/pipeline-board.js +6 -7
  18. package/dist/components/ui/pipeline-board.mjs +4 -4
  19. package/dist/components/ui/policy-ai/index.js +1636 -0
  20. package/dist/components/ui/policy-ai/index.mjs +36 -0
  21. package/dist/components/ui/progress.js +6 -7
  22. package/dist/components/ui/progress.mjs +1 -1
  23. package/dist/components/ui/stage-timeline.js +6 -7
  24. package/dist/components/ui/stage-timeline.mjs +2 -2
  25. package/dist/components/ui/support-agent/index.js +31 -1
  26. package/dist/components/ui/support-agent/index.mjs +1 -1
  27. package/dist/index.js +4105 -3299
  28. package/dist/index.mjs +25 -7
  29. package/dist/styles.css +1 -1
  30. package/package.json +10 -5
  31. package/src/components/index.tsx +30 -0
  32. package/src/components/ui/policy-ai/index.tsx +41 -0
  33. package/src/components/ui/policy-ai/policy-ai-panel.tsx +526 -0
  34. package/src/components/ui/policy-ai/policy-ai-primitives.tsx +332 -0
  35. package/src/components/ui/policy-ai/policy-ai-responses.tsx +543 -0
  36. package/src/components/ui/progress.tsx +15 -12
  37. package/src/components/ui/support-agent/support-agent-panel.tsx +46 -2
  38. package/src/styles/styles-css.ts +1 -1
  39. package/tsup.config.ts +2 -1
@@ -0,0 +1,332 @@
1
+ import * as React from "react";
2
+ import { ChevronDown, ChevronUp, FileText, Tag } from "lucide-react";
3
+ import { cn } from "@/lib/utils";
4
+ import { Badge } from "@/components/ui/badge";
5
+ import { Button } from "@/components/ui/button";
6
+
7
+ // ---------------------------------------------------------------------------
8
+ // Types
9
+ // ---------------------------------------------------------------------------
10
+
11
+ export type PolicyType =
12
+ | "Income"
13
+ | "Security"
14
+ | "Serviceability"
15
+ | "Loan Type"
16
+ | "Borrower";
17
+
18
+ export type PolicyQueryType =
19
+ | "single_bank"
20
+ | "cross_bank_comparison"
21
+ | "threshold_filter"
22
+ | "ranking"
23
+ | "scenario_match"
24
+ | "general";
25
+
26
+ export type PolicyVerdict = "yes" | "soft_no" | "no" | "unknown";
27
+
28
+ /** What the Policy AI classifier detected about the broker's query. */
29
+ export interface PolicyQueryContext {
30
+ policyType: PolicyType;
31
+ /** Fine-grained categories, e.g. ["Bonus Income", "Add Backs"] */
32
+ categories: string[];
33
+ queryType: PolicyQueryType;
34
+ /** Only set for single_bank queries. */
35
+ bankName?: string;
36
+ }
37
+
38
+ /** A single citation attached to a Policy AI response. */
39
+ export interface PolicyCitationItem {
40
+ /** 1-based index used inline as [N] markers in the answer text. */
41
+ index: number;
42
+ bankName: string;
43
+ category: string;
44
+ /** Excerpt from the source policy document. */
45
+ excerpt: string;
46
+ }
47
+
48
+ /** A bank's verdict in a cross-bank comparison. */
49
+ export interface PolicyBankVerdict {
50
+ bankName: string;
51
+ verdict: PolicyVerdict;
52
+ /** Brief human-readable explanation from the policy engine. */
53
+ details?: string;
54
+ citations?: number[];
55
+ }
56
+
57
+ /** A bank's entry in a TOPSIS-ranked list. */
58
+ export interface PolicyRankedBankItem {
59
+ rank: number;
60
+ bankName: string;
61
+ /** TOPSIS closeness score 0.0–1.0 (higher = better). */
62
+ score: number;
63
+ verdict: PolicyVerdict;
64
+ /** Key policy highlights shown as bullets under the bank row. */
65
+ highlights: string[];
66
+ citations?: number[];
67
+ }
68
+
69
+ /**
70
+ * Discriminated union of the three response content formats that Policy AI
71
+ * can return, corresponding to retrieval tiers A / B / C.
72
+ */
73
+ export type PolicyResponseContent =
74
+ | {
75
+ type: "single_bank";
76
+ bankName: string;
77
+ verdict: PolicyVerdict;
78
+ /** Prose answer with inline [N] citation markers. */
79
+ answer: string;
80
+ citations: PolicyCitationItem[];
81
+ }
82
+ | {
83
+ type: "cross_bank_comparison";
84
+ categories: string[];
85
+ banks: PolicyBankVerdict[];
86
+ summaryCounts: {
87
+ yes: number;
88
+ softNo: number;
89
+ no: number;
90
+ total: number;
91
+ };
92
+ citations: PolicyCitationItem[];
93
+ }
94
+ | {
95
+ type: "ranked_list";
96
+ categories: string[];
97
+ banks: PolicyRankedBankItem[];
98
+ citations: PolicyCitationItem[];
99
+ };
100
+
101
+ /**
102
+ * A past conversation entry — reserved for the conversation history feature.
103
+ * Used when rendering a list of previous Policy AI sessions (inline mode).
104
+ */
105
+ export interface PolicyConversationItem {
106
+ id: string;
107
+ /** First user query — used as the conversation title. */
108
+ title: string;
109
+ /** Human-readable timestamp, e.g. "Today, 10:24 AM". */
110
+ timestamp?: string;
111
+ }
112
+
113
+ /** A single message in the Policy AI chat. */
114
+ export interface PolicyAIMessage {
115
+ id: string;
116
+ role: "user" | "assistant";
117
+ content: string;
118
+ /** Classification info shown above the response as a query chip. */
119
+ queryContext?: PolicyQueryContext;
120
+ /** Structured response payload (absent for user messages). */
121
+ responseContent?: PolicyResponseContent;
122
+ }
123
+
124
+ // ---------------------------------------------------------------------------
125
+ // PolicyQueryChip props
126
+ // ---------------------------------------------------------------------------
127
+
128
+ export interface PolicyQueryChipProps {
129
+ context: PolicyQueryContext;
130
+ className?: string;
131
+ }
132
+
133
+ // ---------------------------------------------------------------------------
134
+ // PolicyVerdictBadge props
135
+ // ---------------------------------------------------------------------------
136
+
137
+ export interface PolicyVerdictBadgeProps {
138
+ verdict: PolicyVerdict;
139
+ className?: string;
140
+ }
141
+
142
+ // ---------------------------------------------------------------------------
143
+ // PolicyCitationPanel props
144
+ // ---------------------------------------------------------------------------
145
+
146
+ export interface PolicyCitationPanelProps {
147
+ citations: PolicyCitationItem[];
148
+ className?: string;
149
+ }
150
+
151
+ // ---------------------------------------------------------------------------
152
+ // Internal helpers
153
+ // ---------------------------------------------------------------------------
154
+
155
+ const POLICY_TYPE_COLORS: Record<PolicyType, string> = {
156
+ Income: "text-primary",
157
+ Security: "text-warning",
158
+ Serviceability: "text-info",
159
+ "Loan Type": "text-secondary",
160
+ Borrower: "text-success",
161
+ };
162
+
163
+ const QUERY_TYPE_LABELS: Record<PolicyQueryType, string> = {
164
+ single_bank: "Single bank",
165
+ cross_bank_comparison: "Cross-bank",
166
+ threshold_filter: "Filter",
167
+ ranking: "Ranking",
168
+ scenario_match: "Scenario",
169
+ general: "General",
170
+ };
171
+
172
+ // ---------------------------------------------------------------------------
173
+ // PolicyQueryChip (Atom)
174
+ // ---------------------------------------------------------------------------
175
+
176
+ /**
177
+ * Chip rendered above every Policy AI assistant response.
178
+ * Shows the detected policy type, categories, and query routing type —
179
+ * equivalent to Jira Rovo's "Searching Confluence…" context indicator.
180
+ *
181
+ * @example
182
+ * <PolicyQueryChip context={{ policyType: "Income", categories: ["Bonus Income"], queryType: "ranking" }} />
183
+ */
184
+ export function PolicyQueryChip({ context, className }: PolicyQueryChipProps) {
185
+ const { policyType, categories, queryType, bankName } = context;
186
+ const typeColor = POLICY_TYPE_COLORS[policyType];
187
+
188
+ return (
189
+ <div
190
+ data-slot="policy-query-chip"
191
+ className={cn(
192
+ "inline-flex flex-wrap items-center gap-1.5 text-xs text-muted-foreground",
193
+ className,
194
+ )}
195
+ >
196
+ <Tag className="size-3 shrink-0" aria-hidden="true" />
197
+
198
+ {/* Policy type */}
199
+ <span className={cn("font-medium", typeColor)}>{policyType}</span>
200
+
201
+ {/* Bank name (single_bank only) */}
202
+ {bankName && (
203
+ <>
204
+ <span className="text-border">·</span>
205
+ <span className="font-medium text-foreground">{bankName}</span>
206
+ </>
207
+ )}
208
+
209
+ {/* Categories */}
210
+ {categories.length > 0 && (
211
+ <>
212
+ <span className="text-border">·</span>
213
+ <span>{categories.join(", ")}</span>
214
+ </>
215
+ )}
216
+
217
+ {/* Query type badge */}
218
+ <Badge variant="outline" className="text-xs px-1.5 py-0 shrink-0">
219
+ {QUERY_TYPE_LABELS[queryType]}
220
+ </Badge>
221
+ </div>
222
+ );
223
+ }
224
+
225
+ // ---------------------------------------------------------------------------
226
+ // PolicyVerdictBadge (Atom)
227
+ // ---------------------------------------------------------------------------
228
+
229
+ const VERDICT_CONFIG: Record<
230
+ PolicyVerdict,
231
+ {
232
+ variant: "success" | "warning" | "destructive" | "secondary";
233
+ label: string;
234
+ }
235
+ > = {
236
+ yes: { variant: "success", label: "Yes" },
237
+ soft_no: { variant: "warning", label: "Soft No" },
238
+ no: { variant: "destructive", label: "No" },
239
+ unknown: { variant: "secondary", label: "—" },
240
+ };
241
+
242
+ /**
243
+ * Coloured badge indicating a bank's lending policy verdict.
244
+ * - Yes → success (green)
245
+ * - Soft No → warning (amber) — accepted on specialist/non-prime products
246
+ * - No → destructive (red) — not accepted
247
+ * - Unknown → secondary — data not available
248
+ */
249
+ export function PolicyVerdictBadge({
250
+ verdict,
251
+ className,
252
+ }: PolicyVerdictBadgeProps) {
253
+ const { variant, label } = VERDICT_CONFIG[verdict];
254
+ return (
255
+ <Badge
256
+ data-slot="policy-verdict-badge"
257
+ variant={variant}
258
+ className={cn("shrink-0", className)}
259
+ >
260
+ {label}
261
+ </Badge>
262
+ );
263
+ }
264
+
265
+ // ---------------------------------------------------------------------------
266
+ // PolicyCitationPanel (Molecule)
267
+ // ---------------------------------------------------------------------------
268
+
269
+ /**
270
+ * Collapsible panel listing the policy document sources behind an AI response.
271
+ * Rendered below every response format (SingleBankAnswer, ComparisonTable, RankedList).
272
+ * Collapsed by default; expands on toggle.
273
+ */
274
+ export function PolicyCitationPanel({
275
+ citations,
276
+ className,
277
+ }: PolicyCitationPanelProps) {
278
+ const [open, setOpen] = React.useState(false);
279
+
280
+ if (citations.length === 0) return null;
281
+
282
+ return (
283
+ <div
284
+ data-slot="policy-citation-panel"
285
+ className={cn("border-t border-border", className)}
286
+ >
287
+ <Button
288
+ variant="ghost"
289
+ size="sm"
290
+ className="w-full justify-between px-0 text-xs text-muted-foreground hover:text-foreground hover:bg-transparent gap-1"
291
+ onClick={() => setOpen((v) => !v)}
292
+ aria-expanded={open}
293
+ >
294
+ <span className="flex items-center gap-1.5">
295
+ <FileText className="size-3" aria-hidden="true" />
296
+ View sources ({citations.length})
297
+ </span>
298
+ {open ? (
299
+ <ChevronUp className="size-3" aria-hidden="true" />
300
+ ) : (
301
+ <ChevronDown className="size-3" aria-hidden="true" />
302
+ )}
303
+ </Button>
304
+
305
+ {open && (
306
+ <ol className="mt-1 flex flex-col gap-2 pb-1">
307
+ {citations.map((cite) => (
308
+ <li key={cite.index} className="flex gap-2 text-xs">
309
+ {/* Index chip */}
310
+ <span className="shrink-0 flex items-center justify-center size-4 bg-muted text-muted-foreground font-mono font-semibold text-xs">
311
+ {cite.index}
312
+ </span>
313
+ <div className="flex flex-col gap-0.5 min-w-0">
314
+ <div className="flex items-center gap-1.5 flex-wrap">
315
+ <span className="font-medium text-foreground">
316
+ {cite.bankName}
317
+ </span>
318
+ <Badge variant="secondary" className="text-xs px-1.5 py-0">
319
+ {cite.category}
320
+ </Badge>
321
+ </div>
322
+ <p className="text-muted-foreground leading-relaxed line-clamp-3">
323
+ {cite.excerpt}
324
+ </p>
325
+ </div>
326
+ </li>
327
+ ))}
328
+ </ol>
329
+ )}
330
+ </div>
331
+ );
332
+ }