@skunkworksai/ui-kit 0.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +250 -0
- package/README.md +429 -0
- package/dist/assets/Service-applets-apps/audience-measurement.png +0 -0
- package/dist/assets/Service-applets-apps/coatro-app.png +0 -0
- package/dist/assets/Service-applets-apps/content-effectiveness.png +0 -0
- package/dist/assets/Service-applets-apps/hop-tracking.png +0 -0
- package/dist/assets/Service-applets-apps/index.ts +13 -0
- package/dist/assets/Service-applets-apps/journeys-app.png +0 -0
- package/dist/assets/Service-applets-apps/people-counting.png +0 -0
- package/dist/assets/Service-applets-apps/petra.png +0 -0
- package/dist/assets/Service-applets-apps/sam-generic.png +0 -0
- package/dist/assets/Service-applets-apps/sami-for-environment.png +0 -0
- package/dist/assets/Service-applets-apps/shelf-engagement.png +0 -0
- package/dist/assets/Service-applets-apps/traffic-management.png +0 -0
- package/dist/assets/Service-applets-apps/viana.png +0 -0
- package/dist/assets/Service-applets-apps/zone-engagement.png +0 -0
- package/dist/assets/icons/Dashboard-active.svg +29 -0
- package/dist/assets/icons/Dashboard.svg +25 -0
- package/dist/assets/icons/DashboardActiveIcon.tsx +35 -0
- package/dist/assets/icons/DashboardIcon.tsx +31 -0
- package/dist/assets/icons/Devices-active.svg +27 -0
- package/dist/assets/icons/Devices.svg +20 -0
- package/dist/assets/icons/DevicesActiveIcon.tsx +33 -0
- package/dist/assets/icons/DevicesIcon.tsx +26 -0
- package/dist/assets/icons/Installer-active.svg +29 -0
- package/dist/assets/icons/Installer.svg +17 -0
- package/dist/assets/icons/InstallerActiveIcon.tsx +35 -0
- package/dist/assets/icons/InstallerIcon.tsx +23 -0
- package/dist/assets/icons/Manifest-active.svg +49 -0
- package/dist/assets/icons/Manifest.svg +49 -0
- package/dist/assets/icons/ManifestActiveIcon.tsx +55 -0
- package/dist/assets/icons/ManifestIcon.tsx +55 -0
- package/dist/assets/icons/Sensor-active.svg +15 -0
- package/dist/assets/icons/Sensor.svg +11 -0
- package/dist/assets/icons/SensorActiveIcon.tsx +21 -0
- package/dist/assets/icons/SensorIcon.tsx +17 -0
- package/dist/assets/icons/Site-active.svg +14 -0
- package/dist/assets/icons/Site.svg +10 -0
- package/dist/assets/icons/SiteActiveIcon.tsx +20 -0
- package/dist/assets/icons/SiteIcon.tsx +16 -0
- package/dist/assets/icons/X-ray-active.svg +199 -0
- package/dist/assets/icons/X-ray.svg +47 -0
- package/dist/assets/icons/XrayActiveIcon.tsx +205 -0
- package/dist/assets/icons/XrayIcon.tsx +53 -0
- package/dist/assets/icons/index.ts +14 -0
- package/dist/assets/logos/DarkLogo.tsx +28 -0
- package/dist/assets/logos/DarkSymbol.tsx +9 -0
- package/dist/assets/logos/PrimaryLogo.tsx +28 -0
- package/dist/assets/logos/PrimarySymbol.tsx +9 -0
- package/dist/assets/logos/WhiteLogo.tsx +28 -0
- package/dist/assets/logos/WhiteSymbol.tsx +9 -0
- package/dist/assets/logos/dark_logo.svg +22 -0
- package/dist/assets/logos/dark_symbol.svg +3 -0
- package/dist/assets/logos/index.ts +6 -0
- package/dist/assets/logos/primary-logo.svg +22 -0
- package/dist/assets/logos/primary_logo.svg +22 -0
- package/dist/assets/logos/primary_symbol.svg +3 -0
- package/dist/assets/logos/white_symbol.svg +3 -0
- package/dist/index.cjs +160 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +45276 -0
- package/dist/index.js.map +1 -0
- package/dist/tokens-source.css +121 -0
- package/dist/types/assets/Service-applets-apps/index.d.ts +13 -0
- package/dist/types/assets/icons/DashboardActiveIcon.d.ts +2 -0
- package/dist/types/assets/icons/DashboardIcon.d.ts +2 -0
- package/dist/types/assets/icons/DevicesActiveIcon.d.ts +2 -0
- package/dist/types/assets/icons/DevicesIcon.d.ts +2 -0
- package/dist/types/assets/icons/InstallerActiveIcon.d.ts +2 -0
- package/dist/types/assets/icons/InstallerIcon.d.ts +2 -0
- package/dist/types/assets/icons/ManifestActiveIcon.d.ts +2 -0
- package/dist/types/assets/icons/ManifestIcon.d.ts +2 -0
- package/dist/types/assets/icons/SensorActiveIcon.d.ts +2 -0
- package/dist/types/assets/icons/SensorIcon.d.ts +2 -0
- package/dist/types/assets/icons/SiteActiveIcon.d.ts +2 -0
- package/dist/types/assets/icons/SiteIcon.d.ts +2 -0
- package/dist/types/assets/icons/XrayActiveIcon.d.ts +2 -0
- package/dist/types/assets/icons/XrayIcon.d.ts +2 -0
- package/dist/types/assets/icons/index.d.ts +14 -0
- package/dist/types/assets/logos/DarkLogo.d.ts +2 -0
- package/dist/types/assets/logos/DarkSymbol.d.ts +2 -0
- package/dist/types/assets/logos/PrimaryLogo.d.ts +2 -0
- package/dist/types/assets/logos/PrimarySymbol.d.ts +2 -0
- package/dist/types/assets/logos/WhiteLogo.d.ts +2 -0
- package/dist/types/assets/logos/WhiteSymbol.d.ts +2 -0
- package/dist/types/assets/logos/index.d.ts +6 -0
- package/dist/types/components/blocks/AppBentoMenu.d.ts +31 -0
- package/dist/types/components/blocks/AppDashboard.d.ts +121 -0
- package/dist/types/components/blocks/AppHeader.d.ts +198 -0
- package/dist/types/components/blocks/AppLocationTreeFilter.d.ts +44 -0
- package/dist/types/components/blocks/AppNotificationsMenu.d.ts +50 -0
- package/dist/types/components/blocks/AppPageTitle.d.ts +86 -0
- package/dist/types/components/blocks/AppProfile.d.ts +53 -0
- package/dist/types/components/blocks/TableManager.d.ts +194 -0
- package/dist/types/components/blocks/backgrounds/AppDashboardBackgroundDots.d.ts +14 -0
- package/dist/types/components/blocks/backgrounds/AppDashboardBackgroundWave.d.ts +14 -0
- package/dist/types/components/blocks/backgrounds/index.d.ts +3 -0
- package/dist/types/components/blocks/backgrounds/types.d.ts +13 -0
- package/dist/types/components/blocks/index.d.ts +9 -0
- package/dist/types/components/primitives/AppAccordion.d.ts +22 -0
- package/dist/types/components/primitives/AppAlert.d.ts +33 -0
- package/dist/types/components/primitives/AppAlertDialog.d.ts +79 -0
- package/dist/types/components/primitives/AppAspectRatio.d.ts +7 -0
- package/dist/types/components/primitives/AppAvatar.d.ts +17 -0
- package/dist/types/components/primitives/AppBadge.d.ts +9 -0
- package/dist/types/components/primitives/AppBreadcrumb.d.ts +45 -0
- package/dist/types/components/primitives/AppButton.d.ts +24 -0
- package/dist/types/components/primitives/AppButtonGroup.d.ts +10 -0
- package/dist/types/components/primitives/AppCalendar.d.ts +51 -0
- package/dist/types/components/primitives/AppCard.d.ts +41 -0
- package/dist/types/components/primitives/AppCarousel.d.ts +26 -0
- package/dist/types/components/primitives/AppChart.d.ts +27 -0
- package/dist/types/components/primitives/AppCheckbox.d.ts +9 -0
- package/dist/types/components/primitives/AppCollapsible.d.ts +20 -0
- package/dist/types/components/primitives/AppCombobox.d.ts +37 -0
- package/dist/types/components/primitives/AppCommand.d.ts +47 -0
- package/dist/types/components/primitives/AppContextMenu.d.ts +82 -0
- package/dist/types/components/primitives/AppDataTable.d.ts +23 -0
- package/dist/types/components/primitives/AppDatePicker.d.ts +26 -0
- package/dist/types/components/primitives/AppDialog.d.ts +40 -0
- package/dist/types/components/primitives/AppDrawer.d.ts +58 -0
- package/dist/types/components/primitives/AppDropdownMenu.d.ts +85 -0
- package/dist/types/components/primitives/AppEmpty.d.ts +35 -0
- package/dist/types/components/primitives/AppField.d.ts +65 -0
- package/dist/types/components/primitives/AppForm.d.ts +58 -0
- package/dist/types/components/primitives/AppHoverCard.d.ts +19 -0
- package/dist/types/components/primitives/AppInput.d.ts +21 -0
- package/dist/types/components/primitives/AppKbd.d.ts +18 -0
- package/dist/types/components/primitives/AppLabel.d.ts +8 -0
- package/dist/types/components/primitives/AppMenubar.d.ts +83 -0
- package/dist/types/components/primitives/AppNavigationMenu.d.ts +51 -0
- package/dist/types/components/primitives/AppPagination.d.ts +46 -0
- package/dist/types/components/primitives/AppPopover.d.ts +20 -0
- package/dist/types/components/primitives/AppProgress.d.ts +9 -0
- package/dist/types/components/primitives/AppRadioGroup.d.ts +15 -0
- package/dist/types/components/primitives/AppScrollArea.d.ts +12 -0
- package/dist/types/components/primitives/AppScrollText.d.ts +7 -0
- package/dist/types/components/primitives/AppSelect.d.ts +46 -0
- package/dist/types/components/primitives/AppSeparator.d.ts +8 -0
- package/dist/types/components/primitives/AppSheet.d.ts +32 -0
- package/dist/types/components/primitives/AppSidebar.d.ts +59 -0
- package/dist/types/components/primitives/AppSkeleton.d.ts +6 -0
- package/dist/types/components/primitives/AppSpinner.d.ts +13 -0
- package/dist/types/components/primitives/AppSwitch.d.ts +8 -0
- package/dist/types/components/primitives/AppTable.d.ts +53 -0
- package/dist/types/components/primitives/AppTabs.d.ts +10 -0
- package/dist/types/components/primitives/AppTextarea.d.ts +9 -0
- package/dist/types/components/primitives/AppThemeProvider.d.ts +46 -0
- package/dist/types/components/primitives/AppToaster.d.ts +7 -0
- package/dist/types/components/primitives/AppToggle.d.ts +9 -0
- package/dist/types/components/primitives/AppToggleGroup.d.ts +18 -0
- package/dist/types/components/primitives/AppTooltip.d.ts +26 -0
- package/dist/types/components/primitives/AppTypography.d.ts +80 -0
- package/dist/types/components/primitives/index.d.ts +57 -0
- package/dist/types/components/ui/accordion.d.ts +7 -0
- package/dist/types/components/ui/alert-dialog.d.ts +20 -0
- package/dist/types/components/ui/alert.d.ts +8 -0
- package/dist/types/components/ui/aspect-ratio.d.ts +4 -0
- package/dist/types/components/ui/avatar.d.ts +6 -0
- package/dist/types/components/ui/badge.d.ts +9 -0
- package/dist/types/components/ui/breadcrumb.d.ts +19 -0
- package/dist/types/components/ui/button.d.ts +13 -0
- package/dist/types/components/ui/calendar.d.ts +8 -0
- package/dist/types/components/ui/card.d.ts +11 -0
- package/dist/types/components/ui/carousel.d.ts +28 -0
- package/dist/types/components/ui/chart.d.ts +48 -0
- package/dist/types/components/ui/checkbox.d.ts +4 -0
- package/dist/types/components/ui/collapsible.d.ts +6 -0
- package/dist/types/components/ui/combobox.d.ts +83 -0
- package/dist/types/components/ui/command.d.ts +82 -0
- package/dist/types/components/ui/context-menu.d.ts +27 -0
- package/dist/types/components/ui/dialog.d.ts +19 -0
- package/dist/types/components/ui/drawer.d.ts +23 -0
- package/dist/types/components/ui/dropdown-menu.d.ts +27 -0
- package/dist/types/components/ui/empty.d.ts +14 -0
- package/dist/types/components/ui/field.d.ts +40 -0
- package/dist/types/components/ui/form.d.ts +22 -0
- package/dist/types/components/ui/hover-card.d.ts +6 -0
- package/dist/types/components/ui/input.d.ts +3 -0
- package/dist/types/components/ui/kbd.d.ts +4 -0
- package/dist/types/components/ui/label.d.ts +4 -0
- package/dist/types/components/ui/menubar.d.ts +30 -0
- package/dist/types/components/ui/navigation-menu.d.ts +12 -0
- package/dist/types/components/ui/pagination.d.ts +28 -0
- package/dist/types/components/ui/popover.d.ts +6 -0
- package/dist/types/components/ui/progress.d.ts +4 -0
- package/dist/types/components/ui/radio-group.d.ts +5 -0
- package/dist/types/components/ui/scroll-area.d.ts +5 -0
- package/dist/types/components/ui/scroll-text.d.ts +6 -0
- package/dist/types/components/ui/select.d.ts +13 -0
- package/dist/types/components/ui/separator.d.ts +4 -0
- package/dist/types/components/ui/sheet.d.ts +25 -0
- package/dist/types/components/ui/sidebar.d.ts +69 -0
- package/dist/types/components/ui/skeleton.d.ts +2 -0
- package/dist/types/components/ui/sonner.d.ts +2 -0
- package/dist/types/components/ui/switch.d.ts +4 -0
- package/dist/types/components/ui/table.d.ts +10 -0
- package/dist/types/components/ui/tabs.d.ts +19 -0
- package/dist/types/components/ui/textarea.d.ts +5 -0
- package/dist/types/components/ui/toggle-group.d.ts +15 -0
- package/dist/types/components/ui/toggle.d.ts +12 -0
- package/dist/types/components/ui/tooltip.d.ts +7 -0
- package/dist/types/hooks/use-mobile.d.ts +13 -0
- package/dist/types/hooks/use-page-title.d.ts +23 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/lib/utils.d.ts +2 -0
- package/dist/ui-kit.css +1 -0
- package/package.json +117 -0
- package/rules/accordion.md +60 -0
- package/rules/alert-dialog.md +62 -0
- package/rules/alert.md +61 -0
- package/rules/aspect-ratio.md +47 -0
- package/rules/avatar.md +52 -0
- package/rules/badge.md +55 -0
- package/rules/bento-menu.md +86 -0
- package/rules/breadcrumb.md +80 -0
- package/rules/button-group.md +58 -0
- package/rules/button.md +66 -0
- package/rules/calendar.md +97 -0
- package/rules/card.md +84 -0
- package/rules/carousel.md +113 -0
- package/rules/chart.md +125 -0
- package/rules/checkbox.md +49 -0
- package/rules/collapsible.md +57 -0
- package/rules/combobox.md +133 -0
- package/rules/command.md +73 -0
- package/rules/context-menu.md +65 -0
- package/rules/dashboard.md +368 -0
- package/rules/data-table.md +91 -0
- package/rules/date-picker.md +65 -0
- package/rules/dialog.md +60 -0
- package/rules/drawer.md +65 -0
- package/rules/dropdown-menu.md +72 -0
- package/rules/empty.md +110 -0
- package/rules/field.md +149 -0
- package/rules/form.md +60 -0
- package/rules/header.md +245 -0
- package/rules/hover-card.md +53 -0
- package/rules/icons.md +141 -0
- package/rules/input.md +66 -0
- package/rules/kbd.md +58 -0
- package/rules/label.md +30 -0
- package/rules/location-tree-filter.md +165 -0
- package/rules/logo.md +58 -0
- package/rules/menubar.md +75 -0
- package/rules/navigation-menu.md +68 -0
- package/rules/notifications-menu.md +137 -0
- package/rules/pagetitle.md +160 -0
- package/rules/pagination.md +71 -0
- package/rules/popover.md +48 -0
- package/rules/profile.md +125 -0
- package/rules/progress.md +41 -0
- package/rules/radio-group.md +44 -0
- package/rules/scroll-area.md +32 -0
- package/rules/scroll-text.md +40 -0
- package/rules/select.md +86 -0
- package/rules/separator.md +43 -0
- package/rules/sheet.md +76 -0
- package/rules/sidebar.md +442 -0
- package/rules/skeleton.md +46 -0
- package/rules/spinner.md +43 -0
- package/rules/switch.md +46 -0
- package/rules/table-manager.md +306 -0
- package/rules/table.md +177 -0
- package/rules/tabs.md +82 -0
- package/rules/text.md +3 -0
- package/rules/textarea.md +38 -0
- package/rules/toaster.md +58 -0
- package/rules/toggle-group.md +50 -0
- package/rules/toggle.md +40 -0
- package/rules/tokens.md +88 -0
- package/rules/tooltip.md +78 -0
- package/rules/typography.md +81 -0
- package/scripts/scaffold.mjs +28 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# TableManager
|
|
2
|
+
|
|
3
|
+
> Docs: https://ui-kit.vercel.app/docs/blocks/table-manager
|
|
4
|
+
|
|
5
|
+
**This is a block — import from `blocks/TableManager`, not `primitives/`.**
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import {
|
|
9
|
+
TableManager,
|
|
10
|
+
TableManagerToolbar,
|
|
11
|
+
TableManagerSearch,
|
|
12
|
+
TableManagerToolbarActions,
|
|
13
|
+
TableManagerMultiFilter,
|
|
14
|
+
TableManagerDateRange,
|
|
15
|
+
TableManagerRowsPerPage,
|
|
16
|
+
TableManagerPagination,
|
|
17
|
+
TableManagerColumnToggle,
|
|
18
|
+
TableManagerExport,
|
|
19
|
+
TableManagerContent,
|
|
20
|
+
TableManagerFooter,
|
|
21
|
+
type TableManagerColumnDef,
|
|
22
|
+
type TableManagerFilterOption,
|
|
23
|
+
type TableManagerExportOption,
|
|
24
|
+
} from "@/components/blocks/TableManager"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Hard stop
|
|
28
|
+
|
|
29
|
+
> ❌ **Never build a data table + toolbar manually using `AppTable`, `AppPagination`, and raw inputs.**
|
|
30
|
+
>
|
|
31
|
+
> `TableManager` handles sort state, column visibility, drag-to-reorder columns, row selection, loading overlay, search debounce, multiselect filters, date range, and pagination UI. Building this from scratch will produce inconsistent behaviour and visual drift. Use this block.
|
|
32
|
+
|
|
33
|
+
## Data model
|
|
34
|
+
|
|
35
|
+
TableManager uses a **hybrid data model**:
|
|
36
|
+
|
|
37
|
+
| Concern | Where it lives |
|
|
38
|
+
|---------|---------------|
|
|
39
|
+
| Filtering (search, multiselect, date range) | **Server-side** — block fires callbacks; consumer fetches and passes filtered data |
|
|
40
|
+
| Sorting | **Client-side** — block sorts the `data` prop internally |
|
|
41
|
+
| Pagination | **Server-side** — consumer passes `totalCount`; block renders pagination UI |
|
|
42
|
+
| Column visibility / order | **Client-side** — block owns this state internally |
|
|
43
|
+
| Row selection | **Client-side** — block owns this state; fires `onSelectionChange` |
|
|
44
|
+
|
|
45
|
+
All row objects must have `id: string | number`.
|
|
46
|
+
|
|
47
|
+
## Types
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
type TableManagerColumnDef<T> = {
|
|
51
|
+
id: string // Unique column identifier
|
|
52
|
+
header: string // Column header label
|
|
53
|
+
type?: "date" | "text" | "other" // Drives default sort order
|
|
54
|
+
accessorKey?: keyof T // Key for reading cell values
|
|
55
|
+
cell?: (row: T) => React.ReactNode // Custom cell renderer
|
|
56
|
+
enableSorting?: boolean // Click label to sort (default: false)
|
|
57
|
+
enableFiltering?: boolean // Show filter icon on header (default: false)
|
|
58
|
+
filterPopover?: () => React.ReactNode // Body of the column's filter popover
|
|
59
|
+
defaultVisible?: boolean // Initially visible (default: true)
|
|
60
|
+
headerClassName?: string // Extra class on the rendered <TableHead>
|
|
61
|
+
headerAlign?: "left" | "right" | "center" // Header content alignment
|
|
62
|
+
cellAlign?: "left" | "right" | "center" // Body cell text alignment
|
|
63
|
+
headerCell?: () => React.ReactNode // Full custom header renderer (overrides text/sort/filter content)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
type TableManagerFilterOption = {
|
|
67
|
+
value: string
|
|
68
|
+
label: string
|
|
69
|
+
icon?: React.ReactNode
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
type TableManagerExportOption = {
|
|
73
|
+
label: string
|
|
74
|
+
value: string
|
|
75
|
+
icon?: React.ReactNode
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Props — TableManager
|
|
80
|
+
|
|
81
|
+
| Prop | Type | Default | Description |
|
|
82
|
+
|------|------|---------|-------------|
|
|
83
|
+
| `columns` | `TableManagerColumnDef<T>[]` | required | Column definitions. Drive headers, cell renderers, sort, and filter. |
|
|
84
|
+
| `data` | `T[]` | required | Server-filtered rows for the current page. Must have `id: string \| number`. |
|
|
85
|
+
| `totalCount` | `number` | required | Total records across all pages (for pagination math). |
|
|
86
|
+
| `loading` | `boolean` | `false` | Shows a loading overlay on the table content while data is fetching. Toolbar and footer remain interactive. |
|
|
87
|
+
| `defaultRowsPerPage` | `number` | `20` | Initial rows-per-page value. |
|
|
88
|
+
| `defaultVisibleColumns` | `string[]` | all | Column IDs to show on initial render. |
|
|
89
|
+
| `defaultFilters` | `Record<string, string[]>` | `{}` | Initial filter selections. Use to pre-check multiselect filters. |
|
|
90
|
+
| `onSearchChange` | `(term: string) => void` | — | Fired when search input changes (debounced 300 ms). |
|
|
91
|
+
| `onFilterChange` | `(filters: Record<string, string[]>) => void` | — | Fired when any multiselect filter changes. |
|
|
92
|
+
| `onDateRangeChange` | `(range: { from?: Date; to?: Date }) => void` | — | Fired when the date range changes. |
|
|
93
|
+
| `onPageChange` | `(page: number) => void` | — | Fired when the page changes (0-indexed). |
|
|
94
|
+
| `onRowsPerPageChange` | `(rowsPerPage: number) => void` | — | Fired when rows per page changes. |
|
|
95
|
+
| `onSelectionChange` | `(rows: T[]) => void` | — | Fired when row selection changes. |
|
|
96
|
+
|
|
97
|
+
## Default sort order
|
|
98
|
+
|
|
99
|
+
When no column header has been clicked, data is sorted by:
|
|
100
|
+
|
|
101
|
+
1. First column with `type: "date"` — **descending** (most recent first)
|
|
102
|
+
2. If no date column, first column with `type: "text"` — **ascending**
|
|
103
|
+
3. If neither, natural order
|
|
104
|
+
|
|
105
|
+
Clicking a sortable column header cycles: **desc → asc → default**.
|
|
106
|
+
|
|
107
|
+
## Column header interactions
|
|
108
|
+
|
|
109
|
+
Each column header supports two independent click targets:
|
|
110
|
+
|
|
111
|
+
- **Label click** — sorts the column client-side (if `enableSorting: true`)
|
|
112
|
+
- **Filter icon click** — opens a popover anchored to the header (if `enableFiltering: true` and `filterPopover` is provided)
|
|
113
|
+
|
|
114
|
+
A column may have both `enableSorting` and `enableFiltering` set simultaneously.
|
|
115
|
+
|
|
116
|
+
## Usage
|
|
117
|
+
|
|
118
|
+
### Minimal
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
const columns: TableManagerColumnDef<Row>[] = [
|
|
122
|
+
{ id: "name", header: "Name", type: "text", accessorKey: "name", enableSorting: true },
|
|
123
|
+
{ id: "status", header: "Status", accessorKey: "status" },
|
|
124
|
+
{ id: "date", header: "Date", type: "date", accessorKey: "date", enableSorting: true },
|
|
125
|
+
]
|
|
126
|
+
|
|
127
|
+
export default function Page() {
|
|
128
|
+
const [data, setData] = React.useState<Row[]>(rows)
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<TableManager
|
|
132
|
+
columns={columns}
|
|
133
|
+
data={data}
|
|
134
|
+
totalCount={data.length}
|
|
135
|
+
onSearchChange={(term) => setData(rows.filter(r => r.name.includes(term)))}
|
|
136
|
+
>
|
|
137
|
+
<TableManagerToolbar>
|
|
138
|
+
<TableManagerSearch placeholder="Search..." />
|
|
139
|
+
<TableManagerToolbarActions>
|
|
140
|
+
<TableManagerPagination />
|
|
141
|
+
</TableManagerToolbarActions>
|
|
142
|
+
</TableManagerToolbar>
|
|
143
|
+
<TableManagerContent />
|
|
144
|
+
<TableManagerFooter />
|
|
145
|
+
</TableManager>
|
|
146
|
+
)
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Full toolbar
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
<TableManager
|
|
154
|
+
columns={columns}
|
|
155
|
+
data={data}
|
|
156
|
+
totalCount={totalCount}
|
|
157
|
+
loading={loading}
|
|
158
|
+
defaultFilters={{ applet: ["sami", "zone"] }}
|
|
159
|
+
onSearchChange={handleSearch}
|
|
160
|
+
onFilterChange={handleFilter}
|
|
161
|
+
onDateRangeChange={handleDateRange}
|
|
162
|
+
onPageChange={handlePage}
|
|
163
|
+
onRowsPerPageChange={handleRowsPerPage}
|
|
164
|
+
onSelectionChange={handleSelection}
|
|
165
|
+
>
|
|
166
|
+
<TableManagerToolbar>
|
|
167
|
+
<TableManagerSearch placeholder="Search sessions..." />
|
|
168
|
+
<TableManagerToolbarActions>
|
|
169
|
+
<TableManagerMultiFilter
|
|
170
|
+
name="applet"
|
|
171
|
+
label="Service Applet"
|
|
172
|
+
icon={<img src={icon.src} alt="" className="size-5 rounded object-cover" />}
|
|
173
|
+
options={appletOptions}
|
|
174
|
+
searchPlaceholder="Search Service Applet"
|
|
175
|
+
/>
|
|
176
|
+
<TableManagerDateRange />
|
|
177
|
+
<TableManagerRowsPerPage />
|
|
178
|
+
<TableManagerPagination />
|
|
179
|
+
<TableManagerColumnToggle />
|
|
180
|
+
<TableManagerExport
|
|
181
|
+
options={[{ label: "CSV", value: "csv" }]}
|
|
182
|
+
onExport={(fmt) => exportAs(fmt)}
|
|
183
|
+
/>
|
|
184
|
+
</TableManagerToolbarActions>
|
|
185
|
+
</TableManagerToolbar>
|
|
186
|
+
<TableManagerContent />
|
|
187
|
+
<TableManagerFooter />
|
|
188
|
+
</TableManager>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Pre-checked multiselect filter
|
|
192
|
+
|
|
193
|
+
Use `defaultFilters` to pre-select all options. The consumer's `onFilterChange` should use OR logic: a row is visible if any of its values match any checked option.
|
|
194
|
+
|
|
195
|
+
```tsx
|
|
196
|
+
<TableManager
|
|
197
|
+
defaultFilters={{ applet: ["sami", "zone", "shelf"] }}
|
|
198
|
+
onFilterChange={(filters) => {
|
|
199
|
+
const checked = filters["applet"] ?? []
|
|
200
|
+
const filtered = checked.length === 0
|
|
201
|
+
? []
|
|
202
|
+
: rows.filter(r => r.applets.some(a => checked.includes(a)))
|
|
203
|
+
setData(filtered)
|
|
204
|
+
}}
|
|
205
|
+
...
|
|
206
|
+
>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Right-aligned actions column
|
|
210
|
+
|
|
211
|
+
Use `headerAlign` and `cellAlign` to mirror header alignment with cell alignment. Both accept `"left" | "right" | "center"`.
|
|
212
|
+
|
|
213
|
+
```tsx
|
|
214
|
+
{
|
|
215
|
+
id: "actions",
|
|
216
|
+
header: "Actions",
|
|
217
|
+
headerAlign: "right",
|
|
218
|
+
cellAlign: "right",
|
|
219
|
+
cell: (row) => (
|
|
220
|
+
<AppButton size="sm" variant="ghost" onClick={() => edit(row)}>Edit</AppButton>
|
|
221
|
+
),
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
When `headerCell` is provided it fully replaces the header content (text + sort icon + filter icon). `headerClassName` still applies.
|
|
226
|
+
|
|
227
|
+
```tsx
|
|
228
|
+
{
|
|
229
|
+
id: "actions",
|
|
230
|
+
header: "Actions",
|
|
231
|
+
headerCell: () => (
|
|
232
|
+
<div className="flex justify-end">
|
|
233
|
+
<span className="text-xs text-muted-foreground">Actions</span>
|
|
234
|
+
</div>
|
|
235
|
+
),
|
|
236
|
+
cellAlign: "right",
|
|
237
|
+
cell: (row) => <AppButton size="sm">Edit</AppButton>,
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Custom cell renderer
|
|
242
|
+
|
|
243
|
+
```tsx
|
|
244
|
+
{
|
|
245
|
+
id: "status",
|
|
246
|
+
header: "Status",
|
|
247
|
+
accessorKey: "status",
|
|
248
|
+
cell: (row) => (
|
|
249
|
+
<AppBadge variant={row.status === "PASSED" ? "default" : "destructive"}>
|
|
250
|
+
{row.status}
|
|
251
|
+
</AppBadge>
|
|
252
|
+
),
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Column-level filter popover
|
|
257
|
+
|
|
258
|
+
```tsx
|
|
259
|
+
{
|
|
260
|
+
id: "site",
|
|
261
|
+
header: "Site",
|
|
262
|
+
accessorKey: "site",
|
|
263
|
+
enableSorting: true,
|
|
264
|
+
enableFiltering: true,
|
|
265
|
+
filterPopover: () => (
|
|
266
|
+
<div className="p-2">
|
|
267
|
+
{/* your filter UI here */}
|
|
268
|
+
</div>
|
|
269
|
+
),
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Extending the toolbar
|
|
274
|
+
|
|
275
|
+
`TableManagerToolbarActions` is an open slot — add any custom controls inside it:
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
<TableManagerToolbarActions>
|
|
279
|
+
<TableManagerMultiFilter ... />
|
|
280
|
+
<TableManagerDateRange />
|
|
281
|
+
<TableManagerPagination />
|
|
282
|
+
<TableManagerColumnToggle />
|
|
283
|
+
<TableManagerExport ... />
|
|
284
|
+
{/* custom */}
|
|
285
|
+
<AppButton variant="outline" size="sm">Custom Action</AppButton>
|
|
286
|
+
</TableManagerToolbarActions>
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Rules
|
|
290
|
+
|
|
291
|
+
- ✅ Always wrap everything in `<TableManager>` before using any sub-component
|
|
292
|
+
- ✅ All row objects must have `id: string | number`
|
|
293
|
+
- ✅ Pass `totalCount` equal to the total filtered record count (not just the current page length) for correct pagination
|
|
294
|
+
- ✅ Use `defaultFilters` to pre-select multiselect filter options so they render as checked on first render
|
|
295
|
+
- ✅ Implement OR logic in `onFilterChange` when a row can belong to multiple filter values
|
|
296
|
+
- ✅ Set `type: "date"` on date columns and `type: "text"` on primary text columns so the default sort works correctly
|
|
297
|
+
- ✅ Use `TableManagerToolbarActions` with `shrink-0` behavior built in — it will not compress when the search input grows
|
|
298
|
+
- ❌ Never import sub-components outside of a `<TableManager>` tree — they read from internal context and will throw
|
|
299
|
+
- ❌ Never filter data internally in the block — always pass already-filtered data via the `data` prop
|
|
300
|
+
- ❌ Never add `date-fns` or a date library just for this block — it uses native `Date` methods
|
|
301
|
+
- ❌ Never use arbitrary CSS selectors (`:last-child`, `[&_th:last-child]`) to align column headers — use `headerAlign` / `headerCell` instead
|
|
302
|
+
- ❌ If a prop you need is missing, stop and inform the design team
|
|
303
|
+
|
|
304
|
+
## Responsive
|
|
305
|
+
|
|
306
|
+
`TableManagerToolbar` wraps with `flex-wrap` on small screens. `TableManagerToolbarActions` loses its `ml-auto` below `sm` and flows inline with other toolbar children. Wrapping is automatic — no consumer change needed.
|
package/rules/table.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# AppTable
|
|
2
|
+
|
|
3
|
+
> Docs: https://ui-kit.vercel.app/docs/components/table
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import {
|
|
7
|
+
AppTable,
|
|
8
|
+
AppTableHeader,
|
|
9
|
+
AppTableBody,
|
|
10
|
+
AppTableFooter,
|
|
11
|
+
AppTableHead,
|
|
12
|
+
AppTableRow,
|
|
13
|
+
AppTableCell,
|
|
14
|
+
AppTableCaption,
|
|
15
|
+
} from "@/components/primitives/AppTable"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Sub-components
|
|
19
|
+
|
|
20
|
+
### AppTable
|
|
21
|
+
|
|
22
|
+
| Prop | Type | Default | Description |
|
|
23
|
+
|------|------|---------|-------------|
|
|
24
|
+
| `className` | `string` | — | Merged onto `<table>` via `cn()`. The overflow scroll wrapper is not className-accessible. |
|
|
25
|
+
|
|
26
|
+
### AppTableHeader
|
|
27
|
+
|
|
28
|
+
| Prop | Type | Default | Description |
|
|
29
|
+
|------|------|---------|-------------|
|
|
30
|
+
| `className` | `string` | — | Merged onto `<thead>`. Default: `[&_tr]:border-b`. |
|
|
31
|
+
|
|
32
|
+
### AppTableBody
|
|
33
|
+
|
|
34
|
+
| Prop | Type | Default | Description |
|
|
35
|
+
|------|------|---------|-------------|
|
|
36
|
+
| `className` | `string` | — | Merged onto `<tbody>`. Default removes border from the last row. |
|
|
37
|
+
|
|
38
|
+
### AppTableFooter
|
|
39
|
+
|
|
40
|
+
| Prop | Type | Default | Description |
|
|
41
|
+
|------|------|---------|-------------|
|
|
42
|
+
| `className` | `string` | — | Merged onto `<tfoot>`. Default: `border-t bg-muted/50 font-medium [&>tr]:last:border-b-0`. |
|
|
43
|
+
|
|
44
|
+
### AppTableHead
|
|
45
|
+
|
|
46
|
+
| Prop | Type | Default | Description |
|
|
47
|
+
|------|------|---------|-------------|
|
|
48
|
+
| `className` | `string` | — | Merged onto `<th>`. Default: `h-10 px-2 text-left align-middle font-medium text-muted-foreground`. |
|
|
49
|
+
|
|
50
|
+
### AppTableRow
|
|
51
|
+
|
|
52
|
+
| Prop | Type | Default | Description |
|
|
53
|
+
|------|------|---------|-------------|
|
|
54
|
+
| `data-state` | `"selected" \| undefined` | — | Set to `"selected"` to apply the selection highlight (`bg-muted`). Controlled by your state. |
|
|
55
|
+
| `className` | `string` | — | Merged onto `<tr>`. Default: `border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted`. |
|
|
56
|
+
|
|
57
|
+
### AppTableCell
|
|
58
|
+
|
|
59
|
+
| Prop | Type | Default | Description |
|
|
60
|
+
|------|------|---------|-------------|
|
|
61
|
+
| `colSpan` | `number` | — | Span multiple columns. Common in footer summary rows. |
|
|
62
|
+
| `className` | `string` | — | Merged onto `<td>`. Default: `p-2 align-middle`. |
|
|
63
|
+
|
|
64
|
+
### AppTableCaption
|
|
65
|
+
|
|
66
|
+
| Prop | Type | Default | Description |
|
|
67
|
+
|------|------|---------|-------------|
|
|
68
|
+
| `className` | `string` | — | Merged onto `<caption>`. Default: `mt-4 text-sm text-muted-foreground`. Renders below body via `caption-bottom`. |
|
|
69
|
+
|
|
70
|
+
## Usage
|
|
71
|
+
|
|
72
|
+
### Basic
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
<AppTable>
|
|
76
|
+
<AppTableHeader>
|
|
77
|
+
<AppTableRow>
|
|
78
|
+
<AppTableHead>Name</AppTableHead>
|
|
79
|
+
<AppTableHead>Role</AppTableHead>
|
|
80
|
+
</AppTableRow>
|
|
81
|
+
</AppTableHeader>
|
|
82
|
+
<AppTableBody>
|
|
83
|
+
<AppTableRow>
|
|
84
|
+
<AppTableCell>John Doe</AppTableCell>
|
|
85
|
+
<AppTableCell>Admin</AppTableCell>
|
|
86
|
+
</AppTableRow>
|
|
87
|
+
</AppTableBody>
|
|
88
|
+
</AppTable>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### With caption
|
|
92
|
+
|
|
93
|
+
Place `AppTableCaption` as the first child of `AppTable`. It renders below the body via `caption-bottom`.
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
<AppTable>
|
|
97
|
+
<AppTableCaption>A list of your recent invoices.</AppTableCaption>
|
|
98
|
+
<AppTableHeader>
|
|
99
|
+
<AppTableRow>
|
|
100
|
+
<AppTableHead>Invoice</AppTableHead>
|
|
101
|
+
<AppTableHead>Status</AppTableHead>
|
|
102
|
+
<AppTableHead className="text-right">Amount</AppTableHead>
|
|
103
|
+
</AppTableRow>
|
|
104
|
+
</AppTableHeader>
|
|
105
|
+
<AppTableBody>
|
|
106
|
+
<AppTableRow>
|
|
107
|
+
<AppTableCell className="font-medium">INV-001</AppTableCell>
|
|
108
|
+
<AppTableCell>Paid</AppTableCell>
|
|
109
|
+
<AppTableCell className="text-right">$250.00</AppTableCell>
|
|
110
|
+
</AppTableRow>
|
|
111
|
+
</AppTableBody>
|
|
112
|
+
</AppTable>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### With footer
|
|
116
|
+
|
|
117
|
+
Use `AppTableFooter` for totals or summary rows. Use `colSpan` on `AppTableCell` to span multiple columns.
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
<AppTable>
|
|
121
|
+
<AppTableHeader>
|
|
122
|
+
<AppTableRow>
|
|
123
|
+
<AppTableHead>Invoice</AppTableHead>
|
|
124
|
+
<AppTableHead>Status</AppTableHead>
|
|
125
|
+
<AppTableHead className="text-right">Amount</AppTableHead>
|
|
126
|
+
</AppTableRow>
|
|
127
|
+
</AppTableHeader>
|
|
128
|
+
<AppTableBody>
|
|
129
|
+
<AppTableRow>
|
|
130
|
+
<AppTableCell className="font-medium">INV-001</AppTableCell>
|
|
131
|
+
<AppTableCell>Paid</AppTableCell>
|
|
132
|
+
<AppTableCell className="text-right">$250.00</AppTableCell>
|
|
133
|
+
</AppTableRow>
|
|
134
|
+
</AppTableBody>
|
|
135
|
+
<AppTableFooter>
|
|
136
|
+
<AppTableRow>
|
|
137
|
+
<AppTableCell colSpan={2}>Total</AppTableCell>
|
|
138
|
+
<AppTableCell className="text-right">$250.00</AppTableCell>
|
|
139
|
+
</AppTableRow>
|
|
140
|
+
</AppTableFooter>
|
|
141
|
+
</AppTable>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### With selected row
|
|
145
|
+
|
|
146
|
+
Set `data-state="selected"` on any `AppTableRow` to apply the selection highlight. No built-in selection logic is included — control this via your own state.
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
const [selectedId, setSelectedId] = React.useState<string | null>(null)
|
|
150
|
+
|
|
151
|
+
<AppTableBody>
|
|
152
|
+
{rows.map((row) => (
|
|
153
|
+
<AppTableRow
|
|
154
|
+
key={row.id}
|
|
155
|
+
data-state={selectedId === row.id ? "selected" : undefined}
|
|
156
|
+
onClick={() => setSelectedId(row.id)}
|
|
157
|
+
>
|
|
158
|
+
<AppTableCell>{row.name}</AppTableCell>
|
|
159
|
+
<AppTableCell>{row.email}</AppTableCell>
|
|
160
|
+
</AppTableRow>
|
|
161
|
+
))}
|
|
162
|
+
</AppTableBody>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Rules
|
|
166
|
+
|
|
167
|
+
- ✅ Always use `AppTable` and its sub-components — never use raw `<table>`, `<thead>`, `<tbody>`, `<tfoot>`, `<tr>`, `<th>`, `<td>`, or `<caption>`
|
|
168
|
+
- ✅ Use `AppTableHeader` for column title rows and `AppTableBody` for data rows
|
|
169
|
+
- ✅ Place `AppTableCaption` as the **first child** of `AppTable`
|
|
170
|
+
- ✅ Use `AppTableFooter` for totals and aggregates — it applies the correct muted background automatically
|
|
171
|
+
- ✅ Use `colSpan` on `AppTableCell` in footer rows to span multiple columns
|
|
172
|
+
- ✅ Control row selection via `data-state="selected"` on `AppTableRow` — do not add custom selected styling
|
|
173
|
+
- ❌ Do not add `border-b` manually to rows — `AppTableRow` already applies it
|
|
174
|
+
- ❌ Do not nest `AppTableHead` inside `AppTableBody` or `AppTableCell` inside `AppTableHeader`
|
|
175
|
+
- ❌ Do not place `AppTableCaption` after `AppTableBody` — always put it first inside `AppTable`
|
|
176
|
+
- ❌ Do not apply direct width/height to table cells unless absolutely necessary — use container-level Tailwind classes instead
|
|
177
|
+
- ❌ If a prop you need is missing, stop and inform the design team
|
package/rules/tabs.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# AppTabs
|
|
2
|
+
|
|
3
|
+
> Docs: https://ui-kit.vercel.app/docs/components/tabs
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { AppTabs, AppTabsList, AppTabsTrigger, AppTabsContent } from "@/components/primitives/AppTabs"
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## AppTabs
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
|------|------|---------|-------------|
|
|
13
|
+
| `variant` | `"default" \| "underline" \| "pills"` | `"default"` | Visual style — propagates automatically to `AppTabsList` and `AppTabsTrigger` |
|
|
14
|
+
| `defaultValue` | `string` | — | The value of the tab that should be active by default |
|
|
15
|
+
| `value` | `string` | — | The controlled value of the active tab |
|
|
16
|
+
| `onValueChange` | `(value: string) => void` | — | Event handler called when the value changes |
|
|
17
|
+
| `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | The orientation of the tabs |
|
|
18
|
+
|
|
19
|
+
## AppTabsTrigger
|
|
20
|
+
|
|
21
|
+
| Prop | Type | Default | Description |
|
|
22
|
+
|------|------|---------|-------------|
|
|
23
|
+
| `value` | `string` | — | A unique value for the tab |
|
|
24
|
+
| `disabled` | `boolean` | `false` | When true, prevents the user from interacting with the tab |
|
|
25
|
+
|
|
26
|
+
## AppTabsContent
|
|
27
|
+
|
|
28
|
+
| Prop | Type | Default | Description |
|
|
29
|
+
|------|------|---------|-------------|
|
|
30
|
+
| `value` | `string` | — | A unique value that associates the content with a trigger |
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
### Default (pill container)
|
|
35
|
+
```tsx
|
|
36
|
+
<AppTabs defaultValue="account">
|
|
37
|
+
<AppTabsList>
|
|
38
|
+
<AppTabsTrigger value="account">Account</AppTabsTrigger>
|
|
39
|
+
<AppTabsTrigger value="password">Password</AppTabsTrigger>
|
|
40
|
+
</AppTabsList>
|
|
41
|
+
<AppTabsContent value="account">Account settings content.</AppTabsContent>
|
|
42
|
+
<AppTabsContent value="password">Password settings content.</AppTabsContent>
|
|
43
|
+
</AppTabs>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Underline
|
|
47
|
+
```tsx
|
|
48
|
+
<AppTabs defaultValue="overview" variant="underline">
|
|
49
|
+
<AppTabsList>
|
|
50
|
+
<AppTabsTrigger value="overview">Overview</AppTabsTrigger>
|
|
51
|
+
<AppTabsTrigger value="analytics">Analytics</AppTabsTrigger>
|
|
52
|
+
</AppTabsList>
|
|
53
|
+
<AppTabsContent value="overview">Overview content.</AppTabsContent>
|
|
54
|
+
<AppTabsContent value="analytics">Analytics content.</AppTabsContent>
|
|
55
|
+
</AppTabs>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Pills
|
|
59
|
+
```tsx
|
|
60
|
+
<AppTabs defaultValue="all" variant="pills">
|
|
61
|
+
<AppTabsList>
|
|
62
|
+
<AppTabsTrigger value="all">All</AppTabsTrigger>
|
|
63
|
+
<AppTabsTrigger value="active">Active</AppTabsTrigger>
|
|
64
|
+
<AppTabsTrigger value="archived">Archived</AppTabsTrigger>
|
|
65
|
+
</AppTabsList>
|
|
66
|
+
<AppTabsContent value="all">All items.</AppTabsContent>
|
|
67
|
+
<AppTabsContent value="active">Active items.</AppTabsContent>
|
|
68
|
+
<AppTabsContent value="archived">Archived items.</AppTabsContent>
|
|
69
|
+
</AppTabs>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Rules
|
|
73
|
+
- ✅ Always use `AppTabs` — never use a custom tab implementation
|
|
74
|
+
- ✅ Set `variant` once on `AppTabs` — do not pass it to `AppTabsList` or `AppTabsTrigger` directly
|
|
75
|
+
- ✅ Ensure `value` on `AppTabsTrigger` matches the `value` on the corresponding `AppTabsContent`
|
|
76
|
+
- ✅ Use `defaultValue` for uncontrolled tabs
|
|
77
|
+
- ❌ Do not use `AppTabs` for navigation between pages — use `AppNavigationMenu` or simple links instead
|
|
78
|
+
- ❌ If a prop you need is missing, stop and inform the design team
|
|
79
|
+
|
|
80
|
+
## Responsive
|
|
81
|
+
|
|
82
|
+
`AppTabsList` scrolls horizontally on mobile via an `overflow-x-auto scrollbar-none` wrapper with `min-w-max` on the inner list, so tabs never wrap to a second line and remain fully swipeable. No consumer changes are needed.
|
package/rules/text.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# AppTextarea
|
|
2
|
+
|
|
3
|
+
> Docs: https://ui-kit.vercel.app/docs/components/textarea
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { AppTextarea } from "@/components/primitives/AppTextarea"
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
|------|------|---------|-------------|
|
|
13
|
+
| `placeholder` | `string` | — | Placeholder text |
|
|
14
|
+
| `disabled` | `boolean` | `false` | Disables the textarea |
|
|
15
|
+
| `className` | `string` | — | Additional Tailwind classes |
|
|
16
|
+
|
|
17
|
+
> Accepts all standard HTML `<textarea>` attributes in addition to the props above.
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Basic
|
|
22
|
+
```tsx
|
|
23
|
+
<AppTextarea placeholder="Type your message here..." />
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### With Label
|
|
27
|
+
```tsx
|
|
28
|
+
<div className="grid w-full gap-1.5">
|
|
29
|
+
<AppLabel htmlFor="message">Your message</AppLabel>
|
|
30
|
+
<AppTextarea placeholder="Type your message here." id="message" />
|
|
31
|
+
</div>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Rules
|
|
35
|
+
- ✅ Always use `AppTextarea` — never use a raw `<textarea>` element
|
|
36
|
+
- ✅ Use `AppLabel` for accessibility
|
|
37
|
+
- ✅ Control height via `rows` attribute or Tailwind `h-*` classes
|
|
38
|
+
- ❌ If a prop you need is missing, stop and inform the design team
|
package/rules/toaster.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# AppToaster
|
|
2
|
+
|
|
3
|
+
> Docs: https://ui-kit.vercel.app/docs/components/toaster
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { AppToaster, toast } from "@/components/primitives/AppToaster"
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## AppToaster
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
|------|------|---------|-------------|
|
|
13
|
+
| — | — | — | No primary props; configuration is handled internally |
|
|
14
|
+
|
|
15
|
+
## toast (sonnerToast)
|
|
16
|
+
|
|
17
|
+
| Method | Description |
|
|
18
|
+
|--------|-------------|
|
|
19
|
+
| `toast(message, options?)` | Show a default toast |
|
|
20
|
+
| `toast.success(message, options?)` | Show a success toast |
|
|
21
|
+
| `toast.error(message, options?)` | Show an error toast |
|
|
22
|
+
| `toast.info(message, options?)` | Show an info toast |
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Setup (Layout)
|
|
27
|
+
```tsx
|
|
28
|
+
export default function RootLayout({ children }) {
|
|
29
|
+
return (
|
|
30
|
+
<html>
|
|
31
|
+
<body>
|
|
32
|
+
{children}
|
|
33
|
+
<AppToaster />
|
|
34
|
+
</body>
|
|
35
|
+
</html>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Triggering toast
|
|
41
|
+
```tsx
|
|
42
|
+
<AppButton
|
|
43
|
+
onClick={() =>
|
|
44
|
+
toast.success("Event created", {
|
|
45
|
+
description: "Monday, January 3rd at 6:00pm",
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
>
|
|
49
|
+
Show success
|
|
50
|
+
</AppButton>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Rules
|
|
54
|
+
- ✅ Place `<AppToaster />` once in your root layout
|
|
55
|
+
- ✅ Use `toast.success` or `toast.error` for feedback on user actions
|
|
56
|
+
- ✅ Use the `description` option for additional context
|
|
57
|
+
- ❌ Do not create multiple `AppToaster` instances
|
|
58
|
+
- ❌ If a prop you need is missing, stop and inform the design team
|