@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Loading.js","names":["Loading","NinnaLoading"],"sources":["../../src/feedback/Loading.tsx"],"sourcesContent":["import { Loading as NinnaLoading, type LoadingProps as NinnaLoadingProps } from '@ninna-ui/feedback';\nimport { LoaderCircleIcon, type LucideProps } from 'lucide-react';\nimport { forwardRef } from 'react';\n\nimport { ambientMotion } from '../foundations/AmbientMotion';\n\nconst motions = {\n spin: 'motion-safe:animate-spin',\n always: 'animate-spin',\n status: 'status-spin',\n still: '',\n} as const;\n\ntype SpinnerIconProps = LucideProps & {\n /** The spin: `spin` turns unless the user prefers reduced motion, `always` turns regardless, as a pending action's\n * does, `status` is a status glyph's own spin (its page defines `status-spin`), and `still` doesn't turn. */\n motion?: keyof typeof motions;\n};\n\n/**\n * The loader icon, spinning on a box around it: above a device scale of 1 Chromium can't run a root svg's transform on\n * the compositor, so the page would render every frame. It pauses while out of view or in a hidden window.\n */\nexport function SpinnerIcon({ motion = 'spin', ...icon }: SpinnerIconProps) {\n const spin = motions[motion];\n\n return (\n <span ref={spin ? ambientMotion : undefined} className={`flex w-fit shrink-0 ${spin}`}>\n <LoaderCircleIcon {...icon} />\n </span>\n );\n}\n\ntype LoadingProps = Omit<NinnaLoadingProps, 'title'> & {\n /** What loads. Without a `presentation` it names ninna-ui's spinner for screen readers only; with one it shows\n * beside the spinner. */\n label?: string;\n /** With no label, names the spinner alone, as a cue beside values already shown. */\n title?: string | undefined;\n /** Stops it spinning. */\n still?: boolean;\n /** Without it, ninna-ui's announced spinner. `inline` is a small spinner and what loads in a line of 12px text;\n * `line` stands on its own line of body text; `status` is a step's own loading line, announced, muted body text\n * with room above and below that keeps turning as a pending action's spinner does. */\n presentation?: 'inline' | 'line' | 'status';\n};\n\n/** What shows in place of something still loading: ninna-ui's announced spinner, or with a `presentation`, a small\n * spinner, still under reduced motion, and what loads. */\nexport const Loading = forwardRef<HTMLDivElement, LoadingProps>(\n ({ presentation, label, title, still = false, ...props }, ref) => {\n if (!presentation) return <NinnaLoading ref={ref} label={label} title={title} {...props} />;\n\n if (presentation === 'status')\n return (\n <p role=\"status\" className=\"text-base-700 m-0 flex items-center gap-2 py-4 text-sm\">\n <SpinnerIcon motion={still ? 'still' : 'always'} aria-hidden=\"true\" className=\"size-4\" />\n {label}\n </p>\n );\n\n return (\n <span data-loader className=\"inline-flex min-w-0 items-center gap-1.5\" title={title}>\n <SpinnerIcon\n motion={still ? 'still' : 'spin'}\n aria-hidden=\"true\"\n className={presentation === 'line' ? 'size-4' : 'size-3'}\n />\n {label ? <span className=\"truncate\">{label}</span> : title && <span className=\"sr-only\">{title}</span>}\n </span>\n );\n },\n);\n\nLoading.displayName = 'Loading';\n"],"mappings":";;;;;;AAMA,MAAM,UAAU;CACZ,MAAM;CACN,QAAQ;CACR,QAAQ;CACR,OAAO;AACX;;;;;AAYA,SAAgB,YAAY,EAAE,SAAS,QAAQ,GAAG,QAA0B;CACxE,MAAM,OAAO,QAAQ;CAErB,OACI,oBAAC,QAAD;EAAM,KAAK,OAAO,gBAAgB,KAAA;EAAW,WAAW,uBAAuB;EAC3E,UAAA,oBAAC,kBAAD,EAAkB,GAAI,KAAO,CAAA;CAC3B,CAAA;AAEd;;;AAkBA,MAAaA,YAAU,YAClB,EAAE,cAAc,OAAO,OAAO,QAAQ,OAAO,GAAG,SAAS,QAAQ;CAC9D,IAAI,CAAC,cAAc,OAAO,oBAACC,SAAD;EAAmB;EAAY;EAAc;EAAO,GAAI;CAAQ,CAAA;CAE1F,IAAI,iBAAiB,UACjB,OACI,qBAAC,KAAD;EAAG,MAAK;EAAS,WAAU;EAA3B,UAAA,CACI,oBAAC,aAAD;GAAa,QAAQ,QAAQ,UAAU;GAAU,eAAY;GAAO,WAAU;EAAU,CAAA,GACvF,KACF;;CAGX,OACI,qBAAC,QAAD;EAAM,eAAA;EAAY,WAAU;EAAkD;EAA9E,UAAA,CACI,oBAAC,aAAD;GACI,QAAQ,QAAQ,UAAU;GAC1B,eAAY;GACZ,WAAW,iBAAiB,SAAS,WAAW;EACnD,CAAA,GACA,QAAQ,oBAAC,QAAD;GAAM,WAAU;GAAY,UAAA;EAAY,CAAA,IAAI,SAAS,oBAAC,QAAD;GAAM,WAAU;GAAW,UAAA;EAAY,CAAA,CACnG;;AAEd,CACJ;AAEA,UAAQ,cAAc"}
@@ -1,2 +1,36 @@
1
- export declare function Notifications(): import("react").JSX.Element;
1
+ import { ReactNode } from "react";
2
+ /**
3
+ * The page's notifications. `corner` shows a few at a time in the bottom right corner. `stack` keeps every one, oldest
4
+ * above the newest, above every dialog: when they don't fit, the stack scrolls, follows the newest while you are at the
5
+ * bottom, and fades those scrolled past at its edges, as a Modal's body does. Mount one, once, outside the page's root.
6
+ */
7
+ export declare function Notifications({ presentation }: {
8
+ presentation?: 'corner' | 'stack';
9
+ }): import("react").JSX.Element;
10
+ export interface Notification {
11
+ /** One notification per slot: a new one replaces the last. */
12
+ slot: string;
13
+ /** A failure is red and stays until it's closed; a success is green and clears itself five seconds after the
14
+ * pointer and the keyboard focus leave it. */
15
+ tone?: 'success' | 'danger';
16
+ /** Names the close button, such as "Dismiss: Moved #61". */
17
+ dismissLabel: string;
18
+ /** What it says: text, links and buttons. */
19
+ body: ReactNode;
20
+ /** Called after it closes while the keyboard focus was inside it, to put the focus somewhere useful. */
21
+ onFocusLost?: () => void;
22
+ }
23
+ interface NotificationControls {
24
+ /** Keeps a success from clearing itself while `held`, such as while an action it offers is under way. */
25
+ hold: (held: boolean) => void;
26
+ /** Shows a success as a failure while `failed`, such as when an action it offers failed. */
27
+ fail: (failed: boolean) => void;
28
+ }
29
+ /** For a notification's body: what it can change about the notification it sits in. */
30
+ export declare function useNotificationControls(): NotificationControls;
31
+ /** Shows `notification` in its slot, replacing the one there. */
32
+ export declare function showNotification(notification: Notification): void;
33
+ /** Closes whatever notification holds this slot. */
34
+ export declare function clearNotification(slot: string): void;
35
+ export {};
2
36
  //# sourceMappingURL=Notifications.d.ts.map
@@ -1,9 +1,201 @@
1
- import { jsx } from "react/jsx-runtime";
2
- import { Toaster } from "@ninna-ui/feedback";
1
+ import { DismissButton } from "./DismissButton.js";
2
+ import { createContext, useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
3
+ import { Toaster, toast } from "@ninna-ui/feedback";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { flushSync } from "react-dom";
3
6
  // src/feedback/Notifications.tsx
4
- function Notifications() {
7
+ /** How long a success stays once the pointer and the focus have left it. */
8
+ const SUCCESS_MS = 5e3;
9
+ /** Each notification's fade, as wide as a Modal body's: notifications scrolled past fade out at the stack's edges. */
10
+ const FADE_PX = 24;
11
+ /**
12
+ * The page's notifications. `corner` shows a few at a time in the bottom right corner. `stack` keeps every one, oldest
13
+ * above the newest, above every dialog: when they don't fit, the stack scrolls, follows the newest while you are at the
14
+ * bottom, and fades those scrolled past at its edges, as a Modal's body does. Mount one, once, outside the page's root.
15
+ */
16
+ function Notifications({ presentation = "corner" }) {
17
+ if (presentation === "stack") return /* @__PURE__ */ jsx(Toaster, {
18
+ ref: followNewest,
19
+ position: "bottom-right",
20
+ max: Infinity,
21
+ className: "notification-stack",
22
+ offset: "calc(var(--spacing) * 1)"
23
+ });
5
24
  return /* @__PURE__ */ jsx(Toaster, { position: "bottom-right" });
6
25
  }
7
- export { Notifications };
26
+ /**
27
+ * Follows the newest notification while the user is at the bottom: a new entry, a narrower or shorter window and a
28
+ * notification growing all keep it in view. Once the user scrolls away the stack stays where they left it, until they
29
+ * scroll back. Each notification carries its own slice of the edge fade: a mask on the stack would make it the
30
+ * notifications' backdrop root and cut their blur off from the page behind.
31
+ */
32
+ function followNewest(viewport) {
33
+ if (!viewport) return;
34
+ let following = true;
35
+ const entries = () => Array.from(viewport.children).filter((el) => el instanceof HTMLElement);
36
+ const fade = () => {
37
+ const { scrollTop, scrollHeight, clientHeight } = viewport;
38
+ const stack = viewport.getBoundingClientRect();
39
+ const top = Math.min(FADE_PX, Math.max(0, scrollTop));
40
+ const bottom = Math.min(FADE_PX, Math.max(0, scrollHeight - clientHeight - scrollTop));
41
+ for (const entry of entries()) {
42
+ const y = entry.getBoundingClientRect().top - stack.top;
43
+ entry.style.setProperty("--fade-from", `${-y}px`);
44
+ entry.style.setProperty("--fade-top", `${top - y}px`);
45
+ entry.style.setProperty("--fade-bottom", `${stack.height - bottom - y}px`);
46
+ entry.style.setProperty("--fade-to", `${stack.height - y}px`);
47
+ }
48
+ };
49
+ const toNewest = () => {
50
+ if (following) viewport.scrollTop = viewport.scrollHeight;
51
+ fade();
52
+ };
53
+ const scrolled = () => {
54
+ following = viewport.scrollHeight - viewport.clientHeight - viewport.scrollTop <= 1;
55
+ fade();
56
+ };
57
+ const resizes = new ResizeObserver(toNewest);
58
+ const observe = () => {
59
+ resizes.disconnect();
60
+ resizes.observe(viewport);
61
+ entries().forEach((entry) => resizes.observe(entry));
62
+ };
63
+ const arrivals = new MutationObserver((changes) => {
64
+ observe();
65
+ const newest = viewport.lastElementChild;
66
+ if (changes.some(({ addedNodes }) => Array.from(addedNodes).includes(newest))) toNewest();
67
+ else fade();
68
+ });
69
+ arrivals.observe(viewport, { childList: true });
70
+ viewport.addEventListener("scroll", scrolled, { passive: true });
71
+ viewport.addEventListener("animationend", fade);
72
+ viewport.addEventListener("transitionend", fade);
73
+ observe();
74
+ toNewest();
75
+ return () => {
76
+ arrivals.disconnect();
77
+ resizes.disconnect();
78
+ viewport.removeEventListener("scroll", scrolled);
79
+ viewport.removeEventListener("animationend", fade);
80
+ viewport.removeEventListener("transitionend", fade);
81
+ };
82
+ }
83
+ const Controls = createContext({
84
+ hold: () => {},
85
+ fail: () => {}
86
+ });
87
+ /** For a notification's body: what it can change about the notification it sits in. */
88
+ function useNotificationControls() {
89
+ return useContext(Controls);
90
+ }
91
+ /** The id of the notification in each slot, in the toast manager. */
92
+ const slots = /* @__PURE__ */ new Map();
93
+ /** Forgets every slot, as the toasts they named are gone. */
94
+ function forgetNotificationSlots() {
95
+ slots.clear();
96
+ }
97
+ /** Closes the notification `id` in `slot`; if the focus was in it, `onFocusLost` puts it somewhere else. */
98
+ function close(slot, id, onFocusLost) {
99
+ const hadFocus = Boolean(document.querySelector(`[data-toast-id="${id}"]`)?.contains(document.activeElement));
100
+ flushSync(() => {
101
+ if (slots.get(slot) === id) slots.delete(slot);
102
+ toast.dismiss(id);
103
+ });
104
+ if (hadFocus) onFocusLost?.();
105
+ }
106
+ /** Shows `notification` in its slot, replacing the one there. */
107
+ function showNotification(notification) {
108
+ clearNotification(notification.slot);
109
+ const id = toast.create({
110
+ color: notification.tone === "danger" ? "danger" : "success",
111
+ duration: 0,
112
+ closable: false,
113
+ description: /* @__PURE__ */ jsx(NotificationBody, {
114
+ ...notification,
115
+ onClose: () => close(notification.slot, id, notification.onFocusLost)
116
+ })
117
+ });
118
+ slots.set(notification.slot, id);
119
+ }
120
+ /** Closes whatever notification holds this slot. */
121
+ function clearNotification(slot) {
122
+ const id = slots.get(slot);
123
+ if (id) close(slot, id);
124
+ }
125
+ /** Gives a success five seconds after hover and keyboard focus leave it. */
126
+ function useSuccessClose(ref, enabled, onClose) {
127
+ const latest = useRef(onClose);
128
+ useLayoutEffect(() => {
129
+ latest.current = onClose;
130
+ });
131
+ useEffect(() => {
132
+ if (!enabled) return;
133
+ const entry = ref.current?.closest("[data-slot=\"toast\"]");
134
+ if (!entry) return;
135
+ const held = {
136
+ hovered: entry.matches(":hover"),
137
+ focused: entry.contains(document.activeElement),
138
+ timer: void 0
139
+ };
140
+ const restart = () => {
141
+ clearTimeout(held.timer);
142
+ if (!held.hovered && !held.focused) held.timer = setTimeout(() => latest.current(), SUCCESS_MS);
143
+ };
144
+ const enter = () => {
145
+ held.hovered = true;
146
+ restart();
147
+ };
148
+ const leave = () => {
149
+ held.hovered = false;
150
+ restart();
151
+ };
152
+ const focus = () => {
153
+ held.focused = true;
154
+ restart();
155
+ };
156
+ const blur = (event) => {
157
+ held.focused = event.relatedTarget instanceof Node && entry.contains(event.relatedTarget);
158
+ restart();
159
+ };
160
+ entry.addEventListener("mouseenter", enter);
161
+ entry.addEventListener("mouseleave", leave);
162
+ entry.addEventListener("focusin", focus);
163
+ entry.addEventListener("focusout", blur);
164
+ restart();
165
+ return () => {
166
+ clearTimeout(held.timer);
167
+ entry.removeEventListener("mouseenter", enter);
168
+ entry.removeEventListener("mouseleave", leave);
169
+ entry.removeEventListener("focusin", focus);
170
+ entry.removeEventListener("focusout", blur);
171
+ };
172
+ }, [enabled, ref]);
173
+ }
174
+ /** One notification's content. `onClose` runs when its close button is clicked or, for a success, when its time is up. */
175
+ function NotificationBody({ slot, dismissLabel, tone = "success", body, onClose }) {
176
+ const ref = useRef(null);
177
+ const [held, setHeld] = useState(false);
178
+ const [bodyFailed, setBodyFailed] = useState(false);
179
+ const failed = tone === "danger" || bodyFailed;
180
+ useEffect(() => {
181
+ ref.current?.closest("[data-slot=\"toast\"]")?.setAttribute("data-toast-color", failed ? "danger" : "success");
182
+ }, [failed]);
183
+ useSuccessClose(ref, !failed && !held, onClose);
184
+ return /* @__PURE__ */ jsxs("span", {
185
+ ref,
186
+ "data-toast": slot,
187
+ children: [/* @__PURE__ */ jsx(DismissButton, {
188
+ label: dismissLabel,
189
+ onClick: onClose
190
+ }), /* @__PURE__ */ jsx(Controls.Provider, {
191
+ value: {
192
+ hold: setHeld,
193
+ fail: setBodyFailed
194
+ },
195
+ children: body
196
+ })]
197
+ });
198
+ }
199
+ export { Notifications, clearNotification, forgetNotificationSlots, showNotification, useNotificationControls };
8
200
 
9
201
  //# sourceMappingURL=Notifications.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Notifications.js","names":[],"sources":["../../src/feedback/Notifications.tsx"],"sourcesContent":["import { Toaster } from '@ninna-ui/feedback';\n\nexport function Notifications() {\n return <Toaster position=\"bottom-right\" />;\n}\n"],"mappings":";;;AAEA,SAAgB,gBAAgB;CAC5B,OAAO,oBAAC,SAAD,EAAS,UAAS,eAAgB,CAAA;AAC7C"}
1
+ {"version":3,"file":"Notifications.js","names":[],"sources":["../../src/feedback/Notifications.tsx"],"sourcesContent":["/* oxlint-disable react/only-export-components -- The slot functions and the body's controls belong to the toaster. */\n\nimport { toast, Toaster } from '@ninna-ui/feedback';\nimport {\n createContext,\n type ReactNode,\n type RefObject,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport { flushSync } from 'react-dom';\n\nimport { DismissButton } from './DismissButton';\n\n/** How long a success stays once the pointer and the focus have left it. */\nconst SUCCESS_MS = 5_000;\n\n/** Each notification's fade, as wide as a Modal body's: notifications scrolled past fade out at the stack's edges. */\nconst FADE_PX = 24;\n\n/**\n * The page's notifications. `corner` shows a few at a time in the bottom right corner. `stack` keeps every one, oldest\n * above the newest, above every dialog: when they don't fit, the stack scrolls, follows the newest while you are at the\n * bottom, and fades those scrolled past at its edges, as a Modal's body does. Mount one, once, outside the page's root.\n */\nexport function Notifications({ presentation = 'corner' }: { presentation?: 'corner' | 'stack' }) {\n if (presentation === 'stack')\n return (\n <Toaster\n ref={followNewest}\n position=\"bottom-right\"\n max={Infinity}\n className=\"notification-stack\"\n offset=\"calc(var(--spacing) * 1)\"\n />\n );\n\n return <Toaster position=\"bottom-right\" />;\n}\n\n/**\n * Follows the newest notification while the user is at the bottom: a new entry, a narrower or shorter window and a\n * notification growing all keep it in view. Once the user scrolls away the stack stays where they left it, until they\n * scroll back. Each notification carries its own slice of the edge fade: a mask on the stack would make it the\n * notifications' backdrop root and cut their blur off from the page behind.\n */\nfunction followNewest(viewport: HTMLDivElement | null) {\n if (!viewport) return;\n\n let following = true;\n const entries = () => Array.from(viewport.children).filter((el): el is HTMLElement => el instanceof HTMLElement);\n const fade = () => {\n const { scrollTop, scrollHeight, clientHeight } = viewport;\n const stack = viewport.getBoundingClientRect();\n const top = Math.min(FADE_PX, Math.max(0, scrollTop));\n const bottom = Math.min(FADE_PX, Math.max(0, scrollHeight - clientHeight - scrollTop));\n\n for (const entry of entries()) {\n const y = entry.getBoundingClientRect().top - stack.top;\n\n entry.style.setProperty('--fade-from', `${-y}px`);\n entry.style.setProperty('--fade-top', `${top - y}px`);\n entry.style.setProperty('--fade-bottom', `${stack.height - bottom - y}px`);\n entry.style.setProperty('--fade-to', `${stack.height - y}px`);\n }\n };\n const toNewest = () => {\n if (following) viewport.scrollTop = viewport.scrollHeight;\n\n fade();\n };\n const scrolled = () => {\n following = viewport.scrollHeight - viewport.clientHeight - viewport.scrollTop <= 1;\n fade();\n };\n const resizes = new ResizeObserver(toNewest);\n const observe = () => {\n resizes.disconnect();\n resizes.observe(viewport);\n entries().forEach((entry) => resizes.observe(entry));\n };\n const arrivals = new MutationObserver((changes) => {\n observe();\n\n const newest = viewport.lastElementChild;\n const arrived = changes.some(({ addedNodes }) => Array.from(addedNodes).includes(newest as Node));\n\n // Only a new entry moves the stack; one closing or changing above leaves the user where they are.\n if (arrived) toNewest();\n else fade();\n });\n\n arrivals.observe(viewport, { childList: true });\n viewport.addEventListener('scroll', scrolled, { passive: true });\n // Entering notifications slide in; measure them where they land.\n viewport.addEventListener('animationend', fade);\n viewport.addEventListener('transitionend', fade);\n observe();\n toNewest();\n\n return () => {\n arrivals.disconnect();\n resizes.disconnect();\n viewport.removeEventListener('scroll', scrolled);\n viewport.removeEventListener('animationend', fade);\n viewport.removeEventListener('transitionend', fade);\n };\n}\n\nexport interface Notification {\n /** One notification per slot: a new one replaces the last. */\n slot: string;\n /** A failure is red and stays until it's closed; a success is green and clears itself five seconds after the\n * pointer and the keyboard focus leave it. */\n tone?: 'success' | 'danger';\n /** Names the close button, such as \"Dismiss: Moved #61\". */\n dismissLabel: string;\n /** What it says: text, links and buttons. */\n body: ReactNode;\n /** Called after it closes while the keyboard focus was inside it, to put the focus somewhere useful. */\n onFocusLost?: () => void;\n}\n\ninterface NotificationControls {\n /** Keeps a success from clearing itself while `held`, such as while an action it offers is under way. */\n hold: (held: boolean) => void;\n /** Shows a success as a failure while `failed`, such as when an action it offers failed. */\n fail: (failed: boolean) => void;\n}\n\nconst Controls = createContext<NotificationControls>({ hold: () => {}, fail: () => {} });\n\n/** For a notification's body: what it can change about the notification it sits in. */\nexport function useNotificationControls(): NotificationControls {\n return useContext(Controls);\n}\n\n/** The id of the notification in each slot, in the toast manager. */\nconst slots = new Map<string, string>();\n\n/** Forgets every slot, as the toasts they named are gone. */\nexport function forgetNotificationSlots(): void {\n slots.clear();\n}\n\n/** Closes the notification `id` in `slot`; if the focus was in it, `onFocusLost` puts it somewhere else. */\nfunction close(slot: string, id: string, onFocusLost?: () => void): void {\n const hadFocus = Boolean(document.querySelector(`[data-toast-id=\"${id}\"]`)?.contains(document.activeElement));\n\n flushSync(() => {\n if (slots.get(slot) === id) slots.delete(slot);\n\n toast.dismiss(id);\n });\n\n if (hadFocus) onFocusLost?.();\n}\n\n/** Shows `notification` in its slot, replacing the one there. */\nexport function showNotification(notification: Notification): void {\n clearNotification(notification.slot);\n\n const id: string = toast.create({\n color: notification.tone === 'danger' ? 'danger' : 'success',\n // The body's own clock closes successes and its own button closes every notification, so the manager never does.\n duration: 0,\n closable: false,\n description: (\n <NotificationBody\n {...notification}\n onClose={() => close(notification.slot, id, notification.onFocusLost)}\n />\n ),\n });\n\n slots.set(notification.slot, id);\n}\n\n/** Closes whatever notification holds this slot. */\nexport function clearNotification(slot: string): void {\n const id = slots.get(slot);\n\n if (id) close(slot, id);\n}\n\n/** Gives a success five seconds after hover and keyboard focus leave it. */\nfunction useSuccessClose(ref: RefObject<Element | null>, enabled: boolean, onClose: () => void): void {\n const latest = useRef(onClose);\n\n useLayoutEffect(() => {\n latest.current = onClose;\n });\n useEffect(() => {\n if (!enabled) return;\n\n const entry = ref.current?.closest<HTMLElement>('[data-slot=\"toast\"]');\n\n if (!entry) return;\n\n const held = {\n hovered: entry.matches(':hover'),\n focused: entry.contains(document.activeElement),\n timer: undefined as ReturnType<typeof setTimeout> | undefined,\n };\n const restart = () => {\n clearTimeout(held.timer);\n\n if (!held.hovered && !held.focused) held.timer = setTimeout(() => latest.current(), SUCCESS_MS);\n };\n const enter = () => {\n held.hovered = true;\n restart();\n };\n const leave = () => {\n held.hovered = false;\n restart();\n };\n const focus = () => {\n held.focused = true;\n restart();\n };\n const blur = (event: FocusEvent) => {\n held.focused = event.relatedTarget instanceof Node && entry.contains(event.relatedTarget);\n restart();\n };\n\n entry.addEventListener('mouseenter', enter);\n entry.addEventListener('mouseleave', leave);\n entry.addEventListener('focusin', focus);\n entry.addEventListener('focusout', blur);\n restart();\n\n return () => {\n clearTimeout(held.timer);\n entry.removeEventListener('mouseenter', enter);\n entry.removeEventListener('mouseleave', leave);\n entry.removeEventListener('focusin', focus);\n entry.removeEventListener('focusout', blur);\n };\n }, [enabled, ref]);\n}\n\n/** One notification's content. `onClose` runs when its close button is clicked or, for a success, when its time is up. */\nfunction NotificationBody({\n slot,\n dismissLabel,\n tone = 'success',\n body,\n onClose,\n}: Notification & { onClose: () => void }) {\n const ref = useRef<HTMLSpanElement>(null);\n const [held, setHeld] = useState(false);\n const [bodyFailed, setBodyFailed] = useState(false);\n const failed = tone === 'danger' || bodyFailed;\n\n useEffect(() => {\n ref.current?.closest('[data-slot=\"toast\"]')?.setAttribute('data-toast-color', failed ? 'danger' : 'success');\n }, [failed]);\n useSuccessClose(ref, !failed && !held, onClose);\n\n return (\n <span ref={ref} data-toast={slot}>\n <DismissButton label={dismissLabel} onClick={onClose} />\n <Controls.Provider value={{ hold: setHeld, fail: setBodyFailed }}>{body}</Controls.Provider>\n </span>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { ComponentProps, ReactNode } from "react";
2
+ type ProgressProps = Omit<ComponentProps<'div'>, 'children' | 'className' | 'style'> & {
3
+ value: number;
4
+ max?: number;
5
+ /** Muted text after the bar, such as "Step 2 of 4". */
6
+ caption?: ReactNode;
7
+ };
8
+ /**
9
+ * A determinate progress bar: a rounded track filled to value / max, then an optional caption. Its props (an
10
+ * `aria-label`, say) go on the progressbar. Use ProgressStatusRow for a task's status row and StackedMeter for shares
11
+ * of a whole.
12
+ */
13
+ export declare function Progress({ caption, value, max, ...props }: ProgressProps): import("react").JSX.Element;
14
+ export {};
15
+ //# sourceMappingURL=Progress.d.ts.map
@@ -0,0 +1,38 @@
1
+ import { Text } from "../typography/Typography.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ // src/feedback/Progress.tsx
4
+ /**
5
+ * A determinate progress bar: a rounded track filled to value / max, then an optional caption. Its props (an
6
+ * `aria-label`, say) go on the progressbar. Use ProgressStatusRow for a task's status row and StackedMeter for shares
7
+ * of a whole.
8
+ */
9
+ function Progress({ caption, value, max = 100, ...props }) {
10
+ const share = max > 0 ? Math.min(Math.max(value / max, 0), 1) : 0;
11
+ return /* @__PURE__ */ jsxs("div", {
12
+ className: "flex items-center gap-2",
13
+ "data-slot": "progress",
14
+ children: [/* @__PURE__ */ jsx("div", {
15
+ role: "progressbar",
16
+ "aria-valuemin": 0,
17
+ "aria-valuemax": max,
18
+ "aria-valuenow": value,
19
+ className: "bg-base-200 h-2 max-w-65 flex-1 overflow-hidden rounded-full",
20
+ "data-slot": "progress-bar",
21
+ ...props,
22
+ children: /* @__PURE__ */ jsx("div", {
23
+ className: "bg-primary h-full rounded-[inherit]",
24
+ style: { width: `${share * 100}%` },
25
+ "data-slot": "progress-indicator"
26
+ })
27
+ }), caption && /* @__PURE__ */ jsx(Text, {
28
+ as: "span",
29
+ variant: "caption",
30
+ tone: "muted",
31
+ "data-slot": "progress-caption",
32
+ children: caption
33
+ })]
34
+ });
35
+ }
36
+ export { Progress };
37
+
38
+ //# sourceMappingURL=Progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Progress.js","names":[],"sources":["../../src/feedback/Progress.tsx"],"sourcesContent":["import type { ComponentProps, ReactNode } from 'react';\n\nimport { Text } from '../typography/Typography';\n\ntype ProgressProps = Omit<ComponentProps<'div'>, 'children' | 'className' | 'style'> & {\n value: number;\n max?: number;\n /** Muted text after the bar, such as \"Step 2 of 4\". */\n caption?: ReactNode;\n};\n\n/**\n * A determinate progress bar: a rounded track filled to value / max, then an optional caption. Its props (an\n * `aria-label`, say) go on the progressbar. Use ProgressStatusRow for a task's status row and StackedMeter for shares\n * of a whole.\n */\nexport function Progress({ caption, value, max = 100, ...props }: ProgressProps) {\n const share = max > 0 ? Math.min(Math.max(value / max, 0), 1) : 0;\n\n return (\n <div className=\"flex items-center gap-2\" data-slot=\"progress\">\n <div\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={max}\n aria-valuenow={value}\n className=\"bg-base-200 h-2 max-w-65 flex-1 overflow-hidden rounded-full\"\n data-slot=\"progress-bar\"\n {...props}\n >\n <div\n className=\"bg-primary h-full rounded-[inherit]\"\n style={{ width: `${share * 100}%` }}\n data-slot=\"progress-indicator\"\n />\n </div>\n {caption && (\n <Text as=\"span\" variant=\"caption\" tone=\"muted\" data-slot=\"progress-caption\">\n {caption}\n </Text>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAgBA,SAAgB,SAAS,EAAE,SAAS,OAAO,MAAM,KAAK,GAAG,SAAwB;CAC7E,MAAM,QAAQ,MAAM,IAAI,KAAK,IAAI,KAAK,IAAI,QAAQ,KAAK,CAAC,GAAG,CAAC,IAAI;CAEhE,OACI,qBAAC,OAAD;EAAK,WAAU;EAA0B,aAAU;EAAnD,UAAA,CACI,oBAAC,OAAD;GACI,MAAK;GACL,iBAAe;GACf,iBAAe;GACf,iBAAe;GACf,WAAU;GACV,aAAU;GACV,GAAI;GAEJ,UAAA,oBAAC,OAAD;IACI,WAAU;IACV,OAAO,EAAE,OAAO,GAAG,QAAQ,IAAI,GAAG;IAClC,aAAU;GACb,CAAA;EACA,CAAA,GACJ,WACG,oBAAC,MAAD;GAAM,IAAG;GAAO,SAAQ;GAAU,MAAK;GAAQ,aAAU;GACpD,UAAA;EACC,CAAA,CAET;;AAEb"}
@@ -1,7 +1,7 @@
1
1
  import { Button } from "../actions/Button.js";
2
2
  import { StatusIndicator } from "./StatusIndicator.js";
3
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
3
  import { ChevronRightIcon } from "lucide-react";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
5
  // src/feedback/ProgressStatusRow.tsx
6
6
  /** Ledger rows reserve the count line and track so updates never displace controls. */
7
7
  function ProgressStatusRow({ active, detail, secondaryDetail, issue, label, progress, tone = "info", trailing, onDetails, detailsLabel, progressLabel, compact = false }) {
@@ -3,7 +3,12 @@ interface StatusIndicatorProps {
3
3
  className?: string;
4
4
  size?: 'sm' | 'md';
5
5
  tone: StatusTone;
6
+ /** A colour that comes with data, such as a tracker label's own, in place of the tone's; none keeps the tone. */
7
+ labelColor?: string | undefined;
8
+ /** A short word after the dot in the tone's text colour, such as a check's "Installed"; the neutral tone mutes it,
9
+ * for a check that didn't run. */
10
+ label?: string;
6
11
  }
7
- export declare function StatusIndicator({ className, size, tone }: StatusIndicatorProps): import("react").JSX.Element;
12
+ export declare function StatusIndicator({ className, size, tone, labelColor, label }: StatusIndicatorProps): import("react").JSX.Element;
8
13
  export {};
9
14
  //# sourceMappingURL=StatusIndicator.d.ts.map
@@ -1,4 +1,4 @@
1
- import { jsx } from "react/jsx-runtime";
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
2
  // src/feedback/StatusIndicator.tsx
3
3
  const toneClasses = {
4
4
  neutral: "bg-base-400",
@@ -7,20 +7,34 @@ const toneClasses = {
7
7
  danger: "bg-danger",
8
8
  info: "bg-info"
9
9
  };
10
+ const labelClasses = {
11
+ neutral: "text-base-700",
12
+ success: "text-(--lar-success-text)",
13
+ warning: "text-(--lar-warning-text)",
14
+ danger: "text-(--lar-danger-text)",
15
+ info: "text-(--lar-info-text)"
16
+ };
10
17
  const sizeClasses = {
11
18
  sm: "size-1.5",
12
19
  md: "size-2"
13
20
  };
14
- function StatusIndicator({ className, size = "md", tone }) {
21
+ function StatusIndicator({ className, size = "md", tone, labelColor, label }) {
15
22
  const classes = [
16
23
  "inline-block shrink-0 rounded-full",
17
24
  sizeClasses[size],
18
25
  toneClasses[tone],
19
- className
26
+ label ? null : className
20
27
  ].filter(Boolean).join(" ");
21
- return /* @__PURE__ */ jsx("span", {
28
+ const dot = /* @__PURE__ */ jsx("span", {
22
29
  "aria-hidden": "true",
23
- className: classes
30
+ className: classes,
31
+ style: labelColor ? { background: labelColor } : void 0
32
+ });
33
+ if (label === void 0) return dot;
34
+ return /* @__PURE__ */ jsxs("span", {
35
+ "data-slot": "status-indicator",
36
+ className: `inline-flex items-center gap-1.5 text-xs font-medium whitespace-nowrap ${labelClasses[tone]} ${className ?? ""}`,
37
+ children: [dot, label]
24
38
  });
25
39
  }
26
40
  export { StatusIndicator };
@@ -1 +1 @@
1
- {"version":3,"file":"StatusIndicator.js","names":[],"sources":["../../src/feedback/StatusIndicator.tsx"],"sourcesContent":["export type StatusTone = 'neutral' | 'success' | 'warning' | 'danger' | 'info';\n\ninterface StatusIndicatorProps {\n className?: string;\n size?: 'sm' | 'md';\n tone: StatusTone;\n}\n\nconst toneClasses: Record<StatusTone, string> = {\n neutral: 'bg-base-400',\n success: 'bg-success',\n warning: 'bg-warning',\n danger: 'bg-danger',\n info: 'bg-info',\n};\n\nconst sizeClasses: Record<NonNullable<StatusIndicatorProps['size']>, string> = {\n sm: 'size-1.5',\n md: 'size-2',\n};\n\nexport function StatusIndicator({ className, size = 'md', tone }: StatusIndicatorProps) {\n const classes = ['inline-block shrink-0 rounded-full', sizeClasses[size], toneClasses[tone], className]\n .filter(Boolean)\n .join(' ');\n\n return <span aria-hidden=\"true\" className={classes} />;\n}\n"],"mappings":";;AAQA,MAAM,cAA0C;CAC5C,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,MAAM;AACV;AAEA,MAAM,cAAyE;CAC3E,IAAI;CACJ,IAAI;AACR;AAEA,SAAgB,gBAAgB,EAAE,WAAW,OAAO,MAAM,QAA8B;CACpF,MAAM,UAAU;EAAC;EAAsC,YAAY;EAAO,YAAY;EAAO;CAAS,CAAC,CAClG,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CAEb,OAAO,oBAAC,QAAD;EAAM,eAAY;EAAO,WAAW;CAAU,CAAA;AACzD"}
1
+ {"version":3,"file":"StatusIndicator.js","names":[],"sources":["../../src/feedback/StatusIndicator.tsx"],"sourcesContent":["export type StatusTone = 'neutral' | 'success' | 'warning' | 'danger' | 'info';\n\ninterface StatusIndicatorProps {\n className?: string;\n size?: 'sm' | 'md';\n tone: StatusTone;\n /** A colour that comes with data, such as a tracker label's own, in place of the tone's; none keeps the tone. */\n labelColor?: string | undefined;\n /** A short word after the dot in the tone's text colour, such as a check's \"Installed\"; the neutral tone mutes it,\n * for a check that didn't run. */\n label?: string;\n}\n\nconst toneClasses: Record<StatusTone, string> = {\n neutral: 'bg-base-400',\n success: 'bg-success',\n warning: 'bg-warning',\n danger: 'bg-danger',\n info: 'bg-info',\n};\n\nconst labelClasses: Record<StatusTone, string> = {\n neutral: 'text-base-700',\n success: 'text-(--lar-success-text)',\n warning: 'text-(--lar-warning-text)',\n danger: 'text-(--lar-danger-text)',\n info: 'text-(--lar-info-text)',\n};\n\nconst sizeClasses: Record<NonNullable<StatusIndicatorProps['size']>, string> = {\n sm: 'size-1.5',\n md: 'size-2',\n};\n\nexport function StatusIndicator({ className, size = 'md', tone, labelColor, label }: StatusIndicatorProps) {\n const classes = [\n 'inline-block shrink-0 rounded-full',\n sizeClasses[size],\n toneClasses[tone],\n label ? null : className,\n ]\n .filter(Boolean)\n .join(' ');\n const dot = (\n <span aria-hidden=\"true\" className={classes} style={labelColor ? { background: labelColor } : undefined} />\n );\n\n if (label === undefined) return dot;\n\n return (\n <span\n data-slot=\"status-indicator\"\n className={`inline-flex items-center gap-1.5 text-xs font-medium whitespace-nowrap ${labelClasses[tone]} ${className ?? ''}`}\n >\n {dot}\n {label}\n </span>\n );\n}\n"],"mappings":";;AAaA,MAAM,cAA0C;CAC5C,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,MAAM;AACV;AAEA,MAAM,eAA2C;CAC7C,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,MAAM;AACV;AAEA,MAAM,cAAyE;CAC3E,IAAI;CACJ,IAAI;AACR;AAEA,SAAgB,gBAAgB,EAAE,WAAW,OAAO,MAAM,MAAM,YAAY,SAA+B;CACvG,MAAM,UAAU;EACZ;EACA,YAAY;EACZ,YAAY;EACZ,QAAQ,OAAO;CACnB,CAAC,CACI,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CACb,MAAM,MACF,oBAAC,QAAD;EAAM,eAAY;EAAO,WAAW;EAAS,OAAO,aAAa,EAAE,YAAY,WAAW,IAAI,KAAA;CAAY,CAAA;CAG9G,IAAI,UAAU,KAAA,GAAW,OAAO;CAEhC,OACI,qBAAC,QAAD;EACI,aAAU;EACV,WAAW,0EAA0E,aAAa,MAAM,GAAG,aAAa;EAF5H,UAAA,CAIK,KACA,KACC;;AAEd"}
@@ -1,11 +1,15 @@
1
1
  import { StatusIndicator, StatusTone } from "./StatusIndicator.js";
2
- import { Alert as Alert$1 } from "./Alert.js";
2
+ import { Alert } from "./Alert.js";
3
3
  import { AsyncState } from "./AsyncState.js";
4
4
  import { ErrorNotification, dismissAllNotifications, showErrorNotification, showSuccessNotification } from "./ErrorNotification.js";
5
- import { Notifications } from "./Notifications.js";
5
+ import { DismissButton } from "./DismissButton.js";
6
+ import { FormResult } from "./FormResult.js";
7
+ import { LiveRegion } from "./LiveRegion.js";
8
+ import { Notification, Notifications, clearNotification, showNotification, useNotificationControls } from "./Notifications.js";
9
+ import { Progress } from "./Progress.js";
6
10
  import { ProgressStatusRow } from "./ProgressStatusRow.js";
7
11
  import { SkeletonLoader } from "./SkeletonLoader.js";
12
+ import { Loading } from "./Loading.js";
8
13
  import { StatusPopoverContent } from "./StatusPopoverContent.js";
9
14
  import { StatusRow } from "./StatusRow.js";
10
- import { Loading as Loading$1 } from "@ninna-ui/feedback";
11
- export { Alert$1 as Alert, AsyncState, type ErrorNotification, Loading$1 as Loading, Notifications, ProgressStatusRow, SkeletonLoader, StatusIndicator, StatusPopoverContent, StatusRow, type StatusTone, dismissAllNotifications, showErrorNotification, showSuccessNotification };
15
+ export { Alert, AsyncState, DismissButton, type ErrorNotification, FormResult, LiveRegion, Loading, type Notification, Notifications, Progress, ProgressStatusRow, SkeletonLoader, StatusIndicator, StatusPopoverContent, StatusRow, type StatusTone, clearNotification, dismissAllNotifications, showErrorNotification, showNotification, showSuccessNotification, useNotificationControls };
@@ -1,8 +1,8 @@
1
1
  import { tabbable } from "../foundations/KeyboardFocus.js";
2
2
  import { formChoiceClasses } from "./FormControlStyles.js";
3
3
  import { forwardRef, useImperativeHandle, useLayoutEffect, useRef } from "react";
4
- import { jsx, jsxs } from "react/jsx-runtime";
5
4
  import { CheckIcon } from "lucide-react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
6
  // src/forms/Checkbox.tsx
7
7
  const Checkbox = forwardRef(({ label, indeterminate = false, "aria-checked": ariaChecked, className, onChange, ...props }, ref) => {
8
8
  const inputRef = useRef(null);
@@ -0,0 +1,21 @@
1
+ import { ReactNode } from "react";
2
+ export interface ColorSwatch {
3
+ /** What picking it sets, such as a hex colour without its #. */
4
+ value: string;
5
+ /** The CSS colour it shows. */
6
+ color: string;
7
+ /** Its accessible name, such as "Colour #D73A4A". */
8
+ label: string;
9
+ }
10
+ /**
11
+ * A row of round colour swatches, the one matching `value` (ignoring case) pressed and ringed, then `children`, such as
12
+ * a field for any other colour, wrapping when they don't fit.
13
+ */
14
+ export declare function ColorSwatches({ swatches, value, disabled, onPick, children }: {
15
+ swatches: readonly ColorSwatch[];
16
+ value: string;
17
+ disabled?: boolean;
18
+ onPick: (value: string) => void;
19
+ children?: ReactNode;
20
+ }): import("react").JSX.Element;
21
+ //# sourceMappingURL=ColorSwatches.d.ts.map
@@ -0,0 +1,26 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ // src/forms/ColorSwatches.tsx
3
+ /**
4
+ * A row of round colour swatches, the one matching `value` (ignoring case) pressed and ringed, then `children`, such as
5
+ * a field for any other colour, wrapping when they don't fit.
6
+ */
7
+ function ColorSwatches({ swatches, value, disabled = false, onPick, children }) {
8
+ return /* @__PURE__ */ jsxs("span", {
9
+ className: "flex flex-wrap items-center gap-1.5",
10
+ children: [swatches.map((swatch) => {
11
+ const picked = swatch.value.toLowerCase() === value.toLowerCase();
12
+ return /* @__PURE__ */ jsx("button", {
13
+ type: "button",
14
+ "aria-label": swatch.label,
15
+ "aria-pressed": picked,
16
+ disabled,
17
+ className: `size-5 rounded-full border ${picked ? "ring-2 ring-(--primary) ring-offset-1 ring-offset-(--card)" : ""}`,
18
+ style: { background: swatch.color },
19
+ onClick: () => onPick(swatch.value)
20
+ }, swatch.value);
21
+ }), children]
22
+ });
23
+ }
24
+ export { ColorSwatches };
25
+
26
+ //# sourceMappingURL=ColorSwatches.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ColorSwatches.js","names":[],"sources":["../../src/forms/ColorSwatches.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nexport interface ColorSwatch {\n /** What picking it sets, such as a hex colour without its #. */\n value: string;\n /** The CSS colour it shows. */\n color: string;\n /** Its accessible name, such as \"Colour #D73A4A\". */\n label: string;\n}\n\n/**\n * A row of round colour swatches, the one matching `value` (ignoring case) pressed and ringed, then `children`, such as\n * a field for any other colour, wrapping when they don't fit.\n */\nexport function ColorSwatches({\n swatches,\n value,\n disabled = false,\n onPick,\n children,\n}: {\n swatches: readonly ColorSwatch[];\n value: string;\n disabled?: boolean;\n onPick: (value: string) => void;\n children?: ReactNode;\n}) {\n return (\n <span className=\"flex flex-wrap items-center gap-1.5\">\n {swatches.map((swatch) => {\n const picked = swatch.value.toLowerCase() === value.toLowerCase();\n\n return (\n <button\n key={swatch.value}\n type=\"button\"\n aria-label={swatch.label}\n aria-pressed={picked}\n disabled={disabled}\n className={`size-5 rounded-full border ${picked ? 'ring-2 ring-(--primary) ring-offset-1 ring-offset-(--card)' : ''}`}\n style={{ background: swatch.color }}\n onClick={() => onPick(swatch.value)}\n />\n );\n })}\n {children}\n </span>\n );\n}\n"],"mappings":";;;;;;AAeA,SAAgB,cAAc,EAC1B,UACA,OACA,WAAW,OACX,QACA,YAOD;CACC,OACI,qBAAC,QAAD;EAAM,WAAU;EAAhB,UAAA,CACK,SAAS,KAAK,WAAW;GACtB,MAAM,SAAS,OAAO,MAAM,YAAY,MAAM,MAAM,YAAY;GAEhE,OACI,oBAAC,UAAD;IAEI,MAAK;IACL,cAAY,OAAO;IACnB,gBAAc;IACJ;IACV,WAAW,8BAA8B,SAAS,+DAA+D;IACjH,OAAO,EAAE,YAAY,OAAO,MAAM;IAClC,eAAe,OAAO,OAAO,KAAK;GACrC,GARQ,OAAO,KAQf;EAET,CAAC,GACA,QACC;;AAEd"}
@@ -1,6 +1,9 @@
1
1
  import { ButtonProps } from "../actions/Button.js";
2
2
  import { FieldProps } from "./Field.js";
3
- import { ReactNode } from "react";
3
+ import { ComponentProps, ReactNode } from "react";
4
+ type DataAttributes = {
5
+ [key: `data-${string}`]: string | undefined;
6
+ };
4
7
  export declare function FormContent({ children }: {
5
8
  children: ReactNode;
6
9
  }): import("react").JSX.Element;
@@ -14,18 +17,55 @@ interface FormSectionProps {
14
17
  description?: string;
15
18
  loading?: boolean;
16
19
  loadingLabel?: string;
20
+ presentation?: 'default';
17
21
  title: ReactNode;
18
22
  }
19
- export declare function FormSection({ action, badges, children, description, loading, loadingLabel, title }: FormSectionProps): import("react").JSX.Element;
20
- interface FormRowProps {
23
+ /** A dense tool's settings group: its title (with an optional help popover) and description over the content as
24
+ * given, such as one or more settings panels and their notes. */
25
+ interface DenseFormSectionProps extends DataAttributes {
26
+ presentation: 'dense';
27
+ title?: ReactNode;
28
+ /** Explains the group in a popover from a help button after the title; `helpLabel` names that button. */
29
+ help?: ReactNode;
30
+ helpLabel?: string;
31
+ description?: ReactNode;
32
+ /** Names the group when its title doesn't, or when it has none. */
33
+ 'aria-label'?: string;
34
+ children?: ReactNode;
35
+ }
36
+ export declare function FormSection(props: FormSectionProps | DenseFormSectionProps): import("react").JSX.Element;
37
+ interface FormRowColumnsProps {
21
38
  badges?: ReactNode;
22
39
  children: ReactNode;
23
40
  description: string;
24
41
  /** The row's element id, for linking or scrolling to it; a row with one can take focus when it is opened. */
25
42
  id?: string;
26
43
  label: ReactNode;
44
+ layout?: 'columns';
45
+ }
46
+ /** A dense tool's settings row: the label (with an optional help popover) and description, then its controls flowing
47
+ * beside them and wrapping under them when they don't fit, then content below and an error. */
48
+ interface FormRowFlowProps extends DataAttributes {
49
+ layout: 'flow';
50
+ label: ReactNode;
51
+ /** Explains the setting in a popover from a help button after the label; `helpLabel` names that button. */
52
+ help?: ReactNode;
53
+ helpLabel?: string;
54
+ description?: ReactNode;
55
+ children?: ReactNode;
56
+ /** Full-width content under the label and controls, such as a list the setting governs. */
57
+ below?: ReactNode;
58
+ error?: string | undefined;
59
+ /** The error's element id, for a control's aria-describedby. */
60
+ errorId?: string;
27
61
  }
28
- export declare function FormRow({ badges, children, description, id, label }: FormRowProps): import("react").JSX.Element;
62
+ type FormRowProps = FormRowColumnsProps | FormRowFlowProps;
63
+ export declare function FormRow(props: FormRowProps): import("react").JSX.Element;
64
+ /** A value and its unit beside it in a row's controls, such as a number field and "days". */
65
+ export declare function FormUnit({ children, unit }: {
66
+ children: ReactNode;
67
+ unit: ReactNode;
68
+ }): import("react").JSX.Element;
29
69
  type FormFieldProps = Omit<FieldProps, 'children' | 'className'> & {
30
70
  action?: ReactNode;
31
71
  } & ({
@@ -39,10 +79,32 @@ type FormFieldProps = Omit<FieldProps, 'children' | 'className'> & {
39
79
  });
40
80
  export declare function FormField({ action, children, loading, loadingLabel, ...props }: FormFieldProps): import("react").JSX.Element;
41
81
  export declare function FormAction(props: Omit<ButtonProps, 'type' | 'size' | 'variant' | 'color'>): import("react").JSX.Element;
42
- export declare function Disclosure({ children, label, lazy }: {
82
+ export declare function Disclosure({ children, label, lazy, presentation, defaultOpen, badge, onOpenChange, ...data }: {
43
83
  children: ReactNode;
44
84
  label: string;
45
85
  lazy?: boolean;
46
- }): import("react").JSX.Element;
86
+ /** `note` folds small muted text behind a chevron; `section` folds a section's own content, such as an earlier
87
+ * version of a text, behind a muted label in the body size; `group` folds a form's optional group behind its
88
+ * heading, such as optional settings; `framed` folds a short list in a frame, such as entries that can't be
89
+ * picked. */
90
+ presentation?: 'note' | 'section' | 'group' | 'framed';
91
+ /** Starts open, such as a group whose kept answers may need a look. */
92
+ defaultOpen?: boolean;
93
+ /** A `group`'s badge after its heading, such as "Optional". */
94
+ badge?: string | undefined;
95
+ /** Hears each time it opens or closes, such as to read what it shows once it opens. */
96
+ onOpenChange?: (open: boolean) => void;
97
+ } & DataAttributes): import("react").JSX.Element;
98
+ type FormFieldsetProps = Omit<ComponentProps<'fieldset'>, 'style'> & {
99
+ /** The legend over the group. */
100
+ legend?: ReactNode;
101
+ /** Names the group for assistive technology only, where what's around it already says what it is. */
102
+ hiddenLegend?: boolean;
103
+ /** `group` only groups and disables its fields, with no frame. */
104
+ presentation?: 'bordered' | 'group';
105
+ };
106
+ /** The form section's fieldset: a bordered group of controls under a legend, on the native fieldset, which also
107
+ * disables every control inside it. As a `group`, it only groups and disables its fields. */
108
+ export declare function FormFieldset({ legend, hiddenLegend, presentation, className, children, ...props }: FormFieldsetProps): import("react").JSX.Element;
47
109
  export {};
48
110
  //# sourceMappingURL=FormSection.d.ts.map