Skip to content

refactor(core): split widget ui factories by family - #276

Merged
RtlZeroMemory merged 4 commits into
mainfrom
codex/split-widgets-ui
Mar 16, 2026
Merged

refactor(core): split widget ui factories by family#276
RtlZeroMemory merged 4 commits into
mainfrom
codex/split-widgets-ui

Conversation

@RtlZeroMemory

@RtlZeroMemory RtlZeroMemory commented Mar 16, 2026

Copy link
Copy Markdown
Owner

Summary

  • Split packages/core/src/widgets/ui.ts into internal family modules.
  • Kept the public ui API unchanged.
  • No intended behavior change.

Why

  • Reduce monolithic file size and improve maintainability before deeper runtime refactors.

Validation

  • npm run lint
  • npm run typecheck
  • npm run build
  • node scripts/run-tests.mjs --filter "packages/core/dist/widgets/__tests__/"
  • node scripts/run-tests.mjs --filter "packages/jsx/dist/__tests__/parity"

Summary by CodeRabbit

  • New Features

    • Added a broad set of UI builders for dialogs, modals, forms, layouts, navigation, charts, media, editors, feedback widgets (icons, badges, progress, skeletons), pickers, and tree/table views.
  • Refactor

    • UI factory surface reorganized into modular, composable factories for cleaner APIs and maintenance.
  • Bug Fixes

    • Improved animation playback pause/resume checks to ensure stable completion state.

@coderabbitai

coderabbitai Bot commented Mar 16, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 12e5d1a4-1bf9-43d3-bd35-ca2637fa9bdd

📥 Commits

Reviewing files that changed from the base of the PR and between 3ffee89 and 093af04.

📒 Files selected for processing (1)
  • packages/core/src/widgets/__tests__/composition.animationOrchestration.test.ts

📝 Walkthrough

Walkthrough

Refactors the monolithic widget factory by extracting implementations into multiple focused factory modules (basic, feedback, helpers, interactive, layoutShell, media, navigation, advanced) and re-exports them from ui.ts, adding new factory functions and adjusting one test assertion.

Changes

Cohort / File(s) Summary
Core factories — basic
packages/core/src/widgets/factories/basic.ts
Adds primitives: text, box, row, column, themed, grid, spacer, divider with props normalization, child filtering, default gaps, and reversal support.
Core factories — feedback
packages/core/src/widgets/factories/feedback.ts
Adds feedback/display factories: icon, spinner, progress, skeleton, richText, kbd, keybindingHelp, badge, status, tag, gauge, empty, errorDisplay, errorBoundary, callout, link and keybinding helpers.
Core factories — helpers
packages/core/src/widgets/factories/helpers.ts
Introduces UiChild types and utilities: isUiChildren, filterChildren, maybeReverseChildren, isTextProps, resolveButtonIntent, resolveBoxPreset, plus option shapes (PanelOptions, FormOptions, etc.).
Core factories — interactive
packages/core/src/widgets/factories/interactive.ts
Adds interactive controls: button, input, textarea, select, slider, checkbox, radioGroup, field, virtualList, focusAnnouncer, focusZone, focusTrap.
Core factories — layout shell
packages/core/src/widgets/factories/layoutShell.ts
Adds high-level layout APIs: layers, panel, form, actions, center, page, appShell, card, toolbar, statusBar, header, sidebar, masterDetail with overloads and runtime option normalization.
Core factories — media
packages/core/src/widgets/factories/media.ts
Adds media/chart factories: canvas, image, lineChart, scatter, heatmap, sparkline, barChart, miniChart (data-to-props merging patterns).
Core factories — navigation
packages/core/src/widgets/factories/navigation.ts
Adds navigation delegates: tabs, accordion, breadcrumb, pagination, and router helpers routerBreadcrumb, routerTabs delegating to existing creators.
Core factories — advanced
packages/core/src/widgets/factories/advanced.ts
Adds advanced widgets: dialog, modal, dropdown, layer, table, tree, commandPalette, filePicker, fileTreeExplorer, splitPane, panelGroup, resizablePanel, codeEditor, diffViewer, toolApprovalDialog, logsConsole, toastContainer.
Main export refactor
packages/core/src/widgets/ui.ts
Replaces inline implementations with aggregated re-exports from new factory modules; preserves public API shape but moves implementations out of file (large removal/add).
Tests
packages/core/src/widgets/__tests__/composition.animationOrchestration.test.ts
Tightens assertion: verifies entry exists and is not animating in addition to value proximity check.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I split the factory like a carrot bite,
Boxes, buttons, charts take flight,
Children filtered, props aligned,
Modular fields all nicely primed,
Hop! 🥕✨

🚥 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 'refactor(core): split widget ui factories by family' directly and clearly describes the main refactoring change—reorganizing a monolithic widgets/ui.ts file into modular factory modules while maintaining the public API.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/split-widgets-ui
📝 Coding Plan
  • Generate coding plan for human review comments

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
packages/core/src/widgets/factories/interactive.ts (1)

18-26: Redundant function overload signatures.

Lines 18 and 23 declare overload signatures identical to their implementations. These overloads serve no purpose since they don't provide additional type narrowing.

🧹 Proposed cleanup
-export function button(props: ButtonProps): VNode;
 export function button(props: ButtonProps): VNode {
   return { kind: "button", props: resolveButtonIntent(props) };
 }

-export function input(props: InputProps): VNode;
 export function input(props: InputProps): VNode {
   return { kind: "input", props };
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/widgets/factories/interactive.ts` around lines 18 - 26,
Remove the redundant identical overload declarations for the button and input
functions: delete the standalone overload signatures that duplicate the
implementations and leave only the concrete function implementations (the
definitions of button and input that return VNode). Update references to the
resolveButtonIntent call remain inside the button implementation and ensure
ButtonProps/InputProps and return type VNode are preserved on the remaining
function declarations.
🤖 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/core/src/widgets/factories/advanced.ts`:
- Around line 24-45: In dialog(), action IDs are generated using modalProps.id
which can be undefined causing "undefined-action-X" IDs; update the ID
generation in the actions.map callback (inside dialog) to use a safe base ID
(e.g. use props.id or modalProps.id if present, otherwise a deterministic
fallback like `dialog` or a short generated unique prefix) before appending
`-action-${index}`, so action id becomes `${baseId}-action-${index}` instead of
`${modalProps.id}-action-${index}` to avoid "undefined" IDs and collisions when
no parent id is supplied.
- Around line 79-92: Change the children parameter type of splitPane,
panelGroup, and resizablePanel from readonly VNode[] to readonly UiChild[] to
match other container factory APIs; update the function signatures for
splitPane(props: SplitPaneProps, children: readonly UiChild[] = []),
panelGroup(props: PanelGroupProps, children: readonly UiChild[] = []), and
resizablePanel(props: ResizablePanelProps = {}, children: readonly UiChild[] =
[]), and ensure any necessary UiChild import is present so these factories
accept conditional/nested children like the ones in basic.ts, layoutShell.ts,
and interactive.ts.

In `@packages/core/src/widgets/factories/layoutShell.ts`:
- Around line 120-131: The page() factory currently only forwards p when
provided, allowing calls to ui.page(...) to omit outer padding and violate the
root padding invariant; modify the returned props in page(options) so that p
defaults to 1 when not supplied (e.g., use p: p ?? 1 or spread a fallback when p
is undefined) inside the object returned by the page function so root views
always have minimum outer padding; update the code around the page function's
return (the object that currently conditionally spreads p) to apply this
default.
- Around line 253-263: The button id generation in layoutShell.ts (inside the
buttonNodes mapping using options.id and item.id) can produce duplicate
interactive IDs when options.id is undefined and the fallback "sidebar" is
reused; change the logic so each sidebar instance gets a unique prefix (e.g.,
generate a per-instance uniqueId when options.id is falsy) and use that unique
prefix in place of the static "sidebar" fallback so the constructed id
`${prefix}-${item.id}` is always unique across instances; update any relevant
initialization (where layoutShell creates the widget instance) to create/store
the per-instance prefix and reference it in the buttonNodes mapping.

---

Nitpick comments:
In `@packages/core/src/widgets/factories/interactive.ts`:
- Around line 18-26: Remove the redundant identical overload declarations for
the button and input functions: delete the standalone overload signatures that
duplicate the implementations and leave only the concrete function
implementations (the definitions of button and input that return VNode). Update
references to the resolveButtonIntent call remain inside the button
implementation and ensure ButtonProps/InputProps and return type VNode are
preserved on the remaining function declarations.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 211c78cf-ee4a-4fec-ac75-8621bf34f30f

📥 Commits

Reviewing files that changed from the base of the PR and between 0e804dd and 4ccb10f.

📒 Files selected for processing (9)
  • packages/core/src/widgets/factories/advanced.ts
  • packages/core/src/widgets/factories/basic.ts
  • packages/core/src/widgets/factories/feedback.ts
  • packages/core/src/widgets/factories/helpers.ts
  • packages/core/src/widgets/factories/interactive.ts
  • packages/core/src/widgets/factories/layoutShell.ts
  • packages/core/src/widgets/factories/media.ts
  • packages/core/src/widgets/factories/navigation.ts
  • packages/core/src/widgets/ui.ts

Comment thread packages/core/src/widgets/factories/advanced.ts
Comment thread packages/core/src/widgets/factories/advanced.ts Outdated
Comment thread packages/core/src/widgets/factories/layoutShell.ts
Comment thread packages/core/src/widgets/factories/layoutShell.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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/core/src/widgets/factories/layoutShell.ts`:
- Around line 252-257: The new throw in sidebar() creates a breaking runtime
contract; make it backward-compatible by removing the hard throw and providing a
deterministic fallback when options.id and options.key are missing: update the
idPrefix logic inside the sidebar function to assign a stable generated id
(e.g., module-level counter like sidebarIdCounter -> `sidebar-${counter}`) when
both options.id and options.key are absent, and emit a console.warn or
logger.warn indicating a generated id was used; ensure the rest of the code
continues to use idPrefix for unique item ids (reference symbols: sidebar,
SidebarOptions, idPrefix) so existing callers won’t break.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1e1cbf63-be4f-4d12-bc48-2486ce88c2e7

📥 Commits

Reviewing files that changed from the base of the PR and between 4ccb10f and 331b4da.

📒 Files selected for processing (5)
  • packages/core/src/widgets/__tests__/compositionWidgets.test.ts
  • packages/core/src/widgets/factories/advanced.ts
  • packages/core/src/widgets/factories/interactive.ts
  • packages/core/src/widgets/factories/layoutShell.ts
  • packages/jsx/src/__tests__/parity.test.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/core/src/widgets/factories/advanced.ts
  • packages/core/src/widgets/factories/interactive.ts

Comment thread packages/core/src/widgets/factories/layoutShell.ts Outdated
@RtlZeroMemory
RtlZeroMemory merged commit ec8a6c8 into main Mar 16, 2026
32 checks 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