[Docs][UI] - Components pop-up dynamic-codeblock#877
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds a docs-wide code overlay: a provider/context, a dynamic bottom-aligned overlay component with highlighting and controls, integration into DocsLayout, DynamicCodeblock overlay-mode with floating trigger, and scoped stack layout/CSS resets plus minor demo wrapper class changes. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant DocsPage
participant DocsLayout
participant CodeCtx as CodeOverlayProvider
participant DynBlock as DynamicCodeblock
participant Overlay as DynamicCodeblockOverlay
User->>DocsPage: open docs route
DocsPage->>DocsLayout: render (wrapped by CodeCtx)
DocsLayout->>CodeCtx: provide context
DocsPage->>DynBlock: render code block (useOverlay=true)
DynBlock->>CodeCtx: openOverlay(code, lang, title) [auto or trigger]
CodeCtx-->>Overlay: isOpen=true + props
Overlay->>User: show overlay (highlight/copy/expand)
User-->>Overlay: copy / expand / close
Overlay->>CodeCtx: closeOverlay()
CodeCtx-->>Overlay: isOpen=false
User->>DocsPage: navigate away
DocsLayout->>CodeCtx: pathname change -> closeOverlay()
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Greptile Summary
This PR adds a dynamic popup codeblock feature to the documentation site that allows users to view and interact with code examples for components with live prop manipulation. The implementation consists of several key components:
-
Context-based overlay system: A new React context (
useCodeOverlay) manages the global state for code overlays, including visibility, content, and automatic cleanup when navigating between pages. -
Dynamic overlay component: The
DynamicCodeblockOverlaycomponent provides a full-featured popup with syntax highlighting via Shiki, copy-to-clipboard functionality, responsive design, and keyboard accessibility (ESC to close). -
Enhanced component documentation: The team switcher documentation page now includes an interactive demo with prop manipulation controls and dynamic code generation that updates based on the current component configuration.
-
Styling isolation system: A comprehensive CSS reset system (
stack-reset.css) ensures Stack UI components display correctly within the documentation site without interference from global styles. -
Layout integration: The overlay system is integrated at the root layout level, ensuring proper z-index layering and global accessibility across all documentation pages.
The feature enhances the developer experience by bridging the gap between static documentation and actual implementation, allowing users to see how different prop configurations translate to actual React/JSX code. The implementation follows React best practices with proper context usage, error handling, and responsive design considerations.
Confidence score: 3/5
- This PR introduces significant new functionality that could have unexpected interactions with existing documentation components
- Score reflects the complexity of the overlay positioning system and direct DOM manipulation in event handlers
- Pay close attention to
docs/src/components/mdx/dynamic-code-block.tsxfor potential performance issues with scroll/resize listeners
7 files reviewed, 7 comments
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
docs/src/components/stack-auth/stack-team-switcher.tsx (1)
232-241: Undefined CSS class 'stack-reset-light' + missing stylesheet import
- The wrappers use a 'stack-reset-light' class that isn’t defined in stack-reset.css. As-is, these wrappers won’t get any reset styling.
- Also ensure the reset stylesheet is imported somewhere global (e.g., Docs layout) or locally; otherwise even 'stack-reset' won’t apply.
Action:
- Define a 'stack-reset-light' variant in the CSS (see my CSS comment for a ready diff), and import the stylesheet globally in DocsLayout.
- If you prefer a quick stopgap, swap 'stack-reset-light' → 'stack-reset' in this file:
- <div className="flex items-center justify-center p-4 stack-reset-light"> + <div className="flex items-center justify-center p-4 stack-reset">Also applies to: 258-266, 272-280, 286-298, 323-331
docs/src/components/layouts/docs.tsx (1)
1-4: This file needs to be a Client Component ('use client')You’re using React/Next client hooks (useState, useEffect, usePathname, useRouter, createPortal). Add the directive at the very top to avoid RSC/hydration errors.
+'use client'; /** * DOCS BASE LAYOUT *docs/src/components/mdx/stack-reset.css (1)
1-59: docs/src/components/mdx/stack-reset.css: define.stack-reset-lightand flatten nested rules
- Add a
.stack-reset-lightrule (aliasing the.stack-resetstyles) to cover thestack-reset-lightclass used indocs/src/components/stack-auth/stack-team-switcher.tsx.- Unnest selectors (e.g. replace the
* { … }block inside.stack-reset { … }with flat rules like.stack-reset * { … }) because PostCSS nesting isn’t enabled in the docs’ PostCSS config.docs/src/components/mdx/dynamic-code-block.tsx (1)
105-109: Fix XSS risk in fallback HTML.When Shiki fails, raw
codeis injected without escaping, enabling HTML/JS injection. Escape before injecting.Apply this diff:
- } catch (error) { - console.error('Error highlighting code:', error); - setHighlightedCode(`<pre><code>${code}</code></pre>`); - } + } catch (error) { + console.error('Error highlighting code:', error); + setHighlightedCode(`<pre><code>${escapeHtml(code)}</code></pre>`); + }Add this helper (top-level in the file):
function escapeHtml(s: string) { return s .replaceAll('&', '&') .replaceAll('<', '<') .replaceAll('>', '>') .replaceAll('"', '"') .replaceAll("'", '''); }
🧹 Nitpick comments (13)
docs/src/hooks/use-code-overlay.tsx (1)
26-33: Simplify navigation-close logic; avoid extra state churnTracking
currentPagein state causes an extra effect run. Use a ref for the previous pathname.- const [currentPage, setCurrentPage] = useState(''); + const prevPathRef = useRef<string | null>(null); const pathname = usePathname(); // Close overlay when navigating to a different page useEffect(() => { - if (pathname !== currentPage && currentPage !== '') { - setIsOpen(false); - } - setCurrentPage(pathname); - }, [pathname, currentPage]); + if (prevPathRef.current && pathname !== prevPathRef.current) { + setIsOpen(false); + } + prevPathRef.current = pathname; + }, [pathname]);docs/src/components/mdx/dynamic-code-block-overlay.tsx (4)
172-181: Improve accessibility: add landmark and relationshipsDeclare a landmark and link the header title for screen readers. Also expose expanded state.
- <div + <div className={cn( "fixed bottom-0 bg-fd-background border-t border-fd-border z-50", "transition-all duration-300 ease-out", "shadow-2xl", "flex flex-col", // Add flex container // Position to avoid sidebar overlap - adjust based on sidebar state "left-0 right-0", isMainSidebarCollapsed ? "md:left-16" : "md:left-64" )} style={{ maxHeight: getOptimalHeight(), // Use maxHeight instead of fixed height }} + role="region" + aria-labelledby="dynamic-codeblock-overlay-title" + aria-expanded={isExpanded} > ... - <h3 className="font-semibold text-fd-foreground text-sm sm:text-base truncate">{title}</h3> + <h3 id="dynamic-codeblock-overlay-title" className="font-semibold text-fd-foreground text-sm sm:text-base truncate">{title}</h3>Also applies to: 206-214, 156-170
120-136: Avoid state updates after unmount for copy timeoutStore the timeout id and clear it on unmount.
-import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; ... const [copied, setCopied] = useState(false); + const copyTimeoutRef = useRef<number | null>(null); ... const handleCopy = () => { const copyToClipboard = async () => { try { await navigator.clipboard.writeText(code); setCopied(true); - setTimeout(() => setCopied(false), 2000); + if (copyTimeoutRef.current) clearTimeout(copyTimeoutRef.current); + copyTimeoutRef.current = window.setTimeout(() => setCopied(false), 2000); } catch (error) { // Handle clipboard error gracefully console.error('Failed to copy code:', error instanceof Error ? error.message : 'Unknown error'); // Could show a toast notification here in the future } }; // Run async function - all errors are handled within the function runAsynchronously(copyToClipboard); }; + + useEffect(() => { + return () => { + if (copyTimeoutRef.current) clearTimeout(copyTimeoutRef.current); + }; + }, []);
72-86: Throttle resize handler to reduce layout work on rapid resizesCurrent listener updates state on every event. Throttle to an animation frame or a short timeout.
- useEffect(() => { - const updateWindowSize = () => { - setWindowSize({ width: window.innerWidth, height: window.innerHeight }); - }; + useEffect(() => { + let rafId = 0; + const updateWindowSize = () => { + cancelAnimationFrame(rafId); + rafId = requestAnimationFrame(() => { + setWindowSize({ width: window.innerWidth, height: window.innerHeight }); + }); + }; ... - return () => window.removeEventListener('resize', updateWindowSize); + return () => { + cancelAnimationFrame(rafId); + window.removeEventListener('resize', updateWindowSize); + }; }, []);
220-224: Theme consistencyHardcoded
#0a0a0amay clash with theming. Prefer a design token or Tailwind var consistent with the docs theme.- style={{ - background: '#0a0a0a' - }} + className="bg-fd-code" /* or bg-neutral-950 if available */docs/src/components/layouts/docs.tsx (1)
1357-1373: LGTM with a minor optimization optionRenderer correctly closes on toggle and reads context safely. Optional: lazy-load the overlay to shave initial JS.
- import { DynamicCodeblockOverlay } from '../mdx/dynamic-code-block-overlay'; + import dynamic from 'next/dynamic'; + const DynamicCodeblockOverlay = dynamic( + () => import('../mdx/dynamic-code-block-overlay').then(m => m.DynamicCodeblockOverlay), + { ssr: false } + );docs/src/components/mdx/dynamic-code-block.tsx (7)
4-4: Defer Shiki to reduce bundle size.
import { codeToHtml } from "shiki"eagerly pulls a heavy dependency into the client bundle even whenuseOverlayis true (no inline highlight). Dynamically import Shiki inside the effect.-import { codeToHtml } from "shiki"; +// Defer Shiki to when inline highlighting is needed @@ useEffect(() => { const updateHighlightedCode = async () => { try { - const html = await codeToHtml(code, { + const { codeToHtml } = await import('shiki'); + const html = await codeToHtml(code, { lang: language, theme: 'github-dark',Also applies to: 84-104
151-154: Remove ineffective!importantin inline style.
!importantdoesn’t work in React inline styles and is redundant with Tailwind classes already applied.- <div - className="rounded-lg border bg-[#0a0a0a] p-4 overflow-auto max-h-[500px] text-sm" - style={{ - background: '#0a0a0a !important', - }} - > + <div + className="rounded-lg border bg-[#0a0a0a] p-4 overflow-auto max-h-[500px] text-sm" + >
12-16: Make auto-open user/configurable.Auto-opening can feel intrusive. Expose a prop to control it.
type DynamicCodeblockProps = { code: string, language?: string, title?: string, useOverlay?: boolean, + autoOpen?: boolean, } -export function DynamicCodeblock({ code, language = 'tsx', title, useOverlay = true }: DynamicCodeblockProps) { +export function DynamicCodeblock({ code, language = 'tsx', title, useOverlay = true, autoOpen = true }: DynamicCodeblockProps) { @@ - useEffect(() => { - if (useOverlay && code && !hasInitialized) { + useEffect(() => { + if (useOverlay && autoOpen && code && !hasInitialized) { const timer = setTimeout(() => { openOverlay(code, language, title); setHasInitialized(true); }, 100); return () => clearTimeout(timer); } - }, [useOverlay, code, language, title, openOverlay, hasInitialized]); + }, [useOverlay, autoOpen, code, language, title, openOverlay, hasInitialized]);Also applies to: 62-74
75-81: Avoid redundant overlay refreshes.Prevent repeated
openOverlaycalls when props haven’t effectively changed.+ const [lastOverlayKey, setLastOverlayKey] = useState<string | null>(null); @@ - useEffect(() => { - if (useOverlay && code && hasInitialized && isOpen) { - openOverlay(code, language, title); - } - }, [code, language, title, useOverlay, openOverlay, hasInitialized, isOpen]); + useEffect(() => { + if (!useOverlay || !code || !hasInitialized || !isOpen) return; + const key = `${language}|${title}|${code}`; + if (key !== lastOverlayKey) { + openOverlay(code, language, title); + setLastOverlayKey(key); + } + }, [code, language, title, useOverlay, openOverlay, hasInitialized, isOpen, lastOverlayKey]);
24-37: Throttle the resize listener.Directly setting state on every resize event can cause jank. Throttle via rAF.
useEffect(() => { - const updateWindowWidth = () => { - setWindowWidth(window.innerWidth); - }; + let raf = 0; + const updateWindowWidth = () => { + if (raf) return; + raf = requestAnimationFrame(() => { + raf = 0; + setWindowWidth(window.innerWidth); + }); + }; @@ - return () => window.removeEventListener('resize', updateWindowWidth); + return () => { + window.removeEventListener('resize', updateWindowWidth); + if (raf) cancelAnimationFrame(raf); + }; }, []);
39-61: Prefer IntersectionObserver for near-bottom detection.A sentinel with
IntersectionObserveris cheaper than per-scroll math and respects passive behavior.I can provide a small
useNearBottomhook using an invisible footer sentinel if you want it bundled in this PR.
120-143: Disable the trigger when no code is available.Avoid opening an empty overlay and improve a11y.
- return !isOpen ? ( + return !isOpen ? ( <button - onClick={() => openOverlay(code, language, title)} - className="fixed bottom-6 z-30 flex items-center gap-1.5 px-3 py-2 bg-fd-primary text-fd-primary-foreground rounded-full shadow-lg hover:scale-105 active:scale-95 transition-all duration-300 border border-fd-primary/20" + onClick={() => code?.trim() && openOverlay(code, language, title)} + disabled={!code?.trim()} + aria-disabled={!code?.trim()} + className="fixed bottom-6 z-30 flex items-center gap-1.5 px-3 py-2 bg-fd-primary text-fd-primary-foreground rounded-full shadow-lg hover:scale-105 active:scale-95 transition-all duration-300 border border-fd-primary/20 disabled:opacity-50 disabled:pointer-events-none"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (7)
docs/src/components/layouts/docs.tsx(4 hunks)docs/src/components/mdx/dynamic-code-block-overlay.tsx(1 hunks)docs/src/components/mdx/dynamic-code-block.tsx(2 hunks)docs/src/components/mdx/stack-container.tsx(1 hunks)docs/src/components/mdx/stack-reset.css(1 hunks)docs/src/components/stack-auth/stack-team-switcher.tsx(5 hunks)docs/src/hooks/use-code-overlay.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer ES6 Map over Record when representing key–value collections
Files:
docs/src/hooks/use-code-overlay.tsxdocs/src/components/stack-auth/stack-team-switcher.tsxdocs/src/components/mdx/stack-container.tsxdocs/src/components/mdx/dynamic-code-block-overlay.tsxdocs/src/components/mdx/dynamic-code-block.tsxdocs/src/components/layouts/docs.tsx
🧬 Code graph analysis (3)
docs/src/components/mdx/dynamic-code-block-overlay.tsx (2)
docs/src/components/layouts/sidebar-context.tsx (1)
useSidebar(46-49)packages/stack-shared/src/utils/promises.tsx (1)
runAsynchronously(343-366)
docs/src/components/mdx/dynamic-code-block.tsx (2)
docs/src/hooks/use-code-overlay.tsx (1)
useCodeOverlay(66-72)docs/src/components/layouts/sidebar-context.tsx (1)
useSidebar(46-49)
docs/src/components/layouts/docs.tsx (2)
docs/src/hooks/use-code-overlay.tsx (2)
CodeOverlayProvider(18-64)useCodeOverlay(66-72)docs/src/components/mdx/dynamic-code-block-overlay.tsx (1)
DynamicCodeblockOverlay(18-234)
🪛 ast-grep (0.38.6)
docs/src/components/mdx/dynamic-code-block-overlay.tsx
[warning] 226-226: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🪛 Biome (2.1.2)
docs/src/components/mdx/dynamic-code-block-overlay.tsx
[error] 227-227: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: restart-dev-and-test
- GitHub Check: setup-tests
- GitHub Check: all-good
- GitHub Check: build (22.x)
- GitHub Check: lint_and_build (latest)
- GitHub Check: docker
- GitHub Check: build (22.x)
- GitHub Check: docker
- GitHub Check: Security Check
🔇 Additional comments (4)
docs/src/components/mdx/dynamic-code-block-overlay.tsx (1)
3-3: Deep import required until public API is available
The@stackframe/stack-sharedpackage.json defines no subpath exports forutils/promisesand its root index doesn’t re-exportrunAsynchronously, so the only way to import it today is via the deep path. Keep the import as is until a public export is added.docs/src/components/layouts/docs.tsx (2)
65-66: LGTM: Overlay UI import is correctly scopedImporting DynamicCodeblockOverlay here keeps layout concerns centralized. No issues.
1119-1202: LGTM: Provider wiring and layout integrationWrapping the layout with CodeOverlayProvider and maintaining existing Nav/Sidebar structure looks solid. Search dialog and slots remain intact.
docs/src/components/mdx/dynamic-code-block.tsx (1)
20-23: All DynamicCodeblock usages are already covered by CodeOverlayProvider via the docs layout. No further action required.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (3)
docs/src/components/mdx/dynamic-code-block-overlay.tsx (3)
35-41: SSR-safe window usage looks goodGuarded access avoids hydration pitfalls; sensible defaults used.
32-34: Nice: memoized line countAddresses the earlier perf note.
92-119: Sanitize highlighted HTML and escape fallback to prevent XSS
dangerouslySetInnerHTMLrenders raw HTML. Sanitize the Shiki output and HTML‑escape the fallback to avoid XSS in docs.Apply within this range:
- setHighlightedCode(html); + setHighlightedCode(DOMPurify.sanitize(html)); } catch (error) { console.error('Error highlighting code:', error); - setHighlightedCode(`<pre><code>${code}</code></pre>`); + setHighlightedCode(`<pre><code>${escapeHtml(code)}</code></pre>`);Additions outside this range:
// Top-level import +import DOMPurify from "isomorphic-dompurify";// Helper (module-local; place near the component) +function escapeHtml(input: string): string { + return input + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", '''); +}
🧹 Nitpick comments (6)
docs/src/components/mdx/dynamic-code-block-overlay.tsx (6)
231-233: Document sanitization and suppress the lint warning in placeKeep
dangerouslySetInnerHTMLbut annotate that content is sanitized to satisfy Biome.<div className="[&_*]:!bg-transparent [&_pre]:!bg-transparent [&_code]:!bg-transparent text-xs sm:text-sm leading-[1.4] sm:leading-[1.5] [&_pre]:text-xs [&_pre]:sm:text-sm [&_code]:text-xs [&_code]:sm:text-sm [&_pre]:leading-[1.4] [&_pre]:sm:leading-[1.5] [&_code]:leading-[1.4] [&_code]:sm:leading-[1.5] [&_pre]:m-0 [&_pre]:p-0 [&_pre]:overflow-visible" - dangerouslySetInnerHTML={{ __html: highlightedCode }} + {/* biome-ignore lint/security/noDangerouslySetInnerHtml: Shiki HTML sanitized with DOMPurify above */} + dangerouslySetInnerHTML={{ __html: highlightedCode }} />
143-153: Attach Escape key listener only when overlay is openAvoid a global listener when closed; simpler handler too.
-useEffect(() => { - const handleEscape = (e: KeyboardEvent) => { - if (e.key === 'Escape' && isOpen) { - onToggle?.(false); - } - }; - document.addEventListener('keydown', handleEscape); - return () => document.removeEventListener('keydown', handleEscape); -}, [isOpen, onToggle]); +useEffect(() => { + if (!isOpen) return; + const handleEscape = (e: KeyboardEvent) => { + if (e.key === 'Escape') onToggle?.(false); + }; + document.addEventListener('keydown', handleEscape); + return () => document.removeEventListener('keydown', handleEscape); +}, [isOpen, onToggle]);
75-91: Throttle resize recalcs to reduce layout thrashUse rAF to coalesce rapid resize events.
useEffect(() => { const updateWindowSize = () => { if (typeof window !== 'undefined') { setWindowSize({ width: window.innerWidth, height: window.innerHeight }); } }; // Set initial window size updateWindowSize(); // Add resize listener - window.addEventListener('resize', updateWindowSize); + let raf = 0; + const onResize = () => { + cancelAnimationFrame(raf); + raf = requestAnimationFrame(updateWindowSize); + }; + window.addEventListener('resize', onResize); - return () => window.removeEventListener('resize', updateWindowSize); + return () => { + cancelAnimationFrame(raf); + window.removeEventListener('resize', onResize); + }; }, []);
162-176: Add dialog semantics for accessibilityMark the overlay as a modal dialog; improves SR navigation.
- <div + <div className={cn( "fixed bottom-0 bg-fd-background border-t border-fd-border z-50", "transition-all duration-300 ease-out", "shadow-2xl", "flex flex-col", // Add flex container // Position to avoid sidebar overlap - adjust based on sidebar state "left-0 right-0", isMainSidebarCollapsed ? "md:left-16" : "md:left-64" )} style={{ maxHeight: getOptimalHeight(), // Use maxHeight instead of fixed height }} + role="dialog" + aria-modal="true" + aria-label={title} + tabIndex={-1} >
3-3: Avoid deep import path to shared packageDeep imports are brittle; prefer the package entrypoint if available.
-import { runAsynchronously } from "@stackframe/stack-shared/dist/utils/promises"; +import { runAsynchronously } from "@stackframe/stack-shared/utils/promises";
92-119: Reduce bundle size by lazy-loading ShikiDefer Shiki until needed to keep docs’ initial JS smaller.
Example:
// move import out; lazy-load inside the effect useEffect(() => { const updateHighlightedCode = async () => { try { const { codeToHtml } = await import("shiki/bundle/web"); const html = await codeToHtml(code, { /* ... */ }); setHighlightedCode(DOMPurify.sanitize(html)); } catch (e) { setHighlightedCode(`<pre><code>${escapeHtml(code)}</code></pre>`); } }; runAsynchronously(updateHighlightedCode()); }, [code, language]);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
docs/src/components/mdx/dynamic-code-block-overlay.tsx(1 hunks)docs/src/components/mdx/dynamic-code-block.tsx(2 hunks)docs/src/hooks/use-code-overlay.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- docs/src/components/mdx/dynamic-code-block.tsx
- docs/src/hooks/use-code-overlay.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer ES6 Map over Record when representing key–value collections
Files:
docs/src/components/mdx/dynamic-code-block-overlay.tsx
🧬 Code graph analysis (1)
docs/src/components/mdx/dynamic-code-block-overlay.tsx (2)
docs/src/components/layouts/sidebar-context.tsx (1)
useSidebar(46-49)packages/stack-shared/src/utils/promises.tsx (1)
runAsynchronously(343-366)
🪛 Biome (2.1.2)
docs/src/components/mdx/dynamic-code-block-overlay.tsx
[error] 232-232: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
🪛 ast-grep (0.38.6)
docs/src/components/mdx/dynamic-code-block-overlay.tsx
[warning] 231-231: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: docker
- GitHub Check: build (22.x)
- GitHub Check: all-good
- GitHub Check: lint_and_build (latest)
- GitHub Check: restart-dev-and-test
- GitHub Check: setup-tests
- GitHub Check: build (22.x)
- GitHub Check: Security Check
<!-- Make sure you've read the CONTRIBUTING.md guidelines: https://github.com/stack-auth/stack-auth/blob/dev/CONTRIBUTING.md --> Adds a dynamic popup codeblock on components pages for components that have live examples with prop manipulation. <img width="1253" height="298" alt="image" src="https://github.com/user-attachments/assets/6d046c5f-77c1-4bec-98ed-fd0c2e347635" /> <!-- ELLIPSIS_HIDDEN --> ---- > [!IMPORTANT] > Adds a dynamic code block overlay feature to documentation pages, enhancing code example interaction with new components, hooks, and styling. > > - **Behavior**: > - Adds `DynamicCodeblockOverlay` in `dynamic-code-block-overlay.tsx` for interactive code display with syntax highlighting, copy, expand/collapse, and close features. > - Integrates `CodeOverlayProvider` and `useCodeOverlay` in `use-code-overlay.tsx` to manage overlay state and behavior. > - Updates `DocsLayout` in `docs.tsx` to include the code overlay in the documentation layout. > - **Components**: > - `DynamicCodeblock` in `dynamic-code-block.tsx` now supports overlay mode with a floating "View Code" button. > - `StackContainer` in `stack-container.tsx` updated for better layout and styling. > - **Styling**: > - Adds `stack-reset.css` for isolating stack component styles from global styles. > - Updates `stack-team-switcher.tsx` to use new styling and layout for team switcher demos. > > <sup>This description was created by </sup>[<img alt="Ellipsis" src="https://img.shields.io/badge/Ellipsis-blue?color=175173">](https://www.ellipsis.dev?ref=stack-auth%2Fstack-auth&utm_source=github&utm_medium=referral)<sup> for 4ef6c67. You can [customize](https://app.ellipsis.dev/stack-auth/settings/summaries) this summary. It will automatically update as commits are pushed.</sup> ---- <!-- ELLIPSIS_HIDDEN --> <!-- RECURSEML_SUMMARY:START --> ## Review by RecurseML _🔍 Review performed on [8424c4d..9c860b3](stack-auth/stack-auth@8424c4d...9c860b3067a3d93a3df660d151d8454f516129fe)_ ✨ No bugs found, your code is sparkling clean <details> <summary>✅ Files analyzed, no issues (5)</summary> • `docs/src/components/mdx/dynamic-code-block-overlay.tsx` • `docs/src/components/mdx/dynamic-code-block.tsx` • `docs/src/components/layouts/docs.tsx` • `docs/src/hooks/use-code-overlay.tsx` • `docs/src/components/stack-auth/stack-team-switcher.tsx` </details> <details> <summary>⏭️ Files skipped (trigger manually) (2)</summary> | Locations | Trigger Analysis | |-----------|------------------| `docs/src/components/mdx/stack-container.tsx` | [](https://squash-322339097191.europe-west3.run.app/interactive/0af8763e3d3b011d25ba56322596b6af1f11ecc409a1a617dfa65424263568b8/?repo_owner=stack-auth&repo_name=stack-auth&pr_number=877) `docs/src/components/mdx/stack-reset.css` | [](https://squash-322339097191.europe-west3.run.app/interactive/675653c9b4eee353126aeb1239a30eebf8458add6c467614a2281bc849f1ad14/?repo_owner=stack-auth&repo_name=stack-auth&pr_number=877) </details> [](https://discord.gg/n3SsVDAW6U) <!-- RECURSEML_SUMMARY:END --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * New Features * Interactive code overlay in docs with syntax-highlighted view, copy-to-clipboard, expand/collapse, ESC-to-close, and floating “View Code” trigger; responsive sizing and auto-open behavior. * Adds overlay provider/hooks to control overlay state and exposes a reusable overlay component and trigger. * Refactor * Integrates the overlay into DocsLayout and updates sidebar composition without changing public APIs. * Style * Adjusts Stack layout/title positioning, adds scoped stack CSS reset, and updates team-switcher demo wrappers. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Konsti Wohlwend <n2d4xc@gmail.com>
Adds a dynamic popup codeblock on components pages for components that have live examples with prop manipulation.
Important
Adds a dynamic code block overlay feature to documentation pages, enhancing code example interaction with new components, hooks, and styling.
DynamicCodeblockOverlayindynamic-code-block-overlay.tsxfor interactive code display with syntax highlighting, copy, expand/collapse, and close features.CodeOverlayProvideranduseCodeOverlayinuse-code-overlay.tsxto manage overlay state and behavior.DocsLayoutindocs.tsxto include the code overlay in the documentation layout.DynamicCodeblockindynamic-code-block.tsxnow supports overlay mode with a floating "View Code" button.StackContainerinstack-container.tsxupdated for better layout and styling.stack-reset.cssfor isolating stack component styles from global styles.stack-team-switcher.tsxto use new styling and layout for team switcher demos.This description was created by
for 4ef6c67. You can customize this summary. It will automatically update as commits are pushed.
Review by RecurseML
🔍 Review performed on 8424c4d..9c860b3
✨ No bugs found, your code is sparkling clean
✅ Files analyzed, no issues (5)
•
docs/src/components/mdx/dynamic-code-block-overlay.tsx•
docs/src/components/mdx/dynamic-code-block.tsx•
docs/src/components/layouts/docs.tsx•
docs/src/hooks/use-code-overlay.tsx•
docs/src/components/stack-auth/stack-team-switcher.tsx⏭️ Files skipped (trigger manually) (2)
docs/src/components/mdx/stack-container.tsxdocs/src/components/mdx/stack-reset.cssSummary by CodeRabbit
New Features
Refactor
Style