removed chakra

This commit is contained in:
2024-12-13 09:38:30 -05:00
parent 559dd5fe4c
commit 39fdc30364
55 changed files with 5 additions and 4411 deletions

View File

@@ -1,47 +0,0 @@
import { Accordion, HStack } from "@chakra-ui/react"
import * as React from "react"
import { LuChevronDown } from "react-icons/lu"
interface AccordionItemTriggerProps extends Accordion.ItemTriggerProps {
indicatorPlacement?: "start" | "end"
}
export const AccordionItemTrigger = React.forwardRef<
HTMLButtonElement,
AccordionItemTriggerProps
>(function AccordionItemTrigger(props, ref) {
const { children, indicatorPlacement = "end", ...rest } = props
return (
<Accordion.ItemTrigger {...rest} ref={ref}>
{indicatorPlacement === "start" && (
<Accordion.ItemIndicator rotate={{ base: "-90deg", _open: "0deg" }}>
<LuChevronDown />
</Accordion.ItemIndicator>
)}
<HStack gap="4" flex="1" textAlign="start" width="full">
{children}
</HStack>
{indicatorPlacement === "end" && (
<Accordion.ItemIndicator>
<LuChevronDown />
</Accordion.ItemIndicator>
)}
</Accordion.ItemTrigger>
)
})
interface AccordionItemContentProps extends Accordion.ItemContentProps {}
export const AccordionItemContent = React.forwardRef<
HTMLDivElement,
AccordionItemContentProps
>(function AccordionItemContent(props, ref) {
return (
<Accordion.ItemContent>
<Accordion.ItemBody {...props} ref={ref} />
</Accordion.ItemContent>
)
})
export const AccordionRoot = Accordion.Root
export const AccordionItem = Accordion.Item

View File

@@ -1,40 +0,0 @@
import { ActionBar, Portal } from "@chakra-ui/react"
import { CloseButton } from "./close-button"
import * as React from "react"
interface ActionBarContentProps extends ActionBar.ContentProps {
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
}
export const ActionBarContent = React.forwardRef<
HTMLDivElement,
ActionBarContentProps
>(function ActionBarContent(props, ref) {
const { children, portalled = true, portalRef, ...rest } = props
return (
<Portal disabled={!portalled} container={portalRef}>
<ActionBar.Positioner>
<ActionBar.Content ref={ref} {...rest} asChild={false}>
{children}
</ActionBar.Content>
</ActionBar.Positioner>
</Portal>
)
})
export const ActionBarCloseTrigger = React.forwardRef<
HTMLButtonElement,
ActionBar.CloseTriggerProps
>(function ActionBarCloseTrigger(props, ref) {
return (
<ActionBar.CloseTrigger {...props} asChild ref={ref}>
<CloseButton size="sm" />
</ActionBar.CloseTrigger>
)
})
export const ActionBarRoot = ActionBar.Root
export const ActionBarSelectionTrigger = ActionBar.SelectionTrigger
export const ActionBarSeparator = ActionBar.Separator

View File

@@ -1,51 +0,0 @@
import { Alert as ChakraAlert } from "@chakra-ui/react"
import { CloseButton } from "./close-button"
import * as React from "react"
export interface AlertProps extends Omit<ChakraAlert.RootProps, "title"> {
startElement?: React.ReactNode
endElement?: React.ReactNode
title?: React.ReactNode
icon?: React.ReactElement
closable?: boolean
onClose?: () => void
}
export const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
function Alert(props, ref) {
const {
title,
children,
icon,
closable,
onClose,
startElement,
endElement,
...rest
} = props
return (
<ChakraAlert.Root ref={ref} {...rest}>
{startElement || <ChakraAlert.Indicator>{icon}</ChakraAlert.Indicator>}
{children ? (
<ChakraAlert.Content>
<ChakraAlert.Title>{title}</ChakraAlert.Title>
<ChakraAlert.Description>{children}</ChakraAlert.Description>
</ChakraAlert.Content>
) : (
<ChakraAlert.Title flex="1">{title}</ChakraAlert.Title>
)}
{endElement}
{closable && (
<CloseButton
size="sm"
pos="relative"
top="-2"
insetEnd="-2"
alignSelf="flex-start"
onClick={onClose}
/>
)}
</ChakraAlert.Root>
)
},
)

View File

@@ -1,74 +0,0 @@
"use client"
import type { GroupProps, SlotRecipeProps } from "@chakra-ui/react"
import { Avatar as ChakraAvatar, Group } from "@chakra-ui/react"
import * as React from "react"
type ImageProps = React.ImgHTMLAttributes<HTMLImageElement>
export interface AvatarProps extends ChakraAvatar.RootProps {
name?: string
src?: string
srcSet?: string
loading?: ImageProps["loading"]
icon?: React.ReactElement
fallback?: React.ReactNode
}
export const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(
function Avatar(props, ref) {
const { name, src, srcSet, loading, icon, fallback, children, ...rest } =
props
return (
<ChakraAvatar.Root ref={ref} {...rest}>
<AvatarFallback name={name} icon={icon}>
{fallback}
</AvatarFallback>
<ChakraAvatar.Image src={src} srcSet={srcSet} loading={loading} />
{children}
</ChakraAvatar.Root>
)
},
)
interface AvatarFallbackProps extends ChakraAvatar.FallbackProps {
name?: string
icon?: React.ReactElement
}
const AvatarFallback = React.forwardRef<HTMLDivElement, AvatarFallbackProps>(
function AvatarFallback(props, ref) {
const { name, icon, children, ...rest } = props
return (
<ChakraAvatar.Fallback ref={ref} {...rest}>
{children}
{name != null && children == null && <>{getInitials(name)}</>}
{name == null && children == null && (
<ChakraAvatar.Icon asChild={!!icon}>{icon}</ChakraAvatar.Icon>
)}
</ChakraAvatar.Fallback>
)
},
)
function getInitials(name: string) {
const names = name.trim().split(" ")
const firstName = names[0] != null ? names[0] : ""
const lastName = names.length > 1 ? names[names.length - 1] : ""
return firstName && lastName
? `${firstName.charAt(0)}${lastName.charAt(0)}`
: firstName.charAt(0)
}
interface AvatarGroupProps extends GroupProps, SlotRecipeProps<"avatar"> {}
export const AvatarGroup = React.forwardRef<HTMLDivElement, AvatarGroupProps>(
function AvatarGroup(props, ref) {
const { size, variant, borderless, ...rest } = props
return (
<ChakraAvatar.PropsProvider value={{ size, variant, borderless }}>
<Group gap="0" spaceX="-3" ref={ref} {...rest} />
</ChakraAvatar.PropsProvider>
)
},
)

View File

@@ -1,31 +0,0 @@
import { Blockquote as ChakraBlockquote } from "@chakra-ui/react"
import * as React from "react"
export interface BlockquoteProps extends ChakraBlockquote.RootProps {
cite?: React.ReactNode
citeUrl?: string
icon?: React.ReactNode
showDash?: boolean
}
export const Blockquote = React.forwardRef<HTMLDivElement, BlockquoteProps>(
function Blockquote(props, ref) {
const { children, cite, citeUrl, showDash, icon, ...rest } = props
return (
<ChakraBlockquote.Root ref={ref} {...rest}>
{icon}
<ChakraBlockquote.Content cite={citeUrl}>
{children}
</ChakraBlockquote.Content>
{cite && (
<ChakraBlockquote.Caption>
{showDash ? <>&mdash;</> : null} <cite>{cite}</cite>
</ChakraBlockquote.Caption>
)}
</ChakraBlockquote.Root>
)
},
)
export const BlockquoteIcon = ChakraBlockquote.Icon

View File

@@ -1,40 +0,0 @@
import { Breadcrumb, type SystemStyleObject } from "@chakra-ui/react"
import * as React from "react"
export interface BreadcrumbRootProps extends Breadcrumb.RootProps {
separator?: React.ReactNode
separatorGap?: SystemStyleObject["gap"]
}
export const BreadcrumbRoot = React.forwardRef<
HTMLDivElement,
BreadcrumbRootProps
>(function BreadcrumbRoot(props, ref) {
const { separator, separatorGap, children, ...rest } = props
const validChildren = React.Children.toArray(children).filter(
React.isValidElement,
)
return (
<Breadcrumb.Root ref={ref} {...rest}>
<Breadcrumb.List gap={separatorGap}>
{validChildren.map((child, index) => {
const last = index === validChildren.length - 1
return (
<React.Fragment key={index}>
<Breadcrumb.Item>{child}</Breadcrumb.Item>
{!last && (
<Breadcrumb.Separator>{separator}</Breadcrumb.Separator>
)}
</React.Fragment>
)
})}
</Breadcrumb.List>
</Breadcrumb.Root>
)
})
export const BreadcrumbLink = Breadcrumb.Link
export const BreadcrumbCurrentLink = Breadcrumb.CurrentLink
export const BreadcrumbEllipsis = Breadcrumb.Ellipsis

View File

@@ -1,57 +0,0 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps, } from "class-variance-authority"
import { cn } from "src/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
icon: "h-9 w-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = "Button"
export { Button, buttonVariants }

View File

@@ -1,58 +0,0 @@
import { CheckboxCard as ChakraCheckboxCard } from "@chakra-ui/react"
import * as React from "react"
export interface CheckboxCardProps extends ChakraCheckboxCard.RootProps {
icon?: React.ReactElement
label?: React.ReactNode
description?: React.ReactNode
addon?: React.ReactNode
indicator?: React.ReactNode | null
indicatorPlacement?: "start" | "end" | "inside"
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
}
export const CheckboxCard = React.forwardRef<
HTMLInputElement,
CheckboxCardProps
>(function CheckboxCard(props, ref) {
const {
inputProps,
label,
description,
icon,
addon,
indicator = <ChakraCheckboxCard.Indicator />,
indicatorPlacement = "end",
...rest
} = props
const hasContent = label || description || icon
const ContentWrapper = indicator ? ChakraCheckboxCard.Content : React.Fragment
return (
<ChakraCheckboxCard.Root {...rest}>
<ChakraCheckboxCard.HiddenInput ref={ref} {...inputProps} />
<ChakraCheckboxCard.Control>
{indicatorPlacement === "start" && indicator}
{hasContent && (
<ContentWrapper>
{icon}
{label && (
<ChakraCheckboxCard.Label>{label}</ChakraCheckboxCard.Label>
)}
{description && (
<ChakraCheckboxCard.Description>
{description}
</ChakraCheckboxCard.Description>
)}
{indicatorPlacement === "inside" && indicator}
</ContentWrapper>
)}
{indicatorPlacement === "end" && indicator}
</ChakraCheckboxCard.Control>
{addon && <ChakraCheckboxCard.Addon>{addon}</ChakraCheckboxCard.Addon>}
</ChakraCheckboxCard.Root>
)
})
export const CheckboxCardIndicator = ChakraCheckboxCard.Indicator

