@platned/ui 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1284 @@
1
+ // src/index.tsx
2
+ import clsx20 from "clsx";
3
+
4
+ // src/components/button.tsx
5
+ import clsx from "clsx";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ var variantStyles = {
8
+ primary: clsx(
9
+ "bg-background-brand border border-border-brand text-text-brand-on-brand",
10
+ "hover:bg-background-brand-hover",
11
+ "disabled:bg-background-disabled disabled:border-border-disabled disabled:text-text-disabled-on-disabled"
12
+ ),
13
+ neutral: clsx(
14
+ "bg-background-default border border-border-default text-text-default",
15
+ "hover:bg-background-default-hover",
16
+ "disabled:bg-background-disabled disabled:border-border-disabled disabled:text-text-disabled-on-disabled"
17
+ ),
18
+ subtle: clsx(
19
+ "bg-transparent text-text-neutral",
20
+ "hover:bg-background-neutral-tertiary",
21
+ "disabled:bg-background-disabled disabled:border disabled:border-border-disabled disabled:text-text-disabled-on-disabled"
22
+ ),
23
+ danger: clsx(
24
+ "bg-background-danger border border-border-danger-secondary text-text-danger-on-danger",
25
+ "hover:bg-background-danger-hover",
26
+ "disabled:bg-background-disabled disabled:border-border-disabled disabled:text-text-disabled-on-disabled"
27
+ ),
28
+ "danger-subtle": clsx(
29
+ "bg-transparent text-text-danger",
30
+ "hover:bg-background-danger-tertiary",
31
+ "disabled:bg-background-disabled disabled:border disabled:border-border-disabled disabled:text-text-disabled-on-disabled"
32
+ )
33
+ };
34
+ var sizeStyles = {
35
+ lg: "h-12 px-3 gap-1 rounded-2xl text-body font-semibold [&_svg]:size-5",
36
+ md: "h-9 px-2 gap-0.5 rounded-lg text-body-sm font-semibold [&_svg]:size-5",
37
+ sm: "h-6 px-1.5 pt-0.5 gap-0 rounded-full text-body-tiny font-semibold [&_svg]:size-4"
38
+ };
39
+ function Button({
40
+ variant = "primary",
41
+ size = "md",
42
+ leadingIcon,
43
+ trailingIcon,
44
+ children,
45
+ className,
46
+ ...props
47
+ }) {
48
+ return /* @__PURE__ */ jsxs(
49
+ "button",
50
+ {
51
+ className: clsx(
52
+ "inline-flex items-center justify-center whitespace-nowrap transition-colors",
53
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-brand focus-visible:ring-offset-1",
54
+ "disabled:cursor-not-allowed",
55
+ variantStyles[variant],
56
+ sizeStyles[size],
57
+ className
58
+ ),
59
+ ...props,
60
+ children: [
61
+ leadingIcon,
62
+ /* @__PURE__ */ jsx("div", { className: "px-1", children }),
63
+ trailingIcon
64
+ ]
65
+ }
66
+ );
67
+ }
68
+
69
+ // src/components/icon-button.tsx
70
+ import clsx2 from "clsx";
71
+ import { jsx as jsx2 } from "react/jsx-runtime";
72
+ var variantStyles2 = {
73
+ primary: clsx2(
74
+ "bg-background-brand border border-border-brand text-text-brand-on-brand",
75
+ "hover:bg-background-brand-hover",
76
+ "disabled:bg-background-disabled disabled:border-border-disabled disabled:text-text-disabled-on-disabled"
77
+ ),
78
+ // Neutral uses secondary background (light gray) for visual weight without a text label
79
+ neutral: clsx2(
80
+ "bg-background-default-secondary border border-border-default text-text-default",
81
+ "hover:bg-background-default-secondary-hover",
82
+ "disabled:bg-background-disabled disabled:border-border-disabled disabled:text-text-disabled-on-disabled"
83
+ ),
84
+ subtle: clsx2(
85
+ "bg-transparent text-text-neutral",
86
+ "hover:bg-background-neutral-tertiary",
87
+ "disabled:bg-background-disabled disabled:border disabled:border-border-disabled disabled:text-text-disabled-on-disabled"
88
+ )
89
+ };
90
+ var sizeStyles2 = {
91
+ lg: "size-12 rounded-2xl [&_svg]:size-5",
92
+ md: "size-9 rounded-lg [&_svg]:size-5",
93
+ sm: "size-6 rounded-full [&_svg]:size-4"
94
+ };
95
+ function IconButton({
96
+ variant = "primary",
97
+ size = "md",
98
+ icon,
99
+ className,
100
+ ...props
101
+ }) {
102
+ return /* @__PURE__ */ jsx2(
103
+ "button",
104
+ {
105
+ className: clsx2(
106
+ "inline-flex shrink-0 items-center justify-center transition-colors",
107
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-brand focus-visible:ring-offset-1",
108
+ "disabled:cursor-not-allowed",
109
+ variantStyles2[variant],
110
+ sizeStyles2[size],
111
+ className
112
+ ),
113
+ ...props,
114
+ children: icon
115
+ }
116
+ );
117
+ }
118
+
119
+ // src/components/button-group.tsx
120
+ import clsx3 from "clsx";
121
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
122
+ var containerStyles = {
123
+ primary: "bg-background-neutral-tertiary p-1 rounded-2xl",
124
+ neutral: "bg-background-neutral-tertiary p-1 rounded-2xl",
125
+ filter: "bg-background-default border border-border-default p-1 rounded-xl"
126
+ };
127
+ var selectedStyles = {
128
+ primary: clsx3(
129
+ "bg-background-brand border border-border-brand text-text-brand-on-brand",
130
+ "hover:bg-background-brand-hover"
131
+ ),
132
+ neutral: clsx3(
133
+ "bg-background-default border border-border-default text-text-default",
134
+ "hover:bg-background-default-hover"
135
+ ),
136
+ filter: clsx3(
137
+ "bg-background-brand text-text-brand-on-brand",
138
+ "hover:bg-background-brand-hover"
139
+ )
140
+ };
141
+ var unselectedStyles = {
142
+ primary: clsx3("bg-transparent text-text-neutral", "hover:bg-background-neutral-tertiary-hover"),
143
+ neutral: clsx3("bg-transparent text-text-neutral", "hover:bg-background-neutral-tertiary-hover"),
144
+ filter: clsx3("text-text-default-secondary", "hover:text-text-default")
145
+ };
146
+ var itemSizeStyles = {
147
+ lg: "h-12 px-3 gap-1 rounded-2xl text-body font-semibold [&_svg]:size-5",
148
+ md: "h-9 px-2 gap-0.5 rounded-lg text-body-sm font-semibold [&_svg]:size-5",
149
+ sm: "h-6 px-1.5 pt-0.5 gap-0 rounded-full text-body-tiny font-semibold [&_svg]:size-4"
150
+ };
151
+ var containerAlignStyles = {
152
+ justify: "flex flex-row items-center",
153
+ start: "flex flex-row items-center justify-start",
154
+ end: "flex flex-row items-center justify-end",
155
+ center: "flex flex-row items-center justify-center",
156
+ stack: "flex flex-col items-center"
157
+ };
158
+ function ButtonGroup({
159
+ items,
160
+ value,
161
+ onChange,
162
+ variant = "primary",
163
+ size = "md",
164
+ align = "start",
165
+ className,
166
+ "aria-label": ariaLabel
167
+ }) {
168
+ const isJustify = align === "justify";
169
+ const isStack = align === "stack";
170
+ return /* @__PURE__ */ jsx3(
171
+ "div",
172
+ {
173
+ role: "group",
174
+ "aria-label": ariaLabel,
175
+ className: clsx3(
176
+ containerStyles[variant],
177
+ containerAlignStyles[align],
178
+ className
179
+ ),
180
+ children: items.map((item) => {
181
+ const isSelected = item.value === value;
182
+ return /* @__PURE__ */ jsx3(
183
+ "div",
184
+ {
185
+ className: clsx3(isJustify && "flex-1 min-w-0", isStack && "w-full"),
186
+ children: /* @__PURE__ */ jsxs2(
187
+ "button",
188
+ {
189
+ type: "button",
190
+ "aria-pressed": isSelected,
191
+ disabled: item.disabled,
192
+ onClick: () => onChange(item.value),
193
+ className: clsx3(
194
+ "inline-flex items-center justify-center whitespace-nowrap transition-colors",
195
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-brand focus-visible:ring-offset-1",
196
+ "disabled:cursor-not-allowed disabled:text-text-disabled",
197
+ (isJustify || isStack) && "w-full",
198
+ itemSizeStyles[size],
199
+ isSelected ? selectedStyles[variant] : unselectedStyles[variant]
200
+ ),
201
+ children: [
202
+ item.leadingIcon,
203
+ /* @__PURE__ */ jsx3("div", { className: "px-1", children: item.label }),
204
+ item.trailingIcon
205
+ ]
206
+ }
207
+ )
208
+ },
209
+ item.value
210
+ );
211
+ })
212
+ }
213
+ );
214
+ }
215
+
216
+ // src/components/avatar.tsx
217
+ import clsx4 from "clsx";
218
+ import { jsx as jsx4 } from "react/jsx-runtime";
219
+ var sizeStyles3 = {
220
+ lg: "size-10",
221
+ md: "size-8",
222
+ sm: "size-6"
223
+ };
224
+ var initialTextStyles = {
225
+ lg: "text-body font-semibold",
226
+ md: "text-body-xs font-semibold",
227
+ sm: "text-body-tiny font-semibold"
228
+ };
229
+ var shapeStyles = {
230
+ circle: "rounded-full",
231
+ square: "rounded-lg"
232
+ };
233
+ function Avatar(props) {
234
+ const { size = "lg", shape = "circle", className } = props;
235
+ const base = clsx4(
236
+ "shrink-0 overflow-hidden",
237
+ sizeStyles3[size],
238
+ shapeStyles[shape],
239
+ className
240
+ );
241
+ if (props.type === "image") {
242
+ return /* @__PURE__ */ jsx4("div", { className: base, children: /* @__PURE__ */ jsx4(
243
+ "img",
244
+ {
245
+ src: props.src,
246
+ alt: props.alt ?? "",
247
+ className: "size-full object-cover"
248
+ }
249
+ ) });
250
+ }
251
+ return /* @__PURE__ */ jsx4(
252
+ "div",
253
+ {
254
+ className: clsx4(base, "flex items-center justify-center"),
255
+ style: {
256
+ background: "linear-gradient(135deg, var(--color-graphic-blue) 30%, var(--color-graphic-red) 100%)"
257
+ },
258
+ children: /* @__PURE__ */ jsx4(
259
+ "span",
260
+ {
261
+ className: clsx4(
262
+ "select-none leading-none text-text-brand-on-brand",
263
+ initialTextStyles[size]
264
+ ),
265
+ children: props.initial.charAt(0).toUpperCase()
266
+ }
267
+ )
268
+ }
269
+ );
270
+ }
271
+
272
+ // src/components/avatar-group.tsx
273
+ import clsx5 from "clsx";
274
+ import { jsxs as jsxs3 } from "react/jsx-runtime";
275
+ function AvatarGroup({
276
+ children,
277
+ overflow,
278
+ spacing = "spaced",
279
+ className
280
+ }) {
281
+ return /* @__PURE__ */ jsxs3(
282
+ "div",
283
+ {
284
+ className: clsx5(
285
+ "flex items-center",
286
+ spacing === "spaced" ? "gap-1" : "-space-x-2 isolate",
287
+ className
288
+ ),
289
+ children: [
290
+ children,
291
+ overflow !== void 0 && /* @__PURE__ */ jsxs3(
292
+ "div",
293
+ {
294
+ className: clsx5(
295
+ "flex items-center justify-center",
296
+ "min-w-6 h-6 px-1 rounded-lg",
297
+ "bg-background-default-secondary text-text-default-secondary text-body-sm",
298
+ spacing === "overlap" && "drop-shadow-sm"
299
+ ),
300
+ children: [
301
+ "+",
302
+ overflow
303
+ ]
304
+ }
305
+ )
306
+ ]
307
+ }
308
+ );
309
+ }
310
+
311
+ // src/components/nav-item.tsx
312
+ import clsx6 from "clsx";
313
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
314
+ function NavItem({
315
+ icon,
316
+ label,
317
+ isActive = false,
318
+ indicator = false,
319
+ collapsed = false,
320
+ className
321
+ }) {
322
+ return /* @__PURE__ */ jsxs4(
323
+ "span",
324
+ {
325
+ className: clsx6(
326
+ "relative flex h-11 w-full items-center gap-3 rounded-xl px-3.5 py-2.5 transition-colors",
327
+ collapsed && "justify-center",
328
+ isActive ? "bg-background-brand text-text-brand-on-brand" : [
329
+ "border border-border-default bg-background-default text-text-default-secondary",
330
+ "hover:bg-background-brand-tertiary-hover hover:border-border-brand-tertiary hover:text-text-brand"
331
+ ],
332
+ className
333
+ ),
334
+ children: [
335
+ icon !== void 0 && /* @__PURE__ */ jsx5("span", { className: "shrink-0 [&_svg]:size-4", children: icon }),
336
+ !collapsed && /* @__PURE__ */ jsx5("span", { className: "flex-1 min-w-0 truncate text-body-sm font-regular leading-snug", children: label }),
337
+ indicator && /* @__PURE__ */ jsx5("span", { className: "absolute -right-px -top-px size-2 rounded-full bg-background-danger" })
338
+ ]
339
+ }
340
+ );
341
+ }
342
+
343
+ // src/components/input.tsx
344
+ import { forwardRef } from "react";
345
+ import clsx7 from "clsx";
346
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
347
+ var wrapGap = {
348
+ lg: "gap-2",
349
+ // 8px
350
+ md: "gap-1",
351
+ // 4px
352
+ sm: "gap-0.5"
353
+ // 2px
354
+ };
355
+ var labelText = {
356
+ lg: "text-body",
357
+ md: "text-body-sm",
358
+ sm: "text-body-tiny"
359
+ };
360
+ var inputBase = {
361
+ lg: "h-12 px-4 py-3.5 text-body",
362
+ md: "h-9 px-3 py-2.5 text-body-sm",
363
+ sm: "h-6 px-2 py-[5px] text-body-tiny"
364
+ };
365
+ var leadingPad = {
366
+ lg: "pl-10",
367
+ md: "pl-8",
368
+ sm: "pl-6"
369
+ };
370
+ var trailingPad = {
371
+ lg: "pr-10",
372
+ md: "pr-8",
373
+ sm: "pr-6"
374
+ };
375
+ var iconWrap = {
376
+ lg: { left: "left-4", right: "right-4", size: "size-5" },
377
+ md: { left: "left-3", right: "right-3", size: "size-4" },
378
+ sm: { left: "left-2", right: "right-2", size: "size-3" }
379
+ };
380
+ var Input = forwardRef(function Input2({ label, description, error, hint, size = "md", leadingIcon, trailingIcon, className, disabled, id, ...props }, ref) {
381
+ const hasError = !!error;
382
+ const iw = iconWrap[size];
383
+ return /* @__PURE__ */ jsxs5("div", { className: clsx7("flex flex-col", wrapGap[size], className), children: [
384
+ label && /* @__PURE__ */ jsx6(
385
+ "label",
386
+ {
387
+ htmlFor: id,
388
+ className: clsx7(labelText[size], disabled ? "text-text-disabled" : "text-text-default"),
389
+ children: label
390
+ }
391
+ ),
392
+ description && /* @__PURE__ */ jsx6("p", { className: clsx7(labelText[size], disabled ? "text-text-disabled" : "text-text-default-secondary"), children: description }),
393
+ /* @__PURE__ */ jsxs5("div", { className: "relative flex items-center", children: [
394
+ leadingIcon && /* @__PURE__ */ jsx6("span", { className: clsx7("pointer-events-none absolute", iw.left, iw.size, "flex items-center justify-center text-icon-default-secondary"), children: leadingIcon }),
395
+ /* @__PURE__ */ jsx6(
396
+ "input",
397
+ {
398
+ ref,
399
+ id,
400
+ disabled,
401
+ className: clsx7(
402
+ "w-full rounded-lg border outline-none transition-colors",
403
+ "bg-background-default text-text-default",
404
+ "placeholder:text-text-default-tertiary",
405
+ inputBase[size],
406
+ leadingIcon && leadingPad[size],
407
+ trailingIcon && trailingPad[size],
408
+ disabled ? "cursor-not-allowed bg-background-disabled border-border-disabled text-text-disabled placeholder:text-text-disabled" : hasError ? "border-border-danger-secondary focus:border-border-danger-secondary focus:ring-1 focus:ring-border-danger-secondary" : "border-border-default focus:border-border-brand-tertiary focus:ring-1 focus:ring-border-brand-tertiary"
409
+ ),
410
+ ...props
411
+ }
412
+ ),
413
+ trailingIcon && /* @__PURE__ */ jsx6("span", { className: clsx7("pointer-events-none absolute", iw.right, iw.size, "flex items-center justify-center text-icon-default-secondary"), children: trailingIcon })
414
+ ] }),
415
+ hasError && /* @__PURE__ */ jsx6("p", { className: clsx7(labelText[size], "text-text-danger"), children: error }),
416
+ !hasError && hint && /* @__PURE__ */ jsx6("p", { className: clsx7(labelText[size], "text-text-default-secondary"), children: hint })
417
+ ] });
418
+ });
419
+
420
+ // src/components/textarea.tsx
421
+ import { forwardRef as forwardRef2 } from "react";
422
+ import clsx8 from "clsx";
423
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
424
+ var wrapGap2 = {
425
+ lg: "gap-2",
426
+ md: "gap-1",
427
+ sm: "gap-0.5"
428
+ };
429
+ var labelText2 = {
430
+ lg: "text-body",
431
+ md: "text-body-sm",
432
+ sm: "text-body-tiny"
433
+ };
434
+ var textareaBase = {
435
+ lg: "min-h-20 px-4 py-3.5 text-body",
436
+ md: "min-h-[68px] px-3 py-2.5 text-body-sm",
437
+ sm: "min-h-[52px] px-2 py-[5px] text-body-tiny"
438
+ };
439
+ var Textarea = forwardRef2(function Textarea2({ label, description, error, hint, size = "md", className, disabled, id, ...props }, ref) {
440
+ const hasError = !!error;
441
+ return /* @__PURE__ */ jsxs6("div", { className: clsx8("flex flex-col", wrapGap2[size], className), children: [
442
+ label && /* @__PURE__ */ jsx7(
443
+ "label",
444
+ {
445
+ htmlFor: id,
446
+ className: clsx8(labelText2[size], disabled ? "text-text-disabled" : "text-text-default"),
447
+ children: label
448
+ }
449
+ ),
450
+ description && /* @__PURE__ */ jsx7("p", { className: clsx8(labelText2[size], disabled ? "text-text-disabled" : "text-text-default-secondary"), children: description }),
451
+ /* @__PURE__ */ jsx7(
452
+ "textarea",
453
+ {
454
+ ref,
455
+ id,
456
+ disabled,
457
+ className: clsx8(
458
+ "w-full rounded-lg border outline-none transition-colors resize-y",
459
+ "bg-background-default text-text-default",
460
+ "placeholder:text-text-default-tertiary",
461
+ textareaBase[size],
462
+ disabled ? "cursor-not-allowed bg-background-disabled border-border-disabled text-text-disabled placeholder:text-text-disabled resize-none" : hasError ? "border-border-danger-secondary focus:border-border-danger-secondary focus:ring-1 focus:ring-border-danger-secondary" : "border-border-default focus:border-border-brand-tertiary focus:ring-1 focus:ring-border-brand-tertiary"
463
+ ),
464
+ ...props
465
+ }
466
+ ),
467
+ hasError && /* @__PURE__ */ jsx7("p", { className: clsx8(labelText2[size], "text-text-danger"), children: error }),
468
+ !hasError && hint && /* @__PURE__ */ jsx7("p", { className: clsx8(labelText2[size], "text-text-default-secondary"), children: hint })
469
+ ] });
470
+ });
471
+
472
+ // src/components/select.tsx
473
+ import { forwardRef as forwardRef3 } from "react";
474
+ import clsx9 from "clsx";
475
+ import { LuChevronDown } from "react-icons/lu";
476
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
477
+ var wrapGap3 = {
478
+ lg: "gap-2",
479
+ md: "gap-1",
480
+ sm: "gap-0.5"
481
+ };
482
+ var labelText3 = {
483
+ lg: "text-body",
484
+ md: "text-body-sm",
485
+ sm: "text-body-tiny"
486
+ };
487
+ var selectBase = {
488
+ lg: "h-12 pl-4 pr-9 text-body",
489
+ // right-4 (16) + size-5 (20) = 36px
490
+ md: "h-9 pl-3 pr-7 text-body-sm",
491
+ // right-3 (12) + size-4 (16) = 28px
492
+ sm: "h-6 pl-2 pr-5 text-body-tiny"
493
+ // right-2 (8) + size-3 (12) = 20px
494
+ };
495
+ var chevronPos = {
496
+ lg: { right: "right-4", size: "size-5" },
497
+ md: { right: "right-3", size: "size-4" },
498
+ sm: { right: "right-2", size: "size-3" }
499
+ };
500
+ var Select = forwardRef3(function Select2({ label, description, error, hint, size = "md", options, placeholder, className, disabled, id, ...props }, ref) {
501
+ const hasError = !!error;
502
+ const cp = chevronPos[size];
503
+ return /* @__PURE__ */ jsxs7("div", { className: clsx9("flex flex-col", wrapGap3[size], className), children: [
504
+ label && /* @__PURE__ */ jsx8(
505
+ "label",
506
+ {
507
+ htmlFor: id,
508
+ className: clsx9(labelText3[size], disabled ? "text-text-disabled" : "text-text-default"),
509
+ children: label
510
+ }
511
+ ),
512
+ description && /* @__PURE__ */ jsx8("p", { className: clsx9(labelText3[size], disabled ? "text-text-disabled" : "text-text-default-secondary"), children: description }),
513
+ /* @__PURE__ */ jsxs7("div", { className: "relative flex items-center", children: [
514
+ /* @__PURE__ */ jsxs7(
515
+ "select",
516
+ {
517
+ ref,
518
+ id,
519
+ disabled,
520
+ className: clsx9(
521
+ "w-full appearance-none rounded-lg border outline-none transition-colors pt-0.5",
522
+ "bg-background-default text-text-default",
523
+ selectBase[size],
524
+ disabled ? "cursor-not-allowed bg-background-disabled border-border-disabled text-text-disabled" : hasError ? "border-border-danger-secondary focus:border-border-danger-secondary focus:ring-1 focus:ring-border-danger-secondary" : "border-border-default focus:border-border-brand-tertiary focus:ring-1 focus:ring-border-brand-tertiary"
525
+ ),
526
+ ...props,
527
+ children: [
528
+ placeholder && /* @__PURE__ */ jsx8("option", { value: "", disabled: true, children: placeholder }),
529
+ options.map((opt) => /* @__PURE__ */ jsx8("option", { value: opt.value, children: opt.label }, opt.value))
530
+ ]
531
+ }
532
+ ),
533
+ /* @__PURE__ */ jsx8(
534
+ "span",
535
+ {
536
+ className: clsx9(
537
+ "pointer-events-none absolute",
538
+ cp.right,
539
+ cp.size,
540
+ "flex items-center justify-center",
541
+ disabled ? "text-icon-disabled" : "text-icon-default-secondary"
542
+ ),
543
+ children: /* @__PURE__ */ jsx8(LuChevronDown, { className: "size-full" })
544
+ }
545
+ )
546
+ ] }),
547
+ hasError && /* @__PURE__ */ jsx8("p", { className: clsx9(labelText3[size], "text-text-danger"), children: error }),
548
+ !hasError && hint && /* @__PURE__ */ jsx8("p", { className: clsx9(labelText3[size], "text-text-default-secondary"), children: hint })
549
+ ] });
550
+ });
551
+
552
+ // src/components/stepper.tsx
553
+ import clsx10 from "clsx";
554
+ import { LuCheck, LuChevronRight } from "react-icons/lu";
555
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
556
+ function StepIndicator({ status }) {
557
+ if (status === "complete") {
558
+ return /* @__PURE__ */ jsx9("span", { className: "flex size-5 shrink-0 items-center justify-center rounded-full bg-background-brand text-white", children: /* @__PURE__ */ jsx9(LuCheck, { size: 11, "aria-hidden": true }) });
559
+ }
560
+ if (status === "active") {
561
+ return /* @__PURE__ */ jsx9("span", { className: "flex size-5 shrink-0 items-center justify-center rounded-full border-2 border-background-brand", children: /* @__PURE__ */ jsx9("span", { className: "size-2.5 rounded-full bg-background-brand" }) });
562
+ }
563
+ return /* @__PURE__ */ jsx9("span", { className: "size-5 shrink-0 rounded-full border-2 border-border-disabled", "aria-hidden": "true" });
564
+ }
565
+ function ChevronSeparator() {
566
+ return /* @__PURE__ */ jsx9(LuChevronRight, { className: "mx-1 size-4 shrink-0 text-text-default-tertiary", "aria-hidden": true });
567
+ }
568
+ var labelClass = {
569
+ complete: "text-text-brand font-semibold",
570
+ active: "text-text-brand font-semibold",
571
+ upcoming: "text-text-disabled font-regular"
572
+ };
573
+ function Stepper({ steps, className }) {
574
+ return /* @__PURE__ */ jsx9(
575
+ "ol",
576
+ {
577
+ className: clsx10("flex items-center overflow-x-auto", className),
578
+ "aria-label": "Progress",
579
+ children: steps.map((step, i) => /* @__PURE__ */ jsxs8(
580
+ "li",
581
+ {
582
+ className: "flex items-center",
583
+ "aria-current": step.status === "active" ? "step" : void 0,
584
+ children: [
585
+ /* @__PURE__ */ jsxs8("span", { className: "flex items-center gap-1.5", children: [
586
+ /* @__PURE__ */ jsx9(StepIndicator, { status: step.status }),
587
+ /* @__PURE__ */ jsx9("span", { className: clsx10("text-body-xs whitespace-nowrap", labelClass[step.status]), children: step.label })
588
+ ] }),
589
+ i < steps.length - 1 && /* @__PURE__ */ jsx9(ChevronSeparator, {})
590
+ ]
591
+ },
592
+ i
593
+ ))
594
+ }
595
+ );
596
+ }
597
+
598
+ // src/components/multiselect-card.tsx
599
+ import clsx11 from "clsx";
600
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
601
+ function MultiSelectCard({
602
+ icon,
603
+ title,
604
+ description,
605
+ selected,
606
+ onToggle,
607
+ className
608
+ }) {
609
+ return /* @__PURE__ */ jsxs9(
610
+ "button",
611
+ {
612
+ type: "button",
613
+ role: "checkbox",
614
+ "aria-checked": selected,
615
+ onClick: onToggle,
616
+ className: clsx11(
617
+ "relative w-full rounded-2xl border-2 p-4 text-left transition-all",
618
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-brand focus-visible:ring-offset-1",
619
+ selected ? "border-border-brand bg-background-brand-tertiary" : "border-border-default bg-background-default hover:border-border-default-secondary",
620
+ className
621
+ ),
622
+ children: [
623
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-start justify-between gap-2", children: [
624
+ /* @__PURE__ */ jsx10(
625
+ "span",
626
+ {
627
+ className: clsx11(
628
+ "flex size-10 shrink-0 items-center justify-center rounded-xl",
629
+ selected ? "bg-background-brand" : "bg-background-brand-tertiary"
630
+ ),
631
+ children: /* @__PURE__ */ jsx10("span", { className: clsx11("size-5", selected ? "text-icon-brand-on-brand" : "text-icon-brand"), children: icon })
632
+ }
633
+ ),
634
+ selected ? /* @__PURE__ */ jsx10("span", { className: "flex size-5 shrink-0 items-center justify-center rounded-full bg-background-brand", children: /* @__PURE__ */ jsx10("svg", { width: "11", height: "8", viewBox: "0 0 11 8", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx10(
635
+ "path",
636
+ {
637
+ d: "M1 4L3.9 7L10 1",
638
+ stroke: "white",
639
+ strokeWidth: "1.5",
640
+ strokeLinecap: "round",
641
+ strokeLinejoin: "round"
642
+ }
643
+ ) }) }) : /* @__PURE__ */ jsx10(
644
+ "span",
645
+ {
646
+ className: "size-5 shrink-0 rounded-full border-2 border-border-default",
647
+ "aria-hidden": "true"
648
+ }
649
+ )
650
+ ] }),
651
+ /* @__PURE__ */ jsxs9("div", { className: "mt-3", children: [
652
+ /* @__PURE__ */ jsx10(
653
+ "p",
654
+ {
655
+ className: clsx11(
656
+ "text-body-sm font-semibold",
657
+ selected ? "text-text-brand" : "text-text-default"
658
+ ),
659
+ children: title
660
+ }
661
+ ),
662
+ description && /* @__PURE__ */ jsx10("p", { className: "mt-0.5 text-body-xs text-text-default-secondary", children: description })
663
+ ] })
664
+ ]
665
+ }
666
+ );
667
+ }
668
+
669
+ // src/components/data-table.tsx
670
+ import clsx12 from "clsx";
671
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
672
+ function DataTable({
673
+ columns,
674
+ rows,
675
+ getRowKey,
676
+ className,
677
+ onRowClick
678
+ }) {
679
+ return /* @__PURE__ */ jsxs10(
680
+ "div",
681
+ {
682
+ className: clsx12(
683
+ "overflow-hidden rounded-xl border border-border-default bg-background-default",
684
+ className
685
+ ),
686
+ children: [
687
+ /* @__PURE__ */ jsx11("div", { className: "flex items-center bg-background-default-secondary px-4 py-3", children: columns.map((col) => /* @__PURE__ */ jsx11("div", { className: clsx12("overflow-hidden", col.grow ? "flex-1 min-w-0" : "shrink-0"), style: col.grow ? { minWidth: col.width } : { width: col.width }, children: /* @__PURE__ */ jsx11("span", { className: "text-body-xs font-medium text-text-default-secondary whitespace-nowrap", children: col.header }) }, col.key)) }),
688
+ /* @__PURE__ */ jsx11("div", { children: rows.map((row, i) => /* @__PURE__ */ jsx11(
689
+ "div",
690
+ {
691
+ className: clsx12(
692
+ "flex items-center px-4 py-[14px] transition-colors hover:bg-background-default-secondary/50",
693
+ i > 0 && "border-t border-[#ececec]",
694
+ onRowClick && "cursor-pointer"
695
+ ),
696
+ onClick: onRowClick ? () => onRowClick(row) : void 0,
697
+ children: columns.map((col) => /* @__PURE__ */ jsx11("div", { className: clsx12("overflow-hidden", col.grow ? "flex-1 min-w-0" : "shrink-0"), style: col.grow ? { minWidth: col.width } : { width: col.width }, children: col.render(row) }, col.key))
698
+ },
699
+ getRowKey(row, i)
700
+ )) })
701
+ ]
702
+ }
703
+ );
704
+ }
705
+ function TableCellLeadText({
706
+ primary,
707
+ secondary
708
+ }) {
709
+ return /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-0.5", children: [
710
+ /* @__PURE__ */ jsx11("span", { className: "text-body-sm font-medium text-text-default leading-snug", children: primary }),
711
+ secondary && /* @__PURE__ */ jsx11("span", { className: "text-body-xs font-normal text-text-default-secondary leading-tight", children: secondary })
712
+ ] });
713
+ }
714
+ function TableCellText({
715
+ children,
716
+ muted = true
717
+ }) {
718
+ return /* @__PURE__ */ jsx11(
719
+ "span",
720
+ {
721
+ className: clsx12(
722
+ "text-body-xs font-normal leading-snug whitespace-nowrap",
723
+ muted ? "text-text-default-secondary" : "text-text-default"
724
+ ),
725
+ children
726
+ }
727
+ );
728
+ }
729
+ function TableCellBadge({ label }) {
730
+ return /* @__PURE__ */ jsx11("span", { className: "inline-flex items-center rounded-md border border-border-default bg-background-default-secondary px-2 py-0.5 text-body-tiny font-medium text-text-default-secondary whitespace-nowrap", children: label });
731
+ }
732
+ function TableCellStatusPill({
733
+ label,
734
+ dotColor,
735
+ backgroundColor,
736
+ textColor
737
+ }) {
738
+ return /* @__PURE__ */ jsxs10(
739
+ "span",
740
+ {
741
+ className: "inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-body-xs font-medium leading-tight whitespace-nowrap",
742
+ style: { backgroundColor, color: textColor },
743
+ children: [
744
+ /* @__PURE__ */ jsx11("span", { className: "size-1.5 shrink-0 rounded-full", style: { backgroundColor: dotColor } }),
745
+ label
746
+ ]
747
+ }
748
+ );
749
+ }
750
+ function TableCellProgress({
751
+ percent,
752
+ barColor
753
+ }) {
754
+ const color = barColor ?? "#0c2d58";
755
+ const clamped = Math.min(100, Math.max(0, percent));
756
+ return /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-1", children: [
757
+ /* @__PURE__ */ jsx11("div", { className: "h-1.5 w-16 overflow-hidden rounded-full bg-background-default-secondary", children: /* @__PURE__ */ jsx11(
758
+ "div",
759
+ {
760
+ className: "h-full rounded-full transition-all",
761
+ style: { width: `${clamped}%`, backgroundColor: color }
762
+ }
763
+ ) }),
764
+ /* @__PURE__ */ jsxs10("span", { className: "text-body-tiny text-text-default-secondary leading-none", children: [
765
+ percent,
766
+ "%"
767
+ ] })
768
+ ] });
769
+ }
770
+
771
+ // src/components/stat-tile.tsx
772
+ import clsx13 from "clsx";
773
+ import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
774
+ function StatTile({ label, value, dotColor, className }) {
775
+ return /* @__PURE__ */ jsxs11(
776
+ "div",
777
+ {
778
+ className: clsx13(
779
+ "flex flex-col gap-2 rounded-xl border border-border-default bg-background-default p-4",
780
+ className
781
+ ),
782
+ children: [
783
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5", children: [
784
+ dotColor && /* @__PURE__ */ jsx12("span", { className: "size-2 shrink-0 rounded-full", style: { backgroundColor: dotColor } }),
785
+ /* @__PURE__ */ jsx12("span", { className: "text-body-xs font-medium text-text-default-secondary whitespace-nowrap", children: label })
786
+ ] }),
787
+ /* @__PURE__ */ jsx12("span", { className: "text-heading font-semibold text-text-default leading-none", children: value })
788
+ ]
789
+ }
790
+ );
791
+ }
792
+
793
+ // src/components/toggle.tsx
794
+ import clsx14 from "clsx";
795
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
796
+ function Toggle({ checked, onChange, label, disabled = false }) {
797
+ return /* @__PURE__ */ jsxs12(
798
+ "button",
799
+ {
800
+ type: "button",
801
+ role: "switch",
802
+ "aria-checked": checked,
803
+ disabled,
804
+ onClick: () => onChange(!checked),
805
+ className: clsx14(
806
+ "flex items-center gap-2",
807
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-brand focus-visible:ring-offset-1",
808
+ disabled && "cursor-not-allowed opacity-50"
809
+ ),
810
+ children: [
811
+ /* @__PURE__ */ jsx13(
812
+ "span",
813
+ {
814
+ className: clsx14(
815
+ "relative inline-flex h-6 w-10 shrink-0 rounded-full transition-colors",
816
+ checked ? "bg-background-brand" : "border border-border-default bg-background-neutral-tertiary"
817
+ ),
818
+ children: /* @__PURE__ */ jsx13(
819
+ "span",
820
+ {
821
+ className: clsx14(
822
+ "absolute left-0.5 top-0.5 size-5 rounded-full bg-white shadow-sm transition-transform",
823
+ checked ? "translate-x-4" : "translate-x-0"
824
+ )
825
+ }
826
+ )
827
+ }
828
+ ),
829
+ label && /* @__PURE__ */ jsx13("span", { className: "text-body-xs text-text-default", children: label })
830
+ ]
831
+ }
832
+ );
833
+ }
834
+
835
+ // src/components/file-drop-zone.tsx
836
+ import { useRef, useState } from "react";
837
+ import clsx15 from "clsx";
838
+ import { LuUpload } from "react-icons/lu";
839
+ import { Fragment, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
840
+ function FileDropZone({ className }) {
841
+ const inputRef = useRef(null);
842
+ const [isDragging, setIsDragging] = useState(false);
843
+ return /* @__PURE__ */ jsxs13(Fragment, { children: [
844
+ /* @__PURE__ */ jsx14(
845
+ "input",
846
+ {
847
+ ref: inputRef,
848
+ type: "file",
849
+ accept: ".pdf,.jpg,.jpeg,.png",
850
+ className: "sr-only",
851
+ tabIndex: -1
852
+ }
853
+ ),
854
+ /* @__PURE__ */ jsxs13(
855
+ "div",
856
+ {
857
+ role: "button",
858
+ tabIndex: 0,
859
+ onClick: () => inputRef.current?.click(),
860
+ onKeyDown: (e) => (e.key === "Enter" || e.key === " ") && inputRef.current?.click(),
861
+ onDragOver: (e) => {
862
+ e.preventDefault();
863
+ setIsDragging(true);
864
+ },
865
+ onDragEnter: (e) => {
866
+ e.preventDefault();
867
+ setIsDragging(true);
868
+ },
869
+ onDragLeave: () => setIsDragging(false),
870
+ onDrop: (e) => {
871
+ e.preventDefault();
872
+ setIsDragging(false);
873
+ },
874
+ className: clsx15(
875
+ "flex flex-col items-center justify-center gap-1 rounded-lg border-2 border-dashed py-4 px-4 cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-brand focus-visible:ring-offset-1",
876
+ isDragging ? "border-border-brand bg-background-brand-tertiary" : "border-border-default bg-background-default-secondary hover:border-border-brand hover:bg-background-brand-tertiary",
877
+ className
878
+ ),
879
+ children: [
880
+ /* @__PURE__ */ jsx14("span", { className: isDragging ? "text-text-brand" : "text-text-default-secondary", children: /* @__PURE__ */ jsx14(LuUpload, { size: 20 }) }),
881
+ /* @__PURE__ */ jsx14("span", { className: "text-body-sm font-medium text-text-default", children: "Upload file" }),
882
+ /* @__PURE__ */ jsx14("span", { className: "text-body-xs text-text-default-secondary text-center", children: "Drag & drop or browse \xB7 PDF, JPG, PNG \xB7 up to 10 MB" })
883
+ ]
884
+ }
885
+ )
886
+ ] });
887
+ }
888
+
889
+ // src/components/form-card.tsx
890
+ import clsx16 from "clsx";
891
+ import { LuArrowLeft, LuArrowRight } from "react-icons/lu";
892
+ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
893
+ function FormCard({
894
+ children,
895
+ className
896
+ }) {
897
+ return /* @__PURE__ */ jsx15(
898
+ "div",
899
+ {
900
+ className: clsx16(
901
+ "overflow-hidden rounded-xl border border-border-default bg-background-default",
902
+ className
903
+ ),
904
+ children
905
+ }
906
+ );
907
+ }
908
+ function FormCardHeader({ title, subtitle }) {
909
+ return /* @__PURE__ */ jsxs14("div", { className: "border-b border-border-default px-7 py-6", children: [
910
+ /* @__PURE__ */ jsx15("h2", { className: "text-heading-sm font-semibold text-text-default leading-snug", children: title }),
911
+ subtitle && /* @__PURE__ */ jsx15("p", { className: "mt-1 text-body-xs text-text-default-secondary", children: subtitle })
912
+ ] });
913
+ }
914
+ function FormCardFooter({
915
+ onSaveDraft,
916
+ onBack,
917
+ onContinue,
918
+ continueLabel = "Continue",
919
+ backDisabled = false
920
+ }) {
921
+ return /* @__PURE__ */ jsxs14("div", { className: "flex items-center justify-between border-t border-border-default px-7 py-5", children: [
922
+ /* @__PURE__ */ jsx15(Button, { variant: "neutral", size: "md", onClick: onSaveDraft, children: "Save as draft" }),
923
+ /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2", children: [
924
+ !backDisabled && /* @__PURE__ */ jsx15(Button, { variant: "neutral", size: "md", leadingIcon: /* @__PURE__ */ jsx15(LuArrowLeft, { size: 16 }), onClick: onBack, children: "Back" }),
925
+ /* @__PURE__ */ jsx15(Button, { variant: "primary", size: "md", trailingIcon: /* @__PURE__ */ jsx15(LuArrowRight, { size: 16 }), onClick: onContinue, children: continueLabel })
926
+ ] })
927
+ ] });
928
+ }
929
+
930
+ // src/components/document-row.tsx
931
+ import clsx17 from "clsx";
932
+ import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
933
+ var STATUS_CONFIG = {
934
+ uploaded: { label: "\u2713 Uploaded", style: "bg-[#e6f4ea] text-[#1f7a3d]" },
935
+ "under-review": { label: "\u25CF Under review", style: "bg-[#fbe6cf] text-[#9a6206]" },
936
+ processing: { label: "\u25CF Processing", style: "bg-[#e9eff7] text-[#0c2d58]" },
937
+ missing: { label: "Missing", style: "bg-[#fee2e2] text-[#b91c1c]" },
938
+ "not-provided": { label: "Not provided", style: "bg-background-default-secondary text-text-default-secondary" }
939
+ };
940
+ function FileTypeBadge({ type }) {
941
+ return /* @__PURE__ */ jsx16("div", { className: "flex h-[34px] w-[34px] shrink-0 items-center justify-center rounded-md bg-background-brand-tertiary", children: /* @__PURE__ */ jsx16("span", { className: "text-body-tiny font-semibold text-text-brand", children: type }) });
942
+ }
943
+ function DocumentRow({
944
+ title,
945
+ required,
946
+ description,
947
+ status,
948
+ fileName,
949
+ fileSize,
950
+ fileType = "PDF"
951
+ }) {
952
+ const hasFile = (status === "uploaded" || status === "under-review" || status === "processing") && !!fileName;
953
+ const cfg = STATUS_CONFIG[status];
954
+ return /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-3 py-4", children: [
955
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center justify-between gap-2", children: [
956
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2 min-w-0", children: [
957
+ /* @__PURE__ */ jsx16("span", { className: "text-body-sm font-semibold text-text-default truncate", children: title }),
958
+ /* @__PURE__ */ jsx16("span", { className: "shrink-0 rounded-md border border-border-default bg-background-default-secondary px-2 py-0.5 text-body-tiny font-medium text-text-default-secondary", children: required ? "Required" : "Optional" })
959
+ ] }),
960
+ /* @__PURE__ */ jsx16(
961
+ "span",
962
+ {
963
+ className: clsx17(
964
+ "shrink-0 rounded-full px-2.5 py-0.5 text-body-tiny font-medium whitespace-nowrap",
965
+ cfg.style
966
+ ),
967
+ children: cfg.label
968
+ }
969
+ )
970
+ ] }),
971
+ /* @__PURE__ */ jsx16("p", { className: "text-body-xs text-text-default-secondary", children: description }),
972
+ hasFile ? /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-3 rounded-lg border border-border-default bg-background-default px-3 py-2.5", children: [
973
+ /* @__PURE__ */ jsx16(FileTypeBadge, { type: fileType }),
974
+ /* @__PURE__ */ jsxs15("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
975
+ /* @__PURE__ */ jsx16("span", { className: "truncate text-body-sm font-medium text-text-default", children: fileName }),
976
+ fileSize && /* @__PURE__ */ jsx16("span", { className: "text-body-xs text-text-default-secondary", children: fileSize })
977
+ ] }),
978
+ /* @__PURE__ */ jsxs15("div", { className: "flex shrink-0 items-center gap-4", children: [
979
+ /* @__PURE__ */ jsx16(
980
+ "button",
981
+ {
982
+ type: "button",
983
+ className: "text-body-xs font-medium text-text-brand hover:underline",
984
+ children: "Replace"
985
+ }
986
+ ),
987
+ /* @__PURE__ */ jsx16(
988
+ "button",
989
+ {
990
+ type: "button",
991
+ className: "text-body-xs font-medium text-text-danger hover:underline",
992
+ children: "Remove"
993
+ }
994
+ )
995
+ ] })
996
+ ] }) : /* @__PURE__ */ jsx16(FileDropZone, {})
997
+ ] });
998
+ }
999
+
1000
+ // src/components/modal.tsx
1001
+ import clsx18 from "clsx";
1002
+ import { LuX } from "react-icons/lu";
1003
+ import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
1004
+ function Modal({ isOpen, onClose, title, subtitle, children, footer, maxWidth = "max-w-[540px]" }) {
1005
+ if (!isOpen) return null;
1006
+ return /* @__PURE__ */ jsx17(
1007
+ "div",
1008
+ {
1009
+ className: "fixed inset-0 z-50 flex items-center justify-center bg-black/80",
1010
+ onClick: (e) => {
1011
+ if (e.target === e.currentTarget) onClose();
1012
+ },
1013
+ children: /* @__PURE__ */ jsxs16("div", { className: clsx18("w-full mx-4 rounded-2xl bg-white shadow-xl", maxWidth), children: [
1014
+ /* @__PURE__ */ jsxs16("div", { className: "flex items-start justify-between px-6 py-5", children: [
1015
+ /* @__PURE__ */ jsxs16("div", { children: [
1016
+ /* @__PURE__ */ jsx17("h2", { className: "text-heading-sm font-semibold text-text-default", children: title }),
1017
+ subtitle && /* @__PURE__ */ jsx17("p", { className: "mt-0.5 text-body-xs text-text-default-secondary", children: subtitle })
1018
+ ] }),
1019
+ /* @__PURE__ */ jsx17(
1020
+ IconButton,
1021
+ {
1022
+ variant: "subtle",
1023
+ size: "sm",
1024
+ "aria-label": "Close dialog",
1025
+ icon: /* @__PURE__ */ jsx17(LuX, { size: 16 }),
1026
+ onClick: onClose
1027
+ }
1028
+ )
1029
+ ] }),
1030
+ /* @__PURE__ */ jsx17("hr", { className: "border-border-default" }),
1031
+ /* @__PURE__ */ jsx17("div", { className: "px-6 py-5", children }),
1032
+ footer && /* @__PURE__ */ jsxs16(Fragment2, { children: [
1033
+ /* @__PURE__ */ jsx17("hr", { className: "border-border-default" }),
1034
+ /* @__PURE__ */ jsx17("div", { className: "flex items-center justify-end gap-2 px-6 py-4", children: footer })
1035
+ ] })
1036
+ ] })
1037
+ }
1038
+ );
1039
+ }
1040
+
1041
+ // src/components/role-badge.tsx
1042
+ import clsx19 from "clsx";
1043
+ import { jsx as jsx18 } from "react/jsx-runtime";
1044
+ var ROLE_COLORS = {
1045
+ "Super Admin": { bg: "#e9eff7", text: "#0c2d58" },
1046
+ "Admin": { bg: "#e9eff7", text: "#0c2d58" },
1047
+ "Compliance Lead": { bg: "#ece6f7", text: "#5b3da8" },
1048
+ "Reviewer": { bg: "#dbeafe", text: "#1d4ed8" },
1049
+ "Requester": { bg: "#e6f4ea", text: "#1f7a3d" },
1050
+ "Entity Manager": { bg: "#fbe6cf", text: "#9a6206" },
1051
+ "Intelligence Analyst": { bg: "#fde2e7", text: "#a3284a" },
1052
+ "Auditor": { bg: "#f5f5f5", text: "#757575" },
1053
+ "Viewer": { bg: "#f5f5f5", text: "#757575" },
1054
+ "User": { bg: "#e9eff7", text: "#0c2d58" }
1055
+ };
1056
+ var FALLBACK = { bg: "#f5f5f5", text: "#757575" };
1057
+ function RoleBadge({ role, size = "sm" }) {
1058
+ const colors = ROLE_COLORS[role] ?? FALLBACK;
1059
+ return /* @__PURE__ */ jsx18(
1060
+ "span",
1061
+ {
1062
+ className: clsx19(
1063
+ "inline-flex items-center rounded-full font-medium whitespace-nowrap",
1064
+ size === "sm" ? "px-2 py-0.5 text-body-tiny" : "px-3 py-1 text-body-xs"
1065
+ ),
1066
+ style: { backgroundColor: colors.bg, color: colors.text },
1067
+ children: role
1068
+ }
1069
+ );
1070
+ }
1071
+
1072
+ // src/components/role-combo-box.tsx
1073
+ import { useEffect, useRef as useRef2, useState as useState2 } from "react";
1074
+ import { LuChevronDown as LuChevronDown2 } from "react-icons/lu";
1075
+ import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
1076
+ var ROLE_COMBO_OPTIONS = [
1077
+ { role: "Reviewer", description: "Reviews onboarding requests" },
1078
+ { role: "Admin", description: "Full org control" },
1079
+ { role: "Compliance Lead", description: "Owns compliance" },
1080
+ { role: "Requester", description: "Creates onboarding requests" },
1081
+ { role: "Viewer", description: "Read-only access" },
1082
+ { role: "User", description: "Default user access" }
1083
+ ];
1084
+ function RoleComboBox({ value, onChange, options = ROLE_COMBO_OPTIONS }) {
1085
+ const [open, setOpen] = useState2(false);
1086
+ const [query, setQuery] = useState2("");
1087
+ const containerRef = useRef2(null);
1088
+ const inputRef = useRef2(null);
1089
+ useEffect(() => {
1090
+ if (!open) return;
1091
+ function onClickOutside(e) {
1092
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
1093
+ setOpen(false);
1094
+ setQuery("");
1095
+ }
1096
+ }
1097
+ document.addEventListener("mousedown", onClickOutside);
1098
+ return () => document.removeEventListener("mousedown", onClickOutside);
1099
+ }, [open]);
1100
+ function openDropdown() {
1101
+ setOpen(true);
1102
+ setQuery("");
1103
+ setTimeout(() => inputRef.current?.focus(), 0);
1104
+ }
1105
+ function select(role) {
1106
+ onChange(role);
1107
+ setOpen(false);
1108
+ setQuery("");
1109
+ }
1110
+ const selectedEntry = options.find((o) => o.role === value);
1111
+ const otherOptions = options.filter(
1112
+ (o) => o.role !== value && o.role.toLowerCase().includes(query.toLowerCase())
1113
+ );
1114
+ return /* @__PURE__ */ jsxs17("div", { className: "relative", ref: containerRef, children: [
1115
+ /* @__PURE__ */ jsxs17(
1116
+ "div",
1117
+ {
1118
+ role: "combobox",
1119
+ "aria-expanded": open,
1120
+ "aria-haspopup": "listbox",
1121
+ onClick: openDropdown,
1122
+ className: `flex h-11 cursor-pointer items-center gap-2 rounded-lg border-[1.5px] pl-2.5 pr-3 transition-colors ${open ? "border-blue-500" : "border-border-default hover:border-border-brand-tertiary"}`,
1123
+ children: [
1124
+ /* @__PURE__ */ jsxs17("div", { className: "flex flex-1 min-w-0 items-center gap-1.5 overflow-hidden", children: [
1125
+ /* @__PURE__ */ jsx19(RoleBadge, { role: value, size: "sm" }),
1126
+ value === "User" && !open && /* @__PURE__ */ jsx19("span", { className: "rounded border border-border-default bg-background-default-secondary px-1.5 py-0.5 text-body-tiny font-medium text-text-default-secondary", children: "DEFAULT" }),
1127
+ open && /* @__PURE__ */ jsxs17(Fragment3, { children: [
1128
+ /* @__PURE__ */ jsx19(
1129
+ "input",
1130
+ {
1131
+ ref: inputRef,
1132
+ type: "text",
1133
+ value: query,
1134
+ onChange: (e) => setQuery(e.target.value),
1135
+ onClick: (e) => e.stopPropagation(),
1136
+ className: "min-w-0 flex-1 bg-transparent text-body-xs text-text-default outline-none",
1137
+ "aria-label": "Search roles"
1138
+ }
1139
+ ),
1140
+ /* @__PURE__ */ jsx19("span", { className: "mx-0.5 h-[18px] w-px shrink-0 bg-text-default", "aria-hidden": true })
1141
+ ] })
1142
+ ] }),
1143
+ /* @__PURE__ */ jsx19("span", { className: "shrink-0 text-text-default-secondary", children: /* @__PURE__ */ jsx19(LuChevronDown2, { size: 14 }) })
1144
+ ]
1145
+ }
1146
+ ),
1147
+ open && /* @__PURE__ */ jsxs17(
1148
+ "div",
1149
+ {
1150
+ role: "listbox",
1151
+ className: "absolute left-0 right-0 top-full z-20 mt-1 flex max-h-64 flex-col gap-0.5 overflow-y-auto rounded-xl border border-border-default bg-white p-1.5 shadow-lg",
1152
+ children: [
1153
+ selectedEntry && /* @__PURE__ */ jsxs17(
1154
+ "div",
1155
+ {
1156
+ role: "option",
1157
+ "aria-selected": true,
1158
+ className: "flex cursor-pointer items-center gap-2.5 rounded-md bg-blue-50 px-2.5 py-2",
1159
+ onClick: () => select(selectedEntry.role),
1160
+ children: [
1161
+ /* @__PURE__ */ jsx19(RoleBadge, { role: selectedEntry.role, size: "sm" }),
1162
+ /* @__PURE__ */ jsx19("span", { className: "flex-1 text-body-xs text-text-default-secondary", children: selectedEntry.description }),
1163
+ /* @__PURE__ */ jsx19("span", { className: "shrink-0 text-sm font-bold text-blue-600", children: "\u2713" })
1164
+ ]
1165
+ }
1166
+ ),
1167
+ /* @__PURE__ */ jsx19("div", { className: "h-px bg-border-default" }),
1168
+ otherOptions.length > 0 && /* @__PURE__ */ jsxs17(Fragment3, { children: [
1169
+ /* @__PURE__ */ jsx19("div", { className: "px-2.5 pb-1 pt-1.5", children: /* @__PURE__ */ jsx19("span", { className: "text-body-tiny font-semibold uppercase tracking-wide text-text-default-secondary", children: "Other roles" }) }),
1170
+ otherOptions.map((opt) => /* @__PURE__ */ jsxs17(
1171
+ "div",
1172
+ {
1173
+ role: "option",
1174
+ "aria-selected": false,
1175
+ className: "flex cursor-pointer items-center gap-2.5 rounded-md px-2.5 py-2 hover:bg-background-default-secondary",
1176
+ onClick: () => select(opt.role),
1177
+ children: [
1178
+ /* @__PURE__ */ jsx19(RoleBadge, { role: opt.role, size: "sm" }),
1179
+ /* @__PURE__ */ jsx19("span", { className: "text-body-xs text-text-default-secondary", children: opt.description })
1180
+ ]
1181
+ },
1182
+ opt.role
1183
+ ))
1184
+ ] }),
1185
+ otherOptions.length === 0 && query && /* @__PURE__ */ jsxs17("p", { className: "px-2.5 py-2 text-body-xs text-text-default-secondary", children: [
1186
+ 'No roles match "',
1187
+ query,
1188
+ '"'
1189
+ ] })
1190
+ ]
1191
+ }
1192
+ )
1193
+ ] });
1194
+ }
1195
+
1196
+ // src/index.tsx
1197
+ import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
1198
+ function Panel({
1199
+ children,
1200
+ className
1201
+ }) {
1202
+ return /* @__PURE__ */ jsx20("section", { className: clsx20("rounded-3xl border border-white/70 bg-white/90 p-6 shadow-panel backdrop-blur", className), children });
1203
+ }
1204
+ function MetricCard({
1205
+ label,
1206
+ value,
1207
+ tone = "default"
1208
+ }) {
1209
+ const tones = {
1210
+ default: "from-white to-slate-50 text-text-default",
1211
+ signal: "from-background-brand-tertiary to-cyan-50 text-text-brand",
1212
+ ember: "from-amber-50 to-orange-50 text-text-danger",
1213
+ moss: "from-emerald-50 to-lime-50 text-text-positive"
1214
+ };
1215
+ return /* @__PURE__ */ jsxs18(Panel, { className: clsx20("bg-gradient-to-br", tones[tone]), children: [
1216
+ /* @__PURE__ */ jsx20("p", { className: "text-sm uppercase tracking-[0.2em] text-slate-500", children: label }),
1217
+ /* @__PURE__ */ jsx20("p", { className: "mt-3 text-3xl font-semibold", children: value })
1218
+ ] });
1219
+ }
1220
+ function SeverityBadge({ severity }) {
1221
+ const styles = {
1222
+ critical: "bg-red-100 text-red-700",
1223
+ high: "bg-orange-100 text-orange-700",
1224
+ medium: "bg-amber-100 text-amber-700",
1225
+ low: "bg-slate-100 text-slate-700"
1226
+ };
1227
+ return /* @__PURE__ */ jsx20("span", { className: clsx20("inline-flex rounded-full px-3 py-1 text-xs font-semibold uppercase tracking-wide", styles[severity ?? "low"]), children: severity ?? "unknown" });
1228
+ }
1229
+ function SentimentBadge({ sentiment }) {
1230
+ const styles = {
1231
+ positive: "bg-emerald-100 text-emerald-700",
1232
+ neutral: "bg-slate-100 text-slate-700",
1233
+ negative: "bg-rose-100 text-rose-700",
1234
+ concerning: "bg-amber-100 text-amber-700"
1235
+ };
1236
+ return /* @__PURE__ */ jsx20("span", { className: clsx20("inline-flex rounded-full px-3 py-1 text-xs font-semibold capitalize", styles[sentiment ?? "neutral"] ?? styles.neutral), children: sentiment ?? "unknown" });
1237
+ }
1238
+ function SectionHeading({
1239
+ eyebrow,
1240
+ title,
1241
+ detail
1242
+ }) {
1243
+ return /* @__PURE__ */ jsxs18("div", { children: [
1244
+ /* @__PURE__ */ jsx20("p", { className: "text-xs uppercase tracking-[0.25em] text-text-brand", children: eyebrow }),
1245
+ /* @__PURE__ */ jsx20("h2", { className: "mt-2 text-2xl font-semibold text-text-default", children: title }),
1246
+ detail ? /* @__PURE__ */ jsx20("p", { className: "mt-2 max-w-2xl text-sm text-slate-600", children: detail }) : null
1247
+ ] });
1248
+ }
1249
+ export {
1250
+ Avatar,
1251
+ AvatarGroup,
1252
+ Button,
1253
+ ButtonGroup,
1254
+ DataTable,
1255
+ DocumentRow,
1256
+ FileDropZone,
1257
+ FormCard,
1258
+ FormCardFooter,
1259
+ FormCardHeader,
1260
+ IconButton,
1261
+ Input,
1262
+ MetricCard,
1263
+ Modal,
1264
+ MultiSelectCard,
1265
+ NavItem,
1266
+ Panel,
1267
+ ROLE_COMBO_OPTIONS,
1268
+ RoleBadge,
1269
+ RoleComboBox,
1270
+ SectionHeading,
1271
+ Select,
1272
+ SentimentBadge,
1273
+ SeverityBadge,
1274
+ StatTile,
1275
+ Stepper,
1276
+ TableCellBadge,
1277
+ TableCellLeadText,
1278
+ TableCellProgress,
1279
+ TableCellStatusPill,
1280
+ TableCellText,
1281
+ Textarea,
1282
+ Toggle
1283
+ };
1284
+ //# sourceMappingURL=index.js.map