Repository navigation
v0.185.0
Minor Changes
-
#1427
997e22ccThanks @tenphi! - Add thet4ntypography preset: 12px text at normal (400) weight, witht4's 18px line height.t4is 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 monospaces4, so secondary metadata such as timestamps and counts neededpreset: 't4'plus a hand-setfontWeight: 400. Usepreset: 't4n'instead. -
#1428
4d7a65e6Thanks @tenphi! - AddTagInput, 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,validateTagrejects a value with a message,normalizeTagrewrites typed values before they are checked, andmaxTagscaps the list. WithTagInput.Itemoptions it becomes a combobox that toggles several options in a row, andallowsCustomValuelets 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.isClearableadds a button that clears the typed text, andtagPropssets per-chip props, including a label andisDisabledto lock a value. WithallowsCustomValue, the custom values already added are listed with the options, so they can be unpicked there too.inputModeandenterKeyHintpick the virtual keyboard. The field value is astring[]and works withFormrules. -
#1428
4d7a65e6Thanks @tenphi! -TextInputBasetakes anactionsslot for controls that always sit last in the suffix, after the validation and loading icons and aftersuffixin either position, such as a popover trigger. -
#1427
997e22ccThanks @tenphi! -TooltipProvidertakes aqafor the tooltip it renders, and so does every component'stooltipobject:<Button tooltip={{ title: 'Copy', qa: 'CopyTooltip' }}>. OnlytooltipStylesandwidthused to reach the tooltip, andTooltipitself dropped theqaits props accept, so a test could only find a tooltip byrole="tooltip"— which works while exactly one is open and never says whose it is.
Patch Changes
-
#1429
694068baThanks @tenphi! - StopuseAutoTooltipfrom setting its overflow verdict inside the mount effect. React 19 flushes a sync commit's passive effects before the commit returns, so an overflowingButton,Item,TextItem,LayoutHeader,InlineInputorRadiolabel made a nested update of every commit it mounted in. ag-grid-react 33 wraps every new row influshSync, 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 singleflushSync, 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 synchronousrenderin a test, the verdict lands in a microtask:await act(async () => …)first, then look the label up, since turning the tooltip on remounts it underTooltipProvider. -
#1428
4d7a65e6Thanks @tenphi! - Screen readers now announce the focused option while arrowing throughComboBox,SearchComboBox,CommandTextAreaandFilterListBoxoptions:aria-activedescendantpointed at an id no option had, and inComboBoxandFilterListBoxit also stopped following the arrow keys.FilterListBox's search input now names its list witharia-controls. -
#1428
4d7a65e6Thanks @tenphi! -ComboBox,SearchComboBoxandCommandTextAreano 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 andonBlurnow run in that case too. -
#1427
997e22ccThanks @tenphi! - ABadgeorTagin a field'slabelSuffixno 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
997e22ccThanks @tenphi! -ItemButtonannouncesisSelectedasaria-pressed, as its documentation says, instead ofaria-selected.aria-selectedis not a state of rolebutton, so screen readers ignored it and a toggle or multi-select built fromItemButton isSelectedread as a plain button.isSelected={false}rendersaria-pressed="false", so an unpressed toggle announces as one. As onButton, it is skipped for a link (to) and for a call site's ownrole— a tab or option keepsaria-selected— and also for a trigger that reportsaria-expanded, such asDisclosure.Trigger. An explicitaria-pressedstill wins. A selector that found a selected toggleItemButtonby[aria-selected="true"]should use[aria-pressed="true"]. -
#1427
997e22ccThanks @tenphi! -ListBoxandFilterListBoxaccept their documented style props in TypeScript:height,width,flex,marginand 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 throughstylesinstead. -
#1430
b4d48336Thanks @tenphi! - Fix runtime palette changes that stopped recoloring the app in 0.183.0. In the published build, asetPaletteConfig()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, anduseColorTheme()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
997e22ccThanks @tenphi! - Fix the caret of aSelect,PickerorFilterPickertrigger 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 anyItemButton's actions run. -
#1427
997e22ccThanks @tenphi! -Link,Button,ItemButtonand every otherto-driven action no longer resolve a!or@prefixedtothrough the router. The renderedhrefwas 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 aHashRouterwarn on every render. Only the stripped path is resolved now. -
#1427
997e22ccThanks @tenphi! - Under React 19, a fragment passed asResult'stitleorsubtitle, or as a field'sdescription, is wrapped like any other mixed content again:Resultrenders it in its heading styles instead of as bare text. The check that tells a fragment from a single element usedreact-is@18, which does not recognise React 19 elements, so every fragment was taken for a single element and left unwrapped.