@particle-academy/react-fancy 1.7.1 → 1.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/index.cjs +24 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +2 -0
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.js +24 -1
  6. package/dist/index.js.map +1 -1
  7. package/docs/Accordion.md +78 -0
  8. package/docs/Action.md +76 -0
  9. package/docs/Autocomplete.md +74 -0
  10. package/docs/Avatar.md +40 -0
  11. package/docs/Badge.md +42 -0
  12. package/docs/Brand.md +44 -0
  13. package/docs/Breadcrumbs.md +51 -0
  14. package/docs/Calendar.md +72 -0
  15. package/docs/Callout.md +46 -0
  16. package/docs/Canvas.md +102 -0
  17. package/docs/Card.md +68 -0
  18. package/docs/Carousel.md +97 -0
  19. package/docs/Chart.md +126 -0
  20. package/docs/Checkbox.md +86 -0
  21. package/docs/ColorPicker.md +49 -0
  22. package/docs/Command.md +88 -0
  23. package/docs/Composer.md +60 -0
  24. package/docs/ContentRenderer.md +68 -0
  25. package/docs/ContextMenu.md +82 -0
  26. package/docs/DatePicker.md +64 -0
  27. package/docs/Diagram.md +119 -0
  28. package/docs/Dropdown.md +79 -0
  29. package/docs/Editor.md +84 -0
  30. package/docs/Emoji.md +40 -0
  31. package/docs/EmojiSelect.md +47 -0
  32. package/docs/Field.md +48 -0
  33. package/docs/FileUpload.md +81 -0
  34. package/docs/Heading.md +43 -0
  35. package/docs/Icon.md +75 -0
  36. package/docs/Input.md +73 -0
  37. package/docs/Kanban.md +79 -0
  38. package/docs/Menu.md +71 -0
  39. package/docs/MobileMenu.md +69 -0
  40. package/docs/Modal.md +74 -0
  41. package/docs/MultiSwitch.md +64 -0
  42. package/docs/Navbar.md +65 -0
  43. package/docs/OtpInput.md +48 -0
  44. package/docs/Pagination.md +48 -0
  45. package/docs/Pillbox.md +53 -0
  46. package/docs/Popover.md +82 -0
  47. package/docs/Portal.md +40 -0
  48. package/docs/Profile.md +52 -0
  49. package/docs/Progress.md +42 -0
  50. package/docs/RadioGroup.md +69 -0
  51. package/docs/Select.md +122 -0
  52. package/docs/Separator.md +41 -0
  53. package/docs/Sidebar.md +88 -0
  54. package/docs/Skeleton.md +44 -0
  55. package/docs/Slider.md +75 -0
  56. package/docs/Switch.md +55 -0
  57. package/docs/Table.md +133 -0
  58. package/docs/Tabs.md +85 -0
  59. package/docs/Text.md +44 -0
  60. package/docs/Textarea.md +62 -0
  61. package/docs/TimePicker.md +45 -0
  62. package/docs/Timeline.md +118 -0
  63. package/docs/Toast.md +79 -0
  64. package/docs/Tooltip.md +46 -0
  65. package/docs/hooks.md +180 -0
  66. package/docs/utilities.md +74 -0
  67. package/package.json +2 -1
