@sincpro/web-ui 0.0.0-stage → 0.2.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 (376) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +184 -2
  3. package/dist/components/activity/Activity.d.ts +69 -0
  4. package/dist/components/activity/Activity.js +279 -0
  5. package/dist/components/activity/Messages.d.ts +66 -0
  6. package/dist/components/activity/Messages.js +46 -0
  7. package/dist/components/activity/Timeline.d.ts +21 -0
  8. package/dist/components/activity/Timeline.js +30 -0
  9. package/dist/components/activity/index.d.ts +3 -0
  10. package/dist/components/activity/index.js +4 -0
  11. package/dist/components/assist/AssistMark.d.ts +64 -0
  12. package/dist/components/assist/AssistMark.js +108 -0
  13. package/dist/components/assist/AssistPending.d.ts +24 -0
  14. package/dist/components/assist/AssistPending.js +26 -0
  15. package/dist/components/assist/AssistSuggestion.d.ts +42 -0
  16. package/dist/components/assist/AssistSuggestion.js +55 -0
  17. package/dist/components/assist/ChangeReview.d.ts +56 -0
  18. package/dist/components/assist/ChangeReview.js +121 -0
  19. package/dist/components/assist/assist.d.ts +77 -0
  20. package/dist/components/assist/assist.js +87 -0
  21. package/dist/components/assist/index.d.ts +5 -0
  22. package/dist/components/assist/index.js +7 -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 +47 -0
  26. package/dist/components/form/Sheet.js +90 -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 +111 -0
  40. package/dist/components/lines/LineItems.js +317 -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 +112 -0
  52. package/dist/components/listing/ListingBar.js +144 -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 +110 -0
  60. package/dist/components/listing/Row.js +123 -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 +75 -0
  96. package/dist/components/record/RecordHeader.js +104 -0
  97. package/dist/components/record/RecordNotices.d.ts +37 -0
  98. package/dist/components/record/RecordNotices.js +75 -0
  99. package/dist/components/record/RecordSkeleton.d.ts +3 -0
  100. package/dist/components/record/RecordSkeleton.js +21 -0
  101. package/dist/components/record/SmartButtons.d.ts +35 -0
  102. package/dist/components/record/SmartButtons.js +38 -0
  103. package/dist/components/record/StatusBar.d.ts +51 -0
  104. package/dist/components/record/StatusBar.js +168 -0
  105. package/dist/components/record/ThumbBar.d.ts +36 -0
  106. package/dist/components/record/ThumbBar.js +86 -0
  107. package/dist/components/record/index.d.ts +6 -0
  108. package/dist/components/record/index.js +8 -0
  109. package/dist/components/search/CriteriaBuilder.d.ts +58 -0
  110. package/dist/components/search/CriteriaBuilder.js +278 -0
  111. package/dist/components/search/CriteriaChips.d.ts +22 -0
  112. package/dist/components/search/CriteriaChips.js +64 -0
  113. package/dist/components/search/FilterBuilder.d.ts +142 -0
  114. package/dist/components/search/FilterBuilder.js +421 -0
  115. package/dist/components/search/JoinWord.d.ts +8 -0
  116. package/dist/components/search/JoinWord.js +47 -0
  117. package/dist/components/search/JsonEditor.d.ts +19 -0
  118. package/dist/components/search/JsonEditor.js +78 -0
  119. package/dist/components/search/SearchBar.d.ts +78 -0
  120. package/dist/components/search/SearchBar.js +387 -0
  121. package/dist/components/search/criteria.d.ts +116 -0
  122. package/dist/components/search/criteria.js +159 -0
  123. package/dist/components/search/datePeriods.d.ts +122 -0
  124. package/dist/components/search/datePeriods.js +134 -0
  125. package/dist/components/search/dateRanges.d.ts +54 -0
  126. package/dist/components/search/dateRanges.js +89 -0
  127. package/dist/components/search/index.d.ts +9 -0
  128. package/dist/components/search/index.js +20 -0
  129. package/dist/components/search/model.d.ts +54 -0
  130. package/dist/components/search/model.js +37 -0
  131. package/dist/components/search/query.d.ts +166 -0
  132. package/dist/components/search/query.js +436 -0
  133. package/dist/components/shell/AppFrame.d.ts +14 -0
  134. package/dist/components/shell/AppFrame.js +80 -0
  135. package/dist/components/shell/TopBar.d.ts +73 -0
  136. package/dist/components/shell/TopBar.js +54 -0
  137. package/dist/components/shell/headerSlot.d.ts +17 -0
  138. package/dist/components/shell/headerSlot.js +21 -0
  139. package/dist/components/shell/index.d.ts +2 -0
  140. package/dist/components/shell/index.js +3 -0
  141. package/dist/foundations/aria.d.ts +14 -0
  142. package/dist/foundations/aria.js +18 -0
  143. package/dist/foundations/calendar.d.ts +28 -0
  144. package/dist/foundations/calendar.js +183 -0
  145. package/dist/foundations/copy.d.ts +703 -0
  146. package/dist/foundations/copy.es.d.ts +2 -0
  147. package/dist/foundations/copy.es.js +430 -0
  148. package/dist/foundations/copy.js +520 -0
  149. package/dist/foundations/density.d.ts +16 -0
  150. package/dist/foundations/density.js +21 -0
  151. package/dist/foundations/grouping.d.ts +281 -0
  152. package/dist/foundations/grouping.js +0 -0
  153. package/dist/foundations/index.d.ts +14 -0
  154. package/dist/foundations/index.js +30 -0
  155. package/dist/foundations/layout.d.ts +9 -0
  156. package/dist/foundations/layout.js +9 -0
  157. package/dist/foundations/pivot.d.ts +222 -0
  158. package/dist/foundations/pivot.js +198 -0
  159. package/dist/foundations/pivotSheet.d.ts +61 -0
  160. package/dist/foundations/pivotSheet.js +0 -0
  161. package/dist/foundations/slots.d.ts +67 -0
  162. package/dist/foundations/slots.js +63 -0
  163. package/dist/foundations/sticky.d.ts +53 -0
  164. package/dist/foundations/sticky.js +150 -0
  165. package/dist/foundations/surface.d.ts +9 -0
  166. package/dist/foundations/surface.js +26 -0
  167. package/dist/foundations/theme.d.ts +42 -0
  168. package/dist/foundations/theme.js +88 -0
  169. package/dist/foundations/types.d.ts +23 -0
  170. package/dist/foundations/types.js +50 -0
  171. package/dist/foundations/variants.d.ts +19 -0
  172. package/dist/foundations/variants.js +48 -0
  173. package/dist/foundations/xlsx.d.ts +86 -0
  174. package/dist/foundations/xlsx.js +0 -0
  175. package/dist/index.d.ts +19 -0
  176. package/dist/index.js +19 -0
  177. package/dist/primitives/block/Block.d.ts +66 -0
  178. package/dist/primitives/block/Block.js +34 -0
  179. package/dist/primitives/block/Line.d.ts +18 -0
  180. package/dist/primitives/block/Line.js +45 -0
  181. package/dist/primitives/block/SectionGrid.d.ts +30 -0
  182. package/dist/primitives/block/SectionGrid.js +29 -0
  183. package/dist/primitives/block/Steps.d.ts +76 -0
  184. package/dist/primitives/block/Steps.js +43 -0
  185. package/dist/primitives/block/index.d.ts +4 -0
  186. package/dist/primitives/block/index.js +7 -0
  187. package/dist/primitives/button/Button.d.ts +137 -0
  188. package/dist/primitives/button/Button.js +234 -0
  189. package/dist/primitives/button/index.d.ts +1 -0
  190. package/dist/primitives/button/index.js +2 -0
  191. package/dist/primitives/cell/CellStack.d.ts +47 -0
  192. package/dist/primitives/cell/CellStack.js +33 -0
  193. package/dist/primitives/cell/index.d.ts +1 -0
  194. package/dist/primitives/cell/index.js +3 -0
  195. package/dist/primitives/choice/ComboBox.d.ts +19 -0
  196. package/dist/primitives/choice/ComboBox.js +52 -0
  197. package/dist/primitives/choice/RadioGroup.d.ts +18 -0
  198. package/dist/primitives/choice/RadioGroup.js +50 -0
  199. package/dist/primitives/choice/SearchField.d.ts +33 -0
  200. package/dist/primitives/choice/SearchField.js +46 -0
  201. package/dist/primitives/choice/SegmentedControl.d.ts +16 -0
  202. package/dist/primitives/choice/SegmentedControl.js +69 -0
  203. package/dist/primitives/choice/Slider.d.ts +16 -0
  204. package/dist/primitives/choice/Slider.js +46 -0
  205. package/dist/primitives/choice/Switch.d.ts +14 -0
  206. package/dist/primitives/choice/Switch.js +65 -0
  207. package/dist/primitives/choice/ThemeSwitcher.d.ts +10 -0
  208. package/dist/primitives/choice/ThemeSwitcher.js +25 -0
  209. package/dist/primitives/choice/index.d.ts +8 -0
  210. package/dist/primitives/choice/index.js +11 -0
  211. package/dist/primitives/choice/options.d.ts +28 -0
  212. package/dist/primitives/choice/options.js +6 -0
  213. package/dist/primitives/date/Calendar.d.ts +31 -0
  214. package/dist/primitives/date/Calendar.js +134 -0
  215. package/dist/primitives/date/DatePicker.d.ts +42 -0
  216. package/dist/primitives/date/DatePicker.js +103 -0
  217. package/dist/primitives/date/DateTime.d.ts +35 -0
  218. package/dist/primitives/date/DateTime.js +100 -0
  219. package/dist/primitives/date/index.d.ts +3 -0
  220. package/dist/primitives/date/index.js +6 -0
  221. package/dist/primitives/dialog/Dialog.d.ts +118 -0
  222. package/dist/primitives/dialog/Dialog.js +121 -0
  223. package/dist/primitives/dialog/Drill.d.ts +90 -0
  224. package/dist/primitives/dialog/Drill.js +172 -0
  225. package/dist/primitives/dialog/index.d.ts +2 -0
  226. package/dist/primitives/dialog/index.js +4 -0
  227. package/dist/primitives/disclosure/Disclosure.d.ts +36 -0
  228. package/dist/primitives/disclosure/Disclosure.js +52 -0
  229. package/dist/primitives/disclosure/index.d.ts +1 -0
  230. package/dist/primitives/disclosure/index.js +2 -0
  231. package/dist/primitives/field/Checks.d.ts +57 -0
  232. package/dist/primitives/field/Checks.js +72 -0
  233. package/dist/primitives/field/DropZone.d.ts +42 -0
  234. package/dist/primitives/field/DropZone.js +52 -0
  235. package/dist/primitives/field/Field.d.ts +178 -0
  236. package/dist/primitives/field/Field.js +251 -0
  237. package/dist/primitives/field/Suggest.d.ts +48 -0
  238. package/dist/primitives/field/Suggest.js +43 -0
  239. package/dist/primitives/field/aria.d.ts +61 -0
  240. package/dist/primitives/field/aria.js +70 -0
  241. package/dist/primitives/field/context.d.ts +30 -0
  242. package/dist/primitives/field/context.js +13 -0
  243. package/dist/primitives/field/copy.d.ts +16 -0
  244. package/dist/primitives/field/copy.js +69 -0
  245. package/dist/primitives/field/index.d.ts +9 -0
  246. package/dist/primitives/field/index.js +15 -0
  247. package/dist/primitives/field/layout.d.ts +24 -0
  248. package/dist/primitives/field/layout.js +10 -0
  249. package/dist/primitives/field/mode.d.ts +9 -0
  250. package/dist/primitives/field/mode.js +13 -0
  251. package/dist/primitives/field/note.d.ts +55 -0
  252. package/dist/primitives/field/note.js +117 -0
  253. package/dist/primitives/hint/Hint.d.ts +31 -0
  254. package/dist/primitives/hint/Hint.js +42 -0
  255. package/dist/primitives/hint/index.d.ts +1 -0
  256. package/dist/primitives/hint/index.js +1 -0
  257. package/dist/primitives/index.d.ts +20 -0
  258. package/dist/primitives/index.js +21 -0
  259. package/dist/primitives/menu/Menu.d.ts +128 -0
  260. package/dist/primitives/menu/Menu.js +89 -0
  261. package/dist/primitives/menu/index.d.ts +1 -0
  262. package/dist/primitives/menu/index.js +2 -0
  263. package/dist/primitives/notice/Callout.d.ts +49 -0
  264. package/dist/primitives/notice/Callout.js +28 -0
  265. package/dist/primitives/notice/Flag.d.ts +13 -0
  266. package/dist/primitives/notice/Flag.js +31 -0
  267. package/dist/primitives/notice/Notice.d.ts +45 -0
  268. package/dist/primitives/notice/Notice.js +61 -0
  269. package/dist/primitives/notice/Toast.d.ts +55 -0
  270. package/dist/primitives/notice/Toast.js +142 -0
  271. package/dist/primitives/notice/index.d.ts +4 -0
  272. package/dist/primitives/notice/index.js +6 -0
  273. package/dist/primitives/overlay/Popover.d.ts +6 -0
  274. package/dist/primitives/overlay/Popover.js +27 -0
  275. package/dist/primitives/overlay/PopoverTrigger.d.ts +55 -0
  276. package/dist/primitives/overlay/PopoverTrigger.js +38 -0
  277. package/dist/primitives/overlay/Preview.d.ts +19 -0
  278. package/dist/primitives/overlay/Preview.js +60 -0
  279. package/dist/primitives/overlay/Tooltip.d.ts +38 -0
  280. package/dist/primitives/overlay/Tooltip.js +74 -0
  281. package/dist/primitives/overlay/index.d.ts +4 -0
  282. package/dist/primitives/overlay/index.js +7 -0
  283. package/dist/primitives/picker/Picker.d.ts +89 -0
  284. package/dist/primitives/picker/Picker.js +204 -0
  285. package/dist/primitives/picker/index.d.ts +1 -0
  286. package/dist/primitives/picker/index.js +2 -0
  287. package/dist/primitives/surface/Peek.d.ts +60 -0
  288. package/dist/primitives/surface/Peek.js +71 -0
  289. package/dist/primitives/surface/index.d.ts +1 -0
  290. package/dist/primitives/surface/index.js +2 -0
  291. package/dist/primitives/table/CellCopy.d.ts +20 -0
  292. package/dist/primitives/table/CellCopy.js +23 -0
  293. package/dist/primitives/table/CellEditor.d.ts +14 -0
  294. package/dist/primitives/table/CellEditor.js +83 -0
  295. package/dist/primitives/table/DataTable.d.ts +189 -0
  296. package/dist/primitives/table/DataTable.js +330 -0
  297. package/dist/primitives/table/EditableTable.d.ts +191 -0
  298. package/dist/primitives/table/EditableTable.js +617 -0
  299. package/dist/primitives/table/PivotTable.d.ts +14 -0
  300. package/dist/primitives/table/PivotTable.js +0 -0
  301. package/dist/primitives/table/ReportTable.d.ts +38 -0
  302. package/dist/primitives/table/ReportTable.js +106 -0
  303. package/dist/primitives/table/RowActions.d.ts +16 -0
  304. package/dist/primitives/table/RowActions.js +28 -0
  305. package/dist/primitives/table/SheetTable.d.ts +73 -0
  306. package/dist/primitives/table/SheetTable.js +230 -0
  307. package/dist/primitives/table/Table.d.ts +106 -0
  308. package/dist/primitives/table/Table.js +116 -0
  309. package/dist/primitives/table/index.d.ts +7 -0
  310. package/dist/primitives/table/index.js +9 -0
  311. package/dist/primitives/tabs/Tabs.d.ts +91 -0
  312. package/dist/primitives/tabs/Tabs.js +56 -0
  313. package/dist/primitives/tabs/index.d.ts +1 -0
  314. package/dist/primitives/tabs/index.js +1 -0
  315. package/dist/primitives/tag/Tag.d.ts +36 -0
  316. package/dist/primitives/tag/Tag.js +68 -0
  317. package/dist/primitives/tag/Tags.d.ts +57 -0
  318. package/dist/primitives/tag/Tags.js +104 -0
  319. package/dist/primitives/tag/TagsField.d.ts +35 -0
  320. package/dist/primitives/tag/TagsField.js +186 -0
  321. package/dist/primitives/tag/choices.d.ts +38 -0
  322. package/dist/primitives/tag/choices.js +26 -0
  323. package/dist/primitives/tag/index.d.ts +4 -0
  324. package/dist/primitives/tag/index.js +8 -0
  325. package/dist/primitives/toolbar/Toolbar.d.ts +13 -0
  326. package/dist/primitives/toolbar/Toolbar.js +36 -0
  327. package/dist/primitives/toolbar/index.d.ts +1 -0
  328. package/dist/primitives/toolbar/index.js +2 -0
  329. package/dist/primitives/tree/Tree.d.ts +56 -0
  330. package/dist/primitives/tree/Tree.js +74 -0
  331. package/dist/primitives/tree/index.d.ts +1 -0
  332. package/dist/primitives/tree/index.js +3 -0
  333. package/dist/primitives/value/Copyable.d.ts +48 -0
  334. package/dist/primitives/value/Copyable.js +71 -0
  335. package/dist/primitives/value/Fecha.d.ts +12 -0
  336. package/dist/primitives/value/Fecha.js +89 -0
  337. package/dist/primitives/value/Meter.d.ts +29 -0
  338. package/dist/primitives/value/Meter.js +46 -0
  339. package/dist/primitives/value/Metric.d.ts +42 -0
  340. package/dist/primitives/value/Metric.js +38 -0
  341. package/dist/primitives/value/Person.d.ts +90 -0
  342. package/dist/primitives/value/Person.js +208 -0
  343. package/dist/primitives/value/ProgressBar.d.ts +31 -0
  344. package/dist/primitives/value/ProgressBar.js +53 -0
  345. package/dist/primitives/value/Relation.d.ts +74 -0
  346. package/dist/primitives/value/Relation.js +74 -0
  347. package/dist/primitives/value/Totals.d.ts +121 -0
  348. package/dist/primitives/value/Totals.js +54 -0
  349. package/dist/primitives/value/Value.d.ts +40 -0
  350. package/dist/primitives/value/Value.js +80 -0
  351. package/dist/primitives/value/index.d.ts +9 -0
  352. package/dist/primitives/value/index.js +10 -0
  353. package/dist/tokens.css +1062 -0
  354. package/dist/views/index.d.ts +2 -0
  355. package/dist/views/index.js +3 -0
  356. package/dist/views/list/List.d.ts +119 -0
  357. package/dist/views/list/List.js +101 -0
  358. package/dist/views/list/ListView.d.ts +6 -0
  359. package/dist/views/list/ListView.js +295 -0
  360. package/dist/views/list/columns.d.ts +18 -0
  361. package/dist/views/list/columns.js +27 -0
  362. package/dist/views/list/derive.d.ts +87 -0
  363. package/dist/views/list/derive.js +207 -0
  364. package/dist/views/list/index.d.ts +2 -0
  365. package/dist/views/list/index.js +4 -0
  366. package/dist/views/list/presentations.d.ts +39 -0
  367. package/dist/views/list/presentations.js +105 -0
  368. package/dist/views/list/types.d.ts +284 -0
  369. package/dist/views/list/types.js +1 -0
  370. package/dist/views/list/useNarrowList.d.ts +17 -0
  371. package/dist/views/list/useNarrowList.js +32 -0
  372. package/dist/views/record/Record.d.ts +145 -0
  373. package/dist/views/record/Record.js +211 -0
  374. package/dist/views/record/index.d.ts +1 -0
  375. package/dist/views/record/index.js +2 -0
  376. package/package.json +113 -4
