@dxos/ui-theme 0.8.4-main.c85a9c8dae → 0.8.4-main.cb12b3f963

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 (148) hide show
  1. package/dist/lib/browser/index.mjs +401 -475
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +401 -475
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/plugin/node-cjs/{theme.css → main.css} +126 -56
  8. package/dist/plugin/node-cjs/main.css.map +7 -0
  9. package/dist/plugin/node-cjs/meta.json +1 -1
  10. package/dist/plugin/node-cjs/plugins/ThemePlugin.cjs +8 -15
  11. package/dist/plugin/node-cjs/plugins/ThemePlugin.cjs.map +3 -3
  12. package/dist/plugin/node-esm/{theme.css → main.css} +126 -56
  13. package/dist/plugin/node-esm/main.css.map +7 -0
  14. package/dist/plugin/node-esm/meta.json +1 -1
  15. package/dist/plugin/node-esm/plugins/ThemePlugin.mjs +8 -15
  16. package/dist/plugin/node-esm/plugins/ThemePlugin.mjs.map +3 -3
  17. package/dist/types/src/Theme.stories.d.ts.map +1 -1
  18. package/dist/types/src/defs.d.ts +2 -2
  19. package/dist/types/src/defs.d.ts.map +1 -1
  20. package/dist/types/src/fragments/density.d.ts +1 -4
  21. package/dist/types/src/fragments/density.d.ts.map +1 -1
  22. package/dist/types/src/fragments/index.d.ts +0 -5
  23. package/dist/types/src/fragments/index.d.ts.map +1 -1
  24. package/dist/types/src/fragments/text.d.ts +0 -5
  25. package/dist/types/src/fragments/text.d.ts.map +1 -1
  26. package/dist/types/src/index.d.ts +1 -1
  27. package/dist/types/src/index.d.ts.map +1 -1
  28. package/dist/types/src/plugins/ThemePlugin.d.ts +1 -1
  29. package/dist/types/src/plugins/ThemePlugin.d.ts.map +1 -1
  30. package/dist/types/src/theme/components/avatar.d.ts.map +1 -1
  31. package/dist/types/src/theme/components/card.d.ts +3 -2
  32. package/dist/types/src/theme/components/card.d.ts.map +1 -1
  33. package/dist/types/src/theme/components/dialog.d.ts.map +1 -1
  34. package/dist/types/src/theme/components/focus.d.ts +6 -0
  35. package/dist/types/src/theme/components/focus.d.ts.map +1 -0
  36. package/dist/types/src/theme/components/icon-button.d.ts +1 -0
  37. package/dist/types/src/theme/components/icon-button.d.ts.map +1 -1
  38. package/dist/types/src/theme/components/icon.d.ts +3 -0
  39. package/dist/types/src/theme/components/icon.d.ts.map +1 -1
  40. package/dist/types/src/theme/components/index.d.ts +1 -0
  41. package/dist/types/src/theme/components/index.d.ts.map +1 -1
  42. package/dist/types/src/theme/components/input.d.ts +8 -8
  43. package/dist/types/src/theme/components/input.d.ts.map +1 -1
  44. package/dist/types/src/theme/components/link.d.ts.map +1 -1
  45. package/dist/types/src/theme/components/list.d.ts.map +1 -1
  46. package/dist/types/src/theme/components/main.d.ts.map +1 -1
  47. package/dist/types/src/theme/components/message.d.ts.map +1 -1
  48. package/dist/types/src/theme/components/popover.d.ts.map +1 -1
  49. package/dist/types/src/theme/components/scroll-area.d.ts +12 -2
  50. package/dist/types/src/theme/components/scroll-area.d.ts.map +1 -1
  51. package/dist/types/src/theme/components/select.d.ts.map +1 -1
  52. package/dist/types/src/theme/components/status.d.ts +1 -1
  53. package/dist/types/src/theme/components/status.d.ts.map +1 -1
  54. package/dist/types/src/theme/components/toast.d.ts.map +1 -1
  55. package/dist/types/src/theme/components/toolbar.d.ts +0 -1
  56. package/dist/types/src/theme/components/toolbar.d.ts.map +1 -1
  57. package/dist/types/src/theme/components/tooltip.d.ts.map +1 -1
  58. package/dist/types/src/theme/components/treegrid.d.ts.map +1 -1
  59. package/dist/types/src/theme/index.d.ts +1 -0
  60. package/dist/types/src/theme/index.d.ts.map +1 -1
  61. package/dist/types/src/theme/primitives/column.d.ts +25 -3
  62. package/dist/types/src/theme/primitives/column.d.ts.map +1 -1
  63. package/dist/types/src/theme/primitives/panel.d.ts +9 -5
  64. package/dist/types/src/theme/primitives/panel.d.ts.map +1 -1
  65. package/dist/types/src/theme/theme.d.ts.map +1 -1
  66. package/dist/types/src/util/elevation.d.ts.map +1 -0
  67. package/dist/types/src/util/hash-styles.d.ts.map +1 -1
  68. package/dist/types/src/util/index.d.ts +3 -0
  69. package/dist/types/src/util/index.d.ts.map +1 -1
  70. package/dist/types/src/util/mx.d.ts +52 -4
  71. package/dist/types/src/util/mx.d.ts.map +1 -1
  72. package/dist/types/src/util/size.d.ts +27 -0
  73. package/dist/types/src/util/size.d.ts.map +1 -0
  74. package/dist/types/src/util/valence.d.ts +4 -0
  75. package/dist/types/src/util/valence.d.ts.map +1 -0
  76. package/dist/types/tsconfig.tsbuildinfo +1 -1
  77. package/package.json +13 -16
  78. package/src/css/components/button.css +2 -1
  79. package/src/css/components/{focus-ring.css → focus.css} +15 -1
  80. package/src/css/components/icon.css +9 -0
  81. package/src/css/components/panel.css +22 -22
  82. package/src/css/components/selected.css +35 -0
  83. package/src/css/components/selected.md +101 -0
  84. package/src/css/components/tag.css +3 -1
  85. package/src/css/integrations/codemirror.css +5 -3
  86. package/src/css/integrations/tldraw.css +1 -0
  87. package/src/css/layout/main.css +0 -7
  88. package/src/css/layout/size.css +19 -27
  89. package/src/css/theme/animation.css +31 -0
  90. package/src/css/theme/palette.css +8 -0
  91. package/src/css/theme/semantic.css +25 -9
  92. package/src/css/theme/spacing.css +36 -19
  93. package/src/css/utilities.css +114 -3
  94. package/src/defs.ts +1 -1
  95. package/src/fragments/AUDIT.md +57 -0
  96. package/src/fragments/density.ts +8 -5
  97. package/src/fragments/index.ts +1 -6
  98. package/src/fragments/text.ts +1 -6
  99. package/src/index.ts +1 -1
  100. package/src/{theme.css → main.css} +46 -8
  101. package/src/plugins/ThemePlugin.ts +12 -24
  102. package/src/plugins/main.css +45 -0
  103. package/src/theme/components/avatar.ts +3 -4
  104. package/src/theme/components/button.ts +1 -1
  105. package/src/theme/components/card.ts +19 -11
  106. package/src/theme/components/dialog.ts +4 -3
  107. package/src/theme/components/focus.ts +33 -0
  108. package/src/theme/components/icon-button.ts +6 -5
  109. package/src/theme/components/icon.ts +13 -4
  110. package/src/theme/components/index.ts +1 -0
  111. package/src/theme/components/input.ts +15 -30
  112. package/src/theme/components/link.ts +1 -2
  113. package/src/theme/components/list.ts +4 -4
  114. package/src/theme/components/menu.ts +4 -4
  115. package/src/theme/components/message.ts +6 -7
  116. package/src/theme/components/popover.ts +4 -5
  117. package/src/theme/components/scroll-area.ts +58 -46
  118. package/src/theme/components/select.ts +2 -3
  119. package/src/theme/components/status.ts +5 -5
  120. package/src/theme/components/toast.ts +2 -3
  121. package/src/theme/components/toolbar.ts +1 -7
  122. package/src/theme/components/tooltip.ts +1 -2
  123. package/src/theme/components/treegrid.ts +1 -1
  124. package/src/theme/index.ts +1 -0
  125. package/src/theme/primitives/column.ts +49 -8
  126. package/src/theme/primitives/panel.ts +19 -23
  127. package/src/theme/theme.ts +2 -0
  128. package/src/typings.d.ts +3 -0
  129. package/src/util/index.ts +3 -0
  130. package/src/util/mx.ts +119 -8
  131. package/src/util/size.ts +103 -0
  132. package/dist/plugin/node-cjs/theme.css.map +0 -7
  133. package/dist/plugin/node-esm/theme.css.map +0 -7
  134. package/dist/types/src/fragments/elevation.d.ts.map +0 -1
  135. package/dist/types/src/fragments/focus.d.ts +0 -4
  136. package/dist/types/src/fragments/focus.d.ts.map +0 -1
  137. package/dist/types/src/fragments/selected.d.ts +0 -4
  138. package/dist/types/src/fragments/selected.d.ts.map +0 -1
  139. package/dist/types/src/fragments/size.d.ts +0 -7
  140. package/dist/types/src/fragments/size.d.ts.map +0 -1
  141. package/dist/types/src/fragments/valence.d.ts +0 -4
  142. package/dist/types/src/fragments/valence.d.ts.map +0 -1
  143. package/src/fragments/focus.ts +0 -11
  144. package/src/fragments/selected.ts +0 -12
  145. package/src/fragments/size.ts +0 -117
  146. /package/dist/types/src/{fragments → util}/elevation.d.ts +0 -0
  147. /package/src/{fragments → util}/elevation.ts +0 -0
  148. /package/src/{fragments → util}/valence.ts +0 -0
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type ComponentFunction, type Theme } from '@dxos/ui-types';
5
+ import { type ComponentFunction, type Density, type Theme } from '@dxos/ui-types';
6
6
 
