mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-22 00:05:51 +00:00
更新大量 tsx 原始文件; 已经迁移 login panel; 部分 (#121)
* style(B1-1): 格式化 ink/buddy/cli/context/screens/tasks/services/keybindings/state (43 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 修复了 Box.tsx 和 ScrollBox.tsx 中无效的 global.d.ts import。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-2): 格式化 commands (79 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-3): 格式化 components/messages,permissions,mcp,sandbox,shell (104 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-4): 格式化 components/PromptInput,FeedbackSurvey,tasks,agents,skills,design-system,wizard (73 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-5): 格式化 components其余 + hooks + tools (232 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-6): 格式化 main/entrypoints/utils/moreright (21 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 更新 README,新增 Run.ps1/TODO.md,删除 V6.md - README.md: 大幅重写,更详细版本历史和配置示例 - Run.ps1: 新增 Windows 启动脚本 - TODO.md: 新增包完成清单 - V6.md: 删除(架构重构规划已不适用) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: 修复以前的问题 * fix: 修复 login 面板的问题 --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,28 +1,37 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import React, { createContext, useCallback, useContext, useEffect, useState } from 'react';
|
||||
import { useIsInsideModal, useModalScrollRef } from '../../context/modalContext.js';
|
||||
import { useTerminalSize } from '../../hooks/useTerminalSize.js';
|
||||
import ScrollBox from '../../ink/components/ScrollBox.js';
|
||||
import type { KeyboardEvent } from '../../ink/events/keyboard-event.js';
|
||||
import { stringWidth } from '../../ink/stringWidth.js';
|
||||
import { Box, Text } from '../../ink.js';
|
||||
import { useKeybindings } from '../../keybindings/useKeybinding.js';
|
||||
import type { Theme } from '../../utils/theme.js';
|
||||
import React, {
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react'
|
||||
import {
|
||||
useIsInsideModal,
|
||||
useModalScrollRef,
|
||||
} from '../../context/modalContext.js'
|
||||
import { useTerminalSize } from '../../hooks/useTerminalSize.js'
|
||||
import ScrollBox from '../../ink/components/ScrollBox.js'
|
||||
import type { KeyboardEvent } from '../../ink/events/keyboard-event.js'
|
||||
import { stringWidth } from '../../ink/stringWidth.js'
|
||||
import { Box, Text } from '../../ink.js'
|
||||
import { useKeybindings } from '../../keybindings/useKeybinding.js'
|
||||
import type { Theme } from '../../utils/theme.js'
|
||||
|
||||
type TabsProps = {
|
||||
children: Array<React.ReactElement<TabProps>>;
|
||||
title?: string;
|
||||
color?: keyof Theme;
|
||||
defaultTab?: string;
|
||||
hidden?: boolean;
|
||||
useFullWidth?: boolean;
|
||||
children: Array<React.ReactElement<TabProps>>
|
||||
title?: string
|
||||
color?: keyof Theme
|
||||
defaultTab?: string
|
||||
hidden?: boolean
|
||||
useFullWidth?: boolean
|
||||
/** Controlled mode: current selected tab id/title */
|
||||
selectedTab?: string;
|
||||
selectedTab?: string
|
||||
/** Controlled mode: callback when tab changes */
|
||||
onTabChange?: (tabId: string) => void;
|
||||
onTabChange?: (tabId: string) => void
|
||||
/** Optional banner to display below tabs header */
|
||||
banner?: React.ReactNode;
|
||||
banner?: React.ReactNode
|
||||
/** Disable keyboard navigation (e.g. when a child component handles arrow keys) */
|
||||
disableNavigation?: boolean;
|
||||
disableNavigation?: boolean
|
||||
/**
|
||||
* Initial focus state for the tab header row. Defaults to true (header
|
||||
* focused, nav always works). Keep the default for Select/list content —
|
||||
@@ -31,28 +40,30 @@ type TabsProps = {
|
||||
* content actually binds left/right/tab (e.g. enum cycling), and show a
|
||||
* "↑ tabs" footer hint — without it tabs look broken.
|
||||
*/
|
||||
initialHeaderFocused?: boolean;
|
||||
initialHeaderFocused?: boolean
|
||||
/**
|
||||
* Fixed height for the content area. When set, all tabs render within the
|
||||
* same height (overflow hidden) so switching tabs doesn't cause layout
|
||||
* shifts. Shorter tabs get whitespace; taller tabs are clipped.
|
||||
*/
|
||||
contentHeight?: number;
|
||||
contentHeight?: number
|
||||
/**
|
||||
* Let Tab/←/→ switch tabs from focused content. Opt-in since some
|
||||
* content uses those keys; pass a reactive boolean to cede them when
|
||||
* needed. Switching from content focuses the header.
|
||||
*/
|
||||
navFromContent?: boolean;
|
||||
};
|
||||
navFromContent?: boolean
|
||||
}
|
||||
|
||||
type TabsContextValue = {
|
||||
selectedTab: string | undefined;
|
||||
width: number | undefined;
|
||||
headerFocused: boolean;
|
||||
focusHeader: () => void;
|
||||
blurHeader: () => void;
|
||||
registerOptIn: () => () => void;
|
||||
};
|
||||
selectedTab: string | undefined
|
||||
width: number | undefined
|
||||
headerFocused: boolean
|
||||
focusHeader: () => void
|
||||
blurHeader: () => void
|
||||
registerOptIn: () => () => void
|
||||
}
|
||||
|
||||
const TabsContext = createContext<TabsContextValue>({
|
||||
selectedTab: undefined,
|
||||
width: undefined,
|
||||
@@ -61,236 +72,248 @@ const TabsContext = createContext<TabsContextValue>({
|
||||
headerFocused: false,
|
||||
focusHeader: () => {},
|
||||
blurHeader: () => {},
|
||||
registerOptIn: () => () => {}
|
||||
});
|
||||
export function Tabs(t0) {
|
||||
const $ = _c(25);
|
||||
const {
|
||||
title,
|
||||
color,
|
||||
defaultTab,
|
||||
children,
|
||||
hidden,
|
||||
useFullWidth,
|
||||
selectedTab: controlledSelectedTab,
|
||||
onTabChange,
|
||||
banner,
|
||||
disableNavigation,
|
||||
initialHeaderFocused: t1,
|
||||
contentHeight,
|
||||
navFromContent: t2
|
||||
} = t0;
|
||||
const initialHeaderFocused = t1 === undefined ? true : t1;
|
||||
const navFromContent = t2 === undefined ? false : t2;
|
||||
const {
|
||||
columns: terminalWidth
|
||||
} = useTerminalSize();
|
||||
const tabs = children.map(_temp);
|
||||
const defaultTabIndex = defaultTab ? tabs.findIndex(tab => defaultTab === tab[0]) : 0;
|
||||
const isControlled = controlledSelectedTab !== undefined;
|
||||
const [internalSelectedTab, setInternalSelectedTab] = useState(defaultTabIndex !== -1 ? defaultTabIndex : 0);
|
||||
const controlledTabIndex = isControlled ? tabs.findIndex(tab_0 => tab_0[0] === controlledSelectedTab) : -1;
|
||||
const selectedTabIndex = isControlled ? controlledTabIndex !== -1 ? controlledTabIndex : 0 : internalSelectedTab;
|
||||
const modalScrollRef = useModalScrollRef();
|
||||
const [headerFocused, setHeaderFocused] = useState(initialHeaderFocused);
|
||||
let t3;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t3 = () => setHeaderFocused(true);
|
||||
$[0] = t3;
|
||||
} else {
|
||||
t3 = $[0];
|
||||
}
|
||||
const focusHeader = t3;
|
||||
let t4;
|
||||
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t4 = () => setHeaderFocused(false);
|
||||
$[1] = t4;
|
||||
} else {
|
||||
t4 = $[1];
|
||||
}
|
||||
const blurHeader = t4;
|
||||
const [optInCount, setOptInCount] = useState(0);
|
||||
let t5;
|
||||
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t5 = () => {
|
||||
setOptInCount(_temp2);
|
||||
return () => setOptInCount(_temp3);
|
||||
};
|
||||
$[2] = t5;
|
||||
} else {
|
||||
t5 = $[2];
|
||||
}
|
||||
const registerOptIn = t5;
|
||||
const optedIn = optInCount > 0;
|
||||
const handleTabChange = offset => {
|
||||
const newIndex = (selectedTabIndex + tabs.length + offset) % tabs.length;
|
||||
const newTabId = tabs[newIndex]?.[0];
|
||||
registerOptIn: () => () => {},
|
||||
})
|
||||
|
||||
export function Tabs({
|
||||
title,
|
||||
color,
|
||||
defaultTab,
|
||||
children,
|
||||
hidden,
|
||||
useFullWidth,
|
||||
selectedTab: controlledSelectedTab,
|
||||
onTabChange,
|
||||
banner,
|
||||
disableNavigation,
|
||||
initialHeaderFocused = true,
|
||||
contentHeight,
|
||||
navFromContent = false,
|
||||
}: TabsProps): React.ReactNode {
|
||||
const { columns: terminalWidth } = useTerminalSize()
|
||||
const tabs = children.map(child => [
|
||||
child.props.id ?? child.props.title,
|
||||
child.props.title,
|
||||
])
|
||||
const defaultTabIndex = defaultTab
|
||||
? tabs.findIndex(tab => defaultTab === tab[0])
|
||||
: 0
|
||||
|
||||
// Support both controlled and uncontrolled modes
|
||||
const isControlled = controlledSelectedTab !== undefined
|
||||
const [internalSelectedTab, setInternalSelectedTab] = useState(
|
||||
defaultTabIndex !== -1 ? defaultTabIndex : 0,
|
||||
)
|
||||
|
||||
// In controlled mode, find the index of the controlled tab
|
||||
const controlledTabIndex = isControlled
|
||||
? tabs.findIndex(tab => tab[0] === controlledSelectedTab)
|
||||
: -1
|
||||
const selectedTabIndex = isControlled
|
||||
? controlledTabIndex !== -1
|
||||
? controlledTabIndex
|
||||
: 0
|
||||
: internalSelectedTab
|
||||
|
||||
const modalScrollRef = useModalScrollRef()
|
||||
|
||||
// Header focus: left/right/tab only switch tabs when the header row is
|
||||
// focused. Children with interactive content call focusHeader() (via
|
||||
// useTabHeaderFocus) on up-arrow to hand focus back here; down-arrow
|
||||
// returns it. Tabs that never call the hook see no behavior change —
|
||||
// initialHeaderFocused defaults to true so nav always works.
|
||||
const [headerFocused, setHeaderFocused] = useState(initialHeaderFocused)
|
||||
const focusHeader = useCallback(() => setHeaderFocused(true), [])
|
||||
const blurHeader = useCallback(() => setHeaderFocused(false), [])
|
||||
// Count of mounted children using useTabHeaderFocus(). Down-arrow blur and
|
||||
// the ↓ hint only engage when at least one child has opted in — otherwise
|
||||
// pressing down on a legacy tab would strand the user with nav disabled.
|
||||
const [optInCount, setOptInCount] = useState(0)
|
||||
const registerOptIn = useCallback(() => {
|
||||
setOptInCount(n => n + 1)
|
||||
return () => setOptInCount(n => n - 1)
|
||||
}, [])
|
||||
const optedIn = optInCount > 0
|
||||
|
||||
const handleTabChange = (offset: number) => {
|
||||
const newIndex = (selectedTabIndex + tabs.length + offset) % tabs.length
|
||||
const newTabId = tabs[newIndex]?.[0]
|
||||
|
||||
if (isControlled && onTabChange && newTabId) {
|
||||
onTabChange(newTabId);
|
||||
onTabChange(newTabId)
|
||||
} else {
|
||||
setInternalSelectedTab(newIndex);
|
||||
setInternalSelectedTab(newIndex)
|
||||
}
|
||||
setHeaderFocused(true);
|
||||
};
|
||||
const t6 = !hidden && !disableNavigation && headerFocused;
|
||||
let t7;
|
||||
if ($[3] !== t6) {
|
||||
t7 = {
|
||||
context: "Tabs",
|
||||
isActive: t6
|
||||
};
|
||||
$[3] = t6;
|
||||
$[4] = t7;
|
||||
} else {
|
||||
t7 = $[4];
|
||||
// Tab switching is a header action — stay focused so the user can keep
|
||||
// cycling. The newly mounted tab can blur via its own interaction.
|
||||
setHeaderFocused(true)
|
||||
}
|
||||
useKeybindings({
|
||||
"tabs:next": () => handleTabChange(1),
|
||||
"tabs:previous": () => handleTabChange(-1)
|
||||
}, t7);
|
||||
let t8;
|
||||
if ($[5] !== headerFocused || $[6] !== hidden || $[7] !== optedIn) {
|
||||
t8 = e => {
|
||||
if (!headerFocused || !optedIn || hidden) {
|
||||
return;
|
||||
}
|
||||
if (e.key === "down") {
|
||||
e.preventDefault();
|
||||
setHeaderFocused(false);
|
||||
}
|
||||
};
|
||||
$[5] = headerFocused;
|
||||
$[6] = hidden;
|
||||
$[7] = optedIn;
|
||||
$[8] = t8;
|
||||
} else {
|
||||
t8 = $[8];
|
||||
}
|
||||
const handleKeyDown = t8;
|
||||
const t9 = navFromContent && !headerFocused && optedIn && !hidden && !disableNavigation;
|
||||
let t10;
|
||||
if ($[9] !== t9) {
|
||||
t10 = {
|
||||
context: "Tabs",
|
||||
isActive: t9
|
||||
};
|
||||
$[9] = t9;
|
||||
$[10] = t10;
|
||||
} else {
|
||||
t10 = $[10];
|
||||
}
|
||||
useKeybindings({
|
||||
"tabs:next": () => {
|
||||
handleTabChange(1);
|
||||
setHeaderFocused(true);
|
||||
|
||||
useKeybindings(
|
||||
{
|
||||
'tabs:next': () => handleTabChange(1),
|
||||
'tabs:previous': () => handleTabChange(-1),
|
||||
},
|
||||
"tabs:previous": () => {
|
||||
handleTabChange(-1);
|
||||
setHeaderFocused(true);
|
||||
{
|
||||
context: 'Tabs',
|
||||
isActive: !hidden && !disableNavigation && headerFocused,
|
||||
},
|
||||
)
|
||||
|
||||
// When the header is focused, down-arrow returns focus to content. Only
|
||||
// active when the selected tab has opted in via useTabHeaderFocus() —
|
||||
// legacy tabs have nowhere to return focus to.
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (!headerFocused || !optedIn || hidden) return
|
||||
if (e.key === 'down') {
|
||||
e.preventDefault()
|
||||
setHeaderFocused(false)
|
||||
}
|
||||
}, t10);
|
||||
const titleWidth = title ? stringWidth(title) + 1 : 0;
|
||||
const tabsWidth = tabs.reduce(_temp4, 0);
|
||||
const usedWidth = titleWidth + tabsWidth;
|
||||
const spacerWidth = useFullWidth ? Math.max(0, terminalWidth - usedWidth) : 0;
|
||||
const contentWidth = useFullWidth ? terminalWidth : undefined;
|
||||
const T0 = Box;
|
||||
const t11 = "column";
|
||||
const t12 = 0;
|
||||
const t13 = true;
|
||||
const t14 = modalScrollRef ? 0 : undefined;
|
||||
const t15 = !hidden && <Box flexDirection="row" gap={1} flexShrink={modalScrollRef ? 0 : undefined}>{title !== undefined && <Text bold={true} color={color}>{title}</Text>}{tabs.map((t16, i) => {
|
||||
const [id, title_0] = t16;
|
||||
const isCurrent = selectedTabIndex === i;
|
||||
const hasColorCursor = color && isCurrent && headerFocused;
|
||||
return <Text key={id} backgroundColor={hasColorCursor ? color : undefined} color={hasColorCursor ? "inverseText" : undefined} inverse={isCurrent && !hasColorCursor} bold={isCurrent}>{" "}{title_0}{" "}</Text>;
|
||||
})}{spacerWidth > 0 && <Text>{" ".repeat(spacerWidth)}</Text>}</Box>;
|
||||
let t17;
|
||||
if ($[11] !== children || $[12] !== contentHeight || $[13] !== contentWidth || $[14] !== hidden || $[15] !== modalScrollRef || $[16] !== selectedTabIndex) {
|
||||
t17 = modalScrollRef ? <Box width={contentWidth} marginTop={hidden ? 0 : 1} flexShrink={0}><ScrollBox key={selectedTabIndex} ref={modalScrollRef} flexDirection="column" flexShrink={0}>{children}</ScrollBox></Box> : <Box width={contentWidth} marginTop={hidden ? 0 : 1} height={contentHeight} overflowY={contentHeight !== undefined ? "hidden" : undefined}>{children}</Box>;
|
||||
$[11] = children;
|
||||
$[12] = contentHeight;
|
||||
$[13] = contentWidth;
|
||||
$[14] = hidden;
|
||||
$[15] = modalScrollRef;
|
||||
$[16] = selectedTabIndex;
|
||||
$[17] = t17;
|
||||
} else {
|
||||
t17 = $[17];
|
||||
}
|
||||
let t18;
|
||||
if ($[18] !== T0 || $[19] !== banner || $[20] !== handleKeyDown || $[21] !== t14 || $[22] !== t15 || $[23] !== t17) {
|
||||
t18 = <T0 flexDirection={t11} tabIndex={t12} autoFocus={t13} onKeyDown={handleKeyDown} flexShrink={t14}>{t15}{banner}{t17}</T0>;
|
||||
$[18] = T0;
|
||||
$[19] = banner;
|
||||
$[20] = handleKeyDown;
|
||||
$[21] = t14;
|
||||
$[22] = t15;
|
||||
$[23] = t17;
|
||||
$[24] = t18;
|
||||
} else {
|
||||
t18 = $[24];
|
||||
}
|
||||
return <TabsContext.Provider value={{
|
||||
selectedTab: tabs[selectedTabIndex][0],
|
||||
width: contentWidth,
|
||||
headerFocused,
|
||||
focusHeader,
|
||||
blurHeader,
|
||||
registerOptIn
|
||||
}}>{t18}</TabsContext.Provider>;
|
||||
}
|
||||
function _temp4(sum, t0) {
|
||||
const [, tabTitle] = t0;
|
||||
return sum + (tabTitle ? stringWidth(tabTitle) : 0) + 2 + 1;
|
||||
}
|
||||
function _temp3(n_0) {
|
||||
return n_0 - 1;
|
||||
}
|
||||
function _temp2(n) {
|
||||
return n + 1;
|
||||
}
|
||||
function _temp(child) {
|
||||
return [child.props.id ?? child.props.title, child.props.title];
|
||||
|
||||
// Opt-in: same tabs:next/previous actions, active from content. Focuses
|
||||
// the header so subsequent presses cycle via the handler above.
|
||||
useKeybindings(
|
||||
{
|
||||
'tabs:next': () => {
|
||||
handleTabChange(1)
|
||||
setHeaderFocused(true)
|
||||
},
|
||||
'tabs:previous': () => {
|
||||
handleTabChange(-1)
|
||||
setHeaderFocused(true)
|
||||
},
|
||||
},
|
||||
{
|
||||
context: 'Tabs',
|
||||
isActive:
|
||||
navFromContent &&
|
||||
!headerFocused &&
|
||||
optedIn &&
|
||||
!hidden &&
|
||||
!disableNavigation,
|
||||
},
|
||||
)
|
||||
|
||||
// Calculate spacing to fill the available width. No keyboard hint in the
|
||||
// header row — content footers own hints (see useTabHeaderFocus docs).
|
||||
const titleWidth = title ? stringWidth(title) + 1 : 0 // +1 for gap
|
||||
const tabsWidth = tabs.reduce(
|
||||
(sum, [, tabTitle]) => sum + (tabTitle ? stringWidth(tabTitle) : 0) + 2 + 1, // +2 for padding, +1 for gap
|
||||
0,
|
||||
)
|
||||
const usedWidth = titleWidth + tabsWidth
|
||||
const spacerWidth = useFullWidth ? Math.max(0, terminalWidth - usedWidth) : 0
|
||||
|
||||
const contentWidth = useFullWidth ? terminalWidth : undefined
|
||||
|
||||
return (
|
||||
<TabsContext.Provider
|
||||
value={{
|
||||
selectedTab: tabs[selectedTabIndex]![0],
|
||||
width: contentWidth,
|
||||
headerFocused,
|
||||
focusHeader,
|
||||
blurHeader,
|
||||
registerOptIn,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
flexDirection="column"
|
||||
tabIndex={0}
|
||||
autoFocus
|
||||
onKeyDown={handleKeyDown}
|
||||
// flexShrink=0 inside modal slot — the modal's absolute Box has no
|
||||
// explicit height (grows to fit, maxHeight cap), so flexGrow=1 here
|
||||
// resolves to 0 on re-render and the body blanks on Down arrow.
|
||||
// See #23592. Outside modal, leave layout alone.
|
||||
flexShrink={modalScrollRef ? 0 : undefined}
|
||||
>
|
||||
{!hidden && (
|
||||
<Box
|
||||
flexDirection="row"
|
||||
gap={1}
|
||||
flexShrink={modalScrollRef ? 0 : undefined}
|
||||
>
|
||||
{title !== undefined && (
|
||||
<Text bold color={color}>
|
||||
{title}
|
||||
</Text>
|
||||
)}
|
||||
{tabs.map(([id, title], i) => {
|
||||
const isCurrent = selectedTabIndex === i
|
||||
const hasColorCursor = color && isCurrent && headerFocused
|
||||
return (
|
||||
<Text
|
||||
key={id}
|
||||
backgroundColor={hasColorCursor ? color : undefined}
|
||||
color={hasColorCursor ? 'inverseText' : undefined}
|
||||
inverse={isCurrent && !hasColorCursor}
|
||||
bold={isCurrent}
|
||||
>
|
||||
{' '}
|
||||
{title}{' '}
|
||||
</Text>
|
||||
)
|
||||
})}
|
||||
{spacerWidth > 0 && <Text>{' '.repeat(spacerWidth)}</Text>}
|
||||
</Box>
|
||||
)}
|
||||
{banner}
|
||||
{modalScrollRef ? (
|
||||
// Inside the modal slot: own the ScrollBox here so the tabs
|
||||
// header row above sits OUTSIDE the scroll area — it can never
|
||||
// scroll off. The ref reaches REPL's ScrollKeybindingHandler via
|
||||
// ModalContext. Keyed by selectedTabIndex → remounts on tab
|
||||
// switch, resetting scrollTop to 0 without scrollTo() timing games.
|
||||
<Box width={contentWidth} marginTop={hidden ? 0 : 1} flexShrink={0}>
|
||||
<ScrollBox
|
||||
key={selectedTabIndex}
|
||||
ref={modalScrollRef}
|
||||
flexDirection="column"
|
||||
flexShrink={0}
|
||||
>
|
||||
{children}
|
||||
</ScrollBox>
|
||||
</Box>
|
||||
) : (
|
||||
<Box
|
||||
width={contentWidth}
|
||||
marginTop={hidden ? 0 : 1}
|
||||
height={contentHeight}
|
||||
overflowY={contentHeight !== undefined ? 'hidden' : undefined}
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</TabsContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
type TabProps = {
|
||||
title: string;
|
||||
id?: string;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
export function Tab(t0) {
|
||||
const $ = _c(4);
|
||||
const {
|
||||
title,
|
||||
id,
|
||||
children
|
||||
} = t0;
|
||||
const {
|
||||
selectedTab,
|
||||
width
|
||||
} = useContext(TabsContext);
|
||||
const insideModal = useIsInsideModal();
|
||||
if (selectedTab !== (id ?? title)) {
|
||||
return null;
|
||||
}
|
||||
const t1 = insideModal ? 0 : undefined;
|
||||
let t2;
|
||||
if ($[0] !== children || $[1] !== t1 || $[2] !== width) {
|
||||
t2 = <Box width={width} flexShrink={t1}>{children}</Box>;
|
||||
$[0] = children;
|
||||
$[1] = t1;
|
||||
$[2] = width;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
return t2;
|
||||
title: string
|
||||
id?: string
|
||||
children: React.ReactNode
|
||||
}
|
||||
export function useTabsWidth() {
|
||||
const {
|
||||
width
|
||||
} = useContext(TabsContext);
|
||||
return width;
|
||||
|
||||
export function Tab({ title, id, children }: TabProps): React.ReactNode {
|
||||
const { selectedTab, width } = useContext(TabsContext)
|
||||
const insideModal = useIsInsideModal()
|
||||
if (selectedTab !== (id ?? title)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Box width={width} flexShrink={insideModal ? 0 : undefined}>
|
||||
{children}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export function useTabsWidth(): number | undefined {
|
||||
const { width } = useContext(TabsContext)
|
||||
return width
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -304,36 +327,13 @@ export function useTabsWidth() {
|
||||
* no onUpFromFirstItem to recover. Split the component so the hook only runs
|
||||
* when the Select renders.
|
||||
*/
|
||||
export function useTabHeaderFocus() {
|
||||
const $ = _c(6);
|
||||
const {
|
||||
headerFocused,
|
||||
focusHeader,
|
||||
blurHeader,
|
||||
registerOptIn
|
||||
} = useContext(TabsContext);
|
||||
let t0;
|
||||
if ($[0] !== registerOptIn) {
|
||||
t0 = [registerOptIn];
|
||||
$[0] = registerOptIn;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
useEffect(registerOptIn, t0);
|
||||
let t1;
|
||||
if ($[2] !== blurHeader || $[3] !== focusHeader || $[4] !== headerFocused) {
|
||||
t1 = {
|
||||
headerFocused,
|
||||
focusHeader,
|
||||
blurHeader
|
||||
};
|
||||
$[2] = blurHeader;
|
||||
$[3] = focusHeader;
|
||||
$[4] = headerFocused;
|
||||
$[5] = t1;
|
||||
} else {
|
||||
t1 = $[5];
|
||||
}
|
||||
return t1;
|
||||
export function useTabHeaderFocus(): {
|
||||
headerFocused: boolean
|
||||
focusHeader: () => void
|
||||
blurHeader: () => void
|
||||
} {
|
||||
const { headerFocused, focusHeader, blurHeader, registerOptIn } =
|
||||
useContext(TabsContext)
|
||||
useEffect(registerOptIn, [registerOptIn])
|
||||
return { headerFocused, focusHeader, blurHeader }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user