@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,98 @@
1
+ import type { ResolvedColumn } from "./types";
2
+
3
+ const DATE_ONLY = /^(\d{4})-(\d{2})-(\d{2})$/;
4
+
5
+ export interface Formatters {
6
+ date: Intl.DateTimeFormat;
7
+ yes: string;
8
+ no: string;
9
+ }
10
+
11
+ export function createFormatters(
12
+ locale?: string,
13
+ labels: { yes: string; no: string } = { yes: "Yes", no: "No" },
14
+ ): Formatters {
15
+ return {
16
+ date: new Intl.DateTimeFormat(locale, { dateStyle: "medium" }),
17
+ ...labels,
18
+ };
19
+ }
20
+
21
+ /** Milliseconds since epoch, or null. Date-only strings are read as local dates. */
22
+ export function toTime(value: unknown): number | null {
23
+ if (value instanceof Date) {
24
+ const time = value.getTime();
25
+ return Number.isNaN(time) ? null : time;
26
+ }
27
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
28
+ if (typeof value === "string" && value !== "") {
29
+ const match = DATE_ONLY.exec(value);
30
+ const time = match
31
+ ? new Date(+match[1], +match[2] - 1, +match[3]).getTime()
32
+ : Date.parse(value);
33
+ return Number.isNaN(time) ? null : time;
34
+ }
35
+ return null;
36
+ }
37
+
38
+ export function startOfNextDay(time: number): number {
39
+ const date = new Date(time);
40
+ date.setHours(0, 0, 0, 0);
41
+ date.setDate(date.getDate() + 1);
42
+ return date.getTime();
43
+ }
44
+
45
+ export function startOfDay(time: number): number {
46
+ const date = new Date(time);
47
+ date.setHours(0, 0, 0, 0);
48
+ return date.getTime();
49
+ }
50
+
51
+ export function isEmptyValue(value: unknown): boolean {
52
+ return (
53
+ value === null ||
54
+ value === undefined ||
55
+ (typeof value === "string" && value.trim() === "") ||
56
+ (typeof value === "number" && Number.isNaN(value)) ||
57
+ (Array.isArray(value) && value.length === 0)
58
+ );
59
+ }
60
+
61
+ /** `YYYY-MM-DD` in local time, for `<input type="date">`. */
62
+ export function toDateInputValue(value: unknown): string {
63
+ const time = toTime(value);
64
+ if (time === null) return "";
65
+ const date = new Date(time);
66
+ const pad = (n: number) => String(n).padStart(2, "0");
67
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
68
+ }
69
+
70
+ /** Display text for a cell; also used by search, CSV, PDF and clipboard copy. */
71
+ export function formatCellValue<T>(
72
+ column: ResolvedColumn<T>,
73
+ value: unknown,
74
+ row: T,
75
+ formatters: Formatters,
76
+ ): string {
77
+ if (column.def.format) return column.def.format(value, row);
78
+ if (value === null || value === undefined) return "";
79
+
80
+ const { options } = column.def;
81
+ if (options) {
82
+ const option = options.find((o) => o.value === value);
83
+ if (option) return option.label;
84
+ }
85
+
86
+ switch (column.type) {
87
+ case "date": {
88
+ const time = toTime(value);
89
+ return time === null ? String(value) : formatters.date.format(time);
90
+ }
91
+ case "boolean":
92
+ return value ? formatters.yes : formatters.no;
93
+ default:
94
+ if (Array.isArray(value)) return value.join(", ");
95
+ if (value instanceof Date) return formatters.date.format(value);
96
+ return String(value);
97
+ }
98
+ }
@@ -0,0 +1,85 @@
1
+ import type { ColumnLayout } from "./types";
2
+
3
+ export interface Viewport {
4
+ scrollTop: number;
5
+ scrollLeft: number;
6
+ width: number;
7
+ height: number;
8
+ }
9
+
10
+ /** Half-open range: `start` inclusive, `end` exclusive. */
11
+ export interface Range {
12
+ start: number;
13
+ end: number;
14
+ }
15
+
16
+ export interface VisibleRange {
17
+ rows: Range;
18
+ columns: Range;
19
+ }
20
+
21
+ export function getRowRange(
22
+ viewport: Viewport,
23
+ rowCount: number,
24
+ rowHeight: number,
25
+ headerHeight: number,
26
+ overscan = 6,
27
+ ): Range {
28
+ if (rowCount === 0) return { start: 0, end: 0 };
29
+ const bodyHeight = Math.max(0, viewport.height - headerHeight);
30
+ const first = Math.floor(viewport.scrollTop / rowHeight);
31
+ const last = Math.ceil((viewport.scrollTop + bodyHeight) / rowHeight);
32
+ return {
33
+ start: Math.max(0, Math.min(rowCount, first) - overscan),
34
+ end: Math.min(rowCount, last + overscan),
35
+ };
36
+ }
37
+
38
+ /** Range of center (unpinned) columns intersecting the viewport. */
39
+ export function getColumnRange<T>(
40
+ layout: ColumnLayout<T>,
41
+ viewport: Viewport,
42
+ overscan = 2,
43
+ ): Range {
44
+ const { center } = layout;
45
+ const count = center.length;
46
+ // Width is unknown before the first measurement (and during SSR): render everything.
47
+ if (count === 0 || viewport.width === 0) return { start: 0, end: count };
48
+
49
+ // Browsers report negative scrollLeft in RTL.
50
+ const windowStart = Math.abs(viewport.scrollLeft);
51
+ const windowEnd =
52
+ windowStart + Math.max(0, viewport.width - layout.leftWidth - layout.rightWidth);
53
+
54
+ // First column whose right edge is past windowStart.
55
+ let lo = 0;
56
+ let hi = count;
57
+ while (lo < hi) {
58
+ const mid = (lo + hi) >> 1;
59
+ if (center[mid].offset + center[mid].width <= windowStart) lo = mid + 1;
60
+ else hi = mid;
61
+ }
62
+ const start = lo;
63
+
64
+ // First column starting at or past windowEnd.
65
+ hi = count;
66
+ while (lo < hi) {
67
+ const mid = (lo + hi) >> 1;
68
+ if (center[mid].offset < windowEnd) lo = mid + 1;
69
+ else hi = mid;
70
+ }
71
+
72
+ return {
73
+ start: Math.max(0, start - overscan),
74
+ end: Math.min(count, Math.max(lo, start + 1) + overscan),
75
+ };
76
+ }
77
+
78
+ export function visibleRangeEqual(a: VisibleRange, b: VisibleRange): boolean {
79
+ return (
80
+ a.rows.start === b.rows.start &&
81
+ a.rows.end === b.rows.end &&
82
+ a.columns.start === b.columns.start &&
83
+ a.columns.end === b.columns.end
84
+ );
85
+ }
@@ -0,0 +1,32 @@
1
+ import type { ExportTable } from "./table";
2
+
3
+ /** Spreadsheet apps execute cells starting with these characters as formulas. */
4
+ const FORMULA_PREFIX = /^[=+\-@\t\r]/;
5
+
6
+ function escapeField(text: string, isText: boolean, delimiter: string): string {
7
+ const safe = isText && FORMULA_PREFIX.test(text) ? `'${text}` : text;
8
+ const needsQuotes =
9
+ safe.includes(delimiter) || safe.includes('"') || safe.includes("\n") || safe.includes("\r");
10
+ return needsQuotes ? `"${safe.replace(/"/g, '""')}"` : safe;
11
+ }
12
+
13
+ function serialize(table: ExportTable, delimiter: string): string {
14
+ const lines = [table.columns.map((c) => escapeField(c.header, true, delimiter)).join(delimiter)];
15
+ table.text.forEach((row, r) => {
16
+ lines.push(
17
+ row
18
+ .map((text, c) => escapeField(text, typeof table.values[r][c] === "string", delimiter))
19
+ .join(delimiter),
20
+ );
21
+ });
22
+ return lines.join("\r\n");
23
+ }
24
+
25
+ export const toCsv = (table: ExportTable) => serialize(table, ",");
26
+
27
+ export const toTsv = (table: ExportTable) => serialize(table, "\t");
28
+
29
+ export function createCsvBlob(table: ExportTable): Blob {
30
+ // The BOM makes Excel read the file as UTF-8.
31
+ return new Blob(["", toCsv(table)], { type: "text/csv;charset=utf-8" });
32
+ }
@@ -0,0 +1,12 @@
1
+ export function downloadBlob(blob: Blob, fileName: string): void {
2
+ const url = URL.createObjectURL(blob);
3
+ const link = document.createElement("a");
4
+ link.href = url;
5
+ link.download = fileName;
6
+ link.rel = "noopener";
7
+ link.style.display = "none";
8
+ document.body.append(link);
9
+ link.click();
10
+ link.remove();
11
+ setTimeout(() => URL.revokeObjectURL(url), 1000);
12
+ }
@@ -0,0 +1,139 @@
1
+ /*
2
+ * Metrics for the two standard-14 fonts the PDF exporter uses.
3
+ *
4
+ * Helvetica and Helvetica-Bold are built into every conforming PDF viewer, so
5
+ * nothing is embedded and the export stays dependency-free. The trade is
6
+ * WinAnsi (CP1252) coverage — Latin-1 plus a few typographic characters. Text
7
+ * outside it is replaced with "?" rather than silently dropped, so a wrong
8
+ * glyph is visible instead of a missing column.
9
+ *
10
+ * Widths are advance widths in 1/1000 em, indexed from character code 32. A
11
+ * zero means the code is unused in WinAnsi; `encode` never produces one.
12
+ */
13
+
14
+ // prettier-ignore
15
+ const HELVETICA = [
16
+ 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278,
17
+ 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556,
18
+ 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778,
19
+ 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556,
20
+ 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556,
21
+ 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 0,
22
+ 556, 0, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0,
23
+ 0, 222, 222, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 0, 500, 667,
24
+ 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333,
25
+ 400, 584, 333, 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611,
26
+ 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278,
27
+ 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611,
28
+ 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278,
29
+ 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500,
30
+ ];
31
+
32
+ // prettier-ignore
33
+ const HELVETICA_BOLD = [
34
+ 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278,
35
+ 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611,
36
+ 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778,
37
+ 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556,
38
+ 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611,
39
+ 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 0,
40
+ 556, 0, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0,
41
+ 0, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 0, 500, 667,
42
+ 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333,
43
+ 400, 584, 333, 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611,
44
+ 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278,
45
+ 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611,
46
+ 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278,
47
+ 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556,
48
+ ];
49
+
50
+ export type PdfFont = "regular" | "bold";
51
+
52
+ /** Code points WinAnsi keeps in 0x80-0x9F, where Latin-1 has control codes. */
53
+ const HIGH = new Map<number, number>([
54
+ [0x20ac, 0x80], [0x201a, 0x82], [0x0192, 0x83], [0x201e, 0x84],
55
+ [0x2026, 0x85], [0x2020, 0x86], [0x2021, 0x87], [0x02c6, 0x88],
56
+ [0x2030, 0x89], [0x0160, 0x8a], [0x2039, 0x8b], [0x0152, 0x8c],
57
+ [0x017d, 0x8e], [0x2018, 0x91], [0x2019, 0x92], [0x201c, 0x93],
58
+ [0x201d, 0x94], [0x2022, 0x95], [0x2013, 0x96], [0x2014, 0x97],
59
+ [0x02dc, 0x98], [0x2122, 0x99], [0x0161, 0x9a], [0x203a, 0x9b],
60
+ [0x0153, 0x9c], [0x017e, 0x9e], [0x0178, 0x9f],
61
+ ]);
62
+
63
+ const QUESTION = 0x3f;
64
+ const ELLIPSIS = 0x85;
65
+ const SPACE = 0x20;
66
+
67
+ /**
68
+ * Encodes text as WinAnsi bytes. Characters the encoding cannot carry become
69
+ * "?", and control characters become spaces so a stray tab or newline in a cell
70
+ * cannot break the line layout.
71
+ */
72
+ export function encode(text: string): number[] {
73
+ const bytes: number[] = [];
74
+
75
+ for (const char of text) {
76
+ const code = char.codePointAt(0) ?? QUESTION;
77
+
78
+ if (code === 0x09 || code === 0x0a || code === 0x0d) bytes.push(SPACE);
79
+ else if (code >= 0x20 && code <= 0x7e) bytes.push(code);
80
+ else if (code >= 0xa0 && code <= 0xff) bytes.push(code);
81
+ else bytes.push(HIGH.get(code) ?? QUESTION);
82
+ }
83
+
84
+ return bytes;
85
+ }
86
+
87
+ /** Width of already-encoded bytes, in points, at `size`. */
88
+ export function widthOf(bytes: readonly number[], font: PdfFont, size: number): number {
89
+ const widths = font === "bold" ? HELVETICA_BOLD : HELVETICA;
90
+ let total = 0;
91
+
92
+ for (const byte of bytes) total += widths[byte - 32] ?? 0;
93
+
94
+ return (total * size) / 1000;
95
+ }
96
+
97
+ /**
98
+ * Trims bytes to `max` points, ending in an ellipsis when anything was cut.
99
+ * Returns an empty run when not even the ellipsis fits.
100
+ */
101
+ export function fit(
102
+ bytes: readonly number[],
103
+ font: PdfFont,
104
+ size: number,
105
+ max: number,
106
+ ): number[] {
107
+ if (widthOf(bytes, font, size) <= max) return [...bytes];
108
+
109
+ const room = max - widthOf([ELLIPSIS], font, size);
110
+ if (room < 0) return [];
111
+
112
+ const widths = font === "bold" ? HELVETICA_BOLD : HELVETICA;
113
+ let used = 0;
114
+ let end = 0;
115
+
116
+ while (end < bytes.length) {
117
+ const next = used + ((widths[bytes[end] - 32] ?? 0) * size) / 1000;
118
+ if (next > room) break;
119
+ used = next;
120
+ end++;
121
+ }
122
+
123
+ return [...bytes.slice(0, end), ELLIPSIS];
124
+ }
125
+
126
+ /**
127
+ * A PDF literal string body, without the surrounding parentheses. Only the
128
+ * three delimiters need escaping; every other byte is legal as-is.
129
+ */
130
+ export function literal(bytes: readonly number[]): string {
131
+ let out = "";
132
+
133
+ for (const byte of bytes) {
134
+ if (byte === 0x28 || byte === 0x29 || byte === 0x5c) out += "\\";
135
+ out += String.fromCharCode(byte);
136
+ }
137
+
138
+ return out;
139
+ }
@@ -0,0 +1,113 @@
1
+ /*
2
+ * Minimal PDF 1.7 writer: a header, numbered objects, a cross-reference table
3
+ * of byte offsets and a trailer. Enough for a paginated table, and nothing
4
+ * more.
5
+ *
6
+ * Everything that is not stream data is built as a string whose character
7
+ * codes are all <= 255, so one character is one byte and offsets stay exact.
8
+ * Using UTF-8 here would silently shift every offset past the first accented
9
+ * character and produce a file that some viewers repair and others reject.
10
+ */
11
+
12
+ /**
13
+ * A body such as `<</Type/Catalog …>>`, or a stream. A stream's `/Length` is
14
+ * measured by the writer; `extra` carries anything else the dictionary needs,
15
+ * such as `/Filter/FlateDecode`.
16
+ */
17
+ export type PdfObject = string | { extra?: string; stream: string | Uint8Array };
18
+
19
+ const HEADER = "%PDF-1.7\n%âãÏÓ\n";
20
+
21
+ function latin1(text: string): Uint8Array {
22
+ const bytes = new Uint8Array(text.length);
23
+ for (let i = 0; i < text.length; i++) bytes[i] = text.charCodeAt(i) & 0xff;
24
+ return bytes;
25
+ }
26
+
27
+ /**
28
+ * Deflates with the platform's own compressor, which emits exactly the zlib
29
+ * wrapper `/FlateDecode` expects. Returns null where CompressionStream is
30
+ * missing, and the caller writes the stream uncompressed instead.
31
+ */
32
+ export async function deflate(data: Uint8Array): Promise<Uint8Array | null> {
33
+ if (typeof CompressionStream === "undefined") return null;
34
+
35
+ const stream = new Blob([data as BlobPart]).stream().pipeThrough(new CompressionStream("deflate"));
36
+ return new Uint8Array(await new Response(stream).arrayBuffer());
37
+ }
38
+
39
+ /**
40
+ * A PDF text string, for values like /Title that a viewer shows as chrome.
41
+ *
42
+ * These are NOT the page's WinAnsi strings: a bare literal is read as
43
+ * PDFDocEncoding, which disagrees with WinAnsi across 0x80-0x9F — an em dash
44
+ * would arrive as "S-caron". UTF-16BE behind a byte-order mark is unambiguous.
45
+ */
46
+ export function textString(value: string): string {
47
+ let hex = "FEFF";
48
+ for (let i = 0; i < value.length; i++) {
49
+ hex += value.charCodeAt(i).toString(16).padStart(4, "0").toUpperCase();
50
+ }
51
+ return `<${hex}>`;
52
+ }
53
+
54
+ function pad(value: number, length: number): string {
55
+ return String(value).padStart(length, "0");
56
+ }
57
+
58
+ /** A PDF date string, as `/CreationDate` wants it. */
59
+ export function pdfDate(at: Date): string {
60
+ return (
61
+ `D:${at.getUTCFullYear()}${pad(at.getUTCMonth() + 1, 2)}${pad(at.getUTCDate(), 2)}` +
62
+ `${pad(at.getUTCHours(), 2)}${pad(at.getUTCMinutes(), 2)}${pad(at.getUTCSeconds(), 2)}` +
63
+ `+00'00'`
64
+ );
65
+ }
66
+
67
+ /**
68
+ * Assembles the file. Objects are numbered by position, so `objects[0]` is
69
+ * object 1 — the same numbers the bodies reference.
70
+ */
71
+ export function buildPdf(
72
+ objects: readonly PdfObject[],
73
+ trailer: { root: number; info: number },
74
+ ): Blob {
75
+ const parts: Uint8Array[] = [latin1(HEADER)];
76
+ const offsets: number[] = [];
77
+ let offset = HEADER.length;
78
+
79
+ const push = (chunk: Uint8Array) => {
80
+ parts.push(chunk);
81
+ offset += chunk.length;
82
+ };
83
+
84
+ objects.forEach((object, index) => {
85
+ offsets.push(offset);
86
+ push(latin1(`${index + 1} 0 obj\n`));
87
+
88
+ if (typeof object === "string") {
89
+ push(latin1(`${object}\n`));
90
+ } else {
91
+ const data = typeof object.stream === "string" ? latin1(object.stream) : object.stream;
92
+ push(latin1(`<</Length ${data.length}${object.extra ?? ""}>>\nstream\n`));
93
+ push(data);
94
+ push(latin1("\nendstream\n"));
95
+ }
96
+
97
+ push(latin1("endobj\n"));
98
+ });
99
+
100
+ const start = offset;
101
+ // Entries are exactly 20 bytes each; the table is unusable otherwise.
102
+ let xref = `xref\n0 ${objects.length + 1}\n0000000000 65535 f \n`;
103
+ for (const at of offsets) xref += `${pad(at, 10)} 00000 n \n`;
104
+
105
+ push(
106
+ latin1(
107
+ `${xref}trailer\n<</Size ${objects.length + 1}/Root ${trailer.root} 0 R` +
108
+ `/Info ${trailer.info} 0 R>>\nstartxref\n${start}\n%%EOF\n`,
109
+ ),
110
+ );
111
+
112
+ return new Blob(parts as BlobPart[], { type: "application/pdf" });
113
+ }