@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,283 @@
1
+ // The Markdown editor: Lexical, formatting as you type and storing Markdown, under a light toolbar. "- " starts a
2
+ // bullet list, "1. " a numbered list, "# " a heading and **bold** turns bold; pasted plain-text Markdown renders. It
3
+ // opens HTML, as an older Azure DevOps description holds, as the nodes it stands for, and still reports Markdown.
4
+
5
+ import { CodeNode } from '@lexical/code';
6
+ import { $generateNodesFromDOM } from '@lexical/html';
7
+ import { LinkNode } from '@lexical/link';
8
+ import { $isListItemNode, ListItemNode, ListNode } from '@lexical/list';
9
+ import {
10
+ $convertFromMarkdownString,
11
+ $convertToMarkdownString,
12
+ $generateNodesFromMarkdownString,
13
+ TRANSFORMERS,
14
+ } from '@lexical/markdown';
15
+ import { AutoFocusPlugin } from '@lexical/react/LexicalAutoFocusPlugin';
16
+ import { LexicalComposer } from '@lexical/react/LexicalComposer';
17
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
18
+ import { ContentEditable } from '@lexical/react/LexicalContentEditable';
19
+ import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';
20
+ import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
21
+ import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin';
22
+ import { ListPlugin } from '@lexical/react/LexicalListPlugin';
23
+ import { MarkdownShortcutPlugin } from '@lexical/react/LexicalMarkdownShortcutPlugin';
24
+ import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
25
+ import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
26
+ import { HeadingNode, QuoteNode } from '@lexical/rich-text';
27
+ import {
28
+ $findMatchingParent,
29
+ $getRoot,
30
+ $getSelection,
31
+ $insertNodes,
32
+ $isParagraphNode,
33
+ $isRangeSelection,
34
+ COMMAND_PRIORITY_EDITOR,
35
+ COMMAND_PRIORITY_HIGH,
36
+ INDENT_CONTENT_COMMAND,
37
+ KEY_TAB_COMMAND,
38
+ OUTDENT_CONTENT_COMMAND,
39
+ PASTE_COMMAND,
40
+ } from 'lexical';
41
+ import type { EditorState, LexicalEditor, LexicalNode } from 'lexical';
42
+ import { useCallback, useEffect } from 'react';
43
+
44
+ import type { RichTextFormat } from '../display/RichText';
45
+ import { MarkdownToolbar } from './MarkdownToolbar';
46
+
47
+ const theme = {
48
+ heading: {
49
+ h1: 'text-xl font-semibold mt-4 mb-1.5 first:mt-0',
50
+ h2: 'text-lg font-semibold mt-4 mb-1 first:mt-0',
51
+ h3: 'font-semibold mt-3 mb-1 first:mt-0',
52
+ },
53
+ list: {
54
+ ul: 'list-disc ps-6 my-1.5',
55
+ ol: 'list-decimal ps-6 my-1.5',
56
+ listitem: 'my-0.5 marker:text-base-500',
57
+ nested: { listitem: 'list-none' },
58
+ },
59
+ paragraph: 'my-1.5 first:mt-0',
60
+ quote: 'border-s-2 border-base-300 ps-3 text-base-700 my-1.5',
61
+ code: 'block rounded-md bg-base-200 p-3 font-mono text-xs my-1.5 whitespace-pre-wrap',
62
+ link: 'text-(--lar-info-text) underline underline-offset-2',
63
+ text: {
64
+ bold: 'font-semibold',
65
+ italic: 'italic',
66
+ strikethrough: 'line-through',
67
+ code: 'rounded bg-base-200 px-1 font-mono text-[0.85em]',
68
+ },
69
+ };
70
+
71
+ const LOOKS_LIKE_MARKDOWN = /(^|\n)\s*([-*+] |\d+[.)] |#{1,6} |> |```)|\*\*[^*]+\*\*|\[[^\]]+\]\([^)]+\)/;
72
+
73
+ /** Puts pasted `nodes` in place of the selected text. Ones starting with a heading, list, quote or code block go in after
74
+ * the block the caret is in, unless it is empty, as inserted at the caret the first block's text would join that block's. */
75
+ function $insertPasted(nodes: LexicalNode[]) {
76
+ const selection = $getSelection();
77
+
78
+ if ($isRangeSelection(selection)) selection.removeText();
79
+
80
+ const block = $isRangeSelection(selection) ? selection.anchor.getNode().getTopLevelElement() : null;
81
+ const first = nodes[0];
82
+
83
+ if (!block || !first || $isParagraphNode(first) || block.getTextContentSize() === 0) return $insertNodes(nodes);
84
+
85
+ let last: LexicalNode = block;
86
+
87
+ for (const node of nodes) last = last.insertAfter(node);
88
+ last.selectEnd();
89
+ }
90
+
91
+ /** Plain text that reads as Markdown, pasted without HTML, goes in as the nodes it stands for. */
92
+ function MarkdownPastePlugin() {
93
+ const [editor] = useLexicalComposerContext();
94
+
95
+ useEffect(
96
+ () =>
97
+ editor.registerCommand(
98
+ PASTE_COMMAND,
99
+ (event) => {
100
+ const data = 'clipboardData' in event ? event.clipboardData : null;
101
+
102
+ if (!data || data.types.includes('text/html')) return false;
103
+
104
+ const text = data.getData('text/plain');
105
+
106
+ if (!LOOKS_LIKE_MARKDOWN.test(text)) return false;
107
+
108
+ event.preventDefault();
109
+ editor.update(() => $insertPasted($generateNodesFromMarkdownString(text, TRANSFORMERS)));
110
+
111
+ return true;
112
+ },
113
+ COMMAND_PRIORITY_HIGH,
114
+ ),
115
+ [editor],
116
+ );
117
+
118
+ return null;
119
+ }
120
+
121
+ /** Tab nests the list item the selection is in, one deeper than the item before it at most, and Shift+Tab lifts it back
122
+ * out. Where neither can change anything, as outside a list or on a top-level item, Tab is left to the browser, so it
123
+ * moves focus on rather than trapping it in the editor. */
124
+ function ListTabPlugin() {
125
+ const [editor] = useLexicalComposerContext();
126
+
127
+ useEffect(
128
+ () =>
129
+ editor.registerCommand(
130
+ KEY_TAB_COMMAND,
131
+ (event) => {
132
+ const selection = $getSelection();
133
+
134
+ if (!$isRangeSelection(selection)) return false;
135
+
136
+ const items = selection
137
+ .getNodes()
138
+ .map((node) => ($isListItemNode(node) ? node : $findMatchingParent(node, $isListItemNode)));
139
+ const moves = (item: ListItemNode | null) =>
140
+ item !== null && (event.shiftKey ? item.getIndent() > 0 : item.getPreviousSibling() !== null);
141
+
142
+ if (!items.some(moves)) return false;
143
+
144
+ event.preventDefault();
145
+
146
+ return editor.dispatchCommand(
147
+ event.shiftKey ? OUTDENT_CONTENT_COMMAND : INDENT_CONTENT_COMMAND,
148
+ undefined,
149
+ );
150
+ },
151
+ COMMAND_PRIORITY_EDITOR,
152
+ ),
153
+ [editor],
154
+ );
155
+
156
+ return null;
157
+ }
158
+
159
+ /** Locks the text, as a disabled field does. */
160
+ function EditablePlugin({ editable }: { editable: boolean }) {
161
+ const [editor] = useLexicalComposerContext();
162
+
163
+ useEffect(() => editor.setEditable(editable), [editor, editable]);
164
+
165
+ return null;
166
+ }
167
+
168
+ /** Reports the Markdown the editor makes of its starting text, which a check for changes compares against. */
169
+ function BaselinePlugin({ onBaseline }: { onBaseline: (markdown: string) => void }) {
170
+ const [editor] = useLexicalComposerContext();
171
+
172
+ useEffect(
173
+ () => editor.getEditorState().read(() => onBaseline($convertToMarkdownString(TRANSFORMERS))),
174
+ [editor, onBaseline],
175
+ );
176
+
177
+ return null;
178
+ }
179
+
180
+ /** Fills a new editor from `value`, read as Markdown or as HTML. */
181
+ const startFrom = (value: string, format: RichTextFormat) => (editor: LexicalEditor) => {
182
+ if (format === 'markdown') return $convertFromMarkdownString(value, TRANSFORMERS);
183
+
184
+ $getRoot().select();
185
+ $insertNodes($generateNodesFromDOM(editor, new DOMParser().parseFromString(value, 'text/html')));
186
+ };
187
+
188
+ interface MarkdownEditorProps {
189
+ /** The Markdown it starts from; later changes to it are ignored. */
190
+ value: string;
191
+ /** How `value` is written; the editor reports Markdown either way. */
192
+ format?: RichTextFormat;
193
+ onChange: (markdown: string) => void;
194
+ label: string;
195
+ placeholder: string;
196
+ /** Grows the editor into its parent's height, or, when 'wide', only while its container is 40rem wide or more and
197
+ * otherwise with its text, uncapped, as its parent scrolls. Without it, it grows with its text up to a cap. */
198
+ fill?: boolean | 'wide';
199
+ disabled?: boolean;
200
+ autoFocus?: boolean;
201
+ /** Called with the Markdown the editor makes of `value`, before any edit. */
202
+ onBaseline?: (markdown: string) => void;
203
+ }
204
+
205
+ /** A rich text field that reads and reports Markdown, such as a ticket's description, with a formatting toolbar. */
206
+ export function MarkdownEditor({
207
+ value,
208
+ format = 'markdown',
209
+ onChange,
210
+ label,
211
+ placeholder,
212
+ fill = false,
213
+ disabled = false,
214
+ autoFocus = false,
215
+ onBaseline,
216
+ }: MarkdownEditorProps) {
217
+ // Below 40rem a 'wide' fill gives way to the editor's text height, with no scroll area of its own. The toolbar then
218
+ // sticks to the top of the parent's scroll area, which needs the box to stop clipping, so the toolbar rounds its own
219
+ // corners instead.
220
+ const narrow =
221
+ fill === 'wide'
222
+ ? {
223
+ box: '@max-[40rem]:flex-none @max-[40rem]:overflow-visible',
224
+ area: '@max-[40rem]:flex-none @max-[40rem]:overflow-visible',
225
+ text: '@max-[40rem]:min-h-44',
226
+ toolbar:
227
+ '@max-[40rem]:sticky @max-[40rem]:top-0 @max-[40rem]:z-10 @max-[40rem]:rounded-t-lg @max-[40rem]:bg-base-100',
228
+ }
229
+ : { box: '', area: '', text: '', toolbar: '' };
230
+ const onEdit = useCallback(
231
+ (state: EditorState) => state.read(() => onChange($convertToMarkdownString(TRANSFORMERS))),
232
+ [onChange],
233
+ );
234
+
235
+ return (
236
+ <LexicalComposer
237
+ initialConfig={{
238
+ namespace: 'description',
239
+ theme,
240
+ onError: (error) => {
241
+ throw error;
242
+ },
243
+ nodes: [HeadingNode, QuoteNode, ListNode, ListItemNode, CodeNode, LinkNode],
244
+ editorState: startFrom(value, format),
245
+ }}
246
+ >
247
+ <div
248
+ data-description-editor
249
+ className={`border-base-300 bg-base-100 focus-within:border-primary/60 focus-within:ring-primary/15 flex flex-col overflow-hidden rounded-lg border transition-[border-color,box-shadow] focus-within:ring-3 ${fill ? `min-h-0 flex-1 ${narrow.box}` : ''}`}
250
+ >
251
+ <MarkdownToolbar className={narrow.toolbar} />
252
+ <div
253
+ className={`relative overflow-y-auto ${fill ? `min-h-0 flex-1 ${narrow.area}` : 'max-h-[min(24rem,45dvh)]'}`}
254
+ >
255
+ <RichTextPlugin
256
+ contentEditable={
257
+ <ContentEditable
258
+ aria-label={label}
259
+ className={`px-4 py-3 text-[15px] leading-relaxed outline-none ${fill ? `min-h-full ${narrow.text}` : 'min-h-44'}`}
260
+ />
261
+ }
262
+ placeholder={
263
+ <div className="text-base-700 pointer-events-none absolute top-3 left-4 text-[15px] leading-relaxed">
264
+ {placeholder}
265
+ </div>
266
+ }
267
+ ErrorBoundary={LexicalErrorBoundary}
268
+ />
269
+ </div>
270
+ </div>
271
+ {autoFocus && <AutoFocusPlugin defaultSelection="rootEnd" />}
272
+ <HistoryPlugin />
273
+ <ListPlugin />
274
+ <LinkPlugin />
275
+ <ListTabPlugin />
276
+ <MarkdownShortcutPlugin transformers={TRANSFORMERS} />
277
+ <MarkdownPastePlugin />
278
+ <EditablePlugin editable={!disabled} />
279
+ {onBaseline && <BaselinePlugin onBaseline={onBaseline} />}
280
+ <OnChangePlugin ignoreSelectionChange onChange={onEdit} />
281
+ </LexicalComposer>
282
+ );
283
+ }
@@ -0,0 +1,267 @@
1
+ // The Markdown editor's toolbar: bold, italic, heading, bulleted list, numbered list and link, each pressed while
2
+ // the selection has it. Link opens a URL field under the toolbar, as Electron has no window.prompt: Enter or Apply links
3
+ // the selection, Escape, a click outside or an empty URL closes it with no link, and Escape leaves the dialog open. Its
4
+ // tooltip stays shut while the field is open, so it covers none of it.
5
+
6
+ import { $isLinkNode, $toggleLink, TOGGLE_LINK_COMMAND } from '@lexical/link';
7
+ import {
8
+ $isListNode,
9
+ INSERT_ORDERED_LIST_COMMAND,
10
+ INSERT_UNORDERED_LIST_COMMAND,
11
+ REMOVE_LIST_COMMAND,
12
+ } from '@lexical/list';
13
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
14
+ import { $createHeadingNode, $isHeadingNode } from '@lexical/rich-text';
15
+ import { $setBlocksType } from '@lexical/selection';
16
+ import { $createParagraphNode, $getSelection, $isRangeSelection, $setSelection, FORMAT_TEXT_COMMAND } from 'lexical';
17
+ import type { BaseSelection, EditorState } from 'lexical';
18
+ import { BoldIcon, HeadingIcon, ItalicIcon, LinkIcon, ListIcon, ListOrderedIcon } from 'lucide-react';
19
+ import { useEffect, useRef, useState } from 'react';
20
+ import type { ComponentProps, ReactNode } from 'react';
21
+
22
+ import { Button } from '../actions/Button';
23
+ import { useDesignSystemLabels } from '../foundations/DesignSystemProvider';
24
+ import { applePlatform } from '../foundations/KeyboardShortcut';
25
+ import { Popover } from '../overlays/Popover';
26
+ import { Tooltip, TooltipPopup, TooltipTrigger } from '../overlays/Tooltip';
27
+
28
+ const MOD = applePlatform ? '⌘' : 'Ctrl+';
29
+
30
+ type Block = 'paragraph' | 'heading' | 'bullet' | 'number';
31
+ interface Active {
32
+ bold: boolean;
33
+ italic: boolean;
34
+ link: boolean;
35
+ block: Block;
36
+ }
37
+
38
+ const NONE: Active = { bold: false, italic: false, link: false, block: 'paragraph' };
39
+
40
+ /** What the selection has on. */
41
+ function readActive(state: EditorState): Active {
42
+ return state.read(() => {
43
+ const selection = $getSelection();
44
+
45
+ if (!$isRangeSelection(selection)) return NONE;
46
+
47
+ const node = selection.anchor.getNode();
48
+ const top = node.getKey() === 'root' ? null : node.getTopLevelElement();
49
+ const block = $isHeadingNode(top)
50
+ ? 'heading'
51
+ : $isListNode(top)
52
+ ? top.getListType() === 'number'
53
+ ? 'number'
54
+ : 'bullet'
55
+ : 'paragraph';
56
+
57
+ return {
58
+ bold: selection.hasFormat('bold'),
59
+ italic: selection.hasFormat('italic'),
60
+ link: $isLinkNode(node.getParent()) || $isLinkNode(node),
61
+ block,
62
+ };
63
+ });
64
+ }
65
+
66
+ /** A toolbar button; `quiet` keeps its tooltip shut, as while the field it opens would sit under it. Any other props,
67
+ * such as a popover trigger's, go on the button itself. */
68
+ function ToolButton({
69
+ label,
70
+ keys,
71
+ on,
72
+ icon,
73
+ run,
74
+ quiet = false,
75
+ ...button
76
+ }: {
77
+ label: string;
78
+ keys?: string;
79
+ on: boolean;
80
+ icon: ReactNode;
81
+ run: () => void;
82
+ quiet?: boolean;
83
+ } & ComponentProps<'button'>) {
84
+ // Held here, so a hover while quiet doesn't leave the tooltip to show once it no longer is.
85
+ const [tip, setTip] = useState(false);
86
+
87
+ return (
88
+ <Tooltip open={tip && !quiet} onOpenChange={(open) => setTip(open && !quiet)}>
89
+ <TooltipTrigger asChild>
90
+ {/* Pressing keeps the editor's selection: focus stays in the editor. */}
91
+ <button
92
+ type="button"
93
+ {...button}
94
+ aria-label={label}
95
+ aria-pressed={on}
96
+ onMouseDown={(event) => event.preventDefault()}
97
+ onClick={(event) => {
98
+ run();
99
+ button.onClick?.(event);
100
+ }}
101
+ className={`focus-visible:ring-primary grid size-7 place-items-center rounded-md transition-colors outline-none focus-visible:ring-2 [&_svg]:size-4 ${on ? 'bg-primary/10 text-primary' : 'text-base-700 hover:bg-base-200 hover:text-base-content'}`}
102
+ >
103
+ {icon}
104
+ </button>
105
+ </TooltipTrigger>
106
+ <TooltipPopup side="bottom">
107
+ {label}
108
+ {keys && <span className="text-base-500 ms-2">{keys}</span>}
109
+ </TooltipPopup>
110
+ </Tooltip>
111
+ );
112
+ }
113
+
114
+ /** The URL field Link opens, anchored under its button; `close` gets the URL to link, or null for none. A popover is a
115
+ * layer above the dialog, so Escape closes the field alone. */
116
+ function LinkField({
117
+ open,
118
+ close,
119
+ children,
120
+ }: {
121
+ open: boolean;
122
+ close: (url: string | null) => void;
123
+ children: ReactNode;
124
+ }) {
125
+ const labels = useDesignSystemLabels().editor;
126
+ const field = useRef<HTMLInputElement>(null);
127
+ const apply = () => close(field.current!.value.trim() || null);
128
+
129
+ return (
130
+ <Popover open={open} onOpenChange={(opened) => !opened && close(null)}>
131
+ {/* The button opens the field itself, so the trigger's own toggle is turned off. */}
132
+ <Popover.Trigger asChild onClick={(event) => event.preventDefault()}>
133
+ {children}
134
+ </Popover.Trigger>
135
+ {/* Portalled, its events still reach the form in the React tree, which would count them as edits. */}
136
+ <Popover.Content
137
+ side="bottom"
138
+ align="start"
139
+ onCloseAutoFocus={(event) => event.preventDefault()}
140
+ onInput={(event) => event.stopPropagation()}
141
+ onChange={(event) => event.stopPropagation()}
142
+ >
143
+ <div className="flex items-center gap-1.5">
144
+ <input
145
+ ref={field}
146
+ type="url"
147
+ aria-label={labels.linkUrl}
148
+ placeholder={labels.linkPlaceholder}
149
+ autoComplete="off"
150
+ className="border-base-300 bg-base-100 focus:border-primary/60 focus:ring-primary/15 h-7 w-56 max-w-full rounded-md border px-2 text-sm outline-none focus:ring-3"
151
+ onKeyDown={(event) => {
152
+ if (event.key !== 'Enter') return;
153
+
154
+ event.preventDefault();
155
+ apply();
156
+ }}
157
+ />
158
+ <Button compact onClick={apply}>
159
+ {labels.apply}
160
+ </Button>
161
+ </div>
162
+ </Popover.Content>
163
+ </Popover>
164
+ );
165
+ }
166
+
167
+ /** `className` adds to the bar's own classes. */
168
+ export function MarkdownToolbar({ className = '' }: { className?: string }) {
169
+ const labels = useDesignSystemLabels().editor;
170
+ const [editor] = useLexicalComposerContext();
171
+ const [active, setActive] = useState(NONE);
172
+ // The selection Link opened its field on, which the field's focus would otherwise lose.
173
+ const [linking, setLinking] = useState<BaseSelection | null>(null);
174
+
175
+ useEffect(() => editor.registerUpdateListener(({ editorState }) => setActive(readActive(editorState))), [editor]);
176
+
177
+ const heading = () =>
178
+ editor.update(() => {
179
+ const selection = $getSelection();
180
+
181
+ if ($isRangeSelection(selection))
182
+ $setBlocksType(selection, () =>
183
+ active.block === 'heading' ? $createParagraphNode() : $createHeadingNode('h2'),
184
+ );
185
+ });
186
+ const list = (type: 'bullet' | 'number') => {
187
+ if (active.block === type) editor.dispatchCommand(REMOVE_LIST_COMMAND, undefined);
188
+ else
189
+ editor.dispatchCommand(
190
+ type === 'bullet' ? INSERT_UNORDERED_LIST_COMMAND : INSERT_ORDERED_LIST_COMMAND,
191
+ undefined,
192
+ );
193
+ };
194
+ const link = () => {
195
+ if (active.link) return editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
196
+
197
+ setLinking(editor.getEditorState().read(() => $getSelection()?.clone() ?? null));
198
+ };
199
+ const closeLink = (url: string | null) => {
200
+ const selection = linking;
201
+
202
+ setLinking(null);
203
+
204
+ if (url && selection)
205
+ editor.update(() => {
206
+ $setSelection(selection.clone());
207
+ $toggleLink(url);
208
+ });
209
+
210
+ editor.focus();
211
+ };
212
+
213
+ return (
214
+ <div
215
+ role="toolbar"
216
+ aria-label={labels.formatting}
217
+ className={`border-base-300/70 flex shrink-0 items-center gap-0.5 border-b px-2 py-1 ${className}`}
218
+ >
219
+ <ToolButton
220
+ label={labels.bold}
221
+ keys={`${MOD}B`}
222
+ on={active.bold}
223
+ icon={<BoldIcon />}
224
+ run={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold')}
225
+ />
226
+ <ToolButton
227
+ label={labels.italic}
228
+ keys={`${MOD}I`}
229
+ on={active.italic}
230
+ icon={<ItalicIcon />}
231
+ run={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'italic')}
232
+ />
233
+ <span aria-hidden="true" className="bg-base-300 mx-1 h-4 w-px" />
234
+ <ToolButton
235
+ label={labels.heading}
236
+ keys="#"
237
+ on={active.block === 'heading'}
238
+ icon={<HeadingIcon />}
239
+ run={heading}
240
+ />
241
+ <ToolButton
242
+ label={labels.bulletedList}
243
+ keys="-"
244
+ on={active.block === 'bullet'}
245
+ icon={<ListIcon />}
246
+ run={() => list('bullet')}
247
+ />
248
+ <ToolButton
249
+ label={labels.numberedList}
250
+ keys="1."
251
+ on={active.block === 'number'}
252
+ icon={<ListOrderedIcon />}
253
+ run={() => list('number')}
254
+ />
255
+ <LinkField open={linking !== null} close={closeLink}>
256
+ <ToolButton
257
+ label={labels.link}
258
+ on={active.link}
259
+ icon={<LinkIcon />}
260
+ run={link}
261
+ quiet={linking !== null}
262
+ />
263
+ </LinkField>
264
+ <span className="text-base-700 ms-auto pe-1 text-[11px]">{labels.markdown}</span>
265
+ </div>
266
+ );
267
+ }