@@ -0,0 +1,43 @@
1
+ "use client";
2
+ import { useCallback, useMemo, useState } from "react";
3
+ export function useSelection(visible) {
4
+ const [chosen, setChosen] = useState(new Set());
5
+ const allState = useMemo(() => {
6
+ if (visible.length === 0)
7
+ return false;
8
+ const inside = visible.filter((id) => chosen.has(id)).length;
9
+ if (inside === 0)
10
+ return false;
11
+ return inside === visible.length ? true : "some";
12
+ }, [visible, chosen]);
13
+ const toggle = useCallback((id) => {
14
+ setChosen((current) => {
15
+ const next = new Set(current);
16
+ if (next.has(id))
17
+ next.delete(id);
18
+ else
19
+ next.add(id);
20
+ return next;
21
+ });
22
+ }, []);
23
+ const toggleAll = useCallback(() => {
24
+ setChosen((current) => {
25
+ const inside = visible.filter((id) => current.has(id)).length;
26
+ const next = new Set(current);
27
+ if (inside === visible.length)
28
+ visible.forEach((id) => next.delete(id));
29
+ else
30
+ visible.forEach((id) => next.add(id));
31
+ return next;
32
+ });
33
+ }, [visible]);
34
+ return {
35
+ chosen,
36
+ count: chosen.size,
37
+ has: (id) => chosen.has(id),
38
+ toggle,
39
+ toggleAll,
40
+ allState,
41
+ clear: () => setChosen(new Set()),
42
+ };
43
+ }
@@ -0,0 +1,48 @@
1
+ import { type Pages } from "./pages.js";
2
+ /**
3
+ * How a SET is looked at: which presentation, how many fit on a page.
4
+ *
5
+ * ListView and every catalog-like screen were inventing these two pieces of
6
+ * state on their own. They belong together because they answer the same
7
+ * question — «how do I look at N?» — whether N is domain records or the
8
+ * page of a frame.
9
+ *
10
+ * `Present` is generic so a list (`ListPresent`) and a frame (`table` |
11
+ * `chart`) share the hook without importing each other's unions.
12
+ *
13
+ * Controlled when the view context keeps them (catalog filters must not
14
+ * reset the page size). Uncontrolled when the screen is the only owner.
15
+ */
16
+ /**
17
+ * Las maneras de mirar un conjunto. **Vive acá y no en el arquetipo** porque
18
+ * son dos los que preguntan lo mismo —una lista y un marco— y la definición
19
+ * tiene que ser una sola.
20
+ *
21
+ * Era dos: `ListPresent` en `archetype/ListView.tsx` y esta copia. Mientras las
22
+ * dos decían `rows | table | board` nadie lo notaba; agregar `sheet` a una dejó
23
+ * cuatro vistas sin compilar, que es exactamente lo que pasa cuando la misma
24
+ * idea está escrita dos veces.
25
+ *
26
+ * rows / board no hay columnas: nombre, fichas y meta.
27
+ * table las columnas las DECLARA el código.
28
+ * sheet las columnas salen del ARCHIVO — puede haber cuarenta y un
29
+ * millón de filas, así que va virtualizada.
30
+ * report columnas de período y filas en JERARQUÍA que termina en
31
+ * totales. No se ordena: el orden ES el informe.
32
+ * pivot dos EJES a la vez. Una fila es un montón y una columna
33
+ * también; lo que se lee está en el cruce. Tampoco se
34
+ * ordena: el orden de cada eje es el de sus claves.
35
+ */
36
+ export type ListPresent = "rows" | "table" | "board" | "sheet" | "report" | "pivot";
37
+ export interface SetControl<Row, Present extends string = ListPresent> extends Pages<Row> {
38
+ present: Present;
39
+ setPresent: (next: Present) => void;
40
+ pageSize: number;
41
+ setPageSize: (next: number) => void;
42
+ }
43
+ export declare function useSetControl<Row, Present extends string = ListPresent>(items: readonly Row[], options?: {
44
+ present?: Present;
45
+ onPresentChange?: (next: Present) => void;
46
+ pageSize?: number;
47
+ onPageSizeChange?: (next: number) => void;
48
+ }): SetControl<Row, Present>;
@@ -0,0 +1,24 @@
1
+ "use client";
2
+ import { DEFAULT_PAGE_SIZE, usePagination, } from "./pages.js";
3
+ import { useState } from "react";
4
+ export function useSetControl(items, options = {}) {
5
+ const initialPresent = (options.present ?? "table");
6
+ const [ownedPresent, setOwnedPresent] = useState(initialPresent);
7
+ const [ownedSize, setOwnedSize] = useState(options.pageSize ?? DEFAULT_PAGE_SIZE);
8
+ const presentControlled = options.onPresentChange !== undefined;
9
+ const present = presentControlled
10
+ ? (options.present ?? "table")
11
+ : ownedPresent;
12
+ const setPresent = presentControlled ? options.onPresentChange : setOwnedPresent;
13
+ const sizeControlled = options.onPageSizeChange !== undefined;
14
+ const pageSize = sizeControlled ? (options.pageSize ?? DEFAULT_PAGE_SIZE) : ownedSize;
15
+ const setPageSize = sizeControlled ? options.onPageSizeChange : setOwnedSize;
16
+ const pages = usePagination(items, { pageSize, onPageSizeChange: setPageSize });
17
+ return {
18
+ ...pages,
19
+ present,
20
+ setPresent,
21
+ pageSize,
22
+ setPageSize,
23
+ };
24
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Which BRANCHES of a set are closed.
3
+ *
4
+ * Grouping is the tree: a list split by customer, a table with expandable
5
+ * group rows, a board with the same headers. The collapsed keys belong to the
6
+ * SET, not to one presentation — switching from rows to table must not reopen
7
+ * what the user just closed.
8
+ *
9
+ * **A key here is a pile's PATH**, serialized with `pathKey()`. With one level a
10
+ * plain key was enough, because no two piles could be called the same. With N
11
+ * levels they can: «2026-09» is one month inside «Ferretería Sur» and another inside
12
+ * «Distribuidora Andina», and folding one must not fold the other. What tells them apart is
13
+ * the route that leads to each, so that is what is stored.
14
+ *
15
+ * A hierarchical parent/child present would use the same keys. There is no
16
+ * fourth archetype for «tree»: collapse is how N is folded, the same way
17
+ * pagination is how N is cut.
18
+ */
19
+ export type TreeControl = {
20
+ collapsed: readonly string[];
21
+ isOpen: (key: string) => boolean;
22
+ toggle: (key: string) => void;
23
+ };
24
+ export declare function toggleCollapsed(collapsed: readonly string[], key: string): string[];
25
+ export declare function useTreeControl(options?: {
26
+ collapsed?: readonly string[];
27
+ onCollapsedChange?: (keys: readonly string[]) => void;
28
+ }): TreeControl;
@@ -0,0 +1,23 @@
1
+ "use client";
2
+ import { useCallback, useState } from "react";
3
+ export function toggleCollapsed(collapsed, key) {
4
+ return collapsed.includes(key)
5
+ ? collapsed.filter((one) => one !== key)
6
+ : [...collapsed, key];
7
+ }
8
+ // One empty array for every render: a fresh `[]` would change `toggle` each time.
9
+ const NONE_COLLAPSED = [];
10
+ export function useTreeControl(options = {}) {
11
+ const [owned, setOwned] = useState(options.collapsed ?? NONE_COLLAPSED);
12
+ const controlled = options.onCollapsedChange !== undefined;
13
+ const collapsed = controlled ? (options.collapsed ?? NONE_COLLAPSED) : owned;
14
+ const setCollapsed = controlled ? options.onCollapsedChange : setOwned;
15
+ const toggle = useCallback((key) => {
16
+ setCollapsed(toggleCollapsed(collapsed, key));
17
+ }, [collapsed, setCollapsed]);
18
+ return {
19
+ collapsed,
20
+ isOpen: (key) => collapsed.includes(key) !== true,
21
+ toggle,
22
+ };
23
+ }
@@ -0,0 +1,40 @@
1
+ import { type PaletteCommand } from "./commands.js";
2
+ /**
3
+ * The search box and the list, without the modal around them.
4
+ *
5
+ * Context: split out so the filtering can be rendered on its own — in a test, with a query
6
+ * already typed — since the modal is a portal that only exists in a browser.
7
+ */
8
+ export declare function CommandSearch({ commands, onRun, query, onQueryChange, placeholder, }: {
9
+ commands: readonly PaletteCommand[];
10
+ onRun: (id: string) => void;
11
+ query?: string;
12
+ onQueryChange?: (next: string) => void;
13
+ placeholder?: string;
14
+ }): import("react").JSX.Element;
15
+ /**
16
+ * A modal search over everything the app can do — go to a screen, create a record — opened
17
+ * with ⌘K (Ctrl+K) and run with Enter.
18
+ *
19
+ * Context: it is controlled (`open`, `onOpenChange`) and does not bind the shortcut itself,
20
+ * because an app has ONE palette and many screens: the key is bound once, where the palette
21
+ * lives, with `useCommandPaletteShortcut`. Running a command closes it — the palette is a
22
+ * path, not a place to stay.
23
+ */
24
+ export declare function CommandPalette({ open, onOpenChange, commands, onRun, placeholder, }: {
25
+ open: boolean;
26
+ onOpenChange: (open: boolean) => void;
27
+ commands: readonly PaletteCommand[];
28
+ /** A command was chosen. The palette closes on its own. */
29
+ onRun: (id: string) => void;
30
+ /** The search box's prompt and its accessible name. By default, the copy table's. */
31
+ placeholder?: string;
32
+ }): import("react").JSX.Element;
33
+ /**
34
+ * Binds ⌘K (Ctrl+K on Windows and Linux) to open the palette, anywhere in the page.
35
+ *
36
+ * Context: both modifiers are accepted on every platform. Telling them apart by the user
37
+ * agent guesses wrong on a Mac with a PC keyboard, and the cost of accepting both is that
38
+ * Ctrl+K on a Mac — «delete to the end of the line» in a text box — opens the palette.
39
+ */
40
+ export declare function useCommandPaletteShortcut(setOpen: (open: boolean) => void): void;
@@ -0,0 +1,114 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { commandMatches, groupCommands, } from "./commands.js";
4
+ import { AriaLocale } from "../../foundations/aria.js";
5
+ import { useUiCopy } from "../../foundations/copy.js";
6
+ import { tv } from "../../foundations/variants.js";
7
+ import { Search, X } from "lucide-react";
8
+ import { useEffect, useMemo } from "react";
9
+ import { Autocomplete, Button as AriaButton, Dialog, Header, Input, Keyboard, Menu, MenuItem, MenuSection, Modal, ModalOverlay, SearchField, useFilter, } from "react-aria-components";
10
+ /* ==================================================================== *
11
+ * COMMAND PALETTE — ⌘K, type three letters, Enter.
12
+ *
13
+ * An ERP has a hundred screens and twenty «new» buttons, and the people who
14
+ * use it all day stop wanting to look for any of them: they know the name of
15
+ * what they want. The palette is the shortest path from knowing the name to
16
+ * being there — one key to open, a few letters, Enter — without leaving the
17
+ * keyboard and without knowing in which menu of which module it lives.
18
+ *
19
+ * ┌──────────────────────────────────────────────┐
20
+ * │ 🔍 fact ✕ │
21
+ * ├──────────────────────────────────────────────┤
22
+ * │ IR A… │
23
+ * │ ▌🧾 Facturas │ ← Enter runs it
24
+ * │ CREAR… │
25
+ * │ + Nueva factura ⌘N │
26
+ * └──────────────────────────────────────────────┘
27
+ *
28
+ * React Aria's `Autocomplete` drives it: focus stays in the search box while
29
+ * the arrows walk the list (virtual focus), the first match is highlighted as
30
+ * you type so Enter always does something, and the modal traps focus, closes
31
+ * on Escape and on a click outside, and gives the focus back.
32
+ *
33
+ * The match is the locale's (`useFilter` inside `AriaLocale`): «facturacion»
34
+ * finds «Facturación» because nobody types the accent when they are in a hurry.
35
+ * ==================================================================== */
36
+ const overlay = tv({
37
+ base: "fixed inset-0 z-50 flex items-start justify-center overflow-y-auto bg-scrim/40 px-4 pt-24 transition-opacity duration-(--duration-quick) ease-(--ease-out)",
38
+ variants: {
39
+ isEntering: { true: "opacity-0" },
40
+ isExiting: { true: "opacity-0" },
41
+ },
42
+ });
43
+ const surface = tv({
44
+ base: "w-full max-w-xl overflow-hidden rounded-panel border border-line-strong bg-surface text-ink shadow-window outline-0 transition-[opacity,translate] duration-(--duration-quick) ease-(--ease-out) forced-colors:bg-[Canvas]",
45
+ variants: {
46
+ isEntering: { true: "-translate-y-1 opacity-0" },
47
+ isExiting: { true: "opacity-0" },
48
+ },
49
+ });
50
+ const item = tv({
51
+ base: "flex cursor-default items-center gap-2 rounded-control px-2 py-1.5 text-meta text-ink outline-0 select-none",
52
+ variants: {
53
+ isFocused: {
54
+ true: "bg-primary/8 forced-colors:bg-[Highlight] forced-colors:text-[HighlightText]",
55
+ },
56
+ isPressed: { true: "bg-primary/12" },
57
+ isDisabled: { true: "text-muted forced-colors:text-[GrayText]" },
58
+ },
59
+ });
60
+ /**
61
+ * The search box and the list, without the modal around them.
62
+ *
63
+ * Context: split out so the filtering can be rendered on its own — in a test, with a query
64
+ * already typed — since the modal is a portal that only exists in a browser.
65
+ */
66
+ export function CommandSearch({ commands, onRun, query, onQueryChange, placeholder, }) {
67
+ const copy = useUiCopy();
68
+ const { contains } = useFilter({ sensitivity: "base" });
69
+ const byId = useMemo(() => new Map(commands.map((c) => [c.id, c])), [commands]);
70
+ const groups = useMemo(() => groupCommands(commands), [commands]);
71
+ const hint = placeholder ?? copy.search.placeholder;
72
+ return (_jsxs(Autocomplete, { ...(query === undefined ? {} : { inputValue: query }), ...(onQueryChange === undefined ? {} : { onInputChange: onQueryChange }), filter: (_text, input, node) => {
73
+ const command = byId.get(String(node.key));
74
+ return command === undefined || commandMatches(command, input, contains);
75
+ }, children: [_jsxs(SearchField, { "aria-label": hint, autoFocus: true, className: "group flex items-center gap-2 border-b border-line px-3", children: [_jsx(Search, { className: "size-(--size-icon-md) shrink-0 text-muted", strokeWidth: 2, "aria-hidden": true }), _jsx(Input, { placeholder: hint, className: "h-(--size-control-lg) min-w-0 flex-1 bg-transparent text-body text-ink outline-0 placeholder:text-muted [&::-webkit-search-cancel-button]:hidden" }), _jsx(AriaButton, { className: "inline-flex shrink-0 items-center justify-center rounded-mark p-1 text-muted transition-colors duration-(--duration-instant) group-empty:invisible hover:bg-ink/6 hover:text-ink pressed:bg-ink/10", children: _jsx(X, { className: "size-(--size-icon-md)", strokeWidth: 2, "aria-hidden": true }) })] }), _jsx(Menu, { "aria-label": hint, onAction: (key) => onRun(String(key)), renderEmptyState: () => (_jsx("p", { className: "px-3 py-6 text-center text-meta text-muted italic", children: copy.menu.empty })), className: "max-h-96 overflow-y-auto p-1 outline-0", children: groups.map((group) => (_jsxs(MenuSection, { id: group.section ?? "-", className: "not-first:mt-1", children: [group.section === undefined ? null : (_jsx(Header, { className: "px-2 pt-2 pb-1 text-micro font-medium text-muted", children: group.section })), group.commands.map((command) => {
76
+ const Icon = command.icon;
77
+ return (_jsxs(MenuItem, { id: command.id, textValue: command.label, className: item, children: [_jsx("span", { className: "flex size-(--size-icon-md) shrink-0 items-center justify-center text-muted", children: Icon === undefined ? null : (_jsx(Icon, { className: "size-(--size-icon-md)", strokeWidth: 2, "aria-hidden": true })) }), _jsx("span", { className: "min-w-0 flex-1 truncate", children: command.label }), command.shortcut === undefined ? null : (_jsx(Keyboard, { className: "shrink-0 rounded-mark border border-line px-1.5 font-sans text-micro text-muted tabular-nums", children: command.shortcut }))] }, command.id));
78
+ })] }, group.section ?? ""))) })] }));
79
+ }
80
+ /**
81
+ * A modal search over everything the app can do — go to a screen, create a record — opened
82
+ * with ⌘K (Ctrl+K) and run with Enter.
83
+ *
84
+ * Context: it is controlled (`open`, `onOpenChange`) and does not bind the shortcut itself,
85
+ * because an app has ONE palette and many screens: the key is bound once, where the palette
86
+ * lives, with `useCommandPaletteShortcut`. Running a command closes it — the palette is a
87
+ * path, not a place to stay.
88
+ */
89
+ export function CommandPalette({ open, onOpenChange, commands, onRun, placeholder, }) {
90
+ const copy = useUiCopy();
91
+ return (_jsx(AriaLocale, { children: _jsx(ModalOverlay, { isOpen: open, onOpenChange: onOpenChange, isDismissable: true, className: overlay, children: _jsx(Modal, { className: surface, children: _jsx(Dialog, { "aria-label": placeholder ?? copy.search.placeholder, className: "outline-0", children: _jsx(CommandSearch, { commands: commands, onRun: (id) => {
92
+ onOpenChange(false);
93
+ onRun(id);
94
+ }, ...(placeholder === undefined ? {} : { placeholder }) }) }) }) }) }));
95
+ }
96
+ /**
97
+ * Binds ⌘K (Ctrl+K on Windows and Linux) to open the palette, anywhere in the page.
98
+ *
99
+ * Context: both modifiers are accepted on every platform. Telling them apart by the user
100
+ * agent guesses wrong on a Mac with a PC keyboard, and the cost of accepting both is that
101
+ * Ctrl+K on a Mac — «delete to the end of the line» in a text box — opens the palette.
102
+ */
103
+ export function useCommandPaletteShortcut(setOpen) {
104
+ useEffect(() => {
105
+ const onKey = (e) => {
106
+ if (e.key.toLowerCase() !== "k" || !(e.metaKey || e.ctrlKey) || e.altKey)
107
+ return;
108
+ e.preventDefault();
109
+ setOpen(true);
110
+ };
111
+ document.addEventListener("keydown", onKey);
112
+ return () => document.removeEventListener("keydown", onKey);
113
+ }, [setOpen]);
114
+ }
@@ -0,0 +1,31 @@
1
+ import { type LucideIcon } from "lucide-react";
2
+ /** One entry of the sidebar. With `children` it is a module that opens and closes; without,
3
+ * it is a screen you go to. */
4
+ export interface NavItem {
5
+ id: string;
6
+ label: string;
7
+ icon?: LucideIcon;
8
+ /** What is waiting there: drafts, overdue, to approve. Zero is not drawn — a «0» beside
9
+ * every quiet screen is a column of noise the eye has to read to learn nothing. */
10
+ count?: number;
11
+ children?: readonly NavItem[];
12
+ }
13
+ /**
14
+ * The sidebar of an ERP module: modules that open and close, the screens inside them with
15
+ * an icon and what is waiting there, and the row you are on marked.
16
+ *
17
+ * Context: the modules on the way to `current` start open even when `defaultExpanded` does
18
+ * not name them. A sidebar that loads with the current screen folded away answers «where am
19
+ * I» with a closed module, and that is the whole question it exists for.
20
+ */
21
+ export declare function NavigationTree({ items, current, onNavigate, defaultExpanded, label, }: {
22
+ items: readonly NavItem[];
23
+ /** The id of the screen on view. */
24
+ current?: string;
25
+ /** A screen was chosen — by click, Enter, or the keyboard. Modules only open and close. */
26
+ onNavigate?: (id: string) => void;
27
+ /** The modules that start open. The path to `current` is always added. */
28
+ defaultExpanded?: readonly string[];
29
+ /** The accessible name of the tree. By default, the copy table's name for a module's menus. */
30
+ label?: string;
31
+ }): import("react").JSX.Element;
@@ -0,0 +1,79 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { AriaLocale } from "../../foundations/aria.js";
4
+ import { useUiCopy } from "../../foundations/copy.js";
5
+ import { focusRing, tv } from "../../foundations/variants.js";
6
+ import { ChevronRight } from "lucide-react";
7
+ import { useMemo } from "react";
8
+ import { Button as AriaButton, Link, NavigationTree as AriaNavigationTree, NavigationTreeItem as AriaNavigationTreeItem, NavigationTreeItemContent, RouterProvider, } from "react-aria-components";
9
+ const row = tv({
10
+ extend: focusRing,
11
+ base: "group relative flex min-w-0 items-center rounded-control text-meta text-ink outline-offset-0 select-none",
12
+ variants: {
13
+ isCurrent: {
14
+ true: "bg-primary/10 font-medium text-primary forced-colors:bg-[Highlight] forced-colors:text-[HighlightText]",
15
+ false: "hover:bg-ink/6",
16
+ },
17
+ },
18
+ });
19
+ const link = tv({
20
+ base: "flex h-(--size-control-sm) min-w-0 flex-1 cursor-pointer items-center gap-2 px-2 text-current no-underline outline-0",
21
+ variants: {
22
+ isModule: { true: "font-medium" },
23
+ },
24
+ });
25
+ const chevronButton = tv({
26
+ extend: focusRing,
27
+ base: "mr-1 inline-flex shrink-0 items-center justify-center rounded-mark p-1 text-muted transition-colors duration-(--duration-instant) hover:bg-ink/6 hover:text-ink pressed:bg-ink/10",
28
+ });
29
+ /** The marker of the current row: a bar on the leading edge, so the spot reads in the
30
+ * margin before the label is read. */
31
+ const marker = "absolute inset-y-1 start-0 w-0.5 rounded-pill bg-primary forced-colors:bg-[HighlightText]";
32
+ /** The ids of every module on the way to `id`, so the row you are on is never folded away. */
33
+ function pathTo(items, id) {
34
+ if (id === undefined)
35
+ return [];
36
+ for (const item of items) {
37
+ if (item.id === id)
38
+ return [];
39
+ if (item.children === undefined)
40
+ continue;
41
+ const below = pathTo(item.children, id);
42
+ if (below.length > 0 || item.children.some((c) => c.id === id))
43
+ return [item.id, ...below];
44
+ }
45
+ return [];
46
+ }
47
+ /**
48
+ * The sidebar of an ERP module: modules that open and close, the screens inside them with
49
+ * an icon and what is waiting there, and the row you are on marked.
50
+ *
51
+ * Context: the modules on the way to `current` start open even when `defaultExpanded` does
52
+ * not name them. A sidebar that loads with the current screen folded away answers «where am
53
+ * I» with a closed module, and that is the whole question it exists for.
54
+ */
55
+ export function NavigationTree({ items, current, onNavigate, defaultExpanded = [], label, }) {
56
+ const copy = useUiCopy();
57
+ const number = useMemo(() => new Intl.NumberFormat(copy.locale), [copy.locale]);
58
+ const expanded = useMemo(() => [...new Set([...defaultExpanded, ...pathTo(items, current)])],
59
+ // The initial state only: React Aria owns the expansion after the first render.
60
+ // eslint-disable-next-line react-hooks/exhaustive-deps
61
+ []);
62
+ const render = (item, level) => {
63
+ const children = item.children ?? [];
64
+ const module = children.length > 0;
65
+ const Icon = item.icon;
66
+ /* The first step in puts a screen's label on the vertical of its module's label —
67
+ past the module's icon column — so a module and its screens read as one list of
68
+ words. Every step deeper is the system's nesting step. */
69
+ const indent = level > 1
70
+ ? {
71
+ paddingInlineStart: `calc(var(--spacing) * 4 + var(--size-icon-md) + var(--spacing-indent) * ${level - 2})`,
72
+ }
73
+ : undefined;
74
+ return (_jsxs(AriaNavigationTreeItem, { id: item.id, textValue: item.label, ...(module ? {} : { href: item.id }), className: ({ isCurrent, isFocusVisible }) => row({ isCurrent, isFocusVisible }), children: [_jsx(NavigationTreeItemContent, { children: ({ isCurrent, isCurrentAncestor, isExpanded }) => (_jsxs(_Fragment, { children: [isCurrent ? _jsx("span", { "aria-hidden": true, className: marker }) : null, _jsxs(Link, { className: link({ isModule: module }), style: indent, children: [Icon === undefined ? null : (_jsx(Icon, { className: `size-(--size-icon-md) shrink-0 ${isCurrent || (isCurrentAncestor && !isExpanded)
75
+ ? "text-primary"
76
+ : "text-muted"}`, strokeWidth: 2, "aria-hidden": true })), _jsx("span", { className: `min-w-0 flex-1 truncate ${isCurrentAncestor && !isExpanded ? "text-primary" : ""}`, children: item.label }), item.count === undefined || item.count <= 0 ? null : (_jsx("span", { className: `shrink-0 rounded-pill px-1.5 text-micro leading-normal font-medium tabular-nums ${isCurrent ? "bg-primary/12 text-primary" : "bg-ink/6 text-muted"}`, children: number.format(item.count) }))] }), module ? (_jsx(AriaButton, { slot: "chevron", className: ({ isFocusVisible }) => chevronButton({ isFocusVisible }), children: _jsx(ChevronRight, { className: `size-(--size-icon-sm) transition-transform duration-(--duration-quick) ease-(--ease-out) ${isExpanded ? "rotate-90" : ""}`, strokeWidth: 2, "aria-hidden": true }) })) : null] })) }), children.map((child) => render(child, level + 1))] }, item.id));
77
+ };
78
+ return (_jsx(AriaLocale, { children: _jsx(RouterProvider, { navigate: (id) => onNavigate?.(id), useHref: (id) => `#${id}`, children: _jsx(AriaNavigationTree, { "aria-label": label ?? copy.shell.menus, selectedRoute: current ?? null, defaultExpandedKeys: expanded, className: "flex w-full min-w-0 flex-col gap-px p-2 outline-0", children: items.map((item) => render(item, 1)) }) }) }));
79
+ }
@@ -0,0 +1,30 @@
1
+ import type { LucideIcon } from "lucide-react";
2
+ /** Something the palette can run: go to a screen, create a record, open a report. */
3
+ export interface PaletteCommand {
4
+ id: string;
5
+ label: string;
6
+ /** The heading it is listed under: «Ir a…», «Crear…». Commands without one go first,
7
+ * without a heading. */
8
+ section?: string;
9
+ icon?: LucideIcon;
10
+ /** The key that runs it without the palette, as it should be read: «⌘N», «Alt+F». It is
11
+ * only drawn — the palette is where the shortcut gets learned, not where it is bound. */
12
+ shortcut?: string;
13
+ /** Other words that should find it: «factura» finds «Nueva venta» when the people who use
14
+ * it call it that. */
15
+ keywords?: readonly string[];
16
+ }
17
+ /** The commands under each heading, headings in the order they first appear. */
18
+ export declare function groupCommands(commands: readonly PaletteCommand[]): {
19
+ section: string | undefined;
20
+ commands: PaletteCommand[];
21
+ }[];
22
+ /**
23
+ * Whether a command answers a query. `contains` is the locale's comparison — React Aria's
24
+ * `useFilter` in the palette — so «facturacion» finds «Facturación» and an uppercase query
25
+ * finds a lowercase label.
26
+ *
27
+ * Every word of the query has to appear, in any order, in the label or the keywords:
28
+ * «nueva fac» finds «Nueva factura», and so does «factura nueva».
29
+ */
30
+ export declare function commandMatches(command: PaletteCommand, query: string, contains: (text: string, part: string) => boolean): boolean;
@@ -0,0 +1,30 @@
1
+ /** The commands under each heading, headings in the order they first appear. */
2
+ export function groupCommands(commands) {
3
+ const groups = new Map();
4
+ /* The commands with no heading are listed first, wherever they were written. */
5
+ if (commands.some((c) => c.section === undefined))
6
+ groups.set(undefined, []);
7
+ for (const command of commands) {
8
+ const group = groups.get(command.section);
9
+ if (group === undefined)
10
+ groups.set(command.section, [command]);
11
+ else
12
+ group.push(command);
13
+ }
14
+ return [...groups].map(([section, list]) => ({ section, commands: list }));
15
+ }
16
+ /**
17
+ * Whether a command answers a query. `contains` is the locale's comparison — React Aria's
18
+ * `useFilter` in the palette — so «facturacion» finds «Facturación» and an uppercase query
19
+ * finds a lowercase label.
20
+ *
21
+ * Every word of the query has to appear, in any order, in the label or the keywords:
22
+ * «nueva fac» finds «Nueva factura», and so does «factura nueva».
23
+ */
24
+ export function commandMatches(command, query, contains) {
25
+ const words = query.trim().split(/\s+/).filter(Boolean);
26
+ if (words.length === 0)
27
+ return true;
28
+ const haystack = [command.label, ...(command.keywords ?? [])].join(" ");
29
+ return words.every((word) => contains(haystack, word));
30
+ }
@@ -0,0 +1,3 @@
1
+ export { CommandPalette, useCommandPaletteShortcut, } from "./CommandPalette.js";
2
+ export { type PaletteCommand } from "./commands.js";
3
+ export { NavigationTree, type NavItem, } from "./NavigationTree.js";
@@ -0,0 +1,4 @@
1
+ /* LA NAVEGACIÓN — el árbol lateral de una aplicación y la paleta de comandos. */
2
+ export { CommandPalette, useCommandPaletteShortcut, } from "./CommandPalette.js";
3
+ export {} from "./commands.js";
4
+ export { NavigationTree, } from "./NavigationTree.js";
@@ -0,0 +1,42 @@
1
+ import type { Surface } from "../../foundations/types.js";
2
+ export interface Crumb {
3
+ label: string;
4
+ /** Absent on the last one: the place you are already at cannot be pressed. */
5
+ onClick?: () => void;
6
+ }
7
+ /**
8
+ * Where I came from, without eating the line.
9
+ *
10
+ * Built on React Aria's `Breadcrumbs`: the LAST crumb is the page I am on, so it
11
+ * gets `aria-current="page"` and stops being pressable — React Aria decides that
12
+ * from its position, not from whether the caller forgot an `onClick`. The others
13
+ * are `Link`s, so they press with Enter, show the system focus ring only from the
14
+ * keyboard, and read as links to a screen reader.
15
+ *
16
+ * **The hierarchy is in the TONE, not in a color.** Ancestors are quiet
17
+ * (`text-muted`), the current page is ink and medium weight: the eye lands on where
18
+ * I am and reads backwards. Painting the ancestors in the link blue made the whole
19
+ * row the same weight — four blue words and no «here».
20
+ *
21
+ * Two things keep it inside its place, and they are two because they are two
22
+ * different problems:
23
+ *
24
+ * 1. **Each crumb asks for `--container-crumb` and no more.** A name in this
25
+ * product reaches fifty characters, so one crumb is enough to eat the band even
26
+ * when the trail has three. The rest is cut with «…» and the full name stays in
27
+ * the `title`.
28
+ * 2. **With more than `folded` crumbs, the MIDDLE ones fold** into a «…» menu.
29
+ * By COUNT, not by width: a six-crumb trail is long on any screen. The first
30
+ * —the root, where you go back to— and the last —where I am— never fold, and
31
+ * what folded is still navigable, in order.
32
+ *
33
+ * Folding and truncating are not the same and that is why both exist: one removes
34
+ * CRUMBS and the other removes LETTERS.
35
+ */
36
+ export declare function Breadcrumb({ crumbs, surface: surfaceProp, folded, }: {
37
+ crumbs: readonly Crumb[];
38
+ surface?: Surface;
39
+ /** From how many crumbs the middle folds. Below this every crumb is drawn:
40
+ * folding two crumbs hides half the trail to save one chevron. */
41
+ folded?: number;
42
+ }): import("react").JSX.Element;