Skip to content

feat(a2ui): support Tabs#2649

Merged
HuJean merged 2 commits into
mainfrom
p/a2ui-tabs
May 15, 2026
Merged

feat(a2ui): support Tabs#2649
HuJean merged 2 commits into
mainfrom
p/a2ui-tabs

Conversation

@HuJean
Copy link
Copy Markdown
Collaborator

@HuJean HuJean commented May 15, 2026

Summary by CodeRabbit

  • New Features

    • Added a new Tabs component to the catalog with full styling and theme support
    • Tabs component now available in the playground
  • Documentation

    • Updated README to reflect newly available built-in catalog components
  • Chores

    • Updated theme token overrides for improved theming consistency
    • Enhanced CSS styling for better component presentation

Review Change Stack

Checklist

  • Tests updated (or not required).
  • Documentation updated (or not required).
  • Changeset added, and when a BREAKING CHANGE occurs, it needs to be clearly marked (or not required).

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 15, 2026

🦋 Changeset detected

Latest commit: 52e7c08

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 15, 2026

📝 Walkthrough

Walkthrough

This PR introduces a new Tabs catalog component to the A2UI library with state-managed tab selection and nested component rendering. It integrates Tabs into the playground, enhances type inference for array schema properties, migrates Button and Icon CSS to dedicated theme tokens, and updates supporting documentation and tests.

Changes

Tabs Component & Design System Updates

Layer / File(s) Summary
Tabs component implementation and styling
packages/genui/a2ui/src/catalog/Tabs/index.tsx, packages/genui/a2ui/styles/catalog/Tabs.css
Introduces TabsProps interface with tabs array (title and child component id), local TabsHeader and TabsContent helper components, and main Tabs component that manages active tab index state, clamps selection, renders tab headers with click handlers, resolves and renders active child via NodeRenderer, and returns empty view when tabs list is empty. Complete stylesheet defines container, header row with scroll and border, individual tab styling with active-state color/shadow, and content padding.
Tabs module and package exports
packages/genui/a2ui/src/catalog/index.ts, packages/genui/a2ui/src/index.ts, packages/genui/a2ui/package.json
Re-exports Tabs from catalog module and main library entry; adds subpath exports in package.json for ./catalog/Tabs (TypeScript types and JS entry) and ./catalog/Tabs/catalog.json asset under ./dist/catalog/Tabs/.
Playground app registration and theme classes
packages/genui/a2ui-playground/lynx-src/a2ui/App.tsx
Imports Tabs component and tabsManifest, registers manifestEntry(Tabs, tabsManifest) in ALL_BUILTINS array, and updates themeClassName construction to apply both luna theme class (luna-dark/luna-light) and a2ui override class (a2ui-dark/a2ui-light) simultaneously.
Array type inference enhancement and Tabs catalog entry
packages/genui/a2ui-playground/src/catalog/a2ui.ts
Expands inferType function to derive specific array element types from JSON schema items (including object properties with recursion), replacing generic string[] behavior; adds Tabs to COMPONENT_CATALOG with manifest-derived props, usage description, and usage examples.
Theme token updates for Button, Icon, and root layout
packages/genui/a2ui-playground/lynx-src/a2ui/index.css, packages/genui/a2ui/styles/catalog/Button.css, packages/genui/a2ui/styles/catalog/Icon.css
Updates :root to define flex-column layout, 10px padding, border-box sizing, and explicit background/text colors; refactors A2UI spacing (xs/s/m/l/xl) and font-size (xs/s/l/xl/2xl) tokens from calc()-based derivations to fixed rem values; changes token scope selector from .luna-light, .luna-dark to .a2ui-light, .a2ui-dark; migrates .button styling to --a2ui-button-* tokens (border, background, foreground) and .button-primary to --a2ui-button-primary-*; updates .a2ui-icon and color variant classes to use icon-specific --a2ui-icon-* variables.
Documentation and test coverage
packages/genui/a2ui/README.md, packages/genui/a2ui/src/catalog/README.md, packages/genui/a2ui/test/catalog.test.ts, .changeset/tabs-catalog-and-playground.md
Updates README to list Divider, Icon, and Tabs as built-ins; expands catalog README's all-builtins recipe snippet to include Icon and Tabs with corresponding manifest imports and defineCatalog array entries; adds ICON_MANIFEST and TABS_MANIFEST test fixtures (including nested tabs array schema) and extends recipe test to validate ['Text','Button','Icon','Tabs'] component ordering; creates changesets entry for patch bump.

🎯 4 (Complex) | ⏱️ ~45 minutes


