@lar-works/design-system 0.2.1 → 0.3.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 (432) hide show
  1. package/README.md +5 -1
  2. package/dist/actions/Button.d.ts +39 -1
  3. package/dist/actions/Button.js +39 -9
  4. package/dist/actions/Button.js.map +1 -1
  5. package/dist/actions/ButtonLink.d.ts +5 -1
  6. package/dist/actions/ButtonLink.js +28 -2
  7. package/dist/actions/ButtonLink.js.map +1 -1
  8. package/dist/actions/ButtonRecipes.js +7 -0
  9. package/dist/actions/ButtonRecipes.js.map +1 -0
  10. package/dist/actions/IconButton.d.ts +2 -2
  11. package/dist/actions/IconButton.js +1 -1
  12. package/dist/actions/IconButton.js.map +1 -1
  13. package/dist/actions/ThemeSwitch.js +1 -1
  14. package/dist/board/ActivityLine.d.ts +36 -0
  15. package/dist/board/ActivityLine.js +144 -0
  16. package/dist/board/ActivityLine.js.map +1 -0
  17. package/dist/board/ActivityTrack.d.ts +11 -0
  18. package/dist/board/ActivityTrack.js +25 -0
  19. package/dist/board/ActivityTrack.js.map +1 -0
  20. package/dist/board/AddItem.d.ts +82 -0
  21. package/dist/board/AddItem.js +185 -0
  22. package/dist/board/AddItem.js.map +1 -0
  23. package/dist/board/Archive.d.ts +21 -0
  24. package/dist/board/Archive.js +63 -0
  25. package/dist/board/Archive.js.map +1 -0
  26. package/dist/board/Attention.d.ts +66 -0
  27. package/dist/board/Attention.js +122 -0
  28. package/dist/board/Attention.js.map +1 -0
  29. package/dist/board/BoardShell.d.ts +16 -0
  30. package/dist/board/BoardShell.js +35 -0
  31. package/dist/board/BoardShell.js.map +1 -0
  32. package/dist/board/BoardTitleBar.d.ts +50 -0
  33. package/dist/board/BoardTitleBar.js +125 -0
  34. package/dist/board/BoardTitleBar.js.map +1 -0
  35. package/dist/board/ButtonKinds.d.ts +24 -0
  36. package/dist/board/ButtonKinds.js +19 -0
  37. package/dist/board/ButtonKinds.js.map +1 -0
  38. package/dist/board/Cleanup.d.ts +8 -0
  39. package/dist/board/Cleanup.js +15 -0
  40. package/dist/board/Cleanup.js.map +1 -0
  41. package/dist/board/Counters.d.ts +101 -0
  42. package/dist/board/Counters.js +202 -0
  43. package/dist/board/Counters.js.map +1 -0
  44. package/dist/board/DataAttributes.d.ts +6 -0
  45. package/dist/board/Dependencies.d.ts +17 -0
  46. package/dist/board/Dependencies.js +44 -0
  47. package/dist/board/Dependencies.js.map +1 -0
  48. package/dist/board/Desk.d.ts +52 -0
  49. package/dist/board/Desk.js +130 -0
  50. package/dist/board/Desk.js.map +1 -0
  51. package/dist/board/Dossier.d.ts +100 -0
  52. package/dist/board/Dossier.js +194 -0
  53. package/dist/board/Dossier.js.map +1 -0
  54. package/dist/board/Filters.d.ts +33 -0
  55. package/dist/board/Filters.js +64 -0
  56. package/dist/board/Filters.js.map +1 -0
  57. package/dist/board/ItemDetails.d.ts +167 -0
  58. package/dist/board/ItemDetails.js +339 -0
  59. package/dist/board/ItemDetails.js.map +1 -0
  60. package/dist/board/ItemDialog.d.ts +73 -0
  61. package/dist/board/ItemDialog.js +140 -0
  62. package/dist/board/ItemDialog.js.map +1 -0
  63. package/dist/board/ItemParts.d.ts +42 -0
  64. package/dist/board/ItemParts.js +82 -0
  65. package/dist/board/ItemParts.js.map +1 -0
  66. package/dist/board/ItemProgress.d.ts +56 -0
  67. package/dist/board/ItemProgress.js +138 -0
  68. package/dist/board/ItemProgress.js.map +1 -0
  69. package/dist/board/List.d.ts +65 -0
  70. package/dist/board/List.js +118 -0
  71. package/dist/board/List.js.map +1 -0
  72. package/dist/board/LoadingScreen.d.ts +38 -0
  73. package/dist/board/LoadingScreen.js +74 -0
  74. package/dist/board/LoadingScreen.js.map +1 -0
  75. package/dist/board/NeedsYou.d.ts +13 -0
  76. package/dist/board/NeedsYou.js +31 -0
  77. package/dist/board/NeedsYou.js.map +1 -0
  78. package/dist/board/Onboarding.d.ts +53 -0
  79. package/dist/board/Onboarding.js +122 -0
  80. package/dist/board/Onboarding.js.map +1 -0
  81. package/dist/board/PartsList.d.ts +60 -0
  82. package/dist/board/PartsList.js +115 -0
  83. package/dist/board/PartsList.js.map +1 -0
  84. package/dist/board/ProjectIcon.d.ts +51 -0
  85. package/dist/board/ProjectIcon.js +120 -0
  86. package/dist/board/ProjectIcon.js.map +1 -0
  87. package/dist/board/PullRequests.d.ts +43 -0
  88. package/dist/board/PullRequests.js +83 -0
  89. package/dist/board/PullRequests.js.map +1 -0
  90. package/dist/board/RowStyles.js +14 -0
  91. package/dist/board/RowStyles.js.map +1 -0
  92. package/dist/board/Settings.d.ts +54 -0
  93. package/dist/board/Settings.js +112 -0
  94. package/dist/board/Settings.js.map +1 -0
  95. package/dist/board/Slices.d.ts +32 -0
  96. package/dist/board/Slices.js +88 -0
  97. package/dist/board/Slices.js.map +1 -0
  98. package/dist/board/SourceIcon.d.ts +12 -0
  99. package/dist/board/SourceIcon.js +24 -0
  100. package/dist/board/SourceIcon.js.map +1 -0
  101. package/dist/board/StagePane.d.ts +43 -0
  102. package/dist/board/StagePane.js +97 -0
  103. package/dist/board/StagePane.js.map +1 -0
  104. package/dist/board/StageRow.d.ts +141 -0
  105. package/dist/board/StageRow.js +287 -0
  106. package/dist/board/StageRow.js.map +1 -0
  107. package/dist/board/StageTrack.d.ts +18 -0
  108. package/dist/board/StageTrack.js +38 -0
  109. package/dist/board/StageTrack.js.map +1 -0
  110. package/dist/board/StartControls.d.ts +30 -0
  111. package/dist/board/StartControls.js +51 -0
  112. package/dist/board/StartControls.js.map +1 -0
  113. package/dist/board/StatusColors.d.ts +5 -0
  114. package/dist/board/StatusColors.js +17 -0
  115. package/dist/board/StatusColors.js.map +1 -0
  116. package/dist/board/StatusGlyph.d.ts +18 -0
  117. package/dist/board/StatusGlyph.js +51 -0
  118. package/dist/board/StatusGlyph.js.map +1 -0
  119. package/dist/board/Threads.d.ts +13 -0
  120. package/dist/board/Threads.js +35 -0
  121. package/dist/board/Threads.js.map +1 -0
  122. package/dist/board/TrackerLabels.d.ts +27 -0
  123. package/dist/board/TrackerLabels.js +56 -0
  124. package/dist/board/TrackerLabels.js.map +1 -0
  125. package/dist/board/UpdatePill.d.ts +52 -0
  126. package/dist/board/UpdatePill.js +188 -0
  127. package/dist/board/UpdatePill.js.map +1 -0
  128. package/dist/board/Vocabulary.d.ts +56 -0
  129. package/dist/board/Vocabulary.js +104 -0
  130. package/dist/board/Vocabulary.js.map +1 -0
  131. package/dist/board/Warnings.d.ts +35 -0
  132. package/dist/board/Warnings.js +85 -0
  133. package/dist/board/Warnings.js.map +1 -0
  134. package/dist/board/WorkMap.d.ts +136 -0
  135. package/dist/board/WorkMap.js +274 -0
  136. package/dist/board/WorkMap.js.map +1 -0
  137. package/dist/board/index.d.ts +42 -0
  138. package/dist/collections/CollectionState.d.ts +10 -1
  139. package/dist/collections/CollectionState.js +12 -5
  140. package/dist/collections/CollectionState.js.map +1 -1
  141. package/dist/collections/ResultList.js +1 -1
  142. package/dist/collections/ScrollRow.js +1 -1
  143. package/dist/collections/VirtualList.js +1 -1
  144. package/dist/display/Avatar.d.ts +5 -2
  145. package/dist/display/Avatar.js +2 -2
  146. package/dist/display/Avatar.js.map +1 -1
  147. package/dist/display/Badge.d.ts +6 -1
  148. package/dist/display/Badge.js +9 -4
  149. package/dist/display/Badge.js.map +1 -1
  150. package/dist/display/CheckList.js +1 -1
  151. package/dist/display/Comment.d.ts +12 -0
  152. package/dist/display/Comment.js +39 -0
  153. package/dist/display/Comment.js.map +1 -0
  154. package/dist/display/CopyButton.d.ts +10 -2
  155. package/dist/display/CopyButton.js +29 -16
  156. package/dist/display/CopyButton.js.map +1 -1
  157. package/dist/display/Diagram.d.ts +17 -0
  158. package/dist/display/Diagram.js +49 -0
  159. package/dist/display/Diagram.js.map +1 -0
  160. package/dist/display/ImagePicker.js +1 -1
  161. package/dist/display/InfoBox.js +2 -2
  162. package/dist/display/InsetPanel.d.ts +3 -1
  163. package/dist/display/InsetPanel.js +7 -4
  164. package/dist/display/InsetPanel.js.map +1 -1
  165. package/dist/display/ItemAction.js +2 -2
  166. package/dist/display/LabelChip.d.ts +26 -0
  167. package/dist/display/LabelChip.js +41 -0
  168. package/dist/display/LabelChip.js.map +1 -0
  169. package/dist/display/LabelTint.js +60 -0
  170. package/dist/display/LabelTint.js.map +1 -0
  171. package/dist/display/Person.d.ts +5 -0
  172. package/dist/display/Person.js +19 -0
  173. package/dist/display/Person.js.map +1 -0
  174. package/dist/display/PropertySheet.js +1 -1
  175. package/dist/display/RadioChoice.d.ts +9 -2
  176. package/dist/display/RadioChoice.js +5 -1
  177. package/dist/display/RadioChoice.js.map +1 -1
  178. package/dist/display/RatingLink.js +1 -1
  179. package/dist/display/RichText.d.ts +12 -0
  180. package/dist/display/RichText.js +94 -0
  181. package/dist/display/RichText.js.map +1 -0
  182. package/dist/display/RowList.js +1 -1
  183. package/dist/display/index.d.ts +6 -1
  184. package/dist/feedback/Alert.js +1 -1
  185. package/dist/feedback/AsyncState.js +1 -1
  186. package/dist/feedback/DismissButton.d.ts +12 -0
  187. package/dist/feedback/DismissButton.js +20 -0
  188. package/dist/feedback/DismissButton.js.map +1 -0
  189. package/dist/feedback/ErrorNotification.js +2 -0
  190. package/dist/feedback/ErrorNotification.js.map +1 -1
  191. package/dist/feedback/FormResult.d.ts +16 -0
  192. package/dist/feedback/FormResult.js +30 -0
  193. package/dist/feedback/FormResult.js.map +1 -0
  194. package/dist/feedback/LiveRegion.d.ts +7 -0
  195. package/dist/feedback/LiveRegion.js +15 -0
  196. package/dist/feedback/LiveRegion.js.map +1 -0
  197. package/dist/feedback/Loading.d.ts +19 -0
  198. package/dist/feedback/Loading.js +63 -0
  199. package/dist/feedback/Loading.js.map +1 -0
  200. package/dist/feedback/Notifications.d.ts +35 -1
  201. package/dist/feedback/Notifications.js +196 -4
  202. package/dist/feedback/Notifications.js.map +1 -1
  203. package/dist/feedback/Progress.d.ts +15 -0
  204. package/dist/feedback/Progress.js +38 -0
  205. package/dist/feedback/Progress.js.map +1 -0
  206. package/dist/feedback/ProgressStatusRow.js +1 -1
  207. package/dist/feedback/StatusIndicator.d.ts +6 -1
  208. package/dist/feedback/StatusIndicator.js +19 -5
  209. package/dist/feedback/StatusIndicator.js.map +1 -1
  210. package/dist/feedback/index.d.ts +8 -4
  211. package/dist/forms/Checkbox.js +1 -1
  212. package/dist/forms/ColorSwatches.d.ts +21 -0
  213. package/dist/forms/ColorSwatches.js +26 -0
  214. package/dist/forms/ColorSwatches.js.map +1 -0
  215. package/dist/forms/FormSection.d.ts +68 -6
  216. package/dist/forms/FormSection.js +139 -8
  217. package/dist/forms/FormSection.js.map +1 -1
  218. package/dist/forms/HiddenField.d.ts +6 -0
  219. package/dist/forms/HiddenField.js +13 -0
  220. package/dist/forms/HiddenField.js.map +1 -0
  221. package/dist/forms/Input.d.ts +12 -2
  222. package/dist/forms/Input.js +10 -3
  223. package/dist/forms/Input.js.map +1 -1
  224. package/dist/forms/LabelPicker.d.ts +43 -0
  225. package/dist/forms/LabelPicker.js +107 -0
  226. package/dist/forms/LabelPicker.js.map +1 -0
  227. package/dist/forms/MarkdownEditor.d.ts +21 -0
  228. package/dist/forms/MarkdownEditor.js +175 -0
  229. package/dist/forms/MarkdownEditor.js.map +1 -0
  230. package/dist/forms/MarkdownToolbar.js +204 -0
  231. package/dist/forms/MarkdownToolbar.js.map +1 -0
  232. package/dist/forms/OptionSelect.d.ts +30 -9
  233. package/dist/forms/OptionSelect.js +53 -13
  234. package/dist/forms/OptionSelect.js.map +1 -1
  235. package/dist/forms/Select.d.ts +4 -1
  236. package/dist/forms/Select.js +3 -1
  237. package/dist/forms/Select.js.map +1 -1
  238. package/dist/forms/Switch.d.ts +4 -1
  239. package/dist/forms/Switch.js +5 -2
  240. package/dist/forms/Switch.js.map +1 -1
  241. package/dist/forms/TagInput.js +1 -1
  242. package/dist/forms/index.d.ts +7 -3
  243. package/dist/foundations/AmbientMotion.d.ts +2 -0
  244. package/dist/foundations/AmbientMotion.js +39 -0
  245. package/dist/foundations/AmbientMotion.js.map +1 -0
  246. package/dist/foundations/DesignSystemProvider.d.ts +34 -0
  247. package/dist/foundations/DesignSystemProvider.js +26 -1
  248. package/dist/foundations/DesignSystemProvider.js.map +1 -1
  249. package/dist/foundations/index.d.ts +2 -1
  250. package/dist/icons/BrandIcons.d.ts +8 -2
  251. package/dist/icons/BrandIcons.js +14 -3
  252. package/dist/icons/BrandIcons.js.map +1 -1
  253. package/dist/icons/dynamic.d.ts +2 -0
  254. package/dist/icons/dynamic.js +1 -0
  255. package/dist/icons/index.d.ts +2 -2
  256. package/dist/icons/index.js +1 -1
  257. package/dist/icons.d.ts +2 -2
  258. package/dist/icons.js +1 -1
  259. package/dist/index.d.ts +71 -10
  260. package/dist/index.js +78 -21
  261. package/dist/layout/Site.js +1 -1
  262. package/dist/layout/TitleBar.js +1 -1
  263. package/dist/layout/index.d.ts +2 -2
  264. package/dist/layout/index.js +3 -3
  265. package/dist/layout/toolbar/CommandPaletteTrigger.d.ts +17 -2
  266. package/dist/layout/toolbar/CommandPaletteTrigger.js +89 -6
  267. package/dist/layout/toolbar/CommandPaletteTrigger.js.map +1 -1
  268. package/dist/layout/toolbar/TriggerFit.js +56 -0
  269. package/dist/layout/toolbar/TriggerFit.js.map +1 -0
  270. package/dist/navigation/CollectionBrowseSelector.js +1 -1
  271. package/dist/navigation/CollectionViewToggle.d.ts +26 -0
  272. package/dist/navigation/CollectionViewToggle.js +54 -23
  273. package/dist/navigation/CollectionViewToggle.js.map +1 -1
  274. package/dist/navigation/DrilldownBrowseSelector.js +1 -1
  275. package/dist/navigation/FolderSelector.js +2 -2
  276. package/dist/navigation/SortMenu.d.ts +10 -0
  277. package/dist/navigation/SortMenu.js +33 -0
  278. package/dist/navigation/SortMenu.js.map +1 -0
  279. package/dist/navigation/index.d.ts +3 -2
  280. package/dist/overlays/CommandPalette.d.ts +38 -4
  281. package/dist/overlays/CommandPalette.js +140 -54
  282. package/dist/overlays/CommandPalette.js.map +1 -1
  283. package/dist/overlays/Drawer.js +1 -1
  284. package/dist/overlays/DropdownMenu.d.ts +7 -1
  285. package/dist/overlays/DropdownMenu.js +13 -2
  286. package/dist/overlays/DropdownMenu.js.map +1 -1
  287. package/dist/overlays/HelpTip.d.ts +8 -0
  288. package/dist/overlays/HelpTip.js +29 -0
  289. package/dist/overlays/HelpTip.js.map +1 -0
  290. package/dist/overlays/ImageViewer.js +2 -2
  291. package/dist/overlays/Modal.d.ts +5 -0
  292. package/dist/overlays/Modal.js +17 -2
  293. package/dist/overlays/Modal.js.map +1 -1
  294. package/dist/overlays/ModalExpandButton.d.ts +18 -0
  295. package/dist/overlays/ModalExpandButton.js +43 -0
  296. package/dist/overlays/ModalExpandButton.js.map +1 -0
  297. package/dist/overlays/Popover.d.ts +2 -1
  298. package/dist/overlays/Popover.js +1 -0
  299. package/dist/overlays/Popover.js.map +1 -1
  300. package/dist/overlays/index.d.ts +4 -2
  301. package/dist/showcase/Cards.js +1 -1
  302. package/dist/showcase/FeatureRow.js +1 -1
  303. package/dist/showcase/PhotoSearchConcept.js +1 -1
  304. package/dist/showcase/ProductBand.js +1 -1
  305. package/dist/showcase/Status.js +1 -1
  306. package/dist/typography/Code.d.ts +18 -0
  307. package/dist/typography/Code.js +24 -0
  308. package/dist/typography/Code.js.map +1 -0
  309. package/dist/typography/Link.d.ts +7 -2
  310. package/dist/typography/Link.js +15 -5
  311. package/dist/typography/Link.js.map +1 -1
  312. package/dist/typography/Typography.d.ts +19 -1
  313. package/dist/typography/Typography.js +11 -3
  314. package/dist/typography/Typography.js.map +1 -1
  315. package/dist/typography/index.d.ts +3 -3
  316. package/package.json +26 -3
  317. package/src/actions/Button.tsx +78 -11
  318. package/src/actions/ButtonLink.tsx +34 -0
  319. package/src/actions/ButtonRecipes.ts +10 -0
  320. package/src/actions/IconButton.tsx +7 -4
  321. package/src/board/ActivityLine.tsx +176 -0
  322. package/src/board/ActivityTrack.tsx +23 -0
  323. package/src/board/AddItem.tsx +259 -0
  324. package/src/board/Archive.tsx +75 -0
  325. package/src/board/Attention.tsx +135 -0
  326. package/src/board/BoardShell.tsx +30 -0
  327. package/src/board/BoardTitleBar.tsx +167 -0
  328. package/src/board/ButtonKinds.ts +32 -0
  329. package/src/board/Cleanup.tsx +19 -0
  330. package/src/board/Counters.tsx +224 -0
  331. package/src/board/DataAttributes.ts +3 -0
  332. package/src/board/Dependencies.tsx +49 -0
  333. package/src/board/Desk.tsx +155 -0
  334. package/src/board/Dossier.tsx +262 -0
  335. package/src/board/Filters.tsx +85 -0
  336. package/src/board/ItemDetails.tsx +435 -0
  337. package/src/board/ItemDialog.tsx +179 -0
  338. package/src/board/ItemParts.tsx +128 -0
  339. package/src/board/ItemProgress.tsx +164 -0
  340. package/src/board/List.tsx +154 -0
  341. package/src/board/LoadingScreen.tsx +78 -0
  342. package/src/board/NeedsYou.tsx +30 -0
  343. package/src/board/Onboarding.tsx +124 -0
  344. package/src/board/PartsList.tsx +160 -0
  345. package/src/board/ProjectIcon.tsx +172 -0
  346. package/src/board/PullRequests.tsx +106 -0
  347. package/src/board/RowStyles.ts +17 -0
  348. package/src/board/Settings.tsx +124 -0
  349. package/src/board/Slices.tsx +103 -0
  350. package/src/board/SourceIcon.tsx +33 -0
  351. package/src/board/StagePane.tsx +128 -0
  352. package/src/board/StageRow.tsx +320 -0
  353. package/src/board/StageTrack.tsx +61 -0
  354. package/src/board/StartControls.tsx +77 -0
  355. package/src/board/StatusColors.ts +28 -0
  356. package/src/board/StatusGlyph.tsx +70 -0
  357. package/src/board/Threads.tsx +38 -0
  358. package/src/board/TrackerLabels.tsx +75 -0
  359. package/src/board/UpdatePill.tsx +222 -0
  360. package/src/board/Vocabulary.tsx +155 -0
  361. package/src/board/Warnings.tsx +83 -0
  362. package/src/board/WorkMap.tsx +436 -0
  363. package/src/board/base.css +121 -0
  364. package/src/board/button-kinds.css +8 -0
  365. package/src/board/index.ts +224 -0
  366. package/src/board/items.css +75 -0
  367. package/src/board/loading-screen.css +171 -0
  368. package/src/board/rows.css +180 -0
  369. package/src/board/title-bar.css +56 -0
  370. package/src/board/tokens.css +52 -0
  371. package/src/board.css +19 -0
  372. package/src/collections/CollectionState.tsx +20 -7
  373. package/src/display/Avatar.tsx +6 -3
  374. package/src/display/Badge.tsx +25 -3
  375. package/src/display/Comment.tsx +26 -0
  376. package/src/display/CopyButton.tsx +48 -18
  377. package/src/display/Diagram.tsx +59 -0
  378. package/src/display/InsetPanel.tsx +4 -1
  379. package/src/display/LabelChip.tsx +73 -0
  380. package/src/display/LabelTint.ts +72 -0
  381. package/src/display/Person.tsx +11 -0
  382. package/src/display/RadioChoice.tsx +11 -2
  383. package/src/display/RichText.tsx +114 -0
  384. package/src/display/index.ts +5 -0
  385. package/src/feedback/DismissButton.tsx +28 -0
  386. package/src/feedback/ErrorNotification.ts +3 -0
  387. package/src/feedback/FormResult.tsx +50 -0
  388. package/src/feedback/LiveRegion.tsx +10 -0
  389. package/src/feedback/Loading.tsx +75 -0
  390. package/src/feedback/Notifications.tsx +267 -2
  391. package/src/feedback/Progress.tsx +44 -0
  392. package/src/feedback/StatusIndicator.tsx +34 -3
  393. package/src/feedback/index.ts +12 -2
  394. package/src/forms/ColorSwatches.tsx +50 -0
  395. package/src/forms/FormSection.tsx +245 -10
  396. package/src/forms/HiddenField.tsx +4 -0
  397. package/src/forms/Input.tsx +26 -4
  398. package/src/forms/LabelPicker.tsx +140 -0
  399. package/src/forms/MarkdownEditor.tsx +283 -0
  400. package/src/forms/MarkdownToolbar.tsx +267 -0
  401. package/src/forms/OptionSelect.tsx +110 -25
  402. package/src/forms/Select.tsx +20 -13
  403. package/src/forms/Switch.tsx +16 -2
  404. package/src/forms/index.ts +16 -2
  405. package/src/foundations/AmbientMotion.ts +51 -0
  406. package/src/foundations/DesignSystemProvider.tsx +19 -0
  407. package/src/foundations/index.ts +1 -0
  408. package/src/foundations/theme.css +64 -0
  409. package/src/icons/BrandIcons.tsx +12 -3
  410. package/src/icons/dynamic.ts +4 -0
  411. package/src/icons/index.ts +1 -1
  412. package/src/index.ts +2 -1
  413. package/src/layout/index.ts +1 -1
  414. package/src/layout/toolbar/CommandPaletteTrigger.tsx +187 -31
  415. package/src/layout/toolbar/TriggerFit.ts +84 -0
  416. package/src/navigation/CollectionViewToggle.tsx +94 -24
  417. package/src/navigation/SortMenu.tsx +41 -0
  418. package/src/navigation/index.ts +2 -1
  419. package/src/overlays/CommandPalette.tsx +190 -60
  420. package/src/overlays/DropdownMenu.tsx +12 -1
  421. package/src/overlays/HelpTip.tsx +29 -0
  422. package/src/overlays/Modal.tsx +23 -0
  423. package/src/overlays/ModalExpandButton.tsx +48 -0
  424. package/src/overlays/Popover.tsx +3 -1
  425. package/src/overlays/index.ts +9 -1
  426. package/src/styles.css +3 -1
  427. package/src/typography/Code.tsx +24 -0
  428. package/src/typography/Link.tsx +19 -10
  429. package/src/typography/Typography.tsx +25 -2
  430. package/src/typography/index.ts +1 -1
  431. package/dist/feedback/index.js +0 -11
  432. package/dist/typography/index.js +0 -4
