Skip to content

feat(builder): layers panel and ancestor breadcrumb - #1013

Merged
mobeenabdullah merged 4 commits into
mainfrom
feat/layers-panel
Aug 18, 2026
Merged

mobeenabdullah merged 4 commits into
mainfrom
feat/layers-panel

Conversation

@mobeenabdullah

Copy link
Copy Markdown
Collaborator

Plan 04 B-13 (layers panel) and the navigation half of B-16 (ancestor breadcrumb).

Stacked on #1012. That branch is merged in here, because click-to-select was broken on main and without it the panel cannot be verified at all. Merge #1012 first; this diff then reduces to the layers work.

Why this, now

The editor can insert, select, move, delete, undo and edit. It could not show an author the structure of their page — and structure is exactly where blocks get lost: an empty container is a couple of pixels, and a block hidden at the current breakpoint is not on the canvas at all.

The tree is @nextlyhq/ui's TreeView, not one written here

F7 shipped it and its own docblock says it exists for this control. It is virtualized, and its flat role="treeitem" rows carry aria-level/aria-setsize/aria-posinset because virtualization makes the nested role="group" markup impossible to build — only a window is in the DOM. It also brings the APG keyboard model, roving tabindex and typeahead. Reimplementing that here would have put the accessibility half in the place it would rot.

Decisions, each from a measurement

Children are flattened across slots. Measured across the catalogue: 9 containers declare exactly one slot, none declares more. So a flat tree is faithful today, and slot rows would add a level of nesting to name a distinction no block currently makes. The limit is stated in the module — a two-slot block would show its children in one run, and this is where slot rows grow.

Badges are three facts, not one eye. locked is a boolean the engine defines. Visibility is not: it is conditions evaluated against an entry the editor cannot see, plus a per-breakpoint map where a block hidden on mobile is fully present on desktop. A single eye icon would have to state an answer nothing here knows, so the row reports locked, hidden at some screen sizes and shown conditionally separately — each as clipped text beside an aria-hidden icon, because an icon alone announces as an image with no name.

Expansion is split by how long it should last. Three things want to open a branch: the author, a selection made on the canvas, a search. Deriving all three as one union reads correctly and makes an ancestor of the selected block impossible to close — the author collapses it, the next render puts it straight back. So a selection opens its ancestors once, into the author's own set; a search opens its matches' ancestors only while the query stands. Only the author's set is stored.

One label rule. blockLabel replaces the inspector's editor.label ?? node.type, which agreed only for blocks that declare a label — an unlabelled third-party block was "Collection loop" in the palette and acme/collection-loop in the inspector. This also changes a delete announcement for an unlabelled block from acme/text to "Text"; that test now records the decision and why.

Verified in a browser

rail: ["Insert","Layers"]                       tree present: 1
rows: Box (level 1) · Text (level 1)            — collapsed, Heading hidden
click the nested Heading on the canvas →
rows: Box (level 1, expanded) · Heading (level 2, SELECTED) · Text (level 1)
breadcrumb: ["Box","Heading"]
search "Head" → Box (expanded) · Heading        clear → Text returns
click the first crumb → selection moves to the container
pageerrors: []

Tests

606 in @nextlyhq/builder (was 575), 61 in plugin-page-builder, 30/30 tasks. Every rule stub-verified — broken one at a time, intended tests confirmed failing, restored, restore confirmed by diff: 5 for the tree model, 3 for the expansion rules, 4 for the breadcrumb.

One of those breaks moved nothing, which is a finding rather than a pass: dropping the search-branch filter changed no result, because the filter only runs when the author toggles a branch and no test toggled one during a search. The property was uncovered. The test that reaches it is in this PR, and re-running the same break now fails it.

Not in this PR, deliberately

Rename, the lock toggle, and the 2.5.7 move menus. The lock toggle needs node.locked to be honoured by delete and keyboard-move too — today only drag reads it — and shipping a switch whose effect is half-wired is worse than shipping none. That is a coherent "locking works" PR of its own.

Note for whoever reviews the chrome

