Skip to content

wip #81404

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 6 commits into
base: canary
Choose a base branch
from
Draft

wip #81404

wants to merge 6 commits into from

Conversation

RobPruzan
Copy link
Contributor

@RobPruzan RobPruzan commented Jul 8, 2025

Todos:

  • bug causing drag animation target location and calculated panel position to be off by a few px, causing a snap on animation end
  • how to deal with a panel thats moved to a corner, and then closed
    • jaring since the menu to select a new panel is in a different corner
  • minor ui stuff styling not transferred over in refactor
  • some accessibility not transferred over in refactor
  • determine if we should sync panel position across reload right now, or save of the future
  • missing a couple panel wrappers for a couple menu items
  • update segment explorer to be compatible with detachable panel UI
  • polish on UI defaults
  • transition when panel recalculates static position based on the logo being dragged to a new corner
  • update stories that were configurable via props with new storybook wrapper to be compatible with context

@huozhi huozhi changed the title [segment explorer] capture defined boundaries wip Jul 9, 2025
@RobPruzan RobPruzan force-pushed the detachable-panels-v2 branch from 5783f57 to d744857 Compare July 9, 2025 23:42
isBuildError={isBuildError}
scale={state.scale}
/>
<NextLogo ref={triggerRef} />
Copy link

Choose a reason for hiding this comment

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

The NextLogo component is not a forwardRef component but is being passed a ref={triggerRef} prop, which will cause the ref to not be attached to the actual button element.

📄 Review details

🔍 Technical Analysis

The NextLogo component on line 67 is receiving a ref={triggerRef} prop, but NextLogo is defined as a regular function component that accepts React.ComponentProps<'button'>, not a forwardRef component. This means the ref will not be forwarded to the actual button element inside NextLogo.

Looking at the NextLogo component implementation, it has its own internal triggerRef at line 40, but this is completely separate from the ref being passed from the parent component. The triggerRef from PanelContext is intended to be used for click-outside detection in useClickOutside(menuRef, triggerRef, closeOnClickOutside, ...) (see dev-overlay-menu.tsx line 45), but it will never be properly attached to the DOM element.

This will break functionality like:

  1. Click-outside detection for closing menus
  2. Focus management for accessibility
  3. Any other features that depend on having a reference to the trigger button

The bug manifests because there are two separate triggerRef references:

  • One created in dev-overlay.tsx line 62 and passed through PanelContext
  • Another created internally in NextLogo component line 40 that actually gets attached to the button

Only the internal one gets attached to the DOM, while the external one remains null, breaking dependent functionality.


🔧 Suggested Fix

Convert NextLogo to a forwardRef component to properly forward the ref to the button element:

