Fix flow types (#18204)

* Added missing @flow pragma to React.js

* Fixed useContext() return type definition

* Fixed previously masked Flow errors in DevTools and react-interactions packages

* Added displayName to internal Context Flow type

* Removed Flow generic annotations for createResponder

This seems to cause a parsing error. (Not sure why.) The API is deprecated anyway so I'm being lazy for now and just adding a .
This commit is contained in:
Brian Vaughn
2020-03-03 12:46:24 -08:00
committed by GitHub
parent 8e6a08ea4f
commit d2158d6ccb
29 changed files with 151 additions and 96 deletions
@@ -14,6 +14,8 @@ import {RegistryContext} from './Contexts';
import styles from './ContextMenu.css';
import type {RegistryContextType} from './Contexts';
function respositionToFit(element: HTMLElement, pageX: number, pageY: number) {
const ownerWindow = element.ownerDocument.defaultView;
if (element !== null) {
@@ -52,7 +54,7 @@ type Props = {|
|};
export default function ContextMenu({children, id}: Props) {
const {registerMenu} = useContext(RegistryContext);
const {registerMenu} = useContext<RegistryContextType>(RegistryContext);
const [state, setState] = useState(HIDDEN_STATE);
@@ -61,12 +63,15 @@ export default function ContextMenu({children, id}: Props) {
const menuRef = useRef(null);
useEffect(() => {
const ownerDocument = bodyAccessorRef.current.ownerDocument;
containerRef.current = ownerDocument.createElement('div');
ownerDocument.body.appendChild(containerRef.current);
return () => {
ownerDocument.body.removeChild(containerRef.current);
};
const element = bodyAccessorRef.current;
if (element !== null) {
const ownerDocument = element.ownerDocument;
containerRef.current = ownerDocument.createElement('div');
ownerDocument.body.appendChild(containerRef.current);
return () => {
ownerDocument.body.removeChild(containerRef.current);
};
}
}, []);
useEffect(() => {
@@ -82,45 +87,52 @@ export default function ContextMenu({children, id}: Props) {
return;
}
const menu = menuRef.current;
const menu = ((menuRef.current: any): HTMLElement);
const container = containerRef.current;
if (container !== null) {
const hideUnlessContains = event => {
if (!menu.contains(event.target)) {
setState(HIDDEN_STATE);
}
};
const hideUnlessContains = event => {
if (!menu.contains(event.target)) {
const hide = event => {
setState(HIDDEN_STATE);
}
};
};
const hide = event => {
setState(HIDDEN_STATE);
};
const ownerDocument = container.ownerDocument;
ownerDocument.addEventListener('mousedown', hideUnlessContains);
ownerDocument.addEventListener('touchstart', hideUnlessContains);
ownerDocument.addEventListener('keydown', hideUnlessContains);
const ownerDocument = containerRef.current.ownerDocument;
ownerDocument.addEventListener('mousedown', hideUnlessContains);
ownerDocument.addEventListener('touchstart', hideUnlessContains);
ownerDocument.addEventListener('keydown', hideUnlessContains);
const ownerWindow = ownerDocument.defaultView;
ownerWindow.addEventListener('resize', hide);
const ownerWindow = ownerDocument.defaultView;
ownerWindow.addEventListener('resize', hide);
respositionToFit(menu, state.pageX, state.pageY);
respositionToFit(menu, state.pageX, state.pageY);
return () => {
ownerDocument.removeEventListener('mousedown', hideUnlessContains);
ownerDocument.removeEventListener('touchstart', hideUnlessContains);
ownerDocument.removeEventListener('keydown', hideUnlessContains);
return () => {
ownerDocument.removeEventListener('mousedown', hideUnlessContains);
ownerDocument.removeEventListener('touchstart', hideUnlessContains);
ownerDocument.removeEventListener('keydown', hideUnlessContains);
ownerWindow.removeEventListener('resize', hide);
};
ownerWindow.removeEventListener('resize', hide);
};
}
}, [state]);
if (!state.isVisible) {
return <div ref={bodyAccessorRef} />;
} else {
return createPortal(
<div ref={menuRef} className={styles.ContextMenu}>
{children(state.data)}
</div>,
containerRef.current,
);
const container = containerRef.current;
if (container !== null) {
return createPortal(
<div ref={menuRef} className={styles.ContextMenu}>
{children(state.data)}
</div>,
container,
);
} else {
return null;
}
}
}
@@ -13,6 +13,8 @@ import {RegistryContext} from './Contexts';
import styles from './ContextMenuItem.css';
import type {RegistryContextType} from './Contexts';
type Props = {|
children: React$Node,
onClick: () => void,
@@ -20,7 +22,7 @@ type Props = {|
|};
export default function ContextMenuItem({children, onClick, title}: Props) {
const {hideMenu} = useContext(RegistryContext);
const {hideMenu} = useContext<RegistryContextType>(RegistryContext);
const handleClick = event => {
onClick();
@@ -55,7 +55,18 @@ function registerMenu(id: string, showFn: ShowFn, hideFn: HideFn) {
};
}
export const RegistryContext = createContext({
export type RegistryContextType = {|
hideMenu: () => void,
showMenu: ({|
data: Object,
id: string,
pageX: number,
pageY: number,
|}) => void,
registerMenu: (string, ShowFn, HideFn) => Function,
|};
export const RegistryContext = createContext<RegistryContextType>({
hideMenu,
showMenu,
registerMenu,
@@ -10,6 +10,7 @@
import {useContext, useEffect} from 'react';
import {RegistryContext} from './Contexts';
import type {RegistryContextType} from './Contexts';
import type {ElementRef} from 'react';
export default function useContextMenu({
@@ -21,7 +22,7 @@ export default function useContextMenu({
id: string,
ref: {current: ElementRef<'div'> | null},
|}) {
const {showMenu} = useContext(RegistryContext);
const {showMenu} = useContext<RegistryContextType>(RegistryContext);
useEffect(() => {
if (ref.current !== null) {
@@ -30,11 +31,11 @@ export default function useContextMenu({
event.stopPropagation();
const pageX =
event.pageX ||
(event.touches && ((event: any): TouchEvent).touches[0].pageX);
(event: any).pageX ||
(event.touches && (event: any).touches[0].pageX);
const pageY =
event.pageY ||
(event.touches && ((event: any): TouchEvent).touches[0].pageY);
(event: any).pageY ||
(event.touches && (event: any).touches[0].pageY);
showMenu({data, id, pageX, pageY});
};
@@ -32,11 +32,30 @@ import {NativeStyleContextController} from './NativeStyleEditor/context';
import styles from './Components.css';
function Components(_: {||}) {
const wrapperElementRef = useRef<HTMLElement>(null);
const resizeElementRef = useRef<HTMLElement>(null);
type Orientation = 'horizontal' | 'vertical';
const [state, dispatch] = useReducer<ResizeState, ResizeAction>(
type ResizeActionType =
| 'ACTION_SET_DID_MOUNT'
| 'ACTION_SET_IS_RESIZING'
| 'ACTION_SET_HORIZONTAL_PERCENTAGE'
| 'ACTION_SET_VERTICAL_PERCENTAGE';
type ResizeAction = {|
type: ResizeActionType,
payload: any,
|};
type ResizeState = {|
horizontalPercentage: number,
isResizing: boolean,
verticalPercentage: number,
|};
function Components(_: {||}) {
const wrapperElementRef = useRef<null | HTMLElement>(null);
const resizeElementRef = useRef<null | HTMLElement>(null);
const [state, dispatch] = useReducer<ResizeState, any, ResizeAction>(
resizeReducer,
null,
initResizeState,
@@ -171,25 +190,6 @@ const LOCAL_STORAGE_KEY = 'React::DevTools::createResizeReducer';
const VERTICAL_MODE_MAX_WIDTH = 600;
const MINIMUM_SIZE = 50;
type Orientation = 'horizontal' | 'vertical';
type ResizeActionType =
| 'ACTION_SET_DID_MOUNT'
| 'ACTION_SET_IS_RESIZING'
| 'ACTION_SET_HORIZONTAL_PERCENTAGE'
| 'ACTION_SET_VERTICAL_PERCENTAGE';
type ResizeAction = {|
type: ResizeActionType,
payload: any,
|};
type ResizeState = {|
horizontalPercentage: number,
isResizing: boolean,
verticalPercentage: number,
|};
function initResizeState(): ResizeState {
let horizontalPercentage = 0.65;
let verticalPercentage = 0.5;
@@ -12,7 +12,7 @@ import {useCallback, useState} from 'react';
import AutoSizeInput from './NativeStyleEditor/AutoSizeInput';
import styles from './EditableName.css';
type OverrideNameFn = (path: Array<string | number>, value: any) => void;
type OverrideNameFn = (name: string, value: any) => void;
type EditableNameProps = {|
autoFocus?: boolean,
@@ -241,7 +241,7 @@ function HookView({canEditHooks, hook, id, inspectPath, path}: HookViewProps) {
} else {
let overrideValueFn = null;
// TODO Maybe read editable value from debug hook?
if (canEditHooks && isStateEditable) {
if (canEditHooks && isStateEditable && hookID !== null) {
overrideValueFn = (
absolutePath: Array<string | number>,
newValue: any,
@@ -51,14 +51,16 @@ export type GetInspectedElement = (
id: number,
) => InspectedElementFrontend | null;
type Context = {|
export type InspectedElementContextType = {|
copyInspectedElementPath: CopyInspectedElementPath,
getInspectedElementPath: GetInspectedElementPath,
getInspectedElement: GetInspectedElement,
storeAsGlobal: StoreAsGlobal,
|};
const InspectedElementContext = createContext<Context>(((null: any): Context));
const InspectedElementContext = createContext<InspectedElementContextType>(
((null: any): InspectedElementContextType),
);
InspectedElementContext.displayName = 'InspectedElementContext';
type ResolveFn = (inspectedElement: InspectedElementFrontend) => void;
@@ -24,6 +24,9 @@ import {
} from 'react-devtools-shared/src/devtools/views/context';
import {TreeStateContext} from '../TreeContext';
import type {StateContext} from '../TreeContext';
import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
import type Store from 'react-devtools-shared/src/devtools/store';
import type {StyleAndLayout as StyleAndLayoutBackend} from 'react-devtools-shared/src/backend/NativeStyleEditor/types';
import type {StyleAndLayout as StyleAndLayoutFrontend} from './types';
import type {Element} from 'react-devtools-shared/src/devtools/views/Components/types';
@@ -77,8 +80,8 @@ type Props = {|
|};
function NativeStyleContextController({children}: Props) {
const bridge = useContext(BridgeContext);
const store = useContext(StoreContext);
const bridge = useContext<FrontendBridge>(BridgeContext);
const store = useContext<Store>(StoreContext);
const getStyleAndLayout = useCallback<GetStyleAndLayout>(
(id: number) => {
@@ -95,7 +98,7 @@ function NativeStyleContextController({children}: Props) {
// It's very important that this context consumes selectedElementID and not NativeStyleID.
// Otherwise the effect that sends the "inspect" message across the bridge-
// would itself be blocked by the same render that suspends (waiting for the data).
const {selectedElementID} = useContext(TreeStateContext);
const {selectedElementID} = useContext<StateContext>(TreeStateContext);
const [
currentStyleAndLayout,
@@ -77,7 +77,7 @@ export default function OwnerStack() {
const {ownerID} = useContext(TreeStateContext);
const treeDispatch = useContext(TreeDispatcherContext);
const [state, dispatch] = useReducer<State, Action>(dialogReducer, {
const [state, dispatch] = useReducer<State, State, Action>(dialogReducer, {
ownerID: null,
owners: [],
selectedIndex: 0,
@@ -37,9 +37,11 @@ import {
import styles from './SelectedElement.css';
import type {ContextMenuContextType} from '../context';
import type {
CopyInspectedElementPath,
GetInspectedElementPath,
InspectedElementContextType,
StoreAsGlobal,
} from './InspectedElementContext';
import type {Element, InspectedElement} from './types';
@@ -62,8 +64,7 @@ export default function SelectedElement(_: Props) {
getInspectedElementPath,
getInspectedElement,
storeAsGlobal,
viewInspectedElementPath,
} = useContext(InspectedElementContext);
} = useContext<InspectedElementContextType>(InspectedElementContext);
const element =
inspectedElementID !== null
@@ -244,7 +245,6 @@ export default function SelectedElement(_: Props) {
getInspectedElementPath={getInspectedElementPath}
inspectedElement={inspectedElement}
storeAsGlobal={storeAsGlobal}
viewInspectedElementPath={viewInspectedElementPath}
/>
)}
</div>
@@ -270,7 +270,6 @@ function InspectedElementView({
getInspectedElementPath,
inspectedElement,
storeAsGlobal,
viewInspectedElementPath,
}: InspectedElementViewProps) {
const {id, type} = element;
const {
@@ -293,7 +292,7 @@ function InspectedElementView({
const {
isEnabledForInspectedElement,
viewAttributeSourceFunction,
} = useContext(ContextMenuContext);
} = useContext<ContextMenuContextType>(ContextMenuContext);
const inspectContextPath = useCallback(
(path: Array<string | number>) => {
@@ -78,7 +78,7 @@ type Props = {|
|};
function ModalDialogContextController({children}: Props) {
const [state, dispatch] = useReducer<State, Action>(dialogReducer, {
const [state, dispatch] = useReducer<State, State, Action>(dialogReducer, {
canBeDismissed: true,
content: null,
isVisible: false,
@@ -96,7 +96,9 @@ type Props = {|
|};
function CommitFlamegraph({chartData, commitTree, height, width}: Props) {
const [hoveredFiberData, hoverFiber] = useState<number | null>(null);
const [hoveredFiberData, hoverFiber] = useState<TooltipFiberData | null>(
null,
);
const {lineHeight} = useContext(SettingsContext);
const {selectFiber, selectedFiberID} = useContext(ProfilerContext);
@@ -94,7 +94,9 @@ type Props = {|
|};
function CommitRanked({chartData, commitTree, height, width}: Props) {
const [hoveredFiberData, hoverFiber] = useState<number | null>(null);
const [hoveredFiberData, hoverFiber] = useState<TooltipFiberData | null>(
null,
);
const {lineHeight} = useContext(SettingsContext);
const {selectedFiberID, selectFiber} = useContext(ProfilerContext);
@@ -124,7 +124,10 @@ function ProfilerContextController({children}: Props) {
supportsProfiling,
} = useSubscription<StoreProfilingState>(subscription);
const [prevProfilingData, setPrevProfilingData] = useState();
const [
prevProfilingData,
setPrevProfilingData,
] = useState<ProfilingDataFrontend | null>(null);
const [rootID, setRootID] = useState<number | null>(null);
if (prevProfilingData !== profilingData) {
@@ -39,7 +39,9 @@ export default function ProfilingImportExportButtons() {
return;
}
if (profilingData !== null && downloadRef.current !== null) {
const anchorElement = downloadRef.current;
if (profilingData !== null && anchorElement !== null) {
const profilingDataExport = prepareProfilingDataExport(profilingData);
const date = new Date();
const dateString = date
@@ -55,7 +57,7 @@ export default function ProfilingImportExportButtons() {
})
.replace(/:/g, '-');
downloadFile(
downloadRef.current,
anchorElement,
`profiling-data.${dateString}.${timeString}.json`,
JSON.stringify(profilingDataExport, null, 2),
);
@@ -23,7 +23,7 @@ StoreContext.displayName = 'StoreContext';
export type ContextMenuContextType = {|
isEnabledForInspectedElement: boolean,
viewAttributeSourceFunction?: ?ViewAttributeSource,
viewAttributeSourceFunction: ViewAttributeSource | null,
|};
export const ContextMenuContext = createContext<ContextMenuContextType>({
+2 -1
View File
@@ -78,6 +78,7 @@ export function useEditableValue(
externalValue: any,
): [UseEditableValueState, UseEditableValueDispatch] {
const [state, dispatch] = useReducer<
UseEditableValueState,
UseEditableValueState,
UseEditableValueAction,
>(useEditableValueReducer, {
@@ -158,7 +159,7 @@ export function useLocalStorage<T>(
}
}, [initialValue, key]);
const [storedValue, setStoredValue] = useState(getValueFromLocalStorage);
const [storedValue, setStoredValue] = useState<any>(getValueFromLocalStorage);
const setValue = useCallback(
value => {
@@ -128,7 +128,7 @@ function SuspenseListTest() {
}
function LoadLater() {
const [loadChild, setLoadChild] = useState(0);
const [loadChild, setLoadChild] = useState(false);
return (
<Suspense
fallback={
+2 -1
View File
@@ -113,6 +113,7 @@ const contextMenuImpl = {
},
};
// $FlowFixMe Can't add generic types without causing a parsing/syntax errors
export const ContextMenuResponder = React.DEPRECATED_createResponder(
'ContextMenu',
contextMenuImpl,
@@ -120,6 +121,6 @@ export const ContextMenuResponder = React.DEPRECATED_createResponder(
export function useContextMenu(
props: ContextMenuProps,
): ReactEventResponderListener<any, any> {
): ?ReactEventResponderListener<any, any> {
return React.DEPRECATED_useResponder(ContextMenuResponder, props);
}
+4 -2
View File
@@ -494,6 +494,7 @@ const focusResponderImpl = {
},
};
// $FlowFixMe Can't add generic types without causing a parsing/syntax errors
export const FocusResponder = React.DEPRECATED_createResponder(
'Focus',
focusResponderImpl,
@@ -501,7 +502,7 @@ export const FocusResponder = React.DEPRECATED_createResponder(
export function useFocus(
props: FocusProps,
): ReactEventResponderListener<any, any> {
): ?ReactEventResponderListener<any, any> {
return React.DEPRECATED_useResponder(FocusResponder, props);
}
@@ -680,6 +681,7 @@ const focusWithinResponderImpl = {
},
};
// $FlowFixMe Can't add generic types without causing a parsing/syntax errors
export const FocusWithinResponder = React.DEPRECATED_createResponder(
'FocusWithin',
focusWithinResponderImpl,
@@ -687,6 +689,6 @@ export const FocusWithinResponder = React.DEPRECATED_createResponder(
export function useFocusWithin(
props: FocusWithinProps,
): ReactEventResponderListener<any, any> {
): ?ReactEventResponderListener<any, any> {
return React.DEPRECATED_useResponder(FocusWithinResponder, props);
}
+2 -1
View File
@@ -378,6 +378,7 @@ const hoverResponderFallbackImpl = {
onUnmount: unmountResponder,
};
// $FlowFixMe Can't add generic types without causing a parsing/syntax errors
export const HoverResponder = React.DEPRECATED_createResponder(
'Hover',
hasPointerEvents ? hoverResponderImpl : hoverResponderFallbackImpl,
@@ -385,6 +386,6 @@ export const HoverResponder = React.DEPRECATED_createResponder(
export function useHover(
props: HoverProps,
): ReactEventResponderListener<any, any> {
): ?ReactEventResponderListener<any, any> {
return React.DEPRECATED_useResponder(HoverResponder, props);
}
+2 -1
View File
@@ -212,6 +212,7 @@ const inputResponderImpl = {
},
};
// $FlowFixMe Can't add generic types without causing a parsing/syntax errors
export const InputResponder = React.DEPRECATED_createResponder(
'Input',
inputResponderImpl,
@@ -219,6 +220,6 @@ export const InputResponder = React.DEPRECATED_createResponder(
export function useInput(
props: InputResponderProps,
): ReactEventResponderListener<any, any> {
): ?ReactEventResponderListener<any, any> {
return React.DEPRECATED_useResponder(InputResponder, props);
}
+2 -1
View File
@@ -229,6 +229,7 @@ const keyboardResponderImpl = {
},
};
// $FlowFixMe Can't add generic types without causing a parsing/syntax errors
export const KeyboardResponder = React.DEPRECATED_createResponder(
'Keyboard',
keyboardResponderImpl,
@@ -236,6 +237,6 @@ export const KeyboardResponder = React.DEPRECATED_createResponder(
export function useKeyboard(
props: KeyboardProps,
): ReactEventResponderListener<any, any> {
): ?ReactEventResponderListener<any, any> {
return React.DEPRECATED_useResponder(KeyboardResponder, props);
}
+2 -1
View File
@@ -903,6 +903,7 @@ const pressResponderImpl = {
},
};
// $FlowFixMe Can't add generic types without causing a parsing/syntax errors
export const PressResponder = React.DEPRECATED_createResponder(
'Press',
pressResponderImpl,
@@ -910,6 +911,6 @@ export const PressResponder = React.DEPRECATED_createResponder(
export function usePress(
props: PressProps,
): ReactEventResponderListener<any, any> {
): ?ReactEventResponderListener<any, any> {
return React.DEPRECATED_useResponder(PressResponder, props);
}
+4 -1
View File
@@ -721,11 +721,14 @@ const responderImpl = {
},
};
// $FlowFixMe Can't add generic types without causing a parsing/syntax errors
export const TapResponder = React.DEPRECATED_createResponder(
'Tap',
responderImpl,
);
export function useTap(props: TapProps): ReactEventResponderListener<any, any> {
export function useTap(
props: TapProps,
): ?ReactEventResponderListener<any, any> {
return React.DEPRECATED_useResponder(TapResponder, props);
}
+2
View File
@@ -3,6 +3,8 @@
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import ReactVersion from 'shared/ReactVersion';
+1 -1
View File
@@ -37,7 +37,7 @@ function resolveDispatcher() {
export function useContext<T>(
Context: ReactContext<T>,
unstable_observedBits: number | boolean | void,
) {
): T {
const dispatcher = resolveDispatcher();
if (__DEV__) {
if (unstable_observedBits !== undefined) {
+3
View File
@@ -66,6 +66,9 @@ export type ReactContext<T> = {
// DEV only
_currentRenderer?: Object | null,
_currentRenderer2?: Object | null,
// This value may be added by application code
// to improve DEV tooling display names
displayName?: string,
...
};