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