@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
@@ -1,354 +1,148 @@
1
- # Column composition
1
+ # Column architecture reference
2
2
 
3
3
  ## Background
4
4
 
5
- We have a complex design issue that requires research and deep thinking.
5
+ `Column` establishes a 3-column CSS grid with left/right gutter columns and a center content
6
+ channel. Two CSS custom properties drive the system:
6
7
 
7
- `Column` is a primitive that establishes a 3 column grid (side gutters and main content channel) by creating a CSS `grid` and setting the `--gutter` CSS variable.
8
- Both `Dialog` and `Card` use `Column` to establish their grid and both have separate sub-components.
9
- Also `ScrollArea` uses the `Column` grid to establish the side margins (padding via `--gutter`) for the main content.
10
- Various components (e.g., `Form`) define a `Viewport` that implements a `ScrollArea` to establish their grid.
8
+ - `--gutter` the gutter track width (e.g. `var(--dx-gutter-md)`); consumed by `ScrollArea.Viewport` for padding.
9
+ - `--dx-col` the grid-column placement token; set by `Column.Root` and consumed by `withColumn` utilities.
11
10
 
12
- ## Initial Tasks
11
+ ## Column primitives
13
12
 
14
- 1. Create a column-aligned Markdown table listing the sub-components for `Card` and `Dialog`.
15
- 2. Add to this table all Radix-style components that have a `Viewport` sub-component that uses `ScrollArea`.
16
- 3. For each of these component comment on whether they use appropraite standard for `Content` and `Viewport`, and call out any major design issues.
13
+ ### Column.Root
17
14
 
