@sincpro/web-ui 0.0.0-stage → 0.1.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 (354) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +157 -2
  3. package/dist/components/assist/AssistMark.d.ts +64 -0
  4. package/dist/components/assist/AssistMark.js +108 -0
  5. package/dist/components/assist/AssistPending.d.ts +24 -0
  6. package/dist/components/assist/AssistPending.js +26 -0
  7. package/dist/components/assist/AssistSuggestion.d.ts +42 -0
  8. package/dist/components/assist/AssistSuggestion.js +55 -0
  9. package/dist/components/assist/ChangeReview.d.ts +56 -0
  10. package/dist/components/assist/ChangeReview.js +121 -0
  11. package/dist/components/assist/assist.d.ts +77 -0
  12. package/dist/components/assist/assist.js +87 -0
  13. package/dist/components/assist/index.d.ts +5 -0
  14. package/dist/components/assist/index.js +7 -0
  15. package/dist/components/chatter/Chatter.d.ts +161 -0
  16. package/dist/components/chatter/Chatter.js +232 -0
  17. package/dist/components/chatter/Messages.d.ts +66 -0
  18. package/dist/components/chatter/Messages.js +43 -0
  19. package/dist/components/chatter/Timeline.d.ts +21 -0
  20. package/dist/components/chatter/Timeline.js +30 -0
  21. package/dist/components/chatter/index.d.ts +3 -0
  22. package/dist/components/chatter/index.js +4 -0
  23. package/dist/components/form/Form.d.ts +52 -0
  24. package/dist/components/form/Form.js +49 -0
  25. package/dist/components/form/Sheet.d.ts +43 -0
  26. package/dist/components/form/Sheet.js +83 -0
  27. package/dist/components/form/index.d.ts +2 -0
  28. package/dist/components/form/index.js +4 -0
  29. package/dist/components/frame/Chart.d.ts +13 -0
  30. package/dist/components/frame/Chart.js +24 -0
  31. package/dist/components/frame/FrameView.d.ts +33 -0
  32. package/dist/components/frame/FrameView.js +125 -0
  33. package/dist/components/frame/index.d.ts +3 -0
  34. package/dist/components/frame/index.js +3 -0
  35. package/dist/components/frame/model.d.ts +43 -0
  36. package/dist/components/frame/model.js +101 -0
  37. package/dist/components/index.d.ts +10 -0
  38. package/dist/components/index.js +11 -0
  39. package/dist/components/lines/LineItems.d.ts +74 -0
  40. package/dist/components/lines/LineItems.js +229 -0
  41. package/dist/components/lines/index.d.ts +1 -0
  42. package/dist/components/lines/index.js +2 -0
  43. package/dist/components/lines/lines.d.ts +23 -0
  44. package/dist/components/lines/lines.js +26 -0
  45. package/dist/components/listing/ColumnsMenu.d.ts +20 -0
  46. package/dist/components/listing/ColumnsMenu.js +46 -0
  47. package/dist/components/listing/GroupingLevels.d.ts +35 -0
  48. package/dist/components/listing/GroupingLevels.js +45 -0
  49. package/dist/components/listing/Listing.d.ts +27 -0
  50. package/dist/components/listing/Listing.js +86 -0
  51. package/dist/components/listing/ListingBar.d.ts +73 -0
  52. package/dist/components/listing/ListingBar.js +105 -0
  53. package/dist/components/listing/Pagination.d.ts +36 -0
  54. package/dist/components/listing/Pagination.js +69 -0
  55. package/dist/components/listing/RecordCard.d.ts +33 -0
  56. package/dist/components/listing/RecordCard.js +22 -0
  57. package/dist/components/listing/RecordLink.d.ts +7 -0
  58. package/dist/components/listing/RecordLink.js +22 -0
  59. package/dist/components/listing/Row.d.ts +106 -0
  60. package/dist/components/listing/Row.js +122 -0
  61. package/dist/components/listing/SortMenu.d.ts +62 -0
  62. package/dist/components/listing/SortMenu.js +105 -0
  63. package/dist/components/listing/ViewSwitcher.d.ts +24 -0
  64. package/dist/components/listing/ViewSwitcher.js +16 -0
  65. package/dist/components/listing/columns.d.ts +47 -0
  66. package/dist/components/listing/columns.js +72 -0
  67. package/dist/components/listing/grouping.d.ts +35 -0
  68. package/dist/components/listing/grouping.js +47 -0
  69. package/dist/components/listing/index.d.ts +17 -0
  70. package/dist/components/listing/index.js +20 -0
  71. package/dist/components/listing/modelColumns.d.ts +50 -0
  72. package/dist/components/listing/modelColumns.js +103 -0
  73. package/dist/components/listing/pages.d.ts +78 -0
  74. package/dist/components/listing/pages.js +135 -0
  75. package/dist/components/listing/selection.d.ts +21 -0
  76. package/dist/components/listing/selection.js +43 -0
  77. package/dist/components/listing/set.d.ts +48 -0
  78. package/dist/components/listing/set.js +24 -0
  79. package/dist/components/listing/tree.d.ts +28 -0
  80. package/dist/components/listing/tree.js +23 -0
  81. package/dist/components/navigation/CommandPalette.d.ts +40 -0
  82. package/dist/components/navigation/CommandPalette.js +114 -0
  83. package/dist/components/navigation/NavigationTree.d.ts +31 -0
  84. package/dist/components/navigation/NavigationTree.js +79 -0
  85. package/dist/components/navigation/commands.d.ts +30 -0
  86. package/dist/components/navigation/commands.js +30 -0
  87. package/dist/components/navigation/index.d.ts +3 -0
  88. package/dist/components/navigation/index.js +4 -0
  89. package/dist/components/record/Breadcrumb.d.ts +42 -0
  90. package/dist/components/record/Breadcrumb.js +98 -0
  91. package/dist/components/record/DirtyActions.d.ts +26 -0
  92. package/dist/components/record/DirtyActions.js +22 -0
  93. package/dist/components/record/Pager.d.ts +18 -0
  94. package/dist/components/record/Pager.js +33 -0
  95. package/dist/components/record/RecordHeader.d.ts +71 -0
  96. package/dist/components/record/RecordHeader.js +72 -0
  97. package/dist/components/record/RecordSkeleton.d.ts +3 -0
  98. package/dist/components/record/RecordSkeleton.js +21 -0
  99. package/dist/components/record/SmartButtons.d.ts +35 -0
  100. package/dist/components/record/SmartButtons.js +38 -0
  101. package/dist/components/record/StatusBar.d.ts +51 -0
  102. package/dist/components/record/StatusBar.js +168 -0
  103. package/dist/components/record/ThumbBar.d.ts +36 -0
  104. package/dist/components/record/ThumbBar.js +86 -0
  105. package/dist/components/record/index.d.ts +6 -0
  106. package/dist/components/record/index.js +8 -0
  107. package/dist/components/search/CriteriaBuilder.d.ts +58 -0
  108. package/dist/components/search/CriteriaBuilder.js +278 -0
  109. package/dist/components/search/CriteriaChips.d.ts +22 -0
  110. package/dist/components/search/CriteriaChips.js +64 -0
  111. package/dist/components/search/FilterBuilder.d.ts +142 -0
  112. package/dist/components/search/FilterBuilder.js +421 -0
  113. package/dist/components/search/JoinWord.d.ts +8 -0
  114. package/dist/components/search/JoinWord.js +47 -0
  115. package/dist/components/search/JsonEditor.d.ts +19 -0
  116. package/dist/components/search/JsonEditor.js +78 -0
  117. package/dist/components/search/SearchBar.d.ts +78 -0
  118. package/dist/components/search/SearchBar.js +387 -0
  119. package/dist/components/search/criteria.d.ts +116 -0
  120. package/dist/components/search/criteria.js +159 -0
  121. package/dist/components/search/datePeriods.d.ts +122 -0
  122. package/dist/components/search/datePeriods.js +134 -0
  123. package/dist/components/search/dateRanges.d.ts +54 -0
  124. package/dist/components/search/dateRanges.js +89 -0
  125. package/dist/components/search/index.d.ts +9 -0
  126. package/dist/components/search/index.js +20 -0
  127. package/dist/components/search/model.d.ts +54 -0
  128. package/dist/components/search/model.js +37 -0
  129. package/dist/components/search/query.d.ts +166 -0
  130. package/dist/components/search/query.js +436 -0
  131. package/dist/components/shell/AppFrame.d.ts +14 -0
  132. package/dist/components/shell/AppFrame.js +80 -0
  133. package/dist/components/shell/TopBar.d.ts +73 -0
  134. package/dist/components/shell/TopBar.js +54 -0
  135. package/dist/components/shell/headerSlot.d.ts +17 -0
  136. package/dist/components/shell/headerSlot.js +21 -0
  137. package/dist/components/shell/index.d.ts +2 -0
  138. package/dist/components/shell/index.js +3 -0
  139. package/dist/foundations/aria.d.ts +14 -0
  140. package/dist/foundations/aria.js +18 -0
  141. package/dist/foundations/calendar.d.ts +28 -0
  142. package/dist/foundations/calendar.js +183 -0
  143. package/dist/foundations/copy.d.ts +619 -0
  144. package/dist/foundations/copy.es.d.ts +2 -0
  145. package/dist/foundations/copy.es.js +377 -0
  146. package/dist/foundations/copy.js +472 -0
  147. package/dist/foundations/density.d.ts +16 -0
  148. package/dist/foundations/density.js +21 -0
  149. package/dist/foundations/grouping.d.ts +281 -0
  150. package/dist/foundations/grouping.js +0 -0
  151. package/dist/foundations/index.d.ts +14 -0
  152. package/dist/foundations/index.js +30 -0
  153. package/dist/foundations/layout.d.ts +9 -0
  154. package/dist/foundations/layout.js +9 -0
  155. package/dist/foundations/pivot.d.ts +222 -0
  156. package/dist/foundations/pivot.js +198 -0
  157. package/dist/foundations/pivotSheet.d.ts +61 -0
  158. package/dist/foundations/pivotSheet.js +0 -0
  159. package/dist/foundations/slots.d.ts +67 -0
  160. package/dist/foundations/slots.js +63 -0
  161. package/dist/foundations/sticky.d.ts +53 -0
  162. package/dist/foundations/sticky.js +150 -0
  163. package/dist/foundations/surface.d.ts +9 -0
  164. package/dist/foundations/surface.js +26 -0
  165. package/dist/foundations/theme.d.ts +42 -0
  166. package/dist/foundations/theme.js +88 -0
  167. package/dist/foundations/types.d.ts +23 -0
  168. package/dist/foundations/types.js +50 -0
  169. package/dist/foundations/variants.d.ts +19 -0
  170. package/dist/foundations/variants.js +48 -0
  171. package/dist/foundations/xlsx.d.ts +86 -0
  172. package/dist/foundations/xlsx.js +0 -0
  173. package/dist/index.d.ts +19 -0
  174. package/dist/index.js +19 -0
  175. package/dist/primitives/block/Block.d.ts +66 -0
  176. package/dist/primitives/block/Block.js +34 -0
  177. package/dist/primitives/block/Line.d.ts +18 -0
  178. package/dist/primitives/block/Line.js +45 -0
  179. package/dist/primitives/block/SectionGrid.d.ts +30 -0
  180. package/dist/primitives/block/SectionGrid.js +29 -0
  181. package/dist/primitives/block/Steps.d.ts +76 -0
  182. package/dist/primitives/block/Steps.js +43 -0
  183. package/dist/primitives/block/index.d.ts +4 -0
  184. package/dist/primitives/block/index.js +7 -0
  185. package/dist/primitives/button/Button.d.ts +137 -0
  186. package/dist/primitives/button/Button.js +234 -0
  187. package/dist/primitives/button/index.d.ts +1 -0
  188. package/dist/primitives/button/index.js +2 -0
  189. package/dist/primitives/cell/CellStack.d.ts +47 -0
  190. package/dist/primitives/cell/CellStack.js +33 -0
  191. package/dist/primitives/cell/index.d.ts +1 -0
  192. package/dist/primitives/cell/index.js +3 -0
  193. package/dist/primitives/choice/ComboBox.d.ts +16 -0
  194. package/dist/primitives/choice/ComboBox.js +52 -0
  195. package/dist/primitives/choice/RadioGroup.d.ts +18 -0
  196. package/dist/primitives/choice/RadioGroup.js +50 -0
  197. package/dist/primitives/choice/SearchField.d.ts +24 -0
  198. package/dist/primitives/choice/SearchField.js +27 -0
  199. package/dist/primitives/choice/SegmentedControl.d.ts +16 -0
  200. package/dist/primitives/choice/SegmentedControl.js +69 -0
  201. package/dist/primitives/choice/Slider.d.ts +16 -0
  202. package/dist/primitives/choice/Slider.js +46 -0
  203. package/dist/primitives/choice/Switch.d.ts +14 -0
  204. package/dist/primitives/choice/Switch.js +65 -0
  205. package/dist/primitives/choice/ThemeSwitcher.d.ts +10 -0
  206. package/dist/primitives/choice/ThemeSwitcher.js +25 -0
  207. package/dist/primitives/choice/index.d.ts +8 -0
  208. package/dist/primitives/choice/index.js +11 -0
  209. package/dist/primitives/choice/options.d.ts +28 -0
  210. package/dist/primitives/choice/options.js +6 -0
  211. package/dist/primitives/date/Calendar.d.ts +31 -0
  212. package/dist/primitives/date/Calendar.js +110 -0
  213. package/dist/primitives/date/DatePicker.d.ts +34 -0
  214. package/dist/primitives/date/DatePicker.js +99 -0
  215. package/dist/primitives/date/index.d.ts +2 -0
  216. package/dist/primitives/date/index.js +4 -0
  217. package/dist/primitives/dialog/Dialog.d.ts +118 -0
  218. package/dist/primitives/dialog/Dialog.js +121 -0
  219. package/dist/primitives/dialog/index.d.ts +1 -0
  220. package/dist/primitives/dialog/index.js +2 -0
  221. package/dist/primitives/disclosure/Disclosure.d.ts +36 -0
  222. package/dist/primitives/disclosure/Disclosure.js +52 -0
  223. package/dist/primitives/disclosure/index.d.ts +1 -0
  224. package/dist/primitives/disclosure/index.js +2 -0
  225. package/dist/primitives/field/Checks.d.ts +57 -0
  226. package/dist/primitives/field/Checks.js +72 -0
  227. package/dist/primitives/field/DropZone.d.ts +42 -0
  228. package/dist/primitives/field/DropZone.js +52 -0
  229. package/dist/primitives/field/Field.d.ts +166 -0
  230. package/dist/primitives/field/Field.js +240 -0
  231. package/dist/primitives/field/Suggest.d.ts +48 -0
  232. package/dist/primitives/field/Suggest.js +43 -0
  233. package/dist/primitives/field/aria.d.ts +61 -0
  234. package/dist/primitives/field/aria.js +70 -0
  235. package/dist/primitives/field/context.d.ts +30 -0
  236. package/dist/primitives/field/context.js +13 -0
  237. package/dist/primitives/field/index.d.ts +7 -0
  238. package/dist/primitives/field/index.js +11 -0
  239. package/dist/primitives/field/layout.d.ts +24 -0
  240. package/dist/primitives/field/layout.js +10 -0
  241. package/dist/primitives/field/mode.d.ts +9 -0
  242. package/dist/primitives/field/mode.js +13 -0
  243. package/dist/primitives/hint/Hint.d.ts +31 -0
  244. package/dist/primitives/hint/Hint.js +42 -0
  245. package/dist/primitives/hint/index.d.ts +1 -0
  246. package/dist/primitives/hint/index.js +1 -0
  247. package/dist/primitives/index.d.ts +19 -0
  248. package/dist/primitives/index.js +20 -0
  249. package/dist/primitives/menu/Menu.d.ts +100 -0
  250. package/dist/primitives/menu/Menu.js +59 -0
  251. package/dist/primitives/menu/index.d.ts +1 -0
  252. package/dist/primitives/menu/index.js +2 -0
  253. package/dist/primitives/notice/Callout.d.ts +49 -0
  254. package/dist/primitives/notice/Callout.js +28 -0
  255. package/dist/primitives/notice/Notice.d.ts +45 -0
  256. package/dist/primitives/notice/Notice.js +61 -0
  257. package/dist/primitives/notice/Toast.d.ts +55 -0
  258. package/dist/primitives/notice/Toast.js +142 -0
  259. package/dist/primitives/notice/index.d.ts +3 -0
  260. package/dist/primitives/notice/index.js +5 -0
  261. package/dist/primitives/overlay/Popover.d.ts +6 -0
  262. package/dist/primitives/overlay/Popover.js +27 -0
  263. package/dist/primitives/overlay/PopoverTrigger.d.ts +55 -0
  264. package/dist/primitives/overlay/PopoverTrigger.js +38 -0
  265. package/dist/primitives/overlay/Tooltip.d.ts +38 -0
  266. package/dist/primitives/overlay/Tooltip.js +74 -0
  267. package/dist/primitives/overlay/index.d.ts +3 -0
  268. package/dist/primitives/overlay/index.js +5 -0
  269. package/dist/primitives/picker/Picker.d.ts +48 -0
  270. package/dist/primitives/picker/Picker.js +150 -0
  271. package/dist/primitives/picker/index.d.ts +1 -0
  272. package/dist/primitives/picker/index.js +2 -0
  273. package/dist/primitives/surface/Peek.d.ts +60 -0
  274. package/dist/primitives/surface/Peek.js +71 -0
  275. package/dist/primitives/surface/index.d.ts +1 -0
  276. package/dist/primitives/surface/index.js +2 -0
  277. package/dist/primitives/table/CellEditor.d.ts +14 -0
  278. package/dist/primitives/table/CellEditor.js +83 -0
  279. package/dist/primitives/table/DataTable.d.ts +135 -0
  280. package/dist/primitives/table/DataTable.js +244 -0
  281. package/dist/primitives/table/EditableTable.d.ts +96 -0
  282. package/dist/primitives/table/EditableTable.js +423 -0
  283. package/dist/primitives/table/PivotTable.d.ts +14 -0
  284. package/dist/primitives/table/PivotTable.js +0 -0
  285. package/dist/primitives/table/ReportTable.d.ts +38 -0
  286. package/dist/primitives/table/ReportTable.js +106 -0
  287. package/dist/primitives/table/RowActions.d.ts +16 -0
  288. package/dist/primitives/table/RowActions.js +28 -0
  289. package/dist/primitives/table/SheetTable.d.ts +70 -0
  290. package/dist/primitives/table/SheetTable.js +197 -0
  291. package/dist/primitives/table/Table.d.ts +106 -0
  292. package/dist/primitives/table/Table.js +116 -0
  293. package/dist/primitives/table/index.d.ts +7 -0
  294. package/dist/primitives/table/index.js +9 -0
  295. package/dist/primitives/tabs/Tabs.d.ts +91 -0
  296. package/dist/primitives/tabs/Tabs.js +56 -0
  297. package/dist/primitives/tabs/index.d.ts +1 -0
  298. package/dist/primitives/tabs/index.js +1 -0
  299. package/dist/primitives/tag/Tag.d.ts +36 -0
  300. package/dist/primitives/tag/Tag.js +68 -0
  301. package/dist/primitives/tag/Tags.d.ts +57 -0
  302. package/dist/primitives/tag/Tags.js +104 -0
  303. package/dist/primitives/tag/TagsField.d.ts +32 -0
  304. package/dist/primitives/tag/TagsField.js +182 -0
  305. package/dist/primitives/tag/choices.d.ts +38 -0
  306. package/dist/primitives/tag/choices.js +26 -0
  307. package/dist/primitives/tag/index.d.ts +4 -0
  308. package/dist/primitives/tag/index.js +8 -0
  309. package/dist/primitives/toolbar/Toolbar.d.ts +13 -0
  310. package/dist/primitives/toolbar/Toolbar.js +36 -0
  311. package/dist/primitives/toolbar/index.d.ts +1 -0
  312. package/dist/primitives/toolbar/index.js +2 -0
  313. package/dist/primitives/value/Copyable.d.ts +37 -0
  314. package/dist/primitives/value/Copyable.js +50 -0
  315. package/dist/primitives/value/Fecha.d.ts +12 -0
  316. package/dist/primitives/value/Fecha.js +80 -0
  317. package/dist/primitives/value/Meter.d.ts +29 -0
  318. package/dist/primitives/value/Meter.js +46 -0
  319. package/dist/primitives/value/Metric.d.ts +42 -0
  320. package/dist/primitives/value/Metric.js +38 -0
  321. package/dist/primitives/value/Person.d.ts +90 -0
  322. package/dist/primitives/value/Person.js +208 -0
  323. package/dist/primitives/value/Relation.d.ts +69 -0
  324. package/dist/primitives/value/Relation.js +57 -0
  325. package/dist/primitives/value/Totals.d.ts +26 -0
  326. package/dist/primitives/value/Totals.js +4 -0
  327. package/dist/primitives/value/Value.d.ts +77 -0
  328. package/dist/primitives/value/Value.js +119 -0
  329. package/dist/primitives/value/index.d.ts +8 -0
  330. package/dist/primitives/value/index.js +9 -0
  331. package/dist/tokens.css +1025 -0
  332. package/dist/views/index.d.ts +2 -0
  333. package/dist/views/index.js +3 -0
  334. package/dist/views/list/List.d.ts +113 -0
  335. package/dist/views/list/List.js +97 -0
  336. package/dist/views/list/ListView.d.ts +6 -0
  337. package/dist/views/list/ListView.js +269 -0
  338. package/dist/views/list/columns.d.ts +18 -0
  339. package/dist/views/list/columns.js +27 -0
  340. package/dist/views/list/derive.d.ts +76 -0
  341. package/dist/views/list/derive.js +181 -0
  342. package/dist/views/list/index.d.ts +2 -0
  343. package/dist/views/list/index.js +4 -0
  344. package/dist/views/list/presentations.d.ts +39 -0
  345. package/dist/views/list/presentations.js +103 -0
  346. package/dist/views/list/types.d.ts +272 -0
  347. package/dist/views/list/types.js +1 -0
  348. package/dist/views/list/useNarrowList.d.ts +17 -0
  349. package/dist/views/list/useNarrowList.js +32 -0
  350. package/dist/views/record/Record.d.ts +126 -0
  351. package/dist/views/record/Record.js +141 -0
  352. package/dist/views/record/index.d.ts +1 -0
  353. package/dist/views/record/index.js +2 -0
  354. package/package.json +109 -4
