Skip to content
This repository was archived by the owner on Jul 30, 2025. It is now read-only.

Commit 9fc51cc

Browse files
starpitk8s-ci-robot
authored andcommitted
fix(plugins/plugin-client-common): clicking on split blank space does not focus active block
part of #7618
1 parent 2e54a8f commit 9fc51cc

File tree

2 files changed

+53
-40
lines changed

2 files changed

+53
-40
lines changed

plugins/plugin-client-common/src/components/Views/Terminal/ScrollableTerminal.tsx

Lines changed: 51 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -363,13 +363,15 @@ export default class ScrollableTerminal extends React.PureComponent<Props, State
363363
remove: undefined,
364364
clear: undefined,
365365
onClick: undefined,
366+
onMouseDown: undefined,
366367
onFocus: undefined,
367368
onOutputRender: undefined,
368369
navigateTo: undefined,
369370
setActiveBlock: undefined,
370371
willFocusBlock: undefined,
371372
willRemoveBlock: undefined,
372-
willUpdateCommand: undefined
373+
willUpdateCommand: undefined,
374+
tabRefFor: undefined
373375
}
374376

375377
const getBlockIndexFromEvent = (evt: React.SyntheticEvent, doNotComplain = false) => {
@@ -386,26 +388,33 @@ export default class ScrollableTerminal extends React.PureComponent<Props, State
386388

387389
state.remove = () => this.removeSplit(sbuuid)
388390
state.clear = () => this.clear(sbuuid)
391+
392+
/**
393+
* For inline-input clients, we want empty-space clicks to steal
394+
* focus away from the other split, if we are switching splits;
395+
* otherwise, we don't want empty-space clicks in the focused
396+
* split to steal focus away from that split's active input
397+
*/
389398
state.onClick = () => {
390399
if (getSelectionText().length === 0) {
391-
const sbidx = this.findSplit(this.state, sbuuid)
392-
if (sbidx >= 0) {
393-
const scrollback = this.state.splits[sbidx]
394-
this.doFocus(scrollback)
395-
}
400+
this.doFocus(state)
396401
}
397402
}
398403

404+
/**
405+
* For bottom-input clients, we don't want empty-space clicks to
406+
* steal focus away from the bottom input
407+
*/
408+
state.onMouseDown = (evt: React.MouseEvent<HTMLElement>) => {
409+
evt.preventDefault()
410+
}
411+
399412
/** Output.tsx finished rendering something */
400413
state.onOutputRender = () => {
401414
if (!this.props.noActiveInput) {
402415
// if we are using inline input, then scroll to the bottom
403416
// whenever an output is rendered in this split
404-
const sbidx = this.findSplit(this.state, sbuuid)
405-
if (sbidx >= 0) {
406-
const scrollback = this.state.splits[sbidx]
407-
setTimeout(() => scrollback.facade.scrollToBottom())
408-
}
417+
setTimeout(() => state.facade.scrollToBottom())
409418
}
410419
}
411420

@@ -517,6 +526,34 @@ export default class ScrollableTerminal extends React.PureComponent<Props, State
517526
}
518527
}
519528

529+
state.tabRefFor = (ref: HTMLElement) => {
530+
const scrollback = state
531+
if (ref) {
532+
ref['facade'] = scrollback.facade
533+
scrollback.facade.getSize = getSize.bind(ref)
534+
535+
scrollback.facade.splitCount = () => this.state.splits.length
536+
scrollback.facade.hasSideBySideTerminals = () => {
537+
return !!this.state.splits.find((_, sbidx) => this.isASideBySide(sbidx))
538+
}
539+
540+
scrollback.facade.scrollToBottom = () => {
541+
ref.scrollTop = ref.scrollHeight
542+
}
543+
544+
scrollback.facade.scrollToTop = () => {
545+
ref.scrollTop = 0
546+
}
547+
548+
scrollback.facade.addClass = (cls: string) => {
549+
ref.classList.add(cls)
550+
}
551+
scrollback.facade.removeClass = (cls: string) => {
552+
ref.classList.remove(cls)
553+
}
554+
}
555+
}
556+
520557
// prefetch command history; this helps with master history
521558
History(sbuuid)
522559

@@ -1115,33 +1152,6 @@ export default class ScrollableTerminal extends React.PureComponent<Props, State
11151152
return this.theseAreSideBySide[this.state.splits.length][sbidx]
11161153
}
11171154

1118-
private tabRefFor(scrollback: ScrollbackState, ref: HTMLElement) {
1119-
if (ref) {
1120-
ref['facade'] = scrollback.facade
1121-
scrollback.facade.getSize = getSize.bind(ref)
1122-
1123-
scrollback.facade.splitCount = () => this.state.splits.length
1124-
scrollback.facade.hasSideBySideTerminals = () => {
1125-
return !!this.state.splits.find((_, sbidx) => this.isASideBySide(sbidx))
1126-
}
1127-
1128-
scrollback.facade.scrollToBottom = () => {
1129-
ref.scrollTop = ref.scrollHeight
1130-
}
1131-
1132-
scrollback.facade.scrollToTop = () => {
1133-
ref.scrollTop = 0
1134-
}
1135-
1136-
scrollback.facade.addClass = (cls: string) => {
1137-
ref.classList.add(cls)
1138-
}
1139-
scrollback.facade.removeClass = (cls: string) => {
1140-
ref.classList.remove(cls)
1141-
}
1142-
}
1143-
}
1144-
11451155
private tabFor(scrollback: ScrollbackState): KuiTab {
11461156
if (!scrollback.facade) {
11471157
const { uuid } = scrollback
@@ -1308,8 +1318,9 @@ export default class ScrollableTerminal extends React.PureComponent<Props, State
13081318
data-is-focused={sbidx === this.state.focusedIdx || undefined}
13091319
key={tab.uuid}
13101320
data-scrollback-id={tab.uuid}
1311-
ref={ref => this.tabRefFor(scrollback, ref)}
1312-
onClick={scrollback.onClick}
1321+
ref={scrollback.tabRefFor}
1322+
onClick={!this.props.noActiveInput ? scrollback.onClick : undefined}
1323+
onMouseDown={this.props.noActiveInput ? scrollback.onMouseDown : undefined}
13131324
>
13141325
<React.Fragment>
13151326
{this.state.splits.length > 1 && <SplitHeader onRemove={scrollback.remove} onClear={scrollback.clear} />}

plugins/plugin-client-common/src/components/Views/Terminal/ScrollbackState.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,15 @@ type ScrollbackState = ScrollbackOptions & {
5050
remove: () => void
5151
clear: () => void
5252
onClick: (evt: React.MouseEvent<HTMLElement, MouseEvent>) => void
53+
onMouseDown: (evt: React.MouseEvent<HTMLElement, MouseEvent>) => void
5354
onFocus: (evt: React.FocusEvent) => void
5455
onOutputRender: () => void
5556
navigateTo: (dir: 'first' | 'last' | 'previous' | 'next') => void
5657
setActiveBlock: (c: Block) => void
5758
willFocusBlock: (evt: React.SyntheticEvent) => void
5859
willRemoveBlock: (evt: React.SyntheticEvent, idx?: number) => void
5960
willUpdateCommand: (idx: number, command: string) => void
61+
tabRefFor: (ref: HTMLElement) => void
6062
}
6163

6264
export default ScrollbackState

0 commit comments

Comments
 (0)