@lar-works/design-system 0.0.0-stage → 0.1.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 (555) hide show
  1. package/README.md +24 -2
  2. package/dist/actions/Button.d.ts +25 -0
  3. package/dist/actions/Button.js +55 -0
  4. package/dist/actions/Button.js.map +1 -0
  5. package/dist/actions/ButtonLink.d.ts +21 -0
  6. package/dist/actions/ButtonLink.js +40 -0
  7. package/dist/actions/ButtonLink.js.map +1 -0
  8. package/dist/actions/IconButton.d.ts +14 -0
  9. package/dist/actions/IconButton.js +29 -0
  10. package/dist/actions/IconButton.js.map +1 -0
  11. package/dist/actions/ThemeSwitch.d.ts +7 -0
  12. package/dist/actions/ThemeSwitch.js +42 -0
  13. package/dist/actions/ThemeSwitch.js.map +1 -0
  14. package/dist/actions/index.d.ts +5 -0
  15. package/dist/collections/CollectionSectionHeader.d.ts +5 -0
  16. package/dist/collections/CollectionSectionHeader.js +18 -0
  17. package/dist/collections/CollectionSectionHeader.js.map +1 -0
  18. package/dist/collections/CollectionState.d.ts +37 -0
  19. package/dist/collections/CollectionState.js +69 -0
  20. package/dist/collections/CollectionState.js.map +1 -0
  21. package/dist/collections/CollectionTokens.d.ts +16 -0
  22. package/dist/collections/CollectionTokens.js +19 -0
  23. package/dist/collections/CollectionTokens.js.map +1 -0
  24. package/dist/collections/CollectionViewport.js +36 -0
  25. package/dist/collections/CollectionViewport.js.map +1 -0
  26. package/dist/collections/DataRow.d.ts +23 -0
  27. package/dist/collections/DataRow.js +57 -0
  28. package/dist/collections/DataRow.js.map +1 -0
  29. package/dist/collections/ResultList.d.ts +29 -0
  30. package/dist/collections/ResultList.js +128 -0
  31. package/dist/collections/ResultList.js.map +1 -0
  32. package/dist/collections/ScrollRow.d.ts +23 -0
  33. package/dist/collections/ScrollRow.js +59 -0
  34. package/dist/collections/ScrollRow.js.map +1 -0
  35. package/dist/collections/VirtualGrid.d.ts +14 -0
  36. package/dist/collections/VirtualGrid.js +71 -0
  37. package/dist/collections/VirtualGrid.js.map +1 -0
  38. package/dist/collections/VirtualList.d.ts +34 -0
  39. package/dist/collections/VirtualList.js +128 -0
  40. package/dist/collections/VirtualList.js.map +1 -0
  41. package/dist/collections/index.d.ts +10 -0
  42. package/dist/collections/useCollectionMotion.d.ts +3 -0
  43. package/dist/collections/useCollectionMotion.js +34 -0
  44. package/dist/collections/useCollectionMotion.js.map +1 -0
  45. package/dist/collections/useScrollRow.d.ts +17 -0
  46. package/dist/collections/useScrollRow.js +63 -0
  47. package/dist/collections/useScrollRow.js.map +1 -0
  48. package/dist/display/ActivityCard.d.ts +17 -0
  49. package/dist/display/ActivityCard.js +58 -0
  50. package/dist/display/ActivityCard.js.map +1 -0
  51. package/dist/display/Artwork.d.ts +25 -0
  52. package/dist/display/Artwork.js +97 -0
  53. package/dist/display/Artwork.js.map +1 -0
  54. package/dist/display/Avatar.d.ts +5 -0
  55. package/dist/display/Avatar.js +13 -0
  56. package/dist/display/Avatar.js.map +1 -0
  57. package/dist/display/Badge.d.ts +10 -0
  58. package/dist/display/Badge.js +28 -0
  59. package/dist/display/Badge.js.map +1 -0
  60. package/dist/display/BadgeList.d.ts +11 -0
  61. package/dist/display/BadgeList.js +20 -0
  62. package/dist/display/BadgeList.js.map +1 -0
  63. package/dist/display/BrandMark.d.ts +21 -0
  64. package/dist/display/BrandMark.js +60 -0
  65. package/dist/display/BrandMark.js.map +1 -0
  66. package/dist/display/ChangeList.d.ts +16 -0
  67. package/dist/display/ChangeList.js +56 -0
  68. package/dist/display/ChangeList.js.map +1 -0
  69. package/dist/display/CheckList.d.ts +10 -0
  70. package/dist/display/CheckList.js +25 -0
  71. package/dist/display/CheckList.js.map +1 -0
  72. package/dist/display/CodeBlock.d.ts +6 -0
  73. package/dist/display/CodeBlock.js +12 -0
  74. package/dist/display/CodeBlock.js.map +1 -0
  75. package/dist/display/CopyButton.d.ts +9 -0
  76. package/dist/display/CopyButton.js +59 -0
  77. package/dist/display/CopyButton.js.map +1 -0
  78. package/dist/display/DataTable.d.ts +35 -0
  79. package/dist/display/DataTable.js +53 -0
  80. package/dist/display/DataTable.js.map +1 -0
  81. package/dist/display/DetailHero.d.ts +39 -0
  82. package/dist/display/DetailHero.js +146 -0
  83. package/dist/display/DetailHero.js.map +1 -0
  84. package/dist/display/DetailList.d.ts +15 -0
  85. package/dist/display/DetailList.js +53 -0
  86. package/dist/display/DetailList.js.map +1 -0
  87. package/dist/display/DeviceCard.d.ts +18 -0
  88. package/dist/display/DeviceCard.js +48 -0
  89. package/dist/display/DeviceCard.js.map +1 -0
  90. package/dist/display/Identity.d.ts +14 -0
  91. package/dist/display/Identity.js +54 -0
  92. package/dist/display/Identity.js.map +1 -0
  93. package/dist/display/ImageCard.d.ts +22 -0
  94. package/dist/display/ImageCard.js +63 -0
  95. package/dist/display/ImageCard.js.map +1 -0
  96. package/dist/display/ImagePicker.d.ts +30 -0
  97. package/dist/display/ImagePicker.js +108 -0
  98. package/dist/display/ImagePicker.js.map +1 -0
  99. package/dist/display/InfoBox.d.ts +15 -0
  100. package/dist/display/InfoBox.js +41 -0
  101. package/dist/display/InfoBox.js.map +1 -0
  102. package/dist/display/InsetPanel.d.ts +13 -0
  103. package/dist/display/InsetPanel.js +26 -0
  104. package/dist/display/InsetPanel.js.map +1 -0
  105. package/dist/display/ItemAction.d.ts +10 -0
  106. package/dist/display/ItemAction.js +35 -0
  107. package/dist/display/ItemAction.js.map +1 -0
  108. package/dist/display/Kbd.d.ts +6 -0
  109. package/dist/display/Kbd.js +12 -0
  110. package/dist/display/Kbd.js.map +1 -0
  111. package/dist/display/KindIcon.d.ts +8 -0
  112. package/dist/display/KindIcon.js +15 -0
  113. package/dist/display/KindIcon.js.map +1 -0
  114. package/dist/display/NoticeCard.d.ts +24 -0
  115. package/dist/display/NoticeCard.js +59 -0
  116. package/dist/display/NoticeCard.js.map +1 -0
  117. package/dist/display/PairingList.d.ts +19 -0
  118. package/dist/display/PairingList.js +53 -0
  119. package/dist/display/PairingList.js.map +1 -0
  120. package/dist/display/PathList.d.ts +9 -0
  121. package/dist/display/PathList.js +21 -0
  122. package/dist/display/PathList.js.map +1 -0
  123. package/dist/display/PeoplePreview.d.ts +16 -0
  124. package/dist/display/PeoplePreview.js +41 -0
  125. package/dist/display/PeoplePreview.js.map +1 -0
  126. package/dist/display/PropertySheet.d.ts +56 -0
  127. package/dist/display/PropertySheet.js +150 -0
  128. package/dist/display/PropertySheet.js.map +1 -0
  129. package/dist/display/QrCode.d.ts +6 -0
  130. package/dist/display/QrCode.js +47 -0
  131. package/dist/display/QrCode.js.map +1 -0
  132. package/dist/display/RadioChoice.d.ts +9 -0
  133. package/dist/display/RadioChoice.js +28 -0
  134. package/dist/display/RadioChoice.js.map +1 -0
  135. package/dist/display/RatingLink.d.ts +10 -0
  136. package/dist/display/RatingLink.js +80 -0
  137. package/dist/display/RatingLink.js.map +1 -0
  138. package/dist/display/ResourceCard.d.ts +20 -0
  139. package/dist/display/ResourceCard.js +200 -0
  140. package/dist/display/ResourceCard.js.map +1 -0
  141. package/dist/display/RowList.d.ts +28 -0
  142. package/dist/display/RowList.js +76 -0
  143. package/dist/display/RowList.js.map +1 -0
  144. package/dist/display/StackedMeter.d.ts +28 -0
  145. package/dist/display/StackedMeter.js +48 -0
  146. package/dist/display/StackedMeter.js.map +1 -0
  147. package/dist/display/StatTile.d.ts +13 -0
  148. package/dist/display/StatTile.js +35 -0
  149. package/dist/display/StatTile.js.map +1 -0
  150. package/dist/display/StepList.d.ts +5 -0
  151. package/dist/display/StepList.js +12 -0
  152. package/dist/display/StepList.js.map +1 -0
  153. package/dist/display/TextPreview.d.ts +14 -0
  154. package/dist/display/TextPreview.js +46 -0
  155. package/dist/display/TextPreview.js.map +1 -0
  156. package/dist/display/TimeSeriesChart.d.ts +19 -0
  157. package/dist/display/TimeSeriesChart.js +163 -0
  158. package/dist/display/TimeSeriesChart.js.map +1 -0
  159. package/dist/display/ToneTile.js +12 -0
  160. package/dist/display/ToneTile.js.map +1 -0
  161. package/dist/display/index.d.ts +38 -0
  162. package/dist/feedback/Alert.d.ts +15 -0
  163. package/dist/feedback/Alert.js +19 -0
  164. package/dist/feedback/Alert.js.map +1 -0
  165. package/dist/feedback/AsyncState.d.ts +16 -0
  166. package/dist/feedback/AsyncState.js +29 -0
  167. package/dist/feedback/AsyncState.js.map +1 -0
  168. package/dist/feedback/ErrorNotification.d.ts +8 -0
  169. package/dist/feedback/ErrorNotification.js +20 -0
  170. package/dist/feedback/ErrorNotification.js.map +1 -0
  171. package/dist/feedback/Notifications.d.ts +2 -0
  172. package/dist/feedback/Notifications.js +9 -0
  173. package/dist/feedback/Notifications.js.map +1 -0
  174. package/dist/feedback/ProgressStatusRow.d.ts +23 -0
  175. package/dist/feedback/ProgressStatusRow.js +74 -0
  176. package/dist/feedback/ProgressStatusRow.js.map +1 -0
  177. package/dist/feedback/SkeletonLoader.d.ts +19 -0
  178. package/dist/feedback/SkeletonLoader.js +59 -0
  179. package/dist/feedback/SkeletonLoader.js.map +1 -0
  180. package/dist/feedback/StatusIndicator.d.ts +9 -0
  181. package/dist/feedback/StatusIndicator.js +28 -0
  182. package/dist/feedback/StatusIndicator.js.map +1 -0
  183. package/dist/feedback/StatusPopoverContent.d.ts +13 -0
  184. package/dist/feedback/StatusPopoverContent.js +50 -0
  185. package/dist/feedback/StatusPopoverContent.js.map +1 -0
  186. package/dist/feedback/StatusRow.d.ts +16 -0
  187. package/dist/feedback/StatusRow.js +60 -0
  188. package/dist/feedback/StatusRow.js.map +1 -0
  189. package/dist/feedback/index.d.ts +11 -0
  190. package/dist/feedback/index.js +11 -0
  191. package/dist/forms/Checkbox.d.ts +10 -0
  192. package/dist/forms/Checkbox.js +48 -0
  193. package/dist/forms/Checkbox.js.map +1 -0
  194. package/dist/forms/Field.d.ts +5 -0
  195. package/dist/forms/Field.js +15 -0
  196. package/dist/forms/Field.js.map +1 -0
  197. package/dist/forms/FormControlStyles.js +14 -0
  198. package/dist/forms/FormControlStyles.js.map +1 -0
  199. package/dist/forms/FormSection.d.ts +48 -0
  200. package/dist/forms/FormSection.js +142 -0
  201. package/dist/forms/FormSection.js.map +1 -0
  202. package/dist/forms/InlineFields.d.ts +13 -0
  203. package/dist/forms/InlineFields.js +24 -0
  204. package/dist/forms/InlineFields.js.map +1 -0
  205. package/dist/forms/Input.d.ts +5 -0
  206. package/dist/forms/Input.js +18 -0
  207. package/dist/forms/Input.js.map +1 -0
  208. package/dist/forms/OptionSelect.d.ts +21 -0
  209. package/dist/forms/OptionSelect.js +28 -0
  210. package/dist/forms/OptionSelect.js.map +1 -0
  211. package/dist/forms/RadioGroup.d.ts +5 -0
  212. package/dist/forms/RadioGroup.js +35 -0
  213. package/dist/forms/RadioGroup.js.map +1 -0
  214. package/dist/forms/Select.d.ts +6 -0
  215. package/dist/forms/Select.js +36 -0
  216. package/dist/forms/Select.js.map +1 -0
  217. package/dist/forms/Switch.d.ts +4 -0
  218. package/dist/forms/Switch.js +16 -0
  219. package/dist/forms/Switch.js.map +1 -0
  220. package/dist/forms/TagInput.d.ts +19 -0
  221. package/dist/forms/TagInput.js +60 -0
  222. package/dist/forms/TagInput.js.map +1 -0
  223. package/dist/forms/Textarea.d.ts +4 -0
  224. package/dist/forms/Textarea.js +15 -0
  225. package/dist/forms/Textarea.js.map +1 -0
  226. package/dist/forms/index.d.ts +12 -0
  227. package/dist/foundations/DesignSystemProvider.d.ts +64 -0
  228. package/dist/foundations/DesignSystemProvider.js +66 -0
  229. package/dist/foundations/DesignSystemProvider.js.map +1 -0
  230. package/dist/foundations/KeyboardFocus.d.ts +9 -0
  231. package/dist/foundations/KeyboardFocus.js +10 -0
  232. package/dist/foundations/KeyboardFocus.js.map +1 -0
  233. package/dist/foundations/KeyboardShortcut.d.ts +5 -0
  234. package/dist/foundations/KeyboardShortcut.js +10 -0
  235. package/dist/foundations/KeyboardShortcut.js.map +1 -0
  236. package/dist/foundations/Theme.d.ts +14 -0
  237. package/dist/foundations/Theme.js +56 -0
  238. package/dist/foundations/Theme.js.map +1 -0
  239. package/dist/foundations/index.d.ts +5 -0
  240. package/dist/icons/BrandIcons.d.ts +3 -0
  241. package/dist/icons/BrandIcons.js +14 -0
  242. package/dist/icons/BrandIcons.js.map +1 -0
  243. package/dist/icons/index.d.ts +3 -0
  244. package/dist/icons/index.js +2 -0
  245. package/dist/icons.d.ts +4 -0
  246. package/dist/icons.js +2 -0
  247. package/dist/index.d.ts +133 -0
  248. package/dist/index.js +125 -0
  249. package/dist/layout/AppShell.d.ts +11 -0
  250. package/dist/layout/AppShell.js +46 -0
  251. package/dist/layout/AppShell.js.map +1 -0
  252. package/dist/layout/AuthLayout.d.ts +11 -0
  253. package/dist/layout/AuthLayout.js +48 -0
  254. package/dist/layout/AuthLayout.js.map +1 -0
  255. package/dist/layout/ContentContainer.d.ts +9 -0
  256. package/dist/layout/ContentContainer.js +15 -0
  257. package/dist/layout/ContentContainer.js.map +1 -0
  258. package/dist/layout/Flow.d.ts +26 -0
  259. package/dist/layout/Flow.js +65 -0
  260. package/dist/layout/Flow.js.map +1 -0
  261. package/dist/layout/PageLayout.d.ts +12 -0
  262. package/dist/layout/PageLayout.js +31 -0
  263. package/dist/layout/PageLayout.js.map +1 -0
  264. package/dist/layout/PageSection.d.ts +43 -0
  265. package/dist/layout/PageSection.js +63 -0
  266. package/dist/layout/PageSection.js.map +1 -0
  267. package/dist/layout/ScrollArea.d.ts +4 -0
  268. package/dist/layout/ScrollArea.js +11 -0
  269. package/dist/layout/ScrollArea.js.map +1 -0
  270. package/dist/layout/Section.d.ts +12 -0
  271. package/dist/layout/Section.js +36 -0
  272. package/dist/layout/Section.js.map +1 -0
  273. package/dist/layout/Site.d.ts +41 -0
  274. package/dist/layout/Site.js +157 -0
  275. package/dist/layout/Site.js.map +1 -0
  276. package/dist/layout/TitleBar.d.ts +28 -0
  277. package/dist/layout/TitleBar.js +83 -0
  278. package/dist/layout/TitleBar.js.map +1 -0
  279. package/dist/layout/WorkspaceActionsHeader.d.ts +8 -0
  280. package/dist/layout/WorkspaceActionsHeader.js +18 -0
  281. package/dist/layout/WorkspaceActionsHeader.js.map +1 -0
  282. package/dist/layout/index.d.ts +19 -0
  283. package/dist/layout/index.js +19 -0
  284. package/dist/layout/sidebar/SidebarNavigationItem.d.ts +10 -0
  285. package/dist/layout/sidebar/SidebarNavigationItem.js +36 -0
  286. package/dist/layout/sidebar/SidebarNavigationItem.js.map +1 -0
  287. package/dist/layout/sidebar/SidebarPane.d.ts +13 -0
  288. package/dist/layout/sidebar/SidebarPane.js +30 -0
  289. package/dist/layout/sidebar/SidebarPane.js.map +1 -0
  290. package/dist/layout/toolbar/CommandPaletteTrigger.d.ts +11 -0
  291. package/dist/layout/toolbar/CommandPaletteTrigger.js +46 -0
  292. package/dist/layout/toolbar/CommandPaletteTrigger.js.map +1 -0
  293. package/dist/layout/toolbar/ToolbarStatusGroup.d.ts +5 -0
  294. package/dist/layout/toolbar/ToolbarStatusGroup.js +14 -0
  295. package/dist/layout/toolbar/ToolbarStatusGroup.js.map +1 -0
  296. package/dist/layout/toolbar/ToolbarStatusItem.d.ts +9 -0
  297. package/dist/layout/toolbar/ToolbarStatusItem.js +18 -0
  298. package/dist/layout/toolbar/ToolbarStatusItem.js.map +1 -0
  299. package/dist/navigation/ArtworkTabs.d.ts +18 -0
  300. package/dist/navigation/ArtworkTabs.js +72 -0
  301. package/dist/navigation/ArtworkTabs.js.map +1 -0
  302. package/dist/navigation/Breadcrumbs.d.ts +13 -0
  303. package/dist/navigation/Breadcrumbs.js +32 -0
  304. package/dist/navigation/Breadcrumbs.js.map +1 -0
  305. package/dist/navigation/CollectionBrowseSelector.d.ts +22 -0
  306. package/dist/navigation/CollectionBrowseSelector.js +70 -0
  307. package/dist/navigation/CollectionBrowseSelector.js.map +1 -0
  308. package/dist/navigation/CollectionViewToggle.d.ts +12 -0
  309. package/dist/navigation/CollectionViewToggle.js +36 -0
  310. package/dist/navigation/CollectionViewToggle.js.map +1 -0
  311. package/dist/navigation/DrilldownBrowseSelector.d.ts +31 -0
  312. package/dist/navigation/DrilldownBrowseSelector.js +174 -0
  313. package/dist/navigation/DrilldownBrowseSelector.js.map +1 -0
  314. package/dist/navigation/FolderSelector.d.ts +24 -0
  315. package/dist/navigation/FolderSelector.js +142 -0
  316. package/dist/navigation/FolderSelector.js.map +1 -0
  317. package/dist/navigation/TabKeys.js +13 -0
  318. package/dist/navigation/TabKeys.js.map +1 -0
  319. package/dist/navigation/ViewTabs.d.ts +19 -0
  320. package/dist/navigation/ViewTabs.js +48 -0
  321. package/dist/navigation/ViewTabs.js.map +1 -0
  322. package/dist/navigation/index.d.ts +8 -0
  323. package/dist/overlays/ActionModal.d.ts +21 -0
  324. package/dist/overlays/ActionModal.js +48 -0
  325. package/dist/overlays/ActionModal.js.map +1 -0
  326. package/dist/overlays/CommandPalette.d.ts +43 -0
  327. package/dist/overlays/CommandPalette.js +163 -0
  328. package/dist/overlays/CommandPalette.js.map +1 -0
  329. package/dist/overlays/Drawer.d.ts +19 -0
  330. package/dist/overlays/Drawer.js +83 -0
  331. package/dist/overlays/Drawer.js.map +1 -0
  332. package/dist/overlays/DropdownMenu.d.ts +47 -0
  333. package/dist/overlays/DropdownMenu.js +58 -0
  334. package/dist/overlays/DropdownMenu.js.map +1 -0
  335. package/dist/overlays/ImageViewer.d.ts +21 -0
  336. package/dist/overlays/ImageViewer.js +82 -0
  337. package/dist/overlays/ImageViewer.js.map +1 -0
  338. package/dist/overlays/Modal.d.ts +36 -0
  339. package/dist/overlays/Modal.js +149 -0
  340. package/dist/overlays/Modal.js.map +1 -0
  341. package/dist/overlays/Popover.d.ts +19 -0
  342. package/dist/overlays/Popover.js +26 -0
  343. package/dist/overlays/Popover.js.map +1 -0
  344. package/dist/overlays/Tooltip.d.ts +12 -0
  345. package/dist/overlays/Tooltip.js +54 -0
  346. package/dist/overlays/Tooltip.js.map +1 -0
  347. package/dist/overlays/index.d.ts +9 -0
  348. package/dist/overlays/useModalAutoFocus.js +84 -0
  349. package/dist/overlays/useModalAutoFocus.js.map +1 -0
  350. package/dist/overlays/useScrollFade.js +43 -0
  351. package/dist/overlays/useScrollFade.js.map +1 -0
  352. package/dist/showcase/CallToAction.d.ts +11 -0
  353. package/dist/showcase/CallToAction.js +54 -0
  354. package/dist/showcase/CallToAction.js.map +1 -0
  355. package/dist/showcase/Cards.d.ts +34 -0
  356. package/dist/showcase/Cards.js +122 -0
  357. package/dist/showcase/Cards.js.map +1 -0
  358. package/dist/showcase/Devices.d.ts +72 -0
  359. package/dist/showcase/Devices.js +249 -0
  360. package/dist/showcase/Devices.js.map +1 -0
  361. package/dist/showcase/FeatureRow.d.ts +30 -0
  362. package/dist/showcase/FeatureRow.js +91 -0
  363. package/dist/showcase/FeatureRow.js.map +1 -0
  364. package/dist/showcase/Hero.d.ts +15 -0
  365. package/dist/showcase/Hero.js +73 -0
  366. package/dist/showcase/Hero.js.map +1 -0
  367. package/dist/showcase/PhotoSearchConcept.d.ts +14 -0
  368. package/dist/showcase/PhotoSearchConcept.js +43 -0
  369. package/dist/showcase/PhotoSearchConcept.js.map +1 -0
  370. package/dist/showcase/Platforms.d.ts +15 -0
  371. package/dist/showcase/Platforms.js +48 -0
  372. package/dist/showcase/Platforms.js.map +1 -0
  373. package/dist/showcase/ProductBand.d.ts +38 -0
  374. package/dist/showcase/ProductBand.js +120 -0
  375. package/dist/showcase/ProductBand.js.map +1 -0
  376. package/dist/showcase/Roadmap.d.ts +21 -0
  377. package/dist/showcase/Roadmap.js +111 -0
  378. package/dist/showcase/Roadmap.js.map +1 -0
  379. package/dist/showcase/RouteDiagram.d.ts +14 -0
  380. package/dist/showcase/RouteDiagram.js +57 -0
  381. package/dist/showcase/RouteDiagram.js.map +1 -0
  382. package/dist/showcase/ServerUnit.d.ts +50 -0
  383. package/dist/showcase/ServerUnit.js +175 -0
  384. package/dist/showcase/ServerUnit.js.map +1 -0
  385. package/dist/showcase/Stage.d.ts +46 -0
  386. package/dist/showcase/Stage.js +106 -0
  387. package/dist/showcase/Stage.js.map +1 -0
  388. package/dist/showcase/Status.d.ts +30 -0
  389. package/dist/showcase/Status.js +84 -0
  390. package/dist/showcase/Status.js.map +1 -0
  391. package/dist/showcase/StepFlow.d.ts +13 -0
  392. package/dist/showcase/StepFlow.js +47 -0
  393. package/dist/showcase/StepFlow.js.map +1 -0
  394. package/dist/showcase/index.d.ts +15 -0
  395. package/dist/testing.d.ts +5 -0
  396. package/dist/testing.js +43 -0
  397. package/dist/testing.js.map +1 -0
  398. package/dist/typography/Link.d.ts +21 -0
  399. package/dist/typography/Link.js +60 -0
  400. package/dist/typography/Link.js.map +1 -0
  401. package/dist/typography/Typography.d.ts +53 -0
  402. package/dist/typography/Typography.js +67 -0
  403. package/dist/typography/Typography.js.map +1 -0
  404. package/dist/typography/index.d.ts +4 -0
  405. package/dist/typography/index.js +4 -0
  406. package/package.json +80 -3
  407. package/src/actions/Button.tsx +68 -0
  408. package/src/actions/ButtonLink.tsx +75 -0
  409. package/src/actions/IconButton.tsx +55 -0
  410. package/src/actions/ThemeSwitch.tsx +46 -0
  411. package/src/actions/index.ts +4 -0
  412. package/src/collections/CollectionSectionHeader.tsx +13 -0
  413. package/src/collections/CollectionState.tsx +76 -0
  414. package/src/collections/CollectionTokens.ts +12 -0
  415. package/src/collections/CollectionViewport.ts +40 -0
  416. package/src/collections/DataRow.tsx +79 -0
  417. package/src/collections/ResultList.tsx +164 -0
  418. package/src/collections/ScrollRow.tsx +90 -0
  419. package/src/collections/VirtualGrid.tsx +92 -0
  420. package/src/collections/VirtualList.tsx +224 -0
  421. package/src/collections/index.ts +10 -0
  422. package/src/collections/useCollectionMotion.ts +42 -0
  423. package/src/collections/useScrollRow.ts +64 -0
  424. package/src/display/ActivityCard.tsx +76 -0
  425. package/src/display/Artwork.tsx +140 -0
  426. package/src/display/Avatar.tsx +7 -0
  427. package/src/display/Badge.tsx +33 -0
  428. package/src/display/BadgeList.tsx +25 -0
  429. package/src/display/BrandMark.tsx +72 -0
  430. package/src/display/ChangeList.tsx +41 -0
  431. package/src/display/CheckList.tsx +27 -0
  432. package/src/display/CodeBlock.tsx +12 -0
  433. package/src/display/CopyButton.tsx +77 -0
  434. package/src/display/DataTable.tsx +80 -0
  435. package/src/display/DetailHero.tsx +191 -0
  436. package/src/display/DetailList.tsx +74 -0
  437. package/src/display/DeviceCard.tsx +49 -0
  438. package/src/display/Identity.tsx +56 -0
  439. package/src/display/ImageCard.tsx +102 -0
  440. package/src/display/ImagePicker.tsx +149 -0
  441. package/src/display/InfoBox.tsx +48 -0
  442. package/src/display/InsetPanel.tsx +37 -0
  443. package/src/display/ItemAction.tsx +53 -0
  444. package/src/display/Kbd.tsx +6 -0
  445. package/src/display/KindIcon.tsx +15 -0
  446. package/src/display/NoticeCard.tsx +77 -0
  447. package/src/display/PairingList.tsx +55 -0
  448. package/src/display/PathList.tsx +16 -0
  449. package/src/display/PeoplePreview.tsx +66 -0
  450. package/src/display/PropertySheet.tsx +180 -0
  451. package/src/display/QrCode.tsx +47 -0
  452. package/src/display/RadioChoice.tsx +34 -0
  453. package/src/display/RatingLink.tsx +76 -0
  454. package/src/display/ResourceCard.tsx +201 -0
  455. package/src/display/RowList.tsx +110 -0
  456. package/src/display/StackedMeter.tsx +72 -0
  457. package/src/display/StatTile.tsx +39 -0
  458. package/src/display/StepList.tsx +10 -0
  459. package/src/display/TextPreview.tsx +66 -0
  460. package/src/display/TimeSeriesChart.tsx +191 -0
  461. package/src/display/ToneTile.ts +10 -0
  462. package/src/display/index.ts +37 -0
  463. package/src/feedback/Alert.tsx +35 -0
  464. package/src/feedback/AsyncState.tsx +56 -0
  465. package/src/feedback/ErrorNotification.ts +24 -0
  466. package/src/feedback/Notifications.tsx +5 -0
  467. package/src/feedback/ProgressStatusRow.tsx +104 -0
  468. package/src/feedback/SkeletonLoader.tsx +88 -0
  469. package/src/feedback/StatusIndicator.tsx +28 -0
  470. package/src/feedback/StatusPopoverContent.tsx +54 -0
  471. package/src/feedback/StatusRow.tsx +70 -0
  472. package/src/feedback/index.ts +15 -0
  473. package/src/forms/Checkbox.tsx +61 -0
  474. package/src/forms/Field.tsx +17 -0
  475. package/src/forms/FormControlStyles.ts +9 -0
  476. package/src/forms/FormSection.tsx +175 -0
  477. package/src/forms/InlineFields.tsx +22 -0
  478. package/src/forms/Input.tsx +22 -0
  479. package/src/forms/OptionSelect.tsx +49 -0
  480. package/src/forms/RadioGroup.tsx +48 -0
  481. package/src/forms/Select.tsx +46 -0
  482. package/src/forms/Switch.tsx +10 -0
  483. package/src/forms/TagInput.tsx +76 -0
  484. package/src/forms/Textarea.tsx +14 -0
  485. package/src/forms/index.ts +11 -0
  486. package/src/foundations/DesignSystemProvider.tsx +79 -0
  487. package/src/foundations/KeyboardFocus.ts +6 -0
  488. package/src/foundations/KeyboardShortcut.ts +12 -0
  489. package/src/foundations/Theme.ts +75 -0
  490. package/src/foundations/index.ts +10 -0
  491. package/src/foundations/theme.css +425 -0
  492. package/src/icons/BrandIcons.tsx +8 -0
  493. package/src/icons/index.ts +4 -0
  494. package/src/icons.ts +1 -0
  495. package/src/index.ts +13 -0
  496. package/src/layout/AppShell.tsx +63 -0
  497. package/src/layout/AuthLayout.tsx +40 -0
  498. package/src/layout/ContentContainer.tsx +16 -0
  499. package/src/layout/Flow.tsx +56 -0
  500. package/src/layout/PageLayout.tsx +35 -0
  501. package/src/layout/PageSection.tsx +103 -0
  502. package/src/layout/ScrollArea.tsx +7 -0
  503. package/src/layout/Section.tsx +36 -0
  504. package/src/layout/Site.tsx +205 -0
  505. package/src/layout/TitleBar.tsx +97 -0
  506. package/src/layout/WorkspaceActionsHeader.tsx +17 -0
  507. package/src/layout/index.ts +18 -0
  508. package/src/layout/sidebar/SidebarNavigationItem.tsx +45 -0
  509. package/src/layout/sidebar/SidebarPane.tsx +37 -0
  510. package/src/layout/toolbar/CommandPaletteTrigger.tsx +53 -0
  511. package/src/layout/toolbar/ToolbarStatusGroup.tsx +9 -0
  512. package/src/layout/toolbar/ToolbarStatusItem.tsx +18 -0
  513. package/src/navigation/ArtworkTabs.tsx +107 -0
  514. package/src/navigation/Breadcrumbs.tsx +31 -0
  515. package/src/navigation/CollectionBrowseSelector.tsx +90 -0
  516. package/src/navigation/CollectionViewToggle.tsx +52 -0
  517. package/src/navigation/DrilldownBrowseSelector.tsx +229 -0
  518. package/src/navigation/FolderSelector.tsx +172 -0
  519. package/src/navigation/TabKeys.ts +21 -0
  520. package/src/navigation/ViewTabs.tsx +85 -0
  521. package/src/navigation/index.ts +15 -0
  522. package/src/overlays/ActionModal.tsx +81 -0
  523. package/src/overlays/CommandPalette.tsx +199 -0
  524. package/src/overlays/Drawer.tsx +107 -0
  525. package/src/overlays/DropdownMenu.tsx +122 -0
  526. package/src/overlays/ImageViewer.tsx +96 -0
  527. package/src/overlays/Modal.tsx +234 -0
  528. package/src/overlays/Popover.tsx +40 -0
  529. package/src/overlays/Tooltip.tsx +56 -0
  530. package/src/overlays/index.ts +8 -0
  531. package/src/overlays/useModalAutoFocus.ts +119 -0
  532. package/src/overlays/useScrollFade.ts +49 -0
  533. package/src/showcase/CallToAction.tsx +46 -0
  534. package/src/showcase/Cards.tsx +133 -0
  535. package/src/showcase/Devices.tsx +259 -0
  536. package/src/showcase/FeatureRow.tsx +107 -0
  537. package/src/showcase/Hero.tsx +70 -0
  538. package/src/showcase/PhotoSearchConcept.tsx +50 -0
  539. package/src/showcase/Platforms.tsx +49 -0
  540. package/src/showcase/ProductBand.tsx +148 -0
  541. package/src/showcase/Roadmap.tsx +115 -0
  542. package/src/showcase/RouteDiagram.tsx +56 -0
  543. package/src/showcase/ServerUnit.tsx +191 -0
  544. package/src/showcase/Stage.tsx +160 -0
  545. package/src/showcase/Status.tsx +107 -0
  546. package/src/showcase/StepFlow.tsx +48 -0
  547. package/src/showcase/devices.css +441 -0
  548. package/src/showcase/index.ts +34 -0
  549. package/src/showcase/server-unit.css +258 -0
  550. package/src/showcase/stage.css +175 -0
  551. package/src/styles.css +5 -0
  552. package/src/testing.ts +34 -0
  553. package/src/typography/Link.tsx +105 -0
  554. package/src/typography/Typography.tsx +113 -0
  555. package/src/typography/index.ts +3 -0
@@ -0,0 +1,199 @@
1
+ /* oxlint-disable react/only-export-components -- The option hook belongs to the palette. */
2
+
3
+ import { Modal as NinnaModal } from '@ninna-ui/overlays';
4
+ import { SearchIcon, XIcon } from 'lucide-react';
5
+ import { createContext, type ReactNode, useContext, useEffect, useId, useRef, useState } from 'react';
6
+
7
+ import { IconButton } from '../actions/IconButton';
8
+ import { ResultList } from '../collections/ResultList';
9
+ import { useDesignSystemLabels } from '../foundations/DesignSystemProvider';
10
+ import { Text } from '../typography/Typography';
11
+ import { useModalAutoFocus } from './useModalAutoFocus';
12
+ import { useScrollFade } from './useScrollFade';
13
+
14
+ interface CommandPaletteProps {
15
+ /** The dialog's accessible title and description; the field says the rest. */
16
+ label: string;
17
+ description: string;
18
+ placeholder: string;
19
+ query: string;
20
+ onQueryChange: (query: string) => void;
21
+ /** Narrows the list to one level, shown as a chip before the field; Backspace in an empty field leaves it. */
22
+ scope?: { label: string; leaveLabel: string; onLeave: () => void };
23
+ /** The options' values in list order, for the arrow keys and Enter. */
24
+ options: readonly string[];
25
+ onSelect: (value: string) => void;
26
+ onClose: () => void;
27
+ listLabel: string;
28
+ busy?: boolean;
29
+ /** Shown when nothing is listed. */
30
+ empty?: ReactNode;
31
+ /** Quiet key hints under the list, on screens with a keyboard. */
32
+ footer?: ReactNode;
33
+ children: ReactNode;
34
+ }
35
+
36
+ const OptionContext = createContext<{
37
+ listId: string;
38
+ activeValue: string | undefined;
39
+ setActiveValue: (value: string) => void;
40
+ } | null>(null);
41
+
42
+ /** T3 Code's command palette: a field over one keyboard list of grouped options, as a dialog over the page
43
+ * or, on phones, the whole screen. The arrow keys move through `options`, Enter selects, Escape closes. */
44
+ export function CommandPalette({
45
+ label,
46
+ description,
47
+ placeholder,
48
+ query,
49
+ onQueryChange,
50
+ scope,
51
+ options,
52
+ onSelect,
53
+ onClose,
54
+ listLabel,
55
+ busy = false,
56
+ empty,
57
+ footer,
58
+ children,
59
+ }: CommandPaletteProps) {
60
+ const labels = useDesignSystemLabels();
61
+ const focusProps = useModalAutoFocus();
62
+ const { setViewport, setContent, className } = useScrollFade();
63
+ const listId = useId();
64
+ const input = useRef<HTMLInputElement>(null);
65
+ const [chosen, setActiveValue] = useState<string>();
66
+ // The highlight follows the list: when the chosen option leaves it, the first option takes over.
67
+ const activeValue = chosen !== undefined && options.includes(chosen) ? chosen : options[0];
68
+
69
+ useEffect(() => {
70
+ if (activeValue) document.getElementById(optionId(listId, activeValue))?.scrollIntoView({ block: 'nearest' });
71
+ }, [activeValue, listId]);
72
+
73
+ return (
74
+ <NinnaModal open onOpenChange={(open) => !open && onClose()}>
75
+ <NinnaModal.Content
76
+ title={label}
77
+ description={description}
78
+ centered={false}
79
+ {...focusProps}
80
+ 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)]"
81
+ >
82
+ <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">
83
+ <SearchIcon />
84
+ {scope ? (
85
+ <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">
86
+ {scope.label}
87
+ <button
88
+ type="button"
89
+ tabIndex={-1}
90
+ aria-label={scope.leaveLabel}
91
+ className="hover:bg-primary/15 rounded-sm p-0.5 [&>svg]:size-3"
92
+ onClick={() => {
93
+ scope.onLeave();
94
+ input.current?.focus();
95
+ }}
96
+ >
97
+ <XIcon />
98
+ </button>
99
+ </span>
100
+ ) : null}
101
+ <input
102
+ ref={input}
103
+ role="combobox"
104
+ aria-label={label}
105
+ aria-expanded
106
+ aria-controls={listId}
107
+ aria-autocomplete="list"
108
+ aria-activedescendant={activeValue ? optionId(listId, activeValue) : undefined}
109
+ aria-busy={busy}
110
+ placeholder={placeholder}
111
+ value={query}
112
+ className="text-base-content placeholder:text-base-600 min-w-0 flex-1 bg-transparent text-base outline-none sm:text-sm"
113
+ onChange={(event) => onQueryChange(event.target.value)}
114
+ onKeyDown={(event) => {
115
+ if (event.nativeEvent.isComposing) return;
116
+
117
+ if (event.key === 'Backspace' && !query && scope) {
118
+ event.preventDefault();
119
+ scope.onLeave();
120
+ } else if ((event.key === 'ArrowDown' || event.key === 'ArrowUp') && options.length) {
121
+ event.preventDefault();
122
+
123
+ const index = activeValue ? options.indexOf(activeValue) : -1;
124
+ const step = event.key === 'ArrowDown' ? 1 : -1;
125
+
126
+ setActiveValue(options[(index + step + options.length) % options.length]!);
127
+ } else if (event.key === 'Enter' && activeValue) {
128
+ event.preventDefault();
129
+ onSelect(activeValue);
130
+ }
131
+ }}
132
+ />
133
+ <span className="flex sm:hidden">
134
+ <IconButton aria-label={labels.close} icon={<XIcon />} onClick={onClose} variant="header" />
135
+ </span>
136
+ </div>
137
+ <div ref={setViewport} className={`min-h-0 flex-1 overflow-y-auto overscroll-contain p-2 ${className}`}>
138
+ <div ref={setContent} className="flow-root">
139
+ <OptionContext.Provider value={{ listId, activeValue, setActiveValue }}>
140
+ <ResultList id={listId} label={listLabel} density="compact" aria-busy={busy}>
141
+ {children}
142
+ </ResultList>
143
+ </OptionContext.Provider>
144
+ {options.length === 0 && empty ? (
145
+ <Text tone="muted" className="px-3 py-8 text-center">
146
+ {empty}
147
+ </Text>
148
+ ) : null}
149
+ </div>
150
+ </div>
151
+ {footer ? (
152
+ <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">
153
+ {footer}
154
+ </div>
155
+ ) : null}
156
+ </NinnaModal.Content>
157
+ </NinnaModal>
158
+ );
159
+ }
160
+
161
+ /** A labelled run of options in the palette's list. */
162
+ export function CommandPaletteGroup({ label, children }: { label: string; children: ReactNode }) {
163
+ const labelId = useId();
164
+
165
+ return (
166
+ <div role="group" aria-labelledby={labelId} className="flex flex-col gap-1 not-first:pt-2">
167
+ <Text
168
+ as="span"
169
+ id={labelId}
170
+ variant="caption"
171
+ tone="muted"
172
+ className="px-2 pt-1 font-medium tracking-wide uppercase"
173
+ >
174
+ {label}
175
+ </Text>
176
+ {children}
177
+ </div>
178
+ );
179
+ }
180
+
181
+ /** Props for a palette option, such as a `ResultRow`: its id, highlight and pointer tracking. */
182
+ export function useCommandPaletteOption(value: string) {
183
+ const context = useContext(OptionContext);
184
+
185
+ if (!context) throw new Error('useCommandPaletteOption must be used inside CommandPalette');
186
+
187
+ return {
188
+ id: optionId(context.listId, value),
189
+ selected: context.activeValue === value,
190
+ tabIndex: -1,
191
+ onPointerMove: () => {
192
+ if (context.activeValue !== value) context.setActiveValue(value);
193
+ },
194
+ };
195
+ }
196
+
197
+ function optionId(listId: string, value: string) {
198
+ return `${listId}-${value.replace(/[^\w-]/g, '_')}`;
199
+ }
@@ -0,0 +1,107 @@
1
+ /* oxlint-disable react/only-export-components -- Compound members are exported through Drawer. */
2
+ import {
3
+ Drawer as NinnaDrawer,
4
+ type DrawerBodyProps,
5
+ type DrawerContentProps,
6
+ type DrawerFooterProps,
7
+ } from '@ninna-ui/overlays';
8
+ import { XIcon } from 'lucide-react';
9
+ import { type ComponentProps, forwardRef, type ReactNode } from 'react';
10
+
11
+ import { IconButton } from '../actions/IconButton';
12
+ import { useDesignSystemLabels } from '../foundations/DesignSystemProvider';
13
+ import { Heading, Text } from '../typography/Typography';
14
+ import { useModalAutoFocus } from './useModalAutoFocus';
15
+
16
+ interface DrawerContentPolicyProps extends Omit<DrawerContentProps, 'className' | 'placement' | 'size' | 'title'> {
17
+ title: string;
18
+ subtitle?: ReactNode;
19
+ /** Header controls shown before the close button. */
20
+ actions?: ReactNode;
21
+ /** Runs as the drawer closes; preventing its default keeps focus from returning to the opening control. */
22
+ onCloseAutoFocus?: (event: Event) => void;
23
+ }
24
+
25
+ function DrawerRoot(props: ComponentProps<typeof NinnaDrawer>) {
26
+ return <NinnaDrawer {...props} />;
27
+ }
28
+
29
+ const DrawerContent = forwardRef<HTMLDivElement, DrawerContentPolicyProps>(
30
+ ({ actions, children, description, subtitle, title, onCloseAutoFocus, ...props }, ref) => {
31
+ const labels = useDesignSystemLabels();
32
+ const autoFocus = useModalAutoFocus();
33
+ const focusProps = {
34
+ ...autoFocus,
35
+ onCloseAutoFocus: (event: Event) => {
36
+ onCloseAutoFocus?.(event);
37
+
38
+ if (!event.defaultPrevented) autoFocus.onCloseAutoFocus(event);
39
+ },
40
+ };
41
+
42
+ return (
43
+ <NinnaDrawer.Content
44
+ ref={ref}
45
+ {...props}
46
+ {...focusProps}
47
+ title={title}
48
+ description={description}
49
+ placement="right"
50
+ size="lg"
51
+ className="flex w-full max-w-xl flex-col overflow-hidden"
52
+ >
53
+ <header
54
+ data-slot="drawer-header"
55
+ className="border-base-300 shrink-0 border-b px-5 py-5 sm:px-6 sm:py-6"
56
+ >
57
+ <div className="grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-start gap-4">
58
+ <Heading as="h2" className="min-w-0 wrap-break-word" variant="section">
59
+ {title}
60
+ </Heading>
61
+ <div className="flex items-center gap-1">
62
+ {actions}
63
+ <NinnaDrawer.Close asChild>
64
+ <IconButton aria-label={labels.close} icon={<XIcon />} variant="header" />
65
+ </NinnaDrawer.Close>
66
+ </div>
67
+ </div>
68
+ {(subtitle ?? description) ? (
69
+ <Text className="mt-2 wrap-break-word" variant="description" tone="muted">
70
+ {subtitle ?? description}
71
+ </Text>
72
+ ) : null}
73
+ </header>
74
+ {children}
75
+ </NinnaDrawer.Content>
76
+ );
77
+ },
78
+ );
79
+
80
+ DrawerContent.displayName = 'Drawer.Content';
81
+
82
+ const DrawerBody = forwardRef<HTMLDivElement, Omit<DrawerBodyProps, 'className'>>((props, ref) => (
83
+ <NinnaDrawer.Body
84
+ ref={ref}
85
+ {...props}
86
+ className="min-h-0 min-w-0 flex-1 overflow-y-auto overscroll-contain px-5 py-5 sm:px-6"
87
+ />
88
+ ));
89
+
90
+ DrawerBody.displayName = 'Drawer.Body';
91
+
92
+ const DrawerFooter = forwardRef<HTMLDivElement, Omit<DrawerFooterProps, 'className'>>((props, ref) => (
93
+ <NinnaDrawer.Footer
94
+ ref={ref}
95
+ {...props}
96
+ className="border-base-300 shrink-0 justify-between border-t px-5 py-3 sm:px-6 sm:py-3"
97
+ />
98
+ ));
99
+
100
+ DrawerFooter.displayName = 'Drawer.Footer';
101
+
102
+ export const Drawer = Object.assign(DrawerRoot, {
103
+ Body: DrawerBody,
104
+ Content: DrawerContent,
105
+ Footer: DrawerFooter,
106
+ Trigger: NinnaDrawer.Trigger,
107
+ });
@@ -0,0 +1,122 @@
1
+ /* oxlint-disable react/only-export-components -- Compound members are exported through DropdownMenu. */
2
+
3
+ import {
4
+ DropdownMenu as NinnaDropdownMenu,
5
+ type DropdownMenuContentProps,
6
+ type DropdownMenuItemProps,
7
+ type DropdownMenuLabelProps,
8
+ type DropdownMenuRadioGroupProps,
9
+ type DropdownMenuRadioItemProps,
10
+ } from '@ninna-ui/overlays';
11
+ import { type ComponentProps, forwardRef } from 'react';
12
+
13
+ interface DropdownMenuContentPolicyProps extends Omit<DropdownMenuContentProps, 'className'> {
14
+ width?: 'sm' | 'md';
15
+ }
16
+
17
+ const contentWidthClasses: Record<NonNullable<DropdownMenuContentPolicyProps['width']>, string> = {
18
+ sm: 'w-60',
19
+ md: 'w-64',
20
+ };
21
+
22
+ const DropdownMenuContent = forwardRef<HTMLDivElement, DropdownMenuContentPolicyProps>(
23
+ ({ side = 'bottom', sideOffset = 8, width = 'sm', ...props }, ref) => (
24
+ <NinnaDropdownMenu.Content
25
+ ref={ref}
26
+ side={side}
27
+ sideOffset={sideOffset}
28
+ {...props}
29
+ className={`${contentWidthClasses[width]} max-h-(--radix-dropdown-menu-content-available-height) max-w-[calc(100vw-2rem)] overflow-y-auto`}
30
+ />
31
+ ),
32
+ );
33
+
34
+ DropdownMenuContent.displayName = 'DropdownMenu.Content';
35
+
36
+ interface DropdownMenuLabelPolicyProps extends Omit<DropdownMenuLabelProps, 'className'> {
37
+ presentation?: 'section' | 'identity';
38
+ }
39
+
40
+ const DropdownMenuLabel = forwardRef<HTMLDivElement, DropdownMenuLabelPolicyProps>(
41
+ ({ presentation = 'section', ...props }, ref) => (
42
+ <NinnaDropdownMenu.Label
43
+ ref={ref}
44
+ {...props}
45
+ className={presentation === 'identity' ? 'tracking-normal normal-case' : undefined}
46
+ />
47
+ ),
48
+ );
49
+
50
+ DropdownMenuLabel.displayName = 'DropdownMenu.Label';
51
+
52
+ interface DropdownMenuItemPolicyProps extends Omit<DropdownMenuItemProps, 'className'> {
53
+ /** Forward the underlying menu item's behavior to a link without a second tab stop. */
54
+ asChild?: boolean;
55
+ }
56
+
57
+ const DropdownMenuItem = forwardRef<HTMLDivElement, DropdownMenuItemPolicyProps>((props, ref) => (
58
+ <NinnaDropdownMenu.Item
59
+ ref={ref}
60
+ {...props}
61
+ className="aria-[current=page]:bg-primary/10 aria-[current=page]:text-primary max-lg:min-h-11 pointer-coarse:min-h-11 [&>svg]:size-4 [&>svg]:shrink-0"
62
+ />
63
+ ));
64
+
65
+ DropdownMenuItem.displayName = 'DropdownMenu.Item';
66
+
67
+ interface DropdownMenuRadioGroupPolicyProps extends Omit<DropdownMenuRadioGroupProps, 'className'> {
68
+ presentation?: 'default' | 'segmented';
69
+ }
70
+
71
+ const DropdownMenuRadioGroup = forwardRef<HTMLDivElement, DropdownMenuRadioGroupPolicyProps>(
72
+ ({ presentation = 'default', ...props }, ref) => (
73
+ <NinnaDropdownMenu.RadioGroup
74
+ ref={ref}
75
+ {...props}
76
+ className={presentation === 'segmented' ? 'bg-base-200/70 flex gap-0.5 rounded-lg p-0.5' : undefined}
77
+ />
78
+ ),
79
+ );
80
+
81
+ DropdownMenuRadioGroup.displayName = 'DropdownMenu.RadioGroup';
82
+
83
+ interface DropdownMenuRadioItemPolicyProps extends Omit<DropdownMenuRadioItemProps, 'className'> {
84
+ presentation?: 'default' | 'segmented';
85
+ }
86
+
87
+ const DropdownMenuRadioItem = forwardRef<HTMLDivElement, DropdownMenuRadioItemPolicyProps>(
88
+ ({ onSelect, presentation = 'default', ...props }, ref) => (
89
+ <NinnaDropdownMenu.RadioItem
90
+ ref={ref}
91
+ {...props}
92
+ data-presentation={presentation}
93
+ onSelect={
94
+ presentation === 'segmented'
95
+ ? (event) => {
96
+ event.preventDefault();
97
+ onSelect?.(event);
98
+ }
99
+ : onSelect
100
+ }
101
+ className={
102
+ presentation === 'segmented'
103
+ ? 'text-base-600 focus:bg-base-300 focus:text-base-content data-[state=checked]:bg-base-100 data-[state=checked]:text-base-content size-7 justify-center rounded-md p-0 data-[state=checked]:shadow-sm [&>span]:hidden [&>svg]:size-4'
104
+ : 'max-lg:min-h-11 pointer-coarse:min-h-11 [&>svg]:size-4 [&>svg]:shrink-0'
105
+ }
106
+ />
107
+ ),
108
+ );
109
+
110
+ DropdownMenuRadioItem.displayName = 'DropdownMenu.RadioItem';
111
+
112
+ function DropdownMenuRoot(props: ComponentProps<typeof NinnaDropdownMenu>) {
113
+ return <NinnaDropdownMenu {...props} />;
114
+ }
115
+
116
+ export const DropdownMenu = Object.assign(DropdownMenuRoot, NinnaDropdownMenu, {
117
+ Content: DropdownMenuContent,
118
+ Item: DropdownMenuItem,
119
+ Label: DropdownMenuLabel,
120
+ RadioGroup: DropdownMenuRadioGroup,
121
+ RadioItem: DropdownMenuRadioItem,
122
+ });
@@ -0,0 +1,96 @@
1
+ import { Loading } from '@ninna-ui/feedback';
2
+ import { Modal as NinnaModal } from '@ninna-ui/overlays';
3
+ import { XIcon } from 'lucide-react';
4
+ import { useId, useState } from 'react';
5
+
6
+ import { IconButton } from '../actions/IconButton';
7
+ import { useDesignSystemLabels } from '../foundations/DesignSystemProvider';
8
+ import { Text } from '../typography/Typography';
9
+ import { useModalAutoFocus } from './useModalAutoFocus';
10
+
11
+ interface ImageViewerProps {
12
+ alt: string;
13
+ caption?: string;
14
+ onClose: () => void;
15
+ open: boolean;
16
+ /** Pixel size to show beside the caption; omit when unknown rather than guessing. */
17
+ resolution?: { height: number; width: number };
18
+ /** Omit while the image is not ready yet (still loading, authenticating, and so on); shows the
19
+ * same loading indicator as a slow-loading image rather than a broken one. */
20
+ src?: string;
21
+ }
22
+
23
+ /**
24
+ * Shows one image at its natural size over the blurred modal backdrop, scaled down only when it would not fit.
25
+ * Clicking anywhere except the image, the close button, or Escape dismisses it.
26
+ */
27
+ export function ImageViewer({ alt, caption, onClose, open, resolution, src }: ImageViewerProps) {
28
+ const labels = useDesignSystemLabels();
29
+ const focusProps = useModalAutoFocus();
30
+ const captionId = useId();
31
+ const [loadedSource, setLoadedSource] = useState<string>();
32
+ const loaded = Boolean(src) && loadedSource === src;
33
+ const size = resolution ? labels.imageSize(resolution.width, resolution.height) : undefined;
34
+
35
+ return (
36
+ <NinnaModal open={open} onOpenChange={(next) => !next && onClose()}>
37
+ <NinnaModal.Content
38
+ {...focusProps}
39
+ title={caption ?? alt}
40
+ size="full"
41
+ className="top-0 left-0 flex h-dvh max-h-none w-screen translate-x-0 translate-y-0 items-center justify-center overflow-hidden rounded-none border-0 bg-transparent p-4 shadow-none sm:top-0 sm:left-0 sm:h-dvh sm:w-screen sm:translate-x-0 sm:translate-y-0 sm:p-8"
42
+ onClick={(event) => event.target === event.currentTarget && onClose()}
43
+ >
44
+ {/* The standard header close button, lightened because it always sits on the dark backdrop. */}
45
+ <div className="absolute top-5 right-5 z-10 [--color-header-icon:#ffffff] sm:top-6 sm:right-6">
46
+ <NinnaModal.Close asChild>
47
+ <IconButton aria-label={labels.close} icon={<XIcon />} variant="header" />
48
+ </NinnaModal.Close>
49
+ </div>
50
+ {loaded ? null : (
51
+ <span className="pointer-events-none absolute inset-0 flex items-center justify-center text-white/80">
52
+ <Loading size="lg" />
53
+ </span>
54
+ )}
55
+ {/* Only the image itself catches clicks; the space around it and the caption fall through to close. */}
56
+ <figure
57
+ aria-labelledby={caption ? captionId : undefined}
58
+ className="pointer-events-none m-0 flex max-w-full flex-col items-center gap-3"
59
+ >
60
+ {src ? (
61
+ <img
62
+ alt={alt}
63
+ src={src}
64
+ decoding="async"
65
+ ref={(image) => {
66
+ if (image?.complete && image.naturalWidth > 0) setLoadedSource(src);
67
+ }}
68
+ onLoad={() => setLoadedSource(src)}
69
+ onError={() => setLoadedSource(src)}
70
+ className={`pointer-events-auto max-h-[calc(100dvh-7rem)] max-w-full rounded-lg object-contain shadow-2xl transition-opacity duration-200 motion-reduce:transition-none sm:max-h-[calc(100dvh-9rem)] ${loaded ? 'opacity-100' : 'opacity-0'}`}
71
+ />
72
+ ) : null}
73
+ {caption || size ? (
74
+ <figcaption className="flex max-w-prose flex-wrap items-baseline justify-center gap-x-3 gap-y-1 text-center">
75
+ {caption ? (
76
+ <Text
77
+ id={captionId}
78
+ as="span"
79
+ className="wrap-break-word text-white/90"
80
+ variant="label"
81
+ >
82
+ {caption}
83
+ </Text>
84
+ ) : null}
85
+ {size ? (
86
+ <Text as="span" className="text-white/60 tabular-nums" variant="caption">
87
+ {size}
88
+ </Text>
89
+ ) : null}
90
+ </figcaption>
91
+ ) : null}
92
+ </figure>
93
+ </NinnaModal.Content>
94
+ </NinnaModal>
95
+ );
96
+ }