Polish FileTree, Prompt, and TopicSwitcher in docs example#23
Conversation
📝 WalkthroughSummary by CodeRabbit
WalkthroughThis PR adds three MDX components (Audience, FileTree, Prompt) with TypeScript contracts and React UIs, implements remark transformers to convert them to Markdown, adjusts the JSX processor skip behavior, wires the plugins into the default remark pipeline, and updates app exports, styles, docs, and tests. ChangesAudience-aware Documentation Components with Markdown Conversion
Sequence Diagram(s)sequenceDiagram
participant MDXParser as MDX Parser
participant remarkAudience as remarkAudienceToMarkdown
participant remarkFileTree as remarkFileTreeToMarkdown
participant remarkPrompt as remarkPromptToMarkdown
participant MarkdownOut as Markdown AST
MDXParser->>remarkAudience: encounter <Audience target="...">
remarkAudience-->>MarkdownOut: omit or forward children
MDXParser->>remarkFileTree: encounter <FileTree root="...">
remarkFileTree-->>MarkdownOut: emit code(lang:text) block
MDXParser->>remarkPrompt: encounter <Prompt>
remarkPrompt-->>MarkdownOut: emit paragraphs + code(lang:prompt)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e6b921468f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const target = normalizeTarget(getAttributeValue(node, "target")); | ||
|
|
||
| if (target === TARGET_HUMAN) { |
There was a problem hiding this comment.
Normalize string-expression audience targets
When authors use valid JSX string-expression syntax such as <Audience target={'human'}>, getAttributeValue returns the raw expression text including quotes, so normalizeTarget(...) produces "human" rather than human and this check does not remove the human-only block from generated agent/search markdown. Parse or unwrap string-literal expressions before comparing the target value.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 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 `@apps/example/src/components/docs-mdx/file-tree.tsx`:
- Around line 96-118: The Folder component currently binds defaultOpen directly
to the details open prop, which makes it controlled by props and causes parent
rerenders to override user toggles; change Folder to manage its own open state:
add a useState hook like const [isOpen, setIsOpen] = useState(defaultOpen) and
attach an onToggle handler to the <details> element that updates setIsOpen((e)
=> (e.target as HTMLDetailsElement).open), then pass open={isOpen} (instead of
open={defaultOpen}) so user interactions update internal state and parent
rerenders no longer clobber the toggle; reference Folder, FolderProps,
defaultOpen, isOpen, and the details onToggle handler in your changes.
In `@apps/example/src/components/docs-mdx/prompt.tsx`:
- Around line 134-147: The copyPrompt function uses promise chains
(.then/.catch) for navigator.clipboard.writeText; refactor it to an async
function that awaits navigator.clipboard.writeText(text) inside a try/catch,
returning early if text is falsy (using contentRef.current?.innerText.trim()),
call setCopied(true) and schedule setCopied(false) with
window.setTimeout(COPIED_TIMEOUT_MS) on success, and in the catch block ensure
setCopied(false) (and optionally log the error); update the function signature
to async and keep references to contentRef, setCopied, COPIED_TIMEOUT_MS, and
navigator.clipboard.writeText.
In `@apps/example/src/styles.css`:
- Around line 484-485: The toggle icon selector
[data-leadtype-prompt-toggle-icon] currently always animates; add a
prefers-reduced-motion media override that disables the transform/rotation
transition for that selector (and the other identical occurrence) by setting
transitions to none so users who request reduced motion won't see the rotation
animations; update the CSS to include a `@media` (prefers-reduced-motion: reduce)
rule targeting [data-leadtype-prompt-toggle-icon] that removes or overrides the
transition (e.g., transition: none or Tailwind's transition-none utility).
- Around line 103-123: The current .docs-prose rules (e.g., the selectors
targeting p:not([data-leadtype-prompt-description]),
a:not([data-leadtype-card])..., and ul:not([data-leadtype-file-tree-list])...)
still match elements inside a prompt container; update those selectors so they
also exclude any element that is a descendant of [data-leadtype-prompt-content]
(and the same set used at lines 131-136). In practice, modify the selectors to
not match when the element is inside [data-leadtype-prompt-content] (for example
by adding an exclusion for descendants of [data-leadtype-prompt-content]) so
prompt body paragraphs/lists/links inherit the prompt-specific styling instead
of the generic .docs-prose resets.
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: b3d1c504-3b08-4f9f-97e9-518d2041055c
⛔ Files ignored due to path filters (3)
apps/example/src/generated/agent-readability.jsonis excluded by!**/generated/**apps/example/src/generated/docs-search-content.jsonis excluded by!**/generated/**apps/example/src/generated/docs-search-index.jsonis excluded by!**/generated/**
📒 Files selected for processing (19)
apps/example/src/components/docs-mdx/audience.tsxapps/example/src/components/docs-mdx/file-tree.tsxapps/example/src/components/docs-mdx/index.tsapps/example/src/components/docs-mdx/mdx-components.tsapps/example/src/components/docs-mdx/prompt.tsxapps/example/src/components/docs-mdx/topic-switcher.tsxapps/example/src/lib/docs.tsapps/example/src/styles.cssdocs/authoring/components.mdxdocs/build/bundle-package-docs.mdxdocs/build/connect-docs-site.mdxdocs/quickstart.mdxdocs/reference/remark.mdxpackages/leadtype/src/remark/index.tspackages/leadtype/src/remark/libs/generic-processor.tspackages/leadtype/src/remark/plugins/audience.remark.tspackages/leadtype/src/remark/plugins/file-tree.remark.tspackages/leadtype/src/remark/plugins/prompt.remark.tspackages/leadtype/src/remark/remark-output.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Preferunknownoveranywhen the type is genuinely unknown
Use const assertions (as const) for immutable values and literal types
Leverage TypeScript's type narrowing instead of type assertions
Files:
packages/leadtype/src/remark/plugins/audience.remark.tsapps/example/src/components/docs-mdx/mdx-components.tsapps/example/src/components/docs-mdx/audience.tsxpackages/leadtype/src/remark/plugins/file-tree.remark.tsapps/example/src/lib/docs.tspackages/leadtype/src/remark/remark-output.test.tsapps/example/src/components/docs-mdx/topic-switcher.tsxpackages/leadtype/src/remark/libs/generic-processor.tsapps/example/src/components/docs-mdx/prompt.tsxpackages/leadtype/src/remark/plugins/prompt.remark.tspackages/leadtype/src/remark/index.tsapps/example/src/components/docs-mdx/file-tree.tsxapps/example/src/components/docs-mdx/index.ts
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Use arrow functions for callbacks and short functions
Preferfor...ofloops over.forEach()and indexedforloops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Useconstby default,letonly when reassignment is needed, nevervar
Alwaysawaitpromises in async functions - don't forget to use the return value
Useasync/awaitsyntax instead of promise chains for better readability
Handle errors appropriately in async code with try-catch blocks
Don't use async functions as Promise executors
Removeconsole.log,debugger, andalertstatements from production code
ThrowErrorobjects with descriptive messages, not strings or other values
Usetry-catchblocks meaningfully - don't catch errors just to rethrow them
Prefer early returns over nested conditionals for error cases
Extract complex conditions into well-named boolean variables
Use early returns to reduce nesting
Prefer simple conditionals over nested ternary operators
Don't useeval()or assign directly todocument.cookie
Avoid spread syntax in accumulators within loops
Use top-level regex literals instead of creating them in loops
Prefer specific imports over namespace imports
Use descriptive names for functions, variables, and types for meaningful naming
Add comments for complex logic, but prefer self-documenting code
Files:
packages/leadtype/src/remark/plugins/audience.remark.tsapps/example/src/components/docs-mdx/mdx-components.tsapps/example/src/components/docs-mdx/audience.tsxpackages/leadtype/src/remark/plugins/file-tree.remark.tsapps/example/src/lib/docs.tspackages/leadtype/src/remark/remark-output.test.tsapps/example/src/components/docs-mdx/topic-switcher.tsxpackages/leadtype/src/remark/libs/generic-processor.tsapps/example/src/components/docs-mdx/prompt.tsxpackages/leadtype/src/remark/plugins/prompt.remark.tspackages/leadtype/src/remark/index.tsapps/example/src/components/docs-mdx/file-tree.tsxapps/example/src/components/docs-mdx/index.ts
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{jsx,tsx}: Use function components over class components in React
Call hooks at the top level only, never conditionally
Specify all dependencies in hook dependency arrays correctly
Use thekeyprop for elements in iterables (prefer unique IDs over array indices)
Nest children between opening and closing tags instead of passing as props
Don't define components inside other components
AvoiddangerouslySetInnerHTMLunless absolutely necessary
Use proper image components (e.g., Next.js<Image>) over<img>tags
Use Next.js<Image>component for images
Usenext/heador App Router metadata API for head elements in Next.js
Use Server Components for async data fetching instead of async Client Components in Next.js
Use ref as a prop instead ofReact.forwardRefin React 19+
Files:
apps/example/src/components/docs-mdx/audience.tsxapps/example/src/components/docs-mdx/topic-switcher.tsxapps/example/src/components/docs-mdx/prompt.tsxapps/example/src/components/docs-mdx/file-tree.tsx
**/*.{jsx,tsx,html}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{jsx,tsx,html}: Use semantic HTML and ARIA attributes for accessibility: provide meaningful alt text for images, use proper heading hierarchy, add labels for form inputs, include keyboard event handlers alongside mouse events, use semantic elements instead of divs with roles
Addrel="noopener"when usingtarget="_blank"on links
Files:
apps/example/src/components/docs-mdx/audience.tsxapps/example/src/components/docs-mdx/topic-switcher.tsxapps/example/src/components/docs-mdx/prompt.tsxapps/example/src/components/docs-mdx/file-tree.tsx
**/*.{test,spec}.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{test,spec}.{js,ts,jsx,tsx}: Write assertions insideit()ortest()blocks
Avoid done callbacks in async tests - use async/await instead
Don't use.onlyor.skipin committed code
Keep test suites reasonably flat - avoid excessivedescribenesting
Files:
packages/leadtype/src/remark/remark-output.test.ts
**/index.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Avoid barrel files (index files that re-export everything)
Files:
packages/leadtype/src/remark/index.tsapps/example/src/components/docs-mdx/index.ts
🪛 LanguageTool
docs/reference/remark.mdx
[uncategorized] ~55-~55: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...mandTabsToMarkdown—→ markdown table. 11.remarkStepsToMarkdown—<...
(MARKDOWN_NNP)
[uncategorized] ~58-~58: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...ypeTable>and→ markdown table. 14.remarkAccordionToMarkdown` ...
(MARKDOWN_NNP)
🔍 Remote MCP
PR Review Context Summary
Based on your requirements and the PR changes, here's relevant technical context from documentation sources:
Remark Plugin Architecture & Best Practices
The PR introduces three new remark plugins following standard unified ecosystem patterns. Key insights:
Custom remark plugins are built using the unist-util-visit helper to traverse and modify the tree structure, allowing for programmatic manipulation of markdown content before it is rendered or processed further.
The plugins in this PR (remarkAudienceToMarkdown, remarkFileTreeToMarkdown, remarkPromptToMarkdown) follow the documented pattern: they export a function that returns a Transformer<Root, Root> — the standard structure shown in the Context7 examples for remark plugins.
AST Traversal & Node Manipulation
The PR modifies generic-processor.ts to return tuple-based skip signals [SKIP, index]. This aligns with documented unist-util-visit behavior:
When visitors remove or insert siblings before the current node, returning the correct new index maintains consistent traversal, and using SKIP prevents descending into subtrees. Specifically, the visitor function can return [SKIP, index] to skip the current node's children and move to the sibling at the given index next.
The PR's change from return SKIP to return [SKIP, index] after parent.children.splice() is the correct pattern when the child array is modified in-place, as it prevents the visitor from accidentally processing the wrong node after removal/insertion.
Markdown Serialization
The prompt.remark.ts plugin uses mdast-util-to-markdown with customized options. The toMarkdown function serializes mdast syntax trees into markdown strings and accepts custom Join handlers to control how block-level elements are joined. The PR's use of custom fence and emphasis formatting options follows this documented extension pattern.
Architecture Alignment
All three new plugins integrate into the defaultRemarkPlugins pipeline in a logical sequence — converting JSX components (Audience, Prompt, FileTree) to their markdown equivalents before the final cleanup step. This is consistent with how the remark ecosystem chains transformers.
[Context7::Context7_query-docs::], [Context7::Context7_resolve-library-id::]
🔇 Additional comments (16)
packages/leadtype/src/remark/libs/generic-processor.ts (1)
55-67: Correct visitor index handling after splice mutations.Returning
[SKIP, index]here is the right control signal after child-array mutation and avoids traversal drift.docs/build/bundle-package-docs.mdx (1)
49-58: Good switch to structuredFileTreeexample.This makes the output section consistent with the new component-driven docs authoring flow.
apps/example/src/components/docs-mdx/topic-switcher.tsx (1)
23-31: Variant auto-selection implementation looks solid.
hasDescriptions→data-variantis clear and should pair cleanly with the updated CSS variants.docs/build/connect-docs-site.mdx (1)
142-144: Strong agent-specific routing guidance.This addition clarifies hook ordering and avoids common endpoint interception mistakes.
docs/quickstart.mdx (1)
66-82: Nice quickstart polish withFileTree+Prompt.These changes make the generated artifacts and next-step agent workflow much clearer for readers.
Also applies to: 86-91
apps/example/src/lib/docs.ts (1)
164-178: Component matrix updates are aligned and consistent.The new entries correctly reflect the expanded docs component surface.
docs/reference/remark.mdx (1)
26-43: Pipeline documentation update is coherent and correctly ordered.The new stages and numbering read consistently with the current default remark flow.
Also applies to: 49-63
apps/example/src/components/docs-mdx/mdx-components.ts (1)
2-9: MDX component registry wiring looks complete.All newly introduced docs components are correctly imported and exposed.
Also applies to: 19-29
packages/leadtype/src/remark/remark-output.test.ts (1)
294-369: Strong test coverage for the new flattening plugins.These additions clearly validate Prompt/Audience/FileTree conversions and ensure plugin registration stays enforced in the default pipeline.
Also applies to: 425-428
apps/example/src/components/docs-mdx/index.ts (1)
8-12: Export surface looks consistent and complete.The added component/type re-exports line up with the new docs-MDX component set.
Also applies to: 26-33, 39-39
packages/leadtype/src/remark/plugins/file-tree.remark.ts (1)
17-113: Clean transformer implementation with stable tree rendering.Parsing and rendering flow is straightforward, and the empty-content behavior is handled safely.
docs/authoring/components.mdx (1)
26-27: Docs updates are clear and aligned with the new component contract.The added Prompt/Audience/FileTree sections and examples read consistently with the pipeline behavior.
Also applies to: 40-44, 146-202
packages/leadtype/src/remark/plugins/audience.remark.ts (1)
16-29: Behavior matches expected audience filtering semantics.The transformer correctly omits
target="human"content while preserving agent-facing content for markdown output.packages/leadtype/src/remark/index.ts (1)
10-10: Default remark pipeline update looks correct.The newly added plugin registrations are wired cleanly into the conversion sequence.
Also applies to: 17-19, 37-50
packages/leadtype/src/remark/plugins/prompt.remark.ts (1)
20-59: Prompt-to-markdown transformer is well-structured.The conversion output shape and conditional emission logic are solid.
apps/example/src/components/docs-mdx/prompt.tsx (1)
118-132: Overflow detection/toggle visibility logic is clean.The observer-based measurement and cleanup are implemented correctly for this UX behavior.
e6b9214 to
ec9f205
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
apps/example/src/styles.css (1)
557-559:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAdd
prefers-reduced-motionhandling for the file-tree chevron.The prompt toggle icon correctly disables transitions under
prefers-reduced-motion(lines 498-502), but the file-tree chevron rotation (line 576) lacks the same treatment. Since reduced-motion coverage is part of this PR's test plan, the chevron should also respect this preference.🛡️ Suggested fix
`@media` (prefers-reduced-motion: reduce) { [data-leadtype-prompt-toggle-icon] { transition: none; } + [data-leadtype-file-tree-chevron] { + transition: none; + } }Add this to the existing media query block at lines 498-502.
🤖 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 `@apps/example/src/styles.css` around lines 557 - 559, The file-tree chevron selector [data-leadtype-file-tree-chevron] lacks prefers-reduced-motion handling; update the existing prefers-reduced-motion media query (the same block that disables transitions for the prompt toggle icon) to include [data-leadtype-file-tree-chevron] and disable its transform/transition there so the chevron rotation does not animate when the user prefers reduced motion.
🤖 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 `@docs/authoring/components.mdx`:
- Line 149: The documentation mentions the artifact path "llms-full.txt" which
is incorrect; update the reference in docs/authoring/components.mdx so it uses
the correct pattern "llms-full/*.txt" (matching the generated shape of multiple
leaf files) wherever "llms-full.txt" appears to ensure verification steps use
the correct glob pattern.
In `@docs/quickstart.mdx`:
- Line 71: Remove the incorrect static entry "<File name=\"llms-full.txt\" />"
from docs/quickstart.mdx (the <File ... /> element) because it conflicts with
the existing pattern "public/docs/llms-full/*.txt"; either delete that <File ...
/> line or replace it with the correct glob entry matching the generated files
(e.g., use the existing public/docs/llms-full/*.txt pattern) so the docs
reference the actual generated files.
In `@packages/leadtype/src/remark/plugins/audience.remark.ts`:
- Around line 41-45: The two identical return paths for (node.children ?? []) as
RootContent[] are redundant; remove the conditional block that checks
TARGET_AGENT and instead have a single return of (node.children ?? []) as
RootContent[] in the audience remark logic (remove the if (target ===
TARGET_AGENT || target.length === 0) { ... } branch and keep the final return),
keeping the cast and nullish fallback intact so behavior is unchanged.
---
Duplicate comments:
In `@apps/example/src/styles.css`:
- Around line 557-559: The file-tree chevron selector
[data-leadtype-file-tree-chevron] lacks prefers-reduced-motion handling; update
the existing prefers-reduced-motion media query (the same block that disables
transitions for the prompt toggle icon) to include
[data-leadtype-file-tree-chevron] and disable its transform/transition there so
the chevron rotation does not animate when the user prefers reduced motion.
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: ed57ac3a-9916-4096-9c72-43a54a9d594b
⛔ Files ignored due to path filters (3)
apps/example/src/generated/agent-readability.jsonis excluded by!**/generated/**apps/example/src/generated/docs-search-content.jsonis excluded by!**/generated/**apps/example/src/generated/docs-search-index.jsonis excluded by!**/generated/**
📒 Files selected for processing (19)
apps/example/src/components/docs-mdx/audience.tsxapps/example/src/components/docs-mdx/file-tree.tsxapps/example/src/components/docs-mdx/index.tsapps/example/src/components/docs-mdx/mdx-components.tsapps/example/src/components/docs-mdx/prompt.tsxapps/example/src/components/docs-mdx/topic-switcher.tsxapps/example/src/lib/docs.tsapps/example/src/styles.cssdocs/authoring/components.mdxdocs/build/bundle-package-docs.mdxdocs/build/connect-docs-site.mdxdocs/quickstart.mdxdocs/reference/remark.mdxpackages/leadtype/src/remark/index.tspackages/leadtype/src/remark/libs/generic-processor.tspackages/leadtype/src/remark/plugins/audience.remark.tspackages/leadtype/src/remark/plugins/file-tree.remark.tspackages/leadtype/src/remark/plugins/prompt.remark.tspackages/leadtype/src/remark/remark-output.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Preferunknownoveranywhen the type is genuinely unknown
Use const assertions (as const) for immutable values and literal types
Leverage TypeScript's type narrowing instead of type assertions
Files:
packages/leadtype/src/remark/plugins/prompt.remark.tsapps/example/src/lib/docs.tsapps/example/src/components/docs-mdx/topic-switcher.tsxapps/example/src/components/docs-mdx/mdx-components.tspackages/leadtype/src/remark/plugins/audience.remark.tsapps/example/src/components/docs-mdx/audience.tsxpackages/leadtype/src/remark/libs/generic-processor.tspackages/leadtype/src/remark/remark-output.test.tspackages/leadtype/src/remark/plugins/file-tree.remark.tsapps/example/src/components/docs-mdx/index.tspackages/leadtype/src/remark/index.tsapps/example/src/components/docs-mdx/prompt.tsxapps/example/src/components/docs-mdx/file-tree.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Use arrow functions for callbacks and short functions
Preferfor...ofloops over.forEach()and indexedforloops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Useconstby default,letonly when reassignment is needed, nevervar
Alwaysawaitpromises in async functions - don't forget to use the return value
Useasync/awaitsyntax instead of promise chains for better readability
Handle errors appropriately in async code with try-catch blocks
Don't use async functions as Promise executors
Removeconsole.log,debugger, andalertstatements from production code
ThrowErrorobjects with descriptive messages, not strings or other values
Usetry-catchblocks meaningfully - don't catch errors just to rethrow them
Prefer early returns over nested conditionals for error cases
Extract complex conditions into well-named boolean variables
Use early returns to reduce nesting
Prefer simple conditionals over nested ternary operators
Don't useeval()or assign directly todocument.cookie
Avoid spread syntax in accumulators within loops
Use top-level regex literals instead of creating them in loops
Prefer specific imports over namespace imports
Use descriptive names for functions, variables, and types for meaningful naming
Add comments for complex logic, but prefer self-documenting code
Files:
packages/leadtype/src/remark/plugins/prompt.remark.tsapps/example/src/lib/docs.tsapps/example/src/components/docs-mdx/topic-switcher.tsxapps/example/src/components/docs-mdx/mdx-components.tspackages/leadtype/src/remark/plugins/audience.remark.tsapps/example/src/components/docs-mdx/audience.tsxpackages/leadtype/src/remark/libs/generic-processor.tspackages/leadtype/src/remark/remark-output.test.tspackages/leadtype/src/remark/plugins/file-tree.remark.tsapps/example/src/components/docs-mdx/index.tspackages/leadtype/src/remark/index.tsapps/example/src/components/docs-mdx/prompt.tsxapps/example/src/components/docs-mdx/file-tree.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{jsx,tsx}: Use function components over class components in React
Call hooks at the top level only, never conditionally
Specify all dependencies in hook dependency arrays correctly
Use thekeyprop for elements in iterables (prefer unique IDs over array indices)
Nest children between opening and closing tags instead of passing as props
Don't define components inside other components
AvoiddangerouslySetInnerHTMLunless absolutely necessary
Use proper image components (e.g., Next.js<Image>) over<img>tags
Use Next.js<Image>component for images
Usenext/heador App Router metadata API for head elements in Next.js
Use Server Components for async data fetching instead of async Client Components in Next.js
Use ref as a prop instead ofReact.forwardRefin React 19+
Files:
apps/example/src/components/docs-mdx/topic-switcher.tsxapps/example/src/components/docs-mdx/audience.tsxapps/example/src/components/docs-mdx/prompt.tsxapps/example/src/components/docs-mdx/file-tree.tsx
**/*.{jsx,tsx,html}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{jsx,tsx,html}: Use semantic HTML and ARIA attributes for accessibility: provide meaningful alt text for images, use proper heading hierarchy, add labels for form inputs, include keyboard event handlers alongside mouse events, use semantic elements instead of divs with roles
Addrel="noopener"when usingtarget="_blank"on links
Files:
apps/example/src/components/docs-mdx/topic-switcher.tsxapps/example/src/components/docs-mdx/audience.tsxapps/example/src/components/docs-mdx/prompt.tsxapps/example/src/components/docs-mdx/file-tree.tsx
**/*.{test,spec}.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{test,spec}.{js,ts,jsx,tsx}: Write assertions insideit()ortest()blocks
Avoid done callbacks in async tests - use async/await instead
Don't use.onlyor.skipin committed code
Keep test suites reasonably flat - avoid excessivedescribenesting
Files:
packages/leadtype/src/remark/remark-output.test.ts
**/index.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Avoid barrel files (index files that re-export everything)
Files:
apps/example/src/components/docs-mdx/index.tspackages/leadtype/src/remark/index.ts
🪛 LanguageTool
docs/reference/remark.mdx
[uncategorized] ~55-~55: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...mandTabsToMarkdown—→ markdown table. 11.remarkStepsToMarkdown—<...
(MARKDOWN_NNP)
[uncategorized] ~58-~58: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...ypeTable>and→ markdown table. 14.remarkAccordionToMarkdown` ...
(MARKDOWN_NNP)
🔍 Remote MCP Context7
Findings relevant to the PR review
-
unist-util-visit supports returning a tuple [SKIP, index] (or [true|false, index]) from a visitor to both skip descending into the current node’s children and continue traversal at a specific sibling index. This is the documented, correct pattern when you mutate parent.children (e.g., splice to remove/insert siblings) so traversal doesn’t skip or re-visit the wrong node. Example and API details shown in the docs: visit(...), SKIP, and numeric-index return semantics.
-
mdast-util-to-markdown is the standard serializer used to convert mdast trees back to markdown; it accepts serialization options and supports custom handlers and join functions (e.g., controlling bullet char and fence style, or providing a Join function to control blank lines between nodes). The Prompt transformer’s use of mdast-util-to-markdown with custom options (bullet
-, fence/backtick handling, list formatting) follows supported extension points of the library.
Sources consulted:
- unist-util-visit documentation and examples (SKIP / [SKIP, index] behavior and visitor return values)
- mdast-util-to-markdown README (toMarkdown usage, handlers, custom Join functions and options)
🔇 Additional comments (20)
apps/example/src/components/docs-mdx/prompt.tsx (1)
134-147: LGTM!The
copyPromptfunction correctly uses async/await with try/catch for error handling, addressing the past review comment.apps/example/src/components/docs-mdx/file-tree.tsx (1)
109-118: LGTM! Controlled state correctly implemented.The
Foldercomponent now manages its ownisOpenstate initialized fromdefaultOpen, with anonTogglehandler that updates state from user interactions. This prevents parent rerenders from overriding user toggles.apps/example/src/components/docs-mdx/topic-switcher.tsx (1)
23-30: LGTM!The variant detection logic cleanly derives the layout mode from content and provides a proper data attribute for CSS styling.
packages/leadtype/src/remark/libs/generic-processor.ts (1)
59-59: LGTM! Critical fix for correct traversal after mutations.The tuple return
[SKIP, index]correctly handles continued traversal afterparent.children.splice(), preventing the visitor from skipping or revisiting the wrong nodes. This follows the documented unist-util-visit API pattern.Also applies to: 67-67
packages/leadtype/src/remark/plugins/prompt.remark.ts (2)
20-35: LGTM!The
childrenToMarkdownfunction correctly usesmdast-util-to-markdownwith appropriate serialization options. The spread operator creates a mutable copy from the readonly array, which is safe for the temporary root construction.
37-60: LGTM!The transformer correctly processes
<Prompt>components by extracting attributes, normalizing content, and building appropriate mdast replacements. The conditional assembly ensures only non-empty sections are included.apps/example/src/components/docs-mdx/audience.tsx (1)
10-20: LGTM!The component cleanly implements conditional rendering based on the target audience, returning
nullfor agent-targeted content and a styled wrapper for human-targeted content.packages/leadtype/src/remark/plugins/audience.remark.ts (1)
12-25: LGTM!The string literal unwrapping correctly handles quoted JSX attribute values with proper edge-case handling for empty or single-character inputs.
apps/example/src/components/docs-mdx/index.ts (1)
1-59: LGTM!The barrel file correctly re-exports the new component types and implementations. The biome-ignore directive is appropriate for this intentional component library entry point.
apps/example/src/lib/docs.ts (1)
164-178: LGTM!The new component matrix entries follow the established pattern, with appropriate coverage categories that match each component's behavior (Prompt with browser hydration for its interactive toggle, Audience and FileTree with pipeline conversion for their remark transformers).
apps/example/src/components/docs-mdx/mdx-components.ts (1)
1-41: LGTM!The new MDX component registrations are correctly imported and added to the
mdxComponentsmapping, enabling the MDX processor to render<Audience>,<File>,<FileTree>,<Folder>, and<Prompt>tags.packages/leadtype/src/remark/plugins/file-tree.remark.ts (1)
1-114: LGTM!The FileTree transformer is well-structured:
- Recursively collects nested
File/Folderentries with proper type narrowing- Renders clean Unicode tree connectors (
├──,└──,│)- Handles edge cases (empty trees, root normalization)
- Outputs a fenced
textcode block for agent readabilitypackages/leadtype/src/remark/index.ts (1)
9-52: LGTM!The new plugins are correctly integrated into
defaultRemarkPlugins:
remarkAudienceToMarkdownruns early (after placeholder resolution) to filter content before other transformersremarkFileTreeToMarkdownandremarkPromptToMarkdownrun near the end alongside similar component flattenerspackages/leadtype/src/remark/remark-output.test.ts (1)
328-478: LGTM!Comprehensive test coverage for the new remark transformers:
- Prompt test: Verifies title/description preservation and
promptfence output with bullet content- Audience test: Covers both JSX attribute syntaxes (
target="human"andtarget={'human'}), validating human content removal and agent content retention- FileTree test: Validates tree structure with root, nested folders, and proper indentation
- Plugin assertions: Updated to verify all three new plugins are in
defaultRemarkPluginsdocs/reference/remark.mdx (1)
26-63: LGTM!The documentation accurately reflects the updated
defaultRemarkPluginspipeline:
- Mermaid flowchart shows the correct node sequence including
rau(Audience),rft(FileTree), andrp(Prompt)- Numbered list correctly documents each plugin's purpose with consistent formatting
The lowercase "markdown" usage is consistent with the document's established style.
apps/example/src/styles.css (4)
103-141: LGTM!The
.docs-proseselectors now properly exclude prompt content descendants via:not([data-leadtype-prompt-content] *), preventing prose styles from leaking into multi-paragraph or list-based prompts. The exclusion pattern is consistently applied acrossp,ul,ol,a, andlirules.
409-502: LGTM!The prompt component styles are well-structured:
- Header layout with icon/title/description and copy button
- Collapsible body with gradient fade overlay when collapsed
- Toggle button with proper
aria-expandedstate handlingprefers-reduced-motionrespected for toggle icon animation
504-577: LGTM!The file-tree styles implement the PR objectives well:
- Mono typography with nested indentation via border-left connectors
- Horizontal stubs for nested items using
::beforepseudo-elements- Folder/file row layout with icon color hierarchy
- Chevron rotation on folder open state
- Default
<details>marker hidden via-webkit-details-marker
579-644: LGTM!The topic-switcher variant system cleanly separates:
- Segmented: Inline pill row for items without descriptions
- Grid: 2-column card layout with active state borders for items with descriptions
The uppercase tracking-wide caption for the label matches the PR description.
docs/build/bundle-package-docs.mdx (1)
49-58: LGTM!Good dogfooding of the new
<FileTree>component to replace the manual ASCII tree. The structure correctly represents the bundled output hierarchy and will be converted to a readable text fence byremarkFileTreeToMarkdownfor agent consumption.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@apps/example/src/styles.css`:
- Around line 111-130: The `.docs-prose ol:not([data-leadtype-prompt-content]
*)` rule is missing the `[data-leadtype-steps]` exclusion and thus overrides the
component's `my-8` spacing; update the selector used in that rule (the one
starting with `.docs-prose ol:not([data-leadtype-prompt-content] *)`) to also
exclude `[data-leadtype-steps]` (i.e., add `:not([data-leadtype-steps])`) so
step lists keep their own spacing, mirroring the other similar `.docs-prose`
selectors in this file.
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 99ae1318-c911-4fcc-a20c-998eb7d0428f
📒 Files selected for processing (4)
apps/example/src/styles.cssdocs/authoring/components.mdxdocs/quickstart.mdxpackages/leadtype/src/remark/plugins/audience.remark.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Preferunknownoveranywhen the type is genuinely unknown
Use const assertions (as const) for immutable values and literal types
Leverage TypeScript's type narrowing instead of type assertions
Files:
packages/leadtype/src/remark/plugins/audience.remark.ts
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Use arrow functions for callbacks and short functions
Preferfor...ofloops over.forEach()and indexedforloops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Useconstby default,letonly when reassignment is needed, nevervar
Alwaysawaitpromises in async functions - don't forget to use the return value
Useasync/awaitsyntax instead of promise chains for better readability
Handle errors appropriately in async code with try-catch blocks
Don't use async functions as Promise executors
Removeconsole.log,debugger, andalertstatements from production code
ThrowErrorobjects with descriptive messages, not strings or other values
Usetry-catchblocks meaningfully - don't catch errors just to rethrow them
Prefer early returns over nested conditionals for error cases
Extract complex conditions into well-named boolean variables
Use early returns to reduce nesting
Prefer simple conditionals over nested ternary operators
Don't useeval()or assign directly todocument.cookie
Avoid spread syntax in accumulators within loops
Use top-level regex literals instead of creating them in loops
Prefer specific imports over namespace imports
Use descriptive names for functions, variables, and types for meaningful naming
Add comments for complex logic, but prefer self-documenting code
Files:
packages/leadtype/src/remark/plugins/audience.remark.ts
🔍 Remote MCP Context7
Relevant findings to aid PR review
-
unist-util-visit traversal control
- Visitors may return [SKIP, index] after mutating parent.children (e.g., splice) to skip descending and continue traversal at the correct sibling index; returning a numeric index can restart or reposition traversal (e.g., 0 restarts, parent.children.length skips remaining siblings). Example usage shown for replacing a node with its children and returning [SKIP, index] to avoid skipping injected children.
-
mdast-util-to-markdown serialization options
- toMarkdown supports customizing output via options: custom handlers, bullet character choice, fence style, and custom join functions (e.g., to control blank lines between nodes). The package is ESM-only and requires Node.js >= 16; examples show producing fenced code blocks and controlling list/bullet formatting. These extension points validate the Prompt transformer’s approach of using mdast-util-to-markdown with custom options for bullets, fences, and list rendering.
Tools used:
- Context7_resolve-library-id + Context7_query-docs for unist-util-visit
- Context7_resolve-library-id + Context7_query-docs for mdast-util-to-markdown
🔇 Additional comments (4)
packages/leadtype/src/remark/plugins/audience.remark.ts (1)
11-41: Audience target normalization and filtering logic looks solid.The transformer behavior is clear and consistent: normalize target, drop
human, keep others.docs/authoring/components.mdx (1)
146-202: New Prompt/Audience/FileTree docs are clear and consistent with the flattening model.Examples and output expectations are well aligned for both browser and agent readers.
docs/quickstart.mdx (1)
66-90: Quickstart additions are strong and practical.The
FileTree+ integration prompt make post-generate verification much easier to follow.apps/example/src/styles.css (1)
103-106: The[data-leadtype-topic-switcher-item-description]element is rendered as a<span>, not a<p>, so the selector does not need adjustment for this element. The CSS will not inject.docs-prose pmargins into the description because it targets paragraph elements only.> Likely an incorrect or invalid review comment.
- FileTree: drop bullet leak, add tree-line connectors and folder/file icons - Prompt: tighten header, collapse body to ~72px with click-to-expand fade - TopicSwitcher: segmented row when no descriptions, cleaner card grid otherwise - Strengthen :not() exclusions on .docs-prose so component resets win on specificity
e9b9f08 to
d659735
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
apps/example/src/styles.css (1)
111-112:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winExclude step lists from the generic
olprose spacing rule.This still matches
[data-leadtype-steps], so.docs-prosecan override the component’smy-8spacing withmy-4.Proposed fix
-.docs-prose ol:not([data-leadtype-prompt-content] *) { +.docs-prose + ol:not([data-leadtype-steps]):not([data-leadtype-prompt-content] *) { `@apply` my-4 text-muted-foreground; }🤖 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 `@apps/example/src/styles.css` around lines 111 - 112, Update the CSS selector in styles.css so the generic .docs-prose ordered-list rule excludes step lists as well as prompt-content lists; change the selector used in the rule for .docs-prose ol (the line with "docs-prose ol:not([data-leadtype-prompt-content] *)") to also add a :not for [data-leadtype-steps] (for example use .docs-prose ol:not([data-leadtype-prompt-content] *):not([data-leadtype-steps] *) ) so the component with data-leadtype-steps keeps its own my-8 spacing instead of being overridden by my-4.
🤖 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 `@apps/example/src/components/docs-mdx/file-tree.tsx`:
- Around line 97-119: FolderProps currently extends DetailsHTMLAttributes which
allows callers to override the internal open/onToggle behavior; change the prop
type to Omit<DetailsHTMLAttributes<HTMLDetailsElement>, "open" | "onToggle"> so
incoming props can't override the component-controlled open and onToggle, and in
the Folder component replace the event.target cast with event.currentTarget to
avoid unsafe type assertions (update the onToggle handler inside Folder to use
event.currentTarget and setIsOpen based on its .open). Ensure the {...rest}
spread stays but now cannot contain open/onToggle.
In `@apps/example/src/components/docs-mdx/prompt.tsx`:
- Line 116: The component currently initializes overflows with useState(false)
which makes isExpanded true until the ResizeObserver runs and flips it; change
the initialization so overflows starts as true (useState(true)) or compute the
initial overflow synchronously on mount using the prompt DOM ref, then let the
ResizeObserver update via setOverflows — update the occurrences that reference
overflows/setOverflows (the state declaration and the places controlling
isExpanded at the other two spots around the lines noted) so the prompt is
collapsed by default on first paint.
- Around line 140-144: The copy feedback timer needs de-duplication and cleanup:
in the component that calls navigator.clipboard.writeText and setCopied (using
COPIED_TIMEOUT_MS), store the timeout id (e.g., in a ref or state), clear any
existing timeout before creating a new one, assign the new timeout id to that
ref, and call clearTimeout on that id in a useEffect cleanup (or on unmount) so
the “Copied” state isn’t cleared early and no timers leak when the component
unmounts.
---
Duplicate comments:
In `@apps/example/src/styles.css`:
- Around line 111-112: Update the CSS selector in styles.css so the generic
.docs-prose ordered-list rule excludes step lists as well as prompt-content
lists; change the selector used in the rule for .docs-prose ol (the line with
"docs-prose ol:not([data-leadtype-prompt-content] *)") to also add a :not for
[data-leadtype-steps] (for example use .docs-prose
ol:not([data-leadtype-prompt-content] *):not([data-leadtype-steps] *) ) so the
component with data-leadtype-steps keeps its own my-8 spacing instead of being
overridden by my-4.
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 2d29f85d-b86e-4219-bf8d-063aad355eb7
⛔ Files ignored due to path filters (3)
apps/example/src/generated/agent-readability.jsonis excluded by!**/generated/**apps/example/src/generated/docs-search-content.jsonis excluded by!**/generated/**apps/example/src/generated/docs-search-index.jsonis excluded by!**/generated/**
📒 Files selected for processing (19)
apps/example/src/components/docs-mdx/audience.tsxapps/example/src/components/docs-mdx/file-tree.tsxapps/example/src/components/docs-mdx/index.tsapps/example/src/components/docs-mdx/mdx-components.tsapps/example/src/components/docs-mdx/prompt.tsxapps/example/src/components/docs-mdx/topic-switcher.tsxapps/example/src/lib/docs.tsapps/example/src/styles.cssdocs/authoring/components.mdxdocs/build/bundle-package-docs.mdxdocs/build/connect-docs-site.mdxdocs/quickstart.mdxdocs/reference/remark.mdxpackages/leadtype/src/remark/index.tspackages/leadtype/src/remark/libs/generic-processor.tspackages/leadtype/src/remark/plugins/audience.remark.tspackages/leadtype/src/remark/plugins/file-tree.remark.tspackages/leadtype/src/remark/plugins/prompt.remark.tspackages/leadtype/src/remark/remark-output.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Preferunknownoveranywhen the type is genuinely unknown
Use const assertions (as const) for immutable values and literal types
Leverage TypeScript's type narrowing instead of type assertions
Files:
apps/example/src/components/docs-mdx/topic-switcher.tsxpackages/leadtype/src/remark/plugins/audience.remark.tsapps/example/src/lib/docs.tsapps/example/src/components/docs-mdx/audience.tsxpackages/leadtype/src/remark/libs/generic-processor.tsapps/example/src/components/docs-mdx/mdx-components.tsapps/example/src/components/docs-mdx/file-tree.tsxapps/example/src/components/docs-mdx/index.tspackages/leadtype/src/remark/remark-output.test.tspackages/leadtype/src/remark/index.tspackages/leadtype/src/remark/plugins/prompt.remark.tspackages/leadtype/src/remark/plugins/file-tree.remark.tsapps/example/src/components/docs-mdx/prompt.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Use arrow functions for callbacks and short functions
Preferfor...ofloops over.forEach()and indexedforloops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Useconstby default,letonly when reassignment is needed, nevervar
Alwaysawaitpromises in async functions - don't forget to use the return value
Useasync/awaitsyntax instead of promise chains for better readability
Handle errors appropriately in async code with try-catch blocks
Don't use async functions as Promise executors
Removeconsole.log,debugger, andalertstatements from production code
ThrowErrorobjects with descriptive messages, not strings or other values
Usetry-catchblocks meaningfully - don't catch errors just to rethrow them
Prefer early returns over nested conditionals for error cases
Extract complex conditions into well-named boolean variables
Use early returns to reduce nesting
Prefer simple conditionals over nested ternary operators
Don't useeval()or assign directly todocument.cookie
Avoid spread syntax in accumulators within loops
Use top-level regex literals instead of creating them in loops
Prefer specific imports over namespace imports
Use descriptive names for functions, variables, and types for meaningful naming
Add comments for complex logic, but prefer self-documenting code
Files:
apps/example/src/components/docs-mdx/topic-switcher.tsxpackages/leadtype/src/remark/plugins/audience.remark.tsapps/example/src/lib/docs.tsapps/example/src/components/docs-mdx/audience.tsxpackages/leadtype/src/remark/libs/generic-processor.tsapps/example/src/components/docs-mdx/mdx-components.tsapps/example/src/components/docs-mdx/file-tree.tsxapps/example/src/components/docs-mdx/index.tspackages/leadtype/src/remark/remark-output.test.tspackages/leadtype/src/remark/index.tspackages/leadtype/src/remark/plugins/prompt.remark.tspackages/leadtype/src/remark/plugins/file-tree.remark.tsapps/example/src/components/docs-mdx/prompt.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{jsx,tsx}: Use function components over class components in React
Call hooks at the top level only, never conditionally
Specify all dependencies in hook dependency arrays correctly
Use thekeyprop for elements in iterables (prefer unique IDs over array indices)
Nest children between opening and closing tags instead of passing as props
Don't define components inside other components
AvoiddangerouslySetInnerHTMLunless absolutely necessary
Use proper image components (e.g., Next.js<Image>) over<img>tags
Use Next.js<Image>component for images
Usenext/heador App Router metadata API for head elements in Next.js
Use Server Components for async data fetching instead of async Client Components in Next.js
Use ref as a prop instead ofReact.forwardRefin React 19+
Files:
apps/example/src/components/docs-mdx/topic-switcher.tsxapps/example/src/components/docs-mdx/audience.tsxapps/example/src/components/docs-mdx/file-tree.tsxapps/example/src/components/docs-mdx/prompt.tsx
**/*.{jsx,tsx,html}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{jsx,tsx,html}: Use semantic HTML and ARIA attributes for accessibility: provide meaningful alt text for images, use proper heading hierarchy, add labels for form inputs, include keyboard event handlers alongside mouse events, use semantic elements instead of divs with roles
Addrel="noopener"when usingtarget="_blank"on links
Files:
apps/example/src/components/docs-mdx/topic-switcher.tsxapps/example/src/components/docs-mdx/audience.tsxapps/example/src/components/docs-mdx/file-tree.tsxapps/example/src/components/docs-mdx/prompt.tsx
**/index.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Avoid barrel files (index files that re-export everything)
Files:
apps/example/src/components/docs-mdx/index.tspackages/leadtype/src/remark/index.ts
**/*.{test,spec}.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{test,spec}.{js,ts,jsx,tsx}: Write assertions insideit()ortest()blocks
Avoid done callbacks in async tests - use async/await instead
Don't use.onlyor.skipin committed code
Keep test suites reasonably flat - avoid excessivedescribenesting
Files:
packages/leadtype/src/remark/remark-output.test.ts
🪛 LanguageTool
docs/reference/remark.mdx
[uncategorized] ~55-~55: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...mandTabsToMarkdown—→ markdown table. 11.remarkStepsToMarkdown—<...
(MARKDOWN_NNP)
[uncategorized] ~58-~58: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...ypeTable>and→ markdown table. 14.remarkAccordionToMarkdown` ...
(MARKDOWN_NNP)
🔍 Remote MCP Context7
Additional factual context for reviewing PR #23
-
unist-util-visit supports returning tuple-based skip/position signals when a visitor mutates siblings. Returning
[SKIP, index]prevents descending into the current node’s children and resumes traversal at the given sibling index; returning a numeric index (e.g.,0orparent.children.length) moves/triggers traversal at that position (restart or skip remaining siblings). Example usage shown for replacing a node with its children and returning[SKIP, index]so injected children are visited correctly., -
mdast-util-to-markdown supports customizing serialization via handlers and options (custom handlers map, bullet character, fence style, join functions such as a custom
jointo avoid blank lines). It is used to serialize mdast trees into markdown strings; examples show producing fenced code blocks and demonstrate how to control spacing/joining between blocks. This validates the Prompt remark transform approach of using mdast-util-to-markdown with custom options for bullets/fences and list formatting.,
Sources/calls:
- Resolved library IDs:
- /syntax-tree/unist-util-visit — Context7_resolve-library-id (search for unist-util-visit)
- /syntax-tree/mdast-util-to-markdown — Context7_resolve-library-id (search for mdast-util-to-markdown)
- Documentation pages retrieved:
- Unist Util Visit README (visitor return values, examples) — Context7_query-docs
- Mdast Util To Markdown README (handlers, join, examples) — Context7_query-docs
🔇 Additional comments (15)
packages/leadtype/src/remark/libs/generic-processor.ts (1)
59-67: Traversal control after splice is correctly handled.Using
[SKIP, index]after child-array mutation is the right fix to keep visitation stable when nodes are removed/replaced.apps/example/src/components/docs-mdx/audience.tsx (1)
10-20: Audience render gating is clean and intentional.The target-based null render and passthrough attributes look solid for the docs-runtime behavior.
packages/leadtype/src/remark/plugins/audience.remark.ts (1)
26-41: Target normalization and filtering logic looks correct.This cleanly drops
target="human"content and preserves non-human content for markdown output.apps/example/src/components/docs-mdx/topic-switcher.tsx (1)
23-31: Variant auto-selection is implemented cleanly.
hasDescriptions→grid|segmentedmapping anddata-variantwiring are clear and maintainable.docs/build/bundle-package-docs.mdx (1)
49-58: FileTree example update is consistent and clear.Good alignment with the component-based docs authoring and expected markdown transformation path.
docs/build/connect-docs-site.mdx (1)
142-144: Agent-only guidance is well scoped.Using
<Audience target="agent">here is a good fit for keeping this routing advice in markdown outputs while hiding it from normal docs UI.apps/example/src/components/docs-mdx/mdx-components.ts (1)
2-30: MDX component registry wiring is complete.The added imports and mapping entries correctly expose the new docs MDX components.
docs/reference/remark.mdx (1)
26-63: Remark pipeline docs are well synchronized with the new stages.The added Audience stage and updated FileTree/Prompt ordering read consistently and improve reference accuracy.
docs/authoring/components.mdx (1)
146-202: Prompt/Audience/FileTree documentation is consistent with the flattening contract.The new examples and flattening notes are clear, and the artifact path reference is now consistent (
llms-full/*.txt).apps/example/src/lib/docs.ts (1)
164-178: Component matrix updates look good.Coverage and notes for
Prompt,Audience, andFileTree / Folder / Fileare coherent with the new docs/remark behavior.packages/leadtype/src/remark/remark-output.test.ts (1)
328-417: Great coverage expansion for new MDX components.These tests capture both conversion output and pipeline registration for
Prompt,Audience, andFileTree, which reduces regression risk.Also applies to: 473-476
apps/example/src/components/docs-mdx/index.ts (1)
8-12: Export wiring is clean and complete.The new component and prop-type exports are correctly surfaced from the docs MDX entrypoint.
Also applies to: 26-33, 39-39
packages/leadtype/src/remark/plugins/file-tree.remark.ts (1)
47-63: FileTree transformer implementation looks solid.The traversal and rendering logic are straightforward, and the empty-output guard avoids emitting meaningless blocks.
Also applies to: 84-112
packages/leadtype/src/remark/plugins/prompt.remark.ts (1)
20-35: Prompt markdown transformer behavior is well-structured.Title/description/body mapping is clear, and fenced
promptoutput is deterministic.Also applies to: 37-59
packages/leadtype/src/remark/index.ts (1)
37-37: Default remark pipeline updates are correctly wired.The new plugin entries are inserted in a sensible position in the transformation order.
Also applies to: 49-50
| export type FolderProps = DetailsHTMLAttributes<HTMLDetailsElement> & { | ||
| name: string; | ||
| defaultOpen?: boolean; | ||
| children?: ReactNode; | ||
| }; | ||
|
|
||
| export function Folder({ | ||
| name, | ||
| defaultOpen = true, | ||
| children, | ||
| ...rest | ||
| }: FolderProps) { | ||
| const [isOpen, setIsOpen] = useState(defaultOpen); | ||
|
|
||
| return ( | ||
| <li data-leadtype-file-tree-item=""> | ||
| <details | ||
| data-leadtype-file-tree-folder="" | ||
| onToggle={(event) => | ||
| setIsOpen((event.target as HTMLDetailsElement).open) | ||
| } | ||
| open={isOpen} | ||
| {...rest} |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cd /tmp && find . -type f -name "file-tree.tsx" 2>/dev/null | head -20Repository: inthhq/leadtype
Length of output: 41
🏁 Script executed:
find . -type f -name "file-tree.tsx" 2>/dev/nullRepository: inthhq/leadtype
Length of output: 112
🏁 Script executed:
git ls-files | grep file-tree.tsxRepository: inthhq/leadtype
Length of output: 110
🏁 Script executed:
find . -path "*/components/docs-mdx/*" -type f 2>/dev/nullRepository: inthhq/leadtype
Length of output: 890
🏁 Script executed:
git ls-files | grep -E "(docs-mdx|file-tree)" | head -20Repository: inthhq/leadtype
Length of output: 915
🏁 Script executed:
cat -n apps/example/src/components/docs-mdx/file-tree.tsx | head -130Repository: inthhq/leadtype
Length of output: 3927
🏁 Script executed:
wc -l apps/example/src/components/docs-mdx/file-tree.tsxRepository: inthhq/leadtype
Length of output: 114
🏁 Script executed:
cat -n apps/example/src/components/docs-mdx/file-tree.tsx | sed -n '103,130p'Repository: inthhq/leadtype
Length of output: 943
🏁 Script executed:
rg -A 5 "onToggle" apps/example/src/components/docs-mdx/file-tree.tsxRepository: inthhq/leadtype
Length of output: 209
🏁 Script executed:
# Check if there are any other usages of Folder component to understand the impact
rg "Folder\s*\{" apps/example/src --type tsx -B 2 -A 5 | head -40Repository: inthhq/leadtype
Length of output: 87
🏁 Script executed:
rg "Folder\s*\{" apps/example/src -t ts -B 2 -A 5 | head -60Repository: inthhq/leadtype
Length of output: 41
🏁 Script executed:
rg "<Folder" apps/example/src --type-list | grep -i tsxRepository: inthhq/leadtype
Length of output: 449
🏁 Script executed:
rg "<Folder" apps/example/src -A 3 | head -50Repository: inthhq/leadtype
Length of output: 50374
🏁 Script executed:
rg "import.*Folder" apps/example/src --type ts | head -20Repository: inthhq/leadtype
Length of output: 168
🏁 Script executed:
rg "<Folder" apps/example/src --max-count=10Repository: inthhq/leadtype
Length of output: 50374
🏁 Script executed:
find apps/example/src -name "*.mdx" -o -name "*.md" | xargs grep -l "Folder" 2>/dev/null | head -5Repository: inthhq/leadtype
Length of output: 41
🏁 Script executed:
# Check if there are other TypeScript/TSX files using the Folder component
rg "Folder\s*name=" apps/example --max-count=5Repository: inthhq/leadtype
Length of output: 50374
🏁 Script executed:
cat > /tmp/test_event.ts << 'EOF'
import type { ChangeEvent } from "react";
// Test 1: event.target needs assertion for HTMLDetailsElement
function test1(event: React.SyntheticEvent<HTMLDetailsElement>) {
const open1 = (event.target as HTMLDetailsElement).open; // Has type assertion
const open2 = event.currentTarget.open; // No assertion needed, typed correctly
}
// Test 2: ToggleEvent on details
function test2(event: React.SyntheticEvent<HTMLDetailsElement>) {
// event.target is EventTarget (untyped)
// event.currentTarget is HTMLDetailsElement (typed)
console.log(event.currentTarget.open); // Works without assertion
}
EOF
cat /tmp/test_event.tsRepository: inthhq/leadtype
Length of output: 668
Prevent prop override: omit open/onToggle from FolderProps.
FolderProps currently extends DetailsHTMLAttributes<HTMLDetailsElement>, and {...rest} is spread after the internal open and onToggle props. Since JSX applies props left-to-right, caller-supplied open or onToggle in rest will override the internal state management, breaking the component's ability to track folder open/closed state.
Additionally, the onToggle handler uses event.target as HTMLDetailsElement — a type assertion that violates the coding guideline to leverage type narrowing. event.currentTarget is properly typed without needing a cast.
Proposed fix
-export type FolderProps = DetailsHTMLAttributes<HTMLDetailsElement> & {
+export type FolderProps = Omit<
+ DetailsHTMLAttributes<HTMLDetailsElement>,
+ "open" | "onToggle"
+> & {
name: string;
defaultOpen?: boolean;
children?: ReactNode;
};
@@
<details
data-leadtype-file-tree-folder=""
- onToggle={(event) =>
- setIsOpen((event.target as HTMLDetailsElement).open)
- }
- open={isOpen}
{...rest}
+ open={isOpen}
+ onToggle={(event) => setIsOpen(event.currentTarget.open)}
>🤖 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 `@apps/example/src/components/docs-mdx/file-tree.tsx` around lines 97 - 119,
FolderProps currently extends DetailsHTMLAttributes which allows callers to
override the internal open/onToggle behavior; change the prop type to
Omit<DetailsHTMLAttributes<HTMLDetailsElement>, "open" | "onToggle"> so incoming
props can't override the component-controlled open and onToggle, and in the
Folder component replace the event.target cast with event.currentTarget to avoid
unsafe type assertions (update the onToggle handler inside Folder to use
event.currentTarget and setIsOpen based on its .open). Ensure the {...rest}
spread stays but now cannot contain open/onToggle.
| const contentRef = useRef<HTMLDivElement>(null); | ||
| const [copied, setCopied] = useState(false); | ||
| const [expanded, setExpanded] = useState(false); | ||
| const [overflows, setOverflows] = useState(false); |
There was a problem hiding this comment.
Prompt is initially expanded on first paint for long content.
overflows starts as false, so isExpanded is true until ResizeObserver runs. On Line 116 and Line 155 this makes long prompts render expanded first, then collapse, which breaks the “collapsed by default” behavior.
💡 Suggested fix
- const [overflows, setOverflows] = useState(false);
+ const [overflows, setOverflows] = useState<boolean | null>(null);
...
- const isExpanded = expanded || !overflows;
+ const isExpanded = expanded || overflows === false;
...
- {overflows ? (
+ {overflows === true ? (Also applies to: 155-155, 191-201
🤖 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 `@apps/example/src/components/docs-mdx/prompt.tsx` at line 116, The component
currently initializes overflows with useState(false) which makes isExpanded true
until the ResizeObserver runs and flips it; change the initialization so
overflows starts as true (useState(true)) or compute the initial overflow
synchronously on mount using the prompt DOM ref, then let the ResizeObserver
update via setOverflows — update the occurrences that reference
overflows/setOverflows (the state declaration and the places controlling
isExpanded at the other two spots around the lines noted) so the prompt is
collapsed by default on first paint.
| try { | ||
| await navigator.clipboard.writeText(text); | ||
| setCopied(true); | ||
| window.setTimeout(() => setCopied(false), COPIED_TIMEOUT_MS); | ||
| } catch { |
There was a problem hiding this comment.
Copy feedback timer is not de-duplicated or cleaned up.
Repeated clicks can leave multiple timers active and clear “Copied” earlier than expected; the timer also isn’t canceled on unmount.
💡 Suggested fix
const contentRef = useRef<HTMLDivElement>(null);
+ const copyTimeoutRef = useRef<number | null>(null);
...
+ useEffect(() => {
+ return () => {
+ if (copyTimeoutRef.current !== null) {
+ window.clearTimeout(copyTimeoutRef.current);
+ }
+ };
+ }, []);
...
try {
await navigator.clipboard.writeText(text);
setCopied(true);
- window.setTimeout(() => setCopied(false), COPIED_TIMEOUT_MS);
+ if (copyTimeoutRef.current !== null) {
+ window.clearTimeout(copyTimeoutRef.current);
+ }
+ copyTimeoutRef.current = window.setTimeout(() => {
+ setCopied(false);
+ copyTimeoutRef.current = null;
+ }, COPIED_TIMEOUT_MS);
} catch {
setCopied(false);
}📝 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.
| try { | |
| await navigator.clipboard.writeText(text); | |
| setCopied(true); | |
| window.setTimeout(() => setCopied(false), COPIED_TIMEOUT_MS); | |
| } catch { | |
| try { | |
| await navigator.clipboard.writeText(text); | |
| setCopied(true); | |
| if (copyTimeoutRef.current !== null) { | |
| window.clearTimeout(copyTimeoutRef.current); | |
| } | |
| copyTimeoutRef.current = window.setTimeout(() => { | |
| setCopied(false); | |
| copyTimeoutRef.current = null; | |
| }, COPIED_TIMEOUT_MS); | |
| } catch { | |
| setCopied(false); | |
| } |
🤖 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 `@apps/example/src/components/docs-mdx/prompt.tsx` around lines 140 - 144, The
copy feedback timer needs de-duplication and cleanup: in the component that
calls navigator.clipboard.writeText and setCopied (using COPIED_TIMEOUT_MS),
store the timeout id (e.g., in a ref or state), clear any existing timeout
before creating a new one, assign the new timeout id to that ref, and call
clearTimeout on that id in a useEffect cleanup (or on unmount) so the “Copied”
state isn’t cleared early and no timers leak when the component unmounts.
Summary
<details>, and tree-connector lines (vertical guide on nested groups + horizontal stub per item).:not([data-leadtype-…])exclusion pattern on.docs-proserules (h3,p,a,ul,li) so component resets win on specificity. Without this, prose's class+element selectors override bare attribute selectors and bullets/underlines bleed through.Test plan
/docs/authoring/components— FileTree (no bullets, tree connectors, icons, chevron rotates), Prompt (single short prompt fits, no toggle), TopicSwitcher (grid variant for items with descriptions, no underline on description text)./docs/quickstart— Prompt body is collapsed with a fade and "Show prompt" toggle; clicking expands and toggles to "Show less".<TopicSwitcher>with nodescriptionon any item — confirm segmented pill variant renders.🤖 Generated with Claude Code