@sincpro/web-ui 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +157 -2
  3. package/dist/components/assist/AssistMark.d.ts +64 -0
  4. package/dist/components/assist/AssistMark.js +108 -0
  5. package/dist/components/assist/AssistPending.d.ts +24 -0
  6. package/dist/components/assist/AssistPending.js +26 -0
  7. package/dist/components/assist/AssistSuggestion.d.ts +42 -0
  8. package/dist/components/assist/AssistSuggestion.js +55 -0
  9. package/dist/components/assist/ChangeReview.d.ts +56 -0
  10. package/dist/components/assist/ChangeReview.js +121 -0
  11. package/dist/components/assist/assist.d.ts +77 -0
  12. package/dist/components/assist/assist.js +87 -0
  13. package/dist/components/assist/index.d.ts +5 -0
  14. package/dist/components/assist/index.js +7 -0
  15. package/dist/components/chatter/Chatter.d.ts +161 -0
  16. package/dist/components/chatter/Chatter.js +232 -0
  17. package/dist/components/chatter/Messages.d.ts +66 -0
  18. package/dist/components/chatter/Messages.js +43 -0
  19. package/dist/components/chatter/Timeline.d.ts +21 -0
  20. package/dist/components/chatter/Timeline.js +30 -0
  21. package/dist/components/chatter/index.d.ts +3 -0
  22. package/dist/components/chatter/index.js +4 -0
  23. package/dist/components/form/Form.d.ts +52 -0
  24. package/dist/components/form/Form.js +49 -0
  25. package/dist/components/form/Sheet.d.ts +43 -0
  26. package/dist/components/form/Sheet.js +83 -0
  27. package/dist/components/form/index.d.ts +2 -0
  28. package/dist/components/form/index.js +4 -0
  29. package/dist/components/frame/Chart.d.ts +13 -0
  30. package/dist/components/frame/Chart.js +24 -0
  31. package/dist/components/frame/FrameView.d.ts +33 -0
  32. package/dist/components/frame/FrameView.js +125 -0
  33. package/dist/components/frame/index.d.ts +3 -0
  34. package/dist/components/frame/index.js +3 -0
  35. package/dist/components/frame/model.d.ts +43 -0
  36. package/dist/components/frame/model.js +101 -0
  37. package/dist/components/index.d.ts +10 -0
  38. package/dist/components/index.js +11 -0
  39. package/dist/components/lines/LineItems.d.ts +74 -0
  40. package/dist/components/lines/LineItems.js +229 -0
  41. package/dist/components/lines/index.d.ts +1 -0
  42. package/dist/components/lines/index.js +2 -0
  43. package/dist/components/lines/lines.d.ts +23 -0
  44. package/dist/components/lines/lines.js +26 -0
  45. package/dist/components/listing/ColumnsMenu.d.ts +20 -0
  46. package/dist/components/listing/ColumnsMenu.js +46 -0
  47. package/dist/components/listing/GroupingLevels.d.ts +35 -0
  48. package/dist/components/listing/GroupingLevels.js +45 -0
  49. package/dist/components/listing/Listing.d.ts +27 -0
  50. package/dist/components/listing/Listing.js +86 -0
  51. package/dist/components/listing/ListingBar.d.ts +73 -0
  52. package/dist/components/listing/ListingBar.js +105 -0
  53. package/dist/components/listing/Pagination.d.ts +36 -0
  54. package/dist/components/listing/Pagination.js +69 -0
  55. package/dist/components/listing/RecordCard.d.ts +33 -0
  56. package/dist/components/listing/RecordCard.js +22 -0
  57. package/dist/components/listing/RecordLink.d.ts +7 -0
  58. package/dist/components/listing/RecordLink.js +22 -0
  59. package/dist/components/listing/Row.d.ts +106 -0
  60. package/dist/components/listing/Row.js +122 -0
  61. package/dist/components/listing/SortMenu.d.ts +62 -0
  62. package/dist/components/listing/SortMenu.js +105 -0
  63. package/dist/components/listing/ViewSwitcher.d.ts +24 -0
  64. package/dist/components/listing/ViewSwitcher.js +16 -0
  65. package/dist/components/listing/columns.d.ts +47 -0
  66. package/dist/components/listing/columns.js +72 -0
  67. package/dist/components/listing/grouping.d.ts +35 -0
  68. package/dist/components/listing/grouping.js +47 -0
  69. package/dist/components/listing/index.d.ts +17 -0
  70. package/dist/components/listing/index.js +20 -0
  71. package/dist/components/listing/modelColumns.d.ts +50 -0
  72. package/dist/components/listing/modelColumns.js +103 -0
  73. package/dist/components/listing/pages.d.ts +78 -0
  74. package/dist/components/listing/pages.js +135 -0
  75. package/dist/components/listing/selection.d.ts +21 -0
  76. package/dist/components/listing/selection.js +43 -0
  77. package/dist/components/listing/set.d.ts +48 -0
  78. package/dist/components/listing/set.js +24 -0
  79. package/dist/components/listing/tree.d.ts +28 -0
  80. package/dist/components/listing/tree.js +23 -0
  81. package/dist/components/navigation/CommandPalette.d.ts +40 -0
  82. package/dist/components/navigation/CommandPalette.js +114 -0
  83. package/dist/components/navigation/NavigationTree.d.ts +31 -0
  84. package/dist/components/navigation/NavigationTree.js +79 -0
  85. package/dist/components/navigation/commands.d.ts +30 -0
  86. package/dist/components/navigation/commands.js +30 -0
  87. package/dist/components/navigation/index.d.ts +3 -0
  88. package/dist/components/navigation/index.js +4 -0
  89. package/dist/components/record/Breadcrumb.d.ts +42 -0
  90. package/dist/components/record/Breadcrumb.js +98 -0
  91. package/dist/components/record/DirtyActions.d.ts +26 -0
  92. package/dist/components/record/DirtyActions.js +22 -0
  93. package/dist/components/record/Pager.d.ts +18 -0
  94. package/dist/components/record/Pager.js +33 -0
  95. package/dist/components/record/RecordHeader.d.ts +71 -0
  96. package/dist/components/record/RecordHeader.js +72 -0
  97. package/dist/components/record/RecordSkeleton.d.ts +3 -0
  98. package/dist/components/record/RecordSkeleton.js +21 -0
  99. package/dist/components/record/SmartButtons.d.ts +35 -0
  100. package/dist/components/record/SmartButtons.js +38 -0
  101. package/dist/components/record/StatusBar.d.ts +51 -0
  102. package/dist/components/record/StatusBar.js +168 -0
  103. package/dist/components/record/ThumbBar.d.ts +36 -0
  104. package/dist/components/record/ThumbBar.js +86 -0
  105. package/dist/components/record/index.d.ts +6 -0
  106. package/dist/components/record/index.js +8 -0
  107. package/dist/components/search/CriteriaBuilder.d.ts +58 -0
  108. package/dist/components/search/CriteriaBuilder.js +278 -0
  109. package/dist/components/search/CriteriaChips.d.ts +22 -0
  110. package/dist/components/search/CriteriaChips.js +64 -0
  111. package/dist/components/search/FilterBuilder.d.ts +142 -0
  112. package/dist/components/search/FilterBuilder.js +421 -0
  113. package/dist/components/search/JoinWord.d.ts +8 -0
  114. package/dist/components/search/JoinWord.js +47 -0
  115. package/dist/components/search/JsonEditor.d.ts +19 -0
  116. package/dist/components/search/JsonEditor.js +78 -0
  117. package/dist/components/search/SearchBar.d.ts +78 -0
  118. package/dist/components/search/SearchBar.js +387 -0
  119. package/dist/components/search/criteria.d.ts +116 -0
  120. package/dist/components/search/criteria.js +159 -0
  121. package/dist/components/search/datePeriods.d.ts +122 -0
  122. package/dist/components/search/datePeriods.js +134 -0
  123. package/dist/components/search/dateRanges.d.ts +54 -0
  124. package/dist/components/search/dateRanges.js +89 -0
  125. package/dist/components/search/index.d.ts +9 -0
  126. package/dist/components/search/index.js +20 -0
  127. package/dist/components/search/model.d.ts +54 -0
  128. package/dist/components/search/model.js +37 -0
  129. package/dist/components/search/query.d.ts +166 -0
  130. package/dist/components/search/query.js +436 -0
  131. package/dist/components/shell/AppFrame.d.ts +14 -0
  132. package/dist/components/shell/AppFrame.js +80 -0
  133. package/dist/components/shell/TopBar.d.ts +73 -0
  134. package/dist/components/shell/TopBar.js +54 -0
  135. package/dist/components/shell/headerSlot.d.ts +17 -0
  136. package/dist/components/shell/headerSlot.js +21 -0
  137. package/dist/components/shell/index.d.ts +2 -0
  138. package/dist/components/shell/index.js +3 -0
  139. package/dist/foundations/aria.d.ts +14 -0
  140. package/dist/foundations/aria.js +18 -0
  141. package/dist/foundations/calendar.d.ts +28 -0
  142. package/dist/foundations/calendar.js +183 -0
  143. package/dist/foundations/copy.d.ts +619 -0
  144. package/dist/foundations/copy.es.d.ts +2 -0
  145. package/dist/foundations/copy.es.js +377 -0
  146. package/dist/foundations/copy.js +472 -0
  147. package/dist/foundations/density.d.ts +16 -0
  148. package/dist/foundations/density.js +21 -0
  149. package/dist/foundations/grouping.d.ts +281 -0
  150. package/dist/foundations/grouping.js +0 -0
  151. package/dist/foundations/index.d.ts +14 -0
  152. package/dist/foundations/index.js +30 -0
  153. package/dist/foundations/layout.d.ts +9 -0
  154. package/dist/foundations/layout.js +9 -0
  155. package/dist/foundations/pivot.d.ts +222 -0
  156. package/dist/foundations/pivot.js +198 -0
  157. package/dist/foundations/pivotSheet.d.ts +61 -0
  158. package/dist/foundations/pivotSheet.js +0 -0
  159. package/dist/foundations/slots.d.ts +67 -0
  160. package/dist/foundations/slots.js +63 -0
  161. package/dist/foundations/sticky.d.ts +53 -0
  162. package/dist/foundations/sticky.js +150 -0
  163. package/dist/foundations/surface.d.ts +9 -0
  164. package/dist/foundations/surface.js +26 -0
  165. package/dist/foundations/theme.d.ts +42 -0
  166. package/dist/foundations/theme.js +88 -0
  167. package/dist/foundations/types.d.ts +23 -0
  168. package/dist/foundations/types.js +50 -0
  169. package/dist/foundations/variants.d.ts +19 -0
  170. package/dist/foundations/variants.js +48 -0
  171. package/dist/foundations/xlsx.d.ts +86 -0
  172. package/dist/foundations/xlsx.js +0 -0
  173. package/dist/index.d.ts +19 -0
  174. package/dist/index.js +19 -0
  175. package/dist/primitives/block/Block.d.ts +66 -0
  176. package/dist/primitives/block/Block.js +34 -0
  177. package/dist/primitives/block/Line.d.ts +18 -0
  178. package/dist/primitives/block/Line.js +45 -0
  179. package/dist/primitives/block/SectionGrid.d.ts +30 -0
  180. package/dist/primitives/block/SectionGrid.js +29 -0
  181. package/dist/primitives/block/Steps.d.ts +76 -0
  182. package/dist/primitives/block/Steps.js +43 -0
  183. package/dist/primitives/block/index.d.ts +4 -0
  184. package/dist/primitives/block/index.js +7 -0
  185. package/dist/primitives/button/Button.d.ts +137 -0
  186. package/dist/primitives/button/Button.js +234 -0
  187. package/dist/primitives/button/index.d.ts +1 -0
  188. package/dist/primitives/button/index.js +2 -0
  189. package/dist/primitives/cell/CellStack.d.ts +47 -0
  190. package/dist/primitives/cell/CellStack.js +33 -0
  191. package/dist/primitives/cell/index.d.ts +1 -0
  192. package/dist/primitives/cell/index.js +3 -0
  193. package/dist/primitives/choice/ComboBox.d.ts +16 -0
  194. package/dist/primitives/choice/ComboBox.js +52 -0
  195. package/dist/primitives/choice/RadioGroup.d.ts +18 -0
  196. package/dist/primitives/choice/RadioGroup.js +50 -0
  197. package/dist/primitives/choice/SearchField.d.ts +24 -0
  198. package/dist/primitives/choice/SearchField.js +27 -0
  199. package/dist/primitives/choice/SegmentedControl.d.ts +16 -0
  200. package/dist/primitives/choice/SegmentedControl.js +69 -0
  201. package/dist/primitives/choice/Slider.d.ts +16 -0
  202. package/dist/primitives/choice/Slider.js +46 -0
  203. package/dist/primitives/choice/Switch.d.ts +14 -0
  204. package/dist/primitives/choice/Switch.js +65 -0
  205. package/dist/primitives/choice/ThemeSwitcher.d.ts +10 -0
  206. package/dist/primitives/choice/ThemeSwitcher.js +25 -0
  207. package/dist/primitives/choice/index.d.ts +8 -0
  208. package/dist/primitives/choice/index.js +11 -0
  209. package/dist/primitives/choice/options.d.ts +28 -0
  210. package/dist/primitives/choice/options.js +6 -0
  211. package/dist/primitives/date/Calendar.d.ts +31 -0
  212. package/dist/primitives/date/Calendar.js +110 -0
  213. package/dist/primitives/date/DatePicker.d.ts +34 -0
  214. package/dist/primitives/date/DatePicker.js +99 -0
  215. package/dist/primitives/date/index.d.ts +2 -0
  216. package/dist/primitives/date/index.js +4 -0
  217. package/dist/primitives/dialog/Dialog.d.ts +118 -0
  218. package/dist/primitives/dialog/Dialog.js +121 -0
  219. package/dist/primitives/dialog/index.d.ts +1 -0
  220. package/dist/primitives/dialog/index.js +2 -0
  221. package/dist/primitives/disclosure/Disclosure.d.ts +36 -0
  222. package/dist/primitives/disclosure/Disclosure.js +52 -0
  223. package/dist/primitives/disclosure/index.d.ts +1 -0
  224. package/dist/primitives/disclosure/index.js +2 -0
  225. package/dist/primitives/field/Checks.d.ts +57 -0
  226. package/dist/primitives/field/Checks.js +72 -0
  227. package/dist/primitives/field/DropZone.d.ts +42 -0
  228. package/dist/primitives/field/DropZone.js +52 -0
  229. package/dist/primitives/field/Field.d.ts +166 -0
  230. package/dist/primitives/field/Field.js +240 -0
  231. package/dist/primitives/field/Suggest.d.ts +48 -0
  232. package/dist/primitives/field/Suggest.js +43 -0
  233. package/dist/primitives/field/aria.d.ts +61 -0
  234. package/dist/primitives/field/aria.js +70 -0
  235. package/dist/primitives/field/context.d.ts +30 -0
  236. package/dist/primitives/field/context.js +13 -0
  237. package/dist/primitives/field/index.d.ts +7 -0
  238. package/dist/primitives/field/index.js +11 -0
  239. package/dist/primitives/field/layout.d.ts +24 -0
  240. package/dist/primitives/field/layout.js +10 -0
  241. package/dist/primitives/field/mode.d.ts +9 -0
  242. package/dist/primitives/field/mode.js +13 -0
  243. package/dist/primitives/hint/Hint.d.ts +31 -0
  244. package/dist/primitives/hint/Hint.js +42 -0
  245. package/dist/primitives/hint/index.d.ts +1 -0
  246. package/dist/primitives/hint/index.js +1 -0
  247. package/dist/primitives/index.d.ts +19 -0
  248. package/dist/primitives/index.js +20 -0
  249. package/dist/primitives/menu/Menu.d.ts +100 -0
  250. package/dist/primitives/menu/Menu.js +59 -0
  251. package/dist/primitives/menu/index.d.ts +1 -0
  252. package/dist/primitives/menu/index.js +2 -0
  253. package/dist/primitives/notice/Callout.d.ts +49 -0
  254. package/dist/primitives/notice/Callout.js +28 -0
  255. package/dist/primitives/notice/Notice.d.ts +45 -0
  256. package/dist/primitives/notice/Notice.js +61 -0
  257. package/dist/primitives/notice/Toast.d.ts +55 -0
  258. package/dist/primitives/notice/Toast.js +142 -0
  259. package/dist/primitives/notice/index.d.ts +3 -0
  260. package/dist/primitives/notice/index.js +5 -0
  261. package/dist/primitives/overlay/Popover.d.ts +6 -0
  262. package/dist/primitives/overlay/Popover.js +27 -0
  263. package/dist/primitives/overlay/PopoverTrigger.d.ts +55 -0
  264. package/dist/primitives/overlay/PopoverTrigger.js +38 -0
  265. package/dist/primitives/overlay/Tooltip.d.ts +38 -0
  266. package/dist/primitives/overlay/Tooltip.js +74 -0
  267. package/dist/primitives/overlay/index.d.ts +3 -0
  268. package/dist/primitives/overlay/index.js +5 -0
  269. package/dist/primitives/picker/Picker.d.ts +48 -0
  270. package/dist/primitives/picker/Picker.js +150 -0
  271. package/dist/primitives/picker/index.d.ts +1 -0
  272. package/dist/primitives/picker/index.js +2 -0
  273. package/dist/primitives/surface/Peek.d.ts +60 -0
  274. package/dist/primitives/surface/Peek.js +71 -0
  275. package/dist/primitives/surface/index.d.ts +1 -0
  276. package/dist/primitives/surface/index.js +2 -0
  277. package/dist/primitives/table/CellEditor.d.ts +14 -0
  278. package/dist/primitives/table/CellEditor.js +83 -0
  279. package/dist/primitives/table/DataTable.d.ts +135 -0
  280. package/dist/primitives/table/DataTable.js +244 -0
  281. package/dist/primitives/table/EditableTable.d.ts +96 -0
  282. package/dist/primitives/table/EditableTable.js +423 -0
  283. package/dist/primitives/table/PivotTable.d.ts +14 -0
  284. package/dist/primitives/table/PivotTable.js +0 -0
  285. package/dist/primitives/table/ReportTable.d.ts +38 -0
  286. package/dist/primitives/table/ReportTable.js +106 -0
  287. package/dist/primitives/table/RowActions.d.ts +16 -0
  288. package/dist/primitives/table/RowActions.js +28 -0
  289. package/dist/primitives/table/SheetTable.d.ts +70 -0
  290. package/dist/primitives/table/SheetTable.js +197 -0
  291. package/dist/primitives/table/Table.d.ts +106 -0
  292. package/dist/primitives/table/Table.js +116 -0
  293. package/dist/primitives/table/index.d.ts +7 -0
  294. package/dist/primitives/table/index.js +9 -0
  295. package/dist/primitives/tabs/Tabs.d.ts +91 -0
  296. package/dist/primitives/tabs/Tabs.js +56 -0
  297. package/dist/primitives/tabs/index.d.ts +1 -0
  298. package/dist/primitives/tabs/index.js +1 -0
  299. package/dist/primitives/tag/Tag.d.ts +36 -0
  300. package/dist/primitives/tag/Tag.js +68 -0
  301. package/dist/primitives/tag/Tags.d.ts +57 -0
  302. package/dist/primitives/tag/Tags.js +104 -0
  303. package/dist/primitives/tag/TagsField.d.ts +32 -0
  304. package/dist/primitives/tag/TagsField.js +182 -0
  305. package/dist/primitives/tag/choices.d.ts +38 -0
  306. package/dist/primitives/tag/choices.js +26 -0
  307. package/dist/primitives/tag/index.d.ts +4 -0
  308. package/dist/primitives/tag/index.js +8 -0
  309. package/dist/primitives/toolbar/Toolbar.d.ts +13 -0
  310. package/dist/primitives/toolbar/Toolbar.js +36 -0
  311. package/dist/primitives/toolbar/index.d.ts +1 -0
  312. package/dist/primitives/toolbar/index.js +2 -0
  313. package/dist/primitives/value/Copyable.d.ts +37 -0
  314. package/dist/primitives/value/Copyable.js +50 -0
  315. package/dist/primitives/value/Fecha.d.ts +12 -0
  316. package/dist/primitives/value/Fecha.js +80 -0
  317. package/dist/primitives/value/Meter.d.ts +29 -0
  318. package/dist/primitives/value/Meter.js +46 -0
  319. package/dist/primitives/value/Metric.d.ts +42 -0
  320. package/dist/primitives/value/Metric.js +38 -0
  321. package/dist/primitives/value/Person.d.ts +90 -0
  322. package/dist/primitives/value/Person.js +208 -0
  323. package/dist/primitives/value/Relation.d.ts +69 -0
  324. package/dist/primitives/value/Relation.js +57 -0
  325. package/dist/primitives/value/Totals.d.ts +26 -0
  326. package/dist/primitives/value/Totals.js +4 -0
  327. package/dist/primitives/value/Value.d.ts +77 -0
  328. package/dist/primitives/value/Value.js +119 -0
  329. package/dist/primitives/value/index.d.ts +8 -0
  330. package/dist/primitives/value/index.js +9 -0
  331. package/dist/tokens.css +1025 -0
  332. package/dist/views/index.d.ts +2 -0
  333. package/dist/views/index.js +3 -0
  334. package/dist/views/list/List.d.ts +113 -0
  335. package/dist/views/list/List.js +97 -0
  336. package/dist/views/list/ListView.d.ts +6 -0
  337. package/dist/views/list/ListView.js +269 -0
  338. package/dist/views/list/columns.d.ts +18 -0
  339. package/dist/views/list/columns.js +27 -0
  340. package/dist/views/list/derive.d.ts +76 -0
  341. package/dist/views/list/derive.js +181 -0
  342. package/dist/views/list/index.d.ts +2 -0
  343. package/dist/views/list/index.js +4 -0
  344. package/dist/views/list/presentations.d.ts +39 -0
  345. package/dist/views/list/presentations.js +103 -0
  346. package/dist/views/list/types.d.ts +272 -0
  347. package/dist/views/list/types.js +1 -0
  348. package/dist/views/list/useNarrowList.d.ts +17 -0
  349. package/dist/views/list/useNarrowList.js +32 -0
  350. package/dist/views/record/Record.d.ts +126 -0
  351. package/dist/views/record/Record.js +141 -0
  352. package/dist/views/record/index.d.ts +1 -0
  353. package/dist/views/record/index.js +2 -0
  354. package/package.json +109 -4
