@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.
Files changed (274) hide show
  1. package/AGENTS.md +250 -0
  2. package/README.md +429 -0
  3. package/dist/assets/Service-applets-apps/audience-measurement.png +0 -0
  4. package/dist/assets/Service-applets-apps/coatro-app.png +0 -0
  5. package/dist/assets/Service-applets-apps/content-effectiveness.png +0 -0
  6. package/dist/assets/Service-applets-apps/hop-tracking.png +0 -0
  7. package/dist/assets/Service-applets-apps/index.ts +13 -0
  8. package/dist/assets/Service-applets-apps/journeys-app.png +0 -0
  9. package/dist/assets/Service-applets-apps/people-counting.png +0 -0
  10. package/dist/assets/Service-applets-apps/petra.png +0 -0
  11. package/dist/assets/Service-applets-apps/sam-generic.png +0 -0
  12. package/dist/assets/Service-applets-apps/sami-for-environment.png +0 -0
  13. package/dist/assets/Service-applets-apps/shelf-engagement.png +0 -0
  14. package/dist/assets/Service-applets-apps/traffic-management.png +0 -0
  15. package/dist/assets/Service-applets-apps/viana.png +0 -0
  16. package/dist/assets/Service-applets-apps/zone-engagement.png +0 -0
  17. package/dist/assets/icons/Dashboard-active.svg +29 -0
  18. package/dist/assets/icons/Dashboard.svg +25 -0
  19. package/dist/assets/icons/DashboardActiveIcon.tsx +35 -0
  20. package/dist/assets/icons/DashboardIcon.tsx +31 -0
  21. package/dist/assets/icons/Devices-active.svg +27 -0
  22. package/dist/assets/icons/Devices.svg +20 -0
  23. package/dist/assets/icons/DevicesActiveIcon.tsx +33 -0
  24. package/dist/assets/icons/DevicesIcon.tsx +26 -0
  25. package/dist/assets/icons/Installer-active.svg +29 -0
  26. package/dist/assets/icons/Installer.svg +17 -0
  27. package/dist/assets/icons/InstallerActiveIcon.tsx +35 -0
  28. package/dist/assets/icons/InstallerIcon.tsx +23 -0
  29. package/dist/assets/icons/Manifest-active.svg +49 -0
  30. package/dist/assets/icons/Manifest.svg +49 -0
  31. package/dist/assets/icons/ManifestActiveIcon.tsx +55 -0
  32. package/dist/assets/icons/ManifestIcon.tsx +55 -0
  33. package/dist/assets/icons/Sensor-active.svg +15 -0
  34. package/dist/assets/icons/Sensor.svg +11 -0
  35. package/dist/assets/icons/SensorActiveIcon.tsx +21 -0
  36. package/dist/assets/icons/SensorIcon.tsx +17 -0
  37. package/dist/assets/icons/Site-active.svg +14 -0
  38. package/dist/assets/icons/Site.svg +10 -0
  39. package/dist/assets/icons/SiteActiveIcon.tsx +20 -0
  40. package/dist/assets/icons/SiteIcon.tsx +16 -0
  41. package/dist/assets/icons/X-ray-active.svg +199 -0
  42. package/dist/assets/icons/X-ray.svg +47 -0
  43. package/dist/assets/icons/XrayActiveIcon.tsx +205 -0
  44. package/dist/assets/icons/XrayIcon.tsx +53 -0
  45. package/dist/assets/icons/index.ts +14 -0
  46. package/dist/assets/logos/DarkLogo.tsx +28 -0
  47. package/dist/assets/logos/DarkSymbol.tsx +9 -0
  48. package/dist/assets/logos/PrimaryLogo.tsx +28 -0
  49. package/dist/assets/logos/PrimarySymbol.tsx +9 -0
  50. package/dist/assets/logos/WhiteLogo.tsx +28 -0
  51. package/dist/assets/logos/WhiteSymbol.tsx +9 -0
  52. package/dist/assets/logos/dark_logo.svg +22 -0
  53. package/dist/assets/logos/dark_symbol.svg +3 -0
  54. package/dist/assets/logos/index.ts +6 -0
  55. package/dist/assets/logos/primary-logo.svg +22 -0
  56. package/dist/assets/logos/primary_logo.svg +22 -0
  57. package/dist/assets/logos/primary_symbol.svg +3 -0
  58. package/dist/assets/logos/white_symbol.svg +3 -0
  59. package/dist/index.cjs +160 -0
  60. package/dist/index.cjs.map +1 -0
  61. package/dist/index.js +45276 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/tokens-source.css +121 -0
  64. package/dist/types/assets/Service-applets-apps/index.d.ts +13 -0
  65. package/dist/types/assets/icons/DashboardActiveIcon.d.ts +2 -0
  66. package/dist/types/assets/icons/DashboardIcon.d.ts +2 -0
  67. package/dist/types/assets/icons/DevicesActiveIcon.d.ts +2 -0
  68. package/dist/types/assets/icons/DevicesIcon.d.ts +2 -0
  69. package/dist/types/assets/icons/InstallerActiveIcon.d.ts +2 -0
  70. package/dist/types/assets/icons/InstallerIcon.d.ts +2 -0
  71. package/dist/types/assets/icons/ManifestActiveIcon.d.ts +2 -0
  72. package/dist/types/assets/icons/ManifestIcon.d.ts +2 -0
  73. package/dist/types/assets/icons/SensorActiveIcon.d.ts +2 -0
  74. package/dist/types/assets/icons/SensorIcon.d.ts +2 -0
  75. package/dist/types/assets/icons/SiteActiveIcon.d.ts +2 -0
  76. package/dist/types/assets/icons/SiteIcon.d.ts +2 -0
  77. package/dist/types/assets/icons/XrayActiveIcon.d.ts +2 -0
  78. package/dist/types/assets/icons/XrayIcon.d.ts +2 -0
  79. package/dist/types/assets/icons/index.d.ts +14 -0
  80. package/dist/types/assets/logos/DarkLogo.d.ts +2 -0
  81. package/dist/types/assets/logos/DarkSymbol.d.ts +2 -0
  82. package/dist/types/assets/logos/PrimaryLogo.d.ts +2 -0
  83. package/dist/types/assets/logos/PrimarySymbol.d.ts +2 -0
  84. package/dist/types/assets/logos/WhiteLogo.d.ts +2 -0
  85. package/dist/types/assets/logos/WhiteSymbol.d.ts +2 -0
  86. package/dist/types/assets/logos/index.d.ts +6 -0
  87. package/dist/types/components/blocks/AppBentoMenu.d.ts +31 -0
  88. package/dist/types/components/blocks/AppDashboard.d.ts +121 -0
  89. package/dist/types/components/blocks/AppHeader.d.ts +198 -0
  90. package/dist/types/components/blocks/AppLocationTreeFilter.d.ts +44 -0
  91. package/dist/types/components/blocks/AppNotificationsMenu.d.ts +50 -0
  92. package/dist/types/components/blocks/AppPageTitle.d.ts +86 -0
  93. package/dist/types/components/blocks/AppProfile.d.ts +53 -0
  94. package/dist/types/components/blocks/TableManager.d.ts +194 -0
  95. package/dist/types/components/blocks/backgrounds/AppDashboardBackgroundDots.d.ts +14 -0
  96. package/dist/types/components/blocks/backgrounds/AppDashboardBackgroundWave.d.ts +14 -0
  97. package/dist/types/components/blocks/backgrounds/index.d.ts +3 -0
  98. package/dist/types/components/blocks/backgrounds/types.d.ts +13 -0
  99. package/dist/types/components/blocks/index.d.ts +9 -0
  100. package/dist/types/components/primitives/AppAccordion.d.ts +22 -0
  101. package/dist/types/components/primitives/AppAlert.d.ts +33 -0
  102. package/dist/types/components/primitives/AppAlertDialog.d.ts +79 -0
  103. package/dist/types/components/primitives/AppAspectRatio.d.ts +7 -0
  104. package/dist/types/components/primitives/AppAvatar.d.ts +17 -0
  105. package/dist/types/components/primitives/AppBadge.d.ts +9 -0
  106. package/dist/types/components/primitives/AppBreadcrumb.d.ts +45 -0
  107. package/dist/types/components/primitives/AppButton.d.ts +24 -0
  108. package/dist/types/components/primitives/AppButtonGroup.d.ts +10 -0
  109. package/dist/types/components/primitives/AppCalendar.d.ts +51 -0
  110. package/dist/types/components/primitives/AppCard.d.ts +41 -0
  111. package/dist/types/components/primitives/AppCarousel.d.ts +26 -0
  112. package/dist/types/components/primitives/AppChart.d.ts +27 -0
  113. package/dist/types/components/primitives/AppCheckbox.d.ts +9 -0
  114. package/dist/types/components/primitives/AppCollapsible.d.ts +20 -0
  115. package/dist/types/components/primitives/AppCombobox.d.ts +37 -0
  116. package/dist/types/components/primitives/AppCommand.d.ts +47 -0
  117. package/dist/types/components/primitives/AppContextMenu.d.ts +82 -0
  118. package/dist/types/components/primitives/AppDataTable.d.ts +23 -0
  119. package/dist/types/components/primitives/AppDatePicker.d.ts +26 -0
  120. package/dist/types/components/primitives/AppDialog.d.ts +40 -0
  121. package/dist/types/components/primitives/AppDrawer.d.ts +58 -0
  122. package/dist/types/components/primitives/AppDropdownMenu.d.ts +85 -0
  123. package/dist/types/components/primitives/AppEmpty.d.ts +35 -0
  124. package/dist/types/components/primitives/AppField.d.ts +65 -0
  125. package/dist/types/components/primitives/AppForm.d.ts +58 -0
  126. package/dist/types/components/primitives/AppHoverCard.d.ts +19 -0
  127. package/dist/types/components/primitives/AppInput.d.ts +21 -0
  128. package/dist/types/components/primitives/AppKbd.d.ts +18 -0
  129. package/dist/types/components/primitives/AppLabel.d.ts +8 -0
  130. package/dist/types/components/primitives/AppMenubar.d.ts +83 -0
  131. package/dist/types/components/primitives/AppNavigationMenu.d.ts +51 -0
  132. package/dist/types/components/primitives/AppPagination.d.ts +46 -0
  133. package/dist/types/components/primitives/AppPopover.d.ts +20 -0
  134. package/dist/types/components/primitives/AppProgress.d.ts +9 -0
  135. package/dist/types/components/primitives/AppRadioGroup.d.ts +15 -0
  136. package/dist/types/components/primitives/AppScrollArea.d.ts +12 -0
  137. package/dist/types/components/primitives/AppScrollText.d.ts +7 -0
  138. package/dist/types/components/primitives/AppSelect.d.ts +46 -0
  139. package/dist/types/components/primitives/AppSeparator.d.ts +8 -0
  140. package/dist/types/components/primitives/AppSheet.d.ts +32 -0
  141. package/dist/types/components/primitives/AppSidebar.d.ts +59 -0
  142. package/dist/types/components/primitives/AppSkeleton.d.ts +6 -0
  143. package/dist/types/components/primitives/AppSpinner.d.ts +13 -0
  144. package/dist/types/components/primitives/AppSwitch.d.ts +8 -0
  145. package/dist/types/components/primitives/AppTable.d.ts +53 -0
  146. package/dist/types/components/primitives/AppTabs.d.ts +10 -0
  147. package/dist/types/components/primitives/AppTextarea.d.ts +9 -0
  148. package/dist/types/components/primitives/AppThemeProvider.d.ts +46 -0
  149. package/dist/types/components/primitives/AppToaster.d.ts +7 -0
  150. package/dist/types/components/primitives/AppToggle.d.ts +9 -0
  151. package/dist/types/components/primitives/AppToggleGroup.d.ts +18 -0
  152. package/dist/types/components/primitives/AppTooltip.d.ts +26 -0
  153. package/dist/types/components/primitives/AppTypography.d.ts +80 -0
  154. package/dist/types/components/primitives/index.d.ts +57 -0
  155. package/dist/types/components/ui/accordion.d.ts +7 -0
  156. package/dist/types/components/ui/alert-dialog.d.ts +20 -0
  157. package/dist/types/components/ui/alert.d.ts +8 -0
  158. package/dist/types/components/ui/aspect-ratio.d.ts +4 -0
  159. package/dist/types/components/ui/avatar.d.ts +6 -0
  160. package/dist/types/components/ui/badge.d.ts +9 -0
  161. package/dist/types/components/ui/breadcrumb.d.ts +19 -0
  162. package/dist/types/components/ui/button.d.ts +13 -0
  163. package/dist/types/components/ui/calendar.d.ts +8 -0
  164. package/dist/types/components/ui/card.d.ts +11 -0
  165. package/dist/types/components/ui/carousel.d.ts +28 -0
  166. package/dist/types/components/ui/chart.d.ts +48 -0
  167. package/dist/types/components/ui/checkbox.d.ts +4 -0
  168. package/dist/types/components/ui/collapsible.d.ts +6 -0
  169. package/dist/types/components/ui/combobox.d.ts +83 -0
  170. package/dist/types/components/ui/command.d.ts +82 -0
  171. package/dist/types/components/ui/context-menu.d.ts +27 -0
  172. package/dist/types/components/ui/dialog.d.ts +19 -0
  173. package/dist/types/components/ui/drawer.d.ts +23 -0
  174. package/dist/types/components/ui/dropdown-menu.d.ts +27 -0
  175. package/dist/types/components/ui/empty.d.ts +14 -0
  176. package/dist/types/components/ui/field.d.ts +40 -0
  177. package/dist/types/components/ui/form.d.ts +22 -0
  178. package/dist/types/components/ui/hover-card.d.ts +6 -0
  179. package/dist/types/components/ui/input.d.ts +3 -0
  180. package/dist/types/components/ui/kbd.d.ts +4 -0
  181. package/dist/types/components/ui/label.d.ts +4 -0
  182. package/dist/types/components/ui/menubar.d.ts +30 -0
  183. package/dist/types/components/ui/navigation-menu.d.ts +12 -0
  184. package/dist/types/components/ui/pagination.d.ts +28 -0
  185. package/dist/types/components/ui/popover.d.ts +6 -0
  186. package/dist/types/components/ui/progress.d.ts +4 -0
  187. package/dist/types/components/ui/radio-group.d.ts +5 -0
  188. package/dist/types/components/ui/scroll-area.d.ts +5 -0
  189. package/dist/types/components/ui/scroll-text.d.ts +6 -0
  190. package/dist/types/components/ui/select.d.ts +13 -0
  191. package/dist/types/components/ui/separator.d.ts +4 -0
  192. package/dist/types/components/ui/sheet.d.ts +25 -0
  193. package/dist/types/components/ui/sidebar.d.ts +69 -0
  194. package/dist/types/components/ui/skeleton.d.ts +2 -0
  195. package/dist/types/components/ui/sonner.d.ts +2 -0
  196. package/dist/types/components/ui/switch.d.ts +4 -0
  197. package/dist/types/components/ui/table.d.ts +10 -0
  198. package/dist/types/components/ui/tabs.d.ts +19 -0
  199. package/dist/types/components/ui/textarea.d.ts +5 -0
  200. package/dist/types/components/ui/toggle-group.d.ts +15 -0
  201. package/dist/types/components/ui/toggle.d.ts +12 -0
  202. package/dist/types/components/ui/tooltip.d.ts +7 -0
  203. package/dist/types/hooks/use-mobile.d.ts +13 -0
  204. package/dist/types/hooks/use-page-title.d.ts +23 -0
  205. package/dist/types/index.d.ts +2 -0
  206. package/dist/types/lib/utils.d.ts +2 -0
  207. package/dist/ui-kit.css +1 -0
  208. package/package.json +117 -0
  209. package/rules/accordion.md +60 -0
  210. package/rules/alert-dialog.md +62 -0
  211. package/rules/alert.md +61 -0
  212. package/rules/aspect-ratio.md +47 -0
  213. package/rules/avatar.md +52 -0
  214. package/rules/badge.md +55 -0
  215. package/rules/bento-menu.md +86 -0
  216. package/rules/breadcrumb.md +80 -0
  217. package/rules/button-group.md +58 -0
  218. package/rules/button.md +66 -0
  219. package/rules/calendar.md +97 -0
  220. package/rules/card.md +84 -0
  221. package/rules/carousel.md +113 -0
  222. package/rules/chart.md +125 -0
  223. package/rules/checkbox.md +49 -0
  224. package/rules/collapsible.md +57 -0
  225. package/rules/combobox.md +133 -0
  226. package/rules/command.md +73 -0
  227. package/rules/context-menu.md +65 -0
  228. package/rules/dashboard.md +368 -0
  229. package/rules/data-table.md +91 -0
  230. package/rules/date-picker.md +65 -0
  231. package/rules/dialog.md +60 -0
  232. package/rules/drawer.md +65 -0
  233. package/rules/dropdown-menu.md +72 -0
  234. package/rules/empty.md +110 -0
  235. package/rules/field.md +149 -0
  236. package/rules/form.md +60 -0
  237. package/rules/header.md +245 -0
  238. package/rules/hover-card.md +53 -0
  239. package/rules/icons.md +141 -0
  240. package/rules/input.md +66 -0
  241. package/rules/kbd.md +58 -0
  242. package/rules/label.md +30 -0
  243. package/rules/location-tree-filter.md +165 -0
  244. package/rules/logo.md +58 -0
  245. package/rules/menubar.md +75 -0
  246. package/rules/navigation-menu.md +68 -0
  247. package/rules/notifications-menu.md +137 -0
  248. package/rules/pagetitle.md +160 -0
  249. package/rules/pagination.md +71 -0
  250. package/rules/popover.md +48 -0
  251. package/rules/profile.md +125 -0
  252. package/rules/progress.md +41 -0
  253. package/rules/radio-group.md +44 -0
  254. package/rules/scroll-area.md +32 -0
  255. package/rules/scroll-text.md +40 -0
  256. package/rules/select.md +86 -0
  257. package/rules/separator.md +43 -0
  258. package/rules/sheet.md +76 -0
  259. package/rules/sidebar.md +442 -0
  260. package/rules/skeleton.md +46 -0
  261. package/rules/spinner.md +43 -0
  262. package/rules/switch.md +46 -0
  263. package/rules/table-manager.md +306 -0
  264. package/rules/table.md +177 -0
  265. package/rules/tabs.md +82 -0
  266. package/rules/text.md +3 -0
  267. package/rules/textarea.md +38 -0
  268. package/rules/toaster.md +58 -0
  269. package/rules/toggle-group.md +50 -0
  270. package/rules/toggle.md +40 -0
  271. package/rules/tokens.md +88 -0
  272. package/rules/tooltip.md +78 -0
  273. package/rules/typography.md +81 -0
  274. 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,3 @@
1
+ # Renamed
2
+
3
+ `AppText` has been renamed to `AppTypography`. See `typography.md`.
@@ -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
@@ -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