@@ -0,0 +1,70 @@
1
+ import type { Tone } from "../../foundations/types.js";
2
+ import { type ReactNode } from "react";
3
+ export interface SheetColumn {
4
+ id: string;
5
+ /** The name of the column, just as it came from the file. */
6
+ header: string;
7
+ /** The detected type, underneath the name. It is half the value of a glance:
8
+ * seeing that `importe` was read as text explains the rest of the screen. */
9
+ type?: string;
10
+ numeric?: boolean;
11
+ width?: number;
12
+ }
13
+ export declare function SheetTable({ columns, rows,
14
+ /** The value of a cell, by index. It is a function and not a prebuilt matrix
15
+ * so that the consumer can read from wherever they want without copying a
16
+ * million rows into another structure. */
17
+ value,
18
+ /** Which cells are painted and with what. `undefined` is unpainted, which is
19
+ * the normal case — a spreadsheet with everything colored highlights
20
+ * nothing. */
21
+ tone,
22
+ /** What the cell says on hover: «imputado por la mediana». */
23
+ note, height, rowLabel, band, onBandToggle, caption, onCommit, editable, }: {
24
+ columns: readonly SheetColumn[];
25
+ rows: number;
26
+ value: (row: number, column: SheetColumn, columnIndex: number) => string | number | null;
27
+ tone?: (row: number, column: SheetColumn, columnIndex: number) => Tone | undefined;
28
+ note?: (row: number, column: SheetColumn, columnIndex: number) => string | undefined;
29
+ /** Pixel height of the scroll box. `"auto"` grows with the rows so a
30
+ * twenty-row glance is not a window with its own scrollbar. */
31
+ height?: number | "auto";
32
+ rowLabel?: (row: number) => string;
33
+ /**
34
+ * Esta fila no es una fila: es la cabecera del montón que empieza acá.
35
+ *
36
+ * Agrupar sin perder la virtualización es esto — **una banda es una fila
37
+ * más, de otra clase**. La alternativa era una planilla por montón, y eso
38
+ * son N cuadrículas con N encabezados y N scrolls para un solo conjunto.
39
+ *
40
+ * `depth` es cuán adentro está el montón. La planilla no puede recibir un
41
+ * árbol —está virtualizada por índice, y un índice es una posición en una
42
+ * secuencia—, así que la jerarquía la dice la sangría de cada banda y no el
43
+ * anidamiento del marcado.
44
+ */
45
+ band?: (row: number) => {
46
+ field?: string;
47
+ label: string;
48
+ count: number;
49
+ open: boolean;
50
+ depth?: number;
51
+ /**
52
+ * Lo que el montón suma EN CADA COLUMNA, en la posición de esa columna.
53
+ *
54
+ * Una banda que pone su total en un rincón obliga a buscar a qué columna
55
+ * corresponde el número. Alineado bajo su columna no hay nada que buscar:
56
+ * la cuadrícula ya dice qué significa, que es para lo que existe una
57
+ * cuadrícula. `null` en una columna que no suma — que es la mayoría.
58
+ */
59
+ total?: (column: SheetColumn, columnIndex: number) => string | number | null;
60
+ } | undefined;
61
+ onBandToggle?: (row: number) => void;
62
+ caption?: ReactNode;
63
+ /** Present = the spreadsheet is editable. It receives the raw text just as it
64
+ * was typed; converting it to the column's type belongs to the domain, not
65
+ * here. */
66
+ onCommit?: (row: number, column: SheetColumn, columnIndex: number, next: string) => void;
67
+ /** Which cells are editable. Without this, all of them — but a computed column
68
+ * or an identifier is not touched. */
69
+ editable?: (row: number, column: SheetColumn, columnIndex: number) => boolean;
70
+ }): import("react").JSX.Element;
@@ -0,0 +1,197 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useUiCopy } from "../../foundations/copy.js";
4
+ import { stickyTop, useScrollBox } from "../../foundations/sticky.js";
5
+ import { Cell } from "../value/Value.js";
6
+ import { useVirtualizer } from "@tanstack/react-virtual";
7
+ import { ChevronRight } from "lucide-react";
8
+ import { useState } from "react";
9
+ const TONE = {
10
+ neutral: "bg-ink/6",
11
+ info: "bg-info/12",
12
+ good: "bg-good/12",
13
+ warn: "bg-warn/15",
14
+ bad: "bg-bad/12",
15
+ accent: "bg-accent/20",
16
+ };
17
+ const WIDTH = 168;
18
+ const HEIGHT = 28;
19
+ export function SheetTable({ columns, rows,
20
+ /** The value of a cell, by index. It is a function and not a prebuilt matrix
21
+ * so that the consumer can read from wherever they want without copying a
22
+ * million rows into another structure. */
23
+ value,
24
+ /** Which cells are painted and with what. `undefined` is unpainted, which is
25
+ * the normal case — a spreadsheet with everything colored highlights
26
+ * nothing. */
27
+ tone,
28
+ /** What the cell says on hover: «imputado por la mediana». */
29
+ note, height = 420, rowLabel, band, onBandToggle, caption, onCommit, editable, }) {
30
+ const copy = useUiCopy();
31
+ const labelOf = rowLabel ?? ((i) => (i + 1).toLocaleString(copy.locale));
32
+ /* `"auto"` es para un conjunto que ya vino CORTADO —una página de ochenta— y
33
+ deja de virtualizar de hecho: sin scroll propio, la ventana visible es la
34
+ caja entera y se dibujan todas las filas. Para los datos crudos —donde son
35
+ un millón— hay que declarar un alto, y ahí sí se dibujan las ~30 que se
36
+ ven. Cuándo la caja es un contenedor de scroll lo decide `useScrollBox`. */
37
+ const caja = useScrollBox(height === "auto" ? {} : { height });
38
+ const v = useVirtualizer({
39
+ count: rows,
40
+ getScrollElement: () => caja.ref.current,
41
+ estimateSize: () => HEIGHT,
42
+ overscan: 12,
43
+ });
44
+ const items = v.getVirtualItems();
45
+ const [active, setActive] = useState(null);
46
+ const [draft, setDraft] = useState(null);
47
+ const editing = draft !== null;
48
+ const isEditable = onCommit !== undefined;
49
+ function canEdit(r, c) {
50
+ if (!isEditable)
51
+ return false;
52
+ const col = columns[c];
53
+ if (col === undefined)
54
+ return false;
55
+ return editable === undefined || editable(r, col, c);
56
+ }
57
+ function goTo(r, c) {
58
+ const rr = Math.max(0, Math.min(rows - 1, r));
59
+ const cc = Math.max(0, Math.min(columns.length - 1, c));
60
+ setActive({ r: rr, c: cc });
61
+ setDraft(null);
62
+ v.scrollToIndex(rr);
63
+ }
64
+ function openCell(r, c, initial) {
65
+ if (!canEdit(r, c))
66
+ return;
67
+ const col = columns[c];
68
+ setActive({ r, c });
69
+ setDraft(initial ?? String(value(r, col, c) ?? ""));
70
+ }
71
+ function commit(dr, dc) {
72
+ if (active === null || draft === null)
73
+ return;
74
+ const col = columns[active.c];
75
+ if (col !== undefined)
76
+ onCommit?.(active.r, col, active.c, draft);
77
+ setDraft(null);
78
+ if (dr !== 0 || dc !== 0)
79
+ goTo(active.r + dr, active.c + dc);
80
+ }
81
+ /* All the keyboard handling in one place. Splitting it between the box and
82
+ each cell is how you end up with spreadsheets whose arrows sometimes move
83
+ and sometimes scroll. */
84
+ function onKey(e) {
85
+ if (active === null)
86
+ return;
87
+ const { r, c } = active;
88
+ if (editing) {
89
+ if (e.key === "Escape") {
90
+ e.preventDefault();
91
+ setDraft(null);
92
+ }
93
+ else if (e.key === "Enter") {
94
+ e.preventDefault();
95
+ commit(e.shiftKey ? -1 : 1, 0);
96
+ }
97
+ else if (e.key === "Tab") {
98
+ e.preventDefault();
99
+ commit(0, e.shiftKey ? -1 : 1);
100
+ }
101
+ return;
102
+ }
103
+ switch (e.key) {
104
+ case "ArrowDown":
105
+ e.preventDefault();
106
+ goTo(r + 1, c);
107
+ return;
108
+ case "ArrowUp":
109
+ e.preventDefault();
110
+ goTo(r - 1, c);
111
+ return;
112
+ case "ArrowRight":
113
+ case "Tab":
114
+ e.preventDefault();
115
+ goTo(r, c + (e.shiftKey && e.key === "Tab" ? -1 : 1));
116
+ return;
117
+ case "ArrowLeft":
118
+ e.preventDefault();
119
+ goTo(r, c - 1);
120
+ return;
121
+ case "Enter":
122
+ case "F2":
123
+ e.preventDefault();
124
+ openCell(r, c);
125
+ return;
126
+ case "Delete":
127
+ case "Backspace":
128
+ e.preventDefault();
129
+ if (canEdit(r, c)) {
130
+ const col = columns[c];
131
+ if (col !== undefined)
132
+ onCommit?.(r, col, c, "");
133
+ }
134
+ return;
135
+ default:
136
+ /* Typing with the cell active starts editing and keeps the keystroke:
137
+ it is what anyone coming from a spreadsheet does, and losing the first
138
+ character feels like the app is not responding. */
139
+ if (e.key.length === 1 && !e.metaKey && !e.ctrlKey && !e.altKey) {
140
+ e.preventDefault();
141
+ openCell(r, c, e.key);
142
+ }
143
+ }
144
+ }
145
+ return (_jsxs("div", { className: "flex min-w-0 flex-col", children: [caption === undefined ? null : (_jsx("div", { className: "px-3 pb-2 text-meta text-muted", children: caption })), _jsx("div", { ref: caja.ref, style: caja.style, onKeyDown: isEditable ? onKey : undefined, tabIndex: isEditable ? 0 : undefined, className: `relative min-w-0 rounded-box border border-line bg-surface focus:outline-none ${caja.className}`, role: "grid", "aria-rowcount": rows, "aria-colcount": columns.length + 1, children: _jsxs("div", { style: {
146
+ minWidth: `${ROW_LABEL_WIDTH + columns.reduce((a, c) => a + (c.width ?? WIDTH), 0)}px`,
147
+ }, children: [_jsxs("div", { className: "sticky z-20 flex border-b border-line-strong bg-ground", style: stickyTop, role: "row", children: [_jsx("div", { className: "sticky left-0 z-30 shrink-0 border-r border-line bg-ground", style: { width: ROW_LABEL_WIDTH } }), columns.map((c) => (_jsxs("div", { role: "columnheader", style: { width: c.width ?? WIDTH }, className: `flex shrink-0 flex-col justify-center gap-0.5 border-r border-line px-2.5 py-1.5 ${c.numeric === true ? "items-end" : "items-start"}`, children: [_jsx("span", { className: "max-w-full truncate text-meta font-medium text-ink", title: c.header, children: c.header }), c.type === undefined ? null : (_jsx("span", { className: "max-w-full truncate font-mono text-micro text-muted", children: c.type }))] }, c.id))), _jsx("div", { className: "flex-1" })] }), _jsx("div", { style: { height: v.getTotalSize(), position: "relative" }, children: items.map((item) => {
148
+ const montón = band?.(item.index);
149
+ if (montón !== undefined) {
150
+ /* La banda queda pegada a la IZQUIERDA como el número de fila:
151
+ con cuarenta columnas, un rótulo que se va con el scroll
152
+ horizontal deja de decir en qué montón estás justo cuando
153
+ más lejos estás de él. */
154
+ return (
155
+ /* La banda RESPETA la cuadrícula: rótulo en la columna fija de
156
+ la izquierda, y después una celda por columna —vacía, salvo
157
+ que esa columna sume algo—. Antes era un rótulo suelto que
158
+ ignoraba las columnas, y entonces un total quedaba en un
159
+ rincón sin decir de qué columna era. */
160
+ _jsxs("div", { role: "row", "aria-rowindex": item.index + 1, className: "absolute top-0 left-0 flex w-full border-b border-line-strong bg-ground", style: { height: item.size, transform: `translateY(${item.start}px)` }, children: [_jsx("button", { type: "button", onClick: onBandToggle === undefined
161
+ ? undefined
162
+ : () => onBandToggle(item.index), "aria-expanded": montón.open, className: "sticky left-0 z-10 flex min-w-0 shrink-0 items-center gap-1.5 border-r border-line bg-ground px-2.5 text-left", style: {
163
+ height: "100%",
164
+ /* El mismo ancho que la columna del número de fila, para
165
+ que el rótulo no corra la cuadrícula. */
166
+ width: ROW_LABEL_WIDTH,
167
+ ...(montón.depth === undefined || montón.depth === 0
168
+ ? {}
169
+ : {
170
+ paddingLeft: `calc(var(--spacing-indent) * ${montón.depth} + 0.625rem)`,
171
+ }),
172
+ }, children: onBandToggle === undefined ? null : (_jsx(ChevronRight, { className: `size-(--size-icon-sm) shrink-0 text-muted transition-transform duration-(--duration-instant) ${montón.open ? "rotate-90" : ""}`, strokeWidth: 2, "aria-hidden": true })) }), columns.map((c, ci) => {
173
+ const total = montón.total?.(c, ci) ?? null;
174
+ return (_jsx("div", { role: "gridcell", style: { width: c.width ?? WIDTH }, className: `flex shrink-0 items-center overflow-hidden border-r border-line px-2.5 whitespace-nowrap ${c.numeric === true ? "justify-end" : "justify-start"}`, children: ci === 0 ? (_jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [montón.field === undefined ? null : (_jsx("span", { className: "shrink-0 text-micro text-muted/70", children: montón.field })), _jsx("span", { className: "truncate text-micro font-medium text-ink", children: montón.label }), _jsx("span", { className: "inline-flex shrink-0 items-center rounded-pill border border-line-strong bg-ink/5 px-2 py-0.5 text-micro tabular-nums text-muted", children: montón.count.toLocaleString(copy.locale) })] })) : total === null ? null : (_jsx("span", { className: "truncate text-meta font-medium tabular-nums text-ink", children: typeof total === "number"
175
+ ? total.toLocaleString(copy.locale)
176
+ : total })) }, c.id));
177
+ })] }, item.key));
178
+ }
179
+ return (_jsxs("div", { role: "row", "aria-rowindex": item.index + 1, className: "absolute top-0 left-0 flex w-full border-b border-line", style: { height: item.size, transform: `translateY(${item.start}px)` }, children: [_jsx("div", { className: "sticky left-0 z-10 flex shrink-0 items-center justify-end border-r border-line bg-surface px-2 text-micro tabular-nums text-muted", style: { width: ROW_LABEL_WIDTH }, children: labelOf(item.index) }), columns.map((c, ci) => {
180
+ const t = tone?.(item.index, c, ci);
181
+ const n = note?.(item.index, c, ci);
182
+ const isActive = active !== null && active.r === item.index && active.c === ci;
183
+ const isEditingHere = isActive && editing;
184
+ return (_jsx("div", { role: "gridcell", title: n, "aria-selected": isActive, onClick: isEditable ? () => goTo(item.index, ci) : undefined, onDoubleClick: isEditable ? () => openCell(item.index, ci) : undefined, style: { width: c.width ?? WIDTH }, className: `relative flex shrink-0 items-center overflow-hidden border-r border-line px-2.5 text-meta tabular-nums whitespace-nowrap text-ink ${c.numeric === true ? "justify-end" : "justify-start"} ${t === undefined ? "" : TONE[t]} ${
185
+ /* The outline of the active cell goes on the inside
186
+ (`inset-ring`) and not on the outside: a 2 px border
187
+ would push the content and the whole row would dance
188
+ as you move around with the arrows. */
189
+ isActive
190
+ ? "inset-ring-2 inset-ring-primary"
191
+ : isEditable
192
+ ? "cursor-cell"
193
+ : ""}`, children: isEditingHere ? (_jsx("input", { autoFocus: true, value: draft, onChange: (ev) => setDraft(ev.target.value), onBlur: () => commit(0, 0), className: `absolute inset-0 w-full bg-surface px-2.5 text-meta tabular-nums text-ink outline-none ${c.numeric === true ? "text-right" : "text-left"}` })) : (_jsx(Cell, { value: value(item.index, c, ci), max: 24 })) }, c.id));
194
+ }), _jsx("div", { className: "flex-1" })] }, item.key));
195
+ }) })] }) })] }));
196
+ }
197
+ const ROW_LABEL_WIDTH = 64;
@@ -0,0 +1,106 @@
1
+ import type { Tone } from "../../foundations/types.js";
2
+ import { type ReactNode } from "react";
3
+ export type SortDirection = "asc" | "desc";
4
+ export interface SortState {
5
+ key: string;
6
+ direction: SortDirection;
7
+ }
8
+ export declare function Table({ children,
9
+ /** With a height, the table scrolls on its own and the header sticks.
10
+ * Without a height, the page scrolls and the header goes away. */
11
+ height, }: {
12
+ children: ReactNode;
13
+ /** A number means pixels; a string goes through as is, so `26rem` follows the
14
+ * system scale instead of pinning a size in pixels. */
15
+ height?: number | string;
16
+ }): import("react").JSX.Element;
17
+ export declare function THead({ children }: {
18
+ children: ReactNode;
19
+ }): import("react").JSX.Element;
20
+ /** A column. If it gets a `sortKey`, it can be sorted.
21
+ *
22
+ * The icon is ALWAYS there, dimmed when the column is not the sorted one: an
23
+ * indicator that only shows up once you sort does not say which columns are
24
+ * sortable, and then you have to try them one by one. */
25
+ export declare function Th({ children, sortKey, sort, onSort, numeric, align, width, }: {
26
+ children: ReactNode;
27
+ sortKey?: string;
28
+ sort?: SortState | null;
29
+ onSort?: (next: SortState | null) => void;
30
+ /** Numbers align to the right: that is what lets you compare orders of
31
+ * magnitude without reading the figures. */
32
+ numeric?: boolean;
33
+ /** The alignment, when it is NOT because it is a number. They are two
34
+ * different things: `numeric` says «this is a figure» and drags along the
35
+ * right alignment and the tabular figures; `align` only pushes. A status
36
+ * label on the right is not a number. */
37
+ align?: "left" | "right";
38
+ /** A number means pixels; a string goes through as is, so `6rem` follows the
39
+ * system scale instead of pinning a size in pixels. */
40
+ width?: number | string;
41
+ }): import("react").JSX.Element;
42
+ export declare function Tr({ children, onClick, selected, }: {
43
+ children: ReactNode;
44
+ onClick?: () => void;
45
+ selected?: boolean;
46
+ }): import("react").JSX.Element;
47
+ /**
48
+ * A row that opens its own detail underneath.
49
+ *
50
+ * Context: `DataTable` expands GROUPS —TanStack takes care of that— and that is
51
+ * not enough for the most common case in this product: a column that opens up
52
+ * to show its distribution. That is not a group, it is the detail of ONE row,
53
+ * and every view was writing it by hand with its own `colSpan` and its own
54
+ * chevron.
55
+ *
56
+ * The trigger is the first cell and not a column of chevrons: a whole column
57
+ * for a 12 px control is width that a twelve-column table needs.
58
+ */
59
+ export declare function TrDetail({ children, detail, open, onToggle, columns, label, selected, }: {
60
+ children: ReactNode;
61
+ detail: ReactNode;
62
+ open: boolean;
63
+ onToggle: () => void;
64
+ /** How many columns the table has, so the detail spans all of them. */
65
+ columns: number;
66
+ /** What is being opened, for the screen reader: «distribución de importe». */
67
+ label: string;
68
+ selected?: boolean;
69
+ }): import("react").JSX.Element;
70
+ /** The background of a cell, by tone. It replaces the row wash on that cell:
71
+ * a hovered row and a painted cell are two signals, and stacking them reads
72
+ * as a third color. */
73
+ export declare const CELL_TONE: Record<Tone, string>;
74
+ export declare function Td({ children, numeric, align,
75
+ /** A CODE — an id, a hash, a key — set in the monospaced face. Off by default: a
76
+ * number does not need it (a numeric cell gets tabular figures on its own), and a
77
+ * name in mono reads like a log, not like a report. */
78
+ mono,
79
+ /** Paints the whole cell. For what the eye has to find without reading: an
80
+ * imputed value, one out of range, a row that changed.
81
+ *
82
+ * Context: it is the CELL and not the text. Tinting the text says «this
83
+ * number is of another kind»; tinting the cell says «look here», which is
84
+ * something else — and in a table of forty rows by six columns, colored text
85
+ * gets lost. */
86
+ tone, title, }: {
87
+ children: ReactNode;
88
+ numeric?: boolean;
89
+ /** Pushes without saying it is a number. See the note on `Th`. */
90
+ align?: "left" | "right";
91
+ mono?: boolean;
92
+ tone?: Tone;
93
+ /** Why it is painted. A colored cell with no explanation is a question. */
94
+ title?: string;
95
+ }): import("react").JSX.Element;
96
+ /** The selection checkbox, with its third state.
97
+ *
98
+ * «some» is not an ornament: without it, the header checkbox of a table with
99
+ * three of forty rows selected lies in both directions — empty says «none»
100
+ * and filled says «all». */
101
+ export declare function SelectBox({ checked, indeterminate, onChange, label, }: {
102
+ checked: boolean;
103
+ indeterminate?: boolean;
104
+ onChange?: (next: boolean) => void;
105
+ label: string;
106
+ }): import("react").JSX.Element;
@@ -0,0 +1,116 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { stickyTop, useScrollBox } from "../../foundations/sticky.js";
4
+ import { ArrowDown, ArrowUp, ChevronRight, ChevronsUpDown } from "lucide-react";
5
+ import { createContext, useContext, useId } from "react";
6
+ export function Table({ children,
7
+ /** With a height, the table scrolls on its own and the header sticks.
8
+ * Without a height, the page scrolls and the header goes away. */
9
+ height, }) {
10
+ const caja = useScrollBox(height === undefined ? {} : { height });
11
+ return (
12
+ /* Cuándo esta caja es un contenedor de scroll y cuándo no lo decide
13
+ `useScrollBox`: ahí vive el dilema entero y ahí vive su explicación. Las
14
+ tres tablas del sistema lo resolvían con tres copias de la misma
15
+ medición. */
16
+ _jsx("div", { ref: caja.ref, className: `min-w-0 ${caja.className}`, style: caja.style, children: _jsx("table", { className: "w-full border-separate border-spacing-0 px-1 text-left", children: children }) }));
17
+ }
18
+ export function THead({ children }) {
19
+ return (
20
+ /* Se pega DEBAJO de lo que ya esté pegado —la barra de la aplicación y la
21
+ de la lista— y no en `top: 0`, que lo metía atrás de las dos. Sin alto en
22
+ `Table` el que scrollea es la página, y ahí la diferencia es justamente
23
+ la que hacía desaparecer los nombres de columna. Ver `system/sticky.tsx`. */
24
+ _jsx("thead", { className: "sticky z-10 bg-ground", style: stickyTop, children: _jsx("tr", { children: children }) }));
25
+ }
26
+ /** A column. If it gets a `sortKey`, it can be sorted.
27
+ *
28
+ * The icon is ALWAYS there, dimmed when the column is not the sorted one: an
29
+ * indicator that only shows up once you sort does not say which columns are
30
+ * sortable, and then you have to try them one by one. */
31
+ export function Th({ children, sortKey, sort, onSort, numeric = false, align, width, }) {
32
+ const active = sortKey !== undefined && sort?.key === sortKey;
33
+ const dir = active ? sort.direction : undefined;
34
+ function nextSort() {
35
+ if (sortKey === undefined || onSort === undefined)
36
+ return;
37
+ // asc → desc → unsorted. The third click puts the table back the way it was.
38
+ if (!active)
39
+ onSort({ key: sortKey, direction: "asc" });
40
+ else if (dir === "asc")
41
+ onSort({ key: sortKey, direction: "desc" });
42
+ else
43
+ onSort(null);
44
+ }
45
+ const Icon = dir === "asc" ? ArrowUp : dir === "desc" ? ArrowDown : ChevronsUpDown;
46
+ return (_jsx("th", { scope: "col", style: width === undefined ? undefined : { width }, "aria-sort": active ? (dir === "asc" ? "ascending" : "descending") : "none", className: `border-b border-line-strong px-3 py-2 text-meta font-medium whitespace-nowrap text-muted ${(align ?? (numeric ? "right" : "left")) === "right" ? "text-right" : "text-left"}`, children: sortKey === undefined ? (children) : (_jsxs("button", { type: "button", onClick: nextSort, className: `inline-flex items-center gap-1 rounded-control transition-colors duration-(--duration-instant) hover:text-ink focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-primary ${(align ?? (numeric ? "right" : "left")) === "right" ? "flex-row-reverse" : ""} ${active ? "text-ink" : ""}`, children: [children, _jsx(Icon, { className: `size-(--size-icon-sm) shrink-0 ${active ? "text-primary" : "text-line-strong"}`, strokeWidth: 2, "aria-hidden": true })] })) }));
47
+ }
48
+ /** The wash of a row lives on the cells, not on the `<tr>`. A background on the
49
+ * row paints edge to edge; on the cells the ends can round and the table's
50
+ * padding keeps the mark off the card. */
51
+ const RowMark = createContext(false);
52
+ const ROW_WASH = "group-hover/row:bg-ink/4";
53
+ const ROW_ON = "bg-primary/8";
54
+ function rowWash(selected) {
55
+ return selected ? ROW_ON : ROW_WASH;
56
+ }
57
+ export function Tr({ children, onClick, selected = false, }) {
58
+ return (_jsx(RowMark.Provider, { value: selected, children: _jsx("tr", { onClick: onClick, className: `group/row ${onClick === undefined ? "" : "cursor-pointer"}`, children: children }) }));
59
+ }
60
+ /**
61
+ * A row that opens its own detail underneath.
62
+ *
63
+ * Context: `DataTable` expands GROUPS —TanStack takes care of that— and that is
64
+ * not enough for the most common case in this product: a column that opens up
65
+ * to show its distribution. That is not a group, it is the detail of ONE row,
66
+ * and every view was writing it by hand with its own `colSpan` and its own
67
+ * chevron.
68
+ *
69
+ * The trigger is the first cell and not a column of chevrons: a whole column
70
+ * for a 12 px control is width that a twelve-column table needs.
71
+ */
72
+ export function TrDetail({ children, detail, open, onToggle, columns, label, selected = false, }) {
73
+ const id = useId();
74
+ return (_jsx(RowMark.Provider, { value: selected, children: _jsxs(_Fragment, { children: [_jsxs("tr", { onClick: onToggle, className: "group/row cursor-pointer", children: [_jsx("td", { className: `border-b border-line py-1.5 pr-0 pl-2.5 align-middle first:rounded-l-control ${rowWash(selected)}`, children: _jsx("button", { type: "button", onClick: (e) => {
75
+ e.stopPropagation();
76
+ onToggle();
77
+ }, "aria-expanded": open, "aria-controls": id, "aria-label": label, className: "inline-flex size-5 items-center justify-center rounded-pill text-muted transition-colors duration-(--duration-instant) hover:bg-ink/6 hover:text-ink focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary", children: _jsx(ChevronRight, { className: `size-(--size-icon-sm) transition-transform duration-(--duration-instant) ${open ? "rotate-90" : ""}`, strokeWidth: 2 }) }) }), children] }), _jsx("tr", { id: id, hidden: !open, children: _jsx("td", { colSpan: columns + 1, className: "border-b border-line bg-ground px-3 py-3", children: detail }) })] }) }));
78
+ }
79
+ /** The background of a cell, by tone. It replaces the row wash on that cell:
80
+ * a hovered row and a painted cell are two signals, and stacking them reads
81
+ * as a third color. */
82
+ export const CELL_TONE = {
83
+ neutral: "bg-ink/6",
84
+ info: "bg-info/12",
85
+ good: "bg-good/12",
86
+ warn: "bg-warn/15",
87
+ bad: "bg-bad/12",
88
+ accent: "bg-accent/20",
89
+ };
90
+ export function Td({ children, numeric = false, align,
91
+ /** A CODE — an id, a hash, a key — set in the monospaced face. Off by default: a
92
+ * number does not need it (a numeric cell gets tabular figures on its own), and a
93
+ * name in mono reads like a log, not like a report. */
94
+ mono = false,
95
+ /** Paints the whole cell. For what the eye has to find without reading: an
96
+ * imputed value, one out of range, a row that changed.
97
+ *
98
+ * Context: it is the CELL and not the text. Tinting the text says «this
99
+ * number is of another kind»; tinting the cell says «look here», which is
100
+ * something else — and in a table of forty rows by six columns, colored text
101
+ * gets lost. */
102
+ tone, title, }) {
103
+ const selected = useContext(RowMark);
104
+ return (_jsx("td", { title: title, className: `border-b border-line px-3 py-1.5 text-meta text-ink first:rounded-l-control last:rounded-r-control ${(align ?? (numeric ? "right" : "left")) === "right" ? "text-right" : "text-left"} ${mono ? "font-mono tabular-nums" : numeric ? "tabular-nums" : ""} ${tone === undefined ? rowWash(selected) : CELL_TONE[tone]}`, children: children }));
105
+ }
106
+ /** The selection checkbox, with its third state.
107
+ *
108
+ * «some» is not an ornament: without it, the header checkbox of a table with
109
+ * three of forty rows selected lies in both directions — empty says «none»
110
+ * and filled says «all». */
111
+ export function SelectBox({ checked, indeterminate = false, onChange, label, }) {
112
+ return (_jsx("input", { type: "checkbox", checked: checked, "aria-label": label, ref: (el) => {
113
+ if (el !== null)
114
+ el.indeterminate = indeterminate && !checked;
115
+ }, onChange: (e) => onChange?.(e.target.checked), onClick: (e) => e.stopPropagation(), className: "size-3.5 shrink-0 cursor-pointer accent-primary" }));
116
+ }
@@ -0,0 +1,7 @@
1
+ export { type Aggregate, type DataColumn, DataTable, type GroupColumn, } from "./DataTable.js";
2
+ export { EditableTable, type EditColumn, type EditLayout, type StackPlace, stackPlaces, } from "./EditableTable.js";
3
+ export { PivotTable, type PivotTableProps, } from "./PivotTable.js";
4
+ export { type ReportColumn, type ReportRow, type ReportRowKind, ReportTable, } from "./ReportTable.js";
5
+ export { type RowAction, RowActions } from "./RowActions.js";
6
+ export { type SheetColumn, SheetTable } from "./SheetTable.js";
7
+ export { CELL_TONE, type SortDirection, type SortState, Table, Td, Th, THead, Tr, } from "./Table.js";
@@ -0,0 +1,9 @@
1
+ /* The presentation (`Table`) is ours and is used on its own; `DataTable` is the
2
+ wiring to TanStack for grouping and sorting. See the note in `DataTable.tsx`. */
3
+ export { DataTable, } from "./DataTable.js";
4
+ export { EditableTable, stackPlaces, } from "./EditableTable.js";
5
+ export { PivotTable, } from "./PivotTable.js";
6
+ export { ReportTable, } from "./ReportTable.js";
7
+ export { RowActions } from "./RowActions.js";
8
+ export { SheetTable } from "./SheetTable.js";
9
+ export { CELL_TONE, Table, Td, Th, THead, Tr, } from "./Table.js";
@@ -0,0 +1,91 @@
1
+ import type { Tone } from "../../foundations/types.js";
2
+ import type { LucideIcon } from "lucide-react";
3
+ /**
4
+ * UNA TIRA DE PESTAÑAS. La misma en todo el sistema.
5
+ *
6
+ * Context: esto vivía adentro del encabezado del registro y se llamaba
7
+ * `Aspects`, así que el chatter —que necesita exactamente lo mismo— no podía
8
+ * usarlo: un contexto no importa de otro contexto. El resultado era una tira de
9
+ * pestañas de segunda mano, con el activo marcado de otra manera, en la misma
10
+ * pantalla que la buena.
11
+ *
12
+ * Es una primitiva porque no sabe qué está separando: las caras de un registro,
13
+ * las dos fuentes de una historia, o lo que venga.
14
+ *
15
+ * ── Por qué el activo es una PESTAÑA de carpeta ─────────────────────
16
+ *
17
+ * Y no un subrayado. Un subrayado dice «esto está elegido»; una pestaña que sale
18
+ * del borde y tapa la línea dice «esto está ABIERTO y lo de abajo es su
19
+ * contenido», que es la relación real. La diferencia importa cuando hay tres y
20
+ * el contenido de abajo no cambia de forma al cambiar de una a otra.
21
+ *
22
+ * ── El contador apagado en cero ─────────────────────────────────────
23
+ *
24
+ * Un cero se dibuja, y apagado. Esconderlo obliga a abrir la pestaña para
25
+ * descubrir que está vacía; pintarlo como los demás la hace parecer que tiene
26
+ * algo. «No hay ninguna» es información y se dice.
27
+ *
28
+ * ── El contador y la NOTIFICACIÓN son dos cosas ─────────────────────
29
+ *
30
+ * El contador dice CUÁNTAS cosas hay detrás, y es neutro: «pagos 0» es una
31
+ * respuesta tan válida como «pagos 5». La notificación dice que algo de ahí
32
+ * PIDE que lo mires —falló, cambió, llegó— y por eso tiene color y por eso un
33
+ * cero no se dibuja: no hay nada que pedir.
34
+ *
35
+ * Confundirlos se ve así: una pestaña con «3» al lado y nadie sabe si son tres
36
+ * cosas o tres problemas. Son dos marcas porque son dos preguntas.
37
+ */
38
+ /**
39
+ * ALGO DE ESTA PESTAÑA PIDE ATENCIÓN.
40
+ *
41
+ * No es un conteo: un conteo dice cuántas cosas hay y esto dice que hay algo que
42
+ * mirar. Por eso tiene color, por eso no se dibuja en cero, y por eso puede
43
+ * convivir con el contador — «pagos 4 ⬤» es cuatro cosas, una de ellas
44
+ * rechazada.
45
+ */
46
+ export type TabNotice = {
47
+ /**
48
+ * Qué es lo que pide atención, en la voz del producto: «3 sin leer», «la
49
+ * factura no se pudo enviar».
50
+ *
51
+ * Obligatorio, y por la misma razón que en `StatusDot`: un punto de color sin
52
+ * su palabra al lado obliga a aprender una leyenda que no está escrita en
53
+ * ningún lado, y no le dice nada a quien no distingue el rojo del verde. Acá
54
+ * la marca acelera el barrido y la palabra informa — se lee al pasar por
55
+ * encima y la lee un lector de pantalla.
56
+ */
57
+ label: string;
58
+ /** Cuántas cosas lo piden. Sin esto es un punto, que es lo que se pone cuando
59
+ * llegó algo nuevo y contarlo no agrega nada. Un `0` no dibuja nada: no hay
60
+ * nada que pedir. */
61
+ count?: number;
62
+ /** De qué clase: `bad` algo falló, `warn` algo avisa, `accent` o `info` algo
63
+ * llegó. Sin esto, `bad` — que es el caso por el que esto existe. */
64
+ tone?: Tone;
65
+ };
66
+ export type TabItem = {
67
+ id: string;
68
+ label: string;
69
+ /** La marca de la pestaña. Con tres o más, el ícono es lo que se reconoce sin
70
+ * leer — y en una tira angosta es lo único que sobrevive al truncado. */
71
+ icon?: LucideIcon;
72
+ /** Cuántas cosas hay detrás. `undefined` = no se cuenta; `0` se dibuja
73
+ * apagado, que es distinto de no contar. */
74
+ count?: number;
75
+ /** Que algo de acá pide que lo mires. Aparte del contador: ver `TabNotice`. */
76
+ notice?: TabNotice;
77
+ };
78
+ /**
79
+ * The strip only: what each tab opens is drawn by whoever uses it (`Record`, `Chatter`).
80
+ *
81
+ * Built on React Aria's `Tabs`, so the strip is a real tab list for the keyboard: the
82
+ * arrows move between tabs and select them, Home/End jump to the ends, and only the open
83
+ * tab is in the Tab order. The hand-written version had the roles and none of the keys.
84
+ */
85
+ export declare function Tabs({ tabs, current, onSelect, label, }: {
86
+ tabs: readonly TabItem[];
87
+ current: string;
88
+ onSelect?: (id: string) => void;
89
+ /** El rótulo accesible de la tira. Sin esto, «las caras del registro». */
90
+ label?: string;
91
+ }): import("react").JSX.Element;