Skip to content

fix(core): select imported/shared components in the inspector - #367

Open
stantheman0128 wants to merge 2 commits into
1weiho:mainfrom
stantheman0128:fix/327-inspector-shared-components
Open

fix(core): select imported/shared components in the inspector#367
stantheman0128 wants to merge 2 commits into
1weiho:mainfrom
stantheman0128:fix/327-inspector-shared-components

Conversation

@stantheman0128

@stantheman0128 stantheman0128 commented Jul 23, 2026

Copy link
Copy Markdown

Summary

Fixes #327.

In inspect mode, clicking an element rendered by an imported/shared component produced no selection (or, when nested under a tagged slide host, selected the wrong ancestor). Host JSX authored outside slides/ never gets data-slide-loc, and the fiber fallback required a host fiber whose _debugSource pointed at the slide file, so component call sites were skipped.

  • Prefer an exact data-slide-loc on the clicked element
  • Then walk fibers and allow slide-file component call sites (drop hostOnly at inspector call sites), anchoring highlight to the nearest descendant host
  • Only then fall back to a tagged ancestor (HMR-immune last resort)
  • Covers nested shared components and text inside shared hosts

Evidence (product path)

Scratch e2e fixture shared-select with components/shared.tsx (Heading / Card), Playwright against the live inspector.

Before (main HEAD): click Shared heading click target with Inspect on -> inspector panel stays closed (panelVisible: false).

After (this branch): same click opens the panel with Element text Shared heading click target (host styles 64px / weight 700). Nested Card > Heading (Nested shared heading) also selects.

pnpm exec vitest run packages/core/src/app/lib/inspector/fiber.test.ts
Test Files  1 passed (1)
Tests  13 passed (13)

pnpm exec playwright test e2e/tests/inspector.spec.ts -g "shared component|nested shared|selecting an element opens"
  ok selecting an element opens the panel with its tag and text
  ok selecting text inside an imported shared component opens the panel
  ok selecting text inside a nested shared component opens the panel

Screenshots / logs live under handoff/evidence-open-slide-327/ on the contributor machine (before unselectable, after shared + nested selected).

What was not tested

  • Style edits that require the shared component to forward style / props (selection + source mapping are fixed; forwarding is still per-component)
  • Configurable FORWARDING_COMPONENTS (issue alternative); not needed for selection

AI assistance

This change was prepared with AI assistance (Cursor/Grok). I reviewed the diff, ran the unit and Playwright checks above, and verified the inspector click path before/after on the shared-component fixture.

Test plan

  • Unit: shared call site, nested call site, tagged-ancestor must not steal, hostOnly still rejects when set
  • E2E: select text inside imported Heading; select nested Heading under Card; inline host regression
  • Maintainer: quick click-through in a deck that imports a local component library

Summary by CodeRabbit

  • New Features

    • The inspector can now select elements rendered by imported or shared components, including nested shared components.
    • When selecting shared component content, the inspector’s “Element text” field is populated with the selected text.
  • Bug Fixes

    • Improved inspector target resolution when the clicked element lacks direct location metadata, with better line/column fallback behavior.
  • Tests

    • Added end-to-end and unit test coverage for shared component selection and nested behavior (including inspector visibility and displayed selection text).

Allow fiber hit-testing to resolve slide call sites for hosts authored
outside slides/, and prefer that match over a tagged ancestor wrapper.

Co-authored-by: Cursor <cursoragent@cursor.com>
@vercel

vercel Bot commented Jul 23, 2026

Copy link
Copy Markdown

@stantheman0128 is attempting to deploy a commit to the open-slide Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 201cabf8-d709-401b-8c1a-843c89e7f839

📥 Commits

Reviewing files that changed from the base of the PR and between a9d75e8 and 5f7678e.

