myoperator-mcp 0.2.24 → 0.2.25
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 +887 -753
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8,11 +8,11 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
8
8
|
|
|
9
9
|
// src/data/metadata.ts
|
|
10
10
|
var componentSourceCode = {
|
|
11
|
-
"accordion": `import * as React from "react"
|
|
12
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
13
|
-
import { ChevronDown } from "lucide-react"
|
|
11
|
+
"accordion": `import * as React from "react";
|
|
12
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
13
|
+
import { ChevronDown } from "lucide-react";
|
|
14
14
|
|
|
15
|
-
import { cn } from "@/lib/utils"
|
|
15
|
+
import { cn } from "@/lib/utils";
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Accordion root variants
|
|
@@ -27,7 +27,7 @@ const accordionVariants = cva("w-full", {
|
|
|
27
27
|
defaultVariants: {
|
|
28
28
|
variant: "default",
|
|
29
29
|
},
|
|
30
|
-
})
|
|
30
|
+
});
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Accordion item variants
|
|
@@ -42,7 +42,7 @@ const accordionItemVariants = cva("", {
|
|
|
42
42
|
defaultVariants: {
|
|
43
43
|
variant: "default",
|
|
44
44
|
},
|
|
45
|
-
})
|
|
45
|
+
});
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* Accordion trigger variants
|
|
@@ -60,7 +60,7 @@ const accordionTriggerVariants = cva(
|
|
|
60
60
|
variant: "default",
|
|
61
61
|
},
|
|
62
62
|
}
|
|
63
|
-
)
|
|
63
|
+
);
|
|
64
64
|
|
|
65
65
|
/**
|
|
66
66
|
* Accordion content variants
|
|
@@ -78,58 +78,64 @@ const accordionContentVariants = cva(
|
|
|
78
78
|
variant: "default",
|
|
79
79
|
},
|
|
80
80
|
}
|
|
81
|
-
)
|
|
81
|
+
);
|
|
82
82
|
|
|
83
83
|
// Types
|
|
84
|
-
type AccordionType = "single" | "multiple"
|
|
84
|
+
type AccordionType = "single" | "multiple";
|
|
85
85
|
|
|
86
86
|
interface AccordionContextValue {
|
|
87
|
-
type: AccordionType
|
|
88
|
-
value: string[]
|
|
89
|
-
onValueChange: (value: string[]) => void
|
|
90
|
-
variant: "default" | "bordered"
|
|
87
|
+
type: AccordionType;
|
|
88
|
+
value: string[];
|
|
89
|
+
onValueChange: (value: string[]) => void;
|
|
90
|
+
variant: "default" | "bordered";
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
interface AccordionItemContextValue {
|
|
94
|
-
value: string
|
|
95
|
-
isOpen: boolean
|
|
96
|
-
disabled?: boolean
|
|
94
|
+
value: string;
|
|
95
|
+
isOpen: boolean;
|
|
96
|
+
disabled?: boolean;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
// Contexts
|
|
100
|
-
const AccordionContext = React.createContext<AccordionContextValue | null>(
|
|
101
|
-
|
|
100
|
+
const AccordionContext = React.createContext<AccordionContextValue | null>(
|
|
101
|
+
null
|
|
102
|
+
);
|
|
103
|
+
const AccordionItemContext =
|
|
104
|
+
React.createContext<AccordionItemContextValue | null>(null);
|
|
102
105
|
|
|
103
106
|
function useAccordionContext() {
|
|
104
|
-
const context = React.useContext(AccordionContext)
|
|
107
|
+
const context = React.useContext(AccordionContext);
|
|
105
108
|
if (!context) {
|
|
106
|
-
throw new Error("Accordion components must be used within an Accordion")
|
|
109
|
+
throw new Error("Accordion components must be used within an Accordion");
|
|
107
110
|
}
|
|
108
|
-
return context
|
|
111
|
+
return context;
|
|
109
112
|
}
|
|
110
113
|
|
|
111
114
|
function useAccordionItemContext() {
|
|
112
|
-
const context = React.useContext(AccordionItemContext)
|
|
115
|
+
const context = React.useContext(AccordionItemContext);
|
|
113
116
|
if (!context) {
|
|
114
|
-
throw new Error(
|
|
117
|
+
throw new Error(
|
|
118
|
+
"AccordionTrigger/AccordionContent must be used within an AccordionItem"
|
|
119
|
+
);
|
|
115
120
|
}
|
|
116
|
-
return context
|
|
121
|
+
return context;
|
|
117
122
|
}
|
|
118
123
|
|
|
119
124
|
/**
|
|
120
125
|
* Root accordion component that manages state
|
|
121
126
|
*/
|
|
122
127
|
export interface AccordionProps
|
|
123
|
-
extends
|
|
128
|
+
extends
|
|
129
|
+
React.HTMLAttributes<HTMLDivElement>,
|
|
124
130
|
VariantProps<typeof accordionVariants> {
|
|
125
131
|
/** Whether only one item can be open at a time ('single') or multiple ('multiple') */
|
|
126
|
-
type?: AccordionType
|
|
132
|
+
type?: AccordionType;
|
|
127
133
|
/** Controlled value - array of open item values */
|
|
128
|
-
value?: string[]
|
|
134
|
+
value?: string[];
|
|
129
135
|
/** Default open items for uncontrolled usage */
|
|
130
|
-
defaultValue?: string[]
|
|
136
|
+
defaultValue?: string[];
|
|
131
137
|
/** Callback when open items change */
|
|
132
|
-
onValueChange?: (value: string[]) => void
|
|
138
|
+
onValueChange?: (value: string[]) => void;
|
|
133
139
|
}
|
|
134
140
|
|
|
135
141
|
const Accordion = React.forwardRef<HTMLDivElement, AccordionProps>(
|
|
@@ -146,20 +152,21 @@ const Accordion = React.forwardRef<HTMLDivElement, AccordionProps>(
|
|
|
146
152
|
},
|
|
147
153
|
ref
|
|
148
154
|
) => {
|
|
149
|
-
const [internalValue, setInternalValue] =
|
|
155
|
+
const [internalValue, setInternalValue] =
|
|
156
|
+
React.useState<string[]>(defaultValue);
|
|
150
157
|
|
|
151
|
-
const isControlled = controlledValue !== undefined
|
|
152
|
-
const currentValue = isControlled ? controlledValue : internalValue
|
|
158
|
+
const isControlled = controlledValue !== undefined;
|
|
159
|
+
const currentValue = isControlled ? controlledValue : internalValue;
|
|
153
160
|
|
|
154
161
|
const handleValueChange = React.useCallback(
|
|
155
162
|
(newValue: string[]) => {
|
|
156
163
|
if (!isControlled) {
|
|
157
|
-
setInternalValue(newValue)
|
|
164
|
+
setInternalValue(newValue);
|
|
158
165
|
}
|
|
159
|
-
onValueChange?.(newValue)
|
|
166
|
+
onValueChange?.(newValue);
|
|
160
167
|
},
|
|
161
168
|
[isControlled, onValueChange]
|
|
162
|
-
)
|
|
169
|
+
);
|
|
163
170
|
|
|
164
171
|
const contextValue = React.useMemo(
|
|
165
172
|
() => ({
|
|
@@ -169,7 +176,7 @@ const Accordion = React.forwardRef<HTMLDivElement, AccordionProps>(
|
|
|
169
176
|
variant: variant || "default",
|
|
170
177
|
}),
|
|
171
178
|
[type, currentValue, handleValueChange, variant]
|
|
172
|
-
)
|
|
179
|
+
);
|
|
173
180
|
|
|
174
181
|
return (
|
|
175
182
|
<AccordionContext.Provider value={contextValue}>
|
|
@@ -181,27 +188,28 @@ const Accordion = React.forwardRef<HTMLDivElement, AccordionProps>(
|
|
|
181
188
|
{children}
|
|
182
189
|
</div>
|
|
183
190
|
</AccordionContext.Provider>
|
|
184
|
-
)
|
|
191
|
+
);
|
|
185
192
|
}
|
|
186
|
-
)
|
|
187
|
-
Accordion.displayName = "Accordion"
|
|
193
|
+
);
|
|
194
|
+
Accordion.displayName = "Accordion";
|
|
188
195
|
|
|
189
196
|
/**
|
|
190
197
|
* Individual accordion item
|
|
191
198
|
*/
|
|
192
199
|
export interface AccordionItemProps
|
|
193
|
-
extends
|
|
200
|
+
extends
|
|
201
|
+
React.HTMLAttributes<HTMLDivElement>,
|
|
194
202
|
VariantProps<typeof accordionItemVariants> {
|
|
195
203
|
/** Unique value for this item */
|
|
196
|
-
value: string
|
|
204
|
+
value: string;
|
|
197
205
|
/** Whether this item is disabled */
|
|
198
|
-
disabled?: boolean
|
|
206
|
+
disabled?: boolean;
|
|
199
207
|
}
|
|
200
208
|
|
|
201
209
|
const AccordionItem = React.forwardRef<HTMLDivElement, AccordionItemProps>(
|
|
202
210
|
({ className, value, disabled, children, ...props }, ref) => {
|
|
203
|
-
const { value: openValues, variant } = useAccordionContext()
|
|
204
|
-
const isOpen = openValues.includes(value)
|
|
211
|
+
const { value: openValues, variant } = useAccordionContext();
|
|
212
|
+
const isOpen = openValues.includes(value);
|
|
205
213
|
|
|
206
214
|
const contextValue = React.useMemo(
|
|
207
215
|
() => ({
|
|
@@ -210,7 +218,7 @@ const AccordionItem = React.forwardRef<HTMLDivElement, AccordionItemProps>(
|
|
|
210
218
|
disabled,
|
|
211
219
|
}),
|
|
212
220
|
[value, isOpen, disabled]
|
|
213
|
-
)
|
|
221
|
+
);
|
|
214
222
|
|
|
215
223
|
return (
|
|
216
224
|
<AccordionItemContext.Provider value={contextValue}>
|
|
@@ -223,106 +231,115 @@ const AccordionItem = React.forwardRef<HTMLDivElement, AccordionItemProps>(
|
|
|
223
231
|
{children}
|
|
224
232
|
</div>
|
|
225
233
|
</AccordionItemContext.Provider>
|
|
226
|
-
)
|
|
234
|
+
);
|
|
227
235
|
}
|
|
228
|
-
)
|
|
229
|
-
AccordionItem.displayName = "AccordionItem"
|
|
236
|
+
);
|
|
237
|
+
AccordionItem.displayName = "AccordionItem";
|
|
230
238
|
|
|
231
239
|
/**
|
|
232
240
|
* Trigger button that toggles the accordion item
|
|
233
241
|
*/
|
|
234
242
|
export interface AccordionTriggerProps
|
|
235
|
-
extends
|
|
243
|
+
extends
|
|
244
|
+
React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
236
245
|
VariantProps<typeof accordionTriggerVariants> {
|
|
237
246
|
/** Whether to show the chevron icon */
|
|
238
|
-
showChevron?: boolean
|
|
247
|
+
showChevron?: boolean;
|
|
239
248
|
}
|
|
240
249
|
|
|
241
|
-
const AccordionTrigger = React.forwardRef<
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
250
|
+
const AccordionTrigger = React.forwardRef<
|
|
251
|
+
HTMLButtonElement,
|
|
252
|
+
AccordionTriggerProps
|
|
253
|
+
>(({ className, showChevron = true, children, ...props }, ref) => {
|
|
254
|
+
const {
|
|
255
|
+
type,
|
|
256
|
+
value: openValues,
|
|
257
|
+
onValueChange,
|
|
258
|
+
variant,
|
|
259
|
+
} = useAccordionContext();
|
|
260
|
+
const { value, isOpen, disabled } = useAccordionItemContext();
|
|
261
|
+
|
|
262
|
+
const handleClick = () => {
|
|
263
|
+
if (disabled) return;
|
|
264
|
+
|
|
265
|
+
let newValue: string[];
|
|
266
|
+
|
|
267
|
+
if (type === "single") {
|
|
268
|
+
// In single mode, toggle current item (close if open, open if closed)
|
|
269
|
+
newValue = isOpen ? [] : [value];
|
|
270
|
+
} else {
|
|
271
|
+
// In multiple mode, toggle the item in the array
|
|
272
|
+
newValue = isOpen
|
|
273
|
+
? openValues.filter((v) => v !== value)
|
|
274
|
+
: [...openValues, value];
|
|
262
275
|
}
|
|
263
276
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
277
|
+
onValueChange(newValue);
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
return (
|
|
281
|
+
<button
|
|
282
|
+
ref={ref}
|
|
283
|
+
type="button"
|
|
284
|
+
aria-expanded={isOpen}
|
|
285
|
+
disabled={disabled}
|
|
286
|
+
onClick={handleClick}
|
|
287
|
+
className={cn(accordionTriggerVariants({ variant, className }))}
|
|
288
|
+
{...props}
|
|
289
|
+
>
|
|
290
|
+
<span className="flex-1">{children}</span>
|
|
291
|
+
{showChevron && (
|
|
292
|
+
<ChevronDown
|
|
293
|
+
className={cn(
|
|
294
|
+
"h-4 w-4 shrink-0 text-[#717680] transition-transform duration-300",
|
|
295
|
+
isOpen && "rotate-180"
|
|
296
|
+
)}
|
|
297
|
+
/>
|
|
298
|
+
)}
|
|
299
|
+
</button>
|
|
300
|
+
);
|
|
301
|
+
});
|
|
302
|
+
AccordionTrigger.displayName = "AccordionTrigger";
|
|
288
303
|
|
|
289
304
|
/**
|
|
290
305
|
* Content that is shown/hidden when the item is toggled
|
|
291
306
|
*/
|
|
292
307
|
export interface AccordionContentProps
|
|
293
|
-
extends
|
|
308
|
+
extends
|
|
309
|
+
React.HTMLAttributes<HTMLDivElement>,
|
|
294
310
|
VariantProps<typeof accordionContentVariants> {}
|
|
295
311
|
|
|
296
|
-
const AccordionContent = React.forwardRef<
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
312
|
+
const AccordionContent = React.forwardRef<
|
|
313
|
+
HTMLDivElement,
|
|
314
|
+
AccordionContentProps
|
|
315
|
+
>(({ className, children, ...props }, ref) => {
|
|
316
|
+
const { variant } = useAccordionContext();
|
|
317
|
+
const { isOpen } = useAccordionItemContext();
|
|
318
|
+
const contentRef = React.useRef<HTMLDivElement>(null);
|
|
319
|
+
const [height, setHeight] = React.useState<number | undefined>(undefined);
|
|
320
|
+
|
|
321
|
+
React.useEffect(() => {
|
|
322
|
+
if (contentRef.current) {
|
|
323
|
+
const contentHeight = contentRef.current.scrollHeight;
|
|
324
|
+
setHeight(isOpen ? contentHeight : 0);
|
|
325
|
+
}
|
|
326
|
+
}, [isOpen, children]);
|
|
309
327
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
</div>
|
|
328
|
+
return (
|
|
329
|
+
<div
|
|
330
|
+
ref={ref}
|
|
331
|
+
className={cn(accordionContentVariants({ variant, className }))}
|
|
332
|
+
style={{ height: height !== undefined ? \`\${height}px\` : undefined }}
|
|
333
|
+
aria-hidden={!isOpen}
|
|
334
|
+
{...props}
|
|
335
|
+
>
|
|
336
|
+
<div ref={contentRef} className="pb-4">
|
|
337
|
+
{children}
|
|
321
338
|
</div>
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
)
|
|
325
|
-
AccordionContent.displayName = "AccordionContent"
|
|
339
|
+
</div>
|
|
340
|
+
);
|
|
341
|
+
});
|
|
342
|
+
AccordionContent.displayName = "AccordionContent";
|
|
326
343
|
|
|
327
344
|
export {
|
|
328
345
|
Accordion,
|
|
@@ -333,13 +350,13 @@ export {
|
|
|
333
350
|
accordionItemVariants,
|
|
334
351
|
accordionTriggerVariants,
|
|
335
352
|
accordionContentVariants,
|
|
336
|
-
}
|
|
353
|
+
};
|
|
337
354
|
`,
|
|
338
|
-
"badge": `import * as React from "react"
|
|
339
|
-
import { Slot } from "@radix-ui/react-slot"
|
|
340
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
355
|
+
"badge": `import * as React from "react";
|
|
356
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
357
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
341
358
|
|
|
342
|
-
import { cn } from "@/lib/utils"
|
|
359
|
+
import { cn } from "@/lib/utils";
|
|
343
360
|
|
|
344
361
|
/**
|
|
345
362
|
* Badge variants for status indicators.
|
|
@@ -372,7 +389,7 @@ const badgeVariants = cva(
|
|
|
372
389
|
size: "default",
|
|
373
390
|
},
|
|
374
391
|
}
|
|
375
|
-
)
|
|
392
|
+
);
|
|
376
393
|
|
|
377
394
|
/**
|
|
378
395
|
* Badge component for displaying status indicators.
|
|
@@ -392,19 +409,32 @@ const badgeVariants = cva(
|
|
|
392
409
|
* \`\`\`
|
|
393
410
|
*/
|
|
394
411
|
export interface BadgeProps
|
|
395
|
-
extends
|
|
412
|
+
extends
|
|
413
|
+
React.HTMLAttributes<HTMLDivElement>,
|
|
396
414
|
VariantProps<typeof badgeVariants> {
|
|
397
415
|
/** Icon displayed on the left side of the badge text */
|
|
398
|
-
leftIcon?: React.ReactNode
|
|
416
|
+
leftIcon?: React.ReactNode;
|
|
399
417
|
/** Icon displayed on the right side of the badge text */
|
|
400
|
-
rightIcon?: React.ReactNode
|
|
418
|
+
rightIcon?: React.ReactNode;
|
|
401
419
|
/** Render as child element using Radix Slot */
|
|
402
|
-
asChild?: boolean
|
|
420
|
+
asChild?: boolean;
|
|
403
421
|
}
|
|
404
422
|
|
|
405
423
|
const Badge = React.forwardRef<HTMLDivElement, BadgeProps>(
|
|
406
|
-
(
|
|
407
|
-
|
|
424
|
+
(
|
|
425
|
+
{
|
|
426
|
+
className,
|
|
427
|
+
variant,
|
|
428
|
+
size,
|
|
429
|
+
leftIcon,
|
|
430
|
+
rightIcon,
|
|
431
|
+
asChild = false,
|
|
432
|
+
children,
|
|
433
|
+
...props
|
|
434
|
+
},
|
|
435
|
+
ref
|
|
436
|
+
) => {
|
|
437
|
+
const Comp = asChild ? Slot : "div";
|
|
408
438
|
|
|
409
439
|
// When using asChild, we can't wrap the child with extra elements
|
|
410
440
|
// The child must receive the className and ref directly
|
|
@@ -417,7 +447,7 @@ const Badge = React.forwardRef<HTMLDivElement, BadgeProps>(
|
|
|
417
447
|
>
|
|
418
448
|
{children}
|
|
419
449
|
</Comp>
|
|
420
|
-
)
|
|
450
|
+
);
|
|
421
451
|
}
|
|
422
452
|
|
|
423
453
|
return (
|
|
@@ -430,19 +460,19 @@ const Badge = React.forwardRef<HTMLDivElement, BadgeProps>(
|
|
|
430
460
|
{children}
|
|
431
461
|
{rightIcon && <span className="[&_svg]:size-3">{rightIcon}</span>}
|
|
432
462
|
</Comp>
|
|
433
|
-
)
|
|
463
|
+
);
|
|
434
464
|
}
|
|
435
|
-
)
|
|
436
|
-
Badge.displayName = "Badge"
|
|
465
|
+
);
|
|
466
|
+
Badge.displayName = "Badge";
|
|
437
467
|
|
|
438
|
-
export { Badge, badgeVariants }
|
|
468
|
+
export { Badge, badgeVariants };
|
|
439
469
|
`,
|
|
440
|
-
"button": `import * as React from "react"
|
|
441
|
-
import { Slot } from "@radix-ui/react-slot"
|
|
442
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
443
|
-
import { Loader2 } from "lucide-react"
|
|
470
|
+
"button": `import * as React from "react";
|
|
471
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
472
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
473
|
+
import { Loader2 } from "lucide-react";
|
|
444
474
|
|
|
445
|
-
import { cn } from "@/lib/utils"
|
|
475
|
+
import { cn } from "@/lib/utils";
|
|
446
476
|
|
|
447
477
|
const buttonVariants = cva(
|
|
448
478
|
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded text-sm font-medium transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#343E55] focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
@@ -451,12 +481,10 @@ const buttonVariants = cva(
|
|
|
451
481
|
variant: {
|
|
452
482
|
default: "bg-[#343E55] text-white hover:bg-[#2F384D]",
|
|
453
483
|
primary: "bg-[#343E55] text-white hover:bg-[#2F384D]",
|
|
454
|
-
destructive:
|
|
455
|
-
"bg-[#F04438] text-white hover:bg-[#D92D20]",
|
|
484
|
+
destructive: "bg-[#F04438] text-white hover:bg-[#D92D20]",
|
|
456
485
|
outline:
|
|
457
486
|
"border border-[#343E55] bg-transparent text-[#343E55] hover:bg-[#EBECEE]",
|
|
458
|
-
secondary:
|
|
459
|
-
"bg-[#EBECEE] text-[#343E55] hover:bg-[#D5D7DA]",
|
|
487
|
+
secondary: "bg-[#EBECEE] text-[#343E55] hover:bg-[#D5D7DA]",
|
|
460
488
|
ghost: "text-[#717680] hover:bg-[#F5F5F5] hover:text-[#181D27]",
|
|
461
489
|
link: "text-[#343E55] underline-offset-4 hover:underline",
|
|
462
490
|
dashed:
|
|
@@ -476,7 +504,7 @@ const buttonVariants = cva(
|
|
|
476
504
|
size: "default",
|
|
477
505
|
},
|
|
478
506
|
}
|
|
479
|
-
)
|
|
507
|
+
);
|
|
480
508
|
|
|
481
509
|
/**
|
|
482
510
|
* Button component for user interactions.
|
|
@@ -489,35 +517,39 @@ const buttonVariants = cva(
|
|
|
489
517
|
* \`\`\`
|
|
490
518
|
*/
|
|
491
519
|
export interface ButtonProps
|
|
492
|
-
extends
|
|
520
|
+
extends
|
|
521
|
+
React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
493
522
|
VariantProps<typeof buttonVariants> {
|
|
494
523
|
/** Render as child element using Radix Slot */
|
|
495
|
-
asChild?: boolean
|
|
524
|
+
asChild?: boolean;
|
|
496
525
|
/** Icon displayed on the left side of the button text */
|
|
497
|
-
leftIcon?: React.ReactNode
|
|
526
|
+
leftIcon?: React.ReactNode;
|
|
498
527
|
/** Icon displayed on the right side of the button text */
|
|
499
|
-
rightIcon?: React.ReactNode
|
|
528
|
+
rightIcon?: React.ReactNode;
|
|
500
529
|
/** Shows loading spinner and disables button */
|
|
501
|
-
loading?: boolean
|
|
530
|
+
loading?: boolean;
|
|
502
531
|
/** Text shown during loading state */
|
|
503
|
-
loadingText?: string
|
|
532
|
+
loadingText?: string;
|
|
504
533
|
}
|
|
505
534
|
|
|
506
535
|
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
507
|
-
(
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
536
|
+
(
|
|
537
|
+
{
|
|
538
|
+
className,
|
|
539
|
+
variant,
|
|
540
|
+
size,
|
|
541
|
+
asChild = false,
|
|
542
|
+
leftIcon,
|
|
543
|
+
rightIcon,
|
|
544
|
+
loading = false,
|
|
545
|
+
loadingText,
|
|
546
|
+
children,
|
|
547
|
+
disabled,
|
|
548
|
+
...props
|
|
549
|
+
},
|
|
550
|
+
ref
|
|
551
|
+
) => {
|
|
552
|
+
const Comp = asChild ? Slot : "button";
|
|
521
553
|
|
|
522
554
|
return (
|
|
523
555
|
<Comp
|
|
@@ -539,19 +571,19 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
539
571
|
</>
|
|
540
572
|
)}
|
|
541
573
|
</Comp>
|
|
542
|
-
)
|
|
574
|
+
);
|
|
543
575
|
}
|
|
544
|
-
)
|
|
545
|
-
Button.displayName = "Button"
|
|
576
|
+
);
|
|
577
|
+
Button.displayName = "Button";
|
|
546
578
|
|
|
547
|
-
export { Button, buttonVariants }
|
|
579
|
+
export { Button, buttonVariants };
|
|
548
580
|
`,
|
|
549
|
-
"checkbox": `import * as React from "react"
|
|
550
|
-
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
|
|
551
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
552
|
-
import { Check, Minus } from "lucide-react"
|
|
581
|
+
"checkbox": `import * as React from "react";
|
|
582
|
+
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
|
583
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
584
|
+
import { Check, Minus } from "lucide-react";
|
|
553
585
|
|
|
554
|
-
import { cn } from "@/lib/utils"
|
|
586
|
+
import { cn } from "@/lib/utils";
|
|
555
587
|
|
|
556
588
|
/**
|
|
557
589
|
* Checkbox box variants (the outer container)
|
|
@@ -570,7 +602,7 @@ const checkboxVariants = cva(
|
|
|
570
602
|
size: "default",
|
|
571
603
|
},
|
|
572
604
|
}
|
|
573
|
-
)
|
|
605
|
+
);
|
|
574
606
|
|
|
575
607
|
/**
|
|
576
608
|
* Icon size variants based on checkbox size
|
|
@@ -586,7 +618,7 @@ const iconSizeVariants = cva("", {
|
|
|
586
618
|
defaultVariants: {
|
|
587
619
|
size: "default",
|
|
588
620
|
},
|
|
589
|
-
})
|
|
621
|
+
});
|
|
590
622
|
|
|
591
623
|
/**
|
|
592
624
|
* Label text size variants
|
|
@@ -602,9 +634,9 @@ const labelSizeVariants = cva("", {
|
|
|
602
634
|
defaultVariants: {
|
|
603
635
|
size: "default",
|
|
604
636
|
},
|
|
605
|
-
})
|
|
637
|
+
});
|
|
606
638
|
|
|
607
|
-
export type CheckedState = boolean | "indeterminate"
|
|
639
|
+
export type CheckedState = boolean | "indeterminate";
|
|
608
640
|
|
|
609
641
|
/**
|
|
610
642
|
* A tri-state checkbox component with label support. Built on Radix UI Checkbox primitive.
|
|
@@ -619,18 +651,22 @@ export type CheckedState = boolean | "indeterminate"
|
|
|
619
651
|
* \`\`\`
|
|
620
652
|
*/
|
|
621
653
|
export interface CheckboxProps
|
|
622
|
-
extends
|
|
654
|
+
extends
|
|
655
|
+
Omit<
|
|
656
|
+
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>,
|
|
657
|
+
"onChange"
|
|
658
|
+
>,
|
|
623
659
|
VariantProps<typeof checkboxVariants> {
|
|
624
660
|
/** Optional label text */
|
|
625
|
-
label?: string
|
|
661
|
+
label?: string;
|
|
626
662
|
/** Position of the label */
|
|
627
|
-
labelPosition?: "left" | "right"
|
|
663
|
+
labelPosition?: "left" | "right";
|
|
628
664
|
/** Class name applied to the checkbox element */
|
|
629
|
-
checkboxClassName?: string
|
|
665
|
+
checkboxClassName?: string;
|
|
630
666
|
/** Class name applied to the label element */
|
|
631
|
-
labelClassName?: string
|
|
667
|
+
labelClassName?: string;
|
|
632
668
|
/** If true, uses separate labels with htmlFor/id association instead of wrapping the input. Requires id prop. */
|
|
633
|
-
separateLabel?: boolean
|
|
669
|
+
separateLabel?: boolean;
|
|
634
670
|
}
|
|
635
671
|
|
|
636
672
|
const Checkbox = React.forwardRef<
|
|
@@ -673,7 +709,7 @@ const Checkbox = React.forwardRef<
|
|
|
673
709
|
)}
|
|
674
710
|
</CheckboxPrimitive.Indicator>
|
|
675
711
|
</CheckboxPrimitive.Root>
|
|
676
|
-
)
|
|
712
|
+
);
|
|
677
713
|
|
|
678
714
|
if (label) {
|
|
679
715
|
// separateLabel mode: use htmlFor/id association instead of wrapping
|
|
@@ -708,56 +744,75 @@ const Checkbox = React.forwardRef<
|
|
|
708
744
|
</label>
|
|
709
745
|
)}
|
|
710
746
|
</div>
|
|
711
|
-
)
|
|
747
|
+
);
|
|
712
748
|
}
|
|
713
749
|
|
|
714
750
|
// Default: wrapping label
|
|
715
751
|
return (
|
|
716
|
-
<label
|
|
752
|
+
<label
|
|
753
|
+
className={cn(
|
|
754
|
+
"inline-flex items-center gap-2 cursor-pointer",
|
|
755
|
+
disabled && "cursor-not-allowed"
|
|
756
|
+
)}
|
|
757
|
+
>
|
|
717
758
|
{labelPosition === "left" && (
|
|
718
|
-
<span
|
|
759
|
+
<span
|
|
760
|
+
className={cn(
|
|
761
|
+
labelSizeVariants({ size }),
|
|
762
|
+
"text-[#181D27]",
|
|
763
|
+
disabled && "opacity-50",
|
|
764
|
+
labelClassName
|
|
765
|
+
)}
|
|
766
|
+
>
|
|
719
767
|
{label}
|
|
720
768
|
</span>
|
|
721
769
|
)}
|
|
722
770
|
{checkbox}
|
|
723
771
|
{labelPosition === "right" && (
|
|
724
|
-
<span
|
|
772
|
+
<span
|
|
773
|
+
className={cn(
|
|
774
|
+
labelSizeVariants({ size }),
|
|
775
|
+
"text-[#181D27]",
|
|
776
|
+
disabled && "opacity-50",
|
|
777
|
+
labelClassName
|
|
778
|
+
)}
|
|
779
|
+
>
|
|
725
780
|
{label}
|
|
726
781
|
</span>
|
|
727
782
|
)}
|
|
728
783
|
</label>
|
|
729
|
-
)
|
|
784
|
+
);
|
|
730
785
|
}
|
|
731
786
|
|
|
732
|
-
return checkbox
|
|
787
|
+
return checkbox;
|
|
733
788
|
}
|
|
734
|
-
)
|
|
735
|
-
Checkbox.displayName = "Checkbox"
|
|
789
|
+
);
|
|
790
|
+
Checkbox.displayName = "Checkbox";
|
|
736
791
|
|
|
737
|
-
export { Checkbox, checkboxVariants }
|
|
792
|
+
export { Checkbox, checkboxVariants };
|
|
738
793
|
`,
|
|
739
|
-
"dropdown-menu": `import * as React from "react"
|
|
740
|
-
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
|
741
|
-
import { Check, ChevronRight, Circle } from "lucide-react"
|
|
794
|
+
"dropdown-menu": `import * as React from "react";
|
|
795
|
+
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
796
|
+
import { Check, ChevronRight, Circle } from "lucide-react";
|
|
742
797
|
|
|
743
|
-
import { cn } from "@/lib/utils"
|
|
798
|
+
import { cn } from "@/lib/utils";
|
|
744
799
|
|
|
745
|
-
const DropdownMenu = DropdownMenuPrimitive.Root
|
|
800
|
+
const DropdownMenu = DropdownMenuPrimitive.Root;
|
|
746
801
|
|
|
747
|
-
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
|
|
802
|
+
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
748
803
|
|
|
749
|
-
const DropdownMenuGroup = DropdownMenuPrimitive.Group
|
|
804
|
+
const DropdownMenuGroup = DropdownMenuPrimitive.Group;
|
|
750
805
|
|
|
751
|
-
const DropdownMenuPortal = DropdownMenuPrimitive.Portal
|
|
806
|
+
const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
|
|
752
807
|
|
|
753
|
-
const DropdownMenuSub = DropdownMenuPrimitive.Sub
|
|
808
|
+
const DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
|
754
809
|
|
|
755
|
-
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
|
|
810
|
+
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
|
756
811
|
|
|
757
812
|
const DropdownMenuSubTrigger = React.forwardRef<
|
|
758
813
|
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
|
759
814
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
|
760
|
-
inset?: boolean
|
|
815
|
+
inset?: boolean;
|
|
761
816
|
}
|
|
762
817
|
>(({ className, inset, children, ...props }, ref) => (
|
|
763
818
|
<DropdownMenuPrimitive.SubTrigger
|
|
@@ -772,9 +827,9 @@ const DropdownMenuSubTrigger = React.forwardRef<
|
|
|
772
827
|
{children}
|
|
773
828
|
<ChevronRight className="ml-auto h-4 w-4" />
|
|
774
829
|
</DropdownMenuPrimitive.SubTrigger>
|
|
775
|
-
))
|
|
830
|
+
));
|
|
776
831
|
DropdownMenuSubTrigger.displayName =
|
|
777
|
-
DropdownMenuPrimitive.SubTrigger.displayName
|
|
832
|
+
DropdownMenuPrimitive.SubTrigger.displayName;
|
|
778
833
|
|
|
779
834
|
const DropdownMenuSubContent = React.forwardRef<
|
|
780
835
|
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
|
@@ -788,9 +843,9 @@ const DropdownMenuSubContent = React.forwardRef<
|
|
|
788
843
|
)}
|
|
789
844
|
{...props}
|
|
790
845
|
/>
|
|
791
|
-
))
|
|
846
|
+
));
|
|
792
847
|
DropdownMenuSubContent.displayName =
|
|
793
|
-
DropdownMenuPrimitive.SubContent.displayName
|
|
848
|
+
DropdownMenuPrimitive.SubContent.displayName;
|
|
794
849
|
|
|
795
850
|
const DropdownMenuContent = React.forwardRef<
|
|
796
851
|
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
|
@@ -808,13 +863,13 @@ const DropdownMenuContent = React.forwardRef<
|
|
|
808
863
|
{...props}
|
|
809
864
|
/>
|
|
810
865
|
</DropdownMenuPrimitive.Portal>
|
|
811
|
-
))
|
|
812
|
-
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
|
|
866
|
+
));
|
|
867
|
+
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
|
813
868
|
|
|
814
869
|
const DropdownMenuItem = React.forwardRef<
|
|
815
870
|
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
|
816
871
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
|
817
|
-
inset?: boolean
|
|
872
|
+
inset?: boolean;
|
|
818
873
|
}
|
|
819
874
|
>(({ className, inset, ...props }, ref) => (
|
|
820
875
|
<DropdownMenuPrimitive.Item
|
|
@@ -826,8 +881,8 @@ const DropdownMenuItem = React.forwardRef<
|
|
|
826
881
|
)}
|
|
827
882
|
{...props}
|
|
828
883
|
/>
|
|
829
|
-
))
|
|
830
|
-
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
|
|
884
|
+
));
|
|
885
|
+
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
|
831
886
|
|
|
832
887
|
const DropdownMenuCheckboxItem = React.forwardRef<
|
|
833
888
|
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
|
@@ -849,9 +904,9 @@ const DropdownMenuCheckboxItem = React.forwardRef<
|
|
|
849
904
|
</span>
|
|
850
905
|
{children}
|
|
851
906
|
</DropdownMenuPrimitive.CheckboxItem>
|
|
852
|
-
))
|
|
907
|
+
));
|
|
853
908
|
DropdownMenuCheckboxItem.displayName =
|
|
854
|
-
DropdownMenuPrimitive.CheckboxItem.displayName
|
|
909
|
+
DropdownMenuPrimitive.CheckboxItem.displayName;
|
|
855
910
|
|
|
856
911
|
const DropdownMenuRadioItem = React.forwardRef<
|
|
857
912
|
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
|
@@ -872,13 +927,13 @@ const DropdownMenuRadioItem = React.forwardRef<
|
|
|
872
927
|
</span>
|
|
873
928
|
{children}
|
|
874
929
|
</DropdownMenuPrimitive.RadioItem>
|
|
875
|
-
))
|
|
876
|
-
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
|
|
930
|
+
));
|
|
931
|
+
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
|
|
877
932
|
|
|
878
933
|
const DropdownMenuLabel = React.forwardRef<
|
|
879
934
|
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
|
880
935
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
|
881
|
-
inset?: boolean
|
|
936
|
+
inset?: boolean;
|
|
882
937
|
}
|
|
883
938
|
>(({ className, inset, ...props }, ref) => (
|
|
884
939
|
<DropdownMenuPrimitive.Label
|
|
@@ -890,8 +945,8 @@ const DropdownMenuLabel = React.forwardRef<
|
|
|
890
945
|
)}
|
|
891
946
|
{...props}
|
|
892
947
|
/>
|
|
893
|
-
))
|
|
894
|
-
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
|
|
948
|
+
));
|
|
949
|
+
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
|
|
895
950
|
|
|
896
951
|
const DropdownMenuSeparator = React.forwardRef<
|
|
897
952
|
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
|
@@ -902,8 +957,8 @@ const DropdownMenuSeparator = React.forwardRef<
|
|
|
902
957
|
className={cn("-mx-1 my-1 h-px bg-[#E9EAEB]", className)}
|
|
903
958
|
{...props}
|
|
904
959
|
/>
|
|
905
|
-
))
|
|
906
|
-
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
|
|
960
|
+
));
|
|
961
|
+
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
|
907
962
|
|
|
908
963
|
const DropdownMenuShortcut = ({
|
|
909
964
|
className,
|
|
@@ -914,9 +969,9 @@ const DropdownMenuShortcut = ({
|
|
|
914
969
|
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
|
|
915
970
|
{...props}
|
|
916
971
|
/>
|
|
917
|
-
)
|
|
918
|
-
}
|
|
919
|
-
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
|
|
972
|
+
);
|
|
973
|
+
};
|
|
974
|
+
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
|
|
920
975
|
|
|
921
976
|
export {
|
|
922
977
|
DropdownMenu,
|
|
@@ -934,12 +989,12 @@ export {
|
|
|
934
989
|
DropdownMenuSubContent,
|
|
935
990
|
DropdownMenuSubTrigger,
|
|
936
991
|
DropdownMenuRadioGroup,
|
|
937
|
-
}
|
|
992
|
+
};
|
|
938
993
|
`,
|
|
939
|
-
"input": `import * as React from "react"
|
|
940
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
994
|
+
"input": `import * as React from "react";
|
|
995
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
941
996
|
|
|
942
|
-
import { cn } from "@/lib/utils"
|
|
997
|
+
import { cn } from "@/lib/utils";
|
|
943
998
|
|
|
944
999
|
/**
|
|
945
1000
|
* Input variants for different visual states
|
|
@@ -949,15 +1004,17 @@ const inputVariants = cva(
|
|
|
949
1004
|
{
|
|
950
1005
|
variants: {
|
|
951
1006
|
state: {
|
|
952
|
-
default:
|
|
953
|
-
|
|
1007
|
+
default:
|
|
1008
|
+
"border border-[#E9EAEB] focus:outline-none focus:border-[#2BBCCA]/50 focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
|
|
1009
|
+
error:
|
|
1010
|
+
"border border-[#F04438]/40 focus:outline-none focus:border-[#F04438]/60 focus:shadow-[0_0_0_1px_rgba(240,68,56,0.1)]",
|
|
954
1011
|
},
|
|
955
1012
|
},
|
|
956
1013
|
defaultVariants: {
|
|
957
1014
|
state: "default",
|
|
958
1015
|
},
|
|
959
1016
|
}
|
|
960
|
-
)
|
|
1017
|
+
);
|
|
961
1018
|
|
|
962
1019
|
/**
|
|
963
1020
|
* A flexible input component for text entry with state variants.
|
|
@@ -970,7 +1027,8 @@ const inputVariants = cva(
|
|
|
970
1027
|
* \`\`\`
|
|
971
1028
|
*/
|
|
972
1029
|
export interface InputProps
|
|
973
|
-
extends
|
|
1030
|
+
extends
|
|
1031
|
+
Omit<React.ComponentProps<"input">, "size">,
|
|
974
1032
|
VariantProps<typeof inputVariants> {}
|
|
975
1033
|
|
|
976
1034
|
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
@@ -982,18 +1040,18 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
982
1040
|
ref={ref}
|
|
983
1041
|
{...props}
|
|
984
1042
|
/>
|
|
985
|
-
)
|
|
1043
|
+
);
|
|
986
1044
|
}
|
|
987
|
-
)
|
|
988
|
-
Input.displayName = "Input"
|
|
1045
|
+
);
|
|
1046
|
+
Input.displayName = "Input";
|
|
989
1047
|
|
|
990
|
-
export { Input, inputVariants }
|
|
1048
|
+
export { Input, inputVariants };
|
|
991
1049
|
`,
|
|
992
|
-
"multi-select": `import * as React from "react"
|
|
993
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
994
|
-
import { Check, ChevronDown, X, Loader2 } from "lucide-react"
|
|
1050
|
+
"multi-select": `import * as React from "react";
|
|
1051
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
1052
|
+
import { Check, ChevronDown, X, Loader2 } from "lucide-react";
|
|
995
1053
|
|
|
996
|
-
import { cn } from "@/lib/utils"
|
|
1054
|
+
import { cn } from "@/lib/utils";
|
|
997
1055
|
|
|
998
1056
|
/**
|
|
999
1057
|
* MultiSelect trigger variants matching TextField styling
|
|
@@ -1003,64 +1061,68 @@ const multiSelectTriggerVariants = cva(
|
|
|
1003
1061
|
{
|
|
1004
1062
|
variants: {
|
|
1005
1063
|
state: {
|
|
1006
|
-
default:
|
|
1007
|
-
|
|
1064
|
+
default:
|
|
1065
|
+
"border border-[#E9EAEB] focus:outline-none focus:border-[#2BBCCA]/50 focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
|
|
1066
|
+
error:
|
|
1067
|
+
"border border-[#F04438]/40 focus:outline-none focus:border-[#F04438]/60 focus:shadow-[0_0_0_1px_rgba(240,68,56,0.1)]",
|
|
1008
1068
|
},
|
|
1009
1069
|
},
|
|
1010
1070
|
defaultVariants: {
|
|
1011
1071
|
state: "default",
|
|
1012
1072
|
},
|
|
1013
1073
|
}
|
|
1014
|
-
)
|
|
1074
|
+
);
|
|
1015
1075
|
|
|
1016
1076
|
export interface MultiSelectOption {
|
|
1017
1077
|
/** The value of the option */
|
|
1018
|
-
value: string
|
|
1078
|
+
value: string;
|
|
1019
1079
|
/** The display label of the option */
|
|
1020
|
-
label: string
|
|
1080
|
+
label: string;
|
|
1021
1081
|
/** Whether the option is disabled */
|
|
1022
|
-
disabled?: boolean
|
|
1082
|
+
disabled?: boolean;
|
|
1023
1083
|
}
|
|
1024
1084
|
|
|
1025
|
-
export interface MultiSelectProps extends VariantProps<
|
|
1085
|
+
export interface MultiSelectProps extends VariantProps<
|
|
1086
|
+
typeof multiSelectTriggerVariants
|
|
1087
|
+
> {
|
|
1026
1088
|
/** Label text displayed above the select */
|
|
1027
|
-
label?: string
|
|
1089
|
+
label?: string;
|
|
1028
1090
|
/** Shows red asterisk next to label when true */
|
|
1029
|
-
required?: boolean
|
|
1091
|
+
required?: boolean;
|
|
1030
1092
|
/** Helper text displayed below the select */
|
|
1031
|
-
helperText?: string
|
|
1093
|
+
helperText?: string;
|
|
1032
1094
|
/** Error message - shows error state with red styling */
|
|
1033
|
-
error?: string
|
|
1095
|
+
error?: string;
|
|
1034
1096
|
/** Disabled state */
|
|
1035
|
-
disabled?: boolean
|
|
1097
|
+
disabled?: boolean;
|
|
1036
1098
|
/** Loading state with spinner */
|
|
1037
|
-
loading?: boolean
|
|
1099
|
+
loading?: boolean;
|
|
1038
1100
|
/** Placeholder text when no value selected */
|
|
1039
|
-
placeholder?: string
|
|
1101
|
+
placeholder?: string;
|
|
1040
1102
|
/** Currently selected values (controlled) */
|
|
1041
|
-
value?: string[]
|
|
1103
|
+
value?: string[];
|
|
1042
1104
|
/** Default values (uncontrolled) */
|
|
1043
|
-
defaultValue?: string[]
|
|
1105
|
+
defaultValue?: string[];
|
|
1044
1106
|
/** Callback when values change */
|
|
1045
|
-
onValueChange?: (value: string[]) => void
|
|
1107
|
+
onValueChange?: (value: string[]) => void;
|
|
1046
1108
|
/** Options to display */
|
|
1047
|
-
options: MultiSelectOption[]
|
|
1109
|
+
options: MultiSelectOption[];
|
|
1048
1110
|
/** Enable search/filter functionality */
|
|
1049
|
-
searchable?: boolean
|
|
1111
|
+
searchable?: boolean;
|
|
1050
1112
|
/** Search placeholder text */
|
|
1051
|
-
searchPlaceholder?: string
|
|
1113
|
+
searchPlaceholder?: string;
|
|
1052
1114
|
/** Maximum selections allowed */
|
|
1053
|
-
maxSelections?: number
|
|
1115
|
+
maxSelections?: number;
|
|
1054
1116
|
/** Additional class for wrapper */
|
|
1055
|
-
wrapperClassName?: string
|
|
1117
|
+
wrapperClassName?: string;
|
|
1056
1118
|
/** Additional class for trigger */
|
|
1057
|
-
triggerClassName?: string
|
|
1119
|
+
triggerClassName?: string;
|
|
1058
1120
|
/** Additional class for label */
|
|
1059
|
-
labelClassName?: string
|
|
1121
|
+
labelClassName?: string;
|
|
1060
1122
|
/** ID for the select */
|
|
1061
|
-
id?: string
|
|
1123
|
+
id?: string;
|
|
1062
1124
|
/** Name attribute for form submission */
|
|
1063
|
-
name?: string
|
|
1125
|
+
name?: string;
|
|
1064
1126
|
}
|
|
1065
1127
|
|
|
1066
1128
|
/**
|
|
@@ -1107,104 +1169,109 @@ const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(
|
|
|
1107
1169
|
ref
|
|
1108
1170
|
) => {
|
|
1109
1171
|
// Internal state for selected values (uncontrolled mode)
|
|
1110
|
-
const [internalValue, setInternalValue] =
|
|
1172
|
+
const [internalValue, setInternalValue] =
|
|
1173
|
+
React.useState<string[]>(defaultValue);
|
|
1111
1174
|
// Dropdown open state
|
|
1112
|
-
const [isOpen, setIsOpen] = React.useState(false)
|
|
1175
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
1113
1176
|
// Search query
|
|
1114
|
-
const [searchQuery, setSearchQuery] = React.useState("")
|
|
1177
|
+
const [searchQuery, setSearchQuery] = React.useState("");
|
|
1115
1178
|
|
|
1116
1179
|
// Container ref for click outside detection
|
|
1117
|
-
const containerRef = React.useRef<HTMLDivElement>(null)
|
|
1180
|
+
const containerRef = React.useRef<HTMLDivElement>(null);
|
|
1118
1181
|
|
|
1119
1182
|
// Determine if controlled
|
|
1120
|
-
const isControlled = value !== undefined
|
|
1121
|
-
const selectedValues = isControlled ? value : internalValue
|
|
1183
|
+
const isControlled = value !== undefined;
|
|
1184
|
+
const selectedValues = isControlled ? value : internalValue;
|
|
1122
1185
|
|
|
1123
1186
|
// Derive state from props
|
|
1124
|
-
const derivedState = error ? "error" : (state ?? "default")
|
|
1187
|
+
const derivedState = error ? "error" : (state ?? "default");
|
|
1125
1188
|
|
|
1126
1189
|
// Generate unique IDs for accessibility
|
|
1127
|
-
const generatedId = React.useId()
|
|
1128
|
-
const selectId = id || generatedId
|
|
1129
|
-
const helperId = \`\${selectId}-helper
|
|
1130
|
-
const errorId = \`\${selectId}-error
|
|
1190
|
+
const generatedId = React.useId();
|
|
1191
|
+
const selectId = id || generatedId;
|
|
1192
|
+
const helperId = \`\${selectId}-helper\`;
|
|
1193
|
+
const errorId = \`\${selectId}-error\`;
|
|
1131
1194
|
|
|
1132
1195
|
// Determine aria-describedby
|
|
1133
|
-
const ariaDescribedBy = error ? errorId : helperText ? helperId : undefined
|
|
1196
|
+
const ariaDescribedBy = error ? errorId : helperText ? helperId : undefined;
|
|
1134
1197
|
|
|
1135
1198
|
// Filter options by search query
|
|
1136
1199
|
const filteredOptions = React.useMemo(() => {
|
|
1137
|
-
if (!searchable || !searchQuery) return options
|
|
1200
|
+
if (!searchable || !searchQuery) return options;
|
|
1138
1201
|
return options.filter((option) =>
|
|
1139
1202
|
option.label.toLowerCase().includes(searchQuery.toLowerCase())
|
|
1140
|
-
)
|
|
1141
|
-
}, [options, searchable, searchQuery])
|
|
1203
|
+
);
|
|
1204
|
+
}, [options, searchable, searchQuery]);
|
|
1142
1205
|
|
|
1143
1206
|
// Get selected option labels
|
|
1144
1207
|
const selectedLabels = React.useMemo(() => {
|
|
1145
1208
|
return selectedValues
|
|
1146
1209
|
.map((v) => options.find((o) => o.value === v)?.label)
|
|
1147
|
-
.filter(Boolean) as string[]
|
|
1148
|
-
}, [selectedValues, options])
|
|
1210
|
+
.filter(Boolean) as string[];
|
|
1211
|
+
}, [selectedValues, options]);
|
|
1149
1212
|
|
|
1150
1213
|
// Handle toggle selection
|
|
1151
1214
|
const toggleOption = (optionValue: string) => {
|
|
1152
1215
|
const newValues = selectedValues.includes(optionValue)
|
|
1153
1216
|
? selectedValues.filter((v) => v !== optionValue)
|
|
1154
1217
|
: maxSelections && selectedValues.length >= maxSelections
|
|
1155
|
-
|
|
1156
|
-
|
|
1218
|
+
? selectedValues
|
|
1219
|
+
: [...selectedValues, optionValue];
|
|
1157
1220
|
|
|
1158
1221
|
if (!isControlled) {
|
|
1159
|
-
setInternalValue(newValues)
|
|
1222
|
+
setInternalValue(newValues);
|
|
1160
1223
|
}
|
|
1161
|
-
onValueChange?.(newValues)
|
|
1162
|
-
}
|
|
1224
|
+
onValueChange?.(newValues);
|
|
1225
|
+
};
|
|
1163
1226
|
|
|
1164
1227
|
// Handle remove tag
|
|
1165
1228
|
const removeValue = (valueToRemove: string, e: React.MouseEvent) => {
|
|
1166
|
-
e.stopPropagation()
|
|
1167
|
-
const newValues = selectedValues.filter((v) => v !== valueToRemove)
|
|
1229
|
+
e.stopPropagation();
|
|
1230
|
+
const newValues = selectedValues.filter((v) => v !== valueToRemove);
|
|
1168
1231
|
if (!isControlled) {
|
|
1169
|
-
setInternalValue(newValues)
|
|
1232
|
+
setInternalValue(newValues);
|
|
1170
1233
|
}
|
|
1171
|
-
onValueChange?.(newValues)
|
|
1172
|
-
}
|
|
1234
|
+
onValueChange?.(newValues);
|
|
1235
|
+
};
|
|
1173
1236
|
|
|
1174
1237
|
// Handle clear all
|
|
1175
1238
|
const clearAll = (e: React.MouseEvent) => {
|
|
1176
|
-
e.stopPropagation()
|
|
1239
|
+
e.stopPropagation();
|
|
1177
1240
|
if (!isControlled) {
|
|
1178
|
-
setInternalValue([])
|
|
1241
|
+
setInternalValue([]);
|
|
1179
1242
|
}
|
|
1180
|
-
onValueChange?.([])
|
|
1181
|
-
}
|
|
1243
|
+
onValueChange?.([]);
|
|
1244
|
+
};
|
|
1182
1245
|
|
|
1183
1246
|
// Close dropdown when clicking outside
|
|
1184
1247
|
React.useEffect(() => {
|
|
1185
1248
|
const handleClickOutside = (event: MouseEvent) => {
|
|
1186
|
-
if (
|
|
1187
|
-
|
|
1188
|
-
|
|
1249
|
+
if (
|
|
1250
|
+
containerRef.current &&
|
|
1251
|
+
!containerRef.current.contains(event.target as Node)
|
|
1252
|
+
) {
|
|
1253
|
+
setIsOpen(false);
|
|
1254
|
+
setSearchQuery("");
|
|
1189
1255
|
}
|
|
1190
|
-
}
|
|
1256
|
+
};
|
|
1191
1257
|
|
|
1192
|
-
document.addEventListener("mousedown", handleClickOutside)
|
|
1193
|
-
return () =>
|
|
1194
|
-
|
|
1258
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
1259
|
+
return () =>
|
|
1260
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
1261
|
+
}, []);
|
|
1195
1262
|
|
|
1196
1263
|
// Handle keyboard navigation
|
|
1197
1264
|
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
1198
1265
|
if (e.key === "Escape") {
|
|
1199
|
-
setIsOpen(false)
|
|
1200
|
-
setSearchQuery("")
|
|
1266
|
+
setIsOpen(false);
|
|
1267
|
+
setSearchQuery("");
|
|
1201
1268
|
} else if (e.key === "Enter" || e.key === " ") {
|
|
1202
1269
|
if (!isOpen) {
|
|
1203
|
-
e.preventDefault()
|
|
1204
|
-
setIsOpen(true)
|
|
1270
|
+
e.preventDefault();
|
|
1271
|
+
setIsOpen(true);
|
|
1205
1272
|
}
|
|
1206
1273
|
}
|
|
1207
|
-
}
|
|
1274
|
+
};
|
|
1208
1275
|
|
|
1209
1276
|
return (
|
|
1210
1277
|
<div
|
|
@@ -1256,9 +1323,12 @@ const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(
|
|
|
1256
1323
|
tabIndex={0}
|
|
1257
1324
|
onClick={(e) => removeValue(selectedValues[index], e)}
|
|
1258
1325
|
onKeyDown={(e) => {
|
|
1259
|
-
if (e.key ===
|
|
1260
|
-
e.preventDefault()
|
|
1261
|
-
removeValue(
|
|
1326
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1327
|
+
e.preventDefault();
|
|
1328
|
+
removeValue(
|
|
1329
|
+
selectedValues[index],
|
|
1330
|
+
e as unknown as React.MouseEvent
|
|
1331
|
+
);
|
|
1262
1332
|
}
|
|
1263
1333
|
}}
|
|
1264
1334
|
className="cursor-pointer hover:text-[#F04438] focus:outline-none"
|
|
@@ -1277,9 +1347,9 @@ const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(
|
|
|
1277
1347
|
tabIndex={0}
|
|
1278
1348
|
onClick={clearAll}
|
|
1279
1349
|
onKeyDown={(e) => {
|
|
1280
|
-
if (e.key ===
|
|
1281
|
-
e.preventDefault()
|
|
1282
|
-
clearAll(e as unknown as React.MouseEvent)
|
|
1350
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1351
|
+
e.preventDefault();
|
|
1352
|
+
clearAll(e as unknown as React.MouseEvent);
|
|
1283
1353
|
}
|
|
1284
1354
|
}}
|
|
1285
1355
|
className="p-0.5 cursor-pointer hover:text-[#F04438] focus:outline-none"
|
|
@@ -1333,10 +1403,13 @@ const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(
|
|
|
1333
1403
|
</div>
|
|
1334
1404
|
) : (
|
|
1335
1405
|
filteredOptions.map((option) => {
|
|
1336
|
-
const isSelected = selectedValues.includes(option.value)
|
|
1406
|
+
const isSelected = selectedValues.includes(option.value);
|
|
1337
1407
|
const isDisabled =
|
|
1338
1408
|
option.disabled ||
|
|
1339
|
-
(!isSelected &&
|
|
1409
|
+
(!isSelected &&
|
|
1410
|
+
maxSelections !== undefined &&
|
|
1411
|
+
maxSelections > 0 &&
|
|
1412
|
+
selectedValues.length >= maxSelections);
|
|
1340
1413
|
|
|
1341
1414
|
return (
|
|
1342
1415
|
<button
|
|
@@ -1354,11 +1427,13 @@ const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(
|
|
|
1354
1427
|
)}
|
|
1355
1428
|
>
|
|
1356
1429
|
<span className="absolute right-2 flex size-4 items-center justify-center">
|
|
1357
|
-
{isSelected &&
|
|
1430
|
+
{isSelected && (
|
|
1431
|
+
<Check className="size-4 text-[#2BBCCA]" />
|
|
1432
|
+
)}
|
|
1358
1433
|
</span>
|
|
1359
1434
|
{option.label}
|
|
1360
1435
|
</button>
|
|
1361
|
-
)
|
|
1436
|
+
);
|
|
1362
1437
|
})
|
|
1363
1438
|
)}
|
|
1364
1439
|
</div>
|
|
@@ -1373,9 +1448,10 @@ const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(
|
|
|
1373
1448
|
)}
|
|
1374
1449
|
|
|
1375
1450
|
{/* Hidden input for form submission */}
|
|
1376
|
-
{name &&
|
|
1377
|
-
|
|
1378
|
-
|
|
1451
|
+
{name &&
|
|
1452
|
+
selectedValues.map((v) => (
|
|
1453
|
+
<input key={v} type="hidden" name={name} value={v} />
|
|
1454
|
+
))}
|
|
1379
1455
|
|
|
1380
1456
|
{/* Helper text / Error message */}
|
|
1381
1457
|
{(error || helperText) && (
|
|
@@ -1392,19 +1468,19 @@ const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(
|
|
|
1392
1468
|
</div>
|
|
1393
1469
|
)}
|
|
1394
1470
|
</div>
|
|
1395
|
-
)
|
|
1471
|
+
);
|
|
1396
1472
|
}
|
|
1397
|
-
)
|
|
1398
|
-
MultiSelect.displayName = "MultiSelect"
|
|
1473
|
+
);
|
|
1474
|
+
MultiSelect.displayName = "MultiSelect";
|
|
1399
1475
|
|
|
1400
|
-
export { MultiSelect, multiSelectTriggerVariants }
|
|
1476
|
+
export { MultiSelect, multiSelectTriggerVariants };
|
|
1401
1477
|
`,
|
|
1402
|
-
"page-header": `import * as React from "react"
|
|
1403
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
1404
|
-
import { ArrowLeft, MoreHorizontal, X } from "lucide-react"
|
|
1478
|
+
"page-header": `import * as React from "react";
|
|
1479
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
1480
|
+
import { ArrowLeft, MoreHorizontal, X } from "lucide-react";
|
|
1405
1481
|
|
|
1406
|
-
import { cn } from "@/lib/utils"
|
|
1407
|
-
import { Button } from "./button"
|
|
1482
|
+
import { cn } from "@/lib/utils";
|
|
1483
|
+
import { Button } from "./button";
|
|
1408
1484
|
|
|
1409
1485
|
/**
|
|
1410
1486
|
* PageHeader variants for layout styles.
|
|
@@ -1415,7 +1491,7 @@ const pageHeaderVariants = cva(
|
|
|
1415
1491
|
variants: {},
|
|
1416
1492
|
defaultVariants: {},
|
|
1417
1493
|
}
|
|
1418
|
-
)
|
|
1494
|
+
);
|
|
1419
1495
|
|
|
1420
1496
|
/**
|
|
1421
1497
|
* Page header component for displaying page titles with optional icons and actions.
|
|
@@ -1448,47 +1524,51 @@ const pageHeaderVariants = cva(
|
|
|
1448
1524
|
* \`\`\`
|
|
1449
1525
|
*/
|
|
1450
1526
|
export interface PageHeaderProps
|
|
1451
|
-
extends
|
|
1527
|
+
extends
|
|
1528
|
+
React.HTMLAttributes<HTMLDivElement>,
|
|
1452
1529
|
VariantProps<typeof pageHeaderVariants> {
|
|
1453
1530
|
/** Page title (required) */
|
|
1454
|
-
title: string
|
|
1531
|
+
title: string;
|
|
1455
1532
|
/** Optional description/subtitle displayed below the title */
|
|
1456
|
-
description?: string
|
|
1533
|
+
description?: string;
|
|
1457
1534
|
/** Icon displayed on the left side (hidden when showBackButton is true) */
|
|
1458
|
-
icon?: React.ReactNode
|
|
1535
|
+
icon?: React.ReactNode;
|
|
1459
1536
|
/** Shows back arrow button instead of icon */
|
|
1460
|
-
showBackButton?: boolean
|
|
1537
|
+
showBackButton?: boolean;
|
|
1461
1538
|
/** Callback when back button is clicked */
|
|
1462
|
-
onBackClick?: () => void
|
|
1539
|
+
onBackClick?: () => void;
|
|
1463
1540
|
/** Optional info icon displayed next to the title (e.g., tooltip trigger) */
|
|
1464
|
-
infoIcon?: React.ReactNode
|
|
1541
|
+
infoIcon?: React.ReactNode;
|
|
1465
1542
|
/** Action buttons/elements rendered on the right side */
|
|
1466
|
-
actions?: React.ReactNode
|
|
1543
|
+
actions?: React.ReactNode;
|
|
1467
1544
|
/** Show bottom border (default: true) */
|
|
1468
|
-
showBorder?: boolean
|
|
1545
|
+
showBorder?: boolean;
|
|
1469
1546
|
/** Layout mode: 'horizontal' (single row), 'vertical' (stacked), 'responsive' (auto based on screen size, default) */
|
|
1470
|
-
layout?:
|
|
1547
|
+
layout?: "horizontal" | "vertical" | "responsive";
|
|
1471
1548
|
/** Max actions to show on mobile before overflow (default: 2) */
|
|
1472
|
-
mobileOverflowLimit?: number
|
|
1549
|
+
mobileOverflowLimit?: number;
|
|
1473
1550
|
}
|
|
1474
1551
|
|
|
1475
1552
|
const PageHeader = React.forwardRef<HTMLDivElement, PageHeaderProps>(
|
|
1476
|
-
(
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1553
|
+
(
|
|
1554
|
+
{
|
|
1555
|
+
className,
|
|
1556
|
+
title,
|
|
1557
|
+
description,
|
|
1558
|
+
icon,
|
|
1559
|
+
showBackButton = false,
|
|
1560
|
+
onBackClick,
|
|
1561
|
+
infoIcon,
|
|
1562
|
+
actions,
|
|
1563
|
+
showBorder = true,
|
|
1564
|
+
layout = "responsive",
|
|
1565
|
+
mobileOverflowLimit = 2,
|
|
1566
|
+
...props
|
|
1567
|
+
},
|
|
1568
|
+
ref
|
|
1569
|
+
) => {
|
|
1490
1570
|
// State for overflow expansion (moved to top level)
|
|
1491
|
-
const [isOverflowExpanded, setIsOverflowExpanded] = React.useState(false)
|
|
1571
|
+
const [isOverflowExpanded, setIsOverflowExpanded] = React.useState(false);
|
|
1492
1572
|
|
|
1493
1573
|
// Determine what to show on the left: back button, icon, or nothing
|
|
1494
1574
|
const renderLeftElement = () => {
|
|
@@ -1502,66 +1582,68 @@ const PageHeader = React.forwardRef<HTMLDivElement, PageHeaderProps>(
|
|
|
1502
1582
|
>
|
|
1503
1583
|
<ArrowLeft className="w-5 h-5" />
|
|
1504
1584
|
</button>
|
|
1505
|
-
)
|
|
1585
|
+
);
|
|
1506
1586
|
}
|
|
1507
1587
|
if (icon) {
|
|
1508
1588
|
return (
|
|
1509
1589
|
<div className="flex items-center justify-center w-10 h-10 [&_svg]:w-6 [&_svg]:h-6 text-[#717680]">
|
|
1510
1590
|
{icon}
|
|
1511
1591
|
</div>
|
|
1512
|
-
)
|
|
1592
|
+
);
|
|
1513
1593
|
}
|
|
1514
|
-
return null
|
|
1515
|
-
}
|
|
1594
|
+
return null;
|
|
1595
|
+
};
|
|
1516
1596
|
|
|
1517
|
-
const leftElement = renderLeftElement()
|
|
1597
|
+
const leftElement = renderLeftElement();
|
|
1518
1598
|
|
|
1519
1599
|
// Flatten children recursively to handle fragments
|
|
1520
1600
|
const flattenChildren = (children: React.ReactNode): React.ReactNode[] => {
|
|
1521
|
-
const result: React.ReactNode[] = []
|
|
1601
|
+
const result: React.ReactNode[] = [];
|
|
1522
1602
|
React.Children.forEach(children, (child) => {
|
|
1523
1603
|
if (React.isValidElement(child) && child.type === React.Fragment) {
|
|
1524
|
-
result.push(...flattenChildren(child.props.children))
|
|
1604
|
+
result.push(...flattenChildren(child.props.children));
|
|
1525
1605
|
} else if (child !== null && child !== undefined) {
|
|
1526
|
-
result.push(child)
|
|
1606
|
+
result.push(child);
|
|
1527
1607
|
}
|
|
1528
|
-
})
|
|
1529
|
-
return result
|
|
1530
|
-
}
|
|
1608
|
+
});
|
|
1609
|
+
return result;
|
|
1610
|
+
};
|
|
1531
1611
|
|
|
1532
1612
|
// Convert actions to array for overflow handling
|
|
1533
|
-
const actionsArray = flattenChildren(actions)
|
|
1534
|
-
const hasOverflow = actionsArray.length > mobileOverflowLimit
|
|
1535
|
-
const visibleActions = hasOverflow
|
|
1536
|
-
|
|
1613
|
+
const actionsArray = flattenChildren(actions);
|
|
1614
|
+
const hasOverflow = actionsArray.length > mobileOverflowLimit;
|
|
1615
|
+
const visibleActions = hasOverflow
|
|
1616
|
+
? actionsArray.slice(0, mobileOverflowLimit)
|
|
1617
|
+
: actionsArray;
|
|
1618
|
+
const overflowActions = hasOverflow
|
|
1619
|
+
? actionsArray.slice(mobileOverflowLimit)
|
|
1620
|
+
: [];
|
|
1537
1621
|
|
|
1538
1622
|
// Layout classes based on prop
|
|
1539
1623
|
const layoutClasses = {
|
|
1540
|
-
horizontal:
|
|
1541
|
-
vertical:
|
|
1542
|
-
responsive:
|
|
1543
|
-
}
|
|
1624
|
+
horizontal: "flex-row items-center",
|
|
1625
|
+
vertical: "flex-col",
|
|
1626
|
+
responsive: "flex-col sm:flex-row sm:items-center",
|
|
1627
|
+
};
|
|
1544
1628
|
|
|
1545
1629
|
const heightClasses = {
|
|
1546
|
-
horizontal:
|
|
1547
|
-
vertical:
|
|
1548
|
-
responsive:
|
|
1549
|
-
}
|
|
1630
|
+
horizontal: "h-[76px]",
|
|
1631
|
+
vertical: "min-h-[76px] py-4",
|
|
1632
|
+
responsive: "min-h-[76px] py-4 sm:py-0 sm:h-[76px]",
|
|
1633
|
+
};
|
|
1550
1634
|
|
|
1551
1635
|
// Render actions for desktop (all inline)
|
|
1552
1636
|
const renderDesktopActions = () => (
|
|
1553
|
-
<div className="hidden sm:flex items-center gap-2">
|
|
1554
|
-
|
|
1555
|
-
</div>
|
|
1556
|
-
)
|
|
1637
|
+
<div className="hidden sm:flex items-center gap-2">{actionsArray}</div>
|
|
1638
|
+
);
|
|
1557
1639
|
|
|
1558
1640
|
// Render expandable actions (for mobile and vertical layout)
|
|
1559
1641
|
const renderExpandableActions = (additionalClasses?: string) => {
|
|
1560
1642
|
// Calculate grid columns: equal width for visible actions, smaller for overflow button
|
|
1561
|
-
const hasOverflowBtn = overflowActions.length > 0
|
|
1643
|
+
const hasOverflowBtn = overflowActions.length > 0;
|
|
1562
1644
|
const gridCols = hasOverflowBtn
|
|
1563
1645
|
? \`repeat(\${visibleActions.length}, 1fr) auto\`
|
|
1564
|
-
: \`repeat(\${visibleActions.length}, 1fr)
|
|
1646
|
+
: \`repeat(\${visibleActions.length}, 1fr)\`;
|
|
1565
1647
|
|
|
1566
1648
|
return (
|
|
1567
1649
|
<div className={cn("flex flex-col gap-2 w-full", additionalClasses)}>
|
|
@@ -1581,7 +1663,11 @@ const PageHeader = React.forwardRef<HTMLDivElement, PageHeaderProps>(
|
|
|
1581
1663
|
aria-label={isOverflowExpanded ? "Show less" : "More actions"}
|
|
1582
1664
|
aria-expanded={isOverflowExpanded}
|
|
1583
1665
|
>
|
|
1584
|
-
{isOverflowExpanded ?
|
|
1666
|
+
{isOverflowExpanded ? (
|
|
1667
|
+
<X className="w-4 h-4" />
|
|
1668
|
+
) : (
|
|
1669
|
+
<MoreHorizontal className="w-4 h-4" />
|
|
1670
|
+
)}
|
|
1585
1671
|
</Button>
|
|
1586
1672
|
)}
|
|
1587
1673
|
</div>
|
|
@@ -1597,25 +1683,23 @@ const PageHeader = React.forwardRef<HTMLDivElement, PageHeaderProps>(
|
|
|
1597
1683
|
</div>
|
|
1598
1684
|
)}
|
|
1599
1685
|
</div>
|
|
1600
|
-
)
|
|
1601
|
-
}
|
|
1686
|
+
);
|
|
1687
|
+
};
|
|
1602
1688
|
|
|
1603
1689
|
// For horizontal layout, always show all actions inline
|
|
1604
1690
|
const renderHorizontalActions = () => (
|
|
1605
|
-
<div className="flex items-center gap-2 ml-4">
|
|
1606
|
-
|
|
1607
|
-
</div>
|
|
1608
|
-
)
|
|
1691
|
+
<div className="flex items-center gap-2 ml-4">{actionsArray}</div>
|
|
1692
|
+
);
|
|
1609
1693
|
|
|
1610
1694
|
const renderActions = () => {
|
|
1611
|
-
if (!actions) return null
|
|
1695
|
+
if (!actions) return null;
|
|
1612
1696
|
|
|
1613
|
-
if (layout ===
|
|
1614
|
-
return renderHorizontalActions()
|
|
1697
|
+
if (layout === "horizontal") {
|
|
1698
|
+
return renderHorizontalActions();
|
|
1615
1699
|
}
|
|
1616
1700
|
|
|
1617
|
-
if (layout ===
|
|
1618
|
-
return renderExpandableActions("mt-3")
|
|
1701
|
+
if (layout === "vertical") {
|
|
1702
|
+
return renderExpandableActions("mt-3");
|
|
1619
1703
|
}
|
|
1620
1704
|
|
|
1621
1705
|
// Responsive: render both, CSS handles visibility
|
|
@@ -1626,8 +1710,8 @@ const PageHeader = React.forwardRef<HTMLDivElement, PageHeaderProps>(
|
|
|
1626
1710
|
{renderExpandableActions()}
|
|
1627
1711
|
</div>
|
|
1628
1712
|
</>
|
|
1629
|
-
)
|
|
1630
|
-
}
|
|
1713
|
+
);
|
|
1714
|
+
};
|
|
1631
1715
|
|
|
1632
1716
|
return (
|
|
1633
1717
|
<div
|
|
@@ -1645,9 +1729,7 @@ const PageHeader = React.forwardRef<HTMLDivElement, PageHeaderProps>(
|
|
|
1645
1729
|
<div className="flex items-center flex-1 min-w-0">
|
|
1646
1730
|
{/* Left Section: Icon or Back Button */}
|
|
1647
1731
|
{leftElement && (
|
|
1648
|
-
<div className="flex-shrink-0 mr-4">
|
|
1649
|
-
{leftElement}
|
|
1650
|
-
</div>
|
|
1732
|
+
<div className="flex-shrink-0 mr-4">{leftElement}</div>
|
|
1651
1733
|
)}
|
|
1652
1734
|
|
|
1653
1735
|
{/* Content Section: Title + Description */}
|
|
@@ -1673,17 +1755,17 @@ const PageHeader = React.forwardRef<HTMLDivElement, PageHeaderProps>(
|
|
|
1673
1755
|
{/* Actions Section */}
|
|
1674
1756
|
{renderActions()}
|
|
1675
1757
|
</div>
|
|
1676
|
-
)
|
|
1758
|
+
);
|
|
1677
1759
|
}
|
|
1678
|
-
)
|
|
1679
|
-
PageHeader.displayName = "PageHeader"
|
|
1760
|
+
);
|
|
1761
|
+
PageHeader.displayName = "PageHeader";
|
|
1680
1762
|
|
|
1681
|
-
export { PageHeader, pageHeaderVariants }
|
|
1763
|
+
export { PageHeader, pageHeaderVariants };
|
|
1682
1764
|
`,
|
|
1683
|
-
"select-field": `import * as React from "react"
|
|
1684
|
-
import { Loader2 } from "lucide-react"
|
|
1765
|
+
"select-field": `import * as React from "react";
|
|
1766
|
+
import { Loader2 } from "lucide-react";
|
|
1685
1767
|
|
|
1686
|
-
import { cn } from "@/lib/utils"
|
|
1768
|
+
import { cn } from "@/lib/utils";
|
|
1687
1769
|
import {
|
|
1688
1770
|
Select,
|
|
1689
1771
|
SelectContent,
|
|
@@ -1692,56 +1774,56 @@ import {
|
|
|
1692
1774
|
SelectLabel,
|
|
1693
1775
|
SelectTrigger,
|
|
1694
1776
|
SelectValue,
|
|
1695
|
-
} from "./select"
|
|
1777
|
+
} from "./select";
|
|
1696
1778
|
|
|
1697
1779
|
export interface SelectOption {
|
|
1698
1780
|
/** The value of the option */
|
|
1699
|
-
value: string
|
|
1781
|
+
value: string;
|
|
1700
1782
|
/** The display label of the option */
|
|
1701
|
-
label: string
|
|
1783
|
+
label: string;
|
|
1702
1784
|
/** Whether the option is disabled */
|
|
1703
|
-
disabled?: boolean
|
|
1785
|
+
disabled?: boolean;
|
|
1704
1786
|
/** Group name for grouping options */
|
|
1705
|
-
group?: string
|
|
1787
|
+
group?: string;
|
|
1706
1788
|
}
|
|
1707
1789
|
|
|
1708
1790
|
export interface SelectFieldProps {
|
|
1709
1791
|
/** Label text displayed above the select */
|
|
1710
|
-
label?: string
|
|
1792
|
+
label?: string;
|
|
1711
1793
|
/** Shows red asterisk next to label when true */
|
|
1712
|
-
required?: boolean
|
|
1794
|
+
required?: boolean;
|
|
1713
1795
|
/** Helper text displayed below the select */
|
|
1714
|
-
helperText?: string
|
|
1796
|
+
helperText?: string;
|
|
1715
1797
|
/** Error message - shows error state with red styling */
|
|
1716
|
-
error?: string
|
|
1798
|
+
error?: string;
|
|
1717
1799
|
/** Disabled state */
|
|
1718
|
-
disabled?: boolean
|
|
1800
|
+
disabled?: boolean;
|
|
1719
1801
|
/** Loading state with spinner */
|
|
1720
|
-
loading?: boolean
|
|
1802
|
+
loading?: boolean;
|
|
1721
1803
|
/** Placeholder text when no value selected */
|
|
1722
|
-
placeholder?: string
|
|
1804
|
+
placeholder?: string;
|
|
1723
1805
|
/** Currently selected value (controlled) */
|
|
1724
|
-
value?: string
|
|
1806
|
+
value?: string;
|
|
1725
1807
|
/** Default value (uncontrolled) */
|
|
1726
|
-
defaultValue?: string
|
|
1808
|
+
defaultValue?: string;
|
|
1727
1809
|
/** Callback when value changes */
|
|
1728
|
-
onValueChange?: (value: string) => void
|
|
1810
|
+
onValueChange?: (value: string) => void;
|
|
1729
1811
|
/** Options to display */
|
|
1730
|
-
options: SelectOption[]
|
|
1812
|
+
options: SelectOption[];
|
|
1731
1813
|
/** Enable search/filter functionality */
|
|
1732
|
-
searchable?: boolean
|
|
1814
|
+
searchable?: boolean;
|
|
1733
1815
|
/** Search placeholder text */
|
|
1734
|
-
searchPlaceholder?: string
|
|
1816
|
+
searchPlaceholder?: string;
|
|
1735
1817
|
/** Additional class for wrapper */
|
|
1736
|
-
wrapperClassName?: string
|
|
1818
|
+
wrapperClassName?: string;
|
|
1737
1819
|
/** Additional class for trigger */
|
|
1738
|
-
triggerClassName?: string
|
|
1820
|
+
triggerClassName?: string;
|
|
1739
1821
|
/** Additional class for label */
|
|
1740
|
-
labelClassName?: string
|
|
1822
|
+
labelClassName?: string;
|
|
1741
1823
|
/** ID for the select */
|
|
1742
|
-
id?: string
|
|
1824
|
+
id?: string;
|
|
1743
1825
|
/** Name attribute for form submission */
|
|
1744
|
-
name?: string
|
|
1826
|
+
name?: string;
|
|
1745
1827
|
}
|
|
1746
1828
|
|
|
1747
1829
|
/**
|
|
@@ -1786,59 +1868,59 @@ const SelectField = React.forwardRef<HTMLButtonElement, SelectFieldProps>(
|
|
|
1786
1868
|
ref
|
|
1787
1869
|
) => {
|
|
1788
1870
|
// Internal state for search
|
|
1789
|
-
const [searchQuery, setSearchQuery] = React.useState("")
|
|
1871
|
+
const [searchQuery, setSearchQuery] = React.useState("");
|
|
1790
1872
|
|
|
1791
1873
|
// Derive state from props
|
|
1792
|
-
const derivedState = error ? "error" : "default"
|
|
1874
|
+
const derivedState = error ? "error" : "default";
|
|
1793
1875
|
|
|
1794
1876
|
// Generate unique IDs for accessibility
|
|
1795
|
-
const generatedId = React.useId()
|
|
1796
|
-
const selectId = id || generatedId
|
|
1797
|
-
const helperId = \`\${selectId}-helper
|
|
1798
|
-
const errorId = \`\${selectId}-error
|
|
1877
|
+
const generatedId = React.useId();
|
|
1878
|
+
const selectId = id || generatedId;
|
|
1879
|
+
const helperId = \`\${selectId}-helper\`;
|
|
1880
|
+
const errorId = \`\${selectId}-error\`;
|
|
1799
1881
|
|
|
1800
1882
|
// Determine aria-describedby
|
|
1801
|
-
const ariaDescribedBy = error ? errorId : helperText ? helperId : undefined
|
|
1883
|
+
const ariaDescribedBy = error ? errorId : helperText ? helperId : undefined;
|
|
1802
1884
|
|
|
1803
1885
|
// Group options by group property
|
|
1804
1886
|
const groupedOptions = React.useMemo(() => {
|
|
1805
|
-
const groups: Record<string, SelectOption[]> = {}
|
|
1806
|
-
const ungrouped: SelectOption[] = []
|
|
1887
|
+
const groups: Record<string, SelectOption[]> = {};
|
|
1888
|
+
const ungrouped: SelectOption[] = [];
|
|
1807
1889
|
|
|
1808
1890
|
options.forEach((option) => {
|
|
1809
1891
|
// Filter by search query if searchable
|
|
1810
1892
|
if (searchable && searchQuery) {
|
|
1811
1893
|
if (!option.label.toLowerCase().includes(searchQuery.toLowerCase())) {
|
|
1812
|
-
return
|
|
1894
|
+
return;
|
|
1813
1895
|
}
|
|
1814
1896
|
}
|
|
1815
1897
|
|
|
1816
1898
|
if (option.group) {
|
|
1817
1899
|
if (!groups[option.group]) {
|
|
1818
|
-
groups[option.group] = []
|
|
1900
|
+
groups[option.group] = [];
|
|
1819
1901
|
}
|
|
1820
|
-
groups[option.group].push(option)
|
|
1902
|
+
groups[option.group].push(option);
|
|
1821
1903
|
} else {
|
|
1822
|
-
ungrouped.push(option)
|
|
1904
|
+
ungrouped.push(option);
|
|
1823
1905
|
}
|
|
1824
|
-
})
|
|
1906
|
+
});
|
|
1825
1907
|
|
|
1826
|
-
return { groups, ungrouped }
|
|
1827
|
-
}, [options, searchable, searchQuery])
|
|
1908
|
+
return { groups, ungrouped };
|
|
1909
|
+
}, [options, searchable, searchQuery]);
|
|
1828
1910
|
|
|
1829
|
-
const hasGroups = Object.keys(groupedOptions.groups).length > 0
|
|
1911
|
+
const hasGroups = Object.keys(groupedOptions.groups).length > 0;
|
|
1830
1912
|
|
|
1831
1913
|
// Handle search input change
|
|
1832
1914
|
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
1833
|
-
setSearchQuery(e.target.value)
|
|
1834
|
-
}
|
|
1915
|
+
setSearchQuery(e.target.value);
|
|
1916
|
+
};
|
|
1835
1917
|
|
|
1836
1918
|
// Reset search when dropdown closes
|
|
1837
1919
|
const handleOpenChange = (open: boolean) => {
|
|
1838
1920
|
if (!open) {
|
|
1839
|
-
setSearchQuery("")
|
|
1921
|
+
setSearchQuery("");
|
|
1840
1922
|
}
|
|
1841
|
-
}
|
|
1923
|
+
};
|
|
1842
1924
|
|
|
1843
1925
|
return (
|
|
1844
1926
|
<div className={cn("flex flex-col gap-1", wrapperClassName)}>
|
|
@@ -1866,10 +1948,7 @@ const SelectField = React.forwardRef<HTMLButtonElement, SelectFieldProps>(
|
|
|
1866
1948
|
ref={ref}
|
|
1867
1949
|
id={selectId}
|
|
1868
1950
|
state={derivedState}
|
|
1869
|
-
className={cn(
|
|
1870
|
-
loading && "pr-10",
|
|
1871
|
-
triggerClassName
|
|
1872
|
-
)}
|
|
1951
|
+
className={cn(loading && "pr-10", triggerClassName)}
|
|
1873
1952
|
aria-invalid={!!error}
|
|
1874
1953
|
aria-describedby={ariaDescribedBy}
|
|
1875
1954
|
>
|
|
@@ -1908,20 +1987,22 @@ const SelectField = React.forwardRef<HTMLButtonElement, SelectFieldProps>(
|
|
|
1908
1987
|
|
|
1909
1988
|
{/* Grouped options */}
|
|
1910
1989
|
{hasGroups &&
|
|
1911
|
-
Object.entries(groupedOptions.groups).map(
|
|
1912
|
-
|
|
1913
|
-
<
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1990
|
+
Object.entries(groupedOptions.groups).map(
|
|
1991
|
+
([groupName, groupOptions]) => (
|
|
1992
|
+
<SelectGroup key={groupName}>
|
|
1993
|
+
<SelectLabel>{groupName}</SelectLabel>
|
|
1994
|
+
{groupOptions.map((option) => (
|
|
1995
|
+
<SelectItem
|
|
1996
|
+
key={option.value}
|
|
1997
|
+
value={option.value}
|
|
1998
|
+
disabled={option.disabled}
|
|
1999
|
+
>
|
|
2000
|
+
{option.label}
|
|
2001
|
+
</SelectItem>
|
|
2002
|
+
))}
|
|
2003
|
+
</SelectGroup>
|
|
2004
|
+
)
|
|
2005
|
+
)}
|
|
1925
2006
|
|
|
1926
2007
|
{/* No results message */}
|
|
1927
2008
|
{searchable &&
|
|
@@ -1950,19 +2031,19 @@ const SelectField = React.forwardRef<HTMLButtonElement, SelectFieldProps>(
|
|
|
1950
2031
|
</div>
|
|
1951
2032
|
)}
|
|
1952
2033
|
</div>
|
|
1953
|
-
)
|
|
2034
|
+
);
|
|
1954
2035
|
}
|
|
1955
|
-
)
|
|
1956
|
-
SelectField.displayName = "SelectField"
|
|
2036
|
+
);
|
|
2037
|
+
SelectField.displayName = "SelectField";
|
|
1957
2038
|
|
|
1958
|
-
export { SelectField }
|
|
2039
|
+
export { SelectField };
|
|
1959
2040
|
`,
|
|
1960
|
-
"select": `import * as React from "react"
|
|
1961
|
-
import * as SelectPrimitive from "@radix-ui/react-select"
|
|
1962
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
1963
|
-
import { Check, ChevronDown, ChevronUp } from "lucide-react"
|
|
2041
|
+
"select": `import * as React from "react";
|
|
2042
|
+
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
2043
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
2044
|
+
import { Check, ChevronDown, ChevronUp } from "lucide-react";
|
|
1964
2045
|
|
|
1965
|
-
import { cn } from "@/lib/utils"
|
|
2046
|
+
import { cn } from "@/lib/utils";
|
|
1966
2047
|
|
|
1967
2048
|
/**
|
|
1968
2049
|
* SelectTrigger variants matching TextField styling
|
|
@@ -1972,24 +2053,27 @@ const selectTriggerVariants = cva(
|
|
|
1972
2053
|
{
|
|
1973
2054
|
variants: {
|
|
1974
2055
|
state: {
|
|
1975
|
-
default:
|
|
1976
|
-
|
|
2056
|
+
default:
|
|
2057
|
+
"border border-[#E9EAEB] focus:outline-none focus:border-[#2BBCCA]/50 focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
|
|
2058
|
+
error:
|
|
2059
|
+
"border border-[#F04438]/40 focus:outline-none focus:border-[#F04438]/60 focus:shadow-[0_0_0_1px_rgba(240,68,56,0.1)]",
|
|
1977
2060
|
},
|
|
1978
2061
|
},
|
|
1979
2062
|
defaultVariants: {
|
|
1980
2063
|
state: "default",
|
|
1981
2064
|
},
|
|
1982
2065
|
}
|
|
1983
|
-
)
|
|
2066
|
+
);
|
|
1984
2067
|
|
|
1985
|
-
const Select = SelectPrimitive.Root
|
|
2068
|
+
const Select = SelectPrimitive.Root;
|
|
1986
2069
|
|
|
1987
|
-
const SelectGroup = SelectPrimitive.Group
|
|
2070
|
+
const SelectGroup = SelectPrimitive.Group;
|
|
1988
2071
|
|
|
1989
|
-
const SelectValue = SelectPrimitive.Value
|
|
2072
|
+
const SelectValue = SelectPrimitive.Value;
|
|
1990
2073
|
|
|
1991
2074
|
export interface SelectTriggerProps
|
|
1992
|
-
extends
|
|
2075
|
+
extends
|
|
2076
|
+
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>,
|
|
1993
2077
|
VariantProps<typeof selectTriggerVariants> {}
|
|
1994
2078
|
|
|
1995
2079
|
const SelectTrigger = React.forwardRef<
|
|
@@ -2006,8 +2090,8 @@ const SelectTrigger = React.forwardRef<
|
|
|
2006
2090
|
<ChevronDown className="size-4 text-[#717680] opacity-70" />
|
|
2007
2091
|
</SelectPrimitive.Icon>
|
|
2008
2092
|
</SelectPrimitive.Trigger>
|
|
2009
|
-
))
|
|
2010
|
-
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
|
|
2093
|
+
));
|
|
2094
|
+
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
|
2011
2095
|
|
|
2012
2096
|
const SelectScrollUpButton = React.forwardRef<
|
|
2013
2097
|
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
|
@@ -2023,8 +2107,8 @@ const SelectScrollUpButton = React.forwardRef<
|
|
|
2023
2107
|
>
|
|
2024
2108
|
<ChevronUp className="size-4 text-[#717680]" />
|
|
2025
2109
|
</SelectPrimitive.ScrollUpButton>
|
|
2026
|
-
))
|
|
2027
|
-
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
|
|
2110
|
+
));
|
|
2111
|
+
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
|
2028
2112
|
|
|
2029
2113
|
const SelectScrollDownButton = React.forwardRef<
|
|
2030
2114
|
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
|
@@ -2040,8 +2124,9 @@ const SelectScrollDownButton = React.forwardRef<
|
|
|
2040
2124
|
>
|
|
2041
2125
|
<ChevronDown className="size-4 text-[#717680]" />
|
|
2042
2126
|
</SelectPrimitive.ScrollDownButton>
|
|
2043
|
-
))
|
|
2044
|
-
SelectScrollDownButton.displayName =
|
|
2127
|
+
));
|
|
2128
|
+
SelectScrollDownButton.displayName =
|
|
2129
|
+
SelectPrimitive.ScrollDownButton.displayName;
|
|
2045
2130
|
|
|
2046
2131
|
const SelectContent = React.forwardRef<
|
|
2047
2132
|
React.ElementRef<typeof SelectPrimitive.Content>,
|
|
@@ -2077,8 +2162,8 @@ const SelectContent = React.forwardRef<
|
|
|
2077
2162
|
<SelectScrollDownButton />
|
|
2078
2163
|
</SelectPrimitive.Content>
|
|
2079
2164
|
</SelectPrimitive.Portal>
|
|
2080
|
-
))
|
|
2081
|
-
SelectContent.displayName = SelectPrimitive.Content.displayName
|
|
2165
|
+
));
|
|
2166
|
+
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
2082
2167
|
|
|
2083
2168
|
const SelectLabel = React.forwardRef<
|
|
2084
2169
|
React.ElementRef<typeof SelectPrimitive.Label>,
|
|
@@ -2089,8 +2174,8 @@ const SelectLabel = React.forwardRef<
|
|
|
2089
2174
|
className={cn("px-4 py-1.5 text-xs font-medium text-[#717680]", className)}
|
|
2090
2175
|
{...props}
|
|
2091
2176
|
/>
|
|
2092
|
-
))
|
|
2093
|
-
SelectLabel.displayName = SelectPrimitive.Label.displayName
|
|
2177
|
+
));
|
|
2178
|
+
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
2094
2179
|
|
|
2095
2180
|
const SelectItem = React.forwardRef<
|
|
2096
2181
|
React.ElementRef<typeof SelectPrimitive.Item>,
|
|
@@ -2113,8 +2198,8 @@ const SelectItem = React.forwardRef<
|
|
|
2113
2198
|
</span>
|
|
2114
2199
|
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
|
2115
2200
|
</SelectPrimitive.Item>
|
|
2116
|
-
))
|
|
2117
|
-
SelectItem.displayName = SelectPrimitive.Item.displayName
|
|
2201
|
+
));
|
|
2202
|
+
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
2118
2203
|
|
|
2119
2204
|
const SelectSeparator = React.forwardRef<
|
|
2120
2205
|
React.ElementRef<typeof SelectPrimitive.Separator>,
|
|
@@ -2125,8 +2210,8 @@ const SelectSeparator = React.forwardRef<
|
|
|
2125
2210
|
className={cn("-mx-1 my-1 h-px bg-[#E9EAEB]", className)}
|
|
2126
2211
|
{...props}
|
|
2127
2212
|
/>
|
|
2128
|
-
))
|
|
2129
|
-
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
|
|
2213
|
+
));
|
|
2214
|
+
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
|
2130
2215
|
|
|
2131
2216
|
export {
|
|
2132
2217
|
Select,
|
|
@@ -2140,13 +2225,13 @@ export {
|
|
|
2140
2225
|
SelectScrollUpButton,
|
|
2141
2226
|
SelectScrollDownButton,
|
|
2142
2227
|
selectTriggerVariants,
|
|
2143
|
-
}
|
|
2228
|
+
};
|
|
2144
2229
|
`,
|
|
2145
|
-
"switch": `import * as React from "react"
|
|
2146
|
-
import * as SwitchPrimitives from "@radix-ui/react-switch"
|
|
2147
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
2230
|
+
"switch": `import * as React from "react";
|
|
2231
|
+
import * as SwitchPrimitives from "@radix-ui/react-switch";
|
|
2232
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
2148
2233
|
|
|
2149
|
-
import { cn } from "@/lib/utils"
|
|
2234
|
+
import { cn } from "@/lib/utils";
|
|
2150
2235
|
|
|
2151
2236
|
/**
|
|
2152
2237
|
* Switch track variants (the outer container)
|
|
@@ -2165,7 +2250,7 @@ const switchVariants = cva(
|
|
|
2165
2250
|
size: "default",
|
|
2166
2251
|
},
|
|
2167
2252
|
}
|
|
2168
|
-
)
|
|
2253
|
+
);
|
|
2169
2254
|
|
|
2170
2255
|
/**
|
|
2171
2256
|
* Switch thumb variants (the sliding circle)
|
|
@@ -2184,7 +2269,7 @@ const switchThumbVariants = cva(
|
|
|
2184
2269
|
size: "default",
|
|
2185
2270
|
},
|
|
2186
2271
|
}
|
|
2187
|
-
)
|
|
2272
|
+
);
|
|
2188
2273
|
|
|
2189
2274
|
/**
|
|
2190
2275
|
* Label text size variants
|
|
@@ -2200,7 +2285,7 @@ const labelSizeVariants = cva("", {
|
|
|
2200
2285
|
defaultVariants: {
|
|
2201
2286
|
size: "default",
|
|
2202
2287
|
},
|
|
2203
|
-
})
|
|
2288
|
+
});
|
|
2204
2289
|
|
|
2205
2290
|
/**
|
|
2206
2291
|
* A switch/toggle component for boolean inputs with on/off states
|
|
@@ -2213,12 +2298,16 @@ const labelSizeVariants = cva("", {
|
|
|
2213
2298
|
* \`\`\`
|
|
2214
2299
|
*/
|
|
2215
2300
|
export interface SwitchProps
|
|
2216
|
-
extends
|
|
2301
|
+
extends
|
|
2302
|
+
Omit<
|
|
2303
|
+
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>,
|
|
2304
|
+
"onChange"
|
|
2305
|
+
>,
|
|
2217
2306
|
VariantProps<typeof switchVariants> {
|
|
2218
2307
|
/** Optional label text */
|
|
2219
|
-
label?: string
|
|
2308
|
+
label?: string;
|
|
2220
2309
|
/** Position of the label */
|
|
2221
|
-
labelPosition?: "left" | "right"
|
|
2310
|
+
labelPosition?: "left" | "right";
|
|
2222
2311
|
}
|
|
2223
2312
|
|
|
2224
2313
|
const Switch = React.forwardRef<
|
|
@@ -2226,14 +2315,7 @@ const Switch = React.forwardRef<
|
|
|
2226
2315
|
SwitchProps
|
|
2227
2316
|
>(
|
|
2228
2317
|
(
|
|
2229
|
-
{
|
|
2230
|
-
className,
|
|
2231
|
-
size,
|
|
2232
|
-
label,
|
|
2233
|
-
labelPosition = "right",
|
|
2234
|
-
disabled,
|
|
2235
|
-
...props
|
|
2236
|
-
},
|
|
2318
|
+
{ className, size, label, labelPosition = "right", disabled, ...props },
|
|
2237
2319
|
ref
|
|
2238
2320
|
) => {
|
|
2239
2321
|
const switchElement = (
|
|
@@ -2245,68 +2327,71 @@ const Switch = React.forwardRef<
|
|
|
2245
2327
|
>
|
|
2246
2328
|
<SwitchPrimitives.Thumb className={cn(switchThumbVariants({ size }))} />
|
|
2247
2329
|
</SwitchPrimitives.Root>
|
|
2248
|
-
)
|
|
2330
|
+
);
|
|
2249
2331
|
|
|
2250
2332
|
if (label) {
|
|
2251
2333
|
return (
|
|
2252
|
-
<label
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2334
|
+
<label
|
|
2335
|
+
className={cn(
|
|
2336
|
+
"inline-flex items-center gap-2 cursor-pointer",
|
|
2337
|
+
disabled && "cursor-not-allowed"
|
|
2338
|
+
)}
|
|
2339
|
+
>
|
|
2256
2340
|
{labelPosition === "left" && (
|
|
2257
|
-
<span
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2341
|
+
<span
|
|
2342
|
+
className={cn(
|
|
2343
|
+
labelSizeVariants({ size }),
|
|
2344
|
+
"text-[#181D27]",
|
|
2345
|
+
disabled && "opacity-50"
|
|
2346
|
+
)}
|
|
2347
|
+
>
|
|
2262
2348
|
{label}
|
|
2263
2349
|
</span>
|
|
2264
2350
|
)}
|
|
2265
2351
|
{switchElement}
|
|
2266
2352
|
{labelPosition === "right" && (
|
|
2267
|
-
<span
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2353
|
+
<span
|
|
2354
|
+
className={cn(
|
|
2355
|
+
labelSizeVariants({ size }),
|
|
2356
|
+
"text-[#181D27]",
|
|
2357
|
+
disabled && "opacity-50"
|
|
2358
|
+
)}
|
|
2359
|
+
>
|
|
2272
2360
|
{label}
|
|
2273
2361
|
</span>
|
|
2274
2362
|
)}
|
|
2275
2363
|
</label>
|
|
2276
|
-
)
|
|
2364
|
+
);
|
|
2277
2365
|
}
|
|
2278
2366
|
|
|
2279
|
-
return switchElement
|
|
2367
|
+
return switchElement;
|
|
2280
2368
|
}
|
|
2281
|
-
)
|
|
2282
|
-
Switch.displayName = "Switch"
|
|
2369
|
+
);
|
|
2370
|
+
Switch.displayName = "Switch";
|
|
2283
2371
|
|
|
2284
|
-
export { Switch, switchVariants }
|
|
2372
|
+
export { Switch, switchVariants };
|
|
2285
2373
|
`,
|
|
2286
|
-
"table": `import * as React from "react"
|
|
2287
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
2374
|
+
"table": `import * as React from "react";
|
|
2375
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
2288
2376
|
|
|
2289
|
-
import { cn } from "@/lib/utils"
|
|
2290
|
-
import { Switch, type SwitchProps } from "./switch"
|
|
2377
|
+
import { cn } from "@/lib/utils";
|
|
2378
|
+
import { Switch, type SwitchProps } from "./switch";
|
|
2291
2379
|
|
|
2292
2380
|
/**
|
|
2293
2381
|
* Table size variants for row height.
|
|
2294
2382
|
*/
|
|
2295
|
-
const tableVariants = cva(
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
md: "[&_td]:py-3 [&_th]:py-3",
|
|
2302
|
-
lg: "[&_td]:py-4 [&_th]:py-4",
|
|
2303
|
-
},
|
|
2304
|
-
},
|
|
2305
|
-
defaultVariants: {
|
|
2306
|
-
size: "md",
|
|
2383
|
+
const tableVariants = cva("w-full caption-bottom text-sm", {
|
|
2384
|
+
variants: {
|
|
2385
|
+
size: {
|
|
2386
|
+
sm: "[&_td]:py-2 [&_th]:py-2",
|
|
2387
|
+
md: "[&_td]:py-3 [&_th]:py-3",
|
|
2388
|
+
lg: "[&_td]:py-4 [&_th]:py-4",
|
|
2307
2389
|
},
|
|
2308
|
-
}
|
|
2309
|
-
|
|
2390
|
+
},
|
|
2391
|
+
defaultVariants: {
|
|
2392
|
+
size: "md",
|
|
2393
|
+
},
|
|
2394
|
+
});
|
|
2310
2395
|
|
|
2311
2396
|
/**
|
|
2312
2397
|
* Table component for displaying tabular data.
|
|
@@ -2331,18 +2416,21 @@ const tableVariants = cva(
|
|
|
2331
2416
|
*/
|
|
2332
2417
|
|
|
2333
2418
|
export interface TableProps
|
|
2334
|
-
extends
|
|
2419
|
+
extends
|
|
2420
|
+
React.HTMLAttributes<HTMLTableElement>,
|
|
2335
2421
|
VariantProps<typeof tableVariants> {
|
|
2336
2422
|
/** Remove outer border from the table */
|
|
2337
|
-
withoutBorder?: boolean
|
|
2423
|
+
withoutBorder?: boolean;
|
|
2338
2424
|
}
|
|
2339
2425
|
|
|
2340
2426
|
const Table = React.forwardRef<HTMLTableElement, TableProps>(
|
|
2341
2427
|
({ className, size, withoutBorder, ...props }, ref) => (
|
|
2342
|
-
<div
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2428
|
+
<div
|
|
2429
|
+
className={cn(
|
|
2430
|
+
"relative w-full overflow-auto",
|
|
2431
|
+
!withoutBorder && "rounded-lg border border-[#E9EAEB]"
|
|
2432
|
+
)}
|
|
2433
|
+
>
|
|
2346
2434
|
<table
|
|
2347
2435
|
ref={ref}
|
|
2348
2436
|
className={cn(tableVariants({ size, className }))}
|
|
@@ -2350,8 +2438,8 @@ const Table = React.forwardRef<HTMLTableElement, TableProps>(
|
|
|
2350
2438
|
/>
|
|
2351
2439
|
</div>
|
|
2352
2440
|
)
|
|
2353
|
-
)
|
|
2354
|
-
Table.displayName = "Table"
|
|
2441
|
+
);
|
|
2442
|
+
Table.displayName = "Table";
|
|
2355
2443
|
|
|
2356
2444
|
const TableHeader = React.forwardRef<
|
|
2357
2445
|
HTMLTableSectionElement,
|
|
@@ -2362,8 +2450,8 @@ const TableHeader = React.forwardRef<
|
|
|
2362
2450
|
className={cn("bg-[#FAFAFA] [&_tr]:border-b", className)}
|
|
2363
2451
|
{...props}
|
|
2364
2452
|
/>
|
|
2365
|
-
))
|
|
2366
|
-
TableHeader.displayName = "TableHeader"
|
|
2453
|
+
));
|
|
2454
|
+
TableHeader.displayName = "TableHeader";
|
|
2367
2455
|
|
|
2368
2456
|
const TableBody = React.forwardRef<
|
|
2369
2457
|
HTMLTableSectionElement,
|
|
@@ -2374,8 +2462,8 @@ const TableBody = React.forwardRef<
|
|
|
2374
2462
|
className={cn("[&_tr:last-child]:border-0", className)}
|
|
2375
2463
|
{...props}
|
|
2376
2464
|
/>
|
|
2377
|
-
))
|
|
2378
|
-
TableBody.displayName = "TableBody"
|
|
2465
|
+
));
|
|
2466
|
+
TableBody.displayName = "TableBody";
|
|
2379
2467
|
|
|
2380
2468
|
const TableFooter = React.forwardRef<
|
|
2381
2469
|
HTMLTableSectionElement,
|
|
@@ -2389,12 +2477,12 @@ const TableFooter = React.forwardRef<
|
|
|
2389
2477
|
)}
|
|
2390
2478
|
{...props}
|
|
2391
2479
|
/>
|
|
2392
|
-
))
|
|
2393
|
-
TableFooter.displayName = "TableFooter"
|
|
2480
|
+
));
|
|
2481
|
+
TableFooter.displayName = "TableFooter";
|
|
2394
2482
|
|
|
2395
2483
|
export interface TableRowProps extends React.HTMLAttributes<HTMLTableRowElement> {
|
|
2396
2484
|
/** Highlight the row with a colored background */
|
|
2397
|
-
highlighted?: boolean
|
|
2485
|
+
highlighted?: boolean;
|
|
2398
2486
|
}
|
|
2399
2487
|
|
|
2400
2488
|
const TableRow = React.forwardRef<HTMLTableRowElement, TableRowProps>(
|
|
@@ -2411,20 +2499,23 @@ const TableRow = React.forwardRef<HTMLTableRowElement, TableRowProps>(
|
|
|
2411
2499
|
{...props}
|
|
2412
2500
|
/>
|
|
2413
2501
|
)
|
|
2414
|
-
)
|
|
2415
|
-
TableRow.displayName = "TableRow"
|
|
2502
|
+
);
|
|
2503
|
+
TableRow.displayName = "TableRow";
|
|
2416
2504
|
|
|
2417
2505
|
export interface TableHeadProps extends React.ThHTMLAttributes<HTMLTableCellElement> {
|
|
2418
2506
|
/** Make this column sticky on horizontal scroll */
|
|
2419
|
-
sticky?: boolean
|
|
2507
|
+
sticky?: boolean;
|
|
2420
2508
|
/** Sort direction indicator */
|
|
2421
|
-
sortDirection?:
|
|
2509
|
+
sortDirection?: "asc" | "desc" | null;
|
|
2422
2510
|
/** Show info icon with tooltip */
|
|
2423
|
-
infoTooltip?: string
|
|
2511
|
+
infoTooltip?: string;
|
|
2424
2512
|
}
|
|
2425
2513
|
|
|
2426
2514
|
const TableHead = React.forwardRef<HTMLTableCellElement, TableHeadProps>(
|
|
2427
|
-
(
|
|
2515
|
+
(
|
|
2516
|
+
{ className, sticky, sortDirection, infoTooltip, children, ...props },
|
|
2517
|
+
ref
|
|
2518
|
+
) => (
|
|
2428
2519
|
<th
|
|
2429
2520
|
ref={ref}
|
|
2430
2521
|
className={cn(
|
|
@@ -2439,7 +2530,7 @@ const TableHead = React.forwardRef<HTMLTableCellElement, TableHeadProps>(
|
|
|
2439
2530
|
{children}
|
|
2440
2531
|
{sortDirection && (
|
|
2441
2532
|
<span className="text-[#A4A7AE]">
|
|
2442
|
-
{sortDirection ===
|
|
2533
|
+
{sortDirection === "asc" ? "\u2191" : "\u2193"}
|
|
2443
2534
|
</span>
|
|
2444
2535
|
)}
|
|
2445
2536
|
{infoTooltip && (
|
|
@@ -2450,12 +2541,12 @@ const TableHead = React.forwardRef<HTMLTableCellElement, TableHeadProps>(
|
|
|
2450
2541
|
</div>
|
|
2451
2542
|
</th>
|
|
2452
2543
|
)
|
|
2453
|
-
)
|
|
2454
|
-
TableHead.displayName = "TableHead"
|
|
2544
|
+
);
|
|
2545
|
+
TableHead.displayName = "TableHead";
|
|
2455
2546
|
|
|
2456
2547
|
export interface TableCellProps extends React.TdHTMLAttributes<HTMLTableCellElement> {
|
|
2457
2548
|
/** Make this cell sticky on horizontal scroll */
|
|
2458
|
-
sticky?: boolean
|
|
2549
|
+
sticky?: boolean;
|
|
2459
2550
|
}
|
|
2460
2551
|
|
|
2461
2552
|
const TableCell = React.forwardRef<HTMLTableCellElement, TableCellProps>(
|
|
@@ -2470,8 +2561,8 @@ const TableCell = React.forwardRef<HTMLTableCellElement, TableCellProps>(
|
|
|
2470
2561
|
{...props}
|
|
2471
2562
|
/>
|
|
2472
2563
|
)
|
|
2473
|
-
)
|
|
2474
|
-
TableCell.displayName = "TableCell"
|
|
2564
|
+
);
|
|
2565
|
+
TableCell.displayName = "TableCell";
|
|
2475
2566
|
|
|
2476
2567
|
const TableCaption = React.forwardRef<
|
|
2477
2568
|
HTMLTableCaptionElement,
|
|
@@ -2482,17 +2573,17 @@ const TableCaption = React.forwardRef<
|
|
|
2482
2573
|
className={cn("mt-4 text-sm text-[#717680]", className)}
|
|
2483
2574
|
{...props}
|
|
2484
2575
|
/>
|
|
2485
|
-
))
|
|
2486
|
-
TableCaption.displayName = "TableCaption"
|
|
2576
|
+
));
|
|
2577
|
+
TableCaption.displayName = "TableCaption";
|
|
2487
2578
|
|
|
2488
2579
|
/**
|
|
2489
2580
|
* TableSkeleton - Loading state for table rows
|
|
2490
2581
|
*/
|
|
2491
2582
|
export interface TableSkeletonProps {
|
|
2492
2583
|
/** Number of rows to show */
|
|
2493
|
-
rows?: number
|
|
2584
|
+
rows?: number;
|
|
2494
2585
|
/** Number of columns to show */
|
|
2495
|
-
columns?: number
|
|
2586
|
+
columns?: number;
|
|
2496
2587
|
}
|
|
2497
2588
|
|
|
2498
2589
|
const TableSkeleton = ({ rows = 5, columns = 5 }: TableSkeletonProps) => (
|
|
@@ -2501,24 +2592,28 @@ const TableSkeleton = ({ rows = 5, columns = 5 }: TableSkeletonProps) => (
|
|
|
2501
2592
|
<TableRow key={rowIndex}>
|
|
2502
2593
|
{Array.from({ length: columns }).map((_, colIndex) => (
|
|
2503
2594
|
<TableCell key={colIndex}>
|
|
2504
|
-
<div
|
|
2505
|
-
|
|
2595
|
+
<div
|
|
2596
|
+
className="h-4 bg-[#E9EAEB] rounded animate-pulse"
|
|
2597
|
+
style={{
|
|
2598
|
+
width: colIndex === 1 ? "80%" : colIndex === 2 ? "30%" : "60%",
|
|
2599
|
+
}}
|
|
2600
|
+
/>
|
|
2506
2601
|
</TableCell>
|
|
2507
2602
|
))}
|
|
2508
2603
|
</TableRow>
|
|
2509
2604
|
))}
|
|
2510
2605
|
</>
|
|
2511
|
-
)
|
|
2512
|
-
TableSkeleton.displayName = "TableSkeleton"
|
|
2606
|
+
);
|
|
2607
|
+
TableSkeleton.displayName = "TableSkeleton";
|
|
2513
2608
|
|
|
2514
2609
|
/**
|
|
2515
2610
|
* TableEmpty - Empty state message
|
|
2516
2611
|
*/
|
|
2517
2612
|
export interface TableEmptyProps {
|
|
2518
2613
|
/** Number of columns to span */
|
|
2519
|
-
colSpan: number
|
|
2614
|
+
colSpan: number;
|
|
2520
2615
|
/** Custom message or component */
|
|
2521
|
-
children?: React.ReactNode
|
|
2616
|
+
children?: React.ReactNode;
|
|
2522
2617
|
}
|
|
2523
2618
|
|
|
2524
2619
|
const TableEmpty = ({ colSpan, children }: TableEmptyProps) => (
|
|
@@ -2527,17 +2622,17 @@ const TableEmpty = ({ colSpan, children }: TableEmptyProps) => (
|
|
|
2527
2622
|
{children || "No data available"}
|
|
2528
2623
|
</TableCell>
|
|
2529
2624
|
</TableRow>
|
|
2530
|
-
)
|
|
2531
|
-
TableEmpty.displayName = "TableEmpty"
|
|
2625
|
+
);
|
|
2626
|
+
TableEmpty.displayName = "TableEmpty";
|
|
2532
2627
|
|
|
2533
2628
|
/**
|
|
2534
2629
|
* Avatar component for table cells
|
|
2535
2630
|
*/
|
|
2536
2631
|
export interface TableAvatarProps {
|
|
2537
2632
|
/** Initials to display */
|
|
2538
|
-
initials: string
|
|
2633
|
+
initials: string;
|
|
2539
2634
|
/** Background color */
|
|
2540
|
-
color?: string
|
|
2635
|
+
color?: string;
|
|
2541
2636
|
}
|
|
2542
2637
|
|
|
2543
2638
|
const TableAvatar = ({ initials, color = "#7C3AED" }: TableAvatarProps) => (
|
|
@@ -2547,23 +2642,23 @@ const TableAvatar = ({ initials, color = "#7C3AED" }: TableAvatarProps) => (
|
|
|
2547
2642
|
>
|
|
2548
2643
|
{initials}
|
|
2549
2644
|
</div>
|
|
2550
|
-
)
|
|
2551
|
-
TableAvatar.displayName = "TableAvatar"
|
|
2645
|
+
);
|
|
2646
|
+
TableAvatar.displayName = "TableAvatar";
|
|
2552
2647
|
|
|
2553
2648
|
/**
|
|
2554
2649
|
* Switch component optimized for table cells (previously TableToggle)
|
|
2555
2650
|
*/
|
|
2556
|
-
export interface TableToggleProps extends Omit<SwitchProps,
|
|
2651
|
+
export interface TableToggleProps extends Omit<SwitchProps, "size"> {
|
|
2557
2652
|
/** Size of the switch - defaults to 'sm' for tables */
|
|
2558
|
-
size?:
|
|
2653
|
+
size?: "sm" | "default";
|
|
2559
2654
|
}
|
|
2560
2655
|
|
|
2561
2656
|
const TableToggle = React.forwardRef<HTMLButtonElement, TableToggleProps>(
|
|
2562
|
-
({ size =
|
|
2657
|
+
({ size = "sm", ...props }, ref) => (
|
|
2563
2658
|
<Switch ref={ref} size={size} {...props} />
|
|
2564
2659
|
)
|
|
2565
|
-
)
|
|
2566
|
-
TableToggle.displayName = "TableToggle"
|
|
2660
|
+
);
|
|
2661
|
+
TableToggle.displayName = "TableToggle";
|
|
2567
2662
|
|
|
2568
2663
|
export {
|
|
2569
2664
|
Table,
|
|
@@ -2579,43 +2674,40 @@ export {
|
|
|
2579
2674
|
TableAvatar,
|
|
2580
2675
|
TableToggle,
|
|
2581
2676
|
tableVariants,
|
|
2582
|
-
}
|
|
2677
|
+
};
|
|
2583
2678
|
`,
|
|
2584
|
-
"tag": `import * as React from "react"
|
|
2585
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
2679
|
+
"tag": `import * as React from "react";
|
|
2680
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
2586
2681
|
|
|
2587
|
-
import { cn } from "@/lib/utils"
|
|
2682
|
+
import { cn } from "@/lib/utils";
|
|
2588
2683
|
|
|
2589
2684
|
/**
|
|
2590
2685
|
* Tag variants for event labels and categories.
|
|
2591
2686
|
* Rounded rectangle tags with optional bold labels.
|
|
2592
2687
|
*/
|
|
2593
|
-
const tagVariants = cva(
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
error: "bg-[#FEF3F2] text-[#F04438]",
|
|
2605
|
-
destructive: "bg-[#FEF3F2] text-[#F04438]",
|
|
2606
|
-
},
|
|
2607
|
-
size: {
|
|
2608
|
-
default: "px-2 py-1",
|
|
2609
|
-
sm: "px-1.5 py-0.5 text-xs",
|
|
2610
|
-
lg: "px-3 py-1.5",
|
|
2611
|
-
},
|
|
2688
|
+
const tagVariants = cva("inline-flex items-center rounded text-sm", {
|
|
2689
|
+
variants: {
|
|
2690
|
+
variant: {
|
|
2691
|
+
default: "bg-[#F5F5F5] text-[#181D27]",
|
|
2692
|
+
primary: "bg-[#F5F5F5] text-[#181D27]",
|
|
2693
|
+
accent: "bg-[#EBECEE] text-[#343E55]",
|
|
2694
|
+
secondary: "bg-[#E9EAEB] text-[#414651]",
|
|
2695
|
+
success: "bg-[#ECFDF3] text-[#17B26A]",
|
|
2696
|
+
warning: "bg-[#FFFAEB] text-[#F79009]",
|
|
2697
|
+
error: "bg-[#FEF3F2] text-[#F04438]",
|
|
2698
|
+
destructive: "bg-[#FEF3F2] text-[#F04438]",
|
|
2612
2699
|
},
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2700
|
+
size: {
|
|
2701
|
+
default: "px-2 py-1",
|
|
2702
|
+
sm: "px-1.5 py-0.5 text-xs",
|
|
2703
|
+
lg: "px-3 py-1.5",
|
|
2616
2704
|
},
|
|
2617
|
-
}
|
|
2618
|
-
|
|
2705
|
+
},
|
|
2706
|
+
defaultVariants: {
|
|
2707
|
+
variant: "default",
|
|
2708
|
+
size: "default",
|
|
2709
|
+
},
|
|
2710
|
+
});
|
|
2619
2711
|
|
|
2620
2712
|
/**
|
|
2621
2713
|
* Tag component for displaying event labels and categories.
|
|
@@ -2627,10 +2719,11 @@ const tagVariants = cva(
|
|
|
2627
2719
|
* \`\`\`
|
|
2628
2720
|
*/
|
|
2629
2721
|
export interface TagProps
|
|
2630
|
-
extends
|
|
2722
|
+
extends
|
|
2723
|
+
React.HTMLAttributes<HTMLSpanElement>,
|
|
2631
2724
|
VariantProps<typeof tagVariants> {
|
|
2632
2725
|
/** Bold label prefix displayed before the content */
|
|
2633
|
-
label?: string
|
|
2726
|
+
label?: string;
|
|
2634
2727
|
}
|
|
2635
2728
|
|
|
2636
2729
|
const Tag = React.forwardRef<HTMLSpanElement, TagProps>(
|
|
@@ -2641,15 +2734,13 @@ const Tag = React.forwardRef<HTMLSpanElement, TagProps>(
|
|
|
2641
2734
|
ref={ref}
|
|
2642
2735
|
{...props}
|
|
2643
2736
|
>
|
|
2644
|
-
{label &&
|
|
2645
|
-
<span className="font-semibold mr-1">{label}</span>
|
|
2646
|
-
)}
|
|
2737
|
+
{label && <span className="font-semibold mr-1">{label}</span>}
|
|
2647
2738
|
<span className="font-normal">{children}</span>
|
|
2648
2739
|
</span>
|
|
2649
|
-
)
|
|
2740
|
+
);
|
|
2650
2741
|
}
|
|
2651
|
-
)
|
|
2652
|
-
Tag.displayName = "Tag"
|
|
2742
|
+
);
|
|
2743
|
+
Tag.displayName = "Tag";
|
|
2653
2744
|
|
|
2654
2745
|
/**
|
|
2655
2746
|
* TagGroup component for displaying multiple tags with overflow indicator.
|
|
@@ -2668,15 +2759,15 @@ Tag.displayName = "Tag"
|
|
|
2668
2759
|
*/
|
|
2669
2760
|
export interface TagGroupProps {
|
|
2670
2761
|
/** Array of tags to display */
|
|
2671
|
-
tags: Array<{ label?: string; value: string }
|
|
2762
|
+
tags: Array<{ label?: string; value: string }>;
|
|
2672
2763
|
/** Maximum number of tags to show before overflow (default: 2) */
|
|
2673
|
-
maxVisible?: number
|
|
2764
|
+
maxVisible?: number;
|
|
2674
2765
|
/** Tag variant */
|
|
2675
|
-
variant?: TagProps[
|
|
2766
|
+
variant?: TagProps["variant"];
|
|
2676
2767
|
/** Tag size */
|
|
2677
|
-
size?: TagProps[
|
|
2768
|
+
size?: TagProps["size"];
|
|
2678
2769
|
/** Additional className for the container */
|
|
2679
|
-
className?: string
|
|
2770
|
+
className?: string;
|
|
2680
2771
|
}
|
|
2681
2772
|
|
|
2682
2773
|
const TagGroup = ({
|
|
@@ -2686,13 +2777,14 @@ const TagGroup = ({
|
|
|
2686
2777
|
size,
|
|
2687
2778
|
className,
|
|
2688
2779
|
}: TagGroupProps) => {
|
|
2689
|
-
const visibleTags = tags.slice(0, maxVisible)
|
|
2690
|
-
const overflowCount = tags.length - maxVisible
|
|
2780
|
+
const visibleTags = tags.slice(0, maxVisible);
|
|
2781
|
+
const overflowCount = tags.length - maxVisible;
|
|
2691
2782
|
|
|
2692
2783
|
return (
|
|
2693
2784
|
<div className={cn("flex flex-col items-start gap-2", className)}>
|
|
2694
2785
|
{visibleTags.map((tag, index) => {
|
|
2695
|
-
const isLastVisible =
|
|
2786
|
+
const isLastVisible =
|
|
2787
|
+
index === visibleTags.length - 1 && overflowCount > 0;
|
|
2696
2788
|
|
|
2697
2789
|
if (isLastVisible) {
|
|
2698
2790
|
return (
|
|
@@ -2704,27 +2796,27 @@ const TagGroup = ({
|
|
|
2704
2796
|
+{overflowCount} more
|
|
2705
2797
|
</Tag>
|
|
2706
2798
|
</div>
|
|
2707
|
-
)
|
|
2799
|
+
);
|
|
2708
2800
|
}
|
|
2709
2801
|
|
|
2710
2802
|
return (
|
|
2711
2803
|
<Tag key={index} label={tag.label} variant={variant} size={size}>
|
|
2712
2804
|
{tag.value}
|
|
2713
2805
|
</Tag>
|
|
2714
|
-
)
|
|
2806
|
+
);
|
|
2715
2807
|
})}
|
|
2716
2808
|
</div>
|
|
2717
|
-
)
|
|
2718
|
-
}
|
|
2719
|
-
TagGroup.displayName = "TagGroup"
|
|
2809
|
+
);
|
|
2810
|
+
};
|
|
2811
|
+
TagGroup.displayName = "TagGroup";
|
|
2720
2812
|
|
|
2721
|
-
export { Tag, TagGroup, tagVariants }
|
|
2813
|
+
export { Tag, TagGroup, tagVariants };
|
|
2722
2814
|
`,
|
|
2723
|
-
"text-field": `import * as React from "react"
|
|
2724
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
2725
|
-
import { Loader2 } from "lucide-react"
|
|
2815
|
+
"text-field": `import * as React from "react";
|
|
2816
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
2817
|
+
import { Loader2 } from "lucide-react";
|
|
2726
2818
|
|
|
2727
|
-
import { cn } from "@/lib/utils"
|
|
2819
|
+
import { cn } from "@/lib/utils";
|
|
2728
2820
|
|
|
2729
2821
|
/**
|
|
2730
2822
|
* TextField container variants for when icons/prefix/suffix are present
|
|
@@ -2734,8 +2826,10 @@ const textFieldContainerVariants = cva(
|
|
|
2734
2826
|
{
|
|
2735
2827
|
variants: {
|
|
2736
2828
|
state: {
|
|
2737
|
-
default:
|
|
2738
|
-
|
|
2829
|
+
default:
|
|
2830
|
+
"border border-[#E9EAEB] focus-within:border-[#2BBCCA]/50 focus-within:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
|
|
2831
|
+
error:
|
|
2832
|
+
"border border-[#F04438]/40 focus-within:border-[#F04438]/60 focus-within:shadow-[0_0_0_1px_rgba(240,68,56,0.1)]",
|
|
2739
2833
|
},
|
|
2740
2834
|
disabled: {
|
|
2741
2835
|
true: "cursor-not-allowed opacity-50 bg-[#FAFAFA]",
|
|
@@ -2747,7 +2841,7 @@ const textFieldContainerVariants = cva(
|
|
|
2747
2841
|
disabled: false,
|
|
2748
2842
|
},
|
|
2749
2843
|
}
|
|
2750
|
-
)
|
|
2844
|
+
);
|
|
2751
2845
|
|
|
2752
2846
|
/**
|
|
2753
2847
|
* TextField input variants (standalone without container)
|
|
@@ -2757,15 +2851,17 @@ const textFieldInputVariants = cva(
|
|
|
2757
2851
|
{
|
|
2758
2852
|
variants: {
|
|
2759
2853
|
state: {
|
|
2760
|
-
default:
|
|
2761
|
-
|
|
2854
|
+
default:
|
|
2855
|
+
"border border-[#E9EAEB] focus:outline-none focus:border-[#2BBCCA]/50 focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
|
|
2856
|
+
error:
|
|
2857
|
+
"border border-[#F04438]/40 focus:outline-none focus:border-[#F04438]/60 focus:shadow-[0_0_0_1px_rgba(240,68,56,0.1)]",
|
|
2762
2858
|
},
|
|
2763
2859
|
},
|
|
2764
2860
|
defaultVariants: {
|
|
2765
2861
|
state: "default",
|
|
2766
2862
|
},
|
|
2767
2863
|
}
|
|
2768
|
-
)
|
|
2864
|
+
);
|
|
2769
2865
|
|
|
2770
2866
|
/**
|
|
2771
2867
|
* A comprehensive text field component with label, icons, validation states, and more.
|
|
@@ -2778,34 +2874,35 @@ const textFieldInputVariants = cva(
|
|
|
2778
2874
|
* \`\`\`
|
|
2779
2875
|
*/
|
|
2780
2876
|
export interface TextFieldProps
|
|
2781
|
-
extends
|
|
2877
|
+
extends
|
|
2878
|
+
Omit<React.ComponentProps<"input">, "size">,
|
|
2782
2879
|
VariantProps<typeof textFieldInputVariants> {
|
|
2783
2880
|
/** Label text displayed above the input */
|
|
2784
|
-
label?: string
|
|
2881
|
+
label?: string;
|
|
2785
2882
|
/** Shows red asterisk next to label when true */
|
|
2786
|
-
required?: boolean
|
|
2883
|
+
required?: boolean;
|
|
2787
2884
|
/** Helper text displayed below the input */
|
|
2788
|
-
helperText?: string
|
|
2885
|
+
helperText?: string;
|
|
2789
2886
|
/** Error message - shows error state with red styling */
|
|
2790
|
-
error?: string
|
|
2887
|
+
error?: string;
|
|
2791
2888
|
/** Icon displayed on the left inside the input */
|
|
2792
|
-
leftIcon?: React.ReactNode
|
|
2889
|
+
leftIcon?: React.ReactNode;
|
|
2793
2890
|
/** Icon displayed on the right inside the input */
|
|
2794
|
-
rightIcon?: React.ReactNode
|
|
2891
|
+
rightIcon?: React.ReactNode;
|
|
2795
2892
|
/** Text prefix inside input (e.g., "https://") */
|
|
2796
|
-
prefix?: string
|
|
2893
|
+
prefix?: string;
|
|
2797
2894
|
/** Text suffix inside input (e.g., ".com") */
|
|
2798
|
-
suffix?: string
|
|
2895
|
+
suffix?: string;
|
|
2799
2896
|
/** Shows character count when maxLength is set */
|
|
2800
|
-
showCount?: boolean
|
|
2897
|
+
showCount?: boolean;
|
|
2801
2898
|
/** Shows loading spinner inside input */
|
|
2802
|
-
loading?: boolean
|
|
2899
|
+
loading?: boolean;
|
|
2803
2900
|
/** Additional class for the wrapper container */
|
|
2804
|
-
wrapperClassName?: string
|
|
2901
|
+
wrapperClassName?: string;
|
|
2805
2902
|
/** Additional class for the label */
|
|
2806
|
-
labelClassName?: string
|
|
2903
|
+
labelClassName?: string;
|
|
2807
2904
|
/** Additional class for the input container (includes prefix/suffix/icons) */
|
|
2808
|
-
inputContainerClassName?: string
|
|
2905
|
+
inputContainerClassName?: string;
|
|
2809
2906
|
}
|
|
2810
2907
|
|
|
2811
2908
|
const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(
|
|
@@ -2837,37 +2934,39 @@ const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(
|
|
|
2837
2934
|
ref
|
|
2838
2935
|
) => {
|
|
2839
2936
|
// Internal state for character count in uncontrolled mode
|
|
2840
|
-
const [internalValue, setInternalValue] = React.useState(
|
|
2937
|
+
const [internalValue, setInternalValue] = React.useState(
|
|
2938
|
+
defaultValue ?? ""
|
|
2939
|
+
);
|
|
2841
2940
|
|
|
2842
2941
|
// Determine if controlled
|
|
2843
|
-
const isControlled = value !== undefined
|
|
2844
|
-
const currentValue = isControlled ? value : internalValue
|
|
2942
|
+
const isControlled = value !== undefined;
|
|
2943
|
+
const currentValue = isControlled ? value : internalValue;
|
|
2845
2944
|
|
|
2846
2945
|
// Derive state from props
|
|
2847
|
-
const derivedState = error ?
|
|
2946
|
+
const derivedState = error ? "error" : (state ?? "default");
|
|
2848
2947
|
|
|
2849
2948
|
// Handle change for both controlled and uncontrolled
|
|
2850
2949
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
2851
2950
|
if (!isControlled) {
|
|
2852
|
-
setInternalValue(e.target.value)
|
|
2951
|
+
setInternalValue(e.target.value);
|
|
2853
2952
|
}
|
|
2854
|
-
onChange?.(e)
|
|
2855
|
-
}
|
|
2953
|
+
onChange?.(e);
|
|
2954
|
+
};
|
|
2856
2955
|
|
|
2857
2956
|
// Determine if we need the container wrapper (for icons/prefix/suffix)
|
|
2858
|
-
const hasAddons = leftIcon || rightIcon || prefix || suffix || loading
|
|
2957
|
+
const hasAddons = leftIcon || rightIcon || prefix || suffix || loading;
|
|
2859
2958
|
|
|
2860
2959
|
// Character count
|
|
2861
|
-
const charCount = String(currentValue).length
|
|
2960
|
+
const charCount = String(currentValue).length;
|
|
2862
2961
|
|
|
2863
2962
|
// Generate unique IDs for accessibility
|
|
2864
|
-
const generatedId = React.useId()
|
|
2865
|
-
const inputId = id || generatedId
|
|
2866
|
-
const helperId = \`\${inputId}-helper
|
|
2867
|
-
const errorId = \`\${inputId}-error
|
|
2963
|
+
const generatedId = React.useId();
|
|
2964
|
+
const inputId = id || generatedId;
|
|
2965
|
+
const helperId = \`\${inputId}-helper\`;
|
|
2966
|
+
const errorId = \`\${inputId}-error\`;
|
|
2868
2967
|
|
|
2869
2968
|
// Determine aria-describedby
|
|
2870
|
-
const ariaDescribedBy = error ? errorId : helperText ? helperId : undefined
|
|
2969
|
+
const ariaDescribedBy = error ? errorId : helperText ? helperId : undefined;
|
|
2871
2970
|
|
|
2872
2971
|
// Render the input element
|
|
2873
2972
|
const inputElement = (
|
|
@@ -2888,7 +2987,7 @@ const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(
|
|
|
2888
2987
|
aria-describedby={ariaDescribedBy}
|
|
2889
2988
|
{...props}
|
|
2890
2989
|
/>
|
|
2891
|
-
)
|
|
2990
|
+
);
|
|
2892
2991
|
|
|
2893
2992
|
return (
|
|
2894
2993
|
<div className={cn("flex flex-col gap-1", wrapperClassName)}>
|
|
@@ -2907,17 +3006,38 @@ const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(
|
|
|
2907
3006
|
{hasAddons ? (
|
|
2908
3007
|
<div
|
|
2909
3008
|
className={cn(
|
|
2910
|
-
textFieldContainerVariants({
|
|
3009
|
+
textFieldContainerVariants({
|
|
3010
|
+
state: derivedState,
|
|
3011
|
+
disabled: disabled || loading,
|
|
3012
|
+
}),
|
|
2911
3013
|
"h-10 px-4",
|
|
2912
3014
|
inputContainerClassName
|
|
2913
3015
|
)}
|
|
2914
3016
|
>
|
|
2915
|
-
{prefix &&
|
|
2916
|
-
|
|
3017
|
+
{prefix && (
|
|
3018
|
+
<span className="text-sm text-[#717680] mr-2 select-none">
|
|
3019
|
+
{prefix}
|
|
3020
|
+
</span>
|
|
3021
|
+
)}
|
|
3022
|
+
{leftIcon && (
|
|
3023
|
+
<span className="mr-2 text-[#717680] [&_svg]:size-4 flex-shrink-0">
|
|
3024
|
+
{leftIcon}
|
|
3025
|
+
</span>
|
|
3026
|
+
)}
|
|
2917
3027
|
{inputElement}
|
|
2918
|
-
{loading &&
|
|
2919
|
-
|
|
2920
|
-
|
|
3028
|
+
{loading && (
|
|
3029
|
+
<Loader2 className="animate-spin size-4 text-[#717680] ml-2 flex-shrink-0" />
|
|
3030
|
+
)}
|
|
3031
|
+
{!loading && rightIcon && (
|
|
3032
|
+
<span className="ml-2 text-[#717680] [&_svg]:size-4 flex-shrink-0">
|
|
3033
|
+
{rightIcon}
|
|
3034
|
+
</span>
|
|
3035
|
+
)}
|
|
3036
|
+
{suffix && (
|
|
3037
|
+
<span className="text-sm text-[#717680] ml-2 select-none">
|
|
3038
|
+
{suffix}
|
|
3039
|
+
</span>
|
|
3040
|
+
)}
|
|
2921
3041
|
</div>
|
|
2922
3042
|
) : (
|
|
2923
3043
|
inputElement
|
|
@@ -2950,23 +3070,23 @@ const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(
|
|
|
2950
3070
|
</div>
|
|
2951
3071
|
)}
|
|
2952
3072
|
</div>
|
|
2953
|
-
)
|
|
3073
|
+
);
|
|
2954
3074
|
}
|
|
2955
|
-
)
|
|
2956
|
-
TextField.displayName = "TextField"
|
|
3075
|
+
);
|
|
3076
|
+
TextField.displayName = "TextField";
|
|
2957
3077
|
|
|
2958
|
-
export { TextField, textFieldContainerVariants, textFieldInputVariants }
|
|
3078
|
+
export { TextField, textFieldContainerVariants, textFieldInputVariants };
|
|
2959
3079
|
`,
|
|
2960
|
-
"tooltip": `import * as React from "react"
|
|
2961
|
-
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
|
|
3080
|
+
"tooltip": `import * as React from "react";
|
|
3081
|
+
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
2962
3082
|
|
|
2963
|
-
import { cn } from "@/lib/utils"
|
|
3083
|
+
import { cn } from "@/lib/utils";
|
|
2964
3084
|
|
|
2965
|
-
const TooltipProvider = TooltipPrimitive.Provider
|
|
3085
|
+
const TooltipProvider = TooltipPrimitive.Provider;
|
|
2966
3086
|
|
|
2967
|
-
const Tooltip = TooltipPrimitive.Root
|
|
3087
|
+
const Tooltip = TooltipPrimitive.Root;
|
|
2968
3088
|
|
|
2969
|
-
const TooltipTrigger = TooltipPrimitive.Trigger
|
|
3089
|
+
const TooltipTrigger = TooltipPrimitive.Trigger;
|
|
2970
3090
|
|
|
2971
3091
|
const TooltipContent = React.forwardRef<
|
|
2972
3092
|
React.ElementRef<typeof TooltipPrimitive.Content>,
|
|
@@ -2983,8 +3103,8 @@ const TooltipContent = React.forwardRef<
|
|
|
2983
3103
|
{...props}
|
|
2984
3104
|
/>
|
|
2985
3105
|
</TooltipPrimitive.Portal>
|
|
2986
|
-
))
|
|
2987
|
-
TooltipContent.displayName = TooltipPrimitive.Content.displayName
|
|
3106
|
+
));
|
|
3107
|
+
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
2988
3108
|
|
|
2989
3109
|
const TooltipArrow = React.forwardRef<
|
|
2990
3110
|
React.ElementRef<typeof TooltipPrimitive.Arrow>,
|
|
@@ -2995,8 +3115,8 @@ const TooltipArrow = React.forwardRef<
|
|
|
2995
3115
|
className={cn("fill-[#343E55]", className)}
|
|
2996
3116
|
{...props}
|
|
2997
3117
|
/>
|
|
2998
|
-
))
|
|
2999
|
-
TooltipArrow.displayName = TooltipPrimitive.Arrow.displayName
|
|
3118
|
+
));
|
|
3119
|
+
TooltipArrow.displayName = TooltipPrimitive.Arrow.displayName;
|
|
3000
3120
|
|
|
3001
3121
|
export {
|
|
3002
3122
|
Tooltip,
|
|
@@ -3004,21 +3124,29 @@ export {
|
|
|
3004
3124
|
TooltipContent,
|
|
3005
3125
|
TooltipArrow,
|
|
3006
3126
|
TooltipProvider,
|
|
3007
|
-
}
|
|
3127
|
+
};
|
|
3008
3128
|
`,
|
|
3009
|
-
"typography": `import * as React from "react"
|
|
3010
|
-
import { cn } from "@/lib/utils"
|
|
3129
|
+
"typography": `import * as React from "react";
|
|
3130
|
+
import { cn } from "@/lib/utils";
|
|
3011
3131
|
|
|
3012
3132
|
// =============================================================================
|
|
3013
3133
|
// TYPES
|
|
3014
3134
|
// =============================================================================
|
|
3015
3135
|
|
|
3016
|
-
export type Kind = "display" | "headline" | "title" | "label" | "body"
|
|
3017
|
-
export type Variant = "large" | "medium" | "small"
|
|
3018
|
-
export type Color =
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3136
|
+
export type Kind = "display" | "headline" | "title" | "label" | "body";
|
|
3137
|
+
export type Variant = "large" | "medium" | "small";
|
|
3138
|
+
export type Color =
|
|
3139
|
+
| "primary"
|
|
3140
|
+
| "secondary"
|
|
3141
|
+
| "muted"
|
|
3142
|
+
| "placeholder"
|
|
3143
|
+
| "link"
|
|
3144
|
+
| "inverted"
|
|
3145
|
+
| "error"
|
|
3146
|
+
| "success";
|
|
3147
|
+
export type Align = "left" | "center" | "right";
|
|
3148
|
+
|
|
3149
|
+
type Key = \`\${Kind}-\${Variant}\`;
|
|
3022
3150
|
|
|
3023
3151
|
// =============================================================================
|
|
3024
3152
|
// MAPPINGS
|
|
@@ -3043,7 +3171,7 @@ const mapTagName: { [key in Key]: keyof JSX.IntrinsicElements } = {
|
|
|
3043
3171
|
"body-large": "span",
|
|
3044
3172
|
"body-medium": "span",
|
|
3045
3173
|
"body-small": "span",
|
|
3046
|
-
}
|
|
3174
|
+
};
|
|
3047
3175
|
|
|
3048
3176
|
/**
|
|
3049
3177
|
* Maps kind-variant combinations to Tailwind typography classes
|
|
@@ -3064,7 +3192,7 @@ const mapClassName: { [key in Key]: string } = {
|
|
|
3064
3192
|
"body-large": "text-base leading-5 font-normal",
|
|
3065
3193
|
"body-medium": "text-sm leading-[18px] font-normal",
|
|
3066
3194
|
"body-small": "text-xs leading-4 font-normal",
|
|
3067
|
-
}
|
|
3195
|
+
};
|
|
3068
3196
|
|
|
3069
3197
|
/**
|
|
3070
3198
|
* Maps color variants to Tailwind text color classes
|
|
@@ -3078,7 +3206,7 @@ const mapColorClassName: { [key in Color]: string } = {
|
|
|
3078
3206
|
inverted: "text-white",
|
|
3079
3207
|
error: "text-[#F04438]",
|
|
3080
3208
|
success: "text-[#17B26A]",
|
|
3081
|
-
}
|
|
3209
|
+
};
|
|
3082
3210
|
|
|
3083
3211
|
/**
|
|
3084
3212
|
* Maps alignment to Tailwind text alignment classes
|
|
@@ -3087,7 +3215,7 @@ const mapAlignClassName: { [key in Align]: string } = {
|
|
|
3087
3215
|
left: "text-left",
|
|
3088
3216
|
center: "text-center",
|
|
3089
3217
|
right: "text-right",
|
|
3090
|
-
}
|
|
3218
|
+
};
|
|
3091
3219
|
|
|
3092
3220
|
// =============================================================================
|
|
3093
3221
|
// COMPONENT
|
|
@@ -3098,21 +3226,21 @@ const mapAlignClassName: { [key in Align]: string } = {
|
|
|
3098
3226
|
*/
|
|
3099
3227
|
export interface TypographyProps extends React.HTMLAttributes<HTMLElement> {
|
|
3100
3228
|
/** Text content */
|
|
3101
|
-
children: React.ReactNode
|
|
3229
|
+
children: React.ReactNode;
|
|
3102
3230
|
/** Typography kind - determines base styling and semantic tag */
|
|
3103
|
-
kind?: Kind
|
|
3231
|
+
kind?: Kind;
|
|
3104
3232
|
/** Size variant */
|
|
3105
|
-
variant?: Variant
|
|
3233
|
+
variant?: Variant;
|
|
3106
3234
|
/** Text color */
|
|
3107
|
-
color?: Color
|
|
3235
|
+
color?: Color;
|
|
3108
3236
|
/** Text alignment */
|
|
3109
|
-
align?: Align
|
|
3237
|
+
align?: Align;
|
|
3110
3238
|
/** Enable text truncation with ellipsis */
|
|
3111
|
-
truncate?: boolean
|
|
3239
|
+
truncate?: boolean;
|
|
3112
3240
|
/** Override the default HTML tag */
|
|
3113
|
-
tag?: keyof JSX.IntrinsicElements
|
|
3241
|
+
tag?: keyof JSX.IntrinsicElements;
|
|
3114
3242
|
/** For label elements - associates with form input */
|
|
3115
|
-
htmlFor?: string
|
|
3243
|
+
htmlFor?: string;
|
|
3116
3244
|
}
|
|
3117
3245
|
|
|
3118
3246
|
/**
|
|
@@ -3149,8 +3277,8 @@ const Typography = React.forwardRef<HTMLElement, TypographyProps>(
|
|
|
3149
3277
|
},
|
|
3150
3278
|
ref
|
|
3151
3279
|
) => {
|
|
3152
|
-
const key: Key = \`\${kind}-\${variant}
|
|
3153
|
-
const Tag = tag || mapTagName[key]
|
|
3280
|
+
const key: Key = \`\${kind}-\${variant}\`;
|
|
3281
|
+
const Tag = tag || mapTagName[key];
|
|
3154
3282
|
|
|
3155
3283
|
const classes = cn(
|
|
3156
3284
|
"m-0", // Reset margin
|
|
@@ -3159,7 +3287,7 @@ const Typography = React.forwardRef<HTMLElement, TypographyProps>(
|
|
|
3159
3287
|
align && mapAlignClassName[align],
|
|
3160
3288
|
truncate && "truncate",
|
|
3161
3289
|
className
|
|
3162
|
-
)
|
|
3290
|
+
);
|
|
3163
3291
|
|
|
3164
3292
|
return (
|
|
3165
3293
|
<Tag
|
|
@@ -3170,12 +3298,18 @@ const Typography = React.forwardRef<HTMLElement, TypographyProps>(
|
|
|
3170
3298
|
>
|
|
3171
3299
|
{children}
|
|
3172
3300
|
</Tag>
|
|
3173
|
-
)
|
|
3301
|
+
);
|
|
3174
3302
|
}
|
|
3175
|
-
)
|
|
3176
|
-
Typography.displayName = "Typography"
|
|
3303
|
+
);
|
|
3304
|
+
Typography.displayName = "Typography";
|
|
3177
3305
|
|
|
3178
|
-
export {
|
|
3306
|
+
export {
|
|
3307
|
+
Typography,
|
|
3308
|
+
mapTagName,
|
|
3309
|
+
mapClassName,
|
|
3310
|
+
mapColorClassName,
|
|
3311
|
+
mapAlignClassName,
|
|
3312
|
+
};
|
|
3179
3313
|
`
|
|
3180
3314
|
};
|
|
3181
3315
|
var utilsSourceCode = `import { type ClassValue, clsx } from "clsx"
|