main
js 75 lines 2.62 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @flow
8 */
9
10 import type {ReactFunctionLocation, ReactCallSite} from 'shared/ReactTypes';
11
12 import {useCallback, useContext, useSyncExternalStore} from 'react';
13
14 import ViewElementSourceContext from './Components/ViewElementSourceContext';
15
16 import {getAlwaysOpenInEditor} from '../../utils';
17 import useEditorURL from './useEditorURL';
18 import {LOCAL_STORAGE_ALWAYS_OPEN_IN_EDITOR} from '../../constants';
19
20 import {checkConditions} from './Editor/utils';
21
22 const useOpenResource = (
23 source: null | ReactFunctionLocation | ReactCallSite,
24 symbolicatedSource: null | ReactFunctionLocation | ReactCallSite,
25 ): [
26 boolean, // isEnabled
27 () => void, // Open Resource
28 ] => {
29 const {canViewElementSourceFunction, viewElementSourceFunction} = useContext(
30 ViewElementSourceContext,
31 );
32
33 const editorURL = useEditorURL();
34
35 const alwaysOpenInEditor = useSyncExternalStore(
36 useCallback(function subscribe(callback) {
37 window.addEventListener(LOCAL_STORAGE_ALWAYS_OPEN_IN_EDITOR, callback);
38 return function unsubscribe() {
39 window.removeEventListener(
40 LOCAL_STORAGE_ALWAYS_OPEN_IN_EDITOR,
41 callback,
42 );
43 };
44 }, []),
45 getAlwaysOpenInEditor,
46 );
47
48 // First check if this link is eligible for being open directly in the configured editor.
49 const openInEditor =
50 alwaysOpenInEditor && source !== null
51 ? checkConditions(editorURL, symbolicatedSource || source)
52 : null;
53 // In some cases (e.g. FB internal usage) the standalone shell might not be able to view the source.
54 // To detect this case, we defer to an injected helper function (if present).
55 const linkIsEnabled =
56 (openInEditor !== null && !openInEditor.shouldDisableButton) ||
57 (viewElementSourceFunction != null &&
58 source != null &&
59 (canViewElementSourceFunction == null ||
60 canViewElementSourceFunction(source, symbolicatedSource)));
61
62 const viewSource = useCallback(() => {
63 if (openInEditor !== null && !openInEditor.shouldDisableButton) {
64 // If we have configured to always open in the code editor, we do so if we can.
65 // Otherwise, we fallback to open in the local editor if possible (e.g. non-file urls).
66 window.open(openInEditor.url);
67 } else if (viewElementSourceFunction != null && source != null) {
68 viewElementSourceFunction(source, symbolicatedSource);
69 }
70 }, [openInEditor, source, symbolicatedSource]);
71
72 return [linkIsEnabled, viewSource];
73 };
74
75 export default useOpenResource;