Skip to content

v0.202.0

Choose a tag to compare

@tenphi tenphi released this 28 Oct 14:10
· 12 commits to main since this release
955537f

Minor Changes

  • #1582 2e9ae4b86 Thanks @tenphi! - Divider applies its style props (margin, width and the rest of its documented set), which it used to drop silently, and takes a new orientation="vertical" prop that renders a vertical separator stretching to the height of its row. It no longer claims the divider grid area: inside a grid it now takes the next cell, where it used to land in an extra implicit column with zero width. A divider with text is now a separator named by that text for screen readers, and every divider carries data-qa="Divider" unless you pass qa. A component built with tasty(Divider, …) now renders a real <hr> separator too, where it used to render a div with no role, so screen readers announce it; hide one that is only decoration with aria-hidden.

  • #1586 045328aee Thanks @tenphi! - Breaking: an input's style props now place and size its outer element: the field wrapper when its chrome renders, the input itself when it is bare. Adding a label no longer moves width, height, flex*, gridArea, margin, inset, position or zIndex from the field to the control inside it. When style props size a wrapped field, the input stretches to fill it, unless it has a fixed or capped size of its own (Checkbox and Switch keep their content width, single-line inputs and a vertical Slider their height). styles still styles the input and fieldStyles the wrapper; a style prop wins over fieldStyles for the same key, and only style props make the input fill the field.

    This applies to every field-level input: the TextInput family, SearchInput, ColorInput, ComboBox, SearchComboBox, Select, Picker, FilterPicker, ListBox, FilterListBox, TagInput, Checkbox, CheckboxGroup, RadioGroup, Switch, the sliders, the date and time inputs and pickers, FileInput, ColorPicker and ColorSwatchGroup. They now take exactly the position and dimension style props (FieldLayoutStyleProps, exported). Every other style prop is removed from them: the base, block, color and flow groups, such as fill, color, border, radius, shadow, outline, padding, preset, font, display, hide, opacity, transition, textAlign, overflow, flow, gap, place, placeItems, placeContent, align, alignItems, alignContent, justify, justifyItems and justifyContent (placeSelf, alignSelf and justifySelf stay). Pass those through styles.

    Migrating: on a labelled field, check style props that used to size the control. A side-label field's width now includes the label column, and height includes the label and texts. To size the control alone, use styles={{ width }}. A state map on a style prop now resolves against the wrapper on a labelled field, so use media, container or root states there, not input states such as focused. className, style, qa and ref never move to the wrapper. A fieldStyles used only to place or size the field can become style props.

    Fixes: DateInput, TimeInput and FileInput now apply their styles and style props, which they dropped before. RangeSlider forwards styles. fieldProps.mods adds to the mods a field wrapper computes instead of replacing them, and a null in fieldStyles or fieldProps.styles now resets that key on the wrapper.

  • #1585 51727506a Thanks @tenphi! - Escape and Tab follow one rule in every field you type into: they go on to a surrounding dialog, which closes on Escape and moves focus on Tab, unless the field acts on the key or your onKeyDown calls e.preventDefault(). A prevented Escape or Tab stays at the input. Check your handlers: TextInput, TextArea, PasswordInput and SearchInput with an onKeyDown no longer hold Escape and Tab, so a handler that acts on Escape inside a dialog needs e.preventDefault() to keep the dialog open. ColorInput and an idle SearchComboBox no longer swallow them. In NumberInput, TagInput and CommandTextArea a prevented one no longer reaches the dialog, so a Tab that inserts a CommandTextArea option keeps focus in the field. ComboBox now lets the Escape or Tab that ends an IME composition in Safari reach the dialog too, like every other field.

  • #1587 cc25d5547 Thanks @tenphi! - Add tree-shaped options to FilterPicker: pass treeData (with expandedKeys, defaultExpandedKeys and onExpand) and the popover shows a checkable Tree under the usual header, search and footer. Tree mode is always multiple selection. Its value is every fully checked key, parents included, in tree order: checking a parent checks its children, and a partly checked parent is half-checked. The cascade runs over the whole tree, so a search never unchecks the nodes it hides. A search keeps each match with its subtree and opens the ancestors of deeper matches, then restores the user's expansion when it clears. Focus stays in the search input, which drives the active row: arrows move it, Right and Left open and close it, Space toggles it while the search is empty, and Enter toggles it and closes the popover. The default summary lists the topmost checked nodes, and renderSummary receives every checked key in tree order. Nothing in the tree is a tab stop, so Tab moves from the search to the footer. children is now optional in CubeFilterPickerProps, since a tree-mode picker has none.

    Tree changes that come with it: a node's new textValue names its checkbox when title is not a string, and a Tree with an id gives each row an id derived from it. In defaultCheckedKeys and the array form of checkedKeys, a parent key now checks its whole subtree, as in AntD; before, a parent listed without its children rendered unchecked. That holds for a parent whose own checkbox is disabled too, and in an uncontrolled Tree a parent the user checked also checks the children loadData adds under it later. Checking, unchecking and conducting a parent key now pass through a node whose checkbox is disabled or hidden to the eligible nodes below it, matching how a parent's state already followed them; before, a click stopped at that node and could leave the parent stuck half-checked. The object form { checked, halfChecked } is taken as given, as before. Rows no longer carry aria-checked, which role="row" does not support (axe aria-allowed-attr); each row's checkbox still reports checked and mixed, and the row keeps its data-checked and data-indeterminate attributes, so a test that read the row's aria-checked should read one of those.

  • #1586 045328aee Thanks @tenphi! - Picker, FilterPicker and ColorPicker take their trigger's tooltip as tooltip, as Select, Button and Item do. triggerTooltip still works, but it is deprecated and logs a one-time warning in development. The info badge next to a field's label stays labelTooltip.

  • #1591 363a6c8d7 Thanks @tenphi! - Read-only fields no longer look editable. isReadOnly, on a field or from a read-only Form, Checkbox.Group or Radio.Group, now sets a readonly mod and a default look: a recessed fill, with the value and label at full contrast. A text box also takes a softer border, except in high contrast. A checked Checkbox, an on Switch and a selected classic Radio show the unchecked outline and a dark mark in place of the brand fill. A read-only field takes no hover state. This covers TextInput, TextArea, PasswordInput, SearchInput, NumberInput, CommandTextArea, ColorInput, TagInput, ComboBox, SearchComboBox, DateInput, TimeInput, DatePicker, DateRangePicker, DateRangeSeparatedPicker, PeriodPicker, Checkbox, Switch and Radio. Button and tabs radios get the mod and lose their hover state and pointer cursor, and keep their look. Style the readonly key in styles or inputStyles to change the look.

  • #1583 b727ba8c0 Thanks @tenphi! - Add a tooltip prop to Switch, as Checkbox has: a string or TooltipProvider props, shown on hover over the switch and its inline label and on keyboard focus, and describing the input to screen readers. A disabled switch with a tooltip stays focusable, marked aria-disabled and inert, so the keyboard reaches the reason it is disabled; not being natively disabled, a switch that is on is part of a plain <form>'s submitted data. Without a tooltip it is natively disabled, as before. Wrapping a disabled switch in TooltipProvider opens nothing, since it takes no trigger props while disabled; use tooltip instead. On a labelled switch, tooltip is now the switch's own tooltip rather than the old spelling of labelTooltip, so it no longer warns; the info badge is still labelTooltip.

  • #1592 23d29d04a Thanks @tenphi! - TextInput, NumberInput, PasswordInput, SearchInput, TextArea and CommandTextArea take a tooltip of their own, as Checkbox and Switch do: a string, or TooltipProvider props. It is anchored to the field box, opens on hover over it and on keyboard focus, closes on any key, and describes the input. A first Escape only closes it, so it doesn't clear a SearchInput or close a dialog. A disabled input with a tooltip stays focusable so the keyboard reaches it too: it is aria-disabled and read-only instead of natively disabled, takes no text, doesn't step, and a click on it or on its label doesn't focus it. Not being natively disabled, its value is part of a plain <form>'s submitted data; ui-kit's Form is not affected. tooltip was the old name of labelTooltip, so a caller still passing it for the label badge now gets an input tooltip and no migration warning: rename it to labelTooltip.