View File

@@ -1,25 +0,0 @@
import { Checkbox as ChakraCheckbox } from "@chakra-ui/react"
import * as React from "react"
export interface CheckboxProps extends ChakraCheckbox.RootProps {
icon?: React.ReactNode
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
rootRef?: React.Ref<HTMLLabelElement>
}
export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
function Checkbox(props, ref) {
const { icon, children, inputProps, rootRef, ...rest } = props
return (
<ChakraCheckbox.Root ref={rootRef} {...rest}>
<ChakraCheckbox.HiddenInput ref={ref} {...inputProps} />
<ChakraCheckbox.Control>
{icon || <ChakraCheckbox.Indicator />}
</ChakraCheckbox.Control>
{children != null && (
<ChakraCheckbox.Label>{children}</ChakraCheckbox.Label>
)}
</ChakraCheckbox.Root>
)
},
)

View File

@@ -1,108 +0,0 @@
import type { ButtonProps, InputProps } from "@chakra-ui/react"
import {
Button,
Clipboard as ChakraClipboard,
IconButton,
Input,
} from "@chakra-ui/react"
import * as React from "react"
import { LuCheck, LuClipboard, LuLink } from "react-icons/lu"
const ClipboardIcon = React.forwardRef<
HTMLDivElement,
ChakraClipboard.IndicatorProps
>(function ClipboardIcon(props, ref) {
return (
<ChakraClipboard.Indicator copied={<LuCheck />} {...props} ref={ref}>
<LuClipboard />
</ChakraClipboard.Indicator>
)
})
const ClipboardCopyText = React.forwardRef<
HTMLDivElement,
ChakraClipboard.IndicatorProps
>(function ClipboardCopyText(props, ref) {
return (
<ChakraClipboard.Indicator copied="Copied" {...props} ref={ref}>
Copy
</ChakraClipboard.Indicator>
)
})
export const ClipboardLabel = React.forwardRef<
HTMLLabelElement,
ChakraClipboard.LabelProps
>(function ClipboardLabel(props, ref) {
return (
<ChakraClipboard.Label
textStyle="sm"
fontWeight="medium"
display="inline-block"
mb="1"
{...props}
ref={ref}
/>
)
})
export const ClipboardButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
function ClipboardButton(props, ref) {
return (
<ChakraClipboard.Trigger asChild>
<Button ref={ref} size="sm" variant="surface" {...props}>
<ClipboardIcon />
<ClipboardCopyText />
</Button>
</ChakraClipboard.Trigger>
)
},
)
export const ClipboardLink = React.forwardRef<HTMLButtonElement, ButtonProps>(
function ClipboardLink(props, ref) {
return (
<ChakraClipboard.Trigger asChild>
<Button
unstyled
variant="plain"
size="xs"
display="inline-flex"
alignItems="center"
gap="2"
ref={ref}
{...props}
>
<LuLink />
<ClipboardCopyText />
</Button>
</ChakraClipboard.Trigger>
)
},
)
export const ClipboardIconButton = React.forwardRef<
HTMLButtonElement,
ButtonProps
>(function ClipboardIconButton(props, ref) {
return (
<ChakraClipboard.Trigger asChild>
<IconButton ref={ref} size="xs" variant="subtle" {...props}>
<ClipboardIcon />
<ClipboardCopyText srOnly />
</IconButton>
</ChakraClipboard.Trigger>
)
})
export const ClipboardInput = React.forwardRef<HTMLInputElement, InputProps>(
function ClipboardInputElement(props, ref) {
return (
<ChakraClipboard.Input asChild>
<Input ref={ref} {...props} />
</ChakraClipboard.Input>
)
},
)
export const ClipboardRoot = ChakraClipboard.Root

View File

@@ -1,17 +0,0 @@
import type { ButtonProps as ChakraCloseButtonProps } from "@chakra-ui/react"
import { IconButton as ChakraIconButton } from "@chakra-ui/react"
import * as React from "react"
import { LuX } from "react-icons/lu"
export interface CloseButtonProps extends ChakraCloseButtonProps {}
export const CloseButton = React.forwardRef<
HTMLButtonElement,
CloseButtonProps
>(function CloseButton(props, ref) {
return (
<ChakraIconButton variant="ghost" aria-label="Close" ref={ref} {...props}>
{props.children ?? <LuX />}
</ChakraIconButton>
)
})

View File

@@ -1,67 +0,0 @@
"use client"
import type { IconButtonProps } from "@chakra-ui/react"
import { ClientOnly, IconButton, Skeleton } from "@chakra-ui/react"
import { ThemeProvider, useTheme } from "next-themes"
import type { ThemeProviderProps } from "next-themes"
import * as React from "react"
import { LuMoon, LuSun } from "react-icons/lu"
export interface ColorModeProviderProps extends ThemeProviderProps {}
export function ColorModeProvider(props: ColorModeProviderProps) {
return (
<ThemeProvider attribute="class" disableTransitionOnChange {...props} />
)
}
export function useColorMode() {
const { resolvedTheme, setTheme } = useTheme()
const toggleColorMode = () => {
setTheme(resolvedTheme === "light" ? "dark" : "light")
}
return {
colorMode: resolvedTheme,
setColorMode: setTheme,
toggleColorMode,
}
}
export function useColorModeValue<T>(light: T, dark: T) {
const { colorMode } = useColorMode()
return colorMode === "light" ? light : dark
}
export function ColorModeIcon() {
const { colorMode } = useColorMode()
return colorMode === "light" ? <LuSun /> : <LuMoon />
}
interface ColorModeButtonProps extends Omit<IconButtonProps, "aria-label"> {}
export const ColorModeButton = React.forwardRef<
HTMLButtonElement,
ColorModeButtonProps
>(function ColorModeButton(props, ref) {
const { toggleColorMode } = useColorMode()
return (
<ClientOnly fallback={<Skeleton boxSize="8" />}>
<IconButton
onClick={toggleColorMode}
variant="ghost"
aria-label="Toggle color mode"
size="sm"
ref={ref}
{...props}
css={{
_icon: {
width: "5",
height: "5",
},
}}
>
<ColorModeIcon />
</IconButton>
</ClientOnly>
)
})

View File

@@ -1,30 +0,0 @@
import { DataList as ChakraDataList } from "@chakra-ui/react"
import { InfoTip } from "./toggle-tip"
import * as React from "react"
export const DataListRoot = ChakraDataList.Root
interface ItemProps extends ChakraDataList.ItemProps {
label: React.ReactNode
value: React.ReactNode
info?: React.ReactNode
grow?: boolean
}
export const DataListItem = React.forwardRef<HTMLDivElement, ItemProps>(
function DataListItem(props, ref) {
const { label, info, value, children, grow, ...rest } = props
return (
<ChakraDataList.Item ref={ref} {...rest}>
<ChakraDataList.ItemLabel flex={grow ? "1" : undefined}>
{label}
{info && <InfoTip>{info}</InfoTip>}
</ChakraDataList.ItemLabel>
<ChakraDataList.ItemValue flex={grow ? "1" : undefined}>
{value}
</ChakraDataList.ItemValue>
{children}
</ChakraDataList.Item>
)
},
)

View File

@@ -1,62 +0,0 @@
import { Dialog as ChakraDialog, Portal } from "@chakra-ui/react"
import { CloseButton } from "./close-button"
import * as React from "react"
interface DialogContentProps extends ChakraDialog.ContentProps {
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
backdrop?: boolean
}
export const DialogContent = React.forwardRef<
HTMLDivElement,
DialogContentProps
>(function DialogContent(props, ref) {
const {
children,
portalled = true,
portalRef,
backdrop = true,
...rest
} = props
return (
<Portal disabled={!portalled} container={portalRef}>
{backdrop && <ChakraDialog.Backdrop />}
<ChakraDialog.Positioner>
<ChakraDialog.Content ref={ref} {...rest} asChild={false}>
{children}
</ChakraDialog.Content>
</ChakraDialog.Positioner>
</Portal>
)
})
export const DialogCloseTrigger = React.forwardRef<
HTMLButtonElement,
ChakraDialog.CloseTriggerProps
>(function DialogCloseTrigger(props, ref) {
return (
<ChakraDialog.CloseTrigger
position="absolute"
top="2"
insetEnd="2"
{...props}
asChild
>
<CloseButton size="sm" ref={ref}>
{props.children}
</CloseButton>
</ChakraDialog.CloseTrigger>
)
})
export const DialogRoot = ChakraDialog.Root
export const DialogFooter = ChakraDialog.Footer
export const DialogHeader = ChakraDialog.Header
export const DialogBody = ChakraDialog.Body
export const DialogBackdrop = ChakraDialog.Backdrop
export const DialogTitle = ChakraDialog.Title
export const DialogDescription = ChakraDialog.Description
export const DialogTrigger = ChakraDialog.Trigger
export const DialogActionTrigger = ChakraDialog.ActionTrigger

View File

@@ -1,52 +0,0 @@
import { Drawer as ChakraDrawer, Portal } from "@chakra-ui/react"
import { CloseButton } from "./close-button"
import * as React from "react"
interface DrawerContentProps extends ChakraDrawer.ContentProps {
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
offset?: ChakraDrawer.ContentProps["padding"]
}
export const DrawerContent = React.forwardRef<
HTMLDivElement,
DrawerContentProps
>(function DrawerContent(props, ref) {
const { children, portalled = true, portalRef, offset, ...rest } = props
return (
<Portal disabled={!portalled} container={portalRef}>
<ChakraDrawer.Positioner padding={offset}>
<ChakraDrawer.Content ref={ref} {...rest} asChild={false}>
{children}
</ChakraDrawer.Content>
</ChakraDrawer.Positioner>
</Portal>
)
})
export const DrawerCloseTrigger = React.forwardRef<
HTMLButtonElement,
ChakraDrawer.CloseTriggerProps
>(function DrawerCloseTrigger(props, ref) {
return (
<ChakraDrawer.CloseTrigger
position="absolute"
top="2"
insetEnd="2"
{...props}
asChild
>
<CloseButton size="sm" ref={ref} />
</ChakraDrawer.CloseTrigger>
)
})
export const DrawerTrigger = ChakraDrawer.Trigger
export const DrawerRoot = ChakraDrawer.Root
export const DrawerFooter = ChakraDrawer.Footer
export const DrawerHeader = ChakraDrawer.Header
export const DrawerBody = ChakraDrawer.Body
export const DrawerBackdrop = ChakraDrawer.Backdrop
export const DrawerDescription = ChakraDrawer.Description
export const DrawerTitle = ChakraDrawer.Title
export const DrawerActionTrigger = ChakraDrawer.ActionTrigger

View File

@@ -1,34 +0,0 @@
import { EmptyState as ChakraEmptyState, VStack } from "@chakra-ui/react"
import * as React from "react"
export interface EmptyStateProps extends ChakraEmptyState.RootProps {
title: string
description?: string
icon?: React.ReactNode
}
export const EmptyState = React.forwardRef<HTMLDivElement, EmptyStateProps>(
function EmptyState(props, ref) {
const { title, description, icon, children, ...rest } = props
return (
<ChakraEmptyState.Root ref={ref} {...rest}>
<ChakraEmptyState.Content>
{icon && (
<ChakraEmptyState.Indicator>{icon}</ChakraEmptyState.Indicator>
)}
{description ? (
<VStack textAlign="center">
<ChakraEmptyState.Title>{title}</ChakraEmptyState.Title>
<ChakraEmptyState.Description>
{description}
</ChakraEmptyState.Description>
</VStack>
) : (
<ChakraEmptyState.Title>{title}</ChakraEmptyState.Title>
)}
{children}
</ChakraEmptyState.Content>
</ChakraEmptyState.Root>
)
},
)

View File

@@ -1,33 +0,0 @@
import { Field as ChakraField } from "@chakra-ui/react"
import * as React from "react"
export interface FieldProps extends Omit<ChakraField.RootProps, "label"> {
label?: React.ReactNode
helperText?: React.ReactNode
errorText?: React.ReactNode
optionalText?: React.ReactNode
}
export const Field = React.forwardRef<HTMLDivElement, FieldProps>(
function Field(props, ref) {
const { label, children, helperText, errorText, optionalText, ...rest } =
props
return (
<ChakraField.Root ref={ref} {...rest}>
{label && (
<ChakraField.Label>
{label}
<ChakraField.RequiredIndicator fallback={optionalText} />
</ChakraField.Label>
)}
{children}
{helperText && (
<ChakraField.HelperText>{helperText}</ChakraField.HelperText>
)}
{errorText && (
<ChakraField.ErrorText>{errorText}</ChakraField.ErrorText>
)}
</ChakraField.Root>
)
},
)

View File

@@ -1,170 +0,0 @@
"use client"
import type { ButtonProps, RecipeProps } from "@chakra-ui/react"
import {
Button,
FileUpload as ChakraFileUpload,
Icon,
IconButton,
Span,
Text,
useFileUploadContext,
useRecipe,
} from "@chakra-ui/react"
import * as React from "react"
import { LuFile, LuUpload, LuX } from "react-icons/lu"
export interface FileUploadRootProps extends ChakraFileUpload.RootProps {
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
}
export const FileUploadRoot = React.forwardRef<
HTMLInputElement,
FileUploadRootProps
>(function FileUploadRoot(props, ref) {
const { children, inputProps, ...rest } = props
return (
<ChakraFileUpload.Root {...rest}>
<ChakraFileUpload.HiddenInput ref={ref} {...inputProps} />
{children}
</ChakraFileUpload.Root>
)
})
export interface FileUploadDropzoneProps
extends ChakraFileUpload.DropzoneProps {
label: React.ReactNode
description?: React.ReactNode
}
export const FileUploadDropzone = React.forwardRef<
HTMLInputElement,
FileUploadDropzoneProps
>(function FileUploadDropzone(props, ref) {
const { children, label, description, ...rest } = props
return (
<ChakraFileUpload.Dropzone ref={ref} {...rest}>
<Icon fontSize="xl" color="fg.muted">
<LuUpload />
</Icon>
<ChakraFileUpload.DropzoneContent>
<div>{label}</div>
{description && <Text color="fg.muted">{description}</Text>}
</ChakraFileUpload.DropzoneContent>
{children}
</ChakraFileUpload.Dropzone>
)
})
interface VisibilityProps {
showSize?: boolean
clearable?: boolean
}
interface FileUploadItemProps extends VisibilityProps {
file: File
}
const FileUploadItem = React.forwardRef<HTMLLIElement, FileUploadItemProps>(
function FileUploadItem(props, ref) {
const { file, showSize, clearable } = props
return (
<ChakraFileUpload.Item file={file} ref={ref}>
<ChakraFileUpload.ItemPreview asChild>
<Icon fontSize="lg" color="fg.muted">
<LuFile />
</Icon>
</ChakraFileUpload.ItemPreview>
{showSize ? (
<ChakraFileUpload.ItemContent>
<ChakraFileUpload.ItemName />
<ChakraFileUpload.ItemSizeText />
</ChakraFileUpload.ItemContent>
) : (
<ChakraFileUpload.ItemName flex="1" />
)}
{clearable && (
<ChakraFileUpload.ItemDeleteTrigger asChild>
<IconButton variant="ghost" color="fg.muted" size="xs">
<LuX />
</IconButton>
</ChakraFileUpload.ItemDeleteTrigger>
)}
</ChakraFileUpload.Item>
)
},
)
interface FileUploadListProps
extends VisibilityProps,
ChakraFileUpload.ItemGroupProps {
files?: File[]
}
export const FileUploadList = React.forwardRef<
HTMLUListElement,
FileUploadListProps
>(function FileUploadList(props, ref) {
const { showSize, clearable, files, ...rest } = props
const fileUpload = useFileUploadContext()
const acceptedFiles = files ?? fileUpload.acceptedFiles
if (acceptedFiles.length === 0) return null
return (
<ChakraFileUpload.ItemGroup ref={ref} {...rest}>
{acceptedFiles.map((file) => (
<FileUploadItem
key={file.name}
file={file}
showSize={showSize}
clearable={clearable}
/>
))}
</ChakraFileUpload.ItemGroup>
)
})
type Assign<T, U> = Omit<T, keyof U> & U
interface FileInputProps extends Assign<ButtonProps, RecipeProps<"input">> {
placeholder?: React.ReactNode
}
export const FileInput = React.forwardRef<HTMLButtonElement, FileInputProps>(
function FileInput(props, ref) {
const inputRecipe = useRecipe({ key: "input" })
const [recipeProps, restProps] = inputRecipe.splitVariantProps(props)
const { placeholder = "Select file(s)", ...rest } = restProps
return (
<ChakraFileUpload.Trigger asChild>
<Button
unstyled
py="0"
ref={ref}
{...rest}
css={[inputRecipe(recipeProps), props.css]}
>
<ChakraFileUpload.Context>
{({ acceptedFiles }) => {
if (acceptedFiles.length === 1) {
return <span>{acceptedFiles[0].name}</span>
}
if (acceptedFiles.length > 1) {
return <span>{acceptedFiles.length} files</span>
}
return <Span color="fg.subtle">{placeholder}</Span>
}}
</ChakraFileUpload.Context>
</Button>
</ChakraFileUpload.Trigger>
)
},
)
export const FileUploadLabel = ChakraFileUpload.Label
export const FileUploadClearTrigger = ChakraFileUpload.ClearTrigger
export const FileUploadTrigger = ChakraFileUpload.Trigger

View File

@@ -1,36 +0,0 @@
import { HoverCard, Portal } from "@chakra-ui/react"
import * as React from "react"
interface HoverCardContentProps extends HoverCard.ContentProps {
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
}
export const HoverCardContent = React.forwardRef<
HTMLDivElement,
HoverCardContentProps
>(function HoverCardContent(props, ref) {
const { portalled = true, portalRef, ...rest } = props
return (
<Portal disabled={!portalled} container={portalRef}>
<HoverCard.Positioner>
<HoverCard.Content ref={ref} {...rest} />
</HoverCard.Positioner>
</Portal>
)
})
export const HoverCardArrow = React.forwardRef<
HTMLDivElement,
HoverCard.ArrowProps
>(function HoverCardArrow(props, ref) {
return (
<HoverCard.Arrow ref={ref} {...props}>
<HoverCard.ArrowTip />
</HoverCard.Arrow>
)
})
export const HoverCardRoot = HoverCard.Root
export const HoverCardTrigger = HoverCard.Trigger

View File

@@ -1,50 +0,0 @@
import type { BoxProps, InputElementProps } from "@chakra-ui/react"
import { Group, InputElement } from "@chakra-ui/react"
import * as React from "react"
export interface InputGroupProps extends BoxProps {
startElementProps?: InputElementProps
endElementProps?: InputElementProps
startElement?: React.ReactNode
endElement?: React.ReactNode
children: React.ReactElement
startOffset?: InputElementProps["paddingStart"]
endOffset?: InputElementProps["paddingEnd"]
}
export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
function InputGroup(props, ref) {
const {
startElement,
startElementProps,
endElement,
endElementProps,
children,
startOffset = "6px",
endOffset = "6px",
...rest
} = props
return (
<Group ref={ref} {...rest}>
{startElement && (
<InputElement pointerEvents="none" {...startElementProps}>
{startElement}
</InputElement>
)}
{React.cloneElement(children, {
...(startElement && {
ps: `calc(var(--input-height) - ${startOffset})`,
}),
...(endElement && { pe: `calc(var(--input-height) - ${endOffset})` }),
...children.props,
})}
{endElement && (
<InputElement placement="end" {...endElementProps}>
{endElement}
</InputElement>
)}
</Group>
)
},
)

View File

@@ -1,12 +0,0 @@
"use client"
import type { HTMLChakraProps, RecipeProps } from "@chakra-ui/react"
import { createRecipeContext } from "@chakra-ui/react"
export interface LinkButtonProps
extends HTMLChakraProps<"a", RecipeProps<"button">> {}
const { withContext } = createRecipeContext({ key: "button" })
// Replace "a" with your framework's link component
export const LinkButton = withContext<HTMLAnchorElement, LinkButtonProps>("a")

View File

@@ -1,110 +0,0 @@
"use client"
import { AbsoluteCenter, Menu as ChakraMenu, Portal } from "@chakra-ui/react"
import * as React from "react"
import { LuCheck, LuChevronRight } from "react-icons/lu"
interface MenuContentProps extends ChakraMenu.ContentProps {
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
}
export const MenuContent = React.forwardRef<HTMLDivElement, MenuContentProps>(
function MenuContent(props, ref) {
const { portalled = true, portalRef, ...rest } = props
return (
<Portal disabled={!portalled} container={portalRef}>
<ChakraMenu.Positioner>
<ChakraMenu.Content ref={ref} {...rest} />
</ChakraMenu.Positioner>
</Portal>
)
},
)
export const MenuArrow = React.forwardRef<
HTMLDivElement,
ChakraMenu.ArrowProps
>(function MenuArrow(props, ref) {
return (
<ChakraMenu.Arrow ref={ref} {...props}>
<ChakraMenu.ArrowTip />
</ChakraMenu.Arrow>
)
})
export const MenuCheckboxItem = React.forwardRef<
HTMLDivElement,
ChakraMenu.CheckboxItemProps
>(function MenuCheckboxItem(props, ref) {
return (
<ChakraMenu.CheckboxItem ref={ref} {...props}>
<ChakraMenu.ItemIndicator hidden={false}>
<LuCheck />
</ChakraMenu.ItemIndicator>
{props.children}
</ChakraMenu.CheckboxItem>
)
})
export const MenuRadioItem = React.forwardRef<
HTMLDivElement,
ChakraMenu.RadioItemProps
>(function MenuRadioItem(props, ref) {
const { children, ...rest } = props
return (
<ChakraMenu.RadioItem ps="8" ref={ref} {...rest}>
<AbsoluteCenter axis="horizontal" left="4" asChild>
<ChakraMenu.ItemIndicator>
<LuCheck />
</ChakraMenu.ItemIndicator>
</AbsoluteCenter>
<ChakraMenu.ItemText>{children}</ChakraMenu.ItemText>
</ChakraMenu.RadioItem>
)
})
export const MenuItemGroup = React.forwardRef<
HTMLDivElement,
ChakraMenu.ItemGroupProps
>(function MenuItemGroup(props, ref) {
const { title, children, ...rest } = props
return (
<ChakraMenu.ItemGroup ref={ref} {...rest}>
{title && (
<ChakraMenu.ItemGroupLabel userSelect="none">
{title}
</ChakraMenu.ItemGroupLabel>
)}
{children}
</ChakraMenu.ItemGroup>
)
})
export interface MenuTriggerItemProps extends ChakraMenu.ItemProps {
startIcon?: React.ReactNode
}
export const MenuTriggerItem = React.forwardRef<
HTMLDivElement,
MenuTriggerItemProps
>(function MenuTriggerItem(props, ref) {
const { startIcon, children, ...rest } = props
return (
<ChakraMenu.TriggerItem ref={ref} {...rest}>
{startIcon}
{children}
<LuChevronRight />
</ChakraMenu.TriggerItem>
)
})
export const MenuRadioItemGroup = ChakraMenu.RadioItemGroup
export const MenuContextTrigger = ChakraMenu.ContextTrigger
export const MenuRoot = ChakraMenu.Root
export const MenuSeparator = ChakraMenu.Separator
export const MenuItem = ChakraMenu.Item
export const MenuItemText = ChakraMenu.ItemText
export const MenuItemCommand = ChakraMenu.ItemCommand
export const MenuTrigger = ChakraMenu.Trigger

View File

@@ -1,57 +0,0 @@
"use client"
import { NativeSelect as Select } from "@chakra-ui/react"
import * as React from "react"
interface NativeSelectRootProps extends Select.RootProps {
icon?: React.ReactNode
}
export const NativeSelectRoot = React.forwardRef<
HTMLDivElement,
NativeSelectRootProps
>(function NativeSelect(props, ref) {
const { icon, children, ...rest } = props
return (
<Select.Root ref={ref} {...rest}>
{children}
<Select.Indicator>{icon}</Select.Indicator>
</Select.Root>
)
})
interface NativeSelectItem {
value: string
label: string
disabled?: boolean
}
interface NativeSelectField extends Select.FieldProps {
items?: Array<string | NativeSelectItem>
}
export const NativeSelectField = React.forwardRef<
HTMLSelectElement,
NativeSelectField
>(function NativeSelectField(props, ref) {
const { items: itemsProp, children, ...rest } = props
const items = React.useMemo(
() =>
itemsProp?.map((item) =>
typeof item === "string" ? { label: item, value: item } : item,
),
[itemsProp],
)
return (
<Select.Field ref={ref} {...rest}>
{children}
{items?.map((item) => (
<option key={item.value} value={item.value} disabled={item.disabled}>
{item.label}
</option>
))}
</Select.Field>
)
})

View File

@@ -1,24 +0,0 @@
import { NumberInput as ChakraNumberInput } from "@chakra-ui/react"
import * as React from "react"
export interface NumberInputProps extends ChakraNumberInput.RootProps {}
export const NumberInputRoot = React.forwardRef<
HTMLDivElement,
NumberInputProps
>(function NumberInput(props, ref) {
const { children, ...rest } = props
return (
<ChakraNumberInput.Root ref={ref} variant="outline" {...rest}>
{children}
<ChakraNumberInput.Control>
<ChakraNumberInput.IncrementTrigger />
<ChakraNumberInput.DecrementTrigger />
</ChakraNumberInput.Control>
</ChakraNumberInput.Root>
)
})
export const NumberInputField = ChakraNumberInput.Input
export const NumberInputScruber = ChakraNumberInput.Scrubber
export const NumberInputLabel = ChakraNumberInput.Label

View File

@@ -1,208 +0,0 @@
"use client"
import type { ButtonProps, TextProps } from "@chakra-ui/react"
import {
Button,
Pagination as ChakraPagination,
IconButton,
Text,
createContext,
usePaginationContext,
} from "@chakra-ui/react"
import * as React from "react"
import {
HiChevronLeft,
HiChevronRight,
HiMiniEllipsisHorizontal,
} from "react-icons/hi2"
import { LinkButton } from "./link-button"
interface ButtonVariantMap {
current: ButtonProps["variant"]
default: ButtonProps["variant"]
ellipsis: ButtonProps["variant"]
}
type PaginationVariant = "outline" | "solid" | "subtle"
interface ButtonVariantContext {
size: ButtonProps["size"]
variantMap: ButtonVariantMap
getHref?: (page: number) => string
}
const [RootPropsProvider, useRootProps] = createContext<ButtonVariantContext>({
name: "RootPropsProvider",
})
export interface PaginationRootProps
extends Omit<ChakraPagination.RootProps, "type"> {
size?: ButtonProps["size"]
variant?: PaginationVariant
getHref?: (page: number) => string
}
const variantMap: Record<PaginationVariant, ButtonVariantMap> = {
outline: { default: "ghost", ellipsis: "plain", current: "outline" },
solid: { default: "outline", ellipsis: "outline", current: "solid" },
subtle: { default: "ghost", ellipsis: "plain", current: "subtle" },
}
export const PaginationRoot = React.forwardRef<
HTMLDivElement,
PaginationRootProps
>(function PaginationRoot(props, ref) {
const { size = "sm", variant = "outline", getHref, ...rest } = props
return (
<RootPropsProvider
value={{ size, variantMap: variantMap[variant], getHref }}
>
<ChakraPagination.Root
ref={ref}
type={getHref ? "link" : "button"}
{...rest}
/>
</RootPropsProvider>
)
})
export const PaginationEllipsis = React.forwardRef<
HTMLDivElement,
ChakraPagination.EllipsisProps
>(function PaginationEllipsis(props, ref) {
const { size, variantMap } = useRootProps()
return (
<ChakraPagination.Ellipsis ref={ref} {...props} asChild>
<Button as="span" variant={variantMap.ellipsis} size={size}>
<HiMiniEllipsisHorizontal />
</Button>
</ChakraPagination.Ellipsis>
)
})
export const PaginationItem = React.forwardRef<
HTMLButtonElement,
ChakraPagination.ItemProps
>(function PaginationItem(props, ref) {
const { page } = usePaginationContext()
const { size, variantMap, getHref } = useRootProps()
const current = page === props.value
const variant = current ? variantMap.current : variantMap.default
if (getHref) {
return (
<LinkButton href={getHref(props.value)} variant={variant} size={size}>
{props.value}
</LinkButton>
)
}
return (
<ChakraPagination.Item ref={ref} {...props} asChild>
<Button variant={variant} size={size}>
{props.value}
</Button>
</ChakraPagination.Item>
)
})
export const PaginationPrevTrigger = React.forwardRef<
HTMLButtonElement,
ChakraPagination.PrevTriggerProps
>(function PaginationPrevTrigger(props, ref) {
const { size, variantMap, getHref } = useRootProps()
const { previousPage } = usePaginationContext()
if (getHref) {
return (
<LinkButton
href={previousPage != null ? getHref(previousPage) : undefined}
variant={variantMap.default}
size={size}
>
<HiChevronLeft />
</LinkButton>
)
}
return (
<ChakraPagination.PrevTrigger ref={ref} asChild {...props}>
<IconButton variant={variantMap.default} size={size}>
<HiChevronLeft />
</IconButton>
</ChakraPagination.PrevTrigger>
)
})
export const PaginationNextTrigger = React.forwardRef<
HTMLButtonElement,
ChakraPagination.NextTriggerProps
>(function PaginationNextTrigger(props, ref) {
const { size, variantMap, getHref } = useRootProps()
const { nextPage } = usePaginationContext()
if (getHref) {
return (
<LinkButton
href={nextPage != null ? getHref(nextPage) : undefined}
variant={variantMap.default}
size={size}
>
<HiChevronRight />
</LinkButton>
)
}
return (
<ChakraPagination.NextTrigger ref={ref} asChild {...props}>
<IconButton variant={variantMap.default} size={size}>
<HiChevronRight />
</IconButton>
</ChakraPagination.NextTrigger>
)
})
export const PaginationItems = (props: React.HTMLAttributes<HTMLElement>) => {
return (
<ChakraPagination.Context>
{({ pages }) =>
pages.map((page, index) => {
return page.type === "ellipsis" ? (
<PaginationEllipsis key={index} index={index} {...props} />
) : (
<PaginationItem
key={index}
type="page"
value={page.value}
{...props}
/>
)
})
}
</ChakraPagination.Context>
)
}
interface PageTextProps extends TextProps {
format?: "short" | "compact" | "long"
}
export const PaginationPageText = React.forwardRef<
HTMLParagraphElement,
PageTextProps
>(function PaginationPageText(props, ref) {
const { format = "compact", ...rest } = props
const { page, totalPages, pageRange, count } = usePaginationContext()
const content = React.useMemo(() => {
if (format === "short") return `${page} / ${totalPages}`
if (format === "compact") return `${page} of ${totalPages}`
return `${pageRange.start + 1} - ${pageRange.end} of ${count}`
}, [format, page, totalPages, pageRange, count])
return (
<Text fontWeight="medium" ref={ref} {...rest}>
{content}
</Text>
)
})

View File

