gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 1111HTML 1039Markdown 12TOML 94524 Definitions

⎇ da987064d9c1123d4e8583cb599e63d8d1884512 README.md Markdown · 208 lines · 7.5 KB History raw

Implement new rust API for bindings and release v0.3 4745c0f58 · Emil Sjölander ·

1# Stretch
2[![CircleCI](https://circleci.com/gh/vislyhq/stretch.svg?style=svg)](https://circleci.com/gh/vislyhq/stretch)
3[![Cargo](https://img.shields.io/crates/v/stretch.svg)](https://crates.io/crates/stretch)
4[![npm](https://img.shields.io/npm/v/stretch-layout.svg)](https://www.npmjs.com/package/stretch-layout)
5[![cocoapods](https://img.shields.io/cocoapods/v/StretchKit.svg)](https://cocoapods.org/pods/StretchKit)
6[![bintray](https://api.bintray.com/packages/visly/maven/stretch-kotlin-bindings/images/download.svg)](https://bintray.com/visly/maven/stretch-kotlin-bindings)
7
8Stretch is an implementation of Flexbox written in [Rust](https://www.rust-lang.org). The goal of stretch is to provide a solid foundation for layout across all platforms with a specific focus on mobile. Long term we want stretch to not only support flexbox but also many other layout algorithms such as grid layout. Stretch was made for and powers https://visly.app.
9
10## Goals
11Before using or contributing to stretch it is good to be aware of the core goals of the project. These are goals we are working towards, not necessarily features we currently support.
12
13- High performance
14- Cross platform
15- Small binary size
16- Support multiple layout systems
17- Multi-threaded layout
18- Language bindings for most common languages
19
20## Supported Platforms
21
22- Rust
23- Android
24- iOS
25- JavaScript / TypeScript
26
27## Usage
28Stretch is built in Rust but comes with bindings to multiple languages and platforms so you can use it in a way that feels natural to your project.
29
30### Rust
31```toml
32# Cargo.toml
33
34[dependencies]
35stretch = "0.3.2"
36```
37
38```rust
39// main.rs
40
41use stretch::geometry::Size;
42use stretch::style::*;
43
44fn main() -> Result<(), stretch::Error> {
45    let mut stretch = stretch::node::Stretch::new();
46    
47    let child = stretch.new_node(
48        Style { size: Size { width: Dimension::Percent(0.5), height: Dimension::Auto }, ..Default::default() },
49        vec![],
50    )?;
51
52    let node = stretch.new_node(
53        Style {
54            size: Size { width: Dimension::Points(100.0), height: Dimension::Points(100.0) },
55            justify_content: JustifyContent::Center,
56            ..Default::default()
57        },
58        vec![child],
59    )?;
60
61    stretch.compute_layout(node, Size::undefined())?;
62    dbg!(stretch.layout(node)?);
63}
64
65```
66
67### Android
68```groovy
69// Build.gradle
70
71android {
72    splits {
73        abi {
74            enable true
75        }
76    }
77}
78
79dependencies {
80    implementation 'app.visly.stretch:stretch:0.3.2'
81}
82```
83
84```kotlin
85// MainActivity.kt
86
87val node = Node(
88  Style(size = Size(Dimension.Points(100f), Dimension.Points(100f)), justifyContent = JustifyContent.Center), 
89  listOf(
90    Node(Style(size = Size(Dimension.Percent(0.5f), Dimension.Percent(0.5f))), listOf())
91  ))
92
93val layout = node.computeLayout(Size(null, null))
94Log.d(TAG, "width: ${layout.width}, height: ${layout.height}")
95```
96
97### iOS
98```ruby
99# Podfile
100
101pod 'StretchKit', '~> 0.3.2'
102```
103
104```swift
105// ViewController.swift
106 
107let node = Node(
108  style: Style(size: Size(width: .points(100.0), height: .points(100.0)), justifyContent: .center), 
109  children: [
110    Node(style: Style(size: Size(width: .percent(0.5), height: .percent(0.5))), children: [])
111  ])
112  
113let layout = node.computeLayout(thatFits: Size(width: nil, height: nil))
114print("width: \(layout.width), height: \(layout.height)")
115```
116
117### JavaScript
118```bash
119> npm install --save stretch-layout
120```
121
122```javascript
123// index.js
124
125import { Allocator, Node, JustifyContent } from 'stretch-layout';
126
127const allocator = new Allocator();
128const node = new Node(allocator, {width: 100, height: 100, justifyContent: JustifyContent.Center});
129node.addChild(new Node(allocator, {width: '50%', height: '50%'}));
130const layout = node.computeLayout();
131
132console.log(layout.width, layout.height);
133```
134
135## Contributing
136Contributions are very welcome. Though we ask that you open an issue or pull request early in the process (before writing code) so we can discuss solutions and additions before you start spending time on implementing them. There are some specific areas where we would be extra happy to receive contributions in.
137
138- Binary size reduction
139- Runtime performance
140- Ensure build / test environment works well on non macOS platforms
141- Alternate layout systems (grid layout perhaps?)
142- Web compatibility tests
143- RTL support
144- Platform bindings
145- API improvements
146- Documentation & Examples
147
148### Installation
149If you don't have Rust installed you have to do that first as well as install some components that we make use of to format and lint the codebase. For more on Rust see their [website](https://www.rust-lang.org).
150
151```bash
152curl https://sh.rustup.rs -sSf | sh
153rustup component add rustfmt
154rustup component add clippy
155```
156
157Once that is done you can clone the repo and do some sanity checks to make sure everything is working correctly.
158
159```bash
160git clone https://github.com/vislyhq/stretch.git
161cd stretch
162cargo test
163```
164
165If you have made any changes to the API you should also update and run tests for all the platform bindings located in `/bindings/*`.
166
167### Testing
168Stretch is tested by validating that layouts written in stretch perform the same as in Chrome. This is done by rendering an equivalent layout in HTML and then generating a Rust test case which asserts that the resulting layout is the same when run through stretch.
169
170You can run these tests without setting up a webdriver environment but if you are looking to add any test case you will need to install [chromedriver](http://chromedriver.chromium.org). If you are developing on macOS this is easy to do through brew.
171
172```bash
173brew tap homebrew/cask
174brew cask install chromedriver
175```
176
177Once you have chromedriver installed and available in `PATH` you can re-generate all tests by running `cargo run --package gentest`.
178
179To add a new test case add another HTML file to `/test_fixtures` following the current tests as a template for new tests.
180
181### Benchmarking
182Benchmarks build on the same infrastructure as testing, and actually benchmarks are automatically generated from test fixtures just like tests. Run `cargo bench` to run benchmarks locally.
183
184## Relationship to Yoga
185[Yoga](https://www.yogalayout.com) is a cross-platform implementation of Flexbox written in C. Yoga is a fantastic project but has some fundamental issues which we hope to resolve. Compared to Yoga we aim to have a stronger adherence to web standards, a flexible architecture eventually supporting multiple layout algorithms, and future performance improvements including multi-threaded layout. In addition to this we aim to use a safer language with a more modern codebase.
186
187# LICENCE
188```
189Copyright (c) 2018 Visly Inc.
190
191Permission is hereby granted, free of charge, to any person obtaining a copy
192of this software and associated documentation files (the "Software"), to deal
193in the Software without restriction, including without limitation the rights
194to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
195copies of the Software, and to permit persons to whom the Software is
196furnished to do so, subject to the following conditions:
197
198The above copyright notice and this permission notice shall be included in all
199copies or substantial portions of the Software.
200
201THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
202IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
203FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
204AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
205LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
206OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
207SOFTWARE.
208```

README.md

Stretch

CircleCI Cargo npm cocoapods bintray

Stretch is an implementation of Flexbox written in Rust. The goal of stretch is to provide a solid foundation for layout across all platforms with a specific focus on mobile. Long term we want stretch to not only support flexbox but also many other layout algorithms such as grid layout. Stretch was made for and powers https://visly.app.

Goals

Before using or contributing to stretch it is good to be aware of the core goals of the project. These are goals we are working towards, not necessarily features we currently support.

Supported Platforms

Usage

Stretch is built in Rust but comes with bindings to multiple languages and platforms so you can use it in a way that feels natural to your project.

Rust

# Cargo.toml

[dependencies]
stretch = "0.3.2"
// main.rs

use stretch::geometry::Size;
use stretch::style::*;

fn main() -> Result<(), stretch::Error> {
    let mut stretch = stretch::node::Stretch::new();
    
    let child = stretch.new_node(
        Style { size: Size { width: Dimension::Percent(0.5), height: Dimension::Auto }, ..Default::default() },
        vec![],
    )?;

    let node = stretch.new_node(
        Style {
            size: Size { width: Dimension::Points(100.0), height: Dimension::Points(100.0) },
            justify_content: JustifyContent::Center,
            ..Default::default()
        },
        vec![child],
    )?;

    stretch.compute_layout(node, Size::undefined())?;
    dbg!(stretch.layout(node)?);
}

Android

// Build.gradle

android {
    splits {
        abi {
            enable true
        }
    }
}

dependencies {
    implementation 'app.visly.stretch:stretch:0.3.2'
}
// MainActivity.kt

val node = Node(
  Style(size = Size(Dimension.Points(100f), Dimension.Points(100f)), justifyContent = JustifyContent.Center), 
  listOf(
    Node(Style(size = Size(Dimension.Percent(0.5f), Dimension.Percent(0.5f))), listOf())
  ))

val layout = node.computeLayout(Size(null, null))
Log.d(TAG, "width: ${layout.width}, height: ${layout.height}")

iOS

# Podfile

pod 'StretchKit', '~> 0.3.2'
// ViewController.swift
 
let node = Node(
  style: Style(size: Size(width: .points(100.0), height: .points(100.0)), justifyContent: .center), 
  children: [
    Node(style: Style(size: Size(width: .percent(0.5), height: .percent(0.5))), children: [])
  ])
  
let layout = node.computeLayout(thatFits: Size(width: nil, height: nil))
print("width: \(layout.width), height: \(layout.height)")

JavaScript

> npm install --save stretch-layout
// index.js

import { Allocator, Node, JustifyContent } from 'stretch-layout';

const allocator = new Allocator();
const node = new Node(allocator, {width: 100, height: 100, justifyContent: JustifyContent.Center});
node.addChild(new Node(allocator, {width: '50%', height: '50%'}));
const layout = node.computeLayout();

console.log(layout.width, layout.height);

Contributing

Contributions are very welcome. Though we ask that you open an issue or pull request early in the process (before writing code) so we can discuss solutions and additions before you start spending time on implementing them. There are some specific areas where we would be extra happy to receive contributions in.

Installation

If you don't have Rust installed you have to do that first as well as install some components that we make use of to format and lint the codebase. For more on Rust see their website.

curl https://sh.rustup.rs -sSf | sh
rustup component add rustfmt
rustup component add clippy

Once that is done you can clone the repo and do some sanity checks to make sure everything is working correctly.

git clone https://github.com/vislyhq/stretch.git
cd stretch
cargo test

If you have made any changes to the API you should also update and run tests for all the platform bindings located in /bindings/*.

Testing

Stretch is tested by validating that layouts written in stretch perform the same as in Chrome. This is done by rendering an equivalent layout in HTML and then generating a Rust test case which asserts that the resulting layout is the same when run through stretch.

You can run these tests without setting up a webdriver environment but if you are looking to add any test case you will need to install chromedriver. If you are developing on macOS this is easy to do through brew.

brew tap homebrew/cask
brew cask install chromedriver

Once you have chromedriver installed and available in PATH you can re-generate all tests by running cargo run --package gentest.

To add a new test case add another HTML file to /test_fixtures following the current tests as a template for new tests.

Benchmarking

Benchmarks build on the same infrastructure as testing, and actually benchmarks are automatically generated from test fixtures just like tests. Run cargo bench to run benchmarks locally.

Relationship to Yoga

Yoga is a cross-platform implementation of Flexbox written in C. Yoga is a fantastic project but has some fundamental issues which we hope to resolve. Compared to Yoga we aim to have a stronger adherence to web standards, a flexible architecture eventually supporting multiple layout algorithms, and future performance improvements including multi-threaded layout. In addition to this we aim to use a safer language with a more modern codebase.

LICENCE

Copyright (c) 2018 Visly Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.