18
- ## Design Challenge
19
-
20
- The use of `Column` is intended to standardize how components establish a grid.
21
- It is intended that this supports nesting; e.g., a `Dialog` that has a `Form` in its `Viewport`.
22
- However there is a problem when child components contain other components that contain `Viewport`.
23
- For example:
24
-
25
- ```
26
- - CreateObjectDialog (plugin-space)
27
- - Dialog.Root
28
- - Dialog.Body
29
- - Dialog.Viewport => ScrollArea
30
- - CreateObjectPanel
31
- - Form.Root
32
- - Form.Viewport => ScrollArea
33
- - Form.Content
34
- - Form.FieldSet
35
- - Form.Actions
36
- ```
37
-
38
- The nested Viewports create a double set of scrollbars,
39
- whereas the entire contents of the `Dialog.Body` should be considered to be a single scroll-area.
40
- In this case we could omit the `Dialog.Viewport`, but inside `CreateObjectPanel` there are other components that do not define `Viewports`.
41
-
42
- Determine if this is really a problem. And consider different approachs.
43
-
44
- ## Audit
45
-
46
- ### Sub-components for Dialog and Card
47
-
48
- | Component | Sub-component | Uses Column | Uses ScrollArea | Has Viewport | Notes |
49
- | :--------- | :-------------- | :------------------------------ | :--------------------------------- | :----------- | :------------------------------- |
50
- | **Dialog** | Root | — | — | — | ElevationProvider wrapper |
51
- | | Trigger | — | — | — | Radix primitive |
52
- | | Portal | — | — | — | Radix primitive |
53
- | | Overlay | — | — | — | OverlayLayoutProvider |
54
- | | Content | **Column.Root** (gutter='sm') | — | — | Establishes the 3-col grid |
55
- | | Header | **Column.Row** (center) | — | — | Title + Close row |
56
- | | Body | col-span-full | — | — | Plain div, no gutters applied |
57
- | | **Viewport** | **Column.Viewport** | **ScrollArea** (vertical, padding) | **Yes** | Alias for Column.Viewport |
58
- | | Title | — | — | — | Radix primitive |
59
- | | Description | — | — | — | Radix primitive |
60
- | | ActionBar | **Column.Row** (center) | — | — | Action buttons row |
61
- | | Close | — | — | — | Radix primitive |
62
- | | CloseIconButton | — | — | — | Icon button |
63
- | **Card** | Root | **Column.Root** (gutter varies) | — | — | gutter='lg' coarse, 'md' default |
64
- | | Toolbar | col-span-3, subgrid | — | — | Toolbar.Root wrapper |
65
- | | DragHandle | — | — | — | In CardIconBlock |
66
- | | CloseIconButton | — | — | — | In CardIconBlock |
67
- | | Menu | — | — | — | In CardIconBlock |
68
- | | Icon | — | — | — | In CardIconBlock |
69
- | | IconBlock | — | — | — | Grid cell for icons |
70
- | | Title | — | — | — | Heading div |
71
- | | Content | — | — | — | `display: contents` |
72
- | | Row | **Column.Row** | — | — | With optional icon slot |
73
- | | Section | col-span-full | — | — | **Deprecated** |
74
- | | Heading | — | — | — | **Deprecated** |
75
- | | Text | — | — | — | Text display |
76
- | | Poster | col-span-full | — | — | Image/icon |
77
- | | Action | Column.Row via subgrid | — | — | Button row |
78
- | | Link | Column.Row via subgrid | — | — | External link row |
79
-
80
- ### Components with Viewport sub-components using ScrollArea
81
-
82
- | Component | Viewport impl | ScrollArea config | Notes |
83
- | :------------- | :--------------------- | :---------------------------------------- | :--------------------------------------- |
84
- | **Column** | Column.Viewport | vertical, padding | Base primitive; adds `py-2` |
85
- | **Dialog** | Dialog.Viewport | (alias for Column.Viewport) | No Dialog-specific behavior |
86
- | **Form** | Form.Viewport | vertical, margin, padding, thin | Sets `role='listbox'` |
87
- | **SearchList** | SearchList.Viewport | thin only | Sets `role='listbox'`; no margin/padding |
88
- | **Settings** | Settings.Root (itself) | vertical, margin | Root IS the ScrollArea; adds `p-trim-md` |
89
- | **Popover** | Popover.Viewport | **None** (constraint div, not ScrollArea) | Just constrains inline/block size |
90
- | **Combobox** | Combobox.List | (delegates to SearchList.Viewport) | Nested inside Popover.Viewport |
91
-
92
- ### Design issues per component
93
-
94
- | Component | Content/Viewport standard | Issues |
95
- | :------------- | :-------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
96
- | **Dialog** | Content → Column.Root; Viewport → Column.Viewport | `Dialog.Viewport` is a raw alias with no Dialog-specific awareness. `Dialog.Body` has `col-span-full` but no gutter padding — non-scrolling content inside it has no side margins. |
97
- | **Card** | Content → `display:contents`; No Viewport | Card has no scroll support. Card.Content using `display:contents` collapses the element from layout, which can cause containment/styling issues. No Body equivalent exists. |
98
- | **Form** | Root → context provider; Viewport → ScrollArea | Form.Viewport applies its own gutter padding via `--gutter`. When nested inside Dialog.Content (which sets `--gutter`), the padding aligns — but creates a second scroll container. |
99
- | **SearchList** | Content → flex column; Viewport → ScrollArea (thin) | SearchList.Viewport uses `thin` but NOT `margin` or `padding` — it doesn't apply `--gutter` padding at all. Content alignment inside a Column grid depends entirely on the parent. |
100
- | **Settings** | Root IS the ScrollArea | Standalone design; would double-scroll if placed inside another Viewport. |
101
- | **Combobox** | Delegates to SearchList.Viewport inside Popover | No conflict — Popover.Viewport is not ScrollArea-based. |
102
-
103
- ## Analysis
104
-
105
- ### The problem
106
-
107
- The core tension is between two responsibilities that `Viewport` (ScrollArea) currently conflates:
108
-
109
- 1. **Scrolling** — overflow handling and scrollbar styling.
110
- 2. **Gutter padding** — applying `px-[var(--gutter)]` (with scrollbar-width offset) to align content within the Column grid.
111
-
112
- When a container like `Dialog` provides its own Viewport and a child like `Form` also provides one,
113
- you get double scrollbars. Removing the container's Viewport fixes scrolling but breaks gutter alignment
114
- for child paths that don't bring their own Viewport (e.g., plain text content).
115
-
116
- ### The real nesting in CreateObjectDialog today
117
-
118
- ```
119
- Dialog.Content (Column.Root, sets --gutter)
120
- Dialog.Header (Column.Row)
121
- Dialog.Body (col-span-full, NO gutter padding)
122
- CreateObjectPanel (switches between paths):
123
- Path A: SelectType → SearchList → SearchList.Viewport (ScrollArea, thin)
124
- Path B: SelectSpace → SearchList → SearchList.Viewport (ScrollArea, thin)
125
- Path C: Form.Root → Form.Viewport (ScrollArea, margin, padding, thin) → Form.Content
126
- Path D: (future) plain content — no Viewport, no gutters, broken alignment
15
+ ```css
16
+ /* column.ts — columnRoot */
17
+ dx-column grid
18
+ /* inline style */
19
+ --gutter: <gutterSize>
20
+ --dx-col: 2 / span 1
21
+ grid-template-columns: <gutter> minmax(0,1fr) <gutter>
127
22
  ```
128
23
 
129
- Dialog.Viewport was removed to avoid double scrollbars in paths A–C.
130
- But path D would have no gutter padding because Dialog.Body doesn't provide it.
131
-
132
- ### Design principles
133
-
134
- 1. **Column.Content provides gutters via subgrid.** `Column.Root` sets `--gutter` and establishes the 3-column grid. `Column.Content` inherits this grid via CSS subgrid, placing non-scrolling children in the center column and allowing ScrollArea children to span full width.
135
- 2. **Leaves own scrolling.** Components that need to scroll (Form, SearchList) provide their own Viewport. Components that don't need to scroll do nothing.
136
- 3. **ScrollArea is always full width.** ScrollArea.Root must span all 3 grid columns and apply its own gutter padding via `--gutter` on its Viewport. No parent should constrain its width.
137
- 4. **Subgrid propagation.** Components with both Content and Viewport sub-components (e.g., SearchList) propagate the subgrid in their Content element when inside a Column context.
138
-
139
- ## Implemented Solution: Column.Content as subgrid
140
-
141
- ### Mechanism
24
+ Sets the 3-column grid and both CSS variables. All `withColumn` utilities are no-ops outside this context.
142
25
 
143
- `Column.Content` uses `grid-cols-subgrid` to inherit `Column.Root`'s 3-column grid. Non-scrolling children default to the center column; ScrollArea children span all 3 columns.
144
-
145
- Direct children of `Column.Root` participate in the grid in one of three ways:
146
-
147
- - **Column.Row** — 3-col subgrid row (icons in gutters, content in center).
148
- - **Column.Content** — multi-row subgrid; children default to center column, ScrollArea spans full width.
149
- - **Column.Viewport** — full-width scrollable area (delegates gutters to ScrollArea).
26
+ ### Column.Center
150
27
 
151
28
  ```css
152
- /* Column.Contentsubgrid that inherits Column.Root's 3-column grid */
153
- .column-content {
154
- col-span-full;
155
- display: grid;
156
- grid-template-columns: subgrid;
157
- min-height: 0; /* allow shrinking in flex/grid parents */
158
- > *:not(.dx-container) { col-start: 2 } /* non-ScrollArea children → center column */
159
- /* ScrollArea children span full width via [.dx-column_&]:col-span-full (existing) */
160
- }
29
+ /* column.tscolumnCenter */
30
+ [grid-column:var(--dx-col,auto)] min-h-0
161
31
  ```
162
32
 
163
- ### Why subgrid instead of padding
164
-
165
- An earlier approach used `px-[var(--gutter)]` padding on Column.Content with a `--gutter-offset`
166
- CSS variable for ScrollArea to break out via negative margins. This failed because:
167
-
168
- 1. **Height constraint required `overflow-hidden`** — needed for ScrollArea to get a bounded height.
169
- 2. **`overflow-hidden` clips negative margins** — ScrollArea couldn't break out horizontally.
170
- 3. **CSS doesn't allow mixed overflow** — `overflow-y: hidden` with `overflow-x: visible` isn't possible (browser converts visible to auto).
171
-
172
- Subgrid avoids all three issues: gutters come from grid columns (not padding), so there's nothing to break out of and no overflow conflict.
173
-
174
- ### Subgrid propagation pattern
33
+ Places a single element in col 2 (the center track). Does not use subgrid placement is explicit
34
+ on this element only, so arbitrary compound components (including `display: contents` wrappers) can
35
+ be nested safely.
175
36
 
176
- Components that have both a Content element and a ScrollArea-based Viewport must propagate
177
- the subgrid in their Content element when inside a Column context. This ensures the grid chain
178
- is maintained from Column.Root through intermediate components down to ScrollArea.Root.
37
+ ### Column.Bleed
179
38
 
180
39
  ```css
181
- /* Applied to SearchList.Content (and similar) when inside a Column context */
182
- [.dx-column_&]:col-span-full
183
- [.dx-column_&]:grid
184
- [.dx-column_&]:grid-cols-subgrid
185
- [.dx-column_&]:[&>:not(.dx-container)]:col-start-2
40
+ /* column.ts columnBleed */
41
+ col-span-full grid grid-cols-subgrid min-h-0
186
42
  ```
187
43
 
188
- Components using this pattern:
44
+ Spans all 3 columns and propagates the subgrid. Use for `ScrollArea`, full-width dividers, and
45
+ any content that should ignore the gutters.
189
46
 
190
- - **SearchList.Content** — propagates subgrid; SearchList.Viewport (ScrollArea) spans full width
47
+ ### Column.Row
191
48
 
192
- Outside a Column context, these remain normal flex containers.
193
-
194
- ### Example: CreateObjectDialog
195
-
196
- ```
197
- Dialog.Content (Column.Root, --gutter: var(--dx-gutter-sm), grid: 16px|1fr|16px)
198
- Dialog.Header (Column.Row, center)
199
- Dialog.Body → Column.Content (subgrid, children default to col-start-2)
200
- CreateObjectPanel:
201
- Path A: SearchList.Content (subgrid in column context)
202
- → SearchList.Input (col-start-2, in center — guttered ✓)
203
- → SearchList.Viewport (ScrollArea, col-span-full — full width ✓)
204
- → ScrollArea.Viewport (pl/pr with --gutter and scrollbar offset ✓)
205
- Path B: (same as A) ✓
206
- Path C: Form.Viewport (ScrollArea, col-span-full — full width ✓)
207
- → ScrollArea.Viewport (pl/pr with --gutter and scrollbar offset ✓)
208
- Path D: <plain text> — col-start-2 (center column, guttered ✓)
49
+ ```css
50
+ /* column.ts — columnRow */
51
+ col-span-3 grid grid-cols-subgrid
209
52
  ```
210
53
 
211
- ### Dialog sub-component mapping
212
-
213
- | Dialog sub-component | Column primitive | Gutter mechanism |
214
- | :------------------- | :--------------- | :--------------------------------------------- |
215
- | Dialog.Content | Column.Root | Establishes the 3-col grid and sets `--gutter` |
216
- | Dialog.Header | Column.Row | Gutters via grid columns (subgrid) |
217
- | Dialog.Body | Column.Content | Subgrid; children in center column |
218
- | Dialog.ActionBar | Column.Row | Gutters via grid columns (subgrid) |
54
+ Three-slot icon row. Children map to: `[col-1: icon/slot] [col-2: content] [col-3: icon/action]`.
55
+ Must be a direct child of `Column.Root`.
219
56
 
220
- ### AlertDialog unified with Dialog ✅
57
+ ## withColumn theme utilities
221
58
 
222
- AlertDialog now shares sub-components with Dialog:
59
+ Exported from `@dxos/ui-theme`. Components import and call these in their theme functions to
60
+ participate in the Column grid without importing Column React components.
223
61
 