📒 Files selected for processing (3)
  • packages/core/src/app/components/inspector/inspector-panel.tsx
  • packages/core/src/app/lib/inspector/fiber.test.ts
  • packages/core/src/app/lib/inspector/fiber.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/core/src/app/lib/inspector/fiber.test.ts
  • packages/core/src/app/lib/inspector/fiber.ts

Walkthrough

The inspector now resolves imported and nested shared components through React fiber source locations, while preserving direct and ancestor location-tag handling. Overlay selection, target recovery, fixtures, unit tests, end-to-end tests, and release metadata are updated.

Changes

Shared component inspector selection

Layer / File(s) Summary
Fiber-based shared source resolution
packages/core/src/app/lib/inspector/fiber.ts, packages/core/src/app/lib/inspector/fiber.test.ts
findSlideSource prioritizes direct tags, resolves slide call sites through fibers, supports hostOnly, and falls back to tagged ancestors; tests cover imported and nested components.
Inspector hit-testing and target recovery
packages/core/src/app/components/inspector/inspect-overlay.tsx, packages/core/src/app/components/inspector/inspector-panel.tsx
Pointer handling, selected-target resolution, and line-based anchor recovery call findSlideSource without hostOnly.
Shared fixtures and selection coverage
packages/core/e2e/fixture/components/shared.tsx, packages/core/e2e/fixture/slides/shared-select/index.tsx, packages/core/e2e/fixture/tsconfig.json, packages/core/e2e/tests/inspector.spec.ts, .changeset/shared-inspector-select.md
Adds shared Heading and Card fixtures, registers the slide, tests shared and nested selection, and records a patch release.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant InspectorOverlay
  participant findSlideSource
  participant ReactFiber
  participant InspectorPanel
  InspectorOverlay->>findSlideSource: resolve clicked shared-component element
  findSlideSource->>ReactFiber: walk debug source chain
  ReactFiber-->>findSlideSource: return slide call-site and host anchor
  findSlideSource-->>InspectorOverlay: return selection hit
  InspectorOverlay->>InspectorPanel: provide selected target
  InspectorPanel->>findSlideSource: resolve or recover target anchor
  findSlideSource-->>InspectorPanel: return source line, column, and anchor
Loading

Possibly related PRs

Suggested reviewers: 1weiho

Poem

I hop through fibers, neat and bright,
Finding shared components in sight.
A heading clicks, a card joins too,
The inspector knows just what to do.
Line and anchor, safely found—
No shared component lost around!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.45% 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 is concise and accurately describes the main change: enabling inspector selection for imported/shared components.
Linked Issues check ✅ Passed The changes address #327 by resolving shared component call sites, preserving inline host selection, and adding tests for nested and text cases.
Out of Scope Changes check ✅ Passed The added fixtures, tsconfig include, and tests are all directly supporting the shared-component inspector fix.

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.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/app/components/inspector/inspector-panel.tsx (1)

1096-1107: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

findElementByLine fallback loop ignores column, and this PR increases the odds of collisions.

The tagged lookup at Line 1099 matches on the full ${line}:${column} selector, but the fallback loop at Line 1102-1105 only checks hit.line === line. Now that findSlideSource resolves shared/nested component call sites without hostOnly, multiple elements rendered from different call sites on the same line but different columns (e.g. <Heading>A</Heading><Heading>B</Heading> on one line) can all satisfy hit.line === line, and the loop returns the first DOM-order match rather than the correct one — potentially re-selecting the wrong element after an edit.

🐛 Proposed fix
   for (const el of candidates) {
     const hit = findSlideSource(el, slideId);
-    if (hit && hit.line === line) return hit.anchor;
+    if (hit && hit.line === line && hit.column === column) return hit.anchor;
   }
🤖 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/core/src/app/components/inspector/inspector-panel.tsx` around lines
1096 - 1107, Update the fallback loop in findElementByLine to require both
hit.line === line and hit.column === column before returning hit.anchor.
Preserve the existing full line:column tagged lookup and continue scanning
candidates until the exact source location is found.
🧹 Nitpick comments (1)
packages/core/src/app/lib/inspector/fiber.test.ts (1)

176-199: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Use a real DOM host for the shared-component anchor tests.

The shared-component tests stub HTMLElement to a non-extends class, so in the Node test environment the production fiber.stateNode instanceof HTMLElement check is not exercised. findViaFiber() still returns el as anchor because it was initialized to el and hostOnly stays false, so expect(hit?.anchor).toBe(el) passes without testing the intended host-anchor path. Since the core production code relies on the real HTMLElement constructor, use real DOM nodes in these cases (document.createElement('div')) instead of the fakes.

🤖 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/core/src/app/lib/inspector/fiber.test.ts` around lines 176 - 199,
Update the shared-component anchor test around findSlideSource to use real DOM
elements created with document.createElement('div') for hostEl and the clicked
element, rather than fake HTMLElement instances. Keep the fiber setup and anchor
assertions intact so the production stateNode instanceof HTMLElement path in
findViaFiber is exercised.
🤖 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.

Outside diff comments:
In `@packages/core/src/app/components/inspector/inspector-panel.tsx`:
- Around line 1096-1107: Update the fallback loop in findElementByLine to
require both hit.line === line and hit.column === column before returning
hit.anchor. Preserve the existing full line:column tagged lookup and continue
scanning candidates until the exact source location is found.

---

Nitpick comments:
In `@packages/core/src/app/lib/inspector/fiber.test.ts`:
- Around line 176-199: Update the shared-component anchor test around
findSlideSource to use real DOM elements created with
document.createElement('div') for hostEl and the clicked element, rather than
fake HTMLElement instances. Keep the fiber setup and anchor assertions intact so
the production stateNode instanceof HTMLElement path in findViaFiber is
exercised.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: de631e5c-451b-41f8-b7f2-66d53fb2f6a6

📥 Commits

Reviewing files that changed from the base of the PR and between c408ba0 and a9d75e8.

📒 Files selected for processing (9)
  • .changeset/shared-inspector-select.md
  • packages/core/e2e/fixture/components/shared.tsx
  • packages/core/e2e/fixture/slides/shared-select/index.tsx
  • packages/core/e2e/fixture/tsconfig.json
  • packages/core/e2e/tests/inspector.spec.ts
  • packages/core/src/app/components/inspector/inspect-overlay.tsx
  • packages/core/src/app/components/inspector/inspector-panel.tsx
  • packages/core/src/app/lib/inspector/fiber.test.ts
  • packages/core/src/app/lib/inspector/fiber.ts

Dropping `hostOnly` from the inspector's re-resolution scan widened the
set of elements that can answer for a given source line, and that scan
only compared the line. Several elements routinely originate on one line,
so after an HMR round that detached the selected node the inspector could
hand back whichever element the DOM walk reached first.

Prefer a line and column hit, and keep a line-only hit as a last resort so
an edit that shifts a column degrades to the previous behavior rather than
dropping the selection.

Also add a fiber test that distinguishes host-anchor resolution from the
seeded anchor. The existing imported-call-site test points the host fiber
at the clicked element, which is also `anchor`'s initial value, so it
passes whether or not the host check runs; forcing `isHost` to false
leaves it green. The new test uses a separate host element and fails under
that mutation.

Document the inspector's three resolution strategies and why they are
ordered the way they are.
@stantheman0128

Copy link
Copy Markdown
Author

Addressed CodeRabbit feedback on 6ab55d4: findElementByLine fallback now requires both line and column before returning an anchor (avoids same-line sibling collisions). pnpm exec vitest run packages/core/src/app/lib/inspector/fiber.test.ts — 13 passed.

Stan Shih (@stantheman0128)

@stantheman0128

Copy link
Copy Markdown
Author

Follow-up: fork already had the column-aware fallback at \5f7678e\ (exact column first, line-only fallback); no additional push needed.

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.

[Bug]: Inspector can't select any element rendered by an imported/shared component

2 participants