export const NextLogo = React.forwardRef<HTMLButtonElement, React.ComponentProps<'button'>>(
  function NextLogo(buttonProps, forwardedRef) {
    // ... existing code ...
    
    // Remove the internal triggerRef and use forwardedRef instead:
    // const triggerRef = useRef<HTMLButtonElement | null>(null) // Remove this line
    
    // In the button JSX, use forwardedRef:
    <button
      id="next-logo"
      ref={forwardedRef}  // Use forwardedRef instead of triggerRef
      // ... rest of props
    >

This will ensure the ref from PanelContext is properly forwarded to the actual button element.


👍 or 👎 to improve Vade.

const width = measuredWidth === 0 ? 'auto' : measuredWidth

useEffect(() => {
setIsErrorExpanded(hasError)
}, [hasError])
console.log('its time for next logo',state.disableDevIndicator);
Copy link

Choose a reason for hiding this comment

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

Development console.log statement was left in the code that will pollute the console in production builds.

📄 Review details

🔍 Technical Analysis

A console.log('its time for next logo',state.disableDevIndicator); statement was left in the production code. This is a development debugging statement that should not be present in the final codebase as it will:

  1. Pollute the browser console for end users
  2. Create unnecessary logging noise in production environments
  3. Potentially expose internal state information
  4. Impact performance slightly due to unnecessary console operations

This appears to be a debugging statement that was accidentally committed along with the refactoring changes.


🔧 Suggested Fix

Remove the console.log statement:

// Remove this line:
console.log('its time for next logo',state.disableDevIndicator);

If logging is needed for debugging purposes, consider using a proper debug utility that can be conditionally enabled in development environments only, or use proper debugging tools instead of console.log statements in production code.


👍 or 👎 to improve Vade.


const triggerRef = useRef<HTMLButtonElement>(null)
// @ts-expect-error
process.env.__NEXT_DEVTOOL_NEW_PANEL_UI = true
Copy link

Choose a reason for hiding this comment

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

Direct runtime assignment to process.env.__NEXT_DEVTOOL_NEW_PANEL_UI = true mutates the process environment at runtime, which can cause issues in different deployment environments.

📄 Review details

🔍 Technical Analysis

The code directly assigns process.env.__NEXT_DEVTOOL_NEW_PANEL_UI = true at runtime inside a React component. This is problematic because:

  1. Process.env mutation: process.env is typically meant to be read-only after application startup. Mutating it at runtime can cause unpredictable behavior, especially in environments where process.env might be frozen or where multiple instances share the same process.

  2. Side effects in render: This assignment happens every time the component renders, which is a side effect that should not occur during rendering.

  3. Environment inconsistency: The value is being set conditionally based on runtime logic rather than build-time configuration, which can lead to inconsistent behavior across different environments or instances.

  4. TypeScript suppression: The @ts-expect-error comment indicates that TypeScript knows this is incorrect, but the error is being suppressed rather than fixed properly.

The assignment appears to be forcing the new panel UI to be enabled, but this should be determined at build time or through proper configuration, not through runtime mutation of process.env.


🔧 Suggested Fix

Remove the runtime process.env mutation and handle this through proper configuration:

  1. Remove the problematic line:
// Remove these lines:
// @ts-expect-error
process.env.__NEXT_DEVTOOL_NEW_PANEL_UI = true
  1. Use a proper constant or configuration:
// Add at the top of the file or in a config file:
const ENABLE_NEW_PANEL_UI = true // or read from proper config

// Then use this constant instead of process.env in the conditional:
scale={ENABLE_NEW_PANEL_UI ? state.scale : scale}
  1. If you need runtime control, use component state or context:
const [useNewPanelUI] = useState(true)
// or get from a configuration context

This ensures consistent behavior and avoids mutating the global process environment.


👍 or 👎 to improve Vade.

@RobPruzan RobPruzan force-pushed the detachable-panels-v2 branch from d744857 to a358d2a Compare July 10, 2025 01:04
return (
<DevToolsInfo
title={`${routeType} Route`}
learnMoreLink={learnMore}
close={close}
isOpen={isOpen}
triggerRef={{ current: null }}
Copy link

Choose a reason for hiding this comment

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

The RouteInfo component passes a hardcoded null ref object that will break focus management functionality.

📄 Review details

🔍 Technical Analysis

In the RouteInfo component, line 141 passes triggerRef={{ current: null }} to the DevToolsInfo component. This creates a static object with a null current property that never gets updated.

The DevToolsInfo component uses this triggerRef in useFocusTrap and useClickOutside hooks, which expect a proper React ref that can hold references to DOM elements. The useFocusTrap hook specifically calls triggerRef.current?.focus() to restore focus when the overlay closes, but this will never work because current is always null.

This will break keyboard navigation and focus management in the dev tools overlay, potentially making it inaccessible to keyboard users and breaking the expected UX flow when the overlay is dismissed.


🔧 Suggested Fix

Replace the hardcoded null ref with a proper useRef hook:

export function RouteInfo({ isOpen, close, ...props }: { isOpen: boolean; close: () => void } & HTMLProps<HTMLDivElement>) {
  const { state } = useDevOverlayContext()
  const triggerRef = useRef<HTMLButtonElement>(null) // Add this line

  const routeType = state.staticIndicator ? 'Static' : 'Dynamic'
  const learnMore = state.staticIndicator
    ? learnMoreLink[state.routerType].static
    : learnMoreLink[state.routerType].dynamic

  return (
    <DevToolsInfo
      title={`${routeType} Route`}
      learnMoreLink={learnMore}
      close={close}
      isOpen={isOpen}
      triggerRef={triggerRef} // Use the ref instead of { current: null }
      {...props}
    >
      <RouteInfoBody />
    </DevToolsInfo>
  )
}

Don't forget to import useRef from React.


👍 or 👎 to improve Vade.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants