UNPKG

5.22 kBTypeScriptView Raw
1import React, { Component } from 'react';
2import {
3 findNodeHandle,
4 MeasureInWindowOnSuccessCallback,
5 MeasureLayoutOnSuccessCallback,
6 MeasureOnSuccessCallback,
7 NativeModules,
8 StyleSheet,
9 ViewStyle,
10} from 'react-native';
11import {
12 ClipProps,
13 Color,
14 extractedProps,
15 FillProps,
16 NumberProp,
17 ResponderInstanceProps,
18 ResponderProps,
19 StrokeProps,
20 TransformProps,
21} from '../lib/extract/types';
22import extractResponder from '../lib/extract/extractResponder';
23import extractViewBox from '../lib/extract/extractViewBox';
24import extractColor from '../lib/extract/extractColor';
25import Shape from './Shape';
26import G from './G';
27import { RNSVGSvg } from './NativeComponents';
28
29const RNSVGSvgViewManager = NativeModules.RNSVGSvgViewManager;
30
31const styles = StyleSheet.create({
32 svg: {
33 backgroundColor: 'transparent',
34 borderWidth: 0,
35 },
36});
37const defaultStyle = styles.svg;
38
39export default class Svg extends Shape<
40 {
41 color?: Color;
42 viewBox?: string;
43 opacity?: NumberProp;
44 onLayout?: () => void;
45 preserveAspectRatio?: string;
46 style?: ViewStyle[] | ViewStyle;
47 } & TransformProps &
48 ResponderProps &
49 StrokeProps &
50 FillProps &
51 ClipProps
52> {
53 static displayName = 'Svg';
54
55 static defaultProps = {
56 preserveAspectRatio: 'xMidYMid meet',
57 };
58
59 measureInWindow = (callback: MeasureInWindowOnSuccessCallback) => {
60 const { root } = this;
61 root && root.measureInWindow(callback);
62 };
63
64 measure = (callback: MeasureOnSuccessCallback) => {
65 const { root } = this;
66 root && root.measure(callback);
67 };
68
69 measureLayout = (
70 relativeToNativeNode: number,
71 onSuccess: MeasureLayoutOnSuccessCallback,
72 onFail: () => void /* currently unused */,
73 ) => {
74 const { root } = this;
75 root && root.measureLayout(relativeToNativeNode, onSuccess, onFail);
76 };
77
78 setNativeProps = (
79 props: Object & {
80 width?: NumberProp;
81 height?: NumberProp;
82 bbWidth?: NumberProp;
83 bbHeight?: NumberProp;
84 },
85 ) => {
86 const { width, height } = props;
87 if (width) {
88 props.bbWidth = width;
89 }
90 if (height) {
91 props.bbHeight = height;
92 }
93 const { root } = this;
94 root && root.setNativeProps(props);
95 };
96
97 toDataURL = (callback: () => void, options?: Object) => {
98 if (!callback) {
99 return;
100 }
101 const handle = findNodeHandle(this.root as Component);
102 RNSVGSvgViewManager.toDataURL(handle, options, callback);
103 };
104
105 render() {
106 const {
107 style,
108 opacity,
109 viewBox,
110 children,
111 onLayout,
112 preserveAspectRatio,
113 ...extracted
114 } = this.props;
115 const stylesAndProps = {
116 ...(Array.isArray(style) ? Object.assign({}, ...style) : style),
117 ...extracted,
118 };
119 let {
120 color,
121 width,
122 height,
123 focusable,
124
125 // Inherited G properties
126 font,
127 transform,
128 fill,
129 fillOpacity,
130 fillRule,
131 stroke,
132 strokeWidth,
133 strokeOpacity,
134 strokeDasharray,
135 strokeDashoffset,
136 strokeLinecap,
137 strokeLinejoin,
138 strokeMiterlimit,
139 } = stylesAndProps;
140 if (width === undefined && height === undefined) {
141 width = height = '100%';
142 }
143
144 const props: extractedProps = extracted as extractedProps;
145 props.focusable = Boolean(focusable) && focusable !== 'false';
146 const rootStyles: (ViewStyle | ViewStyle[])[] = [defaultStyle];
147
148 if (style) {
149 rootStyles.push(style);
150 }
151
152 let override = false;
153 const overrideStyles: ViewStyle = {};
154 const o = opacity != null ? +opacity : NaN;
155 if (!isNaN(o)) {
156 override = true;
157 overrideStyles.opacity = o;
158 }
159
160 if (width && height) {
161 override = true;
162 const w = parseInt(width, 10);
163 const h = parseInt(height, 10);
164 const doNotParseWidth = isNaN(w) || width[width.length - 1] === '%';
165 const doNotParseHeight = isNaN(h) || height[height.length - 1] === '%';
166 overrideStyles.width = doNotParseWidth ? width : w;
167 overrideStyles.height = doNotParseHeight ? height : h;
168 overrideStyles.flex = 0;
169 }
170
171 if (override) {
172 rootStyles.push(overrideStyles);
173 }
174
175 props.style = rootStyles.length > 1 ? rootStyles : defaultStyle;
176
177 if (width != null) {
178 props.bbWidth = width;
179 }
180 if (height != null) {
181 props.bbHeight = height;
182 }
183
184 extractResponder(props, props, this as ResponderInstanceProps);
185
186 const tint = extractColor(color);
187 if (tint != null) {
188 props.color = tint;
189 props.tintColor = tint;
190 }
191
192 if (onLayout != null) {
193 props.onLayout = onLayout;
194 }
195
196 return (
197 <RNSVGSvg
198 {...props}
199 ref={this.refMethod}
200 {...extractViewBox({ viewBox, preserveAspectRatio })}
201 >
202 <G
203 {...{
204 children,
205 style,
206 font,
207 transform,
208 fill,
209 fillOpacity,
210 fillRule,
211 stroke,
212 strokeWidth,
213 strokeOpacity,
214 strokeDasharray,
215 strokeDashoffset,
216 strokeLinecap,
217 strokeLinejoin,
218 strokeMiterlimit,
219 }}
220 />
221 </RNSVGSvg>
222 );
223 }
224}