@@ -0,0 +1,232 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { usePagination } from "../listing/pages.js";
4
+ import { Pagination } from "../listing/Pagination.js";
5
+ import { fillCopy, useUiCopy } from "../../foundations/copy.js";
6
+ import { Empty } from "../../primitives/notice/Notice.js";
7
+ import { Tabs } from "../../primitives/tabs/Tabs.js";
8
+ import { Tag } from "../../primitives/tag/Tag.js";
9
+ import { DateValue } from "../../primitives/value/Fecha.js";
10
+ import { Avatar } from "../../primitives/value/Person.js";
11
+ import { ArrowRight, ChevronRight, History, MessageSquare, PanelRightClose, PanelRightOpen, Rows3, Zap, } from "lucide-react";
12
+ import { Lock } from "lucide-react";
13
+ import { useState } from "react";
14
+ /* The tab names come from the copy table: the same three words on every record. */
15
+ const TAB_LABEL = {
16
+ all: (copy) => copy.chatter.tabAll,
17
+ messages: (copy) => copy.chatter.tabMessages,
18
+ events: (copy) => copy.chatter.tabEvents,
19
+ };
20
+ /* El ícono de cada pestaña. Con tres, es lo que se reconoce sin leer — y en el
21
+ chatter angosto, lo único que sobrevive cuando el rótulo se trunca. */
22
+ const TAB_ICON = {
23
+ all: Rows3,
24
+ messages: MessageSquare,
25
+ events: History,
26
+ };
27
+ /* UN SOLO ÍCONO para todos los eventos: el rayo, que es lo que pasó — algo se
28
+ ejecutó. Había uno por tono y eso convertía la historia en un muestrario:
29
+ cinco formas y cinco colores para decir cinco veces «pasó algo».
30
+ Lo que SÍ hay que distinguir es si falló, y eso lo dice el contenedor. */
31
+ const EVENT_ICON = Zap;
32
+ /* DOS estados y no seis: pasó, o falló.
33
+ *
34
+ * El rojo de un fallo queda en la fila entera: es el único color, y tiene que
35
+ * verse sin señalar. El hover no lo reemplaza. Es una marca metida adentro,
36
+ * redondeada, para no pintar el riel. */
37
+ const ROW_SKIN = {
38
+ ok: "",
39
+ failed: "bg-bad/6",
40
+ };
41
+ const ROW_HOVER = {
42
+ ok: "group-hover/entry:bg-ink/4",
43
+ failed: "group-hover/entry:bg-bad/10",
44
+ };
45
+ const NODE_SKIN = {
46
+ ok: "bg-ink/8 text-muted",
47
+ failed: "bg-bad/12 text-bad",
48
+ };
49
+ function at(when) {
50
+ return when instanceof Date ? when.getTime() : new Date(when).getTime();
51
+ }
52
+ function MessageEntry({ message }) {
53
+ const copy = useUiCopy();
54
+ /* Mismo relleno que un evento: las dos clases de entrada viven en la misma
55
+ lista y con relleno distinto se leen como dos listas pegadas. Antes el
56
+ mensaje iba a ras del borde y el evento tenía caja, así que el nombre de
57
+ quien escribió quedaba más cerca del filo que el texto de al lado. */
58
+ return (_jsxs("li", { className: "flex min-w-0 gap-2.5 px-2.5 py-2", children: [_jsx(Avatar, { name: message.author, size: "sm" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-0.5", children: [_jsx("span", { className: "text-meta font-medium text-ink", children: message.author }), _jsx(DateValue, { when: message.at, format: "relative" }), message.internal !== true ? null : (_jsxs("span", { className: "inline-flex items-center gap-1 text-micro text-muted", title: copy.chatter.internalNote, children: [_jsx(Lock, { className: "size-3", "aria-hidden": true }), copy.chatter.internal] }))] }), _jsx("p", { className: `mt-0.5 text-body whitespace-pre-line ${message.internal === true
59
+ ? "rounded-control border border-warn/40 bg-warn/6 px-2 py-1 text-ink"
60
+ : "text-ink"}`, children: message.body })] })] }));
61
+ }
62
+ /** El cambio de estado, cuando lo hubo: de qué a qué.
63
+ *
64
+ * Es la línea más útil de una historia de gestión y la que peor se contaba: «el
65
+ * proyecto cambió de estado» obliga a buscar el evento anterior para saber de
66
+ * dónde venía. Dos fichas y una flecha se leen sin buscar nada.
67
+ *
68
+ * El ESTADO VIEJO va apagado y el nuevo en tinta: lo que importa es dónde
69
+ * quedó, y el de antes está para dar contexto, no para competir.
70
+ *
71
+ * La cápsula es la de `Tag`: pastilla, pelo, mismo relleno. Dos radios
72
+ * distintos para la misma idea de «una ficha» es una familia de más. */
73
+ const STATE_CHIP = "inline-flex max-w-32 min-w-0 items-center truncate rounded-pill border border-line-strong bg-ink/5 px-2 py-0.5 text-micro";
74
+ function Moved({ from, to }) {
75
+ return (_jsxs("span", { className: "inline-flex min-w-0 items-center gap-1", children: [from === undefined ? null : (_jsxs(_Fragment, { children: [_jsx("span", { className: `${STATE_CHIP} text-muted`, children: from }), _jsx(ArrowRight, { className: "size-3 shrink-0 text-muted/60", strokeWidth: 2.5, "aria-hidden": true })] })), _jsx("span", { className: `${STATE_CHIP} font-medium text-ink`, children: to })] }));
76
+ }
77
+ /**
78
+ * UN EVENTO, como línea de una línea de tiempo.
79
+ *
80
+ * ── Por qué hay un riel y no sólo puntos ────────────────────────────
81
+ *
82
+ * El riel —la línea vertical que une los puntos— es lo que convierte una lista
83
+ * en una CRONOLOGÍA. Sin él son renglones sueltos que casualmente tienen fecha;
84
+ * con él se lee que una cosa pasó después de la otra, que es la pregunta que
85
+ * alguien trae cuando abre esto.
86
+ *
87
+ * ── El color es del punto y de nada más ─────────────────────────────
88
+ *
89
+ * El tono pinta el punto, y el texto se queda en tinta normal. Un renglón entero
90
+ * en rojo no se lee más urgente: se lee peor, y cuando hay tres seguidos deja de
91
+ * significar nada. El punto alcanza para encontrar los rojos de un vistazo, que
92
+ * es para lo que el color sirve en una lista larga.
93
+ */
94
+ /** El error: la primera línea, y el resto a un clic.
95
+ *
96
+ * Un stack de cuarenta renglones adentro de una historia tapa la historia; el
97
+ * primer renglón casi siempre alcanza. Pero el resto tiene que estar —quien
98
+ * mira esta pantalla muchas veces no tiene acceso a los logs— así que se
99
+ * guarda, no se descarta.
100
+ *
101
+ * Sin color propio: el rojo ya lo puso el nodo. Esto es una cita textual de la
102
+ * máquina, así que se ve como lo que es — monoespaciada sobre el piso. */
103
+ function ErrorLine({ error }) {
104
+ const copy = useUiCopy();
105
+ const [open, setOpen] = useState(false);
106
+ const lineas = error.split("\n");
107
+ const primera = lineas[0] ?? "";
108
+ const hayMas = lineas.length > 1 || primera.length > 120;
109
+ return (_jsxs("div", { className: "min-w-0 rounded-control border border-line bg-ground px-2 py-1", children: [_jsx("p", { className: `min-w-0 font-mono text-micro text-ink ${open ? "break-words whitespace-pre-wrap" : "truncate"}`, children: open ? error : primera }), !hayMas ? null : (_jsx("button", { type: "button", onClick: () => setOpen(!open), className: "mt-0.5 cursor-pointer text-micro text-muted underline-offset-2 hover:text-ink hover:underline", children: open ? copy.chatter.less : copy.chatter.more }))] }));
110
+ }
111
+ /**
112
+ * UN EVENTO: una FILA que se aprieta, no un renglón.
113
+ *
114
+ * ── Qué se ve sin abrir ─────────────────────────────────────────────
115
+ *
116
+ * El rótulo, quién —si lo hubo— y cuándo. Nada más. Es lo que alguien lee para
117
+ * recorrer la historia; todo lo demás es para cuando ese renglón no alcanzó.
118
+ *
119
+ * ── Un solo ícono, y el contenedor dice si falló ────────────────────
120
+ *
121
+ * El rayo, porque eso es lo que pasó: algo se ejecutó. Había un ícono y un color
122
+ * por tono, y seis colores no señalan nada — una historia de veinte eventos
123
+ * quedaba como una bolsa de caramelos, y el que falló no saltaba más que los
124
+ * otros. El rojo sirve exactamente mientras sea el único.
125
+ *
126
+ * Lo que distingue un error es el TINTE DE LA FILA, translúcido. Y sirve dos
127
+ * veces: dice que falló, y dice que la fila es una zona que se puede apretar —
128
+ * que era lo que no se notaba.
129
+ */
130
+ function EventEntry({ event }) {
131
+ const failed = event.tone === "bad" || event.error !== undefined;
132
+ const skin = failed ? "failed" : "ok";
133
+ const Icon = event.icon ?? EVENT_ICON;
134
+ /* Arranca CERRADO: lo de adentro es para cuando el renglón no alcanzó. */
135
+ const [open, setOpen] = useState(false);
136
+ const hayMas = event.moved !== undefined || event.detail !== undefined || event.error !== undefined;
137
+ const fila = (_jsxs(_Fragment, { children: [_jsx("span", { className: `relative z-10 flex size-6 shrink-0 items-center justify-center rounded-pill ring-2 ring-surface ${NODE_SKIN[skin]}`, children: _jsx(Icon, { className: "size-3", strokeWidth: 2.5, "aria-hidden": true }) }), _jsx("span", { className: "min-w-0 flex-1 truncate text-meta text-ink", children: event.label }), event.by === undefined ? null : (_jsx("span", { className: "hidden shrink-0 truncate text-micro text-muted @xs:inline", children: event.by })), _jsx("span", { className: "shrink-0", children: _jsx(DateValue, { when: event.at, format: "relative" }) }), hayMas ? (_jsx(ChevronRight, { className: `size-3.5 shrink-0 text-muted transition-transform duration-(--duration-instant) ${open ? "rotate-90" : ""}`, strokeWidth: 2.5, "aria-hidden": true })) : (
138
+ /* Hueco del mismo ancho: sin él, las filas que no se abren corren la
139
+ fecha y la columna deja de estar alineada. */
140
+ _jsx("span", { className: "size-3.5 shrink-0", "aria-hidden": true }))] }));
141
+ return (_jsxs("li", { className: "group/event relative @container", children: [_jsx("span", { "aria-hidden": true, className: "absolute top-8 left-5.5 w-px bg-line group-last/event:hidden" }), hayMas ? (_jsxs("button", { type: "button", onClick: () => setOpen(!open), "aria-expanded": open, className: `group/entry relative flex w-full min-w-0 cursor-pointer items-center rounded-box px-2.5 py-2 text-left focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-primary ${ROW_SKIN[skin]}`, children: [_jsx("span", { "aria-hidden": true, className: `pointer-events-none absolute inset-x-1 inset-y-0.5 rounded-control ${ROW_HOVER[skin]}` }), _jsx("span", { className: "relative z-10 flex min-w-0 flex-1 items-center gap-2.5", children: fila })] })) : (_jsx("div", { className: `flex w-full min-w-0 items-center gap-2.5 rounded-box px-2.5 py-2 ${failed ? "bg-bad/6" : ""}`, children: fila })), !open ? null : (
142
+ /* Lo de adentro, alineado bajo el rótulo y sobre el piso: es el DETALLE
143
+ de esa línea, no una línea más de la historia. */
144
+ _jsxs("div", { className: "mt-0.5 mb-1 ml-11 flex min-w-0 flex-col gap-1.5 rounded-box bg-ground px-2.5 py-2", children: [event.moved === undefined ? null : (_jsx(Moved, { ...(event.moved.from === undefined ? {} : { from: event.moved.from }), to: event.moved.to })), event.by === undefined ? null : (_jsx("span", { className: "text-micro text-muted @xs:hidden", children: event.by })), event.detail === undefined ? null : (_jsx("div", { className: "min-w-0 text-micro text-muted", children: event.detail })), event.error === undefined ? null : _jsx(ErrorLine, { error: event.error })] }))] }));
145
+ }
146
+ export function Chatter({ messages, events, composer, current, onCurrentChange, open, onToggle, label: ownLabel, layout = "page", embedded = false, }) {
147
+ const copy = useUiCopy();
148
+ const label = ownLabel ?? copy.chatter.history;
149
+ const [owned, setOwned] = useState("all");
150
+ const view = current ?? owned;
151
+ const setView = onCurrentChange ?? setOwned;
152
+ const hasMessages = messages !== undefined;
153
+ const hasEvents = events !== undefined;
154
+ /* Las tres pestañas sólo cuando hay DOS fuentes: con una sola, «todo» y esa
155
+ una son la misma lista, y tres solapas donde dos dicen lo mismo es un
156
+ control que no decide nada. */
157
+ const tabs = hasMessages && hasEvents ? ["all", "messages", "events"] : [];
158
+ const showing = tabs.length === 0 ? "all" : view;
159
+ const entries = [
160
+ ...(showing === "events" ? [] : (messages ?? [])).map((message) => ({
161
+ kind: "message",
162
+ at: at(message.at),
163
+ message,
164
+ })),
165
+ ...(showing === "messages" ? [] : (events ?? [])).map((event) => ({
166
+ kind: "event",
167
+ at: at(event.at),
168
+ event,
169
+ })),
170
+ ].sort((a, b) => b.at - a.at);
171
+ const total = (messages?.length ?? 0) + (events?.length ?? 0);
172
+ /* Cortado acá y no por quien compone: es la misma lista en todos los
173
+ registros, y una historia que sólo hace scroll es una historia que se
174
+ abandona a la mitad. */
175
+ const pages = usePagination(entries, { pageSize: 15 });
176
+ const page = layout === "page";
177
+ /* Plegado. Embebido es la última fila de la hoja: el marco lo pone la hoja
178
+ y el hover es una marca redondeada adentro, para no pintar la línea que
179
+ la separa del papel. Suelta, o al costado, sí es una tarjeta. */
180
+ if (!open) {
181
+ const strip = page && embedded;
182
+ const face = (_jsxs(_Fragment, { children: [_jsx(MessageSquare, { className: "size-4 shrink-0 text-muted", "aria-hidden": true }), _jsx("span", { className: page
183
+ ? "min-w-0 truncate text-meta text-muted"
184
+ : "min-w-0 truncate text-meta text-muted @4xl:hidden", children: label }), total === 0 ? null : _jsx(Tag, { tone: "neutral", children: total }), _jsx(PanelRightOpen, { className: page
185
+ ? "ml-auto size-4 shrink-0 text-muted"
186
+ : "ml-auto size-4 shrink-0 text-muted @4xl:ml-0", "aria-hidden": true })] }));
187
+ return (_jsxs("button", { type: "button", onClick: onToggle, title: fillCopy(copy.chatter.open, { label }), className: page
188
+ ? strip
189
+ ? "group/strip relative flex w-full shrink-0 cursor-pointer items-center px-3 py-2.5"
190
+ : "flex w-full shrink-0 cursor-pointer items-center gap-2 rounded-box border border-line bg-surface px-3 py-2.5 hover:bg-ground"
191
+ : "flex w-full shrink-0 cursor-pointer items-center gap-2 self-start rounded-box border border-line bg-surface px-2.5 py-2 hover:bg-ground @4xl:w-auto @4xl:flex-col @4xl:px-1.5 @4xl:py-2.5", children: [strip ? (_jsx("span", { "aria-hidden": true, className: "pointer-events-none absolute inset-x-1 inset-y-0.5 rounded-control group-hover/strip:bg-ground" })) : null, strip ? (_jsx("span", { className: "relative z-10 flex min-w-0 flex-1 items-center gap-2", children: face })) : (face)] }));
192
+ }
193
+ return (_jsxs("aside", { className: page
194
+ ? embedded
195
+ ? "flex w-full flex-col"
196
+ : "flex w-full flex-col rounded-box border border-line bg-surface"
197
+ : "flex w-full shrink-0 flex-col self-start rounded-box border border-line bg-surface @4xl:w-(--container-chatter)", children: [_jsxs("header", { className: `flex min-w-0 items-end gap-1 border-b border-line bg-ground px-2 pt-2 ${page && embedded ? "" : "rounded-t-box"}`, children: [tabs.length === 0 ? (_jsxs("span", { className: "px-2 py-1.5 text-meta font-medium text-ink", children: [label, total === 0 ? null : (_jsx("span", { className: "ml-1.5 text-micro text-muted", children: total }))] })) : (_jsx(Tabs, { label: label, current: showing, onSelect: (id) => setView(id), tabs: tabs.map((tab) => ({
198
+ id: tab,
199
+ label: TAB_LABEL[tab](copy),
200
+ icon: TAB_ICON[tab],
201
+ count: tab === "messages"
202
+ ? (messages?.length ?? 0)
203
+ : tab === "events"
204
+ ? (events?.length ?? 0)
205
+ : total,
206
+ })) })), _jsx("button", { type: "button", onClick: onToggle, title: fillCopy(copy.chatter.fold, { label }), className: "mb-1.5 ml-auto inline-flex size-(--size-control-sm) shrink-0 cursor-pointer items-center justify-center rounded-pill text-muted transition-colors duration-(--duration-instant) hover:bg-ink/6 hover:text-ink focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary", children: _jsx(PanelRightClose, { className: "size-(--size-icon-md)", "aria-hidden": true }) })] }), _jsxs("div", { className: page
207
+ ? "flex w-full min-w-0 max-w-(--container-prose) flex-col gap-3 px-3.5 py-3"
208
+ : "flex min-w-0 flex-col gap-3 px-2.5 py-2.5", children: [composer === undefined || showing === "events" ? null : composer, entries.length === 0 ? (_jsx(Empty, { sentence: copy.chatter.empty })) : (_jsxs(_Fragment, { children: [_jsx("ol", { className: "flex flex-col", children: pages.pageItems.map((entry) => entry.kind === "message" ? (_jsx(MessageEntry, { message: entry.message }, `m:${entry.message.id}`)) : (_jsx(EventEntry, { event: entry.event }, `e:${entry.event.id}`))) }), entries.length <= 15 ? null : _jsx(Pagination, { ...pages.bridge })] }))] })] }));
209
+ }
210
+ /** Whether the chatter is open, when the page has no better answer.
211
+ *
212
+ * **Starts folded.** It began the other way round —a history nobody opens is a
213
+ * history nobody reads— and seeing it took the argument apart: open, it holds a
214
+ * 22rem column of context on every record you open, before anybody asked for
215
+ * any. Folded it still says how many there are, which is the half that has to
216
+ * be free; reading them is a click, and a click you chose.
217
+ *
218
+ * It is the same answer for both layouts. A default that depends on the width
219
+ * would mean the same record shows a different screen depending on how many
220
+ * panels happen to be open next to it, and that is not a default, it is a
221
+ * surprise. */
222
+ export function useChatter(initial = false) {
223
+ const [open, setOpen] = useState(initial);
224
+ return {
225
+ open,
226
+ toggle: () => setOpen((current) => !current),
227
+ /** Open it without closing it if it already was. What a button from outside
228
+ * needs —«events 12»— when pressing it twice must not hide the very thing
229
+ * it promised to show. */
230
+ show: () => setOpen(true),
231
+ };
232
+ }
@@ -0,0 +1,66 @@
1
+ import { type ReactNode } from "react";
2
+ /**
3
+ * The box to write in. What gets written is drawn by `Chatter`, together with
4
+ * what the system logged — see its note on why the merge is the default.
5
+ *
6
+ * Odoo's chatter is two things sharing a column — a log the system writes and a
7
+ * thread people write — and they are usually confused because they sit
8
+ * together. They are not the same: an event is a fact that happened, and a
9
+ * message is somebody's account of it. The system's half never needs a reply
10
+ * box; this half is nothing without one.
11
+ *
12
+ * ── A note is not a message, and the difference is who reads it ─────
13
+ *
14
+ * Odoo splits «log an internal note» from «send a message» and the split is
15
+ * worth keeping: one stays inside, the other leaves. Drawing them the same and
16
+ * hoping the writer remembers is how somebody's internal remark reaches a
17
+ * client. So the CHOICE COMES FIRST: the buttons are what you see, and the box
18
+ * only appears once you said which kind of thing you are writing. A box you can
19
+ * type into before choosing is a box whose destination you find out afterwards.
20
+ *
21
+ * ── And who receives it, before you send it ─────────────────────────
22
+ *
23
+ * A message that leaves goes to somebody, and «somebody» has to be readable
24
+ * without pressing send to find out. `recipients` is drawn next to the box for
25
+ * the kinds that leave, and never for an internal note — whose whole definition
26
+ * is that it reaches nobody outside.
27
+ */
28
+ export type Message = {
29
+ id: string;
30
+ author: string;
31
+ at: Date | string | number;
32
+ body: string;
33
+ /** An internal note: it stays inside. Drawn differently on purpose. */
34
+ internal?: boolean;
35
+ };
36
+ /** A way of writing. `note` stays inside; everything else leaves, and what
37
+ * changes between them is only the channel and who is on the other side. */
38
+ export type MessageKind = {
39
+ id: string;
40
+ label: string;
41
+ /** It stays inside. Without this the kit assumes it leaves, which is the
42
+ * answer that errs on the side of asking. */
43
+ internal?: boolean;
44
+ /** Who gets it, in their own words: names for a mail, numbers for WhatsApp.
45
+ * Shown before sending, never after. */
46
+ recipients?: readonly string[];
47
+ placeholder?: string;
48
+ };
49
+ /**
50
+ * ESCRIBIR UNA NOTA, la manera que toda lista tiene.
51
+ *
52
+ * Es una función y no una constante porque sus palabras salen de la copia, y una
53
+ * constante las congelaría con las que hubiera al cargar el módulo —o sea, las
54
+ * de fábrica— por más que después se instale otra.
55
+ */
56
+ export declare function writeANote(): MessageKind;
57
+ export type MessageComposerProps = {
58
+ /** The ways of writing this record takes. Its own list because it is the
59
+ * application that knows whether there is WhatsApp, and to whose number. */
60
+ kinds?: readonly MessageKind[];
61
+ onSend: (body: string, kind: MessageKind) => void;
62
+ sending?: boolean;
63
+ /** Next to the ways of writing, for whatever the application has to say about the send. */
64
+ footer?: ReactNode;
65
+ };
66
+ export declare function MessageComposer({ kinds, onSend, sending, footer, }: MessageComposerProps): import("react").JSX.Element;
@@ -0,0 +1,43 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { currentCopy, useUiCopy } from "../../foundations/copy.js";
4
+ import { Button } from "../../primitives/button/Button.js";
5
+ import { TextArea } from "../../primitives/field/Field.js";
6
+ import { Send, Users, X } from "lucide-react";
7
+ import { useState } from "react";
8
+ /**
9
+ * ESCRIBIR UNA NOTA, la manera que toda lista tiene.
10
+ *
11
+ * Es una función y no una constante porque sus palabras salen de la copia, y una
12
+ * constante las congelaría con las que hubiera al cargar el módulo —o sea, las
13
+ * de fábrica— por más que después se instale otra.
14
+ */
15
+ export function writeANote() {
16
+ const copy = currentCopy();
17
+ return {
18
+ id: "note",
19
+ label: copy.chatter.writeNote,
20
+ internal: true,
21
+ placeholder: copy.chatter.notePlaceholder,
22
+ };
23
+ }
24
+ export function MessageComposer({ kinds, onSend, sending = false, footer, }) {
25
+ const copy = useUiCopy();
26
+ /* La manera por default se arma acá adentro y no en la firma: un default de
27
+ parámetro se evalúa en cada render, sí, pero escrito como constante del
28
+ módulo congelaría las palabras de fábrica. */
29
+ const ways = kinds ?? [writeANote()];
30
+ const [writing, setWriting] = useState(undefined);
31
+ const [body, setBody] = useState("");
32
+ const ready = body.trim() !== "" && !sending;
33
+ function close() {
34
+ setWriting(undefined);
35
+ setBody("");
36
+ }
37
+ return (_jsxs("div", { className: "flex min-w-0 flex-col gap-2", children: [_jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-1.5", children: [ways.map((kind) => (_jsx(Button, { role: writing?.id === kind.id ? "primary" : "ghost", size: "sm", onClick: () => (writing?.id === kind.id ? close() : setWriting(kind)), children: kind.label }, kind.id))), footer === undefined ? null : _jsx("div", { className: "ml-auto min-w-0", children: footer })] }), writing === undefined ? null : (_jsxs("div", { className: "flex min-w-0 flex-col gap-2", children: [writing.internal === true || writing.recipients === undefined ? null : (_jsxs("p", { className: "flex min-w-0 items-center gap-1.5 text-micro text-muted", title: copy.chatter.recipients, children: [_jsx(Users, { className: "size-3.5 shrink-0", "aria-hidden": true }), _jsx("span", { className: "min-w-0 truncate", children: writing.recipients.length === 0
38
+ ? copy.chatter.noRecipients
39
+ : writing.recipients.join(" · ") })] })), _jsx(TextArea, { value: body, onChange: setBody, placeholder: writing.placeholder ?? copy.chatter.messagePlaceholder, rows: 3 }), _jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(Button, { role: "primary", size: "sm", icon: Send, disabled: !ready, onClick: () => {
40
+ onSend(body.trim(), writing);
41
+ close();
42
+ }, children: sending ? copy.chatter.sending : copy.chatter.send }), _jsx(Button, { role: "ghost", size: "sm", icon: X, onClick: close, children: copy.chatter.cancel })] })] }))] }));
43
+ }
@@ -0,0 +1,21 @@
1
+ import type { Surface, Tone } from "../../foundations/types.js";
2
+ import { type ReactNode } from "react";
3
+ export type TimelineItemProps = {
4
+ label: ReactNode;
5
+ at: Date | string | number;
6
+ tone?: Tone;
7
+ action?: ReactNode;
8
+ };
9
+ export type TimelineProps = {
10
+ children?: ReactNode;
11
+ empty?: {
12
+ sentence: string;
13
+ action?: ReactNode;
14
+ };
15
+ surface?: Surface;
16
+ };
17
+ /** Renders items in the order given — this kit's convention is newest first. */
18
+ export declare function Timeline({ children, empty, surface }: TimelineProps): import("react").JSX.Element | null;
19
+ export declare namespace Timeline {
20
+ var Item: ({ label, at, tone, action }: TimelineItemProps) => import("react").JSX.Element;
21
+ }
@@ -0,0 +1,30 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { SurfaceProvider, useSurface } from "../../foundations/surface.js";
4
+ import { Empty } from "../../primitives/notice/Notice.js";
5
+ import { DateValue } from "../../primitives/value/Fecha.js";
6
+ import { Children } from "react";
7
+ const DOT_TONE = {
8
+ neutral: { canvas: "bg-muted", chrome: "bg-chrome-muted" },
9
+ info: { canvas: "bg-info", chrome: "bg-chrome-link" },
10
+ good: { canvas: "bg-good", chrome: "bg-chrome-good" },
11
+ warn: { canvas: "bg-warn", chrome: "bg-chrome-warn" },
12
+ bad: { canvas: "bg-bad", chrome: "bg-chrome-bad" },
13
+ accent: { canvas: "bg-accent", chrome: "bg-chrome-accent" },
14
+ };
15
+ function Item({ label, at, tone = "neutral", action }) {
16
+ const surface = useSurface();
17
+ const isChrome = surface === "chrome";
18
+ const text = isChrome ? "text-chrome-ink" : "text-ink";
19
+ const rail = isChrome ? "bg-chrome-ink/20" : "bg-line";
20
+ return (_jsxs("li", { className: "group/item relative flex gap-3 pb-4 last:pb-0", children: [_jsxs("span", { className: "relative flex w-2 shrink-0 justify-center", children: [_jsx("span", { className: `mt-1 size-2 shrink-0 rounded-pill ${DOT_TONE[tone][surface]}` }), _jsx("span", { className: `absolute top-3 bottom-0 w-px group-last/item:hidden ${rail}` })] }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex min-w-0 flex-wrap items-baseline gap-x-3 gap-y-0.5", children: [_jsx("span", { className: `min-w-0 text-meta ${text}`, children: label }), _jsx(DateValue, { when: at, format: "exact" })] }), action === undefined ? null : _jsx("div", { className: "mt-1", children: action })] })] }));
21
+ }
22
+ /** Renders items in the order given — this kit's convention is newest first. */
23
+ export function Timeline({ children, empty, surface }) {
24
+ const activeSurface = useSurface(surface);
25
+ if (Children.toArray(children).length === 0) {
26
+ return empty === undefined ? null : (_jsx(Empty, { sentence: empty.sentence, ...(empty.action === undefined ? {} : { action: empty.action }) }));
27
+ }
28
+ return (_jsx(SurfaceProvider, { value: activeSurface, children: _jsx("ol", { className: "flex flex-col", children: children }) }));
29
+ }
30
+ Timeline.Item = Item;
@@ -0,0 +1,3 @@
1
+ export { Chatter, type ChatterEvent, type ChatterLayout, type ChatterProps, type ChatterView, useChatter, } from "./Chatter.js";
2
+ export { type Message, MessageComposer, type MessageComposerProps, type MessageKind, writeANote, } from "./Messages.js";
3
+ export { Timeline, type TimelineItemProps, type TimelineProps, } from "./Timeline.js";
@@ -0,0 +1,4 @@
1
+ /* What a record has been through, beside it: messages and events in one column. */
2
+ export { Chatter, useChatter, } from "./Chatter.js";
3
+ export { MessageComposer, writeANote, } from "./Messages.js";
4
+ export { Timeline, } from "./Timeline.js";
@@ -0,0 +1,52 @@
1
+ import type { Tone } from "../../foundations/types.js";
2
+ import type { ReactNode } from "react";
3
+ /** A group of fields with its name and its status.
4
+ *
5
+ * The `status` is the only thing worth copying from the old console: every
6
+ * section said `Required` or `(Incomplete)` in its header, so you could see
7
+ * **what was missing without opening any of them**. Our version forced you to
8
+ * go into every aspect to discover it was empty. */
9
+ export declare function FormSection({ title, hint, status, actions, columns, children, }: {
10
+ /** Absent when the surface already named the form — a dialog title is the
11
+ * section, and repeating «parámetros» under it is a second chrome. */
12
+ title?: string;
13
+ hint?: string;
14
+ /** Context: the tones are the system's and not two names of their own. `falta`
15
+ * and `listo` were a third scale of meaning that only existed here, and it
16
+ * forced you to translate it in order to paint the same pill. */
17
+ status?: {
18
+ label: string;
19
+ tone?: Tone;
20
+ };
21
+ /** The buttons of THIS section: "add a rule", "copy from the last order". They
22
+ * go in the header and not at the end: what goes at the end closes the whole
23
+ * form, and mixing them makes you doubt what saves what. */
24
+ actions?: ReactNode;
25
+ /** How many columns of fields. In compact it goes back to a single one without
26
+ * asking: two columns in 480 px are two half columns. Three is the ceiling —
27
+ * at the fourth, the label and the value no longer fit on the same line. */
28
+ columns?: 1 | 2 | 3;
29
+ children: ReactNode;
30
+ }): import("react").JSX.Element;
31
+ /** What closes a form. One primary, on the right.
32
+ *
33
+ * Cancel sits just to the left of that primary: the two answers to «what do
34
+ * I do with what I wrote». Destroy sits on the far left. Stuck to the
35
+ * primary, a stray click or an Enter lands on the thing that cannot be
36
+ * undone. The sentence, when there is one, stays with the destroy side —
37
+ * it is the warning, not a third button.
38
+ *
39
+ * Context: on a phone (below `sm`, the 40rem of `--container-handheld`) the bar sticks
40
+ * to the bottom of whatever scrolls the form —the window, or a bottom sheet's body— so
41
+ * the primary stays under the thumb while the fields go by, instead of waiting at the
42
+ * end of a form three screens long. Sticky and not fixed: it is the last thing in the
43
+ * form, so at the end it settles in its own place and covers nothing. On a desk it is
44
+ * exactly the static bar it always was. */
45
+ export declare function FormActions({ primary, secondary, danger, aside, }: {
46
+ primary: ReactNode;
47
+ secondary?: ReactNode;
48
+ /** Destroy. Far from the primary. Red belongs here, not on cancel. */
49
+ danger?: ReactNode;
50
+ /** What has to be said before pressing: "this cannot be undone". */
51
+ aside?: ReactNode;
52
+ }): import("react").JSX.Element;
@@ -0,0 +1,49 @@
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 { Hint } from "../../primitives/hint/Hint.js";
5
+ import { Tag } from "../../primitives/tag/Tag.js";
6
+ /* ==================================================================== *
7
+ * LA COMPOSICIÓN DE UN FORMULARIO: la sección y el pie.
8
+ *
9
+ * Vive en `contexts/form` y no junto a los controles porque no es un control:
10
+ * es lo que los ACOMODA. `TextInput` no sabe que existe un formulario —se usa
11
+ * igual adentro de una celda, de un filtro o de un diálogo— y una sección no
12
+ * sabe qué campos le van a poner adentro. Son dos capas y por eso son dos
13
+ * carpetas: `primitives/field` es CON QUÉ se escribe, esto es CÓMO se arma.
14
+ * ==================================================================== */
15
+ /** A group of fields with its name and its status.
16
+ *
17
+ * The `status` is the only thing worth copying from the old console: every
18
+ * section said `Required` or `(Incomplete)` in its header, so you could see
19
+ * **what was missing without opening any of them**. Our version forced you to
20
+ * go into every aspect to discover it was empty. */
21
+ export function FormSection({ title, hint, status, actions, columns = 1, children, }) {
22
+ const d = useDensity();
23
+ const asGrid = columns > 1 && d === "comfortable";
24
+ const grid = columns === 3 ? "grid-cols-3" : "grid-cols-2";
25
+ const withHeader = title !== undefined ||
26
+ status !== undefined ||
27
+ hint !== undefined ||
28
+ actions !== undefined;
29
+ return (_jsxs("section", { className: `flex min-w-0 flex-col ${byDensity(d, "gap-3", "gap-2")}`, children: [withHeader ? (_jsxs("header", { className: "flex min-w-0 flex-wrap items-center gap-x-2.5 gap-y-1", children: [title === undefined && hint === undefined ? null : (_jsxs("h3", { className: "flex min-w-0 items-center gap-1 text-meta font-medium text-ink", children: [title === undefined ? null : _jsx("span", { className: "min-w-0 truncate", children: title }), hint === undefined ? null : _jsx(Hint, { children: hint })] })), status === undefined ? null : _jsx(Tag, { tone: status.tone, children: status.label }), actions === undefined ? null : (_jsx("span", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: actions }))] })) : null, _jsx("div", { className: `min-w-0 ${asGrid
30
+ ? `grid ${grid} gap-x-8 ${byDensity(d, "gap-y-3.5", "gap-y-2.5")}`
31
+ : `flex flex-col ${byDensity(d, "gap-3.5", "gap-2.5")}`}`, children: children })] }));
32
+ }
33
+ /** What closes a form. One primary, on the right.
34
+ *
35
+ * Cancel sits just to the left of that primary: the two answers to «what do
36
+ * I do with what I wrote». Destroy sits on the far left. Stuck to the
37
+ * primary, a stray click or an Enter lands on the thing that cannot be
38
+ * undone. The sentence, when there is one, stays with the destroy side —
39
+ * it is the warning, not a third button.
40
+ *
41
+ * Context: on a phone (below `sm`, the 40rem of `--container-handheld`) the bar sticks
42
+ * to the bottom of whatever scrolls the form —the window, or a bottom sheet's body— so
43
+ * the primary stays under the thumb while the fields go by, instead of waiting at the
44
+ * end of a form three screens long. Sticky and not fixed: it is the last thing in the
45
+ * form, so at the end it settles in its own place and covers nothing. On a desk it is
46
+ * exactly the static bar it always was. */
47
+ export function FormActions({ primary, secondary, danger, aside, }) {
48
+ return (_jsxs("div", { "data-form-actions": "", className: "flex flex-wrap items-center gap-2 border-t border-line pt-3.5 max-sm:sticky max-sm:bottom-0 max-sm:z-10 max-sm:bg-surface max-sm:safe-bottom", children: [danger, aside === undefined ? null : (_jsx("span", { className: "min-w-0 text-micro text-muted", children: aside })), _jsxs("span", { className: "ml-auto flex items-center gap-2", children: [secondary, primary] })] }));
49
+ }
@@ -0,0 +1,43 @@
1
+ import { type SheetLayout } from "../../primitives/field/layout.js";
2
+ import type { LucideIcon } from "lucide-react";
3
+ import { type ReactNode } from "react";
4
+ export type { SheetLayout };
5
+ export type SheetField = {
6
+ label: string;
7
+ value: ReactNode;
8
+ /** Help on the label, as a `?`. Hover or click. */
9
+ hint?: string;
10
+ mono?: boolean;
11
+ };
12
+ export declare function Sheet({ fields, columns, layout, head, children, }: {
13
+ fields?: readonly SheetField[];
14
+ columns?: 1 | 2 | 3 | 4;
15
+ /** How fields inside this sheet (and its groups) place the label. */
16
+ layout?: SheetLayout;
17
+ /** The top of the paper: groups, then the notebook sitting on its mouth.
18
+ * It shares a short gap with `fields`, so the tabs belong to the sheet
19
+ * and not to the page below. */
20
+ head?: ReactNode;
21
+ children?: ReactNode;
22
+ }): import("react").JSX.Element | null;
23
+ /** A row of columns on the paper. The paper is the sheet; a group is not a
24
+ * second box. A vertical hairline separates columns — that is what still
25
+ * groups them when a column has no title. */
26
+ export declare function SheetGroups({ children, columns, }: {
27
+ children: ReactNode;
28
+ columns?: 2 | 3 | 4;
29
+ }): import("react").JSX.Element;
30
+ /** One column of a `SheetGroups` row.
31
+ *
32
+ * The title is OPTIONAL. With one, it is a name above the fields — the same
33
+ * name in read and in edit, so the paper does not rearrange. Without one,
34
+ * the column is still a group: the hairline between columns is the edge.
35
+ *
36
+ * It is not a tray and not a card. Nested boxes on the sheet made untitled
37
+ * groups look empty and made edit mode look like a dashboard. */
38
+ export declare function SheetGroup({ title, hint, icon: Icon, children, }: {
39
+ title?: string;
40
+ hint?: string;
41
+ icon?: LucideIcon;
42
+ children: ReactNode;
43
+ }): import("react").JSX.Element;