mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: migrate to useRef take 2 (#21552)
This commit is contained in:
parent
7a1c5b2aa3
commit
e737ff83b4
@ -37,7 +37,7 @@ export const HeaderView: React.FC<React.PropsWithChildren<{
|
|||||||
setFilterText(params.get('q') || '');
|
setFilterText(params.get('q') || '');
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
});
|
}, [setFilterText]);
|
||||||
|
|
||||||
return (<>
|
return (<>
|
||||||
<div className='pt-3'>
|
<div className='pt-3'>
|
||||||
|
@ -30,7 +30,7 @@ export const CallLogView: React.FC<CallLogProps> = ({
|
|||||||
language,
|
language,
|
||||||
log,
|
log,
|
||||||
}) => {
|
}) => {
|
||||||
const messagesEndRef = React.createRef<HTMLDivElement>();
|
const messagesEndRef = React.useRef<HTMLDivElement>(null);
|
||||||
const [expandOverrides, setExpandOverrides] = React.useState<Map<string, boolean>>(new Map());
|
const [expandOverrides, setExpandOverrides] = React.useState<Map<string, boolean>>(new Map());
|
||||||
React.useLayoutEffect(() => {
|
React.useLayoutEffect(() => {
|
||||||
if (log.find(callLog => callLog.reveal))
|
if (log.find(callLog => callLog.reveal))
|
||||||
|
@ -78,7 +78,7 @@ export const Recorder: React.FC<RecorderProps> = ({
|
|||||||
setFileId(value);
|
setFileId(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const messagesEndRef = React.createRef<HTMLDivElement>();
|
const messagesEndRef = React.useRef<HTMLDivElement>(null);
|
||||||
React.useLayoutEffect(() => {
|
React.useLayoutEffect(() => {
|
||||||
messagesEndRef.current?.scrollIntoView({ block: 'center', inline: 'nearest' });
|
messagesEndRef.current?.scrollIntoView({ block: 'center', inline: 'nearest' });
|
||||||
}, [messagesEndRef]);
|
}, [messagesEndRef]);
|
||||||
|
@ -41,35 +41,37 @@ export const SnapshotTab: React.FunctionComponent<{
|
|||||||
const [highlightedLocator, setHighlightedLocator] = React.useState<string>('');
|
const [highlightedLocator, setHighlightedLocator] = React.useState<string>('');
|
||||||
const [pickerVisible, setPickerVisible] = React.useState(false);
|
const [pickerVisible, setPickerVisible] = React.useState(false);
|
||||||
|
|
||||||
const snapshotMap = new Map<string, { title: string, snapshotName: string }>();
|
const { snapshots, snapshotInfoUrl, snapshotUrl, pointX, pointY, popoutUrl } = React.useMemo(() => {
|
||||||
for (const snapshot of action?.snapshots || [])
|
const snapshotMap = new Map<string, { title: string, snapshotName: string }>();
|
||||||
snapshotMap.set(snapshot.title, snapshot);
|
for (const snapshot of action?.snapshots || [])
|
||||||
const actionSnapshot = snapshotMap.get('action') || snapshotMap.get('after');
|
snapshotMap.set(snapshot.title, snapshot);
|
||||||
const snapshots = [actionSnapshot ? { ...actionSnapshot, title: 'action' } : undefined, snapshotMap.get('before'), snapshotMap.get('after')].filter(Boolean) as { title: string, snapshotName: string }[];
|
const actionSnapshot = snapshotMap.get('action') || snapshotMap.get('after');
|
||||||
|
const snapshots = [actionSnapshot ? { ...actionSnapshot, title: 'action' } : undefined, snapshotMap.get('before'), snapshotMap.get('after')].filter(Boolean) as { title: string, snapshotName: string }[];
|
||||||
let snapshotUrl = 'data:text/html,<body style="background: #ddd"></body>';
|
let snapshotUrl = 'data:text/html,<body style="background: #ddd"></body>';
|
||||||
let popoutUrl: string | undefined;
|
let popoutUrl: string | undefined;
|
||||||
let snapshotInfoUrl: string | undefined;
|
let snapshotInfoUrl: string | undefined;
|
||||||
let pointX: number | undefined;
|
let pointX: number | undefined;
|
||||||
let pointY: number | undefined;
|
let pointY: number | undefined;
|
||||||
if (action) {
|
if (action) {
|
||||||
const snapshot = snapshots[snapshotIndex];
|
const snapshot = snapshots[snapshotIndex];
|
||||||
if (snapshot && snapshot.snapshotName) {
|
if (snapshot && snapshot.snapshotName) {
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
params.set('trace', context(action).traceUrl);
|
params.set('trace', context(action).traceUrl);
|
||||||
params.set('name', snapshot.snapshotName);
|
params.set('name', snapshot.snapshotName);
|
||||||
snapshotUrl = new URL(`snapshot/${action.pageId}?${params.toString()}`, window.location.href).toString();
|
snapshotUrl = new URL(`snapshot/${action.pageId}?${params.toString()}`, window.location.href).toString();
|
||||||
snapshotInfoUrl = new URL(`snapshotInfo/${action.pageId}?${params.toString()}`, window.location.href).toString();
|
snapshotInfoUrl = new URL(`snapshotInfo/${action.pageId}?${params.toString()}`, window.location.href).toString();
|
||||||
if (snapshot.snapshotName.includes('action')) {
|
if (snapshot.snapshotName.includes('action')) {
|
||||||
pointX = action.point?.x;
|
pointX = action.point?.x;
|
||||||
pointY = action.point?.y;
|
pointY = action.point?.y;
|
||||||
|
}
|
||||||
|
const popoutParams = new URLSearchParams();
|
||||||
|
popoutParams.set('r', snapshotUrl);
|
||||||
|
popoutParams.set('trace', context(action).traceUrl);
|
||||||
|
popoutUrl = new URL(`popout.html?${popoutParams.toString()}`, window.location.href).toString();
|
||||||
}
|
}
|
||||||
const popoutParams = new URLSearchParams();
|
|
||||||
popoutParams.set('r', snapshotUrl);
|
|
||||||
popoutParams.set('trace', context(action).traceUrl);
|
|
||||||
popoutUrl = new URL(`popout.html?${popoutParams.toString()}`, window.location.href).toString();
|
|
||||||
}
|
}
|
||||||
}
|
return { snapshots, snapshotInfoUrl, snapshotUrl, pointX, pointY, popoutUrl };
|
||||||
|
}, [action, snapshotIndex]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (snapshots.length >= 1 && snapshotIndex >= snapshots.length)
|
if (snapshots.length >= 1 && snapshotIndex >= snapshots.length)
|
||||||
@ -155,8 +157,9 @@ export const SnapshotTab: React.FunctionComponent<{
|
|||||||
setIsInspecting(!isInspecting);
|
setIsInspecting(!isInspecting);
|
||||||
}}></ToolbarButton>
|
}}></ToolbarButton>
|
||||||
<CodeMirrorWrapper text={highlightedLocator} language={sdkLanguage} readOnly={!popoutUrl} focusOnChange={true} wrapLines={true} onChange={text => {
|
<CodeMirrorWrapper text={highlightedLocator} language={sdkLanguage} readOnly={!popoutUrl} focusOnChange={true} wrapLines={true} onChange={text => {
|
||||||
setIsInspecting(false);
|
// Updating text needs to go first - react can squeeze a render between the state updates.
|
||||||
setHighlightedLocator(text);
|
setHighlightedLocator(text);
|
||||||
|
setIsInspecting(false);
|
||||||
}}></CodeMirrorWrapper>
|
}}></CodeMirrorWrapper>
|
||||||
<ToolbarButton icon='files' title='Copy locator' disabled={!popoutUrl} onClick={() => {
|
<ToolbarButton icon='files' title='Copy locator' disabled={!popoutUrl} onClick={() => {
|
||||||
copy(highlightedLocator);
|
copy(highlightedLocator);
|
||||||
|
@ -70,7 +70,7 @@ export const SourceTab: React.FunctionComponent<{
|
|||||||
|
|
||||||
const targetLine = typeof stackInfo === 'string' ? 0 : stackInfo.frames[selectedFrame]?.line || 0;
|
const targetLine = typeof stackInfo === 'string' ? 0 : stackInfo.frames[selectedFrame]?.line || 0;
|
||||||
|
|
||||||
const targetLineRef = React.createRef<HTMLDivElement>();
|
const targetLineRef = React.useRef<HTMLDivElement>(null);
|
||||||
React.useLayoutEffect(() => {
|
React.useLayoutEffect(() => {
|
||||||
if (needReveal && targetLineRef.current) {
|
if (needReveal && targetLineRef.current) {
|
||||||
targetLineRef.current.scrollIntoView({ block: 'center', inline: 'nearest' });
|
targetLineRef.current.scrollIntoView({ block: 'center', inline: 'nearest' });
|
||||||
|
@ -42,15 +42,16 @@ export const CodeMirrorWrapper: React.FC<SourceProps> = ({
|
|||||||
text,
|
text,
|
||||||
language,
|
language,
|
||||||
readOnly,
|
readOnly,
|
||||||
highlight = [],
|
highlight,
|
||||||
revealLine,
|
revealLine,
|
||||||
lineNumbers,
|
lineNumbers,
|
||||||
focusOnChange,
|
focusOnChange,
|
||||||
wrapLines,
|
wrapLines,
|
||||||
onChange,
|
onChange,
|
||||||
}) => {
|
}) => {
|
||||||
const codemirrorElement = React.createRef<HTMLDivElement>();
|
const codemirrorElement = React.useRef<HTMLDivElement>(null);
|
||||||
const [modulePromise] = React.useState<Promise<CodeMirror>>(import('./codeMirrorModule').then(m => m.default));
|
const [modulePromise] = React.useState<Promise<CodeMirror>>(import('./codeMirrorModule').then(m => m.default));
|
||||||
|
const codemirrorRef = React.useRef<CodeMirror.Editor|null>(null);
|
||||||
const [codemirror, setCodemirror] = React.useState<CodeMirror.Editor>();
|
const [codemirror, setCodemirror] = React.useState<CodeMirror.Editor>();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@ -70,18 +71,17 @@ export const CodeMirrorWrapper: React.FC<SourceProps> = ({
|
|||||||
if (language === 'csharp')
|
if (language === 'csharp')
|
||||||
mode = 'text/x-csharp';
|
mode = 'text/x-csharp';
|
||||||
|
|
||||||
if (codemirror
|
if (codemirrorRef.current
|
||||||
&& mode === codemirror.getOption('mode')
|
&& mode === codemirrorRef.current.getOption('mode')
|
||||||
&& readOnly === codemirror.getOption('readOnly')
|
&& readOnly === codemirrorRef.current.getOption('readOnly')
|
||||||
&& lineNumbers === codemirror.getOption('lineNumbers')
|
&& lineNumbers === codemirrorRef.current.getOption('lineNumbers')
|
||||||
&& wrapLines === codemirror.getOption('lineWrapping')) {
|
&& wrapLines === codemirrorRef.current.getOption('lineWrapping')) {
|
||||||
updateEditor(codemirror, text, highlight, revealLine, focusOnChange);
|
// No need to re-create codemirror.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Either configuration is different or we don't have a codemirror yet.
|
// Either configuration is different or we don't have a codemirror yet.
|
||||||
if (codemirror)
|
codemirrorRef.current?.getWrapperElement().remove();
|
||||||
codemirror.getWrapperElement().remove();
|
|
||||||
|
|
||||||
const cm = CodeMirror(element, {
|
const cm = CodeMirror(element, {
|
||||||
value: '',
|
value: '',
|
||||||
@ -90,29 +90,38 @@ export const CodeMirrorWrapper: React.FC<SourceProps> = ({
|
|||||||
lineNumbers,
|
lineNumbers,
|
||||||
lineWrapping: wrapLines,
|
lineWrapping: wrapLines,
|
||||||
});
|
});
|
||||||
|
codemirrorRef.current = cm;
|
||||||
setCodemirror(cm);
|
setCodemirror(cm);
|
||||||
if (onChange)
|
|
||||||
cm.on('change', () => onChange(cm.getValue()));
|
|
||||||
updateEditor(cm, text, highlight, revealLine, focusOnChange);
|
|
||||||
return cm;
|
return cm;
|
||||||
})();
|
})();
|
||||||
}, [modulePromise, codemirror, codemirrorElement, text, language, highlight, revealLine, focusOnChange, lineNumbers, wrapLines, readOnly, onChange]);
|
}, [modulePromise, codemirror, codemirrorElement, language, lineNumbers, wrapLines, readOnly]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!codemirror)
|
||||||
|
return;
|
||||||
|
codemirror.off('change', (codemirror as any).listenerSymbol);
|
||||||
|
(codemirror as any)[listenerSymbol] = undefined;
|
||||||
|
if (onChange) {
|
||||||
|
(codemirror as any)[listenerSymbol] = () => onChange(codemirror.getValue());
|
||||||
|
codemirror.on('change', (codemirror as any)[listenerSymbol]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (codemirror.getValue() !== text) {
|
||||||
|
codemirror.setValue(text);
|
||||||
|
if (focusOnChange) {
|
||||||
|
codemirror.execCommand('selectAll');
|
||||||
|
codemirror.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i = 0; i < codemirror.lineCount(); ++i)
|
||||||
|
codemirror.removeLineClass(i, 'wrap');
|
||||||
|
for (const h of highlight || [])
|
||||||
|
codemirror.addLineClass(h.line - 1, 'wrap', `source-line-${h.type}`);
|
||||||
|
if (revealLine)
|
||||||
|
codemirror.scrollIntoView({ line: revealLine - 1, ch: 0 }, 50);
|
||||||
|
}, [codemirror, text, highlight, revealLine, focusOnChange, onChange]);
|
||||||
|
|
||||||
return <div className='cm-wrapper' ref={codemirrorElement}></div>;
|
return <div className='cm-wrapper' ref={codemirrorElement}></div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
function updateEditor(cm: CodeMirror.Editor, text: string, highlight: SourceHighlight[], revealLine?: number, focusOnChange?: boolean) {
|
const listenerSymbol = Symbol('listener');
|
||||||
if (cm.getValue() !== text) {
|
|
||||||
cm.setValue(text);
|
|
||||||
if (focusOnChange) {
|
|
||||||
cm.execCommand('selectAll');
|
|
||||||
cm.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (let i = 0; i < cm.lineCount(); ++i)
|
|
||||||
cm.removeLineClass(i, 'wrap');
|
|
||||||
for (const h of highlight)
|
|
||||||
cm.addLineClass(h.line - 1, 'wrap', `source-line-${h.type}`);
|
|
||||||
if (revealLine)
|
|
||||||
cm.scrollIntoView({ line: revealLine - 1, ch: 0 }, 50);
|
|
||||||
}
|
|
||||||
|
@ -52,7 +52,7 @@ export function ListView<T>({
|
|||||||
noItemsMessage,
|
noItemsMessage,
|
||||||
dataTestId,
|
dataTestId,
|
||||||
}: ListViewProps<T>) {
|
}: ListViewProps<T>) {
|
||||||
const itemListRef = React.createRef<HTMLDivElement>();
|
const itemListRef = React.useRef<HTMLDivElement>(null);
|
||||||
const [highlightedItem, setHighlightedItem] = React.useState<any>();
|
const [highlightedItem, setHighlightedItem] = React.useState<any>();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
@ -30,9 +30,9 @@ export type XtermDataSource = {
|
|||||||
export const XtermWrapper: React.FC<{ source: XtermDataSource }> = ({
|
export const XtermWrapper: React.FC<{ source: XtermDataSource }> = ({
|
||||||
source
|
source
|
||||||
}) => {
|
}) => {
|
||||||
const xtermElement = React.createRef<HTMLDivElement>();
|
const xtermElement = React.useRef<HTMLDivElement>(null);
|
||||||
const [modulePromise] = React.useState<Promise<XtermModule>>(import('./xtermModule').then(m => m.default));
|
const [modulePromise] = React.useState<Promise<XtermModule>>(import('./xtermModule').then(m => m.default));
|
||||||
const [terminal, setTerminal] = React.useState<Terminal>();
|
const terminal = React.useRef<Terminal | null>(null);
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
// Always load the module first.
|
// Always load the module first.
|
||||||
@ -41,7 +41,7 @@ export const XtermWrapper: React.FC<{ source: XtermDataSource }> = ({
|
|||||||
if (!element)
|
if (!element)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (terminal)
|
if (terminal.current)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const newTerminal = new Terminal({
|
const newTerminal = new Terminal({
|
||||||
@ -65,7 +65,7 @@ export const XtermWrapper: React.FC<{ source: XtermDataSource }> = ({
|
|||||||
};
|
};
|
||||||
newTerminal.open(element);
|
newTerminal.open(element);
|
||||||
fitAddon.fit();
|
fitAddon.fit();
|
||||||
setTerminal(newTerminal);
|
terminal.current = newTerminal;
|
||||||
const resizeObserver = new ResizeObserver(() => {
|
const resizeObserver = new ResizeObserver(() => {
|
||||||
source.resize(newTerminal.cols, newTerminal.rows);
|
source.resize(newTerminal.cols, newTerminal.rows);
|
||||||
fitAddon.fit();
|
fitAddon.fit();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user