SyrSDK API

This API guide is morphing over time. Please check back often, and feel free to update from the Syr repo and send a PR if you notice something that isn't right.

Components

A Component

SyrSDK uses the familiar React JavaScript pattern for creating components. The basic component setup looks like this.

import { Component } from 'syr';

class MyComponent extends Component {
  constructor() {
  }
  render() {
  }
}

View

A View component is the basic component that renders to a surface (the RootView). This component can be rendered to a SyrRootView.

import { View } from 'syr';

render(){
  return <View></View>
}

It can also own components, that will render to the surface as a child. Such as another View.

import { View } from 'syr';

render(){
  return <View>
      <View></View>
  </View>
}

Because a View does not have any dimensions by default, it will render at X,Y:0,0 and Height,Width:0,0. To change this you can attach a style.

import { View } from 'syr';

render(){
  return <View style={{
    height: 100,
    width: 100,
    left: 50,
    top: 50
  }}></View>
}

Animated.View

An animated view lets the bridge know about any special conditions that need to be setup ahead of time for the animation. Currently this stub exists for Syntax compatibility. In SyrSDK any component that is derived from an animatable is, able to have an animation applied. UIView, Button, Image.

import { Animated } from 'syr';

render(){
  return <Animated.View></Animated.View>
}

TextView

A text view MUST OWN text. We're following this rule from React Native and sticking with it. Text that is not inside a TextView node, will become a value property on nodes that own them. So if you need Text that displays, then you need to ensure it's wrapped inside a TextView

import { TextView } from 'syr';

render(){
  return <TextView></TextView>
}

Image

A component for displaying an Image. It is self terminated as it can not hold any children.

import { Image } from 'syr';

render(){
  return <Image source={{uri:"file_name"}} style={{ height:150, width:300 }}/>
}

Button

A clickable component. Returns an onPress event.

import { Button } from 'syr';

render(){
  return <Button onPress={this.onPress} style={{ height:150, width:300 }}>Press Me</Button>
}
onPress(){
  // the button was pressed!
}

LinearGradient

A View that has a linear gradient applied to the background.

import { LinearGradient } from 'syr';

render() {
  return <LinearGradient colors={['#000000', '#FFFFFF']} style={{ height:150, width:300 }}/>
}

TouchableOpacity

An invisible clickable view. Use it to encapsulate components for which you want to receive a click handler.

import { TouchableOpacity, Image } from 'syr';

render() {
  return <TouchableOpacity onPress={()=>this.handleBackPress()} style={styles.iconContainer}>
          <Image
            style={styles.icon}
            source={{ uri: 'icon' }}
          />
  </TouchableOpacity>
}

ScrollView

A component that introduces scrolling around content inside. We calculate the max Y and max X, and set the content of the scroll view.

import { ScrollView, View } from 'syr';

render() {
  return <ScrollView style={{height: 300, width: 300}}>
      <View style={{height: 500, width: 500}}></View>
  </ScrollView>
}

StackView

☠️  watch out! this is under heavy development!

StackView allows a developers to align and space out content. In lieu of having React-Native's Yoga (Flexbox), we leverage built in layout controls.

import { StackView, View } from 'syr';

render() {
  return <StackView
            axis="vertical"
            style={style}>
    <View style={{height: 50, width: 50}}></View>
    <View style={{height: 50, width: 50}}></View>
    <View style={{height: 50, width: 50}}></View>
  </StackView>
}

Styling a component

☠️  watch out! this is under heavy development!

Styling a component is much like basic React-Native. Create a JavaScript literal that describes the layout properties that you would like to affect.

let style = {
  height: 50,
  width: 100
}

You then bind the style to the rendering node.

render() {
  return <View style={style}></View>
}

height

Set the height of a frame.

let style = {
  height: 50
}

width

Set the width of a frame.

let style = {
  width: 100
}

left

Set the origin left for a frame.

let style = {
  left: 50
}

top

Set the origin top of a frame.

let style = {
  top: 50
}

color

Set the foreground color of a component. Normally text color. Accepts HEX and RGBA.

let style = {
  color: '#FFFFFF'
}

backgroundColor

Set the background color of a component. Accepts HEX and RGBA.

let style = {
  backgroundColor: '#000000'
}

borderRadius

Set the border radius of a component. Slight variations exist for curvature on each platform. Combine with PixelRatio to soften corners.

let style = {
  borderRadius: 15
}

borderWidth

Set the width of the border on a component.

let style = {
  borderWidth: 3
}

borderColor

Set the color of the border on a component. Accepts HEX and RGBA.

let style = {
  borderColor: '#FF00FF'
}

fontSize

Set the font size, normally only useful for TextView. Due to variations in screen sizes, we recommend using PixelRatio to obtain the DisplayPoint to PixelSize.

let style = {
  fontSize: 24
}

fontWeight

Set the font weight, normally only useful for TextView. Currently accepts normal or bold.

let style = {
  fontWeight: 'bold'
}

textAlign

☠️  watch out! this is under heavy development!

Set the text alignment direction. Currently accepts left|center|right. These will be changing to start|middle|end once internationalization support lands.

let style = {
  textAlign: 'center'
}

Rendering

SyrSDK uses the concept of a raster. It tries to detect the environment it's in, based on the availability of the SyrNative bridge. Rendering to the RootView surface is as easy as creating the component, and handing it to the raster.

We recommend, that you use a top level component for an entry. And use this as top level logic for your application. Once handed to the Raster, it will become an instance, and it's logic and program will run starting with it's constructor, and then the lifeCycle events.

import { Component, Render } from 'syr';

class MyApp extends Component {
  render() {
    return <View></View>
  }
}

Render(MyComponent);

LifeCycle

Syr supports Life Cycle events to help control the flow of the program. To take advantage of these add the following to javascript classes.

Method stubs

import { Component } from 'syr';

class MyComponent extends Component {
  constructor() {
    // runs when object is created in javascript
  }

  render() {
    // when what this class should return as it's rendering tree
  }

  componentDidMount() {
    // this fires when component has been added to the rendering surface
  }

  componentWillUnmount() {
    // fires when component is removed from rendering surface
  }

  componentWillUpdate() {
    // fires immediately before rendering when new props or state are being received
  }

  shouldComponentUpdate() {
    // fires before component will update, you can return false
    // to prevent an update
  }

  componentDidUpdate() {
    // component updated, runs after the component state was changed
  }
}

Events

Notifying JavaScript from Native

If you need to notify the JavaScript from the Native layer, you can send events, from your native component. The easiest way to get access to this event.

[self sendEventWithName:@"FooParty" body:@{@"name": @"party at my desk"}];
HashMap<String, String> eventPayload = new HashMap<String, String>();
eventPayload.put("name", "part at my desk");
SyrInstance.getInstance(this).sendEvent("FooParty", "party at my desk")

Subscribing to Events from JavaScript

JavaScript can subscribe to the events that are being passed down from the native layer.

import { NativeEventEmitter } from 'syr';


const subscription = NativeEventEmitter.addListener(
  'FooParty',
  (event) => console.log(event.name)
);

// unsubscribe when needed
subscription.remove();

Animations

Syr has support for animations. With Syr animations you can run animations transitions in parallel, or sequence. Animations allow for the shift in x,y position and size. If you need a more complex animation you can use Animated.Value to bind a transform to the component.

Slide

import { Component, Render, Animated } from 'syr';

class MyComponent extends Component {
  constructor() {
    super();
    // slide animation
    this.slideAnimation = new Animated.XYValue({
      x: 0
      y: 0
    });
  }
  render() {
    return (
      <Animated.View style={{
        height: 100,
        width: 100,
        backgroundColor: '#ffffff',
        transform: [this.slideAnimation]
      }}>
      </Animated.View>
    );
  }
  componentDidMount() {
    Animated.timing(this.slideAnimation, {
      toValue: {
        x:100,
        y:100
      },
      duration: 5000
    }).start()
  }
}

Render(MyComponent);

