# TiDB Cloud UIKit - Complete Documentation

This file contains comprehensive documentation for the TiDB Cloud UIKit library including:
- Complete component documentation with usage examples
- Business components for common patterns
- React hooks documentation
- Icon library reference

All code examples use production npm package imports:
- @tidbcloud/uikit - Core components and hooks
- @tidbcloud/uikit/biz - Business components
- @tidbcloud/uikit/icons - Icon components

================================================================================

## QUICK REFERENCE

### Import Examples

```tsx
// Core components
import { Button, TextInput, Select, Modal, Table } from '@tidbcloud/uikit';

// Business components
import { Form, FormTextInput, ProTable, CodeBlock } from '@tidbcloud/uikit/biz';

// Hooks
import { useDisclosure, useClipboard, useLocalStorage } from '@tidbcloud/uikit';

// Icons
import { IconAlertCircle, IconCheck, IconX } from '@tidbcloud/uikit/icons';
```


## PRIMITIVE COMPONENTS
Basic UI components from @tidbcloud/uikit
Primary Package: @tidbcloud/uikit

--------------------------------------------------------------------------------

### Accordion
Package: @tidbcloud/uikit
Import: import { Accordion } from '@tidbcloud/uikit';
Description: Divide content into collapsible sections.

Divide content into collapsible sections.

## Usage

Accordion allows users to expand and collapse sections of content. It helps manage large amounts of information in a limited space by showing only the section headers initially and revealing content on interaction.

```tsx

const data = [
  {
    emoji: '🍎',
    value: 'Apples',
    description: 'Crisp and refreshing fruit. Apples are known for their versatility and nutritional benefits.'
  },
  {
    emoji: '🍌',
    value: 'Bananas',
    description:
      'Naturally sweet and potassium-rich fruit. Bananas are a popular choice for their energy-boosting properties.'
  },
  {
    emoji: '🥦',
    value: 'Broccoli',
    description: 'Nutrient-packed green vegetable. Broccoli is packed with vitamins, minerals, and fiber.'
  }
]

function Demo() {
  const items = data.map((item) => (
    <Accordion.Item key={item.value} value={item.value}>
      <Accordion.Control icon={item.emoji}>{item.value}</Accordion.Control>
      <Accordion.Panel>{item.description}</Accordion.Panel>
    </Accordion.Item>
  ))

  return <Accordion defaultValue="Apples">{items}</Accordion>
}
```

## Multiple items open

Set `multiple` prop to allow multiple items to be opened at the same time:

```tsx

function Demo() {
  return (
    <Accordion multiple defaultValue={['item-1', 'item-2']}>
      <Accordion.Item value="item-1">
        <Accordion.Control>First item</Accordion.Control>
        <Accordion.Panel>First panel content</Accordion.Panel>
      </Accordion.Item>
      <Accordion.Item value="item-2">
        <Accordion.Control>Second item</Accordion.Control>
        <Accordion.Panel>Second panel content</Accordion.Panel>
      </Accordion.Item>
    </Accordion>
  )
}
```

## Controlled

```tsx

function Demo() {
  const [value, setValue] = useState<string | null>(null)

  return (
    <Accordion value={value} onChange={setValue}>
      <Accordion.Item value="item-1">
        <Accordion.Control>Item 1</Accordion.Control>
        <Accordion.Panel>Panel 1</Accordion.Panel>
      </Accordion.Item>
      <Accordion.Item value="item-2">
        <Accordion.Control>Item 2</Accordion.Control>
        <Accordion.Panel>Panel 2</Accordion.Panel>
      </Accordion.Item>
    </Accordion>
  )
}
```

## Variants

Accordion supports several variants: `default`, `contained`, `filled`, and `separated`.

```tsx

function Demo() {
  return (
    <Accordion variant="contained" radius="md">
      <Accordion.Item value="item-1">
        <Accordion.Control>Item 1</Accordion.Control>
        <Accordion.Panel>Panel 1</Accordion.Panel>
      </Accordion.Item>
    </Accordion>
  )
}
```

## Disabled items

Set the `disabled` prop on `Accordion.Control` to disable it:

```tsx

function Demo() {
  return (
    <Accordion>
      <Accordion.Item value="item-1">
        <Accordion.Control>Enabled item</Accordion.Control>
        <Accordion.Panel>Content</Accordion.Panel>
      </Accordion.Item>
      <Accordion.Item value="item-2">
        <Accordion.Control disabled>Disabled item</Accordion.Control>
        <Accordion.Panel>Content</Accordion.Panel>
      </Accordion.Item>
    </Accordion>
  )
}
```

## Props

| Prop                   | Type                                                  | Default     | Description                                           |
| ---------------------- | ----------------------------------------------------- | ----------- | ----------------------------------------------------- |
| chevron                | `React.ReactNode`                                     | -           | Custom chevron icon                                   |
| chevronPosition        | `'left' \| 'right'`                                   | `'right'`   | Position of the chevron relative to the item label    |
| chevronSize            | `number \| string`                                    | `24`        | Size of the chevron icon container                    |
| defaultValue           | `string \| string[] \| null`                          | -           | Uncontrolled component default value                  |
| disableChevronRotation | `boolean`                                             | -           | If set, chevron rotation is disabled                  |
| loop                   | `boolean`                                             | `true`      | If set, arrow keys loop through items                 |
| multiple               | `boolean`                                             | -           | If set, multiple items can be opened at the same time |
| onChange               | `(value) => void`                                     | -           | Called when value changes                             |
| order                  | `2 \| 3 \| 4 \| 5 \| 6`                               | -           | Heading order, has no effect on visuals               |
| radius                 | `MantineRadius`                                       | -           | Border radius                                         |
| transitionDuration     | `number`                                              | `200`       | Transition duration in ms                             |
| value                  | `string \| string[] \| null`                          | -           | Controlled component value                            |
| variant                | `'default' \| 'contained' \| 'filled' \| 'separated'` | `'default'` | Visual variant                                        |

--------------------------------------------------------------------------------

### ActionIcon
Package: @tidbcloud/uikit
Import: import { ActionIcon } from '@tidbcloud/uikit';
Description: Icon button component.

Icon button component.

## Usage

```tsx

function Demo() {
  return (
    <ActionIcon aria-label="Settings">
      <IconAdjustments style={{ width: '70%', height: '70%' }} stroke={1.5} />
    </ActionIcon>
  )
}
```

## Variants

ActionIcon supports several variants: `filled`, `light`, `outline`, `transparent`, `white`, `subtle`, `default`, and `gradient`.

```tsx

function Demo() {
  return (
    <Group>
      <ActionIcon variant="filled" aria-label="Filled">
        <IconHeart size={18} />
      </ActionIcon>
      <ActionIcon variant="light" aria-label="Light">
        <IconHeart size={18} />
      </ActionIcon>
      <ActionIcon variant="outline" aria-label="Outline">
        <IconHeart size={18} />
      </ActionIcon>
      <ActionIcon variant="default" aria-label="Default">
        <IconHeart size={18} />
      </ActionIcon>
    </Group>
  )
}
```

## Gradient

```tsx

function Demo() {
  return (
    <ActionIcon
      variant="gradient"
      size="xl"
      aria-label="Gradient action icon"
      gradient={{ from: 'cyan', to: 'blue', deg: 90 }}
    >
      <IconHeart />
    </ActionIcon>
  )
}
```

## Size

You can use any valid CSS value in `size` prop. When `size` is a number, the value is treated as `px` units.

```tsx

function Demo() {
  return (
    <ActionIcon size={42} variant="default" aria-label="ActionIcon with size as a number">
      <IconHeart size={24} />
    </ActionIcon>
  )
}
```

## Loading state

When `loading` prop is set, ActionIcon will be disabled and a Loader will be rendered in the center:

```tsx

function Demo() {
  return (
    <ActionIcon loading aria-label="Loading">
      <IconHeart size={18} />
    </ActionIcon>
  )
}
```

## Disabled state

```tsx

function Demo() {
  return (
    <ActionIcon disabled aria-label="Disabled">
      <IconHeart size={18} />
    </ActionIcon>
  )
}
```

## ActionIcon.Group

```tsx

function Demo() {
  return (
    <ActionIcon.Group>
      <ActionIcon variant="default" size="lg" aria-label="Gallery">
        <IconPhoto size={20} />
      </ActionIcon>
      <ActionIcon variant="default" size="lg" aria-label="Settings">
        <IconSettings size={20} />
      </ActionIcon>
      <ActionIcon variant="default" size="lg" aria-label="Likes">
        <IconHeart size={20} />
      </ActionIcon>
    </ActionIcon.Group>
  )
}
```

## Props

| Prop        | Type                    | Default    | Description                                                   |
| ----------- | ----------------------- | ---------- | ------------------------------------------------------------- |
| children    | `React.ReactNode`       | -          | Icon element                                                  |
| color       | `MantineColor`          | -          | Key of `theme.colors` or any valid CSS color                  |
| disabled    | `boolean`               | -          | Sets disabled attribute                                       |
| gradient    | `MantineGradient`       | -          | Gradient values used with `variant="gradient"`                |
| loading     | `boolean`               | -          | If set, Loader component is displayed instead of the children |
| loaderProps | `LoaderProps`           | -          | Props passed to the Loader component                          |
| radius      | `MantineRadius`         | -          | Border radius                                                 |
| size        | `number \| MantineSize` | `'md'`     | Controls width and height                                     |
| variant     | `string`                | `'filled'` | Visual variant                                                |

--------------------------------------------------------------------------------

### Affix
Package: @tidbcloud/uikit
Import: import { Affix } from '@tidbcloud/uikit';
Description: Renders children inside portal at fixed position.

Renders children inside portal at fixed position.

## Usage

`Affix` renders a div element with a fixed position inside the Portal component. Use it to display elements fixed at any position on the screen, for example, scroll to top button:

```tsx

function Demo() {
  const [scroll, scrollTo] = useWindowScroll()

  return (
    <>
      <Affix position={{ bottom: 20, right: 20 }}>
        <Transition transition="slide-up" mounted={scroll.y > 0}>
          {(transitionStyles) => (
            <Button leftSection={<IconArrowUp size={16} />} style={transitionStyles} onClick={() => scrollTo({ y: 0 })}>
              Scroll to top
            </Button>
          )}
        </Transition>
      </Affix>
    </>
  )
}
```

## Position

Use `position` prop to control the position of the Affix:

```tsx

function Demo() {
  return (
    <Affix position={{ bottom: 20, left: 20 }}>
      <Button>Bottom left</Button>
    </Affix>
  )
}
```

## Props

| Prop         | Type                                                               | Default                   | Description                                                   |
| ------------ | ------------------------------------------------------------------ | ------------------------- | ------------------------------------------------------------- |
| children     | `React.ReactNode`                                                  | -                         | Content to render inside Affix                                |
| portalProps  | `PortalProps`                                                      | -                         | Props passed to the Portal component                          |
| position     | `{ top?: number; right?: number; bottom?: number; left?: number }` | `{ bottom: 0, right: 0 }` | Affix position on screen                                      |
| withinPortal | `boolean`                                                          | `true`                    | Determines whether component should be rendered within Portal |
| zIndex       | `number`                                                           | -                         | Root element z-index property                                 |

--------------------------------------------------------------------------------

### Alert
Package: @tidbcloud/uikit
Import: import { Alert } from '@tidbcloud/uikit';
Description: Attract user attention with important static message.

Attract user attention with important static message.

## Usage

```tsx

function Demo() {
  return (
    <Alert icon={<IconInfoCircle />} title="Alert title" color="blue">
      Something important happened! You should check it out.
    </Alert>
  )
}
```

## Variants

Alert supports several variants: `filled`, `light`, `outline`, `default`, and `transparent`.

```tsx

function Demo() {
  return (
    <Stack>
      <Alert variant="filled" color="blue" title="Filled variant">
        This is a filled alert
      </Alert>
      <Alert variant="light" color="blue" title="Light variant">
        This is a light alert
      </Alert>
      <Alert variant="outline" color="blue" title="Outline variant">
        This is an outline alert
      </Alert>
    </Stack>
  )
}
```

## With close button

Set `withCloseButton` prop to display a close button:

```tsx

function Demo() {
  return (
    <Alert
      icon={<IconInfoCircle />}
      title="Dismissible alert"
      withCloseButton
      closeButtonLabel="Dismiss"
      onClose={() => console.log('Alert closed')}
    >
      Click the X button to dismiss this alert.
    </Alert>
  )
}
```

## Accessibility

- Root element role is set to `alert`
- `aria-describedby` is set to body element id, `aria-labelledby` is set to title element id if `title` is provided
- Set `closeButtonLabel` prop to make close button accessible

```tsx

// ✅ Accessible
function Valid() {
  return <Alert withCloseButton closeButtonLabel="Dismiss" />
}
```

## Props

| Prop             | Type              | Default   | Description                                         |
| ---------------- | ----------------- | --------- | --------------------------------------------------- |
| children         | `React.ReactNode` | -         | Alert body content                                  |
| closeButtonLabel | `string`          | -         | Close button aria-label                             |
| color            | `MantineColor`    | -         | Key of theme.colors or any valid CSS color          |
| icon             | `React.ReactNode` | -         | Icon displayed next to the title                    |
| onClose          | `() => void`      | -         | Called when the close button is clicked             |
| radius           | `MantineRadius`   | -         | Border radius                                       |
| title            | `React.ReactNode` | -         | Alert title                                         |
| variant          | `string`          | `'light'` | Visual variant                                      |
| withCloseButton  | `boolean`         | `false`   | Determines whether close button should be displayed |

--------------------------------------------------------------------------------

### AlphaSlider
Package: @tidbcloud/uikit
Import: import { AlphaSlider } from '@tidbcloud/uikit';
Description: Pick alpha (opacity) value for colors.

Pick alpha (opacity) value for colors.

## Usage

`AlphaSlider` is used to select the alpha (opacity) channel for colors. It is typically used alongside `ColorPicker` or `HueSlider`.

```tsx

function Demo() {
  const [value, setValue] = useState(1)

  return (
    <>
      <Text mb="xs">Alpha value: {value}</Text>
      <AlphaSlider color="#1c7ed6" value={value} onChange={setValue} />
    </>
  )
}
```

## With color

The `color` prop determines the color displayed in the gradient:

```tsx

function Demo() {
  return (
    <Stack>
      <AlphaSlider color="#f00" />
      <AlphaSlider color="#0f0" />
      <AlphaSlider color="#00f" />
    </Stack>
  )
}
```

## Props

| Prop        | Type                      | Default | Description                                  |
| ----------- | ------------------------- | ------- | -------------------------------------------- |
| color       | `string`                  | -       | Color displayed in the alpha slider gradient |
| onChange    | `(value: number) => void` | -       | Called when value changes                    |
| onChangeEnd | `(value: number) => void` | -       | Called when user stops dragging              |
| size        | `MantineSize`             | `'md'`  | Controls slider height                       |
| value       | `number`                  | -       | Current alpha value (0-1)                    |

--------------------------------------------------------------------------------

### Anchor
Package: @tidbcloud/uikit
Import: import { Anchor } from '@tidbcloud/uikit';
Description: Display link with theme styles.

Display link with theme styles.

## Usage

```tsx

function Demo() {
  return (
    <Anchor href="https://mantine.dev/" target="_blank">
      Anchor component
    </Anchor>
  )
}
```

## Underline

Use `underline` prop to configure `text-decoration` property:

- `always` - link is always underlined
- `hover` - link is underlined on hover
- `never` - link is never underlined
- `not-hover` - link is underlined when not hovered

```tsx

function Demo() {
  return (
    <Group>
      <Anchor href="#" underline="always">
        Underline always
      </Anchor>
      <Anchor href="#" underline="hover">
        Underline hover
      </Anchor>
      <Anchor href="#" underline="never">
        Underline never
      </Anchor>
    </Group>
  )
}
```

## Text props

`Anchor` supports all Text component props:

```tsx

function Demo() {
  return (
    <Anchor variant="gradient" gradient={{ from: 'pink', to: 'yellow' }} fw={500} fz="lg" href="#">
      A link with pink to yellow gradient
    </Anchor>
  )
}
```

## Polymorphic component

Anchor is a polymorphic component – its default root element is `a`, but it can be changed to any other element or component:

```tsx

function Demo() {
  return (
    <Anchor component={Link} href="/">
      Link with Next.js Link
    </Anchor>
  )
}
```

## Props

| Prop      | Type                                            | Default   | Description                                                |
| --------- | ----------------------------------------------- | --------- | ---------------------------------------------------------- |
| children  | `React.ReactNode`                               | -         | Link content                                               |
| gradient  | `MantineGradient`                               | -         | Gradient configuration for `variant="gradient"`            |
| href      | `string`                                        | -         | Link URL                                                   |
| size      | `MantineSize`                                   | -         | Controls font-size and line-height                         |
| target    | `string`                                        | -         | Link target attribute                                      |
| underline | `'always' \| 'hover' \| 'never' \| 'not-hover'` | `'hover'` | Defines when text-decoration: underline styles are applied |

--------------------------------------------------------------------------------

### AnimatedNumber
Package: @tidbcloud/uikit
Import: import { AnimatedNumber } from '@tidbcloud/uikit';
Description: Animated number component with smooth transitions.

Animated number component with smooth transitions.

## Usage

`AnimatedNumber` displays numbers with smooth animations when values change. It's powered by [number-flow](https://number-flow.barvian.me/).

```tsx

function Demo() {
  const [value, setValue] = useState(1234)

  return (
    <>
      <AnimatedNumber value={value} />
      <Group mt="md">
        <Button onClick={() => setValue((v) => v + 100)}>Increase</Button>
        <Button onClick={() => setValue((v) => v - 100)}>Decrease</Button>
      </Group>
    </>
  )
}
```

## Formatting

You can use standard NumberFlowProps to format the output:

```tsx

function Demo() {
  return <AnimatedNumber value={1234.56} format={{ style: 'currency', currency: 'USD' }} />
}
```

## AnimatedNumber.Group

If an `AnimatedNumber` affects another `AnimatedNumber`'s position, you can wrap them in an `AnimatedNumber.Group` to properly sync their transitions:

```tsx

function Demo() {
  return (
    <AnimatedNumber.Group>
      <AnimatedNumber value={100} />
      <span> / </span>
      <AnimatedNumber value={200} />
    </AnimatedNumber.Group>
  )
}
```

## Style props

`AnimatedNumber` supports all Box component style props:

```tsx

function Demo() {
  return <AnimatedNumber value={9999} fz="xl" fw={700} c="blue" />
}
```

## Props

| Prop        | Type                       | Default | Description                           |
| ----------- | -------------------------- | ------- | ------------------------------------- |
| value       | `number`                   | -       | The number to display                 |
| format      | `Intl.NumberFormatOptions` | -       | Formatting options for the number     |
| locales     | `string \| string[]`       | -       | Locale(s) for number formatting       |
| animated    | `boolean`                  | `true`  | Whether to animate value changes      |
| trend       | `boolean`                  | -       | Highlight positive/negative changes   |
| ...BoxProps | -                          | -       | All Box component props are supported |

--------------------------------------------------------------------------------

### AppShell
Package: @tidbcloud/uikit
Import: import { AppShell } from '@tidbcloud/uikit';
Description: Responsive shell for your application with header, navbar, aside and footer.

Responsive shell for your application with header, navbar, aside and footer.

## Usage

`AppShell` is a layout component that can be used to implement a common Header / Navbar / Footer / Aside layout pattern. All `AppShell` components have `position: fixed` style.

```tsx

function Demo() {
  const [opened, { toggle }] = useDisclosure()

  return (
    <AppShell
      padding="md"
      header={{ height: 60 }}
      navbar={{
        width: 300,
        breakpoint: 'sm',
        collapsed: { mobile: !opened }
      }}
    >
      <AppShell.Header>
        <Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" />
        <div>Logo</div>
      </AppShell.Header>

      <AppShell.Navbar>Navbar</AppShell.Navbar>

      <AppShell.Main>Main content</AppShell.Main>
    </AppShell>
  )
}
```

## AppShell components

- `AppShell` – root component that wraps all other sections
- `AppShell.Header` – fixed header at the top
- `AppShell.Navbar` – fixed navbar on the left
- `AppShell.Aside` – fixed aside on the right
- `AppShell.Footer` – fixed footer at the bottom
- `AppShell.Main` – main content area
- `AppShell.Section` – utility for grouping content inside Navbar or Aside

## Responsive navbar

```tsx

function Demo() {
  const [opened, { toggle }] = useDisclosure()

  return (
    <AppShell
      header={{ height: 60 }}
      navbar={{ width: 300, breakpoint: 'sm', collapsed: { mobile: !opened } }}
      padding="md"
    >
      <AppShell.Header>
        <Group h="100%" px="md">
          <Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" />
          Logo
        </Group>
      </AppShell.Header>

      <AppShell.Navbar p="md">
        <NavLink label="Home" />
        <NavLink label="Dashboard" />
        <NavLink label="Settings" />
      </AppShell.Navbar>

      <AppShell.Main>Main content</AppShell.Main>
    </AppShell>
  )
}
```

## With aside

```tsx

function Demo() {
  return (
    <AppShell
      header={{ height: 60 }}
      navbar={{ width: 300, breakpoint: 'sm' }}
      aside={{ width: 300, breakpoint: 'md' }}
      padding="md"
    >
      <AppShell.Header>Header</AppShell.Header>
      <AppShell.Navbar>Navbar</AppShell.Navbar>
      <AppShell.Main>Main</AppShell.Main>
      <AppShell.Aside>Aside</AppShell.Aside>
    </AppShell>
  )
}
```

## Props

| Prop               | Type                          | Default     | Description                                         |
| ------------------ | ----------------------------- | ----------- | --------------------------------------------------- |
| aside              | `AppShellAsideConfiguration`  | -           | Aside configuration                                 |
| disabled           | `boolean`                     | -           | If set, Navbar, Aside, Header and Footer are hidden |
| footer             | `AppShellFooterConfiguration` | -           | Footer configuration                                |
| header             | `AppShellHeaderConfiguration` | -           | Header configuration                                |
| layout             | `'default' \| 'alt'`          | `'default'` | Layout arrangement                                  |
| navbar             | `AppShellNavbarConfiguration` | -           | Navbar configuration                                |
| padding            | `MantineSpacing`              | -           | Padding of the main section                         |
| transitionDuration | `number`                      | -           | Duration of transitions in ms                       |
| withBorder         | `boolean`                     | `true`      | If set, components have a border                    |
| zIndex             | `number`                      | `100`       | z-index of all elements                             |

--------------------------------------------------------------------------------

### AspectRatio
Package: @tidbcloud/uikit
Import: import { AspectRatio } from '@tidbcloud/uikit';
Description: Maintain responsive consistent width/height ratio.

Maintain responsive consistent width/height ratio.

## Usage

`AspectRatio` maintains a consistent width/height ratio. It can be used to display images, maps, videos and other media.

```tsx

function Demo() {
  return (
    <AspectRatio ratio={16 / 9} maw={400}>
      <img src="https://example.com/image.png" alt="Example" />
    </AspectRatio>
  )
}
```

## Map embed

```tsx

function Demo() {
  return (
    <AspectRatio ratio={16 / 9}>
      <iframe src="https://www.google.com/maps/embed?..." title="Google map" style={{ border: 0 }} />
    </AspectRatio>
  )
}
```

## Video embed

```tsx

function Demo() {
  return (
    <AspectRatio ratio={16 / 9}>
      <iframe
        src="https://www.youtube.com/embed/VIDEO_ID"
        title="YouTube video player"
        style={{ border: 0 }}
        allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
        allowFullScreen
      />
    </AspectRatio>
  )
}
```

## Inside flex container

When used inside a flex container, set `width` or `flex` property:

```tsx

function Demo() {
  return (
    <div style={{ display: 'flex' }}>
      <AspectRatio ratio={1} flex="0 0 100px">
        <Image src="avatar.png" alt="Avatar" />
      </AspectRatio>
    </div>
  )
}
```

## Props

| Prop     | Type              | Default | Description                                          |
| -------- | ----------------- | ------- | ---------------------------------------------------- |
| children | `React.ReactNode` | -       | Content to display inside the aspect ratio container |
| ratio    | `number`          | `1`     | Aspect ratio, e.g., `16 / 9`, `4 / 3`, `1920 / 1080` |

--------------------------------------------------------------------------------

### Autocomplete
Package: @tidbcloud/uikit
Import: import { Autocomplete } from '@tidbcloud/uikit';
Description: Autocomplete user input with any list of options.

Autocomplete user input with any list of options.

## Usage

`Autocomplete` provides user a list of suggestions based on the input. However, user is not limited to suggestions and can type anything.

```tsx

function Demo() {
  return (
    <Autocomplete
      label="Your favorite library"
      placeholder="Pick value or enter anything"
      data={['React', 'Angular', 'Vue', 'Svelte']}
    />
  )
}
```

## Controlled

```tsx

function Demo() {
  const [value, setValue] = useState('')
  return <Autocomplete data={['React', 'Angular']} value={value} onChange={setValue} />
}
```

## Data format

Data can be an array of strings or objects:

```tsx

function Demo() {
  return (
    <Autocomplete
      data={[
        { value: 'react', label: 'React' },
        { value: 'angular', label: 'Angular' }
      ]}
    />
  )
}
```

## Grouped options

```tsx

function Demo() {
  return (
    <Autocomplete
      label="Your favorite library"
      placeholder="Pick value or enter anything"
      data={[
        { group: 'Frontend', items: ['React', 'Angular'] },
        { group: 'Backend', items: ['Express', 'Django'] }
      ]}
    />
  )
}
```

## Clearable

Set `clearable` prop to display the clear button:

```tsx

function Demo() {
  return <Autocomplete clearable defaultValue="React" data={['React', 'Angular']} label="Clearable autocomplete" />
}
```

## Disabled

```tsx

function Demo() {
  return (
    <Autocomplete
      label="Your favorite library"
      placeholder="Pick value or enter anything"
      data={['React', 'Angular', 'Vue', 'Svelte']}
      disabled
    />
  )
}
```

## Props

| Prop              | Type                                             | Default | Description                              |
| ----------------- | ------------------------------------------------ | ------- | ---------------------------------------- |
| clearable         | `boolean`                                        | -       | If set, the clear button is displayed    |
| data              | `string[] \| { value: string; label: string }[]` | -       | Data for options                         |
| defaultValue      | `string`                                         | -       | Default value for uncontrolled component |
| description       | `React.ReactNode`                                | -       | Input description                        |
| disabled          | `boolean`                                        | -       | Sets disabled attribute                  |
| error             | `React.ReactNode`                                | -       | Error message                            |
| filter            | `(options, search) => options`                   | -       | Custom filter function                   |
| label             | `React.ReactNode`                                | -       | Input label                              |
| limit             | `number`                                         | -       | Maximum number of options displayed      |
| maxDropdownHeight | `number`                                         | `250`   | Max dropdown height                      |
| onChange          | `(value: string) => void`                        | -       | Called when value changes                |
| placeholder       | `string`                                         | -       | Input placeholder                        |
| value             | `string`                                         | -       | Controlled component value               |

--------------------------------------------------------------------------------

### Avatar
Package: @tidbcloud/uikit
Import: import { Avatar } from '@tidbcloud/uikit';
Description: Display user profile image, initials or fallback icon.

Display user profile image, initials or fallback icon.

## Usage

```tsx

function Demo() {
  return (
    <>
      {/* With image */}
      <Avatar src="avatar.png" alt="it's me" />

      {/* Default placeholder */}
      <Avatar radius="xl" />

      {/* Letters with xl radius */}
      <Avatar color="cyan" radius="xl">
        MK
      </Avatar>

      {/* Custom placeholder icon */}
      <Avatar color="blue" radius="sm">
        <IconStar size={20} />
      </Avatar>
    </>
  )
}
```

## Initials

To display initials instead of the default placeholder, set `name` prop:

```tsx

function Demo() {
  return (
    <Group>
      <Avatar name="John Doe" color="initials" />
      <Avatar name="Jane Smith" color="initials" />
    </Group>
  )
}
```

## Placeholder

If the image cannot be loaded or not provided, `Avatar` will display a placeholder:

```tsx

function Demo() {
  return (
    <>
      {/* Default placeholder */}
      <Avatar src={null} alt="no image here" />

      {/* Placeholder with initials */}
      <Avatar src={null} alt="Vitaly Rtishchev" color="red">
        VR
      </Avatar>

      {/* Placeholder with custom icon */}
      <Avatar color="blue" radius="xl">
        <IconStar size={20} />
      </Avatar>
    </>
  )
}
```

## Avatar.Group

`Avatar.Group` component combines multiple avatars into a stack:

```tsx

function Demo() {
  return (
    <Avatar.Group>
      <Avatar src="image1.png" />
      <Avatar src="image2.png" />
      <Avatar src="image3.png" />
      <Avatar>+5</Avatar>
    </Avatar.Group>
  )
}
```

## Props

| Prop     | Type                         | Default    | Description                                             |
| -------- | ---------------------------- | ---------- | ------------------------------------------------------- |
| alt      | `string`                     | -          | Image alt attribute, also used as title for placeholder |
| children | `React.ReactNode`            | -          | Avatar placeholder content                              |
| color    | `MantineColor \| 'initials'` | -          | Key of theme.colors or any valid CSS color              |
| name     | `string`                     | -          | Name used to display initials                           |
| radius   | `MantineRadius`              | -          | Border radius                                           |
| size     | `number \| MantineSize`      | `'md'`     | Width and height of the avatar                          |
| src      | `string \| null`             | -          | Image URL                                               |
| variant  | `string`                     | `'filled'` | Visual variant                                          |

--------------------------------------------------------------------------------

### BackgroundImage
Package: @tidbcloud/uikit
Import: import { BackgroundImage } from '@tidbcloud/uikit';
Description: Displays image as background.

Displays image as background.

## Usage

```tsx

function Demo() {
  return (
    <Box maw={300} mx="auto">
      <BackgroundImage src="https://example.com/image.png" radius="md">
        <Center p="md">
          <Text c="white">
            BackgroundImage component can be used to add any content on image. It is useful for hero headers and other
            similar sections.
          </Text>
        </Center>
      </BackgroundImage>
    </Box>
  )
}
```

## Polymorphic component

BackgroundImage is a polymorphic component – its default root element is `div`, but it can be changed:

```tsx

function Demo() {
  return <BackgroundImage component="button" src="image.png" />
}
```

## Props

| Prop     | Type              | Default  | Description                                      |
| -------- | ----------------- | -------- | ------------------------------------------------ |
| children | `React.ReactNode` | -        | Content to render on top of the background image |
| radius   | `MantineRadius`   | -        | Border radius                                    |
| src      | `string`          | required | Image URL                                        |

--------------------------------------------------------------------------------

### Badge
Package: @tidbcloud/uikit
Import: import { Badge } from '@tidbcloud/uikit';
Description: Display badge, pill or tag.

Display badge, pill or tag.

## Usage

```tsx

function Demo() {
  return <Badge>Badge</Badge>
}
```

## Variants

Badge supports several variants: `filled`, `light`, `outline`, `dot`, `transparent`, `white`, and `default`.

```tsx

function Demo() {
  return (
    <Group>
      <Badge variant="filled">Filled</Badge>
      <Badge variant="light">Light</Badge>
      <Badge variant="outline">Outline</Badge>
      <Badge variant="dot">Dot</Badge>
    </Group>
  )
}
```

## Gradient

```tsx

function Demo() {
  return (
    <Badge size="xl" variant="gradient" gradient={{ from: 'cyan', to: 'blue', deg: 90 }}>
      Gradient badge
    </Badge>
  )
}
```

## Rounded

Set `circle` prop to make badge width equal to its height:

```tsx

function Demo() {
  return (
    <Group>
      <Badge size="xs" circle>
        1
      </Badge>
      <Badge size="sm" circle>
        7
      </Badge>
      <Badge size="md" circle>
        9
      </Badge>
      <Badge size="lg" circle>
        3
      </Badge>
    </Group>
  )
}
```

## Left and right sections

```tsx

function Demo() {
  const icon = <IconAt size={12} />
  return (
    <Group>
      <Badge leftSection={icon}>With left section</Badge>
      <Badge rightSection={icon}>With right section</Badge>
    </Group>
  )
}
```

## Full width

Set `fullWidth` to make badge span full width of its parent:

```tsx

function Demo() {
  return <Badge fullWidth>Full width badge</Badge>
}
```

## Props

| Prop         | Type              | Default    | Description                                         |
| ------------ | ----------------- | ---------- | --------------------------------------------------- |
| children     | `React.ReactNode` | -          | Main badge content                                  |
| circle       | `boolean`         | -          | If set, badge min-width becomes equal to its height |
| color        | `MantineColor`    | -          | Key of theme.colors or any valid CSS color          |
| fullWidth    | `boolean`         | -          | If set, badge takes 100% width of its parent        |
| gradient     | `MantineGradient` | -          | Gradient configuration for `variant="gradient"`     |
| leftSection  | `React.ReactNode` | -          | Content displayed on the left side                  |
| radius       | `MantineRadius`   | -          | Border radius                                       |
| rightSection | `React.ReactNode` | -          | Content displayed on the right side                 |
| size         | `MantineSize`     | `'md'`     | Controls font-size, height and padding              |
| variant      | `string`          | `'filled'` | Visual variant                                      |

--------------------------------------------------------------------------------

### Blockquote
Package: @tidbcloud/uikit
Import: import { Blockquote } from '@tidbcloud/uikit';
Description: Blockquote with optional cite.

Blockquote with optional cite.

## Usage

```tsx

function Demo() {
  return (
    <Blockquote cite="– Forrest Gump" icon={<IconInfoCircle />} mt="xl">
      Life is like an npm install – you never know what you are going to get.
    </Blockquote>
  )
}
```

## Without icon

```tsx

function Demo() {
  return <Blockquote cite="– Someone famous">This is a blockquote without an icon.</Blockquote>
}
```

## Colors

```tsx

function Demo() {
  return (
    <Stack>
      <Blockquote color="blue">Blue blockquote</Blockquote>
      <Blockquote color="red">Red blockquote</Blockquote>
      <Blockquote color="green">Green blockquote</Blockquote>
    </Stack>
  )
}
```

## Props

| Prop     | Type              | Default | Description                                |
| -------- | ----------------- | ------- | ------------------------------------------ |
| children | `React.ReactNode` | -       | Quote content                              |
| cite     | `React.ReactNode` | -       | Reference to a cited quote                 |
| color    | `MantineColor`    | -       | Key of theme.colors or any valid CSS color |
| icon     | `React.ReactNode` | -       | Icon displayed at the top left side        |
| iconSize | `number`          | -       | Icon width and height                      |
| radius   | `MantineRadius`   | -       | Border radius                              |

--------------------------------------------------------------------------------

### Box
Package: @tidbcloud/uikit
Import: import { Box } from '@tidbcloud/uikit';
Description: Base component for all Mantine components.

Base component for all Mantine components.

## Usage

`Box` component is used as a base for all other components. `Box` supports the following features:

- `component` prop for polymorphic behavior
- Style props (padding, margin, colors, etc.)
- `style` prop for custom styles

```tsx

function Demo() {
  return (
    <Box bg="red.5" my="xl" component="a" href="/">
      My component
    </Box>
  )
}
```

## Style props

Box supports all style props:

```tsx

function Demo() {
  return (
    <Box p="md" m="lg" bg="blue.1" c="blue.9" ta="center" fz="lg" fw={700}>
      Box with style props
    </Box>
  )
}
```

## Polymorphic component

Box is a polymorphic component – its default root element is `div`, but it can be changed to any other element:

```tsx

function Demo() {
  return (
    <Box component="span" c="red">
      I'm a span element
    </Box>
  )
}
```

## Common style props

| Prop                                    | CSS Property |
| --------------------------------------- | ------------ |
| `m`, `mt`, `mb`, `ml`, `mr`, `mx`, `my` | margin       |
| `p`, `pt`, `pb`, `pl`, `pr`, `px`, `py` | padding      |
| `bg`                                    | background   |
| `c`                                     | color        |
| `fz`                                    | font-size    |
| `fw`                                    | font-weight  |
| `ta`                                    | text-align   |
| `w`                                     | width        |
| `h`                                     | height       |
| `maw`                                   | max-width    |
| `mah`                                   | max-height   |
| `miw`                                   | min-width    |
| `mih`                                   | min-height   |

--------------------------------------------------------------------------------

### Breadcrumbs
Package: @tidbcloud/uikit
Import: import { Breadcrumbs } from '@tidbcloud/uikit';
Description: Separates list of React nodes with given separator.

Separates list of React nodes with given separator.

## Usage

`Breadcrumbs` component accepts any number of React nodes as children and adds a given separator (defaults to `/`) between them:

```tsx

const items = [
  { title: 'Mantine', href: '#' },
  { title: 'Mantine hooks', href: '#' },
  { title: 'use-id', href: '#' }
].map((item, index) => (
  <Anchor href={item.href} key={index}>
    {item.title}
  </Anchor>
))

function Demo() {
  return (
    <>
      <Breadcrumbs>{items}</Breadcrumbs>
      <Breadcrumbs separator="→" separatorMargin="md" mt="xs">
        {items}
      </Breadcrumbs>
    </>
  )
}
```

## Custom separator

```tsx

function Demo() {
  const items = [
    { title: 'Home', href: '#' },
    { title: 'Products', href: '#' },
    { title: 'Item', href: '#' }
  ].map((item, index) => (
    <Anchor href={item.href} key={index}>
      {item.title}
    </Anchor>
  ))

  return <Breadcrumbs separator={<IconChevronRight size={14} />}>{items}</Breadcrumbs>
}
```

## Props

| Prop            | Type              | Default  | Description                                       |
| --------------- | ----------------- | -------- | ------------------------------------------------- |
| children        | `React.ReactNode` | required | React nodes that should be separated              |
| separator       | `React.ReactNode` | `'/'`    | Separator between children                        |
| separatorMargin | `MantineSpacing`  | -        | Controls spacing between separator and breadcrumb |

--------------------------------------------------------------------------------

### Burger
Package: @tidbcloud/uikit
Import: import { Burger } from '@tidbcloud/uikit';
Description: Open/close navigation button.

Open/close navigation button.

## Usage

`Burger` component renders open/close menu button. Set `opened` and `onClick` props to control component state. If `opened` prop is set, cross will be rendered, otherwise – burger.

```tsx

function Demo() {
  const [opened, { toggle }] = useDisclosure()
  return <Burger opened={opened} onClick={toggle} aria-label="Toggle navigation" />
}
```

## Size

```tsx

function Demo() {
  return (
    <Group>
      <Burger size="xs" />
      <Burger size="sm" />
      <Burger size="md" />
      <Burger size="lg" />
      <Burger size="xl" />
    </Group>
  )
}
```

## Color

```tsx

function Demo() {
  return <Burger color="red" />
}
```

## Accessibility

To make `Burger` accessible for screen readers, set `aria-label`:

```tsx

function Demo() {
  return (
    <>
      <Burger aria-label="Toggle navigation" />

      <Burger>
        <VisuallyHidden>Toggle navigation</VisuallyHidden>
      </Burger>
    </>
  )
}
```

## Props

| Prop               | Type           | Default | Description                             |
| ------------------ | -------------- | ------- | --------------------------------------- |
| color              | `MantineColor` | -       | Lines color                             |
| lineSize           | `number`       | -       | Height of lines                         |
| opened             | `boolean`      | -       | When true, burger is transformed into X |
| size               | `MantineSize`  | `'md'`  | Burger width and height                 |
| transitionDuration | `number`       | `300`   | Transition duration in ms               |

--------------------------------------------------------------------------------

### Button
Package: @tidbcloud/uikit
Import: import { Button } from '@tidbcloud/uikit';
Description: Button component to render button or link.

Button component to render button or link.

## Usage

```tsx

function Demo() {
  return <Button>Click me</Button>
}
```

## Variants

Button supports several variants: `filled`, `light`, `outline`, `transparent`, `white`, `subtle`, `default`, and `gradient`.

```tsx

function Demo() {
  return (
    <Group>
      <Button variant="filled">Filled</Button>
      <Button variant="light">Light</Button>
      <Button variant="outline">Outline</Button>
      <Button variant="default">Default</Button>
    </Group>
  )
}
```

## Gradient

```tsx

function Demo() {
  return (
    <Button variant="gradient" gradient={{ from: 'cyan', to: 'blue', deg: 90 }}>
      Gradient button
    </Button>
  )
}
```

## Left and right sections

```tsx

function Demo() {
  return (
    <Group>
      <Button leftSection={<IconPhoto size={14} />} variant="default">
        Gallery
      </Button>
      <Button rightSection={<IconDownload size={14} />}>Download</Button>
    </Group>
  )
}
```

## Full width

```tsx

function Demo() {
  return <Button fullWidth>Full width button</Button>
}
```

## Loading state

When `loading` or `data-loading` prop is set, Button will be disabled and a Loader will replace the left section. This is a custom behavior in `@tidbcloud/uikit`.

```tsx

function Demo() {
  return <Button loading>Loading button</Button>
}
```

You can also use the `data-loading` attribute:

```tsx

function Demo() {
  return <Button data-loading>Loading button</Button>
}
```

## Disabled state

```tsx

function Demo() {
  return <Button disabled>Disabled button</Button>
}
```

## Compact size

Button supports `xs` – `xl` and `compact-xs` – `compact-xl` sizes:

```tsx

function Demo() {
  return (
    <Group>
      <Button size="md">Regular md</Button>
      <Button size="compact-md">Compact md</Button>
    </Group>
  )
}
```

## Button.Group

```tsx

function Demo() {
  return (
    <Button.Group>
      <Button variant="default">First</Button>
      <Button variant="default">Second</Button>
      <Button variant="default">Third</Button>
    </Button.Group>
  )
}
```

## Props

| Prop         | Type                                                                                                  | Default    | Description                                                                |
| ------------ | ----------------------------------------------------------------------------------------------------- | ---------- | -------------------------------------------------------------------------- |
| autoContrast | `boolean`                                                                                             | -          | Determines whether text color should depend on background-color luminosity |
| children     | `React.ReactNode`                                                                                     | -          | Button content                                                             |
| color        | `MantineColor`                                                                                        | -          | Key of theme.colors or any valid CSS color                                 |
| data-loading | `boolean`                                                                                             | -          | Custom: triggers loading state same as `loading` prop                      |
| disabled     | `boolean`                                                                                             | -          | Sets disabled attribute                                                    |
| fullWidth    | `boolean`                                                                                             | -          | If set, button takes 100% width                                            |
| gradient     | `MantineGradient`                                                                                     | -          | Gradient configuration for `variant="gradient"`                            |
| justify      | `JustifyContent`                                                                                      | -          | Sets justify-content of inner element                                      |
| leftSection  | `React.ReactNode`                                                                                     | -          | Content displayed on the left side                                         |
| loading      | `boolean`                                                                                             | -          | If set, Loader replaces leftSection and button is disabled                 |
| loaderProps  | `LoaderProps`                                                                                         | -          | Props passed to Loader component                                           |
| radius       | `MantineRadius`                                                                                       | -          | Border radius                                                              |
| rightSection | `React.ReactNode`                                                                                     | -          | Content displayed on the right side                                        |
| size         | `MantineSize \| 'compact-xs' \| ... \| 'compact-xl'`                                                  | `'sm'`     | Controls height, font-size and padding                                     |
| variant      | `'filled' \| 'light' \| 'outline' \| 'transparent' \| 'white' \| 'subtle' \| 'default' \| 'gradient'` | `'filled'` | Visual variant                                                             |

--------------------------------------------------------------------------------

### Calendar
Package: @tidbcloud/uikit
Import: import { Calendar } from '@tidbcloud/uikit';
Description: Base component for custom date pickers.

Base component for custom date pickers.

## Usage

Use `Calendar` component to create custom date pickers. By default, `Calendar` works the same way as `DatePicker` component but does not include any logic of dates selection.

```tsx

function Demo() {
  return <Calendar />
}
```

## Custom date picker

Use `Calendar` as a base for custom date pickers. For example, you can create a date picker that allows user to pick three or less dates:

```tsx

function Demo() {
  const [selected, setSelected] = useState<Date[]>([])

  const handleSelect = (date: Date) => {
    const isSelected = selected.some((s) => dayjs(date).isSame(s, 'date'))
    if (isSelected) {
      setSelected((current) => current.filter((d) => !dayjs(d).isSame(date, 'date')))
    } else if (selected.length < 3) {
      setSelected((current) => [...current, date])
    }
  }

  return (
    <Calendar
      getDayProps={(date) => ({
        selected: selected.some((s) => dayjs(date).isSame(s, 'date')),
        onClick: () => handleSelect(date)
      })}
    />
  )
}
```

## Static calendar

Set `static` prop to display a calendar that user cannot interact with:

```tsx

function Demo() {
  return (
    <Calendar
      static
      renderDay={(date) => {
        const day = dayjs(date).date()
        return (
          <Indicator size={6} color="red" offset={-2} disabled={day !== 16}>
            <div>{day}</div>
          </Indicator>
        )
      }}
    />
  )
}
```

## Props

| Prop             | Type                            | Default | Description                                     |
| ---------------- | ------------------------------- | ------- | ----------------------------------------------- |
| date             | `string \| Date`                | -       | Displayed date in controlled mode               |
| defaultDate      | `string \| Date`                | -       | Initial displayed date in uncontrolled mode     |
| excludeDate      | `(date: string) => boolean`     | -       | Callback to determine if day should be disabled |
| firstDayOfWeek   | `0-6`                           | -       | First day of week (0 = Sunday, 6 = Saturday)    |
| getDayProps      | `(date: string) => DayProps`    | -       | Passes props to Day components                  |
| hideOutsideDates | `boolean`                       | -       | Hide dates outside current month                |
| hideWeekdays     | `boolean`                       | -       | Hide weekdays row                               |
| highlightToday   | `boolean`                       | -       | Highlight today with a border                   |
| level            | `'month' \| 'year' \| 'decade'` | -       | Current displayed level                         |
| locale           | `string`                        | -       | Dayjs locale                                    |
| maxDate          | `string \| Date`                | -       | Maximum possible date                           |
| minDate          | `string \| Date`                | -       | Minimum possible date                           |
| numberOfColumns  | `number`                        | -       | Number of columns displayed                     |
| onDateChange     | `(date: string) => void`        | -       | Called when date changes                        |
| renderDay        | `(date: string) => ReactNode`   | -       | Custom day rendering                            |
| size             | `MantineSize`                   | `'sm'`  | Component size                                  |
| static           | `boolean`                       | -       | Disable user interaction                        |

--------------------------------------------------------------------------------

### Card
Package: @tidbcloud/uikit
Import: import { Card } from '@tidbcloud/uikit';
Description: Card with sections.

Card with sections.

## Usage

`Card` is a wrapper around Paper component with some additional styles and `Card.Section` component that allows to split card into sections.

```tsx

function Demo() {
  return (
    <Card shadow="sm" padding="lg" radius="md" withBorder>
      <Card.Section>
        <Image src="https://example.com/image.png" height={160} alt="Norway" />
      </Card.Section>

      <Group justify="space-between" mt="md" mb="xs">
        <Text fw={500}>Norway Fjord Adventures</Text>
        <Badge color="pink">On Sale</Badge>
      </Group>

      <Text size="sm" c="dimmed">
        With Fjord Tours you can explore more of the magical fjord landscapes
      </Text>

      <Button color="blue" fullWidth mt="md" radius="md">
        Book classic tour now
      </Button>
    </Card>
  )
}
```

## Card.Section

`Card.Section` is used to remove Card padding from its children:

```tsx

function Demo() {
  return (
    <Card padding="xl">
      {/* top, right, left margins are negative */}
      <Card.Section>First section</Card.Section>

      {/* Content with normal padding */}
      <Text>Some other content</Text>

      {/* right, left margins are negative */}
      <Card.Section>Middle section</Card.Section>

      {/* bottom, right, left margins are negative */}
      <Card.Section>Last section</Card.Section>
    </Card>
  )
}
```

## withBorder and inheritPadding props

- `withBorder` adds top and bottom border to `Card.Section`
- `inheritPadding` adds the same left and right padding as set in `Card`

```tsx

function Demo() {
  return (
    <Card withBorder shadow="sm" radius="md">
      <Card.Section withBorder inheritPadding py="xs">
        <Group justify="space-between">
          <Text fw={500}>Card title</Text>
        </Group>
      </Card.Section>

      <Text mt="sm" c="dimmed" size="sm">
        Card content goes here
      </Text>
    </Card>
  )
}
```

## Props

| Prop       | Type              | Default | Description             |
| ---------- | ----------------- | ------- | ----------------------- |
| children   | `React.ReactNode` | -       | Card content            |
| padding    | `MantineSpacing`  | `'md'`  | Padding inside the card |
| radius     | `MantineRadius`   | -       | Border radius           |
| shadow     | `MantineShadow`   | -       | Box shadow              |
| withBorder | `boolean`         | -       | Adds border to the card |

--------------------------------------------------------------------------------

### Center
Package: @tidbcloud/uikit
Import: import { Center } from '@tidbcloud/uikit';
Description: Centers content vertically and horizontally.

Centers content vertically and horizontally.

## Usage

```tsx

function Demo() {
  return (
    <Center maw={400} h={100} bg="var(--mantine-color-gray-light)">
      <Box bg="var(--mantine-color-blue-light)">All elements inside Center are centered</Box>
    </Center>
  )
}
```

## Inline

To use `Center` with inline elements set `inline` prop:

```tsx

function Demo() {
  return (
    <Anchor href="https://mantine.dev" target="_blank">
      <Center inline>
        <IconArrowLeft size={12} />
        <Box ml={5}>Back to Mantine website</Box>
      </Center>
    </Anchor>
  )
}
```

## Polymorphic component

Center is a polymorphic component – its default root element is `div`:

```tsx

function Demo() {
  return <Center component="button">Click me</Center>
}
```

## Props

| Prop     | Type              | Default | Description                                     |
| -------- | ----------------- | ------- | ----------------------------------------------- |
| children | `React.ReactNode` | -       | Content to center                               |
| inline   | `boolean`         | -       | If set, `inline-flex` is used instead of `flex` |

--------------------------------------------------------------------------------

### Checkbox
Package: @tidbcloud/uikit
Import: import { Checkbox } from '@tidbcloud/uikit';
Description: Capture boolean input from user.

Capture boolean input from user.

## Usage

```tsx

function Demo() {
  return <Checkbox defaultChecked label="I agree to sell my privacy" />
}
```

## Controlled

```tsx

function Demo() {
  const [checked, setChecked] = useState(false)
  return <Checkbox checked={checked} onChange={(event) => setChecked(event.currentTarget.checked)} />
}
```

## States

```tsx

function Demo() {
  return (
    <Stack>
      <Checkbox checked={false} onChange={() => {}} label="Default checkbox" />
      <Checkbox checked={false} onChange={() => {}} indeterminate label="Indeterminate checkbox" />
      <Checkbox checked onChange={() => {}} label="Checked checkbox" />
      <Checkbox disabled label="Disabled checkbox" />
      <Checkbox disabled checked onChange={() => {}} label="Disabled checked checkbox" />
    </Stack>
  )
}
```

## Indeterminate state

`Checkbox` supports indeterminate state:

```tsx

function Demo() {
  return <Checkbox indeterminate label="Indeterminate checkbox" />
}
```

## Label with link

```tsx

function Demo() {
  return (
    <Checkbox
      label={
        <>
          I accept{' '}
          <Anchor href="https://mantine.dev" target="_blank" inherit>
            terms and conditions
          </Anchor>
        </>
      }
    />
  )
}
```

## Checkbox.Group

```tsx

function Demo() {
  return (
    <Checkbox.Group defaultValue={['react']} label="Select your favorite frameworks" description="This is anonymous">
      <Group mt="xs">
        <Checkbox value="react" label="React" />
        <Checkbox value="svelte" label="Svelte" />
        <Checkbox value="ng" label="Angular" />
        <Checkbox value="vue" label="Vue" />
      </Group>
    </Checkbox.Group>
  )
}
```

## Controlled Checkbox.Group

```tsx

function Demo() {
  const [value, setValue] = useState<string[]>([])

  return (
    <Checkbox.Group value={value} onChange={setValue}>
      <Checkbox value="react" label="React" />
      <Checkbox value="svelte" label="Svelte" />
    </Checkbox.Group>
  )
}
```

## Props

| Prop           | Type                   | Default   | Description                                      |
| -------------- | ---------------------- | --------- | ------------------------------------------------ |
| checked        | `boolean`              | -         | Checked state for controlled component           |
| color          | `MantineColor`         | -         | Key of theme.colors or any valid CSS color       |
| defaultChecked | `boolean`              | -         | Default checked state for uncontrolled component |
| description    | `React.ReactNode`      | -         | Description displayed below the label            |
| disabled       | `boolean`              | -         | Disables checkbox                                |
| error          | `React.ReactNode`      | -         | Error message                                    |
| icon           | `(props) => ReactNode` | -         | Custom check icon component                      |
| iconColor      | `MantineColor`         | -         | Icon color                                       |
| indeterminate  | `boolean`              | -         | Indeterminate state, ignores checked prop        |
| label          | `React.ReactNode`      | -         | Checkbox label                                   |
| labelPosition  | `'left' \| 'right'`    | `'right'` | Position of the label                            |
| onChange       | `(event) => void`      | -         | Called when checked state changes                |
| radius         | `MantineRadius`        | -         | Border radius                                    |
| size           | `MantineSize`          | `'sm'`    | Checkbox size                                    |

--------------------------------------------------------------------------------

### Chip
Package: @tidbcloud/uikit
Import: import { Chip } from '@tidbcloud/uikit';
Description: Pick one or multiple values with inline controls.

Pick one or multiple values with inline controls.

## Usage

```tsx

function Demo() {
  return <Chip defaultChecked>Awesome chip</Chip>
}
```

## Controlled

```tsx

function Demo() {
  const [checked, setChecked] = useState(false)

  return (
    <Chip checked={checked} onChange={() => setChecked((v) => !v)}>
      My chip
    </Chip>
  )
}
```

## Variants

Chip supports several variants: `outline`, `light`, and `filled`.

```tsx

function Demo() {
  return (
    <Group>
      <Chip variant="outline">Outline</Chip>
      <Chip variant="light">Light</Chip>
      <Chip variant="filled">Filled</Chip>
    </Group>
  )
}
```

## Custom check icon

```tsx

function Demo() {
  return (
    <Chip icon={<IconX size={16} />} color="red" variant="filled" defaultChecked>
      Forbidden
    </Chip>
  )
}
```

## Chip.Group

`Chip.Group` manages state of child Chip components. Set `multiple` prop to allow multiple chips to be selected:

```tsx

function Demo() {
  return (
    <>
      <Chip.Group>
        <Group>
          <Chip value="1">Single chip</Chip>
          <Chip value="2">Can be selected</Chip>
          <Chip value="3">At a time</Chip>
        </Group>
      </Chip.Group>

      <Chip.Group multiple>
        <Group mt="md">
          <Chip value="1">Multiple chips</Chip>
          <Chip value="2">Can be selected</Chip>
          <Chip value="3">At a time</Chip>
        </Group>
      </Chip.Group>
    </>
  )
}
```

## Controlled Chip.Group

```tsx

function Single() {
  const [value, setValue] = useState('react')

  return (
    <Chip.Group multiple={false} value={value} onChange={setValue}>
      <Chip value="react">React</Chip>
      <Chip value="ng">Angular</Chip>
      <Chip value="svelte">Svelte</Chip>
    </Chip.Group>
  )
}
```

## Props

| Prop           | Type                         | Default      | Description                                      |
| -------------- | ---------------------------- | ------------ | ------------------------------------------------ |
| checked        | `boolean`                    | -            | Checked state for controlled component           |
| children       | `React.ReactNode`            | required     | Label element                                    |
| color          | `MantineColor`               | -            | Controls color based on variant                  |
| defaultChecked | `boolean`                    | -            | Default checked state for uncontrolled component |
| icon           | `React.ReactNode`            | -            | Custom check icon                                |
| onChange       | `(checked: boolean) => void` | -            | Called when checked state changes                |
| radius         | `MantineRadius`              | -            | Border radius                                    |
| size           | `MantineSize`                | `'sm'`       | Chip size                                        |
| type           | `'checkbox' \| 'radio'`      | `'checkbox'` | Input type                                       |
| variant        | `string`                     | `'outline'`  | Visual variant                                   |

--------------------------------------------------------------------------------

### CloseButton
Package: @tidbcloud/uikit
Import: import { CloseButton } from '@tidbcloud/uikit';
Description: Button with close icon.

Button with close icon.

## Usage

`CloseButton` renders a button with X icon inside. It is used in other Mantine components like Drawer or Modal.

```tsx

function Demo() {
  return <CloseButton />
}
```

## Size and variant

```tsx

function Demo() {
  return (
    <Group>
      <CloseButton size="xs" />
      <CloseButton size="sm" />
      <CloseButton size="md" />
      <CloseButton size="lg" />
      <CloseButton size="xl" />
    </Group>
  )
}
```

## Custom icon

You can change icon by passing any react node to the `icon` prop:

```tsx

function Demo() {
  return <CloseButton icon={<IconXboxX size={18} stroke={1.5} />} />
}
```

## Accessibility

To make `CloseButton` accessible for screen readers, set `aria-label`:

```tsx

function Demo() {
  return (
    <>
      <CloseButton aria-label="Close modal" />

      <CloseButton>
        <VisuallyHidden>Close modal</VisuallyHidden>
      </CloseButton>
    </>
  )
}
```

## Props

| Prop     | Type              | Default | Description                          |
| -------- | ----------------- | ------- | ------------------------------------ |
| children | `React.ReactNode` | -       | Content for VisuallyHidden           |
| disabled | `boolean`         | -       | Sets disabled attribute              |
| icon     | `React.ReactNode` | -       | Custom icon, replaces default X icon |
| iconSize | `number`          | -       | X icon width and height              |
| radius   | `MantineRadius`   | -       | Border radius                        |
| size     | `MantineSize`     | `'md'`  | Button width and height              |

--------------------------------------------------------------------------------

### Code
Package: @tidbcloud/uikit
Import: import { Code } from '@tidbcloud/uikit';
Description: Inline and block code without syntax highlighting.

Inline and block code without syntax highlighting.

## Usage

Use `Code` to display inline code. For block code use `CodeHighlight` from `@mantine/code-highlight` or add `block` prop.

```tsx

function Demo() {
  return <Code>React.createElement()</Code>
}
```

## Block code

Add `block` prop to render code inside block:

```tsx

const codeForPreviousDemo = `import { Code } from '@tidbcloud/uikit'

function Demo() {
  return <Code>React.createElement()</Code>
}`

function Demo() {
  return <Code block>{codeForPreviousDemo}</Code>
}
```

## With color

```tsx

function Demo() {
  return (
    <Group>
      <Code color="blue.9" c="white">
        React.createElement()
      </Code>
      <Code color="red.9" c="white">
        React.createElement()
      </Code>
    </Group>
  )
}
```

## Props

| Prop     | Type              | Default | Description                                               |
| -------- | ----------------- | ------- | --------------------------------------------------------- |
| block    | `boolean`         | -       | Sets display to block and adds padding                    |
| children | `React.ReactNode` | -       | Code content                                              |
| color    | `MantineColor`    | -       | Key of theme.colors or any valid CSS color for background |

--------------------------------------------------------------------------------

### Collapse
Package: @tidbcloud/uikit
Import: import { Collapse } from '@tidbcloud/uikit';
Description: Animate presence with slide down/up transition.

Animate presence with slide down/up transition.

## Usage

```tsx

function Demo() {
  const [opened, { toggle }] = useDisclosure(false)

  return (
    <Box maw={400} mx="auto">
      <Button onClick={toggle}>Toggle content</Button>

      <Collapse in={opened}>
        <Text mt="md">
          From Bulbapedia: Pikachu is a short, chubby rodent Pokémon. It is covered in yellow fur with two horizontal
          brown stripes on its back. It has a small mouth, long, pointed ears with black tips, and brown eyes. Each
          cheek is a red circle that contains a pouch for electricity storage.
        </Text>
      </Collapse>
    </Box>
  )
}
```

## Animation duration

Set `transitionDuration` and `transitionTimingFunction` props to control transition:

```tsx

function Demo() {
  const [opened, { toggle }] = useDisclosure(false)

  return (
    <>
      <Button onClick={toggle}>Toggle with custom duration</Button>
      <Collapse in={opened} transitionDuration={1000} transitionTimingFunction="linear">
        <div>Content</div>
      </Collapse>
    </>
  )
}
```

## With nested Collapse

```tsx

function Demo() {
  const [outerOpened, outerHandlers] = useDisclosure(false)
  const [innerOpened, innerHandlers] = useDisclosure(false)

  return (
    <Stack>
      <Button onClick={outerHandlers.toggle}>Toggle outer</Button>
      <Collapse in={outerOpened}>
        <Button onClick={innerHandlers.toggle}>Toggle inner</Button>
        <Collapse in={innerOpened}>
          <div>Inner content</div>
        </Collapse>
      </Collapse>
    </Stack>
  )
}
```

## Props

| Prop                     | Type              | Default  | Description                   |
| ------------------------ | ----------------- | -------- | ----------------------------- |
| animateOpacity           | `boolean`         | `true`   | Should opacity be animated    |
| children                 | `React.ReactNode` | required | Content that will be animated |
| in                       | `boolean`         | required | Control open/close state      |
| onTransitionEnd          | `() => void`      | -        | Called when transition ends   |
| transitionDuration       | `number`          | `200`    | Transition duration in ms     |
| transitionTimingFunction | `string`          | `'ease'` | CSS timing function           |

--------------------------------------------------------------------------------

### ColorInput
Package: @tidbcloud/uikit
Import: import { ColorInput } from '@tidbcloud/uikit';
Description: Capture color from user with a text input and color picker dropdown.

Capture color from user with a text input and color picker dropdown.

## Usage

`ColorInput` allows users to enter a color value manually or pick from a color picker dropdown.

```tsx

function Demo() {
  return <ColorInput label="Pick a color" placeholder="Enter color" />
}
```

## Controlled

```tsx

function Demo() {
  const [value, setValue] = useState('')
  return <ColorInput value={value} onChange={setValue} />
}
```

## Formats

`ColorInput` supports hex, hexa, rgb, rgba, hsl and hsla color formats. Slider to change opacity is displayed only for hexa, rgba and hsla formats:

```tsx

function Demo() {
  return <ColorInput format="rgba" label="RGBA format" />
}
```

## With swatches

You can add predefined color swatches:

```tsx

function Demo() {
  return (
    <ColorInput
      format="hex"
      label="Pick color"
      swatches={[
        '#25262b',
        '#868e96',
        '#fa5252',
        '#e64980',
        '#be4bdb',
        '#7950f2',
        '#4c6ef5',
        '#228be6',
        '#15aabf',
        '#12b886',
        '#40c057',
        '#82c91e',
        '#fab005',
        '#fd7e14'
      ]}
    />
  )
}
```

## Disable free input

Set `disallowInput` prop to prevent manual input:

```tsx

function Demo() {
  return <ColorInput disallowInput label="Click to pick" />
}
```

## Eye dropper

By default, if [EyeDropper API](https://developer.mozilla.org/en-US/docs/Web/API/EyeDropper_API) is available, an eye dropper icon will be displayed. To disable it:

```tsx

function Demo() {
  return <ColorInput withEyeDropper={false} label="Without eye dropper" />
}
```

## Props

| Prop                    | Type                                                  | Default | Description                          |
| ----------------------- | ----------------------------------------------------- | ------- | ------------------------------------ |
| value                   | string                                                | -       | Controlled component value           |
| defaultValue            | string                                                | -       | Uncontrolled component default value |
| onChange                | (value: string) => void                               | -       | Called when value changes            |
| format                  | 'hex' \| 'hexa' \| 'rgb' \| 'rgba' \| 'hsl' \| 'hsla' | 'hex'   | Color format                         |
| swatches                | string[]                                              | -       | Predefined color swatches            |
| swatchesPerRow          | number                                                | 7       | Number of swatches per row           |
| withPicker              | boolean                                               | true    | Show color picker dropdown           |
| withEyeDropper          | boolean                                               | true    | Show eye dropper button              |
| disallowInput           | boolean                                               | false   | Disable manual input                 |
| closeOnColorSwatchClick | boolean                                               | false   | Close dropdown on swatch click       |
| fixOnBlur               | boolean                                               | true    | Revert to last valid value on blur   |
| label                   | ReactNode                                             | -       | Input label                          |
| description             | ReactNode                                             | -       | Input description                    |
| error                   | ReactNode                                             | -       | Error message                        |
| disabled                | boolean                                               | false   | Disable input                        |
| radius                  | MantineRadius                                         | -       | Border radius                        |
| size                    | MantineSize                                           | 'sm'    | Input size                           |

--------------------------------------------------------------------------------

### ColorPicker
Package: @tidbcloud/uikit
Import: import { ColorPicker } from '@tidbcloud/uikit';
Description: Pick colors in hex(a), rgb(a), hsl(a) and hsv(a) formats.

Pick colors in hex(a), rgb(a), hsl(a) and hsv(a) formats.

## Usage

```tsx

function Demo() {
  const [value, onChange] = useState('rgba(47, 119, 150, 0.7)')

  return (
    <>
      <ColorPicker format="rgba" value={value} onChange={onChange} />
      <Text>{value}</Text>
    </>
  )
}
```

## Color format

`ColorPicker` supports hex, hexa, rgb, rgba, hsl and hsla color formats. Slider to change opacity and color preview are displayed only for hexa, rgba and hsla formats:

```tsx

function Demo() {
  return <ColorPicker format="rgba" />
}
```

## With swatches

You can add predefined color swatches with `swatches` prop:

```tsx

function Demo() {
  return (
    <ColorPicker
      format="hex"
      swatches={[
        '#25262b',
        '#868e96',
        '#fa5252',
        '#e64980',
        '#be4bdb',
        '#7950f2',
        '#4c6ef5',
        '#228be6',
        '#15aabf',
        '#12b886',
        '#40c057',
        '#82c91e',
        '#fab005',
        '#fd7e14'
      ]}
    />
  )
}
```

## Swatches only

To display swatches without picker set `withPicker={false}` and `fullWidth` props:

```tsx

function Demo() {
  const [value, onChange] = useState('#fff')

  return (
    <>
      <ColorPicker
        format="hex"
        value={value}
        onChange={onChange}
        withPicker={false}
        fullWidth
        swatches={['#fa5252', '#e64980', '#be4bdb', '#7950f2', '#4c6ef5', '#228be6', '#15aabf']}
      />
      <Text>{value}</Text>
    </>
  )
}
```

## Size

`ColorPicker` has 5 predefined sizes: `xs`, `sm`, `md`, `lg` and `xl`:

```tsx

function Demo() {
  return <ColorPicker size="lg" />
}
```

## Full width

Set `fullWidth` prop to stretch component to 100% of parent width:

```tsx

function Demo() {
  return <ColorPicker fullWidth size="lg" format="rgba" />
}
```

## HueSlider component

```tsx

function Demo() {
  const [value, onChange] = useState(250)

  return (
    <>
      <Text>Hue value: {value}</Text>
      <HueSlider value={value} onChange={onChange} />
    </>
  )
}
```

## AlphaSlider component

```tsx

function Demo() {
  const [value, onChange] = useState(0.55)

  return (
    <>
      <Text>Alpha value: {value}</Text>
      <AlphaSlider color="#1c7ed6" value={value} onChange={onChange} />
    </>
  )
}
```

## Props

| Prop            | Type                    | Default | Description                            |
| --------------- | ----------------------- | ------- | -------------------------------------- |
| value           | string                  | -       | Controlled component value             |
| defaultValue    | string                  | -       | Uncontrolled component default value   |
| onChange        | (value: string) => void | -       | Called when value changes              |
| onChangeEnd     | (value: string) => void | -       | Called when user stops dragging slider |
| format          | ColorFormat             | 'hex'   | Color format                           |
| swatches        | string[]                | -       | List of predefined colors              |
| swatchesPerRow  | number                  | 7       | Number of swatches per row             |
| size            | MantineSize             | 'md'    | Controls size of sliders               |
| withPicker      | boolean                 | true    | Show color picker                      |
| fullWidth       | boolean                 | false   | Take 100% width of container           |
| focusable       | boolean                 | true    | Make interactive elements focusable    |
| saturationLabel | string                  | -       | Saturation slider aria-label           |
| hueLabel        | string                  | -       | Hue slider aria-label                  |
| alphaLabel      | string                  | -       | Alpha slider aria-label                |

--------------------------------------------------------------------------------

### ColorSwatch
Package: @tidbcloud/uikit
Import: import { ColorSwatch } from '@tidbcloud/uikit';
Description: Display a color swatch.

Display a color swatch.

## Usage

```tsx

function Demo() {
  return (
    <Group>
      <ColorSwatch color="#009790" />
      <ColorSwatch color="rgba(234, 22, 174, 0.5)" />
      <ColorSwatch color="var(--mantine-color-orange-5)" />
    </Group>
  )
}
```

## With shadow

By default, `ColorSwatch` has an inner box-shadow to make it more visible on light backgrounds. You can disable it with `withShadow={false}`:

```tsx

function Demo() {
  return <ColorSwatch color="rgba(255, 255, 255, 0.7)" withShadow={false} />
}
```

## As button

`ColorSwatch` is a polymorphic component – its root element can be changed with `component` prop:

```tsx

function Demo() {
  const [checked, setChecked] = useState(true)

  return (
    <ColorSwatch
      component="button"
      color="var(--mantine-color-grape-6)"
      onClick={() => setChecked((c) => !c)}
      style={{ color: '#fff', cursor: 'pointer' }}
    >
      {checked && <CheckIcon size={12} />}
    </ColorSwatch>
  )
}
```

## Props

| Prop       | Type                   | Default      | Description                             |
| ---------- | ---------------------- | ------------ | --------------------------------------- |
| color      | string                 | **required** | Valid CSS color to display              |
| size       | CSSProperties['width'] | -            | Controls width and height of the swatch |
| radius     | MantineRadius          | -            | Border radius                           |
| withShadow | boolean                | true         | Whether to have inner box-shadow        |
| children   | ReactNode              | -            | Content displayed inside the swatch     |
| component  | ElementType            | 'div'        | Root element or component               |

--------------------------------------------------------------------------------

### Combobox
Package: @tidbcloud/uikit
Import: import { Combobox } from '@tidbcloud/uikit';
Description: Create custom select, autocomplete or multiselect inputs.

Create custom select, autocomplete or multiselect inputs.

## Usage

`Combobox` provides a set of components and hooks to build custom select, multiselect or autocomplete components. The component is highly flexible – you have full control of the rendering and logic.

```tsx

const groceries = ['🍎 Apples', '🍌 Bananas', '🥦 Broccoli', '🥕 Carrots', '🍫 Chocolate']

function Demo() {
  const combobox = useCombobox({
    onDropdownClose: () => combobox.resetSelectedOption()
  })

  const [value, setValue] = useState<string | null>(null)

  const options = groceries.map((item) => (
    <Combobox.Option value={item} key={item}>
      {item}
    </Combobox.Option>
  ))

  return (
    <Combobox
      store={combobox}
      onOptionSubmit={(val) => {
        setValue(val)
        combobox.closeDropdown()
      }}
    >
      <Combobox.Target>
        <InputBase
          component="button"
          type="button"
          pointer
          rightSection={<Combobox.Chevron />}
          rightSectionPointerEvents="none"
          onClick={() => combobox.toggleDropdown()}
        >
          {value || <Input.Placeholder>Pick value</Input.Placeholder>}
        </InputBase>
      </Combobox.Target>

      <Combobox.Dropdown>
        <Combobox.Options>{options}</Combobox.Options>
      </Combobox.Dropdown>
    </Combobox>
  )
}
```

## useCombobox hook

`useCombobox` hook provides combobox store that manages the component state:

```tsx

function Demo() {
  const combobox = useCombobox({
    onDropdownOpen: () => combobox.selectFirstOption(),
    onDropdownClose: () => combobox.resetSelectedOption()
  })

  return <Combobox store={combobox}>{/* Your implementation */}</Combobox>
}
```

## Autocomplete example

```tsx

const groceries = ['🍎 Apples', '🍌 Bananas', '🥦 Broccoli', '🥕 Carrots', '🍫 Chocolate']

function Demo() {
  const combobox = useCombobox()
  const [value, setValue] = useState('')

  const filteredOptions = groceries.filter((item) => item.toLowerCase().includes(value.toLowerCase().trim()))

  const options = filteredOptions.map((item) => (
    <Combobox.Option value={item} key={item}>
      {item}
    </Combobox.Option>
  ))

  return (
    <Combobox
      onOptionSubmit={(optionValue) => {
        setValue(optionValue)
        combobox.closeDropdown()
      }}
      store={combobox}
    >
      <Combobox.Target>
        <TextInput
          placeholder="Pick value or type anything"
          value={value}
          onChange={(event) => {
            setValue(event.currentTarget.value)
            combobox.openDropdown()
            combobox.updateSelectedOptionIndex()
          }}
          onClick={() => combobox.openDropdown()}
          onFocus={() => combobox.openDropdown()}
          onBlur={() => combobox.closeDropdown()}
        />
      </Combobox.Target>

      <Combobox.Dropdown>
        <Combobox.Options>
          {options.length === 0 ? <Combobox.Empty>Nothing found</Combobox.Empty> : options}
        </Combobox.Options>
      </Combobox.Dropdown>
    </Combobox>
  )
}
```

## Options groups

```tsx

function Demo() {
  const combobox = useCombobox()

  return (
    <Combobox store={combobox}>
      <Combobox.Target>
        <InputBase component="button" pointer>
          Pick value
        </InputBase>
      </Combobox.Target>

      <Combobox.Dropdown>
        <Combobox.Options>
          <Combobox.Group label="Fruits">
            <Combobox.Option value="🍎 Apples">🍎 Apples</Combobox.Option>
            <Combobox.Option value="🍌 Bananas">🍌 Bananas</Combobox.Option>
          </Combobox.Group>

          <Combobox.Group label="Vegetables">
            <Combobox.Option value="🥦 Broccoli">🥦 Broccoli</Combobox.Option>
            <Combobox.Option value="🥕 Carrots">🥕 Carrots</Combobox.Option>
          </Combobox.Group>
        </Combobox.Options>
      </Combobox.Dropdown>
    </Combobox>
  )
}
```

## Combobox components

- `Combobox` – root component, context provider
- `Combobox.Target` – wrapper for target element
- `Combobox.Dropdown` – dropdown element
- `Combobox.Options` – options wrapper
- `Combobox.Option` – single option
- `Combobox.Group` – options group with label
- `Combobox.Search` – search input inside dropdown
- `Combobox.Empty` – displayed when no options
- `Combobox.Chevron` – chevron icon
- `Combobox.Header` – dropdown header
- `Combobox.Footer` – dropdown footer

## Props

| Prop            | Type                                                      | Default | Description                          |
| --------------- | --------------------------------------------------------- | ------- | ------------------------------------ |
| store           | ComboboxStore                                             | -       | Combobox store from useCombobox hook |
| onOptionSubmit  | (value: string, optionProps: ComboboxOptionProps) => void | -       | Called when option is selected       |
| size            | MantineSize                                               | 'sm'    | Controls items font-size and padding |
| dropdownPadding | number                                                    | -       | Dropdown padding                     |
| disabled        | boolean                                                   | false   | Disable the combobox                 |
| readOnly        | boolean                                                   | false   | Make combobox read-only              |
| width           | PopoverWidth                                              | -       | Dropdown width                       |
| position        | FloatingPosition                                          | -       | Dropdown position                    |
| offset          | number                                                    | -       | Dropdown offset                      |
| withArrow       | boolean                                                   | false   | Display arrow                        |
| shadow          | MantineShadow                                             | -       | Dropdown shadow                      |
| radius          | MantineRadius                                             | -       | Dropdown border radius               |

--------------------------------------------------------------------------------

### Container
Package: @tidbcloud/uikit
Import: import { Container } from '@tidbcloud/uikit';
Description: Center content with padding and max-width.

Center content with padding and max-width.

## Usage

`Container` centers content and limits its `max-width` to the value specified in `size` prop. Note that the `size` prop does not make `max-width` responsive.

```tsx

function Demo() {
  return (
    <>
      <Container>Default Container</Container>
      <Container size="xs">xs Container</Container>
      <Container size="sm">sm Container</Container>
      <Container px={0} size={480}>
        480px Container without padding
      </Container>
    </>
  )
}
```

## Fluid

Set `fluid` prop to make container take 100% width of its parent:

```tsx

function Demo() {
  return <Container fluid>Fluid container has 100% max-width</Container>
}
```

## Grid strategy

`Container` supports `strategy="grid"` which uses CSS Grid for more advanced layouts:

```tsx

function Demo() {
  return (
    <Container strategy="grid" size={500}>
      <Box bg="var(--mantine-color-indigo-light)" h={50}>
        Main content
      </Box>

      <Box data-breakout bg="var(--mantine-color-indigo-light)" mt="xs">
        <div>Breakout</div>
        <Box data-container bg="indigo" c="white" h={50}>
          <div>Container inside breakout</div>
        </Box>
      </Box>
    </Container>
  )
}
```

With grid strategy:

- Children with `data-breakout` attribute take the entire width of the container's parent
- Children with `data-container` inside `data-breakout` have the same width as the main grid column

## Props

| Prop     | Type                  | Default | Description                |
| -------- | --------------------- | ------- | -------------------------- |
| size     | MantineSize \| number | 'md'    | Max-width of the container |
| fluid    | boolean               | false   | Take 100% width of parent  |
| strategy | 'block' \| 'grid'     | 'block' | Centering strategy         |

--------------------------------------------------------------------------------

### CopyButton
Package: @tidbcloud/uikit
Import: import { CopyButton } from '@tidbcloud/uikit';
Description: Copy given text to clipboard.

Copy given text to clipboard.

## Usage

`CopyButton` is based on `useClipboard` hook. Its children is a render function that receives an object with `copied` (boolean) and `copy` (function) properties.

```tsx

function Demo() {
  return (
    <CopyButton value="https://mantine.dev">
      {({ copied, copy }) => (
        <Button color={copied ? 'teal' : 'blue'} onClick={copy}>
          {copied ? 'Copied url' : 'Copy url'}
        </Button>
      )}
    </CopyButton>
  )
}
```

## With ActionIcon and Tooltip

```tsx

function Demo() {
  return (
    <CopyButton value="https://mantine.dev" timeout={2000}>
      {({ copied, copy }) => (
        <Tooltip label={copied ? 'Copied' : 'Copy'} withArrow position="right">
          <ActionIcon color={copied ? 'teal' : 'gray'} variant="subtle" onClick={copy}>
            {copied ? <IconCheck size={16} /> : <IconCopy size={16} />}
          </ActionIcon>
        </Tooltip>
      )}
    </CopyButton>
  )
}
```

## Timeout

You can provide a custom `copied` reset timeout (default is 1000ms):

```tsx

function Demo() {
  return (
    <CopyButton value="https://mantine.dev" timeout={2000}>
      {({ copied, copy }) => <Button onClick={copy}>{copied ? 'Copied!' : 'Copy'}</Button>}
    </CopyButton>
  )
}
```

## Security note

Due to security reasons, `CopyButton` will not work in iframes and may not work with local files opened with `file://` protocol. It works fine with local websites using `http://` protocol.

## Props

| Prop     | Type                                                            | Default      | Description                 |
| -------- | --------------------------------------------------------------- | ------------ | --------------------------- |
| value    | string                                                          | **required** | Value to copy to clipboard  |
| children | (payload: \{ copied: boolean; copy: () => void \}) => ReactNode | **required** | Render function             |
| timeout  | number                                                          | 1000         | Copied status timeout in ms |

--------------------------------------------------------------------------------

### DateInput
Package: @tidbcloud/uikit
Import: import { DateInput } from '@tidbcloud/uikit';
Description: Free form date input that allows users to type a date.

Free form date input that allows users to type a date.

## Usage

```tsx

function Demo() {
  const [value, setValue] = useState<Date | null>(null)
  return <DateInput value={value} onChange={setValue} label="Date input" placeholder="Date input" />
}
```

## Value format

Use `valueFormat` prop to change the dayjs format of the value label:

```tsx

function Demo() {
  return <DateInput valueFormat="YYYY MMM DD" label="Date input" placeholder="Date input" />
}
```

## Allow clear

Set `clearable` prop to allow removing value from the input:

```tsx

function Demo() {
  return <DateInput clearable defaultValue={new Date()} label="Date input" placeholder="Date input" />
}
```

## Min and max date

Set `minDate` and `maxDate` props to define allowed date range:

```tsx

function Demo() {
  const today = new Date()
  const nextMonth = new Date(today.getFullYear(), today.getMonth() + 1, today.getDate())

  return <DateInput minDate={today} maxDate={nextMonth} label="Date input" placeholder="Date input" />
}
```

## Custom date parser

Use `dateParser` prop to replace default date parser:

```tsx

function Demo() {
  const dateParser = (input: string) => {
    if (input === 'WW2') {
      return new Date(1939, 8, 1)
    }
    return dayjs(input, 'DD/MM/YYYY').toDate()
  }

  return <DateInput dateParser={dateParser} valueFormat="DD/MM/YYYY" label="Type WW2" placeholder="Type WW2" />
}
```

## Disabled state

```tsx

function Demo() {
  return <DateInput label="Disabled" placeholder="Date input" disabled />
}
```

## Props

| Prop         | Type                              | Default        | Description                        |
| ------------ | --------------------------------- | -------------- | ---------------------------------- |
| value        | string \| null                    | -              | Controlled component value         |
| defaultValue | string                            | -              | Uncontrolled default value         |
| onChange     | (value: string \| null) => void   | -              | Called when value changes          |
| valueFormat  | string                            | 'MMMM D, YYYY' | dayjs format for display           |
| dateParser   | (value: string) => string \| null | -              | Custom date parser function        |
| clearable    | boolean                           | false          | Show clear button                  |
| minDate      | string                            | -              | Minimum allowed date               |
| maxDate      | string                            | -              | Maximum allowed date               |
| excludeDate  | (date: string) => boolean         | -              | Function to exclude dates          |
| fixOnBlur    | boolean                           | true           | Revert to last valid value on blur |
| label        | ReactNode                         | -              | Input label                        |
| description  | ReactNode                         | -              | Input description                  |
| error        | ReactNode                         | -              | Error message                      |
| disabled     | boolean                           | false          | Disable input                      |
| placeholder  | string                            | -              | Input placeholder                  |
| size         | MantineSize                       | 'sm'           | Input size                         |
| locale       | string                            | 'en'           | dayjs locale                       |

--------------------------------------------------------------------------------

### DatePicker
Package: @tidbcloud/uikit
Import: import { DatePicker } from '@tidbcloud/uikit';
Description: Inline date, multiple dates and dates range picker.

Inline date, multiple dates and dates range picker.

## Usage

```tsx

function Demo() {
  const [value, setValue] = useState<Date | null>(null)
  return <DatePicker value={value} onChange={setValue} />
}
```

## Allow deselect

Set `allowDeselect` to allow user to deselect current selected date by clicking on it:

```tsx

function Demo() {
  return <DatePicker allowDeselect />
}
```

## Multiple dates

Set `type="multiple"` to allow user to pick multiple dates:

```tsx

function Demo() {
  const [value, setValue] = useState<Date[]>([])
  return <DatePicker type="multiple" value={value} onChange={setValue} />
}
```

## Dates range

Set `type="range"` to allow user to pick dates range:

```tsx

function Demo() {
  const [value, setValue] = useState<[Date | null, Date | null]>([null, null])
  return <DatePicker type="range" value={value} onChange={setValue} />
}
```

## Min and max date

Set `minDate` and `maxDate` props to define allowed date range:

```tsx

function Demo() {
  return <DatePicker minDate={new Date(2022, 1, 10)} maxDate={new Date(2022, 1, 25)} />
}
```

## Hide outside dates

Set `hideOutsideDates` prop to remove all dates that do not belong to the current month:

```tsx

function Demo() {
  return <DatePicker hideOutsideDates />
}
```

## Display week numbers

Set `withWeekNumbers` prop to display week numbers:

```tsx

function Demo() {
  return <DatePicker withWeekNumbers />
}
```

## First day of week

Set `firstDayOfWeek` prop (0-6, where 0 is Sunday):

```tsx

function Demo() {
  return <DatePicker firstDayOfWeek={0} /> // Sunday
}
```

## Number of columns

Set `numberOfColumns` prop to display multiple months:

```tsx

function Demo() {
  return <DatePicker numberOfColumns={2} />
}
```

## Default level

Set `defaultLevel` prop to configure initial display level:

```tsx

function Demo() {
  return <DatePicker defaultLevel="decade" />
}
```

## Exclude dates

Use `excludeDate` prop to disable specific dates:

```tsx

function Demo() {
  // Disable all dates except Fridays
  return <DatePicker excludeDate={(date) => date.getDay() !== 5} />
}
```

## Props

| Prop                   | Type                               | Default   | Description                      |
| ---------------------- | ---------------------------------- | --------- | -------------------------------- |
| type                   | 'default' \| 'multiple' \| 'range' | 'default' | Picker type                      |
| value                  | DateValue                          | -         | Controlled value                 |
| defaultValue           | DateValue                          | -         | Default value                    |
| onChange               | (value: DateValue) => void         | -         | Called when value changes        |
| allowDeselect          | boolean                            | false     | Allow deselecting date           |
| allowSingleDateInRange | boolean                            | false     | Allow single date as range       |
| numberOfColumns        | number                             | 1         | Number of columns                |
| minDate                | Date                               | -         | Minimum allowed date             |
| maxDate                | Date                               | -         | Maximum allowed date             |
| excludeDate            | (date: Date) => boolean            | -         | Function to exclude dates        |
| hideOutsideDates       | boolean                            | false     | Hide dates outside current month |
| hideWeekdays           | boolean                            | false     | Hide weekdays row                |
| withWeekNumbers        | boolean                            | false     | Display week numbers             |
| firstDayOfWeek         | 0-6                                | 1         | First day of week                |
| weekendDays            | number[]                           | [0, 6]    | Weekend days indices             |
| defaultLevel           | 'month' \| 'year' \| 'decade'      | 'month'   | Initial display level            |
| maxLevel               | 'month' \| 'year' \| 'decade'      | 'decade'  | Max level user can go to         |
| locale                 | string                             | 'en'      | dayjs locale                     |
| size                   | MantineSize                        | 'sm'      | Component size                   |

--------------------------------------------------------------------------------

### DatePickerInput
Package: @tidbcloud/uikit
Import: import { DatePickerInput } from '@tidbcloud/uikit';
Description: Date, multiple dates and dates range picker input.

Date, multiple dates and dates range picker input.

## Usage

```tsx

function Demo() {
  const [value, setValue] = useState<Date | null>(null)
  return <DatePickerInput label="Pick date" placeholder="Pick date" value={value} onChange={setValue} />
}
```

## Multiple dates

Set `type="multiple"` to allow user to pick multiple dates:

```tsx

function Demo() {
  const [value, setValue] = useState<Date[]>([])
  return (
    <DatePickerInput type="multiple" label="Pick dates" placeholder="Pick dates" value={value} onChange={setValue} />
  )
}
```

## Dates range

Set `type="range"` to allow user to pick dates range:

```tsx

function Demo() {
  const [value, setValue] = useState<[Date | null, Date | null]>([null, null])
  return (
    <DatePickerInput
      type="range"
      label="Pick dates range"
      placeholder="Pick dates range"
      value={value}
      onChange={setValue}
    />
  )
}
```

## Value format

Use `valueFormat` prop to change dayjs format of value label:

```tsx

function Demo() {
  return <DatePickerInput valueFormat="YYYY MMM DD" label="Pick date" placeholder="Pick date" />
}
```

## Clearable

Set `clearable` prop to display clear button:

```tsx

function Demo() {
  return <DatePickerInput clearable label="Pick date" placeholder="Pick date" />
}
```

## Open picker in modal

Set `dropdownType="modal"` to render picker in a modal instead of popover:

```tsx

function Demo() {
  return <DatePickerInput dropdownType="modal" label="Pick date" placeholder="Pick date" />
}
```

## With icon

```tsx

function Demo() {
  return <DatePickerInput leftSection={<IconCalendar size={18} />} label="Pick date" placeholder="Pick date" />
}
```

## Disabled state

```tsx

function Demo() {
  return <DatePickerInput label="Disabled" placeholder="Pick date" disabled />
}
```

## Props

| Prop            | Type                               | Default        | Description                       |
| --------------- | ---------------------------------- | -------------- | --------------------------------- |
| type            | 'default' \| 'multiple' \| 'range' | 'default'      | Picker type                       |
| value           | DateValue                          | -              | Controlled value                  |
| defaultValue    | DateValue                          | -              | Default value                     |
| onChange        | (value: DateValue) => void         | -              | Called when value changes         |
| valueFormat     | string                             | 'MMMM D, YYYY' | dayjs format for display          |
| clearable       | boolean                            | false          | Show clear button                 |
| dropdownType    | 'popover' \| 'modal'               | 'popover'      | Type of dropdown                  |
| closeOnChange   | boolean                            | true           | Close dropdown when date selected |
| numberOfColumns | number                             | 1              | Number of calendar columns        |
| minDate         | string                             | -              | Minimum allowed date              |
| maxDate         | string                             | -              | Maximum allowed date              |
| label           | ReactNode                          | -              | Input label                       |
| description     | ReactNode                          | -              | Input description                 |
| error           | ReactNode                          | -              | Error message                     |
| disabled        | boolean                            | false          | Disable input                     |
| placeholder     | string                             | -              | Input placeholder                 |
| size            | MantineSize                        | 'sm'           | Input size                        |
| locale          | string                             | 'en'           | dayjs locale                      |
| leftSection     | ReactNode                          | -              | Left section content              |
| rightSection    | ReactNode                          | -              | Right section content             |

--------------------------------------------------------------------------------

### DateTimePicker
Package: @tidbcloud/uikit
Import: import { DateTimePicker } from '@tidbcloud/uikit';
Description: Capture datetime from the user.

Capture datetime from the user.

## Usage

```tsx

function Demo() {
  return <DateTimePicker label="Pick date and time" placeholder="Pick date and time" />
}
```

## With seconds

Set `withSeconds` prop to display seconds input:

```tsx

function Demo() {
  return <DateTimePicker withSeconds label="Pick date and time" placeholder="Pick date and time" />
}
```

## Value format

Use `valueFormat` prop to change dayjs format of value label:

```tsx

function Demo() {
  return (
    <DateTimePicker valueFormat="DD MMM YYYY hh:mm A" label="Pick date and time" placeholder="Pick date and time" />
  )
}
```

## Clearable

Set `clearable` prop to display clear button:

```tsx

function Demo() {
  return <DateTimePicker clearable label="Pick date and time" placeholder="Pick date and time" />
}
```

## Open picker in modal

Set `dropdownType="modal"` to render picker in a modal:

```tsx

function Demo() {
  return <DateTimePicker dropdownType="modal" label="Pick date and time" placeholder="Pick date and time" />
}
```

## TimePicker props

You can pass props to the underlying TimePicker component with `timePickerProps`:

```tsx

function Demo() {
  return (
    <DateTimePicker
      label="Pick date and time"
      placeholder="Pick date and time"
      timePickerProps={{
        withDropdown: true,
        format: '12h'
      }}
    />
  )
}
```

## Disabled state

```tsx

function Demo() {
  return <DateTimePicker label="Disabled" placeholder="Pick date and time" disabled />
}
```

## Props

| Prop            | Type                            | Default   | Description               |
| --------------- | ------------------------------- | --------- | ------------------------- |
| value           | string \| null                  | -         | Controlled value          |
| defaultValue    | string                          | -         | Default value             |
| onChange        | (value: string \| null) => void | -         | Called when value changes |
| valueFormat     | string                          | -         | dayjs format for display  |
| withSeconds     | boolean                         | false     | Display seconds input     |
| clearable       | boolean                         | false     | Show clear button         |
| dropdownType    | 'popover' \| 'modal'            | 'popover' | Type of dropdown          |
| timePickerProps | TimePickerProps                 | -         | Props for TimePicker      |
| minDate         | string                          | -         | Minimum allowed date      |
| maxDate         | string                          | -         | Maximum allowed date      |
| label           | ReactNode                       | -         | Input label               |
| description     | ReactNode                       | -         | Input description         |
| error           | ReactNode                       | -         | Error message             |
| disabled        | boolean                         | false     | Disable input             |
| placeholder     | string                          | -         | Input placeholder         |
| size            | MantineSize                     | 'sm'      | Input size                |
| locale          | string                          | 'en'      | dayjs locale              |

--------------------------------------------------------------------------------

### DatesProvider
Package: @tidbcloud/uikit
Import: import { DatesProvider } from '@tidbcloud/uikit';
Description: Configure settings for all date components.

Configure settings for all date components.

## Usage

`DatesProvider` lets you set various settings that are shared across all date components. It supports the following settings:

- `locale` – dayjs locale (you need to import the corresponding locale module from dayjs)
- `firstDayOfWeek` – number from 0 to 6, where 0 is Sunday and 6 is Saturday (default: 1 – Monday)
- `weekendDays` – array of numbers from 0 to 6 (default: [0, 6] – Saturday and Sunday)
- `consistentWeeks` – if true, every month will have 6 weeks (default: false)

```tsx

function Demo() {
  return (
    <DatesProvider settings={{ locale: 'ru', firstDayOfWeek: 0, weekendDays: [0] }}>
      <MonthPickerInput label="Pick month" placeholder="Pick month" />
      <DatePickerInput mt="md" label="Pick date" placeholder="Pick date" />
    </DatesProvider>
  )
}
```

## Consistent weeks

Set `consistentWeeks: true` to avoid layout shifts by ensuring every month has 6 weeks:

```tsx

function Demo() {
  return (
    <DatesProvider settings={{ consistentWeeks: true }}>
      <DatePicker />
    </DatesProvider>
  )
}
```

## Localization

To add localization, import the dayjs locale module and set the `locale` setting:

```tsx

function Demo() {
  return (
    <DatesProvider settings={{ locale: 'de' }}>
      <DatePicker />
    </DatesProvider>
  )
}
```

## Next.js App Router

If you're using Next.js app router, add `'use client'` directive to the file where you import dayjs locales:

```tsx
'use client'

function Demo() {
  return <DatesProvider settings={{ locale: 'ru' }}>{/* Your app */}</DatesProvider>
}
```

## Props

| Prop                     | Type      | Default | Description                    |
| ------------------------ | --------- | ------- | ------------------------------ |
| settings.locale          | string    | 'en'    | dayjs locale                   |
| settings.firstDayOfWeek  | 0-6       | 1       | First day of week (0 = Sunday) |
| settings.weekendDays     | number[]  | [0, 6]  | Weekend days indices           |
| settings.consistentWeeks | boolean   | false   | Always show 6 weeks per month  |
| children                 | ReactNode | -       | Application content            |

--------------------------------------------------------------------------------

### Dialog
Package: @tidbcloud/uikit
Import: import { Dialog } from '@tidbcloud/uikit';
Description: Display a fixed overlay dialog at any side of the screen.

Display a fixed overlay dialog at any side of the screen.

## Usage

`Dialog` is a simplified version of Modal. It does not include focus trap and does not close on click outside. Use it to attract attention with non-critical information or actions.

```tsx

function Demo() {
  const [opened, { toggle, close }] = useDisclosure(false)

  return (
    <>
      <Group justify="center">
        <Button onClick={toggle}>Toggle dialog</Button>
      </Group>

      <Dialog opened={opened} withCloseButton onClose={close} size="lg" radius="md">
        <Text size="sm" mb="xs" fw={500}>
          Subscribe to email newsletter
        </Text>

        <Group align="flex-end">
          <TextInput placeholder="hello@example.com" style={{ flex: 1 }} />
          <Button onClick={close}>Subscribe</Button>
        </Group>
      </Dialog>
    </>
  )
}
```

## Change position

`Dialog` is rendered in Portal and has fixed position. Set `position` prop to control dialog position:

```tsx

function Demo() {
  return (
    <>
      <Dialog position={{ top: 20, left: 20 }} opened>
        Dialog in top left corner
      </Dialog>
      <Dialog position={{ bottom: 20, right: 20 }} opened>
        Dialog in bottom right corner
      </Dialog>
    </>
  )
}
```

## With close button

Set `withCloseButton` prop to display close button:

```tsx

function Demo() {
  return (
    <Dialog opened withCloseButton onClose={() => {}}>
      Dialog with close button
    </Dialog>
  )
}
```

## Accessibility note

`Dialog` is not accessible and most likely will not be announced by screen readers. Do not put important information in Dialog. For critical content, use Modal, Drawer, or Notifications instead.

## Props

| Prop            | Type                  | Default      | Description                         |
| --------------- | --------------------- | ------------ | ----------------------------------- |
| opened          | boolean               | **required** | Opened state                        |
| onClose         | () => void            | -            | Called when close button is clicked |
| position        | AffixPosition         | -            | Dialog position on screen           |
| size            | MantineSize \| number | 'md'         | Dialog width                        |
| radius          | MantineRadius         | -            | Border radius                       |
| shadow          | MantineShadow         | -            | Box shadow                          |
| withCloseButton | boolean               | false        | Display close button                |
| withBorder      | boolean               | false        | Add border to root element          |
| children        | ReactNode             | -            | Dialog content                      |
| withinPortal    | boolean               | true         | Render within Portal                |
| keepMounted     | boolean               | false        | Keep mounted when hidden            |
| zIndex          | number                | -            | z-index CSS property                |
| transitionProps | TransitionProps       | -            | Transition configuration            |

--------------------------------------------------------------------------------

### Divider
Package: @tidbcloud/uikit
Import: import { Divider } from '@tidbcloud/uikit';
Description: Horizontal line with optional label or vertical divider.

Horizontal line with optional label or vertical divider.

## Usage

```tsx

function Demo() {
  return (
    <>
      <Text>First section</Text>
      <Divider my="md" />
      <Text>Second section</Text>
      <Divider my="md" />
      <Text>Third section</Text>
    </>
  )
}
```

## Variants

```tsx

function Demo() {
  return (
    <>
      <Divider my="sm" />
      <Divider my="sm" variant="dashed" />
      <Divider my="sm" variant="dotted" />
    </>
  )
}
```

## With label

```tsx

function Demo() {
  return (
    <>
      <Divider my="xs" label="Label on the left" labelPosition="left" />
      <Divider my="xs" label="Label in the center" labelPosition="center" />
      <Divider my="xs" label="Label on the right" labelPosition="right" />
      <Divider
        my="xs"
        variant="dashed"
        labelPosition="center"
        label={
          <>
            <IconSearch size={12} />
            <Box ml={5}>Search results</Box>
          </>
        }
      />
      <Divider
        my="xs"
        label={
          <Anchor href="https://mantine.dev" target="_blank" inherit>
            Link label
          </Anchor>
        }
      />
    </>
  )
}
```

## Sizes

```tsx

function Demo() {
  return (
    <>
      <Divider size="xs" />
      <Divider size="sm" />
      <Divider size="md" />
      <Divider size="lg" />
      <Divider size="xl" />
      <Divider size={10} />
    </>
  )
}
```

## Vertical orientation

```tsx

function Demo() {
  return (
    <Group>
      <Text>Label</Text>
      <Divider orientation="vertical" />
      <Text>Label</Text>
      <Divider size="sm" orientation="vertical" />
      <Text>Label</Text>
      <Divider size="md" orientation="vertical" />
      <Text>Label</Text>
      <Divider size="lg" orientation="vertical" />
      <Text>Label</Text>
    </Group>
  )
}
```

## Props

| Prop          | Type                            | Default      | Description                  |
| ------------- | ------------------------------- | ------------ | ---------------------------- |
| orientation   | 'horizontal' \| 'vertical'      | 'horizontal' | Divider orientation          |
| size          | MantineSize \| number           | 'xs'         | Border width/height          |
| label         | ReactNode                       | -            | Label text (horizontal only) |
| labelPosition | 'left' \| 'center' \| 'right'   | 'left'       | Label position               |
| variant       | 'solid' \| 'dashed' \| 'dotted' | 'solid'      | Border style                 |
| color         | MantineColor                    | -            | Border color                 |

--------------------------------------------------------------------------------

### Drawer
Package: @tidbcloud/uikit
Import: import { Drawer } from '@tidbcloud/uikit';
Description: Display overlay panel at any side of the screen.

Display overlay panel at any side of the screen.

## Usage

```tsx

function Demo() {
  const [opened, { open, close }] = useDisclosure(false)

  return (
    <>
      <Drawer opened={opened} onClose={close} title="Authentication">
        {/* Drawer content */}
      </Drawer>

      <Button onClick={open}>Open Drawer</Button>
    </>
  )
}
```

## Position

Drawer can be positioned on left (default), top, right, and bottom:

```tsx

function Demo() {
  const [rightOpened, { open: openRight, close: closeRight }] = useDisclosure(false)
  const [topOpened, { open: openTop, close: closeTop }] = useDisclosure(false)

  return (
    <>
      <Drawer position="right" opened={rightOpened} onClose={closeRight} title="Right Drawer">
        Drawer content
      </Drawer>
      <Drawer position="top" opened={topOpened} onClose={closeTop} title="Top Drawer">
        Drawer content
      </Drawer>

      <Group>
        <Button onClick={openRight}>Right</Button>
        <Button onClick={openTop}>Top</Button>
      </Group>
    </>
  )
}
```

## Offset

Set `offset` to change drawer offset from the edge of the viewport:

```tsx
<Drawer offset={8} radius="md" />
```

## Size

Set `size` to control drawer width (for left/right position) or height (for top/bottom position):

```tsx
<Drawer size="xs" />  // 320px
<Drawer size="sm" />  // 380px
<Drawer size="md" />  // 440px (default)
<Drawer size="lg" />  // 620px
<Drawer size="xl" />  // 780px
<Drawer size="100%" /> // Full width/height
<Drawer size={500} />  // Custom pixels
```

## Without overlay

Use `withOverlay={false}` to render drawer without overlay:

```tsx
<Drawer withOverlay={false} />
```

## Without close button

Use `withCloseButton={false}` to hide close button:

```tsx
<Drawer withCloseButton={false} />
```

## Change transition

Use `transitionProps` to customize the transition:

```tsx
<Drawer transitionProps={{ transition: 'rotate-left', duration: 150 }} />
```

## Scrollable content

```tsx

function Demo() {
  const [opened, { open, close }] = useDisclosure(false)

  const content = Array(100)
    .fill(0)
    .map((_, index) => <p key={index}>Drawer with scroll</p>)

  return (
    <>
      <Drawer opened={opened} onClose={close} title="Header is sticky">
        {content}
      </Drawer>

      <Button onClick={open}>Open Drawer</Button>
    </>
  )
}
```

## Compound components

Use compound components for better control over drawer parts:

```tsx

function Demo() {
  const [opened, { open, close }] = useDisclosure(false)

  return (
    <>
      <Drawer.Root opened={opened} onClose={close}>
        <Drawer.Overlay />
        <Drawer.Content>
          <Drawer.Header>
            <Drawer.Title>Drawer title</Drawer.Title>
            <Drawer.CloseButton />
          </Drawer.Header>
          <Drawer.Body>Drawer content</Drawer.Body>
        </Drawer.Content>
      </Drawer.Root>

      <Button onClick={open}>Open drawer</Button>
    </>
  )
}
```

## Props

| Prop                | Type                                   | Default | Description                  |
| ------------------- | -------------------------------------- | ------- | ---------------------------- |
| opened              | boolean                                | -       | Controls drawer opened state |
| onClose             | () => void                             | -       | Called when drawer is closed |
| title               | ReactNode                              | -       | Drawer title                 |
| position            | 'top' \| 'right' \| 'bottom' \| 'left' | 'left'  | Drawer position              |
| size                | MantineSize \| number                  | 'md'    | Drawer width/height          |
| offset              | number                                 | 0       | Offset from viewport edge    |
| radius              | MantineRadius                          | 0       | Border radius                |
| withCloseButton     | boolean                                | true    | Show close button            |
| withOverlay         | boolean                                | true    | Show overlay                 |
| closeOnClickOutside | boolean                                | true    | Close on outside click       |
| closeOnEscape       | boolean                                | true    | Close on escape key          |
| trapFocus           | boolean                                | true    | Trap focus inside drawer     |
| transitionProps     | TransitionProps                        | -       | Transition configuration     |

--------------------------------------------------------------------------------

### Fieldset
Package: @tidbcloud/uikit
Import: import { Fieldset } from '@tidbcloud/uikit';
Description: Group related form elements with optional legend.

Group related form elements with optional legend.

## Usage

```tsx

function Demo() {
  return (
    <Fieldset legend="Personal information">
      <TextInput label="Your name" placeholder="Your name" />
      <TextInput label="Email" placeholder="Email" mt="md" />
      <Checkbox label="I agree to terms and conditions" mt="md" />
      <Group justify="flex-end" mt="md">
        <Button type="submit">Submit</Button>
      </Group>
    </Fieldset>
  )
}
```

## Variants

```tsx

function Demo() {
  return (
    <>
      <Fieldset legend="Default variant" variant="default">
        <TextInput label="Field" placeholder="Field" />
      </Fieldset>
      <Fieldset legend="Filled variant" variant="filled" mt="md">
        <TextInput label="Field" placeholder="Field" />
      </Fieldset>
      <Fieldset legend="Unstyled variant" variant="unstyled" mt="md">
        <TextInput label="Field" placeholder="Field" />
      </Fieldset>
    </>
  )
}
```

## Disabled state

Set `disabled` prop to disable all form elements inside:

```tsx

function Demo() {
  return (
    <Fieldset legend="Personal information" disabled>
      <TextInput label="Your name" placeholder="Your name" />
      <TextInput label="Email" placeholder="Email" mt="md" />
      <Checkbox label="I agree to terms and conditions" mt="md" />
      <Group justify="flex-end" mt="md">
        <Button type="submit">Submit</Button>
      </Group>
    </Fieldset>
  )
}
```

## Radius

```tsx

function Demo() {
  return (
    <>
      <Fieldset legend="Radius xs" radius="xs">
        <TextInput label="Field" placeholder="Field" />
      </Fieldset>
      <Fieldset legend="Radius md" radius="md" mt="md">
        <TextInput label="Field" placeholder="Field" />
      </Fieldset>
      <Fieldset legend="Radius lg" radius="lg" mt="md">
        <TextInput label="Field" placeholder="Field" />
      </Fieldset>
    </>
  )
}
```

## Props

| Prop     | Type                                | Default   | Description                      |
| -------- | ----------------------------------- | --------- | -------------------------------- |
| legend   | ReactNode                           | -         | Fieldset legend text             |
| variant  | 'default' \| 'filled' \| 'unstyled' | 'default' | Fieldset variant                 |
| radius   | MantineRadius                       | 'sm'      | Border radius                    |
| disabled | boolean                             | false     | Disable all form elements inside |

--------------------------------------------------------------------------------

### FileButton
Package: @tidbcloud/uikit
Import: import { FileButton } from '@tidbcloud/uikit';
Description: Open file picker with a button click.

Open file picker with a button click.

## Usage

```tsx

function Demo() {
  const [file, setFile] = useState<File | null>(null)

  return (
    <>
      <Group justify="center">
        <FileButton onChange={setFile} accept="image/png,image/jpeg">
          {(props) => <Button {...props}>Upload image</Button>}
        </FileButton>
      </Group>

      {file && (
        <Text size="sm" ta="center" mt="sm">
          Picked file: {file.name}
        </Text>
      )}
    </>
  )
}
```

## Multiple files

Set `multiple` prop to allow picking multiple files:

```tsx

function Demo() {
  const [files, setFiles] = useState<File[]>([])

  return (
    <>
      <Group justify="center">
        <FileButton onChange={setFiles} accept="image/png,image/jpeg" multiple>
          {(props) => <Button {...props}>Upload images</Button>}
        </FileButton>
      </Group>

      {files.length > 0 && (
        <Text size="sm" mt="sm">
          Picked files:
        </Text>
      )}
      <ul>
        {files.map((file, index) => (
          <li key={index}>{file.name}</li>
        ))}
      </ul>
    </>
  )
}
```

## Reset file

`resetRef` can be used to reset file input value:

```tsx

function Demo() {
  const [file, setFile] = useState<File | null>(null)
  const resetRef = useRef<() => void>(null)

  const clearFile = () => {
    setFile(null)
    resetRef.current?.()
  }

  return (
    <>
      <Group justify="center">
        <FileButton resetRef={resetRef} onChange={setFile} accept="image/png,image/jpeg">
          {(props) => <Button {...props}>Upload image</Button>}
        </FileButton>
        <Button disabled={!file} color="red" onClick={clearFile}>
          Reset
        </Button>
      </Group>

      {file && (
        <Text size="sm" ta="center" mt="sm">
          Picked file: {file.name}
        </Text>
      )}
    </>
  )
}
```

## Disabled state

Set `disabled` prop to prevent file picker from opening:

```tsx
<FileButton onChange={setFile} disabled>
  {(props) => <Button {...props}>Disabled upload</Button>}
</FileButton>
```

## Props

| Prop       | Type                                    | Default | Description                   |
| ---------- | --------------------------------------- | ------- | ----------------------------- |
| onChange   | (files: File \| File[] \| null) => void | -       | Called when files are picked  |
| accept     | string                                  | -       | Accepted file types           |
| multiple   | boolean                                 | false   | Allow multiple file selection |
| disabled   | boolean                                 | false   | Disable file picker           |
| capture    | 'user' \| 'environment'                 | -       | Capture attribute for mobile  |
| resetRef   | React.ForwardedRef\<() => void>         | -       | Ref to reset function         |
| children   | (props) => ReactNode                    | -       | Render prop function          |
| name       | string                                  | -       | Input name attribute          |
| form       | string                                  | -       | Form id attribute             |
| inputProps | object                                  | -       | Props spread to hidden input  |

--------------------------------------------------------------------------------

### FileInput
Package: @tidbcloud/uikit
Import: import { FileInput } from '@tidbcloud/uikit';
Description: Capture file input from user.

Capture file input from user.

## Usage

```tsx

function Demo() {
  return <FileInput label="Upload files" placeholder="Upload files" />
}
```

## Multiple files

Set `multiple` prop to allow picking multiple files:

```tsx

function Demo() {
  return <FileInput label="Upload files" placeholder="Upload files" multiple />
}
```

## Accept

Use `accept` prop to restrict file types:

```tsx

function Demo() {
  return <FileInput accept="image/png,image/jpeg" label="Upload images" placeholder="Upload images" />
}
```

## Clearable

Set `clearable` prop to show clear button:

```tsx

function Demo() {
  return <FileInput clearable label="Upload files" placeholder="Upload files" />
}
```

## Custom value component

Use `valueComponent` to customize how selected files are displayed:

```tsx

const ValueComponent: FileInputProps['valueComponent'] = ({ value }) => {
  if (value === null) {
    return null
  }

  if (Array.isArray(value)) {
    return (
      <Pill.Group>
        {value.map((file, index) => (
          <Pill key={index}>{file.name}</Pill>
        ))}
      </Pill.Group>
    )
  }

  return <Pill>{value.name}</Pill>
}

function Demo() {
  return <FileInput label="Upload files" placeholder="Upload files" multiple valueComponent={ValueComponent} />
}
```

## Left and right sections

```tsx

function Demo() {
  const icon = <IconFileCv style={{ width: rem(18), height: rem(18) }} stroke={1.5} />

  return (
    <>
      <FileInput leftSection={icon} label="With left section" placeholder="With left section" />
      <FileInput rightSection={icon} label="With right section" placeholder="With right section" mt="md" />
    </>
  )
}
```

## Error state

```tsx

function Demo() {
  return (
    <>
      <FileInput label="Boolean error" placeholder="Boolean error" error />
      <FileInput mt="md" label="With error message" placeholder="With error message" error="Invalid file" />
    </>
  )
}
```

## Disabled state

```tsx

function Demo() {
  return <FileInput disabled label="Disabled" placeholder="Disabled" />
}
```

## Props

| Prop           | Type                                    | Default   | Description           |
| -------------- | --------------------------------------- | --------- | --------------------- |
| value          | File \| File[] \| null                  | -         | Controlled value      |
| defaultValue   | File \| File[] \| null                  | -         | Default value         |
| onChange       | (value: File \| File[] \| null) => void | -         | Change callback       |
| accept         | string                                  | -         | Accepted file types   |
| multiple       | boolean                                 | false     | Allow multiple files  |
| clearable      | boolean                                 | false     | Show clear button     |
| valueComponent | ComponentType                           | -         | Custom value display  |
| leftSection    | ReactNode                               | -         | Left section content  |
| rightSection   | ReactNode                               | -         | Right section content |
| label          | ReactNode                               | -         | Input label           |
| description    | ReactNode                               | -         | Input description     |
| error          | ReactNode                               | -         | Error message         |
| placeholder    | string                                  | -         | Placeholder text      |
| disabled       | boolean                                 | false     | Disable input         |
| required       | boolean                                 | false     | Required field        |
| radius         | MantineRadius                           | -         | Border radius         |
| size           | MantineSize                             | 'sm'      | Input size            |
| variant        | 'default' \| 'filled' \| 'unstyled'     | 'default' | Input variant         |

--------------------------------------------------------------------------------

### Flex
Package: @tidbcloud/uikit
Import: import { Flex } from '@tidbcloud/uikit';
Description: Compose elements in a flex container.

Compose elements in a flex container.

## Usage

```tsx

function Demo() {
  return (
    <Flex mih={50} bg="rgba(0, 0, 0, .3)" gap="md" justify="center" align="center" direction="row" wrap="wrap">
      <Button>Button 1</Button>
      <Button>Button 2</Button>
      <Button>Button 3</Button>
    </Flex>
  )
}
```

## Supported props

`Flex` component supports the following props:

- `gap` – gap between elements, key of `theme.spacing` or number value
- `rowGap` – row gap, key of `theme.spacing` or number value
- `columnGap` – column gap, key of `theme.spacing` or number value
- `align` – `align-items` CSS property
- `justify` – `justify-content` CSS property
- `wrap` – `flex-wrap` CSS property
- `direction` – `flex-direction` CSS property

## Responsive props

All Flex props support responsive values:

```tsx

function Demo() {
  return (
    <Flex direction={{ base: 'column', sm: 'row' }} gap={{ base: 'sm', sm: 'lg' }} justify={{ sm: 'center' }}>
      <Button>Button 1</Button>
      <Button>Button 2</Button>
      <Button>Button 3</Button>
    </Flex>
  )
}
```

## Difference from Group and Stack

`Flex` component is a more general alternative to `Group` and `Stack` components:

- `Group` is `Flex` with `direction="row"` and some additional features (children positioning based on `justify` prop)
- `Stack` is `Flex` with `direction="column"`

Use `Flex` when you need more control over flex properties or when you need responsive direction changes.

## Props

| Prop      | Type                | Default  | Description          |
| --------- | ------------------- | -------- | -------------------- |
| gap       | MantineSpacing      | -        | Gap between elements |
| rowGap    | MantineSpacing      | -        | Row gap              |
| columnGap | MantineSpacing      | -        | Column gap           |
| align     | CSS align-items     | -        | Align items          |
| justify   | CSS justify-content | -        | Justify content      |
| wrap      | CSS flex-wrap       | 'nowrap' | Flex wrap            |
| direction | CSS flex-direction  | 'row'    | Flex direction       |

--------------------------------------------------------------------------------

### FloatingIndicator
Package: @tidbcloud/uikit
Import: import { FloatingIndicator } from '@tidbcloud/uikit';
Description: Display a floating highlight indicator over target elements.

Display a floating highlight indicator over target elements.

## Usage

`FloatingIndicator` is a component that displays a floating highlight over a target element. It is useful for creating navigation tabs, segmented controls, and other similar UI patterns.

```tsx

function Demo() {
  const [rootRef, setRootRef] = useState<HTMLDivElement | null>(null)
  const [controlsRefs, setControlsRefs] = useState<Record<string, HTMLButtonElement | null>>({})
  const [active, setActive] = useState(0)

  const setControlRef = (index: number) => (node: HTMLButtonElement) => {
    controlsRefs[index] = node
    setControlsRefs(controlsRefs)
  }

  const controls = ['React', 'Vue', 'Angular', 'Svelte'].map((item, index) => (
    <UnstyledButton
      key={item}
      className="control"
      ref={setControlRef(index)}
      onClick={() => setActive(index)}
      mod={{ active: active === index }}
    >
      <span className="controlLabel">{item}</span>
    </UnstyledButton>
  ))

  return (
    <div className="root" ref={setRootRef}>
      {controls}
      <FloatingIndicator target={controlsRefs[active]} parent={rootRef} className="indicator" />
    </div>
  )
}
```

## With Tabs

```tsx

function Demo() {
  const [rootRef, setRootRef] = useState<HTMLDivElement | null>(null)
  const [value, setValue] = useState<string | null>('first')
  const [controlsRefs, setControlsRefs] = useState<Record<string, HTMLButtonElement | null>>({})

  const setControlRef = (val: string) => (node: HTMLButtonElement) => {
    controlsRefs[val] = node
    setControlsRefs(controlsRefs)
  }

  return (
    <Tabs value={value} onChange={setValue}>
      <Tabs.List ref={setRootRef}>
        <Tabs.Tab value="first" ref={setControlRef('first')}>
          First tab
        </Tabs.Tab>
        <Tabs.Tab value="second" ref={setControlRef('second')}>
          Second tab
        </Tabs.Tab>
        <Tabs.Tab value="third" ref={setControlRef('third')}>
          Third tab
        </Tabs.Tab>

        <FloatingIndicator target={value ? controlsRefs[value] : null} parent={rootRef} className="indicator" />
      </Tabs.List>
    </Tabs>
  )
}
```

## Display vertical

Set `displayAxis="y"` to make the indicator expand vertically:

```tsx
<FloatingIndicator target={controlsRefs[active]} parent={rootRef} displayAxis="y" />
```

## Transition duration

Control the transition duration with `transitionDuration` prop:

```tsx
<FloatingIndicator target={controlsRefs[active]} parent={rootRef} transitionDuration={300} />
```

## Props

| Prop               | Type                | Default | Description                        |
| ------------------ | ------------------- | ------- | ---------------------------------- |
| target             | HTMLElement \| null | -       | Target element to highlight        |
| parent             | HTMLElement \| null | -       | Parent element for positioning     |
| displayAxis        | 'x' \| 'y'          | 'x'     | Axis along which indicator expands |
| transitionDuration | number              | 150     | Transition duration in ms          |

--------------------------------------------------------------------------------

### FocusTrap
Package: @tidbcloud/uikit
Import: import { FocusTrap } from '@tidbcloud/uikit';
Description: Trap focus within a container. Useful for modals and dropdowns.

Trap focus within a container. Useful for modals and dropdowns.

## Usage

`FocusTrap` is a component that traps focus inside a container. Tab key press moves focus from one focusable element to another within the container, and when focus leaves the container, it cycles back to the first focusable element.

```tsx

function Demo() {
  const [active, { toggle }] = useDisclosure(false)

  return (
    <Box maw={400} mx="auto">
      <Button onClick={toggle}>{active ? 'Deactivate' : 'Activate'} focus trap</Button>

      <FocusTrap active={active}>
        <div>
          <TextInput mt="sm" label="First input" placeholder="First input" />
          <TextInput mt="sm" label="Second input" placeholder="Second input" />
          <TextInput mt="sm" label="Third input" placeholder="Third input" />
        </div>
      </FocusTrap>
    </Box>
  )
}
```

## Initial focus

By default, `FocusTrap` focuses the first focusable element. To focus a specific element, set `data-autofocus` attribute:

```tsx

function Demo() {
  const [active, { toggle }] = useDisclosure(false)

  return (
    <Box maw={400} mx="auto">
      <Button onClick={toggle}>{active ? 'Deactivate' : 'Activate'} focus trap</Button>

      <FocusTrap active={active}>
        <div>
          <TextInput mt="sm" label="First input" placeholder="First input" />
          <TextInput mt="sm" label="Second input" placeholder="Second input" data-autofocus />
          <TextInput mt="sm" label="Third input" placeholder="Third input" />
        </div>
      </FocusTrap>
    </Box>
  )
}
```

## FocusTrap.InitialFocus

Use `FocusTrap.InitialFocus` component when you need to define an initial focus element that is not a text input (e.g., a button):

```tsx

function Demo() {
  const [active, { toggle }] = useDisclosure(false)

  return (
    <Box maw={400} mx="auto">
      <Button onClick={toggle}>{active ? 'Deactivate' : 'Activate'} focus trap</Button>

      <FocusTrap active={active}>
        <div>
          <FocusTrap.InitialFocus />
          <TextInput mt="sm" label="First input" placeholder="First input" />
          <TextInput mt="sm" label="Second input" placeholder="Second input" />
          <TextInput mt="sm" label="Third input" placeholder="Third input" />
        </div>
      </FocusTrap>
    </Box>
  )
}
```

## useFocusTrap hook

`useFocusTrap` hook can be used to implement custom focus trap components:

```tsx

function Demo() {
  const focusTrapRef = useFocusTrap()

  return (
    <Box maw={400} mx="auto" ref={focusTrapRef}>
      <TextInput mt="sm" label="First input" placeholder="First input" />
      <TextInput mt="sm" label="Second input" placeholder="Second input" data-autofocus />
      <TextInput mt="sm" label="Third input" placeholder="Third input" />
    </Box>
  )
}
```

## Props

| Prop     | Type      | Default | Description                    |
| -------- | --------- | ------- | ------------------------------ |
| active   | boolean   | true    | Whether focus trap is active   |
| children | ReactNode | -       | Content to trap focus within   |
| refProp  | string    | 'ref'   | Prop name to pass ref to child |

--------------------------------------------------------------------------------

### Grid
Package: @tidbcloud/uikit
Import: import { Grid } from '@tidbcloud/uikit';
Description: Flexbox-based 12-column grid system.

Flexbox-based 12-column grid system.

## Usage

```tsx

function Demo() {
  return (
    <Grid>
      <Grid.Col span={4}>1</Grid.Col>
      <Grid.Col span={4}>2</Grid.Col>
      <Grid.Col span={4}>3</Grid.Col>
    </Grid>
  )
}
```

## Columns span

`Grid.Col` `span` prop controls the ratio of column width to total width of the row. By default, grid uses 12 columns layout, so `span` can be any number from 1 to 12.

```tsx

function Demo() {
  return (
    <Grid>
      <Grid.Col span={3}>1</Grid.Col>
      <Grid.Col span={3}>2</Grid.Col>
      <Grid.Col span={3}>3</Grid.Col>
      <Grid.Col span={3}>4</Grid.Col>
      <Grid.Col span={4}>5</Grid.Col>
      <Grid.Col span={8}>6</Grid.Col>
    </Grid>
  )
}
```

## Gutter

Control spacing between columns with `gutter` prop:

```tsx

function Demo() {
  return (
    <Grid gutter="xl">
      <Grid.Col span={4}>1</Grid.Col>
      <Grid.Col span={4}>2</Grid.Col>
      <Grid.Col span={4}>3</Grid.Col>
    </Grid>
  )
}
```

## Grow

Set `grow` prop to make columns grow to fill available space:

```tsx

function Demo() {
  return (
    <Grid grow>
      <Grid.Col span={4}>1</Grid.Col>
      <Grid.Col span={4}>2</Grid.Col>
      <Grid.Col span={4}>3</Grid.Col>
      <Grid.Col span={4}>4</Grid.Col>
      <Grid.Col span={4}>5</Grid.Col>
    </Grid>
  )
}
```

## Column offset

Set `offset` prop on `Grid.Col` to create space before the column:

```tsx

function Demo() {
  return (
    <Grid>
      <Grid.Col span={3}>1</Grid.Col>
      <Grid.Col span={3}>2</Grid.Col>
      <Grid.Col span={3} offset={3}>
        3
      </Grid.Col>
    </Grid>
  )
}
```

## Column order

Set `order` prop on `Grid.Col` to control visual order:

```tsx

function Demo() {
  return (
    <Grid>
      <Grid.Col span={4} order={2}>
        1
      </Grid.Col>
      <Grid.Col span={4} order={3}>
        2
      </Grid.Col>
      <Grid.Col span={4} order={1}>
        3
      </Grid.Col>
    </Grid>
  )
}
```

## Responsive props

`span`, `offset`, and `order` props support responsive values:

```tsx

function Demo() {
  return (
    <Grid>
      <Grid.Col span={{ base: 12, md: 6, lg: 3 }}>1</Grid.Col>
      <Grid.Col span={{ base: 12, md: 6, lg: 3 }}>2</Grid.Col>
      <Grid.Col span={{ base: 12, md: 6, lg: 3 }}>3</Grid.Col>
      <Grid.Col span={{ base: 12, md: 6, lg: 3 }}>4</Grid.Col>
    </Grid>
  )
}
```

## Auto-sized columns

Set `span="auto"` to let column take available space:

```tsx

function Demo() {
  return (
    <Grid>
      <Grid.Col span="auto">1</Grid.Col>
      <Grid.Col span={6}>2</Grid.Col>
      <Grid.Col span="auto">3</Grid.Col>
    </Grid>
  )
}
```

## Content-sized columns

Set `span="content"` to make column take space based on content:

```tsx

function Demo() {
  return (
    <Grid>
      <Grid.Col span="content">Fit content</Grid.Col>
      <Grid.Col span={6}>2</Grid.Col>
    </Grid>
  )
}
```

## Change columns count

Set `columns` prop to change the default 12 columns layout:

```tsx

function Demo() {
  return (
    <Grid columns={24}>
      <Grid.Col span={12}>1</Grid.Col>
      <Grid.Col span={6}>2</Grid.Col>
      <Grid.Col span={6}>3</Grid.Col>
    </Grid>
  )
}
```

## Props

### Grid

| Prop    | Type                | Default | Description                          |
| ------- | ------------------- | ------- | ------------------------------------ |
| columns | number              | 12      | Number of grid columns               |
| gutter  | MantineSpacing      | 'md'    | Space between columns                |
| grow    | boolean             | false   | Columns grow to fill available space |
| justify | CSS justify-content | -       | Justify-content property             |
| align   | CSS align-items     | -       | Align-items property                 |

### Grid.Col

| Prop   | Type                          | Default | Description         |
| ------ | ----------------------------- | ------- | ------------------- |
| span   | number \| 'auto' \| 'content' | -       | Column span (1-12)  |
| offset | number                        | -       | Space before column |
| order  | number                        | -       | Visual order        |

--------------------------------------------------------------------------------

### Group
Package: @tidbcloud/uikit
Import: import { Group } from '@tidbcloud/uikit';
Description: Compose elements in a horizontal flex container.

Compose elements in a horizontal flex container.

## Usage

```tsx

function Demo() {
  return (
    <Group>
      <Button variant="default">First</Button>
      <Button variant="default">Second</Button>
      <Button variant="default">Third</Button>
    </Group>
  )
}
```

## Gap

Control spacing between children with `gap` prop. `gap` supports all spacing values from theme (xs, sm, md, lg, xl) and numbers:

```tsx

function Demo() {
  return (
    <Group gap="lg">
      <Button variant="default">First</Button>
      <Button variant="default">Second</Button>
      <Button variant="default">Third</Button>
    </Group>
  )
}
```

## Justify

Control `justify-content` property with `justify` prop:

```tsx

function Demo() {
  return (
    <>
      <Group justify="center">
        <Button variant="default">1</Button>
        <Button variant="default">2</Button>
        <Button variant="default">3</Button>
      </Group>
      <Group justify="flex-end" mt="md">
        <Button variant="default">1</Button>
        <Button variant="default">2</Button>
        <Button variant="default">3</Button>
      </Group>
      <Group justify="space-between" mt="md">
        <Button variant="default">1</Button>
        <Button variant="default">2</Button>
        <Button variant="default">3</Button>
      </Group>
    </>
  )
}
```

## Grow

Set `grow` to make children grow to fill available space:

```tsx

function Demo() {
  return (
    <Group grow>
      <Button variant="default">First</Button>
      <Button variant="default">Second</Button>
      <Button variant="default">Third</Button>
    </Group>
  )
}
```

## Wrap

By default, `Group` wraps children. Set `wrap="nowrap"` to prevent wrapping:

```tsx

function Demo() {
  return (
    <Group wrap="nowrap">
      <Button variant="default">First</Button>
      <Button variant="default">Second</Button>
      <Button variant="default">Third</Button>
    </Group>
  )
}
```

## Prevent flex-wrap

Use `preventGrowOverflow` prop to prevent children from taking more space than expected:

```tsx

function Demo() {
  return (
    <Group grow preventGrowOverflow={false} wrap="nowrap">
      <Button variant="default">
        <Text truncate>Very long button text</Text>
      </Button>
      <Button variant="default">Button 2</Button>
      <Button variant="default">Button 3</Button>
    </Group>
  )
}
```

## Responsive props

`gap` and `justify` props support responsive values:

```tsx

function Demo() {
  return (
    <Group justify={{ base: 'center', sm: 'flex-start' }} gap={{ base: 'sm', sm: 'lg' }}>
      <Button variant="default">First</Button>
      <Button variant="default">Second</Button>
      <Button variant="default">Third</Button>
    </Group>
  )
}
```

## Props

| Prop                | Type                | Default      | Description                 |
| ------------------- | ------------------- | ------------ | --------------------------- |
| gap                 | MantineSpacing      | 'md'         | Gap between children        |
| justify             | CSS justify-content | 'flex-start' | Justify-content property    |
| align               | CSS align-items     | 'center'     | Align-items property        |
| wrap                | CSS flex-wrap       | 'wrap'       | Flex-wrap property          |
| grow                | boolean             | false        | Children grow to fill space |
| preventGrowOverflow | boolean             | true         | Prevent grow overflow       |

--------------------------------------------------------------------------------

### Highlight
Package: @tidbcloud/uikit
Import: import { Highlight } from '@tidbcloud/uikit';
Description: Highlight a substring within a string with customizable styles.

Highlight a substring within a string with customizable styles.

## Basic Usage

Use `Highlight` to highlight a substring in a given string with a mark tag. Pass the main string as children and the substring to highlight via the `highlight` prop.

```tsx

function Demo() {
  return <Highlight highlight="important">This is an important message</Highlight>
}
```

## Highlight Multiple Substrings

Provide an array of values to highlight multiple substrings:

```tsx

function Demo() {
  return <Highlight highlight={['this', 'that']}>Highlight this and also that</Highlight>
}
```

## Custom Highlight Styles

Override default styles with the `highlightStyles` prop:

```tsx

function Demo() {
  return (
    <Highlight
      highlight={['highlighted', 'default']}
      highlightStyles={{
        backgroundImage: 'linear-gradient(45deg, var(--mantine-color-cyan-5), var(--mantine-color-indigo-5))',
        fontWeight: 700,
        WebkitBackgroundClip: 'text',
        WebkitTextFillColor: 'transparent'
      }}
    >
      You can change styles of highlighted part if you do not like default styles
    </Highlight>
  )
}
```

## Key Props

| Prop              | Type                 | Description                                  |
| ----------------- | -------------------- | -------------------------------------------- |
| `children`        | `string`             | String to search for highlight matches       |
| `highlight`       | `string \| string[]` | Substring or list of substrings to highlight |
| `highlightStyles` | `CSSProperties`      | Custom styles for highlighted text           |
| `color`           | `string`             | Color key from theme or any valid CSS color  |
| `size`            | `MantineSize`        | Controls font-size and line-height           |
| `inherit`         | `boolean`            | Inherit font properties from parent          |

--------------------------------------------------------------------------------

### HoverCard
Package: @tidbcloud/uikit
Import: import { HoverCard } from '@tidbcloud/uikit';
Description: Display a popover section when the target element is hovered.

Display a popover section when the target element is hovered.

## Basic Usage

```tsx

function Demo() {
  return (
    <Group justify="center">
      <HoverCard width={280} shadow="md">
        <HoverCard.Target>
          <Button>Hover to reveal the card</Button>
        </HoverCard.Target>
        <HoverCard.Dropdown>
          <Text size="sm">
            Hover card is revealed when user hovers over target element, it will be hidden once mouse is not over both
            target and dropdown elements
          </Text>
        </HoverCard.Dropdown>
      </HoverCard>
    </Group>
  )
}
```

## Delays

Set open and close delays with `openDelay` and `closeDelay` props (in ms):

```tsx

function Demo() {
  return (
    <Group justify="center">
      <HoverCard shadow="md" openDelay={1000}>
        <HoverCard.Target>
          <Button>1000ms open delay</Button>
        </HoverCard.Target>
        <HoverCard.Dropdown>
          <Text size="sm">Opened with 1000ms delay</Text>
        </HoverCard.Dropdown>
      </HoverCard>
    </Group>
  )
}
```

## HoverCard Group

Use `HoverCard.Group` to sync open/close delays across multiple HoverCards:

```tsx

function Demo() {
  return (
    <HoverCard.Group openDelay={500} closeDelay={100}>
      <Group justify="center">
        <HoverCard shadow="md">
          <HoverCard.Target>
            <Button>First</Button>
          </HoverCard.Target>
          <HoverCard.Dropdown>
            <Text size="sm">First hover card content</Text>
          </HoverCard.Dropdown>
        </HoverCard>
      </Group>
    </HoverCard.Group>
  )
}
```

## Key Props

| Prop         | Type                 | Description                          |
| ------------ | -------------------- | ------------------------------------ |
| `width`      | `number \| 'target'` | Dropdown width                       |
| `shadow`     | `MantineShadow`      | Box shadow for dropdown              |
| `openDelay`  | `number`             | Open delay in ms                     |
| `closeDelay` | `number`             | Close delay in ms                    |
| `withArrow`  | `boolean`            | Display an arrow pointing to target  |
| `position`   | `FloatingPosition`   | Dropdown position relative to target |
| `offset`     | `number`             | Offset of dropdown from target       |
| `disabled`   | `boolean`            | Disable the hover card               |

## Accessibility

HoverCard is ignored by screen readers and cannot be activated with keyboard. Use it only for additional, non-essential information.

--------------------------------------------------------------------------------

### HueSlider
Package: @tidbcloud/uikit
Import: import { HueSlider } from '@tidbcloud/uikit';
Description: A slider component for selecting hue values (0-360) in color pickers.

A slider component for selecting hue values (0-360) in color pickers.

## Basic Usage

```tsx

function Demo() {
  const [value, onChange] = useState(250)

  return (
    <>
      <Text>Hue value: {value}</Text>
      <HueSlider value={value} onChange={onChange} />
    </>
  )
}
```

## Controlled Component

```tsx

function Demo() {
  const [hue, setHue] = useState(180)

  return <HueSlider value={hue} onChange={setHue} onChangeEnd={(value) => console.log('Final hue:', value)} />
}
```

## Key Props

| Prop          | Type                      | Description                                  |
| ------------- | ------------------------- | -------------------------------------------- |
| `value`       | `number`                  | Controlled hue value (0-360)                 |
| `onChange`    | `(value: number) => void` | Called when value changes during interaction |
| `onChangeEnd` | `(value: number) => void` | Called when interaction ends                 |
| `size`        | `MantineSize`             | Slider size                                  |

## Accessibility

- Slider is focusable
- Values can be changed with arrow keys
- Set appropriate labels for screen readers

--------------------------------------------------------------------------------

### Image
Package: @tidbcloud/uikit
Import: import { Image } from '@tidbcloud/uikit';
Description: Image component with optional fallback support.

Image component with optional fallback support.

## Basic Usage

`Image` is a wrapper for `img` with minimal styles. By default, it takes 100% of parent width.

```tsx

function Demo() {
  return <Image radius="md" src="https://example.com/image.png" />
}
```

## Image Height

Set image height to prevent layout jumps during loading:

```tsx

function Demo() {
  return <Image radius="md" h={200} src="https://example.com/image.png" />
}
```

## Image Fit

By default, images use `object-fit: cover`. Use `fit="contain"` with `w="auto"` for different behavior:

```tsx

function Demo() {
  return <Image radius="md" h={200} w="auto" fit="contain" src="https://example.com/image.png" />
}
```

## Fallback Image

Display a fallback when the image fails to load:

```tsx

function Demo() {
  return <Image radius="md" src={null} h={200} fallbackSrc="https://placehold.co/600x400?text=Placeholder" />
}
```

## Usage with Next.js Image

`Image` is polymorphic and can be used with `next/image`:

```tsx

function Demo() {
  return <Image component={NextImage} src={myImage} alt="My image" />
}
```

## Key Props

| Prop          | Type               | Description                         |
| ------------- | ------------------ | ----------------------------------- |
| `src`         | `string`           | Image URL                           |
| `fallbackSrc` | `string`           | Fallback URL if image fails to load |
| `fit`         | `ObjectFit`        | Controls `object-fit` style         |
| `radius`      | `MantineRadius`    | Border radius                       |
| `h`           | `number \| string` | Image height                        |
| `w`           | `number \| string` | Image width                         |
| `onError`     | `function`         | Called when image fails to load     |

--------------------------------------------------------------------------------

### Indicator
Package: @tidbcloud/uikit
Import: import { Indicator } from '@tidbcloud/uikit';
Description: Display an indicator element at the corner of another element, commonly used for badges, notifications, or status indicators.

Display an indicator element at the corner of another element, commonly used for badges, notifications, or status indicators.

## Basic Usage

```tsx

function Demo() {
  return (
    <Indicator>
      <Avatar size="lg" radius="sm" src="https://example.com/avatar.png" />
    </Indicator>
  )
}
```

## With Label

Display content inside the indicator:

```tsx

function Demo() {
  return (
    <Indicator inline label="New" size={16}>
      <Avatar size="lg" radius="sm" src="https://example.com/avatar.png" />
    </Indicator>
  )
}
```

## Offset

Adjust position for elements with border-radius:

```tsx

function Demo() {
  return (
    <Indicator inline size={16} offset={7} position="bottom-end" color="red" withBorder>
      <Avatar size="lg" radius="xl" src="https://example.com/avatar.png" />
    </Indicator>
  )
}
```

## Processing Animation

Add a pulsing animation to the indicator:

```tsx

function Demo() {
  return (
    <Indicator inline processing color="red" size={12}>
      <Avatar size="lg" radius="sm" src="https://example.com/avatar.png" />
    </Indicator>
  )
}
```

## Disabled

Hide the indicator by setting `disabled`:

```tsx

function Demo() {
  return (
    <Indicator inline disabled color="red" size={12}>
      <Avatar size="lg" radius="sm" src="https://example.com/avatar.png" />
    </Indicator>
  )
}
```

## Key Props

| Prop         | Type                                                         | Description                          |
| ------------ | ------------------------------------------------------------ | ------------------------------------ |
| `label`      | `ReactNode`                                                  | Label displayed inside the indicator |
| `color`      | `MantineColor`                                               | Indicator background color           |
| `size`       | `number \| string`                                           | Indicator width and height           |
| `position`   | `'top-start' \| 'top-end' \| 'bottom-start' \| 'bottom-end'` | Position relative to target          |
| `offset`     | `number`                                                     | Offset from target element           |
| `processing` | `boolean`                                                    | Enable pulsing animation             |
| `disabled`   | `boolean`                                                    | Hide the indicator                   |
| `withBorder` | `boolean`                                                    | Add border to indicator              |
| `inline`     | `boolean`                                                    | Make container inline-block          |

--------------------------------------------------------------------------------

### Input
Package: @tidbcloud/uikit
Import: import { Input } from '@tidbcloud/uikit';
Description: Base component for creating custom inputs. In most cases, prefer using `TextInput` or other specific input components instead.

Base component for creating custom inputs. In most cases, prefer using `TextInput` or other specific input components instead.

## Important Note

`Input` is a base component not designed for direct use. Use it to create custom inputs; for standard use cases, prefer `TextInput` or other input components.

```tsx

// ❌ Incorrect: Input alone is not accessible
function Incorrect() {
  return (
    <Input.Wrapper label="Input label">
      <Input />
    </Input.Wrapper>
  )
}

// ✅ Correct: Use TextInput which includes accessibility features
function Correct() {
  return <TextInput label="Input label" description="Input description" />
}
```

## Basic Usage

```tsx

function Demo() {
  return <Input placeholder="Input component" />
}
```

## Input Sections

Add icons or buttons alongside the input:

```tsx

function Demo() {
  const [value, setValue] = useState('Clear me')
  return (
    <>
      <Input placeholder="Your email" leftSection={<IconAt size={16} />} />
      <Input
        placeholder="Clearable input"
        value={value}
        onChange={(event) => setValue(event.currentTarget.value)}
        rightSectionPointerEvents="all"
        mt="md"
        rightSection={
          <CloseButton
            aria-label="Clear input"
            onClick={() => setValue('')}
            style={{ display: value ? undefined : 'none' }}
          />
        }
      />
    </>
  )
}
```

## Input.Wrapper

Wrap inputs with labels, descriptions, and error messages:

```tsx

function Demo() {
  return (
    <Input.Wrapper label="Your email" description="We'll never share your email" error="">
      <Input placeholder="your@email.com" />
    </Input.Wrapper>
  )
}
```

## Polymorphic Component

`Input` can render as different elements:

```tsx

function Demo() {
  return (
    <>
      <Input component="button" pointer>
        Button input
      </Input>
      <Input component="select" rightSection={<IconChevronDown size={14} />} pointer>
        <option value="1">Option 1</option>
        <option value="2">Option 2</option>
      </Input>
    </>
  )
}
```

## Key Props

| Prop           | Type            | Description               |
| -------------- | --------------- | ------------------------- |
| `leftSection`  | `ReactNode`     | Content on the left side  |
| `rightSection` | `ReactNode`     | Content on the right side |
| `size`         | `MantineSize`   | Input height and padding  |
| `radius`       | `MantineRadius` | Border radius             |
| `disabled`     | `boolean`       | Disable the input         |
| `error`        | `ReactNode`     | Error state and message   |
| `pointer`      | `boolean`       | Show pointer cursor       |
| `component`    | `ElementType`   | Root element type         |

## Accessibility

Always associate inputs with labels using matching `id` attributes or use components like `TextInput` that handle accessibility automatically.

--------------------------------------------------------------------------------

### JsonInput
Package: @tidbcloud/uikit
Import: import { JsonInput } from '@tidbcloud/uikit';
Description: Textarea input for capturing and validating JSON data from users.

Textarea input for capturing and validating JSON data from users.

## Basic Usage

`JsonInput` includes JSON validation and optional formatting on blur:

```tsx

function Demo() {
  return (
    <JsonInput
      label="Your package.json"
      placeholder="Textarea will autosize to fit the content"
      validationError="Invalid JSON"
      formatOnBlur
      autosize
      minRows={4}
    />
  )
}
```

## Controlled

```tsx

function Demo() {
  const [value, setValue] = useState('')
  return <JsonInput value={value} onChange={setValue} />
}
```

## With Validation Error

```tsx

function Demo() {
  return (
    <JsonInput
      label="Configuration"
      placeholder='{ "key": "value" }'
      validationError="Please enter valid JSON"
      formatOnBlur
      autosize
      minRows={4}
    />
  )
}
```

## Disabled State

```tsx

function Demo() {
  return <JsonInput disabled defaultValue='{ "a": 1, "b": 2 }' label="Disabled" placeholder="Disabled" />
}
```

## Key Props

| Prop              | Type                      | Description                        |
| ----------------- | ------------------------- | ---------------------------------- |
| `value`           | `string`                  | Controlled value                   |
| `onChange`        | `(value: string) => void` | Called when value changes          |
| `validationError` | `ReactNode`               | Error message for invalid JSON     |
| `formatOnBlur`    | `boolean`                 | Format JSON when input loses focus |
| `autosize`        | `boolean`                 | Auto-grow textarea height          |
| `minRows`         | `number`                  | Minimum rows for autosize          |
| `maxRows`         | `number`                  | Maximum rows for autosize          |
| `label`           | `ReactNode`               | Input label                        |
| `description`     | `ReactNode`               | Input description                  |
| `error`           | `ReactNode`               | Error message                      |
| `disabled`        | `boolean`                 | Disable the input                  |

## Accessibility

Associate the input with a label for better screen reader support.

--------------------------------------------------------------------------------

### Kbd
Package: @tidbcloud/uikit
Import: import { Kbd } from '@tidbcloud/uikit';
Description: Display keyboard keys or shortcuts in a styled inline element.

Display keyboard keys or shortcuts in a styled inline element.

## Basic Usage

```tsx

function Demo() {
  return <Kbd>Shift</Kbd>
}
```

## Keyboard Shortcuts

Display key combinations:

```tsx

function Demo() {
  return (
    <>
      <Kbd>⌘</Kbd> + <Kbd>K</Kbd>
    </>
  )
}
```

## With Text

Combine with text for instructions:

```tsx

function Demo() {
  return (
    <Text>
      Press <Kbd>⌘</Kbd> + <Kbd>Shift</Kbd> + <Kbd>P</Kbd> to open command palette
    </Text>
  )
}
```

## Different Sizes

```tsx

function Demo() {
  return (
    <Stack>
      <div>
        <Kbd size="xs">Ctrl</Kbd> - Extra small
      </div>
      <div>
        <Kbd size="sm">Ctrl</Kbd> - Small
      </div>
      <div>
        <Kbd size="md">Ctrl</Kbd> - Medium
      </div>
      <div>
        <Kbd size="lg">Ctrl</Kbd> - Large
      </div>
      <div>
        <Kbd size="xl">Ctrl</Kbd> - Extra large
      </div>
    </Stack>
  )
}
```

## Key Props

| Prop       | Type                    | Description                    |
| ---------- | ----------------------- | ------------------------------ |
| `size`     | `MantineSize \| number` | Controls font-size and padding |
| `children` | `ReactNode`             | Key text to display            |

--------------------------------------------------------------------------------

### List
Package: @tidbcloud/uikit
Import: import { List } from '@tidbcloud/uikit';
Description: Display ordered or unordered list with optional icons and nested items.

Display ordered or unordered list with optional icons and nested items.

## Basic Usage

```tsx

function Demo() {
  return (
    <List>
      <List.Item>Clone or download repository from GitHub</List.Item>
      <List.Item>Install dependencies with yarn</List.Item>
      <List.Item>To start development server run npm start command</List.Item>
      <List.Item>Run tests to make sure your changes do not break the build</List.Item>
      <List.Item>Submit a pull request once you are done</List.Item>
    </List>
  )
}
```

## With Icons

Replace list bullets with custom icons using the `icon` prop on `List` or `List.Item`.

```tsx

function Demo() {
  return (
    <List
      spacing="xs"
      size="sm"
      center
      icon={
        <ThemeIcon color="teal" size={24} radius="xl">
          <IconCircleCheck size={16} />
        </ThemeIcon>
      }
    >
      <List.Item>Clone or download repository from GitHub</List.Item>
      <List.Item>Install dependencies with yarn</List.Item>
      <List.Item
        icon={
          <ThemeIcon color="blue" size={24} radius="xl">
            <IconCircleDashed size={16} />
          </ThemeIcon>
        }
      >
        Submit a pull request once you are done
      </List.Item>
    </List>
  )
}
```

## Nested Lists

Use `withPadding` prop to offset nested lists and `listStyleType` to control bullet type.

```tsx

function Demo() {
  return (
    <List listStyleType="disc">
      <List.Item>First order item</List.Item>
      <List.Item>
        First order item with list
        <List withPadding listStyleType="disc">
          <List.Item>Nested item</List.Item>
          <List.Item>Nested item</List.Item>
        </List>
      </List.Item>
      <List.Item>First order item</List.Item>
    </List>
  )
}
```

## Key Props

| Prop            | Type                       | Description                        |
| --------------- | -------------------------- | ---------------------------------- |
| `type`          | `'ordered' \| 'unordered'` | List type (default: unordered)     |
| `icon`          | `ReactNode`                | Icon to replace list item bullet   |
| `spacing`       | `MantineSpacing`           | Spacing between list items         |
| `size`          | `MantineSize`              | Controls font-size and line-height |
| `center`        | `boolean`                  | Center item content with icon      |
| `withPadding`   | `boolean`                  | Offset nested lists with padding   |
| `listStyleType` | `string`                   | Controls CSS list-style-type       |

--------------------------------------------------------------------------------

### Loader
Package: @tidbcloud/uikit
Import: import { Loader } from '@tidbcloud/uikit';
Description: Indicate loading state with animated loading indicators.

Indicate loading state with animated loading indicators.

## Basic Usage

```tsx

function Demo() {
  return <Loader />
}
```

## Loader Types

Loader supports 3 types: `oval` (default), `bars`, and `dots`.

```tsx

function Demo() {
  return (
    <Group>
      <Loader type="oval" />
      <Loader type="bars" />
      <Loader type="dots" />
    </Group>
  )
}
```

## Size and Color

```tsx

function Demo() {
  return (
    <Group>
      <Loader size="xs" />
      <Loader size="sm" />
      <Loader size="md" />
      <Loader size="lg" />
      <Loader size="xl" />
      <Loader size={50} color="blue" />
    </Group>
  )
}
```

## Custom Children

Use `children` prop to render custom content instead of the loader.

```tsx

function Demo() {
  return <Loader>Loading...</Loader>
}
```

## Key Props

| Prop       | Type                         | Description                              |
| ---------- | ---------------------------- | ---------------------------------------- |
| `type`     | `'oval' \| 'bars' \| 'dots'` | Loader animation type                    |
| `size`     | `MantineSize \| number`      | Controls width and height                |
| `color`    | `MantineColor`               | Loader color from theme or CSS color     |
| `children` | `ReactNode`                  | Custom content to replace default loader |
| `loaders`  | `object`                     | Custom loader components                 |

--------------------------------------------------------------------------------

### LoadingOverlay
Package: @tidbcloud/uikit
Import: import { LoadingOverlay } from '@tidbcloud/uikit';
Description: Display an overlay with a centered loader over the parent element.

Display an overlay with a centered loader over the parent element.

## Basic Usage

Renders an overlay with a loader over the parent element with `position: relative`.

```tsx

function Demo() {
  const [visible, { toggle }] = useDisclosure(false)

  return (
    <>
      <Box pos="relative">
        <LoadingOverlay visible={visible} zIndex={1000} overlayProps={{ radius: 'sm', blur: 2 }} />
        {/* ...other content */}
      </Box>

      <Group justify="center">
        <Button onClick={toggle}>Toggle overlay</Button>
      </Group>
    </>
  )
}
```

## Loader Props

Customize the loader using `loaderProps`.

```tsx

function Demo() {
  return (
    <Box pos="relative">
      <LoadingOverlay
        visible={true}
        zIndex={1000}
        overlayProps={{ radius: 'sm', blur: 2 }}
        loaderProps={{ color: 'pink', type: 'bars' }}
      />
      {/* ...content */}
    </Box>
  )
}
```

## Custom Loader Content

Replace the default loader with custom content.

```tsx

function Demo() {
  return (
    <Box pos="relative">
      <LoadingOverlay visible={true} loaderProps={{ children: 'Loading...' }} />
      {/* ...content */}
    </Box>
  )
}
```

## Key Props

| Prop              | Type               | Description                          |
| ----------------- | ------------------ | ------------------------------------ |
| `visible`         | `boolean`          | Controls overlay visibility          |
| `zIndex`          | `number \| string` | Overlay z-index                      |
| `loaderProps`     | `LoaderProps`      | Props passed to Loader component     |
| `overlayProps`    | `OverlayProps`     | Props passed to Overlay component    |
| `transitionProps` | `TransitionProps`  | Props passed to Transition component |

--------------------------------------------------------------------------------

### Mark
Package: @tidbcloud/uikit
Import: import { Mark } from '@tidbcloud/uikit';
Description: Highlight part of the text with a background color.

Highlight part of the text with a background color.

## Basic Usage

```tsx

function Demo() {
  return (
    <Text>
      Highlight <Mark>this chunk</Mark> of the text
    </Text>
  )
}
```

## Custom Color

```tsx

function Demo() {
  return (
    <Text>
      Highlight <Mark color="blue">with blue</Mark> or <Mark color="red.3">with red</Mark>
    </Text>
  )
}
```

## Key Props

| Prop    | Type           | Description                                        |
| ------- | -------------- | -------------------------------------------------- |
| `color` | `MantineColor` | Background color from theme or any valid CSS color |

--------------------------------------------------------------------------------

### MediaQuery
Package: @tidbcloud/uikit
Import: import { MediaQuery } from '@tidbcloud/uikit';
Description: Apply styles to children based on media query. This component is useful for applying responsive styles without using CSS media queries directly.

Apply styles to children based on media query. This component is useful for applying responsive styles without using CSS media queries directly.

## Basic Usage

```tsx

function Demo() {
  return (
    <MediaQuery smallerThan="sm" styles={{ display: 'none' }}>
      <Text>Hidden on small screens</Text>
    </MediaQuery>
  )
}
```

## Larger Than Breakpoint

```tsx

function Demo() {
  return (
    <MediaQuery largerThan="md" styles={{ color: 'red' }}>
      <Text>Red text on medium and larger screens</Text>
    </MediaQuery>
  )
}
```

## Using Theme Function

```tsx

function Demo() {
  return (
    <MediaQuery
      smallerThan="lg"
      styles={(theme) => ({
        backgroundColor: theme.colors.blue[0],
        padding: theme.spacing.md
      })}
    >
      <Text>Styled with theme</Text>
    </MediaQuery>
  )
}
```

## Custom Media Query

```tsx

function Demo() {
  return (
    <MediaQuery query="(max-width: 600px) and (min-width: 400px)" styles={{ fontSize: 12 }}>
      <Text>Custom query styles</Text>
    </MediaQuery>
  )
}
```

## Props

| Prop          | Type                                              | Description                                                |
| ------------- | ------------------------------------------------- | ---------------------------------------------------------- |
| `children`    | `ReactNode`                                       | Child element that should accept className prop (required) |
| `smallerThan` | `MantineSize \| number`                           | Apply styles when viewport is smaller than breakpoint      |
| `largerThan`  | `MantineSize \| number`                           | Apply styles when viewport is larger than breakpoint       |
| `query`       | `string`                                          | Custom media query string                                  |
| `styles`      | `CSSObject \| (theme: MantineTheme) => CSSObject` | Styles to apply when media query matches (required)        |
| `className`   | `string`                                          | Additional className for the child                         |

--------------------------------------------------------------------------------

### Menu
Package: @tidbcloud/uikit
Import: import { Menu } from '@tidbcloud/uikit';
Description: Combine a list of secondary actions into a single interactive dropdown area.

Combine a list of secondary actions into a single interactive dropdown area.

## Basic Usage

```tsx

function Demo() {
  return (
    <Menu shadow="md" width={200}>
      <Menu.Target>
        <Button>Toggle menu</Button>
      </Menu.Target>

      <Menu.Dropdown>
        <Menu.Label>Application</Menu.Label>
        <Menu.Item leftSection={<IconSettings size={14} />}>Settings</Menu.Item>

        <Menu.Divider />

        <Menu.Label>Danger zone</Menu.Label>
        <Menu.Item color="red" leftSection={<IconTrash size={14} />}>
          Delete my account
        </Menu.Item>
      </Menu.Dropdown>
    </Menu>
  )
}
```

## Submenus

```tsx

function Demo() {
  return (
    <Menu width={200} position="bottom-start">
      <Menu.Target>
        <Button>Toggle Menu</Button>
      </Menu.Target>

      <Menu.Dropdown>
        <Menu.Item>Dashboard</Menu.Item>

        <Menu.Sub>
          <Menu.Sub.Target>
            <Menu.Sub.Item>Products</Menu.Sub.Item>
          </Menu.Sub.Target>

          <Menu.Sub.Dropdown>
            <Menu.Item>All products</Menu.Item>
            <Menu.Item>Categories</Menu.Item>
          </Menu.Sub.Dropdown>
        </Menu.Sub>
      </Menu.Dropdown>
    </Menu>
  )
}
```

## Controlled

```tsx

function Demo() {
  const [opened, setOpened] = useState(false)
  return (
    <Menu opened={opened} onChange={setOpened}>
      {/* Menu content */}
    </Menu>
  )
}
```

## Hover Trigger

```tsx

function Demo() {
  return (
    <Menu trigger="hover" openDelay={100} closeDelay={400}>
      {/* ... menu items */}
    </Menu>
  )
}
```

## Key Props

| Prop               | Type                                  | Description                           |
| ------------------ | ------------------------------------- | ------------------------------------- |
| `opened`           | `boolean`                             | Controlled menu opened state          |
| `onChange`         | `(opened: boolean) => void`           | Called when menu opened state changes |
| `trigger`          | `'click' \| 'hover' \| 'click-hover'` | Event trigger to open menu            |
| `openDelay`        | `number`                              | Open delay in ms (for hover trigger)  |
| `closeDelay`       | `number`                              | Close delay in ms (for hover trigger) |
| `width`            | `number \| string`                    | Dropdown width                        |
| `position`         | `FloatingPosition`                    | Dropdown position relative to target  |
| `shadow`           | `MantineShadow`                       | Dropdown shadow                       |
| `withArrow`        | `boolean`                             | Display arrow pointing to target      |
| `closeOnItemClick` | `boolean`                             | Close menu when item is clicked       |
| `disabled`         | `boolean`                             | Disable menu dropdown                 |

--------------------------------------------------------------------------------

### Modal
Package: @tidbcloud/uikit
Import: import { Modal } from '@tidbcloud/uikit';
Description: An accessible overlay dialog for displaying content that requires user attention.

An accessible overlay dialog for displaying content that requires user attention.

## Basic Usage

```tsx

function Demo() {
  const [opened, { open, close }] = useDisclosure(false)

  return (
    <>
      <Modal opened={opened} onClose={close} title="Authentication">
        {/* Modal content */}
      </Modal>

      <Button onClick={open}>Open modal</Button>
    </>
  )
}
```

## Centered Modal

```tsx

function Demo() {
  const [opened, { open, close }] = useDisclosure(false)

  return (
    <>
      <Modal opened={opened} onClose={close} title="Authentication" centered>
        {/* Modal content */}
      </Modal>

      <Button onClick={open}>Open centered Modal</Button>
    </>
  )
}
```

## Fullscreen Modal

```tsx

function Demo() {
  const [opened, { open, close }] = useDisclosure(false)

  return (
    <>
      <Modal
        opened={opened}
        onClose={close}
        title="Fullscreen modal"
        fullScreen
        transitionProps={{ transition: 'fade', duration: 200 }}
      >
        {/* Modal content */}
      </Modal>

      <Button onClick={open}>Open fullscreen modal</Button>
    </>
  )
}
```

## Without Header

```tsx

function Demo() {
  return (
    <Modal opened={true} onClose={() => {}} withCloseButton={false}>
      Modal without header, press escape or click on overlay to close
    </Modal>
  )
}
```

## Customize Overlay

```tsx

function Demo() {
  return (
    <Modal
      opened={true}
      onClose={() => {}}
      title="Authentication"
      overlayProps={{
        backgroundOpacity: 0.55,
        blur: 3
      }}
    >
      {/* Modal content */}
    </Modal>
  )
}
```

## Key Props

| Prop                  | Type                              | Default | Description                                     |
| --------------------- | --------------------------------- | ------- | ----------------------------------------------- |
| `opened`              | `boolean`                         | -       | Controls modal visibility                       |
| `onClose`             | `() => void`                      | -       | Called when modal is closed                     |
| `title`               | `ReactNode`                       | -       | Modal title                                     |
| `centered`            | `boolean`                         | -       | Center modal vertically                         |
| `fullScreen`          | `boolean`                         | -       | Make modal fullscreen                           |
| `size`                | `MantineSize \| number \| string` | `'md'`  | Modal width (xs, sm, md, lg, xl, or any value)  |
| `radius`              | `MantineRadius`                   | -       | Border radius                                   |
| `withCloseButton`     | `boolean`                         | `true`  | Show/hide close button                          |
| `closeButtonProps`    | `CloseButtonProps`                | -       | Props passed to the close button                |
| `closeOnClickOutside` | `boolean`                         | `true`  | Close on outside click                          |
| `closeOnEscape`       | `boolean`                         | `true`  | Close on Escape key press                       |
| `overlayProps`        | `OverlayProps`                    | -       | Props for overlay customization                 |
| `withOverlay`         | `boolean`                         | `true`  | Determines whether overlay should be rendered   |
| `transitionProps`     | `TransitionProps`                 | -       | Transition animation props                      |
| `keepMounted`         | `boolean`                         | `false` | If set, modal will not be unmounted when closed |
| `lockScroll`          | `boolean`                         | `true`  | Determines whether scroll should be locked      |
| `trapFocus`           | `boolean`                         | `true`  | Determines whether focus should be trapped      |
| `returnFocus`         | `boolean`                         | `true`  | Return focus to last active element on close    |
| `padding`             | `MantineSpacing`                  | `'md'`  | Modal content padding                           |
| `shadow`              | `MantineShadow`                   | `'xl'`  | Modal shadow                                    |
| `zIndex`              | `string \| number`                | `200`   | z-index CSS property                            |
| `xOffset`             | `number \| string`                | -       | Horizontal content offset                       |
| `yOffset`             | `number \| string`                | -       | Vertical content offset                         |

--------------------------------------------------------------------------------

### MonthPicker
Package: @tidbcloud/uikit
Import: import { MonthPicker } from '@tidbcloud/uikit';
Description: Inline month, multiple months, and months range picker component.

Inline month, multiple months, and months range picker component.

## Basic Usage

```tsx

function Demo() {
  const [value, setValue] = useState<Date | null>(null)
  return <MonthPicker value={value} onChange={setValue} />
}
```

## Multiple Dates

Select multiple months with `type="multiple"`.

```tsx

function Demo() {
  const [value, setValue] = useState<Date[]>([])
  return <MonthPicker type="multiple" value={value} onChange={setValue} />
}
```

## Date Range

Select a range of months with `type="range"`.

```tsx

function Demo() {
  const [value, setValue] = useState<[Date | null, Date | null]>([null, null])
  return <MonthPicker type="range" value={value} onChange={setValue} />
}
```

## Min and Max Date

```tsx

function Demo() {
  const [value, setValue] = useState<Date | null>(null)
  return <MonthPicker value={value} onChange={setValue} minDate={new Date(2022, 1, 1)} maxDate={new Date(2022, 8, 1)} />
}
```

## Allow Deselect

Allow users to deselect the date by clicking on the selected item.

```tsx

function Demo() {
  const [value, setValue] = useState<Date | null>(null)
  return <MonthPicker allowDeselect value={value} onChange={setValue} />
}
```

## Key Props

| Prop                     | Type                                          | Description                                |
| ------------------------ | --------------------------------------------- | ------------------------------------------ |
| `value`                  | `DateValue \| DateValue[] \| DatesRangeValue` | Selected value                             |
| `onChange`               | `(value) => void`                             | Called when value changes                  |
| `type`                   | `'default' \| 'multiple' \| 'range'`          | Picker type                                |
| `allowDeselect`          | `boolean`                                     | Allow deselecting date (default type only) |
| `allowSingleDateInRange` | `boolean`                                     | Allow single date as range                 |
| `minDate`                | `string \| Date`                              | Minimum selectable date                    |
| `maxDate`                | `string \| Date`                              | Maximum selectable date                    |
| `defaultDate`            | `string \| Date`                              | Initial displayed date                     |
| `numberOfColumns`        | `number`                                      | Number of pickers side by side             |
| `maxLevel`               | `'month' \| 'year' \| 'decade'`               | Max level user can navigate to             |
| `locale`                 | `string`                                      | dayjs locale                               |
| `size`                   | `MantineSize`                                 | Component size                             |

--------------------------------------------------------------------------------

### MonthPickerInput
Package: @tidbcloud/uikit
Import: import { MonthPickerInput } from '@tidbcloud/uikit';
Description: Month, multiple months, and months range picker input with dropdown.

Month, multiple months, and months range picker input with dropdown.

## Basic Usage

```tsx

function Demo() {
  return <MonthPickerInput label="Pick month" placeholder="Pick month" />
}
```

## Multiple Dates

```tsx

function Demo() {
  return <MonthPickerInput type="multiple" label="Pick months" placeholder="Pick months" />
}
```

## Date Range

```tsx

function Demo() {
  return <MonthPickerInput type="range" label="Pick month range" placeholder="Pick month range" />
}
```

## Value Format

Customize the display format using `valueFormat` (dayjs format).

```tsx

function Demo() {
  return <MonthPickerInput valueFormat="YYYY MMM" type="multiple" label="Pick month" placeholder="Pick month" />
}
```

## Clearable

```tsx

function Demo() {
  return <MonthPickerInput label="Pick month" placeholder="Pick month" clearable />
}
```

## Open in Modal

```tsx

function Demo() {
  return <MonthPickerInput label="Pick month" placeholder="Pick month" dropdownType="modal" />
}
```

## Key Props

| Prop           | Type                                          | Description                    |
| -------------- | --------------------------------------------- | ------------------------------ |
| `value`        | `DateValue \| DateValue[] \| DatesRangeValue` | Selected value                 |
| `onChange`     | `(value) => void`                             | Called when value changes      |
| `type`         | `'default' \| 'multiple' \| 'range'`          | Picker type                    |
| `valueFormat`  | `string`                                      | dayjs format for display value |
| `clearable`    | `boolean`                                     | Show clear button              |
| `dropdownType` | `'popover' \| 'modal'`                        | Dropdown type                  |
| `minDate`      | `string \| Date`                              | Minimum selectable date        |
| `maxDate`      | `string \| Date`                              | Maximum selectable date        |
| `label`        | `ReactNode`                                   | Input label                    |
| `placeholder`  | `string`                                      | Input placeholder              |
| `disabled`     | `boolean`                                     | Disable input                  |
| `size`         | `MantineSize`                                 | Component size                 |
| `locale`       | `string`                                      | dayjs locale                   |

--------------------------------------------------------------------------------

### MultiSelect
Package: @tidbcloud/uikit
Import: import { MultiSelect } from '@tidbcloud/uikit';
Description: Custom searchable multi-select component for selecting multiple values from a list.

Custom searchable multi-select component for selecting multiple values from a list.

## Basic Usage

```tsx

function Demo() {
  return (
    <MultiSelect
      label="Your favorite libraries"
      placeholder="Pick value"
      data={['React', 'Angular', 'Vue', 'Svelte']}
    />
  )
}
```

## Controlled

```tsx

function Demo() {
  const [value, setValue] = useState<string[]>([])
  return <MultiSelect data={['React', 'Angular', 'Vue', 'Svelte']} value={value} onChange={setValue} />
}
```

## Searchable

```tsx

function Demo() {
  return (
    <MultiSelect
      label="Your favorite libraries"
      placeholder="Pick value"
      data={['React', 'Angular', 'Vue', 'Svelte']}
      searchable
    />
  )
}
```

## Clearable

```tsx

function Demo() {
  return (
    <MultiSelect
      label="Your favorite libraries"
      placeholder="Pick value"
      data={['React', 'Angular', 'Vue', 'Svelte']}
      defaultValue={['React']}
      clearable
    />
  )
}
```

## Max Values

Limit the number of selected values.

```tsx

function Demo() {
  return (
    <MultiSelect
      label="Your favorite libraries"
      placeholder="Select up to 2 libraries"
      data={['React', 'Angular', 'Vue', 'Svelte']}
      maxValues={2}
    />
  )
}
```

## Hide Picked Options

```tsx

function Demo() {
  return (
    <MultiSelect
      label="Your favorite libraries"
      placeholder="Pick value"
      data={['React', 'Angular', 'Vue', 'Svelte']}
      hidePickedOptions
    />
  )
}
```

## Grouped Options

```tsx

function Demo() {
  return (
    <MultiSelect
      label="Your favorite libraries"
      placeholder="Pick value"
      data={[
        { group: 'Frontend', items: ['React', 'Angular'] },
        { group: 'Backend', items: ['Express', 'Django'] }
      ]}
    />
  )
}
```

## Key Props

| Prop                  | Type                        | Description                          |
| --------------------- | --------------------------- | ------------------------------------ |
| `data`                | `string[] \| ComboboxData`  | Options data                         |
| `value`               | `string[]`                  | Selected values (controlled)         |
| `defaultValue`        | `string[]`                  | Default selected values              |
| `onChange`            | `(value: string[]) => void` | Called when value changes            |
| `searchable`          | `boolean`                   | Enable filtering by user input       |
| `clearable`           | `boolean`                   | Show clear button                    |
| `maxValues`           | `number`                    | Maximum number of selected values    |
| `hidePickedOptions`   | `boolean`                   | Hide selected options from dropdown  |
| `nothingFoundMessage` | `string`                    | Message when no options match search |
| `checkIconPosition`   | `'left' \| 'right'`         | Position of check icon               |
| `withCheckIcon`       | `boolean`                   | Show check icon on selected options  |
| `label`               | `ReactNode`                 | Input label                          |
| `placeholder`         | `string`                    | Input placeholder                    |
| `disabled`            | `boolean`                   | Disable input                        |
| `searchValue`         | `string`                    | Controlled search value              |
| `onSearchChange`      | `(value: string) => void`   | Called when search value changes     |

--------------------------------------------------------------------------------

### NativeSelect
Package: @tidbcloud/uikit
Import: import { NativeSelect } from '@tidbcloud/uikit';
Description: Native select element based on Input. Captures user selection from a dropdown list using the browser's native select element.

Native select element based on Input. Captures user selection from a dropdown list using the browser's native select element.

## Basic Usage

```tsx

function Demo() {
  return <NativeSelect data={['React', 'Angular', 'Vue']} />
}
```

## Controlled

```tsx

function Demo() {
  const [value, setValue] = useState('')

  return (
    <NativeSelect
      value={value}
      onChange={(event) => setValue(event.currentTarget.value)}
      data={['React', 'Angular', 'Svelte', 'Vue']}
    />
  )
}
```

## Data Formats

The `data` prop accepts multiple formats:

```tsx
// Array of strings
<NativeSelect data={['React', 'Angular', 'Vue']} />

// Array of objects
<NativeSelect
  data={[
    { label: 'React', value: 'react' },
    { label: 'Angular', value: 'angular' },
    { label: 'Vue', value: 'vue', disabled: true },
  ]}
/>

// Grouped options
<NativeSelect
  data={[
    {
      group: 'Frontend',
      items: ['React', 'Angular', 'Vue'],
    },
    {
      group: 'Backend',
      items: ['Express', 'Django'],
    },
  ]}
/>
```

## With Sections

```tsx

function Demo() {
  return <NativeSelect leftSection={<IconHash size={16} />} label="With left section" data={['React', 'Angular']} />
}
```

## Key Props

| Prop           | Type              | Description                       |
| -------------- | ----------------- | --------------------------------- |
| `data`         | `ComboboxData`    | Data used to render options       |
| `value`        | `string`          | Controlled input value            |
| `onChange`     | `(event) => void` | Called when value changes         |
| `label`        | `ReactNode`       | Input label                       |
| `description`  | `ReactNode`       | Input description                 |
| `error`        | `ReactNode`       | Error message                     |
| `disabled`     | `boolean`         | Disables the input                |
| `leftSection`  | `ReactNode`       | Content on the left side          |
| `rightSection` | `ReactNode`       | Content on the right side         |
| `size`         | `MantineSize`     | Controls input height and padding |
| `radius`       | `MantineRadius`   | Border radius                     |

--------------------------------------------------------------------------------

### NavLink
Package: @tidbcloud/uikit
Import: import { NavLink } from '@tidbcloud/uikit';
Description: Navigation link component for building sidebars and navigation menus. Supports nested links, icons, and various visual states.

Navigation link component for building sidebars and navigation menus. Supports nested links, icons, and various visual states.

## Basic Usage

```tsx

function Demo() {
  return (
    <>
      <NavLink href="#" label="With icon" leftSection={<IconHome2 size={16} stroke={1.5} />} />
      <NavLink
        href="#"
        label="With description"
        description="Additional information"
        leftSection={<IconGauge size={16} stroke={1.5} />}
      />
      <NavLink href="#" label="Active link" leftSection={<IconGauge size={16} stroke={1.5} />} active />
    </>
  )
}
```

## Active State

```tsx

function Demo() {
  const [active, setActive] = useState(0)

  const links = ['Dashboard', 'Security', 'Activity'].map((label, index) => (
    <NavLink key={label} label={label} active={index === active} onClick={() => setActive(index)} />
  ))

  return <>{links}</>
}
```

## Nested NavLinks

```tsx

function Demo() {
  return (
    <NavLink href="#" label="Parent link" leftSection={<IconGauge size={16} stroke={1.5} />} childrenOffset={28}>
      <NavLink href="#" label="First child" />
      <NavLink href="#" label="Second child" />
      <NavLink label="Nested parent" childrenOffset={28}>
        <NavLink label="Deep child" href="#" />
      </NavLink>
    </NavLink>
  )
}
```

## Variants

```tsx

function Demo() {
  return (
    <>
      <NavLink label="Light (default)" active />
      <NavLink label="Filled" variant="filled" active />
      <NavLink label="Subtle" variant="subtle" active />
    </>
  )
}
```

## Key Props

| Prop             | Type                              | Description                         |
| ---------------- | --------------------------------- | ----------------------------------- |
| `label`          | `ReactNode`                       | Main link label                     |
| `description`    | `ReactNode`                       | Secondary text below label          |
| `active`         | `boolean`                         | Applies active styles               |
| `variant`        | `'light' \| 'filled' \| 'subtle'` | Visual variant                      |
| `color`          | `MantineColor`                    | Color for active styles             |
| `leftSection`    | `ReactNode`                       | Icon/content on the left            |
| `rightSection`   | `ReactNode`                       | Icon/content on the right           |
| `children`       | `ReactNode`                       | Nested NavLink components           |
| `childrenOffset` | `MantineSpacing`                  | Left padding for nested links       |
| `defaultOpened`  | `boolean`                         | Initial open state for nested links |
| `disabled`       | `boolean`                         | Disables the link                   |
| `href`           | `string`                          | Link destination                    |

--------------------------------------------------------------------------------

### Notification
Package: @tidbcloud/uikit
Import: import { Notification } from '@tidbcloud/uikit';
Description: Display notifications and alerts to users. This is the base component for building notification systems.

Display notifications and alerts to users. This is the base component for building notification systems.

## Basic Usage

```tsx

function Demo() {
  return <Notification title="Default notification">This is a notification message</Notification>
}
```

## With Icon

```tsx

function Demo() {
  return (
    <>
      <Notification icon={<IconCheck size={20} />} color="teal" title="Success!">
        Your changes have been saved
      </Notification>

      <Notification icon={<IconX size={20} />} color="red" title="Error!">
        Something went wrong
      </Notification>
    </>
  )
}
```

## With Close Button

```tsx

function Demo() {
  return (
    <Notification title="Dismissable notification" withCloseButton onClose={() => console.log('closed')}>
      Click the close button to dismiss
    </Notification>
  )
}
```

## Loading State

```tsx

function Demo() {
  return (
    <Notification loading title="Uploading...">
      Please wait while we upload your file
    </Notification>
  )
}
```

## Key Props

| Prop               | Type            | Description                      |
| ------------------ | --------------- | -------------------------------- |
| `title`            | `ReactNode`     | Notification title               |
| `children`         | `ReactNode`     | Notification message body        |
| `icon`             | `ReactNode`     | Icon displayed on the left       |
| `color`            | `MantineColor`  | Color for icon or line           |
| `loading`          | `boolean`       | Shows loader instead of icon     |
| `withCloseButton`  | `boolean`       | Shows close button               |
| `onClose`          | `() => void`    | Called when close button clicked |
| `withBorder`       | `boolean`       | Adds border to notification      |
| `radius`           | `MantineRadius` | Border radius                    |
| `closeButtonProps` | `object`        | Props for close button           |

--------------------------------------------------------------------------------

### NumberFormatter
Package: @tidbcloud/uikit
Import: import { NumberFormatter } from '@tidbcloud/uikit';
Description: Format numbers with thousands/decimal separators, prefixes, and suffixes. Displays formatted numbers without input functionality.

Format numbers with thousands/decimal separators, prefixes, and suffixes. Displays formatted numbers without input functionality.

## Basic Usage

```tsx

function Demo() {
  return <NumberFormatter prefix="$ " value={1000000} thousandSeparator />
}
// Output: $ 1,000,000
```

## Prefix and Suffix

```tsx

function Demo() {
  return (
    <>
      <div>
        With prefix: <NumberFormatter prefix="$ " value={100} />
      </div>
      <div>
        With suffix: <NumberFormatter value={100} suffix=" RUB" />
      </div>
    </>
  )
}
```

## Thousands Separator

```tsx

function Demo() {
  return (
    <>
      <div>
        Default separator: <NumberFormatter thousandSeparator value={1000000} />
      </div>
      <div>
        Custom separator: <NumberFormatter thousandSeparator="." decimalSeparator="," value={1000000} />
      </div>
    </>
  )
}
```

## Decimal Scale

```tsx

function Demo() {
  return <NumberFormatter value={5 / 3} decimalScale={2} />
}
// Output: 1.67
```

## Key Props

| Prop                  | Type                                      | Description                      |
| --------------------- | ----------------------------------------- | -------------------------------- |
| `value`               | `string \| number`                        | Value to format                  |
| `prefix`              | `string`                                  | String added before value        |
| `suffix`              | `string`                                  | String added after value         |
| `thousandSeparator`   | `string \| boolean`                       | Character to separate thousands  |
| `decimalSeparator`    | `string`                                  | Character for decimal separator  |
| `decimalScale`        | `number`                                  | Number of decimal places         |
| `fixedDecimalScale`   | `boolean`                                 | Always show fixed decimal places |
| `allowNegative`       | `boolean`                                 | Allow negative values            |
| `thousandsGroupStyle` | `'thousand' \| 'lakh' \| 'wan' \| 'none'` | Grouping style                   |

--------------------------------------------------------------------------------

### NumberInput
Package: @tidbcloud/uikit
Import: import { NumberInput } from '@tidbcloud/uikit';
Description: Capture numeric input from user with increment/decrement controls. This is a custom wrapper in `@tidbcloud/uikit` based on react-number-format.

Capture numeric input from user with increment/decrement controls. This is a custom wrapper in `@tidbcloud/uikit` based on react-number-format.

## Basic Usage

```tsx

function Demo() {
  return <NumberInput label="Enter a number" placeholder="Your number" />
}
```

## Controlled

```tsx

function Demo() {
  const [value, setValue] = useState<string | number>('')
  return <NumberInput value={value} onChange={setValue} />
}
```

## Min and Max

```tsx

function Demo() {
  return <NumberInput label="Value between 10 and 20" min={10} max={20} />
}
```

## Prefix and Suffix

```tsx

function Demo() {
  return (
    <>
      <NumberInput label="Price" prefix="$" defaultValue={100} />
      <NumberInput label="Percentage" suffix="%" defaultValue={50} mt="md" />
    </>
  )
}
```

## Decimal Configuration

```tsx

function Demo() {
  return (
    <>
      <NumberInput label="No decimals" allowDecimal={false} />
      <NumberInput label="2 decimal places" decimalScale={2} fixedDecimalScale defaultValue={2.5} mt="md" />
    </>
  )
}
```

## Thousand Separator

```tsx

function Demo() {
  return <NumberInput label="With thousand separator" thousandSeparator="," defaultValue={1000000} />
}
```

## Hide Controls

```tsx

function Demo() {
  return <NumberInput label="No controls" hideControls />
}
```

## Key Props

| Prop                | Type                                | Description                      |
| ------------------- | ----------------------------------- | -------------------------------- |
| `value`             | `string \| number`                  | Controlled value                 |
| `onChange`          | `(value: string \| number) => void` | Called when value changes        |
| `min`               | `number`                            | Minimum value                    |
| `max`               | `number`                            | Maximum value                    |
| `step`              | `number`                            | Increment/decrement step         |
| `prefix`            | `string`                            | String before value              |
| `suffix`            | `string`                            | String after value               |
| `allowDecimal`      | `boolean`                           | Allow decimal values             |
| `decimalScale`      | `number`                            | Max decimal places               |
| `thousandSeparator` | `string \| boolean`                 | Thousand separator               |
| `hideControls`      | `boolean`                           | Hide increment/decrement buttons |
| `allowNegative`     | `boolean`                           | Allow negative numbers           |
| `clampBehavior`     | `'blur' \| 'strict' \| 'none'`      | How to clamp values              |
| `label`             | `ReactNode`                         | Input label                      |
| `error`             | `ReactNode`                         | Error message                    |
| `disabled`          | `boolean`                           | Disable input                    |

## Custom Addon Props (@tidbcloud/uikit)

| Prop              | Type              | Description                                         |
| ----------------- | ----------------- | --------------------------------------------------- |
| `leftAddon`       | `ReactNode`       | Content displayed as styled addon on the left side  |
| `rightAddon`      | `ReactNode`       | Content displayed as styled addon on the right side |
| `leftAddonProps`  | `TypographyProps` | Props passed to the left addon Typography wrapper   |
| `rightAddonProps` | `TypographyProps` | Props passed to the right addon Typography wrapper  |

--------------------------------------------------------------------------------

### Overlay
Package: @tidbcloud/uikit
Import: import { Overlay } from '@tidbcloud/uikit';
Description: Overlays parent element with a div element with any color and opacity. Useful for creating loading states or modal backdrops.

Overlays parent element with a div element with any color and opacity. Useful for creating loading states or modal backdrops.

## Basic Usage

```tsx

function Demo() {
  const [visible, setVisible] = useState(true)

  return (
    <>
      <Box pos="relative" h={200}>
        <img src="image.png" alt="Demo" />
        {visible && <Overlay color="#000" backgroundOpacity={0.85} />}
      </Box>
      <Button onClick={() => setVisible((v) => !v)}>Toggle overlay</Button>
    </>
  )
}
```

## With Gradient

```tsx

function Demo() {
  return (
    <Box pos="relative" h={200}>
      <img src="image.png" alt="Demo" />
      <Overlay gradient="linear-gradient(145deg, rgba(0, 0, 0, 0.95) 0%, rgba(0, 0, 0, 0) 100%)" />
    </Box>
  )
}
```

## With Blur

```tsx

function Demo() {
  return (
    <Box pos="relative" h={200}>
      <img src="image.png" alt="Demo" />
      <Overlay color="#000" backgroundOpacity={0.35} blur={2} />
    </Box>
  )
}
```

## Fixed Position

```tsx

function Demo() {
  return <Overlay fixed color="#000" backgroundOpacity={0.5} />
}
```

## Key Props

| Prop                | Type               | Description                    |
| ------------------- | ------------------ | ------------------------------ |
| `color`             | `string`           | Background color               |
| `backgroundOpacity` | `number`           | Opacity from 0 to 1            |
| `gradient`          | `string`           | CSS gradient (overrides color) |
| `blur`              | `string \| number` | Backdrop blur amount           |
| `fixed`             | `boolean`          | Use fixed positioning          |
| `center`            | `boolean`          | Center content inside overlay  |
| `zIndex`            | `string \| number` | z-index value                  |
| `radius`            | `MantineRadius`    | Border radius                  |
| `children`          | `ReactNode`        | Content inside overlay         |

--------------------------------------------------------------------------------

### Pagination
Package: @tidbcloud/uikit
Import: import { Pagination } from '@tidbcloud/uikit';
Description: Display active page and navigate between multiple pages. Supports customizable controls and styling.

Display active page and navigate between multiple pages. Supports customizable controls and styling.

## Basic Usage

```tsx

function Demo() {
  return <Pagination total={10} />
}
```

## Controlled

```tsx

function Demo() {
  const [activePage, setPage] = useState(1)
  return <Pagination total={10} value={activePage} onChange={setPage} />
}
```

## With Chunked Content

```tsx

const data = [
  /* array of items */
]
const itemsPerPage = 5

function Demo() {
  const [activePage, setPage] = useState(1)
  const totalPages = Math.ceil(data.length / itemsPerPage)

  const items = data
    .slice((activePage - 1) * itemsPerPage, activePage * itemsPerPage)
    .map((item) => <Text key={item.id}>{item.name}</Text>)

  return (
    <>
      {items}
      <Pagination total={totalPages} value={activePage} onChange={setPage} />
    </>
  )
}
```

## Siblings and Boundaries

```tsx

function Demo() {
  return (
    <>
      {/* Show 2 pages on each side of active */}
      <Pagination total={20} siblings={2} defaultValue={10} />

      {/* Show 3 pages at start and end */}
      <Pagination total={20} boundaries={3} defaultValue={10} />
    </>
  )
}
```

## With Edge Controls

```tsx

function Demo() {
  return <Pagination total={10} withEdges />
}
```

## Compound Components

```tsx

function Demo() {
  return (
    <Pagination.Root total={10}>
      <Group gap={5}>
        <Pagination.First />
        <Pagination.Previous />
        <Pagination.Items />
        <Pagination.Next />
        <Pagination.Last />
      </Group>
    </Pagination.Root>
  )
}
```

## Key Props

| Prop           | Type                     | Description                        |
| -------------- | ------------------------ | ---------------------------------- |
| `total`        | `number`                 | Total number of pages (required)   |
| `value`        | `number`                 | Controlled active page             |
| `onChange`     | `(page: number) => void` | Called when page changes           |
| `defaultValue` | `number`                 | Default active page                |
| `siblings`     | `number`                 | Pages shown on each side of active |
| `boundaries`   | `number`                 | Pages shown at start/end           |
| `withEdges`    | `boolean`                | Show first/last controls           |
| `withControls` | `boolean`                | Show next/previous controls        |
| `withPages`    | `boolean`                | Show page numbers                  |
| `color`        | `MantineColor`           | Active page color                  |
| `size`         | `MantineSize`            | Controls size                      |
| `radius`       | `MantineRadius`          | Border radius                      |
| `disabled`     | `boolean`                | Disable all controls               |

--------------------------------------------------------------------------------

### Paper
Package: @tidbcloud/uikit
Import: import { Paper } from '@tidbcloud/uikit';
Description: Renders white or dark background depending on color scheme. Use it to create cards, dropdowns, modals and other components that require a background with shadow.

Renders white or dark background depending on color scheme. Use it to create cards, dropdowns, modals and other components that require a background with shadow.

## Basic Usage

```tsx

function Demo() {
  return (
    <Paper p="xl">
      <Text>Paper is the most basic UI component</Text>
      <Text>Use it to create cards, dropdowns, modals and other components that require background with shadow</Text>
    </Paper>
  )
}
```

## With Shadow

```tsx

function Demo() {
  return (
    <Paper shadow="xs" p="xl">
      <Text>Paper with extra small shadow</Text>
    </Paper>
  )
}
```

## With Border

```tsx

function Demo() {
  return (
    <Paper withBorder p="xl">
      <Text>Paper with border</Text>
    </Paper>
  )
}
```

## With Radius

```tsx

function Demo() {
  return (
    <Paper radius="md" p="xl">
      <Text>Paper with medium border radius</Text>
    </Paper>
  )
}
```

## Key Props

| Prop         | Type             | Description                           |
| ------------ | ---------------- | ------------------------------------- |
| `shadow`     | `MantineShadow`  | Box shadow from theme or CSS value    |
| `radius`     | `MantineRadius`  | Border radius from theme or CSS value |
| `withBorder` | `boolean`        | Adds border to the element            |
| `p`          | `MantineSpacing` | Padding shorthand                     |
| `component`  | `ElementType`    | Polymorphic component root element    |

--------------------------------------------------------------------------------

### PasswordInput
Package: @tidbcloud/uikit
Import: import { PasswordInput } from '@tidbcloud/uikit';
Description: Capture password data from user with visibility toggle button. Supports all standard input features.

Capture password data from user with visibility toggle button. Supports all standard input features.

## Basic Usage

```tsx

function Demo() {
  return <PasswordInput label="Password" placeholder="Enter your password" />
}
```

## Controlled

```tsx

function Demo() {
  const [value, setValue] = useState('')
  return <PasswordInput value={value} onChange={(event) => setValue(event.currentTarget.value)} />
}
```

## Controlled Visibility

```tsx

function Demo() {
  const [visible, { toggle }] = useDisclosure(false)

  return (
    <Stack>
      <PasswordInput label="Password" visible={visible} onVisibilityChange={toggle} />
      <PasswordInput label="Confirm password" visible={visible} onVisibilityChange={toggle} />
    </Stack>
  )
}
```

## Custom Visibility Icon

```tsx

const VisibilityToggleIcon = ({ reveal }: { reveal: boolean }) =>
  reveal ? <IconEyeOff size={16} /> : <IconEyeCheck size={16} />

function Demo() {
  return <PasswordInput label="Password" visibilityToggleIcon={VisibilityToggleIcon} />
}
```

## With Left Section

```tsx

function Demo() {
  return <PasswordInput leftSection={<IconLock size={18} />} label="Password" placeholder="Enter password" />
}
```

## Key Props

| Prop                          | Type                         | Description                    |
| ----------------------------- | ---------------------------- | ------------------------------ |
| `value`                       | `string`                     | Controlled value               |
| `onChange`                    | `(event) => void`            | Called when value changes      |
| `visible`                     | `boolean`                    | Controlled visibility state    |
| `onVisibilityChange`          | `(visible: boolean) => void` | Called when visibility changes |
| `defaultVisible`              | `boolean`                    | Default visibility state       |
| `visibilityToggleIcon`        | `FC<{ reveal: boolean }>`    | Custom visibility toggle icon  |
| `visibilityToggleButtonProps` | `object`                     | Props for toggle button        |
| `label`                       | `ReactNode`                  | Input label                    |
| `description`                 | `ReactNode`                  | Input description              |
| `error`                       | `ReactNode`                  | Error message                  |
| `disabled`                    | `boolean`                    | Disable input                  |
| `leftSection`                 | `ReactNode`                  | Content on left side           |
| `size`                        | `MantineSize`                | Input size                     |
| `radius`                      | `MantineRadius`              | Border radius                  |

--------------------------------------------------------------------------------

### Pill
Package: @tidbcloud/uikit
Import: import { Pill } from '@tidbcloud/uikit';
Description: Removable and non-removable tags. Designed to be used inside inputs for creating custom multi-select or tag inputs.

Removable and non-removable tags. Designed to be used inside inputs for creating custom multi-select or tag inputs.

## Basic Usage

```tsx

function Demo() {
  return <Pill>React</Pill>
}
```

## With Remove Button

```tsx

function Demo() {
  return (
    <Pill withRemoveButton onRemove={() => console.log('removed')}>
      Removable
    </Pill>
  )
}
```

## Inside Inputs

```tsx

function Demo() {
  const pills = ['React', 'Vue', 'Angular'].map((item) => (
    <Pill key={item} withRemoveButton>
      {item}
    </Pill>
  ))

  return (
    <InputBase component="div" multiline>
      <Pill.Group>{pills}</Pill.Group>
    </InputBase>
  )
}
```

## Pill Group

```tsx

function Demo() {
  return (
    <Pill.Group>
      <Pill>First</Pill>
      <Pill>Second</Pill>
      <Pill>Third</Pill>
    </Pill.Group>
  )
}
```

## Disabled State

```tsx

function Demo() {
  return (
    <Pill disabled withRemoveButton>
      Disabled pill
    </Pill>
  )
}
```

## Key Props

| Prop                | Type            | Description                       |
| ------------------- | --------------- | --------------------------------- |
| `withRemoveButton`  | `boolean`       | Show remove button                |
| `onRemove`          | `() => void`    | Called when remove button clicked |
| `disabled`          | `boolean`       | Applies disabled styles           |
| `size`              | `MantineSize`   | Controls font-size and padding    |
| `radius`            | `MantineRadius` | Border radius                     |
| `removeButtonProps` | `object`        | Props for remove button           |

## Pill.Group Props

| Prop  | Type             | Description       |
| ----- | ---------------- | ----------------- |
| `gap` | `MantineSpacing` | Gap between pills |

--------------------------------------------------------------------------------

### PillsInput
Package: @tidbcloud/uikit
Import: import { PillsInput } from '@tidbcloud/uikit';
Description: Base component for custom tag inputs and multi-selects. A utility component that renders given children without its own logic.

Base component for custom tag inputs and multi-selects. A utility component that renders given children without its own logic.

## Basic Usage

```tsx

function Demo() {
  return (
    <PillsInput label="PillsInput">
      <Pill.Group>
        <Pill>React</Pill>
        <Pill>Vue</Pill>
        <Pill>Svelte</Pill>
        <PillsInput.Field placeholder="Enter tags" />
      </Pill.Group>
    </PillsInput>
  )
}
```

## With Removable Pills

```tsx

function Demo() {
  const [values, setValues] = useState(['React', 'Vue'])

  const handleRemove = (val: string) => {
    setValues((current) => current.filter((v) => v !== val))
  }

  const pills = values.map((item) => (
    <Pill key={item} withRemoveButton onRemove={() => handleRemove(item)}>
      {item}
    </Pill>
  ))

  return (
    <PillsInput label="Technologies">
      <Pill.Group>
        {pills}
        <PillsInput.Field placeholder="Add more" />
      </Pill.Group>
    </PillsInput>
  )
}
```

## With Combobox (Searchable Multiselect)

```tsx

const data = ['React', 'Vue', 'Angular', 'Svelte']

function Demo() {
  const combobox = useCombobox()
  const [search, setSearch] = useState('')
  const [value, setValue] = useState<string[]>([])

  const handleValueSelect = (val: string) =>
    setValue((current) => (current.includes(val) ? current.filter((v) => v !== val) : [...current, val]))

  const pills = value.map((item) => (
    <Pill key={item} withRemoveButton onRemove={() => handleValueSelect(item)}>
      {item}
    </Pill>
  ))

  return (
    <Combobox store={combobox} onOptionSubmit={handleValueSelect}>
      <Combobox.DropdownTarget>
        <PillsInput onClick={() => combobox.openDropdown()}>
          <Pill.Group>
            {pills}
            <Combobox.EventsTarget>
              <PillsInput.Field
                value={search}
                onChange={(e) => setSearch(e.currentTarget.value)}
                placeholder="Search..."
              />
            </Combobox.EventsTarget>
          </Pill.Group>
        </PillsInput>
      </Combobox.DropdownTarget>

      <Combobox.Dropdown>
        <Combobox.Options>
          {data
            .filter((item) => item.toLowerCase().includes(search.toLowerCase()))
            .map((item) => (
              <Combobox.Option key={item} value={item}>
                {item}
              </Combobox.Option>
            ))}
        </Combobox.Options>
      </Combobox.Dropdown>
    </Combobox>
  )
}
```

## Key Props

| Prop           | Type            | Description           |
| -------------- | --------------- | --------------------- |
| `label`        | `ReactNode`     | Input label           |
| `description`  | `ReactNode`     | Input description     |
| `error`        | `ReactNode`     | Error message         |
| `disabled`     | `boolean`       | Disable input         |
| `size`         | `MantineSize`   | Input size            |
| `radius`       | `MantineRadius` | Border radius         |
| `leftSection`  | `ReactNode`     | Content on left side  |
| `rightSection` | `ReactNode`     | Content on right side |
| `pointer`      | `boolean`       | Add pointer cursor    |

## PillsInput.Field Props

| Prop       | Type                              | Description           |
| ---------- | --------------------------------- | --------------------- |
| `type`     | `'visible' \| 'hidden' \| 'auto'` | Field visibility type |
| `disabled` | `boolean`                         | Disable field         |

--------------------------------------------------------------------------------

### PinInput
Package: @tidbcloud/uikit
Import: import { PinInput } from '@tidbcloud/uikit';
Description: Capture PIN code or one-time password from the user. Supports automatic focus management and various input types.

Capture PIN code or one-time password from the user. Supports automatic focus management and various input types.

## Basic Usage

```tsx

function Demo() {
  return <PinInput />
}
```

## Controlled

```tsx

function Demo() {
  const [value, setValue] = useState('')
  return <PinInput value={value} onChange={setValue} />
}
```

## Length

```tsx

function Demo() {
  return <PinInput length={6} />
}
```

## Number Type

```tsx

function Demo() {
  return <PinInput type="number" />
}
```

## Custom Regex Type

```tsx

function Demo() {
  // Only accept digits 0-3
  return <PinInput type={/^[0-3]*$/} inputType="tel" inputMode="numeric" />
}
```

## One-Time Code

```tsx

function Demo() {
  // Enables autocomplete="one-time-code" for SMS autofill
  return <PinInput oneTimeCode />
}
```

## Masked Input

```tsx

function Demo() {
  return <PinInput mask />
}
```

## On Complete

```tsx

function Demo() {
  return <PinInput length={4} onComplete={(value) => console.log('Completed:', value)} />
}
```

## Key Props

| Prop          | Type                                   | Description                   |
| ------------- | -------------------------------------- | ----------------------------- |
| `value`       | `string`                               | Controlled value              |
| `onChange`    | `(value: string) => void`              | Called when value changes     |
| `onComplete`  | `(value: string) => void`              | Called when all inputs filled |
| `length`      | `number`                               | Number of inputs              |
| `type`        | `'number' \| 'alphanumeric' \| RegExp` | Allowed characters            |
| `mask`        | `boolean`                              | Hide input characters         |
| `oneTimeCode` | `boolean`                              | Enable SMS autofill           |
| `placeholder` | `string`                               | Input placeholder             |
| `disabled`    | `boolean`                              | Disable all inputs            |
| `error`       | `boolean`                              | Apply error styles            |
| `size`        | `MantineSize`                          | Input size                    |
| `radius`      | `MantineRadius`                        | Border radius                 |
| `gap`         | `MantineSpacing`                       | Gap between inputs            |
| `manageFocus` | `boolean`                              | Auto-focus next input         |
| `autoFocus`   | `boolean`                              | Focus first input on mount    |

--------------------------------------------------------------------------------

### Popover
Package: @tidbcloud/uikit
Import: import { Popover } from '@tidbcloud/uikit';
Description: Display popover section relative to a target element. Useful for dropdowns, tooltips, and interactive content.

Display popover section relative to a target element. Useful for dropdowns, tooltips, and interactive content.

## Basic Usage

```tsx

function Demo() {
  return (
    <Popover width={200} position="bottom" withArrow shadow="md">
      <Popover.Target>
        <Button>Toggle popover</Button>
      </Popover.Target>
      <Popover.Dropdown>
        <Text size="xs">This is the popover content</Text>
      </Popover.Dropdown>
    </Popover>
  )
}
```

## Controlled

```tsx

function Demo() {
  const [opened, setOpened] = useState(false)

  return (
    <Popover opened={opened} onChange={setOpened}>
      <Popover.Target>
        <Button onClick={() => setOpened((o) => !o)}>Toggle popover</Button>
      </Popover.Target>
      <Popover.Dropdown>Dropdown content</Popover.Dropdown>
    </Popover>
  )
}
```

## Hover Trigger

```tsx

function Demo() {
  const [opened, { close, open }] = useDisclosure(false)

  return (
    <Popover width={200} position="bottom" withArrow opened={opened}>
      <Popover.Target>
        <Button onMouseEnter={open} onMouseLeave={close}>
          Hover me
        </Button>
      </Popover.Target>
      <Popover.Dropdown style={{ pointerEvents: 'none' }}>
        <Text size="sm">Hover popover content</Text>
      </Popover.Dropdown>
    </Popover>
  )
}
```

## With Form

```tsx

function Demo() {
  return (
    <Popover width={300} trapFocus position="bottom" withArrow shadow="md">
      <Popover.Target>
        <Button>Toggle form</Button>
      </Popover.Target>
      <Popover.Dropdown>
        <TextInput label="Name" placeholder="Name" size="xs" />
        <TextInput label="Email" placeholder="Email" size="xs" mt="xs" />
      </Popover.Dropdown>
    </Popover>
  )
}
```

## Same Width as Target

```tsx

function Demo() {
  return (
    <Popover width="target" position="bottom" withArrow>
      <Popover.Target>
        <Button w={280}>Toggle popover</Button>
      </Popover.Target>
      <Popover.Dropdown>
        <Text size="sm">Dropdown has same width as target</Text>
      </Popover.Dropdown>
    </Popover>
  )
}
```

## Key Props

| Prop                  | Type                        | Description               |
| --------------------- | --------------------------- | ------------------------- |
| `opened`              | `boolean`                   | Controlled open state     |
| `onChange`            | `(opened: boolean) => void` | Called when state changes |
| `defaultOpened`       | `boolean`                   | Initial open state        |
| `position`            | `FloatingPosition`          | Dropdown position         |
| `width`               | `number \| 'target'`        | Dropdown width            |
| `withArrow`           | `boolean`                   | Show arrow                |
| `arrowSize`           | `number`                    | Arrow size in px          |
| `offset`              | `number \| object`          | Dropdown offset           |
| `shadow`              | `MantineShadow`             | Dropdown shadow           |
| `radius`              | `MantineRadius`             | Border radius             |
| `trapFocus`           | `boolean`                   | Trap focus in dropdown    |
| `closeOnClickOutside` | `boolean`                   | Close on outside click    |
| `closeOnEscape`       | `boolean`                   | Close on Escape key       |
| `disabled`            | `boolean`                   | Disable popover           |
| `withinPortal`        | `boolean`                   | Render in portal          |
| `zIndex`              | `number`                    | z-index value             |

--------------------------------------------------------------------------------

### Portal
Package: @tidbcloud/uikit
Import: import { Portal } from '@tidbcloud/uikit';
Description: Renders component outside of parent element tree using ReactDOM.createPortal. Useful for modals, popovers, and fixed-position elements.

Renders component outside of parent element tree using ReactDOM.createPortal. Useful for modals, popovers, and fixed-position elements.

## Basic Usage

```tsx

function Demo() {
  const [opened, setOpened] = useState(false)

  return (
    <main style={{ position: 'relative', zIndex: 1 }}>
      {opened && (
        <Portal>
          <div>Your modal content</div>
        </Portal>
      )}

      <button onClick={() => setOpened(true)} type="button">
        Open modal
      </button>
    </main>
  )
}
```

## Custom Target

```tsx

// Render in existing element
function Demo() {
  return <Portal target="#portal-container">My portal</Portal>
}

// Or pass a DOM element
const container = document.getElementById('my-container')
function Demo2() {
  return <Portal target={container}>My portal</Portal>
}
```

## Reuse Target Node

```tsx

function Demo() {
  return (
    <>
      {/* All three will render in the same target node */}
      <Portal reuseTargetNode>
        <p>First</p>
      </Portal>
      <Portal reuseTargetNode>
        <p>Second</p>
      </Portal>
      <Portal reuseTargetNode>
        <p>Third</p>
      </Portal>
    </>
  )
}
```

## OptionalPortal

Use `OptionalPortal` to conditionally render in a portal:

```tsx

function Demo() {
  return (
    <>
      <OptionalPortal withinPortal>This text is rendered in Portal</OptionalPortal>
      <OptionalPortal withinPortal={false}>This text is rendered as regular child</OptionalPortal>
    </>
  )
}
```

## Key Props

| Prop              | Type                    | Description                            |
| ----------------- | ----------------------- | -------------------------------------- |
| `children`        | `ReactNode`             | Content to render in portal (required) |
| `target`          | `string \| HTMLElement` | Target element or selector             |
| `reuseTargetNode` | `boolean`               | Reuse same target for all portals      |

## Notes

- Portal content is rendered at the end of `document.body` by default
- Use Portal to prevent parent styles (z-index, position) from affecting children
- Not rendered during SSR - only after component mounts

--------------------------------------------------------------------------------

### Prism
Package: @tidbcloud/uikit
Import: import { Prism } from '@tidbcloud/uikit';
Description: Code highlight component with copy button. This is a custom component in `@tidbcloud/uikit` built on top of `prism-react-renderer`.

Code highlight component with copy button. This is a custom component in `@tidbcloud/uikit` built on top of `prism-react-renderer`.

## Basic Usage

```tsx

const code = `function greet(name: string) {
  console.log('Hello, ' + name + '!')
}

greet('World')`

function Demo() {
  return <Prism language="tsx">{code}</Prism>
}
```

## With Line Numbers

```tsx

const code = `const numbers = [1, 2, 3, 4, 5]
const doubled = numbers.map(n => n * 2)
console.log(doubled)`

function Demo() {
  return (
    <Prism language="javascript" withLineNumbers>
      {code}
    </Prism>
  )
}
```

## Highlight Lines

```tsx

const code = `function sum(a: number, b: number) {
  // This line is highlighted
  return a + b
}

const result = sum(1, 2)`

function Demo() {
  return (
    <Prism
      language="tsx"
      withLineNumbers
      highlightLines={{
        2: { color: 'yellow', label: 'Important' },
        3: { color: 'green' }
      }}
    >
      {code}
    </Prism>
  )
}
```

## Without Copy Button

```tsx

function Demo() {
  return (
    <Prism language="sql" noCopy>
      SELECT * FROM users WHERE id = 1
    </Prism>
  )
}
```

## Force Color Scheme

```tsx

function Demo() {
  return (
    <Prism language="json" colorScheme="dark">
      {JSON.stringify({ name: 'test', value: 123 }, null, 2)}
    </Prism>
  )
}
```

## Supported Languages

Prism supports many languages including: `javascript`, `typescript`, `tsx`, `jsx`, `json`, `css`, `html`, `sql`, `bash`, `python`, `go`, `rust`, and many more.

## Props

| Prop                  | Type                                                                  | Default       | Description                                   |
| --------------------- | --------------------------------------------------------------------- | ------------- | --------------------------------------------- |
| `children`            | `string`                                                              | -             | Code to highlight (required)                  |
| `language`            | `Language`                                                            | -             | Programming language for syntax highlighting  |
| `noCopy`              | `boolean`                                                             | `false`       | Remove copy to clipboard button               |
| `copyLabel`           | `string`                                                              | `'Copy code'` | Copy button tooltip                           |
| `copiedLabel`         | `string`                                                              | `'Copied'`    | Copy button tooltip in copied state           |
| `withLineNumbers`     | `boolean`                                                             | `false`       | Display line numbers                          |
| `highlightLines`      | `Record<number, { color: MantineColor; label?: string }>`             | `{}`          | Highlight specific lines with color and label |
| `colorScheme`         | `'dark' \| 'light'`                                                   | -             | Force color scheme                            |
| `trim`                | `boolean`                                                             | `true`        | Trim whitespace from code                     |
| `radius`              | `MantineRadius`                                                       | -             | Border radius                                 |
| `scrollAreaComponent` | `React.ComponentType`                                                 | `ScrollArea`  | Custom scroll area component                  |
| `getPrismTheme`       | `(theme: MantineTheme, colorScheme: 'light' \| 'dark') => PrismTheme` | -             | Custom theme function                         |

--------------------------------------------------------------------------------

### Progress
Package: @tidbcloud/uikit
Import: import { Progress } from '@tidbcloud/uikit';
Description: Give user feedback for status of tasks. Displays a progress bar that can be single or multi-sectioned.

Give user feedback for status of tasks. Displays a progress bar that can be single or multi-sectioned.

## Basic Usage

```tsx

function Demo() {
  return <Progress value={50} />
}
```

## With Label

```tsx

function Demo() {
  return <Progress value={75} size="xl" />
}
```

## Multiple Sections

```tsx

function Demo() {
  return (
    <Progress.Root size="xl">
      <Progress.Section value={35} color="cyan">
        <Progress.Label>Documents</Progress.Label>
      </Progress.Section>
      <Progress.Section value={28} color="pink">
        <Progress.Label>Photos</Progress.Label>
      </Progress.Section>
      <Progress.Section value={15} color="orange">
        <Progress.Label>Other</Progress.Label>
      </Progress.Section>
    </Progress.Root>
  )
}
```

## Striped and Animated

```tsx

function Demo() {
  return (
    <>
      <Progress value={65} striped />
      <Progress value={65} striped animated mt="md" />
    </>
  )
}
```

## With Transition

```tsx

function Demo() {
  const [value, setValue] = useState(50)

  return (
    <>
      <Progress value={value} transitionDuration={200} />
      <Button onClick={() => setValue(Math.random() * 100)} mt="md">
        Set random value
      </Button>
    </>
  )
}
```

## Vertical Orientation

```tsx

function Demo() {
  return (
    <Group>
      <Progress value={80} orientation="vertical" h={200} />
      <Progress value={60} color="orange" orientation="vertical" h={200} />
    </Group>
  )
}
```

## With Tooltips

```tsx

function Demo() {
  return (
    <Progress.Root size={40}>
      <Tooltip label="Documents – 33Gb">
        <Progress.Section value={33} color="cyan">
          <Progress.Label>Documents</Progress.Label>
        </Progress.Section>
      </Tooltip>
      <Tooltip label="Photos – 28Gb">
        <Progress.Section value={28} color="pink">
          <Progress.Label>Photos</Progress.Label>
        </Progress.Section>
      </Tooltip>
    </Progress.Root>
  )
}
```

## Key Props

| Prop                 | Type                         | Description             |
| -------------------- | ---------------------------- | ----------------------- |
| `value`              | `number`                     | Progress value (0-100)  |
| `color`              | `MantineColor`               | Progress bar color      |
| `size`               | `MantineSize \| number`      | Progress bar height     |
| `radius`             | `MantineRadius`              | Border radius           |
| `striped`            | `boolean`                    | Add stripes             |
| `animated`           | `boolean`                    | Animate stripes         |
| `transitionDuration` | `number`                     | Width transition in ms  |
| `orientation`        | `'horizontal' \| 'vertical'` | Bar orientation         |
| `autoContrast`       | `boolean`                    | Auto-adjust label color |

## Compound Components

- `Progress.Root` - Root wrapper for sections
- `Progress.Section` - Individual progress section
- `Progress.Label` - Label inside section

--------------------------------------------------------------------------------

### Radio
Package: @tidbcloud/uikit
Import: import { Radio } from '@tidbcloud/uikit';
Description: Radio component is a wrapper for native `input[type="radio"]` element. Use Radio to capture user input when only one option can be selected from a list.

Radio component is a wrapper for native `input[type="radio"]` element. Use Radio to capture user input when only one option can be selected from a list.

## Basic Usage

```tsx

function Demo() {
  return <Radio label="I agree to terms and conditions" />
}
```

## Controlled

```tsx

function Demo() {
  const [checked, setChecked] = useState(false)
  return (
    <Radio checked={checked} onChange={(event) => setChecked(event.currentTarget.checked)} label="Controlled radio" />
  )
}
```

## Radio.Group

Use `Radio.Group` to group multiple radio inputs together:

```tsx

function Demo() {
  return (
    <Radio.Group
      name="favoriteFramework"
      label="Select your favorite framework"
      description="This is anonymous"
      withAsterisk
    >
      <Group mt="xs">
        <Radio value="react" label="React" />
        <Radio value="svelte" label="Svelte" />
        <Radio value="ng" label="Angular" />
        <Radio value="vue" label="Vue" />
      </Group>
    </Radio.Group>
  )
}
```

## Controlled Radio.Group

```tsx

function Demo() {
  const [value, setValue] = useState('react')

  return (
    <Radio.Group value={value} onChange={setValue} name="favoriteFramework">
      <Group mt="xs">
        <Radio value="react" label="React" />
        <Radio value="svelte" label="Svelte" />
        <Radio value="ng" label="Angular" />
        <Radio value="vue" label="Vue" />
      </Group>
    </Radio.Group>
  )
}
```

## States

```tsx

function Demo() {
  return (
    <Stack>
      <Radio checked={false} onChange={() => {}} label="Default radio" />
      <Radio checked onChange={() => {}} label="Checked radio" />
      <Radio checked variant="outline" onChange={() => {}} label="Outline checked radio" />
      <Radio disabled label="Disabled radio" />
      <Radio disabled checked onChange={() => {}} label="Disabled checked radio" />
    </Stack>
  )
}
```

## Radio.Card

`Radio.Card` can be used to build custom cards/buttons that work as radios:

```tsx

function Demo() {
  const [checked, setChecked] = useState(false)

  return (
    <Radio.Card radius="md" checked={checked} onClick={() => setChecked((c) => !c)}>
      <Group wrap="nowrap" align="flex-start">
        <Radio.Indicator />
        <div>
          <Text fw={500}>@tidbcloud/uikit</Text>
          <Text size="sm" c="dimmed">
            Core components library: inputs, buttons, overlays, etc.
          </Text>
        </div>
      </Group>
    </Radio.Card>
  )
}
```

## Key Props

| Prop            | Type                | Description                                    |
| --------------- | ------------------- | ---------------------------------------------- |
| `label`         | `ReactNode`         | Content of the label associated with the radio |
| `description`   | `ReactNode`         | Description displayed below the label          |
| `error`         | `ReactNode`         | Error message displayed below the label        |
| `color`         | `MantineColor`      | Color of the radio in checked state            |
| `size`          | `MantineSize`       | Controls size of the component                 |
| `labelPosition` | `'left' \| 'right'` | Position of the label relative to the input    |
| `disabled`      | `boolean`           | Disables the radio input                       |
| `checked`       | `boolean`           | Controlled checked state                       |
| `onChange`      | `(event) => void`   | Called when checked state changes              |

## Radio.Group Props

| Prop           | Type                      | Description                          |
| -------------- | ------------------------- | ------------------------------------ |
| `value`        | `string`                  | Controlled component value           |
| `defaultValue` | `string`                  | Uncontrolled component default value |
| `onChange`     | `(value: string) => void` | Called when value changes            |
| `name`         | `string`                  | Name attribute of radio inputs       |
| `label`        | `ReactNode`               | Group label                          |
| `description`  | `ReactNode`               | Group description                    |
| `error`        | `ReactNode`               | Group error message                  |

--------------------------------------------------------------------------------

### Rating
Package: @tidbcloud/uikit
Import: import { Rating } from '@tidbcloud/uikit';
Description: Rating component allows users to pick and display a rating value using a visual star-based interface.

Rating component allows users to pick and display a rating value using a visual star-based interface.

## Basic Usage

```tsx

function Demo() {
  return <Rating defaultValue={2} />
}
```

## Controlled

```tsx

function Demo() {
  const [value, setValue] = useState(0)
  return <Rating value={value} onChange={setValue} />
}
```

## Read Only

```tsx

function Demo() {
  return <Rating value={3.5} fractions={2} readOnly />
}
```

## Fractions

Use `fractions` prop to allow fractional ratings:

```tsx

function Demo() {
  return (
    <Stack>
      <Group>
        <span>Fractions: 2</span>
        <Rating fractions={2} defaultValue={1.5} />
      </Group>
      <Group>
        <span>Fractions: 3</span>
        <Rating fractions={3} defaultValue={2.33} />
      </Group>
      <Group>
        <span>Fractions: 4</span>
        <Rating fractions={4} defaultValue={3.75} />
      </Group>
    </Stack>
  )
}
```

## Custom Symbol

```tsx

function Demo() {
  return <Rating emptySymbol={<IconSun size={16} />} fullSymbol={<IconMoon size={16} />} />
}
```

## Custom Symbols Per Item

```tsx

function Demo() {
  const getEmptyIcon = (value: number) => {
    const icons = [IconMoodCry, IconMoodSad, IconMoodSmile, IconMoodHappy, IconMoodCrazyHappy]
    const Icon = icons[value - 1]
    return <Icon size={24} />
  }

  const getFullIcon = (value: number) => {
    const colors = ['red', 'orange', 'yellow', 'lime', 'green']
    const icons = [IconMoodCry, IconMoodSad, IconMoodSmile, IconMoodHappy, IconMoodCrazyHappy]
    const Icon = icons[value - 1]
    return <Icon size={24} color={`var(--mantine-color-${colors[value - 1]}-7)`} />
  }

  return <Rating emptySymbol={getEmptyIcon} fullSymbol={getFullIcon} highlightSelectedOnly />
}
```

## Key Props

| Prop                    | Type                                | Default | Description                                       |
| ----------------------- | ----------------------------------- | ------- | ------------------------------------------------- |
| `value`                 | `number`                            | -       | Controlled component value                        |
| `defaultValue`          | `number`                            | -       | Uncontrolled component default value              |
| `onChange`              | `(value: number) => void`           | -       | Called when value changes                         |
| `count`                 | `number`                            | `5`     | Number of rating items                            |
| `fractions`             | `number`                            | `1`     | Number of fractions each item can be divided into |
| `size`                  | `MantineSize`                       | `'sm'`  | Controls component size                           |
| `color`                 | `MantineColor`                      | -       | Color of filled symbols                           |
| `readOnly`              | `boolean`                           | `false` | If set, user cannot interact with the component   |
| `highlightSelectedOnly` | `boolean`                           | `false` | If set, only the selected symbol changes to full  |
| `emptySymbol`           | `ReactNode \| (value) => ReactNode` | -       | Icon displayed when symbol is empty               |
| `fullSymbol`            | `ReactNode \| (value) => ReactNode` | -       | Icon displayed when symbol is full                |

--------------------------------------------------------------------------------

### RingProgress
Package: @tidbcloud/uikit
Import: import { RingProgress } from '@tidbcloud/uikit';
Description: RingProgress displays a circular progress indicator with customizable sections. Ideal for showing task completion status or data visualization.

RingProgress displays a circular progress indicator with customizable sections. Ideal for showing task completion status or data visualization.

## Basic Usage

Set `sections` prop to an array of objects with `value` (0-100) and `color`:

```tsx

function Demo() {
  return (
    <RingProgress
      label={
        <Text size="xs" ta="center">
          Application data usage
        </Text>
      }
      sections={[
        { value: 40, color: 'cyan' },
        { value: 15, color: 'orange' },
        { value: 15, color: 'grape' }
      ]}
    />
  )
}
```

## Size, Thickness & Rounded Caps

```tsx

function Demo() {
  return (
    <RingProgress
      size={200}
      thickness={20}
      roundCaps
      sections={[
        { value: 40, color: 'cyan' },
        { value: 15, color: 'orange' },
        { value: 15, color: 'grape' }
      ]}
    />
  )
}
```

## Sections with Tooltips

```tsx

function Demo() {
  return (
    <RingProgress
      size={170}
      thickness={16}
      label={
        <Text size="xs" ta="center" px="xs" style={{ pointerEvents: 'none' }}>
          Hover sections to see tooltips
        </Text>
      }
      sections={[
        { value: 40, color: 'cyan', tooltip: 'Documents – 40 Gb' },
        { value: 25, color: 'orange', tooltip: 'Apps – 25 Gb' },
        { value: 15, color: 'grape', tooltip: 'Other – 15 Gb' }
      ]}
    />
  )
}
```

## Root Color

```tsx

function Demo() {
  return <RingProgress sections={[{ value: 40, color: 'yellow' }]} rootColor="red" />
}
```

## Custom Label

```tsx

function Demo() {
  return (
    <>
      <RingProgress
        sections={[{ value: 40, color: 'blue' }]}
        label={
          <Text c="blue" fw={700} ta="center" size="xl">
            40%
          </Text>
        }
      />

      <RingProgress
        sections={[{ value: 100, color: 'teal' }]}
        label={
          <Center>
            <ActionIcon color="teal" variant="light" radius="xl" size="xl">
              <IconCheck size={22} />
            </ActionIcon>
          </Center>
        }
      />
    </>
  )
}
```

## Animated Transitions

```tsx

function Demo() {
  const [value, setValue] = useState(30)

  return (
    <Stack align="center">
      <RingProgress
        sections={[{ value, color: 'blue' }]}
        transitionDuration={250}
        label={<Text ta="center">{value}%</Text>}
      />
      <Button onClick={() => setValue(Math.floor(Math.random() * 100))}>Set random value</Button>
    </Stack>
  )
}
```

## Key Props

| Prop                 | Type                    | Default  | Description                                                 |
| -------------------- | ----------------------- | -------- | ----------------------------------------------------------- |
| `sections`           | `RingProgressSection[]` | required | Ring sections with `value`, `color`, and optional `tooltip` |
| `size`               | `number`                | `120`    | Width and height of the progress ring                       |
| `thickness`          | `number`                | `12`     | Ring thickness                                              |
| `roundCaps`          | `boolean`               | `false`  | Whether edges of progress circle are rounded                |
| `rootColor`          | `MantineColor`          | -        | Color of the root/empty section                             |
| `label`              | `ReactNode`             | -        | Label displayed in the center of the ring                   |
| `transitionDuration` | `number`                | `0`      | Transition duration in ms for animated changes              |

## Section Props

| Prop      | Type           | Description            |
| --------- | -------------- | ---------------------- |
| `value`   | `number`       | Segment value (0-100)  |
| `color`   | `MantineColor` | Segment color          |
| `tooltip` | `ReactNode`    | Tooltip shown on hover |

--------------------------------------------------------------------------------

### ScrollArea
Package: @tidbcloud/uikit
Import: import { ScrollArea } from '@tidbcloud/uikit';
Description: ScrollArea provides a container with custom styled scrollbars for consistent cross-browser appearance.

ScrollArea provides a container with custom styled scrollbars for consistent cross-browser appearance.

## Basic Usage

```tsx

function Demo() {
  return (
    <ScrollArea h={250}>
      {/* Long content here */}
      <p>Content that exceeds the container height...</p>
    </ScrollArea>
  )
}
```

## Horizontal Scrollbars

```tsx

function Demo() {
  return (
    <ScrollArea w={300} h={200}>
      <Box w={600}>{/* Wide content here */}</Box>
    </ScrollArea>
  )
}
```

## Scrollbar Types

Control scrollbar behavior with the `type` prop:

```tsx

function Demo() {
  return (
    <>
      {/* Scrollbars visible on hover (default) */}
      <ScrollArea h={200} type="hover">
        <div>Content...</div>
      </ScrollArea>

      {/* Scrollbars visible on scroll */}
      <ScrollArea h={200} type="scroll">
        <div>Content...</div>
      </ScrollArea>

      {/* Scrollbars always visible when content overflows */}
      <ScrollArea h={200} type="auto">
        <div>Content...</div>
      </ScrollArea>

      {/* Scrollbars always visible */}
      <ScrollArea h={200} type="always">
        <div>Content...</div>
      </ScrollArea>

      {/* Scrollbars always hidden */}
      <ScrollArea h={200} type="never">
        <div>Content...</div>
      </ScrollArea>
    </>
  )
}
```

## Subscribe to Scroll Position

```tsx

function Demo() {
  const [scrollPosition, onScrollPositionChange] = useState({ x: 0, y: 0 })

  return (
    <>
      <ScrollArea w={300} h={200} onScrollPositionChange={onScrollPositionChange}>
        <Box w={600} h={400}>
          {/* Content */}
        </Box>
      </ScrollArea>
      <Text>
        Scroll position: <Code>{`{ x: ${scrollPosition.x}, y: ${scrollPosition.y} }`}</Code>
      </Text>
    </>
  )
}
```

## Scroll to Position

```tsx

function Demo() {
  const viewport = useRef<HTMLDivElement>(null)

  const scrollToBottom = () => viewport.current?.scrollTo({ top: viewport.current.scrollHeight, behavior: 'smooth' })

  const scrollToTop = () => viewport.current?.scrollTo({ top: 0, behavior: 'smooth' })

  return (
    <Stack align="center">
      <ScrollArea w={300} h={200} viewportRef={viewport}>
        {/* Long content */}
      </ScrollArea>
      <Group>
        <Button onClick={scrollToTop}>Scroll to top</Button>
        <Button onClick={scrollToBottom}>Scroll to bottom</Button>
      </Group>
    </Stack>
  )
}
```

## ScrollArea.Autosize

Creates a scrollable container when content exceeds `maxHeight`:

```tsx

function Demo() {
  return (
    <ScrollArea.Autosize mah={300} maw={400}>
      {/* Content that may or may not exceed max height */}
    </ScrollArea.Autosize>
  )
}
```

## Key Props

| Prop                     | Type                                                   | Default     | Description                                               |
| ------------------------ | ------------------------------------------------------ | ----------- | --------------------------------------------------------- |
| `type`                   | `'hover' \| 'scroll' \| 'auto' \| 'always' \| 'never'` | `'hover'`   | Scrollbars behavior                                       |
| `scrollbarSize`          | `number \| string`                                     | `'0.75rem'` | Scrollbar width/height                                    |
| `offsetScrollbars`       | `boolean \| 'x' \| 'y' \| 'present'`                   | -           | Adds padding to offset scrollbars                         |
| `scrollHideDelay`        | `number`                                               | `1000`      | Delay in ms to hide scrollbars for `hover`/`scroll` types |
| `scrollbars`             | `'x' \| 'y' \| 'xy' \| false`                          | `'xy'`      | Which scrollbars to render                                |
| `viewportRef`            | `Ref<HTMLDivElement>`                                  | -           | Ref to the viewport element for programmatic scrolling    |
| `onScrollPositionChange` | `(position: { x: number; y: number }) => void`         | -           | Called when scroll position changes                       |
| `onTopReached`           | `() => void`                                           | -           | Called when scrolled to top                               |
| `onBottomReached`        | `() => void`                                           | -           | Called when scrolled to bottom                            |

--------------------------------------------------------------------------------

### SegmentedControl
Package: @tidbcloud/uikit
Import: import { SegmentedControl } from '@tidbcloud/uikit';
Description: SegmentedControl is a linear set of two or more segments, each of which functions as a mutually exclusive button.

SegmentedControl is a linear set of two or more segments, each of which functions as a mutually exclusive button.

## Basic Usage

```tsx

function Demo() {
  return <SegmentedControl data={['React', 'Angular', 'Vue']} />
}
```

## Controlled

```tsx

function Demo() {
  const [value, setValue] = useState('react')

  return (
    <SegmentedControl
      value={value}
      onChange={setValue}
      data={[
        { label: 'React', value: 'react' },
        { label: 'Angular', value: 'ng' },
        { label: 'Vue', value: 'vue' },
        { label: 'Svelte', value: 'svelte' }
      ]}
    />
  )
}
```

## Data Formats

SegmentedControl supports two data formats:

```tsx

// Array of strings (value and label are the same)
function ArrayOfStrings() {
  return <SegmentedControl data={['React', 'Angular', 'Svelte', 'Vue']} />
}

// Array of objects (value and label are different)
function ArrayOfObjects() {
  return (
    <SegmentedControl
      data={[
        { value: 'react', label: 'React' },
        { value: 'ng', label: 'Angular' },
        { value: 'svelte', label: 'Svelte' },
        { value: 'vue', label: 'Vue' }
      ]}
    />
  )
}
```

## Disabled

```tsx

function Demo() {
  return (
    <Stack>
      {/* Entire component disabled */}
      <div>
        <Text size="sm" fw={500} mb={3}>
          Disabled control
        </Text>
        <SegmentedControl disabled data={['Preview', 'Code', 'Export']} />
      </div>

      {/* Individual option disabled */}
      <div>
        <Text size="sm" fw={500} mb={3}>
          Disabled option
        </Text>
        <SegmentedControl
          data={[
            { value: 'preview', label: 'Preview', disabled: true },
            { value: 'code', label: 'Code' },
            { value: 'export', label: 'Export' }
          ]}
        />
      </div>
    </Stack>
  )
}
```

## Custom Labels with Icons

```tsx

function Demo() {
  return (
    <SegmentedControl
      data={[
        {
          value: 'preview',
          label: (
            <Center style={{ gap: 10 }}>
              <IconEye size={16} />
              <span>Preview</span>
            </Center>
          )
        },
        {
          value: 'code',
          label: (
            <Center style={{ gap: 10 }}>
              <IconCode size={16} />
              <span>Code</span>
            </Center>
          )
        },
        {
          value: 'export',
          label: (
            <Center style={{ gap: 10 }}>
              <IconExternalLink size={16} />
              <span>Export</span>
            </Center>
          )
        }
      ]}
    />
  )
}
```

## Color

```tsx

function Demo() {
  return <SegmentedControl color="blue" data={['React', 'Angular', 'Vue', 'Svelte']} />
}
```

## Read Only

```tsx

function Demo() {
  return <SegmentedControl readOnly defaultValue="Angular" data={['React', 'Angular', 'Vue']} />
}
```

## Key Props

| Prop                 | Type                                 | Default        | Description                             |
| -------------------- | ------------------------------------ | -------------- | --------------------------------------- |
| `data`               | `(string \| SegmentedControlItem)[]` | required       | Data used to generate segments          |
| `value`              | `string`                             | -              | Controlled component value              |
| `defaultValue`       | `string`                             | -              | Uncontrolled component default value    |
| `onChange`           | `(value: string) => void`            | -              | Called when value changes               |
| `color`              | `MantineColor`                       | -              | Color of the indicator                  |
| `size`               | `MantineSize`                        | `'sm'`         | Controls font-size, padding, and height |
| `radius`             | `MantineRadius`                      | -              | Border radius of indicator and root     |
| `fullWidth`          | `boolean`                            | `false`        | Whether component takes 100% width      |
| `orientation`        | `'horizontal' \| 'vertical'`         | `'horizontal'` | Component orientation                   |
| `disabled`           | `boolean`                            | `false`        | Disables all segments                   |
| `readOnly`           | `boolean`                            | `false`        | Prevents value from being changed       |
| `transitionDuration` | `number`                             | `200`          | Indicator transition duration in ms     |

--------------------------------------------------------------------------------

### Select
Package: @tidbcloud/uikit
Import: import { Select } from '@tidbcloud/uikit';
Description: Select component allows capturing user input from a predefined list of options. This is a custom wrapper around Mantine's Select with additional `creatable` functionality.

Select component allows capturing user input from a predefined list of options. This is a custom wrapper around Mantine's Select with additional `creatable` functionality.

## Basic Usage

```tsx

function Demo() {
  return <Select label="Your favorite library" placeholder="Pick value" data={['React', 'Angular', 'Vue', 'Svelte']} />
}
```

## Controlled

```tsx

function Demo() {
  const [value, setValue] = useState<string | null>(null)
  return <Select data={['React', 'Angular', 'Vue', 'Svelte']} value={value} onChange={setValue} />
}
```

## Searchable

```tsx

function Demo() {
  return (
    <Select
      label="Your favorite library"
      placeholder="Pick value"
      data={['React', 'Angular', 'Vue', 'Svelte']}
      searchable
    />
  )
}
```

## Clearable

```tsx

function Demo() {
  return (
    <Select
      label="Your favorite library"
      placeholder="Pick value"
      data={['React', 'Angular', 'Vue', 'Svelte']}
      defaultValue="React"
      clearable
    />
  )
}
```

## Creatable (Custom Feature)

The `@tidbcloud/uikit` Select includes a `creatable` prop that allows users to create new options:

```tsx

function Demo() {
  const [data, setData] = useState(['React', 'Angular', 'Vue', 'Svelte'])

  return (
    <Select
      label="Your favorite library"
      placeholder="Pick or create value"
      data={data}
      searchable
      creatable
      getCreateLabel={(query) => `+ Create ${query}`}
      onCreate={(query) => {
        const item = { value: query, label: query }
        setData((current) => [...current, query])
        return item
      }}
    />
  )
}
```

## Grouped Options

```tsx

function Demo() {
  return (
    <Select
      label="Your favorite library"
      placeholder="Pick value"
      data={[
        { group: 'Frontend', items: ['React', 'Angular'] },
        { group: 'Backend', items: ['Express', 'Django'] }
      ]}
    />
  )
}
```

## Nothing Found Message

```tsx

function Demo() {
  return (
    <Select
      label="Your favorite library"
      placeholder="Pick value"
      data={['React', 'Angular', 'Vue', 'Svelte']}
      searchable
      nothingFoundMessage="Nothing found..."
    />
  )
}
```

## Disabled Options

```tsx

function Demo() {
  return (
    <Select
      label="Your favorite library"
      placeholder="Pick value"
      data={[
        { value: 'react', label: 'React' },
        { value: 'ng', label: 'Angular' },
        { value: 'vue', label: 'Vue', disabled: true },
        { value: 'svelte', label: 'Svelte', disabled: true }
      ]}
    />
  )
}
```

## With Sections

```tsx

function Demo() {
  return (
    <Select
      data={['React', 'Angular', 'Vue']}
      leftSection={<IconComponents size={16} />}
      leftSectionPointerEvents="none"
      label="Your favorite library"
      placeholder="Pick value"
    />
  )
}
```

## Key Props

| Prop                  | Type                                                    | Default  | Description                                     |
| --------------------- | ------------------------------------------------------- | -------- | ----------------------------------------------- |
| `data`                | `ComboboxData`                                          | -        | Data for options                                |
| `value`               | `string \| null`                                        | -        | Controlled component value                      |
| `defaultValue`        | `string \| null`                                        | -        | Uncontrolled component default value            |
| `onChange`            | `(value: string \| null, option: ComboboxItem) => void` | -        | Called when value changes                       |
| `searchable`          | `boolean`                                               | `false`  | Enable search filtering                         |
| `searchValue`         | `string`                                                | -        | Controlled search value                         |
| `onSearchChange`      | `(value: string) => void`                               | -        | Called when search value changes                |
| `clearable`           | `boolean`                                               | `false`  | Show clear button when value is set             |
| `onClear`             | `() => void`                                            | -        | Called when clear button is clicked             |
| `nothingFoundMessage` | `ReactNode`                                             | -        | Message when no options match search            |
| `allowDeselect`       | `boolean`                                               | `true`   | Allow deselecting by clicking selected option   |
| `withCheckIcon`       | `boolean`                                               | `true`   | Show check icon near selected option            |
| `checkIconPosition`   | `'left' \| 'right'`                                     | `'left'` | Position of check icon relative to option label |
| `maxDropdownHeight`   | `number`                                                | `250`    | Max height of dropdown                          |
| `disabled`            | `boolean`                                               | `false`  | Disable the input                               |
| `readOnly`            | `boolean`                                               | `false`  | Make the input read-only                        |
| `error`               | `ReactNode`                                             | -        | Error message                                   |

## Creatable Props (Custom)

| Prop             | Type                                                   | Description                              |
| ---------------- | ------------------------------------------------------ | ---------------------------------------- |
| `creatable`      | `boolean`                                              | Enable creating new options              |
| `getCreateLabel` | `(query: string) => string`                            | Function to generate create option label |
| `onCreate`       | `(query: string) => ComboboxItem \| null \| undefined` | Called when new option is created        |

---

# MultiSelect

MultiSelect component with creatable support. This is a custom wrapper in `@tidbcloud/uikit` that adds the same creatable functionality as Select.

## Basic Usage

```tsx

function Demo() {
  return (
    <MultiSelect
      label="Your favorite libraries"
      placeholder="Pick values"
      data={['React', 'Angular', 'Vue', 'Svelte']}
    />
  )
}
```

## Creatable MultiSelect

```tsx

function Demo() {
  const [data, setData] = useState(['React', 'Angular', 'Vue'])

  return (
    <MultiSelect
      label="Creatable MultiSelect"
      data={data}
      placeholder="Select or create items"
      searchable
      creatable
      getCreateLabel={(query) => `+ Create ${query}`}
      onCreate={(query) => {
        const item = { value: query, label: query }
        setData((current) => [...current, query])
        return item
      }}
    />
  )
}
```

## MultiSelect Props

| Prop                  | Type                        | Default | Description                               |
| --------------------- | --------------------------- | ------- | ----------------------------------------- |
| `data`                | `ComboboxData`              | -       | Data for options                          |
| `value`               | `string[]`                  | -       | Controlled component value                |
| `defaultValue`        | `string[]`                  | -       | Uncontrolled component default value      |
| `onChange`            | `(value: string[]) => void` | -       | Called when value changes                 |
| `searchable`          | `boolean`                   | `false` | Enable search filtering                   |
| `clearable`           | `boolean`                   | `false` | Show clear button when value is set       |
| `nothingFoundMessage` | `ReactNode`                 | -       | Message when no options match search      |
| `maxValues`           | `number`                    | -       | Maximum number of values                  |
| `hidePickedOptions`   | `boolean`                   | `false` | Hide already picked options from dropdown |
| `maxDropdownHeight`   | `number`                    | `250`   | Max height of dropdown                    |
| `disabled`            | `boolean`                   | `false` | Disable the input                         |
| `error`               | `ReactNode`                 | -       | Error message                             |

## MultiSelect Creatable Props (Custom)

| Prop             | Type                                                   | Description                              |
| ---------------- | ------------------------------------------------------ | ---------------------------------------- |
| `creatable`      | `boolean`                                              | Enable creating new options              |
| `getCreateLabel` | `(query: string) => string`                            | Function to generate create option label |
| `onCreate`       | `(query: string) => ComboboxItem \| null \| undefined` | Called when new option is created        |

--------------------------------------------------------------------------------

### SemiCircleProgress
Package: @tidbcloud/uikit
Import: import { SemiCircleProgress } from '@tidbcloud/uikit';
Description: SemiCircleProgress displays progress with a semi-circular diagram, useful for dashboards and status indicators.

SemiCircleProgress displays progress with a semi-circular diagram, useful for dashboards and status indicators.

## Basic Usage

```tsx

function Demo() {
  return <SemiCircleProgress value={40} label="40%" />
}
```

## Size and Thickness

```tsx

function Demo() {
  return <SemiCircleProgress value={60} size={200} thickness={12} label="60%" />
}
```

## Custom Colors

```tsx

function Demo() {
  return <SemiCircleProgress value={30} filledSegmentColor="blue" emptySegmentColor="var(--mantine-color-dimmed)" />
}
```

## Label Position

By default, label is at the bottom. Use `labelPosition="center"` to center it:

```tsx

function Demo() {
  return (
    <>
      <SemiCircleProgress value={30} label="Bottom" mb="xl" />
      <SemiCircleProgress value={30} label="Center" labelPosition="center" />
    </>
  )
}
```

## Fill Direction

Control which direction the progress fills from:

```tsx

function Demo() {
  return (
    <>
      <SemiCircleProgress value={50} fillDirection="left-to-right" label="Left to Right" />
      <SemiCircleProgress value={50} fillDirection="right-to-left" label="Right to Left" />
    </>
  )
}
```

## Orientation

```tsx

function Demo() {
  return (
    <>
      <SemiCircleProgress value={50} orientation="up" label="Up" />
      <SemiCircleProgress value={50} orientation="down" label="Down" />
    </>
  )
}
```

## Animated Transitions

```tsx

function Demo() {
  const [value, setValue] = useState(30)

  return (
    <>
      <SemiCircleProgress value={value} transitionDuration={250} label={`${value}%`} />
      <Button onClick={() => setValue(Math.floor(Math.random() * 100))} mt="xl">
        Set random value
      </Button>
    </>
  )
}
```

## Key Props

| Prop                 | Type                                 | Default           | Description                                    |
| -------------------- | ------------------------------------ | ----------------- | ---------------------------------------------- |
| `value`              | `number`                             | required          | Progress value from 0 to 100                   |
| `size`               | `number`                             | `200`             | Diameter of the SVG in px                      |
| `thickness`          | `number`                             | `12`              | Circle thickness in px                         |
| `label`              | `ReactNode`                          | -                 | Label rendered inside the circle               |
| `labelPosition`      | `'center' \| 'bottom'`               | `'bottom'`        | Label position relative to circle center       |
| `filledSegmentColor` | `MantineColor`                       | -                 | Color of the filled segment                    |
| `emptySegmentColor`  | `MantineColor`                       | -                 | Color of the empty segment                     |
| `fillDirection`      | `'left-to-right' \| 'right-to-left'` | `'left-to-right'` | Direction the circle fills from                |
| `orientation`        | `'up' \| 'down'`                     | `'up'`            | Orientation of the circle                      |
| `transitionDuration` | `number`                             | `0`               | Transition duration in ms for animated changes |

--------------------------------------------------------------------------------

### SimpleGrid
Package: @tidbcloud/uikit
Import: import { SimpleGrid } from '@tidbcloud/uikit';
Description: Responsive grid system with equal-width columns. Uses CSS grid layout for flexible, responsive layouts.

Responsive grid system with equal-width columns. Uses CSS grid layout for flexible, responsive layouts.

## Basic Usage

```tsx

function Demo() {
  return (
    <SimpleGrid cols={3}>
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
    </SimpleGrid>
  )
}
```

## Responsive Columns

Use object notation for responsive values with `base`, `xs`, `sm`, `md`, `lg`, and `xl` breakpoints:

```tsx

function Demo() {
  return (
    <SimpleGrid
      cols={{ base: 1, sm: 2, lg: 5 }}
      spacing={{ base: 10, sm: 'xl' }}
      verticalSpacing={{ base: 'md', sm: 'xl' }}
    >
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
    </SimpleGrid>
  )
}
```

## Container Queries

Use container queries instead of media queries for container-based responsiveness:

```tsx

function Demo() {
  return (
    <SimpleGrid type="container" cols={{ base: 1, '300px': 2, '500px': 5 }} spacing={{ base: 10, '300px': 'xl' }}>
      <div>1</div>
      <div>2</div>
      <div>3</div>
    </SimpleGrid>
  )
}
```

## Key Props

| Prop            | Type                        | Description                                |
| --------------- | --------------------------- | ------------------------------------------ |
| cols            | StyleProp\<number\>         | Number of columns                          |
| spacing         | StyleProp\<MantineSpacing\> | Spacing between columns                    |
| verticalSpacing | StyleProp\<MantineSpacing\> | Spacing between rows                       |
| type            | "media" \| "container"      | Type of queries used for responsive styles |

--------------------------------------------------------------------------------

### Skeleton
Package: @tidbcloud/uikit
Import: import { Skeleton } from '@tidbcloud/uikit';
Description: Indicate content loading state with placeholder animations.

Indicate content loading state with placeholder animations.

## Basic Usage

```tsx

function Demo() {
  return (
    <>
      <Skeleton height={50} circle mb="xl" />
      <Skeleton height={8} radius="xl" />
      <Skeleton height={8} mt={6} radius="xl" />
      <Skeleton height={8} mt={6} width="70%" radius="xl" />
    </>
  )
}
```

## With Content

Wrap existing content and control loading overlay visibility with the `visible` prop:

```tsx

function Demo() {
  const [loading, setLoading] = useState(true)

  return (
    <>
      <Skeleton visible={loading}>Lorem ipsum dolor sit amet...</Skeleton>

      <Button onClick={() => setLoading((l) => !l)}>Toggle Skeleton</Button>
    </>
  )
}
```

## Key Props

| Prop    | Type                       | Description                                       |
| ------- | -------------------------- | ------------------------------------------------- |
| height  | Height\<string \| number\> | Skeleton height                                   |
| width   | CSSProperties["width"]     | Skeleton width                                    |
| radius  | MantineRadius \| number    | Border radius                                     |
| circle  | boolean                    | If set, width and border-radius equal to height   |
| animate | boolean                    | Enables animation                                 |
| visible | boolean                    | Controls overlay visibility when wrapping content |

--------------------------------------------------------------------------------

### Slider
Package: @tidbcloud/uikit
Import: import { Slider } from '@tidbcloud/uikit';
Description: Capture numeric input from users with a draggable slider.

Capture numeric input from users with a draggable slider.

## Basic Usage

```tsx

function Demo() {
  return (
    <Slider
      defaultValue={40}
      marks={[
        { value: 20, label: '20%' },
        { value: 50, label: '50%' },
        { value: 80, label: '80%' }
      ]}
    />
  )
}
```

## Controlled

```tsx

function Demo() {
  const [value, setValue] = useState(40)
  return <Slider value={value} onChange={setValue} />
}
```

## With Marks

```tsx

function Demo() {
  return (
    <Slider
      defaultValue={40}
      marks={[
        { value: 20, label: '20%' },
        { value: 50, label: '50%' },
        { value: 80, label: '80%' }
      ]}
    />
  )
}
```

## Label Control

```tsx

function Demo() {
  return (
    <>
      {/* No label */}
      <Slider defaultValue={40} label={null} />

      {/* Formatted label */}
      <Slider defaultValue={40} label={(value) => `${value} °C`} />

      {/* Label always visible */}
      <Slider defaultValue={40} labelAlwaysOn />
    </>
  )
}
```

## Key Props

| Prop          | Type                                        | Description                     |
| ------------- | ------------------------------------------- | ------------------------------- |
| value         | number                                      | Controlled value                |
| defaultValue  | number                                      | Default value for uncontrolled  |
| onChange      | (value: number) => void                     | Called when value changes       |
| onChangeEnd   | (value: number) => void                     | Called when user stops dragging |
| min           | number                                      | Minimum possible value          |
| max           | number                                      | Maximum possible value          |
| step          | number                                      | Increment/decrement step        |
| marks         | \{ value: number; label?: ReactNode }[]     | Marks displayed on track        |
| label         | ReactNode \| ((value: number) => ReactNode) | Label formatter                 |
| labelAlwaysOn | boolean                                     | Always show label               |
| disabled      | boolean                                     | Disables slider                 |
| color         | MantineColor                                | Track and thumb color           |
| size          | MantineSize                                 | Controls track size             |

--------------------------------------------------------------------------------

### Space
Package: @tidbcloud/uikit
Import: import { Space } from '@tidbcloud/uikit';
Description: Add horizontal or vertical spacing between elements using theme spacing values.

Add horizontal or vertical spacing between elements using theme spacing values.

## Basic Usage

### Vertical Spacing

```tsx

function Demo() {
  return (
    <>
      <Text>First line</Text>
      <Space h="md" />
      <Text>Second line</Text>
    </>
  )
}
```

### Horizontal Spacing

```tsx

function Demo() {
  return (
    <div style={{ display: 'flex' }}>
      <Text>First</Text>
      <Space w="md" />
      <Text>Second</Text>
    </div>
  )
}
```

## When to Use

Use `Space` when working with regular HTML elements that don't have access to margin props:

```tsx

function Demo() {
  return (
    <>
      <div>First line</div>
      <Space h="md" />
      <div>Second line</div>
    </>
  )
}
```

For Mantine components, prefer using margin props instead:

```tsx

function Demo() {
  return (
    <>
      <Text>First line</Text>
      <Text mt="md">Second line</Text>
    </>
  )
}
```

## Key Props

| Prop | Type           | Description            |
| ---- | -------------- | ---------------------- |
| w    | MantineSpacing | Horizontal space width |
| h    | MantineSpacing | Vertical space height  |

--------------------------------------------------------------------------------

### Spoiler
Package: @tidbcloud/uikit
Import: import { Spoiler } from '@tidbcloud/uikit';
Description: Hide long sections of content under a collapsible spoiler with show/hide controls.

Hide long sections of content under a collapsible spoiler with show/hide controls.

## Basic Usage

```tsx

function Demo() {
  return (
    <Spoiler maxHeight={120} showLabel="Show more" hideLabel="Hide">
      {/* Long content here */}
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit...</p>
      <p>More content that will be hidden...</p>
    </Spoiler>
  )
}
```

## Controlled

```tsx

function Demo() {
  const [expanded, setExpanded] = useState(false)

  return (
    <Spoiler
      maxHeight={120}
      showLabel="Show more"
      hideLabel="Hide details"
      expanded={expanded}
      onExpandedChange={setExpanded}
    >
      {/* Content */}
    </Spoiler>
  )
}
```

## Transition Duration

Control or disable the expand/collapse animation:

```tsx

function Demo() {
  return (
    <Spoiler
      maxHeight={120}
      showLabel="Show more"
      hideLabel="Hide"
      transitionDuration={0} // Disable animation
    >
      {/* Content */}
    </Spoiler>
  )
}
```

## Key Props

| Prop               | Type                        | Description                                           |
| ------------------ | --------------------------- | ----------------------------------------------------- |
| maxHeight          | number                      | Maximum visible content height before spoiler appears |
| showLabel          | ReactNode                   | Label for expand action (required)                    |
| hideLabel          | ReactNode                   | Label for collapse action (required)                  |
| expanded           | boolean                     | Controlled expanded state                             |
| onExpandedChange   | (expanded: boolean) => void | Called when expanded state changes                    |
| transitionDuration | number                      | Animation duration in ms (0 to disable)               |
| initialState       | boolean                     | Initial expanded state                                |

--------------------------------------------------------------------------------

### Stack
Package: @tidbcloud/uikit
Import: import { Stack } from '@tidbcloud/uikit';
Description: Compose elements and components in a vertical flex container with consistent spacing.

Compose elements and components in a vertical flex container with consistent spacing.

## Basic Usage

```tsx

function Demo() {
  return (
    <Stack>
      <Button variant="default">First</Button>
      <Button variant="default">Second</Button>
      <Button variant="default">Third</Button>
    </Stack>
  )
}
```

## With Gap and Alignment

```tsx

function Demo() {
  return (
    <Stack h={300} bg="var(--mantine-color-body)" align="center" justify="center" gap="md">
      <Button variant="default">1</Button>
      <Button variant="default">2</Button>
      <Button variant="default">3</Button>
    </Stack>
  )
}
```

## Related Components

- Use **Group** for horizontal flex containers
- Use **Flex** for full control over flex container properties

## Key Props

| Prop    | Type           | Description                                           |
| ------- | -------------- | ----------------------------------------------------- |
| gap     | MantineSpacing | Gap between children (theme.spacing key or CSS value) |
| align   | AlignItems     | Controls `align-items` CSS property                   |
| justify | JustifyContent | Controls `justify-content` CSS property               |

--------------------------------------------------------------------------------

### Stepper
Package: @tidbcloud/uikit
Import: import { Stepper } from '@tidbcloud/uikit';
Description: Display content divided into a steps sequence with navigation controls.

Display content divided into a steps sequence with navigation controls.

## Basic Usage

```tsx

function Demo() {
  const [active, setActive] = useState(1)
  const nextStep = () => setActive((current) => (current < 3 ? current + 1 : current))
  const prevStep = () => setActive((current) => (current > 0 ? current - 1 : current))

  return (
    <>
      <Stepper active={active} onStepClick={setActive}>
        <Stepper.Step label="First step" description="Create an account">
          Step 1 content: Create an account
        </Stepper.Step>
        <Stepper.Step label="Second step" description="Verify email">
          Step 2 content: Verify email
        </Stepper.Step>
        <Stepper.Step label="Final step" description="Get full access">
          Step 3 content: Get full access
        </Stepper.Step>
        <Stepper.Completed>Completed, click back button to get to previous step</Stepper.Completed>
      </Stepper>

      <Group justify="center" mt="xl">
        <Button variant="default" onClick={prevStep}>
          Back
        </Button>
        <Button onClick={nextStep}>Next step</Button>
      </Group>
    </>
  )
}
```

## With Custom Icons

```tsx

function Demo() {
  const [active, setActive] = useState(1)

  return (
    <Stepper active={active} onStepClick={setActive}>
      <Stepper.Step icon={<IconUserCheck size={18} />} label="Step 1" description="Create an account" />
      <Stepper.Step icon={<IconMailOpened size={18} />} label="Step 2" description="Verify email" />
      <Stepper.Step icon={<IconShieldCheck size={18} />} label="Step 3" description="Get full access" />
    </Stepper>
  )
}
```

## Vertical Orientation

```tsx

function Demo() {
  const [active, setActive] = useState(1)

  return (
    <Stepper active={active} onStepClick={setActive} orientation="vertical">
      <Stepper.Step label="Step 1" description="Create an account" />
      <Stepper.Step label="Step 2" description="Verify email" />
      <Stepper.Step label="Step 3" description="Get full access" />
    </Stepper>
  )
}
```

## Loading State

```tsx

function Demo() {
  return (
    <Stepper active={1}>
      <Stepper.Step label="Step 1" description="Create an account" />
      <Stepper.Step label="Step 2" description="Verify email" loading />
      <Stepper.Step label="Step 3" description="Get full access" />
    </Stepper>
  )
}
```

## Key Props

### Stepper

| Prop                 | Type                        | Description                         |
| -------------------- | --------------------------- | ----------------------------------- |
| active               | number                      | Index of the active step (required) |
| onStepClick          | (stepIndex: number) => void | Called when step is clicked         |
| orientation          | "horizontal" \| "vertical"  | Stepper orientation                 |
| iconPosition         | "left" \| "right"           | Icon position relative to step body |
| allowNextStepsSelect | boolean                     | Allow selecting next steps          |
| color                | MantineColor                | Color of active and progress steps  |
| size                 | MantineSize                 | Controls size of elements           |
| completedIcon        | ReactNode                   | Icon for completed steps            |

### Stepper.Step

| Prop            | Type      | Description              |
| --------------- | --------- | ------------------------ |
| label           | ReactNode | Step label               |
| description     | ReactNode | Step description         |
| icon            | ReactNode | Custom step icon         |
| loading         | boolean   | Show loading state       |
| allowStepSelect | boolean   | Allow clicking this step |
| completedIcon   | ReactNode | Custom completed icon    |

--------------------------------------------------------------------------------

### Switch
Package: @tidbcloud/uikit
Import: import { Switch } from '@tidbcloud/uikit';
Description: Capture boolean input from users with a toggle switch control.

Capture boolean input from users with a toggle switch control.

## Basic Usage

```tsx

function Demo() {
  return <Switch defaultChecked label="I agree to sell my privacy" />
}
```

## Controlled

```tsx

function Demo() {
  const [checked, setChecked] = useState(false)
  return <Switch checked={checked} onChange={(event) => setChecked(event.currentTarget.checked)} />
}
```

## With Inner Labels

```tsx

function Demo() {
  return (
    <Group>
      <Switch size="xs" onLabel="ON" offLabel="OFF" />
      <Switch size="sm" onLabel="ON" offLabel="OFF" />
      <Switch size="md" onLabel="ON" offLabel="OFF" />
      <Switch size="lg" onLabel="ON" offLabel="OFF" />
    </Group>
  )
}
```

## With Thumb Icon

```tsx

function Demo() {
  const [checked, setChecked] = useState(false)

  return (
    <Switch
      checked={checked}
      onChange={(event) => setChecked(event.currentTarget.checked)}
      color="teal"
      size="md"
      label="Switch with thumb icon"
      thumbIcon={
        checked ? (
          <IconCheck size={12} color="var(--mantine-color-teal-6)" stroke={3} />
        ) : (
          <IconX size={12} color="var(--mantine-color-red-6)" stroke={3} />
        )
      }
    />
  )
}
```

## Switch.Group

```tsx

function Demo() {
  return (
    <Switch.Group defaultValue={['react']} label="Select frameworks">
      <Group mt="xs">
        <Switch value="react" label="React" />
        <Switch value="svelte" label="Svelte" />
        <Switch value="ng" label="Angular" />
        <Switch value="vue" label="Vue" />
      </Group>
    </Switch.Group>
  )
}
```

## Key Props

| Prop           | Type              | Description                      |
| -------------- | ----------------- | -------------------------------- |
| checked        | boolean           | Controlled checked state         |
| defaultChecked | boolean           | Default checked state            |
| onChange       | (event) => void   | Called when value changes        |
| label          | ReactNode         | Label associated with the switch |
| description    | ReactNode         | Description below the label      |
| error          | ReactNode         | Error message below the label    |
| size           | MantineSize       | Controls size of elements        |
| color          | MantineColor      | Color when checked               |
| onLabel        | ReactNode         | Inner label when checked         |
| offLabel       | ReactNode         | Inner label when unchecked       |
| thumbIcon      | ReactNode         | Icon inside the thumb            |
| labelPosition  | "left" \| "right" | Label position                   |
| disabled       | boolean           | Disables the switch              |

--------------------------------------------------------------------------------

### Table
Package: @tidbcloud/uikit
Import: import { Table } from '@tidbcloud/uikit';
Description: Render tables with theme styles. Supports sticky headers, striped rows, row hover effects, and responsive scrolling.

Render tables with theme styles. Supports sticky headers, striped rows, row hover effects, and responsive scrolling.

## Basic Usage

```tsx

const elements = [
  { position: 6, mass: 12.011, symbol: 'C', name: 'Carbon' },
  { position: 7, mass: 14.007, symbol: 'N', name: 'Nitrogen' },
  { position: 39, mass: 88.906, symbol: 'Y', name: 'Yttrium' }
]

function Demo() {
  const rows = elements.map((element) => (
    <Table.Tr key={element.name}>
      <Table.Td>{element.position}</Table.Td>
      <Table.Td>{element.name}</Table.Td>
      <Table.Td>{element.symbol}</Table.Td>
      <Table.Td>{element.mass}</Table.Td>
    </Table.Tr>
  ))

  return (
    <Table>
      <Table.Thead>
        <Table.Tr>
          <Table.Th>Position</Table.Th>
          <Table.Th>Name</Table.Th>
          <Table.Th>Symbol</Table.Th>
          <Table.Th>Mass</Table.Th>
        </Table.Tr>
      </Table.Thead>
      <Table.Tbody>{rows}</Table.Tbody>
    </Table>
  )
}
```

## With Data Prop

Automatically generate table rows from an array:

```tsx

const tableData: TableData = {
  caption: 'Some elements from periodic table',
  head: ['Position', 'Mass', 'Symbol', 'Name'],
  body: [
    [6, 12.011, 'C', 'Carbon'],
    [7, 14.007, 'N', 'Nitrogen']
  ]
}

function Demo() {
  return <Table data={tableData} />
}
```

## Sticky Header

```tsx
<Table stickyHeader stickyHeaderOffset={60}>
  {/* table content */}
</Table>
```

## Scroll Container

Wrap Table with `Table.ScrollContainer` to prevent viewport overflow:

```tsx
<Table.ScrollContainer minWidth={500}>
  <Table>{/* table content */}</Table>
</Table.ScrollContainer>
```

## Key Props

| Prop                 | Type                         | Description                          |
| -------------------- | ---------------------------- | ------------------------------------ |
| `data`               | `TableData`                  | Data to generate table automatically |
| `striped`            | `boolean \| 'odd' \| 'even'` | Enable striped rows                  |
| `highlightOnHover`   | `boolean`                    | Highlight rows on hover              |
| `stickyHeader`       | `boolean`                    | Make header sticky                   |
| `stickyHeaderOffset` | `number`                     | Offset for sticky header             |
| `withTableBorder`    | `boolean`                    | Add outer border                     |
| `withColumnBorders`  | `boolean`                    | Add column borders                   |
| `withRowBorders`     | `boolean`                    | Add row borders                      |
| `horizontalSpacing`  | `MantineSpacing`             | Horizontal cell padding              |
| `verticalSpacing`    | `MantineSpacing`             | Vertical cell padding                |
| `captionSide`        | `'top' \| 'bottom'`          | Caption position                     |

--------------------------------------------------------------------------------

### Tabs
Package: @tidbcloud/uikit
Import: import { Tabs } from '@tidbcloud/uikit';
Description: Switch between different views using tabbed navigation.

Switch between different views using tabbed navigation.

## Basic Usage

```tsx

function Demo() {
  return (
    <Tabs defaultValue="gallery">
      <Tabs.List>
        <Tabs.Tab value="gallery">Gallery</Tabs.Tab>
        <Tabs.Tab value="messages">Messages</Tabs.Tab>
        <Tabs.Tab value="settings">Settings</Tabs.Tab>
      </Tabs.List>

      <Tabs.Panel value="gallery">Gallery tab content</Tabs.Panel>
      <Tabs.Panel value="messages">Messages tab content</Tabs.Panel>
      <Tabs.Panel value="settings">Settings tab content</Tabs.Panel>
    </Tabs>
  )
}
```

## Controlled

```tsx

function Demo() {
  const [activeTab, setActiveTab] = useState<string | null>('first')

  return (
    <Tabs value={activeTab} onChange={setActiveTab}>
      <Tabs.List>
        <Tabs.Tab value="first">First tab</Tabs.Tab>
        <Tabs.Tab value="second">Second tab</Tabs.Tab>
      </Tabs.List>

      <Tabs.Panel value="first">First panel</Tabs.Panel>
      <Tabs.Panel value="second">Second panel</Tabs.Panel>
    </Tabs>
  )
}
```

## Vertical Tabs

```tsx
<Tabs defaultValue="gallery" orientation="vertical">
  <Tabs.List>
    <Tabs.Tab value="gallery">Gallery</Tabs.Tab>
    <Tabs.Tab value="messages">Messages</Tabs.Tab>
  </Tabs.List>

  <Tabs.Panel value="gallery">Gallery content</Tabs.Panel>
  <Tabs.Panel value="messages">Messages content</Tabs.Panel>
</Tabs>
```

## Disabled Tab

```tsx
<Tabs.Tab value="settings" disabled>
  Settings
</Tabs.Tab>
```

## Key Props

| Prop                   | Type                              | Description                       |
| ---------------------- | --------------------------------- | --------------------------------- |
| `value`                | `string \| null`                  | Controlled active tab value       |
| `defaultValue`         | `string \| null`                  | Default active tab (uncontrolled) |
| `onChange`             | `(value: string \| null) => void` | Called when active tab changes    |
| `orientation`          | `'horizontal' \| 'vertical'`      | Tabs orientation                  |
| `variant`              | `string`                          | Visual variant                    |
| `color`                | `MantineColor`                    | Tab color                         |
| `radius`               | `MantineRadius`                   | Border radius                     |
| `inverted`             | `boolean`                         | Inverted tabs layout              |
| `keepMounted`          | `boolean`                         | Keep inactive panels mounted      |
| `allowTabDeactivation` | `boolean`                         | Allow deactivating active tab     |

--------------------------------------------------------------------------------

### TagsInput
Package: @tidbcloud/uikit
Import: import { TagsInput } from '@tidbcloud/uikit';
Description: Capture a list of values from user with free input and suggestions. Similar to MultiSelect but allows entering custom values.

Capture a list of values from user with free input and suggestions. Similar to MultiSelect but allows entering custom values.

## Basic Usage

```tsx

function Demo() {
  return <TagsInput label="Press Enter to submit a tag" placeholder="Enter tag" />
}
```

## With Suggestions

```tsx

function Demo() {
  return (
    <TagsInput
      label="Pick or enter tags"
      placeholder="Pick tag from list"
      data={['React', 'Angular', 'Vue', 'Svelte']}
    />
  )
}
```

## Controlled

```tsx

function Demo() {
  const [value, setValue] = useState<string[]>(['React'])
  return <TagsInput value={value} onChange={setValue} data={['React', 'Angular', 'Vue']} />
}
```

## Max Tags

```tsx
<TagsInput label="Add up to 3 tags" placeholder="Enter tag" maxTags={3} defaultValue={['first', 'second']} />
```

## Clearable

```tsx
<TagsInput label="Clearable tags" placeholder="Enter tag" defaultValue={['React']} clearable />
```

## Key Props

| Prop                | Type                        | Description                                          |
| ------------------- | --------------------------- | ---------------------------------------------------- |
| `value`             | `string[]`                  | Controlled value                                     |
| `defaultValue`      | `string[]`                  | Default value (uncontrolled)                         |
| `onChange`          | `(value: string[]) => void` | Called when value changes                            |
| `data`              | `string[]`                  | Suggestions data                                     |
| `maxTags`           | `number`                    | Maximum number of tags                               |
| `clearable`         | `boolean`                   | Show clear button                                    |
| `allowDuplicates`   | `boolean`                   | Allow duplicate tags                                 |
| `splitChars`        | `string[]`                  | Characters that trigger tag split (default: `[',']`) |
| `acceptValueOnBlur` | `boolean`                   | Add value on blur                                    |
| `label`             | `ReactNode`                 | Input label                                          |
| `placeholder`       | `string`                    | Input placeholder                                    |
| `error`             | `ReactNode`                 | Error message                                        |
| `disabled`          | `boolean`                   | Disable input                                        |

--------------------------------------------------------------------------------

### Text
Package: @tidbcloud/uikit
Import: import { Text } from '@tidbcloud/uikit';
Description: Display text with various styles, sizes, colors, and formatting options.

Display text with various styles, sizes, colors, and formatting options.

## Basic Usage

```tsx

function Demo() {
  return (
    <>
      <Text size="xs">Extra small text</Text>
      <Text size="sm">Small text</Text>
      <Text size="md">Default text</Text>
      <Text size="lg">Large text</Text>
      <Text size="xl">Extra large text</Text>
      <Text fw={500}>Semibold</Text>
      <Text fw={700}>Bold</Text>
      <Text fs="italic">Italic</Text>
      <Text td="underline">Underlined</Text>
      <Text c="dimmed">Dimmed text</Text>
      <Text c="blue">Blue text</Text>
      <Text tt="uppercase">Uppercase</Text>
    </>
  )
}
```

## Gradient Text

```tsx

function Demo() {
  return (
    <Text size="xl" fw={900} variant="gradient" gradient={{ from: 'cyan', to: 'blue', deg: 90 }}>
      Gradient Text
    </Text>
  )
}
```

## Truncate

```tsx
<Text truncate>Long text that will be truncated...</Text>
```

## Line Clamp

```tsx
<Text lineClamp={3}>Long text that will be clamped to 3 lines...</Text>
```

## As Span

```tsx
<Text span>Inline text element</Text>
```

## Key Props

| Prop        | Type                                   | Description                                        |
| ----------- | -------------------------------------- | -------------------------------------------------- |
| `size`      | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | Font size                                          |
| `c`         | `MantineColor`                         | Text color                                         |
| `fw`        | `number`                               | Font weight                                        |
| `fs`        | `string`                               | Font style (e.g., 'italic')                        |
| `td`        | `string`                               | Text decoration (e.g., 'underline')                |
| `tt`        | `string`                               | Text transform (e.g., 'uppercase')                 |
| `ta`        | `string`                               | Text alignment                                     |
| `truncate`  | `boolean \| 'start' \| 'end'`          | Truncate text with ellipsis                        |
| `lineClamp` | `number`                               | Maximum number of lines                            |
| `span`      | `boolean`                              | Render as span element                             |
| `inherit`   | `boolean`                              | Inherit font styles from parent                    |
| `gradient`  | `MantineGradient`                      | Gradient configuration (with `variant="gradient"`) |

--------------------------------------------------------------------------------

### TextInput
Package: @tidbcloud/uikit
Import: import { TextInput } from '@tidbcloud/uikit';
Description: Capture string input from user. This is a custom wrapper in `@tidbcloud/uikit` that extends the base input functionality with styled addon support.

Capture string input from user. This is a custom wrapper in `@tidbcloud/uikit` that extends the base input functionality with styled addon support.

## Basic Usage

```tsx

function Demo() {
  return <TextInput label="Your name" placeholder="Enter your name" />
}
```

## Controlled

```tsx

function Demo() {
  const [value, setValue] = useState('')
  return <TextInput value={value} onChange={(event) => setValue(event.currentTarget.value)} label="Controlled input" />
}
```

## With Icon

```tsx

function Demo() {
  return <TextInput leftSection={<IconAt size={16} />} label="Your email" placeholder="Your email" />
}
```

## With Addon

Use `leftAddon` and `rightAddon` props to display styled addons on either side of the input. This is a custom feature in `@tidbcloud/uikit`.

```tsx

function Demo() {
  return <TextInput label="Website URL" placeholder="example.com" leftAddon="https://" rightAddon=".com" />
}
```

## Error State

```tsx
<TextInput label="With error" placeholder="Enter value" error="Invalid input" />
```

## Disabled

```tsx
<TextInput label="Disabled" placeholder="Cannot edit" disabled />
```

## Key Props

| Prop           | Type              | Description                  |
| -------------- | ----------------- | ---------------------------- |
| `value`        | `string`          | Controlled value             |
| `defaultValue` | `string`          | Default value (uncontrolled) |
| `onChange`     | `(event) => void` | Called when value changes    |
| `label`        | `ReactNode`       | Input label                  |
| `description`  | `ReactNode`       | Input description            |
| `placeholder`  | `string`          | Placeholder text             |
| `error`        | `ReactNode`       | Error message                |
| `disabled`     | `boolean`         | Disable input                |
| `required`     | `boolean`         | Mark as required             |
| `leftSection`  | `ReactNode`       | Left section content         |
| `rightSection` | `ReactNode`       | Right section content        |
| `size`         | `MantineSize`     | Input size                   |
| `radius`       | `MantineRadius`   | Border radius                |

## Custom Addon Props (@tidbcloud/uikit)

| Prop              | Type              | Description                                         |
| ----------------- | ----------------- | --------------------------------------------------- |
| `leftAddon`       | `ReactNode`       | Content displayed as styled addon on the left side  |
| `rightAddon`      | `ReactNode`       | Content displayed as styled addon on the right side |
| `leftAddonProps`  | `TypographyProps` | Props passed to the left addon Typography wrapper   |
| `rightAddonProps` | `TypographyProps` | Props passed to the right addon Typography wrapper  |

--------------------------------------------------------------------------------

### Textarea
Package: @tidbcloud/uikit
Import: import { Textarea } from '@tidbcloud/uikit';
Description: Multi-line text input with optional autosize functionality.

Multi-line text input with optional autosize functionality.

## Basic Usage

```tsx

function Demo() {
  return <Textarea label="Your comment" placeholder="Enter your comment" />
}
```

## Controlled

```tsx

function Demo() {
  const [value, setValue] = useState('')
  return (
    <Textarea value={value} onChange={(event) => setValue(event.currentTarget.value)} label="Controlled textarea" />
  )
}
```

## Autosize

Textarea height grows with content:

```tsx

function Demo() {
  return (
    <>
      <Textarea label="Autosize with no limit" placeholder="Start typing..." autosize minRows={2} />

      <Textarea label="Autosize with max rows" placeholder="Start typing..." autosize minRows={2} maxRows={4} />
    </>
  )
}
```

## Enable Resize

```tsx
<Textarea label="Resizable" placeholder="Your comment" resize="vertical" />
```

## Error State

```tsx
<Textarea label="With error" placeholder="Enter text" error="This field is required" />
```

## Key Props

| Prop           | Type                                             | Description                  |
| -------------- | ------------------------------------------------ | ---------------------------- |
| `value`        | `string`                                         | Controlled value             |
| `defaultValue` | `string`                                         | Default value (uncontrolled) |
| `onChange`     | `(event) => void`                                | Called when value changes    |
| `label`        | `ReactNode`                                      | Input label                  |
| `description`  | `ReactNode`                                      | Input description            |
| `placeholder`  | `string`                                         | Placeholder text             |
| `error`        | `ReactNode`                                      | Error message                |
| `disabled`     | `boolean`                                        | Disable input                |
| `autosize`     | `boolean`                                        | Enable autosize              |
| `minRows`      | `number`                                         | Minimum rows (with autosize) |
| `maxRows`      | `number`                                         | Maximum rows (with autosize) |
| `resize`       | `'none' \| 'vertical' \| 'horizontal' \| 'both'` | CSS resize property          |
| `size`         | `MantineSize`                                    | Input size                   |
| `radius`       | `MantineRadius`                                  | Border radius                |

--------------------------------------------------------------------------------

### ThemeIcon
Package: @tidbcloud/uikit
Import: import { ThemeIcon } from '@tidbcloud/uikit';
Description: Render an icon inside an element with theme colors. Useful for decorative icons with consistent styling.

Render an icon inside an element with theme colors. Useful for decorative icons with consistent styling.

## Basic Usage

```tsx

function Demo() {
  return (
    <ThemeIcon>
      <IconPhoto style={{ width: '70%', height: '70%' }} />
    </ThemeIcon>
  )
}
```

## Colors and Variants

```tsx

function Demo() {
  return (
    <Group>
      <ThemeIcon variant="filled" color="blue">
        <IconHeart size={16} />
      </ThemeIcon>
      <ThemeIcon variant="light" color="teal">
        <IconHeart size={16} />
      </ThemeIcon>
      <ThemeIcon variant="outline" color="grape">
        <IconHeart size={16} />
      </ThemeIcon>
    </Group>
  )
}
```

## Gradient

```tsx

function Demo() {
  return (
    <ThemeIcon variant="gradient" size="xl" gradient={{ from: 'cyan', to: 'blue', deg: 90 }}>
      <IconHeart />
    </ThemeIcon>
  )
}
```

## Sizes

```tsx

function Demo() {
  return (
    <Group>
      <ThemeIcon size="xs">
        <IconPhoto size={12} />
      </ThemeIcon>
      <ThemeIcon size="sm">
        <IconPhoto size={14} />
      </ThemeIcon>
      <ThemeIcon size="md">
        <IconPhoto size={16} />
      </ThemeIcon>
      <ThemeIcon size="lg">
        <IconPhoto size={20} />
      </ThemeIcon>
      <ThemeIcon size="xl">
        <IconPhoto size={24} />
      </ThemeIcon>
    </Group>
  )
}
```

## Key Props

| Prop           | Type                                             | Description                                        |
| -------------- | ------------------------------------------------ | -------------------------------------------------- |
| `children`     | `ReactNode`                                      | Icon to display                                    |
| `color`        | `MantineColor`                                   | Icon container color                               |
| `variant`      | `'filled' \| 'light' \| 'outline' \| 'gradient'` | Visual variant                                     |
| `size`         | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| number` | Icon container size                                |
| `radius`       | `MantineRadius`                                  | Border radius                                      |
| `gradient`     | `MantineGradient`                                | Gradient configuration (with `variant="gradient"`) |
| `autoContrast` | `boolean`                                        | Adjust icon color based on background              |

--------------------------------------------------------------------------------

### TimeInput
Package: @tidbcloud/uikit
Import: import { TimeInput } from '@tidbcloud/uikit';
Description: Capture time from the user using native browser time input. This component is re-exported from `@mantine/dates` via `@tidbcloud/uikit`.

Capture time from the user using native browser time input. This component is re-exported from `@mantine/dates` via `@tidbcloud/uikit`.

## Basic Usage

```tsx

function Demo() {
  return <TimeInput label="Select time" placeholder="Pick time" />
}
```

## Controlled

```tsx

function Demo() {
  const [value, setValue] = useState('')
  return (
    <TimeInput value={value} onChange={(event) => setValue(event.currentTarget.value)} label="Controlled time input" />
  )
}
```

## With Seconds

```tsx

function Demo() {
  return <TimeInput label="With seconds" withSeconds />
}
```

## With Icon

```tsx

function Demo() {
  return <TimeInput label="Select time" leftSection={<IconClock size={16} />} />
}
```

## Show Browser Picker

```tsx

function Demo() {
  const ref = useRef<HTMLInputElement>(null)

  return (
    <TimeInput
      label="Click icon to show picker"
      ref={ref}
      rightSection={
        <ActionIcon variant="subtle" onClick={() => ref.current?.showPicker()}>
          <IconClock size={16} />
        </ActionIcon>
      }
    />
  )
}
```

## Key Props

| Prop           | Type              | Description                      |
| -------------- | ----------------- | -------------------------------- |
| `value`        | `string`          | Controlled value                 |
| `defaultValue` | `string`          | Default value (uncontrolled)     |
| `onChange`     | `(event) => void` | Called when value changes        |
| `withSeconds`  | `boolean`         | Show seconds input               |
| `minTime`      | `string`          | Minimum time (HH:mm or HH:mm:ss) |
| `maxTime`      | `string`          | Maximum time (HH:mm or HH:mm:ss) |
| `label`        | `ReactNode`       | Input label                      |
| `description`  | `ReactNode`       | Input description                |
| `placeholder`  | `string`          | Placeholder text                 |
| `error`        | `ReactNode`       | Error message                    |
| `disabled`     | `boolean`         | Disable input                    |
| `size`         | `MantineSize`     | Input size                       |
| `radius`       | `MantineRadius`   | Border radius                    |

--------------------------------------------------------------------------------

### Timeline
Package: @tidbcloud/uikit
Import: import { Timeline } from '@tidbcloud/uikit';
Description: Display list of events in chronological order. Timeline is commonly used for activity feeds, version history, or step-by-step processes.

Display list of events in chronological order. Timeline is commonly used for activity feeds, version history, or step-by-step processes.

## Basic Usage

```tsx

function Demo() {
  return (
    <Timeline active={1} bulletSize={24} lineWidth={2}>
      <Timeline.Item title="New branch">
        <Text c="dimmed" size="sm">
          You created new branch fix-notifications from master
        </Text>
        <Text size="xs" mt={4}>
          2 hours ago
        </Text>
      </Timeline.Item>

      <Timeline.Item title="Commits">
        <Text c="dimmed" size="sm">
          You pushed 23 commits to fix-notifications branch
        </Text>
        <Text size="xs" mt={4}>
          52 minutes ago
        </Text>
      </Timeline.Item>

      <Timeline.Item title="Pull request" lineVariant="dashed">
        <Text c="dimmed" size="sm">
          You submitted a pull request
        </Text>
        <Text size="xs" mt={4}>
          34 minutes ago
        </Text>
      </Timeline.Item>

      <Timeline.Item title="Code review">
        <Text c="dimmed" size="sm">
          Robert left a code review on your pull request
        </Text>
        <Text size="xs" mt={4}>
          12 minutes ago
        </Text>
      </Timeline.Item>
    </Timeline>
  )
}
```

## Custom Bullet

Use `bullet` prop to customize the bullet icon:

```tsx

function Demo() {
  return (
    <Timeline bulletSize={24}>
      <Timeline.Item title="Default bullet">Default bullet without anything</Timeline.Item>
      <Timeline.Item title="Avatar" bullet={<Avatar size={22} radius="xl" src="avatar.png" />}>
        Timeline bullet as avatar image
      </Timeline.Item>
      <Timeline.Item title="Icon" bullet={<IconSun size={13} />}>
        Timeline bullet as icon
      </Timeline.Item>
    </Timeline>
  )
}
```

## Key Props

| Prop          | Type              | Description                                |
| ------------- | ----------------- | ------------------------------------------ |
| active        | number            | Index of the active element                |
| align         | 'left' \| 'right' | Position of content relative to the bullet |
| bulletSize    | number            | Size of the bullet                         |
| color         | MantineColor      | Color for active items                     |
| lineWidth     | number            | Width of the line                          |
| radius        | MantineRadius     | Border radius of bullets                   |
| reverseActive | boolean           | Reverse the active items direction         |

--------------------------------------------------------------------------------

### Title
Package: @tidbcloud/uikit
Import: import { Title } from '@tidbcloud/uikit';
Description: Render h1-h6 headings with Mantine theme styles. By default, Title has no margins and paddings.

Render h1-h6 headings with Mantine theme styles. By default, Title has no margins and paddings.

## Basic Usage

Set `order` prop to render a specific heading element (h1-h6):

```tsx

function Demo() {
  return (
    <>
      <Title order={1}>This is h1 title</Title>
      <Title order={2}>This is h2 title</Title>
      <Title order={3}>This is h3 title</Title>
      <Title order={4}>This is h4 title</Title>
      <Title order={5}>This is h5 title</Title>
      <Title order={6}>This is h6 title</Title>
    </>
  )
}
```

## Custom Size

Change Title `size` independent of its `order`:

```tsx

function Demo() {
  return (
    <>
      <Title order={3} size="h1">
        H3 heading with h1 font-size
      </Title>
      <Title size="h4">H1 heading with h4 font-size</Title>
      <Title size={16}>H1 heading with 16px size</Title>
      <Title size="xs">H1 heading with xs size</Title>
    </>
  )
}
```

## Line Clamp

Set `lineClamp` prop to truncate text after a specified number of lines:

```tsx

function Demo() {
  return (
    <Box maw={400}>
      <Title order={2} lineClamp={2}>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Iure doloremque quas dolorum. Quo amet earum alias
        consequuntur.
      </Title>
    </Box>
  )
}
```

## Key Props

| Prop      | Type                                        | Description                                                       |
| --------- | ------------------------------------------- | ----------------------------------------------------------------- |
| order     | 1-6                                         | Heading order (h1-h6), controls font-size if size prop is not set |
| size      | TitleSize                                   | Changes title size independent of order                           |
| lineClamp | number                                      | Number of lines after which heading will be truncated             |
| textWrap  | 'wrap' \| 'nowrap' \| 'balance' \| 'pretty' | Controls text-wrap CSS property                                   |

--------------------------------------------------------------------------------

### Tooltip
Package: @tidbcloud/uikit
Import: import { Tooltip } from '@tidbcloud/uikit';
Description: Render a tooltip at a given element on mouse over or other events. Commonly used to provide additional context or information.

Render a tooltip at a given element on mouse over or other events. Commonly used to provide additional context or information.

## Basic Usage

```tsx

function Demo() {
  return (
    <Tooltip label="Tooltip content">
      <Button>Button with tooltip</Button>
    </Tooltip>
  )
}
```

## With Arrow

Set `withArrow` prop to add an arrow to the tooltip:

```tsx

function Demo() {
  return (
    <Tooltip label="Tooltip with arrow" withArrow>
      <Button>With arrow</Button>
    </Tooltip>
  )
}
```

## Multiline

Enable multiline mode with `multiline` prop and set width with `w` prop:

```tsx

function Demo() {
  return (
    <Tooltip
      multiline
      w={220}
      withArrow
      label="Use this button to save this information in your profile, after that you will be able to access it any time."
    >
      <Button>Multiline tooltip</Button>
    </Tooltip>
  )
}
```

## Controlled

Control tooltip state with `opened` prop:

```tsx

function Demo() {
  const [opened, setOpened] = useState(false)

  return (
    <Tooltip label="Ctrl + J" opened={opened}>
      <Button onClick={() => setOpened((o) => !o)}>Toggle tooltip</Button>
    </Tooltip>
  )
}
```

## Key Props

| Prop       | Type             | Description                                       |
| ---------- | ---------------- | ------------------------------------------------- |
| label      | ReactNode        | Tooltip content                                   |
| position   | FloatingPosition | Tooltip position relative to target               |
| withArrow  | boolean          | Adds an arrow to the tooltip                      |
| arrowSize  | number           | Arrow size in px                                  |
| offset     | number           | Space between tooltip and target in px            |
| multiline  | boolean          | Enable multiline mode                             |
| opened     | boolean          | Control tooltip state (controlled mode)           |
| openDelay  | number           | Delay in ms before showing tooltip                |
| closeDelay | number           | Delay in ms before hiding tooltip                 |
| color      | MantineColor     | Tooltip background color                          |
| events     | object           | Events that trigger tooltip (hover, focus, touch) |

--------------------------------------------------------------------------------

### Transition
Package: @tidbcloud/uikit
Import: import { Transition } from '@tidbcloud/uikit';
Description: Animate presence of components with pre-made or custom animations. Use it to add enter/exit animations to elements.

Animate presence of components with pre-made or custom animations. Use it to add enter/exit animations to elements.

## Basic Usage

```tsx

function Demo({ opened }: { opened: boolean }) {
  return (
    <Transition mounted={opened} transition="fade" duration={400} timingFunction="ease">
      {(styles) => <div style={styles}>Your content</div>}
    </Transition>
  )
}
```

## Premade Transitions

Available transition presets: `fade`, `scale`, `scale-y`, `scale-x`, `skew-up`, `skew-down`, `rotate-left`, `rotate-right`, `slide-down`, `slide-up`, `slide-left`, `slide-right`, `pop`, `pop-bottom-left`, `pop-bottom-right`, `pop-top-left`, `pop-top-right`.

## Custom Transition

Create custom transitions with an object containing `in`, `out`, and `transitionProperty`:

```tsx

const scaleY = {
  in: { opacity: 1, transform: 'scaleY(1)' },
  out: { opacity: 0, transform: 'scaleY(0)' },
  common: { transformOrigin: 'top' },
  transitionProperty: 'transform, opacity'
}

function Demo() {
  const [opened, setOpened] = useState(false)

  return (
    <Box>
      <Button onClick={() => setOpened((o) => !o)}>Toggle</Button>
      <Transition mounted={opened} transition={scaleY} duration={200}>
        {(styles) => (
          <Paper shadow="md" p="xl" style={styles}>
            Dropdown content
          </Paper>
        )}
      </Transition>
    </Box>
  )
}
```

## Enter and Exit Delay

Use `enterDelay` and `exitDelay` props to delay transition start:

```tsx

function Demo({ opened }: { opened: boolean }) {
  return (
    <Transition mounted={opened} transition="pop" enterDelay={500} exitDelay={300}>
      {(styles) => <div style={styles}>Delayed transition</div>}
    </Transition>
  )
}
```

## Key Props

| Prop           | Type              | Description                                   |
| -------------- | ----------------- | --------------------------------------------- |
| mounted        | boolean           | Whether component should be mounted           |
| transition     | MantineTransition | Transition name or custom transition object   |
| duration       | number            | Transition duration in ms                     |
| exitDuration   | number            | Exit transition duration in ms                |
| timingFunction | string            | Timing function for transition                |
| enterDelay     | number            | Delay before enter transition starts          |
| exitDelay      | number            | Delay before exit transition starts           |
| keepMounted    | boolean           | If true, element is not unmounted when hidden |
| onEnter        | () => void        | Called when enter transition starts           |
| onEntered      | () => void        | Called when enter transition ends             |
| onExit         | () => void        | Called when exit transition starts            |
| onExited       | () => void        | Called when exit transition ends              |

--------------------------------------------------------------------------------

### Tree
Package: @tidbcloud/uikit
Import: import { Tree } from '@tidbcloud/uikit';
Description: Display hierarchical data in a tree structure. Commonly used for file explorers, nested menus, or organizational structures.

Display hierarchical data in a tree structure. Commonly used for file explorers, nested menus, or organizational structures.

## Basic Usage

```tsx

const data = [
  {
    value: 'src',
    label: 'src',
    children: [
      { value: 'src/components', label: 'components' },
      { value: 'src/hooks', label: 'hooks' }
    ]
  },
  { value: 'package.json', label: 'package.json' }
]

function Demo() {
  return <Tree data={data} />
}
```

## Custom Node Rendering

Use `renderNode` prop to customize node rendering:

```tsx

function Demo() {
  return (
    <Tree
      data={data}
      levelOffset={23}
      renderNode={({ node, expanded, hasChildren, elementProps }) => (
        <Group gap={5} {...elementProps}>
          {hasChildren && (
            <IconChevronDown size={18} style={{ transform: expanded ? 'rotate(180deg)' : 'rotate(0deg)' }} />
          )}
          <span>{node.label}</span>
        </Group>
      )}
    />
  )
}
```

## Using useTree Hook

Control tree state with `useTree` hook:

```tsx

function Demo() {
  const tree = useTree()

  return (
    <>
      <Tree data={data} tree={tree} />
      <Group mt="md">
        <Button onClick={() => tree.expandAllNodes()}>Expand all</Button>
        <Button onClick={() => tree.collapseAllNodes()}>Collapse all</Button>
      </Group>
    </>
  )
}
```

## Key Props

| Prop                         | Type              | Description                              |
| ---------------------------- | ----------------- | ---------------------------------------- |
| data                         | TreeNodeData[]    | Data used to render nodes (required)     |
| tree                         | UseTreeReturnType | useTree hook instance to control state   |
| renderNode                   | RenderNode        | Function to customize node rendering     |
| levelOffset                  | MantineSpacing    | Horizontal padding of each subtree level |
| expandOnClick                | boolean           | Expand node with children on click       |
| selectOnClick                | boolean           | Select tree node on click                |
| clearSelectionOnOutsideClick | boolean           | Clear selection when clicking outside    |
| allowRangeSelection          | boolean           | Allow range selection with Shift key     |

--------------------------------------------------------------------------------

### Typography
Package: @tidbcloud/uikit
Import: import { Typography } from '@tidbcloud/uikit';
Description: A custom text component with predefined variant styles for consistent typography across your application.

A custom text component with predefined variant styles for consistent typography across your application.

## Basic Usage

```tsx

function Demo() {
  return <Typography variant="headline-lg">Large Headline Text</Typography>
}
```

## Variants

Typography supports 18 predefined variants organized into 5 categories:

### Headlines

```tsx

function Demo() {
  return (
    <Stack>
      <Typography variant="headline-lg">Headline Large (24px, 700)</Typography>
      <Typography variant="headline-md">Headline Medium (20px, 700)</Typography>
      <Typography variant="headline-sm">Headline Small (18px, 700)</Typography>
    </Stack>
  )
}
```

### Titles

```tsx

function Demo() {
  return (
    <Stack>
      <Typography variant="title-lg">Title Large (16px, 700)</Typography>
      <Typography variant="title-md">Title Medium (14px, 700)</Typography>
      <Typography variant="title-sm">Title Small (12px, 700)</Typography>
    </Stack>
  )
}
```

### Actions

```tsx

function Demo() {
  return (
    <Stack>
      <Typography variant="action-lg">Action Large (16px, 600)</Typography>
      <Typography variant="action-md">Action Medium (14px, 600)</Typography>
      <Typography variant="action-sm">Action Small (12px, 600)</Typography>
    </Stack>
  )
}
```

### Labels

```tsx

function Demo() {
  return (
    <Stack>
      <Typography variant="label-lg">Label Large (14px, 500)</Typography>
      <Typography variant="label-md">Label Medium (13px, 500)</Typography>
      <Typography variant="label-sm">Label Small (12px, 500)</Typography>
      <Typography variant="label-xs">Label Extra Small (11px, 500)</Typography>
    </Stack>
  )
}
```

### Body

```tsx

function Demo() {
  return (
    <Stack>
      <Typography variant="body-lg">Body Large (14px, 400)</Typography>
      <Typography variant="body-md">Body Medium (13px, 400)</Typography>
      <Typography variant="body-sm">Body Small (12px, 400)</Typography>
      <Typography variant="body-xs">Body Extra Small (11px, 400)</Typography>
    </Stack>
  )
}
```

## Polymorphic Component

Typography can render as any HTML element using the `component` prop:

```tsx

function Demo() {
  return (
    <>
      <Typography variant="headline-lg" component="h1">
        As H1 Element
      </Typography>
      <Typography variant="body-md" component="span">
        As Span Element
      </Typography>
    </>
  )
}
```

## Override Styles

You can override the default styles using standard Mantine Text props:

```tsx

function Demo() {
  return (
    <Typography variant="body-md" c="blue" fw={700}>
      Custom colored and bold text
    </Typography>
  )
}
```

## Props

| Prop        | Type                 | Default | Description                     |
| ----------- | -------------------- | ------- | ------------------------------- |
| `variant`   | `TypographyVariants` | -       | Predefined typography style     |
| `component` | `ElementType`        | `'div'` | HTML element to render          |
| `c`         | `MantineColor`       | -       | Text color (overrides variant)  |
| `fz`        | `MantineSize`        | -       | Font size (overrides variant)   |
| `fw`        | `number`             | -       | Font weight (overrides variant) |
| `lh`        | `string \| number`   | -       | Line height (overrides variant) |

## Variant Reference

| Variant       | Font Size | Line Height | Font Weight | Color     |
| ------------- | --------- | ----------- | ----------- | --------- |
| `headline-lg` | 24px      | 32px        | 700         | carbon.9  |
| `headline-md` | 20px      | 30px        | 700         | carbon.9  |
| `headline-sm` | 18px      | 28px        | 700         | carbon.9  |
| `title-lg`    | 16px      | 24px        | 700         | carbon.9  |
| `title-md`    | 14px      | 20px        | 700         | carbon.9  |
| `title-sm`    | 12px      | 18px        | 700         | carbon.9  |
| `action-lg`   | 16px      | 24px        | 600         | peacock.7 |
| `action-md`   | 14px      | 20px        | 600         | peacock.7 |
| `action-sm`   | 12px      | 18px        | 600         | peacock.7 |
| `label-lg`    | 14px      | 20px        | 500         | carbon.8  |
| `label-md`    | 13px      | 18px        | 500         | carbon.8  |
| `label-sm`    | 12px      | 18px        | 500         | carbon.8  |
| `label-xs`    | 11px      | 16px        | 500         | carbon.8  |
| `body-lg`     | 14px      | 20px        | 400         | carbon.8  |
| `body-md`     | 13px      | 18px        | 400         | carbon.8  |
| `body-sm`     | 12px      | 18px        | 400         | carbon.8  |
| `body-xs`     | 11px      | 16px        | 400         | carbon.8  |

--------------------------------------------------------------------------------

### TypographyStylesProvider
Package: @tidbcloud/uikit
Import: import { TypographyStylesProvider } from '@tidbcloud/uikit';
Description: Styles provider for HTML content. Use it to add typography styles to raw HTML content, such as content from a CMS or markdown parser.

Styles provider for HTML content. Use it to add typography styles to raw HTML content, such as content from a CMS or markdown parser.

## Basic Usage

Wrap your HTML content with `TypographyStylesProvider` to apply consistent typography styles:

```tsx

function Demo() {
  return (
    <TypographyStylesProvider>
      <div dangerouslySetInnerHTML={{ __html: '<p>Your html content here</p>' }} />
    </TypographyStylesProvider>
  )
}
```

## Styled Elements

`TypographyStylesProvider` includes styles for:

- Paragraphs (`<p>`)
- Headings (`<h1>` - `<h6>`)
- Lists (`<ul>`, `<ol>`, `<li>`)
- Blockquotes (`<blockquote>`)
- Tables (`<table>`, `<th>`, `<td>`)
- Links (`<a>`)
- Images (`<img>`)
- Horizontal rules (`<hr>`)
- Keyboard keys (`<kbd>`)
- Code blocks (`<code>`, `<pre>`)

## Example with Markdown

```tsx

const htmlContent = `
  <h1>Welcome</h1>
  <p>This is a paragraph with a <a href="#">link</a>.</p>
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
  </ul>
  <blockquote>This is a quote</blockquote>
  <pre><code>const x = 1;</code></pre>
`

function Demo() {
  return (
    <TypographyStylesProvider>
      <div dangerouslySetInnerHTML={{ __html: htmlContent }} />
    </TypographyStylesProvider>
  )
}
```

## Key Props

| Prop     | Type      | Description                           |
| -------- | --------- | ------------------------------------- |
| children | ReactNode | Content to apply typography styles to |

--------------------------------------------------------------------------------

### UnstyledButton
Package: @tidbcloud/uikit
Import: import { UnstyledButton } from '@tidbcloud/uikit';
Description: Unstyled polymorphic button that resets default button styles. Use it as a base for custom button components.

Unstyled polymorphic button that resets default button styles. Use it as a base for custom button components.

## Basic Usage

```tsx

function Demo() {
  return <UnstyledButton>Button without styles</UnstyledButton>
}
```

## Polymorphic Component

`UnstyledButton` is a polymorphic component - change the root element with `component` prop:

```tsx

function Demo() {
  return (
    <>
      {/* Renders as button (default) */}
      <UnstyledButton>Click me</UnstyledButton>

      {/* Renders as anchor */}
      <UnstyledButton component="a" href="https://example.com">
        Link button
      </UnstyledButton>
    </>
  )
}
```

## Custom Button Example

Create a custom styled button based on `UnstyledButton`:

```tsx

function CustomButton({ children, ...props }) {
  return (
    <UnstyledButton
      style={{
        padding: '10px 20px',
        backgroundColor: 'var(--mantine-color-blue-6)',
        color: 'white',
        borderRadius: '4px'
      }}
      {...props}
    >
      {children}
    </UnstyledButton>
  )
}
```

## Get Element Ref

```tsx

function Demo() {
  const ref = useRef<HTMLButtonElement>(null)
  return <UnstyledButton ref={ref}>Button</UnstyledButton>
}
```

## Key Props

| Prop      | Type             | Description                                       |
| --------- | ---------------- | ------------------------------------------------- |
| component | ElementType      | Root element to render (default: 'button')        |
| size      | string \| number | Size passed from parent, sets data-size attribute |

--------------------------------------------------------------------------------

### VisuallyHidden
Package: @tidbcloud/uikit
Import: import { VisuallyHidden } from '@tidbcloud/uikit';
Description: Hide content visually but keep it accessible for screen readers. Essential for improving accessibility of icon-only buttons and other visual elements.

Hide content visually but keep it accessible for screen readers. Essential for improving accessibility of icon-only buttons and other visual elements.

## Basic Usage

Use with icon-only buttons to provide accessible labels:

```tsx

function Demo() {
  return (
    <ActionIcon>
      <IconHeart />
      <VisuallyHidden>Like post</VisuallyHidden>
    </ActionIcon>
  )
}
```

## With Burger Menu

```tsx

function Demo() {
  return (
    <Burger opened={false} onClick={() => {}}>
      <VisuallyHidden>Toggle navigation</VisuallyHidden>
    </Burger>
  )
}
```

## With Close Button

```tsx

function Demo() {
  return (
    <CloseButton>
      <VisuallyHidden>Close modal</VisuallyHidden>
    </CloseButton>
  )
}
```

## With SegmentedControl

```tsx

function Demo() {
  return (
    <SegmentedControl
      data={[
        {
          value: 'preview',
          label: (
            <Center>
              <IconEye size={16} />
              <VisuallyHidden>Preview</VisuallyHidden>
            </Center>
          )
        },
        {
          value: 'code',
          label: (
            <Center>
              <IconCode size={16} />
              <VisuallyHidden>Code</VisuallyHidden>
            </Center>
          )
        }
      ]}
    />
  )
}
```

## Key Props

| Prop     | Type      | Description                                  |
| -------- | --------- | -------------------------------------------- |
| children | ReactNode | Content to hide visually but keep accessible |

--------------------------------------------------------------------------------

### YearPicker
Package: @tidbcloud/uikit
Import: import { YearPicker } from '@tidbcloud/uikit';
Description: Inline year picker component. Pick single year, multiple years, or a years range.

Inline year picker component. Pick single year, multiple years, or a years range.

## Basic Usage

```tsx

function Demo() {
  const [value, setValue] = useState<Date | null>(null)
  return <YearPicker value={value} onChange={setValue} />
}
```

## Multiple Years

Set `type="multiple"` to allow selecting multiple years:

```tsx

function Demo() {
  const [value, setValue] = useState<Date[]>([])
  return <YearPicker type="multiple" value={value} onChange={setValue} />
}
```

## Years Range

Set `type="range"` to pick a range of years:

```tsx

function Demo() {
  const [value, setValue] = useState<[Date | null, Date | null]>([null, null])
  return <YearPicker type="range" value={value} onChange={setValue} />
}
```

## Min and Max Date

Set `minDate` and `maxDate` to constrain the selectable range:

```tsx

function Demo() {
  const [value, setValue] = useState<Date | null>(null)
  return <YearPicker value={value} onChange={setValue} minDate={new Date(2021, 1, 1)} maxDate={new Date(2028, 1, 1)} />
}
```

## Custom Year Format

Use `yearsListFormat` to customize year display:

```tsx

function Demo() {
  const [value, setValue] = useState<Date | null>(null)
  return <YearPicker yearsListFormat="YY" value={value} onChange={setValue} />
}
```

## Key Props

| Prop                | Type                               | Description                                 |
| ------------------- | ---------------------------------- | ------------------------------------------- |
| value               | DateValue                          | Selected year value (controlled)            |
| onChange            | (value: DateValue) => void         | Called when value changes                   |
| type                | 'default' \| 'multiple' \| 'range' | Picker type                                 |
| allowDeselect       | boolean                            | Allow deselecting by clicking selected year |
| minDate             | string \| Date                     | Minimum selectable date                     |
| maxDate             | string \| Date                     | Maximum selectable date                     |
| defaultDate         | string \| Date                     | Initial displayed decade                    |
| numberOfColumns     | number                             | Number of pickers displayed side by side    |
| yearsListFormat     | string                             | dayjs format for years list                 |
| decadeLabelFormat   | string                             | dayjs format for decade label               |
| getYearControlProps | function                           | Add props to year controls                  |

--------------------------------------------------------------------------------

### YearPickerInput
Package: @tidbcloud/uikit
Import: import { YearPickerInput } from '@tidbcloud/uikit';
Description: Year picker input with dropdown. Select single year, multiple years, or a years range from a dropdown.

Year picker input with dropdown. Select single year, multiple years, or a years range from a dropdown.

## Basic Usage

```tsx

function Demo() {
  const [value, setValue] = useState<Date | null>(null)
  return <YearPickerInput label="Pick year" placeholder="Pick year" value={value} onChange={setValue} />
}
```

## Multiple Years

Set `type="multiple"` to allow selecting multiple years:

```tsx

function Demo() {
  const [value, setValue] = useState<Date[]>([])
  return (
    <YearPickerInput type="multiple" label="Pick years" placeholder="Pick years" value={value} onChange={setValue} />
  )
}
```

## Years Range

Set `type="range"` to pick a range of years:

```tsx

function Demo() {
  const [value, setValue] = useState<[Date | null, Date | null]>([null, null])
  return (
    <YearPickerInput
      type="range"
      label="Pick years range"
      placeholder="Pick years range"
      value={value}
      onChange={setValue}
    />
  )
}
```

## Custom Value Format

Use `valueFormat` prop to customize display format:

```tsx

function Demo() {
  return <YearPickerInput valueFormat="YY" type="multiple" label="Pick year" placeholder="Pick year" />
}
```

## Modal Dropdown

Change dropdown to modal with `dropdownType="modal"`:

```tsx

function Demo() {
  return <YearPickerInput dropdownType="modal" label="Pick year" placeholder="Pick year" />
}
```

## Key Props

| Prop         | Type                               | Description                      |
| ------------ | ---------------------------------- | -------------------------------- |
| value        | DateValue                          | Selected year value (controlled) |
| onChange     | (value: DateValue) => void         | Called when value changes        |
| type         | 'default' \| 'multiple' \| 'range' | Picker type                      |
| label        | ReactNode                          | Input label                      |
| placeholder  | string                             | Input placeholder                |
| clearable    | boolean                            | Show clear button when has value |
| dropdownType | 'popover' \| 'modal'               | Dropdown type                    |
| valueFormat  | string                             | dayjs format for displayed value |
| minDate      | string \| Date                     | Minimum selectable date          |
| maxDate      | string \| Date                     | Maximum selectable date          |
| disabled     | boolean                            | Disable the input                |
| error        | ReactNode                          | Error message                    |

--------------------------------------------------------------------------------

### notifier
Package: @tidbcloud/uikit
Import: import { notifier } from '@tidbcloud/uikit';
Description: A utility for displaying notifications with pre-configured colors. Built on top of `@mantine/notifications`.

A utility for displaying notifications with pre-configured colors. Built on top of `@mantine/notifications`.

## Setup

Before using notifier, make sure you have the `Notifications` component set up in your app:

```tsx

function App() {
  return (
    <>
      <Notifications />
      {/* Your app content */}
    </>
  )
}
```

## Basic Usage

```tsx

function Demo() {
  return (
    <Group>
      <Button onClick={() => notifier.success('Operation completed successfully!')}>Success</Button>
      <Button onClick={() => notifier.error('Something went wrong!')}>Error</Button>
      <Button onClick={() => notifier.warn('Please check your input')}>Warning</Button>
      <Button onClick={() => notifier.info('New updates available')}>Info</Button>
    </Group>
  )
}
```

## With Additional Options

You can pass additional notification options as the second argument:

```tsx

function Demo() {
  return (
    <Button
      onClick={() =>
        notifier.success('File uploaded!', {
          title: 'Upload Complete',
          autoClose: 5000,
          withCloseButton: true
        })
      }
    >
      Upload File
    </Button>
  )
}
```

## Clear All Notifications

```tsx

function Demo() {
  return <Button onClick={() => notifier.clear()}>Clear All Notifications</Button>
}
```

## Methods

| Method             | Parameters                                       | Description                      |
| ------------------ | ------------------------------------------------ | -------------------------------- |
| `notifier.success` | `(message: ReactNode, props?: NotificationData)` | Show green success notification  |
| `notifier.error`   | `(message: ReactNode, props?: NotificationData)` | Show red error notification      |
| `notifier.warn`    | `(message: ReactNode, props?: NotificationData)` | Show yellow warning notification |
| `notifier.info`    | `(message: ReactNode, props?: NotificationData)` | Show cyan info notification      |
| `notifier.clear`   | `()`                                             | Clear all notifications          |

## NotificationData Options

| Option            | Type              | Description                                |
| ----------------- | ----------------- | ------------------------------------------ |
| `title`           | `ReactNode`       | Notification title                         |
| `icon`            | `ReactNode`       | Notification icon                          |
| `autoClose`       | `number \| false` | Auto close timeout in ms, false to disable |
| `withCloseButton` | `boolean`         | Show close button                          |
| `onClose`         | `() => void`      | Called when notification is closed         |
| `onOpen`          | `() => void`      | Called when notification is opened         |
| `loading`         | `boolean`         | Show loading state                         |
| `radius`          | `MantineRadius`   | Border radius                              |
| `withBorder`      | `boolean`         | Add border                                 |

--------------------------------------------------------------------------------


## BUSINESS COMPONENTS
Higher-level business components from @tidbcloud/uikit/biz
Primary Package: @tidbcloud/uikit/biz

--------------------------------------------------------------------------------

### AppShell
Package: @tidbcloud/uikit/biz
Import: import { AppShell } from '@tidbcloud/uikit/biz';
Description: A main application shell component that provides a layout structure with a collapsible sidebar navbar, banner support, and main content area.

A main application shell component that provides a layout structure with a collapsible sidebar navbar, banner support, and main content area.

## Basic Usage

```tsx

function Demo() {
  return (
    <AppShell
      navbar={{
        logo: <img src="/logo.svg" alt="Logo" />
      }}
    >
      <AppShell.NavMenuPortal>
        <AppShell.NavItem label="Dashboard" href="/dashboard" />
        <AppShell.NavItem label="Settings" href="/settings" />
      </AppShell.NavMenuPortal>

      <AppPageShell title="Dashboard">
        <p>Page content here</p>
      </AppPageShell>
    </AppShell>
  )
}
```

## With Banner

```tsx

function Demo() {
  return (
    <AppShell
      banner={<Alert color="blue">New features available!</Alert>}
      navbar={{
        logo: <img src="/logo.svg" alt="Logo" />
      }}
    >
      <AppPageShell title="Home">Content</AppPageShell>
    </AppShell>
  )
}
```

## Navigation Items

```tsx

function Demo() {
  return (
    <AppShell navbar={{ logo: <Logo /> }}>
      <AppShell.NavMenuPortal>
        <AppShell.NavItem label="Dashboard" href="/dashboard" leftSection={<IconHome size={16} />} />
        <AppShell.NavItem label="Settings" href="/settings" leftSection={<IconSettings size={16} />}>
          <AppShell.NavSubItem label="General" href="/settings/general" />
          <AppShell.NavSubItem label="Security" href="/settings/security" />
        </AppShell.NavItem>
      </AppShell.NavMenuPortal>

      <AppShell.NavFooterPortal>
        <AppShell.NavFooterItem label="Help" href="/help" />
      </AppShell.NavFooterPortal>
    </AppShell>
  )
}
```

## Collapse Events

```tsx

function Demo() {
  return (
    <AppShell
      navbar={{
        logo: <Logo />,
        onCollapse: () => console.log('Navbar collapsed'),
        onExpand: () => console.log('Navbar expanded')
      }}
    >
      {/* content */}
    </AppShell>
  )
}
```

## AppShell Props

| Prop     | Type        | Default | Description                 |
| -------- | ----------- | ------- | --------------------------- |
| `banner` | `ReactNode` | -       | Banner displayed at the top |
| `navbar` | `object`    | -       | Navbar configuration object |

### Navbar Configuration

| Prop                       | Type         | Default | Description                     |
| -------------------------- | ------------ | ------- | ------------------------------- |
| `navbar.width`             | `number`     | `240`   | Custom width of the navbar      |
| `navbar.logo`              | `ReactNode`  | -       | Logo displayed in navbar header |
| `navbar.headerLeftSection` | `ReactNode`  | -       | Left section of navbar header   |
| `navbar.menuTop`           | `ReactNode`  | -       | Content between header and menu |
| `navbar.footer`            | `ReactNode`  | -       | Footer section of navbar        |
| `navbar.onLogoClick`       | `() => void` | -       | Callback when logo is clicked   |
| `navbar.onCollapse`        | `() => void` | -       | Callback when navbar collapses  |
| `navbar.onExpand`          | `() => void` | -       | Callback when navbar expands    |

## Sub-components

| Component                          | Description                   |
| ---------------------------------- | ----------------------------- |
| `AppShell.NavMenuPortal`           | Portal for nav menu items     |
| `AppShell.NavItem`                 | Base navigation item          |
| `AppShell.NavSubItem`              | Sub-navigation item           |
| `AppShell.NavFooterPortal`         | Portal for footer items       |
| `AppShell.NavFooterItem`           | Footer navigation item        |
| `AppShell.ExpandButtonPlaceholder` | Placeholder for expand button |

---

# AppPageShell

Page-level shell component designed to work within AppShell.

## Basic Usage

```tsx

function Demo() {
  return (
    <AppPageShell title="Page Title">
      <p>Page content goes here</p>
    </AppPageShell>
  )
}
```

## With Back Button

```tsx

function Demo() {
  return (
    <AppPageShell title="Details" showBack onBack={() => window.history.back()}>
      <p>Detail content</p>
    </AppPageShell>
  )
}
```

## Sticky Header

```tsx

function Demo() {
  return (
    <AppPageShell title="Long Page" stickyHeader>
      {/* Long scrollable content */}
    </AppPageShell>
  )
}
```

## AppPageShell Props

| Prop           | Type         | Default    | Description                |
| -------------- | ------------ | ---------- | -------------------------- |
| `maxWidth`     | `string`     | `'1920px'` | Maximum width of the page  |
| `withHeader`   | `boolean`    | `true`     | Whether to show the header |
| `title`        | `ReactNode`  | -          | Page title                 |
| `children`     | `ReactNode`  | -          | Page content               |
| `wrapperProps` | `object`     | -          | Props for the wrapper      |
| `stickyHeader` | `boolean`    | -          | Whether header is sticky   |
| `showBack`     | `boolean`    | -          | Show back button           |
| `onBack`       | `() => void` | -          | Back button click handler  |
| `bodyProps`    | `object`     | -          | Props for body section     |

--------------------------------------------------------------------------------

### CodeBlock
Package: @tidbcloud/uikit/biz
Import: import { CodeBlock } from '@tidbcloud/uikit/biz';
Description: A code display component with syntax highlighting, copy functionality, and optional folding/collapsing capabilities.

A code display component with syntax highlighting, copy functionality, and optional folding/collapsing capabilities.

## Basic Usage

```tsx

const code = `SELECT * FROM users WHERE id = 1;`

function Demo() {
  return <CodeBlock language="sql">{code}</CodeBlock>
}
```

## Different Languages

```tsx

function Demo() {
  return (
    <>
      <CodeBlock language="javascript">
        {`const greeting = 'Hello, World!';
console.log(greeting);`}
      </CodeBlock>

      <CodeBlock language="python">
        {`def greet(name):
    return f"Hello, {name}!"`}
      </CodeBlock>
    </>
  )
}
```

## Foldable Code Block

```tsx

const longCode = `// Long code content...
line 1
line 2
line 3
...`

function Demo() {
  return (
    <CodeBlock language="javascript" defaultFoldHeight={100} showFoldIcon foldStateKey="my-code-block">
      {longCode}
    </CodeBlock>
  )
}
```

## Without Copy Button

```tsx

function Demo() {
  return (
    <CodeBlock language="bash" showCopy={false}>
      npm install @tidbcloud/uikit
    </CodeBlock>
  )
}
```

## Without Border

```tsx

function Demo() {
  return (
    <CodeBlock language="json" showBorder={false}>
      {JSON.stringify({ name: 'test' }, null, 2)}
    </CodeBlock>
  )
}
```

## Custom Copy Content

```tsx

function Demo() {
  return (
    <CodeBlock language="bash" copyContent="npm install @tidbcloud/uikit" onCopy={() => console.log('Copied!')}>
      $ npm install @tidbcloud/uikit
    </CodeBlock>
  )
}
```

## Props

| Prop                | Type                          | Default  | Description                                   |
| ------------------- | ----------------------------- | -------- | --------------------------------------------- |
| `children`          | `string`                      | -        | The code content to display                   |
| `language`          | `string`                      | `'bash'` | Programming language for syntax highlight     |
| `copyContent`       | `string`                      | -        | Custom content to copy (defaults to children) |
| `onCopy`            | `() => void`                  | -        | Callback when copy is clicked                 |
| `codeRenderer`      | `(code: string) => ReactNode` | -        | Custom code renderer                          |
| `prismProps`        | `PrismProps`                  | -        | Props for Prism highlighter                   |
| `defaultFoldHeight` | `number`                      | -        | Default height when folded                    |
| `foldStateKey`      | `string`                      | -        | Key for persisting fold state                 |
| `showFoldIcon`      | `boolean`                     | -        | Show fold/expand icon                         |
| `onFoldIconClick`   | `(folded: boolean) => void`   | -        | Fold icon click callback                      |
| `showBorder`        | `boolean`                     | `true`   | Show border                                   |
| `showCopy`          | `boolean`                     | `true`   | Show copy button                              |

---

# CopyText

A component that displays text with a copy button.

## Basic Usage

```tsx

function Demo() {
  return <CopyText value="Text to copy">Click to copy this text</CopyText>
}
```

## Props

| Prop       | Type        | Description       |
| ---------- | ----------- | ----------------- |
| `value`    | `string`    | The value to copy |
| `children` | `ReactNode` | Display content   |

--------------------------------------------------------------------------------

### CollapsibleCard
Package: @tidbcloud/uikit/biz
Import: import { CollapsibleCard } from '@tidbcloud/uikit/biz';
Description: A card component with collapsible/expandable content section, featuring a clickable header with chevron animation.

A card component with collapsible/expandable content section, featuring a clickable header with chevron animation.

## Basic Usage

```tsx

function Demo() {
  return (
    <CollapsibleCard header="Click to expand">
      <p>This content can be collapsed or expanded.</p>
    </CollapsibleCard>
  )
}
```

## Default Open

```tsx

function Demo() {
  return (
    <CollapsibleCard header="Expanded by default" defaultOpened>
      <p>This content is visible by default.</p>
    </CollapsibleCard>
  )
}
```

## Controlled

```tsx

function Demo() {
  const [opened, setOpened] = useState(false)

  return (
    <CollapsibleCard header="Controlled card" opened={opened} onToggle={() => setOpened(!opened)}>
      <p>Controlled collapsible content.</p>
    </CollapsibleCard>
  )
}
```

## Custom Header

```tsx

function Demo() {
  return (
    <CollapsibleCard
      header={
        <Group>
          <Text fw={600}>Advanced Settings</Text>
          <Badge>3 options</Badge>
        </Group>
      }
    >
      <p>Settings content here.</p>
    </CollapsibleCard>
  )
}
```

## Props

| Prop              | Type                        | Default | Description               |
| ----------------- | --------------------------- | ------- | ------------------------- |
| `header`          | `ReactNode`                 | -       | Card header/title content |
| `children`        | `ReactNode`                 | -       | Collapsible content       |
| `opened`          | `boolean`                   | -       | Controlled open state     |
| `defaultOpened`   | `boolean`                   | `false` | Initial open state        |
| `headerProps`     | `BoxProps`                  | -       | Props for header section  |
| `contentProps`    | `CollapseProps`             | -       | Props for content section |
| `onToggle`        | `(opened: boolean) => void` | -       | Callback when toggled     |
| `onTransitionEnd` | `() => void`                | -       | Callback after transition |

--------------------------------------------------------------------------------

### CopyText
Package: @tidbcloud/uikit/biz
Import: import { CopyText } from '@tidbcloud/uikit/biz';
Description: A text component with built-in copy-to-clipboard functionality, displaying text in a code-styled container with a copy button.

A text component with built-in copy-to-clipboard functionality, displaying text in a code-styled container with a copy button.

## Basic Usage

```tsx

function Demo() {
  return <CopyText value="mysql://user:password@host:3306/database">mysql://user:password@host:3306/database</CopyText>
}
```

## Custom Display vs Copy Value

You can display different content than what gets copied:

```tsx

function Demo() {
  const connectionString = 'mysql://user:password@host:3306/database'

  return <CopyText value={connectionString}>mysql://user:***@host:3306/database</CopyText>
}
```

## Custom Styling

CopyText extends Code props, so you can customize the styling:

```tsx

function Demo() {
  return (
    <CopyText value="SELECT * FROM users" bg="dark.6" c="green.4" fz="sm">
      SELECT * FROM users
    </CopyText>
  )
}
```

## In a Card

```tsx

function Demo() {
  return (
    <Card withBorder>
      <Stack gap="sm">
        <Text fw={500}>Connection Details</Text>
        <CopyText value="192.168.1.100">Host: 192.168.1.100</CopyText>
        <CopyText value="3306">Port: 3306</CopyText>
      </Stack>
    </Card>
  )
}
```

## Props

| Prop       | Type        | Default | Description                         |
| ---------- | ----------- | ------- | ----------------------------------- |
| `value`    | `string`    | -       | The text value to copy to clipboard |
| `children` | `ReactNode` | -       | Content to display                  |

CopyText also accepts all Code component props (`bg`, `c`, `fz`, `p`, `sx`, etc.).

--------------------------------------------------------------------------------

### DateTimePicker
Package: @tidbcloud/uikit/biz
Import: import { DateTimePicker } from '@tidbcloud/uikit/biz';
Description: A comprehensive date and time picker with calendar, time input, and scrollable time selection.

A comprehensive date and time picker with calendar, time input, and scrollable time selection.

## Basic Usage

```tsx

function Demo() {
  const [value, setValue] = useState(null)

  return <DateTimePicker value={value} onChange={setValue} placeholder="Select date and time" />
}
```

## With Default Value

```tsx

function Demo() {
  const [value, setValue] = useState(new Date())

  return <DateTimePicker value={value} onChange={setValue} />
}
```

## Custom Format

```tsx

function Demo() {
  return <DateTimePicker placeholder="Select date" format="YYYY/MM/DD HH:mm" />
}
```

## With Min/Max Date

```tsx

function Demo() {
  const minDate = new Date()
  const maxDate = new Date()
  maxDate.setMonth(maxDate.getMonth() + 3)

  return <DateTimePicker placeholder="Select date" minDate={minDate} maxDate={maxDate} />
}
```

## Disabled

```tsx

function Demo() {
  return <DateTimePicker placeholder="Disabled" disabled />
}
```

## Loading

```tsx

function Demo() {
  return <DateTimePicker placeholder="Loading..." loading />
}
```

## With Footer

```tsx

function Demo() {
  return (
    <DateTimePicker
      placeholder="Select date"
      footer={
        <Group justify="flex-end" p="xs">
          <Button size="xs" variant="subtle">
            Now
          </Button>
        </Group>
      }
    />
  )
}
```

## With Form

```tsx

function Demo() {
  return (
    <Form onSubmit={(data) => console.log(data)}>
      <FormDateTimePicker name="datetime" label="Select Date & Time" rules={{ required: 'Date is required' }} />
    </Form>
  )
}
```

## Props

| Prop           | Type                           | Default                  | Description               |
| -------------- | ------------------------------ | ------------------------ | ------------------------- |
| `value`        | `Date \| null`                 | -                        | Controlled date value     |
| `defaultValue` | `Date`                         | -                        | Default date value        |
| `onChange`     | `(date: Date \| null) => void` | -                        | Change callback           |
| `placeholder`  | `string`                       | `'Select date and time'` | Input placeholder         |
| `format`       | `string`                       | `'YYYY-MM-DD HH:mm:ss'`  | Date format string        |
| `formatter`    | `(date: Date) => string`       | -                        | Custom date formatter     |
| `minDate`      | `Date`                         | 10 years ago             | Minimum selectable date   |
| `maxDate`      | `Date`                         | 10 years from now        | Maximum selectable date   |
| `disabled`     | `boolean`                      | `false`                  | Disable the picker        |
| `withinPortal` | `boolean`                      | `true`                   | Render dropdown in portal |
| `loading`      | `boolean`                      | `false`                  | Show loading state        |
| `size`         | `MantineSize`                  | -                        | Input size                |
| `footer`       | `ReactNode`                    | -                        | Footer content            |

--------------------------------------------------------------------------------

### Dot
Package: @tidbcloud/uikit/biz
Import: import { Dot } from '@tidbcloud/uikit/biz';
Description: A simple colored dot/circle indicator component.

A simple colored dot/circle indicator component.

## Basic Usage

```tsx

function Demo() {
  return (
    <Group>
      <Dot color="green" />
      <Dot color="yellow" />
      <Dot color="red" />
    </Group>
  )
}
```

## Different Sizes

```tsx

function Demo() {
  return (
    <Group>
      <Dot color="blue" size={4} />
      <Dot color="blue" size={8} />
      <Dot color="blue" size={12} />
      <Dot color="blue" size={16} />
    </Group>
  )
}
```

## With Text

```tsx

function Demo() {
  return (
    <Group gap="xs">
      <Dot color="green" />
      <Text>Online</Text>
    </Group>
  )
}
```

## Props

| Prop    | Type           | Default | Description             |
| ------- | -------------- | ------- | ----------------------- |
| `color` | `MantineColor` | -       | Theme color for the dot |
| `size`  | `number`       | `8`     | Dot size in pixels      |

Dot also accepts all Box component props.

--------------------------------------------------------------------------------

### DotBadge
Package: @tidbcloud/uikit/biz
Import: import { DotBadge } from '@tidbcloud/uikit/biz';
Description: A badge component with a colored dot indicator, useful for status displays.

A badge component with a colored dot indicator, useful for status displays.

## Basic Usage

```tsx

function Demo() {
  return (
    <Group>
      <DotBadge color="green">Active</DotBadge>
      <DotBadge color="yellow">Pending</DotBadge>
      <DotBadge color="red">Error</DotBadge>
    </Group>
  )
}
```

## Status Indicator

```tsx

function Demo() {
  const statuses = [
    { status: 'running', color: 'green', label: 'Running' },
    { status: 'stopped', color: 'gray', label: 'Stopped' },
    { status: 'error', color: 'red', label: 'Error' },
    { status: 'warning', color: 'yellow', label: 'Warning' }
  ]

  return (
    <Stack>
      {statuses.map((s) => (
        <DotBadge key={s.status} color={s.color}>
          {s.label}
        </DotBadge>
      ))}
    </Stack>
  )
}
```

## Props

| Prop       | Type           | Default   | Description         |
| ---------- | -------------- | --------- | ------------------- |
| `color`    | `MantineColor` | `'green'` | Dot and badge color |
| `children` | `ReactNode`    | -         | Badge content       |

DotBadge also accepts all Badge component props (excluding color).

--------------------------------------------------------------------------------

### Form
Package: @tidbcloud/uikit/biz
Import: import { Form } from '@tidbcloud/uikit/biz';
Description: A comprehensive form component built on react-hook-form with validation, error handling, and layout support.

A comprehensive form component built on react-hook-form with validation, error handling, and layout support.

## Basic Usage

```tsx

function Demo() {
  const handleSubmit = (data) => {
    console.log(data)
  }

  return (
    <Form onSubmit={handleSubmit}>
      <FormTextInput name="username" label="Username" required />
      <FormTextInput name="email" label="Email" type="email" required />
      <FormSelect name="role" label="Role" data={['Admin', 'User', 'Guest']} />
    </Form>
  )
}
```

## With Validation

```tsx

function Demo() {
  return (
    <Form onSubmit={(data) => console.log(data)} defaultValues={{ email: '' }}>
      <FormTextInput
        name="email"
        label="Email"
        rules={{
          required: 'Email is required',
          pattern: {
            value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
            message: 'Invalid email address'
          }
        }}
      />
    </Form>
  )
}
```

## Horizontal Layout

```tsx

function Demo() {
  return (
    <Form layout="horizontal" onSubmit={(data) => console.log(data)}>
      <FormTextInput name="firstName" label="First Name" />
      <FormTextInput name="lastName" label="Last Name" />
    </Form>
  )
}
```

## Without Actions

```tsx

function Demo() {
  return (
    <Form withActions={false} onSubmit={(data) => console.log(data)}>
      <FormTextInput name="search" label="Search" />
      <Button type="submit">Search</Button>
    </Form>
  )
}
```

## Custom Actions

```tsx

function Demo() {
  return (
    <Form
      onSubmit={(data) => console.log(data)}
      onCancel={() => console.log('cancelled')}
      actionsProps={{
        cancelText: 'Reset',
        confirmText: 'Save Changes'
      }}
    >
      <FormTextInput name="name" label="Name" />
    </Form>
  )
}
```

## With Error Message

```tsx

function Demo() {
  return (
    <Form errorMessage="Failed to submit form. Please try again." onSubmit={(data) => console.log(data)}>
      <FormTextInput name="name" label="Name" />
    </Form>
  )
}
```

## Form Props

| Prop                | Type                                   | Default      | Description                   |
| ------------------- | -------------------------------------- | ------------ | ----------------------------- |
| `errorMessage`      | `string`                               | -            | Error message to display      |
| `mode`              | `'onChange' \| 'onBlur' \| 'onSubmit'` | -            | react-hook-form mode          |
| `reValidateMode`    | `'onChange' \| 'onBlur' \| 'onSubmit'` | `'onChange'` | Re-validation mode            |
| `defaultValues`     | `object`                               | -            | Default form values           |
| `form`              | `UseFormReturn`                        | -            | External form instance        |
| `withActions`       | `boolean`                              | `true`       | Show form actions             |
| `actionsProps`      | `FormActionsProps`                     | -            | Props for actions             |
| `errorMessageProps` | `FormErrorMessageProps`                | -            | Props for error message       |
| `layout`            | `'horizontal' \| 'vertical' \| 'none'` | `'vertical'` | Form layout                   |
| `layoutProps`       | `object`                               | -            | Props for layout              |
| `stopPropagation`   | `boolean`                              | -            | Stop submit event propagation |
| `preventDefault`    | `boolean`                              | -            | Prevent default submit        |
| `onSubmit`          | `(data) => void \| Promise`            | -            | Form submit handler           |
| `onRefresh`         | `() => void`                           | -            | Refresh callback              |
| `onError`           | `() => any`                            | -            | Error handler                 |
| `onCancel`          | `() => void`                           | -            | Cancel callback               |
| `onUnmount`         | `() => void`                           | -            | Unmount callback              |

## FormActions Props

| Prop           | Type          | Default     | Description          |
| -------------- | ------------- | ----------- | -------------------- |
| `loading`      | `boolean`     | -           | Loading state        |
| `disabled`     | `boolean`     | -           | Disabled state       |
| `onCancel`     | `() => void`  | -           | Cancel handler       |
| `onConfirm`    | `() => void`  | -           | Confirm handler      |
| `cancelText`   | `ReactNode`   | `'Cancel'`  | Cancel button text   |
| `confirmText`  | `ReactNode`   | `'Confirm'` | Confirm button text  |
| `cancelProps`  | `ButtonProps` | -           | Cancel button props  |
| `confirmProps` | `ButtonProps` | -           | Confirm button props |

## Form Field Components

| Component            | Description           |
| -------------------- | --------------------- |
| `FormTextInput`      | Text input field      |
| `FormPasswordInput`  | Password input field  |
| `FormNumberInput`    | Number input field    |
| `FormTextArea`       | Textarea field        |
| `FormSelect`         | Select dropdown       |
| `FormMultiSelect`    | Multi-select dropdown |
| `FormSwitch`         | Switch toggle         |
| `FormCheckbox`       | Checkbox field        |
| `FormRadioGroup`     | Radio button group    |
| `FormRating`         | Rating input          |
| `FormPhoneInput`     | Phone number input    |
| `FormProMultiSelect` | Enhanced multi-select |
| `FormDateTimePicker` | Date and time picker  |
| `FormCopyText`       | Copyable text field   |
| `FormSegmentControl` | Segmented control     |

--------------------------------------------------------------------------------

### LabelTooltip
Package: @tidbcloud/uikit/biz
Import: import { LabelTooltip } from '@tidbcloud/uikit/biz';
Description: An info icon with a hover card tooltip, commonly used for providing additional information next to form labels.

An info icon with a hover card tooltip, commonly used for providing additional information next to form labels.

## Basic Usage

```tsx

function Demo() {
  return (
    <Group gap="xs">
      <Text>Field Label</Text>
      <LabelTooltip>This is helpful information about the field.</LabelTooltip>
    </Group>
  )
}
```

## With Form Field

```tsx

function Demo() {
  return (
    <TextInput
      label={
        <Group gap={4}>
          Username
          <LabelTooltip>Your username must be unique and between 3-20 characters.</LabelTooltip>
        </Group>
      }
      placeholder="Enter username"
    />
  )
}
```

## Rich Content

```tsx

function Demo() {
  return (
    <LabelTooltip>
      <Stack gap="xs">
        <Text size="sm">Supported formats:</Text>
        <Code>JSON, CSV, XML</Code>
      </Stack>
    </LabelTooltip>
  )
}
```

## Custom HoverCard Props

```tsx

function Demo() {
  return (
    <LabelTooltip
      hoverCardProps={{
        position: 'right',
        width: 300,
        openDelay: 200
      }}
    >
      Detailed explanation that may need more space.
    </LabelTooltip>
  )
}
```

## Props

| Prop             | Type             | Default | Description               |
| ---------------- | ---------------- | ------- | ------------------------- |
| `children`       | `ReactNode`      | -       | Tooltip content           |
| `hoverCardProps` | `HoverCardProps` | -       | Props passed to HoverCard |

--------------------------------------------------------------------------------

### PageShell
Package: @tidbcloud/uikit/biz
Import: import { PageShell } from '@tidbcloud/uikit/biz';
Description: A page layout component with header, body, and optional wrapper sections. Supports back navigation and sticky header.

A page layout component with header, body, and optional wrapper sections. Supports back navigation and sticky header.

> **Note:** For new projects, consider using [AppPageShell](./AppShell) which provides a more modern API.

## Basic Usage

```tsx

function Demo() {
  return (
    <PageShell title="Page Title">
      <p>Page content goes here</p>
    </PageShell>
  )
}
```

## With Back Button

```tsx

function Demo() {
  return (
    <PageShell title="Details Page" showBack onBack={() => window.history.back()}>
      <p>Detail content</p>
    </PageShell>
  )
}
```

## Sticky Header

```tsx

function Demo() {
  return (
    <PageShell title="Long Page" stickyHeader>
      {/* Long scrollable content */}
    </PageShell>
  )
}
```

## With Right Section

```tsx

function Demo() {
  return (
    <PageShell
      title="Settings"
      rightSection={
        <Group>
          <Button variant="default">Cancel</Button>
          <Button>Save</Button>
        </Group>
      }
    >
      <p>Settings form here</p>
    </PageShell>
  )
}
```

## With Wrapper

```tsx

function Demo() {
  return (
    <PageShell title="Wrapped Page" withWrapper wrapperProps={{ maw: 800, mx: 'auto' }}>
      <p>Centered content with max width</p>
    </PageShell>
  )
}
```

## Props

| Prop           | Type         | Default | Description                   |
| -------------- | ------------ | ------- | ----------------------------- |
| `title`        | `ReactNode`  | -       | Page title                    |
| `children`     | `ReactNode`  | -       | Page content                  |
| `withWrapper`  | `boolean`    | `false` | Wrap content in div container |
| `wrapperProps` | `BoxProps`   | -       | Wrapper element props         |
| `stickyHeader` | `boolean`    | `false` | Make header sticky            |
| `rightSection` | `ReactNode`  | -       | Right section content         |
| `showBack`     | `boolean`    | -       | Show back button              |
| `onBack`       | `() => void` | -       | Back click handler            |
| `bodyProps`    | `BoxProps`   | -       | Body element props            |

---

# PageShellBase

A composable page shell system with individual components for building custom page layouts.

## Basic Usage

```tsx

function Demo() {
  return (
    <PageShellBase.Root>
      <PageShellBase.Header>
        <PageShellBase.Title>Custom Page</PageShellBase.Title>
      </PageShellBase.Header>
      <PageShellBase.Body>
        <p>Content here</p>
      </PageShellBase.Body>
    </PageShellBase.Root>
  )
}
```

## With Back Button

```tsx

function Demo() {
  return (
    <PageShellBase.Root>
      <PageShellBase.Header leftSection={<PageShellBase.BackButton />}>
        <PageShellBase.Title>Details</PageShellBase.Title>
      </PageShellBase.Header>
      <PageShellBase.Body>
        <p>Content</p>
      </PageShellBase.Body>
    </PageShellBase.Root>
  )
}
```

## Sub-components

| Component                  | Description            |
| -------------------------- | ---------------------- |
| `PageShellBase.Root`       | Root container         |
| `PageShellBase.Header`     | Header section         |
| `PageShellBase.Title`      | Title component        |
| `PageShellBase.Body`       | Body content area      |
| `PageShellBase.BackButton` | Back navigation button |

## PageShellBase.Header Props

| Prop           | Type        | Default | Description           |
| -------------- | ----------- | ------- | --------------------- |
| `sticky`       | `boolean`   | `false` | Sticky positioning    |
| `leftSection`  | `ReactNode` | -       | Left section content  |
| `rightSection` | `ReactNode` | -       | Right section content |

--------------------------------------------------------------------------------

### PhoneInput
Package: @tidbcloud/uikit/biz
Import: import { PhoneInput } from '@tidbcloud/uikit/biz';
Description: A phone number input with country code selector, built on react-phone-input-2.

A phone number input with country code selector, built on react-phone-input-2.

## Basic Usage

```tsx

function Demo() {
  const [phone, setPhone] = useState('')

  return <PhoneInput value={phone} onChange={setPhone} placeholder="Enter phone number" />
}
```

## With Default Country

```tsx

function Demo() {
  const [phone, setPhone] = useState('')

  return <PhoneInput value={phone} onChange={setPhone} country="us" placeholder="Enter phone number" />
}
```

## Validation

```tsx

function Demo() {
  const [phone, setPhone] = useState('')
  const [isValid, setIsValid] = useState(null)

  const handleValidate = () => {
    setIsValid(isValidPhoneNumber(phone))
  }

  return (
    <Stack>
      <PhoneInput value={phone} onChange={setPhone} />
      <Button onClick={handleValidate}>Validate</Button>
      {isValid !== null && (
        <Text c={isValid ? 'green' : 'red'}>{isValid ? 'Valid phone number' : 'Invalid phone number'}</Text>
      )}
    </Stack>
  )
}
```

## With Form

```tsx

function Demo() {
  return (
    <Form onSubmit={(data) => console.log(data)}>
      <FormPhoneInput name="phone" label="Phone Number" rules={{ required: 'Phone number is required' }} />
    </Form>
  )
}
```

## Props

| Prop                    | Type                      | Default | Description                         |
| ----------------------- | ------------------------- | ------- | ----------------------------------- |
| `value`                 | `string`                  | -       | Phone number value                  |
| `onChange`              | `(value: string) => void` | -       | Change handler                      |
| `placeholder`           | `string`                  | `''`    | Input placeholder                   |
| `country`               | `string`                  | `''`    | Default country code (e.g., 'us')   |
| `enableAreaCodeStretch` | `boolean`                 | -       | Show country code after first focus |
| `rootProps`             | `BoxProps`                | -       | Root container props                |
| `inputClass`            | `string`                  | -       | Input CSS class                     |
| `buttonClass`           | `string`                  | -       | Button CSS class                    |
| `containerClass`        | `string`                  | -       | Container CSS class                 |
| `dropdownClass`         | `string`                  | -       | Dropdown CSS class                  |
| `searchClass`           | `string`                  | -       | Search CSS class                    |
| `onFocus`               | `(e) => void`             | -       | Focus handler                       |

## Utilities

| Function             | Description                     |
| -------------------- | ------------------------------- |
| `isValidPhoneNumber` | Validates a phone number string |

--------------------------------------------------------------------------------

### ProMultiSelect
Package: @tidbcloud/uikit/biz
Import: import { ProMultiSelect } from '@tidbcloud/uikit/biz';
Description: An enhanced multi-select component with search, select all functionality, overflow handling, and pill-based selection display.

An enhanced multi-select component with search, select all functionality, overflow handling, and pill-based selection display.

## Basic Usage

```tsx

function Demo() {
  const [value, setValue] = useState([])

  return (
    <ProMultiSelect
      data={[
        { value: 'react', label: 'React' },
        { value: 'vue', label: 'Vue' },
        { value: 'angular', label: 'Angular' },
        { value: 'svelte', label: 'Svelte' }
      ]}
      value={value}
      onChange={setValue}
      placeholder="Select frameworks"
    />
  )
}
```

## With Search

```tsx

function Demo() {
  return <ProMultiSelect data={frameworks} searchable placeholder="Search and select" />
}
```

## With Select All

```tsx

function Demo() {
  return (
    <ProMultiSelect
      data={frameworks}
      showSelectAll
      selectAllLabel="Select All Frameworks"
      placeholder="Select frameworks"
    />
  )
}
```

## With Max Values

```tsx

function Demo() {
  return <ProMultiSelect data={frameworks} maxValues={3} placeholder="Select up to 3" />
}
```

## Clearable

```tsx

function Demo() {
  return <ProMultiSelect data={frameworks} clearable placeholder="Select frameworks" />
}
```

## With Label and Error

```tsx

function Demo() {
  return (
    <ProMultiSelect
      data={frameworks}
      label="Frameworks"
      error="Please select at least one framework"
      placeholder="Select frameworks"
    />
  )
}
```

## Custom Max Options Display

```tsx

function Demo() {
  return <ProMultiSelect data={frameworks} maxDisplayOptions={2} placeholder="Select frameworks" />
}
```

## With Form

```tsx

function Demo() {
  return (
    <Form onSubmit={(data) => console.log(data)}>
      <FormProMultiSelect
        name="frameworks"
        label="Frameworks"
        data={frameworks}
        rules={{ required: 'Please select at least one framework' }}
      />
    </Form>
  )
}
```

## Props

| Prop                 | Type                                 | Default  | Description                  |
| -------------------- | ------------------------------------ | -------- | ---------------------------- |
| `data`               | `ComboboxData`                       | -        | Select options               |
| `value`              | `string[]`                           | -        | Selected values              |
| `defaultValue`       | `string[]`                           | -        | Default selected values      |
| `onChange`           | `(value: string[]) => void`          | -        | Change handler               |
| `maxDisplayOptions`  | `number`                             | -        | Max options to show in input |
| `searchable`         | `boolean`                            | -        | Enable search                |
| `searchValue`        | `string`                             | -        | Controlled search value      |
| `defaultSearchValue` | `string`                             | -        | Default search value         |
| `onSearchChange`     | `(value: string) => void`            | -        | Search change handler        |
| `maxValues`          | `number`                             | Infinity | Max selections allowed       |
| `readOnly`           | `boolean`                            | -        | Read-only mode               |
| `disabled`           | `boolean`                            | -        | Disabled state               |
| `size`               | `MantineSize`                        | -        | Component size               |
| `w`                  | `number \| string`                   | -        | Component width              |
| `placeholder`        | `string`                             | -        | Input placeholder            |
| `clearable`          | `boolean`                            | -        | Allow clearing               |
| `label`              | `ReactNode`                          | -        | Input label                  |
| `emptyText`          | `string`                             | -        | Empty state message          |
| `dropdownOpened`     | `boolean`                            | -        | Controlled dropdown state    |
| `maxDropdownHeight`  | `number`                             | `200`    | Max dropdown height          |
| `error`              | `ReactNode`                          | -        | Error message                |
| `loading`            | `boolean`                            | -        | Loading state                |
| `showSelectAll`      | `boolean`                            | -        | Show select all option       |
| `selectAllLabel`     | `string`                             | `'All'`  | Select all label             |
| `onSubmit`           | `(options: ComboboxItem[]) => void`  | -        | Option submit handler        |
| `renderOption`       | `(option) => ReactNode`              | -        | Custom option renderer       |
| `filter`             | `(value, options) => ComboboxItem[]` | -        | Custom filter function       |
| `onClear`            | `() => void`                         | -        | Clear handler                |

--------------------------------------------------------------------------------

### PropertyCard
Package: @tidbcloud/uikit/biz
Import: import { PropertyCard } from '@tidbcloud/uikit/biz';
Description: A card component for displaying key-value property lists with consistent styling.

A card component for displaying key-value property lists with consistent styling.

## Basic Usage

```tsx

function Demo() {
  return (
    <PropertyCard title="User Information">
      <PropertyCard.Item label="Name">John Doe</PropertyCard.Item>
      <PropertyCard.Item label="Email">john@example.com</PropertyCard.Item>
      <PropertyCard.Item label="Role">Administrator</PropertyCard.Item>
    </PropertyCard>
  )
}
```

## With Divider

```tsx

function Demo() {
  return (
    <PropertyCard title="Server Details">
      <PropertyCard.Item label="Host">192.168.1.1</PropertyCard.Item>
      <PropertyCard.Item label="Port">3306</PropertyCard.Item>
      <PropertyCard.Divider />
      <PropertyCard.Item label="Status">Running</PropertyCard.Item>
      <PropertyCard.Item label="Uptime">7 days</PropertyCard.Item>
    </PropertyCard>
  )
}
```

## Custom Value Rendering

```tsx

function Demo() {
  return (
    <PropertyCard title="Connection">
      <PropertyCard.Item label="Status">
        <Badge color="green">Connected</Badge>
      </PropertyCard.Item>
      <PropertyCard.Item label="Connection String">
        <Group gap="xs">
          <code>mysql://user:***@host:3306/db</code>
          <CopyButton value="mysql://user:pass@host:3306/db">
            {({ copy }) => (
              <ActionIcon variant="subtle" onClick={copy}>
                <IconCopy size={14} />
              </ActionIcon>
            )}
          </CopyButton>
        </Group>
      </PropertyCard.Item>
    </PropertyCard>
  )
}
```

## Custom Label/Value Props

```tsx

function Demo() {
  return (
    <PropertyCard title="Settings" labelProps={{ w: 150, fw: 600 }} valueProps={{ c: 'dimmed' }}>
      <PropertyCard.Item label="Theme">Dark</PropertyCard.Item>
      <PropertyCard.Item label="Language">English</PropertyCard.Item>
    </PropertyCard>
  )
}
```

## Override Props Per Item

```tsx

function Demo() {
  return (
    <PropertyCard title="Details">
      <PropertyCard.Item label="Normal">Value</PropertyCard.Item>
      <PropertyCard.Item label="Important" labelProps={{ c: 'red', fw: 700 }} valueProps={{ c: 'red' }}>
        Critical Value
      </PropertyCard.Item>
    </PropertyCard>
  )
}
```

## Without Title

```tsx

function Demo() {
  return (
    <PropertyCard>
      <PropertyCard.Item label="Key">Value</PropertyCard.Item>
      <PropertyCard.Item label="Another Key">Another Value</PropertyCard.Item>
    </PropertyCard>
  )
}
```

## Props

### PropertyCard

| Prop         | Type        | Default | Description                |
| ------------ | ----------- | ------- | -------------------------- |
| `title`      | `string`    | -       | Card title                 |
| `labelProps` | `TextProps` | -       | Props for all labels       |
| `valueProps` | `TextProps` | -       | Props for all values       |
| `children`   | `ReactNode` | -       | PropertyCard.Item children |

PropertyCard also accepts all Card component props.

### PropertyCard.Item

| Prop         | Type        | Default | Description          |
| ------------ | ----------- | ------- | -------------------- |
| `label`      | `string`    | -       | Property label       |
| `labelProps` | `TextProps` | -       | Override label props |
| `valueProps` | `TextProps` | -       | Override value props |
| `children`   | `ReactNode` | -       | Property value       |

## Sub-components

| Component              | Description             |
| ---------------------- | ----------------------- |
| `PropertyCard.Item`    | Individual property row |
| `PropertyCard.Divider` | Divider between items   |

--------------------------------------------------------------------------------

### SearchArea
Package: @tidbcloud/uikit/biz
Import: import { SearchArea } from '@tidbcloud/uikit/biz';
Description: A form-based search area with multiple filter types, URL state persistence, debounced text input, and clear/refresh functionality.

A form-based search area with multiple filter types, URL state persistence, debounced text input, and clear/refresh functionality.

## Basic Usage

```tsx

function Demo() {
  const filters = [
    {
      type: 'text',
      name: 'search',
      placeholder: 'Search...'
    },
    {
      type: 'select',
      name: 'status',
      label: 'Status',
      data: ['Active', 'Inactive', 'Pending']
    }
  ]

  return <SearchArea filters={filters} onSubmit={(values) => console.log(values)} />
}
```

## Multiple Filter Types

```tsx

function Demo() {
  const filters = [
    {
      type: 'text',
      name: 'keyword',
      placeholder: 'Search by keyword'
    },
    {
      type: 'select',
      name: 'category',
      label: 'Category',
      data: ['All', 'Electronics', 'Clothing', 'Books']
    },
    {
      type: 'multiselect',
      name: 'tags',
      label: 'Tags',
      data: ['Featured', 'Sale', 'New', 'Popular']
    },
    {
      type: 'datepicker',
      name: 'date',
      label: 'Date'
    }
  ]

  return (
    <SearchArea filters={filters} onSubmit={(values) => console.log(values)} onRefresh={() => console.log('refresh')} />
  )
}
```

## With URL Persistence

```tsx

function Demo() {
  const filters = [
    { type: 'text', name: 'q', placeholder: 'Search...' },
    { type: 'select', name: 'sort', data: ['Newest', 'Oldest', 'Popular'] }
  ]

  return <SearchArea filters={filters} persistUrl urlStateKey="filters" onSubmit={(values) => console.log(values)} />
}
```

## With Default Values

```tsx

function Demo() {
  const filters = [
    { type: 'text', name: 'search', placeholder: 'Search...' },
    { type: 'select', name: 'status', data: ['All', 'Active', 'Inactive'] }
  ]

  return (
    <SearchArea filters={filters} defaultValues={{ status: 'Active' }} onSubmit={(values) => console.log(values)} />
  )
}
```

## Time Range Picker

```tsx

function Demo() {
  const filters = [
    { type: 'text', name: 'search', placeholder: 'Search...' },
    {
      type: 'timerangepicker',
      name: 'timeRange',
      label: 'Time Range'
    }
  ]

  return <SearchArea filters={filters} onSubmit={(values) => console.log(values)} />
}
```

## Props

| Prop            | Type               | Default           | Description                 |
| --------------- | ------------------ | ----------------- | --------------------------- |
| `filters`       | `FormItem[]`       | -                 | Array of filter definitions |
| `persistUrl`    | `boolean`          | -                 | Persist state in URL        |
| `debug`         | `boolean`          | -                 | Enable debug mode           |
| `urlStateKey`   | `string`           | `'__fs'`          | URL query key for state     |
| `clearText`     | `string`           | `'Clear Filters'` | Clear button text           |
| `onSubmit`      | `(values) => void` | -                 | Submit handler              |
| `onRefresh`     | `() => void`       | -                 | Refresh handler             |
| `defaultValues` | `object`           | -                 | Default filter values       |
| `formProps`     | `FormProps`        | -                 | Additional Form props       |

## Filter Types

| Type              | Description                      |
| ----------------- | -------------------------------- |
| `text`            | Text input with debounced search |
| `select`          | Single select dropdown           |
| `multiselect`     | Multi-select dropdown            |
| `datepicker`      | Date picker                      |
| `timerangepicker` | Time range picker                |

--------------------------------------------------------------------------------

### TableBasic
Package: @tidbcloud/uikit/biz
Import: import { TableBasic } from '@tidbcloud/uikit/biz';
Description: A simple table component for displaying tabular data. For advanced features like sorting, pagination, and virtual scrolling, see [ProTable](./TablePro).

A simple table component for displaying tabular data. For advanced features like sorting, pagination, and virtual scrolling, see [ProTable](./TablePro).

## Basic Usage

```tsx

const data = [
  { id: 1, name: 'John', email: 'john@example.com' },
  { id: 2, name: 'Jane', email: 'jane@example.com' },
  { id: 3, name: 'Bob', email: 'bob@example.com' }
]

const columns = [
  { accessorKey: 'id', header: 'ID' },
  { accessorKey: 'name', header: 'Name' },
  { accessorKey: 'email', header: 'Email' }
]

function Demo() {
  return <BasicTable data={data} columns={columns} />
}
```

## With Custom Cell Rendering

```tsx

const columns = [
  { accessorKey: 'name', header: 'Name' },
  {
    accessorKey: 'status',
    header: 'Status',
    Cell: ({ cell }) => <Badge color={cell.getValue() === 'Active' ? 'green' : 'gray'}>{cell.getValue()}</Badge>
  }
]

function Demo() {
  return <BasicTable data={data} columns={columns} />
}
```

## Empty State

```tsx

function Demo() {
  return <BasicTable data={[]} columns={columns} emptyText="No data available" />
}
```

## Loading State

```tsx

function Demo() {
  return <BasicTable data={[]} columns={columns} loading />
}
```

## Without Border

```tsx

function Demo() {
  return <BasicTable data={data} columns={columns} withBorder={false} />
}
```

## Props

| Prop           | Type       | Default | Description           |
| -------------- | ---------- | ------- | --------------------- |
| `data`         | `T[]`      | -       | Table data            |
| `columns`      | `Column[]` | -       | Column definitions    |
| `withBorder`   | `boolean`  | `true`  | Show table border     |
| `emptyText`    | `string`   | -       | Empty state message   |
| `errorText`    | `string`   | -       | Error state message   |
| `loading`      | `boolean`  | `false` | Loading state         |
| `wrapperProps` | `BoxProps` | -       | Wrapper element props |

BasicTable is built on mantine-react-table and supports all its options.

--------------------------------------------------------------------------------

### TablePro
Package: @tidbcloud/uikit/biz
Import: import { TablePro } from '@tidbcloud/uikit/biz';
Description: An advanced data table built on [Mantine React Table](https://v2.mantine-react-table.com/) with customized styling, pagination, sorting, and expansion support.

An advanced data table built on [Mantine React Table](https://v2.mantine-react-table.com/) with customized styling, pagination, sorting, and expansion support.

## Basic Usage

```tsx

const data = [
  { id: 1, name: 'John', email: 'john@example.com', status: 'Active' },
  { id: 2, name: 'Jane', email: 'jane@example.com', status: 'Inactive' }
]

const columns = [
  { accessorKey: 'id', header: 'ID' },
  { accessorKey: 'name', header: 'Name' },
  { accessorKey: 'email', header: 'Email' },
  { accessorKey: 'status', header: 'Status' }
]

function Demo() {
  const table = useProTable({ data, columns })
  return <ProTable table={table} />
}
```

## With Pagination

### Client-side Pagination

```tsx

function Demo() {
  const table = useProTable({
    data,
    columns,
    enablePagination: true
  })

  return <ProTable table={table} />
}
```

### Server-side Pagination

```tsx

function Demo() {
  const [pagination, setPagination] = useState({
    pageIndex: 0,
    pageSize: 10
  })

  const table = useProTable({
    data,
    columns,
    manualPagination: true,
    onPaginationChange: setPagination,
    rowCount: totalCount, // Total rows from server
    enablePagination: true,
    state: { pagination }
  })

  return <ProTable table={table} />
}
```

### Pagination UI Options

```tsx
const table = useProTable({
  data,
  columns,
  enablePagination: true,
  pagination: {
    rowsPerPageOptions: ['10', '20', '50', '100'],
    showRowsPerPage: true,
    showTotal: true,
    localization: {
      total: 'Total:'
    }
  }
})
```

## With Sorting

```tsx

function Demo() {
  const table = useProTable({
    data,
    columns,
    enableSorting: true
  })

  return <ProTable table={table} />
}
```

## With Row Expansion

```tsx

function Demo() {
  const table = useProTable({
    data,
    columns,
    enableExpanding: true,
    renderDetailPanel: ({ row }) => <div>Details for {row.original.name}</div>
  })

  return <ProTable table={table} />
}
```

## With Virtual Scrolling

```tsx

function Demo() {
  const table = useProTable({
    data: largeDataset,
    columns,
    enableRowVirtualization: true
  })

  return <ProTable table={table} />
}
```

## Sticky Header

```tsx

function Demo() {
  const table = useProTable({
    data,
    columns,
    enableStickyHeader: true
  })

  return <ProTable table={table} />
}
```

## Loading State

```tsx

function Demo() {
  const table = useProTable({
    data: [],
    columns,
    loading: true
  })

  return <ProTable table={table} />
}
```

## Props

| Prop                      | Type                | Default | Description                     |
| ------------------------- | ------------------- | ------- | ------------------------------- |
| `table`                   | `MRT_TableInstance` | -       | Table instance from useProTable |
| `data`                    | `T[]`               | -       | Table data                      |
| `columns`                 | `MRT_ColumnDef[]`   | -       | Column definitions              |
| `withBorder`              | `boolean`           | `true`  | Show table border               |
| `emptyText`               | `string`            | -       | Empty state message             |
| `errorText`               | `string`            | -       | Error state message             |
| `loading`                 | `boolean`           | `false` | Loading state                   |
| `enablePagination`        | `boolean`           | `false` | Enable pagination               |
| `enableSorting`           | `boolean`           | `false` | Enable sorting                  |
| `enableExpanding`         | `boolean`           | `false` | Enable row expansion            |
| `enableStickyHeader`      | `boolean`           | -       | Sticky header                   |
| `enableStickyFooter`      | `boolean`           | -       | Sticky footer                   |
| `enableRowVirtualization` | `boolean`           | `false` | Virtual scrolling               |
| `pagination`              | `PaginationConfig`  | -       | Pagination configuration        |
| `wrapperProps`            | `BoxProps`          | -       | Wrapper props                   |

## Pagination Config

| Prop                 | Type        | Default                                     | Description             |
| -------------------- | ----------- | ------------------------------------------- | ----------------------- |
| `rowsPerPageOptions` | `string[]`  | `['5','10','15','20','25','30','50','100']` | Page size options       |
| `showRowsPerPage`    | `boolean`   | `false`                                     | Show page size selector |
| `showTotal`          | `boolean`   | `false`                                     | Show total count        |
| `wrapperProps`       | `FlexProps` | -                                           | Wrapper props           |
| `localization.total` | `string`    | `'Total:'`                                  | Total label text        |

## Exports

| Export            | Description                      |
| ----------------- | -------------------------------- |
| `ProTable`        | Main table component             |
| `useProTable`     | Hook for creating table instance |
| `TablePagination` | Standalone pagination component  |

ProTable supports all [Mantine React Table](https://v2.mantine-react-table.com/) options.

--------------------------------------------------------------------------------

### TimeRangePicker
Package: @tidbcloud/uikit/biz
Import: import { TimeRangePicker } from '@tidbcloud/uikit/biz';
Description: A time range picker supporting both relative (e.g., "Last 15 minutes") and absolute time ranges with a customizable quick selection menu.

A time range picker supporting both relative (e.g., "Last 15 minutes") and absolute time ranges with a customizable quick selection menu.

## Basic Usage

```tsx

function Demo() {
  const [range, setRange] = useState(null)

  return <TimeRangePicker value={range} onChange={setRange} />
}
```

## With Default Relative Range

```tsx

function Demo() {
  const [range, setRange] = useState({
    type: 'relative',
    duration: 3600 // 1 hour in seconds
  })

  return <TimeRangePicker value={range} onChange={setRange} />
}
```

## Absolute Time Range

```tsx

function Demo() {
  const [range, setRange] = useState({
    type: 'absolute',
    start: new Date('2024-01-01T00:00:00'),
    end: new Date('2024-01-31T23:59:59')
  })

  return <TimeRangePicker value={range} onChange={setRange} />
}
```

## Custom Quick Options

```tsx

function Demo() {
  const [range, setRange] = useState(null)

  const quickOptions = [
    { label: 'Last 5 minutes', value: 300 },
    { label: 'Last 15 minutes', value: 900 },
    { label: 'Last 1 hour', value: 3600 },
    { label: 'Last 24 hours', value: 86400 },
    { label: 'Last 7 days', value: 604800 }
  ]

  return <TimeRangePicker value={range} onChange={setRange} quickOptions={quickOptions} />
}
```

## With Max Duration

```tsx

function Demo() {
  const [range, setRange] = useState(null)

  return (
    <TimeRangePicker
      value={range}
      onChange={setRange}
      maxDuration={86400 * 30} // Max 30 days
    />
  )
}
```

## Clearable

```tsx

function Demo() {
  const [range, setRange] = useState(null)

  return <TimeRangePicker value={range} onChange={setRange} clearable />
}
```

## Hide Custom Picker

```tsx

function Demo() {
  const [range, setRange] = useState(null)

  return <TimeRangePicker value={range} onChange={setRange} hideCustomPicker />
}
```

## Props

| Prop               | Type                                   | Default        | Description             |
| ------------------ | -------------------------------------- | -------------- | ----------------------- |
| `value`            | `TimeRange`                            | -              | Selected time range     |
| `onChange`         | `(range: TimeRange) => void`           | -              | Change handler          |
| `loading`          | `boolean`                              | -              | Loading state           |
| `placeholder`      | `string`                               | `'Time Range'` | Button placeholder      |
| `badgePlaceholder` | `string`                               | `'All'`        | Badge placeholder       |
| `clearable`        | `boolean`                              | `false`        | Allow clearing          |
| `formatRelative`   | `(range: RelativeTimeRange) => string` | -              | Custom relative format  |
| `formatAbsolute`   | `(range: AbsoluteTimeRange) => string` | -              | Custom absolute format  |
| `dropdownFooter`   | `ReactNode`                            | -              | Dropdown footer content |
| `minDateTime`      | `Date`                                 | -              | Minimum date/time       |
| `maxDateTime`      | `Date`                                 | -              | Maximum date/time       |
| `maxDuration`      | `number`                               | -              | Max duration in seconds |
| `quickOptions`     | `QuickOption[]`                        | (default list) | Quick selection options |
| `hideCustomPicker` | `boolean`                              | `false`        | Hide custom picker      |
| `timezoneOffset`   | `number`                               | -              | Timezone offset         |
| `datePickerProps`  | `DatePickerProps`                      | -              | Date picker props       |
| `sx`               | `Sx`                                   | -              | Style props             |

## TimeRange Types

```tsx
type RelativeTimeRange = {
  type: 'relative'
  duration: number // seconds
}

type AbsoluteTimeRange = {
  type: 'absolute'
  start: Date
  end: Date
}

type TimeRange = RelativeTimeRange | AbsoluteTimeRange
```

--------------------------------------------------------------------------------

### TransferTree
Package: @tidbcloud/uikit/biz
Import: import { TransferTree } from '@tidbcloud/uikit/biz';
Description: A dual-panel transfer component with tree structures on both sides, allowing users to move items between source and target trees.

A dual-panel transfer component with tree structures on both sides, allowing users to move items between source and target trees.

## Basic Usage

```tsx

function Demo() {
  const [data, setData] = useState([
    {
      key: '1',
      title: 'Node 1',
      children: [
        { key: '1-1', title: 'Child 1-1' },
        { key: '1-2', title: 'Child 1-2' }
      ]
    },
    {
      key: '2',
      title: 'Node 2',
      children: [{ key: '2-1', title: 'Child 2-1' }]
    }
  ])

  return <TransferTree data={data} onChange={(newData) => setData(newData)} />
}
```

## With Custom Headers

```tsx

function Demo() {
  return (
    <TransferTree
      data={treeData}
      sourceHeader="Available Items"
      targetHeader="Selected Items"
      onChange={(newData) => console.log(newData)}
    />
  )
}
```

## With Initial Selection

```tsx

function Demo() {
  return (
    <TransferTree data={treeData} defaultTargetKeys={['1-1', '2-1']} onChange={(newData) => console.log(newData)} />
  )
}
```

## With Callbacks

```tsx

function Demo() {
  return (
    <TransferTree
      data={treeData}
      onChange={(newData) => console.log('Data changed:', newData)}
      onLeftCheck={(keys) => console.log('Left checked:', keys)}
      onRightCheck={(keys) => console.log('Right checked:', keys)}
      onMoveRight={() => console.log('Moved to right')}
      onMoveLeft={() => console.log('Moved to left')}
    />
  )
}
```

## Props

| Prop                | Type                         | Default    | Description              |
| ------------------- | ---------------------------- | ---------- | ------------------------ |
| `sourceHeader`      | `ReactNode`                  | `'Source'` | Source panel header      |
| `targetHeader`      | `ReactNode`                  | `'Target'` | Target panel header      |
| `data`              | `TreeNode[]`                 | -          | Tree data                |
| `onChange`          | `(data: TreeNode[]) => void` | -          | Change handler           |
| `onLeftCheck`       | `(keys: string[]) => void`   | -          | Left tree check handler  |
| `onRightCheck`      | `(keys: string[]) => void`   | -          | Right tree check handler |
| `onMoveRight`       | `() => void`                 | -          | Move right callback      |
| `onMoveLeft`        | `() => void`                 | -          | Move left callback       |
| `className`         | `string`                     | -          | Container class          |
| `treeProps`         | `TreeProps`                  | -          | Props for both trees     |
| `defaultTargetKeys` | `string[]`                   | -          | Initially selected keys  |

## TreeNode Type

```tsx
interface TreeNode {
  key: string
  title: string
  children?: TreeNode[]
  disabled?: boolean
}
```

--------------------------------------------------------------------------------

### Tree
Package: @tidbcloud/uikit/biz
Import: import { Tree } from '@tidbcloud/uikit/biz';
Description: A tree view component built on rc-tree with custom styling, checkboxes, and collapsible nodes.

A tree view component built on rc-tree with custom styling, checkboxes, and collapsible nodes.

## Basic Usage

```tsx

const treeData = [
  {
    key: '1',
    title: 'Parent 1',
    children: [
      { key: '1-1', title: 'Child 1-1' },
      { key: '1-2', title: 'Child 1-2' }
    ]
  },
  {
    key: '2',
    title: 'Parent 2',
    children: [{ key: '2-1', title: 'Child 2-1' }]
  }
]

function Demo() {
  return <Tree treeData={treeData} />
}
```

## With Checkboxes

```tsx

function Demo() {
  const [checkedKeys, setCheckedKeys] = useState([])

  return <Tree treeData={treeData} checkable checkedKeys={checkedKeys} onCheck={(keys) => setCheckedKeys(keys)} />
}
```

## With Lines

```tsx

function Demo() {
  return <Tree treeData={treeData} showLine />
}
```

## Default Expanded

```tsx

function Demo() {
  return <Tree treeData={treeData} defaultExpandAll />
}
```

## Controlled Expansion

```tsx

function Demo() {
  const [expandedKeys, setExpandedKeys] = useState(['1'])

  return <Tree treeData={treeData} expandedKeys={expandedKeys} onExpand={(keys) => setExpandedKeys(keys)} />
}
```

## With Icons

```tsx

const treeData = [
  {
    key: '1',
    title: 'Documents',
    icon: <IconFolder size={16} />,
    children: [
      { key: '1-1', title: 'file1.txt', icon: <IconFile size={16} /> },
      { key: '1-2', title: 'file2.txt', icon: <IconFile size={16} /> }
    ]
  }
]

function Demo() {
  return <Tree treeData={treeData} showIcon />
}
```

## Disabled Nodes

```tsx

const treeData = [
  {
    key: '1',
    title: 'Parent 1',
    children: [
      { key: '1-1', title: 'Child 1-1', disabled: true },
      { key: '1-2', title: 'Child 1-2' }
    ]
  }
]

function Demo() {
  return <Tree treeData={treeData} checkable />
}
```

## Props

| Prop                  | Type                                   | Default | Description              |
| --------------------- | -------------------------------------- | ------- | ------------------------ |
| `treeData`            | `TreeNode[]`                           | -       | Tree data nodes          |
| `showLine`            | `boolean \| { showLeafIcon: boolean }` | -       | Show connecting lines    |
| `className`           | `string`                               | -       | Container class          |
| `multiple`            | `boolean`                              | -       | Multi-select support     |
| `autoExpandParent`    | `boolean`                              | -       | Auto expand parents      |
| `checkable`           | `boolean`                              | `false` | Show checkboxes          |
| `disabled`            | `boolean`                              | -       | Disable entire tree      |
| `defaultExpandAll`    | `boolean`                              | -       | Expand all by default    |
| `defaultExpandParent` | `boolean`                              | -       | Expand parent by default |
| `defaultExpandedKeys` | `string[]`                             | -       | Default expanded keys    |
| `expandedKeys`        | `string[]`                             | -       | Controlled expanded keys |
| `checkedKeys`         | `string[]`                             | -       | Controlled checked keys  |
| `defaultCheckedKeys`  | `string[]`                             | -       | Default checked keys     |
| `selectedKeys`        | `string[]`                             | -       | Controlled selected keys |
| `defaultSelectedKeys` | `string[]`                             | -       | Default selected keys    |
| `selectable`          | `boolean`                              | `true`  | Enable selection         |
| `showIcon`            | `boolean`                              | `false` | Show node icons          |
| `blockNode`           | `boolean`                              | `false` | Full-width nodes         |
| `switcherIcon`        | `ReactNode \| (props) => ReactNode`    | -       | Custom expand icon       |
| `onCheck`             | `(keys, info) => void`                 | -       | Check handler            |
| `onSelect`            | `(keys, info) => void`                 | -       | Select handler           |
| `onExpand`            | `(keys, info) => void`                 | -       | Expand handler           |

## TreeNode Type

```tsx
interface TreeNode {
  key: string
  title: ReactNode
  children?: TreeNode[]
  disabled?: boolean
  disableCheckbox?: boolean
  selectable?: boolean
  checkable?: boolean
  icon?: ReactNode
  isLeaf?: boolean
}
```

--------------------------------------------------------------------------------

### Typography
Package: @tidbcloud/uikit/biz
Import: import { Typography } from '@tidbcloud/uikit/biz';
Description: Typography is now documented in the primitive components section.

Typography is now documented in the primitive components section.

See [Typography (Primitive)](/docs/primitive/Typography) for full documentation.

--------------------------------------------------------------------------------


## HOOKS
React hooks from @tidbcloud/uikit
Primary Package: @tidbcloud/uikit

--------------------------------------------------------------------------------

### useClickOutside
Package: @tidbcloud/uikit
Import: import { useClickOutside } from '@tidbcloud/uikit';
Description: Detect clicks outside of an element.

Detect clicks outside of an element.

## Usage

`useClickOutside` hook accepts a callback function that is called when user clicks outside of the element.

```tsx

function Demo() {
  const [opened, setOpened] = useState(false)
  const ref = useClickOutside(() => setOpened(false))

  return (
    <>
      <Button onClick={() => setOpened(true)}>Open dropdown</Button>

      {opened && (
        <Paper ref={ref} shadow="sm" p="xl">
          Click outside to close
        </Paper>
      )}
    </>
  )
}
```

## API

The hook accepts 3 arguments:

- `handler` – function that is called on outside click
- `events` – optional list of events that trigger outside click, `['mousedown', 'touchstart']` by default
- `nodes` – optional list of nodes that should not trigger outside click event

The hook returns a `ref` object that must be passed to the element based on which outside clicks should be captured.

## Change Events

By default, `useClickOutside` listens to `mousedown` and `touchstart` events. You can change these events by passing an array of events as second argument:

```tsx

function Demo() {
  const ref = useClickOutside(() => console.log('Outside click'), ['mouseup', 'touchend'])
  return <div ref={ref}>Click outside</div>
}
```

## Multiple Nodes

```tsx

function Demo() {
  const [dropdown, setDropdown] = useState<HTMLDivElement | null>(null)
  const [control, setControl] = useState<HTMLDivElement | null>(null)

  useClickOutside(() => console.log('outside'), null, [control, dropdown])

  return (
    <div>
      <div ref={setControl}>Control</div>
      <Portal>
        <div ref={setDropdown}>Dropdown</div>
      </Portal>
    </div>
  )
}
```

## TypeScript

Set ref type:

```tsx

const ref = useClickOutside<HTMLDivElement>(() => console.log('Click outside'))
```

## Definition

```tsx
function useClickOutside<T extends HTMLElement = any>(
  handler: () => void,
  events?: string[] | null,
  nodes?: HTMLElement[]
): React.RefObject<T>
```

--------------------------------------------------------------------------------

### useClipboard
Package: @tidbcloud/uikit
Import: import { useClipboard } from '@tidbcloud/uikit';
Description: Copy text to clipboard with fallback support.

Copy text to clipboard with fallback support.

## Usage

`useClipboard` provides a `copy` function to copy text to the clipboard and a `copied` state that indicates if the text has been copied recently.

```tsx

function Demo() {
  const clipboard = useClipboard({ timeout: 500 })

  return (
    <Group>
      <TextInput value="https://example.com" readOnly />
      <Button color={clipboard.copied ? 'teal' : 'blue'} onClick={() => clipboard.copy('https://example.com')}>
        {clipboard.copied ? 'Copied' : 'Copy'}
      </Button>
    </Group>
  )
}
```

## Timeout

The `copied` value is `true` for a short period after calling `copy`. By default, the timeout is 2000ms. You can change it with the `timeout` option:

```tsx

const clipboard = useClipboard({ timeout: 1000 }) // 1 second
```

## Fallback Support

This hook includes a fallback for non-secure contexts (e.g., `http://` or when `navigator.clipboard` is unavailable). The fallback uses `document.execCommand('copy')` which works in older browsers and non-HTTPS environments.

## API

- `copy(text)` – copy text to clipboard
- `reset()` – reset `copied` value
- `error` – error if copying failed
- `copied` – `true` if text was recently copied

## Definition

```tsx
interface UseClipboardOptions {
  timeout?: number
}

interface UseClipboardReturnValue {
  copy: (valueToCopy: string) => void
  reset: () => void
  error: Error | null
  copied: boolean
}

function useClipboard(options?: UseClipboardOptions): UseClipboardReturnValue
```

--------------------------------------------------------------------------------

### useCounter
Package: @tidbcloud/uikit
Import: import { useCounter } from '@tidbcloud/uikit';
Description: Manage numeric counter state with increment, decrement, set, and reset handlers.

Manage numeric counter state with increment, decrement, set, and reset handlers.

## Usage

```tsx

function Demo() {
  const [count, handlers] = useCounter(0, { min: 0, max: 10 })

  return (
    <>
      <Text>Count: {count}</Text>
      <Group>
        <Button onClick={handlers.increment}>Increment</Button>
        <Button onClick={handlers.decrement}>Decrement</Button>
        <Button onClick={() => handlers.set(5)}>Set 5</Button>
        <Button onClick={handlers.reset}>Reset</Button>
      </Group>
    </>
  )
}
```

## Options

- `min` – minimum value (will not go below)
- `max` – maximum value (will not go above)

## Definition

```tsx
interface UseCounterOptions {
  min?: number
  max?: number
}

interface UseCounterHandlers {
  increment: () => void
  decrement: () => void
  set: (value: number) => void
  reset: () => void
}

type UseCounterReturnValue = [number, UseCounterHandlers]

function useCounter(initialValue?: number, options?: UseCounterOptions): UseCounterReturnValue
```

--------------------------------------------------------------------------------

### useDebouncedCallback
Package: @tidbcloud/uikit
Import: import { useDebouncedCallback } from '@tidbcloud/uikit';
Description: Create a debounced version of a callback function.

Create a debounced version of a callback function.

## Usage

`useDebouncedCallback` creates a debounced version of the given function, delaying its execution until a specified time has elapsed since the last invocation.

```tsx

function Demo() {
  const [value, setValue] = useState('')
  const [debouncedValue, setDebouncedValue] = useState('')

  const handleChange = useDebouncedCallback((val: string) => {
    setDebouncedValue(val)
  }, 500)

  return (
    <>
      <TextInput
        value={value}
        onChange={(e) => {
          setValue(e.currentTarget.value)
          handleChange(e.currentTarget.value)
        }}
        placeholder="Type something..."
      />
      <Text mt="md">Debounced value: {debouncedValue}</Text>
    </>
  )
}
```

## Flush on Unmount

By default, the callback is not fired when the component unmounts. Set `flushOnUnmount: true` to execute the pending callback:

```tsx

const callback = useDebouncedCallback(() => console.log('Hello'), { delay: 1000, flushOnUnmount: true })
```

## Flush Manually

Call the `flush` method to execute the debounced callback immediately:

```tsx

const callback = useDebouncedCallback(() => console.log('Hello'), 1000)

callback.flush() // Immediately executes the pending callback
```

## Definition

```tsx
interface UseDebouncedCallbackOptions {
  delay: number
  flushOnUnmount?: boolean
}

type UseDebouncedCallbackReturnValue<T extends (...args: any[]) => any> = ((...args: Parameters<T>) => void) & {
  flush: () => void
}

function useDebouncedCallback<T extends (...args: any[]) => any>(
  callback: T,
  delayOrOptions: number | UseDebouncedCallbackOptions
): UseDebouncedCallbackReturnValue<T>
```

--------------------------------------------------------------------------------

### useDebouncedState
Package: @tidbcloud/uikit
Import: import { useDebouncedState } from '@tidbcloud/uikit';
Description: Debounce state updates for uncontrolled components.

Debounce state updates for uncontrolled components.

## Usage

`useDebouncedState` hook debounces value changes. It is designed to work with uncontrolled components.

```tsx

function Demo() {
  const [value, setValue] = useDebouncedState('', 500)

  return (
    <>
      <TextInput
        defaultValue={value}
        onChange={(e) => setValue(e.currentTarget.value)}
        placeholder="Type something..."
      />
      <Text mt="md">Debounced value: {value}</Text>
    </>
  )
}
```

## Differences from useDebouncedValue

- You do not have direct access to the non-debounced value
- It is used for uncontrolled inputs (`defaultValue` prop instead of `value`)
- It does not work with custom state providers or props, uses `useState` internally

## Leading Update

Immediately update value with first call using `{ leading: true }`:

```tsx

const [value, setValue] = useDebouncedState('', 500, { leading: true })
```

## Definition

```tsx
interface UseDebouncedStateOptions {
  leading?: boolean
}

type UseDebouncedStateReturnValue<T> = [T, (newValue: SetStateAction<T>) => void]

function useDebouncedState<T = any>(
  defaultValue: T,
  wait: number,
  options?: UseDebouncedStateOptions
): UseDebouncedStateReturnValue<T>
```

--------------------------------------------------------------------------------

### useDebouncedValue
Package: @tidbcloud/uikit
Import: import { useDebouncedValue } from '@tidbcloud/uikit';
Description: Debounce value changes for controlled components.

Debounce value changes for controlled components.

## Usage

`useDebouncedValue` hook debounces value changes. It is designed to work with controlled components.

```tsx

function Demo() {
  const [value, setValue] = useState('')
  const [debounced] = useDebouncedValue(value, 500)

  return (
    <>
      <TextInput value={value} onChange={(e) => setValue(e.currentTarget.value)} placeholder="Type something..." />
      <Text mt="md">Value: {value}</Text>
      <Text>Debounced: {debounced}</Text>
    </>
  )
}
```

## Differences from useDebouncedState

- You have direct access to the non-debounced value
- It is used for controlled inputs (`value` prop instead of `defaultValue`)
- It works with props or other state providers

## Leading Update

Immediately update value with first call using `{ leading: true }`:

```tsx

const [debounced] = useDebouncedValue(value, 500, { leading: true })
```

## Cancel Update

The hook provides a `cancel` callback to cancel the pending update:

```tsx

function Demo() {
  const [value, setValue] = useState('')
  const [debounced, cancel] = useDebouncedValue(value, 1000)

  return (
    <>
      <TextInput value={value} onChange={(e) => setValue(e.currentTarget.value)} />
      <Group mt="md">
        <Button onClick={cancel}>Cancel</Button>
      </Group>
    </>
  )
}
```

## Definition

```tsx
interface UseDebouncedValueOptions {
  leading?: boolean
}

type UseDebouncedValueReturnValue<T> = [T, () => void]

function useDebouncedValue<T = any>(
  value: T,
  wait: number,
  options?: UseDebouncedValueOptions
): UseDebouncedValueReturnValue<T>
```

--------------------------------------------------------------------------------

### useDidUpdate
Package: @tidbcloud/uikit
Import: import { useDidUpdate } from '@tidbcloud/uikit';
Description: Call a function only when dependencies change, not on mount.

Call a function only when dependencies change, not on mount.

## Usage

`useDidUpdate` works like `useEffect`, but does not run on mount – only when dependencies change.

```tsx

function Demo() {
  const [count, setCount] = useState(0)
  const [updates, setUpdates] = useState(0)

  useDidUpdate(() => {
    setUpdates((u) => u + 1)
  }, [count])

  return (
    <>
      <Text>Count: {count}</Text>
      <Text>Updates (excluding mount): {updates}</Text>
      <Group>
        <Button onClick={() => setCount((c) => c + 1)}>Increment</Button>
      </Group>
    </>
  )
}
```

## Definition

```tsx
function useDidUpdate(fn: React.EffectCallback, dependencies?: React.DependencyList): void
```

--------------------------------------------------------------------------------

### useDisclosure
Package: @tidbcloud/uikit
Import: import { useDisclosure } from '@tidbcloud/uikit';
Description: Manage boolean state with open, close, and toggle handlers.

Manage boolean state with open, close, and toggle handlers.

## Usage

`useDisclosure` manages boolean state. It provides `open`, `close`, and `toggle` handlers and accepts optional `onOpen` and `onClose` callbacks.

```tsx

function Demo() {
  const [opened, { open, close }] = useDisclosure(false)

  return (
    <>
      <Modal opened={opened} onClose={close} title="My Modal">
        Modal content
      </Modal>
      <Button onClick={open}>Open modal</Button>
    </>
  )
}
```

## Handlers

```tsx

function Demo() {
  const [opened, handlers] = useDisclosure(false)

  handlers.open() // Sets opened to true
  handlers.close() // Sets opened to false
  handlers.toggle() // Toggles opened state
}
```

## Callbacks

The `onOpen` and `onClose` callbacks execute when the opened state changes:

```tsx

function Demo() {
  const [opened, handlers] = useDisclosure(false, {
    onOpen: () => console.log('Opened'),
    onClose: () => console.log('Closed')
  })

  handlers.open() // Calls onOpen and sets opened to true
  handlers.open() // Does nothing, opened is already true

  handlers.close() // Calls onClose and sets opened to false
  handlers.close() // Does nothing, opened is already false
}
```

## Definition

```tsx
interface UseDisclosureOptions {
  onOpen?: () => void
  onClose?: () => void
}

interface UseDisclosureHandlers {
  open: () => void
  close: () => void
  toggle: () => void
}

type UseDisclosureReturnValue = [boolean, UseDisclosureHandlers]

function useDisclosure(initialState?: boolean, options?: UseDisclosureOptions): UseDisclosureReturnValue
```

--------------------------------------------------------------------------------

### useDocumentTitle
Package: @tidbcloud/uikit
Import: import { useDocumentTitle } from '@tidbcloud/uikit';
Description: Set the document title.

Set the document title.

## Usage

`useDocumentTitle` sets `document.title` property with `React.useLayoutEffect`. It is not called during server side rendering.

```tsx

function Demo() {
  const [title, setTitle] = useState('My App')
  useDocumentTitle(title)

  return (
    <TextInput
      value={title}
      onChange={(e) => setTitle(e.currentTarget.value)}
      label="Page title"
      placeholder="Enter page title"
    />
  )
}
```

## Notes

- Use this hook with client-only applications
- For isomorphic use, consider more advanced options like `react-helmet`
- The hook triggers every time the value changes and is not empty

## Definition

```tsx
function useDocumentTitle(title: string): void
```

--------------------------------------------------------------------------------

### useDocumentVisibility
Package: @tidbcloud/uikit
Import: import { useDocumentVisibility } from '@tidbcloud/uikit';
Description: Track document visibility state.

Track document visibility state.

## Usage

`useDocumentVisibility` returns current `document.visibilityState` – it allows detecting if the current tab is active.

```tsx

function Demo() {
  const documentState = useDocumentVisibility()

  return <Text>Document is {documentState === 'visible' ? 'visible' : 'hidden'}</Text>
}
```

## Use Cases

- Pause videos/animations when tab is not visible
- Stop polling when user switches tabs
- Track user engagement

## Definition

```tsx
// DocumentVisibilityState is 'visible' | 'hidden'
function useDocumentVisibility(): DocumentVisibilityState
```

--------------------------------------------------------------------------------

### useElementSize
Package: @tidbcloud/uikit
Import: import { useElementSize } from '@tidbcloud/uikit';
Description: Returns element width and height and observes changes with ResizeObserver.

Returns element width and height and observes changes with ResizeObserver.

## Usage

`useElementSize` is a simpler version of `useResizeObserver` hook. It returns a `ref` object that should be passed to the observed element, and the element's `height` and `width`.

```tsx

function Demo() {
  const { ref, width, height } = useElementSize()

  return (
    <>
      <textarea ref={ref} style={{ width: 400, height: 200 }}>
        Resize this element
      </textarea>
      <div>
        Width: {width}, Height: {height}
      </div>
    </>
  )
}
```

## API

On the first render (as well as during SSR), or when no element is being observed, `width` and `height` properties are equal to `0`.

```tsx

const { ref, width, height } = useElementSize()
```

## Definition

```tsx
function useElementSize<T extends HTMLElement = any>(): {
  ref: React.RefObject<T>
  width: number
  height: number
}
```

--------------------------------------------------------------------------------

### useEventListener
Package: @tidbcloud/uikit
Import: import { useEventListener } from '@tidbcloud/uikit';
Description: Add event listener to an element.

Add event listener to an element.

## Usage

`useEventListener` adds a given event listener to an element to which `ref` is assigned. After the component is unmounted, the listener is automatically removed.

```tsx

function Demo() {
  const [count, setCount] = useState(0)
  const ref = useEventListener('click', () => setCount((c) => c + 1))

  return <button ref={ref}>Button clicked {count} times</button>
}
```

## Options

The hook supports the same options as `addEventListener` method:

```tsx

const ref = useEventListener('scroll', handler, { passive: true })
```

## Definition

```tsx
function useEventListener<K extends keyof HTMLElementEventMap, T extends HTMLElement = any>(
  type: K,
  listener: (this: HTMLDivElement, ev: HTMLElementEventMap[K]) => any,
  options?: boolean | AddEventListenerOptions
): React.RefCallback<T | null>
```

--------------------------------------------------------------------------------

### useEyeDropper
Package: @tidbcloud/uikit
Import: import { useEyeDropper } from '@tidbcloud/uikit';
Description: Use the EyeDropper API to pick colors from the screen.

Use the EyeDropper API to pick colors from the screen.

## Usage

`useEyeDropper` provides an interface to work with the EyeDropper API. Check [browser support](https://caniuse.com/mdn-api_eyedropper) to learn which browsers support the API.

```tsx

function Demo() {
  const { supported, open } = useEyeDropper()
  const [color, setColor] = useState('')

  const handlePick = async () => {
    const result = await open()
    if (result) {
      setColor(result.sRGBHex)
    }
  }

  if (!supported) {
    return <Text>EyeDropper API is not supported in this browser</Text>
  }

  return (
    <Group>
      <Button onClick={handlePick}>Pick color</Button>
      {color && (
        <>
          <Text>Picked color: {color}</Text>
          <div style={{ width: 30, height: 30, backgroundColor: color }} />
        </>
      )}
    </Group>
  )
}
```

## Definition

```tsx
interface EyeDropperOpenOptions {
  signal?: AbortSignal
}

interface EyeDropperOpenReturnType {
  sRGBHex: string
}

interface UseEyeDropperReturnValue {
  supported: boolean
  open: (options?: EyeDropperOpenOptions) => Promise<EyeDropperOpenReturnType | undefined>
}

function useEyeDropper(): UseEyeDropperReturnValue
```

--------------------------------------------------------------------------------

### useFavicon
Package: @tidbcloud/uikit
Import: import { useFavicon } from '@tidbcloud/uikit';
Description: Set the page favicon.

Set the page favicon.

## Usage

`useFavicon` appends a `<link />` element to the head with the given favicon. The hook is not called during server side rendering.

```tsx

function Demo() {
  useFavicon('/favicon.ico')

  return <div>Page with custom favicon</div>
}
```

## Dynamic Favicon

```tsx

function Demo() {
  const [favicon, setFavicon] = useState('/default.ico')
  useFavicon(favicon)

  return (
    <Group>
      <Button onClick={() => setFavicon('/success.ico')}>Success</Button>
      <Button onClick={() => setFavicon('/error.ico')}>Error</Button>
    </Group>
  )
}
```

## Supported Formats

- `.ico`
- `.png`
- `.svg`
- `.gif`

## Definition

```tsx
function useFavicon(url: string): void
```

--------------------------------------------------------------------------------

### useFetch
Package: @tidbcloud/uikit
Import: import { useFetch } from '@tidbcloud/uikit';
Description: Fetch data with built-in loading and error states.

Fetch data with built-in loading and error states.

## Usage

`useFetch` sends a fetch request to the specified URL and returns the response data, loading state, error, and utility functions.

```tsx

interface User {
  id: number
  name: string
  email: string
}

function Demo() {
  const { data, loading, error, refetch, abort } = useFetch<User>('https://api.example.com/user/1')

  if (loading) return <Loader />
  if (error) return <Text c="red">Error: {error.message}</Text>

  return (
    <>
      <Text>Name: {data?.name}</Text>
      <Text>Email: {data?.email}</Text>
      <Button onClick={refetch}>Refetch</Button>
    </>
  )
}
```

## Options

Pass fetch options as the second argument:

```tsx

const { data, loading } = useFetch('/api/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ key: 'value' })
})
```

## Auto Invoke

By default, the request is sent when the component mounts. Set `autoInvoke: false` to disable:

```tsx

const { data, refetch } = useFetch('/api/data', {
  autoInvoke: false
})

// Call refetch() manually to send the request
```

## Definition

```tsx
interface UseFetchOptions extends RequestInit {
  autoInvoke?: boolean
}

interface UseFetchReturnValue<T> {
  data: T | null
  loading: boolean
  error: Error | null
  refetch: () => Promise<any>
  abort: () => void
}

function useFetch<T>(url: string, options?: UseFetchOptions): UseFetchReturnValue<T>
```

--------------------------------------------------------------------------------

### useFileDialog
Package: @tidbcloud/uikit
Import: import { useFileDialog } from '@tidbcloud/uikit';
Description: Open file dialog without a file input element.

Open file dialog without a file input element.

## Usage

`useFileDialog` allows capturing one or more files from the user without a file input element.

```tsx

function Demo() {
  const { files, open, reset } = useFileDialog({
    multiple: true,
    accept: 'image/*'
  })

  return (
    <Stack>
      <Button onClick={open}>Select images</Button>
      <Button onClick={reset} variant="outline">
        Reset
      </Button>

      {files && (
        <div>
          <Text>Selected files:</Text>
          {Array.from(files).map((file) => (
            <Text key={file.name} size="sm">
              {file.name}
            </Text>
          ))}
        </div>
      )}
    </Stack>
  )
}
```

## Options

```tsx

const { files, open, reset } = useFileDialog({
  multiple: true, // Allow multiple files
  accept: '.pdf,.doc', // Accepted file types
  directory: false, // Allow directory selection
  resetOnOpen: false, // Reset state when dialog opens
  initialFiles: null, // Initial selected files
  onChange: (files) => {}, // Called when files are selected
  onCancel: () => {} // Called when dialog is canceled
})
```

## Definition

```tsx
interface UseFileDialogOptions {
  multiple?: boolean
  accept?: string
  capture?: string
  directory?: boolean
  resetOnOpen?: boolean
  initialFiles?: FileList | File[]
  onChange?: (files: FileList | null) => void
  onCancel?: () => void
}

interface UseFileDialogReturnValue {
  files: FileList | null
  open: () => void
  reset: () => void
}

function useFileDialog(input?: UseFileDialogOptions): UseFileDialogReturnValue
```

--------------------------------------------------------------------------------

### useFocusReturn
Package: @tidbcloud/uikit
Import: import { useFocusReturn } from '@tidbcloud/uikit';
Description: Automatically returns focus to the last focused element when a given condition is met.

Automatically returns focus to the last focused element when a given condition is met.

## Usage

`useFocusReturn` is used to restore focus after a modal, drawer, or similar overlay was closed.

```tsx

function Demo() {
  const [opened, setOpened] = useState(false)

  useFocusReturn({
    opened,
    shouldReturnFocus: true
  })

  return (
    <>
      <button onClick={() => setOpened(true)}>Open</button>
      {opened && (
        <div>
          <button onClick={() => setOpened(false)}>Close</button>
        </div>
      )}
    </>
  )
}
```

## With useFocusTrap

In most cases, you should use this hook with `useFocusTrap`:

```tsx

function Demo() {
  const [opened, setOpened] = useState(false)
  const focusTrapRef = useFocusTrap(opened)

  useFocusReturn({
    opened,
    shouldReturnFocus: true
  })

  return (
    <>
      <button onClick={() => setOpened(true)}>Open</button>
      {opened && (
        <div ref={focusTrapRef}>
          <input />
          <button onClick={() => setOpened(false)}>Close</button>
        </div>
      )}
    </>
  )
}
```

## Manual Focus Return

If `shouldReturnFocus` is set to `false`, you can call the returned function to focus last active element:

```tsx

const returnFocus = useFocusReturn({
  opened: false,
  shouldReturnFocus: false
})

// Later...
returnFocus()
```

## Definition

```tsx
interface UseFocusReturnOptions {
  opened: boolean
  shouldReturnFocus?: boolean
}

function useFocusReturn(options: UseFocusReturnOptions): () => void
```

--------------------------------------------------------------------------------

### useFocusTrap
Package: @tidbcloud/uikit
Import: import { useFocusTrap } from '@tidbcloud/uikit';
Description: Trap focus within an element.

Trap focus within an element.

## Usage

`useFocusTrap` traps focus at the given node, for example in modal, drawer, or menu. Node must include at least one focusable element. When the node unmounts, the focus trap is automatically released.

```tsx

function Demo() {
  const focusTrapRef = useFocusTrap()

  return (
    <div ref={focusTrapRef}>
      <input placeholder="First input" />
      <input placeholder="Second input" />
      <button>Submit</button>
    </div>
  )
}
```

## API

The hook accepts focus trap active state as a single argument:

```tsx

useFocusTrap() // focus trap inactive
useFocusTrap(true) // focus trap active
useFocusTrap(false) // focus trap disabled
```

## Initial Focus

By default, focus trap will move focus to the first interactive element. To specify the element that should receive initial focus, add `data-autofocus` attribute:

```tsx

function Demo() {
  const focusTrapRef = useFocusTrap()

  return (
    <div ref={focusTrapRef}>
      <input placeholder="First input" />
      <input placeholder="Will receive initial focus" data-autofocus />
      <input placeholder="Third input" />
    </div>
  )
}
```

## Combine with Other Ref Hooks

To combine `useFocusTrap` with other ref-based hooks, use `useMergedRef`:

```tsx

function Demo() {
  const myRef = useRef()
  const clickOutsideRef = useClickOutside(() => {})
  const focusTrapRef = useFocusTrap()
  const mergedRef = useMergedRef(myRef, clickOutsideRef, focusTrapRef)

  return <div ref={mergedRef} />
}
```

## Definition

```tsx
function useFocusTrap(active?: boolean): React.RefCallback<HTMLElement | null>
```

--------------------------------------------------------------------------------

### useFocusWithin
Package: @tidbcloud/uikit
Import: import { useFocusWithin } from '@tidbcloud/uikit';
Description: Detect if any element within has focus.

Detect if any element within has focus.

## Usage

`useFocusWithin` hook detects if any element within the other element has focus. It works the same way as `:focus-within` CSS selector.

```tsx

function Demo() {
  const { ref, focused } = useFocusWithin()

  return (
    <Box
      ref={ref}
      p="lg"
      style={{
        backgroundColor: focused ? 'var(--mantine-color-blue-light)' : 'transparent'
      }}
    >
      <TextInput label="Name" placeholder="Enter name" />
      <TextInput label="Email" placeholder="Enter email" mt="md" />
      <Button mt="md">Submit</Button>
    </Box>
  )
}
```

## Callbacks

You can pass `onFocus` and `onBlur` callbacks:

```tsx

function Demo() {
  const { ref, focused } = useFocusWithin({
    onFocus: () => console.log('Focused'),
    onBlur: () => console.log('Blurred')
  })

  return <div ref={ref}>...</div>
}
```

## Definition

```tsx
interface UseFocusWithinOptions {
  onFocus?: (event: FocusEvent) => void
  onBlur?: (event: FocusEvent) => void
}

interface UseFocusWithinReturnValue<T extends HTMLElement = any> {
  ref: React.RefCallback<T | null>
  focused: boolean
}

function useFocusWithin<T extends HTMLElement = any>(options?: UseFocusWithinOptions): UseFocusWithinReturnValue<T>
```

--------------------------------------------------------------------------------

### useForceUpdate
Package: @tidbcloud/uikit
Import: import { useForceUpdate } from '@tidbcloud/uikit';
Description: Force component to re-render.

Force component to re-render.

## Usage

`useForceUpdate` returns a function that forces the component to re-render when called.

```tsx

function Demo() {
  const forceUpdate = useForceUpdate()

  return (
    <>
      <Text>Random value: {Math.random()}</Text>
      <Button onClick={forceUpdate}>Force re-render</Button>
    </>
  )
}
```

## Use Cases

- Force update when external state changes
- Re-render without changing state
- Integration with non-React code

Note: Use this sparingly – most cases should use `useState` or `useReducer` instead.

## Definition

```tsx
function useForceUpdate(): () => void
```

--------------------------------------------------------------------------------

### useFullscreen
Package: @tidbcloud/uikit
Import: import { useFullscreen } from '@tidbcloud/uikit';
Description: Enter/exit fullscreen mode for an element.

Enter/exit fullscreen mode for an element.

## Usage

`useFullscreen` allows entering/exiting fullscreen for a given element using the Fullscreen API. By default, if you don't provide `ref`, the hook will target `document.documentElement`.

```tsx

function Demo() {
  const { toggle, fullscreen } = useFullscreen()

  return (
    <Button onClick={toggle} color={fullscreen ? 'red' : 'blue'}>
      {fullscreen ? 'Exit Fullscreen' : 'Enter Fullscreen'}
    </Button>
  )
}
```

## Custom Target Element

The hook returns an optional `ref` function that can be passed to an element to act as root:

```tsx

function Demo() {
  const { ref, toggle, fullscreen } = useFullscreen()

  return (
    <Stack>
      <Image ref={ref} src="https://example.com/image.jpg" alt="Toggle fullscreen" />
      <Button onClick={toggle}>{fullscreen ? 'Exit' : 'View fullscreen'}</Button>
    </Stack>
  )
}
```

## Definition

```tsx
interface UseFullscreenReturnValue<T extends HTMLElement = any> {
  ref: React.RefCallback<T | null>
  toggle: () => Promise<void>
  fullscreen: boolean
}

function useFullscreen<T extends HTMLElement = any>(): UseFullscreenReturnValue<T>
```

--------------------------------------------------------------------------------

### useHash
Package: @tidbcloud/uikit
Import: import { useHash } from '@tidbcloud/uikit';
Description: Read and write URL hash.

Read and write URL hash.

## Usage

`useHash` returns hash from URL, subscribes to its changes with the hashchange event, and allows changing it with `setHash` function.

```tsx

function Demo() {
  const [hash, setHash] = useHash()

  return (
    <>
      <Text>Current hash: {hash || 'none'}</Text>
      <Group>
        <Button onClick={() => setHash('section-1')}>Go to section 1</Button>
        <Button onClick={() => setHash('section-2')}>Go to section 2</Button>
      </Group>
    </>
  )
}
```

## Initial State Value

By default, `useHash` retrieves value in `useEffect`. If you want to get the initial value immediately:

```tsx

const [hash, setHash] = useHash({ getInitialValueInEffect: false })
```

Note: This option is not compatible with server-side rendering.

## Definition

```tsx
interface UseHashOptions {
  getInitialValueInEffect?: boolean
}

type UseHashReturnValue = [string, (value: string) => void]

function useHash(options?: UseHashOptions): UseHashReturnValue
```

--------------------------------------------------------------------------------

### useHeadroom
Package: @tidbcloud/uikit
Import: import { useHeadroom } from '@tidbcloud/uikit';
Description: Create headers that hide on scroll.

Create headers that hide on scroll.

## Usage

`useHeadroom` creates headers that are hidden after user scrolls past a given distance. It returns `true` when the header should be pinned and `false` when hidden.

```tsx

function Demo() {
  const pinned = useHeadroom({ fixedAt: 120 })

  return (
    <AppShell header={{ height: 60, collapsed: !pinned }}>
      <AppShell.Header>
        <Box p="md">Header content</Box>
      </AppShell.Header>
      <AppShell.Main>{/* Content */}</AppShell.Main>
    </AppShell>
  )
}
```

## Options

- `fixedAt` – scroll distance in px at which element should be fixed
- `onPin` – called when element is pinned
- `onFix` – called when element is at fixed position
- `onRelease` – called when element is unpinned

```tsx

const pinned = useHeadroom({
  fixedAt: 100,
  onPin: () => console.log('Header pinned'),
  onFix: () => console.log('Header fixed'),
  onRelease: () => console.log('Header released')
})
```

## Definition

```tsx
interface UseHeadroomOptions {
  fixedAt?: number
  onPin?: () => void
  onFix?: () => void
  onRelease?: () => void
}

function useHeadroom(input?: UseHeadroomOptions): boolean
```

--------------------------------------------------------------------------------

### useHotkeys
Package: @tidbcloud/uikit
Import: import { useHotkeys } from '@tidbcloud/uikit';
Description: Listen for keyboard shortcuts.

Listen for keyboard shortcuts.

## Usage

`useHotkeys` accepts an array of hotkeys and handler tuples:

- `hotkey` - hotkey string, for example `ctrl+E`, `shift+alt+L`, `mod+S`
- `handler` - event handler called when the combination is pressed
- `options` - optional object with extra options

```tsx

function Demo() {
  useHotkeys([
    ['mod+J', () => console.log('Toggle color scheme')],
    ['ctrl+K', () => console.log('Trigger search')],
    ['alt+mod+shift+X', () => console.log('Special action')]
  ])

  return <div>Press hotkeys to trigger actions</div>
}
```

## Ignored Elements

By default, hotkey events are ignored if focus is in `input`, `textarea`, and `select` elements. You can change this:

```tsx

function Demo() {
  // Ignore only when focus is in input and textarea
  useHotkeys([['ctrl+K', () => console.log('Search')]], ['INPUT', 'TEXTAREA'])

  // Do not ignore any element
  useHotkeys([['ctrl+K', () => console.log('Search')]], [])
}
```

## Targeting Elements

For specific elements, use `getHotkeyHandler`:

```tsx

function Demo() {
  const [value, setValue] = useState('')

  return (
    <TextInput
      placeholder="Press Enter to submit, Escape to clear"
      value={value}
      onChange={(event) => setValue(event.currentTarget.value)}
      onKeyDown={getHotkeyHandler([
        ['Enter', () => console.log('Submit:', value)],
        ['Escape', () => setValue('')]
      ])}
    />
  )
}
```

## Supported Formats

- `mod+S` – detects `⌘+S` on macOS and `Ctrl+S` on Windows
- `ctrl+shift+X` – handles multiple modifiers
- `alt + shift + L` – whitespace is allowed
- `ArrowLeft` – special keys using KeyboardEvent.key format
- `shift + [plus]` – use `[plus]` to detect `+` key

## Definition

```tsx
interface HotkeyItemOptions {
  preventDefault?: boolean
  usePhysicalKeys?: boolean
}

type HotkeyItem = [string, (event: KeyboardEvent) => void, HotkeyItemOptions?]

function useHotkeys(hotkeys: HotkeyItem[], tagsToIgnore?: string[], triggerOnContentEditable?: boolean): void
```

--------------------------------------------------------------------------------

### useHover
Package: @tidbcloud/uikit
Import: import { useHover } from '@tidbcloud/uikit';
Description: Detect hover state of an element.

Detect hover state of an element.

## Usage

```tsx

function Demo() {
  const { hovered, ref } = useHover()

  return (
    <Box
      ref={ref}
      p="xl"
      style={{
        backgroundColor: hovered ? 'var(--mantine-color-blue-light)' : 'transparent'
      }}
    >
      {hovered ? 'Hovered!' : 'Hover over me'}
    </Box>
  )
}
```

## Definition

```tsx
interface UseHoverReturnValue<T extends HTMLElement = any> {
  hovered: boolean
  ref: React.RefCallback<T | null>
}

function useHover<T extends HTMLElement = any>(): UseHoverReturnValue<T>
```

--------------------------------------------------------------------------------

### useId
Package: @tidbcloud/uikit
Import: import { useId } from '@tidbcloud/uikit';
Description: Generate unique IDs that persist across renders.

Generate unique IDs that persist across renders.

## Usage

`useId` generates a random id that persists across renders. It's commonly used to bind input elements to labels.

```tsx

function Input({ id }: { id?: string }) {
  const uuid = useId(id)

  return (
    <>
      <label htmlFor={uuid}>Input label</label>
      <input type="text" id={uuid} />
    </>
  )
}

// Usage:
// <Input id="my-id" />  -> input and label will have id 'my-id'
// <Input />             -> input and label will have random id like 'mantine-fZMoF'
```

## Definition

```tsx
function useId(id?: string): string
```

--------------------------------------------------------------------------------

### useIdle
Package: @tidbcloud/uikit
Import: import { useIdle } from '@tidbcloud/uikit';
Description: Detect user idle state.

Detect user idle state.

## Usage

`useIdle` detects if the user does nothing for a given time in ms.

```tsx

function Demo() {
  const idle = useIdle(2000)

  return <Text>{idle ? 'User is idle' : 'User is active'}</Text>
}
```

## Custom Events

By default, the hook listens to `keypress`, `mousemove`, `touchmove`, `wheel`, `click`, and `scroll` events. You can customize these:

```tsx

const idle = useIdle(2000, { events: ['click', 'keypress'] })
```

## Initial State

By default, the hook returns `true` (idle) on initial render. Change with `initialState`:

```tsx

const idle = useIdle(2000, { initialState: false })
```

## Definition

```tsx
interface UseIdleOptions {
  events?: (keyof DocumentEventMap)[]
  initialState?: boolean
}

function useIdle(timeout: number, options?: UseIdleOptions): boolean
```

--------------------------------------------------------------------------------

### useInViewport
Package: @tidbcloud/uikit
Import: import { useInViewport } from '@tidbcloud/uikit';
Description: Check if an element is visible in the viewport.

Check if an element is visible in the viewport.

## Usage

`useInViewport` is a simpler alternative to `useIntersection` that only checks if the element is visible in the viewport.

```tsx

function Demo() {
  const { ref, inViewport } = useInViewport()

  return (
    <>
      <Text>{inViewport ? 'Box is in viewport' : 'Scroll down to see the box'}</Text>
      <div style={{ height: '150vh' }} />
      <Box ref={ref} p="xl" bg="blue">
        Target element
      </Box>
    </>
  )
}
```

## Definition

```tsx
interface UseInViewportReturnValue<T extends HTMLElement = any> {
  inViewport: boolean
  ref: React.RefCallback<T | null>
}

function useInViewport<T extends HTMLElement = any>(): UseInViewportReturnValue<T>
```

--------------------------------------------------------------------------------

### useInputState
Package: @tidbcloud/uikit
Import: import { useInputState } from '@tidbcloud/uikit';
Description: Handle input state changes for both native and custom inputs.

Handle input state changes for both native and custom inputs.

## Usage

`useInputState` handles state of native inputs (with event in `onChange` handler) and custom inputs (with value in `onChange` handler).

```tsx

function Demo() {
  const [stringValue, setStringValue] = useInputState('')
  const [numberValue, setNumberValue] = useInputState<string | number>(0)

  return (
    <>
      {/* Native input */}
      <input type="text" value={stringValue} onChange={setStringValue} />

      {/* Mantine TextInput */}
      <TextInput value={stringValue} onChange={setStringValue} />

      {/* Mantine NumberInput (passes value directly) */}
      <NumberInput value={numberValue} onChange={setNumberValue} />
    </>
  )
}
```

## Comparison with useState

```tsx

// With useState - requires different handling
function WithUseState() {
  const [stringValue, setStringValue] = useState('')
  const [numberValue, setNumberValue] = useState<string | number>(0)

  return (
    <>
      <input type="text" value={stringValue} onChange={(event) => setStringValue(event.currentTarget.value)} />
      <TextInput value={stringValue} onChange={(event) => setStringValue(event.currentTarget.value)} />
      <NumberInput value={numberValue} onChange={setNumberValue} />
    </>
  )
}

// With useInputState - unified handling
function WithUseInputState() {
  const [stringValue, setStringValue] = useInputState('')
  const [numberValue, setNumberValue] = useInputState<string | number>(0)

  return (
    <>
      <input type="text" value={stringValue} onChange={setStringValue} />
      <TextInput value={stringValue} onChange={setStringValue} />
      <NumberInput value={numberValue} onChange={setNumberValue} />
    </>
  )
}
```

## Definition

```tsx
type UseInputStateReturnValue<T> = [T, (value: null | undefined | T | React.ChangeEvent<any>) => void]

function useInputState<T>(initialState: T): UseInputStateReturnValue<T>
```

--------------------------------------------------------------------------------

### useIntersection
Package: @tidbcloud/uikit
Import: import { useIntersection } from '@tidbcloud/uikit';
Description: Observe element intersection with Intersection Observer API.

Observe element intersection with Intersection Observer API.

## Usage

`useIntersection` returns information about the intersection of a given element with its scroll container or body element.

```tsx

function Demo() {
  const { ref, entry } = useIntersection({
    root: null,
    threshold: 0.5
  })

  return (
    <>
      <Text>{entry?.isIntersecting ? 'Element is visible' : 'Scroll to see element'}</Text>
      <div style={{ height: '150vh' }} />
      <Box ref={ref} p="xl" bg={entry?.isIntersecting ? 'green' : 'red'}>
        Target element ({Math.round((entry?.intersectionRatio || 0) * 100)}% visible)
      </Box>
    </>
  )
}
```

## API

The hook accepts `IntersectionObserver` options as its only argument:

```tsx

useIntersection({
  root: document.querySelector('#some-element'),
  rootMargin: '0px',
  threshold: 1.0
})
```

On the first render (as well as during SSR), or when no element is being observed, the entry is `null`.

## Definition

```tsx
interface UseIntersectionReturnValue<T> {
  ref: React.RefCallback<T | null>
  entry: IntersectionObserverEntry | null
}

function useIntersection<T extends HTMLElement = any>(options?: IntersectionObserverInit): UseIntersectionReturnValue<T>
```

--------------------------------------------------------------------------------

### useInterval
Package: @tidbcloud/uikit
Import: import { useInterval } from '@tidbcloud/uikit';
Description: Run a function at intervals.

Run a function at intervals.

## Usage

```tsx

function Demo() {
  const [seconds, setSeconds] = useState(0)
  const interval = useInterval(() => setSeconds((s) => s + 1), 1000)

  return (
    <>
      <Text>Timer: {seconds} seconds</Text>
      <Group>
        <Button onClick={interval.start} disabled={interval.active}>
          Start
        </Button>
        <Button onClick={interval.stop} disabled={!interval.active}>
          Stop
        </Button>
        <Button onClick={interval.toggle}>Toggle</Button>
      </Group>
    </>
  )
}
```

## Auto Invoke

Start the interval automatically when the component mounts:

```tsx

const interval = useInterval(() => console.log('Interval tick'), 1000, { autoInvoke: true })
```

## API

- `start()` – start the interval
- `stop()` – stop the interval
- `toggle()` – toggle the interval
- `active` – current interval status

## Definition

```tsx
interface UseIntervalOptions {
  autoInvoke?: boolean
}

interface UseIntervalReturnValue {
  start: () => void
  stop: () => void
  toggle: () => void
  active: boolean
}

function useInterval(fn: () => void, interval: number, options?: UseIntervalOptions): UseIntervalReturnValue
```

--------------------------------------------------------------------------------

### useIsFirstRender
Package: @tidbcloud/uikit
Import: import { useIsFirstRender } from '@tidbcloud/uikit';
Description: Check if this is the first render.

Check if this is the first render.

## Usage

`useIsFirstRender` returns `true` only on the first render.

```tsx

function Demo() {
  const [count, setCount] = useState(0)
  const isFirstRender = useIsFirstRender()

  return (
    <>
      <Text>Is first render: {isFirstRender ? 'Yes' : 'No'}</Text>
      <Text>Count: {count}</Text>
      <Button onClick={() => setCount((c) => c + 1)}>Re-render</Button>
    </>
  )
}
```

## Use Cases

- Skip animations on initial render
- Conditional logic based on first render
- Debugging render cycles

## Definition

```tsx
function useIsFirstRender(): boolean
```

--------------------------------------------------------------------------------

### useIsomorphicEffect
Package: @tidbcloud/uikit
Import: import { useIsomorphicEffect } from '@tidbcloud/uikit';
Description: useLayoutEffect that works on both server and client.

useLayoutEffect that works on both server and client.

## Usage

`useIsomorphicEffect` uses `useLayoutEffect` on the client and `useEffect` on the server. This is useful for isomorphic (SSR) apps.

```tsx

function Demo() {
  useIsomorphicEffect(() => {
    // This runs like useLayoutEffect on client
    // And like useEffect on server (no warning)
    console.log('Effect ran')
  }, [])

  return <div>Demo</div>
}
```

## Why?

`useLayoutEffect` fires a warning when used during server-side rendering. This hook suppresses that warning by using `useEffect` on the server.

## Definition

```tsx
function useIsomorphicEffect(effect: React.EffectCallback, deps?: React.DependencyList): void
```

--------------------------------------------------------------------------------

### useListState
Package: @tidbcloud/uikit
Import: import { useListState } from '@tidbcloud/uikit';
Description: Manage array state with convenient handlers.

Manage array state with convenient handlers.

## Usage

`useListState` provides an API to work with list state:

```tsx

const [values, handlers] = useListState([{ a: 1 }])

// Add items to the end
handlers.append({ a: 2 })
// values -> [{ a: 1 }, { a: 2 }]

// Add items to the start
handlers.prepend({ a: 3 }, { a: 4 })
// values -> [{ a: 3 }, { a: 4 }, { a: 1 }, { a: 2 }]

// Remove items at given positions
handlers.remove(0, 2)
// values -> [{ a: 4 }, { a: 2 }]

// Insert items at given position
handlers.insert(1, { a: 5 })
// values -> [{ a: 4 }, { a: 5 }, { a: 2 }]

// Apply function to all items
handlers.apply((item, index) => ({ a: item.a * index }))
// values -> [{ a: 0 }, { a: 5 }, { a: 4 }]

// Move item from one position to another
handlers.reorder({ from: 2, to: 0 })
// values -> [{ a: 4 }, { a: 0 }, { a: 5 }]

// Swap items positions
handlers.swap({ from: 0, to: 2 })
// values -> [{ a: 5 }, { a: 0 }, { a: 4 }]

// Apply function to items matching condition
handlers.applyWhere(
  (item) => item.a > 0,
  (item) => ({ a: item.a + 2 })
)
// values -> [{ a: 7 }, { a: 0 }, { a: 6 }]

// Set new state
handlers.setState([{ a: 6 }, { a: 7 }])
// values -> [{ a: 6 }, { a: 7 }]

// Set item at position
handlers.setItem(0, { a: 8 })
// values -> [{ a: 8 }, { a: 7 }]

// Set item property at position
handlers.setItemProp(1, 'a', 'new-prop')
// values -> [{ a: 8 }, { a: 'new-prop' }]

// Filter items
handlers.filter((item) => item.a === 'new-prop')
// values -> [{ a: 'new-prop' }]
```

## Available Handlers

- `append` – add items to the end of the list
- `prepend` – add items to the start of the list
- `pop` – remove last item
- `shift` – remove first item
- `insert` – insert items at given index
- `remove` – remove items at given indices
- `reorder` – move item from one position to another
- `swap` – swap items positions
- `apply` – apply given function to all items
- `applyWhere` – apply given function to items matching condition
- `setItem` – replace item at given index
- `setItemProp` – set item property at given index
- `setState` – set list state with react action
- `filter` – filter values with callback function

## Set Item Type

By default, the hook will use type from `initialValues`. If you call the hook with an empty array, specify the item type:

```tsx

useListState(['hello']) // ok, item type is string
useListState([]) // not ok, item type is any
useListState<string>([]) // ok, item type is string
```

## Definition

```tsx
interface UseListStateHandlers<T> {
  setState: React.Dispatch<React.SetStateAction<T[]>>
  append: (...items: T[]) => void
  prepend: (...items: T[]) => void
  insert: (index: number, ...items: T[]) => void
  pop: () => void
  shift: () => void
  apply: (fn: (item: T, index?: number) => T) => void
  applyWhere: (condition: (item: T, index: number) => boolean, fn: (item: T, index?: number) => T) => void
  remove: (...indices: number[]) => void
  reorder: ({ from, to }: { from: number; to: number }) => void
  swap: ({ from, to }: { from: number; to: number }) => void
  setItem: (index: number, item: T) => void
  setItemProp: <K extends keyof T, U extends T[K]>(index: number, prop: K, value: U) => void
  filter: (fn: (item: T, i: number) => boolean) => void
}

function useListState<T>(initialValue?: T[]): [T[], UseListStateHandlers<T>]
```

--------------------------------------------------------------------------------

### useLocalStorage
Package: @tidbcloud/uikit
Import: import { useLocalStorage } from '@tidbcloud/uikit';
Description: Persist state in localStorage with automatic synchronization.

Persist state in localStorage with automatic synchronization.

## Usage

`useLocalStorage` allows using value from the `localStorage` as React state. The hook works the same way as `useState`, but also writes the value to localStorage.

```tsx

function Demo() {
  const [value, setValue] = useLocalStorage({
    key: 'color-scheme',
    defaultValue: 'dark'
  })

  // Value is set both to state and localStorage
  setValue('light')

  // You can also use callback like in useState
  setValue((current) => (current === 'dark' ? 'light' : 'dark'))
}
```

## Remove Value

Use `removeValue` callback to clean localStorage. When value is removed, it is reset to `defaultValue`:

```tsx

const [value, setValue, removeValue] = useLocalStorage({
  key: 'color-scheme',
  defaultValue: 'light'
})

// Later...
removeValue() // Removes from localStorage and resets to 'light'
```

## Browser Tabs Synchronization

The hook subscribes to the storage event. When state changes in one tab, it automatically updates the value in all other opened browser tabs.

## Custom Serialization

By default, the hook uses `JSON.stringify`/`JSON.parse`. Provide custom handlers if needed:

```tsx

const [value, setValue] = useLocalStorage({
  key: 'data',
  serialize: (value) => {
    /* return value serialized to string */
  },
  deserialize: (localStorageValue) => {
    /* parse localStorage string value and return value */
  }
})
```

## Session Storage

Use `useSessionStorage` for session storage instead:

```tsx

const [value, setValue] = useSessionStorage({
  key: 'session-key',
  defaultValue: 'mantine'
})
```

## Read Storage Value

To read value from storage without using the hook:

```tsx

const value = readLocalStorageValue({ key: 'color-scheme' })
```

## Definition

```tsx
interface UseStorageOptions<T> {
  key: string
  defaultValue?: T
  getInitialValueInEffect?: boolean
  sync?: boolean
  serialize?: (value: T) => string
  deserialize?: (value: string) => T
}

type UseStorageReturnValue<T> = [T, (val: T | ((prevState: T) => T)) => void, () => void]

function useLocalStorage<T = string>(options: UseStorageOptions<T>): UseStorageReturnValue<T>
```

--------------------------------------------------------------------------------

### useLogger
Package: @tidbcloud/uikit
Import: import { useLogger } from '@tidbcloud/uikit';
Description: Log component lifecycle events.

Log component lifecycle events.

## Usage

`useLogger` logs component lifecycle events to the console. This is useful for debugging.

```tsx

function Demo() {
  const [count, setCount] = useState(0)
  useLogger('Demo', [{ count }])

  return <Button onClick={() => setCount((c) => c + 1)}>Count: {count}</Button>
}
```

## Console Output

```
[Demo] Mounted
[Demo] Updated [{ count: 0 }]
[Demo] Updated [{ count: 1 }]
[Demo] Unmounted
```

## Definition

```tsx
function useLogger(componentName: string, props: any[]): void
```

--------------------------------------------------------------------------------

### useMap
Package: @tidbcloud/uikit
Import: import { useMap } from '@tidbcloud/uikit';
Description: Manage Map state with automatic re-renders.

Manage Map state with automatic re-renders.

## Usage

`useMap` returns a Map object that can be used as React state. The `set`, `clear`, and `delete` methods update state and trigger re-renders.

```tsx

function Demo() {
  const map = useMap([
    ['key1', 'value1'],
    ['key2', 'value2']
  ])

  return (
    <>
      <Text>key1: {map.get('key1')}</Text>
      <Text>key2: {map.get('key2')}</Text>
      <Text>Size: {map.size}</Text>

      <Group mt="md">
        <Button onClick={() => map.set('key3', 'value3')}>Add key3</Button>
        <Button onClick={() => map.delete('key1')}>Delete key1</Button>
        <Button onClick={() => map.clear()}>Clear all</Button>
      </Group>
    </>
  )
}
```

## Definition

```tsx
function useMap<T, V>(initialState?: [T, V][]): Map<T, V>
```

--------------------------------------------------------------------------------

### useMediaQuery
Package: @tidbcloud/uikit
Import: import { useMediaQuery } from '@tidbcloud/uikit';
Description: Subscribe to media query changes.

Subscribe to media query changes.

## Usage

`useMediaQuery` subscribes to media queries. It receives a media query as an argument and returns `true` if the given media query matches the current state.

```tsx

function Demo() {
  const matches = useMediaQuery('(min-width: 768px)')

  return <div>{matches ? 'Desktop view' : 'Mobile view'}</div>
}
```

## Server Side Rendering

During server side rendering, the hook returns `false` as `window.matchMedia` API is not available. You can override the initial value:

```tsx

function Demo() {
  // Set initial value in second argument
  const matches = useMediaQuery('(max-width: 40em)', true, {
    getInitialValueInEffect: false
  })
}
```

## Definition

```tsx
interface UseMediaQueryOptions {
  getInitialValueInEffect: boolean
}

function useMediaQuery(query: string, initialValue?: boolean, options?: UseMediaQueryOptions): boolean
```

--------------------------------------------------------------------------------

### useMergedRef
Package: @tidbcloud/uikit
Import: import { useMergedRef } from '@tidbcloud/uikit';
Description: Merge multiple refs into one.

Merge multiple refs into one.

## Usage

`useMergedRef` accepts any number of refs and returns a function that should be passed to the `ref` prop.

```tsx

function Demo() {
  const myRef = useRef()
  const clickOutsideRef = useClickOutside(() => {})
  const focusTrapRef = useFocusTrap()
  const mergedRef = useMergedRef(myRef, clickOutsideRef, focusTrapRef)

  return <div ref={mergedRef} />
}
```

## mergeRefs Function

For cases where memoization with `useCallback` causes issues (like dynamic lists), use `mergeRefs` instead:

```tsx

function Demo() {
  const myRef = useRef()
  const clickOutsideRef = useClickOutside(() => {})
  const mergedRef = mergeRefs(myRef, clickOutsideRef)

  return <div ref={mergedRef} />
}
```

Note: `mergeRefs` does not work correctly with `useFocusTrap`.

## assignRef Function

`assignRef` can be used to assign refs that are not memoized:

```tsx

interface NumberInputHandlers {
  increment: () => void
  decrement: () => void
}

interface DemoProps {
  handlersRef?: React.ForwardedRef<NumberInputHandlers | undefined>
}

function Demo({ handlersRef }: DemoProps) {
  const [value, setValue] = useState(0)

  const increment = () => setValue((v) => v + 1)
  const decrement = () => setValue((v) => v - 1)

  assignRef(handlersRef, { increment, decrement })

  return (
    <>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </>
  )
}
```

## Definition

```tsx
function useMergedRef<T = any>(...refs: React.ForwardedRef<T>[]): (node: T) => void
```

--------------------------------------------------------------------------------

### useMounted
Package: @tidbcloud/uikit
Import: import { useMounted } from '@tidbcloud/uikit';
Description: Check if the component is mounted.

Check if the component is mounted.

## Usage

`useMounted` returns a function that returns `true` if the component is mounted, which is useful to avoid state updates on unmounted components.

```tsx

function Demo() {
  const mounted = useMounted()
  const [data, setData] = useState(null)

  useEffect(() => {
    async function fetchData() {
      const response = await fetch('/api/data')
      const result = await response.json()

      // Only update state if component is still mounted
      if (mounted()) {
        setData(result)
      }
    }

    fetchData()
  }, [mounted])

  return <Text>{data ? JSON.stringify(data) : 'Loading...'}</Text>
}
```

## Use Cases

- Prevent state updates after unmount
- Safe async operations
- Memory leak prevention

## Definition

```tsx
function useMounted(): () => boolean
```

--------------------------------------------------------------------------------

### useMouse
Package: @tidbcloud/uikit
Import: import { useMouse } from '@tidbcloud/uikit';
Description: Track mouse position relative to an element or document.

Track mouse position relative to an element or document.

## Usage

```tsx

function Demo() {
  const { ref, x, y } = useMouse()

  return (
    <Box ref={ref} p="xl" style={{ height: 200 }}>
      <Text>
        Mouse position: {x}, {y}
      </Text>
    </Box>
  )
}
```

## Document Tracking

If you do not provide `ref`, mouse position is tracked relative to the document element:

```tsx

function Demo() {
  const { x, y } = useMouse()

  return (
    <div>
      Document mouse position: {x}, {y}
    </div>
  )
}
```

## Reset on Exit

Set `resetOnExit` option to reset mouse position to `0, 0` when mouse leaves the element:

```tsx

const { ref, x, y } = useMouse({ resetOnExit: true })
```

## Definition

```tsx
function useMouse<T extends HTMLElement = any>(options?: {
  resetOnExit?: boolean
}): {
  x: number
  y: number
  ref: React.RefObject<T>
}
```

--------------------------------------------------------------------------------

### useMove
Package: @tidbcloud/uikit
Import: import { useMove } from '@tidbcloud/uikit';
Description: Handle move/drag behavior over an element.

Handle move/drag behavior over an element.

## Usage

`useMove` handles move behavior over any element. The callback receives `x` and `y` values between `0` and `1`.

```tsx

function Demo() {
  const [value, setValue] = useState({ x: 0.5, y: 0.5 })
  const { ref, active } = useMove(setValue)

  return (
    <div
      ref={ref}
      style={{
        width: 200,
        height: 200,
        backgroundColor: 'var(--mantine-color-blue-light)',
        position: 'relative'
      }}
    >
      <div
        style={{
          position: 'absolute',
          left: `calc(${value.x * 100}% - 8px)`,
          top: `calc(${value.y * 100}% - 8px)`,
          width: 16,
          height: 16,
          backgroundColor: active ? 'red' : 'blue',
          borderRadius: '50%'
        }}
      />
    </div>
  )
}
```

## Horizontal Slider

You can ignore changes for one of the axes:

```tsx

function Demo() {
  const [value, setValue] = useState(0.5)
  const { ref } = useMove(({ x }) => setValue(x))

  return (
    <div
      ref={ref}
      style={{
        width: 200,
        height: 16,
        backgroundColor: 'var(--mantine-color-gray-2)',
        position: 'relative'
      }}
    >
      <div
        style={{
          position: 'absolute',
          left: `calc(${value * 100}% - 8px)`,
          top: 0,
          width: 16,
          height: 16,
          backgroundColor: 'blue',
          borderRadius: '50%'
        }}
      />
    </div>
  )
}
```

## clampUseMovePosition

Use `clampUseMovePosition` function to clamp `x` and `y` values to `0-1` range:

```tsx

clampUseMovePosition({ x: 0.5, y: 0.5 }) // -> { x: 0.5, y: 0.5 }
clampUseMovePosition({ x: 1.5, y: 0.5 }) // -> { x: 1, y: 0.5 }
clampUseMovePosition({ x: -0.5, y: 0.5 }) // -> { x: 0, y: 0.5 }
```

## Definition

```tsx
interface UseMovePosition {
  x: number
  y: number
}

interface UseMoveHandlers {
  onScrubStart?: () => void
  onScrubEnd?: () => void
}

interface UseMoveReturnValue<T extends HTMLElement = any> {
  ref: React.RefCallback<T | null>
  active: boolean
}

function useMove<T extends HTMLElement = any>(
  onChange: (value: UseMovePosition) => void,
  handlers?: UseMoveHandlers,
  dir?: 'ltr' | 'rtl'
): UseMoveReturnValue<T>
```

--------------------------------------------------------------------------------

### useMutationObserver
Package: @tidbcloud/uikit
Import: import { useMutationObserver } from '@tidbcloud/uikit';
Description: Subscribe to DOM mutations with MutationObserver.

Subscribe to DOM mutations with MutationObserver.

## Usage

`useMutationObserver` is a wrapper for the MutationObserver API. It allows subscribing to changes being made to the DOM tree.

```tsx

function Demo() {
  const [lastMutation, setLastMutation] = useState('')

  const ref = useMutationObserver<HTMLDivElement>(
    (mutations) => {
      mutations.forEach((mutation) => {
        setLastMutation(`${mutation.type}: ${mutation.target.textContent}`)
      })
    },
    { childList: true, subtree: true, characterData: true }
  )

  return (
    <div>
      <div ref={ref}>
        <Text>Content to observe</Text>
      </div>
      <Text mt="md">Last mutation: {lastMutation}</Text>
    </div>
  )
}
```

## Target Element

If you cannot pass `ref` to the target element, you can pass a function to resolve the target element as a third argument:

```tsx

useMutationObserver(
  (mutations) => console.log(mutations),
  { childList: true },
  () => document.body
)
```

## Definition

```tsx
function useMutationObserver<Element extends HTMLElement>(
  callback: MutationCallback,
  options: MutationObserverInit,
  target?: HTMLElement | (() => HTMLElement) | null
): RefObject<Element>
```

--------------------------------------------------------------------------------

### useNetwork
Package: @tidbcloud/uikit
Import: import { useNetwork } from '@tidbcloud/uikit';
Description: Track network connection status.

Track network connection status.

## Usage

`useNetwork` returns an object with current connection status.

```tsx

function Demo() {
  const network = useNetwork()

  return (
    <Stack>
      <Text>Online: {network.online ? 'Yes' : 'No'}</Text>
      <Text>Effective type: {network.effectiveType}</Text>
      <Text>Downlink: {network.downlink} Mbps</Text>
      <Text>RTT: {network.rtt} ms</Text>
      <Text>Save data: {network.saveData ? 'Yes' : 'No'}</Text>
    </Stack>
  )
}
```

## Browser Support

The hook uses experimental `navigator.connection`. See [browser compatibility](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/connection#browser_compatibility) for details.

## Definition

```tsx
interface UserNetworkReturnValue {
  online: boolean
  downlink?: number
  downlinkMax?: number
  effectiveType?: 'slow-2g' | '2g' | '3g' | '4g'
  rtt?: number
  saveData?: boolean
  type?: 'bluetooth' | 'cellular' | 'ethernet' | 'wifi' | 'wimax' | 'none' | 'other' | 'unknown'
}

function useNetwork(): UserNetworkReturnValue
```

--------------------------------------------------------------------------------

### useOrientation
Package: @tidbcloud/uikit
Import: import { useOrientation } from '@tidbcloud/uikit';
Description: Track device orientation.

Track device orientation.

## Usage

`useOrientation` returns an object with the current orientation of the device.

```tsx

function Demo() {
  const { angle, type } = useOrientation()

  return (
    <div>
      <Text>Angle: {angle}</Text>
      <Text>Type: {type}</Text>
    </div>
  )
}
```

## Options

```tsx

const { angle, type } = useOrientation({
  defaultAngle: 0,
  defaultType: 'landscape-primary',
  getInitialValueInEffect: true
})
```

## Definition

```tsx
interface UseOrientationOptions {
  /** Default angle value (during SSR), `0` by default */
  defaultAngle?: number

  /** Default type value (during SSR), `'landscape-primary'` by default */
  defaultType?: OrientationType

  /** If true, the initial value will be resolved in useEffect (SSR safe) */
  getInitialValueInEffect?: boolean
}

interface UseOrientationReturnType {
  angle: number
  type: OrientationType
}

function useOrientation(options?: UseOrientationOptions): UseOrientationReturnType
```

--------------------------------------------------------------------------------

### useOs
Package: @tidbcloud/uikit
Import: import { useOs } from '@tidbcloud/uikit';
Description: Detect the user's operating system.

Detect the user's operating system.

## Usage

`useOs` returns the user's operating system. Possible values are: `undetermined`, `macos`, `ios`, `windows`, `android`, `linux`, `chromeos`.

```tsx

function Demo() {
  const os = useOs()

  return <Text>Your operating system: {os}</Text>
}
```

## SSR

If the OS cannot be identified (e.g., during server-side rendering), `undetermined` is returned.

## Definition

```tsx
type UseOSReturnValue = 'undetermined' | 'macos' | 'ios' | 'windows' | 'android' | 'linux' | 'chromeos'

interface UseOsOptions {
  getValueInEffect: boolean
}

function useOs(options?: UseOsOptions): UseOSReturnValue
```

--------------------------------------------------------------------------------

### usePageLeave
Package: @tidbcloud/uikit
Import: import { usePageLeave } from '@tidbcloud/uikit';
Description: Detect when the mouse leaves the page.

Detect when the mouse leaves the page.

## Usage

`usePageLeave` calls the given function when the mouse leaves the page.

```tsx

function Demo() {
  const [leftCount, setLeftCount] = useState(0)

  usePageLeave(() => {
    setLeftCount((c) => c + 1)
  })

  return <Text>Mouse has left the page {leftCount} times</Text>
}
```

## Use Cases

- Show exit intent popups
- Pause content when user is not on page
- Track user engagement

## Definition

```tsx
function usePageLeave(onPageLeave: () => void): void
```

--------------------------------------------------------------------------------

### usePagination
Package: @tidbcloud/uikit
Import: import { usePagination } from '@tidbcloud/uikit';
Description: Manage pagination state.

Manage pagination state.

## Usage

`usePagination` is a state management hook for the Pagination component. It manages pagination with controlled and uncontrolled state.

```tsx

const pagination = usePagination({ total: 10, initialPage: 1 })

pagination.range // -> [1, 2, 3, 4, 5, 'dots', 10]

pagination.setPage(5)
pagination.range // -> [1, 'dots', 4, 5, 6, 'dots', 10]

pagination.next()
pagination.range // -> [1, 'dots', 5, 6, 7, 'dots', 10]

pagination.previous()
pagination.range // -> [1, 'dots', 4, 5, 6, 'dots', 10]

pagination.last()
pagination.range // -> [1, 'dots', 6, 7, 8, 9, 10]

pagination.first()
pagination.range // -> [1, 2, 3, 4, 5, 'dots', 10]
```

## Controlled Mode

Provide `page` and `onChange` props:

```tsx

const [page, onChange] = useState(1)
const pagination = usePagination({ total: 10, page, onChange })

pagination.setPage(5) // Will call onChange with 5
```

## Siblings and Boundaries

Control the number of items around active page (`siblings`) and on each boundary (`boundaries`):

```tsx

const pagination = usePagination({
  total: 20,
  siblings: 2, // 2 items on each side of active page
  boundaries: 2 // 2 items on each edge
})
```

## Definition

```tsx
interface UsePaginationOptions {
  initialPage?: number
  page?: number
  total: number
  siblings?: number
  boundaries?: number
  onChange?: (page: number) => void
}

interface UsePaginationReturnValue {
  range: (number | 'dots')[]
  active: number
  setPage: (page: number) => void
  next: () => void
  previous: () => void
  first: () => void
  last: () => void
}

function usePagination(settings: UsePaginationOptions): UsePaginationReturnValue
```

--------------------------------------------------------------------------------

### usePrevious
Package: @tidbcloud/uikit
Import: import { usePrevious } from '@tidbcloud/uikit';
Description: Store the previous value of a state.

Store the previous value of a state.

## Usage

`usePrevious` stores the previous value of a state in a ref. It returns `undefined` on initial render and the previous value after re-renders.

```tsx

function Demo() {
  const [value, setValue] = useState('')
  const previousValue = usePrevious(value)

  return (
    <>
      <TextInput value={value} onChange={(e) => setValue(e.currentTarget.value)} placeholder="Type something..." />
      <Text mt="md">Current value: {value}</Text>
      <Text>Previous value: {previousValue}</Text>
    </>
  )
}
```

## Definition

```tsx
function usePrevious<T>(value: T): T | undefined
```

--------------------------------------------------------------------------------

### useQueue
Package: @tidbcloud/uikit
Import: import { useQueue } from '@tidbcloud/uikit';
Description: Manage a queue of items with automatic state limiting.

Manage a queue of items with automatic state limiting.

## Usage

`useQueue` limits the number of items in the current state and places the rest in a queue. This is useful for scenarios like notification systems where you want to display a limited number of items.

```tsx

const { state, queue, add, update, cleanQueue } = useQueue({
  initialValues: [1],
  limit: 2
})

// state -> [1], queue -> []

// When state.length is less than limit, items are added to state
add(2)
// state -> [1, 2], queue -> []

// When state.length equals limit, items are added to queue
add(3, 4, 5, 6)
// state -> [1, 2], queue -> [3, 4, 5, 6]

// Use update to modify items
update((values) => values.map((item) => item * 3))
// state -> [3, 6], queue -> [9, 12, 15, 18]

// Items added/removed in update are distributed according to limit
update((values) => values.filter((item) => item % 2))
// state -> [3, 9], queue -> [15]

// Remove all items from queue
cleanQueue()
// state -> [3, 9], queue -> []

// Remove all items
update(() => [])
// state -> [], queue -> []
```

## Options

- `initialValues` – optional initial values, divided between state and queue according to limit
- `limit` – maximum number of items that state can include

## Set Item Type

```tsx

// Type inferred from initialValues
const q = useQueue({
  limit: 2,
  initialValues: [{ name: 'Bob', id: 1 }]
})

// Explicit type for empty initial values
const q2 = useQueue<{ name: string; id: number }>({
  limit: 2,
  initialValues: []
})
```

## Definition

```tsx
interface UseQueueOptions<T> {
  initialValues?: T[]
  limit: number
}

interface UseQueueReturnValue<T> {
  queue: T[]
  state: T[]
  add: (...items: T[]) => void
  update: (fn: (state: T[]) => T[]) => void
  cleanQueue: () => void
}

function useQueue<T>(options: UseQueueOptions<T>): UseQueueReturnValue<T>
```

--------------------------------------------------------------------------------

### useReducedMotion
Package: @tidbcloud/uikit
Import: import { useReducedMotion } from '@tidbcloud/uikit';
Description: Detect if user prefers reduced motion.

Detect if user prefers reduced motion.

## Usage

`useReducedMotion` detects if user prefers to reduce motion using the `(prefers-reduced-motion: reduce)` media query.

```tsx

function Demo() {
  const reduceMotion = useReducedMotion()

  return (
    <Transition mounted={true} transition={reduceMotion ? 'fade' : 'slide-up'} duration={reduceMotion ? 0 : 200}>
      {(styles) => <div style={styles}>Content</div>}
    </Transition>
  )
}
```

## API

The hook relies on `window.matchMedia()` API and will return `false` if the API is not available (for example, during server-side rendering), unless the initial value is provided.

```tsx

// Provide initial value for SSR
const reduceMotion = useReducedMotion(true)
```

## Definition

```tsx
interface UseMediaQueryOptions {
  getInitialValueInEffect: boolean
}

function useReducedMotion(initialValue?: boolean, options?: UseMediaQueryOptions): boolean
```

--------------------------------------------------------------------------------

### useResizeObserver
Package: @tidbcloud/uikit
Import: import { useResizeObserver } from '@tidbcloud/uikit';
Description: Observe element size changes with ResizeObserver.

Observe element size changes with ResizeObserver.

## Usage

`useResizeObserver` returns a `ref` object that should be passed to the observed element, and the current element content rect.

```tsx

function Demo() {
  const [ref, rect] = useResizeObserver()

  return (
    <>
      <textarea ref={ref} style={{ width: 400, height: 120 }} defaultValue="Resize this textarea" />
      <Text mt="md">
        Width: {rect.width}px, Height: {rect.height}px
      </Text>
    </>
  )
}
```

## API

On the first render (as well as during SSR), or when no element is being observed, all properties are equal to `0`.

See [Resize Observer API](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) documentation for more information.

For a simpler API that only returns `width` and `height`, see `useElementSize`.

## Definition

```tsx
type ObserverRect = Omit<DOMRectReadOnly, 'toJSON'>

function useResizeObserver<T extends HTMLElement = any>(
  options?: ResizeObserverOptions
): readonly [React.RefObject<T>, ObserverRect]
```

--------------------------------------------------------------------------------

### useScrollIntoView
Package: @tidbcloud/uikit
Import: import { useScrollIntoView } from '@tidbcloud/uikit';
Description: Scroll element into view with smooth animation.

Scroll element into view with smooth animation.

## Usage

`useScrollIntoView` handles scroll behavior for any scrollable element. It adjusts scrolling animation with respect to the reduced-motion user preference.

```tsx

function Demo() {
  const { scrollIntoView, targetRef } = useScrollIntoView<HTMLDivElement>()

  return (
    <>
      <Button onClick={() => scrollIntoView({ alignment: 'center' })}>Scroll to target</Button>

      <div style={{ height: '150vh' }} />

      <Box ref={targetRef} p="xl" bg="blue">
        Target element
      </Box>
    </>
  )
}
```

## Options

The hook accepts a settings object:

- `onScrollFinish` – function called after scroll animation
- `easing` – custom easing function
- `duration` – duration of scroll animation in milliseconds
- `axis` – axis of scroll (`'x'` or `'y'`)
- `cancelable` – whether animation may be interrupted by user scrolling
- `offset` – additional distance between the nearest edge and element
- `isList` – prevents content jumping in scrolling lists with multiple targets

```tsx

const { scrollIntoView, targetRef, scrollableRef } = useScrollIntoView({
  duration: 500,
  offset: 60,
  onScrollFinish: () => console.log('Scroll finished')
})
```

## Custom Easing

```tsx

useScrollIntoView({
  easing: (t) => (t < 0.5 ? 16 * t ** 5 : 1 - (-2 * t + 2) ** 5 / 2) // easeInOutQuint
})
```

## Parent Node

For scrolling within a specific container:

```tsx

function Demo() {
  const { scrollIntoView, targetRef, scrollableRef } = useScrollIntoView<HTMLDivElement, HTMLDivElement>()

  return (
    <div ref={scrollableRef} style={{ height: 300, overflow: 'auto' }}>
      <div style={{ height: 1000 }}>
        <div ref={targetRef}>Target</div>
      </div>
    </div>
  )
}
```

## Definition

```tsx
interface UseScrollIntoViewAnimation {
  alignment?: 'start' | 'end' | 'center'
}

interface UseScrollIntoViewOptions {
  onScrollFinish?: () => void
  duration?: number
  axis?: 'x' | 'y'
  easing?: (t: number) => number
  offset?: number
  cancelable?: boolean
  isList?: boolean
}

interface UseScrollIntoViewReturnValue<Target, Parent> {
  scrollableRef: React.RefObject<Parent | null>
  targetRef: React.RefObject<Target | null>
  scrollIntoView: (params?: UseScrollIntoViewAnimation) => void
  cancel: () => void
}

function useScrollIntoView<Target extends HTMLElement = any, Parent extends HTMLElement | null = null>(
  options?: UseScrollIntoViewOptions
): UseScrollIntoViewReturnValue<Target, Parent>
```

--------------------------------------------------------------------------------

### useScrollSpy
Package: @tidbcloud/uikit
Import: import { useScrollSpy } from '@tidbcloud/uikit';
Description: Track scroll position for navigation and table of contents.

Track scroll position for navigation and table of contents.

## Usage

`useScrollSpy` tracks scroll position and returns the index of the element that is currently in the viewport. It's useful for creating table of contents components and similar features.

```tsx

function Demo() {
  const { data, active } = useScrollSpy()

  return (
    <div style={{ display: 'flex', gap: 20 }}>
      <nav style={{ position: 'sticky', top: 20 }}>
        <Stack gap="xs">
          {data.map((item, index) => (
            <NavLink
              key={item.id}
              label={item.value}
              active={active === index}
              onClick={() => item.getNode().scrollIntoView()}
            />
          ))}
        </Stack>
      </nav>

      <main>
        <h1 id="section-1">Section 1</h1>
        <p>Content...</p>
        <h2 id="section-2">Section 2</h2>
        <p>Content...</p>
        <h2 id="section-3">Section 3</h2>
        <p>Content...</p>
      </main>
    </div>
  )
}
```

## Options

- `selector` – selector to get headings, `'h1, h2, h3, h4, h5, h6'` by default
- `getDepth` – function to retrieve depth of heading
- `getValue` – function to retrieve heading value
- `scrollHost` – host element to attach scroll event listener
- `offset` – offset from the top of the viewport

```tsx

// Custom selector for elements with data-heading attribute
const { data, active } = useScrollSpy({
  selector: '[data-heading]',
  getDepth: (element) => Number(element.getAttribute('data-depth')),
  getValue: (element) => element.getAttribute('data-value') || '',
  offset: 100
})
```

## Reinitializing

If the DOM changes after mount, use `reinitialize` to update the headings data:

```tsx

function Demo({ dependency }) {
  const { reinitialize, data, active } = useScrollSpy()

  useEffect(() => {
    reinitialize()
  }, [dependency])

  return null
}
```

## Definition

```tsx
interface UseScrollSpyHeadingData {
  depth: number
  value: string
  id: string
  getNode: () => HTMLElement
}

interface UseScrollSpyOptions {
  selector?: string
  getDepth?: (element: HTMLElement) => number
  getValue?: (element: HTMLElement) => string
  scrollHost?: HTMLElement
  offset?: number
}

interface UseScrollSpyReturnType {
  active: number
  data: UseScrollSpyHeadingData[]
  initialized: boolean
  reinitialize: () => void
}

function useScrollSpy(options?: UseScrollSpyOptions): UseScrollSpyReturnType
```

--------------------------------------------------------------------------------

### useSet
Package: @tidbcloud/uikit
Import: import { useSet } from '@tidbcloud/uikit';
Description: Manage Set state with automatic re-renders.

Manage Set state with automatic re-renders.

## Usage

`useSet` returns a Set object that can be used as React state. The `add`, `clear`, and `delete` methods trigger state updates.

```tsx

function Demo() {
  const set = useSet(['react', 'typescript'])

  return (
    <>
      <Text>Items: {Array.from(set).join(', ')}</Text>
      <Text>Has react: {set.has('react') ? 'Yes' : 'No'}</Text>
      <Text>Size: {set.size}</Text>

      <Group mt="md">
        <Button onClick={() => set.add('mantine')}>Add mantine</Button>
        <Button onClick={() => set.delete('react')}>Delete react</Button>
        <Button onClick={() => set.clear()}>Clear all</Button>
      </Group>
    </>
  )
}
```

## Definition

```tsx
function useSet<T>(values?: T[]): Set<T>
```

--------------------------------------------------------------------------------

### useSetState
Package: @tidbcloud/uikit
Import: import { useSetState } from '@tidbcloud/uikit';
Description: Shallow merge state updates like class component setState.

Shallow merge state updates like class component setState.

## Usage

`useSetState` works similar to how `this.setState` works in class components – it shallow merges state partial into current state.

```tsx

function Demo() {
  const [state, setState] = useSetState({
    name: 'John',
    age: 35,
    job: 'Engineer'
  })

  // state -> { name: 'John', age: 35, job: 'Engineer' }

  setState({ name: 'Jane' })
  // state -> { name: 'Jane', age: 35, job: 'Engineer' }

  setState({ age: 25, job: 'Manager' })
  // state -> { name: 'Jane', age: 25, job: 'Manager' }

  setState((current) => ({ age: current.age + 7 }))
  // state -> { name: 'Jane', age: 32, job: 'Manager' }
}
```

## Limitations

Only works with objects. Primitive values and arrays are not supported:

```tsx

useSetState([1, 2, 3]) // ❌ will not work
useSetState(1) // ❌ will not work
useSetState({ skills: ['JavaScript', 'TypeScript'] }) // ✅ works fine
```

## Definition

```tsx
type UseSetStateCallback<T> = (state: Partial<T> | ((currentState: T) => Partial<T>)) => void

type UseSetStateReturnValue<T> = [T, UseSetStateCallback<T>]

function useSetState<T extends Record<string, any>>(initialState: T): UseSetStateReturnValue<T>
```

--------------------------------------------------------------------------------

### useShallowEffect
Package: @tidbcloud/uikit
Import: import { useShallowEffect } from '@tidbcloud/uikit';
Description: useEffect with shallow comparison.

useEffect with shallow comparison.

## Usage

`useShallowEffect` works like `useEffect`, but does a shallow comparison on dependencies instead of reference equality.

```tsx

function Demo() {
  const [count, setCount] = useState(0)

  // This effect will run only when { value: count } has different shallow values
  // With useEffect, it would run on every render since the object is recreated
  useShallowEffect(() => {
    console.log('Effect ran with', { value: count })
  }, [{ value: count }])

  return (
    <>
      <Text>Count: {count}</Text>
      <Button onClick={() => setCount((c) => c + 1)}>Increment</Button>
    </>
  )
}
```

## When to Use

Use `useShallowEffect` when:

- Dependencies are objects or arrays that are recreated on each render
- You want to compare by value, not reference
- You need to avoid unnecessary effect executions

## Definition

```tsx
function useShallowEffect(cb: React.EffectCallback, dependencies?: React.DependencyList): void
```

--------------------------------------------------------------------------------

### useStateHistory
Package: @tidbcloud/uikit
Import: import { useStateHistory } from '@tidbcloud/uikit';
Description: Track state history with undo/redo functionality.

Track state history with undo/redo functionality.

## Usage

`useStateHistory` creates a state with history. It returns the current value, handlers for navigation, and the history object.

```tsx

function Demo() {
  const [value, handlers, history] = useStateHistory('Initial')

  return (
    <>
      <Text>Current: {value}</Text>
      <Text>History: {JSON.stringify(history)}</Text>

      <Group mt="md">
        <Button onClick={() => handlers.set(`Value ${Date.now()}`)}>Set new value</Button>
        <Button onClick={() => handlers.back()} disabled={history.current === 0}>
          Undo
        </Button>
        <Button onClick={() => handlers.forward()} disabled={history.current === history.history.length - 1}>
          Redo
        </Button>
        <Button onClick={handlers.reset}>Reset</Button>
      </Group>
    </>
  )
}
```

## Handlers

- `set(value)` – set new value, adds to history
- `back(steps?)` – go back in history (default: 1 step)
- `forward(steps?)` – go forward in history (default: 1 step)
- `reset()` – reset to initial value

## Definition

```tsx
interface UseStateHistoryHandlers<T> {
  set: (value: T) => void
  back: (steps?: number) => void
  forward: (steps?: number) => void
  reset: () => void
}

interface UseStateHistoryValue<T> {
  history: T[]
  current: number
}

type UseStateHistoryReturnValue<T> = [T, UseStateHistoryHandlers<T>, UseStateHistoryValue<T>]

function useStateHistory<T>(initialValue: T): UseStateHistoryReturnValue<T>
```

--------------------------------------------------------------------------------

### useSystemColorScheme
Package: @tidbcloud/uikit
Import: import { useSystemColorScheme } from '@tidbcloud/uikit';
Description: Detect user's preferred OS color scheme.

Detect user's preferred OS color scheme.

## Usage

`useSystemColorScheme` returns preferred OS color scheme value (`dark` or `light`) and subscribes to changes.

```tsx

function Demo() {
  const colorScheme = useSystemColorScheme()
  return <div>Your system prefers {colorScheme} mode</div>
}
```

## Limitations

The hook relies on `window.matchMedia()` API and always returns the specified initial value (first argument, `light` by default) if the API is not available (for example, during server-side rendering).

```tsx
// returns 'dark' on server side
// returns computed value on client side after mount
const colorScheme = useSystemColorScheme('dark')
```

## Get Initial Value in Effect

By default, to support server-side rendering, the hook does not calculate the initial value on the first render. Instead, the value is calculated in `useEffect` and updated after the parent component mounts.

If your application does not have server-side rendering, you can enable immediate calculation:

```tsx
const colorScheme = useSystemColorScheme('light', { getInitialValueInEffect: false })
```

## Definition

```tsx
type UseColorSchemeValue = 'dark' | 'light'

interface UseMediaQueryOptions {
  getInitialValueInEffect: boolean
}

function useSystemColorScheme(initialValue?: UseColorSchemeValue, options?: UseMediaQueryOptions): UseColorSchemeValue
```

--------------------------------------------------------------------------------

### useTextSelection
Package: @tidbcloud/uikit
Import: import { useTextSelection } from '@tidbcloud/uikit';
Description: Get the current text selection.

Get the current text selection.

## Usage

`useTextSelection` returns the current text selection.

```tsx

function Demo() {
  const selection = useTextSelection()

  return (
    <>
      <Text>Select some text on this page</Text>
      <Text mt="md">Selected text: {selection?.toString() || 'Nothing selected'}</Text>
    </>
  )
}
```

## Definition

```tsx
function useTextSelection(): Selection | null
```

--------------------------------------------------------------------------------

### useThrottledCallback
Package: @tidbcloud/uikit
Import: import { useThrottledCallback } from '@tidbcloud/uikit';
Description: Create a throttled version of a callback function.

Create a throttled version of a callback function.

## Usage

`useThrottledCallback` accepts a function and a wait time in milliseconds. It returns a throttled version that will only be called at most once every `wait` milliseconds.

```tsx

function Demo() {
  const [value, setValue] = useState('')
  const [throttledValue, setThrottledValue] = useState('')

  const handleChange = useThrottledCallback((val: string) => {
    setThrottledValue(val)
  }, 1000)

  return (
    <>
      <TextInput
        value={value}
        onChange={(e) => {
          setValue(e.currentTarget.value)
          handleChange(e.currentTarget.value)
        }}
        placeholder="Type something..."
      />
      <Text mt="md">Value: {value}</Text>
      <Text>Throttled value (updates at most once per second): {throttledValue}</Text>
    </>
  )
}
```

## Definition

```tsx
function useThrottledCallback<T extends (...args: any[]) => any>(
  callback: T,
  wait: number
): (...args: Parameters<T>) => void
```

--------------------------------------------------------------------------------

### useThrottledState
Package: @tidbcloud/uikit
Import: import { useThrottledState } from '@tidbcloud/uikit';
Description: Throttle state updates.

Throttle state updates.

## Usage

`useThrottledState` works similar to `useState` but throttles state updates. The state will not update more than once every `wait` milliseconds.

```tsx

function Demo() {
  const [value, setValue] = useThrottledState('', 1000)

  return (
    <>
      <TextInput onChange={(e) => setValue(e.currentTarget.value)} placeholder="Type something..." />
      <Text mt="md">Throttled value (updates at most once per second): {value}</Text>
    </>
  )
}
```

## Definition

```tsx
function useThrottledState<T = any>(
  defaultValue: T,
  wait: number
): readonly [T, (newValue: React.SetStateAction<T>) => void]
```

--------------------------------------------------------------------------------

### useThrottledValue
Package: @tidbcloud/uikit
Import: import { useThrottledValue } from '@tidbcloud/uikit';
Description: Throttle value changes.

Throttle value changes.

## Usage

`useThrottledValue` accepts a value and a wait time in milliseconds. It returns a throttled value that cannot change more than once every `wait` milliseconds.

```tsx

function Demo() {
  const [value, setValue] = useState('')
  const throttledValue = useThrottledValue(value, 1000)

  return (
    <>
      <TextInput value={value} onChange={(e) => setValue(e.currentTarget.value)} placeholder="Type something..." />
      <Text mt="md">Value: {value}</Text>
      <Text>Throttled value: {throttledValue}</Text>
    </>
  )
}
```

## Definition

```tsx
function useThrottledValue<T>(value: T, wait: number): T
```

--------------------------------------------------------------------------------

### useTimeout
Package: @tidbcloud/uikit
Import: import { useTimeout } from '@tidbcloud/uikit';
Description: Run a function after a timeout.

Run a function after a timeout.

## Usage

```tsx

function Demo() {
  const [visible, setVisible] = useState(true)
  const { start, clear } = useTimeout(() => setVisible(false), 3000)

  return (
    <>
      <Text>{visible ? 'Message will hide in 3 seconds' : 'Message hidden'}</Text>
      <Group>
        <Button onClick={start}>Start timer</Button>
        <Button onClick={clear}>Cancel</Button>
        <Button onClick={() => setVisible(true)}>Reset message</Button>
      </Group>
    </>
  )
}
```

## Auto Invoke

Start the timeout automatically when the component mounts:

```tsx

const { start, clear } = useTimeout(() => console.log('Timeout!'), 3000, { autoInvoke: true })
```

## API

- `start(...args)` – starts the timer, can pass arguments to the callback
- `clear()` – cancels the timer

## Definition

```tsx
interface UseTimeoutOptions {
  autoInvoke: boolean
}

interface UseTimeoutReturnValue {
  start: (...args: any[]) => void
  clear: () => void
}

function useTimeout(
  callback: (...args: any[]) => void,
  delay: number,
  options?: UseTimeoutOptions
): UseTimeoutReturnValue
```

--------------------------------------------------------------------------------

### useToggle
Package: @tidbcloud/uikit
Import: import { useToggle } from '@tidbcloud/uikit';
Description: Toggle between values.

Toggle between values.

## Usage

`useToggle` switches state between given values.

```tsx

function Demo() {
  const [value, toggle] = useToggle(['light', 'dark'] as const)

  return (
    <>
      <Text>Color scheme: {value}</Text>
      <Button onClick={() => toggle()}>Toggle</Button>
      <Button onClick={() => toggle('dark')}>Force dark</Button>
    </>
  )
}
```

## Boolean Toggle

If you don't provide options, `useToggle` uses boolean values with `false` as default:

```tsx

const [value, toggle] = useToggle()
// value === false

toggle()
// value === true
```

## Type Safety

Use const assertion for better type inference:

```tsx

useToggle(['light', 'dark']) // value is string
useToggle(['light', 'dark'] as const) // value is 'dark' | 'light'
useToggle<'dark' | 'light'>(['light', 'dark']) // same as above
```

## Definition

```tsx
type UseToggleAction<T> = (value?: React.SetStateAction<T>) => void
type UseToggleReturnValue<T> = [T, UseToggleAction<T>]

function useToggle<T = boolean>(options?: T[]): UseToggleReturnValue<T>
```

--------------------------------------------------------------------------------

### useURLQueryState
Package: @tidbcloud/uikit
Import: import { useURLQueryState } from '@tidbcloud/uikit';
Description: Manage state synced with URL query parameters.

Manage state synced with URL query parameters.

## Usage

`useURLQueryState` keeps state in sync with URL query parameters. When the state changes, the URL is updated. When the URL changes (e.g., back/forward navigation), the state is updated.

```tsx

function Demo() {
  const [search, setSearch] = useURLQueryState('search', '')

  return <TextInput value={search} onChange={(e) => setSearch(e.currentTarget.value)} placeholder="Search..." />
}
```

This will update the URL to `?search=value` when the input changes.

## Multiple Parameters

```tsx

function Demo() {
  const [search, setSearch] = useURLQueryState('q', '')
  const [page, setPage] = useURLQueryState('page', '1')

  return (
    <Stack>
      <TextInput value={search} onChange={(e) => setSearch(e.currentTarget.value)} label="Search" />
      <NumberInput value={parseInt(page)} onChange={(val) => setPage(String(val))} label="Page" />
    </Stack>
  )
}
```

## URL State Persistence

When a user bookmarks or shares the URL, the state will be restored from the query parameters.

## Notes

- State is stored as strings in the URL
- Empty values are removed from the URL
- Compatible with browser history (back/forward buttons)

## Definition

```tsx
function useURLQueryState(key: string, defaultValue: string): [string, (value: string) => void]
```

--------------------------------------------------------------------------------

### useUncontrolled
Package: @tidbcloud/uikit
Import: import { useUncontrolled } from '@tidbcloud/uikit';
Description: Handle controlled and uncontrolled component state.

Handle controlled and uncontrolled component state.

## Usage

`useUncontrolled` manages state for both controlled and uncontrolled components. It's useful when building custom form components.

```tsx

interface CustomInputProps {
  value?: string
  defaultValue?: string
  onChange?: (value: string) => void
}

function CustomInput({ value, defaultValue, onChange }: CustomInputProps) {
  const [_value, handleChange] = useUncontrolled({
    value,
    defaultValue,
    finalValue: 'Final',
    onChange,
  })

  return (
    <input
      type="text"
      value={_value}
      onChange={(event) => handleChange(event.currentTarget.value)}
    />
  )
}

// Usage:
// Uncontrolled
<CustomInput defaultValue="Hello" />

// Controlled
<CustomInput value={value} onChange={setValue} />
```

## Options

- `value` – value for controlled state
- `defaultValue` – initial value for uncontrolled state
- `finalValue` – fallback value when both `value` and `defaultValue` are not provided
- `onChange` – controlled state onChange handler

## Return Value

The hook returns a tuple:

1. Current value
2. Handler to update the state
3. Boolean indicating if the state is controlled

## Definition

```tsx
interface UseUncontrolledOptions<T> {
  value?: T
  defaultValue?: T
  finalValue?: T
  onChange?: (value: T) => void
}

type UseUncontrolledReturnValue<T> = [T, (value: T, ...payload: any[]) => void, boolean]

function useUncontrolled<T>(input: UseUncontrolledOptions<T>): UseUncontrolledReturnValue<T>
```

--------------------------------------------------------------------------------

### useValidatedState
Package: @tidbcloud/uikit
Import: import { useValidatedState } from '@tidbcloud/uikit';
Description: State with built-in validation.

State with built-in validation.

## Usage

`useValidatedState` validates state with a given rule each time state is set. It returns an object with the current validation state, last valid value, and current value.

```tsx

function Demo() {
  const [{ value, lastValidValue, valid }, setValue] = useValidatedState('', (val) => /^\S+@\S+$/.test(val))

  return (
    <>
      <TextInput
        value={value}
        onChange={(e) => setValue(e.currentTarget.value)}
        placeholder="Enter email"
        error={!valid && value.length > 0 ? 'Invalid email' : null}
      />
      <Text mt="md">Current value: {value}</Text>
      <Text>Last valid value: {lastValidValue}</Text>
      <Text>Valid: {valid ? 'Yes' : 'No'}</Text>
    </>
  )
}
```

## Example

```tsx

const [{ lastValidValue, value, valid }, setValue] = useValidatedState('valid', (state) => state === 'valid')

// Initial state:
// lastValidValue -> 'valid'
// value -> 'valid'
// valid -> true

setValue('invalid')

// After setting invalid value:
// lastValidValue -> 'valid'
// value -> 'invalid'
// valid -> false
```

## Definition

```tsx
interface UseValidatedStateValue<T> {
  value: T
  lastValidValue: T | undefined
  valid: boolean
}

type UseValidatedStateReturnValue<T> = [UseValidatedStateValue<T>, (value: T) => void]

function useValidatedState<T>(
  initialValue: T,
  validate: (value: T) => boolean,
  initialValidationState?: boolean
): UseValidatedStateReturnValue<T>
```

--------------------------------------------------------------------------------

### useViewportSize
Package: @tidbcloud/uikit
Import: import { useViewportSize } from '@tidbcloud/uikit';
Description: Get viewport width and height.

Get viewport width and height.

## Usage

`useViewportSize` returns current viewport's `width` and `height`, and subscribes to `resize` and `orientationchange` events.

```tsx

function Demo() {
  const { height, width } = useViewportSize()

  return (
    <Text>
      Viewport: {width}px × {height}px
    </Text>
  )
}
```

## Server Side Rendering

During SSR, the hook will return `{ width: 0, height: 0 }`.

## Definition

```tsx
function useViewportSize(): {
  height: number
  width: number
}
```

--------------------------------------------------------------------------------

### useWindowEvent
Package: @tidbcloud/uikit
Import: import { useWindowEvent } from '@tidbcloud/uikit';
Description: Add event listener to window object.

Add event listener to window object.

## Usage

`useWindowEvent` adds event listener to `window` object on component mount and removes it on unmount.

```tsx

function Demo() {
  const inputRef = useRef<HTMLInputElement>(null)

  // Focus search input with Cmd/Ctrl + K
  useWindowEvent('keydown', (event) => {
    if (event.code === 'KeyK' && (event.ctrlKey || event.metaKey)) {
      event.preventDefault()
      inputRef.current?.focus()
    }
  })

  return <TextInput ref={inputRef} placeholder="Press ⌘K to focus" />
}
```

## Comparison with useEffect

```tsx

const handler = (event: KeyboardEvent) => console.log(event)

// Regular way
useEffect(() => {
  window.addEventListener('keydown', handler)
  return () => window.removeEventListener('keydown', handler)
}, [])

// With useWindowEvent
useWindowEvent('keydown', handler)
```

## Definition

The hook has the same signature as `window.addEventListener`:

```tsx
function useWindowEvent<K extends keyof WindowEventMap>(
  type: K,
  listener: (this: Window, ev: WindowEventMap[K]) => any,
  options?: boolean | AddEventListenerOptions
): void
```

--------------------------------------------------------------------------------

### useWindowScroll
Package: @tidbcloud/uikit
Import: import { useWindowScroll } from '@tidbcloud/uikit';
Description: Track and control window scroll position.

Track and control window scroll position.

## Usage

`useWindowScroll` returns the current scroll position and a function to scroll to a given position.

```tsx

function Demo() {
  const [scroll, scrollTo] = useWindowScroll()

  return (
    <Group>
      <Text>
        Scroll position: {scroll.x}, {scroll.y}
      </Text>
      <Button onClick={() => scrollTo({ y: 0 })}>Scroll to top</Button>
    </Group>
  )
}
```

## Smooth Scroll

The `scrollTo` function scrolls smoothly to the given position:

```tsx

function Demo() {
  const [, scrollTo] = useWindowScroll()

  return <button onClick={() => scrollTo({ x: 0, y: 500 })}>Scroll to position</button>
}
```

## Definition

```tsx
interface UseWindowScrollPosition {
  x: number
  y: number
}

type UseWindowScrollTo = (position: Partial<UseWindowScrollPosition>) => void
type UseWindowScrollReturnValue = [UseWindowScrollPosition, UseWindowScrollTo]

function useWindowScroll(): UseWindowScrollReturnValue
```

--------------------------------------------------------------------------------


## ICONS
Icon components from @tidbcloud/uikit/icons
Primary Package: @tidbcloud/uikit/icons

--------------------------------------------------------------------------------

### Icons
Package: @tidbcloud/uikit/icons
Description: We also provide an icon library for convenient use. You can import and use it in the following way:

We also provide an icon library for convenient use. You can import and use it in the following way:

```js

function Demo() {
  return (
    <IconAlertCircle />
  )
}
```

To find the icon you want to use, you can visit here.

### Size

All icons are svg elements, so they support all attributes that SVG supports. Additionally, we have also supported the `size` props, to help you set the width and height of the icon more easily.

```js
function Demo() {
  return (
    <IconAlertCircle
      stroke={1.5}
      color="red"
      size={36}
    />
  );
}
```

### Custom Icon

If you want to use your own svg icon, it is recommended to wrap it as a React components, so you can pass whatever props you want for better reuse. For consistency, it is also recommended to name you icon start with `Icon`.

```js
interface IconCustomProps extends React.ComponentPropsWithoutRef<'svg'> {
  size?: number | string;
}

export function IconCustom({ size, style, ...others }: IconCustomProps) {
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      fill="none"
      stroke="currentColor"
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth="1.5"
      viewBox="0 0 24 24"
      {...others}
    >
      ...
    </svg>
  );
}
```

--------------------------------------------------------------------------------


================================================================================

## Additional Resources

- GitHub Repository: https://github.com/tidbcloud/tidbcloud-uikit
- Based on Mantine UI: https://mantine.dev

This documentation is auto-generated from the source documentation files.
Last updated: 2025-12-18