@@ -1,148 +0,0 @@
"use client"
import type {
ButtonProps,
GroupProps,
InputProps,
StackProps,
} from "@chakra-ui/react"
import {
Box,
HStack,
IconButton,
Input,
Stack,
mergeRefs,
useControllableState,
} from "@chakra-ui/react"
import * as React from "react"
import { LuEye, LuEyeOff } from "react-icons/lu"
import { InputGroup } from "./input-group"
export interface PasswordVisibilityProps {
defaultVisible?: boolean
visible?: boolean
onVisibleChange?: (visible: boolean) => void
visibilityIcon?: { on: React.ReactNode; off: React.ReactNode }
}
export interface PasswordInputProps
extends InputProps,
PasswordVisibilityProps {
rootProps?: GroupProps
}
export const PasswordInput = React.forwardRef<
HTMLInputElement,
PasswordInputProps
>(function PasswordInput(props, ref) {
const {
rootProps,
defaultVisible,
visible: visibleProp,
onVisibleChange,
visibilityIcon = { on: <LuEye />, off: <LuEyeOff /> },
...rest
} = props
const [visible, setVisible] = useControllableState({
value: visibleProp,
defaultValue: defaultVisible || false,
onChange: onVisibleChange,
})
const inputRef = React.useRef<HTMLInputElement>(null)
return (
<InputGroup
width="full"
endElement={
<VisibilityTrigger
disabled={rest.disabled}
onPointerDown={(e) => {
if (rest.disabled) return
if (e.button !== 0) return
e.preventDefault()
setVisible(!visible)
}}
>
{visible ? visibilityIcon.off : visibilityIcon.on}
</VisibilityTrigger>
}
{...rootProps}
>
<Input
{...rest}
ref={mergeRefs(ref, inputRef)}
type={visible ? "text" : "password"}
/>
</InputGroup>
)
})
const VisibilityTrigger = React.forwardRef<HTMLButtonElement, ButtonProps>(
function VisibilityTrigger(props, ref) {
return (
<IconButton
tabIndex={-1}
ref={ref}
me="-2"
aspectRatio="square"
size="sm"
variant="ghost"
height="calc(100% - {spacing.2})"
aria-label="Toggle password visibility"
{...props}
/>
)
},
)
interface PasswordStrengthMeterProps extends StackProps {
max?: number
value: number
}
export const PasswordStrengthMeter = React.forwardRef<
HTMLDivElement,
PasswordStrengthMeterProps
>(function PasswordStrengthMeter(props, ref) {
const { max = 4, value, ...rest } = props
const percent = (value / max) * 100
const { label, colorPalette } = getColorPalette(percent)
return (
<Stack align="flex-end" gap="1" ref={ref} {...rest}>
<HStack width="full" ref={ref} {...rest}>
{Array.from({ length: max }).map((_, index) => (
<Box
key={index}
height="1"
flex="1"
rounded="sm"
data-selected={index < value ? "" : undefined}
layerStyle="fill.subtle"
colorPalette="gray"
_selected={{
colorPalette,
layerStyle: "fill.solid",
}}
/>
))}
</HStack>
{label && <HStack textStyle="xs">{label}</HStack>}
</Stack>
)
})
function getColorPalette(percent: number) {
switch (true) {
case percent < 33:
return { label: "Low", colorPalette: "red" }
case percent < 66:
return { label: "Medium", colorPalette: "orange" }
default:
return { label: "High", colorPalette: "green" }
}
}

View File

@@ -1,27 +0,0 @@
import { PinInput as ChakraPinInput, Group } from "@chakra-ui/react"
import * as React from "react"
export interface PinInputProps extends ChakraPinInput.RootProps {
rootRef?: React.Ref<HTMLDivElement>
count?: number
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
attached?: boolean
}
export const PinInput = React.forwardRef<HTMLInputElement, PinInputProps>(
function PinInput(props, ref) {
const { count = 4, inputProps, rootRef, attached, ...rest } = props
return (
<ChakraPinInput.Root ref={rootRef} {...rest}>
<ChakraPinInput.HiddenInput ref={ref} {...inputProps} />
<ChakraPinInput.Control>
<Group attached={attached}>
{Array.from({ length: count }).map((_, index) => (
<ChakraPinInput.Input key={index} index={index} />
))}
</Group>
</ChakraPinInput.Control>
</ChakraPinInput.Root>
)
},
)

View File

@@ -1,59 +0,0 @@
import { Popover as ChakraPopover, Portal } from "@chakra-ui/react"
import { CloseButton } from "./close-button"
import * as React from "react"
interface PopoverContentProps extends ChakraPopover.ContentProps {
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
}
export const PopoverContent = React.forwardRef<
HTMLDivElement,
PopoverContentProps
>(function PopoverContent(props, ref) {
const { portalled = true, portalRef, ...rest } = props
return (
<Portal disabled={!portalled} container={portalRef}>
<ChakraPopover.Positioner>
<ChakraPopover.Content ref={ref} {...rest} />
</ChakraPopover.Positioner>
</Portal>
)
})
export const PopoverArrow = React.forwardRef<
HTMLDivElement,
ChakraPopover.ArrowProps
>(function PopoverArrow(props, ref) {
return (
<ChakraPopover.Arrow {...props} ref={ref}>
<ChakraPopover.ArrowTip />
</ChakraPopover.Arrow>
)
})
export const PopoverCloseTrigger = React.forwardRef<
HTMLButtonElement,
ChakraPopover.CloseTriggerProps
>(function PopoverCloseTrigger(props, ref) {
return (
<ChakraPopover.CloseTrigger
position="absolute"
top="1"
insetEnd="1"
{...props}
asChild
ref={ref}
>
<CloseButton size="sm" />
</ChakraPopover.CloseTrigger>
)
})
export const PopoverTitle = ChakraPopover.Title
export const PopoverDescription = ChakraPopover.Description
export const PopoverFooter = ChakraPopover.Footer
export const PopoverHeader = ChakraPopover.Header
export const PopoverRoot = ChakraPopover.Root
export const PopoverBody = ChakraPopover.Body
export const PopoverTrigger = ChakraPopover.Trigger

View File

@@ -1,37 +0,0 @@
import type { SystemStyleObject } from "@chakra-ui/react"
import {
AbsoluteCenter,
ProgressCircle as ChakraProgressCircle,
} from "@chakra-ui/react"
import * as React from "react"
interface ProgressCircleRingProps extends ChakraProgressCircle.CircleProps {
trackColor?: SystemStyleObject["stroke"]
cap?: SystemStyleObject["strokeLinecap"]
}
export const ProgressCircleRing = React.forwardRef<
SVGSVGElement,
ProgressCircleRingProps
>(function ProgressCircleRing(props, ref) {
const { trackColor, cap, color, ...rest } = props
return (
<ChakraProgressCircle.Circle {...rest} ref={ref}>
<ChakraProgressCircle.Track stroke={trackColor} />
<ChakraProgressCircle.Range stroke={color} strokeLinecap={cap} />
</ChakraProgressCircle.Circle>
)
})
export const ProgressCircleValueText = React.forwardRef<
HTMLDivElement,
ChakraProgressCircle.ValueTextProps
>(function ProgressCircleValueText(props, ref) {
return (
<AbsoluteCenter>
<ChakraProgressCircle.ValueText {...props} ref={ref} />
</AbsoluteCenter>
)
})
export const ProgressCircleRoot = ChakraProgressCircle.Root

View File

@@ -1,34 +0,0 @@
import { Progress as ChakraProgress } from "@chakra-ui/react"
import { InfoTip } from "./toggle-tip"
import * as React from "react"
export const ProgressBar = React.forwardRef<
HTMLDivElement,
ChakraProgress.TrackProps
>(function ProgressBar(props, ref) {
return (
<ChakraProgress.Track {...props} ref={ref}>
<ChakraProgress.Range />
</ChakraProgress.Track>
)
})
export interface ProgressLabelProps extends ChakraProgress.LabelProps {
info?: React.ReactNode
}
export const ProgressLabel = React.forwardRef<
HTMLDivElement,
ProgressLabelProps
>(function ProgressLabel(props, ref) {
const { children, info, ...rest } = props
return (
<ChakraProgress.Label {...rest} ref={ref}>
{children}
{info && <InfoTip>{info}</InfoTip>}
</ChakraProgress.Label>
)
})
export const ProgressRoot = ChakraProgress.Root
export const ProgressValueText = ChakraProgress.ValueText

View File

