@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,128 @@
1
+ import { type ButtonRole, type ButtonSize } from "../button/Button.js";
2
+ import type { LucideIcon } from "lucide-react";
3
+ import type { ReactNode } from "react";
4
+ import { type Key } from "react-aria-components";
5
+ export interface MenuOption {
6
+ id: string;
7
+ label: string;
8
+ /** The line below. It exists because a thirty-entry menu without hints forces
9
+ * you to open each one to discover what it does. */
10
+ hint?: string;
11
+ icon?: LucideIcon;
12
+ /** For the menus that CHOOSE (group by, favorites) instead of executing. */
13
+ checked?: boolean;
14
+ /** A hairline ABOVE this option. It separates the three rows of a date —months,
15
+ * quarters, years— which are one group because they combine, but read as
16
+ * three because they answer at three different zooms. */
17
+ divider?: boolean;
18
+ /** Cómo se SACA esta opción cuando se dibuja como ficha, si sacarla no es lo mismo que
19
+ * volver a elegirla. El filtro a medida es el caso: elegirlo abre el constructor, y eso
20
+ * no es lo que tiene que pasar al tocar su ×. */
21
+ onRemove?: () => void;
22
+ disabled?: boolean;
23
+ /** Visual mark at the end of the label. A string is drawn as a pill
24
+ * —"maqueta", "nuevo"—; anything else is drawn as is, which is how a status
25
+ * `Tag` or an already formatted counter comes in. */
26
+ badge?: ReactNode;
27
+ /** What THIS option does. It exists on top of the menu's `onSelect` because a
28
+ * menu built from a registry —twenty-five operations, each one with its own
29
+ * action— has no reasonable `switch` on the other side. */
30
+ onSelect?: () => void;
31
+ /** The keys that run this option without opening the menu, as the user reads them
32
+ * —«Ctrl+P», «⌘D»—. Drawn at the end of the row and linked to it for a screen reader.
33
+ * It is a HINT: binding the keys is the application's job, because the menu does not
34
+ * exist until it is opened. In an ERP the frequent verbs have a shortcut, and the menu
35
+ * is where people learn it. */
36
+ shortcut?: string;
37
+ /** The option opens a SUBMENU with these options instead of running. Its own `onSelect`
38
+ * and `checked` are ignored — a row that opens something does not also do something.
39
+ * Children may carry `items` too, but a third level is usually a dialog in disguise. */
40
+ items?: readonly MenuOption[];
41
+ }
42
+ export interface MenuGroup {
43
+ /** The group's label, in the brand voice. Without a label, the group is just
44
+ * a separator — which also serves a purpose. */
45
+ label?: string;
46
+ /**
47
+ * The group folds under its label, and starts folded unless something in it
48
+ * is ticked.
49
+ *
50
+ * It exists for the DATE narrowings. «Fecha de pedido» is not one option, it
51
+ * is eleven —three months, four quarters, three years— and eleven options
52
+ * always open push the rest of the panel off the screen. A date is the only
53
+ * field that brings its own little calendar, so it is the only one that
54
+ * folds; the others are a list and a list does not need a door.
55
+ */
56
+ collapsible?: boolean;
57
+ options: MenuOption[];
58
+ }
59
+ declare const WIDTH: {
60
+ /** A menu of short verbs hanging off an icon: "duplicate", "delete". */
61
+ readonly sm: "min-w-44 max-w-64";
62
+ readonly md: "min-w-56 max-w-80";
63
+ readonly lg: "min-w-80 max-w-(--container-short)";
64
+ };
65
+ /** Every option of the tree by id, children included: a submenu is a separate React Aria
66
+ * menu with its own `onAction`, and both have to reach the same handlers. */
67
+ export declare function indexOptions(options: readonly MenuOption[], into?: Map<string, MenuOption>): Map<string, MenuOption>;
68
+ export declare function Menu({ label, groups, onSelect, surface, align, icon: Trigger,
69
+ /** The menu as a control of a list ("filters ▾") carries the chevron; the
70
+ * actions `⋯` does not, because the icon already says there is more. */
71
+ chevron, active, iconOnly, variant, searchPlaceholder, emptyText, width, role, size, title, closeOnSelect, }: {
72
+ label: string;
73
+ groups: readonly MenuGroup[];
74
+ onSelect?: (id: string) => void;
75
+ surface?: "canvas" | "chrome";
76
+ align?: "start" | "end";
77
+ icon?: LucideIcon;
78
+ chevron?: boolean;
79
+ /** Something is chosen inside. A filter menu that doesn't look different when
80
+ * it filters is how someone ends up looking at a trimmed list without
81
+ * knowing it. */
82
+ active?: boolean;
83
+ /** `text` removes the frame and the background: it is the menu of an
84
+ * application BAR. `button` —the default— is the menu of a control. */
85
+ variant?: "button" | "text";
86
+ /** With a search box, the menu filters over label and hint. It only goes in
87
+ * when there are enough entries for searching to gain something — a search
88
+ * box on top of four options is one more control between the hand and what
89
+ * was already visible. */
90
+ searchPlaceholder?: string;
91
+ emptyText?: string;
92
+ /** `md` for a menu of verbs; `lg` when the entries carry a hint that cannot be
93
+ * truncated without losing its reason to exist. */
94
+ width?: keyof typeof WIDTH;
95
+ /** The trigger looks like a BUTTON of that role. It is for the menu that
96
+ * starts something —"+ Create"—, which has to look like the main action and
97
+ * not like a control of the list. Without this, the trigger is the usual
98
+ * small one. */
99
+ role?: ButtonRole;
100
+ size?: ButtonSize;
101
+ /** What explains the menu on hover. It is not drawn. */
102
+ title?: string;
103
+ /** Icon only. `label` becomes the accessible name and the `title`, and stops
104
+ * being drawn — it is the actions `⋯`, where the icon already says there is
105
+ * more.
106
+ *
107
+ * The label does NOT become optional when hidden: a menu without an
108
+ * accessible name is a menu a screen reader announces as "button". */
109
+ iconOnly?: boolean;
110
+ /** Column and filter menus toggle several options in a row. Closing after
111
+ * each click turns three hides into three open-close round trips. */
112
+ closeOnSelect?: boolean;
113
+ }): import("react").JSX.Element;
114
+ /**
115
+ * The panel of a `Menu`: its groups and rows, and the submenus hanging from them. Internal —
116
+ * it is not exported from the family — and separate from the trigger for two reasons: a
117
+ * submenu is this same panel one level down, and a panel can be rendered on the server
118
+ * without the trigger's popover, which is how the tests see the rows.
119
+ */
120
+ export declare function MenuList({ label, groups, onAction, closeOnSelect, emptyText, width, }: {
121
+ label: string;
122
+ groups: readonly MenuGroup[];
123
+ onAction: (key: Key) => void;
124
+ closeOnSelect: boolean;
125
+ emptyText: string;
126
+ width?: keyof typeof WIDTH;
127
+ }): import("react").JSX.Element;
128
+ export {};
@@ -0,0 +1,89 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useUiCopy } from "../../foundations/copy.js";
4
+ import { buttonClasses, } from "../button/Button.js";
5
+ import { Popover } from "../overlay/Popover.js";
6
+ import { Check, ChevronDown, ChevronRight } from "lucide-react";
7
+ import { Autocomplete, Button as AriaButton, Header, Input, Keyboard, Menu as AriaMenu, MenuItem, MenuSection, MenuTrigger, SearchField, Separator, SubmenuTrigger, useFilter, } from "react-aria-components";
8
+ const WIDTH = {
9
+ /** A menu of short verbs hanging off an icon: "duplicate", "delete". */
10
+ sm: "min-w-44 max-w-64",
11
+ md: "min-w-56 max-w-80",
12
+ lg: "min-w-80 max-w-(--container-short)",
13
+ };
14
+ /** A submenu opens beside its row, flush against the parent panel and pulled up by the
15
+ * panel's padding plus its hairline (`p-1` + 1), so its first row lines up with the row that
16
+ * opened it — a submenu that starts half a row lower reads as belonging to the next one. */
17
+ const SUBMENU_OFFSET = 0;
18
+ const SUBMENU_CROSS_OFFSET = -5;
19
+ /** Every option of the tree by id, children included: a submenu is a separate React Aria
20
+ * menu with its own `onAction`, and both have to reach the same handlers. */
21
+ export function indexOptions(options, into = new Map()) {
22
+ for (const o of options) {
23
+ into.set(o.id, o);
24
+ if (o.items !== undefined)
25
+ indexOptions(o.items, into);
26
+ }
27
+ return into;
28
+ }
29
+ export function Menu({ label, groups, onSelect, surface = "canvas", align = "start", icon: Trigger,
30
+ /** The menu as a control of a list ("filters ▾") carries the chevron; the
31
+ * actions `⋯` does not, because the icon already says there is more. */
32
+ chevron = true, active = false, iconOnly = false, variant = "button", searchPlaceholder, emptyText, width = "md", role, size = "md", title, closeOnSelect = true, }) {
33
+ const copy = useUiCopy();
34
+ const { contains } = useFilter({ sensitivity: "base" });
35
+ /* `text` is the menu of a BAR: no frame and no background, just the highlight
36
+ on hover. Five bordered menus on top of an application are five buttons
37
+ competing with the ones in the view, and the bar stops reading as an index.
38
+ `button` is the menu of a CONTROL —"filters ▾", "group ▾"—, and there the
39
+ frame is what says it can be pressed. */
40
+ const triggerClass = (open) => variant === "text"
41
+ ? surface === "chrome"
42
+ ? `border-transparent text-chrome-muted hover:bg-chrome-ink/12 hover:text-chrome-ink ${active || open ? "bg-chrome-ink/12 text-chrome-ink" : ""}`
43
+ : `border-transparent text-muted hover:bg-ink/6 hover:text-ink ${active || open ? "bg-ink/6 text-ink" : ""}`
44
+ : surface === "chrome"
45
+ ? `border-chrome-muted/35 bg-chrome-raised text-chrome-ink hover:border-chrome-accent/45 ${active ? "border-chrome-accent/60" : ""}`
46
+ : `border-line-strong bg-surface hover:border-primary/45 hover:bg-primary/5 ${active ? "border-primary/60 text-primary" : "text-ink"}`;
47
+ const byId = indexOptions(groups.flatMap((g) => g.options));
48
+ const menu = (_jsx(MenuList, { label: label, groups: groups, width: width, closeOnSelect: closeOnSelect, onAction: (key) => {
49
+ const option = byId.get(String(key));
50
+ option?.onSelect?.();
51
+ onSelect?.(String(key));
52
+ }, emptyText: emptyText ?? copy.menu.empty }));
53
+ return (_jsxs(MenuTrigger, { children: [_jsx(AriaButton, { "aria-label": iconOnly ? label : undefined, ...(role === undefined ? {} : { "data-emphasis": role }), className: ({ isPressed, isFocusVisible }) => role === undefined
54
+ ? `inline-flex h-(--size-control-sm) shrink-0 cursor-default items-center gap-1.5 border text-micro font-medium whitespace-nowrap outline-0 transition-colors duration-(--duration-instant) ${isFocusVisible ? "outline-2 outline-offset-2 outline-primary" : ""} ${iconOnly ? "w-(--size-control-sm) justify-center rounded-pill" : "rounded-control px-2.5"} ${triggerClass(isPressed)}`
55
+ : `${buttonClasses(role, size, surface)} gap-1.5`, children: _jsxs("span", { className: "contents", title: title ?? (iconOnly ? label : undefined), children: [Trigger === undefined ? (iconOnly ? (_jsx(ChevronDown, { className: "size-(--size-icon-sm)", strokeWidth: 2, "aria-hidden": true })) : null) : (_jsx(Trigger, { className: "size-(--size-icon-sm)", strokeWidth: 2, "aria-hidden": true })), iconOnly ? null : label, chevron && !iconOnly ? (_jsx(ChevronDown, { className: "size-(--size-icon-sm)", strokeWidth: 2, "aria-hidden": true })) : null] }) }), _jsx(Popover, { placement: align === "end" ? "bottom end" : "bottom start", className: WIDTH[width], children: searchPlaceholder === undefined ? (menu) : (
56
+ /* The search box stays at the top: in a menu of twenty-five entries,
57
+ scrolling loses exactly the control that explains why only three are
58
+ visible. It filters on label AND hint — half the entries of this
59
+ product are told apart only by the hint. */
60
+ _jsxs(Autocomplete, { filter: contains, children: [_jsx(SearchField, { "aria-label": searchPlaceholder, autoFocus: true, className: "border-b border-line px-2 pt-2 pb-2", children: _jsx(Input, { placeholder: searchPlaceholder, className: "h-(--size-control-sm) w-full rounded-control border border-line-strong bg-surface px-2.5 text-meta text-ink outline-0 placeholder:text-muted focus-visible:border-primary" }) }), menu] })) })] }));
61
+ }
62
+ /**
63
+ * The panel of a `Menu`: its groups and rows, and the submenus hanging from them. Internal —
64
+ * it is not exported from the family — and separate from the trigger for two reasons: a
65
+ * submenu is this same panel one level down, and a panel can be rendered on the server
66
+ * without the trigger's popover, which is how the tests see the rows.
67
+ */
68
+ export function MenuList({ label, groups, onAction, closeOnSelect, emptyText, width = "md", }) {
69
+ /* Per panel: a submenu without icons does not inherit its parent's mark column. */
70
+ const hasMarks = groups.some((g) => g.options.some((o) => o.checked !== undefined || o.icon !== undefined));
71
+ const hasHints = groups.some((g) => g.options.some((o) => o.hint !== undefined));
72
+ const row = (o) => {
73
+ const Icon = o.icon;
74
+ const opens = o.items !== undefined;
75
+ const checked = !opens && o.checked === true;
76
+ return (_jsxs(MenuItem, { id: o.id, textValue: o.hint === undefined ? o.label : `${o.label} ${o.hint}`, isDisabled: o.disabled, className: `flex w-full cursor-default rounded-control ${hasHints ? "items-start py-1.5" : "items-center py-1"} gap-2 px-2 text-left outline-0 transition-colors duration-(--duration-instant) data-focused:bg-primary/8 data-open:bg-primary/8 disabled:opacity-45`, children: [hasMarks ? (_jsx("span", { className: `${hasHints ? "mt-0.5" : ""} flex size-(--size-icon-sm) shrink-0 items-center justify-center`, children: checked ? (_jsx(Check, { className: "size-(--size-icon-sm) text-primary", strokeWidth: 2.5, "aria-hidden": true })) : Icon !== undefined ? (_jsx(Icon, { className: "size-(--size-icon-sm) text-muted", strokeWidth: 2, "aria-hidden": true })) : null })) : null, _jsxs("span", { className: "min-w-0 flex-1", children: [_jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: `truncate text-meta ${checked ? "font-medium text-ink" : "text-ink"}`, children: o.label }), o.badge === undefined ? null : typeof o.badge === "string" ? (_jsx("span", { className: "inline-flex shrink-0 items-center rounded-pill border border-warn/30 bg-warn/10 px-2 py-0.5 text-micro text-warn", children: o.badge })) : (_jsx("span", { className: "ml-auto shrink-0", children: o.badge }))] }), o.hint === undefined ? null : (_jsx("span", { className: "mt-0.5 block truncate text-micro text-muted", children: o.hint }))] }), o.shortcut === undefined ? null : (_jsx(Keyboard, { className: "shrink-0 self-center pl-3 font-mono text-micro text-muted", children: o.shortcut })), opens ? (_jsx(ChevronRight, { className: "size-(--size-icon-sm) shrink-0 self-center text-muted", strokeWidth: 2, "aria-hidden": true })) : null] }, o.id));
77
+ };
78
+ return (_jsx(AriaMenu, { "aria-label": label, shouldCloseOnSelect: closeOnSelect, onAction: onAction, renderEmptyState: () => (_jsx("p", { className: "px-3 py-3 text-meta text-muted italic", children: emptyText })), className: "max-h-[inherit] overflow-y-auto p-1 outline-0", children: groups.map((g, gi) => (_jsxs(MenuSection, { className: "[&:not(:first-child)]:mt-1 [&:not(:first-child)]:border-t [&:not(:first-child)]:border-line [&:not(:first-child)]:pt-1", children: [g.label === undefined ? null : (
79
+ /* Same skeleton as the row: the label sits on the text column. */
80
+ _jsxs(Header, { className: "flex items-center gap-2 px-2 pt-1 pb-0.5 text-micro font-medium text-muted", children: [hasMarks ? (_jsx("span", { className: "size-(--size-icon-sm) shrink-0", "aria-hidden": true })) : null, g.label] })), g.options.flatMap((o) => {
81
+ const item = o.items === undefined ? (row(o)) : (_jsxs(SubmenuTrigger, { children: [row(o), _jsx(Popover, { offset: SUBMENU_OFFSET, crossOffset: SUBMENU_CROSS_OFFSET, className: WIDTH[width], children: _jsx(MenuList, { label: o.label, groups: [{ options: [...o.items] }], onAction: onAction, closeOnSelect: closeOnSelect, emptyText: emptyText, width: width }) })] }, o.id));
82
+ return o.divider === true
83
+ ? [
84
+ _jsx(Separator, { className: "my-1 h-px border-0 bg-line" }, `${o.id}-divider`),
85
+ item,
86
+ ]
87
+ : [item];
88
+ })] }, g.label ?? gi))) }));
89
+ }
@@ -0,0 +1 @@
1
+ export { Menu, type MenuGroup, type MenuOption } from "./Menu.js";
@@ -0,0 +1,2 @@
1
+ /* A data-driven dropdown: the actions `⋯` and "+ Create". */
2
+ export { Menu } from "./Menu.js";
@@ -0,0 +1,49 @@
1
+ import type { Tone } from "../../foundations/types.js";
2
+ import type { LucideIcon } from "lucide-react";
3
+ import type { ReactNode } from "react";
4
+ /**
5
+ * UN AVISO sobre lo que se está mirando.
6
+ *
7
+ * Context: `Empty`, `Failed` y `Missing` dicen que NO HAY contenido y ocupan el
8
+ * lugar de la vista. Esto es lo contrario: hay contenido, se ve, y hace falta
9
+ * decir algo ADEMÁS —«hay asientos sin registrar en este período», «este período
10
+ * está cerrado», «se guardó»—. Sin esta pieza, cada pantalla se lo inventaba
11
+ * con un `div` y un color a ojo, y así es como el mismo grado de urgencia
12
+ * terminaba pintado de tres maneras.
13
+ *
14
+ * ── El tono es la ÚNICA decisión ────────────────────────────────────
15
+ *
16
+ * info un dato que cambia cómo se lee lo de abajo
17
+ * warn algo que conviene mirar antes de seguir
18
+ * bad algo que está mal y ya tuvo consecuencias
19
+ * good algo salió bien y no hay nada que hacer
20
+ *
21
+ * El ícono sale del tono y no se elige: un aviso rojo con un tilde verde adentro
22
+ * es una contradicción que alguien va a escribir si se lo dejamos escribir.
23
+ *
24
+ * ── Lo que NO hace ──────────────────────────────────────────────────
25
+ *
26
+ * No se cierra solo, no tiene temporizador y no se apila. Un aviso que
27
+ * desaparece a los cuatro segundos es un aviso que alguien no llegó a leer — eso
28
+ * es un `Toast`, que es otra pieza y otra pregunta («pasó algo lejos de acá»).
29
+ * Éste habla de lo que está en pantalla, así que se queda mientras sea cierto.
30
+ */
31
+ export type CalloutProps = {
32
+ /** Qué pasa. Una oración, en la voz del producto. */
33
+ children: ReactNode;
34
+ /** Sin esto, `info`. */
35
+ tone?: Extract<Tone, "info" | "warn" | "bad" | "good">;
36
+ /** El encabezado, cuando la oración sola no alcanza. La mayoría no lo
37
+ * necesita: un aviso de dos renglones con título es un cartel. */
38
+ title?: ReactNode;
39
+ /** Lo que resuelve el aviso, si hay algo que apretar. */
40
+ action?: ReactNode;
41
+ /** Presente = se puede cerrar. Ausente = no, porque lo que dice sigue siendo
42
+ * cierto lo mire quien lo mire. */
43
+ onDismiss?: () => void;
44
+ /** El rótulo accesible de la ×. */
45
+ dismissLabel?: string;
46
+ /** Un ícono propio, cuando el del tono no dice lo suficiente. */
47
+ icon?: LucideIcon;
48
+ };
49
+ export declare function Callout({ children, tone, title, action, onDismiss, dismissLabel, icon, }: CalloutProps): import("react").JSX.Element;
@@ -0,0 +1,28 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { byDensity, useDensity } from "../../foundations/density.js";
4
+ import { AlertTriangle, CheckCircle2, Info, OctagonAlert, X } from "lucide-react";
5
+ const ICON = {
6
+ info: Info,
7
+ warn: AlertTriangle,
8
+ bad: OctagonAlert,
9
+ good: CheckCircle2,
10
+ };
11
+ /* El fondo es una capa del color sobre el papel y no un color propio: así el
12
+ aviso se lee sobre el piso y sobre el papel blanco sin dos juegos de tokens, y
13
+ sigue funcionando el día que cambie la paleta. */
14
+ const SKIN = {
15
+ info: "border-info/25 bg-info/8 text-info",
16
+ warn: "border-warn/30 bg-warn/10 text-warn",
17
+ bad: "border-bad/25 bg-bad/8 text-bad",
18
+ good: "border-good/25 bg-good/8 text-good",
19
+ };
20
+ export function Callout({ children, tone = "info", title, action, onDismiss, dismissLabel, icon, }) {
21
+ const d = useDensity();
22
+ const Icon = icon ?? ICON[tone];
23
+ return (_jsxs("div", {
24
+ /* `status` y no `alert`: `alert` interrumpe al lector de pantalla y se
25
+ reserva para lo que pasó JUSTO AHORA. Un aviso que ya estaba cuando la
26
+ pantalla abrió no interrumpe nada. */
27
+ role: "status", className: `flex min-w-0 items-start gap-2.5 rounded-box border ${SKIN[tone]} ${byDensity(d, "px-3 py-2.5", "px-2.5 py-2")}`, children: [_jsx(Icon, { className: "mt-0.5 size-(--size-icon-sm) shrink-0", strokeWidth: 2, "aria-hidden": true }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-wrap items-start gap-x-3 gap-y-2", children: [_jsxs("div", { className: "flex min-w-0 flex-1 basis-(--container-name) flex-col gap-1", children: [title === undefined ? null : (_jsx("p", { className: "text-meta font-medium text-ink", children: title })), _jsx("div", { className: "min-w-0 text-meta text-ink", children: children })] }), action === undefined ? null : _jsx("span", { className: "shrink-0", children: action })] }), onDismiss === undefined ? null : (_jsx("button", { type: "button", onClick: onDismiss, "aria-label": dismissLabel ?? "cerrar", title: dismissLabel ?? "cerrar", className: "-mr-1 shrink-0 rounded-control p-0.5 text-muted transition-colors duration-(--duration-instant) hover:bg-ink/6 hover:text-ink", children: _jsx(X, { className: "size-(--size-icon-sm)", strokeWidth: 2 }) }))] }));
28
+ }
@@ -0,0 +1,13 @@
1
+ import type { Tone } from "../../foundations/types.js";
2
+ import type { ReactNode } from "react";
3
+ export type FlagTone = Extract<Tone, "bad" | "warn" | "info" | "good">;
4
+ export type FlagProps = {
5
+ tone: FlagTone;
6
+ /** The sentence the mark stands for — «Sin existencias». It names the mark and heads
7
+ * the popover. */
8
+ label: string;
9
+ /** What explains it, inside the popover: the figures, what to do. */
10
+ children?: ReactNode;
11
+ };
12
+ /** A toned mark that opens its sentence. See the file's header. */
13
+ export declare function Flag({ tone, label, children }: FlagProps): import("react").JSX.Element;
@@ -0,0 +1,31 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { tv } from "../../foundations/variants.js";
4
+ import { Popover } from "../overlay/Popover.js";
5
+ import { CircleAlert, CircleCheck, Info, TriangleAlert } from "lucide-react";
6
+ import { Button, Dialog, DialogTrigger, Heading } from "react-aria-components";
7
+ const ICON = {
8
+ bad: CircleAlert,
9
+ warn: TriangleAlert,
10
+ info: Info,
11
+ good: CircleCheck,
12
+ };
13
+ const mark = tv({
14
+ base: "inline-flex size-5 shrink-0 cursor-default items-center justify-center rounded-pill outline-0 transition-colors duration-(--duration-instant) forced-colors:text-[ButtonText]",
15
+ variants: {
16
+ tone: {
17
+ bad: "bg-bad/12 text-bad hover:bg-bad/20 aria-expanded:bg-bad/20",
18
+ warn: "bg-warn/15 text-warn hover:bg-warn/25 aria-expanded:bg-warn/25",
19
+ info: "bg-info/12 text-info hover:bg-info/20 aria-expanded:bg-info/20",
20
+ good: "bg-good/12 text-good hover:bg-good/20 aria-expanded:bg-good/20",
21
+ },
22
+ isFocusVisible: {
23
+ true: "outline-2 outline-offset-1 outline-primary forced-colors:outline-[Highlight]",
24
+ },
25
+ },
26
+ });
27
+ /** A toned mark that opens its sentence. See the file's header. */
28
+ export function Flag({ tone, label, children }) {
29
+ const Icon = ICON[tone];
30
+ return (_jsxs(DialogTrigger, { children: [_jsx("span", { className: "inline-flex shrink-0", onClick: (e) => e.stopPropagation(), children: _jsx(Button, { "aria-label": label, className: (state) => mark({ ...state, tone }), children: _jsx(Icon, { className: "size-(--size-icon-sm)", strokeWidth: 2.25, "aria-hidden": true }) }) }), _jsx(Popover, { placement: "bottom start", className: "max-w-72 rounded-box", children: _jsxs(Dialog, { className: "flex flex-col gap-1 px-3 py-2.5 outline-0", children: [_jsx(Heading, { slot: "title", className: "text-meta font-medium text-ink", children: label }), children === undefined ? null : (_jsx("div", { className: "text-micro leading-relaxed text-muted", children: children }))] }) })] }));
31
+ }
@@ -0,0 +1,45 @@
1
+ import { type LucideIcon } from "lucide-react";
2
+ import type { ReactNode } from "react";
3
+ export declare function Skeleton({ rows, label, }: {
4
+ /** How many row-silhouettes. Six is a screen of a list, not a guess at
5
+ * the real count. */
6
+ rows?: number;
7
+ /** What a screen reader hears. The bars stay silent. */
8
+ label: string;
9
+ }): import("react").JSX.Element;
10
+ /** What is shown when there is nothing to show: a sentence, and the gesture
11
+ * that resolves it if there is one. Never a drawing. */
12
+ export declare function Empty({ sentence, action,
13
+ /** Centered for an empty list; left-aligned inside a block, where centering it
14
+ * detaches it from everything else. */
15
+ align, }: {
16
+ sentence: string;
17
+ action?: ReactNode;
18
+ align?: "center" | "start";
19
+ }): import("react").JSX.Element;
20
+ /**
21
+ * The sentence the backend wrote, whole and verbatim.
22
+ *
23
+ * Context: a hairline around a quiet red wash — it is not an alarm, it is an
24
+ * explanation. A bar on the left alone reads as a cut. Trimming the message or
25
+ * replacing it with one of our own is what forces you to go to the console to
26
+ * find out what happened.
27
+ */
28
+ export declare function Failed({ heading, sentence, action, }: {
29
+ heading: string;
30
+ sentence: string;
31
+ action?: ReactNode;
32
+ }): import("react").JSX.Element;
33
+ /**
34
+ * Nobody knows how to draw this. It carries the full identifier because that is
35
+ * the only thing that makes it fixable.
36
+ */
37
+ export declare function Missing({ heading, detail, icon: Icon, tone, }: {
38
+ heading: string;
39
+ detail?: string;
40
+ icon?: LucideIcon;
41
+ tone?: "warn" | "bad";
42
+ }): import("react").JSX.Element;
43
+ /** The icon `Missing` uses for what broke while being drawn, so that whoever
44
+ * composes does not have to choose it. */
45
+ export declare const ICONO_ROTO: LucideIcon;
@@ -0,0 +1,61 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { byDensity, useDensity } from "../../foundations/density.js";
4
+ import { AlertTriangle, PackageX } from "lucide-react";
5
+ /**
6
+ * Context: the ways a view says there is no content yet, and they are
7
+ * different because each one is fixed by a different person.
8
+ *
9
+ * Skeleton the content is coming. The silhouette stays so the eye
10
+ * knows where the rows will land.
11
+ * Empty there is nothing yet, or the filter left nothing. It is NORMAL.
12
+ * Failed something broke. It carries the backend's sentence whole and
13
+ * verbatim.
14
+ * Missing nobody knows how to resolve this. It is a wiring error.
15
+ *
16
+ * A generic «something went wrong» for all four forces you to open the console.
17
+ * A loading sentence drawn with `Empty` is the same mistake: it answers
18
+ * «there is nothing» while the data is still on its way.
19
+ */
20
+ /** Quiet stand-in for a list that has not arrived.
21
+ *
22
+ * The bars are the row: a name on the left, a figure on the right. That is
23
+ * the scan of a list, held in place so the page does not jump when the rows
24
+ * land. There is no shimmer. A pulse already means «this state is alive»
25
+ * (`StatusDot`); a second one would spend motion on a wait. The sentence is
26
+ * for the screen reader — the bars are not the message. */
27
+ const SKELETON_NAME = ["w-48", "w-36", "w-56", "w-40", "w-44", "w-32"];
28
+ export function Skeleton({ rows = 6, label, }) {
29
+ const d = useDensity();
30
+ return (_jsxs("div", { "aria-busy": "true", className: "flex flex-col", children: [_jsx("span", { className: "sr-only", children: label }), Array.from({ length: rows }, (_, i) => (_jsxs("div", { "aria-hidden": true, className: `flex items-center ${byDensity(d, "gap-3 px-2 py-2", "gap-2 px-1.5 py-1")}`, children: [_jsx("span", { className: `h-3.5 rounded-control bg-ink/8 ${SKELETON_NAME[i % SKELETON_NAME.length]}` }), _jsx("span", { className: "ml-auto h-3 w-14 rounded-control bg-ink/5" })] }, i)))] }));
31
+ }
32
+ /** What is shown when there is nothing to show: a sentence, and the gesture
33
+ * that resolves it if there is one. Never a drawing. */
34
+ export function Empty({ sentence, action,
35
+ /** Centered for an empty list; left-aligned inside a block, where centering it
36
+ * detaches it from everything else. */
37
+ align = "center", }) {
38
+ const centered = align === "center";
39
+ return (_jsxs("div", { className: `flex flex-wrap gap-3 px-4 py-10 ${centered ? "flex-col items-center text-center" : "items-center"}`, children: [_jsx("p", { className: "max-w-short text-body text-muted", children: sentence }), action] }));
40
+ }
41
+ /**
42
+ * The sentence the backend wrote, whole and verbatim.
43
+ *
44
+ * Context: a hairline around a quiet red wash — it is not an alarm, it is an
45
+ * explanation. A bar on the left alone reads as a cut. Trimming the message or
46
+ * replacing it with one of our own is what forces you to go to the console to
47
+ * find out what happened.
48
+ */
49
+ export function Failed({ heading, sentence, action, }) {
50
+ return (_jsxs("div", { className: "rounded-control border border-bad/40 bg-bad/5 px-3 py-2.5", children: [_jsx("p", { className: "text-body font-medium text-bad", children: heading }), _jsx("p", { className: "mt-1.5 max-w-prose text-lead leading-relaxed text-ink", children: sentence }), action === undefined ? null : _jsx("div", { className: "mt-2.5", children: action })] }));
51
+ }
52
+ /**
53
+ * Nobody knows how to draw this. It carries the full identifier because that is
54
+ * the only thing that makes it fixable.
55
+ */
56
+ export function Missing({ heading, detail, icon: Icon = PackageX, tone = "warn", }) {
57
+ return (_jsxs("div", { className: "flex h-full min-h-24 flex-col items-center justify-center gap-2 p-6 text-center", children: [_jsx(Icon, { className: `size-(--size-icon-lg) ${tone === "bad" ? "text-bad" : "text-warn"}`, strokeWidth: 1.75 }), _jsx("p", { className: "text-meta font-medium text-ink", children: heading }), detail === undefined ? null : (_jsx("p", { className: "max-w-short font-mono text-micro break-all text-muted", children: detail }))] }));
58
+ }
59
+ /** The icon `Missing` uses for what broke while being drawn, so that whoever
60
+ * composes does not have to choose it. */
61
+ export const ICONO_ROTO = AlertTriangle;
@@ -0,0 +1,55 @@
1
+ import type { Tone } from "../../foundations/types.js";
2
+ import { type ReactNode } from "react";
3
+ export interface ToastSpec {
4
+ /** What happened, in a sentence that stands on its own. */
5
+ message: string;
6
+ tone?: Tone;
7
+ /** The long detail: the server's reason. It goes underneath and small. */
8
+ detail?: string;
9
+ /** Where to go, or how to undo. «Deshacer», «Ver el pago». With `href` a real
10
+ * link is drawn —it can be opened in another tab, copied, shared—; with
11
+ * `onSelect`, a button. Either closes the notice. */
12
+ action?: {
13
+ label: string;
14
+ onSelect?: () => void;
15
+ href?: string;
16
+ };
17
+ /** How long it lives, in ms. `0` = until it is closed. By default: the bad
18
+ * ones stay, the rest leave after 8 s. */
19
+ duration?: number;
20
+ /** The notice's identity. Two notices with the same key are the SAME one: the
21
+ * new one replaces the old one in its place, without stacking.
22
+ *
23
+ * Context: the server sends an import's progress over a channel that can
24
+ * repeat, and three identical stacked notices are not more information —
25
+ * they are the same information, three times, taking up the screen. */
26
+ key?: string;
27
+ }
28
+ interface Toast extends ToastSpec {
29
+ id: number;
30
+ }
31
+ interface ToastApi {
32
+ show: (spec: ToastSpec) => number;
33
+ dismiss: (id: number) => void;
34
+ }
35
+ export declare function useToast(): ToastApi;
36
+ /** The same API, or `null` when no `ToastProvider` is above. For a component that OFFERS
37
+ * undo when the screen has a notice stack and still renders alone — in a story, in a test,
38
+ * in an app that has not mounted the provider yet. */
39
+ export declare function useToastIfAny(): ToastApi | null;
40
+ export declare function ToastProvider({ children }: {
41
+ children: ReactNode;
42
+ }): import("react").JSX.Element;
43
+ /** The region of a given list of notices. `ToastProvider` draws it from its own state; it is
44
+ * exported so it can be drawn without the context — a story that wants to see the tones
45
+ * together and still.
46
+ *
47
+ * Context: React Aria's queue is the behaviour (timers, pause, landmark, focus) and this
48
+ * list is the content. Each notice in the list is mirrored into the queue once; when the
49
+ * queue closes one — its timer ran out, its × or its action was pressed — `onDismiss`
50
+ * hears it, and when the list drops one the queue closes it. */
51
+ export declare function ToastLayer({ toasts, onDismiss, }: {
52
+ toasts: readonly Toast[];
53
+ onDismiss: (id: number) => void;
54
+ }): import("react").JSX.Element | null;
55
+ export {};