@g4rcez/components 3.0.0 → 3.0.1

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 (176) hide show
  1. package/dist/ai/SKILL.md +266 -0
  2. package/dist/ai/docs/Alert.md +167 -0
  3. package/dist/ai/docs/AnimatedList.md +205 -0
  4. package/dist/ai/docs/Autocomplete.md +225 -0
  5. package/dist/ai/docs/Button.md +182 -0
  6. package/dist/ai/docs/Calendar.md +219 -0
  7. package/dist/ai/docs/Card.md +174 -0
  8. package/dist/ai/docs/Checkbox.md +199 -0
  9. package/dist/ai/docs/CommandPalette.md +293 -0
  10. package/dist/ai/docs/DatePicker.md +171 -0
  11. package/dist/ai/docs/Dropdown.md +223 -0
  12. package/dist/ai/docs/Empty.md +163 -0
  13. package/dist/ai/docs/Expand.md +143 -0
  14. package/dist/ai/docs/FileUpload.md +225 -0
  15. package/dist/ai/docs/Form.md +107 -0
  16. package/dist/ai/docs/FormReset.md +117 -0
  17. package/dist/ai/docs/Heading.md +88 -0
  18. package/dist/ai/docs/Input.md +237 -0
  19. package/dist/ai/docs/InputField.md +170 -0
  20. package/dist/ai/docs/List.md +205 -0
  21. package/dist/ai/docs/Menu.md +166 -0
  22. package/dist/ai/docs/Modal.md +280 -0
  23. package/dist/ai/docs/MultiSelect.md +196 -0
  24. package/dist/ai/docs/Notifications.md +231 -0
  25. package/dist/ai/docs/PageCalendar.md +271 -0
  26. package/dist/ai/docs/Polymorph.md +159 -0
  27. package/dist/ai/docs/Progress.md +145 -0
  28. package/dist/ai/docs/Radiobox.md +128 -0
  29. package/dist/ai/docs/RenderOnView.md +138 -0
  30. package/dist/ai/docs/Resizable.md +159 -0
  31. package/dist/ai/docs/Select.md +284 -0
  32. package/dist/ai/docs/Shortcut.md +105 -0
  33. package/dist/ai/docs/Skeleton.md +166 -0
  34. package/dist/ai/docs/Slider.md +144 -0
  35. package/dist/ai/docs/Slot.md +173 -0
  36. package/dist/ai/docs/Spinner.md +118 -0
  37. package/dist/ai/docs/Stats.md +137 -0
  38. package/dist/ai/docs/Step.md +159 -0
  39. package/dist/ai/docs/Switch.md +167 -0
  40. package/dist/ai/docs/Table.md +298 -0
  41. package/dist/ai/docs/Tabs.md +191 -0
  42. package/dist/ai/docs/Tag.md +224 -0
  43. package/dist/ai/docs/TaskList.md +144 -0
  44. package/dist/ai/docs/Textarea.md +167 -0
  45. package/dist/ai/docs/Timeline.md +210 -0
  46. package/dist/ai/docs/Toolbar.md +132 -0
  47. package/dist/ai/docs/Tooltip.md +231 -0
  48. package/dist/ai/docs/TransferList.md +142 -0
  49. package/dist/ai/docs/Typography.md +187 -0
  50. package/dist/ai/docs/Wizard.md +213 -0
  51. package/dist/ai/docs/index.md +183 -0
  52. package/dist/components/core/tag.d.ts +1 -1
  53. package/dist/components/core/tag.d.ts.map +1 -1
  54. package/dist/components/display/list.d.ts.map +1 -1
  55. package/dist/components/floating/dropdown.d.ts +1 -0
  56. package/dist/components/floating/dropdown.d.ts.map +1 -1
  57. package/dist/components/floating/menu.d.ts.map +1 -1
  58. package/dist/config/default-translations.d.ts +4 -4
  59. package/dist/hooks/use-translations.d.ts +4 -4
  60. package/dist/hooks/use-translations.d.ts.map +1 -1
  61. package/dist/index.css +1 -1
  62. package/dist/index.js +28 -20
  63. package/dist/index.js.map +1 -1
  64. package/dist/index.mjs +2463 -2458
  65. package/dist/index.mjs.map +1 -1
  66. package/dist/index.umd.js +12 -12
  67. package/dist/index.umd.js.map +1 -1
  68. package/package.json +4 -4
  69. package/dist/components/core/button.jsx +0 -79
  70. package/dist/components/core/heading.jsx +0 -4
  71. package/dist/components/core/polymorph.jsx +0 -5
  72. package/dist/components/core/render-on-view.jsx +0 -31
  73. package/dist/components/core/resizable.jsx +0 -51
  74. package/dist/components/core/slot.jsx +0 -156
  75. package/dist/components/core/tag.jsx +0 -51
  76. package/dist/components/core/typography.jsx +0 -22
  77. package/dist/components/display/alert.jsx +0 -58
  78. package/dist/components/display/calendar.jsx +0 -299
  79. package/dist/components/display/card.jsx +0 -43
  80. package/dist/components/display/empty.jsx +0 -11
  81. package/dist/components/display/list.jsx +0 -81
  82. package/dist/components/display/notifications.jsx +0 -126
  83. package/dist/components/display/progress.jsx +0 -11
  84. package/dist/components/display/shortcut.jsx +0 -23
  85. package/dist/components/display/skeleton.jsx +0 -12
  86. package/dist/components/display/spinner.jsx +0 -7
  87. package/dist/components/display/stats.jsx +0 -20
  88. package/dist/components/display/step.jsx +0 -131
  89. package/dist/components/display/tabs.jsx +0 -98
  90. package/dist/components/display/timeline.jsx +0 -25
  91. package/dist/components/floating/command-palette.jsx +0 -194
  92. package/dist/components/floating/dropdown.jsx +0 -53
  93. package/dist/components/floating/expand.jsx +0 -44
  94. package/dist/components/floating/menu.jsx +0 -147
  95. package/dist/components/floating/modal.jsx +0 -299
  96. package/dist/components/floating/toolbar.jsx +0 -5
  97. package/dist/components/floating/tooltip.jsx +0 -58
  98. package/dist/components/floating/wizard.jsx +0 -161
  99. package/dist/components/form/autocomplete.jsx +0 -279
  100. package/dist/components/form/checkbox.jsx +0 -12
  101. package/dist/components/form/date-picker.jsx +0 -115
  102. package/dist/components/form/file-upload.jsx +0 -133
  103. package/dist/components/form/form.jsx +0 -10
  104. package/dist/components/form/formReset.jsx +0 -17
  105. package/dist/components/form/free-text.jsx +0 -41
  106. package/dist/components/form/input-field.jsx +0 -56
  107. package/dist/components/form/input.jsx +0 -36
  108. package/dist/components/form/multi-select.jsx +0 -328
  109. package/dist/components/form/radiobox.jsx +0 -6
  110. package/dist/components/form/select.jsx +0 -42
  111. package/dist/components/form/slider.jsx +0 -45
  112. package/dist/components/form/switch.jsx +0 -46
  113. package/dist/components/form/task-list.jsx +0 -26
  114. package/dist/components/form/textarea.jsx +0 -12
  115. package/dist/components/form/transfer-list.jsx +0 -39
  116. package/dist/components/index.js +0 -45
  117. package/dist/components/page-calendar/calendar-header.jsx +0 -81
  118. package/dist/components/page-calendar/day-view.jsx +0 -87
  119. package/dist/components/page-calendar/event-pill.jsx +0 -25
  120. package/dist/components/page-calendar/index.js +0 -2
  121. package/dist/components/page-calendar/month-view.jsx +0 -47
  122. package/dist/components/page-calendar/page-calendar.jsx +0 -41
  123. package/dist/components/page-calendar/page-calendar.types.js +0 -1
  124. package/dist/components/page-calendar/page-calendar.utils.js +0 -71
  125. package/dist/components/page-calendar/week-view.jsx +0 -64
  126. package/dist/components/table/filter.jsx +0 -141
  127. package/dist/components/table/group.jsx +0 -68
  128. package/dist/components/table/index.jsx +0 -60
  129. package/dist/components/table/inner-table.jsx +0 -104
  130. package/dist/components/table/metadata.jsx +0 -36
  131. package/dist/components/table/pagination.jsx +0 -73
  132. package/dist/components/table/row.jsx +0 -58
  133. package/dist/components/table/sort.jsx +0 -105
  134. package/dist/components/table/table-lib.js +0 -83
  135. package/dist/components/table/table.context.jsx +0 -4
  136. package/dist/components/table/thead.jsx +0 -103
  137. package/dist/config/context.js +0 -12
  138. package/dist/config/default-translations.jsx +0 -83
  139. package/dist/config/default-tweaks.js +0 -4
  140. package/dist/constants.js +0 -2
  141. package/dist/hooks/use-click-outside.js +0 -17
  142. package/dist/hooks/use-color-parser.js +0 -9
  143. package/dist/hooks/use-components-provider.jsx +0 -19
  144. package/dist/hooks/use-debounce.js +0 -12
  145. package/dist/hooks/use-floating-ref.js +0 -6
  146. package/dist/hooks/use-form.js +0 -550
  147. package/dist/hooks/use-hover.js +0 -18
  148. package/dist/hooks/use-input-id.js +0 -5
  149. package/dist/hooks/use-is-coarse-device.js +0 -12
  150. package/dist/hooks/use-locale.js +0 -10
  151. package/dist/hooks/use-media-query.js +0 -25
  152. package/dist/hooks/use-on-event.js +0 -7
  153. package/dist/hooks/use-parent.js +0 -21
  154. package/dist/hooks/use-preferences.js +0 -23
  155. package/dist/hooks/use-previous.js +0 -9
  156. package/dist/hooks/use-reactive.js +0 -9
  157. package/dist/hooks/use-remove-scroll.js +0 -61
  158. package/dist/hooks/use-resize-observer.js +0 -17
  159. package/dist/hooks/use-stable-ref.js +0 -9
  160. package/dist/hooks/use-swipe.js +0 -17
  161. package/dist/hooks/use-translations.js +0 -9
  162. package/dist/hooks/use-tweaks.js +0 -9
  163. package/dist/hooks/use-window-size.js +0 -14
  164. package/dist/lib/combi-keys.js +0 -60
  165. package/dist/lib/dict.js +0 -39
  166. package/dist/lib/dom.js +0 -62
  167. package/dist/lib/fns.js +0 -46
  168. package/dist/lib/fzf.js +0 -117
  169. package/dist/lib/keyboard-area.js +0 -14
  170. package/dist/styles/common.js +0 -29
  171. package/dist/styles/dark.js +0 -214
  172. package/dist/styles/design-tokens.js +0 -69
  173. package/dist/styles/light.js +0 -214
  174. package/dist/styles/theme.js +0 -4
  175. package/dist/styles/theme.types.js +0 -1
  176. package/dist/types.js +0 -1
