Skip to content

feat(ui): Add RowList compound component#13

Merged
joshuapare merged 6 commits into
mainfrom
feat/row-list
Mar 8, 2026
Merged

feat(ui): Add RowList compound component#13
joshuapare merged 6 commits into
mainfrom
feat/row-list

Conversation

@joshuapare
Copy link
Copy Markdown
Contributor

@joshuapare joshuapare commented Mar 8, 2026

Summary

  • Adds RowList compound component — a tabular list with structured columns, lighter than a full DataTable
  • Uses CSS Grid driven by a columns prop for aligned header + row layout with a shared --_ov-row-grid-columns variable
  • Visual-only sort indicators (ascending/descending) with onSortChange callback — consumer owns data sorting
  • Wraps List.Root foundation, inheriting selection (single/multiple), keyboard navigation, density variants, and disabled state

Compound Slots

RowList (Root), Header, Viewport, Item, Cell, Group, GroupHeader, Separator, Empty, Loading

Test plan

  • 13 unit tests covering headers, grid positions, sort indicators, sort toggling, non-sortable headers, cell alignment, row selection, keyboard nav, disabled state, density, grid template variable, and sticky header
  • pnpm typecheck passes
  • pnpm test — all 331 tests pass
  • Verify Storybook Lists/RowList section renders all 8 stories (BasicColumns, WithSorting, SingleSelect, MultiSelect, DensityVariants, ProblemsPanel, DisabledRows, LargeList)
  • Manual: columns align between header and rows, sticky header works on scroll

Summary by CodeRabbit

  • New Features
    • RowList: a compound component for tabular/row-based data with configurable columns, sorting, selection modes, density variants, keyboard navigation, alignment, column widths, disabled rows, sticky headers, and icons.
  • Documentation
    • Comprehensive Storybook examples demonstrating usage, sorting, selection, densities, disabled rows, and large lists.
  • Style
    • New grid-based styling and layout for row lists, headers, cells, and sort indicators.
  • Tests
    • Extensive unit and interaction tests covering rendering, sorting, selection, keyboard navigation, density, and accessibility.
  • Chores
    • Public exports updated to expose RowList and its types; components index re-export updated.

Implements RowList — a structured column list lighter than a full DataTable.
Uses CSS Grid driven by column definitions for aligned header + row layout,
with visual-only sort indicators and full List foundation support (selection,
keyboard nav, density variants).
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 8, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new RowList component (implementation, types, CSS, tests, and Storybook stories), exports it from the row-list package, and re-exports it from the main components index.

Changes

Cohort / File(s) Summary
Type definitions
packages/base-ui/src/components/row-list/types.ts
Adds SortDirection, ColumnDef, SortState, RowListRootProps, RowListItemProps, RowListCellProps, RowListHeaderProps to define the RowList public API.
Component implementation
packages/base-ui/src/components/row-list/RowList.tsx
Adds the RowList compound component (Root, Header, Viewport, Item, Cell, Group, GroupHeader, Separator, Empty, Loading) with context, column map, CSS-var grid-template handling, sorting interactions, and alignment support.
Styling
packages/base-ui/src/components/row-list/RowList.module.css
Adds CSS module for grid layout, sticky header, header/cell typography, sortable states and sort icon styling, item/cell grid positioning, alignment, and padding.
Public exports
packages/base-ui/src/components/row-list/index.ts, packages/base-ui/src/components/index.ts
Re-exports RowList and its types from the row-list package and adds export * from './row-list' to the main components index.
Stories
packages/base-ui/src/components/row-list/RowList.stories.tsx
Adds Storybook stories demonstrating BasicColumns, WithSorting, SingleSelect, MultiSelect, DensityVariants, ProblemsPanel, DisabledRows, and LargeList examples.
Tests
packages/base-ui/src/components/row-list/RowList.test.tsx
Adds tests covering rendering, header cells, sorting interactions, selection modes, keyboard navigation, disabled rows, density attribute, column widths, and header stickiness.

Sequence Diagram

