@mortenbrudvik/waveui 0.12.0 → 0.14.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 +362 -60
- package/dist/components/data-display/Avatar.cjs +1 -1
- package/dist/components/data-display/Avatar.cjs.map +1 -1
- package/dist/components/data-display/Avatar.colors.cjs +2 -0
- package/dist/components/data-display/Avatar.colors.cjs.map +1 -0
- package/dist/components/data-display/Avatar.colors.mjs +45 -0
- package/dist/components/data-display/Avatar.colors.mjs.map +1 -0
- package/dist/components/data-display/Avatar.context.cjs +1 -1
- package/dist/components/data-display/Avatar.context.cjs.map +1 -1
- package/dist/components/data-display/Avatar.context.mjs +4 -2
- package/dist/components/data-display/Avatar.context.mjs.map +1 -1
- package/dist/components/data-display/Avatar.mjs +103 -96
- package/dist/components/data-display/Avatar.mjs.map +1 -1
- package/dist/components/data-display/Avatar.sizes.cjs +2 -0
- package/dist/components/data-display/Avatar.sizes.cjs.map +1 -0
- package/dist/components/data-display/Avatar.sizes.mjs +41 -0
- package/dist/components/data-display/Avatar.sizes.mjs.map +1 -0
- package/dist/components/data-display/AvatarGroup.cjs +1 -1
- package/dist/components/data-display/AvatarGroup.cjs.map +1 -1
- package/dist/components/data-display/AvatarGroup.context.cjs +2 -0
- package/dist/components/data-display/AvatarGroup.context.cjs.map +1 -0
- package/dist/components/data-display/AvatarGroup.context.mjs +9 -0
- package/dist/components/data-display/AvatarGroup.context.mjs.map +1 -0
- package/dist/components/data-display/AvatarGroup.mjs +65 -122
- package/dist/components/data-display/AvatarGroup.mjs.map +1 -1
- package/dist/components/data-display/AvatarGroup.partition.cjs +2 -0
- package/dist/components/data-display/AvatarGroup.partition.cjs.map +1 -0
- package/dist/components/data-display/AvatarGroup.partition.mjs +14 -0
- package/dist/components/data-display/AvatarGroup.partition.mjs.map +1 -0
- package/dist/components/data-display/AvatarGroup.parts.cjs +2 -0
- package/dist/components/data-display/AvatarGroup.parts.cjs.map +1 -0
- package/dist/components/data-display/AvatarGroup.parts.mjs +178 -0
- package/dist/components/data-display/AvatarGroup.parts.mjs.map +1 -0
- package/dist/components/data-display/InteractionTag.cjs +1 -1
- package/dist/components/data-display/InteractionTag.cjs.map +1 -1
- package/dist/components/data-display/InteractionTag.mjs +36 -33
- package/dist/components/data-display/InteractionTag.mjs.map +1 -1
- package/dist/components/data-display/List.cjs +1 -1
- package/dist/components/data-display/List.cjs.map +1 -1
- package/dist/components/data-display/List.mjs +245 -195
- package/dist/components/data-display/List.mjs.map +1 -1
- package/dist/components/data-display/List.registry.cjs.map +1 -1
- package/dist/components/data-display/List.registry.mjs.map +1 -1
- package/dist/components/data-display/Persona.cjs +1 -1
- package/dist/components/data-display/Persona.cjs.map +1 -1
- package/dist/components/data-display/Persona.mjs +96 -37
- package/dist/components/data-display/Persona.mjs.map +1 -1
- package/dist/components/data-display/PresenceBadge.cjs +1 -1
- package/dist/components/data-display/PresenceBadge.cjs.map +1 -1
- package/dist/components/data-display/PresenceBadge.mjs +42 -28
- package/dist/components/data-display/PresenceBadge.mjs.map +1 -1
- package/dist/components/data-display/Tag.cjs +1 -1
- package/dist/components/data-display/Tag.cjs.map +1 -1
- package/dist/components/data-display/Tag.mjs +111 -108
- package/dist/components/data-display/Tag.mjs.map +1 -1
- package/dist/components/layout/Card.cjs +1 -1
- package/dist/components/layout/Card.cjs.map +1 -1
- package/dist/components/layout/Card.context.cjs +2 -0
- package/dist/components/layout/Card.context.cjs.map +1 -0
- package/dist/components/layout/Card.context.mjs +14 -0
- package/dist/components/layout/Card.context.mjs.map +1 -0
- package/dist/components/layout/Card.mjs +138 -92
- package/dist/components/layout/Card.mjs.map +1 -1
- package/dist/components/layout/Card.preview.cjs +2 -0
- package/dist/components/layout/Card.preview.cjs.map +1 -0
- package/dist/components/layout/Card.preview.mjs +22 -0
- package/dist/components/layout/Card.preview.mjs.map +1 -0
- package/dist/components/layout/Carousel.button.cjs +2 -0
- package/dist/components/layout/Carousel.button.cjs.map +1 -0
- package/dist/components/layout/Carousel.button.mjs +34 -0
- package/dist/components/layout/Carousel.button.mjs.map +1 -0
- package/dist/components/layout/Carousel.cjs +1 -1
- package/dist/components/layout/Carousel.cjs.map +1 -1
- package/dist/components/layout/Carousel.context.cjs +2 -0
- package/dist/components/layout/Carousel.context.cjs.map +1 -0
- package/dist/components/layout/Carousel.context.mjs +24 -0
- package/dist/components/layout/Carousel.context.mjs.map +1 -0
- package/dist/components/layout/Carousel.drag.cjs +2 -0
- package/dist/components/layout/Carousel.drag.cjs.map +1 -0
- package/dist/components/layout/Carousel.drag.mjs +79 -0
- package/dist/components/layout/Carousel.drag.mjs.map +1 -0
- package/dist/components/layout/Carousel.groups.cjs +2 -0
- package/dist/components/layout/Carousel.groups.cjs.map +1 -0
- package/dist/components/layout/Carousel.groups.mjs +23 -0
- package/dist/components/layout/Carousel.groups.mjs.map +1 -0
- package/dist/components/layout/Carousel.mjs +288 -150
- package/dist/components/layout/Carousel.mjs.map +1 -1
- package/dist/components/layout/Carousel.styles.cjs +2 -0
- package/dist/components/layout/Carousel.styles.cjs.map +1 -0
- package/dist/components/layout/Carousel.styles.mjs +30 -0
- package/dist/components/layout/Carousel.styles.mjs.map +1 -0
- package/dist/components/layout/Overflow.cjs +1 -1
- package/dist/components/layout/Overflow.cjs.map +1 -1
- package/dist/components/layout/Overflow.mjs +240 -192
- package/dist/components/layout/Overflow.mjs.map +1 -1
- package/dist/components/layout/Overflow.store.cjs +2 -0
- package/dist/components/layout/Overflow.store.cjs.map +1 -0
- package/dist/components/layout/Overflow.store.mjs +209 -0
- package/dist/components/layout/Overflow.store.mjs.map +1 -0
- package/dist/components/layout/TabList.cjs +1 -1
- package/dist/components/layout/TabList.cjs.map +1 -1
- package/dist/components/layout/TabList.mjs +163 -124
- package/dist/components/layout/TabList.mjs.map +1 -1
- package/dist/components/navigation/Breadcrumb.cjs +1 -1
- package/dist/components/navigation/Breadcrumb.cjs.map +1 -1
- package/dist/components/navigation/Breadcrumb.mjs +239 -84
- package/dist/components/navigation/Breadcrumb.mjs.map +1 -1
- package/dist/components/overlays/Dialog.slots.cjs +1 -1
- package/dist/components/overlays/Dialog.slots.cjs.map +1 -1
- package/dist/components/overlays/Dialog.slots.mjs +19 -15
- package/dist/components/overlays/Dialog.slots.mjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.cjs +1 -1
- package/dist/components/overlays/TeachingPopover.cjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.context.cjs +2 -0
- package/dist/components/overlays/TeachingPopover.context.cjs.map +1 -0
- package/dist/components/overlays/TeachingPopover.context.mjs +51 -0
- package/dist/components/overlays/TeachingPopover.context.mjs.map +1 -0
- package/dist/components/overlays/TeachingPopover.mjs +15 -185
- package/dist/components/overlays/TeachingPopover.mjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.parts.cjs +2 -0
- package/dist/components/overlays/TeachingPopover.parts.cjs.map +1 -0
- package/dist/components/overlays/TeachingPopover.parts.mjs +398 -0
- package/dist/components/overlays/TeachingPopover.parts.mjs.map +1 -0
- package/dist/components/overlays/TeachingPopover.root.cjs +2 -0
- package/dist/components/overlays/TeachingPopover.root.cjs.map +1 -0
- package/dist/components/overlays/TeachingPopover.root.mjs +150 -0
- package/dist/components/overlays/TeachingPopover.root.mjs.map +1 -0
- package/dist/components/overlays/TeachingPopover.stack.cjs +2 -0
- package/dist/components/overlays/TeachingPopover.stack.cjs.map +1 -0
- package/dist/components/overlays/TeachingPopover.stack.mjs +86 -0
- package/dist/components/overlays/TeachingPopover.stack.mjs.map +1 -0
- package/dist/components/table/DataGrid.cjs +1 -1
- package/dist/components/table/DataGrid.cjs.map +1 -1
- package/dist/components/table/DataGrid.mjs +540 -311
- package/dist/components/table/DataGrid.mjs.map +1 -1
- package/dist/components/table/Table.cjs +1 -1
- package/dist/components/table/Table.cjs.map +1 -1
- package/dist/components/table/Table.mjs +183 -60
- package/dist/components/table/Table.mjs.map +1 -1
- package/dist/components/table/Table.shared.cjs +2 -0
- package/dist/components/table/Table.shared.cjs.map +1 -0
- package/dist/components/table/Table.shared.mjs +65 -0
- package/dist/components/table/Table.shared.mjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2299 -213
- package/dist/index.d.ts +2299 -213
- package/dist/index.mjs +135 -127
- package/dist/lib/breadcrumb.cjs +2 -0
- package/dist/lib/breadcrumb.cjs.map +1 -0
- package/dist/lib/breadcrumb.mjs +26 -0
- package/dist/lib/breadcrumb.mjs.map +1 -0
- package/dist/lib/classNames.cjs +1 -1
- package/dist/lib/classNames.cjs.map +1 -1
- package/dist/lib/classNames.mjs +143 -95
- package/dist/lib/classNames.mjs.map +1 -1
- package/dist/lib/events.cjs +1 -1
- package/dist/lib/events.cjs.map +1 -1
- package/dist/lib/events.mjs +35 -8
- package/dist/lib/events.mjs.map +1 -1
- package/dist/lib/icons.cjs +1 -1
- package/dist/lib/icons.cjs.map +1 -1
- package/dist/lib/icons.mjs +34 -20
- package/dist/lib/icons.mjs.map +1 -1
- package/dist/lib/initials.cjs +2 -0
- package/dist/lib/initials.cjs.map +1 -0
- package/dist/lib/initials.mjs +21 -0
- package/dist/lib/initials.mjs.map +1 -0
- package/dist/lib/table.cjs +2 -0
- package/dist/lib/table.cjs.map +1 -0
- package/dist/lib/table.mjs +16 -0
- package/dist/lib/table.mjs.map +1 -0
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/styles/tokens.css +102 -0
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ A React component library inspired by the Fluent UI 2 design language: 78 access
|
|
|
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.10](#upgrading-from-010) · [Upgrading from 0.9](#upgrading-from-09) · [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)
|
|
10
|
+
- [Keyboard support](#keyboard-support) · [Hooks and utilities](#hooks-and-utilities) · [Upgrading from 0.13](#upgrading-from-013) · [Upgrading from 0.12](#upgrading-from-012) · [Upgrading from 0.11](#upgrading-from-011) · [Upgrading from 0.10](#upgrading-from-010) · [Upgrading from 0.9](#upgrading-from-09) · [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
|
|
|
@@ -370,12 +370,13 @@ export function checkedRows(tree: HTMLElement) {
|
|
|
370
370
|
|
|
371
371
|
## React Server Components
|
|
372
372
|
|
|
373
|
-
- 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`, the date helpers (`addDays`, `addMonths`, `isSameDay`, `startOfWeek`, `getWeekNumber`) and the types are server-safe, so a Server Component can import from `@mortenbrudvik/waveui`, read the constants, create a toaster handle, compute dates and render Wave components with serializable props.
|
|
373
|
+
- 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`, the date helpers (`addDays`, `addMonths`, `isSameDay`, `startOfWeek`, `getWeekNumber`), `getInitials`, `partitionAvatarGroupItems`, the breadcrumb helpers (`partitionBreadcrumbItems`, `truncateBreadcrumbLongName`, `truncateBreadcrumbLongTooltip`, `isTruncatableBreadcrumbContent`), `createTableColumn` and the types are server-safe, so a Server Component can import from `@mortenbrudvik/waveui`, read the constants, create a toaster handle, compute dates and render Wave components with serializable props. A DataGrid column with functions (`compare`, `renderCell`) is not serializable: define such columns in a client component.
|
|
374
374
|
- 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.
|
|
375
|
-
- 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, Dropdown and Listbox, the parts and options of TagPicker, DataGrid parts, Drawer and Menu triggers, the Drawer header, body and footer parts, the tags of a TagGroup and the halves of an InteractionTag, the header of a `Menu.Group`, the halves of a `Menu.SplitGroup`, List, TabList and Tree items, Nav items, categories, section headers, dividers and app items, the header, body and footer of a NavDrawer, the stars of a Rating or RatingDisplay, the parts of Toast and MessageBar, the ColorPicker parts, `SwatchPicker.Row` and the swatches (`ColorSwatch`, `ImageSwatch`, `EmptySwatch`, in rows of the grid layout or the implicit ones), `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.
|
|
375
|
+
- 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, Dropdown and Listbox, the parts and options of TagPicker, DataGrid parts (`DataGrid.SelectionCell` included), the Table parts, Overflow items and dividers, Breadcrumb items (collapsed into the overflow menu too), the TeachingPopover parts, Drawer and Menu triggers, the Drawer header, body and footer parts, the tags of a TagGroup and the halves of an InteractionTag, the header of a `Menu.Group`, the halves of a `Menu.SplitGroup`, List, TabList and Tree items, Nav items, categories, section headers, dividers and app items, the header, body and footer of a NavDrawer, the stars of a Rating or RatingDisplay, the parts of Toast and MessageBar, the ColorPicker parts, `SwatchPicker.Row` and the swatches (`ColorSwatch`, `ImageSwatch`, `EmptySwatch`, in rows of the grid layout or the implicit ones), `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.
|
|
376
376
|
- Event handlers and other functions cannot be passed from a Server Component; put interactive parts in a `'use client'` component.
|
|
377
377
|
- A `Popover`, `Dialog`, overlay `Drawer` or `NavDrawer`, 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.
|
|
378
378
|
- An inline `Drawer` or `NavDrawer` (`type="inline"`) renders in the server HTML: open, or `hidden` when it is closed and kept mounted (`unmountOnClose={false}`).
|
|
379
|
+
- A TeachingPopover with a `TeachingPopover.Trigger` written directly inside it starts closed. One that points at its Trigger or a `target` renders its surface once hydrated (the surface sits in a portal). Write `TeachingPopover.Surface` directly inside TeachingPopover too: a Surface rendered by a component of yours is found only once it has mounted, so the server HTML holds the popover's own surface as well (two dialogs with the same title id) until then. A Surface with children of yours is named by its `TeachingPopover.Title` once mounted (as a Dialog is by `Dialog.Title`), so its server HTML has no `aria-labelledby`.
|
|
379
380
|
|
|
380
381
|
```tsx
|
|
381
382
|
// app/layout.tsx (Server Component)
|
|
@@ -447,11 +448,12 @@ export function SaveArea() {
|
|
|
447
448
|
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
448
449
|
| `Accordion` | `AccordionItem`, `AccordionTrigger`, `AccordionPanel` |
|
|
449
450
|
| `Breadcrumb` | `BreadcrumbItem` |
|
|
450
|
-
| `
|
|
451
|
-
| `
|
|
451
|
+
| `AvatarGroup` | `AvatarGroupItem`, `AvatarGroupPopover` |
|
|
452
|
+
| `Card` | `CardHeader`, `CardPreview`, `CardBody`, `CardFooter` |
|
|
453
|
+
| `Carousel` | `CarouselItem`, `CarouselButton` |
|
|
452
454
|
| `ColorPicker` | `ColorPickerHexField`, `ColorPickerSwatches`, `ColorPickerPreview` |
|
|
453
455
|
| `Combobox` | `ComboboxOption`, `ComboboxOptionGroup` (also `Option`, `OptionGroup`) |
|
|
454
|
-
| `DataGrid` | `DataGridHeader`, `DataGridHeaderCell`, `DataGridBody`, `DataGridRow`, `DataGridCell`
|
|
456
|
+
| `DataGrid` | `DataGridHeader`, `DataGridHeaderCell`, `DataGridBody`, `DataGridRow`, `DataGridCell`, `DataGridSelectionCell` |
|
|
455
457
|
| `Dialog` | `DialogTrigger`, `DialogContent`, `DialogTitle`, `DialogFooter`, `DialogClose` |
|
|
456
458
|
| `Drawer` | `DrawerTrigger`, `DrawerTitle`, `DrawerClose`, `DrawerHeader`, `DrawerHeaderTitle`, `DrawerHeaderNavigation`, `DrawerBody`, `DrawerFooter` |
|
|
457
459
|
| `Dropdown` | `DropdownOption`, `DropdownOptionGroup` |
|
|
@@ -462,7 +464,7 @@ export function SaveArea() {
|
|
|
462
464
|
| `MessageBar` | `MessageBarTitle`, `MessageBarActions` |
|
|
463
465
|
| `Nav` | `NavCategory`, `NavItem`, `NavSubItem`, `NavSectionHeader`, `NavDivider`, `NavAppItem`, `NavAppItemStatic` |
|
|
464
466
|
| `NavDrawer` | `NavDrawerHeader`, `NavDrawerBody`, `NavDrawerFooter` |
|
|
465
|
-
| `Overflow` | `OverflowItem`
|
|
467
|
+
| `Overflow` | `OverflowItem`, `OverflowDivider` |
|
|
466
468
|
| `Popover` | `PopoverTrigger`, `PopoverContent` |
|
|
467
469
|
| `RadioGroup` | `RadioGroupItem` (also `RadioItem`) |
|
|
468
470
|
| `Rating` | `RatingItem` |
|
|
@@ -470,9 +472,10 @@ export function SaveArea() {
|
|
|
470
472
|
| `Skeleton` | `SkeletonGroup` |
|
|
471
473
|
| `Stepper` | `StepperStep` |
|
|
472
474
|
| `SwatchPicker` | `SwatchPickerRow` |
|
|
473
|
-
| `Table` | `TableHeader`, `TableHeaderCell`, `TableBody`, `TableRow`, `TableCell`
|
|
475
|
+
| `Table` | `TableHeader`, `TableHeaderCell`, `TableBody`, `TableRow`, `TableCell`, `TableSelectionCell`, `TableCellLayout`, `TableCellActions` |
|
|
474
476
|
| `TabList` | `TabListTab`, `TabListPanel`, `TabListPanels` |
|
|
475
477
|
| `TagPicker` | `TagPickerControl`, `TagPickerGroup`, `TagPickerInput`, `TagPickerButton`, `TagPickerList`, `TagPickerOption`, `TagPickerOptionGroup` (also `OptionGroup`) |
|
|
478
|
+
| `TeachingPopover` | `TeachingPopoverTrigger`, `TeachingPopoverSurface`, `TeachingPopoverHeader`, `TeachingPopoverTitle`, `TeachingPopoverBody`, `TeachingPopoverFooter`, `TeachingPopoverCarousel`, `TeachingPopoverCarouselNav`, `TeachingPopoverCarouselPageCount`, `TeachingPopoverCarouselFooter` |
|
|
476
479
|
| `Toast` | `ToastTitle`, `ToastBody`, `ToastFooter`, `ToastClose` |
|
|
477
480
|
| `Toolbar` | `ToolbarButton`, `ToolbarToggleButton`, `ToolbarRadioGroup`, `ToolbarRadioButton`, `ToolbarGroup`, `ToolbarDivider` |
|
|
478
481
|
| `Tree` | `TreeItem`, `TreeItemPersonaLayout` |
|
|
@@ -531,20 +534,20 @@ Your `className` is merged last with `cn()`, so it replaces a conflicting class
|
|
|
531
534
|
|
|
532
535
|
| Component | Description |
|
|
533
536
|
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
534
|
-
| `Avatar` | Image, initials or icon, with an image-failure fallback and an optional `badge
|
|
535
|
-
| `AvatarGroup` |
|
|
537
|
+
| `Avatar` | Image, initials or icon, with an image-failure fallback and an optional `badge`; `size` (named or 16 to 128 px), `shape`, `color` (`neutral`, `brand`, `colorful` or one of twelve named colors), `active` and `activeAppearance`, an `initials` slot (see [Avatars and people](#avatars-and-people)). |
|
|
538
|
+
| `AvatarGroup` | Avatars in a `stack`, `spread` or `pie` `layout`; `max` adds an overflow button (`99+` past 99) that lists the hidden members. Compound form: `AvatarGroup.Item` and `AvatarGroup.Popover`. |
|
|
536
539
|
| `Badge` | Status or category label: `appearance` `filled`, `tint`, `outline`; semantic `color` (see [Badges](#badges)). |
|
|
537
540
|
| `CounterBadge` | Count pill (`99+` above `overflowCount`) or, with `dot`, an unread dot; Badge's `color` palette; `showZero`. |
|
|
538
|
-
| `PresenceBadge` | Availability badge with a distinct shape per status.
|
|
541
|
+
| `PresenceBadge` | Availability badge with a distinct shape per status (`available`, `busy`, `away`, `offline`, `do-not-disturb`, `out-of-office`; `dnd` and `oof` are deprecated). |
|
|
539
542
|
| `Tag` | Chip: `appearance` (`filled`, `outline`, `brand`), `size` (`medium` 28px, `small`, `extra-small`), `shape` (`circular`, `rounded`), `disabled`, a look-only `selected`, `value` (its key in a TagGroup) and the `media` (an Avatar), `icon` and `secondaryText` slots; an optional Dismiss button (`dismissible`, `onDismiss`, `dismissLabel`) that also dismisses on Delete and Backspace. `onDismiss` and `dismissIcon` need `dismissible` (a development warning says so). In a TagGroup focus moves for you when a tag is removed; on its own, move it yourself (see [Tags](#tags)). |
|
|
540
543
|
| `TagGroup` | A set of tags: a toolbar (one Tab stop, arrow keys) or, with `role="list"`, a list; default `size`, `appearance`, `shape`, `dismissible` and `disabled` for its tags; `onDismiss(value)`, focus to the next tag (else the previous one, else `fallbackFocusRef`) when the focused tag is removed; selectable InteractionTags through `value`/`defaultValue`/`onValueChange`, with `name`, `form` and `required`. |
|
|
541
544
|
| `InteractionTag` | A tag with an action: `InteractionTag.Primary` (a button, or a toggle in a selecting TagGroup; `media`, `icon`, `secondaryText`) and an optional `InteractionTag.Secondary` (a separate Dismiss button named "Dismiss <text>"); `size`, `appearance`, `shape`, `disabled`, `selected`, `value`. |
|
|
542
545
|
| `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. |
|
|
543
546
|
| `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`). |
|
|
544
|
-
| `Persona` | Avatar with
|
|
547
|
+
| `Persona` | Avatar with up to four lines of text (`primaryText` to `quaternaryText`), `textPosition` (`after`, `before`, `below`), `presenceOnly` and presence; sizes up to `huge`. |
|
|
545
548
|
| `Divider` | Horizontal or vertical separator, optionally labelled. |
|
|
546
549
|
| `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. |
|
|
547
|
-
| `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).
|
|
550
|
+
| `List` | Plain list, selectable listbox (single or multiple) or, with item `action`s, a grid; `navigationMode` (`none`, `items`, `composite`) gives a list without selection arrow keys, or pins the grid; `List.Item onAction`, `disabledSelection` and check marks (`checkmark`); in a selectable or navigable List item values are unique (development warning; see [Lists](#lists)). |
|
|
548
551
|
|
|
549
552
|
### Typography
|
|
550
553
|
|
|
@@ -556,12 +559,12 @@ Your `className` is merged last with `cn()`, so it replaces a conflicting class
|
|
|
556
559
|
|
|
557
560
|
| Component | Description |
|
|
558
561
|
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
559
|
-
| `Card` | Surface with `Card.Header`, `Card.Body`, `Card.Footer`; optionally selectable (`onSelect`, `selected`, `selectionControl`).
|
|
562
|
+
| `Card` | Surface with `Card.Header` (`image`, `action`), `Card.Preview`, `Card.Body`, `Card.Footer`; `appearance`, `size`, `orientation`; optionally selectable (`onSelect`, `selected`, `selectionControl`, `checkbox`) with a `floatingAction` (see [Cards, tabs and carousels](#cards-tabs-and-carousels)). |
|
|
560
563
|
| `Accordion` | Disclosure sections (`Accordion.Item`, `.Trigger`, `.Panel`); single (default) or `type="multiple"`; `headingLevel`; item values are unique (development warning). |
|
|
561
|
-
| `TabList` | Tabs (`TabList.Tab`, `.Panel`, `.Panels`) with automatic activation, or manual with `selectTabOnFocus={false}`; `orientation
|
|
564
|
+
| `TabList` | Tabs (`TabList.Tab`, `.Panel`, `.Panels`) with automatic activation, or manual with `selectTabOnFocus={false}`; `orientation`, `appearance` (`transparent`, `subtle`, `subtle-circular`, `filled-circular`), `size`, a `Tab` `icon` (alone: icon-only); tab values are unique (development warning). |
|
|
562
565
|
| `Tree` | Hierarchical tree (`Tree.Item`) with expand/collapse and typeahead; single selection, or checkboxes with a cascading mixed state (`selectionMode="multiple"`); row `actions`, `aside` and `Tree.ItemPersonaLayout`; `navigationMode="treegrid"` (see [Trees](#trees)). Nested items are `Tree.Item` elements in their parent's children (directly, in Fragments or from a render function), not rendered by a recursive component; values are unique. |
|
|
563
|
-
| `Carousel` |
|
|
564
|
-
| `Overflow` | Hides items that do not fit in one row and renders an overflow button (`useOverflowMenu` lists the hidden items); item ids are unique (development warning). The row has a 4px padding, so its items' focus rings are not clipped.
|
|
566
|
+
| `Carousel` | Slides (`Carousel.Item` children, directly or in Fragments; a component that renders `Carousel.Item` is not a slide) with previous/next, a slide picker and optional auto-rotation with a pause control. `groupSize` (a number or `auto`) shows several at once, `draggable` drags them, `Carousel.Item` `thumbnail` shows thumbnails, `controlsLayout` places the buttons and `Carousel.Button` replaces one. |
|
|
567
|
+
| `Overflow` | Hides items that do not fit in one row (or column, `orientation="vertical"`) and renders an overflow button (`useOverflowMenu` lists the hidden items); items hide by `priority` unless `pinned`, from the end or the start (`overflowDirection`), in groups with `Overflow.Divider`; `buttonPosition`, `minimumVisible`, `asChild` items, `onOverflowChange`; item ids are unique (development warning). The row has a 4px padding, so its items' focus rings are not clipped (see [Overflow](#overflow)). |
|
|
565
568
|
| `Grid` | CSS grid with a column count and token gaps. |
|
|
566
569
|
| `Stack` | Vertical or horizontal stack (`orientation`, `gap`). |
|
|
567
570
|
| `Flex` | Flexbox container (`direction`, `wrap`, `align`, `justify`, `gap`). |
|
|
@@ -580,7 +583,7 @@ Your `className` is merged last with `cn()`, so it replaces a conflicting class
|
|
|
580
583
|
|
|
581
584
|
| Component | Description |
|
|
582
585
|
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
583
|
-
| `Breadcrumb` | Trail of links, buttons or text (`Breadcrumb.Item`, `current`).
|
|
586
|
+
| `Breadcrumb` | Trail of links, buttons or text (`Breadcrumb.Item`, `current`); `maxDisplayedItems` or `overflow="auto"` collapse the middle items into a "…" menu, `size`, `focusMode` (`tab`, `arrow`), `divider` (see [Breadcrumbs](#breadcrumbs)). |
|
|
584
587
|
| `Menu` | Popup menu (`Menu.Trigger`, `Menu.Popover`, which scrolls when it is taller than the viewport) or static menu; `Menu.Item`, `Menu.Divider`; checkbox, radio and switch items bound to `checkedValues`, `Menu.Group`, `Menu.ItemLink`, submenus, `Menu.SplitGroup`, hover opening and context menus (see [Menus](#menus)). |
|
|
585
588
|
| `Nav` | Side navigation with items, collapsible categories and sub-items; links or buttons; a collapsed category that holds the current page is marked. `Nav.SectionHeader` (a heading, `headingLevel`), `Nav.Divider` (decorative), `Nav.AppItem` and `Nav.AppItemStatic` (the app's name at the top), and `actions` on `Nav.Item` and `Nav.SubItem` (your buttons beside the link, shown on hover and focus). Every child of its list is a list item (a development warning says so). |
|
|
586
589
|
| `NavDrawer` | Nav in a drawer panel (see [Navigation drawers and app shells](#navigation-drawers-and-app-shells)): `type` `overlay` (a modal or non-modal dialog around a `<nav>`) or `inline` (part of the page layout), `position` (default `start`), `size` (default `small`, 320px), `separator`, `modalType`, `unmountOnClose`, `finalFocusRef`, `backdrop`, Nav's value and category props and `onItemSelect(value)` on every activation; `NavDrawer.Header`, `NavDrawer.Body` (`focusMode` `tab` or `arrow`) and `NavDrawer.Footer`. |
|
|
@@ -596,14 +599,14 @@ Your `className` is merged last with `cn()`, so it replaces a conflicting class
|
|
|
596
599
|
| `Drawer` | Side or bottom panel (see [Drawers](#drawers)): `type` `overlay` (`modalType` `modal`, `alert` or `non-modal`) or `inline`; `position` (`start`, `end`, `left`, `right`, `bottom`), `size` (`small` 320px, `medium`, `large`, `full`), `separator`, `backdrop`, `closeButton`, `closeLabel`, `unmountOnClose`; `Drawer.Trigger` (toggles), `Drawer.Title`, `Drawer.Close`, and the layout parts `Drawer.Header`, `Drawer.HeaderTitle`, `Drawer.HeaderNavigation`, `Drawer.Body` and `Drawer.Footer`, whose separators show while content is scrolled under them. |
|
|
597
600
|
| `Popover` | Non-modal popup anchored to `Popover.Trigger` or a `target`; `side`, `align`; hover cards (`openOnHover`) and context popovers (`openOnContext`). |
|
|
598
601
|
| `Tooltip` | Hover and focus text for its child, as a description or (`relationship="label"`) a name; `open`/`defaultOpen`/`onOpenChange`; `openDelay`, `closeDelay`. |
|
|
599
|
-
| `TeachingPopover` | Step-by-step onboarding popover, optionally pointing at a `target`.
|
|
602
|
+
| `TeachingPopover` | Step-by-step onboarding popover, optionally pointing at a `target`; `primaryAction` and `secondaryAction` replace its buttons, `footerLayout`, `onFinish`; composable from parts: `TeachingPopover.Trigger`, `.Surface`, `.Header`, `.Title`, `.Body`, `.Footer` and the carousel parts `.Carousel`, `.CarouselNav`, `.CarouselPageCount`, `.CarouselFooter` (see [Teaching popovers and tours](#teaching-popovers-and-tours)). |
|
|
600
603
|
|
|
601
604
|
### Tables
|
|
602
605
|
|
|
603
606
|
| Component | Description |
|
|
604
607
|
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
605
|
-
| `Table` | Static table: `Table.Header`, `Table.HeaderCell`, `Table.Body`, `Table.Row`, `Table.Cell`; `striped`; scrolls horizontally.
|
|
606
|
-
| `DataGrid` | Interactive grid (APG grid keyboard model) with row selection and sortable headers; header from children or `columns`; row ids are unique (development warning). |
|
|
608
|
+
| `Table` | Static table: `Table.Header`, `Table.HeaderCell` (`sortable`, with your sort state), `Table.Body`, `Table.Row`, `Table.Cell`, and the cell parts `Table.SelectionCell`, `Table.CellLayout` and `Table.CellActions`; `striped`; scrolls horizontally (see [Static tables](#static-tables)). |
|
|
609
|
+
| `DataGrid` | Interactive grid (APG grid keyboard model) with row selection and sortable headers; header from children or `columns`, rows from `items` with typed columns (`createTableColumn`) that sort themselves; `selectOnRowClick`, `selectionAppearance`, `subtleSelection`, `DataGrid.SelectionCell`; row ids are unique (development warning; see [Sorting and selecting in a DataGrid](#sorting-and-selecting-in-a-datagrid)). |
|
|
607
610
|
|
|
608
611
|
### Provider
|
|
609
612
|
|
|
@@ -1079,7 +1082,7 @@ export function FruitList() {
|
|
|
1079
1082
|
}
|
|
1080
1083
|
```
|
|
1081
1084
|
|
|
1082
|
-
- **Listbox or List.** Use `Listbox` for a choice among options (the option model of Dropdown and Combobox: typeahead, groups, disabled options, forms). Use `List` with `selectable` when each item needs real focus, actions of its own or interactive content.
|
|
1085
|
+
- **Listbox or List.** Use `Listbox` for a choice among options (the option model of Dropdown and Combobox: typeahead, groups, disabled options, forms). Use `List` with `selectable` (or, without selection, `navigationMode="items"`) when each item needs real focus, actions of its own or interactive content (see [Lists](#lists)).
|
|
1083
1086
|
- **Focus and selection.** One Tab stop. The active option exists only while the list has focus: the selected option (with `multiselect`, the first selected one in list order), else the first; while no option can be active, the list draws its own focus ring. Space and Enter select, so the selection does not follow the active option; a single-select Listbox never deselects. A press on an option focuses the list and makes that option active without scrolling, so the click selects it even while the selected option is scrolled out of view. Tab, Escape and the Alt+arrow keys are left to the page: an enclosing Dialog closes on Escape.
|
|
1084
1087
|
- **Props.** `multiselect` (an array value, announced toggles; see [Multi-select pickers](#multi-select-pickers)), `onActiveOptionChange` (`null` when focus leaves the list), `disabled` (out of the Tab order, selects and submits nothing), `disabledOptionsFocusable`, `autoFocus`, `name`, `form` and `required`, and Field wiring. It has no built-in height: give it one through `className` and it scrolls.
|
|
1085
1088
|
- **Option groups.** `OptionGroup`'s `label` is optional and takes any text content (an icon next to the text is fine). Without one no heading renders, and `aria-label` or `aria-labelledby` names the group; these two always land on the `role="group"` list. A group without a name warns in development.
|
|
@@ -1457,6 +1460,63 @@ export function FormatBar() {
|
|
|
1457
1460
|
- **Size and buttons.** `size` (default `'medium'`) is the default size of `Toolbar.Button`, `Toolbar.ToggleButton` and `Toolbar.RadioButton` and sets the toolbar's padding; a part's own `size` wins, and plain Buttons keep their own default. The three parts use the `subtle` appearance by default. `Toolbar.Button vertical` puts the icon above a caption-size label, for ribbons. `isAccessible` on the toggles and radios draws the pressed state as a brand fill (recommended for icon-only ones).
|
|
1458
1461
|
- Any other focusable control still works inside a Toolbar, as in 0.6: Inputs, Comboboxes and MenuButtons join the arrow-key order, and text fields keep their own arrow keys.
|
|
1459
1462
|
|
|
1463
|
+
### Overflow
|
|
1464
|
+
|
|
1465
|
+
`Overflow` hides the items that do not fit and renders `overflowButton(count, hiddenIds)` instead; `useOverflowMenu()` inside it lists the hidden ids, for a menu. Items with a lower `priority` hide first, a `pinned` item never does, and items with the same `groupId` form a group that an `Overflow.Divider` follows:
|
|
1466
|
+
|
|
1467
|
+
```tsx
|
|
1468
|
+
import { Menu, MenuButton, Overflow, Toolbar, useOverflowMenu } from '@mortenbrudvik/waveui';
|
|
1469
|
+
|
|
1470
|
+
function MoreTools() {
|
|
1471
|
+
const { hiddenIds, count } = useOverflowMenu();
|
|
1472
|
+
return (
|
|
1473
|
+
<Menu>
|
|
1474
|
+
<Menu.Trigger>
|
|
1475
|
+
<MenuButton appearance="subtle">{`+${count}`}</MenuButton>
|
|
1476
|
+
</Menu.Trigger>
|
|
1477
|
+
<Menu.Popover>
|
|
1478
|
+
{hiddenIds.map((id) => (
|
|
1479
|
+
<Menu.Item key={id}>{id}</Menu.Item>
|
|
1480
|
+
))}
|
|
1481
|
+
</Menu.Popover>
|
|
1482
|
+
</Menu>
|
|
1483
|
+
);
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
export function DocumentTools() {
|
|
1487
|
+
return (
|
|
1488
|
+
<Toolbar aria-label="Document tools">
|
|
1489
|
+
<Overflow className="min-w-0 flex-1 gap-1" overflowButton={() => <MoreTools />}>
|
|
1490
|
+
<Overflow.Item itemId="Undo" groupId="history" priority={2}>
|
|
1491
|
+
<Toolbar.Button>Undo</Toolbar.Button>
|
|
1492
|
+
</Overflow.Item>
|
|
1493
|
+
<Overflow.Item itemId="Redo" groupId="history" priority={2}>
|
|
1494
|
+
<Toolbar.Button>Redo</Toolbar.Button>
|
|
1495
|
+
</Overflow.Item>
|
|
1496
|
+
<Overflow.Divider groupId="insert">
|
|
1497
|
+
<Toolbar.Divider />
|
|
1498
|
+
</Overflow.Divider>
|
|
1499
|
+
<Overflow.Item itemId="Image" groupId="insert" priority={1}>
|
|
1500
|
+
<Toolbar.Button>Image</Toolbar.Button>
|
|
1501
|
+
</Overflow.Item>
|
|
1502
|
+
<Overflow.Item itemId="Table" groupId="insert" priority={1}>
|
|
1503
|
+
<Toolbar.Button>Table</Toolbar.Button>
|
|
1504
|
+
</Overflow.Item>
|
|
1505
|
+
<Overflow.Item itemId="Share" pinned>
|
|
1506
|
+
<Toolbar.Button>Share</Toolbar.Button>
|
|
1507
|
+
</Overflow.Item>
|
|
1508
|
+
</Overflow>
|
|
1509
|
+
</Toolbar>
|
|
1510
|
+
);
|
|
1511
|
+
}
|
|
1512
|
+
```
|
|
1513
|
+
|
|
1514
|
+
- **Which item hides.** Items hide in ascending `priority` (default `0`); among equal priorities the last one in DOM order goes first, or the first one with `overflowDirection="start"`. `pinned` items never hide, and `minimumVisible` items always stay. While no item sets `priority` or `pinned`, the first item (with `start`, the last) always stays, as in 0.13; once one does, only `pinned` protects. The hidden items stay mounted with `data-overflow-hidden`, `display: none`, `aria-hidden` and `inert`, so arrow keys and Tab pass them.
|
|
1515
|
+
- **Groups.** A group is `'visible'` (every member shown), `'hidden'` or `'overflow'` (some members hidden): `useIsOverflowGroupVisible(groupId)` reads it, and an `Overflow.Divider` with the group's `groupId` hides while its group is hidden. `useHasHiddenItems()` tells whether anything is hidden. `onOverflowChange(hiddenItems, details)` reports the hidden ids in DOM order, with `details.visibleItems` and `details.groupVisibility`, once per change.
|
|
1516
|
+
- **The button.** `buttonPosition="end"` (the default) puts it after the items, sticking to the end of the row; `"before-hidden"` puts it just before the first hidden item, where the hidden items were (a breadcrumb trail does this), when the items are children of the Overflow (Fragments are fine). The button then moves as items hide and show, without remounting; a browser can still drop focus from a moved element, so focus on it can fall to the page while the row resizes, and switching `buttonPosition` on a mounted row remounts the items. `hasHiddenItems` renders the button before the first measurement, so the server HTML reserves its room.
|
|
1517
|
+
- **Without wrappers.** `Overflow.Item asChild` puts the item's props on its single element child, so `<Overflow role="list">` with `<li>` items is a list (the button's wrapper is then a list item).
|
|
1518
|
+
- **Columns.** `orientation="vertical"` stacks the items and measures heights; give the column a height.
|
|
1519
|
+
|
|
1460
1520
|
### Dialogs and triggers
|
|
1461
1521
|
|
|
1462
1522
|
```tsx
|
|
@@ -1604,6 +1664,46 @@ export function Author() {
|
|
|
1604
1664
|
- **`target`** on the Popover root (next to `side` and `align`; `PopupTarget`, as on `Menu.Popover`) places the content at an element held in state or at a `VirtualElement` instead of the trigger. A controlled popover with a `target` needs no trigger; a toggle button used as the target carries its own `aria-haspopup="dialog"`, `aria-expanded` and `aria-controls` (give `Popover.Content` an `id`), a press on it does not count as outside, and Tab from it enters the content. `Popover`, `Menu.Popover` and TeachingPopover take the same `target`: an element held in state, a `VirtualElement` or a ref object (a ref is read after each render of the popup, and the popup stays hidden while it holds no element).
|
|
1605
1665
|
- **Tooltip timing.** `openDelay` (default 200ms) is how long the pointer rests on the child, or the child has keyboard focus, before the tooltip appears: unlike Menu's and Popover's `openDelay`, it applies to focus too. `closeDelay` (default 100ms) is how long it stays once the pointer has left the child and the tooltip; blur and Escape hide it at once. `delay` is the deprecated name of `openDelay` (it warns once in development).
|
|
1606
1666
|
|
|
1667
|
+
### Teaching popovers and tours
|
|
1668
|
+
|
|
1669
|
+
`<TeachingPopover steps={steps} />` is a tour with Back, Next (Done on the last step) and Close. Built from parts, the same tour gets a trigger, a caption and interactive step buttons:
|
|
1670
|
+
|
|
1671
|
+
```tsx
|
|
1672
|
+
import { Button, TeachingPopover } from '@mortenbrudvik/waveui';
|
|
1673
|
+
|
|
1674
|
+
const steps = [
|
|
1675
|
+
{ title: 'Search', body: 'Type to filter the list.' },
|
|
1676
|
+
{ title: 'Filters', body: 'Narrow the results by owner or date.' },
|
|
1677
|
+
{ title: 'Share', body: 'Send the view to your team.' },
|
|
1678
|
+
];
|
|
1679
|
+
|
|
1680
|
+
export function Tour({ onSeen }: { onSeen: () => void }) {
|
|
1681
|
+
return (
|
|
1682
|
+
<TeachingPopover steps={steps} onFinish={onSeen}>
|
|
1683
|
+
<TeachingPopover.Trigger>
|
|
1684
|
+
<Button>Take the tour</Button>
|
|
1685
|
+
</TeachingPopover.Trigger>
|
|
1686
|
+
<TeachingPopover.Surface>
|
|
1687
|
+
<TeachingPopover.Header>Tip</TeachingPopover.Header>
|
|
1688
|
+
<TeachingPopover.Carousel>
|
|
1689
|
+
<TeachingPopover.Title />
|
|
1690
|
+
<TeachingPopover.Body />
|
|
1691
|
+
<TeachingPopover.CarouselFooter initialStepText="Not now" finalStepText="Got it">
|
|
1692
|
+
<TeachingPopover.CarouselNav />
|
|
1693
|
+
</TeachingPopover.CarouselFooter>
|
|
1694
|
+
</TeachingPopover.Carousel>
|
|
1695
|
+
</TeachingPopover.Surface>
|
|
1696
|
+
</TeachingPopover>
|
|
1697
|
+
);
|
|
1698
|
+
}
|
|
1699
|
+
```
|
|
1700
|
+
|
|
1701
|
+
- **Footer actions.** `primaryAction` replaces Next (Done on the last step) and `secondaryAction` replaces Back, on the popover or on a step (the step's wins); a single-step tip, which has no Back, gets a second button this way ("Learn more" and "Got it"). An action is a label (drawn as a Button), a Button, `<button>` or `<a>` element, or a slot object (`{ as: 'a', href, children: 'Learn more' }` stays a Wave Button). Its `onClick` runs first, then the step's own action (Next, Done or Back) unless it called `preventDefault()`: a "Learn more" link on a later step calls it, or it also goes back. `footerLayout="vertical"` puts the buttons, full width, under the step dots.
|
|
1702
|
+
- **Done and `onFinish`.** Done, and a primary action on the last step whose click was not prevented, close the popover and call `onFinish`, then, through 0.x, `onDismiss`; Close, Escape and the Trigger call only `onDismiss`. From 1.0 Done no longer calls `onDismiss`.
|
|
1703
|
+
- **Parts.** `TeachingPopover.Trigger` opens and closes the popover (`aria-haspopup="dialog"`, `aria-expanded`, `aria-controls`). While `target` is unset the popover points at it and follows it in the Tab order. Focus returns to the Trigger when the popover closes, also when `target` is set. Written directly inside TeachingPopover (a Fragment is fine), it makes the popover start closed. `TeachingPopover.Surface` is the popover and takes the `className`, `style`, `ref` and other element props that the `steps` form takes on TeachingPopover. Inside it, `Header` (the Close button, an optional caption and `icon`; `dismissButton` replaces the Close glyph or merges a Button into the Close button, and `null` removes it), `Title` (`as`; it names the popover), `Body` (`media` above the text) and `Footer` each show their share of the current step unless you give them children; a Surface without children shows all four, which is what the `steps` form renders. The steps, labels, actions and callbacks stay on TeachingPopover.
|
|
1704
|
+
- **Carousel parts.** `TeachingPopover.Carousel` holds the current page (the title, the body and a `CarouselFooter`). `CarouselFooter` lays out an indicator and the buttons: `layout="offset"` (the default, the indicator at the start, as in the Footer) or `"centered"` (the indicator between the buttons; Fluent's default). `finalStepText` relabels Done, and `initialStepText` turns the first step's unavailable Back into an enabled button that dismisses the popover (`onOpenChange(false)`, then `onDismiss`; Fluent's calls `onFinish`). It is the same element as Back, so focus stays on it when Back leads to the first step, where a second press dismisses. The indicator is the decorative step dots unless you put `CarouselNav` there (a group of step buttons named "Step 2 of 3", each a Tab stop, the current one with `aria-current="step"`; `labels.nav` and `labels.navButton` translate them) or `CarouselPageCount` (a visible "2 of 3", worded by its render function child, `(current, total) => …`).
|
|
1705
|
+
- **Placement.** Write the Trigger and the Surface directly inside TeachingPopover. A Trigger nested deeper does not make the popover start closed, and an open popover renders in place until that Trigger has mounted (in the server HTML too), then moves next to it, with focus passing through the Trigger. A Surface inside a component of yours works once mounted, but the server HTML holds the popover's own surface as well until then; a second Surface renders a second popover (development warning `TeachingPopover.Surface:placement`).
|
|
1706
|
+
|
|
1607
1707
|
### Custom overlays
|
|
1608
1708
|
|
|
1609
1709
|
The hooks behind WaveUI's own surfaces are public, so a surface WaveUI does not ship (a command palette, a custom popup) joins the same layer stack: Escape closes the topmost layer first, a press in the Toaster or in a marked region closes nothing, and focus returns to the opener.
|
|
@@ -1853,6 +1953,29 @@ export function UpdateNotice({ onUpdate, onLater }: { onUpdate: () => void; onLa
|
|
|
1853
1953
|
- A badge whose text alone does not say what it means ("3") can be named: with `aria-label` or `aria-labelledby` a Badge or CounterBadge gets `role="img"`, so the name is announced (a `role` you pass wins; an empty or whitespace-only name counts as absent). `<CounterBadge dot aria-label="Unread messages" />` is a named unread dot.
|
|
1854
1954
|
- The root carries `data-color` and `data-appearance` with the resolved values (and `data-dot` on a dot), for your own selectors.
|
|
1855
1955
|
|
|
1956
|
+
### Avatars and people
|
|
1957
|
+
|
|
1958
|
+
- **Sizes and shape.** `size` takes the named sizes or a box in pixels (16, 20, 24, 28, 32, 36, 40, 48, 56, 64, 72, 96, 120, 128); `shape="square"` rounds the corners. An Avatar in a `Tag` with `shape="rounded"` is square.
|
|
1959
|
+
- **Initials** come from `getInitials(name, { dir, firstInitialOnly })`: two letters for a full name, one for a single name, brackets and punctuation dropped, a hyphen or apostrophe joins words. A name with digits only, emoji or a script without letter initials (Han, Kana, Hangul, Thai, Lao, Khmer, Myanmar, Tibetan) shows none, so an icon or the `initials` slot is the better content. `initials` replaces the text. On a right-to-left page the two letters of a left-to-right name swap; Hebrew and Arabic names keep their order.
|
|
1960
|
+
- **Color.** `color` is `neutral` (the default), `brand`, `colorful` or one of `red`, `pumpkin`, `gold`, `forest`, `teal`, `blue`, `navy`, `lavender`, `purple`, `magenta`, `brown`, `steel`. `colorful` picks a named color from `idForColor`, else from `name`: the same input is always the same color, so a person keeps their color across pages. The palette is the `--wave-palette-<name>` and `--wave-palette-<name>-foreground` tokens; high contrast paints a white fill with black text.
|
|
1961
|
+
- **`active`** is `active` (the `activeAppearance` around the avatar: `ring`, `ring-shadow`, `shadow` or `glow`), `inactive` (dimmed) or `unset`.
|
|
1962
|
+
- **Presence.** `PresenceBadge` `status` is `available`, `busy`, `away`, `offline`, `do-not-disturb` or `out-of-office` (Fluent's names); `dnd` and `oof` still work and log a deprecation warning. Inside an Avatar the badge takes the size that fits the avatar.
|
|
1963
|
+
- **`Persona`** shows `primaryText` (default: `name`), then `secondaryText`, `tertiaryText` and `quaternaryText`, after, before or below the avatar (`textPosition`; below, the text is centered unless `textAlignment="start"`). `presenceOnly` swaps the avatar for the presence badge. A Persona without a `name` or text needs an `aria-label`.
|
|
1964
|
+
- **`AvatarGroup`** `layout` is `stack` (overlapping), `spread` (a gap) or `pie` (up to three wedges of a circle). Members take the group's `size`; one with a size of its own keeps it. `max` splits the members; to write the split yourself, use `partitionAvatarGroupItems({ items, maxInlineItems, layout })` and render `AvatarGroup.Item`s with an `AvatarGroup.Popover` for the rest:
|
|
1965
|
+
|
|
1966
|
+
```tsx
|
|
1967
|
+
const { inlineItems, overflowItems } = partitionAvatarGroupItems({ items: people, maxInlineItems: 3 });
|
|
1968
|
+
|
|
1969
|
+
<AvatarGroup aria-label="Project team">
|
|
1970
|
+
{inlineItems.map((name) => <AvatarGroup.Item key={name} name={name} />)}
|
|
1971
|
+
{overflowItems && (
|
|
1972
|
+
<AvatarGroup.Popover>
|
|
1973
|
+
{overflowItems.map((name) => <AvatarGroup.Item key={name} name={name} />)}
|
|
1974
|
+
</AvatarGroup.Popover>
|
|
1975
|
+
)}
|
|
1976
|
+
</AvatarGroup>;
|
|
1977
|
+
```
|
|
1978
|
+
|
|
1856
1979
|
### Tags
|
|
1857
1980
|
|
|
1858
1981
|
Put tags that belong together in a `TagGroup`. By default it is a toolbar: one Tab stop, Left/Right between the tags (mirrored in RTL), Delete or Backspace to dismiss. When the focused tag is removed, focus moves to the next tag, else the previous one, else `fallbackFocusRef`, so it never falls to the page:
|
|
@@ -1922,12 +2045,10 @@ export function Topics() {
|
|
|
1922
2045
|
|
|
1923
2046
|
### Sorting and selecting in a DataGrid
|
|
1924
2047
|
|
|
1925
|
-
|
|
2048
|
+
Give the grid its data (`items`) and typed `columns`: it renders the header, the rows and their cells, and **sorts the rows itself** by the sorted column's `compare`.
|
|
1926
2049
|
|
|
1927
2050
|
```tsx
|
|
1928
|
-
import
|
|
1929
|
-
import { DataGrid } from '@mortenbrudvik/waveui';
|
|
1930
|
-
import type { DataGridColumn, DataGridSort } from '@mortenbrudvik/waveui';
|
|
2051
|
+
import { DataGrid, createTableColumn } from '@mortenbrudvik/waveui';
|
|
1931
2052
|
|
|
1932
2053
|
interface Person {
|
|
1933
2054
|
id: string;
|
|
@@ -1935,41 +2056,152 @@ interface Person {
|
|
|
1935
2056
|
role: string;
|
|
1936
2057
|
}
|
|
1937
2058
|
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
{
|
|
2059
|
+
// Outside the component (or memoised): the rows render again when the array changes.
|
|
2060
|
+
const columns = [
|
|
2061
|
+
createTableColumn<Person>({
|
|
2062
|
+
columnId: 'name',
|
|
2063
|
+
label: 'Name',
|
|
2064
|
+
compare: (a, b) => a.name.localeCompare(b.name),
|
|
2065
|
+
renderCell: (person) => person.name,
|
|
2066
|
+
}),
|
|
2067
|
+
createTableColumn<Person>({ columnId: 'role', label: 'Role', renderCell: (person) => person.role }),
|
|
1941
2068
|
];
|
|
2069
|
+
const personId = (person: Person) => person.id;
|
|
1942
2070
|
|
|
1943
2071
|
export function People({ people }: { people: Person[] }) {
|
|
1944
|
-
const [sort, setSort] = React.useState<DataGridSort | null>(null);
|
|
1945
|
-
const rows = React.useMemo(() => {
|
|
1946
|
-
if (!sort) return people;
|
|
1947
|
-
const sorted = [...people].sort((a, b) => a.name.localeCompare(b.name));
|
|
1948
|
-
return sort.direction === 'ascending' ? sorted : sorted.reverse();
|
|
1949
|
-
}, [people, sort]);
|
|
1950
|
-
|
|
1951
2072
|
return (
|
|
1952
2073
|
<DataGrid
|
|
1953
2074
|
aria-label="People"
|
|
2075
|
+
items={people}
|
|
1954
2076
|
columns={columns}
|
|
1955
|
-
|
|
1956
|
-
|
|
2077
|
+
getRowId={personId}
|
|
2078
|
+
defaultSort={{ columnId: 'name', direction: 'ascending' }}
|
|
1957
2079
|
selectionMode="multiple"
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
2080
|
+
selectOnRowClick
|
|
2081
|
+
/>
|
|
2082
|
+
);
|
|
2083
|
+
}
|
|
2084
|
+
```
|
|
2085
|
+
|
|
2086
|
+
- **Columns.** `createTableColumn` returns a `DataGridColumn<T>` with `sortable` resolved: a column with `compare` is a sort button unless `sortable: false`. `label` is any content, `renderHeaderCell()` replaces it, and `renderCell(item)` fills the column's cells. `columnId` names the column in the header and in the sort (`id` is its deprecated name). A column with functions cannot be passed from a Server Component: define the columns in a client component.
|
|
2087
|
+
- **Built-in sorting.** While the sort names a column with `compare` (the grid's own sort, from `defaultSort` and clicks, or a controlled `sort`), the rows are a stable sort of a copy of `items`, and descending negates `compare`: items that compare equal keep their order in `items` in both directions (a reversed ascending sort would also reverse them). A column without `compare` never reorders the rows, so leave it out when the server sorts, and fetch the sorted data in `onSortChange(sort, details)`. `sortIcon` on a `DataGrid.HeaderCell` replaces the arrow shown while the column is sorted (`false` shows none); `aria-sort` on the header tells the direction.
|
|
2088
|
+
- **Rows.** `getRowId(item)` gives each row its `rowId`, which selection follows across sorts and new `items`; without it, a row's id is the item's index in `items`, which changes with the data. To write the rows yourself, give `DataGrid.Body` a render function, `{(person: Person) => <DataGrid.Row>…</DataGrid.Row>}` (the second argument is the item's index in `items`); each row gets its `rowId`. Write `DataGrid.Header` and `DataGrid.Body` directly inside the grid (a Fragment is fine): one rendered by a component of yours is not seen, and a grid with `columns` then adds its own header (with `items`, its own body too). A row renders again only when its item changes, and a sort only moves it. `items` may not be `undefined` unless `sort` or `defaultSort` is given; pass `items={data ?? []}` while loading: with `items`, `onSortChange` always receives the sort object and `details`.
|
|
2089
|
+
- **Your own row order.** A grid composed from `DataGrid.Header` and `DataGrid.Body` children without `items` keeps the 0.13 contract: it reports the requested sort and you order the rows. Negate the comparison for the descending order, so equal rows keep their order:
|
|
2090
|
+
|
|
2091
|
+
```tsx
|
|
2092
|
+
const [sort, setSort] = React.useState<DataGridSort | null>(null);
|
|
2093
|
+
const rows = React.useMemo(() => {
|
|
2094
|
+
if (!sort) return people;
|
|
2095
|
+
const sign = sort.direction === 'ascending' ? 1 : -1;
|
|
2096
|
+
return [...people].sort((a, b) => sign * a.name.localeCompare(b.name));
|
|
2097
|
+
}, [people, sort]);
|
|
2098
|
+
// <DataGrid aria-label="People" columns={[{ columnId: 'name', label: 'Name', sortable: true }]}
|
|
2099
|
+
// sort={sort} onSortChange={setSort}> <DataGrid.Body>{rows.map(…)}</DataGrid.Body> </DataGrid>
|
|
2100
|
+
```
|
|
2101
|
+
|
|
2102
|
+
- **Row selection.** `selectionMode` (`single`, `multiple`) with `selectedItems`, `defaultSelectedItems` and `onSelectedItemsChange(selectedItems, details)`. With `selectionMode="single"`, pass at most one id (with several, the first one whose row is rendered is selected, with a development warning). Each row's selection control is named after the row's first `DataGrid.Cell`, `<td>` or `<th>` child (Fragments are looked into); a cell rendered by another component is not seen, so pass `selectionLabel` to `DataGrid.Row` then.
|
|
2103
|
+
- **Selecting on a row click.** `selectOnRowClick` toggles a row when it is clicked (in single mode it selects the row alone, or clears it). The row's `onClick` runs first, and its `preventDefault()` keeps the selection. A click on a link, a button, an input or another interactive element in the row, a click from a popup opened from the row (a Menu in a cell), and a click that ends a text selection never toggle; Space on a cell toggles either way.
|
|
2104
|
+
- **Looks.** `selectionAppearance` fills a selected row with the selected token (`brand`, the default), the subtle one (`neutral`) or not at all (`none`; the control, `aria-selected` and the forced-colors outline still show it). `subtleSelection` draws an unchecked row control only while its row is hovered or holds focus, and the select-all while the grid is (always in forced colors and on touch screens); the controls stay focusable and named.
|
|
2105
|
+
- **Per row.** `DataGrid.Row selectionCellProps` takes `disabled` (a natively disabled control: row clicks, Space and select-all skip the row, and select-all counts the enabled rows only), `invisible` (no visible control; the row still selects), `className` and `aria-label`. `DataGrid.SelectionCell` places the selection cell where you write it in a row (the select-all in a header row), instead of the automatic first cell.
|
|
2106
|
+
- **Typing a wrapper.** A generic wrapper `function AppGrid<T>(props: DataGridProps<T>)` compiles and forwards every form, but an inline `onSortChange` passed to it next to `items` gets no contextual type: annotate its parameters, or type the wrapper's props as `DataGridBaseProps<T> & DataGridItemsSortProps<T>`.
|
|
2107
|
+
|
|
2108
|
+
### Static tables
|
|
2109
|
+
|
|
2110
|
+
`Table` keeps no state. A sortable `Table.HeaderCell` reports the click and shows the direction you give it; `Table.SelectionCell` is a native checkbox or radio driven by your state:
|
|
2111
|
+
|
|
2112
|
+
```tsx
|
|
2113
|
+
import * as React from 'react';
|
|
2114
|
+
import { Avatar, Button, Table } from '@mortenbrudvik/waveui';
|
|
2115
|
+
|
|
2116
|
+
type Member = { id: string; name: string; email: string };
|
|
2117
|
+
|
|
2118
|
+
export function Members({ members }: { members: Member[] }) {
|
|
2119
|
+
const [direction, setDirection] = React.useState<'ascending' | 'descending'>();
|
|
2120
|
+
const [selected, setSelected] = React.useState<string[]>([]);
|
|
2121
|
+
const sign = direction === 'descending' ? -1 : 1;
|
|
2122
|
+
const rows = direction ? [...members].sort((a, b) => sign * a.name.localeCompare(b.name)) : members;
|
|
2123
|
+
const all = selected.length === members.length ? true : selected.length > 0 ? 'mixed' : false;
|
|
2124
|
+
return (
|
|
2125
|
+
<Table aria-label="Members">
|
|
2126
|
+
<Table.Header>
|
|
2127
|
+
<Table.Row>
|
|
2128
|
+
<Table.SelectionCell
|
|
2129
|
+
aria-label="Select all members"
|
|
2130
|
+
checked={all}
|
|
2131
|
+
onCheckedChange={(checked) => setSelected(checked ? members.map((m) => m.id) : [])}
|
|
2132
|
+
/>
|
|
2133
|
+
<Table.HeaderCell
|
|
2134
|
+
sortable
|
|
2135
|
+
sortDirection={direction}
|
|
2136
|
+
onSortClick={() => setDirection(direction === 'ascending' ? 'descending' : 'ascending')}
|
|
2137
|
+
>
|
|
2138
|
+
Name
|
|
2139
|
+
</Table.HeaderCell>
|
|
2140
|
+
</Table.Row>
|
|
2141
|
+
</Table.Header>
|
|
2142
|
+
<Table.Body>
|
|
2143
|
+
{rows.map((member) => (
|
|
2144
|
+
<Table.Row key={member.id}>
|
|
2145
|
+
<Table.SelectionCell
|
|
2146
|
+
subtle
|
|
2147
|
+
aria-label={`Select ${member.name}`}
|
|
2148
|
+
checked={selected.includes(member.id)}
|
|
2149
|
+
onCheckedChange={(checked) =>
|
|
2150
|
+
setSelected((prev) =>
|
|
2151
|
+
checked ? [...prev, member.id] : prev.filter((id) => id !== member.id),
|
|
2152
|
+
)
|
|
2153
|
+
}
|
|
2154
|
+
/>
|
|
2155
|
+
<Table.Cell>
|
|
2156
|
+
<Table.CellLayout
|
|
2157
|
+
appearance="primary"
|
|
2158
|
+
media={<Avatar name={member.name} decorative />}
|
|
2159
|
+
description={member.email}
|
|
2160
|
+
>
|
|
2161
|
+
{member.name}
|
|
2162
|
+
</Table.CellLayout>
|
|
2163
|
+
<Table.CellActions>
|
|
2164
|
+
<Button size="small" appearance="subtle">{`Edit ${member.name}`}</Button>
|
|
2165
|
+
</Table.CellActions>
|
|
2166
|
+
</Table.Cell>
|
|
2167
|
+
</Table.Row>
|
|
1965
2168
|
))}
|
|
1966
|
-
</
|
|
1967
|
-
</
|
|
2169
|
+
</Table.Body>
|
|
2170
|
+
</Table>
|
|
1968
2171
|
);
|
|
1969
2172
|
}
|
|
1970
2173
|
```
|
|
1971
2174
|
|
|
1972
|
-
|
|
2175
|
+
- **Sortable headers.** `sortable` wraps the header's content in a `<button>` and puts `aria-sort` on the `<th>` (`"none"` while `sortDirection` is unset); `onSortClick(event)` runs on a click, Enter or Space. There are no grid semantics. `sortIcon` replaces the arrow (as on DataGrid), and `aside` puts content (a filter button) beside the sort button, outside its name.
|
|
2176
|
+
- **Selection cells.** `checked` (`true`, `false` or `'mixed'`, an indeterminate select-all), or `defaultChecked`; `onCheckedChange(checked, details)`; `type="radio"` with a shared `name` selects one row (uncontrolled radios uncheck each other); `name`, `value`, `form` and `required` submit the control. Its id, ARIA attributes and focus, key and change handlers go to the input, `className` and `ref` stay on the cell. Name every control (`aria-label` or `aria-labelledby`; a development warning asks for it). `subtle` draws an unchecked box only while its row is hovered or holds focus, and `invisible` keeps the cell's box without a control.
|
|
2177
|
+
- **Cell layout.** `Table.CellLayout` puts `media` (an icon, or an Avatar, which gets a 32px box) before the main text and a `description` under it; `truncate` keeps each line on one line where the column's width is bounded, and `appearance="primary"` marks the cell that names the row.
|
|
2178
|
+
- **Cell actions.** `Table.CellActions` covers the end of its cell (the cell is its positioning box) and shows its buttons while the row is hovered or holds focus, always in forced colors and on touch screens; `visible` keeps them (while a menu opened from one is open). Its background follows the library's own row fills: none, the row hover, a `striped` table's stripe and a DataGrid's selected rows. A row background of your own, or a table on another surface (a Card), needs the same background class on the actions, and the actions must be direct children of the cell for the stripe and selection fills to match.
|
|
2179
|
+
|
|
2180
|
+
### Lists
|
|
2181
|
+
|
|
2182
|
+
A `List` without selection is a plain list. `navigationMode="items"` makes its items one Tab stop with the arrow keys, Home, End and typeahead, and `onAction` gives an item an action of its own:
|
|
2183
|
+
|
|
2184
|
+
```tsx
|
|
2185
|
+
import { List } from '@mortenbrudvik/waveui';
|
|
2186
|
+
|
|
2187
|
+
export function RecentFiles({ open }: { open: (file: string) => void }) {
|
|
2188
|
+
return (
|
|
2189
|
+
<List navigationMode="items" aria-label="Recent files">
|
|
2190
|
+
<List.Item value="report" onAction={() => open('report')}>
|
|
2191
|
+
Report
|
|
2192
|
+
</List.Item>
|
|
2193
|
+
<List.Item value="budget" onAction={() => open('budget')}>
|
|
2194
|
+
Budget
|
|
2195
|
+
</List.Item>
|
|
2196
|
+
</List>
|
|
2197
|
+
);
|
|
2198
|
+
}
|
|
2199
|
+
```
|
|
2200
|
+
|
|
2201
|
+
- **Navigation modes.** Unset, the list picks its mode as in 0.13: a plain list is `'none'`, a selectable one `'items'` (a listbox), and a selectable one whose items have actions `'composite'` (a grid), which remounts the items when the first action appears or the last one goes. `navigationMode="composite"` makes the grid from the first render (with or without selection), so nothing remounts. `'items'` on a selectable list whose items have actions acts as `'composite'`, and `'none'` on a selectable list is ignored (development warnings say so). The resolved mode is `data-navigation-mode`. A list without selection keeps the item that last had focus as its Tab stop.
|
|
2202
|
+
- **`onAction`** runs on a click and on Enter, and on Space where the item cannot be selected (a list without selection, an item without `value`); in a selectable item Space only toggles. It runs after the item's `onClick` and before the selection toggles: `event.preventDefault()` keeps the selection. Clicks and keys in the item's actions never run it. In a list that does not navigate its items it runs on clicks only, with a development warning.
|
|
2203
|
+
- **`disabledSelection`** keeps an item's selection as it is (click, Enter and Space) while the item stays focusable and in the arrow order; without `onAction` it is also `aria-disabled`.
|
|
2204
|
+
- **Check marks.** `checkmark` on a selectable List draws a decorative check at the start of each selected item; `List.Item checkmark` replaces it with your glyph or hides it (`false`).
|
|
1973
2205
|
|
|
1974
2206
|
### Trees
|
|
1975
2207
|
|
|
@@ -2017,6 +2249,31 @@ export function FileTree() {
|
|
|
2017
2249
|
- **Navigation modes.** With `navigationMode="tree"` (the default), Tab from the focused item enters its actions (one stop; the arrow keys move inside them) and Shift+Tab returns. With `"treegrid"`, the "next" arrow (Right, Left in RTL) moves into the actions of an expanded parent or a leaf (a collapsed parent still expands first), "previous" returns, and Up and Down move between items from an action; the actions then take no Tab stop. This replaces APG's "next on an open item moves to its first child" (Down does that). The roles stay `tree` and `treeitem` in both modes, as in Fluent.
|
|
2018
2250
|
- **Persona rows.** `Tree.ItemPersonaLayout` (flat `TreeItemPersonaLayout`, Fluent's name) lays out an item's label as a person: `media` (an Avatar of size 32 fits a row), the name as children and a `description` under it; the item is named by the name and described by the description.
|
|
2019
2251
|
|
|
2252
|
+
### Breadcrumbs
|
|
2253
|
+
|
|
2254
|
+
```tsx
|
|
2255
|
+
import { Breadcrumb } from '@mortenbrudvik/waveui';
|
|
2256
|
+
|
|
2257
|
+
export function Trail() {
|
|
2258
|
+
return (
|
|
2259
|
+
<Breadcrumb maxDisplayedItems={4} overflowLabel="More folders">
|
|
2260
|
+
<Breadcrumb.Item href="/">Home</Breadcrumb.Item>
|
|
2261
|
+
<Breadcrumb.Item href="/docs">Docs</Breadcrumb.Item>
|
|
2262
|
+
<Breadcrumb.Item href="/docs/guides">Guides</Breadcrumb.Item>
|
|
2263
|
+
<Breadcrumb.Item href="/docs/guides/tables">Tables</Breadcrumb.Item>
|
|
2264
|
+
<Breadcrumb.Item href="/docs/guides/tables/sorting">Sorting</Breadcrumb.Item>
|
|
2265
|
+
<Breadcrumb.Item current>Stable sorts</Breadcrumb.Item>
|
|
2266
|
+
</Breadcrumb>
|
|
2267
|
+
);
|
|
2268
|
+
}
|
|
2269
|
+
// Home › … › Tables › Sorting › Stable sorts; the "…" button opens a menu with Docs and Guides.
|
|
2270
|
+
```
|
|
2271
|
+
|
|
2272
|
+
- **Collapse by count.** `maxDisplayedItems` is the most items shown, the "…" not counted; the middle items from `overflowIndex` (default `1`) go into a "…" button (`overflowLabel`, default "More items") that opens a Menu of them, in trail order: a link item becomes a `Menu.ItemLink` (an `asChild` link too; the element's own `href` wins over the item's, as on the trail), a button item a `Menu.Item`, and an unavailable item stays unavailable there. An `asChild` element of a component (a router link: `<RouterLink to="/docs">`, WaveUI's `<Link as={RouterLink} to="/docs">`, or a Next-style `<NextLink href="/docs">`) becomes a `Menu.ItemLink` rendered by that component with the element's own props, its `as`, `disabled` and `onClick` included (the element's `onClick` runs before the item's), so choosing it navigates the way the trail's link does and closes the menu; the link component must forward `ref` and spread its props onto its anchor. A Fragment around an `asChild` element is opened, whether the element is an `<a>` or a component's, in the menu as on the trail. The entry of a link item or of an `asChild` `<a>` passes on only its `href` and `onClick` (besides its icon, label and disabled state), so a `target`, `rel` or `download` stays on the trail. This applies to both collapses. The first item and the last `current` item are never hidden (the hidden run moves past a current item in the middle). An item the menu cannot list (one without `href` or `onClick` is listed disabled; an element that is not a `Breadcrumb.Item` is left out) logs a development warning. `partitionBreadcrumbItems({ items, maxDisplayedItems, overflowIndex })` gives Fluent's split (`startDisplayedItems`, `overflowItems`, `endDisplayedItems`) for a trail you lay out yourself.
|
|
2273
|
+
- **Collapse by room.** `overflow="auto"` hides the middle items that do not fit, from the start of the trail, and puts a "…" list item with its own separator where they were ("Home › … › Parent › Page"); resizing wider shows them again in order. The first item and the last `current` item never hide; when even they do not fit, the "…" covers the end of the trail. The trail is then an `Overflow` (`role="list"`, with `wave-overflow` and 4px of padding) that measures with `ResizeObserver`, and `maxDisplayedItems` and `overflowIndex` do not apply. Its list element is a `<div role="list">` holding the `<li>` items: assistive technology reads a list, but the nesting is not valid HTML (an Overflow root rendered as a list element is deferred to a later release). The "…" list item is the Overflow's button wrapper (`wave-overflow__overflow-button`); the button in it carries `wave-breadcrumb__overflow-button` in both modes.
|
|
2274
|
+
- **Size, keys and divider.** `size` (`small`, `medium`, `large`) sets the text and the separator. `focusMode="arrow"` makes the trail one Tab stop (the last focused link or button, at first the first one) moved with Left and Right (mirrored in RTL), Home and End, the "…" button included and hidden items skipped. `divider` replaces the chevron (`"/"`, an icon; not mirrored), and `false` hides the separators.
|
|
2275
|
+
- **Long names.** `truncateBreadcrumbLongName(name)` shortens a name longer than 30 characters to its first 30 and adds `...` (a second argument changes the length), `truncateBreadcrumbLongTooltip(text)` does the same at 80 for a tooltip, and `isTruncatableBreadcrumbContent(text, maxLength)` tells whether a text would be cut, so you show the full name in a `Tooltip` only then. A collapsed item wrapped in a Tooltip is not a `Breadcrumb.Item` to the trail, so it is left out of the overflow menu (with a development warning): wrap only items that the collapse keeps, or leave the Tooltip out where the trail collapses.
|
|
2276
|
+
|
|
2020
2277
|
### Navigation
|
|
2021
2278
|
|
|
2022
2279
|
`Nav` is a side navigation of items, collapsible categories and sub-items. Every child of its list renders a list item, so put only Nav parts there, or wrap other content in an `<li>` (a development warning names the rest):
|
|
@@ -2121,6 +2378,15 @@ export function Shell({ narrow }: { narrow: boolean }) {
|
|
|
2121
2378
|
- **Width.** `size` defaults to `small` (320px), Drawer's scale; Fluent's navigation pane is 260px wide, `className="w-65"` on your Tailwind build (or a class of your own with `width: 260px`). `position` defaults to `start` (Drawer's to `end`), and `separator` to on.
|
|
2122
2379
|
- **Server rendering.** An inline NavDrawer renders in the server HTML (open, or hidden when kept mounted); with `focusMode="arrow"` its Tab stop is set once it has mounted.
|
|
2123
2380
|
|
|
2381
|
+
### Cards, tabs and carousels
|
|
2382
|
+
|
|
2383
|
+
- **Card** `appearance` is `filled` (the default), `filled-alternative`, `outline` or `subtle`; `size` (`small`, `medium`, `large`) sets the padding of its parts through `--wave-card-padding`; `orientation="horizontal"` puts a `Card.Preview` beside the text. `Card.Preview` takes a `logo` over its bottom start corner. `Card.Header` takes an `image` (an Avatar, say) and an `action` (a menu button). With `selectionControl="checkbox"`, `checkbox` merges onto the built-in checkbox (an object), replaces it (an element) or removes it (`null`, when you render the control elsewhere); `floatingAction` sits over the top end corner and moves the checkbox to the start corner.
|
|
2384
|
+
- **TabList** `appearance` is `transparent` (the default), `subtle`, `subtle-circular` or `filled-circular`, and `size` `small`, `medium` or `large`. A `TabList.Tab` with an `icon` and no text is icon-only: give it an `aria-label` (development warning `TabList.Tab:icon-only-name`).
|
|
2385
|
+
- **Carousel groups.** `groupSize={n}` shows `n` slides per page and `"auto"` as many as fit (the slides keep their width, which must be equal; `align` places a page that does not fill the width). `value`, `onValueChange` and `defaultValue` are the index of the first slide of the page; previous, next, the picker (one button per page), looping and autoplay move by page. `labels.slides(start, end, total)` names a page.
|
|
2386
|
+
- **Dragging.** `draggable` follows the pointer (mouse, touch, pen); a drag past a quarter of the width, or a release faster than 0.5 px/ms, changes the page, else the track snaps back. The click that ends a drag is dropped, a vertical swipe still scrolls the page, and autoplay pauses while dragging.
|
|
2387
|
+
- **Thumbnails.** `<Carousel.Item thumbnail="/a.png">` (or an object of `<img>` attributes) turns the picker into a row of thumbnails; each button keeps its slide name.
|
|
2388
|
+
- **Controls.** `controlsLayout` is `overlay` (the default, round buttons over the slides), `overlay-wide` (full-height edge strips), `inline` (buttons beside the slides) or `inline-wide`. `Carousel.Button` (`direction="previous"` or `"next"`) replaces the built-in button of that direction and keeps its name, `aria-controls` and disabled behaviour; its children replace the chevron. `appearance="elevated"` rounds the carousel and adds a shadow.
|
|
2389
|
+
|
|
2124
2390
|
### Slots
|
|
2125
2391
|
|
|
2126
2392
|
Props such as `icon`, `contentBefore` and `dismiss` are slots. A slot accepts content (rendered inside the slot's element) or an object with `as`, `className`, `children` and any attribute of the slot's element:
|
|
@@ -2139,16 +2405,16 @@ export const Price = () => (
|
|
|
2139
2405
|
|
|
2140
2406
|
A slot takes any `React.ReactNode`. Spread an attributes object typed by an interface into a new object (`image={{ ...imgProps }}` for a `React.ImgHTMLAttributes<HTMLImageElement>`).
|
|
2141
2407
|
|
|
2142
|
-
Icon slots are decorative (`aria-hidden`). Content that renders nothing (`''`, `[]`, `<></>`, or a collection of only `null`, booleans and `''`) counts as no content: a `contentAfter` that renders nothing takes no room, and SearchBox's `contentBefore` keeps the default search icon. The dismiss and clear slots of `MessageBar`, `SearchBox` and `Tag`,
|
|
2408
|
+
Icon slots are decorative (`aria-hidden`). Content that renders nothing (`''`, `[]`, `<></>`, or a collection of only `null`, booleans and `''`) counts as no content: a `contentAfter` that renders nothing takes no room, and SearchBox's `contentBefore` keeps the default search icon. The dismiss and clear slots of `MessageBar`, `SearchBox` and `Tag`, the `closeButton` of `Dialog.Content` and Drawer, and the `dismissButton` of `TeachingPopover.Header` render their content inside the component's own button; the 0.4 form that passed a button object is deprecated. A Wave `Button` passed there is merged into that button, and its own props never reach the DOM: its `icon` and `iconPosition` place the icon, and `disabledFocusable` makes the built-in button unavailable but focusable. Content that renders nothing keeps the default icon, and a slot object without children (`{ className: 'text-error' }`) wraps it. A slot object that renders a component or a void element (`{ as: CloseIcon }`, `{ as: 'img', src, alt: '' }`) or sets `dangerouslySetInnerHTML` is the icon itself. On `MessageBar`, `dismiss={null}` is the only value that hides the dismiss button (a boolean counts as no slot), and so is `closeButton={null}` for the Close button of a Dialog or Drawer and `dismissButton={null}` for TeachingPopover's.
|
|
2143
2409
|
|
|
2144
|
-
The `backdrop` slot of `Dialog.Content` and Drawer takes content or a slot object with `appearance` (`'dimmed'`, `'transparent'`); `null` renders none, and booleans are no slot. Tag's `media` and `icon` (and an InteractionTag Primary's) are content slots: `media` is not hidden from assistive technology (pass `decorative` to an Avatar whose name repeats the tag's text), `icon` is decorative.
|
|
2410
|
+
The `backdrop` slot of `Dialog.Content` and Drawer takes content or a slot object with `appearance` (`'dimmed'`, `'transparent'`); `null` renders none, and booleans are no slot. Tag's `media` and `icon` (and an InteractionTag Primary's) are content slots: `media` is not hidden from assistive technology (pass `decorative` to an Avatar whose name repeats the tag's text), `icon` is decorative. So are the `media` of `Table.CellLayout` and `TeachingPopover.Body` (give a picture its `alt`), and `Table.HeaderCell`'s `aside`.
|
|
2145
2411
|
|
|
2146
2412
|
Slots that replace a built-in glyph follow one rule per kind:
|
|
2147
2413
|
|
|
2148
|
-
- **Optional indicators** (`MenuButton.menuIcon`, the `expandIcon` of Combobox, Dropdown, TimePicker, TagPicker (and `TagPicker.Control`) and `Tree.Item`, `EmptySwatch.icon`): `null` or `undefined` keep the default glyph; `false` or any value that renders nothing hides it (for Combobox, TimePicker and TagPicker, the whole expand button; for Dropdown, the chevron and its room).
|
|
2414
|
+
- **Optional indicators** (`MenuButton.menuIcon`, the `expandIcon` of Combobox, Dropdown, TimePicker, TagPicker (and `TagPicker.Control`) and `Tree.Item`, `EmptySwatch.icon`, the `sortIcon` of `DataGrid.HeaderCell` and `Table.HeaderCell`, Breadcrumb's `divider`, `List.Item checkmark`): `null` or `undefined` keep the default glyph; `false` or any value that renders nothing hides it (for Combobox, TimePicker and TagPicker, the whole expand button; for Dropdown, the chevron and its room). A sort glyph shows only while its column is sorted, and a list check mark only on a selected item of a selectable List (`List.Item checkmark` content shows also without the List's `checkmark`).
|
|
2149
2415
|
- **Required indicators** (`SplitButton.menuIcon`, `Option.checkIcon`, `Hamburger.icon`): the indicator always shows. A value that renders nothing keeps the default glyph, with a development warning. The check is the sign of an option's selection that does not rely on color, so Fluent's `checkIcon={null}`, which removes it, keeps it here.
|
|
2150
2416
|
- **Status icons** (`MessageBar.icon`, `Toast.icon`, Field `validationMessageIcon`): only `undefined` keeps the default icon; `null` or a value that renders nothing shows none.
|
|
2151
|
-
- A glyph slot inside a built-in button (`expandIcon`, the `menuIcon` of SplitButton and MenuButton, the `icon` of `ColorSwatch`, `EmptySwatch` and `Hamburger`, and the children of `InteractionTag.Secondary`, which is itself the button) is decorative content. A `<button>` or `Button` passed there, or a slot object whose `as` is one, is not nested: its children become the glyph and its props are dropped, with a development warning.
|
|
2417
|
+
- A glyph slot inside a built-in button (`expandIcon`, the `menuIcon` of SplitButton and MenuButton, the `icon` of `ColorSwatch`, `EmptySwatch` and `Hamburger`, a header cell's `sortIcon`, and the children of `InteractionTag.Secondary`, which is itself the button) is decorative content. A `<button>` or `Button` passed there, or a slot object whose `as` is one, is not nested: its children become the glyph and its props are dropped, with a development warning.
|
|
2152
2418
|
|
|
2153
2419
|
### Built-in text
|
|
2154
2420
|
|
|
@@ -2157,11 +2423,12 @@ The names and hidden texts that components render themselves are English by defa
|
|
|
2157
2423
|
| Component | Props |
|
|
2158
2424
|
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
2159
2425
|
| `Dialog.Content`, `Drawer` | `closeLabel` (the Close button; on Drawer also the Close button of each `Drawer.HeaderTitle`; a text label of a button merged into `closeButton` names it instead) |
|
|
2160
|
-
| `TeachingPopover` | `closeLabel` (the Close button), `labels` (`back`, `next`, `done`, `step(index, count)` with a zero-based index)
|
|
2426
|
+
| `TeachingPopover` | `closeLabel` (the Close button), `labels` (`back`, `next`, `done`, `step(index, count)` with a zero-based index, and for `TeachingPopover.CarouselNav` `nav` ("Choose step") and `navButton(index, count)` ("Step 2 of 3", zero-based index)); `TeachingPopover.CarouselPageCount` words its "2 of 3" with its render function child `(current, total)` (one-based) |
|
|
2427
|
+
| `Breadcrumb` | `overflowLabel` (the "…" button of a collapsed trail, "More items") |
|
|
2161
2428
|
| `MessageBar`, `Toast` | `statusLabel` (the hidden severity text; also an option of both `dispatchToast` forms); `Toast` also `dismissLabel` (also an option of the text form) |
|
|
2162
2429
|
| `Tag` | `dismissLabel` ("Dismiss", with the tag's text) |
|
|
2163
2430
|
| `InteractionTag.Secondary` | `dismissLabel` ("Dismiss", with the primary text: "Dismiss Cherry") |
|
|
2164
|
-
| `Carousel` | `labels` (`previous`, `next`, `picker`, `slide(index, total)` with a zero-based index, `carouselRoleDescription`, `slideRoleDescription`), `autoPlayLabels` |
|
|
2431
|
+
| `Carousel` | `labels` (`previous`, `next`, `picker`, `slide(index, total)` with a zero-based index, `slides(start, end, total)` with one-based numbers for a page of several slides, `carouselRoleDescription`, `slideRoleDescription`), `autoPlayLabels` |
|
|
2165
2432
|
| `Stepper` | `statusLabels` (`completed`, `error`; `''` omits the text) |
|
|
2166
2433
|
| `Pagination` | `getItemAriaLabel(type, page, selected)` |
|
|
2167
2434
|
| `ColorPicker` | `labels` (the 0.7 strings, plus `area` (the name of a bound area's group, "Saturation and brightness"), `saturation`, `brightness`, `roleDescription`, `hue`, `transparency`, `colorName(color)` and `valueText(color, channel)` for bound parts) |
|
|
@@ -2190,11 +2457,11 @@ The names and hidden texts that components render themselves are English by defa
|
|
|
2190
2457
|
|
|
2191
2458
|
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`.
|
|
2192
2459
|
|
|
2193
|
-
0.7 and 0.8 add no other built-in text: the submenu half of a `Menu.SplitGroup`, a context menu (`Menu.Popover`) and a `Toolbar.RadioGroup` are named by the `aria-label` you pass, a toast's container by its severity and title, and a tree row's actions toolbar by its item's label. Nor do 0.10 and 0.11, beyond the rows above: a `TagGroup` is named by the `aria-label` you pass, an inline Drawer by its title; a `Listbox`, a `Calendar` and a `ColorSwatch` or `ImageSwatch` are named by the `aria-label` you pass (or a `Field`'s label, or a `Tooltip` around the swatch), an `OptionGroup` by its label, and the month and year buttons by their text in `locale`.
|
|
2460
|
+
0.7 and 0.8 add no other built-in text: the submenu half of a `Menu.SplitGroup`, a context menu (`Menu.Popover`) and a `Toolbar.RadioGroup` are named by the `aria-label` you pass, a toast's container by its severity and title, and a tree row's actions toolbar by its item's label. Nor do 0.10 and 0.11, beyond the rows above: a `TagGroup` is named by the `aria-label` you pass, an inline Drawer by its title; a `Listbox`, a `Calendar` and a `ColorSwatch` or `ImageSwatch` are named by the `aria-label` you pass (or a `Field`'s label, or a `Tooltip` around the swatch), an `OptionGroup` by its label, and the month and year buttons by their text in `locale`. 0.14 adds none either beyond the rows above: a `Table.SelectionCell` control is named by the `aria-label` or `aria-labelledby` you pass (a development warning asks for one), and a `CarouselFooter`'s `initialStepText` and `finalStepText` are your text.
|
|
2194
2461
|
|
|
2195
2462
|
## Keyboard support
|
|
2196
2463
|
|
|
2197
|
-
As implemented
|
|
2464
|
+
As implemented through 0.14. 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. The sort buttons of a sortable `Table.HeaderCell` and the step buttons of `TeachingPopover.CarouselNav` are native buttons too.
|
|
2198
2465
|
|
|
2199
2466
|
| Component | Keys |
|
|
2200
2467
|
| ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -2209,7 +2476,7 @@ As implemented in 0.11. Buttons, links, checkboxes, switches and the trigger but
|
|
|
2209
2476
|
| 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. |
|
|
2210
2477
|
| 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. |
|
|
2211
2478
|
| 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. |
|
|
2212
|
-
| List (selectable)
|
|
2479
|
+
| List (selectable, or `navigationMode="items"`) | One Tab stop (selectable: the first selected item, else the first; without selection: the item that last had focus). Up/Down (wrapping), Home/End, typeahead above 7 items (a Space within 500 ms of a letter continues the search). Enter toggles a selectable item and runs `onAction`; Space toggles a selectable item, or runs `onAction` on an item that cannot be selected. With item actions in a selectable list, or `navigationMode="composite"` (grid): Up/Down between rows, Left/Right into the actions (mirrored in RTL), Enter/F2 into a text field, Escape back. A plain List (`navigationMode` `none`) has no arrow keys: its items' controls are Tab stops. |
|
|
2213
2480
|
| DataGrid | One Tab stop. Arrows between cells (Left/Right to the previous/next cell of the row, mirrored in RTL; Up/Down and PageUp/PageDown keep the visual column across `colSpan`/`rowSpan` cells of grouped headers), Home/End row start/end, Ctrl+Home/Ctrl+End grid start/end, PageUp/PageDown 10 rows; Enter/F2 into a cell's widgets, Escape back; Space on a cell toggles its row's selection. |
|
|
2214
2481
|
| 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. |
|
|
2215
2482
|
| 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, and the previous arrow (Left, Right in RTL) with the caret at the start of the text and nothing selected, focus the last tag; on a tag's remove button Left/Right move between the tags (mirrored in RTL) and past the last one return to the trigger, and Delete, Backspace, Enter or Space remove it and focus the next tag's remove button, else the input (a click focuses the input). Typing makes the option whose label equals the text active, else the first match; with `allowCreate` Enter on the create option adds the text. `TagPicker.Button`: Down, Up and a typed letter open and move, Enter and Space add the active option. The chevron is not a Tab stop; the clear button is, after the trigger. Multi-select (`multiselect`, Combobox): Enter toggles the active option and keeps the list open; Tab, Escape and Alt+Up close without committing; focusing the input selects the shown labels, so typing replaces them with a query, and Backspace and Delete only edit the text. With `disabledOptionsFocusable` (Combobox) the arrow keys reach disabled options, but Enter does nothing on them. |
|
|
@@ -2222,9 +2489,10 @@ As implemented in 0.11. Buttons, links, checkboxes, switches and the trigger but
|
|
|
2222
2489
|
| Dialog, Drawer (non-modal) | Focus moves in on open. Tab and Shift+Tab leave the surface in the page's order right after the element that opened it; Escape closes it only while focus is inside; the trigger toggles; focus returns to the opener (or `finalFocusRef`) only when it was inside. |
|
|
2223
2490
|
| Drawer (inline) | Page content: no trap, opening moves no focus, Escape and presses outside never close it; the trigger toggles; closing it while focus is inside returns focus to `finalFocusRef`, else the element that opened it, else the trigger. |
|
|
2224
2491
|
| Nav | Every item, category and app item is a Tab stop (Enter or Space activates; a category toggles); an item's `actions` follow it in the Tab order. |
|
|
2492
|
+
| Breadcrumb (`focusMode="arrow"`) | One Tab stop: the last focused link or button, at first the first one. Left/Right move (mirrored in RTL, wrapping), Home/End jump; the "…" button is in the order, hidden items are not. With the default `focusMode="tab"` every link and button is a Tab stop. |
|
|
2225
2493
|
| NavDrawer | An overlay as a Drawer (modal or non-modal); an inline one as page content. A Hamburger inside it toggles it, and focus goes to `finalFocusRef` (your page's Hamburger) when it closes with focus inside. |
|
|
2226
2494
|
| NavDrawer.Body (`focusMode="arrow"`) | One Tab stop: the last focused element, at first the current page (or the closed category that holds it), else the first item. Down/Right move to the next element and Up/Left to the previous one (Left and Right swap in RTL), wrapping; Home/End jump; item actions join the order. The footer's items stay Tab stops. |
|
|
2227
|
-
| 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. |
|
|
2495
|
+
| 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 (with a `TeachingPopover.Trigger`, to the Trigger, wherever focus was before); 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. |
|
|
2228
2496
|
| 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. |
|
|
2229
2497
|
| Card (selectable) | With the default `selectionControl="card"`: Enter (key down) or Space (key up) selects. With `"checkbox"`: the built-in checkbox. |
|
|
2230
2498
|
| Stepper | Each reachable step is a Tab stop; Enter/Space activate. |
|
|
@@ -2233,9 +2501,9 @@ As implemented in 0.11. Buttons, links, checkboxes, switches and the trigger but
|
|
|
2233
2501
|
| ColorArea | One Tab stop. Left/Right change saturation (mirrored in RTL), Up/Down brightness; Shift with an arrow by 10; PageUp/PageDown brightness by 10; Home/End saturation to 0/100. |
|
|
2234
2502
|
| ColorSlider, AlphaSlider | The arrows of their axis by 1 (mirrored in RTL when horizontal), Shift with an arrow by 10, PageUp/PageDown by 10, Home/End to the minimum/maximum. |
|
|
2235
2503
|
|
|
2236
|
-
Accordion and Carousel have no arrow-key navigation: their triggers and controls are Tab stops.
|
|
2504
|
+
Accordion and Carousel have no arrow-key navigation between their controls: their triggers and controls are Tab stops. With `groupSize` above 1 the slides of the shown page are one arrow-key group (the slide that last had focus is its Tab stop; an arrow past the end of the page shows the next one).
|
|
2237
2505
|
|
|
2238
|
-
Typeahead (Menu, selectable List, Tree, Dropdown, Listbox) accepts characters typed with AltGr, which Windows reports as Ctrl+Alt (Polish `ł`, Romanian `ș`); Ctrl+Alt with an arrow, Home, End or Space is left to the browser. An item that cannot take focus is passed over for the next match. Menu typeahead matches the item labels, not icons or shortcuts. Options and option groups with `hidden` are skipped like a native `<option hidden>`.
|
|
2506
|
+
Typeahead (Menu, a selectable or navigable List, Tree, Dropdown, Listbox) accepts characters typed with AltGr, which Windows reports as Ctrl+Alt (Polish `ł`, Romanian `ș`); Ctrl+Alt with an arrow, Home, End or Space is left to the browser. An item that cannot take focus is passed over for the next match. Menu typeahead matches the item labels, not icons or shortcuts. Options and option groups with `hidden` are skipped like a native `<option hidden>`.
|
|
2239
2507
|
|
|
2240
2508
|
## Hooks and utilities
|
|
2241
2509
|
|
|
@@ -2268,7 +2536,13 @@ Typeahead (Menu, selectable List, Tree, Dropdown, Listbox) accepts characters ty
|
|
|
2268
2536
|
| `useToastController()` | `dispatchToast` (content or options) / `dismissToast` / `dismissAllToasts` inside `<Toaster>`. |
|
|
2269
2537
|
| `createToaster()` | A toast controller for code outside components; bind it with `<Toaster toaster={handle}>` (see [Toasts](#toasts)). Server-safe. |
|
|
2270
2538
|
| `useIsOverflowing(target)`, `useOverflowMenu()`, `useIsOverflowItemVisible(id)` | Overflow detection. |
|
|
2539
|
+
| `useIsOverflowGroupVisible(groupId)`, `useHasHiddenItems()` | Inside an `Overflow`: whether an item group is `'visible'`, `'hidden'` or `'overflow'` (some members hidden), and whether any item is hidden (see [Overflow](#overflow)). |
|
|
2540
|
+
| `createTableColumn<T>(options)` | A DataGrid column typed by the grid's items (`columnId`, `label`, `compare`, `renderCell`, `renderHeaderCell`), with `sortable` resolved (`true` with `compare`); see [Sorting and selecting in a DataGrid](#sorting-and-selecting-in-a-datagrid). Server-safe. |
|
|
2541
|
+
| `partitionBreadcrumbItems({ items, maxDisplayedItems, overflowIndex })` | Split a trail into `startDisplayedItems`, `overflowItems` and `endDisplayedItems`, by Fluent's rules (it hides `items.length - maxDisplayedItems` items from `overflowIndex`, default 1; a missing or non-positive `maxDisplayedItems` is 6); a trail that fits is all `startDisplayedItems`. Server-safe. |
|
|
2542
|
+
| `truncateBreadcrumbLongName(content, maxLength?)`, `truncateBreadcrumbLongTooltip(content, maxLength?)`, `isTruncatableBreadcrumbContent(content, maxLength)` | Shorten a breadcrumb name (default 30 characters) or its tooltip text (default 80) longer than `maxLength` to that length plus `...`, and tell whether a text is longer than `maxLength`. Server-safe. |
|
|
2271
2543
|
| `hsvToHex(color)`, `hexToHsv(hex)` | Convert between an `HsvColor` and a hex string (`#rrggbb`, or `#rrggbbaa` below full opacity); `hexToHsv` returns `null` for other text. Server-safe. |
|
|
2544
|
+
| `getInitials(name, options?)` | The initials Avatar shows (`dir`, `firstInitialOnly`); none for digits, emoji or scripts without letter initials. Server-safe. |
|
|
2545
|
+
| `partitionAvatarGroupItems({ items, maxInlineItems, layout })` | Split a list into the inline and overflow items of an AvatarGroup (`{ inlineItems, overflowItems }`); imports nothing. |
|
|
2272
2546
|
| `addDays(date, amount)`, `addMonths(date, amount)`, `isSameDay(a, b)`, `startOfWeek(date, firstDayOfWeek?)`, `getWeekNumber(date, options?)` | Date helpers on calendar days: every returned date is local midnight (Fluent's keep the time of day). `addMonths` clamps the day to the target month (January 31 plus a month is February 28 or 29); `getWeekNumber` takes `firstDayOfWeek` and `firstWeekOfYear` (`GetWeekNumberOptions`; ISO 8601 is `{ firstDayOfWeek: 1, firstWeekOfYear: 'first-four-day-week' }`). With the types `DayOfWeek` (`0`–`6`, Sunday first) and `FirstWeekOfYear`. Server-safe. |
|
|
2273
2547
|
| `buttonClassNames`, `toastTitleClassNames`, … | The stable class names of every component and part (see [Styling hooks](#styling-hooks)). Server-safe. |
|
|
2274
2548
|
| `cn(...classes)` | clsx + tailwind-merge that knows Wave's type ramp and shadows; the last class wins over a conflicting class of the same variant. |
|
|
@@ -2277,6 +2551,34 @@ Typeahead (Menu, selectable List, Tree, Dropdown, Listbox) accepts characters ty
|
|
|
2277
2551
|
| `resolveSlot`, `renderSlot` | The slot helpers the components use. |
|
|
2278
2552
|
| `getThemeClassName(theme)` | The theme classes of a theme. |
|
|
2279
2553
|
|
|
2554
|
+
## Upgrading from 0.13
|
|
2555
|
+
|
|
2556
|
+
0.14 removes nothing public, and every new behaviour is opt-in; these changes can still affect your types, tests and styles:
|
|
2557
|
+
|
|
2558
|
+
1. **`DataGridColumn` and `DataGrid` are generic** (`T = unknown` without a type argument): a column's `label` widens to `ReactNode`, and its `id` is optional and deprecated (`column.id` is `string | undefined`; write `columnId`). `children` of `DataGrid` and `DataGrid.Body` is optional, and `DataGridBodyProps['children']` may be a render function.
|
|
2559
|
+
2. **`onSortChange(sort)` and `onSelectedItemsChange(items)` get a second argument, `details` (`{ event }`):** exact `toHaveBeenCalledWith` assertions need it. The 0.4 positional `onSortChange(columnId, direction)` is unchanged, but a grid with `items` always uses the object form, and the deprecated sort props next to `items` are type errors (ignored, with a warning, at run time).
|
|
2560
|
+
3. **A sorted DataGrid header shows an arrow icon** (`data-wave-icon="sort-arrow-up"` or `"sort-arrow-down"`, with `data-direction`) instead of the 0.13 triangle.
|
|
2561
|
+
4. **`OverflowItemProps` is a union type alias:** extend `OverflowItemBaseProps` instead.
|
|
2562
|
+
5. **TeachingPopover:** Done calls `onFinish` and, through 0.x, still `onDismiss`. Children passed to TeachingPopover, dropped in 0.13, now render. The `steps` form's Close button sits in a header `<div class="wave-teaching-popover-header">`, its heading, body and footer carry the new parts' classes, and the surface and footer carry `data-layout`: selectors that rely on the Close button being the surface's child, or on `:first-child`, change.
|
|
2563
|
+
6. **Table and DataGrid cells are `relative`** and their rows the group `group/table-row`: an absolutely positioned element in a cell is placed against it, and a `sticky` header of yours needs a `z-index` to stay over the body cells.
|
|
2564
|
+
7. **New attributes**, always rendered: Overflow `data-orientation`, `data-overflow-direction`, `data-button-position`; Breadcrumb `data-size`, `data-focus-mode`, `data-overflow`; DataGrid `data-selection-appearance`; List `data-navigation-mode`.
|
|
2565
|
+
|
|
2566
|
+
The CHANGELOG's [0.14.0 section](CHANGELOG.md) lists the additions and the full upgrade notes.
|
|
2567
|
+
|
|
2568
|
+
## Upgrading from 0.12
|
|
2569
|
+
|
|
2570
|
+
0.13 removes nothing public; these changes can still affect your types, tests and styles:
|
|
2571
|
+
|
|
2572
|
+
1. **`PresenceStatus` gains `'do-not-disturb'` and `'out-of-office'`** (`dnd` and `oof` stay, deprecated): an exhaustive `switch` or a `Record` over it needs the cases. `PresenceBadge` `status` is optional.
|
|
2573
|
+
2. **`Avatar` `size` also takes a number and `Persona` `size` gains `'huge'`:** code that narrows these unions needs the new members.
|
|
2574
|
+
3. **An Avatar in a rounded Tag is square** (`Tag` and `InteractionTag` pass their shape to their `media`).
|
|
2575
|
+
4. **Initials come from `getInitials`:** punctuation is dropped, a hyphen or apostrophe joins words, and names without letter initials show none.
|
|
2576
|
+
5. **AvatarGroup's popup is `AvatarGroup.Popover`:** the count reads `99+` past 99 (the name keeps the real number).
|
|
2577
|
+
6. **Card parts take their padding from `--wave-card-padding`** instead of a fixed `p-4`.
|
|
2578
|
+
7. **Carousel has a viewport element** (`.wave-carousel__viewport`) that clips the track; the default layout's buttons sit inside it. Reach the track by `.wave-carousel__track`.
|
|
2579
|
+
|
|
2580
|
+
The CHANGELOG's [0.13.0 section](CHANGELOG.md) lists the additions.
|
|
2581
|
+
|
|
2280
2582
|
## Upgrading from 0.11
|
|
2281
2583
|
|
|
2282
2584
|
0.12 removes nothing public; these changes can still affect your types and tests:
|