@grampro/kit 0.0.0-stage → 2.4.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 (505) hide show
  1. package/.gbs/skills/gbs-components/SKILL.md +190 -0
  2. package/.gbs/skills/gbs-components/references/accessibility.md +102 -0
  3. package/.gbs/skills/gbs-components/references/data-display.md +185 -0
  4. package/.gbs/skills/gbs-components/references/data-grid.md +116 -0
  5. package/.gbs/skills/gbs-components/references/forms.md +202 -0
  6. package/.gbs/skills/gbs-components/references/install.md +211 -0
  7. package/.gbs/skills/gbs-components/references/overlays.md +206 -0
  8. package/.gbs/skills/gbs-components/references/pickers.md +83 -0
  9. package/.gbs/skills/gbs-components/references/styling.md +246 -0
  10. package/.gbs/skills/gbs-components/references/toaster.md +57 -0
  11. package/CHANGELOG.md +139 -0
  12. package/LICENSE +15 -0
  13. package/README.md +193 -2
  14. package/index.cjs +1370 -0
  15. package/package.json +74 -4
  16. package/schema/passport-v1.schema.json +204 -0
  17. package/source/components/accordion/README.md +45 -0
  18. package/source/components/accordion/core/index.ts +2 -0
  19. package/source/components/accordion/core/open.ts +56 -0
  20. package/source/components/accordion/core/types.ts +17 -0
  21. package/source/components/accordion/index.ts +8 -0
  22. package/source/components/accordion/passport.json +259 -0
  23. package/source/components/accordion/react/Accordion.tsx +133 -0
  24. package/source/components/accordion/react/AccordionItem.tsx +120 -0
  25. package/source/components/accordion/react/context.ts +20 -0
  26. package/source/components/accordion/react/props.ts +13 -0
  27. package/source/components/accordion/styles.css +207 -0
  28. package/source/components/alert/README.md +39 -0
  29. package/source/components/alert/core/index.ts +2 -0
  30. package/source/components/alert/core/live.ts +25 -0
  31. package/source/components/alert/core/types.ts +7 -0
  32. package/source/components/alert/index.ts +5 -0
  33. package/source/components/alert/passport.json +250 -0
  34. package/source/components/alert/react/Alert.tsx +113 -0
  35. package/source/components/alert/react/icons.tsx +21 -0
  36. package/source/components/alert/react/locale.ts +5 -0
  37. package/source/components/alert/react/props.ts +11 -0
  38. package/source/components/alert/styles.css +154 -0
  39. package/source/components/avatar/core/identity.ts +103 -0
  40. package/source/components/avatar/core/index.ts +2 -0
  41. package/source/components/avatar/core/types.ts +12 -0
  42. package/source/components/avatar/index.ts +7 -0
  43. package/source/components/avatar/passport.json +294 -0
  44. package/source/components/avatar/react/Avatar.tsx +118 -0
  45. package/source/components/avatar/react/AvatarGroup.tsx +74 -0
  46. package/source/components/avatar/react/locale.ts +11 -0
  47. package/source/components/avatar/react/props.ts +6 -0
  48. package/source/components/avatar/styles.css +225 -0
  49. package/source/components/badge/README.md +37 -0
  50. package/source/components/badge/core/count.ts +37 -0
  51. package/source/components/badge/core/index.ts +2 -0
  52. package/source/components/badge/core/types.ts +11 -0
  53. package/source/components/badge/index.ts +7 -0
  54. package/source/components/badge/passport.json +332 -0
  55. package/source/components/badge/react/Badge.tsx +89 -0
  56. package/source/components/badge/react/Tag.tsx +82 -0
  57. package/source/components/badge/react/locale.ts +5 -0
  58. package/source/components/badge/react/props.ts +6 -0
  59. package/source/components/badge/styles.css +203 -0
  60. package/source/components/breadcrumb/README.md +34 -0
  61. package/source/components/breadcrumb/core/index.ts +4 -0
  62. package/source/components/breadcrumb/core/trail.ts +42 -0
  63. package/source/components/breadcrumb/core/types.ts +20 -0
  64. package/source/components/breadcrumb/index.ts +5 -0
  65. package/source/components/breadcrumb/passport.json +243 -0
  66. package/source/components/breadcrumb/react/Breadcrumb.tsx +177 -0
  67. package/source/components/breadcrumb/react/locale.ts +6 -0
  68. package/source/components/breadcrumb/react/props.ts +14 -0
  69. package/source/components/breadcrumb/styles.css +138 -0
  70. package/source/components/button/README.md +32 -0
  71. package/source/components/button/core/index.ts +3 -0
  72. package/source/components/button/core/state.ts +16 -0
  73. package/source/components/button/core/types.ts +28 -0
  74. package/source/components/button/index.ts +5 -0
  75. package/source/components/button/passport.json +402 -0
  76. package/source/components/button/passport.manual.json +31 -0
  77. package/source/components/button/react/Button.tsx +173 -0
  78. package/source/components/button/react/locale.ts +5 -0
  79. package/source/components/button/react/props.ts +23 -0
  80. package/source/components/button/styles.css +232 -0
  81. package/source/components/card/README.md +60 -0
  82. package/source/components/card/core/index.ts +4 -0
  83. package/source/components/card/core/trend.ts +32 -0
  84. package/source/components/card/core/types.ts +5 -0
  85. package/source/components/card/index.ts +5 -0
  86. package/source/components/card/passport.json +337 -0
  87. package/source/components/card/react/Card.tsx +133 -0
  88. package/source/components/card/react/Stat.tsx +127 -0
  89. package/source/components/card/react/props.ts +4 -0
  90. package/source/components/card/styles.css +230 -0
  91. package/source/components/checkbox/README.md +36 -0
  92. package/source/components/checkbox/core/group.ts +30 -0
  93. package/source/components/checkbox/core/index.ts +3 -0
  94. package/source/components/checkbox/core/types.ts +17 -0
  95. package/source/components/checkbox/index.ts +9 -0
  96. package/source/components/checkbox/passport.json +456 -0
  97. package/source/components/checkbox/react/Checkbox.tsx +147 -0
  98. package/source/components/checkbox/react/CheckboxGroup.tsx +149 -0
  99. package/source/components/checkbox/react/context.ts +16 -0
  100. package/source/components/checkbox/react/locale.ts +5 -0
  101. package/source/components/checkbox/react/props.ts +6 -0
  102. package/source/components/checkbox/styles.css +211 -0
  103. package/source/components/combobox/README.md +170 -0
  104. package/source/components/combobox/core/filter.ts +155 -0
  105. package/source/components/combobox/core/index.ts +16 -0
  106. package/source/components/combobox/core/types.ts +48 -0
  107. package/source/components/combobox/core/virtual.ts +67 -0
  108. package/source/components/combobox/index.ts +13 -0
  109. package/source/components/combobox/passport.json +456 -0
  110. package/source/components/combobox/react/Listbox.tsx +310 -0
  111. package/source/components/combobox/react/MultiSelect.tsx +265 -0
  112. package/source/components/combobox/react/Popover.tsx +38 -0
  113. package/source/components/combobox/react/Select.tsx +200 -0
  114. package/source/components/combobox/react/icons.tsx +11 -0
  115. package/source/components/combobox/react/locale.ts +16 -0
  116. package/source/components/combobox/react/props.ts +88 -0
  117. package/source/components/combobox/react/useCombobox.ts +409 -0
  118. package/source/components/combobox/styles.css +419 -0
  119. package/source/components/data-grid/README.md +233 -0
  120. package/source/components/data-grid/agent/coerce.ts +368 -0
  121. package/source/components/data-grid/agent/contract.ts +410 -0
  122. package/source/components/data-grid/agent/dataset.ts +92 -0
  123. package/source/components/data-grid/agent/engine.ts +470 -0
  124. package/source/components/data-grid/agent/executors.ts +155 -0
  125. package/source/components/data-grid/agent/index.ts +79 -0
  126. package/source/components/data-grid/agent/intent.ts +324 -0
  127. package/source/components/data-grid/agent/operations.ts +335 -0
  128. package/source/components/data-grid/agent/validate.ts +630 -0
  129. package/source/components/data-grid/agent/webmcp.ts +107 -0
  130. package/source/components/data-grid/core/columnHelper.ts +21 -0
  131. package/source/components/data-grid/core/columns.ts +288 -0
  132. package/source/components/data-grid/core/filtering.ts +237 -0
  133. package/source/components/data-grid/core/grid.ts +638 -0
  134. package/source/components/data-grid/core/index.ts +14 -0
  135. package/source/components/data-grid/core/rows.ts +64 -0
  136. package/source/components/data-grid/core/sorting.ts +133 -0
  137. package/source/components/data-grid/core/state.ts +82 -0
  138. package/source/components/data-grid/core/store.ts +52 -0
  139. package/source/components/data-grid/core/types.ts +302 -0
  140. package/source/components/data-grid/core/values.ts +98 -0
  141. package/source/components/data-grid/core/virtual.ts +85 -0
  142. package/source/components/data-grid/export/csv.ts +32 -0
  143. package/source/components/data-grid/export/download.ts +12 -0
  144. package/source/components/data-grid/export/pdf-font.ts +139 -0
  145. package/source/components/data-grid/export/pdf-writer.ts +113 -0
  146. package/source/components/data-grid/export/pdf.ts +379 -0
  147. package/source/components/data-grid/export/table.ts +73 -0
  148. package/source/components/data-grid/export/xlsx.ts +145 -0
  149. package/source/components/data-grid/export/zip.ts +87 -0
  150. package/source/components/data-grid/index.ts +14 -0
  151. package/source/components/data-grid/passport.json +1051 -0
  152. package/source/components/data-grid/passport.manual.json +255 -0
  153. package/source/components/data-grid/react/AskGrid.tsx +164 -0
  154. package/source/components/data-grid/react/Cell.tsx +282 -0
  155. package/source/components/data-grid/react/ColumnMenu.tsx +135 -0
  156. package/source/components/data-grid/react/DataGrid.tsx +335 -0
  157. package/source/components/data-grid/react/FilterForm.tsx +142 -0
  158. package/source/components/data-grid/react/HeaderRow.tsx +332 -0
  159. package/source/components/data-grid/react/Pagination.tsx +107 -0
  160. package/source/components/data-grid/react/Popover.tsx +35 -0
  161. package/source/components/data-grid/react/Row.tsx +85 -0
  162. package/source/components/data-grid/react/Toolbar.tsx +267 -0
  163. package/source/components/data-grid/react/Viewport.tsx +167 -0
  164. package/source/components/data-grid/react/context.ts +57 -0
  165. package/source/components/data-grid/react/hooks.ts +83 -0
  166. package/source/components/data-grid/react/icons.tsx +45 -0
  167. package/source/components/data-grid/react/keyboard.ts +110 -0
  168. package/source/components/data-grid/react/locale.ts +130 -0
  169. package/source/components/data-grid/styles.css +874 -0
  170. package/source/components/date-picker/README.md +141 -0
  171. package/source/components/date-picker/core/calendar.ts +266 -0
  172. package/source/components/date-picker/core/format.ts +170 -0
  173. package/source/components/date-picker/core/index.ts +41 -0
  174. package/source/components/date-picker/core/today.ts +72 -0
  175. package/source/components/date-picker/core/types.ts +68 -0
  176. package/source/components/date-picker/index.ts +16 -0
  177. package/source/components/date-picker/passport.json +407 -0
  178. package/source/components/date-picker/react/Calendar.tsx +160 -0
  179. package/source/components/date-picker/react/CalendarPanel.tsx +170 -0
  180. package/source/components/date-picker/react/DatePicker.tsx +249 -0
  181. package/source/components/date-picker/react/DateRangePicker.tsx +291 -0
  182. package/source/components/date-picker/react/MonthYearPanels.tsx +123 -0
  183. package/source/components/date-picker/react/Popover.tsx +45 -0
  184. package/source/components/date-picker/react/icons.tsx +15 -0
  185. package/source/components/date-picker/react/locale.ts +23 -0
  186. package/source/components/date-picker/react/props.ts +76 -0
  187. package/source/components/date-picker/react/useDatePicker.ts +557 -0
  188. package/source/components/date-picker/styles.css +445 -0
  189. package/source/components/dialog/README.md +39 -0
  190. package/source/components/dialog/core/api.ts +34 -0
  191. package/source/components/dialog/core/dialog.ts +11 -0
  192. package/source/components/dialog/core/index.ts +7 -0
  193. package/source/components/dialog/core/store.ts +81 -0
  194. package/source/components/dialog/core/types.ts +59 -0
  195. package/source/components/dialog/index.ts +7 -0
  196. package/source/components/dialog/passport.json +344 -0
  197. package/source/components/dialog/react/Dialog.tsx +279 -0
  198. package/source/components/dialog/react/DialogHost.tsx +45 -0
  199. package/source/components/dialog/react/icons.tsx +20 -0
  200. package/source/components/dialog/react/locale.ts +8 -0
  201. package/source/components/dialog/react/props.ts +13 -0
  202. package/source/components/dialog/styles.css +280 -0
  203. package/source/components/file-uploader/README.md +99 -0
  204. package/source/components/file-uploader/core/format.ts +79 -0
  205. package/source/components/file-uploader/core/index.ts +26 -0
  206. package/source/components/file-uploader/core/store.ts +432 -0
  207. package/source/components/file-uploader/core/transport.ts +154 -0
  208. package/source/components/file-uploader/core/types.ts +126 -0
  209. package/source/components/file-uploader/core/validate.ts +83 -0
  210. package/source/components/file-uploader/index.ts +7 -0
  211. package/source/components/file-uploader/passport.json +518 -0
  212. package/source/components/file-uploader/react/FileRow.tsx +268 -0
  213. package/source/components/file-uploader/react/FileUploader.tsx +511 -0
  214. package/source/components/file-uploader/react/icons.tsx +60 -0
  215. package/source/components/file-uploader/react/locale.ts +33 -0
  216. package/source/components/file-uploader/react/props.ts +31 -0
  217. package/source/components/file-uploader/react/useFileUploader.ts +32 -0
  218. package/source/components/file-uploader/styles.css +394 -0
  219. package/source/components/input/README.md +44 -0
  220. package/source/components/input/core/count.ts +5 -0
  221. package/source/components/input/core/index.ts +11 -0
  222. package/source/components/input/core/otp.ts +64 -0
  223. package/source/components/input/core/types.ts +14 -0
  224. package/source/components/input/index.ts +8 -0
  225. package/source/components/input/passport.json +536 -0
  226. package/source/components/input/react/Input.tsx +219 -0
  227. package/source/components/input/react/OtpInput.tsx +256 -0
  228. package/source/components/input/react/dom.ts +10 -0
  229. package/source/components/input/react/icons.tsx +17 -0
  230. package/source/components/input/react/locale.ts +9 -0
  231. package/source/components/input/react/props.ts +6 -0
  232. package/source/components/input/styles.css +295 -0
  233. package/source/components/menu/README.md +68 -0
  234. package/source/components/menu/core/index.ts +11 -0
  235. package/source/components/menu/core/navigation.ts +84 -0
  236. package/source/components/menu/core/types.ts +32 -0
  237. package/source/components/menu/index.ts +19 -0
  238. package/source/components/menu/passport.json +322 -0
  239. package/source/components/menu/react/Menu.tsx +371 -0
  240. package/source/components/menu/react/context.ts +31 -0
  241. package/source/components/menu/react/items.tsx +268 -0
  242. package/source/components/menu/react/locale.ts +6 -0
  243. package/source/components/menu/react/props.ts +4 -0
  244. package/source/components/menu/react/useMenuKeys.ts +124 -0
  245. package/source/components/menu/styles.css +224 -0
  246. package/source/components/modal/README.md +51 -0
  247. package/source/components/modal/core/dismiss.ts +29 -0
  248. package/source/components/modal/core/index.ts +3 -0
  249. package/source/components/modal/core/types.ts +27 -0
  250. package/source/components/modal/index.ts +5 -0
  251. package/source/components/modal/passport.json +289 -0
  252. package/source/components/modal/react/Modal.tsx +242 -0
  253. package/source/components/modal/react/icons.tsx +1 -0
  254. package/source/components/modal/react/locale.ts +5 -0
  255. package/source/components/modal/react/props.ts +17 -0
  256. package/source/components/modal/styles.css +241 -0
  257. package/source/components/number-input/README.md +53 -0
  258. package/source/components/number-input/core/format.ts +37 -0
  259. package/source/components/number-input/core/index.ts +4 -0
  260. package/source/components/number-input/core/parse.ts +118 -0
  261. package/source/components/number-input/core/step.ts +73 -0
  262. package/source/components/number-input/core/types.ts +32 -0
  263. package/source/components/number-input/index.ts +5 -0
  264. package/source/components/number-input/passport.json +541 -0
  265. package/source/components/number-input/react/NumberInput.tsx +465 -0
  266. package/source/components/number-input/react/icons.tsx +17 -0
  267. package/source/components/number-input/react/locale.ts +7 -0
  268. package/source/components/number-input/react/props.ts +11 -0
  269. package/source/components/number-input/styles.css +230 -0
  270. package/source/components/popover/README.md +44 -0
  271. package/source/components/popover/core/index.ts +2 -0
  272. package/source/components/popover/core/types.ts +12 -0
  273. package/source/components/popover/index.ts +4 -0
  274. package/source/components/popover/passport.json +238 -0
  275. package/source/components/popover/react/Popover.tsx +202 -0
  276. package/source/components/popover/react/locale.ts +5 -0
  277. package/source/components/popover/react/props.ts +4 -0
  278. package/source/components/popover/styles.css +148 -0
  279. package/source/components/progress/README.md +38 -0
  280. package/source/components/progress/core/index.ts +2 -0
  281. package/source/components/progress/core/progress.ts +40 -0
  282. package/source/components/progress/core/types.ts +23 -0
  283. package/source/components/progress/index.ts +7 -0
  284. package/source/components/progress/passport.json +270 -0
  285. package/source/components/progress/react/CircularProgress.tsx +106 -0
  286. package/source/components/progress/react/Progress.tsx +113 -0
  287. package/source/components/progress/react/locale.ts +7 -0
  288. package/source/components/progress/react/props.ts +6 -0
  289. package/source/components/progress/styles.css +200 -0
  290. package/source/components/radio-group/README.md +58 -0
  291. package/source/components/radio-group/core/group.ts +36 -0
  292. package/source/components/radio-group/core/index.ts +2 -0
  293. package/source/components/radio-group/core/types.ts +20 -0
  294. package/source/components/radio-group/index.ts +9 -0
  295. package/source/components/radio-group/passport.json +477 -0
  296. package/source/components/radio-group/react/Radio.tsx +144 -0
  297. package/source/components/radio-group/react/RadioGroup.tsx +179 -0
  298. package/source/components/radio-group/react/context.ts +18 -0
  299. package/source/components/radio-group/react/locale.ts +5 -0
  300. package/source/components/radio-group/react/props.ts +12 -0
  301. package/source/components/radio-group/styles.css +269 -0
  302. package/source/components/shared/README.md +54 -0
  303. package/source/components/shared/core/agent/adapter.ts +65 -0
  304. package/source/components/shared/core/agent/history.ts +120 -0
  305. package/source/components/shared/core/agent/index.ts +46 -0
  306. package/source/components/shared/core/agent/numbers.ts +217 -0
  307. package/source/components/shared/core/agent/schema.ts +180 -0
  308. package/source/components/shared/core/agent/types.ts +169 -0
  309. package/source/components/shared/core/agent/webmcp.ts +328 -0
  310. package/source/components/shared/core/cx.ts +9 -0
  311. package/source/components/shared/core/field.ts +35 -0
  312. package/source/components/shared/core/position.ts +124 -0
  313. package/source/components/shared/core/text.ts +14 -0
  314. package/source/components/shared/index.ts +17 -0
  315. package/source/components/shared/react/GramproAIProvider.tsx +50 -0
  316. package/source/components/shared/react/Popover.tsx +189 -0
  317. package/source/components/shared/react/icons.tsx +74 -0
  318. package/source/components/shared/react/useAskAgent.ts +217 -0
  319. package/source/components/shared/react/useControllableState.ts +42 -0
  320. package/source/components/shared/styles.css +79 -0
  321. package/source/components/shared/version.json +4 -0
  322. package/source/components/shared/version.ts +6 -0
  323. package/source/components/skeleton/README.md +58 -0
  324. package/source/components/skeleton/core/index.ts +3 -0
  325. package/source/components/skeleton/core/lines.ts +25 -0
  326. package/source/components/skeleton/core/types.ts +5 -0
  327. package/source/components/skeleton/index.ts +5 -0
  328. package/source/components/skeleton/passport.json +251 -0
  329. package/source/components/skeleton/react/Empty.tsx +51 -0
  330. package/source/components/skeleton/react/Skeleton.tsx +92 -0
  331. package/source/components/skeleton/react/props.ts +4 -0
  332. package/source/components/skeleton/styles.css +185 -0
  333. package/source/components/spinner/README.md +29 -0
  334. package/source/components/spinner/core/index.ts +3 -0
  335. package/source/components/spinner/core/types.ts +28 -0
  336. package/source/components/spinner/core/visibility.ts +34 -0
  337. package/source/components/spinner/index.ts +6 -0
  338. package/source/components/spinner/passport.json +245 -0
  339. package/source/components/spinner/react/Spinner.tsx +96 -0
  340. package/source/components/spinner/react/locale.ts +5 -0
  341. package/source/components/spinner/react/props.ts +4 -0
  342. package/source/components/spinner/react/useDelayedLoading.ts +39 -0
  343. package/source/components/spinner/styles.css +173 -0
  344. package/source/components/switch/README.md +46 -0
  345. package/source/components/switch/core/index.ts +2 -0
  346. package/source/components/switch/core/toggle.ts +54 -0
  347. package/source/components/switch/core/types.ts +9 -0
  348. package/source/components/switch/index.ts +5 -0
  349. package/source/components/switch/passport.json +421 -0
  350. package/source/components/switch/react/Switch.tsx +219 -0
  351. package/source/components/switch/react/locale.ts +5 -0
  352. package/source/components/switch/react/props.ts +12 -0
  353. package/source/components/switch/styles.css +227 -0
  354. package/source/components/tabs/README.md +32 -0
  355. package/source/components/tabs/core/index.ts +3 -0
  356. package/source/components/tabs/core/navigation.ts +54 -0
  357. package/source/components/tabs/core/types.ts +16 -0
  358. package/source/components/tabs/index.ts +5 -0
  359. package/source/components/tabs/passport.json +315 -0
  360. package/source/components/tabs/react/Tabs.tsx +306 -0
  361. package/source/components/tabs/react/context.ts +21 -0
  362. package/source/components/tabs/styles.css +263 -0
  363. package/source/components/textarea/README.md +39 -0
  364. package/source/components/textarea/core/count.ts +5 -0
  365. package/source/components/textarea/core/index.ts +4 -0
  366. package/source/components/textarea/core/size.ts +23 -0
  367. package/source/components/textarea/core/types.ts +17 -0
  368. package/source/components/textarea/index.ts +5 -0
  369. package/source/components/textarea/passport.json +382 -0
  370. package/source/components/textarea/react/Textarea.tsx +208 -0
  371. package/source/components/textarea/react/locale.ts +5 -0
  372. package/source/components/textarea/react/props.ts +4 -0
  373. package/source/components/textarea/styles.css +158 -0
  374. package/source/components/toaster/README.md +128 -0
  375. package/source/components/toaster/core/api.ts +87 -0
  376. package/source/components/toaster/core/index.ts +14 -0
  377. package/source/components/toaster/core/store.ts +211 -0
  378. package/source/components/toaster/core/toast.ts +12 -0
  379. package/source/components/toaster/core/types.ts +78 -0
  380. package/source/components/toaster/index.ts +6 -0
  381. package/source/components/toaster/passport.json +221 -0
  382. package/source/components/toaster/react/ToastItem.tsx +164 -0
  383. package/source/components/toaster/react/Toaster.tsx +187 -0
  384. package/source/components/toaster/react/icons.tsx +23 -0
  385. package/source/components/toaster/react/locale.ts +6 -0
  386. package/source/components/toaster/react/props.ts +15 -0
  387. package/source/components/toaster/react/useToasts.ts +11 -0
  388. package/source/components/toaster/styles.css +282 -0
  389. package/source/components/tooltip/README.md +43 -0
  390. package/source/components/tooltip/core/index.ts +4 -0
  391. package/source/components/tooltip/core/types.ts +4 -0
  392. package/source/components/tooltip/core/visibility.ts +34 -0
  393. package/source/components/tooltip/index.ts +3 -0
  394. package/source/components/tooltip/passport.json +170 -0
  395. package/source/components/tooltip/react/Tooltip.tsx +196 -0
  396. package/source/components/tooltip/react/props.ts +4 -0
  397. package/source/components/tooltip/styles.css +71 -0
  398. package/source/fallback/index.tsx +11 -0
  399. package/source/globalStyle.ts +74 -0
  400. package/source/hooks/SelectionHooks/type.ts +4 -0
  401. package/source/hooks/SelectionHooks/useClickOutside.ts +22 -0
  402. package/source/hooks/SelectionHooks/useMultiSelectState.ts +64 -0
  403. package/source/hooks/SelectionHooks/useSelectData.ts +58 -0
  404. package/source/hooks/SelectionHooks/useSelectState.ts +36 -0
  405. package/source/icon/Icon.tsx +102 -0
  406. package/source/icon/iconPaths.ts +206 -0
  407. package/source/legacy-components/bargraph/index.tsx +95 -0
  408. package/source/legacy-components/bargraph/type.ts +12 -0
  409. package/source/legacy-components/breadcrumb/index.tsx +66 -0
  410. package/source/legacy-components/breadcrumb/types.ts +10 -0
  411. package/source/legacy-components/button/index.tsx +42 -0
  412. package/source/legacy-components/card/index.tsx +31 -0
  413. package/source/legacy-components/checkbox/index.tsx +25 -0
  414. package/source/legacy-components/contextmenu/ContextMenu.tsx +87 -0
  415. package/source/legacy-components/contextmenu/ContextMenuItem.tsx +30 -0
  416. package/source/legacy-components/contextmenu/index.ts +2 -0
  417. package/source/legacy-components/contextmenu/types.ts +19 -0
  418. package/source/legacy-components/darkmode/index.tsx +55 -0
  419. package/source/legacy-components/datagrid/context/GridContext.tsx +215 -0
  420. package/source/legacy-components/datagrid/createTemplate.tsx +82 -0
  421. package/source/legacy-components/datagrid/hooks/index.ts +6 -0
  422. package/source/legacy-components/datagrid/hooks/useColumns.ts +33 -0
  423. package/source/legacy-components/datagrid/hooks/useDataSource.ts +54 -0
  424. package/source/legacy-components/datagrid/hooks/useFiltering.ts +169 -0
  425. package/source/legacy-components/datagrid/hooks/usePagination.ts +112 -0
  426. package/source/legacy-components/datagrid/hooks/useRowSelection.ts +48 -0
  427. package/source/legacy-components/datagrid/hooks/useSearch.ts +90 -0
  428. package/source/legacy-components/datagrid/index.tsx +28 -0
  429. package/source/legacy-components/datagrid/layout/FilterPopup.tsx +92 -0
  430. package/source/legacy-components/datagrid/layout/GridBody.tsx +184 -0
  431. package/source/legacy-components/datagrid/layout/GridPagination.tsx +119 -0
  432. package/source/legacy-components/datagrid/layout/GridToolbar.tsx +109 -0
  433. package/source/legacy-components/datagrid/layout/index.tsx +68 -0
  434. package/source/legacy-components/datagrid/type.ts +198 -0
  435. package/source/legacy-components/datepicker/index.tsx +365 -0
  436. package/source/legacy-components/datepicker/types.ts +12 -0
  437. package/source/legacy-components/dialog/index.tsx +44 -0
  438. package/source/legacy-components/dialog/types.ts +12 -0
  439. package/source/legacy-components/formrenderer/componentHandles/CheckBoxHandles.tsx +80 -0
  440. package/source/legacy-components/formrenderer/componentHandles/DatePickerHandles.tsx +93 -0
  441. package/source/legacy-components/formrenderer/componentHandles/InputHandles.tsx +106 -0
  442. package/source/legacy-components/formrenderer/componentHandles/MultiHandles.tsx +93 -0
  443. package/source/legacy-components/formrenderer/componentHandles/SelectHandles.tsx +95 -0
  444. package/source/legacy-components/formrenderer/helperFunctions.ts +72 -0
  445. package/source/legacy-components/formrenderer/index.tsx +93 -0
  446. package/source/legacy-components/formrenderer/types.ts +127 -0
  447. package/source/legacy-components/input/index.tsx +142 -0
  448. package/source/legacy-components/input/types.ts +10 -0
  449. package/source/legacy-components/materialInput/index.tsx +138 -0
  450. package/source/legacy-components/materialInput/types.ts +16 -0
  451. package/source/legacy-components/modal/index.tsx +152 -0
  452. package/source/legacy-components/modal/types.ts +19 -0
  453. package/source/legacy-components/multiselect/PortalDropDown.tsx +44 -0
  454. package/source/legacy-components/multiselect/index.tsx +269 -0
  455. package/source/legacy-components/multiselect/types.ts +26 -0
  456. package/source/legacy-components/navbar/AuthSection.tsx +98 -0
  457. package/source/legacy-components/navbar/MobileToggle.tsx +31 -0
  458. package/source/legacy-components/navbar/NavItemComponent.tsx +119 -0
  459. package/source/legacy-components/navbar/SearchBar.tsx +55 -0
  460. package/source/legacy-components/navbar/helperFunctions.ts +27 -0
  461. package/source/legacy-components/navbar/index.tsx +156 -0
  462. package/source/legacy-components/navbar/types.ts +69 -0
  463. package/source/legacy-components/select/PortalDropDown.tsx +59 -0
  464. package/source/legacy-components/select/index.tsx +249 -0
  465. package/source/legacy-components/select/types.ts +29 -0
  466. package/source/legacy-components/sidebar/components/MenuItem.tsx +101 -0
  467. package/source/legacy-components/sidebar/components/MenuSection.tsx +34 -0
  468. package/source/legacy-components/sidebar/components/SidebarFooter.tsx +50 -0
  469. package/source/legacy-components/sidebar/components/SidebarLogo.tsx +24 -0
  470. package/source/legacy-components/sidebar/components/SidebarMenu.tsx +29 -0
  471. package/source/legacy-components/sidebar/components/UserProfile.tsx +31 -0
  472. package/source/legacy-components/sidebar/hooks/useSidebarState.ts +41 -0
  473. package/source/legacy-components/sidebar/index.tsx +77 -0
  474. package/source/legacy-components/sidebar/type.ts +42 -0
  475. package/source/legacy-components/spinner/Stroke.tsx +89 -0
  476. package/source/legacy-components/spinner/index.tsx +54 -0
  477. package/source/legacy-components/spinner/types.ts +9 -0
  478. package/source/legacy-components/tabs/index.tsx +71 -0
  479. package/source/legacy-components/tabs/types.ts +16 -0
  480. package/source/legacy-components/textarea/index.tsx +123 -0
  481. package/source/legacy-components/textarea/types.ts +15 -0
  482. package/source/legacy-components/toast/ToastComponent.tsx +101 -0
  483. package/source/legacy-components/toast/ToastIcon.tsx +61 -0
  484. package/source/legacy-components/toast/index.tsx +42 -0
  485. package/source/legacy-components/toast/toastStore.ts +42 -0
  486. package/source/legacy-components/toast/types.ts +18 -0
  487. package/source/legacy-components/toast/useToast.ts +12 -0
  488. package/source/legacy-components/uploader/ProgressAnimation.tsx +50 -0
  489. package/source/legacy-components/uploader/UploadedFilePreview.tsx +130 -0
  490. package/source/legacy-components/uploader/index.tsx +311 -0
  491. package/source/legacy-components/uploader/types.ts +30 -0
  492. package/source/legacy-components/uploader/uploaderIcon.tsx +72 -0
  493. package/source/legacy-components/uploader/uploaderService.ts +134 -0
  494. package/source/legacy-components/useUploader/useUploader.tsx +310 -0
  495. package/source/legacy-components/usepaginateddata/usePaginatedData.ts +174 -0
  496. package/source/theme.ts +40 -0
  497. package/source/utils.ts +10 -0
  498. package/tools/env.cjs +61 -0
  499. package/tools/passport/cli.cjs +79 -0
  500. package/tools/passport/extract.cjs +493 -0
  501. package/tools/passport/index.cjs +185 -0
  502. package/tools/passport/merge.cjs +131 -0
  503. package/tools/passport/policy.cjs +65 -0
  504. package/tools/passport/validate.cjs +277 -0
  505. package/tools/ts-require.cjs +79 -0