@@ -1,264 +0,0 @@
"use client"
import { chakra } from "@chakra-ui/react"
export const Prose = chakra("div", {
base: {
color: "fg.muted",
maxWidth: "65ch",
fontSize: "sm",
lineHeight: "1.7em",
"& p": {
marginTop: "1em",
marginBottom: "1em",
},
"& blockquote": {
marginTop: "1.285em",
marginBottom: "1.285em",
paddingInline: "1.285em",
borderInlineStartWidth: "0.25em",
},
"& a": {
color: "fg",
textDecoration: "underline",
textUnderlineOffset: "3px",
textDecorationThickness: "2px",
textDecorationColor: "border.muted",
fontWeight: "500",
},
"& strong": {
fontWeight: "600",
},
"& a strong": {
color: "inherit",
},
"& h1": {
fontSize: "2.15em",
letterSpacing: "-0.02em",
marginTop: "0",
marginBottom: "0.8em",
lineHeight: "1.2em",
},
"& h2": {
fontSize: "1.4em",
letterSpacing: "-0.02em",
marginTop: "1.6em",
marginBottom: "0.8em",
lineHeight: "1.4em",
},
"& h3": {
fontSize: "1.285em",
letterSpacing: "-0.01em",
marginTop: "1.5em",
marginBottom: "0.4em",
lineHeight: "1.5em",
},
"& h4": {
marginTop: "1.4em",
marginBottom: "0.5em",
letterSpacing: "-0.01em",
lineHeight: "1.5em",
},
"& img": {
marginTop: "1.7em",
marginBottom: "1.7em",
borderRadius: "lg",
boxShadow: "inset",
},
"& picture": {
marginTop: "1.7em",
marginBottom: "1.7em",
},
"& picture > img": {
marginTop: "0",
marginBottom: "0",
},
"& video": {
marginTop: "1.7em",
marginBottom: "1.7em",
},
"& kbd": {
fontSize: "0.85em",
borderRadius: "xs",
paddingTop: "0.15em",
paddingBottom: "0.15em",
paddingInlineEnd: "0.35em",
paddingInlineStart: "0.35em",
fontFamily: "inherit",
color: "fg.muted",
"--shadow": "colors.border",
boxShadow: "0 0 0 1px var(--shadow),0 1px 0 1px var(--shadow)",
},
"& code": {
fontSize: "0.925em",
letterSpacing: "-0.01em",
borderRadius: "md",
borderWidth: "1px",
padding: "0.25em",
},
"& pre code": {
fontSize: "inherit",
letterSpacing: "inherit",
borderWidth: "inherit",
padding: "0",
},
"& h2 code": {
fontSize: "0.9em",
},
"& h3 code": {
fontSize: "0.8em",
},
"& pre": {
backgroundColor: "bg.subtle",
marginTop: "1.6em",
marginBottom: "1.6em",
borderRadius: "md",
fontSize: "0.9em",
paddingTop: "0.65em",
paddingBottom: "0.65em",
paddingInlineEnd: "1em",
paddingInlineStart: "1em",
overflowX: "auto",
fontWeight: "400",
},
"& ol": {
marginTop: "1em",
marginBottom: "1em",
paddingInlineStart: "1.5em",
},
"& ul": {
marginTop: "1em",
marginBottom: "1em",
paddingInlineStart: "1.5em",
},
"& li": {
marginTop: "0.285em",
marginBottom: "0.285em",
},
"& ol > li": {
paddingInlineStart: "0.4em",
listStyleType: "decimal",
"&::marker": {
color: "fg.muted",
},
},
"& ul > li": {
paddingInlineStart: "0.4em",
listStyleType: "disc",
"&::marker": {
color: "fg.muted",
},
},
"& > ul > li p": {
marginTop: "0.5em",
marginBottom: "0.5em",
},
"& > ul > li > p:first-of-type": {
marginTop: "1em",
},
"& > ul > li > p:last-of-type": {
marginBottom: "1em",
},
"& > ol > li > p:first-of-type": {
marginTop: "1em",
},
"& > ol > li > p:last-of-type": {
marginBottom: "1em",
},
"& ul ul, ul ol, ol ul, ol ol": {
marginTop: "0.5em",
marginBottom: "0.5em",
},
"& dl": {
marginTop: "1em",
marginBottom: "1em",
},
"& dt": {
fontWeight: "600",
marginTop: "1em",
},
"& dd": {
marginTop: "0.285em",
paddingInlineStart: "1.5em",
},
"& hr": {
marginTop: "2.25em",
marginBottom: "2.25em",
},
"& :is(h1,h2,h3,h4,h5,hr) + *": {
marginTop: "0",
},
"& table": {
width: "100%",
tableLayout: "auto",
textAlign: "start",
lineHeight: "1.5em",
marginTop: "2em",
marginBottom: "2em",
},
"& thead": {
borderBottomWidth: "1px",
color: "fg",
},
"& tbody tr": {
borderBottomWidth: "1px",
borderBottomColor: "border",
},
"& thead th": {
paddingInlineEnd: "1em",
paddingBottom: "0.65em",
paddingInlineStart: "1em",
fontWeight: "medium",
textAlign: "start",
},
"& thead th:first-of-type": {
paddingInlineStart: "0",
},
"& thead th:last-of-type": {
paddingInlineEnd: "0",
},
"& tbody td, tfoot td": {
paddingTop: "0.65em",
paddingInlineEnd: "1em",
paddingBottom: "0.65em",
paddingInlineStart: "1em",
},
"& tbody td:first-of-type, tfoot td:first-of-type": {
paddingInlineStart: "0",
},
"& tbody td:last-of-type, tfoot td:last-of-type": {
paddingInlineEnd: "0",
},
"& figure": {
marginTop: "1.625em",
marginBottom: "1.625em",
},
"& figure > *": {
marginTop: "0",
marginBottom: "0",
},
"& figcaption": {
fontSize: "0.85em",
lineHeight: "1.25em",
marginTop: "0.85em",
color: "fg.muted",
},
"& h1, h2, h3, h4": {
color: "fg",
fontWeight: "600",
},
},
variants: {
size: {
md: {
fontSize: "sm",
},
lg: {
fontSize: "md",
},
},
},
defaultVariants: {
size: "md",
},
})

View File

@@ -1,15 +0,0 @@
"use client"
import { ChakraProvider, defaultSystem } from "@chakra-ui/react"
import {
ColorModeProvider,
type ColorModeProviderProps,
} from "./color-mode"
export function Provider(props: ColorModeProviderProps) {
return (
<ChakraProvider value={defaultSystem}>
<ColorModeProvider {...props} />
</ChakraProvider>
)
}

View File

@@ -1,58 +0,0 @@
import { RadioCard } from "@chakra-ui/react"
import * as React from "react"
interface RadioCardItemProps extends RadioCard.ItemProps {
icon?: React.ReactElement
label?: React.ReactNode
description?: React.ReactNode
addon?: React.ReactNode
indicator?: React.ReactNode | null
indicatorPlacement?: "start" | "end" | "inside"
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
}
export const RadioCardItem = React.forwardRef<
HTMLInputElement,
RadioCardItemProps
>(function RadioCardItem(props, ref) {
const {
inputProps,
label,
description,
addon,
icon,
indicator = <RadioCard.ItemIndicator />,
indicatorPlacement = "end",
...rest
} = props
const hasContent = label || description || icon
const ContentWrapper = indicator ? RadioCard.ItemContent : React.Fragment
return (
<RadioCard.Item {...rest}>
<RadioCard.ItemHiddenInput ref={ref} {...inputProps} />
<RadioCard.ItemControl>
{indicatorPlacement === "start" && indicator}
{hasContent && (
<ContentWrapper>
{icon}
{label && <RadioCard.ItemText>{label}</RadioCard.ItemText>}
{description && (
<RadioCard.ItemDescription>
{description}
</RadioCard.ItemDescription>
)}
{indicatorPlacement === "inside" && indicator}
</ContentWrapper>
)}
{indicatorPlacement === "end" && indicator}
</RadioCard.ItemControl>
{addon && <RadioCard.ItemAddon>{addon}</RadioCard.ItemAddon>}
</RadioCard.Item>
)
})
export const RadioCardRoot = RadioCard.Root
export const RadioCardLabel = RadioCard.Label
export const RadioCardItemIndicator = RadioCard.ItemIndicator

View File

@@ -1,24 +0,0 @@
import { RadioGroup as ChakraRadioGroup } from "@chakra-ui/react"
import * as React from "react"
export interface RadioProps extends ChakraRadioGroup.ItemProps {
rootRef?: React.Ref<HTMLDivElement>
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
}
export const Radio = React.forwardRef<HTMLInputElement, RadioProps>(
function Radio(props, ref) {
const { children, inputProps, rootRef, ...rest } = props
return (
<ChakraRadioGroup.Item ref={rootRef} {...rest}>
<ChakraRadioGroup.ItemHiddenInput ref={ref} {...inputProps} />
<ChakraRadioGroup.ItemIndicator />
{children && (
<ChakraRadioGroup.ItemText>{children}</ChakraRadioGroup.ItemText>
)}
</ChakraRadioGroup.Item>
)
},
)
export const RadioGroup = ChakraRadioGroup.Root

View File

@@ -1,27 +0,0 @@
import { RatingGroup } from "@chakra-ui/react"
import * as React from "react"
export interface RatingProps extends RatingGroup.RootProps {
icon?: React.ReactElement
count?: number
label?: React.ReactNode
}
export const Rating = React.forwardRef<HTMLDivElement, RatingProps>(
function Rating(props, ref) {
const { icon, count = 5, label, ...rest } = props
return (
<RatingGroup.Root ref={ref} count={count} {...rest}>
{label && <RatingGroup.Label>{label}</RatingGroup.Label>}
<RatingGroup.HiddenInput />
<RatingGroup.Control>
{Array.from({ length: count }).map((_, index) => (
<RatingGroup.Item key={index} index={index + 1}>
<RatingGroup.ItemIndicator icon={icon} />
</RatingGroup.Item>
))}
</RatingGroup.Control>
</RatingGroup.Root>
)
},
)

View File

@@ -1,47 +0,0 @@
"use client"
import { For, SegmentGroup } from "@chakra-ui/react"
import * as React from "react"
interface Item {
value: string
label: React.ReactNode
disabled?: boolean
}
export interface SegmentedControlProps extends SegmentGroup.RootProps {
items: Array<string | Item>
}
function normalize(items: Array<string | Item>): Item[] {
return items.map((item) => {
if (typeof item === "string") return { value: item, label: item }
return item
})
}
export const SegmentedControl = React.forwardRef<
HTMLDivElement,
SegmentedControlProps
>(function SegmentedControl(props, ref) {
const { items, ...rest } = props
const data = React.useMemo(() => normalize(items), [items])
return (
<SegmentGroup.Root ref={ref} {...rest}>
<SegmentGroup.Indicator />
<For each={data}>
{(item) => (
<SegmentGroup.Item
key={item.value}
value={item.value}
disabled={item.disabled}
>
<SegmentGroup.ItemText>{item.label}</SegmentGroup.ItemText>
<SegmentGroup.ItemHiddenInput />
</SegmentGroup.Item>
)}
</For>
</SegmentGroup.Root>
)
})

View File

