Minor Changes
-
0154b3a: feat(DST-1751): add a select-all to ListView and SelectList
<Table>used to be the only collection that could offer a select-all, because it was the only one with a header to put a checkbox in.allowSelectAllnow renders one for the two multi-select lists, aligned with the row indicators by the component (the padding is a custom property on the wrapper around the list, so a consumer composing a checkbox above it cannot line one up).<ListView aria-label="Uploads" selectionMode="multiple" allowSelectAll items={uploads} > {upload => <ListView.Item textValue={upload.name}>…</ListView.Item>} </ListView>
The checkbox is mixed while the selection is partial, and becomes checked once every selectable row has been picked. It labels itself "Select all" in the current locale, and a count beside it reports how many rows are selected. The prop only takes effect when
selectionMode="multiple", since there is nothing for a select-all to do in the other modes. The header sits outside the grid element rather than claiming column-header semantics a single-column collection does not have, so the checkbox carries its own visible label. A disabledSelectListoption that was preselected keeps its selection in either direction, since the user cannot toggle it by hand either, and clearing from the header honoursdisallowEmptySelectionthe way React Aria's ownclearSelectiondoes.ListViewreports'all'from its select-all, the same value Cmd/Ctrl+A already reported.SelectListreports concrete keys instead, because a field has to submit a value: it now resolves the'all'sentinel to the keys it covers, which also fixes Cmd/Ctrl+A in a multi-selectSelectListsubmitting nothing at all. A controlledselectedKeys="all"resolves the same way, so it submits and validates like any other selection instead of as nothing.Two smaller fixes come with it. A
Setpassed toselectedKeysis no longer copied on every render, which kept React Aria resetting the range anchor and broke Shift+click on a controlled list. AndListViewnow renders its list inside a wrapper element that owns the row-padding custom property, so the header and the rows read the same value.On both components the select-all reads as the list's first row: it takes the same padding as a row and is separated by a divider of the same weight as the ones between rows. A
SelectListkeeps it inside the frame. In theborderedvariant there is no frame to sit in. The select-all stays a control above the option cards, closer to the first card than to the field's label, so it still groups with the list rather than with the label.The
Themetype gainsheaderandcountslots on both components, pluscontaineronListView. All three are optional, so a custom theme written before this release still compiles and renders:useClassNamesreturnsundefinedfor a slot a theme does not supply, and the components render without it. ASelectList'sp/px/pyprops keep writing their custom properties onto the list as well as the new wrapper, so a theme that declares the same variables on its ownlistslot does not win over the prop.