@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,237 @@
1
+ ---
2
+ title: Input
3
+ description: Text input with optional masking for currencies, percentages, phone numbers, dates, and custom regex patterns.
4
+ package: "@g4rcez/components"
5
+ export: "{ Input }"
6
+ import: "import { Input } from '@g4rcez/components/input'"
7
+ category: form
8
+ ---
9
+
10
+ # Input
11
+
12
+ Text input with optional masking for currencies, percentages, phone numbers, dates, and custom regex patterns.
13
+
14
+ ## Import
15
+
16
+ ```tsx
17
+ import { Input } from "@g4rcez/components/input";
18
+ ```
19
+
20
+ ## Props
21
+
22
+ `Input` extends all standard HTML `<input>` attributes plus `InputField` layout props:
23
+
24
+ | Prop | Type | Default | Description |
25
+ |------|------|---------|-------------|
26
+ | `mask` | `AllMasks \| Array<string \| RegExp> \| ((value: string) => AllMasks)` | - | Input mask pattern |
27
+ | `locale` | `Locales` | - | Locale for currency/number formatting |
28
+ | `currency` | `CurrencyCode` | - | Currency code when using `mask="currency"` |
29
+ | `error` | `string` | - | Error message shown below the field |
30
+ | `title` | `string` | - | Field label |
31
+ | `feedback` | `Label` | - | Success or neutral feedback text below the field |
32
+ | `left` | `Label` | - | Content rendered on the left inside the field border |
33
+ | `right` | `Label` | - | Content rendered on the right inside the field border |
34
+ | `required` | `boolean` | `false` | Marks field as required; hides "Optional" label text |
35
+ | `disabled` | `boolean` | `false` | Disabled state |
36
+ | `loading` | `boolean` | `false` | Loading state |
37
+ | `container` | `string` | - | Extra CSS classes for the outer `fieldset` |
38
+ | `labelClassName` | `string` | - | Extra CSS classes for the label/border wrapper |
39
+ | `next` | `string` | - | `id` of the next field to focus when Enter is pressed with `enterKeyHint="next"` |
40
+ | `hiddenLabel` | `boolean` | `false` | Visually hides the label but keeps it for screen readers |
41
+ | `...props` | `React.InputHTMLAttributes<HTMLInputElement>` | - | All standard input attributes |
42
+
43
+ ### Mask patterns
44
+
45
+ | Pattern char | Matches |
46
+ |---|---|
47
+ | `9` | Digit (0–9) |
48
+ | `A` | Letter (a–z, A–Z) |
49
+ | `S` | Alphanumeric |
50
+ | `*` | Any character |
51
+
52
+ ### Special mask strings
53
+
54
+ | Value | Description |
55
+ |---|---|
56
+ | `"currency"` | Currency formatting (requires `locale` and `currency`) |
57
+ | `"percentage"` | Percentage input with `%` symbol |
58
+ | `"decimal"` | Decimal number formatting |
59
+
60
+ ## Design Tokens
61
+
62
+ Tokens this component reads. Customize by overriding these CSS variables in your theme.
63
+
64
+ | Token | CSS Variable | Purpose |
65
+ |-------|-------------|---------|
66
+ | `h-input-height` | `--input-height` | Input height |
67
+ | `px-input-x` | `--input-x` | Horizontal padding |
68
+ | `py-input-y` | `--input-y` | Vertical padding |
69
+ | `mt-input-gap` | `--input-gap` | Gap between field border and error/feedback text |
70
+ | `border-input-border` | `--input-border` | Default border color |
71
+ | `text-field-label` | `--field-label` | Label text color |
72
+ | `text-foreground` | `--foreground` | Input text color |
73
+ | `text-primary` | `--primary` | Focus ring, focus/hover border color |
74
+ | `text-danger` | `--danger` | Error state border, text, and label color |
75
+ | `text-disabled` | `--disabled` | Disabled text and border color |
76
+ | `placeholder-input-mask` | `--input-mask` | Placeholder text color |
77
+ | `placeholder-input-mask-error` | `--input-mask-error` | Placeholder color in error state |
78
+
79
+ ## Examples
80
+
81
+ ### Basic text input
82
+
83
+ ```tsx
84
+ import { Input } from "@g4rcez/components/input";
85
+
86
+ <Input name="name" title="Full name" placeholder="Jane Smith" required />
87
+ ```
88
+
89
+ ### Phone number mask
90
+
91
+ ```tsx
92
+ <Input
93
+ name="phone"
94
+ title="Phone"
95
+ mask="(99) 99999-9999"
96
+ placeholder="(00) 00000-0000"
97
+ />
98
+ ```
99
+
100
+ ### Currency input
101
+
102
+ ```tsx
103
+ <Input
104
+ name="price"
105
+ title="Price"
106
+ mask="currency"
107
+ currency="USD"
108
+ locale="en-US"
109
+ placeholder="0.00"
110
+ />
111
+ ```
112
+
113
+ ### Dynamic mask (CPF / CNPJ)
114
+
115
+ ```tsx
116
+ const docMask = (value: string) =>
117
+ value.replace(/\D/g, "").length <= 11
118
+ ? "999.999.999-99"
119
+ : "99.999.999/9999-99";
120
+
121
+ <Input
122
+ name="document"
123
+ title="CPF or CNPJ"
124
+ mask={docMask}
125
+ placeholder="000.000.000-00"
126
+ />
127
+ ```
128
+
129
+ ### Input with inline left/right slots
130
+
131
+ ```tsx
132
+ import { SearchIcon } from "lucide-react";
133
+
134
+ <Input
135
+ name="search"
136
+ title="Search"
137
+ left={<SearchIcon size={16} className="text-muted-foreground" />}
138
+ placeholder="Type to search..."
139
+ />
140
+ ```
141
+
142
+ ### Input with error and feedback
143
+
144
+ ```tsx
145
+ const [email, setEmail] = useState("");
146
+ const error = email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
147
+ ? "Enter a valid email address"
148
+ : undefined;
149
+
150
+ <Input
151
+ name="email"
152
+ type="email"
153
+ title="Email"
154
+ value={email}
155
+ onChange={(e) => setEmail(e.target.value)}
156
+ error={error}
157
+ feedback={!error && email ? "Looks good!" : undefined}
158
+ />
159
+ ```
160
+
161
+ ### Enter-to-advance between fields
162
+
163
+ ```tsx
164
+ <Input
165
+ name="first"
166
+ title="First name"
167
+ enterKeyHint="next"
168
+ next="last"
169
+ />
170
+ <Input
171
+ name="last"
172
+ id="last"
173
+ title="Last name"
174
+ enterKeyHint="done"
175
+ />
176
+ ```
177
+
178
+ ### Inside a form
179
+
180
+ ```tsx
181
+ import { Form } from "@g4rcez/components/form";
182
+ import { Button } from "@g4rcez/components/button";
183
+
184
+ function SignUpForm() {
185
+ const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
186
+ const data = new FormData(e.currentTarget);
187
+ console.log(Object.fromEntries(data));
188
+ };
189
+
190
+ return (
191
+ <Form onSubmit={handleSubmit} className="flex flex-col gap-base max-w-md">
192
+ <Input name="name" title="Full name" required />
193
+ <Input name="email" type="email" title="Email" required />
194
+ <Input name="phone" title="Phone" mask="(99) 99999-9999" />
195
+ <Button theme="primary" type="submit">Sign up</Button>
196
+ </Form>
197
+ );
198
+ }
199
+ ```
200
+
201
+ ## Do
202
+
203
+ - Use `mask` patterns that match user expectations for the data type.
204
+ - Provide a `placeholder` that shows the expected format (e.g., `"(00) 00000-0000"`).
205
+ - Use the `error` prop to surface validation messages from your form library or manual validation.
206
+ - Use the `next` prop with `enterKeyHint="next"` to create smooth keyboard flows on mobile.
207
+ - Use design-token classes for wrapper elements (`bg-background`, `text-foreground`, `border-border`).
208
+
209
+ ## Don't
210
+
211
+ - Don't pass raw Tailwind color classes (`bg-blue-500`, `text-white`, `border-gray-300`) — use theme props or design tokens instead.
212
+ - Don't use arbitrary Tailwind values (`bg-[#abc]`, `bg-[--my-var]`) — override CSS variables in your `@theme` block instead.
213
+ - Don't use a mask that blocks valid input variations — prefer dynamic masks for formats with variable length.
214
+ - Don't forget that the mask formats the display value; if your backend expects raw data, strip formatting before sending.
215
+ - Don't use `Input` for long-form text — use `Textarea` instead.
216
+
217
+ ## Accessibility
218
+
219
+ - Renders a semantic `<input>` wrapped in a `<fieldset>` with an associated `<label>` (via `InputField`).
220
+ - `aria-disabled`, `aria-readonly`, and `aria-busy` are set automatically from props.
221
+ - Error messages appear as a visible `<p>` below the field after the user has interacted with it (`data-initialized="true"`).
222
+ - Focus ring uses `focus:ring-primary` for consistent, visible keyboard indication.
223
+ - The `hiddenLabel` prop keeps the label in the accessibility tree while hiding it visually.
224
+
225
+ ## Data Attributes
226
+
227
+ - `data-initialized` — managed by `initializeInputDataset`; switches from `"false"` to `"true"` after first user interaction, enabling validation display.
228
+ - `data-next` — set from the `next` prop; used to focus the next field on Enter.
229
+ - `data-component="input"` — set on the outer `fieldset` by `InputField`.
230
+ - `data-error` — on the `fieldset`: `"true"` when an `error` string is present.
231
+
232
+ ## Notes
233
+
234
+ - Built on top of `the-mask-input`. All mask features from that library are available.
235
+ - The component automatically manages cursor positioning during masked input.
236
+ - Works with both controlled (`value` + `onChange`) and uncontrolled (`defaultValue`) patterns.
237
+ - `Input` is created via the `createFreeText` factory, which also powers `Textarea`. Both share the same styling tokens.
@@ -0,0 +1,170 @@
1
+ ---
2
+ title: InputField
3
+ description: Low-level field wrapper that provides a label, tooltip, error message, feedback text, and left/right slots for any form control.
4
+ package: "@g4rcez/components"
5
+ export: "{ InputField }"
6
+ import: "import { InputField } from '@g4rcez/components'"
7
+ category: form
8
+ ---
9
+
10
+ # InputField
11
+
12
+ Low-level field wrapper that provides a label, tooltip, error message, feedback text, and left/right slots for any form control. Most higher-level components (`Input`, `Select`, `Autocomplete`, `DatePicker`, `Textarea`) use `InputField` internally and forward its props automatically.
13
+
14
+ ## Import
15
+
16
+ ```tsx
17
+ import { InputField } from "@g4rcez/components";
18
+ ```
19
+
20
+ ## Props
21
+
22
+ | Prop | Type | Default | Description |
23
+ |------|------|---------|-------------|
24
+ | `title` | `Label` | - | Main label text for the field |
25
+ | `info` | `Label` | - | Informational text shown in a `Tooltip` icon next to the label |
26
+ | `error` | `string` | - | Error message rendered below the field border |
27
+ | `feedback` | `Label` | - | Success or neutral feedback message (hidden when `error` is present) |
28
+ | `left` | `Label` | - | Content rendered to the left inside the field border |
29
+ | `right` | `Label` | - | Content rendered to the right inside the field border |
30
+ | `rightLabel` | `Label` | - | Content rendered to the right of the label text |
31
+ | `required` | `boolean` | `false` | If `true`, hides the "Optional" badge |
32
+ | `optionalText` | `string` | `"Optional"` | Text shown for optional fields (translatable) |
33
+ | `disabled` | `boolean` | `false` | Applies disabled styling to the wrapper and label |
34
+ | `interactive` | `boolean` | `false` | Sets `data-interactive` on the fieldset |
35
+ | `container` | `string` | - | Extra CSS classes for the outer `<fieldset>` |
36
+ | `labelClassName` | `string` | - | Extra CSS classes for the inner label/border wrapper `<div>` |
37
+ | `hiddenLabel` | `boolean` | `false` | Visually hides the label row while keeping it accessible |
38
+ | `reportStatus` | `boolean` | - | Show `CheckCircle`/`XCircle` icons alongside the label based on validity |
39
+ | `componentName` | `string` | - | Sets `data-component` on the fieldset (e.g., `"input"`, `"select"`) |
40
+ | `id` | `string` | - | `id` linked to the inner control via `htmlFor` on the label |
41
+ | `name` | `string` | - | Fallback for `id` when `id` is not provided |
42
+ | `children` | `React.ReactNode` | - | The actual form control (input, select, etc.) |
43
+
44
+ ## Design Tokens
45
+
46
+ Tokens this component reads. Customize by overriding these CSS variables in your theme.
47
+
48
+ | Token | CSS Variable | Purpose |
49
+ |-------|-------------|---------|
50
+ | `border-input-border` | `--input-border` | Default field border color |
51
+ | `text-field-label` | `--field-label` | Label text color |
52
+ | `text-primary` | `--primary` | Label and border color on focus/hover |
53
+ | `text-danger` | `--danger` | Label, border, and error text color in error state |
54
+ | `text-disabled` | `--disabled` | Label and border color when disabled |
55
+ | `mt-input-gap` | `--input-gap` | Gap between border and error/feedback text |
56
+
57
+ ## Examples
58
+
59
+ ### Wrapping a native input
60
+
61
+ ```tsx
62
+ import { InputField } from "@g4rcez/components";
63
+
64
+ <InputField title="Username" name="username" required>
65
+ <input
66
+ id="username"
67
+ name="username"
68
+ className="h-input-height w-full flex-1 bg-transparent px-input-x text-foreground outline-none"
69
+ />
70
+ </InputField>
71
+ ```
72
+
73
+ ### With info tooltip and error
74
+
75
+ ```tsx
76
+ import { SearchIcon, CheckIcon } from "lucide-react";
77
+
78
+ <InputField
79
+ title="API Key"
80
+ name="api_key"
81
+ info="Your secret API key from the developer portal."
82
+ error={apiKeyError}
83
+ left={<SearchIcon size={16} className="text-muted-foreground" />}
84
+ right={isValid ? <CheckIcon size={16} className="text-success" /> : null}
85
+ required
86
+ >
87
+ <input
88
+ id="api_key"
89
+ name="api_key"
90
+ type="password"
91
+ className="h-input-height w-full flex-1 bg-transparent px-input-x text-foreground outline-none"
92
+ />
93
+ </InputField>
94
+ ```
95
+
96
+ ### Optional vs required
97
+
98
+ ```tsx
99
+ {/* Required — "Optional" badge is hidden */}
100
+ <InputField title="Email" name="email" required>
101
+ <input id="email" name="email" type="email" className="h-input-height w-full flex-1 bg-transparent px-input-x text-foreground outline-none" />
102
+ </InputField>
103
+
104
+ {/* Optional — shows "Optional" badge */}
105
+ <InputField title="Website" name="website">
106
+ <input id="website" name="website" type="url" className="h-input-height w-full flex-1 bg-transparent px-input-x text-foreground outline-none" />
107
+ </InputField>
108
+ ```
109
+
110
+ ### Hidden label (accessible)
111
+
112
+ ```tsx
113
+ <InputField title="Search" name="search" hiddenLabel>
114
+ <input
115
+ id="search"
116
+ name="search"
117
+ placeholder="Search..."
118
+ className="h-input-height w-full flex-1 bg-transparent px-input-x text-foreground outline-none"
119
+ />
120
+ </InputField>
121
+ ```
122
+
123
+ ### Feedback after validation
124
+
125
+ ```tsx
126
+ <InputField
127
+ title="Slug"
128
+ name="slug"
129
+ feedback={isAvailable ? "This slug is available." : undefined}
130
+ error={!isAvailable ? "Slug is already taken." : undefined}
131
+ required
132
+ >
133
+ <input id="slug" name="slug" className="h-input-height w-full flex-1 bg-transparent px-input-x text-foreground outline-none" />
134
+ </InputField>
135
+ ```
136
+
137
+ ## Do
138
+
139
+ - Use `InputField` when building new form controls to ensure consistent label, error, and feedback layout across the application.
140
+ - Always provide a `title` for every field so screen readers can identify the control.
141
+ - Use the `info` prop for fields that need supplemental explanation without cluttering the label.
142
+ - Match the `id` on the inner control to the `name` (or `id`) on `InputField` so the `<label htmlFor>` association works correctly.
143
+
144
+ ## Don't
145
+
146
+ - Don't pass raw Tailwind color classes (`bg-blue-500`, `text-white`, `border-gray-300`) to `InputField` wrappers — use theme props or design tokens instead.
147
+ - Don't use arbitrary Tailwind values (`bg-[#abc]`, `bg-[--my-var]`) — override CSS variables in your `@theme` block instead.
148
+ - Don't use `InputField` for non-form content; it is specifically designed for labeled input controls.
149
+ - Don't skip the `title` prop — omitting it hides the label but may break screen reader associations.
150
+
151
+ ## Accessibility
152
+
153
+ - Renders a `<fieldset>` element as the outer wrapper, with `aria-disabled` when disabled.
154
+ - The inner `<label>` uses `htmlFor` linked to `id` (or `name`) to associate with the control.
155
+ - Error messages render as a `<p>` below the field; they are shown after the user interacts with the input (`data-initialized="true"`) or when `error` is set explicitly.
156
+ - Feedback messages render as a separate `<p>` and are hidden when an error is present.
157
+ - The `info` tooltip uses `Tooltip` with `aria-label` / `aria-describedby` for screen reader support.
158
+ - `reportStatus` icons use `aria-hidden="true"` since they are supplemental visual indicators.
159
+
160
+ ## Data Attributes
161
+
162
+ - `data-component` — reflects the `componentName` prop (e.g., `"input"`, `"select"`, `"autocomplete"`).
163
+ - `data-error` — `"true"` when an `error` string is present; drives CSS group variants.
164
+ - `data-interactive` — `"true"` when `interactive` is set; used for custom interactive state styling.
165
+
166
+ ## Notes
167
+
168
+ - `InputField` uses Tailwind `group` classes to synchronize hover and focus states between the outer wrapper and inner elements. The `group-focus-within:border-primary` and `group-hover:border-primary` patterns rely on this.
169
+ - The optional text label ("Optional") is sourced from the translation system via `useTranslations`, making it localizable.
170
+ - `reportStatus` defaults to the value configured in `useTweaks().input.iconFeedback`, allowing a global default.
@@ -0,0 +1,205 @@
1
+ ---
2
+ title: List
3
+ description: Animated list that expands each item into a focused floating detail overlay when clicked.
4
+ package: "@g4rcez/components"
5
+ export: "{ AnimatedList, AnimatedListItem }"
6
+ import: "import { AnimatedList, AnimatedListItem } from '@g4rcez/components/list'"
7
+ category: display
8
+ ---
9
+
10
+ # List
11
+
12
+ Animated list that expands each item into a focused floating detail overlay when clicked.
13
+
14
+ `AnimatedList` and `AnimatedListItem` are exported from the `@g4rcez/components/list` subpath. Each row in the list is clickable; selecting a row opens a `motion/react`-animated card overlay with the item's full content.
15
+
16
+ ## Import
17
+
18
+ ```tsx
19
+ import { AnimatedList, AnimatedListItem } from "@g4rcez/components/list";
20
+ ```
21
+
22
+ ## Props
23
+
24
+ ### AnimatedList
25
+
26
+ | Prop | Type | Default | Description |
27
+ |------|------|---------|-------------|
28
+ | `children` | `React.ReactNode` | — | One or more `AnimatedListItem` elements. |
29
+
30
+ ### AnimatedListItem
31
+
32
+ | Prop | Type | Default | Description |
33
+ |------|------|---------|-------------|
34
+ | `title` | `Label` | — | Primary heading shown in the list row and in the overlay header. |
35
+ | `description` | `Label` | — | Secondary text rendered below the title in both the row and the overlay. |
36
+ | `children` | `Label` | — | Content rendered inside the expanded overlay below the header section. |
37
+ | `avatar` | `Label` | — | Optional leading node (image, icon, or element) displayed before the title in the row. |
38
+ | `leading` | `React.FC<{ open: () => void }>` | — | Optional render-prop component at the trailing end of the row. Receives an `open` callback to open the overlay programmatically. |
39
+
40
+ `Label` is `string | number | ReactNode`.
41
+
42
+ ## Design Tokens
43
+
44
+ Tokens this component reads. Customize by overriding these CSS variables in your theme.
45
+
46
+ | Token | CSS Variable | Purpose |
47
+ |-------|-------------|---------|
48
+ | `border-card-border` | `--card-border` | Row separator and overlay card border |
49
+ | `bg-card-background` | `--card-background` | Overlay card background color |
50
+ | `rounded-card` | `--radius-card` | Overlay card corner radius |
51
+ | `shadow-shadow-card` | `--shadow-card` | Overlay card drop shadow |
52
+ | `text-foreground` | `--foreground` | Default text color for row and overlay content |
53
+ | `text-secondary` | `--secondary` | Description text color |
54
+ | `text-primary` | `--primary` | Row title hover color and avatar focus ring |
55
+ | `text-danger` | `--danger` | Close button hover color in the overlay |
56
+ | `bg-floating-overlay` | `--floating-overlay` | Semi-transparent backdrop behind the overlay (used at 70 % opacity) |
57
+ | `z-floating` | `--z-floating` | `z-index` for the overlay card (value: 22) |
58
+ | `z-overlay` | `--z-overlay` | `z-index` for the backdrop scrim |
59
+
60
+ ## Examples
61
+
62
+ ### Basic usage
63
+
64
+ ```tsx
65
+ import { AnimatedList, AnimatedListItem } from "@g4rcez/components/list";
66
+
67
+ const members = [
68
+ { id: "1", name: "Alice Johnson", role: "Engineering" },
69
+ { id: "2", name: "Bob Smith", role: "Design" },
70
+ ];
71
+
72
+ export function TeamList() {
73
+ return (
74
+ <AnimatedList>
75
+ {members.map((m) => (
76
+ <AnimatedListItem
77
+ key={m.id}
78
+ title={m.name}
79
+ description={m.role}
80
+ >
81
+ <p className="text-foreground">Full profile for {m.name}.</p>
82
+ </AnimatedListItem>
83
+ ))}
84
+ </AnimatedList>
85
+ );
86
+ }
87
+ ```
88
+
89
+ ### With avatar
90
+
91
+ ```tsx
92
+ import { AnimatedList, AnimatedListItem } from "@g4rcez/components/list";
93
+ import { UserCircleIcon } from "lucide-react";
94
+
95
+ export function UserDirectory() {
96
+ return (
97
+ <AnimatedList>
98
+ <AnimatedListItem
99
+ title="Carol White"
100
+ description="Product Manager"
101
+ avatar={<UserCircleIcon size={40} className="text-muted-foreground" />}
102
+ >
103
+ <div className="flex flex-col gap-2 text-foreground">
104
+ <span>Department: Product</span>
105
+ <span>Location: San Francisco</span>
106
+ </div>
107
+ </AnimatedListItem>
108
+ </AnimatedList>
109
+ );
110
+ }
111
+ ```
112
+
113
+ ### With trailing action using `leading`
114
+
115
+ ```tsx
116
+ import { AnimatedList, AnimatedListItem } from "@g4rcez/components/list";
117
+ import { Button } from "@g4rcez/components/button";
118
+
119
+ export function OrderList({ orders }: { orders: Order[] }) {
120
+ return (
121
+ <AnimatedList>
122
+ {orders.map((order) => (
123
+ <AnimatedListItem
124
+ key={order.id}
125
+ title={`Order #${order.id}`}
126
+ description={`Total: ${order.total}`}
127
+ leading={({ open }) => (
128
+ <Button size="small" theme="ghost-muted" onClick={open}>
129
+ View details
130
+ </Button>
131
+ )}
132
+ >
133
+ <OrderDetailContent order={order} />
134
+ </AnimatedListItem>
135
+ ))}
136
+ </AnimatedList>
137
+ );
138
+ }
139
+ ```
140
+
141
+ ### Notification / activity feed
142
+
143
+ ```tsx
144
+ import { AnimatedList, AnimatedListItem } from "@g4rcez/components/list";
145
+ import { CheckCircleIcon, AlertTriangleIcon } from "lucide-react";
146
+
147
+ const feed = [
148
+ { id: "n1", icon: <CheckCircleIcon size={20} className="text-success" />, title: "Deployment succeeded", time: "2 min ago", detail: "All 3 services are healthy." },
149
+ { id: "n2", icon: <AlertTriangleIcon size={20} className="text-warn" />, title: "High CPU usage", time: "10 min ago", detail: "Instance i-0ab2 is at 94 %." },
150
+ ];
151
+
152
+ export function NotificationFeed() {
153
+ return (
154
+ <AnimatedList>
155
+ {feed.map((n) => (
156
+ <AnimatedListItem
157
+ key={n.id}
158
+ title={n.title}
159
+ description={n.time}
160
+ avatar={n.icon}
161
+ >
162
+ <p className="text-sm text-muted-foreground">{n.detail}</p>
163
+ </AnimatedListItem>
164
+ ))}
165
+ </AnimatedList>
166
+ );
167
+ }
168
+ ```
169
+
170
+ ## Do
171
+
172
+ - Keep `title` and `description` short — they share a single row and are not truncated automatically.
173
+ - Provide meaningful `children` content in the overlay to justify clicking the row.
174
+ - Use `leading` to expose a primary call-to-action alongside the title without forcing the user to open the overlay.
175
+ - Use design-token classes inside the overlay content (`bg-card-background`, `text-foreground`, `border-card-border`).
176
+
177
+ ## Don't
178
+
179
+ - Don't pass raw Tailwind color classes (`bg-blue-500`, `text-white`, `border-gray-300`) — use design tokens instead.
180
+ - Don't use arbitrary Tailwind values (`bg-[#abc]`, `bg-[--my-var]`) — override CSS variables in your `@theme` block instead.
181
+ - Don't use this component for purely informational lists where no detail overlay is needed — use a plain `<ul>` instead.
182
+ - Don't embed full applications or heavy forms inside the overlay `children`; use a `Modal` for complex workflows.
183
+ - Don't render `AnimatedListItem` outside of `AnimatedList` — the item component returns a `Fragment` and relies entirely on the parent list for rendering.
184
+
185
+ ## Accessibility
186
+
187
+ - The list renders as `<ul role="list">`.
188
+ - Each row title/description area is a `<button>`, making it keyboard focusable and activatable with `Enter` or `Space`.
189
+ - The overlay uses `FloatingFocusManager` to trap focus and `FloatingOverlay` with `lockScroll` to block background interaction.
190
+ - Pressing `Escape`, clicking outside, or clicking the close button dismisses the overlay.
191
+ - The close button inside the overlay is a focusable `<button>` with an `XIcon`.
192
+ - `MotionConfig reducedMotion="user"` honours the system-level reduced-motion preference, disabling animations when requested.
193
+
194
+ ## Data Attributes
195
+
196
+ - `layoutId="item-{id}"` — shared between the list row `<li>` and the overlay card `<motion.div>` to drive the shared-element expand/collapse animation.
197
+ - `layoutId="toast-{id}"` — inner content wrapper for coordinated layout transitions.
198
+
199
+ ## Notes
200
+
201
+ - Only one item can be open at a time; selecting a new item dismisses the previous overlay automatically.
202
+ - `AnimatedListItem` is a shell — it returns a `Fragment` directly and holds no state. All rendering logic lives inside `AnimatedList`, which reads child props via `React.Children.toArray`.
203
+ - The overlay is rendered in a `FloatingPortal` (outside the DOM tree) to avoid stacking-context or overflow clipping issues.
204
+ - Animations use `motion/react` shared-layout (`layoutId`) so the item card expands smoothly from its row position to the center of the viewport.
205
+ - The animation transition is `tween` with a 0.3 s duration; `stiffness` is set low (25) for a relaxed feel.