@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.
- package/dist/lib/browser/{chunk-OCVRIJCH.mjs → chunk-BDBC6H6V.mjs} +1 -1
- package/dist/lib/browser/{chunk-OCVRIJCH.mjs.map → chunk-BDBC6H6V.mjs.map} +2 -2
- package/dist/lib/browser/index.mjs +156 -156
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +2 -2
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/browser/translations.mjs +18 -0
- package/dist/lib/browser/translations.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-QUD5P3RU.mjs → chunk-3JSJK2ZY.mjs} +1 -1
- package/dist/lib/node-esm/{chunk-QUD5P3RU.mjs.map → chunk-3JSJK2ZY.mjs.map} +2 -2
- package/dist/lib/node-esm/index.mjs +156 -156
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +2 -2
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/translations.mjs +20 -0
- package/dist/lib/node-esm/translations.mjs.map +7 -0
- package/dist/types/src/components/Avatars/Avatar.d.ts.map +1 -1
- package/dist/types/src/components/Avatars/Avatar.stories.d.ts.map +1 -1
- package/dist/types/src/components/Avatars/AvatarGroup.stories.d.ts.map +1 -1
- package/dist/types/src/components/Breadcrumb/Breadcrumb.d.ts.map +1 -1
- package/dist/types/src/components/Breadcrumb/Breadcrumb.stories.d.ts.map +1 -1
- package/dist/types/src/components/Button/Button.stories.d.ts +1 -1
- package/dist/types/src/components/Button/Button.stories.d.ts.map +1 -1
- package/dist/types/src/components/Button/IconButton.d.ts +1 -0
- package/dist/types/src/components/Button/IconButton.d.ts.map +1 -1
- package/dist/types/src/components/Button/IconButton.stories.d.ts.map +1 -1
- package/dist/types/src/components/Button/Toggle.stories.d.ts.map +1 -1
- package/dist/types/src/components/Button/ToggleGroup.d.ts +2 -2
- package/dist/types/src/components/Button/ToggleGroup.stories.d.ts +2 -2
- package/dist/types/src/components/Button/ToggleGroup.stories.d.ts.map +1 -1
- package/dist/types/src/components/Card/Card.d.ts +21 -12
- package/dist/types/src/components/Card/Card.d.ts.map +1 -1
- package/dist/types/src/components/Card/Card.stories.d.ts.map +1 -1
- package/dist/types/src/components/Clipboard/ClipboardProvider.d.ts.map +1 -1
- package/dist/types/src/components/Clipboard/CopyButton.d.ts.map +1 -1
- package/dist/types/src/components/Clipboard/index.d.ts +1 -1
- package/dist/types/src/components/Clipboard/index.d.ts.map +1 -1
- package/dist/types/src/components/DensityProvider/DensityProvider.d.ts.map +1 -1
- package/dist/types/src/components/Dialog/AlertDialog.d.ts +21 -19
- package/dist/types/src/components/Dialog/AlertDialog.d.ts.map +1 -1
- package/dist/types/src/components/Dialog/AlertDialog.stories.d.ts.map +1 -1
- package/dist/types/src/components/Dialog/Dialog.d.ts +22 -20
- package/dist/types/src/components/Dialog/Dialog.d.ts.map +1 -1
- package/dist/types/src/components/Dialog/Dialog.stories.d.ts.map +1 -1
- package/dist/types/src/components/ElevationProvider/ElevationProvider.d.ts.map +1 -1
- package/dist/types/src/components/ErrorFallback/ErrorFallback.d.ts.map +1 -1
- package/dist/types/src/components/ErrorFallback/ErrorFallback.stories.d.ts.map +1 -1
- package/dist/types/src/components/ErrorFallback/ErrorStack.d.ts.map +1 -1
- package/dist/types/src/components/ErrorFallback/ThrowError.d.ts.map +1 -1
- package/dist/types/src/components/Focus/Focus.d.ts +2 -2
- package/dist/types/src/components/Focus/Focus.stories.d.ts.map +1 -1
- package/dist/types/src/components/Icon/Icon.stories.d.ts +1 -1
- package/dist/types/src/components/Icon/Icon.stories.d.ts.map +1 -1
- package/dist/types/src/components/Image/Image.d.ts +2 -1
- package/dist/types/src/components/Image/Image.d.ts.map +1 -1
- package/dist/types/src/components/Image/Image.stories.d.ts +3 -2
- package/dist/types/src/components/Image/Image.stories.d.ts.map +1 -1
- package/dist/types/src/components/Input/Input.d.ts +12 -15
- package/dist/types/src/components/Input/Input.d.ts.map +1 -1
- package/dist/types/src/components/Input/Input.stories.d.ts.map +1 -1
- package/dist/types/src/components/Link/Link.stories.d.ts.map +1 -1
- package/dist/types/src/components/List/List.d.ts +2 -2
- package/dist/types/src/components/List/List.stories.d.ts +1 -1
- package/dist/types/src/components/List/List.stories.d.ts.map +1 -1
- package/dist/types/src/components/List/ListDropIndicator.d.ts.map +1 -1
- package/dist/types/src/components/List/Tree.d.ts +2 -2
- package/dist/types/src/components/List/Tree.d.ts.map +1 -1
- package/dist/types/src/components/List/Tree.stories.d.ts.map +1 -1
- package/dist/types/src/components/List/TreeDropIndicator.d.ts.map +1 -1
- package/dist/types/src/components/List/Treegrid.d.ts +1 -1
- package/dist/types/src/components/List/Treegrid.d.ts.map +1 -1
- package/dist/types/src/components/List/Treegrid.stories.d.ts.map +1 -1
- package/dist/types/src/components/Main/Main.d.ts +7 -3
- package/dist/types/src/components/Main/Main.d.ts.map +1 -1
- package/dist/types/src/components/Main/Main.stories.d.ts.map +1 -1
- package/dist/types/src/components/Main/useSwipeToDismiss.d.ts.map +1 -1
- package/dist/types/src/components/Menu/ContextMenu.d.ts.map +1 -1
- package/dist/types/src/components/Menu/ContextMenu.stories.d.ts.map +1 -1
- package/dist/types/src/components/Menu/DropdownMenu.d.ts +11 -3
- package/dist/types/src/components/Menu/DropdownMenu.d.ts.map +1 -1
- package/dist/types/src/components/Menu/DropdownMenu.stories.d.ts.map +1 -1
- package/dist/types/src/components/Message/Message.d.ts +1 -1
- package/dist/types/src/components/Message/Message.d.ts.map +1 -1
- package/dist/types/src/components/Message/Message.stories.d.ts.map +1 -1
- package/dist/types/src/components/Popover/Popover.d.ts +10 -2
- package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
- package/dist/types/src/components/Popover/Popover.stories.d.ts.map +1 -1
- package/dist/types/src/components/ScrollArea/ScrollArea.d.ts +2 -2
- package/dist/types/src/components/ScrollArea/ScrollArea.d.ts.map +1 -1
- package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts +2 -2
- package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts.map +1 -1
- package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts +11 -3
- package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts.map +1 -1
- package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts.map +1 -1
- package/dist/types/src/components/Select/Select.d.ts.map +1 -1
- package/dist/types/src/components/Select/Select.stories.d.ts.map +1 -1
- package/dist/types/src/components/Skeleton/Skeleton.stories.d.ts.map +1 -1
- package/dist/types/src/components/Splitter/Splitter.d.ts +3 -3
- package/dist/types/src/components/Splitter/Splitter.stories.d.ts.map +1 -1
- package/dist/types/src/components/Status/Status.stories.d.ts.map +1 -1
- package/dist/types/src/components/Tag/Tag.stories.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/ThemeProvider.stories.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts +54 -55
- package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/index.d.ts +1 -1
- package/dist/types/src/components/ThemeProvider/index.d.ts.map +1 -1
- package/dist/types/src/components/Toast/Toast.d.ts +4 -4
- package/dist/types/src/components/Toast/Toast.d.ts.map +1 -1
- package/dist/types/src/components/Toast/Toast.stories.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +5 -5
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
- package/dist/types/src/components/Tooltip/Tooltip.d.ts +2 -2
- package/dist/types/src/components/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts.map +1 -1
- package/dist/types/src/exemplars/generics.stories.d.ts +1 -1
- package/dist/types/src/exemplars/generics.stories.d.ts.map +1 -1
- package/dist/types/src/exemplars/slot.stories.d.ts.map +1 -1
- package/dist/types/src/exemplars/tabster.stories.d.ts.map +1 -1
- package/dist/types/src/exemplars/virtualizer.stories.d.ts.map +1 -1
- package/dist/types/src/hooks/useDensityContext.d.ts.map +1 -1
- package/dist/types/src/hooks/useElevationContext.d.ts.map +1 -1
- package/dist/types/src/hooks/useIconHref.d.ts.map +1 -1
- package/dist/types/src/hooks/useSafeArea.d.ts.map +1 -1
- package/dist/types/src/hooks/useSafeCollisionPadding.d.ts.map +1 -1
- package/dist/types/src/hooks/useVisualViewport.d.ts.map +1 -1
- package/dist/types/src/playground/Controls.stories.d.ts.map +1 -1
- package/dist/types/src/playground/Custom.stories.d.ts +1 -1
- package/dist/types/src/playground/Custom.stories.d.ts.map +1 -1
- package/dist/types/src/playground/Typography.stories.d.ts.map +1 -1
- package/dist/types/src/primitives/Column/Column.d.ts +11 -13
- package/dist/types/src/primitives/Column/Column.d.ts.map +1 -1
- package/dist/types/src/primitives/Column/Column.stories.d.ts +7 -7
- package/dist/types/src/primitives/Column/Column.stories.d.ts.map +1 -1
- package/dist/types/src/primitives/Container/Container.d.ts +1 -1
- package/dist/types/src/primitives/Container/Container.stories.d.ts.map +1 -1
- package/dist/types/src/primitives/Flex/Flex.d.ts +1 -1
- package/dist/types/src/primitives/Flex/Flex.stories.d.ts.map +1 -1
- package/dist/types/src/primitives/Grid/Grid.d.ts +1 -1
- package/dist/types/src/primitives/Grid/Grid.stories.d.ts.map +1 -1
- package/dist/types/src/primitives/Panel/Panel.d.ts +4 -4
- package/dist/types/src/primitives/Panel/Panel.d.ts.map +1 -1
- package/dist/types/src/primitives/Panel/Panel.stories.d.ts.map +1 -1
- package/dist/types/src/testing/Loading.d.ts.map +1 -1
- package/dist/types/src/testing/decorators/withLayout.d.ts.map +1 -1
- package/dist/types/src/testing/decorators/withLayoutVariants.d.ts.map +1 -1
- package/dist/types/src/testing/decorators/withTheme.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +3 -3
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/util/usePx.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +26 -24
- package/src/components/Button/IconButton.tsx +3 -2
- package/src/components/Card/Card.tsx +20 -5
- package/src/components/Dialog/Dialog.stories.tsx +2 -2
- package/src/components/Dialog/Dialog.tsx +29 -29
- package/src/components/Image/Image.tsx +31 -8
- package/src/components/Input/Input.tsx +3 -3
- package/src/components/Message/Message.stories.tsx +1 -1
- package/src/components/Message/Message.tsx +24 -7
- package/src/components/ThemeProvider/index.ts +1 -1
- package/src/components/Toolbar/Toolbar.tsx +2 -1
- package/src/primitives/Column/AUDIT.md +105 -311
- package/src/primitives/Column/Column.stories.tsx +58 -60
- package/src/primitives/Column/Column.tsx +54 -58
- package/src/testing/decorators/withLayout.tsx +1 -1
|
@@ -1,354 +1,148 @@
|
|
|
1
|
-
# Column
|
|
1
|
+
# Column architecture reference
|
|
2
2
|
|
|
3
3
|
## Background
|
|
4
4
|
|
|
5
|
-
|
|
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
|
-
`
|
|
8
|
-
|
|
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
|
-
##
|
|
11
|
+
## Column primitives
|
|
13
12
|
|
|
14
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
/*
|
|
153
|
-
|
|
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.ts — columnCenter */
|
|
30
|
+
[grid-column:var(--dx-col,auto)] min-h-0
|
|
161
31
|
```
|
|
162
32
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
|
|
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
|
-
/*
|
|
182
|
-
|
|
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
|
-
|
|
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
|
-
|
|
47
|
+
### Column.Row
|
|
191
48
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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
|
-
|
|
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
|
-
|
|
57
|
+
## withColumn theme utilities
|
|
221
58
|
|
|
222
|
-
|
|
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
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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
|
-
|
|
66
|
+
withColumn.propagate();
|
|
67
|
+
// → '[.dx-column_&]:col-span-full [.dx-column_&]:grid [.dx-column_&]:grid-cols-subgrid'
|
|
236
68
|
|
|
237
|
-
|
|
238
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
103
|
+
### Dialog
|
|
315
104
|
|
|
316
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
331
|
-
- SearchList.Viewport now passes `padding` for gutter alignment
|
|
119
|
+
### SearchList
|
|
332
120
|
|
|
333
|
-
|
|
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
|
-
###
|
|
126
|
+
### Card
|
|
336
127
|
|
|
337
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
354
|
-
|
|
147
|
+
If any intermediate element wraps the ScrollArea without propagating, use `Column.Bleed` or
|
|
148
|
+
apply `withColumn.propagate()` to that wrapper.
|