224
- | Sub-component | Source | Notes |
225
- | :---------------- | :------------------------- | :------------------------------------------------------------- |
226
- | Header | **Dialog.Header** | Shared — was missing from AlertDialog |
227
- | Body | **Dialog.Body** | Shared — was Column.Viewport, now Column.Content |
228
- | ActionBar | **Dialog.ActionBar** | Shared — was duplicated, now shared |
229
- | CloseIconButton | **Dialog.CloseIconButton** | Shared — AlertDialog gains this |
230
- | Content | AlertDialog-specific | Uses AlertDialogPrimitive.Content; gutter normalized to `'sm'` |
231
- | Overlay | AlertDialog-specific | Uses AlertDialogPrimitive.Overlay |
232
- | Title/Description | AlertDialog-specific | Uses AlertDialogPrimitive.Title/Description |
233
- | Cancel/Action | AlertDialog-specific | Radix dismissal primitives |
62
+ ```ts
63
+ withColumn.center();
64
+ // '[grid-column:var(--dx-col,auto)]'
234
65
 
235
- ## Dialog Usage Audit
66
+ withColumn.propagate();
67
+ // → '[.dx-column_&]:col-span-full [.dx-column_&]:grid [.dx-column_&]:grid-cols-subgrid'
236
68
 
237
- Full audit of all Dialog/AlertDialog consumers, checking whether they use the standard
238
- `Dialog.Content > Dialog.Header > Dialog.Body > Dialog.ActionBar` structure.
239
-
240
- ### Correctly structured (uses Dialog.Body)
241
-
242
- | File | Type | Sub-components used | Body content |
243
- | :--------------------------------------------- | :----- | :------------------------------- | :---------------------------------- |
244
- | `devtools/.../DialogRestoreSpace.tsx` | Dialog | Content, Header, Body, ActionBar | Paragraph text + FileUploader |
245
- | `plugin-navtree/.../CommandsDialogContent.tsx` | Dialog | Content, Header, Body, ActionBar | SearchList with Viewport |
246
- | `plugin-space/.../CreateObjectDialog.tsx` | Dialog | Content, Header, Body | CreateObjectPanel (Form/SearchList) |
247
- | `shell/.../ConfirmReset.tsx` | Dialog | Body, ActionBar (step component) | Message, TextInput, checkboxes |
248
- | `react-ui/.../Dialog.stories.tsx` | Dialog | Content, Header, Body, ActionBar | ScrollArea with Input |
249
-
250
- ### Correctly structured (AlertDialog with Body)
251
-
252
- | File | Type | Sub-components used | Body content |
253
- | :----------------------------------------- | :---------- | :------------------------------ | :---------------------------- |
254
- | `plugin-client/.../RecoveryCodeDialog.tsx` | AlertDialog | Content, Body, Title, ActionBar | Checkboxes, code grid, inputs |
255
- | `composer-app/.../ResetDialog.tsx` | AlertDialog | Content, Body, Title, ActionBar | Error display, IconButtons |
256
- | `shell/.../JoinDialog.tsx` | AlertDialog | Content, Body, Cancel, Action | JoinPanel |
257
- | `shell/.../StatusDialog.tsx` | AlertDialog | Content, Body | StatusPanel |
258
- | `react-ui/.../AlertDialog.stories.tsx` | AlertDialog | Content, Body, Title, ActionBar | Title, Description |
259
-
260
- ### Missing Dialog.Body (should be added)
261
-
262
- | File | Type | What's used instead | Body content | Issue |
263
- | :------------------------------------------- | :----- | :----------------------- | :----------------------------- | :---------------------------------------------------- |
264
- | `plugin-script/.../DeploymentDialog.tsx` | Dialog | Custom flex divs | Text, list items, buttons | No Header, no Body, no gutter padding |
265
- | `plugin-search/.../SearchDialog.tsx` | Dialog | Content directly | SearchList with max-h overflow | No Header, no Body; SearchList has own scroll |
266
- | `plugin-help/.../ShortcutsDialogContent.tsx` | Dialog | Custom flex divs | ShortcutsList | No Header, no Body |
267
- | `plugin-space/.../CreateSpaceDialog.tsx` | Dialog | Form.Viewport in Content | Form fields | Has Header but no Body; Form.Viewport provides scroll |
268
- | `plugin-space/.../JoinDialog.tsx` | Dialog | Content directly | JoinPanel | No Header, no Body; panel manages layout |
269
- | `plugin-client/.../JoinDialog.tsx` | Dialog | Content directly | JoinPanel | No Body; panel manages layout |
270
- | `plugin-client/.../ResetDialog.tsx` | Dialog | Content directly | ConfirmReset step | No Body; step component has its own Body |
271
- | `shell/.../SpaceDialog.tsx` | Dialog | Content directly | SpacePanel | No Header, no Body; panel manages layout |
272
- | `shell/.../IdentityDialog.tsx` | Dialog | Content directly | IdentityPanel | No Header, no Body; panel manages layout |
273
- | `shell/.../run-shell.tsx` | Dialog | Content directly | Button (fallback) | No Header, no Body; minimal fallback UI |
274
-
275
- ### Custom layout (not standard Dialog)
276
-
277
- | File | Type | Notes |
278
- | :------------------------------------ | :----- | :-------------------------------------------------------- |
279
- | `react-ui-chat/.../ChatDialog.tsx` | Custom | Own Column-based grid layout with Header, Content, Footer |
280
- | `plugin-assistant/.../ChatDialog.tsx` | Custom | Uses ChatDialog from react-ui-chat |
281
-
282
- ### Observations
283
-
284
- 1. **Shell panel dialogs** (SpaceDialog, IdentityDialog, JoinDialog) all delegate layout to internal Panel components. These panels manage their own structure inside Dialog.Content, bypassing Dialog.Body/Header. This may be intentional (panels are reusable outside dialogs) but means they lack standard gutter alignment.
285
-
286
- 2. **Search-style dialogs** (SearchDialog, CommandsDialogContent) have full-bleed SearchList content. CommandsDialogContent correctly uses Dialog.Body; SearchDialog does not and handles its own max-height overflow.
287
-
288
- 3. **Form dialogs** (CreateSpaceDialog) use Form.Viewport directly in Dialog.Content, skipping Dialog.Body. This is safe because `--gutter-offset` is set by Column.Content (not Column.Root), so Form.Viewport's ScrollArea.Root sees `--gutter-offset` defaulting to `0px` and applies no negative margin. These dialogs should still be updated to use Dialog.Body for consistency, but they won't break.
289
-
290
- 4. **AlertDialog.Body uses Column.Viewport** (ScrollArea), while **Dialog.Body uses Column.Content** (non-scrolling). This inconsistency should be resolved — AlertDialog.Body should likely also use Column.Content so that child components can bring their own scroll.
291
-
292
- ## Completed Work
293
-
294
- ### Column.Content primitive ✅
295
-
296
- - New `Column.Content` component using CSS subgrid
297
- - `Column.Root` JSDoc updated to document three child types (Row, Content, Viewport)
298
- - `ColumnContentProps` exported from `@dxos/react-ui`
299
- - Column stories added (WithContent, ContentWithScrollArea)
300
-
301
- ### Dialog standardization ✅
302
-
303
- - `Dialog.Viewport` removed (no consumers)
304
- - `Dialog.Body` delegates to `Column.Content`
305
- - Dialog stories updated (DefaultStory, ScrollingStory)
306
- - All dialog stories use consistent `Root > Overlay > Content` wrapping (no Portal)
69
+ withColumn.consumed();
70
+ // '[--dx-col:auto]'
71
+ ```
307
72
 
308
- ### AlertDialog unified with Dialog ✅
73
+ | Utility | Purpose | Where used |
74
+ | :------------ | :-------------------------------------------------------------------------------- | :---------------------------------------------------------------------------- |
75
+ | `center()` | Place element in col 2 via `--dx-col`. No-op outside Column or inside ScrollArea. | Dialog.Header, Dialog.ActionBar, Form.Content, Form.Actions, SearchList.Input |
76
+ | `propagate()` | Extend Column subgrid to children. No-op outside Column. | Dialog.Body, SearchList.Content |
77
+ | `consumed()` | Reset `--dx-col` after `--gutter` is consumed. | ScrollArea.Viewport |
78
+
79
+ ## CSS custom property cascade
80
+
81
+ ```text
82
+ Column.Root
83
+ sets --gutter = var(--dx-gutter-<size>)
84
+ sets --dx-col = 2 / span 1
85
+
86
+ ├─ Column.Center → grid-column: var(--dx-col) ← consumes --dx-col
87
+ ├─ Column.Bleed → col-span-full, subgrid
88
+ ├─ Column.Row → col-span-3, subgrid
89
+
90
+ └─ withColumn.center() → grid-column: var(--dx-col) ← consumes --dx-col
91
+ withColumn.propagate() → col-span-full, grid, subgrid (inside .dx-column only)
92
+
93
+ └─ ScrollArea.Root → col-span-full (inside .dx-column only)
94
+ ScrollArea.Viewport
95
+ applies pl/pr using --gutter
96
+ withColumn.consumed() → sets --dx-col: auto
97
+
98
+ └─ (nested components no longer auto-position)
99
+ ```
309
100
 
310
- - AlertDialog shares Header, Body, ActionBar, CloseIconButton with Dialog
311
- - AlertDialog.Content normalized to `gutter='sm'`
312
- - AlertDialog.Body changed from Column.Viewport (scroll) to Column.Content (subgrid)
101
+ ## Component integration
313
102
 
314
- ### Consumer migrations ✅
103
+ ### Dialog
315
104
 