@@ -1,143 +0,0 @@
"use client"
import type { CollectionItem } from "@chakra-ui/react"
import { Select as ChakraSelect, Portal } from "@chakra-ui/react"
import { CloseButton } from "./close-button"
import * as React from "react"
interface SelectTriggerProps extends ChakraSelect.ControlProps {
clearable?: boolean
}
export const SelectTrigger = React.forwardRef<
HTMLButtonElement,
SelectTriggerProps
>(function SelectTrigger(props, ref) {
const { children, clearable, ...rest } = props
return (
<ChakraSelect.Control {...rest}>
<ChakraSelect.Trigger ref={ref}>{children}</ChakraSelect.Trigger>
<ChakraSelect.IndicatorGroup>
{clearable && <SelectClearTrigger />}
<ChakraSelect.Indicator />
</ChakraSelect.IndicatorGroup>
</ChakraSelect.Control>
)
})
const SelectClearTrigger = React.forwardRef<
HTMLButtonElement,
ChakraSelect.ClearTriggerProps
>(function SelectClearTrigger(props, ref) {
return (
<ChakraSelect.ClearTrigger asChild {...props} ref={ref}>
<CloseButton
size="xs"
variant="plain"
focusVisibleRing="inside"
focusRingWidth="2px"
pointerEvents="auto"
/>
</ChakraSelect.ClearTrigger>
)
})
interface SelectContentProps extends ChakraSelect.ContentProps {
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
}
export const SelectContent = React.forwardRef<
HTMLDivElement,
SelectContentProps
>(function SelectContent(props, ref) {
const { portalled = true, portalRef, ...rest } = props
return (
<Portal disabled={!portalled} container={portalRef}>
<ChakraSelect.Positioner>
<ChakraSelect.Content {...rest} ref={ref} />
</ChakraSelect.Positioner>
</Portal>
)
})
export const SelectItem = React.forwardRef<
HTMLDivElement,
ChakraSelect.ItemProps
>(function SelectItem(props, ref) {
const { item, children, ...rest } = props
return (
<ChakraSelect.Item key={item.value} item={item} {...rest} ref={ref}>
{children}
<ChakraSelect.ItemIndicator />
</ChakraSelect.Item>
)
})
interface SelectValueTextProps
extends Omit<ChakraSelect.ValueTextProps, "children"> {
children?(items: CollectionItem[]): React.ReactNode
}
export const SelectValueText = React.forwardRef<
HTMLSpanElement,
SelectValueTextProps
>(function SelectValueText(props, ref) {
const { children, ...rest } = props
return (
<ChakraSelect.ValueText {...rest} ref={ref}>
<ChakraSelect.Context>
{(select) => {
const items = select.selectedItems
if (items.length === 0) return props.placeholder
if (children) return children(items)
if (items.length === 1)
return select.collection.stringifyItem(items[0])
return `${items.length} selected`
}}
</ChakraSelect.Context>
</ChakraSelect.ValueText>
)
})
export const SelectRoot = React.forwardRef<
HTMLDivElement,
ChakraSelect.RootProps
>(function SelectRoot(props, ref) {
return (
<ChakraSelect.Root
{...props}
ref={ref}
positioning={{ sameWidth: true, ...props.positioning }}
>
{props.asChild ? (
props.children
) : (
<>
<ChakraSelect.HiddenSelect />
{props.children}
</>
)}
</ChakraSelect.Root>
)
}) as ChakraSelect.RootComponent
interface SelectItemGroupProps extends ChakraSelect.ItemGroupProps {
label: React.ReactNode
}
export const SelectItemGroup = React.forwardRef<
HTMLDivElement,
SelectItemGroupProps
>(function SelectItemGroup(props, ref) {
const { children, label, ...rest } = props
return (
<ChakraSelect.ItemGroup {...rest} ref={ref}>
<ChakraSelect.ItemGroupLabel>{label}</ChakraSelect.ItemGroupLabel>
{children}
</ChakraSelect.ItemGroup>
)
})
export const SelectLabel = ChakraSelect.Label
export const SelectItemText = ChakraSelect.ItemText

View File

@@ -1,47 +0,0 @@
import type {
SkeletonProps as ChakraSkeletonProps,
CircleProps,
} from "@chakra-ui/react"
import { Skeleton as ChakraSkeleton, Circle, Stack } from "@chakra-ui/react"
import * as React from "react"
export interface SkeletonCircleProps extends ChakraSkeletonProps {
size?: CircleProps["size"]
}
export const SkeletonCircle = React.forwardRef<
HTMLDivElement,
SkeletonCircleProps
>(function SkeletonCircle(props, ref) {
const { size, ...rest } = props
return (
<Circle size={size} asChild ref={ref}>
<ChakraSkeleton {...rest} />
</Circle>
)
})
export interface SkeletonTextProps extends ChakraSkeletonProps {
noOfLines?: number
}
export const SkeletonText = React.forwardRef<HTMLDivElement, SkeletonTextProps>(
function SkeletonText(props, ref) {
const { noOfLines = 3, gap, ...rest } = props
return (
<Stack gap={gap} width="full" ref={ref}>
{Array.from({ length: noOfLines }).map((_, index) => (
<ChakraSkeleton
height="4"
key={index}
{...props}
_last={{ maxW: "80%" }}
{...rest}
/>
))}
</Stack>
)
},
)
export const Skeleton = ChakraSkeleton

View File

@@ -1,60 +0,0 @@
import { Slider as ChakraSlider, HStack } from "@chakra-ui/react"
import * as React from "react"
export interface SliderProps extends ChakraSlider.RootProps {
marks?: Array<number | { value: number; label: React.ReactNode }>
label?: React.ReactNode
showValue?: boolean
}
export const Slider = React.forwardRef<HTMLDivElement, SliderProps>(
function Slider(props, ref) {
const { marks: marksProp, label, showValue, ...rest } = props
const value = props.defaultValue ?? props.value
const marks = marksProp?.map((mark) => {
if (typeof mark === "number") return { value: mark, label: undefined }
return mark
})
const hasMarkLabel = !!marks?.some((mark) => mark.label)
return (
<ChakraSlider.Root ref={ref} thumbAlignment="center" {...rest}>
{label && !showValue && (
<ChakraSlider.Label fontWeight="medium">{label}</ChakraSlider.Label>
)}
{label && showValue && (
<HStack justify="space-between">
<ChakraSlider.Label fontWeight="medium">{label}</ChakraSlider.Label>
<ChakraSlider.ValueText />
</HStack>
)}
<ChakraSlider.Control mb={hasMarkLabel ? "4" : undefined}>
<ChakraSlider.Track>
<ChakraSlider.Range />
</ChakraSlider.Track>
{value?.map((_, index) => (
<ChakraSlider.Thumb key={index} index={index}>
<ChakraSlider.HiddenInput />
</ChakraSlider.Thumb>
))}
</ChakraSlider.Control>
{marks?.length && (
<ChakraSlider.MarkerGroup>
{marks.map((mark, index) => {
const value = typeof mark === "number" ? mark : mark.value
const label = typeof mark === "number" ? undefined : mark.label
return (
<ChakraSlider.Marker key={index} value={value}>
<ChakraSlider.MarkerIndicator />
{label}
</ChakraSlider.Marker>
)
})}
</ChakraSlider.MarkerGroup>
)}
</ChakraSlider.Root>
)
},
)

View File

@@ -1,68 +0,0 @@
import {
Badge,
type BadgeProps,
Stat as ChakraStat,
FormatNumber,
} from "@chakra-ui/react"
import { InfoTip } from "./toggle-tip"
import * as React from "react"
interface StatLabelProps extends ChakraStat.LabelProps {
info?: React.ReactNode
}
export const StatLabel = React.forwardRef<HTMLDivElement, StatLabelProps>(
function StatLabel(props, ref) {
const { info, children, ...rest } = props
return (
<ChakraStat.Label {...rest} ref={ref}>
{children}
{info && <InfoTip>{info}</InfoTip>}
</ChakraStat.Label>
)
},
)
interface StatValueTextProps extends ChakraStat.ValueTextProps {
value?: number
formatOptions?: Intl.NumberFormatOptions
}
export const StatValueText = React.forwardRef<
HTMLDivElement,
StatValueTextProps
>(function StatValueText(props, ref) {
const { value, formatOptions, children, ...rest } = props
return (
<ChakraStat.ValueText {...rest} ref={ref}>
{children ||
(value != null && <FormatNumber value={value} {...formatOptions} />)}
</ChakraStat.ValueText>
)
})
export const StatUpTrend = React.forwardRef<HTMLDivElement, BadgeProps>(
function StatUpTrend(props, ref) {
return (
<Badge colorPalette="green" gap="0" {...props} ref={ref}>
<ChakraStat.UpIndicator />
{props.children}
</Badge>
)
},
)
export const StatDownTrend = React.forwardRef<HTMLDivElement, BadgeProps>(
function StatDownTrend(props, ref) {
return (
<Badge colorPalette="red" gap="0" {...props} ref={ref}>
<ChakraStat.DownIndicator />
{props.children}
</Badge>
)
},
)
export const StatRoot = ChakraStat.Root
export const StatHelpText = ChakraStat.HelpText
export const StatValueUnit = ChakraStat.ValueUnit

View File

@@ -1,29 +0,0 @@
import type { ColorPalette } from "@chakra-ui/react"
import { Status as ChakraStatus } from "@chakra-ui/react"
import * as React from "react"
type StatusValue = "success" | "error" | "warning" | "info"
export interface StatusProps extends ChakraStatus.RootProps {
value?: StatusValue
}
const statusMap: Record<StatusValue, ColorPalette> = {
success: "green",
error: "red",
warning: "orange",
info: "blue",
}
export const Status = React.forwardRef<HTMLDivElement, StatusProps>(
function Status(props, ref) {
const { children, value = "info", ...rest } = props
const colorPalette = rest.colorPalette ?? statusMap[value]
return (
<ChakraStatus.Root ref={ref} {...rest} colorPalette={colorPalette}>
<ChakraStatus.Indicator />
{children}
</ChakraStatus.Root>
)
},
)

View File

@@ -1,49 +0,0 @@
import { HStack, IconButton, NumberInput } from "@chakra-ui/react"
import * as React from "react"
import { LuMinus, LuPlus } from "react-icons/lu"
export interface StepperInputProps extends NumberInput.RootProps {
label?: React.ReactNode
}
export const StepperInput = React.forwardRef<HTMLDivElement, StepperInputProps>(
function StepperInput(props, ref) {
const { label, ...rest } = props
return (
<NumberInput.Root {...rest} unstyled ref={ref}>
{label && <NumberInput.Label>{label}</NumberInput.Label>}
<HStack gap="2">
<DecrementTrigger />
<NumberInput.ValueText textAlign="center" fontSize="lg" minW="3ch" />
<IncrementTrigger />
</HStack>
</NumberInput.Root>
)
},
)
const DecrementTrigger = React.forwardRef<
HTMLButtonElement,
NumberInput.DecrementTriggerProps
>(function DecrementTrigger(props, ref) {
return (
<NumberInput.DecrementTrigger {...props} asChild ref={ref}>
<IconButton variant="outline" size="sm">
<LuMinus />
</IconButton>
</NumberInput.DecrementTrigger>
)
})
const IncrementTrigger = React.forwardRef<
HTMLButtonElement,
NumberInput.IncrementTriggerProps
>(function IncrementTrigger(props, ref) {
return (
<NumberInput.IncrementTrigger {...props} asChild ref={ref}>
<IconButton variant="outline" size="sm">
<LuPlus />
</IconButton>
</NumberInput.IncrementTrigger>
)
})

View File

@@ -1,82 +0,0 @@
import { Box, Steps as ChakraSteps } from "@chakra-ui/react"
import * as React from "react"
import { LuCheck } from "react-icons/lu"
interface StepInfoProps {
title?: React.ReactNode
description?: React.ReactNode
}
export interface StepsItemProps
extends Omit<ChakraSteps.ItemProps, "title">,
StepInfoProps {
completedIcon?: React.ReactNode
icon?: React.ReactNode
}
export const StepsItem = React.forwardRef<HTMLDivElement, StepsItemProps>(
function StepsItem(props, ref) {
const { title, description, completedIcon, icon, ...rest } = props
return (
<ChakraSteps.Item {...rest} ref={ref}>
<ChakraSteps.Trigger>
<ChakraSteps.Indicator>
<ChakraSteps.Status
complete={completedIcon || <LuCheck />}
incomplete={icon || <ChakraSteps.Number />}
/>
</ChakraSteps.Indicator>
<StepInfo title={title} description={description} />
</ChakraSteps.Trigger>
<ChakraSteps.Separator />
</ChakraSteps.Item>
)
},
)
const StepInfo = (props: StepInfoProps) => {
const { title, description } = props
if (title && description) {
return (
<Box>
<ChakraSteps.Title>{title}</ChakraSteps.Title>
<ChakraSteps.Description>{description}</ChakraSteps.Description>
</Box>
)
}
return (
<>
{title && <ChakraSteps.Title>{title}</ChakraSteps.Title>}
{description && (
<ChakraSteps.Description>{description}</ChakraSteps.Description>
)}
</>
)
}
interface StepsIndicatorProps {
completedIcon: React.ReactNode
icon?: React.ReactNode
}
export const StepsIndicator = React.forwardRef<
HTMLDivElement,
StepsIndicatorProps
>(function StepsIndicator(props, ref) {
const { icon = <ChakraSteps.Number />, completedIcon } = props
return (
<ChakraSteps.Indicator ref={ref}>
<ChakraSteps.Status complete={completedIcon} incomplete={icon} />
</ChakraSteps.Indicator>
)
})
export const StepsList = ChakraSteps.List
export const StepsRoot = ChakraSteps.Root
export const StepsContent = ChakraSteps.Content
export const StepsCompletedContent = ChakraSteps.CompletedContent
export const StepsNextTrigger = ChakraSteps.NextTrigger
export const StepsPrevTrigger = ChakraSteps.PrevTrigger

View File

@@ -1,39 +0,0 @@
import { Switch as ChakraSwitch } from "@chakra-ui/react"
import * as React from "react"
export interface SwitchProps extends ChakraSwitch.RootProps {
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
rootRef?: React.Ref<HTMLLabelElement>
trackLabel?: { on: React.ReactNode; off: React.ReactNode }
thumbLabel?: { on: React.ReactNode; off: React.ReactNode }
}
export const Switch = React.forwardRef<HTMLInputElement, SwitchProps>(
function Switch(props, ref) {
const { inputProps, children, rootRef, trackLabel, thumbLabel, ...rest } =
props
return (
<ChakraSwitch.Root ref={rootRef} {...rest}>
<ChakraSwitch.HiddenInput ref={ref} {...inputProps} />
<ChakraSwitch.Control>
<ChakraSwitch.Thumb>
{thumbLabel && (
<ChakraSwitch.ThumbIndicator fallback={thumbLabel?.off}>
{thumbLabel?.on}
</ChakraSwitch.ThumbIndicator>
)}
</ChakraSwitch.Thumb>
{trackLabel && (
<ChakraSwitch.Indicator fallback={trackLabel.off}>
{trackLabel.on}
</ChakraSwitch.Indicator>
)}
</ChakraSwitch.Control>
{children != null && (
<ChakraSwitch.Label>{children}</ChakraSwitch.Label>
)}
</ChakraSwitch.Root>
)
},
)

View File

@@ -1,39 +0,0 @@
import { Tag as ChakraTag } from "@chakra-ui/react"
import * as React from "react"
export interface TagProps extends ChakraTag.RootProps {
startElement?: React.ReactNode
endElement?: React.ReactNode
onClose?: VoidFunction
closable?: boolean
}
export const Tag = React.forwardRef<HTMLSpanElement, TagProps>(
function Tag(props, ref) {
const {
startElement,
endElement,
onClose,
closable = !!onClose,
children,
...rest
} = props
return (
<ChakraTag.Root ref={ref} {...rest}>
{startElement && (
<ChakraTag.StartElement>{startElement}</ChakraTag.StartElement>
)}
<ChakraTag.Label>{children}</ChakraTag.Label>
{endElement && (
<ChakraTag.EndElement>{endElement}</ChakraTag.EndElement>
)}
{closable && (
<ChakraTag.EndElement>
<ChakraTag.CloseTrigger onClick={onClose} />
</ChakraTag.EndElement>
)}
</ChakraTag.Root>
)
},
)

View File

@@ -1,21 +0,0 @@
import { Timeline as ChakraTimeline } from "@chakra-ui/react"
import * as React from "react"
export const TimelineConnector = React.forwardRef<
HTMLDivElement,
ChakraTimeline.IndicatorProps
>(function TimelineConnector(props, ref) {
return (
<ChakraTimeline.Connector ref={ref}>
<ChakraTimeline.Separator />
<ChakraTimeline.Indicator {...props} />
</ChakraTimeline.Connector>
)
})
export const TimelineRoot = ChakraTimeline.Root
export const TimelineContent = ChakraTimeline.Content
export const TimelineItem = ChakraTimeline.Item
export const TimelineIndicator = ChakraTimeline.Indicator
export const TimelineTitle = ChakraTimeline.Title
export const TimelineDescription = ChakraTimeline.Description

View File

@@ -1,43 +0,0 @@
"use client"
import {
Toaster as ChakraToaster,
Portal,
Spinner,
Stack,
Toast,
createToaster,
} from "@chakra-ui/react"
export const toaster = createToaster({
placement: "bottom-end",
pauseOnPageIdle: true,
})
export const Toaster = () => {
return (
<Portal>
<ChakraToaster toaster={toaster} insetInline={{ mdDown: "4" }}>
{(toast) => (
<Toast.Root width={{ md: "sm" }}>
{toast.type === "loading" ? (
<Spinner size="sm" color="blue.solid" />
) : (
<Toast.Indicator />
)}
<Stack gap="1" flex="1" maxWidth="100%">
{toast.title && <Toast.Title>{toast.title}</Toast.Title>}
{toast.description && (
<Toast.Description>{toast.description}</Toast.Description>
)}
</Stack>
{toast.action && (
<Toast.ActionTrigger>{toast.action.label}</Toast.ActionTrigger>
)}
{toast.meta?.closable && <Toast.CloseTrigger />}
</Toast.Root>
)}
</ChakraToaster>
</Portal>
)
}

View File

@@ -1,70 +0,0 @@
import { Popover as ChakraPopover, IconButton, Portal } from "@chakra-ui/react"
import * as React from "react"
import { HiOutlineInformationCircle } from "react-icons/hi"
export interface ToggleTipProps extends ChakraPopover.RootProps {
showArrow?: boolean
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
content?: React.ReactNode
}
export const ToggleTip = React.forwardRef<HTMLDivElement, ToggleTipProps>(
function ToggleTip(props, ref) {
const {
showArrow,
children,
portalled = true,
content,
portalRef,
...rest
} = props
return (
<ChakraPopover.Root
{...rest}
positioning={{ ...rest.positioning, gutter: 4 }}
>
<ChakraPopover.Trigger asChild>{children}</ChakraPopover.Trigger>
<Portal disabled={!portalled} container={portalRef}>
<ChakraPopover.Positioner>
<ChakraPopover.Content
width="auto"
px="2"
py="1"
textStyle="xs"
rounded="sm"
ref={ref}
>
{showArrow && (
<ChakraPopover.Arrow>
<ChakraPopover.ArrowTip />
</ChakraPopover.Arrow>
)}
{content}
</ChakraPopover.Content>
</ChakraPopover.Positioner>
</Portal>
</ChakraPopover.Root>
)
},
)
export const InfoTip = React.forwardRef<
HTMLDivElement,
Partial<ToggleTipProps>
>(function InfoTip(props, ref) {
const { children, ...rest } = props
return (
<ToggleTip content={children} {...rest} ref={ref}>
<IconButton
variant="ghost"
aria-label="info"
size="2xs"
colorPalette="gray"
>
<HiOutlineInformationCircle />
</IconButton>
</ToggleTip>
)
})

View File

@@ -1,57 +0,0 @@
"use client"
import type { ButtonProps } from "@chakra-ui/react"
import {
Button,
Toggle as ChakraToggle,
useToggleContext,
} from "@chakra-ui/react"
import * as React from "react"
interface ToggleProps extends ChakraToggle.RootProps {
variant?: keyof typeof variantMap
size?: ButtonProps["size"]
}
const variantMap = {
solid: { on: "solid", off: "outline" },
surface: { on: "surface", off: "outline" },
subtle: { on: "subtle", off: "ghost" },
ghost: { on: "subtle", off: "ghost" },
} as const
export const Toggle = React.forwardRef<HTMLButtonElement, ToggleProps>(
function Toggle(props, ref) {
const { variant = "subtle", size, children, ...rest } = props
const variantConfig = variantMap[variant]
return (
<ChakraToggle.Root asChild {...rest}>
<ToggleBaseButton size={size} variant={variantConfig} ref={ref}>
{children}
</ToggleBaseButton>
</ChakraToggle.Root>
)
},
)
interface ToggleBaseButtonProps extends Omit<ButtonProps, "variant"> {
variant: Record<"on" | "off", ButtonProps["variant"]>
}
const ToggleBaseButton = React.forwardRef<
HTMLButtonElement,
ToggleBaseButtonProps
>(function ToggleBaseButton(props, ref) {
const toggle = useToggleContext()
const { variant, ...rest } = props
return (
<Button
variant={toggle.pressed ? variant.on : variant.off}
ref={ref}
{...rest}
/>
)
})
export const ToggleIndicator = ChakraToggle.Indicator

View File

@@ -1,46 +0,0 @@
import { Tooltip as ChakraTooltip, Portal } from "@chakra-ui/react"
import * as React from "react"
export interface TooltipProps extends ChakraTooltip.RootProps {
showArrow?: boolean
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
content: React.ReactNode
contentProps?: ChakraTooltip.ContentProps
disabled?: boolean
}
export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>(
function Tooltip(props, ref) {
const {
showArrow,
children,
disabled,
portalled,
content,
contentProps,
portalRef,
...rest
} = props
if (disabled) return children
return (
<ChakraTooltip.Root {...rest}>
<ChakraTooltip.Trigger asChild>{children}</ChakraTooltip.Trigger>
<Portal disabled={!portalled} container={portalRef}>
<ChakraTooltip.Positioner>
<ChakraTooltip.Content ref={ref} {...contentProps}>
{showArrow && (
<ChakraTooltip.Arrow>
<ChakraTooltip.ArrowTip />
</ChakraTooltip.Arrow>
)}
{content}
</ChakraTooltip.Content>
</ChakraTooltip.Positioner>
</Portal>
</ChakraTooltip.Root>
)
},
)