@mortenbrudvik/waveui 0.8.0 → 0.9.0
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 +231 -85
- package/dist/components/data-display/InfoButton.cjs +2 -0
- package/dist/components/data-display/InfoButton.cjs.map +1 -0
- package/dist/components/data-display/InfoButton.mjs +173 -0
- package/dist/components/data-display/InfoButton.mjs.map +1 -0
- package/dist/components/data-display/InfoLabel.cjs +1 -1
- package/dist/components/data-display/InfoLabel.cjs.map +1 -1
- package/dist/components/data-display/InfoLabel.mjs +39 -96
- package/dist/components/data-display/InfoLabel.mjs.map +1 -1
- package/dist/components/input/Checkbox.cjs +1 -1
- package/dist/components/input/Checkbox.cjs.map +1 -1
- package/dist/components/input/Checkbox.mjs +91 -75
- package/dist/components/input/Checkbox.mjs.map +1 -1
- package/dist/components/input/ColorPicker.parts.cjs +1 -1
- package/dist/components/input/ColorPicker.parts.cjs.map +1 -1
- package/dist/components/input/ColorPicker.parts.mjs +1 -1
- package/dist/components/input/ColorPicker.parts.mjs.map +1 -1
- package/dist/components/input/Combobox.cjs +1 -1
- package/dist/components/input/Combobox.cjs.map +1 -1
- package/dist/components/input/Combobox.expand.cjs +1 -1
- package/dist/components/input/Combobox.expand.cjs.map +1 -1
- package/dist/components/input/Combobox.expand.mjs +20 -20
- package/dist/components/input/Combobox.expand.mjs.map +1 -1
- package/dist/components/input/Combobox.mjs +143 -138
- package/dist/components/input/Combobox.mjs.map +1 -1
- package/dist/components/input/DatePicker.cjs +1 -1
- package/dist/components/input/DatePicker.cjs.map +1 -1
- package/dist/components/input/DatePicker.mjs +213 -209
- package/dist/components/input/DatePicker.mjs.map +1 -1
- package/dist/components/input/Dropdown.cjs +1 -1
- package/dist/components/input/Dropdown.cjs.map +1 -1
- package/dist/components/input/Dropdown.mjs +80 -74
- package/dist/components/input/Dropdown.mjs.map +1 -1
- package/dist/components/input/Field.cjs +1 -1
- package/dist/components/input/Field.cjs.map +1 -1
- package/dist/components/input/Field.mjs +99 -66
- package/dist/components/input/Field.mjs.map +1 -1
- package/dist/components/input/Input.cjs +1 -1
- package/dist/components/input/Input.cjs.map +1 -1
- package/dist/components/input/Input.mjs +79 -55
- package/dist/components/input/Input.mjs.map +1 -1
- package/dist/components/input/Label.cjs +1 -1
- package/dist/components/input/Label.cjs.map +1 -1
- package/dist/components/input/Label.mjs +19 -13
- package/dist/components/input/Label.mjs.map +1 -1
- package/dist/components/input/Rating.cjs +1 -1
- package/dist/components/input/Rating.cjs.map +1 -1
- package/dist/components/input/Rating.item.cjs +2 -0
- package/dist/components/input/Rating.item.cjs.map +1 -0
- package/dist/components/input/Rating.item.mjs +255 -0
- package/dist/components/input/Rating.item.mjs.map +1 -0
- package/dist/components/input/Rating.mjs +150 -151
- package/dist/components/input/Rating.mjs.map +1 -1
- package/dist/components/input/SearchBox.cjs +1 -1
- package/dist/components/input/SearchBox.cjs.map +1 -1
- package/dist/components/input/SearchBox.mjs +146 -115
- package/dist/components/input/SearchBox.mjs.map +1 -1
- package/dist/components/input/Select.cjs +1 -1
- package/dist/components/input/Select.cjs.map +1 -1
- package/dist/components/input/Select.mjs +34 -25
- package/dist/components/input/Select.mjs.map +1 -1
- package/dist/components/input/Slider.cjs +1 -1
- package/dist/components/input/Slider.cjs.map +1 -1
- package/dist/components/input/Slider.mjs +77 -54
- package/dist/components/input/Slider.mjs.map +1 -1
- package/dist/components/input/SpinButton.cjs +1 -1
- package/dist/components/input/SpinButton.cjs.map +1 -1
- package/dist/components/input/SpinButton.mjs +198 -96
- package/dist/components/input/SpinButton.mjs.map +1 -1
- package/dist/components/input/Switch.cjs +1 -1
- package/dist/components/input/Switch.cjs.map +1 -1
- package/dist/components/input/Switch.mjs +71 -55
- package/dist/components/input/Switch.mjs.map +1 -1
- package/dist/components/input/TagPicker.cjs +1 -1
- package/dist/components/input/TagPicker.cjs.map +1 -1
- package/dist/components/input/TagPicker.mjs +142 -116
- package/dist/components/input/TagPicker.mjs.map +1 -1
- package/dist/components/input/Textarea.cjs +1 -1
- package/dist/components/input/Textarea.cjs.map +1 -1
- package/dist/components/input/Textarea.mjs +28 -21
- package/dist/components/input/Textarea.mjs.map +1 -1
- package/dist/components/input/TimePicker.cjs +1 -1
- package/dist/components/input/TimePicker.cjs.map +1 -1
- package/dist/components/input/TimePicker.mjs +189 -184
- package/dist/components/input/TimePicker.mjs.map +1 -1
- package/dist/components/input/fieldLabel.cjs +2 -0
- package/dist/components/input/fieldLabel.cjs.map +1 -0
- package/dist/components/input/fieldLabel.mjs +17 -0
- package/dist/components/input/fieldLabel.mjs.map +1 -0
- package/dist/components/input/inputLook.cjs +2 -0
- package/dist/components/input/inputLook.cjs.map +1 -0
- package/dist/components/input/inputLook.mjs +28 -0
- package/dist/components/input/inputLook.mjs.map +1 -0
- package/dist/components/input/pickerStyles.cjs +1 -1
- package/dist/components/input/pickerStyles.cjs.map +1 -1
- package/dist/components/input/pickerStyles.mjs +42 -4
- package/dist/components/input/pickerStyles.mjs.map +1 -1
- package/dist/components/navigation/Menu.popover.cjs +1 -1
- package/dist/components/navigation/Menu.popover.cjs.map +1 -1
- package/dist/components/navigation/Menu.popover.mjs +10 -10
- package/dist/components/navigation/Menu.root.cjs +1 -1
- package/dist/components/navigation/Menu.root.cjs.map +1 -1
- package/dist/components/navigation/Menu.root.mjs +10 -10
- package/dist/components/overlays/Popover.cjs +1 -1
- package/dist/components/overlays/Popover.cjs.map +1 -1
- package/dist/components/overlays/Popover.mjs +203 -208
- package/dist/components/overlays/Popover.mjs.map +1 -1
- package/dist/components/overlays/Popover.shared.cjs +1 -1
- package/dist/components/overlays/Popover.shared.cjs.map +1 -1
- package/dist/components/overlays/Popover.shared.mjs +82 -77
- package/dist/components/overlays/Popover.shared.mjs.map +1 -1
- package/dist/components/provider/WaveProvider.cjs +1 -1
- package/dist/components/provider/WaveProvider.cjs.map +1 -1
- package/dist/components/provider/WaveProvider.mjs +25 -19
- package/dist/components/provider/WaveProvider.mjs.map +1 -1
- package/dist/hooks/useFieldControl.cjs.map +1 -1
- package/dist/hooks/useFieldControl.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +805 -99
- package/dist/index.d.ts +805 -99
- package/dist/index.mjs +101 -99
- package/dist/lib/classNames.cjs +1 -1
- package/dist/lib/classNames.cjs.map +1 -1
- package/dist/lib/classNames.mjs +74 -66
- package/dist/lib/classNames.mjs.map +1 -1
- package/dist/lib/styles.cjs +1 -1
- package/dist/lib/styles.cjs.map +1 -1
- package/dist/lib/styles.mjs +21 -4
- package/dist/lib/styles.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/styles/tokens.css +13 -0
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# @mortenbrudvik/waveui
|
|
2
2
|
|
|
3
|
-
A React component library inspired by the Fluent UI 2 design language:
|
|
3
|
+
A React component library inspired by the Fluent UI 2 design language: 69 accessible, composable components built with TypeScript, Tailwind CSS 4 and CSS custom properties, with light, dark and high-contrast themes and right-to-left support.
|
|
4
4
|
|
|
5
5
|
> This is **not** Microsoft's official `@fluentui/react-components` package.
|
|
6
6
|
|
|
7
7
|
- [Requirements](#requirements) · [Installation](#installation) · [Quick start](#quick-start)
|
|
8
8
|
- [Styles](#styles) · [Theming](#theming) · [Global effects](#global-effects) · [Styling hooks](#styling-hooks)
|
|
9
9
|
- [React Server Components](#react-server-components) · [Components](#components) · [Usage notes](#usage-notes)
|
|
10
|
-
- [Keyboard support](#keyboard-support) · [Hooks and utilities](#hooks-and-utilities) · [Upgrading from 0.7](#upgrading-from-07) · [Upgrading from 0.6](#upgrading-from-06) · [Upgrading from 0.5](#upgrading-from-05) · [Upgrading from 0.4](#upgrading-from-04) · [Development](#development)
|
|
10
|
+
- [Keyboard support](#keyboard-support) · [Hooks and utilities](#hooks-and-utilities) · [Upgrading from 0.8](#upgrading-from-08) · [Upgrading from 0.7](#upgrading-from-07) · [Upgrading from 0.6](#upgrading-from-06) · [Upgrading from 0.5](#upgrading-from-05) · [Upgrading from 0.4](#upgrading-from-04) · [Development](#development)
|
|
11
11
|
|
|
12
12
|
## Requirements
|
|
13
13
|
|
|
@@ -120,7 +120,8 @@ export function Shell({ children }: { children: React.ReactNode }) {
|
|
|
120
120
|
- A nested provider inherits every prop it omits (`theme`, `dir`, `portalContainer`) from the enclosing provider, so the light panel above stays right-to-left. `portalContainer={null}` sends a nested subtree's overlays to `document.body`.
|
|
121
121
|
- The provider renders `<div class="wave-root wave-<theme>" dir data-wave-theme>` with `bg-background text-foreground font-wave text-body-1`; a `className` you pass wins.
|
|
122
122
|
- Portaled overlays (Dialog, Drawer, Popover, Menu, listboxes, Tooltip, Toaster) render in a `wave-portal` wrapper that carries the provider's theme classes, direction and font.
|
|
123
|
-
- `
|
|
123
|
+
- `inputDefaults`: `{ size?, appearance? }`, the default `size` and `appearance` of the text inputs and pickers below it (see [Sizes and appearances](#sizes-and-appearances)). A nested provider merges its own defined keys over the enclosing provider's, so `<WaveProvider inputDefaults={{ size: 'small' }}>` inside an app with `appearance: 'filled-darker'` gives small filled-darker fields; omitting the prop inherits the enclosing value.
|
|
124
|
+
- `useWaveTheme()` returns `{ theme, dir, themeClassName, portalContainer, inputDefaults, hasProvider }` (`inputDefaults` is `{}` outside a provider).
|
|
124
125
|
|
|
125
126
|
**Theme classes.** The tokens are selected by `wave-light` (also `:root`), `wave-dark` and `wave-high-contrast`; `getThemeClassName(theme)` returns them. For dark and high contrast the provider also emits the deprecated 0.4 classes `dark` and `high-contrast`, so 0.4 `.dark` selectors in your CSS and class-based `dark:` variants (`@custom-variant dark (&:where(.dark, .dark *));`) keep working. Tailwind 4's default `dark:` variant follows `prefers-color-scheme`, not a class, and Wave does not define a class-based one. Wave's CSS still honours the two legacy classes, but they set only `--wave-*` variables. `color-scheme` is set on the three `wave-*` theme classes only, never on `:root`, so a page without a provider keeps its own scrollbar and form-control scheme.
|
|
126
127
|
|
|
@@ -208,7 +209,7 @@ Never load `legacy-tokens.css` in an app that defines shadcn/ui-style variables
|
|
|
208
209
|
Generated from `src/styles/tokens.css`. A value followed by a ramp or token name is a reference (`var(--wave-brand-80)`); the hex is its default.
|
|
209
210
|
|
|
210
211
|
<details>
|
|
211
|
-
<summary>All
|
|
212
|
+
<summary>All 64 color tokens per theme</summary>
|
|
212
213
|
|
|
213
214
|
| Token (`--wave-…`) | Light | Dark | High contrast |
|
|
214
215
|
| ------------------------- | ------------------------------ | ------------------------------ | ------------------------------ |
|
|
@@ -237,6 +238,8 @@ Generated from `src/styles/tokens.css`. A value followed by a ramp or token name
|
|
|
237
238
|
| `stroke-hover` | `#c7c7c7` | `#757575` | `#ffffff` |
|
|
238
239
|
| `stroke-accessible` | `#616161` | `#adadad` | `#ffffff` |
|
|
239
240
|
| `input` | `#d1d1d1` | `#666666` | `#ffffff` |
|
|
241
|
+
| `input-filled-darker` | `#f5f5f5` | `#141414` | `#000000` |
|
|
242
|
+
| `input-filled-stroke` | `transparent` | `transparent` | `#ffffff` |
|
|
240
243
|
| `ring` | `#0f6cbd` (brand-80) | `#479ef5` (brand-100) | `#ffff00` |
|
|
241
244
|
| `success` | `#107c10` | `#5db55d` | `#3ff23f` |
|
|
242
245
|
| `success-foreground` | `#ffffff` | `#000000` | `#000000` |
|
|
@@ -273,11 +276,14 @@ Generated from `src/styles/tokens.css`. A value followed by a ramp or token name
|
|
|
273
276
|
| `secondary-foreground` | `#242424` (foreground) | `#ffffff` (foreground) | `#ffffff` (foreground) |
|
|
274
277
|
| `accent` | `#0f6cbd` (primary) | `#62abf5` (primary) | `#1aebff` (primary) |
|
|
275
278
|
| `accent-foreground` | `#ffffff` (primary-foreground) | `#000000` (primary-foreground) | `#000000` (primary-foreground) |
|
|
279
|
+
| `input-filled-lighter` | `#ffffff` (background) | `#292929` (background) | `#000000` (background) |
|
|
276
280
|
|
|
277
281
|
</details>
|
|
278
282
|
|
|
279
283
|
Theme-independent variables on `:root`: `--wave-brand-10` … `--wave-brand-160` (also utilities such as `bg-brand-80`), `--wave-grey-2` … `--wave-grey-98`, `--wave-font-family` (utility `font-wave`), the stacking layers `--wave-z-overlay` (1000), `--wave-z-toast` (1100) and `--wave-z-tooltip` (1200), and the motion durations `--wave-duration-*` and curves `--wave-curve-*` (see [Enter and exit motion](#enter-and-exit-motion)).
|
|
280
284
|
|
|
285
|
+
The three `input-filled-*` tokens (utilities `bg-input-filled-darker`, `bg-input-filled-lighter`, `border-input-filled-stroke`) draw the `filled-darker` and `filled-lighter` appearances of the text inputs and pickers (see [Sizes and appearances](#sizes-and-appearances)); `input-filled-lighter` follows `background`, and the stroke is transparent except in the high-contrast theme.
|
|
286
|
+
|
|
281
287
|
Contrast of every text and non-text pair is checked per theme by `src/styles/__tests__/tokens.test.ts`. One known limit: the `warning` fill (`#fde300` in light) is a background and accent color only; use `warning-tint-foreground` for warning text and icons.
|
|
282
288
|
|
|
283
289
|
Other Wave theme values: the type ramp `text-caption-2`, `text-caption-1`, `text-body-1`, `text-body-2`, `text-subtitle-2`, `text-subtitle-1`, `text-title-3`, `text-title-2`, `text-title-1`, `text-large-title`, `text-display`; shadows `shadow-2`, `shadow-4`, `shadow-8`, `shadow-16`, `shadow-28`, `shadow-64`; animations `animate-wave-spin`, `animate-wave-spin-slow`, `animate-wave-pulse`, `animate-wave-indeterminate`, `animate-wave-indeterminate-rtl`; on the Tailwind path, the motion utilities `duration-wave-ultra-fast` … `duration-wave-ultra-slow` and `ease-wave-accelerate-max` … `ease-wave-linear`. Border radius uses Tailwind's default scale (Wave no longer overrides it).
|
|
@@ -304,7 +310,7 @@ What adding Wave changes outside its own components:
|
|
|
304
310
|
**Colliding utility names.** Wave's Tailwind color names are unprefixed, because they are the utility vocabulary 0.4 documented and that consumer code uses in `className` overrides. In a shared Tailwind build, or next to another stylesheet that defines the same class names, each of the following names resolves to a single definition in every utility that takes a color (`bg-`, `text-`, `border-`, `ring-`, `outline-`, `fill-`, `stroke-`, `accent-`, `caret-`, `decoration-`, `divide-`, `placeholder-`, `shadow-`, `from-`/`via-`/`to-`, …):
|
|
305
311
|
|
|
306
312
|
- Shared with shadcn/ui: `background`, `foreground`, `card`, `card-foreground`, `primary`, `primary-foreground`, `secondary`, `secondary-foreground`, `muted`, `muted-foreground`, `accent`, `accent-foreground`, `destructive`, `destructive-foreground`, `border`, `input`, `ring`.
|
|
307
|
-
- Wave's other names: `primary-hover`, `primary-pressed`, `error`, `error-foreground`, `subtle`, `subtle-hover`, `subtle-pressed`, `subtle-selected`, `selected`, `selected-foreground`, `stroke`, `stroke-hover`, `stroke-accessible`, `success`, `success-foreground`, `success-tint`, `success-tint-foreground`, `warning`, `warning-foreground`, `warning-tint`, `warning-tint-foreground`, `error-tint`, `error-tint-foreground`, `severe`, `severe-foreground`, `severe-tint`, `severe-tint-foreground`, `info`, `info-foreground`, `info-tint`, `info-tint-foreground`, `inverted`, `inverted-foreground`, `inverted-border`, `track`, `skeleton`, `rating`, `presence-available`, `presence-busy`, `presence-away`, `presence-offline`, `presence-oof`, `presence-glyph`, `backdrop`, `brand-10` … `brand-160`.
|
|
313
|
+
- Wave's other names: `primary-hover`, `primary-pressed`, `error`, `error-foreground`, `subtle`, `subtle-hover`, `subtle-pressed`, `subtle-selected`, `selected`, `selected-foreground`, `stroke`, `stroke-hover`, `stroke-accessible`, `success`, `success-foreground`, `success-tint`, `success-tint-foreground`, `warning`, `warning-foreground`, `warning-tint`, `warning-tint-foreground`, `error-tint`, `error-tint-foreground`, `severe`, `severe-foreground`, `severe-tint`, `severe-tint-foreground`, `info`, `info-foreground`, `info-tint`, `info-tint-foreground`, `inverted`, `inverted-foreground`, `inverted-border`, `input-filled-darker`, `input-filled-lighter`, `input-filled-stroke`, `track`, `skeleton`, `rating`, `presence-available`, `presence-busy`, `presence-away`, `presence-offline`, `presence-oof`, `presence-glyph`, `backdrop`, `brand-10` … `brand-160`.
|
|
308
314
|
|
|
309
315
|
Workarounds when your app has its own design system:
|
|
310
316
|
|
|
@@ -362,7 +368,7 @@ export function checkedRows(tree: HTMLElement) {
|
|
|
362
368
|
|
|
363
369
|
- Every component and hook module of the package starts with `"use client"`. The entry point, `cn`, the slot helpers, the class-name constants (`buttonClassNames`, …), `hsvToHex`, `hexToHsv`, `createToaster` and the types are server-safe, so a Server Component can import from `@mortenbrudvik/waveui`, read the constants, create a toaster handle and render Wave components with serializable props.
|
|
364
370
|
- A Server Component **cannot dot into a client component**: `Card.Header` throws "Cannot access Header on the server". Every sub-component is therefore also exported under a flat name. Use the flat names in Server Components and either form in client components.
|
|
365
|
-
- Every compound can be composed in a Server Component. Parts written there reach the client as lazy references, and the compounds recognise them, so the server HTML and the client behaviour are the same as in a client file: Accordion items, Carousel slides, the options of Combobox and Dropdown, DataGrid parts, Drawer and Menu triggers, the header of a `Menu.Group`, the halves of a `Menu.SplitGroup`, List, Nav, TabList and Tree items, the parts of Toast and MessageBar, the ColorPicker parts, `Tree.ItemPersonaLayout`, and a `Button` passed as a MessageBar, SearchBox or Tag dismiss slot.
|
|
371
|
+
- Every compound can be composed in a Server Component. Parts written there reach the client as lazy references, and the compounds recognise them, so the server HTML and the client behaviour are the same as in a client file: Accordion items, Carousel slides, the options of Combobox and Dropdown, DataGrid parts, Drawer and Menu triggers, the header of a `Menu.Group`, the halves of a `Menu.SplitGroup`, List, Nav, TabList and Tree items, the stars of a Rating or RatingDisplay, the parts of Toast and MessageBar, the ColorPicker parts, `Tree.ItemPersonaLayout`, a `Label` or `InfoLabel` passed as the `label` of a Field, and a `Button` passed as a MessageBar, SearchBox or Tag dismiss slot.
|
|
366
372
|
- Event handlers and other functions cannot be passed from a Server Component; put interactive parts in a `'use client'` component.
|
|
367
373
|
- A `Popover`, `Dialog`, `Drawer`, popup `Menu`, `Combobox`, `Dropdown`, `DatePicker`, `TimePicker` or `TagPicker` rendered on the server with `defaultOpen` (or `open`) is closed in the server HTML and opens once hydrated, so no ARIA reference points at a popup that is not there. `onOpenChange` is not called for it.
|
|
368
374
|
|
|
@@ -432,36 +438,38 @@ export function SaveArea() {
|
|
|
432
438
|
}
|
|
433
439
|
```
|
|
434
440
|
|
|
435
|
-
| Compound
|
|
436
|
-
|
|
|
437
|
-
| `Accordion`
|
|
438
|
-
| `Breadcrumb`
|
|
439
|
-
| `Card`
|
|
440
|
-
| `Carousel`
|
|
441
|
-
| `ColorPicker`
|
|
442
|
-
| `Combobox`
|
|
443
|
-
| `DataGrid`
|
|
444
|
-
| `Dialog`
|
|
445
|
-
| `Drawer`
|
|
446
|
-
| `Dropdown`
|
|
447
|
-
| `List`
|
|
448
|
-
| `Menu`
|
|
449
|
-
| `MessageBar`
|
|
450
|
-
| `Nav`
|
|
451
|
-
| `Overflow`
|
|
452
|
-
| `Popover`
|
|
453
|
-
| `RadioGroup`
|
|
454
|
-
| `
|
|
455
|
-
| `
|
|
456
|
-
| `
|
|
457
|
-
| `
|
|
458
|
-
| `
|
|
459
|
-
| `
|
|
460
|
-
| `
|
|
441
|
+
| Compound | Flat names |
|
|
442
|
+
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
443
|
+
| `Accordion` | `AccordionItem`, `AccordionTrigger`, `AccordionPanel` |
|
|
444
|
+
| `Breadcrumb` | `BreadcrumbItem` |
|
|
445
|
+
| `Card` | `CardHeader`, `CardBody`, `CardFooter` |
|
|
446
|
+
| `Carousel` | `CarouselItem` |
|
|
447
|
+
| `ColorPicker` | `ColorPickerHexField`, `ColorPickerSwatches`, `ColorPickerPreview` |
|
|
448
|
+
| `Combobox` | `ComboboxOption`, `ComboboxOptionGroup` (also `Option`, `OptionGroup`) |
|
|
449
|
+
| `DataGrid` | `DataGridHeader`, `DataGridHeaderCell`, `DataGridBody`, `DataGridRow`, `DataGridCell` |
|
|
450
|
+
| `Dialog` | `DialogTrigger`, `DialogContent`, `DialogTitle`, `DialogFooter`, `DialogClose` |
|
|
451
|
+
| `Drawer` | `DrawerTrigger`, `DrawerTitle`, `DrawerClose` |
|
|
452
|
+
| `Dropdown` | `DropdownOption`, `DropdownOptionGroup` |
|
|
453
|
+
| `List` | `ListItem` |
|
|
454
|
+
| `Menu` | `MenuTrigger`, `MenuPopover`, `MenuItem`, `MenuDivider`, `MenuItemCheckbox`, `MenuItemRadio`, `MenuItemSwitch`, `MenuItemLink`, `MenuGroup`, `MenuGroupHeader`, `MenuSplitGroup` |
|
|
455
|
+
| `MessageBar` | `MessageBarTitle`, `MessageBarActions` |
|
|
456
|
+
| `Nav` | `NavCategory`, `NavItem`, `NavSubItem` |
|
|
457
|
+
| `Overflow` | `OverflowItem` |
|
|
458
|
+
| `Popover` | `PopoverTrigger`, `PopoverContent` |
|
|
459
|
+
| `RadioGroup` | `RadioGroupItem` (also `RadioItem`) |
|
|
460
|
+
| `Rating` | `RatingItem` |
|
|
461
|
+
| `RatingDisplay` | `RatingDisplayItem` (also `RatingItem`) |
|
|
462
|
+
| `Skeleton` | `SkeletonGroup` |
|
|
463
|
+
| `Stepper` | `StepperStep` |
|
|
464
|
+
| `Table` | `TableHeader`, `TableHeaderCell`, `TableBody`, `TableRow`, `TableCell` |
|
|
465
|
+
| `TabList` | `TabListTab`, `TabListPanel`, `TabListPanels` |
|
|
466
|
+
| `Toast` | `ToastTitle`, `ToastBody`, `ToastFooter`, `ToastClose` |
|
|
467
|
+
| `Toolbar` | `ToolbarButton`, `ToolbarToggleButton`, `ToolbarRadioGroup`, `ToolbarRadioButton`, `ToolbarGroup`, `ToolbarDivider` |
|
|
468
|
+
| `Tree` | `TreeItem`, `TreeItemPersonaLayout` |
|
|
461
469
|
|
|
462
470
|
## Components
|
|
463
471
|
|
|
464
|
-
|
|
472
|
+
69 components, plus the `Portal` and `Presence` utilities. Every component accepts `ref` as a prop (React 19), a `className`, and the native attributes of its element. Storybook (`npm run dev`) shows every component with its props, states and themes.
|
|
465
473
|
|
|
466
474
|
Your `className` is merged last with `cn()`, so it replaces a conflicting class **of the same variant**: `bg-error` replaces a resting `bg-primary`. A class behind a variant is replaced only by a class with the same variant. That matters for the gated hover and pressed classes (`not-disabled:not-aria-disabled:hover:…` / `…:active:…`) and the state classes (`data-[selected]:…`, `aria-disabled:…`): they stay next to yours and win while their state applies, because they are more specific. A bare `hover:bg-error` therefore does not override a Button's built-in hover color while the Button is enabled. It still paints on hover while the Button is disabled or `aria-disabled`, and on `appearance="transparent"`, which has no hover background. To override the gated and state classes, use the same prefix (`not-disabled:not-aria-disabled:hover:bg-error`, `data-[selected]:bg-error`) or the important modifier (`hover:bg-error!`); see [Buttons](#buttons).
|
|
467
475
|
|
|
@@ -479,46 +487,47 @@ Your `className` is merged last with `cn()`, so it replaces a conflicting class
|
|
|
479
487
|
|
|
480
488
|
### Inputs and forms
|
|
481
489
|
|
|
482
|
-
| Component | Description
|
|
483
|
-
| -------------- |
|
|
484
|
-
| `Field` | Label, hint, validation message (`validationState` error, warning, success or none; `error` is the shorthand for an error) and required indicator, wired to the control inside it (library controls read the Field context wherever they are in it); `orientation="horizontal"` puts the label beside the control.
|
|
485
|
-
| `Label` | Form label with a
|
|
486
|
-
| `Input` | Text input with `contentBefore`/`contentAfter` slots, `onValueChange(value)` next to the native `onChange`, and an `error` message.
|
|
487
|
-
| `Textarea` | Multi-line text input with an `error` message.
|
|
488
|
-
| `Select` | Styled native `<select>` with an `error` message.
|
|
489
|
-
| `Checkbox` | `checked`/`defaultChecked`/`onCheckedChange`, `indeterminate`, a rich `label` before or after the box (`labelPosition`), `disabledFocusable`, native form support.
|
|
490
|
-
| `Switch` | On/off toggle (`role="switch"`), `onCheckedChange`, a rich `label` before, after or above it (`labelPosition`), `disabledFocusable`, native form support.
|
|
491
|
-
| `RadioGroup` | Single choice with `RadioGroup.Item` items (a rich `label` each); `orientation`, `disabled`, `onValueChange`, native form support.
|
|
492
|
-
| `SearchBox` | Search input with a clear button; `onValueChange`; input attributes go to the `<input>`. The root draws the field, so `className` and `style` style the field box, and `contentBefore`/`contentAfter` sit beside the text.
|
|
493
|
-
| `Slider` | Styled native range input, filled up to the thumb; `onValueChange(number)`.
|
|
494
|
-
| `SpinButton` | Numeric input with step buttons; typed text is a draft committed on blur or Enter; `min`, `max`, `step`, `largeStep
|
|
495
|
-
| `Combobox` | Editable combobox: typing filters the options; `freeform` makes the typed text the value; a chevron (`expandIcon`) and `clearable`. `Combobox.Option`, `Combobox.OptionGroup`.
|
|
496
|
-
| `Dropdown` | Select-only combobox (a button) with typeahead; `clearable`. `Dropdown.Option`, `Dropdown.OptionGroup`.
|
|
497
|
-
| `TagPicker` | Multi-select combobox that shows the selection as removable tags (a list named "Selected"); the input is described by a summary of the selection ("Selected: Apple, Banana"), and additions and removals are announced.
|
|
498
|
-
| `DatePicker` | Date input with a calendar dialog; locale-aware format and parse, `minDate`, `maxDate`, `disabledDates`, `onInvalidInput`.
|
|
499
|
-
| `TimePicker` | Time combobox (`12h`/`24h`, `step`, `minTime`, `maxTime`); value is `HH:mm`; `open`/`defaultOpen`/`onOpenChange` control the list; rejected text is kept and flagged (`onInvalidInput`).
|
|
500
|
-
| `ColorPicker` | Hex value (lowercase `#rrggbb`, or `#rrggbbaa` when not opaque) with a color area, a hue slider, a hex field, preset swatches and an optional opacity slider; with children, your own layout of `ColorArea`, `ColorSlider` and `AlphaSlider` (bound to the picker) and `ColorPicker.HexField`, `.Swatches`, `.Preview` (see [Color](#color)); `shape`. Picking a preset keeps the current opacity (a preset's alpha digits are ignored, with a development warning).
|
|
501
|
-
| `ColorArea` | 2-D saturation and brightness field for an `HsvColor`, with two hidden range inputs (one Tab stop), pointer and touch dragging; mirrored in RTL.
|
|
502
|
-
| `ColorSlider` | Hue (default), saturation or brightness slider (`channel`), horizontal or vertical.
|
|
503
|
-
| `AlphaSlider` | Opacity slider over a checkerboard; `transparency` shows transparency.
|
|
504
|
-
| `SwatchPicker` | Radio group of color swatches (`items` with a `label` each).
|
|
505
|
-
| `Rating` | Star rating (`role="radiogroup"`); `RatingDisplay` is the read-only version (a fractional value draws a partly filled star; `showValue`, `count` and `compact` add the value and the number of ratings as text).
|
|
490
|
+
| Component | Description |
|
|
491
|
+
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
492
|
+
| `Field` | Label, hint, validation message (`validationState` error, warning, success or none; `error` is the shorthand for an error) and required indicator, wired to the control inside it (library controls read the Field context wherever they are in it); `orientation="horizontal"` puts the label beside the control; `size` sets the label's size and the default `size` of the text inputs and pickers inside; `label` also takes a `Label` or `InfoLabel` element, rendered in place of Field's own `<label>` (see [Forms and `Field`](#forms-and-field)). |
|
|
493
|
+
| `Label` | Form label with a required indicator (`required`: the decorative asterisk, or your own content), `size` and `weight`. |
|
|
494
|
+
| `Input` | Text input with `size` and `appearance`, `contentBefore`/`contentAfter` slots, `onValueChange(value)` next to the native `onChange`, and an `error` message; `htmlSize` is the native `size` attribute. |
|
|
495
|
+
| `Textarea` | Multi-line text input with `size`, `appearance` and an `error` message. |
|
|
496
|
+
| `Select` | Styled native `<select>` with `size`, `appearance`, `htmlSize` (visible rows) and an `error` message. |
|
|
497
|
+
| `Checkbox` | `checked`/`defaultChecked`/`onCheckedChange`, `indeterminate`, `size` (`medium`, `large`) and `shape` (`square`, `circular`), a rich `label` before or after the box (`labelPosition`), `disabledFocusable`, native form support. |
|
|
498
|
+
| `Switch` | On/off toggle (`role="switch"`), `onCheckedChange`, `size` (`small`, `medium`), a rich `label` before, after or above it (`labelPosition`), `disabledFocusable`, native form support. |
|
|
499
|
+
| `RadioGroup` | Single choice with `RadioGroup.Item` items (a rich `label` each); `orientation`, `disabled`, `onValueChange`, native form support. |
|
|
500
|
+
| `SearchBox` | Search input with a clear button; `size`, `appearance`, `onValueChange`; input attributes go to the `<input>`. The root draws the field, so `className` and `style` style the field box, and `contentBefore`/`contentAfter` sit beside the text. |
|
|
501
|
+
| `Slider` | Styled native range input, filled up to the thumb; `size` (`small`, `medium`); `onValueChange(number)`. |
|
|
502
|
+
| `SpinButton` | Numeric input with step buttons; `size`, `appearance`; typed text is a draft committed on blur or Enter; `min`, `max`, `step`, `largeStep`, `precision`; `displayValue` shows formatted text; `allowEmpty` allows a `null` value; holding a step button repeats it (see [SpinButton](#spinbutton)). |
|
|
503
|
+
| `Combobox` | Editable combobox: typing filters the options; `freeform` makes the typed text the value; a chevron (`expandIcon`) and `clearable`. `Combobox.Option`, `Combobox.OptionGroup`. |
|
|
504
|
+
| `Dropdown` | Select-only combobox (a button) with typeahead; `clearable`. `Dropdown.Option`, `Dropdown.OptionGroup`. |
|
|
505
|
+
| `TagPicker` | Multi-select combobox that shows the selection as removable tags (a list named "Selected"); `size` (`medium`, `large`, `extra-large`), `appearance`; the input is described by a summary of the selection ("Selected: Apple, Banana"), and additions and removals are announced. |
|
|
506
|
+
| `DatePicker` | Date input with a calendar dialog; `size`, `appearance`; locale-aware format and parse, `minDate`, `maxDate`, `disabledDates`, `onInvalidInput`. |
|
|
507
|
+
| `TimePicker` | Time combobox (`12h`/`24h`, `step`, `minTime`, `maxTime`); `size`, `appearance`; value is `HH:mm`; `open`/`defaultOpen`/`onOpenChange` control the list; rejected text is kept and flagged (`onInvalidInput`). |
|
|
508
|
+
| `ColorPicker` | Hex value (lowercase `#rrggbb`, or `#rrggbbaa` when not opaque) with a color area, a hue slider, a hex field, preset swatches and an optional opacity slider; with children, your own layout of `ColorArea`, `ColorSlider` and `AlphaSlider` (bound to the picker) and `ColorPicker.HexField`, `.Swatches`, `.Preview` (see [Color](#color)); `shape`. Picking a preset keeps the current opacity (a preset's alpha digits are ignored, with a development warning). |
|
|
509
|
+
| `ColorArea` | 2-D saturation and brightness field for an `HsvColor`, with two hidden range inputs (one Tab stop), pointer and touch dragging; mirrored in RTL. |
|
|
510
|
+
| `ColorSlider` | Hue (default), saturation or brightness slider (`channel`), horizontal or vertical. |
|
|
511
|
+
| `AlphaSlider` | Opacity slider over a checkerboard; `transparency` shows transparency. |
|
|
512
|
+
| `SwatchPicker` | Radio group of color swatches (`items` with a `label` each). |
|
|
513
|
+
| `Rating` | Star rating (`role="radiogroup"`); `RatingDisplay` is the read-only version (a fractional value draws a partly filled star; `showValue`, `count` and `compact` add the value and the number of ratings as text). |
|
|
506
514
|
|
|
507
515
|
### Data display
|
|
508
516
|
|
|
509
|
-
| Component | Description
|
|
510
|
-
| --------------- |
|
|
511
|
-
| `Avatar` | Image, initials or icon, with an image-failure fallback and an optional `badge`.
|
|
512
|
-
| `AvatarGroup` | Overlapping avatars; `max` adds an overflow button that lists the hidden members.
|
|
513
|
-
| `Badge` | Status or category label: `appearance` `filled`, `tint`, `outline`; semantic `color` (see [Badges](#badges)).
|
|
514
|
-
| `CounterBadge` | Count pill (`99+` above `overflowCount`) or, with `dot`, an unread dot; Badge's `color` palette; `showZero`.
|
|
515
|
-
| `PresenceBadge` | Availability badge with a distinct shape per status.
|
|
516
|
-
| `Tag` | Chip with an optional dismiss button (`dismissible`, `onDismiss`, `dismissLabel`); `onDismiss` and `dismissIcon` need `dismissible` (a development warning says so). Move focus when you remove a tag (see [Tags](#tags)).
|
|
517
|
-
| `InfoLabel` |
|
|
518
|
-
| `
|
|
519
|
-
| `
|
|
520
|
-
| `
|
|
521
|
-
| `
|
|
517
|
+
| Component | Description |
|
|
518
|
+
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
519
|
+
| `Avatar` | Image, initials or icon, with an image-failure fallback and an optional `badge`. |
|
|
520
|
+
| `AvatarGroup` | Overlapping avatars; `max` adds an overflow button that lists the hidden members. |
|
|
521
|
+
| `Badge` | Status or category label: `appearance` `filled`, `tint`, `outline`; semantic `color` (see [Badges](#badges)). |
|
|
522
|
+
| `CounterBadge` | Count pill (`99+` above `overflowCount`) or, with `dot`, an unread dot; Badge's `color` palette; `showZero`. |
|
|
523
|
+
| `PresenceBadge` | Availability badge with a distinct shape per status. |
|
|
524
|
+
| `Tag` | Chip with an optional dismiss button (`dismissible`, `onDismiss`, `dismissLabel`); `onDismiss` and `dismissIcon` need `dismissible` (a development warning says so). Move focus when you remove a tag (see [Tags](#tags)). |
|
|
525
|
+
| `InfoLabel` | A real `<label>` (`children`, `htmlFor`, `required`, `size`, `weight`, `disabled`) with an info button after it that shows `info` (text, links or other content) in a note; `openOnHover`, `infoButtonLabel`. Usable as the `label` of a Field. |
|
|
526
|
+
| `InfoButton` | A button with the info glyph that shows `info` in a `role="note"` next to it, without moving focus: opens on click, on mouse hover and on keyboard focus (`openOnHover={false}`: click only); Tab from the button enters the note; `size`. Named "Information" (`aria-label`). |
|
|
527
|
+
| `Persona` | Avatar with name, secondary text and presence. |
|
|
528
|
+
| `Divider` | Horizontal or vertical separator, optionally labelled. |
|
|
529
|
+
| `Image` | `<img>` with `fit`, `shape`, `shadow`, `bordered`; warns in development when `alt` is missing. Never wider than its parent; with the default `fit` its height follows its width. `fit="none"` keeps the top-left corner in view, `"center"` the middle. |
|
|
530
|
+
| `List` | Plain list, selectable listbox (single or multiple) or, with item `action`s, a grid; in a selectable List item values are unique (development warning). |
|
|
522
531
|
|
|
523
532
|
### Typography
|
|
524
533
|
|
|
@@ -579,9 +588,9 @@ Your `className` is merged last with `cn()`, so it replaces a conflicting class
|
|
|
579
588
|
|
|
580
589
|
### Provider
|
|
581
590
|
|
|
582
|
-
| Component | Description
|
|
583
|
-
| -------------- |
|
|
584
|
-
| `WaveProvider` | Theme (`light`, `dark`, `high-contrast`), direction and
|
|
591
|
+
| Component | Description |
|
|
592
|
+
| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
593
|
+
| `WaveProvider` | Theme (`light`, `dark`, `high-contrast`), direction, portal container and `inputDefaults` (the default `size` and `appearance` of the text inputs and pickers). |
|
|
585
594
|
|
|
586
595
|
`Portal` renders its children into `document.body` (or the provider's `portalContainer`) inside a themed `wave-portal` wrapper; use it for your own overlays.
|
|
587
596
|
|
|
@@ -693,14 +702,135 @@ export function AccountSettings({ backedUp }: { backedUp: number }) {
|
|
|
693
702
|
- **Validation states.** `validationMessage` renders below the control in the style of `validationState`: `error` (the default when a message is given) marks the control `aria-invalid` and announces the message (`role="alert"`); `warning` announces it without making the control invalid; `success` and `none` show it without announcing it. Each state but `none` shows an icon before the message; `validationMessageIcon` replaces it, and `null` removes it. `validationState="error"` without a message marks the control invalid and shows nothing. The Field root carries `data-validation-state`.
|
|
694
703
|
- **`error`** is the shorthand for an error message: `error="Enter an email address"`, or `error={true}` to mark the control invalid without a message. It wins over `validationMessage` and `validationState` (a development warning fires when both are set).
|
|
695
704
|
- **The hint** stays visible below the message, after it; the control is described by the message, then the hint.
|
|
696
|
-
- **`orientation="horizontal"`** puts the label in a start column (a third of the width) beside the control; the message and the hint stay below the control. The label's first line lines up with the control's first line: a Checkbox, Switch or RadioGroup as the first child (or a plain wrapper around them) gets
|
|
705
|
+
- **`orientation="horizontal"`** puts the label in a start column (a third of the width) beside the control; the message and the hint stay below the control. The label's first line lines up with the control's first line: a Checkbox, Switch or RadioGroup as the first child (or a plain wrapper around them) gets padding above and below its first row (6px at `medium`, 2px at `small`, 10px at `large`), as tall as an Input. The root carries `data-orientation`. The horizontal layout wraps the control, so changing `orientation` on a mounted Field remounts the control (an uncontrolled control loses its state and focus).
|
|
697
706
|
- **ProgressBar** reads the Field: the Field's label names a bar that has no name of its own, the message and the hint describe it, and the validation state (error, warning, success) colors its fill unless you set `color`. A progress bar is never invalid or required. Next to another control in a Field's wrapper element, the bar leaves the Field's label to that control (it gets an id of its own).
|
|
698
707
|
- **Choice labels.** Checkbox, Switch and `RadioGroup.Item` take any phrasing content as `label` (a link to the terms, a second line of subtext; no other form controls). It names the control; clicking its text toggles the control, and clicking a link inside it follows the link. The box, track or radio lines up with the first line of a label that wraps or has a second line (`className="items-center"` centres it instead). Arrow keys, Home and End pressed on a link inside a `RadioGroup.Item` label stay the link's. `children` are not rendered (a development warning says so). `labelPosition` puts the label `"after"` (default) or `"before"` the Checkbox and Switch, or `"above"` the Switch (settings lists). Checkbox and Switch take `disabledFocusable` (focusable, but not toggled and not submitted) and route your `aria-disabled` to the control.
|
|
699
708
|
- A `label`, `hint`, `error` or `validationMessage` that renders nothing (`[]`, such as an empty `errors.map(…)`) counts as absent: no empty message renders, the hint shows, and without `validationState="error"` the control stays valid. A control's own `aria-invalid={false}` wins over the Field's error, which still describes it.
|
|
709
|
+
- **Field `size`** (`'small'`, `'medium'`, `'large'`) sets the label's size and the default `size` of the text inputs and pickers inside it (see [Sizes and appearances](#sizes-and-appearances)). The root renders `data-size`.
|
|
710
|
+
- **Label elements.** `label` also takes a `Label` or an `InfoLabel` element, which Field renders in place of its own `<label>`. Field points it at the control (`htmlFor`) and gives it the Field's label id, `required`, label `size` and `weight="semibold"`, each only where the element leaves it unset; the element shows its own required indicator, so Field adds no asterisk. The control is named by the label text alone, since an InfoLabel's info button sits outside the `<label>`; a `RadioGroup` is named through `aria-labelledby`. Only the element itself counts, not one inside a Fragment or another element.
|
|
711
|
+
|
|
712
|
+
```tsx
|
|
713
|
+
import { Field, InfoLabel, Input, Label } from '@mortenbrudvik/waveui';
|
|
714
|
+
|
|
715
|
+
export function Credentials() {
|
|
716
|
+
return (
|
|
717
|
+
<>
|
|
718
|
+
<Field label={<InfoLabel info="Use at least 12 characters.">Password</InfoLabel>} required>
|
|
719
|
+
<Input type="password" />
|
|
720
|
+
</Field>
|
|
721
|
+
<Field label={<Label required="(required)">Email</Label>}>
|
|
722
|
+
<Input type="email" />
|
|
723
|
+
</Field>
|
|
724
|
+
</>
|
|
725
|
+
);
|
|
726
|
+
}
|
|
727
|
+
```
|
|
728
|
+
|
|
700
729
|
- One control per Field. Put wrapper or layout components (a `Tooltip`, your own row) **inside a plain `<div>`** in the Field; the library control inside is then labelled correctly.
|
|
701
730
|
- `error` on `Input`, `Select` and `Textarea`: a string renders the message after the control in a `role="alert"` element linked with `aria-describedby`/`aria-errormessage`; `error={true}` only marks the control invalid. Inside a Field that shows its own error, the message is not repeated.
|
|
702
731
|
- Value controls take part in native forms when you pass `name`, or when they are required (their own `required`, or a required `Field`): `Checkbox`, `Switch`, `RadioGroup`, `Rating`, `SpinButton`, `SwatchPicker`, `ColorPicker`, `ColorArea`, `ColorSlider` and `AlphaSlider` (the hex of the color; inside a ColorPicker they are bound and the picker submits), `Combobox`, `Dropdown`, `TagPicker`, `DatePicker` (ISO `yyyy-mm-dd`) and `TimePicker` (`HH:mm`) render a hidden input, honour `required` and `form`, and reset with their form. `SearchBox` submits through its own `<input name>` and resets with its form too. No name is generated for you.
|
|
703
732
|
|
|
733
|
+
### Sizes and appearances
|
|
734
|
+
|
|
735
|
+
The text inputs and pickers (`Input`, `Textarea`, `Select`, `SearchBox`, `SpinButton`, `Combobox`, `Dropdown`, `DatePicker`, `TimePicker` and `TagPicker`) take `size` and `appearance`; `Checkbox`, `Switch` and `Slider` take a `size` of their own.
|
|
736
|
+
|
|
737
|
+
| Prop | Values | Default |
|
|
738
|
+
| ------------ | ----------------------------------------------------------------------------------------- | --------- |
|
|
739
|
+
| `size` | `'small'` (24px tall), `'medium'` (32px), `'large'` (40px); type `CoreSize` | `medium` |
|
|
740
|
+
| `appearance` | `'outline'`, `'underline'`, `'filled-darker'`, `'filled-lighter'`; type `InputAppearance` | `outline` |
|
|
741
|
+
|
|
742
|
+
`medium` and `outline` are the 0.7 look. `Textarea` sets minimum heights (64, 80 and 96px) instead of a height. `TagPicker` has no `small` (`TagPickerSize`: `'medium'`, `'large'`, `'extra-large'`). The choice controls have their own unions: `Checkbox` `size` `'medium'` (an 18px box) or `'large'` (22px) and `shape` `'square'` or `'circular'`; `Switch` `size` `'small'` (a 32×16px track) or `'medium'` (40×20px); `Slider` `size` `'small'` (a 16px thumb on a 2px rail) or `'medium'` (a 20px thumb on a 4px rail). The icon buttons of the pickers (clear, expand, calendar) scale with `size` and keep a 24×24px target at every size; the step buttons of `SpinButton` are 24, 32 and 40px wide.
|
|
743
|
+
|
|
744
|
+
```tsx
|
|
745
|
+
import { Field, Input, WaveProvider } from '@mortenbrudvik/waveui';
|
|
746
|
+
|
|
747
|
+
export function CompactForm() {
|
|
748
|
+
return (
|
|
749
|
+
// Small filled fields below this provider, unless a Field or a control says otherwise.
|
|
750
|
+
<WaveProvider inputDefaults={{ size: 'small', appearance: 'filled-darker' }}>
|
|
751
|
+
<Field label="Name">
|
|
752
|
+
<Input />
|
|
753
|
+
</Field>
|
|
754
|
+
<Field label="Email" size="large">
|
|
755
|
+
<Input type="email" appearance="outline" />
|
|
756
|
+
</Field>
|
|
757
|
+
</WaveProvider>
|
|
758
|
+
);
|
|
759
|
+
}
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
- **Resolution order.** `size`: the control's own prop, then the surrounding `Field`'s `size`, then `WaveProvider` `inputDefaults.size`, then `medium`. `appearance`: the control's own prop, then `inputDefaults.appearance`, then `outline`. A Field or provider size that the control does not offer is skipped: a `TagPicker` in a `small` Field is `medium`. `Checkbox`, `Switch` and `Slider` read neither the Field's `size` nor `inputDefaults`.
|
|
763
|
+
- **`inputDefaults`.** `WaveProvider` takes `{ size?, appearance? }` (`InputDefaults`). A nested provider merges its own keys over the enclosing provider's, and `useWaveTheme()` returns the result.
|
|
764
|
+
- **Field `size`.** It sets the label's type ramp (`caption-1`, `body-1`, `body-2`) and, with `orientation="horizontal"`, the label's top padding, so its first line stays centred on a 24, 32 or 40px control. The validation message and the hint keep their size. Without a `size`, the label follows `inputDefaults.size`.
|
|
765
|
+
- **Filled appearances.** `filled-darker` and `filled-lighter` draw a fill from the `input-filled-*` [tokens](#color-tokens) and no visible stroke, so a filled field needs a visible label (a placeholder is not one). Put `filled-darker` on the page background and `filled-lighter` on a surface other than the page background (a card, a panel): `filled-lighter` is the page background color. Windows High Contrast (forced colors) and the high-contrast theme draw a boundary on every appearance. `underline` has only a bottom stroke.
|
|
766
|
+
- **The focus and error looks** are the same in every appearance: the bottom border is 2px in the focus color while the field has focus, and an invalid field keeps its other borders red, also while it is focused (`underline` shows the focus indicator alone).
|
|
767
|
+
- **`htmlSize`.** The native `size` attribute of `Input` (the width in characters) and `Select` (the number of visible rows) is `htmlSize`. A number as `size` still sets the attribute, but is deprecated: it warns once in development and is removed in 1.0. On `Slider` a numeric `size` has no effect and warns once.
|
|
768
|
+
- **Styling hooks.** Every one of these controls renders `data-size`, and the text inputs and pickers `data-appearance`, with the resolved value, on the element that receives your `className` (the `<input>`, `<textarea>` or `<select>`, or the wrapper for `Input` with `contentBefore`/`contentAfter` and for the composite controls). `Checkbox` also renders `data-shape`. Target them with `[data-appearance=underline]` in CSS or `data-[appearance=underline]:` in Tailwind.
|
|
769
|
+
|
|
770
|
+
### SpinButton
|
|
771
|
+
|
|
772
|
+
```tsx
|
|
773
|
+
import * as React from 'react';
|
|
774
|
+
import { SpinButton } from '@mortenbrudvik/waveui';
|
|
775
|
+
|
|
776
|
+
export function Prices() {
|
|
777
|
+
const [price, setPrice] = React.useState(12.5);
|
|
778
|
+
const [quantity, setQuantity] = React.useState<number | null>(null);
|
|
779
|
+
return (
|
|
780
|
+
<>
|
|
781
|
+
<SpinButton
|
|
782
|
+
aria-label="Price"
|
|
783
|
+
value={price}
|
|
784
|
+
onValueChange={setPrice}
|
|
785
|
+
step={0.5}
|
|
786
|
+
precision={2}
|
|
787
|
+
displayValue={`$${price.toFixed(2)}`}
|
|
788
|
+
className="w-full"
|
|
789
|
+
/>
|
|
790
|
+
<SpinButton
|
|
791
|
+
aria-label="Quantity"
|
|
792
|
+
allowEmpty
|
|
793
|
+
min={1}
|
|
794
|
+
value={quantity}
|
|
795
|
+
onValueChange={setQuantity}
|
|
796
|
+
/>
|
|
797
|
+
</>
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
- **`displayValue`** is the text shown for the value while the field is not being edited (`$12.50`), and its `aria-valuetext`. While the field has focus and can be edited it shows the plain number, so typing edits `12.5`, not `$12.50`. It applies only to a controlled `value`: an uncontrolled SpinButton ignores it and warns in development.
|
|
803
|
+
- **`precision`** (0 to 20) rounds every committed value, typed or stepped, to that many decimals. It does not pad: `precision={2}` shows `12.5`, so use `displayValue` for `12.50`.
|
|
804
|
+
- **`allowEmpty`** lets the value be `null`: clearing the text and committing it (blur or Enter) empties the field, `onValueChange` receives `null`, and `aria-valuenow` is omitted. The prop takes the literal `true`; a `boolean` variable fits neither prop type, so branch the JSX or spread `{ allowEmpty: true, value }`. The deprecated `onChange` is not offered in this mode. A `required` SpinButton (or in a required Field) blocks submitting an empty value. Stepping from an empty value starts at 0 and then clamps to `min`/`max`. Without `allowEmpty`, clearing the text still restores the last value.
|
|
805
|
+
- **Holding a step button** repeats the step after 300 ms, faster after that, with a mouse, a finger or a pen. A short press steps once, when it is released, so a finger that starts a scroll on a button changes nothing. The step buttons never take focus.
|
|
806
|
+
- **Width.** An unsized SpinButton is as wide as in 0.7 (114px at `medium`); a root you size (`className="w-full"`) widens the input. Its height follows `size` like the other fields.
|
|
807
|
+
|
|
808
|
+
### Rating
|
|
809
|
+
|
|
810
|
+
```tsx
|
|
811
|
+
import { Rating, RatingDisplay } from '@mortenbrudvik/waveui';
|
|
812
|
+
|
|
813
|
+
export function Reviews() {
|
|
814
|
+
return (
|
|
815
|
+
<>
|
|
816
|
+
<Rating aria-label="Your rating" step={0.5} color="brand" defaultValue={3.5} />
|
|
817
|
+
<RatingDisplay value={4.6} color="neutral" showValue count={1160} />
|
|
818
|
+
{/* One Rating.Item per value from 1 to max draws the stars yourself. */}
|
|
819
|
+
<Rating aria-label="Your mood" max={3} defaultValue={2}>
|
|
820
|
+
<Rating.Item value={1} />
|
|
821
|
+
<Rating.Item value={2} />
|
|
822
|
+
<Rating.Item value={3} iconFilled="♥" iconOutline="♡" />
|
|
823
|
+
</Rating>
|
|
824
|
+
</>
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
- **Half stars.** With `step={0.5}` each star is still one pointer target (24×24px or larger): a click or tap chooses the half or the whole star by the pointer's position over it (the start half mirrors in RTL). Two visually hidden radios per star serve the keyboard and screen readers, named "2.5 stars" and "3 stars" (`labels.star`). The arrow keys move by half a star. With a `name`, the hidden input submits `2.5`. A controlled value between two steps (2.7) checks no radio and is drawn as the step below it; the arrow keys move it to the next or previous step.
|
|
830
|
+
- **`color`** colors the filled stars: `'marigold'` (the default), `'brand'` or `'neutral'` (`RatingColor`); unfilled stars keep a 3:1 outline in every color. The root renders `data-color`. On `Rating` and `RatingDisplay` this narrows the `color` string that `React.HTMLAttributes` declares.
|
|
831
|
+
- **Icons.** `iconFilled` and `iconOutline` replace the star glyphs, as a pair (a filled and an unfilled star must differ by shape): set only one and a development warning asks for the other. They are decorative. A partly filled star in `RatingDisplay` clips the filled glyph over the outline glyph.
|
|
832
|
+
- **`Rating.Item`** (`RatingDisplay.Item`, `RatingItem`) renders one star from its root's context. When `children` render content, they replace the generated stars: pass one item per value from 1 to `max`. An item's own icon pair wins over its root's. A duplicated value, a value that is not a whole number from 1 to `max` and a missing value each warn once in development. A `compact` RatingDisplay ignores its children.
|
|
833
|
+
|
|
704
834
|
### Value callbacks
|
|
705
835
|
|
|
706
836
|
`onChange` is the native DOM change event (`Input`, `Textarea`, `Select`, `Slider`). State callbacks are named after the state and receive the value:
|
|
@@ -1416,12 +1546,13 @@ The names and hidden texts that components render themselves are English by defa
|
|
|
1416
1546
|
| `DatePicker` | `labels` (`clear`, `openCalendar`, `previousMonth`, `nextMonth`, and the error texts `invalidDate(pattern)`, `outOfRange(min, max)`, `unavailableDate`) |
|
|
1417
1547
|
| `TimePicker` | `labels` (`clear`, `expand`, `list`, `noTimes`, `noMatches`, and the error texts `invalidTime(format)`, `outOfRange(min, max)`) |
|
|
1418
1548
|
| `TagPicker` | `labels` (`remove(label)`, `selected`, `summary(labels)`, `added(label, count)`, `removed(label, count)`, `noMatches`) |
|
|
1419
|
-
| `Rating` | `labels` (`star(value, max)`)
|
|
1549
|
+
| `Rating` | `labels` (`star(value, max)`; it also names the half values of a `step={0.5}` Rating, "2.5 stars") |
|
|
1420
1550
|
| `RatingDisplay` | `labels` (`rating(value, max, formattedValue)`, `count(count, formattedCount)`); `locale` formats the value and the count (pass it when rendering on the server) |
|
|
1421
1551
|
| `SpinButton` | `labels` (`increment`, `decrement`) |
|
|
1422
1552
|
| `DataGrid` | `labels` (`selectAll`, `selectionHeader`); each row's fallback name "Select row": `DataGrid.Row` `selectionLabel` |
|
|
1423
1553
|
| `AvatarGroup` | `overflowLabel`, `unnamedMemberLabel` |
|
|
1424
|
-
| `
|
|
1554
|
+
| `InfoButton` | `aria-label` (the button and its note; default "Information") |
|
|
1555
|
+
| `InfoLabel`, `SplitButton` | `infoButtonLabel` (InfoLabel's button is named "‹label› ‹infoButtonLabel›"), `menuButtonLabel` |
|
|
1425
1556
|
| `Spinner`, `Skeleton.Group` | `label` |
|
|
1426
1557
|
|
|
1427
1558
|
Without a text prop, these defaults are replaced through `aria-label`: the PresenceBadge status names ("Available", …: `aria-label` on the badge), the MessageBar "Dismiss" and SearchBox "Clear search" button names (`dismiss={{ 'aria-label': 'Lukk' }}`, which keeps the default icon), and the names of the Breadcrumb, Pagination, Nav, Stepper, Carousel and Toaster regions ("Breadcrumb", "Pagination", "Navigation", "Progress", "Carousel", "Notifications"). The placeholders of Dropdown, DatePicker, TimePicker and SearchBox are `placeholder` props, and ColorPicker's default presets are replaced through `presets`.
|
|
@@ -1430,13 +1561,13 @@ Without a text prop, these defaults are replaced through `aria-label`: the Prese
|
|
|
1430
1561
|
|
|
1431
1562
|
## Keyboard support
|
|
1432
1563
|
|
|
1433
|
-
As implemented in 0.
|
|
1564
|
+
As implemented in 0.9. Buttons, links, checkboxes, switches and the trigger buttons of Accordion, Carousel, Nav, Breadcrumb and Pagination are native elements: Tab to reach them, Enter or Space to activate. A Link or `Button as="a"` without `href`, and a Button or Link rendered as a `div` or `span`, are buttons: Tab reaches them, Enter (key down) and Space (key up) activate them. A `disabledFocusable` control stays in the Tab order but Enter, Space and clicks do nothing.
|
|
1434
1565
|
|
|
1435
1566
|
| Component | Keys |
|
|
1436
1567
|
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1437
1568
|
| Toolbar | One Tab stop (the last focused control; focusing a nested composite, such as a radio group or tab list, or a text field, select, slider or spin button keeps it where it was). Left/Right (Up/Down when vertical) move and wrap, Home/End jump; mirrored in RTL; natively disabled controls and controls hidden with CSS are skipped, while `disabledFocusable` controls stay reachable (a Tooltip on them opens on focus). Text fields, selects, sliders, spin buttons and editable comboboxes keep their own arrow keys; a Dropdown keeps Up/Down, Home and End for its list, but Left/Right move past it. A nested composite keeps its own Tab stop and arrow keys; a `Toolbar.RadioGroup` is none: its radios are part of the arrow order, and Up/Down (Left/Right when vertical, mirrored in RTL) also move among them, wrapping inside the group. The arrows never press a toggle or check a radio: Space and Enter do. |
|
|
1438
1569
|
| RadioGroup, SwatchPicker | One Tab stop. All four arrows move and select (wrapping), Home/End jump; Left/Right mirrored in RTL. Keys pressed on a link inside a radio's label stay the link's. |
|
|
1439
|
-
| Rating | Right/Up one
|
|
1570
|
+
| Rating | Right/Up one step more (a star, or half a star with `step={0.5}`), Left/Down one fewer (never below `step`), Home/End `step`/`max`; mirrored in RTL. A pointer click on a half-star Rating chooses the half or the whole star by position; Space and Enter on a focused radio choose that radio's own value. |
|
|
1440
1571
|
| TabList | One Tab stop (the selected tab). Left/Right (Up/Down when vertical) move and select, Home/End; with `selectTabOnFocus={false}` they only move focus, and Enter or Space selects the focused tab; disabled tabs skipped; mirrored in RTL. |
|
|
1441
1572
|
| Tree | One Tab stop. Up/Down, Home/End; Right expands or moves to the first child, Left collapses or moves to the parent (mirrored in RTL); Enter activates; Space activates, or in a checkbox tree (`selectionMode="multiple"`) toggles the focused item's check; `*` expands siblings; type to jump (a Space within 500 ms of a letter continues the search). Row actions: Tab from the focused item enters them and Shift+Tab returns (`navigationMode="tree"`); with `navigationMode="treegrid"` the "next" arrow moves into them (on an expanded parent too, instead of to its first child), "previous" returns, and Up/Down move between items. |
|
|
1442
1573
|
| List (selectable) | One Tab stop. Up/Down (wrapping), Home/End, Enter/Space toggle, typeahead above 7 items (a Space within 500 ms of a letter continues the search). With item actions (grid): Up/Down between rows, Left/Right into the actions, Enter/F2 into a text field, Escape back. |
|
|
@@ -1444,12 +1575,12 @@ As implemented in 0.8. Buttons, links, checkboxes, switches and the trigger butt
|
|
|
1444
1575
|
| Menu | Trigger: Enter/Space/Down open and focus the first item, Up opens on the last; a trigger with `aria-disabled="true"` (a `disabledFocusable` MenuButton or SplitButton) ignores them and its click. Menu: Up/Down (wrapping), Home/End, typeahead, Enter/Space activate (a Space within 500 ms of a letter continues the search); on a checkbox, radio or switch item Space changes it and keeps the menu open, Enter changes it and closes a popup menu; on `Menu.ItemLink` Enter is the browser's link activation. A submenu's item: Right (Left in RTL), Enter and Space open the submenu and focus its first item; in a submenu Left (Right in RTL) and Escape close only it and return focus to its item. `Menu.SplitGroup`: Right (Left in RTL) moves from the action to the submenu button, Left back. Escape closes and returns focus, Tab closes every level. Context menu (`openOnContext`): Shift+F10 or the ContextMenu key on the region opens it at the focused element; Escape and item activation return focus there, and Tab moves on from it. |
|
|
1445
1576
|
| Combobox, TagPicker, TimePicker | Down/Up open and move, Alt+Down opens, typing makes the first match active (not in a `freeform` Combobox), Enter commits the active option (with no active option, Enter submits the form; TimePicker instead never submits while its text is edited: a complete time within the bounds is committed, erased text clears the value, other text is kept and flagged invalid, and the list closes; leaving the input with edited text settles it the same way and closes the list), Alt+Up and Tab close, Escape closes and then discards typed text. The chevron button (Combobox, TimePicker) is not a Tab stop; the clear button (`clearable`) is a Tab stop after the input. Tab from erased TimePicker text clears the value first, so focus moves past the clear button that goes with it. TagPicker: Backspace in the empty input focuses the last tag, Backspace/Delete removes it. |
|
|
1446
1577
|
| Dropdown | Down/Up/Home/End and typing open and move, PageUp/PageDown move by 10, Enter/Space commit (a Space within 500 ms of a letter continues the search), Alt+Up and Tab commit and close, Escape closes. The clear button (`clearable`) is a Tab stop after the combobox button. |
|
|
1447
|
-
| SpinButton | Up/Down step, PageUp/PageDown large step, Home/End jump to a finite min/max (otherwise they move the caret); Enter commits typed text, Escape reverts it.
|
|
1578
|
+
| SpinButton | Up/Down step, PageUp/PageDown large step, Home/End jump to a finite min/max (otherwise they move the caret; with Shift they select text); Enter commits typed text, Escape reverts it. With the pointer, holding a step button repeats the step; a short press steps once on release. |
|
|
1448
1579
|
| SearchBox | Escape clears the text and keeps focus (the key is consumed, so an enclosing Dialog, Drawer or Popover stays open); in an empty field Escape reaches the enclosing overlay. |
|
|
1449
1580
|
| DatePicker | Alt+Down opens the calendar. The clear button (`clearable`) is a Tab stop between the input and the calendar button; Tab from erased text clears the value first and moves on to the calendar button. Calendar: arrows by day/week (mirrored in RTL), PageUp/PageDown by month, Shift+PageUp/PageDown by year, Home/End week start/end, Enter/Space select, Escape closes; Tab stays inside. |
|
|
1450
1581
|
| Dialog, Drawer | Focus is trapped; Escape closes; focus returns to the first of these that can take focus: `finalFocusRef`, the element that had focus when the modal opened (a trigger's wrapper span resolves to the element inside it), the trigger, an element next to where that opener was. |
|
|
1451
1582
|
| Popover, TeachingPopover | Escape closes. When focus was inside (or lost to `<body>`), Popover returns it to its trigger, TeachingPopover to where focus was before it opened; a close by hover moves no focus. In the Tab order the content follows its trigger (TeachingPopover with `target`: the target): Tab from the trigger enters it, Tab past its end continues after the trigger, Shift+Tab from the element after the trigger enters it at its last element. For a trigger outside the tab order it follows the tab stop before the trigger; with no tab stop before the trigger or target, it is reached at the end of the page. A Tab lap visits it once: Tab from the last element of the page leaves the page, and Shift+Tab from outside the page reaches the page's last element. Focus leaving it does not close it. A context popover (`openOnContext`): Shift+F10 or the ContextMenu key on the region opens it and moves focus into the content, and Escape returns focus to the element that had it; opened by a right click, it is reached by Tab from that element. |
|
|
1452
|
-
| Tooltip, InfoLabel
|
|
1583
|
+
| Tooltip, InfoButton, InfoLabel | Open on keyboard focus (Tooltip after `openDelay`); Escape closes. InfoButton and InfoLabel: a click pins the note; focus stays on the button when the note opens, Tab from the button enters the note's first focusable element (a link) and Tab past its last element continues after the button; Shift+Tab returns; Escape closes it and returns focus to the button when it was in the note. `openOnHover={false}` opens it on a click (Enter, Space) only. |
|
|
1453
1584
|
| Card (selectable) | With the default `selectionControl="card"`: Enter (key down) or Space (key up) selects. With `"checkbox"`: the built-in checkbox. |
|
|
1454
1585
|
| Stepper | Each reachable step is a Tab stop; Enter/Space activate. |
|
|
1455
1586
|
| Slider | Native range keys. |
|
|
@@ -1474,7 +1605,7 @@ Typeahead (Menu, selectable List, Tree, Dropdown) accepts characters typed with
|
|
|
1474
1605
|
| `usePresence(visible, options?)`, `<Presence visible>` | Mount and unmount an element with CSS enter and exit motion (`data-presence` phases; see [Enter and exit motion](#enter-and-exit-motion)). |
|
|
1475
1606
|
| `useFieldControl(props, options?)` | Merge a custom control's labelling props with the surrounding `Field` (its label, validation message, hint and state). |
|
|
1476
1607
|
| `useAnnounce()`, `announce(message, politeness?)` | Screen-reader announcements through a shared live region. |
|
|
1477
|
-
| `useWaveTheme()` | Current theme, direction
|
|
1608
|
+
| `useWaveTheme()` | Current theme, direction, portal container and `inputDefaults`. |
|
|
1478
1609
|
| `useToastController()` | `dispatchToast` (content or options) / `dismissToast` / `dismissAllToasts` inside `<Toaster>`. |
|
|
1479
1610
|
| `createToaster()` | A toast controller for code outside components; bind it with `<Toaster toaster={handle}>` (see [Toasts](#toasts)). Server-safe. |
|
|
1480
1611
|
| `useIsOverflowing(target)`, `useOverflowMenu()`, `useIsOverflowItemVisible(id)` | Overflow detection. |
|
|
@@ -1486,6 +1617,21 @@ Typeahead (Menu, selectable List, Tree, Dropdown) accepts characters typed with
|
|
|
1486
1617
|
| `resolveSlot`, `renderSlot` | The slot helpers the components use. |
|
|
1487
1618
|
| `getThemeClassName(theme)` | The theme classes of a theme. |
|
|
1488
1619
|
|
|
1620
|
+
## Upgrading from 0.8
|
|
1621
|
+
|
|
1622
|
+
0.9 removes nothing public; these changes can still affect your setup, tests and styles:
|
|
1623
|
+
|
|
1624
|
+
1. Text controls, pickers, choice controls, Field, Rating and RatingDisplay render new data attributes (`data-size`, `data-appearance`, `data-shape`, `data-color`): a test that asserts a control's exact attributes changes. Nothing changes visually at the defaults, except items 4 and 6.
|
|
1625
|
+
2. A numeric `size` on `Input` and `Select` is deprecated: use `htmlSize` (a number still sets the native attribute and warns once in development). On `Slider` a numeric `size` has no effect: it is no longer rendered and warns once.
|
|
1626
|
+
3. `InfoLabel` renders a real `<label>` (point it at a control with `htmlFor`), and its `id` moves from the root to that `<label>`. The label content moves to `children` (`label` still works and warns once), and the button is named "‹label› Information". The popup is a `role="note"` with a beak that can hold links, and it is no longer `aria-hidden`: Tab from the open button enters it. The label text takes the `Label` type ramp and color, so a `className` on the root that changes the text size or color no longer reaches it.
|
|
1627
|
+
4. `SpinButton` is 32px tall like the other fields (0.7: 34px). A root you size (`className="w-full"`) now widens the input; an unsized one keeps its width. A step button steps on click (not on the press) and repeats while it is held, and Shift+Home and Shift+End select text instead of jumping to the bounds.
|
|
1628
|
+
5. `Field` renders a `Label` or `InfoLabel` element passed as `label` itself (0.7 wrapped it in a second `<label>`).
|
|
1629
|
+
6. A focused invalid field draws its bottom border in the focus color; the other borders stay red (0.7: all red).
|
|
1630
|
+
7. `Rating` and `RatingDisplay` `color` is a `RatingColor` (`'neutral' | 'brand' | 'marigold'`): it narrows the `color?: string` inherited from `React.HTMLAttributes`. Both gain the static member `Item` and render their `children` (0.7 ignored them).
|
|
1631
|
+
8. `WaveContextValue` (the result of `useWaveTheme()`) gains `inputDefaults`: code that builds one (a test double) adds it. `InputProps`, `SelectProps` and `SliderProps` declare their own `size`, and `SpinButtonProps` gains `allowEmpty?: false` next to the new `SpinButtonAllowEmptyProps`.
|
|
1632
|
+
|
|
1633
|
+
The CHANGELOG's [0.9.0 "Upgrading from 0.8"](CHANGELOG.md#upgrading-from-08) and [0.9.0 "Changed" section](CHANGELOG.md#changed) list every behaviour, DOM, visual and type change.
|
|
1634
|
+
|
|
1489
1635
|
## Upgrading from 0.7
|
|
1490
1636
|
|
|
1491
1637
|
0.8 removes nothing public; these changes can still affect your tests and styles:
|
|
@@ -1502,7 +1648,7 @@ Typeahead (Menu, selectable List, Tree, Dropdown) accepts characters typed with
|
|
|
1502
1648
|
10. `ToastController['dispatchToast']` is overloaded: a test double that implements it must accept content too.
|
|
1503
1649
|
11. A `dispatchToast` options argument that is not a plain object (a class instance, `Object.create(defaults)`) is now read as React content and throws when it renders: pass a plain object (spread it: `{ ...defaults, title }`).
|
|
1504
1650
|
|
|
1505
|
-
The CHANGELOG's [0.8.0 "Changed" section](CHANGELOG.md#changed) lists every behaviour, DOM and type change.
|
|
1651
|
+
The CHANGELOG's [0.8.0 "Changed" section](CHANGELOG.md#changed-1) lists every behaviour, DOM and type change.
|
|
1506
1652
|
|
|
1507
1653
|
## Upgrading from 0.6
|
|
1508
1654
|
|
|
@@ -1518,7 +1664,7 @@ The CHANGELOG's [0.8.0 "Changed" section](CHANGELOG.md#changed) lists every beha
|
|
|
1518
1664
|
8. Wave now requires tailwind-merge 3.7, so an axis shorthand in your `className` (`px-6`) replaces a component's own logical side class of the same variant (`pe-8` on `Dialog.Title`) instead of losing to it in the CSS: write `px-6 pe-8` to keep the side.
|
|
1519
1665
|
9. Wave requires Node.js 22.12 or later (`engines`; Node.js 20 reached its end of life on 2026-04-30). npm and pnpm warn on an older Node.js (npm stops with `engine-strict`), and Yarn 1 refuses to install.
|
|
1520
1666
|
|
|
1521
|
-
The CHANGELOG's [0.7.0 "Changed" section](CHANGELOG.md#changed-
|
|
1667
|
+
The CHANGELOG's [0.7.0 "Changed" section](CHANGELOG.md#changed-2) lists every behaviour, DOM and type change.
|
|
1522
1668
|
|
|
1523
1669
|
## Upgrading from 0.5
|
|
1524
1670
|
|
|
@@ -1533,11 +1679,11 @@ The CHANGELOG's [0.7.0 "Changed" section](CHANGELOG.md#changed-1) lists every be
|
|
|
1533
1679
|
7. RatingDisplay formats its accessible name with the runtime locale when `locale` is omitted: pass `locale` when rendering on the server.
|
|
1534
1680
|
8. Badge `color="important"` becomes a neutral color in 1.0: switch to `color="severe"` to keep the orange look.
|
|
1535
1681
|
|
|
1536
|
-
The CHANGELOG's [0.6.0 "Changed" section](CHANGELOG.md#changed-
|
|
1682
|
+
The CHANGELOG's [0.6.0 "Changed" section](CHANGELOG.md#changed-3) lists every behaviour, DOM and type change.
|
|
1537
1683
|
|
|
1538
1684
|
## Upgrading from 0.4
|
|
1539
1685
|
|
|
1540
|
-
npm went from 0.4.0 to 0.7.0: 0.5.0 and 0.6.0 were never published, and their changes ship in 0.7.0. From 0.4.0, take these steps, then those of [Upgrading from 0.5](#upgrading-from-05), [Upgrading from 0.6](#upgrading-from-06)
|
|
1686
|
+
npm went from 0.4.0 to 0.7.0: 0.5.0 and 0.6.0 were never published, and their changes ship in 0.7.0. From 0.4.0, take these steps, then those of [Upgrading from 0.5](#upgrading-from-05), [Upgrading from 0.6](#upgrading-from-06), [Upgrading from 0.7](#upgrading-from-07) and, for 0.9, [Upgrading from 0.8](#upgrading-from-08).
|
|
1541
1687
|
|
|
1542
1688
|
1. The npm package name is unchanged (`@mortenbrudvik/waveui`, as in 0.4.0). Replace `waveui` imports copied from the 0.4 guide, and a git or local dependency named `waveui`, with `@mortenbrudvik/waveui`.
|
|
1543
1689
|
2. Styles: without Tailwind, keep `import '@mortenbrudvik/waveui/styles'` and make sure a `WaveProvider` wraps the app; with Tailwind 4, switch to `@import '@mortenbrudvik/waveui/tailwind';` after `@import 'tailwindcss';`. Import `preflight.css` if you relied on Wave's Preflight.
|