@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.
- package/dist/ai/SKILL.md +266 -0
- package/dist/ai/docs/Alert.md +167 -0
- package/dist/ai/docs/AnimatedList.md +205 -0
- package/dist/ai/docs/Autocomplete.md +225 -0
- package/dist/ai/docs/Button.md +182 -0
- package/dist/ai/docs/Calendar.md +219 -0
- package/dist/ai/docs/Card.md +174 -0
- package/dist/ai/docs/Checkbox.md +199 -0
- package/dist/ai/docs/CommandPalette.md +293 -0
- package/dist/ai/docs/DatePicker.md +171 -0
- package/dist/ai/docs/Dropdown.md +223 -0
- package/dist/ai/docs/Empty.md +163 -0
- package/dist/ai/docs/Expand.md +143 -0
- package/dist/ai/docs/FileUpload.md +225 -0
- package/dist/ai/docs/Form.md +107 -0
- package/dist/ai/docs/FormReset.md +117 -0
- package/dist/ai/docs/Heading.md +88 -0
- package/dist/ai/docs/Input.md +237 -0
- package/dist/ai/docs/InputField.md +170 -0
- package/dist/ai/docs/List.md +205 -0
- package/dist/ai/docs/Menu.md +166 -0
- package/dist/ai/docs/Modal.md +280 -0
- package/dist/ai/docs/MultiSelect.md +196 -0
- package/dist/ai/docs/Notifications.md +231 -0
- package/dist/ai/docs/PageCalendar.md +271 -0
- package/dist/ai/docs/Polymorph.md +159 -0
- package/dist/ai/docs/Progress.md +145 -0
- package/dist/ai/docs/Radiobox.md +128 -0
- package/dist/ai/docs/RenderOnView.md +138 -0
- package/dist/ai/docs/Resizable.md +159 -0
- package/dist/ai/docs/Select.md +284 -0
- package/dist/ai/docs/Shortcut.md +105 -0
- package/dist/ai/docs/Skeleton.md +166 -0
- package/dist/ai/docs/Slider.md +144 -0
- package/dist/ai/docs/Slot.md +173 -0
- package/dist/ai/docs/Spinner.md +118 -0
- package/dist/ai/docs/Stats.md +137 -0
- package/dist/ai/docs/Step.md +159 -0
- package/dist/ai/docs/Switch.md +167 -0
- package/dist/ai/docs/Table.md +298 -0
- package/dist/ai/docs/Tabs.md +191 -0
- package/dist/ai/docs/Tag.md +224 -0
- package/dist/ai/docs/TaskList.md +144 -0
- package/dist/ai/docs/Textarea.md +167 -0
- package/dist/ai/docs/Timeline.md +210 -0
- package/dist/ai/docs/Toolbar.md +132 -0
- package/dist/ai/docs/Tooltip.md +231 -0
- package/dist/ai/docs/TransferList.md +142 -0
- package/dist/ai/docs/Typography.md +187 -0
- package/dist/ai/docs/Wizard.md +213 -0
- package/dist/ai/docs/index.md +183 -0
- package/dist/components/core/tag.d.ts +1 -1
- package/dist/components/core/tag.d.ts.map +1 -1
- package/dist/components/display/list.d.ts.map +1 -1
- package/dist/components/floating/dropdown.d.ts +1 -0
- package/dist/components/floating/dropdown.d.ts.map +1 -1
- package/dist/components/floating/menu.d.ts.map +1 -1
- package/dist/config/default-translations.d.ts +4 -4
- package/dist/hooks/use-translations.d.ts +4 -4
- package/dist/hooks/use-translations.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.js +28 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2463 -2458
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +12 -12
- package/dist/index.umd.js.map +1 -1
- package/package.json +4 -4
- package/dist/components/core/button.jsx +0 -79
- package/dist/components/core/heading.jsx +0 -4
- package/dist/components/core/polymorph.jsx +0 -5
- package/dist/components/core/render-on-view.jsx +0 -31
- package/dist/components/core/resizable.jsx +0 -51
- package/dist/components/core/slot.jsx +0 -156
- package/dist/components/core/tag.jsx +0 -51
- package/dist/components/core/typography.jsx +0 -22
- package/dist/components/display/alert.jsx +0 -58
- package/dist/components/display/calendar.jsx +0 -299
- package/dist/components/display/card.jsx +0 -43
- package/dist/components/display/empty.jsx +0 -11
- package/dist/components/display/list.jsx +0 -81
- package/dist/components/display/notifications.jsx +0 -126
- package/dist/components/display/progress.jsx +0 -11
- package/dist/components/display/shortcut.jsx +0 -23
- package/dist/components/display/skeleton.jsx +0 -12
- package/dist/components/display/spinner.jsx +0 -7
- package/dist/components/display/stats.jsx +0 -20
- package/dist/components/display/step.jsx +0 -131
- package/dist/components/display/tabs.jsx +0 -98
- package/dist/components/display/timeline.jsx +0 -25
- package/dist/components/floating/command-palette.jsx +0 -194
- package/dist/components/floating/dropdown.jsx +0 -53
- package/dist/components/floating/expand.jsx +0 -44
- package/dist/components/floating/menu.jsx +0 -147
- package/dist/components/floating/modal.jsx +0 -299
- package/dist/components/floating/toolbar.jsx +0 -5
- package/dist/components/floating/tooltip.jsx +0 -58
- package/dist/components/floating/wizard.jsx +0 -161
- package/dist/components/form/autocomplete.jsx +0 -279
- package/dist/components/form/checkbox.jsx +0 -12
- package/dist/components/form/date-picker.jsx +0 -115
- package/dist/components/form/file-upload.jsx +0 -133
- package/dist/components/form/form.jsx +0 -10
- package/dist/components/form/formReset.jsx +0 -17
- package/dist/components/form/free-text.jsx +0 -41
- package/dist/components/form/input-field.jsx +0 -56
- package/dist/components/form/input.jsx +0 -36
- package/dist/components/form/multi-select.jsx +0 -328
- package/dist/components/form/radiobox.jsx +0 -6
- package/dist/components/form/select.jsx +0 -42
- package/dist/components/form/slider.jsx +0 -45
- package/dist/components/form/switch.jsx +0 -46
- package/dist/components/form/task-list.jsx +0 -26
- package/dist/components/form/textarea.jsx +0 -12
- package/dist/components/form/transfer-list.jsx +0 -39
- package/dist/components/index.js +0 -45
- package/dist/components/page-calendar/calendar-header.jsx +0 -81
- package/dist/components/page-calendar/day-view.jsx +0 -87
- package/dist/components/page-calendar/event-pill.jsx +0 -25
- package/dist/components/page-calendar/index.js +0 -2
- package/dist/components/page-calendar/month-view.jsx +0 -47
- package/dist/components/page-calendar/page-calendar.jsx +0 -41
- package/dist/components/page-calendar/page-calendar.types.js +0 -1
- package/dist/components/page-calendar/page-calendar.utils.js +0 -71
- package/dist/components/page-calendar/week-view.jsx +0 -64
- package/dist/components/table/filter.jsx +0 -141
- package/dist/components/table/group.jsx +0 -68
- package/dist/components/table/index.jsx +0 -60
- package/dist/components/table/inner-table.jsx +0 -104
- package/dist/components/table/metadata.jsx +0 -36
- package/dist/components/table/pagination.jsx +0 -73
- package/dist/components/table/row.jsx +0 -58
- package/dist/components/table/sort.jsx +0 -105
- package/dist/components/table/table-lib.js +0 -83
- package/dist/components/table/table.context.jsx +0 -4
- package/dist/components/table/thead.jsx +0 -103
- package/dist/config/context.js +0 -12
- package/dist/config/default-translations.jsx +0 -83
- package/dist/config/default-tweaks.js +0 -4
- package/dist/constants.js +0 -2
- package/dist/hooks/use-click-outside.js +0 -17
- package/dist/hooks/use-color-parser.js +0 -9
- package/dist/hooks/use-components-provider.jsx +0 -19
- package/dist/hooks/use-debounce.js +0 -12
- package/dist/hooks/use-floating-ref.js +0 -6
- package/dist/hooks/use-form.js +0 -550
- package/dist/hooks/use-hover.js +0 -18
- package/dist/hooks/use-input-id.js +0 -5
- package/dist/hooks/use-is-coarse-device.js +0 -12
- package/dist/hooks/use-locale.js +0 -10
- package/dist/hooks/use-media-query.js +0 -25
- package/dist/hooks/use-on-event.js +0 -7
- package/dist/hooks/use-parent.js +0 -21
- package/dist/hooks/use-preferences.js +0 -23
- package/dist/hooks/use-previous.js +0 -9
- package/dist/hooks/use-reactive.js +0 -9
- package/dist/hooks/use-remove-scroll.js +0 -61
- package/dist/hooks/use-resize-observer.js +0 -17
- package/dist/hooks/use-stable-ref.js +0 -9
- package/dist/hooks/use-swipe.js +0 -17
- package/dist/hooks/use-translations.js +0 -9
- package/dist/hooks/use-tweaks.js +0 -9
- package/dist/hooks/use-window-size.js +0 -14
- package/dist/lib/combi-keys.js +0 -60
- package/dist/lib/dict.js +0 -39
- package/dist/lib/dom.js +0 -62
- package/dist/lib/fns.js +0 -46
- package/dist/lib/fzf.js +0 -117
- package/dist/lib/keyboard-area.js +0 -14
- package/dist/styles/common.js +0 -29
- package/dist/styles/dark.js +0 -214
- package/dist/styles/design-tokens.js +0 -69
- package/dist/styles/light.js +0 -214
- package/dist/styles/theme.js +0 -4
- package/dist/styles/theme.types.js +0 -1
- package/dist/types.js +0 -1
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Select
|
|
3
|
+
description: Styled native select component with validation, loading state, and form integration.
|
|
4
|
+
package: "@g4rcez/components"
|
|
5
|
+
export: "{ Select }"
|
|
6
|
+
import: "import { Select } from '@g4rcez/components/select'"
|
|
7
|
+
category: form
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Select
|
|
11
|
+
|
|
12
|
+
Styled native select component with validation, loading state, and form integration.
|
|
13
|
+
|
|
14
|
+
## Import
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { Select } from "@g4rcez/components/select";
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Props
|
|
21
|
+
|
|
22
|
+
| Prop | Type | Default | Description |
|
|
23
|
+
|------|------|---------|-------------|
|
|
24
|
+
| `options` | `OptionProps[]` | — | Array of option objects. |
|
|
25
|
+
| `selectContainer` | `string` | `""` | Additional CSS classes for the select container. |
|
|
26
|
+
| `required` | `boolean` | `true` | Whether the field is required. |
|
|
27
|
+
| `error` | `string` | — | Error message to display. |
|
|
28
|
+
| `loading` | `boolean` | `false` | Shows a loading indicator and disables the field. |
|
|
29
|
+
| `disabled` | `boolean` | `false` | Disables the select. |
|
|
30
|
+
| `placeholder` | `string` | — | Placeholder shown as a disabled hidden option. |
|
|
31
|
+
| `value` | `string` | — | Controlled selected value. |
|
|
32
|
+
| `onChange` | `(e: ChangeEvent<HTMLSelectElement>) => void` | — | Change handler. |
|
|
33
|
+
| `...inputFieldProps` | `InputFieldProps` | — | All `InputField` props (title, left, right, feedback, etc.). |
|
|
34
|
+
|
|
35
|
+
### OptionProps
|
|
36
|
+
|
|
37
|
+
| Prop | Type | Description |
|
|
38
|
+
|------|------|-------------|
|
|
39
|
+
| `value` | `string` | Option value (required). |
|
|
40
|
+
| `label` | `string` | Display text (falls back to `value` if omitted). |
|
|
41
|
+
| `disabled` | `boolean` | Disables this individual option. |
|
|
42
|
+
| `data-dynamic` | `string` | Marks a dynamically generated option. |
|
|
43
|
+
| `data-*` | `string` | Any custom data attributes forwarded to the `<option>`. |
|
|
44
|
+
|
|
45
|
+
## Design Tokens
|
|
46
|
+
|
|
47
|
+
Tokens this component reads. Customize by overriding these CSS variables in your theme.
|
|
48
|
+
|
|
49
|
+
| Token | CSS Variable | Purpose |
|
|
50
|
+
|-------|-------------|---------|
|
|
51
|
+
| `text-foreground` | `--foreground` | Selected option text color |
|
|
52
|
+
| `text-input-placeholder` | `--input-placeholder` | Color when no option is selected |
|
|
53
|
+
| `placeholder-input-placeholder` | `--input-placeholder` | Placeholder styling |
|
|
54
|
+
| `bg-input-mask-error` (via `group-error`) | `--input-mask-error` | Placeholder tint in error state |
|
|
55
|
+
| `text-danger` (via `group-error`) | `--danger` | Text color in error state |
|
|
56
|
+
| `hover:text-primary` | `--primary` | Caret icon hover color |
|
|
57
|
+
| `h-input-height` | `--input-height` | Control height (2.5 rem) |
|
|
58
|
+
| `px-input-x` | `--input-x` | Horizontal padding |
|
|
59
|
+
| `py-input-y` | `--input-y` | Vertical padding |
|
|
60
|
+
|
|
61
|
+
## Examples
|
|
62
|
+
|
|
63
|
+
### Basic usage
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
import { useState } from "react";
|
|
67
|
+
import { Select } from "@g4rcez/components/select";
|
|
68
|
+
|
|
69
|
+
export default function FruitPicker() {
|
|
70
|
+
const [value, setValue] = useState("");
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<Select
|
|
74
|
+
title="Fruit"
|
|
75
|
+
options={[
|
|
76
|
+
{ value: "apple", label: "Apple" },
|
|
77
|
+
{ value: "banana", label: "Banana" },
|
|
78
|
+
{ value: "orange", label: "Orange" },
|
|
79
|
+
]}
|
|
80
|
+
placeholder="Select a fruit"
|
|
81
|
+
value={value}
|
|
82
|
+
onChange={(e) => setValue(e.target.value)}
|
|
83
|
+
/>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### With validation error
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
import { useState } from "react";
|
|
92
|
+
import { Select } from "@g4rcez/components/select";
|
|
93
|
+
|
|
94
|
+
export default function CountrySelect() {
|
|
95
|
+
const [country, setCountry] = useState("");
|
|
96
|
+
const [error, setError] = useState("");
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<Select
|
|
100
|
+
title="Country"
|
|
101
|
+
options={[
|
|
102
|
+
{ value: "us", label: "United States" },
|
|
103
|
+
{ value: "ca", label: "Canada" },
|
|
104
|
+
{ value: "uk", label: "United Kingdom" },
|
|
105
|
+
]}
|
|
106
|
+
placeholder="Select country"
|
|
107
|
+
value={country}
|
|
108
|
+
error={error}
|
|
109
|
+
required
|
|
110
|
+
onChange={(e) => {
|
|
111
|
+
setCountry(e.target.value);
|
|
112
|
+
setError(e.target.value ? "" : "Please select a country");
|
|
113
|
+
}}
|
|
114
|
+
/>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### With disabled options
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
import { Select } from "@g4rcez/components/select";
|
|
123
|
+
|
|
124
|
+
export default function StatusSelect() {
|
|
125
|
+
return (
|
|
126
|
+
<Select
|
|
127
|
+
title="Status"
|
|
128
|
+
options={[
|
|
129
|
+
{ value: "active", label: "Active" },
|
|
130
|
+
{ value: "pending", label: "Pending" },
|
|
131
|
+
{ value: "legacy", label: "Legacy (deprecated)", disabled: true },
|
|
132
|
+
{ value: "inactive", label: "Inactive" },
|
|
133
|
+
]}
|
|
134
|
+
placeholder="Select status"
|
|
135
|
+
/>
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Async options with loading state
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
import { useEffect, useState } from "react";
|
|
144
|
+
import { Select } from "@g4rcez/components/select";
|
|
145
|
+
|
|
146
|
+
export default function AsyncSelect() {
|
|
147
|
+
const [options, setOptions] = useState<{ value: string; label: string }[]>([]);
|
|
148
|
+
const [loading, setLoading] = useState(false);
|
|
149
|
+
const [value, setValue] = useState("");
|
|
150
|
+
|
|
151
|
+
useEffect(() => {
|
|
152
|
+
setLoading(true);
|
|
153
|
+
fetchOptions().then((data) => {
|
|
154
|
+
setOptions(data);
|
|
155
|
+
setLoading(false);
|
|
156
|
+
});
|
|
157
|
+
}, []);
|
|
158
|
+
|
|
159
|
+
return (
|
|
160
|
+
<Select
|
|
161
|
+
title="Region"
|
|
162
|
+
options={options}
|
|
163
|
+
placeholder={loading ? "Loading..." : "Select a region"}
|
|
164
|
+
value={value}
|
|
165
|
+
loading={loading}
|
|
166
|
+
disabled={loading}
|
|
167
|
+
onChange={(e) => setValue(e.target.value)}
|
|
168
|
+
/>
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Form integration with `useForm`
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
import { Select } from "@g4rcez/components/select";
|
|
177
|
+
import { useForm } from "@g4rcez/components/form";
|
|
178
|
+
|
|
179
|
+
export default function UserForm() {
|
|
180
|
+
const form = useForm(schema, "userForm");
|
|
181
|
+
|
|
182
|
+
return (
|
|
183
|
+
<form {...form.props}>
|
|
184
|
+
<Select
|
|
185
|
+
{...form.select("role")}
|
|
186
|
+
options={[
|
|
187
|
+
{ value: "admin", label: "Administrator" },
|
|
188
|
+
{ value: "editor", label: "Editor" },
|
|
189
|
+
{ value: "viewer", label: "Viewer" },
|
|
190
|
+
]}
|
|
191
|
+
placeholder="Select role"
|
|
192
|
+
/>
|
|
193
|
+
</form>
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Cascading selects
|
|
199
|
+
|
|
200
|
+
```tsx
|
|
201
|
+
import { useState } from "react";
|
|
202
|
+
import { Select } from "@g4rcez/components/select";
|
|
203
|
+
|
|
204
|
+
const subcategories: Record<string, { value: string; label: string }[]> = {
|
|
205
|
+
electronics: [
|
|
206
|
+
{ value: "phones", label: "Phones" },
|
|
207
|
+
{ value: "laptops", label: "Laptops" },
|
|
208
|
+
],
|
|
209
|
+
clothing: [
|
|
210
|
+
{ value: "shirts", label: "Shirts" },
|
|
211
|
+
{ value: "pants", label: "Pants" },
|
|
212
|
+
],
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
export default function CascadingSelect() {
|
|
216
|
+
const [category, setCategory] = useState("");
|
|
217
|
+
const [subcategory, setSubcategory] = useState("");
|
|
218
|
+
|
|
219
|
+
return (
|
|
220
|
+
<div className="flex flex-col gap-base">
|
|
221
|
+
<Select
|
|
222
|
+
title="Category"
|
|
223
|
+
options={[
|
|
224
|
+
{ value: "electronics", label: "Electronics" },
|
|
225
|
+
{ value: "clothing", label: "Clothing" },
|
|
226
|
+
]}
|
|
227
|
+
placeholder="Select category"
|
|
228
|
+
value={category}
|
|
229
|
+
onChange={(e) => {
|
|
230
|
+
setCategory(e.target.value);
|
|
231
|
+
setSubcategory("");
|
|
232
|
+
}}
|
|
233
|
+
/>
|
|
234
|
+
|
|
235
|
+
{category && (
|
|
236
|
+
<Select
|
|
237
|
+
title="Subcategory"
|
|
238
|
+
options={subcategories[category] ?? []}
|
|
239
|
+
placeholder="Select subcategory"
|
|
240
|
+
value={subcategory}
|
|
241
|
+
onChange={(e) => setSubcategory(e.target.value)}
|
|
242
|
+
/>
|
|
243
|
+
)}
|
|
244
|
+
</div>
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Do
|
|
250
|
+
|
|
251
|
+
- Use descriptive `label` values for each option.
|
|
252
|
+
- Order options logically (alphabetically or by usage frequency).
|
|
253
|
+
- Provide a `placeholder` so users know what to select.
|
|
254
|
+
- Use `loading` and `disabled` together while fetching options asynchronously.
|
|
255
|
+
- Use design-token classes for wrapper elements (`bg-background`, `text-foreground`, `border-border`).
|
|
256
|
+
|
|
257
|
+
## Don't
|
|
258
|
+
|
|
259
|
+
- Don't use `Select` for only 2–3 options — prefer `Radiobox` or `Switch` for better visibility.
|
|
260
|
+
- Don't use `Select` for large searchable lists — use `Autocomplete` instead.
|
|
261
|
+
- Don't use long option labels that may truncate on small viewports.
|
|
262
|
+
- Don't pass raw Tailwind color classes (`bg-blue-500`, `text-white`, `border-gray-300`) — use design tokens instead.
|
|
263
|
+
- Don't use arbitrary Tailwind values (`bg-[#abc]`, `bg-[--my-var]`) — override CSS variables in your `@theme` block instead.
|
|
264
|
+
|
|
265
|
+
## Accessibility
|
|
266
|
+
|
|
267
|
+
- Uses a native `<select>` element for full keyboard support and screen-reader compatibility.
|
|
268
|
+
- The `placeholder` renders as a `disabled hidden` option so it is never submitted.
|
|
269
|
+
- A `ChevronDownIcon` caret is rendered inside a `<label>` pointing to the select id, giving it a larger click target.
|
|
270
|
+
- `data-selected` is set to `"false"` until the user selects an option, which toggles the placeholder color class.
|
|
271
|
+
|
|
272
|
+
## Data Attributes
|
|
273
|
+
|
|
274
|
+
| Attribute | Element | Value | Description |
|
|
275
|
+
|-----------|---------|-------|-------------|
|
|
276
|
+
| `data-component` | `InputField` root | `"select"` | Identifies the component. |
|
|
277
|
+
| `data-selected` | `<select>` | `"true" \| "false"` | Whether a non-placeholder option is selected. |
|
|
278
|
+
|
|
279
|
+
## Notes
|
|
280
|
+
|
|
281
|
+
- Built on `InputField` for layout, label, error, and loading handling.
|
|
282
|
+
- Supports all standard HTML `<select>` attributes via prop spread.
|
|
283
|
+
- `required` defaults to `true` — pass `required={false}` when the field is optional.
|
|
284
|
+
- Custom data attributes on `OptionProps` (e.g., `data-price`) are forwarded to each `<option>` and accessible via `e.target.selectedOptions[0].dataset`.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Shortcut
|
|
3
|
+
description: Inline keyboard shortcut display with automatic OS-specific key symbol mapping.
|
|
4
|
+
package: "@g4rcez/components"
|
|
5
|
+
export: "{ Shortcut }"
|
|
6
|
+
import: "import { Shortcut } from '@g4rcez/components'"
|
|
7
|
+
category: display
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Shortcut
|
|
11
|
+
|
|
12
|
+
Inline keyboard shortcut display with automatic OS-specific key symbol mapping.
|
|
13
|
+
|
|
14
|
+
## Import
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { Shortcut } from "@g4rcez/components";
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Props
|
|
21
|
+
|
|
22
|
+
| Prop | Type | Default | Description |
|
|
23
|
+
|------|------|---------|-------------|
|
|
24
|
+
| `value` | `string` | — | Shortcut string to display, e.g. `"Mod + K"` or `"Shift + Alt + P"` |
|
|
25
|
+
|
|
26
|
+
## Design Tokens
|
|
27
|
+
|
|
28
|
+
The `Shortcut` component inherits text color and size from its parent. No component-scoped tokens.
|
|
29
|
+
|
|
30
|
+
## OS Mapping
|
|
31
|
+
|
|
32
|
+
The component automatically maps keys based on the user's operating system:
|
|
33
|
+
|
|
34
|
+
| Key token | macOS | Other |
|
|
35
|
+
|-----------|-------|-------|
|
|
36
|
+
| `Mod` | `⌘` (CommandIcon, `size={12}`) | `Ctrl` |
|
|
37
|
+
| `Alt` | `⌥` (OptionIcon, `size={12}`) | `Alt` |
|
|
38
|
+
|
|
39
|
+
All other key tokens are rendered as-is.
|
|
40
|
+
|
|
41
|
+
## Examples
|
|
42
|
+
|
|
43
|
+
### Basic Usage
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
<Shortcut value="Mod + K" />
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### In a Tooltip
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
<Tooltip title="Save changes">
|
|
53
|
+
<div className="flex gap-2 items-center">
|
|
54
|
+
Save <Shortcut value="Mod + S" />
|
|
55
|
+
</div>
|
|
56
|
+
</Tooltip>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### In a Command Palette Item
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
<div className="flex items-center justify-between w-full">
|
|
63
|
+
<span>Open command palette</span>
|
|
64
|
+
<Shortcut value="Mod + K" />
|
|
65
|
+
</div>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Complex Multi-Key Shortcuts
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
<Shortcut value="Shift + Alt + P" />
|
|
72
|
+
<Shortcut value="Mod + Shift + L" />
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### In a Menu Item
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
<div className="flex items-center justify-between px-4 py-2">
|
|
79
|
+
<span className="text-foreground">New File</span>
|
|
80
|
+
<Shortcut value="Mod + N" />
|
|
81
|
+
</div>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Do
|
|
85
|
+
|
|
86
|
+
- Use `"Mod"` instead of `"Ctrl"` or `"Cmd"` to get automatic platform-specific rendering.
|
|
87
|
+
- Use `"Alt"` for the Option/Alt key — it also gets platform-specific rendering on macOS.
|
|
88
|
+
- Place `Shortcut` next to the label of the action it accelerates (button, menu item, tooltip).
|
|
89
|
+
|
|
90
|
+
## Don't
|
|
91
|
+
|
|
92
|
+
- Don't hardcode platform symbols like `⌘` or `Ctrl` directly — let `Shortcut` handle the mapping.
|
|
93
|
+
- Don't pass arbitrary Tailwind values (`text-[--my-var]`) for text color — let the component inherit from its parent.
|
|
94
|
+
- Don't use `Shortcut` for descriptive text longer than a typical keyboard combination.
|
|
95
|
+
|
|
96
|
+
## Accessibility
|
|
97
|
+
|
|
98
|
+
- Each key segment renders inside a `<kbd>` element with an `aria-label` equal to the raw key name (e.g. `aria-label="Mod"`), so screen readers announce the semantic name regardless of the visual symbol.
|
|
99
|
+
- Icon-based keys (`CommandIcon`, `OptionIcon`) also carry their own `aria-label` attribute.
|
|
100
|
+
|
|
101
|
+
## Notes
|
|
102
|
+
|
|
103
|
+
- The component renders a `<span>` with `flex items-center gap-1 text-sm`.
|
|
104
|
+
- Keys are split on `"+"` and trimmed, so `"Mod + K"`, `"Mod+K"`, and `"Mod +K"` all produce the same output.
|
|
105
|
+
- The OS check uses `isMac()` from the internal `combi-keys` utility, which reads `navigator.userAgent`.
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Skeleton
|
|
3
|
+
description: Animated loading placeholder components for content that is being fetched.
|
|
4
|
+
package: "@g4rcez/components"
|
|
5
|
+
export: "{ Skeleton, SkeletonCell, SkeletonList }"
|
|
6
|
+
import: "import { Skeleton, SkeletonCell, SkeletonList } from '@g4rcez/components'"
|
|
7
|
+
category: display
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Skeleton
|
|
11
|
+
|
|
12
|
+
Animated loading placeholder components for content that is being fetched.
|
|
13
|
+
|
|
14
|
+
## Import
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { Skeleton, SkeletonCell, SkeletonList } from "@g4rcez/components";
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Components
|
|
21
|
+
|
|
22
|
+
### SkeletonCell
|
|
23
|
+
|
|
24
|
+
A pre-built table-cell skeleton with `h-6 w-10/12 animate-pulse rounded bg-muted`. Renders as a plain `<div>` (no props).
|
|
25
|
+
|
|
26
|
+
### Skeleton
|
|
27
|
+
|
|
28
|
+
A configurable block skeleton.
|
|
29
|
+
|
|
30
|
+
| Prop | Type | Default | Description |
|
|
31
|
+
|------|------|---------|-------------|
|
|
32
|
+
| `className` | `string` | — | Override or extend dimensions and shape |
|
|
33
|
+
| `as` | `React.ElementType` | `"span"` | Polymorphic root element |
|
|
34
|
+
| `style` | `CSSProperties` | — | Inline styles (e.g. dynamic `width`) |
|
|
35
|
+
|
|
36
|
+
Default appearance: `block h-8 w-32 animate-pulse rounded bg-muted`.
|
|
37
|
+
|
|
38
|
+
### SkeletonList
|
|
39
|
+
|
|
40
|
+
A vertical list of randomized-width `Skeleton` lines.
|
|
41
|
+
|
|
42
|
+
| Prop | Type | Default | Description |
|
|
43
|
+
|------|------|---------|-------------|
|
|
44
|
+
| `rows` | `number` | — | Number of skeleton lines to render |
|
|
45
|
+
| `className` | `string` | — | Additional classes for the `<ul>` container |
|
|
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-muted` | `--muted` | Pulse animation background for all skeleton variants |
|
|
54
|
+
|
|
55
|
+
## Examples
|
|
56
|
+
|
|
57
|
+
### Table Loading Skeleton
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
function TableSkeleton() {
|
|
61
|
+
return (
|
|
62
|
+
<table className="w-full">
|
|
63
|
+
<tbody>
|
|
64
|
+
{Array.from({ length: 5 }).map((_, index) => (
|
|
65
|
+
<tr key={index} className="border-b border-border">
|
|
66
|
+
<td className="py-3 px-4"><SkeletonCell /></td>
|
|
67
|
+
<td className="py-3 px-4"><SkeletonCell /></td>
|
|
68
|
+
<td className="py-3 px-4"><SkeletonCell /></td>
|
|
69
|
+
</tr>
|
|
70
|
+
))}
|
|
71
|
+
</tbody>
|
|
72
|
+
</table>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Card Loading Skeleton
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
function CardSkeleton() {
|
|
81
|
+
return (
|
|
82
|
+
<div className="rounded-card border border-card-border bg-card-background p-6 space-y-4">
|
|
83
|
+
<Skeleton className="h-4 w-3/4" />
|
|
84
|
+
<div className="space-y-2">
|
|
85
|
+
<SkeletonCell />
|
|
86
|
+
<SkeletonCell />
|
|
87
|
+
<Skeleton className="h-2 w-1/2" />
|
|
88
|
+
</div>
|
|
89
|
+
<div className="flex gap-2">
|
|
90
|
+
<Skeleton className="h-8 w-20" />
|
|
91
|
+
<Skeleton className="h-8 w-16" />
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### List Loading Skeleton
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
<SkeletonList rows={5} className="px-4" />
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Conditional Skeleton
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
function DataSection({ data, loading }: { data?: Item; loading: boolean }) {
|
|
108
|
+
return (
|
|
109
|
+
<div>
|
|
110
|
+
{loading ? (
|
|
111
|
+
<Skeleton className="h-6 w-full" />
|
|
112
|
+
) : (
|
|
113
|
+
<p>{data?.name}</p>
|
|
114
|
+
)}
|
|
115
|
+
</div>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Avatar + Text Row Skeleton
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
function UserRowSkeleton() {
|
|
124
|
+
return (
|
|
125
|
+
<div className="flex items-center gap-3">
|
|
126
|
+
<Skeleton className="size-10 rounded-full" />
|
|
127
|
+
<div className="flex-1 space-y-1">
|
|
128
|
+
<SkeletonCell />
|
|
129
|
+
<Skeleton className="h-2 w-1/3" />
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Do
|
|
137
|
+
|
|
138
|
+
- Design skeletons that closely match the dimensions of the real content to minimize layout shift.
|
|
139
|
+
- Use `animate-pulse` (applied by default) to signal that the system is active.
|
|
140
|
+
- Use `SkeletonList` for simple vertically stacked text content.
|
|
141
|
+
- Wrap skeleton containers with `aria-live="polite"` so screen readers announce when real content loads.
|
|
142
|
+
|
|
143
|
+
## Don't
|
|
144
|
+
|
|
145
|
+
- Don't pass raw Tailwind color classes (`bg-gray-200`, `bg-slate-300`) as `className` — use `bg-muted` or other design-token classes instead.
|
|
146
|
+
- Don't use arbitrary Tailwind values (`bg-[#ddd]`) — override CSS variables in your `@theme` block.
|
|
147
|
+
- Don't show skeletons for very short loading states (under ~300 ms) — it causes visual flicker.
|
|
148
|
+
- Don't make skeletons too detailed; simple geometric shapes are most effective.
|
|
149
|
+
- Don't use skeletons for error states — show `Empty` or `Alert` instead.
|
|
150
|
+
|
|
151
|
+
## Accessibility
|
|
152
|
+
|
|
153
|
+
- Skeleton components are purely decorative; they carry no ARIA roles.
|
|
154
|
+
- Add `aria-live="polite"` to the container that transitions from skeleton to real content so assistive technologies announce the change.
|
|
155
|
+
- Consider `aria-label="Loading content"` on the skeleton container for additional context.
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
<div aria-live="polite">
|
|
159
|
+
{loading ? <SkeletonCell /> : <ActualContent />}
|
|
160
|
+
</div>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Notes
|
|
164
|
+
|
|
165
|
+
- `SkeletonList` generates random widths at mount time (via `Math.random()`) so each row looks distinct. Widths are stable across re-renders thanks to `useRef`.
|
|
166
|
+
- `Skeleton` uses `as="span"` by default, making it safe to use inside inline contexts. Change `as` to `"div"` or `"li"` as needed.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Slider
|
|
3
|
+
description: Accessible range input for selecting one or more numeric values along a scale.
|
|
4
|
+
package: "@g4rcez/components"
|
|
5
|
+
export: "{ Slider }"
|
|
6
|
+
import: "import { Slider } from '@g4rcez/components'"
|
|
7
|
+
category: form
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Slider
|
|
11
|
+
|
|
12
|
+
Accessible range input for selecting one or more numeric values along a scale.
|
|
13
|
+
|
|
14
|
+
## Import
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { Slider } from "@g4rcez/components";
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Props
|
|
21
|
+
|
|
22
|
+
`Slider` accepts all props from `@base-ui/react/slider` Root, plus:
|
|
23
|
+
|
|
24
|
+
| Prop | Type | Default | Description |
|
|
25
|
+
|------|------|---------|-------------|
|
|
26
|
+
| `tooltip` | `boolean` | `false` | Shows a tooltip with the current value above the thumb while dragging. |
|
|
27
|
+
| `value` | `number[]` | — | Controlled value(s). |
|
|
28
|
+
| `defaultValue` | `number[]` | `[0]` | Initial value(s) for uncontrolled usage. |
|
|
29
|
+
| `min` | `number` | `0` | Minimum value. |
|
|
30
|
+
| `max` | `number` | `100` | Maximum value. |
|
|
31
|
+
| `step` | `number` | `1` | Increment between selectable values. |
|
|
32
|
+
| `className` | `string` | — | Additional classes applied to the control track wrapper. |
|
|
33
|
+
|
|
34
|
+
## Design Tokens
|
|
35
|
+
|
|
36
|
+
Tokens this component reads. Customize by overriding these CSS variables in your theme.
|
|
37
|
+
|
|
38
|
+
| Token | CSS Variable | Purpose |
|
|
39
|
+
|-------|-------------|---------|
|
|
40
|
+
| `bg-background` | `--background` | Track background (unfilled area) |
|
|
41
|
+
| `bg-primary` | `--primary` | Indicator fill (filled area) |
|
|
42
|
+
| `border-input-border` | `--input-border` | Thumb border color |
|
|
43
|
+
| `bg-input-switch` | `--input-switch` | Thumb fill color (checked/active) |
|
|
44
|
+
| `focus-within:ring-primary` | `--primary` | Focus ring on thumb |
|
|
45
|
+
|
|
46
|
+
## Variants
|
|
47
|
+
|
|
48
|
+
### Single thumb
|
|
49
|
+
|
|
50
|
+
One value in `defaultValue` renders a single draggable thumb.
|
|
51
|
+
|
|
52
|
+
### Range (dual thumb)
|
|
53
|
+
|
|
54
|
+
Two values in `defaultValue` render two thumbs that define a range.
|
|
55
|
+
|
|
56
|
+
## Examples
|
|
57
|
+
|
|
58
|
+
### Single value
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
import { Slider } from "@g4rcez/components";
|
|
62
|
+
|
|
63
|
+
export default function VolumeControl() {
|
|
64
|
+
return (
|
|
65
|
+
<Slider
|
|
66
|
+
min={0}
|
|
67
|
+
max={100}
|
|
68
|
+
defaultValue={[50]}
|
|
69
|
+
onChange={(value) => console.log(value)}
|
|
70
|
+
/>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Range slider
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
import { Slider } from "@g4rcez/components";
|
|
79
|
+
|
|
80
|
+
export default function PriceRangeFilter() {
|
|
81
|
+
return (
|
|
82
|
+
<Slider
|
|
83
|
+
min={0}
|
|
84
|
+
max={1000}
|
|
85
|
+
defaultValue={[200, 800]}
|
|
86
|
+
tooltip
|
|
87
|
+
/>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Controlled with tooltip and custom step
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
import { useState } from "react";
|
|
96
|
+
import { Slider } from "@g4rcez/components";
|
|
97
|
+
|
|
98
|
+
export default function SteppedSlider() {
|
|
99
|
+
const [value, setValue] = useState([0.5]);
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<div className="flex flex-col gap-base">
|
|
103
|
+
<Slider
|
|
104
|
+
min={0}
|
|
105
|
+
max={1}
|
|
106
|
+
step={0.1}
|
|
107
|
+
value={value}
|
|
108
|
+
tooltip
|
|
109
|
+
onValueChange={setValue}
|
|
110
|
+
/>
|
|
111
|
+
<span className="text-sm text-muted-foreground">
|
|
112
|
+
Current: {value[0].toFixed(1)}
|
|
113
|
+
</span>
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Do
|
|
120
|
+
|
|
121
|
+
- Provide visible labels or descriptive context indicating what the slider controls.
|
|
122
|
+
- Use `tooltip` for precise numeric adjustments where the exact value matters.
|
|
123
|
+
- Use `step` to restrict selection to valid increments (e.g., `step={10}` for percentages in tens).
|
|
124
|
+
- Use design-token classes for any wrapper elements (`bg-background`, `text-foreground`).
|
|
125
|
+
|
|
126
|
+
## Don't
|
|
127
|
+
|
|
128
|
+
- Don't use `Slider` for very large or effectively infinite ranges where a text `Input` would be more efficient.
|
|
129
|
+
- Don't use `Slider` for selecting from a small discrete set (e.g., 3 named options) — use `Radiobox` or `Select`.
|
|
130
|
+
- Don't pass raw Tailwind color classes (`bg-blue-500`, `border-gray-300`) — use design tokens instead.
|
|
131
|
+
- Don't use arbitrary Tailwind values (`bg-[#abc]`) — override CSS variables in your `@theme` block instead.
|
|
132
|
+
|
|
133
|
+
## Accessibility
|
|
134
|
+
|
|
135
|
+
- Fully accessible via keyboard: Arrow keys increment/decrement the focused thumb.
|
|
136
|
+
- Each thumb exposes `aria-valuenow`, `aria-valuemin`, and `aria-valuemax`.
|
|
137
|
+
- Touch targets for thumbs are sized generously (`size-5`) for mobile usability.
|
|
138
|
+
- Compatible with screen readers through the underlying `@base-ui/react/slider`.
|
|
139
|
+
|
|
140
|
+
## Notes
|
|
141
|
+
|
|
142
|
+
- Built on `@base-ui/react/slider` — most structural ARIA and keyboard behavior comes from that primitive.
|
|
143
|
+
- The `Thumb` sub-component observes `aria-valuenow` mutations via a `MutationObserver` to keep the tooltip value in sync without additional state.
|
|
144
|
+
- Locale-aware: the `useLocale` hook is used internally for number formatting in tooltips.
|