diff --git a/package-lock.json b/package-lock.json index a85076a976b9..d2e72920113a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -189,6 +189,7 @@ "@types/react-collapse": "^5.0.1", "@types/react-dom": "^18.2.4", "@types/react-is": "^18.3.0", + "@types/react-native-web": "^0.0.0", "@types/react-test-renderer": "^18.0.0", "@types/semver": "^7.5.4", "@types/setimmediate": "^1.0.2", @@ -17851,6 +17852,16 @@ "react-native": "*" } }, + "node_modules/@types/react-native-web": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/@types/react-native-web/-/react-native-web-0.0.0.tgz", + "integrity": "sha512-WeaDnb57Z60pUVu6FO6WybA+7BAbPz83otLVbOpcPvRN2f/PIDt/9ViiXJ989QFrLhdex/Jen15xMOyO2X2L2A==", + "dev": true, + "dependencies": { + "@types/react": "*", + "react-native": "*" + } + }, "node_modules/@types/react-redux": { "version": "7.1.27", "license": "MIT", diff --git a/package.json b/package.json index 4d0974d8fe70..39f1a8a9d2ac 100644 --- a/package.json +++ b/package.json @@ -245,6 +245,7 @@ "@types/react-collapse": "^5.0.1", "@types/react-dom": "^18.2.4", "@types/react-is": "^18.3.0", + "@types/react-native-web": "^0.0.0", "@types/react-test-renderer": "^18.0.0", "@types/semver": "^7.5.4", "@types/setimmediate": "^1.0.2", diff --git a/src/components/BlockingViews/BlockingView.tsx b/src/components/BlockingViews/BlockingView.tsx index f6096e3b55e8..f4e1b992437f 100644 --- a/src/components/BlockingViews/BlockingView.tsx +++ b/src/components/BlockingViews/BlockingView.tsx @@ -1,8 +1,9 @@ import type {ImageContentFit} from 'expo-image'; import React, {useMemo} from 'react'; -import type {ImageSourcePropType, StyleProp, TextStyle, ViewStyle, WebStyle} from 'react-native'; +import type {ImageSourcePropType, StyleProp, TextStyle, ViewStyle} from 'react-native'; import {View} from 'react-native'; import type {SvgProps} from 'react-native-svg'; +import type {WebStyle} from 'react-native-web'; import type {MergeExclusive} from 'type-fest'; import AutoEmailLink from '@components/AutoEmailLink'; import Icon from '@components/Icon'; diff --git a/src/components/Composer/index.tsx b/src/components/Composer/index.tsx index 306319f061ca..a7189dbe88c7 100755 --- a/src/components/Composer/index.tsx +++ b/src/components/Composer/index.tsx @@ -4,7 +4,7 @@ import type {BaseSyntheticEvent, ForwardedRef} from 'react'; import React, {useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; import {flushSync} from 'react-dom'; // eslint-disable-next-line no-restricted-imports -import type {DimensionValue, NativeSyntheticEvent, Text as RNText, TextInput, TextInputKeyPressEventData, TextInputSelectionChangeEventData, TextStyle} from 'react-native'; +import type {NativeSyntheticEvent, Text as RNText, TextInput, TextInputKeyPressEventData, TextInputSelectionChangeEventData, ViewStyle} from 'react-native'; import {DeviceEventEmitter, StyleSheet, View} from 'react-native'; import type {AnimatedMarkdownTextInputRef} from '@components/RNMarkdownTextInput'; import RNMarkdownTextInput from '@components/RNMarkdownTextInput'; @@ -100,7 +100,7 @@ function Composer( }); const [caretContent, setCaretContent] = useState(''); const [valueBeforeCaret, setValueBeforeCaret] = useState(''); - const [textInputWidth, setTextInputWidth] = useState(''); + const [textInputWidth, setTextInputWidth] = useState(''); const [isRendered, setIsRendered] = useState(false); const isScrollBarVisible = useIsScrollBarVisible(textInput, value ?? ''); const [prevScroll, setPrevScroll] = useState(); @@ -352,7 +352,7 @@ function Composer( opacity: 0, }} > - + {`${valueBeforeCaret} `} ; + /** * A component used to wrap an element intended for displaying a tooltip. * This tooltip would show immediately without user's interaction and hide after 5 seconds. @@ -45,7 +47,7 @@ function BaseEducationalTooltip({children, shouldAutoDismiss = false, ...props}: // eslint-disable-next-line react-compiler/react-compiler hideTooltipRef.current = hideTooltip; return React.cloneElement(children as React.ReactElement, { - onLayout: (e: LayoutChangeEvent) => { + onLayout: (e: LayoutChangeEventWithTarget) => { // e.target is specific to native, use e.nativeEvent.target on web instead const target = e.target || e.nativeEvent.target; // When tooltip is used inside an animated view (e.g. popover), we need to wait for the animation to finish before measuring content. diff --git a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts index 8beb0e696d91..e09f85936385 100644 --- a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts +++ b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts @@ -1,5 +1,4 @@ import type {StackCardInterpolationProps, StackNavigationOptions} from '@react-navigation/stack'; -import type {ViewStyle} from 'react-native'; import type {ThemeStyles} from '@styles/index'; import type {StyleUtilsType} from '@styles/utils'; import variables from '@styles/variables'; @@ -61,8 +60,7 @@ const getRootNavigatorScreenOptions: GetRootNavigatorScreenOptions = (isSmallScr width: '100%', top: 0, left: 0, - // We need to guarantee that it covers BottomTabBar on web, but fixed position is not supported in react native. - position: 'fixed' as ViewStyle['position'], + position: 'fixed', }, }), leftModalNavigator: { diff --git a/src/styles/utils/display.ts b/src/styles/utils/display.ts index 82b8c87b0980..0f0166e135c9 100644 --- a/src/styles/utils/display.ts +++ b/src/styles/utils/display.ts @@ -23,31 +23,27 @@ export default { * Web-only style. */ dInline: { - // NOTE: asserting "display" to a valid type, because it isn't possible to augment "display". - display: 'inline' as ViewStyle['display'], + display: 'inline', }, /** * Web-only style. */ dInlineFlex: { - // NOTE: asserting "display" to a valid type, because it isn't possible to augment "display". - display: 'inline-flex' as ViewStyle['display'], + display: 'inline-flex', }, /** * Web-only style. */ dBlock: { - // NOTE: asserting "display" to a valid type, because it isn't possible to augment "display". - display: 'block' as ViewStyle['display'], + display: 'block', }, /** * Web-only style. */ dGrid: { - // NOTE: asserting "display" to a valid type, because it isn't possible to augment "display". - display: 'grid' as ViewStyle['display'], + display: 'grid', }, } satisfies Record; diff --git a/src/styles/utils/generators/ReportActionContextMenuStyleUtils.ts b/src/styles/utils/generators/ReportActionContextMenuStyleUtils.ts index b3f3a816d09a..1894f95a44c1 100644 --- a/src/styles/utils/generators/ReportActionContextMenuStyleUtils.ts +++ b/src/styles/utils/generators/ReportActionContextMenuStyleUtils.ts @@ -20,8 +20,7 @@ const getMiniWrapperStyle = (theme: ThemeColors, styles: ThemeStyles): ViewStyle borderWidth: 1, borderColor: theme.border, // In Safari, when welcome messages use a code block (triple backticks), they would overlap the context menu below when there is no scrollbar without the transform style. - // NOTE: asserting "transform" to a valid type, because it isn't possible to augment "transform". - transform: 'translateZ(0)' as unknown as ViewStyle['transform'], + transform: 'translateZ(0)', }, ]; diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts index ed76abd484d0..56dd9a583c9a 100644 --- a/src/styles/utils/index.ts +++ b/src/styles/utils/index.ts @@ -1,5 +1,5 @@ import {StyleSheet} from 'react-native'; -import type {AnimatableNumericValue, Animated, ColorValue, DimensionValue, ImageStyle, PressableStateCallbackType, StyleProp, TextStyle, ViewStyle} from 'react-native'; +import type {AnimatableNumericValue, Animated, ColorValue, ImageStyle, PressableStateCallbackType, StyleProp, TextStyle, ViewStyle} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import type {EdgeInsets} from 'react-native-safe-area-context'; import type {ValueOf} from 'type-fest'; @@ -342,7 +342,6 @@ function getSafeAreaMargins(insets?: EdgeInsets): ViewStyle { return {marginBottom: (insets?.bottom ?? 0) * variables.safeInsertPercentage}; } -// NOTE: asserting some web style properties to a valid type, because it isn't possible to augment them. function getZoomSizingStyle( isZoomed: boolean, imgWidth: number, @@ -356,23 +355,23 @@ function getZoomSizingStyle( if (isLoading || imgWidth === 0 || imgHeight === 0) { return undefined; } - const top = `${Math.max((containerHeight - imgHeight) / 2, 0)}px` as DimensionValue; - const left = `${Math.max((containerWidth - imgWidth) / 2, 0)}px` as DimensionValue; + const top = `${Math.max((containerHeight - imgHeight) / 2, 0)}px`; + const left = `${Math.max((containerWidth - imgWidth) / 2, 0)}px`; // Return different size and offset style based on zoomScale and isZoom. if (isZoomed) { // When both width and height are smaller than container(modal) size, set the height by multiplying zoomScale if it is zoomed in. if (zoomScale >= 1) { return { - height: `${imgHeight * zoomScale}px` as DimensionValue, - width: `${imgWidth * zoomScale}px` as DimensionValue, + height: `${imgHeight * zoomScale}px`, + width: `${imgWidth * zoomScale}px`, }; } // If image height and width are bigger than container size, display image with original size because original size is bigger and position absolute. return { - height: `${imgHeight}px` as DimensionValue, - width: `${imgWidth}px` as DimensionValue, + height: `${imgHeight}px`, + width: `${imgWidth}px`, top, left, }; @@ -381,8 +380,8 @@ function getZoomSizingStyle( // If image is not zoomed in and image size is smaller than container size, display with original size based on offset and position absolute. if (zoomScale > 1) { return { - height: `${imgHeight}px` as DimensionValue, - width: `${imgWidth}px` as DimensionValue, + height: `${imgHeight}px`, + width: `${imgWidth}px`, top, left, }; @@ -390,11 +389,11 @@ function getZoomSizingStyle( // If image is bigger than container size, display full image in the screen with scaled size (fit by container size) and position absolute. // top, left offset should be different when displaying long or wide image. - const scaledTop = `${Math.max((containerHeight - imgHeight * zoomScale) / 2, 0)}px` as DimensionValue; - const scaledLeft = `${Math.max((containerWidth - imgWidth * zoomScale) / 2, 0)}px` as DimensionValue; + const scaledTop = `${Math.max((containerHeight - imgHeight * zoomScale) / 2, 0)}px`; + const scaledLeft = `${Math.max((containerWidth - imgWidth * zoomScale) / 2, 0)}px`; return { - height: `${imgHeight * zoomScale}px` as DimensionValue, - width: `${imgWidth * zoomScale}px` as DimensionValue, + height: `${imgHeight * zoomScale}px`, + width: `${imgWidth * zoomScale}px`, top: scaledTop, left: scaledLeft, }; @@ -538,6 +537,8 @@ function getButtonStyleWithIcon( } } +type MarginPaddingValue = ViewStyle['marginTop' | 'marginBottom' | 'paddingTop' | 'paddingBottom']; + /** * Combine margin/padding with safe area inset * @@ -545,10 +546,14 @@ function getButtonStyleWithIcon( * @param safeAreaValue - safe area inset * @param shouldAddSafeAreaValue - indicator whether safe area inset should be applied */ -function getCombinedSpacing(modalContainerValue: DimensionValue | undefined, safeAreaValue: number, shouldAddSafeAreaValue: boolean): number | DimensionValue | undefined { +function getCombinedSpacing(modalContainerValue: MarginPaddingValue, safeAreaValue: number, shouldAddSafeAreaValue: boolean): MarginPaddingValue { // modalContainerValue can only be added to safe area inset if it's a number, otherwise it's returned as is - if (typeof modalContainerValue === 'number' || !modalContainerValue) { - return (modalContainerValue ?? 0) + (shouldAddSafeAreaValue ? safeAreaValue : 0); + if (typeof modalContainerValue === 'number') { + return modalContainerValue + (shouldAddSafeAreaValue ? safeAreaValue : 0); + } + + if (!modalContainerValue) { + return shouldAddSafeAreaValue ? safeAreaValue : 0; } return modalContainerValue; @@ -563,10 +568,10 @@ type ModalPaddingStylesParams = { safeAreaPaddingBottom: number; safeAreaPaddingLeft: number; safeAreaPaddingRight: number; - modalContainerStyleMarginTop: DimensionValue | undefined; - modalContainerStyleMarginBottom: DimensionValue | undefined; - modalContainerStylePaddingTop: DimensionValue | undefined; - modalContainerStylePaddingBottom: DimensionValue | undefined; + modalContainerStyleMarginTop: MarginPaddingValue; + modalContainerStyleMarginBottom: MarginPaddingValue; + modalContainerStylePaddingTop: MarginPaddingValue; + modalContainerStylePaddingBottom: MarginPaddingValue; insets: EdgeInsets; }; @@ -964,8 +969,7 @@ function getCheckboxPressableStyle(borderRadius = 6): ViewStyle { return { justifyContent: 'center', alignItems: 'center', - // eslint-disable-next-line object-shorthand - borderRadius: borderRadius, + borderRadius, }; } @@ -1311,8 +1315,7 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({ borderWidth: 2, justifyContent: 'center', alignItems: 'center', - // eslint-disable-next-line object-shorthand - borderRadius: borderRadius, + borderRadius, }), /** @@ -1338,13 +1341,13 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({ /** * Get the style for the AM and PM buttons in the TimePicker */ - getStatusAMandPMButtonStyle: (amPmValue: string): {styleForAM: ViewStyle; styleForPM: ViewStyle} => { + getStatusAMandPMButtonStyle: (amPmValue: string): {styleForAM: StyleProp; styleForPM: StyleProp} => { const computedStyleForAM: ViewStyle = amPmValue !== CONST.TIME_PERIOD.AM ? {backgroundColor: theme.componentBG} : {}; const computedStyleForPM: ViewStyle = amPmValue !== CONST.TIME_PERIOD.PM ? {backgroundColor: theme.componentBG} : {}; return { - styleForAM: [styles.timePickerWidth100, computedStyleForAM] as unknown as ViewStyle, - styleForPM: [styles.timePickerWidth100, computedStyleForPM] as unknown as ViewStyle, + styleForAM: [styles.timePickerWidth100, computedStyleForAM], + styleForPM: [styles.timePickerWidth100, computedStyleForPM], }; }, diff --git a/src/styles/utils/overflowAuto/index.ts b/src/styles/utils/overflowAuto/index.ts index 670a0b9643eb..db55b65b8949 100644 --- a/src/styles/utils/overflowAuto/index.ts +++ b/src/styles/utils/overflowAuto/index.ts @@ -1,12 +1,10 @@ -import type {ViewStyle} from 'react-native'; import type OverflowAutoStyles from './types'; /** * Web-only style. */ const overflowAuto: OverflowAutoStyles = { - // NOTE: asserting "overflow" to a valid type, because it isn't possible to augment "overflow". - overflow: 'auto' as ViewStyle['overflow'], + overflow: 'auto', }; export default overflowAuto; diff --git a/src/styles/utils/positioning.ts b/src/styles/utils/positioning.ts index cbfa8875b9ad..c4affba653ac 100644 --- a/src/styles/utils/positioning.ts +++ b/src/styles/utils/positioning.ts @@ -15,8 +15,7 @@ export default { * Web-only style. */ pFixed: { - // NOTE: asserting "position" to a valid type, because it isn't possible to augment "position". - position: 'fixed' as ViewStyle['position'], + position: 'fixed', }, t0: { diff --git a/src/types/modules/react-native-web.d.ts b/src/types/modules/react-native-web.d.ts deleted file mode 100644 index f7db951eadad..000000000000 --- a/src/types/modules/react-native-web.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* eslint-disable import/prefer-default-export */ -/* eslint-disable @typescript-eslint/consistent-type-definitions */ -declare module 'react-native-web' { - class Clipboard { - static isAvailable(): boolean; - static getString(): Promise; - static setString(text: string): boolean; - } - - export {Clipboard}; -} diff --git a/src/types/modules/react-native.d.ts b/src/types/modules/react-native.d.ts index 87628fded0cc..44ac6c243aa8 100644 --- a/src/types/modules/react-native.d.ts +++ b/src/types/modules/react-native.d.ts @@ -1,12 +1,5 @@ -/* eslint-disable @typescript-eslint/naming-convention */ - -/* eslint-disable @typescript-eslint/no-empty-interface */ - /* eslint-disable @typescript-eslint/consistent-type-definitions */ -// eslint-disable-next-line no-restricted-imports -import type {CSSProperties, FocusEventHandler, KeyboardEventHandler, MouseEventHandler, PointerEventHandler, TouchEventHandler, UIEventHandler, WheelEventHandler} from 'react'; -import 'react-native'; -import type {GestureResponderEvent, LayoutRectangle, NativeSyntheticEvent, TargetedEvent} from 'react-native'; +import type {TargetedEvent} from 'react-native'; import type {BootSplashModule} from '@libs/BootSplash/types'; import type {EnvironmentCheckerModule} from '@libs/Environment/betaChecker/types'; import type StartupTimer from '@libs/StartupTimer/types'; @@ -22,360 +15,6 @@ type RNTextInputResetModule = { }; declare module 'react-native' { - // <------ REACT NATIVE WEB (0.19.12) ------> - // Extracted from react-native-web, packages/react-native-web/src/exports/View/types.js - type idRef = string; - type idRefList = idRef | idRef[]; - - // https://necolas.github.io/react-native-web/docs/accessibility/#accessibility-props-api - // Extracted from react-native-web, packages/react-native-web/src/exports/View/types.js - interface AccessibilityProps { - 'aria-activedescendant'?: idRef; - 'aria-atomic'?: boolean; - 'aria-autocomplete'?: 'none' | 'list' | 'inline' | 'both'; - 'aria-busy'?: boolean; - 'aria-checked'?: boolean | 'mixed'; - 'aria-colcount'?: number; - 'aria-colindex'?: number; - 'aria-colspan'?: number; - 'aria-controls'?: idRef; - 'aria-current'?: boolean | 'page' | 'step' | 'location' | 'date' | 'time'; - 'aria-describedby'?: idRef; - 'aria-details'?: idRef; - 'aria-disabled'?: boolean; - 'aria-errormessage'?: idRef; - 'aria-expanded'?: boolean; - 'aria-flowto'?: idRef; - 'aria-haspopup'?: 'dialog' | 'grid' | 'listbox' | 'menu' | 'tree' | false; - 'aria-hidden'?: boolean; - 'aria-invalid'?: boolean; - 'aria-keyshortcuts'?: string; - 'aria-label'?: string; - 'aria-labelledby'?: idRef; - 'aria-level'?: number; - 'aria-live'?: 'assertive' | 'off' | 'polite'; - 'aria-modal'?: boolean; - 'aria-multiline'?: boolean; - 'aria-multiselectable'?: boolean; - 'aria-orientation'?: 'horizontal' | 'vertical'; - 'aria-owns'?: idRef; - 'aria-placeholder'?: string; - 'aria-posinset'?: number; - 'aria-pressed'?: boolean | 'mixed'; - 'aria-readonly'?: boolean; - 'aria-required'?: boolean; - 'aria-roledescription'?: string; - 'aria-rowcount'?: number; - 'aria-rowindex'?: number; - 'aria-rowspan'?: number; - 'aria-selected'?: boolean; - 'aria-setsize'?: number; - 'aria-sort'?: 'ascending' | 'descending' | 'none' | 'other'; - 'aria-valuemax'?: number; - 'aria-valuemin'?: number; - 'aria-valuenow'?: number; - 'aria-valuetext'?: string; - - // @deprecated - accessibilityActiveDescendant?: idRef; - accessibilityAtomic?: boolean; - accessibilityAutoComplete?: 'none' | 'list' | 'inline' | 'both'; - accessibilityBusy?: boolean; - accessibilityChecked?: boolean | 'mixed'; - accessibilityColumnCount?: number; - accessibilityColumnIndex?: number; - accessibilityColumnSpan?: number; - accessibilityControls?: idRefList; - accessibilityCurrent?: boolean | 'page' | 'step' | 'location' | 'date' | 'time'; - accessibilityDescribedBy?: idRefList; - accessibilityDetails?: idRef; - accessibilityDisabled?: boolean; - accessibilityErrorMessage?: idRef; - accessibilityExpanded?: boolean; - accessibilityFlowTo?: idRefList; - accessibilityHasPopup?: 'dialog' | 'grid' | 'listbox' | 'menu' | 'tree' | false; - accessibilityHidden?: boolean; - accessibilityInvalid?: boolean; - accessibilityKeyShortcuts?: string[]; - accessibilityLabel?: string; - accessibilityLabelledBy?: idRef; - accessibilityLevel?: number; - accessibilityLiveRegion?: 'assertive' | 'none' | 'polite'; - accessibilityModal?: boolean; - accessibilityMultiline?: boolean; - accessibilityMultiSelectable?: boolean; - accessibilityOrientation?: 'horizontal' | 'vertical'; - accessibilityOwns?: idRefList; - accessibilityPlaceholder?: string; - accessibilityPosInSet?: number; - accessibilityPressed?: boolean | 'mixed'; - accessibilityReadOnly?: boolean; - accessibilityRequired?: boolean; - accessibilityRoleDescription?: string; - accessibilityRowCount?: number; - accessibilityRowIndex?: number; - accessibilityRowSpan?: number; - accessibilitySelected?: boolean; - accessibilitySetSize?: number; - accessibilitySort?: 'ascending' | 'descending' | 'none' | 'other'; - accessibilityValueMax?: number; - accessibilityValueMin?: number; - accessibilityValueNow?: number; - accessibilityValueText?: string; - } - - // https://necolas.github.io/react-native-web/docs/interactions/#pointerevent-props-api - // Extracted properties from react-native-web, packages/react-native-web/src/exports/View/types.js and packages/react-native-web/src/modules/forwardedProps/index.js - // Extracted types from @types/react, index.d.ts - interface ClickProps { - onClick?: MouseEventHandler; - onAuxClick?: MouseEventHandler; - onContextMenu?: MouseEventHandler; - onGotPointerCapture?: PointerEventHandler; - onLostPointerCapture?: PointerEventHandler; - onPointerCancel?: PointerEventHandler; - onPointerDown?: PointerEventHandler; - onPointerEnter?: PointerEventHandler; - onPointerMove?: PointerEventHandler; - onPointerLeave?: PointerEventHandler; - onPointerOut?: PointerEventHandler; - onPointerOver?: PointerEventHandler; - onPointerUp?: PointerEventHandler; - onScroll?: UIEventHandler; - onWheel?: WheelEventHandler; - } - - // https://necolas.github.io/react-native-web/docs/interactions/#focusevent-props-api - // Extracted properties from react-native-web, packages/react-native-web/src/exports/View/types.js and packages/react-native-web/src/modules/forwardedProps/index.js - // Extracted types from @types/react, index.d.ts - interface FocusProps { - onBlur?: FocusEventHandler; - onFocus?: FocusEventHandler; - } - - // https://necolas.github.io/react-native-web/docs/interactions/#keyboardevent-props-api - // Extracted properties from react-native-web, packages/react-native-web/src/exports/View/types.js and packages/react-native-web/src/modules/forwardedProps/index.js - // Extracted types from @types/react, index.d.ts - interface KeyboardProps { - onKeyDown?: KeyboardEventHandler; - onKeyDownCapture?: KeyboardEventHandler; - onKeyUp?: KeyboardEventHandler; - onKeyUpCapture?: KeyboardEventHandler; - } - - // Extracted properties from react-native-web, packages/react-native-web/src/exports/View/types.js and packages/react-native-web/src/modules/forwardedProps/index.js - // Extracted types from @types/react, index.d.ts - interface MouseProps { - onMouseDown?: MouseEventHandler; - onMouseEnter?: MouseEventHandler; - onMouseLeave?: MouseEventHandler; - onMouseMove?: MouseEventHandler; - onMouseOver?: MouseEventHandler; - onMouseOut?: MouseEventHandler; - onMouseUp?: MouseEventHandler; - } - - // Extracted properties from react-native-web, packages/react-native-web/src/exports/View/types.js and packages/react-native-web/src/modules/forwardedProps/index.js - // Extracted types from @types/react, index.d.ts - interface TouchProps { - onTouchCancel?: TouchEventHandler; - onTouchCancelCapture?: TouchEventHandler; - onTouchEnd?: TouchEventHandler; - onTouchEndCapture?: TouchEventHandler; - onTouchMove?: TouchEventHandler; - onTouchMoveCapture?: TouchEventHandler; - onTouchStart?: TouchEventHandler; - onTouchStartCapture?: TouchEventHandler; - } - - // https://necolas.github.io/react-native-web/docs/interactions/#responderevent-props-api - // Extracted from react-native-web, packages/react-native-web/src/modules/useResponderEvents/ResponderTouchHistoryStore.js - type TouchRecord = { - currentPageX: number; - currentPageY: number; - currentTimeStamp: number; - previousPageX: number; - previousPageY: number; - previousTimeStamp: number; - startPageX: number; - startPageY: number; - startTimeStamp: number; - touchActive: boolean; - }; - - // https://necolas.github.io/react-native-web/docs/interactions/#responderevent-props-api - // Extracted from react-native-web, packages/react-native-web/src/modules/useResponderEvents/ResponderTouchHistoryStore.js - type TouchHistory = Readonly<{ - indexOfSingleActiveTouch: number; - mostRecentTimeStamp: number; - numberActiveTouches: number; - touchBank: TouchRecord[]; - }>; - - // https://necolas.github.io/react-native-web/docs/interactions/#responderevent-props-api - // Extracted from react-native-web, packages/react-native-web/src/modules/useResponderEvents/createResponderEvent.js - type ResponderEvent = { - bubbles: boolean; - cancelable: boolean; - currentTarget?: unknown; // changed from "any" to "unknown" - defaultPrevented?: boolean; - dispatchConfig: { - registrationName?: string; - phasedRegistrationNames?: { - bubbled: string; - captured: string; - }; - }; - eventPhase?: number; - isDefaultPrevented: () => boolean; - isPropagationStopped: () => boolean; - isTrusted?: boolean; - preventDefault: () => void; - stopPropagation: () => void; - nativeEvent: TouchEvent; - persist: () => void; - target?: unknown; // changed from "any" to "unknown" - timeStamp: number; - touchHistory: TouchHistory; - }; - - // https://necolas.github.io/react-native-web/docs/interactions/#responderevent-props-api - // Extracted from react-native-web, packages/react-native-web/src/modules/useResponderEvents/ResponderSystem.js - interface ResponderProps { - // Direct responder events dispatched directly to responder. Do not bubble. - onResponderEnd?: (e: ResponderEvent) => void; - onResponderGrant?: (e: ResponderEvent) => void | boolean; - onResponderMove?: (e: ResponderEvent) => void; - onResponderRelease?: (e: ResponderEvent) => void; - onResponderReject?: (e: ResponderEvent) => void; - onResponderStart?: (e: ResponderEvent) => void; - onResponderTerminate?: (e: ResponderEvent) => void; - onResponderTerminationRequest?: (e: ResponderEvent) => boolean; - - // On pointer down, should this element become the responder? - onStartShouldSetResponder?: (e: ResponderEvent) => boolean; - onStartShouldSetResponderCapture?: (e: ResponderEvent) => boolean; - - // On pointer move, should this element become the responder? - onMoveShouldSetResponder?: (e: ResponderEvent) => boolean; - onMoveShouldSetResponderCapture?: (e: ResponderEvent) => boolean; - - // On scroll, should this element become the responder? Do no bubble - onScrollShouldSetResponder?: (e: ResponderEvent) => boolean; - onScrollShouldSetResponderCapture?: (e: ResponderEvent) => boolean; - - // On text selection change, should this element become the responder? - onSelectionChangeShouldSetResponder?: (e: ResponderEvent) => boolean; - onSelectionChangeShouldSetResponderCapture?: (e: ResponderEvent) => boolean; - } - - // @ts-expect-error We override this type in order to provide "target" to onLayout event. - type LayoutChangeEvent = NativeSyntheticEvent<{layout: LayoutRectangle; target?: unknown}>; - - interface EventProps extends ClickProps, FocusProps, KeyboardProps, MouseProps, TouchProps, ResponderProps {} - - /** - * Shared props - * Extracted from react-native-web, packages/react-native-web/src/exports/View/types.js - */ - interface WebSharedProps extends AccessibilityProps, EventProps { - dataSet?: Record; - href?: string; - hrefAttrs?: { - download?: boolean; - rel?: string; - target?: string; - }; - tabIndex?: 0 | -1; - lang?: string; - } - - /** - * View - * Extracted from react-native-web, packages/react-native-web/src/exports/View/types.js - */ - interface WebViewProps extends WebSharedProps { - dir?: 'ltr' | 'rtl'; - } - interface ViewProps extends WebViewProps {} - - /** - * Text - * Extracted from react-native-web, packages/react-native-web/src/exports/Text/types.js - */ - interface WebTextProps extends WebSharedProps { - dir?: 'auto' | 'ltr' | 'rtl'; - } - interface TextProps extends WebTextProps {} - - /** - * TextInput - * Extracted from react-native-web, packages/react-native-web/src/exports/TextInput/types.js - */ - interface WebTextInputProps extends WebSharedProps { - dir?: 'auto' | 'ltr' | 'rtl'; - disabled?: boolean; - } - interface TextInputProps extends WebTextInputProps {} - - /** - * Image - * Extracted from react-native-web, packages/react-native-web/src/exports/Image/types.js - */ - interface WebImageProps extends WebSharedProps { - dir?: 'ltr' | 'rtl'; - draggable?: boolean; - } - interface ImageProps extends WebImageProps {} - - /** - * ScrollView - * Extracted from react-native-web, packages/react-native-web/src/exports/ScrollView/ScrollViewBase.js - */ - interface WebScrollViewProps extends WebSharedProps {} - interface ScrollViewProps extends WebScrollViewProps {} - - /** - * Pressable - */ - // https://necolas.github.io/react-native-web/docs/pressable/#interactionstate - // Extracted from react-native-web, packages/react-native-web/src/exports/Pressable/index.js - interface WebPressableStateCallbackType { - readonly focused: boolean; - readonly hovered: boolean; - readonly pressed: boolean; - } - interface PressableStateCallbackType extends WebPressableStateCallbackType {} - - // Extracted from react-native-web, packages/react-native-web/src/exports/Pressable/index.js - interface WebPressableProps extends WebSharedProps { - /** Duration (in milliseconds) from `onPressStart` is called after pointerdown. */ - delayPressIn?: number; - /** Duration (in milliseconds) from `onPressEnd` is called after pointerup. */ - delayPressOut?: number; - /** Called when a touch is moving, after `onPressIn`. */ - onPressMove?: (event: GestureResponderEvent) => void; - } - interface PressableProps extends WebPressableProps {} - - /** - * Styles - */ - // We extend CSSProperties (alias to "csstype" library) which provides all CSS style properties for Web, - // but properties that are already defined on RN won't be overrided / augmented. - interface WebStyle extends CSSProperties { - // https://necolas.github.io/react-native-web/docs/styling/#non-standard-properties - // Exclusive to react-native-web, "pointerEvents" already included on RN - animationKeyframes?: string | Record; - writingDirection?: 'auto' | 'ltr' | 'rtl'; - enableBackground?: string; - } - - interface ViewStyle extends WebStyle {} - interface TextStyle extends WebStyle {} - interface ImageStyle extends WebStyle {} - // <------ REACT NATIVE WEB (0.19.12) ------> - interface TextInputFocusEventData extends TargetedEvent { text: string; eventCount: number; @@ -408,6 +47,7 @@ declare module 'react-native' { namespace Animated { interface AnimatedInterpolation extends AnimatedWithChildren { interpolate(config: InterpolationConfigType): AnimatedInterpolation; + // eslint-disable-next-line @typescript-eslint/naming-convention __getValue: () => OutputT; } } diff --git a/tsconfig.json b/tsconfig.json index c0a588f47a64..572d16798b1e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ "extends": "expo/tsconfig.base", "compilerOptions": { "module": "commonjs", - "types": ["react-native", "jest"], + "types": ["react-native", "react-native-web", "jest"], "lib": ["DOM", "DOM.Iterable", "ESNext"], "isolatedModules": true, "strict": true,