mirror of
https://github.com/quine-global/hyper.git
synced 2026-01-12 20:18:41 -09:00
port remaining js components to ts
This commit is contained in:
parent
4a3132b8e7
commit
78ec88d1e8
8 changed files with 170 additions and 83 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import {SearchBoxProps} from '../hyper';
|
||||||
|
|
||||||
const searchBoxStyling = {
|
const searchBoxStyling: React.CSSProperties = {
|
||||||
float: 'right',
|
float: 'right',
|
||||||
height: '28px',
|
height: '28px',
|
||||||
backgroundColor: 'white',
|
backgroundColor: 'white',
|
||||||
|
|
@ -8,21 +9,22 @@ const searchBoxStyling = {
|
||||||
right: '10px',
|
right: '10px',
|
||||||
top: '25px',
|
top: '25px',
|
||||||
width: '224px',
|
width: '224px',
|
||||||
zIndex: '9999'
|
zIndex: 9999
|
||||||
};
|
};
|
||||||
|
|
||||||
const enterKey = 13;
|
const enterKey = 13;
|
||||||
|
|
||||||
export default class SearchBox extends React.PureComponent {
|
export default class SearchBox extends React.PureComponent<SearchBoxProps> {
|
||||||
constructor(props) {
|
searchTerm: string;
|
||||||
|
constructor(props: SearchBoxProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.searchTerm = '';
|
this.searchTerm = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChange = event => {
|
handleChange = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
this.searchTerm = event.target.value;
|
this.searchTerm = event.currentTarget.value;
|
||||||
if (event.keyCode === enterKey) {
|
if (event.keyCode === enterKey) {
|
||||||
this.props.search(event.target.value);
|
this.props.search(event.currentTarget.value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1,15 +1,18 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Terminal} from 'xterm';
|
import {Terminal, ITerminalOptions, IDisposable} from 'xterm';
|
||||||
import {FitAddon} from 'xterm-addon-fit';
|
import {FitAddon} from 'xterm-addon-fit';
|
||||||
import {WebLinksAddon} from 'xterm-addon-web-links';
|
import {WebLinksAddon} from 'xterm-addon-web-links';
|
||||||
import {SearchAddon} from 'xterm-addon-search';
|
import {SearchAddon} from 'xterm-addon-search';
|
||||||
import {WebglAddon} from 'xterm-addon-webgl';
|
import {WebglAddon} from 'xterm-addon-webgl';
|
||||||
import {LigaturesAddon} from 'xterm-addon-ligatures';
|
import {LigaturesAddon} from 'xterm-addon-ligatures';
|
||||||
import {clipboard} from 'electron';
|
import {clipboard} from 'electron';
|
||||||
import * as Color from 'color';
|
import Color from 'color';
|
||||||
import terms from '../terms';
|
import terms from '../terms';
|
||||||
import processClipboard from '../utils/paste';
|
import processClipboard from '../utils/paste';
|
||||||
import SearchBox from './searchBox';
|
import SearchBox from './searchBox';
|
||||||
|
import ResizeObserver from 'resize-observer-polyfill';
|
||||||
|
import {TermProps} from '../hyper';
|
||||||
|
import {ObjectTypedKeys} from '../utils/object';
|
||||||
|
|
||||||
const isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].includes(navigator.platform);
|
const isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].includes(navigator.platform);
|
||||||
|
|
||||||
|
|
@ -18,7 +21,7 @@ const CURSOR_STYLES = {
|
||||||
BEAM: 'bar',
|
BEAM: 'bar',
|
||||||
UNDERLINE: 'underline',
|
UNDERLINE: 'underline',
|
||||||
BLOCK: 'block'
|
BLOCK: 'block'
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
const isWebgl2Supported = (() => {
|
const isWebgl2Supported = (() => {
|
||||||
let isSupported = window.WebGL2RenderingContext ? undefined : false;
|
let isSupported = window.WebGL2RenderingContext ? undefined : false;
|
||||||
|
|
@ -32,7 +35,7 @@ const isWebgl2Supported = (() => {
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const getTermOptions = props => {
|
const getTermOptions = (props: TermProps): ITerminalOptions => {
|
||||||
// Set a background color only if it is opaque
|
// Set a background color only if it is opaque
|
||||||
const needTransparency = Color(props.backgroundColor).alpha() < 1;
|
const needTransparency = Color(props.backgroundColor).alpha() < 1;
|
||||||
const backgroundColor = needTransparency ? 'transparent' : props.backgroundColor;
|
const backgroundColor = needTransparency ? 'transparent' : props.backgroundColor;
|
||||||
|
|
@ -78,13 +81,23 @@ const getTermOptions = props => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class Term extends React.PureComponent {
|
export default class Term extends React.PureComponent<TermProps> {
|
||||||
constructor(props) {
|
termRef: HTMLElement | null;
|
||||||
|
termWrapperRef: HTMLElement | null;
|
||||||
|
termOptions: ITerminalOptions;
|
||||||
|
disposableListeners: IDisposable[];
|
||||||
|
termDefaultBellSound: string | null;
|
||||||
|
fitAddon: FitAddon;
|
||||||
|
searchAddon: SearchAddon;
|
||||||
|
static rendererTypes: Record<string, string>;
|
||||||
|
term!: Terminal;
|
||||||
|
resizeObserver!: ResizeObserver;
|
||||||
|
resizeTimeout!: NodeJS.Timeout;
|
||||||
|
constructor(props: TermProps) {
|
||||||
super(props);
|
super(props);
|
||||||
props.ref_(props.uid, this);
|
props.ref_(props.uid, this);
|
||||||
this.termRef = null;
|
this.termRef = null;
|
||||||
this.termWrapperRef = null;
|
this.termWrapperRef = null;
|
||||||
this.termRect = null;
|
|
||||||
this.termOptions = {};
|
this.termOptions = {};
|
||||||
this.disposableListeners = [];
|
this.disposableListeners = [];
|
||||||
this.termDefaultBellSound = null;
|
this.termDefaultBellSound = null;
|
||||||
|
|
@ -93,7 +106,7 @@ export default class Term extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The main process shows this in the About dialog
|
// The main process shows this in the About dialog
|
||||||
static reportRenderer(uid, type) {
|
static reportRenderer(uid: string, type: string) {
|
||||||
const rendererTypes = Term.rendererTypes || {};
|
const rendererTypes = Term.rendererTypes || {};
|
||||||
if (rendererTypes[uid] !== type) {
|
if (rendererTypes[uid] !== type) {
|
||||||
rendererTypes[uid] = type;
|
rendererTypes[uid] = type;
|
||||||
|
|
@ -111,14 +124,14 @@ export default class Term extends React.PureComponent {
|
||||||
|
|
||||||
// The parent element for the terminal is attached and removed manually so
|
// The parent element for the terminal is attached and removed manually so
|
||||||
// that we can preserve it across mounts and unmounts of the component
|
// that we can preserve it across mounts and unmounts of the component
|
||||||
this.termRef = props.term ? props.term.element.parentElement : document.createElement('div');
|
this.termRef = props.term ? props.term.element!.parentElement! : document.createElement('div');
|
||||||
this.termRef.className = 'term_fit term_term';
|
this.termRef.className = 'term_fit term_term';
|
||||||
|
|
||||||
this.termWrapperRef.appendChild(this.termRef);
|
this.termWrapperRef?.appendChild(this.termRef);
|
||||||
|
|
||||||
if (!props.term) {
|
if (!props.term) {
|
||||||
let needTransparency = Color(props.backgroundColor).alpha() < 1;
|
const needTransparency = Color(props.backgroundColor).alpha() < 1;
|
||||||
let useWebGL = false;
|
const useWebGL = false;
|
||||||
if (props.webGLRenderer) {
|
if (props.webGLRenderer) {
|
||||||
if (needTransparency) {
|
if (needTransparency) {
|
||||||
console.warn(
|
console.warn(
|
||||||
|
|
@ -148,8 +161,8 @@ export default class Term extends React.PureComponent {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// get the cached plugins
|
// get the cached plugins
|
||||||
this.fitAddon = props.fitAddon;
|
this.fitAddon = props.fitAddon!;
|
||||||
this.searchAddon = props.searchAddon;
|
this.searchAddon = props.searchAddon!;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fitAddon.fit();
|
this.fitAddon.fit();
|
||||||
|
|
@ -163,9 +176,9 @@ export default class Term extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.onActive) {
|
if (props.onActive) {
|
||||||
this.term.textarea.addEventListener('focus', props.onActive);
|
this.term.textarea?.addEventListener('focus', props.onActive);
|
||||||
this.disposableListeners.push({
|
this.disposableListeners.push({
|
||||||
dispose: () => this.term.textarea.removeEventListener('focus', this.props.onActive)
|
dispose: () => this.term.textarea?.removeEventListener('focus', this.props.onActive)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,14 +201,14 @@ export default class Term extends React.PureComponent {
|
||||||
this.disposableListeners.push(
|
this.disposableListeners.push(
|
||||||
this.term.onCursorMove(() => {
|
this.term.onCursorMove(() => {
|
||||||
const cursorFrame = {
|
const cursorFrame = {
|
||||||
x: this.term.buffer.cursorX * this.term._core._renderService.dimensions.actualCellWidth,
|
x: this.term.buffer.cursorX * (this.term as any)._core._renderService.dimensions.actualCellWidth,
|
||||||
y: this.term.buffer.cursorY * this.term._core._renderService.dimensions.actualCellHeight,
|
y: this.term.buffer.cursorY * (this.term as any)._core._renderService.dimensions.actualCellHeight,
|
||||||
width: this.term._core._renderService.dimensions.actualCellWidth,
|
width: (this.term as any)._core._renderService.dimensions.actualCellWidth,
|
||||||
height: this.term._core._renderService.dimensions.actualCellHeight,
|
height: (this.term as any)._core._renderService.dimensions.actualCellHeight,
|
||||||
col: this.term.buffer.cursorX,
|
col: this.term.buffer.cursorX,
|
||||||
row: this.term.buffer.cursorY
|
row: this.term.buffer.cursorY
|
||||||
};
|
};
|
||||||
props.onCursorMove(cursorFrame);
|
props.onCursorMove?.(cursorFrame);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -220,18 +233,18 @@ export default class Term extends React.PureComponent {
|
||||||
|
|
||||||
// intercepting paste event for any necessary processing of
|
// intercepting paste event for any necessary processing of
|
||||||
// clipboard data, if result is falsy, paste event continues
|
// clipboard data, if result is falsy, paste event continues
|
||||||
onWindowPaste = e => {
|
onWindowPaste = (e: any) => {
|
||||||
if (!this.props.isTermActive) return;
|
if (!this.props.isTermActive) return;
|
||||||
|
|
||||||
const processed = processClipboard();
|
const processed = processClipboard();
|
||||||
if (processed) {
|
if (processed) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
this.term._core.handler(processed);
|
(this.term as any)._core.handler(processed);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMouseUp = e => {
|
onMouseUp = (e: React.MouseEvent) => {
|
||||||
if (this.props.quickEdit && e.button === 2) {
|
if (this.props.quickEdit && e.button === 2) {
|
||||||
if (this.term.hasSelection()) {
|
if (this.term.hasSelection()) {
|
||||||
clipboard.writeText(this.term.getSelection());
|
clipboard.writeText(this.term.getSelection());
|
||||||
|
|
@ -244,7 +257,7 @@ export default class Term extends React.PureComponent {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
write(data) {
|
write(data: string | Uint8Array) {
|
||||||
this.term.write(data);
|
this.term.write(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,15 +273,15 @@ export default class Term extends React.PureComponent {
|
||||||
this.term.reset();
|
this.term.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
search = searchTerm => {
|
search = (searchTerm = '') => {
|
||||||
this.searchAddon.findNext(searchTerm);
|
this.searchAddon.findNext(searchTerm);
|
||||||
};
|
};
|
||||||
|
|
||||||
searchNext = searchTerm => {
|
searchNext = (searchTerm: string) => {
|
||||||
this.searchAddon.findNext(searchTerm);
|
this.searchAddon.findNext(searchTerm);
|
||||||
};
|
};
|
||||||
|
|
||||||
searchPrevious = searchTerm => {
|
searchPrevious = (searchTerm: string) => {
|
||||||
this.searchAddon.findPrevious(searchTerm);
|
this.searchAddon.findPrevious(searchTerm);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -276,7 +289,7 @@ export default class Term extends React.PureComponent {
|
||||||
this.props.toggleSearch();
|
this.props.toggleSearch();
|
||||||
};
|
};
|
||||||
|
|
||||||
resize(cols, rows) {
|
resize(cols: number, rows: number) {
|
||||||
this.term.resize(cols, rows);
|
this.term.resize(cols, rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -291,12 +304,12 @@ export default class Term extends React.PureComponent {
|
||||||
this.fitAddon.fit();
|
this.fitAddon.fit();
|
||||||
}
|
}
|
||||||
|
|
||||||
keyboardHandler(e) {
|
keyboardHandler(e: any) {
|
||||||
// Has Mousetrap flagged this event as a command?
|
// Has Mousetrap flagged this event as a command?
|
||||||
return !e.catched;
|
return !e.catched;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps: TermProps) {
|
||||||
if (!prevProps.cleared && this.props.cleared) {
|
if (!prevProps.cleared && this.props.cleared) {
|
||||||
this.clear();
|
this.clear();
|
||||||
}
|
}
|
||||||
|
|
@ -305,14 +318,14 @@ export default class Term extends React.PureComponent {
|
||||||
|
|
||||||
// Use bellSound in nextProps if it exists
|
// Use bellSound in nextProps if it exists
|
||||||
// otherwise use the default sound found in xterm.
|
// otherwise use the default sound found in xterm.
|
||||||
nextTermOptions.bellSound = this.props.bellSound || this.termDefaultBellSound;
|
nextTermOptions.bellSound = this.props.bellSound || this.termDefaultBellSound!;
|
||||||
|
|
||||||
if (!prevProps.search && this.props.search) {
|
if (!prevProps.search && this.props.search) {
|
||||||
this.search();
|
this.search();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update only options that have changed.
|
// Update only options that have changed.
|
||||||
Object.keys(nextTermOptions)
|
ObjectTypedKeys(nextTermOptions)
|
||||||
.filter(option => option !== 'theme' && nextTermOptions[option] !== this.termOptions[option])
|
.filter(option => option !== 'theme' && nextTermOptions[option] !== this.termOptions[option])
|
||||||
.forEach(option => {
|
.forEach(option => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -330,8 +343,8 @@ export default class Term extends React.PureComponent {
|
||||||
const shouldUpdateTheme =
|
const shouldUpdateTheme =
|
||||||
!this.termOptions.theme ||
|
!this.termOptions.theme ||
|
||||||
nextTermOptions.rendererType !== this.termOptions.rendererType ||
|
nextTermOptions.rendererType !== this.termOptions.rendererType ||
|
||||||
Object.keys(nextTermOptions.theme).some(
|
ObjectTypedKeys(nextTermOptions.theme!).some(
|
||||||
option => nextTermOptions.theme[option] !== this.termOptions.theme[option]
|
option => nextTermOptions.theme![option] !== this.termOptions.theme![option]
|
||||||
);
|
);
|
||||||
if (shouldUpdateTheme) {
|
if (shouldUpdateTheme) {
|
||||||
this.term.setOption('theme', nextTermOptions.theme);
|
this.term.setOption('theme', nextTermOptions.theme);
|
||||||
|
|
@ -350,11 +363,11 @@ export default class Term extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevProps.rows !== this.props.rows || prevProps.cols !== this.props.cols) {
|
if (prevProps.rows !== this.props.rows || prevProps.cols !== this.props.cols) {
|
||||||
this.resize(this.props.cols, this.props.rows);
|
this.resize(this.props.cols!, this.props.rows!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onTermWrapperRef = component => {
|
onTermWrapperRef = (component: HTMLElement | null) => {
|
||||||
this.termWrapperRef = component;
|
this.termWrapperRef = component;
|
||||||
|
|
||||||
if (component) {
|
if (component) {
|
||||||
|
|
@ -372,7 +385,7 @@ export default class Term extends React.PureComponent {
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
terms[this.props.uid] = null;
|
terms[this.props.uid] = null;
|
||||||
this.termWrapperRef.removeChild(this.termRef);
|
this.termWrapperRef?.removeChild(this.termRef!);
|
||||||
this.props.ref_(this.props.uid, null);
|
this.props.ref_(this.props.uid, null);
|
||||||
|
|
||||||
// to clean up the terminal, we remove the listeners
|
// to clean up the terminal, we remove the listeners
|
||||||
|
|
@ -3,62 +3,53 @@ import {decorate, getTermGroupProps} from '../utils/plugins';
|
||||||
import {registerCommandHandlers} from '../command-registry';
|
import {registerCommandHandlers} from '../command-registry';
|
||||||
import TermGroup_ from './term-group';
|
import TermGroup_ from './term-group';
|
||||||
import StyleSheet_ from './style-sheet';
|
import StyleSheet_ from './style-sheet';
|
||||||
|
import {TermsProps} from '../hyper';
|
||||||
|
import Term from './term';
|
||||||
|
import {ObjectTypedKeys} from '../utils/object';
|
||||||
|
|
||||||
const TermGroup = decorate(TermGroup_, 'TermGroup');
|
const TermGroup = decorate(TermGroup_, 'TermGroup');
|
||||||
const StyleSheet = decorate(StyleSheet_, 'StyleSheet');
|
const StyleSheet = decorate(StyleSheet_, 'StyleSheet');
|
||||||
|
|
||||||
const isMac = /Mac/.test(navigator.userAgent);
|
const isMac = /Mac/.test(navigator.userAgent);
|
||||||
|
|
||||||
export default class Terms extends React.Component {
|
export default class Terms extends React.Component<TermsProps> {
|
||||||
constructor(props, context) {
|
terms: Record<string, Term>;
|
||||||
|
registerCommands: (cmds: Record<string, (...args: any[]) => void>) => void;
|
||||||
|
constructor(props: TermsProps, context: any) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
this.terms = {};
|
this.terms = {};
|
||||||
this.bound = new WeakMap();
|
|
||||||
this.registerCommands = registerCommandHandlers;
|
this.registerCommands = registerCommandHandlers;
|
||||||
props.ref_(this);
|
props.ref_(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps: TermsProps & {children: any}) {
|
||||||
for (const i in nextProps) {
|
return (
|
||||||
if (i === 'write') {
|
ObjectTypedKeys(nextProps).some(i => i !== 'write' && this.props[i] !== nextProps[i]) ||
|
||||||
continue;
|
ObjectTypedKeys(this.props).some(i => i !== 'write' && this.props[i] !== nextProps[i])
|
||||||
}
|
);
|
||||||
if (this.props[i] !== nextProps[i]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const i in this.props) {
|
|
||||||
if (i === 'write') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (this.props[i] !== nextProps[i]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRef = (uid, term) => {
|
onRef = (uid: string, term: Term) => {
|
||||||
if (term) {
|
if (term) {
|
||||||
this.terms[uid] = term;
|
this.terms[uid] = term;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
getTermByUid(uid) {
|
getTermByUid(uid: string) {
|
||||||
return this.terms[uid];
|
return this.terms[uid];
|
||||||
}
|
}
|
||||||
|
|
||||||
getActiveTerm() {
|
getActiveTerm() {
|
||||||
return this.getTermByUid(this.props.activeSession);
|
return this.getTermByUid(this.props.activeSession!);
|
||||||
}
|
}
|
||||||
|
|
||||||
onTerminal(uid, term) {
|
onTerminal(uid: string, term: Term) {
|
||||||
this.terms[uid] = term;
|
this.terms[uid] = term;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
window.addEventListener('contextmenu', () => {
|
window.addEventListener('contextmenu', () => {
|
||||||
const selection = window.getSelection().toString();
|
const selection = window.getSelection()!.toString();
|
||||||
const {
|
const {
|
||||||
props: {uid}
|
props: {uid}
|
||||||
} = this.getActiveTerm();
|
} = this.getActiveTerm();
|
||||||
|
|
@ -66,8 +57,8 @@ export default class Terms extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps: TermsProps) {
|
||||||
for (let uid in prevProps.sessions) {
|
for (const uid in prevProps.sessions) {
|
||||||
if (!this.props.sessions[uid]) {
|
if (!this.props.sessions[uid]) {
|
||||||
this.terms[uid].term.dispose();
|
this.terms[uid].term.dispose();
|
||||||
delete this.terms[uid];
|
delete this.terms[uid];
|
||||||
67
lib/hyper.d.ts
vendored
67
lib/hyper.d.ts
vendored
|
|
@ -26,7 +26,7 @@ export type ITermState = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type cursorShapes = 'BEAM' | 'UNDERLINE' | 'BLOCK';
|
export type cursorShapes = 'BEAM' | 'UNDERLINE' | 'BLOCK';
|
||||||
import {FontWeight} from 'xterm';
|
import {FontWeight, Terminal} from 'xterm';
|
||||||
|
|
||||||
export type uiState = {
|
export type uiState = {
|
||||||
_lastUpdate: number | null;
|
_lastUpdate: number | null;
|
||||||
|
|
@ -221,7 +221,7 @@ export type TabProps = {
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
isFirst: boolean;
|
isFirst: boolean;
|
||||||
isLast: boolean;
|
isLast: boolean;
|
||||||
onClick: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
|
onClick?: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onSelect: () => void;
|
onSelect: () => void;
|
||||||
text: string;
|
text: string;
|
||||||
|
|
@ -237,8 +237,8 @@ export type ITab = {
|
||||||
export type TabsProps = {
|
export type TabsProps = {
|
||||||
tabs: ITab[];
|
tabs: ITab[];
|
||||||
borderColor: string;
|
borderColor: string;
|
||||||
onChange: () => void;
|
onChange: (uid: string) => void;
|
||||||
onClose: () => void;
|
onClose: (uid: string) => void;
|
||||||
fullScreen: boolean;
|
fullScreen: boolean;
|
||||||
} & extensionProps;
|
} & extensionProps;
|
||||||
|
|
||||||
|
|
@ -312,3 +312,62 @@ export type TermGroupOwnProps = {
|
||||||
|
|
||||||
import {TermGroupConnectedProps} from './components/term-group';
|
import {TermGroupConnectedProps} from './components/term-group';
|
||||||
export type TermGroupProps = TermGroupConnectedProps & TermGroupOwnProps;
|
export type TermGroupProps = TermGroupConnectedProps & TermGroupOwnProps;
|
||||||
|
|
||||||
|
export type SearchBoxProps = {
|
||||||
|
search: (searchTerm: string) => void;
|
||||||
|
next: (searchTerm: string) => void;
|
||||||
|
prev: (searchTerm: string) => void;
|
||||||
|
close: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
import {FitAddon} from 'xterm-addon-fit';
|
||||||
|
import {SearchAddon} from 'xterm-addon-search';
|
||||||
|
export type TermProps = {
|
||||||
|
backgroundColor: string;
|
||||||
|
bell: string;
|
||||||
|
bellSound: string | null;
|
||||||
|
bellSoundURL: string | null;
|
||||||
|
borderColor: string;
|
||||||
|
cleared: boolean;
|
||||||
|
colors: uiState['colors'];
|
||||||
|
cols: number | null;
|
||||||
|
copyOnSelect: boolean;
|
||||||
|
cursorAccentColor?: string;
|
||||||
|
cursorBlink: boolean;
|
||||||
|
cursorColor: string;
|
||||||
|
cursorShape: cursorShapes;
|
||||||
|
disableLigatures: boolean;
|
||||||
|
fitAddon: FitAddon | null;
|
||||||
|
fontFamily: string;
|
||||||
|
fontSize: number;
|
||||||
|
fontSmoothing?: string;
|
||||||
|
fontWeight: FontWeight;
|
||||||
|
fontWeightBold: FontWeight;
|
||||||
|
foregroundColor: string;
|
||||||
|
isTermActive: boolean;
|
||||||
|
letterSpacing: number;
|
||||||
|
lineHeight: number;
|
||||||
|
macOptionSelectionMode: string;
|
||||||
|
modifierKeys: Immutable<{altIsMeta: boolean; cmdIsMeta: boolean}>;
|
||||||
|
onActive: () => void;
|
||||||
|
onContextMenu: (selection: any) => void;
|
||||||
|
onCursorMove?: (cursorFrame: {x: number; y: number; width: number; height: number; col: number; row: number}) => void;
|
||||||
|
onData: (data: any) => void;
|
||||||
|
onResize: (cols: number, rows: number) => void;
|
||||||
|
onTitle: (title: string) => void;
|
||||||
|
padding: string;
|
||||||
|
quickEdit: boolean;
|
||||||
|
rows: number | null;
|
||||||
|
scrollback: number;
|
||||||
|
search: boolean;
|
||||||
|
searchAddon: SearchAddon | null;
|
||||||
|
selectionColor: string;
|
||||||
|
term: Terminal | null;
|
||||||
|
toggleSearch: () => void;
|
||||||
|
uid: string;
|
||||||
|
uiFontFamily: string;
|
||||||
|
url: string | null;
|
||||||
|
webGLRenderer: boolean;
|
||||||
|
} & extensionProps & {ref_?: any};
|
||||||
|
|
||||||
|
export type Assignable<T, U> = {[k in keyof U]: k extends keyof T ? T[k] : U[k]} & Partial<T>;
|
||||||
|
|
|
||||||
|
|
@ -7,5 +7,5 @@ import Term from './components/term';
|
||||||
// optimization for the most common action
|
// optimization for the most common action
|
||||||
// within the system
|
// within the system
|
||||||
|
|
||||||
const terms: Record<string, Term> = {};
|
const terms: Record<string, Term | null> = {};
|
||||||
export default terms;
|
export default terms;
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,19 @@ import React, {PureComponent} from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import Notification from '../components/notification';
|
import Notification from '../components/notification';
|
||||||
import notify from './notify';
|
import notify from './notify';
|
||||||
import {hyperPlugin, IUiReducer, ISessionReducer, ITermGroupReducer, HyperState, HyperDispatch} from '../hyper';
|
import {
|
||||||
|
hyperPlugin,
|
||||||
|
IUiReducer,
|
||||||
|
ISessionReducer,
|
||||||
|
ITermGroupReducer,
|
||||||
|
HyperState,
|
||||||
|
HyperDispatch,
|
||||||
|
TabProps,
|
||||||
|
TabsProps,
|
||||||
|
TermGroupOwnProps,
|
||||||
|
TermProps,
|
||||||
|
Assignable
|
||||||
|
} from '../hyper';
|
||||||
import {Middleware} from 'redux';
|
import {Middleware} from 'redux';
|
||||||
import {ObjectTypedKeys} from './object';
|
import {ObjectTypedKeys} from './object';
|
||||||
|
|
||||||
|
|
@ -402,19 +414,23 @@ function getProps(name: keyof typeof propsDecorators, props: any, ...fnArgs: any
|
||||||
return props_ || props;
|
return props_ || props;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTermGroupProps(uid: string, parentProps: any, props: any) {
|
export function getTermGroupProps<T extends Assignable<TermGroupOwnProps, T>>(
|
||||||
|
uid: string,
|
||||||
|
parentProps: any,
|
||||||
|
props: T
|
||||||
|
): T {
|
||||||
return getProps('getTermGroupProps', props, uid, parentProps);
|
return getProps('getTermGroupProps', props, uid, parentProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTermProps(uid: string, parentProps: any, props: any) {
|
export function getTermProps<T extends Assignable<TermProps, T>>(uid: string, parentProps: any, props: T): T {
|
||||||
return getProps('getTermProps', props, uid, parentProps);
|
return getProps('getTermProps', props, uid, parentProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTabsProps(parentProps: any, props: any) {
|
export function getTabsProps<T extends Assignable<TabsProps, T>>(parentProps: any, props: T): T {
|
||||||
return getProps('getTabsProps', props, parentProps);
|
return getProps('getTabsProps', props, parentProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTabProps(tab: any, parentProps: any, props: any) {
|
export function getTabProps<T extends Assignable<TabProps, T>>(tab: any, parentProps: any, props: T): T {
|
||||||
return getProps('getTabProps', props, tab, parentProps);
|
return getProps('getTabProps', props, tab, parentProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,7 @@
|
||||||
"prettier": "1.19.1",
|
"prettier": "1.19.1",
|
||||||
"proxyquire": "2.1.3",
|
"proxyquire": "2.1.3",
|
||||||
"redux-devtools-extension": "2.13.8",
|
"redux-devtools-extension": "2.13.8",
|
||||||
|
"resize-observer-polyfill": "1.5.1",
|
||||||
"spectron": "10.0.1",
|
"spectron": "10.0.1",
|
||||||
"style-loader": "1.1.3",
|
"style-loader": "1.1.3",
|
||||||
"terser": "4.6.6",
|
"terser": "4.6.6",
|
||||||
|
|
|
||||||
|
|
@ -7049,6 +7049,11 @@ reselect@4.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7"
|
resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7"
|
||||||
integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==
|
integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==
|
||||||
|
|
||||||
|
resize-observer-polyfill@1.5.1:
|
||||||
|
version "1.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
|
||||||
|
integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
|
||||||
|
|
||||||
resolve-cwd@^2.0.0:
|
resolve-cwd@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
|
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue