mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-12 00:52:05 +03: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]);
|
||||
|
||||
return (<>
|
||||
<div className='pt-3'>
|
||||
|
@ -30,7 +30,7 @@ export const CallLogView: React.FC<CallLogProps> = ({
|
||||
language,
|
||||
log,
|
||||
}) => {
|
||||
const messagesEndRef = React.createRef<HTMLDivElement>();
|
||||
const messagesEndRef = React.useRef<HTMLDivElement>(null);
|
||||
const [expandOverrides, setExpandOverrides] = React.useState<Map<string, boolean>>(new Map());
|
||||
React.useLayoutEffect(() => {
|
||||
if (log.find(callLog => callLog.reveal))
|
||||
|
@ -78,7 +78,7 @@ export const Recorder: React.FC<RecorderProps> = ({
|
||||
setFileId(value);
|
||||
};
|
||||
|
||||
const messagesEndRef = React.createRef<HTMLDivElement>();
|
||||
const messagesEndRef = React.useRef<HTMLDivElement>(null);
|
||||
React.useLayoutEffect(() => {
|
||||
messagesEndRef.current?.scrollIntoView({ block: 'center', inline: 'nearest' });
|
||||
}, [messagesEndRef]);
|
||||
|
@ -41,35 +41,37 @@ export const SnapshotTab: React.FunctionComponent<{
|
||||
const [highlightedLocator, setHighlightedLocator] = React.useState<string>('');
|
||||
const [pickerVisible, setPickerVisible] = React.useState(false);
|
||||
|
||||
const snapshotMap = new Map<string, { title: string, snapshotName: string }>();
|
||||
for (const snapshot of action?.snapshots || [])
|
||||
snapshotMap.set(snapshot.title, snapshot);
|
||||
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 popoutUrl: string | undefined;
|
||||
let snapshotInfoUrl: string | undefined;
|
||||
let pointX: number | undefined;
|
||||
let pointY: number | undefined;
|
||||
if (action) {
|
||||
const snapshot = snapshots[snapshotIndex];
|
||||
if (snapshot && snapshot.snapshotName) {
|
||||
const params = new URLSearchParams();
|
||||
params.set('trace', context(action).traceUrl);
|
||||
params.set('name', snapshot.snapshotName);
|
||||
snapshotUrl = new URL(`snapshot/${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')) {
|
||||
pointX = action.point?.x;
|
||||
pointY = action.point?.y;
|
||||
const { snapshots, snapshotInfoUrl, snapshotUrl, pointX, pointY, popoutUrl } = React.useMemo(() => {
|
||||
const snapshotMap = new Map<string, { title: string, snapshotName: string }>();
|
||||
for (const snapshot of action?.snapshots || [])
|
||||
snapshotMap.set(snapshot.title, snapshot);
|
||||
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 popoutUrl: string | undefined;
|
||||
let snapshotInfoUrl: string | undefined;
|
||||
let pointX: number | undefined;
|
||||
let pointY: number | undefined;
|
||||
if (action) {
|
||||
const snapshot = snapshots[snapshotIndex];
|
||||
if (snapshot && snapshot.snapshotName) {
|
||||
const params = new URLSearchParams();
|
||||
params.set('trace', context(action).traceUrl);
|
||||
params.set('name', snapshot.snapshotName);
|
||||
snapshotUrl = new URL(`snapshot/${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')) {
|
||||
pointX = action.point?.x;
|
||||
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(() => {
|
||||
if (snapshots.length >= 1 && snapshotIndex >= snapshots.length)
|
||||
@ -155,8 +157,9 @@ export const SnapshotTab: React.FunctionComponent<{
|
||||
setIsInspecting(!isInspecting);
|
||||
}}></ToolbarButton>
|
||||
<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);
|
||||
setIsInspecting(false);
|
||||
}}></CodeMirrorWrapper>
|
||||
<ToolbarButton icon='files' title='Copy locator' disabled={!popoutUrl} onClick={() => {
|
||||
copy(highlightedLocator);
|
||||
|
@ -70,7 +70,7 @@ export const SourceTab: React.FunctionComponent<{
|
||||
|
||||
const targetLine = typeof stackInfo === 'string' ? 0 : stackInfo.frames[selectedFrame]?.line || 0;
|
||||
|
||||
const targetLineRef = React.createRef<HTMLDivElement>();
|
||||
const targetLineRef = React.useRef<HTMLDivElement>(null);
|
||||
React.useLayoutEffect(() => {
|
||||
if (needReveal && targetLineRef.current) {
|
||||
targetLineRef.current.scrollIntoView({ block: 'center', inline: 'nearest' });
|
||||
|
@ -42,15 +42,16 @@ export const CodeMirrorWrapper: React.FC<SourceProps> = ({
|
||||
text,
|
||||
language,
|
||||
readOnly,
|
||||
highlight = [],
|
||||
highlight,
|
||||
revealLine,
|
||||
lineNumbers,
|
||||
focusOnChange,
|
||||
wrapLines,
|
||||
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 codemirrorRef = React.useRef<CodeMirror.Editor|null>(null);
|
||||
const [codemirror, setCodemirror] = React.useState<CodeMirror.Editor>();
|
||||
|
||||
React.useEffect(() => {
|
||||
@ -70,18 +71,17 @@ export const CodeMirrorWrapper: React.FC<SourceProps> = ({
|
||||
if (language === 'csharp')
|
||||
mode = 'text/x-csharp';
|
||||
|
||||
if (codemirror
|
||||
&& mode === codemirror.getOption('mode')
|
||||
&& readOnly === codemirror.getOption('readOnly')
|
||||
&& lineNumbers === codemirror.getOption('lineNumbers')
|
||||
&& wrapLines === codemirror.getOption('lineWrapping')) {
|
||||
updateEditor(codemirror, text, highlight, revealLine, focusOnChange);
|
||||
if (codemirrorRef.current
|
||||
&& mode === codemirrorRef.current.getOption('mode')
|
||||
&& readOnly === codemirrorRef.current.getOption('readOnly')
|
||||
&& lineNumbers === codemirrorRef.current.getOption('lineNumbers')
|
||||
&& wrapLines === codemirrorRef.current.getOption('lineWrapping')) {
|
||||
// No need to re-create codemirror.
|
||||
return;
|
||||
}
|
||||
|
||||
// Either configuration is different or we don't have a codemirror yet.
|
||||
if (codemirror)
|
||||
codemirror.getWrapperElement().remove();
|
||||
codemirrorRef.current?.getWrapperElement().remove();
|
||||
|
||||
const cm = CodeMirror(element, {
|
||||
value: '',
|
||||
@ -90,29 +90,38 @@ export const CodeMirrorWrapper: React.FC<SourceProps> = ({
|
||||
lineNumbers,
|
||||
lineWrapping: wrapLines,
|
||||
});
|
||||
codemirrorRef.current = cm;
|
||||
setCodemirror(cm);
|
||||
if (onChange)
|
||||
cm.on('change', () => onChange(cm.getValue()));
|
||||
updateEditor(cm, text, highlight, revealLine, focusOnChange);
|
||||
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>;
|
||||
};
|
||||
|
||||
function updateEditor(cm: CodeMirror.Editor, text: string, highlight: SourceHighlight[], revealLine?: number, focusOnChange?: boolean) {
|
||||
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);
|
||||
}
|
||||
const listenerSymbol = Symbol('listener');
|
||||
|
@ -52,7 +52,7 @@ export function ListView<T>({
|
||||
noItemsMessage,
|
||||
dataTestId,
|
||||
}: ListViewProps<T>) {
|
||||
const itemListRef = React.createRef<HTMLDivElement>();
|
||||
const itemListRef = React.useRef<HTMLDivElement>(null);
|
||||
const [highlightedItem, setHighlightedItem] = React.useState<any>();
|
||||
|
||||
React.useEffect(() => {
|
||||
|
@ -30,9 +30,9 @@ export type XtermDataSource = {
|
||||
export const XtermWrapper: React.FC<{ source: XtermDataSource }> = ({
|
||||
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 [terminal, setTerminal] = React.useState<Terminal>();
|
||||
const terminal = React.useRef<Terminal | null>(null);
|
||||
React.useEffect(() => {
|
||||
(async () => {
|
||||
// Always load the module first.
|
||||
@ -41,7 +41,7 @@ export const XtermWrapper: React.FC<{ source: XtermDataSource }> = ({
|
||||
if (!element)
|
||||
return;
|
||||
|
||||
if (terminal)
|
||||
if (terminal.current)
|
||||
return;
|
||||
|
||||
const newTerminal = new Terminal({
|
||||
@ -65,7 +65,7 @@ export const XtermWrapper: React.FC<{ source: XtermDataSource }> = ({
|
||||
};
|
||||
newTerminal.open(element);
|
||||
fitAddon.fit();
|
||||
setTerminal(newTerminal);
|
||||
terminal.current = newTerminal;
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
source.resize(newTerminal.cols, newTerminal.rows);
|
||||
fitAddon.fit();
|
||||
|
Loading…
Reference in New Issue
Block a user