Skip to content

feat(core,react-web): add slot() field factory for custom renderers#7

Merged
wilcorrea merged 1 commit intomainfrom
feat/slot-field-factory
Feb 27, 2026
Merged

feat(core,react-web): add slot() field factory for custom renderers#7
wilcorrea merged 1 commit intomainfrom
feat/slot-field-factory

Conversation

@wilcorrea
Copy link
Contributor

@wilcorrea wilcorrea commented Feb 27, 2026

Motivation

When building read-only view pages (e.g. EntryView, JourneyView) with Ybyra, developers often need to display complex or custom UI elements (status badges, formatted lists, JSON viewers, timeline components) in specific positions within the form layout.

Previously, the only options were:

  • Register a global renderer via registerRenderers() (pollutes the global registry, not scoped to a single page)
  • Skip Ybyra entirely for those pages (misses layout, loading, and action bar benefits)

Solution

This PR introduces a slot() field factory that allows embedding any React component inline inside a DataForm without touching the global renderer registry.

API

// schema.ts
import { slot, text } from '@ybyra/core'

const fields = {
  id:     text().disabled(),
  status: slot().width(50),
  result: slot(),
}
// EntryView.tsx
<DataForm
  schema={schema}
  scope={Scope.view}
  component={component}
  slots={{
    status: ({ value }) => <StatusBadge status={value as string} />,
    result: ({ value }) => <pre>{String(value ?? '')}</pre>,
  }}
/>

SlotRendererProps

interface SlotRendererProps {
  domain: string
  name: string
  value: unknown
  proxy: FieldProxy
  scope: ScopeValue
}

Behaviour

  • Slot fields with no matching renderer in slots are silently omitted (render null)
  • All other field props (width, hidden, scopes, group) work normally on slot fields
  • 100% backward compatible — existing code is unaffected
  • Custom FieldsGrid component overrides (components.FieldsGrid) receive the slots prop as well

Changes

Package File Change
@ybyra/core fields/slot.ts New SlotFieldDefinition + slot() factory
@ybyra/core fields/index.ts, index.ts Export slot and SlotFieldDefinition
@ybyra/react-web types.ts New SlotRendererProps interface; updated FieldsGridProps and DataFormComponents
@ybyra/react-web components/Form.tsx Accept slots prop and thread to FieldsGrid
@ybyra/react-web components/defaults/FieldsGrid.tsx Render slot fields via slots lookup
@ybyra/react-web index.ts Export SlotRendererProps

Summary by CodeRabbit

  • New Features
    • Introduced slot fields enabling custom component rendering at designated points within forms.
    • DataForm now supports a slots configuration to inject custom React components into forms.
    • Slot components receive full context including field values, proxy access, scope, and domain information for proper rendering.

Introduces a new `slot()` field factory that allows embedding arbitrary
React components inside a DataForm without registering global renderers.

Changes:
- packages/core: add SlotFieldDefinition and slot() factory
- packages/react-web: add SlotRendererProps interface
- packages/react-web: FieldsGrid renders slot fields via slots prop
- packages/react-web: DataForm accepts slots prop and threads it down

Usage:
  // schema
  const fields = { status: slot().width(50), result: slot() }

  // page
  <DataForm schema={schema} slots={{
    status: ({ value }) => <StatusBadge status={value as string} />,
    result: ({ value }) => <pre>{String(value)}</pre>,
  }} />

Slot fields with no matching renderer are silently omitted (null render).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@coderabbitai
Copy link

coderabbitai bot commented Feb 27, 2026

📝 Walkthrough

Walkthrough

This pull request introduces a new slot field type to the core package and integrates slot rendering support throughout the React Web component layer. It adds a SlotFieldDefinition class, updates component APIs to accept slot renderers, implements conditional slot field rendering in FieldsGrid, and extends type definitions to support the new functionality.

Changes