7
7
  import { mx } from '../../util';
8
8
 
@@ -11,30 +11,30 @@ export type CardStyleProps = {
11
11
  fullWidth?: boolean;
12
12
  srOnly?: boolean;
13
13
  variant?: 'default' | 'subtitle' | 'description';
14
- coarse?: boolean;
14
+ density?: Density;
15
15
  truncate?: boolean;
16
+ padding?: boolean;
16
17
  };
17
18
 
18
19
  const cardRoot: ComponentFunction<CardStyleProps> = ({ border, fullWidth }, ...etc) =>
19
20
  mx(
20
- 'dx-card group/card relative flex flex-col w-full min-h-(--dx-rail-item) dx-card-min-width overflow-hidden',
21
+ 'dx-card dx-card-min-width dx-card-max-width min-h-(--dx-rail-item) group/card relative overflow-hidden',
21
22
  border &&
22
23
  'bg-card-surface border border-separator dark:border-subdued-separator rounded-xs dx-focus-ring-group-y-indicator',
23
24
  fullWidth && 'max-w-none!',
24
25
  ...etc,
25
26
  );
26
27
 
27
- const cardToolbar: ComponentFunction<CardStyleProps> = ({ coarse }, ...etc) =>
28
+ const cardToolbar: ComponentFunction<CardStyleProps> = (_, ...etc) =>
28
29
  mx(
29
- 'dx-card__toolbar dx-density-fine bg-transparent col-span-3 !grid grid-cols-subgrid [contain:none]',
30
- coarse && 'grid-cols-[var(--dx-l0-avatar-size)_minmax(0,1fr)_var(--dx-rail-item)]',
30
+ 'dx-card__toolbar dx-density-fine bg-transparent p-0! gap-0! col-span-3 grid! grid-cols-subgrid! [contain:none]',
31
31
  ...etc,
32
32
  );
33
33
 
34
34
  const cardTitle: ComponentFunction<CardStyleProps> = (_props, ...etc) => mx('dx-card__title grow truncate', ...etc);
35
35
 
36
36
  const cardContent: ComponentFunction<CardStyleProps> = (_props, ...etc) =>
37
- mx('dx-card__content contents [&>:last-child]:pb-1', ...etc);
37
+ mx('dx-card__content contents pb-1 last:pb-0', ...etc);
38
38
 
39
39
  const cardHeading: ComponentFunction<CardStyleProps> = ({ variant = 'default' }, ...etc) =>
40
40
  mx(
@@ -46,9 +46,9 @@ const cardHeading: ComponentFunction<CardStyleProps> = ({ variant = 'default' },
46
46
 
47
47
  const cardText: ComponentFunction<CardStyleProps> = ({ variant = 'default', truncate: _truncate }, ...etc) =>
48
48
  mx(
49
- 'dx-card__text flex overflow-hidden',
49
+ 'dx-card__text items-center overflow-hidden',
50
50
  variant === 'default' && 'py-1',
51
- variant === 'description' && 'py-1.5',
51
+ variant === 'description' && 'py-1.5 text-description',
52
52
  ...etc,
53
53
  );
54
54
 
@@ -73,14 +73,22 @@ const cardLink: ComponentFunction<CardStyleProps> = (_props, ...etc) =>
73
73
  const cardLinkLabel: ComponentFunction<CardStyleProps> = (_props, ...etc) =>
74
74
  mx('dx-card__link-label min-w-0 flex-1 truncate', ...etc);
75
75
 
76
- const cardIconBlock: ComponentFunction<CardStyleProps> = (_props, ...etc) =>
77
- mx('dx-card__icon-block grid h-[var(--dx-rail-item)] w-[var(--dx-rail-item)] place-items-center', ...etc);
76
+ const cardRow: ComponentFunction<CardStyleProps> = (_, ...etc) =>
77
+ mx('dx-card__row col-span-3 grid grid-cols-subgrid', ...etc);
78
+
79
+ const cardIconBlock: ComponentFunction<CardStyleProps> = ({ padding }, ...etc) =>
80
+ mx(
81
+ 'dx-card__icon-block grid h-[var(--dx-rail-item)] w-[var(--dx-rail-item)] place-items-center',
82
+ padding && '[&>*]:p-1',
83
+ ...etc,
84
+ );
78
85
 
79
86
  export const cardTheme: Theme<CardStyleProps> = {
80
87
  root: cardRoot,
81
88
  toolbar: cardToolbar,
82
89
  title: cardTitle,
83
90
  content: cardContent,
91
+ row: cardRow,
84
92
  heading: cardHeading,
85
93
  text: cardText,
86
94
  'text-span': cardTextSpan,
@@ -5,6 +5,7 @@
5
5
  import { type ComponentFunction, type Elevation, type Theme } from '@dxos/ui-types';
6
6
 
7
7
  import { mx } from '../../util';
8
+ import { withColumn } from '../primitives/column';
8
9
 
9
10
  export type DialogSize = 'sm' | 'md' | 'lg' | 'xl';
10
11
 
@@ -35,13 +36,13 @@ export const dialogContent: ComponentFunction<DialogStyleProps> = ({ inOverlayLa
35
36
  };
36
37
 
37
38
  export const dialogHeader: ComponentFunction<DialogStyleProps> = (_props, ...etc) =>
38
- mx('dx-dialog__header flex pb-4 items-center justify-between', ...etc);
39
+ mx('dx-dialog__header flex pb-4 items-center justify-between', withColumn.center(), ...etc);
39
40
 
40
41
  export const dialogBody: ComponentFunction<DialogStyleProps> = (_props, ...etc) =>
41
- mx('dx-dialog__body flex flex-col h-full py-2 gap-2', ...etc);
42
+ mx('dx-dialog__body dx-expander', withColumn.propagate(), ...etc);
42
43
 
43
44
  export const dialogActionBar: ComponentFunction<DialogStyleProps> = (_props, ...etc) =>
44
- mx('dx-dialog__actionbar flex items-center pt-4 gap-2 dx-density-coarse', ...etc);
45
+ mx('dx-dialog__actionbar flex items-center pt-4 gap-2 dx-density-coarse', withColumn.center(), ...etc);
45
46
 
46
47
  export const dialogTitle: ComponentFunction<DialogStyleProps> = ({ srOnly }, ...etc) =>
47
48
  mx('dx-dialog__title', srOnly && 'sr-only', ...etc);
@@ -0,0 +1,33 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { type ComponentFunction, type Theme } from '@dxos/ui-types';
6
+
7
+ import { mx } from '../../util';
8
+
9
+ export type FocusStyleProps = {
10
+ border?: boolean;
11
+ };
12
+
13
+ /**
14
+ * Focus ring styles shared by Focus.Group and Focus.Item.
15
+ * Uses a `::after` pseudo-element overlay so the ring paints above child content
16
+ * (inset box-shadow alone is obscured by children with backgrounds).
17
+ * The pseudo-element is `pointer-events-none` and absolutely positioned over the element.
18
+ * When `border` is true, a subdued CSS border is always visible (e.g., for grid cell edges).
19
+ */
20
+ const focusRing: ComponentFunction<FocusStyleProps> = ({ border }, ...etc) =>
21
+ mx(
22
+ 'dx-ring-pseudo outline-hidden',
23
+ 'focus:after:ring-neutral-focus-indicator',
24
+ 'data-[focus-state=active]:after:ring-neutral-focus-indicator',
25
+ 'data-[focus-state=error]:after:ring-rose-500',
26
+ border && 'border border-separator',
27
+ ...etc,
28
+ );
29
+
30
+ export const focusTheme: Theme<FocusStyleProps> = {
31
+ group: focusRing,
32
+ item: focusRing,
33
+ };
@@ -5,14 +5,15 @@
5
5
  import type { ComponentFunction, Theme } from '@dxos/ui-types';
6
6
 
7
7
  import { mx } from '../../util';
8
-
9
8
  import { type ButtonStyleProps } from './button';
10
9
 
11
- export type IconButtonStyleProps = ButtonStyleProps & { iconOnly?: boolean };
10
+ export type IconButtonStyleProps = ButtonStyleProps & {
11
+ iconOnly?: boolean;
12
+ square?: boolean;
13
+ };
12
14
 
13
- // TODO(burdon): Gap/font size should depend on density.
14
- export const iconButtonRoot: ComponentFunction<IconButtonStyleProps> = ({ iconOnly }, ...etc) => {
15
- return mx('gap-2', iconOnly && 'p-icon-button-padding min-h-0', ...etc);
15
+ export const iconButtonRoot: ComponentFunction<IconButtonStyleProps> = ({ iconOnly, square }, ...etc) => {
16
+ return mx('px-1.5', !iconOnly && 'gap-2', square && 'aspect-square', ...etc);
16
17
  };
17
18
 
18
19
  export const iconButtonTheme: Theme<IconButtonStyleProps> = {
@@ -4,15 +4,24 @@
4
4
 
5
5
  import { type ComponentFunction, type Size, type Theme } from '@dxos/ui-types';
6
6
 
7
- import { getSize } from '../../fragments';
8
- import { mx } from '../../util';
7
+ import { getSize, mx } from '../../util';
9
8
 
10
9
  export type IconStyleProps = {
11
10
  size?: Size;
12
11
  };
13
12
 
14
- export const iconRoot: ComponentFunction<IconStyleProps> = ({ size }, etc) =>
15
- mx('shrink-0 h-[1em] w-[1em] text-[var(--icons-color,currentColor)]', size && getSize(size), etc);
13
+ /**
14
+ * Size can be specified directly, or inherited from a container (e.g., toolbar).
15
+ */
16
+ export const iconRoot: ComponentFunction<IconStyleProps> = ({ size }, etc) => {
17
+ return mx(
18
+ 'shrink-0 text-[var(--icons-color,currentColor)]',
19
+ size
20
+ ? getSize(size)
21
+ : '[width:var(--icon-size,var(--dx-default-icons-size))] [height:var(--icon-size,var(--dx-default-icons-size))]',
22
+ etc,
23
+ );
24
+ };
16
25
 
17
26
  export const iconTheme: Theme<IconStyleProps> = {
18
27
  root: iconRoot,
@@ -7,6 +7,7 @@ export * from './breadcrumb';
7
7
  export * from './card';
8
8
  export * from './button';
9
9
  export * from './dialog';
10
+ export * from './focus';
10
11
  export * from './icon';
11
12
  export * from './icon-button';
12
13
  export * from './input';
@@ -11,23 +11,8 @@ import {
11
11
  type Size,
12
12
  } from '@dxos/ui-types';
13
13
 
14
- import {
15
- coarseBlockSize,
16
- coarseDimensions,
17
- computeSize,
18
- fineBlockSize,
19
- fineDimensions,
20
- focusRing,
21
- getSize,
22
- getSizeHeight,
23
- getSizeWidth,
24
- sizeValue,
25
- staticDisabled,
26
- staticFocusRing,
27
- subduedFocus,
28
- textValence,
29
- } from '../../fragments';
30
- import { mx } from '../../util';
14
+ import { densityDimensions, staticDisabled } from '../../fragments';
15
+ import { getSize, getHeight, getWidth, mx, snapSize, sizeValue, textValence } from '../../util';
31
16
 
32
17
  export type InputStyleProps = Partial<{
33
18
  variant: 'default' | 'subdued' | 'static';
@@ -73,30 +58,30 @@ const inputValence = (valence?: MessageValence) => {
73
58
  };
74
59
 
75
60
  const sharedSubduedInputStyles: ComponentFragment<InputStyleProps> = (props) => [
76
- 'py-0 w-full bg-transparent text-current placeholder-placeholder',
77
61
  '[[data-drag-autoscroll="active"]_&]:pointer-events-none',
78
- props.density === 'fine' ? fineBlockSize : coarseBlockSize,
79
- subduedFocus,
62
+ 'py-0 w-full bg-transparent text-current placeholder-placeholder',
63
+ 'dx-focus-subdued',
64
+ densityDimensions(props.density),
80
65
  props.disabled && staticDisabled,
81
66
  ];
82
67
 
83
68
  const sharedDefaultInputStyles: ComponentFragment<InputStyleProps> = (props) => [
84
- 'py-0 w-full text-base-surface-text rounded-xs placeholder-placeholder',
85
69
  '[[data-drag-autoscroll="active"]_&]:pointer-events-none',
70
+ 'py-0 w-full text-base-surface-text rounded-xs placeholder-placeholder',
86
71
  textInputSurfaceFocus,
87
- props.density === 'fine' ? fineDimensions : coarseDimensions,
72
+ densityDimensions(props.density),
88
73
  props.disabled ? staticDisabled : textInputSurfaceHover,
89
74
  ];
90
75
 
91
76
  const sharedStaticInputStyles: ComponentFragment<InputStyleProps> = (props) => [
92
- 'py-0 w-full text-base-surface-text rounded-xs placeholder-placeholder',
93
77
  '[[data-drag-autoscroll="active"]_&]:pointer-events-none',
78
+ 'py-0 w-full text-base-surface-text rounded-xs placeholder-placeholder',
94
79
  textInputSurfaceFocus,
95
80
  textInputSurfaceHover,
96
81
  props.focused && 'bg-attention-surface',
97
82
  inputValence(props.validationValence),
98
83
  props.disabled && staticDisabled,
99
- props.focused && staticFocusRing,
84
+ props.focused && 'dx-focus-static',
100
85
  ];
101
86
 
102
87
  const inputInput: ComponentFunction<InputStyleProps> = (props, ...etc) =>
@@ -106,28 +91,28 @@ const inputInput: ComponentFunction<InputStyleProps> = (props, ...etc) =>
106
91
  ? mx(...sharedStaticInputStyles(props), ...etc)
107
92
  : mx(
108
93
  ...sharedDefaultInputStyles(props),
109
- !props.disabled && focusRing,
94
+ !props.disabled && 'dx-focus-ring',
110
95
  inputValence(props.validationValence),
111
96
  ...etc,
112
97
  );
113
98
 
114
- const inputTextArea: ComponentFunction<InputStyleProps> = (props, ...etc) => inputInput(props, ...['-mb-1.5', ...etc]);
99
+ const inputTextArea: ComponentFunction<InputStyleProps> = (props, ...etc) => inputInput(props, ...etc);
115
100
 
116
101
  const inputCheckbox: ComponentFunction<InputStyleProps> = ({ size = 5 }, ...etc) =>
117
102
  mx('dx-checkbox dx-focus-ring', getSize(size), ...etc);
118
103
 
119
104
  const inputCheckboxIndicator: ComponentFunction<InputStyleProps> = ({ size = 5, checked }, ...etc) =>
120
- mx(getSize(computeSize(sizeValue(size) * 0.65, 4)), !checked && 'invisible', ...etc);
105
+ mx(getSize(snapSize(sizeValue(size) * 0.65, 4)), !checked && 'invisible', ...etc);
121
106
 
122
107
  const inputSwitch: ComponentFunction<InputStyleProps> = ({ size = 5, disabled }, ...etc) =>
123
108
  mx(
124
- getSizeHeight(size),
125
- getSizeWidth(computeSize(sizeValue(size) * 1.75, 9)),
109
+ getHeight(size),
110
+ getWidth(snapSize(sizeValue(size) * 1.75, 9)),
126
111
  booleanInputSurface,
127
112
  !disabled && booleanInputSurfaceHover,
128
113
  // TODO(burdon): Added m-1 margin to make 40px width to align with 40px icon button.
129
114
  'cursor-pointer shrink-0 rounded-full px-1 mx-1 relative',
130
- focusRing,
115
+ 'dx-focus-ring',
131
116
  ...etc,
132
117
  );
133
118
 
@@ -4,7 +4,6 @@
4
4
 
5
5
  import { type ComponentFunction, type Theme } from '@dxos/ui-types';
6
6
 
7
- import { focusRing } from '../../fragments';
8
7
  import { mx } from '../../util';
9
8
 
10
9
  export type LinkStyleProps = {
@@ -17,7 +16,7 @@ export const linkRoot: ComponentFunction<LinkStyleProps> = ({ variant }, ...etc)
17
16
  variant === 'neutral'
18
17
  ? 'text-inherit hover:opacity-90 visited:text-inherit visited:hover:opacity-90'
19
18
  : 'text-accent-text hover:text-accent-text-hover visited:text-accent-text visited:hover:text-accent-text-hover',
20
- focusRing,
19
+ 'dx-focus-ring',
21
20
  ...etc,
22
21
  );
23
22
 
@@ -4,8 +4,8 @@
4
4
 
5
5
  import { type ComponentFunction, type Density, type Theme } from '@dxos/ui-types';
6
6
 
7
- import { densityBlockSize, focusRing, getSize, ghostHover } from '../../fragments';
8
- import { mx } from '../../util';
7
+ import { densityBlockSize, ghostHover } from '../../fragments';
8
+ import { getSize, mx } from '../../util';
9
9
 
10
10
  export type ListStyleProps = Partial<{
11
11
  density: Density;
@@ -21,13 +21,13 @@ export const listItemEndcap: ComponentFunction<ListStyleProps> = ({ density }, .
21
21
  mx(density === 'fine' ? getSize(8) : getSize(10), 'shrink-0 flex items-center justify-center', ...etc);
22
22
 
23
23
  export const listItemHeading: ComponentFunction<ListStyleProps> = ({ density }, ...etc) =>
24
- mx(densityBlockSize(density), 'flex items-center', ...etc);
24
+ mx(densityBlockSize(density), 'flex items-center overflow-hidden [&>span]:truncate', ...etc);
25
25
 
26
26
  export const listItemDragHandleIcon: ComponentFunction<ListStyleProps> = (_props, ...etc) =>
27
27
  mx(getSize(5), 'mt-2.5', ...etc);
28
28
 
29
29
  export const listItemOpenTrigger: ComponentFunction<ListStyleProps> = ({ density }, ...etc) =>
30
- mx('w-5 rounded-sm flex justify-center items-center', densityBlockSize(density), ghostHover, focusRing, ...etc);
30
+ mx('w-5 rounded-sm flex justify-center items-center', densityBlockSize(density), ghostHover, 'dx-focus-ring', ...etc);
31
31
 
32
32
  export const listItemOpenTriggerIcon: ComponentFunction<ListStyleProps> = (_props, ...etc) => {
33
33
  return mx(getSize(5), ...etc);
@@ -4,8 +4,8 @@
4
4
 
5
5
  import { type ComponentFunction, type Elevation, type Theme } from '@dxos/ui-types';
6
6
 
7
- import { dataDisabled, subduedFocus, surfaceShadow, surfaceZIndex } from '../../fragments';
8
- import { mx } from '../../util';
7
+ import { dataDisabled } from '../../fragments';
8
+ import { mx, surfaceShadow, surfaceZIndex } from '../../util';
9
9
 
10
10
  export type MenuStyleProps = Partial<{
11
11
  constrainBlockSize: boolean;
@@ -26,8 +26,8 @@ export const menuViewport: ComponentFunction<MenuStyleProps> = (_props, ...etc)
26
26
  export const menuItem: ComponentFunction<MenuStyleProps> = (_props, ...etc) =>
27
27
  mx(
28
28
  'flex cursor-pointer select-none items-center gap-2 rounded-xs px-2 py-2 text-sm',
29
- 'data-[highlighted]:bg-hover-surface',
30
- subduedFocus,
29
+ 'hover:bg-hover-surface data-[highlighted]:bg-hover-surface',
30
+ 'dx-focus-subdued',
31
31
  dataDisabled,
32
32
  ...etc,
33
33
  );
@@ -4,8 +4,7 @@
4
4
 
5
5
  import { type ComponentFunction, type Elevation, type MessageValence, type Theme } from '@dxos/ui-types';
6
6
 
7
- import { messageValence } from '../../fragments';
8
- import { mx } from '../../util';
7
+ import { mx, messageValence } from '../../util';
9
8
 
10
9
  export type MessageStyleProps = {
11
10
  valence?: MessageValence;
@@ -13,23 +12,23 @@ export type MessageStyleProps = {
13
12
  };
14
13
 
15
14
  export const messageRoot: ComponentFunction<MessageStyleProps> = ({ valence }, etc) => {
16
- return mx('grid grid-cols-[min-content_1fr] gap-x-2 p-trim-sm rounded-sm', messageValence(valence), etc);
15
+ return mx('grid grid-cols-[2rem_1fr_2rem] p-1 rounded-sm', messageValence(valence), etc);
17
16
  };
18
17
 
19
18
  export const messageHeader: ComponentFunction<MessageStyleProps> = (_, etc) => {
20
- return mx('col-span-2 grid grid-cols-subgrid items-center', etc);
19
+ return mx('col-span-full grid grid-cols-subgrid items-center', etc);
21
20
  };
22
21
 
23
22
  export const messageTitle: ComponentFunction<MessageStyleProps> = (_, etc) => {
24
- return mx('col-start-2 text-lg gap-trim-sm [&>svg]:inline-block', etc);
23
+ return mx('col-start-2 truncate', etc);
25
24
  };
26
25
 
27
26
  export const messageIcon: ComponentFunction<MessageStyleProps> = (_, etc) => {
28
- return mx('col-start-1', etc);
27
+ return mx('col-start-1 grid place-items-center', etc);
29
28
  };
30
29
 
31
30
  export const messageContent: ComponentFunction<MessageStyleProps> = (_, etc) => {
32
- return mx('grid grid-cols-subgrid col-start-2 first:font-medium', etc);
31
+ return mx('col-start-2 grid grid-cols-subgrid first:font-medium', etc);
33
32
  };
34
33
 
35
34
  export const messageTheme: Theme<MessageStyleProps> = {
@@ -4,8 +4,7 @@
4
4
 
5
5
  import { type ComponentFunction, type Elevation, type Theme } from '@dxos/ui-types';
6
6
 
7
- import { focusRing, surfaceShadow, surfaceZIndex } from '../../fragments';
8
- import { mx } from '../../util';
7
+ import { mx, surfaceShadow, surfaceZIndex } from '../../util';
9
8
 
10
9
  export type PopoverStyleProps = Partial<{
11
10
  constrainBlock: boolean;
@@ -18,15 +17,15 @@ export const popoverContent: ComponentFunction<PopoverStyleProps> = ({ elevation
18
17
  'dx-modal-surface border border-separator rounded-sm',
19
18
  surfaceShadow({ elevation: 'positioned' }),
20
19
  surfaceZIndex({ elevation, level: 'menu' }),
21
- focusRing,
20
+ 'dx-focus-ring',
22
21
  ...etc,
23
22
  );
24
23
 
25
24
  export const popoverViewport: ComponentFunction<PopoverStyleProps> = ({ constrainBlock, constrainInline }, ...etc) =>
26
25
  mx(
27
- 'flex flex-col min-h-0 min-w-popover-min-width',
26
+ 'grid grid-rows-[1fr] min-h-0 min-w-popover-min-width',
28
27
  (constrainBlock || constrainInline) && 'overflow-hidden',
29
- // Ensures it respects available height from Radix (or 100dvh).
28
+ constrainBlock && 'max-h-(--radix-popover-content-available-height)',
30
29
  constrainBlock &&
31
30
  'max-h-[min(var(--radix-popover-content-available-height),calc(100dvh-var(--spacing-screen-border)*2))]',
32
31
  constrainInline && 'max-w-(--radix-popover-content-available-width)',
@@ -5,12 +5,24 @@
5
5
  import { type AllowedAxis, type ComponentFunction, type Theme } from '@dxos/ui-types';
6
6
 
7
7
  import { mx } from '../../util';
8
+ import { withColumn } from '../primitives/column';
9
+
10
+ export const scrollbar = {
11
+ thin: {
12
+ size: 4,
13
+ padding: 4,
14
+ },
15
+ coarse: {
16
+ size: 8,
17
+ padding: 8,
18
+ },
19
+ };
8
20
 
9
21
  export type ScrollAreaStyleProps = {
10
22
  orientation?: AllowedAxis;
11
23
  autoHide?: boolean;
12
- /** Balance left/right, top/bottom "margin" with scrollbar. */
13
- margin?: boolean;
24
+ /** Balance left/right, top/bottom offset with scrollbar. */
25
+ centered?: boolean;
14
26
  /** Add default padding. */
15
27
  /** TODO(burdon): Integrate with Column.Root padding. */
16
28
  padding?: boolean;
@@ -21,29 +33,17 @@ export type ScrollAreaStyleProps = {
21
33
  snap?: boolean;
22
34
  };
23
35
 
24
- export const scrollAreaRoot: ComponentFunction<ScrollAreaStyleProps> = ({ orientation, margin, thin }, ...etc) =>
36
+ export const scrollAreaRoot: ComponentFunction<ScrollAreaStyleProps> = ({ orientation }, ...etc) =>
25
37
  mx(
26
- 'overflow-hidden',
27
-
28
- orientation === 'vertical' && 'group/scroll-v dx-container',
29
- orientation === 'horizontal' && 'group/scroll-h dx-container',
30
- orientation === 'all' && 'group/scroll-all dx-container',
31
-
32
- // TODO(burdon): Audit composition.
33
- // Apply col-span-full only when inside a Column.Root grid (detected via dx-column marker).
34
- '[.dx-column_&]:col-span-full',
35
-
36
- // NOTE: Uses --gutter CSS variable
37
- // If contained within Column.Root grid, the gutter is set by that component.
38
- margin && [
39
- orientation === 'vertical' &&
40
- (thin
41
- ? 'pl-[var(--gutter,4px)] pr-[calc(var(--gutter,4px)-4px)]'
42
- : 'pl-[var(--gutter,8px)] pr-[calc(var(--gutter,8px)-8px)]'),
43
- orientation === 'horizontal' && (thin ? 'py-[var(--gutter,4px)]' : 'py-[var(--gutter,8px)]'),
44
- orientation === 'all' &&
45
- (thin ? 'pl-[var(--gutter,4px)] py-[var(--gutter,8px)]' : 'pl-[var(--gutter,8px)] py-[var(--gutter,8px)]'),
46
- ],
38
+ // Expand
39
+ 'dx-container',
40
+
41
+ orientation === 'vertical' && 'group/scroll-v flex flex-col',
42
+ orientation === 'horizontal' && 'group/scroll-h flex',
43
+ orientation === 'all' && 'group/scroll-all',
44
+
45
+ // Apply col-span-full only when inside a Column.Root grid (detected via dx-column-root marker).
46
+ '[.dx-column-root_&]:col-span-full',
47
47
 
48
48
  ...etc,
49
49
  );
@@ -52,24 +52,47 @@ export const scrollAreaRoot: ComponentFunction<ScrollAreaStyleProps> = ({ orient
52
52
  * NOTE: The browser reserves space for scrollbars.
53
53
  */
54
54
  export const scrollAreaViewport: ComponentFunction<ScrollAreaStyleProps> = (
55
- { orientation, autoHide, padding, snap, thin },
55
+ { orientation, centered, padding, snap, autoHide },
56
56
  ...etc
57
- ) =>
58
- mx(
59
- 'h-full w-full',
57
+ ) => {
58
+ return mx(
59
+ 'flex-1 min-h-0 w-full',
60
60
 
61
- orientation === 'vertical' && 'flex flex-col overflow-y-scroll',
62
- orientation === 'horizontal' && 'flex overflow-x-scroll',
63
- orientation === 'all' && 'overflow-scroll',
61
+ // Reset --dx-col so nested components don't try to grid-position themselves.
62
+ // ScrollArea has already consumed --gutter for padding.
63
+ withColumn.consumed(),
64
64
 
65
- thin
66
- ? '[&::-webkit-scrollbar]:w-[4px] [&::-webkit-scrollbar]:h-[4px]'
67
- : '[&::-webkit-scrollbar]:w-[8px] [&::-webkit-scrollbar]:h-[8px]',
65
+ orientation === 'vertical' && 'overflow-y-scroll',
66
+ orientation === 'horizontal' && 'flex overflow-x-scroll overscroll-x-contain',
67
+ orientation === 'all' && 'overflow-scroll',
68
68
 
69
69
  '[&::-webkit-scrollbar-corner]:bg-transparent',
70
70
  '[&::-webkit-scrollbar-track]:bg-transparent',
71
71
  '[&::-webkit-scrollbar-thumb]:rounded-none',
72
72
 
73
+ '[&::-webkit-scrollbar]:w-[var(--scroll-width)] [&::-webkit-scrollbar]:h-[var(--scroll-width)]',
74
+
75
+ // If contained within Column.Root grid the gutter is set by that component (--gutter CSS variable).
76
+ // If centered, left padding compensates for scrollbar width so content is visually centered.
77
+ (orientation === 'vertical' || orientation === 'all') &&
78
+ (padding
79
+ ? [
80
+ centered ? 'pl-[var(--gutter,calc(var(--scroll-width)+var(--scroll-padding)))]' : 'pl-[var(--gutter,0)]',
81
+ 'pr-[calc(var(--gutter,calc(var(--scroll-width)+var(--scroll-padding)))-var(--scroll-width))]',
82
+ ]
83
+ : centered && 'pl-[var(--scroll-width)]'),
84
+
85
+ (orientation === 'horizontal' || orientation === 'all') &&
86
+ (padding
87
+ ? [centered && 'pt-[calc(var(--scroll-width)+var(--scroll-padding))]', 'pb-[var(--scroll-padding)]']
88
+ : centered && 'pt-[var(--scroll-width)]'),
89
+
90
+ snap && [
91
+ orientation === 'vertical' && 'snap-y snap-mandatory',
92
+ orientation === 'horizontal' && 'snap-x snap-mandatory',
93
+ orientation === 'all' && 'snap-both snap-mandatory',
94
+ ],
95
+
73
96
  autoHide
74
97
  ? [
75
98
  orientation === 'vertical' && 'group-hover/scroll-v:[&::-webkit-scrollbar-thumb]:bg-scrollbar-thumb',
@@ -82,20 +105,9 @@ export const scrollAreaViewport: ComponentFunction<ScrollAreaStyleProps> = (
82
105
  orientation === 'all' && '[&::-webkit-scrollbar-thumb]:bg-scrollbar-thumb',
83
106
  ],
84
107
 
85
- padding && [
86
- orientation === 'vertical' && 'px-[4px]',
87
- orientation === 'horizontal' && 'pb-[4px]',
88
- orientation === 'all' && 'pl-[4px] pb-[4px]',
89
- ],
90
-
91
- snap && [
92
- orientation === 'vertical' && 'snap-y snap-mandatory',
93
- orientation === 'horizontal' && 'snap-x snap-mandatory',
94
- orientation === 'all' && 'snap-both snap-mandatory',
95
- ],
96
-
97
108
  ...etc,
98
109
  );
110
+ };
99
111
 
100
112
  export const scrollAreaTheme: Theme<ScrollAreaStyleProps> = {
101
113
  root: scrollAreaRoot,
@@ -4,8 +4,7 @@
4
4
 
5
5
  import { type ComponentFunction, type Elevation, type Theme } from '@dxos/ui-types';
6
6
 
7
- import { ghostHighlighted, surfaceShadow, surfaceZIndex } from '../../fragments';
8
- import { mx } from '../../util';
7
+ import { mx, surfaceShadow, surfaceZIndex } from '../../util';
9
8
 
10
9
  export type SelectStyleProps = Partial<{
11
10
  elevation: Elevation;
@@ -28,7 +27,7 @@ export const selectItem: ComponentFunction<SelectStyleProps> = (_props, ...etc)
28
27
  'flex items-center min-h-[2rem] px-3 py-1 gap-2',
29
28
  'text-base-surface-text leading-none select-none outline-hidden',
30
29
  '[&>svg]:invisible [&[data-state=checked]>svg]:visible',
31
- ghostHighlighted,
30
+ 'dx-highlighted',
32
31
  ...etc,
33
32
  );
34
33
 
@@ -7,21 +7,21 @@ import type { ComponentFunction, Theme } from '@dxos/ui-types';
7
7
  import { mx } from '../../util';
8
8
 
9
9
  export type StatusStyleProps = {
10
- indeterminate?: boolean;
11
10
  variant?: 'default' | 'main-bottom';
11
+ indeterminate?: boolean;
12
12
  };
13
13
 
14
14
  export const statusRoot: ComponentFunction<StatusStyleProps> = ({ variant = 'default' }, ...etc) =>
15
15
  mx(
16
- 'h-1 relative bg-hover-overlay rounded-full overflow-hidden',
17
- variant === 'main-bottom' ? 'w-full block' : 'inline-20 inline-block',
16
+ 'h-1 relative rounded-full overflow-hidden',
17
+ variant === 'main-bottom' ? 'w-full block' : 'inline-20 inline-block bg-base-surface',
18
18
  ...etc,
19
19
  );
20
20
 
21
- export const statusBar: ComponentFunction<StatusStyleProps> = ({ indeterminate, variant = 'default' }, ...etc) =>
21
+ export const statusBar: ComponentFunction<StatusStyleProps> = ({ variant = 'default', indeterminate }, ...etc) =>
22
22
  mx(
23
23
  'absolute inset-y-0 block rounded-full',
24
- variant === 'main-bottom' ? 'bg-accent-surface' : 'bg-un-accent',
24
+ variant === 'main-bottom' ? 'bg-composer-300' : 'bg-un-accent',
25
25
  indeterminate ? 'animate-progress-indeterminate' : 'start-0',
26
26
  ...etc,
27
27
  );
@@ -4,8 +4,7 @@
4
4
 
5
5
  import { type ComponentFunction, type Theme } from '@dxos/ui-types';
6
6
 
7
- import { focusRing, surfaceShadow } from '../../fragments';
8
- import { mx } from '../../util';
7
+ import { mx, surfaceShadow } from '../../util';
9
8
 
10
9
  export type ToastStyleProps = Partial<{
11
10
  srOnly: boolean;
@@ -28,7 +27,7 @@ export const toastRoot: ComponentFunction<ToastStyleProps> = (_props, ...etc) =>
28
27
  'radix-swipe-end:animate-toast-swipe-out',
29
28
  'translate-x-radix-toast-swipe-move-x',
30
29
  'radix-swipe-cancel:translate-x-0 radix-swipe-cancel:duration-200 radix-swipe-cancel:ease-[ease]',
31
- focusRing,
30
+ 'dx-focus-ring',
32
31
  ...etc,
33
32
  );
34
33