Rotation

import { Component, Render, Animated } from 'syr';

class MyComponent extends Component {
  constructor() {
    super();
    // interpolation animation
    this.spinAnimation = new Animated.Value(0);
  }
  render() {
    return (
      <Animated.View style={{
        height: 100,
        width: 100,
        backgroundColor: '#ffffff',
        top: 50,
        left: 50,
        transform: [this.spinAnimation]
      }}>
      </Animated.View>
    );
  }
  spin() {
    //spin the object 360 degress. and repeat after 5 seconds
    Animated.timing(this.spinAnimation, {
      toValue: 360,
      duration: 5000
    }).start(()=>{
      this.spin();
    });
  }
  componentDidMount() {
    this.spin();
  }
}

Render(MyComponent);

Platform

OS

Retrieve the Platform name the application running under.

let OS = Platform.OS // "ios" || "android" || "browser_name"

Version

Retrieve the version of the Platform the application is running under. For iOS returns the version running. For Android, returns the API level. For Web returns the browser version.

let Version = Platform.Version // iOS : 11.2 , Android : 24 , Web : 63

isWeb

⚠️  deviates from react-native

Provides boolean value, if the application is displaying inside a Web Browser or now.

if(Platform.isWeb) {
  // do something with web platform
}

Pixel Ratio

If you are creating cross platform applications, you typically need to deal with varied resolutions across similar physical screens, and densities of physical pixels that map to virtual pixels. The PixelRatio class can help you detect values you need to ensure you have consistent layouts across platforms.

get

Returns the pixel ratio of the device. Use this ratio to determine which quality images you should be using in your application. Returns a precision value, such as 1, 1.5, 2, 2.5. Use in combination with getPixelSizeForLayoutSize to keep resolution scaled.

let dpi = PixelRatio.get();

getPixelSizeForLayoutSize

Returns interpolated pixels based on device resolution width. (currentScreenWidth / 640)*DisplayPoints, we ensure we take the smaller of the two screen measurements, so we scale appropriately for Landscape based on the resolution for the physical screen. 640 is based on the standard width of the iPhone 5s and SE.

let virtualPixelSize = PixelRatio.getPixelSizeForLayoutSize(75); // pass DisplayPoints

Creating Native Modules

Syr lets you create native modules that can bridge across the native to web spectrum. They are capable of providing renderable (Views, Text, Buttons), and having methods callable from JavaScript.

Syr Native Modules are always used in the Class invocation method. What this means is that if you want to store instanced information (some value) on your class Natively you need to use the sharedDelegate/singelton pattern.

Building your first class

//
// MyNativeModule.h
//

#import "SyrComponent.h"

@interface MyNativeModule : SyrComponent
@end

//
// MyNativeModule.m
//

#import "MyNativeModule.h"

@implementation MyNativeModule

// send this class to the JS bridge
SYR_EXPORT_MODULE();

// this is an objective C method that will get it's invokation from JS
SYR_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)
{
  // do something with Name and Location strings
}

// if you want to use this module in the JSX tree
// there are helper methods on the component to help with
// styling and more
+(NSObject*) render: (NSDictionary*) component {
  UIView *view = [[UIView alloc] init];
  return view;
}

@end

//
// MainActivity.java
//
// Native Modules must be registered manually on Android
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  modules.add(new MyNativeModule());

  ...
  ...
  ...

  instance.setNativeModules(modules);
}

//
// MyNativeModule.java
//

public class SyrView implements SyrBaseModule {
  // this module provide a render stub
  @Override
  public View render(JSONObject component, Context context) {
        View view = new View(context);
        return view;
  }

  // this is the JSX tag that the component will be mapped to
  @Override
  public String getName() {
      return "View";
  }

  // expose methods to the Javascript Environment
  @SyrMethod
  public void testExportMethod(String message, int duration) {

  }
}

Accessing the native modules from javascript.

import { NativeModules } from 'syr';

let MyNativeModule = NativeModules.MyNativeModule;

MyNativeModule.addEvent('building an app', 'at my desk');