Scrollable tabs (#3)
Some checks are pending
CodeQL / Analyze (push) Waiting to run

This commit is contained in:
Philip Peterson 2025-04-21 22:50:39 -07:00 committed by GitHub
parent 8c9af4af0d
commit 0c26db126a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 47 additions and 6 deletions

View file

@ -1,8 +1,8 @@
import React, {forwardRef} from 'react';
import React, {useEffect, useRef} from 'react';
import type {TabProps} from '../../typings/hyper';
const Tab = forwardRef<HTMLLIElement, TabProps>((props, ref) => {
const Tab = (props: TabProps) => {
const handleClick = (event: React.MouseEvent) => {
const isLeftClick = event.nativeEvent.which === 1;
@ -19,6 +19,16 @@ const Tab = forwardRef<HTMLLIElement, TabProps>((props, ref) => {
}
};
const ref = useRef<HTMLLIElement>(null);
useEffect(() => {
if (props.lastFocused) {
ref?.current?.scrollIntoView({
behavior: 'smooth'
});
}
}, [props.lastFocused]);
const {isActive, isFirst, isLast, borderColor, hasActivity} = props;
return (
@ -60,6 +70,7 @@ const Tab = forwardRef<HTMLLIElement, TabProps>((props, ref) => {
list-style-type: none;
flex-grow: 1;
position: relative;
min-width: 10em;
}
.tab_tab:hover {
@ -161,7 +172,7 @@ const Tab = forwardRef<HTMLLIElement, TabProps>((props, ref) => {
`}</style>
</>
);
});
};
Tab.displayName = 'Tab';

View file

@ -1,6 +1,8 @@
import React, {forwardRef} from 'react';
import React, {forwardRef, useEffect, useState} from 'react';
import type {TabsProps} from '../../typings/hyper';
import debounce from 'lodash/debounce';
import type {ITab, TabsProps} from '../../typings/hyper';
import {decorate, getTabProps} from '../utils/plugins';
import DropdownButton from './new-tab';
@ -12,6 +14,23 @@ const isMac = /Mac/.test(navigator.userAgent);
const Tabs = forwardRef<HTMLElement, TabsProps>((props, ref) => {
const {tabs = [], borderColor, onChange, onClose, fullScreen} = props;
const [shouldFocusCounter, setShouldFocusCounter] = useState({
index: 0,
when: undefined as Date | undefined
});
const scrollToActiveTab = debounce((currTabs: ITab[]) => {
const activeTab = currTabs.findIndex((t) => t.isActive);
setShouldFocusCounter({
index: activeTab,
when: new Date()
});
}, 100);
useEffect(() => {
scrollToActiveTab(tabs);
}, [tabs, tabs.length]);
const hide = !isMac && tabs.length === 1;
return (
@ -31,8 +50,12 @@ const Tabs = forwardRef<HTMLElement, TabsProps>((props, ref) => {
isActive,
hasActivity,
onSelect: onChange.bind(null, uid),
onClose: onClose.bind(null, uid)
onClose: onClose.bind(null, uid),
lastFocused: undefined as Date | undefined
});
if (shouldFocusCounter.index === i) {
tabProps.lastFocused = shouldFocusCounter.when;
}
return <Tab key={`tab-${uid}`} {...tabProps} />;
})}
</ul>
@ -85,6 +108,12 @@ const Tabs = forwardRef<HTMLElement, TabsProps>((props, ref) => {
flex-flow: row;
margin-left: ${isMac ? '76px' : '0'};
flex-grow: 1;
overflow-x: auto;
}
.tabs_list::-webkit-scrollbar,
.tabs_list::-webkit-scrollbar-button {
display: none;
}
.tabs_fullScreen {

1
typings/hyper.d.ts vendored
View file

@ -230,6 +230,7 @@ export type TabProps = {
onClose: () => void;
onSelect: () => void;
text: string;
lastFocused: Date | undefined;
} & extensionProps;
export type ITab = {