UNPKG

@daveyplate/better-auth-ui

Version:

Plug & play shadcn/ui components for better-auth

1,592 lines (1,561 loc) 504 kB
"use client" "use client"; import { AuthUIContext, AuthUIProvider, useAuthData, useCurrentOrganization, useIsHydrated, useLang, useTheme } from "./chunk-NLJJMS6W.js"; import { accountViewPaths, authLocalization, authViewPaths, cn, getLocalizedError, getPasswordSchema, getSearchParam, getViewByPath, isValidEmail, organizationViewPaths } from "./chunk-QGW7NU44.js"; // src/components/account/account-view.tsx import { MenuIcon } from "lucide-react"; import { useContext as useContext42, useMemo as useMemo11 } from "react"; // src/hooks/use-authenticate.ts import { useContext, useEffect } from "react"; function useAuthenticate(options) { const { authView = "SIGN_IN", enabled = true } = options ?? {}; const { hooks: { useSession }, basePath, viewPaths, replace } = useContext(AuthUIContext); const { data, isPending, error, refetch } = useSession(); const sessionData = data; useEffect(() => { if (!enabled || isPending || sessionData) return; const searchParams = new URLSearchParams(window.location.search); const redirectTo = searchParams.get("redirectTo") || window.location.pathname + window.location.search; replace( `${basePath}/${viewPaths[authView]}?redirectTo=${encodeURIComponent(redirectTo)}` ); }, [ isPending, sessionData, basePath, viewPaths, replace, authView, enabled ]); return { data: sessionData, user: sessionData == null ? void 0 : sessionData.user, isPending, error, refetch }; } // src/components/organization/organizations-card.tsx import { useContext as useContext8, useMemo as useMemo5, useState as useState4 } from "react"; // src/components/ui/card.tsx import { jsx } from "react/jsx-runtime"; function Card({ className, ...props }) { return /* @__PURE__ */ jsx( "div", { "data-slot": "card", className: cn( "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm", className ), ...props } ); } function CardHeader({ className, ...props }) { return /* @__PURE__ */ jsx( "div", { "data-slot": "card-header", className: cn( "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6", className ), ...props } ); } function CardTitle({ className, ...props }) { return /* @__PURE__ */ jsx( "div", { "data-slot": "card-title", className: cn("leading-none font-semibold", className), ...props } ); } function CardDescription({ className, ...props }) { return /* @__PURE__ */ jsx( "div", { "data-slot": "card-description", className: cn("text-muted-foreground text-sm", className), ...props } ); } function CardContent({ className, ...props }) { return /* @__PURE__ */ jsx( "div", { "data-slot": "card-content", className: cn("px-6", className), ...props } ); } function CardFooter({ className, ...props }) { return /* @__PURE__ */ jsx( "div", { "data-slot": "card-footer", className: cn("flex items-center px-6 [.border-t]:pt-6", className), ...props } ); } // src/components/ui/skeleton.tsx import { jsx as jsx2 } from "react/jsx-runtime"; function Skeleton({ className, ...props }) { return /* @__PURE__ */ jsx2( "div", { "data-slot": "skeleton", className: cn("bg-accent animate-pulse rounded-md", className), ...props } ); } // src/components/settings/shared/settings-action-button.tsx import { Loader2 } from "lucide-react"; import { useFormState } from "react-hook-form"; // src/components/ui/button.tsx import { Slot } from "@radix-ui/react-slot"; import { cva } from "class-variance-authority"; import { jsx as jsx3 } from "react/jsx-runtime"; var buttonVariants = cva( "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", { variants: { variant: { default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50", secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80", ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", link: "text-primary underline-offset-4 hover:underline" }, size: { default: "h-9 px-4 py-2 has-[>svg]:px-3", sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", lg: "h-10 rounded-md px-6 has-[>svg]:px-4", icon: "size-9" } }, defaultVariants: { variant: "default", size: "default" } } ); function Button({ className, variant, size, asChild = false, ...props }) { const Comp = asChild ? Slot : "button"; return /* @__PURE__ */ jsx3( Comp, { "data-slot": "button", className: cn(buttonVariants({ variant, size, className })), ...props } ); } // src/components/settings/shared/settings-action-button.tsx import { jsx as jsx4, jsxs } from "react/jsx-runtime"; function SettingsActionButton({ classNames, actionLabel, disabled, isSubmitting, variant, onClick, ...props }) { if (!onClick) { const formState = useFormState(); isSubmitting = formState.isSubmitting; } return /* @__PURE__ */ jsxs( Button, { className: cn( "md:ms-auto", classNames == null ? void 0 : classNames.button, variant === "default" && (classNames == null ? void 0 : classNames.primaryButton), variant === "destructive" && (classNames == null ? void 0 : classNames.destructiveButton) ), disabled: isSubmitting || disabled, size: "sm", type: onClick ? "button" : "submit", variant, onClick, ...props, children: [ isSubmitting && /* @__PURE__ */ jsx4(Loader2, { className: "animate-spin" }), actionLabel ] } ); } // src/components/settings/shared/settings-card-footer.tsx import { Fragment, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime"; function SettingsCardFooter({ className, classNames, actionLabel, disabled, instructions, isPending, isSubmitting, variant, action }) { return /* @__PURE__ */ jsx5( CardFooter, { className: cn( "flex flex-col justify-between gap-4 rounded-b-xl md:flex-row", (actionLabel || instructions) && "!py-4 border-t", variant === "destructive" ? "border-destructive/30 bg-destructive/15" : "bg-sidebar", className, classNames == null ? void 0 : classNames.footer ), children: isPending ? /* @__PURE__ */ jsxs2(Fragment, { children: [ instructions && /* @__PURE__ */ jsx5( Skeleton, { className: cn( "my-0.5 h-3 w-48 max-w-full md:h-4 md:w-56", classNames == null ? void 0 : classNames.skeleton ) } ), actionLabel && /* @__PURE__ */ jsx5( Skeleton, { className: cn( "h-8 w-14 md:ms-auto", classNames == null ? void 0 : classNames.skeleton ) } ) ] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [ instructions && /* @__PURE__ */ jsx5( CardDescription, { className: cn( "text-center text-muted-foreground text-xs md:text-start md:text-sm", classNames == null ? void 0 : classNames.instructions ), children: instructions } ), actionLabel && /* @__PURE__ */ jsx5( SettingsActionButton, { classNames, actionLabel, disabled, isSubmitting, variant, onClick: action } ) ] }) } ); } // src/components/settings/shared/settings-card-header.tsx import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime"; function SettingsCardHeader({ className, classNames, description, isPending, title }) { return /* @__PURE__ */ jsx6(CardHeader, { className: cn(classNames == null ? void 0 : classNames.header, className), children: isPending ? /* @__PURE__ */ jsxs3(Fragment2, { children: [ /* @__PURE__ */ jsx6( Skeleton, { className: cn( "my-0.5 h-5 w-1/3 md:h-5.5", classNames == null ? void 0 : classNames.skeleton ) } ), description && /* @__PURE__ */ jsx6( Skeleton, { className: cn( "mt-1.5 mb-0.5 h-3 w-2/3 md:h-3.5", classNames == null ? void 0 : classNames.skeleton ) } ) ] }) : /* @__PURE__ */ jsxs3(Fragment2, { children: [ /* @__PURE__ */ jsx6( CardTitle, { className: cn("text-lg md:text-xl", classNames == null ? void 0 : classNames.title), children: title } ), description && /* @__PURE__ */ jsx6( CardDescription, { className: cn( "text-xs md:text-sm", classNames == null ? void 0 : classNames.description ), children: description } ) ] }) }); } // src/components/settings/shared/settings-card.tsx import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime"; function SettingsCard({ children, className, classNames, title, description, instructions, actionLabel, disabled, isPending, isSubmitting, optimistic, variant, action, ...props }) { return /* @__PURE__ */ jsxs4( Card, { className: cn( "w-full pb-0 text-start", variant === "destructive" && "border-destructive/40", className, classNames == null ? void 0 : classNames.base ), ...props, children: [ /* @__PURE__ */ jsx7( SettingsCardHeader, { classNames, description, isPending, title } ), children, /* @__PURE__ */ jsx7( SettingsCardFooter, { classNames, actionLabel, disabled, isPending, isSubmitting, instructions, optimistic, variant, action } ) ] } ); } // src/components/settings/skeletons/settings-cell-skeleton.tsx import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime"; function SettingsCellSkeleton({ classNames }) { return /* @__PURE__ */ jsxs5( Card, { className: cn( "flex-row items-center gap-3 px-4 py-3", classNames == null ? void 0 : classNames.cell ), children: [ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [ /* @__PURE__ */ jsx8( Skeleton, { className: cn("size-5 rounded-full", classNames == null ? void 0 : classNames.skeleton) } ), /* @__PURE__ */ jsx8("div", { children: /* @__PURE__ */ jsx8( Skeleton, { className: cn("h-4 w-24", classNames == null ? void 0 : classNames.skeleton) } ) }) ] }), /* @__PURE__ */ jsx8( Skeleton, { className: cn("ms-auto size-8 w-12", classNames == null ? void 0 : classNames.skeleton) } ) ] } ); } // src/components/organization/create-organization-dialog.tsx import { zodResolver } from "@hookform/resolvers/zod"; import { Loader2 as Loader22, Trash2Icon, UploadCloudIcon } from "lucide-react"; import { useContext as useContext4, useMemo as useMemo2, useRef, useState } from "react"; import { useForm } from "react-hook-form"; import * as z from "zod"; // src/lib/image-utils.ts async function resizeAndCropImage(file, name, size, extension) { const image = await loadImage(file); const canvas = document.createElement("canvas"); canvas.width = canvas.height = size; const ctx = canvas.getContext("2d"); const minEdge = Math.min(image.width, image.height); const sx = (image.width - minEdge) / 2; const sy = (image.height - minEdge) / 2; const sWidth = minEdge; const sHeight = minEdge; ctx == null ? void 0 : ctx.drawImage(image, sx, sy, sWidth, sHeight, 0, 0, size, size); const resizedImageBlob = await new Promise( (resolve) => canvas.toBlob(resolve, `image/${extension}`) ); return new File([resizedImageBlob], `${name}.${extension}`, { type: `image/${extension}` }); } async function loadImage(file) { return new Promise((resolve, reject) => { const image = new Image(); const reader = new FileReader(); reader.onload = (e) => { var _a; image.src = (_a = e.target) == null ? void 0 : _a.result; }; image.onload = () => resolve(image); image.onerror = (err) => reject(err); reader.readAsDataURL(file); }); } async function fileToBase64(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result); reader.onerror = reject; reader.readAsDataURL(file); }); } // src/components/ui/dialog.tsx import * as DialogPrimitive from "@radix-ui/react-dialog"; import { XIcon } from "lucide-react"; import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime"; function Dialog({ ...props }) { return /* @__PURE__ */ jsx9(DialogPrimitive.Root, { "data-slot": "dialog", ...props }); } function DialogPortal({ ...props }) { return /* @__PURE__ */ jsx9(DialogPrimitive.Portal, { "data-slot": "dialog-portal", ...props }); } function DialogOverlay({ className, ...props }) { return /* @__PURE__ */ jsx9( DialogPrimitive.Overlay, { "data-slot": "dialog-overlay", className: cn( "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50", className ), ...props } ); } function DialogContent({ className, children, showCloseButton = true, ...props }) { return /* @__PURE__ */ jsxs6(DialogPortal, { "data-slot": "dialog-portal", children: [ /* @__PURE__ */ jsx9(DialogOverlay, {}), /* @__PURE__ */ jsxs6( DialogPrimitive.Content, { "data-slot": "dialog-content", className: cn( "bg-background 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 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg", className ), ...props, children: [ children, showCloseButton && /* @__PURE__ */ jsxs6( DialogPrimitive.Close, { "data-slot": "dialog-close", className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", children: [ /* @__PURE__ */ jsx9(XIcon, {}), /* @__PURE__ */ jsx9("span", { className: "sr-only", children: "Close" }) ] } ) ] } ) ] }); } function DialogHeader({ className, ...props }) { return /* @__PURE__ */ jsx9( "div", { "data-slot": "dialog-header", className: cn("flex flex-col gap-2 text-center sm:text-left", className), ...props } ); } function DialogFooter({ className, ...props }) { return /* @__PURE__ */ jsx9( "div", { "data-slot": "dialog-footer", className: cn( "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className ), ...props } ); } function DialogTitle({ className, ...props }) { return /* @__PURE__ */ jsx9( DialogPrimitive.Title, { "data-slot": "dialog-title", className: cn("text-lg leading-none font-semibold", className), ...props } ); } function DialogDescription({ className, ...props }) { return /* @__PURE__ */ jsx9( DialogPrimitive.Description, { "data-slot": "dialog-description", className: cn("text-muted-foreground text-sm", className), ...props } ); } // src/components/ui/dropdown-menu.tsx import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"; import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime"; function DropdownMenu({ ...props }) { return /* @__PURE__ */ jsx10(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props }); } function DropdownMenuTrigger({ ...props }) { return /* @__PURE__ */ jsx10( DropdownMenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props } ); } function DropdownMenuContent({ className, sideOffset = 4, ...props }) { return /* @__PURE__ */ jsx10(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx10( DropdownMenuPrimitive.Content, { "data-slot": "dropdown-menu-content", sideOffset, className: cn( "bg-popover text-popover-foreground 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-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md", className ), ...props } ) }); } function DropdownMenuItem({ className, inset, variant = "default", ...props }) { return /* @__PURE__ */ jsx10( DropdownMenuPrimitive.Item, { "data-slot": "dropdown-menu-item", "data-inset": inset, "data-variant": variant, className: cn( "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className ), ...props } ); } function DropdownMenuSeparator({ className, ...props }) { return /* @__PURE__ */ jsx10( DropdownMenuPrimitive.Separator, { "data-slot": "dropdown-menu-separator", className: cn("bg-border -mx-1 my-1 h-px", className), ...props } ); } // src/components/ui/form.tsx import * as React from "react"; import { Slot as Slot2 } from "@radix-ui/react-slot"; import { Controller, FormProvider, useFormContext, useFormState as useFormState2 } from "react-hook-form"; // src/components/ui/label.tsx import * as LabelPrimitive from "@radix-ui/react-label"; import { jsx as jsx11 } from "react/jsx-runtime"; function Label2({ className, ...props }) { return /* @__PURE__ */ jsx11( LabelPrimitive.Root, { "data-slot": "label", className: cn( "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50", className ), ...props } ); } // src/components/ui/form.tsx import { jsx as jsx12 } from "react/jsx-runtime"; var Form = FormProvider; var FormFieldContext = React.createContext( {} ); var FormField = ({ ...props }) => { return /* @__PURE__ */ jsx12(FormFieldContext.Provider, { value: { name: props.name }, children: /* @__PURE__ */ jsx12(Controller, { ...props }) }); }; var useFormField = () => { const fieldContext = React.useContext(FormFieldContext); const itemContext = React.useContext(FormItemContext); const { getFieldState } = useFormContext(); const formState = useFormState2({ name: fieldContext.name }); const fieldState = getFieldState(fieldContext.name, formState); if (!fieldContext) { throw new Error("useFormField should be used within <FormField>"); } const { id } = itemContext; return { id, name: fieldContext.name, formItemId: `${id}-form-item`, formDescriptionId: `${id}-form-item-description`, formMessageId: `${id}-form-item-message`, ...fieldState }; }; var FormItemContext = React.createContext( {} ); function FormItem({ className, ...props }) { const id = React.useId(); return /* @__PURE__ */ jsx12(FormItemContext.Provider, { value: { id }, children: /* @__PURE__ */ jsx12( "div", { "data-slot": "form-item", className: cn("grid gap-2", className), ...props } ) }); } function FormLabel({ className, ...props }) { const { error, formItemId } = useFormField(); return /* @__PURE__ */ jsx12( Label2, { "data-slot": "form-label", "data-error": !!error, className: cn("data-[error=true]:text-destructive", className), htmlFor: formItemId, ...props } ); } function FormControl({ ...props }) { const { error, formItemId, formDescriptionId, formMessageId } = useFormField(); return /* @__PURE__ */ jsx12( Slot2, { "data-slot": "form-control", id: formItemId, "aria-describedby": !error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`, "aria-invalid": !!error, ...props } ); } function FormMessage({ className, ...props }) { const { error, formMessageId } = useFormField(); const body = error ? String((error == null ? void 0 : error.message) ?? "") : props.children; if (!body) { return null; } return /* @__PURE__ */ jsx12( "p", { "data-slot": "form-message", id: formMessageId, className: cn("text-destructive text-sm", className), ...props, children: body } ); } // src/components/ui/input.tsx import { jsx as jsx13 } from "react/jsx-runtime"; function Input({ className, type, ...props }) { return /* @__PURE__ */ jsx13( "input", { type, "data-slot": "input", className: cn( "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]", "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", className ), ...props } ); } // src/components/organization/organization-logo.tsx import { BuildingIcon } from "lucide-react"; import { useContext as useContext3, useMemo } from "react"; // src/components/ui/avatar.tsx import * as AvatarPrimitive from "@radix-ui/react-avatar"; import { jsx as jsx14 } from "react/jsx-runtime"; function Avatar({ className, ...props }) { return /* @__PURE__ */ jsx14( AvatarPrimitive.Root, { "data-slot": "avatar", className: cn( "relative flex size-8 shrink-0 overflow-hidden rounded-full", className ), ...props } ); } function AvatarImage({ className, ...props }) { return /* @__PURE__ */ jsx14( AvatarPrimitive.Image, { "data-slot": "avatar-image", className: cn("aspect-square size-full", className), ...props } ); } function AvatarFallback({ className, ...props }) { return /* @__PURE__ */ jsx14( AvatarPrimitive.Fallback, { "data-slot": "avatar-fallback", className: cn( "bg-muted flex size-full items-center justify-center rounded-full", className ), ...props } ); } // src/components/organization/organization-logo.tsx import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime"; function OrganizationLogo({ className, classNames, isPending, size, organization, localization: propLocalization, ...props }) { const { localization: contextLocalization, avatar } = useContext3(AuthUIContext); const localization = useMemo( () => ({ ...contextLocalization, ...propLocalization }), [contextLocalization, propLocalization] ); const name = organization == null ? void 0 : organization.name; const src = organization == null ? void 0 : organization.logo; if (isPending) { return /* @__PURE__ */ jsx15( Skeleton, { className: cn( "shrink-0 rounded-full", size === "sm" ? "size-6" : size === "lg" ? "size-10" : size === "xl" ? "size-12" : "size-8", className, classNames == null ? void 0 : classNames.base, classNames == null ? void 0 : classNames.skeleton ) } ); } return /* @__PURE__ */ jsxs8( Avatar, { className: cn( "bg-muted", size === "sm" ? "size-6" : size === "lg" ? "size-10" : size === "xl" ? "size-12" : "size-8", className, classNames == null ? void 0 : classNames.base ), ...props, children: [ (avatar == null ? void 0 : avatar.Image) ? /* @__PURE__ */ jsx15( avatar.Image, { alt: name || (localization == null ? void 0 : localization.ORGANIZATION), className: classNames == null ? void 0 : classNames.image, src: src || "" } ) : /* @__PURE__ */ jsx15( AvatarImage, { alt: name || (localization == null ? void 0 : localization.ORGANIZATION), className: classNames == null ? void 0 : classNames.image, src: src || void 0 } ), /* @__PURE__ */ jsx15( AvatarFallback, { className: cn("text-foreground", classNames == null ? void 0 : classNames.fallback), delayMs: src ? 600 : void 0, children: /* @__PURE__ */ jsx15( BuildingIcon, { className: cn("size-[50%]", classNames == null ? void 0 : classNames.fallbackIcon) } ) } ) ] } ); } // src/components/organization/create-organization-dialog.tsx import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime"; function CreateOrganizationDialog({ className, classNames, localization: localizationProp, onOpenChange, ...props }) { var _a, _b, _c; const { authClient, localization: contextLocalization, organization: organizationOptions, navigate, toast, localizeErrors } = useContext4(AuthUIContext); const localization = useMemo2( () => ({ ...contextLocalization, ...localizationProp }), [contextLocalization, localizationProp] ); const [logo, setLogo] = useState(null); const [logoPending, setLogoPending] = useState(false); const fileInputRef = useRef(null); const openFileDialog = () => { var _a2; return (_a2 = fileInputRef.current) == null ? void 0 : _a2.click(); }; const formSchema = z.object({ logo: z.string().optional(), name: z.string().min(1, { message: `${localization.ORGANIZATION_NAME} ${localization.IS_REQUIRED}` }), slug: z.string().min(1, { message: `${localization.ORGANIZATION_SLUG} ${localization.IS_REQUIRED}` }).regex(/^[a-z0-9-]+$/, { message: `${localization.ORGANIZATION_SLUG} ${localization.IS_INVALID}` }) }); const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { logo: "", name: "", slug: "" } }); const isSubmitting = form.formState.isSubmitting; const handleLogoChange = async (file) => { if (!(organizationOptions == null ? void 0 : organizationOptions.logo)) return; setLogoPending(true); try { const resizedFile = await resizeAndCropImage( file, crypto.randomUUID(), organizationOptions.logo.size, organizationOptions.logo.extension ); let image; if (organizationOptions == null ? void 0 : organizationOptions.logo.upload) { image = await organizationOptions.logo.upload(resizedFile); } else { image = await fileToBase64(resizedFile); } setLogo(image || null); form.setValue("logo", image || ""); } catch (error) { toast({ variant: "error", message: getLocalizedError({ error, localization, localizeErrors }) }); } setLogoPending(false); }; const deleteLogo = async () => { var _a2; setLogoPending(true); const currentUrl = logo || void 0; if (currentUrl && ((_a2 = organizationOptions == null ? void 0 : organizationOptions.logo) == null ? void 0 : _a2.delete)) { await organizationOptions.logo.delete(currentUrl); } setLogo(null); form.setValue("logo", ""); setLogoPending(false); }; async function onSubmit({ name, slug, logo: logo2 }) { try { const organization = await authClient.organization.create({ name, slug, logo: logo2, fetchOptions: { throw: true } }); if ((organizationOptions == null ? void 0 : organizationOptions.pathMode) === "slug") { navigate(`${organizationOptions.basePath}/${organization.slug}`); return; } await authClient.organization.setActive({ organizationId: organization.id }); onOpenChange == null ? void 0 : onOpenChange(false); form.reset(); setLogo(null); toast({ variant: "success", message: localization.CREATE_ORGANIZATION_SUCCESS }); } catch (error) { toast({ variant: "error", message: getLocalizedError({ error, localization, localizeErrors }) }); } } return /* @__PURE__ */ jsx16(Dialog, { onOpenChange, ...props, children: /* @__PURE__ */ jsxs9(DialogContent, { className: (_a = classNames == null ? void 0 : classNames.dialog) == null ? void 0 : _a.content, children: [ /* @__PURE__ */ jsxs9(DialogHeader, { className: (_b = classNames == null ? void 0 : classNames.dialog) == null ? void 0 : _b.header, children: [ /* @__PURE__ */ jsx16( DialogTitle, { className: cn("text-lg md:text-xl", classNames == null ? void 0 : classNames.title), children: localization.CREATE_ORGANIZATION } ), /* @__PURE__ */ jsx16( DialogDescription, { className: cn( "text-xs md:text-sm", classNames == null ? void 0 : classNames.description ), children: localization.ORGANIZATIONS_INSTRUCTIONS } ) ] }), /* @__PURE__ */ jsx16(Form, { ...form, children: /* @__PURE__ */ jsxs9( "form", { onSubmit: form.handleSubmit(onSubmit), className: "space-y-6", children: [ (organizationOptions == null ? void 0 : organizationOptions.logo) && /* @__PURE__ */ jsx16( FormField, { control: form.control, name: "logo", render: () => /* @__PURE__ */ jsxs9(FormItem, { children: [ /* @__PURE__ */ jsx16( "input", { ref: fileInputRef, accept: "image/*", disabled: logoPending, hidden: true, type: "file", onChange: (e) => { var _a2; const file = (_a2 = e.target.files) == null ? void 0 : _a2.item(0); if (file) handleLogoChange(file); e.target.value = ""; } } ), /* @__PURE__ */ jsx16(FormLabel, { children: localization.LOGO }), /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-4", children: [ /* @__PURE__ */ jsxs9(DropdownMenu, { children: [ /* @__PURE__ */ jsx16(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx16( Button, { className: "size-fit rounded-full", size: "icon", type: "button", variant: "ghost", children: /* @__PURE__ */ jsx16( OrganizationLogo, { className: "size-16", isPending: logoPending, localization, organization: { name: form.watch( "name" ), logo } } ) } ) }), /* @__PURE__ */ jsxs9( DropdownMenuContent, { align: "start", onCloseAutoFocus: (e) => e.preventDefault(), children: [ /* @__PURE__ */ jsxs9( DropdownMenuItem, { onClick: openFileDialog, disabled: logoPending, children: [ /* @__PURE__ */ jsx16(UploadCloudIcon, {}), localization.UPLOAD_LOGO ] } ), logo && /* @__PURE__ */ jsxs9( DropdownMenuItem, { onClick: deleteLogo, disabled: logoPending, variant: "destructive", children: [ /* @__PURE__ */ jsx16(Trash2Icon, {}), localization.DELETE_LOGO ] } ) ] } ) ] }), /* @__PURE__ */ jsxs9( Button, { disabled: logoPending, variant: "outline", onClick: openFileDialog, type: "button", children: [ logoPending && /* @__PURE__ */ jsx16(Loader22, { className: "animate-spin" }), localization.UPLOAD ] } ) ] }), /* @__PURE__ */ jsx16(FormMessage, {}) ] }) } ), /* @__PURE__ */ jsx16( FormField, { control: form.control, name: "name", render: ({ field }) => /* @__PURE__ */ jsxs9(FormItem, { children: [ /* @__PURE__ */ jsx16(FormLabel, { children: localization.ORGANIZATION_NAME }), /* @__PURE__ */ jsx16(FormControl, { children: /* @__PURE__ */ jsx16( Input, { placeholder: localization.ORGANIZATION_NAME_PLACEHOLDER, ...field } ) }), /* @__PURE__ */ jsx16(FormMessage, {}) ] }) } ), /* @__PURE__ */ jsx16( FormField, { control: form.control, name: "slug", render: ({ field }) => /* @__PURE__ */ jsxs9(FormItem, { children: [ /* @__PURE__ */ jsx16(FormLabel, { children: localization.ORGANIZATION_SLUG }), /* @__PURE__ */ jsx16(FormControl, { children: /* @__PURE__ */ jsx16( Input, { placeholder: localization.ORGANIZATION_SLUG_PLACEHOLDER, ...field } ) }), /* @__PURE__ */ jsx16(FormMessage, {}) ] }) } ), /* @__PURE__ */ jsxs9(DialogFooter, { className: (_c = classNames == null ? void 0 : classNames.dialog) == null ? void 0 : _c.footer, children: [ /* @__PURE__ */ jsx16( Button, { type: "button", variant: "outline", onClick: () => onOpenChange == null ? void 0 : onOpenChange(false), className: cn( classNames == null ? void 0 : classNames.button, classNames == null ? void 0 : classNames.outlineButton ), children: localization.CANCEL } ), /* @__PURE__ */ jsxs9( Button, { type: "submit", className: cn( classNames == null ? void 0 : classNames.button, classNames == null ? void 0 : classNames.primaryButton ), disabled: isSubmitting, children: [ isSubmitting && /* @__PURE__ */ jsx16(Loader22, { className: "animate-spin" }), localization.CREATE_ORGANIZATION ] } ) ] }) ] } ) }) ] }) }); } // src/components/organization/organization-cell.tsx import { EllipsisIcon, Loader2 as Loader24, LogOutIcon, SettingsIcon } from "lucide-react"; import { useCallback, useContext as useContext7, useMemo as useMemo4, useState as useState3 } from "react"; // src/components/organization/leave-organization-dialog.tsx import { Loader2 as Loader23 } from "lucide-react"; import { useContext as useContext6, useMemo as useMemo3, useState as useState2 } from "react"; // src/components/organization/organization-cell-view.tsx import { useContext as useContext5 } from "react"; import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime"; function OrganizationCellView({ className, classNames, isPending, size, organization, localization: propLocalization }) { const { localization: contextLocalization } = useContext5(AuthUIContext); const localization = { ...contextLocalization, ...propLocalization }; return /* @__PURE__ */ jsxs10( "div", { className: cn( "flex items-center gap-2 truncate", className, classNames == null ? void 0 : classNames.base ), children: [ /* @__PURE__ */ jsx17( OrganizationLogo, { className: cn(size !== "sm" && "my-0.5"), classNames: classNames == null ? void 0 : classNames.avatar, isPending, localization, organization, size } ), /* @__PURE__ */ jsx17( "div", { className: cn( "flex flex-col truncate text-left leading-tight", classNames == null ? void 0 : classNames.content ), children: isPending ? /* @__PURE__ */ jsxs10(Fragment3, { children: [ /* @__PURE__ */ jsx17( Skeleton, { className: cn( "max-w-full", size === "lg" ? "h-4.5 w-32" : "h-3.5 w-24", classNames == null ? void 0 : classNames.title, classNames == null ? void 0 : classNames.skeleton ) } ), size !== "sm" && /* @__PURE__ */ jsx17( Skeleton, { className: cn( "mt-1.5 max-w-full", size === "lg" ? "h-3.5 w-24" : "h-3 w-16", classNames == null ? void 0 : classNames.subtitle, classNames == null ? void 0 : classNames.skeleton ) } ) ] }) : /* @__PURE__ */ jsxs10(Fragment3, { children: [ /* @__PURE__ */ jsx17( "span", { className: cn( "truncate font-semibold", size === "lg" ? "text-base" : "text-sm", classNames == null ? void 0 : classNames.title ), children: (organization == null ? void 0 : organization.name) || (localization == null ? void 0 : localization.ORGANIZATION) } ), size !== "sm" && (organization == null ? void 0 : organization.slug) && /* @__PURE__ */ jsx17( "span", { className: cn( "truncate opacity-70", size === "lg" ? "text-sm" : "text-xs", classNames == null ? void 0 : classNames.subtitle ), children: organization.slug } ) ] }) } ) ] } ); } // src/components/organization/leave-organization-dialog.tsx import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime"; function LeaveOrganizationDialog({ organization, className, classNames, localization: localizationProp, onOpenChange, ...props }) { var _a, _b, _c; const { authClient, hooks: { useListOrganizations }, localization: contextLocalization, toast, localizeErrors } = useContext6(AuthUIContext); const localization = useMemo3( () => ({ ...contextLocalization, ...localizationProp }), [contextLocalization, localizationProp] ); const { refetch: refetchOrganizations } = useListOrganizations(); const [isLeaving, setIsLeaving] = useState2(false); const handleLeaveOrganization = async () => { setIsLeaving(true); try { await authClient.organization.leave({ organizationId: organization.id, fetchOptions: { throw: true } }); await (refetchOrganizations == null ? void 0 : refetchOrganizations()); toast({ variant: "success", message: localization.LEAVE_ORGANIZATION_SUCCESS }); onOpenChange == null ? void 0 : onOpenChange(false); } catch (error) { toast({ variant: "error", message: getLocalizedError({ error, localization, localizeErrors }) }); } setIsLeaving(false); }; return /* @__PURE__ */ jsx18(Dialog, { onOpenChange, ...props, children: /* @__PURE__ */ jsxs11( DialogContent, { className: (_a = classNames == null ? void 0 : classNames.dialog) == null ? void 0 : _a.content, onOpenAutoFocus: (e) => e.preventDefault(), children: [ /* @__PURE__ */ jsxs11(DialogHeader, { className: (_b = classNames == null ? void 0 : classNames.dialog) == null ? void 0 : _b.header, children: [ /* @__PURE__ */ jsx18( DialogTitle, { className: cn("text-lg md:text-xl", classNames == null ? void 0 : classNames.title), children: localization.LEAVE_ORGANIZATION } ), /* @__PURE__ */ jsx18( DialogDescription, { className: cn( "text-xs md:text-sm", classNames == null ? void 0 : classNames.description ), children: localization.LEAVE_ORGANIZATION_CONFIRM } ) ] }), /* @__PURE__ */ jsx18( Card, { className: cn( "my-2 flex-row p-4", className, classNames == null ? void 0 : classNames.cell ), children: /* @__PURE__ */ jsx18( OrganizationCellView, { organization, localization } ) } ), /* @__PURE__ */ jsxs11(DialogFooter, { className: (_c = classNames == null ? void 0 : classNames.dialog) == null ? void 0 : _c.footer, children: [ /* @__PURE__ */ jsx18( Button, { type: "button", variant: "outline", onClick: () => onOpenChange == null ? void 0 : onOpenChange(false), className: cn( classNames == null ? void 0 : classNames.button, classNames == null ? void 0 : classNames.outlineButton ), disabled: isLeaving, children: localization.CANCEL } ), /* @__PURE__ */ jsxs11( Button, { type: "button", variant: "destructive", onClick: handleLeaveOrganization, className: cn( classNames == null ? void 0 : classNames.button, classNames == null ? void 0 : classNames.destructiveButton ), disabled: isLeaving, children: [ isLeaving && /* @__PURE__ */ jsx18(Loader23, { className: "animate-spin" }), localization.LEAVE_ORGANIZATION ] } ) ] }) ] } ) }); } // src/components/organization/organization-cell.tsx import { Fragment as Fragment4, jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime"; function OrganizationCell({ className, classNames, organization, localization: localizationProp }) { var _a; const { authClient, localization: contextLocalization, organization: organizationOptions, navigate, toast, localizeErrors } = useContext7(AuthUIContext); const localization = useMemo4( () => ({ ...contextLocalization, ...localizationProp }), [contextLocalization, localizationProp] ); const { pathMode } = organizationOptions || {}; const [isLeaveDialogOpen, setIsLeaveDialogOpen] = useState3(false); const [isManagingOrganization, setIsManagingOrganization] = useState3(false); const handleManageOrganization = useCallback(async () => { var _a2; setIsManagingOrganization(true); if (pathMode === "slug") { navigate( `${organizationOptions == null ? void 0 : organizationOptions.basePath}/${organization.slug}/${organizationOptions == null ? void 0 : organizationOptions.viewPaths.SETTINGS}` ); return; } try { await authClient.organization.setActive({ organizationId: organization.id, fetchOptions: { throw: true } }); navigate( `${organizationOptions == null ? void 0 : organizationOptions.basePath}/${(_a2 = organizationOptions == null ? void 0 : organizationOptions.viewPaths) == null ? void 0 : _a2.SETTINGS}` ); } catch (error) { toast({ variant: "error", message: getLocalizedError({ error, localization, localizeErrors }) }); setIsManagingOrganization(false); } }, [ authClient, organization.id, organizationOptions == null ? void 0 : organizationOptions.basePath, (_a = organizationOptions == null ? void 0 : organizationOptions.viewPaths) == null ? void 0 : _a.SETTINGS, organization.slug, pathMode, navigate, toast, localization, localizeErrors ]); return /* @__PURE__ */ jsxs12(Fragment4, { children: [ /* @__PURE__ */ jsxs12(Card, { className: cn("flex-row p-4", className, classNames == null ? void 0 : classNames.cell), children: [ /* @__PURE__ */ jsx19( OrganizationCellView, { organization, localization } ), /* @__PURE__ */ jsxs12(DropdownMenu, { children: [ /* @__PURE__ */ jsx19(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx19(