diff --git a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElement.js b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElement.js index 0c980f0db48..cc37953f4d2 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElement.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElement.js @@ -18,16 +18,14 @@ import Toggle from '../Toggle'; import {ElementTypeSuspense} from 'react-devtools-shared/src/frontend/types'; import InspectedElementView from './InspectedElementView'; import {InspectedElementContext} from './InspectedElementContext'; -import {getOpenInEditorURL, getAlwaysOpenInEditor} from '../../../utils'; -import { - LOCAL_STORAGE_OPEN_IN_EDITOR_URL, - LOCAL_STORAGE_ALWAYS_OPEN_IN_EDITOR, -} from '../../../constants'; +import {getAlwaysOpenInEditor} from '../../../utils'; +import {LOCAL_STORAGE_ALWAYS_OPEN_IN_EDITOR} from '../../../constants'; import FetchFileWithCachingContext from './FetchFileWithCachingContext'; import {symbolicateSourceWithCache} from 'react-devtools-shared/src/symbolicateSource'; import OpenInEditorButton from './OpenInEditorButton'; import InspectedElementViewSourceButton from './InspectedElementViewSourceButton'; import Skeleton from './Skeleton'; +import useEditorURL from '../useEditorURL'; import styles from './InspectedElement.css'; @@ -134,12 +132,7 @@ export default function InspectedElementWrapper(_: Props): React.Node { getAlwaysOpenInEditor, ); - const editorURL = useSyncExternalStore(function subscribe(callback) { - window.addEventListener(LOCAL_STORAGE_OPEN_IN_EDITOR_URL, callback); - return function unsubscribe() { - window.removeEventListener(LOCAL_STORAGE_OPEN_IN_EDITOR_URL, callback); - }; - }, getOpenInEditorURL); + const editorURL = useEditorURL(); const toggleErrored = useCallback(() => { if (inspectedElement == null) { diff --git a/packages/react-devtools-shared/src/devtools/views/Editor/EditorPane.js b/packages/react-devtools-shared/src/devtools/views/Editor/EditorPane.js index 09c76e1d26e..bc1187d8f6e 100644 --- a/packages/react-devtools-shared/src/devtools/views/Editor/EditorPane.js +++ b/packages/react-devtools-shared/src/devtools/views/Editor/EditorPane.js @@ -8,7 +8,7 @@ */ import * as React from 'react'; -import {useSyncExternalStore, useState, startTransition} from 'react'; +import {useState, startTransition} from 'react'; import portaledContent from '../portaledContent'; @@ -18,8 +18,7 @@ import Button from 'react-devtools-shared/src/devtools/views/Button'; import ButtonIcon from 'react-devtools-shared/src/devtools/views/ButtonIcon'; import OpenInEditorButton from './OpenInEditorButton'; -import {getOpenInEditorURL} from '../../../utils'; -import {LOCAL_STORAGE_OPEN_IN_EDITOR_URL} from '../../../constants'; +import useEditorURL from '../useEditorURL'; import EditorSettings from './EditorSettings'; import CodeEditorByDefault from '../Settings/CodeEditorByDefault'; @@ -38,17 +37,7 @@ export type Props = {selectedSource: ?SourceSelection}; function EditorPane({selectedSource}: Props) { const [showSettings, setShowSettings] = useState(false); - const editorURL = useSyncExternalStore( - function subscribe(callback) { - window.addEventListener(LOCAL_STORAGE_OPEN_IN_EDITOR_URL, callback); - return function unsubscribe() { - window.removeEventListener(LOCAL_STORAGE_OPEN_IN_EDITOR_URL, callback); - }; - }, - function getState() { - return getOpenInEditorURL(); - }, - ); + const editorURL = useEditorURL(); let editorToolbar; if (showSettings) { diff --git a/packages/react-devtools-shared/src/devtools/views/Settings/CodeEditorOptions.js b/packages/react-devtools-shared/src/devtools/views/Settings/CodeEditorOptions.js index aa5a7767867..d6e81ef3554 100644 --- a/packages/react-devtools-shared/src/devtools/views/Settings/CodeEditorOptions.js +++ b/packages/react-devtools-shared/src/devtools/views/Settings/CodeEditorOptions.js @@ -13,12 +13,13 @@ import { LOCAL_STORAGE_OPEN_IN_EDITOR_URL_PRESET, } from '../../../constants'; import {useLocalStorage} from '../hooks'; -import {getDefaultOpenInEditorURL} from 'react-devtools-shared/src/utils'; +import { + getDefaultPreset, + getDefaultOpenInEditorURL, +} from 'react-devtools-shared/src/utils'; import styles from './SettingsShared.css'; -const vscodeFilepath = 'vscode://file/{path}:{line}:{column}'; - export default function CodeEditorOptions({ environmentNames, }: { @@ -26,7 +27,7 @@ export default function CodeEditorOptions({ }): React.Node { const [openInEditorURLPreset, setOpenInEditorURLPreset] = useLocalStorage< 'vscode' | 'custom', - >(LOCAL_STORAGE_OPEN_IN_EDITOR_URL_PRESET, 'custom'); + >(LOCAL_STORAGE_OPEN_IN_EDITOR_URL_PRESET, getDefaultPreset()); const [openInEditorURL, setOpenInEditorURL] = useLocalStorage( LOCAL_STORAGE_OPEN_IN_EDITOR_URL, @@ -40,11 +41,6 @@ export default function CodeEditorOptions({ onChange={({currentTarget}) => { const selectedValue = currentTarget.value; setOpenInEditorURLPreset(selectedValue); - if (selectedValue === 'vscode') { - setOpenInEditorURL(vscodeFilepath); - } else if (selectedValue === 'custom') { - setOpenInEditorURL(''); - } }}> @@ -53,7 +49,7 @@ export default function CodeEditorOptions({ { setOpenInEditorURL(event.target.value); diff --git a/packages/react-devtools-shared/src/devtools/views/useEditorURL.js b/packages/react-devtools-shared/src/devtools/views/useEditorURL.js new file mode 100644 index 00000000000..303758d6968 --- /dev/null +++ b/packages/react-devtools-shared/src/devtools/views/useEditorURL.js @@ -0,0 +1,39 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import {useCallback, useSyncExternalStore} from 'react'; + +import {getOpenInEditorURL} from '../../utils'; +import { + LOCAL_STORAGE_OPEN_IN_EDITOR_URL, + LOCAL_STORAGE_OPEN_IN_EDITOR_URL_PRESET, +} from '../../constants'; + +const useEditorURL = (): string => { + const editorURL = useSyncExternalStore( + useCallback(function subscribe(callback) { + window.addEventListener(LOCAL_STORAGE_OPEN_IN_EDITOR_URL, callback); + window.addEventListener( + LOCAL_STORAGE_OPEN_IN_EDITOR_URL_PRESET, + callback, + ); + return function unsubscribe() { + window.removeEventListener(LOCAL_STORAGE_OPEN_IN_EDITOR_URL, callback); + window.removeEventListener( + LOCAL_STORAGE_OPEN_IN_EDITOR_URL_PRESET, + callback, + ); + }; + }, []), + getOpenInEditorURL, + ); + return editorURL; +}; + +export default useEditorURL; diff --git a/packages/react-devtools-shared/src/devtools/views/useOpenResource.js b/packages/react-devtools-shared/src/devtools/views/useOpenResource.js index c645efc1e5e..3a7fee5b684 100644 --- a/packages/react-devtools-shared/src/devtools/views/useOpenResource.js +++ b/packages/react-devtools-shared/src/devtools/views/useOpenResource.js @@ -13,11 +13,9 @@ import {useCallback, useContext, useSyncExternalStore} from 'react'; import ViewElementSourceContext from './Components/ViewElementSourceContext'; -import {getOpenInEditorURL, getAlwaysOpenInEditor} from '../../utils'; -import { - LOCAL_STORAGE_OPEN_IN_EDITOR_URL, - LOCAL_STORAGE_ALWAYS_OPEN_IN_EDITOR, -} from '../../constants'; +import {getAlwaysOpenInEditor} from '../../utils'; +import useEditorURL from './useEditorURL'; +import {LOCAL_STORAGE_ALWAYS_OPEN_IN_EDITOR} from '../../constants'; import {checkConditions} from './Editor/utils'; @@ -32,15 +30,7 @@ const useOpenResource = ( ViewElementSourceContext, ); - const editorURL = useSyncExternalStore( - useCallback(function subscribe(callback) { - window.addEventListener(LOCAL_STORAGE_OPEN_IN_EDITOR_URL, callback); - return function unsubscribe() { - window.removeEventListener(LOCAL_STORAGE_OPEN_IN_EDITOR_URL, callback); - }; - }, []), - getOpenInEditorURL, - ); + const editorURL = useEditorURL(); const alwaysOpenInEditor = useSyncExternalStore( useCallback(function subscribe(callback) { diff --git a/packages/react-devtools-shared/src/utils.js b/packages/react-devtools-shared/src/utils.js index eb4044909eb..325224844d7 100644 --- a/packages/react-devtools-shared/src/utils.js +++ b/packages/react-devtools-shared/src/utils.js @@ -35,6 +35,7 @@ import { TREE_OPERATION_UPDATE_TREE_BASE_DURATION, LOCAL_STORAGE_COMPONENT_FILTER_PREFERENCES_KEY, LOCAL_STORAGE_OPEN_IN_EDITOR_URL, + LOCAL_STORAGE_OPEN_IN_EDITOR_URL_PRESET, LOCAL_STORAGE_ALWAYS_OPEN_IN_EDITOR, SESSION_STORAGE_RELOAD_AND_PROFILE_KEY, SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY, @@ -385,14 +386,27 @@ export function filterOutLocationComponentFilters( return componentFilters.filter(f => f.type !== ComponentFilterLocation); } +const vscodeFilepath = 'vscode://file/{path}:{line}:{column}'; + +export function getDefaultPreset(): 'custom' | 'vscode' { + return typeof process.env.EDITOR_URL === 'string' ? 'custom' : 'vscode'; +} + export function getDefaultOpenInEditorURL(): string { return typeof process.env.EDITOR_URL === 'string' ? process.env.EDITOR_URL - : ''; + : vscodeFilepath; } export function getOpenInEditorURL(): string { try { + const rawPreset = localStorageGetItem( + LOCAL_STORAGE_OPEN_IN_EDITOR_URL_PRESET, + ); + switch (rawPreset) { + case '"vscode"': + return vscodeFilepath; + } const raw = localStorageGetItem(LOCAL_STORAGE_OPEN_IN_EDITOR_URL); if (raw != null) { return JSON.parse(raw);