@@ -0,0 +1,174 @@
1
+ ---
2
+ title: Card
3
+ description: Polymorphic container for grouping related content with optional title header, loading state, and composable sub-components.
4
+ package: "@g4rcez/components"
5
+ export: "{ Card }"
6
+ import: "import { Card } from '@g4rcez/components/card'"
7
+ category: display
8
+ ---
9
+
10
+ # Card
11
+
12
+ Polymorphic container for grouping related content with optional title header, loading state, and composable sub-components.
13
+
14
+ ## Import
15
+
16
+ ```tsx
17
+ import { Card } from "@g4rcez/components/card";
18
+ ```
19
+
20
+ ## Props
21
+
22
+ ### Card
23
+
24
+ | Prop | Type | Default | Description |
25
+ |------|------|---------|-------------|
26
+ | `title` | `React.ReactNode` | — | Renders an automatic header with border separator |
27
+ | `loading` | `boolean` | — | Replaces content with animated skeleton lines |
28
+ | `titleClassName` | `string` | `""` | Additional classes for the title header element |
29
+ | `header` | `React.ReactElement \| null` | `null` | Custom header element; overrides `title` |
30
+ | `container` | `string` | `""` | Additional classes for the outer card element |
31
+ | `as` | `React.ElementType` | `"div"` | Polymorphic root element |
32
+ | `className` | `string` | `""` | Additional classes for the card body element |
33
+ | `children` | `React.ReactNode` | — | Card body content |
34
+
35
+ ### Card.Title
36
+
37
+ A composable header with a title and an optional navigation/action area.
38
+
39
+ | Prop | Type | Default | Description |
40
+ |------|------|---------|-------------|
41
+ | `title` | `React.ReactElement \| string` | — | Title content |
42
+ | `titleTag` | `React.ElementType` | `"h2"` | Element type for the title |
43
+ | `navTag` | `React.ElementType` | `"nav"` | Element type for the actions wrapper |
44
+ | `as` | `React.ElementType` | `"div"` | Element type for the container |
45
+ | `children` | `React.ReactNode` | — | Action elements rendered in the navigation area |
46
+
47
+ ## Design Tokens
48
+
49
+ Tokens this component reads. Customize by overriding these CSS variables in your theme.
50
+
51
+ | Token | CSS Variable | Purpose |
52
+ |-------|-------------|---------|
53
+ | `bg-card-background` | `--card-background` | Card surface color |
54
+ | `border-card-border` | `--card-border` | Card border and title separator |
55
+ | `rounded-card` | `--radius-card` | Corner radius |
56
+ | `shadow-shadow-card` | `--shadow-card` | Card drop shadow |
57
+ | `bg-muted` | `--muted` | Skeleton loading lines |
58
+
59
+ ## Examples
60
+
61
+ ### Basic Card
62
+
63
+ ```tsx
64
+ <Card>
65
+ <p>Card content goes here.</p>
66
+ </Card>
67
+ ```
68
+
69
+ ### Card with Title
70
+
71
+ ```tsx
72
+ <Card title="User Profile">
73
+ <div className="space-y-4">
74
+ <p>Name: John Doe</p>
75
+ <p>Email: john@example.com</p>
76
+ </div>
77
+ </Card>
78
+ ```
79
+
80
+ ### Card with Loading State
81
+
82
+ ```tsx
83
+ <Card title="Analytics" loading={isLoading}>
84
+ <p>Loaded content rendered here when not loading.</p>
85
+ </Card>
86
+ ```
87
+
88
+ ### Card.Title with Actions
89
+
90
+ ```tsx
91
+ import { Button } from "@g4rcez/components/button";
92
+
93
+ <Card>
94
+ <Card.Title title="Project Overview">
95
+ <Button theme="primary" size="small">Edit</Button>
96
+ <Button theme="neutral" size="small">Share</Button>
97
+ </Card.Title>
98
+
99
+ <p>Project description and details.</p>
100
+ </Card>
101
+ ```
102
+
103
+ ### Custom Header
104
+
105
+ ```tsx
106
+ <Card
107
+ header={
108
+ <header className="flex justify-between items-center p-4 border-b border-card-border">
109
+ <h2 className="text-foreground font-semibold">Custom Header</h2>
110
+ </header>
111
+ }
112
+ >
113
+ <p>Content with a completely custom header.</p>
114
+ </Card>
115
+ ```
116
+
117
+ ### Nested Cards
118
+
119
+ ```tsx
120
+ <Card title="Dashboard">
121
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
122
+ <Card title="Statistics">
123
+ <p>Chart content here</p>
124
+ </Card>
125
+ <Card title="Recent Activity">
126
+ <ul>
127
+ <li>User logged in</li>
128
+ <li>New order received</li>
129
+ </ul>
130
+ </Card>
131
+ </div>
132
+ </Card>
133
+ ```
134
+
135
+ ### Semantic Element
136
+
137
+ ```tsx
138
+ <Card as="article" title="Blog Post">
139
+ <p>Blog post content.</p>
140
+ </Card>
141
+ ```
142
+
143
+ ## Do
144
+
145
+ - Use `title` or `Card.Title` to give cards a clear, descriptive heading.
146
+ - Use `as="article"` or `as="section"` when semantics matter.
147
+ - Use `loading={true}` while data is fetching to prevent layout shift.
148
+ - Maintain consistent spacing between multiple cards in a grid using gap utilities.
149
+ - Use design-token classes for wrapper elements (`bg-background`, `border-border`).
150
+
151
+ ## Don't
152
+
153
+ - Don't pass raw Tailwind color classes (`bg-blue-500`, `text-white`, `border-gray-300`) — use design tokens instead.
154
+ - Don't use arbitrary Tailwind values (`bg-[#abc]`, `bg-[--my-var]`) — override CSS variables in your `@theme` block instead.
155
+ - Don't over-nest cards; multiple borders and shadows create visual clutter.
156
+ - Don't put more than one primary action in a single `Card.Title` — keep actions focused.
157
+
158
+ ## Accessibility
159
+
160
+ - Uses semantic HTML; `Card.Title` renders an `h2` by default (configurable via `titleTag`).
161
+ - Polymorphic `as` prop allows correct element type for document structure.
162
+ - Interactive elements within cards remain keyboard accessible.
163
+
164
+ ## Data Attributes
165
+
166
+ - `data-component="card"` — outer card element.
167
+ - `data-component="card-title"` — automatic title header.
168
+ - `data-component="card-body"` — card body wrapper.
169
+
170
+ ## Notes
171
+
172
+ - When both `title` and `header` are provided, `title` takes precedence and `header` is ignored.
173
+ - The `loading` prop replaces children with four `Skeleton` lines of varying widths.
174
+ - `Card.Title` lays out title and actions responsively: stacked on mobile, inline on `sm+`.
@@ -0,0 +1,199 @@
1
+ ---
2
+ title: Checkbox
3
+ description: Styled checkbox with label support, task mode, error display, loading state, and size variants.
4
+ package: "@g4rcez/components"
5
+ export: "{ Checkbox }"
6
+ import: "import { Checkbox } from '@g4rcez/components/checkbox'"
7
+ category: form
8
+ ---
9
+
10
+ # Checkbox
11
+
12
+ Styled checkbox with label support, task mode, error display, loading state, and size variants.
13
+
14
+ ## Import
15
+
16
+ ```tsx
17
+ import { Checkbox } from "@g4rcez/components/checkbox";
18
+ ```
19
+
20
+ ## Props
21
+
22
+ | Prop | Type | Default | Description |
23
+ |------|------|---------|-------------|
24
+ | `checked` | `boolean` | - | Controlled checked state |
25
+ | `onChange` | `(e: React.ChangeEvent<HTMLInputElement>) => void` | - | Change handler |
26
+ | `disabled` | `boolean` | `false` | Disabled state |
27
+ | `loading` | `boolean` | `false` | Loading state — disables the checkbox while loading |
28
+ | `error` | `string` | - | Error message rendered below the label |
29
+ | `asTask` | `boolean` | `false` | Task mode: applies strikethrough to the label when checked |
30
+ | `size` | `"medium" \| "large"` | `"medium"` | Checkbox size |
31
+ | `container` | `string` | - | Extra CSS classes for the outer `<label>` wrapper |
32
+ | `labelClassName` | `string` | - | Extra CSS classes for the error text element |
33
+ | `className` | `string` | - | Extra CSS classes for the `<input>` element |
34
+ | `children` | `React.ReactNode` | - | Label content |
35
+ | `...props` | `React.InputHTMLAttributes<HTMLInputElement>` | - | All standard input attributes |
36
+
37
+ ## Design Tokens
38
+
39
+ Tokens this component reads. Customize by overriding these CSS variables in your theme.
40
+
41
+ | Token | CSS Variable | Purpose |
42
+ |-------|-------------|---------|
43
+ | `text-primary` | `--primary` | Checkbox accent / checked color |
44
+ | `border-card-border` | `--card-border` | Unchecked border color |
45
+ | `text-danger` | `--danger` | Error message text color |
46
+ | `text-disabled` | `--disabled` | Opacity and cursor on disabled state |
47
+ | `focus:ring-primary` | `--primary` | Focus ring color |
48
+
49
+ ## Variants
50
+
51
+ ### Size
52
+
53
+ | Value | Description |
54
+ |-------|-------------|
55
+ | `"medium"` | Default size — 1rem × 1rem (`size-4`) |
56
+ | `"large"` | Larger touch target |
57
+
58
+ ### Task mode
59
+
60
+ When `asTask={true}`, the label text receives a strikethrough style when the checkbox is checked. This is intended for to-do lists and task management UIs.
61
+
62
+ ## Examples
63
+
64
+ ### Basic checkbox
65
+
66
+ ```tsx
67
+ const [accepted, setAccepted] = useState(false);
68
+
69
+ <Checkbox
70
+ checked={accepted}
71
+ onChange={(e) => setAccepted(e.target.checked)}
72
+ >
73
+ I accept the terms and conditions
74
+ </Checkbox>
75
+ ```
76
+
77
+ ### Checkbox with error
78
+
79
+ ```tsx
80
+ const [agreed, setAgreed] = useState(false);
81
+ const [error, setError] = useState("");
82
+
83
+ <Checkbox
84
+ checked={agreed}
85
+ onChange={(e) => {
86
+ setAgreed(e.target.checked);
87
+ if (e.target.checked) setError("");
88
+ }}
89
+ error={error}
90
+ >
91
+ I agree to the privacy policy
92
+ </Checkbox>
93
+ ```
94
+
95
+ ### Task list
96
+
97
+ ```tsx
98
+ const [tasks, setTasks] = useState([
99
+ { id: 1, text: "Write release notes", done: false },
100
+ { id: 2, text: "Merge pull request", done: true },
101
+ ]);
102
+
103
+ <div className="flex flex-col gap-sm">
104
+ {tasks.map((task) => (
105
+ <Checkbox
106
+ key={task.id}
107
+ checked={task.done}
108
+ onChange={() =>
109
+ setTasks((prev) =>
110
+ prev.map((t) => (t.id === task.id ? { ...t, done: !t.done } : t))
111
+ )
112
+ }
113
+ asTask
114
+ >
115
+ {task.text}
116
+ </Checkbox>
117
+ ))}
118
+ </div>
119
+ ```
120
+
121
+ ### Loading state
122
+
123
+ ```tsx
124
+ const [loading, setLoading] = useState(false);
125
+ const [subscribed, setSubscribed] = useState(false);
126
+
127
+ const handleChange = async (checked: boolean) => {
128
+ setLoading(true);
129
+ await updateSubscription(checked);
130
+ setSubscribed(checked);
131
+ setLoading(false);
132
+ };
133
+
134
+ <Checkbox
135
+ checked={subscribed}
136
+ onChange={(e) => handleChange(e.target.checked)}
137
+ loading={loading}
138
+ >
139
+ Subscribe to newsletter
140
+ </Checkbox>
141
+ ```
142
+
143
+ ### Notification preferences form
144
+
145
+ ```tsx
146
+ function PreferencesForm() {
147
+ const [prefs, setPrefs] = useState({
148
+ email: false,
149
+ push: true,
150
+ sms: false,
151
+ });
152
+
153
+ const toggle = (key: keyof typeof prefs) => (e: React.ChangeEvent<HTMLInputElement>) =>
154
+ setPrefs((prev) => ({ ...prev, [key]: e.target.checked }));
155
+
156
+ return (
157
+ <form className="flex flex-col gap-sm">
158
+ <Checkbox checked={prefs.email} onChange={toggle("email")}>Email notifications</Checkbox>
159
+ <Checkbox checked={prefs.push} onChange={toggle("push")}>Push notifications</Checkbox>
160
+ <Checkbox checked={prefs.sms} onChange={toggle("sms")}>SMS notifications</Checkbox>
161
+ </form>
162
+ );
163
+ }
164
+ ```
165
+
166
+ ## Do
167
+
168
+ - Use descriptive, actionable labels so users know exactly what they are agreeing to or enabling.
169
+ - Group related checkboxes visually to signal they form a set.
170
+ - Use `asTask` for items in a to-do list or task-tracking UI.
171
+ - Provide an `error` message when the checkbox is part of required validation (e.g., accepting terms).
172
+
173
+ ## Don't
174
+
175
+ - Don't pass raw Tailwind color classes (`bg-blue-500`, `text-white`, `border-gray-300`) — use theme props or design tokens instead.
176
+ - Don't use arbitrary Tailwind values (`bg-[#abc]`, `bg-[--my-var]`) — override CSS variables in your `@theme` block instead.
177
+ - Don't use `Checkbox` to trigger an immediate action — use a `Button` or `Switch` instead.
178
+ - Don't use checkboxes for mutually exclusive choices — use `Radiobox` instead.
179
+
180
+ ## Accessibility
181
+
182
+ - Renders a native `<input type="checkbox">` for full browser and screen reader support.
183
+ - The outer `<label>` wraps both the input and the label text, so clicking anywhere on the label toggles the checkbox.
184
+ - `aria-disabled` and `data-disabled` are applied when `disabled` or `loading` is true.
185
+ - Error messages are rendered as visible text below the label and are discoverable by screen readers.
186
+ - Focus ring is visible for keyboard navigation.
187
+
188
+ ## Data Attributes
189
+
190
+ - `data-component="checkbox"` — on the outer `<label>`.
191
+ - `data-task` — reflects the `asTask` prop value.
192
+ - `data-disabled` — reflects the effective disabled state (`disabled || loading`).
193
+ - `data-name="checkbox-label"` — on the error text `<span>`.
194
+
195
+ ## Notes
196
+
197
+ - `loading` sets `disabled` on the underlying input. The two states share the same visual treatment.
198
+ - The component forwards its ref to the `<input>` element.
199
+ - All standard `HTMLInputElement` attributes are forwarded to the native input, so you can use `name`, `value`, `required`, `defaultChecked`, and so on.
@@ -0,0 +1,293 @@
1
+ ---
2
+ title: CommandPalette
3
+ description: Searchable command palette with fuzzy search, keyboard shortcuts, and grouped commands.
4
+ package: "@g4rcez/components"
5
+ export: "{ CommandPalette }"
6
+ import: "import { CommandPalette } from '@g4rcez/components'"
7
+ category: floating
8
+ ---
9
+
10
+ # CommandPalette
11
+
12
+ Searchable command palette with fuzzy search, keyboard shortcuts, and grouped commands.
13
+
14
+ ## Import
15
+
16
+ ```tsx
17
+ import { CommandPalette } from "@g4rcez/components";
18
+ ```
19
+
20
+ ## Props
21
+
22
+ | Prop | Type | Default | Description |
23
+ |------|------|---------|-------------|
24
+ | `open` | `boolean` | — | Controlled open state |
25
+ | `commands` | `CommandItemTypes[]` | — | Array of commands to display |
26
+ | `onChangeVisibility` | `(next: boolean) => void` | — | Open/close handler |
27
+ | `bind` | `string` | `"Mod + k"` | Global keyboard shortcut to open the palette |
28
+ | `loading` | `boolean` | `false` | Show loading skeleton while commands load |
29
+ | `emptyMessage` | `Label` | — | Message shown when no results match |
30
+ | `footer` | `React.ReactElement` | — | Custom footer content |
31
+ | `onChangeText` | `(text: string) => void` | — | Search text change handler |
32
+ | `Preview` | `React.FC<{ command: CommandItemTypes; text: string }>` | — | Preview panel component for the active command |
33
+ | `Icon` | `React.FC<LucideProps & { text: string; Default: React.FC<LucideProps> }>` | — | Custom search icon |
34
+
35
+ ## Command Types
36
+
37
+ ### CommandShortcutItem
38
+
39
+ ```tsx
40
+ type CommandShortcutItem = {
41
+ type: "shortcut";
42
+ title: string | ((props: { text: string }) => string);
43
+ hint?: string | string[];
44
+ shortcut?: string;
45
+ Icon?: React.ReactElement;
46
+ enabled?: boolean | ((props: { text: string }) => boolean);
47
+ action: (args: {
48
+ text: string;
49
+ setText: (state: string) => void;
50
+ setOpen: (state: boolean) => void;
51
+ event: KeyboardEvent | React.MouseEvent | React.KeyboardEvent;
52
+ }) => void | Promise<void>;
53
+ };
54
+ ```
55
+
56
+ ### CommandGroupItem
57
+
58
+ ```tsx
59
+ type CommandGroupItem = {
60
+ type: "group";
61
+ title: string | ((props: { text: string }) => string);
62
+ items: CommandItemTypes[];
63
+ };
64
+ ```
65
+
66
+ ## Design Tokens
67
+
68
+ Tokens this component reads. Customize by overriding these CSS variables in your theme.
69
+
70
+ | Token | CSS Variable | Purpose |
71
+ |-------|-------------|---------|
72
+ | `bg-floating-background` | `--floating-background` | Palette surface background |
73
+ | `border-floating-border` | `--floating-border` | Palette surface border |
74
+ | `bg-floating-hover` | `--floating-hover` | Hovered/active command item background |
75
+ | `z-floating` | `--z-floating` | Z-index for the search header |
76
+ | `text-secondary` | `--secondary` | Group label and empty state text color |
77
+
78
+ ## Examples
79
+
80
+ ### Basic Command Palette
81
+
82
+ ```tsx
83
+ import { useState } from "react";
84
+ import { FileTextIcon, SaveIcon, FolderOpenIcon } from "lucide-react";
85
+ import { CommandPalette } from "@g4rcez/components";
86
+
87
+ function BasicCommandPalette() {
88
+ const [open, setOpen] = useState(false);
89
+
90
+ const commands = [
91
+ {
92
+ type: "shortcut" as const,
93
+ title: "New Document",
94
+ shortcut: "Ctrl+N",
95
+ Icon: <FileTextIcon size={16} />,
96
+ action: ({ setOpen }) => {
97
+ console.log("Creating new document");
98
+ setOpen(false);
99
+ },
100
+ },
101
+ {
102
+ type: "shortcut" as const,
103
+ title: "Save Document",
104
+ shortcut: "Ctrl+S",
105
+ Icon: <SaveIcon size={16} />,
106
+ action: ({ setOpen }) => {
107
+ console.log("Saving document");
108
+ setOpen(false);
109
+ },
110
+ },
111
+ {
112
+ type: "shortcut" as const,
113
+ title: "Open File",
114
+ shortcut: "Ctrl+O",
115
+ Icon: <FolderOpenIcon size={16} />,
116
+ action: ({ setOpen }) => {
117
+ console.log("Opening file");
118
+ setOpen(false);
119
+ },
120
+ },
121
+ ];
122
+
123
+ return (
124
+ <CommandPalette
125
+ open={open}
126
+ commands={commands}
127
+ onChangeVisibility={setOpen}
128
+ />
129
+ );
130
+ }
131
+ ```
132
+
133
+ ### Grouped Commands
134
+
135
+ ```tsx
136
+ import { FileIcon, FolderOpenIcon, HomeIcon, SettingsIcon, MoonIcon } from "lucide-react";
137
+ import { CommandPalette } from "@g4rcez/components";
138
+
139
+ function GroupedCommandPalette() {
140
+ const [open, setOpen] = useState(false);
141
+
142
+ const commands = [
143
+ {
144
+ type: "group" as const,
145
+ title: "File Operations",
146
+ items: [
147
+ {
148
+ type: "shortcut" as const,
149
+ title: "New File",
150
+ hint: ["create", "new", "file"],
151
+ shortcut: "Ctrl+N",
152
+ Icon: <FileIcon size={16} />,
153
+ action: ({ setOpen }) => setOpen(false),
154
+ },
155
+ {
156
+ type: "shortcut" as const,
157
+ title: "Open File",
158
+ hint: ["open", "load"],
159
+ shortcut: "Ctrl+O",
160
+ Icon: <FolderOpenIcon size={16} />,
161
+ action: ({ setOpen }) => setOpen(false),
162
+ },
163
+ ],
164
+ },
165
+ {
166
+ type: "group" as const,
167
+ title: "Navigation",
168
+ items: [
169
+ {
170
+ type: "shortcut" as const,
171
+ title: "Go to Dashboard",
172
+ hint: ["dashboard", "home", "main"],
173
+ Icon: <HomeIcon size={16} />,
174
+ action: ({ setOpen }) => {
175
+ window.location.href = "/dashboard";
176
+ setOpen(false);
177
+ },
178
+ },
179
+ {
180
+ type: "shortcut" as const,
181
+ title: "Go to Settings",
182
+ hint: ["settings", "preferences", "config"],
183
+ Icon: <SettingsIcon size={16} />,
184
+ action: ({ setOpen }) => {
185
+ window.location.href = "/settings";
186
+ setOpen(false);
187
+ },
188
+ },
189
+ ],
190
+ },
191
+ {
192
+ type: "group" as const,
193
+ title: "Theme",
194
+ items: [
195
+ {
196
+ type: "shortcut" as const,
197
+ title: "Toggle Dark Mode",
198
+ hint: ["dark", "theme", "mode"],
199
+ Icon: <MoonIcon size={16} />,
200
+ action: ({ setOpen }) => {
201
+ document.documentElement.classList.toggle("dark");
202
+ setOpen(false);
203
+ },
204
+ },
205
+ ],
206
+ },
207
+ ];
208
+
209
+ return (
210
+ <CommandPalette
211
+ open={open}
212
+ commands={commands}
213
+ onChangeVisibility={setOpen}
214
+ emptyMessage="No commands found"
215
+ />
216
+ );
217
+ }
218
+ ```
219
+
220
+ ### Custom Keyboard Shortcut
221
+
222
+ ```tsx
223
+ <CommandPalette
224
+ open={open}
225
+ commands={commands}
226
+ onChangeVisibility={setOpen}
227
+ bind="Mod + /"
228
+ />
229
+ ```
230
+
231
+ ### Conditional Commands
232
+
233
+ ```tsx
234
+ import { UserIcon, ShieldIcon } from "lucide-react";
235
+
236
+ const commands = [
237
+ {
238
+ type: "shortcut" as const,
239
+ title: "User Dashboard",
240
+ Icon: <UserIcon size={16} />,
241
+ action: ({ setOpen }) => setOpen(false),
242
+ },
243
+ {
244
+ type: "shortcut" as const,
245
+ title: "Admin Panel",
246
+ enabled: user.isAdmin,
247
+ Icon: <ShieldIcon size={16} />,
248
+ action: ({ setOpen }) => {
249
+ console.log("Opening admin panel");
250
+ setOpen(false);
251
+ },
252
+ },
253
+ ];
254
+ ```
255
+
256
+ ## Do
257
+
258
+ - Use `hint` arrays to add synonyms so commands match varied search terms (e.g., `["preferences", "config"]` for a "Settings" command).
259
+ - Group related commands with `type: "group"` so users can scan results quickly.
260
+ - Provide a clear `emptyMessage` so users know when nothing matches.
261
+ - Keep command titles short; let `hint` carry the synonym load.
262
+
263
+ ## Don't
264
+
265
+ - Don't put every action in the palette — focus on the most useful commands.
266
+ - Don't use raw Tailwind color classes (`bg-blue-500`, `text-white`) in custom `Icon` or `Preview` components — use design-token classes instead.
267
+ - Don't pass arbitrary Tailwind values (`bg-[#abc]`, `z-[9999]`) — override CSS variables in your `@theme` block.
268
+ - Don't omit the global shortcut — the default `Mod+K` is a strong convention users expect.
269
+
270
+ ## Accessibility
271
+
272
+ - Full arrow-key navigation within the list with loop support.
273
+ - `Enter` executes the active command; `Escape` closes the palette.
274
+ - Each item renders with `role="option"` and `aria-selected` reflecting the active state.
275
+ - The palette is wrapped in a `Modal` with `ariaTitle="Command palette"` for screen readers.
276
+ - The search input receives `autoFocus` when the palette opens.
277
+
278
+ ## Data Attributes
279
+
280
+ | Attribute | Applied to | Description |
281
+ |-----------|-----------|-------------|
282
+ | `data-component="command-palette"` | Root modal container | Identifies the palette root |
283
+ | `data-component="command-palette-list"` | `<ul>` | Identifies the command list |
284
+ | `data-component="command-palette-item"` | Each `<button>` item | Identifies individual command buttons |
285
+ | `data-component="command-palette-container"` | List/preview wrapper | Identifies the content area |
286
+
287
+ ## Notes
288
+
289
+ - The component registers global keyboard listeners via `CombiKeys`. All `shortcut` commands are also registered as global hotkeys — they fire even when the palette is closed.
290
+ - Fuzzy search runs over `title`, `shortcut`, and `hint` fields. When `title` is a function, it is called with the current search text to produce a string for matching.
291
+ - Commands with `enabled: false` (or a function returning `false`) are filtered out of results.
292
+ - The `Preview` panel is shown only when `activeIndex` is set and a `Preview` component is provided.
293
+ - The palette is built on top of `Modal`, so it inherits modal accessibility and portal rendering.