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