packages/builder/src/** is outside the three design-token ESLint rules, outside lint-design.mjs, and outside the alpha-contrast suite's scanned directories. Nothing would catch a sub-3:1 border in this panel. The new styles therefore use only the existing --nx-builder-* tokens, which alias the vetted admin palette, and add no opacity-modified colours — an alpha-blended foreground's contrast depends on whatever is behind it, which is what broke main earlier today. That coverage gap is worth closing separately.

The canvas shows a page. It does not show that a heading is inside a box which
is inside a section, and it cannot show a block that renders nothing — an empty
container is a couple of pixels and a block hidden at the current breakpoint is
not there at all. Those are the blocks an author loses.

`layers.ts` derives the tree, the path to a block and what a search leaves
standing. The panel and the breadcrumb both read it, so the trail and the
panel's highlight cannot name different ancestors.

The tree is `@nextlyhq/ui`'s `TreeView` rather than one written here: it is
virtualized, and its flat `role="treeitem"` rows carry the level and position
attributes that a virtualized tree needs because nested `role="group"` markup
cannot be built when only a window is rendered. Reimplementing that would put
the accessibility half where it would rot.

Children are flattened across slots. Measured across the catalogue: nine
containers declare exactly one slot and none declares more, so a flat tree
describes the document faithfully and slot rows would add a level of nesting to
name a distinction no block currently makes.

Badges are three separate facts rather than one eye. `locked` is a boolean the
engine defines; visibility is conditions evaluated against an entry the editor
cannot see, and a per-breakpoint map where a block hidden on mobile is fully
present on desktop. One icon would have to state an answer nothing here knows.

Expansion is split by how long it should last. A selection opens its ancestors
once, into the author's own set, and the author may close them again; a search
opens its matches' ancestors only while the query stands. Deriving all three as
one union reads correctly and makes an ancestor of the selected block
impossible to close.

One label rule, from `blockLabel`. The inspector's `editor.label ?? node.type`
was a second rule that agreed only for blocks declaring a label, so an
unlabelled third-party block was "Collection loop" in the palette and
`acme/collection-loop` in the inspector.
Clicking a block on the canvas cleared the selection instead of setting it.

`setPointerCapture` on `pointerdown` retargets every later pointer event to the
capturing element, and a browser derives a `click`'s target from where the press
and the release landed. Capturing on the press therefore made every click on the
canvas report the canvas ROOT as its target; the hit test walks up from there,
finds no block above the root, and reads that as a click on the background.

Capture waits for activation instead. A drag needs it because the pointer may
leave the canvas and must keep delivering moves; a click does not, and until the
pointer has travelled far enough there is no way to tell which one a press will
turn out to be.

jsdom implements no capture retargeting and synthesises no click from a press,
so the symptom is not reproducible in a unit test — the test asserts WHEN
capture is taken, which is what the defect was, with the activation case as its
positive control.
The trail itself is asserted in `layers.test.ts` without a DOM. What is only
true in the component is which crumb is marked current, that every crumb changes
the selection, and that an empty path renders nothing rather than an empty bar —
which is the case an undo reaches routinely, by removing the selected node while
the selection stands.
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

1 similar comment
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@mobeenabdullah, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 56 minutes

Limit details: You’ve used all 1 included review currently available under your plan.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 50176d25-1f65-48cb-9bdd-7296a55915cb

📥 Commits

Reviewing files that changed from the base of the PR and between 0d559cb and 3727712.

⛔ Files ignored due to path filters (2)
  • .changeset/canvas-click-selects-again.md is excluded by !.changeset/**
  • .changeset/layers-panel-and-breadcrumb.md is excluded by !.changeset/**
📒 Files selected for processing (16)
  • packages/builder/src/breadcrumb.test.tsx
  • packages/builder/src/breadcrumb.tsx
  • packages/builder/src/canvas-drag.test.tsx
  • packages/builder/src/canvas-drag.tsx
  • packages/builder/src/index.ts
  • packages/builder/src/inserter.ts
  • packages/builder/src/inspector.ts
  • packages/builder/src/keyboard-actions.test.tsx
  • packages/builder/src/keyboard-actions.tsx
  • packages/builder/src/layers-panel.test.tsx
  • packages/builder/src/layers-panel.tsx
  • packages/builder/src/layers.test.ts
  • packages/builder/src/layers.ts
  • packages/builder/src/shell.ts
  • packages/builder/src/styles/builder-chrome.css
  • packages/plugin-page-builder/src/admin/BlocksField.tsx

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.

@greptile-apps

greptile-apps Bot commented Aug 18, 2026

Copy link
Copy Markdown

Greptile Summary

Adds a virtualized layers tree, searchable structural model, ancestor breadcrumb, and page-builder shell integration, while also changing canvas pointer capture to restore click selection.

  • Derives block labels, hierarchy paths, visibility badges, and filtered layer trees from BlockDocument data.
  • Adds selection-driven and search-driven expansion behavior through the shared TreeView.
  • Integrates Layers and breadcrumb controls into the plugin page-builder editor.
  • Delays pointer capture until drag activation and adds associated gesture tests.

Confidence Score: 2/5

The PR is not yet safe to merge because pointer gestures can remain stale and the layers panel can hide selected or searched-for descendants.

Delayed pointer capture lacks cleanup for releases outside the canvas, selection expansion is not recomputed after moves, and matching collapsed containers are not temporarily expanded during search; the duplicate changesets also need consolidation.

Files Needing Attention: packages/builder/src/canvas-drag.tsx, packages/builder/src/layers-panel.tsx, packages/builder/src/layers.ts, and the two new changeset files

Important Files Changed

Filename Overview
packages/builder/src/canvas-drag.tsx Delays pointer capture until activation but leaves an unactivated gesture stale when release occurs outside the canvas.
packages/builder/src/layers-panel.tsx Implements tree rendering and temporary expansion, but does not refresh selection ancestors when the selected node moves.
packages/builder/src/layers.ts Adds hierarchy and search derivation, but direct container matches are not temporarily expanded to reveal their retained children.
packages/builder/src/breadcrumb.tsx Renders the selected node's ancestor path and selects crumbs without an identified defect.
packages/plugin-page-builder/src/admin/BlocksField.tsx Integrates the new layers panel and breadcrumb into the full-screen builder shell.
.changeset/canvas-click-selects-again.md Introduces one of two all-package changesets where repository policy requires a single combined changeset.
.changeset/layers-panel-and-breadcrumb.md Introduces the second all-package changeset that should be consolidated with the first.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Document[BlockDocument] --> Layers[layersOf / filterLayers]
  Selection[Editor selection] --> Expansion[Ancestor expansion]
  Layers --> Panel[LayersPanel / TreeView]
  Expansion --> Panel
  Document --> Path[pathTo]
  Selection --> Path
  Path --> Breadcrumb[SelectionBreadcrumb]
  Panel -->|select row| Selection
  Breadcrumb -->|select ancestor| Selection
Loading

Fix all with Greploop Fix All in Claude Code

Prompt To Fix All With AI
### Issue 1
packages/builder/src/canvas-drag.tsx:237
**Unreleased presses leave stale gestures**

When a press leaves the canvas before crossing the activation threshold and is released outside, the root receives no release or cancellation because capture has not started. The stored gesture then activates on a later hover without checking the pointer or button state, allowing the old block to be selected or moved without a current drag.

### Issue 2
packages/builder/src/layers-panel.tsx:140
**Moved selections lose ancestor expansion**

When the selected block is dragged or keyboard-indented into a collapsed container, the document changes while `selectedId` remains the same, so this effect does not add the new ancestors to `opened`. `TreeView` then omits the selected descendant, causing the selected block to disappear from the layers panel.

### Issue 3
packages/builder/src/layers.ts:206-210
**Matching containers remain collapsed**

When a query directly matches a collapsed container, this branch retains its children but does not add the container to `expand`. Because the panel expands only author-opened IDs and `search.expand`, the search displays the container while hiding the subtree it is documented to reveal.

### Issue 4
.changeset/canvas-click-selects-again.md:1
**Duplicate lockstep changesets**

This PR adds two separate all-packages patch changesets, while the repository's lockstep release policy requires one changeset per PR. Consolidating them preserves a single release entry for the combined stacked changes.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "test(builder): cover the breadcrumb's ow..." | Re-trigger Greptile

// delivering. Without it a drag that wanders outside simply stops
// reporting, and the gesture ends wherever the pointer happened to exit.
root.setPointerCapture(event.pointerId);
// NOT captured here. See the activation branch in `onPointerMove`.

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 Unreleased presses leave stale gestures

When a press leaves the canvas before crossing the activation threshold and is released outside, the root receives no release or cancellation because capture has not started. The stored gesture then activates on a later hover without checking the pointer or button state, allowing the old block to be selected or moved without a current drag.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/builder/src/canvas-drag.tsx
Line: 237

Comment:
**Unreleased presses leave stale gestures**

When a press leaves the canvas before crossing the activation threshold and is released outside, the root receives no release or cancellation because capture has not started. The stored gesture then activates on a later hover without checking the pointer or button state, allowing the old block to be selected or moved without a current drag.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code

// effect re-rendering forever: a new array every run is a new state value.
return missing.length === 0 ? previous : [...previous, ...missing];
});
}, [editor.selectedId]);

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 Moved selections lose ancestor expansion

When the selected block is dragged or keyboard-indented into a collapsed container, the document changes while selectedId remains the same, so this effect does not add the new ancestors to opened. TreeView then omits the selected descendant, causing the selected block to disappear from the layers panel.

Knowledge Base Used: Page Builder plugin

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/builder/src/layers-panel.tsx
Line: 140

Comment:
**Moved selections lose ancestor expansion**

When the selected block is dragged or keyboard-indented into a collapsed container, the document changes while `selectedId` remains the same, so this effect does not add the new ancestors to `opened`. `TreeView` then omits the selected descendant, causing the selected block to disappear from the layers panel.

**Knowledge Base Used:** [Page Builder plugin](https://app.greptile.com/nextly/-/custom-context/knowledge-base/nextlyhq/nextly/-/docs/plugin-page-builder.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code

Comment on lines +206 to +210
if (matches(node, needle)) {
// Kept whole. Its descendants are the contents of a thing the author
// asked for, and hiding them would answer a narrower question than the
// one they typed.
return [node];

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 Matching containers remain collapsed

When a query directly matches a collapsed container, this branch retains its children but does not add the container to expand. Because the panel expands only author-opened IDs and search.expand, the search displays the container while hiding the subtree it is documented to reveal.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/builder/src/layers.ts
Line: 206-210

Comment:
**Matching containers remain collapsed**

When a query directly matches a collapsed container, this branch retains its children but does not add the container to `expand`. Because the panel expands only author-opened IDs and `search.expand`, the search displays the container while hiding the subtree it is documented to reveal.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code

@@ -0,0 +1,32 @@
---

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Duplicate lockstep changesets

This PR adds two separate all-packages patch changesets, while the repository's lockstep release policy requires one changeset per PR. Consolidating them preserves a single release entry for the combined stacked changes.

Rule Used: In the nextlyhq/nextly repo, every PR must include... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: .changeset/canvas-click-selects-again.md
Line: 1

Comment:
**Duplicate lockstep changesets**

This PR adds two separate all-packages patch changesets, while the repository's lockstep release policy requires one changeset per PR. Consolidating them preserves a single release entry for the combined stacked changes.

**Rule Used:** In the nextlyhq/nextly repo, every PR must include... ([source](https://app.greptile.com/nextly/github/nextlyhq/nextly/-/custom-context?memory=376ea7a2-1076-49e6-bbd9-dd342f286b4e))

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

@pkg-pr-new

pkg-pr-new Bot commented Aug 18, 2026

Copy link
Copy Markdown

Open in StackBlitz

@nextlyhq/adapter-drizzle

npm i https://pkg.pr.new/@nextlyhq/adapter-drizzle@3727712

@nextlyhq/adapter-mysql

npm i https://pkg.pr.new/@nextlyhq/adapter-mysql@3727712

@nextlyhq/adapter-postgres

npm i https://pkg.pr.new/@nextlyhq/adapter-postgres@3727712

@nextlyhq/adapter-sqlite

npm i https://pkg.pr.new/@nextlyhq/adapter-sqlite@3727712

@nextlyhq/admin

npm i https://pkg.pr.new/@nextlyhq/admin@3727712

@nextlyhq/admin-css

npm i https://pkg.pr.new/@nextlyhq/admin-css@3727712

@nextlyhq/blocks-engine

npm i https://pkg.pr.new/@nextlyhq/blocks-engine@3727712

@nextlyhq/blocks-react

npm i https://pkg.pr.new/@nextlyhq/blocks-react@3727712

@nextlyhq/builder

npm i https://pkg.pr.new/@nextlyhq/builder@3727712

create-nextly-app

npm i https://pkg.pr.new/create-nextly-app@3727712

@nextlyhq/eslint-plugin

npm i https://pkg.pr.new/@nextlyhq/eslint-plugin@3727712

nextly

npm i https://pkg.pr.new/nextly@3727712

@nextlyhq/plugin-form-builder

npm i https://pkg.pr.new/@nextlyhq/plugin-form-builder@3727712

@nextlyhq/plugin-page-builder

npm i https://pkg.pr.new/@nextlyhq/plugin-page-builder@3727712

@nextlyhq/plugin-sdk

npm i https://pkg.pr.new/@nextlyhq/plugin-sdk@3727712

@nextlyhq/plugin-seo

npm i https://pkg.pr.new/@nextlyhq/plugin-seo@3727712

@nextlyhq/storage-s3

npm i https://pkg.pr.new/@nextlyhq/storage-s3@3727712

@nextlyhq/storage-uploadthing

npm i https://pkg.pr.new/@nextlyhq/storage-uploadthing@3727712

@nextlyhq/storage-vercel-blob

npm i https://pkg.pr.new/@nextlyhq/storage-vercel-blob@3727712

@nextlyhq/ui

npm i https://pkg.pr.new/@nextlyhq/ui@3727712

commit: 3727712

@github-actions

Copy link
Copy Markdown
Contributor

Fallow audit report

Found 41 findings.

Dependencies (40)
Severity Rule Location Description
major fallow/unused-dependency apps/playground/package.json:24 Package '@nextlyhq/adapter-drizzle' is in dependencies but never imported; imported in other workspaces: packages/adapter-mysql, packages/adapter-postgres, packages/adapter-sqlite, packages/nextly
major fallow/unused-dependency apps/playground/package.json:25 Package '@nextlyhq/adapter-mysql' is in dependencies but never imported; imported in other workspaces: packages/nextly
major fallow/unused-dependency apps/playground/package.json:26 Package '@nextlyhq/adapter-postgres' is in dependencies but never imported; imported in other workspaces: packages/nextly
major fallow/unused-dependency apps/playground/package.json:27 Package '@nextlyhq/adapter-sqlite' is in dependencies but never imported; imported in other workspaces: packages/nextly
major fallow/unused-dependency apps/playground/package.json:42 Package 'sharp' is in dependencies but never imported; imported in other workspaces: packages/nextly
minor fallow/unused-dev-dependency apps/playground/package.json:45 Package '@eslint/eslintrc' is in devDependencies but never imported
minor fallow/unused-dev-dependency apps/playground/package.json:54 Package 'better-sqlite3' is in devDependencies but never imported; imported in other workspaces: packages/adapter-sqlite, packages/nextly
minor fallow/unused-dev-dependency apps/playground/package.json:55 Package 'culori' is in devDependencies but never imported; imported in other workspaces: packages/ui
minor fallow/unused-dev-dependency e2e/package.json:17 Package '@nextlyhq/adapter-drizzle' is in devDependencies but never imported; imported in other workspaces: packages/adapter-mysql, packages/adapter-postgres, packages/adapter-sqlite, packages/nextly
minor fallow/unused-dev-dependency e2e/package.json:18 Package '@nextlyhq/adapter-sqlite' is in devDependencies but never imported; imported in other workspaces: packages/nextly
minor fallow/unused-dev-dependency e2e/package.json:22 Package '@nextlyhq/plugin-form-builder' is in devDependencies but never imported; imported in other workspaces: apps/playground
minor fallow/unused-dev-dependency e2e/package.json:23 Package '@nextlyhq/plugin-page-builder' is in devDependencies but never imported; imported in other workspaces: apps/playground
minor fallow/dev-dependency-in-production package.json:92 devDependency '@manypkg/get-packages' is imported by production code at runtime (consider moving to dependencies)
minor fallow/dev-dependency-in-production package.json:104 devDependency 'micromatch' is imported by production code at runtime (consider moving to dependencies)
minor fallow/unused-dev-dependency package.json:106 Package 'publint' is in devDependencies but never imported
major fallow/unused-dependency packages/admin/package.json:110 Package '@lexical/history' is in dependencies but never imported
major fallow/unused-dependency packages/admin/package.json:119 Package '@radix-ui/react-accordion' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:120 Package '@radix-ui/react-alert-dialog' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:121 Package '@radix-ui/react-avatar' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:122 Package '@radix-ui/react-checkbox' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:123 Package '@radix-ui/react-collapsible' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:124 Package '@radix-ui/react-dialog' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:125 Package '@radix-ui/react-dropdown-menu' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:127 Package '@radix-ui/react-popover' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:128 Package '@radix-ui/react-radio-group' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:129 Package '@radix-ui/react-select' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:130 Package '@radix-ui/react-separator' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:132 Package '@radix-ui/react-switch' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:133 Package '@radix-ui/react-tabs' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:134 Package '@radix-ui/react-tooltip' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:140 Package 'cmdk' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:149 Package 'tailwind-variants' is in dependencies but never imported
major fallow/unused-dependency packages/admin/package.json:150 Package 'tailwindcss-animate' is in dependencies but never imported
minor fallow/unused-dev-dependency packages/builder/package.json:68 Package '@nextlyhq/plugin-sdk' is in devDependencies but never imported; imported in other workspaces: apps/playground, packages/plugin-form-builder, packages/plugin-page-builder, packages/plugin-sdk, packages/plugin-seo
major fallow/unused-dependency packages/plugin-page-builder/package.json:51 Package '@dnd-kit/dom' is in dependencies but never imported
major fallow/unused-dependency packages/plugin-page-builder/package.json:52 Package '@dnd-kit/react' is in dependencies but never imported
major fallow/unused-dependency packages/plugin-page-builder/package.json:56 Package 'isomorphic-dompurify' is in dependencies but never imported; imported in other workspaces: packages/nextly
minor fallow/unused-dev-dependency packages/plugin-page-builder/package.json:63 Package '@tanstack/react-query' is in devDependencies but never imported; imported in other workspaces: packages/admin, packages/plugin-form-builder
minor fallow/unused-dev-dependency packages/plugin-page-builder/package.json:72 Package '@dnd-kit/abstract' is in devDependencies but never imported
major fallow/unused-dependency packages/telemetry/package.json:32 Package 'env-paths' is in dependencies but never imported
Health (1)
Severity Rule Location Description
minor fallow/css-token-drift packages/builder/src/styles/builder-chrome.css:533 [css-token-drift] raw-style-value: font-size font-size: .75rem

Generated by fallow.

@github-actions github-actions Bot added type: docs Documentation only scope: plugin @nextlyhq/plugin-* packages labels Aug 18, 2026
@mobeenabdullah
mobeenabdullah merged commit ed47f82 into main Aug 18, 2026
25 of 26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: plugin @nextlyhq/plugin-* packages type: docs Documentation only

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant