docs: generate documentation for UI components (#5849)

* added tool to generate spec files for React components

* use typedoc for missing descriptions and types

* improvements and fixes

* improvements

* added doc comments for half of the components

* add custom resolver + more doc comments

* added all tsdocs

* general improvements

* add specs to UI docs

* added github action

* remove unnecessary api route

* Added readme for react-docs-generator

* remove comment

* Update packages/design-system/ui/src/components/currency-input/currency-input.tsx

Co-authored-by: Kasper Fabricius Kristensen <45367945+kasperkristensen@users.noreply.github.com>

* remove description of aria fields + add generate script

---------

Co-authored-by: Kasper Fabricius Kristensen <45367945+kasperkristensen@users.noreply.github.com>
This commit is contained in:
Shahed Nasser
2023-12-13 16:02:41 +02:00
committed by GitHub
parent edc49bfe1d
commit 245e5c9a69
288 changed files with 6029 additions and 1447 deletions

View File

@@ -52,12 +52,34 @@ interface AvatarProps
fallback: string
}
/**
* This component is based on the [Radix UI Avatar](https://www.radix-ui.com/primitives/docs/components/avatar) primitive.
*/
const Avatar = React.forwardRef<
React.ElementRef<typeof Primitives.Root>,
AvatarProps
>(
(
{ src, fallback, variant = "rounded", size = "base", className, ...props },
{
/**
* The URL of the image used in the Avatar.
*/
src,
/**
* Text to show in the avatar if the URL provided in `src` can't be opened.
*/
fallback,
/**
* The style of the avatar.
*/
variant = "rounded",
/**
* The size of the avatar's border radius.
*/
size = "base",
className,
...props
}: AvatarProps,
ref
) => {
return (

View File

@@ -49,16 +49,32 @@ interface BadgeProps
asChild?: boolean
}
/**
* This component is based on the `div` element and supports all of its props
*/
const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(
(
{
className,
/**
* The badge's size.
*/
size = "base",
/**
* The style of the badge's border radius.
*/
rounded = "base",
/**
* The badge's color.
*/
color = "grey",
/**
* Whether to remove the wrapper `span` element and use the
* passed child element instead.
*/
asChild = false,
...props
},
}: BadgeProps,
ref
) => {
const Component = asChild ? Slot : "span"

View File

@@ -59,18 +59,34 @@ interface ButtonProps
asChild?: boolean
}
/**
* This component is based on the `button` element and supports all of its props
*/
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
(
{
/**
* The button's style.
*/
variant = "primary",
/**
* The button's size.
*/
size = "base",
className,
/**
* Whether to remove the wrapper `button` element and use the
* passed child element instead.
*/
asChild = false,
children,
/**
* Whether to show a loading spinner.
*/
isLoading = false,
disabled,
...props
},
}: ButtonProps,
ref
) => {
const Component = asChild ? Slot : "button"

View File

@@ -22,6 +22,9 @@ type KeysToOmit = "showWeekNumber" | "captionLayout" | "mode"
type SingleProps = OmitKeys<DayPickerSingleProps, KeysToOmit>
type RangeProps = OmitKeys<DayPickerRangeProps, KeysToOmit>
/**
* @interface
*/
type CalendarProps =
| ({
mode: "single"
@@ -33,10 +36,29 @@ type CalendarProps =
mode: "range"
} & RangeProps)
/**
* This component is based on the [react-date-picker](https://www.npmjs.com/package/react-date-picker) package.
*
* @excludeExternal
*/
const Calendar = ({
/**
* @ignore
*/
className,
/**
* @ignore
*/
classNames,
/**
* The calendar's mode.
*/
mode = "single",
/**
* Whether to show days of previous and next months.
*
* @keep
*/
showOutsideDays = true,
...props
}: CalendarProps) => {

View File

@@ -6,6 +6,9 @@ import * as React from "react"
import { clx } from "@/utils/clx"
/**
* This component is based on the [Radix UI Checkbox](https://www.radix-ui.com/primitives/docs/components/checkbox) primitive.
*/
const Checkbox = React.forwardRef<
React.ElementRef<typeof Primitives.Root>,
React.ComponentPropsWithoutRef<typeof Primitives.Root>

View File

@@ -6,10 +6,25 @@ import { Copy } from "@/components/copy"
import { clx } from "@/utils/clx"
export type CodeSnippet = {
/**
* The label of the code snippet's tab.
*/
label: string
/**
* The language of the code snippet. For example, `tsx`.
*/
language: string
/**
* The code snippet.
*/
code: string
/**
* Whether to hide the line numbers shown as the side of the code snippet.
*/
hideLineNumbers?: boolean
/**
* Whether to hide the copy button.
*/
hideCopy?: boolean
}
@@ -36,7 +51,13 @@ type RootProps = {
snippets: CodeSnippet[]
}
/**
* This component is based on the `div` element and supports all of its props
*/
const Root = ({
/**
* The code snippets.
*/
snippets,
className,
children,
@@ -58,14 +79,21 @@ const Root = ({
</CodeBlockContext.Provider>
)
}
Root.displayName = "CodeBlock"
type HeaderProps = {
hideLabels?: boolean
}
/**
* This component is based on the `div` element and supports all of its props
*/
const HeaderComponent = ({
children,
className,
/**
* Whether to hide the code snippets' labels.
*/
hideLabels = false,
...props
}: React.HTMLAttributes<HTMLDivElement> & HeaderProps) => {
@@ -98,7 +126,11 @@ const HeaderComponent = ({
</div>
)
}
HeaderComponent.displayName = "CodeBlock.Header"
/**
* This component is based on the `div` element and supports all of its props
*/
const Meta = ({
className,
...props
@@ -110,9 +142,13 @@ const Meta = ({
/>
)
}
Meta.displayName = "CodeBlock.Header.Meta"
const Header = Object.assign(HeaderComponent, { Meta })
/**
* This component is based on the `div` element and supports all of its props
*/
const Body = ({
className,
...props
@@ -240,6 +276,7 @@ const Body = ({
</div>
)
}
Body.displayName = "CodeBlock.Body"
const CodeBlock = Object.assign(Root, { Body, Header, Meta })

View File

@@ -1,6 +1,9 @@
import { clx } from "@/utils/clx"
import * as React from "react"
/**
* This component is based on the `code` element and supports all of its props
*/
const Code = React.forwardRef<
HTMLElement,
React.ComponentPropsWithoutRef<"code">

View File

@@ -7,17 +7,32 @@ import * as React from "react"
import { Kbd } from "@/components/kbd"
import { clx } from "@/utils/clx"
type CommandBarProps = React.PropsWithChildren<{
interface CommandBarProps extends React.PropsWithChildren {
open?: boolean
onOpenChange?: (open: boolean) => void
defaultOpen?: boolean
disableAutoFocus?: boolean
}>
}
/**
* The root component of the command bar. This component manages the state of the command bar.
*/
const Root = ({
/**
* Whether to open (show) the command bar.
*/
open = false,
/**
* Specify a function to handle the change of `open`'s value.
*/
onOpenChange,
/**
* Whether the command bar is open by default.
*/
defaultOpen = false,
/**
* Whether to disable focusing automatically on the command bar when it's opened.
*/
disableAutoFocus = true,
children,
}: CommandBarProps) => {
@@ -53,6 +68,10 @@ const Root = ({
}
Root.displayName = "CommandBar"
/**
* The value component of the command bar. This component is used to display a value,
* such as the number of selected items which the commands will act on.
*/
const Value = React.forwardRef<
HTMLDivElement,
React.ComponentPropsWithoutRef<"div">
@@ -70,6 +89,9 @@ const Value = React.forwardRef<
})
Value.displayName = "CommandBar.Value"
/**
* The bar component of the command bar. This component is used to display the commands.
*/
const Bar = React.forwardRef<
HTMLDivElement,
React.ComponentPropsWithoutRef<"div">
@@ -88,6 +110,9 @@ const Bar = React.forwardRef<
})
Bar.displayName = "CommandBar.Bar"
/**
* The seperator component of the command bar. This component is used to display a seperator between commands.
*/
const Seperator = React.forwardRef<
HTMLDivElement,
Omit<React.ComponentPropsWithoutRef<"div">, "children">
@@ -112,9 +137,29 @@ interface CommandProps
shortcut: string
}
/**
* The command component of the command bar. This component is used to display a command, as well as registering the keyboad shortcut.
*/
const Command = React.forwardRef<HTMLButtonElement, CommandProps>(
(
{ className, type = "button", label, action, shortcut, disabled, ...props },
{
className,
type = "button",
/**
* The command's label.
*/
label,
/**
* The function to execute when the command is triggered.
*/
action,
/**
* The command's shortcut
*/
shortcut,
disabled,
...props
}: CommandProps,
ref
) => {
React.useEffect(() => {

View File

@@ -4,6 +4,9 @@ import { Copy } from "@/components/copy"
import { clx } from "@/utils/clx"
import React from "react"
/**
* This component is based on the div element and supports all of its props
*/
const CommandComponent = ({
className,
...props
@@ -19,6 +22,7 @@ const CommandComponent = ({
/>
)
}
CommandComponent.displayName = "Command"
const Command = Object.assign(CommandComponent, { Copy })

View File

@@ -2,6 +2,9 @@ import * as React from "react"
import { clx } from "@/utils/clx"
/**
* This component is based on the `div` element and supports all of its props
*/
const Container = React.forwardRef<
HTMLDivElement,
React.ComponentPropsWithoutRef<"div">

View File

@@ -7,15 +7,31 @@ import { Slot } from "@radix-ui/react-slot"
import copy from "copy-to-clipboard"
import React, { useState } from "react"
type CopyProps = {
type CopyProps = React.HTMLAttributes<HTMLButtonElement> & {
content: string
asChild?: boolean
}
/**
* This component is based on the `button` element and supports all of its props
*/
const Copy = React.forwardRef<
HTMLButtonElement,
React.HTMLAttributes<HTMLButtonElement> & CopyProps
>(({ children, className, content, asChild = false, ...props }, ref) => {
CopyProps
>(({
children,
className,
/**
* The content to copy.
*/
content,
/**
* Whether to remove the wrapper `button` element and use the
* passed child element instead.
*/
asChild = false,
...props
}: CopyProps, ref) => {
const [done, setDone] = useState(false)
const [open, setOpen] = useState(false)
const [text, setText] = useState("Copy")

View File

@@ -34,9 +34,31 @@ interface CurrencyInputProps
code: string
}
/**
* This component is based on the input element and supports all of its props
*
* @excludeExternal
*/
const CurrencyInput = React.forwardRef<HTMLInputElement, CurrencyInputProps>(
(
{ size = "base", symbol, code, disabled, onInvalid, className, ...props },
{
/**
* The input's size.
*/
size = "base",
/**
* The symbol to show in the input.
*/
symbol,
/**
* The currency code to show in the input.
*/
code,
disabled,
onInvalid,
className,
...props
}: CurrencyInputProps,
ref
) => {
const innerRef = React.useRef<HTMLInputElement>(null)

View File

@@ -34,13 +34,27 @@ const displayVariants = cva({
},
})
interface DisplayProps extends React.ComponentProps<"button"> {
placeholder?: string
size?: "small" | "base"
}
const Display = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<"button"> & {
placeholder?: string
size?: "small" | "base"
}
>(({ className, children, placeholder, size = "base", ...props }, ref) => {
DisplayProps
>(({
className,
children,
/**
* Placeholder of the date picker's input.
*/
placeholder,
/**
* The size of the date picker's input.
*/
size = "base",
...props
}: DisplayProps, ref) => {
return (
<Primitives.Trigger asChild>
<button
@@ -88,14 +102,23 @@ const Flyout = React.forwardRef<
Flyout.displayName = "DatePicker.Flyout"
interface Preset {
/**
* The preset's label.
*/
label: string
}
interface DatePreset extends Preset {
/**
* The preset's selected date.
*/
date: Date
}
interface DateRangePreset extends Preset {
/**
* The preset's selected date range.
*/
dateRange: DateRange
}
@@ -106,8 +129,17 @@ type PresetContainerProps<TPreset extends Preset, TValue> = {
}
const PresetContainer = <TPreset extends Preset, TValue>({
/**
* Selectable preset configurations.
*/
presets,
/**
* A function that handles the event when a preset is selected.
*/
onSelect,
/**
* The currently selected preset.
*/
currentValue,
}: PresetContainerProps<TPreset, TValue>) => {
const isDateRangePresets = (preset: any): preset is DateRangePreset => {
@@ -203,6 +235,7 @@ const PresetContainer = <TPreset extends Preset, TValue>({
</ul>
)
}
PresetContainer.displayName = "DatePicker.PresetContainer"
const formatDate = (date: Date, includeTime?: boolean) => {
const usesAmPm = !isBrowserLocaleClockType24h()
@@ -219,21 +252,60 @@ const formatDate = (date: Date, includeTime?: boolean) => {
}
type CalendarProps = {
/**
* The year to start showing the dates from.
*/
fromYear?: number
/**
* The year to show dates to.
*/
toYear?: number
/**
* The month to start showing dates from.
*/
fromMonth?: Date
/**
* The month to show dates to.
*/
toMonth?: Date
/**
* The day to start showing dates from.
*/
fromDay?: Date
/**
* The day to show dates to.
*/
toDay?: Date
/**
* The date to show dates from.
*/
fromDate?: Date
/**
* The date to show dates to.
*/
toDate?: Date
}
interface PickerProps extends CalendarProps {
/**
* The class name to apply on the date picker.
*/
className?: string
/**
* Whether the date picker's input is disabled.
*/
disabled?: boolean
/**
* Whether the date picker's input is required.
*/
required?: boolean
/**
* The date picker's size.
*/
size?: "small" | "base"
/**
* Whether to show a time picker along with the date picker.
*/
showTimePicker?: boolean
id?: string
"aria-invalid"?: boolean
@@ -466,11 +538,23 @@ interface RangeProps extends PickerProps {
}
const RangeDatePicker = ({
/**
* The date range selected by default.
*/
defaultValue,
/**
* The selected date range.
*/
value,
/**
* A function to handle the change in the selected date range.
*/
onChange,
size = "base",
showTimePicker,
/**
* Provide selectable preset configurations.
*/
presets,
disabled,
className,
@@ -732,6 +816,14 @@ const RangeDatePicker = ({
)
}
/**
* @interface
*
* @prop presets - Provide selectable preset configurations.
* @prop defaultValue - The date selected by default.
* @prop value - The selected date.
* @prop onChange - A function to handle the change in the selected date.
*/
type DatePickerProps = (
| {
mode?: "single"
@@ -891,7 +983,17 @@ const validatePresets = (
}
}
const DatePicker = ({ mode = "single", ...props }: DatePickerProps) => {
/**
* This component is based on the [Calendar](https://docs.medusajs.com/ui/components/calendar)
* component and [Radix UI Popover](https://www.radix-ui.com/primitives/docs/components/popover).
*/
const DatePicker = ({
/**
* The date picker's mode.
*/
mode = "single",
...props
}: DatePickerProps) => {
if (props.presets) {
validatePresets(props.presets, props)
}

View File

@@ -10,12 +10,15 @@ import { Kbd } from "@/components/kbd"
import { Text } from "@/components/text"
import { clx } from "@/utils/clx"
/**
* This component is based on the [Radix UI Dialog](https://www.radix-ui.com/primitives/docs/components/dialog) primitives.
*/
const DrawerRoot = (
props: React.ComponentPropsWithoutRef<typeof DrawerPrimitives.Root>
) => {
return <DrawerPrimitives.Root {...props} />
}
DrawerRoot.displayName = "Drawer.Root"
DrawerRoot.displayName = "Drawer"
const DrawerTrigger = React.forwardRef<
React.ElementRef<typeof DrawerPrimitives.Trigger>,

View File

@@ -6,21 +6,39 @@ import * as React from "react"
import { clx } from "@/utils/clx"
/**
* This component is based on the [Radix UI Dropdown Menu](https://www.radix-ui.com/primitives/docs/components/dropdown-menu) primitive.
*/
const Root = Primitives.Root
Root.displayName = "DropdownMenu.Root"
Root.displayName = "DropdownMenu"
/**
* This component is based on the [Radix UI Dropdown Menu Trigger](https://www.radix-ui.com/primitives/docs/components/dropdown-menu#trigger) primitive.
*/
const Trigger = Primitives.Trigger
Trigger.displayName = "DropdownMenu.Trigger"
/**
* This component is based on the [Radix UI Dropdown Menu Group](https://www.radix-ui.com/primitives/docs/components/dropdown-menu#group) primitive.
*/
const Group = Primitives.Group
Group.displayName = "DropdownMenu.Group"
/**
* This component is based on the [Radix UI Dropdown Menu Sub](https://www.radix-ui.com/primitives/docs/components/dropdown-menu#sub) primitive.
*/
const SubMenu = Primitives.Sub
SubMenu.displayName = "DropdownMenu.SubMenu"
/**
* This component is based on the [Radix UI Dropdown Menu RadioGroup](https://www.radix-ui.com/primitives/docs/components/dropdown-menu#radiogroup) primitive.
*/
const RadioGroup = Primitives.RadioGroup
RadioGroup.displayName = "DropdownMenu.RadioGroup"
/**
* This component is based on the [Radix UI Dropdown Menu SubTrigger](https://www.radix-ui.com/primitives/docs/components/dropdown-menu#subtrigger) primitive.
*/
const SubMenuTrigger = React.forwardRef<
React.ElementRef<typeof Primitives.SubTrigger>,
React.ComponentPropsWithoutRef<typeof Primitives.SubTrigger>
@@ -39,6 +57,9 @@ const SubMenuTrigger = React.forwardRef<
))
SubMenuTrigger.displayName = "DropdownMenu.SubMenuTrigger"
/**
* This component is based on the [Radix UI Dropdown Menu SubContent](https://www.radix-ui.com/primitives/docs/components/dropdown-menu#subcontent) primitive.
*/
const SubMenuContent = React.forwardRef<
React.ElementRef<typeof Primitives.SubContent>,
React.ComponentPropsWithoutRef<typeof Primitives.SubContent>
@@ -58,6 +79,9 @@ const SubMenuContent = React.forwardRef<
))
SubMenuContent.displayName = "DropdownMenu.SubMenuContent"
/**
* This component is based on the [Radix UI Dropdown Menu Content](https://www.radix-ui.com/primitives/docs/components/dropdown-menu#content) primitive.
*/
const Content = React.forwardRef<
React.ElementRef<typeof Primitives.Content>,
React.ComponentPropsWithoutRef<typeof Primitives.Content>
@@ -90,6 +114,9 @@ const Content = React.forwardRef<
)
Content.displayName = "DropdownMenu.Content"
/**
* This component is based on the [Radix UI Dropdown Menu Item](https://www.radix-ui.com/primitives/docs/components/dropdown-menu#item) primitive.
*/
const Item = React.forwardRef<
React.ElementRef<typeof Primitives.Item>,
React.ComponentPropsWithoutRef<typeof Primitives.Item>
@@ -105,6 +132,9 @@ const Item = React.forwardRef<
))
Item.displayName = "DropdownMenu.Item"
/**
* This component is based on the [Radix UI Dropdown Menu CheckboxItem](https://www.radix-ui.com/primitives/docs/components/dropdown-menu#checkboxitem) primitive.
*/
const CheckboxItem = React.forwardRef<
React.ElementRef<typeof Primitives.CheckboxItem>,
React.ComponentPropsWithoutRef<typeof Primitives.CheckboxItem>
@@ -128,6 +158,9 @@ const CheckboxItem = React.forwardRef<
))
CheckboxItem.displayName = "DropdownMenu.CheckboxItem"
/**
* This component is based on the [Radix UI Dropdown Menu RadioItem](https://www.radix-ui.com/primitives/docs/components/dropdown-menu#radioitem) primitive.
*/
const RadioItem = React.forwardRef<
React.ElementRef<typeof Primitives.RadioItem>,
React.ComponentPropsWithoutRef<typeof Primitives.RadioItem>
@@ -150,6 +183,9 @@ const RadioItem = React.forwardRef<
))
RadioItem.displayName = "DropdownMenu.RadioItem"
/**
* This component is based on the [Radix UI Dropdown Menu Label](https://www.radix-ui.com/primitives/docs/components/dropdown-menu#label) primitive.
*/
const Label = React.forwardRef<
React.ElementRef<typeof Primitives.Label>,
React.ComponentPropsWithoutRef<typeof Primitives.Label>
@@ -165,6 +201,9 @@ const Label = React.forwardRef<
))
Label.displayName = "DropdownMenu.Label"
/**
* This component is based on the [Radix UI Dropdown Menu Separator](https://www.radix-ui.com/primitives/docs/components/dropdown-menu#separator) primitive.
*/
const Separator = React.forwardRef<
React.ElementRef<typeof Primitives.Separator>,
React.ComponentPropsWithoutRef<typeof Primitives.Separator>
@@ -177,6 +216,9 @@ const Separator = React.forwardRef<
))
Separator.displayName = "DropdownMenu.Separator"
/**
* This component is based on the `span` element and supports all of its props
*/
const Shortcut = ({
className,
...props
@@ -193,6 +235,9 @@ const Shortcut = ({
}
Shortcut.displayName = "DropdownMenu.Shortcut"
/**
* This component is based on the `span` element and supports all of its props
*/
const Hint = ({
className,
...props

View File

@@ -8,8 +8,20 @@ import { IconButton } from "@/components/icon-button"
import { Kbd } from "@/components/kbd"
import { clx } from "@/utils/clx"
/**
* @prop defaultOpen - Whether the modal is opened by default.
* @prop open - Whether the modal is opened.
* @prop onOpenChange - A function to handle when the modal is opened or closed.
*/
interface FocusModalRootProps
extends React.ComponentPropsWithoutRef<typeof FocusModalPrimitives.Root> {
}
/**
* This component is based on the [Radix UI Dialog](https://www.radix-ui.com/primitives/docs/components/dialog) primitives.
*/
const FocusModalRoot = (
props: React.ComponentPropsWithoutRef<typeof FocusModalPrimitives.Root>
props: FocusModalRootProps
) => {
return <FocusModalPrimitives.Root {...props} />
}
@@ -72,6 +84,9 @@ const FocusModalContent = React.forwardRef<
})
FocusModalContent.displayName = "FocusModal.Content"
/**
* This component is based on the `div` element and supports all of its props
*/
const FocusModalHeader = React.forwardRef<
HTMLDivElement,
React.ComponentPropsWithoutRef<"div">
@@ -99,6 +114,9 @@ const FocusModalHeader = React.forwardRef<
})
FocusModalHeader.displayName = "FocusModal.Header"
/**
* This component is based on the `div` element and supports all of its props
*/
const FocusModalBody = React.forwardRef<
HTMLDivElement,
React.ComponentPropsWithoutRef<"div">

View File

@@ -17,11 +17,22 @@ const headingVariants = cva({
},
})
type HeadingProps = VariantProps<typeof headingVariants> &
React.HTMLAttributes<HTMLHeadingElement>
interface HeadingProps extends VariantProps<typeof headingVariants>,
React.HTMLAttributes<HTMLHeadingElement> {}
const Heading = ({ level, className, ...props }: HeadingProps) => {
const Component = level ? level : "h1"
/**
* This component is based on the heading element (`h1`, `h2`, etc...) depeneding on the specified level
* and supports all of its props
*/
const Heading = ({
/**
* The heading level which specifies which heading element is used.
*/
level = "h1",
className,
...props
}: HeadingProps) => {
const Component = level || "h1"
return (
<Component

View File

@@ -17,11 +17,19 @@ const hintVariants = cva({
},
})
type HintProps = VariantProps<typeof hintVariants> &
React.ComponentPropsWithoutRef<"span">
interface HintProps extends VariantProps<typeof hintVariants>,
React.ComponentPropsWithoutRef<"span"> {}
const Hint = React.forwardRef<HTMLSpanElement, HintProps>(
({ className, variant = "info", children, ...props }, ref) => {
({
className,
/**
* The hint's style.
*/
variant = "info",
children,
...props
}: HintProps, ref) => {
return (
<span
ref={ref}

View File

@@ -22,16 +22,29 @@ interface IconBadgeProps
asChild?: boolean
}
/**
* This component is based on the `span` element and supports all of its props
*/
const IconBadge = React.forwardRef<HTMLSpanElement, IconBadgeProps>(
(
{
children,
className,
/**
* The badge's color.
*/
color = "grey",
/**
* The badge's size.
*/
size = "base",
/**
* Whether to remove the wrapper `span` element and use the
* passed child element instead.
*/
asChild = false,
...props
},
}: IconBadgeProps,
ref
) => {
const Component = asChild ? Slot : "span"

View File

@@ -46,18 +46,34 @@ interface IconButtonProps
isLoading?: boolean
}
/**
* This component is based on the `button` element and supports all of its props
*/
const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(
(
{
/**
* The button's style.
*/
variant = "primary",
/**
* The button's size.
*/
size = "base",
/**
* Whether to remove the wrapper `button` element and use the
* passed child element instead.
*/
asChild = false,
className,
children,
/**
* Whether to show a loading spinner.
*/
isLoading = false,
disabled,
...props
},
}: IconButtonProps,
ref
) => {
const Component = asChild ? Slot : "button"

View File

@@ -29,11 +29,24 @@ const inputVariants = cva({
},
})
interface InputProps extends VariantProps<typeof inputVariants>,
Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> {}
/**
* This component is based on the `input` element and supports all of its props
*/
const Input = React.forwardRef<
HTMLInputElement,
VariantProps<typeof inputVariants> &
Omit<React.InputHTMLAttributes<HTMLInputElement>, "size">
>(({ className, type, size = "base", ...props }, ref) => {
InputProps
>(({
className,
type,
/**
* The input's size.
*/
size = "base",
...props
}: InputProps, ref) => {
const [typeState, setTypeState] = React.useState(type)
const isPassword = type === "password"

View File

@@ -2,6 +2,9 @@ import * as React from "react"
import { clx } from "@/utils/clx"
/**
* This component is based on the `kbd` element and supports all of its props
*/
const Kbd = React.forwardRef<
HTMLElement,
React.ComponentPropsWithoutRef<"kbd">

View File

@@ -30,8 +30,22 @@ interface LabelProps
extends React.ComponentPropsWithoutRef<"label">,
VariantProps<typeof labelVariants> {}
/**
* This component is based on the [Radix UI Label](https://www.radix-ui.com/primitives/docs/components/label) primitive.
*/
const Label = React.forwardRef<HTMLLabelElement, LabelProps>(
({ className, size = "base", weight = "regular", ...props }, ref) => {
({
className,
/**
* The label's size.
*/
size = "base",
/**
* The label's font weight.
*/
weight = "regular",
...props
}: LabelProps, ref) => {
return (
<Primitives.Root
ref={ref}

View File

@@ -3,6 +3,9 @@ import * as React from "react"
import { clx } from "@/utils/clx"
/**
* This component is based on the [Radix UI Popover](https://www.radix-ui.com/primitives/docs/components/popover) primitves.
*/
const Root = (
props: React.ComponentPropsWithoutRef<typeof Primitives.Root>
) => {
@@ -34,19 +37,34 @@ const Close = React.forwardRef<
})
Close.displayName = "Popover.Close"
interface ContentProps extends React.ComponentPropsWithoutRef<typeof Primitives.Content> {}
/**
* @excludeExternal
*/
const Content = React.forwardRef<
React.ElementRef<typeof Primitives.Content>,
React.ComponentPropsWithoutRef<typeof Primitives.Content>
ContentProps
>(
(
{
className,
/**
* The distance in pixels from the anchor.
*/
sideOffset = 8,
/**
* The preferred side of the anchor to render against when open.
* Will be reversed when collisions occur and `avoidCollisions` is enabled.
*/
side = "bottom",
/**
* The preferred alignment against the anchor. May change when collisions occur.
*/
align = "start",
collisionPadding,
...props
},
}: ContentProps,
ref
) => {
return (

View File

@@ -13,6 +13,9 @@ import { ProgressStatus } from "@/types"
import { clx } from "@/utils/clx"
import { IconButton } from "../icon-button"
/**
* This component is based on the [Radix UI Accordion](https://radix-ui.com/primitives/docs/components/accordion) primitves.
*/
const Root = (props: React.ComponentPropsWithoutRef<typeof Primitves.Root>) => {
return <Primitves.Root {...props} />
}
@@ -44,7 +47,13 @@ interface StatusIndicatorProps extends React.ComponentPropsWithoutRef<"span"> {
status: ProgressStatus
}
const ProgressIndicator = ({ status, ...props }: StatusIndicatorProps) => {
const ProgressIndicator = ({
/**
* The current status.
*/
status,
...props
}: StatusIndicatorProps) => {
const Icon = React.useMemo(() => {
switch (status) {
case "not-started":
@@ -67,29 +76,39 @@ const ProgressIndicator = ({ status, ...props }: StatusIndicatorProps) => {
</span>
)
}
ProgressIndicator.displayName = "ProgressAccordion.ProgressIndicator"
const Header = React.forwardRef<
React.ElementRef<typeof Primitves.Header>,
HeaderProps
>(({ className, status = "not-started", children, ...props }, ref) => {
return (
<Primitves.Header
ref={ref}
className={clx(
"h3-core text-ui-fg-base group flex w-full flex-1 items-center gap-4 px-8",
className
)}
{...props}
>
<ProgressIndicator status={status} />
{children}
<Primitves.Trigger asChild className="ml-auto">
<IconButton variant="transparent">
<Plus className="transform transition-transform group-data-[state=open]:rotate-45" />
</IconButton>
</Primitves.Trigger>
</Primitves.Header>
)
>((
{
className,
/**
* The current status.
*/
status = "not-started",
children,
...props
}: HeaderProps, ref) => {
return (
<Primitves.Header
ref={ref}
className={clx(
"h3-core text-ui-fg-base group flex w-full flex-1 items-center gap-4 px-8",
className
)}
{...props}
>
<ProgressIndicator status={status} />
{children}
<Primitves.Trigger asChild className="ml-auto">
<IconButton variant="transparent">
<Plus className="transform transition-transform group-data-[state=open]:rotate-45" />
</IconButton>
</Primitves.Trigger>
</Primitves.Header>
)
})
Header.displayName = "ProgressAccordion.Header"

View File

@@ -11,6 +11,11 @@ import * as React from "react"
import { ProgressStatus } from "@/types"
import { clx } from "@/utils/clx"
/**
* This component is based on the [Radix UI Tabs](https://radix-ui.com/primitives/docs/components/tabs) primitves.
*
* @excludeExternal
*/
const ProgressTabsRoot = (props: ProgressTabsPrimitives.TabsProps) => {
return <ProgressTabsPrimitives.Root {...props} />
}
@@ -18,10 +23,17 @@ ProgressTabsRoot.displayName = "ProgressTabs"
interface IndicatorProps
extends Omit<React.ComponentPropsWithoutRef<"span">, "children"> {
/**
* The current status.
*/
status?: ProgressStatus
}
const ProgressIndicator = ({ status, className, ...props }: IndicatorProps) => {
const ProgressIndicator = ({
status,
className,
...props
}: IndicatorProps) => {
const Icon = React.useMemo(() => {
switch (status) {
case "not-started":
@@ -47,6 +59,7 @@ const ProgressIndicator = ({ status, className, ...props }: IndicatorProps) => {
</span>
)
}
ProgressIndicator.displayName = "ProgressTabs.ProgressIndicator"
interface ProgressTabsTriggerProps
extends Omit<
@@ -59,7 +72,7 @@ interface ProgressTabsTriggerProps
const ProgressTabsTrigger = React.forwardRef<
React.ElementRef<typeof ProgressTabsPrimitives.Trigger>,
ProgressTabsTriggerProps
>(({ className, children, status = "not-started", ...props }, ref) => (
>(({ className, children, status = "not-started", ...props }: ProgressTabsTriggerProps, ref) => (
<ProgressTabsPrimitives.Trigger
ref={ref}
className={clx(

View File

@@ -7,8 +7,11 @@ import { Button } from "@/components/button"
import { Heading } from "@/components/heading"
import { clx } from "@/utils/clx"
/**
* This component is based on the [Radix UI Alert Dialog](https://www.radix-ui.com/primitives/docs/components/alert-dialog) primitives.
*/
const Root = Primitives.AlertDialog
Root.displayName = "Prompt.Root"
Root.displayName = "Prompt"
const Trigger = Primitives.Trigger
Trigger.displayName = "Prompt.Trigger"
@@ -111,6 +114,9 @@ const Cancel = React.forwardRef<
})
Cancel.displayName = "Prompt.Cancel"
/**
* This component is based on the `div` element and supports all of its props
*/
const Header = ({
className,
...props
@@ -122,7 +128,11 @@ const Header = ({
/>
)
}
Header.displayName = "Prompt.Header"
/**
* This component is based on the `div` element and supports all of its props
*/
const Footer = ({
className,
...props
@@ -134,6 +144,7 @@ const Footer = ({
/>
)
}
Footer.displayName = "Prompt.Footer"
const Prompt = Object.assign(Root, {
Trigger,

View File

@@ -7,6 +7,9 @@ import { clx } from "@/utils/clx"
import { Hint } from "../hint"
import { Label } from "../label"
/**
* This component is based on the [Radix UI Radio Group](https://www.radix-ui.com/primitives/docs/components/radio-group) primitives.
*/
const Root = React.forwardRef<
React.ElementRef<typeof Primitives.Root>,
React.ComponentPropsWithoutRef<typeof Primitives.Root>
@@ -19,7 +22,7 @@ const Root = React.forwardRef<
/>
)
})
Root.displayName = "RadioGroup.Root"
Root.displayName = "RadioGroup"
const Indicator = React.forwardRef<
React.ElementRef<typeof Primitives.Indicator>,

View File

@@ -28,17 +28,38 @@ const useSelectContext = () => {
return context
}
const Root = ({ children, size = "base", ...props }: SelectProps) => {
/**
* This component is based on [Radix UI Select](https://www.radix-ui.com/primitives/docs/components/select).
* It also accepts all props of the HTML `select` component.
*/
const Root = ({
children,
/**
* The select's size.
*/
size = "base",
...props
}: SelectProps) => {
return (
<SelectContext.Provider value={React.useMemo(() => ({ size }), [size])}>
<SelectPrimitive.Root {...props}>{children}</SelectPrimitive.Root>
</SelectContext.Provider>
)
}
Root.displayName = "Select"
/**
* Groups multiple items together.
*/
const Group = SelectPrimitive.Group
Group.displayName = "Select.Group"
/**
* Displays the selected value, or a placeholder if no value is selected.
* It's based on [Radix UI Select Value](https://www.radix-ui.com/primitives/docs/components/select#value).
*/
const Value = SelectPrimitive.Value
Value.displayName = "Select.Value"
const triggerVariants = cva({
base: clx(
@@ -59,6 +80,9 @@ const triggerVariants = cva({
},
})
/**
* The trigger that toggles the select.
*/
const Trigger = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
@@ -78,7 +102,7 @@ const Trigger = React.forwardRef<
</SelectPrimitive.Trigger>
)
})
Trigger.displayName = SelectPrimitive.Trigger.displayName
Trigger.displayName = "Select.Trigger"
const Content = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
@@ -127,8 +151,11 @@ const Content = React.forwardRef<
</SelectPrimitive.Portal>
)
)
Content.displayName = SelectPrimitive.Content.displayName
Content.displayName = "Select.Content"
/**
* Used to label a group of items.
*/
const Label = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
@@ -142,8 +169,12 @@ const Label = React.forwardRef<
{...props}
/>
))
Label.displayName = SelectPrimitive.Label.displayName
Label.displayName = "Select.Label"
/**
* An item in the select. It's based on [Radix UI Select Item](https://www.radix-ui.com/primitives/docs/components/select#item)
* and accepts its props.
*/
const Item = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
@@ -177,7 +208,7 @@ const Item = React.forwardRef<
</SelectPrimitive.Item>
)
})
Item.displayName = SelectPrimitive.Item.displayName
Item.displayName = "Select.Item"
const Separator = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Separator>,
@@ -189,7 +220,7 @@ const Separator = React.forwardRef<
{...props}
/>
))
Separator.displayName = SelectPrimitive.Separator.displayName
Separator.displayName = "Select.Separator"
const Select = Object.assign(Root, {
Group,

View File

@@ -15,8 +15,19 @@ interface StatusBadgeProps
color?: "green" | "red" | "blue" | "orange" | "grey" | "purple"
}
/**
* This component is based on the span element and supports all of its props
*/
const StatusBadge = React.forwardRef<HTMLSpanElement, StatusBadgeProps>(
({ children, className, color = "grey", ...props }, ref) => {
({
children,
className,
/**
* The status's color.
*/
color = "grey",
...props
}: StatusBadgeProps, ref) => {
const StatusIndicator = {
green: EllipseGreenSolid,
red: EllipseRedSolid,

View File

@@ -40,10 +40,20 @@ interface SwitchProps
>,
VariantProps<typeof switchVariants> {}
/**
* This component is based on the [Radix UI Switch](https://www.radix-ui.com/primitives/docs/components/switch) primitive.
*/
const Switch = React.forwardRef<
React.ElementRef<typeof Primitives.Root>,
SwitchProps
>(({ className, size = "base", ...props }, ref) => (
>(({
className,
/**
* The switch's size.
*/
size = "base",
...props
}: SwitchProps, ref) => (
<Primitives.Root
className={clx(switchVariants({ size }), className)}
{...props}

View File

@@ -4,6 +4,18 @@ import * as React from "react"
import { Button } from "@/components/button"
import { clx } from "@/utils/clx"
/**
* This component is based on the table element and its various children:
*
* - `Table`: `table`
* - `Table.Header`: `thead`
* - `Table.Row`: `tr`
* - `Table.HeaderCell`: `th`
* - `Table.Body`: `tbody`
* - `Table.Cell`: `td`
*
* Each component supports the props or attributes of its equivalent HTML element.
*/
const Root = React.forwardRef<
HTMLTableElement,
React.HTMLAttributes<HTMLTableElement>
@@ -87,20 +99,49 @@ interface TablePaginationProps extends React.HTMLAttributes<HTMLDivElement> {
nextPage: () => void
}
/**
* This component is based on the `div` element and supports all of its props
*/
const Pagination = React.forwardRef<HTMLDivElement, TablePaginationProps>(
(
{
className,
/**
* The total number of items.
*/
count,
/**
* The number of items per page.
*/
pageSize,
/**
* The total number of pages.
*/
pageCount,
/**
* The current page index.
*/
pageIndex,
/**
* Whether there's a previous page that can be navigated to.
*/
canPreviousPage,
/**
* Whether there's a next page that can be navigated to.
*/
canNextPage,
/**
* A function that handles navigating to the next page.
* This function should handle retrieving data for the next page.
*/
nextPage,
/**
* A function that handles navigating to the previous page.
* This function should handle retrieving data for the previous page.
*/
previousPage,
...props
},
}: TablePaginationProps,
ref
) => {
const { from, to } = React.useMemo(() => {

View File

@@ -5,6 +5,9 @@ import * as React from "react"
import { clx } from "@/utils/clx"
/**
* This component is based on the [Radix UI Tabs](https://radix-ui.com/primitives/docs/components/tabs) primitves
*/
const TabsRoot = (
props: React.ComponentPropsWithoutRef<typeof TabsPrimitives.Root>
) => {

View File

@@ -93,19 +93,41 @@ interface TextProps
as?: "p" | "span" | "div"
}
/**
* This component is based on the `p` element and supports all of its props
*/
const Text = React.forwardRef<HTMLParagraphElement, TextProps>(
(
{
className,
/**
* Whether to remove the wrapper `button` element and use the
* passed child element instead.
*/
asChild = false,
/**
* The wrapper element to use when `asChild` is disabled.
*/
as = "p",
/**
* The text's size.
*/
size = "base",
/**
* The text's font weight.
*/
weight = "regular",
/**
* The text's font family.
*/
family = "sans",
/**
* The text's line height.
*/
leading = "normal",
children,
...props
},
}: TextProps,
ref
) => {
const Component = asChild ? Slot : as

View File

@@ -3,6 +3,9 @@ import * as React from "react"
import { clx } from "@/utils/clx"
import { inputBaseStyles } from "../input"
/**
* This component is based on the `textarea` element and supports all of its props
*/
const Textarea = React.forwardRef<
HTMLTextAreaElement,
React.ComponentPropsWithoutRef<"textarea">

View File

@@ -71,8 +71,18 @@ type TimeInputProps = Omit<
"label" | "shouldForceLeadingZeros" | "description" | "errorMessage"
>
/**
* This component is based on the `div` element and supports all of its props.
*/
const TimeInput = React.forwardRef<HTMLDivElement, TimeInputProps>(
({ hourCycle, ...props }: TimeInputProps, ref) => {
({
/**
* The time's format. If no value is specified, the format is
* set based on the user's locale.
*/
hourCycle,
...props
}: TimeInputProps, ref) => {
const innerRef = React.useRef<HTMLDivElement>(null)
React.useImperativeHandle<HTMLDivElement | null, HTMLDivElement | null>(

View File

@@ -28,7 +28,7 @@ const ToastViewport = React.forwardRef<
{...props}
/>
))
ToastViewport.displayName = "ToastViewport"
ToastViewport.displayName = "Toast.Viewport"
interface ActionProps {
label: string
@@ -45,6 +45,11 @@ interface ToastProps
disableDismiss?: boolean
}
/**
* This component is based on the [Radix UI Toast](https://www.radix-ui.com/primitives/docs/components/toast) primitives.
*
* @excludeExternal
*/
const Toast = React.forwardRef<
React.ElementRef<typeof Primitives.Root>,
ToastProps
@@ -52,13 +57,28 @@ const Toast = React.forwardRef<
(
{
className,
/**
* The toast's style.
*/
variant,
/**
* The toast's title.
*/
title,
/**
* The toast's content.
*/
description,
/**
* The actions to show in the toast as buttons.
*/
action,
/**
* Whether to hide the Close button.
*/
disableDismiss = false,
...props
},
}: ToastProps,
ref
) => {
let Icon = undefined

View File

@@ -17,6 +17,11 @@ interface TooltipProps
maxWidth?: number
}
/**
* This component is based on the [Radix UI Tooltip](https://www.radix-ui.com/primitives/docs/components/tooltip) primitive.
*
* @excludeExternal
*/
const Tooltip = ({
children,
content,
@@ -24,6 +29,9 @@ const Tooltip = ({
defaultOpen,
onOpenChange,
delayDuration,
/**
* The maximum width of the tooltip.
*/
maxWidth = 220,
className,
side,

View File

@@ -6,7 +6,7 @@ import { Input } from "@/components/input"
import { Label } from "@/components/label"
import { Prompt } from "@/components/prompt"
export type RenderPromptProps = {
export interface RenderPromptProps {
open: boolean
title: string
description: string
@@ -18,13 +18,37 @@ export type RenderPromptProps = {
}
export const RenderPrompt = ({
/**
* @ignore
*/
open,
/**
* The prompt's title.
*/
title,
/**
* The prompt's description.
*/
description,
/**
* The text the user has to input in order to confirm the action.
*/
verificationText,
/**
* The label for the Cancel button.
*/
cancelText = "Cancel",
/**
* Label for the Confirm button.
*/
confirmText = "Confirm",
/**
* @ignore
*/
onConfirm,
/**
* @ignore
*/
onCancel,
}: RenderPromptProps) => {
const [userInput, setUserInput] = React.useState("")
@@ -108,3 +132,4 @@ export const RenderPrompt = ({
</Prompt>
)
}
RenderPrompt.displayName = "RenderPrompt"

View File

@@ -1,6 +1,12 @@
export type ProgressStatus = "not-started" | "in-progress" | "completed"
export type DateRange = {
/**
* The range's start date.
*/
from: Date | undefined
/**
* The range's end date.
*/
to?: Date | undefined
}