@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,181 @@
1
+ import { levelKey, pathKey, pileItems, pileLabel, } from "../../foundations/grouping.js";
2
+ import { aggregateOf } from "../../primitives/table/DataTable.js";
3
+ /**
4
+ * Context: what a list DERIVES from its set, as pure functions — the table's group levels,
5
+ * the sheet drawn from the declared columns, the sheet's flattened band/row sequence and
6
+ * the report built from the piles. `ListView` calls them inside `useMemo` with the same
7
+ * dependencies they always had; nothing here knows React.
8
+ */
9
+ /**
10
+ * Los niveles, como los necesita la tabla: uno por NIVEL y no uno por campo.
11
+ *
12
+ * La clave sale de `group.of` —la misma que arman las otras cinco
13
+ * presentaciones— así que los montones de la tabla son los mismos y lo plegado
14
+ * vale para todas. El rótulo sale de la misma regla que el árbol: un nivel no
15
+ * repite lo que el de arriba, del mismo campo, ya dijo.
16
+ */
17
+ export function groupLevelsOf(group, columns) {
18
+ if (group === undefined || group.levels.length === 0)
19
+ return [];
20
+ const above = [];
21
+ const label = group.label ?? pileLabel;
22
+ return group.levels.map((level) => {
23
+ const within = above.flatMap((one) => one.field === level.field && one.grain !== undefined ? [one.grain] : []);
24
+ above.push(level);
25
+ /* Cómo se llama el corte: como lo llama la columna que contesta por ese
26
+ campo, que es el único rótulo humano que esta capa tiene. */
27
+ const column = columns?.find((one) => one.id === level.field || one.field === level.field);
28
+ return {
29
+ id: levelKey(level),
30
+ label: column?.header ?? level.field,
31
+ keyOf: (item) => group.of(item, level),
32
+ labelOf: (key) => label(key, level, within),
33
+ };
34
+ });
35
+ }
36
+ /**
37
+ * La planilla de un conjunto de REGISTROS sale de las columnas que la lista
38
+ * ya declaró. Sin esto, ofrecer `sheet` obligaba a escribir las columnas dos
39
+ * veces —una como `DataColumn` y otra como `SheetColumn`— y entonces nadie la
40
+ * ofrecía: la presentación existía en el arquetipo y no estaba en ninguna
41
+ * pantalla.
42
+ *
43
+ * `sheet` explícita sigue siendo para los DATOS CRUDOS, donde las columnas
44
+ * salen del archivo y el código no sabe cuáles son.
45
+ */
46
+ export function sheetFromColumns(shownColumns) {
47
+ if (shownColumns === undefined || shownColumns.length === 0)
48
+ return undefined;
49
+ const byId = new Map(shownColumns.map((column) => [column.id, column]));
50
+ return {
51
+ columns: shownColumns.map((column) => ({
52
+ id: column.id,
53
+ header: column.header,
54
+ ...(column.numeric === true ? { numeric: true } : {}),
55
+ ...(column.width === undefined ? {} : { width: column.width }),
56
+ })),
57
+ cell: (item, column) => {
58
+ const declared = byId.get(column.id);
59
+ /* `text` primero: `value` es la clave de ORDEN, no lo que se lee. Sin
60
+ esto la planilla mostraba `computed` donde la tabla muestra
61
+ «calculado». */
62
+ if (declared?.text !== undefined)
63
+ return declared.text(item);
64
+ const raw = declared?.value(item);
65
+ /* Un booleano no es una celda: la cuadrícula dibuja texto o número, y
66
+ `false` se vería como una celda vacía, que significa otra cosa. */
67
+ return typeof raw === "boolean" ? String(raw) : (raw ?? null);
68
+ },
69
+ tone: (item, column) => byId.get(column.id)?.tone?.(item),
70
+ note: (item, column) => byId.get(column.id)?.note?.(item),
71
+ /* Crece con la página en vez de abrir una caja con scroll adentro de otra
72
+ que ya scrollea. La lista ya vino paginada, así que son ochenta filas y
73
+ no ciento ochenta y siete — el caso de un millón es el de los datos
74
+ crudos, y ése declara su propio alto. */
75
+ height: "auto",
76
+ };
77
+ }
78
+ /**
79
+ * La planilla, cuando hay montones: una SECUENCIA donde cada índice es una
80
+ * fila o la cabecera del montón que empieza ahí.
81
+ *
82
+ * **Acá decía que la planilla no agrupa y estaba mal razonado.** El argumento
83
+ * —una banda corre la cuadrícula y mirar datos crudos es seguir una fila a lo
84
+ * ancho— vale para los datos crudos, donde las columnas salen del archivo y
85
+ * no hay ningún eje del dominio por el que agrupar. Pero la planilla DERIVADA
86
+ * es el mismo conjunto de registros que la tabla, con los mismos ejes: que
87
+ * agrupe la tabla y no ella es exactamente el drift que este arquetipo existe
88
+ * para impedir — cambiar de presentación perdía la agrupación.
89
+ *
90
+ * La regla queda en manos de la vista, como corresponde: si declara `group`,
91
+ * agrupa; si no, no hay montones que dibujar.
92
+ */
93
+ export function sheetRowsOf(piles, isOpen, columns) {
94
+ if (piles === null)
95
+ return null;
96
+ const out = [];
97
+ let n = 0;
98
+ /* Aplanar es recursivo porque el árbol lo es. La planilla no puede recibir
99
+ el árbol: está virtualizada por índice, y un índice es una posición en una
100
+ secuencia — así que la jerarquía se expresa en la sangría de cada banda. */
101
+ const walk = (list) => {
102
+ for (const pile of list) {
103
+ const open = isOpen(pile);
104
+ const inside = pile.piles.length === 0 ? pile.items : pileItems(pile.piles);
105
+ out.push({
106
+ band: {
107
+ field: pile.field,
108
+ label: pile.label,
109
+ count: pile.count,
110
+ open,
111
+ key: pathKey(pile.path),
112
+ depth: pile.depth,
113
+ /* El total de cada columna, en la posición de esa columna. Sale de
114
+ las `columns` de la lista —las mismas que suma el pie de la
115
+ tabla— para que la planilla y la tabla no digan números distintos
116
+ del mismo montón. La planilla declara SUS columnas aparte, así que
117
+ se busca por id. */
118
+ total: (column) => {
119
+ const declared = columns?.find((one) => one.id === column.id);
120
+ return declared === undefined ? null : aggregateOf(declared, inside);
121
+ },
122
+ },
123
+ });
124
+ if (!open)
125
+ continue;
126
+ if (pile.piles.length > 0) {
127
+ walk(pile.piles);
128
+ continue;
129
+ }
130
+ for (const one of pile.items) {
131
+ n += 1;
132
+ out.push({ item: one, n });
133
+ }
134
+ }
135
+ };
136
+ walk(piles);
137
+ return out;
138
+ }
139
+ /**
140
+ * El informe armado a partir de los montones, cuando el dominio no declaró
141
+ * líneas.
142
+ *
143
+ * Cada montón es una línea con los agregados de las columnas que declararon
144
+ * uno, y el nivel más profundo cuelga sus filas. Las columnas del informe las
145
+ * pone `report.columns`; los números salen de las `columns` de la lista, que
146
+ * son las mismas que suma el pie de la tabla — para que el informe y la tabla
147
+ * no digan totales distintos del mismo conjunto.
148
+ */
149
+ export function reportRowsOf(piles, columns, row) {
150
+ if (piles === null || columns === undefined)
151
+ return [];
152
+ const numeric = columns.filter((column) => column.aggregate !== undefined);
153
+ /* A pile is named by the HEADER of the column that answers for its field — the word the
154
+ person reads in the table — not by the field's id: «stage · pedido» showed the
155
+ model's name for it. */
156
+ const fieldName = (field) => columns.find((column) => column.id === field || column.field === field)?.header ?? field;
157
+ const line = (pile) => {
158
+ const inside = pile.piles.length === 0 ? pile.items : pileItems(pile.piles);
159
+ const children = pile.piles.length > 0
160
+ ? pile.piles.map(line)
161
+ : pile.items.map((item, index) => ({
162
+ id: `${pathKey(pile.path)}\u0000${index}`,
163
+ label: row(item).name,
164
+ kind: "line",
165
+ level: pile.depth + 1,
166
+ values: numeric.map((column) => {
167
+ const value = column.value(item);
168
+ return typeof value === "number" ? value : null;
169
+ }),
170
+ }));
171
+ return {
172
+ id: pathKey(pile.path),
173
+ label: `${fieldName(pile.field)} · ${pile.label}`,
174
+ kind: pile.depth === 0 ? "section" : "group",
175
+ level: pile.depth,
176
+ values: numeric.map((column) => aggregateOf(column, inside)),
177
+ children,
178
+ };
179
+ };
180
+ return piles.map(line);
181
+ }
@@ -0,0 +1,2 @@
1
+ export { List, type ListProps } from "./List.js";
2
+ export { type ListCrumb, type ListEmpty, type ListGroup, type ListPivot, type ListPresent, type ListReport, type ListSheet, type RowOf, } from "./types.js";
@@ -0,0 +1,4 @@
1
+ /* LISTA — N registros. `List` se escribe como ÁRBOL: las caras que ofrece son las que
2
+ están escritas adentro. `ListView` es el DIBUJO que hay detrás y no se publica. */
3
+ export { List } from "./List.js";
4
+ export {} from "./types.js";
@@ -0,0 +1,39 @@
1
+ import { type DataColumn, DataTable } from "../../primitives/table/DataTable.js";
2
+ import type { SheetEntry } from "./derive.js";
3
+ import type { ListGroup, ListSheet, ListViewProps } from "./types.js";
4
+ /**
5
+ * Context: the two presentations whose body is an adapter between the list's vocabulary
6
+ * (one selection that speaks one id at a time, a grouping tree, an index-addressed sequence)
7
+ * and a primitive's (a Set, levels, indexes). They draw nothing of their own — they are
8
+ * `ListView`'s `table` and `sheet` branches, moved out so that file reads as the decision of
9
+ * WHICH presentation, and these as HOW the two grids are fed.
10
+ */
11
+ type TableProps<T extends object> = {
12
+ items: readonly T[];
13
+ columns: readonly DataColumn<T>[];
14
+ keyOf: (item: T) => string;
15
+ levels: NonNullable<Parameters<typeof DataTable<T>>[0]["levels"]>;
16
+ group?: ListGroup<T>;
17
+ totals: boolean;
18
+ } & Pick<ListViewProps<T>, "sort" | "onSortChange" | "selection" | "rowActions" | "onPeek" | "onOpen">;
19
+ /** The table receives EVERYTHING that belongs to the set —sorting, selection, grouping,
20
+ * which columns are on screen— and not a trimmed down version: that was exactly the trap
21
+ * this archetype exists to avoid, that switching presentation loses capabilities. */
22
+ export declare function TablePresentation<T extends object>({ items, columns, keyOf, levels, group, totals, sort, onSortChange, selection, rowActions, onPeek, onOpen, }: TableProps<T>): import("react").JSX.Element;
23
+ type SheetProps<T extends object> = {
24
+ spec: ListSheet<T>;
25
+ /** The flattened bands and rows when the set is grouped; `null` when it is not. */
26
+ entries: readonly SheetEntry<T>[] | null;
27
+ ordered: readonly T[];
28
+ group?: ListGroup<T>;
29
+ };
30
+ /** The sheet receives the set by INDEX and not a ready-made matrix: `SheetTable` is
31
+ * virtualized precisely so as not to materialize a million rows, and handing it copies
32
+ * would throw that away.
33
+ *
34
+ * It groups like the other three —grouping belongs to the SET, not to the presentation—
35
+ * and the piles enter as rows of another kind, so virtualization is not lost. What it still
36
+ * lacks is selection: a checkbox per row in a forty-column grid competes with the frozen
37
+ * row-number column, the one that lets you know which row you are on. */
38
+ export declare function SheetPresentation<T extends object>({ spec, entries, ordered, group, }: SheetProps<T>): import("react").JSX.Element;
39
+ export {};
@@ -0,0 +1,103 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useUiCopy } from "../../foundations/copy.js";
4
+ import { DataTable } from "../../primitives/table/DataTable.js";
5
+ import { SheetTable } from "../../primitives/table/SheetTable.js";
6
+ /** The table receives EVERYTHING that belongs to the set —sorting, selection, grouping,
7
+ * which columns are on screen— and not a trimmed down version: that was exactly the trap
8
+ * this archetype exists to avoid, that switching presentation loses capabilities. */
9
+ export function TablePresentation({ items, columns, keyOf, levels, group, totals, sort, onSortChange, selection, rowActions, onPeek, onOpen, }) {
10
+ return (_jsx(DataTable, { data: items, columns: columns, getRowId: keyOf, ...(sort === undefined ? {} : { sort }), ...(onSortChange === undefined ? {} : { onSortChange }), ...(levels.length === 0 ? {} : { levels: levels }), ...(group?.collapsed === undefined ? {} : { collapsed: group.collapsed }), ...(group?.onToggle === undefined ? {} : { onGroupToggle: group.onToggle }), ...(selection === undefined
11
+ ? {}
12
+ : {
13
+ selected: new Set(items.filter((i) => selection.has(keyOf(i))).map(keyOf)),
14
+ onSelectedChange: (next) => {
15
+ /* `DataTable` sends the whole set; the view's selection speaks
16
+ one at a time. It is translated here and not there because the
17
+ one who knows what changed is the one holding the before and
18
+ the after. */
19
+ for (const item of items) {
20
+ const id = keyOf(item);
21
+ if (next.has(id) !== selection.has(id))
22
+ selection.toggle(id);
23
+ }
24
+ },
25
+ }), ...(totals ? { totals: true } : {}), ...(rowActions === undefined ? {} : { rowActions }), ...((onPeek ?? onOpen) === undefined ? {} : { onRowClick: onPeek ?? onOpen }) }));
26
+ }
27
+ /** The sheet receives the set by INDEX and not a ready-made matrix: `SheetTable` is
28
+ * virtualized precisely so as not to materialize a million rows, and handing it copies
29
+ * would throw that away.
30
+ *
31
+ * It groups like the other three —grouping belongs to the SET, not to the presentation—
32
+ * and the piles enter as rows of another kind, so virtualization is not lost. What it still
33
+ * lacks is selection: a checkbox per row in a forty-column grid competes with the frozen
34
+ * row-number column, the one that lets you know which row you are on. */
35
+ export function SheetPresentation({ spec, entries, ordered, group, }) {
36
+ const copy = useUiCopy();
37
+ /** Qué ítem hay en este índice de la planilla. Con montones, un índice puede
38
+ * ser una banda y no una fila — y entonces no hay ítem. Una sola vez, porque
39
+ * las seis funciones que la planilla recibe hacen la misma pregunta. */
40
+ const sheetItemAt = (index) => entries === null ? ordered[index] : entries[index]?.item;
41
+ return (_jsx(SheetTable, { columns: spec.columns, rows: entries === null ? ordered.length : entries.length, value: (index, column, columnIndex) => {
42
+ const item = sheetItemAt(index);
43
+ return item === undefined ? null : spec.cell(item, column, columnIndex);
44
+ }, ...(entries === null
45
+ ? {}
46
+ : {
47
+ band: (index) => entries[index]?.band,
48
+ ...(group?.onToggle === undefined
49
+ ? {}
50
+ : {
51
+ onBandToggle: (index) => {
52
+ const key = entries[index]?.band?.key;
53
+ if (key !== undefined)
54
+ group.onToggle?.(key);
55
+ },
56
+ }),
57
+ }), ...(spec.tone === undefined
58
+ ? {}
59
+ : {
60
+ tone: (index, column, columnIndex) => {
61
+ const item = sheetItemAt(index);
62
+ return item === undefined ? undefined : spec.tone?.(item, column, columnIndex);
63
+ },
64
+ }), ...(spec.note === undefined
65
+ ? {}
66
+ : {
67
+ note: (index, column, columnIndex) => {
68
+ const item = sheetItemAt(index);
69
+ return item === undefined ? undefined : spec.note?.(item, column, columnIndex);
70
+ },
71
+ }), ...(spec.height === undefined ? {} : { height: spec.height }), ...(spec.rowLabel !== undefined
72
+ ? {
73
+ rowLabel: (index) => {
74
+ const item = sheetItemAt(index);
75
+ return item === undefined ? "" : (spec.rowLabel?.(item, index) ?? "");
76
+ },
77
+ }
78
+ : entries === null
79
+ ? {}
80
+ : {
81
+ rowLabel: (index) => {
82
+ const n = entries[index]?.n;
83
+ return n === undefined ? "" : n.toLocaleString(copy.locale);
84
+ },
85
+ }), ...(spec.onCommit === undefined
86
+ ? {}
87
+ : {
88
+ onCommit: (index, column, columnIndex, next) => {
89
+ const item = sheetItemAt(index);
90
+ if (item !== undefined)
91
+ spec.onCommit?.(item, column, columnIndex, next);
92
+ },
93
+ }), ...(spec.editable === undefined
94
+ ? {}
95
+ : {
96
+ editable: (index, column, columnIndex) => {
97
+ const item = sheetItemAt(index);
98
+ return item === undefined
99
+ ? false
100
+ : (spec.editable?.(item, column, columnIndex) ?? false);
101
+ },
102
+ }) }));
103
+ }
@@ -0,0 +1,272 @@
1
+ import type { ListIdentity } from "../../components/listing/ListingBar.js";
2
+ import type { ListPresent } from "../../components/listing/set.js";
3
+ import type { SortField } from "../../components/listing/SortMenu.js";
4
+ import type { Grouping, GroupLevel } from "../../foundations/grouping.js";
5
+ import type { Pivot, PivotKey, PivotSpec } from "../../foundations/pivot.js";
6
+ import type { Surface, Tone } from "../../foundations/types.js";
7
+ import type { DataColumn } from "../../primitives/table/DataTable.js";
8
+ import type { ReportColumn, ReportRow } from "../../primitives/table/ReportTable.js";
9
+ import type { RowAction } from "../../primitives/table/RowActions.js";
10
+ import type { SheetColumn } from "../../primitives/table/SheetTable.js";
11
+ import type { SortState } from "../../primitives/table/Table.js";
12
+ import type { LucideIcon } from "lucide-react";
13
+ import type { ReactNode } from "react";
14
+ /**
15
+ * Las seis maneras de mirar un conjunto. La unión vive en `list/set.ts`, que
16
+ * es donde ya vivía su copia.
17
+ *
18
+ * Las seis son el MISMO conjunto mirado distinto, y por eso comparten barra.
19
+ * Lo que cambia entre ellas es qué sabe el código de las columnas — y, en el
20
+ * pivote, que las filas de la pantalla ya no son las filas del conjunto.
21
+ */
22
+ export type { ListPresent };
23
+ /** What an item looks like when the presentation is rows. */
24
+ export type RowOf = {
25
+ icon?: LucideIcon;
26
+ name: string;
27
+ tags?: ReactNode;
28
+ meta?: string;
29
+ /** What this resource produced, hanging underneath. */
30
+ children?: ReactNode;
31
+ actions?: ReactNode;
32
+ };
33
+ /** A crumb of the list: where I came from. */
34
+ export type ListCrumb = {
35
+ label: string;
36
+ onClick?: () => void;
37
+ };
38
+ export type ListEmpty = {
39
+ sentence: string;
40
+ action?: ReactNode;
41
+ /** Empty because of a filter is ANOTHER situation: content is not missing,
42
+ * there is an extra narrowing. Telling «importá tus facturas» to someone who has 180
43
+ * and mistyped a name is answering a different question. */
44
+ whenFiltered?: {
45
+ sentence: string;
46
+ action?: ReactNode;
47
+ };
48
+ };
49
+ /**
50
+ * El agrupado de una lista: el CONTRATO de `system/grouping.ts` más lo único que
51
+ * una tabla necesita de más.
52
+ *
53
+ * Las seis presentaciones parten el conjunto con el MISMO árbol y las mismas
54
+ * claves — la tabla incluida. Lo único que una tabla agrega es una pregunta de
55
+ * VISIBILIDAD: agrupar por un campo cuya columna está escondida dejaría montones
56
+ * cuyo criterio no se ve en ninguna parte, así que esa columna se repone, y para
57
+ * reponerla hay que saber cuál es. Eso es `columnOf`, y nada más: la clave del
58
+ * montón no sale de una columna.
59
+ *
60
+ * Va acá y no en el contrato para que una vista que no tenga columnas no tenga
61
+ * que fingir que las tiene.
62
+ */
63
+ export type ListGroup<T extends object> = Grouping<T> & {
64
+ /** Qué COLUMNA contesta por cada nivel, para reponerla cuando está escondida.
65
+ * Sin esto, la que se llame como el campo o la que lo declare en `field`. */
66
+ columnOf?: (level: GroupLevel) => string | undefined;
67
+ };
68
+ /**
69
+ * La PLANILLA de una lista: las columnas y cómo se lee cada celda.
70
+ *
71
+ * Se declara cuando las columnas salen del ARCHIVO y el código no sabe cuáles
72
+ * son. Para un conjunto de registros no hace falta: sale de las `columns` que
73
+ * la lista ya declaró.
74
+ */
75
+ export type ListSheet<T> = {
76
+ columns: readonly SheetColumn[];
77
+ /** El valor de una celda. `null` es un faltante y `""` una celda vacía: son
78
+ * cosas distintas y el motor las distingue, así que la interfaz también. */
79
+ cell: (item: T, column: SheetColumn, columnIndex: number) => string | number | null;
80
+ /** Qué celdas se pintan y con qué: un valor imputado, uno fuera de rango. */
81
+ tone?: (item: T, column: SheetColumn, columnIndex: number) => Tone | undefined;
82
+ note?: (item: T, column: SheetColumn, columnIndex: number) => string | undefined;
83
+ height?: number | "auto";
84
+ /** Qué dice la columna fija de la izquierda. Sin esto, el número de fila. */
85
+ rowLabel?: (item: T, index: number) => string;
86
+ /** Presente = la planilla se edita como planilla. Recibe el texto crudo;
87
+ * convertirlo al tipo de la columna es del dominio, no de acá. */
88
+ onCommit?: (item: T, column: SheetColumn, columnIndex: number, next: string) => void;
89
+ editable?: (item: T, column: SheetColumn, columnIndex: number) => boolean;
90
+ };
91
+ /**
92
+ * El INFORME de una lista: los períodos y la jerarquía que termina en totales.
93
+ *
94
+ * Las filas van aparte de `items` y es deliberado: un balance no es la lista
95
+ * plana agrupada —«Total Activos» es una suma de sumas— y el arquetipo no puede
96
+ * inventar esa jerarquía. La arma quien conoce el dominio, como ya arma
97
+ * `columns`.
98
+ */
99
+ export type ListReport = {
100
+ columns: readonly ReportColumn[];
101
+ /**
102
+ * Las líneas del informe, cuando el DOMINIO las arma.
103
+ *
104
+ * Un balance no es la lista plana agrupada —«Total Activos» es una suma de
105
+ * sumas— y el arquetipo no puede inventar esa jerarquía.
106
+ *
107
+ * **Sin esto, el informe se arma con los montones**: cada nivel es una línea
108
+ * con sus agregados, y el más profundo son las filas. Es el mismo conjunto que
109
+ * ven las otras cuatro presentaciones, contado — que es lo que alguien espera
110
+ * al pasar de «tabla» a «informe» con dos niveles puestos.
111
+ */
112
+ rows?: readonly ReportRow[];
113
+ /** Qué grupos arrancan abiertos. Por omisión ninguno: un balance con todo
114
+ * desplegado son cuatrocientas líneas y lo que se mira primero son los
115
+ * totales. */
116
+ defaultOpen?: readonly string[];
117
+ height?: number;
118
+ };
119
+ /**
120
+ * El PIVOTE de una lista: los dos ejes y las medidas que se pliegan en el cruce.
121
+ *
122
+ * Es la presentación en la que **las filas de la pantalla dejan de ser los
123
+ * registros**: una fila es un montón y una columna también, así que no hay nada
124
+ * que elegir ni que abrir, y lo que se lee está en el cruce.
125
+ *
126
+ * De ahí que venga plegado de dos lugares posibles, igual que los montones de
127
+ * una lista agrupada:
128
+ *
129
+ * folded lo plegó quien guarda los datos. Es el caso normal en cuanto el
130
+ * conjunto no entra en el navegador: contar 187 vencidas no lo
131
+ * pueden contestar las doce filas que se bajaron.
132
+ * spec lo pliega esta máquina, con las filas en la mano.
133
+ *
134
+ * Los dos dibujan igual porque dibujan el mismo tipo.
135
+ */
136
+ export type ListPivot<T> = {
137
+ /** El pivote ya plegado. Gana sobre `spec` cuando están los dos: si alguien
138
+ * con el conjunto entero ya contestó, no hay nada que recalcular. */
139
+ folded?: Pivot;
140
+ /**
141
+ * Cómo armarlo acá adentro. Las medidas traen su pliegue, y los márgenes salen
142
+ * de la BASE y no de sumar celdas — ver `system/pivot.ts`.
143
+ *
144
+ * Quien además necesite la grilla EN LA MANO —para bajarla como planilla con
145
+ * `downloadPivot`, por ejemplo— la pliega él con `pivotFrom` y la pasa por
146
+ * `folded`: así la que se dibuja y la que se baja son el mismo objeto, y no
147
+ * dos que podrían no coincidir.
148
+ */
149
+ spec?: PivotSpec<T>;
150
+ /** Qué pasa al tocar un cruce: abrir las filas que cayeron ahí. */
151
+ onCell?: (row: PivotKey, column: PivotKey) => void;
152
+ height?: number | string;
153
+ };
154
+ export type ListViewProps<T extends object> = {
155
+ items: readonly T[];
156
+ keyOf: (item: T) => string;
157
+ identity?: ListIdentity;
158
+ /** Where I came from. It goes above the bar, and only when the bar is chrome. */
159
+ crumbs?: readonly ListCrumb[];
160
+ /** The metrics that also NARROW: «2 por confirmar», «41 por entregar». They go
161
+ * below the bar and above the rows — they belong to the set, not to the frame. */
162
+ metrics?: ReactNode;
163
+ /** Which surface the BAR sits on. `canvas` (the default) is a light control bar;
164
+ * `chrome` turns it into a dark band — an explicit choice, since the application bar
165
+ * is the screen's one dark band (same as the rail of a record). */
166
+ surface?: Surface;
167
+ /** The search field, already assembled. It is assembled by whoever holds the
168
+ * domain declarations — the system does not know what a provenance is. */
169
+ search?: ReactNode;
170
+ pagination?: ReactNode;
171
+ /** Escape hatch: a custom switcher. Prefer `presents` so the archetype draws it. */
172
+ views?: ReactNode;
173
+ actions?: ReactNode;
174
+ row: (item: T) => RowOf;
175
+ /**
176
+ * Los rótulos de las zonas de una fila, arriba de todas. Sin esto no hay
177
+ * encabezado: `rows` no es una tabla y no toda lista tiene algo que rotular
178
+ * —una lista de cinco archivos con el nombre y nada más no lo necesita.
179
+ *
180
+ * No son columnas. Una fila tiene un nombre, UNA cadena de `meta` ya
181
+ * formateada y una columna de fichas: eso es lo que se rotula, y por eso los
182
+ * rótulos los escribe la vista y no salen de `columns`.
183
+ */
184
+ rowHeader?: {
185
+ name: string;
186
+ meta?: string;
187
+ tags?: string;
188
+ };
189
+ /** The table presentation. With this, `present="table"` draws a `DataTable`. */
190
+ columns?: readonly DataColumn<T>[];
191
+ /** Which table columns are on screen. Required columns stay even if omitted.
192
+ * Owned by the view when omitted — catalog filters must not reset them. */
193
+ visibleColumnIds?: readonly string[];
194
+ onVisibleColumnIdsChange?: (ids: readonly string[]) => void;
195
+ /** The sorting of the table. It lives outside because it belongs to the SET
196
+ * and not to the presentation: switching from table to rows has no reason to
197
+ * lose it. */
198
+ sort?: SortState | null;
199
+ onSortChange?: (next: SortState | null) => void;
200
+ /**
201
+ * Por qué campos se puede ordenar, para las presentaciones que NO tienen
202
+ * encabezados donde hacer clic.
203
+ *
204
+ * Sin esto, ordenar existe sólo en la tabla — y entonces pasar a filas o a
205
+ * tablero no pierde el orden puesto, pierde la posibilidad de ordenar. La
206
+ * tabla sigue teniendo además sus encabezados: son dos puertas a lo mismo, y
207
+ * la de los encabezados es más rápida donde existe.
208
+ */
209
+ sortable?: readonly SortField<T>[];
210
+ /** The footer with the aggregates of the columns that declared one. */
211
+ totals?: boolean;
212
+ /** What gets done to ONE row without entering it, in the table presentation.
213
+ * They are drawn hidden and appear on the row being pointed at. */
214
+ rowActions?: (item: T) => readonly RowAction[];
215
+ /** The board presentation. */
216
+ card?: (item: T) => ReactNode;
217
+ /**
218
+ * La PLANILLA. Con esto, `present="sheet"` dibuja un `SheetTable`.
219
+ *
220
+ * Es la presentación de los datos crudos, y por eso no recibe `DataColumn`:
221
+ * las columnas salen del archivo y el código no sabe cuáles son ni cuántas.
222
+ * El valor se pide por índice —igual que `SheetTable`, que está virtualizado—
223
+ * así que un millón de filas no se copia a ninguna otra estructura.
224
+ */
225
+ sheet?: ListSheet<T>;
226
+ /**
227
+ * El INFORME: una jerarquía que termina en totales. Con esto,
228
+ * `present="report"` dibuja un `ReportTable`.
229
+ *
230
+ * Las filas van aparte de `items` y es deliberado: un balance NO es la lista
231
+ * plana agrupada —«Total Activos» no es un montón de cuentas, es una suma de
232
+ * sumas— y el arquetipo no puede inventar esa jerarquía a partir del
233
+ * conjunto. La arma quien conoce el dominio, como ya arma `columns`.
234
+ */
235
+ report?: ListReport;
236
+ /**
237
+ * El PIVOTE: dos ejes a la vez. Con esto, `present="pivot"` dibuja un
238
+ * `PivotTable`.
239
+ *
240
+ * Va aparte de `group` y no derivado de él aunque los dos partan el conjunto,
241
+ * porque un pivote parte por DOS ejes y una lista agrupada por uno: los
242
+ * niveles de `group` no dicen cuál de ellos sería el eje horizontal, y
243
+ * elegirlo acá sería adivinar la pregunta.
244
+ */
245
+ pivot?: ListPivot<T>;
246
+ present?: ListPresent;
247
+ /** Which presentations this list offers. Two or more draw the switcher. */
248
+ presents?: readonly ListPresent[];
249
+ onPresentChange?: (next: ListPresent) => void;
250
+ group?: ListGroup<T>;
251
+ selection?: {
252
+ has: (id: string) => boolean;
253
+ toggle: (id: string) => void;
254
+ count: number;
255
+ clear: () => void;
256
+ actions?: ReactNode;
257
+ };
258
+ onOpen?: (item: T) => void;
259
+ onPeek?: (item: T) => void;
260
+ isPeeked?: (item: T) => boolean;
261
+ /** The three states, in a single place. Every view used to re-assemble them
262
+ * with three nested ternaries, and that is why «empty because of a filter»
263
+ * and «really empty» got mixed up in half the screens. */
264
+ state?: {
265
+ loading?: boolean;
266
+ error?: string | null;
267
+ };
268
+ filtered?: boolean;
269
+ empty?: ListEmpty;
270
+ /** The escape hatch. */
271
+ children?: ReactNode;
272
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,17 @@
1
+ import type { ListPresent } from "../../components/listing/set.js";
2
+ import { type RefObject } from "react";
3
+ /**
4
+ * A narrow LIST — a phone, a drawer, a panel among four — does not offer the presentations
5
+ * that need width: a seven-column table at 360 px is a horizontal scroll nobody reads.
6
+ * There the list shows rows (a stacked card per record: the name, its state, its facts)
7
+ * and the board, and the switcher offers only those. It is the width of the list's own
8
+ * container that decides, not the window's: a narrow panel on a wide screen is narrow.
9
+ *
10
+ * Attach `frame` to the list's root element; `offered` is what the switcher may show and
11
+ * `present` what to draw (a wide one that was asked for falls back to rows).
12
+ */
13
+ export declare function useNarrowList(presents: readonly ListPresent[] | undefined, requested: ListPresent): {
14
+ frame: RefObject<HTMLDivElement | null>;
15
+ offered: readonly ListPresent[];
16
+ present: ListPresent;
17
+ };
@@ -0,0 +1,32 @@
1
+ "use client";
2
+ import { HANDHELD_WIDTH } from "../../foundations/layout.js";
3
+ import { WIDE_PRESENTS } from "./columns.js";
4
+ import { useEffect, useRef, useState } from "react";
5
+ /**
6
+ * A narrow LIST — a phone, a drawer, a panel among four — does not offer the presentations
7
+ * that need width: a seven-column table at 360 px is a horizontal scroll nobody reads.
8
+ * There the list shows rows (a stacked card per record: the name, its state, its facts)
9
+ * and the board, and the switcher offers only those. It is the width of the list's own
10
+ * container that decides, not the window's: a narrow panel on a wide screen is narrow.
11
+ *
12
+ * Attach `frame` to the list's root element; `offered` is what the switcher may show and
13
+ * `present` what to draw (a wide one that was asked for falls back to rows).
14
+ */
15
+ export function useNarrowList(presents, requested) {
16
+ const frame = useRef(null);
17
+ const [narrow, setNarrow] = useState(false);
18
+ useEffect(() => {
19
+ const el = frame.current;
20
+ if (el === null || typeof ResizeObserver === "undefined")
21
+ return;
22
+ const watch = new ResizeObserver(([entry]) => {
23
+ if (entry !== undefined)
24
+ setNarrow(entry.contentRect.width < HANDHELD_WIDTH);
25
+ });
26
+ watch.observe(el);
27
+ return () => watch.disconnect();
28
+ }, []);
29
+ const offered = (presents ?? []).filter((p) => !narrow || !WIDE_PRESENTS.includes(p));
30
+ const present = narrow && WIDE_PRESENTS.includes(requested) ? "rows" : requested;
31
+ return { frame, offered, present };
32
+ }