sequenceDiagram
    autonumber
    actor User
    participant Header as "RowListHeader"
    participant Context as "RowListContext"
    participant Parent as "ParentComponent"
    participant Root as "RowListRoot"

    User->>Header: click sortable header cell
    Header->>Context: read current sortState
    Header->>Header: compute next sort direction
    Header->>Parent: call onSortChange(newSortState)
    Parent->>Parent: update sortState prop
    Parent->>Root: re-render with updated props
    Root->>Context: provide updated sortState
    Context->>Header: Header receives updated sortState and updates aria-sort
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped a row and found a list,
Columns neat and headers kissed,
Arrows twirl when sorts delight,
Sticky tops that hold on tight,
I nibble bugs — code looks bliss! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(ui): Add RowList compound component' clearly and specifically describes the main change—introducing a new RowList compound component to the UI package.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/row-list

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/base-ui/src/components/row-list/RowList.stories.tsx`:
- Around line 322-328: The large-list story uses Math.random() to generate the
duration in the largeData array, causing non-deterministic renders; update the
duration generation in the largeData constant so it is derived deterministically
from the index (i) instead (for example use a function of i like (i * 7) % 120
or i % 120) so each entry's duration is stable across runs—modify the largeData
definition (the duration field) to use a deterministic computation instead of
Math.random().
- Around line 91-124: The render callback for WithSorting currently calls
useState (sortState/setSortState) which violates rules-of-hooks; extract that
logic into a capitalized React component (e.g., WithSortingComponent or
WithSortingStory) that accepts the same props (spread args) and contains the
useState<SortState> hook, the sorted computation, and returns the RowList JSX
using sortState and setSortState (passed to RowList via sortState and
onSortChange). Then change WithSorting.render to simply return
<WithSortingComponent {...args} /> (preserving style width and other props) so
hooks run inside a proper component.

In `@packages/base-ui/src/components/row-list/types.ts`:
- Line 41: Replace the empty interface declaration "RowListHeaderProps" with a
type alias to avoid the empty-object lint rule: change the export from an empty
interface to a type alias using HTMLAttributes<HTMLDivElement> (i.e., export
type RowListHeaderProps = HTMLAttributes<HTMLDivElement>), and ensure any
imports/usages of RowListHeaderProps remain valid.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 18860584-59b9-428f-acb0-0f04c0afab3a

📥 Commits

Reviewing files that changed from the base of the PR and between 6043989 and 895714d.

📒 Files selected for processing (7)
  • packages/base-ui/src/components/index.ts
  • packages/base-ui/src/components/row-list/RowList.module.css
  • packages/base-ui/src/components/row-list/RowList.stories.tsx
  • packages/base-ui/src/components/row-list/RowList.test.tsx
  • packages/base-ui/src/components/row-list/RowList.tsx
  • packages/base-ui/src/components/row-list/index.ts
  • packages/base-ui/src/components/row-list/types.ts

Comment thread packages/base-ui/src/components/row-list/RowList.stories.tsx Outdated
Comment thread packages/base-ui/src/components/row-list/RowList.stories.tsx
Comment thread packages/base-ui/src/components/row-list/types.ts Outdated
- Extract WithSorting render into a proper component to fix hooks violation
- Use deterministic duration generation instead of Math.random()
- Replace empty RowListHeaderProps interface with type alias
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/base-ui/src/components/row-list/RowList.stories.tsx`:
- Around line 209-213: The stories for DensityVariants and ProblemsPanel pass
density explicitly to RowList but then spread meta.args (which sets density:
'default') after {...args}, causing the explicit density to be overridden; fix
by ensuring explicit props win—move {...args} before the explicit density prop
or remove density from meta.args in those stories so RowList receives the
intended density; update the RowList usage in the DensityVariants and
ProblemsPanel story definitions (and the repeated block around the other
occurrence) to place {...args} before density or strip density from meta.args.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: d7e43227-a2a2-460c-83a2-e2d84ac4d04b

📥 Commits

Reviewing files that changed from the base of the PR and between 895714d and f8bbea2.

📒 Files selected for processing (2)
  • packages/base-ui/src/components/row-list/RowList.stories.tsx
  • packages/base-ui/src/components/row-list/types.ts

Comment thread packages/base-ui/src/components/row-list/RowList.stories.tsx
… stories

Move {...args} spread before explicit density prop in DensityVariants
and ProblemsPanel stories so the intended density value wins.
…ignment

List.Item applies padding-inline on the outer element, which shifts the
grid inward relative to the Header row. Reset to 0 since each Cell
already applies its own padding-inline, matching the header cells.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/base-ui/src/components/row-list/RowList.module.css`:
- Around line 22-35: .HeaderCell is missing min-width: 0 which prevents grid
items from shrinking and stops text-overflow: ellipsis from working; update the
.HeaderCell rule to include "min-width: 0" (same approach used in .Cell) so long
header labels can truncate properly while keeping existing display, padding, and
overflow rules.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 204c654e-377b-440e-aa90-ad65de712011

📥 Commits

Reviewing files that changed from the base of the PR and between db3c04e and 13f3e16.

📒 Files selected for processing (1)
  • packages/base-ui/src/components/row-list/RowList.module.css

Comment thread packages/base-ui/src/components/row-list/RowList.module.css
…lity

- Reset inherited gap from List.Item so row columns align with header
- Add muted text color on disabled rows to make them clearly
  distinguishable alongside the base opacity treatment
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
packages/base-ui/src/components/row-list/RowList.module.css (1)

22-35: ⚠️ Potential issue | 🟡 Minor

Missing min-width: 0 prevents text truncation in header cells.

.HeaderCell is missing min-width: 0, while .Cell (line 77) correctly includes it. Without this, grid items default to min-width: auto, preventing them from shrinking below their content size. Long header labels won't trigger text-overflow: ellipsis—the cell will overflow its grid column instead.

🔧 Proposed fix
 .HeaderCell {
   display: flex;
   align-items: center;
   gap: var(--ov-space-inline-xs, 4px);
+  min-width: 0;
   min-height: var(--_ov-item-height);
   padding-inline: var(--_ov-item-padding-inline);
   font-size: var(--ov-font-size-caption);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/base-ui/src/components/row-list/RowList.module.css` around lines 22
- 35, .HeaderCell is missing min-width: 0 which prevents grid items from
shrinking and stops text-overflow: ellipsis from working; update the .HeaderCell
rule (alongside existing .Cell behavior) to include min-width: 0 so long header
labels can truncate correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/base-ui/src/components/row-list/RowList.module.css`:
- Around line 22-35: .HeaderCell is missing min-width: 0 which prevents grid
items from shrinking and stops text-overflow: ellipsis from working; update the
.HeaderCell rule (alongside existing .Cell behavior) to include min-width: 0 so
long header labels can truncate correctly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6ebb1fd6-3a97-4b66-ab38-cf94516f8273

📥 Commits

Reviewing files that changed from the base of the PR and between 13f3e16 and be9ed46.

📒 Files selected for processing (1)
  • packages/base-ui/src/components/row-list/RowList.module.css

Without min-width: 0, grid items won't shrink below content size,
preventing text-overflow: ellipsis from working on long header labels.
@joshuapare joshuapare merged commit d9aba1e into main Mar 8, 2026
1 check passed
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.

1 participant