1/**
2 * Copyright (c) Expo.
3 * Copyright (c) Nicolas Gallagher.
4 * Copyright (c) Facebook, Inc. and its affiliates.
5 *
6 * This source code is licensed under the MIT license found in the
7 * LICENSE file in the root directory of this source tree.
8 */
9import * as React from 'react';
10import StyleSheet from 'react-native-web/dist/exports/StyleSheet';
11import TextAncestorContext from 'react-native-web/dist/exports/Text/TextAncestorContext';
12import createElement from 'react-native-web/dist/exports/createElement';
13import * as forwardedProps from 'react-native-web/dist/modules/forwardedProps';
14import pick from 'react-native-web/dist/modules/pick';
15import useElementLayout from 'react-native-web/dist/modules/useElementLayout';
16import useMergeRefs from 'react-native-web/dist/modules/useMergeRefs';
17import usePlatformMethods from 'react-native-web/dist/modules/usePlatformMethods';
18import useResponderEvents from 'react-native-web/dist/modules/useResponderEvents';
19import { PlatformMethods, ViewProps } from 'react-native-web/dist/types';
20
21const forwardPropsList = {
22  ...forwardedProps.defaultProps,
23  ...forwardedProps.accessibilityProps,
24  ...forwardedProps.clickProps,
25  ...forwardedProps.focusProps,
26  ...forwardedProps.keyboardProps,
27  ...forwardedProps.mouseProps,
28  ...forwardedProps.touchProps,
29  ...forwardedProps.styleProps,
30  lang: true,
31  onScroll: true,
32  onWheel: true,
33  pointerEvents: true,
34};
35
36const pickProps = (props) => pick(props, forwardPropsList);
37
38/**
39 * This is the View from react-native-web copied out in order to supply a custom `__element` property.
40 * In the past, you could use `createElement` to create an element with a custom HTML element, but this changed
41 * somewhere between 0.14...0.17.
42 */
43
44// @ts-ignore
45const View: React.AbstractComponent<ViewProps, HTMLElement & PlatformMethods> = React.forwardRef(
46  (props, forwardedRef) => {
47    const {
48      onLayout,
49      onMoveShouldSetResponder,
50      onMoveShouldSetResponderCapture,
51      onResponderEnd,
52      onResponderGrant,
53      onResponderMove,
54      onResponderReject,
55      onResponderRelease,
56      onResponderStart,
57      onResponderTerminate,
58      onResponderTerminationRequest,
59      onScrollShouldSetResponder,
60      onScrollShouldSetResponderCapture,
61      onSelectionChangeShouldSetResponder,
62      onSelectionChangeShouldSetResponderCapture,
63      onStartShouldSetResponder,
64      onStartShouldSetResponderCapture,
65      __element,
66    } = props as any;
67
68    const hasTextAncestor = React.useContext(TextAncestorContext);
69    const hostRef = React.useRef(null);
70
71    useElementLayout(hostRef, onLayout);
72    useResponderEvents(hostRef, {
73      onMoveShouldSetResponder,
74      onMoveShouldSetResponderCapture,
75      onResponderEnd,
76      onResponderGrant,
77      onResponderMove,
78      onResponderReject,
79      onResponderRelease,
80      onResponderStart,
81      onResponderTerminate,
82      onResponderTerminationRequest,
83      onScrollShouldSetResponder,
84      onScrollShouldSetResponderCapture,
85      onSelectionChangeShouldSetResponder,
86      onSelectionChangeShouldSetResponderCapture,
87      onStartShouldSetResponder,
88      onStartShouldSetResponderCapture,
89    });
90
91    const style = StyleSheet.compose(
92      hasTextAncestor && styles.inline,
93      // @ts-ignore: untyped
94      props.style
95    );
96
97    const supportedProps = pickProps(props);
98    supportedProps.style = style;
99
100    const platformMethodsRef = usePlatformMethods(supportedProps);
101    const setRef = useMergeRefs(hostRef, platformMethodsRef, forwardedRef);
102
103    supportedProps.ref = setRef;
104
105    return createElement(__element, supportedProps);
106  }
107);
108
109View.displayName = 'View';
110
111const styles = StyleSheet.create({
112  view: {
113    alignItems: 'stretch',
114    border: '0 solid black',
115    boxSizing: 'border-box',
116    display: 'flex',
117    flexBasis: 'auto',
118    flexDirection: 'column',
119    flexShrink: 0,
120    margin: 0,
121    minHeight: 0,
122    minWidth: 0,
123    padding: 0,
124    position: 'relative',
125    zIndex: 0,
126  },
127  inline: {
128    display: 'inline-flex',
129  },
130});
131
132export default View;
133