myoperator-ui 0.0.95 → 0.0.97

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +712 -6
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -289,9 +289,9 @@ const buttonVariants = cva(
289
289
  "border border-dashed border-[#D5D7DA] bg-transparent text-[#717680] hover:border-[#343E55] hover:text-[#343E55] hover:bg-[#FAFAFA]",
290
290
  },
291
291
  size: {
292
- default: "py-2.5 px-4 [&_svg]:size-4",
293
- sm: "py-2 px-3 text-xs [&_svg]:size-3.5",
294
- lg: "py-3 px-6 [&_svg]:size-5",
292
+ default: "min-w-20 py-2.5 px-4 [&_svg]:size-4",
293
+ sm: "min-w-16 py-2 px-3 text-xs [&_svg]:size-3.5",
294
+ lg: "min-w-24 py-3 px-6 [&_svg]:size-5",
295
295
  icon: "h-8 w-8 rounded-md",
296
296
  "icon-sm": "h-7 w-7 rounded-md",
297
297
  "icon-lg": "h-10 w-10 rounded-md",
@@ -671,7 +671,7 @@ const Typography = React.forwardRef<HTMLElement, TypographyProps>(
671
671
  ref
672
672
  ) => {
673
673
  const key: Key = \`\${kind}-\${variant}\`;
674
- const Tag = tag || mapTagName[key];
674
+ const Tag = (tag || mapTagName[key]) as React.ElementType;
675
675
 
676
676
  const classes = cn(
677
677
  "m-0", // Reset margin
@@ -682,11 +682,13 @@ const Typography = React.forwardRef<HTMLElement, TypographyProps>(
682
682
  className
683
683
  );
684
684
 
685
+ const tagName = tag || mapTagName[key];
686
+
685
687
  return (
686
688
  <Tag
687
- ref={ref as React.Ref<HTMLElement>}
689
+ ref={ref}
688
690
  className={classes}
689
- htmlFor={Tag === "label" ? htmlFor : undefined}
691
+ htmlFor={tagName === "label" ? htmlFor : undefined}
690
692
  {...props}
691
693
  >
692
694
  {children}
@@ -2699,6 +2701,169 @@ export {
2699
2701
  TableToggle,
2700
2702
  tableVariants,
2701
2703
  };
2704
+ `, prefix)
2705
+ }
2706
+ ]
2707
+ },
2708
+ "dialog": {
2709
+ name: "dialog",
2710
+ description: "A modal dialog component built on Radix UI Dialog with size variants and animations",
2711
+ dependencies: [
2712
+ "@radix-ui/react-dialog",
2713
+ "class-variance-authority",
2714
+ "clsx",
2715
+ "tailwind-merge",
2716
+ "lucide-react"
2717
+ ],
2718
+ files: [
2719
+ {
2720
+ name: "dialog.tsx",
2721
+ content: prefixTailwindClasses(`import * as React from "react";
2722
+ import * as DialogPrimitive from "@radix-ui/react-dialog";
2723
+ import { X } from "lucide-react";
2724
+ import { cva, type VariantProps } from "class-variance-authority";
2725
+
2726
+ import { cn } from "../../lib/utils";
2727
+
2728
+ const Dialog = DialogPrimitive.Root;
2729
+
2730
+ const DialogTrigger = DialogPrimitive.Trigger;
2731
+
2732
+ const DialogPortal = DialogPrimitive.Portal;
2733
+
2734
+ const DialogClose = DialogPrimitive.Close;
2735
+
2736
+ const DialogOverlay = React.forwardRef<
2737
+ React.ElementRef<typeof DialogPrimitive.Overlay>,
2738
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
2739
+ >(({ className, ...props }, ref) => (
2740
+ <DialogPrimitive.Overlay
2741
+ ref={ref}
2742
+ className={cn(
2743
+ "fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
2744
+ className
2745
+ )}
2746
+ {...props}
2747
+ />
2748
+ ));
2749
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
2750
+
2751
+ const dialogContentVariants = cva(
2752
+ "fixed left-[50%] top-[50%] z-50 grid translate-x-[-50%] translate-y-[-50%] gap-4 border border-border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-lg",
2753
+ {
2754
+ variants: {
2755
+ size: {
2756
+ sm: "w-full max-w-sm",
2757
+ default: "w-full max-w-lg",
2758
+ lg: "w-full max-w-2xl",
2759
+ xl: "w-full max-w-4xl",
2760
+ full: "w-[calc(100%-2rem)] h-[calc(100%-2rem)] max-w-none",
2761
+ },
2762
+ },
2763
+ defaultVariants: {
2764
+ size: "default",
2765
+ },
2766
+ }
2767
+ );
2768
+
2769
+ export interface DialogContentProps
2770
+ extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>,
2771
+ VariantProps<typeof dialogContentVariants> {
2772
+ /** Hide the default close button in the top-right corner */
2773
+ hideCloseButton?: boolean;
2774
+ }
2775
+
2776
+ const DialogContent = React.forwardRef<
2777
+ React.ElementRef<typeof DialogPrimitive.Content>,
2778
+ DialogContentProps
2779
+ >(({ className, children, size, hideCloseButton = false, ...props }, ref) => (
2780
+ <DialogPortal>
2781
+ <DialogOverlay />
2782
+ <DialogPrimitive.Content
2783
+ ref={ref}
2784
+ className={cn(dialogContentVariants({ size, className }))}
2785
+ {...props}
2786
+ >
2787
+ {children}
2788
+ {!hideCloseButton && (
2789
+ <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
2790
+ <X className="h-4 w-4" />
2791
+ <span className="sr-only">Close</span>
2792
+ </DialogPrimitive.Close>
2793
+ )}
2794
+ </DialogPrimitive.Content>
2795
+ </DialogPortal>
2796
+ ));
2797
+ DialogContent.displayName = DialogPrimitive.Content.displayName;
2798
+
2799
+ const DialogHeader = ({
2800
+ className,
2801
+ ...props
2802
+ }: React.HTMLAttributes<HTMLDivElement>) => (
2803
+ <div
2804
+ className={cn(
2805
+ "flex flex-col space-y-1.5 text-center sm:text-left",
2806
+ className
2807
+ )}
2808
+ {...props}
2809
+ />
2810
+ );
2811
+ DialogHeader.displayName = "DialogHeader";
2812
+
2813
+ const DialogFooter = ({
2814
+ className,
2815
+ ...props
2816
+ }: React.HTMLAttributes<HTMLDivElement>) => (
2817
+ <div
2818
+ className={cn(
2819
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
2820
+ className
2821
+ )}
2822
+ {...props}
2823
+ />
2824
+ );
2825
+ DialogFooter.displayName = "DialogFooter";
2826
+
2827
+ const DialogTitle = React.forwardRef<
2828
+ React.ElementRef<typeof DialogPrimitive.Title>,
2829
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
2830
+ >(({ className, ...props }, ref) => (
2831
+ <DialogPrimitive.Title
2832
+ ref={ref}
2833
+ className={cn(
2834
+ "text-lg font-semibold leading-none tracking-tight text-foreground",
2835
+ className
2836
+ )}
2837
+ {...props}
2838
+ />
2839
+ ));
2840
+ DialogTitle.displayName = DialogPrimitive.Title.displayName;
2841
+
2842
+ const DialogDescription = React.forwardRef<
2843
+ React.ElementRef<typeof DialogPrimitive.Description>,
2844
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
2845
+ >(({ className, ...props }, ref) => (
2846
+ <DialogPrimitive.Description
2847
+ ref={ref}
2848
+ className={cn("text-sm text-muted-foreground", className)}
2849
+ {...props}
2850
+ />
2851
+ ));
2852
+ DialogDescription.displayName = DialogPrimitive.Description.displayName;
2853
+
2854
+ export {
2855
+ Dialog,
2856
+ DialogPortal,
2857
+ DialogOverlay,
2858
+ DialogClose,
2859
+ DialogTrigger,
2860
+ DialogContent,
2861
+ DialogHeader,
2862
+ DialogFooter,
2863
+ DialogTitle,
2864
+ DialogDescription,
2865
+ dialogContentVariants,
2866
+ };
2702
2867
  `, prefix)
2703
2868
  }
2704
2869
  ]
@@ -2977,6 +3142,331 @@ export {
2977
3142
  TooltipArrow,
2978
3143
  TooltipProvider,
2979
3144
  };
3145
+ `, prefix)
3146
+ }
3147
+ ]
3148
+ },
3149
+ "delete-confirmation-modal": {
3150
+ name: "delete-confirmation-modal",
3151
+ description: "A confirmation modal requiring text input to confirm deletion",
3152
+ dependencies: [
3153
+ "clsx",
3154
+ "tailwind-merge"
3155
+ ],
3156
+ files: [
3157
+ {
3158
+ name: "delete-confirmation-modal.tsx",
3159
+ content: prefixTailwindClasses(`import * as React from "react";
3160
+
3161
+ import { cn } from "../../lib/utils";
3162
+ import {
3163
+ Dialog,
3164
+ DialogContent,
3165
+ DialogHeader,
3166
+ DialogFooter,
3167
+ DialogTitle,
3168
+ DialogDescription,
3169
+ DialogTrigger,
3170
+ } from "./dialog";
3171
+ import { Button } from "./button";
3172
+ import { Input } from "./input";
3173
+
3174
+ /**
3175
+ * Props for the DeleteConfirmationModal component
3176
+ */
3177
+ export interface DeleteConfirmationModalProps {
3178
+ /** Controls modal visibility (controlled mode) */
3179
+ open?: boolean;
3180
+ /** Callback when open state changes */
3181
+ onOpenChange?: (open: boolean) => void;
3182
+ /** The name of the item being deleted (shown in title) */
3183
+ itemName?: string;
3184
+ /** Custom title (overrides default) */
3185
+ title?: React.ReactNode;
3186
+ /** Additional description text */
3187
+ description?: React.ReactNode;
3188
+ /** Text user must type to confirm (default: "DELETE") */
3189
+ confirmText?: string;
3190
+ /** Called when user confirms deletion */
3191
+ onConfirm?: () => void;
3192
+ /** Called when user cancels */
3193
+ onCancel?: () => void;
3194
+ /** Loading state for delete button */
3195
+ loading?: boolean;
3196
+ /** Text for delete button (default: "Delete") */
3197
+ deleteButtonText?: string;
3198
+ /** Text for cancel button (default: "Cancel") */
3199
+ cancelButtonText?: string;
3200
+ /** Trigger element for uncontrolled usage */
3201
+ trigger?: React.ReactNode;
3202
+ /** Additional className for the dialog content */
3203
+ className?: string;
3204
+ }
3205
+
3206
+ /**
3207
+ * A confirmation modal that requires the user to type a specific text to confirm deletion.
3208
+ *
3209
+ * @example
3210
+ * \`\`\`tsx
3211
+ * // Controlled usage
3212
+ * <DeleteConfirmationModal
3213
+ * open={isOpen}
3214
+ * onOpenChange={setIsOpen}
3215
+ * itemName="webhook"
3216
+ * onConfirm={handleDelete}
3217
+ * />
3218
+ *
3219
+ * // Uncontrolled with trigger
3220
+ * <DeleteConfirmationModal
3221
+ * trigger={<Button variant="destructive">Delete</Button>}
3222
+ * itemName="user"
3223
+ * onConfirm={handleDelete}
3224
+ * />
3225
+ * \`\`\`
3226
+ */
3227
+ const DeleteConfirmationModal = React.forwardRef<
3228
+ HTMLDivElement,
3229
+ DeleteConfirmationModalProps
3230
+ >(
3231
+ (
3232
+ {
3233
+ open,
3234
+ onOpenChange,
3235
+ itemName = "item",
3236
+ title,
3237
+ description,
3238
+ confirmText = "DELETE",
3239
+ onConfirm,
3240
+ onCancel,
3241
+ loading = false,
3242
+ deleteButtonText = "Delete",
3243
+ cancelButtonText = "Cancel",
3244
+ trigger,
3245
+ className,
3246
+ },
3247
+ ref
3248
+ ) => {
3249
+ const [inputValue, setInputValue] = React.useState("");
3250
+ const isConfirmEnabled = inputValue === confirmText;
3251
+
3252
+ // Reset input when modal closes
3253
+ React.useEffect(() => {
3254
+ if (!open) {
3255
+ setInputValue("");
3256
+ }
3257
+ }, [open]);
3258
+
3259
+ const handleConfirm = () => {
3260
+ if (isConfirmEnabled) {
3261
+ onConfirm?.();
3262
+ }
3263
+ };
3264
+
3265
+ const handleCancel = () => {
3266
+ onCancel?.();
3267
+ onOpenChange?.(false);
3268
+ };
3269
+
3270
+ const handleOpenChange = (newOpen: boolean) => {
3271
+ if (!newOpen) {
3272
+ setInputValue("");
3273
+ }
3274
+ onOpenChange?.(newOpen);
3275
+ };
3276
+
3277
+ const defaultTitle = \`Are you sure you want to delete this \${itemName}?\`;
3278
+
3279
+ return (
3280
+ <Dialog open={open} onOpenChange={handleOpenChange}>
3281
+ {trigger && <DialogTrigger asChild>{trigger}</DialogTrigger>}
3282
+ <DialogContent ref={ref} size="sm" className={cn(className)}>
3283
+ <DialogHeader>
3284
+ <DialogTitle>{title || defaultTitle}</DialogTitle>
3285
+ {description && (
3286
+ <DialogDescription>{description}</DialogDescription>
3287
+ )}
3288
+ </DialogHeader>
3289
+ <div className="grid gap-2 py-4">
3290
+ <label
3291
+ htmlFor="delete-confirmation-input"
3292
+ className="text-sm text-muted-foreground"
3293
+ >
3294
+ Enter "{confirmText}" in uppercase to confirm
3295
+ </label>
3296
+ <Input
3297
+ id="delete-confirmation-input"
3298
+ value={inputValue}
3299
+ onChange={(e) => setInputValue(e.target.value)}
3300
+ placeholder={confirmText}
3301
+ autoComplete="off"
3302
+ autoFocus
3303
+ />
3304
+ </div>
3305
+ <DialogFooter className="gap-2 sm:gap-0">
3306
+ <Button variant="outline" onClick={handleCancel} disabled={loading}>
3307
+ {cancelButtonText}
3308
+ </Button>
3309
+ <Button
3310
+ variant="destructive"
3311
+ onClick={handleConfirm}
3312
+ disabled={!isConfirmEnabled || loading}
3313
+ loading={loading}
3314
+ >
3315
+ {deleteButtonText}
3316
+ </Button>
3317
+ </DialogFooter>
3318
+ </DialogContent>
3319
+ </Dialog>
3320
+ );
3321
+ }
3322
+ );
3323
+ DeleteConfirmationModal.displayName = "DeleteConfirmationModal";
3324
+
3325
+ export { DeleteConfirmationModal };
3326
+ `, prefix)
3327
+ }
3328
+ ]
3329
+ },
3330
+ "confirmation-modal": {
3331
+ name: "confirmation-modal",
3332
+ description: "A simple confirmation modal for yes/no decisions",
3333
+ dependencies: [
3334
+ "clsx",
3335
+ "tailwind-merge"
3336
+ ],
3337
+ files: [
3338
+ {
3339
+ name: "confirmation-modal.tsx",
3340
+ content: prefixTailwindClasses(`import * as React from "react";
3341
+
3342
+ import { cn } from "../../lib/utils";
3343
+ import {
3344
+ Dialog,
3345
+ DialogContent,
3346
+ DialogHeader,
3347
+ DialogFooter,
3348
+ DialogTitle,
3349
+ DialogDescription,
3350
+ DialogTrigger,
3351
+ } from "./dialog";
3352
+ import { Button } from "./button";
3353
+
3354
+ /**
3355
+ * Props for the ConfirmationModal component
3356
+ */
3357
+ export interface ConfirmationModalProps {
3358
+ /** Controls modal visibility (controlled mode) */
3359
+ open?: boolean;
3360
+ /** Callback when open state changes */
3361
+ onOpenChange?: (open: boolean) => void;
3362
+ /** Modal title */
3363
+ title: React.ReactNode;
3364
+ /** Modal description/message */
3365
+ description?: React.ReactNode;
3366
+ /** Visual style of confirm button */
3367
+ variant?: "default" | "destructive";
3368
+ /** Called when user confirms */
3369
+ onConfirm?: () => void;
3370
+ /** Called when user cancels */
3371
+ onCancel?: () => void;
3372
+ /** Loading state for confirm button */
3373
+ loading?: boolean;
3374
+ /** Text for confirm button (default: "Yes") */
3375
+ confirmButtonText?: string;
3376
+ /** Text for cancel button (default: "Cancel") */
3377
+ cancelButtonText?: string;
3378
+ /** Trigger element for uncontrolled usage */
3379
+ trigger?: React.ReactNode;
3380
+ /** Additional className for the dialog content */
3381
+ className?: string;
3382
+ }
3383
+
3384
+ /**
3385
+ * A simple confirmation modal for yes/no decisions.
3386
+ *
3387
+ * @example
3388
+ * \`\`\`tsx
3389
+ * // Controlled usage
3390
+ * <ConfirmationModal
3391
+ * open={isOpen}
3392
+ * onOpenChange={setIsOpen}
3393
+ * title="Disable Webhook"
3394
+ * description="Are you sure you want to disable this webhook?"
3395
+ * onConfirm={handleDisable}
3396
+ * />
3397
+ *
3398
+ * // Destructive variant
3399
+ * <ConfirmationModal
3400
+ * open={isOpen}
3401
+ * onOpenChange={setIsOpen}
3402
+ * title="Archive Project"
3403
+ * variant="destructive"
3404
+ * confirmButtonText="Archive"
3405
+ * onConfirm={handleArchive}
3406
+ * />
3407
+ * \`\`\`
3408
+ */
3409
+ const ConfirmationModal = React.forwardRef<
3410
+ HTMLDivElement,
3411
+ ConfirmationModalProps
3412
+ >(
3413
+ (
3414
+ {
3415
+ open,
3416
+ onOpenChange,
3417
+ title,
3418
+ description,
3419
+ variant = "default",
3420
+ onConfirm,
3421
+ onCancel,
3422
+ loading = false,
3423
+ confirmButtonText = "Yes",
3424
+ cancelButtonText = "Cancel",
3425
+ trigger,
3426
+ className,
3427
+ },
3428
+ ref
3429
+ ) => {
3430
+ const handleConfirm = () => {
3431
+ onConfirm?.();
3432
+ };
3433
+
3434
+ const handleCancel = () => {
3435
+ onCancel?.();
3436
+ onOpenChange?.(false);
3437
+ };
3438
+
3439
+ return (
3440
+ <Dialog open={open} onOpenChange={onOpenChange}>
3441
+ {trigger && <DialogTrigger asChild>{trigger}</DialogTrigger>}
3442
+ <DialogContent ref={ref} size="sm" className={cn(className)}>
3443
+ <DialogHeader>
3444
+ <DialogTitle>{title}</DialogTitle>
3445
+ {description && (
3446
+ <DialogDescription>{description}</DialogDescription>
3447
+ )}
3448
+ </DialogHeader>
3449
+ <DialogFooter className="gap-2 sm:gap-0">
3450
+ <Button variant="outline" onClick={handleCancel} disabled={loading}>
3451
+ {cancelButtonText}
3452
+ </Button>
3453
+ <Button
3454
+ variant={variant === "destructive" ? "destructive" : "default"}
3455
+ onClick={handleConfirm}
3456
+ disabled={loading}
3457
+ loading={loading}
3458
+ >
3459
+ {confirmButtonText}
3460
+ </Button>
3461
+ </DialogFooter>
3462
+ </DialogContent>
3463
+ </Dialog>
3464
+ );
3465
+ }
3466
+ );
3467
+ ConfirmationModal.displayName = "ConfirmationModal";
3468
+
3469
+ export { ConfirmationModal };
2980
3470
  `, prefix)
2981
3471
  }
2982
3472
  ]
@@ -3127,6 +3617,222 @@ const TagGroup = ({
3127
3617
  TagGroup.displayName = "TagGroup";
3128
3618
 
3129
3619
  export { Tag, TagGroup, tagVariants };
3620
+ `, prefix)
3621
+ }
3622
+ ]
3623
+ },
3624
+ "alert": {
3625
+ name: "alert",
3626
+ description: "A dismissible alert component for notifications, errors, warnings, and success messages with icons, actions, and controlled visibility",
3627
+ dependencies: [
3628
+ "class-variance-authority",
3629
+ "clsx",
3630
+ "tailwind-merge",
3631
+ "lucide-react"
3632
+ ],
3633
+ files: [
3634
+ {
3635
+ name: "alert.tsx",
3636
+ content: prefixTailwindClasses(`import * as React from "react";
3637
+ import { cva, type VariantProps } from "class-variance-authority";
3638
+ import { CheckCircle2, XCircle, AlertTriangle, Info, X } from "lucide-react";
3639
+
3640
+ import { cn } from "../../lib/utils";
3641
+
3642
+ /**
3643
+ * Alert variants for different notification types.
3644
+ * Colors are hardcoded for Bootstrap compatibility.
3645
+ */
3646
+ const alertVariants = cva(
3647
+ "relative w-full rounded border p-4 text-sm text-[#181D27] [&>svg~*]:pl-8 [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4",
3648
+ {
3649
+ variants: {
3650
+ variant: {
3651
+ default: "bg-[#F5F5F5] border-[#E9EAEB] [&>svg]:text-[#181D27]",
3652
+ success: "bg-[#ECFDF3] border-[#17B26A]/20 [&>svg]:text-[#17B26A]",
3653
+ error: "bg-[#FEF3F2] border-[#F04438]/20 [&>svg]:text-[#F04438]",
3654
+ destructive: "bg-[#FEF3F2] border-[#F04438]/20 [&>svg]:text-[#F04438]",
3655
+ warning: "bg-[#FFFAEB] border-[#F79009]/20 [&>svg]:text-[#F79009]",
3656
+ info: "bg-[#EBF5FF] border-[#4275D6]/20 [&>svg]:text-[#4275D6]",
3657
+ },
3658
+ },
3659
+ defaultVariants: {
3660
+ variant: "default",
3661
+ },
3662
+ }
3663
+ );
3664
+
3665
+ /**
3666
+ * Default icons for each alert variant
3667
+ */
3668
+ const defaultIcons: Record<string, React.ReactNode> = {
3669
+ default: <Info className="size-5" />,
3670
+ success: <CheckCircle2 className="size-5" />,
3671
+ error: <XCircle className="size-5" />,
3672
+ destructive: <XCircle className="size-5" />,
3673
+ warning: <AlertTriangle className="size-5" />,
3674
+ info: <Info className="size-5" />,
3675
+ };
3676
+
3677
+ /**
3678
+ * Dismissible alert banners for notifications, errors, warnings, and success messages.
3679
+ *
3680
+ * @example
3681
+ * \`\`\`tsx
3682
+ * // Simple alert
3683
+ * <Alert variant="success">
3684
+ * <AlertTitle>Success!</AlertTitle>
3685
+ * <AlertDescription>Your changes have been saved.</AlertDescription>
3686
+ * </Alert>
3687
+ *
3688
+ * // With close button and actions
3689
+ * <Alert
3690
+ * variant="error"
3691
+ * closable
3692
+ * onClose={() => console.log('closed')}
3693
+ * action={<Button size="sm">Retry</Button>}
3694
+ * >
3695
+ * <AlertTitle>Error</AlertTitle>
3696
+ * <AlertDescription>Something went wrong.</AlertDescription>
3697
+ * </Alert>
3698
+ *
3699
+ * // Controlled visibility
3700
+ * const [open, setOpen] = useState(true)
3701
+ * <Alert open={open} onClose={() => setOpen(false)} closable>...</Alert>
3702
+ * \`\`\`
3703
+ */
3704
+ export interface AlertProps
3705
+ extends
3706
+ React.HTMLAttributes<HTMLDivElement>,
3707
+ VariantProps<typeof alertVariants> {
3708
+ /** Custom icon to display. Set to null to hide icon. */
3709
+ icon?: React.ReactNode | null;
3710
+ /** Whether to show the default variant icon (default: true) */
3711
+ showIcon?: boolean;
3712
+ /** Show close button */
3713
+ closable?: boolean;
3714
+ /** Callback when close button is clicked */
3715
+ onClose?: () => void;
3716
+ /** Primary action element (e.g., button) */
3717
+ action?: React.ReactNode;
3718
+ /** Secondary action element */
3719
+ secondaryAction?: React.ReactNode;
3720
+ /** Controlled visibility state */
3721
+ open?: boolean;
3722
+ /** Initial visibility for uncontrolled mode (default: true) */
3723
+ defaultOpen?: boolean;
3724
+ }
3725
+
3726
+ const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
3727
+ (
3728
+ {
3729
+ className,
3730
+ variant = "default",
3731
+ icon,
3732
+ showIcon = true,
3733
+ closable = false,
3734
+ onClose,
3735
+ action,
3736
+ secondaryAction,
3737
+ open: controlledOpen,
3738
+ defaultOpen = true,
3739
+ children,
3740
+ ...props
3741
+ },
3742
+ ref
3743
+ ) => {
3744
+ const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
3745
+ const isControlled = controlledOpen !== undefined;
3746
+ const isOpen = isControlled ? controlledOpen : internalOpen;
3747
+
3748
+ const handleClose = React.useCallback(() => {
3749
+ if (!isControlled) {
3750
+ setInternalOpen(false);
3751
+ }
3752
+ onClose?.();
3753
+ }, [isControlled, onClose]);
3754
+
3755
+ if (!isOpen) {
3756
+ return null;
3757
+ }
3758
+
3759
+ const renderIcon = () => {
3760
+ if (icon === null || !showIcon) return null;
3761
+ if (icon) return icon;
3762
+ return defaultIcons[variant || "default"];
3763
+ };
3764
+
3765
+ const hasActions = action || secondaryAction;
3766
+
3767
+ return (
3768
+ <div
3769
+ ref={ref}
3770
+ role="alert"
3771
+ aria-live="polite"
3772
+ className={cn(alertVariants({ variant, className }))}
3773
+ {...props}
3774
+ >
3775
+ {renderIcon()}
3776
+ <div className="flex flex-1 items-center justify-between gap-4">
3777
+ <div className="flex-1">{children}</div>
3778
+ {(hasActions || closable) && (
3779
+ <div className="flex shrink-0 items-center gap-2">
3780
+ {secondaryAction}
3781
+ {action}
3782
+ {closable && (
3783
+ <button
3784
+ type="button"
3785
+ onClick={handleClose}
3786
+ className={cn(
3787
+ "rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2",
3788
+ variant === "default" && "focus:ring-[#181D27]",
3789
+ variant === "success" && "focus:ring-[#17B26A]",
3790
+ (variant === "error" || variant === "destructive") &&
3791
+ "focus:ring-[#F04438]",
3792
+ variant === "warning" && "focus:ring-[#F79009]",
3793
+ variant === "info" && "focus:ring-[#4275D6]"
3794
+ )}
3795
+ aria-label="Close alert"
3796
+ >
3797
+ <X className="size-5" />
3798
+ </button>
3799
+ )}
3800
+ </div>
3801
+ )}
3802
+ </div>
3803
+ </div>
3804
+ );
3805
+ }
3806
+ );
3807
+ Alert.displayName = "Alert";
3808
+
3809
+ /**
3810
+ * Alert title component for the heading text.
3811
+ */
3812
+ const AlertTitle = React.forwardRef<
3813
+ HTMLHeadingElement,
3814
+ React.HTMLAttributes<HTMLHeadingElement>
3815
+ >(({ className, ...props }, ref) => (
3816
+ <h5
3817
+ ref={ref}
3818
+ className={cn("font-semibold leading-tight tracking-tight", className)}
3819
+ {...props}
3820
+ />
3821
+ ));
3822
+ AlertTitle.displayName = "AlertTitle";
3823
+
3824
+ /**
3825
+ * Alert description component for the body text.
3826
+ */
3827
+ const AlertDescription = React.forwardRef<
3828
+ HTMLParagraphElement,
3829
+ React.HTMLAttributes<HTMLParagraphElement>
3830
+ >(({ className, ...props }, ref) => (
3831
+ <p ref={ref} className={cn("mt-1 text-sm", className)} {...props} />
3832
+ ));
3833
+ AlertDescription.displayName = "AlertDescription";
3834
+
3835
+ export { Alert, AlertTitle, AlertDescription, alertVariants };
3130
3836
  `, prefix)
3131
3837
  }
3132
3838
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myoperator-ui",
3
- "version": "0.0.95",
3
+ "version": "0.0.97",
4
4
  "description": "CLI for adding myOperator UI components to your project",
5
5
  "type": "module",
6
6
  "exports": "./dist/index.js",