@dxos/react-ui 0.8.4-main.9be5663bfe → 0.8.4-main.abd8ff62ef

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 (169) hide show
  1. package/dist/lib/browser/{chunk-OCVRIJCH.mjs → chunk-BDBC6H6V.mjs} +1 -1
  2. package/dist/lib/browser/{chunk-OCVRIJCH.mjs.map → chunk-BDBC6H6V.mjs.map} +2 -2
  3. package/dist/lib/browser/index.mjs +156 -156
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +2 -2
  7. package/dist/lib/browser/testing/index.mjs.map +3 -3
  8. package/dist/lib/browser/translations.mjs +18 -0
  9. package/dist/lib/browser/translations.mjs.map +7 -0
  10. package/dist/lib/node-esm/{chunk-QUD5P3RU.mjs → chunk-3JSJK2ZY.mjs} +1 -1
  11. package/dist/lib/node-esm/{chunk-QUD5P3RU.mjs.map → chunk-3JSJK2ZY.mjs.map} +2 -2
  12. package/dist/lib/node-esm/index.mjs +156 -156
  13. package/dist/lib/node-esm/index.mjs.map +4 -4
  14. package/dist/lib/node-esm/meta.json +1 -1
  15. package/dist/lib/node-esm/testing/index.mjs +2 -2
  16. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  17. package/dist/lib/node-esm/translations.mjs +20 -0
  18. package/dist/lib/node-esm/translations.mjs.map +7 -0
  19. package/dist/types/src/components/Avatars/Avatar.d.ts.map +1 -1
  20. package/dist/types/src/components/Avatars/Avatar.stories.d.ts.map +1 -1
  21. package/dist/types/src/components/Avatars/AvatarGroup.stories.d.ts.map +1 -1
  22. package/dist/types/src/components/Breadcrumb/Breadcrumb.d.ts.map +1 -1
  23. package/dist/types/src/components/Breadcrumb/Breadcrumb.stories.d.ts.map +1 -1
  24. package/dist/types/src/components/Button/Button.stories.d.ts +1 -1
  25. package/dist/types/src/components/Button/Button.stories.d.ts.map +1 -1
  26. package/dist/types/src/components/Button/IconButton.d.ts +1 -0
  27. package/dist/types/src/components/Button/IconButton.d.ts.map +1 -1
  28. package/dist/types/src/components/Button/IconButton.stories.d.ts.map +1 -1
  29. package/dist/types/src/components/Button/Toggle.stories.d.ts.map +1 -1
  30. package/dist/types/src/components/Button/ToggleGroup.d.ts +2 -2
  31. package/dist/types/src/components/Button/ToggleGroup.stories.d.ts +2 -2
  32. package/dist/types/src/components/Button/ToggleGroup.stories.d.ts.map +1 -1
  33. package/dist/types/src/components/Card/Card.d.ts +21 -12
  34. package/dist/types/src/components/Card/Card.d.ts.map +1 -1
  35. package/dist/types/src/components/Card/Card.stories.d.ts.map +1 -1
  36. package/dist/types/src/components/Clipboard/ClipboardProvider.d.ts.map +1 -1
  37. package/dist/types/src/components/Clipboard/CopyButton.d.ts.map +1 -1
  38. package/dist/types/src/components/Clipboard/index.d.ts +1 -1
  39. package/dist/types/src/components/Clipboard/index.d.ts.map +1 -1
  40. package/dist/types/src/components/DensityProvider/DensityProvider.d.ts.map +1 -1
  41. package/dist/types/src/components/Dialog/AlertDialog.d.ts +21 -19
  42. package/dist/types/src/components/Dialog/AlertDialog.d.ts.map +1 -1
  43. package/dist/types/src/components/Dialog/AlertDialog.stories.d.ts.map +1 -1
  44. package/dist/types/src/components/Dialog/Dialog.d.ts +22 -20
  45. package/dist/types/src/components/Dialog/Dialog.d.ts.map +1 -1
  46. package/dist/types/src/components/Dialog/Dialog.stories.d.ts.map +1 -1
  47. package/dist/types/src/components/ElevationProvider/ElevationProvider.d.ts.map +1 -1
  48. package/dist/types/src/components/ErrorFallback/ErrorFallback.d.ts.map +1 -1
  49. package/dist/types/src/components/ErrorFallback/ErrorFallback.stories.d.ts.map +1 -1
  50. package/dist/types/src/components/ErrorFallback/ErrorStack.d.ts.map +1 -1
  51. package/dist/types/src/components/ErrorFallback/ThrowError.d.ts.map +1 -1
  52. package/dist/types/src/components/Focus/Focus.d.ts +2 -2
  53. package/dist/types/src/components/Focus/Focus.stories.d.ts.map +1 -1
  54. package/dist/types/src/components/Icon/Icon.stories.d.ts +1 -1
  55. package/dist/types/src/components/Icon/Icon.stories.d.ts.map +1 -1
  56. package/dist/types/src/components/Image/Image.d.ts +2 -1
  57. package/dist/types/src/components/Image/Image.d.ts.map +1 -1
  58. package/dist/types/src/components/Image/Image.stories.d.ts +3 -2
  59. package/dist/types/src/components/Image/Image.stories.d.ts.map +1 -1
  60. package/dist/types/src/components/Input/Input.d.ts +12 -15
  61. package/dist/types/src/components/Input/Input.d.ts.map +1 -1
  62. package/dist/types/src/components/Input/Input.stories.d.ts.map +1 -1
  63. package/dist/types/src/components/Link/Link.stories.d.ts.map +1 -1
  64. package/dist/types/src/components/List/List.d.ts +2 -2
  65. package/dist/types/src/components/List/List.stories.d.ts +1 -1
  66. package/dist/types/src/components/List/List.stories.d.ts.map +1 -1
  67. package/dist/types/src/components/List/ListDropIndicator.d.ts.map +1 -1
  68. package/dist/types/src/components/List/Tree.d.ts +2 -2
  69. package/dist/types/src/components/List/Tree.d.ts.map +1 -1
  70. package/dist/types/src/components/List/Tree.stories.d.ts.map +1 -1
  71. package/dist/types/src/components/List/TreeDropIndicator.d.ts.map +1 -1
  72. package/dist/types/src/components/List/Treegrid.d.ts +1 -1
  73. package/dist/types/src/components/List/Treegrid.d.ts.map +1 -1
  74. package/dist/types/src/components/List/Treegrid.stories.d.ts.map +1 -1
  75. package/dist/types/src/components/Main/Main.d.ts +7 -3
  76. package/dist/types/src/components/Main/Main.d.ts.map +1 -1
  77. package/dist/types/src/components/Main/Main.stories.d.ts.map +1 -1
  78. package/dist/types/src/components/Main/useSwipeToDismiss.d.ts.map +1 -1
  79. package/dist/types/src/components/Menu/ContextMenu.d.ts.map +1 -1
  80. package/dist/types/src/components/Menu/ContextMenu.stories.d.ts.map +1 -1
  81. package/dist/types/src/components/Menu/DropdownMenu.d.ts +11 -3
  82. package/dist/types/src/components/Menu/DropdownMenu.d.ts.map +1 -1
  83. package/dist/types/src/components/Menu/DropdownMenu.stories.d.ts.map +1 -1
  84. package/dist/types/src/components/Message/Message.d.ts +1 -1
  85. package/dist/types/src/components/Message/Message.d.ts.map +1 -1
  86. package/dist/types/src/components/Message/Message.stories.d.ts.map +1 -1
  87. package/dist/types/src/components/Popover/Popover.d.ts +10 -2
  88. package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
  89. package/dist/types/src/components/Popover/Popover.stories.d.ts.map +1 -1
  90. package/dist/types/src/components/ScrollArea/ScrollArea.d.ts +2 -2
  91. package/dist/types/src/components/ScrollArea/ScrollArea.d.ts.map +1 -1
  92. package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts +2 -2
  93. package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts.map +1 -1
  94. package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts +11 -3
  95. package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts.map +1 -1
  96. package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts.map +1 -1
  97. package/dist/types/src/components/Select/Select.d.ts.map +1 -1
  98. package/dist/types/src/components/Select/Select.stories.d.ts.map +1 -1
  99. package/dist/types/src/components/Skeleton/Skeleton.stories.d.ts.map +1 -1
  100. package/dist/types/src/components/Splitter/Splitter.d.ts +3 -3
  101. package/dist/types/src/components/Splitter/Splitter.stories.d.ts.map +1 -1
  102. package/dist/types/src/components/Status/Status.stories.d.ts.map +1 -1
  103. package/dist/types/src/components/Tag/Tag.stories.d.ts.map +1 -1
  104. package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts.map +1 -1
  105. package/dist/types/src/components/ThemeProvider/ThemeProvider.stories.d.ts.map +1 -1
  106. package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts +54 -55
  107. package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts.map +1 -1
  108. package/dist/types/src/components/ThemeProvider/index.d.ts +1 -1
  109. package/dist/types/src/components/ThemeProvider/index.d.ts.map +1 -1
  110. package/dist/types/src/components/Toast/Toast.d.ts +4 -4
  111. package/dist/types/src/components/Toast/Toast.d.ts.map +1 -1
  112. package/dist/types/src/components/Toast/Toast.stories.d.ts.map +1 -1
  113. package/dist/types/src/components/Toolbar/Toolbar.d.ts +5 -5
  114. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  115. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
  116. package/dist/types/src/components/Tooltip/Tooltip.d.ts +2 -2
  117. package/dist/types/src/components/Tooltip/Tooltip.d.ts.map +1 -1
  118. package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts.map +1 -1
  119. package/dist/types/src/exemplars/generics.stories.d.ts +1 -1
  120. package/dist/types/src/exemplars/generics.stories.d.ts.map +1 -1
  121. package/dist/types/src/exemplars/slot.stories.d.ts.map +1 -1
  122. package/dist/types/src/exemplars/tabster.stories.d.ts.map +1 -1
  123. package/dist/types/src/exemplars/virtualizer.stories.d.ts.map +1 -1
  124. package/dist/types/src/hooks/useDensityContext.d.ts.map +1 -1
  125. package/dist/types/src/hooks/useElevationContext.d.ts.map +1 -1
  126. package/dist/types/src/hooks/useIconHref.d.ts.map +1 -1
  127. package/dist/types/src/hooks/useSafeArea.d.ts.map +1 -1
  128. package/dist/types/src/hooks/useSafeCollisionPadding.d.ts.map +1 -1
  129. package/dist/types/src/hooks/useVisualViewport.d.ts.map +1 -1
  130. package/dist/types/src/playground/Controls.stories.d.ts.map +1 -1
  131. package/dist/types/src/playground/Custom.stories.d.ts +1 -1
  132. package/dist/types/src/playground/Custom.stories.d.ts.map +1 -1
  133. package/dist/types/src/playground/Typography.stories.d.ts.map +1 -1
  134. package/dist/types/src/primitives/Column/Column.d.ts +11 -13
  135. package/dist/types/src/primitives/Column/Column.d.ts.map +1 -1
  136. package/dist/types/src/primitives/Column/Column.stories.d.ts +7 -7
  137. package/dist/types/src/primitives/Column/Column.stories.d.ts.map +1 -1
  138. package/dist/types/src/primitives/Container/Container.d.ts +1 -1
  139. package/dist/types/src/primitives/Container/Container.stories.d.ts.map +1 -1
  140. package/dist/types/src/primitives/Flex/Flex.d.ts +1 -1
  141. package/dist/types/src/primitives/Flex/Flex.stories.d.ts.map +1 -1
  142. package/dist/types/src/primitives/Grid/Grid.d.ts +1 -1
  143. package/dist/types/src/primitives/Grid/Grid.stories.d.ts.map +1 -1
  144. package/dist/types/src/primitives/Panel/Panel.d.ts +4 -4
  145. package/dist/types/src/primitives/Panel/Panel.d.ts.map +1 -1
  146. package/dist/types/src/primitives/Panel/Panel.stories.d.ts.map +1 -1
  147. package/dist/types/src/testing/Loading.d.ts.map +1 -1
  148. package/dist/types/src/testing/decorators/withLayout.d.ts.map +1 -1
  149. package/dist/types/src/testing/decorators/withLayoutVariants.d.ts.map +1 -1
  150. package/dist/types/src/testing/decorators/withTheme.d.ts.map +1 -1
  151. package/dist/types/src/translations.d.ts +3 -3
  152. package/dist/types/src/translations.d.ts.map +1 -1
  153. package/dist/types/src/util/usePx.d.ts.map +1 -1
  154. package/dist/types/tsconfig.tsbuildinfo +1 -1
  155. package/package.json +26 -24
  156. package/src/components/Button/IconButton.tsx +3 -2
  157. package/src/components/Card/Card.tsx +20 -5
  158. package/src/components/Dialog/Dialog.stories.tsx +2 -2
  159. package/src/components/Dialog/Dialog.tsx +29 -29
  160. package/src/components/Image/Image.tsx +31 -8
  161. package/src/components/Input/Input.tsx +3 -3
  162. package/src/components/Message/Message.stories.tsx +1 -1
  163. package/src/components/Message/Message.tsx +24 -7
  164. package/src/components/ThemeProvider/index.ts +1 -1
  165. package/src/components/Toolbar/Toolbar.tsx +2 -1
  166. package/src/primitives/Column/AUDIT.md +105 -311
  167. package/src/primitives/Column/Column.stories.tsx +58 -60
  168. package/src/primitives/Column/Column.tsx +54 -58
  169. package/src/testing/decorators/withLayout.tsx +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui",