316
- All dialogs updated to standard `Dialog.Content > Dialog.Header > Dialog.Body` structure:
105
+ | Sub-component | withColumn applied | Effect |
106
+ | :----------------- | :---------------------------- | :---------------------------- |
107
+ | `Dialog.Content` | `Column.Root` (gutter `'sm'`) | Establishes the 3-col grid. |
108
+ | `Dialog.Header` | `withColumn.center()` | Placed in col 2. |
109
+ | `Dialog.Body` | `withColumn.propagate()` | Children inherit the subgrid. |
110
+ | `Dialog.ActionBar` | `withColumn.center()` | Placed in col 2. |
317
111
 
318
- 1. CreateSpaceDialog — wrapped Form.Root in Dialog.Body ✅
319
- 2. SearchDialog — added Header and Body ✅
320
- 3. ShortcutsDialogContent — replaced custom flex layout with Header and Body ✅
321
- 4. DeploymentDialog — restructured to use Header, Body, ActionBar ✅
322
- 5. SpaceDialog — wrapped SpacePanel in Dialog.Body ✅
323
- 6. IdentityDialog — wrapped IdentityPanel in Dialog.Body ✅
324
- 7. JoinDialog (plugin-space) — wrapped JoinPanel in Dialog.Body ✅
325
- 8. JoinDialog (plugin-client) — wrapped JoinPanel in Dialog.Body ✅
326
- 9. plugin-client ResetDialog — already correct (ConfirmReset uses Dialog.Body internally) ✅
112
+ ### Form
327
113
 
328
- ### SearchList subgrid propagation
114
+ | Sub-component | withColumn applied | Effect |
115
+ | :------------- | :-------------------- | :---------------------------------- |
116
+ | `Form.Content` | `withColumn.center()` | Placed in col 2 when inside Column. |
117
+ | `Form.Actions` | `withColumn.center()` | Placed in col 2 when inside Column. |
329
118
 
330
- - SearchList.Content propagates subgrid when inside a Column context
331
- - SearchList.Viewport now passes `padding` for gutter alignment
119
+ ### SearchList
332
120
 
333
- ## Remaining Work
121
+ | Sub-component | withColumn applied | Effect |
122
+ | :------------------------- | :----------------------- | :---------------------------------------------- |
123
+ | `SearchList.Content` | `withColumn.propagate()` | Extends subgrid to children when inside Column. |
124
+ | `SearchList.Input` wrapper | `withColumn.center()` | Input row placed in col 2. |
334
125
 
335
- ### Storybook verification
126
+ ### Card
336
127
 
337
- Visually verify all migrated dialogs in storybook:
128
+ `Card.Row` uses its own inline subgrid CSS (`col-span-3 grid grid-cols-subgrid`) and does not
129
+ participate in an outer Column grid. `Card.Root` establishes a separate 3-column grid for its
130
+ own icon-slot layout.
338
131
 
339
- - Gutter alignment for non-scrolling content in Dialog.Body
340
- - ScrollArea full width with correct gutter padding on Viewport
341
- - Height constraint and scrolling behavior
342
- - AlertDialog stories with the aligned Body implementation
132
+ ## Subgrid chain integrity
343
133
 
344
- ### Form subgrid propagation
134
+ Every intermediate container between `Column.Root` and a `ScrollArea.Root` must propagate the
135
+ subgrid, otherwise `ScrollArea.Root`'s `[.dx-column_&]:col-span-full` selector will not match
136
+ and the scrollbar will not extend to the gutter.
345
137
 
346
- Form currently doesn't propagate the subgrid in Column context.
347
- If Form is used inside Dialog.Body, Form.Viewport (ScrollArea) needs to
348
- span full width. This may require the same subgrid propagation pattern
349
- applied to SearchList.Content.
138
+ Required chain:
350
139
 
351
- ### Card alignment
140
+ ```
141
+ Column.Root (.dx-column)
142
+ → withColumn.propagate() container (col-span-full, grid, grid-cols-subgrid)
143
+ → ScrollArea.Root (.dx-container, [.dx-column_&]:col-span-full)
144
+ → ScrollArea.Viewport (applies --gutter padding, resets --dx-col)
145
+ ```
352
146
 
353
- Card has no Body equivalent. Consider adding Card.Body using Column.Content
354
- for cards that need scrollable or guttered content areas.
147
+ If any intermediate element wraps the ScrollArea without propagating, use `Column.Bleed` or
148
+ apply `withColumn.propagate()` to that wrapper.