@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
@@ -1,36 +1,67 @@
1
1
  import { IconButton } from "../actions/IconButton.js";
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { tabbable } from "../foundations/KeyboardFocus.js";
3
3
  import { LayoutGridIcon, TableIcon } from "lucide-react";
4
+ import { jsx } from "react/jsx-runtime";
4
5
  // src/navigation/CollectionViewToggle.tsx
5
- function CollectionViewToggle({ disabledViews = [], gridLabel, label, onChange, tableLabel, value }) {
6
- return /* @__PURE__ */ jsxs("div", {
6
+ /**
7
+ * A group of icon buttons that picks one way of drawing a view, the picked one raised. `compact` draws 24px buttons with
8
+ * 14px icons, for a row's line. As `text`, each button is its label in small type, such as a dialog's panes in its
9
+ * header.
10
+ */
11
+ function ViewToggle({ label, options, value, onChange, compact = false, presentation = "icons" }) {
12
+ if (presentation === "text") return /* @__PURE__ */ jsx("div", {
13
+ role: "group",
14
+ "aria-label": label,
15
+ className: "bg-base-200 flex gap-0.5 rounded-lg p-0.5",
16
+ children: options.map((option) => /* @__PURE__ */ jsx("button", {
17
+ ...tabbable,
18
+ ...option.attributes,
19
+ type: "button",
20
+ "aria-pressed": value === option.value,
21
+ disabled: option.disabled,
22
+ onClick: () => onChange(option.value),
23
+ className: `focus-visible:ring-primary h-7 rounded-md px-2.5 text-xs font-medium outline-none focus-visible:ring-2 ${value === option.value ? "bg-base-100 text-base-content shadow-sm" : "hover:text-base-content text-(--muted-foreground)"}`,
24
+ children: option.label
25
+ }, option.value))
26
+ });
27
+ return /* @__PURE__ */ jsx("div", {
7
28
  role: "group",
8
29
  "aria-label": label,
9
30
  className: "bg-base-200/70 flex gap-0.5 rounded-lg p-0.5",
10
- children: [/* @__PURE__ */ jsx(IconButton, {
11
- "aria-label": gridLabel,
12
- "aria-pressed": value === "grid",
13
- disabled: disabledViews.includes("grid"),
14
- icon: /* @__PURE__ */ jsx(LayoutGridIcon, {}),
15
- title: gridLabel,
16
- className: buttonClasses(value === "grid"),
17
- onClick: () => onChange("grid"),
31
+ children: options.map((option) => /* @__PURE__ */ jsx(IconButton, {
32
+ ...option.attributes,
33
+ "aria-label": option.label,
34
+ "aria-pressed": value === option.value,
35
+ disabled: option.disabled,
36
+ icon: option.icon,
37
+ title: option.label,
38
+ className: buttonClasses(value === option.value, compact),
39
+ onClick: () => onChange(option.value),
18
40
  tone: "neutral"
19
- }), /* @__PURE__ */ jsx(IconButton, {
20
- "aria-label": tableLabel,
21
- "aria-pressed": value === "table",
22
- disabled: disabledViews.includes("table"),
41
+ }, option.value))
42
+ });
43
+ }
44
+ function CollectionViewToggle({ disabledViews = [], gridLabel, label, onChange, tableLabel, value }) {
45
+ return /* @__PURE__ */ jsx(ViewToggle, {
46
+ label,
47
+ value,
48
+ onChange,
49
+ options: [{
50
+ value: "grid",
51
+ label: gridLabel,
52
+ icon: /* @__PURE__ */ jsx(LayoutGridIcon, {}),
53
+ disabled: disabledViews.includes("grid")
54
+ }, {
55
+ value: "table",
56
+ label: tableLabel,
23
57
  icon: /* @__PURE__ */ jsx(TableIcon, {}),
24
- title: tableLabel,
25
- className: buttonClasses(value === "table"),
26
- onClick: () => onChange("table"),
27
- tone: "neutral"
28
- })]
58
+ disabled: disabledViews.includes("table")
59
+ }]
29
60
  });
30
61
  }
31
- function buttonClasses(active) {
32
- return `size-8 p-0 ${active ? "bg-base-100 text-base-content shadow-sm" : "text-base-600"}`;
62
+ function buttonClasses(active, compact) {
63
+ return `${compact ? "size-6 **:data-[slot=icon]:size-3.5" : "size-8"} p-0 ${active ? "bg-base-100 text-base-content shadow-sm" : "text-base-600"}`;
33
64
  }
34
- export { CollectionViewToggle };
65
+ export { CollectionViewToggle, ViewToggle };
35
66
 
36
67
  //# sourceMappingURL=CollectionViewToggle.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CollectionViewToggle.js","names":[],"sources":["../../src/navigation/CollectionViewToggle.tsx"],"sourcesContent":["import { LayoutGridIcon, TableIcon } from 'lucide-react';\n\nimport { IconButton } from '../actions/IconButton';\n\nexport type CollectionView = 'grid' | 'table';\n\ninterface CollectionViewToggleProps {\n disabledViews?: readonly CollectionView[];\n gridLabel: string;\n label: string;\n onChange: (view: CollectionView) => void;\n tableLabel: string;\n value: CollectionView;\n}\n\nexport function CollectionViewToggle({\n disabledViews = [],\n gridLabel,\n label,\n onChange,\n tableLabel,\n value,\n}: CollectionViewToggleProps) {\n return (\n <div role=\"group\" aria-label={label} className=\"bg-base-200/70 flex gap-0.5 rounded-lg p-0.5\">\n <IconButton\n aria-label={gridLabel}\n aria-pressed={value === 'grid'}\n disabled={disabledViews.includes('grid')}\n icon={<LayoutGridIcon />}\n title={gridLabel}\n className={buttonClasses(value === 'grid')}\n onClick={() => onChange('grid')}\n tone=\"neutral\"\n />\n <IconButton\n aria-label={tableLabel}\n aria-pressed={value === 'table'}\n disabled={disabledViews.includes('table')}\n icon={<TableIcon />}\n title={tableLabel}\n className={buttonClasses(value === 'table')}\n onClick={() => onChange('table')}\n tone=\"neutral\"\n />\n </div>\n );\n}\n\nfunction buttonClasses(active: boolean): string {\n return `size-8 p-0 ${active ? 'bg-base-100 text-base-content shadow-sm' : 'text-base-600'}`;\n}\n"],"mappings":";;;;AAeA,SAAgB,qBAAqB,EACjC,gBAAgB,CAAC,GACjB,WACA,OACA,UACA,YACA,SAC0B;CAC1B,OACI,qBAAC,OAAD;EAAK,MAAK;EAAQ,cAAY;EAAO,WAAU;EAA/C,UAAA,CACI,oBAAC,YAAD;GACI,cAAY;GACZ,gBAAc,UAAU;GACxB,UAAU,cAAc,SAAS,MAAM;GACvC,MAAM,oBAAC,gBAAD,CAAiB,CAAA;GACvB,OAAO;GACP,WAAW,cAAc,UAAU,MAAM;GACzC,eAAe,SAAS,MAAM;GAC9B,MAAK;EACR,CAAA,GACD,oBAAC,YAAD;GACI,cAAY;GACZ,gBAAc,UAAU;GACxB,UAAU,cAAc,SAAS,OAAO;GACxC,MAAM,oBAAC,WAAD,CAAY,CAAA;GAClB,OAAO;GACP,WAAW,cAAc,UAAU,OAAO;GAC1C,eAAe,SAAS,OAAO;GAC/B,MAAK;EACR,CAAA,CACA;;AAEb;AAEA,SAAS,cAAc,QAAyB;CAC5C,OAAO,cAAc,SAAS,4CAA4C;AAC9E"}
1
+ {"version":3,"file":"CollectionViewToggle.js","names":[],"sources":["../../src/navigation/CollectionViewToggle.tsx"],"sourcesContent":["import { LayoutGridIcon, TableIcon } from 'lucide-react';\nimport type { ReactNode } from 'react';\n\nimport { IconButton } from '../actions/IconButton';\nimport { tabbable } from '../foundations/KeyboardFocus';\n\nexport type CollectionView = 'grid' | 'table';\n\n/** One way of drawing a view, as ViewToggle offers it: its icon, named by its label (or, as `text`, its label alone).\n * `attributes` are `data-*` markers for its button, such as the pane it shows. */\nexport interface ViewToggleOption<V extends string> {\n value: V;\n label: string;\n icon?: ReactNode;\n disabled?: boolean;\n attributes?: { [name: `data-${string}`]: string };\n}\n\n/**\n * A group of icon buttons that picks one way of drawing a view, the picked one raised. `compact` draws 24px buttons with\n * 14px icons, for a row's line. As `text`, each button is its label in small type, such as a dialog's panes in its\n * header.\n */\nexport function ViewToggle<V extends string>({\n label,\n options,\n value,\n onChange,\n compact = false,\n presentation = 'icons',\n}: {\n /** Names the group; with none, the group is named by its options alone. */\n label?: string;\n options: readonly ViewToggleOption<V>[];\n value: V;\n onChange: (view: V) => void;\n compact?: boolean;\n presentation?: 'icons' | 'text';\n}) {\n if (presentation === 'text')\n return (\n <div role=\"group\" aria-label={label} className=\"bg-base-200 flex gap-0.5 rounded-lg p-0.5\">\n {options.map((option) => (\n <button\n key={option.value}\n {...tabbable}\n {...option.attributes}\n type=\"button\"\n aria-pressed={value === option.value}\n disabled={option.disabled}\n onClick={() => onChange(option.value)}\n className={`focus-visible:ring-primary h-7 rounded-md px-2.5 text-xs font-medium outline-none focus-visible:ring-2 ${value === option.value ? 'bg-base-100 text-base-content shadow-sm' : 'hover:text-base-content text-(--muted-foreground)'}`}\n >\n {option.label}\n </button>\n ))}\n </div>\n );\n\n return (\n <div role=\"group\" aria-label={label} className=\"bg-base-200/70 flex gap-0.5 rounded-lg p-0.5\">\n {options.map((option) => (\n <IconButton\n key={option.value}\n {...option.attributes}\n aria-label={option.label}\n aria-pressed={value === option.value}\n disabled={option.disabled}\n icon={option.icon}\n title={option.label}\n className={buttonClasses(value === option.value, compact)}\n onClick={() => onChange(option.value)}\n tone=\"neutral\"\n />\n ))}\n </div>\n );\n}\n\ninterface CollectionViewToggleProps {\n disabledViews?: readonly CollectionView[];\n gridLabel: string;\n label: string;\n onChange: (view: CollectionView) => void;\n tableLabel: string;\n value: CollectionView;\n}\n\nexport function CollectionViewToggle({\n disabledViews = [],\n gridLabel,\n label,\n onChange,\n tableLabel,\n value,\n}: CollectionViewToggleProps) {\n return (\n <ViewToggle\n label={label}\n value={value}\n onChange={onChange}\n options={[\n {\n value: 'grid',\n label: gridLabel,\n icon: <LayoutGridIcon />,\n disabled: disabledViews.includes('grid'),\n },\n {\n value: 'table',\n label: tableLabel,\n icon: <TableIcon />,\n disabled: disabledViews.includes('table'),\n },\n ]}\n />\n );\n}\n\nfunction buttonClasses(active: boolean, compact: boolean): string {\n return `${compact ? 'size-6 **:data-[slot=icon]:size-3.5' : 'size-8'} p-0 ${active ? 'bg-base-100 text-base-content shadow-sm' : 'text-base-600'}`;\n}\n"],"mappings":";;;;;;;;;;AAuBA,SAAgB,WAA6B,EACzC,OACA,SACA,OACA,UACA,UAAU,OACV,eAAe,WAShB;CACC,IAAI,iBAAiB,QACjB,OACI,oBAAC,OAAD;EAAK,MAAK;EAAQ,cAAY;EAAO,WAAU;EAC1C,UAAA,QAAQ,KAAK,WACV,oBAAC,UAAD;GAEI,GAAI;GACJ,GAAI,OAAO;GACX,MAAK;GACL,gBAAc,UAAU,OAAO;GAC/B,UAAU,OAAO;GACjB,eAAe,SAAS,OAAO,KAAK;GACpC,WAAW,0GAA0G,UAAU,OAAO,QAAQ,4CAA4C;GAEzL,UAAA,OAAO;EACJ,GAVC,OAAO,KAUR,CACX;CACA,CAAA;CAGb,OACI,oBAAC,OAAD;EAAK,MAAK;EAAQ,cAAY;EAAO,WAAU;EAC1C,UAAA,QAAQ,KAAK,WACV,oBAAC,YAAD;GAEI,GAAI,OAAO;GACX,cAAY,OAAO;GACnB,gBAAc,UAAU,OAAO;GAC/B,UAAU,OAAO;GACjB,MAAM,OAAO;GACb,OAAO,OAAO;GACd,WAAW,cAAc,UAAU,OAAO,OAAO,OAAO;GACxD,eAAe,SAAS,OAAO,KAAK;GACpC,MAAK;EACR,GAVQ,OAAO,KAUf,CACJ;CACA,CAAA;AAEb;AAWA,SAAgB,qBAAqB,EACjC,gBAAgB,CAAC,GACjB,WACA,OACA,UACA,YACA,SAC0B;CAC1B,OACI,oBAAC,YAAD;EACW;EACA;EACG;EACV,SAAS,CACL;GACI,OAAO;GACP,OAAO;GACP,MAAM,oBAAC,gBAAD,CAAiB,CAAA;GACvB,UAAU,cAAc,SAAS,MAAM;EAC3C,GACA;GACI,OAAO;GACP,OAAO;GACP,MAAM,oBAAC,WAAD,CAAY,CAAA;GAClB,UAAU,cAAc,SAAS,OAAO;EAC5C,CACJ;CACH,CAAA;AAET;AAEA,SAAS,cAAc,QAAiB,SAA0B;CAC9D,OAAO,GAAG,UAAU,wCAAwC,SAAS,OAAO,SAAS,4CAA4C;AACrI"}
@@ -4,8 +4,8 @@ import { ScrollArea } from "../layout/ScrollArea.js";
4
4
  import { Popover } from "../overlays/Popover.js";
5
5
  import { CollectionBrowseTrigger } from "./CollectionBrowseSelector.js";
6
6
  import { useMemo, useState } from "react";
7
- import { jsx, jsxs } from "react/jsx-runtime";
8
7
  import { ChevronDownIcon, SearchIcon } from "lucide-react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
9
  // src/navigation/DrilldownBrowseSelector.tsx
10
10
  function DrilldownBrowseSelector({ icon, allLabel, backLabel, disabledOptionLabel, groups, label, onClear }) {
11
11
  const [open, setOpen] = useState(false);
@@ -6,9 +6,9 @@ import { Inline, Stack } from "../layout/Flow.js";
6
6
  import { ScrollArea } from "../layout/ScrollArea.js";
7
7
  import { Popover } from "../overlays/Popover.js";
8
8
  import { Text } from "../typography/Typography.js";
9
- import { jsx, jsxs } from "react/jsx-runtime";
10
- import { ChevronDownIcon, FolderIcon, FolderUpIcon, HouseIcon } from "lucide-react";
11
9
  import { Alert, Loading } from "@ninna-ui/feedback";
10
+ import { ChevronDownIcon, FolderIcon, FolderUpIcon, HouseIcon } from "lucide-react";
11
+ import { jsx, jsxs } from "react/jsx-runtime";
12
12
  // src/navigation/FolderSelector.tsx
13
13
  function FolderSelector({ id, title, "aria-describedby": describedBy, "aria-invalid": invalid, "aria-required": required, browsePath, disabled, error, hasMore, loading, loadingMore, onBrowsePathChange, onChange, onLoadMore, onOpenChange, onRetry, open, options, parentPath, value }) {
14
14
  const labels = useDesignSystemLabels();
@@ -0,0 +1,10 @@
1
+ /** A menu of the ways a list sorts, its button naming the current one. */
2
+ export declare function SortMenu<Value extends string>({ value, options, onChange }: {
3
+ value: Value;
4
+ options: readonly {
5
+ value: Value;
6
+ label: string;
7
+ }[];
8
+ onChange: (value: Value) => void;
9
+ }): import("react").JSX.Element;
10
+ //# sourceMappingURL=SortMenu.d.ts.map
@@ -0,0 +1,33 @@
1
+ import { Button } from "../actions/Button.js";
2
+ import { DropdownMenu } from "../overlays/DropdownMenu.js";
3
+ import { ChevronDownIcon } from "lucide-react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ // src/navigation/SortMenu.tsx
6
+ /** A menu of the ways a list sorts, its button naming the current one. */
7
+ function SortMenu({ value, options, onChange }) {
8
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenu.Trigger, {
9
+ asChild: true,
10
+ children: /* @__PURE__ */ jsx(Button, {
11
+ variant: "secondary",
12
+ compact: true,
13
+ rightIcon: /* @__PURE__ */ jsx(ChevronDownIcon, {}),
14
+ children: options.find((option) => option.value === value)?.label
15
+ })
16
+ }), /* @__PURE__ */ jsx(DropdownMenu.Content, {
17
+ align: "end",
18
+ children: /* @__PURE__ */ jsx(DropdownMenu.RadioGroup, {
19
+ value,
20
+ onValueChange: (next) => {
21
+ const picked = options.find((option) => option.value === next);
22
+ if (picked) onChange(picked.value);
23
+ },
24
+ children: options.map((option) => /* @__PURE__ */ jsx(DropdownMenu.RadioItem, {
25
+ value: option.value,
26
+ children: option.label
27
+ }, option.value))
28
+ })
29
+ })] });
30
+ }
31
+ export { SortMenu };
32
+
33
+ //# sourceMappingURL=SortMenu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SortMenu.js","names":[],"sources":["../../src/navigation/SortMenu.tsx"],"sourcesContent":["import { ChevronDownIcon } from 'lucide-react';\n\nimport { Button } from '../actions/Button';\nimport { DropdownMenu } from '../overlays/DropdownMenu';\n\n/** A menu of the ways a list sorts, its button naming the current one. */\nexport function SortMenu<Value extends string>({\n value,\n options,\n onChange,\n}: {\n value: Value;\n options: readonly { value: Value; label: string }[];\n onChange: (value: Value) => void;\n}) {\n return (\n <DropdownMenu>\n <DropdownMenu.Trigger asChild>\n <Button variant=\"secondary\" compact rightIcon={<ChevronDownIcon />}>\n {options.find((option) => option.value === value)?.label}\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n <DropdownMenu.RadioGroup\n value={value}\n onValueChange={(next) => {\n const picked = options.find((option) => option.value === next);\n\n if (picked) onChange(picked.value);\n }}\n >\n {options.map((option) => (\n <DropdownMenu.RadioItem key={option.value} value={option.value}>\n {option.label}\n </DropdownMenu.RadioItem>\n ))}\n </DropdownMenu.RadioGroup>\n </DropdownMenu.Content>\n </DropdownMenu>\n );\n}\n"],"mappings":";;;;;;AAMA,SAAgB,SAA+B,EAC3C,OACA,SACA,YAKD;CACC,OACI,qBAAC,cAAD,EAAA,UAAA,CACI,oBAAC,aAAa,SAAd;EAAsB,SAAA;EAClB,UAAA,oBAAC,QAAD;GAAQ,SAAQ;GAAY,SAAA;GAAQ,WAAW,oBAAC,iBAAD,CAAkB,CAAA;GAC5D,UAAA,QAAQ,MAAM,WAAW,OAAO,UAAU,KAAK,CAAC,EAAE;EAC/C,CAAA;CACU,CAAA,GACtB,oBAAC,aAAa,SAAd;EAAsB,OAAM;EACxB,UAAA,oBAAC,aAAa,YAAd;GACW;GACP,gBAAgB,SAAS;IACrB,MAAM,SAAS,QAAQ,MAAM,WAAW,OAAO,UAAU,IAAI;IAE7D,IAAI,QAAQ,SAAS,OAAO,KAAK;GACrC;GAEC,UAAA,QAAQ,KAAK,WACV,oBAAC,aAAa,WAAd;IAA2C,OAAO,OAAO;IACpD,UAAA,OAAO;GACY,GAFK,OAAO,KAEZ,CAC3B;EACoB,CAAA;CACP,CAAA,CACZ,EAAA,CAAA;AAEtB"}
@@ -1,8 +1,9 @@
1
1
  import { ArtworkTabs, ArtworkTabsItem } from "./ArtworkTabs.js";
2
2
  import { Breadcrumbs } from "./Breadcrumbs.js";
3
3
  import { CollectionBrowseControls, CollectionBrowseSelector, CollectionBrowseTrigger } from "./CollectionBrowseSelector.js";
4
- import { CollectionView, CollectionViewToggle } from "./CollectionViewToggle.js";
4
+ import { CollectionView, CollectionViewToggle, ViewToggle, ViewToggleOption } from "./CollectionViewToggle.js";
5
5
  import { DrilldownBrowseGroup, DrilldownBrowseItem, DrilldownBrowseSelector } from "./DrilldownBrowseSelector.js";
6
6
  import { FolderSelector, FolderSelectorOption, FolderSelectorProps } from "./FolderSelector.js";
7
+ import { SortMenu } from "./SortMenu.js";
7
8
  import { ViewTabs, ViewTabsItem } from "./ViewTabs.js";
8
- export { ArtworkTabs, type ArtworkTabsItem, Breadcrumbs, CollectionBrowseControls, CollectionBrowseSelector, CollectionBrowseTrigger, type CollectionView, CollectionViewToggle, type DrilldownBrowseGroup, type DrilldownBrowseItem, DrilldownBrowseSelector, FolderSelector, type FolderSelectorOption, type FolderSelectorProps, ViewTabs, type ViewTabsItem };
9
+ export { ArtworkTabs, type ArtworkTabsItem, Breadcrumbs, CollectionBrowseControls, CollectionBrowseSelector, CollectionBrowseTrigger, type CollectionView, CollectionViewToggle, type DrilldownBrowseGroup, type DrilldownBrowseItem, DrilldownBrowseSelector, FolderSelector, type FolderSelectorOption, type FolderSelectorProps, SortMenu, ViewTabs, type ViewTabsItem, ViewToggle, type ViewToggleOption };
@@ -1,4 +1,16 @@
1
1
  import { ReactNode } from "react";
2
+ /** A chip before the field for something that narrows the list, such as a filter. */
3
+ export interface CommandPaletteToken {
4
+ id: string;
5
+ label: string;
6
+ /** An icon or colour mark before the label. */
7
+ leading?: ReactNode;
8
+ /** A button on the chip that takes it away; the focus stays in the field. */
9
+ remove?: {
10
+ label: string;
11
+ onRemove: () => void;
12
+ };
13
+ }
2
14
  interface CommandPaletteProps {
3
15
  /** The dialog's accessible title and description; the field says the rest. */
4
16
  label: string;
@@ -12,26 +24,48 @@ interface CommandPaletteProps {
12
24
  leaveLabel: string;
13
25
  onLeave: () => void;
14
26
  };
27
+ /** Chips before the field, such as active filters, which wrap and scroll on their own when there are many. A
28
+ * palette given tokens, even none, is a filtering search, as wide as its chips need. */
29
+ tokens?: readonly CommandPaletteToken[];
30
+ /** Backspace in an empty field, such as to take the last token away. */
31
+ onBackspaceEmpty?: () => void;
32
+ /** A control after the field, such as Clear. A press on it leaves the focus in the field. */
33
+ trailing?: ReactNode;
15
34
  /** The options' values in list order, for the arrow keys and Enter. */
16
35
  options: readonly string[];
17
- onSelect: (value: string) => void;
36
+ /** May return the option the highlight moves to, when choosing changes the list. */
37
+ onSelect: (value: string) => string | void;
18
38
  onClose: () => void;
19
39
  listLabel: string;
40
+ /** Marks the list busy while more may arrive; `busyLabel` shows under it meanwhile. */
20
41
  busy?: boolean;
21
- /** Shown when nothing is listed. */
42
+ busyLabel?: ReactNode;
43
+ /** Shown when nothing is listed and nothing is pending. */
22
44
  empty?: ReactNode;
23
45
  /** Quiet key hints under the list, on screens with a keyboard. */
24
46
  footer?: ReactNode;
25
47
  children: ReactNode;
26
48
  }
27
49
  /** T3 Code's command palette: a field over one keyboard list of grouped options, as a dialog over the page
28
- * or, on phones, the whole screen. The arrow keys move through `options`, Enter selects, Escape closes. */
29
- export declare function CommandPalette({ label, description, placeholder, query, onQueryChange, scope, options, onSelect, onClose, listLabel, busy, empty, footer, children }: CommandPaletteProps): import("react").JSX.Element;
50
+ * or, on phones, the whole screen. The arrow keys move through `options`, Enter selects, Escape closes. Tokens
51
+ * before the field say what narrows the list. */
52
+ export declare function CommandPalette({ label, description, placeholder, query, onQueryChange, scope, tokens: givenTokens, onBackspaceEmpty, trailing, options, onSelect, onClose, listLabel, busy, busyLabel, empty, footer, children }: CommandPaletteProps): import("react").JSX.Element;
30
53
  /** A labelled run of options in the palette's list. */
31
54
  export declare function CommandPaletteGroup({ label, children }: {
32
55
  label: string;
33
56
  children: ReactNode;
34
57
  }): import("react").JSX.Element;
58
+ /** One line of the palette's list: an icon, the name, an optional hint (searched with the name) and meta (on wider
59
+ * screens), and a tick while `checked`, as a filter that is on. Choosing it keeps the focus in the field. */
60
+ export declare function CommandPaletteOption({ value, icon, name, hint, meta, checked }: {
61
+ value: string;
62
+ icon: ReactNode;
63
+ name: string;
64
+ hint?: string;
65
+ meta?: string;
66
+ /** Whether a filter's option is on; other options leave it out. */
67
+ checked?: boolean;
68
+ }): import("react").JSX.Element;
35
69
  /** Props for a palette option, such as a `ResultRow`: its id, highlight and pointer tracking. */
36
70
  export declare function useCommandPaletteOption(value: string): {
37
71
  id: string;
@@ -5,14 +5,15 @@ import { Text } from "../typography/Typography.js";
5
5
  import { useModalAutoFocus } from "./useModalAutoFocus.js";
6
6
  import { useScrollFade } from "./useScrollFade.js";
7
7
  import { createContext, useContext, useEffect, useId, useRef, useState } from "react";
8
+ import { CheckIcon, SearchIcon, XIcon } from "lucide-react";
8
9
  import { jsx, jsxs } from "react/jsx-runtime";
9
- import { SearchIcon, XIcon } from "lucide-react";
10
10
  import { Modal } from "@ninna-ui/overlays";
11
11
  // src/overlays/CommandPalette.tsx
12
12
  const OptionContext = createContext(null);
13
13
  /** T3 Code's command palette: a field over one keyboard list of grouped options, as a dialog over the page
14
- * or, on phones, the whole screen. The arrow keys move through `options`, Enter selects, Escape closes. */
15
- function CommandPalette({ label, description, placeholder, query, onQueryChange, scope, options, onSelect, onClose, listLabel, busy = false, empty, footer, children }) {
14
+ * or, on phones, the whole screen. The arrow keys move through `options`, Enter selects, Escape closes. Tokens
15
+ * before the field say what narrows the list. */
16
+ function CommandPalette({ label, description, placeholder, query, onQueryChange, scope, tokens: givenTokens, onBackspaceEmpty, trailing, options, onSelect, onClose, listLabel, busy = false, busyLabel, empty, footer, children }) {
16
17
  const labels = useDesignSystemLabels();
17
18
  const focusProps = useModalAutoFocus();
18
19
  const { setViewport, setContent, className } = useScrollFade();
@@ -20,6 +21,20 @@ function CommandPalette({ label, description, placeholder, query, onQueryChange,
20
21
  const input = useRef(null);
21
22
  const [chosen, setActiveValue] = useState();
22
23
  const activeValue = chosen !== void 0 && options.includes(chosen) ? chosen : options[0];
24
+ const select = (value) => {
25
+ const next = onSelect(value);
26
+ if (next) setActiveValue(next);
27
+ };
28
+ const tokens = scope ? [{
29
+ id: "scope",
30
+ label: scope.label,
31
+ remove: {
32
+ label: scope.leaveLabel,
33
+ onRemove: scope.onLeave
34
+ }
35
+ }] : givenTokens ?? [];
36
+ const leaveLast = scope ? scope.onLeave : onBackspaceEmpty;
37
+ const rows = givenTokens !== void 0 || Boolean(trailing);
23
38
  useEffect(() => {
24
39
  if (activeValue) document.getElementById(optionId(listId, activeValue))?.scrollIntoView({ block: "nearest" });
25
40
  }, [activeValue, listId]);
@@ -31,55 +46,79 @@ function CommandPalette({ label, description, placeholder, query, onQueryChange,
31
46
  description,
32
47
  centered: false,
33
48
  ...focusProps,
34
- className: "flex max-h-[min(36rem,calc(100dvh-6rem))] w-[calc(100vw-2rem)] max-w-2xl flex-col overflow-hidden p-0 shadow-(--lar-shadow-dialog) max-sm:top-0 max-sm:left-0 max-sm:h-dvh max-sm:max-h-none max-sm:w-full max-sm:max-w-none max-sm:translate-x-0 max-sm:rounded-none! max-sm:border-0 max-sm:pt-[env(safe-area-inset-top)]",
49
+ "data-command-palette": true,
50
+ onEscapeKeyDown: (event) => {
51
+ if (event.isComposing) event.preventDefault();
52
+ },
53
+ className: `flex max-h-[min(36rem,calc(100dvh-6rem))] w-[calc(100vw-2rem)] max-w-2xl flex-col overflow-hidden p-0 shadow-(--lar-shadow-dialog) max-sm:top-0 max-sm:left-0 max-sm:h-dvh max-sm:max-h-none max-sm:w-full max-sm:max-w-none max-sm:translate-x-0 max-sm:rounded-none! max-sm:border-0 max-sm:pt-[env(safe-area-inset-top)] ${rows ? "max-sm:pb-[env(safe-area-inset-bottom)] sm:w-[calc(100vw-2rem)] sm:max-w-2xl" : ""}`,
35
54
  children: [
36
55
  /* @__PURE__ */ jsxs("div", {
37
- className: "border-base-300 [&>svg]:text-base-600 flex shrink-0 items-center gap-2 border-b px-4 py-3 [&>svg]:size-4 [&>svg]:shrink-0",
56
+ className: `border-base-300 [&>svg]:text-base-600 flex shrink-0 gap-2 border-b px-4 [&>svg]:size-4 [&>svg]:shrink-0 ${rows ? "items-start py-2 [&>svg]:mt-2" : "items-center py-3"}`,
38
57
  children: [
39
58
  /* @__PURE__ */ jsx(SearchIcon, {}),
40
- scope ? /* @__PURE__ */ jsxs("span", {
41
- className: "bg-primary/12 text-primary flex shrink-0 items-center gap-1 rounded-md py-0.5 pr-1 pl-2 text-xs font-medium",
42
- children: [scope.label, /* @__PURE__ */ jsx("button", {
43
- type: "button",
44
- tabIndex: -1,
45
- "aria-label": scope.leaveLabel,
46
- className: "hover:bg-primary/15 rounded-sm p-0.5 [&>svg]:size-3",
47
- onClick: () => {
48
- scope.onLeave();
49
- input.current?.focus();
50
- },
51
- children: /* @__PURE__ */ jsx(XIcon, {})
52
- })]
53
- }) : null,
54
- /* @__PURE__ */ jsx("input", {
55
- ref: input,
56
- role: "combobox",
57
- "aria-label": label,
58
- "aria-expanded": true,
59
- "aria-controls": listId,
60
- "aria-autocomplete": "list",
61
- "aria-activedescendant": activeValue ? optionId(listId, activeValue) : void 0,
62
- "aria-busy": busy,
63
- placeholder,
64
- value: query,
65
- className: "text-base-content placeholder:text-base-600 min-w-0 flex-1 bg-transparent text-base outline-none sm:text-sm",
66
- onChange: (event) => onQueryChange(event.target.value),
67
- onKeyDown: (event) => {
68
- if (event.nativeEvent.isComposing) return;
69
- if (event.key === "Backspace" && !query && scope) {
70
- event.preventDefault();
71
- scope.onLeave();
72
- } else if ((event.key === "ArrowDown" || event.key === "ArrowUp") && options.length) {
73
- event.preventDefault();
74
- const index = activeValue ? options.indexOf(activeValue) : -1;
75
- const step = event.key === "ArrowDown" ? 1 : -1;
76
- setActiveValue(options[(index + step + options.length) % options.length]);
77
- } else if (event.key === "Enter" && activeValue) {
78
- event.preventDefault();
79
- onSelect(activeValue);
59
+ /* @__PURE__ */ jsxs("div", {
60
+ className: `flex min-w-0 flex-1 items-center gap-x-2 ${rows ? "flex-wrap gap-y-1" : ""}`,
61
+ children: [tokens.length > 0 ? /* @__PURE__ */ jsx("ul", {
62
+ className: `flex max-w-full min-w-0 shrink-0 items-center gap-1 ${rows ? "max-h-19 flex-wrap overflow-y-auto overscroll-contain py-1 pointer-coarse:max-h-22 pointer-coarse:gap-y-3 pointer-coarse:py-1.5" : ""}`,
63
+ children: tokens.map((token) => /* @__PURE__ */ jsxs("li", {
64
+ className: `bg-primary/12 text-primary flex max-w-full min-w-0 shrink-0 items-center gap-1 rounded-md py-0.5 pr-1 pl-2 text-xs font-medium ${rows ? "dark:text-base-content pointer-coarse:min-h-8 pointer-coarse:py-0 pointer-coarse:pr-0" : ""}`,
65
+ children: [
66
+ token.leading ? /* @__PURE__ */ jsx("span", {
67
+ className: "flex shrink-0 items-center [&>svg]:size-3.5",
68
+ children: token.leading
69
+ }) : null,
70
+ /* @__PURE__ */ jsx("span", {
71
+ className: "min-w-0 truncate",
72
+ children: token.label
73
+ }),
74
+ token.remove ? /* @__PURE__ */ jsx("button", {
75
+ type: "button",
76
+ tabIndex: scope ? -1 : void 0,
77
+ "aria-label": token.remove.label,
78
+ className: `hover:bg-primary/15 grid shrink-0 place-items-center rounded-sm p-0.5 [&>svg]:size-3 ${rows ? "pointer-coarse:-my-1.5 pointer-coarse:size-11 pointer-coarse:p-0" : ""}`,
79
+ onClick: () => {
80
+ token.remove?.onRemove();
81
+ input.current?.focus();
82
+ },
83
+ children: /* @__PURE__ */ jsx(XIcon, {})
84
+ }) : null
85
+ ]
86
+ }, token.id))
87
+ }) : null, /* @__PURE__ */ jsx("input", {
88
+ ref: input,
89
+ role: "combobox",
90
+ "aria-label": label,
91
+ "aria-expanded": true,
92
+ "aria-controls": listId,
93
+ "aria-autocomplete": "list",
94
+ "aria-activedescendant": activeValue ? optionId(listId, activeValue) : void 0,
95
+ "aria-busy": busy,
96
+ placeholder,
97
+ value: query,
98
+ className: `text-base-content placeholder:text-base-600 min-w-0 flex-1 bg-transparent text-base outline-none sm:text-sm ${rows ? "h-8 min-w-32" : ""}`,
99
+ onChange: (event) => onQueryChange(event.target.value),
100
+ onKeyDown: (event) => {
101
+ if (event.nativeEvent.isComposing) return;
102
+ if (event.key === "Backspace" && !query && leaveLast) {
103
+ event.preventDefault();
104
+ leaveLast();
105
+ } else if ((event.key === "ArrowDown" || event.key === "ArrowUp") && options.length) {
106
+ event.preventDefault();
107
+ const index = activeValue ? options.indexOf(activeValue) : -1;
108
+ const step = event.key === "ArrowDown" ? 1 : -1;
109
+ setActiveValue(options[(index + step + options.length) % options.length]);
110
+ } else if (event.key === "Enter" && activeValue) {
111
+ event.preventDefault();
112
+ select(activeValue);
113
+ }
80
114
  }
81
- }
115
+ })]
82
116
  }),
117
+ trailing ? /* @__PURE__ */ jsx("div", {
118
+ className: "flex min-h-8 shrink-0 items-center pointer-coarse:[&_[data-slot=button]]:h-11!",
119
+ onClick: () => input.current?.focus(),
120
+ children: trailing
121
+ }) : null,
83
122
  /* @__PURE__ */ jsx("span", {
84
123
  className: "flex sm:hidden",
85
124
  children: /* @__PURE__ */ jsx(IconButton, {
@@ -101,7 +140,8 @@ function CommandPalette({ label, description, placeholder, query, onQueryChange,
101
140
  value: {
102
141
  listId,
103
142
  activeValue,
104
- setActiveValue
143
+ setActiveValue,
144
+ select
105
145
  },
106
146
  children: /* @__PURE__ */ jsx(ResultList, {
107
147
  id: listId,
@@ -110,11 +150,15 @@ function CommandPalette({ label, description, placeholder, query, onQueryChange,
110
150
  "aria-busy": busy,
111
151
  children
112
152
  })
113
- }), options.length === 0 && empty ? /* @__PURE__ */ jsx(Text, {
114
- tone: "muted",
115
- className: "px-3 py-8 text-center",
116
- children: empty
117
- }) : null]
153
+ }), /* @__PURE__ */ jsx("div", {
154
+ role: "status",
155
+ children: busy && busyLabel || options.length === 0 && empty ? /* @__PURE__ */ jsx(Text, {
156
+ as: "div",
157
+ tone: "muted",
158
+ className: "px-3 py-8 text-center",
159
+ children: busy && busyLabel ? busyLabel : empty
160
+ }) : null
161
+ })]
118
162
  })
119
163
  }),
120
164
  footer ? /* @__PURE__ */ jsx("div", {
@@ -142,6 +186,48 @@ function CommandPaletteGroup({ label, children }) {
142
186
  }), children]
143
187
  });
144
188
  }
189
+ /** One line of the palette's list: an icon, the name, an optional hint (searched with the name) and meta (on wider
190
+ * screens), and a tick while `checked`, as a filter that is on. Choosing it keeps the focus in the field. */
191
+ function CommandPaletteOption({ value, icon, name, hint, meta, checked }) {
192
+ const context = useContext(OptionContext);
193
+ if (!context) throw new Error("CommandPaletteOption must be used inside CommandPalette");
194
+ return /* @__PURE__ */ jsxs("div", {
195
+ id: optionId(context.listId, value),
196
+ role: "option",
197
+ "aria-selected": context.activeValue === value,
198
+ "aria-checked": checked,
199
+ tabIndex: -1,
200
+ onPointerMove: () => {
201
+ if (context.activeValue !== value) context.setActiveValue(value);
202
+ },
203
+ onMouseDown: (event) => event.preventDefault(),
204
+ onClick: () => context.select(value),
205
+ className: "text-base-800 aria-selected:bg-primary/10 aria-selected:ring-primary/30 dark:text-base-content flex h-8 cursor-pointer items-center gap-2 rounded-md px-2 text-sm aria-selected:ring-1 aria-selected:ring-inset pointer-coarse:h-11",
206
+ children: [
207
+ /* @__PURE__ */ jsx("span", {
208
+ className: "text-base-700 grid size-4 shrink-0 place-items-center [&>svg]:size-3.5",
209
+ children: icon
210
+ }),
211
+ /* @__PURE__ */ jsx("span", {
212
+ title: name,
213
+ className: "min-w-0 flex-1 truncate",
214
+ children: name
215
+ }),
216
+ hint ? /* @__PURE__ */ jsx("span", {
217
+ className: "text-base-700 max-w-40 shrink-0 truncate text-xs tabular-nums",
218
+ children: hint
219
+ }) : null,
220
+ meta ? /* @__PURE__ */ jsx("span", {
221
+ className: "text-base-700 max-w-56 shrink-0 truncate text-xs max-sm:hidden",
222
+ children: meta
223
+ }) : null,
224
+ checked ? /* @__PURE__ */ jsx(CheckIcon, {
225
+ "aria-hidden": "true",
226
+ className: "text-primary size-3.5 shrink-0"
227
+ }) : null
228
+ ]
229
+ });
230
+ }
145
231
  /** Props for a palette option, such as a `ResultRow`: its id, highlight and pointer tracking. */
146
232
  function useCommandPaletteOption(value) {
147
233
  const context = useContext(OptionContext);
@@ -156,8 +242,8 @@ function useCommandPaletteOption(value) {
156
242
  };
157
243
  }
158
244
  function optionId(listId, value) {
159
- return `${listId}-${value.replace(/[^\w-]/g, "_")}`;
245
+ return `${listId}-${encodeURIComponent(value)}`;
160
246
  }
161
- export { CommandPalette, CommandPaletteGroup, useCommandPaletteOption };
247
+ export { CommandPalette, CommandPaletteGroup, CommandPaletteOption, useCommandPaletteOption };
162
248
 
163
249
  //# sourceMappingURL=CommandPalette.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CommandPalette.js","names":["NinnaModal"],"sources":["../../src/overlays/CommandPalette.tsx"],"sourcesContent":["/* oxlint-disable react/only-export-components -- The option hook belongs to the palette. */\n\nimport { Modal as NinnaModal } from '@ninna-ui/overlays';\nimport { SearchIcon, XIcon } from 'lucide-react';\nimport { createContext, type ReactNode, useContext, useEffect, useId, useRef, useState } from 'react';\n\nimport { IconButton } from '../actions/IconButton';\nimport { ResultList } from '../collections/ResultList';\nimport { useDesignSystemLabels } from '../foundations/DesignSystemProvider';\nimport { Text } from '../typography/Typography';\nimport { useModalAutoFocus } from './useModalAutoFocus';\nimport { useScrollFade } from './useScrollFade';\n\ninterface CommandPaletteProps {\n /** The dialog's accessible title and description; the field says the rest. */\n label: string;\n description: string;\n placeholder: string;\n query: string;\n onQueryChange: (query: string) => void;\n /** Narrows the list to one level, shown as a chip before the field; Backspace in an empty field leaves it. */\n scope?: { label: string; leaveLabel: string; onLeave: () => void };\n /** The options' values in list order, for the arrow keys and Enter. */\n options: readonly string[];\n onSelect: (value: string) => void;\n onClose: () => void;\n listLabel: string;\n busy?: boolean;\n /** Shown when nothing is listed. */\n empty?: ReactNode;\n /** Quiet key hints under the list, on screens with a keyboard. */\n footer?: ReactNode;\n children: ReactNode;\n}\n\nconst OptionContext = createContext<{\n listId: string;\n activeValue: string | undefined;\n setActiveValue: (value: string) => void;\n} | null>(null);\n\n/** T3 Code's command palette: a field over one keyboard list of grouped options, as a dialog over the page\n * or, on phones, the whole screen. The arrow keys move through `options`, Enter selects, Escape closes. */\nexport function CommandPalette({\n label,\n description,\n placeholder,\n query,\n onQueryChange,\n scope,\n options,\n onSelect,\n onClose,\n listLabel,\n busy = false,\n empty,\n footer,\n children,\n}: CommandPaletteProps) {\n const labels = useDesignSystemLabels();\n const focusProps = useModalAutoFocus();\n const { setViewport, setContent, className } = useScrollFade();\n const listId = useId();\n const input = useRef<HTMLInputElement>(null);\n const [chosen, setActiveValue] = useState<string>();\n // The highlight follows the list: when the chosen option leaves it, the first option takes over.\n const activeValue = chosen !== undefined && options.includes(chosen) ? chosen : options[0];\n\n useEffect(() => {\n if (activeValue) document.getElementById(optionId(listId, activeValue))?.scrollIntoView({ block: 'nearest' });\n }, [activeValue, listId]);\n\n return (\n <NinnaModal open onOpenChange={(open) => !open && onClose()}>\n <NinnaModal.Content\n title={label}\n description={description}\n centered={false}\n {...focusProps}\n className=\"flex max-h-[min(36rem,calc(100dvh-6rem))] w-[calc(100vw-2rem)] max-w-2xl flex-col overflow-hidden p-0 shadow-(--lar-shadow-dialog) max-sm:top-0 max-sm:left-0 max-sm:h-dvh max-sm:max-h-none max-sm:w-full max-sm:max-w-none max-sm:translate-x-0 max-sm:rounded-none! max-sm:border-0 max-sm:pt-[env(safe-area-inset-top)]\"\n >\n <div className=\"border-base-300 [&>svg]:text-base-600 flex shrink-0 items-center gap-2 border-b px-4 py-3 [&>svg]:size-4 [&>svg]:shrink-0\">\n <SearchIcon />\n {scope ? (\n <span className=\"bg-primary/12 text-primary flex shrink-0 items-center gap-1 rounded-md py-0.5 pr-1 pl-2 text-xs font-medium\">\n {scope.label}\n <button\n type=\"button\"\n tabIndex={-1}\n aria-label={scope.leaveLabel}\n className=\"hover:bg-primary/15 rounded-sm p-0.5 [&>svg]:size-3\"\n onClick={() => {\n scope.onLeave();\n input.current?.focus();\n }}\n >\n <XIcon />\n </button>\n </span>\n ) : null}\n <input\n ref={input}\n role=\"combobox\"\n aria-label={label}\n aria-expanded\n aria-controls={listId}\n aria-autocomplete=\"list\"\n aria-activedescendant={activeValue ? optionId(listId, activeValue) : undefined}\n aria-busy={busy}\n placeholder={placeholder}\n value={query}\n className=\"text-base-content placeholder:text-base-600 min-w-0 flex-1 bg-transparent text-base outline-none sm:text-sm\"\n onChange={(event) => onQueryChange(event.target.value)}\n onKeyDown={(event) => {\n if (event.nativeEvent.isComposing) return;\n\n if (event.key === 'Backspace' && !query && scope) {\n event.preventDefault();\n scope.onLeave();\n } else if ((event.key === 'ArrowDown' || event.key === 'ArrowUp') && options.length) {\n event.preventDefault();\n\n const index = activeValue ? options.indexOf(activeValue) : -1;\n const step = event.key === 'ArrowDown' ? 1 : -1;\n\n setActiveValue(options[(index + step + options.length) % options.length]!);\n } else if (event.key === 'Enter' && activeValue) {\n event.preventDefault();\n onSelect(activeValue);\n }\n }}\n />\n <span className=\"flex sm:hidden\">\n <IconButton aria-label={labels.close} icon={<XIcon />} onClick={onClose} variant=\"header\" />\n </span>\n </div>\n <div ref={setViewport} className={`min-h-0 flex-1 overflow-y-auto overscroll-contain p-2 ${className}`}>\n <div ref={setContent} className=\"flow-root\">\n <OptionContext.Provider value={{ listId, activeValue, setActiveValue }}>\n <ResultList id={listId} label={listLabel} density=\"compact\" aria-busy={busy}>\n {children}\n </ResultList>\n </OptionContext.Provider>\n {options.length === 0 && empty ? (\n <Text tone=\"muted\" className=\"px-3 py-8 text-center\">\n {empty}\n </Text>\n ) : null}\n </div>\n </div>\n {footer ? (\n <div className=\"border-base-300 text-2xs text-base-700 hidden shrink-0 items-center gap-4 border-t px-4 py-2 pointer-fine:flex\">\n {footer}\n </div>\n ) : null}\n </NinnaModal.Content>\n </NinnaModal>\n );\n}\n\n/** A labelled run of options in the palette's list. */\nexport function CommandPaletteGroup({ label, children }: { label: string; children: ReactNode }) {\n const labelId = useId();\n\n return (\n <div role=\"group\" aria-labelledby={labelId} className=\"flex flex-col gap-1 not-first:pt-2\">\n <Text\n as=\"span\"\n id={labelId}\n variant=\"caption\"\n tone=\"muted\"\n className=\"px-2 pt-1 font-medium tracking-wide uppercase\"\n >\n {label}\n </Text>\n {children}\n </div>\n );\n}\n\n/** Props for a palette option, such as a `ResultRow`: its id, highlight and pointer tracking. */\nexport function useCommandPaletteOption(value: string) {\n const context = useContext(OptionContext);\n\n if (!context) throw new Error('useCommandPaletteOption must be used inside CommandPalette');\n\n return {\n id: optionId(context.listId, value),\n selected: context.activeValue === value,\n tabIndex: -1,\n onPointerMove: () => {\n if (context.activeValue !== value) context.setActiveValue(value);\n },\n };\n}\n\nfunction optionId(listId: string, value: string) {\n return `${listId}-${value.replace(/[^\\w-]/g, '_')}`;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"CommandPalette.js","names":["NinnaModal"],"sources":["../../src/overlays/CommandPalette.tsx"],"sourcesContent":["/* oxlint-disable react/only-export-components -- The option hook belongs to the palette. */\n\nimport { Modal as NinnaModal } from '@ninna-ui/overlays';\nimport { CheckIcon, SearchIcon, XIcon } from 'lucide-react';\nimport { createContext, type ReactNode, useContext, useEffect, useId, useRef, useState } from 'react';\n\nimport { IconButton } from '../actions/IconButton';\nimport { ResultList } from '../collections/ResultList';\nimport { useDesignSystemLabels } from '../foundations/DesignSystemProvider';\nimport { Text } from '../typography/Typography';\nimport { useModalAutoFocus } from './useModalAutoFocus';\nimport { useScrollFade } from './useScrollFade';\n\n/** A chip before the field for something that narrows the list, such as a filter. */\nexport interface CommandPaletteToken {\n id: string;\n label: string;\n /** An icon or colour mark before the label. */\n leading?: ReactNode;\n /** A button on the chip that takes it away; the focus stays in the field. */\n remove?: { label: string; onRemove: () => void };\n}\n\ninterface CommandPaletteProps {\n /** The dialog's accessible title and description; the field says the rest. */\n label: string;\n description: string;\n placeholder: string;\n query: string;\n onQueryChange: (query: string) => void;\n /** Narrows the list to one level, shown as a chip before the field; Backspace in an empty field leaves it. */\n scope?: { label: string; leaveLabel: string; onLeave: () => void };\n /** Chips before the field, such as active filters, which wrap and scroll on their own when there are many. A\n * palette given tokens, even none, is a filtering search, as wide as its chips need. */\n tokens?: readonly CommandPaletteToken[];\n /** Backspace in an empty field, such as to take the last token away. */\n onBackspaceEmpty?: () => void;\n /** A control after the field, such as Clear. A press on it leaves the focus in the field. */\n trailing?: ReactNode;\n /** The options' values in list order, for the arrow keys and Enter. */\n options: readonly string[];\n /** May return the option the highlight moves to, when choosing changes the list. */\n onSelect: (value: string) => string | void;\n onClose: () => void;\n listLabel: string;\n /** Marks the list busy while more may arrive; `busyLabel` shows under it meanwhile. */\n busy?: boolean;\n busyLabel?: ReactNode;\n /** Shown when nothing is listed and nothing is pending. */\n empty?: ReactNode;\n /** Quiet key hints under the list, on screens with a keyboard. */\n footer?: ReactNode;\n children: ReactNode;\n}\n\nconst OptionContext = createContext<{\n listId: string;\n activeValue: string | undefined;\n setActiveValue: (value: string) => void;\n select: (value: string) => void;\n} | null>(null);\n\n/** T3 Code's command palette: a field over one keyboard list of grouped options, as a dialog over the page\n * or, on phones, the whole screen. The arrow keys move through `options`, Enter selects, Escape closes. Tokens\n * before the field say what narrows the list. */\nexport function CommandPalette({\n label,\n description,\n placeholder,\n query,\n onQueryChange,\n scope,\n tokens: givenTokens,\n onBackspaceEmpty,\n trailing,\n options,\n onSelect,\n onClose,\n listLabel,\n busy = false,\n busyLabel,\n empty,\n footer,\n children,\n}: CommandPaletteProps) {\n const labels = useDesignSystemLabels();\n const focusProps = useModalAutoFocus();\n const { setViewport, setContent, className } = useScrollFade();\n const listId = useId();\n const input = useRef<HTMLInputElement>(null);\n const [chosen, setActiveValue] = useState<string>();\n // The highlight follows the list: when the chosen option leaves it, the first option takes over.\n const activeValue = chosen !== undefined && options.includes(chosen) ? chosen : options[0];\n const select = (value: string) => {\n const next = onSelect(value);\n\n if (next) setActiveValue(next);\n };\n // A scope is the one token of a palette that narrows by levels.\n const tokens: readonly CommandPaletteToken[] = scope\n ? [{ id: 'scope', label: scope.label, remove: { label: scope.leaveLabel, onRemove: scope.onLeave } }]\n : (givenTokens ?? []);\n const leaveLast = scope ? scope.onLeave : onBackspaceEmpty;\n // A palette that takes tokens, or a trailing control, is a filtering search: wide, with its field wrapping onto\n // rows under the tokens, from the top.\n const rows = givenTokens !== undefined || Boolean(trailing);\n\n useEffect(() => {\n if (activeValue) document.getElementById(optionId(listId, activeValue))?.scrollIntoView({ block: 'nearest' });\n }, [activeValue, listId]);\n\n return (\n <NinnaModal open onOpenChange={(open) => !open && onClose()}>\n <NinnaModal.Content\n title={label}\n description={description}\n centered={false}\n {...focusProps}\n data-command-palette\n // The dialog listens for Escape on the document, past the field's own keys; an input method's Escape\n // only ends its composition.\n onEscapeKeyDown={(event) => {\n if (event.isComposing) event.preventDefault();\n }}\n className={`flex max-h-[min(36rem,calc(100dvh-6rem))] w-[calc(100vw-2rem)] max-w-2xl flex-col overflow-hidden p-0 shadow-(--lar-shadow-dialog) max-sm:top-0 max-sm:left-0 max-sm:h-dvh max-sm:max-h-none max-sm:w-full max-sm:max-w-none max-sm:translate-x-0 max-sm:rounded-none! max-sm:border-0 max-sm:pt-[env(safe-area-inset-top)] ${rows ? 'max-sm:pb-[env(safe-area-inset-bottom)] sm:w-[calc(100vw-2rem)] sm:max-w-2xl' : ''}`}\n >\n <div\n className={`border-base-300 [&>svg]:text-base-600 flex shrink-0 gap-2 border-b px-4 [&>svg]:size-4 [&>svg]:shrink-0 ${rows ? 'items-start py-2 [&>svg]:mt-2' : 'items-center py-3'}`}\n >\n <SearchIcon />\n <div className={`flex min-w-0 flex-1 items-center gap-x-2 ${rows ? 'flex-wrap gap-y-1' : ''}`}>\n {tokens.length > 0 ? (\n // Many tokens scroll on their own, so the field stays in view however many there are. Under\n // a coarse pointer each remove button is 44 px, reaching into the gap between rows.\n <ul\n className={`flex max-w-full min-w-0 shrink-0 items-center gap-1 ${rows ? 'max-h-19 flex-wrap overflow-y-auto overscroll-contain py-1 pointer-coarse:max-h-22 pointer-coarse:gap-y-3 pointer-coarse:py-1.5' : ''}`}\n >\n {tokens.map((token) => (\n <li\n key={token.id}\n className={`bg-primary/12 text-primary flex max-w-full min-w-0 shrink-0 items-center gap-1 rounded-md py-0.5 pr-1 pl-2 text-xs font-medium ${rows ? 'dark:text-base-content pointer-coarse:min-h-8 pointer-coarse:py-0 pointer-coarse:pr-0' : ''}`}\n >\n {token.leading ? (\n <span className=\"flex shrink-0 items-center [&>svg]:size-3.5\">\n {token.leading}\n </span>\n ) : null}\n <span className=\"min-w-0 truncate\">{token.label}</span>\n {token.remove ? (\n <button\n type=\"button\"\n // A scope's chip leaves with Backspace alone; several tokens' buttons are tab stops.\n tabIndex={scope ? -1 : undefined}\n aria-label={token.remove.label}\n className={`hover:bg-primary/15 grid shrink-0 place-items-center rounded-sm p-0.5 [&>svg]:size-3 ${rows ? 'pointer-coarse:-my-1.5 pointer-coarse:size-11 pointer-coarse:p-0' : ''}`}\n onClick={() => {\n token.remove?.onRemove();\n input.current?.focus();\n }}\n >\n <XIcon />\n </button>\n ) : null}\n </li>\n ))}\n </ul>\n ) : null}\n <input\n ref={input}\n role=\"combobox\"\n aria-label={label}\n aria-expanded\n aria-controls={listId}\n aria-autocomplete=\"list\"\n aria-activedescendant={activeValue ? optionId(listId, activeValue) : undefined}\n aria-busy={busy}\n placeholder={placeholder}\n value={query}\n className={`text-base-content placeholder:text-base-600 min-w-0 flex-1 bg-transparent text-base outline-none sm:text-sm ${rows ? 'h-8 min-w-32' : ''}`}\n onChange={(event) => onQueryChange(event.target.value)}\n onKeyDown={(event) => {\n if (event.nativeEvent.isComposing) return;\n\n if (event.key === 'Backspace' && !query && leaveLast) {\n event.preventDefault();\n leaveLast();\n } else if ((event.key === 'ArrowDown' || event.key === 'ArrowUp') && options.length) {\n event.preventDefault();\n\n const index = activeValue ? options.indexOf(activeValue) : -1;\n const step = event.key === 'ArrowDown' ? 1 : -1;\n\n setActiveValue(options[(index + step + options.length) % options.length]!);\n } else if (event.key === 'Enter' && activeValue) {\n event.preventDefault();\n select(activeValue);\n }\n }}\n />\n </div>\n {trailing ? (\n // Under a coarse pointer the control is 44 px, as a token's remove button is.\n <div\n className=\"flex min-h-8 shrink-0 items-center pointer-coarse:[&_[data-slot=button]]:h-11!\"\n onClick={() => input.current?.focus()}\n >\n {trailing}\n </div>\n ) : null}\n <span className=\"flex sm:hidden\">\n <IconButton aria-label={labels.close} icon={<XIcon />} onClick={onClose} variant=\"header\" />\n </span>\n </div>\n <div ref={setViewport} className={`min-h-0 flex-1 overflow-y-auto overscroll-contain p-2 ${className}`}>\n <div ref={setContent} className=\"flow-root\">\n <OptionContext.Provider value={{ listId, activeValue, setActiveValue, select }}>\n <ResultList id={listId} label={listLabel} density=\"compact\" aria-busy={busy}>\n {children}\n </ResultList>\n </OptionContext.Provider>\n <div role=\"status\">\n {(busy && busyLabel) || (options.length === 0 && empty) ? (\n <Text as=\"div\" tone=\"muted\" className=\"px-3 py-8 text-center\">\n {busy && busyLabel ? busyLabel : empty}\n </Text>\n ) : null}\n </div>\n </div>\n </div>\n {footer ? (\n <div className=\"border-base-300 text-2xs text-base-700 hidden shrink-0 items-center gap-4 border-t px-4 py-2 pointer-fine:flex\">\n {footer}\n </div>\n ) : null}\n </NinnaModal.Content>\n </NinnaModal>\n );\n}\n\n/** A labelled run of options in the palette's list. */\nexport function CommandPaletteGroup({ label, children }: { label: string; children: ReactNode }) {\n const labelId = useId();\n\n return (\n <div role=\"group\" aria-labelledby={labelId} className=\"flex flex-col gap-1 not-first:pt-2\">\n <Text\n as=\"span\"\n id={labelId}\n variant=\"caption\"\n tone=\"muted\"\n className=\"px-2 pt-1 font-medium tracking-wide uppercase\"\n >\n {label}\n </Text>\n {children}\n </div>\n );\n}\n\n/** One line of the palette's list: an icon, the name, an optional hint (searched with the name) and meta (on wider\n * screens), and a tick while `checked`, as a filter that is on. Choosing it keeps the focus in the field. */\nexport function CommandPaletteOption({\n value,\n icon,\n name,\n hint,\n meta,\n checked,\n}: {\n value: string;\n icon: ReactNode;\n name: string;\n hint?: string;\n meta?: string;\n /** Whether a filter's option is on; other options leave it out. */\n checked?: boolean;\n}) {\n const context = useContext(OptionContext);\n\n if (!context) throw new Error('CommandPaletteOption must be used inside CommandPalette');\n\n return (\n <div\n id={optionId(context.listId, value)}\n role=\"option\"\n aria-selected={context.activeValue === value}\n aria-checked={checked}\n tabIndex={-1}\n onPointerMove={() => {\n if (context.activeValue !== value) context.setActiveValue(value);\n }}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => context.select(value)}\n className=\"text-base-800 aria-selected:bg-primary/10 aria-selected:ring-primary/30 dark:text-base-content flex h-8 cursor-pointer items-center gap-2 rounded-md px-2 text-sm aria-selected:ring-1 aria-selected:ring-inset pointer-coarse:h-11\"\n >\n <span className=\"text-base-700 grid size-4 shrink-0 place-items-center [&>svg]:size-3.5\">{icon}</span>\n <span title={name} className=\"min-w-0 flex-1 truncate\">\n {name}\n </span>\n {hint ? (\n <span className=\"text-base-700 max-w-40 shrink-0 truncate text-xs tabular-nums\">{hint}</span>\n ) : null}\n {meta ? (\n <span className=\"text-base-700 max-w-56 shrink-0 truncate text-xs max-sm:hidden\">{meta}</span>\n ) : null}\n {checked ? <CheckIcon aria-hidden=\"true\" className=\"text-primary size-3.5 shrink-0\" /> : null}\n </div>\n );\n}\n\n/** Props for a palette option, such as a `ResultRow`: its id, highlight and pointer tracking. */\nexport function useCommandPaletteOption(value: string) {\n const context = useContext(OptionContext);\n\n if (!context) throw new Error('useCommandPaletteOption must be used inside CommandPalette');\n\n return {\n id: optionId(context.listId, value),\n selected: context.activeValue === value,\n tabIndex: -1,\n onPointerMove: () => {\n if (context.activeValue !== value) context.setActiveValue(value);\n },\n };\n}\n\nfunction optionId(listId: string, value: string) {\n return `${listId}-${encodeURIComponent(value)}`;\n}\n"],"mappings":"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"}