package/README.md CHANGED
@@ -22,7 +22,11 @@ import { PlusIcon } from '@lar-works/design-system/icons';
22
22
  ```
23
23
 
24
24
  A website that uses the marketing showcase (`Hero`, device frames, `ServerUnit`…) imports
25
- `@lar-works/design-system/showcase.css` instead of `styles.css`.
25
+ `@lar-works/design-system/showcase.css` instead of `styles.css`, and Lar Factory's board, which composes the `board`
26
+ components (its title bar, counters, desk, loading screen…), imports `@lar-works/design-system/board.css`.
27
+
28
+ Icons come from `@lar-works/design-system/icons`, and lucide's `DynamicIcon`, which draws an icon by its name and loads
29
+ lucide's name map lazily, from `@lar-works/design-system/icons/dynamic`.
26
30
 
27
31
  Apps compose these components and never style anything themselves; `@lar-works/config`'s lint rules enforce it.
28
32
  `@lar-works/design-system/testing` has helpers for apps' jsdom test setup.
@@ -1,10 +1,12 @@
1
1
  import { ButtonProps } from "@ninna-ui/primitives";
2
2
  declare const recipes: {
3
- readonly primary: 'border-primary bg-primary text-primary-content shadow-xs shadow-primary/24 inset-shadow-[0_1px_rgb(255_255_255/16%)] hover:bg-primary/90 active:shadow-none active:inset-shadow-[0_1px_rgb(0_0_0/8%)]';
3
+ readonly primary: "border-primary bg-primary text-primary-content shadow-xs shadow-primary/24 inset-shadow-[0_1px_rgb(255_255_255/16%)] hover:bg-primary/90 active:shadow-none active:inset-shadow-[0_1px_rgb(0_0_0/8%)]";
4
4
  readonly secondary: "border-base-400/90 bg-base-100 text-base-content shadow-xs/5 hover:bg-base-200/70 dark:border-base-400 dark:bg-base-400/30 dark:hover:bg-base-400/60 [&_[data-slot=icon]]:text-base-700";
5
5
  readonly quiet: "border-transparent text-base-content hover:bg-base-200 data-[state=open]:bg-base-200 [&_[data-slot=icon]]:text-base-700";
6
6
  readonly row: "border-transparent text-base-content hover:bg-base-200 data-[state=open]:bg-base-200 [&_[data-slot=icon]]:text-base-700 h-auto min-h-8 min-w-0 max-w-full justify-start whitespace-normal px-0 py-1 text-left text-xs font-normal text-base-700 hover:bg-transparent hover:text-base-content sm:h-auto active:scale-100";
7
7
  readonly subtle: 'border-transparent bg-base-200 text-base-content hover:bg-base-300/70 dark:bg-base-300 dark:hover:bg-base-400';
8
+ /** The primary colour tinted on the card, with no border or shadow, deeper on hover and while its popup is open. */
9
+ readonly tinted: 'border-transparent bg-[color-mix(in_srgb,var(--color-primary)_10%,var(--color-base-100))] text-primary shadow-none not-disabled:not-aria-disabled:hover:bg-[color-mix(in_srgb,var(--color-primary)_18%,var(--color-base-100))] data-[state=open]:bg-[color-mix(in_srgb,var(--color-primary)_18%,var(--color-base-100))] [&_[data-slot=icon]]:text-current';
8
10
  readonly destructive: 'border-danger bg-danger text-white shadow-xs shadow-danger/24 inset-shadow-[0_1px_rgb(255_255_255/16%)] hover:bg-danger/90 active:shadow-none';
9
11
  readonly 'destructive-quiet': 'border-transparent text-(--lar-danger-text) hover:bg-danger/8 dark:hover:bg-danger/16 [&_[data-slot=icon]]:text-current';
10
12
  readonly choice: "border-base-400/90 bg-base-100 text-base-content shadow-xs/5 hover:bg-base-200/70 dark:border-base-400 dark:bg-base-400/30 dark:hover:bg-base-400/60 [&_[data-slot=icon]]:text-base-700";
@@ -16,10 +18,46 @@ declare const recipes: {
16
18
  type ButtonProps$1 = Omit<ButtonProps, 'color' | 'radius' | 'size' | 'variant'> & {
17
19
  variant?: keyof typeof recipes;
18
20
  selected?: boolean;
21
+ /** The dense 28px control with 12px text, as Lar Factory's board draws every button. */
22
+ compact?: boolean;
23
+ /** Lets a long label wrap, anywhere in a long word if it must, growing the button, which never grows past its
24
+ * container, where it would otherwise clip. */
25
+ wrap?: boolean;
26
+ /** A square button showing its `leftIcon` alone, named by its `aria-label`. */
27
+ iconOnly?: boolean;
28
+ /** Lets the button shrink in a crowded row: its label truncates, while its `mark` (a trailing character, such as ▾
29
+ * or ✓) stays. */
30
+ shrinks?: boolean;
31
+ mark?: string;
32
+ /** Its action is in flight: a spinner, turning even under reduced motion, takes its left icon's place, and it reads
33
+ * as busy. `false` leaves out the busy state altogether. */
34
+ busy?: boolean;
35
+ /** Draws the button as waiting, with the progress cursor at 70%, while `aria-disabled` holds it for an action in
36
+ * flight; `'disabled'` draws it as a disabled button instead, while it keeps its focus (a save with nothing to
37
+ * save, say). */
38
+ pendingLook?: boolean | 'disabled';
19
39
  };
20
40
  declare const Button$1: import("react").ForwardRefExoticComponent<Omit<ButtonProps, "color" | "radius" | "size" | "variant"> & {
21
41
  variant?: keyof typeof recipes;
22
42
  selected?: boolean;
43
+ /** The dense 28px control with 12px text, as Lar Factory's board draws every button. */
44
+ compact?: boolean;
45
+ /** Lets a long label wrap, anywhere in a long word if it must, growing the button, which never grows past its
46
+ * container, where it would otherwise clip. */
47
+ wrap?: boolean;
48
+ /** A square button showing its `leftIcon` alone, named by its `aria-label`. */
49
+ iconOnly?: boolean;
50
+ /** Lets the button shrink in a crowded row: its label truncates, while its `mark` (a trailing character, such as ▾
51
+ * or ✓) stays. */
52
+ shrinks?: boolean;
53
+ mark?: string;
54
+ /** Its action is in flight: a spinner, turning even under reduced motion, takes its left icon's place, and it reads
55
+ * as busy. `false` leaves out the busy state altogether. */
56
+ busy?: boolean;
57
+ /** Draws the button as waiting, with the progress cursor at 70%, while `aria-disabled` holds it for an action in
58
+ * flight; `'disabled'` draws it as a disabled button instead, while it keeps its focus (a save with nothing to
59
+ * save, say). */
60
+ pendingLook?: boolean | 'disabled';
23
61
  } & import("react").RefAttributes<HTMLButtonElement>>;
24
62
  export { Button$1 as Button, ButtonProps$1 as ButtonProps };
25
63
  //# sourceMappingURL=Button.d.ts.map
@@ -1,19 +1,33 @@
1
+ import { SpinnerIcon } from "../feedback/Loading.js";
1
2
  import { tabbable } from "../foundations/KeyboardFocus.js";
3
+ import { ghostRecipe, outlineRecipe, primaryRecipe } from "./ButtonRecipes.js";
2
4
  import { Button } from "@ninna-ui/primitives";
3
5
  import { forwardRef } from "react";
4
- import { jsx } from "react/jsx-runtime";
6
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
7
  // src/actions/Button.tsx
6
8
  /** T3 Code's button (coss ui): an 8px-radius control, 36px on touch and 32px with a pointer, that dips to
7
9
  * 97% while pressed. Every recipe sets its own colours, so ninna-ui only supplies behaviour. */
8
- const base = "h-9 gap-2 rounded-md border px-[11px] text-sm font-medium whitespace-nowrap transition-[background-color,box-shadow,scale,color] duration-150 active:scale-[0.97] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary focus-visible:ring-offset-0 disabled:opacity-64 sm:h-8 [&_[data-slot=icon]>svg]:size-4";
9
- const outline = "border-base-400/90 bg-base-100 text-base-content shadow-xs/5 hover:bg-base-200/70 dark:border-base-400 dark:bg-base-400/30 dark:hover:bg-base-400/60 [&_[data-slot=icon]]:text-base-700";
10
- const ghost = "border-transparent text-base-content hover:bg-base-200 data-[state=open]:bg-base-200 [&_[data-slot=icon]]:text-base-700";
10
+ const base = "gap-2 rounded-md border px-[11px] font-medium transition-[background-color,box-shadow,scale,color] duration-150 active:scale-[0.97] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary focus-visible:ring-offset-0 disabled:opacity-64 [&_[data-slot=icon]>svg]:size-4";
11
+ /** The default 36px (32px with a pointer) control, and the compact 28px one with 12px text that dense tools use. */
12
+ const sizes = {
13
+ default: "h-9 text-sm sm:h-8",
14
+ compact: "h-7 text-xs sm:h-7"
15
+ };
16
+ /** A label that would clip on a narrow surface wraps instead, growing the button past its height. */
17
+ const wrapping = {
18
+ nowrap: "whitespace-nowrap",
19
+ wrap: "h-auto min-h-7 max-w-full min-w-0 py-1 whitespace-normal wrap-anywhere sm:h-auto"
20
+ };
21
+ const outline = outlineRecipe;
22
+ const ghost = ghostRecipe;
11
23
  const recipes = {
12
- primary: "border-primary bg-primary text-primary-content shadow-xs shadow-primary/24 inset-shadow-[0_1px_rgb(255_255_255/16%)] hover:bg-primary/90 active:shadow-none active:inset-shadow-[0_1px_rgb(0_0_0/8%)]",
24
+ primary: primaryRecipe,
13
25
  secondary: outline,
14
26
  quiet: ghost,
15
27
  row: `${ghost} h-auto min-h-8 min-w-0 max-w-full justify-start whitespace-normal px-0 py-1 text-left text-xs font-normal text-base-700 hover:bg-transparent hover:text-base-content sm:h-auto active:scale-100`,
16
28
  subtle: "border-transparent bg-base-200 text-base-content hover:bg-base-300/70 dark:bg-base-300 dark:hover:bg-base-400",
29
+ /** The primary colour tinted on the card, with no border or shadow, deeper on hover and while its popup is open. */
30
+ tinted: "border-transparent bg-[color-mix(in_srgb,var(--color-primary)_10%,var(--color-base-100))] text-primary shadow-none not-disabled:not-aria-disabled:hover:bg-[color-mix(in_srgb,var(--color-primary)_18%,var(--color-base-100))] data-[state=open]:bg-[color-mix(in_srgb,var(--color-primary)_18%,var(--color-base-100))] [&_[data-slot=icon]]:text-current",
17
31
  destructive: "border-danger bg-danger text-white shadow-xs shadow-danger/24 inset-shadow-[0_1px_rgb(255_255_255/16%)] hover:bg-danger/90 active:shadow-none",
18
32
  "destructive-quiet": "border-transparent text-(--lar-danger-text) hover:bg-danger/8 dark:hover:bg-danger/16 [&_[data-slot=icon]]:text-current",
19
33
  choice: outline,
@@ -22,8 +36,15 @@ const recipes = {
22
36
  avatar: "size-7 rounded-full border-transparent p-0 hover:bg-transparent sm:h-7 [&>*]:size-7",
23
37
  status: "h-4 min-w-0 max-w-full justify-start gap-1.5 rounded-sm border-transparent px-0 text-xs font-normal text-base-700 hover:bg-transparent hover:text-base-content sm:h-4 active:scale-100 [&>svg]:size-3 [&>svg]:shrink-0"
24
38
  };
39
+ /** An icon-only button is as wide as it is tall, with no padding. */
40
+ const square = {
41
+ default: "size-9 px-0 sm:size-8",
42
+ compact: "w-7 px-0"
43
+ };
44
+ const pending = "aria-disabled:cursor-progress aria-disabled:opacity-70";
45
+ const heldDisabled = "aria-disabled:opacity-64";
25
46
  const selectedChoice = "border-primary/60 bg-primary/8 text-base-content ring-1 ring-inset ring-primary/40 hover:bg-primary/12 dark:border-primary/60 dark:bg-primary/16 dark:hover:bg-primary/20";
26
- const Button$1 = forwardRef(({ variant = "primary", selected, className = "", children, leftIcon, rightIcon, ...props }, ref) => {
47
+ const Button$1 = forwardRef(({ variant = "primary", selected, compact = false, wrap = false, iconOnly = false, shrinks = false, mark, busy, pendingLook = false, className = "", children, leftIcon, rightIcon, ...props }, ref) => {
27
48
  const context = variant === "context";
28
49
  return /* @__PURE__ */ jsx(Button, {
29
50
  ref,
@@ -34,8 +55,14 @@ const Button$1 = forwardRef(({ variant = "primary", selected, className = "", ch
34
55
  variant: "ghost",
35
56
  color: "neutral",
36
57
  "aria-pressed": selected ?? props["aria-pressed"],
37
- className: `${base} ${variant === "choice" && selected ? selectedChoice : recipes[variant]} ${selected && variant !== "choice" ? "bg-base-200" : ""} ${className}`,
38
- leftIcon: context ? /* @__PURE__ */ jsx("span", {
58
+ ...busy === void 0 ? {} : { "aria-busy": busy || void 0 },
59
+ "data-wrap": wrap || void 0,
60
+ ...iconOnly ? { "data-icon-only": "" } : {},
61
+ className: `${base} ${sizes[compact ? "compact" : "default"]} ${wrapping[wrap ? "wrap" : "nowrap"]} ${variant === "choice" && selected ? selectedChoice : recipes[variant]} ${selected && variant !== "choice" ? "bg-base-200" : ""} ${iconOnly ? square[compact ? "compact" : "default"] : ""} ${shrinks ? "max-w-full min-w-0 shrink" : ""} ${pendingLook === "disabled" ? heldDisabled : pendingLook ? pending : ""} ${className}`,
62
+ leftIcon: busy ? /* @__PURE__ */ jsx(SpinnerIcon, {
63
+ motion: "always",
64
+ className: "size-4"
65
+ }) : context ? /* @__PURE__ */ jsx("span", {
39
66
  className: "text-(--color-header-icon) [&>svg]:size-4",
40
67
  children: leftIcon
41
68
  }) : leftIcon,
@@ -46,7 +73,10 @@ const Button$1 = forwardRef(({ variant = "primary", selected, className = "", ch
46
73
  children: context ? /* @__PURE__ */ jsx("span", {
47
74
  className: "truncate",
48
75
  children
49
- }) : children
76
+ }) : shrinks ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
77
+ className: "truncate",
78
+ children
79
+ }), mark !== void 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [" ", mark] })] }) : children
50
80
  });
51
81
  });
52
82
  Button$1.displayName = "Button";
@@ -1 +1 @@
1
- {"version":3,"file":"Button.js","names":["Button","NinnaButton"],"sources":["../../src/actions/Button.tsx"],"sourcesContent":["import { Button as NinnaButton, type ButtonProps as NinnaButtonProps } from '@ninna-ui/primitives';\nimport { forwardRef } from 'react';\n\nimport { tabbable } from '../foundations/KeyboardFocus';\n\n/** T3 Code's button (coss ui): an 8px-radius control, 36px on touch and 32px with a pointer, that dips to\n * 97% while pressed. Every recipe sets its own colours, so ninna-ui only supplies behaviour. */\nconst base =\n 'h-9 gap-2 rounded-md border px-[11px] text-sm font-medium whitespace-nowrap transition-[background-color,box-shadow,scale,color] duration-150 active:scale-[0.97] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary focus-visible:ring-offset-0 disabled:opacity-64 sm:h-8 [&_[data-slot=icon]>svg]:size-4';\n\nconst outline =\n 'border-base-400/90 bg-base-100 text-base-content shadow-xs/5 hover:bg-base-200/70 dark:border-base-400 dark:bg-base-400/30 dark:hover:bg-base-400/60 [&_[data-slot=icon]]:text-base-700';\nconst ghost =\n 'border-transparent text-base-content hover:bg-base-200 data-[state=open]:bg-base-200 [&_[data-slot=icon]]:text-base-700';\n\nconst recipes = {\n primary:\n 'border-primary bg-primary text-primary-content shadow-xs shadow-primary/24 inset-shadow-[0_1px_rgb(255_255_255/16%)] hover:bg-primary/90 active:shadow-none active:inset-shadow-[0_1px_rgb(0_0_0/8%)]',\n secondary: outline,\n quiet: ghost,\n row: `${ghost} h-auto min-h-8 min-w-0 max-w-full justify-start whitespace-normal px-0 py-1 text-left text-xs font-normal text-base-700 hover:bg-transparent hover:text-base-content sm:h-auto active:scale-100`,\n subtle: 'border-transparent bg-base-200 text-base-content hover:bg-base-300/70 dark:bg-base-300 dark:hover:bg-base-400',\n destructive:\n 'border-danger bg-danger text-white shadow-xs shadow-danger/24 inset-shadow-[0_1px_rgb(255_255_255/16%)] hover:bg-danger/90 active:shadow-none',\n 'destructive-quiet':\n 'border-transparent text-(--lar-danger-text) hover:bg-danger/8 dark:hover:bg-danger/16 [&_[data-slot=icon]]:text-current',\n choice: outline,\n context: `${ghost} h-11 min-w-0 gap-1.5 px-2 lg:max-w-48 lg:pointer-fine:h-8`,\n summary: `${ghost} h-7 min-w-0 px-1.5 sm:h-7`,\n avatar: 'size-7 rounded-full border-transparent p-0 hover:bg-transparent sm:h-7 [&>*]:size-7',\n status: 'h-4 min-w-0 max-w-full justify-start gap-1.5 rounded-sm border-transparent px-0 text-xs font-normal text-base-700 hover:bg-transparent hover:text-base-content sm:h-4 active:scale-100 [&>svg]:size-3 [&>svg]:shrink-0',\n} as const;\n\nconst selectedChoice =\n 'border-primary/60 bg-primary/8 text-base-content ring-1 ring-inset ring-primary/40 hover:bg-primary/12 dark:border-primary/60 dark:bg-primary/16 dark:hover:bg-primary/20';\n\nexport type ButtonProps = Omit<NinnaButtonProps, 'color' | 'radius' | 'size' | 'variant'> & {\n variant?: keyof typeof recipes;\n selected?: boolean;\n};\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ variant = 'primary', selected, className = '', children, leftIcon, rightIcon, ...props }, ref) => {\n const context = variant === 'context';\n\n return (\n <NinnaButton\n ref={ref}\n {...tabbable}\n {...props}\n size=\"sm\"\n radius=\"lg\"\n variant=\"ghost\"\n color=\"neutral\"\n aria-pressed={selected ?? props['aria-pressed']}\n className={`${base} ${variant === 'choice' && selected ? selectedChoice : recipes[variant]} ${selected && variant !== 'choice' ? 'bg-base-200' : ''} ${className}`}\n leftIcon={\n context ? <span className=\"text-(--color-header-icon) [&>svg]:size-4\">{leftIcon}</span> : leftIcon\n }\n rightIcon={context ? <span className=\"text-base-700 [&>svg]:size-3.5\">{rightIcon}</span> : rightIcon}\n >\n {context ? <span className=\"truncate\">{children}</span> : children}\n </NinnaButton>\n );\n },\n);\n\nButton.displayName = 'Button';\n"],"mappings":";;;;;;;AAOA,MAAM,OACF;AAEJ,MAAM,UACF;AACJ,MAAM,QACF;AAEJ,MAAM,UAAU;CACZ,SACI;CACJ,WAAW;CACX,OAAO;CACP,KAAK,GAAG,MAAM;CACd,QAAQ;CACR,aACI;CACJ,qBACI;CACJ,QAAQ;CACR,SAAS,GAAG,MAAM;CAClB,SAAS,GAAG,MAAM;CAClB,QAAQ;CACR,QAAQ;AACZ;AAEA,MAAM,iBACF;AAOJ,MAAaA,WAAS,YACjB,EAAE,UAAU,WAAW,UAAU,YAAY,IAAI,UAAU,UAAU,WAAW,GAAG,SAAS,QAAQ;CACjG,MAAM,UAAU,YAAY;CAE5B,OACI,oBAACC,QAAD;EACS;EACL,GAAI;EACJ,GAAI;EACJ,MAAK;EACL,QAAO;EACP,SAAQ;EACR,OAAM;EACN,gBAAc,YAAY,MAAM;EAChC,WAAW,GAAG,KAAK,GAAG,YAAY,YAAY,WAAW,iBAAiB,QAAQ,SAAS,GAAG,YAAY,YAAY,WAAW,gBAAgB,GAAG,GAAG;EACvJ,UACI,UAAU,oBAAC,QAAD;GAAM,WAAU;GAA6C,UAAA;EAAe,CAAA,IAAI;EAE9F,WAAW,UAAU,oBAAC,QAAD;GAAM,WAAU;GAAkC,UAAA;EAAgB,CAAA,IAAI;EAE1F,UAAA,UAAU,oBAAC,QAAD;GAAM,WAAU;GAAY;EAAe,CAAA,IAAI;CACjD,CAAA;AAErB,CACJ;AAEA,SAAO,cAAc"}
1
+ {"version":3,"file":"Button.js","names":["Button","NinnaButton"],"sources":["../../src/actions/Button.tsx"],"sourcesContent":["import { Button as NinnaButton, type ButtonProps as NinnaButtonProps } from '@ninna-ui/primitives';\nimport { forwardRef } from 'react';\n\nimport { SpinnerIcon } from '../feedback/Loading';\nimport { tabbable } from '../foundations/KeyboardFocus';\nimport { ghostRecipe, outlineRecipe, primaryRecipe } from './ButtonRecipes';\n\n/** T3 Code's button (coss ui): an 8px-radius control, 36px on touch and 32px with a pointer, that dips to\n * 97% while pressed. Every recipe sets its own colours, so ninna-ui only supplies behaviour. */\nconst base =\n 'gap-2 rounded-md border px-[11px] font-medium transition-[background-color,box-shadow,scale,color] duration-150 active:scale-[0.97] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary focus-visible:ring-offset-0 disabled:opacity-64 [&_[data-slot=icon]>svg]:size-4';\n/** The default 36px (32px with a pointer) control, and the compact 28px one with 12px text that dense tools use. */\nconst sizes = { default: 'h-9 text-sm sm:h-8', compact: 'h-7 text-xs sm:h-7' } as const;\n/** A label that would clip on a narrow surface wraps instead, growing the button past its height. */\nconst wrapping = {\n nowrap: 'whitespace-nowrap',\n wrap: 'h-auto min-h-7 max-w-full min-w-0 py-1 whitespace-normal wrap-anywhere sm:h-auto',\n} as const;\n\nconst outline = outlineRecipe;\nconst ghost = ghostRecipe;\n\nconst recipes = {\n primary: primaryRecipe,\n secondary: outline,\n quiet: ghost,\n row: `${ghost} h-auto min-h-8 min-w-0 max-w-full justify-start whitespace-normal px-0 py-1 text-left text-xs font-normal text-base-700 hover:bg-transparent hover:text-base-content sm:h-auto active:scale-100`,\n subtle: 'border-transparent bg-base-200 text-base-content hover:bg-base-300/70 dark:bg-base-300 dark:hover:bg-base-400',\n /** The primary colour tinted on the card, with no border or shadow, deeper on hover and while its popup is open. */\n tinted: 'border-transparent bg-[color-mix(in_srgb,var(--color-primary)_10%,var(--color-base-100))] text-primary shadow-none not-disabled:not-aria-disabled:hover:bg-[color-mix(in_srgb,var(--color-primary)_18%,var(--color-base-100))] data-[state=open]:bg-[color-mix(in_srgb,var(--color-primary)_18%,var(--color-base-100))] [&_[data-slot=icon]]:text-current',\n destructive:\n 'border-danger bg-danger text-white shadow-xs shadow-danger/24 inset-shadow-[0_1px_rgb(255_255_255/16%)] hover:bg-danger/90 active:shadow-none',\n 'destructive-quiet':\n 'border-transparent text-(--lar-danger-text) hover:bg-danger/8 dark:hover:bg-danger/16 [&_[data-slot=icon]]:text-current',\n choice: outline,\n context: `${ghost} h-11 min-w-0 gap-1.5 px-2 lg:max-w-48 lg:pointer-fine:h-8`,\n summary: `${ghost} h-7 min-w-0 px-1.5 sm:h-7`,\n avatar: 'size-7 rounded-full border-transparent p-0 hover:bg-transparent sm:h-7 [&>*]:size-7',\n status: 'h-4 min-w-0 max-w-full justify-start gap-1.5 rounded-sm border-transparent px-0 text-xs font-normal text-base-700 hover:bg-transparent hover:text-base-content sm:h-4 active:scale-100 [&>svg]:size-3 [&>svg]:shrink-0',\n} as const;\n\n/** An icon-only button is as wide as it is tall, with no padding. */\nconst square = { default: 'size-9 px-0 sm:size-8', compact: 'w-7 px-0' } as const;\nconst pending = 'aria-disabled:cursor-progress aria-disabled:opacity-70';\nconst heldDisabled = 'aria-disabled:opacity-64';\n\nconst selectedChoice =\n 'border-primary/60 bg-primary/8 text-base-content ring-1 ring-inset ring-primary/40 hover:bg-primary/12 dark:border-primary/60 dark:bg-primary/16 dark:hover:bg-primary/20';\n\nexport type ButtonProps = Omit<NinnaButtonProps, 'color' | 'radius' | 'size' | 'variant'> & {\n variant?: keyof typeof recipes;\n selected?: boolean;\n /** The dense 28px control with 12px text, as Lar Factory's board draws every button. */\n compact?: boolean;\n /** Lets a long label wrap, anywhere in a long word if it must, growing the button, which never grows past its\n * container, where it would otherwise clip. */\n wrap?: boolean;\n /** A square button showing its `leftIcon` alone, named by its `aria-label`. */\n iconOnly?: boolean;\n /** Lets the button shrink in a crowded row: its label truncates, while its `mark` (a trailing character, such as ▾\n * or ✓) stays. */\n shrinks?: boolean;\n mark?: string;\n /** Its action is in flight: a spinner, turning even under reduced motion, takes its left icon's place, and it reads\n * as busy. `false` leaves out the busy state altogether. */\n busy?: boolean;\n /** Draws the button as waiting, with the progress cursor at 70%, while `aria-disabled` holds it for an action in\n * flight; `'disabled'` draws it as a disabled button instead, while it keeps its focus (a save with nothing to\n * save, say). */\n pendingLook?: boolean | 'disabled';\n};\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n variant = 'primary',\n selected,\n compact = false,\n wrap = false,\n iconOnly = false,\n shrinks = false,\n mark,\n busy,\n pendingLook = false,\n className = '',\n children,\n leftIcon,\n rightIcon,\n ...props\n },\n ref,\n ) => {\n const context = variant === 'context';\n\n return (\n <NinnaButton\n ref={ref}\n {...tabbable}\n {...props}\n size=\"sm\"\n radius=\"lg\"\n variant=\"ghost\"\n color=\"neutral\"\n aria-pressed={selected ?? props['aria-pressed']}\n {...(busy === undefined ? {} : { 'aria-busy': busy || undefined })}\n data-wrap={wrap || undefined}\n {...(iconOnly ? { 'data-icon-only': '' } : {})}\n className={`${base} ${sizes[compact ? 'compact' : 'default']} ${wrapping[wrap ? 'wrap' : 'nowrap']} ${variant === 'choice' && selected ? selectedChoice : recipes[variant]} ${selected && variant !== 'choice' ? 'bg-base-200' : ''} ${iconOnly ? square[compact ? 'compact' : 'default'] : ''} ${shrinks ? 'max-w-full min-w-0 shrink' : ''} ${pendingLook === 'disabled' ? heldDisabled : pendingLook ? pending : ''} ${className}`}\n leftIcon={\n busy ? (\n <SpinnerIcon motion=\"always\" className=\"size-4\" />\n ) : context ? (\n <span className=\"text-(--color-header-icon) [&>svg]:size-4\">{leftIcon}</span>\n ) : (\n leftIcon\n )\n }\n rightIcon={context ? <span className=\"text-base-700 [&>svg]:size-3.5\">{rightIcon}</span> : rightIcon}\n >\n {context ? (\n <span className=\"truncate\">{children}</span>\n ) : shrinks ? (\n <>\n <span className=\"truncate\">{children}</span>\n {mark !== undefined && <> {mark}</>}\n </>\n ) : (\n children\n )}\n </NinnaButton>\n );\n },\n);\n\nButton.displayName = 'Button';\n"],"mappings":";;;;;;;;;AASA,MAAM,OACF;;AAEJ,MAAM,QAAQ;CAAE,SAAS;CAAsB,SAAS;AAAqB;;AAE7E,MAAM,WAAW;CACb,QAAQ;CACR,MAAM;AACV;AAEA,MAAM,UAAU;AAChB,MAAM,QAAQ;AAEd,MAAM,UAAU;CACZ,SAAS;CACT,WAAW;CACX,OAAO;CACP,KAAK,GAAG,MAAM;CACd,QAAQ;;CAER,QAAQ;CACR,aACI;CACJ,qBACI;CACJ,QAAQ;CACR,SAAS,GAAG,MAAM;CAClB,SAAS,GAAG,MAAM;CAClB,QAAQ;CACR,QAAQ;AACZ;;AAGA,MAAM,SAAS;CAAE,SAAS;CAAyB,SAAS;AAAW;AACvE,MAAM,UAAU;AAChB,MAAM,eAAe;AAErB,MAAM,iBACF;AAyBJ,MAAaA,WAAS,YAEd,EACI,UAAU,WACV,UACA,UAAU,OACV,OAAO,OACP,WAAW,OACX,UAAU,OACV,MACA,MACA,cAAc,OACd,YAAY,IACZ,UACA,UACA,WACA,GAAG,SAEP,QACC;CACD,MAAM,UAAU,YAAY;CAE5B,OACI,oBAACC,QAAD;EACS;EACL,GAAI;EACJ,GAAI;EACJ,MAAK;EACL,QAAO;EACP,SAAQ;EACR,OAAM;EACN,gBAAc,YAAY,MAAM;EAChC,GAAK,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,QAAQ,KAAA,EAAU;EAChE,aAAW,QAAQ,KAAA;EACnB,GAAK,WAAW,EAAE,kBAAkB,GAAG,IAAI,CAAC;EAC5C,WAAW,GAAG,KAAK,GAAG,MAAM,UAAU,YAAY,WAAW,GAAG,SAAS,OAAO,SAAS,UAAU,GAAG,YAAY,YAAY,WAAW,iBAAiB,QAAQ,SAAS,GAAG,YAAY,YAAY,WAAW,gBAAgB,GAAG,GAAG,WAAW,OAAO,UAAU,YAAY,aAAa,GAAG,GAAG,UAAU,8BAA8B,GAAG,GAAG,gBAAgB,aAAa,eAAe,cAAc,UAAU,GAAG,GAAG;EAC1Z,UACI,OACI,oBAAC,aAAD;GAAa,QAAO;GAAS,WAAU;EAAU,CAAA,IACjD,UACA,oBAAC,QAAD;GAAM,WAAU;GAA6C,UAAA;EAAe,CAAA,IAE5E;EAGR,WAAW,UAAU,oBAAC,QAAD;GAAM,WAAU;GAAkC,UAAA;EAAgB,CAAA,IAAI;EAE1F,UAAA,UACG,oBAAC,QAAD;GAAM,WAAU;GAAY;EAAe,CAAA,IAC3C,UACA,qBAAA,YAAA,EAAA,UAAA,CACI,oBAAC,QAAD;GAAM,WAAU;GAAY;EAAe,CAAA,GAC1C,SAAS,KAAA,KAAa,qBAAA,YAAA,EAAA,UAAA,CAAE,KAAE,IAAO,EAAA,CAAA,CACpC,EAAA,CAAA,IAEF;CAEK,CAAA;AAErB,CACJ;AAEA,SAAO,cAAc"}
@@ -15,7 +15,11 @@ export interface ButtonLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorEle
15
15
  arrow?: boolean;
16
16
  external?: boolean;
17
17
  onNavigate?: (href: string) => void;
18
+ /** The app Button's compact 28px look in place of the marketing one, its `icon` leading it. */
19
+ compact?: boolean;
20
+ /** With `compact`, a square link showing its icon alone, named by its `aria-label`. */
21
+ iconOnly?: boolean;
18
22
  }
19
- export declare function ButtonLink({ variant, size, icon, arrow, external, onNavigate, onClick, children, href, ...props }: ButtonLinkProps): import("react").JSX.Element;
23
+ export declare function ButtonLink({ variant, size, icon, arrow, external, onNavigate, onClick, compact, iconOnly, children, href, ...props }: ButtonLinkProps): import("react").JSX.Element;
20
24
  export {};
21
25
  //# sourceMappingURL=ButtonLink.d.ts.map
@@ -1,6 +1,7 @@
1
1
  import { tabbable } from "../foundations/KeyboardFocus.js";
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { ghostRecipe, outlineRecipe, primaryRecipe } from "./ButtonRecipes.js";
3
3
  import { ArrowRightIcon } from "lucide-react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
4
5
  // src/actions/ButtonLink.tsx
5
6
  /** The marketing pages' calls to action: the Button recipes at a roomier 44px, as links. */
6
7
  const recipes = {
@@ -9,7 +10,32 @@ const recipes = {
9
10
  inverse: "border-transparent bg-base-content text-base-50 shadow-sm hover:bg-[color-mix(in_srgb,var(--color-base-content)_86%,transparent)]",
10
11
  quiet: "border-transparent text-base-content hover:text-primary dark:hover:text-[color-mix(in_srgb,var(--color-primary)_45%,white)]"
11
12
  };
12
- function ButtonLink({ variant = "primary", size = "lg", icon, arrow, external, onNavigate, onClick, children, href, ...props }) {
13
+ /** A compact link is the app Button's compact 28px control with 12px text, in the Button's own recipes, for an action
14
+ * that opens a page from a dense tool (such as Lar Factory's board). */
15
+ const compactBase = "relative isolate inline-flex h-7 items-center justify-center gap-2 rounded-md border px-[11px] text-xs font-medium whitespace-nowrap transition-[background-color,box-shadow,scale,color] duration-150 active:scale-[0.97] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary focus-visible:outline-none [&_[data-slot=icon]>svg]:size-4";
16
+ const compactRecipes = {
17
+ primary: primaryRecipe,
18
+ secondary: outlineRecipe,
19
+ inverse: recipes.inverse,
20
+ quiet: ghostRecipe
21
+ };
22
+ function ButtonLink({ variant = "primary", size = "lg", icon, arrow, external, onNavigate, onClick, compact = false, iconOnly = false, children, href, ...props }) {
23
+ if (compact) return /* @__PURE__ */ jsxs("a", {
24
+ ...props,
25
+ href,
26
+ ...external ? {
27
+ target: "_blank",
28
+ rel: "noreferrer"
29
+ } : {},
30
+ onClick,
31
+ "data-slot": "button",
32
+ ...iconOnly ? { "data-icon-only": "" } : {},
33
+ className: `${compactBase} ${compactRecipes[variant]} ${iconOnly ? "w-7 px-0" : ""}`,
34
+ children: [icon && /* @__PURE__ */ jsx("span", {
35
+ "data-slot": "icon",
36
+ children: icon
37
+ }), children]
38
+ });
13
39
  return /* @__PURE__ */ jsxs("a", {
14
40
  ...tabbable,
15
41
  ...props,
@@ -1 +1 @@
1
- {"version":3,"file":"ButtonLink.js","names":[],"sources":["../../src/actions/ButtonLink.tsx"],"sourcesContent":["import { ArrowRightIcon } from 'lucide-react';\nimport type { AnchorHTMLAttributes, ReactNode } from 'react';\n\nimport { tabbable } from '../foundations/KeyboardFocus';\n\n/** The marketing pages' calls to action: the Button recipes at a roomier 44px, as links. */\nconst recipes = {\n primary:\n 'border-primary bg-primary text-primary-content shadow-sm shadow-primary/30 inset-shadow-[0_1px_rgb(255_255_255/18%)] hover:bg-[color-mix(in_srgb,var(--color-primary)_88%,white)] active:shadow-none',\n secondary:\n 'border-base-400/90 bg-base-100 text-base-content shadow-xs/5 hover:bg-base-200/70 dark:border-base-400 dark:bg-base-300/40 dark:hover:bg-base-400/50',\n inverse:\n 'border-transparent bg-base-content text-base-50 shadow-sm hover:bg-[color-mix(in_srgb,var(--color-base-content)_86%,transparent)]',\n quiet: 'border-transparent text-base-content hover:text-primary dark:hover:text-[color-mix(in_srgb,var(--color-primary)_45%,white)]',\n} as const;\n\nexport interface ButtonLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'className' | 'style'> {\n href: string;\n variant?: keyof typeof recipes;\n size?: 'md' | 'lg';\n icon?: ReactNode;\n /** Shows an arrow that nudges forward on hover. */\n arrow?: boolean;\n external?: boolean;\n onNavigate?: (href: string) => void;\n}\n\nexport function ButtonLink({\n variant = 'primary',\n size = 'lg',\n icon,\n arrow,\n external,\n onNavigate,\n onClick,\n children,\n href,\n ...props\n}: ButtonLinkProps) {\n return (\n <a\n {...tabbable}\n {...props}\n href={href}\n {...(external ? { target: '_blank', rel: 'noreferrer' } : {})}\n onClick={(event) => {\n onClick?.(event);\n\n if (\n !onNavigate ||\n external ||\n event.defaultPrevented ||\n event.button !== 0 ||\n event.metaKey ||\n event.ctrlKey ||\n event.shiftKey ||\n event.altKey\n )\n return;\n\n event.preventDefault();\n onNavigate(href);\n }}\n className={`group/button focus-visible:outline-primary inline-flex shrink-0 items-center justify-center gap-2 rounded-[0.625rem] border font-medium whitespace-nowrap transition-[background-color,box-shadow,scale,color] duration-150 select-none focus-visible:outline-2 focus-visible:outline-offset-2 active:scale-[0.97] [&_svg]:size-4 [&_svg]:shrink-0 ${size === 'lg' ? 'h-11 text-[15px]' : 'h-9 text-sm'} ${variant === 'quiet' ? 'px-0' : size === 'lg' ? 'px-[1.125rem]' : 'px-3.5'} ${recipes[variant]}`}\n >\n {icon}\n {children}\n {arrow ? (\n <span className=\"-mr-0.5 inline-flex transition-transform duration-200 group-hover/button:translate-x-0.5\">\n <ArrowRightIcon />\n </span>\n ) : null}\n </a>\n );\n}\n"],"mappings":";;;;;AAMA,MAAM,UAAU;CACZ,SACI;CACJ,WACI;CACJ,SACI;CACJ,OAAO;AACX;AAaA,SAAgB,WAAW,EACvB,UAAU,WACV,OAAO,MACP,MACA,OACA,UACA,YACA,SACA,UACA,MACA,GAAG,SACa;CAChB,OACI,qBAAC,KAAD;EACI,GAAI;EACJ,GAAI;EACE;EACN,GAAK,WAAW;GAAE,QAAQ;GAAU,KAAK;EAAa,IAAI,CAAC;EAC3D,UAAU,UAAU;GAChB,UAAU,KAAK;GAEf,IACI,CAAC,cACD,YACA,MAAM,oBACN,MAAM,WAAW,KACjB,MAAM,WACN,MAAM,WACN,MAAM,YACN,MAAM,QAEN;GAEJ,MAAM,eAAe;GACrB,WAAW,IAAI;EACnB;EACA,WAAW,sVAAsV,SAAS,OAAO,qBAAqB,cAAc,GAAG,YAAY,UAAU,SAAS,SAAS,OAAO,kBAAkB,SAAS,GAAG,QAAQ;EAvBhf,UAAA;GAyBK;GACA;GACA,QACG,oBAAC,QAAD;IAAM,WAAU;IACZ,UAAA,oBAAC,gBAAD,CAAiB,CAAA;GACf,CAAA,IACN;EACL;;AAEX"}
1
+ {"version":3,"file":"ButtonLink.js","names":[],"sources":["../../src/actions/ButtonLink.tsx"],"sourcesContent":["import { ArrowRightIcon } from 'lucide-react';\nimport type { AnchorHTMLAttributes, ReactNode } from 'react';\n\nimport { tabbable } from '../foundations/KeyboardFocus';\nimport { ghostRecipe, outlineRecipe, primaryRecipe } from './ButtonRecipes';\n\n/** The marketing pages' calls to action: the Button recipes at a roomier 44px, as links. */\nconst recipes = {\n primary:\n 'border-primary bg-primary text-primary-content shadow-sm shadow-primary/30 inset-shadow-[0_1px_rgb(255_255_255/18%)] hover:bg-[color-mix(in_srgb,var(--color-primary)_88%,white)] active:shadow-none',\n secondary:\n 'border-base-400/90 bg-base-100 text-base-content shadow-xs/5 hover:bg-base-200/70 dark:border-base-400 dark:bg-base-300/40 dark:hover:bg-base-400/50',\n inverse:\n 'border-transparent bg-base-content text-base-50 shadow-sm hover:bg-[color-mix(in_srgb,var(--color-base-content)_86%,transparent)]',\n quiet: 'border-transparent text-base-content hover:text-primary dark:hover:text-[color-mix(in_srgb,var(--color-primary)_45%,white)]',\n} as const;\n\n/** A compact link is the app Button's compact 28px control with 12px text, in the Button's own recipes, for an action\n * that opens a page from a dense tool (such as Lar Factory's board). */\nconst compactBase =\n 'relative isolate inline-flex h-7 items-center justify-center gap-2 rounded-md border px-[11px] text-xs font-medium whitespace-nowrap transition-[background-color,box-shadow,scale,color] duration-150 active:scale-[0.97] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary focus-visible:outline-none [&_[data-slot=icon]>svg]:size-4';\nconst compactRecipes = {\n primary: primaryRecipe,\n secondary: outlineRecipe,\n inverse: recipes.inverse,\n quiet: ghostRecipe,\n} as const;\n\nexport interface ButtonLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'className' | 'style'> {\n href: string;\n variant?: keyof typeof recipes;\n size?: 'md' | 'lg';\n icon?: ReactNode;\n /** Shows an arrow that nudges forward on hover. */\n arrow?: boolean;\n external?: boolean;\n onNavigate?: (href: string) => void;\n /** The app Button's compact 28px look in place of the marketing one, its `icon` leading it. */\n compact?: boolean;\n /** With `compact`, a square link showing its icon alone, named by its `aria-label`. */\n iconOnly?: boolean;\n}\n\nexport function ButtonLink({\n variant = 'primary',\n size = 'lg',\n icon,\n arrow,\n external,\n onNavigate,\n onClick,\n compact = false,\n iconOnly = false,\n children,\n href,\n ...props\n}: ButtonLinkProps) {\n if (compact)\n return (\n <a\n {...props}\n href={href}\n {...(external ? { target: '_blank', rel: 'noreferrer' } : {})}\n onClick={onClick}\n data-slot=\"button\"\n {...(iconOnly ? { 'data-icon-only': '' } : {})}\n className={`${compactBase} ${compactRecipes[variant]} ${iconOnly ? 'w-7 px-0' : ''}`}\n >\n {icon && <span data-slot=\"icon\">{icon}</span>}\n {children}\n </a>\n );\n\n return (\n <a\n {...tabbable}\n {...props}\n href={href}\n {...(external ? { target: '_blank', rel: 'noreferrer' } : {})}\n onClick={(event) => {\n onClick?.(event);\n\n if (\n !onNavigate ||\n external ||\n event.defaultPrevented ||\n event.button !== 0 ||\n event.metaKey ||\n event.ctrlKey ||\n event.shiftKey ||\n event.altKey\n )\n return;\n\n event.preventDefault();\n onNavigate(href);\n }}\n className={`group/button focus-visible:outline-primary inline-flex shrink-0 items-center justify-center gap-2 rounded-[0.625rem] border font-medium whitespace-nowrap transition-[background-color,box-shadow,scale,color] duration-150 select-none focus-visible:outline-2 focus-visible:outline-offset-2 active:scale-[0.97] [&_svg]:size-4 [&_svg]:shrink-0 ${size === 'lg' ? 'h-11 text-[15px]' : 'h-9 text-sm'} ${variant === 'quiet' ? 'px-0' : size === 'lg' ? 'px-[1.125rem]' : 'px-3.5'} ${recipes[variant]}`}\n >\n {icon}\n {children}\n {arrow ? (\n <span className=\"-mr-0.5 inline-flex transition-transform duration-200 group-hover/button:translate-x-0.5\">\n <ArrowRightIcon />\n </span>\n ) : null}\n </a>\n );\n}\n"],"mappings":";;;;;;AAOA,MAAM,UAAU;CACZ,SACI;CACJ,WACI;CACJ,SACI;CACJ,OAAO;AACX;;;AAIA,MAAM,cACF;AACJ,MAAM,iBAAiB;CACnB,SAAS;CACT,WAAW;CACX,SAAS,QAAQ;CACjB,OAAO;AACX;AAiBA,SAAgB,WAAW,EACvB,UAAU,WACV,OAAO,MACP,MACA,OACA,UACA,YACA,SACA,UAAU,OACV,WAAW,OACX,UACA,MACA,GAAG,SACa;CAChB,IAAI,SACA,OACI,qBAAC,KAAD;EACI,GAAI;EACE;EACN,GAAK,WAAW;GAAE,QAAQ;GAAU,KAAK;EAAa,IAAI,CAAC;EAClD;EACT,aAAU;EACV,GAAK,WAAW,EAAE,kBAAkB,GAAG,IAAI,CAAC;EAC5C,WAAW,GAAG,YAAY,GAAG,eAAe,SAAS,GAAG,WAAW,aAAa;EAPpF,UAAA,CASK,QAAQ,oBAAC,QAAD;GAAM,aAAU;GAAQ,UAAA;EAAW,CAAA,GAC3C,QACF;;CAGX,OACI,qBAAC,KAAD;EACI,GAAI;EACJ,GAAI;EACE;EACN,GAAK,WAAW;GAAE,QAAQ;GAAU,KAAK;EAAa,IAAI,CAAC;EAC3D,UAAU,UAAU;GAChB,UAAU,KAAK;GAEf,IACI,CAAC,cACD,YACA,MAAM,oBACN,MAAM,WAAW,KACjB,MAAM,WACN,MAAM,WACN,MAAM,YACN,MAAM,QAEN;GAEJ,MAAM,eAAe;GACrB,WAAW,IAAI;EACnB;EACA,WAAW,sVAAsV,SAAS,OAAO,qBAAqB,cAAc,GAAG,YAAY,UAAU,SAAS,SAAS,OAAO,kBAAkB,SAAS,GAAG,QAAQ;EAvBhf,UAAA;GAyBK;GACA;GACA,QACG,oBAAC,QAAD;IAAM,WAAU;IACZ,UAAA,oBAAC,gBAAD,CAAiB,CAAA;GACf,CAAA,IACN;EACL;;AAEX"}
@@ -0,0 +1,7 @@
1
+ // src/actions/ButtonRecipes.ts
2
+ const primaryRecipe = "border-primary bg-primary text-primary-content shadow-xs shadow-primary/24 inset-shadow-[0_1px_rgb(255_255_255/16%)] hover:bg-primary/90 active:shadow-none active:inset-shadow-[0_1px_rgb(0_0_0/8%)]";
3
+ const outlineRecipe = "border-base-400/90 bg-base-100 text-base-content shadow-xs/5 hover:bg-base-200/70 dark:border-base-400 dark:bg-base-400/30 dark:hover:bg-base-400/60 [&_[data-slot=icon]]:text-base-700";
4
+ const ghostRecipe = "border-transparent text-base-content hover:bg-base-200 data-[state=open]:bg-base-200 [&_[data-slot=icon]]:text-base-700";
5
+ export { ghostRecipe, outlineRecipe, primaryRecipe };
6
+
7
+ //# sourceMappingURL=ButtonRecipes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ButtonRecipes.js","names":[],"sources":["../../src/actions/ButtonRecipes.ts"],"sourcesContent":["// The app Button's filled and outlined recipes, which ButtonLink's compact links draw too.\n\nexport const primaryRecipe =\n 'border-primary bg-primary text-primary-content shadow-xs shadow-primary/24 inset-shadow-[0_1px_rgb(255_255_255/16%)] hover:bg-primary/90 active:shadow-none active:inset-shadow-[0_1px_rgb(0_0_0/8%)]';\n\nexport const outlineRecipe =\n 'border-base-400/90 bg-base-100 text-base-content shadow-xs/5 hover:bg-base-200/70 dark:border-base-400 dark:bg-base-400/30 dark:hover:bg-base-400/60 [&_[data-slot=icon]]:text-base-700';\n\nexport const ghostRecipe =\n 'border-transparent text-base-content hover:bg-base-200 data-[state=open]:bg-base-200 [&_[data-slot=icon]]:text-base-700';\n"],"mappings":";AAEA,MAAa,gBACT;AAEJ,MAAa,gBACT;AAEJ,MAAa,cACT"}
@@ -1,12 +1,12 @@
1
1
  import { StatusTone } from "../feedback/StatusIndicator.js";
2
2
  import { IconButtonProps } from "@ninna-ui/primitives";
3
3
  type IconButtonProps$1 = Omit<IconButtonProps, 'color' | 'radius' | 'size' | 'variant'> & {
4
- variant?: 'header' | 'quiet' | 'title-bar';
4
+ variant?: 'header' | 'quiet' | 'title-bar' | 'inline';
5
5
  tone?: StatusTone | 'accent';
6
6
  notification?: string;
7
7
  };
8
8
  declare const IconButton$1: import("react").ForwardRefExoticComponent<Omit<IconButtonProps, "color" | "radius" | "size" | "variant"> & {
9
- variant?: 'header' | 'quiet' | 'title-bar';
9
+ variant?: 'header' | 'quiet' | 'title-bar' | 'inline';
10
10
  tone?: StatusTone | 'accent';
11
11
  notification?: string;
12
12
  } & import("react").RefAttributes<HTMLButtonElement>>;
@@ -21,7 +21,7 @@ const IconButton$1 = forwardRef(({ variant = "quiet", tone = "neutral", classNam
21
21
  color: tone === "accent" ? "primary" : tone,
22
22
  size: "sm",
23
23
  radius: "lg",
24
- className: (variant === "header" ? "text-base-700 hover:bg-base-200 hover:text-base-content data-[state=open]:bg-base-200 data-[state=open]:text-base-content size-8 rounded-md p-0 before:-inset-1 **:data-[slot=icon]:size-[18px] " : variant === "title-bar" ? "text-base-700 hover:bg-base-200 hover:text-base-content data-[state=open]:bg-base-200 data-[state=open]:text-base-content size-7 rounded-md p-0 before:-inset-1.5 **:data-[slot=icon]:size-4 " : tone === "neutral" ? "text-base-700 hover:bg-base-200 hover:text-base-content data-[state=open]:bg-base-200 rounded-md " : "rounded-md ") + "transition-[background-color,color,scale] active:scale-[0.94] [&_svg]:size-full " + className
24
+ className: (variant === "header" ? "text-base-700 hover:bg-base-200 hover:text-base-content data-[state=open]:bg-base-200 data-[state=open]:text-base-content size-8 rounded-md p-0 before:-inset-1 **:data-[slot=icon]:size-[18px] " : variant === "title-bar" ? "text-base-700 hover:bg-base-200 hover:text-base-content data-[state=open]:bg-base-200 data-[state=open]:text-base-content size-7 rounded-md p-0 before:-inset-1.5 **:data-[slot=icon]:size-4 " : variant === "inline" ? "text-base-700 hover:bg-base-200 grid size-5 place-items-center rounded p-0 disabled:opacity-50 disabled:hover:bg-transparent **:data-[slot=icon]:size-3 " : tone === "neutral" ? "text-base-700 hover:bg-base-200 hover:text-base-content data-[state=open]:bg-base-200 rounded-md " : "rounded-md ") + "transition-[background-color,color,scale] active:scale-[0.94] [&_svg]:size-full " + className
25
25
  }));
26
26
  IconButton$1.displayName = "IconButton";
27
27
  export { IconButton$1 as IconButton };
@@ -1 +1 @@
1
- {"version":3,"file":"IconButton.js","names":["IconButton","NinnaIconButton"],"sources":["../../src/actions/IconButton.tsx"],"sourcesContent":["import { IconButton as NinnaIconButton, type IconButtonProps as NinnaIconButtonProps } from '@ninna-ui/primitives';\nimport { forwardRef } from 'react';\n\nimport { StatusIndicator, type StatusTone } from '../feedback/StatusIndicator';\nimport { tabbable } from '../foundations/KeyboardFocus';\n\nexport type IconButtonProps = Omit<NinnaIconButtonProps, 'color' | 'radius' | 'size' | 'variant'> & {\n variant?: 'header' | 'quiet' | 'title-bar';\n tone?: StatusTone | 'accent';\n notification?: string;\n};\n\nexport const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(\n ({ variant = 'quiet', tone = 'neutral', className = '', notification, icon, ...props }, ref) => (\n <NinnaIconButton\n ref={ref}\n {...tabbable}\n aria-description={notification}\n {...props}\n icon={\n notification ? (\n <span className=\"relative block size-full\">\n {icon}\n <StatusIndicator\n tone=\"warning\"\n size=\"sm\"\n className=\"ring-base-100 absolute -top-0.5 -right-0.5 ring-2\"\n />\n </span>\n ) : (\n icon\n )\n }\n variant=\"ghost\"\n color={tone === 'accent' ? 'primary' : tone}\n size=\"sm\"\n radius=\"lg\"\n className={\n // T3 Code's ghost icon button: muted until hovered, on an accent fill.\n (variant === 'header'\n ? 'text-base-700 hover:bg-base-200 hover:text-base-content data-[state=open]:bg-base-200 data-[state=open]:text-base-content size-8 rounded-md p-0 before:-inset-1 **:data-[slot=icon]:size-[18px] '\n : variant === 'title-bar'\n ? // The title bar's 28px row of controls, with 16px icons.\n 'text-base-700 hover:bg-base-200 hover:text-base-content data-[state=open]:bg-base-200 data-[state=open]:text-base-content size-7 rounded-md p-0 before:-inset-1.5 **:data-[slot=icon]:size-4 '\n : tone === 'neutral'\n ? 'text-base-700 hover:bg-base-200 hover:text-base-content data-[state=open]:bg-base-200 rounded-md '\n : 'rounded-md ') +\n 'transition-[background-color,color,scale] active:scale-[0.94] [&_svg]:size-full ' +\n className\n }\n />\n ),\n);\n\nIconButton.displayName = 'IconButton';\n"],"mappings":";;;;;;AAYA,MAAaA,eAAa,YACrB,EAAE,UAAU,SAAS,OAAO,WAAW,YAAY,IAAI,cAAc,MAAM,GAAG,SAAS,QACpF,oBAACC,YAAD;CACS;CACL,GAAI;CACJ,oBAAkB;CAClB,GAAI;CACJ,MACI,eACI,qBAAC,QAAD;EAAM,WAAU;EAAhB,UAAA,CACK,MACD,oBAAC,iBAAD;GACI,MAAK;GACL,MAAK;GACL,WAAU;EACb,CAAA,CACC;CAEN,CAAA,IAAA;CAGR,SAAQ;CACR,OAAO,SAAS,WAAW,YAAY;CACvC,MAAK;CACL,QAAO;CACP,YAEK,YAAY,WACP,qMACA,YAAY,cAEV,kMACA,SAAS,YACP,sGACA,iBACV,qFACA;AAEP,CAAA,CAET;AAEA,aAAW,cAAc"}
1
+ {"version":3,"file":"IconButton.js","names":["IconButton","NinnaIconButton"],"sources":["../../src/actions/IconButton.tsx"],"sourcesContent":["import { IconButton as NinnaIconButton, type IconButtonProps as NinnaIconButtonProps } from '@ninna-ui/primitives';\nimport { forwardRef } from 'react';\n\nimport { StatusIndicator, type StatusTone } from '../feedback/StatusIndicator';\nimport { tabbable } from '../foundations/KeyboardFocus';\n\nexport type IconButtonProps = Omit<NinnaIconButtonProps, 'color' | 'radius' | 'size' | 'variant'> & {\n variant?: 'header' | 'quiet' | 'title-bar' | 'inline';\n tone?: StatusTone | 'accent';\n notification?: string;\n};\n\nexport const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(\n ({ variant = 'quiet', tone = 'neutral', className = '', notification, icon, ...props }, ref) => (\n <NinnaIconButton\n ref={ref}\n {...tabbable}\n aria-description={notification}\n {...props}\n icon={\n notification ? (\n <span className=\"relative block size-full\">\n {icon}\n <StatusIndicator\n tone=\"warning\"\n size=\"sm\"\n className=\"ring-base-100 absolute -top-0.5 -right-0.5 ring-2\"\n />\n </span>\n ) : (\n icon\n )\n }\n variant=\"ghost\"\n color={tone === 'accent' ? 'primary' : tone}\n size=\"sm\"\n radius=\"lg\"\n className={\n // T3 Code's ghost icon button: muted until hovered, on an accent fill.\n (variant === 'header'\n ? 'text-base-700 hover:bg-base-200 hover:text-base-content data-[state=open]:bg-base-200 data-[state=open]:text-base-content size-8 rounded-md p-0 before:-inset-1 **:data-[slot=icon]:size-[18px] '\n : variant === 'title-bar'\n ? // The title bar's 28px row of controls, with 16px icons.\n 'text-base-700 hover:bg-base-200 hover:text-base-content data-[state=open]:bg-base-200 data-[state=open]:text-base-content size-7 rounded-md p-0 before:-inset-1.5 **:data-[slot=icon]:size-4 '\n : variant === 'inline'\n ? // A 20px control inside a line of text, such as the pencil beside a list of labels, with a 12px icon.\n 'text-base-700 hover:bg-base-200 grid size-5 place-items-center rounded p-0 disabled:opacity-50 disabled:hover:bg-transparent **:data-[slot=icon]:size-3 '\n : tone === 'neutral'\n ? 'text-base-700 hover:bg-base-200 hover:text-base-content data-[state=open]:bg-base-200 rounded-md '\n : 'rounded-md ') +\n 'transition-[background-color,color,scale] active:scale-[0.94] [&_svg]:size-full ' +\n className\n }\n />\n ),\n);\n\nIconButton.displayName = 'IconButton';\n"],"mappings":";;;;;;AAYA,MAAaA,eAAa,YACrB,EAAE,UAAU,SAAS,OAAO,WAAW,YAAY,IAAI,cAAc,MAAM,GAAG,SAAS,QACpF,oBAACC,YAAD;CACS;CACL,GAAI;CACJ,oBAAkB;CAClB,GAAI;CACJ,MACI,eACI,qBAAC,QAAD;EAAM,WAAU;EAAhB,UAAA,CACK,MACD,oBAAC,iBAAD;GACI,MAAK;GACL,MAAK;GACL,WAAU;EACb,CAAA,CACC;CAEN,CAAA,IAAA;CAGR,SAAQ;CACR,OAAO,SAAS,WAAW,YAAY;CACvC,MAAK;CACL,QAAO;CACP,YAEK,YAAY,WACP,qMACA,YAAY,cAEV,kMACA,YAAY,WAEV,6JACA,SAAS,YACP,sGACA,iBACZ,qFACA;AAEP,CAAA,CAET;AAEA,aAAW,cAAc"}
@@ -1,7 +1,7 @@
1
1
  import { useDesignSystemLabels } from "../foundations/DesignSystemProvider.js";
2
2
  import { tabbable } from "../foundations/KeyboardFocus.js";
3
- import { jsx } from "react/jsx-runtime";
4
3
  import { MonitorIcon, MoonIcon, SunIcon } from "lucide-react";
4
+ import { jsx } from "react/jsx-runtime";
5
5
  // src/actions/ThemeSwitch.tsx
6
6
  const choices = [
7
7
  {
@@ -0,0 +1,36 @@
1
+ import { ReactNode } from "react";
2
+ /** What a thread's activity line says it is doing. */
3
+ export type ActivityState = 'working' | 'quiet' | 'waiting' | 'stopped' | 'unavailable';
4
+ /**
5
+ * A thread's activity: its state's mark, its `action`, then its `age` and how many `agents` work, each after a dot. With
6
+ * `agentList`, the line takes focus and its tooltip lists the agents at work.
7
+ */
8
+ export declare function ActivityLine({ state, action, age, agents, agentList }: {
9
+ state: ActivityState;
10
+ action: ReactNode;
11
+ age?: string | undefined;
12
+ agents?: string | undefined;
13
+ agentList?: ReactNode;
14
+ }): import("react").JSX.Element;
15
+ /** The agents at work, one AgentRow each. */
16
+ export declare function AgentList({ children }: {
17
+ children: ReactNode;
18
+ }): import("react").JSX.Element;
19
+ /** An agent at work: its title, any `model` after it, its action's `age` at the right, and its `action` under it. */
20
+ export declare function AgentRow({ title, model, age, action }: {
21
+ title: string;
22
+ model?: string | undefined;
23
+ age?: ReactNode;
24
+ action?: string | undefined;
25
+ }): import("react").JSX.Element;
26
+ /** An agent's action's age, in AgentRow. */
27
+ export declare function AgentAge({ children }: {
28
+ children: ReactNode;
29
+ }): import("react").JSX.Element;
30
+ /** The agents at work in the item dialog, under `heading`; or, with `unavailable`, why they can't be listed. */
31
+ export declare function WorkingAgents({ heading, unavailable, children }: {
32
+ heading: string;
33
+ unavailable?: string | undefined;
34
+ children?: ReactNode;
35
+ }): import("react").JSX.Element;
36
+ //# sourceMappingURL=ActivityLine.d.ts.map
@@ -0,0 +1,144 @@
1
+ import { Badge } from "../display/Badge.js";
2
+ import { Tooltip, TooltipPopup, TooltipTrigger } from "../overlays/Tooltip.js";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ // src/board/ActivityLine.tsx
5
+ /** Quiet is hollow and stopped is square, so each reads apart from working without its colour. */
6
+ const MARK = {
7
+ working: "rounded-full bg-(--st-now)",
8
+ quiet: "rounded-full border-[1.5px] border-(--warning-foreground)",
9
+ waiting: "rounded-full bg-(--st-amber)",
10
+ stopped: "rounded-[1px] bg-(--st-idle)",
11
+ unavailable: "rounded-full border-[1.5px] border-(--st-idle)"
12
+ };
13
+ /** The line's words for its state, which `data-action` marks. */
14
+ function Words({ state, children }) {
15
+ switch (state) {
16
+ case "working": return /* @__PURE__ */ jsx("span", {
17
+ "data-action": true,
18
+ className: "min-w-0 truncate text-(--foreground)",
19
+ children
20
+ });
21
+ case "quiet": return /* @__PURE__ */ jsx("span", {
22
+ "data-action": true,
23
+ className: "min-w-0 truncate font-medium text-(--warning-foreground) tabular-nums",
24
+ children
25
+ });
26
+ case "waiting": return /* @__PURE__ */ jsx(Badge, {
27
+ "data-action": true,
28
+ "data-activity-badge": true,
29
+ tone: "warning",
30
+ className: "shrink-0",
31
+ children
32
+ });
33
+ case "stopped": return /* @__PURE__ */ jsx(Badge, {
34
+ "data-action": true,
35
+ "data-activity-badge": true,
36
+ className: "shrink-0",
37
+ children
38
+ });
39
+ case "unavailable": return /* @__PURE__ */ jsx("span", {
40
+ "data-action": true,
41
+ className: "min-w-0 truncate",
42
+ children
43
+ });
44
+ }
45
+ }
46
+ /**
47
+ * A thread's activity: its state's mark, its `action`, then its `age` and how many `agents` work, each after a dot. With
48
+ * `agentList`, the line takes focus and its tooltip lists the agents at work.
49
+ */
50
+ function ActivityLine({ state, action, age, agents, agentList }) {
51
+ const shown = /* @__PURE__ */ jsxs("span", {
52
+ "data-activity": state,
53
+ tabIndex: agentList ? 0 : void 0,
54
+ className: "flex min-w-0 items-center gap-1.5 rounded focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--primary)",
55
+ children: [
56
+ /* @__PURE__ */ jsx("span", {
57
+ "data-mark": true,
58
+ className: `inline-block size-2 shrink-0 ${MARK[state]}`
59
+ }),
60
+ /* @__PURE__ */ jsx(Words, {
61
+ state,
62
+ children: action
63
+ }),
64
+ age !== void 0 && /* @__PURE__ */ jsxs("span", {
65
+ "data-age": true,
66
+ className: "shrink-0 tabular-nums",
67
+ children: ["· ", age]
68
+ }),
69
+ agents && /* @__PURE__ */ jsxs("span", {
70
+ "data-agents": true,
71
+ className: "shrink-0 tabular-nums",
72
+ children: ["· ", agents]
73
+ })
74
+ ]
75
+ });
76
+ if (!agentList) return shown;
77
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
78
+ asChild: true,
79
+ children: shown
80
+ }), /* @__PURE__ */ jsx(TooltipPopup, {
81
+ side: "bottom",
82
+ align: "start",
83
+ className: "max-w-md",
84
+ children: agentList
85
+ })] });
86
+ }
87
+ /** The agents at work, one AgentRow each. */
88
+ function AgentList({ children }) {
89
+ return /* @__PURE__ */ jsx("ul", {
90
+ "data-agent-list": true,
91
+ className: "m-0 grid min-w-0 list-none gap-1 p-0 text-left",
92
+ children
93
+ });
94
+ }
95
+ /** An agent at work: its title, any `model` after it, its action's `age` at the right, and its `action` under it. */
96
+ function AgentRow({ title, model, age, action }) {
97
+ return /* @__PURE__ */ jsxs("li", {
98
+ className: "grid grid-cols-[auto_minmax(0,1fr)_auto] items-baseline gap-x-1.5",
99
+ children: [
100
+ /* @__PURE__ */ jsx("span", { className: `inline-block size-2 self-center ${MARK.working}` }),
101
+ /* @__PURE__ */ jsxs("span", {
102
+ className: "flex min-w-0 gap-1.5",
103
+ children: [/* @__PURE__ */ jsx("span", {
104
+ className: "min-w-0 truncate font-medium",
105
+ children: title
106
+ }), model && /* @__PURE__ */ jsxs("span", {
107
+ className: "shrink-0 opacity-70",
108
+ children: ["· ", model]
109
+ })]
110
+ }),
111
+ age || /* @__PURE__ */ jsx("span", {}),
112
+ action && /* @__PURE__ */ jsx("span", {
113
+ title: action,
114
+ className: "col-span-2 col-start-2 truncate opacity-70",
115
+ children: action
116
+ })
117
+ ]
118
+ });
119
+ }
120
+ /** An agent's action's age, in AgentRow. */
121
+ function AgentAge({ children }) {
122
+ return /* @__PURE__ */ jsx("span", {
123
+ "data-agent-age": true,
124
+ className: "shrink-0 tabular-nums opacity-70",
125
+ children
126
+ });
127
+ }
128
+ /** The agents at work in the item dialog, under `heading`; or, with `unavailable`, why they can't be listed. */
129
+ function WorkingAgents({ heading, unavailable, children }) {
130
+ return /* @__PURE__ */ jsx("section", {
131
+ "data-working-agents": true,
132
+ className: "grid min-w-0 grid-cols-[minmax(0,1fr)] gap-2 text-xs",
133
+ children: unavailable ? /* @__PURE__ */ jsx("p", {
134
+ className: "m-0 text-(--muted-foreground)",
135
+ children: unavailable
136
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("p", {
137
+ className: "m-0 font-medium",
138
+ children: heading
139
+ }), children] })
140
+ });
141
+ }
142
+ export { ActivityLine, AgentAge, AgentList, AgentRow, WorkingAgents };
143
+
144
+ //# sourceMappingURL=ActivityLine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActivityLine.js","names":[],"sources":["../../src/board/ActivityLine.tsx"],"sourcesContent":["// What a row says its T3 thread is doing, in its second line's text slot: a status mark, then the newest action, its\n// age and the agents at work; and the list of agents at work, in its tooltip and the item dialog.\n\nimport type { ReactNode } from 'react';\n\nimport { Badge } from '../display/Badge';\nimport { Tooltip, TooltipPopup, TooltipTrigger } from '../overlays/Tooltip';\n\n/** What a thread's activity line says it is doing. */\nexport type ActivityState = 'working' | 'quiet' | 'waiting' | 'stopped' | 'unavailable';\n\n/** Quiet is hollow and stopped is square, so each reads apart from working without its colour. */\nconst MARK: Record<ActivityState, string> = {\n working: 'rounded-full bg-(--st-now)',\n quiet: 'rounded-full border-[1.5px] border-(--warning-foreground)',\n waiting: 'rounded-full bg-(--st-amber)',\n stopped: 'rounded-[1px] bg-(--st-idle)',\n unavailable: 'rounded-full border-[1.5px] border-(--st-idle)',\n};\n\n/** The line's words for its state, which `data-action` marks. */\nfunction Words({ state, children }: { state: ActivityState; children: ReactNode }) {\n switch (state) {\n case 'working':\n return (\n <span data-action className=\"min-w-0 truncate text-(--foreground)\">\n {children}\n </span>\n );\n case 'quiet':\n return (\n <span data-action className=\"min-w-0 truncate font-medium text-(--warning-foreground) tabular-nums\">\n {children}\n </span>\n );\n case 'waiting':\n return (\n <Badge data-action data-activity-badge tone=\"warning\" className=\"shrink-0\">\n {children}\n </Badge>\n );\n case 'stopped':\n return (\n <Badge data-action data-activity-badge className=\"shrink-0\">\n {children}\n </Badge>\n );\n case 'unavailable':\n return (\n <span data-action className=\"min-w-0 truncate\">\n {children}\n </span>\n );\n }\n}\n\n/**\n * A thread's activity: its state's mark, its `action`, then its `age` and how many `agents` work, each after a dot. With\n * `agentList`, the line takes focus and its tooltip lists the agents at work.\n */\nexport function ActivityLine({\n state,\n action,\n age,\n agents,\n agentList,\n}: {\n state: ActivityState;\n action: ReactNode;\n age?: string | undefined;\n agents?: string | undefined;\n agentList?: ReactNode;\n}) {\n const shown = (\n <span\n data-activity={state}\n tabIndex={agentList ? 0 : undefined}\n className=\"flex min-w-0 items-center gap-1.5 rounded focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--primary)\"\n >\n <span data-mark className={`inline-block size-2 shrink-0 ${MARK[state]}`} />\n <Words state={state}>{action}</Words>\n {age !== undefined && (\n <span data-age className=\"shrink-0 tabular-nums\">\n · {age}\n </span>\n )}\n {agents && (\n <span data-agents className=\"shrink-0 tabular-nums\">\n · {agents}\n </span>\n )}\n </span>\n );\n\n if (!agentList) return shown;\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>{shown}</TooltipTrigger>\n <TooltipPopup side=\"bottom\" align=\"start\" className=\"max-w-md\">\n {agentList}\n </TooltipPopup>\n </Tooltip>\n );\n}\n\n/** The agents at work, one AgentRow each. */\nexport function AgentList({ children }: { children: ReactNode }) {\n return (\n <ul data-agent-list className=\"m-0 grid min-w-0 list-none gap-1 p-0 text-left\">\n {children}\n </ul>\n );\n}\n\n/** An agent at work: its title, any `model` after it, its action's `age` at the right, and its `action` under it. */\nexport function AgentRow({\n title,\n model,\n age,\n action,\n}: {\n title: string;\n model?: string | undefined;\n age?: ReactNode;\n action?: string | undefined;\n}) {\n return (\n <li className=\"grid grid-cols-[auto_minmax(0,1fr)_auto] items-baseline gap-x-1.5\">\n <span className={`inline-block size-2 self-center ${MARK.working}`} />\n <span className=\"flex min-w-0 gap-1.5\">\n <span className=\"min-w-0 truncate font-medium\">{title}</span>\n {model && <span className=\"shrink-0 opacity-70\">· {model}</span>}\n </span>\n {age || <span />}\n {action && (\n <span title={action} className=\"col-span-2 col-start-2 truncate opacity-70\">\n {action}\n </span>\n )}\n </li>\n );\n}\n\n/** An agent's action's age, in AgentRow. */\nexport function AgentAge({ children }: { children: ReactNode }) {\n return (\n <span data-agent-age className=\"shrink-0 tabular-nums opacity-70\">\n {children}\n </span>\n );\n}\n\n/** The agents at work in the item dialog, under `heading`; or, with `unavailable`, why they can't be listed. */\nexport function WorkingAgents({\n heading,\n unavailable,\n children,\n}: {\n heading: string;\n unavailable?: string | undefined;\n children?: ReactNode;\n}) {\n return (\n <section data-working-agents className=\"grid min-w-0 grid-cols-[minmax(0,1fr)] gap-2 text-xs\">\n {unavailable ? (\n <p className=\"m-0 text-(--muted-foreground)\">{unavailable}</p>\n ) : (\n <>\n <p className=\"m-0 font-medium\">{heading}</p>\n {children}\n </>\n )}\n </section>\n );\n}\n"],"mappings":";;;;;AAYA,MAAM,OAAsC;CACxC,SAAS;CACT,OAAO;CACP,SAAS;CACT,SAAS;CACT,aAAa;AACjB;;AAGA,SAAS,MAAM,EAAE,OAAO,YAA2D;CAC/E,QAAQ,OAAR;EACI,KAAK,WACD,OACI,oBAAC,QAAD;GAAM,eAAA;GAAY,WAAU;GACvB;EACC,CAAA;EAEd,KAAK,SACD,OACI,oBAAC,QAAD;GAAM,eAAA;GAAY,WAAU;GACvB;EACC,CAAA;EAEd,KAAK,WACD,OACI,oBAAC,OAAD;GAAO,eAAA;GAAY,uBAAA;GAAoB,MAAK;GAAU,WAAU;GAC3D;EACE,CAAA;EAEf,KAAK,WACD,OACI,oBAAC,OAAD;GAAO,eAAA;GAAY,uBAAA;GAAoB,WAAU;GAC5C;EACE,CAAA;EAEf,KAAK,eACD,OACI,oBAAC,QAAD;GAAM,eAAA;GAAY,WAAU;GACvB;EACC,CAAA;CAElB;AACJ;;;;;AAMA,SAAgB,aAAa,EACzB,OACA,QACA,KACA,QACA,aAOD;CACC,MAAM,QACF,qBAAC,QAAD;EACI,iBAAe;EACf,UAAU,YAAY,IAAI,KAAA;EAC1B,WAAU;EAHd,UAAA;GAKI,oBAAC,QAAD;IAAM,aAAA;IAAU,WAAW,gCAAgC,KAAK;GAAW,CAAA;GAC3E,oBAAC,OAAD;IAAc;IAAQ,UAAA;GAAc,CAAA;GACnC,QAAQ,KAAA,KACL,qBAAC,QAAD;IAAM,YAAA;IAAS,WAAU;IAAzB,UAAA,CAAiD,MAC1C,GACD;;GAET,UACG,qBAAC,QAAD;IAAM,eAAA;IAAY,WAAU;IAA5B,UAAA,CAAoD,MAC7C,MACD;;EAER;;CAGV,IAAI,CAAC,WAAW,OAAO;CAEvB,OACI,qBAAC,SAAD,EAAA,UAAA,CACI,oBAAC,gBAAD;EAAgB,SAAA;EAAS,UAAA;CAAsB,CAAA,GAC/C,oBAAC,cAAD;EAAc,MAAK;EAAS,OAAM;EAAQ,WAAU;EAC/C,UAAA;CACS,CAAA,CACT,EAAA,CAAA;AAEjB;;AAGA,SAAgB,UAAU,EAAE,YAAqC;CAC7D,OACI,oBAAC,MAAD;EAAI,mBAAA;EAAgB,WAAU;EACzB;CACD,CAAA;AAEZ;;AAGA,SAAgB,SAAS,EACrB,OACA,OACA,KACA,UAMD;CACC,OACI,qBAAC,MAAD;EAAI,WAAU;EAAd,UAAA;GACI,oBAAC,QAAD,EAAM,WAAW,mCAAmC,KAAK,UAAY,CAAA;GACrE,qBAAC,QAAD;IAAM,WAAU;IAAhB,UAAA,CACI,oBAAC,QAAD;KAAM,WAAU;KAAgC,UAAA;IAAY,CAAA,GAC3D,SAAS,qBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA,CAAsC,MAAG,KAAY;IAC7D,CAAA,CAAA;;GACL,OAAO,oBAAC,QAAD,CAAO,CAAA;GACd,UACG,oBAAC,QAAD;IAAM,OAAO;IAAQ,WAAU;IAC1B,UAAA;GACC,CAAA;EAEV;;AAEZ;;AAGA,SAAgB,SAAS,EAAE,YAAqC;CAC5D,OACI,oBAAC,QAAD;EAAM,kBAAA;EAAe,WAAU;EAC1B;CACC,CAAA;AAEd;;AAGA,SAAgB,cAAc,EAC1B,SACA,aACA,YAKD;CACC,OACI,oBAAC,WAAD;EAAS,uBAAA;EAAoB,WAAU;EAClC,UAAA,cACG,oBAAC,KAAD;GAAG,WAAU;GAAiC,UAAA;EAAe,CAAA,IAE7D,qBAAA,UAAA,EAAA,UAAA,CACI,oBAAC,KAAD;GAAG,WAAU;GAAmB,UAAA;EAAW,CAAA,GAC1C,QACH,EAAA,CAAA;CAED,CAAA;AAEjB"}
@@ -0,0 +1,11 @@
1
+ import { ReactNode } from "react";
2
+ /** A thin track named by `label`, swept by a bar while `running`. */
3
+ export declare function ActivityTrack({ label, running }: {
4
+ label: string;
5
+ running: boolean;
6
+ }): import("react").JSX.Element;
7
+ /** The activity's words alone, in one small muted line. */
8
+ export declare function ActivityLabel({ children }: {
9
+ children: ReactNode;
10
+ }): import("react").JSX.Element;
11
+ //# sourceMappingURL=ActivityTrack.d.ts.map
@@ -0,0 +1,25 @@
1
+ import { ambientMotion } from "../foundations/AmbientMotion.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ // src/board/ActivityTrack.tsx
4
+ /** A thin track named by `label`, swept by a bar while `running`. */
5
+ function ActivityTrack({ label, running }) {
6
+ return /* @__PURE__ */ jsx("div", {
7
+ role: "img",
8
+ "aria-label": label,
9
+ className: "activity-track h-1.5 overflow-hidden rounded-full bg-(--soft)",
10
+ children: running && /* @__PURE__ */ jsx("span", {
11
+ ref: ambientMotion,
12
+ className: "activity-sweep block h-1.5 w-1/3 rounded-full bg-(--st-now)"
13
+ })
14
+ });
15
+ }
16
+ /** The activity's words alone, in one small muted line. */
17
+ function ActivityLabel({ children }) {
18
+ return /* @__PURE__ */ jsx("span", {
19
+ className: "block h-4 text-[11px] leading-4 whitespace-nowrap text-(--muted-foreground)",
20
+ children
21
+ });
22
+ }
23
+ export { ActivityLabel, ActivityTrack };
24
+
25
+ //# sourceMappingURL=ActivityTrack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActivityTrack.js","names":[],"sources":["../../src/board/ActivityTrack.tsx"],"sourcesContent":["// A piece of work's activity as the board reads it from T3: the track that sweeps while it runs, and its label.\n\nimport type { ReactNode } from 'react';\n\nimport { ambientMotion } from '../foundations/AmbientMotion';\n\n/** A thin track named by `label`, swept by a bar while `running`. */\nexport function ActivityTrack({ label, running }: { label: string; running: boolean }) {\n return (\n <div role=\"img\" aria-label={label} className=\"activity-track h-1.5 overflow-hidden rounded-full bg-(--soft)\">\n {running && (\n <span ref={ambientMotion} className=\"activity-sweep block h-1.5 w-1/3 rounded-full bg-(--st-now)\" />\n )}\n </div>\n );\n}\n\n/** The activity's words alone, in one small muted line. */\nexport function ActivityLabel({ children }: { children: ReactNode }) {\n return (\n <span className=\"block h-4 text-[11px] leading-4 whitespace-nowrap text-(--muted-foreground)\">{children}</span>\n );\n}\n"],"mappings":";;;;AAOA,SAAgB,cAAc,EAAE,OAAO,WAAgD;CACnF,OACI,oBAAC,OAAD;EAAK,MAAK;EAAM,cAAY;EAAO,WAAU;EACxC,UAAA,WACG,oBAAC,QAAD;GAAM,KAAK;GAAe,WAAU;EAA+D,CAAA;CAEtG,CAAA;AAEb;;AAGA,SAAgB,cAAc,EAAE,YAAqC;CACjE,OACI,oBAAC,QAAD;EAAM,WAAU;EAA+E;CAAe,CAAA;AAEtH"}