Skip to content

feat(core): add missing navigation/core widgets#82

Merged
RtlZeroMemory merged 2 commits into
mainfrom
core-components-tabs-accordion
Feb 18, 2026
Merged

feat(core): add missing navigation/core widgets#82
RtlZeroMemory merged 2 commits into
mainfrom
core-components-tabs-accordion

Conversation

@RtlZeroMemory

Copy link
Copy Markdown
Owner

Summary

Adds the 4 missing essential widgets in core UI with stateful composition, rendering, and keyboard/focus integration:

  • ui.tabs()
  • ui.accordion()
  • ui.breadcrumb()
  • ui.pagination()

What changed

  • Added new widget implementations and factories in packages/core/src/widgets/ and packages/core/src/widgets/ui.ts
  • Extended VNode discriminated union/types in packages/core/src/widgets/types.ts
  • Added keyboard routing for tabs and pagination in packages/core/src/runtime/router/
  • Integrated new widget handling into commit, zone routing, and renderer/layout plumbing
  • Added renderer support for navigation widget kinds in packages/core/src/renderer/renderToDrawlist/widgets/navigation.ts
  • Added deterministic unit tests:
    • tabs.test.ts (26)
    • accordion.test.ts (18)
    • breadcrumb.test.ts (12)
    • pagination.test.ts (15)
  • Updated widget docs with dedicated pages and index links

Why

These components were missing from core and are required for standard app navigation/content disclosure patterns with accessible keyboard behavior and predictable focus management.

Validation

  • npm run build
  • npm run typecheck
  • node scripts/run-tests.mjs
  • npm run lint

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 413702de64

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +81 to +85
const zoneId = ctx.activeZoneId ?? findZoneForId(ctx.zones, focusedId);
if (zoneId === null) return null;

const tabsId = parseTabsContentZoneId(zoneId);
if (tabsId === null) return null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Handle Escape from nested zones inside tab content

The Escape path only works when activeZoneId itself is a tabs content zone id. If focus is inside a nested focusZone/focusTrap within the active tab panel, activeZoneId points to that nested zone, parseTabsContentZoneId(...) returns null, and the handler exits without moving focus back to the tab bar. This makes the documented Escape behavior fail for common tab content that contains its own focus-scoped widgets.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in 7600d74.

What changed:

  • Added zone ancestry metadata (parentZoneId) in focus-zone collection/runtime metadata.
  • Updated routeTabsKey to walk parent zones from the active nested zone until it finds the tabs content zone, then return focus to the tab bar.

Regression coverage:

  • packages/core/src/widgets/__tests__/tabs.test.ts
    • escape from nested zone inside tab content returns focus to tab bar

Comment on lines +57 to +60
const nextFocusedId = computeZoneMovement(
zone,
ctx.focusedId,
event.key === ZR_KEY_LEFT ? "left" : "right",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Route arrows by adjacent page instead of adjacent control

Left/Right navigation is driven by computeZoneMovement over focusable controls, then immediately presses whatever control receives focus. When ellipses are present, those ... items are non-focusable, so the next focusable can be a far page (or last), causing large page jumps rather than moving to page - 1 / page + 1. This violates the widget’s stated keyboard contract in large paginations.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in 7600d74.

What changed:

  • Updated routePaginationKey so Left/Right on page buttons routes by adjacent page intent (page - 1 / page + 1) rather than by next focusable control.
  • If an adjacent page button is not currently visible due to ellipsis, routing now falls back to prev/next controls (still one-page movement) instead of jumping to far page controls.

Regression coverage:

  • packages/core/src/widgets/__tests__/pagination.test.ts
    • right arrow on sparse page buttons uses next control instead of jumping pages
    • left arrow on sparse page buttons uses prev control instead of jumping pages

@RtlZeroMemory
RtlZeroMemory merged commit 3c5b221 into main Feb 18, 2026
18 checks passed
@RtlZeroMemory
RtlZeroMemory deleted the core-components-tabs-accordion branch February 19, 2026 17:45
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