Skip to content

v0.185.0

Choose a tag to compare

@tenphi tenphi released this 25 Sep 15:46
· 158 commits to main since this release
d5d5400

Minor Changes

  • #1427 997e22cc Thanks @tenphi! - Add the t4n typography preset: 12px text at normal (400) weight, with t4's 18px line height. t4 is 500 so small text keeps its presence next to 14px body text, and until now it had no lighter option — the only 12px/400 preset was the monospace s4, so secondary metadata such as timestamps and counts needed preset: 't4' plus a hand-set fontWeight: 400. Use preset: 't4n' instead.

  • #1428 4d7a65e6 Thanks @tenphi! - Add TagInput, a multi-value field whose values show as removable chips below a single-line input. Values are committed with Enter or a delimiter (a comma by default), and Enter never submits a surrounding form; pasted lists are split into chips, validateTag rejects a value with a message, normalizeTag rewrites typed values before they are checked, and maxTags caps the list. With TagInput.Item options it becomes a combobox that toggles several options in a row, and allowsCustomValue lets the user add values that are not in the list. Backspace in the empty input moves to the last chip and the next one removes it; Escape or typing on a chip goes back to the input. isClearable adds a button that clears the typed text, and tagProps sets per-chip props, including a label and isDisabled to lock a value. With allowsCustomValue, the custom values already added are listed with the options, so they can be unpicked there too. inputMode and enterKeyHint pick the virtual keyboard. The field value is a string[] and works with Form rules.

  • #1428 4d7a65e6 Thanks @tenphi! - TextInputBase takes an actions slot for controls that always sit last in the suffix, after the validation and loading icons and after suffix in either position, such as a popover trigger.

  • #1427 997e22cc Thanks @tenphi! - TooltipProvider takes a qa for the tooltip it renders, and so does every component's tooltip object: <Button tooltip={{ title: 'Copy', qa: 'CopyTooltip' }}>. Only tooltipStyles and width used to reach the tooltip, and Tooltip itself dropped the qa its props accept, so a test could only find a tooltip by role="tooltip" — which works while exactly one is open and never says whose it is.

Patch Changes

  • #1429 694068ba Thanks @tenphi! - Stop useAutoTooltip from setting its overflow verdict inside the mount effect. React 19 flushes a sync commit's passive effects before the commit returns, so an overflowing Button, Item, TextItem, LayoutHeader, InlineInput or Radio label made a nested update of every commit it mounted in. ag-grid-react 33 wraps every new row in flushSync, so a long table crashed with "Maximum update depth exceeded" once about 50 such rows mounted in one task, for example when it jumped back to its top. Labels now queue their checks for one shared microtask. It reads every pending label, then commits the verdicts that changed in a single flushSync, after the commit but still before paint and before any other task. The teardown moved from an unmount effect to the label's callback ref, so React 18 Strict Mode, which replays effects with refs still attached, no longer loses the measurement. After a synchronous render in a test, the verdict lands in a microtask: await act(async () => …) first, then look the label up, since turning the tooltip on remounts it under TooltipProvider.

  • #1428 4d7a65e6 Thanks @tenphi! - Screen readers now announce the focused option while arrowing through ComboBox, SearchComboBox, CommandTextArea and FilterListBox options: aria-activedescendant pointed at an id no option had, and in ComboBox and FilterListBox it also stopped following the arrow keys. FilterListBox's search input now names its list with aria-controls.

  • #1428 4d7a65e6 Thanks @tenphi! - ComboBox, SearchComboBox and CommandTextArea no longer miss a blur when focus enters and leaves them within one animation frame, as it does in a fast automated test. Commit-on-blur and onBlur now run in that case too.

  • #1427 997e22cc Thanks @tenphi! - A Badge or Tag in a field's labelSuffix no longer grows the label row by a pixel. The suffix was wrapped in a block, where an inline-level element sits in a line box whose strut added space under it, so the row measured 21px instead of 20px and the field below stepped out of line with its neighbours. A single-element suffix is now a flex item, centred on the row. Mixed content — text, a fragment, several elements — is wrapped in a <span> and keeps flowing inline, spaces included.

  • #1427 997e22cc Thanks @tenphi! - ItemButton announces isSelected as aria-pressed, as its documentation says, instead of aria-selected. aria-selected is not a state of role button, so screen readers ignored it and a toggle or multi-select built from ItemButton isSelected read as a plain button. isSelected={false} renders aria-pressed="false", so an unpressed toggle announces as one. As on Button, it is skipped for a link (to) and for a call site's own role — a tab or option keeps aria-selected — and also for a trigger that reports aria-expanded, such as Disclosure.Trigger. An explicit aria-pressed still wins. A selector that found a selected toggle ItemButton by [aria-selected="true"] should use [aria-pressed="true"].

  • #1427 997e22cc Thanks @tenphi! - ListBox and FilterListBox accept their documented style props in TypeScript: height, width, flex, margin and the rest of the base, outer and color groups. They were always applied at runtime, but the props type did not declare them, so <ListBox height="20x"> failed to type-check and callers routed it through styles instead.

  • #1430 b4d48336 Thanks @tenphi! - Fix runtime palette changes that stopped recoloring the app in 0.183.0. In the published build, a setPaletteConfig() call, or a <Root palette> that changed after mount, updated the palette store, but the page kept the tokens of its first render, so the whole UI stayed on the palette it loaded with. usePaletteConfig() likewise kept returning its first render's config, and useColorTheme() kept injecting a theme's old tokens after the palette changed. All three follow every change again. The bug was in the React Compiler build only, so tests against the source did not show it.

  • #1427 997e22cc Thanks @tenphi! - Fix the caret of a Select, Picker or FilterPicker trigger not opening the dropdown. The trigger keeps an empty placeholder under its actions run to reserve that run's width, and the placeholder stopped every press that reached it. Once the run had been measured it sat right under the caret, so a press there only closed an open dropdown and never opened a closed one. The placeholder now lets presses through; real actions still keep a press on them from pressing the row. The same dead zone covered the padding and gaps of any ItemButton's actions run.

  • #1427 997e22cc Thanks @tenphi! - Link, Button, ItemButton and every other to-driven action no longer resolve a ! or @ prefixed to through the router. The rendered href was already correct, but the raw value was resolved too, so <Link to="!https://cube.dev"> — the documented way to open an external URL in a new tab — made a HashRouter warn on every render. Only the stripped path is resolved now.

  • #1427 997e22cc Thanks @tenphi! - Under React 19, a fragment passed as Result's title or subtitle, or as a field's description, is wrapped like any other mixed content again: Result renders it in its heading styles instead of as bare text. The check that tells a fragment from a single element used react-is@18, which does not recognise React 19 elements, so every fragment was taken for a single element and left unwrapped.