Cohort / File(s) Summary
Core Slot Field Type
packages/core/src/fields/slot.ts, packages/core/src/fields/index.ts, packages/core/src/index.ts
Introduces new SlotFieldDefinition class extending FieldDefinition and slot factory function. Exports added to fields and root index modules to expose new field type.
Form Component Integration
packages/react-web/src/components/Form.tsx
Adds slots prop to DataForm component interface and signature, threading slots through all ResolvedFieldsGrid render paths (grouped, ungrouped, and default sections).
Field Rendering
packages/react-web/src/components/defaults/FieldsGrid.tsx
Implements conditional rendering for slot fields: detects fields with component="slot", renders SlotRenderer if provided via slots map, otherwise skips rendering. Extracts domain, name, value, proxy, and scope for slot components.
Type System
packages/react-web/src/types.ts, packages/react-web/src/index.ts
Adds SlotRendererProps interface with domain, name, value, proxy, and scope fields. Updates FieldsGridProps and DataFormComponents types to include slots configuration. Removes domain field from ActionButtonProps. Exports SlotRendererProps from public API.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 A slot field hops into view,
Threading through each form and grid so true,
With slots and renderers dancing in sync,
Component mapping with a wink,
New types align, the API takes flight!

🚥 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 accurately summarizes the main changes: introducing a slot() field factory in core and react-web packages for custom component rendering.

✏️ 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 feat/slot-field-factory

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.

Copy link

@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.

🧹 Nitpick comments (1)
packages/react-web/src/types.ts (1)

47-47: DataFormComponents.Slot is exposed but not used in the default rendering flow.

The default path uses slots lookup in FieldsGrid; components.Slot is not consumed there, which can create API confusion. Consider removing it or wiring it as a real fallback.

♻️ Suggested cleanup (if you keep the current `slots`-only behavior)
 export interface DataFormComponents {
   ActionBar?: ComponentType<ActionBarProps>;
   ActionButton?: ComponentType<ActionButtonProps>;
   FieldsGrid?: ComponentType<FieldsGridProps>;
   GroupWrapper?: ComponentType<GroupWrapperProps>;
   Loading?: ComponentType<LoadingProps>;
   Divider?: ComponentType<DividerProps>;
-  Slot?: ComponentType<SlotRendererProps>;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react-web/src/types.ts` at line 47, DataFormComponents exposes Slot
(Slot?: ComponentType<SlotRendererProps>) but FieldsGrid never reads
components.Slot and instead uses the slots lookup, creating API confusion;
either remove Slot from the DataFormComponents type or wire it as a fallback by
updating FieldsGrid to check components.Slot when a named slot is missing (i.e.,
inside FieldsGrid’s slot resolution logic use components?.Slot as the default
renderer before falling back to slots map), referencing the symbols
DataFormComponents.Slot, components.Slot, and FieldsGrid to locate the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/react-web/src/types.ts`:
- Line 47: DataFormComponents exposes Slot (Slot?:
ComponentType<SlotRendererProps>) but FieldsGrid never reads components.Slot and
instead uses the slots lookup, creating API confusion; either remove Slot from
the DataFormComponents type or wire it as a fallback by updating FieldsGrid to
check components.Slot when a named slot is missing (i.e., inside FieldsGrid’s
slot resolution logic use components?.Slot as the default renderer before
falling back to slots map), referencing the symbols DataFormComponents.Slot,
components.Slot, and FieldsGrid to locate the change.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 59ec685 and 7e5915d.

📒 Files selected for processing (7)
  • packages/core/src/fields/index.ts
  • packages/core/src/fields/slot.ts
  • packages/core/src/index.ts
  • packages/react-web/src/components/Form.tsx
  • packages/react-web/src/components/defaults/FieldsGrid.tsx
  • packages/react-web/src/index.ts
  • packages/react-web/src/types.ts

@wilcorrea wilcorrea merged commit aefba5d into main Feb 27, 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