@@ -0,0 +1,107 @@
1
+ /*
2
+ * The DataGrid's WebMCP tool.
3
+ *
4
+ * All of the mechanism lives in `shared/core/agent/webmcp`. What belongs here
5
+ * is only what is true of a grid: the tool's name, how to describe this grid
6
+ * to an agent in words, and which numbers a successful call should report.
7
+ *
8
+ * Framework-free, like the rest of `agent/` — no React import, so a host can
9
+ * register the tool from an effect, a router, or not at all.
10
+ */
11
+
12
+ import {
13
+ registerAgentTool,
14
+ type ModelContext,
15
+ type RegistrationResult,
16
+ type ToolCallLog,
17
+ } from "../../shared/core/agent/webmcp";
18
+ import type { GridAgent } from "./engine";
19
+
20
+ /*
21
+ * Re-exported so a host that only imports from `data-grid` has every type that
22
+ * appears in this module's options and results.
23
+ */
24
+ export type {
25
+ ModelContext,
26
+ RegistrationResult,
27
+ ToolCallLog,
28
+ ToolResultPayload,
29
+ } from "../../shared/core/agent/webmcp";
30
+
31
+ export const GRID_TOOL_NAME = "operate_grid";
32
+
33
+ export interface RegisterGridToolOptions {
34
+ /** Override the tool name when a page carries more than one grid. */
35
+ name?: string;
36
+ /** Observe every call, for a UI log or a test. */
37
+ onCall?: (entry: ToolCallLog) => void;
38
+ /** Where to register. Defaults to `document.modelContext`. */
39
+ modelContext?: ModelContext;
40
+ /** How many operations an agent may send in one call. Default 8. */
41
+ maxIntents?: number;
42
+ }
43
+
44
+ /**
45
+ * How the grid introduces itself to an agent.
46
+ *
47
+ * Built from the live contract rather than written once, so a grid with
48
+ * different columns advertises different columns. Policy-restricted fields are
49
+ * absent from the generated schema entirely, so they are not listed here
50
+ * either — an agent should not be told about a column it cannot address.
51
+ */
52
+ function describeGrid(agent: GridAgent<unknown>): string {
53
+ const contract = agent.contract();
54
+ const columns = contract.columns
55
+ .filter((column) => column.filterable || column.sortable)
56
+ .map((column) => column.id)
57
+ .join(", ");
58
+
59
+ return [
60
+ "Filter, sort, search, paginate, select rows in, or export the data grid on this page.",
61
+ `Columns: ${columns}.`,
62
+ `Operations: ${contract.operations.join(", ")}.`,
63
+ 'Values may be written as a person would — "1 lakh", "20%", "last month" — and are',
64
+ "converted exactly. Every call is validated before anything happens; an invalid request",
65
+ "is refused with a reason rather than approximated.",
66
+ ].join(" ");
67
+ }
68
+
69
+ /**
70
+ * Registers `operate_grid` against the browser's WebMCP surface.
71
+ *
72
+ * Returns rather than throws when WebMCP is absent, because that is the normal
73
+ * case in most browsers today: the caller shows the grid regardless and the
74
+ * agent affordance is simply not there.
75
+ *
76
+ * ```ts
77
+ * const agent = createGridAgent({ api: apiRef.current, options });
78
+ * const result = registerGridTool(agent);
79
+ * if (!result.registered) console.info(result.reason);
80
+ * ```
81
+ *
82
+ * One tool per page: WebMCP throws on a duplicate name, and React's
83
+ * StrictMode runs effects twice in development, so guard the call with a ref
84
+ * or register outside the render path.
85
+ */
86
+ export function registerGridTool(
87
+ agent: GridAgent<unknown>,
88
+ options: RegisterGridToolOptions = {},
89
+ ): RegistrationResult {
90
+ return registerAgentTool(agent, {
91
+ name: options.name ?? GRID_TOOL_NAME,
92
+ describe: describeGrid,
93
+ maxIntents: options.maxIntents,
94
+ intentsDescription:
95
+ "Operations to apply in order. Several filters on different columns combine with AND.",
96
+ summarise: (current) => {
97
+ const contract = current.contract();
98
+ return {
99
+ rowsShowing: contract.stats.filteredRows,
100
+ rowsTotal: contract.stats.totalRows,
101
+ canUndo: contract.state.canUndo,
102
+ };
103
+ },
104
+ onCall: options.onCall,
105
+ modelContext: options.modelContext,
106
+ });
107
+ }
@@ -0,0 +1,21 @@
1
+ import type { ColumnDef } from "./types";
2
+
3
+ type Base<T, V> = Omit<ColumnDef<T, V>, "id" | "field" | "accessor">;
4
+
5
+ /**
6
+ * Typed column builders: `value` in `cell`, `format`, `validate` and friends is
7
+ * inferred from the field or accessor.
8
+ */
9
+ export function createColumnHelper<T>() {
10
+ return {
11
+ field<K extends Extract<keyof T, string>>(field: K, def: Base<T, T[K]> & { id?: string } = {}): ColumnDef<T> {
12
+ return { ...def, field } as unknown as ColumnDef<T>;
13
+ },
14
+ accessor<V>(id: string, accessor: (row: T) => V, def: Base<T, V> = {}): ColumnDef<T> {
15
+ return { ...def, id, accessor } as unknown as ColumnDef<T>;
16
+ },
17
+ display(id: string, def: Base<T, undefined>): ColumnDef<T> {
18
+ return { ...def, id } as unknown as ColumnDef<T>;
19
+ },
20
+ };
21
+ }
@@ -0,0 +1,288 @@
1
+ import type {
2
+ ColumnDef,
3
+ ColumnLayout,
4
+ ColumnLayoutItem,
5
+ ColumnPinningState,
6
+ GridState,
7
+ PinSide,
8
+ ResolvedColumn,
9
+ } from "./types";
10
+
11
+ export const SELECTION_COLUMN_ID = "__select__";
12
+
13
+ const DEFAULT_WIDTH = 160;
14
+ const DEFAULT_MIN_WIDTH = 60;
15
+ const DEFAULT_MAX_WIDTH = 1200;
16
+
17
+ type LayoutState = Pick<
18
+ GridState,
19
+ "columnOrder" | "columnVisibility" | "columnSizing" | "columnPinning"
20
+ >;
21
+
22
+ export function getColumnId<T>(def: ColumnDef<T>): string {
23
+ const id = def.id ?? def.field;
24
+ if (!id) {
25
+ throw new Error("[DataGrid] Every column needs an `id` or a `field`.");
26
+ }
27
+ return id;
28
+ }
29
+
30
+ function humanize(id: string): string {
31
+ const spaced = id
32
+ .replace(/[_-]+/g, " ")
33
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
34
+ .trim();
35
+ return spaced.charAt(0).toUpperCase() + spaced.slice(1);
36
+ }
37
+
38
+ const clamp = (value: number, min: number, max: number) =>
39
+ Math.min(max, Math.max(min, value));
40
+
41
+ export function resolveColumns<T>(
42
+ defs: readonly ColumnDef<T>[],
43
+ ): ResolvedColumn<T>[] {
44
+ const seen = new Set<string>();
45
+
46
+ return defs.map((def) => {
47
+ const id = getColumnId(def);
48
+ if (seen.has(id)) {
49
+ throw new Error(`[DataGrid] Duplicate column id "${id}".`);
50
+ }
51
+ seen.add(id);
52
+
53
+ const { field, accessor } = def;
54
+ const hasValue = accessor !== undefined || field !== undefined;
55
+ const getValue: (row: T) => unknown = accessor
56
+ ? (row) => accessor(row)
57
+ : field
58
+ ? (row) => row[field]
59
+ : () => undefined;
60
+ const type = def.type ?? "string";
61
+ const minWidth = def.minWidth ?? DEFAULT_MIN_WIDTH;
62
+ const maxWidth = def.maxWidth ?? DEFAULT_MAX_WIDTH;
63
+
64
+ return {
65
+ id,
66
+ def,
67
+ header: def.header ?? humanize(id),
68
+ type,
69
+ hasValue,
70
+ getValue,
71
+ width: clamp(def.width ?? DEFAULT_WIDTH, minWidth, maxWidth),
72
+ minWidth,
73
+ maxWidth,
74
+ align:
75
+ def.align ??
76
+ (type === "number" ? "end" : type === "boolean" ? "center" : "start"),
77
+ sortable: hasValue && def.sortable !== false,
78
+ filterable: hasValue && def.filterable !== false,
79
+ resizable: def.resizable !== false,
80
+ hideable: def.hideable !== false,
81
+ reorderable: def.reorderable !== false,
82
+ pinnable: def.pinnable !== false,
83
+ searchable: hasValue && def.searchable !== false,
84
+ exportable:
85
+ (hasValue || def.exportValue !== undefined) && def.exportable !== false,
86
+ internal: false,
87
+ };
88
+ });
89
+ }
90
+
91
+ export function createSelectionColumn<T>(): ResolvedColumn<T> {
92
+ return {
93
+ id: SELECTION_COLUMN_ID,
94
+ def: { id: SELECTION_COLUMN_ID },
95
+ header: "",
96
+ type: "boolean",
97
+ hasValue: false,
98
+ getValue: () => undefined,
99
+ width: 44,
100
+ minWidth: 44,
101
+ maxWidth: 44,
102
+ align: "center",
103
+ sortable: false,
104
+ filterable: false,
105
+ resizable: false,
106
+ hideable: false,
107
+ reorderable: false,
108
+ pinnable: false,
109
+ searchable: false,
110
+ exportable: false,
111
+ internal: true,
112
+ };
113
+ }
114
+
115
+ /** Columns in user order: ids from `order` first, the rest in definition order. */
116
+ export function orderColumns<T>(
117
+ columns: readonly ResolvedColumn<T>[],
118
+ order: readonly string[],
119
+ ): ResolvedColumn<T>[] {
120
+ if (order.length === 0) return [...columns];
121
+ const byId = new Map(columns.map((c) => [c.id, c]));
122
+ const result: ResolvedColumn<T>[] = [];
123
+ const used = new Set<string>();
124
+ for (const id of order) {
125
+ const column = byId.get(id);
126
+ if (column && !used.has(id)) {
127
+ result.push(column);
128
+ used.add(id);
129
+ }
130
+ }
131
+ for (const column of columns) {
132
+ if (!used.has(column.id)) result.push(column);
133
+ }
134
+ return result;
135
+ }
136
+
137
+ export function getColumnWidth<T>(
138
+ column: ResolvedColumn<T>,
139
+ sizing: Record<string, number>,
140
+ ): number {
141
+ const width = sizing[column.id];
142
+ return width === undefined
143
+ ? column.width
144
+ : clamp(width, column.minWidth, column.maxWidth);
145
+ }
146
+
147
+ export function computeLayout<T>(
148
+ columns: readonly ResolvedColumn<T>[],
149
+ state: LayoutState,
150
+ leading: readonly ResolvedColumn<T>[] = [],
151
+ ): ColumnLayout<T> {
152
+ const byId = new Map(columns.map((c) => [c.id, c]));
153
+ const isVisible = (c: ResolvedColumn<T> | undefined): c is ResolvedColumn<T> =>
154
+ c !== undefined && state.columnVisibility[c.id] !== false;
155
+
156
+ const pinnedIds = new Set([
157
+ ...state.columnPinning.left,
158
+ ...state.columnPinning.right,
159
+ ]);
160
+ const leftColumns = [
161
+ ...leading,
162
+ ...state.columnPinning.left.map((id) => byId.get(id)).filter(isVisible),
163
+ ];
164
+ const rightColumns = state.columnPinning.right
165
+ .map((id) => byId.get(id))
166
+ .filter(isVisible);
167
+ const centerColumns = orderColumns(columns, state.columnOrder).filter(
168
+ (c) => !pinnedIds.has(c.id) && isVisible(c),
169
+ );
170
+
171
+ let visibleIndex = 0;
172
+ const build = (
173
+ section: ResolvedColumn<T>[],
174
+ pinned: PinSide | false,
175
+ ): [ColumnLayoutItem<T>[], number] => {
176
+ let offset = 0;
177
+ const items = section.map((column) => {
178
+ const width = getColumnWidth(column, state.columnSizing);
179
+ const index = visibleIndex++;
180
+ const style: Record<string, string> = { width: `var(--dg-c${index}-w)` };
181
+ if (pinned === "left") style.insetInlineStart = `var(--dg-c${index}-o)`;
182
+ if (pinned === "right") style.insetInlineEnd = `var(--dg-c${index}-o)`;
183
+ const item = { column, width, pinned, offset, visibleIndex: index, style, pinEdge: false };
184
+ offset += width;
185
+ return item;
186
+ });
187
+ return [items, offset];
188
+ };
189
+
190
+ const [left, leftWidth] = build(leftColumns, "left");
191
+ const [center, centerWidth] = build(centerColumns, false);
192
+ const [right, rightWidth] = build(rightColumns, "right");
193
+ const lastLeft = left.at(-1);
194
+ if (lastLeft) lastLeft.pinEdge = true;
195
+ if (right[0]) right[0].pinEdge = true;
196
+
197
+ return {
198
+ columns: [...left, ...center, ...right],
199
+ left,
200
+ center,
201
+ right,
202
+ leftWidth,
203
+ centerWidth,
204
+ rightWidth,
205
+ totalWidth: leftWidth + centerWidth + rightWidth,
206
+ };
207
+ }
208
+
209
+ /**
210
+ * CSS custom properties that size and position every column. Resizing only
211
+ * rewrites these variables, so cells never re-render during a drag.
212
+ */
213
+ export function getLayoutVars<T>(
214
+ layout: ColumnLayout<T>,
215
+ overrides?: Record<string, number>,
216
+ ): Record<string, string> {
217
+ const widthOf = (item: ColumnLayoutItem<T>) =>
218
+ overrides?.[item.column.id] ?? item.width;
219
+ const vars: Record<string, string> = {};
220
+ let total = 0;
221
+
222
+ let leftOffset = 0;
223
+ for (const item of layout.left) {
224
+ const width = widthOf(item);
225
+ vars[`--dg-c${item.visibleIndex}-w`] = `${width}px`;
226
+ vars[`--dg-c${item.visibleIndex}-o`] = `${leftOffset}px`;
227
+ leftOffset += width;
228
+ }
229
+ for (const item of layout.center) {
230
+ vars[`--dg-c${item.visibleIndex}-w`] = `${widthOf(item)}px`;
231
+ total += widthOf(item);
232
+ }
233
+ let rightOffset = 0;
234
+ for (let i = layout.right.length - 1; i >= 0; i--) {
235
+ const item = layout.right[i];
236
+ const width = widthOf(item);
237
+ vars[`--dg-c${item.visibleIndex}-w`] = `${width}px`;
238
+ vars[`--dg-c${item.visibleIndex}-o`] = `${rightOffset}px`;
239
+ rightOffset += width;
240
+ }
241
+
242
+ total += leftOffset + rightOffset;
243
+ vars["--dg-total-width"] = `${total}px`;
244
+ return vars;
245
+ }
246
+
247
+ export function pinColumn(
248
+ pinning: ColumnPinningState,
249
+ columnId: string,
250
+ side: PinSide | false,
251
+ ): ColumnPinningState {
252
+ const left = pinning.left.filter((id) => id !== columnId);
253
+ const right = pinning.right.filter((id) => id !== columnId);
254
+ if (side === "left") left.push(columnId);
255
+ if (side === "right") right.unshift(columnId);
256
+ return { left, right };
257
+ }
258
+
259
+ /** Moves a column next to another one, adopting the target's pin section. */
260
+ export function moveColumn<T>(
261
+ columns: readonly ResolvedColumn<T>[],
262
+ state: Pick<GridState, "columnOrder" | "columnPinning">,
263
+ columnId: string,
264
+ targetId: string,
265
+ placement: "before" | "after",
266
+ ): Pick<GridState, "columnOrder" | "columnPinning"> {
267
+ if (columnId === targetId) return state;
268
+
269
+ const insert = (ids: string[]) => {
270
+ const next = ids.filter((id) => id !== columnId);
271
+ const targetIndex = next.indexOf(targetId);
272
+ if (targetIndex === -1) return next;
273
+ next.splice(placement === "before" ? targetIndex : targetIndex + 1, 0, columnId);
274
+ return next;
275
+ };
276
+
277
+ const { left, right } = state.columnPinning;
278
+ const stripped = pinColumn(state.columnPinning, columnId, false);
279
+
280
+ if (left.includes(targetId)) {
281
+ return { ...state, columnPinning: { ...stripped, left: insert(stripped.left) } };
282
+ }
283
+ if (right.includes(targetId)) {
284
+ return { ...state, columnPinning: { ...stripped, right: insert(stripped.right) } };
285
+ }
286
+ const order = orderColumns(columns, state.columnOrder).map((c) => c.id);
287
+ return { columnOrder: insert(order), columnPinning: stripped };
288
+ }
@@ -0,0 +1,237 @@
1
+ import type {
2
+ ColumnFilter,
3
+ FilterOperator,
4
+ FilterValue,
5
+ GridRow,
6
+ ResolvedColumn,
7
+ } from "./types";
8
+ import {
9
+ formatCellValue,
10
+ isEmptyValue,
11
+ startOfDay,
12
+ startOfNextDay,
13
+ toTime,
14
+ type Formatters,
15
+ } from "./values";
16
+
17
+ const STRING_OPERATORS: FilterOperator[] = [
18
+ "contains",
19
+ "notContains",
20
+ "equals",
21
+ "notEquals",
22
+ "startsWith",
23
+ "endsWith",
24
+ "isEmpty",
25
+ "isNotEmpty",
26
+ ];
27
+ const NUMBER_OPERATORS: FilterOperator[] = [
28
+ "equals",
29
+ "notEquals",
30
+ "gt",
31
+ "gte",
32
+ "lt",
33
+ "lte",
34
+ "between",
35
+ "isEmpty",
36
+ "isNotEmpty",
37
+ ];
38
+ const DATE_OPERATORS: FilterOperator[] = [
39
+ "equals",
40
+ "before",
41
+ "after",
42
+ "between",
43
+ "isEmpty",
44
+ "isNotEmpty",
45
+ ];
46
+
47
+ export function getFilterOperators<T>(column: ResolvedColumn<T>): FilterOperator[] {
48
+ if (column.def.options) return ["in", "isEmpty", "isNotEmpty"];
49
+ switch (column.type) {
50
+ case "number":
51
+ return NUMBER_OPERATORS;
52
+ case "date":
53
+ return DATE_OPERATORS;
54
+ case "boolean":
55
+ return ["equals"];
56
+ default:
57
+ return STRING_OPERATORS;
58
+ }
59
+ }
60
+
61
+ const hasValue = (value: FilterValue | undefined) =>
62
+ value !== undefined &&
63
+ value !== null &&
64
+ value !== "" &&
65
+ !(Array.isArray(value) && value.length === 0);
66
+
67
+ /** A filter with no usable value (e.g. an empty text box) matches everything. */
68
+ export function isFilterActive(filter: ColumnFilter): boolean {
69
+ switch (filter.operator) {
70
+ case "isEmpty":
71
+ case "isNotEmpty":
72
+ return true;
73
+ case "between":
74
+ return hasValue(filter.value) || hasValue(filter.value2);
75
+ default:
76
+ return hasValue(filter.value);
77
+ }
78
+ }
79
+
80
+ const toNumber = (value: unknown): number | null => {
81
+ if (value === null || value === undefined || value === "") return null;
82
+ const n = typeof value === "number" ? value : Number(value);
83
+ return Number.isNaN(n) ? null : n;
84
+ };
85
+
86
+ type Predicate<T> = (row: T) => boolean;
87
+
88
+ export function compileFilter<T>(
89
+ column: ResolvedColumn<T>,
90
+ filter: ColumnFilter,
91
+ formatters: Formatters,
92
+ ): Predicate<T> | null {
93
+ if (!isFilterActive(filter)) return null;
94
+
95
+ const { getValue } = column;
96
+ const { filterFn } = column.def;
97
+ if (filterFn) return (row) => filterFn(getValue(row), filter, row);
98
+
99
+ const { operator } = filter;
100
+ if (operator === "isEmpty") return (row) => isEmptyValue(getValue(row));
101
+ if (operator === "isNotEmpty") return (row) => !isEmptyValue(getValue(row));
102
+
103
+ if (operator === "in") {
104
+ const values = Array.isArray(filter.value) ? filter.value : [filter.value];
105
+ const allowed = new Set(values.map(String));
106
+ return (row) => allowed.has(String(getValue(row)));
107
+ }
108
+
109
+ switch (column.type) {
110
+ case "number": {
111
+ const a = toNumber(filter.value);
112
+ const b = toNumber(filter.value2);
113
+ return (row) => {
114
+ const v = toNumber(getValue(row));
115
+ if (v === null) return operator === "notEquals";
116
+ switch (operator) {
117
+ case "equals": return a === null || v === a;
118
+ case "notEquals": return a === null || v !== a;
119
+ case "gt": return a === null || v > a;
120
+ case "gte": return a === null || v >= a;
121
+ case "lt": return a === null || v < a;
122
+ case "lte": return a === null || v <= a;
123
+ case "between": return (a === null || v >= a) && (b === null || v <= b);
124
+ default: return true;
125
+ }
126
+ };
127
+ }
128
+
129
+ case "date": {
130
+ const a = toTime(filter.value);
131
+ const b = toTime(filter.value2);
132
+ const aStart = a === null ? null : startOfDay(a);
133
+ const aEnd = a === null ? null : startOfNextDay(a);
134
+ const bEnd = b === null ? null : startOfNextDay(b);
135
+ return (row) => {
136
+ const t = toTime(getValue(row));
137
+ if (t === null) return false;
138
+ switch (operator) {
139
+ case "equals": return aStart === null || (t >= aStart && t < aEnd!);
140
+ case "before": return aStart === null || t < aStart;
141
+ case "after": return aEnd === null || t >= aEnd;
142
+ case "between":
143
+ return (aStart === null || t >= aStart) && (bEnd === null || t < bEnd);
144
+ default: return true;
145
+ }
146
+ };
147
+ }
148
+
149
+ case "boolean": {
150
+ const wanted = filter.value === true || filter.value === "true";
151
+ return (row) => Boolean(getValue(row)) === wanted;
152
+ }
153
+
154
+ default: {
155
+ const needle = String(filter.value).toLocaleLowerCase();
156
+ const text = (row: T) =>
157
+ formatCellValue(column, getValue(row), row, formatters).toLocaleLowerCase();
158
+ switch (operator) {
159
+ case "contains": return (row) => text(row).includes(needle);
160
+ case "notContains": return (row) => !text(row).includes(needle);
161
+ case "equals": return (row) => text(row) === needle;
162
+ case "notEquals": return (row) => text(row) !== needle;
163
+ case "startsWith": return (row) => text(row).startsWith(needle);
164
+ case "endsWith": return (row) => text(row).endsWith(needle);
165
+ default: return null;
166
+ }
167
+ }
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Search text per row, built once per (columns, formatters) and reused across
173
+ * keystrokes. Rows are rebuilt when `data` changes, which invalidates the cache.
174
+ */
175
+ const searchCache = new WeakMap<
176
+ readonly ResolvedColumn<unknown>[],
177
+ { formatters: Formatters; text: WeakMap<object, string> }
178
+ >();
179
+
180
+ function getSearchText<T>(
181
+ row: GridRow<T>,
182
+ columns: readonly ResolvedColumn<T>[],
183
+ formatters: Formatters,
184
+ ): string {
185
+ const key = columns as readonly ResolvedColumn<unknown>[];
186
+ let entry = searchCache.get(key);
187
+ if (!entry || entry.formatters !== formatters) {
188
+ entry = { formatters, text: new WeakMap() };
189
+ searchCache.set(key, entry);
190
+ }
191
+ let text = entry.text.get(row);
192
+ if (text === undefined) {
193
+ const parts: string[] = [];
194
+ for (const column of columns) {
195
+ if (!column.searchable) continue;
196
+ const value = column.getValue(row.original);
197
+ parts.push(formatCellValue(column, value, row.original, formatters));
198
+ }
199
+ text = parts.join("").toLocaleLowerCase();
200
+ entry.text.set(row, text);
201
+ }
202
+ return text;
203
+ }
204
+
205
+ /** Applies column filters (AND) and the global search (every term must match). */
206
+ export function filterRows<T>(
207
+ rows: GridRow<T>[],
208
+ columns: readonly ResolvedColumn<T>[],
209
+ filters: readonly ColumnFilter[],
210
+ globalFilter: string,
211
+ formatters: Formatters,
212
+ ): GridRow<T>[] {
213
+ const byId = new Map(columns.map((c) => [c.id, c]));
214
+ const predicates: Predicate<T>[] = [];
215
+ for (const filter of filters) {
216
+ const column = byId.get(filter.columnId);
217
+ const predicate = column && compileFilter(column, filter, formatters);
218
+ if (predicate) predicates.push(predicate);
219
+ }
220
+ const terms = globalFilter.trim().toLocaleLowerCase().split(/\s+/).filter(Boolean);
221
+
222
+ // Returning the same array keeps downstream memoization intact.
223
+ if (predicates.length === 0 && terms.length === 0) return rows;
224
+
225
+ return rows.filter((row) => {
226
+ for (const predicate of predicates) {
227
+ if (!predicate(row.original)) return false;
228
+ }
229
+ if (terms.length > 0) {
230
+ const text = getSearchText(row, columns, formatters);
231
+ for (const term of terms) {
232
+ if (!text.includes(term)) return false;
233
+ }
234
+ }
235
+ return true;
236
+ });
237
+ }