Possibly Related PRs

  • lynx-family/lynx-stack#2618: Shares modified catalog type inference logic in packages/genui/a2ui-playground/src/catalog/a2ui.ts for the array type handling that improved Tabs prop documentation display.

Suggested Reviewers

  • PupilTong
  • Sherry-hue
  • gaoachao
  • fzx2666-fz

🐰 A curious rabbit hops through the code,
Where Tabs now dance in state-managed mode,
Theme tokens unified, Button and Icon aligned,
Array types inferred, schemas redesigned—
A tidy refactor, both feature and polish combined!

🚥 Pre-merge checks | ✅ 4 | ❌ 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 (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: adding Tabs component support to the a2ui package. It is concise, specific, and directly reflects the primary objective shown across all file modifications.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch p/a2ui-tabs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@codecov
Copy link
Copy Markdown

codecov Bot commented May 15, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

@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

🧹 Nitpick comments (3)
packages/genui/a2ui/styles/catalog/Icon.css (1)

14-14: ⚡ Quick win

Add fallback token mapping for icon colors.

Using icon-specific vars is good, but keep fallbacks so icons remain visible in themes that only provide base text tokens.

♻️ Proposed fallback-safe icon colors
 .a2ui-icon {
@@
-  color: var(--a2ui-icon-color);
+  color: var(--a2ui-icon-color, var(--a2ui-color-text));
 }
@@
 .a2ui-icon-color-primary {
-  color: var(--a2ui-icon-color-primary);
+  color: var(--a2ui-icon-color-primary, var(--a2ui-color-primary));
 }
@@
 .a2ui-icon-color-muted {
-  color: var(--a2ui-icon-color-muted);
+  color: var(--a2ui-icon-color-muted, var(--a2ui-color-text-muted));
 }

Also applies to: 30-30, 34-34

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/genui/a2ui/styles/catalog/Icon.css` at line 14, The icon color
declarations use only the icon-specific token var(--a2ui-icon-color) and need
fallback tokens so icons remain visible when themes only define base text
tokens; update each occurrence (including the rule containing "color:
var(--a2ui-icon-color);" and the other instances noted) to use a CSS var
fallback chain such as var(--a2ui-icon-color, var(--a2ui-text-color,
currentColor)) so the icon falls back to the base text token and finally to
currentColor.
packages/genui/a2ui/styles/catalog/Button.css (1)

11-15: ⚡ Quick win

Add fallback token chain for button styles.

The new button-specific vars should fall back to base A2UI vars to avoid empty/invalid styling when component vars are not provided by a theme.

♻️ Proposed resilient fallback mapping
 .button {
@@
-  border: var(--a2ui-button-border);
+  border: var(--a2ui-button-border, var(--a2ui-border));
@@
-  background: var(--a2ui-button-background);
+  background: var(--a2ui-button-background, var(--a2ui-color-surface));
@@
-  color: var(--a2ui-button-foreground);
+  color: var(--a2ui-button-foreground, var(--a2ui-color-on-secondary));
 }
@@
 .button-primary {
-  background-color: var(--a2ui-button-primary-background);
+  background-color: var(--a2ui-button-primary-background, var(--a2ui-color-primary));
   border: none;
-  color: var(--a2ui-button-primary-foreground);
+  color: var(--a2ui-button-primary-foreground, var(--a2ui-color-on-primary));
 }

Also applies to: 28-30

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/genui/a2ui/styles/catalog/Button.css` around lines 11 - 15, The
button CSS uses component-specific custom properties without fallbacks; update
each use of --a2ui-button-* in Button.css to fall back to the base A2UI tokens
(e.g., make --a2ui-button-border fall back to --a2ui-border,
--a2ui-button-border-radius fall back to --a2ui-border-radius,
--a2ui-button-background fall back to --a2ui-background, and
--a2ui-button-foreground fall back to --a2ui-foreground) so themes that only
provide base tokens still style buttons; apply the same fallback pattern to the
other occurrences referenced (lines 28–30).
packages/genui/a2ui/test/catalog.test.ts (1)

147-163: ⚖️ Poor tradeoff

Test scope doesn't match the documented recipe.

The test comment claims to be a "snapshot of the recipe documented in README.md," but it only includes 4 of the 12 components shown in the README's allBuiltins example (Text, Button, Icon, Tabs vs. Text, Image, Row, Column, List, Card, Button, Divider, CheckBox, Icon, RadioGroup, Tabs).

Consider either:

  1. Preferred: Expand the test to include all 12 components from the README recipe to ensure they stay in sync, or
  2. Update the test description and comment to clarify this is testing a minimal subset, not the full recipe

This will prevent drift between the documentation and test coverage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/genui/a2ui/test/catalog.test.ts` around lines 147 - 163, The test
"paste-able recipe builds the expected manifest" currently constructs
defineCatalog with only [Text, Button, Icon, Tabs] but the README's recipe uses
allBuiltins (Text, Image, Row, Column, List, Card, Button, Divider, CheckBox,
Icon, RadioGroup, Tabs); update the test to include the missing manifests (e.g.
IMAGE_MANIFEST, ROW_MANIFEST, COLUMN_MANIFEST, LIST_MANIFEST, CARD_MANIFEST,
DIVIDER_MANIFEST, CHECKBOX_MANIFEST, RADIOGROUP_MANIFEST) when calling
defineCatalog and update the expected manifest.components.map(... ) array to
list all 12 names, or if you prefer the minimal-subset approach, change the test
description/comment to explicitly state it verifies a minimal subset (and keep
the four-item catalog) so the README and test intent no longer conflict.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/genui/a2ui-playground/src/catalog/a2ui.ts`:
- Around line 55-65: The code that builds array types in the prop.type ===
'array' branch can produce incorrect precedence like "A | B[]"; modify the block
where you return `${inferType(items)}[]` so that you parenthesize the item type
when it can be a union: if items has oneOf/anyOf (or if the inferred string
contains '|' or '&' indicating a composite type), return
`(${inferType(items)})[]` instead of `${inferType(items)}[]`; keep the existing
branches for object items and unknown[] unchanged and reference the inferType
function and the local items variable when implementing this check.

---

Nitpick comments:
In `@packages/genui/a2ui/styles/catalog/Button.css`:
- Around line 11-15: The button CSS uses component-specific custom properties
without fallbacks; update each use of --a2ui-button-* in Button.css to fall back
to the base A2UI tokens (e.g., make --a2ui-button-border fall back to
--a2ui-border, --a2ui-button-border-radius fall back to --a2ui-border-radius,
--a2ui-button-background fall back to --a2ui-background, and
--a2ui-button-foreground fall back to --a2ui-foreground) so themes that only
provide base tokens still style buttons; apply the same fallback pattern to the
other occurrences referenced (lines 28–30).

In `@packages/genui/a2ui/styles/catalog/Icon.css`:
- Line 14: The icon color declarations use only the icon-specific token
var(--a2ui-icon-color) and need fallback tokens so icons remain visible when
themes only define base text tokens; update each occurrence (including the rule
containing "color: var(--a2ui-icon-color);" and the other instances noted) to
use a CSS var fallback chain such as var(--a2ui-icon-color,
var(--a2ui-text-color, currentColor)) so the icon falls back to the base text
token and finally to currentColor.

In `@packages/genui/a2ui/test/catalog.test.ts`:
- Around line 147-163: The test "paste-able recipe builds the expected manifest"
currently constructs defineCatalog with only [Text, Button, Icon, Tabs] but the
README's recipe uses allBuiltins (Text, Image, Row, Column, List, Card, Button,
Divider, CheckBox, Icon, RadioGroup, Tabs); update the test to include the
missing manifests (e.g. IMAGE_MANIFEST, ROW_MANIFEST, COLUMN_MANIFEST,
LIST_MANIFEST, CARD_MANIFEST, DIVIDER_MANIFEST, CHECKBOX_MANIFEST,
RADIOGROUP_MANIFEST) when calling defineCatalog and update the expected
manifest.components.map(... ) array to list all 12 names, or if you prefer the
minimal-subset approach, change the test description/comment to explicitly state
it verifies a minimal subset (and keep the four-item catalog) so the README and
test intent no longer conflict.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 47d1322e-b34f-452e-9c52-d831095b7a22

