@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,11 +5,16 @@
5
5
  import { useArrowNavigationGroup } from '@fluentui/react-tabster';
6
6
  import { createContext } from '@radix-ui/react-context';
7
7
  import React, {
8
+ Children,
8
9
  type KeyboardEvent,
9
10
  type PropsWithChildren,
10
11
  type ReactNode,
12
+ type TransitionEvent,
13
+ cloneElement,
14
+ isValidElement,
11
15
  useCallback,
12
16
  useEffect,
17
+ useRef,
13
18
  useState,
14
19
  } from 'react';
15
20
 
@@ -19,18 +24,33 @@ import { useTranslation } from '../../primitives';
19
24
  import { translationKey } from '../../translations';
20
25
  import { type ThemedClassName, composable, composableProps } from '../../util';
21
26
  import { IconButton } from '../Button';
22
- import { MediaPlayer, type MediaKind } from '../MediaPlayer';
27
+ import { type MediaKind, MediaPlayer } from '../MediaPlayer';
23
28
 
24
- // TODO(burdon): Move per-element class strings to `@dxos/ui-theme` (theme tokens)
25
- // so callers can re-theme via the same mechanism the rest of `react-ui` uses.
29
+ // TODO(burdon): Controller.
26
30
 
27
31
  //
28
32
  // Context
29
33
  //
30
34
 
35
+ /** Slide change behaviour: `none` hard-swaps the active slide, `slide` animates a horizontal track. */
36
+ export type CarouselTransition = 'none' | 'slide';
37
+
31
38
  type CarouselContextValue = {
32
39
  index: number;
33
40
  count: number;
41
+ transition: CarouselTransition;
42
+ /** When `transition === 'slide'`, wrap-around advances continue in the same direction (clone + snap). */
43
+ continuous: boolean;
44
+ /**
45
+ * Track position in slide units. Equals `index` except mid-wrap, when it points at a clone cell
46
+ * (`count` = trailing clone of the first slide, `-1` = leading clone of the last) so the track keeps
47
+ * moving in the travel direction. Settled back to the real index once the transition ends.
48
+ */
49
+ offset: number;
50
+ /** Whether the track transform should animate; disabled for the instantaneous post-wrap snap. */
51
+ animate: boolean;
52
+ /** Snap a clone cell back to its real slide once the wrap transition completes. */
53
+ settle: () => void;
34
54
  setIndex: (index: number) => void;
35
55
  next: () => void;
36
56
  prev: () => void;
@@ -50,58 +70,120 @@ export const useCarousel = (): CarouselContextValue => useCarouselContext('useCa
50
70
  export type CarouselRootProps = PropsWithChildren<{
51
71
  /** Total number of slides; drives auto-advance and indicator counts. */
52
72
  count: number;
53
- /** Whether to auto-advance slides on mount. Defaults to `false`. */
54
- autorun?: boolean;
55
- /** Auto-advance interval in milliseconds. Set 0 to disable. */
56
- intervalMs?: number;
73
+ /**
74
+ * Auto-advance interval in milliseconds. A positive value advances slides on its own until the user
75
+ * interacts with a control; omit (or `0`) to disable.
76
+ */
77
+ autoAdvance?: number;
57
78
  defaultIndex?: number;
79
+ /** Slide change behaviour. Defaults to `none` (hard swap); `slide` animates a horizontal track. */
80
+ transition?: CarouselTransition;
81
+ /**
82
+ * Wrap-around in the same travel direction (last → first slides forward, first → last slides back).
83
+ * Only applies when `transition === 'slide'`; otherwise wrap is an instant index change.
84
+ */
85
+ continuous?: boolean;
58
86
  }>;
59
87
 
60
88
  const CarouselRoot = ({
61
89
  children,
62
90
  count,
63
- autorun = false,
64
- intervalMs = 5_000,
91
+ autoAdvance = 0,
65
92
  defaultIndex = 0,
93
+ transition = 'none',
94
+ continuous = false,
66
95
  }: CarouselRootProps) => {
67
96
  const [index, setIndexState] = useState(defaultIndex);
68
- const [autoAdvance, setAutoAdvance] = useState(autorun);
97
+ const [offset, setOffset] = useState(defaultIndex);
98
+ const [animate, setAnimate] = useState(true);
99
+ const [autoEnabled, setAutoEnabled] = useState(autoAdvance > 0);
100
+
101
+ // Continuous wrap is only meaningful for the animated track with more than one slide.
102
+ const wraps = continuous && transition === 'slide' && count > 1;
103
+
104
+ // Latest index without re-creating the advance/auto-advance callbacks on every change.
105
+ const indexRef = useRef(index);
106
+ useEffect(() => {
107
+ indexRef.current = index;
108
+ }, [index]);
69
109
 
70
110
  // Reset to first slide if the slide count shrinks below the current index.
71
111
  useEffect(() => {
72
112
  if (index >= count) {
73
113
  setIndexState(0);
114
+ setOffset(0);
74
115
  }
75
116
  }, [count, index]);
76
117
 
118
+ // Step one slide in `delta` direction. `stopAuto` halts auto-advance on user interaction. In wrap
119
+ // mode an edge step targets a clone cell (offset `count` / `-1`) so the track travels in `delta`'s
120
+ // direction; `settle` snaps it back to the real index after the transition.
121
+ const advance = useCallback(
122
+ (delta: 1 | -1, stopAuto: boolean) => {
123
+ if (stopAuto) {
124
+ setAutoEnabled(false);
125
+ }
126
+ const current = indexRef.current;
127
+ const nextIndex = (current + delta + count) % count;
128
+ setAnimate(true);
129
+ if (wraps && delta === 1 && current === count - 1) {
130
+ setOffset(count);
131
+ } else if (wraps && delta === -1 && current === 0) {
132
+ setOffset(-1);
133
+ } else {
134
+ setOffset(nextIndex);
135
+ }
136
+ setIndexState(nextIndex);
137
+ },
138
+ [count, wraps],
139
+ );
140
+
77
141
  // Auto-advance — stops permanently once the user interacts with any control.
78
142
  useEffect(() => {
79
- if (!autoAdvance || count <= 1 || intervalMs <= 0) {
143
+ if (!autoEnabled || count <= 1 || autoAdvance <= 0) {
80
144
  return;
81
145
  }
82
- const handle = setInterval(() => setIndexState((i) => (i + 1) % count), intervalMs);
146
+ const handle = setInterval(() => advance(1, false), autoAdvance);
83
147
  return () => clearInterval(handle);
84
- }, [autoAdvance, count, intervalMs]);
148
+ }, [autoEnabled, count, autoAdvance, advance]);
85
149
 
86
150
  const setIndex = useCallback((next: number) => {
87
- setAutoAdvance(false);
151
+ setAutoEnabled(false);
152
+ setAnimate(true);
153
+ setOffset(next);
88
154
  setIndexState(next);
89
155
  }, []);
90
- const next = useCallback(() => {
91
- setAutoAdvance(false);
92
- setIndexState((i) => (i + 1) % count);
93
- }, [count]);
94
- const prev = useCallback(() => {
95
- setAutoAdvance(false);
96
- setIndexState((i) => (i - 1 + count) % count);
97
- }, [count]);
156
+ const next = useCallback(() => advance(1, true), [advance]);
157
+ const prev = useCallback(() => advance(-1, true), [advance]);
158
+
159
+ // Once the wrap transition lands on a clone, jump (without animating) to the matching real slide.
160
+ const settle = useCallback(() => {
161
+ if (offset === count) {
162
+ setAnimate(false);
163
+ setOffset(0);
164
+ } else if (offset === -1) {
165
+ setAnimate(false);
166
+ setOffset(count - 1);
167
+ }
168
+ }, [offset, count]);
98
169
 
99
170
  if (count === 0) {
100
171
  return null;
101
172
  }
102
173
 
103
174
  return (
104
- <CarouselProvider index={index} count={count} setIndex={setIndex} next={next} prev={prev}>
175
+ <CarouselProvider
176
+ index={index}
177
+ count={count}
178
+ transition={transition}
179
+ continuous={wraps}
180
+ offset={offset}
181
+ animate={animate}
182
+ settle={settle}
183
+ setIndex={setIndex}
184
+ next={next}
185
+ prev={prev}
186
+ >
105
187
  {children}
106
188
  </CarouselProvider>
107
189
  );
@@ -115,7 +197,6 @@ CarouselRoot.displayName = 'Carousel.Root';
115
197
 
116
198
  export type CarouselContentProps = ThemedClassName<PropsWithChildren<{}>>;
117
199
 
118
- // `composable` so a parent `<… asChild>` (Slot) is respected — the injected className/ref land on the grid.
119
200
  const CarouselContent = composable<HTMLDivElement>(({ children, ...props }, forwardedRef) => (
120
201
  // Rows are `[1fr, auto]`: row 1 (Previous|Viewport|Next) stretches when the parent
121
202
  // gives the carousel a definite height, and row 2 (Indicators / Caption) sticks to
@@ -143,7 +224,8 @@ export type CarouselViewportProps = ThemedClassName<PropsWithChildren<{}>>;
143
224
 
144
225
  const CarouselViewport = ({ children, classNames }: CarouselViewportProps) => {
145
226
  const { t } = useTranslation(translationKey);
146
- const { count, next, prev } = useCarousel();
227
+ const { count, transition, continuous, offset, animate, settle, next, prev } = useCarousel();
228
+
147
229
  const handleKeyDown = useCallback(
148
230
  (event: KeyboardEvent<HTMLDivElement>) => {
149
231
  if (count <= 1) {
@@ -160,6 +242,31 @@ const CarouselViewport = ({ children, classNames }: CarouselViewportProps) => {
160
242
  [count, next, prev],
161
243
  );
162
244
 
245
+ // In continuous mode bracket the track with clones — last before first, first after last — so a wrap
246
+ // step has a real cell to slide into before `settle` snaps back to the matching slide.
247
+ const slides = Children.toArray(children);
248
+ const first = slides[0];
249
+ const last = slides[slides.length - 1];
250
+ const trackChildren =
251
+ continuous && slides.length > 1
252
+ ? [
253
+ isValidElement(last) ? cloneElement(last, { key: 'clone-last' }) : last,
254
+ ...slides,
255
+ isValidElement(first) ? cloneElement(first, { key: 'clone-first' }) : first,
256
+ ]
257
+ : slides;
258
+ // Leading clone occupies the first cell in continuous mode, so shift the translate by one.
259
+ const translate = continuous ? -(offset + 1) * 100 : -offset * 100;
260
+
261
+ const handleTransitionEnd = useCallback(
262
+ (event: TransitionEvent<HTMLDivElement>) => {
263
+ if (event.target === event.currentTarget && event.propertyName === 'transform') {
264
+ settle();
265
+ }
266
+ },
267
+ [settle],
268
+ );
269
+
163
270
  return (
164
271
  <div
165
272
  // TODO(burdon): Move to ui-theme.
@@ -174,7 +281,24 @@ const CarouselViewport = ({ children, classNames }: CarouselViewportProps) => {
174
281
  aria-label={t('carousel-viewport.label')}
175
282
  onKeyDown={handleKeyDown}
176
283
  >
177
- {children}
284
+ {transition === 'slide' ? (
285
+ // Lay slides side-by-side in a flex track and translate by the active index. Each slide
286
+ // sizes itself to the viewport via `shrink-0 basis-full` (see `Carousel.Slide`).
287
+ // `motion-reduce` respects the user's reduced-motion preference; the snap after a wrap also
288
+ // disables the transition (`animate === false`).
289
+ <div
290
+ className={mx(
291
+ 'flex h-full motion-reduce:transition-none',
292
+ animate ? 'transition-transform duration-300 ease-out' : 'transition-none',
293
+ )}
294
+ style={{ transform: `translateX(${translate}%)` }}
295
+ onTransitionEnd={handleTransitionEnd}
296
+ >
297
+ {trackChildren}
298
+ </div>
299
+ ) : (
300
+ children
301
+ )}
178
302
  </div>
179
303
  );
180
304
  };
@@ -212,20 +336,30 @@ const CarouselSlide = ({
212
336
  muted,
213
337
  crossOrigin,
214
338
  }: CarouselSlideProps) => {
215
- const { index: active } = useCarousel();
216
- if (active !== index) {
339
+ const { index: active, transition } = useCarousel();
340
+ // In `slide` mode every slide stays mounted as a fixed-width track cell so the track can animate;
341
+ // in `none` mode only the active slide mounts, overlaid via absolute positioning.
342
+ if (transition !== 'slide' && active !== index) {
217
343
  return null;
218
344
  }
219
345
 
220
346
  return (
221
- <div className={mx('absolute inset-0 w-full h-full bg-baseSurface', classNames)}>
347
+ <div
348
+ className={mx(
349
+ transition === 'slide'
350
+ ? 'relative shrink-0 basis-full h-full bg-baseSurface'
351
+ : 'absolute inset-0 w-full h-full bg-baseSurface',
352
+ classNames,
353
+ )}
354
+ >
222
355
  <MediaPlayer
223
356
  src={src}
224
357
  kind={kind}
225
358
  alt={alt}
226
359
  classNames='w-full h-full'
227
360
  controls={controls}
228
- autoPlay={autoPlay}
361
+ // In `slide` mode every slide is mounted; only auto-play the active one to avoid off-screen playback.
362
+ autoPlay={autoPlay && active === index}
229
363
  loop={loop}
230
364
  muted={muted}
231
365
  crossOrigin={crossOrigin}
@@ -314,14 +448,16 @@ const CarouselIndicators = ({ classNames }: CarouselIndicatorsProps) => {
314
448
  key={i}
315
449
  role='tab'
316
450
  aria-selected={i === index}
317
- classNames={i === index ? 'text-primary-500' : 'text-description'}
451
+ classNames={mx(i === index ? 'text-primary-500' : 'text-description')}
452
+ variant='ghost'
453
+ density='sm'
454
+ size={3}
455
+ square
318
456
  icon={i === index ? 'ph--circle--fill' : 'ph--circle--regular'}
319
457
  iconOnly
320
458
  label={t('carousel-go-to.label', { index: i + 1 })}
321
459
  onClick={() => setIndex(i)}
322
460
  onFocus={() => setIndex(i)}
323
- size={3}
324
- variant='ghost'
325
461
  />
326
462
  ))}
327
463
  </div>
@@ -9,20 +9,47 @@ import { withColumn } from './withColumn';
9
9
 
10
10
  export type ColumnStyleProps = {};
11
11
 
12
+ export type ColumnBlockStyleProps = {
13
+ /** Trailing gutter (column 3) instead of the default leading gutter (column 1). */
14
+ end?: boolean;
15
+ compact?: boolean;
16
+ /** Constrain to a square (1:1) slot rather than the default rail-item width. */
17
+ square?: boolean;
18
+ };
19
+
12
20
  const root: ComponentFunction<ColumnStyleProps> = (_, ...etc) => {
13
21
  return mx('dx-column-root grid', ...etc);
14
22
  };
15
23
 
16
24
  /**
17
- * Three-column icon-slot row: spans all 3 columns of the parent Column.Root grid.
18
- * Uses CSS subgrid to inherit column sizing from the parent Column.
19
- * Children map to: [col-1: icon/slot] [col-2: content] [col-3: icon/action].
25
+ * Three-column subgrid row spanning all 3 columns of the parent Column.Root grid.
26
+ * Placement is explicit, not source-order based:
27
+ * - `Column.Block` self-places into column 1 (leading) or column 3 (trailing, `end`) and
28
+ * carries the `dx-gutter` marker class.
29
+ * - Every other (content) child is placed in column 2 via `[&>*:not(.dx-gutter)]`.
30
+ * Class-based placement (rather than `[data-slot=…]`) is used because Tailwind does not
31
+ * generate arbitrary variants that nest a square-bracket attribute selector.
32
+ * Robust to conditional children: a falsy leading slot never shifts content into a gutter.
20
33
  * NOTE: Must not use overflow-hidden here since it will clip input focus rings.
21
34
  */
22
35
  const row: ComponentFunction<ColumnStyleProps> = (_, ...etc) => {
23
- return mx('col-span-3 grid grid-cols-subgrid', ...etc);
36
+ return mx('col-span-3 grid grid-cols-subgrid', '[&>*:not(.dx-gutter)]:col-start-2', ...etc);
24
37
  };
25
38
 
39
+ /**
40
+ * Gutter slot geometry: a `--dx-rail-item` square that centers its child, so a passive
41
+ * `<Icon>` and an interactive `IconButton` line up to the pixel. Self-places into column 1
42
+ * (default) or column 3 (`end`); the `dx-gutter` marker keeps it out of the content track.
43
+ */
44
+ const block: ComponentFunction<ColumnBlockStyleProps> = ({ end, compact, square }, ...etc) =>
45
+ mx(
46
+ 'dx-gutter grid place-items-center [&>img]:max-w-[1.5rem]',
47
+ end ? 'col-start-3' : 'col-start-1',
48
+ square ? 'aspect-square' : 'w-[var(--dx-rail-item)]',
49
+ compact ? '' : 'h-[var(--dx-rail-item)]',
50
+ ...etc,
51
+ );
52
+
26
53
  /**
27
54
  * Bleed placement: spans all 3 columns of the parent Column.Root grid (gutter-to-gutter).
28
55
  * Use for `ScrollArea`, full-width dividers, tables, or any content that should ignore gutters.
@@ -43,6 +70,7 @@ const center: ComponentFunction<ColumnStyleProps> = (_, ...etc) => {
43
70
  export const columnTheme = {
44
71
  root,
45
72
  row,
73
+ block,
46
74
  bleed,
47
75
  center,
48
76
  };
@@ -17,10 +17,9 @@ import { composableProps, slottable } from '../../util';
17
17
 
18
18
  const COLUMN_ROOT_NAME = 'Column.Root';
19
19
 
20
- type GutterSize = 'xs' | 'sm' | 'md' | 'lg';
20
+ type GutterSize = 'sm' | 'md' | 'lg';
21
21
 
22
22
  const gutterSizes: Record<GutterSize, string> = {
23
- xs: 'var(--dx-gutter-xs)',
24
23
  sm: 'var(--dx-gutter-sm)',
25
24
  md: 'var(--dx-gutter-md)',
26
25
  lg: 'var(--dx-gutter-lg)',
@@ -42,11 +41,9 @@ type ColumnRootProps = { gutter?: GutterSize };
42
41
  * - **Column.Row** — 3-col subgrid row (icons in gutters, content in center).
43
42
  *
44
43
  * Use `withColumn.center()` / `withColumn.bleed()` helpers to apply placement on slotted elements.
45
- *
46
- * Gutter sizes: `'sm'` for compact layouts (Dialog); `'md'` (default); `'lg'` for wider spacing.
47
44
  */
48
45
  const ColumnRoot = slottable<HTMLDivElement, ColumnRootProps>(
49
- ({ children, asChild, role, gutter = 'md', ...props }, forwardedRef) => {
46
+ ({ children, asChild, role, gutter = 'lg', ...props }, forwardedRef) => {
50
47
  const { className, ...rest } = composableProps(props);
51
48
  const Comp = asChild ? Slot : Primitive.div;
52
49
  const { tx } = useThemeContext();
@@ -60,7 +57,7 @@ const ColumnRoot = slottable<HTMLDivElement, ColumnRootProps>(
60
57
  ...rest.style,
61
58
  '--gutter': gutterSize,
62
59
  '--dx-col': '2 / span 1',
63
- gridTemplateColumns: [gutterSize, 'minmax(0,1fr)', gutterSize].join(' '),
60
+ 'gridTemplateColumns': [gutterSize, 'minmax(0,1fr)', gutterSize].join(' '),
64
61
  } as CSSProperties
65
62
  }
66
63
  className={tx('column.root', { gutter }, className)}
@@ -152,6 +149,40 @@ const ColumnCenter = slottable<HTMLDivElement>(({ children, asChild, ...props },
152
149
 
153
150
  ColumnCenter.displayName = COLUMN_CENTER_NAME;
154
151
 
152
+ //
153
+ // Block
154
+ //
155
+
156
+ const COLUMN_BLOCK_NAME = 'Column.Block';
157
+
158
+ type ColumnBlockProps = SlottableProps<{ end?: boolean; compact?: boolean; square?: boolean }>;
159
+
160
+ /**
161
+ * A gutter slot inside a Column.Row. Sized to `--dx-rail-item` and centers its child so a passive
162
+ * `<Icon>` and an interactive `IconButton` align to the pixel. `end` opts into the trailing gutter
163
+ * (column 3); default is the leading gutter (column 1). Placement is via `data-slot`, so it is
164
+ * robust to conditional rendering and source order.
165
+ */
166
+ const ColumnBlock = slottable<HTMLDivElement, ColumnBlockProps>(
167
+ ({ children, asChild, end, compact, square, ...props }, forwardedRef) => {
168
+ const { tx } = useThemeContext();
169
+ const { className, ...rest } = composableProps(props);
170
+ const Comp = asChild ? Slot : Primitive.div;
171
+ return (
172
+ <Comp
173
+ {...rest}
174
+ data-slot={end ? 'end' : 'start'}
175
+ className={tx('column.block', { end, compact, square }, className)}
176
+ ref={forwardedRef}
177
+ >
178
+ {children}
179
+ </Comp>
180
+ );
181
+ },
182
+ );
183
+
184
+ ColumnBlock.displayName = COLUMN_BLOCK_NAME;
185
+
155
186
  //
156
187
  // Column
157
188
  //
@@ -159,8 +190,9 @@ ColumnCenter.displayName = COLUMN_CENTER_NAME;
159
190
  export const Column = {
160
191
  Root: ColumnRoot,
161
192
  Row: ColumnRow,
193
+ Block: ColumnBlock,
162
194
  Bleed: ColumnBleed,
163
195
  Center: ColumnCenter,
164
196
  };
165
197
 
166
- export type { ColumnRootProps, ColumnRowProps, ColumnBleedProps, ColumnCenterProps };
198
+ export type { ColumnBleedProps, ColumnBlockProps, ColumnCenterProps, ColumnRootProps, ColumnRowProps };
@@ -11,7 +11,7 @@ import { withTheme } from '../../testing';
11
11
  import { Button } from '../Button';
12
12
  import { AlertDialog } from './AlertDialog';
13
13
 
14
- type DefaultStoryProps = Partial<{
14
+ type StoryArgs = Partial<{
15
15
  title: string;
16
16
  description: string;
17
17
  openTrigger: string;
@@ -19,7 +19,7 @@ type DefaultStoryProps = Partial<{
19
19
  actionTrigger: string;
20
20
  }>;
21
21
 
22
- const DefaultStory = ({ title, description, openTrigger, cancelTrigger, actionTrigger }: DefaultStoryProps) => {
22
+ const DefaultStory = ({ title, description, openTrigger, cancelTrigger, actionTrigger }: StoryArgs) => {
23
23
  return (
24
24
  <AlertDialog.Root defaultOpen>
25
25
  <AlertDialog.Trigger asChild>
@@ -13,10 +13,10 @@ import { type ThemedClassName } from '../../util';
13
13
  import { Column } from '../Column';
14
14
  import {
15
15
  Dialog,
16
- type DialogHeaderProps,
17
- type DialogBodyProps,
18
16
  type DialogActionBarProps,
19
17
  type DialogActionIconButtonProps,
18
+ type DialogBodyProps,
19
+ type DialogHeaderProps,
20
20
  } from './Dialog';
21
21
 
22
22
  //
@@ -122,7 +122,7 @@ const AlertDialogContent: ForwardRefExoticComponent<AlertDialogContentProps> = f
122
122
  className={tx('dialog.content', { inOverlayLayout, size }, classNames)}
123
123
  ref={forwardedRef}
124
124
  >
125
- <Column.Root classNames='dx-expander' gutter='sm'>
125
+ <Column.Root classNames='dx-expander' gutter='lg'>
126
126
  {children}
127
127
  </Column.Root>
128
128
  </AlertDialogPrimitive.Content>
@@ -192,18 +192,18 @@ export const AlertDialog = {
192
192
  };
193
193
 
194
194
  export type {
195
- AlertDialogRootProps,
196
- AlertDialogTriggerProps,
197
- AlertDialogPortalProps,
198
- AlertDialogOverlayProps,
195
+ DialogActionBarProps as AlertDialogActionBarProps,
196
+ DialogActionIconButtonProps as AlertDialogActionIconButtonProps,
197
+ AlertDialogActionProps,
198
+ DialogBodyProps as AlertDialogBodyProps,
199
+ AlertDialogCancelProps,
199
200
  AlertDialogContentProps,
200
- AlertDialogTitleProps,
201
201
  AlertDialogDescriptionProps,
202
- AlertDialogCancelProps,
203
- AlertDialogActionProps,
204
202
  // Re-export shared types.
205
203
  DialogHeaderProps as AlertDialogHeaderProps,
206
- DialogBodyProps as AlertDialogBodyProps,
207
- DialogActionBarProps as AlertDialogActionBarProps,
208
- DialogActionIconButtonProps as AlertDialogActionIconButtonProps,
204
+ AlertDialogOverlayProps,
205
+ AlertDialogPortalProps,
206
+ AlertDialogRootProps,
207
+ AlertDialogTitleProps,
208
+ AlertDialogTriggerProps,
209
209
  };
@@ -13,7 +13,7 @@ import { Input } from '../Input';
13
13
  import { ScrollArea } from '../ScrollArea';
14
14
  import { Dialog, type DialogContentProps } from './Dialog';
15
15
 
16
- type DefaultStoryProps = Pick<DialogContentProps, 'size'> &
16
+ type StoryArgs = Pick<DialogContentProps, 'size'> &
17
17
  Partial<{
18
18
  title: string;
19
19
  description: string;
@@ -26,7 +26,7 @@ type DefaultStoryProps = Pick<DialogContentProps, 'size'> &
26
26
  * Standard Dialog with non-scrolling content in Dialog.Body.
27
27
  * Dialog.Body propagates the Column grid via subgrid. Children auto-center via --dx-col.
28
28
  */
29
- const DefaultStory = ({ size, title, description, openTrigger, closeTrigger, blockAlign }: DefaultStoryProps) => {
29
+ const DefaultStory = ({ size, title, description, openTrigger, closeTrigger, blockAlign }: StoryArgs) => {
30
30
  return (
31
31
  <Dialog.Root defaultOpen modal>
32
32
  <Dialog.Trigger asChild>
@@ -45,7 +45,6 @@ const DefaultStory = ({ size, title, description, openTrigger, closeTrigger, blo
45
45
  <Dialog.Body>
46
46
  <Dialog.Description>{description}</Dialog.Description>
47
47
  <Input.Root>
48
- <Input.Label>Value</Input.Label>
49
48
  <Input.TextInput placeholder='Enter value' />
50
49
  </Input.Root>
51
50
  </Dialog.Body>
@@ -65,7 +64,7 @@ const DefaultStory = ({ size, title, description, openTrigger, closeTrigger, blo
65
64
  * The ScrollArea breaks out of Body's gutter padding via `--gutter`
66
65
  * and applies its own asymmetric padding (accounting for scrollbar width).
67
66
  */
68
- const ScrollingStory = ({ size, title, description, openTrigger, closeTrigger, blockAlign }: DefaultStoryProps) => {
67
+ const ScrollingStory = ({ size, title, description, openTrigger, closeTrigger, blockAlign }: StoryArgs) => {
69
68
  return (
70
69
  <Dialog.Root defaultOpen modal>
71
70
  <Dialog.Trigger asChild>
@@ -39,7 +39,7 @@ const header: ComponentFunction<DialogStyleProps> = (_props, ...etc) =>
39
39
  mx('dx-dialog__header flex pb-4 items-center justify-between', withColumn.center(), ...etc);
40
40
 
41
41
  const body: ComponentFunction<DialogStyleProps> = (_props, ...etc) =>
42
- mx('dx-dialog__body dx-expander', withColumn.propagate(), ...etc);
42
+ mx('dx-dialog__body dx-expander gap-y-2', withColumn.propagate(), ...etc);
43
43
 
44
44
  const actionBar: ComponentFunction<DialogStyleProps> = (_props, ...etc) =>
45
45
  mx('dx-dialog__actionbar flex items-center pt-4 gap-2', withColumn.center(), ...etc);
@@ -107,7 +107,7 @@ type DialogContentProps = ThemedClassName<ComponentPropsWithRef<typeof DialogPri
107
107
  };
108
108
 
109
109
  const DialogContent: ForwardRefExoticComponent<DialogContentProps> = forwardRef<HTMLDivElement, DialogContentProps>(
110
- ({ classNames, children, size = 'md', inOverlayLayout: propsInOverlayLayout, ...props }, forwardedRef) => {
110
+ ({ classNames, children, size = 'sm', inOverlayLayout: propsInOverlayLayout, ...props }, forwardedRef) => {
111
111
  const { tx } = useThemeContext();
112
112
  const { inOverlayLayout } = useOverlayLayoutContext(DIALOG_CONTENT_NAME);
113
113
 
@@ -127,7 +127,7 @@ const DialogContent: ForwardRefExoticComponent<DialogContentProps> = forwardRef<
127
127
  )}
128
128
  ref={forwardedRef}
129
129
  >
130
- <Column.Root classNames='dx-expander' gutter='sm'>
130
+ <Column.Root classNames='dx-expander' gutter='lg'>
131
131
  {children}
132
132
  </Column.Root>
133
133
  </DialogPrimitive.Content>
@@ -298,17 +298,17 @@ export const Dialog = {
298
298
  };
299
299
 
300
300
  export type {
301
- DialogRootProps,
302
- DialogTriggerProps,
303
- DialogPortalProps,
304
- DialogOverlayProps,
305
- DialogContentProps,
306
- DialogHeaderProps,
307
- DialogBodyProps,
308
- DialogTitleProps,
309
- DialogDescriptionProps,
310
301
  DialogActionBarProps,
311
- DialogCloseProps,
312
302
  DialogActionIconButtonAction,
313
303
  DialogActionIconButtonProps,
304
+ DialogBodyProps,
305
+ DialogCloseProps,
306
+ DialogContentProps,
307
+ DialogDescriptionProps,
308
+ DialogHeaderProps,
309
+ DialogOverlayProps,
310
+ DialogPortalProps,
311
+ DialogRootProps,
312
+ DialogTitleProps,
313
+ DialogTriggerProps,
314
314
  };
@@ -75,6 +75,29 @@ export const Static: Story = {
75
75
  },
76
76
  };
77
77
 
78
+ export const Custom_DXOS: Story = {
79
+ args: {
80
+ icon: 'dx--dxos--regular',
81
+ classNames: getSize(16),
82
+ },
83
+ };
84
+
85
+ /**
86
+ * Custom DXOS brand icons (the `dx--` set), sourced from `@dxos/brand` SVGs.
87
+ */
88
+ export const Brand: Story = {
89
+ args: {
90
+ icon: 'dx--dxos--regular',
91
+ },
92
+ render: () => (
93
+ <div className='flex gap-8'>
94
+ {(['dxos', 'echo', 'halo', 'mesh', 'dxns', 'kube'] as const).map((name) => (
95
+ <Icon key={name} icon={`dx--${name}--regular`} classNames={getSize(12)} />
96
+ ))}
97
+ </div>
98
+ ),
99
+ };
100
+
78
101
  export const Dynamic: Story = {
79
102
  args: {
80
103
  icon: 'ph--github-logo--regular',
@@ -33,7 +33,7 @@ const root: ComponentFunction<IconStyleProps> = ({ size }, etc) => {
33
33
  */
34
34
  const block: ComponentFunction<IconBlockStyleProps> = ({ compact, square }, ...etc) =>
35
35
  mx(
36
- 'grid place-items-center [&>img]:max-w-[1.5rem]',
36
+ 'grid place-items-center shrink-0 [&>img]:max-w-[1.5rem]',
37
37
  square ? 'aspect-square' : 'w-[var(--dx-rail-item)]',
38
38
  compact ? '' : 'h-[var(--dx-rail-item)]',
39
39
  ...etc,