mirror of
https://github.com/quine-global/hyper.git
synced 2026-01-12 20:18:41 -09:00
Convert tab, tabs and searchBox to function components
This commit is contained in:
parent
a793a1d9a4
commit
6c8d0433d2
3 changed files with 360 additions and 391 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
import React, {useCallback} from 'react';
|
import React, {useCallback, useRef, useEffect} from 'react';
|
||||||
import type {SearchBoxProps} from '../hyper';
|
import type {SearchBoxProps} from '../hyper';
|
||||||
import {VscArrowUp} from '@react-icons/all-files/vsc/VscArrowUp';
|
import {VscArrowUp} from '@react-icons/all-files/vsc/VscArrowUp';
|
||||||
import {VscArrowDown} from '@react-icons/all-files/vsc/VscArrowDown';
|
import {VscArrowDown} from '@react-icons/all-files/vsc/VscArrowDown';
|
||||||
|
|
@ -82,179 +82,152 @@ const SearchButton = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SearchBox extends React.PureComponent<SearchBoxProps> {
|
const SearchBox = (props: SearchBoxProps) => {
|
||||||
searchTerm: string;
|
const {
|
||||||
input: HTMLInputElement | null = null;
|
caseSensitive,
|
||||||
searchButtonColors: SearchButtonColors;
|
wholeWord,
|
||||||
|
regex,
|
||||||
|
results,
|
||||||
|
toggleCaseSensitive,
|
||||||
|
toggleWholeWord,
|
||||||
|
toggleRegex,
|
||||||
|
next,
|
||||||
|
prev,
|
||||||
|
close,
|
||||||
|
backgroundColor,
|
||||||
|
foregroundColor,
|
||||||
|
borderColor,
|
||||||
|
selectionColor,
|
||||||
|
font
|
||||||
|
} = props;
|
||||||
|
|
||||||
constructor(props: SearchBoxProps) {
|
const searchTermRef = useRef<string>('');
|
||||||
super(props);
|
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||||
this.searchTerm = '';
|
|
||||||
this.searchButtonColors = {
|
|
||||||
backgroundColor: this.props.borderColor,
|
|
||||||
selectionColor: this.props.selectionColor,
|
|
||||||
foregroundColor: this.props.foregroundColor
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChange = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
const handleChange = useCallback(
|
||||||
this.searchTerm = event.currentTarget.value;
|
(event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
if (event.shiftKey && event.key === 'Enter') {
|
searchTermRef.current = event.currentTarget.value;
|
||||||
this.props.prev(this.searchTerm);
|
if (event.shiftKey && event.key === 'Enter') {
|
||||||
} else if (event.key === 'Enter') {
|
prev(searchTermRef.current);
|
||||||
this.props.next(this.searchTerm);
|
} else if (event.key === 'Enter') {
|
||||||
}
|
next(searchTermRef.current);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[prev, next]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
inputRef.current?.focus();
|
||||||
|
}, [inputRef.current]);
|
||||||
|
|
||||||
|
const searchButtonColors: SearchButtonColors = {
|
||||||
|
backgroundColor: borderColor,
|
||||||
|
selectionColor,
|
||||||
|
foregroundColor
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount(): void {
|
return (
|
||||||
this.input?.focus();
|
<div className="flex-row search-container">
|
||||||
}
|
<div className="flex-row search-box">
|
||||||
|
<input className="search-input" type="text" onKeyDown={handleChange} ref={inputRef} placeholder="Search" />
|
||||||
|
|
||||||
render() {
|
<SearchButton onClick={toggleCaseSensitive} active={caseSensitive} title="Match Case" {...searchButtonColors}>
|
||||||
const {
|
<VscCaseSensitive size="14px" />
|
||||||
caseSensitive,
|
</SearchButton>
|
||||||
wholeWord,
|
|
||||||
regex,
|
|
||||||
results,
|
|
||||||
toggleCaseSensitive,
|
|
||||||
toggleWholeWord,
|
|
||||||
toggleRegex,
|
|
||||||
next,
|
|
||||||
prev,
|
|
||||||
close,
|
|
||||||
backgroundColor,
|
|
||||||
foregroundColor,
|
|
||||||
borderColor,
|
|
||||||
selectionColor,
|
|
||||||
font
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
return (
|
<SearchButton onClick={toggleWholeWord} active={wholeWord} title="Match Whole Word" {...searchButtonColors}>
|
||||||
<div className="flex-row search-container">
|
<VscWholeWord size="14px" />
|
||||||
<div className="flex-row search-box">
|
</SearchButton>
|
||||||
<input
|
|
||||||
className="search-input"
|
|
||||||
type="text"
|
|
||||||
onKeyDown={this.handleChange}
|
|
||||||
ref={(input) => {
|
|
||||||
this.input = input;
|
|
||||||
}}
|
|
||||||
placeholder="Search"
|
|
||||||
></input>
|
|
||||||
|
|
||||||
<SearchButton
|
<SearchButton onClick={toggleRegex} active={regex} title="Use Regular Expression" {...searchButtonColors}>
|
||||||
onClick={toggleCaseSensitive}
|
<VscRegex size="14px" />
|
||||||
active={caseSensitive}
|
</SearchButton>
|
||||||
title="Match Case"
|
|
||||||
{...this.searchButtonColors}
|
|
||||||
>
|
|
||||||
<VscCaseSensitive size="14px" />
|
|
||||||
</SearchButton>
|
|
||||||
|
|
||||||
<SearchButton
|
|
||||||
onClick={toggleWholeWord}
|
|
||||||
active={wholeWord}
|
|
||||||
title="Match Whole Word"
|
|
||||||
{...this.searchButtonColors}
|
|
||||||
>
|
|
||||||
<VscWholeWord size="14px" />
|
|
||||||
</SearchButton>
|
|
||||||
|
|
||||||
<SearchButton
|
|
||||||
onClick={toggleRegex}
|
|
||||||
active={regex}
|
|
||||||
title="Use Regular Expression"
|
|
||||||
{...this.searchButtonColors}
|
|
||||||
>
|
|
||||||
<VscRegex size="14px" />
|
|
||||||
</SearchButton>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span style={{minWidth: '60px', marginLeft: '4px'}}>
|
|
||||||
{results === undefined
|
|
||||||
? ''
|
|
||||||
: results.resultCount === 0
|
|
||||||
? 'No results'
|
|
||||||
: `${results.resultIndex + 1} of ${results.resultCount}`}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div className="flex-row">
|
|
||||||
<SearchButton
|
|
||||||
onClick={() => prev(this.searchTerm)}
|
|
||||||
active={false}
|
|
||||||
title="Previous Match"
|
|
||||||
{...this.searchButtonColors}
|
|
||||||
>
|
|
||||||
<VscArrowUp size="14px" />
|
|
||||||
</SearchButton>
|
|
||||||
|
|
||||||
<SearchButton
|
|
||||||
onClick={() => next(this.searchTerm)}
|
|
||||||
active={false}
|
|
||||||
title="Next Match"
|
|
||||||
{...this.searchButtonColors}
|
|
||||||
>
|
|
||||||
<VscArrowDown size="14px" />
|
|
||||||
</SearchButton>
|
|
||||||
|
|
||||||
<SearchButton onClick={() => close()} active={false} title="Close" {...this.searchButtonColors}>
|
|
||||||
<VscClose size="14px" />
|
|
||||||
</SearchButton>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style jsx>
|
|
||||||
{`
|
|
||||||
.search-container {
|
|
||||||
background-color: ${backgroundColor};
|
|
||||||
border: 1px solid ${borderColor};
|
|
||||||
border-radius: 2px;
|
|
||||||
position: absolute;
|
|
||||||
right: 13px;
|
|
||||||
top: 4px;
|
|
||||||
z-index: 10;
|
|
||||||
padding: 4px;
|
|
||||||
font-family: ${font};
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-input {
|
|
||||||
outline: none;
|
|
||||||
background-color: transparent;
|
|
||||||
border: none;
|
|
||||||
color: ${foregroundColor};
|
|
||||||
align-self: stretch;
|
|
||||||
width: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-row {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-box {
|
|
||||||
border: none;
|
|
||||||
border-radius: 2px;
|
|
||||||
outline: ${borderColor} solid 1px;
|
|
||||||
background-color: ${backgroundColor};
|
|
||||||
color: ${foregroundColor};
|
|
||||||
padding: 0px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-input::placeholder {
|
|
||||||
color: ${foregroundColor};
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-box:focus-within {
|
|
||||||
outline: ${selectionColor} solid 2px;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
</style>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
|
||||||
}
|
<span style={{minWidth: '60px', marginLeft: '4px'}}>
|
||||||
}
|
{results === undefined
|
||||||
|
? ''
|
||||||
|
: results.resultCount === 0
|
||||||
|
? 'No results'
|
||||||
|
: `${results.resultIndex + 1} of ${results.resultCount}`}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div className="flex-row">
|
||||||
|
<SearchButton
|
||||||
|
onClick={() => prev(searchTermRef.current)}
|
||||||
|
active={false}
|
||||||
|
title="Previous Match"
|
||||||
|
{...searchButtonColors}
|
||||||
|
>
|
||||||
|
<VscArrowUp size="14px" />
|
||||||
|
</SearchButton>
|
||||||
|
|
||||||
|
<SearchButton
|
||||||
|
onClick={() => next(searchTermRef.current)}
|
||||||
|
active={false}
|
||||||
|
title="Next Match"
|
||||||
|
{...searchButtonColors}
|
||||||
|
>
|
||||||
|
<VscArrowDown size="14px" />
|
||||||
|
</SearchButton>
|
||||||
|
|
||||||
|
<SearchButton onClick={close} active={false} title="Close" {...searchButtonColors}>
|
||||||
|
<VscClose size="14px" />
|
||||||
|
</SearchButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style jsx>
|
||||||
|
{`
|
||||||
|
.search-container {
|
||||||
|
background-color: ${backgroundColor};
|
||||||
|
border: 1px solid ${borderColor};
|
||||||
|
border-radius: 2px;
|
||||||
|
position: absolute;
|
||||||
|
right: 13px;
|
||||||
|
top: 4px;
|
||||||
|
z-index: 10;
|
||||||
|
padding: 4px;
|
||||||
|
font-family: ${font};
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
outline: none;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
color: ${foregroundColor};
|
||||||
|
align-self: stretch;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
border: none;
|
||||||
|
border-radius: 2px;
|
||||||
|
outline: ${borderColor} solid 1px;
|
||||||
|
background-color: ${backgroundColor};
|
||||||
|
color: ${foregroundColor};
|
||||||
|
padding: 0px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input::placeholder {
|
||||||
|
color: ${foregroundColor};
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box:focus-within {
|
||||||
|
outline: ${selectionColor} solid 2px;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
</style>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default SearchBox;
|
export default SearchBox;
|
||||||
|
|
|
||||||
|
|
@ -1,164 +1,160 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import type {TabProps} from '../hyper';
|
import type {TabProps} from '../hyper';
|
||||||
|
|
||||||
export default class Tab extends React.PureComponent<TabProps> {
|
const Tab = (props: TabProps) => {
|
||||||
constructor(props: TabProps) {
|
const handleClick = (event: React.MouseEvent) => {
|
||||||
super(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleClick = (event: React.MouseEvent) => {
|
|
||||||
const isLeftClick = event.nativeEvent.which === 1;
|
const isLeftClick = event.nativeEvent.which === 1;
|
||||||
|
|
||||||
if (isLeftClick && !this.props.isActive) {
|
if (isLeftClick && !props.isActive) {
|
||||||
this.props.onSelect();
|
props.onSelect();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleMouseUp = (event: React.MouseEvent) => {
|
const handleMouseUp = (event: React.MouseEvent) => {
|
||||||
const isMiddleClick = event.nativeEvent.which === 2;
|
const isMiddleClick = event.nativeEvent.which === 2;
|
||||||
|
|
||||||
if (isMiddleClick) {
|
if (isMiddleClick) {
|
||||||
this.props.onClose();
|
props.onClose();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
const {isActive, isFirst, isLast, borderColor, hasActivity} = props;
|
||||||
const {isActive, isFirst, isLast, borderColor, hasActivity} = this.props;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<>
|
||||||
<li
|
<li
|
||||||
onClick={this.props.onClick}
|
onClick={props.onClick}
|
||||||
style={{borderColor}}
|
style={{borderColor}}
|
||||||
className={`tab_tab ${isFirst ? 'tab_first' : ''} ${isActive ? 'tab_active' : ''} ${
|
className={`tab_tab ${isFirst ? 'tab_first' : ''} ${isActive ? 'tab_active' : ''} ${
|
||||||
isFirst && isActive ? 'tab_firstActive' : ''
|
isFirst && isActive ? 'tab_firstActive' : ''
|
||||||
} ${hasActivity ? 'tab_hasActivity' : ''}`}
|
} ${hasActivity ? 'tab_hasActivity' : ''}`}
|
||||||
|
>
|
||||||
|
{props.customChildrenBefore}
|
||||||
|
<span
|
||||||
|
className={`tab_text ${isLast ? 'tab_textLast' : ''} ${isActive ? 'tab_textActive' : ''}`}
|
||||||
|
onClick={handleClick}
|
||||||
|
onMouseUp={handleMouseUp}
|
||||||
>
|
>
|
||||||
{this.props.customChildrenBefore}
|
<span title={props.text} className="tab_textInner">
|
||||||
<span
|
{props.text}
|
||||||
className={`tab_text ${isLast ? 'tab_textLast' : ''} ${isActive ? 'tab_textActive' : ''}`}
|
|
||||||
onClick={this.handleClick}
|
|
||||||
onMouseUp={this.handleMouseUp}
|
|
||||||
>
|
|
||||||
<span title={this.props.text} className="tab_textInner">
|
|
||||||
{this.props.text}
|
|
||||||
</span>
|
|
||||||
</span>
|
</span>
|
||||||
<i className="tab_icon" onClick={this.props.onClose}>
|
</span>
|
||||||
<svg className="tab_shape">
|
<i className="tab_icon" onClick={props.onClose}>
|
||||||
<use xlinkHref="./renderer/assets/icons.svg#close-tab" />
|
<svg className="tab_shape">
|
||||||
</svg>
|
<use xlinkHref="./renderer/assets/icons.svg#close-tab" />
|
||||||
</i>
|
</svg>
|
||||||
{this.props.customChildren}
|
</i>
|
||||||
</li>
|
{props.customChildren}
|
||||||
|
</li>
|
||||||
|
|
||||||
<style jsx>{`
|
<style jsx>{`
|
||||||
.tab_tab {
|
.tab_tab {
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
border-color: #ccc;
|
border-color: #ccc;
|
||||||
border-bottom-width: 1px;
|
border-bottom-width: 1px;
|
||||||
border-bottom-style: solid;
|
border-bottom-style: solid;
|
||||||
border-left-width: 1px;
|
border-left-width: 1px;
|
||||||
border-left-style: solid;
|
border-left-style: solid;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab_tab:hover {
|
.tab_tab:hover {
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab_first {
|
.tab_first {
|
||||||
border-left-width: 0;
|
border-left-width: 0;
|
||||||
padding-left: 1px;
|
padding-left: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab_firstActive {
|
.tab_firstActive {
|
||||||
border-left-width: 1px;
|
border-left-width: 1px;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab_active {
|
.tab_active {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border-bottom-width: 0;
|
border-bottom-width: 0;
|
||||||
}
|
}
|
||||||
.tab_active:hover {
|
.tab_active:hover {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab_hasActivity {
|
.tab_hasActivity {
|
||||||
color: #50e3c2;
|
color: #50e3c2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab_hasActivity:hover {
|
.tab_hasActivity:hover {
|
||||||
color: #50e3c2;
|
color: #50e3c2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab_text {
|
.tab_text {
|
||||||
transition: color 0.2s ease;
|
transition: color 0.2s ease;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab_textInner {
|
.tab_textInner {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 24px;
|
left: 24px;
|
||||||
right: 24px;
|
right: 24px;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab_icon {
|
.tab_icon {
|
||||||
transition: opacity 0.2s ease, color 0.2s ease, transform 0.25s ease, background-color 0.1s ease;
|
transition: opacity 0.2s ease, color 0.2s ease, transform 0.25s ease, background-color 0.1s ease;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 7px;
|
right: 7px;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
color: #e9e9e9;
|
color: #e9e9e9;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: scale(0.95);
|
transform: scale(0.95);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab_icon:hover {
|
.tab_icon:hover {
|
||||||
background-color: rgba(255, 255, 255, 0.13);
|
background-color: rgba(255, 255, 255, 0.13);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab_icon:active {
|
.tab_icon:active {
|
||||||
background-color: rgba(255, 255, 255, 0.1);
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
color: #909090;
|
color: #909090;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab_tab:hover .tab_icon {
|
.tab_tab:hover .tab_icon {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: none;
|
transform: none;
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab_shape {
|
.tab_shape {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 4px;
|
left: 4px;
|
||||||
top: 4px;
|
top: 4px;
|
||||||
width: 6px;
|
width: 6px;
|
||||||
height: 6px;
|
height: 6px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
fill: currentColor;
|
fill: currentColor;
|
||||||
shape-rendering: crispEdges;
|
shape-rendering: crispEdges;
|
||||||
}
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
</React.Fragment>
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
export default Tab;
|
||||||
|
|
|
||||||
|
|
@ -9,103 +9,103 @@ import DropdownButton from './new-tab';
|
||||||
const Tab = decorate(Tab_, 'Tab');
|
const Tab = decorate(Tab_, 'Tab');
|
||||||
const isMac = /Mac/.test(navigator.userAgent);
|
const isMac = /Mac/.test(navigator.userAgent);
|
||||||
|
|
||||||
export default class Tabs extends React.PureComponent<TabsProps> {
|
const Tabs = (props: TabsProps) => {
|
||||||
render() {
|
const {tabs = [], borderColor, onChange, onClose, fullScreen} = props;
|
||||||
const {tabs = [], borderColor, onChange, onClose, fullScreen} = this.props;
|
|
||||||
|
|
||||||
const hide = !isMac && tabs.length === 1;
|
const hide = !isMac && tabs.length === 1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className={`tabs_nav ${hide ? 'tabs_hiddenNav' : ''}`}>
|
<nav className={`tabs_nav ${hide ? 'tabs_hiddenNav' : ''}`}>
|
||||||
{this.props.customChildrenBefore}
|
{props.customChildrenBefore}
|
||||||
{tabs.length === 1 && isMac ? <div className="tabs_title">{tabs[0].title}</div> : null}
|
{tabs.length === 1 && isMac ? <div className="tabs_title">{tabs[0].title}</div> : null}
|
||||||
{tabs.length > 1
|
{tabs.length > 1 ? (
|
||||||
? [
|
<>
|
||||||
<ul key="list" className={`tabs_list ${fullScreen && isMac ? 'tabs_fullScreen' : ''}`}>
|
<ul key="list" className={`tabs_list ${fullScreen && isMac ? 'tabs_fullScreen' : ''}`}>
|
||||||
{tabs.map((tab, i) => {
|
{tabs.map((tab, i) => {
|
||||||
const {uid, title, isActive, hasActivity} = tab;
|
const {uid, title, isActive, hasActivity} = tab;
|
||||||
const props = getTabProps(tab, this.props, {
|
const tabProps = getTabProps(tab, props, {
|
||||||
text: title === '' ? 'Shell' : title,
|
text: title === '' ? 'Shell' : title,
|
||||||
isFirst: i === 0,
|
isFirst: i === 0,
|
||||||
isLast: tabs.length - 1 === i,
|
isLast: tabs.length - 1 === i,
|
||||||
borderColor,
|
borderColor,
|
||||||
isActive,
|
isActive,
|
||||||
hasActivity,
|
hasActivity,
|
||||||
onSelect: onChange.bind(null, uid),
|
onSelect: onChange.bind(null, uid),
|
||||||
onClose: onClose.bind(null, uid)
|
onClose: onClose.bind(null, uid)
|
||||||
});
|
});
|
||||||
return <Tab key={`tab-${uid}`} {...props} />;
|
return <Tab key={`tab-${uid}`} {...tabProps} />;
|
||||||
})}
|
})}
|
||||||
</ul>,
|
</ul>
|
||||||
isMac && (
|
{isMac && (
|
||||||
<div
|
<div
|
||||||
key="shim"
|
key="shim"
|
||||||
style={{borderColor}}
|
style={{borderColor}}
|
||||||
className={`tabs_borderShim ${fullScreen ? 'tabs_borderShimUndo' : ''}`}
|
className={`tabs_borderShim ${fullScreen ? 'tabs_borderShimUndo' : ''}`}
|
||||||
/>
|
/>
|
||||||
)
|
)}
|
||||||
]
|
</>
|
||||||
: null}
|
) : null}
|
||||||
<DropdownButton {...this.props} tabsVisible={tabs.length > 1} />
|
<DropdownButton {...props} tabsVisible={tabs.length > 1} />
|
||||||
{this.props.customChildren}
|
{props.customChildren}
|
||||||
|
|
||||||
<style jsx>{`
|
<style jsx>{`
|
||||||
.tabs_nav {
|
.tabs_nav {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
line-height: 34px;
|
line-height: 34px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
color: #9b9b9b;
|
color: #9b9b9b;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
position: relative;
|
position: relative;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
-webkit-app-region: ${isMac ? 'drag' : ''};
|
-webkit-app-region: ${isMac ? 'drag' : ''};
|
||||||
top: ${isMac ? '0px' : '34px'};
|
top: ${isMac ? '0px' : '34px'};
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: row;
|
flex-flow: row;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs_hiddenNav {
|
.tabs_hiddenNav {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs_title {
|
.tabs_title {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
padding-left: 76px;
|
padding-left: 76px;
|
||||||
padding-right: 76px;
|
padding-right: 76px;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs_list {
|
.tabs_list {
|
||||||
max-height: 34px;
|
max-height: 34px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: row;
|
flex-flow: row;
|
||||||
margin-left: ${isMac ? '76px' : '0'};
|
margin-left: ${isMac ? '76px' : '0'};
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs_fullScreen {
|
.tabs_fullScreen {
|
||||||
margin-left: -1px;
|
margin-left: -1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs_borderShim {
|
.tabs_borderShim {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 76px;
|
width: 76px;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
border-color: #ccc;
|
border-color: #ccc;
|
||||||
border-bottom-style: solid;
|
border-bottom-style: solid;
|
||||||
border-bottom-width: 1px;
|
border-bottom-width: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs_borderShimUndo {
|
.tabs_borderShimUndo {
|
||||||
border-bottom-width: 0px;
|
border-bottom-width: 0px;
|
||||||
}
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
</nav>
|
</nav>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
export default Tabs;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue