plass-ui 1.6.0 → 1.7.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/CHANGELOG.md +276 -0
- package/README.md +3 -1
- package/dist/components/accordion/PlAccordion.d.ts +13 -0
- package/dist/components/accordion/PlAccordion.js +1 -1
- package/dist/components/accordion/index.d.ts +1 -1
- package/dist/components/alert/PlAlert.js +1 -1
- package/dist/components/animate-headline/PlAnimateHeadline.d.ts +10 -1
- package/dist/components/animate-marquee/PlAnimateMarquee.d.ts +8 -1
- package/dist/components/animate-marquee/PlAnimateMarquee.js +1 -1
- package/dist/components/app-logo/PlAppLogo.js +1 -1
- package/dist/components/area-chart/PlAreaChart.d.ts +35 -6
- package/dist/components/area-chart/PlAreaChart.js +1 -1
- package/dist/components/aspect-ratio/PlAspectRatio.js +1 -1
- package/dist/components/avatar/PlAvatar.js +1 -1
- package/dist/components/back-top/PlBackTop.d.ts +5 -5
- package/dist/components/back-top/PlBackTop.js +1 -1
- package/dist/components/badge/PlBadge.js +1 -1
- package/dist/components/bar-chart/PlBarChart.d.ts +54 -2
- package/dist/components/bar-chart/PlBarChart.js +1 -1
- package/dist/components/blockquote/PlBlockquote.d.ts +2 -2
- package/dist/components/blockquote/PlBlockquote.js +1 -1
- package/dist/components/bottom-navigation/PlBottomNavigation.js +1 -1
- package/dist/components/button/PlButton.d.ts +7 -0
- package/dist/components/button/PlButton.js +1 -1
- package/dist/components/calendar/PlCalendar.js +1 -1
- package/dist/components/card/PlCard.d.ts +7 -4
- package/dist/components/carousel/PlCarousel.d.ts +14 -4
- package/dist/components/carousel/PlCarousel.js +1 -1
- package/dist/components/chat-bubble/PlChatBubble.js +1 -1
- package/dist/components/checkbox/PlCheckbox.js +1 -1
- package/dist/components/chip/PlChip.d.ts +2 -1
- package/dist/components/chip/PlChip.js +1 -1
- package/dist/components/collapsible/PlCollapsible.d.ts +11 -0
- package/dist/components/collapsible/PlCollapsible.js +1 -1
- package/dist/components/color-picker/PlColorPicker.d.ts +3 -1
- package/dist/components/color-picker/PlColorPicker.js +1 -1
- package/dist/components/combobox/PlCombobox.d.ts +11 -5
- package/dist/components/combobox/PlCombobox.js +1 -1
- package/dist/components/command-palette/PlCommandPalette.js +1 -1
- package/dist/components/confirm/PlConfirmProvider.js +1 -1
- package/dist/components/data-table/PlDataTable.d.ts +13 -2
- package/dist/components/data-table/PlDataTable.js +1 -1
- package/dist/components/drawer/PlDrawer.js +1 -1
- package/dist/components/fieldset/PlFieldset.js +1 -1
- package/dist/components/file-picker/PlFilePicker.d.ts +3 -1
- package/dist/components/file-picker/PlFilePicker.js +1 -1
- package/dist/components/floating-action-button/PlFloatingActionButton.d.ts +5 -0
- package/dist/components/floating-action-button/PlFloatingActionButton.js +1 -1
- package/dist/components/floating-bottom-navigation/PlFloatingBottomNavigation.js +1 -1
- package/dist/components/footer/PlFooter.d.ts +3 -1
- package/dist/components/gallery/PlGallery.js +1 -1
- package/dist/components/gauge-chart/PlGaugeChart.js +1 -1
- package/dist/components/header/PlHeader.d.ts +4 -2
- package/dist/components/header/PlHeader.js +1 -1
- package/dist/components/heatmap-chart/PlHeatmapChart.js +1 -1
- package/dist/components/hover-card/PlHoverCard.js +1 -1
- package/dist/components/how-to-steps/PlHowToSteps.js +1 -1
- package/dist/components/image/PlImage.js +1 -1
- package/dist/components/line-chart/PlLineChart.d.ts +32 -6
- package/dist/components/line-chart/PlLineChart.js +1 -1
- package/dist/components/menu/PlMenu.js +1 -1
- package/dist/components/mockup/PlMockup.d.ts +5 -0
- package/dist/components/mockup/PlMockup.js +1 -1
- package/dist/components/modal/PlModal.js +1 -1
- package/dist/components/navigation-menu/PlNavigationMenu.d.ts +4 -3
- package/dist/components/navigation-menu/PlNavigationMenu.js +1 -1
- package/dist/components/number-field/PlNumberField.d.ts +7 -5
- package/dist/components/number-field/PlNumberField.js +1 -1
- package/dist/components/otp-field/PlOtpField.js +1 -1
- package/dist/components/overlay/PlOverlay.js +1 -1
- package/dist/components/page-layout/PlPageLayout.d.ts +14 -3
- package/dist/components/page-layout/PlPageLayout.js +1 -1
- package/dist/components/pagination/PlPagination.js +1 -1
- package/dist/components/panes/PlPanes.js +1 -1
- package/dist/components/pie-chart/PlPieChart.d.ts +26 -1
- package/dist/components/pie-chart/PlPieChart.js +1 -1
- package/dist/components/pill/PlPill.js +1 -1
- package/dist/components/popconfirm/PlPopconfirm.d.ts +8 -1
- package/dist/components/popconfirm/PlPopconfirm.js +1 -1
- package/dist/components/popover/PlPopover.js +1 -1
- package/dist/components/progress-box/PlProgressBox.js +1 -1
- package/dist/components/progress-circular/PlProgressCircular.js +1 -1
- package/dist/components/progress-linear/PlProgressLinear.js +1 -1
- package/dist/components/radio-group/PlRadioGroup.js +1 -1
- package/dist/components/rating/PlRating.js +1 -1
- package/dist/components/scatter-chart/PlScatterChart.js +1 -1
- package/dist/components/scroll-area/PlScrollArea.js +1 -1
- package/dist/components/segmented-button/PlSegmentedButton.js +1 -1
- package/dist/components/select/PlSelect.d.ts +4 -1
- package/dist/components/select/PlSelect.js +1 -1
- package/dist/components/sidebar/PlSidebar.js +1 -1
- package/dist/components/slider/PlSlider.js +1 -1
- package/dist/components/sparkline/PlSparkline.js +1 -1
- package/dist/components/stepper/PlStepper.js +1 -1
- package/dist/components/switch/PlSwitch.js +1 -1
- package/dist/components/table/PlTable.d.ts +11 -1
- package/dist/components/table/PlTable.js +1 -1
- package/dist/components/tabs/PlTabs.d.ts +18 -1
- package/dist/components/tabs/PlTabs.js +1 -1
- package/dist/components/text-field/PlTextField.d.ts +6 -8
- package/dist/components/text-field/PlTextField.js +1 -1
- package/dist/components/text-link/PlTextLink.js +1 -1
- package/dist/components/timeline-chart/PlTimelineChart.js +1 -1
- package/dist/components/toast/PlToast.js +1 -1
- package/dist/components/toggle/PlToggle.js +1 -1
- package/dist/components/tooltip/PlTooltip.d.ts +4 -0
- package/dist/components/tooltip/PlTooltip.js +1 -1
- package/dist/components/tour/PlTour.js +1 -1
- package/dist/components/transfer/PlTransfer.d.ts +5 -2
- package/dist/components/transfer/PlTransfer.js +1 -1
- package/dist/components/tree/PlTree.js +1 -1
- package/dist/components/window-pane/PlWindowPane.d.ts +13 -3
- package/dist/components/window-pane/PlWindowPane.js +1 -1
- package/dist/internal/animate.js +1 -1
- package/dist/internal/bottom-bar.d.ts +29 -0
- package/dist/internal/bottom-bar.js +1 -0
- package/dist/internal/calendar.js +1 -1
- package/dist/internal/chart-frame.d.ts +88 -10
- package/dist/internal/chart-frame.js +1 -1
- package/dist/internal/chart-line.d.ts +11 -6
- package/dist/internal/chart-line.js +1 -1
- package/dist/internal/chart.d.ts +149 -1
- package/dist/internal/chart.js +1 -1
- package/dist/internal/defaults.d.ts +2 -2
- package/dist/internal/focusable.d.ts +10 -0
- package/dist/internal/focusable.js +1 -1
- package/dist/internal/form.d.ts +29 -0
- package/dist/internal/form.js +1 -1
- package/dist/internal/glow.d.ts +32 -1
- package/dist/internal/glow.js +1 -1
- package/dist/internal/icons.d.ts +24 -0
- package/dist/internal/icons.js +1 -1
- package/dist/internal/labels.d.ts +22 -0
- package/dist/internal/labels.js +1 -1
- package/dist/internal/loading.d.ts +13 -0
- package/dist/internal/loading.js +1 -0
- package/dist/internal/mockup.js +1 -1
- package/dist/internal/notch.d.ts +57 -3
- package/dist/internal/notch.js +1 -1
- package/dist/internal/picker.d.ts +8 -2
- package/dist/internal/picker.js +1 -1
- package/dist/internal/progress.d.ts +17 -6
- package/dist/internal/progress.js +1 -1
- package/dist/internal/sizer.d.ts +12 -11
- package/dist/internal/sizer.js +1 -1
- package/dist/internal/steps.d.ts +0 -15
- package/dist/internal/steps.js +1 -1
- package/dist/internal/styles.d.ts +114 -8
- package/dist/internal/styles.js +1 -1
- package/dist/internal/table-scroll.d.ts +42 -0
- package/dist/internal/table-scroll.js +1 -0
- package/dist/internal/table.js +1 -1
- package/dist/internal/text.d.ts +8 -5
- package/dist/internal/window.js +1 -1
- package/dist/locales/de.js +1 -1
- package/dist/locales/es.js +1 -1
- package/dist/locales/fr.js +1 -1
- package/dist/locales/ja.js +1 -1
- package/dist/locales/ko.js +1 -1
- package/dist/locales/zh-Hans.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/tailwind.css +406 -42
- package/dist/tokens.css +406 -42
- package/dist/types.d.ts +217 -13
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,282 @@
|
|
|
4
4
|
|
|
5
5
|
## vNext (2026--)
|
|
6
6
|
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **A quick click on the words of a resting `float` label opens the `PlTreeSelect` under it.** The press gave the trigger the focus, which ended the rest and put the label back in reach of the pointer while it was still lying over the words. A release that came before the label had moved off them landed on the label, the browser gave the click to the frame round both rather than to the trigger, and the picker stayed shut. The label now lets the pointer through until a press that went down on the control is over, and a click on the label once it has risen still reaches the control.
|
|
10
|
+
|
|
11
|
+
## 1.7.0 (2026-09-28)
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **A field-shaped control takes `labelPlacement: 'float'`, a label that rests inside the control until it is wanted in the notch.** While the control is empty, does not have the focus and has no popup open, the label sits where the value would be written, set as the placeholder is — in the control's own text size, the regular weight and the muted ink — and the placeholder waits behind it. As soon as one of the three stops being true, the label rises into the same notch a `notch` label sits in, at its weight, and it comes back down once all three hold again. It moves by its position, its font size and its weight rather than by a transform, and under reduced motion it arrives at once. The gap in the edge opens as the label starts to rise and closes only once it is back down, so the line never crosses the word. A control that draws something at its start keeps a floating label in the notch, since that is where it would rest: a field with a `startIcon`, a `PlNumberField` with `split` steppers, the date, time and colour pickers with their glyph, and a `PlFilePicker`. It rests in `PlTextField`, `PlNumberField`, `PlCombobox`, `PlSelect` and `PlTreeSelect`, and `PlassProvider` carries it. The Flutter build adds the same placement.
|
|
16
|
+
|
|
17
|
+
- **`PlAccordion` takes `headingLevel`, so its headers sit at the level the page's outline needs.** Every header was an `<h3>`, so an FAQ straight under the page's title skipped a level. It takes `1` to `6` and defaults to `3`; only the element changes, never the type scale.
|
|
18
|
+
|
|
19
|
+
- **`PlAnimateMarquee` takes `label`, which names the strip.** Under `prefers-reduced-motion` the box becomes a tab stop while there is anything to scroll, and that stop had no name unless the caller added `role="group"` and an `aria-label` themselves. `label` makes the box a group with that name, the way `PlScrollZone`'s `label` names its region.
|
|
20
|
+
|
|
21
|
+
- **A `fixed` `PlBottomNavigation` or `PlFloatingBottomNavigation` publishes its height as `--plass-bottom-navigation-height`.** The end of the page was always under the bar, and so was a link reached with Tab, with no way to know how much room to leave. The bar now writes its measured height, the home indicator included, on the root element while it is mounted, and the token is `0px` without one, so `padding-bottom` and `scroll-padding-bottom` on the page reserve exactly the room it covers.
|
|
22
|
+
|
|
23
|
+
- **`PlButton`, `PlIconButton` and `PlFloatingActionButton` take `loadingLabel`, the word a screen reader hears while `loading`.** A loading button was always described by the label set's `loading`, "Loading" in English, which does not say what is being waited for. `loadingLabel` puts the button's own word in its place, such as "Saving", and the name stays what it was.
|
|
24
|
+
|
|
25
|
+
- **An `autoPlay` `PlCarousel` has a button that stops it and starts it again.** There was no way to stop a carousel that advanced on its own, which WCAG 2.2.2 asks of anything that moves for longer than five seconds. The button sits in the frame's top corner, comes first in the focus order, and is named "Stop slide show" or "Start slide show" from the new `carouselStop` and `carouselPlay` keys in all seven label packs, or from `playLabel` and `stopLabel`.
|
|
26
|
+
|
|
27
|
+
- **`PlassChartSeries` takes `id`, which the chart knows a series by from one render to the next.** A series' legend entry was known by its name and how many series before it have that name, so a series renamed between two renders came back switched on and let go of the pointer resting on its entry, and when the first of two series with one name left the data, the second took its state over. A series with an `id` keeps its switched-off state and the pointer on its entry through both. A series without one is known as before, and so is a `PlPieChart`'s slice, which has no `id`. The Flutter build makes the same change.
|
|
28
|
+
|
|
29
|
+
- **A chart's tooltip takes `mode: 'nearest'`, which answers for the mark the pointer is nearest rather than for the column it is over.** It is what a `PlScatterChart` has always done, and on a line or an area it is the answer when two series cross and the reader is pointing at one of them rather than at the month they share. There is no crosshair with it — a crosshair says "these numbers all belong to this column", and there is no column — and the arrow keys walk mark by mark instead of column by column. It measures to the mark, which on a bar is the bar's data end, and it reads a stacked series where the band was actually drawn rather than at its bare value.
|
|
30
|
+
|
|
31
|
+
- **A chart legend can fold past `maxEntries`.** A legend is a key, and a key of twelve names wrapped over four rows is a paragraph the reader has to search — on a card it is also four rows the plot no longer has. Past the number given, the rest go behind a button that says how many they are and opens them, with the same button folding them back. The entries kept are the **first** ones, in the order the series were passed, because that is the order their colours were handed out in and a key that rearranged itself as series were switched off would stop being a key. Nothing is hidden from a screen reader by it: the fold is a real button, reachable by keyboard, and every series is in the table under the chart either way.
|
|
32
|
+
|
|
33
|
+
- **`PlBarChart` takes `sort`, `maxCategories` and `otherLabel`.** A bar chart is the one shape whose categories can be shuffled without losing anything — that is the test for reaching for it over a line chart — so `sort` is free, and it is what turns a wall of bars into a ranking a reader can scan down. `maxCategories` keeps the largest that many and sums the rest into one, which is the answer to a chart of ninety countries: a bar too short to see costs width without saying anything. What is folded is decided by size and never by `sort`, and the fold is always last, because it is not a category but what is left; a fold of nothing but gaps stays a gap rather than becoming a zero. Both are changes to the **data**, so the axis, the tooltip and the table under the chart all agree with the picture about which categories there are — and both happen before a `'full'` stack renormalises, or a category folded away afterwards would have taken its share of every other bar with it. A series hidden from the legend is still counted, because a chart whose columns rearranged themselves when an entry was clicked is one a reader cannot use. The label pack gains `chartOther`, `chartMore` and `chartFewer` in all seven languages.
|
|
34
|
+
|
|
35
|
+
- **A chart takes `reference`, which draws a target, an average or a limit across the plot.** One line or several, each at a value on the **value** axis — so a reference runs across a vertical chart and down a horizontal one, and a caller who turns a bar chart on its side does not have to move it. It is **not data** and is drawn as if it knows that: dashed, in the muted ink rather than a palette slot, and under the marks, because a reference that looks like a series is one a reader will try to read a value off. `color` takes it to a family where the line means something the page already has a colour for, `dashed: false` makes it solid, and `label` sets a short word at the end of it. Each one is also written into the description a screen reader is handed with the chart, because a target is a fact about the picture rather than decoration on it. On `PlLineChart`, `PlAreaChart`, `PlBarChart`, `PlScatterChart` and `PlTimelineChart`.
|
|
36
|
+
|
|
37
|
+
- **A value axis can step by multiplying, with `scale`.** `log` is the one scale in the library that changes what a distance on the plot means: the same length becomes the same **ratio** rather than the same number of units, so the gap from 10 to 100 is the gap from 100 to 1,000 — which is the only way a series that runs from 3 to 3,000,000 is drawn with the small end still legible. There is no zero on it and nothing below it either, and that is stated rather than hidden: the axis floors at the smallest positive power of ten the data needs, or three decades under the top when the data offers none, and a zero or a negative is drawn on that floor. The ticks are powers of ten, with each decade's 2 and 5 as well over a span of two decades or fewer. It is read on the value axis, and on a category axis only where that axis is a second value axis — a `PlScatterChart`'s. A bar is the wrong mark for it, for the same reason a bar's axis cannot be cropped.
|
|
38
|
+
|
|
39
|
+
- **A chart's value labels take `valueLabelColor`, for a chart that needs them in the page's own ink.** They are written in their series' colour by default, which is what says which number belongs to which mark. The palette clears 4:1 against the sheet — the floor the design language sets for a chart _mark_ rather than the 4.5:1 body text wants — so a chart whose labels have to meet the text contrast rule on their own asks for `ink` and gets the page's foreground on every one. On `PlLineChart`, `PlAreaChart` and `PlBarChart`.
|
|
40
|
+
|
|
41
|
+
- **A chart's category axis can turn its labels, with `tickAngle`.** An axis runs out of room across and not down, so a name wider than its slot was cut to it — and past about four characters a cut stops telling two names apart: "Onboar…", "Onboa…" and "Onbo…" are three labels a reader cannot tell apart. `xAxis` now takes an angle in degrees, and a turned label takes one line of text across the axis however long it is, spending the room under the plot instead. `-45` is the one to reach for and `-90` stands the names on end. The band under the plot grows to hold them, up to about two fifths of the chart's height; past that a name is still cut, and the tooltip and the table still have all of it. Only the category axis, and only where it runs along the bottom — a value axis' ticks are numbers already rounded to be short, and a horizontal bar chart's names already have a row each.
|
|
42
|
+
|
|
43
|
+
- **`tickAngle` takes `'auto'`, which turns the labels only once one of them would be cut.** Upright is the best an axis can do when there is room for it, and a diagonal beats a cut at every width, so `auto` is the setting for a chart whose categories are the caller's data rather than the caller's choice. It settles on `0` or `-45` and never on a third angle: one fitted to the longest name would be a different angle on every chart on a dashboard, and would change under the reader as the window is dragged.
|
|
44
|
+
|
|
45
|
+
- **`PlLineChart` and `PlAreaChart` take `nulls`, which has the answer `connectNulls` could not express.** A `null` means _nothing was measured_, which is a different claim from _nothing happened_, and a boolean only had two of the three replies. `gap` breaks the line, which is the default and what the chart has always done; `connect` joins the two sides, which is what `connectNulls` was; and `zero` reads the gap as a nought — on the value axis, in the tooltip and in the table under the chart as well as under the line, because a zero is a value and has to be somewhere on the axis. `connectNulls` still works and is read only where `nulls` says nothing, so nothing has to change today; it is deprecated and goes in 2.0.0.
|
|
46
|
+
|
|
47
|
+
- **`PlPieChart` takes `innerRadius` and `padAngle`.** `shape` picked both — nothing cut out of a `pie`, a little under two thirds out of a `donut` and a `semi`, and a gap of 2px between slices — and neither could be moved. `innerRadius` is a fraction of the radius, so a hole holds its proportion at whatever size the chart is drawn; `padAngle` is in degrees, and widening it is what makes a ring read as separate segments rather than as one band. Left out, both are what they were. A slice narrower than twice the gap still keeps none of it, or a one-degree sliver would invert and draw the whole circle instead of nothing.
|
|
48
|
+
|
|
49
|
+
- **`PlPopconfirm` takes `loadingLabel`, the word a screen reader hears while it waits on `onConfirm`.** Its confirming button was always described by the label set's `loading`, "Loading" in English, which does not say what is being waited for, and the popconfirm had no way to hand it another. `loadingLabel` reaches that button and puts the popconfirm's own word in its place, such as "Revoking", and the name stays what it was.
|
|
50
|
+
|
|
51
|
+
- **`PlTable` takes `label`, which names the table when there is no `caption`.** It is the `<table>`'s `aria-label`, and while a grid wider than its sheet, or taller than its `maxHeight`, scrolls, it also names the box the grid scrolls in, which is a tab stop then and had no name without a caption. The box becomes a group with that name, the way `PlScrollZone`'s `label` names its strip; a `caption` still names both when there is one.
|
|
52
|
+
|
|
53
|
+
- **`PlTabs` takes `align`, which places each label inside its tab.** It moves the words and never the tabs, so it is safe to set on a bar that is already laid out. A horizontal bar sizes every tab to its own label and nothing changes; it takes effect on a `vertical` bar, whose tabs are all as wide as the widest, and on a `fullWidth` one, whose tabs are all an equal share. `start` is what a bar down the side of a settings page usually wants, so the names line up as a list rather than drifting around a centre line. Logical rather than physical, so it turns over under `rtl` and an icon beside the label travels with it.
|
|
54
|
+
|
|
55
|
+
- **The title bar of a `draggable` `PlWindowPane` is a tab stop, and the arrow keys move the window.** A window moved only by dragging, so a keyboard could resize one and never move it. The bar is now a stop ahead of the window's buttons, named from the new `moveWindow` key in all seven label packs or from `moveLabel`, with a ring while the keyboard holds it. Each arrow key moves the window 16px, and 64px with Shift, the way the arrow points in either writing direction, and a key never takes the bar off the screen. Every move goes through `offset`, so a window given `offset` and `onOffsetChange` reports where it should go, which is also how an app adds buttons that move it without a drag.
|
|
56
|
+
|
|
57
|
+
### Changed
|
|
58
|
+
|
|
59
|
+
- **`plass-ui/styles.css` no longer restyles the page's own images and SVGs.** Its reset made every `<img>`, `<svg>` and `<video>` on the page a block and gave every picture `max-width: 100%` and `height: auto`, so an icon set in a sentence dropped onto a line of its own and a picture with `width` and `height` written on it lost the height it was given. The components now lay out the glyphs and pictures they draw themselves, and a bare `<img>` handed to a `PlCarousel` slide, a `PlAvatar` or a `PlChatBubble`'s `media` still fits its box. A project that runs Tailwind is unaffected: Preflight still applies both rules.
|
|
60
|
+
|
|
61
|
+
- **A field's interaction light is turned down, and steps out of the way while the field is being typed into.** A key is pressed and the reader has moved on; a field is pressed once and then written in for a minute, with the bloom sitting under the words being typed and following a pointer nobody is moving any more. At a key's strength that reads as a stain on the sentence rather than as the surface answering. Both layers are now mixed down to `--plass-glow-field-strength`, a new token at 55% that a theme can move, on `PlTextField`, `PlNumberField`, `PlSelect`, `PlCombobox`, `PlFilePicker` and the six picker triggers. Buttons, toggles, chips, pills and segmented controls are untouched. On the three fields that hold a text input the bloom also fades out on the first keystroke and comes back on the next real pointer move, which is `[data-quiet]` over `.plass-glow` and costs one render per change of it.
|
|
62
|
+
|
|
63
|
+
- **A carousel stops once the focus comes into it, and stays stopped until its button starts it again.** Hover and focus shared one pause, so a pointer passing over the frame started it again while a keyboard reader's focus was still inside. The pointer now pauses it only while it is over the frame. A reader who asked for reduced motion starts stopped rather than never starting, and the live region announces the slide once the carousel has stopped.
|
|
64
|
+
|
|
65
|
+
- **A `PlScatterChart` card and its live region write a bubble's `z` after its y, in brackets.** The size was left to be read off the bubble, and was written only in the table under the chart. It now follows the y through the chart's `format`, or compactly without one, "10, Q1: 22 (5)", and follows a point's own `label` too, since a label stands in for the y alone.
|
|
66
|
+
|
|
67
|
+
- **A `dashed` series is keyed in the legend with a short dashed rule rather than the filled square.** A dashed line reads as a forecast or a target on the plot, and its legend entry was the same square as every other series', so the key did not carry the one distinction the plot did. The entry now draws two dashes at the line's weight and rhythm wherever the line is drawn dashed, on `PlLineChart` and on a `PlAreaChart` that is not stacked; a bar or a stacked band has no line to dash and keeps the square.
|
|
68
|
+
|
|
69
|
+
- **A chart's value labels are written in their series' colour.** `valueLabels` wrote every number in the page's own ink, so a plot with four labelled lines left the reader tracing each number back to the mark it belonged to. Each one now takes the colour of the line or the bar it sits on — or of the point, where a point carries a colour of its own — at a slightly heavier weight to hold up against the sheet. A pie's share is unchanged: it is written _inside_ the slice, where the sheet's own colour is what stays legible on a pale fill and a dark one. The palette clears 4:1 against the sheet, which is the floor the design language sets for a chart mark rather than the 4.5:1 body text wants; every number is also in the tooltip and in the table under the chart.
|
|
70
|
+
|
|
71
|
+
- **A chart legend's switched-off entry fades instead of going grey.** The swatch went part-transparent and the name was recoloured to the muted ink, which read as a second kind of text rather than as the same entry, off. The whole row now fades as one thing — swatch, name and value together, at one opacity — which is what a control that has been switched off looks like everywhere else in the library. The line through the name stays, because it is the half of "off" that survives being read in one colour. The Flutter build makes the same change.
|
|
72
|
+
|
|
73
|
+
- **A `PlCollapsible`'s title and subtitle wrap, as a `PlAccordionItem`'s do.** They were each held to one line and ellipsed, so a heading that ran past the header lost its end with nothing to press for the rest. `truncate` puts both back on one line, for a name out of a database beside a control.
|
|
74
|
+
|
|
75
|
+
- **`PlCommandPalette` draws the first 100 matching commands, with a line under the list saying how many more matched.** Every match was drawn, which made the first open and a short query slow at around two thousand commands. Typing narrows the list, so a command further down is a letter or two away, and the line is written with the label pack's `chartMore` ("150 more").
|
|
76
|
+
|
|
77
|
+
- **A `PlConfirmProvider` sheet draws no × any more, as the Flutter one never has.** A question is answered by its own buttons, which say what each answer does, and while it is `dismissible`, Escape and a press outside still answer no.
|
|
78
|
+
|
|
79
|
+
- **A `PlTextField`'s `startIcon`, `endIcon` and loading spinner stay muted while the field is focused, as a `PlNumberField`'s adornments do.** They turned to the family's accent as the field took the focus, which dyed the content of a glass field that the family otherwise reaches only at its edge, its ring and its caret. The focus still shows on those three.
|
|
80
|
+
|
|
81
|
+
### Fixed
|
|
82
|
+
|
|
83
|
+
- **A key or a move that changes nothing reports nothing, in both builds, as Base UI's slider reports nothing at an end.** An arrow at the end of a range still reported the value it left unchanged: through `PlPanes` `onResize` and `onResizeEnd`, `PlSidebar` `onResize` and `onResizeEnd`, a `PlWindowPane` corner's `onResize` and a `PlColorPicker`'s `onValueChange` from its square and its opacity rail in both builds, and through a Flutter `PlSlider`'s `onChanged` and `onChangeEnd`. Each now reports only a value that moved, and a drag held against a limit reports nothing either.
|
|
84
|
+
|
|
85
|
+
- **Under reduced motion everything a component eases arrives at once, as the Flutter surfaces do.** Only the pointer light stopped easing under `prefers-reduced-motion`. Every change the house transition carries still eased over `--plass-duration`, a glass key's wash, a field's edge, a shadow, a label's ink and a switch's track, and so did every transition a component writes for itself: a popup, sheet, scrim or toast fading in and out, an accordion, collapsible or tree branch folding, a chevron turning, the `PlTabs` indicator, the `PlSegmentedButton` tile, the `PlFloatingBottomNavigation` key and the `PlSwitch` thumb travelling, a progress bar, meter, ring or gauge filling, and the colours of close buttons, table rows, links, legend entries and field adornments. A `PlImage` picture that arrives at once takes its stand-in away as it arrives, rather than a `--plass-duration` later.
|
|
86
|
+
|
|
87
|
+
- **Clearing a picker from its × hands the focus back to the trigger.** The × leaves the page with the value it cleared, and the focus it held fell to the document, so a keyboard reader who emptied a date started again from the top of the page. It now goes to the trigger of the field they just emptied, on `PlDatePicker`, `PlDateRangePicker`, `PlDateTimePicker`, `PlTimePicker`, `PlColorPicker` and `PlTreeSelect`.
|
|
88
|
+
|
|
89
|
+
- **The × on a `PlAlert`, a toast, a `PlModal`, a `PlDrawer`, a `PlPopover`, a `PlTour` and a `PlFilePicker` file can be pressed anywhere in a 24px square around it.** It could be pressed only where it is drawn, which at the smaller sizes is under the minimum target size of WCAG 2.5.8. The × is drawn at the same size and nothing around it moves. It is the square the × on a chip and on a picker trigger already had.
|
|
90
|
+
|
|
91
|
+
- **A notched label stays where it is as its field takes and loses the focus, as the Flutter label does.** The edge thickens from 1px to 2px with the focus, and a legend is laid out from the inside of its border, so the label moved a pixel along with it and seemed to shake on a `PlTextField`, `PlSelect`, `PlCombobox`, `PlNumberField` and the six picker triggers. The edge still thickens, inward, and the label no longer moves.
|
|
92
|
+
|
|
93
|
+
- **Under reduced motion, a `PlAnimate*` effect ends on its last frame rather than on the element as it stands.** The effect was switched off, so `<PlAnimateRotate from={0} to={90}>` stood at 0°, a `mode="out"` element never left, and a caller waiting on `animationend` waited for ever. The effect now runs in no time: nothing changes until the moment it would have started, `delay` included, and then it is on its last frame, so the turn stands at 90°, an exit has left and `animationend` fires. An alternating run ends where it would have, an endless one on the last frame of one pass, and a `timeline="view"` effect goes back to the clock. Content waiting for its trigger is still shown as it is.
|
|
94
|
+
|
|
95
|
+
- **A `PlAppLogo` or `PlAspectRatio` rendered as a link draws the house focus ring while the keyboard holds the focus, as the Flutter logo draws it, rather than the browser's own outline.** Neither carried the ring a `render={<a href="…" />}` needs, so a keyboard reader saw the browser's default outline round the one link on the page drawn in another style.
|
|
96
|
+
|
|
97
|
+
- **A `PlAppLogo` plate is drawn in the material a `PlAvatar` is, as in the Flutter build.** It rests at an elevation of 1 on every variant, a `glass` plate takes the neutral `--plass-border` edge and the gloss along its top, and a `ghost` plate takes `--p-soft-press`. A `glass` plate had a white edge that disappeared on a white header and no gloss, a `solid` one had no drop shadow under its tinted one, and a `ghost` one took the paler `--p-soft`.
|
|
98
|
+
|
|
99
|
+
- **A floating `PlBackTop` clears the safe area at its inline end as well as at the bottom.** It added only `env(safe-area-inset-bottom)`, so the camera cutout of a phone held on its side could cover it. It now stands off the side it is against as well, the right or the left under RTL, as `PlFloatingActionButton` does.
|
|
100
|
+
|
|
101
|
+
- **A `ghost` `PlBadge` is lifted by its `elevation`, as a `ghost` `PlAvatar` is.** The badge kept its own copy of the mark material, and that copy left the elevation shadow off `ghost`, so a ghost badge given an `elevation` still lay flat. `solid` and `glass` badges are unchanged.
|
|
102
|
+
|
|
103
|
+
- **A `PlButton`, a `PlIconButton` and a `PlFloatingActionButton` that are `loading` say so after their name.** The button was announced as unavailable with nothing to say why: most screen readers do not read `aria-busy`, and the spinner is hidden from them. It is now described by the label pack's new `loading` key, "Loading" in English, so its name, and an `aria-label` given to it, stays as it was.
|
|
104
|
+
|
|
105
|
+
- **A `PlCalendar` draws its chosen day in its family's gradient, as a picker's calendar does.** The inline calendar set no fill for the chosen cell, so the day it held showed only as a bolder number in the page's ink.
|
|
106
|
+
|
|
107
|
+
- **An `autoPlay` `PlCarousel` holds the slide it is on for a whole `interval` once its browser tab comes back from the background.** It held still while the tab was hidden, but the interval went on running behind it, so the first turn could come a moment after the page was back in sight. Coming back now starts the interval over, as it does when a hidden tab panel shows the carousel again.
|
|
108
|
+
|
|
109
|
+
- **An `autoPlay` `PlCarousel` holds still while a finger is down on its strip, and for a whole `interval` once the finger lifts.** It paused only while a pointer was over the frame, and a browser that takes a touch over to scroll the strip reports that pointer as cancelled and gone while the finger is still dragging, so the next turn pulled the strip from under the finger. Every touch that starts on the strip now holds it until the last one lifts.
|
|
110
|
+
|
|
111
|
+
- **Clicking an arrow or a dot of an `autoPlay` `PlCarousel` stops it in Safari too.** The carousel stopped only because the click brought the focus into it, and Safari does not focus a button it clicks, so there a reader who had steered to a slide saw it turn away at the next interval. A click on an arrow or a dot now stops it by itself, as a press does in the Flutter build, and the button reads "Start slide show" until it is pressed. A carousel the button has just started keeps playing through a click on an arrow or a dot until the focus next comes in or goes out, whether or not the start brought the focus in.
|
|
112
|
+
|
|
113
|
+
- **A `PlCarousel` in a hidden tab or a closed disclosure shows the slide its dots mark when it appears, and an `autoPlay` one waits there while it is hidden.** The strip could not be placed while it had no width, so one mounted there showed the first slide under the dot its `defaultValue` or `value` named, and one hidden after it had been on screen came back on the slide it was hidden on, whatever `value` had moved it to meanwhile. `autoPlay` also went on turning the dots while nobody could see them. The strip is now placed on the current slide every time its width comes back, before that frame is painted and without travelling there, and `autoPlay` holds while the track has no width, then keeps the slide it was hidden on for a whole `interval` once it is shown again, without touching the stop and start button.
|
|
114
|
+
|
|
115
|
+
- **A `PlCarousel` given a `defaultValue` or `value` other than 0 opens on that slide.** The strip was placed only when the slide changed after the first render, so the dots marked the chosen slide while the first one was showing. The strip is now on the chosen slide before the first paint, without travelling there.
|
|
116
|
+
|
|
117
|
+
- **A line or area series the legend lets go of stays cut out under its markers until it is whole again, as in the Flutter build.** The cut went at once while the series' opacity eased back, so its line and band showed through its markers for the length of the ease.
|
|
118
|
+
|
|
119
|
+
- **A named `PlGaugeChart` whose `min` equals `max` is called by its `label` alone.** It draws only its empty state, but its name still gave a reading and the top of the scale, "Quota: 5 / 10", ahead of the empty state's words that describe it. It draws no reading, so its name no longer gives one, as with a `null` value. The Flutter build makes the same change.
|
|
120
|
+
|
|
121
|
+
- **An empty `PlPieChart` `donut` or `semi` no longer draws its `center` over the empty state.** With a total of zero no ring is drawn, and the empty state's words sit where the hole would be, but the caller's `center` was still laid over them in the middle of the box. An empty pie now draws its empty state alone, as the Flutter pie does.
|
|
122
|
+
|
|
123
|
+
- **A chart's empty state and what a `PlPieChart`'s hole holds are read, and so are a named `PlGaugeChart`'s own `center` and its `caption`.** All of them are drawn inside the chart's `role="img"`, whose content a screen reader never reads, so an empty `PlLineChart`, `PlAreaChart`, `PlBarChart`, `PlScatterChart`, `PlTimelineChart`, `PlHeatmapChart` or `PlPieChart` was announced by its name alone, a donut's "2,670 accounts" was never heard, and a gauge's caption and a `center` of its own were lost behind a name that says only the number. They now describe the chart through `aria-describedby`: the empty state's words in place of the summary, the pie's centre ahead of its slices, and a named gauge's own `center`, then its `caption`, or its empty state, leaving out the number its name already says. The Flutter charts already read the first two after their name, and the Flutter build makes the same change to the gauge.
|
|
124
|
+
|
|
125
|
+
- **A line or area chart draws its markers over every band and every line, and its value labels over every marker.** A stacked `PlAreaChart` drew each band's markers and labels before the band above it, so that band's tint covered the upper half of each marker and the labels, and the gap between the two bands ran through the middle of each marker; on a line chart, a line drawn later crossed an earlier series' markers. A series faded for a legend entry still fades its markers and labels with it, and its own line or band does not show through them. The Flutter build makes the same change.
|
|
126
|
+
|
|
127
|
+
- **A `PlScatterChart`, a `PlTimelineChart`, and a `PlLineChart`, `PlAreaChart` or `PlBarChart` whose tooltip is in `nearest` mode go on reading the mark they are on when a series or a row ahead of it leaves the data.** The mark being read was held by its series' place, so when a series before it left, the card and the live region read the mark at the same place in the series that moved into its place, and a mark whose series left handed its reading to the series after it. It is now held by what its series' legend entry is known by, its `id`, its name or else its place, and a timeline's span by its row's name or else its place, and the reading is let go once that series or row has left. The Flutter build makes the same change.
|
|
128
|
+
|
|
129
|
+
- **A `PlPieChart` goes on reading the slice it is on when a slice ahead of it leaves the data.** The slice being read was held by its place, so when a slice before it left, the card and the live region read whichever slice moved into that place, and a slice read as it left the data handed its reading to the slice that moved in. It is now held by its name, as a slice switched off in the legend is, and the reading is let go once no slice drawn has that name. The Flutter build makes the same change.
|
|
130
|
+
|
|
131
|
+
- **Two series of the same name in a chart's legend, or two slices of the same name in a `PlPieChart`'s, are switched off and pointed at one at a time.** Each legend entry was known by its name alone, so switching off either of two series of one name switched off both, pointing at the second faded every series but the first, and React warned of two children with the same key in the legend and in the table under the chart. A series named "1" was known by the same key as an unnamed series in the second place, so the two switched off and on together. A repeated name is now told apart by how many series before it have that name, and a name never meets a place. The Flutter build makes the same change.
|
|
132
|
+
|
|
133
|
+
- **A series switched off in a chart's legend, or a slice switched off in a `PlPieChart`'s, is held by its name when the data changes.** It was held by its place, so when a series ahead of it left the data, the series that moved into that place was switched off instead, and a place past the new end switched a series off again once the data grew back. It is now held by its name, or by its place when it has none, and a series that leaves the data is drawn again if it comes back. `hidden` is still read once, when the chart mounts. The Flutter build makes the same change.
|
|
134
|
+
|
|
135
|
+
- **A `PlPieChart` lets go of the slice it is reading once it is rendered again with that slice drawing no arc.** A slice that left the data went on being read as "0 · 0%", or "0 · NaN%" when the slices left summed to 0, and a slice now worth 0 or a gap went on being read as worth nothing, each with every other slice faded for it. A slice that still draws an arc is still read. The Flutter build makes the same change.
|
|
136
|
+
|
|
137
|
+
- **`Home` and `End` on a line, bar or area chart whose tooltip is in `item` mode read the whole column they move to, as in the Flutter build.** With the pointer still over the plot, either key read only the one value nearest where the pointer last was, where the arrow keys read the whole column, since a key brings no pointer to measure against.
|
|
138
|
+
|
|
139
|
+
- **A `PlHeatmapChart` rendered again without the cell it is reading lets go of it, as in the Flutter build.** A cell the data turned into a gap, or a treemap tile whose value no longer had an area to be, was kept: nothing was read while it was gone, `Escape` was taken with nothing to clear, and once the data brought the cell back it was read again, with its card and drawn whole. A cell that is still there is still read.
|
|
140
|
+
|
|
141
|
+
- **A line, bar or area chart lets go of the column it is reading, and a scatter, a timeline or a chart whose tooltip is in `nearest` mode of the mark it is reading, once it is rendered again without it, as in the Flutter build.** A column past the end was kept, with its crosshair drawn past the plot, and read again once the data grew back, and a mark was held by its place among the marks, so the reading moved onto whichever mark took that place. A column or a mark that is still there is still read.
|
|
142
|
+
|
|
143
|
+
- **A line, bar, area, scatter or pie chart lets go of the legend entry the pointer or the focus is on when it is rendered again without that entry.** The entry's button was removed without reporting a leave, so its series stayed hovered: every remaining entry was drawn faded once the last series went, every series but the one that took the place of a middle one was faded, and the other series faded again once the data brought a series back to that place, wherever the pointer was by then.
|
|
144
|
+
|
|
145
|
+
- **A `PlPieChart` whose tooltip is turned off takes no key, as every other chart.** With `tooltip={false}` or `mode: 'none'`, ← and → still lit a slice and faded the others, with no card and no live region to say which slice it was. The keys now go on to whatever the chart sits in, as they do on a line, bar, area, scatter, timeline or heatmap chart with its tooltip off.
|
|
146
|
+
|
|
147
|
+
- **The first ← on a `PlPieChart` with no slice being read reaches the last slice.** It reached the second from the end, while the first → reached the first slice; the Flutter pie already started a walk backwards on the last.
|
|
148
|
+
|
|
149
|
+
- **Every chart mark fades as a legend entry or the crosshair points at it, and a line's marker and a scatter mark grow under the crosshair, over `--plass-duration`.** The class that eases them was pieced together out of three strings, so the stylesheet never had a rule for it. Every line, area, bar, scatter, pie, heatmap and timeline mark changed in one frame. Under reduced motion they still change at once.
|
|
150
|
+
|
|
151
|
+
- **A `PlPieChart` slice's name is said and written once.** The live region read "Search, Search: 40 · 40%", and the card was headed by the name and wrote it again beside the swatch. The name now heads both with only what the slice is worth after it, "Search, 40 · 40%", as the Flutter card writes it. A custom `tooltip.render` is still handed the slice with its `name`.
|
|
152
|
+
|
|
153
|
+
- **A `PlTimelineChart`'s own `tooltip.render` is handed the row a span sits on, and the span's own name.** Its `category` was the name of whichever row had the same place as the span has along its own row, its `index` was that place, and its item's `name` was the row, so the second span on "Design" was handed "Build", `1` and "Design", and nothing said which span it was. It is now handed the span's row as `category` and that row's place as `index`, as a bar is handed its column, and the span's own `label`, in words, as its item's `name`.
|
|
154
|
+
|
|
155
|
+
- **`Escape` clears a `PlPieChart` readout.** The pie took only the arrow keys, so a slice being read stayed on the card and in the live region until the pointer or the focus left, where every other chart clears it on `Escape`. With a slice being read, the press now clears it and stops there; with none, it goes on to whatever the chart sits in.
|
|
156
|
+
|
|
157
|
+
- **A `PlScatterChart`'s table writes a point's own `label` in place of its y.** The table wrote the bare y beside a point the card called by its label; it now writes the label, as the card and every other chart's table do.
|
|
158
|
+
|
|
159
|
+
- **A `PlTimelineChart` span with no name is read with its row once.** Its card was headed by its row and named the row again beside the swatch, and the live region read "Design, Design: Jan 1, 2026 – Jan 9, 2026". The row now heads the card alone and is read once, "Design, Jan 1, 2026 – Jan 9, 2026"; a span that names itself still has its row beside the swatch. A custom `tooltip.render` is handed no `name` for such a span.
|
|
160
|
+
|
|
161
|
+
- **A `PlScatterChart` point's x is written on its card, in its live region and in its table as the x axis writes it.** It was written as the raw figure, `12345`, where the axis under it wrote `12.3K`. It now goes through the axis' `tickFormat` when it has one and compactly when it has not; the chart's `format` stays the y's, and a date is still written as a date.
|
|
162
|
+
|
|
163
|
+
- **A `PlScatterChart`'s table writes y and z as every chart writes a value.** They were written with at most two decimals and never compacted, so a z the card and the legend never showed was `1,500,000` and a y the card wrote as `48.3K` was `48,300`. They now go through the chart's `format`, or compactly without one.
|
|
164
|
+
|
|
165
|
+
- **`Escape` on a `PlHeatmapChart` is taken only while a cell is being read.** The heatmap answered the key whatever it held and marked it handled, so a heatmap with nothing being read kept the key from a `usePlHotKeys` binding around it, and one with a readout let the same press go on and close the sheet it sat in as well. With a readout, the press now clears it and stops there; with none, it goes on to whatever the chart sits in, as on every other chart.
|
|
166
|
+
|
|
167
|
+
- **A labelled `PlSparkline` reads its numbers the way a chart writes them.** The values written out for a screen reader were the raw figures, `48300` and `1234.567`, where every other chart writes a value it has no `format` for compactly and grouped in the reader's locale. They now go through the same writer, in the provider's `locale`: "1,234.57, 48.3K".
|
|
168
|
+
|
|
169
|
+
- **`Escape` on a chart is taken only while there is a readout to clear.** The plot answered it whatever it held and marked it handled, so a chart with nothing being read kept the key from a `usePlHotKeys` binding around it, and a chart with a readout let the same press go on and close the sheet it sat in as well. With a readout, the press now clears it and stops there; with none, it goes on to whatever the chart sits in, as in the Flutter build.
|
|
170
|
+
|
|
171
|
+
- **A `PlSparkline` value outside a pinned `min` or `max` is cut at the edge of the strip.** It was drawn past the box, so a bar for 2 under a `min` of 5 hung below the strip into whatever sat under it. The marks are now held to the strip's height, so a value outside the range is not seen, and no end dot is drawn on a last value the strip cannot hold.
|
|
172
|
+
|
|
173
|
+
- **An element a chart axis's `tickFormat` returns is written as the words in it.** The type lets a formatter return any node, and the axis passed the result through `String`, so `<b>12</b>` put `[object Object]` on the axis. A tick is SVG text, which holds words and no markup, so an element is now read for its text, on either axis; a string or a number is written as before.
|
|
174
|
+
|
|
175
|
+
- **A read-only `PlCheckbox` that is `indeterminate` is filled with its family's gradient, as a live or disabled half-set box is, and a disabled one drops its edge over the gradient, as a disabled ticked box does.** A read-only half-set box was left as clear glass, with its dash in the page's ink, and a disabled one kept its neutral edge drawn round its gradient.
|
|
176
|
+
|
|
177
|
+
- **A `PlChip` with `onClick` stays a button while it is `disabled`, announced as one that cannot be used, as a disabled `PlButton` is, and what it holds is no longer mounted again as `disabled` changes.** The button was taken away while the chip was disabled, so a screen reader heard a run of text with nothing to say it was a control, and the label, the icons and the count moved out of the button and back, which loaded a `PlAvatar` in `startIcon` again and showed its initials until it had. The label is now a `<button disabled>`, out of the tab order, and a click on it reaches nothing around the chip. The Flutter build makes the same change.
|
|
178
|
+
|
|
179
|
+
- **`PlCodeBlock theme="auto"` follows the nearest element that forces a theme.** On a `.dark` page, or one the system had made dark, a block inside an element forced light with `.light` or `data-theme="light"` was still painted dark, because only a dark ancestor was named. The palette `auto` reads is now declared on every theme root, so the nearest one wins however deep the nesting goes, as it already did for the colour tokens.
|
|
180
|
+
|
|
181
|
+
- **A `PlCollapsible` leaves space between its header and its body.** Under the default header the body began at the open header's tinted edge, so its first line read as part of the title; only a `trigger` of the caller's own had the space. Both now have the space a `PlAccordion` section leaves.
|
|
182
|
+
|
|
183
|
+
- **An open `PlColorPicker` popup inside a disabled `PlFieldset` or `<fieldset>` takes nothing, as with the picker's own `disabled`.** The panel is portalled out of the fieldset, and a popup picker counted only its own `disabled`, so a controlled `open` showed a square, rails, swatches and a value field that still changed the colour while the trigger was disabled. They are now disabled with the fieldset.
|
|
184
|
+
|
|
185
|
+
- **The value field of a disabled `PlColorPicker` is disabled, so Tab passes it and a screen reader announces it as unavailable.** It was only read-only while the picker was `disabled`, so it stayed a tab stop and was read as read-only beside swatches that were disabled, while a disabled `<fieldset>` round the picker disabled it as the browser does. A `readOnly` picker's field is still read-only and takes the focus.
|
|
186
|
+
|
|
187
|
+
- **The chevron of a `PlCombobox` with a `label` is named by `openLabel`, `Open` by default.** Base UI pointed it at the field's label, which outranks an `aria-label`, so a screen reader announced the chevron by the field's name rather than by what it does, and `openLabel` had no effect there.
|
|
188
|
+
|
|
189
|
+
- **The chevron of a disabled `PlCombobox` and the steppers of a disabled `PlNumberField` are drawn at the half opacity of the field they sit in, as a `PlSelect` chevron is, and a disabled combobox shows no clear ×, as a read-only one shows none.** The chevron, the × and the steppers each faded to half a second time inside a field already at half, so they were drawn at a quarter, and the × stood beside a value it could not clear, where the Flutter combobox and the pickers of both builds show none on a disabled field. A stepper that has run into `min` or `max` in a field that is not disabled still fades to half on its own.
|
|
190
|
+
|
|
191
|
+
- **A `PlCombobox` that holds a value keeps what is typed into it as it renders again, under a parent that passes `items` inline and renders on every keystroke as much as with a value the list does not have.** The value was handed to Base UI as a row object made anew each time `items` was, and on every render for a value no option holds, and Base UI took each new object for a new value and wrote its label back over the query, so the field could not be typed into. It also dropped an error a `PlForm`'s `errors` had put on the field, with or without `multiple`, whenever the combobox rendered again. A renamed option's new label is still written into the field, but no longer over a query typed into the open list, as the Flutter combobox does.
|
|
192
|
+
|
|
193
|
+
- **A disabled `PlCombobox` keeps its chevron in the muted ink under the pointer, and so do a `PlNumberField` stepper that has run into `min` or `max` or sits in a disabled field, and the label of a disabled `PlSegmentedButton` segment or of any segment in a disabled set.** The chevron and the steppers turned to the family's accent as the pointer went over them, and a segment's label to the foreground, where a disabled control answers the pointer with nothing else, and the Flutter chevron, steppers and segments stay muted.
|
|
194
|
+
|
|
195
|
+
- **A `PlCombobox` that holds nothing says nothing when `Escape` is pressed with its list closed, or when the text of a single-value field is emptied.** Both called `onValueChange` with `null`, or with an empty array under `multiple`, so a parent heard a change that was not one, where the Flutter combobox calls nothing. A field that holds a value is still emptied by `Escape`, and says so once.
|
|
196
|
+
|
|
197
|
+
- **The clear × on a `PlCombobox` can be pressed anywhere in a 24px square around it.** It could be pressed only where it is drawn, which at the smaller sizes is under the minimum target size of WCAG 2.5.8. The × is drawn at the same size and nothing around it moves; the chevron beside it keeps its own size, and a press on the input opens the list as it always has.
|
|
198
|
+
|
|
199
|
+
- **A `PlCommandPalette` row eases its ink with its wash as the highlight reaches it and leaves it, and washes in the family's `--p-soft-hover`, as a `PlSelect` and a `PlMenu` row do.** The ink changed in one frame while the wash eased, and the wash was the paler `--p-soft`.
|
|
200
|
+
|
|
201
|
+
- **The sort mark of a `PlDataTable` heading turns over as the column changes direction.** Its transition named `transform`, but `rotate-180` sets the separate `rotate` property, so the mark flipped in one frame.
|
|
202
|
+
|
|
203
|
+
- **A `PlDataTable` wider than its sheet, or taller than its `maxHeight`, can be scrolled from the keyboard.** A table with no sortable heading and no tick column had nothing in it to take the focus, which left whatever was past the edge out of reach without a pointer. While the grid scrolls, the box it scrolls in is a tab stop, named by `caption` or, without one, by the new `label`, as a `PlTable`'s is; `label` names the `<table>` itself as well.
|
|
204
|
+
|
|
205
|
+
- **A `PlDataTable` with `manual` paging and no `getRowKey` keys a row by its place in the whole set.** The default key is a row's position in `rows`, and with the pages cut by a server `rows` is only the page on screen, so every page's first row had the key `0` and a row ticked on one page showed ticked on the row in the same place on the next. The position is now counted from the first row of the first page. `getRowKey` is still the one to set: a page the server sends again with a row added moves every key below it.
|
|
206
|
+
|
|
207
|
+
- **A picker inside a disabled native `<fieldset>` looks and reads disabled, as it does inside a disabled `PlFieldset`.** The browser disabled the trigger button, but the field was drawn at rest and said nothing of it: `PlDatePicker`, `PlDateRangePicker`, `PlDateTimePicker`, `PlTimePicker`, `PlTreeSelect` and a popup `PlColorPicker` read only the `PlFieldset` context. They now count the fieldsets round them as well, as the colour picker's panel already did.
|
|
208
|
+
|
|
209
|
+
- **Every control inside a disabled `PlFieldset` is drawn disabled, exactly as with a `disabled` of its own.** Base UI and the browser disabled the controls in one, but each drew itself from its own `disabled` only, so a text field, a select, a checkbox or a button there kept its resting look, its label's ink and its pointer light, and looked as live as a field outside. The fields, the pickers, `PlCheckbox`, `PlSwitch`, `PlRadioGroup`, `PlSlider`, `PlRating`, `PlSegmentedButton`, `PlToggle`, `PlButton`, `PlCalendar`, `PlPagination` and `PlTransfer` now read the fieldset, a fieldset further out included. A `PlSlider` and a `PlSegmentedButton` in one also stop answering, which they went on doing because neither is a native control nor inside a `Field`; a `PlFilePicker` in one refuses a dropped file; and a `PlFilePicker`, a `PlCalendar`, a `PlDateRangePicker` and a `multiple` `PlTreeSelect` in one no longer hand their values to a `PlForm`, as a disabled field does not. A `PlButton` rendered as a link stays live and is drawn that way, since the browser disables no `<a>`.
|
|
210
|
+
|
|
211
|
+
- **A floating `PlFloatingActionButton` clears the safe area of an edge-to-edge screen.** It stood a fixed `offset` off the corner, so on a phone that draws under its home indicator or navigation bar it sat on top of them. `env(safe-area-inset-*)` on the two edges it is against is now added to `offset`, with the start and the end following the page's direction. A browser reports those insets only to a page whose viewport meta tag has `viewport-fit=cover`; an app that added them to `offset` itself should take them back out.
|
|
212
|
+
|
|
213
|
+
- **A `PlHeader` with no middle puts its actions at the far end of the bar.** With a `brand` and `actions` and no `children`, at the default `align` or at `end`, the actions sat one gap after the brand, and a bar with actions and no brand started with them, where the header page and the Flutter build put them at the end. The actions now take the room an empty middle leaves. A bar with a middle, and a centred one, lay out as before.
|
|
214
|
+
|
|
215
|
+
- **A `fixed` `PlHeader` or `PlFooter` that spans only the content of a `PlPageLayout` no longer covers the sidebars.** A fixed bar spans the window whatever `headerSpan` or `footerSpan` says, but the layout reserved its height only in the column beside the sidebars, so the bar covered the top or the bottom edge of each sidebar and the end of its resize handle. The layout now measures a fixed bar whatever its span, so the sidebars start below a fixed header and end above a fixed footer, whether the page or only the content scrolls. A bar meant to sit between the sidebars is `sticky`.
|
|
216
|
+
|
|
217
|
+
- **A `PlHowToSteps` step's title and the line under it, and a `PlStepper` step's title, ease to their new colours as `active` moves, over `--plass-duration`, and change at once under reduced motion.** Each changed in one frame while the bullet beside it eased.
|
|
218
|
+
|
|
219
|
+
- **A `PlHowToSteps` fills its done and current bullets with its family's gradient, with the number in the ink that goes on it, and eases them as `active` moves, as a `PlStepper` and a `PlTimeline` do.** Its bullets had no gradient, so a done or current step was a bare number in the page's ink, with only a halo round the current one, where the Flutter bullets are filled.
|
|
220
|
+
|
|
221
|
+
- **A `PlMockup` whose `width` or `height` is a number is visible in the server HTML.** The whole device was `visibility: hidden` until the page hydrated and measured it, which left a mockup in a hero empty while the script loaded and kept it out of the LCP candidates. With a size in pixels the scale is known before anything is measured, so the device is drawn at once; a CSS length, the default `'100%'` included, still waits for the measurement.
|
|
222
|
+
|
|
223
|
+
- **A vertical `PlNavigationMenu` opens its panels beside the rail, at the end of the line, level with their item, and its chevrons point there.** `orientation="vertical"` was documented as a nav rail whose panels open beside it, but every panel hung under its item, over the items below it, and each item's chevron pointed down and turned up when its panel opened. A panel now opens at the rail's inline end, which is its left under RTL with `PlassProvider`, with its top level with its item's, as a `PlMenuSubmenu` opens beside its row. Every item spans the rail, so each panel opens against the rail's edge, and the sheet moves down the rail by the items' spacing from one item to the next. An item's chevron points at the inline end and stays there while its panel is open, as a submenu's does. The rail's labels now sit in its middle, as they do in the Flutter build and in a vertical `PlMenubar`.
|
|
224
|
+
|
|
225
|
+
- **A `PlNavigationMenu` sheet eases from one panel to the next, and follows the item it hangs from.** Moving between items, the sheet took the next panel's size in one frame and jumped to its place under the next item, and closing collapsed it to its edges before it could fade. It now eases to the size of the panel coming in and to its place under the new item, whether a trigger or the page changed the panel, and lands on that size however slow the frames are; a panel keeps its own lines while the sheet is between two sizes, and the sheet keeps the size of what it held while it fades out. Opening, and every change under `prefers-reduced-motion`, arrives at once. Once it has arrived, including after a move to a panel of the same size in the same place, it follows the row without easing, so it does not trail a row that scrolls with the page.
|
|
226
|
+
|
|
227
|
+
- **Every `PlNavigationMenu` panel's links are in the server HTML.** A panel was rendered only once it opened, so a crawler that never hovers found none of the links the component exists to hold. Every panel is now kept mounted, and a closed one is hidden: not drawn, not announced and not a focus stop.
|
|
228
|
+
|
|
229
|
+
- **A `PlNavigationMenuLink`'s `startIcon` follows the link's `size`: 1.2em of its title, in a box one of the title's lines high, as in the Flutter build.** It was measured against the page's font, so on a 16px page it was 19.2px in a 24px box whatever the link's `size`, larger than the title at `sm` and `md` and lower than its first line.
|
|
230
|
+
|
|
231
|
+
- **A `PlNumberField` eases a stepper's tint in as it is pressed and its shell's fill and edge in as it takes the focus, and a `PlOtpField` slot eases its own in as it takes the focus, each over the same `--plass-duration` it eases them out over.** A press or a focus changed them in one frame and only the release or the blur eased them, where every other control eases both ways, a `PlTextField` among them, and so does the Flutter build. Under reduced motion they still change at once.
|
|
232
|
+
|
|
233
|
+
- **A `PlNumberField` stepper that has run into `min` or `max` fades to half, as every other disabled control does.** It went to 40% opacity, so on a form the one unavailable stepper was fainter than a disabled button or field beside it, and fainter than the same stepper in the Flutter build. It now fades to 50%.
|
|
234
|
+
|
|
235
|
+
- **A `PlPageLayout` inside another no longer adds a second `<main>`.** The inner layout rendered its own `<main>`, skip link and `id="main"`, so the page had two of each. It now renders its content in a `<div>` and leaves the skip link and the `id` to the outer layout.
|
|
236
|
+
|
|
237
|
+
- **A `PlPill` that starts `expanded` is open on its first frame.** It rendered its panel at a height of 0 and measured it afterwards, so it animated open as it arrived. An open panel is now at its natural height until it has been measured, in the server's HTML as well, and opening and closing afterwards animate as before.
|
|
238
|
+
|
|
239
|
+
- **A progress `value` of `Infinity` draws as full on `PlProgressLinear`, `PlProgressCircular` and `PlProgressBox`.** The shape and the text clamped it to the top of the range, but Base UI read it as indeterminate, so the bar drew neither a fill nor the sweep beside a "100%" and `aria-valuenow` was missing. Base UI is now handed the value clamped into `min`…`max`, so the fill, the value attributes and the text agree. `NaN` is still indeterminate.
|
|
240
|
+
|
|
241
|
+
- **Every segment of a read-only `PlSegmentedButton` keeps its pointer light out, and its label stays in the muted ink under the pointer.** Each segment still carried the interaction light and darkened its label as the pointer went over it, as though it could be chosen, where the light goes out on a read-only control and the Flutter segments of a read-only set show neither.
|
|
242
|
+
|
|
243
|
+
- **The segments of a disabled `PlSegmentedButton` and the chips of a disabled `multiple` `PlCombobox` are drawn at the half opacity of the set or the field they sit in, and a disabled set's segments put their pointer light out.** Each faded to half a second time inside a set or a field already at half, so they were drawn at a quarter and hard to read, and the pointer still lit the segment under it in a disabled set, where the Flutter build puts the light out. A chip in a disabled field keeps the look of a disabled chip, and a segment disabled on its own in a set that is not disabled, like a `PlChip` disabled anywhere else, still fades to half on its own.
|
|
244
|
+
|
|
245
|
+
- **A press on a read-only `PlSelect` does not open it, even when the lock lifts before the press is answered.** Base UI answers a pointer press on the next frame, and `PlSelect` checked `readOnly` at that frame rather than at the press, so a lock lifted in between, such as by a form that unlocks the field on the same press, let the press open the list anyway. The press is now judged by whether the field was locked when it was made.
|
|
246
|
+
|
|
247
|
+
- **A `PlSelect` whose labels are elements no longer draws every one of them to hold its width.** A trigger that is not `fullWidth` laid out every option's label to find the widest, so a list of 250 countries with a flag in each asked for 250 flags before it was opened. Such a label, and a placeholder, is now measured by its text alone, so no picture in it is loaded for the measurement; the trigger can widen by the picture once that option is chosen.
|
|
248
|
+
|
|
249
|
+
- **The resize handle of a `PlSidebar` is drawn over a header or a footer that spans only the content of a `PlPageLayout`, and takes a press there.** The handle straddles the sidebar's edge, but a sidebar that is sticky or glass is a stacking context of its own, so the handle's `z-1` could not rise above a sticky bar's `z-20`, or above a glass bar painted after a start sidebar. The outer half of the handle was hidden under the bar beside it, and a press there went to the bar. While a bar spans the content beside a sidebar, the layout now lifts its sidebars over the column beside them, as the Flutter layout paints them. It does this inside a layer of its own, so a full-width bar, the sticky header of a page the layout scrolls under, and a portal all stay above the sidebars. In that layer, a `fixed` element in the page, such as a floating `PlFloatingActionButton`, goes under a full-width sticky bar where the two meet. A nested layout's content-span bar also no longer draws over the sticky header of the page it scrolls under.
|
|
250
|
+
|
|
251
|
+
- **A `PlTable` wider than its sheet, or taller than its `maxHeight`, can be scrolled from the keyboard.** A table whose cells take no focus left whatever was past the edge out of reach without a pointer. While the grid scrolls, the box it scrolls in is a tab stop, and with a `caption` it is a group named by it. The measurement is a client module of its own, so `PlTable` can still be rendered by a server component.
|
|
252
|
+
|
|
253
|
+
- **A `PlTabs` tab brought into view stops clear of the edge fade.** The chosen tab as the bar was laid out, and the next one along as the arrow keys moved, ended flush against the edge, which is where the 24px fade is strongest. Both now stop the fade's length short of it.
|
|
254
|
+
|
|
255
|
+
- **A mouse press on the padding or on a drawn adornment of a focused `PlTextField` or `PlNumberField` keeps the focus in the field, in both builds.** The two builds and the two fields each did something different: the React text field kept the focus for a press on its padding and lost it for one on an adornment, the React number field lost it for both, and the Flutter fields lost it and took it back. A press anywhere in the field now keeps the focus there, and a button or a link in an adornment still takes its own press.
|
|
256
|
+
|
|
257
|
+
- **A `PlToast` whose colour or variant `update` or `promise` changes, and a `PlAppLogo` plate whose `color` or `variant` changes, ease to their new fill, edge, shadow and ink over `--plass-duration`, and change at once under reduced motion, as a `PlAlert` does.** The toast eased only its opacity and the plate nothing, so both took their new colours in one frame. A `solid` toast's action now takes the toast's own ink, so it eases with the words round it.
|
|
258
|
+
|
|
259
|
+
- **A toast swiped away fades from where the finger left it.** Base UI drops a toast's drag offset the moment the finger lifts, so a toast flicked off jumped back to its place before it faded out. It now holds the offset for its exit. A toast closed any other way fades where it is, as before.
|
|
260
|
+
|
|
261
|
+
- **A `solid` `PlToggle`, a `PlCheckbox`, a `PlRadioGroup` option, a `PlSwitch`, the chosen day or time in a picker, a step's bullet in a `PlStepper` or a `PlTimeline`, and the current page of a `PlPagination` fade their gradient in and out as their state changes, and put it on at once under reduced motion, and a `solid` `PlSegmentedButton` fades its tile in where the first choice of an empty set lands.** The gradient was the control's own `background-image`, which no browser eases to or from nothing, so it arrived in one frame and left in one while the colours round it eased. It is now a layer of its own that fades over `--plass-duration`, as the Flutter controls fade theirs, and looks the same at rest. A `solid` toggle and every `PlPagination` page draw it as an `aria-hidden` `<span>` inside the button, since both of their pseudo-elements are the pointer light, so each page's DOM gains that `<span>`.
|
|
262
|
+
|
|
263
|
+
- **A `PlTooltip` switched off with `disabled` while it is open closes and reports the close through `onOpenChange`, and a controlled `open` shows nothing while it is `disabled`, as the Flutter build does.** `disabled` only stopped the trigger from opening the tooltip. A tooltip opened by hover stayed on the page with the trigger's `aria-describedby` still pointing at it, and `onOpenChange` never heard it close. A controlled `open` also showed a disabled tooltip; it is now answered with `false`. The Flutter build makes the same change to what it reports.
|
|
264
|
+
|
|
265
|
+
- **One tick in a `PlTransfer` renders only the row it changed.** Every row of both lists rendered again for each tick, each one a `PlCheckbox`, so a list of thousands stalled on every press. A row now renders again only when its own label, tick or availability changes. The first render of a long list still draws every row.
|
|
266
|
+
|
|
267
|
+
- **A `PlTransfer` move announcement names a list whose heading is an element by the words the heading draws.** It used the label pack's `transferAvailable` or `transferSelected`, a name the page did not show, while the list's select-all tick read the heading itself. Both now read it the same way.
|
|
268
|
+
|
|
269
|
+
- **A `PlTransfer` select-all tick is named in the order each language puts it.** "Select all" was put in front of the list's heading in every language, so Korean read "전체 선택 사용 가능". The name now comes from the label pack's new `transferSelectAll`, "Select all in Available" in English, which puts the list's name where its own grammar puts it. A `selectAllLabel` given to the component still goes in front of the heading, as before.
|
|
270
|
+
|
|
271
|
+
- **A `PlWindowPane`'s draggable title bar shows the grab hand, closing while the bar is held, and no hand over the caption buttons and `actions`, where nothing drags, in both builds.** The Flutter bar showed the move cursor, and both builds showed their drag cursor in the space round the caption buttons and the actions. The Flutter bar now shows `grab` and `grabbing`, as the React bar's `cursor-grab` and `active:cursor-grabbing`, and both show the default cursor over the buttons' column and the actions.
|
|
272
|
+
|
|
273
|
+
- **A `PlWindowPane` close button pressed on a touch screen draws its × white on the red, as in the Flutter build.** A press turned the button red, but only the pointer's hover turned its × white, and a finger brings no hover with it, so a touch press drew the title bar's own ink on the red.
|
|
274
|
+
|
|
275
|
+
- **A `PlWindowPane` resized as short as it goes stops at its title bar and the frame round it, and `minHeight` does not take it any shorter.** The floor was the bar alone, so a window shrunk by an edge, the resize corner or the arrow keys, or given a `minHeight` below its bar, lost the bottom of its bar to the frame: 2px on most systems, and 4px on `windows8`.
|
|
276
|
+
|
|
277
|
+
- **A rolled-up `PlWindowPane` is as tall as its title bar and the frame round it, however it was rolled up and whatever `size` or `os` it has been given since.** A window that started rolled up through `defaultMinimized` or a controlled `minimized` was only as tall as its bar, so the frame cut the bottom off the bar: 2px on most systems, and 4px on `windows8`. A window rolled up by its button kept the height it had at the press, so one rolled up at `md` and then set to `xl`, or given an `os` with a taller bar, had its bar cut by the difference: 11px on a `macos` window.
|
|
278
|
+
|
|
279
|
+
- **A double click on a `PlWindowPane`'s `actions` belongs to the action and leaves the window's size alone.** The `actions` kept a press from dragging the bar, but not a double click, so an action clicked twice also maximized or restored the window and called `onMaximizedChange`. The caption buttons already kept their double clicks, and a double tap on `actions` already stays theirs in the Flutter build.
|
|
280
|
+
|
|
281
|
+
- **A `PlWindowPane` that is both `maximized` and `minimized` is rolled up to its title bar across the whole of what holds it.** The maximized window stayed `100%` tall whatever `minimized` said, so the minimize button left it filling its container with an empty, inert body and seemed to do nothing. It now keeps the full width and is only as tall as its bar, easing there as any roll-up does, as the Flutter build does. A window rolled up while maximized and restored before it came back down also comes down to its own height rather than growing to the height of the box it filled.
|
|
282
|
+
|
|
7
283
|
## 1.6.0 (2026-09-19)
|
|
8
284
|
|
|
9
285
|
### Breaking changes
|
package/README.md
CHANGED
|
@@ -120,7 +120,9 @@ One thing does **not** change with the theme, and it is deliberate: the colour o
|
|
|
120
120
|
|
|
121
121
|
Every component is exported under a `Pl` prefix. `Button`, `Card` and `Table` are the most-taken identifiers in the ecosystem, and a consumer should not have to alias ours on import.
|
|
122
122
|
|
|
123
|
-
130 of them
|
|
123
|
+
130 of them, one for each folder in `dist/components`. The [Flutter package](https://pub.dev/packages/plass_ui) holds 127 of these under the same names, and the other three, `PlFlex`, `PlPortal` and `PlVisuallyHidden`, answer problems only the DOM has. Every component has a page of its own with live previews and the full props table.
|
|
124
|
+
|
|
125
|
+
The list also names two exports that are not counted, because each shares a folder and a page with another component: `PlToggleGroup`, beside `PlToggle`, and `PlContextMenu`, a second trigger onto `PlMenu`'s surface. Flutter has `PlToggleGroup` but not `PlContextMenu`, for a reason of its own: no right-click gesture means the same thing on every platform Flutter runs on, so a Flutter app opens a `PlMenu` from `onLongPress` itself.
|
|
124
126
|
|
|
125
127
|
### Charts
|
|
126
128
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { PlassElevation, PlassStyleProps } from '../../types.js';
|
|
3
|
+
/** The six levels an HTML heading has. */
|
|
4
|
+
export type PlAccordionHeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
|
3
5
|
export interface PlAccordionProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'defaultValue' | 'onChange'> {
|
|
4
6
|
/**
|
|
5
7
|
* Drop shadow depth. `0` is the default — an accordion is part of the page it
|
|
@@ -32,6 +34,17 @@ export interface PlAccordionProps extends PlassStyleProps, Omit<React.ComponentP
|
|
|
32
34
|
dividers?: boolean;
|
|
33
35
|
/** Unavailable. Every section stops answering. */
|
|
34
36
|
disabled?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* The level of the heading every section's header is, `1` to `6`.
|
|
39
|
+
*
|
|
40
|
+
* A header is a heading, so a screen reader's list of headings can take the
|
|
41
|
+
* reader from one question to the next — and a heading has to sit one level
|
|
42
|
+
* under the one above it, or the outline skips a step. `3` fits an accordion
|
|
43
|
+
* under a section's `<h2>`; an FAQ directly under the page's `<h1>` wants `2`.
|
|
44
|
+
* Only the element changes: the type scale is the accordion's either way.
|
|
45
|
+
* @default 3
|
|
46
|
+
*/
|
|
47
|
+
headingLevel?: PlAccordionHeadingLevel;
|
|
35
48
|
/**
|
|
36
49
|
* Keeps closed panels in the DOM so the browser's own page search can find
|
|
37
50
|
* and open them. Overrides `keepMounted`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as l from"react";import{useDefaults as s}from"../../internal/defaults.js";import{Accordion as a}from"@base-ui/react/accordion";import{ChevronIcon as n}from"../../internal/icons.js";import{focusRingClasses as i,focusRingInsetClasses as r,gapClasses as
|
|
1
|
+
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as l from"react";import{useDefaults as s}from"../../internal/defaults.js";import{Accordion as a}from"@base-ui/react/accordion";import{ChevronIcon as n}from"../../internal/icons.js";import{focusRingClasses as i,focusRingInsetClasses as r,gapClasses as d,hasContent as o,iconClasses as c,metaTextClasses as m,radiusClasses as p,sheetBodyClasses as u,sheetHeaderGapClasses as f,sheetPaddingXClasses as h,sheetPaddingYClasses as x,sheetRestClasses as v,sheetTitleClasses as b,surfaceSlots as g,transitionClasses as N}from"../../internal/styles.js";const j=/* @__PURE__ */l.createContext({size:"md",density:"default",dividers:!0,headingLevel:3}),y={xs:p.xs,sm:p.xs,md:p.sm,lg:p.sm,xl:p.md},w={default:{xs:"pt-1.5",sm:"pt-2",md:"pt-3",lg:"pt-3.5",xl:"pt-4"},compact:{xs:"pt-1",sm:"pt-1.5",md:"pt-2",lg:"pt-2.5",xl:"pt-3"}},$={default:{xs:"pb-2.5",sm:"pb-3",md:"pb-5",lg:"pb-6",xl:"pb-7"},compact:{xs:"pb-2",sm:"pb-2.5",md:"pb-3.5",lg:"pb-4",xl:"pb-5"}};export const PlAccordion=/* @__PURE__ */l.forwardRef(function PlAccordion({variant:t="glass",size:n,color:i,density:r,elevation:d=0,multiple:o=!1,value:c,defaultValue:m,onValueChange:u,dividers:f=!0,disabled:h=!1,headingLevel:x=3,hiddenUntilFound:b=!1,keepMounted:y=!1,className:w,style:$,children:P,...k},z){const A=s(),I=n??A.size??"md",C=i??A.color??"primary",L=r??A.density??"default",V=Number.isInteger(x)&&x>=1&&x<=6?x:3,_=l.useMemo(()=>({size:I,density:L,dividers:f,headingLevel:V}),[I,L,f,V]),B=["flex flex-col",p[I],v[t],N,f?"overflow-hidden [&>div+div]:border-t [&>div+div]:[border-color:var(--plass-divider)]":"p-1",w??""].filter(Boolean).join(" ");return e(j.Provider,{value:_,children:e(a.Root,{ref:z,multiple:o,value:c,defaultValue:m,onValueChange:e=>u?.(e),disabled:h,hiddenUntilFound:b,keepMounted:y,className:B,style:{...g(C,d),...$},...k,children:P})})});export const PlAccordionItem=/* @__PURE__ */l.forwardRef(function PlAccordionItem({value:s,title:p,subtitle:v,startIcon:g,action:P,truncate:k=!1,disabled:z=!1,className:A,children:I,...C},L){const{size:V,density:_,dividers:B,headingLevel:M}=l.useContext(j),R=`h${M}`,F=h[_][V],U=x[_][V],H=k?"truncate":"";return t(a.Item,{ref:L,value:s,disabled:z,className:["flex flex-col",A??""].filter(Boolean).join(" "),...C,children:[t(a.Header,{render:e(R,{}),className:"m-0 flex w-full items-center [font:inherit]",children:[t(a.Trigger,{className:["flex min-w-0 flex-1 cursor-pointer items-center text-start",F,U,d[V],N,c,B?r:`${i} ${y[V]}`,"hover:bg-(--p-soft)","data-[panel-open]:bg-(--p-soft) data-[panel-open]:text-(--p-accent)","disabled:cursor-not-allowed disabled:bg-transparent disabled:opacity-50"].filter(Boolean).join(" "),children:[o(g)?e("span",{className:"flex h-[1lh] shrink-0 items-center text-(--plass-muted-fg)",children:g}):null,t("span",{className:`flex min-w-0 flex-1 flex-col ${f[V]}`,children:[o(p)?e("span",{className:`plass-title font-semibold ${H} ${b[V]}`.trim(),children:p}):null,o(v)?e("span",{className:`text-(--plass-muted-fg) ${H} ${m[V]}`.trim(),children:v}):null]}),e("span",{className:["flex h-[1lh] shrink-0 items-center text-(--plass-muted-fg)","[transition:rotate_var(--plass-duration)_var(--plass-ease)]","motion-reduce:[transition-duration:0ms]","data-[panel-open]:rotate-180"].join(" "),children:e(n,{})})]}),o(P)?e("span",{className:`flex shrink-0 items-center ${F}`,children:P}):null]}),e(a.Panel,{className:["h-(--accordion-panel-height) overflow-hidden","[transition:height_var(--plass-duration-slow)_var(--plass-ease)]","motion-reduce:[transition-duration:0ms]","data-[starting-style]:h-0 data-[ending-style]:h-0"].join(" "),children:e("div",{className:["text-(--plass-muted-fg)",u[V],F,w[_][V],$[_][V]].join(" "),children:I})})]})});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { PlAccordion, PlAccordionItem } from './PlAccordion.js';
|
|
2
|
-
export type { PlAccordionProps, PlAccordionItemProps } from './PlAccordion.js';
|
|
2
|
+
export type { PlAccordionHeadingLevel, PlAccordionProps, PlAccordionItemProps } from './PlAccordion.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as s,jsxs as e}from"react/jsx-runtime";import*as l from"react";import{useDefaults as t}from"../../internal/defaults.js";import{useLabels as a}from"../../internal/labels.js";import{CloseIcon as i,severityIcon as r}from"../../internal/icons.js";import{controlSlots as o,focusRingClasses as n,forcedFieldEdgeClasses as c,glassClasses as d,hasContent as m,iconClasses as f,radiusClasses as p,sheetBodyClasses as u,sheetHeaderGapClasses as h,sheetPaddingXClasses as v,sheetPaddingYClasses as x,sheetSectionGapClasses as g,sheetTitleClasses as b,transitionClasses as
|
|
1
|
+
"use client";import{jsx as s,jsxs as e}from"react/jsx-runtime";import*as l from"react";import{useDefaults as t}from"../../internal/defaults.js";import{useLabels as a}from"../../internal/labels.js";import{CloseIcon as i,severityIcon as r}from"../../internal/icons.js";import{controlSlots as o,focusRingClasses as n,forcedFieldEdgeClasses as c,glassClasses as d,hasContent as m,iconClasses as f,radiusClasses as p,sheetBodyClasses as u,sheetHeaderGapClasses as h,sheetPaddingXClasses as v,sheetPaddingYClasses as x,sheetSectionGapClasses as g,sheetTitleClasses as b,targetClasses as y,transitionClasses as j}from"../../internal/styles.js";const N={solid:/* @__PURE__ */["text-(--p-on-solid) [background-image:var(--p-fill)]","[box-shadow:var(--p-elev),var(--p-lift)]",c].join(" "),glass:/* @__PURE__ */[d,"border text-(--plass-fg) bg-(--plass-glass)","[border-color:var(--p-line)]","[box-shadow:var(--p-elev),var(--plass-gloss-glass)]"].join(" "),ghost:"text-(--plass-fg) bg-(--p-soft)"},w={solid:"",glass:"text-(--p-accent)",ghost:"text-(--p-accent)"},k={solid:"",glass:"text-(--plass-muted-fg)",ghost:"text-(--plass-muted-fg)"},$={primary:"status",secondary:"status",info:"status",success:"status",warning:"alert",danger:"alert"};export const PlAlert=/* @__PURE__ */l.forwardRef(function PlAlert({variant:l="glass",size:c,color:d,density:z,elevation:A=0,title:C,icon:P,action:_,onClose:B,closeLabel:L,className:R,style:q,children:D,...E},F){const G=t(),H=a(),I=L??H.dismiss,J=c??G.size??"md",K=d??G.color??"info",M=z??G.density??"default",O=void 0===P?r(K):P,Q=w[l],S=m(C);return e("div",{ref:F,role:$[K],className:["flex w-full items-start",v[M][J],x[M][J],p[J],g[J],u[J],j,N[l],f,R??""].filter(Boolean).join(" "),style:{...o(K,A,l),...q},...E,children:[m(O)?s("span",{className:`flex h-[1lh] shrink-0 items-center ${Q}`,children:O}):null,e("div",{className:`flex min-w-0 flex-1 flex-col ${h[J]}`,children:[S?s("div",{className:`plass-title font-semibold ${b[J]} ${Q}`,children:C}):null,m(D)?s("div",{className:S?k[l]:void 0,children:D}):null]}),m(_)?s("div",{className:"flex h-[1lh] shrink-0 items-center",children:_}):null,B?s("span",{className:"flex h-[1lh] shrink-0 items-center",children:s("button",{type:"button","aria-label":I,onClick:B,className:[y,"inline-flex size-[1.15em] cursor-pointer items-center justify-center rounded-full","opacity-70 [transition:opacity_var(--plass-duration)_var(--plass-ease)]","motion-reduce:[transition-duration:0ms]","hover:opacity-100 focus-visible:opacity-100",n].join(" "),children:s(i,{})})}):null]})});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import type { PlassAnimateProps } from '../../types.js';
|
|
2
|
+
import type { PlassAnimateProps, PlassAnimateRepeat } from '../../types.js';
|
|
3
3
|
export interface PlAnimateHeadlineProps extends Omit<PlassAnimateProps, 'alternate'>, React.ComponentPropsWithoutRef<'div'> {
|
|
4
4
|
/**
|
|
5
5
|
* How long each line is held before the next one comes up, in milliseconds.
|
|
@@ -23,6 +23,15 @@ export interface PlAnimateHeadlineProps extends Omit<PlassAnimateProps, 'alterna
|
|
|
23
23
|
* @default true
|
|
24
24
|
*/
|
|
25
25
|
loop?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* How the headline stops, and nothing else. It counts neither lines nor
|
|
28
|
+
* cycles: `loop` decides whether the lines start again after the last one.
|
|
29
|
+
* With `trigger="hover"`, `'infinite'` stops the reel where it is when the
|
|
30
|
+
* pointer and the focus leave, and a count leaves it turning after they have
|
|
31
|
+
* gone. Under any other `trigger` it changes nothing.
|
|
32
|
+
* @default 'infinite'
|
|
33
|
+
*/
|
|
34
|
+
repeat?: PlassAnimateRepeat;
|
|
26
35
|
/**
|
|
27
36
|
* How far a line travels as it comes up or leaves — a CSS length, or a number
|
|
28
37
|
* in pixels. `'100%'` is one line's own height.
|
|
@@ -41,6 +41,13 @@ export interface PlAnimateMarqueeProps extends PlassAnimateProps, React.Componen
|
|
|
41
41
|
* @default true
|
|
42
42
|
*/
|
|
43
43
|
pauseOnHover?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* What the strip is called — "Partners", "Customers". It names the box as a
|
|
46
|
+
* group, and under `prefers-reduced-motion` that box is the tab stop a
|
|
47
|
+
* keyboard reader scrolls it with, which is otherwise announced with no name
|
|
48
|
+
* of its own.
|
|
49
|
+
*/
|
|
50
|
+
label?: string;
|
|
44
51
|
/** The things that scroll past. */
|
|
45
52
|
children?: React.ReactNode;
|
|
46
53
|
}
|
|
@@ -66,7 +73,7 @@ export interface PlAnimateMarqueeProps extends PlassAnimateProps, React.Componen
|
|
|
66
73
|
* the box would be out of sight for good. So the stylesheet draws only the
|
|
67
74
|
* first copy and lets the box scroll along it instead of clipping it, and the
|
|
68
75
|
* box is a tab stop while there is anything to scroll, for a reader with no
|
|
69
|
-
* pointer to scroll it with.
|
|
76
|
+
* pointer to scroll it with. `label` is that stop's name.
|
|
70
77
|
*
|
|
71
78
|
* Only the first copy is read out or reached with Tab. The rest carry
|
|
72
79
|
* `aria-hidden`, or a screen reader would announce everything on the strip as
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e}from"react/jsx-runtime";import*as t from"react";import{mergeProps as r}from"@base-ui/react/merge-props";import{isInfinite as a,lengthValue as
|
|
1
|
+
"use client";import{jsx as e}from"react/jsx-runtime";import*as t from"react";import{mergeProps as r}from"@base-ui/react/merge-props";import{isInfinite as a,lengthValue as i,repeatValue as n,directionValue as s,useAnimationRun as o}from"../../internal/animate.js";import{inertProps as l}from"../../internal/inert.js";import{usePrefersReducedMotion as m}from"../../internal/media.js";import{cx as p}from"../../internal/styles.js";export const PlAnimateMarquee=/* @__PURE__ */t.forwardRef(function PlAnimateMarquee({duration:u,delay:c=0,easing:d,repeat:f="infinite",alternate:h,paused:v,trigger:g="mount",play:y,once:b=!0,threshold:j=.2,orientation:q="horizontal",reverse:x=!1,speed:R=60,gap:H="2rem",copies:M=2,pauseOnHover:w=!0,label:z,className:A,style:N,children:O,...S},W){const G=void 0===u&&R<=0,P=o({trigger:g,play:y,once:b,threshold:j,paused:v||G,infinite:a(f)}),$=t.useRef(null),k=t.useRef(null),[C,E]=t.useState(0),[F,I]=t.useState(!1),B="vertical"===q,D=m();t.useEffect(()=>{const e=$.current,t=k.current;if(!e||!t)return;const measure=()=>{const r=getComputedStyle(e),a=parseFloat(B?r.rowGap:r.columnGap)||0,i=B?t.offsetHeight:t.offsetWidth;E(i+a),I(B?e.scrollHeight>e.clientHeight:e.scrollWidth>e.clientWidth)};if(measure(),"undefined"==typeof ResizeObserver)return;const r=new ResizeObserver(measure);return r.observe(t),r.observe(e),()=>r.disconnect()},[B,D]);const J=u??(C>0&&!G?C/R*1e3:12e3);return e("div",{ref:e=>{$.current=e,P.ref(e),"function"==typeof W?W(e):W&&(W.current=e)},className:p("plass-marquee",B&&"plass-marquee-vertical",A),style:{"--p-anim-gap":i(H),...d?{"--p-anim-ease":d}:{},"--p-anim-duration":`${Math.round(J)}ms`,"--p-anim-delay":`${c}ms`,"--p-anim-repeat":n(f),"--p-anim-direction":s(x?"out":"in",h),"--p-anim-state":P.state,...N},"data-plass-animation":"marquee","data-state":P.state,"data-pause-on-hover":w?"":void 0,tabIndex:D&&F?0:void 0,role:z?"group":void 0,"aria-label":z,...r(S,P.handlers),children:Array.from({length:Math.max(1,M)},(t,r)=>(t=>e("div",{ref:0===t?k:void 0,className:"plass-marquee-track","aria-hidden":0===t?void 0:"true",...l(0!==t),children:O},t))(r))})});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as s,Fragment as l}from"react/jsx-runtime";import*as
|
|
1
|
+
"use client";import{jsx as e,jsxs as s,Fragment as l}from"react/jsx-runtime";import*as r from"react";import{useRender as t}from"@base-ui/react/use-render";import{useDefaults as a}from"../../internal/defaults.js";import{controlSlots as n,cx as i,focusRingClasses as o,hasContent as c,markRestClasses as m,metaTextClasses as d,radiusClasses as p,transitionClasses as x}from"../../internal/styles.js";const f={xs:"h-5",sm:"h-6",md:"h-8",lg:"h-10",xl:"h-12"},u={xs:"size-5",sm:"size-6",md:"size-8",lg:"size-10",xl:"size-12"},g={xs:"text-sm",sm:"text-base",md:"text-lg",lg:"text-xl",xl:"text-2xl"},h={xs:"gap-1.5",sm:"gap-2",md:"gap-2.5",lg:"gap-3",xl:"gap-3.5"};export const PlAppLogo=/* @__PURE__ */r.forwardRef(function PlAppLogo({children:r,src:z,alt:j="",name:N,description:b,shape:v="bare",variant:w="solid",size:y,color:A,render:L,className:P,style:$,..._},k){const F=a(),R=y??F.size??"md",q=A??F.color??"primary",B="bare"!==v,C=c(N)||c(b),D=z?e("img",{src:z,alt:j,className:B?"size-[70%] object-contain":"h-full w-auto"}):r;return t({render:L,ref:k,props:{className:i("inline-flex items-center text-(--plass-fg) [&_svg]:h-full [&_svg]:w-auto",h[R],o,P),style:{...n(q,1,w),...$},children:s(l,{children:[e("span",{"aria-hidden":!!c(N)||void 0,className:i("flex shrink-0 items-center justify-center overflow-hidden",B?u[R]:f[R],B?`${x} ${m[w]}`:"","circle"===v?"rounded-full":B?p[R]:""),children:D}),C?s("span",{className:"flex min-w-0 flex-col",children:[c(N)?e("span",{className:i("truncate font-semibold",g[R]),children:N}):null,c(b)?e("span",{className:i("truncate text-(--plass-muted-fg)",d[R]),children:b}):null]}):null]}),..._}})});
|