@dxos/react-ui 0.9.0 → 0.9.1-staging.ee54ba693a

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 (263) hide show
  1. package/dist/lib/browser/{chunk-5SPBSIWS.mjs → chunk-CMHHVHX3.mjs} +14 -1
  2. package/dist/lib/browser/chunk-CMHHVHX3.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-7JFD5ZHZ.mjs → chunk-GTHV4WYK.mjs} +141 -254
  4. package/dist/lib/browser/chunk-GTHV4WYK.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +1553 -1274
  6. package/dist/lib/browser/index.mjs.map +4 -4
  7. package/dist/lib/browser/meta.json +1 -1
  8. package/dist/lib/browser/testing/index.mjs +5 -5
  9. package/dist/lib/browser/testing/index.mjs.map +2 -2
  10. package/dist/lib/browser/translations.mjs +1 -1
  11. package/dist/lib/node-esm/{chunk-TTEL2FP2.mjs → chunk-3VSKWNCQ.mjs} +141 -254
  12. package/dist/lib/node-esm/chunk-3VSKWNCQ.mjs.map +7 -0
  13. package/dist/lib/node-esm/{chunk-FPVTVXND.mjs → chunk-P4KFQGJI.mjs} +14 -1
  14. package/dist/lib/node-esm/chunk-P4KFQGJI.mjs.map +7 -0
  15. package/dist/lib/node-esm/index.mjs +1553 -1274
  16. package/dist/lib/node-esm/index.mjs.map +4 -4
  17. package/dist/lib/node-esm/meta.json +1 -1
  18. package/dist/lib/node-esm/testing/index.mjs +5 -5
  19. package/dist/lib/node-esm/testing/index.mjs.map +2 -2
  20. package/dist/lib/node-esm/translations.mjs +1 -1
  21. package/dist/types/src/components/Avatars/Avatar.d.ts +1 -1
  22. package/dist/types/src/components/Avatars/Avatar.d.ts.map +1 -1
  23. package/dist/types/src/components/Breadcrumb/Breadcrumb.d.ts +3 -3
  24. package/dist/types/src/components/Breadcrumb/Breadcrumb.d.ts.map +1 -1
  25. package/dist/types/src/components/Button/Button.d.ts +4 -2
  26. package/dist/types/src/components/Button/Button.d.ts.map +1 -1
  27. package/dist/types/src/components/Button/IconButton.d.ts +0 -1
  28. package/dist/types/src/components/Button/IconButton.d.ts.map +1 -1
  29. package/dist/types/src/components/Button/IconButton.stories.d.ts +37 -0
  30. package/dist/types/src/components/Button/IconButton.stories.d.ts.map +1 -1
  31. package/dist/types/src/components/Button/MicButton.d.ts +24 -0
  32. package/dist/types/src/components/Button/MicButton.d.ts.map +1 -0
  33. package/dist/types/src/components/Button/MicButton.stories.d.ts +57 -0
  34. package/dist/types/src/components/Button/MicButton.stories.d.ts.map +1 -0
  35. package/dist/types/src/components/Button/SystemIconButton.d.ts +33 -0
  36. package/dist/types/src/components/Button/SystemIconButton.d.ts.map +1 -0
  37. package/dist/types/src/components/Button/SystemIconButton.stories.d.ts +51 -0
  38. package/dist/types/src/components/Button/SystemIconButton.stories.d.ts.map +1 -0
  39. package/dist/types/src/components/Button/ToggleGroup.d.ts +2 -2
  40. package/dist/types/src/components/Button/ToggleGroup.d.ts.map +1 -1
  41. package/dist/types/src/components/Button/ToggleIconButton.d.ts +15 -0
  42. package/dist/types/src/components/Button/ToggleIconButton.d.ts.map +1 -0
  43. package/dist/types/src/components/Button/index.d.ts +3 -0
  44. package/dist/types/src/components/Button/index.d.ts.map +1 -1
  45. package/dist/types/src/components/Calendar/Calendar.d.ts.map +1 -1
  46. package/dist/types/src/components/Calendar/Calendar.theme.d.ts.map +1 -1
  47. package/dist/types/src/components/Card/Card.d.ts +32 -26
  48. package/dist/types/src/components/Card/Card.d.ts.map +1 -1
  49. package/dist/types/src/components/Card/Card.stories.d.ts +3 -3
  50. package/dist/types/src/components/Card/Card.stories.d.ts.map +1 -1
  51. package/dist/types/src/components/Card/Card.theme.d.ts.map +1 -1
  52. package/dist/types/src/components/Carousel/Carousel.d.ts +29 -6
  53. package/dist/types/src/components/Carousel/Carousel.d.ts.map +1 -1
  54. package/dist/types/src/components/Carousel/Carousel.stories.d.ts +48 -2
  55. package/dist/types/src/components/Carousel/Carousel.stories.d.ts.map +1 -1
  56. package/dist/types/src/components/Clipboard/index.d.ts +1 -0
  57. package/dist/types/src/components/Clipboard/index.d.ts.map +1 -1
  58. package/dist/types/src/components/Column/Column.d.ts +20 -2
  59. package/dist/types/src/components/Column/Column.d.ts.map +1 -1
  60. package/dist/types/src/components/Column/Column.theme.d.ts +8 -0
  61. package/dist/types/src/components/Column/Column.theme.d.ts.map +1 -1
  62. package/dist/types/src/components/Dialog/AlertDialog.d.ts +2 -2
  63. package/dist/types/src/components/Dialog/AlertDialog.d.ts.map +1 -1
  64. package/dist/types/src/components/Dialog/Dialog.d.ts +1 -1
  65. package/dist/types/src/components/Dialog/Dialog.d.ts.map +1 -1
  66. package/dist/types/src/components/Dialog/Dialog.stories.d.ts +2 -2
  67. package/dist/types/src/components/Dialog/Dialog.stories.d.ts.map +1 -1
  68. package/dist/types/src/components/Icon/Icon.stories.d.ts +5 -0
  69. package/dist/types/src/components/Icon/Icon.stories.d.ts.map +1 -1
  70. package/dist/types/src/components/Input/Input.d.ts +4 -1
  71. package/dist/types/src/components/Input/Input.d.ts.map +1 -1
  72. package/dist/types/src/components/Input/Input.stories.d.ts +3 -3
  73. package/dist/types/src/components/Input/Input.stories.d.ts.map +1 -1
  74. package/dist/types/src/components/Input/Input.theme.d.ts +10 -10
  75. package/dist/types/src/components/Input/Input.theme.d.ts.map +1 -1
  76. package/dist/types/src/components/Input/SegmentedInput.d.ts +8 -8
  77. package/dist/types/src/components/Input/SegmentedInput.d.ts.map +1 -1
  78. package/dist/types/src/components/Input/index.d.ts +0 -1
  79. package/dist/types/src/components/Input/index.d.ts.map +1 -1
  80. package/dist/types/src/components/Main/Main.d.ts +3 -3
  81. package/dist/types/src/components/Main/Main.d.ts.map +1 -1
  82. package/dist/types/src/components/Menu/ContextMenu.d.ts +1 -1
  83. package/dist/types/src/components/Menu/ContextMenu.d.ts.map +1 -1
  84. package/dist/types/src/components/Menu/DropdownMenu.d.ts +2 -2
  85. package/dist/types/src/components/Menu/DropdownMenu.d.ts.map +1 -1
  86. package/dist/types/src/components/Message/Message.d.ts +1 -1
  87. package/dist/types/src/components/Message/Message.d.ts.map +1 -1
  88. package/dist/types/src/components/Message/Message.stories.d.ts +2 -2
  89. package/dist/types/src/components/Message/Message.stories.d.ts.map +1 -1
  90. package/dist/types/src/components/Message/Message.theme.d.ts.map +1 -1
  91. package/dist/types/src/components/Panel/Panel.d.ts +1 -1
  92. package/dist/types/src/components/Panel/Panel.d.ts.map +1 -1
  93. package/dist/types/src/components/Panel/Panel.theme.d.ts.map +1 -1
  94. package/dist/types/src/components/Popover/Popover.d.ts +2 -2
  95. package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
  96. package/dist/types/src/components/ScrollArea/ScrollArea.d.ts +2 -0
  97. package/dist/types/src/components/ScrollArea/ScrollArea.d.ts.map +1 -1
  98. package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts +1 -0
  99. package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts.map +1 -1
  100. package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts +1 -1
  101. package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts.map +1 -1
  102. package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts +2 -2
  103. package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts.map +1 -1
  104. package/dist/types/src/components/Select/Select.d.ts +1 -1
  105. package/dist/types/src/components/Select/Select.d.ts.map +1 -1
  106. package/dist/types/src/components/Select/Select.stories.d.ts +2 -2
  107. package/dist/types/src/components/Select/Select.stories.d.ts.map +1 -1
  108. package/dist/types/src/components/Separator/Separator.d.ts.map +1 -1
  109. package/dist/types/src/components/Splitter/Splitter.d.ts +30 -16
  110. package/dist/types/src/components/Splitter/Splitter.d.ts.map +1 -1
  111. package/dist/types/src/components/Splitter/Splitter.stories.d.ts +6 -1
  112. package/dist/types/src/components/Splitter/Splitter.stories.d.ts.map +1 -1
  113. package/dist/types/src/components/Splitter/Splitter.theme.d.ts +3 -1
  114. package/dist/types/src/components/Splitter/Splitter.theme.d.ts.map +1 -1
  115. package/dist/types/src/components/Tag/Tag.d.ts +1 -1
  116. package/dist/types/src/components/Tag/Tag.d.ts.map +1 -1
  117. package/dist/types/src/components/Tag/Tag.theme.d.ts +1 -1
  118. package/dist/types/src/components/Tag/Tag.theme.d.ts.map +1 -1
  119. package/dist/types/src/components/Toast/Toast.d.ts +1 -1
  120. package/dist/types/src/components/Toast/Toast.d.ts.map +1 -1
  121. package/dist/types/src/components/Toast/Toast.theme.d.ts.map +1 -1
  122. package/dist/types/src/components/Toolbar/Toolbar.d.ts +1 -1
  123. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  124. package/dist/types/src/components/Tooltip/TextTooltip.d.ts +19 -0
  125. package/dist/types/src/components/Tooltip/TextTooltip.d.ts.map +1 -0
  126. package/dist/types/src/components/Tooltip/Tooltip.d.ts +3 -3
  127. package/dist/types/src/components/Tooltip/Tooltip.d.ts.map +1 -1
  128. package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts +2 -2
  129. package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts.map +1 -1
  130. package/dist/types/src/components/Tooltip/index.d.ts +1 -0
  131. package/dist/types/src/components/Tooltip/index.d.ts.map +1 -1
  132. package/dist/types/src/components/index.d.ts +0 -1
  133. package/dist/types/src/components/index.d.ts.map +1 -1
  134. package/dist/types/src/index.d.ts +1 -1
  135. package/dist/types/src/index.d.ts.map +1 -1
  136. package/dist/types/src/primitives/ThemeProvider/TranslationsProvider.d.ts +1 -8
  137. package/dist/types/src/primitives/ThemeProvider/TranslationsProvider.d.ts.map +1 -1
  138. package/dist/types/src/testing/Loading.d.ts.map +1 -1
  139. package/dist/types/src/theme/defaultTheme.d.ts.map +1 -1
  140. package/dist/types/src/theme/index.d.ts +0 -2
  141. package/dist/types/src/theme/index.d.ts.map +1 -1
  142. package/dist/types/src/translations.d.ts +13 -0
  143. package/dist/types/src/translations.d.ts.map +1 -1
  144. package/dist/types/src/util/slots.d.ts +1 -1
  145. package/dist/types/src/util/slots.d.ts.map +1 -1
  146. package/dist/types/tsconfig.tsbuildinfo +1 -1
  147. package/package.json +22 -21
  148. package/src/components/Avatars/Avatar.stories.tsx +2 -2
  149. package/src/components/Avatars/Avatar.theme.ts +1 -1
  150. package/src/components/Avatars/Avatar.tsx +3 -3
  151. package/src/components/Breadcrumb/Breadcrumb.tsx +6 -6
  152. package/src/components/Button/Button.tsx +25 -4
  153. package/src/components/Button/IconButton.stories.tsx +81 -1
  154. package/src/components/Button/IconButton.tsx +2 -4
  155. package/src/components/Button/MicButton.stories.tsx +60 -0
  156. package/src/components/Button/MicButton.tsx +117 -0
  157. package/src/components/Button/SystemIconButton.stories.tsx +91 -0
  158. package/src/components/Button/SystemIconButton.tsx +264 -0
  159. package/src/components/Button/ToggleGroup.tsx +2 -2
  160. package/src/components/Button/ToggleIconButton.tsx +32 -0
  161. package/src/components/Button/index.ts +3 -0
  162. package/src/components/Calendar/Calendar.theme.ts +2 -0
  163. package/src/components/Calendar/Calendar.tsx +3 -3
  164. package/src/components/Card/Card.stories.tsx +71 -29
  165. package/src/components/Card/Card.theme.ts +27 -9
  166. package/src/components/Card/Card.tsx +176 -99
  167. package/src/components/Carousel/Carousel.stories.tsx +42 -18
  168. package/src/components/Carousel/Carousel.tsx +169 -33
  169. package/src/components/Column/Column.theme.ts +32 -4
  170. package/src/components/Column/Column.tsx +39 -7
  171. package/src/components/Dialog/AlertDialog.stories.tsx +2 -2
  172. package/src/components/Dialog/AlertDialog.tsx +13 -13
  173. package/src/components/Dialog/Dialog.stories.tsx +3 -4
  174. package/src/components/Dialog/Dialog.theme.ts +1 -1
  175. package/src/components/Dialog/Dialog.tsx +12 -12
  176. package/src/components/Icon/Icon.stories.tsx +23 -0
  177. package/src/components/Icon/Icon.theme.ts +1 -1
  178. package/src/components/Input/Input.stories.tsx +13 -5
  179. package/src/components/Input/Input.theme.ts +17 -39
  180. package/src/components/Input/Input.tsx +30 -13
  181. package/src/components/Input/SegmentedInput.tsx +50 -41
  182. package/src/components/Input/index.ts +0 -1
  183. package/src/components/Main/Main.tsx +3 -3
  184. package/src/components/MediaPlayer/MediaPlayer.tsx +4 -4
  185. package/src/components/Menu/ContextMenu.tsx +8 -8
  186. package/src/components/Menu/DropdownMenu.tsx +12 -13
  187. package/src/components/Message/Message.stories.tsx +2 -2
  188. package/src/components/Message/Message.theme.ts +1 -11
  189. package/src/components/Message/Message.tsx +6 -6
  190. package/src/components/Panel/Panel.theme.ts +2 -1
  191. package/src/components/Panel/Panel.tsx +1 -1
  192. package/src/components/Popover/Popover.theme.ts +1 -1
  193. package/src/components/Popover/Popover.tsx +9 -9
  194. package/src/components/ScrollArea/ScrollArea.tsx +7 -4
  195. package/src/components/ScrollContainer/ScrollContainer.stories.tsx +2 -2
  196. package/src/components/ScrollContainer/ScrollContainer.tsx +2 -2
  197. package/src/components/Select/Select.stories.tsx +2 -2
  198. package/src/components/Select/Select.theme.ts +1 -1
  199. package/src/components/Select/Select.tsx +14 -14
  200. package/src/components/Separator/Separator.tsx +1 -0
  201. package/src/components/Splitter/Splitter.stories.tsx +84 -20
  202. package/src/components/Splitter/Splitter.theme.ts +20 -3
  203. package/src/components/Splitter/Splitter.tsx +320 -47
  204. package/src/components/Tag/Tag.stories.tsx +1 -1
  205. package/src/components/Tag/Tag.theme.ts +1 -1
  206. package/src/components/Tag/Tag.tsx +3 -5
  207. package/src/components/Toast/Toast.theme.ts +3 -8
  208. package/src/components/Toast/Toast.tsx +16 -15
  209. package/src/components/Toolbar/Toolbar.tsx +10 -10
  210. package/src/components/Tooltip/TextTooltip.tsx +54 -0
  211. package/src/components/Tooltip/Tooltip.stories.tsx +2 -2
  212. package/src/components/Tooltip/Tooltip.tsx +3 -3
  213. package/src/components/Tooltip/index.ts +1 -0
  214. package/src/components/index.ts +0 -1
  215. package/src/exemplars/tabster.stories.tsx +1 -1
  216. package/src/index.ts +1 -1
  217. package/src/primitives/ThemeProvider/TranslationsProvider.tsx +10 -30
  218. package/src/testing/Loading.tsx +2 -1
  219. package/src/testing/decorators/withLayout.tsx +2 -2
  220. package/src/theme/defaultTheme.ts +0 -4
  221. package/src/theme/index.ts +0 -2
  222. package/src/translations.ts +18 -0
  223. package/src/util/slots.ts +5 -5
  224. package/dist/lib/browser/chunk-5SPBSIWS.mjs.map +0 -7
  225. package/dist/lib/browser/chunk-7JFD5ZHZ.mjs.map +0 -7
  226. package/dist/lib/node-esm/chunk-FPVTVXND.mjs.map +0 -7
  227. package/dist/lib/node-esm/chunk-TTEL2FP2.mjs.map +0 -7
  228. package/dist/types/src/components/Input/constants.d.ts +0 -2
  229. package/dist/types/src/components/Input/constants.d.ts.map +0 -1
  230. package/dist/types/src/components/List/List.d.ts +0 -29
  231. package/dist/types/src/components/List/List.d.ts.map +0 -1
  232. package/dist/types/src/components/List/List.stories.d.ts +0 -16
  233. package/dist/types/src/components/List/List.stories.d.ts.map +0 -1
  234. package/dist/types/src/components/List/List.theme.d.ts +0 -7
  235. package/dist/types/src/components/List/List.theme.d.ts.map +0 -1
  236. package/dist/types/src/components/List/ListDropIndicator.d.ts +0 -13
  237. package/dist/types/src/components/List/ListDropIndicator.d.ts.map +0 -1
  238. package/dist/types/src/components/List/Tree.d.ts +0 -23
  239. package/dist/types/src/components/List/Tree.d.ts.map +0 -1
  240. package/dist/types/src/components/List/Tree.stories.d.ts +0 -15
  241. package/dist/types/src/components/List/Tree.stories.d.ts.map +0 -1
  242. package/dist/types/src/components/List/TreeDropIndicator.d.ts +0 -8
  243. package/dist/types/src/components/List/TreeDropIndicator.d.ts.map +0 -1
  244. package/dist/types/src/components/List/Treegrid.d.ts +0 -33
  245. package/dist/types/src/components/List/Treegrid.d.ts.map +0 -1
  246. package/dist/types/src/components/List/Treegrid.stories.d.ts +0 -12
  247. package/dist/types/src/components/List/Treegrid.stories.d.ts.map +0 -1
  248. package/dist/types/src/components/List/Treegrid.theme.d.ts +0 -7
  249. package/dist/types/src/components/List/Treegrid.theme.d.ts.map +0 -1
  250. package/dist/types/src/components/List/index.d.ts +0 -4
  251. package/dist/types/src/components/List/index.d.ts.map +0 -1
  252. package/src/components/Input/constants.ts +0 -5
  253. package/src/components/List/List.stories.tsx +0 -234
  254. package/src/components/List/List.theme.ts +0 -47
  255. package/src/components/List/List.tsx +0 -171
  256. package/src/components/List/ListDropIndicator.tsx +0 -69
  257. package/src/components/List/Tree.stories.tsx +0 -87
  258. package/src/components/List/Tree.tsx +0 -74
  259. package/src/components/List/TreeDropIndicator.tsx +0 -70
  260. package/src/components/List/Treegrid.stories.tsx +0 -156
  261. package/src/components/List/Treegrid.theme.ts +0 -35
  262. package/src/components/List/Treegrid.tsx +0 -187
  263. package/src/components/List/index.ts +0 -7
@@ -5,25 +5,23 @@
5
5
  import { Primitive } from '@radix-ui/react-primitive';
6
6
  import { Slot } from '@radix-ui/react-slot';
7
7
  import DOMPurify from 'dompurify';
8
- import React, { CSSProperties, JSX, MouseEventHandler, type ReactNode, forwardRef, useId, useMemo } from 'react';
8
+ import React, { CSSProperties, MouseEventHandler, type ReactNode, forwardRef, useId, useMemo } from 'react';
9
+ import { useTranslation } from 'react-i18next';
9
10
 
10
11
  import { iconSize } from '@dxos/ui-theme';
11
- import { type Density } from '@dxos/ui-types';
12
+ import { type Density, type SlottableProps } from '@dxos/ui-types';
13
+
14
+ import { translationKey } from '#translations';
12
15
 
13
16
  import { useThemeContext } from '../../hooks';
14
17
  import { composable, composableProps, slottable } from '../../util';
15
18
  import { type ThemedClassName } from '../../util';
16
- import { Button } from '../Button';
19
+ import { Button, IconButton } from '../Button';
17
20
  import { Column } from '../Column';
18
- import { Icon, IconBlock, type IconBlockProps, type IconProps } from '../Icon';
21
+ import { Icon } from '../Icon';
19
22
  import { Image, type ImageProps } from '../Image';
20
- import {
21
- Toolbar,
22
- type ToolbarActionIconButtonProps,
23
- ToolbarDragHandleProps,
24
- type ToolbarMenuProps,
25
- type ToolbarRootProps,
26
- } from '../Toolbar';
23
+ import { DropdownMenu } from '../Menu';
24
+ import { type ToolbarActionIconButtonProps, type ToolbarDragHandleProps, type ToolbarMenuProps } from '../Toolbar';
27
25
 
28
26
  //
29
27
  // Root
@@ -32,13 +30,13 @@ import {
32
30
  const CARD_ROOT_NAME = 'Card.Root';
33
31
 
34
32
  type CardRootProps = {
35
- id?: string;
36
- border?: boolean;
37
- fullWidth?: boolean;
38
- density?: Density;
39
- style?: CSSProperties;
40
- tabIndex?: number;
41
- onClick?: MouseEventHandler<HTMLDivElement>;
33
+ 'id'?: string;
34
+ 'border'?: boolean;
35
+ 'fullWidth'?: boolean;
36
+ 'density'?: Density;
37
+ 'style'?: CSSProperties;
38
+ 'tabIndex'?: number;
39
+ 'onClick'?: MouseEventHandler<HTMLDivElement>;
42
40
  'data-selected'?: boolean;
43
41
  'data-testid'?: string;
44
42
  };
@@ -62,7 +60,7 @@ const CardRoot = composable<HTMLDivElement, CardRootProps>(
62
60
  return (
63
61
  <Column.Root
64
62
  asChild
65
- gutter={density === 'lg' ? 'lg' : density === 'sm' || density === 'xs' ? 'sm' : 'md'}
63
+ gutter='lg'
66
64
  classNames={tx('card.root', { border, fullWidth }, className)}
67
65
  role={role ?? 'group'}
68
66
  >
@@ -82,22 +80,34 @@ CardRoot.displayName = CARD_ROOT_NAME;
82
80
 
83
81
  const CARD_HEADER_NAME = 'Card.Header';
84
82
 
85
- type CardHeaderProps = ToolbarRootProps;
83
+ type CardHeaderProps = SlottableProps;
86
84
 
87
85
  /**
88
- * Top "header" slot of a Card. Despite the name, this renders as an ARIA
89
- * toolbar (`role="toolbar"`) so its action children get keyboard navigation
90
- * for free`<header>` is allowed to contain a toolbar.
86
+ * Top header row of a Card. Renders as a `<header>` and shares `Card.Row`'s subgrid +
87
+ * `data-slot` layout: `Card.Block` children land in the gutters, anonymous children
88
+ * (e.g. `Card.Title`) in the center. Sets `--icon-size` 5 — header icons are larger than
89
+ * row icons (which use 4). Not a toolbar: most headers carry 0–1 controls, so `role="toolbar"`
90
+ * was inaccurate; controls are reached by normal tab order.
91
91
  */
92
- const CardHeader = composable<HTMLDivElement, CardHeaderProps>(({ children, classNames, ...props }, forwardedRef) => {
93
- const { tx } = useThemeContext();
92
+ const CardHeader = slottable<HTMLDivElement, CardHeaderProps>(
93
+ ({ children, asChild, style, ...props }, forwardedRef) => {
94
+ const { tx } = useThemeContext();
95
+ const { className, ...rest } = composableProps(props);
96
+ // `@radix-ui/react-primitive` has no `header` node; the intrinsic element handles asChild via Slot.
97
+ const Comp = asChild ? Slot : 'header';
94
98
 
95
- return (
96
- <Toolbar.Root {...props} style={iconSize(5)} classNames={[tx('card.header', {}), classNames]} ref={forwardedRef}>
97
- {children}
98
- </Toolbar.Root>
99
- );
100
- });
99
+ return (
100
+ <Comp
101
+ {...rest}
102
+ style={{ ...iconSize(5), ...style }}
103
+ className={tx('card.header', {}, className)}
104
+ ref={forwardedRef}
105
+ >
106
+ {children}
107
+ </Comp>
108
+ );
109
+ },
110
+ );
101
111
 
102
112
  CardHeader.displayName = CARD_HEADER_NAME;
103
113
 
@@ -109,13 +119,27 @@ const CARD_DRAG_HANDLE_NAME = 'Card.DragHandle';
109
119
 
110
120
  type CardDragHandleProps = ToolbarDragHandleProps;
111
121
 
112
- const CardDragHandle = forwardRef<HTMLButtonElement, CardDragHandleProps>((props, forwardedRef) => {
113
- return (
114
- <CardIconBlock>
115
- <Toolbar.DragHandle {...props} ref={forwardedRef} />
116
- </CardIconBlock>
117
- );
118
- });
122
+ const CardDragHandle = forwardRef<HTMLButtonElement, CardDragHandleProps>(
123
+ ({ testId = 'drag-handle', label }, forwardedRef) => {
124
+ const { t } = useTranslation(translationKey);
125
+ return (
126
+ <CardBlock>
127
+ <IconButton
128
+ data-testid={testId}
129
+ tabIndex={-1}
130
+ noTooltip
131
+ iconOnly
132
+ icon='ph--dots-six-vertical--regular'
133
+ variant='ghost'
134
+ label={label ?? t('toolbar-drag-handle.label')}
135
+ classNames='dx-focus-ring-none cursor-pointer text-base-fg'
136
+ disabled={!forwardedRef}
137
+ ref={forwardedRef}
138
+ />
139
+ </CardBlock>
140
+ );
141
+ },
142
+ );
119
143
 
120
144
  CardDragHandle.displayName = CARD_DRAG_HANDLE_NAME;
121
145
 
@@ -127,13 +151,28 @@ const CARD_ACTION_ICON_BUTTON_NAME = 'Card.ActionIconButton';
127
151
 
128
152
  type CardActionIconButtonProps = ToolbarActionIconButtonProps;
129
153
 
130
- const CardActionIconButton = forwardRef<HTMLButtonElement, CardActionIconButtonProps>((props, forwardedRef) => {
131
- return (
132
- <CardIconBlock>
133
- <Toolbar.ActionIconButton {...props} ref={forwardedRef} />
134
- </CardIconBlock>
135
- );
136
- });
154
+ const CARD_ACTION_ICONS = { close: 'ph--x--regular', delete: 'ph--trash--regular' } as const;
155
+
156
+ const CARD_ACTION_LABEL_KEYS = { close: 'toolbar-close.label', delete: 'toolbar-delete.label' } as const;
157
+
158
+ const CardActionIconButton = forwardRef<HTMLButtonElement, CardActionIconButtonProps>(
159
+ ({ action, onClick, label }, forwardedRef) => {
160
+ const { t } = useTranslation(translationKey);
161
+ return (
162
+ <CardBlock end>
163
+ <IconButton
164
+ iconOnly
165
+ icon={CARD_ACTION_ICONS[action]}
166
+ variant='ghost'
167
+ label={label ?? t(CARD_ACTION_LABEL_KEYS[action])}
168
+ classNames='cursor-pointer'
169
+ onClick={onClick}
170
+ ref={forwardedRef}
171
+ />
172
+ </CardBlock>
173
+ );
174
+ },
175
+ );
137
176
 
138
177
  CardActionIconButton.displayName = CARD_ACTION_ICON_BUTTON_NAME;
139
178
 
@@ -145,43 +184,67 @@ const CARD_MENU_NAME = 'Card.Menu';
145
184
 
146
185
  type CardMenuProps<T extends any | void = void> = ToolbarMenuProps<T>;
147
186
 
148
- function CardMenu<T extends any | void = void>({ context, items, ...props }: CardMenuProps<T>) {
187
+ function CardMenu<T extends any | void = void>({ context, items }: CardMenuProps<T>) {
188
+ const { t } = useTranslation(translationKey);
149
189
  return (
150
- <CardIconBlock>
151
- <Toolbar.Menu {...props} context={context} items={items ?? []} />
152
- </CardIconBlock>
190
+ <CardBlock end>
191
+ <DropdownMenu.Root>
192
+ <DropdownMenu.Trigger disabled={!items?.length} asChild>
193
+ <IconButton
194
+ iconOnly
195
+ variant='ghost'
196
+ icon='ph--dots-three-vertical--regular'
197
+ label={t('toolbar-menu.label')}
198
+ />
199
+ </DropdownMenu.Trigger>
200
+ {(items?.length ?? 0) > 0 && (
201
+ <DropdownMenu.Portal>
202
+ <DropdownMenu.Content>
203
+ <DropdownMenu.Viewport>
204
+ {items?.map(({ label, onClick: onSelect }, index) => (
205
+ // `context` is the generic payload threaded to each handler; the cast is the
206
+ // generic boundary (T may be `void`, so `context` is typed `T | undefined`).
207
+ <DropdownMenu.Item key={index} onSelect={() => onSelect(context as T)}>
208
+ {label}
209
+ </DropdownMenu.Item>
210
+ ))}
211
+ </DropdownMenu.Viewport>
212
+ <DropdownMenu.Arrow />
213
+ </DropdownMenu.Content>
214
+ </DropdownMenu.Portal>
215
+ )}
216
+ </DropdownMenu.Root>
217
+ </CardBlock>
153
218
  );
154
219
  }
155
220
 
156
221
  CardMenu.displayName = CARD_MENU_NAME;
157
222
 
158
223
  //
159
- // Icon
224
+ // Block
160
225
  //
161
226
 
162
- const CARD_ICON_NAME = 'Card.Icon';
227
+ const CARD_BLOCK_NAME = 'Card.Block';
163
228
 
164
- function CardIcon(props: IconProps) {
165
- return (
166
- <CardIconBlock>
167
- <Icon {...props} />
168
- </CardIconBlock>
169
- );
170
- }
229
+ type CardBlockProps = SlottableProps<{ end?: boolean; compact?: boolean; square?: boolean }>;
171
230
 
172
- CardIcon.displayName = CARD_ICON_NAME;
173
-
174
- //
175
- // IconBlock
176
- //
177
-
178
- const CARD_ICON_BLOCK_NAME = 'Card.IconBlock';
231
+ /**
232
+ * Leading (default) or trailing (`end`) gutter slot of a Card row/header. Sized to the
233
+ * rail-item square so a passive `<Icon>` aligns with an `IconButton`. Defaults text color to
234
+ * `subdued` so a decorative `<Icon>` child needs no styling; interactive children set their own.
235
+ */
236
+ const CardBlock = composable<HTMLDivElement, CardBlockProps>(({ children, ...props }, forwardedRef) => {
237
+ const { tx } = useThemeContext();
238
+ const { className, ...rest } = composableProps(props);
179
239
 
180
- const CardIconBlock = forwardRef<HTMLDivElement, IconBlockProps>((props, forwardedRef) => {
181
- return <IconBlock {...props} ref={forwardedRef} />;
240
+ return (
241
+ <Column.Block {...rest} classNames={tx('card.block', {}, className)} ref={forwardedRef}>
242
+ {children}
243
+ </Column.Block>
244
+ );
182
245
  });
183
246
 
184
- CardIconBlock.displayName = CARD_ICON_BLOCK_NAME;
247
+ CardBlock.displayName = CARD_BLOCK_NAME;
185
248
 
186
249
  //
187
250
  // Title
@@ -271,32 +334,28 @@ CardSection.displayName = CARD_SECTION_NAME;
271
334
 
272
335
  const CARD_ROW_NAME = 'Card.Row';
273
336
 
274
- type CardRowProps = { icon?: string | JSX.Element; fullWidth?: boolean };
337
+ type CardRowProps = { fullWidth?: boolean };
275
338
 
276
339
  /**
277
340
  * A row inside a Card.
278
- * - Default: spans all 3 columns and establishes a subgrid so children align to the Card's columns.
279
- * An optional `icon` lands in the first column; when omitted, the first column is left empty.
280
- * - `fullWidth`: spans all columns without a subgrid — children do their own internal layout.
281
- * The `icon` prop is ignored in this mode.
341
+ * - Default: spans all 3 columns as a subgrid; children align via `data-slot` — `Card.Block`
342
+ * lands in the gutters (start/end), anonymous children in the center. Sets `--icon-size` 4.
343
+ * - `fullWidth`: spans all columns without a subgrid — children do their own internal layout;
344
+ * `Card.Block` placement is inert in this mode.
282
345
  */
283
346
  const CardRow = slottable<HTMLDivElement, CardRowProps>(
284
- ({ children, asChild, icon: iconProp, fullWidth, ...props }, forwardedRef) => {
347
+ ({ children, asChild, fullWidth, style, ...props }, forwardedRef) => {
285
348
  const { tx } = useThemeContext();
286
349
  const { className, ...rest } = composableProps(props);
287
350
  const Comp = asChild ? Slot : Primitive.div;
288
- const icon =
289
- typeof iconProp === 'string' ? (
290
- <CardIcon classNames='text-subdued' icon={iconProp as string} size={4} />
291
- ) : iconProp ? (
292
- iconProp
293
- ) : (
294
- <div />
295
- );
296
351
 
297
352
  return (
298
- <Comp {...rest} className={tx('card.row', { fullWidth }, className)} ref={forwardedRef}>
299
- {!fullWidth && icon}
353
+ <Comp
354
+ {...rest}
355
+ style={{ ...iconSize(4), ...style }}
356
+ className={tx('card.row', { fullWidth }, className)}
357
+ ref={forwardedRef}
358
+ >
300
359
  {children}
301
360
  </Comp>
302
361
  );
@@ -379,15 +438,21 @@ type CardPosterProps = ThemedClassName<
379
438
  Omit<ImageProps, 'src' | 'alt' | 'classNames'>
380
439
  >;
381
440
 
382
- function CardPoster({ classNames, alt, aspect: aspectProp, image, icon, ...imageProps }: CardPosterProps) {
441
+ function CardPoster({
442
+ classNames,
443
+ alt,
444
+ aspect: aspectProp,
445
+ image,
446
+ icon,
447
+ fit = 'cover',
448
+ ...imageProps
449
+ }: CardPosterProps) {
383
450
  const { tx } = useThemeContext();
384
451
  const aspect = aspectProp === 'auto' ? 'aspect-auto' : 'aspect-video';
385
452
 
386
453
  if (image) {
387
454
  return (
388
- <div className='col-span-full'>
389
- <Image classNames={[tx('card.poster', {}), aspect, classNames]} src={image} alt={alt} {...imageProps} />
390
- </div>
455
+ <Image classNames={[tx('card.poster', {}), aspect, classNames]} src={image} alt={alt} fit={fit} {...imageProps} />
391
456
  );
392
457
  }
393
458
 
@@ -414,9 +479,17 @@ function CardAction({ icon, actionIcon = 'ph--arrow-right--regular', label, onCl
414
479
  const { tx } = useThemeContext();
415
480
  return (
416
481
  <Button variant='ghost' classNames={tx('card.action', {})} onClick={onClick}>
417
- {icon ? <CardIcon classNames='text-subdued' icon={icon} size={4} /> : <div />}
418
- <span className={tx('card.action-label', {}, !actionIcon ? 'col-span-2' : undefined)}>{label}</span>
419
- {actionIcon && <CardIcon icon={actionIcon} size={4} />}
482
+ {icon && (
483
+ <CardBlock>
484
+ <Icon icon={icon} size={4} />
485
+ </CardBlock>
486
+ )}
487
+ <span className={tx('card.action-label', {})}>{label}</span>
488
+ {actionIcon && (
489
+ <CardBlock end>
490
+ <Icon icon={actionIcon} size={4} />
491
+ </CardBlock>
492
+ )}
420
493
  </Button>
421
494
  );
422
495
  }
@@ -435,9 +508,13 @@ function CardLink({ label, href }: CardLinkProps) {
435
508
  const { tx } = useThemeContext();
436
509
  return (
437
510
  <a className={tx('card.link', {})} data-variant='ghost' href={href} target='_blank' rel='noreferrer'>
438
- <CardIcon classNames='text-subdued' icon='ph--link--regular' />
511
+ <CardBlock>
512
+ <Icon icon='ph--link--regular' size={4} />
513
+ </CardBlock>
439
514
  <span className={tx('card.link-label', {})}>{label}</span>
440
- <CardIcon classNames='invisible group-hover:visible' icon='ph--arrow-square-out--regular' />
515
+ <CardBlock end classNames='invisible group-hover:visible'>
516
+ <Icon icon='ph--arrow-square-out--regular' size={4} />
517
+ </CardBlock>
441
518
  </a>
442
519
  );
443
520
  }
@@ -454,12 +531,11 @@ export const Card = {
454
531
  // Header
455
532
  Header: CardHeader,
456
533
 
457
- // Header parts
458
- IconBlock: CardIconBlock,
534
+ // Header / row parts
535
+ Block: CardBlock,
459
536
  DragHandle: CardDragHandle,
460
537
  ActionIconButton: CardActionIconButton,
461
538
  Menu: CardMenu,
462
- Icon: CardIcon,
463
539
  Title: CardTitle,
464
540
 
465
541
  // Body
@@ -476,10 +552,11 @@ export const Card = {
476
552
  };
477
553
 
478
554
  export type {
479
- CardRootProps,
480
- CardHeaderProps,
481
- CardDragHandleProps,
482
555
  CardActionIconButtonProps,
556
+ CardBlockProps,
557
+ CardDragHandleProps,
558
+ CardHeaderProps,
483
559
  CardMenuProps,
560
+ CardRootProps,
484
561
  CardSectionProps,
485
562
  };
@@ -5,37 +5,49 @@
5
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React from 'react';
7
7
 
8
- import { withTheme } from '../../testing';
9
- import { Carousel } from './Carousel';
8
+ import { withLayout, withTheme } from '../../testing';
9
+ import { translations } from '../../translations';
10
+ import { Carousel, type CarouselTransition } from './Carousel';
10
11
 
11
12
  // Stable placeholder images so the story renders without network fixtures.
12
13
  const IMAGES = Array.from({ length: 5 }).map((_, index) => `https://placehold.co/640x360?text=Slide+${index + 1}`);
13
14
 
14
- type DefaultStoryProps = { count?: number };
15
+ type StoryArgs = {
16
+ count?: number;
17
+ transition?: CarouselTransition;
18
+ continuous?: boolean;
19
+ autoAdvance?: number;
20
+ };
15
21
 
16
- const DefaultStory = ({ count = IMAGES.length }: DefaultStoryProps) => {
22
+ const DefaultStory = ({ count = IMAGES.length, transition, continuous, autoAdvance }: StoryArgs) => {
17
23
  const images = IMAGES.slice(0, count);
18
24
  return (
19
- <Carousel.Root count={images.length}>
20
- <Carousel.Content classNames='max-w-[40rem]'>
21
- <Carousel.Previous />
22
- <Carousel.Viewport>
23
- {images.map((src, index) => (
24
- <Carousel.Slide key={src} index={index} src={src} alt={`Slide ${index + 1}`} />
25
- ))}
26
- </Carousel.Viewport>
27
- <Carousel.Next />
28
- <Carousel.Indicators />
29
- <Carousel.Caption>{(index) => `Slide ${index + 1} of ${images.length}`}</Carousel.Caption>
30
- </Carousel.Content>
31
- </Carousel.Root>
25
+ <div className='h-full flex items-center'>
26
+ <Carousel.Root count={images.length} transition={transition} continuous={continuous} autoAdvance={autoAdvance}>
27
+ <Carousel.Content>
28
+ <Carousel.Previous />
29
+ <Carousel.Viewport>
30
+ {images.map((src, index) => (
31
+ <Carousel.Slide key={src} index={index} src={src} alt={`Slide ${index + 1}`} />
32
+ ))}
33
+ </Carousel.Viewport>
34
+ <Carousel.Next />
35
+ <Carousel.Indicators />
36
+ <Carousel.Caption>{(index) => `Slide ${index + 1} of ${images.length}`}</Carousel.Caption>
37
+ </Carousel.Content>
38
+ </Carousel.Root>
39
+ </div>
32
40
  );
33
41
  };
34
42
 
35
43
  const meta = {
36
44
  title: 'ui/react-ui-core/components/Carousel',
37
45
  render: DefaultStory,
38
- decorators: [withTheme()],
46
+ decorators: [withTheme(), withLayout({ layout: 'column' })],
47
+ parameters: {
48
+ layout: 'fullscreen',
49
+ translations,
50
+ },
39
51
  } satisfies Meta<typeof DefaultStory>;
40
52
 
41
53
  export default meta;
@@ -45,3 +57,15 @@ type Story = StoryObj<typeof meta>;
45
57
  export const Default: Story = {
46
58
  args: { count: 5 },
47
59
  };
60
+
61
+ export const Sliding: Story = {
62
+ args: { count: 5, transition: 'slide' },
63
+ };
64
+
65
+ export const Continuous: Story = {
66
+ args: { count: 5, transition: 'slide', continuous: true },
67
+ };
68
+
69
+ export const AutoAdvancing: Story = {
70
+ args: { count: 5, transition: 'slide', continuous: true, autoAdvance: 5_000 },
71
+ };