mlola-ui 1.0.2 → 1.0.4
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/README.md +30 -3
- package/package.json +1 -1
- package/registry/agents.json +419 -0
- package/registry/agents.md +453 -0
- package/registry/assets.json +734 -110
- package/registry/catalog.json +1187 -0
- package/registry/contract.json +1064 -0
- package/registry/index.json +65 -65
- package/registry/source/packages/components/alert/alert.tsx +1 -1
- package/registry/source/packages/components/badge/badge.tsx +2 -2
- package/registry/source/packages/components/breadcrumb/breadcrumb.tsx +1 -1
- package/registry/source/packages/components/carousel/carousel.tsx +1 -0
- package/registry/source/packages/components/checkbox/checkbox.tsx +3 -2
- package/registry/source/packages/components/color-picker/color-picker.tsx +15 -13
- package/registry/source/packages/components/color-picker/color.ts +1 -1
- package/registry/source/packages/components/combobox/combobox.tsx +33 -6
- package/registry/source/packages/components/date-picker/date-picker.tsx +5 -3
- package/registry/source/packages/components/dropzone/dropzone.tsx +1 -1
- package/registry/source/packages/components/empty-state/empty-state.tsx +1 -1
- package/registry/source/packages/components/hover-card/hover-card.tsx +1 -1
- package/registry/source/packages/components/number-input/number-input.tsx +6 -5
- package/registry/source/packages/components/otp-input/otp-input.tsx +6 -4
- package/registry/source/packages/components/progress/progress.tsx +1 -1
- package/registry/source/packages/components/segmented-control/segmented-control.tsx +5 -3
- package/registry/source/packages/components/select/select.tsx +6 -5
- package/registry/source/packages/components/tag-input/tag-input.tsx +7 -6
- package/registry/source/packages/components/textarea/textarea.tsx +1 -1
- package/registry/source/packages/components/time-picker/time-picker.tsx +8 -5
- package/registry/source/packages/components/timeline/timeline.tsx +1 -1
- package/registry/source/packages/components/toast/toast.tsx +1 -1
- package/registry/source/packages/components/toggle/toggle.tsx +1 -0
- package/registry/source/packages/components/tour/tour.tsx +3 -3
- package/registry/source-manifest.json +24 -24
- package/src/agents.js +119 -0
- package/src/cli.js +29 -4
- package/src/knowledge.js +235 -0
- package/src/mcp.js +241 -0
- package/src/pro.js +1 -1
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
# Mlola UI for code generation
|
|
2
|
+
|
|
3
|
+
Generated from the source of truth. Do not edit by hand.
|
|
4
|
+
|
|
5
|
+
## Read this first
|
|
6
|
+
|
|
7
|
+
- **Do not import a styling framework.** The library ships its own CSS. There
|
|
8
|
+
is no Tailwind, no CSS-in-JS and no class name utility to install.
|
|
9
|
+
- **Style through the classes below, never through invented ones.** A class
|
|
10
|
+
that is not in this document does not exist. (Mlola Pro's classes are in the
|
|
11
|
+
guide that comes with Pro source.)
|
|
12
|
+
- **Behavior is optional and framework-free.** `@mlola-ui/behavior` attaches
|
|
13
|
+
to markup you already rendered. It never renders anything itself, so it works
|
|
14
|
+
with React, Svelte, Vue, Rails, a Go template or a static file.
|
|
15
|
+
- **Native controls stay native.** Checkbox and radio are real `<input>`
|
|
16
|
+
elements. Do not reimplement them.
|
|
17
|
+
|
|
18
|
+
## The shortest correct example
|
|
19
|
+
|
|
20
|
+
```html
|
|
21
|
+
<link rel="stylesheet" href="@mlola-ui/engine" />
|
|
22
|
+
|
|
23
|
+
<div data-theme="graphite" data-mode="light">
|
|
24
|
+
<button class="ml-button" data-variant="primary">Save</button>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<script type="module">
|
|
28
|
+
import { observe } from "@mlola-ui/behavior";
|
|
29
|
+
observe();
|
|
30
|
+
</script>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Themes
|
|
34
|
+
|
|
35
|
+
Set `data-theme` and `data-mode` on any ancestor. Nothing else changes.
|
|
36
|
+
|
|
37
|
+
| id | name |
|
|
38
|
+
| --- | --- |
|
|
39
|
+
| `graphite` | Graphite |
|
|
40
|
+
| `atelier` | Atelier Umami |
|
|
41
|
+
| `machined` | Machined Titanium |
|
|
42
|
+
| `aerogel` | Aerogel Glass |
|
|
43
|
+
| `nordic` | Nordic Earth |
|
|
44
|
+
|
|
45
|
+
`data-mode` is `light` or `dark`.
|
|
46
|
+
|
|
47
|
+
A project defines its own theme in one file, `mlola.theme.json`, which
|
|
48
|
+
overrides fonts, colors, geometry, the spacing and type scale, and any
|
|
49
|
+
custom property through `extend`. See `mlola.theme.example.json`.
|
|
50
|
+
|
|
51
|
+
## Tokens
|
|
52
|
+
|
|
53
|
+
Every value a design needs is a token. Read them with `var()`; never write
|
|
54
|
+
a color, a size from outside the scales, a shadow or a duration by hand.
|
|
55
|
+
Values change with the theme and the mode, the names never do.
|
|
56
|
+
|
|
57
|
+
- **Planes and ink.** Backgrounds, surfaces, the three levels of text, borders.
|
|
58
|
+
`--ml-background` `--ml-background-subtle` `--ml-surface` `--ml-surface-elevated` `--ml-text` `--ml-text-muted` `--ml-text-faint` `--ml-border` `--ml-border-subtle`
|
|
59
|
+
- **Color roles.** Each role is a fill with its `-foreground`, a `-text` for text and marks on the page, and (primary) a `-subtle` tint.
|
|
60
|
+
`--ml-primary` `--ml-primary-foreground` `--ml-primary-text` `--ml-primary-subtle` `--ml-success` `--ml-success-foreground` `--ml-success-text` `--ml-warning` `--ml-warning-foreground` `--ml-warning-text` `--ml-danger` `--ml-danger-foreground` `--ml-danger-text` `--ml-info` `--ml-info-foreground` `--ml-info-text`
|
|
61
|
+
- **Charts.** A categorical palette for series, 3:1 on the surface. Never a status.
|
|
62
|
+
`--ml-chart-1` `--ml-chart-2` `--ml-chart-3` `--ml-chart-4` `--ml-chart-5` `--ml-chart-6`
|
|
63
|
+
- **Interaction and light.** Focus, hover and pressed fills, tracks, the veil behind overlays, light and knobs.
|
|
64
|
+
`--ml-focus` `--ml-primary-hover` `--ml-fill-hover` `--ml-fill-active` `--ml-track` `--ml-control-border` `--ml-ring` `--ml-scrim` `--ml-highlight` `--ml-knob` `--ml-knob-shadow` `--ml-sheen`
|
|
65
|
+
- **Spacing.** The only spacing: gaps, padding, margins, offsets.
|
|
66
|
+
`--ml-space-px` `--ml-space-0-5` `--ml-space-1` `--ml-space-1-5` `--ml-space-2` `--ml-space-2-5` `--ml-space-3` `--ml-space-3-5` `--ml-space-4` `--ml-space-4-5` `--ml-space-5` `--ml-space-6` `--ml-space-7` `--ml-space-8` `--ml-space-9` `--ml-space-10` `--ml-space-12` `--ml-space-14` `--ml-space-16`
|
|
67
|
+
- **Type.** The only type sizes, line heights, families and weights.
|
|
68
|
+
`--ml-type-2xs` `--ml-type-xs` `--ml-type-sm` `--ml-type-base` `--ml-type-md` `--ml-type-lg` `--ml-type-xl` `--ml-type-2xl` `--ml-leading-tight` `--ml-leading-snug` `--ml-leading-normal` `--ml-font-sans` `--ml-font-display` `--ml-font-mono` `--ml-display-weight` `--ml-body-leading` `--ml-tracking`
|
|
69
|
+
- **Density.** Control heights, panel padding, the touch target.
|
|
70
|
+
`--ml-control-sm` `--ml-control-md` `--ml-control-lg` `--ml-panel-padding` `--ml-target-min`
|
|
71
|
+
- **Shape.** Corner radii by the size of the thing, and the border weight.
|
|
72
|
+
`--ml-radius-xs` `--ml-radius-sm` `--ml-radius-md` `--ml-radius-lg` `--ml-radius-pill` `--ml-border-width`
|
|
73
|
+
- **Depth and material.** Elevation, and the material a floating surface is made of.
|
|
74
|
+
`--ml-texture-opacity` `--ml-material` `--ml-surface-alpha` `--ml-surface-blur` `--ml-surface-grain` `--ml-surface-highlight` `--ml-shadow-xs` `--ml-shadow-sm` `--ml-shadow-md` `--ml-shadow-lg` `--ml-shadow-xl` `--ml-shadow-tint`
|
|
75
|
+
- **Motion.** Every transition and entrance.
|
|
76
|
+
`--ml-duration-fast` `--ml-duration-normal` `--ml-duration-slow` `--ml-duration-reveal` `--ml-ease-standard` `--ml-ease-spring` `--ml-ease-bounce`
|
|
77
|
+
- **Layers.** The one stacking order.
|
|
78
|
+
`--ml-layer-raised` `--ml-layer-sticky` `--ml-layer-header` `--ml-layer-dropdown` `--ml-layer-overlay` `--ml-layer-modal` `--ml-layer-popover` `--ml-layer-toast` `--ml-layer-tooltip` `--ml-layer-top`
|
|
79
|
+
- **Icons.** The theme's icon channel.
|
|
80
|
+
`--ml-icon-stroke`
|
|
81
|
+
|
|
82
|
+
## Designing new UI in the Mlola language
|
|
83
|
+
|
|
84
|
+
When the elements above do not cover what you need, build it the way they are
|
|
85
|
+
built, and it will look like it belongs.
|
|
86
|
+
|
|
87
|
+
1. **Compose first.** Reach for a component, then a layout primitive, and
|
|
88
|
+
write CSS only for what neither covers. Put it in a layer of your own,
|
|
89
|
+
declared before `mlola.accessibility` so the accessibility guarantees
|
|
90
|
+
still win:
|
|
91
|
+
`@layer mlola.tokens, mlola.foundations, mlola.materials, mlola.recipes, mlola.motion, app, mlola.accessibility;`
|
|
92
|
+
2. **Name what it is, not how it looks.** One class per element role, with
|
|
93
|
+
your own prefix (not `ml-`, so a later Mlola element never collides).
|
|
94
|
+
State and variant go in `data-*` and `aria-*`, never in a second class.
|
|
95
|
+
Reuse the shared words: `data-tone` is `neutral primary info success
|
|
96
|
+
warning danger`; `data-size` is `xs sm md lg xl`; work that went
|
|
97
|
+
wrong is `error`.
|
|
98
|
+
3. **Color by role, never by value.** Planes are `background`,
|
|
99
|
+
`background-subtle`, `surface`, `surface-elevated`. Ink is `text`,
|
|
100
|
+
`text-muted`, `text-faint`. A colored fill (`primary`, `danger`, …)
|
|
101
|
+
always carries its `-foreground`. Colored text, icons, lines and status
|
|
102
|
+
marks on the page use the `-text` role: fills are only kept 1.5:1 from the
|
|
103
|
+
page, enough for an area, not for meaning. Series use `chart-1`…`chart-6`.
|
|
104
|
+
4. **Measure with the scales.** Spacing from `--ml-space-*`, type from
|
|
105
|
+
`--ml-type-*` with `--ml-leading-*`, control heights from
|
|
106
|
+
`--ml-control-*`, panel padding from `--ml-panel-padding`. A `clamp()`
|
|
107
|
+
between two steps is fine; a value invented between them is not.
|
|
108
|
+
5. **Shape and depth come from the theme.** Radii by the size of the thing
|
|
109
|
+
(`xs` a tag, `sm` a small control, `md` a control or card, `lg` a panel
|
|
110
|
+
or dialog, `pill`). Elevation from `--ml-shadow-*`; a floating surface
|
|
111
|
+
also takes the material: `--ml-surface-alpha`, `--ml-surface-blur`,
|
|
112
|
+
`--ml-surface-highlight`.
|
|
113
|
+
6. **Move with the theme.** Durations from `--ml-duration-*`, easing from
|
|
114
|
+
`--ml-ease-*`. Reduced motion is handled by the engine.
|
|
115
|
+
7. **Stack with the layers.** `--ml-layer-*`, never a raw z-index above 9.
|
|
116
|
+
8. **Keep it usable by hand.** Never remove an outline without a
|
|
117
|
+
`:focus-visible` style in its place. Targets are at least 24px; a smaller
|
|
118
|
+
control adds `data-hit="expand"` for touch. Text is never under
|
|
119
|
+
`--ml-type-2xs`.
|
|
120
|
+
9. **Leave the theme alone.** `data-theme` and `data-mode` belong to the
|
|
121
|
+
engine; never set them for a component's own meaning, and never style a
|
|
122
|
+
theme or mode by name. If something must differ by theme, it is a token.
|
|
123
|
+
|
|
124
|
+
## Composition primitives
|
|
125
|
+
|
|
126
|
+
Compose pages from these before writing layout CSS: sections, stacks,
|
|
127
|
+
clusters, grids, headings, forms, stats. They read the same tokens as every
|
|
128
|
+
component, so a page built from them themes with the rest.
|
|
129
|
+
|
|
130
|
+
`.ml-actions` `.ml-brand` `.ml-brand-mark` `.ml-brand-name` `.ml-chart` `.ml-chart-bar` `.ml-chart-bars` `.ml-chart-heading` `.ml-cluster` `.ml-definition-list` `.ml-display` `.ml-divider` `.ml-empty-state` `.ml-eyebrow` `.ml-filter-chip` `.ml-filter-group` `.ml-fine-print` `.ml-form` `.ml-form-message` `.ml-form-options` `.ml-grid` `.ml-heading` `.ml-icon-chip` `.ml-inline-form` `.ml-inline-form-field` `.ml-label` `.ml-lede` `.ml-link` `.ml-page-shell` `.ml-person` `.ml-person-copy` `.ml-positive` `.ml-price` `.ml-required-mark` `.ml-section` `.ml-section-description` `.ml-section-header` `.ml-section-header-centered` `.ml-section-muted` `.ml-section-shell` `.ml-stack` `.ml-stat` `.ml-stat-card` `.ml-stat-grid` `.ml-stat-list` `.ml-stat-meta` `.ml-stat-value` `.ml-text-primary` `.ml-value`
|
|
131
|
+
|
|
132
|
+
- `.ml-link` — A glyph inside a link flows with the text instead of breaking the line.
|
|
133
|
+
- `.ml-page-shell` — A full page: header, main and footer stacked on the page background.
|
|
134
|
+
|
|
135
|
+
## Elements and their attributes
|
|
136
|
+
|
|
137
|
+
Emit these classes and attributes from any language and the visuals are
|
|
138
|
+
correct. This table is read out of the stylesheet, so it is never stale.
|
|
139
|
+
|
|
140
|
+
| class | attribute | allowed values |
|
|
141
|
+
| --- | --- | --- |
|
|
142
|
+
| `.ml-accordion-item` | `data-state` | `open` |
|
|
143
|
+
| `.ml-alert` | `data-state` | `closing` |
|
|
144
|
+
| `.ml-alert` | `data-tone` | `danger`, `info`, `neutral`, `success`, `warning` |
|
|
145
|
+
| `.ml-alert` | `data-variant` | `soft` |
|
|
146
|
+
| `.ml-app-shell` | `data-narrow` | _presence only_ |
|
|
147
|
+
| `.ml-avatar-root` | `data-size` | `lg`, `sm`, `xl`, `xs` |
|
|
148
|
+
| `.ml-avatar-status` | `data-status` | `away`, `busy`, `online` |
|
|
149
|
+
| `.ml-badge` | `data-size` | `lg`, `sm` |
|
|
150
|
+
| `.ml-badge` | `data-tone` | `danger`, `info`, `primary`, `success`, `warning` |
|
|
151
|
+
| `.ml-badge` | `data-variant` | `outline`, `solid` |
|
|
152
|
+
| `.ml-breadcrumb-item` | `data-collapse-indicator` | _presence only_ |
|
|
153
|
+
| `.ml-breadcrumb-item` | `data-collapsible` | _presence only_ |
|
|
154
|
+
| `.ml-button` | `aria-disabled` | `true` |
|
|
155
|
+
| `.ml-button` | `aria-pressed` | `true` |
|
|
156
|
+
| `.ml-button` | `data-loading` | _presence only_ |
|
|
157
|
+
| `.ml-button` | `data-size` | `icon`, `lg`, `sm` |
|
|
158
|
+
| `.ml-button` | `data-state` | `success` |
|
|
159
|
+
| `.ml-button` | `data-variant` | `danger`, `link`, `outline`, `primary`, `secondary`, `subtle` |
|
|
160
|
+
| `.ml-calendar-cell` | `data-preview` | _presence only_ |
|
|
161
|
+
| `.ml-calendar-cell` | `data-range` | `end`, `start` |
|
|
162
|
+
| `.ml-calendar-day` | `aria-disabled` | `true` |
|
|
163
|
+
| `.ml-calendar-day` | `data-outside` | _presence only_ |
|
|
164
|
+
| `.ml-calendar-day` | `data-selected` | _presence only_ |
|
|
165
|
+
| `.ml-calendar-day` | `data-today` | _presence only_ |
|
|
166
|
+
| `.ml-calendar-day` | `data-unreachable` | _presence only_ |
|
|
167
|
+
| `.ml-card` | `data-interactive` | _presence only_ |
|
|
168
|
+
| `.ml-card` | `data-variant` | `elevated`, `glass`, `specular` |
|
|
169
|
+
| `.ml-carousel` | `data-playing` | _presence only_ |
|
|
170
|
+
| `.ml-carousel-arrow` | `data-side` | `next`, `previous` |
|
|
171
|
+
| `.ml-carousel-dot` | `aria-current` | `true` |
|
|
172
|
+
| `.ml-chart-bar` | `data-highlighted` | `true` |
|
|
173
|
+
| `.ml-checkbox-field` | `data-state` | `checked`, `indeterminate` |
|
|
174
|
+
| `.ml-circular-progress` | `data-size` | `lg`, `sm` |
|
|
175
|
+
| `.ml-circular-progress` | `data-state` | `complete`, `indeterminate` |
|
|
176
|
+
| `.ml-circular-progress` | `data-tone` | `danger`, `info`, `success`, `warning` |
|
|
177
|
+
| `.ml-color-picker-preset` | `aria-pressed` | `true` |
|
|
178
|
+
| `.ml-combobox-control` | `data-open` | _presence only_ |
|
|
179
|
+
| `.ml-combobox-input` | `data-clearable` | _presence only_ |
|
|
180
|
+
| `.ml-combobox-input` | `data-leading` | _presence only_ |
|
|
181
|
+
| `.ml-combobox-option` | `aria-disabled` | `true` |
|
|
182
|
+
| `.ml-combobox-option` | `aria-selected` | `true` |
|
|
183
|
+
| `.ml-combobox-option` | `data-create` | _presence only_ |
|
|
184
|
+
| `.ml-combobox-option` | `data-highlighted` | _presence only_ |
|
|
185
|
+
| `.ml-combobox-popover` | `data-side` | `top` |
|
|
186
|
+
| `.ml-command-item` | `aria-disabled` | _presence only_ |
|
|
187
|
+
| `.ml-command-item` | `aria-selected` | `true` |
|
|
188
|
+
| `.ml-context-menu-item` | `aria-disabled` | `true` |
|
|
189
|
+
| `.ml-context-menu-item` | `data-danger` | _presence only_ |
|
|
190
|
+
| `.ml-context-menu-item` | `data-highlighted` | _presence only_ |
|
|
191
|
+
| `.ml-date-picker-panel` | `data-presets` | _presence only_ |
|
|
192
|
+
| `.ml-date-picker-trigger` | `data-empty` | _presence only_ |
|
|
193
|
+
| `.ml-dropdown-item` | `data-danger` | _presence only_ |
|
|
194
|
+
| `.ml-dropdown-item` | `data-highlighted` | _presence only_ |
|
|
195
|
+
| `.ml-dropdown-menu` | `data-align` | `end` |
|
|
196
|
+
| `.ml-dropdown-trigger` | `aria-expanded` | `true` |
|
|
197
|
+
| `.ml-dropzone` | `aria-disabled` | _presence only_ |
|
|
198
|
+
| `.ml-dropzone` | `data-dragging` | _presence only_ |
|
|
199
|
+
| `.ml-dropzone-file` | `data-status` | `error` |
|
|
200
|
+
| `.ml-empty` | `data-size` | `page` |
|
|
201
|
+
| `.ml-filter-chip` | `aria-pressed` | `true` |
|
|
202
|
+
| `.ml-filter-chip` | `data-state` | `active` |
|
|
203
|
+
| `.ml-form-message` | `data-tone` | `danger`, `success` |
|
|
204
|
+
| `.ml-grid` | `data-columns` | `1`, `2`, `3`, `4`, `6` |
|
|
205
|
+
| `.ml-grid` | `data-layout` | `3-col`, `4-col`, `list` |
|
|
206
|
+
| `.ml-heatmap` | `data-tone` | `info`, `success`, `warning` |
|
|
207
|
+
| `.ml-heatmap-cell` | `data-active` | _presence only_ |
|
|
208
|
+
| `.ml-heatmap-cell` | `data-level` | `1`, `2`, `3`, `4` |
|
|
209
|
+
| `.ml-heatmap-cell` | `data-outside` | _presence only_ |
|
|
210
|
+
| `.ml-input` | `aria-invalid` | `true` |
|
|
211
|
+
| `.ml-input` | `data-size` | `lg`, `sm` |
|
|
212
|
+
| `.ml-input` | `data-variant` | `filled`, `subtle` |
|
|
213
|
+
| `.ml-input-control` | `data-leading` | _presence only_ |
|
|
214
|
+
| `.ml-input-control` | `data-trailing` | _presence only_ |
|
|
215
|
+
| `.ml-input-field` | `data-invalid` | _presence only_ |
|
|
216
|
+
| `.ml-modal` | `data-size` | `full`, `lg`, `sm`, `xl` |
|
|
217
|
+
| `.ml-number-input-control` | `data-disabled` | _presence only_ |
|
|
218
|
+
| `.ml-number-input-control` | `data-invalid` | _presence only_ |
|
|
219
|
+
| `.ml-otp` | `data-invalid` | _presence only_ |
|
|
220
|
+
| `.ml-pagination-button` | `aria-current` | `page` |
|
|
221
|
+
| `.ml-pagination-button` | `data-state` | `active` |
|
|
222
|
+
| `.ml-popover` | `data-side` | `bottom`, `left`, `right`, `top` |
|
|
223
|
+
| `.ml-priority-icon` | `data-priority` | `high`, `none`, `urgent` |
|
|
224
|
+
| `.ml-progress-root` | `data-active` | _presence only_ |
|
|
225
|
+
| `.ml-progress-root` | `data-size` | `lg`, `sm` |
|
|
226
|
+
| `.ml-progress-root` | `data-state` | `complete`, `indeterminate` |
|
|
227
|
+
| `.ml-progress-root` | `data-tone` | `danger`, `info`, `success`, `warning` |
|
|
228
|
+
| `.ml-radio-group` | `data-orientation` | `horizontal` |
|
|
229
|
+
| `.ml-radio-item` | `data-state` | `checked` |
|
|
230
|
+
| `.ml-resizable` | `data-anchor` | `second` |
|
|
231
|
+
| `.ml-resizable` | `data-direction` | `horizontal`, `vertical` |
|
|
232
|
+
| `.ml-resizable-pane` | `data-folded` | _presence only_ |
|
|
233
|
+
| `.ml-segmented-control-item` | `aria-pressed` | `true` |
|
|
234
|
+
| `.ml-segmented-control-item` | `data-state` | `active` |
|
|
235
|
+
| `.ml-select` | `data-size` | `lg`, `sm` |
|
|
236
|
+
| `.ml-select` | `data-state` | `open` |
|
|
237
|
+
| `.ml-select-option` | `data-disabled` | _presence only_ |
|
|
238
|
+
| `.ml-select-option` | `data-highlighted` | _presence only_ |
|
|
239
|
+
| `.ml-select-option` | `data-state` | `checked` |
|
|
240
|
+
| `.ml-select-popover` | `data-side` | `top` |
|
|
241
|
+
| `.ml-select-root` | `data-invalid` | _presence only_ |
|
|
242
|
+
| `.ml-select-value` | `data-placeholder` | _presence only_ |
|
|
243
|
+
| `.ml-sheet-panel` | `data-side` | `bottom`, `left`, `right`, `top` |
|
|
244
|
+
| `.ml-sheet-panel` | `data-size` | `lg`, `sm` |
|
|
245
|
+
| `.ml-sidebar-item` | `aria-current` | `page` |
|
|
246
|
+
| `.ml-sidebar-title` | `aria-expanded` | `false` |
|
|
247
|
+
| `.ml-sidebar-title` | `data-collapsible` | _presence only_ |
|
|
248
|
+
| `.ml-skeleton` | `data-rounded` | `none` |
|
|
249
|
+
| `.ml-slider-field` | `data-size` | `sm` |
|
|
250
|
+
| `.ml-status-icon` | `data-status` | `backlog`, `canceled`, `done`, `in-progress`, `in-review` |
|
|
251
|
+
| `.ml-stepper` | `data-orientation` | `horizontal`, `vertical` |
|
|
252
|
+
| `.ml-stepper-step` | `data-status` | `complete`, `current`, `error`, `upcoming` |
|
|
253
|
+
| `.ml-table` | `data-size` | `sm` |
|
|
254
|
+
| `.ml-table` | `data-stripe` | `alternate` |
|
|
255
|
+
| `.ml-table` | `data-striped` | _presence only_ |
|
|
256
|
+
| `.ml-table-row` | `data-state` | `selected` |
|
|
257
|
+
| `.ml-tabs` | `data-orientation` | `vertical` |
|
|
258
|
+
| `.ml-tabs` | `data-variant` | `enclosed`, `pills` |
|
|
259
|
+
| `.ml-tabs-trigger` | `aria-selected` | `true` |
|
|
260
|
+
| `.ml-tabs-trigger` | `data-state` | `active` |
|
|
261
|
+
| `.ml-tag-input-control` | `data-disabled` | _presence only_ |
|
|
262
|
+
| `.ml-tag-input-control` | `data-invalid` | _presence only_ |
|
|
263
|
+
| `.ml-tag-input-tag` | `data-armed` | _presence only_ |
|
|
264
|
+
| `.ml-textarea-count` | `data-full` | _presence only_ |
|
|
265
|
+
| `.ml-time-picker-control` | `data-disabled` | _presence only_ |
|
|
266
|
+
| `.ml-time-picker-control` | `data-unavailable` | _presence only_ |
|
|
267
|
+
| `.ml-time-picker-option` | `aria-selected` | `true` |
|
|
268
|
+
| `.ml-time-picker-segment` | `data-empty` | _presence only_ |
|
|
269
|
+
| `.ml-time-picker-segment` | `data-period` | _presence only_ |
|
|
270
|
+
| `.ml-timeline-item` | `data-status` | `complete`, `current`, `upcoming` |
|
|
271
|
+
| `.ml-timeline-marker` | `data-status` | `complete`, `current`, `upcoming` |
|
|
272
|
+
| `.ml-timeline-marker` | `data-tone` | `danger`, `info`, `primary`, `success`, `warning` |
|
|
273
|
+
| `.ml-toast` | `data-has-description` | _presence only_ |
|
|
274
|
+
| `.ml-toast` | `data-swiping` | _presence only_ |
|
|
275
|
+
| `.ml-toast` | `data-tone` | `danger`, `info`, `success`, `warning` |
|
|
276
|
+
| `.ml-toast-slot` | `data-state` | `closed` |
|
|
277
|
+
| `.ml-toaster` | `data-position` | `bottom-center`, `bottom-right`, `top-center`, `top-right` |
|
|
278
|
+
| `.ml-toggle` | `aria-checked` | `true` |
|
|
279
|
+
| `.ml-toggle` | `data-size` | `lg`, `sm` |
|
|
280
|
+
| `.ml-toggle` | `data-state` | `checked` |
|
|
281
|
+
| `.ml-toggle-button` | `aria-pressed` | `true` |
|
|
282
|
+
| `.ml-toggle-button` | `data-state` | `on` |
|
|
283
|
+
| `.ml-tooltip` | `data-side` | `bottom`, `left`, `right`, `top` |
|
|
284
|
+
| `.ml-tour-button` | `data-primary` | _presence only_ |
|
|
285
|
+
| `.ml-tour-card` | `data-centered` | _presence only_ |
|
|
286
|
+
| `.ml-tour-dot` | `data-active` | _presence only_ |
|
|
287
|
+
| `.ml-tour-scrim` | `data-spotlight` | _presence only_ |
|
|
288
|
+
|
|
289
|
+
## Behavior
|
|
290
|
+
|
|
291
|
+
### accordion
|
|
292
|
+
|
|
293
|
+
Disclosure list. One panel open at a time, or several.
|
|
294
|
+
|
|
295
|
+
- Root: `.ml-accordion`
|
|
296
|
+
- Parts: item `.ml-accordion-item`, trigger `.ml-accordion-trigger`, panel `.ml-accordion-panel`
|
|
297
|
+
- ARIA on trigger: `role` — button (a real <button> is preferred); `aria-expanded` — true when the item is open; `aria-controls` — id of the panel
|
|
298
|
+
- ARIA on panel: `role` — region; `aria-labelledby` — id of the trigger
|
|
299
|
+
- Keyboard:
|
|
300
|
+
- <kbd>Enter</kbd> / <kbd>Space</kbd>: Toggle the focused item.
|
|
301
|
+
- <kbd>ArrowDown</kbd> / <kbd>ArrowUp</kbd>: Move focus between triggers.
|
|
302
|
+
- <kbd>Home</kbd> / <kbd>End</kbd>: Focus the first or last trigger.
|
|
303
|
+
- State changes:
|
|
304
|
+
- On click or activate a trigger, set data-state on the item, trigger and panel to open, or closed when it was open and collapsing is allowed. Also: hide the closed panel from the accessibility tree.
|
|
305
|
+
|
|
306
|
+
### tabs
|
|
307
|
+
|
|
308
|
+
One panel visible at a time, selected by a tab strip.
|
|
309
|
+
|
|
310
|
+
- Root: `.ml-tabs`
|
|
311
|
+
- Parts: list `.ml-tabs-list`, trigger `.ml-tabs-trigger`, content `.ml-tabs-content`
|
|
312
|
+
- ARIA on list: `role` — tablist; `aria-orientation` — matches data-orientation
|
|
313
|
+
- ARIA on trigger: `role` — tab; `aria-selected` — true on the active tab; `aria-controls` — id of the panel; `tabindex` — 0 on the active tab, -1 on the rest
|
|
314
|
+
- ARIA on content: `role` — tabpanel; `aria-labelledby` — id of the tab
|
|
315
|
+
- Keyboard:
|
|
316
|
+
- <kbd>ArrowRight</kbd> / <kbd>ArrowLeft</kbd>: Move to the next or previous enabled tab when horizontal, wrapping around.
|
|
317
|
+
- <kbd>ArrowDown</kbd> / <kbd>ArrowUp</kbd>: The same when vertical.
|
|
318
|
+
- <kbd>Home</kbd> / <kbd>End</kbd>: Move to the first or last enabled tab.
|
|
319
|
+
- State changes:
|
|
320
|
+
- On select a tab by pointer or key, set data-state and aria-selected on triggers, data-state on panels to active for the chosen pair, inactive for the rest. Also: move focus to the newly selected tab.
|
|
321
|
+
- Note: Selection follows focus. Disabled tabs are skipped, never focused.
|
|
322
|
+
|
|
323
|
+
### dropdown-menu
|
|
324
|
+
|
|
325
|
+
A menu anchored to a trigger.
|
|
326
|
+
|
|
327
|
+
- Root: `.ml-dropdown`
|
|
328
|
+
- Parts: trigger `.ml-dropdown-trigger`, menu `.ml-dropdown-menu`, item `.ml-dropdown-item`
|
|
329
|
+
- ARIA on trigger: `aria-haspopup` — menu; `aria-expanded` — true while open
|
|
330
|
+
- ARIA on menu: `role` — menu
|
|
331
|
+
- ARIA on item: `role` — menuitem; `data-highlighted` — present on the active item
|
|
332
|
+
- Keyboard:
|
|
333
|
+
- <kbd>ArrowDown</kbd> / <kbd>ArrowUp</kbd>: Open the menu, then move the highlight.
|
|
334
|
+
- <kbd>Enter</kbd> / <kbd>Space</kbd>: Activate the highlighted item.
|
|
335
|
+
- <kbd>Escape</kbd>: Close and return focus to the trigger.
|
|
336
|
+
- <kbd>Tab</kbd>: Close without activating.
|
|
337
|
+
- State changes:
|
|
338
|
+
- On click the trigger, set data-state to open or closed.
|
|
339
|
+
- On pointer over an item, set data-highlighted to that item only.
|
|
340
|
+
- On pointer down outside the root, set data-state to closed.
|
|
341
|
+
- Note: Disabled items are skipped by the highlight and cannot be activated.
|
|
342
|
+
|
|
343
|
+
### select
|
|
344
|
+
|
|
345
|
+
A listbox behind a combobox trigger.
|
|
346
|
+
|
|
347
|
+
- Root: `.ml-select-root`
|
|
348
|
+
- Parts: trigger `.ml-select`, popover `.ml-select-popover`, list `.ml-select-list`, option `.ml-select-option`, search `.ml-select-search`
|
|
349
|
+
- ARIA on trigger: `role` — combobox; `aria-expanded` — true while open; `aria-controls` — id of the listbox; `aria-activedescendant` — id of the highlighted option while open
|
|
350
|
+
- ARIA on list: `role` — listbox; `aria-multiselectable` — true when multiple
|
|
351
|
+
- ARIA on option: `role` — option; `aria-selected` — true when chosen; `data-highlighted` — present on the active option
|
|
352
|
+
- Keyboard:
|
|
353
|
+
- <kbd>ArrowDown</kbd> / <kbd>ArrowUp</kbd>: Open, then move the highlight past disabled options.
|
|
354
|
+
- <kbd>Enter</kbd> / <kbd>Space</kbd>: Choose the highlighted option. Space types when a search field has focus.
|
|
355
|
+
- <kbd>Home</kbd> / <kbd>End</kbd>: Highlight the first or last enabled option.
|
|
356
|
+
- <kbd>Escape</kbd>: Close and return focus to the trigger.
|
|
357
|
+
- <kbd>Tab</kbd>: Close without choosing.
|
|
358
|
+
- State changes:
|
|
359
|
+
- On choose an option, set aria-selected and data-state on options to checked for the chosen option. Also: single select closes and restores focus; multiple select stays open.
|
|
360
|
+
|
|
361
|
+
### modal
|
|
362
|
+
|
|
363
|
+
A dialog over the page that owns focus while open.
|
|
364
|
+
|
|
365
|
+
- Root: `.ml-modal`
|
|
366
|
+
- Parts: overlay `.ml-modal-overlay`, close `.ml-modal-close`
|
|
367
|
+
- ARIA on root: `role` — dialog; `aria-modal` — true; `aria-labelledby` — id of the title, or aria-label
|
|
368
|
+
- Keyboard:
|
|
369
|
+
- <kbd>Escape</kbd>: Close, unless closing on Escape is disabled.
|
|
370
|
+
- <kbd>Tab</kbd> / <kbd>Shift+Tab</kbd>: Cycle focus inside the dialog and never leave it.
|
|
371
|
+
- State changes:
|
|
372
|
+
- On open, set focus to the first focusable element inside. Also: lock page scroll.
|
|
373
|
+
- On close, set focus to the element that opened the dialog. Also: release page scroll.
|
|
374
|
+
- On pointer down on the backdrop, set closed to unless closing on backdrop is disabled.
|
|
375
|
+
|
|
376
|
+
### sheet
|
|
377
|
+
|
|
378
|
+
A dialog anchored to one edge of the viewport.
|
|
379
|
+
|
|
380
|
+
- Root: `.ml-sheet-panel`
|
|
381
|
+
- Parts: overlay `.ml-sheet-overlay`, close `.ml-sheet-close`
|
|
382
|
+
- ARIA on root: `role` — dialog; `aria-modal` — true
|
|
383
|
+
- Keyboard:
|
|
384
|
+
- <kbd>Escape</kbd>: Close, unless closing on Escape is disabled.
|
|
385
|
+
- <kbd>Tab</kbd> / <kbd>Shift+Tab</kbd>: Cycle focus inside the panel.
|
|
386
|
+
- State changes:
|
|
387
|
+
- On open, set focus to inside the panel. Also: lock page scroll.
|
|
388
|
+
- On close, set focus to the trigger. Also: release page scroll.
|
|
389
|
+
- Note: Identical to modal apart from which edge it is anchored to.
|
|
390
|
+
|
|
391
|
+
### tooltip
|
|
392
|
+
|
|
393
|
+
A short label shown on hover or focus.
|
|
394
|
+
|
|
395
|
+
- Root: `.ml-tooltip-root`
|
|
396
|
+
- Parts: tooltip `.ml-tooltip`, arrow `.ml-tooltip-arrow`
|
|
397
|
+
- ARIA on tooltip: `role` — tooltip
|
|
398
|
+
- ARIA on trigger: `aria-describedby` — id of the tooltip while it is open
|
|
399
|
+
- Keyboard:
|
|
400
|
+
- <kbd>Escape</kbd>: Hide the tooltip.
|
|
401
|
+
- State changes:
|
|
402
|
+
- On pointer enter or focus the trigger, set visible to after the delay.
|
|
403
|
+
- On pointer leave or blur, set hidden to immediately, canceling any pending delay.
|
|
404
|
+
- Note: Never put essential information or interactive content in a tooltip.
|
|
405
|
+
|
|
406
|
+
### toast
|
|
407
|
+
|
|
408
|
+
Transient messages in a live region.
|
|
409
|
+
|
|
410
|
+
- Root: `.ml-toaster`
|
|
411
|
+
- Parts: toast `.ml-toast`, action `.ml-toast-action`, close `.ml-toast-close`
|
|
412
|
+
- ARIA on root: `role` — region; `aria-label` — distinct per region, so several are distinguishable
|
|
413
|
+
- ARIA on toast: `role` — status for ordinary messages, alert for danger and warning; `aria-live` — polite, or assertive for danger and warning; `aria-busy` — true while it waits on work (a loading toast)
|
|
414
|
+
- Keyboard:
|
|
415
|
+
- <kbd>Tab</kbd>: Reach the action and dismiss controls.
|
|
416
|
+
- State changes:
|
|
417
|
+
- On push, set a toast into the region matching its position to visible.
|
|
418
|
+
- On duration elapsed, set removed to unless the duration is zero.
|
|
419
|
+
|
|
420
|
+
### switch
|
|
421
|
+
|
|
422
|
+
An on/off control that is not a native checkbox.
|
|
423
|
+
|
|
424
|
+
- Root: `.ml-toggle`
|
|
425
|
+
- Parts: thumb `.ml-toggle-thumb`
|
|
426
|
+
- ARIA on root: `role` — switch; `aria-checked` — true or false
|
|
427
|
+
- Keyboard:
|
|
428
|
+
- <kbd>Enter</kbd> / <kbd>Space</kbd>: Toggle.
|
|
429
|
+
- State changes:
|
|
430
|
+
- On activate, set aria-checked and data-state to the opposite value.
|
|
431
|
+
- Note: Prefer a native checkbox unless the control genuinely reads as a switch.
|
|
432
|
+
|
|
433
|
+
### slider
|
|
434
|
+
|
|
435
|
+
A single value chosen from a range.
|
|
436
|
+
|
|
437
|
+
- Root: `.ml-slider-field`
|
|
438
|
+
- Parts: control `.ml-slider`, track `.ml-slider-track`, range `.ml-slider-range`, thumb `.ml-slider-thumb`
|
|
439
|
+
- ARIA on thumb: `role` — slider; `aria-valuenow` — current value; `aria-valuemin` — minimum; `aria-valuemax` — maximum; `tabindex` — 0 unless disabled
|
|
440
|
+
- Keyboard:
|
|
441
|
+
- <kbd>ArrowRight</kbd> / <kbd>ArrowUp</kbd>: Increase by one step.
|
|
442
|
+
- <kbd>ArrowLeft</kbd> / <kbd>ArrowDown</kbd>: Decrease by one step.
|
|
443
|
+
- <kbd>Home</kbd> / <kbd>End</kbd>: Jump to the minimum or maximum.
|
|
444
|
+
- <kbd>PageUp</kbd> / <kbd>PageDown</kbd>: Move by a larger step.
|
|
445
|
+
- State changes:
|
|
446
|
+
- On pointer down on the track, or drag the thumb, set the value from the pointer position, snapped to the step to within min and max.
|
|
447
|
+
|
|
448
|
+
## If you are unsure
|
|
449
|
+
|
|
450
|
+
Prefer emitting less. A plain `<button class="ml-button">` is correct; a
|
|
451
|
+
button with a variant this document does not list is not. When a component
|
|
452
|
+
needs behavior, mark its root with `data-ml="<behavior name>"` and let the
|
|
453
|
+
runtime attach, rather than writing event handlers that guess at the contract.
|