Patch Changes

  • #1583 b727ba8c0 Thanks @tenphi! - Keep a disabled Checkbox focusable while it has a tooltip, as a disabled Radio and Button already are, so the keyboard can open the tooltip as the mouse does: it is usually the reason the checkbox is disabled. This covers a checkbox disabled on its own and one in a disabled Checkbox.Group. Such a checkbox is marked aria-disabled and stays inert: Space and clicks on the box or its label change nothing. Not being natively disabled, a checked one is part of a plain <form>'s submitted data. A disabled checkbox without a tooltip is natively disabled, as before.

  • #1593 badb2dc57 Thanks @tenphi! - A RadioGroup (including Radio.ButtonGroup and Radio.Tabs) or CheckboxGroup given isDisabled={false} inside a disabled <Form> or <Provider> now enables its options, as an explicit false does on every other field. Before, the group itself was enabled but each option stayed disabled. The same holds for a CheckboxGroup given isReadOnly={false} inside a read-only form. A group that sets neither prop still follows its form, and an option given isDisabled is still disabled inside an enabled group. A group's isReadOnly now also makes other fields rendered inside it read-only, such as a TextInput next to its options, as its isDisabled already disabled them. A loading button radio is now disabled unless the radio itself sets isDisabled={false}: a false it inherits from its group, form or provider no longer keeps it clickable while it loads.

  • #1588 7d60390d0 Thanks @tenphi! - A disabled Slider, RangeSlider or HueSlider is now disabled as a whole field: its label is muted and its message hidden, as on every other disabled field. Before, isDisabled reached only the track and thumbs. In a disabled form, the track now looks disabled too, and an explicit isDisabled={false} enables the slider there, as it does every other field.

  • #1589 0db331834 Thanks @tenphi! - A field given isDisabled, isReadOnly, isRequired, isInvalid or isValid as undefined now keeps the state of its enclosing <Form> or <Provider>, as it does when the prop is left out. Before, the undefined replaced it, so a wrapper passing an optional isDisabled through rendered an enabled field inside a disabled form. An explicit true or false behaves as before. This applies everywhere useProviderProps is used: every input, SearchInput, SearchComboBox, Label, the calendars and a nested Form. Form presentation props such as labelPosition, and form itself, are unchanged: form={undefined} still detaches a field from its form.