Skip to content
This repository was archived by the owner on Apr 1, 2020. It is now read-only.

Enable use of middle click to close tabs #2190

Merged
merged 15 commits into from
May 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions @types/classnames/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Custom type definitions for classnames master branch
// Project: https://github.com/JedWatson/classnames

declare module "classnames" {
type ClassValue = string | number | ClassDictionary | ClassArray | undefined | null | false

interface ClassDictionary {
[id: string]: boolean | undefined | null
}

// This is the only way I found to break circular references between ClassArray and ClassValue
// https://github.com/Microsoft/TypeScript/issues/3496#issuecomment-128553540
interface ClassArray extends Array<ClassValue> {} // tslint:disable-line no-empty-interface

type ClassNamesFn = (...classes: ClassValue[]) => string

const classNames: ClassNamesFn

export default classNames
}
70 changes: 36 additions & 34 deletions browser/src/UI/components/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as path from "path"
import * as React from "react"
import { connect } from "react-redux"

import * as classNames from "classnames"
import classNames from "classnames"
import { keyframes } from "styled-components"

import * as BufferSelectors from "./../../Editor/NeovimEditor/NeovimEditorSelectors"
Expand Down Expand Up @@ -40,8 +40,8 @@ export interface ITabContainerProps {
}

export interface ITabsProps {
onSelect?: (id: number) => void
onClose?: (id: number) => void
onTabSelect?: (id: number) => void
onTabClose?: (id: number) => void

visible: boolean
tabs: ITabProps[]
Expand All @@ -65,16 +65,6 @@ const InnerName = styled.span`
`

export class Tabs extends React.PureComponent<ITabsProps, {}> {
private _boundOnSelect: (tabId: number) => void
private _boundOnClose: (tabId: number) => void

constructor(props: ITabsProps) {
super(props)

this._boundOnSelect = (id: number) => this._onSelect(id)
this._boundOnClose = (id: number) => this._onClickClose(id)
}

public render(): JSX.Element {
if (!this.props.visible) {
return null
Expand All @@ -98,8 +88,8 @@ export class Tabs extends React.PureComponent<ITabsProps, {}> {
<Tab
key={t.id}
{...t}
onClickName={this._boundOnSelect}
onClickClose={this._boundOnClose}
onSelect={this.props.onTabSelect}
onClose={this.props.onTabClose}
backgroundColor={this.props.backgroundColor}
foregroundColor={this.props.foregroundColor}
height={this.props.height}
Expand All @@ -114,19 +104,11 @@ export class Tabs extends React.PureComponent<ITabsProps, {}> {
</div>
)
}

private _onSelect(id: number): void {
this.props.onSelect(id)
}

private _onClickClose(id: number): void {
this.props.onClose(id)
}
}

export interface ITabPropsWithClick extends ITabProps {
onClickName: (id: number) => void
onClickClose: (id: number) => void
onSelect: (id: number) => void
onClose: (id: number) => void

backgroundColor: string
foregroundColor: string
Expand Down Expand Up @@ -175,28 +157,28 @@ export class Tab extends React.PureComponent<ITabPropsWithClick> {
borderTop: "2px solid " + this.props.highlightColor,
}

const handleTitleClick = this._handleTitleClick.bind(this)
const handleCloseButtonClick = this._handleCloseButtonClick.bind(this)

return (
<Sneakable callback={() => this.props.onClickName(this.props.id)} tag={this.props.name}>
<Sneakable callback={() => this.props.onSelect(this.props.id)} tag={this.props.name}>
<TabWrapper
innerRef={(e: IChromeDivElement) => (this._tab = e)}
className={cssClasses}
title={this.props.description}
style={style}
>
<div className="corner" onClick={() => this.props.onClickName(this.props.id)}>
<div className="corner" onMouseDown={handleTitleClick}>
<FileIcon
fileName={this.props.iconFileName}
isLarge={true}
playAppearAnimation={true}
/>
</div>
<div className="name" onClick={() => this.props.onClickName(this.props.id)}>
<div className="name" onMouseDown={handleTitleClick}>
<InnerName>{this.props.name}</InnerName>
</div>
<div
className="corner enable-hover"
onClick={() => this.props.onClickClose(this.props.id)}
>
<div className="corner enable-hover" onClick={handleCloseButtonClick}>
<div className="icon-container x-icon-container">
<Icon name="times" />
</div>
Expand All @@ -220,6 +202,26 @@ export class Tab extends React.PureComponent<ITabPropsWithClick> {
}
}
}

private _handleTitleClick(event: React.MouseEvent<HTMLElement>): void {
if (this._isLeftClick(event)) {
this.props.onSelect(this.props.id)
} else if (this._isMiddleClick(event)) {
this.props.onClose(this.props.id)
}
}

private _handleCloseButtonClick(): void {
this.props.onClose(this.props.id)
}

private _isMiddleClick(event: React.MouseEvent<HTMLElement>): boolean {
return event.button === 1
}

private _isLeftClick(event: React.MouseEvent<HTMLElement>): boolean {
return event.button === 0
}
}

export const getTabName = (name: string, isDuplicate?: boolean): string => {
Expand Down Expand Up @@ -365,8 +367,8 @@ const mapStateToProps = (state: State.IState, ownProps: ITabContainerProps): ITa
fontSize: addDefaultUnitIfNeeded(state.configuration["ui.fontSize"]),
backgroundColor: state.colors["tabs.background"],
foregroundColor: state.colors["tabs.foreground"],
onSelect: selectFunc,
onClose: closeFunc,
onTabSelect: selectFunc,
onTabClose: closeFunc,
height,
maxWidth,
shouldWrap,
Expand Down
2 changes: 1 addition & 1 deletion browser/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@
"sourceMap": true,
"types": ["mocha", "webgl2"]
},
"include": ["src/**/*.ts", "test/**/*.ts"],
"include": ["../@types/**/*.d.ts", "src/**/*.ts", "test/**/*.ts"],
"exclude": ["node_modules"]
}
2 changes: 1 addition & 1 deletion browser/tsconfig.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@
"sourceMap": true,
"types": ["mocha", "webgl2"]
},
"include": ["src/**/*.ts", "src/**/*.tsx", "test/**/*.ts"],
"include": ["../@types/**/*.d.ts", "src/**/*.ts", "src/**/*.tsx", "test/**/*.ts"],
"exclude": ["node_modules"]
}
1 change: 0 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ module.exports = {
PersistentSettings: "<rootDir>/ui-tests/mocks/PersistentSettings.ts",
Utility: "<rootDir>/ui-tests/mocks/Utility.ts",
Configuration: "<rootDir>/ui-tests/mocks/Configuration.ts",
classnames: "<rootDir>/ui-tests/mocks/classnames.ts",
KeyboardLayout: "<rootDir>/ui-tests/mocks/keyboardLayout.ts",
},
snapshotSerializers: ["enzyme-to-json/serializer"],
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,6 @@
},
"devDependencies": {
"@types/chokidar": "^1.7.5",
"@types/classnames": "0.0.32",
"@types/color": "2.0.0",
"@types/detect-indent": "^5.0.0",
"@types/dompurify": "^0.0.31",
Expand Down Expand Up @@ -759,7 +758,7 @@
"babel-minify-webpack-plugin": "^0.3.1",
"babel-plugin-dynamic-import-node": "^1.2.0",
"bs-platform": "2.1.0",
"classnames": "2.2.5",
"classnames": "JedWatson/classnames",
"codecov": "^3.0.0",
"color": "2.0.0",
"concurrently": "3.1.0",
Expand Down
Loading