fix: resolve TypeScript errors in migrated components
This commit is contained in:
121
apps/web/src/components/ui/alert-dialog.tsx
Normal file
121
apps/web/src/components/ui/alert-dialog.tsx
Normal file
@@ -0,0 +1,121 @@
|
||||
import * as React from "react";
|
||||
|
||||
export interface AlertDialogProps {
|
||||
open?: boolean;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface AlertDialogTriggerProps {
|
||||
children?: React.ReactNode;
|
||||
asChild?: boolean;
|
||||
}
|
||||
|
||||
export interface AlertDialogContentProps {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface AlertDialogHeaderProps {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface AlertDialogFooterProps {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface AlertDialogTitleProps {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface AlertDialogDescriptionProps {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface AlertDialogActionProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface AlertDialogCancelProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
const AlertDialogContext = React.createContext<{
|
||||
open?: boolean;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
}>({});
|
||||
|
||||
export function AlertDialog({ open, onOpenChange, children }: AlertDialogProps) {
|
||||
return (
|
||||
<AlertDialogContext.Provider value={{ open, onOpenChange }}>
|
||||
{children}
|
||||
</AlertDialogContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function AlertDialogTrigger({ children, asChild }: AlertDialogTriggerProps) {
|
||||
const { onOpenChange } = React.useContext(AlertDialogContext);
|
||||
|
||||
if (asChild && React.isValidElement(children)) {
|
||||
return React.cloneElement(children, {
|
||||
onClick: () => onOpenChange?.(true),
|
||||
} as React.HTMLAttributes<HTMLElement>);
|
||||
}
|
||||
|
||||
return <div onClick={() => onOpenChange?.(true)}>{children}</div>;
|
||||
}
|
||||
|
||||
export function AlertDialogContent({ children }: AlertDialogContentProps) {
|
||||
const { open, onOpenChange } = React.useContext(AlertDialogContext);
|
||||
|
||||
if (!open) return null;
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
||||
<div className="fixed inset-0 bg-black/50" onClick={() => onOpenChange?.(false)} />
|
||||
<div className="relative z-50 w-full max-w-lg rounded-lg bg-white p-6 shadow-lg">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function AlertDialogHeader({ children }: AlertDialogHeaderProps) {
|
||||
return <div className="mb-4">{children}</div>;
|
||||
}
|
||||
|
||||
export function AlertDialogFooter({ children }: AlertDialogFooterProps) {
|
||||
return <div className="mt-4 flex justify-end gap-2">{children}</div>;
|
||||
}
|
||||
|
||||
export function AlertDialogTitle({ children }: AlertDialogTitleProps) {
|
||||
return <h2 className="text-lg font-semibold">{children}</h2>;
|
||||
}
|
||||
|
||||
export function AlertDialogDescription({ children }: AlertDialogDescriptionProps) {
|
||||
return <p className="text-sm text-gray-600">{children}</p>;
|
||||
}
|
||||
|
||||
export function AlertDialogAction({ children, ...props }: AlertDialogActionProps) {
|
||||
return (
|
||||
<button
|
||||
className="rounded-md bg-blue-600 px-4 py-2 text-sm text-white hover:bg-blue-700"
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export function AlertDialogCancel({ children, ...props }: AlertDialogCancelProps) {
|
||||
const { onOpenChange } = React.useContext(AlertDialogContext);
|
||||
|
||||
return (
|
||||
<button
|
||||
className="rounded-md border border-gray-300 px-4 py-2 text-sm hover:bg-gray-100"
|
||||
onClick={() => onOpenChange?.(false)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
22
apps/web/src/components/ui/badge.tsx
Normal file
22
apps/web/src/components/ui/badge.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Badge as BaseBadge } from "@mosaic/ui";
|
||||
import type { BadgeProps as BaseBadgeProps, BadgeVariant as BaseBadgeVariant } from "@mosaic/ui";
|
||||
|
||||
// Extend BadgeVariant to include shadcn/ui variants
|
||||
export type BadgeVariant = BaseBadgeVariant | "secondary" | "outline" | "default" | "destructive";
|
||||
|
||||
export interface BadgeProps extends Omit<BaseBadgeProps, "variant"> {
|
||||
variant?: BadgeVariant;
|
||||
}
|
||||
|
||||
// Map extended variants to base variants
|
||||
const variantMap: Record<string, BaseBadgeVariant> = {
|
||||
"secondary": "status-neutral",
|
||||
"outline": "status-info",
|
||||
"default": "status-neutral",
|
||||
"destructive": "status-error",
|
||||
};
|
||||
|
||||
export function Badge({ variant = "default", ...props }: BadgeProps) {
|
||||
const mappedVariant = (variantMap[variant] || variant) as BaseBadgeVariant;
|
||||
return <BaseBadge variant={mappedVariant} {...props} />;
|
||||
}
|
||||
26
apps/web/src/components/ui/button.tsx
Normal file
26
apps/web/src/components/ui/button.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Button as BaseButton } from "@mosaic/ui";
|
||||
import type { ButtonProps as BaseButtonProps } from "@mosaic/ui";
|
||||
import type { ReactNode, ButtonHTMLAttributes } from "react";
|
||||
|
||||
// Extend Button to support additional variants
|
||||
type ExtendedVariant = "primary" | "secondary" | "danger" | "ghost" | "outline" | "destructive" | "link";
|
||||
|
||||
export interface ButtonProps extends Omit<BaseButtonProps, "variant"> {
|
||||
variant?: ExtendedVariant;
|
||||
size?: "sm" | "md" | "lg" | "icon";
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
// Map extended variants to base variants
|
||||
const variantMap: Record<string, "primary" | "secondary" | "danger" | "ghost"> = {
|
||||
"outline": "ghost",
|
||||
"destructive": "danger",
|
||||
"link": "ghost",
|
||||
};
|
||||
|
||||
export function Button({ variant = "primary", size = "md", ...props }: ButtonProps) {
|
||||
const mappedVariant = variantMap[variant] || variant;
|
||||
const mappedSize = size === "icon" ? "sm" : size;
|
||||
|
||||
return <BaseButton variant={mappedVariant as "primary" | "secondary" | "danger" | "ghost"} size={mappedSize as "sm" | "md" | "lg"} {...props} />;
|
||||
}
|
||||
22
apps/web/src/components/ui/card.tsx
Normal file
22
apps/web/src/components/ui/card.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
export { Card, CardHeader, CardContent, CardFooter } from "@mosaic/ui";
|
||||
export type { CardProps, CardHeaderProps, CardContentProps, CardFooterProps } from "@mosaic/ui";
|
||||
|
||||
// Additional Card sub-components for shadcn/ui compatibility
|
||||
import * as React from "react";
|
||||
|
||||
export interface CardTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {}
|
||||
export interface CardDescriptionProps extends React.HTMLAttributes<HTMLParagraphElement> {}
|
||||
|
||||
export const CardTitle = React.forwardRef<HTMLHeadingElement, CardTitleProps>(
|
||||
({ className = "", ...props }, ref) => (
|
||||
<h3 ref={ref} className={`text-2xl font-semibold leading-none tracking-tight ${className}`} {...props} />
|
||||
)
|
||||
);
|
||||
CardTitle.displayName = "CardTitle";
|
||||
|
||||
export const CardDescription = React.forwardRef<HTMLParagraphElement, CardDescriptionProps>(
|
||||
({ className = "", ...props }, ref) => (
|
||||
<p ref={ref} className={`text-sm text-gray-600 ${className}`} {...props} />
|
||||
)
|
||||
);
|
||||
CardDescription.displayName = "CardDescription";
|
||||
2
apps/web/src/components/ui/input.tsx
Normal file
2
apps/web/src/components/ui/input.tsx
Normal file
@@ -0,0 +1,2 @@
|
||||
export { Input } from "@mosaic/ui";
|
||||
export type { InputProps } from "@mosaic/ui";
|
||||
17
apps/web/src/components/ui/label.tsx
Normal file
17
apps/web/src/components/ui/label.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import * as React from "react";
|
||||
|
||||
export interface LabelProps extends React.LabelHTMLAttributes<HTMLLabelElement> {}
|
||||
|
||||
export const Label = React.forwardRef<HTMLLabelElement, LabelProps>(
|
||||
({ className = "", ...props }, ref) => {
|
||||
return (
|
||||
<label
|
||||
ref={ref}
|
||||
className={`text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 ${className}`}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Label.displayName = "Label";
|
||||
102
apps/web/src/components/ui/select.tsx
Normal file
102
apps/web/src/components/ui/select.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import * as React from "react";
|
||||
|
||||
export interface SelectProps {
|
||||
value?: string;
|
||||
onValueChange?: (value: string) => void;
|
||||
defaultValue?: string;
|
||||
disabled?: boolean;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface SelectTriggerProps {
|
||||
id?: string;
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface SelectContentProps {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface SelectItemProps {
|
||||
value: string;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface SelectValueProps {
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
const SelectContext = React.createContext<{
|
||||
value?: string;
|
||||
onValueChange?: (value: string) => void;
|
||||
isOpen: boolean;
|
||||
setIsOpen: (open: boolean) => void;
|
||||
}>({ isOpen: false, setIsOpen: () => {} });
|
||||
|
||||
export function Select({ value, onValueChange, defaultValue, disabled, children }: SelectProps) {
|
||||
const [isOpen, setIsOpen] = React.useState(false);
|
||||
const [internalValue, setInternalValue] = React.useState(defaultValue);
|
||||
|
||||
const currentValue = value !== undefined ? value : internalValue;
|
||||
|
||||
const handleValueChange = (newValue: string) => {
|
||||
if (value === undefined) {
|
||||
setInternalValue(newValue);
|
||||
}
|
||||
onValueChange?.(newValue);
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<SelectContext.Provider value={{ value: currentValue, onValueChange: handleValueChange, isOpen, setIsOpen }}>
|
||||
<div className="relative">{children}</div>
|
||||
</SelectContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function SelectTrigger({ id, className = "", children }: SelectTriggerProps) {
|
||||
const { isOpen, setIsOpen } = React.useContext(SelectContext);
|
||||
|
||||
return (
|
||||
<button
|
||||
id={id}
|
||||
type="button"
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
className={`flex h-10 w-full items-center justify-between rounded-md border border-gray-300 bg-white px-3 py-2 text-sm ${className}`}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export function SelectValue({ placeholder }: SelectValueProps) {
|
||||
const { value } = React.useContext(SelectContext);
|
||||
|
||||
return <span>{value || placeholder}</span>;
|
||||
}
|
||||
|
||||
export function SelectContent({ children }: SelectContentProps) {
|
||||
const { isOpen } = React.useContext(SelectContext);
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
<div className="absolute z-50 mt-1 max-h-60 w-full overflow-auto rounded-md border border-gray-300 bg-white shadow-lg">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function SelectItem({ value, children }: SelectItemProps) {
|
||||
const { onValueChange } = React.useContext(SelectContext);
|
||||
|
||||
return (
|
||||
<div
|
||||
onClick={() => onValueChange?.(value)}
|
||||
className="cursor-pointer px-3 py-2 text-sm hover:bg-gray-100"
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
28
apps/web/src/components/ui/switch.tsx
Normal file
28
apps/web/src/components/ui/switch.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import * as React from "react";
|
||||
|
||||
export interface SwitchProps {
|
||||
id?: string;
|
||||
checked?: boolean;
|
||||
onCheckedChange?: (checked: boolean) => void;
|
||||
disabled?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const Switch = React.forwardRef<HTMLInputElement, SwitchProps>(
|
||||
({ id, checked, onCheckedChange, disabled, className = "" }, ref) => {
|
||||
return (
|
||||
<input
|
||||
type="checkbox"
|
||||
role="switch"
|
||||
ref={ref}
|
||||
id={id}
|
||||
checked={checked}
|
||||
onChange={(e) => onCheckedChange?.(e.target.checked)}
|
||||
disabled={disabled}
|
||||
className={`w-11 h-6 rounded-full ${className}`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Switch.displayName = "Switch";
|
||||
2
apps/web/src/components/ui/textarea.tsx
Normal file
2
apps/web/src/components/ui/textarea.tsx
Normal file
@@ -0,0 +1,2 @@
|
||||
export { Textarea } from "@mosaic/ui";
|
||||
export type { TextareaProps } from "@mosaic/ui";
|
||||
Reference in New Issue
Block a user