@rebasepro/cli 0.6.1 → 0.8.0

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 (57) hide show
  1. package/README.md +0 -1
  2. package/dist/commands/api-keys.d.ts +1 -0
  3. package/dist/commands/generate_sdk.d.ts +1 -1
  4. package/dist/index.es.js +464 -58
  5. package/dist/index.es.js.map +1 -1
  6. package/dist/utils/project.d.ts +15 -0
  7. package/package.json +8 -9
  8. package/templates/template/backend/Dockerfile +4 -3
  9. package/templates/template/backend/functions/hello.ts +32 -32
  10. package/templates/template/backend/package.json +1 -1
  11. package/templates/template/backend/src/index.ts +1 -2
  12. package/templates/template/config/collections/posts.ts +4 -4
  13. package/templates/template/config/collections/presets/ecommerce/categories.ts +3 -1
  14. package/templates/template/config/collections/presets/ecommerce/orders.ts +3 -1
  15. package/templates/template/config/collections/presets/ecommerce/products.ts +3 -1
  16. package/templates/template/config/collections/tags.ts +1 -3
  17. package/templates/template/config/collections/users.ts +4 -5
  18. package/templates/template/frontend/Dockerfile +5 -3
  19. package/templates/template/package.json +3 -2
  20. package/templates/template/pnpm-workspace.yaml +2 -0
  21. package/templates/template/scripts/example.ts +5 -2
  22. package/skills/rebase-admin/SKILL.md +0 -710
  23. package/skills/rebase-api/SKILL.md +0 -662
  24. package/skills/rebase-api/references/.gitkeep +0 -3
  25. package/skills/rebase-auth/SKILL.md +0 -1143
  26. package/skills/rebase-auth/references/.gitkeep +0 -3
  27. package/skills/rebase-backend-postgres/SKILL.md +0 -633
  28. package/skills/rebase-backend-postgres/references/.gitkeep +0 -3
  29. package/skills/rebase-basics/SKILL.md +0 -749
  30. package/skills/rebase-basics/references/.gitkeep +0 -3
  31. package/skills/rebase-collections/SKILL.md +0 -1328
  32. package/skills/rebase-collections/references/.gitkeep +0 -3
  33. package/skills/rebase-cron-jobs/SKILL.md +0 -699
  34. package/skills/rebase-cron-jobs/references/.gitkeep +0 -1
  35. package/skills/rebase-custom-functions/SKILL.md +0 -233
  36. package/skills/rebase-deployment/SKILL.md +0 -885
  37. package/skills/rebase-deployment/references/.gitkeep +0 -3
  38. package/skills/rebase-design-language/SKILL.md +0 -692
  39. package/skills/rebase-email/SKILL.md +0 -701
  40. package/skills/rebase-email/references/.gitkeep +0 -1
  41. package/skills/rebase-entity-history/SKILL.md +0 -485
  42. package/skills/rebase-entity-history/references/.gitkeep +0 -1
  43. package/skills/rebase-local-env-setup/SKILL.md +0 -189
  44. package/skills/rebase-local-env-setup/references/.gitkeep +0 -3
  45. package/skills/rebase-realtime/SKILL.md +0 -755
  46. package/skills/rebase-realtime/references/.gitkeep +0 -3
  47. package/skills/rebase-sdk/SKILL.md +0 -594
  48. package/skills/rebase-sdk/references/.gitkeep +0 -0
  49. package/skills/rebase-storage/SKILL.md +0 -765
  50. package/skills/rebase-storage/references/.gitkeep +0 -3
  51. package/skills/rebase-studio/SKILL.md +0 -746
  52. package/skills/rebase-studio/references/.gitkeep +0 -3
  53. package/skills/rebase-ui-components/SKILL.md +0 -1488
  54. package/skills/rebase-ui-components/references/.gitkeep +0 -3
  55. package/skills/rebase-webhooks/SKILL.md +0 -623
  56. package/skills/rebase-webhooks/references/.gitkeep +0 -1
  57. package/templates/template/backend/drizzle.config.ts +0 -51
@@ -1,1488 +0,0 @@
1
- ---
2
- name: rebase-ui-components
3
- description: Guide for using the @rebasepro/ui component library. Use this skill when building UI with Rebase, creating custom views, or needing to know which components are available.
4
- ---
5
-
6
- # Rebase UI Component Library
7
-
8
- `@rebasepro/ui` is Rebase's standalone, production-ready component library built on **Tailwind CSS v4** and **Radix UI**. It's fully typed, accessible, and can be used in any React project.
9
-
10
- > **IMPORTANT FOR AGENTS:** Always import components, hooks, utilities, icons, and style mixins from `@rebasepro/ui`. **Never** add direct `@radix-ui/*` or `lucide-react` dependencies — the UI package re-exports everything you need.
11
-
12
- ## Installation
13
-
14
- ```bash
15
- pnpm add @rebasepro/ui
16
- ```
17
-
18
- ## Core Rules
19
-
20
- 1. **Always use `@rebasepro/ui`** for all UI components. Check this skill before creating custom ones.
21
- 2. **Never use `as any`** — use proper types or `unknown`.
22
- 3. **Use `cls()`** for conditional class merging — not template literals.
23
- 4. **Use `Typography`** for all text — never raw `<h1>`, `<p>`, `<span>`.
24
- 5. **Icons come from `lucide-react` via `@rebasepro/ui`** — there are no `ArrowForwardIcon` or `AddIcon` exports. Use real lucide names like `ArrowRightIcon`, `PlusIcon`.
25
-
26
- ## Package Exports
27
-
28
- The package exports five modules:
29
-
30
- ```ts
31
- export * from "./components"; // All UI components
32
- export * from "./styles"; // Tailwind style mixin strings
33
- export * from "./util"; // cls(), debounce(), chip_colors, keyToIconComponent
34
- export * from "./icons"; // Icon component, iconSize, lucideIcons map, icon_keys, cool_icon_keys
35
- export * from "./hooks"; // React hooks
36
- ```
37
-
38
- ---
39
-
40
- ## Components — Complete Reference
41
-
42
- ### Button
43
-
44
- Polymorphic button with multiple variants and colors.
45
-
46
- | Prop | Type | Default | Description |
47
- |------|------|---------|-------------|
48
- | `variant` | `"filled" \| "outlined" \| "text"` | `"filled"` | Visual style |
49
- | `color` | `"primary" \| "secondary" \| "text" \| "error" \| "neutral"` | `"neutral"` | Color scheme |
50
- | `size` | `"small" \| "medium" \| "large" \| "xl" \| "2xl"` | `"medium"` | Size preset |
51
- | `startIcon` | `ReactNode` | `null` | Icon before label |
52
- | `fullWidth` | `boolean` | `false` | Stretch to container width |
53
- | `disabled` | `boolean` | `false` | Disabled state |
54
- | `component` | `React.ElementType` | `"button"` | Render as a different element (e.g. `"a"`) |
55
- | `className` | `string` | — | Additional classes |
56
- | `onClick` | `MouseEventHandler` | — | Click handler |
57
-
58
- ```tsx
59
- import { Button } from "@rebasepro/ui";
60
- import { PlusIcon } from "@rebasepro/ui";
61
-
62
- <Button variant="filled" color="primary" size="large" startIcon={<PlusIcon size={20} />}>
63
- Create Item
64
- </Button>
65
-
66
- <Button variant="outlined" color="error" size="small">Delete</Button>
67
- <Button variant="text" color="secondary">Cancel</Button>
68
-
69
- {/* As an anchor */}
70
- <Button component="a" href="/docs" variant="text" color="primary">
71
- Go to Docs
72
- </Button>
73
- ```
74
-
75
- ### IconButton
76
-
77
- Icon-only button with ghost or filled background.
78
-
79
- | Prop | Type | Default | Description |
80
- |------|------|---------|-------------|
81
- | `size` | `"smallest" \| "small" \| "medium" \| "large"` | `"medium"` | Size (6/8/10/12 = 24/32/40/48 px) |
82
- | `variant` | `"ghost" \| "filled"` | `"ghost"` | Background style |
83
- | `shape` | `"circular" \| "square"` | `"circular"` | Border radius |
84
- | `disabled` | `boolean` | — | Disabled state |
85
- | `toggled` | `boolean` | — | Shows outline ring when toggled |
86
- | `component` | `React.ElementType` | `"button"` | Polymorphic element |
87
- | `onClick` | `MouseEventHandler` | — | Click handler |
88
- | `aria-label` | `string` | — | Required for accessibility |
89
-
90
- ```tsx
91
- import { IconButton } from "@rebasepro/ui";
92
- import { SettingsIcon } from "@rebasepro/ui";
93
-
94
- <IconButton aria-label="Settings" onClick={openSettings}>
95
- <SettingsIcon size={20} />
96
- </IconButton>
97
- ```
98
-
99
- ### LoadingButton
100
-
101
- Extends `Button` with a loading spinner. Automatically disables when loading.
102
-
103
- | Prop | Type | Default | Description |
104
- |------|------|---------|-------------|
105
- | `loading` | `boolean` | — | Shows spinner, hides startIcon, disables button |
106
- | _...all ButtonProps_ | | | Inherits all Button props |
107
-
108
- ```tsx
109
- import { LoadingButton } from "@rebasepro/ui";
110
-
111
- <LoadingButton loading={isSaving} variant="filled" color="primary" onClick={handleSave}>
112
- Save Changes
113
- </LoadingButton>
114
- ```
115
-
116
- ### Typography
117
-
118
- Renders text with semantic HTML elements and consistent styling.
119
-
120
- | Prop | Type | Default | Description |
121
- |------|------|---------|-------------|
122
- | `variant` | `TypographyVariant` (see below) | `"body1"` | Text style |
123
- | `color` | `"inherit" \| "initial" \| "primary" \| "secondary" \| "disabled" \| "error"` | `"primary"` | Text color |
124
- | `component` | `React.ElementType` | auto from variant | Override rendered element |
125
- | `gutterBottom` | `boolean` | `false` | Adds bottom margin |
126
- | `noWrap` | `boolean` | `false` | Truncate with ellipsis |
127
- | `paragraph` | `boolean` | `false` | Renders as `<p>` with margin |
128
- | `align` | `"center" \| "inherit" \| "justify" \| "left" \| "right"` | `"inherit"` | Text alignment |
129
- | `variantMapping` | `Record<string, string>` | built-in | Override variant→element mapping |
130
-
131
- **TypographyVariant values:** `"h1"`, `"h2"`, `"h3"`, `"h4"`, `"h5"`, `"h6"`, `"subtitle1"`, `"subtitle2"`, `"label"`, `"body1"`, `"body2"`, `"inherit"`, `"caption"`, `"button"`
132
-
133
- | Variant | Default Element | CSS Class |
134
- |---------|----------------|-----------|
135
- | `h1`–`h6` | `<h1>`–`<h6>` | `typography-h1`–`typography-h6` |
136
- | `subtitle1`, `subtitle2` | `<h6>` | `typography-subtitle1/2` |
137
- | `body1`, `body2` | `<p>` | `typography-body1/2` |
138
- | `label` | `<label>` | `typography-label` |
139
- | `caption` | `<p>` | `typography-caption` |
140
- | `button` | `<span>` | `typography-button` |
141
-
142
- ```tsx
143
- import { Typography } from "@rebasepro/ui";
144
-
145
- <Typography variant="h4" gutterBottom>Page Title</Typography>
146
- <Typography variant="body1">Regular text content</Typography>
147
- <Typography variant="caption" color="secondary">Helper text</Typography>
148
- <Typography variant="body2" color="error">Validation message</Typography>
149
- <Typography variant="h6" noWrap>Very long title that will truncate...</Typography>
150
- ```
151
-
152
- ### Container
153
-
154
- Centered max-width container with responsive padding.
155
-
156
- | Prop | Type | Default | Description |
157
- |------|------|---------|-------------|
158
- | `maxWidth` | `"xs" \| "sm" \| "md" \| "lg" \| "xl" \| "2xl" \| "3xl" \| "4xl" \| "5xl" \| "6xl" \| "7xl"` | `"7xl"` | Maximum width |
159
- | `className` | `string` | — | Extra classes |
160
- | `style` | `CSSProperties` | — | Inline styles |
161
-
162
- ```tsx
163
- import { Container } from "@rebasepro/ui";
164
-
165
- <Container maxWidth="4xl">
166
- {/* Content limited to max-w-4xl with mx-auto px-3 md:px-4 */}
167
- </Container>
168
- ```
169
-
170
- ### Card
171
-
172
- Bordered card with optional click behavior. Automatically adds keyboard support and `role="button"` when `onClick` is provided.
173
-
174
- | Prop | Type | Default | Description |
175
- |------|------|---------|-------------|
176
- | `onClick` | `(e?: React.MouseEvent) => void` | — | Makes card clickable with hover effects |
177
- | `className` | `string` | — | Extra classes (padding NOT included — add `p-4`/`p-6`) |
178
- | `style` | `CSSProperties` | — | Inline styles |
179
-
180
- > **IMPORTANT FOR AGENTS:** Card does NOT include padding. Always add `className="p-4"` or similar.
181
-
182
- ```tsx
183
- import { Card, Typography } from "@rebasepro/ui";
184
-
185
- {/* Static card */}
186
- <Card className="p-6">
187
- <Typography variant="h6">Title</Typography>
188
- <Typography variant="body2" color="secondary">Description</Typography>
189
- </Card>
190
-
191
- {/* Clickable card — gets hover effects automatically */}
192
- <Card className="p-4" onClick={() => navigate("/details")}>
193
- <Typography variant="body1">Click me</Typography>
194
- </Card>
195
- ```
196
-
197
- ### Paper
198
-
199
- Minimal bordered container. Uses `paperMixin` styling: white bg, rounded-md, border.
200
-
201
- ```tsx
202
- import { Paper } from "@rebasepro/ui";
203
- <Paper className="p-4">Content</Paper>
204
- ```
205
-
206
- ### CenteredView
207
-
208
- Centers content vertically and horizontally within a full-height container.
209
-
210
- ```tsx
211
- import { CenteredView } from "@rebasepro/ui";
212
- <CenteredView>
213
- <Typography>Centered content</Typography>
214
- </CenteredView>
215
- ```
216
-
217
- ### Alert
218
-
219
- Contextual alert banner with color-coded left border.
220
-
221
- | Prop | Type | Default | Description |
222
- |------|------|---------|-------------|
223
- | `color` | `"error" \| "warning" \| "info" \| "success" \| "base"` | `"info"` | Alert severity |
224
- | `size` | `"small" \| "medium" \| "large"` | `"medium"` | Padding size |
225
- | `onDismiss` | `() => void` | — | Shows × dismiss button |
226
- | `action` | `ReactNode` | — | Action element on right side |
227
- | `className` | `string` | — | Class for inner content div |
228
- | `outerClassName` | `string` | — | Class for outer container |
229
- | `style` | `CSSProperties` | — | Inline styles |
230
-
231
- ```tsx
232
- import { Alert, Button } from "@rebasepro/ui";
233
-
234
- <Alert color="error" onDismiss={() => setShow(false)}>
235
- Something went wrong. Please try again.
236
- </Alert>
237
-
238
- <Alert color="success" size="small">
239
- Record saved successfully!
240
- </Alert>
241
-
242
- <Alert color="warning" action={<Button variant="text" size="small">Fix</Button>}>
243
- Missing required fields
244
- </Alert>
245
- ```
246
-
247
- ### Chip
248
-
249
- Colored label/tag with optional icon.
250
-
251
- | Prop | Type | Default | Description |
252
- |------|------|---------|-------------|
253
- | `colorScheme` | `ChipColorScheme \| ChipColorKey` | — | Color. Can be a key string (`"blue"`, `"teal"`, etc.) or a `ChipColorScheme` object |
254
- | `size` | `"smallest" \| "small" \| "medium" \| "large"` | `"large"` | Size preset |
255
- | `outlined` | `boolean` | — | Outlined variant with translucent bg |
256
- | `error` | `boolean` | — | Red error styling |
257
- | `onClick` | `() => void` | — | Makes chip clickable |
258
- | `icon` | `ReactNode` | — | Icon rendered after text |
259
- | `className` | `string` | — | Extra classes |
260
-
261
- **ChipColorKey values:** `"blue"`, `"teal"`, `"yellow"`, `"pink"`, `"purple"`, `"cyan"`, `"orange"`, `"green"`, `"red"`, `"gray"`, `"indigo"`, `"violet"`, `"fuchsia"`, `"rose"`, `"emerald"`
262
-
263
- ```tsx
264
- import { Chip } from "@rebasepro/ui";
265
-
266
- <Chip colorScheme="blue" size="medium">Active</Chip>
267
- <Chip colorScheme="red" outlined>Urgent</Chip>
268
- <Chip error>Error</Chip>
269
- <Chip size="small">Default</Chip>
270
- ```
271
-
272
- ### FilterChip
273
-
274
- Toggle chip for filter presets. Uses inset box-shadow for stable sizing.
275
-
276
- | Prop | Type | Default | Description |
277
- |------|------|---------|-------------|
278
- | `active` | `boolean` | `false` | Selected/active state |
279
- | `icon` | `ReactNode` | — | Icon before label |
280
- | `size` | `"small" \| "medium"` | `"medium"` | Size preset |
281
- | `disabled` | `boolean` | `false` | Disabled state |
282
- | `onClick` | handler | — | Click handler |
283
-
284
- ```tsx
285
- import { FilterChip } from "@rebasepro/ui";
286
-
287
- <FilterChip active={filter === "active"} onClick={() => setFilter("active")}>
288
- Active
289
- </FilterChip>
290
- ```
291
-
292
- ### Dialog, DialogTitle, DialogContent, DialogActions
293
-
294
- Modal dialog built on Radix Dialog.
295
-
296
- **Dialog Props:**
297
-
298
- | Prop | Type | Default | Description |
299
- |------|------|---------|-------------|
300
- | `open` | `boolean` | — | Controlled open state |
301
- | `onOpenChange` | `(open: boolean) => void` | — | Open state callback |
302
- | `maxWidth` | `"xs" \| "sm" \| "md" \| "lg" \| "xl" \| "2xl"–"7xl" \| "full"` | `"lg"` | Dialog max width |
303
- | `fullWidth` | `boolean` | `true` | Use 11/12 of available width |
304
- | `fullHeight` | `boolean` | — | Full height |
305
- | `fullScreen` | `boolean` | — | Full screen overlay |
306
- | `scrollable` | `boolean` | `true` | Scrollable content |
307
- | `modal` | `boolean` | `true` | Modal behavior |
308
- | `disableInitialFocus` | `boolean` | `true` | Skip auto-focus on open |
309
-
310
- **DialogTitle Props:**
311
-
312
- | Prop | Type | Default | Description |
313
- |------|------|---------|-------------|
314
- | `variant` | `TypographyVariant` | `"subtitle2"` | Typography variant |
315
- | `hidden` | `boolean` | — | Visually hidden (for a11y) |
316
- | `includeMargin` | `boolean` | `true` | Add mt-8 mx-8 margin |
317
- | `gutterBottom` | `boolean` | `true` | Bottom margin |
318
-
319
- **DialogContent Props:**
320
-
321
- | Prop | Type | Default | Description |
322
- |------|------|---------|-------------|
323
- | `includeMargin` | `boolean` | `true` | Add my-8 mx-8 margin |
324
- | `fullHeight` | `boolean` | — | Flex-grow full height |
325
-
326
- **DialogActions Props:**
327
-
328
- | Prop | Type | Default | Description |
329
- |------|------|---------|-------------|
330
- | `position` | `"sticky" \| "absolute"` | `"sticky"` | Positioning |
331
- | `translucent` | `boolean` | `true` | Backdrop blur effect |
332
-
333
- ```tsx
334
- import { Dialog, DialogTitle, DialogContent, DialogActions, Button } from "@rebasepro/ui";
335
-
336
- function ConfirmDialog({ open, onClose, onConfirm }) {
337
- return (
338
- <Dialog open={open} onOpenChange={onClose} maxWidth="sm">
339
- <DialogTitle>Confirm Action</DialogTitle>
340
- <DialogContent>
341
- <Typography>Are you sure you want to proceed?</Typography>
342
- </DialogContent>
343
- <DialogActions>
344
- <Button variant="text" onClick={onClose}>Cancel</Button>
345
- <Button variant="filled" color="primary" onClick={onConfirm}>
346
- Confirm
347
- </Button>
348
- </DialogActions>
349
- </Dialog>
350
- );
351
- }
352
- ```
353
-
354
- ### Select, SelectItem, SelectGroup
355
-
356
- Radix-based single-value select dropdown.
357
-
358
- **Select Props:**
359
-
360
- | Prop | Type | Default | Description |
361
- |------|------|---------|-------------|
362
- | `value` | `string \| number \| boolean` | — | Selected value |
363
- | `onValueChange` | `(value: T) => void` | — | Value change callback |
364
- | `size` | `"smallest" \| "small" \| "medium" \| "large"` | `"large"` | Size preset |
365
- | `label` | `ReactNode \| string` | — | Label (string renders as `SelectInputLabel`) |
366
- | `placeholder` | `ReactNode` | — | Placeholder when no value |
367
- | `renderValue` | `(value: T) => ReactNode` | — | Custom value renderer |
368
- | `disabled` | `boolean` | — | Disabled state |
369
- | `error` | `boolean` | — | Error styling |
370
- | `invisible` | `boolean` | — | Transparent background |
371
- | `fullWidth` | `boolean` | `false` | Full width |
372
- | `position` | `"item-aligned" \| "popper"` | `"item-aligned"` | Dropdown position |
373
- | `endAdornment` | `ReactNode` | — | End adornment |
374
- | `dataType` | `"string" \| "number" \| "boolean"` | `"string"` | Type coercion for value |
375
-
376
- ```tsx
377
- import { Select, SelectItem, SelectGroup } from "@rebasepro/ui";
378
-
379
- <Select
380
- value={status}
381
- onValueChange={setStatus}
382
- label="Status"
383
- placeholder="Select a status"
384
- size="large"
385
- >
386
- <SelectGroup label="Active">
387
- <SelectItem value="draft">Draft</SelectItem>
388
- <SelectItem value="published">Published</SelectItem>
389
- </SelectGroup>
390
- <SelectItem value="archived">Archived</SelectItem>
391
- </Select>
392
- ```
393
-
394
- ### MultiSelect, MultiSelectItem
395
-
396
- Multi-value select with search, chips, select-all, and clear.
397
-
398
- **MultiSelect Props:**
399
-
400
- | Prop | Type | Default | Description |
401
- |------|------|---------|-------------|
402
- | `value` | `T[]` | — | Selected values |
403
- | `onValueChange` | `(values: T[]) => void` | — | Change callback |
404
- | `size` | `"smallest" \| "small" \| "medium" \| "large"` | `"large"` | Size |
405
- | `label` | `ReactNode \| string` | — | Label |
406
- | `placeholder` | `ReactNode` | — | Placeholder |
407
- | `useChips` | `boolean` | `true` | Show selected values as chips |
408
- | `includeSelectAll` | `boolean` | `true` | Show "(Select All)" option |
409
- | `includeClear` | `boolean` | `true` | Show clear button |
410
- | `renderValues` | `(values: T[]) => ReactNode` | — | Custom selected values renderer |
411
- | `disabled`, `error`, `invisible` | `boolean` | — | State flags |
412
-
413
- ```tsx
414
- import { MultiSelect, MultiSelectItem } from "@rebasepro/ui";
415
-
416
- <MultiSelect
417
- value={selectedTags}
418
- onValueChange={setSelectedTags}
419
- label="Tags"
420
- placeholder="Select tags..."
421
- >
422
- <MultiSelectItem value="frontend">Frontend</MultiSelectItem>
423
- <MultiSelectItem value="backend">Backend</MultiSelectItem>
424
- <MultiSelectItem value="devops">DevOps</MultiSelectItem>
425
- </MultiSelect>
426
- ```
427
-
428
- ### TextField
429
-
430
- Single-line or multiline text input with floating label.
431
-
432
- | Prop | Type | Default | Description |
433
- |------|------|---------|-------------|
434
- | `value` | `string \| number` | — | Input value |
435
- | `onChange` | `ChangeEventHandler` | — | Change handler |
436
- | `label` | `ReactNode` | — | Floating label |
437
- | `type` | `InputType` | `"text"` | `"text" \| "number" \| "email" \| "password" \| "url" \| "search"` etc. |
438
- | `size` | `"smallest" \| "small" \| "medium" \| "large"` | `"large"` | Height preset |
439
- | `multiline` | `boolean` | `false` | Renders as textarea |
440
- | `disabled` | `boolean` | — | Disabled state |
441
- | `invisible` | `boolean` | — | Transparent bg |
442
- | `error` | `boolean` | — | Error border |
443
- | `placeholder` | `string` | — | Placeholder text |
444
- | `endAdornment` | `ReactNode` | — | Element at input end |
445
- | `autoFocus` | `boolean` | — | Auto focus |
446
-
447
- ```tsx
448
- import { TextField } from "@rebasepro/ui";
449
-
450
- <TextField
451
- label="Email"
452
- type="email"
453
- value={email}
454
- onChange={(e) => setEmail(e.target.value)}
455
- size="large"
456
- error={!isValid}
457
- />
458
-
459
- <TextField
460
- label="Description"
461
- multiline
462
- minRows={3}
463
- value={desc}
464
- onChange={(e) => setDesc(e.target.value)}
465
- />
466
- ```
467
-
468
- ### DebouncedTextField
469
-
470
- Wraps `TextField` with 150ms debounce. Flushes on blur. Same props as `TextField`.
471
-
472
- ```tsx
473
- import { DebouncedTextField } from "@rebasepro/ui";
474
-
475
- <DebouncedTextField
476
- label="Search"
477
- value={searchTerm}
478
- onChange={(e) => setSearchTerm(e.target.value)}
479
- />
480
- ```
481
-
482
- ### Tabs, Tab
483
-
484
- Tabbed navigation with three visual variants.
485
-
486
- **Tabs Props:**
487
-
488
- | Prop | Type | Default | Description |
489
- |------|------|---------|-------------|
490
- | `value` | `string` | — | Active tab value |
491
- | `onValueChange` | `(value: string) => void` | — | Tab change callback |
492
- | `variant` | `"standard" \| "boxy" \| "pill"` | `"standard"` | Visual style |
493
- | `className` | `string` | — | Outer container class |
494
- | `innerClassName` | `string` | — | Tab list class |
495
-
496
- **Tab Props:**
497
-
498
- | Prop | Type | Default | Description |
499
- |------|------|---------|-------------|
500
- | `value` | `string` | — | Tab identifier |
501
- | `disabled` | `boolean` | — | Disabled state |
502
- | `className` | `string` | — | Extra classes |
503
-
504
- ```tsx
505
- import { Tabs, Tab } from "@rebasepro/ui";
506
-
507
- <Tabs value={activeTab} onValueChange={setActiveTab} variant="standard">
508
- <Tab value="general">General</Tab>
509
- <Tab value="advanced">Advanced</Tab>
510
- <Tab value="settings">Settings</Tab>
511
- </Tabs>
512
-
513
- {/* Boxy variant — bordered tabs with bottom highlight */}
514
- <Tabs value={tab} onValueChange={setTab} variant="boxy">
515
- <Tab value="data">Data</Tab>
516
- <Tab value="schema">Schema</Tab>
517
- </Tabs>
518
-
519
- {/* Pill variant — compact rounded pills */}
520
- <Tabs value={tab} onValueChange={setTab} variant="pill">
521
- <Tab value="all">All</Tab>
522
- <Tab value="active">Active</Tab>
523
- </Tabs>
524
- ```
525
-
526
- ### Sheet
527
-
528
- Slide-in panel overlay (side drawer) built on Radix Dialog.
529
-
530
- | Prop | Type | Default | Description |
531
- |------|------|---------|-------------|
532
- | `open` | `boolean` | — | Controlled open state |
533
- | `onOpenChange` | `(open: boolean) => void` | — | Open state change |
534
- | `side` | `"top" \| "bottom" \| "left" \| "right"` | `"right"` | Slide direction |
535
- | `modal` | `boolean` | `true` | Modal behavior |
536
- | `includeBackgroundOverlay` | `boolean` | `true` | Show backdrop blur overlay |
537
- | `transparent` | `boolean` | — | No shadow/background on panel |
538
- | `title` | `string` | `"Sheet"` | Accessible title (sr-only) |
539
- | `className` | `string` | — | Panel class |
540
- | `overlayClassName` | `string` | — | Overlay class |
541
-
542
- ```tsx
543
- import { Sheet, Typography, Button } from "@rebasepro/ui";
544
-
545
- <Sheet open={isOpen} onOpenChange={setIsOpen} side="right">
546
- <div className="p-6 w-[400px]">
547
- <Typography variant="h5" gutterBottom>Details</Typography>
548
- <Typography variant="body1">Panel content here</Typography>
549
- <Button onClick={() => setIsOpen(false)} className="mt-4">Close</Button>
550
- </div>
551
- </Sheet>
552
- ```
553
-
554
- ### Popover
555
-
556
- Positioned popover built on Radix Popover.
557
-
558
- | Prop | Type | Default | Description |
559
- |------|------|---------|-------------|
560
- | `trigger` | `ReactNode` | — | **Required.** Trigger element |
561
- | `children` | `ReactNode` | — | Popover content |
562
- | `open` | `boolean` | — | Controlled open state |
563
- | `onOpenChange` | `(open: boolean) => void` | — | Open state change |
564
- | `side` | `"top" \| "right" \| "bottom" \| "left"` | — | Preferred side |
565
- | `sideOffset` | `number` | `5` | Distance from trigger |
566
- | `align` | `"start" \| "center" \| "end"` | — | Alignment |
567
- | `enabled` | `boolean` | `true` | When false, renders trigger only |
568
- | `modal` | `boolean` | `false` | Modal behavior |
569
-
570
- ```tsx
571
- import { Popover, Button, Typography } from "@rebasepro/ui";
572
-
573
- <Popover
574
- trigger={<Button variant="outlined">Options</Button>}
575
- side="bottom"
576
- align="start"
577
- >
578
- <div className="p-4">
579
- <Typography variant="body2">Popover content</Typography>
580
- </div>
581
- </Popover>
582
- ```
583
-
584
- ### ExpandablePanel
585
-
586
- Collapsible panel with animated open/close.
587
-
588
- | Prop | Type | Default | Description |
589
- |------|------|---------|-------------|
590
- | `title` | `ReactNode` | — | **Required.** Panel header |
591
- | `initiallyExpanded` | `boolean` | `true` | Initial open state |
592
- | `expanded` | `boolean` | — | Controlled open state |
593
- | `onExpandedChange` | `(expanded: boolean) => void` | — | Expansion change callback |
594
- | `invisible` | `boolean` | `false` | Remove border, use border-bottom only |
595
- | `asField` | `boolean` | — | Apply field background styling |
596
- | `className` | `string` | — | Root container class |
597
- | `innerClassName` | `string` | — | Content wrapper class |
598
- | `titleClassName` | `string` | — | Trigger header class |
599
-
600
- ```tsx
601
- import { ExpandablePanel, Typography } from "@rebasepro/ui";
602
-
603
- <ExpandablePanel title={<Typography variant="subtitle2">Advanced Options</Typography>}>
604
- <div className="p-4">
605
- {/* panel content */}
606
- </div>
607
- </ExpandablePanel>
608
-
609
- {/* Controlled, initially collapsed */}
610
- <ExpandablePanel
611
- title="Filters"
612
- initiallyExpanded={false}
613
- invisible
614
- asField
615
- >
616
- {/* filter form fields */}
617
- </ExpandablePanel>
618
- ```
619
-
620
- ### BooleanSwitch
621
-
622
- Standalone toggle switch.
623
-
624
- | Prop | Type | Default | Description |
625
- |------|------|---------|-------------|
626
- | `value` | `boolean \| null` | — | Current value |
627
- | `onValueChange` | `(value: boolean) => void` | — | Change callback |
628
- | `disabled` | `boolean` | `false` | Disabled state |
629
- | `size` | `"smallest" \| "small" \| "medium" \| "large"` | `"medium"` | Size preset |
630
- | `allowIndeterminate` | `boolean` | `false` | Allow null (three-state) |
631
-
632
- ### BooleanSwitchWithLabel
633
-
634
- Toggle switch with a label. Wraps `BooleanSwitch`.
635
-
636
- | Prop | Type | Default | Description |
637
- |------|------|---------|-------------|
638
- | `label` | `ReactNode` | — | Label text |
639
- | `position` | `"start" \| "end"` | `"end"` | Label position relative to switch |
640
- | `invisible` | `boolean` | — | Remove field background |
641
- | `error` | `boolean` | — | Error state |
642
- | `fullWidth` | `boolean` | `true` | Full width |
643
- | `size` | `"smallest" \| "small" \| "medium" \| "large"` | `"medium"` | Size |
644
- | _...all BooleanSwitchProps_ | | | |
645
-
646
- ```tsx
647
- import { BooleanSwitchWithLabel } from "@rebasepro/ui";
648
-
649
- <BooleanSwitchWithLabel
650
- value={isEnabled}
651
- onValueChange={setIsEnabled}
652
- label="Enable notifications"
653
- size="medium"
654
- />
655
- ```
656
-
657
- ### Checkbox
658
-
659
- Styled checkbox based on Radix Checkbox. See source for full props.
660
-
661
- ### RadioGroup, RadioGroupItem
662
-
663
- Radio button group built on Radix RadioGroup.
664
-
665
- | Prop (RadioGroup) | Type | Default | Description |
666
- |------|------|---------|-------------|
667
- | `value` | `string` | — | Selected value |
668
- | `onValueChange` | `(value: string) => void` | — | Change callback |
669
- | `disabled` | `boolean` | — | Disabled |
670
- | `loop` | `boolean` | `false` | Keyboard navigation loops |
671
-
672
- ```tsx
673
- import { RadioGroup, RadioGroupItem } from "@rebasepro/ui";
674
-
675
- <RadioGroup value={plan} onValueChange={setPlan}>
676
- <div className="flex items-center gap-2">
677
- <RadioGroupItem value="free" />
678
- <label>Free</label>
679
- </div>
680
- <div className="flex items-center gap-2">
681
- <RadioGroupItem value="pro" />
682
- <label>Pro</label>
683
- </div>
684
- </RadioGroup>
685
- ```
686
-
687
- ### Slider
688
-
689
- Range slider with tooltip, built on Radix Slider.
690
-
691
- | Prop | Type | Default | Description |
692
- |------|------|---------|-------------|
693
- | `value` | `number[]` | — | Current value(s) |
694
- | `onValueChange` | `(value: number[]) => void` | — | Live change |
695
- | `onValueCommit` | `(value: number[]) => void` | — | Change on release |
696
- | `min` | `number` | — | Minimum |
697
- | `max` | `number` | — | Maximum |
698
- | `step` | `number` | — | Step size |
699
- | `disabled` | `boolean` | — | Disabled |
700
- | `size` | `"small" \| "regular"` | `"regular"` | Track/thumb size |
701
-
702
- ```tsx
703
- import { Slider } from "@rebasepro/ui";
704
-
705
- <Slider
706
- value={[volume]}
707
- onValueChange={([v]) => setVolume(v)}
708
- min={0}
709
- max={100}
710
- step={1}
711
- />
712
- ```
713
-
714
- ### DateTimeField
715
-
716
- Date/datetime picker using native `<input type="date|datetime-local">`.
717
-
718
- | Prop | Type | Default | Description |
719
- |------|------|---------|-------------|
720
- | `value` | `Date \| null` | — | Date value |
721
- | `onChange` | `(date: Date \| null) => void` | — | Change callback |
722
- | `mode` | `"date" \| "date_time"` | `"date"` | Date only or datetime |
723
- | `disabled` | `boolean` | — | Disabled |
724
- | `clearable` | `boolean` | — | Show clear button |
725
- | `error` | `boolean` | — | Error state |
726
- | `size` | `"smallest" \| "small" \| "medium" \| "large"` | `"large"` | Size |
727
- | `label` | `ReactNode` | — | Floating label |
728
- | `timezone` | `string` | local | IANA timezone string |
729
-
730
- ```tsx
731
- import { DateTimeField } from "@rebasepro/ui";
732
-
733
- <DateTimeField
734
- value={dueDate}
735
- onChange={setDueDate}
736
- mode="date_time"
737
- label="Due Date"
738
- clearable
739
- timezone="America/New_York"
740
- />
741
- ```
742
-
743
- ### ColorPicker
744
-
745
- Grid of color swatches using `CHIP_COLORS`. For selecting colors for enum values and tags.
746
-
747
- | Prop | Type | Default | Description |
748
- |------|------|---------|-------------|
749
- | `value` | `ChipColorKey` | — | Selected color key |
750
- | `onChange` | `(key: ChipColorKey \| undefined) => void` | — | Change callback |
751
- | `size` | `"small" \| "medium"` | `"medium"` | Swatch size |
752
- | `allowClear` | `boolean` | `true` | Show "Auto" clear option |
753
- | `disabled` | `boolean` | `false` | Disabled |
754
-
755
- ```tsx
756
- import { ColorPicker } from "@rebasepro/ui";
757
-
758
- <ColorPicker value={color} onChange={setColor} />
759
- ```
760
-
761
- ### FileUpload
762
-
763
- Drag-and-drop file upload zone using `react-dropzone`.
764
-
765
- | Prop | Type | Default | Description |
766
- |------|------|---------|-------------|
767
- | `onFilesAdded` | `(files: File[]) => void` | — | **Required.** Files accepted callback |
768
- | `onFilesRejected` | handler | — | Files rejected callback |
769
- | `accept` | `Record<string, string[]>` | — | MIME type filter, e.g. `{ "image/*": [] }` |
770
- | `maxSize` | `number` | — | Max file size in bytes |
771
- | `maxFiles` | `number` | — | Max number of files |
772
- | `disabled` | `boolean` | — | Disabled |
773
- | `title` | `ReactNode` | — | Top-left caption |
774
- | `uploadDescription` | `ReactNode` | — | Center description |
775
- | `size` | `"small" \| "medium" \| "large"` | — | Height: 64/112/176 px |
776
-
777
- ```tsx
778
- import { FileUpload } from "@rebasepro/ui";
779
-
780
- <FileUpload
781
- accept={{ "image/*": [] }}
782
- onFilesAdded={(files) => handleUpload(files)}
783
- title="Cover Image"
784
- uploadDescription="Drop an image or click to browse"
785
- size="medium"
786
- />
787
- ```
788
-
789
- ### SearchBar
790
-
791
- Debounced search input with clear button and loading state.
792
-
793
- | Prop | Type | Default | Description |
794
- |------|------|---------|-------------|
795
- | `onTextSearch` | `(searchString?: string) => void` | — | Debounced search callback |
796
- | `placeholder` | `string` | `"Search"` | Placeholder text |
797
- | `size` | `"smallest" \| "small" \| "medium"` | `"medium"` | Height preset |
798
- | `expandable` | `boolean` | `false` | Expand on focus |
799
- | `loading` | `boolean` | — | Show spinner instead of icon |
800
- | `disabled` | `boolean` | — | Disabled |
801
- | `autoFocus` | `boolean` | — | Auto focus |
802
- | `initialValue` | `string` | — | Initial search text |
803
-
804
- ```tsx
805
- import { SearchBar } from "@rebasepro/ui";
806
-
807
- <SearchBar
808
- onTextSearch={(term) => filterItems(term)}
809
- placeholder="Search items..."
810
- size="small"
811
- />
812
- ```
813
-
814
- ### Table, TableHeader, TableBody, TableRow, TableCell
815
-
816
- Basic HTML table components with consistent styling.
817
-
818
- ```tsx
819
- import { Table, TableHeader, TableBody, TableRow, TableCell } from "@rebasepro/ui";
820
-
821
- <Table>
822
- <TableHeader>
823
- <TableCell header>Name</TableCell>
824
- <TableCell header>Email</TableCell>
825
- <TableCell header align="right">Actions</TableCell>
826
- </TableHeader>
827
- <TableBody>
828
- {users.map(user => (
829
- <TableRow key={user.id} onClick={() => selectUser(user)}>
830
- <TableCell>{user.name}</TableCell>
831
- <TableCell>{user.email}</TableCell>
832
- <TableCell align="right">
833
- <IconButton aria-label="Edit"><PencilIcon size={16} /></IconButton>
834
- </TableCell>
835
- </TableRow>
836
- ))}
837
- </TableBody>
838
- </Table>
839
- ```
840
-
841
- **TableCell extra props:** `header` (boolean), `align` (`"left" | "center" | "right"`), `colspan` (number).
842
-
843
- ### VirtualTable
844
-
845
- High-performance virtualized table for large datasets. Uses `react-window` for windowed rendering. Supports sorting, filtering, column resize, drag-and-drop column reorder, infinite scroll, and frozen columns.
846
-
847
- Key props: `data`, `columns` (array of `VirtualTableColumn`), `cellRenderer`, `onRowClick`, `onEndReached`, `filter`, `onFilterUpdate`, `sortBy`, `onSortByUpdate`, `loading`, `emptyComponent`.
848
-
849
- See `VirtualTableProps` and `VirtualTableColumn` types for full API.
850
-
851
- ### ToggleButtonGroup
852
-
853
- Single-select button group for toggling between options.
854
-
855
- | Prop | Type | Default | Description |
856
- |------|------|---------|-------------|
857
- | `value` | `T extends string` | — | Selected value |
858
- | `onValueChange` | `(value: T) => void` | — | Change callback |
859
- | `options` | `ToggleButtonOption<T>[]` | — | Array of `{ value, label, icon?, disabled? }` |
860
- | `className` | `string` | — | Extra classes |
861
-
862
- ```tsx
863
- import { ToggleButtonGroup } from "@rebasepro/ui";
864
- import { LayoutGridIcon, ListIcon } from "@rebasepro/ui";
865
-
866
- <ToggleButtonGroup
867
- value={viewMode}
868
- onValueChange={setViewMode}
869
- options={[
870
- { value: "grid", label: "Grid", icon: <LayoutGridIcon size={16} /> },
871
- { value: "list", label: "List", icon: <ListIcon size={16} /> }
872
- ]}
873
- />
874
- ```
875
-
876
- ### ResizablePanels
877
-
878
- Two-panel resizable layout with drag handle.
879
-
880
- | Prop | Type | Default | Description |
881
- |------|------|---------|-------------|
882
- | `firstPanel` | `ReactNode` | — | First panel content |
883
- | `secondPanel` | `ReactNode` | — | Second panel content |
884
- | `panelSizePercent` | `number` | — | 0–100, width/height of first panel |
885
- | `onPanelSizeChange` | `(percent: number) => void` | — | Resize callback |
886
- | `showFirstPanel` | `boolean` | `true` | Toggle first panel visibility |
887
- | `showSecondPanel` | `boolean` | `true` | Toggle second panel visibility |
888
- | `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | Layout direction |
889
- | `minPanelSizePx` | `number` | `200` | Minimum panel size in pixels |
890
- | `animateLayout` | `boolean` | `true` | Animate transitions |
891
- | `stacked` | `boolean` | `false` | Stack panels absolutely |
892
-
893
- ```tsx
894
- import { ResizablePanels } from "@rebasepro/ui";
895
-
896
- <ResizablePanels
897
- firstPanel={<Sidebar />}
898
- secondPanel={<MainContent />}
899
- panelSizePercent={30}
900
- onPanelSizeChange={setPanelSize}
901
- minPanelSizePx={250}
902
- />
903
- ```
904
-
905
- ### CircularProgress
906
-
907
- Animated loading spinner.
908
-
909
- | Prop | Type | Default | Description |
910
- |------|------|---------|-------------|
911
- | `size` | `"smallest" \| "small" \| "medium" \| "large"` | — | Size preset |
912
-
913
- ### CircularProgressCenter
914
-
915
- Full-screen centered loading spinner with optional text message.
916
-
917
- | Prop | Type | Default | Description |
918
- |------|------|---------|-------------|
919
- | `text` | `string` | — | Loading message below spinner |
920
- | _...CircularProgressProps_ | | | |
921
-
922
- ```tsx
923
- import { CircularProgressCenter } from "@rebasepro/ui";
924
-
925
- <CircularProgressCenter text="Loading data..." />
926
- ```
927
-
928
- ### ErrorBoundary
929
-
930
- React error boundary with inline or full-page error display. Detects permission errors for tailored messaging.
931
-
932
- | Prop | Type | Default | Description |
933
- |------|------|---------|-------------|
934
- | `fullPage` | `boolean` | — | Full-page centered error display |
935
- | `onReset` | `() => void` | — | Custom reset handler |
936
-
937
- ```tsx
938
- import { ErrorBoundary } from "@rebasepro/ui";
939
-
940
- <ErrorBoundary fullPage>
941
- <App />
942
- </ErrorBoundary>
943
- ```
944
-
945
- ### Tooltip
946
-
947
- Tooltip on hover, built on Radix Tooltip.
948
-
949
- | Prop | Type | Default | Description |
950
- |------|------|---------|-------------|
951
- | `title` | `string \| ReactNode` | — | Tooltip content. If falsy, renders children only |
952
- | `side` | `"top" \| "bottom" \| "left" \| "right"` | `"bottom"` | Tooltip position |
953
- | `delayDuration` | `number` | `200` | Delay in ms |
954
- | `sideOffset` | `number` | `4` | Distance from trigger |
955
- | `align` | `"start" \| "center" \| "end"` | — | Alignment |
956
-
957
- ```tsx
958
- import { Tooltip, IconButton } from "@rebasepro/ui";
959
- import { SettingsIcon } from "@rebasepro/ui";
960
-
961
- <Tooltip title="Open settings" side="bottom">
962
- <IconButton aria-label="Settings">
963
- <SettingsIcon size={20} />
964
- </IconButton>
965
- </Tooltip>
966
- ```
967
-
968
- ### Other Components
969
-
970
- | Component | Description |
971
- |-----------|-------------|
972
- | `Autocomplete` | Text input with filtered suggestions dropdown |
973
- | `Avatar` | User avatar circle with image/initials |
974
- | `Badge` | Small count badge |
975
- | `Collapse` | Animated show/hide wrapper |
976
- | `InputLabel` | Floating label used internally by `TextField`. Props: `shrink` |
977
- | `SelectInputLabel` | Small label above Select/MultiSelect. Props: `error` |
978
- | `InfoLabel` | Small info label |
979
- | `Label` | Form label |
980
- | `Markdown` | Markdown renderer |
981
- | `Menu` | Context menu |
982
- | `Menubar` | Horizontal menu bar |
983
- | `MenuItem` | Menu item |
984
- | `Paper` | Bordered container |
985
- | `Separator` | Horizontal/vertical divider |
986
- | `Skeleton` | Loading placeholder |
987
- | `TextareaAutosize` | Auto-growing textarea |
988
-
989
- ### Re-exported Radix Primitives
990
-
991
- These are re-exported so you never need a direct `@radix-ui` dependency:
992
-
993
- ```tsx
994
- import { Portal, PopoverPrimitive, Slot } from "@rebasepro/ui";
995
- ```
996
-
997
- - **`Portal`** — `@radix-ui/react-portal`
998
- - **`PopoverPrimitive`** — `@radix-ui/react-popover` (full primitive API)
999
- - **`Slot`** — `@radix-ui/react-slot` (for composition)
1000
-
1001
- ---
1002
-
1003
- ## Icon System
1004
-
1005
- > **WARNING FOR AGENTS:** There are NO `ArrowForwardIcon` or `AddIcon` exports. Use real Lucide icon names: `ArrowRightIcon`, `PlusIcon`, etc.
1006
-
1007
- ### Using Icons
1008
-
1009
- Icons are re-exported from `lucide-react`. Use the `iconSize` map for consistent sizing:
1010
-
1011
- ```tsx
1012
- import { PlusIcon, SettingsIcon, Trash2Icon, iconSize } from "@rebasepro/ui";
1013
-
1014
- // Use iconSize for consistent sizing
1015
- <PlusIcon size={iconSize.small} /> // 20px
1016
- <SettingsIcon size={iconSize.medium} /> // 24px
1017
- <Trash2Icon size={iconSize.large} /> // 28px
1018
- ```
1019
-
1020
- ### `iconSize` Map
1021
-
1022
- | Key | Value (px) |
1023
- |-----|-----------|
1024
- | `smallest` | `16` |
1025
- | `small` | `20` |
1026
- | `medium` | `24` |
1027
- | `large` | `28` |
1028
-
1029
- ### `IconProps` Type
1030
-
1031
- | Prop | Type | Description |
1032
- |------|------|-------------|
1033
- | `size` | `IconSize \| number` | Size in px |
1034
- | `color` | `IconColor` | `"inherit" \| "primary" \| "secondary" \| "disabled" \| "error" \| "success" \| "warning"` |
1035
- | `className` | `string` | Extra classes |
1036
-
1037
- ### `colorClassesMapping`
1038
-
1039
- Maps `IconColor` values to Tailwind classes:
1040
-
1041
- | Color | Class |
1042
- |-------|-------|
1043
- | `"primary"` | `text-primary` |
1044
- | `"secondary"` | `text-secondary` |
1045
- | `"error"` | `text-red-500` |
1046
- | `"success"` | `text-green-500` |
1047
- | `"warning"` | `text-yellow-500` |
1048
- | `"disabled"` | `text-text-disabled dark:text-text-disabled-dark` |
1049
- | `"inherit"` | _(none)_ |
1050
-
1051
- ### `lucideIcons` — Full Icon Map
1052
-
1053
- ```tsx
1054
- import { lucideIcons } from "@rebasepro/ui";
1055
-
1056
- // Dynamic lookup by string name
1057
- const IconComponent = lucideIcons["Database"]; // LucideIcon component
1058
- <IconComponent size={24} />
1059
- ```
1060
-
1061
- ### `icon_keys` and `cool_icon_keys`
1062
-
1063
- - **`icon_keys`** — Array of ~1900+ all available Lucide icon name strings.
1064
- - **`cool_icon_keys`** — Curated subset of ~50 visually distinctive icon names for icon pickers.
1065
-
1066
- ```tsx
1067
- import { icon_keys, coolIconKeys, lucideIcons } from "@rebasepro/ui";
1068
- ```
1069
-
1070
- ### `keyToIconComponent(key: string): string`
1071
-
1072
- Converts a snake_case icon key to a PascalCase component name with `Icon` suffix:
1073
-
1074
- ```tsx
1075
- import { keyToIconComponent } from "@rebasepro/ui";
1076
-
1077
- keyToIconComponent("arrow_right"); // "ArrowRightIcon"
1078
- keyToIconComponent("database"); // "DatabaseIcon"
1079
- ```
1080
-
1081
- ### Custom Icons
1082
-
1083
- - **`GitHubIcon`** — GitHub logo SVG
1084
- - **`HandleIcon`** — Drag handle dots
1085
-
1086
- ```tsx
1087
- import { GitHubIcon, HandleIcon } from "@rebasepro/ui";
1088
- ```
1089
-
1090
- ---
1091
-
1092
- ## Style Mixins
1093
-
1094
- Exported Tailwind class strings for consistent styling. Import and use with `cls()`:
1095
-
1096
- ```tsx
1097
- import {
1098
- focusedClasses,
1099
- focusedDisabled,
1100
- focusedInvisibleMixin,
1101
- fieldBackgroundMixin,
1102
- fieldBackgroundInvisibleMixin,
1103
- fieldBackgroundDisabledMixin,
1104
- fieldBackgroundHoverMixin,
1105
- defaultBorderMixin,
1106
- paperMixin,
1107
- cardMixin,
1108
- cardClickableMixin,
1109
- cardSelectedMixin
1110
- } from "@rebasepro/ui";
1111
- ```
1112
-
1113
- | Mixin | Purpose |
1114
- |-------|---------|
1115
- | `focusedClasses` | Focus ring: `ring-2 ring-primary ring-opacity-75` |
1116
- | `focusedDisabled` | Remove focus ring: `focus-visible:ring-0` |
1117
- | `focusedInvisibleMixin` | Focus bg for invisible fields |
1118
- | `fieldBackgroundMixin` | Default field background (light/dark) |
1119
- | `fieldBackgroundInvisibleMixin` | Transparent field background |
1120
- | `fieldBackgroundDisabledMixin` | Disabled field background |
1121
- | `fieldBackgroundHoverMixin` | Field hover background |
1122
- | `defaultBorderMixin` | Standard border: `border-surface-200/60 dark:border-surface-700/60` |
1123
- | `paperMixin` | Paper container: white bg, rounded-md, border |
1124
- | `cardMixin` | Card container: white/dark bg, rounded-md, border, margin |
1125
- | `cardClickableMixin` | Hover/click effects for interactive cards |
1126
- | `cardSelectedMixin` | Selected card highlight: `bg-primary-bg/30 ring-1 ring-primary/75` |
1127
-
1128
- ```tsx
1129
- import { cls, paperMixin, cardClickableMixin } from "@rebasepro/ui";
1130
-
1131
- <div className={cls(paperMixin, "p-4")}>Paper-styled container</div>
1132
- ```
1133
-
1134
- ---
1135
-
1136
- ## Utility Functions
1137
-
1138
- ### `cls(...classes)`
1139
-
1140
- Combines `clsx` + `twMerge` for conditional class merging with Tailwind conflict resolution.
1141
-
1142
- ```tsx
1143
- import { cls } from "@rebasepro/ui";
1144
-
1145
- <div className={cls(
1146
- "p-4 rounded-lg",
1147
- isActive && "bg-blue-500",
1148
- isDisabled && "opacity-50 cursor-not-allowed"
1149
- )} />
1150
- ```
1151
-
1152
- ### `debounce(func, wait?)`
1153
-
1154
- General-purpose debounce function. Returns a debounced function with a `.clear()` method.
1155
-
1156
- | Param | Type | Default | Description |
1157
- |-------|------|---------|-------------|
1158
- | `func` | `Function` | — | Function to debounce |
1159
- | `wait` | `number` | `166` | Delay in ms |
1160
-
1161
- ```tsx
1162
- import { debounce } from "@rebasepro/ui";
1163
-
1164
- const debouncedSearch = debounce((query: string) => {
1165
- fetchResults(query);
1166
- }, 300);
1167
-
1168
- debouncedSearch("hello");
1169
- debouncedSearch.clear(); // Cancel pending call
1170
- ```
1171
-
1172
- ### `hashString(str)`
1173
-
1174
- Deterministic 32-bit hash of a string. Returns a positive integer.
1175
-
1176
- ```tsx
1177
- import { hashString } from "@rebasepro/ui";
1178
- hashString("my-entity-id"); // e.g. 1234567
1179
- ```
1180
-
1181
- ### Chip Color Utilities
1182
-
1183
- ```tsx
1184
- import {
1185
- CHIP_COLORS, // Record<string, ChipColorScheme>
1186
- getColorSchemeForKey, // (key: ChipColorKey) => ChipColorScheme
1187
- getColorSchemeForSeed // (seed: string) => ChipColorScheme (deterministic)
1188
- } from "@rebasepro/ui";
1189
- ```
1190
-
1191
- **`ChipColorScheme`** type:
1192
- ```ts
1193
- {
1194
- color: string; // Light mode background hex
1195
- text: string; // Light mode text hex
1196
- darkColor?: string; // Dark mode background hex
1197
- darkText?: string; // Dark mode text hex
1198
- }
1199
- ```
1200
-
1201
- **Available CHIP_COLORS keys:** `blue`, `teal`, `yellow`, `pink`, `purple`, `cyan`, `orange`, `green`, `red`, `gray`, `indigo`, `violet`, `fuchsia`, `rose`, `emerald`
1202
-
1203
- ```tsx
1204
- // Deterministic color from any string
1205
- const scheme = getColorSchemeForSeed("user-status-active");
1206
- <Chip colorScheme={scheme}>Active</Chip>
1207
-
1208
- // Or by key
1209
- <Chip colorScheme="blue">Info</Chip>
1210
- ```
1211
-
1212
- ---
1213
-
1214
- ## Hooks
1215
-
1216
- ### `useInjectStyles(key, styles)`
1217
-
1218
- Injects a `<style>` element into the DOM (idempotent). Respects `PortalContainerContext`.
1219
-
1220
- ```tsx
1221
- import { useInjectStyles } from "@rebasepro/ui";
1222
-
1223
- useInjectStyles("MyComponent", `
1224
- .my-animation { animation: fadeIn 200ms ease-out; }
1225
- `);
1226
- ```
1227
-
1228
- ### `useOutsideAlerter(ref, onOutsideClick, active?)`
1229
-
1230
- Calls `onOutsideClick` when a click occurs outside the referenced element. Ignores clicks inside Radix presentation layers.
1231
-
1232
- ```tsx
1233
- import { useOutsideAlerter } from "@rebasepro/ui";
1234
-
1235
- const ref = useRef<HTMLDivElement>(null);
1236
- useOutsideAlerter(ref, () => setOpen(false), isOpen);
1237
- ```
1238
-
1239
- ### `useDebouncedCallback(value, callback, immediate, timeoutMs?)`
1240
-
1241
- Debounces a callback that fires when `value` changes.
1242
-
1243
- | Param | Type | Default | Description |
1244
- |-------|------|---------|-------------|
1245
- | `value` | `T` | — | Watched value |
1246
- | `callback` | `() => void` | — | Callback to debounce |
1247
- | `immediate` | `boolean` | — | If true, flush immediately |
1248
- | `timeoutMs` | `number` | `300` | Debounce delay |
1249
-
1250
- ### `useDebounceCallback(callback?, delay?)`
1251
-
1252
- Returns a debounced version of the given callback function.
1253
-
1254
- | Param | Type | Default | Description |
1255
- |-------|------|---------|-------------|
1256
- | `callback` | `Function` | — | Function to debounce |
1257
- | `delay` | `number` | `200` | Delay in ms |
1258
-
1259
- ### `useDebounceValue(value, delay?)`
1260
-
1261
- Returns a debounced version of a value.
1262
-
1263
- | Param | Type | Default | Description |
1264
- |-------|------|---------|-------------|
1265
- | `value` | `T` | — | Value to debounce |
1266
- | `delay` | `number` | `300` | Delay in ms |
1267
-
1268
- ```tsx
1269
- import { useDebounceValue } from "@rebasepro/ui";
1270
-
1271
- const debouncedSearch = useDebounceValue(searchText, 200);
1272
- useEffect(() => { fetchResults(debouncedSearch); }, [debouncedSearch]);
1273
- ```
1274
-
1275
- ### `PortalContainerProvider` and `usePortalContainer()`
1276
-
1277
- Context provider that controls where Radix portals are rendered. All portal-based components (`Dialog`, `Sheet`, `Select`, `MultiSelect`, `Tooltip`, `Popover`) automatically use this context.
1278
-
1279
- ```tsx
1280
- import { PortalContainerProvider } from "@rebasepro/ui";
1281
-
1282
- const containerRef = useRef<HTMLDivElement>(null);
1283
-
1284
- <div ref={containerRef}>
1285
- <PortalContainerProvider container={containerRef.current}>
1286
- {/* All portals render inside this div */}
1287
- <Select ... />
1288
- <Dialog ... />
1289
- </PortalContainerProvider>
1290
- </div>
1291
- ```
1292
-
1293
- ---
1294
-
1295
- ## Complete Custom View Example
1296
-
1297
- ```tsx
1298
- import {
1299
- Container,
1300
- Typography,
1301
- Card,
1302
- Button,
1303
- TextField,
1304
- Tabs,
1305
- Tab,
1306
- Alert,
1307
- Chip,
1308
- SearchBar,
1309
- Table,
1310
- TableHeader,
1311
- TableBody,
1312
- TableRow,
1313
- TableCell,
1314
- Dialog,
1315
- DialogTitle,
1316
- DialogContent,
1317
- DialogActions,
1318
- cls,
1319
- iconSize
1320
- } from "@rebasepro/ui";
1321
- import { PlusIcon, PencilIcon } from "@rebasepro/ui";
1322
- import { useState } from "react";
1323
-
1324
- export function DashboardView() {
1325
- const [tab, setTab] = useState("all");
1326
- const [dialogOpen, setDialogOpen] = useState(false);
1327
-
1328
- return (
1329
- <Container maxWidth="5xl">
1330
- <div className="flex justify-between items-center mb-6">
1331
- <Typography variant="h4">Dashboard</Typography>
1332
- <Button
1333
- variant="filled"
1334
- color="primary"
1335
- startIcon={<PlusIcon size={iconSize.small} />}
1336
- onClick={() => setDialogOpen(true)}
1337
- >
1338
- New Item
1339
- </Button>
1340
- </div>
1341
-
1342
- <Alert color="info" size="small" className="mb-4">
1343
- Welcome back! You have 3 items needing review.
1344
- </Alert>
1345
-
1346
- <div className="flex gap-4 mb-4">
1347
- <Tabs value={tab} onValueChange={setTab} variant="standard">
1348
- <Tab value="all">All</Tab>
1349
- <Tab value="active">Active</Tab>
1350
- <Tab value="archived">Archived</Tab>
1351
- </Tabs>
1352
- <SearchBar
1353
- onTextSearch={(term) => console.log(term)}
1354
- size="small"
1355
- />
1356
- </div>
1357
-
1358
- <Card className="p-0 overflow-hidden">
1359
- <Table>
1360
- <TableHeader>
1361
- <TableCell header>Name</TableCell>
1362
- <TableCell header>Status</TableCell>
1363
- <TableCell header align="right">Actions</TableCell>
1364
- </TableHeader>
1365
- <TableBody>
1366
- <TableRow>
1367
- <TableCell>Example Item</TableCell>
1368
- <TableCell>
1369
- <Chip colorScheme="green" size="small">Active</Chip>
1370
- </TableCell>
1371
- <TableCell align="right">
1372
- <IconButton aria-label="Edit" size="small">
1373
- <PencilIcon size={iconSize.smallest} />
1374
- </IconButton>
1375
- </TableCell>
1376
- </TableRow>
1377
- </TableBody>
1378
- </Table>
1379
- </Card>
1380
-
1381
- <Dialog open={dialogOpen} onOpenChange={setDialogOpen} maxWidth="md">
1382
- <DialogTitle>Create New Item</DialogTitle>
1383
- <DialogContent>
1384
- <TextField label="Name" size="large" />
1385
- </DialogContent>
1386
- <DialogActions>
1387
- <Button variant="text" onClick={() => setDialogOpen(false)}>
1388
- Cancel
1389
- </Button>
1390
- <Button variant="filled" color="primary">
1391
- Create
1392
- </Button>
1393
- </DialogActions>
1394
- </Dialog>
1395
- </Container>
1396
- );
1397
- }
1398
- ```
1399
-
1400
- ## Rich Text Editor (`RichTextEditor`)
1401
-
1402
- > **IMPORTANT:** `RichTextEditor` lives in `@rebasepro/admin`, NOT in `@rebasepro/ui`. It is a separate heavy entry point (~300 KB) because it bundles ProseMirror.
1403
-
1404
- A full-featured, block-based WYSIWYG editor with slash commands, bubble menus, image uploads, tables, AI autocomplete, drag-and-drop reordering, and a raw Markdown toggle. Outputs **Markdown**, **JSON** (ProseMirror document tree), and **HTML**.
1405
-
1406
- ### Import
1407
-
1408
- ```ts
1409
- // The component (heavy — code-split / lazy-load when possible)
1410
- import { RichTextEditor } from "@rebasepro/admin/editor";
1411
-
1412
- // Types only (lightweight — from the main entry point)
1413
- import type { RichTextEditorProps, JSONContent, EditorAIController } from "@rebasepro/admin";
1414
- ```
1415
-
1416
- > **Note:** The previous export name `RebaseEditor` still works but is deprecated. Always use `RichTextEditor`.
1417
-
1418
- ### Props
1419
-
1420
- | Prop | Type | Default | Description |
1421
- |------|------|---------|-------------|
1422
- | `content` | `JSONContent \| string` | — | Initial content. Pass a markdown string or a ProseMirror JSON document. |
1423
- | `onMarkdownContentChange` | `(md: string) => void` | — | Called with serialized Markdown on edits |
1424
- | `onJsonContentChange` | `(json: JSONContent \| null) => void` | — | Called with ProseMirror JSON on edits |
1425
- | `onHtmlContentChange` | `(html: string) => void` | — | Called with HTML string on edits |
1426
- | `handleImageUpload` | `(file: File) => Promise<string>` | **required** | Upload handler that returns the image URL |
1427
- | `version` | `number` | — | Bump to force-reset editor content (e.g. on form discard) |
1428
- | `textSize` | `"sm" \| "base" \| "lg"` | `"base"` | Prose typography scale |
1429
- | `highlight` | `{ from: number, to: number }` | — | Highlight a character range (used by AI autocomplete) |
1430
- | `aiController` | `EditorAIController` | — | AI autocomplete controller |
1431
- | `disabled` | `boolean` | `false` | Read-only mode |
1432
- | `markdownConfig` | `MarkdownEditorConfig` | — | Markdown parser options (`html`, `transformPastedText`) |
1433
-
1434
- ### Usage Example
1435
-
1436
- ```tsx
1437
- import { RichTextEditor } from "@rebasepro/admin/editor";
1438
-
1439
- function MyEditor() {
1440
- const [markdown, setMarkdown] = useState("");
1441
-
1442
- return (
1443
- <RichTextEditor
1444
- content={markdown}
1445
- onMarkdownContentChange={setMarkdown}
1446
- handleImageUpload={async (file) => {
1447
- const url = await uploadToStorage(file);
1448
- return url;
1449
- }}
1450
- textSize="base"
1451
- />
1452
- );
1453
- }
1454
- ```
1455
-
1456
- ### Lazy Loading
1457
-
1458
- Because the editor is ~300 KB, lazy-load it when it's not immediately visible:
1459
-
1460
- ```tsx
1461
- import { lazy, Suspense } from "react";
1462
- import { Skeleton } from "@rebasepro/ui";
1463
-
1464
- const RichTextEditor = lazy(() =>
1465
- import("@rebasepro/admin/editor").then(m => ({ default: m.RichTextEditor }))
1466
- );
1467
-
1468
- function LazyEditor(props) {
1469
- return (
1470
- <Suspense fallback={<Skeleton height={200} className="w-full rounded-md" />}>
1471
- <RichTextEditor {...props} />
1472
- </Suspense>
1473
- );
1474
- }
1475
- ```
1476
-
1477
- ## Tailwind CSS v4
1478
-
1479
- Rebase uses Tailwind CSS v4 with CSS-first configuration:
1480
- - No `tailwind.config.js` — configuration is in CSS
1481
- - CSS variables for theming
1482
- - Native cascade layers
1483
-
1484
- ## References
1485
-
1486
- - **Documentation:** [rebase.pro/docs](https://rebase.pro/docs)
1487
- - **GitHub:** [github.com/rebasepro/rebase](https://github.com/rebasepro/rebase)
1488
- - **UI Source:** `packages/ui/src/` in the monorepo