Skip to content

fix: narrow row actions, widths, popover, dropdown keys, checkbox wrapLabel, sticky table header, date picker (qorus#646) — 0.78.9 - #722

Merged
davidnich merged 48 commits into
developfrom
bugfix/qorus646-functional
Oct 21, 2026
Merged

davidnich merged 48 commits into
developfrom
bugfix/qorus646-functional

Conversation

@davidnich

@davidnich davidnich commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

The functional fixes from #717 that reqraft (qoretechnologies/toolkit-react#137) and the Qorus IDE depend on, as their own PR (qoretechnologies/qorus#646). The front-end team asked for the contrast changes to be kept apart, so they are in a stacked PR of their own (#723, based on this branch). #717 will be closed with a note linking both.

Version: 0.78.10, develop's next version (develop took 0.78.8 with #721 and 0.78.9 with #720, both merged into this branch). #723 is 0.78.10 too; whichever merges second merges develop and bumps again only if its version is on npm by then.

How this branch was built:

Fixes, each with the test that fails without it

The test counts were run on this branch. "Before" means the fix's own source change taken back, with its tests and stories kept.

Rows (EntityRow, SeverityRow, RowActionsMenu), Table:

  • Narrow actions stay in sight by default. A narrow ReqoreEntityRow keeps its actions as buttons under the label (narrowActions='row', the default); the menu fold is opted into with 'menu'.
  • A folded action keeps its own name, and the actions menu is named for its row.
    • Unit (rowActionsMenu, EntityRow, SeverityRow): 8 tests fail before.
  • A lone or stacked row action spans the row where the row's container is a phone's width (480px) or narrower - on a phone, or in as narrow a container on a desktop; in a wider container each is as wide as its label. The container is measured, not the screen (2f666426, Foxhoundn's review; David's rule).
    • Unit (rowActionShortLabel, SeverityRow): 3 tests fail before. Stories: 6 Entity Row and 3 Severity Row fail before, among them No Wrap and Narrow Container Actions Stack on both rows; new: Entity Row · Lone Action Keeps Its Width Just Wider Than A Phone and Lone Action Spans The Row On A Phone, Severity Row · Actions Keep Their Width Just Wider Than A Phone.
  • A severity row's actions sit side by side while its container is wider than a phone (dc95bbe5, Foxhoundn's review on build Bump version to 0.48.11 and enhance gradient mixing logic in colors helper #412; David: side by side, wrapping if needed). With narrowActions='stack', the default, they stack, each the row's width, only at a phone's width (480px) or narrower. Between 480 and 640px they sit under the label, each as wide as its label, wrapping only when they don't fit, as with 'row'.
    • Unit (SeverityRow): 2 tests fail before. Story: Severity Row · Actions Keep Their Width Just Wider Than A Phone. It has three boxes: 560px side by side, 500px with three actions wrapping, and 480px stacked.
  • In 'menu' mode, a lone action stays at the end of the label's line while its container is wider than a phone; at a phone's width it goes under the label and spans the row (2f666426).
    • EntityRow: stories Narrow Container Lone Action In Menu Mode, and the same On A Phone.
    • SeverityRow: unit, 1 test fails before; plus its two stories.
  • A row-end action on a narrow screen says its shortLabel where it is drawn at the end of the label's line: a severity row in a container between 480 and 640px (an entity row is narrow only at a phone's width, where its action spans the row and says its label), and a table's folded column.
    • Unit (rowActionShortLabel): 10 of 16 fail before.
  • Table: a folded actions column is as wide as what its cells draw (8b98f148). Folded to the menu button's square, a short label or a label was cut to "T…".
    • A menu or an icon keeps the square. An action with no icon gets its short label, or its full label where it has none, whole in its button.
    • The width is measured with the browser's text metrics over the table's rows, and again when a font loads. It is never wider than the column was.
    • Unit (rowActionShortLabel, the rendered width against the measured words): 4 of 6 fail before.
    • Stories: Table › Folded Column Says The Short Label, and Folded Column Says The Full Label Without A Short Label. Both fail before: the text gets 20px where it needs 27px, and 131px.
  • Table: a sticky header is drawn above the table's pinned columns, and a pinned column's header cell is opaque (theme main, as a pinned body cell).
    • Unit (stickyLayers): 3 of 5 fail before. Stories: Panel › Sticky Header Above Its Body, Table › Sticky Header Above Pinned Columns.
  • Table header cell (DeepScan REACT_INEFFICIENT_PURE_COMPONENT_PROP):
    • Its button and menus get stable handlers and objects. A stacked control group's child keeps its style object while the values are equal.
    • Unit (controlGroupKeepsChildStyle + tableHeaderCellKeepsItsControls): 3 of 7 fail before the style change, and 2 of 4 before the header-cell change.
    • A cell with no sort data is drawn: 1 of 5 fails on the commit before it.

Widths:

  • A wrapped control group's child is never wider than the group. Unit (controlGroupWrapCap): 3 of 4 fail before. Stories: Control Group › Wrapped Group Keeps A Long Button Inside, and the same On A Phone.
  • A button is never wider than its container unless it sets its own maxWidth. Unit: 3 of 6 fail before; the 3 that pass are the cases that do not change. Stories: Button › Fixed Button Stays Inside Its Container, and its phone story.
  • A column's minimum is never more than its container. Unit: 3 of 3 fail before. Stories: Collection › Narrow Container Keeps Its Items Inside, and its phone story.
  • DataView: an editable key's Rename control is as wide as the key. Story: DataView › Editable Key Rename.

