@lar-works/design-system 0.2.0 → 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 (433) 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/showcase.css +6 -0
  427. package/src/styles.css +9 -1
  428. package/src/typography/Code.tsx +24 -0
  429. package/src/typography/Link.tsx +19 -10
  430. package/src/typography/Typography.tsx +25 -2
  431. package/src/typography/index.ts +1 -1
  432. package/dist/feedback/index.js +0 -11
  433. package/dist/typography/index.js +0 -4
@@ -23,16 +23,23 @@ const variants = {
23
23
  layout: "max-w-md px-4 py-5",
24
24
  icon: "[&>svg]:size-6",
25
25
  space: "related"
26
+ },
27
+ /** A first run's welcome in an app's empty main area: its `icon` (such as the brand mark) in its own colours over a
28
+ * section-sized title. */
29
+ welcome: {
30
+ layout: "max-w-xl px-6 py-16",
31
+ icon: "",
32
+ space: "group"
26
33
  }
27
34
  };
28
- function CollectionState({ actionLabel, description, icon, onAction, title, variant = "page" }) {
35
+ function CollectionState({ action, actionLabel, description, icon, onAction, title, variant = "page" }) {
29
36
  const compact = variant === "compact" || variant === "panel";
30
37
  const state = /* @__PURE__ */ jsxs(Stack, {
31
38
  align: "center",
32
39
  space: variants[variant].space,
33
40
  className: `mx-auto text-center ${variants[variant].layout}`,
34
41
  children: [
35
- icon ? /* @__PURE__ */ jsx("span", {
42
+ icon ? variant === "welcome" ? icon : /* @__PURE__ */ jsx("span", {
36
43
  className: `text-base-500 ${variants[variant].icon}`,
37
44
  children: icon
38
45
  }) : null,
@@ -43,7 +50,7 @@ function CollectionState({ actionLabel, description, icon, onAction, title, vari
43
50
  children: title
44
51
  }) : /* @__PURE__ */ jsx(Heading, {
45
52
  as: "h2",
46
- variant: "subsection",
53
+ variant: variant === "welcome" ? "section" : "subsection",
47
54
  children: title
48
55
  }), /* @__PURE__ */ jsx(Text, {
49
56
  variant: compact ? "caption" : "description",
@@ -51,12 +58,12 @@ function CollectionState({ actionLabel, description, icon, onAction, title, vari
51
58
  children: description
52
59
  })]
53
60
  }),
54
- actionLabel && onAction ? /* @__PURE__ */ jsx(Button, {
61
+ action ?? (actionLabel && onAction ? /* @__PURE__ */ jsx(Button, {
55
62
  type: "button",
56
63
  onClick: onAction,
57
64
  variant: "secondary",
58
65
  children: actionLabel
59
- }) : null
66
+ }) : null)
60
67
  ]
61
68
  });
62
69
  return variant === "framed" || variant === "panel" ? /* @__PURE__ */ jsx("div", {
@@ -1 +1 @@
1
- {"version":3,"file":"CollectionState.js","names":[],"sources":["../../src/collections/CollectionState.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport { Button } from '../actions/Button';\nimport { Stack } from '../layout/Flow';\nimport { Heading, Text } from '../typography/Typography';\n\nconst page = { layout: 'max-w-lg px-6 py-16', icon: '[&>svg]:size-8', space: 'group' } as const;\nconst variants = {\n page,\n /** A placeholder outlining the content that will fill the region. */\n framed: page,\n /** Fits inside a panel or popover instead of owning a page region. */\n compact: { layout: 'max-w-64 px-3 py-6', icon: '[&>svg]:size-6', space: 'related' },\n /** A quiet empty state with the same surface as dashboard content. */\n panel: { layout: 'max-w-md px-4 py-5', icon: '[&>svg]:size-6', space: 'related' },\n} as const;\n\ninterface CollectionStateProps {\n actionLabel?: string;\n description: string;\n icon?: ReactNode;\n onAction?: () => void;\n title: string;\n variant?: keyof typeof variants;\n}\n\nexport function CollectionState({\n actionLabel,\n description,\n icon,\n onAction,\n title,\n variant = 'page',\n}: CollectionStateProps) {\n const compact = variant === 'compact' || variant === 'panel';\n const state = (\n <Stack\n align=\"center\"\n space={variants[variant].space}\n className={`mx-auto text-center ${variants[variant].layout}`}\n >\n {icon ? <span className={`text-base-500 ${variants[variant].icon}`}>{icon}</span> : null}\n <Stack space=\"tight\">\n {compact ? (\n <Text variant=\"label\">{title}</Text>\n ) : (\n <Heading as=\"h2\" variant=\"subsection\">\n {title}\n </Heading>\n )}\n <Text variant={compact ? 'caption' : 'description'} tone=\"muted\">\n {description}\n </Text>\n </Stack>\n {actionLabel && onAction ? (\n <Button type=\"button\" onClick={onAction} variant=\"secondary\">\n {actionLabel}\n </Button>\n ) : null}\n </Stack>\n );\n\n return variant === 'framed' || variant === 'panel' ? (\n <div\n className={\n variant === 'panel'\n ? 'border-base-300 bg-base-100 rounded-xl border'\n : 'border-base-300 rounded-xl border border-dashed'\n }\n >\n {state}\n </div>\n ) : (\n state\n );\n}\n"],"mappings":";;;;;AAMA,MAAM,OAAO;CAAE,QAAQ;CAAuB,MAAM;CAAkB,OAAO;AAAQ;AACrF,MAAM,WAAW;CACb;;CAEA,QAAQ;;CAER,SAAS;EAAE,QAAQ;EAAsB,MAAM;EAAkB,OAAO;CAAU;;CAElF,OAAO;EAAE,QAAQ;EAAsB,MAAM;EAAkB,OAAO;CAAU;AACpF;AAWA,SAAgB,gBAAgB,EAC5B,aACA,aACA,MACA,UACA,OACA,UAAU,UACW;CACrB,MAAM,UAAU,YAAY,aAAa,YAAY;CACrD,MAAM,QACF,qBAAC,OAAD;EACI,OAAM;EACN,OAAO,SAAS,QAAQ,CAAC;EACzB,WAAW,uBAAuB,SAAS,QAAQ,CAAC;EAHxD,UAAA;GAKK,OAAO,oBAAC,QAAD;IAAM,WAAW,iBAAiB,SAAS,QAAQ,CAAC;IAAS,UAAA;GAAW,CAAA,IAAI;GACpF,qBAAC,OAAD;IAAO,OAAM;IAAb,UAAA,CACK,UACG,oBAAC,MAAD;KAAM,SAAQ;KAAS,UAAA;IAAY,CAAA,IAEnC,oBAAC,SAAD;KAAS,IAAG;KAAK,SAAQ;KACpB,UAAA;IACI,CAAA,GAEb,oBAAC,MAAD;KAAM,SAAS,UAAU,YAAY;KAAe,MAAK;KACpD,UAAA;IACC,CAAA,CACH;;GACN,eAAe,WACZ,oBAAC,QAAD;IAAQ,MAAK;IAAS,SAAS;IAAU,SAAQ;IAC5C,UAAA;GACG,CAAA,IACR;EACD;;CAGX,OAAO,YAAY,YAAY,YAAY,UACvC,oBAAC,OAAD;EACI,WACI,YAAY,UACN,kDACA;EAGT,UAAA;CACA,CAAA,IAEL;AAER"}
1
+ {"version":3,"file":"CollectionState.js","names":[],"sources":["../../src/collections/CollectionState.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport { Button } from '../actions/Button';\nimport { Stack } from '../layout/Flow';\nimport { Heading, Text } from '../typography/Typography';\n\nconst page = { layout: 'max-w-lg px-6 py-16', icon: '[&>svg]:size-8', space: 'group' } as const;\nconst variants = {\n page,\n /** A placeholder outlining the content that will fill the region. */\n framed: page,\n /** Fits inside a panel or popover instead of owning a page region. */\n compact: { layout: 'max-w-64 px-3 py-6', icon: '[&>svg]:size-6', space: 'related' },\n /** A quiet empty state with the same surface as dashboard content. */\n panel: { layout: 'max-w-md px-4 py-5', icon: '[&>svg]:size-6', space: 'related' },\n /** A first run's welcome in an app's empty main area: its `icon` (such as the brand mark) in its own colours over a\n * section-sized title. */\n welcome: { layout: 'max-w-xl px-6 py-16', icon: '', space: 'group' },\n} as const;\n\ninterface CollectionStateProps {\n /** The action in place of `actionLabel` and `onAction`, for a caller whose button has its own look or markers. */\n action?: ReactNode;\n actionLabel?: string;\n description: string;\n icon?: ReactNode;\n onAction?: () => void;\n title: string;\n variant?: keyof typeof variants;\n}\n\nexport function CollectionState({\n action,\n actionLabel,\n description,\n icon,\n onAction,\n title,\n variant = 'page',\n}: CollectionStateProps) {\n const compact = variant === 'compact' || variant === 'panel';\n const state = (\n <Stack\n align=\"center\"\n space={variants[variant].space}\n className={`mx-auto text-center ${variants[variant].layout}`}\n >\n {icon ? (\n variant === 'welcome' ? (\n icon\n ) : (\n <span className={`text-base-500 ${variants[variant].icon}`}>{icon}</span>\n )\n ) : null}\n <Stack space=\"tight\">\n {compact ? (\n <Text variant=\"label\">{title}</Text>\n ) : (\n <Heading as=\"h2\" variant={variant === 'welcome' ? 'section' : 'subsection'}>\n {title}\n </Heading>\n )}\n <Text variant={compact ? 'caption' : 'description'} tone=\"muted\">\n {description}\n </Text>\n </Stack>\n {action ??\n (actionLabel && onAction ? (\n <Button type=\"button\" onClick={onAction} variant=\"secondary\">\n {actionLabel}\n </Button>\n ) : null)}\n </Stack>\n );\n\n return variant === 'framed' || variant === 'panel' ? (\n <div\n className={\n variant === 'panel'\n ? 'border-base-300 bg-base-100 rounded-xl border'\n : 'border-base-300 rounded-xl border border-dashed'\n }\n >\n {state}\n </div>\n ) : (\n state\n );\n}\n"],"mappings":";;;;;AAMA,MAAM,OAAO;CAAE,QAAQ;CAAuB,MAAM;CAAkB,OAAO;AAAQ;AACrF,MAAM,WAAW;CACb;;CAEA,QAAQ;;CAER,SAAS;EAAE,QAAQ;EAAsB,MAAM;EAAkB,OAAO;CAAU;;CAElF,OAAO;EAAE,QAAQ;EAAsB,MAAM;EAAkB,OAAO;CAAU;;;CAGhF,SAAS;EAAE,QAAQ;EAAuB,MAAM;EAAI,OAAO;CAAQ;AACvE;AAaA,SAAgB,gBAAgB,EAC5B,QACA,aACA,aACA,MACA,UACA,OACA,UAAU,UACW;CACrB,MAAM,UAAU,YAAY,aAAa,YAAY;CACrD,MAAM,QACF,qBAAC,OAAD;EACI,OAAM;EACN,OAAO,SAAS,QAAQ,CAAC;EACzB,WAAW,uBAAuB,SAAS,QAAQ,CAAC;EAHxD,UAAA;GAKK,OACG,YAAY,YACR,OAEA,oBAAC,QAAD;IAAM,WAAW,iBAAiB,SAAS,QAAQ,CAAC;IAAS,UAAA;GAAW,CAAA,IAE5E;GACJ,qBAAC,OAAD;IAAO,OAAM;IAAb,UAAA,CACK,UACG,oBAAC,MAAD;KAAM,SAAQ;KAAS,UAAA;IAAY,CAAA,IAEnC,oBAAC,SAAD;KAAS,IAAG;KAAK,SAAS,YAAY,YAAY,YAAY;KACzD,UAAA;IACI,CAAA,GAEb,oBAAC,MAAD;KAAM,SAAS,UAAU,YAAY;KAAe,MAAK;KACpD,UAAA;IACC,CAAA,CACH;;GACN,WACI,eAAe,WACZ,oBAAC,QAAD;IAAQ,MAAK;IAAS,SAAS;IAAU,SAAQ;IAC5C,UAAA;GACG,CAAA,IACR;EACL;;CAGX,OAAO,YAAY,YAAY,YAAY,UACvC,oBAAC,OAAD;EACI,WACI,YAAY,UACN,kDACA;EAGT,UAAA;CACA,CAAA,IAEL;AAER"}
@@ -4,8 +4,8 @@ import { Stack } from "../layout/Flow.js";
4
4
  import { LinkBox, LinkOverlay } from "../typography/Link.js";
5
5
  import { Text } from "../typography/Typography.js";
6
6
  import { createContext, useContext } from "react";
7
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
7
  import { ChevronRightIcon } from "lucide-react";
8
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
9
  // src/collections/ResultList.tsx
10
10
  const ResultListContext = createContext({
11
11
  compact: false,
@@ -1,8 +1,8 @@
1
1
  import { IconButton } from "../actions/IconButton.js";
2
2
  import { SkeletonLoader } from "../feedback/SkeletonLoader.js";
3
3
  import { Inline } from "../layout/Flow.js";
4
- import { jsx, jsxs } from "react/jsx-runtime";
5
4
  import { ChevronRightIcon } from "lucide-react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
6
  // src/collections/ScrollRow.tsx
7
7
  const row = "-mx-1 flex snap-x scroll-px-1 gap-4 overflow-x-auto px-1 pt-1 pb-3";
8
8
  /** One row of wide cards, such as video stills, that scrolls sideways instead of wrapping. */
@@ -6,8 +6,8 @@ import { useCollectionViewport } from "./CollectionViewport.js";
6
6
  import { DataRow } from "./DataRow.js";
7
7
  import { useCollectionMotion } from "./useCollectionMotion.js";
8
8
  import { useCallback, useEffect, useRef } from "react";
9
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
9
  import { ChevronDownIcon } from "lucide-react";
10
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
11
  import { useWindowVirtualizer } from "@tanstack/react-virtual";
12
12
  // src/collections/VirtualList.tsx
13
13
  function VirtualList({ columns, count, itemAt, itemLabel, label, onRangeChange, onSelect, itemHref, onNavigate, placeholderAt, itemKey, loading, section, sort, direction = "asc" }) {
@@ -1,5 +1,8 @@
1
1
  import { AvatarProps } from "@ninna-ui/primitives";
2
- type AvatarProps$1 = Omit<AvatarProps, 'color' | 'size' | 'radius'>;
3
- declare function Avatar$1(props: AvatarProps$1): import("react").JSX.Element;
2
+ type AvatarProps$1 = Omit<AvatarProps, 'color' | 'size' | 'radius'> & {
3
+ /** The 24px avatar beside a name in a dense list, such as a comment's author. */
4
+ compact?: boolean;
5
+ };
6
+ declare function Avatar$1({ compact, ...props }: AvatarProps$1): import("react").JSX.Element;
4
7
  export { Avatar$1 as Avatar };
5
8
  //# sourceMappingURL=Avatar.d.ts.map
@@ -1,11 +1,11 @@
1
1
  import { Avatar } from "@ninna-ui/primitives";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  // src/display/Avatar.tsx
4
- function Avatar$1(props) {
4
+ function Avatar$1({ compact = false, ...props }) {
5
5
  return /* @__PURE__ */ jsx(Avatar, {
6
6
  ...props,
7
7
  color: "neutral",
8
- size: "sm"
8
+ size: compact ? "xs" : "sm"
9
9
  });
10
10
  }
11
11
  export { Avatar$1 as Avatar };
@@ -1 +1 @@
1
- {"version":3,"file":"Avatar.js","names":["Avatar","NinnaAvatar"],"sources":["../../src/display/Avatar.tsx"],"sourcesContent":["import { Avatar as NinnaAvatar, type AvatarProps as NinnaAvatarProps } from '@ninna-ui/primitives';\n\ntype AvatarProps = Omit<NinnaAvatarProps, 'color' | 'size' | 'radius'>;\n\nexport function Avatar(props: AvatarProps) {\n return <NinnaAvatar {...props} color=\"neutral\" size=\"sm\" />;\n}\n"],"mappings":";;;AAIA,SAAgBA,SAAO,OAAoB;CACvC,OAAO,oBAACC,QAAD;EAAa,GAAI;EAAO,OAAM;EAAU,MAAK;CAAM,CAAA;AAC9D"}
1
+ {"version":3,"file":"Avatar.js","names":["Avatar","NinnaAvatar"],"sources":["../../src/display/Avatar.tsx"],"sourcesContent":["import { Avatar as NinnaAvatar, type AvatarProps as NinnaAvatarProps } from '@ninna-ui/primitives';\n\ntype AvatarProps = Omit<NinnaAvatarProps, 'color' | 'size' | 'radius'> & {\n /** The 24px avatar beside a name in a dense list, such as a comment's author. */\n compact?: boolean;\n};\n\nexport function Avatar({ compact = false, ...props }: AvatarProps) {\n return <NinnaAvatar {...props} color=\"neutral\" size={compact ? 'xs' : 'sm'} />;\n}\n"],"mappings":";;;AAOA,SAAgBA,SAAO,EAAE,UAAU,OAAO,GAAG,SAAsB;CAC/D,OAAO,oBAACC,QAAD;EAAa,GAAI;EAAO,OAAM;EAAU,MAAM,UAAU,OAAO;CAAO,CAAA;AACjF"}
@@ -4,7 +4,12 @@ type BadgeProps$1 = Omit<BadgeProps, 'color' | 'size' | 'variant'> & {
4
4
  tone?: StatusTone | 'accent';
5
5
  /** A lar-brand app hue that colours the badge in place of its tone. */
6
6
  hue?: number;
7
+ /** A tracker label's own colour, such as GitHub's, as a soft tint readable in both modes; anything but a colour
8
+ * keeps the tone. */
9
+ labelColor?: string | undefined;
10
+ /** Dims the text to the muted colour, for an entry that is listed but switched off. */
11
+ muted?: boolean;
7
12
  };
8
- declare function Badge$1({ tone, hue, className, style, ...props }: BadgeProps$1): import("react").JSX.Element;
13
+ declare function Badge$1({ tone, hue, labelColor, muted, className, style, ...props }: BadgeProps$1): import("react").JSX.Element;
9
14
  export { Badge$1 as Badge, BadgeProps$1 as BadgeProps };
10
15
  //# sourceMappingURL=Badge.d.ts.map
@@ -1,3 +1,4 @@
1
+ import { tint } from "./LabelTint.js";
1
2
  import { Badge } from "@ninna-ui/primitives";
2
3
  import { jsx } from "react/jsx-runtime";
3
4
  // src/display/Badge.tsx
@@ -10,17 +11,21 @@ const toneClasses = {
10
11
  danger: "bg-danger/10 text-(--lar-danger-text) dark:bg-danger/16",
11
12
  info: "bg-info/10 text-(--lar-info-text) dark:bg-info/16"
12
13
  };
13
- function Badge$1({ tone = "neutral", hue, className = "", style, ...props }) {
14
+ function Badge$1({ tone = "neutral", hue, labelColor, muted = false, className = "", style, ...props }) {
15
+ const labelTint = tint(labelColor);
14
16
  return /* @__PURE__ */ jsx(Badge, {
15
17
  ...props,
16
18
  color: tone === "accent" ? "primary" : tone,
17
19
  size: "sm",
18
20
  variant: "soft",
19
- style: hue === void 0 ? style : {
21
+ style: hue !== void 0 ? {
20
22
  ...style,
21
23
  "--lar-kind-hue": hue
22
- },
23
- className: `h-5 gap-1 rounded-sm px-1.5 text-xs font-medium [&>svg]:size-3 [&>svg]:shrink-0 ${hue === void 0 ? toneClasses[tone] : "kind-badge!"} ${className}`
24
+ } : labelTint ? {
25
+ ...style,
26
+ ...labelTint
27
+ } : style,
28
+ className: `h-5 gap-1 rounded-sm px-1.5 text-xs font-medium [&>svg]:size-3 [&>svg]:shrink-0 ${hue === void 0 ? toneClasses[tone] : "kind-badge!"} ${muted ? "text-(--muted-foreground)" : ""} ${className}`
24
29
  });
25
30
  }
26
31
  export { Badge$1 as Badge };
@@ -1 +1 @@
1
- {"version":3,"file":"Badge.js","names":["Badge","NinnaBadge"],"sources":["../../src/display/Badge.tsx"],"sourcesContent":["import { Badge as NinnaBadge, type BadgeProps as NinnaBadgeProps } from '@ninna-ui/primitives';\nimport type { CSSProperties } from 'react';\n\nimport type { StatusTone } from '../feedback/StatusIndicator';\n\nexport type BadgeProps = Omit<NinnaBadgeProps, 'color' | 'size' | 'variant'> & {\n tone?: StatusTone | 'accent';\n /** A lar-brand app hue that colours the badge in place of its tone. */\n hue?: number;\n};\n\n/** T3 Code's badge: a 6px-radius label on an 8% tint of its tone, in the tone's foreground colour. */\nconst toneClasses: Record<NonNullable<BadgeProps['tone']>, string> = {\n neutral: 'bg-base-200 text-base-800 dark:bg-base-300 dark:text-base-800',\n accent: 'bg-primary/10 text-primary dark:bg-primary/20 dark:text-[color-mix(in_srgb,var(--color-primary)_55%,white)]',\n success: 'bg-success/10 text-(--lar-success-text) dark:bg-success/16',\n warning: 'bg-warning/12 text-(--lar-warning-text) dark:bg-warning/16',\n danger: 'bg-danger/10 text-(--lar-danger-text) dark:bg-danger/16',\n info: 'bg-info/10 text-(--lar-info-text) dark:bg-info/16',\n};\n\nexport function Badge({ tone = 'neutral', hue, className = '', style, ...props }: BadgeProps) {\n return (\n <NinnaBadge\n {...props}\n color={tone === 'accent' ? 'primary' : tone}\n size=\"sm\"\n variant=\"soft\"\n style={hue === undefined ? style : ({ ...style, '--lar-kind-hue': hue } as CSSProperties)}\n className={`h-5 gap-1 rounded-sm px-1.5 text-xs font-medium [&>svg]:size-3 [&>svg]:shrink-0 ${hue === undefined ? toneClasses[tone] : 'kind-badge!'} ${className}`}\n />\n );\n}\n"],"mappings":";;;;AAYA,MAAM,cAA+D;CACjE,SAAS;CACT,QAAQ;CACR,SAAS;CACT,SAAS;CACT,QAAQ;CACR,MAAM;AACV;AAEA,SAAgBA,QAAM,EAAE,OAAO,WAAW,KAAK,YAAY,IAAI,OAAO,GAAG,SAAqB;CAC1F,OACI,oBAACC,OAAD;EACI,GAAI;EACJ,OAAO,SAAS,WAAW,YAAY;EACvC,MAAK;EACL,SAAQ;EACR,OAAO,QAAQ,KAAA,IAAY,QAAS;GAAE,GAAG;GAAO,kBAAkB;EAAI;EACtE,WAAW,mFAAmF,QAAQ,KAAA,IAAY,YAAY,QAAQ,cAAc,GAAG;CAC1J,CAAA;AAET"}
1
+ {"version":3,"file":"Badge.js","names":["Badge","NinnaBadge"],"sources":["../../src/display/Badge.tsx"],"sourcesContent":["import { Badge as NinnaBadge, type BadgeProps as NinnaBadgeProps } from '@ninna-ui/primitives';\nimport type { CSSProperties } from 'react';\n\nimport type { StatusTone } from '../feedback/StatusIndicator';\nimport { tint } from './LabelTint';\n\nexport type BadgeProps = Omit<NinnaBadgeProps, 'color' | 'size' | 'variant'> & {\n tone?: StatusTone | 'accent';\n /** A lar-brand app hue that colours the badge in place of its tone. */\n hue?: number;\n /** A tracker label's own colour, such as GitHub's, as a soft tint readable in both modes; anything but a colour\n * keeps the tone. */\n labelColor?: string | undefined;\n /** Dims the text to the muted colour, for an entry that is listed but switched off. */\n muted?: boolean;\n};\n\n/** T3 Code's badge: a 6px-radius label on an 8% tint of its tone, in the tone's foreground colour. */\nconst toneClasses: Record<NonNullable<BadgeProps['tone']>, string> = {\n neutral: 'bg-base-200 text-base-800 dark:bg-base-300 dark:text-base-800',\n accent: 'bg-primary/10 text-primary dark:bg-primary/20 dark:text-[color-mix(in_srgb,var(--color-primary)_55%,white)]',\n success: 'bg-success/10 text-(--lar-success-text) dark:bg-success/16',\n warning: 'bg-warning/12 text-(--lar-warning-text) dark:bg-warning/16',\n danger: 'bg-danger/10 text-(--lar-danger-text) dark:bg-danger/16',\n info: 'bg-info/10 text-(--lar-info-text) dark:bg-info/16',\n};\n\nexport function Badge({\n tone = 'neutral',\n hue,\n labelColor,\n muted = false,\n className = '',\n style,\n ...props\n}: BadgeProps) {\n const labelTint = tint(labelColor);\n\n return (\n <NinnaBadge\n {...props}\n color={tone === 'accent' ? 'primary' : tone}\n size=\"sm\"\n variant=\"soft\"\n style={\n hue !== undefined\n ? ({ ...style, '--lar-kind-hue': hue } as CSSProperties)\n : labelTint\n ? { ...style, ...labelTint }\n : style\n }\n className={`h-5 gap-1 rounded-sm px-1.5 text-xs font-medium [&>svg]:size-3 [&>svg]:shrink-0 ${hue === undefined ? toneClasses[tone] : 'kind-badge!'} ${muted ? 'text-(--muted-foreground)' : ''} ${className}`}\n />\n );\n}\n"],"mappings":";;;;;AAkBA,MAAM,cAA+D;CACjE,SAAS;CACT,QAAQ;CACR,SAAS;CACT,SAAS;CACT,QAAQ;CACR,MAAM;AACV;AAEA,SAAgBA,QAAM,EAClB,OAAO,WACP,KACA,YACA,QAAQ,OACR,YAAY,IACZ,OACA,GAAG,SACQ;CACX,MAAM,YAAY,KAAK,UAAU;CAEjC,OACI,oBAACC,OAAD;EACI,GAAI;EACJ,OAAO,SAAS,WAAW,YAAY;EACvC,MAAK;EACL,SAAQ;EACR,OACI,QAAQ,KAAA,IACD;GAAE,GAAG;GAAO,kBAAkB;EAAI,IACnC,YACE;GAAE,GAAG;GAAO,GAAG;EAAU,IACzB;EAEZ,WAAW,mFAAmF,QAAQ,KAAA,IAAY,YAAY,QAAQ,cAAc,GAAG,QAAQ,8BAA8B,GAAG,GAAG;CACtM,CAAA;AAET"}
@@ -1,6 +1,6 @@
1
1
  import { Text } from "../typography/Typography.js";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
2
  import { CheckIcon } from "lucide-react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
4
  // src/display/CheckList.tsx
5
5
  /** Short statements of what something does or includes, each with a check mark. */
6
6
  function CheckList({ items, label }) {
@@ -0,0 +1,12 @@
1
+ import { ReactNode } from "react";
2
+ /** The comments, newest first, one Comment each, such as a ticket's. */
3
+ export declare function CommentList({ children }: {
4
+ children: ReactNode;
5
+ }): import("react").JSX.Element;
6
+ /** A comment: its author's avatar beside a card with their name and `time` over the comment. */
7
+ export declare function Comment({ author, time, children }: {
8
+ author: string;
9
+ time: ReactNode;
10
+ children: ReactNode;
11
+ }): import("react").JSX.Element;
12
+ //# sourceMappingURL=Comment.d.ts.map
@@ -0,0 +1,39 @@
1
+ import { Avatar } from "./Avatar.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ // src/display/Comment.tsx
4
+ /** The comments, newest first, one Comment each, such as a ticket's. */
5
+ function CommentList({ children }) {
6
+ return /* @__PURE__ */ jsx("ol", {
7
+ className: "m-0 grid list-none grid-cols-[minmax(0,1fr)] gap-3 p-0",
8
+ children
9
+ });
10
+ }
11
+ /** A comment: its author's avatar beside a card with their name and `time` over the comment. */
12
+ function Comment({ author, time, children }) {
13
+ return /* @__PURE__ */ jsxs("li", {
14
+ className: "flex gap-3",
15
+ children: [/* @__PURE__ */ jsx(Avatar, {
16
+ name: author,
17
+ compact: true
18
+ }), /* @__PURE__ */ jsxs("div", {
19
+ className: "border-border bg-base-100 min-w-0 flex-1 rounded-lg border",
20
+ children: [/* @__PURE__ */ jsxs("div", {
21
+ className: "border-border flex items-center gap-2 border-b px-3 py-1.5 text-xs",
22
+ children: [/* @__PURE__ */ jsx("span", {
23
+ className: "font-medium",
24
+ "data-comment-author": true,
25
+ children: author
26
+ }), /* @__PURE__ */ jsx("span", {
27
+ className: "text-base-700",
28
+ children: time
29
+ })]
30
+ }), /* @__PURE__ */ jsx("div", {
31
+ className: "px-3 py-2",
32
+ children
33
+ })]
34
+ })]
35
+ });
36
+ }
37
+ export { Comment, CommentList };
38
+
39
+ //# sourceMappingURL=Comment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Comment.js","names":[],"sources":["../../src/display/Comment.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport { Avatar } from './Avatar';\n\n/** The comments, newest first, one Comment each, such as a ticket's. */\nexport function CommentList({ children }: { children: ReactNode }) {\n return <ol className=\"m-0 grid list-none grid-cols-[minmax(0,1fr)] gap-3 p-0\">{children}</ol>;\n}\n\n/** A comment: its author's avatar beside a card with their name and `time` over the comment. */\nexport function Comment({ author, time, children }: { author: string; time: ReactNode; children: ReactNode }) {\n return (\n <li className=\"flex gap-3\">\n <Avatar name={author} compact />\n <div className=\"border-border bg-base-100 min-w-0 flex-1 rounded-lg border\">\n <div className=\"border-border flex items-center gap-2 border-b px-3 py-1.5 text-xs\">\n <span className=\"font-medium\" data-comment-author>\n {author}\n </span>\n <span className=\"text-base-700\">{time}</span>\n </div>\n <div className=\"px-3 py-2\">{children}</div>\n </div>\n </li>\n );\n}\n"],"mappings":";;;;AAKA,SAAgB,YAAY,EAAE,YAAqC;CAC/D,OAAO,oBAAC,MAAD;EAAI,WAAU;EAA0D;CAAa,CAAA;AAChG;;AAGA,SAAgB,QAAQ,EAAE,QAAQ,MAAM,YAAsE;CAC1G,OACI,qBAAC,MAAD;EAAI,WAAU;EAAd,UAAA,CACI,oBAAC,QAAD;GAAQ,MAAM;GAAQ,SAAA;EAAS,CAAA,GAC/B,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACI,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACI,oBAAC,QAAD;KAAM,WAAU;KAAc,uBAAA;KACzB,UAAA;IACC,CAAA,GACN,oBAAC,QAAD;KAAM,WAAU;KAAiB,UAAA;IAAW,CAAA,CAC3C;GACL,CAAA,GAAA,oBAAC,OAAD;IAAK,WAAU;IAAa;GAAc,CAAA,CACzC;EACL,CAAA,CAAA;;AAEZ"}
@@ -2,8 +2,16 @@ interface CopyButtonProps {
2
2
  copiedLabel: string;
3
3
  label: string;
4
4
  value: string;
5
+ /** `icon` is a copy icon that turns into a tick; `text` is a compact button that reads `copyText`, then
6
+ * `copiedLabel`, as a dense tool's Copy beside a command. */
7
+ presentation?: 'icon' | 'text';
8
+ /** The text presentation's word before a copy, such as "Copy"; `label` stays its accessible name. */
9
+ copyText?: string;
10
+ /** Called after each copy, such as to announce it in a live region. */
11
+ onCopied?: () => void;
5
12
  }
6
- /** The LAN admin also runs over HTTP, where the async clipboard API is unavailable. */
7
- export declare function CopyButton({ copiedLabel, label, value }: CopyButtonProps): import("react").JSX.Element;
13
+ /** Copies `value`. The LAN admin also runs over HTTP, where the async clipboard API is unavailable, so it falls back
14
+ * to a selected textarea. */
15
+ export declare function CopyButton({ copiedLabel, label, value, presentation, copyText, onCopied }: CopyButtonProps): import("react").JSX.Element;
8
16
  export {};
9
17
  //# sourceMappingURL=CopyButton.d.ts.map
@@ -1,11 +1,13 @@
1
+ import { Button } from "../actions/Button.js";
1
2
  import { IconButton } from "../actions/IconButton.js";
2
3
  import { useEffect, useState } from "react";
3
- import { jsx } from "react/jsx-runtime";
4
4
  import { CheckIcon, CopyIcon } from "lucide-react";
5
+ import { jsx } from "react/jsx-runtime";
5
6
  // src/display/CopyButton.tsx
6
7
  const COPIED_FEEDBACK_MS = 1500;
7
- /** The LAN admin also runs over HTTP, where the async clipboard API is unavailable. */
8
- function CopyButton({ copiedLabel, label, value }) {
8
+ /** Copies `value`. The LAN admin also runs over HTTP, where the async clipboard API is unavailable, so it falls back
9
+ * to a selected textarea. */
10
+ function CopyButton({ copiedLabel, label, value, presentation = "icon", copyText = label, onCopied }) {
9
11
  const [copiedValue, setCopiedValue] = useState(null);
10
12
  const [copying, setCopying] = useState(false);
11
13
  const copied = copiedValue === value;
@@ -14,24 +16,35 @@ function CopyButton({ copiedLabel, label, value }) {
14
16
  const timer = window.setTimeout(() => setCopiedValue(null), COPIED_FEEDBACK_MS);
15
17
  return () => window.clearTimeout(timer);
16
18
  }, [copiedValue]);
19
+ const copy = async () => {
20
+ setCopying(true);
21
+ let done = false;
22
+ try {
23
+ if (navigator.clipboard) {
24
+ await navigator.clipboard.writeText(value);
25
+ done = true;
26
+ } else done = copySelection(value);
27
+ } catch {
28
+ done = copySelection(value);
29
+ } finally {
30
+ setCopiedValue(done ? value : null);
31
+ setCopying(false);
32
+ }
33
+ if (done) onCopied?.();
34
+ };
35
+ if (presentation === "text") return /* @__PURE__ */ jsx(Button, {
36
+ variant: "secondary",
37
+ compact: true,
38
+ "aria-label": label,
39
+ onClick: () => void copy(),
40
+ children: copied ? copiedLabel : copyText
41
+ });
17
42
  return /* @__PURE__ */ jsx(IconButton, {
18
43
  icon: copied ? /* @__PURE__ */ jsx(CheckIcon, {}) : /* @__PURE__ */ jsx(CopyIcon, {}),
19
44
  "aria-label": copied ? copiedLabel : label,
20
45
  title: copied ? copiedLabel : label,
21
46
  loading: copying,
22
- onClick: async () => {
23
- setCopying(true);
24
- try {
25
- if (navigator.clipboard) {
26
- await navigator.clipboard.writeText(value);
27
- setCopiedValue(value);
28
- } else setCopiedValue(copySelection(value) ? value : null);
29
- } catch {
30
- setCopiedValue(copySelection(value) ? value : null);
31
- } finally {
32
- setCopying(false);
33
- }
34
- },
47
+ onClick: copy,
35
48
  tone: copied ? "success" : "neutral"
36
49
  });
37
50
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CopyButton.js","names":[],"sources":["../../src/display/CopyButton.tsx"],"sourcesContent":["import { CheckIcon, CopyIcon } from 'lucide-react';\nimport { useEffect, useState } from 'react';\n\nimport { IconButton } from '../actions/IconButton';\n\nconst COPIED_FEEDBACK_MS = 1500;\n\ninterface CopyButtonProps {\n copiedLabel: string;\n label: string;\n value: string;\n}\n\n/** The LAN admin also runs over HTTP, where the async clipboard API is unavailable. */\nexport function CopyButton({ copiedLabel, label, value }: CopyButtonProps) {\n const [copiedValue, setCopiedValue] = useState<string | null>(null);\n const [copying, setCopying] = useState(false);\n const copied = copiedValue === value;\n\n useEffect(() => {\n if (copiedValue === null) return undefined;\n\n const timer = window.setTimeout(() => setCopiedValue(null), COPIED_FEEDBACK_MS);\n\n return () => window.clearTimeout(timer);\n }, [copiedValue]);\n\n return (\n <IconButton\n icon={copied ? <CheckIcon /> : <CopyIcon />}\n aria-label={copied ? copiedLabel : label}\n title={copied ? copiedLabel : label}\n loading={copying}\n onClick={async () => {\n setCopying(true);\n\n try {\n if (navigator.clipboard) {\n await navigator.clipboard.writeText(value);\n setCopiedValue(value);\n } else {\n setCopiedValue(copySelection(value) ? value : null);\n }\n } catch {\n setCopiedValue(copySelection(value) ? value : null);\n } finally {\n setCopying(false);\n }\n }}\n tone={copied ? 'success' : 'neutral'}\n />\n );\n}\n\nfunction copySelection(value: string): boolean {\n if (typeof document.execCommand !== 'function') return false;\n\n const previousFocus = document.activeElement;\n const input = document.createElement('textarea');\n\n input.value = value;\n input.readOnly = true;\n input.className = 'fixed -left-full top-0 opacity-0';\n document.body.append(input);\n input.focus({ preventScroll: true });\n input.select();\n\n try {\n return document.execCommand('copy');\n } catch {\n return false;\n } finally {\n input.remove();\n\n if (previousFocus instanceof HTMLElement) previousFocus.focus();\n }\n}\n"],"mappings":";;;;;AAKA,MAAM,qBAAqB;;AAS3B,SAAgB,WAAW,EAAE,aAAa,OAAO,SAA0B;CACvE,MAAM,CAAC,aAAa,kBAAkB,SAAwB,IAAI;CAClE,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,SAAS,gBAAgB;CAE/B,gBAAgB;EACZ,IAAI,gBAAgB,MAAM,OAAO,KAAA;EAEjC,MAAM,QAAQ,OAAO,iBAAiB,eAAe,IAAI,GAAG,kBAAkB;EAE9E,aAAa,OAAO,aAAa,KAAK;CAC1C,GAAG,CAAC,WAAW,CAAC;CAEhB,OACI,oBAAC,YAAD;EACI,MAAM,SAAS,oBAAC,WAAD,CAAY,CAAA,IAAI,oBAAC,UAAD,CAAW,CAAA;EAC1C,cAAY,SAAS,cAAc;EACnC,OAAO,SAAS,cAAc;EAC9B,SAAS;EACT,SAAS,YAAY;GACjB,WAAW,IAAI;GAEf,IAAI;IACA,IAAI,UAAU,WAAW;KACrB,MAAM,UAAU,UAAU,UAAU,KAAK;KACzC,eAAe,KAAK;IACxB,OACI,eAAe,cAAc,KAAK,IAAI,QAAQ,IAAI;GAE1D,QAAQ;IACJ,eAAe,cAAc,KAAK,IAAI,QAAQ,IAAI;GACtD,UAAU;IACN,WAAW,KAAK;GACpB;EACJ;EACA,MAAM,SAAS,YAAY;CAC9B,CAAA;AAET;AAEA,SAAS,cAAc,OAAwB;CAC3C,IAAI,OAAO,SAAS,gBAAgB,YAAY,OAAO;CAEvD,MAAM,gBAAgB,SAAS;CAC/B,MAAM,QAAQ,SAAS,cAAc,UAAU;CAE/C,MAAM,QAAQ;CACd,MAAM,WAAW;CACjB,MAAM,YAAY;CAClB,SAAS,KAAK,OAAO,KAAK;CAC1B,MAAM,MAAM,EAAE,eAAe,KAAK,CAAC;CACnC,MAAM,OAAO;CAEb,IAAI;EACA,OAAO,SAAS,YAAY,MAAM;CACtC,QAAQ;EACJ,OAAO;CACX,UAAU;EACN,MAAM,OAAO;EAEb,IAAI,yBAAyB,aAAa,cAAc,MAAM;CAClE;AACJ"}
1
+ {"version":3,"file":"CopyButton.js","names":[],"sources":["../../src/display/CopyButton.tsx"],"sourcesContent":["import { CheckIcon, CopyIcon } from 'lucide-react';\nimport { useEffect, useState } from 'react';\n\nimport { Button } from '../actions/Button';\nimport { IconButton } from '../actions/IconButton';\n\nconst COPIED_FEEDBACK_MS = 1500;\n\ninterface CopyButtonProps {\n copiedLabel: string;\n label: string;\n value: string;\n /** `icon` is a copy icon that turns into a tick; `text` is a compact button that reads `copyText`, then\n * `copiedLabel`, as a dense tool's Copy beside a command. */\n presentation?: 'icon' | 'text';\n /** The text presentation's word before a copy, such as \"Copy\"; `label` stays its accessible name. */\n copyText?: string;\n /** Called after each copy, such as to announce it in a live region. */\n onCopied?: () => void;\n}\n\n/** Copies `value`. The LAN admin also runs over HTTP, where the async clipboard API is unavailable, so it falls back\n * to a selected textarea. */\nexport function CopyButton({\n copiedLabel,\n label,\n value,\n presentation = 'icon',\n copyText = label,\n onCopied,\n}: CopyButtonProps) {\n const [copiedValue, setCopiedValue] = useState<string | null>(null);\n const [copying, setCopying] = useState(false);\n const copied = copiedValue === value;\n\n useEffect(() => {\n if (copiedValue === null) return undefined;\n\n const timer = window.setTimeout(() => setCopiedValue(null), COPIED_FEEDBACK_MS);\n\n return () => window.clearTimeout(timer);\n }, [copiedValue]);\n\n const copy = async () => {\n setCopying(true);\n\n let done = false;\n\n try {\n if (navigator.clipboard) {\n await navigator.clipboard.writeText(value);\n done = true;\n } else {\n done = copySelection(value);\n }\n } catch {\n done = copySelection(value);\n } finally {\n setCopiedValue(done ? value : null);\n setCopying(false);\n }\n\n if (done) onCopied?.();\n };\n\n if (presentation === 'text')\n return (\n <Button variant=\"secondary\" compact aria-label={label} onClick={() => void copy()}>\n {copied ? copiedLabel : copyText}\n </Button>\n );\n\n return (\n <IconButton\n icon={copied ? <CheckIcon /> : <CopyIcon />}\n aria-label={copied ? copiedLabel : label}\n title={copied ? copiedLabel : label}\n loading={copying}\n onClick={copy}\n tone={copied ? 'success' : 'neutral'}\n />\n );\n}\n\nfunction copySelection(value: string): boolean {\n if (typeof document.execCommand !== 'function') return false;\n\n const previousFocus = document.activeElement;\n const input = document.createElement('textarea');\n\n input.value = value;\n input.readOnly = true;\n input.className = 'fixed -left-full top-0 opacity-0';\n document.body.append(input);\n input.focus({ preventScroll: true });\n input.select();\n\n try {\n return document.execCommand('copy');\n } catch {\n return false;\n } finally {\n input.remove();\n\n if (previousFocus instanceof HTMLElement) previousFocus.focus();\n }\n}\n"],"mappings":";;;;;;AAMA,MAAM,qBAAqB;;;AAiB3B,SAAgB,WAAW,EACvB,aACA,OACA,OACA,eAAe,QACf,WAAW,OACX,YACgB;CAChB,MAAM,CAAC,aAAa,kBAAkB,SAAwB,IAAI;CAClE,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,SAAS,gBAAgB;CAE/B,gBAAgB;EACZ,IAAI,gBAAgB,MAAM,OAAO,KAAA;EAEjC,MAAM,QAAQ,OAAO,iBAAiB,eAAe,IAAI,GAAG,kBAAkB;EAE9E,aAAa,OAAO,aAAa,KAAK;CAC1C,GAAG,CAAC,WAAW,CAAC;CAEhB,MAAM,OAAO,YAAY;EACrB,WAAW,IAAI;EAEf,IAAI,OAAO;EAEX,IAAI;GACA,IAAI,UAAU,WAAW;IACrB,MAAM,UAAU,UAAU,UAAU,KAAK;IACzC,OAAO;GACX,OACI,OAAO,cAAc,KAAK;EAElC,QAAQ;GACJ,OAAO,cAAc,KAAK;EAC9B,UAAU;GACN,eAAe,OAAO,QAAQ,IAAI;GAClC,WAAW,KAAK;EACpB;EAEA,IAAI,MAAM,WAAW;CACzB;CAEA,IAAI,iBAAiB,QACjB,OACI,oBAAC,QAAD;EAAQ,SAAQ;EAAY,SAAA;EAAQ,cAAY;EAAO,eAAe,KAAK,KAAK;EAC3E,UAAA,SAAS,cAAc;CACpB,CAAA;CAGhB,OACI,oBAAC,YAAD;EACI,MAAM,SAAS,oBAAC,WAAD,CAAY,CAAA,IAAI,oBAAC,UAAD,CAAW,CAAA;EAC1C,cAAY,SAAS,cAAc;EACnC,OAAO,SAAS,cAAc;EAC9B,SAAS;EACT,SAAS;EACT,MAAM,SAAS,YAAY;CAC9B,CAAA;AAET;AAEA,SAAS,cAAc,OAAwB;CAC3C,IAAI,OAAO,SAAS,gBAAgB,YAAY,OAAO;CAEvD,MAAM,gBAAgB,SAAS;CAC/B,MAAM,QAAQ,SAAS,cAAc,UAAU;CAE/C,MAAM,QAAQ;CACd,MAAM,WAAW;CACjB,MAAM,YAAY;CAClB,SAAS,KAAK,OAAO,KAAK;CAC1B,MAAM,MAAM,EAAE,eAAe,KAAK,CAAC;CACnC,MAAM,OAAO;CAEb,IAAI;EACA,OAAO,SAAS,YAAY,MAAM;CACtC,QAAQ;EACJ,OAAO;CACX,UAAU;EACN,MAAM,OAAO;EAEb,IAAI,yBAAyB,aAAa,cAAc,MAAM;CAClE;AACJ"}
@@ -0,0 +1,17 @@
1
+ interface DiagramProps {
2
+ /** The diagram's text, such as a Mermaid flowchart. */
3
+ source: string;
4
+ /** Draws `source` as an SVG document's markup; `id` is unique to this diagram. A rejection shows `failedLabel`. */
5
+ draw: (source: string, id: string) => Promise<string>;
6
+ /** The drawing's accessible name. */
7
+ label: string;
8
+ /** Shown in place of the drawing when `draw` fails. */
9
+ failedLabel: string;
10
+ /** The disclosure that shows the source under the drawing. */
11
+ sourceLabel: string;
12
+ }
13
+ /** A drawn diagram in a bordered figure, with its source under it in a disclosure. The SVG comes from `draw`, so the
14
+ * design system needs no diagram library; a drawing too wide for its figure scrolls inside it. */
15
+ export declare function Diagram({ source, draw, label, failedLabel, sourceLabel }: DiagramProps): import("react").JSX.Element;
16
+ export {};
17
+ //# sourceMappingURL=Diagram.d.ts.map
@@ -0,0 +1,49 @@
1
+ import { useEffect, useId, useRef, useState } from "react";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ // src/display/Diagram.tsx
4
+ /** A drawn diagram in a bordered figure, with its source under it in a disclosure. The SVG comes from `draw`, so the
5
+ * design system needs no diagram library; a drawing too wide for its figure scrolls inside it. */
6
+ function Diagram({ source, draw, label, failedLabel, sourceLabel }) {
7
+ const id = useId().replace(/[^a-zA-Z0-9]/g, "");
8
+ const host = useRef(null);
9
+ const [failed, setFailed] = useState(null);
10
+ useEffect(() => {
11
+ const drawn = new AbortController();
12
+ draw(source, id).then((svg) => {
13
+ if (!drawn.signal.aborted && host.current) host.current.innerHTML = svg;
14
+ }, () => {
15
+ if (!drawn.signal.aborted) setFailed(source);
16
+ });
17
+ return () => drawn.abort();
18
+ }, [
19
+ draw,
20
+ id,
21
+ source
22
+ ]);
23
+ return /* @__PURE__ */ jsxs("figure", {
24
+ className: "m-0 grid min-w-0 gap-2 rounded-lg border p-3",
25
+ "data-map-diagram": true,
26
+ children: [failed === source ? /* @__PURE__ */ jsx("p", {
27
+ role: "status",
28
+ className: "text-base-700 m-0 text-xs",
29
+ children: failedLabel
30
+ }) : /* @__PURE__ */ jsx("div", {
31
+ ref: host,
32
+ className: "overflow-auto [&_svg]:mx-auto [&_svg]:h-auto [&_svg]:max-w-full",
33
+ role: "img",
34
+ "aria-label": label
35
+ }), /* @__PURE__ */ jsxs("details", {
36
+ className: "text-base-700 text-xs",
37
+ children: [/* @__PURE__ */ jsx("summary", {
38
+ className: "cursor-pointer",
39
+ children: sourceLabel
40
+ }), /* @__PURE__ */ jsx("pre", {
41
+ className: "overflow-auto pt-2 whitespace-pre-wrap",
42
+ children: source
43
+ })]
44
+ })]
45
+ });
46
+ }
47
+ export { Diagram };
48
+
49
+ //# sourceMappingURL=Diagram.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Diagram.js","names":[],"sources":["../../src/display/Diagram.tsx"],"sourcesContent":["import { useEffect, useId, useRef, useState } from 'react';\n\ninterface DiagramProps {\n /** The diagram's text, such as a Mermaid flowchart. */\n source: string;\n /** Draws `source` as an SVG document's markup; `id` is unique to this diagram. A rejection shows `failedLabel`. */\n draw: (source: string, id: string) => Promise<string>;\n /** The drawing's accessible name. */\n label: string;\n /** Shown in place of the drawing when `draw` fails. */\n failedLabel: string;\n /** The disclosure that shows the source under the drawing. */\n sourceLabel: string;\n}\n\n/** A drawn diagram in a bordered figure, with its source under it in a disclosure. The SVG comes from `draw`, so the\n * design system needs no diagram library; a drawing too wide for its figure scrolls inside it. */\nexport function Diagram({ source, draw, label, failedLabel, sourceLabel }: DiagramProps) {\n const id = useId().replace(/[^a-zA-Z0-9]/g, '');\n const host = useRef<HTMLDivElement>(null);\n // The source the diagram failed on, so a new source draws afresh.\n const [failed, setFailed] = useState<string | null>(null);\n\n useEffect(() => {\n const drawn = new AbortController();\n\n draw(source, id).then(\n (svg) => {\n if (!drawn.signal.aborted && host.current) host.current.innerHTML = svg;\n },\n () => {\n if (!drawn.signal.aborted) setFailed(source);\n },\n );\n\n return () => drawn.abort();\n }, [draw, id, source]);\n\n return (\n <figure className=\"m-0 grid min-w-0 gap-2 rounded-lg border p-3\" data-map-diagram>\n {failed === source ? (\n <p role=\"status\" className=\"text-base-700 m-0 text-xs\">\n {failedLabel}\n </p>\n ) : (\n <div\n ref={host}\n className=\"overflow-auto [&_svg]:mx-auto [&_svg]:h-auto [&_svg]:max-w-full\"\n role=\"img\"\n aria-label={label}\n />\n )}\n <details className=\"text-base-700 text-xs\">\n <summary className=\"cursor-pointer\">{sourceLabel}</summary>\n <pre className=\"overflow-auto pt-2 whitespace-pre-wrap\">{source}</pre>\n </details>\n </figure>\n );\n}\n"],"mappings":";;;;;AAiBA,SAAgB,QAAQ,EAAE,QAAQ,MAAM,OAAO,aAAa,eAA6B;CACrF,MAAM,KAAK,MAAM,CAAC,CAAC,QAAQ,iBAAiB,EAAE;CAC9C,MAAM,OAAO,OAAuB,IAAI;CAExC,MAAM,CAAC,QAAQ,aAAa,SAAwB,IAAI;CAExD,gBAAgB;EACZ,MAAM,QAAQ,IAAI,gBAAgB;EAElC,KAAK,QAAQ,EAAE,CAAC,CAAC,MACZ,QAAQ;GACL,IAAI,CAAC,MAAM,OAAO,WAAW,KAAK,SAAS,KAAK,QAAQ,YAAY;EACxE,SACM;GACF,IAAI,CAAC,MAAM,OAAO,SAAS,UAAU,MAAM;EAC/C,CACJ;EAEA,aAAa,MAAM,MAAM;CAC7B,GAAG;EAAC;EAAM;EAAI;CAAM,CAAC;CAErB,OACI,qBAAC,UAAD;EAAQ,WAAU;EAA+C,oBAAA;EAAjE,UAAA,CACK,WAAW,SACR,oBAAC,KAAD;GAAG,MAAK;GAAS,WAAU;GACtB,UAAA;EACF,CAAA,IAEH,oBAAC,OAAD;GACI,KAAK;GACL,WAAU;GACV,MAAK;GACL,cAAY;EACf,CAAA,GAEL,qBAAC,WAAD;GAAS,WAAU;GAAnB,UAAA,CACI,oBAAC,WAAD;IAAS,WAAU;IAAkB,UAAA;GAAqB,CAAA,GAC1D,oBAAC,OAAD;IAAK,WAAU;IAA0C,UAAA;GAAY,CAAA,CAChE;EACL,CAAA,CAAA;;AAEhB"}
@@ -2,8 +2,8 @@ import { Button } from "../actions/Button.js";
2
2
  import { tabbable } from "../foundations/KeyboardFocus.js";
3
3
  import { Artwork } from "./Artwork.js";
4
4
  import { useRef, useState } from "react";
5
- import { jsx, jsxs } from "react/jsx-runtime";
6
5
  import { CheckIcon, Disc3Icon } from "lucide-react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
7
  // src/display/ImagePicker.tsx
8
8
  function ImagePicker({ label, header, children }) {
9
9
  return /* @__PURE__ */ jsxs("section", {
@@ -1,7 +1,7 @@
1
1
  import { Heading, Text } from "../typography/Typography.js";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import { ChevronRightIcon } from "lucide-react";
4
2
  import { Alert } from "@ninna-ui/feedback";
3
+ import { ChevronRightIcon } from "lucide-react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
5
  // src/display/InfoBox.tsx
6
6
  /**
7
7
  * A prominent, actionable introduction that opens optional guidance.
@@ -3,11 +3,13 @@ interface InsetPanelProps {
3
3
  children: ReactNode;
4
4
  onClick?: () => void;
5
5
  presentation?: 'default' | 'settings';
6
+ /** Under a `settings` panel's rows, on the muted surface: the group's own action, such as an add button. */
7
+ footer?: ReactNode;
6
8
  }
7
9
  /**
8
10
  * A neutral surface that groups related content without adding message or status meaning.
9
11
  * Use Alert for current status, InfoBox for optional guidance, and NoticeCard for a decision item.
10
12
  */
11
- export declare function InsetPanel({ children, onClick, presentation }: InsetPanelProps): import("react").JSX.Element;
13
+ export declare function InsetPanel({ children, onClick, presentation, footer }: InsetPanelProps): import("react").JSX.Element;
12
14
  export {};
13
15
  //# sourceMappingURL=InsetPanel.d.ts.map
@@ -1,15 +1,18 @@
1
1
  import { tabbable } from "../foundations/KeyboardFocus.js";
2
2
  import { Stack } from "../layout/Flow.js";
3
- import { jsx } from "react/jsx-runtime";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
4
  // src/display/InsetPanel.tsx
5
5
  /**
6
6
  * A neutral surface that groups related content without adding message or status meaning.
7
7
  * Use Alert for current status, InfoBox for optional guidance, and NoticeCard for a decision item.
8
8
  */
9
- function InsetPanel({ children, onClick, presentation = "default" }) {
10
- if (presentation === "settings") return /* @__PURE__ */ jsx("div", {
9
+ function InsetPanel({ children, onClick, presentation = "default", footer }) {
10
+ if (presentation === "settings") return /* @__PURE__ */ jsxs("div", {
11
11
  className: "divide-base-300 border-base-300 bg-base-100 divide-y overflow-hidden rounded-lg border shadow-xs/5",
12
- children
12
+ children: [children, footer && /* @__PURE__ */ jsx("div", {
13
+ className: "rounded-b-xl bg-(--muted) px-4 py-2",
14
+ children: footer
15
+ })]
13
16
  });
14
17
  return /* @__PURE__ */ jsx(Stack, {
15
18
  as: onClick ? "button" : "div",
@@ -1 +1 @@
1
- {"version":3,"file":"InsetPanel.js","names":[],"sources":["../../src/display/InsetPanel.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport { tabbable } from '../foundations/KeyboardFocus';\nimport { Stack } from '../layout/Flow';\n\ninterface InsetPanelProps {\n children: ReactNode;\n onClick?: () => void;\n presentation?: 'default' | 'settings';\n}\n\n/**\n * A neutral surface that groups related content without adding message or status meaning.\n * Use Alert for current status, InfoBox for optional guidance, and NoticeCard for a decision item.\n */\nexport function InsetPanel({ children, onClick, presentation = 'default' }: InsetPanelProps) {\n if (presentation === 'settings') {\n return (\n <div className=\"divide-base-300 border-base-300 bg-base-100 divide-y overflow-hidden rounded-lg border shadow-xs/5\">\n {children}\n </div>\n );\n }\n\n return (\n <Stack\n as={onClick ? 'button' : 'div'}\n type={onClick ? 'button' : undefined}\n tabIndex={onClick ? tabbable.tabIndex : undefined}\n onClick={onClick}\n space=\"related\"\n className={`border-base-300 bg-base-100 rounded-lg border p-5 ${onClick ? 'focus-visible:outline-primary w-full cursor-pointer text-left focus-visible:outline-2 focus-visible:outline-offset-2' : ''}`}\n >\n {children}\n </Stack>\n );\n}\n"],"mappings":";;;;;;;;AAeA,SAAgB,WAAW,EAAE,UAAU,SAAS,eAAe,aAA8B;CACzF,IAAI,iBAAiB,YACjB,OACI,oBAAC,OAAD;EAAK,WAAU;EACV;CACA,CAAA;CAIb,OACI,oBAAC,OAAD;EACI,IAAI,UAAU,WAAW;EACzB,MAAM,UAAU,WAAW,KAAA;EAC3B,UAAU,UAAU,SAAS,WAAW,KAAA;EAC/B;EACT,OAAM;EACN,WAAW,qDAAqD,UAAU,yHAAyH;EAElM;CACE,CAAA;AAEf"}
1
+ {"version":3,"file":"InsetPanel.js","names":[],"sources":["../../src/display/InsetPanel.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport { tabbable } from '../foundations/KeyboardFocus';\nimport { Stack } from '../layout/Flow';\n\ninterface InsetPanelProps {\n children: ReactNode;\n onClick?: () => void;\n presentation?: 'default' | 'settings';\n /** Under a `settings` panel's rows, on the muted surface: the group's own action, such as an add button. */\n footer?: ReactNode;\n}\n\n/**\n * A neutral surface that groups related content without adding message or status meaning.\n * Use Alert for current status, InfoBox for optional guidance, and NoticeCard for a decision item.\n */\nexport function InsetPanel({ children, onClick, presentation = 'default', footer }: InsetPanelProps) {\n if (presentation === 'settings') {\n return (\n <div className=\"divide-base-300 border-base-300 bg-base-100 divide-y overflow-hidden rounded-lg border shadow-xs/5\">\n {children}\n {footer && <div className=\"rounded-b-xl bg-(--muted) px-4 py-2\">{footer}</div>}\n </div>\n );\n }\n\n return (\n <Stack\n as={onClick ? 'button' : 'div'}\n type={onClick ? 'button' : undefined}\n tabIndex={onClick ? tabbable.tabIndex : undefined}\n onClick={onClick}\n space=\"related\"\n className={`border-base-300 bg-base-100 rounded-lg border p-5 ${onClick ? 'focus-visible:outline-primary w-full cursor-pointer text-left focus-visible:outline-2 focus-visible:outline-offset-2' : ''}`}\n >\n {children}\n </Stack>\n );\n}\n"],"mappings":";;;;;;;;AAiBA,SAAgB,WAAW,EAAE,UAAU,SAAS,eAAe,WAAW,UAA2B;CACjG,IAAI,iBAAiB,YACjB,OACI,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACK,UACA,UAAU,oBAAC,OAAD;GAAK,WAAU;GAAuC,UAAA;EAAY,CAAA,CAC5E;;CAIb,OACI,oBAAC,OAAD;EACI,IAAI,UAAU,WAAW;EACzB,MAAM,UAAU,WAAW,KAAA;EAC3B,UAAU,UAAU,SAAS,WAAW,KAAA;EAC/B;EACT,OAAM;EACN,WAAW,qDAAqD,UAAU,yHAAyH;EAElM;CACE,CAAA;AAEf"}
@@ -1,6 +1,6 @@
1
- import { jsx } from "react/jsx-runtime";
2
- import { PencilIcon } from "lucide-react";
3
1
  import { Loading } from "@ninna-ui/feedback";
2
+ import { PencilIcon } from "lucide-react";
3
+ import { jsx } from "react/jsx-runtime";
4
4
  // src/display/ItemAction.tsx
5
5
  function ItemAction({ action, loading = false, loadingLabel }) {
6
6
  const disabled = loading || !action?.onClick;
@@ -0,0 +1,26 @@
1
+ import { ReactNode } from "react";
2
+ type DataAttributes = {
3
+ [key: `data-${string}`]: string | undefined;
4
+ };
5
+ interface LabelChipProps extends DataAttributes {
6
+ /** The label's name, truncating, which its tooltip gives whole. */
7
+ label: string;
8
+ /** The label's own colour, such as a tracker's, as Badge's `labelColor`; none keeps the neutral badge. */
9
+ color?: string | undefined;
10
+ /** Follows the name, faded, such as "new" for a label still to be created. */
11
+ note?: ReactNode;
12
+ /** A lock before the name, for a label that can't be edited here; `lockedLabel` says why. */
13
+ locked?: boolean;
14
+ lockedLabel?: string;
15
+ /** A × after the name, for a chip inside a control that removes it, such as an active filter's. */
16
+ removable?: boolean;
17
+ /** Its own × button, which `removeLabel` names, that removes the label. */
18
+ onRemove?: () => void;
19
+ removeLabel?: string;
20
+ disabled?: boolean;
21
+ }
22
+ /** A label as a chip in its own colour, such as a tracker's: its name truncating, then any note, and a lock or a × that
23
+ * removes it. */
24
+ export declare function LabelChip({ label, color, note, locked, lockedLabel, removable, onRemove, removeLabel, disabled, ...data }: LabelChipProps): import("react").JSX.Element;
25
+ export {};
26
+ //# sourceMappingURL=LabelChip.d.ts.map
@@ -0,0 +1,41 @@
1
+ import { Badge } from "./Badge.js";
2
+ import { LockIcon } from "lucide-react";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ // src/display/LabelChip.tsx
5
+ /** A label as a chip in its own colour, such as a tracker's: its name truncating, then any note, and a lock or a × that
6
+ * removes it. */
7
+ function LabelChip({ label, color, note, locked = false, lockedLabel, removable = false, onRemove, removeLabel, disabled = false, ...data }) {
8
+ return /* @__PURE__ */ jsxs(Badge, {
9
+ "data-label-chip": "",
10
+ ...data,
11
+ title: locked ? lockedLabel : void 0,
12
+ className: "max-w-full min-w-0",
13
+ labelColor: color,
14
+ children: [
15
+ locked && /* @__PURE__ */ jsx(LockIcon, { "aria-label": lockedLabel }),
16
+ /* @__PURE__ */ jsx("span", {
17
+ className: "max-w-52 truncate",
18
+ title: label,
19
+ children: label
20
+ }),
21
+ note && /* @__PURE__ */ jsxs(Fragment, { children: [" ", /* @__PURE__ */ jsx("span", {
22
+ className: "opacity-70",
23
+ children: note
24
+ })] }),
25
+ onRemove ? /* @__PURE__ */ jsx("button", {
26
+ type: "button",
27
+ className: "cursor-pointer bg-transparent p-0",
28
+ "aria-label": removeLabel,
29
+ disabled,
30
+ onClick: onRemove,
31
+ children: "×"
32
+ }) : removable && /* @__PURE__ */ jsx("span", {
33
+ "aria-hidden": "true",
34
+ children: "×"
35
+ })
36
+ ]
37
+ });
38
+ }
39
+ export { LabelChip };
40
+
41
+ //# sourceMappingURL=LabelChip.js.map