Skip to content

Conversation

spence709
Copy link

Here’s exactly what I changed/fixed:

  • New feature (optional)

    • Layout prop: closeTabOnMiddleClick?: boolean (default false)
    • Middle‑click closes tabs and border tabs when enabled
    • Files: src/view/Layout.tsx, src/view/TabButton.tsx, src/view/BorderButton.tsx
  • Build error

    • Fixed TS7030 in BorderTabSet useEffect (returned undefined)
    • File: src/view/BorderTabSet.tsx
  • Render performance (fewer re‑renders)

    • Cache tab render base (icon/title/buttons) in getRenderStateEx; keyed by tab name/icon/angle and onRenderTab identity; always return fresh buttons array
    • Memoize customizeTabSet results in TabSet/BorderTabSet with useMemo; clone arrays before mutating
    • Memoize TabButton and BorderButton with React.memo
    • Files: src/view/Utils.tsx, src/view/TabSet.tsx, src/view/BorderTabSet.tsx, src/view/TabButton.tsx, src/view/BorderButton.tsx
  • Housekeeping

    • package.json: added packageManager field to pin pnpm version

Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds optional middle-click tab closing functionality and improves rendering performance through memoization and caching optimizations.

  • Introduces a new optional closeTabOnMiddleClick layout prop that enables middle-click to close tabs
  • Implements performance optimizations by caching tab render state and memoizing components to reduce re-renders
  • Fixes a TypeScript build error in BorderTabSet where useEffect returned undefined

Reviewed Changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/view/Layout.tsx Adds closeTabOnMiddleClick prop and accessor method
src/view/Utils.tsx Implements tab render state caching with WeakMap for performance
src/view/TabSet.tsx Memoizes customizeTabSet results and clones arrays before mutation
src/view/BorderTabSet.tsx Applies same memoization as TabSet and fixes useEffect return value
src/view/TabButton.tsx Adds middle-click handling and React.memo optimization
src/view/BorderButton.tsx Adds middle-click handling and React.memo optimization
package.json Pins pnpm version with packageManager field

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

return desktop;
}
/** @internal */
const tabRenderCache: WeakMap<TabNode, { key: string; base: { leading: React.ReactNode; content: React.ReactNode; name: string; buttons: any[] } }> = new WeakMap();
Copy link

Copilot AI Sep 23, 2025

Choose a reason for hiding this comment

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

The cache value type is complex and duplicated. Consider extracting it to an interface to improve maintainability and type safety.

Copilot uses AI. Check for mistakes.

const icon = node.getIcon();
const angle = iconAngle ?? 0;
const onRenderRef = (layout as any).props?.onRenderTab; // function identity
const cacheKey = `${name}|${icon ?? ''}|${angle}|${onRenderRef ? onRenderRef : 'no'}`;
Copy link

Copilot AI Sep 23, 2025

Choose a reason for hiding this comment

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

Using a function reference in a string cache key is unreliable since different function instances with identical behavior will create different cache keys. Consider using a more stable identifier or removing this from the cache key.

Suggested change
const cacheKey = `${name}|${icon ?? ''}|${angle}|${onRenderRef ? onRenderRef : 'no'}`;
const cacheKey = `${name}|${icon ?? ''}|${angle}|${onRenderRef ? (onRenderRef.name || 'anon') : 'no'}`;

Copilot uses AI. Check for mistakes.

layout.customizeTabSet(node, rs);
return rs;
// depend on node identity and callback identity
}, [node, (layout as any).props?.onRenderTabSet]);
Copy link

Copilot AI Sep 23, 2025

Choose a reason for hiding this comment

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

The type assertion (layout as any) should be avoided. Consider properly typing the layout props or accessing the callback through a typed interface.

Suggested change
}, [node, (layout as any).props?.onRenderTabSet]);
}, [node, layout.onRenderTabSet]);

Copilot uses AI. Check for mistakes.

const rs: ITabSetRenderValues = { leading: undefined, buttons: [], stickyButtons: [], overflowPosition: undefined };
layout.customizeTabSet(border, rs);
return rs;
}, [border, (layout as any).props?.onRenderTabSet]);
Copy link

Copilot AI Sep 23, 2025

Choose a reason for hiding this comment

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

The type assertion (layout as any) should be avoided. Consider properly typing the layout props or accessing the callback through a typed interface.

Copilot uses AI. Check for mistakes.

@powerdragonfire
Copy link
Owner

Just waiting on fix to pinning feature to fix previous commit, will merge after.
caplin#503

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants