@datawire-ai/busyfile-design-library
v1.30.10
Published
Design system for busyfile
Keywords
Readme
BusyFile Design System
Design system library for Busyfile Applications
Installation
Design system library for Busyfile Applications
Installation
# Using npm
npm install busyfile-design-system
# Using pnpm
pnpm add busyfile-design-systemDevelopment
Development
Prerequisites
- Node.js - v22.19
- pnpm - v10.15
- Node.js - v22.19
- pnpm - v10.15
Setup
# Clone the repository
git clone https://github.com/your-username/busyfile-design-system.git
cd busyfile-design-system
# Install dependencies
pnpm install
# Start development server
pnpm dev
# Start Storybook
pnpm storybook
# Build the library
pnpm build
# Run tests
pnpm testDevelopment Workflow
- Fork the repository
- Create a feature branch
- Make your changes
- Create changeset
pnpm changeset:add&pnpm changeset version - Submit a pull request
PRs & Changeset Process
- [ ] Do not run
changesetuntil your PR is ready for merge- [ ] Complete all required changes
- [ ] Apply PR review feedback
- [ ] Get the PR reviewed
- [ ] Once reviews are done and PR is approved
- [ ] Run the
changesetscripts - [ ] Get the PR reviewed and approved again
- [ ] Merge into
main
- [ ] Run the
- [ ] If you receive comments after creating a
changeset- [ ] Delete the generated
changesetfiles - [ ] Apply PR feedback
- [ ] Push the changes and get them reviewed again
- [ ] Repeat until the PR is ready for merge into
main
- [ ] Delete the generated
- [ ] Do not publish from your local on npm
Development Workflow
- Fork the repository
- Create a feature branch
- Make your changes
- Create changeset
pnpm changeset:add&pnpm changeset version - Submit a pull request
PRs & Changeset Process
- [ ] Do not run
changesetuntil your PR is ready for merge- [ ] Complete all required changes
- [ ] Apply PR review feedback
- [ ] Get the PR reviewed
- [ ] Once reviews are done and PR is approved
- [ ] Run the
changesetscripts - [ ] Get the PR reviewed and approved again
- [ ] Merge into
main
- [ ] Run the
- [ ] If you receive comments after creating a
changeset- [ ] Delete the generated
changesetfiles - [ ] Apply PR feedback
- [ ] Push the changes and get them reviewed again
- [ ] Repeat until the PR is ready for merge into
main
- [ ] Delete the generated
- [ ] Do not publish from your local on npm
Project Structure
src/
├── components/ # React components
│ └── ui/
│ ├── badge/ # Badge component
│ │ ├── badge.tsx
│ │ ├── badge.types.ts
│ │ ├── badge.utils.ts
│ │ └── badge.test.tsx
├── badge.stories.tsx
│ ├── button/ # Button component
│ │ ├── button.tsx
│ │ ├── button.types.ts
│ │ ├── button.utils.ts
│ │ └── button.test.tsx
| ├── button.stories.tsx
│ ├── divider/ # Divider component
│ │ ├── divider.tsx
│ │ ├── divider.types.ts
│ │ └── divider.test.tsx
| ├── divider.stories.tsx
│ └── index.ts # Component exports
├── lib/ # Utility functions
│ └── utils.ts
├── styles/
│ └── style.css # Global styles
├── App.tsx # Demo application
├── main.tsx # Application entry point
└── index.ts # Main package exports
│ └── ui/
│ ├── badge/ # Badge component
│ │ ├── badge.tsx
│ │ ├── badge.types.ts
│ │ ├── badge.utils.ts
│ │ └── badge.test.tsx
├── badge.stories.tsx
│ ├── button/ # Button component
│ │ ├── button.tsx
│ │ ├── button.types.ts
│ │ ├── button.utils.ts
│ │ └── button.test.tsx
| ├── button.stories.tsx
│ ├── divider/ # Divider component
│ │ ├── divider.tsx
│ │ ├── divider.types.ts
│ │ └── divider.test.tsx
| ├── divider.stories.tsx
│ └── index.ts # Component exports
├── lib/ # Utility functions
│ └── utils.ts
├── styles/
│ └── style.css # Global styles
├── App.tsx # Demo application
├── main.tsx # Application entry point
└── index.ts # Main package exports
Testing
Testing
# Run all tests
pnpm test
# Run tests in watch mode
pnpm test:watch
# Run tests with coverage
pnpm test:coverage
# Run tests in browser
pnpm test:browserStorybook
Storybook
Storybook provides an interactive playground for all components:
# Start Storybook
pnpm storybook
# Build Storybook
pnpm build-storybookVisit http://localhost:6006 to explore components, test props, and see examples.
Configuration
Configuration
Tailwind CSS
The design system includes a pre-configured Tailwind CSS setup. You can extend it in your project:
// tailwind.config.js
module.exports = {
content: [
'./src/**/*.{js,ts,jsx,tsx}',
'./node_modules/busyfile-design-system/**/*.{js,ts,jsx,tsx}',
'./src/**/*.{js,ts,jsx,tsx}',
'./node_modules/busyfile-design-system/**/*.{js,ts,jsx,tsx}',
],
theme: {
extend: {
// Your custom theme extensions
},
},
},
plugins: [],
};
plugins: [],
};Typography
The BusyFile Design System provides a consistent typography scale based on Nunito with predefined sizes and line-heights from Figma.
| Token | Font Size | Line Height | Example Class |
| ------------------- | --------- | ----------- | ----------------- |
| --text-display-lg | 3rem | 1.2rem | text-display-lg |
| --text-display-md | 2.25rem | 1.2rem | text-display-md |
| --text-display-sm | 1.875rem | 1.2rem | text-display-sm |
| --text-display-xs | 1.5rem | 1.2rem | text-display-xs |
| --text-xl | 1.25rem | 1.6rem | text-xl |
| --text-lg | 1.125rem | 1.6rem | text-lg |
| --text-md | 1rem | 1.6rem | text-md |
| --text-sm | 0.875rem | 1.6rem | text-sm |
| --text-xs | 0.75rem | 1.6rem | text-xs |
Usage
Colors
The BusyFile Design System defines a unified color palette for primary, neutral, and semantic states. These tokens can be used directly as Tailwind utility classes like bg-primary-30 or text-neutral-60.
Primary Colors
| Token | Hex | Example Class |
| -------------------- | --------- | --------------- |
| --color-primary-0 | #36060a | bg-primary-0 |
| --color-primary-10 | #6a131d | bg-primary-10 |
| --color-primary-20 | #a52432 | bg-primary-20 |
| --color-primary-30 | #e33549 | bg-primary-30 |
| --color-primary-40 | #f17b83 | bg-primary-40 |
| --color-primary-50 | #f5b5b9 | bg-primary-50 |
| --color-primary-60 | #fceaea | bg-primary-60 |
Neutral Colors
| Token | Hex | Example Class |
| -------------------- | --------- | --------------- |
| --color-neutral-0 | #0a0a0a | bg-neutral-0 |
| --color-neutral-10 | #1f1f1f | bg-neutral-10 |
| --color-neutral-20 | #333333 | bg-neutral-20 |
| --color-neutral-30 | #474747 | bg-neutral-30 |
| --color-neutral-40 | #5c5c5c | bg-neutral-40 |
| --color-neutral-50 | #707070 | bg-neutral-50 |
| --color-neutral-60 | #858585 | bg-neutral-60 |
| --color-neutral-70 | #999999 | bg-neutral-70 |
| --color-neutral-80 | #adadad | bg-neutral-80 |
| --color-neutral-90 | #c2c2c2 | bg-neutral-90 |
| --color-neutral-95 | #d6d6d6 | bg-neutral-95 |
| --color-neutral-99 | #f1f1f1 | bg-neutral-99 |
Semantic Colors
| State | Light | Dark | Example Classes |
| ----------- | --------- | --------- | ------------------------------ |
| Error | #f9dcdf | #bf2234 | bg-error-l, bg-error-d |
| Warning | #fbf2da | #e8b321 | bg-warning-l, bg-warning-d |
| Success | #c5fce3 | #099a59 | bg-success-l, bg-success-d |
Usage
<div className="bg-primary-30 text-white p-4 rounded">
Primary Button
</div>
<div className="bg-error-d text-white p-4 rounded">
Error Alert
</div>Card
The Card component provides a flexible and styled container for displaying grouped content consistently across your application.
It supports multiple visual variants and customizable shadow colors via both theme variables and direct color values.
Usage
import { Card } from '@/components/ui/card';
export function Example() {
return (
<section className="space-y-6">
{/* Widget 1 - Inner Shadow */}
<Card variant="widget-1" shadowColor="#3649EA">
<h3 className="text-lg font-semibold">Widget 1 Card</h3>
<p>This card uses an inner shadow and supports a custom inset color.</p>
</Card>
{/* Widget 2 - Border with Shadow */}
<Card variant="widget-2">
<h3 className="text-lg font-semibold">Widget 2 Card</h3>
<p>This card has a border with a subtle drop shadow.</p>
</Card>
</section>
);
}| Prop | Type | Default | Description |
| ------------- | ----------------------------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| variant | "widget-1" | "widget-2" | "widget-1" | Determines the visual style of the card. |
| shadowColor | string | undefined | Optional. Accepts either a HEX value (e.g. #3649EA) or a theme color variable (e.g. var(--color-primary-1)) to customize the inner shadow color for widget-1. |
| asChild | boolean | false | If true, renders the component as a child element using Radix’s <Slot> for better composition. |
| className | string | undefined | Adds custom class names for additional styling. |
| children | React.ReactNode | — | Content inside the card. |
| ...props | React.HTMLAttributes<HTMLElement> | — | Additional HTML attributes are spread onto the root element. |
Toggle Button
A customizable and accessible toggle button (switch) component. Supports both controlled (Toggle) and uncontrolled/stateful (StatefulToggle) usage.
Usage
// Controlled toggle
'use client';
import * as React from 'react';
import { Toggle } from '@/components/ui/toggle-button';
export default function Example() {
const [checked, setChecked] = React.useState(false);
return (
<div className="flex items-center gap-3">
<Toggle
id="dark-mode"
checked={checked}
onCheckedChange={setChecked}
className="data-[state=checked]:bg-green-500 data-[state=unchecked]:bg-gray-300"
/>
<label
htmlFor="dark-mode"
className="cursor-pointer select-none text-sm font-medium"
>
Enable Dark Mode
</label>
</div>
);
}Props
| Prop | Type | Default | Description |
| ----------------- | --------------------------------------------------- | ------- | --------------------------------------------------------------- |
| checked | boolean | false | Controls the switch state (on/off). |
| defaultChecked | boolean | false | Sets the initial state when using the switch uncontrolled. |
| onCheckedChange | (checked: boolean) => void | — | Callback function fired when the checked state changes. |
| disabled | boolean | false | Disables the switch if true. |
| id | string | — | Used to pair the switch with a <label> for accessibility. |
| className | string | — | Apply custom Tailwind/utility classes. |
| ...props | React.ComponentProps<typeof SwitchPrimitive.Root> | — | Any additional props supported by Radix SwitchPrimitive.Root. |
Radio Button
A radio button is a user interface element that allows the user to select one option from a list of mutually exclusive options. They are typically used in interfaces where the user needs to choose a single option from a set of options, such as in a survey or form.
Usage
'use client';
import { RadioGroup, RadioGroupItem } from './radio-button';
export default function Example() {
return (
<RadioGroup defaultValue="option1" className="flex flex-col gap-3">
<RadioGroupItem value="option1">Option 1</RadioGroupItem>
<RadioGroupItem value="option2">Option 2</RadioGroupItem>
<RadioGroupItem value="option3" disabled>
Option 3 (Disabled)
</RadioGroupItem>
</RadioGroup>
);
}Props
| Prop | Type | Default | Description |
| --------------- | ------------------------- | -------- | --------------------------------------------- |
| value | string | – | Controlled value of the selected radio. |
| defaultValue | string | – | Uncontrolled initial value. |
| onValueChange | (value: string) => void | – | Callback fired when the value changes. |
| name | string | auto-gen | Name for the underlying native radio inputs. |
| disabled | boolean | false | Disables all radios inside the group. |
| className | string | – | Tailwind/custom classes for the root wrapper. |
| children | React.ReactNode | – | One or more <RadioGroupItem />. |
The Skeleton component is used to display a placeholder while content is loading. It supports custom dimensions, border radius, and animations.
It also includes a SkeletonText variant for rendering multiple placeholder text lines.
Usage
import { Skeleton, SkeletonText } from "@/components/ui/skeleton";
// Basic skeleton block
<Skeleton width={120} height={20} />
// Rounded skeleton (e.g., avatar)
<Skeleton width={40} height={40} borderRadius="50%" />
// Animated skeleton
<Skeleton width="100%" height={16} animation="pulse" />
// Multi-line skeleton text
<SkeletonText lines={3} />Props
| Prop | Type | Default | Description |
| -------------- | ---------------------- | ------- | ------------------------------------ |
| className | string | - | Custom classes for styling. |
| animation | "shimmer" \| "pulse" | - | Animation style for skeleton. |
| width | number \| string | - | Width of the skeleton (px, %, etc.). |
| height | number \| string | - | Height of the skeleton. |
| borderRadius | number \| string | 4px | Border radius (px or CSS value). |
| style | React.CSSProperties | - | Inline styles override. |
Typography
The BusyFile Design System provides a consistent typography scale based on Nunito with predefined sizes and line-heights from Figma.
| Token | Font Size | Line Height | Example Class |
| ------------------- | --------- | ----------- | ----------------- |
| --text-display-lg | 3rem | 1.2rem | text-display-lg |
| --text-display-md | 2.25rem | 1.2rem | text-display-md |
| --text-display-sm | 1.875rem | 1.2rem | text-display-sm |
| --text-display-xs | 1.5rem | 1.2rem | text-display-xs |
| --text-xl | 1.25rem | 1.6rem | text-xl |
| --text-lg | 1.125rem | 1.6rem | text-lg |
| --text-md | 1rem | 1.6rem | text-md |
| --text-sm | 0.875rem | 1.6rem | text-sm |
| --text-xs | 0.75rem | 1.6rem | text-xs |
Usage
Colors
The BusyFile Design System defines a unified color palette for primary, neutral, and semantic states. These tokens can be used directly as Tailwind utility classes like bg-primary-30 or text-neutral-60.
Primary Colors
| Token | Hex | Example Class |
| -------------------- | --------- | --------------- |
| --color-primary-0 | #36060a | bg-primary-0 |
| --color-primary-10 | #6a131d | bg-primary-10 |
| --color-primary-20 | #a52432 | bg-primary-20 |
| --color-primary-30 | #e33549 | bg-primary-30 |
| --color-primary-40 | #f17b83 | bg-primary-40 |
| --color-primary-50 | #f5b5b9 | bg-primary-50 |
| --color-primary-60 | #fceaea | bg-primary-60 |
Neutral Colors
| Token | Hex | Example Class |
| -------------------- | --------- | --------------- |
| --color-neutral-0 | #0a0a0a | bg-neutral-0 |
| --color-neutral-10 | #1f1f1f | bg-neutral-10 |
| --color-neutral-20 | #333333 | bg-neutral-20 |
| --color-neutral-30 | #474747 | bg-neutral-30 |
| --color-neutral-40 | #5c5c5c | bg-neutral-40 |
| --color-neutral-50 | #707070 | bg-neutral-50 |
| --color-neutral-60 | #858585 | bg-neutral-60 |
| --color-neutral-70 | #999999 | bg-neutral-70 |
| --color-neutral-80 | #adadad | bg-neutral-80 |
| --color-neutral-90 | #c2c2c2 | bg-neutral-90 |
| --color-neutral-95 | #d6d6d6 | bg-neutral-95 |
| --color-neutral-99 | #f1f1f1 | bg-neutral-99 |
Semantic Colors
| State | Light | Dark | Example Classes |
| ----------- | --------- | --------- | ------------------------------ |
| Error | #f9dcdf | #bf2234 | bg-error-l, bg-error-d |
| Warning | #fbf2da | #e8b321 | bg-warning-l, bg-warning-d |
| Success | #c5fce3 | #099a59 | bg-success-l, bg-success-d |
Usage
<div className="bg-primary-30 text-white p-4 rounded">
Primary Button
</div>
<div className="bg-error-d text-white p-4 rounded">
Error Alert
</div>
## Badge
The `Badge` component is used to display small status indicators, tags, or labels.
It supports multiple variants, types `(filled / outline)`, and accepts custom children (icons, avatars, flags, etc.).
### Usage
tsx
{/_ Outline badges _/} Outlined
{/_ With icons _/} ✔ Success with Icon
# Checkbox
The `Checkbox` is a user interface element that allows the user to select one or more options from a list of independent options. They are typically used in interfaces where the user needs to choose one or more options from a set of options, such as in a filter menu.
## Usage
```tsx
import { Checkbox } from '@/components/ui/checkbox';
export function Example() {
return (
<div className="flex items-center gap-2">
<Checkbox id="terms" />
<label htmlFor="terms" className="text-sm text-neutral-black-1">
Accept terms and conditions
</label>
</div>
);
}
### Props
| Prop | Type | Default | Description |
| ----------------- | ----------------------------------------------- | ------- | -------------------------------------------------------------- |
| `className` | `string` | `—` | Custom class names for styling. |
| `checked` | `boolean \| "indeterminate"` | `—` | Controlled state of the checkbox. |
| `defaultChecked` | `boolean` | `false` | Uncontrolled initial checked state. |
| `disabled` | `boolean` | `false` | Disables the checkbox when true. |
| `onCheckedChange` | `(checked: boolean \| "indeterminate") => void` | `—` | Callback fired when the checked state changes. |
| `id` | `string` | `—` | Used to associate the checkbox with a `<label>` via `htmlFor`. |
| `name` | `string` | `—` | Name of the checkbox input (useful in forms). |
| `value` | `string` | `—` | Value associated with the checkbox input. |
# Timeline
A flexible and customizable timeline component built with React. Supports different visual styles (`filled`, `outlined`, and `icon`), visited/unvisited states, connectors, and custom content.
## Usage
```tsx
import { Timeline } from '@/components/timeline';
import { CheckCircle } from 'lucide-react';
<Timeline
variant="icon"
items={[
{
id: 'step-1',
title: 'Step 1',
description: 'This is the first step of the process.',
icon: <CheckCircle size={16} />,
},
{
id: 'step-2',
title: 'Step 2',
description: 'This step contains extra details.',
content: <CustomComponent />,
icon: <CheckCircle size={16} />,
},
{
id: 'step-3',
title: 'Step 3',
notVisited: true,
icon: <CheckCircle size={16} />,
},
]}
/>;
```
### Props
| Prop | Type | Default | Description |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `items` | `Array<{ id: string; title: string; description?: string; content?: React.ReactNode; icon?: React.ReactNode; notVisited?: boolean }>` | **Required** | Timeline steps data. Each item requires a unique `id` and `title`. Optional fields include `description`, `content`, `icon`, and `notVisited`. |
| `variant` | `"filled" \| "outlined" \| "icon"` | `"filled"` | Style variant of the timeline dot. `"icon"` allows passing a custom `icon` for each item. |
| `className` | `string` | `-` | Custom classes for the root wrapper. |
# Button
The `Button` component is a core interactive element in the design system. It supports multiple variants, sizes, and icons while ensuring accessibility and consistency.
## Usage
```tsx
<Button variant="default">Default</Button>
<Button variant="primary">Primary</Button>
<Button variant="outline" size="sm">Outline Small</Button>
<Button size="icon"><Icon /></Button>
```
## Badge
The `Badge` component is used to display small status indicators, tags, or labels.
It supports multiple variants, types `(filled / outline)`, and accepts custom children (icons, avatars, flags, etc.).
### Usage
```tsx
<div className="flex gap-2 flex-wrap">
<Badge variant="primary">Primary</Badge>
<Badge variant="success">Success</Badge>
<Badge variant="warning">Warning</Badge>
<Badge variant="error">Error</Badge>
<Badge variant="gray">Gray</Badge>
<Badge variant="blue">Blue</Badge>
<Badge variant="purple">Purple</Badge>
<Badge variant="pink">Pink</Badge>
<Badge variant="rose">Rose</Badge>
{/* Outline badges */}
<Badge variant="blue" type="outline">
Outlined
</Badge>
{/* With icons */}
<Badge variant="success">
<span className="mr-1">✔</span>
Success with Icon
</Badge>
</div>
```
| Prop | Type | Default | Description |
| ---------- | ---------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------- |
| `variant` | `"primary" \| "success" \| "warning" \| "error" \| "secondary" \| "neutral"` | `"primary"` | Color style of the badge. |
| `type` | `"filled" \| "outline"` | `"filled"` | Whether the badge is filled or outlined. |
| `children` | `React.ReactNode` | — | Content inside the badge (text, icons, avatars, flags, etc.). |
## Divider
The `Divider` component is used to separate content visually.
It supports `vertical` and `horizontal` orientations, with configurable thickness (size) and custom width/height.
```tsx
<div className="flex flex-col gap-4">
{/* Horizontal Divider */}
<Divider orientation="horizontal" size={2} />
{/* Vertical Divider */}
<div className="flex items-center gap-4">
<span>Left</span>
<Divider orientation="vertical" size={2} height={40} />
<span>Right</span>
</div>
</div>
```
| Prop | Type | Default | Description |
| ------------- | ---------------------------- | -------------- | --------------------------------------------------------------------- |
| `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | Orientation of the divider. |
| `size` | `1 \| 2 \| 3 \| 4` | `1` | Thickness of the divider (height for horizontal, width for vertical). |
| `color` | `string` | `#D9DAE4` | Color of the divider line. |
### BreadCrumb
A `breadcrumb` is a navigational element that helps users understand their current location within a website or application. Breadcrumbs enhance user experience by providing a clear path for navigation, allowing users to backtrack easily or move up within the site's hierarchy.
## Usage
```tsx
import {
Breadcrumb,
BreadcrumbList,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbPage,
BreadcrumbSeparator,
BreadcrumbEllipsis,
} from '@/components/ui/breadcrumb';
export default function Example() {
return (
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink href="/projects">Projects</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Project Alpha</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
);
}
```
### Props
| Component | Props | Description |
| ----------------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| **Breadcrumb** | All native `nav` props | Root container with `aria-label="breadcrumb"`. |
| **BreadcrumbList** | `className?` + all native `ol` props | Wrapper for breadcrumb items (`<ol>`). Adds spacing & layout classes. |
| **BreadcrumbItem** | `className?` + all native `li` props | Represents each breadcrumb node (`<li>`). |
| **BreadcrumbLink** | `asChild?: boolean`, `className?`, all native `a` props | Renders a link. If `asChild` is true, uses Radix `Slot` instead of `<a>`. |
| **BreadcrumbPage** | `className?` + all native `span` props | Represents the current page. Adds `aria-current="page"`. |
| **BreadcrumbSeparator** | `children?` (defaults to `<ChevronRight />`), `className?`, native `li` props | Separator between items. You can replace with custom icon/text. |
| **BreadcrumbEllipsis** | `className?` + all native `span` props | Renders an ellipsis with `MoreHorizontal` icon for collapsed paths. |
### Stepper
A re-usable stepper component to lead users through multi-step workflows (checkout, sign-up, forms, etc.).
Supports numeric, dots, progress, and labeled versions.
### Example
```tsx
const steps = [
{ title: 'Account Setup' },
{ title: 'Profile Info' },
{ title: 'Preferences' },
{ title: 'Confirmation' },
];
export default function Example() {
return (
<div className="space-y-6">
{/* Numeric */}
<Stepper steps={steps} variant="numeric" />
{/* Dots */}
<Stepper steps={steps} variant="dots" />
{/* Progress */}
<Stepper steps={steps} variant="progress" />
{/* Labeled */}
<Stepper steps={steps} variant="labeled" />
</div>
);
}
```
## Props
| Prop | Type | Default | Description |
| -------------- | ------------------------ | ----------- | ---------------------------------- | ---------- | ----------- | --------------------------- |
| `steps` | `{ title?: string }[]` | `[]` | Steps with optional labels |
| `variant` | `"numeric" | "dots" | "progress" | "labeled"` | `"numeric"` | Visual style of the stepper |
| `initialStep` | `number` | `0` | Starting step index |
| `onStepChange` | `(step: number) => void` | `undefined` | Callback when step changes |
| `showControls` | `boolean` | `true` | Show back/next navigation controls |
| `className` | `string` | `undefined` | Additional Tailwind classes |
### SelectOption
A custom dropdown supporting single, multi(with chips), and grouped selections. Built with React and Tailwind CSS.
### Usage
```tsx
import { useState } from 'react';
import { SelectOption } from '@/components/select-option';
const options = [
{ label: 'Option 1', value: 'opt1' },
{ label: 'Option 2', value: 'opt2' },
];
export default function Demo() {
const [single, setSingle] = useState('');
const [multi, setMulti] = useState<string[]>([]);
return (
<>
<SelectOption
options={options}
value={single}
onChange={(val) => setSingle(val as string)}
placeholder="Single select"
/>
<SelectOption
options={options}
multiple
value={multi}
onChange={(val) => setMulti(val as string[])}
placeholder="Multi select"
/>
</>
);
}
```
### Props
| Prop | Type | Default | Description |
| ------------- | ----------------------------------------- | ------------- | ------------------------------------------ |
| `options` | `SelectOptionType[] \| SelectGroupType[]` | required | List of options (flat or grouped) |
| `multiple` | `boolean` | `false` | Enables multi-select with chips |
| `placeholder` | `string` | `"Select..."` | Placeholder text when no value is selected |
| `disabled` | `boolean` | `false` | Disables the select |
| `error` | `string` | `undefined` | Error message, highlights border |
| `helperText` | `string` | `undefined` | Helper text shown below the select |
| `value` | `string \| string[]` | internal | Controlled value |
| `onChange` | `(value: string \| string[]) => void` | optional | Callback when value changes |
### TypeScript
Full TypeScript support is included. No additional types package needed.
## Building
```tsx
bash
# Build for production
pnpm build
# Build types
pnpm build:types
# Build Storybook
pnpm build-storybook
```
Made with ❤️ by the BusyFile team