Controls:

  • A responsive control group folds only what it has, and each child once. Before, it was a render loop, drew a child twice, and crashed on a single child. Unit (controlGroupFoldIsBounded): 3 of 4 fail before.
  • Popover: an element is handed to every ref as it is drawn, so a popover takes a click at once. Unit (popoverArmedWhenDrawn): 1 of 2 fails before.
  • Popover: its open() control opens a popover that is closed now, as its isOpen() says (204dfc79, new since the first push). With this PR's first prerelease, reqraft's creatable value field lost its list (its unit test formEngineCreatableAllowedValues found no "Create new"). The list had closed itself before the popover rendered again, and the field's open() read the render's "open" and did nothing while isOpen() said closed. The refs fix above made that close come sooner; the controls' disagreement was already in develop. A trigger's own click still goes by the popover as it was when the click began. Unit (popoverControlsAnswerNow): 1 of 9 fails before; reqraft's test passes 3 of 3, and reqraft's 2826 unit tests pass.
  • Popover: a list never runs off the screen (7b71340e, Foxhoundn's review). What a popover draws stays inside its height cap and scrolls there (the list inside drew past it: 382px in a 297px surface), and the cap follows the room left: window and visual-viewport resize and scroll, the field's size, each at most once a frame. Stories: RichTextEditor › The List Opens In A Short Window, and On A Phone In Landscape; both fail before (the drawn list ends at 445px in a 380px window).
  • Popover: a list held to a short popover keeps its whole frame, and only its rows scroll (0f63e565, Foxhoundn's review on build Bump version to 0.48.11 and enhance gradient mixing logic in colors helper #412).
    • The capped surface holds a panel or a menu to the cap instead of scrolling it whole. Before, the panel's bottom border was out of sight under the surface's edge (445 against 360), and its rows scrolled inside that again.
    • Stories: both RichTextEditor list stories now check the frame and the single scroll area, and fail before.
  • Popover: making room for a list below its field never scrolls the field out of view. Stories: RichTextEditor › The List Opens In A Short Window, and On A Phone In Landscape.
  • Dropdown: back at a level with ←, the row it came from is highlighted, so → opens it again; a click back highlights nothing (09e12671, 1d133cbb, Foxhoundn's review). Unit (dropdownBackHighlightsWhereItCameFrom): 2 of 2 fail before, then 1 of 3 for the click-back case. Story: Dropdown › Keyboard Navigation With Left Arrow Navigates Back.
  • Dropdown: only the level the list shows hears the keys, and an opened level gets the list's options. Stories: Dropdown › Only The Open Level Hears The Keys, and An Opened Level Says And Ranks As The List Does.
  • Checkbox: a label with wrapLabel wraps, and the checkbox is as high as it. Unit (checkboxWrapLabel): 3 of 5 fail before. Stories: four, in Checkbox; their boxes are drawn so that every label in them ends inside (c16f4da2, from David's review).
  • Input: an auto-focused field is focused once, so a typed character is no longer dropped. Unit (useAutoFocusOncePerElement): 1 of 2 fails before. Story: Collection › Search Keeps Every Typed Character.
  • Input: a field's clear button is a named button (clearLabel). Unit (inputClearButtonName): 3 of 3 fail before.
  • Button: an icon-only button is named by its string tooltip. Unit (buttonTooltipName): 1 of 5 fails before.
  • Breadcrumbs: the folded crumbs' menus say they are menus, and open at a tap. Story: Breadcrumbs › Folded Trail Opens At A Tap, which now ends with the menu open (0820cbfc, Foxhoundn's review).
  • Date picker: a value it cannot read is no date, never a throw from its render. Unit (datePickerUnreadableValues): 7 of 7 fail before. Story: DatePicker › Values Without A Zone Or Unreadable.
  • Tests and stories (DeepScan NULL_POINTER): what they read off the page is found, or they fail saying what is missing (requiredElement, requiredAttribute).

Stories

Story links go to qlip build #413, which David approved. Every story was approved by David again on this branch, against develop rather than against #717, and again after Foxhoundn's 8 rejections were fixed.

New stories (31), each failing without its fix:

Story What it shows Quick check
Display/Entity Row · Narrow Container Actions Row A narrow row keeps its actions as buttons under the label by default; the menu fold is opt-in (qoretechnologies/toolkit-react#137's ExperimentCard) The buttons are visible and wrap; no ⋮
Display/Entity Row · Narrow Container Lone Action In Menu Mode / On A Phone In 'menu' mode, one action in a 400px container (a phone's width or narrower) goes under the label and spans the row; on a phone it says "Test the connection" (2f666426) Run under the label, the row's width; on the phone, a finger's height
Display/Entity Row · Narrow Container Lone Action Spans The Row With Its Full Label (renamed from Narrow Container Lone Action Short Label, 9ca09c13) A narrow entity row's lone action spans the row and says its full label: an entity row is narrow only at a phone's width, so it draws no short label 720px: at the row's end, as wide as its label. 400px: under the label, the row's width, its full label
Display/Severity Row · Narrow Container Lone Action In Menu Mode / On A Phone / Short Label The same for the severity row: in a 560px container, wider than a phone, the lone action stays at the end of the label's line, and there it says its shortLabel 560px: Investigate at the line's end. 400px and on a phone: under the text, full width
Collections/Table · Sticky Header Above Pinned Columns Scrolled, the header (label and menu) stays above the pinned columns; pinned headers are opaque Scroll: nothing covers the header; no header text shows through a pinned header
Layout/Panel · Sticky Header Above Its Body Nothing in a panel's body is drawn over its sticky header Scroll: the header stays on top
Form/Control Group · Wrapped Group Keeps A Long Button Inside / On A Phone A picked data-provider path in a 346px card Every step and Apply is inside the card
Form/Button · Fixed Button Stays Inside Its Container / On A Phone Fixed buttons with long descriptions No button is wider than the card
Collections/Collection · Narrow Container Keeps Its Items Inside / On A Phone Saved favorites in a 342px box, and in a dialog on a phone Each card with its Apply is inside
Collections/Collection · Search Keeps Every Typed Character An auto-focused search over 100 items "cat" stays "cat"; "XY" after the c reads "cXYat"
Form/RichTextEditor · The List Opens In A Short Window / On A Phone In Landscape A field 200px down a page in a 380px-high window Click it: the list opens below it and stays open
Form/Dropdown · Only The Open Level Hears The Keys Group opened from a text field, then ↓ Enter Only "Inner 1" is picked
Form/Dropdown · An Opened Level Says And Ranks As The List Does A German list opened at its group "2 Einträge durchsuchen", Telegram first, "Nichts gefunden"
Form/Checkbox · A Long Label Wraps In A Narrow Box / On The Left / Three Line Label / On A Phone wrapLabel in 160px boxes, and settings on a phone Labels wrap inside; each checkbox is as tall as its label
Form/DatePicker · Values Without A Zone Or Unreadable Three pickers 08:00 local; that day at midnight; text that is no date leaves the field empty and marks it invalid
Navigation/Breadcrumbs · Folded Trail Opens At A Tap A chat trail folded in a phone header Each fold opens at a tap; "Back to chats" is reached
Display/Entity Row · Lone Action Keeps Its Width Just Wider Than A Phone A 500px container on a wide screen Run at the row's end, as wide as its label
Display/Entity Row · Lone Action Spans The Row On A Phone A lone action in the default 'row' mode on a phone "Test the connection" under the label, full width
Display/Severity Row · Actions Keep Their Width Just Wider Than A Phone A callout's actions at 560px, at 500px with three, and at 480px 560px: side by side, label-wide. 500px: the third wraps. 480px: stacked, each the row's width
Collections/Table · Folded Column Says The Short Label One action with a short label, at 720, 480 and 265px Folded: "Test", whole, in a 47px column
Collections/Table · Folded Column Says The Full Label Without A Short Label One action with no icon and no short label Folded: "Test the connection", whole, in a 151px column

Existing stories that change against develop: none now. Before Foxhoundn's review, 11 did (stacked and lone row actions as wide as their labels, the Panel title action, the Dropdown left-arrow frame). Since 2f666426 and 1d133cbb, all of them match develop's frames again. Examples are Entity Row · No Wrap, Severity Row · Narrow Container Actions Stack and the Dropdown frame (0.00% in qlip build #412).

qlip build #413 (1223 snapshots), approved by David: 1 changed and 5 new. The changed frame is Severity Row · Actions Keep Their Width Just Wider Than A Phone. The new ones are the two Table stories and the three fixed rejections from build #412 whose rejected frames left no baseline.

Noise, not from the change:

  • Paging · Infinite With Auto Load: two scroll positions.
  • Progress · Live Update: a live value.
  • Drawer · Responsive Sheet Mobile: a header icon's anti-aliasing.
  • Error Boundary · Show Details: stack URLs.

Gates

  • Precheck at 83af187: 153 files, 1769 tests, 0 failed. Lint, both tsc runs and the test build pass.
  • Every story file, run one at a time and captured:
    • At f0e1d57: 1221 passed, 0 failed (75 files, 1193 captures). Only the three fixed frames and noise differ from ccf1c85.
    • The folded column on the same tree: 1223 passed. Only its two new stories differ.
    • At 1a95b75 and again at 83af187: the Table, SeverityRow, TemplateFieldUX, Dropdown and EntityRow files pass 182 of 182. Their captures equal the ones David approved.
  • Fail-first on this branch (each fix's source change taken back, with its tests and stories kept):
    • unit:
      • controlGroupFoldIsBounded: 3 of 4 fail;
      • rowActionsMenu, EntityRow and SeverityRow: 8 fail;
      • popoverArmedWhenDrawn: 1 of 2;
      • popoverControlsAnswerNow (the open() control): 1 of 9;
      • useAutoFocusOncePerElement: 1 of 2;
      • buttonTooltipName: 1 of 5;
      • EntityRow (actions row by default): 2 fail;
      • inputClearButtonName: 3 of 3;
      • datePickerUnreadableValues: 7 of 7;
      • stickyLayers: 3 of 5;
      • SeverityRow (lone action): 1 fail;
      • rowActionShortLabel: 10 of 16; the container rule (2f66642): 3 unit tests in rowActionShortLabel and SeverityRow;
      • dropdownBackHighlightsWhereItCameFrom: 2 of 2, then 1 of 3 for the click-back case;
      • SeverityRow, side by side above a phone's width: 2 of 2;
      • rowActionShortLabel, the folded column's rendered width: 4 of 6;
      • controlGroupWrapCap: 3 of 4;
      • buttonNeverWiderThanItsContainer: 3 of 6;
      • columnNeverWiderThanItsContainer: 3 of 3;
      • checkboxWrapLabel: 3 of 5;
      • controlGroupKeepsChildStyle and tableHeaderCellKeepsItsControls: 3 of 7 on the style change, 2 of 4 on the header-cell change;
      • a cell with no sort data: 1 of 5.
    • stories: the popover cap (7b71340): both RichTextEditor list stories (the drawn list ends at 445px in a 380px window); the container rule (2f66642): 6 Entity Row and 3 Severity Row stories. Every new story but one fails without its fix. The exception is Collection · Search Keeps Every Typed Character, which passes without its fix as well: it shows the behaviour, and the auto-focus fix's proof is its unit test.
  • Consumers: reqraft (fix: a card's one-line name centred on its actions; numbers with templates shown as used; operands named — 0.10.65 toolkit-react#137) passes on this PR's prerelease 0.78.10-pr.722.gccf1c85: precheck 278 files, 2828 tests; story run 767 passed, 0 failed. Its frames are unchanged apart from 1px of noise. It moves to the released 0.78.10 once this PR merges.
  • Contrast removed: none of it is here. The contrast PR (fix: text and icons read on what they are drawn on; reduced motion (qorus#646) — 0.78.13 #723) stacks on this branch, with every commit of it merged in.
  • CI at 83af187: Tests, the prerelease, CodeQL and DeepScan (see the PR's checks). On 1a95b75, DeepScan reported 1 new issue; 83af187 answers it.
  • qlip: build #413 is approved by David. Foxhoundn's 3 rejections on build #412 and 8 on build #410 are each answered on their snapshot and in a comment on this PR.

Classification of #717's commits

Classes: F functional (this PR), C contrast (#723), M merge (not picked), S split in two. The "Now" column is the commit on this branch (F) or on #723's branch (C).

# #717 commit Class Now Reason
1 508f3738 feat(colors): text and icon colors read against what they are drawn on C C f37efdc7 the readable-colour helpers and ReqoreSurfaceProvider: the foundation of the contrast work
2 c9f922e3 fix: Reqore's text and icons stand out from what they are drawn on C C 082c86c4 the contrast pass over 41 components. Borderline: it also adds aria-disabled to disabled non-form components, which WCAG ties to the contrast exemption for disabled content. I kept it with C because it changes no layout or behaviour that reqraft or the IDE rely on
3 5625247c fix(stories): stories draw text only on colors it can be read on C C b2781f54 story colours
4 3c1ff235 test(stories): the story run checks the contrast of text and icons C C 914bef8f the contrast gate (axe-core); a dev dependency
5 d3c8108a fix(button): an icon's color given in its props stands out… C C f29a49de icon colour readability
6 e563e640 fix(deepscan): readable-color props are one object… C C 3efd2cdd DeepScan fixes for code the contrast pass added
7 79b6fe62 feat(motion): Reqore honours prefers-reduced-motion C C 490bae24 reduced motion, purely visual. Its reason was that contrast was measured mid-fade
8 8ad3d8c8 fix(icons): an icon's color given in its props stands out… C C ad654fcb icon colour
9 e8b4ec29 fix(link): a link's intent reads on the surface it is drawn on C C b66060bd colour
10 2a15c0fb fix(button): an active button draws what it holds on its fill C C f809892e colour
11 0fda83b1 fix(entity-row): the description and metadata fade their text… C C 3cd130e0 fading and colour
12 aeb3d8c1 fix(effect): a translucent gradient is read with its ring C C 7c08b6e3 colour reading
13 2f2bbcfd fix(control-group): a responsive group folds only what it has… F F 89ede0b8 a render loop, a child drawn twice, and a crash on a single child
14 7aa3aa82 Merge origin/bugfix/focus-popover-opens-when-focused M not picked #708, already in develop: not picked
15 b8245662 fix(colors): colors the helpers cannot read are drawn as given… (Foxhoundn) C C dcb327ca his review of the colour helpers
16 11fdbfa3 fix(components): explicit values, own fills and surfaces… (Foxhoundn) C C f3bde577 his review of the contrast pass. Borderline: it also makes ReqoreTag a memo component and fixes crashes. The crashes are in code the contrast pass added, so this stays with C
17 951549cd fix(stories): story icon colors and opacities given as values… (Foxhoundn) C C a186d8a6 story colours
18 473ada31 Merge origin/… into … (Foxhoundn) M not picked a sync merge: not picked
19 52add6e7 Merge develop (0.78.5, #708) into the contrast work M not picked develop's content: not picked
20 cbcd1ada fix(deepscan): memo components get the same props… (Foxhoundn) C C 249e84c6 DeepScan flags that exist only because 11fdbfa made ReqoreTag a memo (DataView, the dropdown's trail tags, SegmentedControl's More button)
21 e970c1f0 fix(rows): a folded action keeps its own name, and the actions menu is named for its row F F 5cbc42aa accessible names; reqraft #137's ExperimentCard
22 dceb77d3 fix(refs): an element is handed to every ref as it is drawn… F F 1b6b4d8c a popover now takes a click at once; the IDE's story harness kept sleeps for it
23 db81d7e5 Merge Foxhoundn's review into the develop merge and the two fixes M not picked not picked; its one hand-resolved spot (EntityRow) is covered by #21 and #16
24 4193ebc4 fix(breadcrumbs): the folded crumbs' menus say they are menus… F F 30cb1310 aria and the tap story; the IDE's Qonsole on a phone
25 db3fa639 fix(input): an auto-focused field is focused once… F F 2f3521eb a typed character was dropped
26 dcb33d8e chore: 0.78.7 F F d5b8a150 the functional PR's version
27 1e5236e8 fix(button): an icon-only button is named by its string tooltip F F be6e7574 accessible name; the IDE's tests find buttons by name
28 ef001231 test(message): a muted refusal reads on its fill as drawn C C b33363ad a story proving the contrast fix
29 287701bf fix(data-view): an editable key's Rename control is as wide as the key F F f441647a width; the IDE's width check
30 52c8fbde fix(rows): stacked row actions span the row only on a phone F F b9dc6578 row layout (David's width rule)
31 c2e8ade3 fix(entity-row): narrow, a row's actions stay in sight by default; the menu is opted into F F fbf56678 reqraft #137 depends on it: Foxhoundn's ExperimentCard rejections
32 232c00bd fix(effect): a frost's opacity given by its caller is drawn as given C C 237a911f contrast floors. It also moves helpers/surface.ts, which C uses
33 fa238d9e fix(cards): a card reads its text on what it paints… C C 67d0b3ec colour
34 ae00764d test(stories): the contrast check measures what axe cannot decide… C C f9c8eddf the contrast gate
35 8e93b4ed docs(stories): two stories describe what they render… S F 42f23ae0 · C 45053f64 one description each: Collection · Search Keeps Every Typed Character → F (goes with #25); Message · Muted Refusal On The Page → C (goes with #28)
36 0f0f6f11 fix(motion): reduced motion stills Reqore's elements in the app's own portal too C C bffdabe1 reduced motion (goes with #7)
37 aed40753 fix(rating): a star in a theme's color is drawn in the shade that stands out C C be440ff0 colour
38 d409a609 refactor: one copy of each color rule the /audit of #717 found twice C C 37048b41 refactor of contrast code
39 5732f356 test: stories say and check what they show, tests share their helpers S F fb70e1c5 · C 718c8cf2 F part: the Breadcrumbs · Folded Trail Opens At A Tap checks (#24), and the EntityRow/SeverityRow · Narrow Container Actions Menu naming checks (#21). C part: the reduced-motion story, the NavRail/Icon/Notification descriptions, DatePicker · With Effect's colours, the aria-disabled and crumb-intent tests, and the shared colour and surface test helpers
40 14430590 fix(accordion): a header and what it holds are read on what the header is drawn on C C a46e938e colour
41 7f1016d3 fix(description-list): an uppercase label in an intent is faded… C C c3709a41 colour
42 e096a8e5 fix(nav-rail): a rail's marks read on the gradient its effect paints C C 087a9ecd colour
43 eafd29b7 fix(panel): a panel's own text is read on the fill it paints C C bafbec63 colour
44 28b8395c refactor: one owner for each fill a component paints… C C 73a205b8 refactor of contrast code; its SegmentedControl handler-map fix is a bug in a map that #6 added
45 ec8aa0b5 fix(panel): what a panel's title bar holds is written in the bar's text C C 3802a29a colour
46 e9d21ac2 test(stories): the lead fixes are shown… C C b6fedda8 contrast stories
47 4a4039cc fix(cards): a clickable card's text reads on its hover fill too C C 26328208 colour
48 ae33bdc2 fix(button): a hovered button's description reads on its hover fill C C 4bc1a8c7 colour
49 f303c5af fix(input): a field's clear button is a named button F F ce64e679 role and name; the IDE's tests find the expression's ×
50 da508bf8 fix(entity-row): with narrowActions='menu', a lone action stays at the end of the label's line F F ec7fff3a row layout
51 a6def18e fix(date-picker): a value it cannot read is no date, never a throw from its render F F 82985aff the IDE's Workflow Orders page crashed
52 c08c7ee0 test(stories): a date picker's values without a zone… F F 1ba85612 story for #51
53 268e2fb5 fix(table): a sticky header is drawn above the table's pinned columns… S F 5c19133e · C 7eb9e444 F part: the panel body's stacking context (isolation); a pinned header cell is opaque and above what scrolls under it; the stories and stickyLayers test. C part: the pinned header's fill read from the handed-down surface (getThemeSurface), and the ReqoreSurfaceProvider around the cell. The dry run fails to type-check on exactly these two imports
54 5a02458d fix(severity-row): with narrowActions='menu', a lone action stays at the end… F F 1e35fc08 row layout
55 90f64b02 feat(row-actions): a row-end action on a narrow screen says its short label F F 26109600 shortLabel (David's rule)
56 1cf24cb1 style(stories): the phone story's description quotes its labels as prose does F F 361a1ce7 formatting of #55's story
57 e12ed1d2 fix(control-group): a wrapped group's child is never wider than the group F F 59daa1c0 width; the IDE's data provider path
58 2789e173 fix(button): a button is never wider than its container unless it sets its own maxWidth F F c06b3169 width
59 374d40f6 fix(columns): a column's minimum is never more than its container F F 32534bff width; the IDE's favorites dialog
60 a1884445 fix(popover): making room for a list below its field never scrolls the field out of view F F ab0d32eb the list never opened in a short window
61 9bd654e5 fix(dropdown): only the level the list shows hears the keys… F F 457280ba keys and option inheritance
62 54547aed fix(checkbox): a label that wraps wraps… F F 038ece32 the IDE's "Skip totals rows"
63 a6212819 test: what a test or a story reads off the page is found… F F 5a450a10 DeepScan NULL_POINTER, in F tests and stories (stickyLayers, checkbox, dropdown, template field)
64 d76200e8 fix(control-group): a child keeps the style it is handed while it says the same F F a6af5cb0 DeepScan memo
65 01ad747d fix(table): a header cell hands its button and menus the same handlers… F F 790ab78a DeepScan memo
66 053b4e41 fix(table): a header cell with no sort data is drawn F F cefa51f0 fix of #65

🤖 Generated with Claude Code

https://claude.ai/code/session_01EVRGWEwQAi5btU1qdHBfmb

David Nichols and others added 30 commits October 20, 2026 22:14
…ch child once (qorus#646)

A responsive group folds its children into a `…` menu one at a time while
its row overflows. Three things were wrong with how it counted:

- Nothing stopped the count once every child was in the menu. A group
  whose overflow button alone is wider than its room (a labelled or large
  button, a narrow container) kept counting. Each step re-rendered the same
  row and measured it again, forever. In a browser that is a render loop at
  frame rate; under act it never returns. The Qorus IDE's agent found the
  unbounded counter while chasing a frozen story.
- The row sliced the raw `children` array, but the menu took from
  React.Children.toArray(children), which leaves out the holes a caller
  leaves (null, false: an action it decided not to render). With a hole in
  front, a child was drawn in both the row and the menu.
- A group with one child, which is not an array, threw at its first fold
  (`children.slice` is not a function).

The row, the menu and the count now read one list, `foldable`: the
children as React renders them, holes left out. The count stops when the
row fits or when nothing is left in the row to fold. That bound is the end
of the list, not an iteration cap. The old comment explained why the count
could not be bounded by the number of children: the row and the count read
different lists. They no longer do.

Tests: controlGroupFoldIsBounded. Three cases fail before the fix: the
group measures itself past the test's limit, `children.slice is not a
function`, and a child is in both the row and the menu. A fourth case, the
row still stops as soon as it fits, passes both before and after.
…s named for its row (qorus#646)

When a narrow EntityRow or SeverityRow folds its actions into one menu, the
action's own aria-label was not passed on to its menu item. reqraft's
experiment card has "Show analytics for Short copy" on a button; folded, the
item was called only "Show analytics", the same as the item in every other
row's menu. Every menu button was also called "Actions", so a list of
versions read as a list of identical buttons.

- An item now keeps its action's own aria-label as its accessible name. Its
  words still come from its label, tooltip or aria-label, as before.
- The menu button, and the menu it opens, are named for their row when the
  row's label is text: "<actionsMenuLabel>: <row label>", for example
  "Actions: Short copy" (rowLabel on ReqoreRowActionsMenu, rowLabelText).
  A row whose label is an element keeps the plain "Actions". A colon rather
  than "for", so a host's own word ("Akce") reads right in its language.
- Applies to ReqoreEntityRow and ReqoreSeverityRow. A table's row menu is
  unchanged, since its rows have no label of their own.

Tests: rowActionsMenu, EntityRow and SeverityRow. Eight cases fail before
the fix: items keep their names, the button and menu are named for the row
(also with a host word), a blank row label names nothing, rowLabelText, and
the rows' folded menus. The EntityRow and SeverityRow narrow-menu stories
check the row-named button. COMPONENTS.md documents both.
…over takes a click at once (qorus#646)

useCombinedRefs handed a component's element to the refs it was given in an
effect, after the browser had painted it. A popover around a Reqore button
or a dropdown learnt of its trigger only then, and armed its click listener
in the render after that. So a trigger on screen opened nothing when it was
clicked straight away, and nothing on the page said when it would. The Qorus
IDE's story harness kept sleeps for it (a dropdown's .template-selector,
among others). The effect also ran after every render, since its list of
refs is a new array each time.

useCombinedRefs now returns setRef, a ref callback. React calls it in the
commit that attaches the element, so every ref holds the element before the
paint. It changes only when a ref given changes, and then React hands the
element over as it does for any new ref callback. Button, Input, Textarea,
Tabs item, FadeScroller, Table body and header, Panel, Menu and Menu item
draw their element with it. The four that draw through a ref callback of
their own (Popover, Panel, Menu, Menu item) call it from a callback that is
one function for the component's life: a new callback each render would
detach and attach the element every time. The unused `_innerRef` state, set
again on every render, is gone.

Tests: popoverArmedWhenDrawn. The page is drawn and committed with flushSync
and nothing more, which is the state of a page as it is first painted. The
trigger is then clicked at once. A dropdown's popover opens; it stayed shut
before the fix. A popover around a Reqore button opens too, which already
held before the fix.
…story taps them on a phone (qorus#646)

A Qonsole panel on a phone folds its whole trail into the dropdown named
for the current chat. In the Qorus IDE a tap opened nothing, so a finger
reached neither the chat's full name nor "Back to chats". The IDE was on a
#708 prerelease from before 26327a4. That commit made every ReqoreDropdown
open at a tap (opensOnTap), including both of the breadcrumbs' fold menus,
and it is in 0.78.5. Nothing tested it for the breadcrumbs.

- Both fold menus (the current-page dropdown and the "…") now say what they
  are and whether they are open: aria-haspopup="menu" and aria-expanded,
  as the row actions menu does.
- The "…" dropdown has a class of its own,
  reqore-breadcrumbs-overflow-menu.

Story Navigation/Breadcrumbs › Folded Trail Opens At A Tap (touch, 390 px):
- A finger taps the folded current crumb. Its menu names the chat in full,
  and "Back to chats" in it is reached by a tap.
- A finger taps the "…" of folded ancestors. It opens, and "Back to chats"
  is reached there too.
- Both buttons say they are menus, closed and then open.
Before this change the aria checks fail. With the dropdown's opensOnTap
taken out, the tap checks fail (the menu never opens), which was the IDE's
case. Hover is unchanged: the menus are still hoverStay for a mouse.
… (qorus#646)

A field with `focusRules: { type: 'auto' }` is focused when it appears. useAutoFocus
re-applied that focus — and moved the selection to the end — every time its element
reference changed. A controlled input hands React a new ref callback on every render,
so the SAME node arrives under a changing identity on each keystroke; under a heavy
per-keystroke re-render the re-applied selection raced the keystroke and dropped a
character — typing "ca" into a ReqoreCollection's auto-focused search left "c".

useAutoFocus now focuses an element once, when it first appears, and leaves a
re-appearing same element alone. A genuinely different element that takes its place —
a new field opening — is still focused.

Tests:
- useAutoFocusOncePerElement: the same element handed back under a changing reference
  is focused once, not again (fails before the fix); a different element that replaces
  it is focused.
- Collection story "Search Keeps Every Typed Character": a filterable collection whose
  search auto-focuses keeps every character typed into its heavy, re-rendering filter
  and the caret where it is typed.
…s#646)

A ReqoreButton with an icon and no label of its own had no accessible name unless the caller gave it an
aria-label: assistive technology heard "button", and a test that finds buttons by name found nothing to
test. In the Qorus IDE's Interfaces view, 24 of 29 visible buttons were unnamed.

When a button has no visible label, no aria-label and no aria-labelledby, its tooltip names it if the
tooltip is a string - the words the button would say. A tooltip that is a node or an object is left to
the caller, and a button with a label, or one already named, is not named twice. No pixel changes.

Tests: buttonTooltipName. An icon-only button is found by its tooltip's name (fails before the fix);
four guards pass before and after: a labelled button is named by its label and carries no aria-label,
an explicit aria-label wins, aria-labelledby is not doubled, and an object tooltip names nothing.
…y (qorus#646)

An editable DataView draws each key as a control ("Rename key") holding
the key's tag. The control is a grid item, and a grid item stretches to
its cell, so it was as wide as the key column (220px for a 50px key) and,
in a stacked row, as wide as the row: a click target across empty space,
which the Qorus IDE's width check reported. It now sits in the key's
cell at its own width.

Story: DataView › Editable Key Rename checks the control is as wide as
its key (fails before: 220px for a 59px key).
A design change, from David's width rule for the Qorus IDE: on any screen
wider than a phone's, a control is as wide as what it says and never
stretches to fill its row; on a phone (480px or narrower) it may span
the screen, where a full-width row is a finger's target.

A narrow severity row (and an entity row with `narrowActions='stack'`)
stacks its actions under the label, one to a line, and each was the
row's width wherever the row was narrow - also in a 320px drawer on a
1920px screen, where a button was a bar with a word in it. Stacked, each
is now the row's width only on a phone (`isMobile`) and as wide as its
label elsewhere. An action that is itself a menu does the same.

Stories: SeverityRow › Narrow Container Actions Stack and EntityRow ›
Narrow Container Actions Stack / Narrow Stacked Menu Action Is Labelled
check each action against the row on a phone and against its label on a
wider screen; the touch story checks the phone.
…e menu is opted into (qorus#646)

Foxhoundn on the ExperimentCard stories (toolkit-react #137, qlip #361):
"put the buttons back here, they should NOT be folded into a menu. The
buttons need to be accessible and visible. Do not make general changes
like that - it needs to be opted in!"

0.78.5 (a7790c8) made a narrow entity row (under 480px of its container)
fold two or more actions into one menu button by default, so every row
that never asked for it lost its buttons behind a ⋮: the A/B test card's
Show analytics, Accept and Remove among them. Up to 0.78.0 a narrow row
kept its actions as buttons under the label.

- A new narrow mode, `'row'`, is that layout again, and EntityRow's
  default: under the label, a row of buttons each as wide as what it says,
  onto another line where they do not fit (0.78.0's did not wrap, and
  labelled actions reached past a phone's card).
- `'menu'` is opted into. A host that relies on the fold sets
  `narrowActions='menu'`.
- `'stack'` is as it was. SeverityRow keeps `'stack'` as its default and
  takes `'row'` too.
- A narrow row says which it is in `data-actions` (`row`, `stack` or
  `menu`).

Tests: a narrow row keeps two actions as buttons under the label by
default (fails before: they were folded); the menu tests opt in. Stories:
EntityRow › Narrow Container Actions Row (fails before); the menu stories
set `narrowActions='menu'`.
… not how it came to be (qorus#646)

Collection › Search Keeps Every Typed Character now says what it renders
and shows, in the "Renders X…" form, without naming internals or history
(the /audit of #717).

The functional part of 8e93b4e on #717; the Message story's description
is on the contrast branch with the story it belongs to.
…the control group tests share their layout model (qorus#646)

From the /audit of #717, each checked against the code first:
- Breadcrumbs › Folded Trail Opens At A Tap said both menus say "open"
  only while open, and checked only "open": it now checks each closes
  again, and that "Back to chats" is all that was chosen. The narrow
  header, not a short trail, is what folds it.
- EntityRow and SeverityRow › Narrow Container Actions Menu name the menu
  button they check.
- A host word for the row menu is checked without a row too; a test name
  says what it checks.
- The two control group tests share the modelled control-group layout
  (__tests__/shared/controlGroupLayout.ts) instead of each copying it.

The functional part of 5732f35 on #717; its contrast part is on the
contrast branch.
The clear button on an input or a text area is an icon with a click handler
on it. It had no role and no name: a screen reader said nothing for it, and a
test could not find it by role. The Qorus IDE's tests could not find the
expression's ×.

It is now a button named "Clear". An input and a text area take
`clearLabel` for a host's own words. The text area keeps the prop off the
element it renders: the rich text editor's Slate editable writes the props
it does not know onto its div.

Test: inputClearButtonName. An input's button is found by role and name and
clears the field; so is a text area's; and a host's word is used when given.
All three fail before.
…e end of the label's line (qorus#646)

In the opt-in 'menu' mode, two or more actions fold into one menu button at
the end of the label's line when the row is narrow. A row of that mode with
one action had no menu to fold into, so it wrapped the action under the
label: a line of its own for one button, where a row with more had none.

Now that one action stays a button at the end of the label's line, where the
menu would be. The row says so: `data-actions='end'`. Only 'menu' rows
change. The default ('row', visible buttons under the label) and 'stack' are
as they were (David, qorus#646).

Stories, both failing before (the action was under the label):
- Entity Row > Narrow Container Lone Action In Menu Mode (a 400px container);
- Entity Row > Narrow Container Lone Action In Menu Mode On A Phone: a
  finger's size, and a tap runs the action without opening the row.

Narrow Container Actions Menu (two or more) is unchanged. The prop's docs,
TReqoreNarrowRowActions and COMPONENTS.md say it.
…om its render (qorus#646)

The date picker read its value, and its minValue and maxValue, with
parseAbsoluteToLocal, which throws for anything but an ISO date-time with a
zone. Any other string threw from the render, and so did an invalid Date
(through toISOString). The Qorus IDE's Workflow Orders page went to its
router's error page for "2026-06-02T08:00:00".

The rule, in one reader (readDate) that never throws:
- A date-time with a zone or an offset is that instant, in the user's
  zone, as before.
- A date-time without one is that wall-clock time in the user's zone: ISO
  8601 reads a date-time with no offset as local time.
- A date alone is that day at midnight, local.
- Anything else, text that is no date or an invalid Date, is no date. The
  field is empty, and says it was given a value it cannot read the way it
  says a value out of its bounds: it is invalid (aria-invalid,
  data-invalid), drawn in the danger intent.
- A bound it cannot read is no bound. The year and month dropdowns fall
  back to their default range.

Other inputs that read a value while rendering, checked:
- DataView's scalar threw for an invalid Date (toISOString); it now shows
  it as it is ("Invalid Date").
- TimeAgo already handled an unreadable time.
- There is no other date, time or date-range input, and the number inputs
  parse nothing while rendering.

Test: datePickerUnreadableValues, 7 cases, all failing before:
- a date-time with no zone, and a date alone, shown as local time;
- text and an invalid Date: empty and invalid;
- unreadable bounds, and an invalid Date as a bound;
- DataView with an invalid Date.
…ot read (qorus#646)

Form/DatePicker > Values Without A Zone Or Unreadable renders three pickers:
- "2026-06-02T08:00:00" shows 08:00, local;
- "2026-10-17" shows that day at midnight;
- text that is no date is an empty field, drawn as invalid.

Before a6def18 the story threw from its render: "Invalid ISO 8601 date time
string: 2026-06-02T08:00:00".
…, and a pinned column's header hides what scrolls under it (qorus#646)

Scrolled, a table's pinned columns were drawn over its sticky header: the
label was cut off and the menu button covered, and only the middle showed
the header. The panel's sticky header and a pinned cell were both at
z-index 2 in one stacking context, and the cells come later in the
document, so they won. A panel with a sticky header now draws its body in
a stacking context of its own (isolation: isolate), so nothing in the body
is drawn over the header, whatever its z-index. It is not a containing
block: nothing in the body is placed differently, and popovers and menus
are drawn outside the panel.

A pinned column's header cell painted nothing, so the column headers that
scroll under it showed through ("ORDER DA" under "ACTIONS"). It now paints
the theme's main color, opaque, as a pinned body cell does.

Stories: Layout/Panel "Sticky Header Above Its Body" and Collections/Table
"Sticky Header Above Pinned Columns" scroll each layer under the header and
read every point across it, and require pinned column headers to be opaque
and on top. Unit: __tests__/stickyLayers.test.tsx.

The functional part of 268e2fb on #717. On the contrast branch, the
pinned header cell paints what the header row is drawn on and tells what
it holds.
…the end of the label's line (qorus#646)

As on ReqoreEntityRow (da508bf), at David's direction: in the opt-in 'menu'
mode, two or more actions fold into one menu button at the end of the
label's line when the row is narrow. A severity row of that mode with one
action had no menu to fold into, so it stacked the action under the label:
a line of its own for one button, where a row with more had none.

Now that one action stays a button at the end of the label's line, where
the menu would be, and the row says so: data-actions='end'. It is not
stacked, so an icon-only action stays its icon with its tooltip, as at full
width. Only 'menu' rows change: the default ('stack') and 'row' are as they
were.

Stories, both failing before (data-actions was 'stack', the action under
the label):
- Severity Row > Narrow Container Lone Action In Menu Mode: a 400px
  container, beside the same row with the default, still stacked;
- Severity Row > Narrow Container Lone Action In Menu Mode On A Phone: a
  finger's size, and a tap runs the action without opening the row.
Unit (SeverityRow.test.tsx): 'end' for 'menu' with one action, labeled or
icon-only (fails before); one action unchanged by default, with 'stack',
with 'row', and wide with 'menu'.

The prop's docs, RowActionsMenu's TReqoreNarrowRowActions and COMPONENTS.md
say it.
… label (qorus#646)

David, on the EntityRow phone story ("the button takes up too much space on
a narrow screen; on a narrow screen it should read 'Test'"), as a general
rule: a row-end action on a narrow screen uses a short label.

Every row action type takes an optional `shortLabel`
(IReqoreRowActionShortLabel: IReqoreEntityRowAction, IReqoreSeverityRowAction,
TReqoreTableCellAction). Where reqore draws an action compactly, on a line
it shares with the row's label, the action says it:
- the one action of a narrow narrowActions='menu' ReqoreEntityRow or
  ReqoreSeverityRow, at the end of the label's line (data-actions='end');
- a narrow table's folded column, for an action with no icon (one with an
  icon is its icon alone there, as before: the column is the menu button's
  width).
Its label is then its tooltip (unless it has one) and its accessible name
(unless it has one), so a short label is written as words of its label.

With no short label (getCompactRowAction), an action with an icon and a
tooltip is its icon alone there, named by its label: its author gave it the
words it reads by without its label. Any other says its label, as before.
So no row drawn today changes unless it gives an action a short label or a
tooltip. Wide, and on a line of its own (stacked, or in a row under the
label), every action says its label. Menus name each action by its label.

Stories:
- Entity Row > Narrow Container Lone Action In Menu Mode On A Phone: the
  action reads "Test", and is still called "Test the connection" (fails
  before: it read "Test the connection");
- Entity Row > Narrow Container Lone Action Short Label and Severity Row >
  Narrow Container Lone Action Short Label: three rows in a 720px box and a
  400px one; wide each says its label, narrow its short label, its icon
  alone (an icon and a tooltip), or its label (neither). Both fail before.
Unit: __tests__/rowActionShortLabel.test.tsx (getCompactRowAction, both
rows, the table's folded column; 10 of 16 fail before, the 6 that pass are
the cases that do not change).

COMPONENTS.md documents shortLabel on EntityRow, SeverityRow and Table; the
type is exported from the index.
…ose does, as prettier writes it (qorus#646)

90f64b0 escaped the double quotes around "Test" and "Test the connection" in
the description, which prettier writes as a single-quoted string: two more
deviations in a file whose count must not go up. Typographic quotes need no
escape. EntityRow.stories: 36 deviations, as before 90f64b0.
…roup (qorus#646)

A wrapped ReqoreControlGroup gave its children no cap. A child as wide as
content that does not wrap stayed that wide, past the group and the card it
was in: the Qorus IDE's data provider path (a `fluid wrap fill` group whose
steps are `fluid={false}` groups holding a select that says its value and
description) ran 487-712px wide in a 346px card on a phone, and the
favorites dialog's Apply was cut off.

Now each child of a wrapped group is capped at the row (max-width: 100%)
and may shrink below its content to fit it (min-width: 0). A capped button
says its description on as many lines as it takes, as a fluid button in a
wrapped group already did (fluid buttons always had max-width: 100%).

The rule is reqore's global style (UIProvider,
WRAPPED_CONTROL_GROUP_CHILD_SELECTOR, `:where(.reqore-control-group-wrapped)
> *`), and weighs nothing: a child that sets its own width limits (a
button's maxWidth) keeps them. A group's own styles could not weigh less
than the child's: styled-components scopes them to the group's class. The
group marks itself `reqore-control-group-wrapped` when it wraps.

Stories (Form/Control Group):
- Wrapped Group Keeps A Long Button Inside: a picked path in a 346px card;
  fails before (children 488, 351 and 382px wide in 346px);
- Wrapped Group Keeps A Long Button Inside On A Phone: the same in a card
  on a phone, with the card's Apply; fails before (488px in 332px).
Unit: __tests__/controlGroupWrapCap.test.tsx (which children are capped,
the rule's weight; without the class, the two that cap fail).
…s its own maxWidth (qorus#646)

A button had max-width: 100% only when it was fluid and not fixed
(`maxWidth || (fluid && !fixed ? '100%' : undefined)`). A fixed button had
no cap at all, and fixed reaches a select's button directly or through a
group (a group hands its children `fixed`). So in the Qorus IDE's data
provider path, a step's select saying its value and description stayed as
wide as both on one line, 487-712px in a 346px card on a phone, even inside
the group round 9 capped at the row.

Now every button is capped at its container (max-width: 100%) unless it
sets its own maxWidth, which stays its limit; a square button keeps its
side. fixed keeps meaning that the button does not stretch. A capped
button's label is clipped as any button's is, and its description takes as
many lines as it needs, as in round 9.

What else this changes (every story file captured before and after, 1188
captures): a panel's single action that the title bar's responsive group
folded into a menu of one, because its labelled button overflowed the
group, now stays its icon, as the panel's own stories describe (Panel ·
Compact Title When Narrow, Fit Label Comparison); and a drawer sheet's
header icons sit half a pixel lower (82.64 to 83.14px; the buttons' boxes
are unchanged), which shows in Drawer · Responsive Sheet Mobile.

Stories, failing before: Button · Fixed Button Stays Inside Its Container
(476px in a 346px card) and its phone story.
Unit: __tests__/buttonNeverWiderThanItsContainer.test.tsx (fixed, fixed and
fluid, and neither fail before; fluid, maxWidth and square are the cases
that do not change).
…rus#646)

ReqoreColumns, and ReqoreCollection with it, laid its columns out at
`minmax(<minColumnWidth>, <maxColumnWidth>)`. A collection's minimum is its
zoom width, 400px at 100%, so in a container narrower than that the column
stayed 400px and its cards ran past it: in the Qorus IDE's favorites dialog
on a phone, a card was laid out at 63-433px in a dialog whose content ends at
342px, and its Apply was out of reach.

Now the minimum is `min(<minColumnWidth>, 100%)` (getColumnMinimum): the
width is the narrowest a column is where the container has room for it, not
a width it keeps where there is less. A keyword minimum (auto, min-content,
max-content, fit-content(...)) is kept as it is. Callers that already wrote
min(<width>, 100%) themselves are unaffected.

What else this changes: nothing else drawn (every story file captured before
and after, 1188 captures).

Stories, failing before: Collection · Narrow Container Keeps Its Items Inside
(cards 420px in a 342px box, Apply and Remove past it) and its phone story
(the favorites in a dialog on a phone).
Unit: __tests__/columnNeverWiderThanItsContainer.test.tsx (the minimum and
the rule fail before; the keywords are the case that does not change).
…e field out of view (qorus#646)

Root-caused by the Qorus IDE agent (David's round-7 review): in a short
window - a 1280x720 Storybook window's ~380px canvas, a phone in landscape -
a click into an editor opened no list at all.

A popover held below its target (keepPlacement) makes room by scrolling the
target's scroller by what the list lacks. A list taller than the window
scrolled the field from y=209 to y=-59: out of view, so Popper marked the
reference hidden, and the popover closed as it opened.

The field is now scrolled up at most to the top of what shows it (its
scroller, or the window where the scroller starts above it). What is still
missing is taken from the list's height (it is clamped to the room under the
field), or the list flips where that room is under a hundred pixels, as
before.

Stories (Form/RichTextEditor), both failing before (the list never opens):
- The List Opens In A Short Window: a field 200px down a scrolling page in a
  980x380 window, a list of twenty templates;
- The List Opens On A Phone In Landscape: the same on a touch screen at
  844x390, opened with a tap.
…pened level is the same list (qorus#646)

Found building the Qorus IDE's field picker, and in released reqore with
plain nested `items`.

The list of an opened level is drawn by the list of the level above it,
which kept its document key listener and its `passKeyHandler`. With the
focus outside the list - a text field or an editor it is opened from,
which keeps the focus - every key was handled by both levels: ↓ moved the
highlight in both, and Enter in the opened level also selected the row the
level above had highlighted ("Inner 1 | Plain" for one Enter). Only the
level the list shows now listens, and hands its controls to
`passKeyHandler`.

An opened level was also handed only some of the list's options, so it
dropped `filterRanking`, `filterPlaceholderBuilder`, `noItemsFoundText`,
`listId` and `passKeyHandler`: a list in German said "Search 2 items..."
and "No items found" one level down, ranked nothing, and its rows had no
ids for `aria-activedescendant`. It is handed them all now.

Stories (Form/Dropdown), both failing before:
- Only The Open Level Hears The Keys: a group opened from a text field
  that keeps the focus; ↓ Enter picks "Inner 1" only;
- An Opened Level Says And Ranks As The List Does: a German list ranked by
  relevance with a `listId`, opened at its group.
…as it (qorus#646)

Root-caused by the Qorus IDE agent from David's IDE round-1 review: a
checkbox with `wrapLabel` in less room than its box and its label on one
line - the IDE's "Skip totals rows" in a 38px row - kept its label on one
line, past the row.

`wrapLabel` only stopped the label's text from being kept on one line. The
label sits in two control groups (on either side of the box), and a group
that is not fluid is `flex: 0 0 auto`: it kept the width of the label's
one line, so there was never less room for the label to wrap in. The
checkbox was also exactly one line high, so a label that did wrap would
have run out of it.

With `wrapLabel` now:
- the groups the label is in shrink (`flex-shrink: 1; min-width: 0`);
- the checkbox is never wider than its container and shrinks in a row
  (`max-width: 100%`, `min-width: 0`, `flex: 0 1 auto` unless fluid or
  fixed);
- it is as high as its label, at least one line (`min-height`).
A checkbox whose label does not wrap is drawn as before.

Stories (Form/Checkbox), each failing before (the label runs to 338px or
632px in a 160px box, or past a 390px screen):
- A Long Label Wraps In A Narrow Box (beside one that does not wrap);
- A Long Label On The Left Wraps In A Narrow Box;
- A Three Line Label Makes The Checkbox As High (a checkbox and a switch);
- Long Labels Wrap On A Phone (touch, 390px; a tap on a wrapped label
  checks its box).
Unit: __tests__/checkboxWrapLabel.test.tsx; its three wrapping tests fail
before, and a checkbox that does not wrap keeps its height and width.
… saying what is missing (qorus#646)

DeepScan on #717 (NULL_POINTER, __tests__/stickyLayers.test.tsx:61): the
header row was asserted with `expect(row).toBeTruthy()` and then read
through `row!`, and each header cell's probe through `!` too. An assertion
that does not narrow the type leaves the next line reading a property of
what may be nothing.

`requiredElement(selector, what, parent)` and
`requiredAttribute(element, name)` (src/stories/utils/required.ts) return
what they find, or throw with what is missing. stickyLayers uses them for
every element and attribute it reads, and its header cells are told from
their row's children by `instanceof HTMLElement`, not a cast.

The same in round 11's own tests and stories, where a `!` or a cast read
an element that might not be there: checkboxWrapLabel.test, the Checkbox
stories' boxes and phone story, the Dropdown stories' search field, and
the RichTextEditor short-window stories' page, list and window.

Nothing drawn changes: the Checkbox, Dropdown and RichTextEditor
TemplateFieldUX story files pass as before (61 stories) with captures
identical to the last ones.
…s the same (qorus#646)

Found with DeepScan's REACT_INEFFICIENT_PURE_COMPONENT_PROP on #717 (a
table header cell's inline click handler for the memo ReqoreButton):
handing the button a stable handler did not stop it being drawn again,
because the stacked control group it is in handed it a new style object
on every render. A stacked group squares the corners that meet and tucks
each border under the one before, in a style it makes anew each time; it
was a prop that always changed, so a memo child - a button, a dropdown -
was drawn again with its group whatever else it was handed.

useCloneThroughFragments (the control group's, the button rail's and the
menu's) now keeps the style each child was last handed, by its place, and
hands it again while it has the same properties with the same values. What
is drawn does not change.

Unit: __tests__/controlGroupKeepsChildStyle.test.tsx - a memo child is not
drawn again when its group is (fails before), and is when its place in the
group changes its style (its corners rounded at the new end).
…s and objects while they are the same (qorus#646)

DeepScan on #717 (REACT_INEFFICIENT_PURE_COMPONENT_PROP,
src/components/Table/headerCell.tsx:430): the cell handed the memo
ReqoreButton a click handler made anew on every render, so the button was
drawn again each time the cell was - when another column was sorted, or
the cell moved - for nothing. Its effect object, and the menus'
(ReqoreDropdown is a memo too) handlers, input props, effect and button
style were made anew the same way.

Now:
- the click (⌘-click sorts, then the column's onClick) and the filter
  handler are useCallbacks of what they use;
- the menus' input props, the menu's effect (the filter's glow, the sorted
  column's gradient) and the button's effect are memos of what they are
  made of;
- whether a menu opens (not on a ⌘-click) and the ⋯'s style are module
  constants. A ⌘ check of an event that is not there no longer throws.
What is drawn does not change.

Unit: __tests__/tableHeaderCellKeepsItsControls.test.tsx - the header
cell's button, and its menu's, are not drawn again when another column is
sorted or the cell moves (both fail before, with the cell's handlers made
inline), and are when the cell's own column is sorted or it is handed
another click handler.
01ad747 read the sort direction in the menu effect's dependencies,
whatever the column: a table that does not sort hands its header cells no
sort data, and every such table threw "Cannot read properties of undefined
(reading 'direction')" (42 table unit tests). The cell now reads what it
is told of the sort only when it is told it: whether it is the column
sorted by, and its direction, both of sort data that may be absent.

Unit: tableHeaderCellKeepsItsControls - a cell with no sort data is drawn,
and drawn again (fails on 01ad747).
…f under its header, as it says (qorus#646)

Foxhoundn's qlip review of Panel · Sticky Header Above Its Body: the
story did not show what its description says. Its play measured each
row under the header by scrolling there and back (findDrawnOverStickyHeader
restores the scroll), so the frame was the panel unscrolled, with
nothing under the header.

The play now ends scrolled with the raised row's middle at the stuck
header's bottom edge, and checks that where they overlap the header is
what is drawn. The description says what the frame shows.
… it says (qorus#646)

Foxhoundn's qlip review of Breadcrumbs · Folded Trail Opens At A Tap:
the story did not show what its description says. Its play tapped each
fold open and then "Back to chats", which closes the menu, so the frame
was the two folded trails with no menu.

The play now ends by tapping the folded current crumb open again and
checking its menu: Workspace, "Back to chats" and the chat named in
full, the crumb saying it is expanded. The description says the story
ends there.
…tainer is a phone's width or narrower (qorus#646)

Foxhoundn's qlip review of Entity Row · No Wrap, Severity Row · Narrow
Container Actions Stack and Severity Row · Narrow Container Lone Action
In Menu Mode On A Phone: the lone action should fill the row's width,
the easiest target there is (Fitts's law), on a phone and in a tiny
container on a desktop; on a phone, a 'menu' row's lone action goes
under the text. David: one rule, keyed to the container's width, not
the screen's.

- In a container a phone's width or narrower (480px, Reqore's phone
  breakpoint, measured on the row's container), stacked actions and a
  lone action under the label are the row's width - on a phone, or in
  as narrow a container on any screen. In a wider container each is as
  wide as its label, as before. The rows asked the screen (isMobile)
  before; they ask the container now.
- A 'menu' row's lone action stays at the end of the label's line only
  while its container is wider than a phone; as narrow as a phone it
  goes under the label and spans the row (replacing ec7fff3/1e35fc08
  there). An entity row is narrow only at a phone's width, so its lone
  action is under the label wherever it is narrow; a severity row
  (narrow under 640px) keeps it at the line's end between 480 and
  640px, saying its shortLabel there.

useNarrowContainer reports both answers from one measurement (its
breakpoint, and the phone's width). The stories check widths against
the same measure (rowContainerIsPhoneWidth), and two new ones show a
container just wider than a phone keeping label width: Entity Row ·
Lone Action Keeps Its Width Just Wider Than A Phone (500px) and
Severity Row · Actions Keep Their Width Just Wider Than A Phone
(560px). Entity Row · Lone Action Spans The Row On A Phone shows the
default ('row') on a phone.

Fail-first: with the hook and both rows as before, the new unit cases
fail (3: rowActionShortLabel x2, SeverityRow x1), as do 6 Entity Row
stories and 3 Severity Row stories. Precheck: 153 files, 1758 tests.
…ere the keys went back (qorus#646)

09e1267 highlighted the row a level came from on any way back - also
after a click on the back button or on a crumb. To a pointer a
highlighted row looks picked: Dropdown · Back Buttons Work drew its
"Test child 3" in the intent's full fill after a click back, and
Items Can Be Traversed Via Tags its "Test" row. The highlight answers
the keys (Foxhoundn: can the arrow keys go on?), so only the left
arrow brings it back; a click back highlights nothing, as before.

The list's way back says whether the keys took it (_onBackClick(true)
from the left arrow; the back button has its own click handler).

Fail-first: dropdownBackHighlightsWhereItCameFrom "highlights nothing
after a click back" fails on 09e1267's list (the right arrow opened
Carrot); 3 of 3 pass. The Dropdown story file passes 32 of 32, its
frames as before but for Keyboard Navigation With Left Arrow Navigates
Back.
…shows, a lone action spanning the row with its full label (qorus#646)

Since 2f66642 an entity row is narrow only where its container is a
phone's width or narrower, and there its lone action goes under the
label, the row's width, saying its full label: it draws a short label
nowhere. Entity Row · Narrow Container Lone Action Short Label no
longer showed a short label. David: rename it to what it shows; short
labels stay covered by the severity-row and folded-column stories.

Entity Row · Narrow Container Lone Action Spans The Row With Its Full
Label: the same three rows in a 720px and a 400px container. Its play
now also checks that each action in the 720px container is at the end
of the row, beside the label, as wide as its label, and that the first
action has a short label it does not say.

Fail-first: with the rows' sources of 0820cbf the story fails (the
action at the end of the label's line, 310 < 329.5); with 2f66642 the
EntityRow story file passes 35 of 35, and the renamed story's frame is
the old story's, pixel for pixel.
davidnich added a commit that referenced this pull request Oct 21, 2026
… (qorus#646)

The functional PR's answers to the 8 rejections on its qlip build #410:
the dropdown's way back highlights the row it came from, a list never
runs off the screen, the panel and folded-trail stories end on what
they say, and a lone or stacked row action spans its row where the
row's container is a phone's width or narrower. Merged, not rebased:
this PR is open. Two conflicts, both this branch's re-indentation of a
block the functional branch changed (EntityRow's actions, the popover's
surface): this branch's version, with the functional change made in
it.
davidnich added a commit that referenced this pull request Oct 21, 2026
@davidnich

Copy link
Copy Markdown
Member Author

Foxhoundn's 8 rejections on qlip build #410, each fixed, pushed in ccf1c85 with develop merged in (#721, #720) and the version at 0.78.10. Each rejected frame also has this answer as a comment in qlip. The new frames are on qlip build #412; every changed and new frame there is flagged with its cause, none accepted.

  • Entity Row · No Wrap → new frame (identical to develop's baseline (0.00% diff), so qlip passed it), story. Cause: The lone Run action was as wide as its label in a 360px column on a desktop: the rows asked the screen (isMobile), not the container, whether to span the row. Fix (2f666426): David's rule: a lone action, and stacked actions, span the row where the row's container is a phone's width (480px) or narrower - on a phone, or in as narrow a container on a desktop - measured on the container, not the screen; in a wider container each is as wide as its label. A 360px column is a phone's width or narrower, so both Run buttons span their row.
  • Severity Row · Narrow Container Actions Stack → new frame (identical to develop's baseline (0.00% diff), so qlip passed it), story. Cause: The stacked actions were as wide as their labels in a 320px container on a desktop, for the same reason. Fix (2f666426): David's rule: a lone action, and stacked actions, span the row where the row's container is a phone's width (480px) or narrower - on a phone, or in as narrow a container on a desktop - measured on the container, not the screen; in a wider container each is as wide as its label. See your subscription and Try again each span the row.
  • Severity Row · Narrow Container Lone Action In Menu Mode On A Phone → new frame (flagged for review, not accepted), story. Cause: A 'menu'-mode row kept its lone action at the end of the label's line on a phone (ec7fff3/1e35fc08). Fix (2f666426): At a phone's width it now goes under the text and spans the row; a 'menu' row's lone action stays at the end of the label's line only while its container is wider than a phone.
  • Dropdown · Keyboard Navigation With Left Arrow Navigates Back → new frame (identical to develop's baseline (0.00% diff), so qlip passed it), story. Cause: Back at a level with ←, no row was highlighted, so → could not open the submenu again: the right arrow had cleared the highlight (develop showed one only because the parent level also heard the sublevel's keys). Fix (09e12671, 1d133cbb): Going back by the keys highlights the row the level came from, so → reopens it; a click back highlights nothing, as before (1d133cb narrows it to the keys).
  • RichTextEditor · The List Opens In A Short Window → new frame (flagged for review, not accepted), story. Cause: The list ran off the window. Two popover bugs: the height cap was on the popover's surface only, and the list inside drew past it (382px in a 297px surface); and the cap was set once, at opening, so a resize left it stale. The stories measured the surface, so they passed. Fix (7b71340e): What a popover draws stays inside its cap and scrolls there, and the cap follows the room left (window and visual-viewport resize and scroll, the field's size; event-driven, at most once a frame). The stories now measure what is drawn.
  • RichTextEditor · The List Opens On A Phone In Landscape → new frame (flagged for review, not accepted), story. Cause: The same two popover bugs as The List Opens In A Short Window. Fix (7b71340e): The same fix: the list stays inside the window at 844×390, its rows scrolling.
  • Panel · Sticky Header Above Its Body → new frame (flagged for review, not accepted), story. Cause: The play scrolled to measure and scrolled back, so the frame showed the panel unscrolled. Fix (2268fe45): The play ends scrolled, the raised row half under the stuck header, as its description says.
  • Breadcrumbs · Folded Trail Opens At A Tap → new frame (flagged for review, not accepted), story. Cause: The play ended after choosing "Back to chats", which closes the menu. Fix (0820cbfc): The play ends with the folded crumb's menu open: Workspace, Back to chats, the chat named in full.

davidnich added a commit that referenced this pull request Oct 21, 2026
Every outstanding PR takes develop's next version (develop is 0.78.9), so
#723 is 0.78.10, as #722 is. Whichever merges second merges develop and
bumps again only if its version is then on npm.
…nd only its rows scroll (qorus#646)

Foxhoundn on qlip build #412 (RichTextEditor · The List Opens In A Short
Window, and On A Phone In Landscape): "Where is the bottom border of the
popover? It still seems its being cut off."

7b71340 held what a capped popover draws inside its cap by scrolling the
whole surface. The Dropdown's panel inside stayed as tall as before: at
980x380 the surface is 297px (y 63 to 360) and the panel 382px, its
bottom border at y 445, scrolled out of sight under the surface's edge,
and its rows scrolled inside that again: two scroll areas.

- A capped surface is a column that holds what can scroll its own
  content - a panel (its body scrolls) or a menu - to the cap: it shrinks
  to it and keeps its whole frame. Anything else keeps its height, and
  the surface scrolls it, as before.
- The Dropdown's panel lays its body out as a column, and the list may
  shrink in it (min-height 0), so its rows, the menu, take the room its
  search and tags leave. Only the rows scroll.

Measured after: the panel is 63 to 360, its body 295px with nothing to
scroll, the rows 215px scrolling 775px.

Fail-first: both list stories now check that the panel's whole frame,
bottom border included, is inside the surface and the window, and that
one place scrolls, the rows. Before: "expected 445 to be less than or
equal to 360.5" (and 370.5 in landscape). After: the TemplateFieldUX
file passes 13 of 13.
…e by side, stacking only at a phone's width (qorus#646)

Foxhoundn on qlip build #412 (Severity Row · Actions Keep Their Width Just
Wider Than A Phone): "These should be rendered next to each other, while
keeping their widths - law of proximity. They should only fold under one
another on phone / very narrow container size." David: side by side,
wrapping if needed.

A severity row is narrow below 640px of its container, and its default
narrowActions='stack' put its actions one to a line anywhere there. Now
'stack' stacks them, each the row's width, only where the container is a
phone's width or narrower (480px). Wider, they sit side by side under the
label, each as wide as its label, onto another line only where they do
not fit, as with 'row' (data-actions='row'). An entity row is narrow only
at a phone's width, so it does not change.

Docs: SeverityRow's narrowActions, TReqoreNarrowRowActions, COMPONENTS.md
(and the rows' container rule there is 0.78.10, the version #722 ships
as, not 0.78.9).

Fail-first:
- SeverityRow unit: the default and 'stack' at 600px are side by side
  ('row') and at 480px stacked; one action at 600px is in a row in every
  mode but 'menu'. 2 of 2 fail before.
- Severity Row · Actions Keep Their Width Just Wider Than A Phone: a 560px
  box with two actions on one line, a 500px box whose three actions wrap
  onto two lines, each as wide as its label, and a 480px box stacked, each
  the row's width. Before: "expected 'stack' to be 'row'".
After: SeverityRow unit 35 of 35; the SeverityRow story file 28 of 28.
…r wraps it (qorus#646)

2f66642 left loneActionAtLineEnd on one 98-character line in EntityRow and
SeverityRow; prettier wraps it. Formatting only: the deviation counts are
back to 204dfc7's (21 and 30).
…, so a short label or a label is never cut to "T…" (qorus#646)

A narrow table folded its actions column to the menu button's square
(38px), whatever its cells drew. That suits a menu or an icon, not
words: a row's one action with no icon says its short label there
(2610960), and "Test" was cut to "T…" - the cell's text read "Test"
while the screen showed one letter, so the unit test that read the text
passed. An action with no icon and no short label was cut the same way
("Test the connection" to "T…") since the fold began.

David: a folded column is as wide as what its cells draw, never wider
than unfolded - the square for a menu or an icon, an action's words
whole in their button: its short label, or its full label where it has
none, even if the column barely narrows.

- getFoldedActionText: what a folded cell says, as the row draws it -
  nothing for a menu or an icon, else the short label or the label.
- useFoldedActionWidths: over the table's rows (so the width holds as
  they scroll and page), each folded column's distinct words, measured
  with the browser's text metrics (canvas measureText, as useFitTextSize
  does) in the font of a button drawn as the cell draws it, plus what
  that button draws around its words (padding, border, spacers). The
  button is a probe out of sight in a box of no size that clips it, so
  it never reaches past the table or makes anything scroll. Measured
  again when the words change and on document.fonts "loadingdone" (no
  polling). Words that cannot be measured (an element, no canvas) keep
  the column its width.
- foldActionsColumns takes the widths: the square at least, never wider
  than the column was, plus a padded cell's padding.
- hasRowActionLabel moves to a module of its own (re-exported as
  before), so the table's helpers use it without loading the menu's
  components (an import cycle through Dropdown and Paging).

Docs: the cell.actions and actionsMenuBelowWidth props, COMPONENTS.md.

Tests, failing first with the table's sources of 9ca09c1:
- rowActionShortLabel: the rendered cell width against the measured
  words (7px a character, 18px around them): 4 of 6 fail before (a short
  label, a full label, the cap at the column's width, words that cannot
  be measured); an icon in the square and a wide table pass, as before.
- helpers/table: getFoldedActionText, getFoldedActionTexts and the
  folded widths (the square, the cap, Infinity, padding).
- Stories Collections/Table · Folded Column Says The Short Label and
  Folded Column Says The Full Label Without A Short Label, at 720, 480
  and 265px: the words whole and in sight inside their button, not cut
  to an ellipsis, in a column no wider than they need; their label the
  accessible name (and the tooltip of a short label); a click runs it.
  Both fail before (the text 27px in 20, and 131px in 20).
Foxhoundn
Foxhoundn previously approved these changes Oct 21, 2026
…a memoised group, and plays read the page through requiredElement (qorus#646)

DeepScan on 1a95b75: 1 new issue. Its dashboard needs a login, so the
new code since ccf1c85 was read for its rule set:

- SeverityRow: actionsStacked ended in "&& !loneActionAtLineEnd", which
  is always true there - it already requires isPhoneWidth, and a lone
  action is at the line's end only while the container is wider than a
  phone (CONSTANT_CONDITION). The clause is gone; nothing changes.
- Dropdown list: the style handed to its memoised control group was a
  new object on every render (REACT_INEFFICIENT_PURE_COMPONENT_PROP); it
  is one module constant now.
- Table helpers: getFoldedActionText indexed actions[0] after an
  optional chain; it destructures the one action instead.
- The new Table and Severity Row plays read their boxes through
  requiredElement instead of a non-null assertion or a cast
  (NULL_POINTER), as the rest of the stories do.

No visual or behaviour change: precheck 153 files / 1769 tests; the
Table, SeverityRow, TemplateFieldUX, Dropdown and EntityRow story files
pass 182 of 182 and their 180 captures equal 1a95b75's.
@davidnich

Copy link
Copy Markdown
Member Author

Foxhoundn's 3 rejections on qlip build #412, each fixed (pushed in 1a95b75; the frames are on qlip build #413, approved by David). Each rejected frame also has this answer in qlip.

  • Severity Row · Actions Keep Their Width Just Wider Than A Phone → fixed frame, story. Cause: a severity row's default narrowActions='stack' put its actions one to a line anywhere under 640px, so in a 560px box they were stacked although they fit side by side. Fix (dc95bbe5): David: side by side, wrapping if needed. 'stack' now stacks them, each the row's width, only at a phone's width (480px) or narrower; wider, they sit side by side under the label, each as wide as its label, wrapping only when they do not fit. The story shows a 560px box (side by side), a 500px box with three actions (the third wraps) and a 480px box (stacked).
  • RichTextEditor · The List Opens In A Short Window → fixed frame, story. Cause: the height cap (7b71340) scrolled the popover's whole content: the list's panel stayed 382px tall in a 297px surface, its bottom border at y 445 out of sight under the edge at 360, and its rows scrolled inside that again. Fix (0f63e565): A capped surface holds what can scroll its own content (a panel, a menu) to the cap, so the panel keeps its whole frame, bottom border included; in the Dropdown list the rows take the room under the search and tags, so only the rows scroll. The play checks the frame is inside the surface and the window, and that one place scrolls.
  • RichTextEditor · The List Opens On A Phone In Landscape → fixed frame, story. Cause: the same as The List Opens In A Short Window (the bottom border at 445 against the edge at 370). Fix (0f63e565): The same fix, at 844x390.

@davidnich
davidnich requested a review from Foxhoundn October 21, 2026 14:00
@davidnich
davidnich merged commit 9c340d9 into develop Oct 21, 2026
7 checks passed
@davidnich
davidnich deleted the bugfix/qorus646-functional branch October 21, 2026 14:21
davidnich added a commit that referenced this pull request Oct 21, 2026
develop is at 0.78.10 (#722, published), so #723 takes the next version.
davidnich added a commit to qoretechnologies/toolkit-react that referenced this pull request Oct 21, 2026
… on its row again, as reqore keeps them in sight (qorus#646)

21d2718 moved reqraft to reqore 0.78.5, where a row narrower than 480px
folded two or more actions into one "Actions" menu, and the experiment
card's stories opened that menu to read Show analytics, Accept and
Remove. reqore 0.78.9 (qoretechnologies/reqore#722) keeps a narrow row's
actions in sight by default (narrowActions='row'), which answers
Foxhoundn's qlip rejections of those frames, so the stories and their
descriptions go back to what they were before 21d2718: each version's
actions are buttons on its row.
davidnich added a commit to qoretechnologies/toolkit-react that referenced this pull request Oct 21, 2026
…m button by the name reqore gives it (qorus#646)

reqore 0.78.9 (qoretechnologies/reqore#722) names an icon-only button by
its string tooltip, so the compact field's confirm button (the + icon,
tooltip "Add item") is now a button called "Add item". Compact Empty
asserted that no button had that name, which was only true while the
confirm button had no name at all. Its intent is that the disabled
confirm button is the one way to add an item: the play now checks that
it is the only button called "Add item", and that it is disabled.

Fail-first: with reqore 0.78.9-pr.722.g204dfc7 the old play fails
("expected document not to contain element, found <button
aria-label="Add item" ...>"); the story file passes 9 of 9 with this one,
its captures unchanged.
davidnich added a commit that referenced this pull request Oct 24, 2026
…se they shipped in (qorus#646)

0.78.7 was never published (npm has 0.78.6, then 0.78.8). Fourteen
labels in COMPONENTS.md named it: the button's width cap, the checkbox's
wrapLabel, the columns' and the collection's width caps, the wrapped
control group's child cap, the dropdown's opened level, the entity and
severity rows' narrow actions and end-of-line action, the row actions'
shortLabel, the panel's sticky header, and the table's pinned header
cell. Each
was introduced by a commit of #722, whose merge into develop (9c340d9)
published 0.78.10, the first release that holds them (found with
`git log -S` on each label and the first develop merge containing it).

The pinned header cell's sentence also says what #723 adds: it paints
what the header row is drawn on and hands that on (0.78.13).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants