@databricks/design-system 2.0.6 → 2.0.7
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/AGENTS.md +239 -166
- package/CHANGELOG.md +28 -0
- package/dist/{RHFControlledTypeaheadComboboxV2-Ct9x3rC1.js → RHFControlledTypeaheadComboboxV2-nSSYj16I.js} +3 -3
- package/dist/{RHFControlledTypeaheadComboboxV2-Ct9x3rC1.js.map → RHFControlledTypeaheadComboboxV2-nSSYj16I.js.map} +1 -1
- package/dist/{WizardStepContentWrapper-6YTjeEaA.js → WizardStepContentWrapper-bbh_CoIf.js} +195 -257
- package/dist/WizardStepContentWrapper-bbh_CoIf.js.map +1 -0
- package/dist/dubois-colors.less +1 -1
- package/dist/icon-metadata.json +5 -0
- package/dist/{index-DiRpSwH2.js → index-CUCuUviS.js} +119 -109
- package/dist/index-CUCuUviS.js.map +1 -0
- package/dist/index-dark.css +135 -1
- package/dist/index-dark.mitigated.css +163 -16
- package/dist/index.css +182 -28
- package/dist/index.js +2 -2
- package/dist/index.mitigated.css +210 -43
- package/dist/patterns.js +1 -1
- package/dist-types/design-system/Alert/Alert.d.ts +21 -4
- package/dist-types/design-system/Button/Button.d.ts +2 -1
- package/dist-types/design-system/Icon/__generated/icons/SlidesIcon.d.ts +4 -0
- package/dist-types/design-system/Icon/__generated/icons/index.d.ts +1 -0
- package/dist-types/design-system/TypeaheadCombobox/TypeaheadComboboxControls.d.ts +0 -2
- package/dist-types/design-system/index.d.ts +0 -1
- package/dist-types/design-system/utils/safex.d.ts +4 -2
- package/dist-types/theme/generalVariables.d.ts +0 -1
- package/package.json +5 -4
- package/setup.mjs +586 -0
- package/dist/WizardStepContentWrapper-6YTjeEaA.js.map +0 -1
- package/dist/index-DiRpSwH2.js.map +0 -1
- package/dist-types/design-system/LegacyTooltip/LegacyTooltip.d.ts +0 -47
- package/dist-types/design-system/LegacyTooltip/index.d.ts +0 -1
package/AGENTS.md
CHANGED
|
@@ -1,16 +1,39 @@
|
|
|
1
1
|
# Using Du Bois (`@databricks/design-system`)
|
|
2
2
|
|
|
3
|
-
Du Bois is Databricks' React component library. This file is guidance for coding agents
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Du Bois is Databricks' React component library. This file is guidance for coding agents building UI
|
|
4
|
+
with it. Everything it describes is available from the published package; all components are named
|
|
5
|
+
exports from `@databricks/design-system`.
|
|
6
6
|
|
|
7
7
|
## If you remember only four things
|
|
8
8
|
|
|
9
9
|
1. **Use an existing component** — don't hand-build a widget the library already has.
|
|
10
|
-
2. **Prefer the composite** — `InfoTooltip`, `DangerModal`, `DropdownMenu`, not primitives glued
|
|
10
|
+
2. **Prefer the composite** — `InfoTooltip`, `DangerModal`, `DropdownMenu`, not primitives glued
|
|
11
|
+
together.
|
|
11
12
|
3. **Always pass `componentId`** — stable, dotted, no PII.
|
|
12
13
|
4. **Never hardcode colors or spacing** — read `theme.*` tokens.
|
|
13
14
|
|
|
15
|
+
## Step-by-step workflows
|
|
16
|
+
|
|
17
|
+
This package ships task-oriented workflows under
|
|
18
|
+
`node_modules/@databricks/design-system/design-guidance/`. Point your coding agent at the relevant
|
|
19
|
+
file when you want a repeatable procedure rather than the quick reference below. Start from
|
|
20
|
+
`design-guidance/docs/README.md`, then open the workflow for your task:
|
|
21
|
+
|
|
22
|
+
| Task | Workflow |
|
|
23
|
+
|------------------------------|-----------------------------------|
|
|
24
|
+
| Select a component | `skills/dbui-pick-component.md` |
|
|
25
|
+
| Select an icon | `skills/dbui-pick-icon.md` |
|
|
26
|
+
| Implement a screen | `skills/dbui-build-screen.md` |
|
|
27
|
+
| Check an implementation | `skills/dbui-validate.md` |
|
|
28
|
+
| Review a design (all checks) | `skills/dbui-review.md` |
|
|
29
|
+
| Review copy / voice | `skills/dbui-check-voice.md` |
|
|
30
|
+
| Review UX behavior | `skills/dbui-check-guidelines.md` |
|
|
31
|
+
| Review design intent | `skills/dbui-check-principles.md` |
|
|
32
|
+
| Review platform fit | `skills/dbui-check-ecosystem.md` |
|
|
33
|
+
|
|
34
|
+
Reference docs sit alongside them: `docs/tokens.md` (finding theme tokens as a consumer),
|
|
35
|
+
`docs/voice.md` (product copy), and `docs/review-contract.md`.
|
|
36
|
+
|
|
14
37
|
## Setup
|
|
15
38
|
|
|
16
39
|
Install the package and its peer dependencies:
|
|
@@ -19,8 +42,8 @@ Install the package and its peer dependencies:
|
|
|
19
42
|
npm install @databricks/design-system @emotion/react react react-dom moment
|
|
20
43
|
```
|
|
21
44
|
|
|
22
|
-
`moment` is required by the date components. `@jest/globals` is an additional peer dependency
|
|
23
|
-
|
|
45
|
+
`moment` is required by the date components. `@jest/globals` is an additional peer dependency if you
|
|
46
|
+
use the `test-utils` entry point.
|
|
24
47
|
|
|
25
48
|
Import the stylesheet once at your app's entry point, wrap the tree in
|
|
26
49
|
`DesignSystemProvider`, and render `ApplyGlobalStyles` inside it:
|
|
@@ -29,27 +52,55 @@ Import the stylesheet once at your app's entry point, wrap the tree in
|
|
|
29
52
|
import '@databricks/design-system/index.css';
|
|
30
53
|
import '@databricks/design-system/fonts/dm-sans.css';
|
|
31
54
|
|
|
32
|
-
import {
|
|
55
|
+
import {ApplyGlobalStyles, DesignSystemProvider} from '@databricks/design-system';
|
|
33
56
|
|
|
34
57
|
export const App = () => (
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
58
|
+
<DesignSystemProvider>
|
|
59
|
+
<ApplyGlobalStyles/>
|
|
60
|
+
<YourApp/>
|
|
61
|
+
</DesignSystemProvider>
|
|
39
62
|
);
|
|
40
63
|
```
|
|
41
64
|
|
|
42
|
-
Without `DesignSystemProvider` the theme context is missing and `useDesignSystemTheme()`
|
|
43
|
-
|
|
44
|
-
`
|
|
65
|
+
Without `DesignSystemProvider` the theme context is missing and `useDesignSystemTheme()` throws.
|
|
66
|
+
|
|
67
|
+
`ApplyGlobalStyles` sets the body background and text color but **not** `font-family` (`Typography`
|
|
68
|
+
sets only color and size), so text falls back to the browser serif until you point `body` at the
|
|
69
|
+
`--db-font-family` token `index.css` defines (DM Sans; correct in both themes):
|
|
70
|
+
|
|
71
|
+
```css
|
|
72
|
+
body {
|
|
73
|
+
font-family: var(--db-font-family);
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
For dark mode, also import `@databricks/design-system/index-dark.css` and set `isDarkMode` on a
|
|
78
|
+
`DesignSystemThemeProvider` wrapping `DesignSystemProvider` — the provider has no `isDarkMode` prop
|
|
79
|
+
of its own (it reads theme context), so setting it there is a type error that stays light:
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import {
|
|
83
|
+
ApplyGlobalStyles,
|
|
84
|
+
DesignSystemProvider,
|
|
85
|
+
DesignSystemThemeProvider
|
|
86
|
+
} from '@databricks/design-system';
|
|
87
|
+
|
|
88
|
+
export const App = () => (
|
|
89
|
+
<DesignSystemThemeProvider isDarkMode>
|
|
90
|
+
<DesignSystemProvider>
|
|
91
|
+
<ApplyGlobalStyles/>
|
|
92
|
+
<YourApp/>
|
|
93
|
+
</DesignSystemProvider>
|
|
94
|
+
</DesignSystemThemeProvider>
|
|
95
|
+
);
|
|
96
|
+
```
|
|
45
97
|
|
|
46
98
|
Styling uses the Emotion `css` prop, so configure Emotion's JSX runtime — set
|
|
47
99
|
`jsxImportSource: '@emotion/react'` in your TypeScript or Babel config, or add
|
|
48
100
|
`/** @jsxImportSource @emotion/react */` per file.
|
|
49
101
|
|
|
50
102
|
The CSS entry points have no type declarations, so TypeScript rejects those side-effect imports
|
|
51
|
-
unless your project declares them. Add this once rather than suppressing the error at each
|
|
52
|
-
import:
|
|
103
|
+
unless your project declares them. Add this once rather than suppressing the error at each import:
|
|
53
104
|
|
|
54
105
|
```ts
|
|
55
106
|
// css.d.ts
|
|
@@ -61,19 +112,19 @@ declare module '*.css';
|
|
|
61
112
|
Read every design value off the theme.
|
|
62
113
|
|
|
63
114
|
```tsx
|
|
64
|
-
import {
|
|
115
|
+
import {useDesignSystemTheme} from '@databricks/design-system';
|
|
65
116
|
|
|
66
117
|
const MyPanel = () => {
|
|
67
|
-
const {
|
|
118
|
+
const {theme} = useDesignSystemTheme();
|
|
68
119
|
return (
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
120
|
+
<div
|
|
121
|
+
css={{
|
|
122
|
+
padding: theme.spacing.md, // 16 — never write 16
|
|
123
|
+
color: theme.colors.textPrimary,
|
|
124
|
+
backgroundColor: theme.colors.backgroundPrimary,
|
|
125
|
+
borderRadius: theme.borders.borderRadiusSm,
|
|
126
|
+
}}
|
|
127
|
+
/>
|
|
77
128
|
);
|
|
78
129
|
};
|
|
79
130
|
```
|
|
@@ -85,73 +136,93 @@ const MyPanel = () => {
|
|
|
85
136
|
- **Radius** — `theme.borders.borderRadius*`. **Shadows** — `theme.shadows.{xs,sm,md,lg,xl}`.
|
|
86
137
|
- **Motion** — `theme.animation.transitionDuration` (170ms).
|
|
87
138
|
|
|
88
|
-
Every semantic token has a correct dark-mode value, so using tokens is what makes dark mode
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
##
|
|
92
|
-
|
|
93
|
-
| Need
|
|
94
|
-
|
|
95
|
-
| Action / navigation
|
|
96
|
-
| Button + menu
|
|
97
|
-
|
|
|
98
|
-
| Text
|
|
99
|
-
|
|
|
100
|
-
|
|
|
101
|
-
|
|
|
102
|
-
|
|
|
103
|
-
|
|
|
104
|
-
|
|
|
105
|
-
|
|
|
106
|
-
|
|
|
107
|
-
|
|
|
108
|
-
|
|
|
109
|
-
|
|
|
110
|
-
|
|
|
111
|
-
|
|
|
112
|
-
|
|
|
113
|
-
|
|
|
114
|
-
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
139
|
+
Every semantic token has a correct dark-mode value, so using tokens is what makes dark mode work for
|
|
140
|
+
free.
|
|
141
|
+
|
|
142
|
+
## Available components
|
|
143
|
+
|
|
144
|
+
| Need | Use |
|
|
145
|
+
|-----------------------------------------|-----------------------------------------------------------------------------|
|
|
146
|
+
| Action / navigation | `Button` (with `type`, `danger`), `Typography.Link` for navigation |
|
|
147
|
+
| Button + menu | `SplitButton` (primary action + menu) or `DropdownMenu` |
|
|
148
|
+
| Grouped controls bar | `Toolbar` (buttons, toggles, and menus as one bar) |
|
|
149
|
+
| Text & headings | `Typography.Title` / `.Text` / `.Paragraph` / `.Link` / `.Hint` |
|
|
150
|
+
| Text input | `Input`, `Input.TextArea`, `Input.Password` |
|
|
151
|
+
| Boolean | `Checkbox` (multi-select / terms), `Switch` (instant setting toggle) |
|
|
152
|
+
| Toggle a view on/off | `ToggleButton` (binary filter with an immediately visible result) |
|
|
153
|
+
| One of a small set | `Radio.Group`, or `SimpleSelect` for a dropdown |
|
|
154
|
+
| One of a small set (rich cards) | `RadioTile` (option cards, inside a `Radio.Group`) |
|
|
155
|
+
| One of 4+ options | `Select` (dropdown built on `DialogCombobox`) |
|
|
156
|
+
| One of many / searchable | `DialogCombobox` (searchable list), `TypeaheadComboboxV2` (autocomplete) |
|
|
157
|
+
| Selectable option list (building block) | `Listbox` (optionally filterable) |
|
|
158
|
+
| Filter a list / switch related views | `SegmentedControl` (filter), `PillControl` (related page areas) |
|
|
159
|
+
| Value from a range | `Slider` (single, range, or stepped) |
|
|
160
|
+
| Date / time | `DatePicker` (single, range, optional time) |
|
|
161
|
+
| Container / summary | `Card` |
|
|
162
|
+
| Asset preview + actions | `PreviewCard` (image plus related actions) |
|
|
163
|
+
| User or entity avatar | `Avatar` |
|
|
164
|
+
| Label / category / status chip | `Tag` (colored, optionally closable) |
|
|
165
|
+
| Compute resource status | `ResourceStatusIndicator` |
|
|
166
|
+
| Progress of a task | `Progress` (determinate bar) |
|
|
167
|
+
| Multi-step task / wizard | `Stepper` |
|
|
168
|
+
| Sectioned content | `Tabs` |
|
|
169
|
+
| Dialog | `Modal`; `DangerModal` for destructive confirmation |
|
|
170
|
+
| Contextual help | `Tooltip` (wraps any control), `InfoTooltip` (info icon + tooltip) |
|
|
171
|
+
| Menu of actions | `DropdownMenu` |
|
|
172
|
+
| Inline message / callout | `Alert` (field/section); `Banner` for page-level with a CTA |
|
|
173
|
+
| Toast | `SnackBar` + `useSnackBar` |
|
|
174
|
+
| Passive in-app notification | `Notification` (upper-right, auto-dismiss; use `Alert` if action is needed) |
|
|
175
|
+
| Loading / empty | `Spinner`, `Skeleton` variants, `LoadingState`; `Empty` for no-data |
|
|
176
|
+
| Page layout | `PageWrapper`, `Header`, `Sidebar`, `Grid.Row` / `Grid.Col` |
|
|
177
|
+
| Breadcrumb trail | `Breadcrumb` |
|
|
178
|
+
| Routed nav tabs | `NavigationMenu` (wrap your router's `Link` in `NavigationMenu.Item`) |
|
|
179
|
+
| Pagination | `Pagination` (page-based or cursor-based) |
|
|
180
|
+
| Tabular data | `Table` + `TableRow` / `TableHeader` / `TableCell` |
|
|
181
|
+
| Nested hierarchy | `Tree` (navigable), `TreeGrid` (hierarchical rows with columns) |
|
|
182
|
+
| Collapse a long list of items | `Overflow` (shows a few, folds the rest into `+N`) |
|
|
183
|
+
| Form | `Form` + `FormUI.*`; `RHFControlledComponents.*` with React Hook Form |
|
|
184
|
+
| Icon | Any `<XxxIcon />` (standalone component) |
|
|
185
|
+
| Spacing between elements | `<Spacer size="…" />`, or `theme.spacing.*` in `css` |
|
|
186
|
+
|
|
187
|
+
The library has roughly 90 components. For anything not listed, check the bundled type declarations
|
|
188
|
+
(`dist-types/index.d.ts`) before building something custom — the export list is the authoritative
|
|
189
|
+
catalog, and prop types are the authoritative API.
|
|
119
190
|
|
|
120
191
|
## Use the composite
|
|
121
192
|
|
|
122
|
-
When you are about to combine primitives, stop. A purpose-built composite usually exists and
|
|
123
|
-
|
|
193
|
+
When you are about to combine primitives, stop. A purpose-built composite usually exists and handles
|
|
194
|
+
state, accessibility, and theming for you.
|
|
124
195
|
|
|
125
|
-
| About to build…
|
|
126
|
-
|
|
127
|
-
| `Tooltip` wrapping an info icon
|
|
128
|
-
| `Modal` with a destructive confirm button
|
|
129
|
-
| `Button` + chevron + dropdown
|
|
130
|
-
| `Popover` + `<ul>`/`<li>` action list
|
|
131
|
-
| `Input` + autocomplete list
|
|
132
|
-
| `Input` + selectable dropdown
|
|
133
|
-
| Manually managed open/close for a section
|
|
134
|
-
| A row of buttons acting as a single choice | `SegmentedControlGroup`
|
|
196
|
+
| About to build… | Use instead |
|
|
197
|
+
|--------------------------------------------|------------------------------------|
|
|
198
|
+
| `Tooltip` wrapping an info icon | `InfoTooltip` |
|
|
199
|
+
| `Modal` with a destructive confirm button | `DangerModal` |
|
|
200
|
+
| `Button` + chevron + dropdown | `SplitButton` or `DropdownMenu` |
|
|
201
|
+
| `Popover` + `<ul>`/`<li>` action list | `DropdownMenu` |
|
|
202
|
+
| `Input` + autocomplete list | `TypeaheadComboboxV2` |
|
|
203
|
+
| `Input` + selectable dropdown | `DialogCombobox` or `SimpleSelect` |
|
|
204
|
+
| Manually managed open/close for a section | `Accordion` |
|
|
205
|
+
| A row of buttons acting as a single choice | `SegmentedControlGroup` |
|
|
135
206
|
|
|
136
207
|
### Picking an overlay
|
|
137
208
|
|
|
138
|
-
| Trigger / intent
|
|
139
|
-
|
|
140
|
-
| Short label on hover/focus
|
|
141
|
-
| Info icon + its tooltip
|
|
142
|
-
| Info icon + rich clickable content | `InfoPopover`
|
|
143
|
-
| Click for custom transient content | `Popover`
|
|
144
|
-
| Hover for a rich preview card
|
|
145
|
-
| A list of actions
|
|
146
|
-
| Blocking dialog
|
|
147
|
-
| Side panel
|
|
209
|
+
| Trigger / intent | Use |
|
|
210
|
+
|------------------------------------|----------------------------------------------------|
|
|
211
|
+
| Short label on hover/focus | `Tooltip` |
|
|
212
|
+
| Info icon + its tooltip | `InfoTooltip` |
|
|
213
|
+
| Info icon + rich clickable content | `InfoPopover` |
|
|
214
|
+
| Click for custom transient content | `Popover` |
|
|
215
|
+
| Hover for a rich preview card | `HoverCard` |
|
|
216
|
+
| A list of actions | `DropdownMenu` (or `ContextMenu` on right-click) |
|
|
217
|
+
| Blocking dialog | `Modal` / `DangerModal` |
|
|
218
|
+
| Side panel | `Drawer` (`Drawer.Root` / `.Trigger` / `.Content`) |
|
|
148
219
|
|
|
149
220
|
## Common components
|
|
150
221
|
|
|
151
222
|
### Button
|
|
152
223
|
|
|
153
|
-
`
|
|
154
|
-
`
|
|
224
|
+
`type` is `primary | tertiary | link` (omit for the default); `danger` for destructive;
|
|
225
|
+
`size="small"` for compact.
|
|
155
226
|
|
|
156
227
|
```tsx
|
|
157
228
|
<Button componentId="settings.save" type="primary" onClick={handleSave}>
|
|
@@ -159,13 +230,13 @@ handles state, accessibility, and theming for you.
|
|
|
159
230
|
</Button>
|
|
160
231
|
|
|
161
232
|
// Icon-only buttons must carry an accessible label.
|
|
162
|
-
<Button componentId="row.delete" icon={<TrashIcon
|
|
233
|
+
<Button componentId="row.delete" icon={<TrashIcon/>} aria-label="Delete row" danger/>
|
|
163
234
|
```
|
|
164
235
|
|
|
165
236
|
### Typography
|
|
166
237
|
|
|
167
|
-
Never render bare `<h1>`–`<h4>`, `<p>`, or `<a>` for content, so that sizing, color tokens, and
|
|
168
|
-
|
|
238
|
+
Never render bare `<h1>`–`<h4>`, `<p>`, or `<a>` for content, so that sizing, color tokens, and link
|
|
239
|
+
behavior come from the system.
|
|
169
240
|
|
|
170
241
|
```tsx
|
|
171
242
|
<Typography.Title level={2}>Section title</Typography.Title>
|
|
@@ -182,14 +253,15 @@ Give every input a real label, not a `placeholder` alone. Use `validationState`
|
|
|
182
253
|
|
|
183
254
|
```tsx
|
|
184
255
|
<FormUI.Label htmlFor="email">Email</FormUI.Label>
|
|
185
|
-
<Input id="email" componentId="signup.email" type="email"
|
|
186
|
-
<FormUI.Message message="Enter a valid email" type="error"
|
|
256
|
+
<Input id="email" componentId="signup.email" type="email"/>
|
|
257
|
+
<FormUI.Message message="Enter a valid email" type="error"/>
|
|
187
258
|
|
|
188
259
|
<Checkbox componentId="terms.accept" isChecked={agreed} onChange={setAgreed}>
|
|
189
260
|
I agree to the terms
|
|
190
261
|
</Checkbox>
|
|
191
262
|
|
|
192
|
-
<Switch componentId="settings.notifications" checked={enabled} onChange={setEnabled}
|
|
263
|
+
<Switch componentId="settings.notifications" checked={enabled} onChange={setEnabled}
|
|
264
|
+
label="Email notifications"/>
|
|
193
265
|
|
|
194
266
|
<SimpleSelect componentId="chart.type" value={type} onChange={setType} placeholder="Chart type">
|
|
195
267
|
<SimpleSelectOption value="bar">Bar</SimpleSelectOption>
|
|
@@ -200,15 +272,15 @@ Give every input a real label, not a `placeholder` alone. Use `validationState`
|
|
|
200
272
|
With React Hook Form, use `RHFControlledComponents.*` — each takes `name` + `control` + `rules`
|
|
201
273
|
plus the underlying component's props. Available: `Input`, `PasswordInput`, `TextArea`,
|
|
202
274
|
`Select`, `Checkbox`, `CheckboxGroup`, `Radio`, `RadioGroup`, `Switch`, `DialogCombobox`,
|
|
203
|
-
`
|
|
275
|
+
`TypeaheadComboboxV2`, `MultiSelectTypeaheadComboboxV2`.
|
|
204
276
|
|
|
205
277
|
```tsx
|
|
206
278
|
<Form componentId="signup.form" onSubmit={handleSubmit(onSubmit)}>
|
|
207
279
|
<RHFControlledComponents.Input
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
280
|
+
name="email"
|
|
281
|
+
control={control}
|
|
282
|
+
componentId="signup.email"
|
|
283
|
+
rules={{required: 'Email is required'}}
|
|
212
284
|
/>
|
|
213
285
|
<Button componentId="signup.submit" htmlType="submit" type="primary">
|
|
214
286
|
Sign up
|
|
@@ -223,12 +295,12 @@ restyling a `Modal`. Both need a `title` for their accessible name.
|
|
|
223
295
|
|
|
224
296
|
```tsx
|
|
225
297
|
<DangerModal
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
298
|
+
componentId="delete.modal"
|
|
299
|
+
visible={open}
|
|
300
|
+
title="Delete project"
|
|
301
|
+
okText="Delete"
|
|
302
|
+
onOk={handleDelete}
|
|
303
|
+
onCancel={close}
|
|
232
304
|
>
|
|
233
305
|
This permanently deletes all project data.
|
|
234
306
|
</DangerModal>
|
|
@@ -243,11 +315,11 @@ Compound API: `Root` / `Trigger` (use `asChild` to wrap your own `Button`) / `Co
|
|
|
243
315
|
```tsx
|
|
244
316
|
<DropdownMenu.Root>
|
|
245
317
|
<DropdownMenu.Trigger asChild>
|
|
246
|
-
<Button componentId="row.menu" icon={<OverflowIcon
|
|
318
|
+
<Button componentId="row.menu" icon={<OverflowIcon/>} aria-label="More actions"/>
|
|
247
319
|
</DropdownMenu.Trigger>
|
|
248
320
|
<DropdownMenu.Content>
|
|
249
321
|
<DropdownMenu.Item componentId="row.edit" onClick={edit}>Edit</DropdownMenu.Item>
|
|
250
|
-
<DropdownMenu.Separator
|
|
322
|
+
<DropdownMenu.Separator/>
|
|
251
323
|
<DropdownMenu.Item componentId="row.delete" onClick={remove}>Delete</DropdownMenu.Item>
|
|
252
324
|
</DropdownMenu.Content>
|
|
253
325
|
</DropdownMenu.Root>
|
|
@@ -255,33 +327,31 @@ Compound API: `Root` / `Trigger` (use `asChild` to wrap your own `Button`) / `Co
|
|
|
255
327
|
|
|
256
328
|
### Tooltip and InfoTooltip
|
|
257
329
|
|
|
258
|
-
`Tooltip` wraps a control and describes it. For a standalone info affordance next to a label,
|
|
259
|
-
|
|
330
|
+
`Tooltip` wraps a control and describes it. For a standalone info affordance next to a label, use
|
|
331
|
+
`InfoTooltip` — it bundles the icon, the tooltip, accessibility, and theming. Never compose
|
|
260
332
|
`Tooltip` around an `InfoIcon` yourself.
|
|
261
333
|
|
|
262
|
-
Both take a required `componentId`.
|
|
263
|
-
|
|
264
334
|
```tsx
|
|
265
335
|
// Incorrect — hand-rolled info affordance
|
|
266
|
-
<Tooltip componentId="search.info" content="Searches project names only."><InfoIcon
|
|
336
|
+
<Tooltip componentId="search.info" content="Searches project names only."><InfoIcon/></Tooltip>
|
|
267
337
|
|
|
268
338
|
// Correct
|
|
269
339
|
<FormUI.Label htmlFor="search">
|
|
270
|
-
Search <InfoTooltip componentId="search.info" content="Searches project names only."
|
|
340
|
+
Search <InfoTooltip componentId="search.info" content="Searches project names only."/>
|
|
271
341
|
</FormUI.Label>
|
|
272
342
|
|
|
273
343
|
// Tooltip is for describing a control you already have
|
|
274
344
|
<Tooltip componentId="refresh.tooltip" content="Refresh data">
|
|
275
|
-
<Button componentId="refresh" icon={<RefreshIcon
|
|
345
|
+
<Button componentId="refresh" icon={<RefreshIcon/>} aria-label="Refresh"/>
|
|
276
346
|
</Tooltip>
|
|
277
347
|
```
|
|
278
348
|
|
|
279
349
|
### Table
|
|
280
350
|
|
|
281
351
|
Compose `Table` from the flat exports `TableRow`, `TableHeader`, and `TableCell`. These are
|
|
282
|
-
individual named exports, not a namespace — there is no `TableUI.*`, and no separate head or
|
|
283
|
-
|
|
284
|
-
`componentId`.
|
|
352
|
+
individual named exports, not a namespace — there is no `TableUI.*`, and no separate head or body
|
|
353
|
+
wrapper. Mark the header row with `isHeader`, and give each `TableHeader` a
|
|
354
|
+
`componentId`.
|
|
285
355
|
|
|
286
356
|
```tsx
|
|
287
357
|
<Table>
|
|
@@ -290,10 +360,10 @@ body wrapper. Mark the header row with `isHeader`, and give each `TableHeader` a
|
|
|
290
360
|
<TableHeader componentId="projects.header.status">Status</TableHeader>
|
|
291
361
|
</TableRow>
|
|
292
362
|
{rows.map((row) => (
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
363
|
+
<TableRow key={row.id}>
|
|
364
|
+
<TableCell>{row.name}</TableCell>
|
|
365
|
+
<TableCell>{row.status}</TableCell>
|
|
366
|
+
</TableRow>
|
|
297
367
|
))}
|
|
298
368
|
</Table>
|
|
299
369
|
```
|
|
@@ -303,8 +373,8 @@ Related exports for richer tables: `TableRowAction`, `TableRowActionHeader`,
|
|
|
303
373
|
|
|
304
374
|
### Icons
|
|
305
375
|
|
|
306
|
-
Icons are standalone components — `<PlusIcon />`, `<TrashIcon />`. They take no `componentId`.
|
|
307
|
-
|
|
376
|
+
Icons are standalone components — `<PlusIcon />`, `<TrashIcon />`. They take no `componentId`. Never
|
|
377
|
+
use the legacy `<Icon component={PlusIcon} />` form, and import icons only from
|
|
308
378
|
`@databricks/design-system`.
|
|
309
379
|
|
|
310
380
|
### Loading and empty states
|
|
@@ -314,36 +384,40 @@ where the content shape is known, is the single most common way agent-written Du
|
|
|
314
384
|
unfinished.
|
|
315
385
|
|
|
316
386
|
- `Skeleton` variants (`TitleSkeleton`, `ParagraphSkeleton`, `TableSkeleton`,
|
|
317
|
-
`GenericSkeleton`) — use one shaped like the content it replaces, so there is no layout jump
|
|
318
|
-
|
|
387
|
+
`GenericSkeleton`) — use one shaped like the content it replaces, so there is no layout jump when
|
|
388
|
+
data arrives. This is the default choice for a loading branch.
|
|
319
389
|
- `Spinner` — only when the content shape is unknown. Pass `label` for its accessible name.
|
|
320
390
|
- `Empty` — needs `title` and `description`; add a `button` for the next step.
|
|
321
391
|
|
|
322
392
|
```tsx
|
|
323
393
|
// Incorrect — hand-rolled loading text
|
|
324
|
-
{
|
|
394
|
+
{
|
|
395
|
+
isLoading ? <div css={{textAlign: 'center'}}><Typography.Text>Loading…</Typography.Text></div> : …
|
|
396
|
+
}
|
|
325
397
|
|
|
326
398
|
// Correct — a skeleton shaped like the table it replaces
|
|
327
|
-
{
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
399
|
+
{
|
|
400
|
+
isLoading ? (
|
|
401
|
+
<TableSkeleton lines={5}/>
|
|
402
|
+
) : rows.length ? (
|
|
403
|
+
<Table>…</Table>
|
|
404
|
+
) : (
|
|
405
|
+
<Empty title="No dashboards" description="Create one to get started."/>
|
|
406
|
+
)
|
|
407
|
+
}
|
|
334
408
|
```
|
|
335
409
|
|
|
336
410
|
## Accessibility
|
|
337
411
|
|
|
338
|
-
Du Bois components target WCAG 2.2 and handle roles and semantics, focus management (dialogs
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
412
|
+
Du Bois components target WCAG 2.2 and handle roles and semantics, focus management (dialogs trap
|
|
413
|
+
and restore focus; overlays handle Escape and outside-click), keyboard interaction, focus-visible
|
|
414
|
+
outlines, and token contrast in both themes. The corollary: replacing a component with raw HTML or
|
|
415
|
+
overriding its structure means taking all of that on yourself.
|
|
342
416
|
|
|
343
417
|
You must supply:
|
|
344
418
|
|
|
345
|
-
- **Accessible labels on icon-only controls.** An icon-only `Button` has no accessible name.
|
|
346
|
-
|
|
419
|
+
- **Accessible labels on icon-only controls.** An icon-only `Button` has no accessible name. A
|
|
420
|
+
wrapping `Tooltip` is not a substitute — it contributes a *description*
|
|
347
421
|
(`aria-describedby`), not a *name*. Always set `aria-label`.
|
|
348
422
|
- **Real labels on form controls.** A `placeholder` disappears on input and is not reliably
|
|
349
423
|
announced.
|
|
@@ -369,8 +443,8 @@ You must supply:
|
|
|
369
443
|
|
|
370
444
|
### Raw HTML where a component exists
|
|
371
445
|
|
|
372
|
-
Use Du Bois components for interactive controls and styled text. Use semantic HTML for
|
|
373
|
-
|
|
446
|
+
Use Du Bois components for interactive controls and styled text. Use semantic HTML for structure and
|
|
447
|
+
layout (`div`, `span`, `section`, `ul`/`li`).
|
|
374
448
|
|
|
375
449
|
```tsx
|
|
376
450
|
// Incorrect
|
|
@@ -386,8 +460,8 @@ structure and layout (`div`, `span`, `section`, `ul`/`li`).
|
|
|
386
460
|
|
|
387
461
|
### Missing or bad `componentId`
|
|
388
462
|
|
|
389
|
-
Required on most interactive components, for analytics. Supply a stable, human-readable dotted
|
|
390
|
-
|
|
463
|
+
Required on most interactive components, for analytics. Supply a stable, human-readable dotted path.
|
|
464
|
+
Never a uuid, and never PII (emails, resource names, user input).
|
|
391
465
|
|
|
392
466
|
```tsx
|
|
393
467
|
// Incorrect
|
|
@@ -403,15 +477,15 @@ path. Never a uuid, and never PII (emails, resource names, user input).
|
|
|
403
477
|
|
|
404
478
|
```tsx
|
|
405
479
|
// Incorrect
|
|
406
|
-
<div css={{
|
|
480
|
+
<div css={{color: '#64727D', marginTop: 8, padding: '4px 12px'}}/>
|
|
407
481
|
|
|
408
482
|
// Correct
|
|
409
483
|
<div
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
484
|
+
css={{
|
|
485
|
+
color: theme.colors.textSecondary,
|
|
486
|
+
marginTop: theme.spacing.sm,
|
|
487
|
+
padding: `${theme.spacing.xs}px ${theme.spacing.mid}px`,
|
|
488
|
+
}}
|
|
415
489
|
/>
|
|
416
490
|
```
|
|
417
491
|
|
|
@@ -423,51 +497,50 @@ Don't reach for `css=`, `style=`, `dangerouslySetAntdProps`, `dangerouslyAppendE
|
|
|
423
497
|
|
|
424
498
|
```tsx
|
|
425
499
|
// Incorrect — fighting the component
|
|
426
|
-
<Button componentId="x" css={{
|
|
500
|
+
<Button componentId="x" css={{backgroundColor: '#1B5E20', border: 'none'}}>Save</Button>
|
|
427
501
|
|
|
428
502
|
// Correct — use the intended prop
|
|
429
503
|
<Button componentId="x" type="primary">Save</Button>
|
|
430
504
|
```
|
|
431
505
|
|
|
432
|
-
`className` for *layout* (margin, max-width, grid placement) is fine. `className` or `css` to
|
|
433
|
-
|
|
506
|
+
`className` for *layout* (margin, max-width, grid placement) is fine. `className` or `css` to change
|
|
507
|
+
a component's *colors or typography* is not.
|
|
434
508
|
|
|
435
509
|
### Legacy components
|
|
436
510
|
|
|
437
511
|
Du Bois ships modern replacements for every `Legacy*` component. Don't introduce new
|
|
438
|
-
`LegacySelect`, `LegacyTable`, `
|
|
512
|
+
`LegacySelect`, `LegacyTable`, `LegacyPopover`, or `LegacyForm` imports.
|
|
439
513
|
`Layout` (`Layout.Header` / `.Sider` / `.Content`) is likewise deprecated — use `PageWrapper` +
|
|
440
514
|
`Header`.
|
|
441
515
|
|
|
442
516
|
### Direct AntD imports
|
|
443
517
|
|
|
444
|
-
Du Bois is built on AntD internally. Never import AntD or `@ant-design/icons` directly — it
|
|
445
|
-
|
|
518
|
+
Du Bois is built on AntD internally. Never import AntD or `@ant-design/icons` directly — it bypasses
|
|
519
|
+
theming and breaks on version bumps.
|
|
446
520
|
|
|
447
521
|
```tsx
|
|
448
522
|
// Incorrect
|
|
449
|
-
import {
|
|
450
|
-
import {
|
|
523
|
+
import {Button} from 'antd';
|
|
524
|
+
import {PlusOutlined} from '@ant-design/icons';
|
|
451
525
|
|
|
452
526
|
// Correct
|
|
453
|
-
import {
|
|
527
|
+
import {Button, PlusIcon} from '@databricks/design-system';
|
|
454
528
|
```
|
|
455
529
|
|
|
456
530
|
## Making it look good
|
|
457
531
|
|
|
458
|
-
Polish
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
next step), and hover/focus/active/disabled are what separate polished UI from unpolished.
|
|
532
|
+
Polish is restraint, not decoration. Gradients, glass effects, heavy shadows, and custom accent
|
|
533
|
+
colors make an enterprise data product look worse; hand-writing a color, shadow, radius, or spacing
|
|
534
|
+
value to make something "pop" is the signal you are leaving the system.
|
|
535
|
+
|
|
536
|
+
- **Use the scales.** Reuse a few spacing steps rather than mixing `13px` and `15px`; set hierarchy
|
|
537
|
+
with `Typography.Title` levels and `Text` sizes, never a hand-set `fontSize`. Body text reads best
|
|
538
|
+
at 45–90 characters per line.
|
|
539
|
+
- **Let components own elevation.** Card, Popover, Modal, and Dropdown apply their own shadow —
|
|
540
|
+
hand-set `boxShadow` is almost always wrong.
|
|
541
|
+
- **Let semantic tokens carry state.** Prefer a component's own prop (`type="primary"`, `danger`)
|
|
542
|
+
over a raw token; it wires the full hover/press/disabled set. Never let color be the only signal —
|
|
543
|
+
pair it with an icon, label, or weight.
|
|
544
|
+
- **Build the states everyone skips** — loading (shape-matched skeletons), empty (`Empty` with a
|
|
545
|
+
next step), hover/focus/active/disabled.
|
|
473
546
|
- **Match density to context** with `size` props rather than cramming default-size components.
|