Conversation
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (50)
📝 WalkthroughWalkthroughAdds a stream panel system (presets, saved/custom streams, persisted docs-dial store, overlays, slider, and media-sync hook), migrates several UI primitives to Base UI, introduces a composable Field UI system, integrates stream controls into the PlayerLayoutDemo with animated tabs, and applies minor styling tweaks. ChangesStream Playback Control System
UI Foundation and Form System
Demo Integration and Component Updates
Styling and Maintenance
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 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 unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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. Comment |
There was a problem hiding this comment.
Pull request overview
This PR enhances the docs site’s player demos by introducing a configurable “stream panel” (presets + custom streams) and updating several UI primitives to align with Base UI / newer styling, alongside dependency bumps.
Changes:
- Added a new stream preset system + persisted “docs dial” state (presets/custom streams, autoplay/mute/volume).
- Introduced a StreamPanel popover/overlay UI and integrated it into the player demo + component preview flow.
- Migrated/added several UI primitives (Select/Popover/DropdownMenu/Field/Label/Textarea) and updated
@base-ui/reactdependency.
Reviewed changes
Copilot reviewed 28 out of 30 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| bun.lock | Updates lockfile for @base-ui/react and transitive deps. |
| apps/www/package.json | Bumps @base-ui/react to ^1.4.1. |
| apps/www/registry/default/ui/playback-control.tsx | Adjusts disabled logic for playback control. |
| apps/www/registry/default/internal/custom-demo-controls.tsx | Refactors demo controls container layout and styling. |
| apps/www/registry/default/examples/player-root-demo.tsx | Adds preview/code tabs animation, reload button, and StreamPanel integration. |
| apps/www/lib/stream-presets.ts | Adds preset definitions + localStorage helpers. |
| apps/www/lib/docs-dial-store.ts | Adds persisted Zustand store for docs “dial” state. |
| apps/www/components/youtube-music-hover-player.tsx | Minor rounding class tweak. |
| apps/www/components/ui/toggle-group.tsx | Refactors ToggleGroup wrapper and styling. |
| apps/www/components/ui/textarea.tsx | Adds Textarea UI component. |
| apps/www/components/ui/select.tsx | Migrates Select implementation to Base UI Select. |
| apps/www/components/ui/popover.tsx | Adds Base UI Popover wrapper components. |
| apps/www/components/ui/label.tsx | Adds Label UI component. |
| apps/www/components/ui/field.tsx | Adds Field/FieldGroup UI components and variants. |
| apps/www/components/ui/dropdown-menu.tsx | Migrates DropdownMenu implementation to Base UI Menu. |
| apps/www/components/stream-panel/use-stream-panel-sync.ts | Adds hook to sync StreamPanel selections to the media player. |
| apps/www/components/stream-panel/saved-overlay.tsx | Adds overlay for selecting/removing saved custom streams. |
| apps/www/components/stream-panel/provider.tsx | Adds StreamPanel context/provider (popover handle + open state). |
| apps/www/components/stream-panel/presets-overlay.tsx | Adds overlay for selecting built-in presets. |
| apps/www/components/stream-panel/panel-slider.tsx | Adds custom slider control (currently unused in panel). |
| apps/www/components/stream-panel/panel-popover.tsx | Adds main StreamPanel popover UI (presets/custom/autoplay/muted). |
| apps/www/components/stream-panel/overlay-shell.tsx | Adds animated overlay shell used by StreamPanel subviews. |
| apps/www/components/stream-panel/index.ts | Barrel exports for StreamPanel components/hooks. |
| apps/www/components/stream-panel/custom-overlay.tsx | Adds custom stream URL + config entry and “save stream” flow. |
| apps/www/components/component-preview.tsx | Updates preview rendering to use PlayerLayoutDemo for withPlayer. |
| apps/www/components/component-preview-control.tsx | Adds animated transitions and trailing slot support. |
| apps/www/components/codeblock.tsx | Adjusts CodeBlock styling classes. |
| apps/www/app/docs/[[...slug]]/page.tsx | Minor docs page header styling tweak. |
| .gitignore | Ignores .claude. |
| import { cva, type VariantProps } from "class-variance-authority" | ||
| import { useMemo } from "react" | ||
|
|
||
| import { Label } from "@/components/ui/label" |
| import { cn } from "@/lib/utils" | ||
|
|
||
| import { CustomOverlay } from "./custom-overlay" | ||
| import { PanelHeaderIcon } from "./panel-header" |
| const isDisabled = | ||
| readyState < MediaReadyState.HAVE_CURRENT_DATA || | ||
| status === "buffering" || | ||
| userDisabled | ||
| readyState < MediaReadyState.HAVE_CURRENT_DATA || userDisabled | ||
|
|
||
| const getDefaultAriaLabel = () => { | ||
| const shortcutText = shortcut ? ` (keyboard shortcut ${shortcut})` : "" |
| opacity: 0, | ||
| x: activeTab === "preview" ? -50 : 50, | ||
| }} | ||
| key={activeTab} | ||
| transition={{ |
| animate={{ opacity: 1, x: 0 }} | ||
| exit={{ opacity: 0, x: activeTab === "preview" ? 50 : -50 }} | ||
| initial={{ opacity: 0, x: activeTab === "preview" ? -50 : 50 }} | ||
| key={activeTab} | ||
| transition={{ |
| ` | ||
| relative flex w-full items-center gap-2 rounded-lg px-2.5 py-2 text-sm outline-hidden transition-[colors,transform] select-none | ||
| hover:bg-accent/70 hover:text-accent-foreground | ||
| focus:bg-accent/70 focus:text-accent-foreground |
|
|
||
| return ( | ||
| <OverlayShell onBack={onBack} show={show} title="Custom Stream"> | ||
| <div className={cn("no-scrollbar flex-1 overflow-y-auto p-2", "flex flex-col gap-3 p-3")}> |
There was a problem hiding this comment.
Actionable comments posted: 14
🤖 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/www/components/component-preview-control.tsx`:
- Around line 81-93: The tab wrapper is being keyed by activeTab
(key={activeTab}) inside AnimatePresence/motion.div which unmounts/remounts the
entire subtree (childArray) on tab switches and resets state; remove the key
from the shared wrapper and instead keep both tab contents mounted and animate
only the active pane (e.g., render each pane from childArray with its own motion
container keyed by pane id or toggle visibility/pointer-events based on
activeTab) so interactive preview state and scroll position are preserved (look
for AnimatePresence, motion.div, key={activeTab}, childArray, and activeTab to
apply the change).
In `@apps/www/components/stream-panel/custom-overlay.tsx`:
- Line 21: Replace the broad useDocsDialStore() call with granular selectors for
each state and action used: call useDocsDialStore(s => s.customSrc),
useDocsDialStore(s => s.customConfig), useDocsDialStore(s => s.setCustomSrc),
useDocsDialStore(s => s.setCustomConfig) and useDocsDialStore(s =>
s.saveStream), then update all references in this file so store.customSrc →
customSrc, store.customConfig → customConfig, store.setCustomSrc → setCustomSrc,
store.setCustomConfig → setCustomConfig, and store.saveStream → saveStream to
comply with per-feature selector guidelines.
In `@apps/www/components/stream-panel/panel-popover.tsx`:
- Around line 86-89: The useMemo for selectedPresetName still depends on
store.presetId; update its dependency array to use the new granular
selector/preset variable name (presetId) instead of store.presetId so the memo
reads dependencies [presets, presetId]; ensure the memo expression still uses
presets and presetId (selectedPresetName, presets, presetId) so it re-computes
correctly after the refactor.
- Around line 43-48: The mapping in positionClasses has an unexpected
"-bottom-10" for the "bottom-right" key which likely is a typo; update
positionClasses["bottom-right"] in panel-popover.tsx to use "bottom-4 right-4"
to match the other quadrants (or if the larger offset is intentional, add an
inline comment above the "bottom-right" entry explaining why "-bottom-10" is
required to compensate for the external bottom bar).
- Line 73: The component currently calls useDocsDialStore() which subscribes to
the entire slice and causes excessive re-renders; replace that with granular
selectors for each field and setter used (e.g. const muted = useDocsDialStore(s
=> s.muted), const setMuted = useDocsDialStore(s => s.setMuted), const
savedStreams = useDocsDialStore(s => s.savedStreams), const presetId =
useDocsDialStore(s => s.presetId), const setPresetId = useDocsDialStore(s =>
s.setPresetId), etc.), then update all store.X references (value={muted ?
"on":"off"}, setMuted(v==="on"), savedStreams.length, setPresetId(presetId), and
useMemo dependencies to use presetId instead of store) so the component only
re-renders when those specific fields change.
- Around line 76-84: The ESLint warning is because groups is typed as
Record<string, StreamPreset[]> so checking !groups[tag] is always-falsy; replace
the conditional initialization in the useMemo for groupedPresets with an
explicit logical-assignment or existence check: change the line "if
(!groups[tag]) groups[tag] = []" to use nullish coalescing assignment
"groups[tag] ??= []" (or alternatively "if (!(tag in groups)) groups[tag] = []")
so the intent to initialize an absent group is explicit; update only the
groupedPresets useMemo block that declares groups and iterates presets.
- Around line 19-23: The file imports PanelHeaderIcon and PanelSlider (and also
imports from a non-existent module "./panel-header") but
PanelHeaderIcon/PanelSlider are unused and the "./panel-header" module doesn't
exist; remove the broken import and any unused imports (delete the
PanelHeaderIcon and PanelSlider imports and replace the "./panel-header" import
with the correct module or remove it entirely), and drop the commented-out
<PanelSlider … /> block so the file no longer references non-existent or unused
symbols; ensure remaining imports (PresetsOverlay, useStreamPanel, SavedOverlay)
are kept if used.
In `@apps/www/components/stream-panel/panel-slider.tsx`:
- Around line 119-144: The root <div> currently only has pointer handlers so add
full slider semantics and keyboard support: make the element focusable
(tabIndex=0), set role="slider" and aria-valuemin/aria-valuemax/aria-valuenow
(use the existing min/max/value variables), and wire a keyDown handler that maps
ArrowLeft/ArrowDown and ArrowRight/ArrowUp to decrement/increment the value, and
Home/End to set to min/max using the same update logic as
handlePointerDown/handlePointerMove (refer to those functions and trackRef for
hit calculations), ensure focus/blur state (setIsHovered or a separate
isFocused) is managed so styling remains correct, and keep fillWidth, label and
Math.round(value) rendering unchanged.
- Around line 36-58: The positionToValue snapping currently rounds relative to
zero causing incorrect snaps when min isn't a multiple of step and can produce
NaN/Infinity when step <= 0 or max <= min; change the snapping in
positionToValue to anchor to min (e.g. round((raw - min)/step) * step + min),
ensure the returned value is clamped to [min, max], and add guards at the top of
the component (or inside percentage calculation and positionToValue) to handle
invalid ranges (if max <= min or step <= 0) by returning min or early-exiting so
you never divide by zero when computing percentage/fillPercent or compute an
out-of-range width.
In `@apps/www/components/stream-panel/use-stream-panel-sync.ts`:
- Around line 40-60: The loadStream callback can race when multiple loads are
triggered; make it async and add a generation/abort guard: introduce a local
incrementing generation ID (or use an AbortController stored in the hook) for
use-stream-panel-sync, capture the current generation before awaiting
player.load(src), await the load call (or await a wrapped promise), and after
the await check that the captured generation still matches the latest generation
stored on the hook; if it does not, bail out and do not apply further state or
configuration. Update references to the existing loadStream useCallback and
player.load invocation to use this generation/abort check so only the most
recent load completes.
In `@apps/www/components/ui/field.tsx`:
- Around line 170-187: Filter out falsy/undefined messages before deduplicating
so undefined isn't treated as a distinct key: build uniqueErrors from errors by
mapping to error.message, filtering truthy values, then deduping (e.g., via Set
or flatMap+Set) and reconstructing the error list; replace the optional chaining
length check (uniqueErrors?.length) with strict equality checks
(uniqueErrors.length === 1) and return the single message when exactly one
unique message exists; update references in this block (errors, uniqueErrors) in
the Field component to use the new filtered/deduped list.
In `@apps/www/components/ui/toggle-group.tsx`:
- Around line 35-37: The root class string contains an unreachable selector
data-[spacing=default] because spacing is numeric (default 0); update that
selector to match the numeric value used (e.g., replace data-[spacing=default]
with data-[spacing=0]) in the toggle group root class (the template literal
containing "group/toggle-group flex w-fit items-center
gap-[--spacing(var(--gap))] rounded-md") so the data-[variant=outline]:shadow-xs
rule applies correctly.
In `@apps/www/registry/default/examples/player-root-demo.tsx`:
- Around line 8-16: The example imports reach into the app's internal components
instead of the registry copy; update the imports for StreamPanel,
StreamPanelProvider, useStreamPanel, useStreamPanelSync, Button, PopoverTrigger,
Tabs, TabsContent and TabsList to import from "@/registry/default/..." (e.g.
"@/registry/default/components/stream-panel" and
"@/registry/default/components/ui/...") and ensure the registry contains
duplicated/forwarding modules for those symbols so the example resolves
standalone; adjust the import statements in player-root-demo.tsx to use those
registry paths and confirm the exported names match (StreamPanel,
StreamPanelProvider, useStreamPanel, useStreamPanelSync, Button, PopoverTrigger,
Tabs, TabsContent, TabsList).
In `@apps/www/registry/pro`:
- Line 1: The parent repository points the submodule apps/www/registry/pro at a
missing commit 27004f0ad27c640c652ddb2b5054ee41eee13c12; fix this by either
pushing that commit to the remote of the apps/www/registry/pro submodule so it
exists there, or update the submodule pointer in the parent repo to a valid
existing commit (e.g., check out a correct branch/tag in apps/www/registry/pro
and update the submodule ref) and commit that change in the parent repo before
merging.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: a80049ce-2839-4787-b518-53a7edb070f1
⛔ Files ignored due to path filters (3)
.gitignoreis excluded by none and included by noneapps/www/package.jsonis excluded by none and included by nonebun.lockis excluded by!**/*.lockand included by none
📒 Files selected for processing (27)
apps/www/app/docs/[[...slug]]/page.tsxapps/www/components/codeblock.tsxapps/www/components/component-preview-control.tsxapps/www/components/component-preview.tsxapps/www/components/stream-panel/custom-overlay.tsxapps/www/components/stream-panel/index.tsapps/www/components/stream-panel/overlay-shell.tsxapps/www/components/stream-panel/panel-popover.tsxapps/www/components/stream-panel/panel-slider.tsxapps/www/components/stream-panel/presets-overlay.tsxapps/www/components/stream-panel/provider.tsxapps/www/components/stream-panel/saved-overlay.tsxapps/www/components/stream-panel/use-stream-panel-sync.tsapps/www/components/ui/dropdown-menu.tsxapps/www/components/ui/field.tsxapps/www/components/ui/label.tsxapps/www/components/ui/popover.tsxapps/www/components/ui/select.tsxapps/www/components/ui/textarea.tsxapps/www/components/ui/toggle-group.tsxapps/www/components/youtube-music-hover-player.tsxapps/www/lib/docs-dial-store.tsapps/www/lib/stream-presets.tsapps/www/registry/default/examples/player-root-demo.tsxapps/www/registry/default/internal/custom-demo-controls.tsxapps/www/registry/default/ui/playback-control.tsxapps/www/registry/pro
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/www/components/component-preview-control.tsx (1)
81-93: ⚡ Quick winTab-switch animations won't execute.
The single unkeyed
motion.divwrapper (line 82) never unmounts or remounts—it stays in the React tree while only its content changes. Motion for React'sAnimatePresencerunsexit/initialanimations only when direct children are removed/added from the tree, not on internal state changes. As a result, theinitial/exitvariants (lines 84–85) won't animate onactiveTabchanges.To animate tab switching, render each pane as a direct
AnimatePresencechild keyed by tab id/value, rather than animating a persistent shared wrapper.🤖 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/www/components/component-preview-control.tsx` around lines 81 - 93, The AnimatePresence + motion.div wrapper never unmounts so exit/initial variants for tab changes don't run; update the render so each tab pane is a direct child of AnimatePresence with a stable key tied to activeTab (e.g., use activeTab or pane id as the React key) instead of a single unkeyed motion.div, and render childArray items (or map over panes) into keyed motion.div children so AnimatePresence can detect removals/additions and run the exit/initial animations for AnimatePresence, motion.div and activeTab.
🤖 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.
Nitpick comments:
In `@apps/www/components/component-preview-control.tsx`:
- Around line 81-93: The AnimatePresence + motion.div wrapper never unmounts so
exit/initial variants for tab changes don't run; update the render so each tab
pane is a direct child of AnimatePresence with a stable key tied to activeTab
(e.g., use activeTab or pane id as the React key) instead of a single unkeyed
motion.div, and render childArray items (or map over panes) into keyed
motion.div children so AnimatePresence can detect removals/additions and run the
exit/initial animations for AnimatePresence, motion.div and activeTab.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 3c901802-f941-41b0-9559-5c868866ebea
📒 Files selected for processing (2)
apps/www/components/component-preview-control.tsxapps/www/components/stream-panel/panel-popover.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/www/components/stream-panel/panel-popover.tsx
Summary by CodeRabbit
New Features
UI Improvements
Bug Fixes