package/docs/Input.md ADDED
@@ -0,0 +1,73 @@
1
+ # Input
2
+
3
+ Text input with built-in label, error, prefix/suffix, and leading/trailing icon support.
4
+
5
+ ## Import
6
+
7
+ ```tsx
8
+ import { Input } from "@particle-academy/react-fancy";
9
+ ```
10
+
11
+ ## Basic Usage
12
+
13
+ ```tsx
14
+ <Input label="Email" type="email" placeholder="you@example.com" />
15
+ ```
16
+
17
+ ## Props
18
+
19
+ Extends all native `<input>` attributes (except `size`, `type`, `prefix`).
20
+
21
+ | Prop | Type | Default | Description |
22
+ |------|------|---------|-------------|
23
+ | `type` | `"text" \| "email" \| "password" \| "number" \| "tel" \| "url" \| "search"` | `"text"` | Input type |
24
+ | `size` | `"xs" \| "sm" \| "md" \| "lg" \| "xl"` | `"md"` | Controls input height and text size |
25
+ | `label` | `string` | - | Wraps input in a `Field` with this label |
26
+ | `description` | `string` | - | Helper text below the input |
27
+ | `error` | `string` | - | Error message (red text below input, red border) |
28
+ | `required` | `boolean` | `false` | Red asterisk on label, sets native `required` |
29
+ | `dirty` | `boolean` | `false` | Amber ring to indicate unsaved changes |
30
+ | `disabled` | `boolean` | `false` | Disables the input |
31
+ | `leading` | `ReactNode` | - | Icon/element positioned inside the input on the left |
32
+ | `trailing` | `ReactNode` | - | Icon/element positioned inside the input on the right |
33
+ | `prefix` | `ReactNode` | - | Affix rendered before the input |
34
+ | `suffix` | `ReactNode` | - | Affix rendered after the input |
35
+ | `prefixPosition` | `"inside" \| "outside"` | - | Whether prefix renders inside or outside the input border |
36
+ | `suffixPosition` | `"inside" \| "outside"` | - | Whether suffix renders inside or outside the input border |
37
+ | `onValueChange` | `(value: string) => void` | - | Convenience callback with the string value directly |
38
+ | `className` | `string` | - | Additional CSS classes on the `<input>` element |
39
+
40
+ ## Examples
41
+
42
+ ### With leading icon
43
+
44
+ ```tsx
45
+ import { Search } from "lucide-react";
46
+
47
+ <Input
48
+ label="Search"
49
+ type="search"
50
+ leading={<Search size={16} />}
51
+ placeholder="Search..."
52
+ />
53
+ ```
54
+
55
+ ### With prefix and suffix
56
+
57
+ ```tsx
58
+ <Input prefix="https://" suffix=".com" placeholder="yoursite" />
59
+ ```
60
+
61
+ ### Controlled with onValueChange
62
+
63
+ ```tsx
64
+ const [email, setEmail] = useState("");
65
+
66
+ <Input
67
+ label="Email"
68
+ type="email"
69
+ value={email}
70
+ onValueChange={setEmail}
71
+ error={email ? undefined : "Required"}
72
+ />
73
+ ```
package/docs/Kanban.md ADDED
@@ -0,0 +1,79 @@
1
+ # Kanban
2
+
3
+ A drag-and-drop kanban board using the HTML5 Drag and Drop API. Cards can be moved between columns.
4
+
5
+ ## Import
6
+
7
+ ```tsx
8
+ import { Kanban } from "@particle-academy/react-fancy";
9
+ ```
10
+
11
+ ## Basic Usage
12
+
13
+ ```tsx
14
+ <Kanban onCardMove={(cardId, from, to) => console.log(`${cardId}: ${from} -> ${to}`)}>
15
+ <Kanban.Column id="todo" title="To Do">
16
+ <Kanban.Card id="task-1">Design homepage</Kanban.Card>
17
+ <Kanban.Card id="task-2">Write tests</Kanban.Card>
18
+ </Kanban.Column>
19
+ <Kanban.Column id="in-progress" title="In Progress">
20
+ <Kanban.Card id="task-3">Build API</Kanban.Card>
21
+ </Kanban.Column>
22
+ <Kanban.Column id="done" title="Done">
23
+ <Kanban.Card id="task-4">Setup CI/CD</Kanban.Card>
24
+ </Kanban.Column>
25
+ </Kanban>
26
+ ```
27
+
28
+ ## Props
29
+
30
+ ### Kanban (root)
31
+
32
+ | Prop | Type | Default | Description |
33
+ |------|------|---------|-------------|
34
+ | onCardMove | `(cardId: string, fromColumn: string, toColumn: string) => void` | - | Callback when a card is dropped into a different column |
35
+ | className | `string` | - | Additional CSS classes |
36
+
37
+ ### Kanban.Column
38
+
39
+ | Prop | Type | Default | Description |
40
+ |------|------|---------|-------------|
41
+ | id | `string` | - | Unique column identifier (required) |
42
+ | title | `string` | - | Column header text |
43
+ | className | `string` | - | Additional CSS classes |
44
+
45
+ ### Kanban.Card
46
+
47
+ | Prop | Type | Default | Description |
48
+ |------|------|---------|-------------|
49
+ | id | `string` | - | Unique card identifier (required) |
50
+ | children | `ReactNode` | - | Card content |
51
+ | className | `string` | - | Additional CSS classes |
52
+
53
+ ## Stateful Example
54
+
55
+ ```tsx
56
+ const [columns, setColumns] = useState({
57
+ todo: ["task-1", "task-2"],
58
+ doing: ["task-3"],
59
+ done: [],
60
+ });
61
+
62
+ function handleMove(cardId: string, from: string, to: string) {
63
+ setColumns((prev) => ({
64
+ ...prev,
65
+ [from]: prev[from].filter((id) => id !== cardId),
66
+ [to]: [...prev[to], cardId],
67
+ }));
68
+ }
69
+
70
+ <Kanban onCardMove={handleMove}>
71
+ {Object.entries(columns).map(([colId, cards]) => (
72
+ <Kanban.Column key={colId} id={colId} title={colId}>
73
+ {cards.map((id) => (
74
+ <Kanban.Card key={id} id={id}>{id}</Kanban.Card>
75
+ ))}
76
+ </Kanban.Column>
77
+ ))}
78
+ </Kanban>
79
+ ```
package/docs/Menu.md ADDED
@@ -0,0 +1,71 @@
1
+ # Menu
2
+
3
+ A navigation menu supporting horizontal/vertical orientation, nested submenus, grouped items, icons, and badges.
4
+
5
+ ## Import
6
+
7
+ ```tsx
8
+ import { Menu } from "@particle-academy/react-fancy";
9
+ ```
10
+
11
+ ## Basic Usage
12
+
13
+ ```tsx
14
+ <Menu>
15
+ <Menu.Item href="/" active>Home</Menu.Item>
16
+ <Menu.Item href="/about">About</Menu.Item>
17
+ <Menu.Submenu label="Products" icon={<BoxIcon />}>
18
+ <Menu.Item href="/products/widgets">Widgets</Menu.Item>
19
+ <Menu.Item href="/products/gadgets">Gadgets</Menu.Item>
20
+ </Menu.Submenu>
21
+ </Menu>
22
+ ```
23
+
24
+ ## Props
25
+
26
+ ### Menu (root)
27
+
28
+ | Prop | Type | Default | Description |
29
+ |------|------|---------|-------------|
30
+ | orientation | `"horizontal" \| "vertical"` | `"vertical"` | Layout direction |
31
+ | className | `string` | - | Additional CSS classes |
32
+
33
+ ### Menu.Item
34
+
35
+ | Prop | Type | Default | Description |
36
+ |------|------|---------|-------------|
37
+ | children | `ReactNode` | - | Item content |
38
+ | href | `string` | - | Link URL |
39
+ | icon | `ReactNode` | - | Leading icon |
40
+ | active | `boolean` | - | Active state highlight |
41
+ | disabled | `boolean` | - | Disable the item |
42
+ | badge | `ReactNode` | - | Trailing badge element |
43
+ | onClick | `() => void` | - | Click handler |
44
+ | className | `string` | - | Additional CSS classes |
45
+
46
+ ### Menu.Submenu
47
+
48
+ | Prop | Type | Default | Description |
49
+ |------|------|---------|-------------|
50
+ | label | `ReactNode` | - | Submenu trigger label (required) |
51
+ | icon | `ReactNode` | - | Leading icon |
52
+ | defaultOpen | `boolean` | - | Whether the submenu starts open |
53
+ | className | `string` | - | Additional CSS classes |
54
+
55
+ ### Menu.Group
56
+
57
+ | Prop | Type | Default | Description |
58
+ |------|------|---------|-------------|
59
+ | children | `ReactNode` | - | Grouped items |
60
+ | label | `string` | - | Group heading |
61
+ | className | `string` | - | Additional CSS classes |
62
+
63
+ ## Horizontal Menu
64
+
65
+ ```tsx
66
+ <Menu orientation="horizontal">
67
+ <Menu.Item href="/" active>Home</Menu.Item>
68
+ <Menu.Item href="/docs">Docs</Menu.Item>
69
+ <Menu.Item href="/pricing" badge={<span>New</span>}>Pricing</Menu.Item>
70
+ </Menu>
71
+ ```
@@ -0,0 +1,69 @@
1
+ # MobileMenu
2
+
3
+ Mobile navigation components with two variants: a slide-out flyout panel and a fixed bottom tab bar.
4
+
5
+ ## Import
6
+
7
+ ```tsx
8
+ import { MobileMenu } from "@particle-academy/react-fancy";
9
+ ```
10
+
11
+ ## Flyout
12
+
13
+ A slide-out panel from the left or right edge.
14
+
15
+ ```tsx
16
+ const [open, setOpen] = useState(false);
17
+
18
+ <button onClick={() => setOpen(true)}>Menu</button>
19
+
20
+ <MobileMenu.Flyout open={open} onClose={() => setOpen(false)} side="left" title="Menu">
21
+ <MobileMenu.Item href="/" icon={<HomeIcon />} active>Home</MobileMenu.Item>
22
+ <MobileMenu.Item href="/about" icon={<InfoIcon />}>About</MobileMenu.Item>
23
+ <MobileMenu.Item href="/contact" icon={<MailIcon />}>Contact</MobileMenu.Item>
24
+ </MobileMenu.Flyout>
25
+ ```
26
+
27
+ ## Bottom Bar
28
+
29
+ A fixed bottom navigation bar for mobile.
30
+
31
+ ```tsx
32
+ <MobileMenu.BottomBar>
33
+ <MobileMenu.Item href="/" icon={<HomeIcon />} active>Home</MobileMenu.Item>
34
+ <MobileMenu.Item href="/search" icon={<SearchIcon />}>Search</MobileMenu.Item>
35
+ <MobileMenu.Item href="/profile" icon={<UserIcon />}>Profile</MobileMenu.Item>
36
+ </MobileMenu.BottomBar>
37
+ ```
38
+
39
+ ## Props
40
+
41
+ ### MobileMenu.Flyout
42
+
43
+ | Prop | Type | Default | Description |
44
+ |------|------|---------|-------------|
45
+ | open | `boolean` | - | Whether the flyout is visible (required) |
46
+ | onClose | `() => void` | - | Callback to close the flyout (required) |
47
+ | side | `"left" \| "right"` | - | Which edge the panel slides from |
48
+ | title | `string` | - | Optional header title |
49
+ | className | `string` | - | Additional CSS classes |
50
+
51
+ ### MobileMenu.BottomBar
52
+
53
+ | Prop | Type | Default | Description |
54
+ |------|------|---------|-------------|
55
+ | children | `ReactNode` | - | Menu items |
56
+ | className | `string` | - | Additional CSS classes |
57
+
58
+ ### MobileMenu.Item
59
+
60
+ | Prop | Type | Default | Description |
61
+ |------|------|---------|-------------|
62
+ | children | `ReactNode` | - | Item label |
63
+ | href | `string` | - | Link URL |
64
+ | icon | `ReactNode` | - | Icon element |
65
+ | active | `boolean` | - | Active state highlight |
66
+ | disabled | `boolean` | - | Disable the item |
67
+ | badge | `ReactNode` | - | Badge element |
68
+ | onClick | `() => void` | - | Click handler |
69
+ | className | `string` | - | Additional CSS classes |
package/docs/Modal.md ADDED
@@ -0,0 +1,74 @@
1
+ # Modal
2
+
3
+ A dialog overlay with backdrop, focus trapping, escape-to-close, and body scroll locking. Renders via a portal.
4
+
5
+ ## Import
6
+
7
+ ```tsx
8
+ import { Modal } from "@particle-academy/react-fancy";
9
+ ```
10
+
11
+ ## Basic Usage
12
+
13
+ ```tsx
14
+ const [open, setOpen] = useState(false);
15
+
16
+ <button onClick={() => setOpen(true)}>Open Modal</button>
17
+
18
+ <Modal open={open} onClose={() => setOpen(false)}>
19
+ <Modal.Header>Confirm Action</Modal.Header>
20
+ <Modal.Body>
21
+ <p>Are you sure you want to proceed?</p>
22
+ </Modal.Body>
23
+ <Modal.Footer>
24
+ <button onClick={() => setOpen(false)}>Cancel</button>
25
+ <button onClick={handleConfirm}>Confirm</button>
26
+ </Modal.Footer>
27
+ </Modal>
28
+ ```
29
+
30
+ ## Props
31
+
32
+ ### Modal (root)
33
+
34
+ | Prop | Type | Default | Description |
35
+ |------|------|---------|-------------|
36
+ | open | `boolean` | - | Whether the modal is visible (required) |
37
+ | onClose | `() => void` | - | Callback to close the modal (required) |
38
+ | size | `"sm" \| "md" \| "lg" \| "xl" \| "full"` | `"md"` | Max width of the modal panel |
39
+ | className | `string` | - | Additional CSS classes for the panel |
40
+
41
+ ### Modal.Header
42
+
43
+ | Prop | Type | Default | Description |
44
+ |------|------|---------|-------------|
45
+ | children | `ReactNode` | - | Header content |
46
+ | className | `string` | - | Additional CSS classes |
47
+
48
+ ### Modal.Body
49
+
50
+ | Prop | Type | Default | Description |
51
+ |------|------|---------|-------------|
52
+ | children | `ReactNode` | - | Body content |
53
+ | className | `string` | - | Additional CSS classes |
54
+
55
+ ### Modal.Footer
56
+
57
+ | Prop | Type | Default | Description |
58
+ |------|------|---------|-------------|
59
+ | children | `ReactNode` | - | Footer content (typically action buttons) |
60
+ | className | `string` | - | Additional CSS classes |
61
+
62
+ ## Large Modal
63
+
64
+ ```tsx
65
+ <Modal open={open} onClose={() => setOpen(false)} size="xl">
66
+ <Modal.Header>Large Content</Modal.Header>
67
+ <Modal.Body>
68
+ <p>This modal uses the xl size variant for wider content.</p>
69
+ </Modal.Body>
70
+ <Modal.Footer>
71
+ <button onClick={() => setOpen(false)}>Close</button>
72
+ </Modal.Footer>
73
+ </Modal>
74
+ ```
@@ -0,0 +1,64 @@
1
+ # MultiSwitch
2
+
3
+ Segmented control that allows selecting one value from a set of options, with an animated sliding indicator.
4
+
5
+ ## Import
6
+
7
+ ```tsx
8
+ import { MultiSwitch } from "@particle-academy/react-fancy";
9
+ ```
10
+
11
+ ## Basic Usage
12
+
13
+ ```tsx
14
+ <MultiSwitch
15
+ list={["Daily", "Weekly", "Monthly"]}
16
+ defaultValue="Weekly"
17
+ />
18
+ ```
19
+
20
+ ## Props
21
+
22
+ | Prop | Type | Default | Description |
23
+ |------|------|---------|-------------|
24
+ | `list` | `InputOption[]` | **required** | Options as strings or `{ value, label, disabled? }` |
25
+ | `value` | `V` | - | Controlled selected value |
26
+ | `defaultValue` | `V` | first option | Default selected value (uncontrolled) |
27
+ | `onValueChange` | `(value: V) => void` | - | Callback when selection changes |
28
+ | `linear` | `boolean` | `false` | When true, clicking any button cycles to the next option instead of selecting the clicked one |
29
+ | `label` | `string` | - | Wraps in a `Field` with this label |
30
+ | `description` | `string` | - | Helper text |
31
+ | `error` | `string` | - | Error message |
32
+ | `size` | `"xs" \| "sm" \| "md" \| "lg" \| "xl"` | `"md"` | Controls padding and text size |
33
+ | `dirty` | `boolean` | `false` | Amber ring |
34
+ | `disabled` | `boolean` | `false` | Disables all options |
35
+ | `name` | `string` | - | Form field name (renders a hidden input) |
36
+ | `className` | `string` | - | Additional CSS classes |
37
+
38
+ ## Examples
39
+
40
+ ### Controlled with label
41
+
42
+ ```tsx
43
+ const [interval, setInterval] = useState("monthly");
44
+
45
+ <MultiSwitch
46
+ label="Billing interval"
47
+ list={[
48
+ { value: "monthly", label: "Monthly" },
49
+ { value: "yearly", label: "Yearly" },
50
+ ]}
51
+ value={interval}
52
+ onValueChange={setInterval}
53
+ />
54
+ ```
55
+
56
+ ### Linear cycling
57
+
58
+ ```tsx
59
+ <MultiSwitch
60
+ linear
61
+ list={["Off", "Low", "Medium", "High"]}
62
+ defaultValue="Off"
63
+ />
64
+ ```
package/docs/Navbar.md ADDED
@@ -0,0 +1,65 @@
1
+ # Navbar
2
+
3
+ A top navigation bar with brand slot, navigation items, and a mobile hamburger toggle.
4
+
5
+ ## Import
6
+
7
+ ```tsx
8
+ import { Navbar } from "@particle-academy/react-fancy";
9
+ ```
10
+
11
+ ## Basic Usage
12
+
13
+ ```tsx
14
+ <Navbar>
15
+ <Navbar.Brand>
16
+ <a href="/">MyApp</a>
17
+ </Navbar.Brand>
18
+ <Navbar.Items>
19
+ <Navbar.Item href="/" active>Home</Navbar.Item>
20
+ <Navbar.Item href="/about">About</Navbar.Item>
21
+ <Navbar.Item href="/contact">Contact</Navbar.Item>
22
+ </Navbar.Items>
23
+ <Navbar.Toggle />
24
+ </Navbar>
25
+ ```
26
+
27
+ ## Props
28
+
29
+ ### Navbar (root)
30
+
31
+ | Prop | Type | Default | Description |
32
+ |------|------|---------|-------------|
33
+ | children | `ReactNode` | - | Brand, items, toggle children |
34
+ | className | `string` | - | Additional CSS classes |
35
+
36
+ ### Navbar.Brand
37
+
38
+ | Prop | Type | Default | Description |
39
+ |------|------|---------|-------------|
40
+ | children | `ReactNode` | - | Logo or brand element |
41
+ | className | `string` | - | Additional CSS classes |
42
+
43
+ ### Navbar.Items
44
+
45
+ | Prop | Type | Default | Description |
46
+ |------|------|---------|-------------|
47
+ | children | `ReactNode` | - | Navigation items |
48
+ | className | `string` | - | Additional CSS classes |
49
+
50
+ ### Navbar.Item
51
+
52
+ | Prop | Type | Default | Description |
53
+ |------|------|---------|-------------|
54
+ | children | `ReactNode` | - | Item content |
55
+ | href | `string` | - | Link URL |
56
+ | active | `boolean` | - | Active/current page indicator |
57
+ | className | `string` | - | Additional CSS classes |
58
+
59
+ ### Navbar.Toggle
60
+
61
+ | Prop | Type | Default | Description |
62
+ |------|------|---------|-------------|
63
+ | className | `string` | - | Additional CSS classes |
64
+
65
+ The Navbar manages a `mobileOpen` state internally. `Navbar.Toggle` toggles the mobile navigation drawer, and `Navbar.Items` responds to that state.
@@ -0,0 +1,48 @@
1
+ # OtpInput
2
+
3
+ One-time password input with individual digit cells, auto-advance, and paste support.
4
+
5
+ ## Import
6
+
7
+ ```tsx
8
+ import { OtpInput } from "@particle-academy/react-fancy";
9
+ ```
10
+
11
+ ## Basic Usage
12
+
13
+ ```tsx
14
+ <OtpInput length={6} onChange={(code) => console.log(code)} />
15
+ ```
16
+
17
+ ## Props
18
+
19
+ | Prop | Type | Default | Description |
20
+ |------|------|---------|-------------|
21
+ | `length` | `number` | `6` | Number of digit cells |
22
+ | `value` | `string` | - | Controlled value |
23
+ | `onChange` | `(value: string) => void` | - | Callback with the full OTP string |
24
+ | `disabled` | `boolean` | `false` | Disables all inputs |
25
+ | `autoFocus` | `boolean` | `false` | Auto-focus the first cell on mount |
26
+ | `className` | `string` | - | Additional CSS classes on the container |
27
+
28
+ **Behavior:**
29
+ - Only numeric digits are accepted.
30
+ - Focus advances to the next cell after input.
31
+ - **Backspace** clears the current cell, or moves to the previous cell if already empty.
32
+ - **Arrow keys** move focus between cells.
33
+ - **Paste** fills cells from the clipboard (non-numeric characters are stripped).
34
+
35
+ ## Examples
36
+
37
+ ### 4-digit code with auto-focus
38
+
39
+ ```tsx
40
+ const [code, setCode] = useState("");
41
+
42
+ <OtpInput
43
+ length={4}
44
+ autoFocus
45
+ value={code}
46
+ onChange={setCode}
47
+ />
48
+ ```
@@ -0,0 +1,48 @@
1
+ # Pagination
2
+
3
+ A page navigation component with previous/next buttons, page numbers, and ellipsis for large ranges.
4
+
5
+ ## Import
6
+
7
+ ```tsx
8
+ import { Pagination } from "@particle-academy/react-fancy";
9
+ ```
10
+
11
+ ## Basic Usage
12
+
13
+ ```tsx
14
+ <Pagination page={1} totalPages={10} onPageChange={setPage} />
15
+ ```
16
+
17
+ ## Props
18
+
19
+ | Prop | Type | Default | Description |
20
+ |------|------|---------|-------------|
21
+ | page | `number` | **required** | Current active page (1-based) |
22
+ | onPageChange | `(page: number) => void` | **required** | Callback when a page is selected |
23
+ | totalPages | `number` | **required** | Total number of pages |
24
+ | siblingCount | `number` | `1` | Number of sibling pages shown around the current page |
25
+ | className | `string` | - | Additional CSS classes |
26
+
27
+ Renders `null` when `totalPages <= 1`. Automatically inserts ellipsis when the page count exceeds the visible slot count.
28
+
29
+ ## Examples
30
+
31
+ ### Basic pagination
32
+
33
+ ```tsx
34
+ const [page, setPage] = useState(1);
35
+
36
+ <Pagination page={page} totalPages={20} onPageChange={setPage} />
37
+ ```
38
+
39
+ ### More visible siblings
40
+
41
+ ```tsx
42
+ <Pagination
43
+ page={page}
44
+ totalPages={50}
45
+ onPageChange={setPage}
46
+ siblingCount={2}
47
+ />
48
+ ```
@@ -0,0 +1,53 @@
1
+ # Pillbox
2
+
3
+ Tag/pill input that lets users type free-text values and manage them as removable pills.
4
+
5
+ ## Import
6
+
7
+ ```tsx
8
+ import { Pillbox } from "@particle-academy/react-fancy";
9
+ ```
10
+
11
+ ## Basic Usage
12
+
13
+ ```tsx
14
+ <Pillbox placeholder="Add tags..." onChange={(tags) => console.log(tags)} />
15
+ ```
16
+
17
+ ## Props
18
+
19
+ | Prop | Type | Default | Description |
20
+ |------|------|---------|-------------|
21
+ | `value` | `string[]` | - | Controlled list of items |
22
+ | `defaultValue` | `string[]` | `[]` | Default items (uncontrolled) |
23
+ | `onChange` | `(values: string[]) => void` | - | Callback when items change |
24
+ | `placeholder` | `string` | `"Type and press Enter..."` | Placeholder (shown only when no items exist) |
25
+ | `maxItems` | `number` | - | Maximum number of items allowed |
26
+ | `disabled` | `boolean` | `false` | Disables input and removal |
27
+ | `className` | `string` | - | Additional CSS classes |
28
+
29
+ **Behavior:**
30
+ - Press **Enter** to add the current text as a pill. Duplicates and empty strings are ignored.
31
+ - Press **Backspace** on an empty input to remove the last pill.
32
+ - Click the **X** on any pill to remove it.
33
+
34
+ ## Examples
35
+
36
+ ### With max items
37
+
38
+ ```tsx
39
+ <Pillbox
40
+ placeholder="Add up to 5 skills..."
41
+ maxItems={5}
42
+ defaultValue={["React", "TypeScript"]}
43
+ onChange={setSkills}
44
+ />
45
+ ```
46
+
47
+ ### Controlled
48
+
49
+ ```tsx
50
+ const [emails, setEmails] = useState<string[]>([]);
51
+
52
+ <Pillbox value={emails} onChange={setEmails} placeholder="Add email addresses..." />
53
+ ```