📥 Commits

Reviewing files that changed from the base of the PR and between 363f9e7 and fd05653.

📒 Files selected for processing (15)
  • .changeset/tabs-catalog-and-playground.md
  • packages/genui/a2ui-playground/lynx-src/a2ui/App.tsx
  • packages/genui/a2ui-playground/lynx-src/a2ui/index.css
  • packages/genui/a2ui-playground/src/catalog/a2ui.ts
  • packages/genui/a2ui/README.md
  • packages/genui/a2ui/package.json
  • packages/genui/a2ui/src/catalog/README.md
  • packages/genui/a2ui/src/catalog/Tabs/index.tsx
  • packages/genui/a2ui/src/catalog/index.ts
  • packages/genui/a2ui/src/index.ts
  • packages/genui/a2ui/styles/catalog/Button.css
  • packages/genui/a2ui/styles/catalog/Icon.css
  • packages/genui/a2ui/styles/catalog/Tabs.css
  • packages/genui/a2ui/styles/theme.css
  • packages/genui/a2ui/test/catalog.test.ts

Comment thread packages/genui/a2ui-playground/src/catalog/a2ui.ts
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 15, 2026

Merging this PR will improve performance by 19.02%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 1 improved benchmark
✅ 80 untouched benchmarks
⏩ 26 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
008-many-use-state-destroyBackground 9.5 ms 8 ms +19.02%

Tip

Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.


Comparing p/a2ui-tabs (52e7c08) with main (363f9e7)

Open in CodSpeed

Footnotes

  1. 26 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@HuJean HuJean enabled auto-merge (squash) May 15, 2026 11:35
@relativeci
Copy link
Copy Markdown

relativeci Bot commented May 15, 2026

React External

#1412 Bundle Size — 695.33KiB (0%).

52e7c08(current) vs 363f9e7 main#1407(baseline)

Bundle metrics  no changes
                 Current
#1412
     Baseline
#1407
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
No change  Cache Invalidation 0% 0%
No change  Chunks 0 0
No change  Assets 3 3
No change  Modules 17 17
No change  Duplicate Modules 5 5
No change  Duplicate Code 8.59% 8.59%
No change  Packages 0 0
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#1412
     Baseline
#1407
No change  Other 695.33KiB 695.33KiB

Bundle analysis reportBranch p/a2ui-tabsProject dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci Bot commented May 15, 2026

React MTF Example

#1431 Bundle Size — 208.1KiB (0%).

52e7c08(current) vs 363f9e7 main#1426(baseline)

Bundle metrics  no changes
                 Current
#1431
     Baseline
#1426
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
No change  Cache Invalidation 0% 0%
No change  Chunks 0 0
No change  Assets 3 3
No change  Modules 192 192
No change  Duplicate Modules 77 77
No change  Duplicate Code 44.4% 44.4%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#1431
     Baseline
#1426
No change  IMG 111.23KiB 111.23KiB
No change  Other 96.86KiB 96.86KiB

Bundle analysis reportBranch p/a2ui-tabsProject dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci Bot commented May 15, 2026

React Example

#8298 Bundle Size — 237.15KiB (0%).

52e7c08(current) vs 363f9e7 main#8293(baseline)

Bundle metrics  no changes
                 Current
#8298
     Baseline
#8293
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
No change  Cache Invalidation 0% 0%
No change  Chunks 0 0
No change  Assets 4 4
No change  Modules 197 197
No change  Duplicate Modules 80 80
No change  Duplicate Code 44.89% 44.89%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#8298
     Baseline
#8293
No change  IMG 145.76KiB 145.76KiB
No change  Other 91.39KiB 91.39KiB

Bundle analysis reportBranch p/a2ui-tabsProject dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci Bot commented May 15, 2026

Web Explorer

#9871 Bundle Size — 901.35KiB (0%).

52e7c08(current) vs 363f9e7 main#9866(baseline)

Bundle metrics  Change 1 change
                 Current
#9871
     Baseline
#9866
No change  Initial JS 45.06KiB 45.06KiB
No change  Initial CSS 2.22KiB 2.22KiB
No change  Cache Invalidation 0% 0%
No change  Chunks 9 9
No change  Assets 11 11
Change  Modules 230(+0.88%) 228
No change  Duplicate Modules 11 11
No change  Duplicate Code 27.22% 27.22%
No change  Packages 10 10
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#9871
     Baseline
#9866
No change  JS 497.08KiB 497.08KiB
No change  Other 402.06KiB 402.06KiB
No change  CSS 2.22KiB 2.22KiB

Bundle analysis reportBranch p/a2ui-tabsProject dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci Bot commented May 15, 2026

React Example with Element Template

#566 Bundle Size — 199.95KiB (0%).

52e7c08(current) vs 363f9e7 main#561(baseline)

Bundle metrics  Change 2 changes
                 Current
#566
     Baseline
#561
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
No change  Cache Invalidation 0% 0%
No change  Chunks 0 0
No change  Assets 4 4
Change  Modules 90(+1.12%) 89
No change  Duplicate Modules 27 27
Change  Duplicate Code 40.05%(-0.05%) 40.07%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#566
     Baseline
#561
No change  IMG 145.76KiB 145.76KiB
No change  Other 54.19KiB 54.19KiB

Bundle analysis reportBranch p/a2ui-tabsProject dashboard


Generated by RelativeCIDocumentationReport issue

@HuJean HuJean merged commit 9449860 into main May 15, 2026
83 of 85 checks passed
@HuJean HuJean deleted the p/a2ui-tabs branch May 15, 2026 12:03
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