Skip to content

♻️ Refactor | flatten brick props — data fields spread directly onto component - #1

Open
davidgaspardev wants to merge 3 commits into
mainfrom
refactor/set-component-brick-map
Open

♻️ Refactor | flatten brick props — data fields spread directly onto component#1
davidgaspardev wants to merge 3 commits into
mainfrom
refactor/set-component-brick-map

Conversation

@davidgaspardev

@davidgaspardev davidgaspardev commented Jun 22, 2026

Copy link
Copy Markdown
Member

Why?

The previous API required every brick component to destructure brick.data?.field, which was verbose, not type-safe at the component signature level, and inconsistent with how typical React components work. Spreading data fields directly as props gives components a plain, idiomatic React interface.

Type of change

  • Bug fix (non-breaking)
  • New feature (non-breaking)
  • Breaking change (affects public API or wire format)
  • Internal / refactor (no public API impact)

What changed?

  • BrickProps<D> replaces BrickComponentProps<D> — now a type alias D & { id: string; children?: ReactNode } instead of { brick: Brick<..., D>; children? }. Consumers must update imports.
  • BrickComponent<D> now constrains D extends object (was unconstrained).
  • BrickNode renderer spreads { id: brick.id, ...brick.data, children } onto the component instead of passing the full brick prop.
  • Web adapters (Container, Image, Text) updated to destructure flat props.
  • Tests updated to use the new flat prop interface.
  • README updated with new usage examples showing the flat prop API and id availability.
  • .github/PULL_REQUEST_TEMPLATE.md simplified for a web lib project.
  • .claude/commands/open-pr.md added for project automation.

Consumers need to update: Any BrickComponent that reads brick.data?.field must switch to destructuring field directly. Any import of BrickComponentProps must be updated to BrickProps.

Checklist

  • bun test passes
  • bun run typecheck passes
  • Public API changes are reflected in the README
  • Breaking changes are noted above

Summary by CodeRabbit

  • New Features

    • Added PR template and command documentation for streamlined contribution workflow.
  • Documentation

    • Clarified custom brick component creation guide with updated examples showing simplified prop handling.
  • Refactor

    • Simplified brick component props contract: component data now arrives as individual props instead of nested under a single object, improving developer experience and type safety.
  • Tests

    • Updated test examples to reflect new simplified props API.

davidgaspardev and others added 3 commits June 21, 2026 23:17
…onent

BrickComponent now receives { id, children, ...data } instead of { brick }.
BrickComponentProps is replaced by BrickProps<D>. All built-in web adapters
and the README examples updated accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removed mobile platform checklist, Flutter widget tests, and complex
branching rules. Replaced with a minimal template focused on public API
impact, typecheck, and README coverage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR replaces the BrickComponentProps interface (which wrapped a brick object) with a flat BrickProps<D> type that spreads brick data fields plus id and children directly as React props. The renderer, all built-in adapters (Container, Image, Text), defineBrick's generic constraint, public exports, tests, and README are updated accordingly. A GitHub PR template and a Claude open-pr command are also added.

Changes

Flat BrickProps contract

Layer / File(s) Summary
BrickProps type contract and public exports
src/core/types.ts, src/core/catalog.ts, src/core/index.ts
Introduces BrickProps<D> (brick data fields + id + children), removes BrickComponentProps, tightens D extends object on defineBrick, and updates the public re-export.
Renderer: flat props spread
src/core/renderer.tsx
BrickNode constructs a flat props object (id, spread brick.data, children) and renders the component via spread instead of the previous brick={brick} prop.
Built-in adapter migration
src/web/adapters/Container.tsx, src/web/adapters/Image.tsx, src/web/adapters/Text.tsx
Container, Image, and Text each destructure BrickProps fields directly; brick.data access and null-guards are removed.
Test and README update
test/renderer.test.tsx, README.md
Renderer test updates the badge brick to destructure label from props; README rewrites the "Adding a custom brick type" section with flat-props examples for defineBrick, inline maps, and id usage.

PR Workflow Tooling

Layer / File(s) Summary
PR template and Claude open-pr command
.github/PULL_REQUEST_TEMPLATE.md, .claude/commands/open-pr.md
Adds a PR template with Why/Type/What/Checklist sections and a Claude command defining the gh pr create workflow with base-branch detection and a title emoji/type mapping table.

Sequence Diagram(s)

sequenceDiagram
  participant Renderer as BrickNode (renderer.tsx)
  participant Props as Flat BrickProps
  participant Adapter as BrickComponent (e.g. Text/Image/Container)

  Renderer->>Props: build { id, ...brick.data, children }
  Renderer->>Adapter: <Component {...props} />
  Adapter->>Adapter: destructure { id, value, style, ... } from props
  Adapter-->>Renderer: rendered JSX
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 No more brick.data to unwrap and dig,
the props come in flat — that's kind of a big...
id right up front, and children in tow,
label just waiting wherever you go.
The rabbit refactored, the adapters sing,
flat props for all bricks — a glorious spring! 🌸

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: flattening brick props by spreading data fields directly onto components instead of nesting them in a brick object.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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

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

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/core/types.ts (1)

54-59: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider documenting or guarding against reserved prop names.

The intersection D & { id: string; children?: ReactNode } will cause unexpected type behavior if a user's data shape D defines id or children with incompatible types (e.g., id: number would intersect to never). TypeScript catches this at compile time, but a clearer API might use a conditional type or document the constraint explicitly.

Optional safeguard approach:

type ReservedKeys = 'id' | 'children';
export type BrickProps<D extends object = object> = 
  (keyof D & ReservedKeys) extends never 
    ? D & { id: string; children?: ReactNode }
    : never; // Forces compile error with clear intent

Alternatively, add a JSDoc note that D must not contain id or children properties.

🤖 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 `@src/core/types.ts` around lines 54 - 59, The BrickProps type definition has
no guard against users passing a data shape D that contains id or children
properties with incompatible types, which silently resolves to never. Add a
conditional type check to the BrickProps generic that validates D does not
contain the reserved keys id or children. If D extends a type with these
reserved keys, the type should resolve to never, forcing a compile-time error
with clear intent. Alternatively, if you prefer a documentation-first approach,
add explicit JSDoc comments to BrickProps clarifying that the generic type
parameter D must not define id or children properties.
🤖 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 @.claude/commands/open-pr.md:
- Around line 19-26: Step 5 in open-pr.md references PR template sections that
do not exist in the actual .github/PULL_REQUEST_TEMPLATE.md file. Update Step 5
to remove instructions for non-existent sections (Screenshots, Testing,
Reference Links/Dependencies) and keep only the sections that are actually
present in the template: Why?, Type of Change, What Changed?, and Checklist.
Ensure the instructions accurately reflect what users will encounter when they
create the PR so there is no contradiction with the earlier instruction on line
14 to read the template structure.

In `@src/core/renderer.tsx`:
- Around line 34-35: The props object on line 34 is spreading brick.data after
setting id, which allows brick.data.id to overwrite the canonical brick.id
value. This breaks the flat-props contract. Reorder the spread operation in the
props object so that the id assignment comes after spreading brick.data,
ensuring the renderer-controlled brick.id field takes precedence and cannot be
overwritten by any id property in brick.data.

---

Nitpick comments:
In `@src/core/types.ts`:
- Around line 54-59: The BrickProps type definition has no guard against users
passing a data shape D that contains id or children properties with incompatible
types, which silently resolves to never. Add a conditional type check to the
BrickProps generic that validates D does not contain the reserved keys id or
children. If D extends a type with these reserved keys, the type should resolve
to never, forcing a compile-time error with clear intent. Alternatively, if you
prefer a documentation-first approach, add explicit JSDoc comments to BrickProps
clarifying that the generic type parameter D must not define id or children
properties.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: aabef493-a59d-4e0f-98f9-2eb6f12d43a3

📥 Commits

Reviewing files that changed from the base of the PR and between 46664f1 and bfc5428.

📒 Files selected for processing (11)
  • .claude/commands/open-pr.md
  • .github/PULL_REQUEST_TEMPLATE.md
  • README.md
  • src/core/catalog.ts
  • src/core/index.ts
  • src/core/renderer.tsx
  • src/core/types.ts
  • src/web/adapters/Container.tsx
  • src/web/adapters/Image.tsx
  • src/web/adapters/Text.tsx
  • test/renderer.test.tsx

Comment on lines +19 to +26
5. Run `gh pr create --base <base>` filling each section:
- **Why?** — the problem this solves
- **Type of Change** — tick the correct checkbox
- **What Changed?** — layers, classes, entities affected
- **Screenshots** — remove the table if there are no UI changes
- **Testing** — tick platforms and verification items based on the diff; describe test scenarios
- **Reference Links / Dependencies** — include `$ARGUMENTS` if provided; omit if empty
- **Checklist** — tick Self-review and Tests/Docs items based on the diff

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's check the command file to see Step 5 exactly
cat -n .claude/commands/open-pr.md | head -30

Repository: squillteam/bricks-web-client

Length of output: 1855


🏁 Script executed:

# Then check the PR template file
cat -n .github/PULL_REQUEST_TEMPLATE.md

Repository: squillteam/bricks-web-client

Length of output: 803


Mismatch between command instructions and actual PR template structure.

Step 5 instructs users to fill sections—Screenshots, Testing, Reference Links / Dependencies, and Merge Rules—that do not exist in .github/PULL_REQUEST_TEMPLATE.md. The template contains only: Why?, Type of change, What changed?, and Checklist.

Additionally, line 14 instructs users to read the template to understand its structure, but Step 5 then contradicts this by listing non-existent fields. This creates confusion when users follow the command and discover the template lacks these sections.

Either expand the template to include the missing sections or update Step 5 to match the actual template structure.

🤖 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 @.claude/commands/open-pr.md around lines 19 - 26, Step 5 in open-pr.md
references PR template sections that do not exist in the actual
.github/PULL_REQUEST_TEMPLATE.md file. Update Step 5 to remove instructions for
non-existent sections (Screenshots, Testing, Reference Links/Dependencies) and
keep only the sections that are actually present in the template: Why?, Type of
Change, What Changed?, and Checklist. Ensure the instructions accurately reflect
what users will encounter when they create the PR so there is no contradiction
with the earlier instruction on line 14 to read the template structure.

Comment thread src/core/renderer.tsx
Comment on lines +34 to +35
const props = { id: brick.id, ...(brick.data as object | undefined), children };
return <Component {...(props as any)} />;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve canonical brick identity when flattening props.

Line 34 currently lets brick.data.id overwrite brick.id because of spread order. That breaks the flat-props contract and can propagate incorrect IDs into adapters (data-brick-id, analytics hooks, test selectors). Ensure renderer-controlled fields win.

🔧 Proposed fix
-  const props = { id: brick.id, ...(brick.data as object | undefined), children };
+  const props = { ...(brick.data as object | undefined), id: brick.id, children };
   return <Component {...(props as any)} />;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const props = { id: brick.id, ...(brick.data as object | undefined), children };
return <Component {...(props as any)} />;
const props = { ...(brick.data as object | undefined), id: brick.id, children };
return <Component {...(props as any)} />;
🤖 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 `@src/core/renderer.tsx` around lines 34 - 35, The props object on line 34 is
spreading brick.data after setting id, which allows brick.data.id to overwrite
the canonical brick.id value. This breaks the flat-props contract. Reorder the
spread operation in the props object so that the id assignment comes after
spreading brick.data, ensuring the renderer-controlled brick.id field takes
precedence and cannot be overwritten by any id property in brick.data.

@davidgaspardev davidgaspardev self-assigned this Jun 27, 2026
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