diff --git a/ARKit.js b/ARKit.js index 6d85c689..3981e347 100644 --- a/ARKit.js +++ b/ARKit.js @@ -13,7 +13,7 @@ import { View, Text, NativeModules, - requireNativeComponent, + requireNativeComponent } from 'react-native'; import generateId from './components/lib/generateId'; @@ -26,7 +26,7 @@ const TRACKING_REASONS = [ 'NONE', 'INITIALIZING', 'EXCESSIVE_MOTION', - 'INSUFFICIENT_FEATURES', + 'INSUFFICIENT_FEATURES' ]; const TRACKING_STATES_COLOR = ['red', 'orange', 'green']; @@ -34,7 +34,7 @@ class ARKit extends Component { state = { state: 0, reason: 0, - floor: null, + floor: null }; componentWillMount() { ARKitManager.clearScene(); @@ -55,7 +55,7 @@ class ARKit extends Component { @@ -84,13 +84,13 @@ class ARKit extends Component { _onTrackingState = ({ state = this.state.state, reason = this.state.reason, - floor, + floor }) => { if (this.props.onTrackingState) { this.props.onTrackingState({ state: TRACKING_STATES[state] || state, reason: TRACKING_REASONS[reason] || reason, - floor, + floor }); } @@ -98,7 +98,7 @@ class ARKit extends Component { this.setState({ state, reason, - floor: floor ? floor.toFixed(2) : this.state.floor, + floor: floor ? floor.toFixed(2) : this.state.floor }); } }; @@ -138,19 +138,19 @@ const styles = StyleSheet.create({ borderRadius: 10, padding: 4, backgroundColor: 'black', - flexDirection: 'row', + flexDirection: 'row' }, stateIcon: { width: 12, height: 12, borderRadius: 6, - marginRight: 4, + marginRight: 4 }, stateText: { color: 'white', fontSize: 10, - height: 12, - }, + height: 12 + } }); // copy all ARKitManager properties to ARKit @@ -160,7 +160,7 @@ Object.keys(ARKitManager).forEach(key => { const addDefaultsToSnapShotFunc = funcName => ({ target = 'cameraRoll', - format = 'png', + format = 'png' }) => ARKitManager[funcName]({ target, format }); ARKit.snapshot = addDefaultsToSnapShotFunc('snapshot'); @@ -182,7 +182,7 @@ ARKit.propTypes = { onTrackingState: PropTypes.func, onTapOnPlaneUsingExtent: PropTypes.func, onTapOnPlaneNoExtent: PropTypes.func, - onEvent: PropTypes.func, + onEvent: PropTypes.func }; const RCTARKit = requireNativeComponent('RCTARKit', ARKit); diff --git a/README.md b/README.md index 726bfaa1..ed1866f1 100644 --- a/README.md +++ b/README.md @@ -23,15 +23,18 @@ There is a Slack group that anyone can join for help / support / general questio `$ react-native link react-native-arkit` +! Currently automatic installation does not work as PocketSVG is missing. Follow the manual installation + ### Manual installation #### iOS 1. In XCode, in the project navigator, right click `Libraries` ➜ `Add Files to [your project's name]` -2. Go to `node_modules` ➜ `react-native-arkit` and add `RCTARKit.xcodeproj` -3. In XCode, in the project navigator, select your project. Add `libRCTARKit.a` to your project's `Build Phases` ➜ `Link Binary With Libraries` -4. Run your project (`Cmd+R`)< +2. Go to `node_modules` ➜ add `react-native-arkit/RCTARKit.xcodeproj` and `_PocketSVG/_PocketSVG.xcodeproj` +3. In XCode, in the project navigator, select your project. Add `libRCTARKit.a` `and PocketSVG.framework` to your project's `Build Phases` ➜ `Link Binary With Libraries` +4. In Tab `General` ➜ `Embedded Binaries` ➜ `+` ➜ Add `PocketSVG.framework ios` +5. Run your project (`Cmd+R`)< ## Usage @@ -100,11 +103,32 @@ export default class ReactNativeARKit extends Component { /> + + + `, + pathFlatness: 0.1, + // it's also possible to specify a chamfer profile: + chamferRadius: 5, + chamferProfilePathSvg: ` + + `, + extrusion: 10, + }} + /> ); @@ -273,6 +297,20 @@ SceneKit only supports `.scn` and `.dae` formats. | `eulerAngles` | `{ x, y, z }` | | `model` | `{ file, node, scale, alpha }` | +#### `` + +Creates a extruded shape by an svg path. +See https://github.com/HippoAR/react-native-arkit/pull/89 for details + +##### Props + +| Prop | Type | +|---|---| +| `position` | `{ x, y, z }` | +| `eulerAngles` | `{ x, y, z }` | +| `shape` | `{ pathSvg, extrusion, pathFlatness, chamferRadius, chamferProfilePathSvg, chamferProfilePathFlatness }` | + + ## Contributing diff --git a/components/ARShape.js b/components/ARShape.js new file mode 100644 index 00000000..4cf6cfd7 --- /dev/null +++ b/components/ARShape.js @@ -0,0 +1,18 @@ +import PropTypes from 'prop-types'; + +import { chamferMode } from './lib/propTypes'; +import createArComponent from './lib/createArComponent'; + +const ARShape = createArComponent('addShape', { + shape: PropTypes.shape({ + extrusion: PropTypes.number, + pathSvg: PropTypes.string, + pathFlatness: PropTypes.number, + chamferMode, + chamferRadius: PropTypes.number, + chamferProfilePathSvg: PropTypes.string, + chamferProfilePathFlatness: PropTypes.string + }) +}); + +module.exports = ARShape; diff --git a/components/ARSprite.js b/components/ARSprite.js index f44022af..0052f365 100644 --- a/components/ARSprite.js +++ b/components/ARSprite.js @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import withAnimationFrame from 'react-animation-frame'; +import withAnimationFrame from '@panter/react-animation-frame'; import { NativeModules, Animated } from 'react-native'; @@ -13,7 +13,7 @@ const ARSprite = withAnimationFrame( super(props); this.state = { zIndex: new Animated.Value(), - pos2D: new Animated.ValueXY(), // inits to zero + pos2D: new Animated.ValueXY() // inits to zero }; } onAnimationFrame() { @@ -22,9 +22,9 @@ const ARSprite = withAnimationFrame( { x: this.state.pos2D.x, y: this.state.pos2D.y, - z: this.state.zIndex, - }, - ]), + z: this.state.zIndex + } + ]) ); } @@ -34,18 +34,18 @@ const ARSprite = withAnimationFrame( style={{ position: 'absolute', transform: this.state.pos2D.getTranslateTransform(), - ...this.props.style, + ...this.props.style }} > {this.props.children} ); } - }, + } ); ARSprite.propTypes = { - position, + position }; module.exports = ARSprite; diff --git a/components/lib/createArComponent.js b/components/lib/createArComponent.js index f48ecd78..df09ebe1 100644 --- a/components/lib/createArComponent.js +++ b/components/lib/createArComponent.js @@ -15,7 +15,7 @@ import { orientation, position, rotation, - transition, + transition } from './propTypes'; import { processColorInMaterial } from './parseColor'; import generateId from './generateId'; @@ -25,14 +25,15 @@ const NODE_PROPS = [ 'position', 'eulerAngles', 'rotation', + 'scale', 'orientation', - 'transition', + 'transition' ]; const KEYS_THAT_NEED_REMOUNT = ['material', 'shape', 'model']; const nodeProps = (id, props) => ({ id, - ...pick(props, NODE_PROPS), + ...pick(props, NODE_PROPS) }); export default (mountConfig, propTypes = {}) => { @@ -40,11 +41,11 @@ export default (mountConfig, propTypes = {}) => { typeof mountConfig === 'string' ? { shape: props.shape, - material: processColorInMaterial(props.material), + material: processColorInMaterial(props.material) } : { ...pick(props, mountConfig.pick), - material: processColorInMaterial(props.material), + material: processColorInMaterial(props.material) }; const mountFunc = @@ -56,7 +57,7 @@ export default (mountConfig, propTypes = {}) => { mountFunc( getShapeAndMaterialProps(props), nodeProps(id, props), - props.frame, + props.frame ); }; @@ -71,7 +72,7 @@ export default (mountConfig, propTypes = {}) => { componentWillUpdate(props) { const changedKeys = filter( keys(this.props), - key => !isDeepEqual(props[key], this.props[key]), + key => !isDeepEqual(props[key], this.props[key]) ); if (isEmpty(changedKeys)) { @@ -87,7 +88,7 @@ export default (mountConfig, propTypes = {}) => { // always include transition ARGeosManager.update( this.identifier, - pick(props, ['transition', ...changedKeys]), + pick(props, ['transition', ...changedKeys]) ); } } @@ -108,7 +109,7 @@ export default (mountConfig, propTypes = {}) => { rotation, orientation, material, - ...propTypes, + ...propTypes }; return ARComponent; diff --git a/components/lib/propTypes.js b/components/lib/propTypes.js index 97a48d45..db9d52f8 100644 --- a/components/lib/propTypes.js +++ b/components/lib/propTypes.js @@ -8,43 +8,44 @@ const ARKitManager = NativeModules.ARKitManager; export const position = PropTypes.shape({ x: PropTypes.number, y: PropTypes.number, - z: PropTypes.number, + z: PropTypes.number }); export const transition = PropTypes.shape({ - duration: PropTypes.number, + duration: PropTypes.number }); export const eulerAngles = PropTypes.shape({ x: PropTypes.number, y: PropTypes.number, - z: PropTypes.number, + z: PropTypes.number }); export const rotation = PropTypes.shape({ x: PropTypes.number, y: PropTypes.number, z: PropTypes.number, - w: PropTypes.number, + w: PropTypes.number }); export const orientation = PropTypes.shape({ x: PropTypes.number, y: PropTypes.number, z: PropTypes.number, - w: PropTypes.number, + w: PropTypes.number }); export const shaders = PropTypes.shape({ [ARKitManager.ShaderModifierEntryPoint.Geometry]: PropTypes.string, [ARKitManager.ShaderModifierEntryPoint.Surface]: PropTypes.string, [ARKitManager.ShaderModifierEntryPoint.LightingModel]: PropTypes.string, - [ARKitManager.ShaderModifierEntryPoint.Fragment]: PropTypes.string, + [ARKitManager.ShaderModifierEntryPoint.Fragment]: PropTypes.string }); export const lightingModel = PropTypes.oneOf( - values(ARKitManager.LightingModel), + values(ARKitManager.LightingModel) ); export const blendMode = PropTypes.oneOf(values(ARKitManager.BlendMode)); +export const chamferMode = PropTypes.oneOf(values(ARKitManager.ChamferMode)); export const material = PropTypes.shape({ color: PropTypes.string, @@ -52,5 +53,5 @@ export const material = PropTypes.shape({ roughness: PropTypes.number, blendMode, lightingModel, - shaders, + shaders }); diff --git a/index.js b/index.js index d54139eb..e832bb32 100644 --- a/index.js +++ b/index.js @@ -21,6 +21,7 @@ import ARText from './components/ARText'; import ARModel from './components/ARModel'; import ARSprite from './components/ARSprite'; import ARGroup from './components/ARGroup'; +import ARShape from './components/ARShape'; ARKit.Box = ARBox; ARKit.Sphere = ARSphere; @@ -35,6 +36,7 @@ ARKit.Text = ARText; ARKit.Model = ARModel; ARKit.Sprite = ARSprite; ARKit.Group = ARGroup; +ARKit.Shape = ARShape; module.exports = { ARKit, @@ -50,5 +52,5 @@ module.exports = { ARPlane, ARText, ARModel, - ARGroup, + ARGroup }; diff --git a/ios/RCTARKit.m b/ios/RCTARKit.m index 8d6b2b60..9abc35bf 100644 --- a/ios/RCTARKit.m +++ b/ios/RCTARKit.m @@ -435,26 +435,28 @@ - (void)session:(ARSession *)session didUpdateFrame:(ARFrame *)frame { } } if (self.onFeaturesDetected) { + NSMutableArray * featurePoints = [NSMutableArray array]; + for (int i = 0; i < frame.rawFeaturePoints.count; i++) { + vector_float3 point = frame.rawFeaturePoints.points[i]; + + NSString * pointId = [NSString stringWithFormat:@"featurepoint_%lld",frame.rawFeaturePoints.identifiers[i]]; + + [featurePoints addObject:@{ + @"x": @(point[0]), + @"y": @(point[1]), + @"z": @(point[2]), + @"id":pointId, + }]; + + } dispatch_async(dispatch_get_main_queue(), ^{ - NSMutableArray * featurePoints = [NSMutableArray array]; - for (int i = 0; i < frame.rawFeaturePoints.count; i++) { - vector_float3 point = frame.rawFeaturePoints.points[i]; - - NSString * pointId = [NSString stringWithFormat:@"featurepoint_%lld",frame.rawFeaturePoints.identifiers[i]]; - - [featurePoints addObject:@{ - @"x": @(point[0]), - @"y": @(point[1]), - @"z": @(point[2]), - @"id":pointId, - }]; - - } - self.onFeaturesDetected(@{ - @"featurePoints":featurePoints - }); + if(self.onFeaturesDetected) { + self.onFeaturesDetected(@{ + @"featurePoints":featurePoints + }); + } }); } } diff --git a/ios/RCTARKit.xcodeproj/project.pbxproj b/ios/RCTARKit.xcodeproj/project.pbxproj index aa4ab109..b180ffd6 100644 --- a/ios/RCTARKit.xcodeproj/project.pbxproj +++ b/ios/RCTARKit.xcodeproj/project.pbxproj @@ -29,6 +29,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + B14C363A1F9504D70047CB67 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -52,6 +61,8 @@ 10FEF6121F774C9000EC21AE /* RCTARKitNodes.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTARKitNodes.m; sourceTree = ""; }; 10FEF6131F774C9000EC21AE /* RCTARKitDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTARKitDelegate.h; sourceTree = ""; }; 134814201AA4EA6300B7C361 /* libRCTARKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTARKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; + B14C36631F960C500047CB67 /* PocketSVG.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PocketSVG.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B14C36651F960C6E0047CB67 /* PocketSVG.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PocketSVG.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B3E7B5881CC2AC0600A0062D /* RCTARKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTARKit.h; sourceTree = ""; }; B3E7B5891CC2AC0600A0062D /* RCTARKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTARKit.m; sourceTree = ""; }; /* End PBXFileReference section */ @@ -108,7 +119,17 @@ 105F124C1F7C0718006D4BA3 /* RCTConvert+ARKit.h */, 105F124D1F7C0718006D4BA3 /* RCTConvert+ARKit.m */, 134814211AA4EA7D00B7C361 /* Products */, + B13FF7601F94F72400A6C92B /* Frameworks */, + ); + sourceTree = ""; + }; + B13FF7601F94F72400A6C92B /* Frameworks */ = { + isa = PBXGroup; + children = ( + B14C36651F960C6E0047CB67 /* PocketSVG.framework */, + B14C36631F960C500047CB67 /* PocketSVG.framework */, ); + name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ @@ -121,6 +142,7 @@ 58B511D71A9E6C8500147676 /* Sources */, 58B511D81A9E6C8500147676 /* Frameworks */, 58B511D91A9E6C8500147676 /* CopyFiles */, + B14C363A1F9504D70047CB67 /* CopyFiles */, ); buildRules = ( ); @@ -269,6 +291,7 @@ "$(SRCROOT)/../../react-native-arcl/ios", ../../../ios/Pods/Headers/Public/, ../../../ios/Pods/Headers/Public/React, + "$(SRCROOT)/../../_PocketSVG/**", ); IPHONEOS_DEPLOYMENT_TARGET = 11.0; LIBRARY_SEARCH_PATHS = "$(inherited)"; @@ -290,6 +313,7 @@ "$(SRCROOT)/../../react-native-arcl/ios", ../../../ios/Pods/Headers/Public/, ../../../ios/Pods/Headers/Public/React, + "$(SRCROOT)/../../_PocketSVG/**", ); IPHONEOS_DEPLOYMENT_TARGET = 11.0; LIBRARY_SEARCH_PATHS = "$(inherited)"; diff --git a/ios/RCTARKitManager.m b/ios/RCTARKitManager.m index 5c220214..585e5fd1 100644 --- a/ios/RCTARKitManager.m +++ b/ios/RCTARKitManager.m @@ -51,6 +51,12 @@ - (NSDictionary *)constantsToExport @"Screen": [@(SCNBlendModeScreen) stringValue], @"Replace": [@(SCNBlendModeReplace) stringValue], + }, + @"ChamferMode": @{ + @"Both": [@(SCNChamferModeBoth) stringValue], + @"Back": [@(SCNChamferModeBack) stringValue], + @"Front": [@(SCNChamferModeBack) stringValue], + } }; } diff --git a/ios/RCTConvert+ARKit.h b/ios/RCTConvert+ARKit.h index 0576ed06..7a122ce0 100644 --- a/ios/RCTConvert+ARKit.h +++ b/ios/RCTConvert+ARKit.h @@ -31,6 +31,7 @@ + (SCNTorus *)SCNTorus:(id)json; + (SCNCapsule *)SCNCapsule:(id)json; + (SCNPlane *)SCNPlane:(id)json; ++ (SCNShape * )SCNShape:(id)json; + (SCNTextNode *)SCNTextNode:(id)json; diff --git a/ios/RCTConvert+ARKit.m b/ios/RCTConvert+ARKit.m index 91a22c24..ecc263ea 100644 --- a/ios/RCTConvert+ARKit.m +++ b/ios/RCTConvert+ARKit.m @@ -7,6 +7,7 @@ // #import "RCTConvert+ARKit.h" +#import "SVGBezierPath.h" @implementation RCTConvert (ARKit) @@ -37,10 +38,10 @@ + (SCNVector4)SCNVector4:(id)json { + (SCNNode *)SCNNode:(id)json { SCNNode *node = [SCNNode new]; - + node.name = [NSString stringWithFormat:@"%@", json[@"id"]]; [self setNodeProperties:node properties:json]; - + return node; } @@ -51,10 +52,9 @@ + (SCNBox *)SCNBox:(id)json { CGFloat length = [shape[@"length"] floatValue]; CGFloat chamfer = [shape[@"chamfer"] floatValue]; SCNBox *geometry = [SCNBox boxWithWidth:width height:height length:length chamferRadius:chamfer]; - SCNMaterial *material = [self SCNMaterial:json[@"material"]]; geometry.materials = @[material, material, material, material, material, material]; - + return geometry; } @@ -65,7 +65,7 @@ + (SCNSphere *)SCNSphere:(id)json { SCNMaterial *material = [self SCNMaterial:json[@"material"]]; geometry.materials = @[material]; - + return geometry; } @@ -131,7 +131,7 @@ + (SCNTorus *)SCNTorus:(id)json { return geometry; } - + + (SCNCapsule *)SCNCapsule:(id)json { NSDictionary* shape = json[@"shape"]; CGFloat capR = [shape[@"capR"] floatValue]; @@ -167,6 +167,67 @@ + (SCNPlane *)SCNPlane:(id)json { return geometry; } ++ (SVGBezierPath *)svgStringToBezier:(NSString *)pathString { + NSArray * paths = [SVGBezierPath pathsFromSVGString:pathString]; + SVGBezierPath * fullPath; + for(SVGBezierPath *path in paths) { + if(!fullPath) { + fullPath = path; + } else { + [fullPath appendPath:path]; + } + } + return fullPath; +} + ++ (SCNShape * )SCNShape:(id)json { + NSDictionary* shape = json[@"shape"]; + NSString * pathString = shape[@"pathSvg"]; + + SVGBezierPath * path = [self svgStringToBezier:pathString]; + + if (shape[@"pathFlatness"]) { + path.flatness = [shape[@"pathFlatness"] floatValue]; + } + CGFloat extrusion = [shape[@"extrusion"] floatValue]; + SCNShape *geometry = [SCNShape shapeWithPath:path extrusionDepth:extrusion]; + if (shape[@"chamferMode"]) { + geometry.chamferMode = (SCNChamferMode) [shape[@"chamferMode"] integerValue]; + } + if (shape[@"chamferRadius"]) { + geometry.chamferRadius = [shape[@"chamferRadius"] floatValue]; + } + + if (shape[@"chamferProfilePathSvg"]) { + + SVGBezierPath * path = [self svgStringToBezier:shape[@"chamferProfilePathSvg"]]; + if(shape[@"chamferProfilePathFlatness"]) { + path.flatness = [shape[@"chamferProfilePathFlatness"] floatValue]; + } + // normalize path + CGRect boundingBox = path.bounds; + if(path.bounds.size.width !=0 && path.bounds.size.height != 0) { + CGFloat scaleX = 1/boundingBox.size.width; + CGFloat scaleY = scaleY = 1/boundingBox.size.height; + + CGAffineTransform transform = CGAffineTransformMakeScale(scaleX, scaleY); + [path applyTransform:transform]; + geometry.chamferProfile = path; + } else { + NSLog(@"Invalid chamferProfilePathFlatness"); + } + + } + + + + SCNMaterial *material = [self SCNMaterial:json[@"material"]]; + material.doubleSided = YES; + + geometry.materials = @[material]; + return geometry; +} + + (SCNTextNode *)SCNTextNode:(id)json { // init SCNText @@ -183,7 +244,7 @@ + (SCNTextNode *)SCNTextNode:(id)json { CGFloat fontSize = [font[@"size"] floatValue]; CGFloat size = fontSize / 12; SCNText *scnText = [SCNText textWithString:text extrusionDepth:depth / size]; - + scnText.flatness = 0.1; // font @@ -215,7 +276,7 @@ + (SCNTextNode *)SCNTextNode:(id)json { SCNVector3 min = SCNVector3Zero; SCNVector3 max = SCNVector3Zero; [textNode getBoundingBoxMin:&min max:&max]; - + textNode.position = SCNVector3Make(-(min.x + max.x) / 2 * size, -(min.y + max.y) / 2 * size, -(min.z + max.z) / 2 * size); @@ -257,7 +318,7 @@ + (void)setNodeProperties:(SCNNode *)node properties:(id)json { } else { [SCNTransaction setAnimationDuration:0.0]; } - + } else { [SCNTransaction setAnimationDuration:0.0]; } @@ -265,6 +326,12 @@ + (void)setNodeProperties:(SCNNode *)node properties:(id)json { node.position = [self SCNVector3:json[@"position"]]; } + if (json[@"scale"]) { + CGFloat scale = [json[@"scale"] floatValue]; + node.scale = SCNVector3Make(scale, scale, scale); + + } + if (json[@"eulerAngles"]) { node.eulerAngles = [self SCNVector3:json[@"eulerAngles"]]; } diff --git a/ios/components/ARGeosManager.m b/ios/components/ARGeosManager.m index 754cc4b8..1157f35b 100644 --- a/ios/components/ARGeosManager.m +++ b/ios/components/ARGeosManager.m @@ -58,6 +58,11 @@ @implementation ARGeosManager [[RCTARKitNodes sharedInstance] addNodeToScene:node inReferenceFrame:frame]; } +RCT_EXPORT_METHOD(addShape:(SCNShape *)geometry node:(SCNNode *)node frame:(NSString *)frame) { + node.geometry = geometry; + [[RCTARKitNodes sharedInstance] addNodeToScene:node inReferenceFrame:frame]; +} + RCT_EXPORT_METHOD(unmount:(NSString *)identifier) { [[RCTARKitNodes sharedInstance] removeNodeForKey:identifier]; } diff --git a/package.json b/package.json index a9bb2cf5..67b4f1e5 100644 --- a/package.json +++ b/package.json @@ -15,11 +15,12 @@ "test": "echo \"Error: no test specified\" && exit 1" }, "dependencies": { + "_PocketSVG": "https://github.com/pocketsvg/PocketSVG", "fast-deep-equal": "^1.0.0", "lodash": "^4.17.4", "prop-types": "^15.5.7", "react": "16.0.0-alpha.12", - "react-animation-frame": "^0.3.5" + "@panter/react-animation-frame": "^0.3.6" }, "devDependencies": { "babel-eslint": "^7.2.3", diff --git a/yarn.lock b/yarn.lock index 3655f102..30fd06b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,10 @@ # yarn lockfile v1 +"_PocketSVG@https://github.com/pocketsvg/PocketSVG": + version "0.0.0" + resolved "https://github.com/pocketsvg/PocketSVG#e6d84ddeb11f99c4420e354ebb9fd34db2cf507a" + acorn-jsx@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"