Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move Hyper container to function component #7365

Merged
merged 1 commit into from
Jul 25, 2023
Merged
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
170 changes: 83 additions & 87 deletions lib/containers/hyper.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, {forwardRef, useEffect, useRef} from 'react';
import type {MousetrapInstance} from 'mousetrap';
import Mousetrap from 'mousetrap';

Expand All @@ -15,131 +15,127 @@ import type Terms from '../components/terms';

const isMac = /Mac/.test(navigator.userAgent);

class Hyper extends React.PureComponent<HyperProps> {
mousetrap!: MousetrapInstance;
terms!: Terms;
constructor(props: HyperProps) {
super(props);
}

componentDidUpdate(prev: HyperProps) {
const {lastConfigUpdate} = this.props;
if (lastConfigUpdate && lastConfigUpdate !== prev.lastConfigUpdate) {
void this.attachKeyListeners();
}
if (prev.activeSession !== this.props.activeSession) {
this.handleFocusActive(this.props.activeSession);
}
}
const Hyper = forwardRef<HTMLDivElement, HyperProps>((props, ref) => {
const mousetrap = useRef<MousetrapInstance | null>(null);
const terms = useRef<Terms | null>(null);

useEffect(() => {
void attachKeyListeners();
}, [props.lastConfigUpdate]);
useEffect(() => {
handleFocusActive(props.activeSession);
}, [props.activeSession]);

handleFocusActive = (uid?: string | null) => {
const term = uid && this.terms.getTermByUid(uid);
const handleFocusActive = (uid?: string | null) => {
const term = uid && terms.current?.getTermByUid(uid);
if (term) {
term.focus();
}
};

handleSelectAll = () => {
const term = this.terms.getActiveTerm();
const handleSelectAll = () => {
const term = terms.current?.getActiveTerm();
if (term) {
term.selectAll();
}
};

async attachKeyListeners() {
if (!this.mousetrap) {
const attachKeyListeners = async () => {
if (!mousetrap.current) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
this.mousetrap = new (Mousetrap as any)(window, true);
this.mousetrap.stopCallback = () => {
mousetrap.current = new (Mousetrap as any)(window, true);
mousetrap.current!.stopCallback = () => {
// All events should be intercepted even if focus is in an input/textarea
return false;
};
} else {
this.mousetrap.reset();
mousetrap.current.reset();
}

const keys = await getRegisteredKeys();
Object.keys(keys).forEach((commandKeys) => {
this.mousetrap.bind(
mousetrap.current?.bind(
commandKeys,
(e) => {
const command = keys[commandKeys];
// We should tell to xterm that it should ignore this event.
// We should tell xterm to ignore this event.
(e as any).catched = true;
this.props.execCommand(command, getCommandHandler(command), e);
props.execCommand(command, getCommandHandler(command), e);
shouldPreventDefault(command) && e.preventDefault();
},
'keydown'
);
});
}
};

componentDidMount() {
void this.attachKeyListeners();
window.rpc.on('term selectAll', this.handleSelectAll);
}
useEffect(() => {
void attachKeyListeners();
window.rpc.on('term selectAll', handleSelectAll);
}, []);

onTermsRef = (terms: Terms) => {
this.terms = terms;
const onTermsRef = (_terms: Terms) => {
terms.current = _terms;
window.focusActiveTerm = (uid?: string) => {
if (uid) {
this.handleFocusActive(uid);
handleFocusActive(uid);
} else {
this.terms.getActiveTerm().focus();
terms.current?.getActiveTerm()?.focus();
}
};
};

componentWillUnmount() {
this.mousetrap?.reset();
}

render() {
const {isMac: isMac_, customCSS, uiFontFamily, borderColor, maximized, fullScreen} = this.props;
const borderWidth = isMac_ ? '' : `${maximized ? '0' : '1'}px`;
stylis.set({prefix: false});
return (
<div id="hyper">
<div
style={{fontFamily: uiFontFamily, borderColor, borderWidth}}
className={`hyper_main ${isMac_ && 'hyper_mainRounded'} ${fullScreen ? 'fullScreen' : ''}`}
>
<HeaderContainer />
<TermsContainer ref_={this.onTermsRef} />
{this.props.customInnerChildren}
</div>

<NotificationsContainer />

{this.props.customChildren}

<style jsx>
{`
.hyper_main {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 1px solid #333;
}

.hyper_mainRounded {
border-radius: 10.5px;
overflow: hidden;
}
`}
</style>

{/*
Add custom CSS to Hyper.
We add a scope to the customCSS so that it can get around the weighting applied by styled-jsx
*/}
<style dangerouslySetInnerHTML={{__html: stylis('#hyper', customCSS)}} />
useEffect(() => {
return () => {
mousetrap.current?.reset();
};
}, []);

const {isMac: isMac_, customCSS, uiFontFamily, borderColor, maximized, fullScreen} = props;
const borderWidth = isMac_ ? '' : `${maximized ? '0' : '1'}px`;
stylis.set({prefix: false});
return (
<div id="hyper" ref={ref}>
<div
style={{fontFamily: uiFontFamily, borderColor, borderWidth}}
className={`hyper_main ${isMac_ && 'hyper_mainRounded'} ${fullScreen ? 'fullScreen' : ''}`}
>
<HeaderContainer />
<TermsContainer ref_={onTermsRef} />
{props.customInnerChildren}
</div>
);
}
}

<NotificationsContainer />

{props.customChildren}

<style jsx>
{`
.hyper_main {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 1px solid #333;
}

.hyper_mainRounded {
border-radius: 10.5px;
overflow: hidden;
}
`}
</style>

{/*
Add custom CSS to Hyper.
We add a scope to the customCSS so that it can get around the weighting applied by styled-jsx
*/}
<style dangerouslySetInnerHTML={{__html: stylis('#hyper', customCSS)}} />
</div>
);
});

Hyper.displayName = 'Hyper';

const mapStateToProps = (state: HyperState) => {
return {
Expand Down
Loading