3
- "version": "0.8.4-main.9be5663bfe",
3
+ "version": "0.8.4-main.abd8ff62ef",
4
4
  "description": "Low-level React components for DXOS, applying a theme to a core group of primitives",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -12,6 +12,9 @@
12
12
  "author": "DXOS.org",
13
13
  "sideEffects": false,
14
14
  "type": "module",
15
+ "imports": {
16
+ "#translations": "./src/translations.ts"
17
+ },
15
18
  "exports": {
16
19
  ".": {
17
20
  "source": "./src/index.ts",
@@ -24,16 +27,15 @@
24
27
  "browser": "./dist/lib/browser/testing/index.mjs",
25
28
  "node": "./dist/lib/node-esm/testing/index.mjs",
26
29
  "types": "./dist/types/src/testing/index.d.ts"
30
+ },
31
+ "./translations": {
32
+ "source": "./src/translations.ts",
33
+ "types": "./dist/types/src/translations.d.ts",
34
+ "browser": "./dist/lib/browser/translations.mjs",
35
+ "node": "./dist/lib/node-esm/translations.mjs"
27
36
  }
28
37
  },
29
38
  "types": "dist/types/src/index.d.ts",
30
- "typesVersions": {
31
- "*": {
32
- "testing": [
33
- "./dist/types/src/testing/index.d.ts"
34
- ]
35
- }
36
- },
37
39
  "files": [
38
40
  "dist",
39
41
  "src"
@@ -81,17 +83,17 @@
81
83
  "react-error-boundary": "^4.0.13",
82
84
  "react-i18next": "^11.18.6",
83
85
  "react-remove-scroll": "^2.6.0",
84
- "@dxos/async": "0.8.4-main.9be5663bfe",
85
- "@dxos/debug": "0.8.4-main.9be5663bfe",
86
- "@dxos/lit-ui": "0.8.4-main.9be5663bfe",
87
- "@dxos/invariant": "0.8.4-main.9be5663bfe",
88
- "@dxos/log": "0.8.4-main.9be5663bfe",
89
- "@dxos/react-error-boundary": "0.8.4-main.9be5663bfe",
90
- "@dxos/react-input": "0.8.4-main.9be5663bfe",
91
- "@dxos/react-hooks": "0.8.4-main.9be5663bfe",
92
- "@dxos/react-list": "0.8.4-main.9be5663bfe",
93
- "@dxos/ui-types": "0.8.4-main.9be5663bfe",
94
- "@dxos/util": "0.8.4-main.9be5663bfe"
86
+ "@dxos/async": "0.8.4-main.abd8ff62ef",
87
+ "@dxos/debug": "0.8.4-main.abd8ff62ef",
88
+ "@dxos/invariant": "0.8.4-main.abd8ff62ef",
89
+ "@dxos/log": "0.8.4-main.abd8ff62ef",
90
+ "@dxos/react-error-boundary": "0.8.4-main.abd8ff62ef",
91
+ "@dxos/lit-ui": "0.8.4-main.abd8ff62ef",
92
+ "@dxos/react-input": "0.8.4-main.abd8ff62ef",
93
+ "@dxos/react-hooks": "0.8.4-main.abd8ff62ef",
94
+ "@dxos/util": "0.8.4-main.abd8ff62ef",
95
+ "@dxos/ui-types": "0.8.4-main.abd8ff62ef",
96
+ "@dxos/react-list": "0.8.4-main.abd8ff62ef"
95
97
  },
96
98
  "devDependencies": {
97
99
  "@dnd-kit/core": "^6.0.5",
@@ -104,15 +106,15 @@
104
106
  "react": "~19.2.3",
105
107
  "react-dom": "~19.2.3",
106
108
  "tabster": "^8.5.5",
107
- "vite": "^7.1.11",
108
- "@dxos/ui-theme": "0.8.4-main.9be5663bfe",
109
- "@dxos/random": "0.8.4-main.9be5663bfe",
110
- "@dxos/util": "0.8.4-main.9be5663bfe"
109
+ "vite": "^8.0.10",
110
+ "@dxos/random": "0.8.4-main.abd8ff62ef",
111
+ "@dxos/ui-theme": "0.8.4-main.abd8ff62ef",
112
+ "@dxos/util": "0.8.4-main.abd8ff62ef"
111
113
  },
112
114
  "peerDependencies": {
113
115
  "react": "~19.2.3",
114
116
  "react-dom": "~19.2.3",
115
- "@dxos/ui-theme": "0.8.4-main.9be5663bfe"
117
+ "@dxos/ui-theme": "0.8.4-main.abd8ff62ef"
116
118
  },
117
119
  "publishConfig": {
118
120
  "access": "public"
@@ -16,6 +16,7 @@ type IconButtonProps = Omit<ButtonProps, 'children'> &
16
16
  noTooltip?: boolean;
17
17
  caretDown?: boolean;
18
18
  iconOnly?: boolean;
19
+ square?: boolean; // TODO(burdon): Handle more uniformly.
19
20
  iconEnd?: boolean;
20
21
  iconClassNames?: ThemedClassName<any>['classNames'];
21
22
  tooltipSide?: TooltipSide;
@@ -45,12 +46,12 @@ const IconOnlyButton = forwardRef<HTMLButtonElement, IconButtonProps>(
45
46
 
46
47
  const LabelledIconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
47
48
  (
48
- { size, icon, iconOnly, iconEnd, iconClassNames, label, caretDown, noTooltip: _, classNames, ...props },
49
+ { size, icon, iconOnly, square, iconEnd, iconClassNames, label, caretDown, noTooltip: _, classNames, ...props },
49
50
  forwardedRef,
50
51
  ) => {
51
52
  const { tx } = useThemeContext();
52
53
  return (
53
- <Button {...props} classNames={tx('iconButton.root', { iconOnly }, classNames)} ref={forwardedRef}>
54
+ <Button {...props} classNames={tx('iconButton.root', { iconOnly, square }, classNames)} ref={forwardedRef}>
54
55
  {icon && !iconEnd && <Icon icon={icon} size={size} classNames={iconClassNames} />}
55
56
  <span className={iconOnly ? 'sr-only' : undefined}>{label}</span>
56
57
  {icon && iconEnd && <Icon icon={icon} size={size} classNames={iconClassNames} />}
@@ -80,7 +80,9 @@ const CardRoot = slottable<HTMLDivElement, CardRootOwnProps>(
80
80
  className={tx('card.root', { border, fullWidth }, className)}
81
81
  ref={forwardedRef}
82
82
  >
83
- <Column.Root gutter={density === 'coarse' ? 'lg' : 'md'}>{children}</Column.Root>
83
+ <Column.Root classNames='overflow-hidden' gutter={density === 'coarse' ? 'lg' : 'md'}>
84
+ {children}
85
+ </Column.Root>
84
86
  </Comp>
85
87
  );
86
88
  },
@@ -251,15 +253,16 @@ const CARD_ROW_NAME = 'Card.Row';
251
253
 
252
254
  type CardRowProps = { icon?: string; fullWidth?: boolean };
253
255
 
254
- const CardRow = composable<HTMLDivElement, CardRowProps>(({ children, icon, ...props }, forwardedRef) => {
256
+ const CardRow = slottable<HTMLDivElement, CardRowProps>(({ children, asChild, icon, ...props }, forwardedRef) => {
255
257
  const { className, ...rest } = composableProps(props);
258
+ const Comp = asChild ? Slot : Primitive.div;
256
259
  const { tx } = useThemeContext();
257
260
 
258
261
  return (
259
- <Column.Row {...rest} className={tx('card.row', {}, className)} ref={forwardedRef}>
262
+ <Comp {...rest} className={tx('card.row', {}, className)} ref={forwardedRef}>
260
263
  {(icon && <CardIcon classNames='text-subdued' icon={icon} size={4} />) || <div />}
261
264
  {children}
262
- </Column.Row>
265
+ </Comp>
263
266
  );
264
267
  });
265
268
 
@@ -382,6 +385,13 @@ type CardPosterProps = ThemedClassName<
382
385
  {
383
386
  alt: string;
384
387
  aspect?: 'video' | 'auto';
388
+ /**
389
+ * How the image fills the poster box. `'contain'` (default) preserves
390
+ * aspect ratio and may letterbox; `'cover'` fills the box edge-to-edge,
391
+ * cropping as needed. Forwarded to the underlying `Image`'s
392
+ * `object-fit`.
393
+ */
394
+ fit?: 'contain' | 'cover';
385
395
  } & Partial<{ image: string; icon: string }>
386
396
  >;
387
397
 
@@ -392,7 +402,12 @@ const CardPoster = (props: CardPosterProps) => {
392
402
  if (props.image) {
393
403
  return (
394
404
  <div role='none' className='col-span-full'>
395
- <Image classNames={[tx('card.poster', {}), aspect, props.classNames]} src={props.image} alt={props.alt} />
405
+ <Image
406
+ classNames={[tx('card.poster', {}), aspect, props.classNames]}
407
+ src={props.image}
408
+ alt={props.alt}
409
+ fit={props.fit}
410
+ />
396
411
  </div>
397
412
  );
398
413
  }
@@ -24,7 +24,7 @@ type DefaultStoryProps = Pick<DialogContentProps, 'size'> &
24
24
 
25
25
  /**
26
26
  * Standard Dialog with non-scrolling content in Dialog.Body.
27
- * Dialog.Body delegates to Column.Content, which applies gutter padding via `px-[var(--gutter)]`.
27
+ * Dialog.Body propagates the Column grid via subgrid. Children auto-center via --dx-col.
28
28
  */
29
29
  const DefaultStory = ({ size, title, description, openTrigger, closeTrigger, blockAlign }: DefaultStoryProps) => {
30
30
  return (
@@ -62,7 +62,7 @@ const DefaultStory = ({ size, title, description, openTrigger, closeTrigger, blo
62
62
 
63
63
  /**
64
64
  * Dialog with a ScrollArea child inside Dialog.Body.
65
- * The ScrollArea breaks out of Body's gutter padding via `--gutter-offset`
65
+ * The ScrollArea breaks out of Body's gutter padding via `--gutter`
66
66
  * and applies its own asymmetric padding (accounting for scrollbar width).
67
67
  */
68
68
  const ScrollingStory = ({ size, title, description, openTrigger, closeTrigger, blockAlign }: DefaultStoryProps) => {
@@ -4,17 +4,17 @@
4
4
 
5
5
  import { createContext } from '@radix-ui/react-context';
6
6
  import * as DialogPrimitive from '@radix-ui/react-dialog';
7
+ import { Primitive } from '@radix-ui/react-primitive';
8
+ import { Slot } from '@radix-ui/react-slot';
7
9
  import React, {
8
10
  type ComponentPropsWithRef,
9
11
  type ForwardRefExoticComponent,
10
12
  type FunctionComponent,
11
- type PropsWithChildren,
12
13
  forwardRef,
13
14
  } from 'react';
14
15
  import { useTranslation } from 'react-i18next';
15
16
 
16
- import { type DialogSize, osTranslations } from '@dxos/ui-theme';
17
- import { slottable } from '@dxos/ui-theme';
17
+ import { composableProps, type DialogSize, osTranslations, slottable } from '@dxos/ui-theme';
18
18
  import { type SlottableProps } from '@dxos/ui-types';
19
19
 
20
20
  import { useThemeContext } from '../../hooks';
@@ -138,18 +138,18 @@ DialogContent.displayName = DIALOG_CONTENT_NAME;
138
138
  // Header
139
139
  //
140
140
 
141
- type DialogHeaderProps = PropsWithChildren;
141
+ type DialogHeaderProps = SlottableProps;
142
142
 
143
- const DialogHeader: ForwardRefExoticComponent<DialogHeaderProps> = forwardRef<HTMLHeadingElement, DialogHeaderProps>(
144
- ({ children }, forwardedRef) => {
145
- const { tx } = useThemeContext();
146
- return (
147
- <Column.Row className={tx('dialog.header')} center ref={forwardedRef}>
148
- {children}
149
- </Column.Row>
150
- );
151
- },
152
- );
143
+ const DialogHeader = slottable<HTMLDivElement>(({ children, asChild, ...props }, forwardedRef) => {
144
+ const { className, ...rest } = composableProps(props);
145
+ const Comp = asChild ? Slot : Primitive.div;
146
+ const { tx } = useThemeContext();
147
+ return (
148
+ <Comp {...rest} className={tx('dialog.header', {}, className)} ref={forwardedRef}>
149
+ {children}
150
+ </Comp>
151
+ );
152
+ });
153
153
 
154
154
  //
155
155
  // CloseIconButton
@@ -181,11 +181,13 @@ const DialogCloseIconButton = forwardRef<HTMLButtonElement, DialogCloseIconButto
181
181
  type DialogBodyProps = SlottableProps;
182
182
 
183
183
  const DialogBody = slottable<HTMLDivElement>(({ children, asChild, ...props }, forwardedRef) => {
184
+ const { className, ...rest } = composableProps(props);
185
+ const Comp = asChild ? Slot : Primitive.div;
184
186
  const { tx } = useThemeContext();
185
187
  return (
186
- <Column.Content {...props} asChild={asChild} className={tx('dialog.body', {})} ref={forwardedRef}>
188
+ <Comp {...rest} className={tx('dialog.body', {}, className)} ref={forwardedRef}>
187
189
  {children}
188
- </Column.Content>
190
+ </Comp>
189
191
  );
190
192
  });
191
193
 
@@ -227,20 +229,18 @@ const DialogDescription = forwardRef<HTMLParagraphElement, DialogDescriptionProp
227
229
  // ActionBar
228
230
  //
229
231
 
230
- type DialogActionBarProps = ThemedClassName<PropsWithChildren>;
232
+ type DialogActionBarProps = SlottableProps;
231
233
 
232
- const DialogActionBar = forwardRef<HTMLDivElement, DialogActionBarProps>(
233
- ({ children, classNames, ...props }, forwardedRef) => {
234
- const { tx } = useThemeContext();
235
- return (
236
- <Column.Row center>
237
- <div {...props} className={tx('dialog.actionbar', {}, classNames)} ref={forwardedRef}>
238
- {children}
239
- </div>
240
- </Column.Row>
241
- );
242
- },
243
- );
234
+ const DialogActionBar = slottable<HTMLDivElement>(({ children, asChild, ...props }, forwardedRef) => {
235
+ const { className: classNames, ...rest } = composableProps(props);
236
+ const Comp = asChild ? Slot : Primitive.div;
237
+ const { tx } = useThemeContext();
238
+ return (
239
+ <Comp {...rest} className={tx('dialog.actionbar', {}, classNames)} ref={forwardedRef}>
240
+ {children}
241
+ </Comp>
242
+ );
243
+ });
244
244
 
245
245
  //
246
246
  // Close
@@ -13,15 +13,16 @@ export type ImageProps = ThemedClassName<
13
13
  {
14
14
  src: string;
15
15
  alt?: string;
16
+ fit?: 'contain' | 'cover';
16
17
  crossOrigin?: 'anonymous' | 'use-credentials' | '';
17
18
  } & ColorOptions
18
19
  >;
19
20
 
20
- // TODO(burdon): Option for neutral background color.
21
21
  export const Image = ({
22
22
  classNames,
23
23
  src,
24
24
  alt = '',
25
+ fit = 'contain',
25
26
  crossOrigin = 'anonymous',
26
27
  sampleSize = 64,
27
28
  contrast = 0.9,
@@ -68,7 +69,16 @@ export const Image = ({
68
69
 
69
70
  return (
70
71
  <div
71
- className={mx(`relative flex w-full justify-center overflow-hidden transition-all duration-700`, classNames)}
72
+ // `isolate` (`isolation: isolate`) creates a new stacking context so
73
+ // the inner <img>'s `z-10` stays scoped to this wrapper. Without it
74
+ // the z-10 leaks into the parent's stacking context and elevates the
75
+ // image above any pseudo-element rings (e.g. Focus.Item's
76
+ // `dx-ring-pseudo` `::after`) painted on ancestors — most visibly,
77
+ // the focus ring on a Card containing a Card.Poster.
78
+ className={mx(
79
+ `relative flex w-full justify-center overflow-hidden transition-all duration-700 isolate`,
80
+ classNames,
81
+ )}
72
82
  style={{
73
83
  backgroundColor: dominantColor,
74
84
  }}
@@ -94,7 +104,10 @@ export const Image = ({
94
104
  crossOrigin={crossOriginState}
95
105
  onError={handleImageError}
96
106
  onLoad={handleImageLoad}
97
- className='z-10 object-contain transition-opacity duration-500'
107
+ className={mx(
108
+ 'z-10 transition-opacity duration-500',
109
+ fit === 'cover' ? 'w-full h-full object-cover' : 'object-contain',
110
+ )}
98
111
  style={{
99
112
  opacity: imageLoaded ? 1 : 0,
100
113
  }}
@@ -162,7 +175,9 @@ const extractDominantColor = (
162
175
  const alpha = pixels[i + 3];
163
176
 
164
177
  // Skip transparent pixels.
165
- if (alpha === 0) continue;
178
+ if (alpha === 0) {
179
+ continue;
180
+ }
166
181
 
167
182
  // Calculate saturation to weight vibrant colors more.
168
183
  const max = Math.max(red, green, blue);
@@ -202,21 +217,29 @@ const isTransparent = (pixels: Uint8ClampedArray, sampleSize: number, threshold:
202
217
  for (let x = 0; x < sampleSize; x++) {
203
218
  // Top edge.
204
219
  const topIndex = x * 4;
205
- if (pixels[topIndex + 3] === 0) edgeTransparentPixels++;
220
+ if (pixels[topIndex + 3] === 0) {
221
+ edgeTransparentPixels++;
222
+ }
206
223
 
207
224
  // Bottom edge.
208
225
  const bottomIndex = ((sampleSize - 1) * sampleSize + x) * 4;
209
- if (pixels[bottomIndex + 3] === 0) edgeTransparentPixels++;
226
+ if (pixels[bottomIndex + 3] === 0) {
227
+ edgeTransparentPixels++;
228
+ }
210
229
  }
211
230
 
212
231
  for (let y = 1; y < sampleSize - 1; y++) {
213
232
  // Left edge.
214
233
  const leftIndex = y * sampleSize * 4;
215
- if (pixels[leftIndex + 3] === 0) edgeTransparentPixels++;
234
+ if (pixels[leftIndex + 3] === 0) {
235
+ edgeTransparentPixels++;
236
+ }
216
237
 
217
238
  // Right edge.
218
239
  const rightIndex = (y * sampleSize + sampleSize - 1) * 4;
219
- if (pixels[rightIndex + 3] === 0) edgeTransparentPixels++;
240
+ if (pixels[rightIndex + 3] === 0) {
241
+ edgeTransparentPixels++;
242
+ }
220
243
  }
221
244
 
222
245
  return edgeTransparentPixels / edgePixels > threshold;
@@ -130,13 +130,13 @@ type TextInputProps = InputSharedProps & ThemedClassName<TextInputPrimitiveProps
130
130
 
131
131
  const TextInput = forwardRef<HTMLInputElement, InputScopedProps<TextInputProps>>(
132
132
  (
133
- { __inputScope, classNames, density: propsDensity, elevation: propsElevation, variant, noAutoFill, ...props },
133
+ { __inputScope, classNames, density: densityProp, elevation: elevationProp, variant, noAutoFill, ...props },
134
134
  forwardedRef,
135
135
  ) => {
136
136
  const { hasIosKeyboard } = useThemeContext();
137
137
  const { tx } = useThemeContext();
138
- const density = useDensityContext(propsDensity);
139
- const elevation = useElevationContext(propsElevation);
138
+ const density = useDensityContext(densityProp);
139
+ const elevation = useElevationContext(elevationProp);
140
140
  const { validationValence } = useInputContext(INPUT_NAME, __inputScope);
141
141
 
142
142
  return (
@@ -22,7 +22,7 @@ type DefaultStoryProps = {
22
22
  const DefaultStory = ({ valence, title, body }: DefaultStoryProps) => (
23
23
  <div className='w-[30rem]'>
24
24
  <Message.Root valence={valence}>
25
- {title && <Message.Title>{title}</Message.Title>}
25
+ {title && <Message.Title onClose={() => console.log('close')}>{title}</Message.Title>}
26
26
  {body && <Message.Content>{body}</Message.Content>}
27
27
  </Message.Root>
28
28
  </div>
@@ -6,12 +6,16 @@ import { createContext } from '@radix-ui/react-context';
6
6
  import { Primitive } from '@radix-ui/react-primitive';
7
7
  import { Slot } from '@radix-ui/react-slot';
8
8
  import React, { type ComponentPropsWithRef, forwardRef } from 'react';
9
+ import { useTranslation } from 'react-i18next';
9
10
 
10
11
  import { useId } from '@dxos/react-hooks';
11
12
  import { type Elevation, type MessageValence } from '@dxos/ui-types';
12
13
 
14
+ import { translationKey } from '#translations';
15
+
13
16
  import { useElevationContext, useThemeContext } from '../../hooks';
14
17
  import { type ThemedClassName } from '../../util';
18
+ import { IconButton } from '../Button';
15
19
  import { Icon } from '../Icon';
16
20
 
17
21
  const messageIcons: Record<MessageValence, string> = {
@@ -84,23 +88,36 @@ MessageRoot.displayName = MESSAGE_NAME;
84
88
  //
85
89
 
86
90
  type MessageTitleProps = Omit<ThemedClassName<ComponentPropsWithRef<typeof Primitive.h2>>, 'id'> & {
87
- asChild?: boolean;
88
91
  icon?: string;
92
+ onClose?: () => void;
89
93
  };
90
94
 
91
95
  const MESSAGE_TITLE_NAME = 'MessageTitle';
92
96
 
93
97
  const MessageTitle = forwardRef<HTMLHeadingElement, MessageTitleProps>(
94
- ({ asChild, classNames, children, icon: iconProp, ...props }, forwardedRef) => {
98
+ ({ classNames, children, icon: iconProp, onClose }, forwardedRef) => {
99
+ const { t } = useTranslation(translationKey);
95
100
  const { tx } = useThemeContext();
96
101
  const { titleId, valence } = useMessageContext(MESSAGE_TITLE_NAME);
97
- const Comp = asChild ? Slot : Primitive.h2;
98
102
  const icon = iconProp ?? messageIcons[valence];
99
103
  return (
100
- <Comp {...props} className={tx('message.header', {}, classNames)} id={titleId} ref={forwardedRef}>
101
- {!icon && valence === 'neutral' ? <div /> : <Icon icon={icon} classNames={tx('message.icon', { valence })} />}
102
- <span className={tx('message.title', {}, classNames)}>{children}</span>
103
- </Comp>
104
+ <div role='none' className={tx('message.header', {}, classNames)} id={titleId} ref={forwardedRef}>
105
+ {icon && (
106
+ <div role='none' className={tx('message.icon', { valence })}>
107
+ <Icon icon={icon} />
108
+ </div>
109
+ )}
110
+ <h2 className={tx('message.title', {}, classNames)}>{children}</h2>
111
+ {onClose && (
112
+ <IconButton
113
+ variant='ghost'
114
+ icon='ph--x--regular'
115
+ iconOnly
116
+ label={t('toolbar-close.label')}
117
+ onClick={onClose}
118
+ />
119
+ )}
120
+ </div>
104
121
  );
105
122
  },
106
123
  );
@@ -2,7 +2,7 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- export { type Label, isLabel, toLocalizedString } from '@dxos/ui-types';
5
+ export { type Label, isLabel, toLocalizedString } from '@dxos/ui-types/translations';
6
6
 
7
7
  export * from './ThemeProvider';
8
8
  export { useTranslation } from './TranslationsProvider';
@@ -12,8 +12,9 @@ import { useTranslation } from 'react-i18next';
12
12
  import { composable, composableProps, slottable, type ToolbarStyleProps } from '@dxos/ui-theme';
13
13
  import { type SlottableProps } from '@dxos/ui-types';
14
14
 
15
+ import { translationKey } from '#translations';
16
+
15
17
  import { useThemeContext } from '../../hooks';
16
- import { translationKey } from '../../translations';
17
18
  import {
18
19
  Button,
19
20
  ButtonGroup,